diff options
| -rw-r--r-- | fs/fuse/dev.c | 7 | ||||
| -rw-r--r-- | fs/fuse/dir.c | 21 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 4 | ||||
| -rw-r--r-- | fs/fuse/inode.c | 2 |
4 files changed, 31 insertions, 3 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 49b18d7accb3..6d59cbc877c6 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2041,13 +2041,14 @@ static int fuse_notify_resend(struct fuse_conn *fc) /* * Increments the fuse connection epoch. This will result of dentries from - * previous epochs to be invalidated. - * - * XXX optimization: add call to shrink_dcache_sb()? + * previous epochs to be invalidated. Additionally, if inval_wq is set, a work + * queue is scheduled to trigger the invalidation. */ static int fuse_notify_inc_epoch(struct fuse_conn *fc) { atomic_inc(&fc->epoch); + if (inval_wq) + schedule_work(&fc->epoch_work); return 0; } diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 77982fdbcf27..8ef8134e1cd5 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -189,6 +189,27 @@ static void fuse_dentry_tree_work(struct work_struct *work) secs_to_jiffies(inval_wq)); } +void fuse_epoch_work(struct work_struct *work) +{ + struct fuse_conn *fc = container_of(work, struct fuse_conn, + epoch_work); + struct fuse_mount *fm; + struct inode *inode; + + down_read(&fc->killsb); + + inode = fuse_ilookup(fc, FUSE_ROOT_ID, &fm); + iput(inode); + + if (fm) { + /* Remove all possible active references to cached inodes */ + shrink_dcache_sb(fm->sb); + } else + pr_warn("Failed to get root inode"); + + up_read(&fc->killsb); +} + void fuse_dentry_tree_init(void) { int i; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index ac717b3b46a1..a80411028254 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -649,6 +649,8 @@ struct fuse_conn { /** Current epoch for up-to-date dentries */ atomic_t epoch; + struct work_struct epoch_work; + struct rcu_head rcu; /** The user id for this mount */ @@ -1287,6 +1289,8 @@ void fuse_check_timeout(struct work_struct *work); void fuse_dentry_tree_init(void); void fuse_dentry_tree_cleanup(void); +void fuse_epoch_work(struct work_struct *work); + /** * Invalidate inode attributes */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 793f1766ae5a..3087165a6004 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -977,6 +977,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm, refcount_set(&fc->count, 1); atomic_set(&fc->dev_count, 1); atomic_set(&fc->epoch, 1); + INIT_WORK(&fc->epoch_work, fuse_epoch_work); init_waitqueue_head(&fc->blocked_waitq); fuse_iqueue_init(&fc->iq, fiq_ops, fiq_priv); INIT_LIST_HEAD(&fc->bg_queue); @@ -1029,6 +1030,7 @@ void fuse_conn_put(struct fuse_conn *fc) fuse_dax_conn_free(fc); if (fc->timeout.req_timeout) cancel_delayed_work_sync(&fc->timeout.work); + cancel_work_sync(&fc->epoch_work); if (fiq->ops->release) fiq->ops->release(fiq); put_pid_ns(fc->pid_ns); |
