diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2006-03-02 05:54:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-02 11:33:07 -0500 |
commit | 6a3124a3946c16159c3faf83e62ffdb5d1134b3a (patch) | |
tree | 989f1e89ed0971824db973af5347b879e12c67cd /fs/9p/vfs_inode.c | |
parent | 77a3313551afd53c90012e5a87f7f2b2195fc67e (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/vfs_inode.c')
-rw-r--r-- | fs/9p/vfs_inode.c | 478 |
1 files changed, 312 insertions, 166 deletions
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 | ||
128 | int 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 | ||
164 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | 196 | struct 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 | |||
234 | static int | 257 | static int |
235 | v9fs_create(struct inode *dir, | 258 | v9fs_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)) { | 297 | error: |
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; | 305 | static struct v9fs_fid* |
318 | if (err < 0) | 306 | v9fs_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); | 345 | clunk_fid: |
352 | if (result < 0) { | 346 | v9fs_t_clunk(v9ses, nfid); |
353 | PRINT_FCALL_ERROR("stat error", fcall); | 347 | |
354 | goto CleanUpFid; | 348 | error: |
355 | } | 349 | kfree(fcall); |
350 | return ERR_PTR(err); | ||
351 | } | ||
356 | 352 | ||
353 | struct inode * | ||
354 | v9fs_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: | 380 | error: |
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 | ||
439 | static int | ||
440 | v9fs_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 | ||
452 | static int | 454 | static int |
453 | v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, | 455 | v9fs_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 | |||
522 | error: | ||
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 | ||
467 | static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode) | 540 | static 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 | |||
586 | error: | ||
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 | |||
983 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | 1107 | static 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 | ||
1030 | free_mem: | 1169 | error: |
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 | /** |