1 /* 2 * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 7 * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression) 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 3. Neither the name of The DragonFly Project nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific, prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 /* 37 * Per-node backend for kernel filesystem interface. 38 * 39 * This executes a VOP concurrently on multiple nodes, each node via its own 40 * thread, and competes to advance the original request. The original 41 * request is retired the moment all requirements are met, even if the 42 * operation is still in-progress on some nodes. 43 */ 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/fcntl.h> 48 #include <sys/buf.h> 49 #include <sys/proc.h> 50 #include <sys/namei.h> 51 #include <sys/mount.h> 52 #include <sys/vnode.h> 53 #include <sys/mountctl.h> 54 #include <sys/dirent.h> 55 #include <sys/uio.h> 56 #include <sys/objcache.h> 57 #include <sys/event.h> 58 #include <sys/file.h> 59 #include <vfs/fifofs/fifo.h> 60 61 #include "hammer2.h" 62 63 /* 64 * Determine if the specified directory is empty. Returns 0 on success. 65 * 66 * May return 0, ENOTDIR, or EAGAIN. 67 */ 68 static 69 int 70 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex) 71 { 72 hammer2_chain_t *parent; 73 hammer2_chain_t *chain; 74 hammer2_key_t key_next; 75 int cache_index = -1; 76 int error; 77 78 error = 0; 79 chain = hammer2_chain_lookup_init(ochain, 0); 80 81 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) { 82 if (oparent) 83 hammer2_chain_unlock(oparent); 84 85 parent = NULL; 86 error = hammer2_chain_hardlink_find(&parent, &chain, 87 clindex, 0); 88 if (parent) { 89 hammer2_chain_unlock(parent); 90 hammer2_chain_drop(parent); 91 } 92 if (oparent) { 93 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS); 94 if (ochain->parent != oparent) { 95 if (chain) { 96 hammer2_chain_unlock(chain); 97 hammer2_chain_drop(chain); 98 } 99 kprintf("H2EAGAIN\n"); 100 101 return EAGAIN; 102 } 103 } 104 } 105 106 parent = chain; 107 chain = NULL; 108 if (parent) { 109 chain = hammer2_chain_lookup(&parent, &key_next, 110 HAMMER2_DIRHASH_VISIBLE, 111 HAMMER2_KEY_MAX, 112 &cache_index, 0); 113 } 114 if (chain) { 115 error = ENOTEMPTY; 116 hammer2_chain_unlock(chain); 117 hammer2_chain_drop(chain); 118 } else { 119 error = 0; 120 } 121 hammer2_chain_lookup_done(parent); 122 123 return error; 124 } 125 126 /* 127 * Backend for hammer2_vfs_root() 128 * 129 * This is called when a newly mounted PFS has not yet synchronized 130 * to the inode_tid and modify_tid. 131 */ 132 void 133 hammer2_xop_ipcluster(hammer2_xop_t *arg, int clindex) 134 { 135 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster; 136 hammer2_chain_t *chain; 137 int error; 138 139 chain = hammer2_inode_chain(xop->head.ip1, clindex, 140 HAMMER2_RESOLVE_ALWAYS | 141 HAMMER2_RESOLVE_SHARED); 142 if (chain) 143 error = chain->error; 144 else 145 error = EIO; 146 147 hammer2_xop_feed(&xop->head, chain, clindex, error); 148 if (chain) { 149 hammer2_chain_unlock(chain); 150 hammer2_chain_drop(chain); 151 } 152 } 153 154 /* 155 * Backend for hammer2_vop_readdir() 156 */ 157 void 158 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex) 159 { 160 hammer2_xop_readdir_t *xop = &arg->xop_readdir; 161 hammer2_chain_t *parent; 162 hammer2_chain_t *chain; 163 hammer2_key_t key_next; 164 hammer2_key_t lkey; 165 int cache_index = -1; 166 int error = 0; 167 168 lkey = xop->lkey; 169 if (hammer2_debug & 0x0020) 170 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey); 171 172 /* 173 * The inode's chain is the iterator. If we cannot acquire it our 174 * contribution ends here. 175 */ 176 parent = hammer2_inode_chain(xop->head.ip1, clindex, 177 HAMMER2_RESOLVE_ALWAYS | 178 HAMMER2_RESOLVE_SHARED); 179 if (parent == NULL) { 180 kprintf("xop_readdir: NULL parent\n"); 181 goto done; 182 } 183 184 /* 185 * Directory scan [re]start and loop, the feed inherits the chain's 186 * lock so do not unlock it on the iteration. 187 */ 188 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey, 189 &cache_index, HAMMER2_LOOKUP_SHARED); 190 if (chain == NULL) { 191 chain = hammer2_chain_lookup(&parent, &key_next, 192 lkey, HAMMER2_KEY_MAX, 193 &cache_index, 194 HAMMER2_LOOKUP_SHARED); 195 } 196 while (chain) { 197 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 198 if (error) 199 break; 200 chain = hammer2_chain_next(&parent, chain, &key_next, 201 key_next, HAMMER2_KEY_MAX, 202 &cache_index, 203 HAMMER2_LOOKUP_SHARED); 204 } 205 if (chain) { 206 hammer2_chain_unlock(chain); 207 hammer2_chain_drop(chain); 208 } 209 hammer2_chain_unlock(parent); 210 hammer2_chain_drop(parent); 211 done: 212 hammer2_xop_feed(&xop->head, NULL, clindex, error); 213 } 214 215 /* 216 * Backend for hammer2_vop_nresolve() 217 */ 218 void 219 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex) 220 { 221 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve; 222 hammer2_chain_t *parent; 223 hammer2_chain_t *chain; 224 const hammer2_inode_data_t *ripdata; 225 const char *name; 226 size_t name_len; 227 hammer2_key_t key_next; 228 hammer2_key_t lhc; 229 int cache_index = -1; /* XXX */ 230 int error; 231 232 parent = hammer2_inode_chain(xop->head.ip1, clindex, 233 HAMMER2_RESOLVE_ALWAYS | 234 HAMMER2_RESOLVE_SHARED); 235 if (parent == NULL) { 236 kprintf("xop_nresolve: NULL parent\n"); 237 chain = NULL; 238 error = EIO; 239 goto done; 240 } 241 name = xop->head.name1; 242 name_len = xop->head.name1_len; 243 244 /* 245 * Lookup the directory entry 246 */ 247 lhc = hammer2_dirhash(name, name_len); 248 chain = hammer2_chain_lookup(&parent, &key_next, 249 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 250 &cache_index, 251 HAMMER2_LOOKUP_ALWAYS | 252 HAMMER2_LOOKUP_SHARED); 253 while (chain) { 254 ripdata = &chain->data->ipdata; 255 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 256 ripdata->meta.name_len == name_len && 257 bcmp(ripdata->filename, name, name_len) == 0) { 258 break; 259 } 260 chain = hammer2_chain_next(&parent, chain, &key_next, 261 key_next, 262 lhc + HAMMER2_DIRHASH_LOMASK, 263 &cache_index, 264 HAMMER2_LOOKUP_ALWAYS | 265 HAMMER2_LOOKUP_SHARED); 266 } 267 268 /* 269 * If the entry is a hardlink pointer, resolve it. 270 */ 271 error = 0; 272 if (chain) { 273 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) { 274 error = hammer2_chain_hardlink_find(&parent, &chain, 275 clindex, 276 HAMMER2_LOOKUP_SHARED); 277 } 278 } 279 done: 280 error = hammer2_xop_feed(&xop->head, chain, clindex, error); 281 if (chain) { 282 hammer2_chain_unlock(chain); 283 hammer2_chain_drop(chain); 284 } 285 if (parent) { 286 hammer2_chain_unlock(parent); 287 hammer2_chain_drop(parent); 288 } 289 } 290 291 /* 292 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper 293 * for hammer2_vop_nrename(). 294 * 295 * This function locates and removes a directory entry. If the entry is 296 * a hardlink pointer, this function does NOT remove the hardlink target, 297 * but will lookup and return the hardlink target. 298 * 299 * Note that any hardlink target's nlinks may not be synchronized to the 300 * in-memory inode. hammer2_inode_unlink_finisher() is responsible for the 301 * final disposition of the hardlink target. 302 * 303 * If an inode pointer we lookup and return the actual inode. If not, we 304 * return the deleted directory entry. 305 * 306 * The frontend is responsible for moving open inodes to the hidden directory 307 * and for decrementing nlinks. 308 */ 309 void 310 hammer2_xop_unlink(hammer2_xop_t *arg, int clindex) 311 { 312 hammer2_xop_unlink_t *xop = &arg->xop_unlink; 313 hammer2_chain_t *parent; 314 hammer2_chain_t *chain; 315 const hammer2_inode_data_t *ripdata; 316 const char *name; 317 size_t name_len; 318 hammer2_key_t key_next; 319 hammer2_key_t lhc; 320 int cache_index = -1; /* XXX */ 321 int error; 322 323 again: 324 /* 325 * Requires exclusive lock 326 */ 327 parent = hammer2_inode_chain(xop->head.ip1, clindex, 328 HAMMER2_RESOLVE_ALWAYS); 329 chain = NULL; 330 if (parent == NULL) { 331 kprintf("xop_nresolve: NULL parent\n"); 332 error = EIO; 333 goto done; 334 } 335 name = xop->head.name1; 336 name_len = xop->head.name1_len; 337 338 /* 339 * Lookup the directory entry 340 */ 341 lhc = hammer2_dirhash(name, name_len); 342 chain = hammer2_chain_lookup(&parent, &key_next, 343 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 344 &cache_index, 345 HAMMER2_LOOKUP_ALWAYS); 346 while (chain) { 347 ripdata = &chain->data->ipdata; 348 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 349 ripdata->meta.name_len == name_len && 350 bcmp(ripdata->filename, name, name_len) == 0) { 351 break; 352 } 353 chain = hammer2_chain_next(&parent, chain, &key_next, 354 key_next, 355 lhc + HAMMER2_DIRHASH_LOMASK, 356 &cache_index, 357 HAMMER2_LOOKUP_ALWAYS); 358 } 359 360 /* 361 * The directory entry will almost always be a hardlink pointer, 362 * which we permanently delete. Otherwise we go by xop->dopermanent. 363 * Note that the target chain's nlinks may not be synchronized with 364 * the in-memory hammer2_inode_t structure, so we don't try to do 365 * anything fancy here. 366 */ 367 error = 0; 368 if (chain) { 369 int dopermanent = xop->dopermanent; 370 uint8_t type; 371 372 /* 373 * If the directory entry is the actual inode then use its 374 * type for the directory typing tests, otherwise if it is 375 * a hardlink pointer then use the secondary type field for 376 * directory typing tests. 377 * 378 * Also, hardlink pointers are always permanently deleted 379 * (because they aren't the actual inode). 380 */ 381 type = chain->data->ipdata.meta.type; 382 if (type == HAMMER2_OBJTYPE_HARDLINK) { 383 type = chain->data->ipdata.meta.target_type; 384 dopermanent |= HAMMER2_DELETE_PERMANENT; 385 } 386 387 /* 388 * Check directory typing and delete the entry. Note that 389 * nlinks adjustments are made on the real inode by the 390 * frontend, not here. 391 * 392 * Unfortunately, checkdirempty() may have to unlock (parent). 393 * If it no longer matches chain->parent after re-locking, 394 * EAGAIN is returned. 395 */ 396 if (type == HAMMER2_OBJTYPE_DIRECTORY && 397 (error = checkdirempty(parent, chain, clindex)) != 0) { 398 /* error may be EAGAIN or ENOTEMPTY */ 399 if (error == EAGAIN) { 400 hammer2_chain_unlock(chain); 401 hammer2_chain_drop(chain); 402 hammer2_chain_unlock(parent); 403 hammer2_chain_drop(parent); 404 goto again; 405 } 406 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 407 xop->isdir == 0) { 408 error = ENOTDIR; 409 } else if (type != HAMMER2_OBJTYPE_DIRECTORY && 410 xop->isdir >= 1) { 411 error = EISDIR; 412 } else { 413 /* 414 * This deletes the directory entry itself, which is 415 * also the inode when nlinks == 1. Hardlink targets 416 * are handled in the next conditional. 417 */ 418 error = chain->error; 419 hammer2_chain_delete(parent, chain, 420 xop->head.mtid, dopermanent); 421 } 422 } 423 424 /* 425 * If the entry is a hardlink pointer, resolve it. We do not try 426 * to manipulate the contents of the hardlink target as it might 427 * not be synchronized with the front-end hammer2_inode_t. Nor do 428 * we try to lookup the front-end hammer2_inode_t here (we are the 429 * backend!). 430 */ 431 if (chain && 432 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) { 433 int error2; 434 435 lhc = chain->data->ipdata.meta.inum; 436 437 error2 = hammer2_chain_hardlink_find(&parent, &chain, 438 clindex, 0); 439 if (error2) { 440 kprintf("hardlink_find: %016jx %p failed\n", 441 lhc, chain); 442 error2 = 0; /* silently ignore */ 443 } 444 if (error == 0) 445 error = error2; 446 } 447 448 /* 449 * Return the inode target for further action. Typically used by 450 * hammer2_inode_unlink_finisher(). 451 */ 452 done: 453 hammer2_xop_feed(&xop->head, chain, clindex, error); 454 if (chain) { 455 hammer2_chain_unlock(chain); 456 hammer2_chain_drop(chain); 457 chain = NULL; 458 } 459 if (parent) { 460 hammer2_chain_unlock(parent); 461 hammer2_chain_drop(parent); 462 parent = NULL; 463 } 464 } 465 466 #if 0 467 /* 468 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename() 469 * 470 * ip1 - fdip 471 * ip2 - ip 472 * ip3 - cdip 473 * 474 * If a hardlink pointer: 475 * The existing hardlink target {fdip,ip} must be moved to another 476 * directory {cdip,ip} 477 * 478 * If not a hardlink pointer: 479 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and 480 * replace the original namespace {fdip,name} with a hardlink pointer. 481 */ 482 void 483 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex) 484 { 485 hammer2_xop_nlink_t *xop = &arg->xop_nlink; 486 hammer2_pfs_t *pmp; 487 hammer2_inode_data_t *wipdata; 488 hammer2_chain_t *parent; 489 hammer2_chain_t *chain; 490 hammer2_chain_t *tmp; 491 hammer2_inode_t *ip; 492 hammer2_key_t key_dummy; 493 int cache_index = -1; 494 int error; 495 int did_delete = 0; 496 497 /* 498 * We need the precise parent chain to issue the deletion. 499 */ 500 ip = xop->head.ip2; 501 pmp = ip->pmp; 502 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 503 if (parent) 504 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS); 505 if (parent == NULL) { 506 chain = NULL; 507 error = EIO; 508 goto done; 509 } 510 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 511 if (chain == NULL) { 512 error = EIO; 513 goto done; 514 } 515 KKASSERT(chain->parent == parent); 516 517 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) { 518 /* 519 * Delete the original chain and hold onto it for the move 520 * to cdir. 521 * 522 * Replace the namespace with a hardlink pointer if the 523 * chain being moved is not already a hardlink target. 524 */ 525 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 526 did_delete = 1; 527 528 tmp = NULL; 529 error = hammer2_chain_create(&parent, &tmp, 530 pmp, HAMMER2_METH_DEFAULT, 531 chain->bref.key, 0, 532 HAMMER2_BREF_TYPE_INODE, 533 HAMMER2_INODE_BYTES, 534 xop->head.mtid, 0, 0); 535 if (error) 536 goto done; 537 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0); 538 wipdata = &tmp->data->ipdata; 539 bzero(wipdata, sizeof(*wipdata)); 540 wipdata->meta.name_key = chain->data->ipdata.meta.name_key; 541 wipdata->meta.name_len = chain->data->ipdata.meta.name_len; 542 bcopy(chain->data->ipdata.filename, wipdata->filename, 543 chain->data->ipdata.meta.name_len); 544 wipdata->meta.target_type = chain->data->ipdata.meta.type; 545 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK; 546 wipdata->meta.inum = ip->meta.inum; 547 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE; 548 wipdata->meta.nlinks = 1; 549 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA; 550 551 hammer2_chain_unlock(tmp); 552 hammer2_chain_drop(tmp); 553 } else if (xop->head.ip1 != xop->head.ip3) { 554 /* 555 * Delete the hardlink target so it can be moved 556 * to cdir. 557 */ 558 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 559 did_delete = 1; 560 } else { 561 /* 562 * Deletion not necessary (just a nlinks update). 563 */ 564 did_delete = 0; 565 } 566 567 hammer2_chain_unlock(parent); 568 hammer2_chain_drop(parent); 569 parent = NULL; 570 571 /* 572 * Ok, back to the deleted chain. We must reconnect this chain 573 * as a hardlink target to cdir (ip3). 574 * 575 * WARNING! Frontend assumes filename length is 18 bytes. 576 */ 577 if (did_delete) { 578 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 579 wipdata = &chain->data->ipdata; 580 ksnprintf(wipdata->filename, sizeof(wipdata->filename), 581 "0x%016jx", (intmax_t)ip->meta.inum); 582 wipdata->meta.name_len = strlen(wipdata->filename); 583 wipdata->meta.name_key = ip->meta.inum; 584 585 /* 586 * We must seek parent properly for the create to reattach 587 * chain. XXX just use chain->parent or 588 * inode_chain_and_parent() ? 589 */ 590 parent = hammer2_inode_chain(xop->head.ip3, clindex, 591 HAMMER2_RESOLVE_ALWAYS); 592 if (parent == NULL) { 593 error = EIO; 594 goto done; 595 } 596 tmp = hammer2_chain_lookup(&parent, &key_dummy, 597 ip->meta.inum, ip->meta.inum, 598 &cache_index, 0); 599 if (tmp) { 600 hammer2_chain_unlock(tmp); 601 hammer2_chain_drop(tmp); 602 error = EEXIST; 603 goto done; 604 } 605 error = hammer2_chain_create(&parent, &chain, 606 pmp, HAMMER2_METH_DEFAULT, 607 wipdata->meta.name_key, 0, 608 HAMMER2_BREF_TYPE_INODE, 609 HAMMER2_INODE_BYTES, 610 xop->head.mtid, 0, 0); 611 } else { 612 error = 0; 613 } 614 615 /* 616 * Bump nlinks to synchronize with frontend. 617 */ 618 if (xop->nlinks_delta) { 619 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 620 chain->data->ipdata.meta.nlinks += xop->nlinks_delta; 621 } 622 623 /* 624 * To avoid having to scan the collision space we can simply 625 * reuse the inode's original name_key. But ip->meta.name_key 626 * may have already been updated by the front-end, so use xop->lhc. 627 */ 628 done: 629 hammer2_xop_feed(&xop->head, NULL, clindex, error); 630 if (parent) { 631 hammer2_chain_unlock(parent); 632 hammer2_chain_drop(parent); 633 } 634 if (chain) { 635 hammer2_chain_unlock(chain); 636 hammer2_chain_drop(chain); 637 } 638 } 639 #endif 640 641 /* 642 * Backend for hammer2_vop_nrename() 643 * 644 * This handles the final step of renaming, either renaming the 645 * actual inode or renaming the hardlink pointer. 646 */ 647 void 648 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex) 649 { 650 hammer2_xop_nrename_t *xop = &arg->xop_nrename; 651 hammer2_pfs_t *pmp; 652 hammer2_chain_t *parent; 653 hammer2_chain_t *chain; 654 hammer2_chain_t *tmp; 655 hammer2_inode_t *ip; 656 hammer2_key_t key_dummy; 657 int cache_index = -1; 658 int error; 659 660 /* 661 * We need the precise parent chain to issue the deletion. 662 * 663 * If this is not a hardlink target we can act on the inode, 664 * otherwise we have to locate the hardlink pointer. 665 */ 666 ip = xop->head.ip2; 667 pmp = ip->pmp; 668 chain = NULL; 669 670 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) { 671 /* 672 * Find ip's direct parent chain. 673 */ 674 parent = hammer2_inode_chain(ip, clindex, 675 HAMMER2_RESOLVE_ALWAYS); 676 if (parent) 677 hammer2_chain_getparent(&parent, 678 HAMMER2_RESOLVE_ALWAYS); 679 if (parent == NULL) { 680 error = EIO; 681 goto done; 682 } 683 chain = hammer2_inode_chain(ip, clindex, 684 HAMMER2_RESOLVE_ALWAYS); 685 if (chain == NULL) { 686 error = EIO; 687 goto done; 688 } 689 } else { 690 /* 691 * The hardlink pointer for the head.ip1 hardlink target 692 * is in fdip, do a namespace search. 693 */ 694 const hammer2_inode_data_t *ripdata; 695 hammer2_key_t lhc; 696 hammer2_key_t key_next; 697 const char *name; 698 size_t name_len; 699 700 parent = hammer2_inode_chain(xop->head.ip1, clindex, 701 HAMMER2_RESOLVE_ALWAYS); 702 if (parent == NULL) { 703 kprintf("xop_nrename: NULL parent\n"); 704 error = EIO; 705 goto done; 706 } 707 name = xop->head.name1; 708 name_len = xop->head.name1_len; 709 710 /* 711 * Lookup the directory entry 712 */ 713 lhc = hammer2_dirhash(name, name_len); 714 chain = hammer2_chain_lookup(&parent, &key_next, 715 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 716 &cache_index, 717 HAMMER2_LOOKUP_ALWAYS); 718 while (chain) { 719 ripdata = &chain->data->ipdata; 720 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 721 ripdata->meta.name_len == name_len && 722 bcmp(ripdata->filename, name, name_len) == 0) { 723 break; 724 } 725 chain = hammer2_chain_next(&parent, chain, &key_next, 726 key_next, 727 lhc + HAMMER2_DIRHASH_LOMASK, 728 &cache_index, 729 HAMMER2_LOOKUP_ALWAYS); 730 } 731 } 732 733 if (chain == NULL) { 734 /* XXX shouldn't happen, but does under fsstress */ 735 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n", 736 xop->head.name1, 737 xop->head.name2); 738 error = ENOENT; 739 goto done; 740 } 741 742 /* 743 * Delete it, then create it in the new namespace. 744 */ 745 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 746 hammer2_chain_unlock(parent); 747 hammer2_chain_drop(parent); 748 parent = NULL; /* safety */ 749 750 /* 751 * Ok, back to the deleted chain. We must reconnect this chain 752 * to tdir (ip3). The chain (a real inode or a hardlink pointer) 753 * is not otherwise modified. 754 * 755 * Frontend is expected to replicate the same inode meta data 756 * modifications. 757 * 758 * NOTE! This chain may not represent the actual inode, it 759 * can be a hardlink pointer. 760 * 761 * XXX in-inode parent directory specification? 762 */ 763 if (chain->data->ipdata.meta.name_key != xop->lhc || 764 xop->head.name1_len != xop->head.name2_len || 765 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) { 766 hammer2_inode_data_t *wipdata; 767 768 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 769 wipdata = &chain->data->ipdata; 770 771 bzero(wipdata->filename, sizeof(wipdata->filename)); 772 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len); 773 wipdata->meta.name_key = xop->lhc; 774 wipdata->meta.name_len = xop->head.name2_len; 775 } 776 if (chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) { 777 hammer2_inode_data_t *wipdata; 778 779 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 780 wipdata = &chain->data->ipdata; 781 782 wipdata->meta.iparent = xop->head.ip3->meta.inum; 783 } 784 785 /* 786 * We must seek parent properly for the create. 787 */ 788 parent = hammer2_inode_chain(xop->head.ip3, clindex, 789 HAMMER2_RESOLVE_ALWAYS); 790 if (parent == NULL) { 791 error = EIO; 792 goto done; 793 } 794 tmp = hammer2_chain_lookup(&parent, &key_dummy, 795 xop->lhc, xop->lhc, 796 &cache_index, 0); 797 if (tmp) { 798 hammer2_chain_unlock(tmp); 799 hammer2_chain_drop(tmp); 800 error = EEXIST; 801 goto done; 802 } 803 804 error = hammer2_chain_create(&parent, &chain, 805 pmp, HAMMER2_METH_DEFAULT, 806 xop->lhc, 0, 807 HAMMER2_BREF_TYPE_INODE, 808 HAMMER2_INODE_BYTES, 809 xop->head.mtid, 0, 0); 810 done: 811 hammer2_xop_feed(&xop->head, NULL, clindex, error); 812 if (parent) { 813 hammer2_chain_unlock(parent); 814 hammer2_chain_drop(parent); 815 } 816 if (chain) { 817 hammer2_chain_unlock(chain); 818 hammer2_chain_drop(chain); 819 } 820 } 821 822 /* 823 * Directory collision resolver scan helper (backend, threaded). 824 * 825 * Used by the inode create code to locate an unused lhc. 826 */ 827 void 828 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex) 829 { 830 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 831 hammer2_chain_t *parent; 832 hammer2_chain_t *chain; 833 hammer2_key_t key_next; 834 int cache_index = -1; /* XXX */ 835 int error = 0; 836 837 parent = hammer2_inode_chain(xop->head.ip1, clindex, 838 HAMMER2_RESOLVE_ALWAYS | 839 HAMMER2_RESOLVE_SHARED); 840 if (parent == NULL) { 841 kprintf("xop_nresolve: NULL parent\n"); 842 chain = NULL; 843 error = EIO; 844 goto done; 845 } 846 847 /* 848 * Lookup all possibly conflicting directory entries, the feed 849 * inherits the chain's lock so do not unlock it on the iteration. 850 */ 851 chain = hammer2_chain_lookup(&parent, &key_next, 852 xop->lhc, 853 xop->lhc + HAMMER2_DIRHASH_LOMASK, 854 &cache_index, 855 HAMMER2_LOOKUP_ALWAYS | 856 HAMMER2_LOOKUP_SHARED); 857 while (chain) { 858 error = hammer2_xop_feed(&xop->head, chain, clindex, 859 chain->error); 860 if (error) { 861 hammer2_chain_unlock(chain); 862 hammer2_chain_drop(chain); 863 chain = NULL; /* safety */ 864 break; 865 } 866 chain = hammer2_chain_next(&parent, chain, &key_next, 867 key_next, 868 xop->lhc + HAMMER2_DIRHASH_LOMASK, 869 &cache_index, 870 HAMMER2_LOOKUP_ALWAYS | 871 HAMMER2_LOOKUP_SHARED); 872 } 873 done: 874 hammer2_xop_feed(&xop->head, NULL, clindex, error); 875 if (parent) { 876 hammer2_chain_unlock(parent); 877 hammer2_chain_drop(parent); 878 } 879 } 880 881 /* 882 * Generic lookup of a specific key. 883 * 884 * Used by the inode hidden directory code to find the hidden directory. 885 */ 886 void 887 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex) 888 { 889 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 890 hammer2_chain_t *parent; 891 hammer2_chain_t *chain; 892 hammer2_key_t key_next; 893 int cache_index = -1; /* XXX */ 894 int error = 0; 895 896 parent = hammer2_inode_chain(xop->head.ip1, clindex, 897 HAMMER2_RESOLVE_ALWAYS | 898 HAMMER2_RESOLVE_SHARED); 899 chain = NULL; 900 if (parent == NULL) { 901 error = EIO; 902 goto done; 903 } 904 905 /* 906 * Lookup all possibly conflicting directory entries, the feed 907 * inherits the chain's lock so do not unlock it on the iteration. 908 */ 909 chain = hammer2_chain_lookup(&parent, &key_next, 910 xop->lhc, xop->lhc, 911 &cache_index, 912 HAMMER2_LOOKUP_ALWAYS | 913 HAMMER2_LOOKUP_SHARED); 914 if (chain) 915 hammer2_xop_feed(&xop->head, chain, clindex, chain->error); 916 else 917 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT); 918 919 done: 920 if (chain) { 921 hammer2_chain_unlock(chain); 922 hammer2_chain_drop(chain); 923 } 924 if (parent) { 925 hammer2_chain_unlock(parent); 926 hammer2_chain_drop(parent); 927 } 928 } 929 930 /* 931 * Generic scan 932 * 933 * WARNING! Fed chains must be locked shared so ownership can be transfered 934 * and to prevent frontend/backend stalls that would occur with an 935 * exclusive lock. The shared lock also allows chain->data to be 936 * retained. 937 */ 938 void 939 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex) 940 { 941 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 942 hammer2_chain_t *parent; 943 hammer2_chain_t *chain; 944 hammer2_key_t key_next; 945 int cache_index = -1; 946 int error = 0; 947 948 /* 949 * Assert required flags. 950 */ 951 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 952 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 953 954 /* 955 * The inode's chain is the iterator. If we cannot acquire it our 956 * contribution ends here. 957 */ 958 parent = hammer2_inode_chain(xop->head.ip1, clindex, 959 xop->resolve_flags); 960 if (parent == NULL) { 961 kprintf("xop_readdir: NULL parent\n"); 962 goto done; 963 } 964 965 /* 966 * Generic scan of exact records. Note that indirect blocks are 967 * automatically recursed and will not be returned. 968 */ 969 chain = hammer2_chain_lookup(&parent, &key_next, 970 xop->key_beg, xop->key_end, 971 &cache_index, xop->lookup_flags); 972 while (chain) { 973 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 974 if (error) 975 break; 976 chain = hammer2_chain_next(&parent, chain, &key_next, 977 key_next, xop->key_end, 978 &cache_index, xop->lookup_flags); 979 } 980 if (chain) { 981 hammer2_chain_unlock(chain); 982 hammer2_chain_drop(chain); 983 } 984 hammer2_chain_unlock(parent); 985 hammer2_chain_drop(parent); 986 done: 987 hammer2_xop_feed(&xop->head, NULL, clindex, error); 988 } 989