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