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