buildkernel - Fix build issue w/libmd changes
[dragonfly.git] / sys / vfs / hammer2 / hammer2_xops.c
blob69619697fa72b4a33035a214a0b22c3a7f5b34d3
1 /*
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
11 * are met:
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.
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.
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>
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>
61 #include "hammer2.h"
64 * Determine if the specified directory is empty. Returns 0 on success.
66 * May return 0, ENOTDIR, or EAGAIN.
68 static
69 int
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;
75 int cache_index = -1;
76 int error;
78 error = 0;
79 chain = hammer2_chain_lookup_init(ochain, 0);
81 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
82 if (oparent)
83 hammer2_chain_unlock(oparent);
85 parent = NULL;
86 error = hammer2_chain_hardlink_find(&parent, &chain,
87 clindex, 0);
88 if (parent) {
89 hammer2_chain_unlock(parent);
90 hammer2_chain_drop(parent);
92 if (oparent) {
93 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
94 if (ochain->parent != oparent) {
95 if (chain) {
96 hammer2_chain_unlock(chain);
97 hammer2_chain_drop(chain);
99 kprintf("H2EAGAIN\n");
101 return EAGAIN;
106 parent = chain;
107 chain = NULL;
108 if (parent) {
109 chain = hammer2_chain_lookup(&parent, &key_next,
110 HAMMER2_DIRHASH_VISIBLE,
111 HAMMER2_KEY_MAX,
112 &cache_index, 0);
114 if (chain) {
115 error = ENOTEMPTY;
116 hammer2_chain_unlock(chain);
117 hammer2_chain_drop(chain);
118 } else {
119 error = 0;
121 hammer2_chain_lookup_done(parent);
123 return error;
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.
132 void
133 hammer2_xop_ipcluster(hammer2_xop_t *arg, int clindex)
135 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
136 hammer2_chain_t *chain;
137 int error;
139 chain = hammer2_inode_chain(xop->head.ip1, clindex,
140 HAMMER2_RESOLVE_ALWAYS |
141 HAMMER2_RESOLVE_SHARED);
142 if (chain)
143 error = chain->error;
144 else
145 error = EIO;
147 hammer2_xop_feed(&xop->head, chain, clindex, error);
148 if (chain) {
149 hammer2_chain_unlock(chain);
150 hammer2_chain_drop(chain);
155 * Backend for hammer2_vop_readdir()
157 void
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;
164 hammer2_key_t lkey;
165 int cache_index = -1;
166 int error = 0;
168 lkey = xop->lkey;
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");
181 goto done;
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);
190 if (chain == NULL) {
191 chain = hammer2_chain_lookup(&parent, &key_next,
192 lkey, HAMMER2_KEY_MAX,
193 &cache_index,
194 HAMMER2_LOOKUP_SHARED);
196 while (chain) {
197 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
198 if (error)
199 break;
200 chain = hammer2_chain_next(&parent, chain, &key_next,
201 key_next, HAMMER2_KEY_MAX,
202 &cache_index,
203 HAMMER2_LOOKUP_SHARED);
205 if (chain) {
206 hammer2_chain_unlock(chain);
207 hammer2_chain_drop(chain);
209 hammer2_chain_unlock(parent);
210 hammer2_chain_drop(parent);
211 done:
212 hammer2_xop_feed(&xop->head, NULL, clindex, error);
216 * Backend for hammer2_vop_nresolve()
218 void
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;
225 const char *name;
226 size_t name_len;
227 hammer2_key_t key_next;
228 hammer2_key_t lhc;
229 int cache_index = -1; /* XXX */
230 int error;
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");
237 chain = NULL;
238 error = EIO;
239 goto done;
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,
250 &cache_index,
251 HAMMER2_LOOKUP_ALWAYS |
252 HAMMER2_LOOKUP_SHARED);
253 while (chain) {
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) {
258 break;
260 chain = hammer2_chain_next(&parent, chain, &key_next,
261 key_next,
262 lhc + HAMMER2_DIRHASH_LOMASK,
263 &cache_index,
264 HAMMER2_LOOKUP_ALWAYS |
265 HAMMER2_LOOKUP_SHARED);
269 * If the entry is a hardlink pointer, resolve it.
271 error = 0;
272 if (chain) {
273 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
274 error = hammer2_chain_hardlink_find(&parent, &chain,
275 clindex,
276 HAMMER2_LOOKUP_SHARED);
279 done:
280 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
281 if (chain) {
282 hammer2_chain_unlock(chain);
283 hammer2_chain_drop(chain);
285 if (parent) {
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.
309 void
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;
316 const char *name;
317 size_t name_len;
318 hammer2_key_t key_next;
319 hammer2_key_t lhc;
320 int cache_index = -1; /* XXX */
321 int error;
323 again:
325 * Requires exclusive lock
327 parent = hammer2_inode_chain(xop->head.ip1, clindex,
328 HAMMER2_RESOLVE_ALWAYS);
329 chain = NULL;
330 if (parent == NULL) {
331 kprintf("xop_nresolve: NULL parent\n");
332 error = EIO;
333 goto done;
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,
344 &cache_index,
345 HAMMER2_LOOKUP_ALWAYS);
346 while (chain) {
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) {
351 break;
353 chain = hammer2_chain_next(&parent, chain, &key_next,
354 key_next,
355 lhc + HAMMER2_DIRHASH_LOMASK,
356 &cache_index,
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.
367 error = 0;
368 if (chain) {
369 int dopermanent = xop->dopermanent;
370 uint8_t type;
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);
404 goto again;
406 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
407 xop->isdir == 0) {
408 error = ENOTDIR;
409 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
410 xop->isdir >= 1) {
411 error = EISDIR;
412 } else {
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
429 * backend!).
431 if (chain &&
432 chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
433 int error2;
435 lhc = chain->data->ipdata.meta.inum;
437 error2 = hammer2_chain_hardlink_find(&parent, &chain,
438 clindex, 0);
439 if (error2) {
440 kprintf("hardlink_find: %016jx %p failed\n",
441 lhc, chain);
442 error2 = 0; /* silently ignore */
444 if (error == 0)
445 error = error2;
449 * Return the inode target for further action. Typically used by
450 * hammer2_inode_unlink_finisher().
452 done:
453 hammer2_xop_feed(&xop->head, chain, clindex, error);
454 if (chain) {
455 hammer2_chain_unlock(chain);
456 hammer2_chain_drop(chain);
457 chain = NULL;
459 if (parent) {
460 hammer2_chain_unlock(parent);
461 hammer2_chain_drop(parent);
462 parent = NULL;
466 #if 0
468 * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
470 * ip1 - fdip
471 * ip2 - ip
472 * ip3 - cdip
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.
482 void
483 hammer2_xop_nlink(hammer2_xop_t *arg, int clindex)
485 hammer2_xop_nlink_t *xop = &arg->xop_nlink;
486 hammer2_pfs_t *pmp;
487 hammer2_inode_data_t *wipdata;
488 hammer2_chain_t *parent;
489 hammer2_chain_t *chain;
490 hammer2_chain_t *tmp;
491 hammer2_inode_t *ip;
492 hammer2_key_t key_dummy;
493 int cache_index = -1;
494 int error;
495 int did_delete = 0;
498 * We need the precise parent chain to issue the deletion.
500 ip = xop->head.ip2;
501 pmp = ip->pmp;
502 parent = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
503 if (parent)
504 hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
505 if (parent == NULL) {
506 chain = NULL;
507 error = EIO;
508 goto done;
510 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
511 if (chain == NULL) {
512 error = EIO;
513 goto done;
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
520 * to cdir.
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);
526 did_delete = 1;
528 tmp = NULL;
529 error = hammer2_chain_create(&parent, &tmp,
530 pmp, HAMMER2_METH_DEFAULT,
531 chain->bref.key, 0,
532 HAMMER2_BREF_TYPE_INODE,
533 HAMMER2_INODE_BYTES,
534 xop->head.mtid, 0, 0);
535 if (error)
536 goto done;
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
556 * to cdir.
558 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
559 did_delete = 1;
560 } else {
562 * Deletion not necessary (just a nlinks update).
564 did_delete = 0;
567 hammer2_chain_unlock(parent);
568 hammer2_chain_drop(parent);
569 parent = NULL;
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.
577 if (did_delete) {
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) {
593 error = EIO;
594 goto done;
596 tmp = hammer2_chain_lookup(&parent, &key_dummy,
597 ip->meta.inum, ip->meta.inum,
598 &cache_index, 0);
599 if (tmp) {
600 hammer2_chain_unlock(tmp);
601 hammer2_chain_drop(tmp);
602 error = EEXIST;
603 goto done;
605 error = hammer2_chain_create(&parent, &chain,
606 pmp, HAMMER2_METH_DEFAULT,
607 wipdata->meta.name_key, 0,
608 HAMMER2_BREF_TYPE_INODE,
609 HAMMER2_INODE_BYTES,
610 xop->head.mtid, 0, 0);
611 } else {
612 error = 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.
628 done:
629 hammer2_xop_feed(&xop->head, NULL, clindex, error);
630 if (parent) {
631 hammer2_chain_unlock(parent);
632 hammer2_chain_drop(parent);
634 if (chain) {
635 hammer2_chain_unlock(chain);
636 hammer2_chain_drop(chain);
639 #endif
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.
647 void
648 hammer2_xop_nrename(hammer2_xop_t *arg, int clindex)
650 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
651 hammer2_pfs_t *pmp;
652 hammer2_chain_t *parent;
653 hammer2_chain_t *chain;
654 hammer2_chain_t *tmp;
655 hammer2_inode_t *ip;
656 hammer2_key_t key_dummy;
657 int cache_index = -1;
658 int error;
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.
666 ip = xop->head.ip2;
667 pmp = ip->pmp;
668 chain = NULL;
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);
676 if (parent)
677 hammer2_chain_getparent(&parent,
678 HAMMER2_RESOLVE_ALWAYS);
679 if (parent == NULL) {
680 error = EIO;
681 goto done;
683 chain = hammer2_inode_chain(ip, clindex,
684 HAMMER2_RESOLVE_ALWAYS);
685 if (chain == NULL) {
686 error = EIO;
687 goto done;
689 } else {
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;
695 hammer2_key_t lhc;
696 hammer2_key_t key_next;
697 const char *name;
698 size_t name_len;
700 parent = hammer2_inode_chain(xop->head.ip1, clindex,
701 HAMMER2_RESOLVE_ALWAYS);
702 if (parent == NULL) {
703 kprintf("xop_nrename: NULL parent\n");
704 error = EIO;
705 goto done;
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,
716 &cache_index,
717 HAMMER2_LOOKUP_ALWAYS);
718 while (chain) {
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) {
723 break;
725 chain = hammer2_chain_next(&parent, chain, &key_next,
726 key_next,
727 lhc + HAMMER2_DIRHASH_LOMASK,
728 &cache_index,
729 HAMMER2_LOOKUP_ALWAYS);
733 if (chain == NULL) {
734 /* XXX shouldn't happen, but does under fsstress */
735 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
736 xop->head.name1,
737 xop->head.name2);
738 error = ENOENT;
739 goto done;
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
756 * modifications.
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) {
791 error = EIO;
792 goto done;
794 tmp = hammer2_chain_lookup(&parent, &key_dummy,
795 xop->lhc, xop->lhc,
796 &cache_index, 0);
797 if (tmp) {
798 hammer2_chain_unlock(tmp);
799 hammer2_chain_drop(tmp);
800 error = EEXIST;
801 goto done;
804 error = hammer2_chain_create(&parent, &chain,
805 pmp, HAMMER2_METH_DEFAULT,
806 xop->lhc, 0,
807 HAMMER2_BREF_TYPE_INODE,
808 HAMMER2_INODE_BYTES,
809 xop->head.mtid, 0, 0);
810 done:
811 hammer2_xop_feed(&xop->head, NULL, clindex, error);
812 if (parent) {
813 hammer2_chain_unlock(parent);
814 hammer2_chain_drop(parent);
816 if (chain) {
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.
827 void
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 */
835 int error = 0;
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");
842 chain = NULL;
843 error = EIO;
844 goto done;
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,
852 xop->lhc,
853 xop->lhc + HAMMER2_DIRHASH_LOMASK,
854 &cache_index,
855 HAMMER2_LOOKUP_ALWAYS |
856 HAMMER2_LOOKUP_SHARED);
857 while (chain) {
858 error = hammer2_xop_feed(&xop->head, chain, clindex,
859 chain->error);
860 if (error) {
861 hammer2_chain_unlock(chain);
862 hammer2_chain_drop(chain);
863 chain = NULL; /* safety */
864 break;
866 chain = hammer2_chain_next(&parent, chain, &key_next,
867 key_next,
868 xop->lhc + HAMMER2_DIRHASH_LOMASK,
869 &cache_index,
870 HAMMER2_LOOKUP_ALWAYS |
871 HAMMER2_LOOKUP_SHARED);
873 done:
874 hammer2_xop_feed(&xop->head, NULL, clindex, error);
875 if (parent) {
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.
886 void
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 */
894 int error = 0;
896 parent = hammer2_inode_chain(xop->head.ip1, clindex,
897 HAMMER2_RESOLVE_ALWAYS |
898 HAMMER2_RESOLVE_SHARED);
899 chain = NULL;
900 if (parent == NULL) {
901 error = EIO;
902 goto done;
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,
910 xop->lhc, xop->lhc,
911 &cache_index,
912 HAMMER2_LOOKUP_ALWAYS |
913 HAMMER2_LOOKUP_SHARED);
914 if (chain)
915 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
916 else
917 hammer2_xop_feed(&xop->head, NULL, clindex, ENOENT);
919 done:
920 if (chain) {
921 hammer2_chain_unlock(chain);
922 hammer2_chain_drop(chain);
924 if (parent) {
925 hammer2_chain_unlock(parent);
926 hammer2_chain_drop(parent);
931 * Generic scan
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
936 * retained.
938 void
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;
946 int error = 0;
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,
959 xop->resolve_flags);
960 if (parent == NULL) {
961 kprintf("xop_readdir: NULL parent\n");
962 goto done;
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);
972 while (chain) {
973 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
974 if (error)
975 break;
976 chain = hammer2_chain_next(&parent, chain, &key_next,
977 key_next, xop->key_end,
978 &cache_index, xop->lookup_flags);
980 if (chain) {
981 hammer2_chain_unlock(chain);
982 hammer2_chain_drop(chain);
984 hammer2_chain_unlock(parent);
985 hammer2_chain_drop(parent);
986 done:
987 hammer2_xop_feed(&xop->head, NULL, clindex, error);