Skip to content

Commit c3a0e13

Browse files
authored
Merge pull request #8 from yongzech/FUSE_DENTRY_INVAL
fuse: invalidate inode aliases when doing inode invalidation
2 parents 1157436 + 49720b5 commit c3a0e13

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

fs/fuse/fuse_i.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,12 @@ struct fuse_conn {
723723
*/
724724
unsigned handle_killpriv_v2:1;
725725

726+
/* invalidate inode entries when doing inode invalidation */
727+
unsigned inval_inode_entries:1;
728+
729+
/* expire inode entries when doing inode invalidation */
730+
unsigned expire_inode_entries:1;
731+
726732
/*
727733
* The following bitfields are only for optimization purposes
728734
* and hence races in setting them will not cause malfunction

fs/fuse/inode.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,45 @@ struct inode *fuse_ilookup(struct fuse_conn *fc, u64 nodeid,
542542
return NULL;
543543
}
544544

545+
static void fuse_prune_aliases(struct inode *inode)
546+
{
547+
struct dentry *dentry;
548+
549+
spin_lock(&inode->i_lock);
550+
hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
551+
fuse_invalidate_entry_cache(dentry);
552+
}
553+
spin_unlock(&inode->i_lock);
554+
555+
d_prune_aliases(inode);
556+
}
557+
558+
static void fuse_invalidate_inode_entry(struct inode *inode)
559+
{
560+
struct dentry *dentry;
561+
562+
if (S_ISDIR(inode->i_mode)) {
563+
/* For directories, use d_invalidate to handle children and submounts */
564+
dentry = d_find_alias(inode);
565+
if (dentry) {
566+
d_invalidate(dentry);
567+
fuse_invalidate_entry_cache(dentry);
568+
dput(dentry);
569+
}
570+
} else {
571+
/* For regular files, just unhash the dentry */
572+
spin_lock(&inode->i_lock);
573+
hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
574+
spin_lock(&dentry->d_lock);
575+
if (!d_unhashed(dentry))
576+
__d_drop(dentry);
577+
spin_unlock(&dentry->d_lock);
578+
fuse_invalidate_entry_cache(dentry);
579+
}
580+
spin_unlock(&inode->i_lock);
581+
}
582+
}
583+
545584
int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
546585
loff_t offset, loff_t len)
547586
{
@@ -559,6 +598,11 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
559598
fi->attr_version = atomic64_inc_return(&fc->attr_version);
560599
spin_unlock(&fi->lock);
561600

601+
if (fc->inval_inode_entries)
602+
fuse_invalidate_inode_entry(inode);
603+
else if (fc->expire_inode_entries)
604+
fuse_prune_aliases(inode);
605+
562606
fuse_invalidate_attr(inode);
563607
forget_all_cached_acls(inode);
564608
if (offset >= 0) {
@@ -1374,6 +1418,10 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
13741418
fc->io_uring = 1;
13751419
if (flags & FUSE_NO_EXPORT_SUPPORT)
13761420
fm->sb->s_export_op = &fuse_export_fid_operations;
1421+
if (flags & FUSE_INVAL_INODE_ENTRY)
1422+
fc->inval_inode_entries = 1;
1423+
if (flags & FUSE_EXPIRE_INODE_ENTRY)
1424+
fc->expire_inode_entries = 1;
13771425
} else {
13781426
ra_pages = fc->max_read / PAGE_SIZE;
13791427
fc->no_lock = 1;
@@ -1424,7 +1472,7 @@ void fuse_send_init(struct fuse_mount *fm)
14241472
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
14251473
FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
14261474
FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
1427-
FUSE_NO_EXPORT_SUPPORT;
1475+
FUSE_NO_EXPORT_SUPPORT | FUSE_INVAL_INODE_ENTRY | FUSE_EXPIRE_INODE_ENTRY;
14281476
#ifdef CONFIG_FUSE_DAX
14291477
if (fm->fc->dax)
14301478
flags |= FUSE_MAP_ALIGNMENT;

include/uapi/linux/fuse.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,8 @@ struct fuse_file_lock {
427427
* FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode.
428428
* FUSE_NO_EXPORT_SUPPORT: explicitly disable export support
429429
* FUSE_OVER_IO_URING: Indicate that client supports io-uring
430+
* FUSE_INVAL_INODE_ENTRY: invalidate inode aliases when doing inode invalidation
431+
* FUSE_EXPIRE_INODE_ENTRY: expire inode aliases when doing inode invalidation
430432
*/
431433
#define FUSE_ASYNC_READ (1 << 0)
432434
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -471,6 +473,8 @@ struct fuse_file_lock {
471473
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
472474
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
473475
#define FUSE_OVER_IO_URING (1ULL << 41)
476+
#define FUSE_INVAL_INODE_ENTRY (1ULL << 60)
477+
#define FUSE_EXPIRE_INODE_ENTRY (1ULL << 61)
474478

475479
/**
476480
* CUSE INIT request/reply flags

0 commit comments

Comments
 (0)