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 * We always return the hardlink target (the real inode) for
404 hammer2_xop_feed(&xop->head, chain, clindex, error);
406 hammer2_chain_unlock(chain);
407 hammer2_chain_drop(chain);
411 hammer2_chain_unlock(parent);
412 hammer2_chain_drop(parent);
419 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
425 * If a hardlink pointer:
426 * The existing hardlink target {fdip,ip} must be moved to another
427 * directory {cdip,ip}
429 * If not a hardlink pointer:
430 * Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
431 * replace the original namespace {fdip,name} with a hardlink pointer.
434 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
436 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
438 hammer2_inode_data_t *wipdata;
439 hammer2_chain_t *parent;
440 hammer2_chain_t *chain;
441 hammer2_chain_t *tmp;
443 hammer2_key_t key_dummy;
444 int cache_index = -1;
449 * We need the precise parent chain to issue the deletion.
453 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
455 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
456 if (parent == NULL) {
461 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
466 KKASSERT(chain->parent == parent);
468 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
470 * Delete the original chain and hold onto it for the move
473 * Replace the namespace with a hardlink pointer if the
474 * chain being moved is not already a hardlink target.
476 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
480 error = hammer2_chain_create(&parent, &tmp, pmp,
482 HAMMER2_BREF_TYPE_INODE,
484 xop->head.mtid, 0, 0);
487 hammer2_chain_modify(tmp, xop->head.mtid, 0, 0);
488 wipdata = &tmp->data->ipdata;
489 bzero(wipdata, sizeof(*wipdata));
490 wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
491 wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
492 bcopy(chain->data->ipdata.filename, wipdata->filename,
493 chain->data->ipdata.meta.name_len);
494 wipdata->meta.target_type = chain->data->ipdata.meta.type;
495 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
496 wipdata->meta.inum = ip->meta.inum;
497 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
498 wipdata->meta.nlinks = 1;
499 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
501 hammer2_chain_unlock(tmp);
502 hammer2_chain_drop(tmp);
503 } else if (xop->head.ip1 != xop->head.ip3) {
505 * Delete the hardlink target so it can be moved
508 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
512 * Deletion not necessary (just a nlinks update).
517 hammer2_chain_unlock(parent);
518 hammer2_chain_drop(parent);
522 * Ok, back to the deleted chain. We must reconnect this chain
523 * as a hardlink target to cdir (ip3).
525 * WARNING! Frontend assumes filename length is 18 bytes.
528 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
529 wipdata = &chain->data->ipdata;
530 ksnprintf(wipdata->filename, sizeof(wipdata->filename),
531 "0x%016jx", (intmax_t)ip->meta.inum);
532 wipdata->meta.name_len = strlen(wipdata->filename);
533 wipdata->meta.name_key = ip->meta.inum;
536 * We must seek parent properly for the create to reattach
537 * chain. XXX just use chain->parent or
538 * inode_chain_and_parent() ?
540 parent = hammer2_inode_chain(xop->head.ip3, clindex,
541 HAMMER2_RESOLVE_ALWAYS);
542 if (parent == NULL) {
546 tmp = hammer2_chain_lookup(&parent, &key_dummy,
547 ip->meta.inum, ip->meta.inum,
550 hammer2_chain_unlock(tmp);
551 hammer2_chain_drop(tmp);
555 error = hammer2_chain_create(&parent, &chain, pmp,
556 wipdata->meta.name_key, 0,
557 HAMMER2_BREF_TYPE_INODE,
559 xop->head.mtid, 0, 0);
565 * Bump nlinks to synchronize with frontend.
567 if (xop->nlinks_delta) {
568 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
569 chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
573 * To avoid having to scan the collision space we can simply
574 * reuse the inode's original name_key. But ip->meta.name_key
575 * may have already been updated by the front-end, so use xop->lhc.
577 * (frontend is responsible for fixing up ip->pip).
580 hammer2_xop_feed(&xop->head, NULL, clindex, error);
582 hammer2_chain_unlock(parent);
583 hammer2_chain_drop(parent);
586 hammer2_chain_unlock(chain);
587 hammer2_chain_drop(chain);
593 * Backend for hammer2_vop_nrename()
595 * This handles the final step of renaming, either renaming the
596 * actual inode or renaming the hardlink pointer.
599 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
601 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
603 hammer2_chain_t *parent;
604 hammer2_chain_t *chain;
605 hammer2_chain_t *tmp;
607 hammer2_key_t key_dummy;
608 int cache_index = -1;
612 * We need the precise parent chain to issue the deletion.
614 * If this is not a hardlink target we can act on the inode,
615 * otherwise we have to locate the hardlink pointer.
621 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
623 * Find ip's direct parent chain.
625 parent = hammer2_inode_chain(ip, clindex,
626 HAMMER2_RESOLVE_ALWAYS);
628 hammer2_chain_getparent(&parent,
629 HAMMER2_RESOLVE_ALWAYS);
630 if (parent == NULL) {
634 chain = hammer2_inode_chain(ip, clindex,
635 HAMMER2_RESOLVE_ALWAYS);
642 * The hardlink pointer for the head.ip1 hardlink target
643 * is in fdip, do a namespace search.
645 const hammer2_inode_data_t *ripdata;
647 hammer2_key_t key_next;
651 parent = hammer2_inode_chain(xop->head.ip1, clindex,
652 HAMMER2_RESOLVE_ALWAYS);
653 if (parent == NULL) {
654 kprintf("xop_nrename: NULL parent\n");
658 name = xop->head.name1;
659 name_len = xop->head.name1_len;
662 * Lookup the directory entry
664 lhc = hammer2_dirhash(name, name_len);
665 chain = hammer2_chain_lookup(&parent, &key_next,
666 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
668 HAMMER2_LOOKUP_ALWAYS);
670 ripdata = &chain->data->ipdata;
671 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
672 ripdata->meta.name_len == name_len &&
673 bcmp(ripdata->filename, name, name_len) == 0) {
676 chain = hammer2_chain_next(&parent, chain, &key_next,
678 lhc + HAMMER2_DIRHASH_LOMASK,
680 HAMMER2_LOOKUP_ALWAYS);
685 /* XXX shouldn't happen, but does under fsstress */
686 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
694 * Delete it, then create it in the new namespace.
696 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
697 hammer2_chain_unlock(parent);
698 hammer2_chain_drop(parent);
699 parent = NULL; /* safety */
702 * Ok, back to the deleted chain. We must reconnect this chain
703 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
704 * is not otherwise modified.
706 * Frontend is expected to replicate the same inode meta data
709 * NOTE! This chain may not represent the actual inode, it
710 * can be a hardlink pointer.
712 * XXX in-inode parent directory specification?
714 if (chain->data->ipdata.meta.name_key != xop->lhc ||
715 xop->head.name1_len != xop->head.name2_len ||
716 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
717 hammer2_inode_data_t *wipdata;
719 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
720 wipdata = &chain->data->ipdata;
722 bzero(wipdata->filename, sizeof(wipdata->filename));
723 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
724 wipdata->meta.name_key = xop->lhc;
725 wipdata->meta.name_len = xop->head.name2_len;
727 if (chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
728 hammer2_inode_data_t *wipdata;
730 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
731 wipdata = &chain->data->ipdata;
733 wipdata->meta.iparent = xop->head.ip3->meta.inum;
737 * We must seek parent properly for the create.
739 parent = hammer2_inode_chain(xop->head.ip3, clindex,
740 HAMMER2_RESOLVE_ALWAYS);
741 if (parent == NULL) {
745 tmp = hammer2_chain_lookup(&parent, &key_dummy,
749 hammer2_chain_unlock(tmp);
750 hammer2_chain_drop(tmp);
755 error = hammer2_chain_create(&parent, &chain, pmp,
757 HAMMER2_BREF_TYPE_INODE,
759 xop->head.mtid, 0, 0);
761 * (frontend is responsible for fixing up ip->pip).
764 hammer2_xop_feed(&xop->head, NULL, clindex, error);
766 hammer2_chain_unlock(parent);
767 hammer2_chain_drop(parent);
770 hammer2_chain_unlock(chain);
771 hammer2_chain_drop(chain);
776 * Directory collision resolver scan helper (backend, threaded).
778 * Used by the inode create code to locate an unused lhc.
781 hammer2_xop_scanlhc(hammer2_xop_t *arg, int clindex)
783 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
784 hammer2_chain_t *parent;
785 hammer2_chain_t *chain;
786 hammer2_key_t key_next;
787 int cache_index = -1; /* XXX */
790 parent = hammer2_inode_chain(xop->head.ip1, clindex,
791 HAMMER2_RESOLVE_ALWAYS |
792 HAMMER2_RESOLVE_SHARED);
793 if (parent == NULL) {
794 kprintf("xop_nresolve: NULL parent\n");
801 * Lookup all possibly conflicting directory entries, the feed
802 * inherits the chain's lock so do not unlock it on the iteration.
804 chain = hammer2_chain_lookup(&parent, &key_next,
806 xop->lhc + HAMMER2_DIRHASH_LOMASK,
808 HAMMER2_LOOKUP_ALWAYS |
809 HAMMER2_LOOKUP_SHARED);
811 error = hammer2_xop_feed(&xop->head, chain, clindex,
814 hammer2_chain_unlock(chain);
815 hammer2_chain_drop(chain);
816 chain = NULL; /* safety */
819 chain = hammer2_chain_next(&parent, chain, &key_next,
821 xop->lhc + HAMMER2_DIRHASH_LOMASK,
823 HAMMER2_LOOKUP_ALWAYS |
824 HAMMER2_LOOKUP_SHARED);
827 hammer2_xop_feed(&xop->head, NULL, clindex, error);
829 hammer2_chain_unlock(parent);
830 hammer2_chain_drop(parent);
835 * Generic lookup of a specific key.
837 * Used by the inode hidden directory code to find the hidden directory.
840 hammer2_xop_lookup(hammer2_xop_t *arg, int clindex)
842 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
843 hammer2_chain_t *parent;
844 hammer2_chain_t *chain;
845 hammer2_key_t key_next;
846 int cache_index = -1; /* XXX */
849 parent = hammer2_inode_chain(xop->head.ip1, clindex,
850 HAMMER2_RESOLVE_ALWAYS |
851 HAMMER2_RESOLVE_SHARED);
853 if (parent == NULL) {
859 * Lookup all possibly conflicting directory entries, the feed
860 * inherits the chain's lock so do not unlock it on the iteration.
862 chain = hammer2_chain_lookup(&parent, &key_next,
865 HAMMER2_LOOKUP_ALWAYS |
866 HAMMER2_LOOKUP_SHARED);
868 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
870 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
874 hammer2_chain_unlock(chain);
875 hammer2_chain_drop(chain);
878 hammer2_chain_unlock(parent);
879 hammer2_chain_drop(parent);
886 * WARNING! Fed chains must be locked shared so ownership can be transfered
887 * and to prevent frontend/backend stalls that would occur with an
888 * exclusive lock. The shared lock also allows chain->data to be
892 hammer2_xop_scanall(hammer2_xop_t *arg, int clindex)
894 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
895 hammer2_chain_t *parent;
896 hammer2_chain_t *chain;
897 hammer2_key_t key_next;
898 int cache_index = -1;
902 * Assert required flags.
904 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
905 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
908 * The inode's chain is the iterator. If we cannot acquire it our
909 * contribution ends here.
911 parent = hammer2_inode_chain(xop->head.ip1, clindex,
913 if (parent == NULL) {
914 kprintf("xop_readdir: NULL parent\n");
919 * Generic scan of exact records. Note that indirect blocks are
920 * automatically recursed and will not be returned.
922 chain = hammer2_chain_lookup(&parent, &key_next,
923 xop->key_beg, xop->key_end,
924 &cache_index, xop->lookup_flags);
926 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
929 chain = hammer2_chain_next(&parent, chain, &key_next,
930 key_next, xop->key_end,
931 &cache_index, xop->lookup_flags);
934 hammer2_chain_unlock(chain);
935 hammer2_chain_drop(chain);
937 hammer2_chain_unlock(parent);
938 hammer2_chain_drop(parent);
940 hammer2_xop_feed(&xop->head, NULL, clindex, error);