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
*oparent
, hammer2_chain_t
*ochain
, int clindex
)
70 hammer2_chain_t
*parent
;
71 hammer2_chain_t
*chain
;
72 hammer2_key_t key_next
;
77 chain
= hammer2_chain_lookup_init(ochain
, 0);
79 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
81 hammer2_chain_unlock(oparent
);
82 inum
= chain
->bref
.embed
.dirent
.inum
;
84 error
= hammer2_chain_inode_find(chain
->pmp
, inum
,
88 hammer2_chain_unlock(parent
);
89 hammer2_chain_drop(parent
);
92 hammer2_chain_lock(oparent
, HAMMER2_RESOLVE_ALWAYS
);
93 if (ochain
->parent
!= oparent
) {
95 hammer2_chain_unlock(chain
);
96 hammer2_chain_drop(chain
);
98 return HAMMER2_ERROR_EAGAIN
;
104 * Determine if the directory is empty or not by checking its
105 * visible namespace (the area which contains directory entries).
110 chain
= hammer2_chain_lookup(&parent
, &key_next
,
111 HAMMER2_DIRHASH_VISIBLE
,
116 error
= HAMMER2_ERROR_ENOTEMPTY
;
117 hammer2_chain_unlock(chain
);
118 hammer2_chain_drop(chain
);
120 hammer2_chain_lookup_done(parent
);
126 * Backend for hammer2_vfs_root()
128 * This is called when a newly mounted PFS has not yet synchronized
129 * to the inode_tid and modify_tid.
132 hammer2_xop_ipcluster(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
134 hammer2_xop_ipcluster_t
*xop
= &arg
->xop_ipcluster
;
135 hammer2_chain_t
*chain
;
138 chain
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
139 HAMMER2_RESOLVE_ALWAYS
|
140 HAMMER2_RESOLVE_SHARED
);
142 error
= chain
->error
;
144 error
= HAMMER2_ERROR_EIO
;
146 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
148 hammer2_chain_unlock(chain
);
149 hammer2_chain_drop(chain
);
154 * Backend for hammer2_vop_readdir()
157 hammer2_xop_readdir(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
159 hammer2_xop_readdir_t
*xop
= &arg
->xop_readdir
;
160 hammer2_chain_t
*parent
;
161 hammer2_chain_t
*chain
;
162 hammer2_key_t key_next
;
167 if (hammer2_debug
& 0x0020)
168 kprintf("xop_readdir %p lkey=%016jx\n", xop
, lkey
);
171 * The inode's chain is the iterator. If we cannot acquire it our
172 * contribution ends here.
174 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
175 HAMMER2_RESOLVE_ALWAYS
|
176 HAMMER2_RESOLVE_SHARED
);
177 if (parent
== NULL
) {
178 kprintf("xop_readdir: NULL parent\n");
183 * Directory scan [re]start and loop, the feed inherits the chain's
184 * lock so do not unlock it on the iteration.
186 chain
= hammer2_chain_lookup(&parent
, &key_next
, lkey
, lkey
,
187 &error
, HAMMER2_LOOKUP_SHARED
);
189 chain
= hammer2_chain_lookup(&parent
, &key_next
,
190 lkey
, HAMMER2_KEY_MAX
,
191 &error
, HAMMER2_LOOKUP_SHARED
);
194 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, 0);
197 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
198 key_next
, HAMMER2_KEY_MAX
,
199 &error
, HAMMER2_LOOKUP_SHARED
);
203 hammer2_chain_unlock(chain
);
204 hammer2_chain_drop(chain
);
206 hammer2_chain_unlock(parent
);
207 hammer2_chain_drop(parent
);
209 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
213 * Backend for hammer2_vop_nresolve()
216 hammer2_xop_nresolve(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
218 hammer2_xop_nresolve_t
*xop
= &arg
->xop_nresolve
;
219 hammer2_chain_t
*parent
;
220 hammer2_chain_t
*chain
;
223 hammer2_key_t key_next
;
227 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
228 HAMMER2_RESOLVE_ALWAYS
|
229 HAMMER2_RESOLVE_SHARED
);
230 if (parent
== NULL
) {
231 kprintf("xop_nresolve: NULL parent\n");
233 error
= HAMMER2_ERROR_EIO
;
236 name
= xop
->head
.name1
;
237 name_len
= xop
->head
.name1_len
;
240 * Lookup the directory entry
242 lhc
= hammer2_dirhash(name
, name_len
);
243 chain
= hammer2_chain_lookup(&parent
, &key_next
,
244 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
246 HAMMER2_LOOKUP_ALWAYS
|
247 HAMMER2_LOOKUP_SHARED
);
249 if (hammer2_chain_dirent_test(chain
, name
, name_len
))
251 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
253 lhc
+ HAMMER2_DIRHASH_LOMASK
,
255 HAMMER2_LOOKUP_ALWAYS
|
256 HAMMER2_LOOKUP_SHARED
);
260 * If the entry is a hardlink pointer, resolve it.
262 if (chain
&& chain
->error
== 0) {
263 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
264 lhc
= chain
->bref
.embed
.dirent
.inum
;
265 error
= hammer2_chain_inode_find(chain
->pmp
,
268 HAMMER2_LOOKUP_SHARED
,
272 } else if (chain
&& error
== 0) {
273 error
= chain
->error
;
276 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
278 hammer2_chain_unlock(chain
);
279 hammer2_chain_drop(chain
);
282 hammer2_chain_unlock(parent
);
283 hammer2_chain_drop(parent
);
288 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
289 * backend for pfs_delete.
291 * This function locates and removes a directory entry, and will lookup
292 * and return the underlying inode. For directory entries the underlying
293 * inode is not removed. If the directory entry is the actual inode itself,
294 * it may be conditonally removed and returned.
296 * WARNING! Any target inode's nlinks may not be synchronized to the
297 * in-memory inode. The frontend's hammer2_inode_unlink_finisher()
298 * is responsible for the final disposition of the actual inode.
301 hammer2_xop_unlink(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
303 hammer2_xop_unlink_t
*xop
= &arg
->xop_unlink
;
304 hammer2_chain_t
*parent
;
305 hammer2_chain_t
*chain
;
308 hammer2_key_t key_next
;
314 * Requires exclusive lock
316 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
317 HAMMER2_RESOLVE_ALWAYS
);
319 if (parent
== NULL
) {
320 kprintf("xop_nresolve: NULL parent\n");
321 error
= HAMMER2_ERROR_EIO
;
324 name
= xop
->head
.name1
;
325 name_len
= xop
->head
.name1_len
;
328 * Lookup the directory entry
330 lhc
= hammer2_dirhash(name
, name_len
);
331 chain
= hammer2_chain_lookup(&parent
, &key_next
,
332 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
333 &error
, HAMMER2_LOOKUP_ALWAYS
);
335 if (hammer2_chain_dirent_test(chain
, name
, name_len
))
337 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
339 lhc
+ HAMMER2_DIRHASH_LOMASK
,
340 &error
, HAMMER2_LOOKUP_ALWAYS
);
344 * The directory entry will either be a BREF_TYPE_DIRENT or a
345 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but
346 * must go by xop->dopermanent for BREF_TYPE_INODE.
348 * Note that the target chain's nlinks may not be synchronized with
349 * the in-memory hammer2_inode_t structure, so we don't try to do
350 * anything fancy here. The frontend deals with nlinks
353 if (chain
&& chain
->error
== 0) {
354 int dopermanent
= xop
->dopermanent
& 1;
355 int doforce
= xop
->dopermanent
& 2;
359 * If the directory entry is the actual inode then use its
360 * type for the directory typing tests, otherwise if it is
361 * a directory entry, pull the type field from the entry.
363 * Directory entries are always permanently deleted
364 * (because they aren't the actual inode).
366 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
367 type
= chain
->bref
.embed
.dirent
.type
;
368 dopermanent
|= HAMMER2_DELETE_PERMANENT
;
370 type
= chain
->data
->ipdata
.meta
.type
;
374 * Check directory typing and delete the entry. Note that
375 * nlinks adjustments are made on the real inode by the
376 * frontend, not here.
378 * Unfortunately, checkdirempty() may have to unlock (parent).
379 * If it no longer matches chain->parent after re-locking,
380 * EAGAIN is returned.
382 if (type
== HAMMER2_OBJTYPE_DIRECTORY
&& doforce
) {
384 * If doforce then execute the operation even if
385 * the directory is not empty or errored.
387 /* ignore chain->error */
388 error
= hammer2_chain_delete(parent
, chain
,
389 xop
->head
.mtid
, dopermanent
);
390 } else if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
391 (error
= checkdirempty(parent
, chain
, thr
->clindex
)) != 0) {
393 * error may be EAGAIN or ENOTEMPTY
395 if (error
== HAMMER2_ERROR_EAGAIN
) {
396 hammer2_chain_unlock(chain
);
397 hammer2_chain_drop(chain
);
398 hammer2_chain_unlock(parent
);
399 hammer2_chain_drop(parent
);
402 } else if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
404 error
= HAMMER2_ERROR_ENOTDIR
;
405 } else if (type
!= HAMMER2_OBJTYPE_DIRECTORY
&&
407 error
= HAMMER2_ERROR_EISDIR
;
410 * Delete the directory entry. chain might also
411 * be a directly-embedded inode.
413 error
= chain
->error
;
414 hammer2_chain_delete(parent
, chain
,
415 xop
->head
.mtid
, dopermanent
);
418 if (chain
&& error
== 0)
419 error
= chain
->error
;
423 * If chain is a directory entry we must resolve it. We do not try
424 * to manipulate the contents as it might not be synchronized with
425 * the frontend hammer2_inode_t, nor do we try to lookup the
426 * frontend hammer2_inode_t here (we are the backend!).
428 if (chain
&& chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
431 lhc
= chain
->bref
.embed
.dirent
.inum
;
433 error2
= hammer2_chain_inode_find(chain
->pmp
, lhc
,
437 kprintf("inode_find: %016jx %p failed\n",
439 error2
= 0; /* silently ignore */
446 * Return the inode target for further action. Typically used by
447 * hammer2_inode_unlink_finisher().
450 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
452 hammer2_chain_unlock(chain
);
453 hammer2_chain_drop(chain
);
457 hammer2_chain_unlock(parent
);
458 hammer2_chain_drop(parent
);
464 * Backend for hammer2_vop_nrename()
466 * This handles the backend rename operation. Typically this renames
467 * directory entries but can also be used to rename embedded inodes.
469 * NOTE! The frontend is responsible for updating the inode meta-data in
470 * the file being renamed and for decrementing the target-replaced
471 * inode's nlinks, if present.
474 hammer2_xop_nrename(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
476 hammer2_xop_nrename_t
*xop
= &arg
->xop_nrename
;
478 hammer2_chain_t
*parent
;
479 hammer2_chain_t
*chain
;
480 hammer2_chain_t
*tmp
;
482 hammer2_key_t key_next
;
486 * We need the precise parent chain to issue the deletion.
488 * If this is a directory entry we must locate the underlying
489 * inode. If it is an embedded inode we can act directly on it.
496 if (xop
->ip_key
& HAMMER2_DIRHASH_VISIBLE
) {
498 * Find ip's direct parent chain.
500 chain
= hammer2_inode_chain(ip
, thr
->clindex
,
501 HAMMER2_RESOLVE_ALWAYS
);
503 error
= HAMMER2_ERROR_EIO
;
507 parent
= hammer2_chain_getparent(chain
, HAMMER2_RESOLVE_ALWAYS
);
508 if (parent
== NULL
) {
509 error
= HAMMER2_ERROR_EIO
;
514 * The directory entry for the head.ip1 inode
515 * is in fdip, do a namespace search.
521 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
522 HAMMER2_RESOLVE_ALWAYS
);
523 if (parent
== NULL
) {
524 kprintf("xop_nrename: NULL parent\n");
525 error
= HAMMER2_ERROR_EIO
;
528 name
= xop
->head
.name1
;
529 name_len
= xop
->head
.name1_len
;
532 * Lookup the directory entry
534 lhc
= hammer2_dirhash(name
, name_len
);
535 chain
= hammer2_chain_lookup(&parent
, &key_next
,
536 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
537 &error
, HAMMER2_LOOKUP_ALWAYS
);
539 if (hammer2_chain_dirent_test(chain
, name
, name_len
))
541 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
543 lhc
+ HAMMER2_DIRHASH_LOMASK
,
545 HAMMER2_LOOKUP_ALWAYS
);
550 /* XXX shouldn't happen, but does under fsstress */
551 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
555 error
= HAMMER2_ERROR_ENOENT
;
560 error
= chain
->error
;
565 * Delete it, then create it in the new namespace.
567 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
568 hammer2_chain_unlock(parent
);
569 hammer2_chain_drop(parent
);
570 parent
= NULL
; /* safety */
573 * Adjust fields in the deleted chain appropriate for the rename
576 * NOTE! For embedded inodes, the frontend will officially replicate
577 * the field adjustments, but we also do it here to maintain
578 * consistency in case of a crash.
580 if (chain
->bref
.key
!= xop
->lhc
||
581 xop
->head
.name1_len
!= xop
->head
.name2_len
||
582 bcmp(xop
->head
.name1
, xop
->head
.name2
, xop
->head
.name1_len
) != 0) {
583 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
) {
584 hammer2_inode_data_t
*wipdata
;
586 error
= hammer2_chain_modify(chain
, xop
->head
.mtid
,
589 wipdata
= &chain
->data
->ipdata
;
591 bzero(wipdata
->filename
,
592 sizeof(wipdata
->filename
));
593 bcopy(xop
->head
.name2
,
595 xop
->head
.name2_len
);
596 wipdata
->meta
.name_key
= xop
->lhc
;
597 wipdata
->meta
.name_len
= xop
->head
.name2_len
;
600 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_DIRENT
) {
601 if (xop
->head
.name2_len
<=
602 sizeof(chain
->bref
.check
.buf
)) {
604 * Remove any related data buffer, we can
605 * embed the filename in the bref itself.
607 error
= hammer2_chain_resize(
608 chain
, xop
->head
.mtid
, 0, 0, 0);
610 error
= hammer2_chain_modify(
611 chain
, xop
->head
.mtid
,
615 bzero(chain
->bref
.check
.buf
,
616 sizeof(chain
->bref
.check
.buf
));
617 bcopy(xop
->head
.name2
,
618 chain
->bref
.check
.buf
,
619 xop
->head
.name2_len
);
623 * Associate a data buffer with the bref.
624 * Zero it for consistency. Note that the
625 * data buffer is not 64KB so use chain->bytes
626 * instead of sizeof().
628 error
= hammer2_chain_resize(
629 chain
, xop
->head
.mtid
, 0,
630 hammer2_getradix(HAMMER2_ALLOC_MIN
), 0);
632 error
= hammer2_chain_modify(
633 chain
, xop
->head
.mtid
,
637 bzero(chain
->data
->buf
, chain
->bytes
);
638 bcopy(xop
->head
.name2
,
640 xop
->head
.name2_len
);
644 chain
->bref
.embed
.dirent
.namlen
=
651 * The frontend will replicate this operation and is the real final
652 * authority, but adjust the inode's iparent field too if the inode
653 * is embedded in the directory.
655 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
656 chain
->data
->ipdata
.meta
.iparent
!= xop
->head
.ip3
->meta
.inum
) {
657 hammer2_inode_data_t
*wipdata
;
659 error
= hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
661 wipdata
= &chain
->data
->ipdata
;
662 wipdata
->meta
.iparent
= xop
->head
.ip3
->meta
.inum
;
667 * Destroy any matching target(s) before creating the new entry.
668 * This will result in some ping-ponging of the directory key
669 * iterator but that is ok.
671 parent
= hammer2_inode_chain(xop
->head
.ip3
, thr
->clindex
,
672 HAMMER2_RESOLVE_ALWAYS
);
673 if (parent
== NULL
) {
674 error
= HAMMER2_ERROR_EIO
;
679 tmp
= hammer2_chain_lookup(&parent
, &key_next
,
680 xop
->lhc
& ~HAMMER2_DIRHASH_LOMASK
,
681 xop
->lhc
| HAMMER2_DIRHASH_LOMASK
,
683 HAMMER2_LOOKUP_ALWAYS
);
685 if (hammer2_chain_dirent_test(tmp
, xop
->head
.name2
,
686 xop
->head
.name2_len
)) {
687 hammer2_chain_delete(parent
, tmp
,
690 tmp
= hammer2_chain_next(&parent
, tmp
, &key_next
,
693 HAMMER2_DIRHASH_LOMASK
,
695 HAMMER2_LOOKUP_ALWAYS
);
700 * A relookup is required before the create to properly
701 * position the parent chain.
703 tmp
= hammer2_chain_lookup(&parent
, &key_next
,
706 KKASSERT(tmp
== NULL
);
707 error
= hammer2_chain_create(&parent
, &chain
,
708 pmp
, HAMMER2_METH_DEFAULT
,
710 HAMMER2_BREF_TYPE_INODE
,
712 xop
->head
.mtid
, 0, 0);
715 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
717 hammer2_chain_unlock(parent
);
718 hammer2_chain_drop(parent
);
721 hammer2_chain_unlock(chain
);
722 hammer2_chain_drop(chain
);
727 * Directory collision resolver scan helper (backend, threaded).
729 * Used by the inode create code to locate an unused lhc.
732 hammer2_xop_scanlhc(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
734 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
735 hammer2_chain_t
*parent
;
736 hammer2_chain_t
*chain
;
737 hammer2_key_t key_next
;
740 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
741 HAMMER2_RESOLVE_ALWAYS
|
742 HAMMER2_RESOLVE_SHARED
);
743 if (parent
== NULL
) {
744 kprintf("xop_nresolve: NULL parent\n");
746 error
= HAMMER2_ERROR_EIO
;
751 * Lookup all possibly conflicting directory entries, the feed
752 * inherits the chain's lock so do not unlock it on the iteration.
754 chain
= hammer2_chain_lookup(&parent
, &key_next
,
756 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
758 HAMMER2_LOOKUP_ALWAYS
|
759 HAMMER2_LOOKUP_SHARED
);
761 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, 0);
763 hammer2_chain_unlock(chain
);
764 hammer2_chain_drop(chain
);
765 chain
= NULL
; /* safety */
768 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
770 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
772 HAMMER2_LOOKUP_ALWAYS
|
773 HAMMER2_LOOKUP_SHARED
);
776 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
778 hammer2_chain_unlock(parent
);
779 hammer2_chain_drop(parent
);
784 * Generic lookup of a specific key.
786 * Used by the inode hidden directory code to find the hidden directory.
789 hammer2_xop_lookup(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
791 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
792 hammer2_chain_t
*parent
;
793 hammer2_chain_t
*chain
;
794 hammer2_key_t key_next
;
797 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
798 HAMMER2_RESOLVE_ALWAYS
|
799 HAMMER2_RESOLVE_SHARED
);
801 if (parent
== NULL
) {
802 error
= HAMMER2_ERROR_EIO
;
807 * Lookup all possibly conflicting directory entries, the feed
808 * inherits the chain's lock so do not unlock it on the iteration.
810 chain
= hammer2_chain_lookup(&parent
, &key_next
,
813 HAMMER2_LOOKUP_ALWAYS
|
814 HAMMER2_LOOKUP_SHARED
);
817 error
= chain
->error
;
819 error
= HAMMER2_ERROR_ENOENT
;
821 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
825 hammer2_chain_unlock(chain
);
826 hammer2_chain_drop(chain
);
829 hammer2_chain_unlock(parent
);
830 hammer2_chain_drop(parent
);
837 * WARNING! Fed chains must be locked shared so ownership can be transfered
838 * and to prevent frontend/backend stalls that would occur with an
839 * exclusive lock. The shared lock also allows chain->data to be
843 hammer2_xop_scanall(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
845 hammer2_xop_scanall_t
*xop
= &arg
->xop_scanall
;
846 hammer2_chain_t
*parent
;
847 hammer2_chain_t
*chain
;
848 hammer2_key_t key_next
;
852 * Assert required flags.
854 KKASSERT(xop
->resolve_flags
& HAMMER2_RESOLVE_SHARED
);
855 KKASSERT(xop
->lookup_flags
& HAMMER2_LOOKUP_SHARED
);
858 * The inode's chain is the iterator. If we cannot acquire it our
859 * contribution ends here.
861 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
863 if (parent
== NULL
) {
864 kprintf("xop_readdir: NULL parent\n");
869 * Generic scan of exact records. Note that indirect blocks are
870 * automatically recursed and will not be returned.
872 chain
= hammer2_chain_lookup(&parent
, &key_next
,
873 xop
->key_beg
, xop
->key_end
,
874 &error
, xop
->lookup_flags
);
876 error
= hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, 0);
879 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
880 key_next
, xop
->key_end
,
881 &error
, xop
->lookup_flags
);
885 hammer2_chain_unlock(chain
);
886 hammer2_chain_drop(chain
);
888 hammer2_chain_unlock(parent
);
889 hammer2_chain_drop(parent
);
891 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);