2 * Copyright (c) 2011-2018 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.
66 * Caller assumes that we do not cycle the lock on oparent and ochain.
70 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
72 hammer2_chain_t *parent;
73 hammer2_chain_t *chain;
74 hammer2_key_t key_next;
80 if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
82 * Forward the directory entry to the directory inode.
83 * This is not strictly heirarchical so the locks kinda
84 * violate top-down lock order.
86 * Define an allowance for directory-entry -> dinode
87 * chain lock ordering, since directory entries have only
88 * one link the directory inode is kinda topologically
89 * underneath the directory entry, even though it isn't
92 inum = ochain->bref.embed.dirent.inum;
95 error = hammer2_chain_inode_find(ochain->pmp, inum,
99 hammer2_chain_unlock(parent);
100 hammer2_chain_drop(parent);
104 * The directory entry *is* the directory inode
106 chain = hammer2_chain_lookup_init(ochain, 0);
110 * Determine if the directory is empty or not by checking its
111 * visible namespace (the area which contains directory entries).
116 chain = hammer2_chain_lookup(&parent, &key_next,
117 HAMMER2_DIRHASH_VISIBLE,
122 error = HAMMER2_ERROR_ENOTEMPTY;
123 hammer2_chain_unlock(chain);
124 hammer2_chain_drop(chain);
126 hammer2_chain_lookup_done(parent);
132 * Backend for hammer2_vfs_root()
134 * This is called when a newly mounted PFS has not yet synchronized
135 * to the inode_tid and modify_tid.
138 hammer2_xop_ipcluster(hammer2_thread_t *thr, hammer2_xop_t *arg)
140 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
141 hammer2_chain_t *chain;
144 chain = hammer2_inode_chain(xop->head.ip1, thr->clindex,
145 HAMMER2_RESOLVE_ALWAYS |
146 HAMMER2_RESOLVE_SHARED);
148 error = chain->error;
150 error = HAMMER2_ERROR_EIO;
152 hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
154 hammer2_chain_unlock(chain);
155 hammer2_chain_drop(chain);
160 * Backend for hammer2_vop_readdir()
163 hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg)
165 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
166 hammer2_chain_t *parent;
167 hammer2_chain_t *chain;
168 hammer2_key_t key_next;
173 if (hammer2_debug & 0x0020)
174 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
177 * The inode's chain is the iterator. If we cannot acquire it our
178 * contribution ends here.
180 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
181 HAMMER2_RESOLVE_ALWAYS |
182 HAMMER2_RESOLVE_SHARED);
183 if (parent == NULL) {
184 kprintf("xop_readdir: NULL parent\n");
189 * Directory scan [re]start and loop, the feed inherits the chain's
190 * lock so do not unlock it on the iteration.
192 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
193 &error, HAMMER2_LOOKUP_SHARED);
195 chain = hammer2_chain_lookup(&parent, &key_next,
196 lkey, HAMMER2_KEY_MAX,
197 &error, HAMMER2_LOOKUP_SHARED);
200 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
203 chain = hammer2_chain_next(&parent, chain, &key_next,
204 key_next, HAMMER2_KEY_MAX,
205 &error, HAMMER2_LOOKUP_SHARED);
209 hammer2_chain_unlock(chain);
210 hammer2_chain_drop(chain);
212 hammer2_chain_unlock(parent);
213 hammer2_chain_drop(parent);
215 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
219 * Backend for hammer2_vop_nresolve()
222 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
224 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
225 hammer2_chain_t *parent;
226 hammer2_chain_t *chain;
229 hammer2_key_t key_next;
233 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
234 HAMMER2_RESOLVE_ALWAYS |
235 HAMMER2_RESOLVE_SHARED);
236 if (parent == NULL) {
237 kprintf("xop_nresolve: NULL parent\n");
239 error = HAMMER2_ERROR_EIO;
242 name = xop->head.name1;
243 name_len = xop->head.name1_len;
246 * Lookup the directory entry
248 lhc = hammer2_dirhash(name, name_len);
249 chain = hammer2_chain_lookup(&parent, &key_next,
250 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
252 HAMMER2_LOOKUP_ALWAYS |
253 HAMMER2_LOOKUP_SHARED);
255 if (hammer2_chain_dirent_test(chain, name, name_len))
257 chain = hammer2_chain_next(&parent, chain, &key_next,
259 lhc + HAMMER2_DIRHASH_LOMASK,
261 HAMMER2_LOOKUP_ALWAYS |
262 HAMMER2_LOOKUP_SHARED);
266 * If the entry is a hardlink pointer, resolve it.
268 if (chain && chain->error == 0) {
269 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
270 lhc = chain->bref.embed.dirent.inum;
271 error = hammer2_chain_inode_find(chain->pmp,
274 HAMMER2_LOOKUP_SHARED,
278 } else if (chain && error == 0) {
279 error = chain->error;
282 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
284 hammer2_chain_unlock(chain);
285 hammer2_chain_drop(chain);
288 hammer2_chain_unlock(parent);
289 hammer2_chain_drop(parent);
294 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
295 * backend for pfs_delete.
297 * This function locates and removes a directory entry, and will lookup
298 * and return the underlying inode. For directory entries the underlying
299 * inode is not removed. If the directory entry is the actual inode itself,
300 * it may be conditonally removed and returned.
302 * WARNING! Any target inode's nlinks may not be synchronized to the
303 * in-memory inode. The frontend's hammer2_inode_unlink_finisher()
304 * is responsible for the final disposition of the actual inode.
307 hammer2_xop_unlink(hammer2_thread_t *thr, hammer2_xop_t *arg)
309 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
310 hammer2_chain_t *parent;
311 hammer2_chain_t *chain;
314 hammer2_key_t key_next;
320 * Requires exclusive lock
322 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
323 HAMMER2_RESOLVE_ALWAYS);
325 if (parent == NULL) {
326 kprintf("xop_nresolve: NULL parent\n");
327 error = HAMMER2_ERROR_EIO;
330 name = xop->head.name1;
331 name_len = xop->head.name1_len;
334 * Lookup the directory entry
336 lhc = hammer2_dirhash(name, name_len);
337 chain = hammer2_chain_lookup(&parent, &key_next,
338 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
339 &error, HAMMER2_LOOKUP_ALWAYS);
341 if (hammer2_chain_dirent_test(chain, name, name_len))
343 chain = hammer2_chain_next(&parent, chain, &key_next,
345 lhc + HAMMER2_DIRHASH_LOMASK,
346 &error, HAMMER2_LOOKUP_ALWAYS);
350 * The directory entry will either be a BREF_TYPE_DIRENT or a
351 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but
352 * must go by xop->dopermanent for BREF_TYPE_INODE.
354 * Note that the target chain's nlinks may not be synchronized with
355 * the in-memory hammer2_inode_t structure, so we don't try to do
356 * anything fancy here. The frontend deals with nlinks
359 if (chain && chain->error == 0) {
360 int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
361 int doforce = xop->dopermanent & H2DOPERM_FORCE;
365 * If the directory entry is the actual inode then use its
366 * type for the directory typing tests, otherwise if it is
367 * a directory entry, pull the type field from the entry.
369 * Directory entries are always permanently deleted
370 * (because they aren't the actual inode).
372 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
373 type = chain->bref.embed.dirent.type;
374 dopermanent |= HAMMER2_DELETE_PERMANENT;
376 type = chain->data->ipdata.meta.type;
380 * Check directory typing and delete the entry. Note that
381 * nlinks adjustments are made on the real inode by the
382 * frontend, not here.
384 * Unfortunately, checkdirempty() may have to unlock (parent).
385 * If it no longer matches chain->parent after re-locking,
386 * EAGAIN is returned.
388 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
390 * If doforce then execute the operation even if
391 * the directory is not empty or errored. We
392 * ignore chain->error here, allowing an errored
393 * chain (aka directory entry) to still be deleted.
395 error = hammer2_chain_delete(parent, chain,
396 xop->head.mtid, dopermanent);
397 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
398 (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
400 * error may be EAGAIN or ENOTEMPTY
402 if (error == HAMMER2_ERROR_EAGAIN) {
403 hammer2_chain_unlock(chain);
404 hammer2_chain_drop(chain);
405 hammer2_chain_unlock(parent);
406 hammer2_chain_drop(parent);
409 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
411 error = HAMMER2_ERROR_ENOTDIR;
412 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
414 error = HAMMER2_ERROR_EISDIR;
417 * Delete the directory entry. chain might also
418 * be a directly-embedded inode.
420 * Allow the deletion to proceed even if the chain
421 * is errored. Give priority to error-on-delete over
424 error = hammer2_chain_delete(parent, chain,
428 error = chain->error;
431 if (chain && error == 0)
432 error = chain->error;
436 * If chain is a directory entry we must resolve it. We do not try
437 * to manipulate the contents as it might not be synchronized with
438 * the frontend hammer2_inode_t, nor do we try to lookup the
439 * frontend hammer2_inode_t here (we are the backend!).
441 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
442 (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
445 lhc = chain->bref.embed.dirent.inum;
447 error2 = hammer2_chain_inode_find(chain->pmp, lhc,
451 kprintf("inode_find: %016jx %p failed\n",
453 error2 = 0; /* silently ignore */
460 * Return the inode target for further action. Typically used by
461 * hammer2_inode_unlink_finisher().
464 hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
466 hammer2_chain_unlock(chain);
467 hammer2_chain_drop(chain);
471 hammer2_chain_unlock(parent);
472 hammer2_chain_drop(parent);
478 * Backend for hammer2_vop_nrename()
480 * This handles the backend rename operation. Typically this renames
481 * directory entries but can also be used to rename embedded inodes.
483 * NOTE! The frontend is responsible for updating the inode meta-data in
484 * the file being renamed and for decrementing the target-replaced
485 * inode's nlinks, if present.
488 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
490 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
492 hammer2_chain_t *parent;
493 hammer2_chain_t *chain;
494 hammer2_chain_t *tmp;
496 hammer2_key_t key_next;
500 * We need the precise parent chain to issue the deletion.
502 * If this is a directory entry we must locate the underlying
503 * inode. If it is an embedded inode we can act directly on it.
510 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
512 * Find ip's direct parent chain.
514 chain = hammer2_inode_chain(ip, thr->clindex,
515 HAMMER2_RESOLVE_ALWAYS);
517 error = HAMMER2_ERROR_EIO;
521 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
522 if (parent == NULL) {
523 error = HAMMER2_ERROR_EIO;
528 * The directory entry for the head.ip1 inode
529 * is in fdip, do a namespace search.
535 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
536 HAMMER2_RESOLVE_ALWAYS);
537 if (parent == NULL) {
538 kprintf("xop_nrename: NULL parent\n");
539 error = HAMMER2_ERROR_EIO;
542 name = xop->head.name1;
543 name_len = xop->head.name1_len;
546 * Lookup the directory entry
548 lhc = hammer2_dirhash(name, name_len);
549 chain = hammer2_chain_lookup(&parent, &key_next,
550 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
551 &error, HAMMER2_LOOKUP_ALWAYS);
553 if (hammer2_chain_dirent_test(chain, name, name_len))
555 chain = hammer2_chain_next(&parent, chain, &key_next,
557 lhc + HAMMER2_DIRHASH_LOMASK,
559 HAMMER2_LOOKUP_ALWAYS);
564 /* XXX shouldn't happen, but does under fsstress */
565 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
569 error = HAMMER2_ERROR_ENOENT;
574 error = chain->error;
579 * Delete it, then create it in the new namespace.
581 * An error can occur if the chain being deleted requires
582 * modification and the media is full.
584 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
585 hammer2_chain_unlock(parent);
586 hammer2_chain_drop(parent);
587 parent = NULL; /* safety */
592 * Adjust fields in the deleted chain appropriate for the rename
595 * NOTE! For embedded inodes, the frontend will officially replicate
596 * the field adjustments, but we also do it here to maintain
597 * consistency in case of a crash.
599 if (chain->bref.key != xop->lhc ||
600 xop->head.name1_len != xop->head.name2_len ||
601 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
602 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
603 hammer2_inode_data_t *wipdata;
605 error = hammer2_chain_modify(chain, xop->head.mtid,
608 wipdata = &chain->data->ipdata;
610 bzero(wipdata->filename,
611 sizeof(wipdata->filename));
612 bcopy(xop->head.name2,
614 xop->head.name2_len);
615 wipdata->meta.name_key = xop->lhc;
616 wipdata->meta.name_len = xop->head.name2_len;
619 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
620 if (xop->head.name2_len <=
621 sizeof(chain->bref.check.buf)) {
623 * Remove any related data buffer, we can
624 * embed the filename in the bref itself.
626 error = hammer2_chain_resize(
627 chain, xop->head.mtid, 0, 0, 0);
629 error = hammer2_chain_modify(
630 chain, xop->head.mtid,
634 bzero(chain->bref.check.buf,
635 sizeof(chain->bref.check.buf));
636 bcopy(xop->head.name2,
637 chain->bref.check.buf,
638 xop->head.name2_len);
642 * Associate a data buffer with the bref.
643 * Zero it for consistency. Note that the
644 * data buffer is not 64KB so use chain->bytes
645 * instead of sizeof().
647 error = hammer2_chain_resize(
648 chain, xop->head.mtid, 0,
649 hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
651 error = hammer2_chain_modify(
652 chain, xop->head.mtid,
656 bzero(chain->data->buf, chain->bytes);
657 bcopy(xop->head.name2,
659 xop->head.name2_len);
663 chain->bref.embed.dirent.namlen =
670 * The frontend will replicate this operation and is the real final
671 * authority, but adjust the inode's iparent field too if the inode
672 * is embedded in the directory.
674 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
675 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
676 hammer2_inode_data_t *wipdata;
678 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
680 wipdata = &chain->data->ipdata;
681 wipdata->meta.iparent = xop->head.ip3->meta.inum;
686 * Destroy any matching target(s) before creating the new entry.
687 * This will result in some ping-ponging of the directory key
688 * iterator but that is ok.
690 parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
691 HAMMER2_RESOLVE_ALWAYS);
692 if (parent == NULL) {
693 error = HAMMER2_ERROR_EIO;
698 * Delete all matching directory entries. That is, get rid of
699 * multiple duplicates if present, as a self-healing mechanism.
702 tmp = hammer2_chain_lookup(&parent, &key_next,
703 xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
704 xop->lhc | HAMMER2_DIRHASH_LOMASK,
706 HAMMER2_LOOKUP_ALWAYS);
709 if (hammer2_chain_dirent_test(tmp, xop->head.name2,
710 xop->head.name2_len)) {
711 e2 = hammer2_chain_delete(parent, tmp,
713 if (error == 0 && e2)
716 tmp = hammer2_chain_next(&parent, tmp, &key_next,
719 HAMMER2_DIRHASH_LOMASK,
721 HAMMER2_LOOKUP_ALWAYS);
726 * A relookup is required before the create to properly
727 * position the parent chain.
729 tmp = hammer2_chain_lookup(&parent, &key_next,
732 KKASSERT(tmp == NULL);
733 error = hammer2_chain_create(&parent, &chain,
734 pmp, HAMMER2_METH_DEFAULT,
736 HAMMER2_BREF_TYPE_INODE,
738 xop->head.mtid, 0, 0);
741 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
743 hammer2_chain_unlock(parent);
744 hammer2_chain_drop(parent);
747 hammer2_chain_unlock(chain);
748 hammer2_chain_drop(chain);
753 * Directory collision resolver scan helper (backend, threaded).
755 * Used by the inode create code to locate an unused lhc.
758 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
760 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
761 hammer2_chain_t *parent;
762 hammer2_chain_t *chain;
763 hammer2_key_t key_next;
766 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
767 HAMMER2_RESOLVE_ALWAYS |
768 HAMMER2_RESOLVE_SHARED);
769 if (parent == NULL) {
770 kprintf("xop_nresolve: NULL parent\n");
772 error = HAMMER2_ERROR_EIO;
777 * Lookup all possibly conflicting directory entries, the feed
778 * inherits the chain's lock so do not unlock it on the iteration.
780 chain = hammer2_chain_lookup(&parent, &key_next,
782 xop->lhc + HAMMER2_DIRHASH_LOMASK,
784 HAMMER2_LOOKUP_ALWAYS |
785 HAMMER2_LOOKUP_SHARED);
787 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
789 hammer2_chain_unlock(chain);
790 hammer2_chain_drop(chain);
791 chain = NULL; /* safety */
794 chain = hammer2_chain_next(&parent, chain, &key_next,
796 xop->lhc + HAMMER2_DIRHASH_LOMASK,
798 HAMMER2_LOOKUP_ALWAYS |
799 HAMMER2_LOOKUP_SHARED);
802 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
804 hammer2_chain_unlock(parent);
805 hammer2_chain_drop(parent);
810 * Generic lookup of a specific key.
812 * Used by the inode hidden directory code to find the hidden directory.
815 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
817 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
818 hammer2_chain_t *parent;
819 hammer2_chain_t *chain;
820 hammer2_key_t key_next;
823 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
824 HAMMER2_RESOLVE_ALWAYS |
825 HAMMER2_RESOLVE_SHARED);
827 if (parent == NULL) {
828 error = HAMMER2_ERROR_EIO;
833 * Lookup all possibly conflicting directory entries, the feed
834 * inherits the chain's lock so do not unlock it on the iteration.
836 chain = hammer2_chain_lookup(&parent, &key_next,
839 HAMMER2_LOOKUP_ALWAYS |
840 HAMMER2_LOOKUP_SHARED);
843 error = chain->error;
845 error = HAMMER2_ERROR_ENOENT;
847 hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
851 hammer2_chain_unlock(chain);
852 hammer2_chain_drop(chain);
855 hammer2_chain_unlock(parent);
856 hammer2_chain_drop(parent);
863 * WARNING! Fed chains must be locked shared so ownership can be transfered
864 * and to prevent frontend/backend stalls that would occur with an
865 * exclusive lock. The shared lock also allows chain->data to be
869 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
871 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
872 hammer2_chain_t *parent;
873 hammer2_chain_t *chain;
874 hammer2_key_t key_next;
878 * Assert required flags.
880 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
881 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
884 * The inode's chain is the iterator. If we cannot acquire it our
885 * contribution ends here.
887 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
889 if (parent == NULL) {
890 kprintf("xop_readdir: NULL parent\n");
895 * Generic scan of exact records. Note that indirect blocks are
896 * automatically recursed and will not be returned.
898 chain = hammer2_chain_lookup(&parent, &key_next,
899 xop->key_beg, xop->key_end,
900 &error, xop->lookup_flags);
902 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
905 chain = hammer2_chain_next(&parent, chain, &key_next,
906 key_next, xop->key_end,
907 &error, xop->lookup_flags);
911 hammer2_chain_unlock(chain);
912 hammer2_chain_drop(chain);
914 hammer2_chain_unlock(parent);
915 hammer2_chain_drop(parent);
917 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);