[PATCH] v9fs: simplify fid mapping

v9fs has been plagued by an over-complicated approach trying to map Linux
dentry semantics to Plan 9 fid semantics. Our previous approach called for
aggressive flushing of the dcache resulting in several problems (including
wierd cwd behavior when running /bin/pwd).

This patch dramatically simplifies our handling of this fid management. Fids
will not be clunked as promptly, but the new approach is more functionally
correct. We now clunk un-open fids only when their dentry ref_count reaches 0
(and d_delete is called).

Another simplification is we no longer seek to match fids to the process-id or
uid of the action initiator. The uid-matching will need to be revisited when
we fix the security model.

Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Eric Van Hensbergen and committed by Linus Torvalds 46f6dac2 74b8054c

+15 -126
+6 -88
fs/9p/fid.c
··· 1 /* 2 * V9FS FID Management 3 * 4 - * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by ··· 57 } 58 59 fid->uid = current->uid; 60 - fid->pid = current->pid; 61 list_add(&fid->list, fid_list); 62 return 0; 63 } ··· 87 new->rdir_fcall = NULL; 88 INIT_LIST_HEAD(&new->list); 89 90 - return new; 91 } 92 93 /** ··· 103 } 104 105 /** 106 - * v9fs_fid_walk_up - walks from the process current directory 107 - * up to the specified dentry. 108 - */ 109 - static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) 110 - { 111 - int fidnum, cfidnum, err; 112 - struct v9fs_fid *cfid, *fid; 113 - struct dentry *cde; 114 - struct v9fs_session_info *v9ses; 115 - 116 - v9ses = v9fs_inode2v9ses(current->fs->pwd->d_inode); 117 - cfid = v9fs_fid_lookup(current->fs->pwd); 118 - if (cfid == NULL) { 119 - dprintk(DEBUG_ERROR, "process cwd doesn't have a fid\n"); 120 - return ERR_PTR(-ENOENT); 121 - } 122 - 123 - cfidnum = cfid->fid; 124 - cde = current->fs->pwd; 125 - /* TODO: take advantage of multiwalk */ 126 - 127 - fidnum = v9fs_get_idpool(&v9ses->fidpool); 128 - if (fidnum < 0) { 129 - dprintk(DEBUG_ERROR, "could not get a new fid num\n"); 130 - err = -ENOENT; 131 - goto clunk_fid; 132 - } 133 - 134 - while (cde != dentry) { 135 - if (cde == cde->d_parent) { 136 - dprintk(DEBUG_ERROR, "can't find dentry\n"); 137 - err = -ENOENT; 138 - goto clunk_fid; 139 - } 140 - 141 - err = v9fs_t_walk(v9ses, cfidnum, fidnum, "..", NULL); 142 - if (err < 0) { 143 - dprintk(DEBUG_ERROR, "problem walking to parent\n"); 144 - goto clunk_fid; 145 - } 146 - 147 - cfidnum = fidnum; 148 - cde = cde->d_parent; 149 - } 150 - 151 - fid = v9fs_fid_create(v9ses, fidnum); 152 - if (fid) { 153 - err = v9fs_fid_insert(fid, dentry); 154 - if (err < 0) { 155 - kfree(fid); 156 - goto clunk_fid; 157 - } 158 - } 159 - 160 - return fid; 161 - 162 - clunk_fid: 163 - v9fs_t_clunk(v9ses, fidnum); 164 - return ERR_PTR(err); 165 - } 166 - 167 - /** 168 * v9fs_fid_lookup - retrieve the right fid from a particular dentry 169 * @dentry: dentry to look for fid in 170 * @type: intent of lookup (operation or traversal) 171 * 172 - * search list of fids associated with a dentry for a fid with a matching 173 - * thread id or uid. If that fails, look up the dentry's parents to see if you 174 - * can find a matching fid. 175 * 176 */ 177 ··· 124 return_fid = list_entry(fid_list->next, struct v9fs_fid, list); 125 126 if (!return_fid) { 127 - struct dentry *par = current->fs->pwd->d_parent; 128 - int count = 1; 129 - while (par != NULL) { 130 - if (par == dentry) 131 - break; 132 - count++; 133 - if (par == par->d_parent) { 134 - dprintk(DEBUG_ERROR, 135 - "got to root without finding dentry\n"); 136 - break; 137 - } 138 - par = par->d_parent; 139 - } 140 - 141 - /* XXX - there may be some duplication we can get rid of */ 142 - if (par == dentry) { 143 - return_fid = v9fs_fid_walk_up(dentry); 144 - if (IS_ERR(return_fid)) 145 - return_fid = NULL; 146 - } 147 } 148 149 return return_fid;
··· 1 /* 2 * V9FS FID Management 3 * 4 + * Copyright (C) 2005, 2006 by Eric Van Hensbergen <ericvh@gmail.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by ··· 57 } 58 59 fid->uid = current->uid; 60 list_add(&fid->list, fid_list); 61 return 0; 62 } ··· 88 new->rdir_fcall = NULL; 89 INIT_LIST_HEAD(&new->list); 90 91 + return new; 92 } 93 94 /** ··· 104 } 105 106 /** 107 * v9fs_fid_lookup - retrieve the right fid from a particular dentry 108 * @dentry: dentry to look for fid in 109 * @type: intent of lookup (operation or traversal) 110 * 111 + * find a fid in the dentry 112 + * 113 + * TODO: only match fids that have the same uid as current user 114 * 115 */ 116 ··· 187 return_fid = list_entry(fid_list->next, struct v9fs_fid, list); 188 189 if (!return_fid) { 190 + dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n"); 191 } 192 193 return return_fid;
-1
fs/9p/fid.h
··· 44 struct v9fs_fcall *rdir_fcall; 45 46 /* management stuff */ 47 - pid_t pid; /* thread associated with this fid */ 48 uid_t uid; /* user associated with this fid */ 49 50 /* private data */
··· 44 struct v9fs_fcall *rdir_fcall; 45 46 /* management stuff */ 47 uid_t uid; /* user associated with this fid */ 48 49 /* private data */
+1
fs/9p/v9fs.c
··· 397 } 398 399 if (v9ses->afid != ~0) { 400 if (v9fs_t_clunk(v9ses, v9ses->afid)) 401 dprintk(DEBUG_ERROR, "clunk failed\n"); 402 }
··· 397 } 398 399 if (v9ses->afid != ~0) { 400 + dprintk(DEBUG_ERROR, "afid not equal to ~0\n"); 401 if (v9fs_t_clunk(v9ses, v9ses->afid)) 402 dprintk(DEBUG_ERROR, "clunk failed\n"); 403 }
+8 -37
fs/9p/vfs_dentry.c
··· 43 #include "fid.h" 44 45 /** 46 - * v9fs_dentry_validate - VFS dcache hook to validate cache 47 - * @dentry: dentry that is being validated 48 - * @nd: path data 49 * 50 - * dcache really shouldn't be used for 9P2000 as at all due to 51 - * potential attached semantics to directory traversal (walk). 52 - * 53 - * FUTURE: look into how to use dcache to allow multi-stage 54 - * walks in Plan 9 & potential for better dcache operation which 55 - * would remain valid for Plan 9 semantics. Older versions 56 - * had validation via stat for those interested. However, since 57 - * stat has the same approximate overhead as walk there really 58 - * is no difference. The only improvement would be from a 59 - * time-decay cache like NFS has and that undermines the 60 - * synchronous nature of 9P2000. 61 * 62 */ 63 64 - static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) 65 { 66 - struct dentry *dc = current->fs->pwd; 67 - 68 - dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); 69 - if (v9fs_fid_lookup(dentry)) { 70 - dprintk(DEBUG_VFS, "VALID\n"); 71 - return 1; 72 - } 73 - 74 - while (dc != NULL) { 75 - if (dc == dentry) { 76 - dprintk(DEBUG_VFS, "VALID\n"); 77 - return 1; 78 - } 79 - if (dc == dc->d_parent) 80 - break; 81 - 82 - dc = dc->d_parent; 83 - } 84 - 85 - dprintk(DEBUG_VFS, "INVALID\n"); 86 - return 0; 87 } 88 89 /** ··· 89 } 90 91 struct dentry_operations v9fs_dentry_operations = { 92 - .d_revalidate = v9fs_dentry_validate, 93 .d_release = v9fs_dentry_release, 94 };
··· 43 #include "fid.h" 44 45 /** 46 + * v9fs_dentry_delete - called when dentry refcount equals 0 47 + * @dentry: dentry in question 48 * 49 + * By returning 1 here we should remove cacheing of unused 50 + * dentry components. 51 * 52 */ 53 54 + int v9fs_dentry_delete(struct dentry *dentry) 55 { 56 + dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 57 + return 1; 58 } 59 60 /** ··· 118 } 119 120 struct dentry_operations v9fs_dentry_operations = { 121 + .d_delete = v9fs_dentry_delete, 122 .d_release = v9fs_dentry_release, 123 };