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/proc.h> 48 #include <sys/mount.h> 49 50 #include "hammer2.h" 51 52 /* 53 * Determine if the specified directory is empty. 54 * 55 * Returns 0 on success. 56 * 57 * Returns HAMMER_ERROR_EAGAIN if caller must re-lookup the entry and 58 * retry. (occurs if we race a ripup on oparent or ochain). 59 * 60 * Or returns a permanent HAMMER2_ERROR_* error mask. 61 * 62 * The caller must pass in an exclusively locked oparent and ochain. This 63 * function will handle the case where the chain is a directory entry or 64 * the inode itself. The original oparent,ochain will be locked upon return. 65 * 66 * This function will unlock the underlying oparent,ochain temporarily when 67 * doing an inode lookup to avoid deadlocks. The caller MUST handle the EAGAIN 68 * result as this means that oparent is no longer the parent of ochain, or 69 * that ochain was destroyed while it was unlocked. 70 */ 71 static 72 int 73 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex) 74 { 75 hammer2_chain_t *parent; 76 hammer2_chain_t *chain; 77 hammer2_key_t key_next; 78 hammer2_key_t inum; 79 int error; 80 int didunlock; 81 82 error = 0; 83 didunlock = 0; 84 85 /* 86 * Find the inode, set it up as a locked 'chain'. ochain can be the 87 * inode itself, or it can be a directory entry. 88 */ 89 if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 90 inum = ochain->bref.embed.dirent.inum; 91 hammer2_chain_unlock(ochain); 92 hammer2_chain_unlock(oparent); 93 94 parent = NULL; 95 chain = NULL; 96 error = hammer2_chain_inode_find(ochain->pmp, inum, 97 clindex, 0, 98 &parent, &chain); 99 if (parent) { 100 hammer2_chain_unlock(parent); 101 hammer2_chain_drop(parent); 102 } 103 didunlock = 1; 104 } else { 105 /* 106 * The directory entry *is* the directory inode 107 */ 108 chain = hammer2_chain_lookup_init(ochain, 0); 109 } 110 111 /* 112 * Determine if the directory is empty or not by checking its 113 * visible namespace (the area which contains directory entries). 114 */ 115 if (error == 0) { 116 parent = chain; 117 chain = NULL; 118 if (parent) { 119 chain = hammer2_chain_lookup(&parent, &key_next, 120 HAMMER2_DIRHASH_VISIBLE, 121 HAMMER2_KEY_MAX, 122 &error, 0); 123 } 124 if (chain) { 125 error = HAMMER2_ERROR_ENOTEMPTY; 126 hammer2_chain_unlock(chain); 127 hammer2_chain_drop(chain); 128 } 129 hammer2_chain_lookup_done(parent); 130 } else { 131 if (chain) { 132 hammer2_chain_unlock(chain); 133 hammer2_chain_drop(chain); 134 chain = NULL; /* safety */ 135 } 136 } 137 138 if (didunlock) { 139 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS); 140 hammer2_chain_lock(ochain, HAMMER2_RESOLVE_ALWAYS); 141 if ((ochain->flags & HAMMER2_CHAIN_DELETED) || 142 (oparent->flags & HAMMER2_CHAIN_DELETED) || 143 ochain->parent != oparent) { 144 kprintf("hammer2: debug: CHECKDIR inum %jd RETRY\n", 145 inum); 146 error = HAMMER2_ERROR_EAGAIN; 147 } 148 } 149 return error; 150 } 151 152 /* 153 * Backend for hammer2_vfs_root() 154 * 155 * This is called when a newly mounted PFS has not yet synchronized 156 * to the inode_tid and modify_tid. 157 */ 158 void 159 hammer2_xop_ipcluster(hammer2_xop_t *arg, void *scratch, int clindex) 160 { 161 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster; 162 hammer2_chain_t *chain; 163 int error; 164 165 chain = hammer2_inode_chain(xop->head.ip1, clindex, 166 HAMMER2_RESOLVE_ALWAYS | 167 HAMMER2_RESOLVE_SHARED); 168 if (chain) 169 error = chain->error; 170 else 171 error = HAMMER2_ERROR_EIO; 172 173 hammer2_xop_feed(&xop->head, chain, clindex, error); 174 if (chain) { 175 hammer2_chain_unlock(chain); 176 hammer2_chain_drop(chain); 177 } 178 } 179 180 /* 181 * Backend for hammer2_vop_readdir() 182 */ 183 void 184 hammer2_xop_readdir(hammer2_xop_t *arg, void *scratch, int clindex) 185 { 186 hammer2_xop_readdir_t *xop = &arg->xop_readdir; 187 hammer2_chain_t *parent; 188 hammer2_chain_t *chain; 189 hammer2_key_t key_next; 190 hammer2_key_t lkey; 191 int error = 0; 192 193 lkey = xop->lkey; 194 if (hammer2_debug & 0x0020) 195 kprintf("xop_readdir: %p lkey=%016jx\n", xop, lkey); 196 197 /* 198 * The inode's chain is the iterator. If we cannot acquire it our 199 * contribution ends here. 200 */ 201 parent = hammer2_inode_chain(xop->head.ip1, clindex, 202 HAMMER2_RESOLVE_ALWAYS | 203 HAMMER2_RESOLVE_SHARED); 204 if (parent == NULL) { 205 kprintf("xop_readdir: NULL parent\n"); 206 goto done; 207 } 208 209 /* 210 * Directory scan [re]start and loop, the feed inherits the chain's 211 * lock so do not unlock it on the iteration. 212 */ 213 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey, 214 &error, HAMMER2_LOOKUP_SHARED); 215 if (chain == NULL) { 216 chain = hammer2_chain_lookup(&parent, &key_next, 217 lkey, HAMMER2_KEY_MAX, 218 &error, HAMMER2_LOOKUP_SHARED); 219 } 220 while (chain) { 221 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 222 if (error) 223 goto break2; 224 chain = hammer2_chain_next(&parent, chain, &key_next, 225 key_next, HAMMER2_KEY_MAX, 226 &error, HAMMER2_LOOKUP_SHARED); 227 } 228 break2: 229 if (chain) { 230 hammer2_chain_unlock(chain); 231 hammer2_chain_drop(chain); 232 } 233 hammer2_chain_unlock(parent); 234 hammer2_chain_drop(parent); 235 done: 236 hammer2_xop_feed(&xop->head, NULL, clindex, error); 237 } 238 239 /* 240 * Backend for hammer2_vop_nresolve() 241 */ 242 void 243 hammer2_xop_nresolve(hammer2_xop_t *arg, void *scratch, int clindex) 244 { 245 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve; 246 hammer2_chain_t *parent; 247 hammer2_chain_t *chain; 248 const char *name; 249 size_t name_len; 250 hammer2_key_t key_next; 251 hammer2_key_t lhc; 252 int error; 253 254 parent = hammer2_inode_chain(xop->head.ip1, clindex, 255 HAMMER2_RESOLVE_ALWAYS | 256 HAMMER2_RESOLVE_SHARED); 257 if (parent == NULL) { 258 kprintf("xop_nresolve: NULL parent\n"); 259 chain = NULL; 260 error = HAMMER2_ERROR_EIO; 261 goto done; 262 } 263 name = xop->head.name1; 264 name_len = xop->head.name1_len; 265 266 /* 267 * Lookup the directory entry 268 */ 269 lhc = hammer2_dirhash(name, name_len); 270 chain = hammer2_chain_lookup(&parent, &key_next, 271 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 272 &error, 273 HAMMER2_LOOKUP_ALWAYS | 274 HAMMER2_LOOKUP_SHARED); 275 while (chain) { 276 if (hammer2_chain_dirent_test(chain, name, name_len)) 277 break; 278 chain = hammer2_chain_next(&parent, chain, &key_next, 279 key_next, 280 lhc + HAMMER2_DIRHASH_LOMASK, 281 &error, 282 HAMMER2_LOOKUP_ALWAYS | 283 HAMMER2_LOOKUP_SHARED); 284 } 285 286 /* 287 * Locate the target inode for a directory entry 288 */ 289 if (chain && chain->error == 0) { 290 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 291 lhc = chain->bref.embed.dirent.inum; 292 error = hammer2_chain_inode_find(chain->pmp, 293 lhc, 294 clindex, 295 HAMMER2_LOOKUP_SHARED, 296 &parent, 297 &chain); 298 } 299 } else if (chain && error == 0) { 300 error = chain->error; 301 } 302 done: 303 error = hammer2_xop_feed(&xop->head, chain, clindex, error); 304 if (chain) { 305 hammer2_chain_unlock(chain); 306 hammer2_chain_drop(chain); 307 } 308 if (parent) { 309 hammer2_chain_unlock(parent); 310 hammer2_chain_drop(parent); 311 } 312 } 313 314 /* 315 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and 316 * backend for pfs_delete. 317 * 318 * This function locates and removes a directory entry, and will lookup 319 * and return the underlying inode. For directory entries the underlying 320 * inode is not removed. If the directory entry is the actual inode itself, 321 * it may be conditonally removed and returned. 322 * 323 * WARNING! Any target inode's nlinks may not be synchronized to the 324 * in-memory inode. The frontend's hammer2_inode_unlink_finisher() 325 * is responsible for the final disposition of the actual inode. 326 */ 327 void 328 hammer2_xop_unlink(hammer2_xop_t *arg, void *scratch, int clindex) 329 { 330 hammer2_xop_unlink_t *xop = &arg->xop_unlink; 331 hammer2_chain_t *parent; 332 hammer2_chain_t *chain; 333 const char *name; 334 size_t name_len; 335 hammer2_key_t key_next; 336 hammer2_key_t lhc; 337 int error; 338 339 again: 340 /* 341 * Requires exclusive lock 342 */ 343 parent = hammer2_inode_chain(xop->head.ip1, clindex, 344 HAMMER2_RESOLVE_ALWAYS); 345 chain = NULL; 346 if (parent == NULL) { 347 kprintf("xop_unlink: NULL parent\n"); 348 error = HAMMER2_ERROR_EIO; 349 goto done; 350 } 351 name = xop->head.name1; 352 name_len = xop->head.name1_len; 353 354 /* 355 * Lookup the directory entry 356 */ 357 lhc = hammer2_dirhash(name, name_len); 358 chain = hammer2_chain_lookup(&parent, &key_next, 359 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 360 &error, HAMMER2_LOOKUP_ALWAYS); 361 while (chain) { 362 if (hammer2_chain_dirent_test(chain, name, name_len)) 363 break; 364 chain = hammer2_chain_next(&parent, chain, &key_next, 365 key_next, 366 lhc + HAMMER2_DIRHASH_LOMASK, 367 &error, HAMMER2_LOOKUP_ALWAYS); 368 } 369 370 /* 371 * The directory entry will either be a BREF_TYPE_DIRENT or a 372 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but 373 * must go by xop->dopermanent for BREF_TYPE_INODE. 374 * 375 * Note that the target chain's nlinks may not be synchronized with 376 * the in-memory hammer2_inode_t structure, so we don't try to do 377 * anything fancy here. The frontend deals with nlinks 378 * synchronization. 379 */ 380 if (chain && chain->error == 0) { 381 int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT; 382 int doforce = xop->dopermanent & H2DOPERM_FORCE; 383 uint8_t type; 384 385 /* 386 * If the directory entry is the actual inode then use its 387 * type for the directory typing tests, otherwise if it is 388 * a directory entry, pull the type field from the entry. 389 * 390 * Directory entries are always permanently deleted 391 * (because they aren't the actual inode). 392 */ 393 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 394 type = chain->bref.embed.dirent.type; 395 dopermanent |= HAMMER2_DELETE_PERMANENT; 396 } else { 397 type = chain->data->ipdata.meta.type; 398 } 399 400 /* 401 * Check directory typing and delete the entry. Note that 402 * nlinks adjustments are made on the real inode by the 403 * frontend, not here. 404 * 405 * Unfortunately, checkdirempty() may have to unlock (parent). 406 * If it no longer matches chain->parent after re-locking, 407 * EAGAIN is returned. 408 */ 409 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) { 410 /* 411 * If doforce then execute the operation even if 412 * the directory is not empty or errored. We 413 * ignore chain->error here, allowing an errored 414 * chain (aka directory entry) to still be deleted. 415 */ 416 error = hammer2_chain_delete(parent, chain, 417 xop->head.mtid, dopermanent); 418 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 419 xop->isdir == 0) { 420 error = HAMMER2_ERROR_EISDIR; 421 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 422 (error = checkdirempty(parent, chain, clindex)) != 0) { 423 /* 424 * error may be EAGAIN or ENOTEMPTY 425 */ 426 if (error == HAMMER2_ERROR_EAGAIN) { 427 hammer2_chain_unlock(chain); 428 hammer2_chain_drop(chain); 429 hammer2_chain_unlock(parent); 430 hammer2_chain_drop(parent); 431 goto again; 432 } 433 } else if (type != HAMMER2_OBJTYPE_DIRECTORY && 434 xop->isdir >= 1) { 435 error = HAMMER2_ERROR_ENOTDIR; 436 } else { 437 /* 438 * Delete the directory entry. chain might also 439 * be a directly-embedded inode. 440 * 441 * Allow the deletion to proceed even if the chain 442 * is errored. Give priority to error-on-delete over 443 * chain->error. 444 */ 445 error = hammer2_chain_delete(parent, chain, 446 xop->head.mtid, 447 dopermanent); 448 if (error == 0) 449 error = chain->error; 450 } 451 } else { 452 if (chain && error == 0) 453 error = chain->error; 454 } 455 456 /* 457 * If chain is a directory entry we must resolve it. We do not try 458 * to manipulate the contents as it might not be synchronized with 459 * the frontend hammer2_inode_t, nor do we try to lookup the 460 * frontend hammer2_inode_t here (we are the backend!). 461 */ 462 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT && 463 (xop->dopermanent & H2DOPERM_IGNINO) == 0) { 464 int error2; 465 466 lhc = chain->bref.embed.dirent.inum; 467 468 error2 = hammer2_chain_inode_find(chain->pmp, lhc, 469 clindex, 0, 470 &parent, &chain); 471 if (error2) { 472 kprintf("xop_unlink: %016jx %p failed\n", 473 lhc, chain); 474 error2 = 0; /* silently ignore */ 475 } 476 if (error == 0) 477 error = error2; 478 } 479 480 /* 481 * Return the inode target for further action. Typically used by 482 * hammer2_inode_unlink_finisher(). 483 */ 484 done: 485 hammer2_xop_feed(&xop->head, chain, clindex, error); 486 if (chain) { 487 hammer2_chain_unlock(chain); 488 hammer2_chain_drop(chain); 489 chain = NULL; 490 } 491 if (parent) { 492 hammer2_chain_unlock(parent); 493 hammer2_chain_drop(parent); 494 parent = NULL; 495 } 496 } 497 498 /* 499 * Backend for hammer2_vop_nrename() 500 * 501 * This handles the backend rename operation. Typically this renames 502 * directory entries but can also be used to rename embedded inodes. 503 * 504 * NOTE! The frontend is responsible for updating the inode meta-data in 505 * the file being renamed and for decrementing the target-replaced 506 * inode's nlinks, if present. 507 */ 508 void 509 hammer2_xop_nrename(hammer2_xop_t *arg, void *scratch, int clindex) 510 { 511 hammer2_xop_nrename_t *xop = &arg->xop_nrename; 512 hammer2_pfs_t *pmp; 513 hammer2_chain_t *parent; 514 hammer2_chain_t *chain; 515 hammer2_chain_t *tmp; 516 hammer2_inode_t *ip; 517 hammer2_key_t key_next; 518 int error; 519 520 /* 521 * If ip4 is non-NULL we must check to see if the entry being 522 * overwritten is a non-empty directory. 523 */ 524 ip = xop->head.ip4; 525 if (ip) { 526 uint8_t type; 527 528 chain = hammer2_inode_chain(ip, clindex, 529 HAMMER2_RESOLVE_ALWAYS); 530 if (chain == NULL) { 531 error = HAMMER2_ERROR_EIO; 532 parent = NULL; 533 goto done; 534 } 535 type = chain->data->ipdata.meta.type; 536 if (type == HAMMER2_OBJTYPE_DIRECTORY && 537 (error = checkdirempty(NULL, chain, clindex)) != 0) 538 { 539 KKASSERT(error != HAMMER2_ERROR_EAGAIN); 540 parent = NULL; 541 goto done; 542 } 543 hammer2_chain_unlock(chain); 544 hammer2_chain_drop(chain); 545 } 546 547 /* 548 * We need the precise parent chain to issue the deletion. 549 * 550 * If this is a directory entry we must locate the underlying 551 * inode. If it is an embedded inode we can act directly on it. 552 */ 553 ip = xop->head.ip2; 554 pmp = ip->pmp; 555 chain = NULL; 556 error = 0; 557 558 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) { 559 /* 560 * Find ip's direct parent chain. 561 */ 562 chain = hammer2_inode_chain(ip, clindex, 563 HAMMER2_RESOLVE_ALWAYS); 564 if (chain == NULL) { 565 error = HAMMER2_ERROR_EIO; 566 parent = NULL; 567 goto done; 568 } 569 if (ip->flags & HAMMER2_INODE_CREATING) { 570 parent = NULL; 571 } else { 572 parent = hammer2_chain_getparent(chain, 573 HAMMER2_RESOLVE_ALWAYS); 574 if (parent == NULL) { 575 error = HAMMER2_ERROR_EIO; 576 goto done; 577 } 578 } 579 } else { 580 /* 581 * The directory entry for the head.ip1 inode 582 * is in fdip, do a namespace search. 583 */ 584 hammer2_key_t lhc; 585 const char *name; 586 size_t name_len; 587 588 parent = hammer2_inode_chain(xop->head.ip1, clindex, 589 HAMMER2_RESOLVE_ALWAYS); 590 if (parent == NULL) { 591 kprintf("xop_nrename: NULL parent\n"); 592 error = HAMMER2_ERROR_EIO; 593 goto done; 594 } 595 name = xop->head.name1; 596 name_len = xop->head.name1_len; 597 598 /* 599 * Lookup the directory entry 600 */ 601 lhc = hammer2_dirhash(name, name_len); 602 chain = hammer2_chain_lookup(&parent, &key_next, 603 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 604 &error, HAMMER2_LOOKUP_ALWAYS); 605 while (chain) { 606 if (hammer2_chain_dirent_test(chain, name, name_len)) 607 break; 608 chain = hammer2_chain_next(&parent, chain, &key_next, 609 key_next, 610 lhc + HAMMER2_DIRHASH_LOMASK, 611 &error, 612 HAMMER2_LOOKUP_ALWAYS); 613 } 614 } 615 616 if (chain == NULL) { 617 /* XXX shouldn't happen, but does under fsstress */ 618 kprintf("xop_nrename: \"%s\" -> \"%s\" ENOENT\n", 619 xop->head.name1, 620 xop->head.name2); 621 if (error == 0) 622 error = HAMMER2_ERROR_ENOENT; 623 goto done; 624 } 625 626 if (chain->error) { 627 error = chain->error; 628 goto done; 629 } 630 631 /* 632 * Delete it, then create it in the new namespace. 633 * 634 * An error can occur if the chain being deleted requires 635 * modification and the media is full. 636 */ 637 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 638 if (parent) { 639 hammer2_chain_unlock(parent); 640 hammer2_chain_drop(parent); 641 parent = NULL; /* safety */ 642 } else { 643 kprintf("hammer2_xop_nrename() (debugging): parent was NULL\n"); 644 error = EINVAL; 645 } 646 if (error) 647 goto done; 648 649 /* 650 * Adjust fields in the deleted chain appropriate for the rename 651 * operation. 652 * 653 * NOTE! For embedded inodes, the frontend will officially replicate 654 * the field adjustments, but we also do it here to maintain 655 * consistency in case of a crash. 656 */ 657 if (chain->bref.key != xop->lhc || 658 xop->head.name1_len != xop->head.name2_len || 659 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) { 660 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { 661 hammer2_inode_data_t *wipdata; 662 663 error = hammer2_chain_modify(chain, xop->head.mtid, 664 0, 0); 665 if (error == 0) { 666 wipdata = &chain->data->ipdata; 667 668 bzero(wipdata->filename, 669 sizeof(wipdata->filename)); 670 bcopy(xop->head.name2, 671 wipdata->filename, 672 xop->head.name2_len); 673 wipdata->meta.name_key = xop->lhc; 674 wipdata->meta.name_len = xop->head.name2_len; 675 } 676 } 677 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 678 if (xop->head.name2_len <= 679 sizeof(chain->bref.check.buf)) { 680 /* 681 * Remove any related data buffer, we can 682 * embed the filename in the bref itself. 683 */ 684 error = hammer2_chain_resize( 685 chain, xop->head.mtid, 0, 0, 0); 686 if (error == 0) { 687 error = hammer2_chain_modify( 688 chain, xop->head.mtid, 689 0, 0); 690 } 691 if (error == 0) { 692 bzero(chain->bref.check.buf, 693 sizeof(chain->bref.check.buf)); 694 bcopy(xop->head.name2, 695 chain->bref.check.buf, 696 xop->head.name2_len); 697 } 698 } else { 699 /* 700 * Associate a data buffer with the bref. 701 * Zero it for consistency. Note that the 702 * data buffer is not 64KB so use chain->bytes 703 * instead of sizeof(). 704 */ 705 error = hammer2_chain_resize( 706 chain, xop->head.mtid, 0, 707 hammer2_getradix(HAMMER2_ALLOC_MIN), 0); 708 if (error == 0) { 709 error = hammer2_chain_modify( 710 chain, xop->head.mtid, 711 0, 0); 712 } 713 if (error == 0) { 714 bzero(chain->data->buf, chain->bytes); 715 bcopy(xop->head.name2, 716 chain->data->buf, 717 xop->head.name2_len); 718 } 719 } 720 if (error == 0) { 721 chain->bref.embed.dirent.namlen = 722 xop->head.name2_len; 723 } 724 } 725 } 726 727 /* 728 * The frontend will replicate this operation and is the real final 729 * authority, but adjust the inode's iparent field too if the inode 730 * is embedded in the directory. 731 */ 732 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 733 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) { 734 hammer2_inode_data_t *wipdata; 735 736 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 737 if (error == 0) { 738 wipdata = &chain->data->ipdata; 739 wipdata->meta.iparent = xop->head.ip3->meta.inum; 740 } 741 } 742 743 /* 744 * Destroy any matching target(s) before creating the new entry. 745 * This will result in some ping-ponging of the directory key 746 * iterator but that is ok. 747 */ 748 parent = hammer2_inode_chain(xop->head.ip3, clindex, 749 HAMMER2_RESOLVE_ALWAYS); 750 if (parent == NULL) { 751 error = HAMMER2_ERROR_EIO; 752 goto done; 753 } 754 755 /* 756 * Delete all matching directory entries. That is, get rid of 757 * multiple duplicates if present, as a self-healing mechanism. 758 */ 759 if (error == 0) { 760 tmp = hammer2_chain_lookup(&parent, &key_next, 761 xop->lhc & ~HAMMER2_DIRHASH_LOMASK, 762 xop->lhc | HAMMER2_DIRHASH_LOMASK, 763 &error, 764 HAMMER2_LOOKUP_ALWAYS); 765 while (tmp) { 766 int e2; 767 if (hammer2_chain_dirent_test(tmp, xop->head.name2, 768 xop->head.name2_len)) { 769 e2 = hammer2_chain_delete(parent, tmp, 770 xop->head.mtid, 0); 771 if (error == 0 && e2) 772 error = e2; 773 } 774 tmp = hammer2_chain_next(&parent, tmp, &key_next, 775 key_next, 776 xop->lhc | 777 HAMMER2_DIRHASH_LOMASK, 778 &error, 779 HAMMER2_LOOKUP_ALWAYS); 780 } 781 } 782 if (error == 0) { 783 /* 784 * A relookup is required before the create to properly 785 * position the parent chain. 786 */ 787 tmp = hammer2_chain_lookup(&parent, &key_next, 788 xop->lhc, xop->lhc, 789 &error, 0); 790 KKASSERT(tmp == NULL); 791 error = hammer2_chain_create(&parent, &chain, NULL, pmp, 792 HAMMER2_METH_DEFAULT, 793 xop->lhc, 0, 794 HAMMER2_BREF_TYPE_INODE, 795 HAMMER2_INODE_BYTES, 796 xop->head.mtid, 0, 0); 797 } 798 done: 799 hammer2_xop_feed(&xop->head, NULL, clindex, error); 800 if (parent) { 801 hammer2_chain_unlock(parent); 802 hammer2_chain_drop(parent); 803 } 804 if (chain) { 805 hammer2_chain_unlock(chain); 806 hammer2_chain_drop(chain); 807 } 808 } 809 810 /* 811 * Directory collision resolver scan helper (backend, threaded). 812 * 813 * Used by the inode create code to locate an unused lhc. 814 */ 815 void 816 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex) 817 { 818 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 819 hammer2_chain_t *parent; 820 hammer2_chain_t *chain; 821 hammer2_key_t key_next; 822 int error = 0; 823 824 parent = hammer2_inode_chain(xop->head.ip1, clindex, 825 HAMMER2_RESOLVE_ALWAYS | 826 HAMMER2_RESOLVE_SHARED); 827 if (parent == NULL) { 828 kprintf("xop_scanlhc: NULL parent\n"); 829 chain = NULL; 830 error = HAMMER2_ERROR_EIO; 831 goto done; 832 } 833 834 /* 835 * Lookup all possibly conflicting directory entries, the feed 836 * inherits the chain's lock so do not unlock it on the iteration. 837 */ 838 chain = hammer2_chain_lookup(&parent, &key_next, 839 xop->lhc, 840 xop->lhc + HAMMER2_DIRHASH_LOMASK, 841 &error, 842 HAMMER2_LOOKUP_ALWAYS | 843 HAMMER2_LOOKUP_SHARED); 844 while (chain) { 845 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 846 if (error) { 847 hammer2_chain_unlock(chain); 848 hammer2_chain_drop(chain); 849 chain = NULL; /* safety */ 850 goto done; 851 } 852 chain = hammer2_chain_next(&parent, chain, &key_next, 853 key_next, 854 xop->lhc + HAMMER2_DIRHASH_LOMASK, 855 &error, 856 HAMMER2_LOOKUP_ALWAYS | 857 HAMMER2_LOOKUP_SHARED); 858 } 859 done: 860 hammer2_xop_feed(&xop->head, NULL, clindex, error); 861 if (parent) { 862 hammer2_chain_unlock(parent); 863 hammer2_chain_drop(parent); 864 } 865 } 866 867 /* 868 * Generic lookup of a specific key. 869 */ 870 void 871 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex) 872 { 873 hammer2_xop_lookup_t *xop = &arg->xop_lookup; 874 hammer2_chain_t *parent; 875 hammer2_chain_t *chain; 876 hammer2_key_t key_next; 877 int error = 0; 878 879 parent = hammer2_inode_chain(xop->head.ip1, clindex, 880 HAMMER2_RESOLVE_ALWAYS | 881 HAMMER2_RESOLVE_SHARED); 882 chain = NULL; 883 if (parent == NULL) { 884 error = HAMMER2_ERROR_EIO; 885 goto done; 886 } 887 888 /* 889 * Lookup all possibly conflicting directory entries, the feed 890 * inherits the chain's lock so do not unlock it on the iteration. 891 */ 892 chain = hammer2_chain_lookup(&parent, &key_next, 893 xop->lhc, xop->lhc, 894 &error, 895 HAMMER2_LOOKUP_ALWAYS | 896 HAMMER2_LOOKUP_SHARED); 897 if (error == 0) { 898 if (chain) 899 error = chain->error; 900 else 901 error = HAMMER2_ERROR_ENOENT; 902 } 903 hammer2_xop_feed(&xop->head, chain, clindex, error); 904 905 done: 906 if (chain) { 907 hammer2_chain_unlock(chain); 908 hammer2_chain_drop(chain); 909 } 910 if (parent) { 911 hammer2_chain_unlock(parent); 912 hammer2_chain_drop(parent); 913 } 914 } 915 916 void 917 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex) 918 { 919 hammer2_xop_lookup_t *xop = &arg->xop_lookup; 920 hammer2_chain_t *parent; 921 hammer2_chain_t *chain; 922 hammer2_key_t key_next; 923 int error = 0; 924 925 parent = hammer2_inode_chain(xop->head.ip1, clindex, 926 HAMMER2_RESOLVE_ALWAYS); 927 chain = NULL; 928 if (parent == NULL) { 929 error = HAMMER2_ERROR_EIO; 930 goto done; 931 } 932 933 /* 934 * Lookup all possibly conflicting directory entries, the feed 935 * inherits the chain's lock so do not unlock it on the iteration. 936 */ 937 chain = hammer2_chain_lookup(&parent, &key_next, 938 xop->lhc, xop->lhc, 939 &error, 940 HAMMER2_LOOKUP_NODATA); 941 if (error == 0) { 942 if (chain) 943 error = chain->error; 944 else 945 error = HAMMER2_ERROR_ENOENT; 946 } 947 if (chain) { 948 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 949 HAMMER2_DELETE_PERMANENT); 950 } 951 hammer2_xop_feed(&xop->head, NULL, clindex, error); 952 953 done: 954 if (chain) { 955 hammer2_chain_unlock(chain); 956 hammer2_chain_drop(chain); 957 } 958 if (parent) { 959 hammer2_chain_unlock(parent); 960 hammer2_chain_drop(parent); 961 } 962 } 963 964 /* 965 * Generic scan 966 * 967 * WARNING! Fed chains must be locked shared so ownership can be transfered 968 * and to prevent frontend/backend stalls that would occur with an 969 * exclusive lock. The shared lock also allows chain->data to be 970 * retained. 971 */ 972 void 973 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex) 974 { 975 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 976 hammer2_chain_t *parent; 977 hammer2_chain_t *chain; 978 hammer2_key_t key_next; 979 int error = 0; 980 981 /* 982 * Assert required flags. 983 */ 984 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 985 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 986 987 /* 988 * The inode's chain is the iterator. If we cannot acquire it our 989 * contribution ends here. 990 */ 991 parent = hammer2_inode_chain(xop->head.ip1, clindex, 992 xop->resolve_flags); 993 if (parent == NULL) { 994 kprintf("xop_scanall: NULL parent\n"); 995 goto done; 996 } 997 998 /* 999 * Generic scan of exact records. Note that indirect blocks are 1000 * automatically recursed and will not be returned. 1001 */ 1002 chain = hammer2_chain_lookup(&parent, &key_next, 1003 xop->key_beg, xop->key_end, 1004 &error, xop->lookup_flags); 1005 while (chain) { 1006 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 1007 if (error) 1008 goto break2; 1009 chain = hammer2_chain_next(&parent, chain, &key_next, 1010 key_next, xop->key_end, 1011 &error, xop->lookup_flags); 1012 } 1013 break2: 1014 if (chain) { 1015 hammer2_chain_unlock(chain); 1016 hammer2_chain_drop(chain); 1017 } 1018 hammer2_chain_unlock(parent); 1019 hammer2_chain_drop(parent); 1020 done: 1021 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1022 } 1023 1024 /************************************************************************ 1025 * INODE LAYER XOPS * 1026 ************************************************************************ 1027 * 1028 */ 1029 /* 1030 * Helper to create a directory entry. 1031 */ 1032 void 1033 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex) 1034 { 1035 hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent; 1036 hammer2_chain_t *parent; 1037 hammer2_chain_t *chain; 1038 hammer2_key_t key_next; 1039 size_t data_len; 1040 int error; 1041 1042 if (hammer2_debug & 0x0001) 1043 kprintf("xop_inode_mkdirent: lhc %016jx clindex %d\n", 1044 xop->lhc, clindex); 1045 1046 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1047 HAMMER2_RESOLVE_ALWAYS); 1048 if (parent == NULL) { 1049 error = HAMMER2_ERROR_EIO; 1050 chain = NULL; 1051 goto fail; 1052 } 1053 chain = hammer2_chain_lookup(&parent, &key_next, 1054 xop->lhc, xop->lhc, 1055 &error, 0); 1056 if (chain) { 1057 error = HAMMER2_ERROR_EEXIST; 1058 goto fail; 1059 } 1060 1061 /* 1062 * We may be able to embed the directory entry directly in the 1063 * blockref. 1064 */ 1065 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf)) 1066 data_len = 0; 1067 else 1068 data_len = HAMMER2_ALLOC_MIN; 1069 1070 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp, 1071 HAMMER2_METH_DEFAULT, 1072 xop->lhc, 0, 1073 HAMMER2_BREF_TYPE_DIRENT, 1074 data_len, 1075 xop->head.mtid, 0, 0); 1076 if (error == 0) { 1077 /* 1078 * WARNING: chain->data->buf is sized to chain->bytes, 1079 * do not use sizeof(chain->data->buf), which 1080 * will be much larger. 1081 */ 1082 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1083 if (error == 0) { 1084 chain->bref.embed.dirent = xop->dirent; 1085 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf)) 1086 bcopy(xop->head.name1, chain->bref.check.buf, 1087 xop->dirent.namlen); 1088 else 1089 bcopy(xop->head.name1, chain->data->buf, 1090 xop->dirent.namlen); 1091 } 1092 } 1093 fail: 1094 if (parent) { 1095 hammer2_chain_unlock(parent); 1096 hammer2_chain_drop(parent); 1097 } 1098 hammer2_xop_feed(&xop->head, chain, clindex, error); 1099 if (chain) { 1100 hammer2_chain_unlock(chain); 1101 hammer2_chain_drop(chain); 1102 } 1103 } 1104 1105 /* 1106 * Inode create helper (threaded, backend) 1107 * 1108 * Used by ncreate, nmknod, nsymlink, nmkdir. 1109 * Used by nlink and rename to create HARDLINK pointers. 1110 * 1111 * Frontend holds the parent directory ip locked exclusively. We 1112 * create the inode and feed the exclusively locked chain to the 1113 * frontend. 1114 */ 1115 void 1116 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex) 1117 { 1118 hammer2_xop_create_t *xop = &arg->xop_create; 1119 hammer2_chain_t *parent; 1120 hammer2_chain_t *chain; 1121 hammer2_key_t key_next; 1122 int error; 1123 1124 if (hammer2_debug & 0x0001) 1125 kprintf("xop_inode_create: lhc %016jx clindex %d\n", 1126 xop->lhc, clindex); 1127 1128 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1129 HAMMER2_RESOLVE_ALWAYS); 1130 if (parent == NULL) { 1131 error = HAMMER2_ERROR_EIO; 1132 chain = NULL; 1133 goto fail; 1134 } 1135 chain = hammer2_chain_lookup(&parent, &key_next, 1136 xop->lhc, xop->lhc, 1137 &error, 0); 1138 if (chain) { 1139 error = HAMMER2_ERROR_EEXIST; 1140 goto fail; 1141 } 1142 1143 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp, 1144 HAMMER2_METH_DEFAULT, 1145 xop->lhc, 0, 1146 HAMMER2_BREF_TYPE_INODE, 1147 HAMMER2_INODE_BYTES, 1148 xop->head.mtid, 0, xop->flags); 1149 if (error == 0) { 1150 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1151 if (error == 0) { 1152 chain->data->ipdata.meta = xop->meta; 1153 if (xop->head.name1) { 1154 bcopy(xop->head.name1, 1155 chain->data->ipdata.filename, 1156 xop->head.name1_len); 1157 chain->data->ipdata.meta.name_len = 1158 xop->head.name1_len; 1159 } 1160 chain->data->ipdata.meta.name_key = xop->lhc; 1161 } 1162 } 1163 fail: 1164 if (parent) { 1165 hammer2_chain_unlock(parent); 1166 hammer2_chain_drop(parent); 1167 } 1168 hammer2_xop_feed(&xop->head, chain, clindex, error); 1169 if (chain) { 1170 hammer2_chain_unlock(chain); 1171 hammer2_chain_drop(chain); 1172 } 1173 } 1174 1175 /* 1176 * Create inode as above but leave it detached from the hierarchy. 1177 */ 1178 void 1179 hammer2_xop_inode_create_det(hammer2_xop_t *arg, void *scratch, int clindex) 1180 { 1181 hammer2_xop_create_t *xop = &arg->xop_create; 1182 hammer2_chain_t *parent; 1183 hammer2_chain_t *chain; 1184 hammer2_chain_t *null_parent; 1185 hammer2_key_t key_next; 1186 hammer2_inode_t *pip; 1187 hammer2_inode_t *iroot; 1188 int error; 1189 1190 if (hammer2_debug & 0x0001) 1191 kprintf("xop_inode_create_det: lhc %016jx clindex %d\n", 1192 xop->lhc, clindex); 1193 1194 pip = xop->head.ip1; 1195 iroot = pip->pmp->iroot; 1196 1197 parent = hammer2_inode_chain(iroot, clindex, HAMMER2_RESOLVE_ALWAYS); 1198 1199 if (parent == NULL) { 1200 error = HAMMER2_ERROR_EIO; 1201 chain = NULL; 1202 goto fail; 1203 } 1204 chain = hammer2_chain_lookup(&parent, &key_next, 1205 xop->lhc, xop->lhc, 1206 &error, 0); 1207 if (chain) { 1208 error = HAMMER2_ERROR_EEXIST; 1209 goto fail; 1210 } 1211 1212 /* 1213 * Create as a detached chain with no parent. We must specify 1214 * methods 1215 */ 1216 null_parent = NULL; 1217 error = hammer2_chain_create(&null_parent, &chain, 1218 parent->hmp, pip->pmp, 1219 HAMMER2_ENC_COMP(pip->meta.comp_algo) + 1220 HAMMER2_ENC_CHECK(pip->meta.check_algo), 1221 xop->lhc, 0, 1222 HAMMER2_BREF_TYPE_INODE, 1223 HAMMER2_INODE_BYTES, 1224 xop->head.mtid, 0, xop->flags); 1225 if (error == 0) { 1226 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1227 if (error == 0) { 1228 chain->data->ipdata.meta = xop->meta; 1229 if (xop->head.name1) { 1230 bcopy(xop->head.name1, 1231 chain->data->ipdata.filename, 1232 xop->head.name1_len); 1233 chain->data->ipdata.meta.name_len = 1234 xop->head.name1_len; 1235 } 1236 chain->data->ipdata.meta.name_key = xop->lhc; 1237 } 1238 } 1239 fail: 1240 if (parent) { 1241 hammer2_chain_unlock(parent); 1242 hammer2_chain_drop(parent); 1243 } 1244 hammer2_xop_feed(&xop->head, chain, clindex, error); 1245 if (chain) { 1246 hammer2_chain_unlock(chain); 1247 hammer2_chain_drop(chain); 1248 } 1249 } 1250 1251 /* 1252 * Take a detached chain and insert it into the topology 1253 */ 1254 void 1255 hammer2_xop_inode_create_ins(hammer2_xop_t *arg, void *scratch, int clindex) 1256 { 1257 hammer2_xop_create_t *xop = &arg->xop_create; 1258 hammer2_chain_t *parent; 1259 hammer2_chain_t *chain; 1260 hammer2_key_t key_next; 1261 int error; 1262 1263 if (hammer2_debug & 0x0001) 1264 kprintf("xop_inode_create_ins: lhc %016jx clindex %d\n", 1265 xop->lhc, clindex); 1266 1267 /* 1268 * (parent) will be the insertion point for inode under iroot 1269 */ 1270 parent = hammer2_inode_chain(xop->head.ip1->pmp->iroot, clindex, 1271 HAMMER2_RESOLVE_ALWAYS); 1272 if (parent == NULL) { 1273 error = HAMMER2_ERROR_EIO; 1274 chain = NULL; 1275 goto fail; 1276 } 1277 chain = hammer2_chain_lookup(&parent, &key_next, 1278 xop->lhc, xop->lhc, 1279 &error, 0); 1280 if (chain) { 1281 error = HAMMER2_ERROR_EEXIST; 1282 goto fail; 1283 } 1284 1285 /* 1286 * (chain) is the detached inode that is being inserted 1287 */ 1288 chain = hammer2_inode_chain(xop->head.ip1, clindex, 1289 HAMMER2_RESOLVE_ALWAYS); 1290 if (chain == NULL) { 1291 error = HAMMER2_ERROR_EIO; 1292 chain = NULL; 1293 goto fail; 1294 } 1295 1296 /* 1297 * This create call will insert the non-NULL chain into parent. 1298 * Most of the auxillary fields are ignored since the chain already 1299 * exists. 1300 */ 1301 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp, 1302 HAMMER2_METH_DEFAULT, 1303 xop->lhc, 0, 1304 HAMMER2_BREF_TYPE_INODE, 1305 HAMMER2_INODE_BYTES, 1306 xop->head.mtid, 0, xop->flags); 1307 #if 0 1308 if (error == 0) { 1309 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1310 if (error == 0) { 1311 chain->data->ipdata.meta = xop->meta; 1312 if (xop->head.name1) { 1313 bcopy(xop->head.name1, 1314 chain->data->ipdata.filename, 1315 xop->head.name1_len); 1316 chain->data->ipdata.meta.name_len = 1317 xop->head.name1_len; 1318 } 1319 chain->data->ipdata.meta.name_key = xop->lhc; 1320 } 1321 } 1322 #endif 1323 fail: 1324 if (parent) { 1325 hammer2_chain_unlock(parent); 1326 hammer2_chain_drop(parent); 1327 } 1328 hammer2_xop_feed(&xop->head, chain, clindex, error); 1329 if (chain) { 1330 hammer2_chain_unlock(chain); 1331 hammer2_chain_drop(chain); 1332 } 1333 } 1334 1335 /* 1336 * Inode delete helper (backend, threaded) 1337 * 1338 * Generally used by hammer2_run_sideq() 1339 */ 1340 void 1341 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex) 1342 { 1343 hammer2_xop_destroy_t *xop = &arg->xop_destroy; 1344 hammer2_chain_t *parent; 1345 hammer2_chain_t *chain; 1346 hammer2_inode_t *ip; 1347 int error; 1348 1349 /* 1350 * We need the precise parent chain to issue the deletion. 1351 */ 1352 ip = xop->head.ip1; 1353 1354 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 1355 if (chain == NULL) { 1356 parent = NULL; 1357 error = HAMMER2_ERROR_EIO; 1358 goto done; 1359 } 1360 1361 if (ip->flags & HAMMER2_INODE_CREATING) { 1362 /* 1363 * Inode's chains are not linked into the media topology 1364 * because it is a new inode (which is now being destroyed). 1365 */ 1366 parent = NULL; 1367 } else { 1368 /* 1369 * Inode's chains are linked into the media topology 1370 */ 1371 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS); 1372 if (parent == NULL) { 1373 error = HAMMER2_ERROR_EIO; 1374 goto done; 1375 } 1376 } 1377 KKASSERT(chain->parent == parent); 1378 1379 /* 1380 * We have the correct parent, we can issue the deletion. 1381 */ 1382 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 1383 error = 0; 1384 done: 1385 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1386 if (parent) { 1387 hammer2_chain_unlock(parent); 1388 hammer2_chain_drop(parent); 1389 } 1390 if (chain) { 1391 hammer2_chain_unlock(chain); 1392 hammer2_chain_drop(chain); 1393 } 1394 } 1395 1396 void 1397 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex) 1398 { 1399 hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall; 1400 hammer2_chain_t *parent; 1401 hammer2_chain_t *chain; 1402 hammer2_key_t key_next; 1403 int error; 1404 1405 /* 1406 * We need the precise parent chain to issue the deletion. 1407 */ 1408 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1409 HAMMER2_RESOLVE_ALWAYS); 1410 chain = NULL; 1411 if (parent == NULL) { 1412 error = 0; 1413 goto done; 1414 } 1415 chain = hammer2_chain_lookup(&parent, &key_next, 1416 xop->key_beg, xop->key_end, 1417 &error, HAMMER2_LOOKUP_ALWAYS); 1418 while (chain) { 1419 hammer2_chain_delete(parent, chain, 1420 xop->head.mtid, HAMMER2_DELETE_PERMANENT); 1421 hammer2_xop_feed(&xop->head, chain, clindex, chain->error); 1422 /* depend on function to unlock the shared lock */ 1423 chain = hammer2_chain_next(&parent, chain, &key_next, 1424 key_next, xop->key_end, 1425 &error, 1426 HAMMER2_LOOKUP_ALWAYS); 1427 } 1428 done: 1429 if (error == 0) 1430 error = HAMMER2_ERROR_ENOENT; 1431 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1432 if (parent) { 1433 hammer2_chain_unlock(parent); 1434 hammer2_chain_drop(parent); 1435 } 1436 if (chain) { 1437 hammer2_chain_unlock(chain); 1438 hammer2_chain_drop(chain); 1439 } 1440 } 1441 1442 void 1443 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex) 1444 { 1445 hammer2_xop_connect_t *xop = &arg->xop_connect; 1446 hammer2_inode_data_t *wipdata; 1447 hammer2_chain_t *parent; 1448 hammer2_chain_t *chain; 1449 hammer2_pfs_t *pmp; 1450 hammer2_key_t key_dummy; 1451 int error; 1452 1453 /* 1454 * Get directory, then issue a lookup to prime the parent chain 1455 * for the create. The lookup is expected to fail. 1456 */ 1457 pmp = xop->head.ip1->pmp; 1458 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1459 HAMMER2_RESOLVE_ALWAYS); 1460 if (parent == NULL) { 1461 chain = NULL; 1462 error = HAMMER2_ERROR_EIO; 1463 goto fail; 1464 } 1465 chain = hammer2_chain_lookup(&parent, &key_dummy, 1466 xop->lhc, xop->lhc, 1467 &error, 0); 1468 if (chain) { 1469 hammer2_chain_unlock(chain); 1470 hammer2_chain_drop(chain); 1471 chain = NULL; 1472 error = HAMMER2_ERROR_EEXIST; 1473 goto fail; 1474 } 1475 if (error) 1476 goto fail; 1477 1478 /* 1479 * Adjust the filename in the inode, set the name key. 1480 * 1481 * NOTE: Frontend must also adjust ip2->meta on success, we can't 1482 * do it here. 1483 */ 1484 chain = hammer2_inode_chain(xop->head.ip2, clindex, 1485 HAMMER2_RESOLVE_ALWAYS); 1486 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1487 if (error) 1488 goto fail; 1489 1490 wipdata = &chain->data->ipdata; 1491 1492 hammer2_inode_modify(xop->head.ip2); 1493 if (xop->head.name1) { 1494 bzero(wipdata->filename, sizeof(wipdata->filename)); 1495 bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len); 1496 wipdata->meta.name_len = xop->head.name1_len; 1497 } 1498 wipdata->meta.name_key = xop->lhc; 1499 1500 /* 1501 * Reconnect the chain to the new parent directory 1502 */ 1503 error = hammer2_chain_create(&parent, &chain, NULL, pmp, 1504 HAMMER2_METH_DEFAULT, 1505 xop->lhc, 0, 1506 HAMMER2_BREF_TYPE_INODE, 1507 HAMMER2_INODE_BYTES, 1508 xop->head.mtid, 0, 0); 1509 1510 /* 1511 * Feed result back. 1512 */ 1513 fail: 1514 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1515 if (parent) { 1516 hammer2_chain_unlock(parent); 1517 hammer2_chain_drop(parent); 1518 } 1519 if (chain) { 1520 hammer2_chain_unlock(chain); 1521 hammer2_chain_drop(chain); 1522 } 1523 } 1524 1525 /* 1526 * Synchronize the in-memory inode with the chain. This does not flush 1527 * the chain to disk. Instead, it makes front-end inode changes visible 1528 * in the chain topology, thus visible to the backend. This is done in an 1529 * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled 1530 * manner inside the vfs_sync. 1531 */ 1532 void 1533 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex) 1534 { 1535 hammer2_xop_fsync_t *xop = &arg->xop_fsync; 1536 hammer2_chain_t *parent; 1537 hammer2_chain_t *chain; 1538 int error; 1539 1540 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1541 HAMMER2_RESOLVE_ALWAYS); 1542 chain = NULL; 1543 if (parent == NULL) { 1544 error = HAMMER2_ERROR_EIO; 1545 goto done; 1546 } 1547 if (parent->error) { 1548 error = parent->error; 1549 goto done; 1550 } 1551 1552 error = 0; 1553 1554 if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) { 1555 /* osize must be ignored */ 1556 } else if (xop->meta.size < xop->osize) { 1557 /* 1558 * We must delete any chains beyond the EOF. The chain 1559 * straddling the EOF will be pending in the bioq. 1560 */ 1561 hammer2_key_t lbase; 1562 hammer2_key_t key_next; 1563 1564 lbase = (xop->meta.size + HAMMER2_PBUFMASK64) & 1565 ~HAMMER2_PBUFMASK64; 1566 chain = hammer2_chain_lookup(&parent, &key_next, 1567 lbase, HAMMER2_KEY_MAX, 1568 &error, 1569 HAMMER2_LOOKUP_NODATA | 1570 HAMMER2_LOOKUP_NODIRECT); 1571 while (chain) { 1572 /* 1573 * Degenerate embedded case, nothing to loop on 1574 */ 1575 switch (chain->bref.type) { 1576 case HAMMER2_BREF_TYPE_DIRENT: 1577 case HAMMER2_BREF_TYPE_INODE: 1578 KKASSERT(0); 1579 break; 1580 case HAMMER2_BREF_TYPE_DATA: 1581 hammer2_chain_delete(parent, chain, 1582 xop->head.mtid, 1583 HAMMER2_DELETE_PERMANENT); 1584 break; 1585 } 1586 chain = hammer2_chain_next(&parent, chain, &key_next, 1587 key_next, HAMMER2_KEY_MAX, 1588 &error, 1589 HAMMER2_LOOKUP_NODATA | 1590 HAMMER2_LOOKUP_NODIRECT); 1591 } 1592 1593 /* 1594 * Reset to point at inode for following code, if necessary. 1595 */ 1596 if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) { 1597 hammer2_chain_unlock(parent); 1598 hammer2_chain_drop(parent); 1599 parent = hammer2_inode_chain(xop->head.ip1, 1600 clindex, 1601 HAMMER2_RESOLVE_ALWAYS); 1602 kprintf("xop_inode_chain_sync: TRUNCATE RESET on '%s'\n", 1603 parent->data->ipdata.filename); 1604 } 1605 } 1606 1607 /* 1608 * Sync the inode meta-data, potentially clear the blockset area 1609 * of direct data so it can be used for blockrefs. 1610 */ 1611 if (error == 0) { 1612 error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0); 1613 if (error == 0) { 1614 parent->data->ipdata.meta = xop->meta; 1615 if (xop->clear_directdata) { 1616 bzero(&parent->data->ipdata.u.blockset, 1617 sizeof(parent->data->ipdata.u.blockset)); 1618 } 1619 } 1620 } 1621 done: 1622 if (chain) { 1623 hammer2_chain_unlock(chain); 1624 hammer2_chain_drop(chain); 1625 } 1626 if (parent) { 1627 hammer2_chain_unlock(parent); 1628 hammer2_chain_drop(parent); 1629 } 1630 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1631 } 1632