aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-12-11 16:02:59 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-17 11:59:15 -0500
commit19bbb926203dbcf3a03915e934c36d7681bf6e13 (patch)
treeef08b67839bb7d4265c397e40a5eab01da7bf1cf /fs/kernfs
parent47a52e91f485dfd935042dbd2f66df1ac3fdfbb9 (diff)
kernfs: allow negative dentries
kernfs doesn't allow negative dentries - kernfs_iop_lookup() returns ERR_PTR(-ENOENT) instead of NULL which short-circuits negative dentry creation and kernfs's d_delete() callback, kernfs_dop_delete(), returns 1 for all removed nodes. This in turn allows kernfs_dop_revalidate() to assume that there's no negative dentry for kernfs. This worked fine for sysfs but kernfs is scheduled to grow mkdir(2) support which depend on negative dentries. This patch updates so that kernfs allows negative dentries. The required changes are almost trivial - kernfs_iop_lookup() now returns NULL instead of ERR_PTR(-ENOENT) when the target kernfs_node doesn't exist, kernfs_dop_delete() is removed and kernfs_dop_revalidate() is updated to check whether the target dentry is negative and request fresh lookup if so. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c37
1 files changed, 13 insertions, 24 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index d33af95321fb..42c5b9f23b41 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -264,12 +264,6 @@ void kernfs_put(struct kernfs_node *kn)
264} 264}
265EXPORT_SYMBOL_GPL(kernfs_put); 265EXPORT_SYMBOL_GPL(kernfs_put);
266 266
267static int kernfs_dop_delete(const struct dentry *dentry)
268{
269 struct kernfs_node *kn = dentry->d_fsdata;
270 return !(kn && !(kn->flags & KERNFS_REMOVED));
271}
272
273static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) 267static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
274{ 268{
275 struct kernfs_node *kn; 269 struct kernfs_node *kn;
@@ -277,6 +271,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
277 if (flags & LOOKUP_RCU) 271 if (flags & LOOKUP_RCU)
278 return -ECHILD; 272 return -ECHILD;
279 273
274 /* Always perform fresh lookup for negatives */
275 if (!dentry->d_inode)
276 goto out_bad_unlocked;
277
280 kn = dentry->d_fsdata; 278 kn = dentry->d_fsdata;
281 mutex_lock(&kernfs_mutex); 279 mutex_lock(&kernfs_mutex);
282 280
@@ -301,22 +299,14 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
301out_valid: 299out_valid:
302 return 1; 300 return 1;
303out_bad: 301out_bad:
304 /*
305 * Remove the dentry from the dcache hashes.
306 * If this is a deleted dentry we use d_drop instead of d_delete
307 * so kernfs doesn't need to cope with negative dentries.
308 *
309 * If this is a dentry that has simply been renamed we
310 * use d_drop to remove it from the dcache lookup on its
311 * old parent. If this dentry persists later when a lookup
312 * is performed at its new name the dentry will be readded
313 * to the dcache hashes.
314 */
315 mutex_unlock(&kernfs_mutex); 302 mutex_unlock(&kernfs_mutex);
316 303out_bad_unlocked:
317 /* If we have submounts we must allow the vfs caches 304 /*
318 * to lie about the state of the filesystem to prevent 305 * @dentry doesn't match the underlying kernfs node, drop the
319 * leaks and other nasty things. 306 * dentry and force lookup. If we have submounts we must allow the
307 * vfs caches to lie about the state of the filesystem to prevent
308 * leaks and other nasty things, so use check_submounts_and_drop()
309 * instead of d_drop().
320 */ 310 */
321 if (check_submounts_and_drop(dentry) != 0) 311 if (check_submounts_and_drop(dentry) != 0)
322 goto out_valid; 312 goto out_valid;
@@ -331,7 +321,6 @@ static void kernfs_dop_release(struct dentry *dentry)
331 321
332const struct dentry_operations kernfs_dops = { 322const struct dentry_operations kernfs_dops = {
333 .d_revalidate = kernfs_dop_revalidate, 323 .d_revalidate = kernfs_dop_revalidate,
334 .d_delete = kernfs_dop_delete,
335 .d_release = kernfs_dop_release, 324 .d_release = kernfs_dop_release,
336}; 325};
337 326
@@ -682,7 +671,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
682 struct dentry *dentry, 671 struct dentry *dentry,
683 unsigned int flags) 672 unsigned int flags)
684{ 673{
685 struct dentry *ret = NULL; 674 struct dentry *ret;
686 struct kernfs_node *parent = dentry->d_parent->d_fsdata; 675 struct kernfs_node *parent = dentry->d_parent->d_fsdata;
687 struct kernfs_node *kn; 676 struct kernfs_node *kn;
688 struct inode *inode; 677 struct inode *inode;
@@ -697,7 +686,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
697 686
698 /* no such entry */ 687 /* no such entry */
699 if (!kn) { 688 if (!kn) {
700 ret = ERR_PTR(-ENOENT); 689 ret = NULL;
701 goto out_unlock; 690 goto out_unlock;
702 } 691 }
703 kernfs_get(kn); 692 kernfs_get(kn);