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 the directory entry. If the
277 * entry is a hardlink pointer, this function will also remove the
278 * hardlink target if the target's nlinks is 1.
280 * The frontend is responsible for moving open inodes to the hidden directory
281 * and for decrementing nlinks.
284 hammer2_xop_unlink(hammer2_xop_t *arg, int clindex)
286 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
287 hammer2_chain_t *parent;
288 hammer2_chain_t *chain;
289 const hammer2_inode_data_t *ripdata;
292 hammer2_key_t key_next;
294 int cache_index = -1; /* XXX */
298 * Requires exclusive lock
300 parent = hammer2_inode_chain(xop->head.ip1, clindex,
301 HAMMER2_RESOLVE_ALWAYS);
303 if (parent == NULL) {
304 kprintf("xop_nresolve: NULL parent\n");
308 name = xop->head.name1;
309 name_len = xop->head.name1_len;
312 * Lookup the directory entry
314 lhc = hammer2_dirhash(name, name_len);
315 chain = hammer2_chain_lookup(&parent, &key_next,
316 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
318 HAMMER2_LOOKUP_ALWAYS);
320 ripdata = &chain->data->ipdata;
321 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
322 ripdata->meta.name_len == name_len &&
323 bcmp(ripdata->filename, name, name_len) == 0) {
326 chain = hammer2_chain_next(&parent, chain, &key_next,
328 lhc + HAMMER2_DIRHASH_LOMASK,
330 HAMMER2_LOOKUP_ALWAYS);
334 * If the directory entry is a HARDLINK pointer then obtain the
335 * underlying file type for the directory typing tests and delete
336 * the HARDLINK pointer chain permanently. The frontend is left
337 * responsible for handling nlinks on and deleting the actual inode.
339 * If the directory entry is the actual inode then use its type
340 * for the directory typing tests and delete the chain, permanency
341 * depends on whether the inode is open or not.
343 * Check directory typing and delete the entry. Note that
344 * nlinks adjustments are made on the real inode by the frontend,
349 int dopermanent = xop->dopermanent;
352 type = chain->data->ipdata.meta.type;
353 if (type == HAMMER2_OBJTYPE_HARDLINK) {
354 type = chain->data->ipdata.meta.target_type;
355 dopermanent |= HAMMER2_DELETE_PERMANENT;
358 if (type == HAMMER2_OBJTYPE_DIRECTORY &&
359 checkdirempty(parent, chain, clindex) != 0) {
361 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
365 if (type != HAMMER2_OBJTYPE_DIRECTORY &&
370 * This deletes the directory entry itself, which is
371 * also the inode when nlinks == 1. Hardlink targets
372 * are handled in the next conditional.
374 error = chain->error;
375 hammer2_chain_delete(parent, chain,
376 xop->head.mtid, dopermanent);
381 * If the entry is a hardlink pointer, resolve it. If this is the
382 * last link, delete it. The frontend has the master copy of nlinks
383 * but we still have to make adjustments here to synchronize with it.
385 * On delete / adjust nlinks if there is no error. But we still need
386 * to resolve the hardlink to feed the inode's real chain back to
389 * XXX we are basically tracking the nlinks count by doing a delta
390 * adjustment instead of having the frontend pass the absolute
391 * value down. We really need to have the frontend pass the
392 * absolute value down (difficult because there might not be
393 * an 'ip'). See also hammer2_xop_nlink().
396 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
399 error2 = hammer2_chain_hardlink_find(&parent, &chain,
401 if (chain && error == 0 && error2 == 0 &&
402 (int64_t)chain->data->ipdata.meta.nlinks <= 1) {
403 hammer2_chain_delete(parent, chain,
406 } else if (chain && error == 0 && error2 == 0) {
407 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
408 --chain->data->ipdata.meta.nlinks;
415 * We always return the hardlink target (the real inode) for
419 hammer2_xop_feed(&xop->head, chain, clindex, error);
421 hammer2_chain_unlock(chain);
422 hammer2_chain_drop(chain);
426 hammer2_chain_unlock(parent);
427 hammer2_chain_drop(parent);
434 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
440 * If a hardlink pointer:
441 * The existing hardlink target {fdip,ip} must be moved to another
442 * directory {cdip,ip}
444 * If not a hardlink pointer:
445 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
446 * replace the original namespace {fdip,name} with a hardlink pointer.
449 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
451 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
453 hammer2_inode_data_t *wipdata;
454 hammer2_chain_t *parent;
455 hammer2_chain_t *chain;
456 hammer2_chain_t *tmp;
458 hammer2_key_t key_dummy;
459 int cache_index = -1;
464 * We need the precise parent chain to issue the deletion.
468 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
470 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
471 if (parent == NULL) {
476 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
481 KKASSERT(chain->parent == parent);
483 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
485 * Delete the original chain and hold onto it for the move
488 * Replace the namespace with a hardlink pointer if the
489 * chain being moved is not already a hardlink target.
491 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
495 error = hammer2_chain_create(&parent, &tmp, pmp,
497 HAMMER2_BREF_TYPE_INODE,
499 xop->head.mtid, 0, 0);
502 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0);
503 wipdata = &tmp->data->ipdata;
504 bzero(wipdata, sizeof(*wipdata));
505 wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
506 wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
507 bcopy(chain->data->ipdata.filename, wipdata->filename,
508 chain->data->ipdata.meta.name_len);
509 wipdata->meta.target_type = chain->data->ipdata.meta.type;
510 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
511 wipdata->meta.inum = ip->meta.inum;
512 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
513 wipdata->meta.nlinks = 1;
514 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
516 hammer2_chain_unlock(tmp);
517 hammer2_chain_drop(tmp);
518 } else if (xop->head.ip1 != xop->head.ip3) {
520 * Delete the hardlink target so it can be moved
523 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
527 * Deletion not necessary (just a nlinks update).
532 hammer2_chain_unlock(parent);
533 hammer2_chain_drop(parent);
537 * Ok, back to the deleted chain. We must reconnect this chain
538 * as a hardlink target to cdir (ip3).
540 * WARNING! Frontend assumes filename length is 18 bytes.
543 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
544 wipdata = &chain->data->ipdata;
545 ksnprintf(wipdata->filename, sizeof(wipdata->filename),
546 "0x%016jx", (intmax_t)ip->meta.inum);
547 wipdata->meta.name_len = strlen(wipdata->filename);
548 wipdata->meta.name_key = ip->meta.inum;
551 * We must seek parent properly for the create to reattach
552 * chain. XXX just use chain->parent or
553 * inode_chain_and_parent() ?
555 parent = hammer2_inode_chain(xop->head.ip3, clindex,
556 HAMMER2_RESOLVE_ALWAYS);
557 if (parent == NULL) {
561 tmp = hammer2_chain_lookup(&parent, &key_dummy,
562 ip->meta.inum, ip->meta.inum,
565 hammer2_chain_unlock(tmp);
566 hammer2_chain_drop(tmp);
570 error = hammer2_chain_create(&parent, &chain, pmp,
571 wipdata->meta.name_key, 0,
572 HAMMER2_BREF_TYPE_INODE,
574 xop->head.mtid, 0, 0);
580 * Bump nlinks to synchronize with frontend.
582 if (xop->nlinks_delta) {
583 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
584 chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
588 * To avoid having to scan the collision space we can simply
589 * reuse the inode's original name_key. But ip->meta.name_key
590 * may have already been updated by the front-end, so use xop->lhc.
593 hammer2_xop_feed(&xop->head, NULL, clindex, error);
595 hammer2_chain_unlock(parent);
596 hammer2_chain_drop(parent);
599 hammer2_chain_unlock(chain);
600 hammer2_chain_drop(chain);
606 * Backend for hammer2_vop_nrename()
608 * This handles the final step of renaming, either renaming the
609 * actual inode or renaming the hardlink pointer.
612 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
614 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
616 hammer2_chain_t *parent;
617 hammer2_chain_t *chain;
618 hammer2_chain_t *tmp;
620 hammer2_key_t key_dummy;
621 int cache_index = -1;
625 * We need the precise parent chain to issue the deletion.
627 * If this is not a hardlink target we can act on the inode,
628 * otherwise we have to locate the hardlink pointer.
634 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
636 * Find ip's direct parent chain.
638 parent = hammer2_inode_chain(ip, clindex,
639 HAMMER2_RESOLVE_ALWAYS);
641 hammer2_chain_getparent(&parent,
642 HAMMER2_RESOLVE_ALWAYS);
643 if (parent == NULL) {
647 chain = hammer2_inode_chain(ip, clindex,
648 HAMMER2_RESOLVE_ALWAYS);
655 * The hardlink pointer for the head.ip1 hardlink target
656 * is in fdip, do a namespace search.
658 const hammer2_inode_data_t *ripdata;
660 hammer2_key_t key_next;
664 parent = hammer2_inode_chain(xop->head.ip1, clindex,
665 HAMMER2_RESOLVE_ALWAYS);
666 if (parent == NULL) {
667 kprintf("xop_nrename: NULL parent\n");
671 name = xop->head.name1;
672 name_len = xop->head.name1_len;
675 * Lookup the directory entry
677 lhc = hammer2_dirhash(name, name_len);
678 chain = hammer2_chain_lookup(&parent, &key_next,
679 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
681 HAMMER2_LOOKUP_ALWAYS);
683 ripdata = &chain->data->ipdata;
684 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
685 ripdata->meta.name_len == name_len &&
686 bcmp(ripdata->filename, name, name_len) == 0) {
689 chain = hammer2_chain_next(&parent, chain, &key_next,
691 lhc + HAMMER2_DIRHASH_LOMASK,
693 HAMMER2_LOOKUP_ALWAYS);
698 /* XXX shouldn't happen, but does under fsstress */
699 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
707 * Delete it, then create it in the new namespace.
709 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
710 hammer2_chain_unlock(parent);
711 hammer2_chain_drop(parent);
712 parent = NULL; /* safety */
715 * Ok, back to the deleted chain. We must reconnect this chain
716 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
717 * is not otherwise modified.
719 * Frontend is expected to replicate the same inode meta data
722 * NOTE! This chain may not represent the actual inode, it
723 * can be a hardlink pointer.
725 * XXX in-inode parent directory specification?
727 if (chain->data->ipdata.meta.name_key != xop->lhc ||
728 xop->head.name1_len != xop->head.name2_len ||
729 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
730 hammer2_inode_data_t *wipdata;
732 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
733 wipdata = &chain->data->ipdata;
735 bzero(wipdata->filename, sizeof(wipdata->filename));
736 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
737 wipdata->meta.name_key = xop->lhc;
738 wipdata->meta.name_len = xop->head.name2_len;
740 if (chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
741 hammer2_inode_data_t *wipdata;
743 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
744 wipdata = &chain->data->ipdata;
746 wipdata->meta.iparent = xop->head.ip3->meta.inum;
750 * We must seek parent properly for the create.
752 parent = hammer2_inode_chain(xop->head.ip3, clindex,
753 HAMMER2_RESOLVE_ALWAYS);
754 if (parent == NULL) {
758 tmp = hammer2_chain_lookup(&parent, &key_dummy,
762 hammer2_chain_unlock(tmp);
763 hammer2_chain_drop(tmp);
768 error = hammer2_chain_create(&parent, &chain, pmp,
770 HAMMER2_BREF_TYPE_INODE,
772 xop->head.mtid, 0, 0);
774 hammer2_xop_feed(&xop->head, NULL, clindex, error);
776 hammer2_chain_unlock(parent);
777 hammer2_chain_drop(parent);
780 hammer2_chain_unlock(chain);
781 hammer2_chain_drop(chain);
786 * Directory collision resolver scan helper (backend, threaded).
788 * Used by the inode create code to locate an unused lhc.
791 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex)
793 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
794 hammer2_chain_t *parent;
795 hammer2_chain_t *chain;
796 hammer2_key_t key_next;
797 int cache_index = -1; /* XXX */
800 parent = hammer2_inode_chain(xop->head.ip1, clindex,
801 HAMMER2_RESOLVE_ALWAYS |
802 HAMMER2_RESOLVE_SHARED);
803 if (parent == NULL) {
804 kprintf("xop_nresolve: NULL parent\n");
811 * Lookup all possibly conflicting directory entries, the feed
812 * inherits the chain's lock so do not unlock it on the iteration.
814 chain = hammer2_chain_lookup(&parent, &key_next,
816 xop->lhc + HAMMER2_DIRHASH_LOMASK,
818 HAMMER2_LOOKUP_ALWAYS |
819 HAMMER2_LOOKUP_SHARED);
821 error = hammer2_xop_feed(&xop->head, chain, clindex,
824 hammer2_chain_unlock(chain);
825 hammer2_chain_drop(chain);
826 chain = NULL; /* safety */
829 chain = hammer2_chain_next(&parent, chain, &key_next,
831 xop->lhc + HAMMER2_DIRHASH_LOMASK,
833 HAMMER2_LOOKUP_ALWAYS |
834 HAMMER2_LOOKUP_SHARED);
837 hammer2_xop_feed(&xop->head, NULL, clindex, error);
839 hammer2_chain_unlock(parent);
840 hammer2_chain_drop(parent);
845 * Generic lookup of a specific key.
847 * Used by the inode hidden directory code to find the hidden directory.
850 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex)
852 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
853 hammer2_chain_t *parent;
854 hammer2_chain_t *chain;
855 hammer2_key_t key_next;
856 int cache_index = -1; /* XXX */
859 parent = hammer2_inode_chain(xop->head.ip1, clindex,
860 HAMMER2_RESOLVE_ALWAYS |
861 HAMMER2_RESOLVE_SHARED);
863 if (parent == NULL) {
869 * Lookup all possibly conflicting directory entries, the feed
870 * inherits the chain's lock so do not unlock it on the iteration.
872 chain = hammer2_chain_lookup(&parent, &key_next,
875 HAMMER2_LOOKUP_ALWAYS |
876 HAMMER2_LOOKUP_SHARED);
878 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
880 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
884 hammer2_chain_unlock(chain);
885 hammer2_chain_drop(chain);
888 hammer2_chain_unlock(parent);
889 hammer2_chain_drop(parent);
896 * WARNING! Fed chains must be locked shared so ownership can be transfered
897 * and to prevent frontend/backend stalls that would occur with an
898 * exclusive lock. The shared lock also allows chain->data to be
902 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex)
904 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
905 hammer2_chain_t *parent;
906 hammer2_chain_t *chain;
907 hammer2_key_t key_next;
908 int cache_index = -1;
912 * Assert required flags.
914 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
915 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
918 * The inode's chain is the iterator. If we cannot acquire it our
919 * contribution ends here.
921 parent = hammer2_inode_chain(xop->head.ip1, clindex,
923 if (parent == NULL) {
924 kprintf("xop_readdir: NULL parent\n");
929 * Generic scan of exact records. Note that indirect blocks are
930 * automatically recursed and will not be returned.
932 chain = hammer2_chain_lookup(&parent, &key_next,
933 xop->key_beg, xop->key_end,
934 &cache_index, xop->lookup_flags);
936 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
939 chain = hammer2_chain_next(&parent, chain, &key_next,
940 key_next, xop->key_end,
941 &cache_index, xop->lookup_flags);
944 hammer2_chain_unlock(chain);
945 hammer2_chain_drop(chain);
947 hammer2_chain_unlock(parent);
948 hammer2_chain_drop(parent);
950 hammer2_xop_feed(&xop->head, NULL, clindex, error);