1 /* 2 * Copyright (c) 2017-2020 Juniper Networks, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27 /* This file contains VFS file ops for the 9P protocol. 28 * This makes the upper layer of the p9fs driver. These functions interact 29 * with the VFS layer and lower layer of p9fs driver which is 9Pnet. All 30 * the user file operations are handled here. 31 */ 32 #include <sys/cdefs.h> 33 #include <sys/systm.h> 34 #include <sys/bio.h> 35 #include <sys/buf.h> 36 #include <sys/dirent.h> 37 #include <sys/fcntl.h> 38 #include <sys/namei.h> 39 #include <sys/priv.h> 40 #include <sys/stat.h> 41 #include <sys/vnode.h> 42 43 #include <vm/vm.h> 44 #include <vm/vm_extern.h> 45 #include <vm/vm_object.h> 46 #include <vm/vnode_pager.h> 47 48 #include <fs/p9fs/p9_client.h> 49 #include <fs/p9fs/p9_debug.h> 50 #include <fs/p9fs/p9fs.h> 51 #include <fs/p9fs/p9fs_proto.h> 52 53 /* File permissions. */ 54 #define IEXEC 0000100 /* Executable. */ 55 #define IWRITE 0000200 /* Writeable. */ 56 #define IREAD 0000400 /* Readable. */ 57 #define ISVTX 0001000 /* Sticky bit. */ 58 #define ISGID 0002000 /* Set-gid. */ 59 #define ISUID 0004000 /* Set-uid. */ 60 61 static MALLOC_DEFINE(M_P9UIOV, "uio", "UIOV structures for strategy in p9fs"); 62 extern uma_zone_t p9fs_io_buffer_zone; 63 extern uma_zone_t p9fs_getattr_zone; 64 extern uma_zone_t p9fs_setattr_zone; 65 /* For the root vnode's vnops. */ 66 struct vop_vector p9fs_vnops; 67 68 static uint32_t p9fs_unix2p9_mode(uint32_t mode); 69 70 static void 71 p9fs_itimes(struct vnode *vp) 72 { 73 struct p9fs_node *node; 74 struct timespec ts; 75 struct p9fs_inode *inode; 76 77 node = P9FS_VTON(vp); 78 inode = &node->inode; 79 80 vfs_timestamp(&ts); 81 inode->i_mtime = ts.tv_sec; 82 } 83 84 /* 85 * Cleanup the p9fs node, the in memory representation of a vnode for p9fs. 86 * The cleanup includes invalidating all cache entries for the vnode, 87 * destroying the vobject, removing vnode from hashlist, removing p9fs node 88 * from the list of session p9fs nodes, and disposing of the p9fs node. 89 * Basically it is doing a reverse of what a create/vget does. 90 */ 91 void 92 p9fs_cleanup(struct p9fs_node *np) 93 { 94 struct vnode *vp; 95 struct p9fs_session *vses; 96 97 if (np == NULL) 98 return; 99 100 vp = P9FS_NTOV(np); 101 vses = np->p9fs_ses; 102 103 /* Remove the vnode from hash list if vnode is not already deleted */ 104 if ((np->flags & P9FS_NODE_DELETED) == 0) 105 vfs_hash_remove(vp); 106 107 P9FS_LOCK(vses); 108 if ((np->flags & P9FS_NODE_IN_SESSION) != 0) { 109 np->flags &= ~P9FS_NODE_IN_SESSION; 110 STAILQ_REMOVE(&vses->virt_node_list, np, p9fs_node, p9fs_node_next); 111 } else { 112 P9FS_UNLOCK(vses); 113 return; 114 } 115 P9FS_UNLOCK(vses); 116 117 /* Invalidate all entries to a particular vnode. */ 118 cache_purge(vp); 119 120 /* Destroy the vm object and flush associated pages. */ 121 vnode_destroy_vobject(vp); 122 123 /* Remove the vnode from hash list if vnode is not already deleted */ 124 if ((np->flags & P9FS_NODE_DELETED) == 0) 125 vfs_hash_remove(vp); 126 127 /* Invalidate all entries to a particular vnode. */ 128 cache_purge(vp); 129 130 /* Destroy the vm object and flush associated pages. */ 131 vnode_destroy_vobject(vp); 132 133 /* Remove all the FID */ 134 p9fs_fid_remove_all(np, FALSE); 135 136 /* Dispose all node knowledge.*/ 137 p9fs_destroy_node(&np); 138 } 139 140 /* 141 * Reclaim VOP is defined to be called for every vnode. This starts off 142 * the cleanup by clunking(remove the fid on the server) and calls 143 * p9fs_cleanup to free all the resources allocated for p9fs node. 144 */ 145 static int 146 p9fs_reclaim(struct vop_reclaim_args *ap) 147 { 148 struct vnode *vp; 149 struct p9fs_node *np; 150 151 vp = ap->a_vp; 152 np = P9FS_VTON(vp); 153 154 P9_DEBUG(VOPS, "%s: vp:%p node:%p\n", __func__, vp, np); 155 p9fs_cleanup(np); 156 157 return (0); 158 } 159 160 /* 161 * recycle vnodes which are no longer referenced i.e, their usecount is zero 162 */ 163 static int 164 p9fs_inactive(struct vop_inactive_args *ap) 165 { 166 struct vnode *vp; 167 struct p9fs_node *np; 168 169 vp = ap->a_vp; 170 np = P9FS_VTON(vp); 171 172 P9_DEBUG(VOPS, "%s: vp:%p node:%p file:%s\n", __func__, vp, np, np->inode.i_name); 173 if (np->flags & P9FS_NODE_DELETED) 174 vrecycle(vp); 175 176 return (0); 177 } 178 179 struct p9fs_lookup_alloc_arg { 180 struct componentname *cnp; 181 struct p9fs_node *dnp; 182 struct p9_fid *newfid; 183 }; 184 185 /* Callback for vn_get_ino */ 186 static int 187 p9fs_lookup_alloc(struct mount *mp, void *arg, int lkflags, struct vnode **vpp) 188 { 189 struct p9fs_lookup_alloc_arg *p9aa = arg; 190 191 return (p9fs_vget_common(mp, NULL, p9aa->cnp->cn_lkflags, p9aa->dnp, 192 p9aa->newfid, vpp, p9aa->cnp->cn_nameptr)); 193 } 194 195 /* 196 * p9fs_lookup is called for every component name that is being searched for. 197 * 198 * I. If component is found on the server, we look for the in-memory 199 * repesentation(vnode) of this component in namecache. 200 * A. If the node is found in the namecache, we check is the vnode is still 201 * valid. 202 * 1. If it is still valid, return vnode. 203 * 2. If it is not valid, we remove this vnode from the name cache and 204 * create a new vnode for the component and return that vnode. 205 * B. If the vnode is not found in the namecache, we look for it in the 206 * hash list. 207 * 1. If the vnode is in the hash list, we check if the vnode is still 208 * valid. 209 * a. If it is still valid, we add that vnode to the namecache for 210 * future lookups and return the vnode. 211 * b. If it is not valid, create a new vnode and p9fs node, 212 * initialize them and return the vnode. 213 * 2. If the vnode is not found in the hash list, we create a new vnode 214 * and p9fs node, initialize them and return the vnode. 215 * II. If the component is not found on the server, an error code is returned. 216 * A. For the creation case, we return EJUSTRETURN so VFS can handle it. 217 * B. For all other cases, ENOENT is returned. 218 */ 219 static int 220 p9fs_lookup(struct vop_lookup_args *ap) 221 { 222 struct vnode *dvp; 223 struct vnode **vpp, *vp; 224 struct componentname *cnp; 225 struct p9fs_node *dnp; /*dir p9_node */ 226 struct p9fs_node *np; 227 struct p9fs_session *vses; 228 struct mount *mp; /* Get the mount point */ 229 struct p9_fid *dvfid, *newfid; 230 int error; 231 struct vattr vattr; 232 int flags; 233 char tmpchr; 234 235 dvp = ap->a_dvp; 236 vpp = ap->a_vpp; 237 cnp = ap->a_cnp; 238 dnp = P9FS_VTON(dvp); 239 error = 0; 240 flags = cnp->cn_flags; 241 *vpp = NULLVP; 242 243 if (dnp == NULL) 244 return (ENOENT); 245 246 vses = dnp->p9fs_ses; 247 mp = vses->p9fs_mount; 248 249 /* Do the cache part ourselves */ 250 if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && 251 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 252 return (EROFS); 253 254 if (dvp->v_type != VDIR) 255 return (ENOTDIR); 256 257 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, curthread); 258 if (error) 259 return (error); 260 261 /* Do the directory walk on host to check if file exist */ 262 dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 263 if (error) 264 return (error); 265 266 /* 267 * Save the character present at namelen in nameptr string and 268 * null terminate the character to get the search name for p9_dir_walk 269 * This is done to handle when lookup is for "a" and component 270 * name contains a/b/c 271 */ 272 tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 273 cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 274 275 /* 276 * If the client_walk fails, it means the file looking for doesnt exist. 277 * Create the file is the flags are set or just return the error 278 */ 279 newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error); 280 281 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 282 283 if (error != 0 || newfid == NULL) { 284 /* Clunk the newfid if it is not NULL */ 285 if (newfid != NULL) 286 p9_client_clunk(newfid); 287 288 if (error != ENOENT) 289 return (error); 290 291 /* The requested file was not found. */ 292 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && 293 (flags & ISLASTCN)) { 294 295 if (mp->mnt_flag & MNT_RDONLY) 296 return (EROFS); 297 298 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 299 curthread); 300 if (!error) { 301 return (EJUSTRETURN); 302 } 303 } 304 return (error); 305 } 306 307 /* Look for the entry in the component cache*/ 308 error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 309 if (error > 0 && error != ENOENT) { 310 P9_DEBUG(VOPS, "%s: Cache lookup error %d \n", __func__, error); 311 goto out; 312 } 313 314 if (error == -1) { 315 vp = *vpp; 316 /* Check if the entry in cache is stale or not */ 317 if ((p9fs_node_cmp(vp, &newfid->qid) == 0) && 318 ((error = VOP_GETATTR(vp, &vattr, cnp->cn_cred)) == 0)) { 319 goto out; 320 } 321 /* 322 * This case, we have an error coming from getattr, 323 * act accordingly. 324 */ 325 cache_purge(vp); 326 if (dvp != vp) 327 vput(vp); 328 else 329 vrele(vp); 330 331 *vpp = NULLVP; 332 } else if (error == ENOENT) { 333 if (VN_IS_DOOMED(dvp)) 334 goto out; 335 if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0) { 336 error = ENOENT; 337 goto out; 338 } 339 cache_purge_negative(dvp); 340 } 341 /* Reset values */ 342 error = 0; 343 vp = NULLVP; 344 345 tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 346 cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 347 348 /* 349 * Looks like we have found an entry. Now take care of all other cases. 350 */ 351 if (flags & ISDOTDOT) { 352 struct p9fs_lookup_alloc_arg p9aa; 353 p9aa.cnp = cnp; 354 p9aa.dnp = dnp; 355 p9aa.newfid = newfid; 356 error = vn_vget_ino_gen(dvp, p9fs_lookup_alloc, &p9aa, 0, &vp); 357 if (error) 358 goto out; 359 *vpp = vp; 360 } else { 361 /* 362 * client_walk is equivalent to searching a component name in a 363 * directory(fid) here. If new fid is returned, we have found an 364 * entry for this component name so, go and create the rest of 365 * the vnode infra(vget_common) for the returned newfid. 366 */ 367 if ((cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 368 && (flags & ISLASTCN)) { 369 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 370 curthread); 371 if (error) 372 goto out; 373 374 error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 375 dnp, newfid, &vp, cnp->cn_nameptr); 376 if (error) 377 goto out; 378 379 *vpp = vp; 380 np = P9FS_VTON(vp); 381 if ((dnp->inode.i_mode & ISVTX) && 382 cnp->cn_cred->cr_uid != 0 && 383 cnp->cn_cred->cr_uid != dnp->inode.n_uid && 384 cnp->cn_cred->cr_uid != np->inode.n_uid) { 385 vput(*vpp); 386 *vpp = NULL; 387 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 388 return (EPERM); 389 } 390 } else { 391 error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 392 dnp, newfid, &vp, cnp->cn_nameptr); 393 if (error) 394 goto out; 395 *vpp = vp; 396 } 397 } 398 399 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 400 401 /* Store the result the cache if MAKEENTRY is specified in flags */ 402 if ((cnp->cn_flags & MAKEENTRY) != 0) 403 cache_enter(dvp, *vpp, cnp); 404 return (error); 405 out: 406 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 407 p9_client_clunk(newfid); 408 return (error); 409 } 410 411 /* 412 * Common creation function for file/directory with respective flags. We first 413 * open the parent directory in order to create the file under it. For this, 414 * as 9P protocol suggests, we need to call client_walk to create the open fid. 415 * Once we have the open fid, the file_create function creates the direntry with 416 * the name and perm specified under the parent dir. If this succeeds (an entry 417 * is created for the new file on the server), we create our metadata for this 418 * file (vnode, p9fs node calling vget). Once we are done, we clunk the open 419 * fid of the parent directory. 420 */ 421 static int 422 create_common(struct p9fs_node *dnp, struct componentname *cnp, 423 char *extension, uint32_t perm, uint8_t mode, struct vnode **vpp) 424 { 425 char tmpchr; 426 struct p9_fid *dvfid, *ofid, *newfid; 427 struct p9fs_session *vses; 428 struct mount *mp; 429 int error; 430 431 P9_DEBUG(VOPS, "%s: name %s\n", __func__, cnp->cn_nameptr); 432 433 vses = dnp->p9fs_ses; 434 mp = vses->p9fs_mount; 435 newfid = NULL; 436 error = 0; 437 438 dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 439 if (error != 0) 440 return (error); 441 442 /* Clone the directory fid to create the new file */ 443 ofid = p9_client_walk(dvfid, 0, NULL, 1, &error); 444 if (error != 0) 445 return (error); 446 447 /* 448 * Save the character present at namelen in nameptr string and 449 * null terminate the character to get the search name for p9_dir_walk 450 */ 451 tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 452 cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 453 454 error = p9_client_file_create(ofid, cnp->cn_nameptr, perm, mode, 455 extension); 456 if (error != 0) { 457 P9_DEBUG(ERROR, "%s: p9_client_fcreate failed %d\n", __func__, error); 458 goto out; 459 } 460 461 /* If its not hardlink only then do the walk, else we are done. */ 462 if (!(perm & P9PROTO_DMLINK)) { 463 /* 464 * Do the lookup part and add the vnode, p9fs node. Note that vpp 465 * is filled in here. 466 */ 467 newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error); 468 if (newfid != NULL) { 469 error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 470 dnp, newfid, vpp, cnp->cn_nameptr); 471 if (error != 0) 472 goto out; 473 } else { 474 /* Not found return NOENTRY.*/ 475 goto out; 476 } 477 478 if ((cnp->cn_flags & MAKEENTRY) != 0) 479 cache_enter(P9FS_NTOV(dnp), *vpp, cnp); 480 } 481 P9_DEBUG(VOPS, "%s: created file under vp %p node %p fid %ju\n", 482 __func__, *vpp, dnp, (uintmax_t)dvfid->fid); 483 /* Clunk the open ofid. */ 484 if (ofid != NULL) 485 (void)p9_client_clunk(ofid); 486 487 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 488 return (0); 489 out: 490 if (ofid != NULL) 491 (void)p9_client_clunk(ofid); 492 493 if (newfid != NULL) 494 (void)p9_client_clunk(newfid); 495 496 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 497 return (error); 498 } 499 500 /* 501 * This is the main file creation VOP. Make the permissions of the new 502 * file and call the create_common common code to complete the create. 503 */ 504 static int 505 p9fs_create(struct vop_create_args *ap) 506 { 507 struct vnode *dvp; 508 struct vnode **vpp; 509 struct componentname *cnp; 510 uint32_t mode; 511 struct p9fs_node *dnp; 512 struct p9fs_inode *dinode; 513 uint32_t perm; 514 int ret; 515 516 dvp = ap->a_dvp; 517 vpp = ap->a_vpp; 518 cnp = ap->a_cnp; 519 dnp = P9FS_VTON(dvp); 520 dinode = &dnp->inode; 521 mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 522 perm = p9fs_unix2p9_mode(mode); 523 524 P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 525 526 ret = create_common(dnp, cnp, NULL, perm, P9PROTO_ORDWR, vpp); 527 if (ret == 0) { 528 P9FS_INCR_LINKS(dinode); 529 } 530 531 return (ret); 532 } 533 534 /* 535 * p9fs_mkdir is the main directory creation vop. Make the permissions of the new dir 536 * and call the create_common common code to complete the create. 537 */ 538 static int 539 p9fs_mkdir(struct vop_mkdir_args *ap) 540 { 541 struct vnode *dvp; 542 struct vnode **vpp; 543 struct componentname *cnp; 544 uint32_t mode; 545 struct p9fs_node *dnp; 546 struct p9fs_inode *dinode; 547 uint32_t perm; 548 int ret; 549 550 dvp = ap->a_dvp; 551 vpp = ap->a_vpp; 552 cnp = ap->a_cnp; 553 dnp = P9FS_VTON(dvp); 554 dinode = &dnp->inode; 555 mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 556 perm = p9fs_unix2p9_mode(mode | S_IFDIR); 557 558 P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 559 560 ret = create_common(dnp, cnp, NULL, perm, P9PROTO_ORDWR, vpp); 561 if (ret == 0) 562 P9FS_INCR_LINKS(dinode); 563 564 return (ret); 565 } 566 567 /* 568 * p9fs_mknod is the main node creation vop. Make the permissions of the new node 569 * and call the create_common common code to complete the create. 570 */ 571 static int 572 p9fs_mknod(struct vop_mknod_args *ap) 573 { 574 struct vnode *dvp; 575 struct vnode **vpp; 576 struct componentname *cnp; 577 uint32_t mode; 578 struct p9fs_node *dnp; 579 struct p9fs_inode *dinode; 580 uint32_t perm; 581 int ret; 582 583 dvp = ap->a_dvp; 584 vpp = ap->a_vpp; 585 cnp = ap->a_cnp; 586 dnp = P9FS_VTON(dvp); 587 dinode = &dnp->inode; 588 mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 589 perm = p9fs_unix2p9_mode(mode); 590 591 P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 592 593 ret = create_common(dnp, cnp, NULL, perm, P9PROTO_OREAD, vpp); 594 if (ret == 0) { 595 P9FS_INCR_LINKS(dinode); 596 } 597 598 return (ret); 599 } 600 601 /* Convert open mode permissions to P9 */ 602 static int 603 p9fs_uflags_mode(int uflags, int extended) 604 { 605 uint32_t ret; 606 607 /* Convert first to O flags.*/ 608 uflags = OFLAGS(uflags); 609 610 switch (uflags & 3) { 611 612 case O_RDONLY: 613 ret = P9PROTO_OREAD; 614 break; 615 616 case O_WRONLY: 617 ret = P9PROTO_OWRITE; 618 break; 619 620 case O_RDWR: 621 ret = P9PROTO_ORDWR; 622 break; 623 } 624 625 if (extended) { 626 if (uflags & O_EXCL) 627 ret |= P9PROTO_OEXCL; 628 629 if (uflags & O_APPEND) 630 ret |= P9PROTO_OAPPEND; 631 } 632 633 return (ret); 634 } 635 636 /* 637 * This is the main open VOP for every file open. If the file is already 638 * open, then increment and return. If there is no open fid for this file, 639 * there needs to be a client_walk which creates a new open fid for this file. 640 * Once we have a open fid, call the open on this file with the mode creating 641 * the vobject. 642 */ 643 static int 644 p9fs_open(struct vop_open_args *ap) 645 { 646 int error; 647 struct vnode *vp; 648 struct p9fs_node *np; 649 struct p9fs_session *vses; 650 struct p9_fid *vofid, *vfid; 651 size_t filesize; 652 uint32_t mode; 653 654 error = 0; 655 vp = ap->a_vp; 656 np = P9FS_VTON(vp); 657 vses = np->p9fs_ses; 658 659 P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp); 660 661 if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) 662 return (EOPNOTSUPP); 663 664 error = p9fs_reload_stats_dotl(vp, ap->a_cred); 665 if (error != 0) 666 return (error); 667 668 ASSERT_VOP_LOCKED(vp, __func__); 669 /* 670 * Invalidate the pages of the vm_object cache if the file is modified 671 * based on the flag set in reload stats 672 */ 673 if (vp->v_type == VREG && (np->flags & P9FS_NODE_MODIFIED) != 0) { 674 error = vinvalbuf(vp, 0, 0, 0); 675 if (error != 0) 676 return (error); 677 np->flags &= ~P9FS_NODE_MODIFIED; 678 } 679 680 vfid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VFID, -1, &error); 681 if (error != 0) 682 return (error); 683 684 /* 685 * Translate kernel fflags to 9p mode 686 */ 687 mode = p9fs_uflags_mode(ap->a_mode, 1); 688 689 /* 690 * Search the fid in vofid_list for current user. If found increase the open 691 * count and return. If not found clone a new fid and open the file using 692 * that cloned fid. 693 */ 694 vofid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VOFID, mode, &error); 695 if (vofid != NULL) { 696 vofid->v_opens++; 697 return (0); 698 } else { 699 /*vofid is the open fid for this file.*/ 700 vofid = p9_client_walk(vfid, 0, NULL, 1, &error); 701 if (error != 0) 702 return (error); 703 } 704 705 error = p9_client_open(vofid, mode); 706 if (error != 0) 707 p9_client_clunk(vofid); 708 else { 709 vofid->v_opens = 1; 710 filesize = np->inode.i_size; 711 vnode_create_vobject(vp, filesize, ap->a_td); 712 p9fs_fid_add(np, vofid, VOFID); 713 } 714 715 return (error); 716 } 717 718 /* 719 * Close the open references. Just reduce the open count on vofid and return. 720 * Let clunking of VOFID happen in p9fs_reclaim. 721 */ 722 static int 723 p9fs_close(struct vop_close_args *ap) 724 { 725 struct vnode *vp; 726 struct p9fs_node *np; 727 struct p9fs_session *vses; 728 struct p9_fid *vofid; 729 int error; 730 731 vp = ap->a_vp; 732 np = P9FS_VTON(vp); 733 734 if (np == NULL) 735 return (0); 736 737 vses = np->p9fs_ses; 738 error = 0; 739 740 P9_DEBUG(VOPS, "%s: file_name %s\n", __func__, np->inode.i_name); 741 742 /* 743 * Translate kernel fflags to 9p mode 744 */ 745 vofid = p9fs_get_fid(vses->clnt, np, ap->a_cred, VOFID, 746 p9fs_uflags_mode(ap->a_fflag, 1), &error); 747 if (vofid == NULL) 748 return (0); 749 750 vofid->v_opens--; 751 752 return (0); 753 } 754 755 /* Helper routine for checking if fileops are possible on this file */ 756 static int 757 p9fs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) 758 { 759 760 /* Check if we are allowed to write */ 761 switch (vap->va_type) { 762 case VDIR: 763 case VLNK: 764 case VREG: 765 /* 766 * Normal nodes: check if we're on a read-only mounted 767 * file system and bail out if we're trying to write. 768 */ 769 if ((mode & VMODIFY_PERMS) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 770 return (EROFS); 771 break; 772 case VBLK: 773 case VCHR: 774 case VSOCK: 775 case VFIFO: 776 /* 777 * Special nodes: even on read-only mounted file systems 778 * these are allowed to be written to if permissions allow. 779 */ 780 break; 781 default: 782 /* No idea what this is */ 783 return (EINVAL); 784 } 785 786 return (0); 787 } 788 789 /* Check the access permissions of the file. */ 790 static int 791 p9fs_access(struct vop_access_args *ap) 792 { 793 struct vnode *vp; 794 accmode_t accmode; 795 struct ucred *cred; 796 struct vattr vap; 797 int error; 798 799 vp = ap->a_vp; 800 accmode = ap->a_accmode; 801 cred = ap->a_cred; 802 803 P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp); 804 805 /* make sure getattr is working correctly and is defined.*/ 806 error = VOP_GETATTR(vp, &vap, cred); 807 if (error != 0) 808 return (error); 809 810 error = p9fs_check_possible(vp, &vap, accmode); 811 if (error != 0) 812 return (error); 813 814 /* Call the Generic Access check in VOPS*/ 815 error = vaccess(vp->v_type, vap.va_mode, vap.va_uid, vap.va_gid, accmode, 816 cred); 817 818 819 return (error); 820 } 821 822 /* 823 * Reload the file stats from the server and update the inode structure present 824 * in p9fs node. 825 */ 826 int 827 p9fs_reload_stats_dotl(struct vnode *vp, struct ucred *cred) 828 { 829 struct p9_stat_dotl *stat; 830 int error; 831 struct p9fs_node *node; 832 struct p9fs_session *vses; 833 struct p9_fid *vfid; 834 835 error = 0; 836 node = P9FS_VTON(vp); 837 vses = node->p9fs_ses; 838 839 vfid = p9fs_get_fid(vses->clnt, node, cred, VOFID, P9PROTO_OREAD, &error); 840 if (vfid == NULL) { 841 vfid = p9fs_get_fid(vses->clnt, node, cred, VFID, -1, &error); 842 if (error) 843 return (error); 844 } 845 846 stat = uma_zalloc(p9fs_getattr_zone, M_WAITOK | M_ZERO); 847 848 error = p9_client_getattr(vfid, stat, P9PROTO_STATS_ALL); 849 if (error != 0) { 850 P9_DEBUG(ERROR, "%s: p9_client_getattr failed: %d\n", __func__, error); 851 goto out; 852 } 853 854 /* Init the vnode with the disk info */ 855 p9fs_stat_vnode_dotl(stat, vp); 856 out: 857 if (stat != NULL) { 858 uma_zfree(p9fs_getattr_zone, stat); 859 } 860 861 return (error); 862 } 863 864 /* 865 * Read the current inode values into the vap attr. We reload the stats from 866 * the server. 867 */ 868 static int 869 p9fs_getattr_dotl(struct vop_getattr_args *ap) 870 { 871 struct vnode *vp; 872 struct vattr *vap; 873 struct p9fs_node *node; 874 struct p9fs_inode *inode; 875 int error; 876 877 vp = ap->a_vp; 878 vap = ap->a_vap; 879 node = P9FS_VTON(vp); 880 881 if (node == NULL) 882 return (ENOENT); 883 884 inode = &node->inode; 885 886 P9_DEBUG(VOPS, "%s: %u %u\n", __func__, inode->i_mode, IFTOVT(inode->i_mode)); 887 888 /* Reload our stats once to get the right values.*/ 889 error = p9fs_reload_stats_dotl(vp, ap->a_cred); 890 if (error != 0) { 891 P9_DEBUG(ERROR, "%s: failed: %d\n", __func__, error); 892 return (error); 893 } 894 895 /* Basic info */ 896 VATTR_NULL(vap); 897 898 vap->va_atime.tv_sec = inode->i_atime; 899 vap->va_mtime.tv_sec = inode->i_mtime; 900 vap->va_ctime.tv_sec = inode->i_ctime; 901 vap->va_atime.tv_nsec = inode->i_atime_nsec; 902 vap->va_mtime.tv_nsec = inode->i_mtime_nsec; 903 vap->va_ctime.tv_nsec = inode->i_ctime_nsec; 904 vap->va_type = IFTOVT(inode->i_mode); 905 vap->va_mode = inode->i_mode; 906 vap->va_uid = inode->n_uid; 907 vap->va_gid = inode->n_gid; 908 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 909 vap->va_size = inode->i_size; 910 vap->va_nlink = inode->i_links_count; 911 vap->va_blocksize = inode->blksize; 912 vap->va_fileid = inode->i_qid_path; 913 vap->va_flags = inode->i_flags; 914 vap->va_gen = inode->gen; 915 vap->va_filerev = inode->data_version; 916 vap->va_vaflags = 0; 917 vap->va_bytes = inode->blocks * P9PROTO_TGETATTR_BLK; 918 919 return (0); 920 } 921 922 /* Convert a standard FreeBSD permission to P9. */ 923 static uint32_t 924 p9fs_unix2p9_mode(uint32_t mode) 925 { 926 uint32_t res; 927 928 res = mode & 0777; 929 if (S_ISDIR(mode)) 930 res |= P9PROTO_DMDIR; 931 if (S_ISSOCK(mode)) 932 res |= P9PROTO_DMSOCKET; 933 if (S_ISLNK(mode)) 934 res |= P9PROTO_DMSYMLINK; 935 if (S_ISFIFO(mode)) 936 res |= P9PROTO_DMNAMEDPIPE; 937 if ((mode & S_ISUID) == S_ISUID) 938 res |= P9PROTO_DMSETUID; 939 if ((mode & S_ISGID) == S_ISGID) 940 res |= P9PROTO_DMSETGID; 941 if ((mode & S_ISVTX) == S_ISVTX) 942 res |= P9PROTO_DMSETVTX; 943 944 return (res); 945 } 946 947 /* Update inode with the stats read from server.(9P2000.L version) */ 948 int 949 p9fs_stat_vnode_dotl(struct p9_stat_dotl *stat, struct vnode *vp) 950 { 951 struct p9fs_node *np; 952 struct p9fs_inode *inode; 953 954 np = P9FS_VTON(vp); 955 inode = &np->inode; 956 957 ASSERT_VOP_LOCKED(vp, __func__); 958 /* Update the pager size if file size changes on host */ 959 if (inode->i_size != stat->st_size) { 960 inode->i_size = stat->st_size; 961 if (vp->v_type == VREG) 962 vnode_pager_setsize(vp, inode->i_size); 963 } 964 965 inode->i_mtime = stat->st_mtime_sec; 966 inode->i_atime = stat->st_atime_sec; 967 inode->i_ctime = stat->st_ctime_sec; 968 inode->i_mtime_nsec = stat->st_mtime_nsec; 969 inode->i_atime_nsec = stat->st_atime_nsec; 970 inode->i_ctime_nsec = stat->st_ctime_nsec; 971 inode->n_uid = stat->st_uid; 972 inode->n_gid = stat->st_gid; 973 inode->i_mode = stat->st_mode; 974 vp->v_type = IFTOVT(inode->i_mode); 975 inode->i_links_count = stat->st_nlink; 976 inode->blksize = stat->st_blksize; 977 inode->blocks = stat->st_blocks; 978 inode->gen = stat->st_gen; 979 inode->data_version = stat->st_data_version; 980 981 ASSERT_VOP_LOCKED(vp, __func__); 982 /* Setting a flag if file changes based on qid version */ 983 if (np->vqid.qid_version != stat->qid.version) 984 np->flags |= P9FS_NODE_MODIFIED; 985 memcpy(&np->vqid, &stat->qid, sizeof(stat->qid)); 986 987 return (0); 988 } 989 990 /* 991 * Write the current in memory inode stats into persistent stats structure 992 * to write to the server(for linux version). 993 */ 994 static int 995 p9fs_inode_to_iattr(struct p9fs_inode *inode, struct p9_iattr_dotl *p9attr) 996 { 997 p9attr->size = inode->i_size; 998 p9attr->mode = inode->i_mode; 999 p9attr->uid = inode->n_uid; 1000 p9attr->gid = inode->n_gid; 1001 p9attr->atime_sec = inode->i_atime; 1002 p9attr->atime_nsec = inode->i_atime_nsec; 1003 p9attr->mtime_sec = inode->i_mtime; 1004 p9attr->mtime_nsec = inode->i_mtime_nsec; 1005 1006 return (0); 1007 } 1008 1009 /* 1010 * Modify the ownership of a file whenever the chown is called on the 1011 * file. 1012 */ 1013 static int 1014 p9fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, 1015 struct thread *td) 1016 { 1017 struct p9fs_node *np; 1018 struct p9fs_inode *inode; 1019 uid_t ouid; 1020 gid_t ogid; 1021 int error; 1022 1023 np = P9FS_VTON(vp); 1024 inode = &np->inode; 1025 1026 if (uid == (uid_t)VNOVAL) 1027 uid = inode->n_uid; 1028 if (gid == (gid_t)VNOVAL) 1029 gid = inode->n_gid; 1030 /* 1031 * To modify the ownership of a file, must possess VADMIN for that 1032 * file. 1033 */ 1034 if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) 1035 return (error); 1036 /* 1037 * To change the owner of a file, or change the group of a file to a 1038 * group of which we are not a member, the caller must have 1039 * privilege. 1040 */ 1041 if (((uid != inode->n_uid && uid != cred->cr_uid) || 1042 (gid != inode->n_gid && !groupmember(gid, cred))) && 1043 (error = priv_check_cred(cred, PRIV_VFS_CHOWN))) 1044 return (error); 1045 1046 ogid = inode->n_gid; 1047 ouid = inode->n_uid; 1048 1049 inode->n_gid = gid; 1050 inode->n_uid = uid; 1051 1052 if ((inode->i_mode & (ISUID | ISGID)) && 1053 (ouid != uid || ogid != gid)) { 1054 1055 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID)) 1056 inode->i_mode &= ~(ISUID | ISGID); 1057 } 1058 P9_DEBUG(VOPS, "%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, cred, td); 1059 1060 return (0); 1061 } 1062 1063 /* 1064 * Update the in memory inode with all chmod new permissions/mode. Typically a 1065 * setattr is called to update it to server. 1066 */ 1067 static int 1068 p9fs_chmod(struct vnode *vp, uint32_t mode, struct ucred *cred, struct thread *td) 1069 { 1070 struct p9fs_node *np; 1071 struct p9fs_inode *inode; 1072 uint32_t nmode; 1073 int error; 1074 1075 np = P9FS_VTON(vp); 1076 inode = &np->inode; 1077 1078 P9_DEBUG(VOPS, "%s: vp %p, mode %x, cred %p, td %p\n", __func__, vp, mode, cred, td); 1079 /* 1080 * To modify the permissions on a file, must possess VADMIN 1081 * for that file. 1082 */ 1083 if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) 1084 return (error); 1085 1086 /* 1087 * Privileged processes may set the sticky bit on non-directories, 1088 * as well as set the setgid bit on a file with a group that the 1089 * process is not a member of. Both of these are allowed in 1090 * jail(8). 1091 */ 1092 if (vp->v_type != VDIR && (mode & S_ISTXT)) { 1093 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE)) 1094 return (EFTYPE); 1095 } 1096 if (!groupmember(inode->n_gid, cred) && (mode & ISGID)) { 1097 error = priv_check_cred(cred, PRIV_VFS_SETGID); 1098 if (error != 0) 1099 return (error); 1100 } 1101 1102 /* 1103 * Deny setting setuid if we are not the file owner. 1104 */ 1105 if ((mode & ISUID) && inode->n_uid != cred->cr_uid) { 1106 error = priv_check_cred(cred, PRIV_VFS_ADMIN); 1107 if (error != 0) 1108 return (error); 1109 } 1110 nmode = inode->i_mode; 1111 nmode &= ~ALLPERMS; 1112 nmode |= (mode & ALLPERMS); 1113 inode->i_mode = nmode; 1114 1115 P9_DEBUG(VOPS, "%s: to mode %x %d \n ", __func__, nmode, error); 1116 1117 return (error); 1118 } 1119 1120 /* 1121 * Set the attributes of a file referenced by fid. A valid bitmask is sent 1122 * in request selecting which fields to set 1123 */ 1124 static int 1125 p9fs_setattr_dotl(struct vop_setattr_args *ap) 1126 { 1127 struct vnode *vp; 1128 struct vattr *vap; 1129 struct p9fs_node *node; 1130 struct p9fs_inode *inode; 1131 struct ucred *cred; 1132 struct thread *td; 1133 struct p9_iattr_dotl *p9attr; 1134 struct p9fs_session *vses; 1135 struct p9_fid *vfid; 1136 uint64_t oldfilesize; 1137 int error; 1138 1139 vp = ap->a_vp; 1140 vap = ap->a_vap; 1141 node = P9FS_VTON(vp); 1142 inode = &node->inode; 1143 cred = ap->a_cred; 1144 td = curthread; 1145 vses = node->p9fs_ses; 1146 error = 0; 1147 1148 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 1149 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 1150 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 1151 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 1152 P9_DEBUG(ERROR, "%s: unsettable attribute\n", __func__); 1153 return (EINVAL); 1154 } 1155 /* Disallow write attempts on read only filesystem */ 1156 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1157 return (EROFS); 1158 1159 /* Setting of flags is not supported */ 1160 if (vap->va_flags != VNOVAL) 1161 return (EOPNOTSUPP); 1162 1163 /* Allocate p9attr struct */ 1164 p9attr = uma_zalloc(p9fs_setattr_zone, M_WAITOK | M_ZERO); 1165 if (p9attr == NULL) 1166 return (ENOMEM); 1167 1168 /* Check if we need to change the ownership of the file*/ 1169 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 1170 P9_DEBUG(VOPS, "%s: vp:%p td:%p uid/gid %x/%x\n", __func__, 1171 vp, td, vap->va_uid, vap->va_gid); 1172 1173 error = p9fs_chown(vp, vap->va_uid, vap->va_gid, cred, td); 1174 p9attr->valid |= P9PROTO_SETATTR_UID | P9PROTO_SETATTR_GID | 1175 P9PROTO_SETATTR_MODE; 1176 if (error) 1177 goto out; 1178 } 1179 1180 /* Check for mode changes */ 1181 if (vap->va_mode != (mode_t)VNOVAL) { 1182 P9_DEBUG(VOPS, "%s: vp:%p td:%p mode %x\n", __func__, vp, td, 1183 vap->va_mode); 1184 1185 error = p9fs_chmod(vp, (int)vap->va_mode, cred, td); 1186 p9attr->valid |= P9PROTO_SETATTR_MODE; 1187 if (error) 1188 goto out; 1189 } 1190 1191 /* Update the size of the file and update mtime */ 1192 if (vap->va_size != (uint64_t)VNOVAL) { 1193 P9_DEBUG(VOPS, "%s: vp:%p td:%p size:%jx\n", __func__, 1194 vp, td, (uintmax_t)vap->va_size); 1195 switch (vp->v_type) { 1196 case VDIR: 1197 error = EISDIR; 1198 goto out; 1199 case VLNK: 1200 case VREG: 1201 /* Invalidate cached pages of vp */ 1202 error = vinvalbuf(vp, 0, 0, 0); 1203 if (error) 1204 goto out; 1205 oldfilesize = inode->i_size; 1206 inode->i_size = vap->va_size; 1207 /* Update the p9fs_inode time */ 1208 p9fs_itimes(vp); 1209 p9attr->valid |= P9PROTO_SETATTR_SIZE | 1210 P9PROTO_SETATTR_ATIME | 1211 P9PROTO_SETATTR_MTIME | 1212 P9PROTO_SETATTR_ATIME_SET | 1213 P9PROTO_SETATTR_MTIME_SET ; 1214 break; 1215 default: 1216 goto out; 1217 } 1218 } else if (vap->va_atime.tv_sec != VNOVAL || 1219 vap->va_mtime.tv_sec != VNOVAL) { 1220 P9_DEBUG(VOPS, "%s: vp:%p td:%p time a/m %jx/%jx/\n", 1221 __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec, 1222 (uintmax_t)vap->va_mtime.tv_sec); 1223 /* Update the p9fs_inode times */ 1224 p9fs_itimes(vp); 1225 p9attr->valid |= P9PROTO_SETATTR_ATIME | 1226 P9PROTO_SETATTR_MTIME | P9PROTO_SETATTR_ATIME_SET | 1227 P9PROTO_SETATTR_MTIME_SET; 1228 } 1229 1230 vfid = p9fs_get_fid(vses->clnt, node, cred, VOFID, P9PROTO_OWRITE, &error); 1231 if (vfid == NULL) { 1232 vfid = p9fs_get_fid(vses->clnt, node, cred, VFID, -1, &error); 1233 if (error) 1234 goto out; 1235 } 1236 1237 /* Write the inode structure values into p9attr */ 1238 p9fs_inode_to_iattr(inode, p9attr); 1239 error = p9_client_setattr(vfid, p9attr); 1240 if (vap->va_size != (uint64_t)VNOVAL && vp->v_type == VREG) { 1241 if (error) 1242 inode->i_size = oldfilesize; 1243 else 1244 vnode_pager_setsize(vp, inode->i_size); 1245 } 1246 out: 1247 if (p9attr) { 1248 uma_zfree(p9fs_setattr_zone, p9attr); 1249 } 1250 P9_DEBUG(VOPS, "%s: error: %d\n", __func__, error); 1251 return (error); 1252 } 1253 1254 struct open_fid_state { 1255 struct p9_fid *vofid; 1256 int fflags; 1257 int opened; 1258 }; 1259 1260 /* 1261 * TODO: change this to take P9PROTO_* mode and avoid routing through 1262 * VOP_OPEN, factoring out implementation of p9fs_open. 1263 */ 1264 static int 1265 p9fs_get_open_fid(struct vnode *vp, int fflags, struct ucred *cr, struct open_fid_state *statep) 1266 { 1267 struct p9fs_node *np; 1268 struct p9fs_session *vses; 1269 struct p9_fid *vofid; 1270 int mode = p9fs_uflags_mode(fflags, TRUE); 1271 int error = 0; 1272 1273 statep->opened = FALSE; 1274 1275 np = P9FS_VTON(vp); 1276 vses = np->p9fs_ses; 1277 vofid = p9fs_get_fid(vses->clnt, np, cr, VOFID, mode, &error); 1278 if (vofid == NULL) { 1279 error = VOP_OPEN(vp, fflags, cr, curthread, NULL); 1280 if (error) { 1281 return (error); 1282 } 1283 vofid = p9fs_get_fid(vses->clnt, np, cr, VOFID, mode, &error); 1284 if (vofid == NULL) { 1285 return (EBADF); 1286 } 1287 statep->fflags = fflags; 1288 statep->opened = TRUE; 1289 } 1290 statep->vofid = vofid; 1291 return (0); 1292 } 1293 1294 static void 1295 p9fs_release_open_fid(struct vnode *vp, struct ucred *cr, struct open_fid_state *statep) 1296 { 1297 if (statep->opened) { 1298 (void) VOP_CLOSE(vp, statep->fflags, cr, curthread); 1299 } 1300 } 1301 1302 /* 1303 * An I/O buffer is used to to do any transfer. The uio is the vfs structure we 1304 * need to copy data into. As long as resid is greater than zero, we call 1305 * client_read to read data from offset(offset into the file) in the open fid 1306 * for the file into the I/O buffer. The data is read into the user data buffer. 1307 */ 1308 static int 1309 p9fs_read(struct vop_read_args *ap) 1310 { 1311 struct vnode *vp; 1312 struct uio *uio; 1313 struct p9fs_node *np; 1314 uint64_t offset; 1315 int64_t ret; 1316 uint64_t resid; 1317 uint32_t count; 1318 int error; 1319 char *io_buffer = NULL; 1320 uint64_t filesize; 1321 struct open_fid_state ostate; 1322 1323 vp = ap->a_vp; 1324 uio = ap->a_uio; 1325 np = P9FS_VTON(vp); 1326 error = 0; 1327 1328 if (vp->v_type == VCHR || vp->v_type == VBLK) 1329 return (EOPNOTSUPP); 1330 if (vp->v_type != VREG) 1331 return (EISDIR); 1332 if (uio->uio_resid == 0) 1333 return (0); 1334 if (uio->uio_offset < 0) 1335 return (EINVAL); 1336 1337 error = p9fs_get_open_fid(vp, FREAD, ap->a_cred, &ostate); 1338 if (error) 1339 return (error); 1340 1341 /* where in the file are we to start reading */ 1342 offset = uio->uio_offset; 1343 filesize = np->inode.i_size; 1344 if (uio->uio_offset >= filesize) 1345 goto out; 1346 1347 P9_DEBUG(VOPS, "%s: called %jd at %ju\n", 1348 __func__, (intmax_t)uio->uio_resid, (uintmax_t)uio->uio_offset); 1349 1350 /* Work with a local buffer from the pool for this vop */ 1351 1352 io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO); 1353 while ((resid = uio->uio_resid) > 0) { 1354 if (offset >= filesize) 1355 break; 1356 count = MIN(filesize - uio->uio_offset , resid); 1357 if (count == 0) 1358 break; 1359 1360 /* Copy count bytes into the uio */ 1361 ret = p9_client_read(ostate.vofid, offset, count, io_buffer); 1362 /* 1363 * This is the only place in the entire p9fs where we check the 1364 * error for < 0 as p9_client_read/write return the number of 1365 * bytes instead of an error code. In this case if ret is < 0, 1366 * it means there is an IO error. 1367 */ 1368 if (ret < 0) { 1369 error = -ret; 1370 goto out; 1371 } 1372 error = uiomove(io_buffer, ret, uio); 1373 if (error != 0) 1374 goto out; 1375 1376 offset += ret; 1377 } 1378 uio->uio_offset = offset; 1379 out: 1380 uma_zfree(p9fs_io_buffer_zone, io_buffer); 1381 p9fs_release_open_fid(vp, ap->a_cred, &ostate); 1382 1383 return (error); 1384 } 1385 1386 /* 1387 * The user buffer contains the data to be written. This data is copied first 1388 * from uio into I/O buffer. This I/O buffer is used to do the client_write to 1389 * the fid of the file starting from the offset given upto count bytes. The 1390 * number of bytes written is returned to the caller. 1391 */ 1392 static int 1393 p9fs_write(struct vop_write_args *ap) 1394 { 1395 struct vnode *vp; 1396 struct uio *uio; 1397 struct p9fs_node *np; 1398 uint64_t off, offset; 1399 int64_t ret; 1400 uint64_t resid, bytes_written; 1401 uint32_t count; 1402 int error, ioflag; 1403 uint64_t file_size; 1404 char *io_buffer = NULL; 1405 struct open_fid_state ostate; 1406 1407 vp = ap->a_vp; 1408 uio = ap->a_uio; 1409 np = P9FS_VTON(vp); 1410 error = 0; 1411 ioflag = ap->a_ioflag; 1412 1413 error = p9fs_get_open_fid(vp, FWRITE, ap->a_cred, &ostate); 1414 if (error) 1415 return (error); 1416 1417 P9_DEBUG(VOPS, "%s: %#zx at %#jx\n", 1418 __func__, uio->uio_resid, (uintmax_t)uio->uio_offset); 1419 1420 if (uio->uio_offset < 0) { 1421 error = EINVAL; 1422 goto out; 1423 } 1424 if (uio->uio_resid == 0) 1425 goto out; 1426 1427 file_size = np->inode.i_size; 1428 1429 switch (vp->v_type) { 1430 case VREG: 1431 if (ioflag & IO_APPEND) 1432 uio->uio_offset = file_size; 1433 break; 1434 case VDIR: 1435 return (EISDIR); 1436 case VLNK: 1437 break; 1438 default: 1439 panic("%s: bad file type vp: %p", __func__, vp); 1440 } 1441 1442 resid = uio->uio_resid; 1443 offset = uio->uio_offset; 1444 bytes_written = 0; 1445 error = 0; 1446 1447 io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO); 1448 while ((resid = uio->uio_resid) > 0) { 1449 off = 0; 1450 count = MIN(resid, P9FS_IOUNIT); 1451 error = uiomove(io_buffer, count, uio); 1452 1453 if (error != 0) { 1454 P9_DEBUG(ERROR, "%s: uiomove failed: %d\n", __func__, error); 1455 goto out; 1456 } 1457 1458 /* While count still exists, keep writing.*/ 1459 while (count > 0) { 1460 /* Copy count bytes from the uio */ 1461 ret = p9_client_write(ostate.vofid, offset, count, 1462 io_buffer + off); 1463 if (ret < 0) { 1464 if (bytes_written == 0) { 1465 error = -ret; 1466 goto out; 1467 } else { 1468 break; 1469 } 1470 } 1471 P9_DEBUG(VOPS, "%s: write %#zx at %#jx\n", 1472 __func__, uio->uio_resid, (uintmax_t)uio->uio_offset); 1473 1474 off += ret; 1475 offset += ret; 1476 bytes_written += ret; 1477 count -= ret; 1478 } 1479 } 1480 /* Update the fields in the node to reflect the change*/ 1481 if (file_size < uio->uio_offset + uio->uio_resid) { 1482 np->inode.i_size = uio->uio_offset + uio->uio_resid; 1483 vnode_pager_setsize(vp, uio->uio_offset + uio->uio_resid); 1484 } 1485 out: 1486 if (io_buffer) 1487 uma_zfree(p9fs_io_buffer_zone, io_buffer); 1488 p9fs_release_open_fid(vp, ap->a_cred, &ostate); 1489 1490 return (error); 1491 } 1492 1493 /* 1494 * Common handler of all removal-related VOPs (e.g. rmdir, rm). Perform the 1495 * client_remove op to send messages to remove the node's fid on the server. 1496 * After that, does a node metadata cleanup on client side. 1497 */ 1498 static int 1499 remove_common(struct p9fs_node *np, struct ucred *cred) 1500 { 1501 int error; 1502 struct p9fs_session *vses; 1503 struct vnode *vp; 1504 struct p9_fid *vfid; 1505 1506 error = 0; 1507 vses = np->p9fs_ses; 1508 vp = P9FS_NTOV(np); 1509 1510 vfid = p9fs_get_fid(vses->clnt, np, cred, VFID, -1, &error); 1511 if (error != 0) 1512 return (error); 1513 1514 error = p9_client_remove(vfid); 1515 if (error != 0) 1516 return (error); 1517 1518 /* Remove all non-open fids associated with the vp */ 1519 p9fs_fid_remove_all(np, TRUE); 1520 1521 /* Invalidate all entries of vnode from name cache and hash list. */ 1522 cache_purge(vp); 1523 1524 vfs_hash_remove(vp); 1525 np->flags |= P9FS_NODE_DELETED; 1526 1527 return (error); 1528 } 1529 1530 /* Remove vop for all files. Call common code for remove and adjust links */ 1531 static int 1532 p9fs_remove(struct vop_remove_args *ap) 1533 { 1534 struct vnode *vp; 1535 struct p9fs_node *np; 1536 struct vnode *dvp; 1537 struct p9fs_node *dnp; 1538 struct p9fs_inode *dinode; 1539 int error; 1540 1541 vp = ap->a_vp; 1542 np = P9FS_VTON(vp); 1543 dvp = ap->a_dvp; 1544 dnp = P9FS_VTON(dvp); 1545 dinode = &dnp->inode; 1546 1547 P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np); 1548 1549 if (vp->v_type == VDIR) 1550 return (EISDIR); 1551 1552 error = remove_common(np, ap->a_cnp->cn_cred); 1553 if (error == 0) 1554 P9FS_DECR_LINKS(dinode); 1555 1556 return (error); 1557 } 1558 1559 /* Remove vop for all directories. Call common code for remove and adjust links */ 1560 static int 1561 p9fs_rmdir(struct vop_rmdir_args *ap) 1562 { 1563 struct vnode *vp; 1564 struct p9fs_node *np; 1565 struct vnode *dvp; 1566 struct p9fs_node *dnp; 1567 struct p9fs_inode *dinode; 1568 int error; 1569 1570 vp = ap->a_vp; 1571 np = P9FS_VTON(vp); 1572 dvp = ap->a_dvp; 1573 dnp = P9FS_VTON(dvp); 1574 dinode = &dnp->inode; 1575 1576 P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np); 1577 1578 error = remove_common(np, ap->a_cnp->cn_cred); 1579 if (error == 0) 1580 P9FS_DECR_LINKS(dinode); 1581 1582 return (error); 1583 } 1584 1585 /* 1586 * Create symlinks. Make the permissions and call create_common code 1587 * for Soft links. 1588 */ 1589 static int 1590 p9fs_symlink(struct vop_symlink_args *ap) 1591 { 1592 struct vnode *dvp; 1593 struct vnode **vpp; 1594 struct vattr *vap; 1595 struct componentname *cnp; 1596 char *symtgt; 1597 struct p9fs_node *dnp; 1598 struct p9fs_session *vses; 1599 struct mount *mp; 1600 struct p9_fid *dvfid, *newfid; 1601 int error; 1602 char tmpchr; 1603 gid_t gid; 1604 1605 dvp = ap->a_dvp; 1606 vpp = ap->a_vpp; 1607 vap = ap->a_vap; 1608 cnp = ap->a_cnp; 1609 symtgt = (char*)(uintptr_t) ap->a_target; 1610 dnp = P9FS_VTON(dvp); 1611 vses = dnp->p9fs_ses; 1612 mp = vses->p9fs_mount; 1613 newfid = NULL; 1614 error = 0; 1615 gid = vap->va_gid; 1616 1617 P9_DEBUG(VOPS, "%s: dvp %p\n", __func__, dvp); 1618 1619 /* 1620 * Save the character present at namelen in nameptr string and 1621 * null terminate the character to get the search name for p9_dir_walk 1622 */ 1623 tmpchr = cnp->cn_nameptr[cnp->cn_namelen]; 1624 cnp->cn_nameptr[cnp->cn_namelen] = '\0'; 1625 1626 dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 1627 if (error != 0) 1628 goto out; 1629 1630 error = p9_create_symlink(dvfid, cnp->cn_nameptr, symtgt, gid); 1631 if (error != 0) 1632 goto out; 1633 1634 /*create vnode for symtgt */ 1635 newfid = p9_client_walk(dvfid, 1, &cnp->cn_nameptr, 1, &error); 1636 if (newfid != NULL) { 1637 error = p9fs_vget_common(mp, NULL, cnp->cn_lkflags, 1638 dnp, newfid, vpp, cnp->cn_nameptr); 1639 if (error != 0) 1640 goto out; 1641 } else 1642 goto out; 1643 1644 if ((cnp->cn_flags & MAKEENTRY) != 0) { 1645 cache_enter(P9FS_NTOV(dnp), *vpp, cnp); 1646 } 1647 P9_DEBUG(VOPS, "%s: created file under vp %p node %p fid %ju\n", 1648 __func__, *vpp, dnp, (uintmax_t)dvfid->fid); 1649 1650 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 1651 return (error); 1652 1653 out: 1654 if (newfid != NULL) 1655 p9_client_clunk(newfid); 1656 cnp->cn_nameptr[cnp->cn_namelen] = tmpchr; 1657 return (error); 1658 } 1659 1660 /* Create hard link */ 1661 static int 1662 p9fs_link(struct vop_link_args *ap) 1663 { 1664 struct vnode *vp; 1665 struct vnode *tdvp; 1666 struct componentname *cnp; 1667 struct p9fs_node *dnp; 1668 struct p9fs_node *np; 1669 struct p9fs_inode *inode; 1670 struct p9fs_session *vses; 1671 struct p9_fid *dvfid, *oldvfid; 1672 int error; 1673 1674 vp = ap->a_vp; 1675 tdvp = ap->a_tdvp; 1676 cnp = ap->a_cnp; 1677 dnp = P9FS_VTON(tdvp); 1678 np = P9FS_VTON(vp); 1679 inode = &np->inode; 1680 vses = np->p9fs_ses; 1681 error = 0; 1682 1683 P9_DEBUG(VOPS, "%s: tdvp %p vp %p\n", __func__, tdvp, vp); 1684 1685 dvfid = p9fs_get_fid(vses->clnt, dnp, cnp->cn_cred, VFID, -1, &error); 1686 if (error != 0) 1687 return (error); 1688 oldvfid = p9fs_get_fid(vses->clnt, np, cnp->cn_cred, VFID, -1, &error); 1689 if (error != 0) 1690 return (error); 1691 1692 error = p9_create_hardlink(dvfid, oldvfid, cnp->cn_nameptr); 1693 if (error != 0) 1694 return (error); 1695 /* Increment ref count on the inode */ 1696 P9FS_INCR_LINKS(inode); 1697 1698 return (0); 1699 } 1700 1701 /* Read contents of the symbolic link */ 1702 static int 1703 p9fs_readlink(struct vop_readlink_args *ap) 1704 { 1705 struct vnode *vp; 1706 struct uio *uio; 1707 struct p9fs_node *dnp; 1708 struct p9fs_session *vses; 1709 struct p9_fid *dvfid; 1710 int error, len; 1711 char *target; 1712 1713 vp = ap->a_vp; 1714 uio = ap->a_uio; 1715 dnp = P9FS_VTON(vp); 1716 vses = dnp->p9fs_ses; 1717 error = 0; 1718 1719 P9_DEBUG(VOPS, "%s: vp %p\n", __func__, vp); 1720 1721 dvfid = p9fs_get_fid(vses->clnt, dnp, ap->a_cred, VFID, -1, &error); 1722 if (error != 0) 1723 return (error); 1724 1725 error = p9_readlink(dvfid, &target); 1726 if (error != 0) 1727 return (error); 1728 1729 len = strlen(target); 1730 error = uiomove(target, len, uio); 1731 1732 return (0); 1733 } 1734 1735 /* 1736 * Iterate through a directory. An entire 8k data is read into the I/O buffer. 1737 * This buffer is parsed to make dir entries and fed to the user buffer to 1738 * complete it to the VFS. 1739 */ 1740 static int 1741 p9fs_readdir(struct vop_readdir_args *ap) 1742 { 1743 struct uio *uio; 1744 struct vnode *vp; 1745 struct dirent cde; 1746 int64_t offset; 1747 uint64_t diroffset; 1748 struct p9fs_node *np; 1749 int error; 1750 int32_t count; 1751 struct p9_client *clnt; 1752 struct p9_dirent dent; 1753 char *io_buffer; 1754 struct p9_fid *vofid; 1755 1756 uio = ap->a_uio; 1757 vp = ap->a_vp; 1758 np = P9FS_VTON(ap->a_vp); 1759 offset = 0; 1760 diroffset = 0; 1761 error = 0; 1762 count = 0; 1763 clnt = np->p9fs_ses->clnt; 1764 1765 P9_DEBUG(VOPS, "%s: vp %p, offset %jd, resid %zd\n", __func__, vp, (intmax_t) uio->uio_offset, uio->uio_resid); 1766 1767 if (ap->a_uio->uio_iov->iov_len <= 0) 1768 return (EINVAL); 1769 1770 if (vp->v_type != VDIR) 1771 return (ENOTDIR); 1772 1773 vofid = p9fs_get_fid(clnt, np, ap->a_cred, VOFID, P9PROTO_OREAD, &error); 1774 if (vofid == NULL) { 1775 P9_DEBUG(ERROR, "%s: NULL FID\n", __func__); 1776 return (EBADF); 1777 } 1778 1779 io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK); 1780 1781 /* We haven't reached the end yet. read more. */ 1782 diroffset = uio->uio_offset; 1783 while (uio->uio_resid >= sizeof(struct dirent)) { 1784 /* 1785 * We need to read more data as what is indicated by filesize because 1786 * filesize is based on data stored in struct dirent structure but 1787 * we read data in struct p9_dirent format which has different size. 1788 * Hence we read max data(P9FS_IOUNIT) everytime from host, convert 1789 * it into struct dirent structure and send it back. 1790 */ 1791 count = P9FS_IOUNIT; 1792 bzero(io_buffer, P9FS_MTU); 1793 count = p9_client_readdir(vofid, (char *)io_buffer, 1794 diroffset, count); 1795 1796 if (count == 0) 1797 break; 1798 1799 if (count < 0) { 1800 error = EIO; 1801 goto out; 1802 } 1803 1804 offset = 0; 1805 while (offset + QEMU_DIRENTRY_SZ <= count) { 1806 1807 /* 1808 * Read and make sense out of the buffer in one dirent 1809 * This is part of 9p protocol read. This reads one p9_dirent, 1810 * appends it to dirent(FREEBSD specifc) and continues to parse the buffer. 1811 */ 1812 bzero(&dent, sizeof(dent)); 1813 offset = p9_dirent_read(clnt, io_buffer, offset, count, 1814 &dent); 1815 if (offset < 0 || offset > count) { 1816 error = EIO; 1817 goto out; 1818 } 1819 1820 bzero(&cde, sizeof(cde)); 1821 strncpy(cde.d_name, dent.d_name, dent.len); 1822 cde.d_fileno = dent.qid.path; 1823 cde.d_type = dent.d_type; 1824 cde.d_namlen = dent.len; 1825 cde.d_reclen = GENERIC_DIRSIZ(&cde); 1826 1827 /* 1828 * If there isn't enough space in the uio to return a 1829 * whole dirent, break off read 1830 */ 1831 if (uio->uio_resid < GENERIC_DIRSIZ(&cde)) 1832 break; 1833 1834 /* Transfer */ 1835 error = uiomove(&cde, GENERIC_DIRSIZ(&cde), uio); 1836 if (error != 0) { 1837 error = EIO; 1838 goto out; 1839 } 1840 diroffset = dent.d_off; 1841 } 1842 } 1843 /* Pass on last transferred offset */ 1844 uio->uio_offset = diroffset; 1845 1846 out: 1847 uma_zfree(p9fs_io_buffer_zone, io_buffer); 1848 1849 return (error); 1850 } 1851 1852 static void 1853 p9fs_doio(struct vnode *vp, struct buf *bp, struct p9_fid *vofid, struct ucred *cr) 1854 { 1855 struct uio *uiov; 1856 struct iovec io; 1857 int error; 1858 uint64_t off, offset; 1859 uint64_t filesize; 1860 uint64_t resid; 1861 uint32_t count; 1862 int64_t ret; 1863 struct p9fs_node *np; 1864 char *io_buffer; 1865 1866 error = 0; 1867 np = P9FS_VTON(vp); 1868 1869 filesize = np->inode.i_size; 1870 uiov = malloc(sizeof(struct uio), M_P9UIOV, M_WAITOK); 1871 uiov->uio_iov = &io; 1872 uiov->uio_iovcnt = 1; 1873 uiov->uio_segflg = UIO_SYSSPACE; 1874 io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK | M_ZERO); 1875 1876 if (bp->b_iocmd == BIO_READ) { 1877 io.iov_len = uiov->uio_resid = bp->b_bcount; 1878 io.iov_base = bp->b_data; 1879 uiov->uio_rw = UIO_READ; 1880 1881 switch (vp->v_type) { 1882 1883 case VREG: 1884 { 1885 uiov->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE; 1886 1887 if (uiov->uio_resid) { 1888 int left = uiov->uio_resid; 1889 int nread = bp->b_bcount - left; 1890 1891 if (left > 0) 1892 bzero((char *)bp->b_data + nread, left); 1893 } 1894 /* where in the file are we to start reading */ 1895 offset = uiov->uio_offset; 1896 if (uiov->uio_offset >= filesize) 1897 goto out; 1898 1899 while ((resid = uiov->uio_resid) > 0) { 1900 if (offset >= filesize) 1901 break; 1902 count = min(filesize - uiov->uio_offset, resid); 1903 if (count == 0) 1904 break; 1905 1906 P9_DEBUG(VOPS, "%s: read called %#zx at %#jx\n", 1907 __func__, uiov->uio_resid, (uintmax_t)uiov->uio_offset); 1908 1909 /* Copy count bytes into the uio */ 1910 ret = p9_client_read(vofid, offset, count, io_buffer); 1911 error = uiomove(io_buffer, ret, uiov); 1912 1913 if (error != 0) 1914 goto out; 1915 offset += ret; 1916 } 1917 break; 1918 } 1919 default: 1920 printf("vfs: type %x unexpected\n", vp->v_type); 1921 break; 1922 } 1923 } else { 1924 if (bp->b_dirtyend > bp->b_dirtyoff) { 1925 io.iov_len = uiov->uio_resid = bp->b_dirtyend - bp->b_dirtyoff; 1926 uiov->uio_offset = ((off_t)bp->b_blkno) * PAGE_SIZE + bp->b_dirtyoff; 1927 io.iov_base = (char *)bp->b_data + bp->b_dirtyoff; 1928 uiov->uio_rw = UIO_WRITE; 1929 1930 if (uiov->uio_offset < 0) { 1931 error = EINVAL; 1932 goto out; 1933 } 1934 1935 if (uiov->uio_resid == 0) 1936 goto out; 1937 1938 resid = uiov->uio_resid; 1939 offset = uiov->uio_offset; 1940 error = 0; 1941 1942 while ((resid = uiov->uio_resid) > 0) { 1943 off = 0; 1944 count = MIN(resid, P9FS_IOUNIT); 1945 error = uiomove(io_buffer, count, uiov); 1946 if (error != 0) { 1947 goto out; 1948 } 1949 1950 while (count > 0) { 1951 /* Copy count bytes from the uio */ 1952 ret = p9_client_write(vofid, offset, count, 1953 io_buffer + off); 1954 if (ret < 0) 1955 goto out; 1956 1957 P9_DEBUG(VOPS, "%s: write called %#zx at %#jx\n", 1958 __func__, uiov->uio_resid, (uintmax_t)uiov->uio_offset); 1959 off += ret; 1960 offset += ret; 1961 count -= ret; 1962 } 1963 } 1964 1965 /* Update the fields in the node to reflect the change */ 1966 if (filesize < uiov->uio_offset + uiov->uio_resid) { 1967 np->inode.i_size = uiov->uio_offset + uiov->uio_resid; 1968 vnode_pager_setsize(vp, uiov->uio_offset + uiov->uio_resid); 1969 /* update the modified timers. */ 1970 p9fs_itimes(vp); 1971 } 1972 } else { 1973 bp->b_resid = 0; 1974 goto out1; 1975 } 1976 } 1977 out: 1978 /* Set the error */ 1979 if (error != 0) { 1980 bp->b_error = error; 1981 bp->b_ioflags |= BIO_ERROR; 1982 } 1983 bp->b_resid = uiov->uio_resid; 1984 out1: 1985 bufdone(bp); 1986 uma_zfree(p9fs_io_buffer_zone, io_buffer); 1987 free(uiov, M_P9UIOV); 1988 } 1989 1990 /* 1991 * The I/O buffer is mapped to a uio and a client_write/client_read is performed 1992 * the same way as p9fs_read and p9fs_write. 1993 */ 1994 static int 1995 p9fs_strategy(struct vop_strategy_args *ap) 1996 { 1997 struct vnode *vp; 1998 struct buf *bp; 1999 struct ucred *cr; 2000 int error; 2001 struct open_fid_state ostate; 2002 2003 vp = ap->a_vp; 2004 bp = ap->a_bp; 2005 error = 0; 2006 2007 P9_DEBUG(VOPS, "%s: vp %p, iocmd %d\n ", __func__, vp, bp->b_iocmd); 2008 2009 if (bp->b_iocmd == BIO_READ) 2010 cr = bp->b_rcred; 2011 else 2012 cr = bp->b_wcred; 2013 2014 error = p9fs_get_open_fid(vp, bp->b_iocmd == BIO_READ ? FREAD : FWRITE, cr, &ostate); 2015 if (error) { 2016 P9_DEBUG(ERROR, "%s: p9fs_get_open_fid failed: %d\n", __func__, error); 2017 bp->b_error = error; 2018 bp->b_ioflags |= BIO_ERROR; 2019 bufdone(bp); 2020 return (0); 2021 } 2022 2023 p9fs_doio(vp, bp, ostate.vofid, cr); 2024 p9fs_release_open_fid(vp, cr, &ostate); 2025 2026 return (0); 2027 } 2028 2029 /* Rename a file */ 2030 static int 2031 p9fs_rename(struct vop_rename_args *ap) 2032 { 2033 struct vnode *tvp; 2034 struct vnode *tdvp; 2035 struct vnode *fvp; 2036 struct vnode *fdvp; 2037 struct componentname *tcnp; 2038 struct componentname *fcnp; 2039 struct p9fs_node *tdnode; 2040 struct p9fs_node *fdnode; 2041 struct p9fs_inode *fdinode; 2042 struct p9fs_node *fnode; 2043 struct p9fs_inode *finode; 2044 struct p9fs_session *vses; 2045 struct p9fs_node *tnode; 2046 struct p9fs_inode *tinode; 2047 struct p9_fid *olddirvfid, *newdirvfid ; 2048 int error; 2049 2050 tvp = ap->a_tvp; 2051 tdvp = ap->a_tdvp; 2052 fvp = ap->a_fvp; 2053 fdvp = ap->a_fdvp; 2054 tcnp = ap->a_tcnp; 2055 fcnp = ap->a_fcnp; 2056 tdnode = P9FS_VTON(tdvp); 2057 fdnode = P9FS_VTON(fdvp); 2058 fdinode = &fdnode->inode; 2059 fnode = P9FS_VTON(fvp); 2060 finode = &fnode->inode; 2061 vses = fnode->p9fs_ses; 2062 error = 0; 2063 2064 P9_DEBUG(VOPS, "%s: tvp %p, tdvp %p, fvp %p, fdvp %p\n ", __func__, tvp, tdvp, fvp, fdvp); 2065 2066 /* Check for cross mount operation */ 2067 if (fvp->v_mount != tdvp->v_mount || 2068 (tvp && (fvp->v_mount != tvp->v_mount))) { 2069 error = EXDEV; 2070 goto out; 2071 } 2072 2073 /* warning if you are renaming to the same name */ 2074 if (fvp == tvp) 2075 error = 0; 2076 2077 olddirvfid = p9fs_get_fid(vses->clnt, fdnode, fcnp->cn_cred, VFID, -1, &error); 2078 if (error != 0) 2079 goto out; 2080 newdirvfid = p9fs_get_fid(vses->clnt, tdnode, tcnp->cn_cred, VFID, -1, &error); 2081 if (error != 0) 2082 goto out; 2083 2084 error = p9_client_renameat(olddirvfid, fcnp->cn_nameptr, newdirvfid, tcnp->cn_nameptr); 2085 if (error != 0) 2086 goto out; 2087 2088 /* 2089 * decrement the link count on the "from" file whose name is going 2090 * to be changed if its a directory 2091 */ 2092 if (fvp->v_type == VDIR) { 2093 if (tvp && tvp->v_type == VDIR) 2094 cache_purge(tdvp); 2095 P9FS_DECR_LINKS(fdinode); 2096 cache_purge(fdvp); 2097 } 2098 2099 /* Taking exclusive lock on the from node before decrementing the link count */ 2100 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 2101 goto out; 2102 P9FS_DECR_LINKS(finode); 2103 VOP_UNLOCK(fvp); 2104 2105 if (tvp) { 2106 tnode = P9FS_VTON(tvp); 2107 tinode = &tnode->inode; 2108 P9FS_DECR_LINKS(tinode); 2109 } 2110 2111 out: 2112 if (tdvp == tvp) 2113 vrele(tdvp); 2114 else 2115 vput(tdvp); 2116 if (tvp) 2117 vput(tvp); 2118 vrele(fdvp); 2119 vrele(fvp); 2120 return (error); 2121 } 2122 2123 2124 struct vop_vector p9fs_vnops = { 2125 .vop_default = &default_vnodeops, 2126 .vop_lookup = p9fs_lookup, 2127 .vop_open = p9fs_open, 2128 .vop_close = p9fs_close, 2129 .vop_access = p9fs_access, 2130 .vop_getattr = p9fs_getattr_dotl, 2131 .vop_setattr = p9fs_setattr_dotl, 2132 .vop_reclaim = p9fs_reclaim, 2133 .vop_inactive = p9fs_inactive, 2134 .vop_readdir = p9fs_readdir, 2135 .vop_create = p9fs_create, 2136 .vop_mknod = p9fs_mknod, 2137 .vop_read = p9fs_read, 2138 .vop_write = p9fs_write, 2139 .vop_remove = p9fs_remove, 2140 .vop_mkdir = p9fs_mkdir, 2141 .vop_rmdir = p9fs_rmdir, 2142 .vop_strategy = p9fs_strategy, 2143 .vop_symlink = p9fs_symlink, 2144 .vop_rename = p9fs_rename, 2145 .vop_link = p9fs_link, 2146 .vop_readlink = p9fs_readlink, 2147 }; 2148 VFS_VOP_VECTOR_REGISTER(p9fs_vnops); 2149