2 * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved.
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)
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
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
37 * Per-node backend for kernel filesystem interface.
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.
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/fcntl.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>
56 #include <sys/objcache.h>
57 #include <sys/event.h>
59 #include <vfs/fifofs/fifo.h>
64 * Determine if the specified directory is empty. Returns 0 on success.
68 checkdirempty(hammer2_chain_t *orig_parent)
70 hammer2_chain_t *parent;
71 hammer2_chain_t *chain;
72 hammer2_key_t key_next;
76 parent = hammer2_chain_lookup_init(orig_parent, 0);
77 chain = hammer2_chain_lookup(&parent, &key_next,
78 HAMMER2_DIRHASH_VISIBLE,
81 error = chain ? ENOTEMPTY : 0;
83 hammer2_chain_unlock(chain);
84 hammer2_chain_drop(chain);
86 hammer2_chain_lookup_done(parent);
92 * Backend for hammer2_vfs_root()
94 * This is called when a newly mounted PFS has not yet synchronized
95 * to the inode_tid and modify_tid.
98 hammer2_xop_ipcluster(hammer2_xop_t *arg, int clindex)
100 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
101 hammer2_chain_t *chain;
104 chain = hammer2_inode_chain(xop->head.ip1, clindex,
105 HAMMER2_RESOLVE_ALWAYS |
106 HAMMER2_RESOLVE_SHARED);
108 error = chain->error;
112 hammer2_xop_feed(&xop->head, chain, clindex, error);
114 hammer2_chain_unlock(chain);
115 hammer2_chain_drop(chain);
120 * Backend for hammer2_vop_readdir()
123 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
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;
130 int cache_index = -1;
134 if (hammer2_debug & 0x0020)
135 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
138 * The inode's chain is the iterator. If we cannot acquire it our
139 * contribution ends here.
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");
150 * Directory scan [re]start and loop, the feed inherits the chain's
151 * lock so do not unlock it on the iteration.
153 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
154 &cache_index, HAMMER2_LOOKUP_SHARED);
156 chain = hammer2_chain_lookup(&parent, &key_next,
157 lkey, HAMMER2_KEY_MAX,
159 HAMMER2_LOOKUP_SHARED);
162 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
165 chain = hammer2_chain_next(&parent, chain, &key_next,
166 key_next, HAMMER2_KEY_MAX,
168 HAMMER2_LOOKUP_SHARED);
171 hammer2_chain_unlock(chain);
172 hammer2_chain_drop(chain);
174 hammer2_chain_unlock(parent);
175 hammer2_chain_drop(parent);
177 hammer2_xop_feed(&xop->head, NULL, clindex, error);
181 * Backend for hammer2_vop_nresolve()
184 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
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;
192 hammer2_key_t key_next;
194 int cache_index = -1; /* XXX */
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");
206 name = xop->head.name1;
207 name_len = xop->head.name1_len;
210 * Lookup the directory entry
212 lhc = hammer2_dirhash(name, name_len);
213 chain = hammer2_chain_lookup(&parent, &key_next,
214 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
216 HAMMER2_LOOKUP_ALWAYS |
217 HAMMER2_LOOKUP_SHARED);
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) {
225 chain = hammer2_chain_next(&parent, chain, &key_next,
227 lhc + HAMMER2_DIRHASH_LOMASK,
229 HAMMER2_LOOKUP_ALWAYS |
230 HAMMER2_LOOKUP_SHARED);
234 * If the entry is a hardlink pointer, resolve it.
238 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
239 error = hammer2_chain_hardlink_find(
242 HAMMER2_LOOKUP_SHARED);
246 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
248 hammer2_chain_unlock(chain);
249 hammer2_chain_drop(chain);
252 hammer2_chain_unlock(parent);
253 hammer2_chain_drop(parent);
258 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper
259 * for hammer2_vop_nrename().
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.
265 * The frontend is responsible for moving open inodes to the hidden directory
266 * and for decrementing nlinks.
269 hammer2_xop_unlink(hammer2_xop_t *arg, int clindex)
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;
277 hammer2_key_t key_next;
279 int cache_index = -1; /* XXX */
283 * Requires exclusive lock
285 parent = hammer2_inode_chain(xop->head.ip1, clindex,
286 HAMMER2_RESOLVE_ALWAYS);
288 if (parent == NULL) {
289 kprintf("xop_nresolve: NULL parent\n");
293 name = xop->head.name1;
294 name_len = xop->head.name1_len;
297 * Lookup the directory entry
299 lhc = hammer2_dirhash(name, name_len);
300 chain = hammer2_chain_lookup(&parent, &key_next,
301 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
303 HAMMER2_LOOKUP_ALWAYS);
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) {
311 chain = hammer2_chain_next(&parent, chain, &key_next,
313 lhc + HAMMER2_DIRHASH_LOMASK,
315 HAMMER2_LOOKUP_ALWAYS);
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.
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.
328 * Check directory typing and delete the entry. Note that
329 * nlinks adjustments are made on the real inode by the frontend,
334 int dopermanent = xop->dopermanent;
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;
343 if (type == HAMMER2_OBJTYPE_DIRECTORY &&
344 checkdirempty(chain) != 0) {
346 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
350 if (type != HAMMER2_OBJTYPE_DIRECTORY &&
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.
359 error = chain->error;
360 hammer2_chain_delete(parent, chain,
361 xop->head.mtid, dopermanent);
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.
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
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().
381 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
384 error2 = hammer2_chain_hardlink_find(xop->head.ip1,
386 if (chain && error == 0 && error2 == 0 &&
387 (int64_t)chain->data->ipdata.meta.nlinks <= 1) {
388 hammer2_chain_delete(parent, chain,
391 } else if (chain && error == 0 && error2 == 0) {
392 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
393 --chain->data->ipdata.meta.nlinks;
400 * Chains passed to feed are expected to be locked shared.
403 hammer2_chain_unlock(chain);
404 hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
405 HAMMER2_RESOLVE_SHARED);
409 * We always return the hardlink target (the real inode) for
413 hammer2_xop_feed(&xop->head, chain, clindex, error);
415 hammer2_chain_unlock(chain);
416 hammer2_chain_drop(chain);
420 hammer2_chain_unlock(parent);
421 hammer2_chain_drop(parent);
427 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
433 * If a hardlink pointer:
434 * The existing hardlink target {fdip,ip} must be moved to another
435 * directory {cdip,ip}
437 * If not a hardlink pointer:
438 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
439 * replace the original namespace {fdip,name} with a hardlink pointer.
442 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
444 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
446 hammer2_inode_data_t *wipdata;
447 hammer2_chain_t *parent;
448 hammer2_chain_t *chain;
449 hammer2_chain_t *tmp;
451 hammer2_key_t key_dummy;
452 int cache_index = -1;
457 * We need the precise parent chain to issue the deletion.
461 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
463 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
464 if (parent == NULL) {
469 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
474 KKASSERT(chain->parent == parent);
476 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
478 * Delete the original chain and hold onto it for the move
481 * Replace the namespace with a hardlink pointer if the
482 * chain being moved is not already a hardlink target.
484 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
488 error = hammer2_chain_create(&parent, &tmp, pmp,
490 HAMMER2_BREF_TYPE_INODE,
492 xop->head.mtid, 0, 0);
495 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0);
496 wipdata = &tmp->data->ipdata;
497 bzero(wipdata, sizeof(*wipdata));
498 wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
499 wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
500 bcopy(chain->data->ipdata.filename, wipdata->filename,
501 chain->data->ipdata.meta.name_len);
502 wipdata->meta.target_type = chain->data->ipdata.meta.type;
503 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
504 wipdata->meta.inum = ip->meta.inum;
505 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
506 wipdata->meta.nlinks = 1;
507 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
509 hammer2_chain_unlock(tmp);
510 hammer2_chain_drop(tmp);
511 } else if (xop->head.ip1 != xop->head.ip3) {
513 * Delete the hardlink target so it can be moved
516 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
520 * Deletion not necessary (just a nlinks update).
525 hammer2_chain_unlock(parent);
526 hammer2_chain_drop(parent);
530 * Ok, back to the deleted chain. We must reconnect this chain
531 * as a hardlink target to cdir (ip3).
533 * WARNING! Frontend assumes filename length is 18 bytes.
536 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
537 wipdata = &chain->data->ipdata;
538 ksnprintf(wipdata->filename, sizeof(wipdata->filename),
539 "0x%016jx", (intmax_t)ip->meta.inum);
540 wipdata->meta.name_len = strlen(wipdata->filename);
541 wipdata->meta.name_key = ip->meta.inum;
544 * We must seek parent properly for the create to reattach
545 * chain. XXX just use chain->parent or
546 * inode_chain_and_parent() ?
548 parent = hammer2_inode_chain(xop->head.ip3, clindex,
549 HAMMER2_RESOLVE_ALWAYS);
550 if (parent == NULL) {
554 tmp = hammer2_chain_lookup(&parent, &key_dummy,
555 ip->meta.inum, ip->meta.inum,
558 hammer2_chain_unlock(tmp);
559 hammer2_chain_drop(tmp);
563 error = hammer2_chain_create(&parent, &chain, pmp,
564 wipdata->meta.name_key, 0,
565 HAMMER2_BREF_TYPE_INODE,
567 xop->head.mtid, 0, 0);
573 * Bump nlinks to synchronize with frontend.
575 if (xop->nlinks_delta) {
576 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
577 chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
581 * To avoid having to scan the collision space we can simply
582 * reuse the inode's original name_key. But ip->meta.name_key
583 * may have already been updated by the front-end, so use xop->lhc.
585 * (frontend is responsible for fixing up ip->pip).
588 hammer2_xop_feed(&xop->head, NULL, clindex, error);
590 hammer2_chain_unlock(parent);
591 hammer2_chain_drop(parent);
594 hammer2_chain_unlock(chain);
595 hammer2_chain_drop(chain);
600 * Backend for hammer2_vop_nrename()
602 * This handles the final step of renaming, either renaming the
603 * actual inode or renaming the hardlink pointer.
606 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
608 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
610 hammer2_chain_t *parent;
611 hammer2_chain_t *chain;
612 hammer2_chain_t *tmp;
614 hammer2_key_t key_dummy;
615 int cache_index = -1;
619 * We need the precise parent chain to issue the deletion.
621 * If this is not a hardlink target we can act on the inode,
622 * otherwise we have to locate the hardlink pointer.
628 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
630 * Find ip's direct parent chain.
632 parent = hammer2_inode_chain(ip, clindex,
633 HAMMER2_RESOLVE_ALWAYS);
635 hammer2_chain_getparent(&parent,
636 HAMMER2_RESOLVE_ALWAYS);
637 if (parent == NULL) {
641 chain = hammer2_inode_chain(ip, clindex,
642 HAMMER2_RESOLVE_ALWAYS);
649 * The hardlink pointer for the head.ip1 hardlink target
650 * is in fdip, do a namespace search.
652 const hammer2_inode_data_t *ripdata;
654 hammer2_key_t key_next;
658 parent = hammer2_inode_chain(xop->head.ip1, clindex,
659 HAMMER2_RESOLVE_ALWAYS);
660 if (parent == NULL) {
661 kprintf("xop_nrename: NULL parent\n");
665 name = xop->head.name1;
666 name_len = xop->head.name1_len;
669 * Lookup the directory entry
671 lhc = hammer2_dirhash(name, name_len);
672 chain = hammer2_chain_lookup(&parent, &key_next,
673 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
675 HAMMER2_LOOKUP_ALWAYS);
677 ripdata = &chain->data->ipdata;
678 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
679 ripdata->meta.name_len == name_len &&
680 bcmp(ripdata->filename, name, name_len) == 0) {
683 chain = hammer2_chain_next(&parent, chain, &key_next,
685 lhc + HAMMER2_DIRHASH_LOMASK,
687 HAMMER2_LOOKUP_ALWAYS);
692 /* XXX shouldn't happen, but does under fsstress */
693 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
701 * Delete it, then create it in the new namespace.
703 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
704 hammer2_chain_unlock(parent);
705 hammer2_chain_drop(parent);
706 parent = NULL; /* safety */
709 * Ok, back to the deleted chain. We must reconnect this chain
710 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
711 * is not otherwise modified.
713 * Frontend is expected to replicate the same inode meta data
716 * NOTE! This chain may not represent the actual inode, it
717 * can be a hardlink pointer.
719 * XXX in-inode parent directory specification?
721 if (chain->data->ipdata.meta.name_key != xop->lhc ||
722 xop->head.name1_len != xop->head.name2_len ||
723 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
724 hammer2_inode_data_t *wipdata;
726 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
727 wipdata = &chain->data->ipdata;
729 bzero(wipdata->filename, sizeof(wipdata->filename));
730 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
731 wipdata->meta.name_key = xop->lhc;
732 wipdata->meta.name_len = xop->head.name2_len;
736 * We must seek parent properly for the create.
738 parent = hammer2_inode_chain(xop->head.ip3, clindex,
739 HAMMER2_RESOLVE_ALWAYS);
740 if (parent == NULL) {
744 tmp = hammer2_chain_lookup(&parent, &key_dummy,
748 hammer2_chain_unlock(tmp);
749 hammer2_chain_drop(tmp);
754 error = hammer2_chain_create(&parent, &chain, pmp,
756 HAMMER2_BREF_TYPE_INODE,
758 xop->head.mtid, 0, 0);
760 * (frontend is responsible for fixing up ip->pip).
763 hammer2_xop_feed(&xop->head, NULL, clindex, error);
765 hammer2_chain_unlock(parent);
766 hammer2_chain_drop(parent);
769 hammer2_chain_unlock(chain);
770 hammer2_chain_drop(chain);
775 * Directory collision resolver scan helper (backend, threaded).
777 * Used by the inode create code to locate an unused lhc.
780 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex)
782 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
783 hammer2_chain_t *parent;
784 hammer2_chain_t *chain;
785 hammer2_key_t key_next;
786 int cache_index = -1; /* XXX */
789 parent = hammer2_inode_chain(xop->head.ip1, clindex,
790 HAMMER2_RESOLVE_ALWAYS |
791 HAMMER2_RESOLVE_SHARED);
792 if (parent == NULL) {
793 kprintf("xop_nresolve: NULL parent\n");
800 * Lookup all possibly conflicting directory entries, the feed
801 * inherits the chain's lock so do not unlock it on the iteration.
803 chain = hammer2_chain_lookup(&parent, &key_next,
805 xop->lhc + HAMMER2_DIRHASH_LOMASK,
807 HAMMER2_LOOKUP_ALWAYS |
808 HAMMER2_LOOKUP_SHARED);
810 error = hammer2_xop_feed(&xop->head, chain, clindex,
813 hammer2_chain_unlock(chain);
814 hammer2_chain_drop(chain);
815 chain = NULL; /* safety */
818 chain = hammer2_chain_next(&parent, chain, &key_next,
820 xop->lhc + HAMMER2_DIRHASH_LOMASK,
822 HAMMER2_LOOKUP_ALWAYS |
823 HAMMER2_LOOKUP_SHARED);
826 hammer2_xop_feed(&xop->head, NULL, clindex, error);
828 hammer2_chain_unlock(parent);
829 hammer2_chain_drop(parent);
834 * Generic lookup of a specific key.
836 * Used by the inode hidden directory code to find the hidden directory.
839 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex)
841 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
842 hammer2_chain_t *parent;
843 hammer2_chain_t *chain;
844 hammer2_key_t key_next;
845 int cache_index = -1; /* XXX */
848 parent = hammer2_inode_chain(xop->head.ip1, clindex,
849 HAMMER2_RESOLVE_ALWAYS |
850 HAMMER2_RESOLVE_SHARED);
852 if (parent == NULL) {
858 * Lookup all possibly conflicting directory entries, the feed
859 * inherits the chain's lock so do not unlock it on the iteration.
861 chain = hammer2_chain_lookup(&parent, &key_next,
864 HAMMER2_LOOKUP_ALWAYS |
865 HAMMER2_LOOKUP_SHARED);
867 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
869 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
873 hammer2_chain_unlock(chain);
874 hammer2_chain_drop(chain);
877 hammer2_chain_unlock(parent);
878 hammer2_chain_drop(parent);
886 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex)
888 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
889 hammer2_chain_t *parent;
890 hammer2_chain_t *chain;
891 hammer2_key_t key_next;
892 int cache_index = -1;
896 * The inode's chain is the iterator. If we cannot acquire it our
897 * contribution ends here.
899 parent = hammer2_inode_chain(xop->head.ip1, clindex,
900 HAMMER2_RESOLVE_ALWAYS |
901 HAMMER2_RESOLVE_SHARED);
902 if (parent == NULL) {
903 kprintf("xop_readdir: NULL parent\n");
908 * Generic scan of exact records. Note that indirect blocks are
909 * automatically recursed and will not be returned.
911 chain = hammer2_chain_lookup(&parent, &key_next,
912 xop->key_beg, xop->key_end,
913 &cache_index, HAMMER2_LOOKUP_SHARED |
914 HAMMER2_LOOKUP_NODIRECT);
916 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
919 chain = hammer2_chain_next(&parent, chain, &key_next,
920 key_next, xop->key_end,
922 HAMMER2_LOOKUP_SHARED |
923 HAMMER2_LOOKUP_NODIRECT);
926 hammer2_chain_unlock(chain);
927 hammer2_chain_drop(chain);
929 hammer2_chain_unlock(parent);
930 hammer2_chain_drop(parent);
932 hammer2_xop_feed(&xop->head, NULL, clindex, error);