Skip to content

Commit 4d4ed3f

Browse files
hbirthbsbernd
authored andcommitted
fuse: fix inode initialization race
Fix a race between fuse_iget() and fuse_reverse_inval_inode() where invalidation can arrive while an inode is being initialized, causing the invalidation to be lost. Add a waitqueue to make fuse_reverse_inval_inode() wait when it encounters an inode with attr_version == 0 (still initializing). When fuse_change_attributes_common() completes initialization, it wakes waiting threads. This ensures invalidations are properly serialized with inode initialization, maintaining cache coherency. Signed-off-by: Horst Birthelmer <hbirthelmer@ddn.com> (cherry picked from commit 03eacfd)
1 parent ccaf499 commit 4d4ed3f

2 files changed

Lines changed: 13 additions & 1 deletion

File tree

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,9 @@ struct fuse_conn {
895895
/** Version counter for attribute changes */
896896
atomic64_t attr_version;
897897

898+
/** Waitqueue for attr_version initialization */
899+
wait_queue_head_t attr_version_waitq;
900+
898901
/** Version counter for evict inode */
899902
atomic64_t evict_ctr;
900903

fs/fuse/inode.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
242242
set_mask_bits(&fi->inval_mask, STATX_BASIC_STATS, 0);
243243

244244
fi->attr_version = atomic64_inc_return(&fc->attr_version);
245+
wake_up_all(&fc->attr_version_waitq);
245246
fi->i_time = attr_valid;
246247

247248
inode->i_ino = fuse_squash_ino(attr->ino);
@@ -604,10 +605,17 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
604605
return -ENOENT;
605606

606607
fi = get_fuse_inode(inode);
608+
607609
spin_lock(&fi->lock);
610+
while (fi->attr_version == 0) {
611+
spin_unlock(&fi->lock);
612+
wait_event(fc->attr_version_waitq, READ_ONCE(fi->attr_version) != 0);
613+
spin_lock(&fi->lock);
614+
}
615+
608616
fi->attr_version = atomic64_inc_return(&fc->attr_version);
609617
spin_unlock(&fi->lock);
610-
618+
611619
if (fc->inval_inode_entries)
612620
fuse_invalidate_inode_entry(inode);
613621
else if (fc->expire_inode_entries)
@@ -1024,6 +1032,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
10241032
refcount_set(&fc->count, 1);
10251033
atomic_set(&fc->dev_count, 1);
10261034
init_waitqueue_head(&fc->blocked_waitq);
1035+
init_waitqueue_head(&fc->attr_version_waitq);
10271036
fuse_iqueue_init(&fc->iq, fiq_ops, fiq_priv);
10281037
INIT_LIST_HEAD(&fc->bg_queue);
10291038
INIT_LIST_HEAD(&fc->entry);

0 commit comments

Comments
 (0)