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/inet.h> 34 #include <linux/namei.h> 35 #include <linux/idr.h> 36 #include <linux/sched.h> 37 #include <net/9p/9p.h> 38 #include <net/9p/client.h> 39 40 #include "v9fs.h" 41 #include "v9fs_vfs.h" 42 #include "fid.h" 43 #include "cache.h" 44 45 static const struct inode_operations v9fs_dir_inode_operations; 46 static const struct inode_operations v9fs_dir_inode_operations_ext; 47 static const struct inode_operations v9fs_file_inode_operations; 48 static const struct inode_operations v9fs_symlink_inode_operations; 49 50 /** 51 * unixmode2p9mode - convert unix mode bits to plan 9 52 * @v9ses: v9fs session information 53 * @mode: mode to convert 54 * 55 */ 56 57 static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) 58 { 59 int res; 60 res = mode & 0777; 61 if (S_ISDIR(mode)) 62 res |= P9_DMDIR; 63 if (v9fs_extended(v9ses)) { 64 if (S_ISLNK(mode)) 65 res |= P9_DMSYMLINK; 66 if (v9ses->nodev == 0) { 67 if (S_ISSOCK(mode)) 68 res |= P9_DMSOCKET; 69 if (S_ISFIFO(mode)) 70 res |= P9_DMNAMEDPIPE; 71 if (S_ISBLK(mode)) 72 res |= P9_DMDEVICE; 73 if (S_ISCHR(mode)) 74 res |= P9_DMDEVICE; 75 } 76 77 if ((mode & S_ISUID) == S_ISUID) 78 res |= P9_DMSETUID; 79 if ((mode & S_ISGID) == S_ISGID) 80 res |= P9_DMSETGID; 81 if ((mode & S_ISVTX) == S_ISVTX) 82 res |= P9_DMSETVTX; 83 if ((mode & P9_DMLINK)) 84 res |= P9_DMLINK; 85 } 86 87 return res; 88 } 89 90 /** 91 * p9mode2unixmode- convert plan9 mode bits to unix mode bits 92 * @v9ses: v9fs session information 93 * @mode: mode to convert 94 * 95 */ 96 97 static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) 98 { 99 int res; 100 101 res = mode & 0777; 102 103 if ((mode & P9_DMDIR) == P9_DMDIR) 104 res |= S_IFDIR; 105 else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses))) 106 res |= S_IFLNK; 107 else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses)) 108 && (v9ses->nodev == 0)) 109 res |= S_IFSOCK; 110 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses)) 111 && (v9ses->nodev == 0)) 112 res |= S_IFIFO; 113 else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses)) 114 && (v9ses->nodev == 0)) 115 res |= S_IFBLK; 116 else 117 res |= S_IFREG; 118 119 if (v9fs_extended(v9ses)) { 120 if ((mode & P9_DMSETUID) == P9_DMSETUID) 121 res |= S_ISUID; 122 123 if ((mode & P9_DMSETGID) == P9_DMSETGID) 124 res |= S_ISGID; 125 126 if ((mode & P9_DMSETVTX) == P9_DMSETVTX) 127 res |= S_ISVTX; 128 } 129 130 return res; 131 } 132 133 /** 134 * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits 135 * @uflags: flags to convert 136 * @extended: if .u extensions are active 137 */ 138 139 int v9fs_uflags2omode(int uflags, int extended) 140 { 141 int ret; 142 143 ret = 0; 144 switch (uflags&3) { 145 default: 146 case O_RDONLY: 147 ret = P9_OREAD; 148 break; 149 150 case O_WRONLY: 151 ret = P9_OWRITE; 152 break; 153 154 case O_RDWR: 155 ret = P9_ORDWR; 156 break; 157 } 158 159 if (uflags & O_TRUNC) 160 ret |= P9_OTRUNC; 161 162 if (extended) { 163 if (uflags & O_EXCL) 164 ret |= P9_OEXCL; 165 166 if (uflags & O_APPEND) 167 ret |= P9_OAPPEND; 168 } 169 170 return ret; 171 } 172 173 /** 174 * v9fs_blank_wstat - helper function to setup a 9P stat structure 175 * @wstat: structure to initialize 176 * 177 */ 178 179 static void 180 v9fs_blank_wstat(struct p9_wstat *wstat) 181 { 182 wstat->type = ~0; 183 wstat->dev = ~0; 184 wstat->qid.type = ~0; 185 wstat->qid.version = ~0; 186 *((long long *)&wstat->qid.path) = ~0; 187 wstat->mode = ~0; 188 wstat->atime = ~0; 189 wstat->mtime = ~0; 190 wstat->length = ~0; 191 wstat->name = NULL; 192 wstat->uid = NULL; 193 wstat->gid = NULL; 194 wstat->muid = NULL; 195 wstat->n_uid = ~0; 196 wstat->n_gid = ~0; 197 wstat->n_muid = ~0; 198 wstat->extension = NULL; 199 } 200 201 #ifdef CONFIG_9P_FSCACHE 202 /** 203 * v9fs_alloc_inode - helper function to allocate an inode 204 * This callback is executed before setting up the inode so that we 205 * can associate a vcookie with each inode. 206 * 207 */ 208 209 struct inode *v9fs_alloc_inode(struct super_block *sb) 210 { 211 struct v9fs_cookie *vcookie; 212 vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache, 213 GFP_KERNEL); 214 if (!vcookie) 215 return NULL; 216 217 vcookie->fscache = NULL; 218 vcookie->qid = NULL; 219 spin_lock_init(&vcookie->lock); 220 return &vcookie->inode; 221 } 222 223 /** 224 * v9fs_destroy_inode - destroy an inode 225 * 226 */ 227 228 void v9fs_destroy_inode(struct inode *inode) 229 { 230 kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); 231 } 232 #endif 233 234 /** 235 * v9fs_get_inode - helper function to setup an inode 236 * @sb: superblock 237 * @mode: mode to setup inode with 238 * 239 */ 240 241 struct inode *v9fs_get_inode(struct super_block *sb, int mode) 242 { 243 int err; 244 struct inode *inode; 245 struct v9fs_session_info *v9ses = sb->s_fs_info; 246 247 P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); 248 249 inode = new_inode(sb); 250 if (!inode) { 251 P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); 252 return ERR_PTR(-ENOMEM); 253 } 254 255 inode->i_mode = mode; 256 inode->i_uid = current_fsuid(); 257 inode->i_gid = current_fsgid(); 258 inode->i_blocks = 0; 259 inode->i_rdev = 0; 260 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 261 inode->i_mapping->a_ops = &v9fs_addr_operations; 262 263 switch (mode & S_IFMT) { 264 case S_IFIFO: 265 case S_IFBLK: 266 case S_IFCHR: 267 case S_IFSOCK: 268 if (!v9fs_extended(v9ses)) { 269 P9_DPRINTK(P9_DEBUG_ERROR, 270 "special files without extended mode\n"); 271 err = -EINVAL; 272 goto error; 273 } 274 init_special_inode(inode, inode->i_mode, inode->i_rdev); 275 break; 276 case S_IFREG: 277 inode->i_op = &v9fs_file_inode_operations; 278 inode->i_fop = &v9fs_file_operations; 279 break; 280 case S_IFLNK: 281 if (!v9fs_extended(v9ses)) { 282 P9_DPRINTK(P9_DEBUG_ERROR, 283 "extended modes used w/o 9P2000.u\n"); 284 err = -EINVAL; 285 goto error; 286 } 287 inode->i_op = &v9fs_symlink_inode_operations; 288 break; 289 case S_IFDIR: 290 inc_nlink(inode); 291 if (v9fs_extended(v9ses)) 292 inode->i_op = &v9fs_dir_inode_operations_ext; 293 else 294 inode->i_op = &v9fs_dir_inode_operations; 295 inode->i_fop = &v9fs_dir_operations; 296 break; 297 default: 298 P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", 299 mode, mode & S_IFMT); 300 err = -EINVAL; 301 goto error; 302 } 303 304 return inode; 305 306 error: 307 iput(inode); 308 return ERR_PTR(err); 309 } 310 311 /* 312 static struct v9fs_fid* 313 v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) 314 { 315 int err; 316 int nfid; 317 struct v9fs_fid *ret; 318 struct v9fs_fcall *fcall; 319 320 nfid = v9fs_get_idpool(&v9ses->fidpool); 321 if (nfid < 0) { 322 eprintk(KERN_WARNING, "no free fids available\n"); 323 return ERR_PTR(-ENOSPC); 324 } 325 326 err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, 327 &fcall); 328 329 if (err < 0) { 330 if (fcall && fcall->id == RWALK) 331 goto clunk_fid; 332 333 PRINT_FCALL_ERROR("walk error", fcall); 334 v9fs_put_idpool(nfid, &v9ses->fidpool); 335 goto error; 336 } 337 338 kfree(fcall); 339 fcall = NULL; 340 ret = v9fs_fid_create(v9ses, nfid); 341 if (!ret) { 342 err = -ENOMEM; 343 goto clunk_fid; 344 } 345 346 err = v9fs_fid_insert(ret, dentry); 347 if (err < 0) { 348 v9fs_fid_destroy(ret); 349 goto clunk_fid; 350 } 351 352 return ret; 353 354 clunk_fid: 355 v9fs_t_clunk(v9ses, nfid); 356 357 error: 358 kfree(fcall); 359 return ERR_PTR(err); 360 } 361 */ 362 363 364 /** 365 * v9fs_clear_inode - release an inode 366 * @inode: inode to release 367 * 368 */ 369 void v9fs_clear_inode(struct inode *inode) 370 { 371 filemap_fdatawrite(inode->i_mapping); 372 373 #ifdef CONFIG_9P_FSCACHE 374 v9fs_cache_inode_put_cookie(inode); 375 #endif 376 } 377 378 /** 379 * v9fs_inode_from_fid - populate an inode by issuing a attribute request 380 * @v9ses: session information 381 * @fid: fid to issue attribute request for 382 * @sb: superblock on which to create inode 383 * 384 */ 385 386 static struct inode * 387 v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 388 struct super_block *sb) 389 { 390 int err, umode; 391 struct inode *ret; 392 struct p9_wstat *st; 393 394 ret = NULL; 395 st = p9_client_stat(fid); 396 if (IS_ERR(st)) 397 return ERR_CAST(st); 398 399 umode = p9mode2unixmode(v9ses, st->mode); 400 ret = v9fs_get_inode(sb, umode); 401 if (IS_ERR(ret)) { 402 err = PTR_ERR(ret); 403 goto error; 404 } 405 406 v9fs_stat2inode(st, ret, sb); 407 ret->i_ino = v9fs_qid2ino(&st->qid); 408 409 #ifdef CONFIG_9P_FSCACHE 410 v9fs_vcookie_set_qid(ret, &st->qid); 411 v9fs_cache_inode_get_cookie(ret); 412 #endif 413 p9stat_free(st); 414 kfree(st); 415 416 return ret; 417 418 error: 419 p9stat_free(st); 420 kfree(st); 421 return ERR_PTR(err); 422 } 423 424 /** 425 * v9fs_remove - helper function to remove files and directories 426 * @dir: directory inode that is being deleted 427 * @file: dentry that is being deleted 428 * @rmdir: removing a directory 429 * 430 */ 431 432 static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) 433 { 434 struct inode *file_inode; 435 struct v9fs_session_info *v9ses; 436 struct p9_fid *v9fid; 437 438 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, 439 rmdir); 440 441 file_inode = file->d_inode; 442 v9ses = v9fs_inode2v9ses(file_inode); 443 v9fid = v9fs_fid_clone(file); 444 if (IS_ERR(v9fid)) 445 return PTR_ERR(v9fid); 446 447 return p9_client_remove(v9fid); 448 } 449 450 static int 451 v9fs_open_created(struct inode *inode, struct file *file) 452 { 453 return 0; 454 } 455 456 457 /** 458 * v9fs_create - Create a file 459 * @v9ses: session information 460 * @dir: directory that dentry is being created in 461 * @dentry: dentry that is being created 462 * @extension: 9p2000.u extension string to support devices, etc. 463 * @perm: create permissions 464 * @mode: open mode 465 * 466 */ 467 static struct p9_fid * 468 v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, 469 struct dentry *dentry, char *extension, u32 perm, u8 mode) 470 { 471 int err; 472 char *name; 473 struct p9_fid *dfid, *ofid, *fid; 474 struct inode *inode; 475 476 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); 477 478 err = 0; 479 ofid = NULL; 480 fid = NULL; 481 name = (char *) dentry->d_name.name; 482 dfid = v9fs_fid_clone(dentry->d_parent); 483 if (IS_ERR(dfid)) { 484 err = PTR_ERR(dfid); 485 P9_DPRINTK(P9_DEBUG_VFS, "fid clone failed %d\n", err); 486 dfid = NULL; 487 goto error; 488 } 489 490 /* clone a fid to use for creation */ 491 ofid = p9_client_walk(dfid, 0, NULL, 1); 492 if (IS_ERR(ofid)) { 493 err = PTR_ERR(ofid); 494 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); 495 ofid = NULL; 496 goto error; 497 } 498 499 err = p9_client_fcreate(ofid, name, perm, mode, extension); 500 if (err < 0) { 501 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err); 502 goto error; 503 } 504 505 /* now walk from the parent so we can get unopened fid */ 506 fid = p9_client_walk(dfid, 1, &name, 0); 507 if (IS_ERR(fid)) { 508 err = PTR_ERR(fid); 509 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); 510 fid = NULL; 511 goto error; 512 } else 513 dfid = NULL; 514 515 /* instantiate inode and assign the unopened fid to the dentry */ 516 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); 517 if (IS_ERR(inode)) { 518 err = PTR_ERR(inode); 519 P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); 520 goto error; 521 } 522 523 if (v9ses->cache) 524 dentry->d_op = &v9fs_cached_dentry_operations; 525 else 526 dentry->d_op = &v9fs_dentry_operations; 527 528 d_instantiate(dentry, inode); 529 err = v9fs_fid_add(dentry, fid); 530 if (err < 0) 531 goto error; 532 533 return ofid; 534 535 error: 536 if (dfid) 537 p9_client_clunk(dfid); 538 539 if (ofid) 540 p9_client_clunk(ofid); 541 542 if (fid) 543 p9_client_clunk(fid); 544 545 return ERR_PTR(err); 546 } 547 548 /** 549 * v9fs_vfs_create - VFS hook to create files 550 * @dir: directory inode that is being created 551 * @dentry: dentry that is being deleted 552 * @mode: create permissions 553 * @nd: path information 554 * 555 */ 556 557 static int 558 v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, 559 struct nameidata *nd) 560 { 561 int err; 562 u32 perm; 563 int flags; 564 struct v9fs_session_info *v9ses; 565 struct p9_fid *fid; 566 struct file *filp; 567 568 err = 0; 569 fid = NULL; 570 v9ses = v9fs_inode2v9ses(dir); 571 perm = unixmode2p9mode(v9ses, mode); 572 if (nd && nd->flags & LOOKUP_OPEN) 573 flags = nd->intent.open.flags - 1; 574 else 575 flags = O_RDWR; 576 577 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, 578 v9fs_uflags2omode(flags, v9fs_extended(v9ses))); 579 if (IS_ERR(fid)) { 580 err = PTR_ERR(fid); 581 fid = NULL; 582 goto error; 583 } 584 585 /* if we are opening a file, assign the open fid to the file */ 586 if (nd && nd->flags & LOOKUP_OPEN) { 587 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); 588 if (IS_ERR(filp)) { 589 err = PTR_ERR(filp); 590 goto error; 591 } 592 593 filp->private_data = fid; 594 } else 595 p9_client_clunk(fid); 596 597 return 0; 598 599 error: 600 if (fid) 601 p9_client_clunk(fid); 602 603 return err; 604 } 605 606 /** 607 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory 608 * @dir: inode that is being unlinked 609 * @dentry: dentry that is being unlinked 610 * @mode: mode for new directory 611 * 612 */ 613 614 static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 615 { 616 int err; 617 u32 perm; 618 struct v9fs_session_info *v9ses; 619 struct p9_fid *fid; 620 621 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); 622 err = 0; 623 v9ses = v9fs_inode2v9ses(dir); 624 perm = unixmode2p9mode(v9ses, mode | S_IFDIR); 625 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD); 626 if (IS_ERR(fid)) { 627 err = PTR_ERR(fid); 628 fid = NULL; 629 } 630 631 if (fid) 632 p9_client_clunk(fid); 633 634 return err; 635 } 636 637 /** 638 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode 639 * @dir: inode that is being walked from 640 * @dentry: dentry that is being walked to? 641 * @nameidata: path data 642 * 643 */ 644 645 static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, 646 struct nameidata *nameidata) 647 { 648 struct super_block *sb; 649 struct v9fs_session_info *v9ses; 650 struct p9_fid *dfid, *fid; 651 struct inode *inode; 652 char *name; 653 int result = 0; 654 655 P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", 656 dir, dentry->d_name.name, dentry, nameidata); 657 658 sb = dir->i_sb; 659 v9ses = v9fs_inode2v9ses(dir); 660 dfid = v9fs_fid_lookup(dentry->d_parent); 661 if (IS_ERR(dfid)) 662 return ERR_CAST(dfid); 663 664 name = (char *) dentry->d_name.name; 665 fid = p9_client_walk(dfid, 1, &name, 1); 666 if (IS_ERR(fid)) { 667 result = PTR_ERR(fid); 668 if (result == -ENOENT) { 669 d_add(dentry, NULL); 670 return NULL; 671 } 672 673 return ERR_PTR(result); 674 } 675 676 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); 677 if (IS_ERR(inode)) { 678 result = PTR_ERR(inode); 679 inode = NULL; 680 goto error; 681 } 682 683 result = v9fs_fid_add(dentry, fid); 684 if (result < 0) 685 goto error; 686 687 if ((fid->qid.version) && (v9ses->cache)) 688 dentry->d_op = &v9fs_cached_dentry_operations; 689 else 690 dentry->d_op = &v9fs_dentry_operations; 691 692 d_add(dentry, inode); 693 return NULL; 694 695 error: 696 p9_client_clunk(fid); 697 698 return ERR_PTR(result); 699 } 700 701 /** 702 * v9fs_vfs_unlink - VFS unlink hook to delete an inode 703 * @i: inode that is being unlinked 704 * @d: dentry that is being unlinked 705 * 706 */ 707 708 static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) 709 { 710 return v9fs_remove(i, d, 0); 711 } 712 713 /** 714 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory 715 * @i: inode that is being unlinked 716 * @d: dentry that is being unlinked 717 * 718 */ 719 720 static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) 721 { 722 return v9fs_remove(i, d, 1); 723 } 724 725 /** 726 * v9fs_vfs_rename - VFS hook to rename an inode 727 * @old_dir: old dir inode 728 * @old_dentry: old dentry 729 * @new_dir: new dir inode 730 * @new_dentry: new dentry 731 * 732 */ 733 734 static int 735 v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, 736 struct inode *new_dir, struct dentry *new_dentry) 737 { 738 struct inode *old_inode; 739 struct v9fs_session_info *v9ses; 740 struct p9_fid *oldfid; 741 struct p9_fid *olddirfid; 742 struct p9_fid *newdirfid; 743 struct p9_wstat wstat; 744 int retval; 745 746 P9_DPRINTK(P9_DEBUG_VFS, "\n"); 747 retval = 0; 748 old_inode = old_dentry->d_inode; 749 v9ses = v9fs_inode2v9ses(old_inode); 750 oldfid = v9fs_fid_lookup(old_dentry); 751 if (IS_ERR(oldfid)) 752 return PTR_ERR(oldfid); 753 754 olddirfid = v9fs_fid_clone(old_dentry->d_parent); 755 if (IS_ERR(olddirfid)) { 756 retval = PTR_ERR(olddirfid); 757 goto done; 758 } 759 760 newdirfid = v9fs_fid_clone(new_dentry->d_parent); 761 if (IS_ERR(newdirfid)) { 762 retval = PTR_ERR(newdirfid); 763 goto clunk_olddir; 764 } 765 766 /* 9P can only handle file rename in the same directory */ 767 if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { 768 P9_DPRINTK(P9_DEBUG_ERROR, 769 "old dir and new dir are different\n"); 770 retval = -EXDEV; 771 goto clunk_newdir; 772 } 773 774 v9fs_blank_wstat(&wstat); 775 wstat.muid = v9ses->uname; 776 wstat.name = (char *) new_dentry->d_name.name; 777 retval = p9_client_wstat(oldfid, &wstat); 778 779 clunk_newdir: 780 p9_client_clunk(newdirfid); 781 782 clunk_olddir: 783 p9_client_clunk(olddirfid); 784 785 done: 786 return retval; 787 } 788 789 /** 790 * v9fs_vfs_getattr - retrieve file metadata 791 * @mnt: mount information 792 * @dentry: file to get attributes on 793 * @stat: metadata structure to populate 794 * 795 */ 796 797 static int 798 v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 799 struct kstat *stat) 800 { 801 int err; 802 struct v9fs_session_info *v9ses; 803 struct p9_fid *fid; 804 struct p9_wstat *st; 805 806 P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); 807 err = -EPERM; 808 v9ses = v9fs_inode2v9ses(dentry->d_inode); 809 if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) 810 return simple_getattr(mnt, dentry, stat); 811 812 fid = v9fs_fid_lookup(dentry); 813 if (IS_ERR(fid)) 814 return PTR_ERR(fid); 815 816 st = p9_client_stat(fid); 817 if (IS_ERR(st)) 818 return PTR_ERR(st); 819 820 v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); 821 generic_fillattr(dentry->d_inode, stat); 822 823 kfree(st); 824 return 0; 825 } 826 827 /** 828 * v9fs_vfs_setattr - set file metadata 829 * @dentry: file whose metadata to set 830 * @iattr: metadata assignment structure 831 * 832 */ 833 834 static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) 835 { 836 int retval; 837 struct v9fs_session_info *v9ses; 838 struct p9_fid *fid; 839 struct p9_wstat wstat; 840 841 P9_DPRINTK(P9_DEBUG_VFS, "\n"); 842 retval = -EPERM; 843 v9ses = v9fs_inode2v9ses(dentry->d_inode); 844 fid = v9fs_fid_lookup(dentry); 845 if(IS_ERR(fid)) 846 return PTR_ERR(fid); 847 848 v9fs_blank_wstat(&wstat); 849 if (iattr->ia_valid & ATTR_MODE) 850 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); 851 852 if (iattr->ia_valid & ATTR_MTIME) 853 wstat.mtime = iattr->ia_mtime.tv_sec; 854 855 if (iattr->ia_valid & ATTR_ATIME) 856 wstat.atime = iattr->ia_atime.tv_sec; 857 858 if (iattr->ia_valid & ATTR_SIZE) 859 wstat.length = iattr->ia_size; 860 861 if (v9fs_extended(v9ses)) { 862 if (iattr->ia_valid & ATTR_UID) 863 wstat.n_uid = iattr->ia_uid; 864 865 if (iattr->ia_valid & ATTR_GID) 866 wstat.n_gid = iattr->ia_gid; 867 } 868 869 retval = p9_client_wstat(fid, &wstat); 870 if (retval >= 0) 871 retval = inode_setattr(dentry->d_inode, iattr); 872 873 return retval; 874 } 875 876 /** 877 * v9fs_stat2inode - populate an inode structure with mistat info 878 * @stat: Plan 9 metadata (mistat) structure 879 * @inode: inode to populate 880 * @sb: superblock of filesystem 881 * 882 */ 883 884 void 885 v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, 886 struct super_block *sb) 887 { 888 char ext[32]; 889 struct v9fs_session_info *v9ses = sb->s_fs_info; 890 891 inode->i_nlink = 1; 892 893 inode->i_atime.tv_sec = stat->atime; 894 inode->i_mtime.tv_sec = stat->mtime; 895 inode->i_ctime.tv_sec = stat->mtime; 896 897 inode->i_uid = v9ses->dfltuid; 898 inode->i_gid = v9ses->dfltgid; 899 900 if (v9fs_extended(v9ses)) { 901 inode->i_uid = stat->n_uid; 902 inode->i_gid = stat->n_gid; 903 } 904 905 inode->i_mode = p9mode2unixmode(v9ses, stat->mode); 906 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { 907 char type = 0; 908 int major = -1; 909 int minor = -1; 910 911 strncpy(ext, stat->extension, sizeof(ext)); 912 sscanf(ext, "%c %u %u", &type, &major, &minor); 913 switch (type) { 914 case 'c': 915 inode->i_mode &= ~S_IFBLK; 916 inode->i_mode |= S_IFCHR; 917 break; 918 case 'b': 919 break; 920 default: 921 P9_DPRINTK(P9_DEBUG_ERROR, 922 "Unknown special type %c %s\n", type, 923 stat->extension); 924 }; 925 inode->i_rdev = MKDEV(major, minor); 926 init_special_inode(inode, inode->i_mode, inode->i_rdev); 927 } else 928 inode->i_rdev = 0; 929 930 i_size_write(inode, stat->length); 931 932 /* not real number of blocks, but 512 byte ones ... */ 933 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; 934 } 935 936 /** 937 * v9fs_qid2ino - convert qid into inode number 938 * @qid: qid to hash 939 * 940 * BUG: potential for inode number collisions? 941 */ 942 943 ino_t v9fs_qid2ino(struct p9_qid *qid) 944 { 945 u64 path = qid->path + 2; 946 ino_t i = 0; 947 948 if (sizeof(ino_t) == sizeof(path)) 949 memcpy(&i, &path, sizeof(ino_t)); 950 else 951 i = (ino_t) (path ^ (path >> 32)); 952 953 return i; 954 } 955 956 /** 957 * v9fs_readlink - read a symlink's location (internal version) 958 * @dentry: dentry for symlink 959 * @buffer: buffer to load symlink location into 960 * @buflen: length of buffer 961 * 962 */ 963 964 static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) 965 { 966 int retval; 967 968 struct v9fs_session_info *v9ses; 969 struct p9_fid *fid; 970 struct p9_wstat *st; 971 972 P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); 973 retval = -EPERM; 974 v9ses = v9fs_inode2v9ses(dentry->d_inode); 975 fid = v9fs_fid_lookup(dentry); 976 if (IS_ERR(fid)) 977 return PTR_ERR(fid); 978 979 if (!v9fs_extended(v9ses)) 980 return -EBADF; 981 982 st = p9_client_stat(fid); 983 if (IS_ERR(st)) 984 return PTR_ERR(st); 985 986 if (!(st->mode & P9_DMSYMLINK)) { 987 retval = -EINVAL; 988 goto done; 989 } 990 991 /* copy extension buffer into buffer */ 992 strncpy(buffer, st->extension, buflen); 993 994 P9_DPRINTK(P9_DEBUG_VFS, 995 "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); 996 997 retval = buflen; 998 999 done: 1000 kfree(st); 1001 return retval; 1002 } 1003 1004 /** 1005 * v9fs_vfs_readlink - read a symlink's location 1006 * @dentry: dentry for symlink 1007 * @buffer: buffer to load symlink location into 1008 * @buflen: length of buffer 1009 * 1010 */ 1011 1012 static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, 1013 int buflen) 1014 { 1015 int retval; 1016 int ret; 1017 char *link = __getname(); 1018 1019 if (unlikely(!link)) 1020 return -ENOMEM; 1021 1022 if (buflen > PATH_MAX) 1023 buflen = PATH_MAX; 1024 1025 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, 1026 dentry); 1027 1028 retval = v9fs_readlink(dentry, link, buflen); 1029 1030 if (retval > 0) { 1031 if ((ret = copy_to_user(buffer, link, retval)) != 0) { 1032 P9_DPRINTK(P9_DEBUG_ERROR, 1033 "problem copying to user: %d\n", ret); 1034 retval = ret; 1035 } 1036 } 1037 1038 __putname(link); 1039 return retval; 1040 } 1041 1042 /** 1043 * v9fs_vfs_follow_link - follow a symlink path 1044 * @dentry: dentry for symlink 1045 * @nd: nameidata 1046 * 1047 */ 1048 1049 static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) 1050 { 1051 int len = 0; 1052 char *link = __getname(); 1053 1054 P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name); 1055 1056 if (!link) 1057 link = ERR_PTR(-ENOMEM); 1058 else { 1059 len = v9fs_readlink(dentry, link, PATH_MAX); 1060 1061 if (len < 0) { 1062 __putname(link); 1063 link = ERR_PTR(len); 1064 } else 1065 link[len] = 0; 1066 } 1067 nd_set_link(nd, link); 1068 1069 return NULL; 1070 } 1071 1072 /** 1073 * v9fs_vfs_put_link - release a symlink path 1074 * @dentry: dentry for symlink 1075 * @nd: nameidata 1076 * @p: unused 1077 * 1078 */ 1079 1080 static void 1081 v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) 1082 { 1083 char *s = nd_get_link(nd); 1084 1085 P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, 1086 IS_ERR(s) ? "<error>" : s); 1087 if (!IS_ERR(s)) 1088 __putname(s); 1089 } 1090 1091 /** 1092 * v9fs_vfs_mkspecial - create a special file 1093 * @dir: inode to create special file in 1094 * @dentry: dentry to create 1095 * @mode: mode to create special file 1096 * @extension: 9p2000.u format extension string representing special file 1097 * 1098 */ 1099 1100 static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 1101 int mode, const char *extension) 1102 { 1103 u32 perm; 1104 struct v9fs_session_info *v9ses; 1105 struct p9_fid *fid; 1106 1107 v9ses = v9fs_inode2v9ses(dir); 1108 if (!v9fs_extended(v9ses)) { 1109 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); 1110 return -EPERM; 1111 } 1112 1113 perm = unixmode2p9mode(v9ses, mode); 1114 fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm, 1115 P9_OREAD); 1116 if (IS_ERR(fid)) 1117 return PTR_ERR(fid); 1118 1119 p9_client_clunk(fid); 1120 return 0; 1121 } 1122 1123 /** 1124 * v9fs_vfs_symlink - helper function to create symlinks 1125 * @dir: directory inode containing symlink 1126 * @dentry: dentry for symlink 1127 * @symname: symlink data 1128 * 1129 * See Also: 9P2000.u RFC for more information 1130 * 1131 */ 1132 1133 static int 1134 v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 1135 { 1136 P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, 1137 dentry->d_name.name, symname); 1138 1139 return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); 1140 } 1141 1142 /** 1143 * v9fs_vfs_link - create a hardlink 1144 * @old_dentry: dentry for file to link to 1145 * @dir: inode destination for new link 1146 * @dentry: dentry for link 1147 * 1148 */ 1149 1150 static int 1151 v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, 1152 struct dentry *dentry) 1153 { 1154 int retval; 1155 struct p9_fid *oldfid; 1156 char *name; 1157 1158 P9_DPRINTK(P9_DEBUG_VFS, 1159 " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 1160 old_dentry->d_name.name); 1161 1162 oldfid = v9fs_fid_clone(old_dentry); 1163 if (IS_ERR(oldfid)) 1164 return PTR_ERR(oldfid); 1165 1166 name = __getname(); 1167 if (unlikely(!name)) { 1168 retval = -ENOMEM; 1169 goto clunk_fid; 1170 } 1171 1172 sprintf(name, "%d\n", oldfid->fid); 1173 retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); 1174 __putname(name); 1175 1176 clunk_fid: 1177 p9_client_clunk(oldfid); 1178 return retval; 1179 } 1180 1181 /** 1182 * v9fs_vfs_mknod - create a special file 1183 * @dir: inode destination for new link 1184 * @dentry: dentry for file 1185 * @mode: mode for creation 1186 * @rdev: device associated with special file 1187 * 1188 */ 1189 1190 static int 1191 v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) 1192 { 1193 int retval; 1194 char *name; 1195 1196 P9_DPRINTK(P9_DEBUG_VFS, 1197 " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, 1198 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); 1199 1200 if (!new_valid_dev(rdev)) 1201 return -EINVAL; 1202 1203 name = __getname(); 1204 if (!name) 1205 return -ENOMEM; 1206 /* build extension */ 1207 if (S_ISBLK(mode)) 1208 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); 1209 else if (S_ISCHR(mode)) 1210 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); 1211 else if (S_ISFIFO(mode)) 1212 *name = 0; 1213 else { 1214 __putname(name); 1215 return -EINVAL; 1216 } 1217 1218 retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); 1219 __putname(name); 1220 1221 return retval; 1222 } 1223 1224 static const struct inode_operations v9fs_dir_inode_operations_ext = { 1225 .create = v9fs_vfs_create, 1226 .lookup = v9fs_vfs_lookup, 1227 .symlink = v9fs_vfs_symlink, 1228 .link = v9fs_vfs_link, 1229 .unlink = v9fs_vfs_unlink, 1230 .mkdir = v9fs_vfs_mkdir, 1231 .rmdir = v9fs_vfs_rmdir, 1232 .mknod = v9fs_vfs_mknod, 1233 .rename = v9fs_vfs_rename, 1234 .readlink = v9fs_vfs_readlink, 1235 .getattr = v9fs_vfs_getattr, 1236 .setattr = v9fs_vfs_setattr, 1237 }; 1238 1239 static const struct inode_operations v9fs_dir_inode_operations = { 1240 .create = v9fs_vfs_create, 1241 .lookup = v9fs_vfs_lookup, 1242 .unlink = v9fs_vfs_unlink, 1243 .mkdir = v9fs_vfs_mkdir, 1244 .rmdir = v9fs_vfs_rmdir, 1245 .mknod = v9fs_vfs_mknod, 1246 .rename = v9fs_vfs_rename, 1247 .getattr = v9fs_vfs_getattr, 1248 .setattr = v9fs_vfs_setattr, 1249 }; 1250 1251 static const struct inode_operations v9fs_file_inode_operations = { 1252 .getattr = v9fs_vfs_getattr, 1253 .setattr = v9fs_vfs_setattr, 1254 }; 1255 1256 static const struct inode_operations v9fs_symlink_inode_operations = { 1257 .readlink = v9fs_vfs_readlink, 1258 .follow_link = v9fs_vfs_follow_link, 1259 .put_link = v9fs_vfs_put_link, 1260 .getattr = v9fs_vfs_getattr, 1261 .setattr = v9fs_vfs_setattr, 1262 }; 1263