aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2006-03-02 05:54:30 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-02 11:33:07 -0500
commit6a3124a3946c16159c3faf83e62ffdb5d1134b3a (patch)
tree989f1e89ed0971824db973af5347b879e12c67cd /fs/9p
parent77a3313551afd53c90012e5a87f7f2b2195fc67e (diff)
[PATCH] v9fs: fix atomic create open
In order to assure atomic create+open v9fs stores the open fid produced by v9fs_vfs_create in the dentry, from where v9fs_file_open retrieves it and associates it with the open file. This patch modifies v9fs to use nameidata.intent.open values to do the atomic create+open. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> 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>
Diffstat (limited to 'fs/9p')
-rw-r--r--fs/9p/fid.c73
-rw-r--r--fs/9p/fid.h5
-rw-r--r--fs/9p/v9fs_vfs.h1
-rw-r--r--fs/9p/vfs_file.c106
-rw-r--r--fs/9p/vfs_inode.c478
-rw-r--r--fs/9p/vfs_super.c12
6 files changed, 379 insertions, 296 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index eda449778fa5..c27f546dd25b 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -40,7 +40,7 @@
40 * 40 *
41 */ 41 */
42 42
43static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) 43int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
44{ 44{
45 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; 45 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
46 dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid, 46 dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid,
@@ -68,14 +68,11 @@ static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
68 * 68 *
69 */ 69 */
70 70
71struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, 71struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid)
72 struct v9fs_session_info *v9ses, int fid, int create)
73{ 72{
74 struct v9fs_fid *new; 73 struct v9fs_fid *new;
75 74
76 dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n", 75 dprintk(DEBUG_9P, "fid create fid %d\n", fid);
77 dentry, fid, create);
78
79 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 76 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
80 if (new == NULL) { 77 if (new == NULL) {
81 dprintk(DEBUG_ERROR, "Out of Memory\n"); 78 dprintk(DEBUG_ERROR, "Out of Memory\n");
@@ -85,19 +82,13 @@ struct v9fs_fid *v9fs_fid_create(struct dentry *dentry,
85 new->fid = fid; 82 new->fid = fid;
86 new->v9ses = v9ses; 83 new->v9ses = v9ses;
87 new->fidopen = 0; 84 new->fidopen = 0;
88 new->fidcreate = create;
89 new->fidclunked = 0; 85 new->fidclunked = 0;
90 new->iounit = 0; 86 new->iounit = 0;
91 new->rdir_pos = 0; 87 new->rdir_pos = 0;
92 new->rdir_fcall = NULL; 88 new->rdir_fcall = NULL;
89 INIT_LIST_HEAD(&new->list);
93 90
94 if (v9fs_fid_insert(new, dentry) == 0)
95 return new; 91 return new;
96 else {
97 dprintk(DEBUG_ERROR, "Problems inserting to dentry\n");
98 kfree(new);
99 return NULL;
100 }
101} 92}
102 93
103/** 94/**
@@ -119,7 +110,7 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
119static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) 110static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
120{ 111{
121 int fidnum, cfidnum, err; 112 int fidnum, cfidnum, err;
122 struct v9fs_fid *cfid; 113 struct v9fs_fid *cfid, *fid;
123 struct dentry *cde; 114 struct dentry *cde;
124 struct v9fs_session_info *v9ses; 115 struct v9fs_session_info *v9ses;
125 116
@@ -158,7 +149,16 @@ static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry)
158 cde = cde->d_parent; 149 cde = cde->d_parent;
159 } 150 }
160 151
161 return v9fs_fid_create(dentry, v9ses, fidnum, 0); 152 fid = v9fs_fid_create(v9ses, fidnum);
153 if (fid) {
154 err = v9fs_fid_insert(fid, dentry);
155 if (err < 0) {
156 kfree(fid);
157 goto clunk_fid;
158 }
159 }
160
161 return fid;
162 162
163clunk_fid: 163clunk_fid:
164 v9fs_t_clunk(v9ses, fidnum); 164 v9fs_t_clunk(v9ses, fidnum);
@@ -179,29 +179,12 @@ clunk_fid:
179struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) 179struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
180{ 180{
181 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; 181 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
182 struct v9fs_fid *current_fid = NULL;
183 struct v9fs_fid *temp = NULL;
184 struct v9fs_fid *return_fid = NULL; 182 struct v9fs_fid *return_fid = NULL;
185 183
186 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); 184 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
187 185
188 if (fid_list) { 186 if (fid_list)
189 list_for_each_entry_safe(current_fid, temp, fid_list, list) { 187 return_fid = list_entry(fid_list->next, struct v9fs_fid, list);
190 if (!current_fid->fidcreate) {
191 return_fid = current_fid;
192 break;
193 }
194 }
195
196 if (!return_fid)
197 return_fid = current_fid;
198 }
199
200 /* we are at the root but didn't match */
201 if ((!return_fid) && (dentry->d_parent == dentry)) {
202 /* TODO: clone attach with new uid */
203 return_fid = current_fid;
204 }
205 188
206 if (!return_fid) { 189 if (!return_fid) {
207 struct dentry *par = current->fs->pwd->d_parent; 190 struct dentry *par = current->fs->pwd->d_parent;
@@ -228,25 +211,3 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
228 211
229 return return_fid; 212 return return_fid;
230} 213}
231
232struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry)
233{
234 struct list_head *fid_list;
235 struct v9fs_fid *fid, *ftmp, *ret;
236
237 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
238 fid_list = (struct list_head *)dentry->d_fsdata;
239 ret = NULL;
240 if (fid_list) {
241 list_for_each_entry_safe(fid, ftmp, fid_list, list) {
242 if (fid->fidcreate && fid->pid == current->pid) {
243 list_del(&fid->list);
244 ret = fid;
245 break;
246 }
247 }
248 }
249
250 dprintk(DEBUG_9P, "return %p\n", ret);
251 return ret;
252}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 84c673a44c83..7ccf0d064e25 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -33,7 +33,6 @@ struct v9fs_fid {
33 33
34 u32 fid; 34 u32 fid;
35 unsigned char fidopen; /* set when fid is opened */ 35 unsigned char fidopen; /* set when fid is opened */
36 unsigned char fidcreate; /* set when fid was just created */
37 unsigned char fidclunked; /* set when fid has already been clunked */ 36 unsigned char fidclunked; /* set when fid has already been clunked */
38 37
39 struct v9fs_qid qid; 38 struct v9fs_qid qid;
@@ -56,5 +55,5 @@ struct v9fs_fid {
56struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); 55struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry);
57struct v9fs_fid *v9fs_fid_get_created(struct dentry *); 56struct v9fs_fid *v9fs_fid_get_created(struct dentry *);
58void v9fs_fid_destroy(struct v9fs_fid *fid); 57void v9fs_fid_destroy(struct v9fs_fid *fid);
59struct v9fs_fid *v9fs_fid_create(struct dentry *, 58struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid);
60 struct v9fs_session_info *v9ses, int fid, int create); 59int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 69cf2905dc90..a759278acaae 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -51,3 +51,4 @@ int v9fs_dir_release(struct inode *inode, struct file *filp);
51int v9fs_file_open(struct inode *inode, struct file *file); 51int v9fs_file_open(struct inode *inode, struct file *file);
52void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); 52void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
53void v9fs_dentry_release(struct dentry *); 53void v9fs_dentry_release(struct dentry *);
54int v9fs_uflags2omode(int uflags);
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index c7e14d917215..de3a129698da 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -53,94 +53,70 @@
53int v9fs_file_open(struct inode *inode, struct file *file) 53int 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, *fid; 56 struct v9fs_fid *vfid;
57 struct v9fs_fcall *fcall = NULL; 57 struct v9fs_fcall *fcall = NULL;
58 int open_mode = 0; 58 int omode;
59 unsigned int iounit = 0; 59 int fid = V9FS_NOFID;
60 int newfid = -1; 60 int err;
61 long result = -1;
62 61
63 dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); 62 dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
64 63
65 v9fid = v9fs_fid_get_created(file->f_dentry); 64 vfid = v9fs_fid_lookup(file->f_dentry);
66 if (!v9fid) 65 if (!vfid) {
67 v9fid = v9fs_fid_lookup(file->f_dentry);
68
69 if (!v9fid) {
70 dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); 66 dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n");
71 return -EBADF; 67 return -EBADF;
72 } 68 }
73 69
74 if (!v9fid->fidcreate) { 70 fid = v9fs_get_idpool(&v9ses->fidpool);
75 fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 71 if (fid < 0) {
76 if (fid == NULL) {
77 dprintk(DEBUG_ERROR, "Out of Memory\n");
78 return -ENOMEM;
79 }
80
81 fid->fidopen = 0;
82 fid->fidcreate = 0;
83 fid->fidclunked = 0;
84 fid->iounit = 0;
85 fid->v9ses = v9ses;
86
87 newfid = v9fs_get_idpool(&v9ses->fidpool);
88 if (newfid < 0) {
89 eprintk(KERN_WARNING, "newfid fails!\n"); 72 eprintk(KERN_WARNING, "newfid fails!\n");
90 return -ENOSPC; 73 return -ENOSPC;
91 } 74 }
92 75
93 result = 76 err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL);
94 v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); 77 if (err < 0) {
95
96 if (result < 0) {
97 v9fs_put_idpool(newfid, &v9ses->fidpool);
98 dprintk(DEBUG_ERROR, "rewalk didn't work\n"); 78 dprintk(DEBUG_ERROR, "rewalk didn't work\n");
99 return -EBADF; 79 goto put_fid;
80 }
81
82 vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
83 if (vfid == NULL) {
84 dprintk(DEBUG_ERROR, "out of memory\n");
85 goto clunk_fid;
100 } 86 }
101 87
102 fid->fid = newfid;
103 v9fid = fid;
104 /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ 88 /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */
105 /* translate open mode appropriately */ 89 /* translate open mode appropriately */
106 open_mode = file->f_flags & 0x3; 90 omode = v9fs_uflags2omode(file->f_flags);
91 err = v9fs_t_open(v9ses, fid, omode, &fcall);
92 if (err < 0) {
93 PRINT_FCALL_ERROR("open failed", fcall);
94 goto destroy_vfid;
95 }
107 96
108 if (file->f_flags & O_EXCL) 97 file->private_data = vfid;
109 open_mode |= V9FS_OEXCL; 98 vfid->fid = fid;
99 vfid->fidopen = 1;
100 vfid->fidclunked = 0;
101 vfid->iounit = fcall->params.ropen.iounit;
102 vfid->rdir_pos = 0;
103 vfid->rdir_fcall = NULL;
104 vfid->filp = file;
105 kfree(fcall);
110 106
111 if (v9ses->extended) { 107 return 0;
112 if (file->f_flags & O_TRUNC)
113 open_mode |= V9FS_OTRUNC;
114 108
115 if (file->f_flags & O_APPEND) 109destroy_vfid:
116 open_mode |= V9FS_OAPPEND; 110 v9fs_fid_destroy(vfid);
117 }
118 111
119 result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); 112clunk_fid:
120 if (result < 0) { 113 v9fs_t_clunk(v9ses, fid);
121 PRINT_FCALL_ERROR("open failed", fcall);
122 kfree(fcall);
123 return result;
124 }
125 114
126 iounit = fcall->params.ropen.iounit; 115put_fid:
116 v9fs_put_idpool(fid, &v9ses->fidpool);
127 kfree(fcall); 117 kfree(fcall);
128 } else {
129 /* create case */
130 newfid = v9fid->fid;
131 iounit = v9fid->iounit;
132 v9fid->fidcreate = 0;
133 }
134
135 file->private_data = v9fid;
136
137 v9fid->rdir_pos = 0;
138 v9fid->rdir_fcall = NULL;
139 v9fid->fidopen = 1;
140 v9fid->filp = file;
141 v9fid->iounit = iounit;
142 118
143 return 0; 119 return err;
144} 120}
145 121
146/** 122/**
@@ -289,9 +265,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
289 total += result; 265 total += result;
290 } while (count); 266 } while (count);
291 267
292 if(inode->i_mapping->nrpages)
293 invalidate_inode_pages2(inode->i_mapping); 268 invalidate_inode_pages2(inode->i_mapping);
294
295 return total; 269 return total;
296} 270}
297 271
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 63e5b0398e8b..dce729d42869 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -125,6 +125,38 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
125 return res; 125 return res;
126} 126}
127 127
128int v9fs_uflags2omode(int uflags)
129{
130 int ret;
131
132 ret = 0;
133 switch (uflags&3) {
134 default:
135 case O_RDONLY:
136 ret = V9FS_OREAD;
137 break;
138
139 case O_WRONLY:
140 ret = V9FS_OWRITE;
141 break;
142
143 case O_RDWR:
144 ret = V9FS_ORDWR;
145 break;
146 }
147
148 if (uflags & O_EXCL)
149 ret |= V9FS_OEXCL;
150
151 if (uflags & O_TRUNC)
152 ret |= V9FS_OTRUNC;
153
154 if (uflags & O_APPEND)
155 ret |= V9FS_OAPPEND;
156
157 return ret;
158}
159
128/** 160/**
129 * v9fs_blank_wstat - helper function to setup a 9P stat structure 161 * v9fs_blank_wstat - helper function to setup a 9P stat structure
130 * @v9ses: 9P session info (for determining extended mode) 162 * @v9ses: 9P session info (for determining extended mode)
@@ -163,7 +195,7 @@ v9fs_blank_wstat(struct v9fs_wstat *wstat)
163 195
164struct inode *v9fs_get_inode(struct super_block *sb, int mode) 196struct inode *v9fs_get_inode(struct super_block *sb, int mode)
165{ 197{
166 struct inode *inode = NULL; 198 struct inode *inode;
167 struct v9fs_session_info *v9ses = sb->s_fs_info; 199 struct v9fs_session_info *v9ses = sb->s_fs_info;
168 200
169 dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); 201 dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
@@ -222,171 +254,135 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
222 return inode; 254 return inode;
223} 255}
224 256
225/**
226 * v9fs_create - helper function to create files and directories
227 * @dir: directory inode file is being created in
228 * @file_dentry: dentry file is being created in
229 * @perm: permissions file is being created with
230 * @open_mode: resulting open mode for file
231 *
232 */
233
234static int 257static int
235v9fs_create(struct inode *dir, 258v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name,
236 struct dentry *file_dentry, 259 u32 perm, u8 mode, u32 *fidp, struct v9fs_qid *qid, u32 *iounit)
237 unsigned int perm, unsigned int open_mode)
238{ 260{
239 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); 261 u32 fid;
240 struct super_block *sb = dir->i_sb;
241 struct v9fs_fid *dirfid =
242 v9fs_fid_lookup(file_dentry->d_parent);
243 struct v9fs_fid *fid = NULL;
244 struct inode *file_inode = NULL;
245 struct v9fs_fcall *fcall = NULL;
246 struct v9fs_qid qid;
247 int dirfidnum = -1;
248 long newfid = -1;
249 int result = 0;
250 unsigned int iounit = 0;
251 int wfidno = -1;
252 int err; 262 int err;
263 struct v9fs_fcall *fcall;
253 264
254 perm = unixmode2p9mode(v9ses, perm); 265 fid = v9fs_get_idpool(&v9ses->fidpool);
255 266 if (fid < 0) {
256 dprintk(DEBUG_VFS, "dir: %p dentry: %p perm: %o mode: %o\n", dir,
257 file_dentry, perm, open_mode);
258
259 if (!dirfid)
260 return -EBADF;
261
262 dirfidnum = dirfid->fid;
263 if (dirfidnum < 0) {
264 dprintk(DEBUG_ERROR, "No fid for the directory #%lu\n",
265 dir->i_ino);
266 return -EBADF;
267 }
268
269 if (file_dentry->d_inode) {
270 dprintk(DEBUG_ERROR,
271 "Odd. There is an inode for dir %lu, name :%s:\n",
272 dir->i_ino, file_dentry->d_name.name);
273 return -EEXIST;
274 }
275
276 newfid = v9fs_get_idpool(&v9ses->fidpool);
277 if (newfid < 0) {
278 eprintk(KERN_WARNING, "no free fids available\n"); 267 eprintk(KERN_WARNING, "no free fids available\n");
279 return -ENOSPC; 268 err = -ENOSPC;
269 goto error;
280 } 270 }
281 271
282 result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); 272 err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall);
283 if (result < 0) { 273 if (err < 0) {
284 PRINT_FCALL_ERROR("clone error", fcall); 274 PRINT_FCALL_ERROR("clone error", fcall);
285 v9fs_put_idpool(newfid, &v9ses->fidpool); 275 goto error;
286 newfid = -1;
287 goto CleanUpFid;
288 } 276 }
289
290 kfree(fcall); 277 kfree(fcall);
291 fcall = NULL;
292 278
293 result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, 279 err = v9fs_t_create(v9ses, fid, name, perm, mode, &fcall);
294 perm, open_mode, &fcall); 280 if (err < 0) {
295 if (result < 0) {
296 PRINT_FCALL_ERROR("create fails", fcall); 281 PRINT_FCALL_ERROR("create fails", fcall);
297 goto CleanUpFid; 282 goto error;
298 } 283 }
299 284
300 iounit = fcall->params.rcreate.iounit; 285 if (iounit)
301 qid = fcall->params.rcreate.qid; 286 *iounit = fcall->params.rcreate.iounit;
287
288 if (qid)
289 *qid = fcall->params.rcreate.qid;
290
291 if (fidp)
292 *fidp = fid;
293
302 kfree(fcall); 294 kfree(fcall);
303 fcall = NULL; 295 return 0;
304 296
305 if (!(perm&V9FS_DMDIR)) { 297error:
306 fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); 298 if (fid >= 0)
307 dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); 299 v9fs_put_idpool(fid, &v9ses->fidpool);
308 if (!fid) {
309 result = -ENOMEM;
310 goto CleanUpFid;
311 }
312 300
313 fid->qid = qid; 301 kfree(fcall);
314 fid->iounit = iounit; 302 return err;
315 } else { 303}
316 err = v9fs_t_clunk(v9ses, newfid); 304
317 newfid = -1; 305static struct v9fs_fid*
318 if (err < 0) 306v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
319 dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err); 307{
320 } 308 int err;
309 u32 nfid;
310 struct v9fs_fid *ret;
311 struct v9fs_fcall *fcall;
321 312
322 /* walk to the newly created file and put the fid in the dentry */ 313 nfid = v9fs_get_idpool(&v9ses->fidpool);
323 wfidno = v9fs_get_idpool(&v9ses->fidpool); 314 if (nfid < 0) {
324 if (wfidno < 0) {
325 eprintk(KERN_WARNING, "no free fids available\n"); 315 eprintk(KERN_WARNING, "no free fids available\n");
326 return -ENOSPC; 316 err = -ENOSPC;
317 goto error;
327 } 318 }
328 319
329 result = v9fs_t_walk(v9ses, dirfidnum, wfidno, 320 err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,
330 (char *) file_dentry->d_name.name, &fcall); 321 &fcall);
331 if (result < 0) { 322
332 PRINT_FCALL_ERROR("clone error", fcall); 323 if (err < 0) {
333 v9fs_put_idpool(wfidno, &v9ses->fidpool); 324 PRINT_FCALL_ERROR("walk error", fcall);
334 wfidno = -1; 325 v9fs_put_idpool(nfid, &v9ses->fidpool);
335 goto CleanUpFid; 326 goto error;
336 } 327 }
328
337 kfree(fcall); 329 kfree(fcall);
338 fcall = NULL; 330 fcall = NULL;
331 ret = v9fs_fid_create(v9ses, nfid);
332 if (!ret) {
333 err = -ENOMEM;
334 goto clunk_fid;
335 }
339 336
340 if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { 337 err = v9fs_fid_insert(ret, dentry);
341 v9fs_put_idpool(wfidno, &v9ses->fidpool); 338 if (err < 0) {
342 339 v9fs_fid_destroy(ret);
343 goto CleanUpFid; 340 goto clunk_fid;
344 } 341 }
345 342
346 if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || 343 return ret;
347 (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) ||
348 (perm & V9FS_DMDEVICE))
349 return 0;
350 344
351 result = v9fs_t_stat(v9ses, wfidno, &fcall); 345clunk_fid:
352 if (result < 0) { 346 v9fs_t_clunk(v9ses, nfid);
353 PRINT_FCALL_ERROR("stat error", fcall); 347
354 goto CleanUpFid; 348error:
355 } 349 kfree(fcall);
350 return ERR_PTR(err);
351}
356 352
353struct inode *
354v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid,
355 struct super_block *sb)
356{
357 int err, umode;
358 struct inode *ret;
359 struct v9fs_fcall *fcall;
357 360
358 file_inode = v9fs_get_inode(sb, 361 ret = NULL;
359 p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode)); 362 err = v9fs_t_stat(v9ses, fid, &fcall);
363 if (err) {
364 PRINT_FCALL_ERROR("stat error", fcall);
365 goto error;
366 }
360 367
361 if ((!file_inode) || IS_ERR(file_inode)) { 368 umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode);
362 dprintk(DEBUG_ERROR, "create inode failed\n"); 369 ret = v9fs_get_inode(sb, umode);
363 result = -EBADF; 370 if (IS_ERR(ret)) {
364 goto CleanUpFid; 371 err = PTR_ERR(ret);
372 ret = NULL;
373 goto error;
365 } 374 }
366 375
367 v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb); 376 v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb);
368 kfree(fcall); 377 kfree(fcall);
369 fcall = NULL; 378 return ret;
370 file_dentry->d_op = &v9fs_dentry_operations;
371 d_instantiate(file_dentry, file_inode);
372
373 return 0;
374 379
375 CleanUpFid: 380error:
376 kfree(fcall); 381 kfree(fcall);
377 fcall = NULL; 382 if (ret)
383 iput(ret);
378 384
379 if (newfid >= 0) { 385 return ERR_PTR(err);
380 err = v9fs_t_clunk(v9ses, newfid);
381 if (err < 0)
382 dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
383 }
384 if (wfidno >= 0) {
385 err = v9fs_t_clunk(v9ses, wfidno);
386 if (err < 0)
387 dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
388 }
389 return result;
390} 386}
391 387
392/** 388/**
@@ -440,20 +436,97 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
440 return result; 436 return result;
441} 437}
442 438
439static int
440v9fs_open_created(struct inode *inode, struct file *file)
441{
442 return 0;
443}
444
443/** 445/**
444 * v9fs_vfs_create - VFS hook to create files 446 * v9fs_vfs_create - VFS hook to create files
445 * @inode: directory inode that is being deleted 447 * @inode: directory inode that is being deleted
446 * @dentry: dentry that is being deleted 448 * @dentry: dentry that is being deleted
447 * @perm: create permissions 449 * @mode: create permissions
448 * @nd: path information 450 * @nd: path information
449 * 451 *
450 */ 452 */
451 453
452static int 454static int
453v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, 455v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
454 struct nameidata *nd) 456 struct nameidata *nd)
455{ 457{
456 return v9fs_create(inode, dentry, perm, O_RDWR); 458 int err;
459 u32 fid, perm, iounit;
460 int flags;
461 struct v9fs_session_info *v9ses;
462 struct v9fs_fid *dfid, *vfid, *ffid;
463 struct inode *inode;
464 struct v9fs_qid qid;
465 struct file *filp;
466
467 inode = NULL;
468 vfid = NULL;
469 v9ses = v9fs_inode2v9ses(dir);
470 dfid = v9fs_fid_lookup(dentry->d_parent);
471 perm = unixmode2p9mode(v9ses, mode);
472
473 if (nd && nd->flags & LOOKUP_OPEN)
474 flags = nd->intent.open.flags - 1;
475 else
476 flags = O_RDWR;
477
478 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
479 perm, v9fs_uflags2omode(flags), &fid, &qid, &iounit);
480
481 if (err)
482 goto error;
483
484 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
485 if (IS_ERR(vfid)) {
486 err = PTR_ERR(vfid);
487 vfid = NULL;
488 goto error;
489 }
490
491 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
492 if (IS_ERR(inode)) {
493 err = PTR_ERR(inode);
494 inode = NULL;
495 goto error;
496 }
497
498 dentry->d_op = &v9fs_dentry_operations;
499 d_instantiate(dentry, inode);
500
501 if (nd && nd->flags & LOOKUP_OPEN) {
502 ffid = v9fs_fid_create(v9ses, fid);
503 if (!ffid)
504 return -ENOMEM;
505
506 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
507 if (IS_ERR(filp)) {
508 v9fs_fid_destroy(ffid);
509 return PTR_ERR(filp);
510 }
511
512 ffid->rdir_pos = 0;
513 ffid->rdir_fcall = NULL;
514 ffid->fidopen = 1;
515 ffid->iounit = iounit;
516 ffid->filp = filp;
517 filp->private_data = ffid;
518 }
519
520 return 0;
521
522error:
523 if (vfid)
524 v9fs_fid_destroy(vfid);
525
526 if (inode)
527 iput(inode);
528
529 return err;
457} 530}
458 531
459/** 532/**
@@ -464,9 +537,57 @@ v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm,
464 * 537 *
465 */ 538 */
466 539
467static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode) 540static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
468{ 541{
469 return v9fs_create(inode, dentry, mode | S_IFDIR, O_RDONLY); 542 int err;
543 u32 fid, perm;
544 struct v9fs_session_info *v9ses;
545 struct v9fs_fid *dfid, *vfid;
546 struct inode *inode;
547
548 inode = NULL;
549 vfid = NULL;
550 v9ses = v9fs_inode2v9ses(dir);
551 dfid = v9fs_fid_lookup(dentry->d_parent);
552 perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
553
554 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
555 perm, V9FS_OREAD, &fid, NULL, NULL);
556
557 if (err) {
558 dprintk(DEBUG_ERROR, "create error %d\n", err);
559 goto error;
560 }
561
562 err = v9fs_t_clunk(v9ses, fid);
563 if (err) {
564 dprintk(DEBUG_ERROR, "clunk error %d\n", err);
565 goto error;
566 }
567
568 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
569 if (IS_ERR(vfid)) {
570 err = PTR_ERR(vfid);
571 vfid = NULL;
572 goto error;
573 }
574
575 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
576 if (IS_ERR(inode)) {
577 err = PTR_ERR(inode);
578 inode = NULL;
579 goto error;
580 }
581
582 dentry->d_op = &v9fs_dentry_operations;
583 d_instantiate(dentry, inode);
584 return 0;
585
586error:
587 if (vfid)
588 v9fs_fid_destroy(vfid);
589
590 return err;
470} 591}
471 592
472/** 593/**
@@ -516,9 +637,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
516 return ERR_PTR(-ENOSPC); 637 return ERR_PTR(-ENOSPC);
517 } 638 }
518 639
519 result = 640 result = v9fs_t_walk(v9ses, dirfidnum, newfid,
520 v9fs_t_walk(v9ses, dirfidnum, newfid, (char *)dentry->d_name.name, 641 (char *)dentry->d_name.name, NULL);
521 NULL);
522 if (result < 0) { 642 if (result < 0) {
523 v9fs_put_idpool(newfid, &v9ses->fidpool); 643 v9fs_put_idpool(newfid, &v9ses->fidpool);
524 if (result == -ENOENT) { 644 if (result == -ENOENT) {
@@ -551,13 +671,17 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
551 671
552 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); 672 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
553 673
554 fid = v9fs_fid_create(dentry, v9ses, newfid, 0); 674 fid = v9fs_fid_create(v9ses, newfid);
555 if (fid == NULL) { 675 if (fid == NULL) {
556 dprintk(DEBUG_ERROR, "couldn't insert\n"); 676 dprintk(DEBUG_ERROR, "couldn't insert\n");
557 result = -ENOMEM; 677 result = -ENOMEM;
558 goto FreeFcall; 678 goto FreeFcall;
559 } 679 }
560 680
681 result = v9fs_fid_insert(fid, dentry);
682 if (result < 0)
683 goto FreeFcall;
684
561 fid->qid = fcall->params.rstat.stat.qid; 685 fid->qid = fcall->params.rstat.stat.qid;
562 686
563 dentry->d_op = &v9fs_dentry_operations; 687 dentry->d_op = &v9fs_dentry_operations;
@@ -886,8 +1010,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
886 } 1010 }
887 1011
888 /* copy extension buffer into buffer */ 1012 /* copy extension buffer into buffer */
889 if (fcall->params.rstat.stat.extension.len+1 < buflen) 1013 if (fcall->params.rstat.stat.extension.len < buflen)
890 buflen = fcall->params.rstat.stat.extension.len + 1; 1014 buflen = fcall->params.rstat.stat.extension.len;
891 1015
892 memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); 1016 memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
893 buffer[buflen-1] = 0; 1017 buffer[buflen-1] = 0;
@@ -951,7 +1075,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
951 if (!link) 1075 if (!link)
952 link = ERR_PTR(-ENOMEM); 1076 link = ERR_PTR(-ENOMEM);
953 else { 1077 else {
954 len = v9fs_readlink(dentry, link, PATH_MAX); 1078 len = v9fs_readlink(dentry, link, strlen(link));
955 1079
956 if (len < 0) { 1080 if (len < 0) {
957 __putname(link); 1081 __putname(link);
@@ -983,53 +1107,75 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
983static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 1107static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
984 int mode, const char *extension) 1108 int mode, const char *extension)
985{ 1109{
986 int err, retval; 1110 int err;
1111 u32 fid, perm;
987 struct v9fs_session_info *v9ses; 1112 struct v9fs_session_info *v9ses;
1113 struct v9fs_fid *dfid, *vfid;
1114 struct inode *inode;
988 struct v9fs_fcall *fcall; 1115 struct v9fs_fcall *fcall;
989 struct v9fs_fid *fid;
990 struct v9fs_wstat wstat; 1116 struct v9fs_wstat wstat;
991 1117
992 v9ses = v9fs_inode2v9ses(dir);
993 retval = -EPERM;
994 fcall = NULL; 1118 fcall = NULL;
1119 inode = NULL;
1120 vfid = NULL;
1121 v9ses = v9fs_inode2v9ses(dir);
1122 dfid = v9fs_fid_lookup(dentry->d_parent);
1123 perm = unixmode2p9mode(v9ses, mode);
995 1124
996 if (!v9ses->extended) { 1125 if (!v9ses->extended) {
997 dprintk(DEBUG_ERROR, "not extended\n"); 1126 dprintk(DEBUG_ERROR, "not extended\n");
998 goto free_mem; 1127 return -EPERM;
999 } 1128 }
1000 1129
1001 /* issue a create */ 1130 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
1002 retval = v9fs_create(dir, dentry, mode, 0); 1131 perm, V9FS_OREAD, &fid, NULL, NULL);
1003 if (retval != 0)
1004 goto free_mem;
1005 1132
1006 fid = v9fs_fid_get_created(dentry); 1133 if (err)
1007 if (!fid) { 1134 goto error;
1008 dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); 1135
1009 goto free_mem; 1136 err = v9fs_t_clunk(v9ses, fid);
1137 if (err)
1138 goto error;
1139
1140 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
1141 if (IS_ERR(vfid)) {
1142 err = PTR_ERR(vfid);
1143 vfid = NULL;
1144 goto error;
1145 }
1146
1147 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
1148 if (IS_ERR(inode)) {
1149 err = PTR_ERR(inode);
1150 inode = NULL;
1151 goto error;
1010 } 1152 }
1011 1153
1012 /* issue a Twstat */ 1154 /* issue a Twstat */
1013 v9fs_blank_wstat(&wstat); 1155 v9fs_blank_wstat(&wstat);
1014 wstat.muid = v9ses->name; 1156 wstat.muid = v9ses->name;
1015 wstat.extension = (char *) extension; 1157 wstat.extension = (char *) extension;
1016 retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); 1158 err = v9fs_t_wstat(v9ses, vfid->fid, &wstat, &fcall);
1017 if (retval < 0) {
1018 PRINT_FCALL_ERROR("wstat error", fcall);
1019 goto free_mem;
1020 }
1021
1022 err = v9fs_t_clunk(v9ses, fid->fid);
1023 if (err < 0) { 1159 if (err < 0) {
1024 dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); 1160 PRINT_FCALL_ERROR("wstat error", fcall);
1025 goto free_mem; 1161 goto error;
1026 } 1162 }
1027 1163
1028 d_drop(dentry); /* FID - will this also clunk? */ 1164 kfree(fcall);
1165 dentry->d_op = &v9fs_dentry_operations;
1166 d_instantiate(dentry, inode);
1167 return 0;
1029 1168
1030free_mem: 1169error:
1031 kfree(fcall); 1170 kfree(fcall);
1032 return retval; 1171 if (vfid)
1172 v9fs_fid_destroy(vfid);
1173
1174 if (inode)
1175 iput(inode);
1176
1177 return err;
1178
1033} 1179}
1034 1180
1035/** 1181/**
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 2c4fa75be025..0c85872be51a 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -146,7 +146,6 @@ static struct super_block *v9fs_get_sb(struct file_system_type
146 inode->i_gid = gid; 146 inode->i_gid = gid;
147 147
148 root = d_alloc_root(inode); 148 root = d_alloc_root(inode);
149
150 if (!root) { 149 if (!root) {
151 retval = -ENOMEM; 150 retval = -ENOMEM;
152 goto put_back_sb; 151 goto put_back_sb;
@@ -157,24 +156,27 @@ static struct super_block *v9fs_get_sb(struct file_system_type
157 stat_result = v9fs_t_stat(v9ses, newfid, &fcall); 156 stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
158 if (stat_result < 0) { 157 if (stat_result < 0) {
159 dprintk(DEBUG_ERROR, "stat error\n"); 158 dprintk(DEBUG_ERROR, "stat error\n");
159 kfree(fcall);
160 v9fs_t_clunk(v9ses, newfid); 160 v9fs_t_clunk(v9ses, newfid);
161 v9fs_put_idpool(newfid, &v9ses->fidpool);
162 } else { 161 } else {
163 /* Setup the Root Inode */ 162 /* Setup the Root Inode */
164 root_fid = v9fs_fid_create(root, v9ses, newfid, 0); 163 kfree(fcall);
164 root_fid = v9fs_fid_create(v9ses, newfid);
165 if (root_fid == NULL) { 165 if (root_fid == NULL) {
166 retval = -ENOMEM; 166 retval = -ENOMEM;
167 goto put_back_sb; 167 goto put_back_sb;
168 } 168 }
169 169
170 retval = v9fs_fid_insert(root_fid, root);
171 if (retval < 0)
172 goto put_back_sb;
173
170 root_fid->qid = fcall->params.rstat.stat.qid; 174 root_fid->qid = fcall->params.rstat.stat.qid;
171 root->d_inode->i_ino = 175 root->d_inode->i_ino =
172 v9fs_qid2ino(&fcall->params.rstat.stat.qid); 176 v9fs_qid2ino(&fcall->params.rstat.stat.qid);
173 v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); 177 v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
174 } 178 }
175 179
176 kfree(fcall);
177
178 if (stat_result < 0) { 180 if (stat_result < 0) {
179 retval = stat_result; 181 retval = stat_result;
180 goto put_back_sb; 182 goto put_back_sb;