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