Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac45d613 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: fix nlink after unlink



Anand Avati reports that the following sequence of system calls fail on a fuse
filesystem:


 	create("filename") => 0
 	link("filename", "linkname") => 0
 	unlink("filename") => 0
 	link("linkname", "filename") => -ENOENT ### BUG ###

vfs_link() fails with ENOENT if i_nlink is zero, this is done to prevent
resurrecting already deleted files.

Fuse clears i_nlink on unlink even if there are other links pointing to the
file.

Reported-by: default avatarAnand Avati <avati@redhat.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 192cfd58
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -644,13 +644,12 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
	fuse_put_request(fc, req);
	if (!err) {
		struct inode *inode = entry->d_inode;
		struct fuse_inode *fi = get_fuse_inode(inode);

		/*
		 * Set nlink to zero so the inode can be cleared, if the inode
		 * does have more links this will be discovered at the next
		 * lookup/getattr.
		 */
		clear_nlink(inode);
		spin_lock(&fc->lock);
		fi->attr_version = ++fc->attr_version;
		drop_nlink(inode);
		spin_unlock(&fc->lock);
		fuse_invalidate_attr(inode);
		fuse_invalidate_attr(dir);
		fuse_invalidate_entry_cache(entry);
@@ -762,8 +761,17 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
	   will reflect changes in the backing inode (link count,
	   etc.)
	*/
	if (!err || err == -EINTR)
	if (!err) {
		struct fuse_inode *fi = get_fuse_inode(inode);

		spin_lock(&fc->lock);
		fi->attr_version = ++fc->attr_version;
		inc_nlink(inode);
		spin_unlock(&fc->lock);
		fuse_invalidate_attr(inode);
	} else if (err == -EINTR) {
		fuse_invalidate_attr(inode);
	}
	return err;
}