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. We 386 * ignore chain->error here, allowing an errored 387 * chain (aka directory entry) to still be deleted. 388 */ 389 error = hammer2_chain_delete(parent, chain, 390 xop->head.mtid, dopermanent); 391 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 392 (error = checkdirempty(parent, chain, thr->clindex)) != 0) { 393 /* 394 * error may be EAGAIN or ENOTEMPTY 395 */ 396 if (error == HAMMER2_ERROR_EAGAIN) { 397 hammer2_chain_unlock(chain); 398 hammer2_chain_drop(chain); 399 hammer2_chain_unlock(parent); 400 hammer2_chain_drop(parent); 401 goto again; 402 } 403 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 404 xop->isdir == 0) { 405 error = HAMMER2_ERROR_ENOTDIR; 406 } else if (type != HAMMER2_OBJTYPE_DIRECTORY && 407 xop->isdir >= 1) { 408 error = HAMMER2_ERROR_EISDIR; 409 } else { 410 /* 411 * Delete the directory entry. chain might also 412 * be a directly-embedded inode. 413 * 414 * Allow the deletion to proceed even if the chain 415 * is errored. Give priority to error-on-delete over 416 * chain->error. 417 */ 418 error = hammer2_chain_delete(parent, chain, 419 xop->head.mtid, 420 dopermanent); 421 if (error == 0) 422 error = chain->error; 423 } 424 } else { 425 if (chain && error == 0) 426 error = chain->error; 427 } 428 429 /* 430 * If chain is a directory entry we must resolve it. We do not try 431 * to manipulate the contents as it might not be synchronized with 432 * the frontend hammer2_inode_t, nor do we try to lookup the 433 * frontend hammer2_inode_t here (we are the backend!). 434 */ 435 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT && 436 (xop->dopermanent & H2DOPERM_IGNINO) == 0) { 437 int error2; 438 439 lhc = chain->bref.embed.dirent.inum; 440 441 error2 = hammer2_chain_inode_find(chain->pmp, lhc, 442 thr->clindex, 0, 443 &parent, &chain); 444 if (error2) { 445 kprintf("inode_find: %016jx %p failed\n", 446 lhc, chain); 447 error2 = 0; /* silently ignore */ 448 } 449 if (error == 0) 450 error = error2; 451 } 452 453 /* 454 * Return the inode target for further action. Typically used by 455 * hammer2_inode_unlink_finisher(). 456 */ 457 done: 458 hammer2_xop_feed(&xop->head, chain, thr->clindex, error); 459 if (chain) { 460 hammer2_chain_unlock(chain); 461 hammer2_chain_drop(chain); 462 chain = NULL; 463 } 464 if (parent) { 465 hammer2_chain_unlock(parent); 466 hammer2_chain_drop(parent); 467 parent = NULL; 468 } 469 } 470 471 /* 472 * Backend for hammer2_vop_nrename() 473 * 474 * This handles the backend rename operation. Typically this renames 475 * directory entries but can also be used to rename embedded inodes. 476 * 477 * NOTE! The frontend is responsible for updating the inode meta-data in 478 * the file being renamed and for decrementing the target-replaced 479 * inode's nlinks, if present. 480 */ 481 void 482 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg) 483 { 484 hammer2_xop_nrename_t *xop = &arg->xop_nrename; 485 hammer2_pfs_t *pmp; 486 hammer2_chain_t *parent; 487 hammer2_chain_t *chain; 488 hammer2_chain_t *tmp; 489 hammer2_inode_t *ip; 490 hammer2_key_t key_next; 491 int error; 492 493 /* 494 * We need the precise parent chain to issue the deletion. 495 * 496 * If this is a directory entry we must locate the underlying 497 * inode. If it is an embedded inode we can act directly on it. 498 */ 499 ip = xop->head.ip2; 500 pmp = ip->pmp; 501 chain = NULL; 502 error = 0; 503 504 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) { 505 /* 506 * Find ip's direct parent chain. 507 */ 508 chain = hammer2_inode_chain(ip, thr->clindex, 509 HAMMER2_RESOLVE_ALWAYS); 510 if (chain == NULL) { 511 error = HAMMER2_ERROR_EIO; 512 parent = NULL; 513 goto done; 514 } 515 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS); 516 if (parent == NULL) { 517 error = HAMMER2_ERROR_EIO; 518 goto done; 519 } 520 } else { 521 /* 522 * The directory entry for the head.ip1 inode 523 * is in fdip, do a namespace search. 524 */ 525 hammer2_key_t lhc; 526 const char *name; 527 size_t name_len; 528 529 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 530 HAMMER2_RESOLVE_ALWAYS); 531 if (parent == NULL) { 532 kprintf("xop_nrename: NULL parent\n"); 533 error = HAMMER2_ERROR_EIO; 534 goto done; 535 } 536 name = xop->head.name1; 537 name_len = xop->head.name1_len; 538 539 /* 540 * Lookup the directory entry 541 */ 542 lhc = hammer2_dirhash(name, name_len); 543 chain = hammer2_chain_lookup(&parent, &key_next, 544 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 545 &error, HAMMER2_LOOKUP_ALWAYS); 546 while (chain) { 547 if (hammer2_chain_dirent_test(chain, name, name_len)) 548 break; 549 chain = hammer2_chain_next(&parent, chain, &key_next, 550 key_next, 551 lhc + HAMMER2_DIRHASH_LOMASK, 552 &error, 553 HAMMER2_LOOKUP_ALWAYS); 554 } 555 } 556 557 if (chain == NULL) { 558 /* XXX shouldn't happen, but does under fsstress */ 559 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n", 560 xop->head.name1, 561 xop->head.name2); 562 if (error == 0) 563 error = HAMMER2_ERROR_ENOENT; 564 goto done; 565 } 566 567 if (chain->error) { 568 error = chain->error; 569 goto done; 570 } 571 572 /* 573 * Delete it, then create it in the new namespace. 574 * 575 * An error can occur if the chain being deleted requires 576 * modification and the media is full. 577 */ 578 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 579 hammer2_chain_unlock(parent); 580 hammer2_chain_drop(parent); 581 parent = NULL; /* safety */ 582 if (error) 583 goto done; 584 585 /* 586 * Adjust fields in the deleted chain appropriate for the rename 587 * operation. 588 * 589 * NOTE! For embedded inodes, the frontend will officially replicate 590 * the field adjustments, but we also do it here to maintain 591 * consistency in case of a crash. 592 */ 593 if (chain->bref.key != xop->lhc || 594 xop->head.name1_len != xop->head.name2_len || 595 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) { 596 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { 597 hammer2_inode_data_t *wipdata; 598 599 error = hammer2_chain_modify(chain, xop->head.mtid, 600 0, 0); 601 if (error == 0) { 602 wipdata = &chain->data->ipdata; 603 604 bzero(wipdata->filename, 605 sizeof(wipdata->filename)); 606 bcopy(xop->head.name2, 607 wipdata->filename, 608 xop->head.name2_len); 609 wipdata->meta.name_key = xop->lhc; 610 wipdata->meta.name_len = xop->head.name2_len; 611 } 612 } 613 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 614 if (xop->head.name2_len <= 615 sizeof(chain->bref.check.buf)) { 616 /* 617 * Remove any related data buffer, we can 618 * embed the filename in the bref itself. 619 */ 620 error = hammer2_chain_resize( 621 chain, xop->head.mtid, 0, 0, 0); 622 if (error == 0) { 623 error = hammer2_chain_modify( 624 chain, xop->head.mtid, 625 0, 0); 626 } 627 if (error == 0) { 628 bzero(chain->bref.check.buf, 629 sizeof(chain->bref.check.buf)); 630 bcopy(xop->head.name2, 631 chain->bref.check.buf, 632 xop->head.name2_len); 633 } 634 } else { 635 /* 636 * Associate a data buffer with the bref. 637 * Zero it for consistency. Note that the 638 * data buffer is not 64KB so use chain->bytes 639 * instead of sizeof(). 640 */ 641 error = hammer2_chain_resize( 642 chain, xop->head.mtid, 0, 643 hammer2_getradix(HAMMER2_ALLOC_MIN), 0); 644 if (error == 0) { 645 error = hammer2_chain_modify( 646 chain, xop->head.mtid, 647 0, 0); 648 } 649 if (error == 0) { 650 bzero(chain->data->buf, chain->bytes); 651 bcopy(xop->head.name2, 652 chain->data->buf, 653 xop->head.name2_len); 654 } 655 } 656 if (error == 0) { 657 chain->bref.embed.dirent.namlen = 658 xop->head.name2_len; 659 } 660 } 661 } 662 663 /* 664 * The frontend will replicate this operation and is the real final 665 * authority, but adjust the inode's iparent field too if the inode 666 * is embedded in the directory. 667 */ 668 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 669 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) { 670 hammer2_inode_data_t *wipdata; 671 672 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 673 if (error == 0) { 674 wipdata = &chain->data->ipdata; 675 wipdata->meta.iparent = xop->head.ip3->meta.inum; 676 } 677 } 678 679 /* 680 * Destroy any matching target(s) before creating the new entry. 681 * This will result in some ping-ponging of the directory key 682 * iterator but that is ok. 683 */ 684 parent = hammer2_inode_chain(xop->head.ip3, thr->clindex, 685 HAMMER2_RESOLVE_ALWAYS); 686 if (parent == NULL) { 687 error = HAMMER2_ERROR_EIO; 688 goto done; 689 } 690 691 /* 692 * Delete all matching directory entries. That is, get rid of 693 * multiple duplicates if present, as a self-healing mechanism. 694 */ 695 if (error == 0) { 696 tmp = hammer2_chain_lookup(&parent, &key_next, 697 xop->lhc & ~HAMMER2_DIRHASH_LOMASK, 698 xop->lhc | HAMMER2_DIRHASH_LOMASK, 699 &error, 700 HAMMER2_LOOKUP_ALWAYS); 701 while (tmp) { 702 int e2; 703 if (hammer2_chain_dirent_test(tmp, xop->head.name2, 704 xop->head.name2_len)) { 705 e2 = hammer2_chain_delete(parent, tmp, 706 xop->head.mtid, 0); 707 if (error == 0 && e2) 708 error = e2; 709 } 710 tmp = hammer2_chain_next(&parent, tmp, &key_next, 711 key_next, 712 xop->lhc | 713 HAMMER2_DIRHASH_LOMASK, 714 &error, 715 HAMMER2_LOOKUP_ALWAYS); 716 } 717 } 718 if (error == 0) { 719 /* 720 * A relookup is required before the create to properly 721 * position the parent chain. 722 */ 723 tmp = hammer2_chain_lookup(&parent, &key_next, 724 xop->lhc, xop->lhc, 725 &error, 0); 726 KKASSERT(tmp == NULL); 727 error = hammer2_chain_create(&parent, &chain, 728 pmp, HAMMER2_METH_DEFAULT, 729 xop->lhc, 0, 730 HAMMER2_BREF_TYPE_INODE, 731 HAMMER2_INODE_BYTES, 732 xop->head.mtid, 0, 0); 733 } 734 done: 735 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 736 if (parent) { 737 hammer2_chain_unlock(parent); 738 hammer2_chain_drop(parent); 739 } 740 if (chain) { 741 hammer2_chain_unlock(chain); 742 hammer2_chain_drop(chain); 743 } 744 } 745 746 /* 747 * Directory collision resolver scan helper (backend, threaded). 748 * 749 * Used by the inode create code to locate an unused lhc. 750 */ 751 void 752 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg) 753 { 754 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 755 hammer2_chain_t *parent; 756 hammer2_chain_t *chain; 757 hammer2_key_t key_next; 758 int error = 0; 759 760 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 761 HAMMER2_RESOLVE_ALWAYS | 762 HAMMER2_RESOLVE_SHARED); 763 if (parent == NULL) { 764 kprintf("xop_nresolve: NULL parent\n"); 765 chain = NULL; 766 error = HAMMER2_ERROR_EIO; 767 goto done; 768 } 769 770 /* 771 * Lookup all possibly conflicting directory entries, the feed 772 * inherits the chain's lock so do not unlock it on the iteration. 773 */ 774 chain = hammer2_chain_lookup(&parent, &key_next, 775 xop->lhc, 776 xop->lhc + HAMMER2_DIRHASH_LOMASK, 777 &error, 778 HAMMER2_LOOKUP_ALWAYS | 779 HAMMER2_LOOKUP_SHARED); 780 while (chain) { 781 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0); 782 if (error) { 783 hammer2_chain_unlock(chain); 784 hammer2_chain_drop(chain); 785 chain = NULL; /* safety */ 786 goto done; 787 } 788 chain = hammer2_chain_next(&parent, chain, &key_next, 789 key_next, 790 xop->lhc + HAMMER2_DIRHASH_LOMASK, 791 &error, 792 HAMMER2_LOOKUP_ALWAYS | 793 HAMMER2_LOOKUP_SHARED); 794 } 795 done: 796 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 797 if (parent) { 798 hammer2_chain_unlock(parent); 799 hammer2_chain_drop(parent); 800 } 801 } 802 803 /* 804 * Generic lookup of a specific key. 805 * 806 * Used by the inode hidden directory code to find the hidden directory. 807 */ 808 void 809 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg) 810 { 811 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 812 hammer2_chain_t *parent; 813 hammer2_chain_t *chain; 814 hammer2_key_t key_next; 815 int error = 0; 816 817 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 818 HAMMER2_RESOLVE_ALWAYS | 819 HAMMER2_RESOLVE_SHARED); 820 chain = NULL; 821 if (parent == NULL) { 822 error = HAMMER2_ERROR_EIO; 823 goto done; 824 } 825 826 /* 827 * Lookup all possibly conflicting directory entries, the feed 828 * inherits the chain's lock so do not unlock it on the iteration. 829 */ 830 chain = hammer2_chain_lookup(&parent, &key_next, 831 xop->lhc, xop->lhc, 832 &error, 833 HAMMER2_LOOKUP_ALWAYS | 834 HAMMER2_LOOKUP_SHARED); 835 if (error == 0) { 836 if (chain) 837 error = chain->error; 838 else 839 error = HAMMER2_ERROR_ENOENT; 840 } 841 hammer2_xop_feed(&xop->head, chain, thr->clindex, error); 842 843 done: 844 if (chain) { 845 hammer2_chain_unlock(chain); 846 hammer2_chain_drop(chain); 847 } 848 if (parent) { 849 hammer2_chain_unlock(parent); 850 hammer2_chain_drop(parent); 851 } 852 } 853 854 /* 855 * Generic scan 856 * 857 * WARNING! Fed chains must be locked shared so ownership can be transfered 858 * and to prevent frontend/backend stalls that would occur with an 859 * exclusive lock. The shared lock also allows chain->data to be 860 * retained. 861 */ 862 void 863 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg) 864 { 865 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 866 hammer2_chain_t *parent; 867 hammer2_chain_t *chain; 868 hammer2_key_t key_next; 869 int error = 0; 870 871 /* 872 * Assert required flags. 873 */ 874 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 875 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 876 877 /* 878 * The inode's chain is the iterator. If we cannot acquire it our 879 * contribution ends here. 880 */ 881 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex, 882 xop->resolve_flags); 883 if (parent == NULL) { 884 kprintf("xop_readdir: NULL parent\n"); 885 goto done; 886 } 887 888 /* 889 * Generic scan of exact records. Note that indirect blocks are 890 * automatically recursed and will not be returned. 891 */ 892 chain = hammer2_chain_lookup(&parent, &key_next, 893 xop->key_beg, xop->key_end, 894 &error, xop->lookup_flags); 895 while (chain) { 896 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0); 897 if (error) 898 goto break2; 899 chain = hammer2_chain_next(&parent, chain, &key_next, 900 key_next, xop->key_end, 901 &error, xop->lookup_flags); 902 } 903 break2: 904 if (chain) { 905 hammer2_chain_unlock(chain); 906 hammer2_chain_drop(chain); 907 } 908 hammer2_chain_unlock(parent); 909 hammer2_chain_drop(parent); 910 done: 911 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error); 912 } 913