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