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_lock_downgrade(chain);
406 * We always return the hardlink target (the real inode) for
410 hammer2_xop_feed(&xop->head, chain, clindex, error);
412 hammer2_chain_unlock(chain);
413 hammer2_chain_drop(chain);
417 hammer2_chain_unlock(parent);
418 hammer2_chain_drop(parent);
424 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
430 * If a hardlink pointer:
431 * The existing hardlink target {fdip,ip} must be moved to another
432 * directory {cdip,ip}
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.
439 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
441 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
443 hammer2_inode_data_t *wipdata;
444 hammer2_chain_t *parent;
445 hammer2_chain_t *chain;
446 hammer2_chain_t *tmp;
448 hammer2_key_t key_dummy;
449 int cache_index = -1;
454 * We need the precise parent chain to issue the deletion.
458 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
460 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
461 if (parent == NULL) {
466 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
471 KKASSERT(chain->parent == parent);
473 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
475 * Delete the original chain and hold onto it for the move
478 * Replace the namespace with a hardlink pointer if the
479 * chain being moved is not already a hardlink target.
481 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
485 error = hammer2_chain_create(&parent, &tmp, pmp,
487 HAMMER2_BREF_TYPE_INODE,
489 xop->head.mtid, 0, 0);
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;
506 hammer2_chain_unlock(tmp);
507 hammer2_chain_drop(tmp);
508 } else if (xop->head.ip1 != xop->head.ip3) {
510 * Delete the hardlink target so it can be moved
513 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
517 * Deletion not necessary (just a nlinks update).
522 hammer2_chain_unlock(parent);
523 hammer2_chain_drop(parent);
527 * Ok, back to the deleted chain. We must reconnect this chain
528 * as a hardlink target to cdir (ip3).
530 * WARNING! Frontend assumes filename length is 18 bytes.
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;
541 * We must seek parent properly for the create to reattach
542 * chain. XXX just use chain->parent or
543 * inode_chain_and_parent() ?
545 parent = hammer2_inode_chain(xop->head.ip3, clindex,
546 HAMMER2_RESOLVE_ALWAYS);
547 if (parent == NULL) {
551 tmp = hammer2_chain_lookup(&parent, &key_dummy,
552 ip->meta.inum, ip->meta.inum,
555 hammer2_chain_unlock(tmp);
556 hammer2_chain_drop(tmp);
560 error = hammer2_chain_create(&parent, &chain, pmp,
561 wipdata->meta.name_key, 0,
562 HAMMER2_BREF_TYPE_INODE,
564 xop->head.mtid, 0, 0);
570 * Bump nlinks to synchronize with frontend.
572 if (xop->nlinks_delta) {
573 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
574 chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
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.
582 * (frontend is responsible for fixing up ip->pip).
585 hammer2_xop_feed(&xop->head, NULL, clindex, error);
587 hammer2_chain_unlock(parent);
588 hammer2_chain_drop(parent);
591 hammer2_chain_unlock(chain);
592 hammer2_chain_drop(chain);
597 * Backend for hammer2_vop_nrename()
599 * This handles the final step of renaming, either renaming the
600 * actual inode or renaming the hardlink pointer.
603 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
605 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
607 hammer2_chain_t *parent;
608 hammer2_chain_t *chain;
609 hammer2_chain_t *tmp;
611 hammer2_key_t key_dummy;
612 int cache_index = -1;
616 * We need the precise parent chain to issue the deletion.
618 * If this is not a hardlink target we can act on the inode,
619 * otherwise we have to locate the hardlink pointer.
625 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
627 * Find ip's direct parent chain.
629 parent = hammer2_inode_chain(ip, clindex,
630 HAMMER2_RESOLVE_ALWAYS);
632 hammer2_chain_getparent(&parent,
633 HAMMER2_RESOLVE_ALWAYS);
634 if (parent == NULL) {
638 chain = hammer2_inode_chain(ip, clindex,
639 HAMMER2_RESOLVE_ALWAYS);
646 * The hardlink pointer for the head.ip1 hardlink target
647 * is in fdip, do a namespace search.
649 const hammer2_inode_data_t *ripdata;
651 hammer2_key_t key_next;
655 parent = hammer2_inode_chain(xop->head.ip1, clindex,
656 HAMMER2_RESOLVE_ALWAYS);
657 if (parent == NULL) {
658 kprintf("xop_nrename: NULL parent\n");
662 name = xop->head.name1;
663 name_len = xop->head.name1_len;
666 * Lookup the directory entry
668 lhc = hammer2_dirhash(name, name_len);
669 chain = hammer2_chain_lookup(&parent, &key_next,
670 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
672 HAMMER2_LOOKUP_ALWAYS);
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) {
680 chain = hammer2_chain_next(&parent, chain, &key_next,
682 lhc + HAMMER2_DIRHASH_LOMASK,
684 HAMMER2_LOOKUP_ALWAYS);
689 /* XXX shouldn't happen, but does under fsstress */
690 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
698 * Delete it, then create it in the new namespace.
700 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
701 hammer2_chain_unlock(parent);
702 hammer2_chain_drop(parent);
703 parent = NULL; /* safety */
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.
710 * Frontend is expected to replicate the same inode meta data
713 * NOTE! This chain may not represent the actual inode, it
714 * can be a hardlink pointer.
716 * XXX in-inode parent directory specification?
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;
723 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
724 wipdata = &chain->data->ipdata;
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;
733 * We must seek parent properly for the create.
735 parent = hammer2_inode_chain(xop->head.ip3, clindex,
736 HAMMER2_RESOLVE_ALWAYS);
737 if (parent == NULL) {
741 tmp = hammer2_chain_lookup(&parent, &key_dummy,
745 hammer2_chain_unlock(tmp);
746 hammer2_chain_drop(tmp);
751 error = hammer2_chain_create(&parent, &chain, pmp,
753 HAMMER2_BREF_TYPE_INODE,
755 xop->head.mtid, 0, 0);
757 * (frontend is responsible for fixing up ip->pip).
760 hammer2_xop_feed(&xop->head, NULL, clindex, error);
762 hammer2_chain_unlock(parent);
763 hammer2_chain_drop(parent);
766 hammer2_chain_unlock(chain);
767 hammer2_chain_drop(chain);
772 * Directory collision resolver scan helper (backend, threaded).
774 * Used by the inode create code to locate an unused lhc.
777 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex)
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 */
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");
797 * Lookup all possibly conflicting directory entries, the feed
798 * inherits the chain's lock so do not unlock it on the iteration.
800 chain = hammer2_chain_lookup(&parent, &key_next,
802 xop->lhc + HAMMER2_DIRHASH_LOMASK,
804 HAMMER2_LOOKUP_ALWAYS |
805 HAMMER2_LOOKUP_SHARED);
807 error = hammer2_xop_feed(&xop->head, chain, clindex,
810 hammer2_chain_unlock(chain);
811 hammer2_chain_drop(chain);
812 chain = NULL; /* safety */
815 chain = hammer2_chain_next(&parent, chain, &key_next,
817 xop->lhc + HAMMER2_DIRHASH_LOMASK,
819 HAMMER2_LOOKUP_ALWAYS |
820 HAMMER2_LOOKUP_SHARED);
823 hammer2_xop_feed(&xop->head, NULL, clindex, error);
825 hammer2_chain_unlock(parent);
826 hammer2_chain_drop(parent);
831 * Generic lookup of a specific key.
833 * Used by the inode hidden directory code to find the hidden directory.
836 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex)
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 */
845 parent = hammer2_inode_chain(xop->head.ip1, clindex,
846 HAMMER2_RESOLVE_ALWAYS |
847 HAMMER2_RESOLVE_SHARED);
849 if (parent == NULL) {
855 * Lookup all possibly conflicting directory entries, the feed
856 * inherits the chain's lock so do not unlock it on the iteration.
858 chain = hammer2_chain_lookup(&parent, &key_next,
861 HAMMER2_LOOKUP_ALWAYS |
862 HAMMER2_LOOKUP_SHARED);
864 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
866 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
870 hammer2_chain_unlock(chain);
871 hammer2_chain_drop(chain);
874 hammer2_chain_unlock(parent);
875 hammer2_chain_drop(parent);
883 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex)
885 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
886 hammer2_chain_t *parent;
887 hammer2_chain_t *chain;
888 hammer2_key_t key_next;
889 int cache_index = -1;
893 * The inode's chain is the iterator. If we cannot acquire it our
894 * contribution ends here.
896 parent = hammer2_inode_chain(xop->head.ip1, clindex,
897 HAMMER2_RESOLVE_ALWAYS |
898 HAMMER2_RESOLVE_SHARED);
899 if (parent == NULL) {
900 kprintf("xop_readdir: NULL parent\n");
905 * Generic scan of exact records. Note that indirect blocks are
906 * automatically recursed and will not be returned.
908 chain = hammer2_chain_lookup(&parent, &key_next,
909 xop->key_beg, xop->key_end,
910 &cache_index, HAMMER2_LOOKUP_SHARED |
911 HAMMER2_LOOKUP_NODIRECT);
913 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
916 chain = hammer2_chain_next(&parent, chain, &key_next,
917 key_next, xop->key_end,
919 HAMMER2_LOOKUP_SHARED |
920 HAMMER2_LOOKUP_NODIRECT);
923 hammer2_chain_unlock(chain);
924 hammer2_chain_drop(chain);
926 hammer2_chain_unlock(parent);
927 hammer2_chain_drop(parent);
929 hammer2_xop_feed(&xop->head, NULL, clindex, error);