1 /* 2 * Copyright (c) 2011-2015 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. Returns 0 on success. 65 */ 66 static 67 int 68 checkdirempty(hammer2_chain_t *orig_parent) 69 { 70 hammer2_chain_t *parent; 71 hammer2_chain_t *chain; 72 hammer2_key_t key_next; 73 int cache_index = -1; 74 int error; 75 76 parent = hammer2_chain_lookup_init(orig_parent, 0); 77 chain = hammer2_chain_lookup(&parent, &key_next, 78 HAMMER2_DIRHASH_VISIBLE, 79 HAMMER2_KEY_MAX, 80 &cache_index, 0); 81 error = chain ? ENOTEMPTY : 0; 82 if (chain) { 83 hammer2_chain_unlock(chain); 84 hammer2_chain_drop(chain); 85 } 86 hammer2_chain_lookup_done(parent); 87 88 return error; 89 } 90 91 /* 92 * Backend for hammer2_vfs_root() 93 * 94 * This is called when a newly mounted PFS has not yet synchronized 95 * to the inode_tid and modify_tid. 96 */ 97 void 98 hammer2_xop_ipcluster(hammer2_xop_t *arg, int clindex) 99 { 100 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster; 101 hammer2_chain_t *chain; 102 int error; 103 104 chain = hammer2_inode_chain(xop->head.ip1, clindex, 105 HAMMER2_RESOLVE_ALWAYS | 106 HAMMER2_RESOLVE_SHARED); 107 if (chain) 108 error = chain->error; 109 else 110 error = EIO; 111 112 hammer2_xop_feed(&xop->head, chain, clindex, error); 113 if (chain) { 114 hammer2_chain_unlock(chain); 115 hammer2_chain_drop(chain); 116 } 117 } 118 119 /* 120 * Backend for hammer2_vop_readdir() 121 */ 122 void 123 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex) 124 { 125 hammer2_xop_readdir_t *xop = &arg->xop_readdir; 126 hammer2_chain_t *parent; 127 hammer2_chain_t *chain; 128 hammer2_key_t key_next; 129 hammer2_key_t lkey; 130 int cache_index = -1; 131 int error = 0; 132 133 lkey = xop->lkey; 134 if (hammer2_debug & 0x0020) 135 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey); 136 137 /* 138 * The inode's chain is the iterator. If we cannot acquire it our 139 * contribution ends here. 140 */ 141 parent = hammer2_inode_chain(xop->head.ip1, clindex, 142 HAMMER2_RESOLVE_ALWAYS | 143 HAMMER2_RESOLVE_SHARED); 144 if (parent == NULL) { 145 kprintf("xop_readdir: NULL parent\n"); 146 goto done; 147 } 148 149 /* 150 * Directory scan [re]start and loop, the feed inherits the chain's 151 * lock so do not unlock it on the iteration. 152 */ 153 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey, 154 &cache_index, HAMMER2_LOOKUP_SHARED); 155 if (chain == NULL) { 156 chain = hammer2_chain_lookup(&parent, &key_next, 157 lkey, HAMMER2_KEY_MAX, 158 &cache_index, 159 HAMMER2_LOOKUP_SHARED); 160 } 161 while (chain) { 162 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 163 if (error) 164 break; 165 chain = hammer2_chain_next(&parent, chain, &key_next, 166 key_next, HAMMER2_KEY_MAX, 167 &cache_index, 168 HAMMER2_LOOKUP_SHARED); 169 } 170 if (chain) { 171 hammer2_chain_unlock(chain); 172 hammer2_chain_drop(chain); 173 } 174 hammer2_chain_unlock(parent); 175 hammer2_chain_drop(parent); 176 done: 177 hammer2_xop_feed(&xop->head, NULL, clindex, error); 178 } 179 180 /* 181 * Backend for hammer2_vop_nresolve() 182 */ 183 void 184 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex) 185 { 186 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve; 187 hammer2_chain_t *parent; 188 hammer2_chain_t *chain; 189 const hammer2_inode_data_t *ripdata; 190 const char *name; 191 size_t name_len; 192 hammer2_key_t key_next; 193 hammer2_key_t lhc; 194 int cache_index = -1; /* XXX */ 195 int error; 196 197 parent = hammer2_inode_chain(xop->head.ip1, clindex, 198 HAMMER2_RESOLVE_ALWAYS | 199 HAMMER2_RESOLVE_SHARED); 200 if (parent == NULL) { 201 kprintf("xop_nresolve: NULL parent\n"); 202 chain = NULL; 203 error = EIO; 204 goto done; 205 } 206 name = xop->head.name1; 207 name_len = xop->head.name1_len; 208 209 /* 210 * Lookup the directory entry 211 */ 212 lhc = hammer2_dirhash(name, name_len); 213 chain = hammer2_chain_lookup(&parent, &key_next, 214 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 215 &cache_index, 216 HAMMER2_LOOKUP_ALWAYS | 217 HAMMER2_LOOKUP_SHARED); 218 while (chain) { 219 ripdata = &chain->data->ipdata; 220 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 221 ripdata->meta.name_len == name_len && 222 bcmp(ripdata->filename, name, name_len) == 0) { 223 break; 224 } 225 chain = hammer2_chain_next(&parent, chain, &key_next, 226 key_next, 227 lhc + HAMMER2_DIRHASH_LOMASK, 228 &cache_index, 229 HAMMER2_LOOKUP_ALWAYS | 230 HAMMER2_LOOKUP_SHARED); 231 } 232 233 /* 234 * If the entry is a hardlink pointer, resolve it. 235 */ 236 error = 0; 237 if (chain) { 238 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) { 239 error = hammer2_chain_hardlink_find( 240 xop->head.ip1, 241 &parent, &chain, 242 HAMMER2_LOOKUP_SHARED); 243 } 244 } 245 done: 246 error = hammer2_xop_feed(&xop->head, chain, clindex, error); 247 if (chain) { 248 hammer2_chain_unlock(chain); 249 hammer2_chain_drop(chain); 250 } 251 if (parent) { 252 hammer2_chain_unlock(parent); 253 hammer2_chain_drop(parent); 254 } 255 } 256 257 /* 258 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper 259 * for hammer2_vop_nrename(). 260 * 261 * This function locates and removes the directory entry. If the 262 * entry is a hardlink pointer, this function will also remove the 263 * hardlink target if the target's nlinks is 1. 264 * 265 * The frontend is responsible for moving open inodes to the hidden directory 266 * and for decrementing nlinks. 267 */ 268 void 269 hammer2_xop_unlink(hammer2_xop_t *arg, int clindex) 270 { 271 hammer2_xop_unlink_t *xop = &arg->xop_unlink; 272 hammer2_chain_t *parent; 273 hammer2_chain_t *chain; 274 const hammer2_inode_data_t *ripdata; 275 const char *name; 276 size_t name_len; 277 hammer2_key_t key_next; 278 hammer2_key_t lhc; 279 int cache_index = -1; /* XXX */ 280 int error; 281 282 /* 283 * Requires exclusive lock 284 */ 285 parent = hammer2_inode_chain(xop->head.ip1, clindex, 286 HAMMER2_RESOLVE_ALWAYS); 287 chain = NULL; 288 if (parent == NULL) { 289 kprintf("xop_nresolve: NULL parent\n"); 290 error = EIO; 291 goto done; 292 } 293 name = xop->head.name1; 294 name_len = xop->head.name1_len; 295 296 /* 297 * Lookup the directory entry 298 */ 299 lhc = hammer2_dirhash(name, name_len); 300 chain = hammer2_chain_lookup(&parent, &key_next, 301 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 302 &cache_index, 303 HAMMER2_LOOKUP_ALWAYS); 304 while (chain) { 305 ripdata = &chain->data->ipdata; 306 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 307 ripdata->meta.name_len == name_len && 308 bcmp(ripdata->filename, name, name_len) == 0) { 309 break; 310 } 311 chain = hammer2_chain_next(&parent, chain, &key_next, 312 key_next, 313 lhc + HAMMER2_DIRHASH_LOMASK, 314 &cache_index, 315 HAMMER2_LOOKUP_ALWAYS); 316 } 317 318 /* 319 * If the directory entry is a HARDLINK pointer then obtain the 320 * underlying file type for the directory typing tests and delete 321 * the HARDLINK pointer chain permanently. The frontend is left 322 * responsible for handling nlinks on and deleting the actual inode. 323 * 324 * If the directory entry is the actual inode then use its type 325 * for the directory typing tests and delete the chain, permanency 326 * depends on whether the inode is open or not. 327 * 328 * Check directory typing and delete the entry. Note that 329 * nlinks adjustments are made on the real inode by the frontend, 330 * not here. 331 */ 332 error = 0; 333 if (chain) { 334 int dopermanent = xop->dopermanent; 335 uint8_t type; 336 337 type = chain->data->ipdata.meta.type; 338 if (type == HAMMER2_OBJTYPE_HARDLINK) { 339 type = chain->data->ipdata.meta.target_type; 340 dopermanent |= HAMMER2_DELETE_PERMANENT; 341 } 342 343 if (type == HAMMER2_OBJTYPE_DIRECTORY && 344 checkdirempty(chain) != 0) { 345 error = ENOTEMPTY; 346 } else if (type == HAMMER2_OBJTYPE_DIRECTORY && 347 xop->isdir == 0) { 348 error = ENOTDIR; 349 } else 350 if (type != HAMMER2_OBJTYPE_DIRECTORY && 351 xop->isdir >= 1) { 352 error = EISDIR; 353 } else { 354 /* 355 * This deletes the directory entry itself, which is 356 * also the inode when nlinks == 1. Hardlink targets 357 * are handled in the next conditional. 358 */ 359 error = chain->error; 360 hammer2_chain_delete(parent, chain, 361 xop->head.mtid, dopermanent); 362 } 363 } 364 365 /* 366 * If the entry is a hardlink pointer, resolve it. If this is the 367 * last link, delete it. The frontend has the master copy of nlinks 368 * but we still have to make adjustments here to synchronize with it. 369 * 370 * On delete / adjust nlinks if there is no error. But we still need 371 * to resolve the hardlink to feed the inode's real chain back to 372 * the frontend. 373 * 374 * XXX we are basically tracking the nlinks count by doing a delta 375 * adjustment instead of having the frontend pass the absolute 376 * value down. We really need to have the frontend pass the 377 * absolute value down (difficult because there might not be 378 * an 'ip'). See also hammer2_xop_nlink(). 379 */ 380 if (chain && 381 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) { 382 int error2; 383 384 error2 = hammer2_chain_hardlink_find(xop->head.ip1, 385 &parent, &chain, 0); 386 if (chain && error == 0 && error2 == 0 && 387 (int64_t)chain->data->ipdata.meta.nlinks <= 1) { 388 hammer2_chain_delete(parent, chain, 389 xop->head.mtid, 390 xop->dopermanent); 391 } else if (chain && error == 0 && error2 == 0) { 392 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 393 --chain->data->ipdata.meta.nlinks; 394 } 395 if (error == 0) 396 error = error2; 397 } 398 399 /* 400 * Chains passed to feed are expected to be locked shared. 401 */ 402 if (chain) 403 hammer2_chain_lock_downgrade(chain); 404 405 /* 406 * We always return the hardlink target (the real inode) for 407 * further action. 408 */ 409 done: 410 hammer2_xop_feed(&xop->head, chain, clindex, error); 411 if (chain) { 412 hammer2_chain_unlock(chain); 413 hammer2_chain_drop(chain); 414 chain = NULL; 415 } 416 if (parent) { 417 hammer2_chain_unlock(parent); 418 hammer2_chain_drop(parent); 419 parent = NULL; 420 } 421 } 422 423 /* 424 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename() 425 * 426 * ip1 - fdip 427 * ip2 - ip 428 * ip3 - cdip 429 * 430 * If a hardlink pointer: 431 * The existing hardlink target {fdip,ip} must be moved to another 432 * directory {cdip,ip} 433 * 434 * If not a hardlink pointer: 435 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and 436 * replace the original namespace {fdip,name} with a hardlink pointer. 437 */ 438 void 439 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex) 440 { 441 hammer2_xop_nlink_t *xop = &arg->xop_nlink; 442 hammer2_pfs_t *pmp; 443 hammer2_inode_data_t *wipdata; 444 hammer2_chain_t *parent; 445 hammer2_chain_t *chain; 446 hammer2_chain_t *tmp; 447 hammer2_inode_t *ip; 448 hammer2_key_t key_dummy; 449 int cache_index = -1; 450 int error; 451 int did_delete = 0; 452 453 /* 454 * We need the precise parent chain to issue the deletion. 455 */ 456 ip = xop->head.ip2; 457 pmp = ip->pmp; 458 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 459 if (parent) 460 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS); 461 if (parent == NULL) { 462 chain = NULL; 463 error = EIO; 464 goto done; 465 } 466 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS); 467 if (chain == NULL) { 468 error = EIO; 469 goto done; 470 } 471 KKASSERT(chain->parent == parent); 472 473 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) { 474 /* 475 * Delete the original chain and hold onto it for the move 476 * to cdir. 477 * 478 * Replace the namespace with a hardlink pointer if the 479 * chain being moved is not already a hardlink target. 480 */ 481 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 482 did_delete = 1; 483 484 tmp = NULL; 485 error = hammer2_chain_create(&parent, &tmp, pmp, 486 chain->bref.key, 0, 487 HAMMER2_BREF_TYPE_INODE, 488 HAMMER2_INODE_BYTES, 489 xop->head.mtid, 0, 0); 490 if (error) 491 goto done; 492 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0); 493 wipdata = &tmp->data->ipdata; 494 bzero(wipdata, sizeof(*wipdata)); 495 wipdata->meta.name_key = chain->data->ipdata.meta.name_key; 496 wipdata->meta.name_len = chain->data->ipdata.meta.name_len; 497 bcopy(chain->data->ipdata.filename, wipdata->filename, 498 chain->data->ipdata.meta.name_len); 499 wipdata->meta.target_type = chain->data->ipdata.meta.type; 500 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK; 501 wipdata->meta.inum = ip->meta.inum; 502 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE; 503 wipdata->meta.nlinks = 1; 504 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA; 505 506 hammer2_chain_unlock(tmp); 507 hammer2_chain_drop(tmp); 508 } else if (xop->head.ip1 != xop->head.ip3) { 509 /* 510 * Delete the hardlink target so it can be moved 511 * to cdir. 512 */ 513 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 514 did_delete = 1; 515 } else { 516 /* 517 * Deletion not necessary (just a nlinks update). 518 */ 519 did_delete = 0; 520 } 521 522 hammer2_chain_unlock(parent); 523 hammer2_chain_drop(parent); 524 parent = NULL; 525 526 /* 527 * Ok, back to the deleted chain. We must reconnect this chain 528 * as a hardlink target to cdir (ip3). 529 * 530 * WARNING! Frontend assumes filename length is 18 bytes. 531 */ 532 if (did_delete) { 533 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 534 wipdata = &chain->data->ipdata; 535 ksnprintf(wipdata->filename, sizeof(wipdata->filename), 536 "0x%016jx", (intmax_t)ip->meta.inum); 537 wipdata->meta.name_len = strlen(wipdata->filename); 538 wipdata->meta.name_key = ip->meta.inum; 539 540 /* 541 * We must seek parent properly for the create to reattach 542 * chain. XXX just use chain->parent or 543 * inode_chain_and_parent() ? 544 */ 545 parent = hammer2_inode_chain(xop->head.ip3, clindex, 546 HAMMER2_RESOLVE_ALWAYS); 547 if (parent == NULL) { 548 error = EIO; 549 goto done; 550 } 551 tmp = hammer2_chain_lookup(&parent, &key_dummy, 552 ip->meta.inum, ip->meta.inum, 553 &cache_index, 0); 554 if (tmp) { 555 hammer2_chain_unlock(tmp); 556 hammer2_chain_drop(tmp); 557 error = EEXIST; 558 goto done; 559 } 560 error = hammer2_chain_create(&parent, &chain, pmp, 561 wipdata->meta.name_key, 0, 562 HAMMER2_BREF_TYPE_INODE, 563 HAMMER2_INODE_BYTES, 564 xop->head.mtid, 0, 0); 565 } else { 566 error = 0; 567 } 568 569 /* 570 * Bump nlinks to synchronize with frontend. 571 */ 572 if (xop->nlinks_delta) { 573 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 574 chain->data->ipdata.meta.nlinks += xop->nlinks_delta; 575 } 576 577 /* 578 * To avoid having to scan the collision space we can simply 579 * reuse the inode's original name_key. But ip->meta.name_key 580 * may have already been updated by the front-end, so use xop->lhc. 581 * 582 * (frontend is responsible for fixing up ip->pip). 583 */ 584 done: 585 hammer2_xop_feed(&xop->head, NULL, clindex, error); 586 if (parent) { 587 hammer2_chain_unlock(parent); 588 hammer2_chain_drop(parent); 589 } 590 if (chain) { 591 hammer2_chain_unlock(chain); 592 hammer2_chain_drop(chain); 593 } 594 } 595 596 /* 597 * Backend for hammer2_vop_nrename() 598 * 599 * This handles the final step of renaming, either renaming the 600 * actual inode or renaming the hardlink pointer. 601 */ 602 void 603 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex) 604 { 605 hammer2_xop_nrename_t *xop = &arg->xop_nrename; 606 hammer2_pfs_t *pmp; 607 hammer2_chain_t *parent; 608 hammer2_chain_t *chain; 609 hammer2_chain_t *tmp; 610 hammer2_inode_t *ip; 611 hammer2_key_t key_dummy; 612 int cache_index = -1; 613 int error; 614 615 /* 616 * We need the precise parent chain to issue the deletion. 617 * 618 * If this is not a hardlink target we can act on the inode, 619 * otherwise we have to locate the hardlink pointer. 620 */ 621 ip = xop->head.ip2; 622 pmp = ip->pmp; 623 chain = NULL; 624 625 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) { 626 /* 627 * Find ip's direct parent chain. 628 */ 629 parent = hammer2_inode_chain(ip, clindex, 630 HAMMER2_RESOLVE_ALWAYS); 631 if (parent) 632 hammer2_chain_getparent(&parent, 633 HAMMER2_RESOLVE_ALWAYS); 634 if (parent == NULL) { 635 error = EIO; 636 goto done; 637 } 638 chain = hammer2_inode_chain(ip, clindex, 639 HAMMER2_RESOLVE_ALWAYS); 640 if (chain == NULL) { 641 error = EIO; 642 goto done; 643 } 644 } else { 645 /* 646 * The hardlink pointer for the head.ip1 hardlink target 647 * is in fdip, do a namespace search. 648 */ 649 const hammer2_inode_data_t *ripdata; 650 hammer2_key_t lhc; 651 hammer2_key_t key_next; 652 const char *name; 653 size_t name_len; 654 655 parent = hammer2_inode_chain(xop->head.ip1, clindex, 656 HAMMER2_RESOLVE_ALWAYS); 657 if (parent == NULL) { 658 kprintf("xop_nrename: NULL parent\n"); 659 error = EIO; 660 goto done; 661 } 662 name = xop->head.name1; 663 name_len = xop->head.name1_len; 664 665 /* 666 * Lookup the directory entry 667 */ 668 lhc = hammer2_dirhash(name, name_len); 669 chain = hammer2_chain_lookup(&parent, &key_next, 670 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 671 &cache_index, 672 HAMMER2_LOOKUP_ALWAYS); 673 while (chain) { 674 ripdata = &chain->data->ipdata; 675 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE && 676 ripdata->meta.name_len == name_len && 677 bcmp(ripdata->filename, name, name_len) == 0) { 678 break; 679 } 680 chain = hammer2_chain_next(&parent, chain, &key_next, 681 key_next, 682 lhc + HAMMER2_DIRHASH_LOMASK, 683 &cache_index, 684 HAMMER2_LOOKUP_ALWAYS); 685 } 686 } 687 688 if (chain == NULL) { 689 /* XXX shouldn't happen, but does under fsstress */ 690 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n", 691 xop->head.name1, 692 xop->head.name2); 693 error = ENOENT; 694 goto done; 695 } 696 697 /* 698 * Delete it, then create it in the new namespace. 699 */ 700 hammer2_chain_delete(parent, chain, xop->head.mtid, 0); 701 hammer2_chain_unlock(parent); 702 hammer2_chain_drop(parent); 703 parent = NULL; /* safety */ 704 705 /* 706 * Ok, back to the deleted chain. We must reconnect this chain 707 * to tdir (ip3). The chain (a real inode or a hardlink pointer) 708 * is not otherwise modified. 709 * 710 * Frontend is expected to replicate the same inode meta data 711 * modifications. 712 * 713 * NOTE! This chain may not represent the actual inode, it 714 * can be a hardlink pointer. 715 * 716 * XXX in-inode parent directory specification? 717 */ 718 if (chain->data->ipdata.meta.name_key != xop->lhc || 719 xop->head.name1_len != xop->head.name2_len || 720 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) { 721 hammer2_inode_data_t *wipdata; 722 723 hammer2_chain_modify(chain, xop->head.mtid, 0, 0); 724 wipdata = &chain->data->ipdata; 725 726 bzero(wipdata->filename, sizeof(wipdata->filename)); 727 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len); 728 wipdata->meta.name_key = xop->lhc; 729 wipdata->meta.name_len = xop->head.name2_len; 730 } 731 732 /* 733 * We must seek parent properly for the create. 734 */ 735 parent = hammer2_inode_chain(xop->head.ip3, clindex, 736 HAMMER2_RESOLVE_ALWAYS); 737 if (parent == NULL) { 738 error = EIO; 739 goto done; 740 } 741 tmp = hammer2_chain_lookup(&parent, &key_dummy, 742 xop->lhc, xop->lhc, 743 &cache_index, 0); 744 if (tmp) { 745 hammer2_chain_unlock(tmp); 746 hammer2_chain_drop(tmp); 747 error = EEXIST; 748 goto done; 749 } 750 751 error = hammer2_chain_create(&parent, &chain, pmp, 752 xop->lhc, 0, 753 HAMMER2_BREF_TYPE_INODE, 754 HAMMER2_INODE_BYTES, 755 xop->head.mtid, 0, 0); 756 /* 757 * (frontend is responsible for fixing up ip->pip). 758 */ 759 done: 760 hammer2_xop_feed(&xop->head, NULL, clindex, error); 761 if (parent) { 762 hammer2_chain_unlock(parent); 763 hammer2_chain_drop(parent); 764 } 765 if (chain) { 766 hammer2_chain_unlock(chain); 767 hammer2_chain_drop(chain); 768 } 769 } 770 771 /* 772 * Directory collision resolver scan helper (backend, threaded). 773 * 774 * Used by the inode create code to locate an unused lhc. 775 */ 776 void 777 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex) 778 { 779 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 780 hammer2_chain_t *parent; 781 hammer2_chain_t *chain; 782 hammer2_key_t key_next; 783 int cache_index = -1; /* XXX */ 784 int error = 0; 785 786 parent = hammer2_inode_chain(xop->head.ip1, clindex, 787 HAMMER2_RESOLVE_ALWAYS | 788 HAMMER2_RESOLVE_SHARED); 789 if (parent == NULL) { 790 kprintf("xop_nresolve: NULL parent\n"); 791 chain = NULL; 792 error = EIO; 793 goto done; 794 } 795 796 /* 797 * Lookup all possibly conflicting directory entries, the feed 798 * inherits the chain's lock so do not unlock it on the iteration. 799 */ 800 chain = hammer2_chain_lookup(&parent, &key_next, 801 xop->lhc, 802 xop->lhc + HAMMER2_DIRHASH_LOMASK, 803 &cache_index, 804 HAMMER2_LOOKUP_ALWAYS | 805 HAMMER2_LOOKUP_SHARED); 806 while (chain) { 807 error = hammer2_xop_feed(&xop->head, chain, clindex, 808 chain->error); 809 if (error) { 810 hammer2_chain_unlock(chain); 811 hammer2_chain_drop(chain); 812 chain = NULL; /* safety */ 813 break; 814 } 815 chain = hammer2_chain_next(&parent, chain, &key_next, 816 key_next, 817 xop->lhc + HAMMER2_DIRHASH_LOMASK, 818 &cache_index, 819 HAMMER2_LOOKUP_ALWAYS | 820 HAMMER2_LOOKUP_SHARED); 821 } 822 done: 823 hammer2_xop_feed(&xop->head, NULL, clindex, error); 824 if (parent) { 825 hammer2_chain_unlock(parent); 826 hammer2_chain_drop(parent); 827 } 828 } 829 830 /* 831 * Generic lookup of a specific key. 832 * 833 * Used by the inode hidden directory code to find the hidden directory. 834 */ 835 void 836 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex) 837 { 838 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc; 839 hammer2_chain_t *parent; 840 hammer2_chain_t *chain; 841 hammer2_key_t key_next; 842 int cache_index = -1; /* XXX */ 843 int error = 0; 844 845 parent = hammer2_inode_chain(xop->head.ip1, clindex, 846 HAMMER2_RESOLVE_ALWAYS | 847 HAMMER2_RESOLVE_SHARED); 848 chain = NULL; 849 if (parent == NULL) { 850 error = EIO; 851 goto done; 852 } 853 854 /* 855 * Lookup all possibly conflicting directory entries, the feed 856 * inherits the chain's lock so do not unlock it on the iteration. 857 */ 858 chain = hammer2_chain_lookup(&parent, &key_next, 859 xop->lhc, xop->lhc, 860 &cache_index, 861 HAMMER2_LOOKUP_ALWAYS | 862 HAMMER2_LOOKUP_SHARED); 863 if (chain) 864 hammer2_xop_feed(&xop->head, chain, clindex, chain->error); 865 else 866 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT); 867 868 done: 869 if (chain) { 870 hammer2_chain_unlock(chain); 871 hammer2_chain_drop(chain); 872 } 873 if (parent) { 874 hammer2_chain_unlock(parent); 875 hammer2_chain_drop(parent); 876 } 877 } 878 879 /* 880 * Generic scan 881 * 882 * WARNING! Fed chains must be locked shared so ownership can be transfered 883 * and to prevent frontend/backend stalls that would occur with an 884 * exclusive lock. The shared lock also allows chain->data to be 885 * retained. 886 */ 887 void 888 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex) 889 { 890 hammer2_xop_scanall_t *xop = &arg->xop_scanall; 891 hammer2_chain_t *parent; 892 hammer2_chain_t *chain; 893 hammer2_key_t key_next; 894 int cache_index = -1; 895 int error = 0; 896 897 /* 898 * Assert required flags. 899 */ 900 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED); 901 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED); 902 903 /* 904 * The inode's chain is the iterator. If we cannot acquire it our 905 * contribution ends here. 906 */ 907 parent = hammer2_inode_chain(xop->head.ip1, clindex, 908 xop->resolve_flags); 909 if (parent == NULL) { 910 kprintf("xop_readdir: NULL parent\n"); 911 goto done; 912 } 913 914 /* 915 * Generic scan of exact records. Note that indirect blocks are 916 * automatically recursed and will not be returned. 917 */ 918 chain = hammer2_chain_lookup(&parent, &key_next, 919 xop->key_beg, xop->key_end, 920 &cache_index, xop->lookup_flags); 921 while (chain) { 922 error = hammer2_xop_feed(&xop->head, chain, clindex, 0); 923 if (error) 924 break; 925 chain = hammer2_chain_next(&parent, chain, &key_next, 926 key_next, xop->key_end, 927 &cache_index, xop->lookup_flags); 928 } 929 if (chain) { 930 hammer2_chain_unlock(chain); 931 hammer2_chain_drop(chain); 932 } 933 hammer2_chain_unlock(parent); 934 hammer2_chain_drop(parent); 935 done: 936 hammer2_xop_feed(&xop->head, NULL, clindex, error); 937 } 938