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_unlink: 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("xop_unlink: %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("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 if (parent) { 633 hammer2_chain_unlock(parent); 634 hammer2_chain_drop(parent); 635 parent = NULL; /* safety */ 636 } else { 637 kprintf("hammer2_xop_nrename() (debugging): parent was NULL\n"); 638 error = EINVAL; 639 } 640 if (error) 641 goto done; 642 643 /* 644 * Adjust fields in the deleted chain appropriate for the rename 645 * operation. 646 * 647 * NOTE! For embedded inodes, the frontend will officially replicate 648 * the field adjustments, but we also do it here to maintain 649 * consistency in case of a crash. 650 */ 651 if (chain->bref.key != xop->lhc || 652 xop->head.name1_len != xop->head.name2_len || 653 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) { 654 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { 655 hammer2_inode_data_t *wipdata; 656 657 error = hammer2_chain_modify(chain, xop->head.mtid, 658 0, 0); 659 if (error == 0) { 660 wipdata = &chain->data->ipdata; 661 662 bzero(wipdata->filename, 663 sizeof(wipdata->filename)); 664 bcopy(xop->head.name2, 665 wipdata->filename, 666 xop->head.name2_len); 667 wipdata->meta.name_key = xop->lhc; 668 wipdata->meta.name_len = xop->head.name2_len; 669 } 670 } 671 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) { 672 if (xop->head.name2_len <= 673 sizeof(chain->bref.check.buf)) { 674 /* 675 * Remove any related data buffer, we can 676 * embed the filename in the bref itself. 677 */ 678 error = hammer2_chain_resize( 679 chain, xop->head.mtid, 0, 0, 0); 680 if (error == 0) { 681 error = hammer2_chain_modify( 682 chain, xop->head.mtid, 683 0, 0); 684 } 685 if (error == 0) { 686 bzero(chain->bref.check.buf, 687 sizeof(chain->bref.check.buf)); 688 bcopy(xop->head.name2, 689 chain->bref.check.buf, 690 xop->head.name2_len); 691 } 692 } else { 693 /* 694 * Associate a data buffer with the bref. 695 * Zero it for consistency. Note that the 696 * data buffer is not 64KB so use chain->bytes 697 * instead of sizeof(). 698 */ 699 error = hammer2_chain_resize( 700 chain, xop->head.mtid, 0, 701 hammer2_getradix(HAMMER2_ALLOC_MIN), 0); 702 if (error == 0) { 703 error = hammer2_chain_modify( 704 chain, xop->head.mtid, 705 0, 0); 706 } 707 if (error == 0) { 708 bzero(chain->data->buf, chain->bytes); 709 bcopy(xop->head.name2, 710 chain->data->buf, 711 xop->head.name2_len); 712 } 713 } 714 if (error == 0) { 715 chain->bref.embed.dirent.namlen = 716 xop->head.name2_len; 717 } 718 } 719 } 720 721 /* 722 * The frontend will replicate this operation and is the real final 723 * authority, but adjust the inode's iparent field too if the inode 724 * is embedded in the directory. 725 */ 726 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 727 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) { 728 hammer2_inode_data_t *wipdata; 729 730 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 731 if (error == 0) { 732 wipdata = &chain->data->ipdata; 733 wipdata->meta.iparent = xop->head.ip3->meta.inum; 734 } 735 } 736 737 /* 738 * Destroy any matching target(s) before creating the new entry. 739 * This will result in some ping-ponging of the directory key 740 * iterator but that is ok. 741 */ 742 parent = hammer2_inode_chain(xop->head.ip3, clindex, 743 HAMMER2_RESOLVE_ALWAYS); 744 if (parent == NULL) { 745 error = HAMMER2_ERROR_EIO; 746 goto done; 747 } 748 749 /* 750 * Delete all matching directory entries. That is, get rid of 751 * multiple duplicates if present, as a self-healing mechanism. 752 */ 753 if (error == 0) { 754 tmp = hammer2_chain_lookup(&parent, &key_next, 755 xop->lhc & ~HAMMER2_DIRHASH_LOMASK, 756 xop->lhc | HAMMER2_DIRHASH_LOMASK, 757 &error, 758 HAMMER2_LOOKUP_ALWAYS); 759 while (tmp) { 760 int e2; 761 if (hammer2_chain_dirent_test(tmp, xop->head.name2, 762 xop->head.name2_len)) { 763 e2 = hammer2_chain_delete(parent, tmp, 764 xop->head.mtid, 0); 765 if (error == 0 && e2) 766 error = e2; 767 } 768 tmp = hammer2_chain_next(&parent, tmp, &key_next, 769 key_next, 770 xop->lhc | 771 HAMMER2_DIRHASH_LOMASK, 772 &error, 773 HAMMER2_LOOKUP_ALWAYS); 774 } 775 } 776 if (error == 0) { 777 /* 778 * A relookup is required before the create to properly 779 * position the parent chain. 780 */ 781 tmp = hammer2_chain_lookup(&parent, &key_next, 782 xop->lhc, xop->lhc, 783 &error, 0); 784 KKASSERT(tmp == NULL); 785 error = hammer2_chain_create(&parent, &chain, NULL, pmp, 786 HAMMER2_METH_DEFAULT, 787 xop->lhc, 0, 788 HAMMER2_BREF_TYPE_INODE, 789 HAMMER2_INODE_BYTES, 790 xop->head.mtid, 0, 0); 791 } 792 done: 793 hammer2_xop_feed(&xop->head, NULL, clindex, error); 794 if (parent) { 795 hammer2_chain_unlock(parent); 796 hammer2_chain_drop(parent); 797 } 798 if (chain) { 799 hammer2_chain_unlock(chain); 800 hammer2_chain_drop(chain); 801 } 802 } 803 804 /* 805 * Directory collision resolver scan helper (backend, threaded). 806 * 807 * Used by the inode create code to locate an unused lhc. 808 */ 809 void 810 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex) 811 { 812 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 813 hammer2_chain_t *parent; 814 hammer2_chain_t *chain; 815 hammer2_key_t key_next; 816 int error = 0; 817 818 parent = hammer2_inode_chain(xop->head.ip1, clindex, 819 HAMMER2_RESOLVE_ALWAYS | 820 HAMMER2_RESOLVE_SHARED); 821 if (parent == NULL) { 822 kprintf("xop_scanlhc: NULL parent\n"); 823 chain = NULL; 824 error = HAMMER2_ERROR_EIO; 825 goto done; 826 } 827 828 /* 829 * Lookup all possibly conflicting directory entries, the feed 830 * inherits the chain's lock so do not unlock it on the iteration. 831 */ 832 chain = hammer2_chain_lookup(&parent, &key_next, 833 xop->lhc, 834 xop->lhc + HAMMER2_DIRHASH_LOMASK, 835 &error, 836 HAMMER2_LOOKUP_ALWAYS | 837 HAMMER2_LOOKUP_SHARED); 838 while (chain) { 839 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 840 if (error) { 841 hammer2_chain_unlock(chain); 842 hammer2_chain_drop(chain); 843 chain = NULL; /* safety */ 844 goto done; 845 } 846 chain = hammer2_chain_next(&parent, chain, &key_next, 847 key_next, 848 xop->lhc + HAMMER2_DIRHASH_LOMASK, 849 &error, 850 HAMMER2_LOOKUP_ALWAYS | 851 HAMMER2_LOOKUP_SHARED); 852 } 853 done: 854 hammer2_xop_feed(&xop->head, NULL, clindex, error); 855 if (parent) { 856 hammer2_chain_unlock(parent); 857 hammer2_chain_drop(parent); 858 } 859 } 860 861 /* 862 * Generic lookup of a specific key. 863 */ 864 void 865 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex) 866 { 867 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 868 hammer2_chain_t *parent; 869 hammer2_chain_t *chain; 870 hammer2_key_t key_next; 871 int error = 0; 872 873 parent = hammer2_inode_chain(xop->head.ip1, clindex, 874 HAMMER2_RESOLVE_ALWAYS | 875 HAMMER2_RESOLVE_SHARED); 876 chain = NULL; 877 if (parent == NULL) { 878 error = HAMMER2_ERROR_EIO; 879 goto done; 880 } 881 882 /* 883 * Lookup all possibly conflicting directory entries, the feed 884 * inherits the chain's lock so do not unlock it on the iteration. 885 */ 886 chain = hammer2_chain_lookup(&parent, &key_next, 887 xop->lhc, xop->lhc, 888 &error, 889 HAMMER2_LOOKUP_ALWAYS | 890 HAMMER2_LOOKUP_SHARED); 891 if (error == 0) { 892 if (chain) 893 error = chain->error; 894 else 895 error = HAMMER2_ERROR_ENOENT; 896 } 897 hammer2_xop_feed(&xop->head, chain, clindex, error); 898 899 done: 900 if (chain) { 901 hammer2_chain_unlock(chain); 902 hammer2_chain_drop(chain); 903 } 904 if (parent) { 905 hammer2_chain_unlock(parent); 906 hammer2_chain_drop(parent); 907 } 908 } 909 910 void 911 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex) 912 { 913 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 914 hammer2_chain_t *parent; 915 hammer2_chain_t *chain; 916 hammer2_key_t key_next; 917 int error = 0; 918 919 parent = hammer2_inode_chain(xop->head.ip1, clindex, 920 HAMMER2_RESOLVE_ALWAYS); 921 chain = NULL; 922 if (parent == NULL) { 923 error = HAMMER2_ERROR_EIO; 924 goto done; 925 } 926 927 /* 928 * Lookup all possibly conflicting directory entries, the feed 929 * inherits the chain's lock so do not unlock it on the iteration. 930 */ 931 chain = hammer2_chain_lookup(&parent, &key_next, 932 xop->lhc, xop->lhc, 933 &error, 934 HAMMER2_LOOKUP_NODATA); 935 if (error == 0) { 936 if (chain) 937 error = chain->error; 938 else 939 error = HAMMER2_ERROR_ENOENT; 940 } 941 if (chain) { 942 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 943 HAMMER2_DELETE_PERMANENT); 944 } 945 hammer2_xop_feed(&xop->head, NULL, clindex, error); 946 947 done: 948 if (chain) { 949 hammer2_chain_unlock(chain); 950 hammer2_chain_drop(chain); 951 } 952 if (parent) { 953 hammer2_chain_unlock(parent); 954 hammer2_chain_drop(parent); 955 } 956 } 957 958 /* 959 * Generic scan 960 * 961 * WARNING! Fed chains must be locked shared so ownership can be transfered 962 * and to prevent frontend/backend stalls that would occur with an 963 * exclusive lock. The shared lock also allows chain->data to be 964 * retained. 965 */ 966 void 967 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex) 968 { 969 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 970 hammer2_chain_t *parent; 971 hammer2_chain_t *chain; 972 hammer2_key_t key_next; 973 int error = 0; 974 975 /* 976 * Assert required flags. 977 */ 978 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 979 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 980 981 /* 982 * The inode's chain is the iterator. If we cannot acquire it our 983 * contribution ends here. 984 */ 985 parent = hammer2_inode_chain(xop->head.ip1, clindex, 986 xop->resolve_flags); 987 if (parent == NULL) { 988 kprintf("xop_scanall: NULL parent\n"); 989 goto done; 990 } 991 992 /* 993 * Generic scan of exact records. Note that indirect blocks are 994 * automatically recursed and will not be returned. 995 */ 996 chain = hammer2_chain_lookup(&parent, &key_next, 997 xop->key_beg, xop->key_end, 998 &error, xop->lookup_flags); 999 while (chain) { 1000 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 1001 if (error) 1002 goto break2; 1003 chain = hammer2_chain_next(&parent, chain, &key_next, 1004 key_next, xop->key_end, 1005 &error, xop->lookup_flags); 1006 } 1007 break2: 1008 if (chain) { 1009 hammer2_chain_unlock(chain); 1010 hammer2_chain_drop(chain); 1011 } 1012 hammer2_chain_unlock(parent); 1013 hammer2_chain_drop(parent); 1014 done: 1015 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1016 } 1017 1018 /************************************************************************ 1019 * INODE LAYER XOPS * 1020 ************************************************************************ 1021 * 1022 */ 1023 /* 1024 * Helper to create a directory entry. 1025 */ 1026 void 1027 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex) 1028 { 1029 hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent; 1030 hammer2_chain_t *parent; 1031 hammer2_chain_t *chain; 1032 hammer2_key_t key_next; 1033 size_t data_len; 1034 int error; 1035 1036 if (hammer2_debug & 0x0001) 1037 kprintf("xop_inode_mkdirent: lhc %016jx clindex %d\n", 1038 xop->lhc, clindex); 1039 1040 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1041 HAMMER2_RESOLVE_ALWAYS); 1042 if (parent == NULL) { 1043 error = HAMMER2_ERROR_EIO; 1044 chain = NULL; 1045 goto fail; 1046 } 1047 chain = hammer2_chain_lookup(&parent, &key_next, 1048 xop->lhc, xop->lhc, 1049 &error, 0); 1050 if (chain) { 1051 error = HAMMER2_ERROR_EEXIST; 1052 goto fail; 1053 } 1054 1055 /* 1056 * We may be able to embed the directory entry directly in the 1057 * blockref. 1058 */ 1059 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf)) 1060 data_len = 0; 1061 else 1062 data_len = HAMMER2_ALLOC_MIN; 1063 1064 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp, 1065 HAMMER2_METH_DEFAULT, 1066 xop->lhc, 0, 1067 HAMMER2_BREF_TYPE_DIRENT, 1068 data_len, 1069 xop->head.mtid, 0, 0); 1070 if (error == 0) { 1071 /* 1072 * WARNING: chain->data->buf is sized to chain->bytes, 1073 * do not use sizeof(chain->data->buf), which 1074 * will be much larger. 1075 */ 1076 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1077 if (error == 0) { 1078 chain->bref.embed.dirent = xop->dirent; 1079 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf)) 1080 bcopy(xop->head.name1, chain->bref.check.buf, 1081 xop->dirent.namlen); 1082 else 1083 bcopy(xop->head.name1, chain->data->buf, 1084 xop->dirent.namlen); 1085 } 1086 } 1087 fail: 1088 if (parent) { 1089 hammer2_chain_unlock(parent); 1090 hammer2_chain_drop(parent); 1091 } 1092 hammer2_xop_feed(&xop->head, chain, clindex, error); 1093 if (chain) { 1094 hammer2_chain_unlock(chain); 1095 hammer2_chain_drop(chain); 1096 } 1097 } 1098 1099 /* 1100 * Inode create helper (threaded, backend) 1101 * 1102 * Used by ncreate, nmknod, nsymlink, nmkdir. 1103 * Used by nlink and rename to create HARDLINK pointers. 1104 * 1105 * Frontend holds the parent directory ip locked exclusively. We 1106 * create the inode and feed the exclusively locked chain to the 1107 * frontend. 1108 */ 1109 void 1110 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex) 1111 { 1112 hammer2_xop_create_t *xop = &arg->xop_create; 1113 hammer2_chain_t *parent; 1114 hammer2_chain_t *chain; 1115 hammer2_key_t key_next; 1116 int error; 1117 1118 if (hammer2_debug & 0x0001) 1119 kprintf("xop_inode_create: lhc %016jx clindex %d\n", 1120 xop->lhc, clindex); 1121 1122 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1123 HAMMER2_RESOLVE_ALWAYS); 1124 if (parent == NULL) { 1125 error = HAMMER2_ERROR_EIO; 1126 chain = NULL; 1127 goto fail; 1128 } 1129 chain = hammer2_chain_lookup(&parent, &key_next, 1130 xop->lhc, xop->lhc, 1131 &error, 0); 1132 if (chain) { 1133 error = HAMMER2_ERROR_EEXIST; 1134 goto fail; 1135 } 1136 1137 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp, 1138 HAMMER2_METH_DEFAULT, 1139 xop->lhc, 0, 1140 HAMMER2_BREF_TYPE_INODE, 1141 HAMMER2_INODE_BYTES, 1142 xop->head.mtid, 0, xop->flags); 1143 if (error == 0) { 1144 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1145 if (error == 0) { 1146 chain->data->ipdata.meta = xop->meta; 1147 if (xop->head.name1) { 1148 bcopy(xop->head.name1, 1149 chain->data->ipdata.filename, 1150 xop->head.name1_len); 1151 chain->data->ipdata.meta.name_len = 1152 xop->head.name1_len; 1153 } 1154 chain->data->ipdata.meta.name_key = xop->lhc; 1155 } 1156 } 1157 fail: 1158 if (parent) { 1159 hammer2_chain_unlock(parent); 1160 hammer2_chain_drop(parent); 1161 } 1162 hammer2_xop_feed(&xop->head, chain, clindex, error); 1163 if (chain) { 1164 hammer2_chain_unlock(chain); 1165 hammer2_chain_drop(chain); 1166 } 1167 } 1168 1169 /* 1170 * Create inode as above but leave it detached from the hierarchy. 1171 */ 1172 void 1173 hammer2_xop_inode_create_det(hammer2_xop_t *arg, void *scratch, int clindex) 1174 { 1175 hammer2_xop_create_t *xop = &arg->xop_create; 1176 hammer2_chain_t *parent; 1177 hammer2_chain_t *chain; 1178 hammer2_chain_t *null_parent; 1179 hammer2_key_t key_next; 1180 hammer2_inode_t *pip; 1181 hammer2_inode_t *iroot; 1182 int error; 1183 1184 if (hammer2_debug & 0x0001) 1185 kprintf("xop_inode_create_det: lhc %016jx clindex %d\n", 1186 xop->lhc, clindex); 1187 1188 pip = xop->head.ip1; 1189 iroot = pip->pmp->iroot; 1190 1191 parent = hammer2_inode_chain(iroot, clindex, HAMMER2_RESOLVE_ALWAYS); 1192 1193 if (parent == NULL) { 1194 error = HAMMER2_ERROR_EIO; 1195 chain = NULL; 1196 goto fail; 1197 } 1198 chain = hammer2_chain_lookup(&parent, &key_next, 1199 xop->lhc, xop->lhc, 1200 &error, 0); 1201 if (chain) { 1202 error = HAMMER2_ERROR_EEXIST; 1203 goto fail; 1204 } 1205 1206 /* 1207 * Create as a detached chain with no parent. We must specify 1208 * methods 1209 */ 1210 null_parent = NULL; 1211 error = hammer2_chain_create(&null_parent, &chain, 1212 parent->hmp, pip->pmp, 1213 HAMMER2_ENC_COMP(pip->meta.comp_algo) + 1214 HAMMER2_ENC_CHECK(pip->meta.check_algo), 1215 xop->lhc, 0, 1216 HAMMER2_BREF_TYPE_INODE, 1217 HAMMER2_INODE_BYTES, 1218 xop->head.mtid, 0, xop->flags); 1219 if (error == 0) { 1220 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1221 if (error == 0) { 1222 chain->data->ipdata.meta = xop->meta; 1223 if (xop->head.name1) { 1224 bcopy(xop->head.name1, 1225 chain->data->ipdata.filename, 1226 xop->head.name1_len); 1227 chain->data->ipdata.meta.name_len = 1228 xop->head.name1_len; 1229 } 1230 chain->data->ipdata.meta.name_key = xop->lhc; 1231 } 1232 } 1233 fail: 1234 if (parent) { 1235 hammer2_chain_unlock(parent); 1236 hammer2_chain_drop(parent); 1237 } 1238 hammer2_xop_feed(&xop->head, chain, clindex, error); 1239 if (chain) { 1240 hammer2_chain_unlock(chain); 1241 hammer2_chain_drop(chain); 1242 } 1243 } 1244 1245 /* 1246 * Take a detached chain and insert it into the topology 1247 */ 1248 void 1249 hammer2_xop_inode_create_ins(hammer2_xop_t *arg, void *scratch, int clindex) 1250 { 1251 hammer2_xop_create_t *xop = &arg->xop_create; 1252 hammer2_chain_t *parent; 1253 hammer2_chain_t *chain; 1254 hammer2_key_t key_next; 1255 int error; 1256 1257 if (hammer2_debug & 0x0001) 1258 kprintf("xop_inode_create_ins: lhc %016jx clindex %d\n", 1259 xop->lhc, clindex); 1260 1261 /* 1262 * (parent) will be the insertion point for inode under iroot 1263 */ 1264 parent = hammer2_inode_chain(xop->head.ip1->pmp->iroot, clindex, 1265 HAMMER2_RESOLVE_ALWAYS); 1266 if (parent == NULL) { 1267 error = HAMMER2_ERROR_EIO; 1268 chain = NULL; 1269 goto fail; 1270 } 1271 chain = hammer2_chain_lookup(&parent, &key_next, 1272 xop->lhc, xop->lhc, 1273 &error, 0); 1274 if (chain) { 1275 error = HAMMER2_ERROR_EEXIST; 1276 goto fail; 1277 } 1278 1279 /* 1280 * (chain) is the detached inode that is being inserted 1281 */ 1282 chain = hammer2_inode_chain(xop->head.ip1, clindex, 1283 HAMMER2_RESOLVE_ALWAYS); 1284 if (chain == NULL) { 1285 error = HAMMER2_ERROR_EIO; 1286 chain = NULL; 1287 goto fail; 1288 } 1289 1290 /* 1291 * This create call will insert the non-NULL chain into parent. 1292 * Most of the auxillary fields are ignored since the chain already 1293 * exists. 1294 */ 1295 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp, 1296 HAMMER2_METH_DEFAULT, 1297 xop->lhc, 0, 1298 HAMMER2_BREF_TYPE_INODE, 1299 HAMMER2_INODE_BYTES, 1300 xop->head.mtid, 0, xop->flags); 1301 #if 0 1302 if (error == 0) { 1303 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1304 if (error == 0) { 1305 chain->data->ipdata.meta = xop->meta; 1306 if (xop->head.name1) { 1307 bcopy(xop->head.name1, 1308 chain->data->ipdata.filename, 1309 xop->head.name1_len); 1310 chain->data->ipdata.meta.name_len = 1311 xop->head.name1_len; 1312 } 1313 chain->data->ipdata.meta.name_key = xop->lhc; 1314 } 1315 } 1316 #endif 1317 fail: 1318 if (parent) { 1319 hammer2_chain_unlock(parent); 1320 hammer2_chain_drop(parent); 1321 } 1322 hammer2_xop_feed(&xop->head, chain, clindex, error); 1323 if (chain) { 1324 hammer2_chain_unlock(chain); 1325 hammer2_chain_drop(chain); 1326 } 1327 } 1328 1329 /* 1330 * Inode delete helper (backend, threaded) 1331 * 1332 * Generally used by hammer2_run_sideq() 1333 */ 1334 void 1335 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex) 1336 { 1337 hammer2_xop_destroy_t *xop = &arg->xop_destroy; 1338 hammer2_pfs_t *pmp; 1339 hammer2_chain_t *parent; 1340 hammer2_chain_t *chain; 1341 hammer2_inode_t *ip; 1342 int error; 1343 1344 /* 1345 * We need the precise parent chain to issue the deletion. 1346 */ 1347 ip = xop->head.ip1; 1348 pmp = ip->pmp; 1349 1350 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 1351 if (chain == NULL) { 1352 parent = NULL; 1353 error = HAMMER2_ERROR_EIO; 1354 goto done; 1355 } 1356 1357 if (ip->flags & HAMMER2_INODE_CREATING) { 1358 /* 1359 * Inode's chains are not linked into the media topology 1360 * because it is a new inode (which is now being destroyed). 1361 */ 1362 parent = NULL; 1363 } else { 1364 /* 1365 * Inode's chains are linked into the media topology 1366 */ 1367 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS); 1368 if (parent == NULL) { 1369 error = HAMMER2_ERROR_EIO; 1370 goto done; 1371 } 1372 } 1373 KKASSERT(chain->parent == parent); 1374 1375 /* 1376 * We have the correct parent, we can issue the deletion. 1377 */ 1378 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 1379 error = 0; 1380 done: 1381 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1382 if (parent) { 1383 hammer2_chain_unlock(parent); 1384 hammer2_chain_drop(parent); 1385 } 1386 if (chain) { 1387 hammer2_chain_unlock(chain); 1388 hammer2_chain_drop(chain); 1389 } 1390 } 1391 1392 void 1393 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex) 1394 { 1395 hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall; 1396 hammer2_chain_t *parent; 1397 hammer2_chain_t *chain; 1398 hammer2_key_t key_next; 1399 int error; 1400 1401 /* 1402 * We need the precise parent chain to issue the deletion. 1403 */ 1404 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1405 HAMMER2_RESOLVE_ALWAYS); 1406 chain = NULL; 1407 if (parent == NULL) { 1408 error = 0; 1409 goto done; 1410 } 1411 chain = hammer2_chain_lookup(&parent, &key_next, 1412 xop->key_beg, xop->key_end, 1413 &error, HAMMER2_LOOKUP_ALWAYS); 1414 while (chain) { 1415 hammer2_chain_delete(parent, chain, 1416 xop->head.mtid, HAMMER2_DELETE_PERMANENT); 1417 hammer2_xop_feed(&xop->head, chain, clindex, chain->error); 1418 /* depend on function to unlock the shared lock */ 1419 chain = hammer2_chain_next(&parent, chain, &key_next, 1420 key_next, xop->key_end, 1421 &error, 1422 HAMMER2_LOOKUP_ALWAYS); 1423 } 1424 done: 1425 if (error == 0) 1426 error = HAMMER2_ERROR_ENOENT; 1427 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1428 if (parent) { 1429 hammer2_chain_unlock(parent); 1430 hammer2_chain_drop(parent); 1431 } 1432 if (chain) { 1433 hammer2_chain_unlock(chain); 1434 hammer2_chain_drop(chain); 1435 } 1436 } 1437 1438 void 1439 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex) 1440 { 1441 hammer2_xop_connect_t *xop = &arg->xop_connect; 1442 hammer2_inode_data_t *wipdata; 1443 hammer2_chain_t *parent; 1444 hammer2_chain_t *chain; 1445 hammer2_pfs_t *pmp; 1446 hammer2_key_t key_dummy; 1447 int error; 1448 1449 /* 1450 * Get directory, then issue a lookup to prime the parent chain 1451 * for the create. The lookup is expected to fail. 1452 */ 1453 pmp = xop->head.ip1->pmp; 1454 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1455 HAMMER2_RESOLVE_ALWAYS); 1456 if (parent == NULL) { 1457 chain = NULL; 1458 error = HAMMER2_ERROR_EIO; 1459 goto fail; 1460 } 1461 chain = hammer2_chain_lookup(&parent, &key_dummy, 1462 xop->lhc, xop->lhc, 1463 &error, 0); 1464 if (chain) { 1465 hammer2_chain_unlock(chain); 1466 hammer2_chain_drop(chain); 1467 chain = NULL; 1468 error = HAMMER2_ERROR_EEXIST; 1469 goto fail; 1470 } 1471 if (error) 1472 goto fail; 1473 1474 /* 1475 * Adjust the filename in the inode, set the name key. 1476 * 1477 * NOTE: Frontend must also adjust ip2->meta on success, we can't 1478 * do it here. 1479 */ 1480 chain = hammer2_inode_chain(xop->head.ip2, clindex, 1481 HAMMER2_RESOLVE_ALWAYS); 1482 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 1483 if (error) 1484 goto fail; 1485 1486 wipdata = &chain->data->ipdata; 1487 1488 hammer2_inode_modify(xop->head.ip2); 1489 if (xop->head.name1) { 1490 bzero(wipdata->filename, sizeof(wipdata->filename)); 1491 bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len); 1492 wipdata->meta.name_len = xop->head.name1_len; 1493 } 1494 wipdata->meta.name_key = xop->lhc; 1495 1496 /* 1497 * Reconnect the chain to the new parent directory 1498 */ 1499 error = hammer2_chain_create(&parent, &chain, NULL, pmp, 1500 HAMMER2_METH_DEFAULT, 1501 xop->lhc, 0, 1502 HAMMER2_BREF_TYPE_INODE, 1503 HAMMER2_INODE_BYTES, 1504 xop->head.mtid, 0, 0); 1505 1506 /* 1507 * Feed result back. 1508 */ 1509 fail: 1510 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1511 if (parent) { 1512 hammer2_chain_unlock(parent); 1513 hammer2_chain_drop(parent); 1514 } 1515 if (chain) { 1516 hammer2_chain_unlock(chain); 1517 hammer2_chain_drop(chain); 1518 } 1519 } 1520 1521 /* 1522 * Synchronize the in-memory inode with the chain. This does not flush 1523 * the chain to disk. Instead, it makes front-end inode changes visible 1524 * in the chain topology, thus visible to the backend. This is done in an 1525 * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled 1526 * manner inside the vfs_sync. 1527 */ 1528 void 1529 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex) 1530 { 1531 hammer2_xop_fsync_t *xop = &arg->xop_fsync; 1532 hammer2_chain_t *parent; 1533 hammer2_chain_t *chain; 1534 int error; 1535 1536 parent = hammer2_inode_chain(xop->head.ip1, clindex, 1537 HAMMER2_RESOLVE_ALWAYS); 1538 chain = NULL; 1539 if (parent == NULL) { 1540 error = HAMMER2_ERROR_EIO; 1541 goto done; 1542 } 1543 if (parent->error) { 1544 error = parent->error; 1545 goto done; 1546 } 1547 1548 error = 0; 1549 1550 if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) { 1551 /* osize must be ignored */ 1552 } else if (xop->meta.size < xop->osize) { 1553 /* 1554 * We must delete any chains beyond the EOF. The chain 1555 * straddling the EOF will be pending in the bioq. 1556 */ 1557 hammer2_key_t lbase; 1558 hammer2_key_t key_next; 1559 1560 lbase = (xop->meta.size + HAMMER2_PBUFMASK64) & 1561 ~HAMMER2_PBUFMASK64; 1562 chain = hammer2_chain_lookup(&parent, &key_next, 1563 lbase, HAMMER2_KEY_MAX, 1564 &error, 1565 HAMMER2_LOOKUP_NODATA | 1566 HAMMER2_LOOKUP_NODIRECT); 1567 while (chain) { 1568 /* 1569 * Degenerate embedded case, nothing to loop on 1570 */ 1571 switch (chain->bref.type) { 1572 case HAMMER2_BREF_TYPE_DIRENT: 1573 case HAMMER2_BREF_TYPE_INODE: 1574 KKASSERT(0); 1575 break; 1576 case HAMMER2_BREF_TYPE_DATA: 1577 hammer2_chain_delete(parent, chain, 1578 xop->head.mtid, 1579 HAMMER2_DELETE_PERMANENT); 1580 break; 1581 } 1582 chain = hammer2_chain_next(&parent, chain, &key_next, 1583 key_next, HAMMER2_KEY_MAX, 1584 &error, 1585 HAMMER2_LOOKUP_NODATA | 1586 HAMMER2_LOOKUP_NODIRECT); 1587 } 1588 1589 /* 1590 * Reset to point at inode for following code, if necessary. 1591 */ 1592 if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) { 1593 hammer2_chain_unlock(parent); 1594 hammer2_chain_drop(parent); 1595 parent = hammer2_inode_chain(xop->head.ip1, 1596 clindex, 1597 HAMMER2_RESOLVE_ALWAYS); 1598 kprintf("xop_inode_chain_sync: TRUNCATE RESET on '%s'\n", 1599 parent->data->ipdata.filename); 1600 } 1601 } 1602 1603 /* 1604 * Sync the inode meta-data, potentially clear the blockset area 1605 * of direct data so it can be used for blockrefs. 1606 */ 1607 if (error == 0) { 1608 error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0); 1609 if (error == 0) { 1610 parent->data->ipdata.meta = xop->meta; 1611 if (xop->clear_directdata) { 1612 bzero(&parent->data->ipdata.u.blockset, 1613 sizeof(parent->data->ipdata.u.blockset)); 1614 } 1615 } 1616 } 1617 done: 1618 if (chain) { 1619 hammer2_chain_unlock(chain); 1620 hammer2_chain_drop(chain); 1621 } 1622 if (parent) { 1623 hammer2_chain_unlock(parent); 1624 hammer2_chain_drop(parent); 1625 } 1626 hammer2_xop_feed(&xop->head, NULL, clindex, error); 1627 } 1628