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
,
499 pmp
, HAMMER2_METH_DEFAULT
,
501 HAMMER2_BREF_TYPE_INODE
,
503 xop
->head
.mtid
, 0, 0);
506 hammer2_chain_modify(tmp
, xop
->head
.mtid
, 0, 0);
507 wipdata
= &tmp
->data
->ipdata
;
508 bzero(wipdata
, sizeof(*wipdata
));
509 wipdata
->meta
.name_key
= chain
->data
->ipdata
.meta
.name_key
;
510 wipdata
->meta
.name_len
= chain
->data
->ipdata
.meta
.name_len
;
511 bcopy(chain
->data
->ipdata
.filename
, wipdata
->filename
,
512 chain
->data
->ipdata
.meta
.name_len
);
513 wipdata
->meta
.target_type
= chain
->data
->ipdata
.meta
.type
;
514 wipdata
->meta
.type
= HAMMER2_OBJTYPE_HARDLINK
;
515 wipdata
->meta
.inum
= ip
->meta
.inum
;
516 wipdata
->meta
.version
= HAMMER2_INODE_VERSION_ONE
;
517 wipdata
->meta
.nlinks
= 1;
518 wipdata
->meta
.op_flags
= HAMMER2_OPFLAG_DIRECTDATA
;
520 hammer2_chain_unlock(tmp
);
521 hammer2_chain_drop(tmp
);
522 } else if (xop
->head
.ip1
!= xop
->head
.ip3
) {
524 * Delete the hardlink target so it can be moved
527 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
531 * Deletion not necessary (just a nlinks update).
536 hammer2_chain_unlock(parent
);
537 hammer2_chain_drop(parent
);
541 * Ok, back to the deleted chain. We must reconnect this chain
542 * as a hardlink target to cdir (ip3).
544 * WARNING! Frontend assumes filename length is 18 bytes.
547 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
548 wipdata
= &chain
->data
->ipdata
;
549 ksnprintf(wipdata
->filename
, sizeof(wipdata
->filename
),
550 "0x%016jx", (intmax_t)ip
->meta
.inum
);
551 wipdata
->meta
.name_len
= strlen(wipdata
->filename
);
552 wipdata
->meta
.name_key
= ip
->meta
.inum
;
555 * We must seek parent properly for the create to reattach
556 * chain. XXX just use chain->parent or
557 * inode_chain_and_parent() ?
559 parent
= hammer2_inode_chain(xop
->head
.ip3
, clindex
,
560 HAMMER2_RESOLVE_ALWAYS
);
561 if (parent
== NULL
) {
565 tmp
= hammer2_chain_lookup(&parent
, &key_dummy
,
566 ip
->meta
.inum
, ip
->meta
.inum
,
569 hammer2_chain_unlock(tmp
);
570 hammer2_chain_drop(tmp
);
574 error
= hammer2_chain_create(&parent
, &chain
,
575 pmp
, HAMMER2_METH_DEFAULT
,
576 wipdata
->meta
.name_key
, 0,
577 HAMMER2_BREF_TYPE_INODE
,
579 xop
->head
.mtid
, 0, 0);
585 * Bump nlinks to synchronize with frontend.
587 if (xop
->nlinks_delta
) {
588 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
589 chain
->data
->ipdata
.meta
.nlinks
+= xop
->nlinks_delta
;
593 * To avoid having to scan the collision space we can simply
594 * reuse the inode's original name_key. But ip->meta.name_key
595 * may have already been updated by the front-end, so use xop->lhc.
598 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
600 hammer2_chain_unlock(parent
);
601 hammer2_chain_drop(parent
);
604 hammer2_chain_unlock(chain
);
605 hammer2_chain_drop(chain
);
611 * Backend for hammer2_vop_nrename()
613 * This handles the final step of renaming, either renaming the
614 * actual inode or renaming the hardlink pointer.
617 hammer2_xop_nrename(hammer2_xop_t
*arg
, int clindex
)
619 hammer2_xop_nrename_t
*xop
= &arg
->xop_nrename
;
621 hammer2_chain_t
*parent
;
622 hammer2_chain_t
*chain
;
623 hammer2_chain_t
*tmp
;
625 hammer2_key_t key_dummy
;
626 int cache_index
= -1;
630 * We need the precise parent chain to issue the deletion.
632 * If this is not a hardlink target we can act on the inode,
633 * otherwise we have to locate the hardlink pointer.
639 if (xop
->ip_key
& HAMMER2_DIRHASH_VISIBLE
) {
641 * Find ip's direct parent chain.
643 parent
= hammer2_inode_chain(ip
, clindex
,
644 HAMMER2_RESOLVE_ALWAYS
);
646 hammer2_chain_getparent(&parent
,
647 HAMMER2_RESOLVE_ALWAYS
);
648 if (parent
== NULL
) {
652 chain
= hammer2_inode_chain(ip
, clindex
,
653 HAMMER2_RESOLVE_ALWAYS
);
660 * The hardlink pointer for the head.ip1 hardlink target
661 * is in fdip, do a namespace search.
663 const hammer2_inode_data_t
*ripdata
;
665 hammer2_key_t key_next
;
669 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
670 HAMMER2_RESOLVE_ALWAYS
);
671 if (parent
== NULL
) {
672 kprintf("xop_nrename: NULL parent\n");
676 name
= xop
->head
.name1
;
677 name_len
= xop
->head
.name1_len
;
680 * Lookup the directory entry
682 lhc
= hammer2_dirhash(name
, name_len
);
683 chain
= hammer2_chain_lookup(&parent
, &key_next
,
684 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
686 HAMMER2_LOOKUP_ALWAYS
);
688 ripdata
= &chain
->data
->ipdata
;
689 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
690 ripdata
->meta
.name_len
== name_len
&&
691 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
694 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
696 lhc
+ HAMMER2_DIRHASH_LOMASK
,
698 HAMMER2_LOOKUP_ALWAYS
);
703 /* XXX shouldn't happen, but does under fsstress */
704 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
712 * Delete it, then create it in the new namespace.
714 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
715 hammer2_chain_unlock(parent
);
716 hammer2_chain_drop(parent
);
717 parent
= NULL
; /* safety */
720 * Ok, back to the deleted chain. We must reconnect this chain
721 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
722 * is not otherwise modified.
724 * Frontend is expected to replicate the same inode meta data
727 * NOTE! This chain may not represent the actual inode, it
728 * can be a hardlink pointer.
730 * XXX in-inode parent directory specification?
732 if (chain
->data
->ipdata
.meta
.name_key
!= xop
->lhc
||
733 xop
->head
.name1_len
!= xop
->head
.name2_len
||
734 bcmp(xop
->head
.name1
, xop
->head
.name2
, xop
->head
.name1_len
) != 0) {
735 hammer2_inode_data_t
*wipdata
;
737 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
738 wipdata
= &chain
->data
->ipdata
;
740 bzero(wipdata
->filename
, sizeof(wipdata
->filename
));
741 bcopy(xop
->head
.name2
, wipdata
->filename
, xop
->head
.name2_len
);
742 wipdata
->meta
.name_key
= xop
->lhc
;
743 wipdata
->meta
.name_len
= xop
->head
.name2_len
;
745 if (chain
->data
->ipdata
.meta
.iparent
!= xop
->head
.ip3
->meta
.inum
) {
746 hammer2_inode_data_t
*wipdata
;
748 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
749 wipdata
= &chain
->data
->ipdata
;
751 wipdata
->meta
.iparent
= xop
->head
.ip3
->meta
.inum
;
755 * We must seek parent properly for the create.
757 parent
= hammer2_inode_chain(xop
->head
.ip3
, clindex
,
758 HAMMER2_RESOLVE_ALWAYS
);
759 if (parent
== NULL
) {
763 tmp
= hammer2_chain_lookup(&parent
, &key_dummy
,
767 hammer2_chain_unlock(tmp
);
768 hammer2_chain_drop(tmp
);
773 error
= hammer2_chain_create(&parent
, &chain
,
774 pmp
, HAMMER2_METH_DEFAULT
,
776 HAMMER2_BREF_TYPE_INODE
,
778 xop
->head
.mtid
, 0, 0);
780 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
782 hammer2_chain_unlock(parent
);
783 hammer2_chain_drop(parent
);
786 hammer2_chain_unlock(chain
);
787 hammer2_chain_drop(chain
);
792 * Directory collision resolver scan helper (backend, threaded).
794 * Used by the inode create code to locate an unused lhc.
797 hammer2_xop_scanlhc(hammer2_xop_t
*arg
, int clindex
)
799 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
800 hammer2_chain_t
*parent
;
801 hammer2_chain_t
*chain
;
802 hammer2_key_t key_next
;
803 int cache_index
= -1; /* XXX */
806 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
807 HAMMER2_RESOLVE_ALWAYS
|
808 HAMMER2_RESOLVE_SHARED
);
809 if (parent
== NULL
) {
810 kprintf("xop_nresolve: NULL parent\n");
817 * Lookup all possibly conflicting directory entries, the feed
818 * inherits the chain's lock so do not unlock it on the iteration.
820 chain
= hammer2_chain_lookup(&parent
, &key_next
,
822 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
824 HAMMER2_LOOKUP_ALWAYS
|
825 HAMMER2_LOOKUP_SHARED
);
827 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
,
830 hammer2_chain_unlock(chain
);
831 hammer2_chain_drop(chain
);
832 chain
= NULL
; /* safety */
835 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
837 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
839 HAMMER2_LOOKUP_ALWAYS
|
840 HAMMER2_LOOKUP_SHARED
);
843 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
845 hammer2_chain_unlock(parent
);
846 hammer2_chain_drop(parent
);
851 * Generic lookup of a specific key.
853 * Used by the inode hidden directory code to find the hidden directory.
856 hammer2_xop_lookup(hammer2_xop_t
*arg
, int clindex
)
858 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
859 hammer2_chain_t
*parent
;
860 hammer2_chain_t
*chain
;
861 hammer2_key_t key_next
;
862 int cache_index
= -1; /* XXX */
865 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
866 HAMMER2_RESOLVE_ALWAYS
|
867 HAMMER2_RESOLVE_SHARED
);
869 if (parent
== NULL
) {
875 * Lookup all possibly conflicting directory entries, the feed
876 * inherits the chain's lock so do not unlock it on the iteration.
878 chain
= hammer2_chain_lookup(&parent
, &key_next
,
881 HAMMER2_LOOKUP_ALWAYS
|
882 HAMMER2_LOOKUP_SHARED
);
884 hammer2_xop_feed(&xop
->head
, chain
, clindex
, chain
->error
);
886 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, ENOENT
);
890 hammer2_chain_unlock(chain
);
891 hammer2_chain_drop(chain
);
894 hammer2_chain_unlock(parent
);
895 hammer2_chain_drop(parent
);
902 * WARNING! Fed chains must be locked shared so ownership can be transfered
903 * and to prevent frontend/backend stalls that would occur with an
904 * exclusive lock. The shared lock also allows chain->data to be
908 hammer2_xop_scanall(hammer2_xop_t
*arg
, int clindex
)
910 hammer2_xop_scanall_t
*xop
= &arg
->xop_scanall
;
911 hammer2_chain_t
*parent
;
912 hammer2_chain_t
*chain
;
913 hammer2_key_t key_next
;
914 int cache_index
= -1;
918 * Assert required flags.
920 KKASSERT(xop
->resolve_flags
& HAMMER2_RESOLVE_SHARED
);
921 KKASSERT(xop
->lookup_flags
& HAMMER2_LOOKUP_SHARED
);
924 * The inode's chain is the iterator. If we cannot acquire it our
925 * contribution ends here.
927 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
929 if (parent
== NULL
) {
930 kprintf("xop_readdir: NULL parent\n");
935 * Generic scan of exact records. Note that indirect blocks are
936 * automatically recursed and will not be returned.
938 chain
= hammer2_chain_lookup(&parent
, &key_next
,
939 xop
->key_beg
, xop
->key_end
,
940 &cache_index
, xop
->lookup_flags
);
942 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, 0);
945 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
946 key_next
, xop
->key_end
,
947 &cache_index
, xop
->lookup_flags
);
950 hammer2_chain_unlock(chain
);
951 hammer2_chain_drop(chain
);
953 hammer2_chain_unlock(parent
);
954 hammer2_chain_drop(parent
);
956 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);