aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2018-10-01 04:07:05 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2018-10-01 04:07:05 -0400
commit261aaba72fdba17b74a3a434d9f925b43d90e958 (patch)
tree88700d029d1bdf476b8f23e6adb46e3acb2c4b2b
parent7118883b44b8edfea732aadeb0d4424da3f152b2 (diff)
fuse: use iversion for readdir cache verification
Use the internal iversion counter to make sure modifications of the directory through this filesystem are not missed by the mtime check (due to mtime granularity). Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/fuse/dir.c21
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/readdir.c5
3 files changed, 21 insertions, 8 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 3a333b0ea9ad..6800fdc3e730 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -14,6 +14,7 @@
14#include <linux/namei.h> 14#include <linux/namei.h>
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/xattr.h> 16#include <linux/xattr.h>
17#include <linux/iversion.h>
17#include <linux/posix_acl.h> 18#include <linux/posix_acl.h>
18 19
19static void fuse_advise_use_readdirplus(struct inode *dir) 20static void fuse_advise_use_readdirplus(struct inode *dir)
@@ -89,6 +90,12 @@ void fuse_invalidate_attr(struct inode *inode)
89 get_fuse_inode(inode)->i_time = 0; 90 get_fuse_inode(inode)->i_time = 0;
90} 91}
91 92
93static void fuse_dir_changed(struct inode *dir)
94{
95 fuse_invalidate_attr(dir);
96 inode_maybe_inc_iversion(dir, false);
97}
98
92/** 99/**
93 * Mark the attributes as stale due to an atime change. Avoid the invalidate if 100 * Mark the attributes as stale due to an atime change. Avoid the invalidate if
94 * atime is not used. 101 * atime is not used.
@@ -447,7 +454,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
447 kfree(forget); 454 kfree(forget);
448 d_instantiate(entry, inode); 455 d_instantiate(entry, inode);
449 fuse_change_entry_timeout(entry, &outentry); 456 fuse_change_entry_timeout(entry, &outentry);
450 fuse_invalidate_attr(dir); 457 fuse_dir_changed(dir);
451 err = finish_open(file, entry, generic_file_open); 458 err = finish_open(file, entry, generic_file_open);
452 if (err) { 459 if (err) {
453 fuse_sync_release(ff, flags); 460 fuse_sync_release(ff, flags);
@@ -561,7 +568,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
561 } else { 568 } else {
562 fuse_change_entry_timeout(entry, &outarg); 569 fuse_change_entry_timeout(entry, &outarg);
563 } 570 }
564 fuse_invalidate_attr(dir); 571 fuse_dir_changed(dir);
565 return 0; 572 return 0;
566 573
567 out_put_forget_req: 574 out_put_forget_req:
@@ -671,7 +678,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
671 drop_nlink(inode); 678 drop_nlink(inode);
672 spin_unlock(&fc->lock); 679 spin_unlock(&fc->lock);
673 fuse_invalidate_attr(inode); 680 fuse_invalidate_attr(inode);
674 fuse_invalidate_attr(dir); 681 fuse_dir_changed(dir);
675 fuse_invalidate_entry_cache(entry); 682 fuse_invalidate_entry_cache(entry);
676 fuse_update_ctime(inode); 683 fuse_update_ctime(inode);
677 } else if (err == -EINTR) 684 } else if (err == -EINTR)
@@ -693,7 +700,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
693 err = fuse_simple_request(fc, &args); 700 err = fuse_simple_request(fc, &args);
694 if (!err) { 701 if (!err) {
695 clear_nlink(d_inode(entry)); 702 clear_nlink(d_inode(entry));
696 fuse_invalidate_attr(dir); 703 fuse_dir_changed(dir);
697 fuse_invalidate_entry_cache(entry); 704 fuse_invalidate_entry_cache(entry);
698 } else if (err == -EINTR) 705 } else if (err == -EINTR)
699 fuse_invalidate_entry(entry); 706 fuse_invalidate_entry(entry);
@@ -732,9 +739,9 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
732 fuse_update_ctime(d_inode(newent)); 739 fuse_update_ctime(d_inode(newent));
733 } 740 }
734 741
735 fuse_invalidate_attr(olddir); 742 fuse_dir_changed(olddir);
736 if (olddir != newdir) 743 if (olddir != newdir)
737 fuse_invalidate_attr(newdir); 744 fuse_dir_changed(newdir);
738 745
739 /* newent will end up negative */ 746 /* newent will end up negative */
740 if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) { 747 if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) {
@@ -967,7 +974,7 @@ int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
967 if (!entry) 974 if (!entry)
968 goto unlock; 975 goto unlock;
969 976
970 fuse_invalidate_attr(parent); 977 fuse_dir_changed(parent);
971 fuse_invalidate_entry(entry); 978 fuse_invalidate_entry(entry);
972 979
973 if (child_nodeid != 0 && d_really_is_positive(entry)) { 980 if (child_nodeid != 0 && d_really_is_positive(entry)) {
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 3deb013a289e..d9d1ea78efa6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -120,6 +120,9 @@ struct fuse_inode {
120 /* modification time of directory when cache was started */ 120 /* modification time of directory when cache was started */
121 struct timespec64 mtime; 121 struct timespec64 mtime;
122 122
123 /* iversion of directory when cache was started */
124 u64 iversion;
125
123 /* protects above fields */ 126 /* protects above fields */
124 spinlock_t lock; 127 spinlock_t lock;
125 } rdc; 128 } rdc;
diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c
index dafd6543cca2..ab18b78f4755 100644
--- a/fs/fuse/readdir.c
+++ b/fs/fuse/readdir.c
@@ -8,6 +8,7 @@
8 8
9 9
10#include "fuse_i.h" 10#include "fuse_i.h"
11#include <linux/iversion.h>
11#include <linux/posix_acl.h> 12#include <linux/posix_acl.h>
12#include <linux/pagemap.h> 13#include <linux/pagemap.h>
13#include <linux/highmem.h> 14#include <linux/highmem.h>
@@ -447,6 +448,7 @@ retry_locked:
447 /* Starting cache? Set cache mtime. */ 448 /* Starting cache? Set cache mtime. */
448 if (!ctx->pos && !fi->rdc.size) { 449 if (!ctx->pos && !fi->rdc.size) {
449 fi->rdc.mtime = inode->i_mtime; 450 fi->rdc.mtime = inode->i_mtime;
451 fi->rdc.iversion = inode_query_iversion(inode);
450 } 452 }
451 spin_unlock(&fi->rdc.lock); 453 spin_unlock(&fi->rdc.lock);
452 return UNCACHED; 454 return UNCACHED;
@@ -457,7 +459,8 @@ retry_locked:
457 * changed, and reset the cache if so. 459 * changed, and reset the cache if so.
458 */ 460 */
459 if (!ctx->pos) { 461 if (!ctx->pos) {
460 if (!timespec64_equal(&fi->rdc.mtime, &inode->i_mtime)) { 462 if (inode_peek_iversion(inode) != fi->rdc.iversion ||
463 !timespec64_equal(&fi->rdc.mtime, &inode->i_mtime)) {
461 fuse_rdc_reset(inode); 464 fuse_rdc_reset(inode);
462 goto retry_locked; 465 goto retry_locked;
463 } 466 }