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