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