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