hammer2 - Refactor frontend part 14/many
[dragonfly.git] / sys / vfs / hammer2 / hammer2_xops.c
CommitLineData
7026ada6
MD
1/*
2 * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved.
3 *
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)
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
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
18 * distribution.
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.
22 *
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
34 * SUCH DAMAGE.
35 */
36/*
37 * Per-node backend for kernel filesystem interface.
38 *
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.
43 */
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/fcntl.h>
48#include <sys/buf.h>
49#include <sys/proc.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>
55#include <sys/uio.h>
56#include <sys/objcache.h>
57#include <sys/event.h>
58#include <sys/file.h>
59#include <vfs/fifofs/fifo.h>
60
61#include "hammer2.h"
62
e12ae3a5
MD
63/*
64 * Backend for hammer2_vop_readdir()
65 */
7026ada6
MD
66void
67hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
68{
69 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
70 hammer2_chain_t *parent;
71 hammer2_chain_t *chain;
72 hammer2_key_t key_next;
73 hammer2_key_t lkey;
74 int cache_index = -1;
75 int error = 0;
76
77 lkey = xop->head.lkey;
78 if (hammer2_debug & 0x0020)
79 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
80
81 /*
82 * The inode's chain is the iterator. If we cannot acquire it our
83 * contribution ends here.
84 */
85 parent = hammer2_inode_chain(xop->head.ip, clindex,
86 HAMMER2_RESOLVE_ALWAYS |
87 HAMMER2_RESOLVE_SHARED);
88 if (parent == NULL) {
89 kprintf("xop_readdir: NULL parent\n");
90 goto done;
91 }
92
93 /*
12ff971c
MD
94 * Directory scan [re]start and loop, the feed inherits the chain's
95 * lock so do not unlock it on the iteration.
7026ada6
MD
96 */
97 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
98 &cache_index, HAMMER2_LOOKUP_SHARED);
99 if (chain == NULL) {
100 chain = hammer2_chain_lookup(&parent, &key_next,
101 lkey, (hammer2_key_t)-1,
102 &cache_index,
103 HAMMER2_LOOKUP_SHARED);
104 }
c603b86b 105 while (chain) {
7026ada6
MD
106 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
107 if (error)
108 break;
109 chain = hammer2_chain_next(&parent, chain, &key_next,
110 key_next, (hammer2_key_t)-1,
111 &cache_index,
112 HAMMER2_LOOKUP_SHARED |
113 HAMMER2_LOOKUP_NOUNLOCK);
114 }
c603b86b 115 if (chain)
7026ada6 116 hammer2_chain_drop(chain);
7026ada6
MD
117 hammer2_chain_unlock(parent);
118 hammer2_chain_drop(parent);
119done:
120 hammer2_xop_feed(&xop->head, NULL, clindex, error);
121}
122
e12ae3a5
MD
123/*
124 * Backend for hammer2_vop_nresolve()
125 */
c603b86b
MD
126void
127hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
7026ada6 128{
c603b86b
MD
129 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
130 hammer2_chain_t *parent;
131 hammer2_chain_t *chain;
7026ada6 132 const hammer2_inode_data_t *ripdata;
12ff971c
MD
133 const char *name;
134 size_t name_len;
7026ada6
MD
135 hammer2_key_t key_next;
136 hammer2_key_t lhc;
c603b86b
MD
137 int cache_index = -1; /* XXX */
138 int error;
7026ada6 139
c603b86b
MD
140 parent = hammer2_inode_chain(xop->head.ip, clindex,
141 HAMMER2_RESOLVE_ALWAYS |
142 HAMMER2_RESOLVE_SHARED);
143 if (parent == NULL) {
144 kprintf("xop_nresolve: NULL parent\n");
145 chain = NULL;
146 error = EIO;
147 goto done;
7026ada6 148 }
12ff971c
MD
149 name = xop->head.name;
150 name_len = xop->head.name_len;
7026ada6
MD
151
152 /*
c603b86b 153 * Lookup the directory entry
7026ada6 154 */
12ff971c 155 lhc = hammer2_dirhash(name, name_len);
c603b86b
MD
156 chain = hammer2_chain_lookup(&parent, &key_next,
157 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
158 &cache_index,
159 HAMMER2_LOOKUP_ALWAYS |
160 HAMMER2_LOOKUP_SHARED);
161 while (chain) {
162 ripdata = &chain->data->ipdata;
163 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
12ff971c
MD
164 ripdata->meta.name_len == name_len &&
165 bcmp(ripdata->filename, name, name_len) == 0) {
c603b86b 166 break;
7026ada6 167 }
c603b86b
MD
168 chain = hammer2_chain_next(&parent, chain, &key_next,
169 key_next,
170 lhc + HAMMER2_DIRHASH_LOMASK,
171 &cache_index,
172 HAMMER2_LOOKUP_ALWAYS |
173 HAMMER2_LOOKUP_SHARED);
7026ada6
MD
174 }
175
7026ada6 176 /*
c603b86b 177 * If the entry is a hardlink pointer, resolve it.
7026ada6 178 */
c603b86b
MD
179 error = 0;
180 if (chain) {
181 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
e12ae3a5
MD
182 error = hammer2_chain_hardlink_find(
183 xop->head.ip,
184 &parent, &chain,
185 HAMMER2_RESOLVE_SHARED);
7026ada6 186 }
7026ada6 187 }
c603b86b
MD
188done:
189 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
190 if (chain)
191 hammer2_chain_drop(chain);
192 if (parent) {
193 hammer2_chain_unlock(parent);
194 hammer2_chain_drop(parent);
7026ada6 195 }
7026ada6
MD
196}
197
e12ae3a5
MD
198/*
199 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and helper
200 * for hammer2_vop_nrename().
201 *
202 * This function does locates and removes the directory entry. If the
203 * entry is a hardlink pointer, this function will also remove the
204 * hardlink target if the target's nlinks is 1.
205 *
206 * The frontend is responsible for moving open inodes to the hidden directory
207 * and for decrementing nlinks.
208 */
209void
210hammer2_xop_unlink(hammer2_xop_t *arg, int clindex)
211{
212 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
213 hammer2_chain_t *parent;
214 hammer2_chain_t *chain;
215 const hammer2_inode_data_t *ripdata;
216 const char *name;
217 size_t name_len;
218 uint8_t type;
219 hammer2_key_t key_next;
220 hammer2_key_t lhc;
221 int cache_index = -1; /* XXX */
222 int error;
223
224 /*
225 * Requires exclusive lock
226 */
227 parent = hammer2_inode_chain(xop->head.ip, clindex,
228 HAMMER2_RESOLVE_ALWAYS);
229 if (parent == NULL) {
230 kprintf("xop_nresolve: NULL parent\n");
231 chain = NULL;
232 error = EIO;
233 goto done;
234 }
235 name = xop->head.name;
236 name_len = xop->head.name_len;
237
238 /*
239 * Lookup the directory entry
240 */
241 lhc = hammer2_dirhash(name, name_len);
242 chain = hammer2_chain_lookup(&parent, &key_next,
243 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
244 &cache_index,
245 HAMMER2_LOOKUP_ALWAYS);
246 while (chain) {
247 ripdata = &chain->data->ipdata;
248 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
249 ripdata->meta.name_len == name_len &&
250 bcmp(ripdata->filename, name, name_len) == 0) {
251 break;
252 }
253 chain = hammer2_chain_next(&parent, chain, &key_next,
254 key_next,
255 lhc + HAMMER2_DIRHASH_LOMASK,
256 &cache_index,
257 HAMMER2_LOOKUP_ALWAYS);
258 }
259
260 /*
261 * If the directory entry is a HARDLINK pointer then obtain the
262 * underlying file type for the directory typing tests and delete
263 * the HARDLINK pointer chain permanently. The frontend is left
264 * responsible for handling nlinks on and deleting the actual inode.
265 *
266 * If the directory entry is the actual inode then use its type
267 * for the directory typing tests and delete the chain, permanency
268 * depends on whether the inode is open or not.
269 *
270 * Check directory typing and delete the entry. Note that
271 * nlinks adjustments are made on the real inode by the frontend,
272 * not here.
273 */
274 error = 0;
275 if (chain) {
276 int dopermanent = xop->dopermanent;
277
278 type = chain->data->ipdata.meta.type;
279 if (type == HAMMER2_OBJTYPE_HARDLINK) {
280 type = chain->data->ipdata.meta.target_type;
281 dopermanent |= HAMMER2_DELETE_PERMANENT;
282 }
283 if (type == HAMMER2_OBJTYPE_DIRECTORY &&
284 xop->isdir == 0) {
285 error = ENOTDIR;
286 } else
287 if (type != HAMMER2_OBJTYPE_DIRECTORY &&
288 xop->isdir >= 1) {
289 error = EISDIR;
290 } else {
291 hammer2_chain_delete(parent, chain, xop->dopermanent);
292 }
293 }
294
295 /*
296 * If the entry is a hardlink pointer, resolve it. If this is the
297 * last link, delete it. We aren't the frontend so we can't adjust
298 * nlinks.
299 */
300 if (chain) {
301 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
302 error = hammer2_chain_hardlink_find(
303 xop->head.ip,
304 &parent, &chain,
305 0);
306 if (chain &&
307 (int64_t)chain->data->ipdata.meta.nlinks <= 1) {
308 hammer2_chain_delete(parent, chain,
309 xop->dopermanent);
310 }
311 }
312 }
313
314 /*
315 * Chains passed to feed are expected to be locked shared.
316 */
317 if (chain) {
318 hammer2_chain_unlock(chain);
319 hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
320 HAMMER2_RESOLVE_SHARED);
321 }
322
323 /*
324 * We always return the hardlink target (the real inode) for
325 * further action.
326 */
327done:
328 hammer2_xop_feed(&xop->head, chain, clindex, error);
329 if (chain)
330 hammer2_chain_drop(chain);
331 if (parent) {
332 hammer2_chain_unlock(parent);
333 hammer2_chain_drop(parent);
334 }
335}
336
337/*
338 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
339 *
340 * Convert the target {dip,ip} to a hardlink target and replace
341 * the original namespace with a hardlink pointer.
342 */
343void
344hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
345{
346 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
347 hammer2_pfs_t *pmp;
348 hammer2_inode_data_t *wipdata;
349 hammer2_chain_t *parent;
350 hammer2_chain_t *chain;
351 hammer2_chain_t *tmp;
352 hammer2_inode_t *ip;
353 hammer2_key_t key_dummy;
354 int cache_index = -1;
355 int error;
356
357 /*
358 * We need the precise parent chain to issue the deletion.
359 */
360 ip = xop->head.ip2;
361 pmp = ip->pmp;
362 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
363 if (parent)
364 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
365 if (parent == NULL) {
366 chain = NULL;
367 error = EIO;
368 goto done;
369 }
370 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
371 if (chain == NULL) {
372 error = EIO;
373 goto done;
374 }
375 hammer2_chain_delete(parent, chain, 0);
376
377 /*
378 * Replace the namespace with a hardlink pointer if the chain being
379 * moved is not already a hardlink target.
380 */
381 if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
382 tmp = NULL;
383 error = hammer2_chain_create(&parent, &tmp, pmp,
384 chain->bref.key, 0,
385 HAMMER2_BREF_TYPE_INODE,
386 HAMMER2_INODE_BYTES,
387 0);
388 if (error)
389 goto done;
390 hammer2_chain_modify(tmp, 0);
391 wipdata = &tmp->data->ipdata;
392 bzero(wipdata, sizeof(*wipdata));
393 wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
394 wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
395 bcopy(chain->data->ipdata.filename, wipdata->filename,
396 chain->data->ipdata.meta.name_len);
397 wipdata->meta.target_type = chain->data->ipdata.meta.type;
398 wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
399 wipdata->meta.inum = ip->meta.inum;
400 wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
401 wipdata->meta.nlinks = 1;
402 wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
403
404 hammer2_chain_unlock(tmp);
405 hammer2_chain_drop(tmp);
406 }
407
408 hammer2_chain_unlock(parent);
409 hammer2_chain_drop(parent);
410
411 /*
412 * Ok, back to the deleted chain. We must reconnect this chain
413 * as a hardlink target to cdir (ip3).
414 *
415 * WARNING! Frontend assumes filename length is 18 bytes.
416 */
417 hammer2_chain_modify(chain, 0);
418 wipdata = &chain->data->ipdata;
419 ksnprintf(wipdata->filename, sizeof(wipdata->filename),
420 "0x%016jx", (intmax_t)ip->meta.inum);
421 wipdata->meta.name_len = strlen(wipdata->filename);
422 wipdata->meta.name_key = ip->meta.inum;
423
424 /*
425 * We must seek parent properly for the create.
426 */
427 parent = hammer2_inode_chain(xop->head.ip3, clindex,
428 HAMMER2_RESOLVE_ALWAYS);
429 if (parent == NULL) {
430 error = EIO;
431 goto done;
432 }
433 tmp = hammer2_chain_lookup(&parent, &key_dummy,
434 ip->meta.inum, ip->meta.inum,
435 &cache_index, 0);
436 if (tmp) {
437 hammer2_chain_unlock(tmp);
438 hammer2_chain_drop(tmp);
439 error = EEXIST;
440 goto done;
441 }
442 error = hammer2_chain_create(&parent, &chain, pmp,
443 wipdata->meta.name_key, 0,
444 HAMMER2_BREF_TYPE_INODE,
445 HAMMER2_INODE_BYTES,
446 0);
447 /*
448 * To avoid having to scan the collision space we can simply
449 * reuse the inode's original name_key. But ip->meta.name_key
450 * may have already been updated by the front-end, so use xop->lhc.
451 *
452 * (frontend is responsible for fixing up ip->pip).
453 */
454done:
455 hammer2_xop_feed(&xop->head, NULL, clindex, error);
456 if (parent) {
457 hammer2_chain_unlock(parent);
458 hammer2_chain_drop(parent);
459 }
460 if (chain) {
461 hammer2_chain_unlock(chain);
462 hammer2_chain_drop(chain);
463 }
464}
465
466/*
467 * Backend for hammer2_vop_nrename()
468 *
469 * This handles the final step of renaming, either renaming the
470 * actual inode or renaming the hardlink pointer.
471 */
472void
473hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
474{
475 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
476 hammer2_pfs_t *pmp;
477 hammer2_chain_t *parent;
478 hammer2_chain_t *chain;
479 hammer2_chain_t *tmp;
480 hammer2_inode_t *ip;
481 hammer2_key_t key_dummy;
482 int cache_index = -1;
483 int error;
484
485 /*
486 * We need the precise parent chain to issue the deletion.
487 *
488 * If this is not a hardlink target we can act on the inode,
489 * otherwise we have to locate the hardlink pointer.
490 */
491 ip = xop->head.ip2;
492 pmp = ip->pmp;
493 chain = NULL;
494
495 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
496 /*
497 * Find ip's direct parent chain.
498 */
499 parent = hammer2_inode_chain(ip, clindex,
500 HAMMER2_RESOLVE_ALWAYS);
501 if (parent)
502 hammer2_chain_getparent(&parent,
503 HAMMER2_RESOLVE_ALWAYS);
504 if (parent == NULL) {
505 error = EIO;
506 goto done;
507 }
508 chain = hammer2_inode_chain(ip, clindex,
509 HAMMER2_RESOLVE_ALWAYS);
510 if (chain == NULL) {
511 error = EIO;
512 goto done;
513 }
514 } else {
515 /*
516 * head.ip is fdip, do a namespace search.
517 */
518 const hammer2_inode_data_t *ripdata;
519 hammer2_key_t lhc;
520 hammer2_key_t key_next;
521 const char *name;
522 size_t name_len;
523
524 parent = hammer2_inode_chain(xop->head.ip, clindex,
525 HAMMER2_RESOLVE_ALWAYS |
526 HAMMER2_RESOLVE_SHARED);
527 if (parent == NULL) {
528 kprintf("xop_nrename: NULL parent\n");
529 error = EIO;
530 goto done;
531 }
532 name = xop->head.name;
533 name_len = xop->head.name_len;
534
535 /*
536 * Lookup the directory entry
537 */
538 lhc = hammer2_dirhash(name, name_len);
539 chain = hammer2_chain_lookup(&parent, &key_next,
540 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
541 &cache_index,
542 HAMMER2_LOOKUP_ALWAYS);
543 while (chain) {
544 ripdata = &chain->data->ipdata;
545 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
546 ripdata->meta.name_len == name_len &&
547 bcmp(ripdata->filename, name, name_len) == 0) {
548 break;
549 }
550 chain = hammer2_chain_next(&parent, chain, &key_next,
551 key_next,
552 lhc + HAMMER2_DIRHASH_LOMASK,
553 &cache_index,
554 HAMMER2_LOOKUP_ALWAYS);
555 }
556 }
557
558 /*
559 * Delete it, then create it in the new namespace.
560 */
561 hammer2_chain_delete(parent, chain, 0);
562 hammer2_chain_unlock(parent);
563 hammer2_chain_drop(parent);
564 parent = NULL; /* safety */
565
566
567 /*
568 * Ok, back to the deleted chain. We must reconnect this chain
569 * to tdir (ip3). The chain (a real inode or a hardlink pointer)
570 * is not otherwise modified.
571 *
572 * Frontend is expected to replicate the same inode meta data
573 * modifications.
574 *
575 * NOTE! This chain may not represent the actual inode, it
576 * can be a hardlink pointer.
577 *
578 * XXX in-inode parent directory specification?
579 */
580 if (chain->data->ipdata.meta.name_key != xop->lhc ||
581 xop->head.name_len != xop->head.name2_len ||
582 bcmp(xop->head.name, xop->head.name2, xop->head.name_len) != 0) {
583 hammer2_inode_data_t *wipdata;
584
585 hammer2_chain_modify(chain, 0);
586 wipdata = &chain->data->ipdata;
587
588 bzero(wipdata->filename, sizeof(wipdata->filename));
589 bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
590 wipdata->meta.name_key = xop->lhc;
591 wipdata->meta.name_len = xop->head.name2_len;
592 }
593
594 /*
595 * We must seek parent properly for the create.
596 */
597 parent = hammer2_inode_chain(xop->head.ip3, clindex,
598 HAMMER2_RESOLVE_ALWAYS);
599 if (parent == NULL) {
600 error = EIO;
601 goto done;
602 }
603 tmp = hammer2_chain_lookup(&parent, &key_dummy,
604 xop->lhc, xop->lhc,
605 &cache_index, 0);
606 if (tmp) {
607 hammer2_chain_unlock(tmp);
608 hammer2_chain_drop(tmp);
609 error = EEXIST;
610 goto done;
611 }
612
613 error = hammer2_chain_create(&parent, &chain, pmp,
614 xop->lhc, 0,
615 HAMMER2_BREF_TYPE_INODE,
616 HAMMER2_INODE_BYTES,
617 0);
618 /*
619 * (frontend is responsible for fixing up ip->pip).
620 */
621done:
622 hammer2_xop_feed(&xop->head, NULL, clindex, error);
623 if (parent) {
624 hammer2_chain_unlock(parent);
625 hammer2_chain_drop(parent);
626 }
627 if (chain) {
628 hammer2_chain_unlock(chain);
629 hammer2_chain_drop(chain);
630 }
631}
632
7026ada6 633/*
12ff971c
MD
634 * Directory collision resolver scan helper (backend, threaded).
635 *
636 * Used by the inode create code to locate an unused lhc.
7026ada6 637 */
c603b86b
MD
638void
639hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
7026ada6 640{
c603b86b
MD
641 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
642 hammer2_chain_t *parent;
643 hammer2_chain_t *chain;
644 hammer2_key_t key_next;
645 int cache_index = -1; /* XXX */
646 int error = 0;
7026ada6 647
c603b86b
MD
648 parent = hammer2_inode_chain(xop->head.ip, clindex,
649 HAMMER2_RESOLVE_ALWAYS |
650 HAMMER2_RESOLVE_SHARED);
651 if (parent == NULL) {
652 kprintf("xop_nresolve: NULL parent\n");
653 chain = NULL;
654 error = EIO;
7026ada6 655 goto done;
c603b86b 656 }
7026ada6
MD
657
658 /*
12ff971c
MD
659 * Lookup all possibly conflicting directory entries, the feed
660 * inherits the chain's lock so do not unlock it on the iteration.
7026ada6 661 */
c603b86b
MD
662 chain = hammer2_chain_lookup(&parent, &key_next,
663 xop->lhc,
664 xop->lhc + HAMMER2_DIRHASH_LOMASK,
665 &cache_index,
666 HAMMER2_LOOKUP_ALWAYS |
667 HAMMER2_LOOKUP_SHARED);
668 while (chain) {
669 error = hammer2_xop_feed(&xop->head, chain, clindex,
670 chain->error);
671 if (error) {
672 hammer2_chain_drop(chain);
673 chain = NULL; /* safety */
674 break;
675 }
676 chain = hammer2_chain_next(&parent, chain, &key_next,
677 key_next,
678 xop->lhc + HAMMER2_DIRHASH_LOMASK,
679 &cache_index,
680 HAMMER2_LOOKUP_ALWAYS |
12ff971c
MD
681 HAMMER2_LOOKUP_SHARED |
682 HAMMER2_LOOKUP_NOUNLOCK);
7026ada6
MD
683 }
684done:
c603b86b
MD
685 hammer2_xop_feed(&xop->head, NULL, clindex, error);
686 if (parent) {
687 hammer2_chain_unlock(parent);
688 hammer2_chain_drop(parent);
7026ada6 689 }
7026ada6 690}