aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2012-03-05 09:48:11 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2012-03-05 09:48:11 -0500
commitac45d61357e86b9a0cf14e45e8e09dfb626970ef (patch)
treee560d3a8f26d1530780ed62f2a4bd3f16a20ac55
parent192cfd58774b4d17b2fe8bdc77d89c2ef4e0591d (diff)
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: Anand Avati <avati@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r--fs/fuse/dir.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 206632887bb4..da379070fab5 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -644,13 +644,12 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
644 fuse_put_request(fc, req); 644 fuse_put_request(fc, req);
645 if (!err) { 645 if (!err) {
646 struct inode *inode = entry->d_inode; 646 struct inode *inode = entry->d_inode;
647 struct fuse_inode *fi = get_fuse_inode(inode);
647 648
648 /* 649 spin_lock(&fc->lock);
649 * Set nlink to zero so the inode can be cleared, if the inode 650 fi->attr_version = ++fc->attr_version;
650 * does have more links this will be discovered at the next 651 drop_nlink(inode);
651 * lookup/getattr. 652 spin_unlock(&fc->lock);
652 */
653 clear_nlink(inode);
654 fuse_invalidate_attr(inode); 653 fuse_invalidate_attr(inode);
655 fuse_invalidate_attr(dir); 654 fuse_invalidate_attr(dir);
656 fuse_invalidate_entry_cache(entry); 655 fuse_invalidate_entry_cache(entry);
@@ -762,8 +761,17 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
762 will reflect changes in the backing inode (link count, 761 will reflect changes in the backing inode (link count,
763 etc.) 762 etc.)
764 */ 763 */
765 if (!err || err == -EINTR) 764 if (!err) {
765 struct fuse_inode *fi = get_fuse_inode(inode);
766
767 spin_lock(&fc->lock);
768 fi->attr_version = ++fc->attr_version;
769 inc_nlink(inode);
770 spin_unlock(&fc->lock);
766 fuse_invalidate_attr(inode); 771 fuse_invalidate_attr(inode);
772 } else if (err == -EINTR) {
773 fuse_invalidate_attr(inode);
774 }
767 return err; 775 return err;
768} 776}
769 777