diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2005-09-28 00:45:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-28 10:46:40 -0400 |
commit | 0b8dd17762194ec77066d339e0b2866b0c66b715 (patch) | |
tree | 710bb489487c83fc03008228080d47f08662cc9f | |
parent | dc7b5fd6b0d3beb41f9e5e3a94dd1eadf52209f3 (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>
-rw-r--r-- | fs/9p/fid.c | 176 | ||||
-rw-r--r-- | fs/9p/fid.h | 7 | ||||
-rw-r--r-- | fs/9p/vfs_dentry.c | 2 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 11 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 88 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 91 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 21 |
7 files changed, 200 insertions, 196 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 | ||
74 | struct v9fs_fid *v9fs_fid_create(struct dentry *dentry) | 74 | struct 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 | */ | ||
122 | static 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 | |||
166 | clunk_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 | ||
122 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type) | 182 | struct 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) { | 235 | struct 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 | } |
diff --git a/fs/9p/fid.h b/fs/9p/fid.h index 7db478ccca36..84c673a44c83 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #define FID_OP 0 | 26 | #define FID_OP 0 |
27 | #define FID_WALK 1 | 27 | #define FID_WALK 1 |
28 | #define FID_CREATE 2 | ||
28 | 29 | ||
29 | struct v9fs_fid { | 30 | struct v9fs_fid { |
30 | struct list_head list; /* list of fids associated with a dentry */ | 31 | struct list_head list; /* list of fids associated with a dentry */ |
@@ -52,6 +53,8 @@ struct v9fs_fid { | |||
52 | struct v9fs_session_info *v9ses; /* session info for this FID */ | 53 | struct v9fs_session_info *v9ses; /* session info for this FID */ |
53 | }; | 54 | }; |
54 | 55 | ||
55 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry, int type); | 56 | struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); |
57 | struct v9fs_fid *v9fs_fid_get_created(struct dentry *); | ||
56 | void v9fs_fid_destroy(struct v9fs_fid *fid); | 58 | void v9fs_fid_destroy(struct v9fs_fid *fid); |
57 | struct v9fs_fid *v9fs_fid_create(struct dentry *); | 59 | struct v9fs_fid *v9fs_fid_create(struct dentry *, |
60 | struct v9fs_session_info *v9ses, int fid, int create); | ||
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 306c96741f81..a6aa947de0f9 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c | |||
@@ -67,7 +67,7 @@ static int v9fs_dentry_validate(struct dentry *dentry, struct nameidata *nd) | |||
67 | struct dentry *dc = current->fs->pwd; | 67 | struct dentry *dc = current->fs->pwd; |
68 | 68 | ||
69 | dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); | 69 | dprintk(DEBUG_VFS, "dentry: %s (%p)\n", dentry->d_iname, dentry); |
70 | if (v9fs_fid_lookup(dentry, FID_OP)) { | 70 | if (v9fs_fid_lookup(dentry)) { |
71 | dprintk(DEBUG_VFS, "VALID\n"); | 71 | dprintk(DEBUG_VFS, "VALID\n"); |
72 | return 1; | 72 | return 1; |
73 | } | 73 | } |
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index c478a7384186..57a43b8feef5 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -197,21 +197,18 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) | |||
197 | filemap_fdatawait(inode->i_mapping); | 197 | filemap_fdatawait(inode->i_mapping); |
198 | 198 | ||
199 | if (fidnum >= 0) { | 199 | if (fidnum >= 0) { |
200 | fid->fidopen--; | ||
201 | dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, | 200 | dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen, |
202 | fid->fid); | 201 | fid->fid); |
203 | 202 | ||
204 | if (fid->fidopen == 0) { | 203 | if (v9fs_t_clunk(v9ses, fidnum, NULL)) |
205 | if (v9fs_t_clunk(v9ses, fidnum, NULL)) | 204 | dprintk(DEBUG_ERROR, "clunk failed\n"); |
206 | dprintk(DEBUG_ERROR, "clunk failed\n"); | ||
207 | 205 | ||
208 | v9fs_put_idpool(fid->fid, &v9ses->fidpool); | 206 | v9fs_put_idpool(fid->fid, &v9ses->fidpool); |
209 | } | ||
210 | 207 | ||
211 | kfree(fid->rdir_fcall); | 208 | kfree(fid->rdir_fcall); |
209 | kfree(fid); | ||
212 | 210 | ||
213 | filp->private_data = NULL; | 211 | filp->private_data = NULL; |
214 | v9fs_fid_destroy(fid); | ||
215 | } | 212 | } |
216 | 213 | ||
217 | d_drop(filp->f_dentry); | 214 | d_drop(filp->f_dentry); |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 1f8ae7d580ab..a4799e971d1c 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -53,30 +53,36 @@ | |||
53 | int v9fs_file_open(struct inode *inode, struct file *file) | 53 | int v9fs_file_open(struct inode *inode, struct file *file) |
54 | { | 54 | { |
55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
56 | struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK); | 56 | struct v9fs_fid *v9fid, *fid; |
57 | struct v9fs_fid *v9newfid = NULL; | ||
58 | struct v9fs_fcall *fcall = NULL; | 57 | struct v9fs_fcall *fcall = NULL; |
59 | int open_mode = 0; | 58 | int open_mode = 0; |
60 | unsigned int iounit = 0; | 59 | unsigned int iounit = 0; |
61 | int newfid = -1; | 60 | int newfid = -1; |
62 | long result = -1; | 61 | long result = -1; |
63 | 62 | ||
64 | dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file, | 63 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); |
65 | v9fid); | 64 | |
65 | v9fid = v9fs_fid_get_created(file->f_dentry); | ||
66 | if (!v9fid) | ||
67 | v9fid = v9fs_fid_lookup(file->f_dentry); | ||
66 | 68 | ||
67 | if (!v9fid) { | 69 | if (!v9fid) { |
68 | struct dentry *dentry = file->f_dentry; | ||
69 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); | 70 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); |
71 | return -EBADF; | ||
72 | } | ||
70 | 73 | ||
71 | /* XXX - some duplication from lookup, generalize later */ | 74 | if (!v9fid->fidcreate) { |
72 | /* basically vfs_lookup is too heavy weight */ | 75 | fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); |
73 | v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP); | 76 | if (fid == NULL) { |
74 | if (!v9fid) | 77 | dprintk(DEBUG_ERROR, "Out of Memory\n"); |
75 | return -EBADF; | 78 | return -ENOMEM; |
79 | } | ||
76 | 80 | ||
77 | v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); | 81 | fid->fidopen = 0; |
78 | if (!v9fid) | 82 | fid->fidcreate = 0; |
79 | return -EBADF; | 83 | fid->fidclunked = 0; |
84 | fid->iounit = 0; | ||
85 | fid->v9ses = v9ses; | ||
80 | 86 | ||
81 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 87 | newfid = v9fs_get_idpool(&v9ses->fidpool); |
82 | if (newfid < 0) { | 88 | if (newfid < 0) { |
@@ -85,58 +91,16 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
85 | } | 91 | } |
86 | 92 | ||
87 | result = | 93 | result = |
88 | v9fs_t_walk(v9ses, v9fid->fid, newfid, | 94 | v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); |
89 | (char *)file->f_dentry->d_name.name, NULL); | 95 | |
90 | if (result < 0) { | 96 | if (result < 0) { |
91 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 97 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
92 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); | 98 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); |
93 | return -EBADF; | 99 | return -EBADF; |
94 | } | 100 | } |
95 | 101 | ||
96 | v9fid = v9fs_fid_create(dentry); | 102 | fid->fid = newfid; |
97 | if (v9fid == NULL) { | 103 | v9fid = fid; |
98 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | v9fid->fid = newfid; | ||
102 | } | ||
103 | |||
104 | if (v9fid->fidcreate) { | ||
105 | /* create case */ | ||
106 | newfid = v9fid->fid; | ||
107 | iounit = v9fid->iounit; | ||
108 | v9fid->fidcreate = 0; | ||
109 | } else { | ||
110 | if (!S_ISDIR(inode->i_mode)) | ||
111 | newfid = v9fid->fid; | ||
112 | else { | ||
113 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
114 | if (newfid < 0) { | ||
115 | eprintk(KERN_WARNING, "allocation failed\n"); | ||
116 | return -ENOSPC; | ||
117 | } | ||
118 | /* This would be a somewhat critical clone */ | ||
119 | result = | ||
120 | v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, | ||
121 | &fcall); | ||
122 | if (result < 0) { | ||
123 | dprintk(DEBUG_ERROR, "clone error: %s\n", | ||
124 | FCALL_ERROR(fcall)); | ||
125 | kfree(fcall); | ||
126 | return result; | ||
127 | } | ||
128 | |||
129 | v9newfid = v9fs_fid_create(file->f_dentry); | ||
130 | v9newfid->fid = newfid; | ||
131 | v9newfid->qid = v9fid->qid; | ||
132 | v9newfid->iounit = v9fid->iounit; | ||
133 | v9newfid->fidopen = 0; | ||
134 | v9newfid->fidclunked = 0; | ||
135 | v9newfid->v9ses = v9ses; | ||
136 | v9fid = v9newfid; | ||
137 | kfree(fcall); | ||
138 | } | ||
139 | |||
140 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ | 104 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ |
141 | /* translate open mode appropriately */ | 105 | /* translate open mode appropriately */ |
142 | open_mode = file->f_flags & 0x3; | 106 | open_mode = file->f_flags & 0x3; |
@@ -163,9 +127,13 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
163 | 127 | ||
164 | iounit = fcall->params.ropen.iounit; | 128 | iounit = fcall->params.ropen.iounit; |
165 | kfree(fcall); | 129 | kfree(fcall); |
130 | } else { | ||
131 | /* create case */ | ||
132 | newfid = v9fid->fid; | ||
133 | iounit = v9fid->iounit; | ||
134 | v9fid->fidcreate = 0; | ||
166 | } | 135 | } |
167 | 136 | ||
168 | |||
169 | file->private_data = v9fid; | 137 | file->private_data = v9fid; |
170 | 138 | ||
171 | v9fid->rdir_pos = 0; | 139 | v9fid->rdir_pos = 0; |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index b16322db5ce6..2b696ae6655a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -307,7 +307,7 @@ v9fs_create(struct inode *dir, | |||
307 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 307 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); |
308 | struct super_block *sb = dir->i_sb; | 308 | struct super_block *sb = dir->i_sb; |
309 | struct v9fs_fid *dirfid = | 309 | struct v9fs_fid *dirfid = |
310 | v9fs_fid_lookup(file_dentry->d_parent, FID_WALK); | 310 | v9fs_fid_lookup(file_dentry->d_parent); |
311 | struct v9fs_fid *fid = NULL; | 311 | struct v9fs_fid *fid = NULL; |
312 | struct inode *file_inode = NULL; | 312 | struct inode *file_inode = NULL; |
313 | struct v9fs_fcall *fcall = NULL; | 313 | struct v9fs_fcall *fcall = NULL; |
@@ -317,6 +317,7 @@ v9fs_create(struct inode *dir, | |||
317 | long newfid = -1; | 317 | long newfid = -1; |
318 | int result = 0; | 318 | int result = 0; |
319 | unsigned int iounit = 0; | 319 | unsigned int iounit = 0; |
320 | int wfidno = -1; | ||
320 | 321 | ||
321 | perm = unixmode2p9mode(v9ses, perm); | 322 | perm = unixmode2p9mode(v9ses, perm); |
322 | 323 | ||
@@ -350,7 +351,7 @@ v9fs_create(struct inode *dir, | |||
350 | if (result < 0) { | 351 | if (result < 0) { |
351 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); | 352 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); |
352 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 353 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
353 | newfid = 0; | 354 | newfid = -1; |
354 | goto CleanUpFid; | 355 | goto CleanUpFid; |
355 | } | 356 | } |
356 | 357 | ||
@@ -369,20 +370,39 @@ v9fs_create(struct inode *dir, | |||
369 | qid = fcall->params.rcreate.qid; | 370 | qid = fcall->params.rcreate.qid; |
370 | kfree(fcall); | 371 | kfree(fcall); |
371 | 372 | ||
372 | fid = v9fs_fid_create(file_dentry); | 373 | fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); |
374 | dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); | ||
373 | if (!fid) { | 375 | if (!fid) { |
374 | result = -ENOMEM; | 376 | result = -ENOMEM; |
375 | goto CleanUpFid; | 377 | goto CleanUpFid; |
376 | } | 378 | } |
377 | 379 | ||
378 | fid->fid = newfid; | ||
379 | fid->fidopen = 0; | ||
380 | fid->fidcreate = 1; | ||
381 | fid->qid = qid; | 380 | fid->qid = qid; |
382 | fid->iounit = iounit; | 381 | fid->iounit = iounit; |
383 | fid->rdir_pos = 0; | 382 | |
384 | fid->rdir_fcall = NULL; | 383 | /* walk to the newly created file and put the fid in the dentry */ |
385 | fid->v9ses = v9ses; | 384 | wfidno = v9fs_get_idpool(&v9ses->fidpool); |
385 | if (newfid < 0) { | ||
386 | eprintk(KERN_WARNING, "no free fids available\n"); | ||
387 | return -ENOSPC; | ||
388 | } | ||
389 | |||
390 | result = v9fs_t_walk(v9ses, dirfidnum, wfidno, | ||
391 | (char *) file_dentry->d_name.name, NULL); | ||
392 | if (result < 0) { | ||
393 | dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); | ||
394 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
395 | wfidno = -1; | ||
396 | goto CleanUpFid; | ||
397 | } | ||
398 | |||
399 | if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { | ||
400 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) { | ||
401 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
402 | } | ||
403 | |||
404 | goto CleanUpFid; | ||
405 | } | ||
386 | 406 | ||
387 | if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || | 407 | if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || |
388 | (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || | 408 | (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || |
@@ -410,11 +430,11 @@ v9fs_create(struct inode *dir, | |||
410 | d_instantiate(file_dentry, file_inode); | 430 | d_instantiate(file_dentry, file_inode); |
411 | 431 | ||
412 | if (perm & V9FS_DMDIR) { | 432 | if (perm & V9FS_DMDIR) { |
413 | if (v9fs_t_clunk(v9ses, newfid, &fcall)) | 433 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) |
434 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
435 | else | ||
414 | dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", | 436 | dprintk(DEBUG_ERROR, "clunk for mkdir failed: %s\n", |
415 | FCALL_ERROR(fcall)); | 437 | FCALL_ERROR(fcall)); |
416 | |||
417 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
418 | kfree(fcall); | 438 | kfree(fcall); |
419 | fid->fidopen = 0; | 439 | fid->fidopen = 0; |
420 | fid->fidcreate = 0; | 440 | fid->fidcreate = 0; |
@@ -426,12 +446,22 @@ v9fs_create(struct inode *dir, | |||
426 | CleanUpFid: | 446 | CleanUpFid: |
427 | kfree(fcall); | 447 | kfree(fcall); |
428 | 448 | ||
429 | if (newfid) { | 449 | if (newfid >= 0) { |
430 | if (v9fs_t_clunk(v9ses, newfid, &fcall)) | 450 | if (!v9fs_t_clunk(v9ses, newfid, &fcall)) |
451 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
452 | else | ||
453 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", | ||
454 | FCALL_ERROR(fcall)); | ||
455 | |||
456 | kfree(fcall); | ||
457 | } | ||
458 | if (wfidno >= 0) { | ||
459 | if (!v9fs_t_clunk(v9ses, wfidno, &fcall)) | ||
460 | v9fs_put_idpool(wfidno, &v9ses->fidpool); | ||
461 | else | ||
431 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", | 462 | dprintk(DEBUG_ERROR, "clunk failed: %s\n", |
432 | FCALL_ERROR(fcall)); | 463 | FCALL_ERROR(fcall)); |
433 | 464 | ||
434 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
435 | kfree(fcall); | 465 | kfree(fcall); |
436 | } | 466 | } |
437 | return result; | 467 | return result; |
@@ -461,7 +491,7 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
461 | file_inode = file->d_inode; | 491 | file_inode = file->d_inode; |
462 | sb = file_inode->i_sb; | 492 | sb = file_inode->i_sb; |
463 | v9ses = v9fs_inode2v9ses(file_inode); | 493 | v9ses = v9fs_inode2v9ses(file_inode); |
464 | v9fid = v9fs_fid_lookup(file, FID_OP); | 494 | v9fid = v9fs_fid_lookup(file); |
465 | 495 | ||
466 | if (!v9fid) { | 496 | if (!v9fid) { |
467 | dprintk(DEBUG_ERROR, | 497 | dprintk(DEBUG_ERROR, |
@@ -545,7 +575,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
545 | 575 | ||
546 | sb = dir->i_sb; | 576 | sb = dir->i_sb; |
547 | v9ses = v9fs_inode2v9ses(dir); | 577 | v9ses = v9fs_inode2v9ses(dir); |
548 | dirfid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); | 578 | dirfid = v9fs_fid_lookup(dentry->d_parent); |
549 | 579 | ||
550 | if (!dirfid) { | 580 | if (!dirfid) { |
551 | dprintk(DEBUG_ERROR, "no dirfid\n"); | 581 | dprintk(DEBUG_ERROR, "no dirfid\n"); |
@@ -573,7 +603,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
573 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 603 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
574 | if (result == -ENOENT) { | 604 | if (result == -ENOENT) { |
575 | d_add(dentry, NULL); | 605 | d_add(dentry, NULL); |
576 | dprintk(DEBUG_ERROR, | 606 | dprintk(DEBUG_VFS, |
577 | "Return negative dentry %p count %d\n", | 607 | "Return negative dentry %p count %d\n", |
578 | dentry, atomic_read(&dentry->d_count)); | 608 | dentry, atomic_read(&dentry->d_count)); |
579 | return NULL; | 609 | return NULL; |
@@ -601,16 +631,13 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
601 | 631 | ||
602 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); | 632 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); |
603 | 633 | ||
604 | fid = v9fs_fid_create(dentry); | 634 | fid = v9fs_fid_create(dentry, v9ses, newfid, 0); |
605 | if (fid == NULL) { | 635 | if (fid == NULL) { |
606 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | 636 | dprintk(DEBUG_ERROR, "couldn't insert\n"); |
607 | result = -ENOMEM; | 637 | result = -ENOMEM; |
608 | goto FreeFcall; | 638 | goto FreeFcall; |
609 | } | 639 | } |
610 | 640 | ||
611 | fid->fid = newfid; | ||
612 | fid->fidopen = 0; | ||
613 | fid->v9ses = v9ses; | ||
614 | fid->qid = fcall->params.rstat.stat->qid; | 641 | fid->qid = fcall->params.rstat.stat->qid; |
615 | 642 | ||
616 | dentry->d_op = &v9fs_dentry_operations; | 643 | dentry->d_op = &v9fs_dentry_operations; |
@@ -665,11 +692,11 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
665 | { | 692 | { |
666 | struct inode *old_inode = old_dentry->d_inode; | 693 | struct inode *old_inode = old_dentry->d_inode; |
667 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); | 694 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); |
668 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_WALK); | 695 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); |
669 | struct v9fs_fid *olddirfid = | 696 | struct v9fs_fid *olddirfid = |
670 | v9fs_fid_lookup(old_dentry->d_parent, FID_WALK); | 697 | v9fs_fid_lookup(old_dentry->d_parent); |
671 | struct v9fs_fid *newdirfid = | 698 | struct v9fs_fid *newdirfid = |
672 | v9fs_fid_lookup(new_dentry->d_parent, FID_WALK); | 699 | v9fs_fid_lookup(new_dentry->d_parent); |
673 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 700 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); |
674 | struct v9fs_fcall *fcall = NULL; | 701 | struct v9fs_fcall *fcall = NULL; |
675 | int fid = -1; | 702 | int fid = -1; |
@@ -744,7 +771,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
744 | { | 771 | { |
745 | struct v9fs_fcall *fcall = NULL; | 772 | struct v9fs_fcall *fcall = NULL; |
746 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 773 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
747 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); | 774 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
748 | int err = -EPERM; | 775 | int err = -EPERM; |
749 | 776 | ||
750 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); | 777 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); |
@@ -778,7 +805,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
778 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 805 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) |
779 | { | 806 | { |
780 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 807 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
781 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); | 808 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
782 | struct v9fs_fcall *fcall = NULL; | 809 | struct v9fs_fcall *fcall = NULL; |
783 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 810 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); |
784 | int res = -EPERM; | 811 | int res = -EPERM; |
@@ -960,7 +987,7 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | |||
960 | if (retval != 0) | 987 | if (retval != 0) |
961 | goto FreeFcall; | 988 | goto FreeFcall; |
962 | 989 | ||
963 | newfid = v9fs_fid_lookup(dentry, FID_OP); | 990 | newfid = v9fs_fid_lookup(dentry); |
964 | 991 | ||
965 | /* issue a twstat */ | 992 | /* issue a twstat */ |
966 | v9fs_blank_mistat(v9ses, mistat); | 993 | v9fs_blank_mistat(v9ses, mistat); |
@@ -1004,7 +1031,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
1004 | 1031 | ||
1005 | struct v9fs_fcall *fcall = NULL; | 1032 | struct v9fs_fcall *fcall = NULL; |
1006 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 1033 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
1007 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry, FID_OP); | 1034 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
1008 | 1035 | ||
1009 | if (!fid) { | 1036 | if (!fid) { |
1010 | dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); | 1037 | dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); |
@@ -1148,7 +1175,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1148 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); | 1175 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); |
1149 | struct v9fs_fcall *fcall = NULL; | 1176 | struct v9fs_fcall *fcall = NULL; |
1150 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); | 1177 | struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); |
1151 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry, FID_OP); | 1178 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); |
1152 | struct v9fs_fid *newfid = NULL; | 1179 | struct v9fs_fid *newfid = NULL; |
1153 | char *symname = __getname(); | 1180 | char *symname = __getname(); |
1154 | 1181 | ||
@@ -1168,7 +1195,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1168 | if (retval != 0) | 1195 | if (retval != 0) |
1169 | goto FreeMem; | 1196 | goto FreeMem; |
1170 | 1197 | ||
1171 | newfid = v9fs_fid_lookup(dentry, FID_OP); | 1198 | newfid = v9fs_fid_lookup(dentry); |
1172 | if (!newfid) { | 1199 | if (!newfid) { |
1173 | dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); | 1200 | dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); |
1174 | goto FreeMem; | 1201 | goto FreeMem; |
@@ -1246,7 +1273,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
1246 | if (retval != 0) | 1273 | if (retval != 0) |
1247 | goto FreeMem; | 1274 | goto FreeMem; |
1248 | 1275 | ||
1249 | newfid = v9fs_fid_lookup(dentry, FID_OP); | 1276 | newfid = v9fs_fid_lookup(dentry); |
1250 | if (!newfid) { | 1277 | if (!newfid) { |
1251 | dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); | 1278 | dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n"); |
1252 | retval = -EINVAL; | 1279 | retval = -EINVAL; |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 1e2b2b54d300..0957f4da91d4 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -129,8 +129,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type | |||
129 | 129 | ||
130 | if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { | 130 | if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { |
131 | dprintk(DEBUG_ERROR, "problem initiating session\n"); | 131 | dprintk(DEBUG_ERROR, "problem initiating session\n"); |
132 | kfree(v9ses); | 132 | return newfid; |
133 | return ERR_PTR(newfid); | ||
134 | } | 133 | } |
135 | 134 | ||
136 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); | 135 | sb = sget(fs_type, NULL, v9fs_set_super, v9ses); |
@@ -155,23 +154,19 @@ static struct super_block *v9fs_get_sb(struct file_system_type | |||
155 | 154 | ||
156 | sb->s_root = root; | 155 | sb->s_root = root; |
157 | 156 | ||
158 | /* Setup the Root Inode */ | ||
159 | root_fid = v9fs_fid_create(root); | ||
160 | if (root_fid == NULL) { | ||
161 | retval = -ENOMEM; | ||
162 | goto put_back_sb; | ||
163 | } | ||
164 | |||
165 | root_fid->fidopen = 0; | ||
166 | root_fid->v9ses = v9ses; | ||
167 | |||
168 | stat_result = v9fs_t_stat(v9ses, newfid, &fcall); | 157 | stat_result = v9fs_t_stat(v9ses, newfid, &fcall); |
169 | if (stat_result < 0) { | 158 | if (stat_result < 0) { |
170 | dprintk(DEBUG_ERROR, "stat error\n"); | 159 | dprintk(DEBUG_ERROR, "stat error\n"); |
171 | v9fs_t_clunk(v9ses, newfid, NULL); | 160 | v9fs_t_clunk(v9ses, newfid, NULL); |
172 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 161 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
173 | } else { | 162 | } else { |
174 | root_fid->fid = newfid; | 163 | /* Setup the Root Inode */ |
164 | root_fid = v9fs_fid_create(root, v9ses, newfid, 0); | ||
165 | if (root_fid == NULL) { | ||
166 | retval = -ENOMEM; | ||
167 | goto put_back_sb; | ||
168 | } | ||
169 | |||
175 | root_fid->qid = fcall->params.rstat.stat->qid; | 170 | root_fid->qid = fcall->params.rstat.stat->qid; |
176 | root->d_inode->i_ino = | 171 | root->d_inode->i_ino = |
177 | v9fs_qid2ino(&fcall->params.rstat.stat->qid); | 172 | v9fs_qid2ino(&fcall->params.rstat.stat->qid); |