diff options
Diffstat (limited to 'fs/9p/vfs_dentry.c')
| -rw-r--r-- | fs/9p/vfs_dentry.c | 128 |
1 files changed, 62 insertions, 66 deletions
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index a6aa947de0f..b03dd23feda 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -7,9 +7,8 @@ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,59 +30,31 @@ #include <linux/pagemap.h> #include <linux/stat.h> #include <linux/string.h> -#include <linux/smp_lock.h> #include <linux/inet.h> #include <linux/namei.h> #include <linux/idr.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <net/9p/9p.h> +#include <net/9p/client.h> -#include "debug.h" #include "v9fs.h" -#include "9p.h" #include "v9fs_vfs.h" -#include "conv.h" #include "fid.h" /** - * v9fs_dentry_validate - VFS dcache hook to validate cache - * @dentry: dentry that is being validated - * @nd: path data - * - * dcache really shouldn't be used for 9P2000 as at all due to - * potential attached semantics to directory traversal (walk). - * - * FUTURE: look into how to use dcache to allow multi-stage - * walks in Plan 9 & potential for better dcache operation which - * would remain valid for Plan 9 semantics. Older versions - * had validation via stat for those interested. However, since - * stat has the same approximate overhead as walk there really - * is no difference. The only improvement would be from a - * time-decay cache like NFS has and that undermines the - * synchronous nature of 9P2000. + * v9fs_cached_dentry_delete - called when dentry refcount equals 0 + * @dentry: dentry in question * */ - -static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) +static int v9fs_cached_dentry_delete(const struct dentry *dentry) { - struct dentry *dc = current->fs->pwd; + p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", + dentry->d_name.name, dentry); - dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); - if (v9fs_fid_lookup(dentry)) { - dprintk(DEBUG_VFS, "VALID\n"); + /* Don't cache negative dentries */ + if (!dentry->d_inode) return 1; - } - - while (dc != NULL) { - if (dc == dentry) { - dprintk(DEBUG_VFS, "VALID\n"); - return 1; - } - if (dc == dc->d_parent) - break; - - dc = dc->d_parent; - } - - dprintk(DEBUG_VFS, "INVALID\n"); return 0; } @@ -93,34 +64,59 @@ static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) * */ -void v9fs_dentry_release(struct dentry *dentry) +static void v9fs_dentry_release(struct dentry *dentry) { - dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); - - if (dentry->d_fsdata != NULL) { - struct list_head *fid_list = dentry->d_fsdata; - struct v9fs_fid *temp = NULL; - struct v9fs_fid *current_fid = NULL; - struct v9fs_fcall *fcall = NULL; - - list_for_each_entry_safe(current_fid, temp, fid_list, list) { - if (v9fs_t_clunk - (current_fid->v9ses, current_fid->fid, &fcall)) - dprintk(DEBUG_ERROR, "clunk failed: %s\n", - FCALL_ERROR(fcall)); - - v9fs_put_idpool(current_fid->fid, - ¤t_fid->v9ses->fidpool); - - kfree(fcall); - v9fs_fid_destroy(current_fid); - } + struct hlist_node *p, *n; + p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", + dentry->d_name.name, dentry); + hlist_for_each_safe(p, n, (struct hlist_head *)&dentry->d_fsdata) + p9_client_clunk(hlist_entry(p, struct p9_fid, dlist)); + dentry->d_fsdata = NULL; +} - kfree(dentry->d_fsdata); /* free the list_head */ +static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags) +{ + struct p9_fid *fid; + struct inode *inode; + struct v9fs_inode *v9inode; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + inode = dentry->d_inode; + if (!inode) + goto out_valid; + + v9inode = V9FS_I(inode); + if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) { + int retval; + struct v9fs_session_info *v9ses; + fid = v9fs_fid_lookup(dentry); + if (IS_ERR(fid)) + return PTR_ERR(fid); + + v9ses = v9fs_inode2v9ses(inode); + if (v9fs_proto_dotl(v9ses)) + retval = v9fs_refresh_inode_dotl(fid, inode); + else + retval = v9fs_refresh_inode(fid, inode); + if (retval == -ENOENT) + return 0; + if (retval < 0) + return retval; } +out_valid: + return 1; } -struct dentry_operations v9fs_dentry_operations = { - .d_revalidate = v9fs_dentry_validate, +const struct dentry_operations v9fs_cached_dentry_operations = { + .d_revalidate = v9fs_lookup_revalidate, + .d_weak_revalidate = v9fs_lookup_revalidate, + .d_delete = v9fs_cached_dentry_delete, + .d_release = v9fs_dentry_release, +}; + +const struct dentry_operations v9fs_dentry_operations = { + .d_delete = always_delete_dentry, .d_release = v9fs_dentry_release, }; |
