Skip to content

Commit 49720b5

Browse files
committed
fuse: invalidate inode aliases when doing inode invalidation
Add support to invalidate inode aliases when doing inode invalidation. This is useful for distributed file systems, which use DLM for cache coherency. So, when a client losts its inode lock, it should invalidate its inode cache and dentry cache since the other client may delete this file after getting inode lock. Signed-off-by: Yong Ze Chen <yochen@ddn.com>
1 parent 1157436 commit 49720b5

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)