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
;
79 chain
= hammer2_chain_lookup_init(ochain
, 0);
81 if (chain
->data
->ipdata
.meta
.type
== HAMMER2_OBJTYPE_HARDLINK
) {
83 hammer2_chain_unlock(oparent
);
86 error
= hammer2_chain_hardlink_find(&parent
, &chain
,
89 hammer2_chain_unlock(parent
);
90 hammer2_chain_drop(parent
);
93 hammer2_chain_lock(oparent
, HAMMER2_RESOLVE_ALWAYS
);
94 if (ochain
->parent
!= oparent
) {
96 hammer2_chain_unlock(chain
);
97 hammer2_chain_drop(chain
);
99 kprintf("H2EAGAIN\n");
109 chain
= hammer2_chain_lookup(&parent
, &key_next
,
110 HAMMER2_DIRHASH_VISIBLE
,
116 hammer2_chain_unlock(chain
);
117 hammer2_chain_drop(chain
);
121 hammer2_chain_lookup_done(parent
);
127 * Backend for hammer2_vfs_root()
129 * This is called when a newly mounted PFS has not yet synchronized
130 * to the inode_tid and modify_tid.
133 hammer2_xop_ipcluster(hammer2_xop_t
*arg
, int clindex
)
135 hammer2_xop_ipcluster_t
*xop
= &arg
->xop_ipcluster
;
136 hammer2_chain_t
*chain
;
139 chain
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
140 HAMMER2_RESOLVE_ALWAYS
|
141 HAMMER2_RESOLVE_SHARED
);
143 error
= chain
->error
;
147 hammer2_xop_feed(&xop
->head
, chain
, clindex
, error
);
149 hammer2_chain_unlock(chain
);
150 hammer2_chain_drop(chain
);
155 * Backend for hammer2_vop_readdir()
158 hammer2_xop_readdir(hammer2_xop_t
*arg
, int clindex
)
160 hammer2_xop_readdir_t
*xop
= &arg
->xop_readdir
;
161 hammer2_chain_t
*parent
;
162 hammer2_chain_t
*chain
;
163 hammer2_key_t key_next
;
165 int cache_index
= -1;
169 if (hammer2_debug
& 0x0020)
170 kprintf("xop_readdir %p lkey=%016jx\n", xop
, lkey
);
173 * The inode's chain is the iterator. If we cannot acquire it our
174 * contribution ends here.
176 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
177 HAMMER2_RESOLVE_ALWAYS
|
178 HAMMER2_RESOLVE_SHARED
);
179 if (parent
== NULL
) {
180 kprintf("xop_readdir: NULL parent\n");
185 * Directory scan [re]start and loop, the feed inherits the chain's
186 * lock so do not unlock it on the iteration.
188 chain
= hammer2_chain_lookup(&parent
, &key_next
, lkey
, lkey
,
189 &cache_index
, HAMMER2_LOOKUP_SHARED
);
191 chain
= hammer2_chain_lookup(&parent
, &key_next
,
192 lkey
, HAMMER2_KEY_MAX
,
194 HAMMER2_LOOKUP_SHARED
);
197 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, 0);
200 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
201 key_next
, HAMMER2_KEY_MAX
,
203 HAMMER2_LOOKUP_SHARED
);
206 hammer2_chain_unlock(chain
);
207 hammer2_chain_drop(chain
);
209 hammer2_chain_unlock(parent
);
210 hammer2_chain_drop(parent
);
212 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
216 * Backend for hammer2_vop_nresolve()
219 hammer2_xop_nresolve(hammer2_xop_t
*arg
, int clindex
)
221 hammer2_xop_nresolve_t
*xop
= &arg
->xop_nresolve
;
222 hammer2_chain_t
*parent
;
223 hammer2_chain_t
*chain
;
224 const hammer2_inode_data_t
*ripdata
;
227 hammer2_key_t key_next
;
229 int cache_index
= -1; /* XXX */
232 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
233 HAMMER2_RESOLVE_ALWAYS
|
234 HAMMER2_RESOLVE_SHARED
);
235 if (parent
== NULL
) {
236 kprintf("xop_nresolve: NULL parent\n");
241 name
= xop
->head
.name1
;
242 name_len
= xop
->head
.name1_len
;
245 * Lookup the directory entry
247 lhc
= hammer2_dirhash(name
, name_len
);
248 chain
= hammer2_chain_lookup(&parent
, &key_next
,
249 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
251 HAMMER2_LOOKUP_ALWAYS
|
252 HAMMER2_LOOKUP_SHARED
);
254 ripdata
= &chain
->data
->ipdata
;
255 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
256 ripdata
->meta
.name_len
== name_len
&&
257 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
260 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
262 lhc
+ HAMMER2_DIRHASH_LOMASK
,
264 HAMMER2_LOOKUP_ALWAYS
|
265 HAMMER2_LOOKUP_SHARED
);
269 * If the entry is a hardlink pointer, resolve it.
273 if (chain
->data
->ipdata
.meta
.type
== HAMMER2_OBJTYPE_HARDLINK
) {
274 error
= hammer2_chain_hardlink_find(&parent
, &chain
,
276 HAMMER2_LOOKUP_SHARED
);
280 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, error
);
282 hammer2_chain_unlock(chain
);
283 hammer2_chain_drop(chain
);
286 hammer2_chain_unlock(parent
);
287 hammer2_chain_drop(parent
);
292 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper
293 * for hammer2_vop_nrename().
295 * This function locates and removes a directory entry. If the entry is
296 * a hardlink pointer, this function does NOT remove the hardlink target,
297 * but will lookup and return the hardlink target.
299 * Note that any hardlink target's nlinks may not be synchronized to the
300 * in-memory inode. hammer2_inode_unlink_finisher() is responsible for the
301 * final disposition of the hardlink target.
303 * If an inode pointer we lookup and return the actual inode. If not, we
304 * return the deleted directory entry.
306 * The frontend is responsible for moving open inodes to the hidden directory
307 * and for decrementing nlinks.
310 hammer2_xop_unlink(hammer2_xop_t
*arg
, int clindex
)
312 hammer2_xop_unlink_t
*xop
= &arg
->xop_unlink
;
313 hammer2_chain_t
*parent
;
314 hammer2_chain_t
*chain
;
315 const hammer2_inode_data_t
*ripdata
;
318 hammer2_key_t key_next
;
320 int cache_index
= -1; /* XXX */
325 * Requires exclusive lock
327 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
328 HAMMER2_RESOLVE_ALWAYS
);
330 if (parent
== NULL
) {
331 kprintf("xop_nresolve: NULL parent\n");
335 name
= xop
->head
.name1
;
336 name_len
= xop
->head
.name1_len
;
339 * Lookup the directory entry
341 lhc
= hammer2_dirhash(name
, name_len
);
342 chain
= hammer2_chain_lookup(&parent
, &key_next
,
343 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
345 HAMMER2_LOOKUP_ALWAYS
);
347 ripdata
= &chain
->data
->ipdata
;
348 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
349 ripdata
->meta
.name_len
== name_len
&&
350 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
353 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
355 lhc
+ HAMMER2_DIRHASH_LOMASK
,
357 HAMMER2_LOOKUP_ALWAYS
);
361 * The directory entry will almost always be a hardlink pointer,
362 * which we permanently delete. Otherwise we go by xop->dopermanent.
363 * Note that the target chain's nlinks may not be synchronized with
364 * the in-memory hammer2_inode_t structure, so we don't try to do
365 * anything fancy here.
369 int dopermanent
= xop
->dopermanent
;
373 * If the directory entry is the actual inode then use its
374 * type for the directory typing tests, otherwise if it is
375 * a hardlink pointer then use the secondary type field for
376 * directory typing tests.
378 * Also, hardlink pointers are always permanently deleted
379 * (because they aren't the actual inode).
381 type
= chain
->data
->ipdata
.meta
.type
;
382 if (type
== HAMMER2_OBJTYPE_HARDLINK
) {
383 type
= chain
->data
->ipdata
.meta
.target_type
;
384 dopermanent
|= HAMMER2_DELETE_PERMANENT
;
388 * Check directory typing and delete the entry. Note that
389 * nlinks adjustments are made on the real inode by the
390 * frontend, not here.
392 * Unfortunately, checkdirempty() may have to unlock (parent).
393 * If it no longer matches chain->parent after re-locking,
394 * EAGAIN is returned.
396 if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
397 (error
= checkdirempty(parent
, chain
, clindex
)) != 0) {
398 /* error may be EAGAIN or ENOTEMPTY */
399 if (error
== EAGAIN
) {
400 hammer2_chain_unlock(chain
);
401 hammer2_chain_drop(chain
);
402 hammer2_chain_unlock(parent
);
403 hammer2_chain_drop(parent
);
406 } else if (type
== HAMMER2_OBJTYPE_DIRECTORY
&&
409 } else if (type
!= HAMMER2_OBJTYPE_DIRECTORY
&&
414 * This deletes the directory entry itself, which is
415 * also the inode when nlinks == 1. Hardlink targets
416 * are handled in the next conditional.
418 error
= chain
->error
;
419 hammer2_chain_delete(parent
, chain
,
420 xop
->head
.mtid
, dopermanent
);
425 * If the entry is a hardlink pointer, resolve it. We do not try
426 * to manipulate the contents of the hardlink target as it might
427 * not be synchronized with the front-end hammer2_inode_t. Nor do
428 * we try to lookup the front-end hammer2_inode_t here (we are the
432 chain
->data
->ipdata
.meta
.type
== HAMMER2_OBJTYPE_HARDLINK
) {
435 lhc
= chain
->data
->ipdata
.meta
.inum
;
437 error2
= hammer2_chain_hardlink_find(&parent
, &chain
,
440 kprintf("hardlink_find: %016jx %p failed\n",
442 error2
= 0; /* silently ignore */
449 * Return the inode target for further action. Typically used by
450 * hammer2_inode_unlink_finisher().
453 hammer2_xop_feed(&xop
->head
, chain
, clindex
, error
);
455 hammer2_chain_unlock(chain
);
456 hammer2_chain_drop(chain
);
460 hammer2_chain_unlock(parent
);
461 hammer2_chain_drop(parent
);
468 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
474 * If a hardlink pointer:
475 * The existing hardlink target {fdip,ip} must be moved to another
476 * directory {cdip,ip}
478 * If not a hardlink pointer:
479 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
480 * replace the original namespace {fdip,name} with a hardlink pointer.
483 hammer2_xop_nlink(hammer2_xop_t
*arg
, int clindex
)
485 hammer2_xop_nlink_t
*xop
= &arg
->xop_nlink
;
487 hammer2_inode_data_t
*wipdata
;
488 hammer2_chain_t
*parent
;
489 hammer2_chain_t
*chain
;
490 hammer2_chain_t
*tmp
;
492 hammer2_key_t key_dummy
;
493 int cache_index
= -1;
498 * We need the precise parent chain to issue the deletion.
502 parent
= hammer2_inode_chain(ip
, clindex
, HAMMER2_RESOLVE_ALWAYS
);
504 hammer2_chain_getparent(&parent
, HAMMER2_RESOLVE_ALWAYS
);
505 if (parent
== NULL
) {
510 chain
= hammer2_inode_chain(ip
, clindex
, HAMMER2_RESOLVE_ALWAYS
);
515 KKASSERT(chain
->parent
== parent
);
517 if (chain
->data
->ipdata
.meta
.name_key
& HAMMER2_DIRHASH_VISIBLE
) {
519 * Delete the original chain and hold onto it for the move
522 * Replace the namespace with a hardlink pointer if the
523 * chain being moved is not already a hardlink target.
525 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
529 error
= hammer2_chain_create(&parent
, &tmp
,
530 pmp
, HAMMER2_METH_DEFAULT
,
532 HAMMER2_BREF_TYPE_INODE
,
534 xop
->head
.mtid
, 0, 0);
537 hammer2_chain_modify(tmp
, xop
->head
.mtid
, 0, 0);
538 wipdata
= &tmp
->data
->ipdata
;
539 bzero(wipdata
, sizeof(*wipdata
));
540 wipdata
->meta
.name_key
= chain
->data
->ipdata
.meta
.name_key
;
541 wipdata
->meta
.name_len
= chain
->data
->ipdata
.meta
.name_len
;
542 bcopy(chain
->data
->ipdata
.filename
, wipdata
->filename
,
543 chain
->data
->ipdata
.meta
.name_len
);
544 wipdata
->meta
.target_type
= chain
->data
->ipdata
.meta
.type
;
545 wipdata
->meta
.type
= HAMMER2_OBJTYPE_HARDLINK
;
546 wipdata
->meta
.inum
= ip
->meta
.inum
;
547 wipdata
->meta
.version
= HAMMER2_INODE_VERSION_ONE
;
548 wipdata
->meta
.nlinks
= 1;
549 wipdata
->meta
.op_flags
= HAMMER2_OPFLAG_DIRECTDATA
;
551 hammer2_chain_unlock(tmp
);
552 hammer2_chain_drop(tmp
);
553 } else if (xop
->head
.ip1
!= xop
->head
.ip3
) {
555 * Delete the hardlink target so it can be moved
558 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
562 * Deletion not necessary (just a nlinks update).
567 hammer2_chain_unlock(parent
);
568 hammer2_chain_drop(parent
);
572 * Ok, back to the deleted chain. We must reconnect this chain
573 * as a hardlink target to cdir (ip3).
575 * WARNING! Frontend assumes filename length is 18 bytes.
578 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
579 wipdata
= &chain
->data
->ipdata
;
580 ksnprintf(wipdata
->filename
, sizeof(wipdata
->filename
),
581 "0x%016jx", (intmax_t)ip
->meta
.inum
);
582 wipdata
->meta
.name_len
= strlen(wipdata
->filename
);
583 wipdata
->meta
.name_key
= ip
->meta
.inum
;
586 * We must seek parent properly for the create to reattach
587 * chain. XXX just use chain->parent or
588 * inode_chain_and_parent() ?
590 parent
= hammer2_inode_chain(xop
->head
.ip3
, clindex
,
591 HAMMER2_RESOLVE_ALWAYS
);
592 if (parent
== NULL
) {
596 tmp
= hammer2_chain_lookup(&parent
, &key_dummy
,
597 ip
->meta
.inum
, ip
->meta
.inum
,
600 hammer2_chain_unlock(tmp
);
601 hammer2_chain_drop(tmp
);
605 error
= hammer2_chain_create(&parent
, &chain
,
606 pmp
, HAMMER2_METH_DEFAULT
,
607 wipdata
->meta
.name_key
, 0,
608 HAMMER2_BREF_TYPE_INODE
,
610 xop
->head
.mtid
, 0, 0);
616 * Bump nlinks to synchronize with frontend.
618 if (xop
->nlinks_delta
) {
619 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
620 chain
->data
->ipdata
.meta
.nlinks
+= xop
->nlinks_delta
;
624 * To avoid having to scan the collision space we can simply
625 * reuse the inode's original name_key. But ip->meta.name_key
626 * may have already been updated by the front-end, so use xop->lhc.
629 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
631 hammer2_chain_unlock(parent
);
632 hammer2_chain_drop(parent
);
635 hammer2_chain_unlock(chain
);
636 hammer2_chain_drop(chain
);
642 * Backend for hammer2_vop_nrename()
644 * This handles the final step of renaming, either renaming the
645 * actual inode or renaming the hardlink pointer.
648 hammer2_xop_nrename(hammer2_xop_t
*arg
, int clindex
)
650 hammer2_xop_nrename_t
*xop
= &arg
->xop_nrename
;
652 hammer2_chain_t
*parent
;
653 hammer2_chain_t
*chain
;
654 hammer2_chain_t
*tmp
;
656 hammer2_key_t key_dummy
;
657 int cache_index
= -1;
661 * We need the precise parent chain to issue the deletion.
663 * If this is not a hardlink target we can act on the inode,
664 * otherwise we have to locate the hardlink pointer.
670 if (xop
->ip_key
& HAMMER2_DIRHASH_VISIBLE
) {
672 * Find ip's direct parent chain.
674 parent
= hammer2_inode_chain(ip
, clindex
,
675 HAMMER2_RESOLVE_ALWAYS
);
677 hammer2_chain_getparent(&parent
,
678 HAMMER2_RESOLVE_ALWAYS
);
679 if (parent
== NULL
) {
683 chain
= hammer2_inode_chain(ip
, clindex
,
684 HAMMER2_RESOLVE_ALWAYS
);
691 * The hardlink pointer for the head.ip1 hardlink target
692 * is in fdip, do a namespace search.
694 const hammer2_inode_data_t
*ripdata
;
696 hammer2_key_t key_next
;
700 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
701 HAMMER2_RESOLVE_ALWAYS
);
702 if (parent
== NULL
) {
703 kprintf("xop_nrename: NULL parent\n");
707 name
= xop
->head
.name1
;
708 name_len
= xop
->head
.name1_len
;
711 * Lookup the directory entry
713 lhc
= hammer2_dirhash(name
, name_len
);
714 chain
= hammer2_chain_lookup(&parent
, &key_next
,
715 lhc
, lhc
+ HAMMER2_DIRHASH_LOMASK
,
717 HAMMER2_LOOKUP_ALWAYS
);
719 ripdata
= &chain
->data
->ipdata
;
720 if (chain
->bref
.type
== HAMMER2_BREF_TYPE_INODE
&&
721 ripdata
->meta
.name_len
== name_len
&&
722 bcmp(ripdata
->filename
, name
, name_len
) == 0) {
725 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
727 lhc
+ HAMMER2_DIRHASH_LOMASK
,
729 HAMMER2_LOOKUP_ALWAYS
);
734 /* XXX shouldn't happen, but does under fsstress */
735 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
743 * Delete it, then create it in the new namespace.
745 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
746 hammer2_chain_unlock(parent
);
747 hammer2_chain_drop(parent
);
748 parent
= NULL
; /* safety */
751 * Ok, back to the deleted chain. We must reconnect this chain
752 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
753 * is not otherwise modified.
755 * Frontend is expected to replicate the same inode meta data
758 * NOTE! This chain may not represent the actual inode, it
759 * can be a hardlink pointer.
761 * XXX in-inode parent directory specification?
763 if (chain
->data
->ipdata
.meta
.name_key
!= xop
->lhc
||
764 xop
->head
.name1_len
!= xop
->head
.name2_len
||
765 bcmp(xop
->head
.name1
, xop
->head
.name2
, xop
->head
.name1_len
) != 0) {
766 hammer2_inode_data_t
*wipdata
;
768 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
769 wipdata
= &chain
->data
->ipdata
;
771 bzero(wipdata
->filename
, sizeof(wipdata
->filename
));
772 bcopy(xop
->head
.name2
, wipdata
->filename
, xop
->head
.name2_len
);
773 wipdata
->meta
.name_key
= xop
->lhc
;
774 wipdata
->meta
.name_len
= xop
->head
.name2_len
;
776 if (chain
->data
->ipdata
.meta
.iparent
!= xop
->head
.ip3
->meta
.inum
) {
777 hammer2_inode_data_t
*wipdata
;
779 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
780 wipdata
= &chain
->data
->ipdata
;
782 wipdata
->meta
.iparent
= xop
->head
.ip3
->meta
.inum
;
786 * We must seek parent properly for the create.
788 parent
= hammer2_inode_chain(xop
->head
.ip3
, clindex
,
789 HAMMER2_RESOLVE_ALWAYS
);
790 if (parent
== NULL
) {
794 tmp
= hammer2_chain_lookup(&parent
, &key_dummy
,
798 hammer2_chain_unlock(tmp
);
799 hammer2_chain_drop(tmp
);
804 error
= hammer2_chain_create(&parent
, &chain
,
805 pmp
, HAMMER2_METH_DEFAULT
,
807 HAMMER2_BREF_TYPE_INODE
,
809 xop
->head
.mtid
, 0, 0);
811 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
813 hammer2_chain_unlock(parent
);
814 hammer2_chain_drop(parent
);
817 hammer2_chain_unlock(chain
);
818 hammer2_chain_drop(chain
);
823 * Directory collision resolver scan helper (backend, threaded).
825 * Used by the inode create code to locate an unused lhc.
828 hammer2_xop_scanlhc(hammer2_xop_t
*arg
, int clindex
)
830 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
831 hammer2_chain_t
*parent
;
832 hammer2_chain_t
*chain
;
833 hammer2_key_t key_next
;
834 int cache_index
= -1; /* XXX */
837 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
838 HAMMER2_RESOLVE_ALWAYS
|
839 HAMMER2_RESOLVE_SHARED
);
840 if (parent
== NULL
) {
841 kprintf("xop_nresolve: NULL parent\n");
848 * Lookup all possibly conflicting directory entries, the feed
849 * inherits the chain's lock so do not unlock it on the iteration.
851 chain
= hammer2_chain_lookup(&parent
, &key_next
,
853 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
855 HAMMER2_LOOKUP_ALWAYS
|
856 HAMMER2_LOOKUP_SHARED
);
858 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
,
861 hammer2_chain_unlock(chain
);
862 hammer2_chain_drop(chain
);
863 chain
= NULL
; /* safety */
866 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
868 xop
->lhc
+ HAMMER2_DIRHASH_LOMASK
,
870 HAMMER2_LOOKUP_ALWAYS
|
871 HAMMER2_LOOKUP_SHARED
);
874 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);
876 hammer2_chain_unlock(parent
);
877 hammer2_chain_drop(parent
);
882 * Generic lookup of a specific key.
884 * Used by the inode hidden directory code to find the hidden directory.
887 hammer2_xop_lookup(hammer2_xop_t
*arg
, int clindex
)
889 hammer2_xop_scanlhc_t
*xop
= &arg
->xop_scanlhc
;
890 hammer2_chain_t
*parent
;
891 hammer2_chain_t
*chain
;
892 hammer2_key_t key_next
;
893 int cache_index
= -1; /* XXX */
896 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
897 HAMMER2_RESOLVE_ALWAYS
|
898 HAMMER2_RESOLVE_SHARED
);
900 if (parent
== NULL
) {
906 * Lookup all possibly conflicting directory entries, the feed
907 * inherits the chain's lock so do not unlock it on the iteration.
909 chain
= hammer2_chain_lookup(&parent
, &key_next
,
912 HAMMER2_LOOKUP_ALWAYS
|
913 HAMMER2_LOOKUP_SHARED
);
915 hammer2_xop_feed(&xop
->head
, chain
, clindex
, chain
->error
);
917 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, ENOENT
);
921 hammer2_chain_unlock(chain
);
922 hammer2_chain_drop(chain
);
925 hammer2_chain_unlock(parent
);
926 hammer2_chain_drop(parent
);
933 * WARNING! Fed chains must be locked shared so ownership can be transfered
934 * and to prevent frontend/backend stalls that would occur with an
935 * exclusive lock. The shared lock also allows chain->data to be
939 hammer2_xop_scanall(hammer2_xop_t
*arg
, int clindex
)
941 hammer2_xop_scanall_t
*xop
= &arg
->xop_scanall
;
942 hammer2_chain_t
*parent
;
943 hammer2_chain_t
*chain
;
944 hammer2_key_t key_next
;
945 int cache_index
= -1;
949 * Assert required flags.
951 KKASSERT(xop
->resolve_flags
& HAMMER2_RESOLVE_SHARED
);
952 KKASSERT(xop
->lookup_flags
& HAMMER2_LOOKUP_SHARED
);
955 * The inode's chain is the iterator. If we cannot acquire it our
956 * contribution ends here.
958 parent
= hammer2_inode_chain(xop
->head
.ip1
, clindex
,
960 if (parent
== NULL
) {
961 kprintf("xop_readdir: NULL parent\n");
966 * Generic scan of exact records. Note that indirect blocks are
967 * automatically recursed and will not be returned.
969 chain
= hammer2_chain_lookup(&parent
, &key_next
,
970 xop
->key_beg
, xop
->key_end
,
971 &cache_index
, xop
->lookup_flags
);
973 error
= hammer2_xop_feed(&xop
->head
, chain
, clindex
, 0);
976 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
977 key_next
, xop
->key_end
,
978 &cache_index
, xop
->lookup_flags
);
981 hammer2_chain_unlock(chain
);
982 hammer2_chain_drop(chain
);
984 hammer2_chain_unlock(parent
);
985 hammer2_chain_drop(parent
);
987 hammer2_xop_feed(&xop
->head
, NULL
, clindex
, error
);