1 /* 2 * linux/fs/9p/vfs_inode.c 3 * 4 * This file contains vfs inode ops for the 9P2000 protocol. 5 * 6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 11 * as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to: 20 * Free Software Foundation 21 * 51 Franklin Street, Fifth Floor 22 * Boston, MA 02111-1301 USA 23 * 24 */ 25 26 #include <linux/module.h> 27 #include <linux/errno.h> 28 #include <linux/fs.h> 29 #include <linux/file.h> 30 #include <linux/pagemap.h> 31 #include <linux/stat.h> 32 #include <linux/string.h> 33 #include <linux/smp_lock.h> 34 #include <linux/inet.h> 35 #include <linux/namei.h> 36 #include <linux/idr.h> 37 38 #include "debug.h" 39 #include "v9fs.h" 40 #include "9p.h" 41 #include "v9fs_vfs.h" 42 #include "fid.h" 43 44 static struct inode_operations v9fs_dir_inode_operations; 45 static struct inode_operations v9fs_dir_inode_operations_ext; 46 static struct inode_operations v9fs_file_inode_operations; 47 static struct inode_operations v9fs_symlink_inode_operations; 48 49 /** 50 * unixmode2p9mode - convert unix mode bits to plan 9 51 * @v9ses: v9fs session information 52 * @mode: mode to convert 53 * 54 */ 55 56 static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) 57 { 58 int res; 59 res = mode & 0777; 60 if (S_ISDIR(mode)) 61 res |= V9FS_DMDIR; 62 if (v9ses->extended) { 63 if (S_ISLNK(mode)) 64 res |= V9FS_DMSYMLINK; 65 if (v9ses->nodev == 0) { 66 if (S_ISSOCK(mode)) 67 res |= V9FS_DMSOCKET; 68 if (S_ISFIFO(mode)) 69 res |= V9FS_DMNAMEDPIPE; 70 if (S_ISBLK(mode)) 71 res |= V9FS_DMDEVICE; 72 if (S_ISCHR(mode)) 73 res |= V9FS_DMDEVICE; 74 } 75 76 if ((mode & S_ISUID) == S_ISUID) 77 res |= V9FS_DMSETUID; 78 if ((mode & S_ISGID) == S_ISGID) 79 res |= V9FS_DMSETGID; 80 if ((mode & V9FS_DMLINK)) 81 res |= V9FS_DMLINK; 82 } 83 84 return res; 85 } 86 87 /** 88 * p9mode2unixmode- convert plan9 mode bits to unix mode bits 89 * @v9ses: v9fs session information 90 * @mode: mode to convert 91 * 92 */ 93 94 static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) 95 { 96 int res; 97 98 res = mode & 0777; 99 100 if ((mode & V9FS_DMDIR) == V9FS_DMDIR) 101 res |= S_IFDIR; 102 else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended)) 103 res |= S_IFLNK; 104 else if ((mode & V9FS_DMSOCKET) && (v9ses->extended) 105 && (v9ses->nodev == 0)) 106 res |= S_IFSOCK; 107 else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended) 108 && (v9ses->nodev == 0)) 109 res |= S_IFIFO; 110 else if ((mode & V9FS_DMDEVICE) && (v9ses->extended) 111 && (v9ses->nodev == 0)) 112 res |= S_IFBLK; 113 else 114 res |= S_IFREG; 115 116 if (v9ses->extended) { 117 if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID) 118 res |= S_ISUID; 119 120 if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID) 121 res |= S_ISGID; 122 } 123 124 return res; 125 } 126 127 int v9fs_uflags2omode(int uflags) 128 { 129 int ret; 130 131 ret = 0; 132 switch (uflags&3) { 133 default: 134 case O_RDONLY: 135 ret = V9FS_OREAD; 136 break; 137 138 case O_WRONLY: 139 ret = V9FS_OWRITE; 140 break; 141 142 case O_RDWR: 143 ret = V9FS_ORDWR; 144 break; 145 } 146 147 if (uflags & O_EXCL) 148 ret |= V9FS_OEXCL; 149 150 if (uflags & O_TRUNC) 151 ret |= V9FS_OTRUNC; 152 153 if (uflags & O_APPEND) 154 ret |= V9FS_OAPPEND; 155 156 return ret; 157 } 158 159 /** 160 * v9fs_blank_wstat - helper function to setup a 9P stat structure 161 * @v9ses: 9P session info (for determining extended mode) 162 * @wstat: structure to initialize 163 * 164 */ 165 166 static void 167 v9fs_blank_wstat(struct v9fs_wstat *wstat) 168 { 169 wstat->type = ~0; 170 wstat->dev = ~0; 171 wstat->qid.type = ~0; 172 wstat->qid.version = ~0; 173 *((long long *)&wstat->qid.path) = ~0; 174 wstat->mode = ~0; 175 wstat->atime = ~0; 176 wstat->mtime = ~0; 177 wstat->length = ~0; 178 wstat->name = NULL; 179 wstat->uid = NULL; 180 wstat->gid = NULL; 181 wstat->muid = NULL; 182 wstat->n_uid = ~0; 183 wstat->n_gid = ~0; 184 wstat->n_muid = ~0; 185 wstat->extension = NULL; 186 } 187 188 /** 189 * v9fs_get_inode - helper function to setup an inode 190 * @sb: superblock 191 * @mode: mode to setup inode with 192 * 193 */ 194 195 struct inode *v9fs_get_inode(struct super_block *sb, int mode) 196 { 197 struct inode *inode; 198 struct v9fs_session_info *v9ses = sb->s_fs_info; 199 200 dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); 201 202 inode = new_inode(sb); 203 if (inode) { 204 inode->i_mode = mode; 205 inode->i_uid = current->fsuid; 206 inode->i_gid = current->fsgid; 207 inode->i_blocks = 0; 208 inode->i_rdev = 0; 209 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 210 inode->i_mapping->a_ops = &v9fs_addr_operations; 211 212 switch (mode & S_IFMT) { 213 case S_IFIFO: 214 case S_IFBLK: 215 case S_IFCHR: 216 case S_IFSOCK: 217 if(!v9ses->extended) { 218 dprintk(DEBUG_ERROR, "special files without extended mode\n"); 219 return ERR_PTR(-EINVAL); 220 } 221 init_special_inode(inode, inode->i_mode, 222 inode->i_rdev); 223 break; 224 case S_IFREG: 225 inode->i_op = &v9fs_file_inode_operations; 226 inode->i_fop = &v9fs_file_operations; 227 break; 228 case S_IFLNK: 229 if(!v9ses->extended) { 230 dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); 231 return ERR_PTR(-EINVAL); 232 } 233 inode->i_op = &v9fs_symlink_inode_operations; 234 break; 235 case S_IFDIR: 236 inc_nlink(inode); 237 if(v9ses->extended) 238 inode->i_op = &v9fs_dir_inode_operations_ext; 239 else 240 inode->i_op = &v9fs_dir_inode_operations; 241 inode->i_fop = &v9fs_dir_operations; 242 break; 243 default: 244 dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", 245 mode, mode & S_IFMT); 246 return ERR_PTR(-EINVAL); 247 } 248 } else { 249 eprintk(KERN_WARNING, "Problem allocating inode\n"); 250 return ERR_PTR(-ENOMEM); 251 } 252 return inode; 253 } 254 255 static int 256 v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, 257 u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) 258 { 259 int fid; 260 int err; 261 struct v9fs_fcall *fcall; 262 263 fid = v9fs_get_idpool(&v9ses->fidpool); 264 if (fid < 0) { 265 eprintk(KERN_WARNING, "no free fids available\n"); 266 return -ENOSPC; 267 } 268 269 err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); 270 if (err < 0) { 271 PRINT_FCALL_ERROR("clone error", fcall); 272 if (fcall && fcall->id == RWALK) 273 goto clunk_fid; 274 else 275 goto put_fid; 276 } 277 kfree(fcall); 278 279 err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall); 280 if (err < 0) { 281 PRINT_FCALL_ERROR("create fails", fcall); 282 goto clunk_fid; 283 } 284 285 if (iounit) 286 *iounit = fcall->params.rcreate.iounit; 287 288 if (qid) 289 *qid = fcall->params.rcreate.qid; 290 291 if (fidp) 292 *fidp = fid; 293 294 kfree(fcall); 295 return 0; 296 297 clunk_fid: 298 v9fs_t_clunk(v9ses, fid); 299 fid = V9FS_NOFID; 300 301 put_fid: 302 if (fid != V9FS_NOFID) 303 v9fs_put_idpool(fid, &v9ses->fidpool); 304 305 kfree(fcall); 306 return err; 307 } 308 309 static struct v9fs_fid* 310 v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) 311 { 312 int err; 313 int nfid; 314 struct v9fs_fid *ret; 315 struct v9fs_fcall *fcall; 316 317 nfid = v9fs_get_idpool(&v9ses->fidpool); 318 if (nfid < 0) { 319 eprintk(KERN_WARNING, "no free fids available\n"); 320 return ERR_PTR(-ENOSPC); 321 } 322 323 err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, 324 &fcall); 325 326 if (err < 0) { 327 if (fcall && fcall->id == RWALK) 328 goto clunk_fid; 329 330 PRINT_FCALL_ERROR("walk error", fcall); 331 v9fs_put_idpool(nfid, &v9ses->fidpool); 332 goto error; 333 } 334 335 kfree(fcall); 336 fcall = NULL; 337 ret = v9fs_fid_create(v9ses, nfid); 338 if (!ret) { 339 err = -ENOMEM; 340 goto clunk_fid; 341 } 342 343 err = v9fs_fid_insert(ret, dentry); 344 if (err < 0) { 345 v9fs_fid_destroy(ret); 346 goto clunk_fid; 347 } 348 349 return ret; 350 351 clunk_fid: 352 v9fs_t_clunk(v9ses, nfid); 353 354 error: 355 kfree(fcall); 356 return ERR_PTR(err); 357 } 358 359 static struct inode * 360 v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, 361 struct super_block *sb) 362 { 363 int err, umode; 364 struct inode *ret; 365 struct v9fs_fcall *fcall; 366 367 ret = NULL; 368 err = v9fs_t_stat(v9ses, fid, &fcall); 369 if (err) { 370 PRINT_FCALL_ERROR("stat error", fcall); 371 goto error; 372 } 373 374 umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); 375 ret = v9fs_get_inode(sb, umode); 376 if (IS_ERR(ret)) { 377 err = PTR_ERR(ret); 378 ret = NULL; 379 goto error; 380 } 381 382 v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); 383 kfree(fcall); 384 return ret; 385 386 error: 387 kfree(fcall); 388 if (ret) 389 iput(ret); 390 391 return ERR_PTR(err); 392 } 393 394 /** 395 * v9fs_remove - helper function to remove files and directories 396 * @dir: directory inode that is being deleted 397 * @file: dentry that is being deleted 398 * @rmdir: removing a directory 399 * 400 */ 401 402 static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) 403 { 404 struct v9fs_fcall *fcall = NULL; 405 struct super_block *sb = NULL; 406 struct v9fs_session_info *v9ses = NULL; 407 struct v9fs_fid *v9fid = NULL; 408 struct inode *file_inode = NULL; 409 int fid = -1; 410 int result = 0; 411 412 dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, 413 rmdir); 414 415 file_inode = file->d_inode; 416 sb = file_inode->i_sb; 417 v9ses = v9fs_inode2v9ses(file_inode); 418 v9fid = v9fs_fid_lookup(file); 419 if(IS_ERR(v9fid)) 420 return PTR_ERR(v9fid); 421 422 fid = v9fid->fid; 423 if (fid < 0) { 424 dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", 425 file_inode->i_ino); 426 return -EBADF; 427 } 428 429 result = v9fs_t_remove(v9ses, fid, &fcall); 430 if (result < 0) { 431 PRINT_FCALL_ERROR("remove fails", fcall); 432 goto Error; 433 } 434 435 v9fs_put_idpool(fid, &v9ses->fidpool); 436 v9fs_fid_destroy(v9fid); 437 438 Error: 439 kfree(fcall); 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_clone(dentry->d_parent); 475 if(IS_ERR(dfid)) { 476 err = PTR_ERR(dfid); 477 goto error; 478 } 479 480 perm = unixmode2p9mode(v9ses, mode); 481 if (nd && nd->flags & LOOKUP_OPEN) 482 flags = nd->intent.open.flags - 1; 483 else 484 flags = O_RDWR; 485 486 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 487 perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); 488 489 if (err) 490 goto clunk_dfid; 491 492 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 493 v9fs_fid_clunk(v9ses, dfid); 494 if (IS_ERR(vfid)) { 495 err = PTR_ERR(vfid); 496 vfid = NULL; 497 goto error; 498 } 499 500 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 501 if (IS_ERR(inode)) { 502 err = PTR_ERR(inode); 503 inode = NULL; 504 goto error; 505 } 506 507 dentry->d_op = &v9fs_dentry_operations; 508 d_instantiate(dentry, inode); 509 510 if (nd && nd->flags & LOOKUP_OPEN) { 511 ffid = v9fs_fid_create(v9ses, fid); 512 if (!ffid) 513 return -ENOMEM; 514 515 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); 516 if (IS_ERR(filp)) { 517 v9fs_fid_destroy(ffid); 518 return PTR_ERR(filp); 519 } 520 521 ffid->rdir_pos = 0; 522 ffid->rdir_fcall = NULL; 523 ffid->fidopen = 1; 524 ffid->iounit = iounit; 525 ffid->filp = filp; 526 filp->private_data = ffid; 527 } 528 529 return 0; 530 531 clunk_dfid: 532 v9fs_fid_clunk(v9ses, dfid); 533 534 error: 535 if (vfid) 536 v9fs_fid_destroy(vfid); 537 538 return err; 539 } 540 541 /** 542 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory 543 * @inode: inode that is being unlinked 544 * @dentry: dentry that is being unlinked 545 * @mode: mode for new directory 546 * 547 */ 548 549 static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 550 { 551 int err; 552 u32 fid, perm; 553 struct v9fs_session_info *v9ses; 554 struct v9fs_fid *dfid, *vfid; 555 struct inode *inode; 556 557 inode = NULL; 558 vfid = NULL; 559 v9ses = v9fs_inode2v9ses(dir); 560 dfid = v9fs_fid_clone(dentry->d_parent); 561 if(IS_ERR(dfid)) { 562 err = PTR_ERR(dfid); 563 goto error; 564 } 565 566 perm = unixmode2p9mode(v9ses, mode | S_IFDIR); 567 568 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 569 perm, V9FS_OREAD, NULL, &fid, NULL, NULL); 570 571 if (err) { 572 dprintk(DEBUG_ERROR, "create error %d\n", err); 573 goto clean_up_dfid; 574 } 575 576 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 577 if (IS_ERR(vfid)) { 578 err = PTR_ERR(vfid); 579 vfid = NULL; 580 goto clean_up_dfid; 581 } 582 583 v9fs_fid_clunk(v9ses, dfid); 584 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 585 if (IS_ERR(inode)) { 586 err = PTR_ERR(inode); 587 inode = NULL; 588 goto clean_up_fids; 589 } 590 591 dentry->d_op = &v9fs_dentry_operations; 592 d_instantiate(dentry, inode); 593 return 0; 594 595 clean_up_fids: 596 if (vfid) 597 v9fs_fid_destroy(vfid); 598 599 clean_up_dfid: 600 v9fs_fid_clunk(v9ses, dfid); 601 602 error: 603 return err; 604 } 605 606 /** 607 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode 608 * @dir: inode that is being walked from 609 * @dentry: dentry that is being walked to? 610 * @nameidata: path data 611 * 612 */ 613 614 static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, 615 struct nameidata *nameidata) 616 { 617 struct super_block *sb; 618 struct v9fs_session_info *v9ses; 619 struct v9fs_fid *dirfid; 620 struct v9fs_fid *fid; 621 struct inode *inode; 622 struct v9fs_fcall *fcall = NULL; 623 int dirfidnum = -1; 624 int newfid = -1; 625 int result = 0; 626 627 dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", 628 dir, dentry->d_name.name, dentry, nameidata); 629 630 sb = dir->i_sb; 631 v9ses = v9fs_inode2v9ses(dir); 632 dentry->d_op = &v9fs_dentry_operations; 633 dirfid = v9fs_fid_lookup(dentry->d_parent); 634 635 if(IS_ERR(dirfid)) 636 return ERR_PTR(PTR_ERR(dirfid)); 637 638 dirfidnum = dirfid->fid; 639 640 newfid = v9fs_get_idpool(&v9ses->fidpool); 641 if (newfid < 0) { 642 eprintk(KERN_WARNING, "newfid fails!\n"); 643 result = -ENOSPC; 644 goto Release_Dirfid; 645 } 646 647 result = v9fs_t_walk(v9ses, dirfidnum, newfid, 648 (char *)dentry->d_name.name, &fcall); 649 650 up(&dirfid->lock); 651 652 if (result < 0) { 653 if (fcall && fcall->id == RWALK) 654 v9fs_t_clunk(v9ses, newfid); 655 else 656 v9fs_put_idpool(newfid, &v9ses->fidpool); 657 658 if (result == -ENOENT) { 659 d_add(dentry, NULL); 660 dprintk(DEBUG_VFS, 661 "Return negative dentry %p count %d\n", 662 dentry, atomic_read(&dentry->d_count)); 663 kfree(fcall); 664 return NULL; 665 } 666 dprintk(DEBUG_ERROR, "walk error:%d\n", result); 667 goto FreeFcall; 668 } 669 kfree(fcall); 670 671 result = v9fs_t_stat(v9ses, newfid, &fcall); 672 if (result < 0) { 673 dprintk(DEBUG_ERROR, "stat error\n"); 674 goto FreeFcall; 675 } 676 677 inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, 678 fcall->params.rstat.stat.mode)); 679 680 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { 681 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", 682 PTR_ERR(inode)); 683 684 result = -ENOSPC; 685 goto FreeFcall; 686 } 687 688 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); 689 690 fid = v9fs_fid_create(v9ses, newfid); 691 if (fid == NULL) { 692 dprintk(DEBUG_ERROR, "couldn't insert\n"); 693 result = -ENOMEM; 694 goto FreeFcall; 695 } 696 697 result = v9fs_fid_insert(fid, dentry); 698 if (result < 0) 699 goto FreeFcall; 700 701 fid->qid = fcall->params.rstat.stat.qid; 702 v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); 703 704 d_add(dentry, inode); 705 kfree(fcall); 706 707 return NULL; 708 709 Release_Dirfid: 710 up(&dirfid->lock); 711 712 FreeFcall: 713 kfree(fcall); 714 715 return ERR_PTR(result); 716 } 717 718 /** 719 * v9fs_vfs_unlink - VFS unlink hook to delete an inode 720 * @i: inode that is being unlinked 721 * @d: dentry that is being unlinked 722 * 723 */ 724 725 static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) 726 { 727 return v9fs_remove(i, d, 0); 728 } 729 730 /** 731 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory 732 * @i: inode that is being unlinked 733 * @d: dentry that is being unlinked 734 * 735 */ 736 737 static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) 738 { 739 return v9fs_remove(i, d, 1); 740 } 741 742 /** 743 * v9fs_vfs_rename - VFS hook to rename an inode 744 * @old_dir: old dir inode 745 * @old_dentry: old dentry 746 * @new_dir: new dir inode 747 * @new_dentry: new dentry 748 * 749 */ 750 751 static int 752 v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, 753 struct inode *new_dir, struct dentry *new_dentry) 754 { 755 struct inode *old_inode = old_dentry->d_inode; 756 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); 757 struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); 758 struct v9fs_fid *olddirfid; 759 struct v9fs_fid *newdirfid; 760 struct v9fs_wstat wstat; 761 struct v9fs_fcall *fcall = NULL; 762 int fid = -1; 763 int olddirfidnum = -1; 764 int newdirfidnum = -1; 765 int retval = 0; 766 767 dprintk(DEBUG_VFS, "\n"); 768 769 if(IS_ERR(oldfid)) 770 return PTR_ERR(oldfid); 771 772 olddirfid = v9fs_fid_clone(old_dentry->d_parent); 773 if(IS_ERR(olddirfid)) { 774 retval = PTR_ERR(olddirfid); 775 goto Release_lock; 776 } 777 778 newdirfid = v9fs_fid_clone(new_dentry->d_parent); 779 if(IS_ERR(newdirfid)) { 780 retval = PTR_ERR(newdirfid); 781 goto Clunk_olddir; 782 } 783 784 /* 9P can only handle file rename in the same directory */ 785 if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { 786 dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); 787 retval = -EXDEV; 788 goto Clunk_newdir; 789 } 790 791 fid = oldfid->fid; 792 olddirfidnum = olddirfid->fid; 793 newdirfidnum = newdirfid->fid; 794 795 if (fid < 0) { 796 dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", 797 old_inode->i_ino); 798 retval = -EBADF; 799 goto Clunk_newdir; 800 } 801 802 v9fs_blank_wstat(&wstat); 803 wstat.muid = v9ses->name; 804 wstat.name = (char *) new_dentry->d_name.name; 805 806 retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); 807 808 if (retval < 0) 809 PRINT_FCALL_ERROR("wstat error", fcall); 810 811 kfree(fcall); 812 813 Clunk_newdir: 814 v9fs_fid_clunk(v9ses, newdirfid); 815 816 Clunk_olddir: 817 v9fs_fid_clunk(v9ses, olddirfid); 818 819 Release_lock: 820 up(&oldfid->lock); 821 822 return retval; 823 } 824 825 /** 826 * v9fs_vfs_getattr - retrieve file metadata 827 * @mnt - mount information 828 * @dentry - file to get attributes on 829 * @stat - metadata structure to populate 830 * 831 */ 832 833 static int 834 v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 835 struct kstat *stat) 836 { 837 struct v9fs_fcall *fcall = NULL; 838 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 839 struct v9fs_fid *fid = v9fs_fid_clone(dentry); 840 int err = -EPERM; 841 842 dprintk(DEBUG_VFS, "dentry: %p\n", dentry); 843 if(IS_ERR(fid)) 844 return PTR_ERR(fid); 845 846 err = v9fs_t_stat(v9ses, fid->fid, &fcall); 847 848 if (err < 0) 849 dprintk(DEBUG_ERROR, "stat error\n"); 850 else { 851 v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, 852 dentry->d_inode->i_sb); 853 generic_fillattr(dentry->d_inode, stat); 854 } 855 856 kfree(fcall); 857 v9fs_fid_clunk(v9ses, fid); 858 return err; 859 } 860 861 /** 862 * v9fs_vfs_setattr - set file metadata 863 * @dentry: file whose metadata to set 864 * @iattr: metadata assignment structure 865 * 866 */ 867 868 static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) 869 { 870 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 871 struct v9fs_fid *fid = v9fs_fid_clone(dentry); 872 struct v9fs_fcall *fcall = NULL; 873 struct v9fs_wstat wstat; 874 int res = -EPERM; 875 876 dprintk(DEBUG_VFS, "\n"); 877 if(IS_ERR(fid)) 878 return PTR_ERR(fid); 879 880 v9fs_blank_wstat(&wstat); 881 if (iattr->ia_valid & ATTR_MODE) 882 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); 883 884 if (iattr->ia_valid & ATTR_MTIME) 885 wstat.mtime = iattr->ia_mtime.tv_sec; 886 887 if (iattr->ia_valid & ATTR_ATIME) 888 wstat.atime = iattr->ia_atime.tv_sec; 889 890 if (iattr->ia_valid & ATTR_SIZE) 891 wstat.length = iattr->ia_size; 892 893 if (v9ses->extended) { 894 if (iattr->ia_valid & ATTR_UID) 895 wstat.n_uid = iattr->ia_uid; 896 897 if (iattr->ia_valid & ATTR_GID) 898 wstat.n_gid = iattr->ia_gid; 899 } 900 901 res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); 902 903 if (res < 0) 904 PRINT_FCALL_ERROR("wstat error", fcall); 905 906 kfree(fcall); 907 if (res >= 0) 908 res = inode_setattr(dentry->d_inode, iattr); 909 910 v9fs_fid_clunk(v9ses, fid); 911 return res; 912 } 913 914 /** 915 * v9fs_stat2inode - populate an inode structure with mistat info 916 * @stat: Plan 9 metadata (mistat) structure 917 * @inode: inode to populate 918 * @sb: superblock of filesystem 919 * 920 */ 921 922 void 923 v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, 924 struct super_block *sb) 925 { 926 int n; 927 char ext[32]; 928 struct v9fs_session_info *v9ses = sb->s_fs_info; 929 930 inode->i_nlink = 1; 931 932 inode->i_atime.tv_sec = stat->atime; 933 inode->i_mtime.tv_sec = stat->mtime; 934 inode->i_ctime.tv_sec = stat->mtime; 935 936 inode->i_uid = v9ses->uid; 937 inode->i_gid = v9ses->gid; 938 939 if (v9ses->extended) { 940 inode->i_uid = stat->n_uid; 941 inode->i_gid = stat->n_gid; 942 } 943 944 inode->i_mode = p9mode2unixmode(v9ses, stat->mode); 945 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { 946 char type = 0; 947 int major = -1; 948 int minor = -1; 949 950 n = stat->extension.len; 951 if (n > sizeof(ext)-1) 952 n = sizeof(ext)-1; 953 memmove(ext, stat->extension.str, n); 954 ext[n] = 0; 955 sscanf(ext, "%c %u %u", &type, &major, &minor); 956 switch (type) { 957 case 'c': 958 inode->i_mode &= ~S_IFBLK; 959 inode->i_mode |= S_IFCHR; 960 break; 961 case 'b': 962 break; 963 default: 964 dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", 965 type, stat->extension.len, stat->extension.str); 966 }; 967 inode->i_rdev = MKDEV(major, minor); 968 } else 969 inode->i_rdev = 0; 970 971 inode->i_size = stat->length; 972 973 inode->i_blocks = 974 (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 975 } 976 977 /** 978 * v9fs_qid2ino - convert qid into inode number 979 * @qid: qid to hash 980 * 981 * BUG: potential for inode number collisions? 982 */ 983 984 ino_t v9fs_qid2ino(struct v9fs_qid *qid) 985 { 986 u64 path = qid->path + 2; 987 ino_t i = 0; 988 989 if (sizeof(ino_t) == sizeof(path)) 990 memcpy(&i, &path, sizeof(ino_t)); 991 else 992 i = (ino_t) (path ^ (path >> 32)); 993 994 return i; 995 } 996 997 /** 998 * v9fs_readlink - read a symlink's location (internal version) 999 * @dentry: dentry for symlink 1000 * @buffer: buffer to load symlink location into 1001 * @buflen: length of buffer 1002 * 1003 */ 1004 1005 static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) 1006 { 1007 int retval = -EPERM; 1008 1009 struct v9fs_fcall *fcall = NULL; 1010 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 1011 struct v9fs_fid *fid = v9fs_fid_clone(dentry); 1012 1013 if(IS_ERR(fid)) 1014 return PTR_ERR(fid); 1015 1016 if (!v9ses->extended) { 1017 retval = -EBADF; 1018 dprintk(DEBUG_ERROR, "not extended\n"); 1019 goto ClunkFid; 1020 } 1021 1022 dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); 1023 retval = v9fs_t_stat(v9ses, fid->fid, &fcall); 1024 1025 if (retval < 0) { 1026 dprintk(DEBUG_ERROR, "stat error\n"); 1027 goto FreeFcall; 1028 } 1029 1030 if (!fcall) { 1031 retval = -EIO; 1032 goto ClunkFid; 1033 } 1034 1035 if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { 1036 retval = -EINVAL; 1037 goto FreeFcall; 1038 } 1039 1040 /* copy extension buffer into buffer */ 1041 if (fcall->params.rstat.stat.extension.len < buflen) 1042 buflen = fcall->params.rstat.stat.extension.len + 1; 1043 1044 memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); 1045 buffer[buflen-1] = 0; 1046 1047 dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len, 1048 fcall->params.rstat.stat.extension.str, buffer); 1049 retval = buflen; 1050 1051 FreeFcall: 1052 kfree(fcall); 1053 1054 ClunkFid: 1055 v9fs_fid_clunk(v9ses, fid); 1056 1057 return retval; 1058 } 1059 1060 /** 1061 * v9fs_vfs_readlink - read a symlink's location 1062 * @dentry: dentry for symlink 1063 * @buf: buffer to load symlink location into 1064 * @buflen: length of buffer 1065 * 1066 */ 1067 1068 static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, 1069 int buflen) 1070 { 1071 int retval; 1072 int ret; 1073 char *link = __getname(); 1074 1075 if (unlikely(!link)) 1076 return -ENOMEM; 1077 1078 if (buflen > PATH_MAX) 1079 buflen = PATH_MAX; 1080 1081 dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 1082 1083 retval = v9fs_readlink(dentry, link, buflen); 1084 1085 if (retval > 0) { 1086 if ((ret = copy_to_user(buffer, link, retval)) != 0) { 1087 dprintk(DEBUG_ERROR, "problem copying to user: %d\n", 1088 ret); 1089 retval = ret; 1090 } 1091 } 1092 1093 __putname(link); 1094 return retval; 1095 } 1096 1097 /** 1098 * v9fs_vfs_follow_link - follow a symlink path 1099 * @dentry: dentry for symlink 1100 * @nd: nameidata 1101 * 1102 */ 1103 1104 static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) 1105 { 1106 int len = 0; 1107 char *link = __getname(); 1108 1109 dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); 1110 1111 if (!link) 1112 link = ERR_PTR(-ENOMEM); 1113 else { 1114 len = v9fs_readlink(dentry, link, PATH_MAX); 1115 1116 if (len < 0) { 1117 __putname(link); 1118 link = ERR_PTR(len); 1119 } else 1120 link[len] = 0; 1121 } 1122 nd_set_link(nd, link); 1123 1124 return NULL; 1125 } 1126 1127 /** 1128 * v9fs_vfs_put_link - release a symlink path 1129 * @dentry: dentry for symlink 1130 * @nd: nameidata 1131 * 1132 */ 1133 1134 static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) 1135 { 1136 char *s = nd_get_link(nd); 1137 1138 dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); 1139 if (!IS_ERR(s)) 1140 __putname(s); 1141 } 1142 1143 static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 1144 int mode, const char *extension) 1145 { 1146 int err; 1147 u32 fid, perm; 1148 struct v9fs_session_info *v9ses; 1149 struct v9fs_fid *dfid, *vfid = NULL; 1150 struct inode *inode = NULL; 1151 1152 v9ses = v9fs_inode2v9ses(dir); 1153 if (!v9ses->extended) { 1154 dprintk(DEBUG_ERROR, "not extended\n"); 1155 return -EPERM; 1156 } 1157 1158 dfid = v9fs_fid_clone(dentry->d_parent); 1159 if(IS_ERR(dfid)) { 1160 err = PTR_ERR(dfid); 1161 goto error; 1162 } 1163 1164 perm = unixmode2p9mode(v9ses, mode); 1165 1166 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 1167 perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); 1168 1169 if (err) 1170 goto clunk_dfid; 1171 1172 err = v9fs_t_clunk(v9ses, fid); 1173 if (err) 1174 goto clunk_dfid; 1175 1176 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 1177 if (IS_ERR(vfid)) { 1178 err = PTR_ERR(vfid); 1179 vfid = NULL; 1180 goto clunk_dfid; 1181 } 1182 1183 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 1184 if (IS_ERR(inode)) { 1185 err = PTR_ERR(inode); 1186 inode = NULL; 1187 goto free_vfid; 1188 } 1189 1190 dentry->d_op = &v9fs_dentry_operations; 1191 d_instantiate(dentry, inode); 1192 return 0; 1193 1194 free_vfid: 1195 v9fs_fid_destroy(vfid); 1196 1197 clunk_dfid: 1198 v9fs_fid_clunk(v9ses, dfid); 1199 1200 error: 1201 return err; 1202 1203 } 1204 1205 /** 1206 * v9fs_vfs_symlink - helper function to create symlinks 1207 * @dir: directory inode containing symlink 1208 * @dentry: dentry for symlink 1209 * @symname: symlink data 1210 * 1211 * See 9P2000.u RFC for more information 1212 * 1213 */ 1214 1215 static int 1216 v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 1217 { 1218 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 1219 symname); 1220 1221 return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); 1222 } 1223 1224 /** 1225 * v9fs_vfs_link - create a hardlink 1226 * @old_dentry: dentry for file to link to 1227 * @dir: inode destination for new link 1228 * @dentry: dentry for link 1229 * 1230 */ 1231 1232 /* XXX - lots of code dup'd from symlink and creates, 1233 * figure out a better reuse strategy 1234 */ 1235 1236 static int 1237 v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, 1238 struct dentry *dentry) 1239 { 1240 int retval; 1241 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); 1242 struct v9fs_fid *oldfid; 1243 char *name; 1244 1245 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 1246 old_dentry->d_name.name); 1247 1248 oldfid = v9fs_fid_clone(old_dentry); 1249 if(IS_ERR(oldfid)) 1250 return PTR_ERR(oldfid); 1251 1252 name = __getname(); 1253 if (unlikely(!name)) { 1254 retval = -ENOMEM; 1255 goto clunk_fid; 1256 } 1257 1258 sprintf(name, "%d\n", oldfid->fid); 1259 retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); 1260 __putname(name); 1261 1262 clunk_fid: 1263 v9fs_fid_clunk(v9ses, oldfid); 1264 return retval; 1265 } 1266 1267 /** 1268 * v9fs_vfs_mknod - create a special file 1269 * @dir: inode destination for new link 1270 * @dentry: dentry for file 1271 * @mode: mode for creation 1272 * @dev_t: device associated with special file 1273 * 1274 */ 1275 1276 static int 1277 v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) 1278 { 1279 int retval; 1280 char *name; 1281 1282 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, 1283 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); 1284 1285 if (!new_valid_dev(rdev)) 1286 return -EINVAL; 1287 1288 name = __getname(); 1289 if (!name) 1290 return -ENOMEM; 1291 /* build extension */ 1292 if (S_ISBLK(mode)) 1293 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); 1294 else if (S_ISCHR(mode)) 1295 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); 1296 else if (S_ISFIFO(mode)) 1297 *name = 0; 1298 else { 1299 __putname(name); 1300 return -EINVAL; 1301 } 1302 1303 retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); 1304 __putname(name); 1305 1306 return retval; 1307 } 1308 1309 static struct inode_operations v9fs_dir_inode_operations_ext = { 1310 .create = v9fs_vfs_create, 1311 .lookup = v9fs_vfs_lookup, 1312 .symlink = v9fs_vfs_symlink, 1313 .link = v9fs_vfs_link, 1314 .unlink = v9fs_vfs_unlink, 1315 .mkdir = v9fs_vfs_mkdir, 1316 .rmdir = v9fs_vfs_rmdir, 1317 .mknod = v9fs_vfs_mknod, 1318 .rename = v9fs_vfs_rename, 1319 .readlink = v9fs_vfs_readlink, 1320 .getattr = v9fs_vfs_getattr, 1321 .setattr = v9fs_vfs_setattr, 1322 }; 1323 1324 static struct inode_operations v9fs_dir_inode_operations = { 1325 .create = v9fs_vfs_create, 1326 .lookup = v9fs_vfs_lookup, 1327 .unlink = v9fs_vfs_unlink, 1328 .mkdir = v9fs_vfs_mkdir, 1329 .rmdir = v9fs_vfs_rmdir, 1330 .mknod = v9fs_vfs_mknod, 1331 .rename = v9fs_vfs_rename, 1332 .getattr = v9fs_vfs_getattr, 1333 .setattr = v9fs_vfs_setattr, 1334 }; 1335 1336 static struct inode_operations v9fs_file_inode_operations = { 1337 .getattr = v9fs_vfs_getattr, 1338 .setattr = v9fs_vfs_setattr, 1339 }; 1340 1341 static struct inode_operations v9fs_symlink_inode_operations = { 1342 .readlink = v9fs_vfs_readlink, 1343 .follow_link = v9fs_vfs_follow_link, 1344 .put_link = v9fs_vfs_put_link, 1345 .getattr = v9fs_vfs_getattr, 1346 .setattr = v9fs_vfs_setattr, 1347 }; 1348