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
*orig_parent
)
70 hammer2_chain_t
*parent
;
71 hammer2_chain_t
*chain
;
72 hammer2_key_t key_next
;
76 parent
= hammer2_chain_lookup_init(orig_parent
, 0);
77 chain
= hammer2_chain_lookup(&parent
, &key_next
,
78 HAMMER2_DIRHASH_VISIBLE
,
81 error
= chain
? ENOTEMPTY
: 0;
83 hammer2_chain_unlock(chain
);
84 hammer2_chain_drop(chain
);
86 hammer2_chain_lookup_done(parent
);
92 * Backend for hammer2_vfs_root()
94 * This is called when a newly mounted PFS has not yet synchronized
95 * to the inode_tid and modify_tid.
98 hammer2_xop_ipcluster(hammer2_xop_t
*arg
, int clindex
)
100 hammer2_xop_ipcluster_t
*xop
= &arg
->xop_ipcluster
;
101 hammer2_chain_t
*chain
;
104 chain
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
105 HAMMER2_RESOLVE_ALWAYS
|
106 HAMMER2_RESOLVE_SHARED
);
108 error
= chain
->error
;
112 hammer2_xop_feed(&xop
->head
, chain
, clindex
, error
);
114 hammer2_chain_unlock(chain
);
115 hammer2_chain_drop(chain
);
120 * Backend for hammer2_vop_readdir()
123 hammer2_xop_readdir(hammer2_xop_t
*arg
, int clindex
)
125 hammer2_xop_readdir_t
*xop
= &arg
->xop_readdir
;
126 hammer2_chain_t
*parent
;
127 hammer2_chain_t
*chain
;
128 hammer2_key_t key_next
;
130 int cache_index
= -1;
134 if (hammer2_debug
& 0x0020)
135 kprintf("xop_readdir %p lkey=%016jx\n", xop
, lkey
);
138 * The inode's chain is the iterator. If we cannot acquire it our
139 * contribution ends here.
141 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
142 HAMMER2_RESOLVE_ALWAYS
|
143 HAMMER2_RESOLVE_SHARED
);
144 if (parent
== NULL
) {
145 kprintf("xop_readdir: NULL parent\n");
150 * Directory scan [re]start and loop, the feed inherits the chain's
151 * lock so do not unlock it on the iteration.
153 chain
= hammer2_chain_lookup(&parent
, &key_next
, lkey
, lkey
,
154 &cache_index
, HAMMER2_LOOKUP_SHARED
);
156 chain
= hammer2_chain_lookup(&parent
, &key_next
,
157 lkey
, HAMMER2_KEY_MAX
,
159 HAMMER2_LOOKUP_SHARED
);
162 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, 0);
165 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
166 key_next
, HAMMER2_KEY_MAX
,
168 HAMMER2_LOOKUP_SHARED
);
171 hammer2_chain_unlock(chain
);
172 hammer2_chain_drop(chain
);
174 hammer2_chain_unlock(parent
);
175 hammer2_chain_drop(parent
);
177 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
181 * Backend for hammer2_vop_nresolve()
184 hammer2_xop_nresolve(hammer2_xop_t
*arg
, int clindex
)
186 hammer2_xop_nresolve_t
*xop
= &arg
->xop_nresolve
;
187 hammer2_chain_t
*parent
;
188 hammer2_chain_t
*chain
;
189 const hammer2_inode_data_t
*ripdata
;
192 hammer2_key_t key_next
;
194 int cache_index
= -1; /* XXX */
197 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
198 HAMMER2_RESOLVE_ALWAYS
|
199 HAMMER2_RESOLVE_SHARED
);
200 if (parent
== NULL
) {
201 kprintf("xop_nresolve: NULL parent\n");
206 name
= xop
->head
.name1
;
207 name_len
= xop
->head
.name1_len
;
210 * Lookup the directory entry
212 lhc
= hammer2_dirhash(name
, name_len
);
213 chain
= hammer2_chain_lookup(&parent
, &key_next
,
214 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
216 HAMMER2_LOOKUP_ALWAYS
|
217 HAMMER2_LOOKUP_SHARED
);
219 ripdata
= &chain
->data
->ipdata
;
220 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
221 ripdata
->meta
.name_len
== name_len
&&
222 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
225 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
227 lhc
+ HAMMER2_DIRHASH_LOMASK
,
229 HAMMER2_LOOKUP_ALWAYS
|
230 HAMMER2_LOOKUP_SHARED
);
234 * If the entry is a hardlink pointer, resolve it.
238 if (chain
->data
->ipdata
.meta
.type
== HAMMER2_OBJTYPE_HARDLINK
) {
239 error
= hammer2_chain_hardlink_find(
242 HAMMER2_LOOKUP_SHARED
);
246 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, error
);
248 hammer2_chain_unlock(chain
);
249 hammer2_chain_drop(chain
);
252 hammer2_chain_unlock(parent
);
253 hammer2_chain_drop(parent
);
258 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper
259 * for hammer2_vop_nrename().
261 * This function locates and removes the directory entry. If the
262 * entry is a hardlink pointer, this function will also remove the
263 * hardlink target if the target's nlinks is 1.
265 * The frontend is responsible for moving open inodes to the hidden directory
266 * and for decrementing nlinks.
269 hammer2_xop_unlink(hammer2_xop_t
*arg
, int clindex
)
271 hammer2_xop_unlink_t
*xop
= &arg
->xop_unlink
;
272 hammer2_chain_t
*parent
;
273 hammer2_chain_t
*chain
;
274 const hammer2_inode_data_t
*ripdata
;
277 hammer2_key_t key_next
;
279 int cache_index
= -1; /* XXX */
283 * Requires exclusive lock
285 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
286 HAMMER2_RESOLVE_ALWAYS
);
288 if (parent
== NULL
) {
289 kprintf("xop_nresolve: NULL parent\n");
293 name
= xop
->head
.name1
;
294 name_len
= xop
->head
.name1_len
;
297 * Lookup the directory entry
299 lhc
= hammer2_dirhash(name
, name_len
);
300 chain
= hammer2_chain_lookup(&parent
, &key_next
,
301 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
303 HAMMER2_LOOKUP_ALWAYS
);
305 ripdata
= &chain
->data
->ipdata
;
306 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
307 ripdata
->meta
.name_len
== name_len
&&
308 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
311 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
313 lhc
+ HAMMER2_DIRHASH_LOMASK
,
315 HAMMER2_LOOKUP_ALWAYS
);
319 * If the directory entry is a HARDLINK pointer then obtain the
320 * underlying file type for the directory typing tests and delete
321 * the HARDLINK pointer chain permanently. The frontend is left
322 * responsible for handling nlinks on and deleting the actual inode.
324 * If the directory entry is the actual inode then use its type
325 * for the directory typing tests and delete the chain, permanency
326 * depends on whether the inode is open or not.
328 * Check directory typing and delete the entry. Note that
329 * nlinks adjustments are made on the real inode by the frontend,
334 int dopermanent
= xop
->dopermanent
;
337 type
= chain
->data
->ipdata
.meta
.type
;
338 if (type
== HAMMER2_OBJTYPE_HARDLINK
) {
339 type
= chain
->data
->ipdata
.meta
.target_type
;
340 dopermanent
|= HAMMER2_DELETE_PERMANENT
;
343 if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
344 checkdirempty(chain
) != 0) {
346 } else if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
350 if (type
!= HAMMER2_OBJTYPE_DIRECTORY
&&
355 * This deletes the directory entry itself, which is
356 * also the inode when nlinks == 1. Hardlink targets
357 * are handled in the next conditional.
359 error
= chain
->error
;
360 hammer2_chain_delete(parent
, chain
,
361 xop
->head
.mtid
, dopermanent
);
366 * If the entry is a hardlink pointer, resolve it. If this is the
367 * last link, delete it. The frontend has the master copy of nlinks
368 * but we still have to make adjustments here to synchronize with it.
370 * On delete / adjust nlinks if there is no error. But we still need
371 * to resolve the hardlink to feed the inode's real chain back to
374 * XXX we are basically tracking the nlinks count by doing a delta
375 * adjustment instead of having the frontend pass the absolute
376 * value down. We really need to have the frontend pass the
377 * absolute value down (difficult because there might not be
378 * an 'ip'). See also hammer2_xop_nlink().
381 chain
->data
->ipdata
.meta
.type
== HAMMER2_OBJTYPE_HARDLINK
) {
384 error2
= hammer2_chain_hardlink_find(xop
->head
.ip1
,
386 if (chain
&& error
== 0 && error2
== 0 &&
387 (int64_t)chain
->data
->ipdata
.meta
.nlinks
<= 1) {
388 hammer2_chain_delete(parent
, chain
,
391 } else if (chain
&& error
== 0 && error2
== 0) {
392 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
393 --chain
->data
->ipdata
.meta
.nlinks
;
400 * Chains passed to feed are expected to be locked shared.
403 hammer2_chain_lock_downgrade(chain
);
406 * We always return the hardlink target (the real inode) for
410 hammer2_xop_feed(&xop
->head
, chain
, clindex
, error
);
412 hammer2_chain_unlock(chain
);
413 hammer2_chain_drop(chain
);
417 hammer2_chain_unlock(parent
);
418 hammer2_chain_drop(parent
);
425 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
431 * If a hardlink pointer:
432 * The existing hardlink target {fdip,ip} must be moved to another
433 * directory {cdip,ip}
435 * If not a hardlink pointer:
436 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
437 * replace the original namespace {fdip,name} with a hardlink pointer.
440 hammer2_xop_nlink(hammer2_xop_t
*arg
, int clindex
)
442 hammer2_xop_nlink_t
*xop
= &arg
->xop_nlink
;
444 hammer2_inode_data_t
*wipdata
;
445 hammer2_chain_t
*parent
;
446 hammer2_chain_t
*chain
;
447 hammer2_chain_t
*tmp
;
449 hammer2_key_t key_dummy
;
450 int cache_index
= -1;
455 * We need the precise parent chain to issue the deletion.
459 parent
= hammer2_inode_chain(ip
, clindex
, HAMMER2_RESOLVE_ALWAYS
);
461 hammer2_chain_getparent(&parent
, HAMMER2_RESOLVE_ALWAYS
);
462 if (parent
== NULL
) {
467 chain
= hammer2_inode_chain(ip
, clindex
, HAMMER2_RESOLVE_ALWAYS
);
472 KKASSERT(chain
->parent
== parent
);
474 if (chain
->data
->ipdata
.meta
.name_key
& HAMMER2_DIRHASH_VISIBLE
) {
476 * Delete the original chain and hold onto it for the move
479 * Replace the namespace with a hardlink pointer if the
480 * chain being moved is not already a hardlink target.
482 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
486 error
= hammer2_chain_create(&parent
, &tmp
, pmp
,
488 HAMMER2_BREF_TYPE_INODE
,
490 xop
->head
.mtid
, 0, 0);
493 hammer2_chain_modify(tmp
, xop
->head
.mtid
, 0, 0);
494 wipdata
= &tmp
->data
->ipdata
;
495 bzero(wipdata
, sizeof(*wipdata
));
496 wipdata
->meta
.name_key
= chain
->data
->ipdata
.meta
.name_key
;
497 wipdata
->meta
.name_len
= chain
->data
->ipdata
.meta
.name_len
;
498 bcopy(chain
->data
->ipdata
.filename
, wipdata
->filename
,
499 chain
->data
->ipdata
.meta
.name_len
);
500 wipdata
->meta
.target_type
= chain
->data
->ipdata
.meta
.type
;
501 wipdata
->meta
.type
= HAMMER2_OBJTYPE_HARDLINK
;
502 wipdata
->meta
.inum
= ip
->meta
.inum
;
503 wipdata
->meta
.version
= HAMMER2_INODE_VERSION_ONE
;
504 wipdata
->meta
.nlinks
= 1;
505 wipdata
->meta
.op_flags
= HAMMER2_OPFLAG_DIRECTDATA
;
507 hammer2_chain_unlock(tmp
);
508 hammer2_chain_drop(tmp
);
509 } else if (xop
->head
.ip1
!= xop
->head
.ip3
) {
511 * Delete the hardlink target so it can be moved
514 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
518 * Deletion not necessary (just a nlinks update).
523 hammer2_chain_unlock(parent
);
524 hammer2_chain_drop(parent
);
528 * Ok, back to the deleted chain. We must reconnect this chain
529 * as a hardlink target to cdir (ip3).
531 * WARNING! Frontend assumes filename length is 18 bytes.
534 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
535 wipdata
= &chain
->data
->ipdata
;
536 ksnprintf(wipdata
->filename
, sizeof(wipdata
->filename
),
537 "0x%016jx", (intmax_t)ip
->meta
.inum
);
538 wipdata
->meta
.name_len
= strlen(wipdata
->filename
);
539 wipdata
->meta
.name_key
= ip
->meta
.inum
;
542 * We must seek parent properly for the create to reattach
543 * chain. XXX just use chain->parent or
544 * inode_chain_and_parent() ?
546 parent
= hammer2_inode_chain(xop
->head
.ip3
, clindex
,
547 HAMMER2_RESOLVE_ALWAYS
);
548 if (parent
== NULL
) {
552 tmp
= hammer2_chain_lookup(&parent
, &key_dummy
,
553 ip
->meta
.inum
, ip
->meta
.inum
,
556 hammer2_chain_unlock(tmp
);
557 hammer2_chain_drop(tmp
);
561 error
= hammer2_chain_create(&parent
, &chain
, pmp
,
562 wipdata
->meta
.name_key
, 0,
563 HAMMER2_BREF_TYPE_INODE
,
565 xop
->head
.mtid
, 0, 0);
571 * Bump nlinks to synchronize with frontend.
573 if (xop
->nlinks_delta
) {
574 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
575 chain
->data
->ipdata
.meta
.nlinks
+= xop
->nlinks_delta
;
579 * To avoid having to scan the collision space we can simply
580 * reuse the inode's original name_key. But ip->meta.name_key
581 * may have already been updated by the front-end, so use xop->lhc.
583 * (frontend is responsible for fixing up ip->pip).
586 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
588 hammer2_chain_unlock(parent
);
589 hammer2_chain_drop(parent
);
592 hammer2_chain_unlock(chain
);
593 hammer2_chain_drop(chain
);
599 * Backend for hammer2_vop_nrename()
601 * This handles the final step of renaming, either renaming the
602 * actual inode or renaming the hardlink pointer.
605 hammer2_xop_nrename(hammer2_xop_t
*arg
, int clindex
)
607 hammer2_xop_nrename_t
*xop
= &arg
->xop_nrename
;
609 hammer2_chain_t
*parent
;
610 hammer2_chain_t
*chain
;
611 hammer2_chain_t
*tmp
;
613 hammer2_key_t key_dummy
;
614 int cache_index
= -1;
618 * We need the precise parent chain to issue the deletion.
620 * If this is not a hardlink target we can act on the inode,
621 * otherwise we have to locate the hardlink pointer.
627 if (xop
->ip_key
& HAMMER2_DIRHASH_VISIBLE
) {
629 * Find ip's direct parent chain.
631 parent
= hammer2_inode_chain(ip
, clindex
,
632 HAMMER2_RESOLVE_ALWAYS
);
634 hammer2_chain_getparent(&parent
,
635 HAMMER2_RESOLVE_ALWAYS
);
636 if (parent
== NULL
) {
640 chain
= hammer2_inode_chain(ip
, clindex
,
641 HAMMER2_RESOLVE_ALWAYS
);
648 * The hardlink pointer for the head.ip1 hardlink target
649 * is in fdip, do a namespace search.
651 const hammer2_inode_data_t
*ripdata
;
653 hammer2_key_t key_next
;
657 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
658 HAMMER2_RESOLVE_ALWAYS
);
659 if (parent
== NULL
) {
660 kprintf("xop_nrename: NULL parent\n");
664 name
= xop
->head
.name1
;
665 name_len
= xop
->head
.name1_len
;
668 * Lookup the directory entry
670 lhc
= hammer2_dirhash(name
, name_len
);
671 chain
= hammer2_chain_lookup(&parent
, &key_next
,
672 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
674 HAMMER2_LOOKUP_ALWAYS
);
676 ripdata
= &chain
->data
->ipdata
;
677 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
678 ripdata
->meta
.name_len
== name_len
&&
679 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
682 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
684 lhc
+ HAMMER2_DIRHASH_LOMASK
,
686 HAMMER2_LOOKUP_ALWAYS
);
691 /* XXX shouldn't happen, but does under fsstress */
692 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
700 * Delete it, then create it in the new namespace.
702 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
703 hammer2_chain_unlock(parent
);
704 hammer2_chain_drop(parent
);
705 parent
= NULL
; /* safety */
708 * Ok, back to the deleted chain. We must reconnect this chain
709 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
710 * is not otherwise modified.
712 * Frontend is expected to replicate the same inode meta data
715 * NOTE! This chain may not represent the actual inode, it
716 * can be a hardlink pointer.
718 * XXX in-inode parent directory specification?
720 if (chain
->data
->ipdata
.meta
.name_key
!= xop
->lhc
||
721 xop
->head
.name1_len
!= xop
->head
.name2_len
||
722 bcmp(xop
->head
.name1
, xop
->head
.name2
, xop
->head
.name1_len
) != 0) {
723 hammer2_inode_data_t
*wipdata
;
725 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
726 wipdata
= &chain
->data
->ipdata
;
728 bzero(wipdata
->filename
, sizeof(wipdata
->filename
));
729 bcopy(xop
->head
.name2
, wipdata
->filename
, xop
->head
.name2_len
);
730 wipdata
->meta
.name_key
= xop
->lhc
;
731 wipdata
->meta
.name_len
= xop
->head
.name2_len
;
735 * We must seek parent properly for the create.
737 parent
= hammer2_inode_chain(xop
->head
.ip3
, clindex
,
738 HAMMER2_RESOLVE_ALWAYS
);
739 if (parent
== NULL
) {
743 tmp
= hammer2_chain_lookup(&parent
, &key_dummy
,
747 hammer2_chain_unlock(tmp
);
748 hammer2_chain_drop(tmp
);
753 error
= hammer2_chain_create(&parent
, &chain
, pmp
,
755 HAMMER2_BREF_TYPE_INODE
,
757 xop
->head
.mtid
, 0, 0);
759 * (frontend is responsible for fixing up ip->pip).
762 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
764 hammer2_chain_unlock(parent
);
765 hammer2_chain_drop(parent
);
768 hammer2_chain_unlock(chain
);
769 hammer2_chain_drop(chain
);
774 * Directory collision resolver scan helper (backend, threaded).
776 * Used by the inode create code to locate an unused lhc.
779 hammer2_xop_scanlhc(hammer2_xop_t
*arg
, int clindex
)
781 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
782 hammer2_chain_t
*parent
;
783 hammer2_chain_t
*chain
;
784 hammer2_key_t key_next
;
785 int cache_index
= -1; /* XXX */
788 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
789 HAMMER2_RESOLVE_ALWAYS
|
790 HAMMER2_RESOLVE_SHARED
);
791 if (parent
== NULL
) {
792 kprintf("xop_nresolve: NULL parent\n");
799 * Lookup all possibly conflicting directory entries, the feed
800 * inherits the chain's lock so do not unlock it on the iteration.
802 chain
= hammer2_chain_lookup(&parent
, &key_next
,
804 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
806 HAMMER2_LOOKUP_ALWAYS
|
807 HAMMER2_LOOKUP_SHARED
);
809 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
,
812 hammer2_chain_unlock(chain
);
813 hammer2_chain_drop(chain
);
814 chain
= NULL
; /* safety */
817 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
819 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
821 HAMMER2_LOOKUP_ALWAYS
|
822 HAMMER2_LOOKUP_SHARED
);
825 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
827 hammer2_chain_unlock(parent
);
828 hammer2_chain_drop(parent
);
833 * Generic lookup of a specific key.
835 * Used by the inode hidden directory code to find the hidden directory.
838 hammer2_xop_lookup(hammer2_xop_t
*arg
, int clindex
)
840 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
841 hammer2_chain_t
*parent
;
842 hammer2_chain_t
*chain
;
843 hammer2_key_t key_next
;
844 int cache_index
= -1; /* XXX */
847 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
848 HAMMER2_RESOLVE_ALWAYS
|
849 HAMMER2_RESOLVE_SHARED
);
851 if (parent
== NULL
) {
857 * Lookup all possibly conflicting directory entries, the feed
858 * inherits the chain's lock so do not unlock it on the iteration.
860 chain
= hammer2_chain_lookup(&parent
, &key_next
,
863 HAMMER2_LOOKUP_ALWAYS
|
864 HAMMER2_LOOKUP_SHARED
);
866 hammer2_xop_feed(&xop
->head
, chain
, clindex
, chain
->error
);
868 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, ENOENT
);
872 hammer2_chain_unlock(chain
);
873 hammer2_chain_drop(chain
);
876 hammer2_chain_unlock(parent
);
877 hammer2_chain_drop(parent
);
884 * WARNING! Fed chains must be locked shared so ownership can be transfered
885 * and to prevent frontend/backend stalls that would occur with an
886 * exclusive lock. The shared lock also allows chain->data to be
890 hammer2_xop_scanall(hammer2_xop_t
*arg
, int clindex
)
892 hammer2_xop_scanall_t
*xop
= &arg
->xop_scanall
;
893 hammer2_chain_t
*parent
;
894 hammer2_chain_t
*chain
;
895 hammer2_key_t key_next
;
896 int cache_index
= -1;
900 * Assert required flags.
902 KKASSERT(xop
->resolve_flags
& HAMMER2_RESOLVE_SHARED
);
903 KKASSERT(xop
->lookup_flags
& HAMMER2_LOOKUP_SHARED
);
906 * The inode's chain is the iterator. If we cannot acquire it our
907 * contribution ends here.
909 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
911 if (parent
== NULL
) {
912 kprintf("xop_readdir: NULL parent\n");
917 * Generic scan of exact records. Note that indirect blocks are
918 * automatically recursed and will not be returned.
920 chain
= hammer2_chain_lookup(&parent
, &key_next
,
921 xop
->key_beg
, xop
->key_end
,
922 &cache_index
, xop
->lookup_flags
);
924 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, 0);
927 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
928 key_next
, xop
->key_end
,
929 &cache_index
, xop
->lookup_flags
);
932 hammer2_chain_unlock(chain
);
933 hammer2_chain_drop(chain
);
935 hammer2_chain_unlock(parent
);
936 hammer2_chain_drop(parent
);
938 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);