aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p/fid.c
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2005-09-28 00:45:24 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-28 10:46:40 -0400
commit0b8dd17762194ec77066d339e0b2866b0c66b715 (patch)
tree710bb489487c83fc03008228080d47f08662cc9f /fs/9p/fid.c
parentdc7b5fd6b0d3beb41f9e5e3a94dd1eadf52209f3 (diff)
[PATCH] v9fs: fix races in fid allocation
Fid management cleanup. The patch attempts to fix the races in dentry's fid management. Dentries don't keep the opened fids anymore, they are moved to the file structs. Ideally there should be no more than one fid with fidcreate equal to zero in the dentry's list of fids. v9fs_fid_create initializes the important fields (fid, fidcreated) before v9fs_fid is added to the list. v9fs_fid_lookup returns only fids that are not created by v9fs_create. v9fs_fid_get_created returns the fid created by the same process by v9fs_create (if any) and removes it from dentry's list Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Cc: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p/fid.c')
-rw-r--r--fs/9p/fid.c176
1 files changed, 95 insertions, 81 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 821c9c4d76aa..d95f8626d170 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -71,21 +71,28 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
71 * 71 *
72 */ 72 */
73 73
74struct v9fs_fid *v9fs_fid_create(struct dentry *dentry) 74struct v9fs_fid *v9fs_fid_create(struct dentry *dentry,
75 struct v9fs_session_info *v9ses, int fid, int create)
75{ 76{
76 struct v9fs_fid *new; 77 struct v9fs_fid *new;
77 78
79 dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n",
80 dentry, fid, create);
81
78 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 82 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
79 if (new == NULL) { 83 if (new == NULL) {
80 dprintk(DEBUG_ERROR, "Out of Memory\n"); 84 dprintk(DEBUG_ERROR, "Out of Memory\n");
81 return ERR_PTR(-ENOMEM); 85 return ERR_PTR(-ENOMEM);
82 } 86 }
83 87
84 new->fid = -1; 88 new->fid = fid;
89 new->v9ses = v9ses;
85 new->fidopen = 0; 90 new->fidopen = 0;
86 new->fidcreate = 0; 91 new->fidcreate = create;
87 new->fidclunked = 0; 92 new->fidclunked = 0;
88 new->iounit = 0; 93 new->iounit = 0;
94 new->rdir_pos = 0;
95 new->rdir_fcall = NULL;
89 96
90 if (v9fs_fid_insert(new, dentry) == 0) 97 if (v9fs_fid_insert(new, dentry) == 0)
91 return new; 98 return new;
@@ -109,6 +116,59 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
109} 116}
110 117
111/** 118/**
119 * v9fs_fid_walk_up - walks from the process current directory
120 * up to the specified dentry.
121 */
122static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
123{
124 int fidnum, cfidnum, err;
125 struct v9fs_fid *cfid;
126 struct dentry *cde;
127 struct v9fs_session_info *v9ses;
128
129 v9ses = v9fs_inode2v9ses(current->fs->pwd->d_inode);
130 cfid = v9fs_fid_lookup(current->fs->pwd);
131 if (cfid == NULL) {
132 dprintk(DEBUG_ERROR, "process cwd doesn't have a fid\n");
133 return ERR_PTR(-ENOENT);
134 }
135
136 cfidnum = cfid->fid;
137 cde = current->fs->pwd;
138 /* TODO: take advantage of multiwalk */
139
140 fidnum = v9fs_get_idpool(&v9ses->fidpool);
141 if (fidnum < 0) {
142 dprintk(DEBUG_ERROR, "could not get a new fid num\n");
143 err = -ENOENT;
144 goto clunk_fid;
145 }
146
147 while (cde != dentry) {
148 if (cde == cde->d_parent) {
149 dprintk(DEBUG_ERROR, "can't find dentry\n");
150 err = -ENOENT;
151 goto clunk_fid;
152 }
153
154 err = v9fs_t_walk(v9ses, cfidnum, fidnum, "..", NULL);
155 if (err < 0) {
156 dprintk(DEBUG_ERROR, "problem walking to parent\n");
157 goto clunk_fid;
158 }
159
160 cfidnum = fidnum;
161 cde = cde->d_parent;
162 }
163
164 return v9fs_fid_create(dentry, v9ses, fidnum, 0);
165
166clunk_fid:
167 v9fs_t_clunk(v9ses, fidnum, NULL);
168 return ERR_PTR(err);
169}
170
171/**
112 * v9fs_fid_lookup - retrieve the right fid from a particular dentry 172 * v9fs_fid_lookup - retrieve the right fid from a particular dentry
113 * @dentry: dentry to look for fid in 173 * @dentry: dentry to look for fid in
114 * @type: intent of lookup (operation or traversal) 174 * @type: intent of lookup (operation or traversal)
@@ -119,49 +179,25 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
119 * 179 *
120 */ 180 */
121 181
122struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) 182struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
123{ 183{
124 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; 184 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
125 struct v9fs_fid *current_fid = NULL; 185 struct v9fs_fid *current_fid = NULL;
126 struct v9fs_fid *temp = NULL; 186 struct v9fs_fid *temp = NULL;
127 struct v9fs_fid *return_fid = NULL; 187 struct v9fs_fid *return_fid = NULL;
128 int found_parent = 0;
129 int found_user = 0;
130 188
131 dprintk(DEBUG_9P, " dentry: %s (%p) type %d\n", dentry->d_iname, dentry, 189 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
132 type);
133 190
134 if (fid_list && !list_empty(fid_list)) { 191 if (fid_list) {
135 list_for_each_entry_safe(current_fid, temp, fid_list, list) { 192 list_for_each_entry_safe(current_fid, temp, fid_list, list) {
136 if (current_fid->uid == current->uid) { 193 if (!current_fid->fidcreate) {
137 if (return_fid == NULL) { 194 return_fid = current_fid;
138 if ((type == FID_OP) 195 break;
139 || (!current_fid->fidopen)) {
140 return_fid = current_fid;
141 found_user = 1;
142 }
143 }
144 }
145 if (current_fid->pid == current->real_parent->pid) {
146 if ((return_fid == NULL) || (found_parent)
147 || (found_user)) {
148 if ((type == FID_OP)
149 || (!current_fid->fidopen)) {
150 return_fid = current_fid;
151 found_parent = 1;
152 found_user = 0;
153 }
154 }
155 }
156 if (current_fid->pid == current->pid) {
157 if ((type == FID_OP) ||
158 (!current_fid->fidopen)) {
159 return_fid = current_fid;
160 found_parent = 0;
161 found_user = 0;
162 }
163 } 196 }
164 } 197 }
198
199 if (!return_fid)
200 return_fid = current_fid;
165 } 201 }
166 202
167 /* we are at the root but didn't match */ 203 /* we are at the root but didn't match */
@@ -187,55 +223,33 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type)
187 223
188/* XXX - there may be some duplication we can get rid of */ 224/* XXX - there may be some duplication we can get rid of */
189 if (par == dentry) { 225 if (par == dentry) {
190 /* we need to fid_lookup the starting point */ 226 return_fid = v9fs_fid_walk_up(dentry);
191 int fidnum = -1; 227 if (IS_ERR(return_fid))
192 int oldfid = -1; 228 return_fid = NULL;
193 int result = -1; 229 }
194 struct v9fs_session_info *v9ses = 230 }
195 v9fs_inode2v9ses(current->fs->pwd->d_inode);
196
197 current_fid =
198 v9fs_fid_lookup(current->fs->pwd, FID_WALK);
199 if (current_fid == NULL) {
200 dprintk(DEBUG_ERROR,
201 "process cwd doesn't have a fid\n");
202 return return_fid;
203 }
204 oldfid = current_fid->fid;
205 par = current->fs->pwd;
206 /* TODO: take advantage of multiwalk */
207 231
208 fidnum = v9fs_get_idpool(&v9ses->fidpool); 232 return return_fid;
209 if (fidnum < 0) { 233}
210 dprintk(DEBUG_ERROR,
211 "could not get a new fid num\n");
212 return return_fid;
213 }
214 234
215 while (par != dentry) { 235struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry)
216 result = 236{
217 v9fs_t_walk(v9ses, oldfid, fidnum, "..", 237 struct list_head *fid_list;
218 NULL); 238 struct v9fs_fid *fid, *ftmp, *ret;
219 if (result < 0) { 239
220 dprintk(DEBUG_ERROR, 240 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
221 "problem walking to parent\n"); 241 fid_list = (struct list_head *)dentry->d_fsdata;
222 242 ret = NULL;
223 break; 243 if (fid_list) {
224 } 244 list_for_each_entry_safe(fid, ftmp, fid_list, list) {
225 oldfid = fidnum; 245 if (fid->fidcreate && fid->pid == current->pid) {
226 if (par == par->d_parent) { 246 list_del(&fid->list);
227 dprintk(DEBUG_ERROR, 247 ret = fid;
228 "can't find dentry\n"); 248 break;
229 break;
230 }
231 par = par->d_parent;
232 }
233 if (par == dentry) {
234 return_fid = v9fs_fid_create(dentry);
235 return_fid->fid = fidnum;
236 } 249 }
237 } 250 }
238 } 251 }
239 252
240 return return_fid; 253 dprintk(DEBUG_9P, "return %p\n", ret);
254 return ret;
241} 255}