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 *parent, hammer2_chain_t *chain, int clindex)
70 hammer2_key_t key_next;
75 chain = hammer2_chain_lookup_init(chain, 0);
77 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
79 error = hammer2_chain_hardlink_find(&parent, &chain,
82 hammer2_chain_unlock(parent);
83 hammer2_chain_drop(parent);
90 chain = hammer2_chain_lookup(&parent, &key_next,
91 HAMMER2_DIRHASH_VISIBLE,
97 hammer2_chain_unlock(chain);
98 hammer2_chain_drop(chain);
102 hammer2_chain_lookup_done(parent);
108 * Backend for hammer2_vfs_root()
110 * This is called when a newly mounted PFS has not yet synchronized
111 * to the inode_tid and modify_tid.
114 hammer2_xop_ipcluster(hammer2_xop_t *arg, int clindex)
116 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
117 hammer2_chain_t *chain;
120 chain = hammer2_inode_chain(xop->head.ip1, clindex,
121 HAMMER2_RESOLVE_ALWAYS |
122 HAMMER2_RESOLVE_SHARED);
124 error = chain->error;
128 hammer2_xop_feed(&xop->head, chain, clindex, error);
130 hammer2_chain_unlock(chain);
131 hammer2_chain_drop(chain);
136 * Backend for hammer2_vop_readdir()
139 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
141 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
142 hammer2_chain_t *parent;
143 hammer2_chain_t *chain;
144 hammer2_key_t key_next;
146 int cache_index = -1;
150 if (hammer2_debug & 0x0020)
151 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
154 * The inode's chain is the iterator. If we cannot acquire it our
155 * contribution ends here.
157 parent = hammer2_inode_chain(xop->head.ip1, clindex,
158 HAMMER2_RESOLVE_ALWAYS |
159 HAMMER2_RESOLVE_SHARED);
160 if (parent == NULL) {
161 kprintf("xop_readdir: NULL parent\n");
166 * Directory scan [re]start and loop, the feed inherits the chain's
167 * lock so do not unlock it on the iteration.
169 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
170 &cache_index, HAMMER2_LOOKUP_SHARED);
172 chain = hammer2_chain_lookup(&parent, &key_next,
173 lkey, HAMMER2_KEY_MAX,
175 HAMMER2_LOOKUP_SHARED);
178 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
181 chain = hammer2_chain_next(&parent, chain, &key_next,
182 key_next, HAMMER2_KEY_MAX,
184 HAMMER2_LOOKUP_SHARED);
187 hammer2_chain_unlock(chain);
188 hammer2_chain_drop(chain);
190 hammer2_chain_unlock(parent);
191 hammer2_chain_drop(parent);
193 hammer2_xop_feed(&xop->head, NULL, clindex, error);
197 * Backend for hammer2_vop_nresolve()
200 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
202 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
203 hammer2_chain_t *parent;
204 hammer2_chain_t *chain;
205 const hammer2_inode_data_t *ripdata;
208 hammer2_key_t key_next;
210 int cache_index = -1; /* XXX */
213 parent = hammer2_inode_chain(xop->head.ip1, clindex,
214 HAMMER2_RESOLVE_ALWAYS |
215 HAMMER2_RESOLVE_SHARED);
216 if (parent == NULL) {
217 kprintf("xop_nresolve: NULL parent\n");
222 name = xop->head.name1;
223 name_len = xop->head.name1_len;
226 * Lookup the directory entry
228 lhc = hammer2_dirhash(name, name_len);
229 chain = hammer2_chain_lookup(&parent, &key_next,
230 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
232 HAMMER2_LOOKUP_ALWAYS |
233 HAMMER2_LOOKUP_SHARED);
235 ripdata = &chain->data->ipdata;
236 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
237 ripdata->meta.name_len == name_len &&
238 bcmp(ripdata->filename, name, name_len) == 0) {
241 chain = hammer2_chain_next(&parent, chain, &key_next,
243 lhc + HAMMER2_DIRHASH_LOMASK,
245 HAMMER2_LOOKUP_ALWAYS |
246 HAMMER2_LOOKUP_SHARED);
250 * If the entry is a hardlink pointer, resolve it.
254 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
255 error = hammer2_chain_hardlink_find(&parent, &chain,
257 HAMMER2_LOOKUP_SHARED);
261 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
263 hammer2_chain_unlock(chain);
264 hammer2_chain_drop(chain);
267 hammer2_chain_unlock(parent);
268 hammer2_chain_drop(parent);
273 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper
274 * for hammer2_vop_nrename().
276 * This function locates and removes a directory entry. If the entry is
277 * a hardlink pointer, this function does NOT remove the hardlink target,
278 * but will lookup and return the hardlink target.
280 * Note that any hardlink target's nlinks may not be synchronized to the
281 * in-memory inode. hammer2_inode_unlink_finisher() is responsible for the
282 * final disposition of the hardlink target.
284 * If an inode pointer we lookup and return the actual inode. If not, we
285 * return the deleted directory entry.
287 * The frontend is responsible for moving open inodes to the hidden directory
288 * and for decrementing nlinks.
291 hammer2_xop_unlink(hammer2_xop_t *arg, int clindex)
293 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
294 hammer2_chain_t *parent;
295 hammer2_chain_t *chain;
296 const hammer2_inode_data_t *ripdata;
299 hammer2_key_t key_next;
301 int cache_index = -1; /* XXX */
305 * Requires exclusive lock
307 parent = hammer2_inode_chain(xop->head.ip1, clindex,
308 HAMMER2_RESOLVE_ALWAYS);
310 if (parent == NULL) {
311 kprintf("xop_nresolve: NULL parent\n");
315 name = xop->head.name1;
316 name_len = xop->head.name1_len;
319 * Lookup the directory entry
321 lhc = hammer2_dirhash(name, name_len);
322 chain = hammer2_chain_lookup(&parent, &key_next,
323 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
325 HAMMER2_LOOKUP_ALWAYS);
327 ripdata = &chain->data->ipdata;
328 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
329 ripdata->meta.name_len == name_len &&
330 bcmp(ripdata->filename, name, name_len) == 0) {
333 chain = hammer2_chain_next(&parent, chain, &key_next,
335 lhc + HAMMER2_DIRHASH_LOMASK,
337 HAMMER2_LOOKUP_ALWAYS);
341 * The directory entry will almost always be a hardlink pointer,
342 * which we permanently delete. Otherwise we go by xop->dopermanent.
343 * Note that the target chain's nlinks may not be synchronized with
344 * the in-memory hammer2_inode_t structure, so we don't try to do
345 * anything fancy here.
349 int dopermanent = xop->dopermanent;
353 * If the directory entry is the actual inode then use its
354 * type for the directory typing tests, otherwise if it is
355 * a hardlink pointer then use the secondary type field for
356 * directory typing tests.
358 * Also, hardlink pointers are always permanently deleted
359 * (because they aren't the actual inode).
361 type = chain->data->ipdata.meta.type;
362 if (type == HAMMER2_OBJTYPE_HARDLINK) {
363 type = chain->data->ipdata.meta.target_type;
364 dopermanent |= HAMMER2_DELETE_PERMANENT;
368 * Check directory typing and delete the entry. Note that
369 * nlinks adjustments are made on the real inode by the
370 * frontend, not here.
372 if (type == HAMMER2_OBJTYPE_DIRECTORY &&
373 checkdirempty(parent, chain, clindex) != 0) {
375 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
378 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
383 * This deletes the directory entry itself, which is
384 * also the inode when nlinks == 1. Hardlink targets
385 * are handled in the next conditional.
387 error = chain->error;
388 hammer2_chain_delete(parent, chain,
389 xop->head.mtid, dopermanent);
394 * If the entry is a hardlink pointer, resolve it. We do not try
395 * to manipulate the contents of the hardlink target as it might
396 * not be synchronized with the front-end hammer2_inode_t. Nor do
397 * we try to lookup the front-end hammer2_inode_t here (we are the
401 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
404 lhc = chain->data->ipdata.meta.inum;
406 error2 = hammer2_chain_hardlink_find(&parent, &chain,
409 kprintf("hardlink_find: %016jx %p failed\n",
411 error2 = 0; /* silently ignore */
418 * Return the inode target for further action. Typically used by
419 * hammer2_inode_unlink_finisher().
422 hammer2_xop_feed(&xop->head, chain, clindex, error);
424 hammer2_chain_unlock(chain);
425 hammer2_chain_drop(chain);
429 hammer2_chain_unlock(parent);
430 hammer2_chain_drop(parent);
437 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
443 * If a hardlink pointer:
444 * The existing hardlink target {fdip,ip} must be moved to another
445 * directory {cdip,ip}
447 * If not a hardlink pointer:
448 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
449 * replace the original namespace {fdip,name} with a hardlink pointer.
452 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
454 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
456 hammer2_inode_data_t *wipdata;
457 hammer2_chain_t *parent;
458 hammer2_chain_t *chain;
459 hammer2_chain_t *tmp;
461 hammer2_key_t key_dummy;
462 int cache_index = -1;
467 * We need the precise parent chain to issue the deletion.
471 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
473 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
474 if (parent == NULL) {
479 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
484 KKASSERT(chain->parent == parent);
486 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
488 * Delete the original chain and hold onto it for the move
491 * Replace the namespace with a hardlink pointer if the
492 * chain being moved is not already a hardlink target.
494 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
498 error = hammer2_chain_create(&parent, &tmp, pmp,
500 HAMMER2_BREF_TYPE_INODE,
502 xop->head.mtid, 0, 0);
505 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0);
506 wipdata = &tmp->data->ipdata;
507 bzero(wipdata, sizeof(*wipdata));
508 wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
509 wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
510 bcopy(chain->data->ipdata.filename, wipdata->filename,
511 chain->data->ipdata.meta.name_len);
512 wipdata->meta.target_type = chain->data->ipdata.meta.type;
513 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
514 wipdata->meta.inum = ip->meta.inum;
515 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
516 wipdata->meta.nlinks = 1;
517 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
519 hammer2_chain_unlock(tmp);
520 hammer2_chain_drop(tmp);
521 } else if (xop->head.ip1 != xop->head.ip3) {
523 * Delete the hardlink target so it can be moved
526 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
530 * Deletion not necessary (just a nlinks update).
535 hammer2_chain_unlock(parent);
536 hammer2_chain_drop(parent);
540 * Ok, back to the deleted chain. We must reconnect this chain
541 * as a hardlink target to cdir (ip3).
543 * WARNING! Frontend assumes filename length is 18 bytes.
546 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
547 wipdata = &chain->data->ipdata;
548 ksnprintf(wipdata->filename, sizeof(wipdata->filename),
549 "0x%016jx", (intmax_t)ip->meta.inum);
550 wipdata->meta.name_len = strlen(wipdata->filename);
551 wipdata->meta.name_key = ip->meta.inum;
554 * We must seek parent properly for the create to reattach
555 * chain. XXX just use chain->parent or
556 * inode_chain_and_parent() ?
558 parent = hammer2_inode_chain(xop->head.ip3, clindex,
559 HAMMER2_RESOLVE_ALWAYS);
560 if (parent == NULL) {
564 tmp = hammer2_chain_lookup(&parent, &key_dummy,
565 ip->meta.inum, ip->meta.inum,
568 hammer2_chain_unlock(tmp);
569 hammer2_chain_drop(tmp);
573 error = hammer2_chain_create(&parent, &chain, pmp,
574 wipdata->meta.name_key, 0,
575 HAMMER2_BREF_TYPE_INODE,
577 xop->head.mtid, 0, 0);
583 * Bump nlinks to synchronize with frontend.
585 if (xop->nlinks_delta) {
586 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
587 chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
591 * To avoid having to scan the collision space we can simply
592 * reuse the inode's original name_key. But ip->meta.name_key
593 * may have already been updated by the front-end, so use xop->lhc.
596 hammer2_xop_feed(&xop->head, NULL, clindex, error);
598 hammer2_chain_unlock(parent);
599 hammer2_chain_drop(parent);
602 hammer2_chain_unlock(chain);
603 hammer2_chain_drop(chain);
609 * Backend for hammer2_vop_nrename()
611 * This handles the final step of renaming, either renaming the
612 * actual inode or renaming the hardlink pointer.
615 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
617 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
619 hammer2_chain_t *parent;
620 hammer2_chain_t *chain;
621 hammer2_chain_t *tmp;
623 hammer2_key_t key_dummy;
624 int cache_index = -1;
628 * We need the precise parent chain to issue the deletion.
630 * If this is not a hardlink target we can act on the inode,
631 * otherwise we have to locate the hardlink pointer.
637 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
639 * Find ip's direct parent chain.
641 parent = hammer2_inode_chain(ip, clindex,
642 HAMMER2_RESOLVE_ALWAYS);
644 hammer2_chain_getparent(&parent,
645 HAMMER2_RESOLVE_ALWAYS);
646 if (parent == NULL) {
650 chain = hammer2_inode_chain(ip, clindex,
651 HAMMER2_RESOLVE_ALWAYS);
658 * The hardlink pointer for the head.ip1 hardlink target
659 * is in fdip, do a namespace search.
661 const hammer2_inode_data_t *ripdata;
663 hammer2_key_t key_next;
667 parent = hammer2_inode_chain(xop->head.ip1, clindex,
668 HAMMER2_RESOLVE_ALWAYS);
669 if (parent == NULL) {
670 kprintf("xop_nrename: NULL parent\n");
674 name = xop->head.name1;
675 name_len = xop->head.name1_len;
678 * Lookup the directory entry
680 lhc = hammer2_dirhash(name, name_len);
681 chain = hammer2_chain_lookup(&parent, &key_next,
682 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
684 HAMMER2_LOOKUP_ALWAYS);
686 ripdata = &chain->data->ipdata;
687 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
688 ripdata->meta.name_len == name_len &&
689 bcmp(ripdata->filename, name, name_len) == 0) {
692 chain = hammer2_chain_next(&parent, chain, &key_next,
694 lhc + HAMMER2_DIRHASH_LOMASK,
696 HAMMER2_LOOKUP_ALWAYS);
701 /* XXX shouldn't happen, but does under fsstress */
702 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
710 * Delete it, then create it in the new namespace.
712 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
713 hammer2_chain_unlock(parent);
714 hammer2_chain_drop(parent);
715 parent = NULL; /* safety */
718 * Ok, back to the deleted chain. We must reconnect this chain
719 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
720 * is not otherwise modified.
722 * Frontend is expected to replicate the same inode meta data
725 * NOTE! This chain may not represent the actual inode, it
726 * can be a hardlink pointer.
728 * XXX in-inode parent directory specification?
730 if (chain->data->ipdata.meta.name_key != xop->lhc ||
731 xop->head.name1_len != xop->head.name2_len ||
732 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
733 hammer2_inode_data_t *wipdata;
735 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
736 wipdata = &chain->data->ipdata;
738 bzero(wipdata->filename, sizeof(wipdata->filename));
739 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
740 wipdata->meta.name_key = xop->lhc;
741 wipdata->meta.name_len = xop->head.name2_len;
743 if (chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
744 hammer2_inode_data_t *wipdata;
746 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
747 wipdata = &chain->data->ipdata;
749 wipdata->meta.iparent = xop->head.ip3->meta.inum;
753 * We must seek parent properly for the create.
755 parent = hammer2_inode_chain(xop->head.ip3, clindex,
756 HAMMER2_RESOLVE_ALWAYS);
757 if (parent == NULL) {
761 tmp = hammer2_chain_lookup(&parent, &key_dummy,
765 hammer2_chain_unlock(tmp);
766 hammer2_chain_drop(tmp);
771 error = hammer2_chain_create(&parent, &chain, pmp,
773 HAMMER2_BREF_TYPE_INODE,
775 xop->head.mtid, 0, 0);
777 hammer2_xop_feed(&xop->head, NULL, clindex, error);
779 hammer2_chain_unlock(parent);
780 hammer2_chain_drop(parent);
783 hammer2_chain_unlock(chain);
784 hammer2_chain_drop(chain);
789 * Directory collision resolver scan helper (backend, threaded).
791 * Used by the inode create code to locate an unused lhc.
794 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex)
796 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
797 hammer2_chain_t *parent;
798 hammer2_chain_t *chain;
799 hammer2_key_t key_next;
800 int cache_index = -1; /* XXX */
803 parent = hammer2_inode_chain(xop->head.ip1, clindex,
804 HAMMER2_RESOLVE_ALWAYS |
805 HAMMER2_RESOLVE_SHARED);
806 if (parent == NULL) {
807 kprintf("xop_nresolve: NULL parent\n");
814 * Lookup all possibly conflicting directory entries, the feed
815 * inherits the chain's lock so do not unlock it on the iteration.
817 chain = hammer2_chain_lookup(&parent, &key_next,
819 xop->lhc + HAMMER2_DIRHASH_LOMASK,
821 HAMMER2_LOOKUP_ALWAYS |
822 HAMMER2_LOOKUP_SHARED);
824 error = hammer2_xop_feed(&xop->head, chain, clindex,
827 hammer2_chain_unlock(chain);
828 hammer2_chain_drop(chain);
829 chain = NULL; /* safety */
832 chain = hammer2_chain_next(&parent, chain, &key_next,
834 xop->lhc + HAMMER2_DIRHASH_LOMASK,
836 HAMMER2_LOOKUP_ALWAYS |
837 HAMMER2_LOOKUP_SHARED);
840 hammer2_xop_feed(&xop->head, NULL, clindex, error);
842 hammer2_chain_unlock(parent);
843 hammer2_chain_drop(parent);
848 * Generic lookup of a specific key.
850 * Used by the inode hidden directory code to find the hidden directory.
853 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex)
855 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
856 hammer2_chain_t *parent;
857 hammer2_chain_t *chain;
858 hammer2_key_t key_next;
859 int cache_index = -1; /* XXX */
862 parent = hammer2_inode_chain(xop->head.ip1, clindex,
863 HAMMER2_RESOLVE_ALWAYS |
864 HAMMER2_RESOLVE_SHARED);
866 if (parent == NULL) {
872 * Lookup all possibly conflicting directory entries, the feed
873 * inherits the chain's lock so do not unlock it on the iteration.
875 chain = hammer2_chain_lookup(&parent, &key_next,
878 HAMMER2_LOOKUP_ALWAYS |
879 HAMMER2_LOOKUP_SHARED);
881 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
883 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
887 hammer2_chain_unlock(chain);
888 hammer2_chain_drop(chain);
891 hammer2_chain_unlock(parent);
892 hammer2_chain_drop(parent);
899 * WARNING! Fed chains must be locked shared so ownership can be transfered
900 * and to prevent frontend/backend stalls that would occur with an
901 * exclusive lock. The shared lock also allows chain->data to be
905 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex)
907 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
908 hammer2_chain_t *parent;
909 hammer2_chain_t *chain;
910 hammer2_key_t key_next;
911 int cache_index = -1;
915 * Assert required flags.
917 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
918 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
921 * The inode's chain is the iterator. If we cannot acquire it our
922 * contribution ends here.
924 parent = hammer2_inode_chain(xop->head.ip1, clindex,
926 if (parent == NULL) {
927 kprintf("xop_readdir: NULL parent\n");
932 * Generic scan of exact records. Note that indirect blocks are
933 * automatically recursed and will not be returned.
935 chain = hammer2_chain_lookup(&parent, &key_next,
936 xop->key_beg, xop->key_end,
937 &cache_index, xop->lookup_flags);
939 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
942 chain = hammer2_chain_next(&parent, chain, &key_next,
943 key_next, xop->key_end,
944 &cache_index, xop->lookup_flags);
947 hammer2_chain_unlock(chain);
948 hammer2_chain_drop(chain);
950 hammer2_chain_unlock(parent);
951 hammer2_chain_drop(parent);
953 hammer2_xop_feed(&xop->head, NULL, clindex, error);