Skip to content

Commit 2396356

Browse files
luis-henrixMiklos Szeredi
authored andcommitted
fuse: add more control over cache invalidation behaviour
Currently userspace is able to notify the kernel to invalidate the cache for an inode. This means that, if all the inodes in a filesystem need to be invalidated, then userspace needs to iterate through all of them and do this kernel notification separately. This patch adds the concept of 'epoch': each fuse connection will have the current epoch initialized and every new dentry will have it's d_time set to the current epoch value. A new operation will then allow userspace to increment the epoch value. Every time a dentry is d_revalidate()'ed, it's epoch is compared with the current connection epoch and invalidated if it's value is different. Signed-off-by: Luis Henriques <[email protected]> Tested-by: Laura Promberger <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent faa794d commit 2396356

File tree

6 files changed

+50
-6
lines changed

6 files changed

+50
-6
lines changed

fs/fuse/dev.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,19 @@ static int fuse_notify_resend(struct fuse_conn *fc)
20212021
return 0;
20222022
}
20232023

2024+
/*
2025+
* Increments the fuse connection epoch. This will result of dentries from
2026+
* previous epochs to be invalidated.
2027+
*
2028+
* XXX optimization: add call to shrink_dcache_sb()?
2029+
*/
2030+
static int fuse_notify_inc_epoch(struct fuse_conn *fc)
2031+
{
2032+
atomic_inc(&fc->epoch);
2033+
2034+
return 0;
2035+
}
2036+
20242037
static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
20252038
unsigned int size, struct fuse_copy_state *cs)
20262039
{
@@ -2049,6 +2062,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
20492062
case FUSE_NOTIFY_RESEND:
20502063
return fuse_notify_resend(fc);
20512064

2065+
case FUSE_NOTIFY_INC_EPOCH:
2066+
return fuse_notify_inc_epoch(fc);
2067+
20522068
default:
20532069
fuse_copy_finish(cs);
20542070
return -EINVAL;

fs/fuse/dir.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,14 @@ static int fuse_dentry_revalidate(struct inode *dir, const struct qstr *name,
200200
{
201201
struct inode *inode;
202202
struct fuse_mount *fm;
203+
struct fuse_conn *fc;
203204
struct fuse_inode *fi;
204205
int ret;
205206

207+
fc = get_fuse_conn_super(dir->i_sb);
208+
if (entry->d_time < atomic_read(&fc->epoch))
209+
goto invalid;
210+
206211
inode = d_inode_rcu(entry);
207212
if (inode && fuse_is_bad(inode))
208213
goto invalid;
@@ -415,16 +420,20 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
415420
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
416421
unsigned int flags)
417422
{
418-
int err;
419423
struct fuse_entry_out outarg;
424+
struct fuse_conn *fc;
420425
struct inode *inode;
421426
struct dentry *newent;
427+
int err, epoch;
422428
bool outarg_valid = true;
423429
bool locked;
424430

425431
if (fuse_is_bad(dir))
426432
return ERR_PTR(-EIO);
427433

434+
fc = get_fuse_conn_super(dir->i_sb);
435+
epoch = atomic_read(&fc->epoch);
436+
428437
locked = fuse_lock_inode(dir);
429438
err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
430439
&outarg, &inode);
@@ -446,6 +455,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
446455
goto out_err;
447456

448457
entry = newent ? newent : entry;
458+
entry->d_time = epoch;
449459
if (outarg_valid)
450460
fuse_change_entry_timeout(entry, &outarg);
451461
else
@@ -619,7 +629,6 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
619629
struct dentry *entry, struct file *file,
620630
unsigned int flags, umode_t mode, u32 opcode)
621631
{
622-
int err;
623632
struct inode *inode;
624633
struct fuse_mount *fm = get_fuse_mount(dir);
625634
FUSE_ARGS(args);
@@ -629,11 +638,13 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
629638
struct fuse_entry_out outentry;
630639
struct fuse_inode *fi;
631640
struct fuse_file *ff;
641+
int epoch, err;
632642
bool trunc = flags & O_TRUNC;
633643

634644
/* Userspace expects S_IFREG in create mode */
635645
BUG_ON((mode & S_IFMT) != S_IFREG);
636646

647+
epoch = atomic_read(&fm->fc->epoch);
637648
forget = fuse_alloc_forget();
638649
err = -ENOMEM;
639650
if (!forget)
@@ -702,6 +713,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
702713
}
703714
kfree(forget);
704715
d_instantiate(entry, inode);
716+
entry->d_time = epoch;
705717
fuse_change_entry_timeout(entry, &outentry);
706718
fuse_dir_changed(dir);
707719
err = generic_file_open(inode, file);
@@ -788,12 +800,14 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
788800
struct fuse_entry_out outarg;
789801
struct inode *inode;
790802
struct dentry *d;
791-
int err;
792803
struct fuse_forget_link *forget;
804+
int epoch, err;
793805

794806
if (fuse_is_bad(dir))
795807
return ERR_PTR(-EIO);
796808

809+
epoch = atomic_read(&fm->fc->epoch);
810+
797811
forget = fuse_alloc_forget();
798812
if (!forget)
799813
return ERR_PTR(-ENOMEM);
@@ -835,10 +849,13 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun
835849
if (IS_ERR(d))
836850
return d;
837851

838-
if (d)
852+
if (d) {
853+
d->d_time = epoch;
839854
fuse_change_entry_timeout(d, &outarg);
840-
else
855+
} else {
856+
entry->d_time = epoch;
841857
fuse_change_entry_timeout(entry, &outarg);
858+
}
842859
fuse_dir_changed(dir);
843860
return d;
844861

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,9 @@ struct fuse_conn {
636636
/** Number of fuse_dev's */
637637
atomic_t dev_count;
638638

639+
/** Current epoch for up-to-date dentries */
640+
atomic_t epoch;
641+
639642
struct rcu_head rcu;
640643

641644
/** The user id for this mount */

fs/fuse/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
962962
init_rwsem(&fc->killsb);
963963
refcount_set(&fc->count, 1);
964964
atomic_set(&fc->dev_count, 1);
965+
atomic_set(&fc->epoch, 1);
965966
init_waitqueue_head(&fc->blocked_waitq);
966967
fuse_iqueue_init(&fc->iq, fiq_ops, fiq_priv);
967968
INIT_LIST_HEAD(&fc->bg_queue);

fs/fuse/readdir.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ static int fuse_direntplus_link(struct file *file,
161161
struct fuse_conn *fc;
162162
struct inode *inode;
163163
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
164+
int epoch;
164165

165166
if (!o->nodeid) {
166167
/*
@@ -190,6 +191,7 @@ static int fuse_direntplus_link(struct file *file,
190191
return -EIO;
191192

192193
fc = get_fuse_conn(dir);
194+
epoch = atomic_read(&fc->epoch);
193195

194196
name.hash = full_name_hash(parent, name.name, name.len);
195197
dentry = d_lookup(parent, &name);
@@ -256,6 +258,7 @@ static int fuse_direntplus_link(struct file *file,
256258
}
257259
if (fc->readdirplus_auto)
258260
set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
261+
dentry->d_time = epoch;
259262
fuse_change_entry_timeout(dentry, o);
260263

261264
dput(dentry);

include/uapi/linux/fuse.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@
232232
*
233233
* 7.43
234234
* - add FUSE_REQUEST_TIMEOUT
235+
*
236+
* 7.44
237+
* - add FUSE_NOTIFY_INC_EPOCH
235238
*/
236239

237240
#ifndef _LINUX_FUSE_H
@@ -267,7 +270,7 @@
267270
#define FUSE_KERNEL_VERSION 7
268271

269272
/** Minor version number of this interface */
270-
#define FUSE_KERNEL_MINOR_VERSION 43
273+
#define FUSE_KERNEL_MINOR_VERSION 44
271274

272275
/** The node ID of the root inode */
273276
#define FUSE_ROOT_ID 1
@@ -671,6 +674,7 @@ enum fuse_notify_code {
671674
FUSE_NOTIFY_RETRIEVE = 5,
672675
FUSE_NOTIFY_DELETE = 6,
673676
FUSE_NOTIFY_RESEND = 7,
677+
FUSE_NOTIFY_INC_EPOCH = 8,
674678
FUSE_NOTIFY_CODE_MAX,
675679
};
676680

0 commit comments

Comments
 (0)