1 /* $NetBSD: lfs_rename.c,v 1.4 2013/07/28 01:10:49 dholland Exp $ */ 2 /* from NetBSD: ufs_rename.c,v 1.6 2013/01/22 09:39:18 dholland Exp */ 3 4 /*- 5 * Copyright (c) 2012 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Taylor R Campbell. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 /*- 33 * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc. 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to The NetBSD Foundation 37 * by Konrad E. Schroder <perseant@hhhh.org>. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 58 * POSSIBILITY OF SUCH DAMAGE. 59 */ 60 /* 61 * Copyright (c) 1986, 1989, 1991, 1993, 1995 62 * The Regents of the University of California. All rights reserved. 63 * 64 * Redistribution and use in source and binary forms, with or without 65 * modification, are permitted provided that the following conditions 66 * are met: 67 * 1. Redistributions of source code must retain the above copyright 68 * notice, this list of conditions and the following disclaimer. 69 * 2. Redistributions in binary form must reproduce the above copyright 70 * notice, this list of conditions and the following disclaimer in the 71 * documentation and/or other materials provided with the distribution. 72 * 3. Neither the name of the University nor the names of its contributors 73 * may be used to endorse or promote products derived from this software 74 * without specific prior written permission. 75 * 76 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 77 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 78 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 79 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 80 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 81 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 82 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 83 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 84 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 85 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 86 * SUCH DAMAGE. 87 * 88 * @(#)lfs_vnops.c 8.13 (Berkeley) 6/10/95 89 */ 90 91 #include <sys/cdefs.h> 92 __KERNEL_RCSID(0, "$NetBSD: lfs_rename.c,v 1.4 2013/07/28 01:10:49 dholland Exp $"); 93 94 #include <sys/param.h> 95 #include <sys/systm.h> 96 #include <sys/errno.h> 97 #include <sys/namei.h> 98 #include <sys/resourcevar.h> 99 #include <sys/kernel.h> 100 #include <sys/file.h> 101 #include <sys/stat.h> 102 #include <sys/buf.h> 103 #include <sys/proc.h> 104 #include <sys/mount.h> 105 #include <sys/vnode.h> 106 #include <sys/vnode_if.h> 107 #include <sys/pool.h> 108 #include <sys/signalvar.h> 109 #include <sys/kauth.h> 110 #include <sys/syslog.h> 111 #include <sys/fstrans.h> 112 113 #include <uvm/uvm.h> 114 #include <uvm/uvm_pmap.h> 115 #include <uvm/uvm_stat.h> 116 #include <uvm/uvm_pager.h> 117 118 #include <miscfs/fifofs/fifo.h> 119 #include <miscfs/genfs/genfs.h> 120 #include <miscfs/specfs/specdev.h> 121 122 #include <ufs/lfs/ulfs_inode.h> 123 #include <ufs/lfs/ulfsmount.h> 124 #include <ufs/lfs/ulfs_bswap.h> 125 #include <ufs/lfs/ulfs_extern.h> 126 127 #include <ufs/lfs/lfs.h> 128 #include <ufs/lfs/lfs_extern.h> 129 130 /* 131 * A virgin directory (no blushing please). 132 * 133 * XXX Copypasta from ulfs_vnops.c. Kill! 134 */ 135 static const struct lfs_dirtemplate mastertemplate = { 136 0, 12, LFS_DT_DIR, 1, ".", 137 0, LFS_DIRBLKSIZ - 12, LFS_DT_DIR, 2, ".." 138 }; 139 140 /* 141 * ulfs_gro_directory_empty_p: Return true if the directory vp is 142 * empty. dvp is its parent. 143 * 144 * vp and dvp must be locked and referenced. 145 */ 146 static bool 147 ulfs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred, 148 struct vnode *vp, struct vnode *dvp) 149 { 150 151 (void)mp; 152 KASSERT(mp != NULL); 153 KASSERT(vp != NULL); 154 KASSERT(dvp != NULL); 155 KASSERT(vp != dvp); 156 KASSERT(vp->v_mount == mp); 157 KASSERT(dvp->v_mount == mp); 158 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 159 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 160 161 return ulfs_dirempty(VTOI(vp), VTOI(dvp)->i_number, cred); 162 } 163 164 /* 165 * ulfs_gro_rename_check_possible: Check whether a rename is possible 166 * independent of credentials. 167 */ 168 static int 169 ulfs_gro_rename_check_possible(struct mount *mp, 170 struct vnode *fdvp, struct vnode *fvp, 171 struct vnode *tdvp, struct vnode *tvp) 172 { 173 174 (void)mp; 175 KASSERT(mp != NULL); 176 KASSERT(fdvp != NULL); 177 KASSERT(fvp != NULL); 178 KASSERT(tdvp != NULL); 179 KASSERT(fdvp != fvp); 180 KASSERT(fdvp != tvp); 181 KASSERT(tdvp != fvp); 182 KASSERT(tdvp != tvp); 183 KASSERT(fvp != tvp); 184 KASSERT(fdvp->v_type == VDIR); 185 KASSERT(tdvp->v_type == VDIR); 186 KASSERT(fdvp->v_mount == mp); 187 KASSERT(fvp->v_mount == mp); 188 KASSERT(tdvp->v_mount == mp); 189 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 190 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 191 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 192 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 193 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 194 195 return genfs_ufslike_rename_check_possible( 196 VTOI(fdvp)->i_flags, VTOI(fvp)->i_flags, 197 VTOI(tdvp)->i_flags, (tvp? VTOI(tvp)->i_flags : 0), 198 (tvp != NULL), 199 IMMUTABLE, APPEND); 200 } 201 202 /* 203 * ulfs_gro_rename_check_permitted: Check whether a rename is permitted 204 * given our credentials. 205 */ 206 static int 207 ulfs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred, 208 struct vnode *fdvp, struct vnode *fvp, 209 struct vnode *tdvp, struct vnode *tvp) 210 { 211 212 (void)mp; 213 KASSERT(mp != NULL); 214 KASSERT(fdvp != NULL); 215 KASSERT(fvp != NULL); 216 KASSERT(tdvp != NULL); 217 KASSERT(fdvp != fvp); 218 KASSERT(fdvp != tvp); 219 KASSERT(tdvp != fvp); 220 KASSERT(tdvp != tvp); 221 KASSERT(fvp != tvp); 222 KASSERT(fdvp->v_type == VDIR); 223 KASSERT(tdvp->v_type == VDIR); 224 KASSERT(fdvp->v_mount == mp); 225 KASSERT(fvp->v_mount == mp); 226 KASSERT(tdvp->v_mount == mp); 227 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 228 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 229 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 230 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 231 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 232 233 return genfs_ufslike_rename_check_permitted(cred, 234 fdvp, VTOI(fdvp)->i_mode, VTOI(fdvp)->i_uid, 235 fvp, VTOI(fvp)->i_uid, 236 tdvp, VTOI(tdvp)->i_mode, VTOI(tdvp)->i_uid, 237 tvp, (tvp? VTOI(tvp)->i_uid : 0)); 238 } 239 240 /* 241 * ulfs_gro_remove_check_possible: Check whether a remove is possible 242 * independent of credentials. 243 */ 244 static int 245 ulfs_gro_remove_check_possible(struct mount *mp, 246 struct vnode *dvp, struct vnode *vp) 247 { 248 249 (void)mp; 250 KASSERT(mp != NULL); 251 KASSERT(dvp != NULL); 252 KASSERT(vp != NULL); 253 KASSERT(dvp != vp); 254 KASSERT(dvp->v_type == VDIR); 255 KASSERT(vp->v_type != VDIR); 256 KASSERT(dvp->v_mount == mp); 257 KASSERT(vp->v_mount == mp); 258 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 259 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 260 261 return genfs_ufslike_remove_check_possible( 262 VTOI(dvp)->i_flags, VTOI(vp)->i_flags, 263 IMMUTABLE, APPEND); 264 } 265 266 /* 267 * ulfs_gro_remove_check_permitted: Check whether a remove is permitted 268 * given our credentials. 269 */ 270 static int 271 ulfs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred, 272 struct vnode *dvp, struct vnode *vp) 273 { 274 275 (void)mp; 276 KASSERT(mp != NULL); 277 KASSERT(dvp != NULL); 278 KASSERT(vp != NULL); 279 KASSERT(dvp != vp); 280 KASSERT(dvp->v_type == VDIR); 281 KASSERT(vp->v_type != VDIR); 282 KASSERT(dvp->v_mount == mp); 283 KASSERT(vp->v_mount == mp); 284 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 285 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 286 287 return genfs_ufslike_remove_check_permitted(cred, 288 dvp, VTOI(dvp)->i_mode, VTOI(dvp)->i_uid, vp, VTOI(vp)->i_uid); 289 } 290 291 /* 292 * ulfs_rename_ulr_overlap_p: True iff tulr overlaps with fulr so that 293 * entering a directory entry at tulr may move fulr. 294 */ 295 static bool 296 ulfs_rename_ulr_overlap_p(const struct ulfs_lookup_results *fulr, 297 const struct ulfs_lookup_results *tulr) 298 { 299 doff_t from_prev_start, from_prev_end, to_start, to_end; 300 301 KASSERT(fulr != NULL); 302 KASSERT(tulr != NULL); 303 KASSERT(fulr != tulr); 304 305 /* 306 * fulr is from a DELETE lookup, so fulr->ulr_count is the size 307 * of the preceding entry (d_reclen). 308 */ 309 from_prev_end = fulr->ulr_offset; 310 KASSERT(fulr->ulr_count <= from_prev_end); 311 from_prev_start = (from_prev_end - fulr->ulr_count); 312 313 /* 314 * tulr is from a RENAME lookup, so tulr->ulr_count is the size 315 * of the free space for an entry that we are about to fill. 316 */ 317 to_start = tulr->ulr_offset; 318 KASSERT(tulr->ulr_count < (LFS_MAXDIRSIZE - to_start)); 319 to_end = (to_start + tulr->ulr_count); 320 321 return 322 (((to_start <= from_prev_start) && (from_prev_start < to_end)) || 323 ((to_start <= from_prev_end) && (from_prev_end < to_end))); 324 } 325 326 /* 327 * ulfs_direct_namlen: Return the namlen of the directory entry ep from 328 * the directory vp. 329 */ 330 static int /* XXX int? uint8_t? */ 331 ulfs_direct_namlen(const struct lfs_direct *ep, const struct vnode *vp) 332 { 333 bool swap; 334 335 KASSERT(ep != NULL); 336 KASSERT(vp != NULL); 337 KASSERT(VTOI(vp) != NULL); 338 KASSERT(VTOI(vp)->i_ump != NULL); 339 340 #if (BYTE_ORDER == LITTLE_ENDIAN) 341 swap = (ULFS_IPNEEDSWAP(VTOI(vp)) == 0); 342 #else 343 swap = (ULFS_IPNEEDSWAP(VTOI(vp)) != 0); 344 #endif 345 346 return ((FSFMT(vp) && swap)? ep->d_type : ep->d_namlen); 347 } 348 349 /* 350 * ulfs_rename_recalculate_fulr: If we have just entered a directory into 351 * dvp at tulr, and we were about to remove one at fulr for an entry 352 * named fcnp, fulr may be invalid. So, if necessary, recalculate it. 353 */ 354 static int 355 ulfs_rename_recalculate_fulr(struct vnode *dvp, 356 struct ulfs_lookup_results *fulr, const struct ulfs_lookup_results *tulr, 357 const struct componentname *fcnp) 358 { 359 struct mount *mp; 360 struct lfs *fs; 361 struct ulfsmount *ump; 362 int needswap; 363 /* XXX int is a silly type for this; blame ulfsmount::um_dirblksiz. */ 364 int dirblksiz; 365 doff_t search_start, search_end; 366 doff_t offset; /* Offset of entry we're examining. */ 367 struct buf *bp; /* I/O block we're examining. */ 368 char *dirbuf; /* Pointer into directory at search_start. */ 369 struct lfs_direct *ep; /* Pointer to the entry we're examining. */ 370 /* XXX direct::d_reclen is 16-bit; 371 * ulfs_lookup_results::ulr_reclen is 32-bit. Blah. */ 372 uint32_t reclen; /* Length of the entry we're examining. */ 373 uint32_t prev_reclen; /* Length of the preceding entry. */ 374 int error; 375 376 KASSERT(dvp != NULL); 377 KASSERT(dvp->v_mount != NULL); 378 KASSERT(VTOI(dvp) != NULL); 379 KASSERT(fulr != NULL); 380 KASSERT(tulr != NULL); 381 KASSERT(fulr != tulr); 382 KASSERT(ulfs_rename_ulr_overlap_p(fulr, tulr)); 383 384 mp = dvp->v_mount; 385 ump = VFSTOULFS(mp); 386 fs = ump->um_lfs; 387 KASSERT(ump != NULL); 388 KASSERT(ump == VTOI(dvp)->i_ump); 389 KASSERT(fs == VTOI(dvp)->i_lfs); 390 391 needswap = ULFS_MPNEEDSWAP(fs); 392 393 dirblksiz = fs->um_dirblksiz; 394 KASSERT(0 < dirblksiz); 395 KASSERT((dirblksiz & (dirblksiz - 1)) == 0); 396 397 /* A directory block may not span across multiple I/O blocks. */ 398 KASSERT(dirblksiz <= mp->mnt_stat.f_iosize); 399 400 /* Find the bounds of the search. */ 401 search_start = tulr->ulr_offset; 402 KASSERT(fulr->ulr_reclen < (LFS_MAXDIRSIZE - fulr->ulr_offset)); 403 search_end = (fulr->ulr_offset + fulr->ulr_reclen); 404 405 /* Compaction must happen only within a directory block. (*) */ 406 KASSERT(search_start <= search_end); 407 KASSERT((search_end - (search_start &~ (dirblksiz - 1))) <= dirblksiz); 408 409 dirbuf = NULL; 410 bp = NULL; 411 error = ulfs_blkatoff(dvp, (off_t)search_start, &dirbuf, &bp, false); 412 if (error) 413 return error; 414 KASSERT(dirbuf != NULL); 415 KASSERT(bp != NULL); 416 417 /* 418 * Guarantee we sha'n't go past the end of the buffer we got. 419 * dirbuf is bp->b_data + (search_start & (iosize - 1)), and 420 * the valid range is [bp->b_data, bp->b_data + bp->b_bcount). 421 */ 422 KASSERT((search_end - search_start) <= 423 (bp->b_bcount - (search_start & (mp->mnt_stat.f_iosize - 1)))); 424 425 prev_reclen = fulr->ulr_count; 426 offset = search_start; 427 428 /* 429 * Search from search_start to search_end for the entry matching 430 * fcnp, which must be there because we found it before and it 431 * should only at most have moved earlier. 432 */ 433 for (;;) { 434 KASSERT(search_start <= offset); 435 KASSERT(offset < search_end); 436 437 /* 438 * Examine the directory entry at offset. 439 */ 440 ep = (struct lfs_direct *)(dirbuf + (offset - search_start)); 441 reclen = ulfs_rw16(ep->d_reclen, needswap); 442 443 if (ep->d_ino == 0) 444 goto next; /* Entry is unused. */ 445 446 if (ulfs_rw32(ep->d_ino, needswap) == ULFS_WINO) 447 goto next; /* Entry is whiteout. */ 448 449 if (fcnp->cn_namelen != ulfs_direct_namlen(ep, dvp)) 450 goto next; /* Wrong name length. */ 451 452 if (memcmp(ep->d_name, fcnp->cn_nameptr, fcnp->cn_namelen)) 453 goto next; /* Wrong name. */ 454 455 /* Got it! */ 456 break; 457 458 next: 459 if (! ((reclen < search_end) && 460 (offset < (search_end - reclen)))) { 461 brelse(bp, 0); 462 return EIO; /* XXX Panic? What? */ 463 } 464 465 /* We may not move past the search end. */ 466 KASSERT(reclen < search_end); 467 KASSERT(offset < (search_end - reclen)); 468 469 /* 470 * We may not move across a directory block boundary; 471 * see (*) above. 472 */ 473 KASSERT((offset &~ (dirblksiz - 1)) == 474 ((offset + reclen) &~ (dirblksiz - 1))); 475 476 prev_reclen = reclen; 477 offset += reclen; 478 } 479 480 /* 481 * Found the entry. Record where. 482 */ 483 fulr->ulr_offset = offset; 484 fulr->ulr_reclen = reclen; 485 486 /* 487 * Record the preceding record length, but not if we're at the 488 * start of a directory block. 489 */ 490 fulr->ulr_count = ((offset & (dirblksiz - 1))? prev_reclen : 0); 491 492 brelse(bp, 0); 493 return 0; 494 } 495 496 /* 497 * ulfs_gro_remove: Rename an object over another link to itself, 498 * effectively removing just the original link. 499 */ 500 static int 501 ulfs_gro_remove(struct mount *mp, kauth_cred_t cred, 502 struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp) 503 { 504 struct ulfs_lookup_results *ulr = de; 505 int error; 506 507 KASSERT(mp != NULL); 508 KASSERT(dvp != NULL); 509 KASSERT(cnp != NULL); 510 KASSERT(ulr != NULL); 511 KASSERT(vp != NULL); 512 KASSERT(dvp != vp); 513 KASSERT(dvp->v_mount == mp); 514 KASSERT(vp->v_mount == mp); 515 KASSERT(dvp->v_type == VDIR); 516 KASSERT(vp->v_type != VDIR); 517 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 518 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 519 KASSERT(cnp->cn_nameiop == DELETE); 520 521 fstrans_start(mp, FSTRANS_SHARED); 522 523 /* XXX ulfs_dirremove decrements vp's link count for us. */ 524 error = ulfs_dirremove(dvp, ulr, VTOI(vp), cnp->cn_flags, 0); 525 if (error) 526 goto out1; 527 528 VN_KNOTE(dvp, NOTE_WRITE); 529 VN_KNOTE(vp, (VTOI(vp)->i_nlink? NOTE_LINK : NOTE_DELETE)); 530 531 out1: 532 fstrans_done(mp); 533 return error; 534 } 535 536 /* 537 * ulfs_gro_lookup: Look up and save the lookup results. 538 */ 539 static int 540 ulfs_gro_lookup(struct mount *mp, struct vnode *dvp, 541 struct componentname *cnp, void *de_ret, struct vnode **vp_ret) 542 { 543 struct ulfs_lookup_results *ulr_ret = de_ret; 544 struct vnode *vp = NULL; 545 int error; 546 547 (void)mp; 548 KASSERT(mp != NULL); 549 KASSERT(dvp != NULL); 550 KASSERT(cnp != NULL); 551 KASSERT(ulr_ret != NULL); 552 KASSERT(vp_ret != NULL); 553 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 554 555 /* Kludge cargo-culted from dholland's ulfs_rename. */ 556 cnp->cn_flags &=~ MODMASK; 557 cnp->cn_flags |= (LOCKPARENT | LOCKLEAF); 558 559 error = relookup(dvp, &vp, cnp, 0 /* dummy */); 560 if ((error == 0) && (vp == NULL)) { 561 error = ENOENT; 562 goto out; 563 } else if (error) { 564 return error; 565 } 566 567 /* 568 * Thanks to VFS insanity, relookup locks vp, which screws us 569 * in various ways. 570 */ 571 KASSERT(vp != NULL); 572 VOP_UNLOCK(vp); 573 574 out: *ulr_ret = VTOI(dvp)->i_crap; 575 *vp_ret = vp; 576 return error; 577 } 578 579 /* 580 * ulfs_rmdired_p: Check whether the directory vp has been rmdired. 581 * 582 * vp must be locked and referenced. 583 */ 584 static bool 585 ulfs_rmdired_p(struct vnode *vp) 586 { 587 588 KASSERT(vp != NULL); 589 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 590 KASSERT(vp->v_type == VDIR); 591 592 /* XXX Is this correct? */ 593 return (VTOI(vp)->i_size == 0); 594 } 595 596 /* 597 * ulfs_dirbuf_dotdot_namlen: Return the namlen of the directory buffer 598 * dirbuf that came from the directory vp. Swap byte order if 599 * necessary. 600 */ 601 static int /* XXX int? uint8_t? */ 602 ulfs_dirbuf_dotdot_namlen(const struct lfs_dirtemplate *dirbuf, 603 const struct vnode *vp) 604 { 605 bool swap; 606 607 KASSERT(dirbuf != NULL); 608 KASSERT(vp != NULL); 609 KASSERT(VTOI(vp) != NULL); 610 KASSERT(VTOI(vp)->i_ump != NULL); 611 612 #if (BYTE_ORDER == LITTLE_ENDIAN) 613 swap = (ULFS_IPNEEDSWAP(VTOI(vp)) == 0); 614 #else 615 swap = (ULFS_IPNEEDSWAP(VTOI(vp)) != 0); 616 #endif 617 618 return ((FSFMT(vp) && swap)? 619 dirbuf->dotdot_type : dirbuf->dotdot_namlen); 620 } 621 622 /* 623 * ulfs_read_dotdot: Store in *ino_ret the inode number of the parent 624 * of the directory vp. 625 */ 626 static int 627 ulfs_read_dotdot(struct vnode *vp, kauth_cred_t cred, ino_t *ino_ret) 628 { 629 struct lfs_dirtemplate dirbuf; 630 int error; 631 632 KASSERT(vp != NULL); 633 KASSERT(ino_ret != NULL); 634 KASSERT(vp->v_type == VDIR); 635 636 error = vn_rdwr(UIO_READ, vp, &dirbuf, sizeof dirbuf, (off_t)0, 637 UIO_SYSSPACE, IO_NODELOCKED, cred, NULL, NULL); 638 if (error) 639 return error; 640 641 if (ulfs_dirbuf_dotdot_namlen(&dirbuf, vp) != 2 || 642 dirbuf.dotdot_name[0] != '.' || 643 dirbuf.dotdot_name[1] != '.') 644 /* XXX Panic? Print warning? */ 645 return ENOTDIR; 646 647 *ino_ret = ulfs_rw32(dirbuf.dotdot_ino, 648 ULFS_IPNEEDSWAP(VTOI(vp))); 649 return 0; 650 } 651 652 /* 653 * ulfs_gro_lock_directory: Lock the directory vp, but fail if it has 654 * been rmdir'd. 655 */ 656 static int 657 ulfs_gro_lock_directory(struct mount *mp, struct vnode *vp) 658 { 659 660 (void)mp; 661 KASSERT(mp != NULL); 662 KASSERT(vp != NULL); 663 KASSERT(vp->v_mount == mp); 664 665 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 666 667 if (ulfs_rmdired_p(vp)) { 668 VOP_UNLOCK(vp); 669 return ENOENT; 670 } 671 672 return 0; 673 } 674 675 /* 676 * ulfs_gro_genealogy: Analyze the genealogy of the source and target 677 * directories. 678 */ 679 static int 680 ulfs_gro_genealogy(struct mount *mp, kauth_cred_t cred, 681 struct vnode *fdvp, struct vnode *tdvp, 682 struct vnode **intermediate_node_ret) 683 { 684 struct vnode *vp, *dvp; 685 ino_t dotdot_ino; 686 int error; 687 688 KASSERT(mp != NULL); 689 KASSERT(fdvp != NULL); 690 KASSERT(tdvp != NULL); 691 KASSERT(fdvp != tdvp); 692 KASSERT(intermediate_node_ret != NULL); 693 KASSERT(fdvp->v_mount == mp); 694 KASSERT(tdvp->v_mount == mp); 695 KASSERT(fdvp->v_type == VDIR); 696 KASSERT(tdvp->v_type == VDIR); 697 698 /* 699 * We need to provisionally lock tdvp to keep rmdir from 700 * deleting it -- or any ancestor -- at an inopportune moment. 701 */ 702 error = ulfs_gro_lock_directory(mp, tdvp); 703 if (error) 704 return error; 705 706 vp = tdvp; 707 vref(vp); 708 709 for (;;) { 710 KASSERT(vp != NULL); 711 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 712 KASSERT(vp->v_mount == mp); 713 KASSERT(vp->v_type == VDIR); 714 KASSERT(!ulfs_rmdired_p(vp)); 715 716 /* Did we hit the root without finding fdvp? */ 717 if (VTOI(vp)->i_number == ULFS_ROOTINO) { 718 vput(vp); 719 *intermediate_node_ret = NULL; 720 return 0; 721 } 722 723 error = ulfs_read_dotdot(vp, cred, &dotdot_ino); 724 if (error) { 725 vput(vp); 726 return error; 727 } 728 729 /* Did we find that fdvp is an ancestor of tdvp? */ 730 if (VTOI(fdvp)->i_number == dotdot_ino) { 731 /* Unlock vp, but keep it referenced. */ 732 VOP_UNLOCK(vp); 733 *intermediate_node_ret = vp; 734 return 0; 735 } 736 737 /* Neither -- keep ascending the family tree. */ 738 739 /* 740 * Unlock vp so that we can lock the parent, but keep 741 * vp referenced until after we have found the parent, 742 * so that dotdot_ino will not be recycled. 743 * 744 * XXX This guarantees that vp's inode number will not 745 * be recycled, but why can't dotdot_ino be recycled? 746 */ 747 VOP_UNLOCK(vp); 748 error = VFS_VGET(mp, dotdot_ino, &dvp); 749 vrele(vp); 750 if (error) 751 return error; 752 753 KASSERT(dvp != NULL); 754 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 755 vp = dvp; 756 757 if (vp->v_type != VDIR) { 758 /* 759 * XXX Panic? Print a warning? Can this 760 * happen if we lose the race I suspect to 761 * exist above, and the `..' inode number has 762 * been recycled? 763 */ 764 vput(vp); 765 return ENOTDIR; 766 } 767 768 if (ulfs_rmdired_p(vp)) { 769 vput(vp); 770 return ENOENT; 771 } 772 } 773 } 774 775 /* 776 * ulfs_gro_rename: Actually perform the rename operation. 777 */ 778 static int 779 ulfs_gro_rename(struct mount *mp, kauth_cred_t cred, 780 struct vnode *fdvp, struct componentname *fcnp, 781 void *fde, struct vnode *fvp, 782 struct vnode *tdvp, struct componentname *tcnp, 783 void *tde, struct vnode *tvp) 784 { 785 struct ulfs_lookup_results *fulr = fde; 786 struct ulfs_lookup_results *tulr = tde; 787 bool directory_p, reparent_p; 788 struct lfs_direct *newdir; 789 int error; 790 791 KASSERT(mp != NULL); 792 KASSERT(fdvp != NULL); 793 KASSERT(fcnp != NULL); 794 KASSERT(fulr != NULL); 795 KASSERT(fvp != NULL); 796 KASSERT(tdvp != NULL); 797 KASSERT(tcnp != NULL); 798 KASSERT(tulr != NULL); 799 KASSERT(fulr != tulr); 800 KASSERT(fdvp != fvp); 801 KASSERT(fdvp != tvp); 802 KASSERT(tdvp != fvp); 803 KASSERT(tdvp != tvp); 804 KASSERT(fvp != tvp); 805 KASSERT(fdvp->v_mount == mp); 806 KASSERT(fvp->v_mount == mp); 807 KASSERT(tdvp->v_mount == mp); 808 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 809 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 810 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 811 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 812 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 813 814 /* 815 * We shall need to temporarily bump the link count, so make 816 * sure there is room to do so. 817 */ 818 if ((nlink_t)VTOI(fvp)->i_nlink >= LINK_MAX) 819 return EMLINK; 820 821 directory_p = (fvp->v_type == VDIR); 822 KASSERT(directory_p == ((VTOI(fvp)->i_mode & LFS_IFMT) == LFS_IFDIR)); 823 KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR))); 824 KASSERT((tvp == NULL) || (directory_p == 825 ((VTOI(tvp)->i_mode & LFS_IFMT) == LFS_IFDIR))); 826 827 reparent_p = (fdvp != tdvp); 828 KASSERT(reparent_p == (VTOI(fdvp)->i_number != VTOI(tdvp)->i_number)); 829 830 /* 831 * Commence hacking of the data on disk. 832 */ 833 834 fstrans_start(mp, FSTRANS_SHARED); 835 error = 0; 836 837 /* 838 * 1) Bump link count while we're moving stuff 839 * around. If we crash somewhere before 840 * completing our work, the link count 841 * may be wrong, but correctable. 842 */ 843 844 KASSERT((nlink_t)VTOI(fvp)->i_nlink < LINK_MAX); 845 VTOI(fvp)->i_nlink++; 846 DIP_ASSIGN(VTOI(fvp), nlink, VTOI(fvp)->i_nlink); 847 VTOI(fvp)->i_flag |= IN_CHANGE; 848 error = lfs_update(fvp, NULL, NULL, UPDATE_DIROP); 849 if (error) 850 goto whymustithurtsomuch; 851 852 /* 853 * 2) If target doesn't exist, link the target 854 * to the source and unlink the source. 855 * Otherwise, rewrite the target directory 856 * entry to reference the source inode and 857 * expunge the original entry's existence. 858 */ 859 860 if (tvp == NULL) { 861 /* 862 * Account for ".." in new directory. 863 * When source and destination have the same 864 * parent we don't fool with the link count. 865 */ 866 if (directory_p && reparent_p) { 867 if ((nlink_t)VTOI(tdvp)->i_nlink >= LINK_MAX) { 868 error = EMLINK; 869 goto whymustithurtsomuch; 870 } 871 KASSERT((nlink_t)VTOI(tdvp)->i_nlink < LINK_MAX); 872 VTOI(tdvp)->i_nlink++; 873 DIP_ASSIGN(VTOI(tdvp), nlink, VTOI(tdvp)->i_nlink); 874 VTOI(tdvp)->i_flag |= IN_CHANGE; 875 error = lfs_update(tdvp, NULL, NULL, UPDATE_DIROP); 876 if (error) { 877 /* 878 * Link count update didn't take -- 879 * back out the in-memory link count. 880 */ 881 KASSERT(0 < VTOI(tdvp)->i_nlink); 882 VTOI(tdvp)->i_nlink--; 883 DIP_ASSIGN(VTOI(tdvp), nlink, 884 VTOI(tdvp)->i_nlink); 885 VTOI(tdvp)->i_flag |= IN_CHANGE; 886 goto whymustithurtsomuch; 887 } 888 } 889 890 newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK); 891 ulfs_makedirentry(VTOI(fvp), tcnp, newdir); 892 error = ulfs_direnter(tdvp, tulr, NULL, newdir, tcnp, NULL); 893 pool_cache_put(ulfs_direct_cache, newdir); 894 if (error) { 895 if (directory_p && reparent_p) { 896 /* 897 * Directory update didn't take, but 898 * the link count update did -- back 899 * out the in-memory link count and the 900 * on-disk link count. 901 */ 902 KASSERT(0 < VTOI(tdvp)->i_nlink); 903 VTOI(tdvp)->i_nlink--; 904 DIP_ASSIGN(VTOI(tdvp), nlink, 905 VTOI(tdvp)->i_nlink); 906 VTOI(tdvp)->i_flag |= IN_CHANGE; 907 (void)lfs_update(tdvp, NULL, NULL, 908 UPDATE_WAIT | UPDATE_DIROP); 909 } 910 goto whymustithurtsomuch; 911 } 912 } else { 913 if (directory_p) 914 /* XXX WTF? Why purge here? Why not purge others? */ 915 cache_purge(tdvp); 916 917 /* 918 * Make the target directory's entry for tcnp point at 919 * the source node. 920 * 921 * XXX ulfs_dirrewrite decrements tvp's link count, but 922 * doesn't touch the link count of the new inode. Go 923 * figure. 924 */ 925 error = ulfs_dirrewrite(VTOI(tdvp), tulr->ulr_offset, 926 VTOI(tvp), VTOI(fvp)->i_number, LFS_IFTODT(VTOI(fvp)->i_mode), 927 ((directory_p && reparent_p) ? reparent_p : directory_p), 928 IN_CHANGE | IN_UPDATE); 929 if (error) 930 goto whymustithurtsomuch; 931 932 /* 933 * If the source and target are directories, and the 934 * target is in the same directory as the source, 935 * decrement the link count of the common parent 936 * directory, since we are removing the target from 937 * that directory. 938 */ 939 if (directory_p && !reparent_p) { 940 KASSERT(fdvp == tdvp); 941 /* XXX check, don't kassert */ 942 KASSERT(0 < VTOI(tdvp)->i_nlink); 943 VTOI(tdvp)->i_nlink--; 944 DIP_ASSIGN(VTOI(tdvp), nlink, VTOI(tdvp)->i_nlink); 945 VTOI(tdvp)->i_flag |= IN_CHANGE; 946 } 947 948 if (directory_p) { 949 /* 950 * XXX I don't understand the following comment 951 * from ulfs_rename -- in particular, the part 952 * about `there may be other hard links'. 953 * 954 * Truncate inode. The only stuff left in the directory 955 * is "." and "..". The "." reference is inconsequential 956 * since we are quashing it. We have removed the "." 957 * reference and the reference in the parent directory, 958 * but there may be other hard links. 959 * 960 * XXX The ulfs_dirempty call earlier does 961 * not guarantee anything about nlink. 962 */ 963 if (VTOI(tvp)->i_nlink != 1) 964 ulfs_dirbad(VTOI(tvp), (doff_t)0, 965 "hard-linked directory"); 966 VTOI(tvp)->i_nlink = 0; 967 DIP_ASSIGN(VTOI(tvp), nlink, 0); 968 error = lfs_truncate(tvp, (off_t)0, IO_SYNC, cred); 969 if (error) 970 goto whymustithurtsomuch; 971 } 972 } 973 974 /* 975 * If the source is a directory with a new parent, the link 976 * count of the old parent directory must be decremented and 977 * ".." set to point to the new parent. 978 * 979 * XXX ulfs_dirrewrite updates the link count of fdvp, but not 980 * the link count of fvp or the link count of tdvp. Go figure. 981 */ 982 if (directory_p && reparent_p) { 983 error = ulfs_dirrewrite(VTOI(fvp), mastertemplate.dot_reclen, 984 VTOI(fdvp), VTOI(tdvp)->i_number, LFS_DT_DIR, 0, IN_CHANGE); 985 #if 0 /* XXX This branch was not in ulfs_rename! */ 986 if (error) 987 goto whymustithurtsomuch; 988 #endif 989 990 /* XXX WTF? Why purge here? Why not purge others? */ 991 cache_purge(fdvp); 992 } 993 994 /* 995 * 3) Unlink the source. 996 */ 997 998 /* 999 * ulfs_direnter may compact the directory in the process of 1000 * inserting a new entry. That may invalidate fulr, which we 1001 * need in order to remove the old entry. In that case, we 1002 * need to recalculate what fulr should be. 1003 */ 1004 if (!reparent_p && (tvp == NULL) && 1005 ulfs_rename_ulr_overlap_p(fulr, tulr)) { 1006 error = ulfs_rename_recalculate_fulr(fdvp, fulr, tulr, fcnp); 1007 #if 0 /* XXX */ 1008 if (error) /* XXX Try to back out changes? */ 1009 goto whymustithurtsomuch; 1010 #endif 1011 } 1012 1013 /* 1014 * XXX 0 means !isrmdir. But can't this be an rmdir? 1015 * XXX Well, turns out that argument to ulfs_dirremove is ignored... 1016 * XXX And it turns out ulfs_dirremove updates the link count of fvp. 1017 * XXX But it doesn't update the link count of fdvp. Go figure. 1018 * XXX fdvp's link count is updated in ulfs_dirrewrite instead. 1019 * XXX Actually, sometimes it doesn't update fvp's link count. 1020 * XXX I hate the world. 1021 */ 1022 error = ulfs_dirremove(fdvp, fulr, VTOI(fvp), fcnp->cn_flags, 0); 1023 if (error) 1024 #if 0 /* XXX */ 1025 goto whymustithurtsomuch; 1026 #endif 1027 goto arghmybrainhurts; 1028 1029 /* 1030 * XXX Perhaps this should go at the top, in case the file 1031 * system is modified but incompletely so because of an 1032 * intermediate error. 1033 */ 1034 genfs_rename_knote(fdvp, fvp, tdvp, tvp, 1035 ((tvp != NULL) && (VTOI(tvp)->i_nlink == 0))); 1036 #if 0 /* XXX */ 1037 genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp); 1038 #endif 1039 goto arghmybrainhurts; 1040 1041 whymustithurtsomuch: 1042 KASSERT(0 < VTOI(fvp)->i_nlink); 1043 VTOI(fvp)->i_nlink--; 1044 DIP_ASSIGN(VTOI(fvp), nlink, VTOI(fvp)->i_nlink); 1045 VTOI(fvp)->i_flag |= IN_CHANGE; 1046 1047 arghmybrainhurts: 1048 /*ihateyou:*/ 1049 fstrans_done(mp); 1050 return error; 1051 } 1052 1053 /* 1054 * lfs_gro_rename: Actually perform the rename operation. Do a little 1055 * LFS bookkeeping and then defer to ulfs_gro_rename. 1056 */ 1057 static int 1058 lfs_gro_rename(struct mount *mp, kauth_cred_t cred, 1059 struct vnode *fdvp, struct componentname *fcnp, 1060 void *fde, struct vnode *fvp, 1061 struct vnode *tdvp, struct componentname *tcnp, 1062 void *tde, struct vnode *tvp) 1063 { 1064 int error; 1065 1066 KASSERT(mp != NULL); 1067 KASSERT(fdvp != NULL); 1068 KASSERT(fcnp != NULL); 1069 KASSERT(fde != NULL); 1070 KASSERT(fvp != NULL); 1071 KASSERT(tdvp != NULL); 1072 KASSERT(tcnp != NULL); 1073 KASSERT(tde != NULL); 1074 KASSERT(fdvp != fvp); 1075 KASSERT(fdvp != tvp); 1076 KASSERT(tdvp != fvp); 1077 KASSERT(tdvp != tvp); 1078 KASSERT(fvp != tvp); 1079 KASSERT(fdvp->v_mount == mp); 1080 KASSERT(fvp->v_mount == mp); 1081 KASSERT(tdvp->v_mount == mp); 1082 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 1083 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 1084 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 1085 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 1086 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 1087 1088 error = SET_DIROP_REMOVE(tdvp, tvp); 1089 if (error != 0) 1090 return error; 1091 1092 MARK_VNODE(fdvp); 1093 MARK_VNODE(fvp); 1094 1095 error = ulfs_gro_rename(mp, cred, 1096 fdvp, fcnp, fde, fvp, 1097 tdvp, tcnp, tde, tvp); 1098 1099 UNMARK_VNODE(fdvp); 1100 UNMARK_VNODE(fvp); 1101 SET_ENDOP_REMOVE(VFSTOULFS(mp)->um_lfs, tdvp, tvp, "rename"); 1102 1103 return error; 1104 } 1105 1106 static const struct genfs_rename_ops lfs_genfs_rename_ops = { 1107 .gro_directory_empty_p = ulfs_gro_directory_empty_p, 1108 .gro_rename_check_possible = ulfs_gro_rename_check_possible, 1109 .gro_rename_check_permitted = ulfs_gro_rename_check_permitted, 1110 .gro_remove_check_possible = ulfs_gro_remove_check_possible, 1111 .gro_remove_check_permitted = ulfs_gro_remove_check_permitted, 1112 .gro_rename = lfs_gro_rename, 1113 .gro_remove = ulfs_gro_remove, 1114 .gro_lookup = ulfs_gro_lookup, 1115 .gro_genealogy = ulfs_gro_genealogy, 1116 .gro_lock_directory = ulfs_gro_lock_directory, 1117 }; 1118 1119 /* 1120 * lfs_sane_rename: The hairiest vop, with the saner API. 1121 * 1122 * Arguments: 1123 * 1124 * . fdvp (from directory vnode), 1125 * . fcnp (from component name), 1126 * . tdvp (to directory vnode), 1127 * . tcnp (to component name), 1128 * . cred (credentials structure), and 1129 * . posixly_correct (flag for behaviour if target & source link same file). 1130 * 1131 * fdvp and tdvp may be the same, and must be referenced and unlocked. 1132 */ 1133 static int 1134 lfs_sane_rename( 1135 struct vnode *fdvp, struct componentname *fcnp, 1136 struct vnode *tdvp, struct componentname *tcnp, 1137 kauth_cred_t cred, bool posixly_correct) 1138 { 1139 struct ulfs_lookup_results fulr, tulr; 1140 1141 /* 1142 * XXX Provisional kludge -- ulfs_lookup does not reject rename 1143 * of . or .. (from or to), so we hack it here. This is not 1144 * the right place: it should be caller's responsibility to 1145 * reject this case. 1146 */ 1147 KASSERT(fcnp != NULL); 1148 KASSERT(tcnp != NULL); 1149 KASSERT(fcnp != tcnp); 1150 KASSERT(fcnp->cn_nameptr != NULL); 1151 KASSERT(tcnp->cn_nameptr != NULL); 1152 1153 if ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) 1154 return EINVAL; /* XXX EISDIR? */ 1155 if ((fcnp->cn_namelen == 1) && (fcnp->cn_nameptr[0] == '.')) 1156 return EINVAL; 1157 if ((tcnp->cn_namelen == 1) && (tcnp->cn_nameptr[0] == '.')) 1158 return EINVAL; 1159 1160 return genfs_sane_rename(&lfs_genfs_rename_ops, 1161 fdvp, fcnp, &fulr, tdvp, tcnp, &tulr, 1162 cred, posixly_correct); 1163 } 1164 1165 /* 1166 * lfs_rename: The hairiest vop, with the insanest API. Defer to 1167 * genfs_insane_rename immediately. 1168 */ 1169 int 1170 lfs_rename(void *v) 1171 { 1172 1173 return genfs_insane_rename(v, &lfs_sane_rename); 1174 } 1175