diff options
-rw-r--r-- | fs/internal.h | 1 | ||||
-rw-r--r-- | fs/libfs.c | 29 | ||||
-rw-r--r-- | fs/nsfs.c | 16 | ||||
-rw-r--r-- | fs/pidfs.c | 13 |
4 files changed, 31 insertions, 28 deletions
diff --git a/fs/internal.h b/fs/internal.h index a34531bcad6e..b0c843c3fa3c 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -314,3 +314,4 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino, struct vfsmount *mnt, const struct file_operations *fops, const struct inode_operations *iops, void *data, struct path *path); +void stashed_dentry_prune(struct dentry *dentry); diff --git a/fs/libfs.c b/fs/libfs.c index 7617e1bc6e5b..472f21bd0325 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1988,7 +1988,8 @@ static inline struct dentry *get_stashed_dentry(struct dentry *stashed) return dentry; } -static struct dentry *prepare_anon_dentry(unsigned long ino, +static struct dentry *prepare_anon_dentry(struct dentry **stashed, + unsigned long ino, struct super_block *sb, const struct file_operations *fops, const struct inode_operations *iops, @@ -2019,6 +2020,9 @@ static struct dentry *prepare_anon_dentry(unsigned long ino, inode->i_private = data; simple_inode_init_ts(inode); + /* Store address of location where dentry's supposed to be stashed. */ + dentry->d_fsdata = stashed; + /* @data is now owned by the fs */ d_instantiate(dentry, inode); return dentry; @@ -2081,7 +2085,7 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino, goto out_path; /* Allocate a new dentry. */ - dentry = prepare_anon_dentry(ino, mnt->mnt_sb, fops, iops, data); + dentry = prepare_anon_dentry(stashed, ino, mnt->mnt_sb, fops, iops, data); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -2092,6 +2096,27 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino, ret = 1; out_path: + WARN_ON_ONCE(path->dentry->d_fsdata != stashed); + WARN_ON_ONCE(d_inode(path->dentry)->i_private != data); path->mnt = mntget(mnt); return ret; } + +void stashed_dentry_prune(struct dentry *dentry) +{ + struct dentry **stashed = dentry->d_fsdata; + struct inode *inode = d_inode(dentry); + + if (WARN_ON_ONCE(!stashed)) + return; + + if (!inode) + return; + + /* + * Only replace our own @dentry as someone else might've + * already cleared out @dentry and stashed their own + * dentry in there. + */ + cmpxchg(stashed, dentry, NULL); +} diff --git a/fs/nsfs.c b/fs/nsfs.c index 3a36bb62353c..2ce229af34e9 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -34,22 +34,10 @@ static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) ns_ops->name, inode->i_ino); } -static void ns_prune_dentry(struct dentry *dentry) -{ - struct inode *inode; - - inode = d_inode(dentry); - if (inode) { - struct ns_common *ns = inode->i_private; - cmpxchg(&ns->stashed, dentry, NULL); - } -} - -const struct dentry_operations ns_dentry_operations = -{ - .d_prune = ns_prune_dentry, +const struct dentry_operations ns_dentry_operations = { .d_delete = always_delete_dentry, .d_dname = ns_dname, + .d_prune = stashed_dentry_prune, }; static void nsfs_evict(struct inode *inode) diff --git a/fs/pidfs.c b/fs/pidfs.c index 5f33c820b7f8..d38b7a184994 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -187,21 +187,10 @@ static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen) d_inode(dentry)->i_ino); } -static void pidfs_prune_dentry(struct dentry *dentry) -{ - struct inode *inode; - - inode = d_inode(dentry); - if (inode) { - struct pid *pid = inode->i_private; - cmpxchg(&pid->stashed, dentry, NULL); - } -} - static const struct dentry_operations pidfs_dentry_operations = { .d_delete = always_delete_dentry, .d_dname = pidfs_dname, - .d_prune = pidfs_prune_dentry, + .d_prune = stashed_dentry_prune, }; static int pidfs_init_fs_context(struct fs_context *fc) |