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