[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>

authored by Latchesar Ionkov and committed by Linus Torvalds 6a3124a3 77a33135

+401 -318
+17 -56
fs/9p/fid.c
··· 40 * 41 */ 42 43 - static int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) 44 { 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, ··· 68 * 69 */ 70 71 - struct v9fs_fid *v9fs_fid_create(struct dentry *dentry, 72 - struct v9fs_session_info *v9ses, int fid, int create) 73 { 74 struct v9fs_fid *new; 75 76 - dprintk(DEBUG_9P, "fid create dentry %p, fid %d, create %d\n", 77 - dentry, fid, create); 78 - 79 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 80 if (new == NULL) { 81 dprintk(DEBUG_ERROR, "Out of Memory\n"); ··· 82 new->fid = fid; 83 new->v9ses = v9ses; 84 new->fidopen = 0; 85 - new->fidcreate = create; 86 new->fidclunked = 0; 87 new->iounit = 0; 88 new->rdir_pos = 0; 89 new->rdir_fcall = NULL; 90 91 - if (v9fs_fid_insert(new, dentry) == 0) 92 return new; 93 - else { 94 - dprintk(DEBUG_ERROR, "Problems inserting to dentry\n"); 95 - kfree(new); 96 - return NULL; 97 - } 98 } 99 100 /** ··· 110 static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) 111 { 112 int fidnum, cfidnum, err; 113 - struct v9fs_fid *cfid; 114 struct dentry *cde; 115 struct v9fs_session_info *v9ses; 116 ··· 149 cde = cde->d_parent; 150 } 151 152 - return v9fs_fid_create(dentry, v9ses, fidnum, 0); 153 154 clunk_fid: 155 v9fs_t_clunk(v9ses, fidnum); ··· 179 struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) 180 { 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; 185 186 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); 187 188 - if (fid_list) { 189 - list_for_each_entry_safe(current_fid, temp, fid_list, 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 206 if (!return_fid) { 207 struct dentry *par = current->fs->pwd->d_parent; ··· 210 } 211 212 return return_fid; 213 - } 214 - 215 - struct v9fs_fid *v9fs_fid_get_created(struct dentry *dentry) 216 - { 217 - struct list_head *fid_list; 218 - struct v9fs_fid *fid, *ftmp, *ret; 219 - 220 - dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); 221 - fid_list = (struct list_head *)dentry->d_fsdata; 222 - ret = NULL; 223 - if (fid_list) { 224 - list_for_each_entry_safe(fid, ftmp, fid_list, list) { 225 - if (fid->fidcreate && fid->pid == current->pid) { 226 - list_del(&fid->list); 227 - ret = fid; 228 - break; 229 - } 230 - } 231 - } 232 - 233 - dprintk(DEBUG_9P, "return %p\n", ret); 234 - return ret; 235 }
··· 40 * 41 */ 42 43 + int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry) 44 { 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, ··· 68 * 69 */ 70 71 + struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid) 72 { 73 struct v9fs_fid *new; 74 75 + dprintk(DEBUG_9P, "fid create fid %d\n", fid); 76 new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 77 if (new == NULL) { 78 dprintk(DEBUG_ERROR, "Out of Memory\n"); ··· 85 new->fid = fid; 86 new->v9ses = v9ses; 87 new->fidopen = 0; 88 new->fidclunked = 0; 89 new->iounit = 0; 90 new->rdir_pos = 0; 91 new->rdir_fcall = NULL; 92 + INIT_LIST_HEAD(&new->list); 93 94 return new; 95 } 96 97 /** ··· 119 static struct v9fs_fid *v9fs_fid_walk_up(struct dentry *dentry) 120 { 121 int fidnum, cfidnum, err; 122 + struct v9fs_fid *cfid, *fid; 123 struct dentry *cde; 124 struct v9fs_session_info *v9ses; 125 ··· 158 cde = cde->d_parent; 159 } 160 161 + fid = v9fs_fid_create(v9ses, fidnum); 162 + if (fid) { 163 + err = v9fs_fid_insert(fid, dentry); 164 + if (err < 0) { 165 + kfree(fid); 166 + goto clunk_fid; 167 + } 168 + } 169 + 170 + return fid; 171 172 clunk_fid: 173 v9fs_t_clunk(v9ses, fidnum); ··· 179 struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry) 180 { 181 struct list_head *fid_list = (struct list_head *)dentry->d_fsdata; 182 struct v9fs_fid *return_fid = NULL; 183 184 dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry); 185 186 + if (fid_list) 187 + return_fid = list_entry(fid_list->next, struct v9fs_fid, list); 188 189 if (!return_fid) { 190 struct dentry *par = current->fs->pwd->d_parent; ··· 227 } 228 229 return return_fid; 230 }
+2 -3
fs/9p/fid.h
··· 33 34 u32 fid; 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 */ 38 39 struct v9fs_qid qid; ··· 55 struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); 56 struct v9fs_fid *v9fs_fid_get_created(struct dentry *); 57 void v9fs_fid_destroy(struct v9fs_fid *fid); 58 - struct v9fs_fid *v9fs_fid_create(struct dentry *, 59 - struct v9fs_session_info *v9ses, int fid, int create);
··· 33 34 u32 fid; 35 unsigned char fidopen; /* set when fid is opened */ 36 unsigned char fidclunked; /* set when fid has already been clunked */ 37 38 struct v9fs_qid qid; ··· 56 struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry); 57 struct v9fs_fid *v9fs_fid_get_created(struct dentry *); 58 void v9fs_fid_destroy(struct v9fs_fid *fid); 59 + struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid); 60 + int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
+1
fs/9p/v9fs_vfs.h
··· 51 int v9fs_file_open(struct inode *inode, struct file *file); 52 void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); 53 void v9fs_dentry_release(struct dentry *);
··· 51 int v9fs_file_open(struct inode *inode, struct file *file); 52 void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat); 53 void v9fs_dentry_release(struct dentry *); 54 + int v9fs_uflags2omode(int uflags);
+46 -72
fs/9p/vfs_file.c
··· 53 int v9fs_file_open(struct inode *inode, struct file *file) 54 { 55 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 56 - struct v9fs_fid *v9fid, *fid; 57 struct v9fs_fcall *fcall = NULL; 58 - int open_mode = 0; 59 - unsigned int iounit = 0; 60 - int newfid = -1; 61 - long result = -1; 62 63 dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); 64 65 - v9fid = v9fs_fid_get_created(file->f_dentry); 66 - if (!v9fid) 67 - v9fid = v9fs_fid_lookup(file->f_dentry); 68 - 69 - if (!v9fid) { 70 dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); 71 return -EBADF; 72 } 73 74 - if (!v9fid->fidcreate) { 75 - fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); 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"); 90 return -ENOSPC; 91 } 92 93 - result = 94 - v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); 95 - 96 - if (result < 0) { 97 - v9fs_put_idpool(newfid, &v9ses->fidpool); 98 dprintk(DEBUG_ERROR, "rewalk didn't work\n"); 99 - return -EBADF; 100 - } 101 - 102 - fid->fid = newfid; 103 - v9fid = fid; 104 - /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ 105 - /* translate open mode appropriately */ 106 - open_mode = file->f_flags & 0x3; 107 - 108 - if (file->f_flags & O_EXCL) 109 - open_mode |= V9FS_OEXCL; 110 - 111 - if (v9ses->extended) { 112 - if (file->f_flags & O_TRUNC) 113 - open_mode |= V9FS_OTRUNC; 114 - 115 - if (file->f_flags & O_APPEND) 116 - open_mode |= V9FS_OAPPEND; 117 - } 118 - 119 - result = v9fs_t_open(v9ses, newfid, open_mode, &fcall); 120 - if (result < 0) { 121 - PRINT_FCALL_ERROR("open failed", fcall); 122 - kfree(fcall); 123 - return result; 124 - } 125 - 126 - iounit = fcall->params.ropen.iounit; 127 - 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 143 return 0; 144 } 145 146 /** ··· 265 total += result; 266 } while (count); 267 268 - if(inode->i_mapping->nrpages) 269 invalidate_inode_pages2(inode->i_mapping); 270 - 271 return total; 272 } 273
··· 53 int v9fs_file_open(struct inode *inode, struct file *file) 54 { 55 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 56 + struct v9fs_fid *vfid; 57 struct v9fs_fcall *fcall = NULL; 58 + int omode; 59 + int fid = V9FS_NOFID; 60 + int err; 61 62 dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); 63 64 + vfid = v9fs_fid_lookup(file->f_dentry); 65 + if (!vfid) { 66 dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); 67 return -EBADF; 68 } 69 70 + fid = v9fs_get_idpool(&v9ses->fidpool); 71 + if (fid < 0) { 72 eprintk(KERN_WARNING, "newfid fails!\n"); 73 return -ENOSPC; 74 } 75 76 + err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL); 77 + if (err < 0) { 78 dprintk(DEBUG_ERROR, "rewalk didn't work\n"); 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; 86 + } 87 88 + /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ 89 + /* translate open mode appropriately */ 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 + } 96 + 97 + file->private_data = vfid; 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); 106 107 return 0; 108 + 109 + destroy_vfid: 110 + v9fs_fid_destroy(vfid); 111 + 112 + clunk_fid: 113 + v9fs_t_clunk(v9ses, fid); 114 + 115 + put_fid: 116 + v9fs_put_idpool(fid, &v9ses->fidpool); 117 + kfree(fcall); 118 + 119 + return err; 120 } 121 122 /** ··· 289 total += result; 290 } while (count); 291 292 invalidate_inode_pages2(inode->i_mapping); 293 return total; 294 } 295
+328 -182
fs/9p/vfs_inode.c
··· 125 return res; 126 } 127 128 /** 129 * v9fs_blank_wstat - helper function to setup a 9P stat structure 130 * @v9ses: 9P session info (for determining extended mode) ··· 195 196 struct inode *v9fs_get_inode(struct super_block *sb, int mode) 197 { 198 - struct inode *inode = NULL; 199 struct v9fs_session_info *v9ses = sb->s_fs_info; 200 201 dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); ··· 254 return inode; 255 } 256 257 - /** 258 - * v9fs_create - helper function to create files and directories 259 - * @dir: directory inode file is being created in 260 - * @file_dentry: dentry file is being created in 261 - * @perm: permissions file is being created with 262 - * @open_mode: resulting open mode for file 263 - * 264 - */ 265 - 266 static int 267 - v9fs_create(struct inode *dir, 268 - struct dentry *file_dentry, 269 - unsigned int perm, unsigned int open_mode) 270 { 271 - struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); 272 - struct super_block *sb = dir->i_sb; 273 - struct v9fs_fid *dirfid = 274 - v9fs_fid_lookup(file_dentry->d_parent); 275 - struct v9fs_fid *fid = NULL; 276 - struct inode *file_inode = NULL; 277 - struct v9fs_fcall *fcall = NULL; 278 - struct v9fs_qid qid; 279 - int dirfidnum = -1; 280 - long newfid = -1; 281 - int result = 0; 282 - unsigned int iounit = 0; 283 - int wfidno = -1; 284 int err; 285 286 - perm = unixmode2p9mode(v9ses, perm); 287 - 288 - dprintk(DEBUG_VFS, "dir: %p dentry: %p perm: %o mode: %o\n", dir, 289 - file_dentry, perm, open_mode); 290 - 291 - if (!dirfid) 292 - return -EBADF; 293 - 294 - dirfidnum = dirfid->fid; 295 - if (dirfidnum < 0) { 296 - dprintk(DEBUG_ERROR, "No fid for the directory #%lu\n", 297 - dir->i_ino); 298 - return -EBADF; 299 - } 300 - 301 - if (file_dentry->d_inode) { 302 - dprintk(DEBUG_ERROR, 303 - "Odd. There is an inode for dir %lu, name :%s:\n", 304 - dir->i_ino, file_dentry->d_name.name); 305 - return -EEXIST; 306 - } 307 - 308 - newfid = v9fs_get_idpool(&v9ses->fidpool); 309 - if (newfid < 0) { 310 eprintk(KERN_WARNING, "no free fids available\n"); 311 - return -ENOSPC; 312 } 313 314 - result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); 315 - if (result < 0) { 316 PRINT_FCALL_ERROR("clone error", fcall); 317 - v9fs_put_idpool(newfid, &v9ses->fidpool); 318 - newfid = -1; 319 - goto CleanUpFid; 320 } 321 - 322 kfree(fcall); 323 - fcall = NULL; 324 325 - result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, 326 - perm, open_mode, &fcall); 327 - if (result < 0) { 328 PRINT_FCALL_ERROR("create fails", fcall); 329 - goto CleanUpFid; 330 } 331 332 - iounit = fcall->params.rcreate.iounit; 333 - qid = fcall->params.rcreate.qid; 334 kfree(fcall); 335 - fcall = NULL; 336 - 337 - if (!(perm&V9FS_DMDIR)) { 338 - fid = v9fs_fid_create(file_dentry, v9ses, newfid, 1); 339 - dprintk(DEBUG_VFS, "fid %p %d\n", fid, fid->fidcreate); 340 - if (!fid) { 341 - result = -ENOMEM; 342 - goto CleanUpFid; 343 - } 344 - 345 - fid->qid = qid; 346 - fid->iounit = iounit; 347 - } else { 348 - err = v9fs_t_clunk(v9ses, newfid); 349 - newfid = -1; 350 - if (err < 0) 351 - dprintk(DEBUG_ERROR, "clunk for mkdir failed: %d\n", err); 352 - } 353 - 354 - /* walk to the newly created file and put the fid in the dentry */ 355 - wfidno = v9fs_get_idpool(&v9ses->fidpool); 356 - if (wfidno < 0) { 357 - eprintk(KERN_WARNING, "no free fids available\n"); 358 - return -ENOSPC; 359 - } 360 - 361 - result = v9fs_t_walk(v9ses, dirfidnum, wfidno, 362 - (char *) file_dentry->d_name.name, &fcall); 363 - if (result < 0) { 364 - PRINT_FCALL_ERROR("clone error", fcall); 365 - v9fs_put_idpool(wfidno, &v9ses->fidpool); 366 - wfidno = -1; 367 - goto CleanUpFid; 368 - } 369 - kfree(fcall); 370 - fcall = NULL; 371 - 372 - if (!v9fs_fid_create(file_dentry, v9ses, wfidno, 0)) { 373 - v9fs_put_idpool(wfidno, &v9ses->fidpool); 374 - 375 - goto CleanUpFid; 376 - } 377 - 378 - if ((perm & V9FS_DMSYMLINK) || (perm & V9FS_DMLINK) || 379 - (perm & V9FS_DMNAMEDPIPE) || (perm & V9FS_DMSOCKET) || 380 - (perm & V9FS_DMDEVICE)) 381 - return 0; 382 - 383 - result = v9fs_t_stat(v9ses, wfidno, &fcall); 384 - if (result < 0) { 385 - PRINT_FCALL_ERROR("stat error", fcall); 386 - goto CleanUpFid; 387 - } 388 - 389 - 390 - file_inode = v9fs_get_inode(sb, 391 - p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode)); 392 - 393 - if ((!file_inode) || IS_ERR(file_inode)) { 394 - dprintk(DEBUG_ERROR, "create inode failed\n"); 395 - result = -EBADF; 396 - goto CleanUpFid; 397 - } 398 - 399 - v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb); 400 - kfree(fcall); 401 - fcall = NULL; 402 - file_dentry->d_op = &v9fs_dentry_operations; 403 - d_instantiate(file_dentry, file_inode); 404 - 405 return 0; 406 407 - CleanUpFid: 408 kfree(fcall); 409 fcall = NULL; 410 411 - if (newfid >= 0) { 412 - err = v9fs_t_clunk(v9ses, newfid); 413 - if (err < 0) 414 - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); 415 } 416 - if (wfidno >= 0) { 417 - err = v9fs_t_clunk(v9ses, wfidno); 418 - if (err < 0) 419 - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); 420 } 421 - return result; 422 } 423 424 /** ··· 436 return result; 437 } 438 439 /** 440 * v9fs_vfs_create - VFS hook to create files 441 * @inode: directory inode that is being deleted 442 * @dentry: dentry that is being deleted 443 - * @perm: create permissions 444 * @nd: path information 445 * 446 */ 447 448 static int 449 - v9fs_vfs_create(struct inode *inode, struct dentry *dentry, int perm, 450 struct nameidata *nd) 451 { 452 - return v9fs_create(inode, dentry, perm, O_RDWR); 453 } 454 455 /** ··· 537 * 538 */ 539 540 - static int v9fs_vfs_mkdir(struct inode *inode, struct dentry *dentry, int mode) 541 { 542 - return v9fs_create(inode, dentry, mode | S_IFDIR, O_RDONLY); 543 } 544 545 /** ··· 637 return ERR_PTR(-ENOSPC); 638 } 639 640 - result = 641 - v9fs_t_walk(v9ses, dirfidnum, newfid, (char *)dentry->d_name.name, 642 - NULL); 643 if (result < 0) { 644 v9fs_put_idpool(newfid, &v9ses->fidpool); 645 if (result == -ENOENT) { ··· 671 672 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); 673 674 - fid = v9fs_fid_create(dentry, v9ses, newfid, 0); 675 if (fid == NULL) { 676 dprintk(DEBUG_ERROR, "couldn't insert\n"); 677 result = -ENOMEM; 678 goto FreeFcall; 679 } 680 681 fid->qid = fcall->params.rstat.stat.qid; 682 ··· 1010 } 1011 1012 /* copy extension buffer into buffer */ 1013 - if (fcall->params.rstat.stat.extension.len+1 < buflen) 1014 - buflen = fcall->params.rstat.stat.extension.len + 1; 1015 1016 memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); 1017 buffer[buflen-1] = 0; ··· 1075 if (!link) 1076 link = ERR_PTR(-ENOMEM); 1077 else { 1078 - len = v9fs_readlink(dentry, link, PATH_MAX); 1079 1080 if (len < 0) { 1081 __putname(link); ··· 1107 static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 1108 int mode, const char *extension) 1109 { 1110 - int err, retval; 1111 struct v9fs_session_info *v9ses; 1112 struct v9fs_fcall *fcall; 1113 - struct v9fs_fid *fid; 1114 struct v9fs_wstat wstat; 1115 1116 - v9ses = v9fs_inode2v9ses(dir); 1117 - retval = -EPERM; 1118 fcall = NULL; 1119 1120 if (!v9ses->extended) { 1121 dprintk(DEBUG_ERROR, "not extended\n"); 1122 - goto free_mem; 1123 } 1124 1125 - /* issue a create */ 1126 - retval = v9fs_create(dir, dentry, mode, 0); 1127 - if (retval != 0) 1128 - goto free_mem; 1129 1130 - fid = v9fs_fid_get_created(dentry); 1131 - if (!fid) { 1132 - dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); 1133 - goto free_mem; 1134 } 1135 1136 /* issue a Twstat */ 1137 v9fs_blank_wstat(&wstat); 1138 wstat.muid = v9ses->name; 1139 wstat.extension = (char *) extension; 1140 - retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); 1141 - if (retval < 0) { 1142 - PRINT_FCALL_ERROR("wstat error", fcall); 1143 - goto free_mem; 1144 - } 1145 - 1146 - err = v9fs_t_clunk(v9ses, fid->fid); 1147 if (err < 0) { 1148 - dprintk(DEBUG_ERROR, "clunk failed: %d\n", err); 1149 - goto free_mem; 1150 } 1151 1152 - d_drop(dentry); /* FID - will this also clunk? */ 1153 - 1154 - free_mem: 1155 kfree(fcall); 1156 - return retval; 1157 } 1158 1159 /**
··· 125 return res; 126 } 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 + 160 /** 161 * v9fs_blank_wstat - helper function to setup a 9P stat structure 162 * @v9ses: 9P session info (for determining extended mode) ··· 163 164 struct inode *v9fs_get_inode(struct super_block *sb, int mode) 165 { 166 + struct inode *inode; 167 struct v9fs_session_info *v9ses = sb->s_fs_info; 168 169 dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); ··· 222 return inode; 223 } 224 225 static int 226 + v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, 227 + u32 perm, u8 mode, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) 228 { 229 + u32 fid; 230 int err; 231 + struct v9fs_fcall *fcall; 232 233 + fid = v9fs_get_idpool(&v9ses->fidpool); 234 + if (fid < 0) { 235 eprintk(KERN_WARNING, "no free fids available\n"); 236 + err = -ENOSPC; 237 + goto error; 238 } 239 240 + err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); 241 + if (err < 0) { 242 PRINT_FCALL_ERROR("clone error", fcall); 243 + goto error; 244 } 245 kfree(fcall); 246 247 + err = v9fs_t_create(v9ses, fid, name, perm, mode, &fcall); 248 + if (err < 0) { 249 PRINT_FCALL_ERROR("create fails", fcall); 250 + goto error; 251 } 252 253 + if (iounit) 254 + *iounit = fcall->params.rcreate.iounit; 255 + 256 + if (qid) 257 + *qid = fcall->params.rcreate.qid; 258 + 259 + if (fidp) 260 + *fidp = fid; 261 + 262 kfree(fcall); 263 return 0; 264 265 + error: 266 + if (fid >= 0) 267 + v9fs_put_idpool(fid, &v9ses->fidpool); 268 + 269 + kfree(fcall); 270 + return err; 271 + } 272 + 273 + static struct v9fs_fid* 274 + v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) 275 + { 276 + int err; 277 + u32 nfid; 278 + struct v9fs_fid *ret; 279 + struct v9fs_fcall *fcall; 280 + 281 + nfid = v9fs_get_idpool(&v9ses->fidpool); 282 + if (nfid < 0) { 283 + eprintk(KERN_WARNING, "no free fids available\n"); 284 + err = -ENOSPC; 285 + goto error; 286 + } 287 + 288 + err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, 289 + &fcall); 290 + 291 + if (err < 0) { 292 + PRINT_FCALL_ERROR("walk error", fcall); 293 + v9fs_put_idpool(nfid, &v9ses->fidpool); 294 + goto error; 295 + } 296 + 297 kfree(fcall); 298 fcall = NULL; 299 + ret = v9fs_fid_create(v9ses, nfid); 300 + if (!ret) { 301 + err = -ENOMEM; 302 + goto clunk_fid; 303 + } 304 305 + err = v9fs_fid_insert(ret, dentry); 306 + if (err < 0) { 307 + v9fs_fid_destroy(ret); 308 + goto clunk_fid; 309 } 310 + 311 + return ret; 312 + 313 + clunk_fid: 314 + v9fs_t_clunk(v9ses, nfid); 315 + 316 + error: 317 + kfree(fcall); 318 + return ERR_PTR(err); 319 + } 320 + 321 + struct inode * 322 + v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, 323 + struct super_block *sb) 324 + { 325 + int err, umode; 326 + struct inode *ret; 327 + struct v9fs_fcall *fcall; 328 + 329 + ret = NULL; 330 + err = v9fs_t_stat(v9ses, fid, &fcall); 331 + if (err) { 332 + PRINT_FCALL_ERROR("stat error", fcall); 333 + goto error; 334 } 335 + 336 + umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); 337 + ret = v9fs_get_inode(sb, umode); 338 + if (IS_ERR(ret)) { 339 + err = PTR_ERR(ret); 340 + ret = NULL; 341 + goto error; 342 + } 343 + 344 + v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); 345 + kfree(fcall); 346 + return ret; 347 + 348 + error: 349 + kfree(fcall); 350 + if (ret) 351 + iput(ret); 352 + 353 + return ERR_PTR(err); 354 } 355 356 /** ··· 440 return result; 441 } 442 443 + static int 444 + v9fs_open_created(struct inode *inode, struct file *file) 445 + { 446 + return 0; 447 + } 448 + 449 /** 450 * v9fs_vfs_create - VFS hook to create files 451 * @inode: directory inode that is being deleted 452 * @dentry: dentry that is being deleted 453 + * @mode: create permissions 454 * @nd: path information 455 * 456 */ 457 458 static int 459 + v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, 460 struct nameidata *nd) 461 { 462 + int err; 463 + u32 fid, perm, iounit; 464 + int flags; 465 + struct v9fs_session_info *v9ses; 466 + struct v9fs_fid *dfid, *vfid, *ffid; 467 + struct inode *inode; 468 + struct v9fs_qid qid; 469 + struct file *filp; 470 + 471 + inode = NULL; 472 + vfid = NULL; 473 + v9ses = v9fs_inode2v9ses(dir); 474 + dfid = v9fs_fid_lookup(dentry->d_parent); 475 + perm = unixmode2p9mode(v9ses, mode); 476 + 477 + if (nd && nd->flags & LOOKUP_OPEN) 478 + flags = nd->intent.open.flags - 1; 479 + else 480 + flags = O_RDWR; 481 + 482 + err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 483 + perm, v9fs_uflags2omode(flags), &fid, &qid, &iounit); 484 + 485 + if (err) 486 + goto error; 487 + 488 + vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 489 + if (IS_ERR(vfid)) { 490 + err = PTR_ERR(vfid); 491 + vfid = NULL; 492 + goto error; 493 + } 494 + 495 + inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 496 + if (IS_ERR(inode)) { 497 + err = PTR_ERR(inode); 498 + inode = NULL; 499 + goto error; 500 + } 501 + 502 + dentry->d_op = &v9fs_dentry_operations; 503 + d_instantiate(dentry, inode); 504 + 505 + if (nd && nd->flags & LOOKUP_OPEN) { 506 + ffid = v9fs_fid_create(v9ses, fid); 507 + if (!ffid) 508 + return -ENOMEM; 509 + 510 + filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); 511 + if (IS_ERR(filp)) { 512 + v9fs_fid_destroy(ffid); 513 + return PTR_ERR(filp); 514 + } 515 + 516 + ffid->rdir_pos = 0; 517 + ffid->rdir_fcall = NULL; 518 + ffid->fidopen = 1; 519 + ffid->iounit = iounit; 520 + ffid->filp = filp; 521 + filp->private_data = ffid; 522 + } 523 + 524 + return 0; 525 + 526 + error: 527 + if (vfid) 528 + v9fs_fid_destroy(vfid); 529 + 530 + if (inode) 531 + iput(inode); 532 + 533 + return err; 534 } 535 536 /** ··· 464 * 465 */ 466 467 + static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 468 { 469 + int err; 470 + u32 fid, perm; 471 + struct v9fs_session_info *v9ses; 472 + struct v9fs_fid *dfid, *vfid; 473 + struct inode *inode; 474 + 475 + inode = NULL; 476 + vfid = NULL; 477 + v9ses = v9fs_inode2v9ses(dir); 478 + dfid = v9fs_fid_lookup(dentry->d_parent); 479 + perm = unixmode2p9mode(v9ses, mode | S_IFDIR); 480 + 481 + err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 482 + perm, V9FS_OREAD, &fid, NULL, NULL); 483 + 484 + if (err) { 485 + dprintk(DEBUG_ERROR, "create error %d\n", err); 486 + goto error; 487 + } 488 + 489 + err = v9fs_t_clunk(v9ses, fid); 490 + if (err) { 491 + dprintk(DEBUG_ERROR, "clunk error %d\n", err); 492 + goto error; 493 + } 494 + 495 + vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 496 + if (IS_ERR(vfid)) { 497 + err = PTR_ERR(vfid); 498 + vfid = NULL; 499 + goto error; 500 + } 501 + 502 + inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 503 + if (IS_ERR(inode)) { 504 + err = PTR_ERR(inode); 505 + inode = NULL; 506 + goto error; 507 + } 508 + 509 + dentry->d_op = &v9fs_dentry_operations; 510 + d_instantiate(dentry, inode); 511 + return 0; 512 + 513 + error: 514 + if (vfid) 515 + v9fs_fid_destroy(vfid); 516 + 517 + return err; 518 } 519 520 /** ··· 516 return ERR_PTR(-ENOSPC); 517 } 518 519 + result = v9fs_t_walk(v9ses, dirfidnum, newfid, 520 + (char *)dentry->d_name.name, NULL); 521 if (result < 0) { 522 v9fs_put_idpool(newfid, &v9ses->fidpool); 523 if (result == -ENOENT) { ··· 551 552 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); 553 554 + fid = v9fs_fid_create(v9ses, newfid); 555 if (fid == NULL) { 556 dprintk(DEBUG_ERROR, "couldn't insert\n"); 557 result = -ENOMEM; 558 goto FreeFcall; 559 } 560 + 561 + result = v9fs_fid_insert(fid, dentry); 562 + if (result < 0) 563 + goto FreeFcall; 564 565 fid->qid = fcall->params.rstat.stat.qid; 566 ··· 886 } 887 888 /* copy extension buffer into buffer */ 889 + if (fcall->params.rstat.stat.extension.len < buflen) 890 + buflen = fcall->params.rstat.stat.extension.len; 891 892 memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); 893 buffer[buflen-1] = 0; ··· 951 if (!link) 952 link = ERR_PTR(-ENOMEM); 953 else { 954 + len = v9fs_readlink(dentry, link, strlen(link)); 955 956 if (len < 0) { 957 __putname(link); ··· 983 static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 984 int mode, const char *extension) 985 { 986 + int err; 987 + u32 fid, perm; 988 struct v9fs_session_info *v9ses; 989 + struct v9fs_fid *dfid, *vfid; 990 + struct inode *inode; 991 struct v9fs_fcall *fcall; 992 struct v9fs_wstat wstat; 993 994 fcall = NULL; 995 + inode = NULL; 996 + vfid = NULL; 997 + v9ses = v9fs_inode2v9ses(dir); 998 + dfid = v9fs_fid_lookup(dentry->d_parent); 999 + perm = unixmode2p9mode(v9ses, mode); 1000 1001 if (!v9ses->extended) { 1002 dprintk(DEBUG_ERROR, "not extended\n"); 1003 + return -EPERM; 1004 } 1005 1006 + err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 1007 + perm, V9FS_OREAD, &fid, NULL, NULL); 1008 1009 + if (err) 1010 + goto error; 1011 + 1012 + err = v9fs_t_clunk(v9ses, fid); 1013 + if (err) 1014 + goto error; 1015 + 1016 + vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 1017 + if (IS_ERR(vfid)) { 1018 + err = PTR_ERR(vfid); 1019 + vfid = NULL; 1020 + goto error; 1021 + } 1022 + 1023 + inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 1024 + if (IS_ERR(inode)) { 1025 + err = PTR_ERR(inode); 1026 + inode = NULL; 1027 + goto error; 1028 } 1029 1030 /* issue a Twstat */ 1031 v9fs_blank_wstat(&wstat); 1032 wstat.muid = v9ses->name; 1033 wstat.extension = (char *) extension; 1034 + err = v9fs_t_wstat(v9ses, vfid->fid, &wstat, &fcall); 1035 if (err < 0) { 1036 + PRINT_FCALL_ERROR("wstat error", fcall); 1037 + goto error; 1038 } 1039 1040 kfree(fcall); 1041 + dentry->d_op = &v9fs_dentry_operations; 1042 + d_instantiate(dentry, inode); 1043 + return 0; 1044 + 1045 + error: 1046 + kfree(fcall); 1047 + if (vfid) 1048 + v9fs_fid_destroy(vfid); 1049 + 1050 + if (inode) 1051 + iput(inode); 1052 + 1053 + return err; 1054 + 1055 } 1056 1057 /**
+7 -5
fs/9p/vfs_super.c
··· 146 inode->i_gid = gid; 147 148 root = d_alloc_root(inode); 149 - 150 if (!root) { 151 retval = -ENOMEM; 152 goto put_back_sb; ··· 156 stat_result = v9fs_t_stat(v9ses, newfid, &fcall); 157 if (stat_result < 0) { 158 dprintk(DEBUG_ERROR, "stat error\n"); 159 v9fs_t_clunk(v9ses, newfid); 160 - v9fs_put_idpool(newfid, &v9ses->fidpool); 161 } else { 162 /* Setup the Root Inode */ 163 - root_fid = v9fs_fid_create(root, v9ses, newfid, 0); 164 if (root_fid == NULL) { 165 retval = -ENOMEM; 166 goto put_back_sb; 167 } 168 169 root_fid->qid = fcall->params.rstat.stat.qid; 170 root->d_inode->i_ino = 171 v9fs_qid2ino(&fcall->params.rstat.stat.qid); 172 v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); 173 } 174 - 175 - kfree(fcall); 176 177 if (stat_result < 0) { 178 retval = stat_result;
··· 146 inode->i_gid = gid; 147 148 root = d_alloc_root(inode); 149 if (!root) { 150 retval = -ENOMEM; 151 goto put_back_sb; ··· 157 stat_result = v9fs_t_stat(v9ses, newfid, &fcall); 158 if (stat_result < 0) { 159 dprintk(DEBUG_ERROR, "stat error\n"); 160 + kfree(fcall); 161 v9fs_t_clunk(v9ses, newfid); 162 } else { 163 /* Setup the Root Inode */ 164 + kfree(fcall); 165 + root_fid = v9fs_fid_create(v9ses, newfid); 166 if (root_fid == NULL) { 167 retval = -ENOMEM; 168 goto put_back_sb; 169 } 170 + 171 + retval = v9fs_fid_insert(root_fid, root); 172 + if (retval < 0) 173 + goto put_back_sb; 174 175 root_fid->qid = fcall->params.rstat.stat.qid; 176 root->d_inode->i_ino = 177 v9fs_qid2ino(&fcall->params.rstat.stat.qid); 178 v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb); 179 } 180 181 if (stat_result < 0) { 182 retval = stat_result;