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_blksize = sb->s_blocksize; 208 inode->i_blocks = 0; 209 inode->i_rdev = 0; 210 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 211 inode->i_mapping->a_ops = &v9fs_addr_operations; 212 213 switch (mode & S_IFMT) { 214 case S_IFIFO: 215 case S_IFBLK: 216 case S_IFCHR: 217 case S_IFSOCK: 218 if(!v9ses->extended) { 219 dprintk(DEBUG_ERROR, "special files without extended mode\n"); 220 return ERR_PTR(-EINVAL); 221 } 222 init_special_inode(inode, inode->i_mode, 223 inode->i_rdev); 224 break; 225 case S_IFREG: 226 inode->i_op = &v9fs_file_inode_operations; 227 inode->i_fop = &v9fs_file_operations; 228 break; 229 case S_IFLNK: 230 if(!v9ses->extended) { 231 dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); 232 return ERR_PTR(-EINVAL); 233 } 234 inode->i_op = &v9fs_symlink_inode_operations; 235 break; 236 case S_IFDIR: 237 inode->i_nlink++; 238 if(v9ses->extended) 239 inode->i_op = &v9fs_dir_inode_operations_ext; 240 else 241 inode->i_op = &v9fs_dir_inode_operations; 242 inode->i_fop = &v9fs_dir_operations; 243 break; 244 default: 245 dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", 246 mode, mode & S_IFMT); 247 return ERR_PTR(-EINVAL); 248 } 249 } else { 250 eprintk(KERN_WARNING, "Problem allocating inode\n"); 251 return ERR_PTR(-ENOMEM); 252 } 253 return inode; 254 } 255 256 static int 257 v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, 258 u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) 259 { 260 u32 fid; 261 int err; 262 struct v9fs_fcall *fcall; 263 264 fid = v9fs_get_idpool(&v9ses->fidpool); 265 if (fid < 0) { 266 eprintk(KERN_WARNING, "no free fids available\n"); 267 return -ENOSPC; 268 } 269 270 err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); 271 if (err < 0) { 272 PRINT_FCALL_ERROR("clone error", fcall); 273 goto put_fid; 274 } 275 kfree(fcall); 276 277 err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall); 278 if (err < 0) { 279 PRINT_FCALL_ERROR("create fails", fcall); 280 goto clunk_fid; 281 } 282 283 if (iounit) 284 *iounit = fcall->params.rcreate.iounit; 285 286 if (qid) 287 *qid = fcall->params.rcreate.qid; 288 289 if (fidp) 290 *fidp = fid; 291 292 kfree(fcall); 293 return 0; 294 295 clunk_fid: 296 v9fs_t_clunk(v9ses, fid); 297 fid = V9FS_NOFID; 298 299 put_fid: 300 if (fid >= 0) 301 v9fs_put_idpool(fid, &v9ses->fidpool); 302 303 kfree(fcall); 304 return err; 305 } 306 307 static struct v9fs_fid* 308 v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) 309 { 310 int err; 311 u32 nfid; 312 struct v9fs_fid *ret; 313 struct v9fs_fcall *fcall; 314 315 nfid = v9fs_get_idpool(&v9ses->fidpool); 316 if (nfid < 0) { 317 eprintk(KERN_WARNING, "no free fids available\n"); 318 return ERR_PTR(-ENOSPC); 319 } 320 321 err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, 322 &fcall); 323 324 if (err < 0) { 325 PRINT_FCALL_ERROR("walk error", fcall); 326 v9fs_put_idpool(nfid, &v9ses->fidpool); 327 goto error; 328 } 329 330 kfree(fcall); 331 fcall = NULL; 332 ret = v9fs_fid_create(v9ses, nfid); 333 if (!ret) { 334 err = -ENOMEM; 335 goto clunk_fid; 336 } 337 338 err = v9fs_fid_insert(ret, dentry); 339 if (err < 0) { 340 v9fs_fid_destroy(ret); 341 goto clunk_fid; 342 } 343 344 return ret; 345 346 clunk_fid: 347 v9fs_t_clunk(v9ses, nfid); 348 349 error: 350 kfree(fcall); 351 return ERR_PTR(err); 352 } 353 354 static struct inode * 355 v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, 356 struct super_block *sb) 357 { 358 int err, umode; 359 struct inode *ret; 360 struct v9fs_fcall *fcall; 361 362 ret = NULL; 363 err = v9fs_t_stat(v9ses, fid, &fcall); 364 if (err) { 365 PRINT_FCALL_ERROR("stat error", fcall); 366 goto error; 367 } 368 369 umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); 370 ret = v9fs_get_inode(sb, umode); 371 if (IS_ERR(ret)) { 372 err = PTR_ERR(ret); 373 ret = NULL; 374 goto error; 375 } 376 377 v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); 378 kfree(fcall); 379 return ret; 380 381 error: 382 kfree(fcall); 383 if (ret) 384 iput(ret); 385 386 return ERR_PTR(err); 387 } 388 389 /** 390 * v9fs_remove - helper function to remove files and directories 391 * @dir: directory inode that is being deleted 392 * @file: dentry that is being deleted 393 * @rmdir: removing a directory 394 * 395 */ 396 397 static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) 398 { 399 struct v9fs_fcall *fcall = NULL; 400 struct super_block *sb = NULL; 401 struct v9fs_session_info *v9ses = NULL; 402 struct v9fs_fid *v9fid = NULL; 403 struct inode *file_inode = NULL; 404 int fid = -1; 405 int result = 0; 406 407 dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, 408 rmdir); 409 410 file_inode = file->d_inode; 411 sb = file_inode->i_sb; 412 v9ses = v9fs_inode2v9ses(file_inode); 413 v9fid = v9fs_fid_lookup(file); 414 415 if (!v9fid) { 416 dprintk(DEBUG_ERROR, 417 "no v9fs_fid\n"); 418 return -EBADF; 419 } 420 421 fid = v9fid->fid; 422 if (fid < 0) { 423 dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", 424 file_inode->i_ino); 425 return -EBADF; 426 } 427 428 result = v9fs_t_remove(v9ses, fid, &fcall); 429 if (result < 0) { 430 PRINT_FCALL_ERROR("remove fails", fcall); 431 } else { 432 v9fs_put_idpool(fid, &v9ses->fidpool); 433 v9fs_fid_destroy(v9fid); 434 } 435 436 kfree(fcall); 437 return result; 438 } 439 440 static int 441 v9fs_open_created(struct inode *inode, struct file *file) 442 { 443 return 0; 444 } 445 446 /** 447 * v9fs_vfs_create - VFS hook to create files 448 * @inode: directory inode that is being deleted 449 * @dentry: dentry that is being deleted 450 * @mode: create permissions 451 * @nd: path information 452 * 453 */ 454 455 static int 456 v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, 457 struct nameidata *nd) 458 { 459 int err; 460 u32 fid, perm, iounit; 461 int flags; 462 struct v9fs_session_info *v9ses; 463 struct v9fs_fid *dfid, *vfid, *ffid; 464 struct inode *inode; 465 struct v9fs_qid qid; 466 struct file *filp; 467 468 inode = NULL; 469 vfid = NULL; 470 v9ses = v9fs_inode2v9ses(dir); 471 dfid = v9fs_fid_lookup(dentry->d_parent); 472 perm = unixmode2p9mode(v9ses, mode); 473 474 if (nd && nd->flags & LOOKUP_OPEN) 475 flags = nd->intent.open.flags - 1; 476 else 477 flags = O_RDWR; 478 479 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 480 perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); 481 482 if (err) 483 goto error; 484 485 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 486 if (IS_ERR(vfid)) { 487 err = PTR_ERR(vfid); 488 vfid = NULL; 489 goto error; 490 } 491 492 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 493 if (IS_ERR(inode)) { 494 err = PTR_ERR(inode); 495 inode = NULL; 496 goto error; 497 } 498 499 dentry->d_op = &v9fs_dentry_operations; 500 d_instantiate(dentry, inode); 501 502 if (nd && nd->flags & LOOKUP_OPEN) { 503 ffid = v9fs_fid_create(v9ses, fid); 504 if (!ffid) 505 return -ENOMEM; 506 507 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); 508 if (IS_ERR(filp)) { 509 v9fs_fid_destroy(ffid); 510 return PTR_ERR(filp); 511 } 512 513 ffid->rdir_pos = 0; 514 ffid->rdir_fcall = NULL; 515 ffid->fidopen = 1; 516 ffid->iounit = iounit; 517 ffid->filp = filp; 518 filp->private_data = ffid; 519 } 520 521 return 0; 522 523 error: 524 if (vfid) 525 v9fs_fid_destroy(vfid); 526 527 if (inode) 528 iput(inode); 529 530 return err; 531 } 532 533 /** 534 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory 535 * @inode: inode that is being unlinked 536 * @dentry: dentry that is being unlinked 537 * @mode: mode for new directory 538 * 539 */ 540 541 static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 542 { 543 int err; 544 u32 fid, perm; 545 struct v9fs_session_info *v9ses; 546 struct v9fs_fid *dfid, *vfid; 547 struct inode *inode; 548 549 inode = NULL; 550 vfid = NULL; 551 v9ses = v9fs_inode2v9ses(dir); 552 dfid = v9fs_fid_lookup(dentry->d_parent); 553 perm = unixmode2p9mode(v9ses, mode | S_IFDIR); 554 555 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 556 perm, V9FS_OREAD, NULL, &fid, NULL, NULL); 557 558 if (err) { 559 dprintk(DEBUG_ERROR, "create error %d\n", err); 560 goto error; 561 } 562 563 err = v9fs_t_clunk(v9ses, fid); 564 if (err) { 565 dprintk(DEBUG_ERROR, "clunk error %d\n", err); 566 goto error; 567 } 568 569 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 570 if (IS_ERR(vfid)) { 571 err = PTR_ERR(vfid); 572 vfid = NULL; 573 goto error; 574 } 575 576 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 577 if (IS_ERR(inode)) { 578 err = PTR_ERR(inode); 579 inode = NULL; 580 goto error; 581 } 582 583 dentry->d_op = &v9fs_dentry_operations; 584 d_instantiate(dentry, inode); 585 return 0; 586 587 error: 588 if (vfid) 589 v9fs_fid_destroy(vfid); 590 591 return err; 592 } 593 594 /** 595 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode 596 * @dir: inode that is being walked from 597 * @dentry: dentry that is being walked to? 598 * @nameidata: path data 599 * 600 */ 601 602 static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, 603 struct nameidata *nameidata) 604 { 605 struct super_block *sb; 606 struct v9fs_session_info *v9ses; 607 struct v9fs_fid *dirfid; 608 struct v9fs_fid *fid; 609 struct inode *inode; 610 struct v9fs_fcall *fcall = NULL; 611 int dirfidnum = -1; 612 int newfid = -1; 613 int result = 0; 614 615 dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", 616 dir, dentry->d_name.name, dentry, nameidata); 617 618 sb = dir->i_sb; 619 v9ses = v9fs_inode2v9ses(dir); 620 dentry->d_op = &v9fs_dentry_operations; 621 dirfid = v9fs_fid_lookup(dentry->d_parent); 622 623 if (!dirfid) { 624 dprintk(DEBUG_ERROR, "no dirfid\n"); 625 return ERR_PTR(-EINVAL); 626 } 627 628 dirfidnum = dirfid->fid; 629 630 if (dirfidnum < 0) { 631 dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n", 632 dir, dir->i_ino); 633 return ERR_PTR(-EBADF); 634 } 635 636 newfid = v9fs_get_idpool(&v9ses->fidpool); 637 if (newfid < 0) { 638 eprintk(KERN_WARNING, "newfid fails!\n"); 639 return ERR_PTR(-ENOSPC); 640 } 641 642 result = v9fs_t_walk(v9ses, dirfidnum, newfid, 643 (char *)dentry->d_name.name, NULL); 644 if (result < 0) { 645 v9fs_put_idpool(newfid, &v9ses->fidpool); 646 if (result == -ENOENT) { 647 d_add(dentry, NULL); 648 dprintk(DEBUG_VFS, 649 "Return negative dentry %p count %d\n", 650 dentry, atomic_read(&dentry->d_count)); 651 return NULL; 652 } 653 dprintk(DEBUG_ERROR, "walk error:%d\n", result); 654 goto FreeFcall; 655 } 656 657 result = v9fs_t_stat(v9ses, newfid, &fcall); 658 if (result < 0) { 659 dprintk(DEBUG_ERROR, "stat error\n"); 660 goto FreeFcall; 661 } 662 663 inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, 664 fcall->params.rstat.stat.mode)); 665 666 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { 667 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", 668 PTR_ERR(inode)); 669 670 result = -ENOSPC; 671 goto FreeFcall; 672 } 673 674 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); 675 676 fid = v9fs_fid_create(v9ses, newfid); 677 if (fid == NULL) { 678 dprintk(DEBUG_ERROR, "couldn't insert\n"); 679 result = -ENOMEM; 680 goto FreeFcall; 681 } 682 683 result = v9fs_fid_insert(fid, dentry); 684 if (result < 0) 685 goto FreeFcall; 686 687 fid->qid = fcall->params.rstat.stat.qid; 688 v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); 689 690 d_add(dentry, inode); 691 kfree(fcall); 692 693 return NULL; 694 695 FreeFcall: 696 kfree(fcall); 697 return ERR_PTR(result); 698 } 699 700 /** 701 * v9fs_vfs_unlink - VFS unlink hook to delete an inode 702 * @i: inode that is being unlinked 703 * @d: dentry that is being unlinked 704 * 705 */ 706 707 static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) 708 { 709 return v9fs_remove(i, d, 0); 710 } 711 712 /** 713 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory 714 * @i: inode that is being unlinked 715 * @d: dentry that is being unlinked 716 * 717 */ 718 719 static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) 720 { 721 return v9fs_remove(i, d, 1); 722 } 723 724 /** 725 * v9fs_vfs_rename - VFS hook to rename an inode 726 * @old_dir: old dir inode 727 * @old_dentry: old dentry 728 * @new_dir: new dir inode 729 * @new_dentry: new dentry 730 * 731 */ 732 733 static int 734 v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, 735 struct inode *new_dir, struct dentry *new_dentry) 736 { 737 struct inode *old_inode = old_dentry->d_inode; 738 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); 739 struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); 740 struct v9fs_fid *olddirfid = 741 v9fs_fid_lookup(old_dentry->d_parent); 742 struct v9fs_fid *newdirfid = 743 v9fs_fid_lookup(new_dentry->d_parent); 744 struct v9fs_wstat wstat; 745 struct v9fs_fcall *fcall = NULL; 746 int fid = -1; 747 int olddirfidnum = -1; 748 int newdirfidnum = -1; 749 int retval = 0; 750 751 dprintk(DEBUG_VFS, "\n"); 752 753 if ((!oldfid) || (!olddirfid) || (!newdirfid)) { 754 dprintk(DEBUG_ERROR, "problem with arguments\n"); 755 return -EBADF; 756 } 757 758 /* 9P can only handle file rename in the same directory */ 759 if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { 760 dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); 761 retval = -EPERM; 762 goto FreeFcallnBail; 763 } 764 765 fid = oldfid->fid; 766 olddirfidnum = olddirfid->fid; 767 newdirfidnum = newdirfid->fid; 768 769 if (fid < 0) { 770 dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", 771 old_inode->i_ino); 772 retval = -EBADF; 773 goto FreeFcallnBail; 774 } 775 776 v9fs_blank_wstat(&wstat); 777 wstat.muid = v9ses->name; 778 wstat.name = (char *) new_dentry->d_name.name; 779 780 retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); 781 782 FreeFcallnBail: 783 if (retval < 0) 784 PRINT_FCALL_ERROR("wstat error", fcall); 785 786 kfree(fcall); 787 return retval; 788 } 789 790 /** 791 * v9fs_vfs_getattr - retrieve file metadata 792 * @mnt - mount information 793 * @dentry - file to get attributes on 794 * @stat - metadata structure to populate 795 * 796 */ 797 798 static int 799 v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 800 struct kstat *stat) 801 { 802 struct v9fs_fcall *fcall = NULL; 803 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 804 struct v9fs_fid *fid = v9fs_fid_lookup(dentry); 805 int err = -EPERM; 806 807 dprintk(DEBUG_VFS, "dentry: %p\n", dentry); 808 if (!fid) { 809 dprintk(DEBUG_ERROR, 810 "couldn't find fid associated with dentry\n"); 811 return -EBADF; 812 } 813 814 err = v9fs_t_stat(v9ses, fid->fid, &fcall); 815 816 if (err < 0) 817 dprintk(DEBUG_ERROR, "stat error\n"); 818 else { 819 v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, 820 dentry->d_inode->i_sb); 821 generic_fillattr(dentry->d_inode, stat); 822 } 823 824 kfree(fcall); 825 return err; 826 } 827 828 /** 829 * v9fs_vfs_setattr - set file metadata 830 * @dentry: file whose metadata to set 831 * @iattr: metadata assignment structure 832 * 833 */ 834 835 static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) 836 { 837 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 838 struct v9fs_fid *fid = v9fs_fid_lookup(dentry); 839 struct v9fs_fcall *fcall = NULL; 840 struct v9fs_wstat wstat; 841 int res = -EPERM; 842 843 dprintk(DEBUG_VFS, "\n"); 844 845 if (!fid) { 846 dprintk(DEBUG_ERROR, 847 "Couldn't find fid associated with dentry\n"); 848 return -EBADF; 849 } 850 851 v9fs_blank_wstat(&wstat); 852 if (iattr->ia_valid & ATTR_MODE) 853 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); 854 855 if (iattr->ia_valid & ATTR_MTIME) 856 wstat.mtime = iattr->ia_mtime.tv_sec; 857 858 if (iattr->ia_valid & ATTR_ATIME) 859 wstat.atime = iattr->ia_atime.tv_sec; 860 861 if (iattr->ia_valid & ATTR_SIZE) 862 wstat.length = iattr->ia_size; 863 864 if (v9ses->extended) { 865 if (iattr->ia_valid & ATTR_UID) 866 wstat.n_uid = iattr->ia_uid; 867 868 if (iattr->ia_valid & ATTR_GID) 869 wstat.n_gid = iattr->ia_gid; 870 } 871 872 res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); 873 874 if (res < 0) 875 PRINT_FCALL_ERROR("wstat error", fcall); 876 877 kfree(fcall); 878 if (res >= 0) 879 res = inode_setattr(dentry->d_inode, iattr); 880 881 return res; 882 } 883 884 /** 885 * v9fs_stat2inode - populate an inode structure with mistat info 886 * @stat: Plan 9 metadata (mistat) structure 887 * @inode: inode to populate 888 * @sb: superblock of filesystem 889 * 890 */ 891 892 void 893 v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, 894 struct super_block *sb) 895 { 896 int n; 897 char ext[32]; 898 struct v9fs_session_info *v9ses = sb->s_fs_info; 899 900 inode->i_nlink = 1; 901 902 inode->i_atime.tv_sec = stat->atime; 903 inode->i_mtime.tv_sec = stat->mtime; 904 inode->i_ctime.tv_sec = stat->mtime; 905 906 inode->i_uid = v9ses->uid; 907 inode->i_gid = v9ses->gid; 908 909 if (v9ses->extended) { 910 inode->i_uid = stat->n_uid; 911 inode->i_gid = stat->n_gid; 912 } 913 914 inode->i_mode = p9mode2unixmode(v9ses, stat->mode); 915 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { 916 char type = 0; 917 int major = -1; 918 int minor = -1; 919 920 n = stat->extension.len; 921 if (n > sizeof(ext)-1) 922 n = sizeof(ext)-1; 923 memmove(ext, stat->extension.str, n); 924 ext[n] = 0; 925 sscanf(ext, "%c %u %u", &type, &major, &minor); 926 switch (type) { 927 case 'c': 928 inode->i_mode &= ~S_IFBLK; 929 inode->i_mode |= S_IFCHR; 930 break; 931 case 'b': 932 break; 933 default: 934 dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", 935 type, stat->extension.len, stat->extension.str); 936 }; 937 inode->i_rdev = MKDEV(major, minor); 938 } else 939 inode->i_rdev = 0; 940 941 inode->i_size = stat->length; 942 943 inode->i_blksize = sb->s_blocksize; 944 inode->i_blocks = 945 (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits; 946 } 947 948 /** 949 * v9fs_qid2ino - convert qid into inode number 950 * @qid: qid to hash 951 * 952 * BUG: potential for inode number collisions? 953 */ 954 955 ino_t v9fs_qid2ino(struct v9fs_qid *qid) 956 { 957 u64 path = qid->path + 2; 958 ino_t i = 0; 959 960 if (sizeof(ino_t) == sizeof(path)) 961 memcpy(&i, &path, sizeof(ino_t)); 962 else 963 i = (ino_t) (path ^ (path >> 32)); 964 965 return i; 966 } 967 968 /** 969 * v9fs_readlink - read a symlink's location (internal version) 970 * @dentry: dentry for symlink 971 * @buffer: buffer to load symlink location into 972 * @buflen: length of buffer 973 * 974 */ 975 976 static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) 977 { 978 int retval = -EPERM; 979 980 struct v9fs_fcall *fcall = NULL; 981 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 982 struct v9fs_fid *fid = v9fs_fid_lookup(dentry); 983 984 if (!fid) { 985 dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); 986 retval = -EBADF; 987 goto FreeFcall; 988 } 989 990 if (!v9ses->extended) { 991 retval = -EBADF; 992 dprintk(DEBUG_ERROR, "not extended\n"); 993 goto FreeFcall; 994 } 995 996 dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); 997 retval = v9fs_t_stat(v9ses, fid->fid, &fcall); 998 999 if (retval < 0) { 1000 dprintk(DEBUG_ERROR, "stat error\n"); 1001 goto FreeFcall; 1002 } 1003 1004 if (!fcall) 1005 return -EIO; 1006 1007 if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { 1008 retval = -EINVAL; 1009 goto FreeFcall; 1010 } 1011 1012 /* copy extension buffer into buffer */ 1013 if (fcall->params.rstat.stat.extension.len < buflen) 1014 buflen = fcall->params.rstat.stat.extension.len + 1; 1015 1016 memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); 1017 buffer[buflen-1] = 0; 1018 1019 dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len, 1020 fcall->params.rstat.stat.extension.str, buffer); 1021 retval = buflen; 1022 1023 FreeFcall: 1024 kfree(fcall); 1025 1026 return retval; 1027 } 1028 1029 /** 1030 * v9fs_vfs_readlink - read a symlink's location 1031 * @dentry: dentry for symlink 1032 * @buf: buffer to load symlink location into 1033 * @buflen: length of buffer 1034 * 1035 */ 1036 1037 static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, 1038 int buflen) 1039 { 1040 int retval; 1041 int ret; 1042 char *link = __getname(); 1043 1044 if (buflen > PATH_MAX) 1045 buflen = PATH_MAX; 1046 1047 dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); 1048 1049 retval = v9fs_readlink(dentry, link, buflen); 1050 1051 if (retval > 0) { 1052 if ((ret = copy_to_user(buffer, link, retval)) != 0) { 1053 dprintk(DEBUG_ERROR, "problem copying to user: %d\n", 1054 ret); 1055 retval = ret; 1056 } 1057 } 1058 1059 __putname(link); 1060 return retval; 1061 } 1062 1063 /** 1064 * v9fs_vfs_follow_link - follow a symlink path 1065 * @dentry: dentry for symlink 1066 * @nd: nameidata 1067 * 1068 */ 1069 1070 static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) 1071 { 1072 int len = 0; 1073 char *link = __getname(); 1074 1075 dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); 1076 1077 if (!link) 1078 link = ERR_PTR(-ENOMEM); 1079 else { 1080 len = v9fs_readlink(dentry, link, PATH_MAX); 1081 1082 if (len < 0) { 1083 __putname(link); 1084 link = ERR_PTR(len); 1085 } else 1086 link[len] = 0; 1087 } 1088 nd_set_link(nd, link); 1089 1090 return NULL; 1091 } 1092 1093 /** 1094 * v9fs_vfs_put_link - release a symlink path 1095 * @dentry: dentry for symlink 1096 * @nd: nameidata 1097 * 1098 */ 1099 1100 static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) 1101 { 1102 char *s = nd_get_link(nd); 1103 1104 dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); 1105 if (!IS_ERR(s)) 1106 __putname(s); 1107 } 1108 1109 static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 1110 int mode, const char *extension) 1111 { 1112 int err; 1113 u32 fid, perm; 1114 struct v9fs_session_info *v9ses; 1115 struct v9fs_fid *dfid, *vfid; 1116 struct inode *inode; 1117 1118 inode = NULL; 1119 vfid = NULL; 1120 v9ses = v9fs_inode2v9ses(dir); 1121 dfid = v9fs_fid_lookup(dentry->d_parent); 1122 perm = unixmode2p9mode(v9ses, mode); 1123 1124 if (!v9ses->extended) { 1125 dprintk(DEBUG_ERROR, "not extended\n"); 1126 return -EPERM; 1127 } 1128 1129 err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, 1130 perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); 1131 1132 if (err) 1133 goto error; 1134 1135 err = v9fs_t_clunk(v9ses, fid); 1136 if (err) 1137 goto error; 1138 1139 vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); 1140 if (IS_ERR(vfid)) { 1141 err = PTR_ERR(vfid); 1142 vfid = NULL; 1143 goto error; 1144 } 1145 1146 inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); 1147 if (IS_ERR(inode)) { 1148 err = PTR_ERR(inode); 1149 inode = NULL; 1150 goto error; 1151 } 1152 1153 dentry->d_op = &v9fs_dentry_operations; 1154 d_instantiate(dentry, inode); 1155 return 0; 1156 1157 error: 1158 if (vfid) 1159 v9fs_fid_destroy(vfid); 1160 1161 if (inode) 1162 iput(inode); 1163 1164 return err; 1165 1166 } 1167 1168 /** 1169 * v9fs_vfs_symlink - helper function to create symlinks 1170 * @dir: directory inode containing symlink 1171 * @dentry: dentry for symlink 1172 * @symname: symlink data 1173 * 1174 * See 9P2000.u RFC for more information 1175 * 1176 */ 1177 1178 static int 1179 v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 1180 { 1181 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 1182 symname); 1183 1184 return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); 1185 } 1186 1187 /** 1188 * v9fs_vfs_link - create a hardlink 1189 * @old_dentry: dentry for file to link to 1190 * @dir: inode destination for new link 1191 * @dentry: dentry for link 1192 * 1193 */ 1194 1195 /* XXX - lots of code dup'd from symlink and creates, 1196 * figure out a better reuse strategy 1197 */ 1198 1199 static int 1200 v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, 1201 struct dentry *dentry) 1202 { 1203 int retval; 1204 struct v9fs_fid *oldfid; 1205 char *name; 1206 1207 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 1208 old_dentry->d_name.name); 1209 1210 oldfid = v9fs_fid_lookup(old_dentry); 1211 if (!oldfid) { 1212 dprintk(DEBUG_ERROR, "can't find oldfid\n"); 1213 return -EPERM; 1214 } 1215 1216 name = __getname(); 1217 sprintf(name, "%d\n", oldfid->fid); 1218 retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); 1219 __putname(name); 1220 1221 return retval; 1222 } 1223 1224 /** 1225 * v9fs_vfs_mknod - create a special file 1226 * @dir: inode destination for new link 1227 * @dentry: dentry for file 1228 * @mode: mode for creation 1229 * @dev_t: device associated with special file 1230 * 1231 */ 1232 1233 static int 1234 v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) 1235 { 1236 int retval; 1237 char *name; 1238 1239 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, 1240 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); 1241 1242 if (!new_valid_dev(rdev)) 1243 return -EINVAL; 1244 1245 name = __getname(); 1246 if (!name) 1247 return -ENOMEM; 1248 /* build extension */ 1249 if (S_ISBLK(mode)) 1250 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); 1251 else if (S_ISCHR(mode)) 1252 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); 1253 else if (S_ISFIFO(mode)) 1254 *name = 0; 1255 else { 1256 __putname(name); 1257 return -EINVAL; 1258 } 1259 1260 retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); 1261 __putname(name); 1262 1263 return retval; 1264 } 1265 1266 static struct inode_operations v9fs_dir_inode_operations_ext = { 1267 .create = v9fs_vfs_create, 1268 .lookup = v9fs_vfs_lookup, 1269 .symlink = v9fs_vfs_symlink, 1270 .link = v9fs_vfs_link, 1271 .unlink = v9fs_vfs_unlink, 1272 .mkdir = v9fs_vfs_mkdir, 1273 .rmdir = v9fs_vfs_rmdir, 1274 .mknod = v9fs_vfs_mknod, 1275 .rename = v9fs_vfs_rename, 1276 .readlink = v9fs_vfs_readlink, 1277 .getattr = v9fs_vfs_getattr, 1278 .setattr = v9fs_vfs_setattr, 1279 }; 1280 1281 static struct inode_operations v9fs_dir_inode_operations = { 1282 .create = v9fs_vfs_create, 1283 .lookup = v9fs_vfs_lookup, 1284 .unlink = v9fs_vfs_unlink, 1285 .mkdir = v9fs_vfs_mkdir, 1286 .rmdir = v9fs_vfs_rmdir, 1287 .mknod = v9fs_vfs_mknod, 1288 .rename = v9fs_vfs_rename, 1289 .getattr = v9fs_vfs_getattr, 1290 .setattr = v9fs_vfs_setattr, 1291 }; 1292 1293 static struct inode_operations v9fs_file_inode_operations = { 1294 .getattr = v9fs_vfs_getattr, 1295 .setattr = v9fs_vfs_setattr, 1296 }; 1297 1298 static struct inode_operations v9fs_symlink_inode_operations = { 1299 .readlink = v9fs_vfs_readlink, 1300 .follow_link = v9fs_vfs_follow_link, 1301 .put_link = v9fs_vfs_put_link, 1302 .getattr = v9fs_vfs_getattr, 1303 .setattr = v9fs_vfs_setattr, 1304 }; 1305