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 * Backend for hammer2_vfs_root()
66 * This is called when a newly mounted PFS has not yet synchronized
67 * to the inode_tid and modify_tid.
70 hammer2_xop_ipcluster(hammer2_xop_t *arg, int clindex)
72 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
73 hammer2_chain_t *chain;
76 chain = hammer2_inode_chain(xop->head.ip1, clindex,
77 HAMMER2_RESOLVE_ALWAYS |
78 HAMMER2_RESOLVE_SHARED);
84 hammer2_xop_feed(&xop->head, chain, clindex, error);
86 hammer2_chain_drop(chain);
90 * Backend for hammer2_vop_readdir()
93 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
95 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
96 hammer2_chain_t *parent;
97 hammer2_chain_t *chain;
98 hammer2_key_t key_next;
100 int cache_index = -1;
104 if (hammer2_debug & 0x0020)
105 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
108 * The inode's chain is the iterator. If we cannot acquire it our
109 * contribution ends here.
111 parent = hammer2_inode_chain(xop->head.ip1, clindex,
112 HAMMER2_RESOLVE_ALWAYS |
113 HAMMER2_RESOLVE_SHARED);
114 if (parent == NULL) {
115 kprintf("xop_readdir: NULL parent\n");
120 * Directory scan [re]start and loop, the feed inherits the chain's
121 * lock so do not unlock it on the iteration.
123 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
124 &cache_index, HAMMER2_LOOKUP_SHARED);
126 chain = hammer2_chain_lookup(&parent, &key_next,
127 lkey, HAMMER2_KEY_MAX,
129 HAMMER2_LOOKUP_SHARED);
132 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
135 chain = hammer2_chain_next(&parent, chain, &key_next,
136 key_next, HAMMER2_KEY_MAX,
138 HAMMER2_LOOKUP_SHARED |
139 HAMMER2_LOOKUP_NOUNLOCK);
142 hammer2_chain_drop(chain);
143 hammer2_chain_unlock(parent);
144 hammer2_chain_drop(parent);
146 hammer2_xop_feed(&xop->head, NULL, clindex, error);
150 * Backend for hammer2_vop_nresolve()
153 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
155 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
156 hammer2_chain_t *parent;
157 hammer2_chain_t *chain;
158 const hammer2_inode_data_t *ripdata;
161 hammer2_key_t key_next;
163 int cache_index = -1; /* XXX */
166 parent = hammer2_inode_chain(xop->head.ip1, clindex,
167 HAMMER2_RESOLVE_ALWAYS |
168 HAMMER2_RESOLVE_SHARED);
169 if (parent == NULL) {
170 kprintf("xop_nresolve: NULL parent\n");
175 name = xop->head.name1;
176 name_len = xop->head.name1_len;
179 * Lookup the directory entry
181 lhc = hammer2_dirhash(name, name_len);
182 chain = hammer2_chain_lookup(&parent, &key_next,
183 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
185 HAMMER2_LOOKUP_ALWAYS |
186 HAMMER2_LOOKUP_SHARED);
188 ripdata = &chain->data->ipdata;
189 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
190 ripdata->meta.name_len == name_len &&
191 bcmp(ripdata->filename, name, name_len) == 0) {
194 chain = hammer2_chain_next(&parent, chain, &key_next,
196 lhc + HAMMER2_DIRHASH_LOMASK,
198 HAMMER2_LOOKUP_ALWAYS |
199 HAMMER2_LOOKUP_SHARED);
203 * If the entry is a hardlink pointer, resolve it.
207 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
208 error = hammer2_chain_hardlink_find(
211 HAMMER2_RESOLVE_SHARED);
215 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
217 /* leave lock intact for feed */
218 hammer2_chain_drop(chain);
221 hammer2_chain_unlock(parent);
222 hammer2_chain_drop(parent);
227 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper
228 * for hammer2_vop_nrename().
230 * This function locates and removes the directory entry. If the
231 * entry is a hardlink pointer, this function will also remove the
232 * hardlink target if the target's nlinks is 1.
234 * The frontend is responsible for moving open inodes to the hidden directory
235 * and for decrementing nlinks.
238 hammer2_xop_unlink(hammer2_xop_t *arg, int clindex)
240 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
241 hammer2_chain_t *parent;
242 hammer2_chain_t *chain;
243 const hammer2_inode_data_t *ripdata;
246 hammer2_key_t key_next;
248 int cache_index = -1; /* XXX */
252 * Requires exclusive lock
254 parent = hammer2_inode_chain(xop->head.ip1, clindex,
255 HAMMER2_RESOLVE_ALWAYS);
256 if (parent == NULL) {
257 kprintf("xop_nresolve: NULL parent\n");
262 name = xop->head.name1;
263 name_len = xop->head.name1_len;
266 * Lookup the directory entry
268 lhc = hammer2_dirhash(name, name_len);
269 chain = hammer2_chain_lookup(&parent, &key_next,
270 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
272 HAMMER2_LOOKUP_ALWAYS);
274 ripdata = &chain->data->ipdata;
275 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
276 ripdata->meta.name_len == name_len &&
277 bcmp(ripdata->filename, name, name_len) == 0) {
280 chain = hammer2_chain_next(&parent, chain, &key_next,
282 lhc + HAMMER2_DIRHASH_LOMASK,
284 HAMMER2_LOOKUP_ALWAYS);
288 * If the directory entry is a HARDLINK pointer then obtain the
289 * underlying file type for the directory typing tests and delete
290 * the HARDLINK pointer chain permanently. The frontend is left
291 * responsible for handling nlinks on and deleting the actual inode.
293 * If the directory entry is the actual inode then use its type
294 * for the directory typing tests and delete the chain, permanency
295 * depends on whether the inode is open or not.
297 * Check directory typing and delete the entry. Note that
298 * nlinks adjustments are made on the real inode by the frontend,
303 int dopermanent = xop->dopermanent;
306 type = chain->data->ipdata.meta.type;
307 if (type == HAMMER2_OBJTYPE_HARDLINK) {
308 type = chain->data->ipdata.meta.target_type;
309 dopermanent |= HAMMER2_DELETE_PERMANENT;
312 if (type == HAMMER2_OBJTYPE_DIRECTORY &&
316 if (type != HAMMER2_OBJTYPE_DIRECTORY &&
321 * This deletes the directory entry itself, which is
322 * also the inode when nlinks == 1. Hardlink targets
323 * are handled in the next conditional.
325 hammer2_chain_delete(parent, chain,
326 xop->head.mtid, dopermanent);
331 * If the entry is a hardlink pointer, resolve it. If this is the
332 * last link, delete it. The frontend has the master copy of nlinks
333 * but we still have to make adjustments here to synchronize with it.
335 * On delete / adjust nlinks if there is no error. But we still need
336 * to resolve the hardlink to feed the inode's real chain back to
339 * XXX we are basically tracking the nlinks count by doing a delta
340 * adjustment instead of having the frontend pass the absolute
341 * value down. We really need to have the frontend pass the
342 * absolute value down (difficult because there might not be
343 * an 'ip'). See also hammer2_xop_nlink().
346 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
349 error2 = hammer2_chain_hardlink_find(xop->head.ip1,
351 if (chain && error == 0 && error2 == 0 &&
352 (int64_t)chain->data->ipdata.meta.nlinks <= 1) {
353 hammer2_chain_delete(parent, chain,
356 } else if (chain && error == 0 && error2 == 0) {
357 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
358 --chain->data->ipdata.meta.nlinks;
365 * Chains passed to feed are expected to be locked shared.
368 hammer2_chain_unlock(chain);
369 hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
370 HAMMER2_RESOLVE_SHARED);
374 * We always return the hardlink target (the real inode) for
378 hammer2_xop_feed(&xop->head, chain, clindex, error);
380 hammer2_chain_drop(chain);
382 hammer2_chain_unlock(parent);
383 hammer2_chain_drop(parent);
388 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
394 * If a hardlink pointer:
395 * The existing hardlink target {fdip,ip} must be moved to another
396 * directory {cdip,ip}
398 * If not a hardlink pointer:
399 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
400 * replace the original namespace {fdip,name} with a hardlink pointer.
403 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
405 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
407 hammer2_inode_data_t *wipdata;
408 hammer2_chain_t *parent;
409 hammer2_chain_t *chain;
410 hammer2_chain_t *tmp;
412 hammer2_key_t key_dummy;
413 int cache_index = -1;
418 * We need the precise parent chain to issue the deletion.
422 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
424 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
425 if (parent == NULL) {
430 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
435 KKASSERT(chain->parent == parent);
437 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
439 * Delete the original chain and hold onto it for the move
442 * Replace the namespace with a hardlink pointer if the
443 * chain being moved is not already a hardlink target.
445 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
449 error = hammer2_chain_create(&parent, &tmp, pmp,
451 HAMMER2_BREF_TYPE_INODE,
453 xop->head.mtid, 0, 0);
456 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0);
457 wipdata = &tmp->data->ipdata;
458 bzero(wipdata, sizeof(*wipdata));
459 wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
460 wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
461 bcopy(chain->data->ipdata.filename, wipdata->filename,
462 chain->data->ipdata.meta.name_len);
463 wipdata->meta.target_type = chain->data->ipdata.meta.type;
464 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
465 wipdata->meta.inum = ip->meta.inum;
466 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
467 wipdata->meta.nlinks = 1;
468 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
470 hammer2_chain_unlock(tmp);
471 hammer2_chain_drop(tmp);
472 } else if (xop->head.ip1 != xop->head.ip3) {
474 * Delete the hardlink target so it can be moved
477 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
481 * Deletion not necessary (just a nlinks update).
486 hammer2_chain_unlock(parent);
487 hammer2_chain_drop(parent);
491 * Ok, back to the deleted chain. We must reconnect this chain
492 * as a hardlink target to cdir (ip3).
494 * WARNING! Frontend assumes filename length is 18 bytes.
497 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
498 wipdata = &chain->data->ipdata;
499 ksnprintf(wipdata->filename, sizeof(wipdata->filename),
500 "0x%016jx", (intmax_t)ip->meta.inum);
501 wipdata->meta.name_len = strlen(wipdata->filename);
502 wipdata->meta.name_key = ip->meta.inum;
505 * We must seek parent properly for the create to reattach
506 * chain. XXX just use chain->parent or
507 * inode_chain_and_parent() ?
509 parent = hammer2_inode_chain(xop->head.ip3, clindex,
510 HAMMER2_RESOLVE_ALWAYS);
511 if (parent == NULL) {
515 tmp = hammer2_chain_lookup(&parent, &key_dummy,
516 ip->meta.inum, ip->meta.inum,
519 hammer2_chain_unlock(tmp);
520 hammer2_chain_drop(tmp);
524 error = hammer2_chain_create(&parent, &chain, pmp,
525 wipdata->meta.name_key, 0,
526 HAMMER2_BREF_TYPE_INODE,
528 xop->head.mtid, 0, 0);
534 * Bump nlinks to synchronize with frontend.
536 if (xop->nlinks_delta) {
537 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
538 chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
542 * To avoid having to scan the collision space we can simply
543 * reuse the inode's original name_key. But ip->meta.name_key
544 * may have already been updated by the front-end, so use xop->lhc.
546 * (frontend is responsible for fixing up ip->pip).
549 hammer2_xop_feed(&xop->head, NULL, clindex, error);
551 hammer2_chain_unlock(parent);
552 hammer2_chain_drop(parent);
555 hammer2_chain_unlock(chain);
556 hammer2_chain_drop(chain);
561 * Backend for hammer2_vop_nrename()
563 * This handles the final step of renaming, either renaming the
564 * actual inode or renaming the hardlink pointer.
567 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
569 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
571 hammer2_chain_t *parent;
572 hammer2_chain_t *chain;
573 hammer2_chain_t *tmp;
575 hammer2_key_t key_dummy;
576 int cache_index = -1;
580 * We need the precise parent chain to issue the deletion.
582 * If this is not a hardlink target we can act on the inode,
583 * otherwise we have to locate the hardlink pointer.
589 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
591 * Find ip's direct parent chain.
593 parent = hammer2_inode_chain(ip, clindex,
594 HAMMER2_RESOLVE_ALWAYS);
596 hammer2_chain_getparent(&parent,
597 HAMMER2_RESOLVE_ALWAYS);
598 if (parent == NULL) {
602 chain = hammer2_inode_chain(ip, clindex,
603 HAMMER2_RESOLVE_ALWAYS);
610 * The hardlink pointer for the head.ip1 hardlink target
611 * is in fdip, do a namespace search.
613 const hammer2_inode_data_t *ripdata;
615 hammer2_key_t key_next;
619 parent = hammer2_inode_chain(xop->head.ip1, clindex,
620 HAMMER2_RESOLVE_ALWAYS);
621 if (parent == NULL) {
622 kprintf("xop_nrename: NULL parent\n");
626 name = xop->head.name1;
627 name_len = xop->head.name1_len;
630 * Lookup the directory entry
632 lhc = hammer2_dirhash(name, name_len);
633 chain = hammer2_chain_lookup(&parent, &key_next,
634 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
636 HAMMER2_LOOKUP_ALWAYS);
638 ripdata = &chain->data->ipdata;
639 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
640 ripdata->meta.name_len == name_len &&
641 bcmp(ripdata->filename, name, name_len) == 0) {
644 chain = hammer2_chain_next(&parent, chain, &key_next,
646 lhc + HAMMER2_DIRHASH_LOMASK,
648 HAMMER2_LOOKUP_ALWAYS);
653 /* XXX shouldn't happen, but does under fsstress */
654 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
662 * Delete it, then create it in the new namespace.
664 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
665 hammer2_chain_unlock(parent);
666 hammer2_chain_drop(parent);
667 parent = NULL; /* safety */
670 * Ok, back to the deleted chain. We must reconnect this chain
671 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
672 * is not otherwise modified.
674 * Frontend is expected to replicate the same inode meta data
677 * NOTE! This chain may not represent the actual inode, it
678 * can be a hardlink pointer.
680 * XXX in-inode parent directory specification?
682 if (chain->data->ipdata.meta.name_key != xop->lhc ||
683 xop->head.name1_len != xop->head.name2_len ||
684 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
685 hammer2_inode_data_t *wipdata;
687 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
688 wipdata = &chain->data->ipdata;
690 bzero(wipdata->filename, sizeof(wipdata->filename));
691 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
692 wipdata->meta.name_key = xop->lhc;
693 wipdata->meta.name_len = xop->head.name2_len;
697 * We must seek parent properly for the create.
699 parent = hammer2_inode_chain(xop->head.ip3, clindex,
700 HAMMER2_RESOLVE_ALWAYS);
701 if (parent == NULL) {
705 tmp = hammer2_chain_lookup(&parent, &key_dummy,
709 hammer2_chain_unlock(tmp);
710 hammer2_chain_drop(tmp);
715 error = hammer2_chain_create(&parent, &chain, pmp,
717 HAMMER2_BREF_TYPE_INODE,
719 xop->head.mtid, 0, 0);
721 * (frontend is responsible for fixing up ip->pip).
724 hammer2_xop_feed(&xop->head, NULL, clindex, error);
726 hammer2_chain_unlock(parent);
727 hammer2_chain_drop(parent);
730 hammer2_chain_unlock(chain);
731 hammer2_chain_drop(chain);
736 * Directory collision resolver scan helper (backend, threaded).
738 * Used by the inode create code to locate an unused lhc.
741 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex)
743 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
744 hammer2_chain_t *parent;
745 hammer2_chain_t *chain;
746 hammer2_key_t key_next;
747 int cache_index = -1; /* XXX */
750 parent = hammer2_inode_chain(xop->head.ip1, clindex,
751 HAMMER2_RESOLVE_ALWAYS |
752 HAMMER2_RESOLVE_SHARED);
753 if (parent == NULL) {
754 kprintf("xop_nresolve: NULL parent\n");
761 * Lookup all possibly conflicting directory entries, the feed
762 * inherits the chain's lock so do not unlock it on the iteration.
764 chain = hammer2_chain_lookup(&parent, &key_next,
766 xop->lhc + HAMMER2_DIRHASH_LOMASK,
768 HAMMER2_LOOKUP_ALWAYS |
769 HAMMER2_LOOKUP_SHARED);
771 error = hammer2_xop_feed(&xop->head, chain, clindex,
774 hammer2_chain_drop(chain);
775 chain = NULL; /* safety */
778 chain = hammer2_chain_next(&parent, chain, &key_next,
780 xop->lhc + HAMMER2_DIRHASH_LOMASK,
782 HAMMER2_LOOKUP_ALWAYS |
783 HAMMER2_LOOKUP_SHARED |
784 HAMMER2_LOOKUP_NOUNLOCK);
787 hammer2_xop_feed(&xop->head, NULL, clindex, error);
789 hammer2_chain_unlock(parent);
790 hammer2_chain_drop(parent);
795 * Generic lookup of a specific key.
797 * Used by the inode hidden directory code to find the hidden directory.
800 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex)
802 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
803 hammer2_chain_t *parent;
804 hammer2_chain_t *chain;
805 hammer2_key_t key_next;
806 int cache_index = -1; /* XXX */
809 parent = hammer2_inode_chain(xop->head.ip1, clindex,
810 HAMMER2_RESOLVE_ALWAYS |
811 HAMMER2_RESOLVE_SHARED);
813 if (parent == NULL) {
819 * Lookup all possibly conflicting directory entries, the feed
820 * inherits the chain's lock so do not unlock it on the iteration.
822 chain = hammer2_chain_lookup(&parent, &key_next,
825 HAMMER2_LOOKUP_ALWAYS |
826 HAMMER2_LOOKUP_SHARED);
828 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
830 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
834 /* leave lock intact for feed */
835 hammer2_chain_drop(chain);
838 hammer2_chain_unlock(parent);
839 hammer2_chain_drop(parent);
847 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex)
849 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
850 hammer2_chain_t *parent;
851 hammer2_chain_t *chain;
852 hammer2_key_t key_next;
853 int cache_index = -1;
857 * The inode's chain is the iterator. If we cannot acquire it our
858 * contribution ends here.
860 parent = hammer2_inode_chain(xop->head.ip1, clindex,
861 HAMMER2_RESOLVE_ALWAYS |
862 HAMMER2_RESOLVE_SHARED);
863 if (parent == NULL) {
864 kprintf("xop_readdir: NULL parent\n");
869 * Generic scan of exact records. Note that indirect blocks are
870 * automatically recursed and will not be returned.
872 chain = hammer2_chain_lookup(&parent, &key_next,
873 xop->key_beg, xop->key_end,
874 &cache_index, HAMMER2_LOOKUP_SHARED |
875 HAMMER2_LOOKUP_NODIRECT);
877 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
880 chain = hammer2_chain_next(&parent, chain, &key_next,
881 key_next, xop->key_end,
883 HAMMER2_LOOKUP_SHARED |
884 HAMMER2_LOOKUP_NODIRECT |
885 HAMMER2_LOOKUP_NOUNLOCK);
888 hammer2_chain_drop(chain);
889 hammer2_chain_unlock(parent);
890 hammer2_chain_drop(parent);
892 hammer2_xop_feed(&xop->head, NULL, clindex, error);