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