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.
66 * Returns 0 on success.
68 * Returns HAMMER_ERROR_EAGAIN if caller must re-lookup the entry and
69 * retry. (occurs if we race a ripup on oparent or ochain).
71 * Or returns a permanent HAMMER2_ERROR_* error mask.
73 * The caller must pass in an exclusively locked oparent and ochain. This
74 * function will handle the case where the chain is a directory entry or
75 * the inode itself. The original oparent,ochain will be locked upon return.
77 * This function will unlock the underlying oparent,ochain temporarily when
78 * doing an inode lookup to avoid deadlocks. The caller MUST handle the EAGAIN
79 * result as this means that oparent is no longer the parent of ochain, or
80 * that ochain was destroyed while it was unlocked.
84 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
86 hammer2_chain_t *parent;
87 hammer2_chain_t *chain;
88 hammer2_key_t key_next;
97 * Find the inode, set it up as a locked 'chain'. ochain can be the
98 * inode itself, or it can be a directory entry.
100 if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
101 inum = ochain->bref.embed.dirent.inum;
102 hammer2_chain_unlock(ochain);
103 hammer2_chain_unlock(oparent);
107 error = hammer2_chain_inode_find(ochain->pmp, inum,
111 hammer2_chain_unlock(parent);
112 hammer2_chain_drop(parent);
117 * The directory entry *is* the directory inode
119 chain = hammer2_chain_lookup_init(ochain, 0);
123 * Determine if the directory is empty or not by checking its
124 * visible namespace (the area which contains directory entries).
130 chain = hammer2_chain_lookup(&parent, &key_next,
131 HAMMER2_DIRHASH_VISIBLE,
136 error = HAMMER2_ERROR_ENOTEMPTY;
137 hammer2_chain_unlock(chain);
138 hammer2_chain_drop(chain);
140 hammer2_chain_lookup_done(parent);
144 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
145 hammer2_chain_lock(ochain, HAMMER2_RESOLVE_ALWAYS);
146 if ((ochain->flags & HAMMER2_CHAIN_DELETED) ||
147 (oparent->flags & HAMMER2_CHAIN_DELETED) ||
148 ochain->parent != oparent) {
149 kprintf("hammer2: debug: CHECKDIR inum %jd RETRY\n",
151 error = HAMMER2_ERROR_EAGAIN;
158 * Backend for hammer2_vfs_root()
160 * This is called when a newly mounted PFS has not yet synchronized
161 * to the inode_tid and modify_tid.
164 hammer2_xop_ipcluster(hammer2_thread_t *thr, hammer2_xop_t *arg)
166 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
167 hammer2_chain_t *chain;
170 chain = hammer2_inode_chain(xop->head.ip1, thr->clindex,
171 HAMMER2_RESOLVE_ALWAYS |
172 HAMMER2_RESOLVE_SHARED);
174 error = chain->error;
176 error = HAMMER2_ERROR_EIO;
178 hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
180 hammer2_chain_unlock(chain);
181 hammer2_chain_drop(chain);
186 * Backend for hammer2_vop_readdir()
189 hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg)
191 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
192 hammer2_chain_t *parent;
193 hammer2_chain_t *chain;
194 hammer2_key_t key_next;
199 if (hammer2_debug & 0x0020)
200 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
203 * The inode's chain is the iterator. If we cannot acquire it our
204 * contribution ends here.
206 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
207 HAMMER2_RESOLVE_ALWAYS |
208 HAMMER2_RESOLVE_SHARED);
209 if (parent == NULL) {
210 kprintf("xop_readdir: NULL parent\n");
215 * Directory scan [re]start and loop, the feed inherits the chain's
216 * lock so do not unlock it on the iteration.
218 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
219 &error, HAMMER2_LOOKUP_SHARED);
221 chain = hammer2_chain_lookup(&parent, &key_next,
222 lkey, HAMMER2_KEY_MAX,
223 &error, HAMMER2_LOOKUP_SHARED);
226 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
229 chain = hammer2_chain_next(&parent, chain, &key_next,
230 key_next, HAMMER2_KEY_MAX,
231 &error, HAMMER2_LOOKUP_SHARED);
235 hammer2_chain_unlock(chain);
236 hammer2_chain_drop(chain);
238 hammer2_chain_unlock(parent);
239 hammer2_chain_drop(parent);
241 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
245 * Backend for hammer2_vop_nresolve()
248 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
250 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
251 hammer2_chain_t *parent;
252 hammer2_chain_t *chain;
255 hammer2_key_t key_next;
259 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
260 HAMMER2_RESOLVE_ALWAYS |
261 HAMMER2_RESOLVE_SHARED);
262 if (parent == NULL) {
263 kprintf("xop_nresolve: NULL parent\n");
265 error = HAMMER2_ERROR_EIO;
268 name = xop->head.name1;
269 name_len = xop->head.name1_len;
272 * Lookup the directory entry
274 lhc = hammer2_dirhash(name, name_len);
275 chain = hammer2_chain_lookup(&parent, &key_next,
276 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
278 HAMMER2_LOOKUP_ALWAYS |
279 HAMMER2_LOOKUP_SHARED);
281 if (hammer2_chain_dirent_test(chain, name, name_len))
283 chain = hammer2_chain_next(&parent, chain, &key_next,
285 lhc + HAMMER2_DIRHASH_LOMASK,
287 HAMMER2_LOOKUP_ALWAYS |
288 HAMMER2_LOOKUP_SHARED);
292 * If the entry is a hardlink pointer, resolve it.
294 if (chain && chain->error == 0) {
295 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
296 lhc = chain->bref.embed.dirent.inum;
297 error = hammer2_chain_inode_find(chain->pmp,
300 HAMMER2_LOOKUP_SHARED,
304 } else if (chain && error == 0) {
305 error = chain->error;
308 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
310 hammer2_chain_unlock(chain);
311 hammer2_chain_drop(chain);
314 hammer2_chain_unlock(parent);
315 hammer2_chain_drop(parent);
320 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
321 * backend for pfs_delete.
323 * This function locates and removes a directory entry, and will lookup
324 * and return the underlying inode. For directory entries the underlying
325 * inode is not removed. If the directory entry is the actual inode itself,
326 * it may be conditonally removed and returned.
328 * WARNING! Any target inode's nlinks may not be synchronized to the
329 * in-memory inode. The frontend's hammer2_inode_unlink_finisher()
330 * is responsible for the final disposition of the actual inode.
333 hammer2_xop_unlink(hammer2_thread_t *thr, hammer2_xop_t *arg)
335 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
336 hammer2_chain_t *parent;
337 hammer2_chain_t *chain;
340 hammer2_key_t key_next;
346 * Requires exclusive lock
348 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
349 HAMMER2_RESOLVE_ALWAYS);
351 if (parent == NULL) {
352 kprintf("xop_nresolve: NULL parent\n");
353 error = HAMMER2_ERROR_EIO;
356 name = xop->head.name1;
357 name_len = xop->head.name1_len;
360 * Lookup the directory entry
362 lhc = hammer2_dirhash(name, name_len);
363 chain = hammer2_chain_lookup(&parent, &key_next,
364 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
365 &error, HAMMER2_LOOKUP_ALWAYS);
367 if (hammer2_chain_dirent_test(chain, name, name_len))
369 chain = hammer2_chain_next(&parent, chain, &key_next,
371 lhc + HAMMER2_DIRHASH_LOMASK,
372 &error, HAMMER2_LOOKUP_ALWAYS);
376 * The directory entry will either be a BREF_TYPE_DIRENT or a
377 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but
378 * must go by xop->dopermanent for BREF_TYPE_INODE.
380 * Note that the target chain's nlinks may not be synchronized with
381 * the in-memory hammer2_inode_t structure, so we don't try to do
382 * anything fancy here. The frontend deals with nlinks
385 if (chain && chain->error == 0) {
386 int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
387 int doforce = xop->dopermanent & H2DOPERM_FORCE;
391 * If the directory entry is the actual inode then use its
392 * type for the directory typing tests, otherwise if it is
393 * a directory entry, pull the type field from the entry.
395 * Directory entries are always permanently deleted
396 * (because they aren't the actual inode).
398 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
399 type = chain->bref.embed.dirent.type;
400 dopermanent |= HAMMER2_DELETE_PERMANENT;
402 type = chain->data->ipdata.meta.type;
406 * Check directory typing and delete the entry. Note that
407 * nlinks adjustments are made on the real inode by the
408 * frontend, not here.
410 * Unfortunately, checkdirempty() may have to unlock (parent).
411 * If it no longer matches chain->parent after re-locking,
412 * EAGAIN is returned.
414 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
416 * If doforce then execute the operation even if
417 * the directory is not empty or errored. We
418 * ignore chain->error here, allowing an errored
419 * chain (aka directory entry) to still be deleted.
421 error = hammer2_chain_delete(parent, chain,
422 xop->head.mtid, dopermanent);
423 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
424 (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
426 * error may be EAGAIN or ENOTEMPTY
428 if (error == HAMMER2_ERROR_EAGAIN) {
429 hammer2_chain_unlock(chain);
430 hammer2_chain_drop(chain);
431 hammer2_chain_unlock(parent);
432 hammer2_chain_drop(parent);
435 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
437 error = HAMMER2_ERROR_ENOTDIR;
438 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
440 error = HAMMER2_ERROR_EISDIR;
443 * Delete the directory entry. chain might also
444 * be a directly-embedded inode.
446 * Allow the deletion to proceed even if the chain
447 * is errored. Give priority to error-on-delete over
450 error = hammer2_chain_delete(parent, chain,
454 error = chain->error;
457 if (chain && error == 0)
458 error = chain->error;
462 * If chain is a directory entry we must resolve it. We do not try
463 * to manipulate the contents as it might not be synchronized with
464 * the frontend hammer2_inode_t, nor do we try to lookup the
465 * frontend hammer2_inode_t here (we are the backend!).
467 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
468 (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
471 lhc = chain->bref.embed.dirent.inum;
473 error2 = hammer2_chain_inode_find(chain->pmp, lhc,
477 kprintf("inode_find: %016jx %p failed\n",
479 error2 = 0; /* silently ignore */
486 * Return the inode target for further action. Typically used by
487 * hammer2_inode_unlink_finisher().
490 hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
492 hammer2_chain_unlock(chain);
493 hammer2_chain_drop(chain);
497 hammer2_chain_unlock(parent);
498 hammer2_chain_drop(parent);
504 * Backend for hammer2_vop_nrename()
506 * This handles the backend rename operation. Typically this renames
507 * directory entries but can also be used to rename embedded inodes.
509 * NOTE! The frontend is responsible for updating the inode meta-data in
510 * the file being renamed and for decrementing the target-replaced
511 * inode's nlinks, if present.
514 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
516 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
518 hammer2_chain_t *parent;
519 hammer2_chain_t *chain;
520 hammer2_chain_t *tmp;
522 hammer2_key_t key_next;
526 * We need the precise parent chain to issue the deletion.
528 * If this is a directory entry we must locate the underlying
529 * inode. If it is an embedded inode we can act directly on it.
536 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
538 * Find ip's direct parent chain.
540 chain = hammer2_inode_chain(ip, thr->clindex,
541 HAMMER2_RESOLVE_ALWAYS);
543 error = HAMMER2_ERROR_EIO;
547 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
548 if (parent == NULL) {
549 error = HAMMER2_ERROR_EIO;
554 * The directory entry for the head.ip1 inode
555 * is in fdip, do a namespace search.
561 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
562 HAMMER2_RESOLVE_ALWAYS);
563 if (parent == NULL) {
564 kprintf("xop_nrename: NULL parent\n");
565 error = HAMMER2_ERROR_EIO;
568 name = xop->head.name1;
569 name_len = xop->head.name1_len;
572 * Lookup the directory entry
574 lhc = hammer2_dirhash(name, name_len);
575 chain = hammer2_chain_lookup(&parent, &key_next,
576 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
577 &error, HAMMER2_LOOKUP_ALWAYS);
579 if (hammer2_chain_dirent_test(chain, name, name_len))
581 chain = hammer2_chain_next(&parent, chain, &key_next,
583 lhc + HAMMER2_DIRHASH_LOMASK,
585 HAMMER2_LOOKUP_ALWAYS);
590 /* XXX shouldn't happen, but does under fsstress */
591 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
595 error = HAMMER2_ERROR_ENOENT;
600 error = chain->error;
605 * Delete it, then create it in the new namespace.
607 * An error can occur if the chain being deleted requires
608 * modification and the media is full.
610 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
611 hammer2_chain_unlock(parent);
612 hammer2_chain_drop(parent);
613 parent = NULL; /* safety */
618 * Adjust fields in the deleted chain appropriate for the rename
621 * NOTE! For embedded inodes, the frontend will officially replicate
622 * the field adjustments, but we also do it here to maintain
623 * consistency in case of a crash.
625 if (chain->bref.key != xop->lhc ||
626 xop->head.name1_len != xop->head.name2_len ||
627 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
628 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
629 hammer2_inode_data_t *wipdata;
631 error = hammer2_chain_modify(chain, xop->head.mtid,
634 wipdata = &chain->data->ipdata;
636 bzero(wipdata->filename,
637 sizeof(wipdata->filename));
638 bcopy(xop->head.name2,
640 xop->head.name2_len);
641 wipdata->meta.name_key = xop->lhc;
642 wipdata->meta.name_len = xop->head.name2_len;
645 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
646 if (xop->head.name2_len <=
647 sizeof(chain->bref.check.buf)) {
649 * Remove any related data buffer, we can
650 * embed the filename in the bref itself.
652 error = hammer2_chain_resize(
653 chain, xop->head.mtid, 0, 0, 0);
655 error = hammer2_chain_modify(
656 chain, xop->head.mtid,
660 bzero(chain->bref.check.buf,
661 sizeof(chain->bref.check.buf));
662 bcopy(xop->head.name2,
663 chain->bref.check.buf,
664 xop->head.name2_len);
668 * Associate a data buffer with the bref.
669 * Zero it for consistency. Note that the
670 * data buffer is not 64KB so use chain->bytes
671 * instead of sizeof().
673 error = hammer2_chain_resize(
674 chain, xop->head.mtid, 0,
675 hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
677 error = hammer2_chain_modify(
678 chain, xop->head.mtid,
682 bzero(chain->data->buf, chain->bytes);
683 bcopy(xop->head.name2,
685 xop->head.name2_len);
689 chain->bref.embed.dirent.namlen =
696 * The frontend will replicate this operation and is the real final
697 * authority, but adjust the inode's iparent field too if the inode
698 * is embedded in the directory.
700 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
701 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
702 hammer2_inode_data_t *wipdata;
704 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
706 wipdata = &chain->data->ipdata;
707 wipdata->meta.iparent = xop->head.ip3->meta.inum;
712 * Destroy any matching target(s) before creating the new entry.
713 * This will result in some ping-ponging of the directory key
714 * iterator but that is ok.
716 parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
717 HAMMER2_RESOLVE_ALWAYS);
718 if (parent == NULL) {
719 error = HAMMER2_ERROR_EIO;
724 * Delete all matching directory entries. That is, get rid of
725 * multiple duplicates if present, as a self-healing mechanism.
728 tmp = hammer2_chain_lookup(&parent, &key_next,
729 xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
730 xop->lhc | HAMMER2_DIRHASH_LOMASK,
732 HAMMER2_LOOKUP_ALWAYS);
735 if (hammer2_chain_dirent_test(tmp, xop->head.name2,
736 xop->head.name2_len)) {
737 e2 = hammer2_chain_delete(parent, tmp,
739 if (error == 0 && e2)
742 tmp = hammer2_chain_next(&parent, tmp, &key_next,
745 HAMMER2_DIRHASH_LOMASK,
747 HAMMER2_LOOKUP_ALWAYS);
752 * A relookup is required before the create to properly
753 * position the parent chain.
755 tmp = hammer2_chain_lookup(&parent, &key_next,
758 KKASSERT(tmp == NULL);
759 error = hammer2_chain_create(&parent, &chain,
760 pmp, HAMMER2_METH_DEFAULT,
762 HAMMER2_BREF_TYPE_INODE,
764 xop->head.mtid, 0, 0);
767 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
769 hammer2_chain_unlock(parent);
770 hammer2_chain_drop(parent);
773 hammer2_chain_unlock(chain);
774 hammer2_chain_drop(chain);
779 * Directory collision resolver scan helper (backend, threaded).
781 * Used by the inode create code to locate an unused lhc.
784 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
786 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
787 hammer2_chain_t *parent;
788 hammer2_chain_t *chain;
789 hammer2_key_t key_next;
792 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
793 HAMMER2_RESOLVE_ALWAYS |
794 HAMMER2_RESOLVE_SHARED);
795 if (parent == NULL) {
796 kprintf("xop_nresolve: NULL parent\n");
798 error = HAMMER2_ERROR_EIO;
803 * Lookup all possibly conflicting directory entries, the feed
804 * inherits the chain's lock so do not unlock it on the iteration.
806 chain = hammer2_chain_lookup(&parent, &key_next,
808 xop->lhc + HAMMER2_DIRHASH_LOMASK,
810 HAMMER2_LOOKUP_ALWAYS |
811 HAMMER2_LOOKUP_SHARED);
813 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
815 hammer2_chain_unlock(chain);
816 hammer2_chain_drop(chain);
817 chain = NULL; /* safety */
820 chain = hammer2_chain_next(&parent, chain, &key_next,
822 xop->lhc + HAMMER2_DIRHASH_LOMASK,
824 HAMMER2_LOOKUP_ALWAYS |
825 HAMMER2_LOOKUP_SHARED);
828 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
830 hammer2_chain_unlock(parent);
831 hammer2_chain_drop(parent);
836 * Generic lookup of a specific key.
838 * Used by the inode hidden directory code to find the hidden directory.
841 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
843 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
844 hammer2_chain_t *parent;
845 hammer2_chain_t *chain;
846 hammer2_key_t key_next;
849 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
850 HAMMER2_RESOLVE_ALWAYS |
851 HAMMER2_RESOLVE_SHARED);
853 if (parent == NULL) {
854 error = HAMMER2_ERROR_EIO;
859 * Lookup all possibly conflicting directory entries, the feed
860 * inherits the chain's lock so do not unlock it on the iteration.
862 chain = hammer2_chain_lookup(&parent, &key_next,
865 HAMMER2_LOOKUP_ALWAYS |
866 HAMMER2_LOOKUP_SHARED);
869 error = chain->error;
871 error = HAMMER2_ERROR_ENOENT;
873 hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
877 hammer2_chain_unlock(chain);
878 hammer2_chain_drop(chain);
881 hammer2_chain_unlock(parent);
882 hammer2_chain_drop(parent);
889 * WARNING! Fed chains must be locked shared so ownership can be transfered
890 * and to prevent frontend/backend stalls that would occur with an
891 * exclusive lock. The shared lock also allows chain->data to be
895 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
897 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
898 hammer2_chain_t *parent;
899 hammer2_chain_t *chain;
900 hammer2_key_t key_next;
904 * Assert required flags.
906 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
907 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
910 * The inode's chain is the iterator. If we cannot acquire it our
911 * contribution ends here.
913 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
915 if (parent == NULL) {
916 kprintf("xop_readdir: NULL parent\n");
921 * Generic scan of exact records. Note that indirect blocks are
922 * automatically recursed and will not be returned.
924 chain = hammer2_chain_lookup(&parent, &key_next,
925 xop->key_beg, xop->key_end,
926 &error, xop->lookup_flags);
928 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
931 chain = hammer2_chain_next(&parent, chain, &key_next,
932 key_next, xop->key_end,
933 &error, xop->lookup_flags);
937 hammer2_chain_unlock(chain);
938 hammer2_chain_drop(chain);
940 hammer2_chain_unlock(parent);
941 hammer2_chain_drop(parent);
943 hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);