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_xop_t *arg, void *scratch, int clindex) 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, 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, 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_xop_t *arg, void *scratch, int clindex) 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, 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, 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, clindex, error); 242 } 243 244 /* 245 * Backend for hammer2_vop_nresolve() 246 */ 247 void 248 hammer2_xop_nresolve(hammer2_xop_t *arg, void *scratch, int clindex) 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, 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 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, 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_xop_t *arg, void *scratch, int clindex) 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, 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, 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_EISDIR; 438 } else if (type != HAMMER2_OBJTYPE_DIRECTORY && 439 xop->isdir >= 1) { 440 error = HAMMER2_ERROR_ENOTDIR; 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 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, 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_xop_t *arg, void *scratch, int clindex) 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, 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, 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, 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, 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_xop_t *arg, void *scratch, int clindex) 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, 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, 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, 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 void 839 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex) 840 { 841 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 842 hammer2_chain_t *parent; 843 hammer2_chain_t *chain; 844 hammer2_key_t key_next; 845 int error = 0; 846 847 parent = hammer2_inode_chain(xop->head.ip1, clindex, 848 HAMMER2_RESOLVE_ALWAYS | 849 HAMMER2_RESOLVE_SHARED); 850 chain = NULL; 851 if (parent == NULL) { 852 error = HAMMER2_ERROR_EIO; 853 goto done; 854 } 855 856 /* 857 * Lookup all possibly conflicting directory entries, the feed 858 * inherits the chain's lock so do not unlock it on the iteration. 859 */ 860 chain = hammer2_chain_lookup(&parent, &key_next, 861 xop->lhc, xop->lhc, 862 &error, 863 HAMMER2_LOOKUP_ALWAYS | 864 HAMMER2_LOOKUP_SHARED); 865 if (error == 0) { 866 if (chain) 867 error = chain->error; 868 else 869 error = HAMMER2_ERROR_ENOENT; 870 } 871 hammer2_xop_feed(&xop->head, chain, clindex, error); 872 873 done: 874 if (chain) { 875 hammer2_chain_unlock(chain); 876 hammer2_chain_drop(chain); 877 } 878 if (parent) { 879 hammer2_chain_unlock(parent); 880 hammer2_chain_drop(parent); 881 } 882 } 883 884 void 885 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex) 886 { 887 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 888 hammer2_chain_t *parent; 889 hammer2_chain_t *chain; 890 hammer2_key_t key_next; 891 int error = 0; 892 893 parent = hammer2_inode_chain(xop->head.ip1, clindex, 894 HAMMER2_RESOLVE_ALWAYS); 895 chain = NULL; 896 if (parent == NULL) { 897 error = HAMMER2_ERROR_EIO; 898 goto done; 899 } 900 901 /* 902 * Lookup all possibly conflicting directory entries, the feed 903 * inherits the chain's lock so do not unlock it on the iteration. 904 */ 905 chain = hammer2_chain_lookup(&parent, &key_next, 906 xop->lhc, xop->lhc, 907 &error, 908 HAMMER2_LOOKUP_NODATA); 909 if (error == 0) { 910 if (chain) 911 error = chain->error; 912 else 913 error = HAMMER2_ERROR_ENOENT; 914 } 915 if (chain) { 916 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 917 HAMMER2_DELETE_PERMANENT); 918 } 919 hammer2_xop_feed(&xop->head, NULL, clindex, error); 920 921 done: 922 if (chain) { 923 hammer2_chain_unlock(chain); 924 hammer2_chain_drop(chain); 925 } 926 if (parent) { 927 hammer2_chain_unlock(parent); 928 hammer2_chain_drop(parent); 929 } 930 } 931 932 /* 933 * Generic scan 934 * 935 * WARNING! Fed chains must be locked shared so ownership can be transfered 936 * and to prevent frontend/backend stalls that would occur with an 937 * exclusive lock. The shared lock also allows chain->data to be 938 * retained. 939 */ 940 void 941 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex) 942 { 943 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 944 hammer2_chain_t *parent; 945 hammer2_chain_t *chain; 946 hammer2_key_t key_next; 947 int error = 0; 948 949 /* 950 * Assert required flags. 951 */ 952 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 953 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 954 955 /* 956 * The inode's chain is the iterator. If we cannot acquire it our 957 * contribution ends here. 958 */ 959 parent = hammer2_inode_chain(xop->head.ip1, clindex, 960 xop->resolve_flags); 961 if (parent == NULL) { 962 kprintf("xop_readdir: NULL parent\n"); 963 goto done; 964 } 965 966 /* 967 * Generic scan of exact records. Note that indirect blocks are 968 * automatically recursed and will not be returned. 969 */ 970 chain = hammer2_chain_lookup(&parent, &key_next, 971 xop->key_beg, xop->key_end, 972 &error, xop->lookup_flags); 973 while (chain) { 974 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 975 if (error) 976 goto break2; 977 chain = hammer2_chain_next(&parent, chain, &key_next, 978 key_next, xop->key_end, 979 &error, xop->lookup_flags); 980 } 981 break2: 982 if (chain) { 983 hammer2_chain_unlock(chain); 984 hammer2_chain_drop(chain); 985 } 986 hammer2_chain_unlock(parent); 987 hammer2_chain_drop(parent); 988 done: 989 hammer2_xop_feed(&xop->head, NULL, clindex, error); 990 } 991 992 /************************************************************************ 993 * INODE LAYER XOPS * 994 ************************************************************************ 995 * 996 */ 997 /* 998 * Helper to create a directory entry. 999 */ 1000 void 1001 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex) 1002 { 1003 hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent; 1004 hammer2_chain_t *parent; 1005 hammer2_chain_t *chain; 1006 hammer2_key_t key_next; 1007 size_t data_len; 1008 int error; 1009 1010 if (hammer2_debug & 0x0001) 1011 kprintf("dirent_create lhc %016jx clindex %d\n", 1012 xop->lhc, clindex); 1013 1014 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1015 HAMMER2_RESOLVE_ALWAYS); 1016 if (parent == NULL) { 1017 error = HAMMER2_ERROR_EIO; 1018 chain = NULL; 1019 goto fail; 1020 } 1021 chain = hammer2_chain_lookup(&parent, &key_next, 1022 xop->lhc, xop->lhc, 1023 &error, 0); 1024 if (chain) { 1025 error = HAMMER2_ERROR_EEXIST; 1026 goto fail; 1027 } 1028 1029 /* 1030 * We may be able to embed the directory entry directly in the 1031 * blockref. 1032 */ 1033 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf)) 1034 data_len = 0; 1035 else 1036 data_len = HAMMER2_ALLOC_MIN; 1037 1038 error = hammer2_chain_create(&parent, &chain, 1039 xop->head.ip1->pmp, HAMMER2_METH_DEFAULT, 1040 xop->lhc, 0, 1041 HAMMER2_BREF_TYPE_DIRENT, 1042 data_len, 1043 xop->head.mtid, 0, 0); 1044 if (error == 0) { 1045 /* 1046 * WARNING: chain->data->buf is sized to chain->bytes, 1047 * do not use sizeof(chain->data->buf), which 1048 * will be much larger. 1049 */ 1050 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1051 if (error == 0) { 1052 chain->bref.embed.dirent = xop->dirent; 1053 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf)) 1054 bcopy(xop->head.name1, chain->bref.check.buf, 1055 xop->dirent.namlen); 1056 else 1057 bcopy(xop->head.name1, chain->data->buf, 1058 xop->dirent.namlen); 1059 } 1060 } 1061 fail: 1062 if (parent) { 1063 hammer2_chain_unlock(parent); 1064 hammer2_chain_drop(parent); 1065 } 1066 hammer2_xop_feed(&xop->head, chain, clindex, error); 1067 if (chain) { 1068 hammer2_chain_unlock(chain); 1069 hammer2_chain_drop(chain); 1070 } 1071 } 1072 1073 /* 1074 * Inode create helper (threaded, backend) 1075 * 1076 * Used by ncreate, nmknod, nsymlink, nmkdir. 1077 * Used by nlink and rename to create HARDLINK pointers. 1078 * 1079 * Frontend holds the parent directory ip locked exclusively. We 1080 * create the inode and feed the exclusively locked chain to the 1081 * frontend. 1082 */ 1083 void 1084 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex) 1085 { 1086 hammer2_xop_create_t *xop = &arg->xop_create; 1087 hammer2_chain_t *parent; 1088 hammer2_chain_t *chain; 1089 hammer2_key_t key_next; 1090 int error; 1091 1092 if (hammer2_debug & 0x0001) 1093 kprintf("inode_create lhc %016jx clindex %d\n", 1094 xop->lhc, clindex); 1095 1096 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1097 HAMMER2_RESOLVE_ALWAYS); 1098 if (parent == NULL) { 1099 error = HAMMER2_ERROR_EIO; 1100 chain = NULL; 1101 goto fail; 1102 } 1103 chain = hammer2_chain_lookup(&parent, &key_next, 1104 xop->lhc, xop->lhc, 1105 &error, 0); 1106 if (chain) { 1107 error = HAMMER2_ERROR_EEXIST; 1108 goto fail; 1109 } 1110 1111 error = hammer2_chain_create(&parent, &chain, 1112 xop->head.ip1->pmp, HAMMER2_METH_DEFAULT, 1113 xop->lhc, 0, 1114 HAMMER2_BREF_TYPE_INODE, 1115 HAMMER2_INODE_BYTES, 1116 xop->head.mtid, 0, xop->flags); 1117 if (error == 0) { 1118 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1119 if (error == 0) { 1120 chain->data->ipdata.meta = xop->meta; 1121 if (xop->head.name1) { 1122 bcopy(xop->head.name1, 1123 chain->data->ipdata.filename, 1124 xop->head.name1_len); 1125 chain->data->ipdata.meta.name_len = 1126 xop->head.name1_len; 1127 } 1128 chain->data->ipdata.meta.name_key = xop->lhc; 1129 } 1130 } 1131 fail: 1132 if (parent) { 1133 hammer2_chain_unlock(parent); 1134 hammer2_chain_drop(parent); 1135 } 1136 hammer2_xop_feed(&xop->head, chain, clindex, error); 1137 if (chain) { 1138 hammer2_chain_unlock(chain); 1139 hammer2_chain_drop(chain); 1140 } 1141 } 1142 1143 /* 1144 * Inode delete helper (backend, threaded) 1145 * 1146 * Generally used by hammer2_run_sideq() 1147 */ 1148 void 1149 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex) 1150 { 1151 hammer2_xop_destroy_t *xop = &arg->xop_destroy; 1152 hammer2_pfs_t *pmp; 1153 hammer2_chain_t *parent; 1154 hammer2_chain_t *chain; 1155 hammer2_inode_t *ip; 1156 int error; 1157 1158 /* 1159 * We need the precise parent chain to issue the deletion. 1160 */ 1161 ip = xop->head.ip1; 1162 pmp = ip->pmp; 1163 1164 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 1165 if (chain == NULL) { 1166 parent = NULL; 1167 error = HAMMER2_ERROR_EIO; 1168 goto done; 1169 } 1170 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS); 1171 if (parent == NULL) { 1172 error = HAMMER2_ERROR_EIO; 1173 goto done; 1174 } 1175 KKASSERT(chain->parent == parent); 1176 1177 /* 1178 * We have the correct parent, we can issue the deletion. 1179 */ 1180 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 1181 error = 0; 1182 done: 1183 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1184 if (parent) { 1185 hammer2_chain_unlock(parent); 1186 hammer2_chain_drop(parent); 1187 } 1188 if (chain) { 1189 hammer2_chain_unlock(chain); 1190 hammer2_chain_drop(chain); 1191 } 1192 } 1193 1194 void 1195 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex) 1196 { 1197 hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall; 1198 hammer2_chain_t *parent; 1199 hammer2_chain_t *chain; 1200 hammer2_key_t key_next; 1201 int error; 1202 1203 /* 1204 * We need the precise parent chain to issue the deletion. 1205 */ 1206 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1207 HAMMER2_RESOLVE_ALWAYS); 1208 chain = NULL; 1209 if (parent == NULL) { 1210 error = 0; 1211 goto done; 1212 } 1213 chain = hammer2_chain_lookup(&parent, &key_next, 1214 xop->key_beg, xop->key_end, 1215 &error, HAMMER2_LOOKUP_ALWAYS); 1216 while (chain) { 1217 hammer2_chain_delete(parent, chain, 1218 xop->head.mtid, HAMMER2_DELETE_PERMANENT); 1219 hammer2_xop_feed(&xop->head, chain, clindex, chain->error); 1220 /* depend on function to unlock the shared lock */ 1221 chain = hammer2_chain_next(&parent, chain, &key_next, 1222 key_next, xop->key_end, 1223 &error, 1224 HAMMER2_LOOKUP_ALWAYS); 1225 } 1226 done: 1227 if (error == 0) 1228 error = HAMMER2_ERROR_ENOENT; 1229 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1230 if (parent) { 1231 hammer2_chain_unlock(parent); 1232 hammer2_chain_drop(parent); 1233 } 1234 if (chain) { 1235 hammer2_chain_unlock(chain); 1236 hammer2_chain_drop(chain); 1237 } 1238 } 1239 1240 void 1241 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex) 1242 { 1243 hammer2_xop_connect_t *xop = &arg->xop_connect; 1244 hammer2_inode_data_t *wipdata; 1245 hammer2_chain_t *parent; 1246 hammer2_chain_t *chain; 1247 hammer2_pfs_t *pmp; 1248 hammer2_key_t key_dummy; 1249 int error; 1250 1251 /* 1252 * Get directory, then issue a lookup to prime the parent chain 1253 * for the create. The lookup is expected to fail. 1254 */ 1255 pmp = xop->head.ip1->pmp; 1256 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1257 HAMMER2_RESOLVE_ALWAYS); 1258 if (parent == NULL) { 1259 chain = NULL; 1260 error = HAMMER2_ERROR_EIO; 1261 goto fail; 1262 } 1263 chain = hammer2_chain_lookup(&parent, &key_dummy, 1264 xop->lhc, xop->lhc, 1265 &error, 0); 1266 if (chain) { 1267 hammer2_chain_unlock(chain); 1268 hammer2_chain_drop(chain); 1269 chain = NULL; 1270 error = HAMMER2_ERROR_EEXIST; 1271 goto fail; 1272 } 1273 if (error) 1274 goto fail; 1275 1276 /* 1277 * Adjust the filename in the inode, set the name key. 1278 * 1279 * NOTE: Frontend must also adjust ip2->meta on success, we can't 1280 * do it here. 1281 */ 1282 chain = hammer2_inode_chain(xop->head.ip2, clindex, 1283 HAMMER2_RESOLVE_ALWAYS); 1284 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1285 if (error) 1286 goto fail; 1287 1288 wipdata = &chain->data->ipdata; 1289 1290 hammer2_inode_modify(xop->head.ip2); 1291 if (xop->head.name1) { 1292 bzero(wipdata->filename, sizeof(wipdata->filename)); 1293 bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len); 1294 wipdata->meta.name_len = xop->head.name1_len; 1295 } 1296 wipdata->meta.name_key = xop->lhc; 1297 1298 /* 1299 * Reconnect the chain to the new parent directory 1300 */ 1301 error = hammer2_chain_create(&parent, &chain, 1302 pmp, HAMMER2_METH_DEFAULT, 1303 xop->lhc, 0, 1304 HAMMER2_BREF_TYPE_INODE, 1305 HAMMER2_INODE_BYTES, 1306 xop->head.mtid, 0, 0); 1307 1308 /* 1309 * Feed result back. 1310 */ 1311 fail: 1312 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1313 if (parent) { 1314 hammer2_chain_unlock(parent); 1315 hammer2_chain_drop(parent); 1316 } 1317 if (chain) { 1318 hammer2_chain_unlock(chain); 1319 hammer2_chain_drop(chain); 1320 } 1321 } 1322 1323 /* 1324 * Synchronize the in-memory inode with the chain. This does not flush 1325 * the chain to disk. Instead, it makes front-end inode changes visible 1326 * in the chain topology, thus visible to the backend. This is done in an 1327 * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled 1328 * manner inside the vfs_sync. 1329 */ 1330 void 1331 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex) 1332 { 1333 hammer2_xop_fsync_t *xop = &arg->xop_fsync; 1334 hammer2_chain_t *parent; 1335 hammer2_chain_t *chain; 1336 int error; 1337 1338 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1339 HAMMER2_RESOLVE_ALWAYS); 1340 chain = NULL; 1341 if (parent == NULL) { 1342 error = HAMMER2_ERROR_EIO; 1343 goto done; 1344 } 1345 if (parent->error) { 1346 error = parent->error; 1347 goto done; 1348 } 1349 1350 error = 0; 1351 1352 if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) { 1353 /* osize must be ignored */ 1354 } else if (xop->meta.size < xop->osize) { 1355 /* 1356 * We must delete any chains beyond the EOF. The chain 1357 * straddling the EOF will be pending in the bioq. 1358 */ 1359 hammer2_key_t lbase; 1360 hammer2_key_t key_next; 1361 1362 lbase = (xop->meta.size + HAMMER2_PBUFMASK64) & 1363 ~HAMMER2_PBUFMASK64; 1364 chain = hammer2_chain_lookup(&parent, &key_next, 1365 lbase, HAMMER2_KEY_MAX, 1366 &error, 1367 HAMMER2_LOOKUP_NODATA | 1368 HAMMER2_LOOKUP_NODIRECT); 1369 while (chain) { 1370 /* 1371 * Degenerate embedded case, nothing to loop on 1372 */ 1373 switch (chain->bref.type) { 1374 case HAMMER2_BREF_TYPE_DIRENT: 1375 case HAMMER2_BREF_TYPE_INODE: 1376 KKASSERT(0); 1377 break; 1378 case HAMMER2_BREF_TYPE_DATA: 1379 hammer2_chain_delete(parent, chain, 1380 xop->head.mtid, 1381 HAMMER2_DELETE_PERMANENT); 1382 break; 1383 } 1384 chain = hammer2_chain_next(&parent, chain, &key_next, 1385 key_next, HAMMER2_KEY_MAX, 1386 &error, 1387 HAMMER2_LOOKUP_NODATA | 1388 HAMMER2_LOOKUP_NODIRECT); 1389 } 1390 1391 /* 1392 * Reset to point at inode for following code, if necessary. 1393 */ 1394 if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) { 1395 hammer2_chain_unlock(parent); 1396 hammer2_chain_drop(parent); 1397 parent = hammer2_inode_chain(xop->head.ip1, 1398 clindex, 1399 HAMMER2_RESOLVE_ALWAYS); 1400 kprintf("hammer2: TRUNCATE RESET on '%s'\n", 1401 parent->data->ipdata.filename); 1402 } 1403 } 1404 1405 /* 1406 * Sync the inode meta-data, potentially clear the blockset area 1407 * of direct data so it can be used for blockrefs. 1408 */ 1409 if (error == 0) { 1410 error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0); 1411 if (error == 0) { 1412 parent->data->ipdata.meta = xop->meta; 1413 if (xop->clear_directdata) { 1414 bzero(&parent->data->ipdata.u.blockset, 1415 sizeof(parent->data->ipdata.u.blockset)); 1416 } 1417 } 1418 } 1419 done: 1420 if (chain) { 1421 hammer2_chain_unlock(chain); 1422 hammer2_chain_drop(chain); 1423 } 1424 if (parent) { 1425 hammer2_chain_unlock(parent); 1426 hammer2_chain_drop(parent); 1427 } 1428 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1429 } 1430