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.
66 * May return 0, ENOTDIR, or EAGAIN.
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 chain
= hammer2_chain_lookup_init(ochain
, 0);
82 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
84 hammer2_chain_unlock(oparent
);
85 inum
= chain
->bref
.embed
.dirent
.inum
;
87 error
= hammer2_chain_inode_find(chain
->pmp
, inum
,
91 hammer2_chain_unlock(parent
);
92 hammer2_chain_drop(parent
);
95 hammer2_chain_lock(oparent
, HAMMER2_RESOLVE_ALWAYS
);
96 if (ochain
->parent
!= oparent
) {
98 hammer2_chain_unlock(chain
);
99 hammer2_chain_drop(chain
);
101 kprintf("H2EAGAIN\n");
109 * Determine if the directory is empty or not by checking its
110 * visible namespace (the area which contains directory entries).
115 chain
= hammer2_chain_lookup(&parent
, &key_next
,
116 HAMMER2_DIRHASH_VISIBLE
,
122 hammer2_chain_unlock(chain
);
123 hammer2_chain_drop(chain
);
127 hammer2_chain_lookup_done(parent
);
133 * Backend for hammer2_vfs_root()
135 * This is called when a newly mounted PFS has not yet synchronized
136 * to the inode_tid and modify_tid.
139 hammer2_xop_ipcluster(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
141 hammer2_xop_ipcluster_t
*xop
= &arg
->xop_ipcluster
;
142 hammer2_chain_t
*chain
;
145 chain
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
146 HAMMER2_RESOLVE_ALWAYS
|
147 HAMMER2_RESOLVE_SHARED
);
149 error
= chain
->error
;
153 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
155 hammer2_chain_unlock(chain
);
156 hammer2_chain_drop(chain
);
161 * Backend for hammer2_vop_readdir()
164 hammer2_xop_readdir(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
166 hammer2_xop_readdir_t
*xop
= &arg
->xop_readdir
;
167 hammer2_chain_t
*parent
;
168 hammer2_chain_t
*chain
;
169 hammer2_key_t key_next
;
171 int cache_index
= -1;
175 if (hammer2_debug
& 0x0020)
176 kprintf("xop_readdir %p lkey=%016jx\n", xop
, lkey
);
179 * The inode's chain is the iterator. If we cannot acquire it our
180 * contribution ends here.
182 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
183 HAMMER2_RESOLVE_ALWAYS
|
184 HAMMER2_RESOLVE_SHARED
);
185 if (parent
== NULL
) {
186 kprintf("xop_readdir: NULL parent\n");
191 * Directory scan [re]start and loop, the feed inherits the chain's
192 * lock so do not unlock it on the iteration.
194 chain
= hammer2_chain_lookup(&parent
, &key_next
, lkey
, lkey
,
195 &cache_index
, HAMMER2_LOOKUP_SHARED
);
197 chain
= hammer2_chain_lookup(&parent
, &key_next
,
198 lkey
, HAMMER2_KEY_MAX
,
200 HAMMER2_LOOKUP_SHARED
);
203 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, 0);
206 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
207 key_next
, HAMMER2_KEY_MAX
,
209 HAMMER2_LOOKUP_SHARED
);
212 hammer2_chain_unlock(chain
);
213 hammer2_chain_drop(chain
);
215 hammer2_chain_unlock(parent
);
216 hammer2_chain_drop(parent
);
218 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
222 * Backend for hammer2_vop_nresolve()
225 hammer2_xop_nresolve(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
227 hammer2_xop_nresolve_t
*xop
= &arg
->xop_nresolve
;
228 hammer2_chain_t
*parent
;
229 hammer2_chain_t
*chain
;
232 hammer2_key_t key_next
;
234 int cache_index
= -1; /* XXX */
237 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
238 HAMMER2_RESOLVE_ALWAYS
|
239 HAMMER2_RESOLVE_SHARED
);
240 if (parent
== NULL
) {
241 kprintf("xop_nresolve: NULL parent\n");
246 name
= xop
->head
.name1
;
247 name_len
= xop
->head
.name1_len
;
250 * Lookup the directory entry
252 lhc
= hammer2_dirhash(name
, name_len
);
253 chain
= hammer2_chain_lookup(&parent
, &key_next
,
254 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
256 HAMMER2_LOOKUP_ALWAYS
|
257 HAMMER2_LOOKUP_SHARED
);
259 if (hammer2_chain_dirent_test(chain
, name
, name_len
))
261 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
263 lhc
+ HAMMER2_DIRHASH_LOMASK
,
265 HAMMER2_LOOKUP_ALWAYS
|
266 HAMMER2_LOOKUP_SHARED
);
270 * If the entry is a hardlink pointer, resolve it.
274 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
275 lhc
= chain
->bref
.embed
.dirent
.inum
;
276 error
= hammer2_chain_inode_find(chain
->pmp
,
279 HAMMER2_LOOKUP_SHARED
,
285 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
287 hammer2_chain_unlock(chain
);
288 hammer2_chain_drop(chain
);
291 hammer2_chain_unlock(parent
);
292 hammer2_chain_drop(parent
);
297 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
298 * backend for pfs_delete.
300 * This function locates and removes a directory entry, and will lookup
301 * and return the underlying inode. For directory entries the underlying
302 * inode is not removed. If the directory entry is the actual inode itself,
303 * it may be conditonally removed and returned.
305 * WARNING! Any target inode's nlinks may not be synchronized to the
306 * in-memory inode. The frontend's hammer2_inode_unlink_finisher()
307 * is responsible for the final disposition of the actual inode.
310 hammer2_xop_unlink(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
312 hammer2_xop_unlink_t
*xop
= &arg
->xop_unlink
;
313 hammer2_chain_t
*parent
;
314 hammer2_chain_t
*chain
;
317 hammer2_key_t key_next
;
319 int cache_index
= -1; /* XXX */
324 * Requires exclusive lock
326 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
327 HAMMER2_RESOLVE_ALWAYS
);
329 if (parent
== NULL
) {
330 kprintf("xop_nresolve: NULL parent\n");
334 name
= xop
->head
.name1
;
335 name_len
= xop
->head
.name1_len
;
338 * Lookup the directory entry
340 lhc
= hammer2_dirhash(name
, name_len
);
341 chain
= hammer2_chain_lookup(&parent
, &key_next
,
342 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
344 HAMMER2_LOOKUP_ALWAYS
);
346 if (hammer2_chain_dirent_test(chain
, name
, name_len
))
348 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
350 lhc
+ HAMMER2_DIRHASH_LOMASK
,
352 HAMMER2_LOOKUP_ALWAYS
);
356 * The directory entry will either be a BREF_TYPE_DIRENT or a
357 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but
358 * must go by xop->dopermanent for BREF_TYPE_INODE.
360 * Note that the target chain's nlinks may not be synchronized with
361 * the in-memory hammer2_inode_t structure, so we don't try to do
362 * anything fancy here. The frontend deals with nlinks
367 int dopermanent
= xop
->dopermanent
& 1;
368 int doforce
= xop
->dopermanent
& 2;
372 * If the directory entry is the actual inode then use its
373 * type for the directory typing tests, otherwise if it is
374 * a directory entry, pull the type field from the entry.
376 * Directory entries are always permanently deleted
377 * (because they aren't the actual inode).
379 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
380 type
= chain
->bref
.embed
.dirent
.type
;
381 dopermanent
|= HAMMER2_DELETE_PERMANENT
;
383 type
= chain
->data
->ipdata
.meta
.type
;
387 * Check directory typing and delete the entry. Note that
388 * nlinks adjustments are made on the real inode by the
389 * frontend, not here.
391 * Unfortunately, checkdirempty() may have to unlock (parent).
392 * If it no longer matches chain->parent after re-locking,
393 * EAGAIN is returned.
395 if (type
== HAMMER2_OBJTYPE_DIRECTORY
&& doforce
) {
397 * If doforce then execute the operation even if
398 * the directory is not empty.
400 error
= chain
->error
;
401 hammer2_chain_delete(parent
, chain
,
402 xop
->head
.mtid
, dopermanent
);
403 } else if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
404 (error
= checkdirempty(parent
, chain
, thr
->clindex
)) != 0) {
406 * error may be EAGAIN or ENOTEMPTY
408 if (error
== EAGAIN
) {
409 hammer2_chain_unlock(chain
);
410 hammer2_chain_drop(chain
);
411 hammer2_chain_unlock(parent
);
412 hammer2_chain_drop(parent
);
415 } else if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
418 } else if (type
!= HAMMER2_OBJTYPE_DIRECTORY
&&
423 * Delete the directory entry. chain might also
424 * be a directly-embedded inode.
426 error
= chain
->error
;
427 hammer2_chain_delete(parent
, chain
,
428 xop
->head
.mtid
, dopermanent
);
433 * If chain is a directory entry we must resolve it. We do not try
434 * to manipulate the contents as it might not be synchronized with
435 * the frontend hammer2_inode_t, nor do we try to lookup the
436 * frontend hammer2_inode_t here (we are the backend!).
438 if (chain
&& chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
441 lhc
= chain
->bref
.embed
.dirent
.inum
;
443 error2
= hammer2_chain_inode_find(chain
->pmp
, lhc
,
447 kprintf("inode_find: %016jx %p failed\n",
449 error2
= 0; /* silently ignore */
456 * Return the inode target for further action. Typically used by
457 * hammer2_inode_unlink_finisher().
460 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
462 hammer2_chain_unlock(chain
);
463 hammer2_chain_drop(chain
);
467 hammer2_chain_unlock(parent
);
468 hammer2_chain_drop(parent
);
474 * Backend for hammer2_vop_nrename()
476 * This handles the backend rename operation. Typically this renames
477 * directory entries but can also be used to rename embedded inodes.
479 * NOTE! The frontend is responsible for updating the inode meta-data in
480 * the file being renamed and for decrementing the target-replaced
481 * inode's nlinks, if present.
484 hammer2_xop_nrename(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
486 hammer2_xop_nrename_t
*xop
= &arg
->xop_nrename
;
488 hammer2_chain_t
*parent
;
489 hammer2_chain_t
*chain
;
490 hammer2_chain_t
*tmp
;
492 hammer2_key_t key_next
;
493 int cache_index
= -1;
497 * We need the precise parent chain to issue the deletion.
499 * If this is a directory entry we must locate the underlying
500 * inode. If it is an embedded inode we can act directly on it.
506 if (xop
->ip_key
& HAMMER2_DIRHASH_VISIBLE
) {
508 * Find ip's direct parent chain.
510 parent
= hammer2_inode_chain(ip
, thr
->clindex
,
511 HAMMER2_RESOLVE_ALWAYS
);
513 hammer2_chain_getparent(&parent
,
514 HAMMER2_RESOLVE_ALWAYS
);
515 if (parent
== NULL
) {
519 chain
= hammer2_inode_chain(ip
, thr
->clindex
,
520 HAMMER2_RESOLVE_ALWAYS
);
527 * The directory entry for the head.ip1 inode
528 * is in fdip, do a namespace search.
534 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
535 HAMMER2_RESOLVE_ALWAYS
);
536 if (parent
== NULL
) {
537 kprintf("xop_nrename: NULL parent\n");
541 name
= xop
->head
.name1
;
542 name_len
= xop
->head
.name1_len
;
545 * Lookup the directory entry
547 lhc
= hammer2_dirhash(name
, name_len
);
548 chain
= hammer2_chain_lookup(&parent
, &key_next
,
549 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
551 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",
573 * Delete it, then create it in the new namespace.
575 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
576 hammer2_chain_unlock(parent
);
577 hammer2_chain_drop(parent
);
578 parent
= NULL
; /* safety */
581 * Adjust fields in the deleted chain appropriate for the rename
584 * NOTE! For embedded inodes, the frontend will officially replicate
585 * the field adjustments, but we also do it here to maintain
586 * consistency in case of a crash.
588 if (chain
->bref
.key
!= xop
->lhc
||
589 xop
->head
.name1_len
!= xop
->head
.name2_len
||
590 bcmp(xop
->head
.name1
, xop
->head
.name2
, xop
->head
.name1_len
) != 0) {
591 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
) {
592 hammer2_inode_data_t
*wipdata
;
594 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
595 wipdata
= &chain
->data
->ipdata
;
597 bzero(wipdata
->filename
, sizeof(wipdata
->filename
));
598 bcopy(xop
->head
.name2
, wipdata
->filename
,
599 xop
->head
.name2_len
);
600 wipdata
->meta
.name_key
= xop
->lhc
;
601 wipdata
->meta
.name_len
= xop
->head
.name2_len
;
603 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
604 if (xop
->head
.name2_len
<= sizeof(chain
->bref
.check
.buf
)) {
605 hammer2_chain_resize(chain
, xop
->head
.mtid
, 0,
607 hammer2_chain_modify(chain
, xop
->head
.mtid
,
609 bzero(chain
->bref
.check
.buf
,
610 sizeof(chain
->bref
.check
.buf
));
611 bcopy(xop
->head
.name2
, chain
->bref
.check
.buf
,
612 xop
->head
.name2_len
);
614 hammer2_chain_resize(chain
, xop
->head
.mtid
, 0,
615 hammer2_getradix(HAMMER2_ALLOC_MIN
), 0);
616 hammer2_chain_modify(chain
, xop
->head
.mtid
,
618 bzero(chain
->data
->buf
,
619 sizeof(chain
->data
->buf
));
620 bcopy(xop
->head
.name2
, chain
->data
->buf
,
621 xop
->head
.name2_len
);
623 chain
->bref
.embed
.dirent
.namlen
= xop
->head
.name2_len
;
628 * The frontend will replicate this operation and is the real final
629 * authority, but adjust the inode's iparent field too if the inode
630 * is embedded in the directory.
632 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
633 chain
->data
->ipdata
.meta
.iparent
!= xop
->head
.ip3
->meta
.inum
) {
634 hammer2_inode_data_t
*wipdata
;
636 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
637 wipdata
= &chain
->data
->ipdata
;
639 wipdata
->meta
.iparent
= xop
->head
.ip3
->meta
.inum
;
643 * Destroy any matching target(s) before creating the new entry.
644 * This will result in some ping-ponging of the directory key
645 * iterator but that is ok.
647 parent
= hammer2_inode_chain(xop
->head
.ip3
, thr
->clindex
,
648 HAMMER2_RESOLVE_ALWAYS
);
649 if (parent
== NULL
) {
654 tmp
= hammer2_chain_lookup(&parent
, &key_next
,
655 xop
->lhc
& ~HAMMER2_DIRHASH_LOMASK
,
656 xop
->lhc
| HAMMER2_DIRHASH_LOMASK
,
658 HAMMER2_LOOKUP_ALWAYS
);
660 if (hammer2_chain_dirent_test(tmp
, xop
->head
.name2
,
661 xop
->head
.name2_len
)) {
662 hammer2_chain_delete(parent
, tmp
, xop
->head
.mtid
, 0);
664 tmp
= hammer2_chain_next(&parent
, tmp
, &key_next
,
666 xop
->lhc
| HAMMER2_DIRHASH_LOMASK
,
668 HAMMER2_LOOKUP_ALWAYS
);
672 * A relookup is required before the create to properly position
675 tmp
= hammer2_chain_lookup(&parent
, &key_next
,
678 KKASSERT(tmp
== NULL
);
679 error
= hammer2_chain_create(&parent
, &chain
,
680 pmp
, HAMMER2_METH_DEFAULT
,
682 HAMMER2_BREF_TYPE_INODE
,
684 xop
->head
.mtid
, 0, 0);
686 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
688 hammer2_chain_unlock(parent
);
689 hammer2_chain_drop(parent
);
692 hammer2_chain_unlock(chain
);
693 hammer2_chain_drop(chain
);
698 * Directory collision resolver scan helper (backend, threaded).
700 * Used by the inode create code to locate an unused lhc.
703 hammer2_xop_scanlhc(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
705 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
706 hammer2_chain_t
*parent
;
707 hammer2_chain_t
*chain
;
708 hammer2_key_t key_next
;
709 int cache_index
= -1; /* XXX */
712 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
713 HAMMER2_RESOLVE_ALWAYS
|
714 HAMMER2_RESOLVE_SHARED
);
715 if (parent
== NULL
) {
716 kprintf("xop_nresolve: NULL parent\n");
723 * Lookup all possibly conflicting directory entries, the feed
724 * inherits the chain's lock so do not unlock it on the iteration.
726 chain
= hammer2_chain_lookup(&parent
, &key_next
,
728 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
730 HAMMER2_LOOKUP_ALWAYS
|
731 HAMMER2_LOOKUP_SHARED
);
733 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
,
736 hammer2_chain_unlock(chain
);
737 hammer2_chain_drop(chain
);
738 chain
= NULL
; /* safety */
741 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
743 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
745 HAMMER2_LOOKUP_ALWAYS
|
746 HAMMER2_LOOKUP_SHARED
);
749 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
751 hammer2_chain_unlock(parent
);
752 hammer2_chain_drop(parent
);
757 * Generic lookup of a specific key.
759 * Used by the inode hidden directory code to find the hidden directory.
762 hammer2_xop_lookup(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
764 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
765 hammer2_chain_t
*parent
;
766 hammer2_chain_t
*chain
;
767 hammer2_key_t key_next
;
768 int cache_index
= -1; /* XXX */
771 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
772 HAMMER2_RESOLVE_ALWAYS
|
773 HAMMER2_RESOLVE_SHARED
);
775 if (parent
== NULL
) {
781 * Lookup all possibly conflicting directory entries, the feed
782 * inherits the chain's lock so do not unlock it on the iteration.
784 chain
= hammer2_chain_lookup(&parent
, &key_next
,
787 HAMMER2_LOOKUP_ALWAYS
|
788 HAMMER2_LOOKUP_SHARED
);
790 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, chain
->error
);
792 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, ENOENT
);
796 hammer2_chain_unlock(chain
);
797 hammer2_chain_drop(chain
);
800 hammer2_chain_unlock(parent
);
801 hammer2_chain_drop(parent
);
808 * WARNING! Fed chains must be locked shared so ownership can be transfered
809 * and to prevent frontend/backend stalls that would occur with an
810 * exclusive lock. The shared lock also allows chain->data to be
814 hammer2_xop_scanall(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
816 hammer2_xop_scanall_t
*xop
= &arg
->xop_scanall
;
817 hammer2_chain_t
*parent
;
818 hammer2_chain_t
*chain
;
819 hammer2_key_t key_next
;
820 int cache_index
= -1;
824 * Assert required flags.
826 KKASSERT(xop
->resolve_flags
& HAMMER2_RESOLVE_SHARED
);
827 KKASSERT(xop
->lookup_flags
& HAMMER2_LOOKUP_SHARED
);
830 * The inode's chain is the iterator. If we cannot acquire it our
831 * contribution ends here.
833 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
835 if (parent
== NULL
) {
836 kprintf("xop_readdir: NULL parent\n");
841 * Generic scan of exact records. Note that indirect blocks are
842 * automatically recursed and will not be returned.
844 chain
= hammer2_chain_lookup(&parent
, &key_next
,
845 xop
->key_beg
, xop
->key_end
,
846 &cache_index
, xop
->lookup_flags
);
848 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, 0);
851 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
852 key_next
, xop
->key_end
,
853 &cache_index
, xop
->lookup_flags
);
856 hammer2_chain_unlock(chain
);
857 hammer2_chain_drop(chain
);
859 hammer2_chain_unlock(parent
);
860 hammer2_chain_drop(parent
);
862 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);