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 static 67 int 68 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex) 69 { 70 hammer2_chain_t *parent; 71 hammer2_chain_t *chain; 72 hammer2_key_t key_next; 73 hammer2_key_t inum; 74 int error; 75 76 error = 0; 77 chain = hammer2_chain_lookup_init(ochain, 0); 78 79 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 80 if (oparent) 81 hammer2_chain_unlock(oparent); 82 inum = chain->bref.embed.dirent.inum; 83 parent = NULL; 84 error = hammer2_chain_inode_find(chain->pmp, inum, 85 clindex, 0, 86 &parent, &chain); 87 if (parent) { 88 hammer2_chain_unlock(parent); 89 hammer2_chain_drop(parent); 90 } 91 if (oparent) { 92 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS); 93 if (ochain->parent != oparent) { 94 if (chain) { 95 hammer2_chain_unlock(chain); 96 hammer2_chain_drop(chain); 97 } 98 return HAMMER2_ERROR_EAGAIN; 99 } 100 } 101 } 102 103 /* 104 * Determine if the directory is empty or not by checking its 105 * visible namespace (the area which contains directory entries). 106 */ 107 parent = chain; 108 chain = NULL; 109 if (parent) { 110 chain = hammer2_chain_lookup(&parent, &key_next, 111 HAMMER2_DIRHASH_VISIBLE, 112 HAMMER2_KEY_MAX, 113 &error, 0); 114 } 115 if (chain) { 116 error = HAMMER2_ERROR_ENOTEMPTY; 117 hammer2_chain_unlock(chain); 118 hammer2_chain_drop(chain); 119 } 120 hammer2_chain_lookup_done(parent); 121 122 return error; 123 } 124 125 /* 126 * Backend for hammer2_vfs_root() 127 * 128 * This is called when a newly mounted PFS has not yet synchronized 129 * to the inode_tid and modify_tid. 130 */ 131 void 132 hammer2_xop_ipcluster(hammer2_thread_t *thr, hammer2_xop_t *arg) 133 { 134 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster; 135 hammer2_chain_t *chain; 136 int error; 137 138 chain = hammer2_inode_chain(xop->head.ip1, thr->clindex, 139 HAMMER2_RESOLVE_ALWAYS | 140 HAMMER2_RESOLVE_SHARED); 141 if (chain) 142 error = chain->error; 143 else 144 error = HAMMER2_ERROR_EIO; 145 146 hammer2_xop_feed(&xop->head, chain, thr->clindex, error); 147 if (chain) { 148 hammer2_chain_unlock(chain); 149 hammer2_chain_drop(chain); 150 } 151 } 152 153 /* 154 * Backend for hammer2_vop_readdir() 155 */ 156 void 157 hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg) 158 { 159 hammer2_xop_readdir_t *xop = &arg->xop_readdir; 160 hammer2_chain_t *parent; 161 hammer2_chain_t *chain; 162 hammer2_key_t key_next; 163 hammer2_key_t lkey; 164 int error = 0; 165 166 lkey = xop->lkey; 167 if (hammer2_debug & 0x0020) 168 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey); 169 170 /* 171 * The inode's chain is the iterator. If we cannot acquire it our 172 * contribution ends here. 173 */ 174 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 175 HAMMER2_RESOLVE_ALWAYS | 176 HAMMER2_RESOLVE_SHARED); 177 if (parent == NULL) { 178 kprintf("xop_readdir: NULL parent\n"); 179 goto done; 180 } 181 182 /* 183 * Directory scan [re]start and loop, the feed inherits the chain's 184 * lock so do not unlock it on the iteration. 185 */ 186 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey, 187 &error, HAMMER2_LOOKUP_SHARED); 188 if (chain == NULL) { 189 chain = hammer2_chain_lookup(&parent, &key_next, 190 lkey, HAMMER2_KEY_MAX, 191 &error, HAMMER2_LOOKUP_SHARED); 192 } 193 while (chain) { 194 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0); 195 if (error) 196 goto break2; 197 chain = hammer2_chain_next(&parent, chain, &key_next, 198 key_next, HAMMER2_KEY_MAX, 199 &error, HAMMER2_LOOKUP_SHARED); 200 } 201 break2: 202 if (chain) { 203 hammer2_chain_unlock(chain); 204 hammer2_chain_drop(chain); 205 } 206 hammer2_chain_unlock(parent); 207 hammer2_chain_drop(parent); 208 done: 209 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 210 } 211 212 /* 213 * Backend for hammer2_vop_nresolve() 214 */ 215 void 216 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg) 217 { 218 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve; 219 hammer2_chain_t *parent; 220 hammer2_chain_t *chain; 221 const char *name; 222 size_t name_len; 223 hammer2_key_t key_next; 224 hammer2_key_t lhc; 225 int error; 226 227 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 228 HAMMER2_RESOLVE_ALWAYS | 229 HAMMER2_RESOLVE_SHARED); 230 if (parent == NULL) { 231 kprintf("xop_nresolve: NULL parent\n"); 232 chain = NULL; 233 error = HAMMER2_ERROR_EIO; 234 goto done; 235 } 236 name = xop->head.name1; 237 name_len = xop->head.name1_len; 238 239 /* 240 * Lookup the directory entry 241 */ 242 lhc = hammer2_dirhash(name, name_len); 243 chain = hammer2_chain_lookup(&parent, &key_next, 244 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 245 &error, 246 HAMMER2_LOOKUP_ALWAYS | 247 HAMMER2_LOOKUP_SHARED); 248 while (chain) { 249 if (hammer2_chain_dirent_test(chain, name, name_len)) 250 break; 251 chain = hammer2_chain_next(&parent, chain, &key_next, 252 key_next, 253 lhc + HAMMER2_DIRHASH_LOMASK, 254 &error, 255 HAMMER2_LOOKUP_ALWAYS | 256 HAMMER2_LOOKUP_SHARED); 257 } 258 259 /* 260 * If the entry is a hardlink pointer, resolve it. 261 */ 262 if (chain && chain->error == 0) { 263 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 264 lhc = chain->bref.embed.dirent.inum; 265 error = hammer2_chain_inode_find(chain->pmp, 266 lhc, 267 thr->clindex, 268 HAMMER2_LOOKUP_SHARED, 269 &parent, 270 &chain); 271 } 272 } else if (chain && error == 0) { 273 error = chain->error; 274 } 275 done: 276 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error); 277 if (chain) { 278 hammer2_chain_unlock(chain); 279 hammer2_chain_drop(chain); 280 } 281 if (parent) { 282 hammer2_chain_unlock(parent); 283 hammer2_chain_drop(parent); 284 } 285 } 286 287 /* 288 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and 289 * backend for pfs_delete. 290 * 291 * This function locates and removes a directory entry, and will lookup 292 * and return the underlying inode. For directory entries the underlying 293 * inode is not removed. If the directory entry is the actual inode itself, 294 * it may be conditonally removed and returned. 295 * 296 * WARNING! Any target inode's nlinks may not be synchronized to the 297 * in-memory inode. The frontend's hammer2_inode_unlink_finisher() 298 * is responsible for the final disposition of the actual inode. 299 */ 300 void 301 hammer2_xop_unlink(hammer2_thread_t *thr, hammer2_xop_t *arg) 302 { 303 hammer2_xop_unlink_t *xop = &arg->xop_unlink; 304 hammer2_chain_t *parent; 305 hammer2_chain_t *chain; 306 const char *name; 307 size_t name_len; 308 hammer2_key_t key_next; 309 hammer2_key_t lhc; 310 int error; 311 312 again: 313 /* 314 * Requires exclusive lock 315 */ 316 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 317 HAMMER2_RESOLVE_ALWAYS); 318 chain = NULL; 319 if (parent == NULL) { 320 kprintf("xop_nresolve: NULL parent\n"); 321 error = HAMMER2_ERROR_EIO; 322 goto done; 323 } 324 name = xop->head.name1; 325 name_len = xop->head.name1_len; 326 327 /* 328 * Lookup the directory entry 329 */ 330 lhc = hammer2_dirhash(name, name_len); 331 chain = hammer2_chain_lookup(&parent, &key_next, 332 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 333 &error, HAMMER2_LOOKUP_ALWAYS); 334 while (chain) { 335 if (hammer2_chain_dirent_test(chain, name, name_len)) 336 break; 337 chain = hammer2_chain_next(&parent, chain, &key_next, 338 key_next, 339 lhc + HAMMER2_DIRHASH_LOMASK, 340 &error, HAMMER2_LOOKUP_ALWAYS); 341 } 342 343 /* 344 * The directory entry will either be a BREF_TYPE_DIRENT or a 345 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but 346 * must go by xop->dopermanent for BREF_TYPE_INODE. 347 * 348 * Note that the target chain's nlinks may not be synchronized with 349 * the in-memory hammer2_inode_t structure, so we don't try to do 350 * anything fancy here. The frontend deals with nlinks 351 * synchronization. 352 */ 353 if (chain && chain->error == 0) { 354 int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT; 355 int doforce = xop->dopermanent & H2DOPERM_FORCE; 356 uint8_t type; 357 358 /* 359 * If the directory entry is the actual inode then use its 360 * type for the directory typing tests, otherwise if it is 361 * a directory entry, pull the type field from the entry. 362 * 363 * Directory entries are always permanently deleted 364 * (because they aren't the actual inode). 365 */ 366 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 367 type = chain->bref.embed.dirent.type; 368 dopermanent |= HAMMER2_DELETE_PERMANENT; 369 } else { 370 type = chain->data->ipdata.meta.type; 371 } 372 373 /* 374 * Check directory typing and delete the entry. Note that 375 * nlinks adjustments are made on the real inode by the 376 * frontend, not here. 377 * 378 * Unfortunately, checkdirempty() may have to unlock (parent). 379 * If it no longer matches chain->parent after re-locking, 380 * EAGAIN is returned. 381 */ 382 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) { 383 /* 384 * If doforce then execute the operation even if 385 * the directory is not empty or errored. 386 */ 387 /* ignore chain->error */ 388 error = hammer2_chain_delete(parent, chain, 389 xop->head.mtid, dopermanent); 390 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 391 (error = checkdirempty(parent, chain, thr->clindex)) != 0) { 392 /* 393 * error may be EAGAIN or ENOTEMPTY 394 */ 395 if (error == HAMMER2_ERROR_EAGAIN) { 396 hammer2_chain_unlock(chain); 397 hammer2_chain_drop(chain); 398 hammer2_chain_unlock(parent); 399 hammer2_chain_drop(parent); 400 goto again; 401 } 402 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 403 xop->isdir == 0) { 404 error = HAMMER2_ERROR_ENOTDIR; 405 } else if (type != HAMMER2_OBJTYPE_DIRECTORY && 406 xop->isdir >= 1) { 407 error = HAMMER2_ERROR_EISDIR; 408 } else { 409 /* 410 * Delete the directory entry. chain might also 411 * be a directly-embedded inode. 412 */ 413 error = chain->error; 414 hammer2_chain_delete(parent, chain, 415 xop->head.mtid, dopermanent); 416 } 417 } else { 418 if (chain && error == 0) 419 error = chain->error; 420 } 421 422 /* 423 * If chain is a directory entry we must resolve it. We do not try 424 * to manipulate the contents as it might not be synchronized with 425 * the frontend hammer2_inode_t, nor do we try to lookup the 426 * frontend hammer2_inode_t here (we are the backend!). 427 */ 428 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT && 429 (xop->dopermanent & H2DOPERM_IGNINO) == 0) { 430 int error2; 431 432 lhc = chain->bref.embed.dirent.inum; 433 434 error2 = hammer2_chain_inode_find(chain->pmp, lhc, 435 thr->clindex, 0, 436 &parent, &chain); 437 if (error2) { 438 kprintf("inode_find: %016jx %p failed\n", 439 lhc, chain); 440 error2 = 0; /* silently ignore */ 441 } 442 if (error == 0) 443 error = error2; 444 } 445 446 /* 447 * Return the inode target for further action. Typically used by 448 * hammer2_inode_unlink_finisher(). 449 */ 450 done: 451 hammer2_xop_feed(&xop->head, chain, thr->clindex, error); 452 if (chain) { 453 hammer2_chain_unlock(chain); 454 hammer2_chain_drop(chain); 455 chain = NULL; 456 } 457 if (parent) { 458 hammer2_chain_unlock(parent); 459 hammer2_chain_drop(parent); 460 parent = NULL; 461 } 462 } 463 464 /* 465 * Backend for hammer2_vop_nrename() 466 * 467 * This handles the backend rename operation. Typically this renames 468 * directory entries but can also be used to rename embedded inodes. 469 * 470 * NOTE! The frontend is responsible for updating the inode meta-data in 471 * the file being renamed and for decrementing the target-replaced 472 * inode's nlinks, if present. 473 */ 474 void 475 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg) 476 { 477 hammer2_xop_nrename_t *xop = &arg->xop_nrename; 478 hammer2_pfs_t *pmp; 479 hammer2_chain_t *parent; 480 hammer2_chain_t *chain; 481 hammer2_chain_t *tmp; 482 hammer2_inode_t *ip; 483 hammer2_key_t key_next; 484 int error; 485 486 /* 487 * We need the precise parent chain to issue the deletion. 488 * 489 * If this is a directory entry we must locate the underlying 490 * inode. If it is an embedded inode we can act directly on it. 491 */ 492 ip = xop->head.ip2; 493 pmp = ip->pmp; 494 chain = NULL; 495 error = 0; 496 497 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) { 498 /* 499 * Find ip's direct parent chain. 500 */ 501 chain = hammer2_inode_chain(ip, thr->clindex, 502 HAMMER2_RESOLVE_ALWAYS); 503 if (chain == NULL) { 504 error = HAMMER2_ERROR_EIO; 505 parent = NULL; 506 goto done; 507 } 508 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS); 509 if (parent == NULL) { 510 error = HAMMER2_ERROR_EIO; 511 goto done; 512 } 513 } else { 514 /* 515 * The directory entry for the head.ip1 inode 516 * is in fdip, do a namespace search. 517 */ 518 hammer2_key_t lhc; 519 const char *name; 520 size_t name_len; 521 522 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 523 HAMMER2_RESOLVE_ALWAYS); 524 if (parent == NULL) { 525 kprintf("xop_nrename: NULL parent\n"); 526 error = HAMMER2_ERROR_EIO; 527 goto done; 528 } 529 name = xop->head.name1; 530 name_len = xop->head.name1_len; 531 532 /* 533 * Lookup the directory entry 534 */ 535 lhc = hammer2_dirhash(name, name_len); 536 chain = hammer2_chain_lookup(&parent, &key_next, 537 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 538 &error, HAMMER2_LOOKUP_ALWAYS); 539 while (chain) { 540 if (hammer2_chain_dirent_test(chain, name, name_len)) 541 break; 542 chain = hammer2_chain_next(&parent, chain, &key_next, 543 key_next, 544 lhc + HAMMER2_DIRHASH_LOMASK, 545 &error, 546 HAMMER2_LOOKUP_ALWAYS); 547 } 548 } 549 550 if (chain == NULL) { 551 /* XXX shouldn't happen, but does under fsstress */ 552 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n", 553 xop->head.name1, 554 xop->head.name2); 555 if (error == 0) 556 error = HAMMER2_ERROR_ENOENT; 557 goto done; 558 } 559 560 if (chain->error) { 561 error = chain->error; 562 goto done; 563 } 564 565 /* 566 * Delete it, then create it in the new namespace. 567 */ 568 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 569 hammer2_chain_unlock(parent); 570 hammer2_chain_drop(parent); 571 parent = NULL; /* safety */ 572 573 /* 574 * Adjust fields in the deleted chain appropriate for the rename 575 * operation. 576 * 577 * NOTE! For embedded inodes, the frontend will officially replicate 578 * the field adjustments, but we also do it here to maintain 579 * consistency in case of a crash. 580 */ 581 if (chain->bref.key != xop->lhc || 582 xop->head.name1_len != xop->head.name2_len || 583 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) { 584 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { 585 hammer2_inode_data_t *wipdata; 586 587 error = hammer2_chain_modify(chain, xop->head.mtid, 588 0, 0); 589 if (error == 0) { 590 wipdata = &chain->data->ipdata; 591 592 bzero(wipdata->filename, 593 sizeof(wipdata->filename)); 594 bcopy(xop->head.name2, 595 wipdata->filename, 596 xop->head.name2_len); 597 wipdata->meta.name_key = xop->lhc; 598 wipdata->meta.name_len = xop->head.name2_len; 599 } 600 } 601 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 602 if (xop->head.name2_len <= 603 sizeof(chain->bref.check.buf)) { 604 /* 605 * Remove any related data buffer, we can 606 * embed the filename in the bref itself. 607 */ 608 error = hammer2_chain_resize( 609 chain, xop->head.mtid, 0, 0, 0); 610 if (error == 0) { 611 error = hammer2_chain_modify( 612 chain, xop->head.mtid, 613 0, 0); 614 } 615 if (error == 0) { 616 bzero(chain->bref.check.buf, 617 sizeof(chain->bref.check.buf)); 618 bcopy(xop->head.name2, 619 chain->bref.check.buf, 620 xop->head.name2_len); 621 } 622 } else { 623 /* 624 * Associate a data buffer with the bref. 625 * Zero it for consistency. Note that the 626 * data buffer is not 64KB so use chain->bytes 627 * instead of sizeof(). 628 */ 629 error = hammer2_chain_resize( 630 chain, xop->head.mtid, 0, 631 hammer2_getradix(HAMMER2_ALLOC_MIN), 0); 632 if (error == 0) { 633 error = hammer2_chain_modify( 634 chain, xop->head.mtid, 635 0, 0); 636 } 637 if (error == 0) { 638 bzero(chain->data->buf, chain->bytes); 639 bcopy(xop->head.name2, 640 chain->data->buf, 641 xop->head.name2_len); 642 } 643 } 644 if (error == 0) { 645 chain->bref.embed.dirent.namlen = 646 xop->head.name2_len; 647 } 648 } 649 } 650 651 /* 652 * The frontend will replicate this operation and is the real final 653 * authority, but adjust the inode's iparent field too if the inode 654 * is embedded in the directory. 655 */ 656 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 657 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) { 658 hammer2_inode_data_t *wipdata; 659 660 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 661 if (error == 0) { 662 wipdata = &chain->data->ipdata; 663 wipdata->meta.iparent = xop->head.ip3->meta.inum; 664 } 665 } 666 667 /* 668 * Destroy any matching target(s) before creating the new entry. 669 * This will result in some ping-ponging of the directory key 670 * iterator but that is ok. 671 */ 672 parent = hammer2_inode_chain(xop->head.ip3, thr->clindex, 673 HAMMER2_RESOLVE_ALWAYS); 674 if (parent == NULL) { 675 error = HAMMER2_ERROR_EIO; 676 goto done; 677 } 678 679 if (error == 0) { 680 tmp = hammer2_chain_lookup(&parent, &key_next, 681 xop->lhc & ~HAMMER2_DIRHASH_LOMASK, 682 xop->lhc | HAMMER2_DIRHASH_LOMASK, 683 &error, 684 HAMMER2_LOOKUP_ALWAYS); 685 while (tmp) { 686 if (hammer2_chain_dirent_test(tmp, xop->head.name2, 687 xop->head.name2_len)) { 688 hammer2_chain_delete(parent, tmp, 689 xop->head.mtid, 0); 690 } 691 tmp = hammer2_chain_next(&parent, tmp, &key_next, 692 key_next, 693 xop->lhc | 694 HAMMER2_DIRHASH_LOMASK, 695 &error, 696 HAMMER2_LOOKUP_ALWAYS); 697 } 698 } 699 if (error == 0) { 700 /* 701 * A relookup is required before the create to properly 702 * position the parent chain. 703 */ 704 tmp = hammer2_chain_lookup(&parent, &key_next, 705 xop->lhc, xop->lhc, 706 &error, 0); 707 KKASSERT(tmp == NULL); 708 error = hammer2_chain_create(&parent, &chain, 709 pmp, HAMMER2_METH_DEFAULT, 710 xop->lhc, 0, 711 HAMMER2_BREF_TYPE_INODE, 712 HAMMER2_INODE_BYTES, 713 xop->head.mtid, 0, 0); 714 } 715 done: 716 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 717 if (parent) { 718 hammer2_chain_unlock(parent); 719 hammer2_chain_drop(parent); 720 } 721 if (chain) { 722 hammer2_chain_unlock(chain); 723 hammer2_chain_drop(chain); 724 } 725 } 726 727 /* 728 * Directory collision resolver scan helper (backend, threaded). 729 * 730 * Used by the inode create code to locate an unused lhc. 731 */ 732 void 733 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg) 734 { 735 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 736 hammer2_chain_t *parent; 737 hammer2_chain_t *chain; 738 hammer2_key_t key_next; 739 int error = 0; 740 741 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 742 HAMMER2_RESOLVE_ALWAYS | 743 HAMMER2_RESOLVE_SHARED); 744 if (parent == NULL) { 745 kprintf("xop_nresolve: NULL parent\n"); 746 chain = NULL; 747 error = HAMMER2_ERROR_EIO; 748 goto done; 749 } 750 751 /* 752 * Lookup all possibly conflicting directory entries, the feed 753 * inherits the chain's lock so do not unlock it on the iteration. 754 */ 755 chain = hammer2_chain_lookup(&parent, &key_next, 756 xop->lhc, 757 xop->lhc + HAMMER2_DIRHASH_LOMASK, 758 &error, 759 HAMMER2_LOOKUP_ALWAYS | 760 HAMMER2_LOOKUP_SHARED); 761 while (chain) { 762 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0); 763 if (error) { 764 hammer2_chain_unlock(chain); 765 hammer2_chain_drop(chain); 766 chain = NULL; /* safety */ 767 goto done; 768 } 769 chain = hammer2_chain_next(&parent, chain, &key_next, 770 key_next, 771 xop->lhc + HAMMER2_DIRHASH_LOMASK, 772 &error, 773 HAMMER2_LOOKUP_ALWAYS | 774 HAMMER2_LOOKUP_SHARED); 775 } 776 done: 777 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 778 if (parent) { 779 hammer2_chain_unlock(parent); 780 hammer2_chain_drop(parent); 781 } 782 } 783 784 /* 785 * Generic lookup of a specific key. 786 * 787 * Used by the inode hidden directory code to find the hidden directory. 788 */ 789 void 790 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg) 791 { 792 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 793 hammer2_chain_t *parent; 794 hammer2_chain_t *chain; 795 hammer2_key_t key_next; 796 int error = 0; 797 798 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 799 HAMMER2_RESOLVE_ALWAYS | 800 HAMMER2_RESOLVE_SHARED); 801 chain = NULL; 802 if (parent == NULL) { 803 error = HAMMER2_ERROR_EIO; 804 goto done; 805 } 806 807 /* 808 * Lookup all possibly conflicting directory entries, the feed 809 * inherits the chain's lock so do not unlock it on the iteration. 810 */ 811 chain = hammer2_chain_lookup(&parent, &key_next, 812 xop->lhc, xop->lhc, 813 &error, 814 HAMMER2_LOOKUP_ALWAYS | 815 HAMMER2_LOOKUP_SHARED); 816 if (error == 0) { 817 if (chain) 818 error = chain->error; 819 else 820 error = HAMMER2_ERROR_ENOENT; 821 } 822 hammer2_xop_feed(&xop->head, chain, thr->clindex, error); 823 824 done: 825 if (chain) { 826 hammer2_chain_unlock(chain); 827 hammer2_chain_drop(chain); 828 } 829 if (parent) { 830 hammer2_chain_unlock(parent); 831 hammer2_chain_drop(parent); 832 } 833 } 834 835 /* 836 * Generic scan 837 * 838 * WARNING! Fed chains must be locked shared so ownership can be transfered 839 * and to prevent frontend/backend stalls that would occur with an 840 * exclusive lock. The shared lock also allows chain->data to be 841 * retained. 842 */ 843 void 844 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg) 845 { 846 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 847 hammer2_chain_t *parent; 848 hammer2_chain_t *chain; 849 hammer2_key_t key_next; 850 int error = 0; 851 852 /* 853 * Assert required flags. 854 */ 855 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 856 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 857 858 /* 859 * The inode's chain is the iterator. If we cannot acquire it our 860 * contribution ends here. 861 */ 862 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 863 xop->resolve_flags); 864 if (parent == NULL) { 865 kprintf("xop_readdir: NULL parent\n"); 866 goto done; 867 } 868 869 /* 870 * Generic scan of exact records. Note that indirect blocks are 871 * automatically recursed and will not be returned. 872 */ 873 chain = hammer2_chain_lookup(&parent, &key_next, 874 xop->key_beg, xop->key_end, 875 &error, xop->lookup_flags); 876 while (chain) { 877 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0); 878 if (error) 879 goto break2; 880 chain = hammer2_chain_next(&parent, chain, &key_next, 881 key_next, xop->key_end, 882 &error, xop->lookup_flags); 883 } 884 break2: 885 if (chain) { 886 hammer2_chain_unlock(chain); 887 hammer2_chain_drop(chain); 888 } 889 hammer2_chain_unlock(parent); 890 hammer2_chain_drop(parent); 891 done: 892 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 893 } 894