dhcpcd: update README.DRAGONFLY
[dragonfly.git] / sys / vfs / hammer2 / hammer2_xops.c
blob7560bee94646bb1ba161d983cbd40a2eef982755
1 /*
2 * Copyright (c) 2011-2018 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/proc.h>
48 #include <sys/mount.h>
50 #include "hammer2.h"
53 * Determine if the specified directory is empty.
55 * Returns 0 on success.
57 * Returns HAMMER_ERROR_EAGAIN if caller must re-lookup the entry and
58 * retry. (occurs if we race a ripup on oparent or ochain).
60 * Or returns a permanent HAMMER2_ERROR_* error mask.
62 * The caller must pass in an exclusively locked oparent and ochain. This
63 * function will handle the case where the chain is a directory entry or
64 * the inode itself. The original oparent,ochain will be locked upon return.
66 * This function will unlock the underlying oparent,ochain temporarily when
67 * doing an inode lookup to avoid deadlocks. The caller MUST handle the EAGAIN
68 * result as this means that oparent is no longer the parent of ochain, or
69 * that ochain was destroyed while it was unlocked.
71 static
72 int
73 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
75 hammer2_chain_t *parent;
76 hammer2_chain_t *chain;
77 hammer2_key_t key_next;
78 hammer2_key_t inum;
79 int error;
80 int didunlock;
82 error = 0;
83 didunlock = 0;
86 * Find the inode, set it up as a locked 'chain'. ochain can be the
87 * inode itself, or it can be a directory entry.
89 if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
90 inum = ochain->bref.embed.dirent.inum;
91 hammer2_chain_unlock(ochain);
92 hammer2_chain_unlock(oparent);
94 parent = NULL;
95 chain = NULL;
96 error = hammer2_chain_inode_find(ochain->pmp, inum,
97 clindex, 0,
98 &parent, &chain);
99 if (parent) {
100 hammer2_chain_unlock(parent);
101 hammer2_chain_drop(parent);
103 didunlock = 1;
104 } else {
106 * The directory entry *is* the directory inode
108 chain = hammer2_chain_lookup_init(ochain, 0);
112 * Determine if the directory is empty or not by checking its
113 * visible namespace (the area which contains directory entries).
115 if (error == 0) {
116 parent = chain;
117 chain = NULL;
118 if (parent) {
119 chain = hammer2_chain_lookup(&parent, &key_next,
120 HAMMER2_DIRHASH_VISIBLE,
121 HAMMER2_KEY_MAX,
122 &error, 0);
124 if (chain) {
125 error = HAMMER2_ERROR_ENOTEMPTY;
126 hammer2_chain_unlock(chain);
127 hammer2_chain_drop(chain);
129 hammer2_chain_lookup_done(parent);
130 } else {
131 if (chain) {
132 hammer2_chain_unlock(chain);
133 hammer2_chain_drop(chain);
134 chain = NULL; /* safety */
138 if (didunlock) {
139 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
140 hammer2_chain_lock(ochain, HAMMER2_RESOLVE_ALWAYS);
141 if ((ochain->flags & HAMMER2_CHAIN_DELETED) ||
142 (oparent->flags & HAMMER2_CHAIN_DELETED) ||
143 ochain->parent != oparent) {
144 kprintf("hammer2: debug: CHECKDIR inum %jd RETRY\n",
145 inum);
146 error = HAMMER2_ERROR_EAGAIN;
149 return error;
153 * Backend for hammer2_vfs_root()
155 * This is called when a newly mounted PFS has not yet synchronized
156 * to the inode_tid and modify_tid.
158 void
159 hammer2_xop_ipcluster(hammer2_xop_t *arg, void *scratch, int clindex)
161 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
162 hammer2_chain_t *chain;
163 int error;
165 chain = hammer2_inode_chain(xop->head.ip1, clindex,
166 HAMMER2_RESOLVE_ALWAYS |
167 HAMMER2_RESOLVE_SHARED);
168 if (chain)
169 error = chain->error;
170 else
171 error = HAMMER2_ERROR_EIO;
173 hammer2_xop_feed(&xop->head, chain, clindex, error);
174 if (chain) {
175 hammer2_chain_unlock(chain);
176 hammer2_chain_drop(chain);
181 * Backend for hammer2_vop_readdir()
183 void
184 hammer2_xop_readdir(hammer2_xop_t *arg, void *scratch, int clindex)
186 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
187 hammer2_chain_t *parent;
188 hammer2_chain_t *chain;
189 hammer2_key_t key_next;
190 hammer2_key_t lkey;
191 int error = 0;
193 lkey = xop->lkey;
194 if (hammer2_debug & 0x0020)
195 kprintf("xop_readdir: %p lkey=%016jx\n", xop, lkey);
198 * The inode's chain is the iterator. If we cannot acquire it our
199 * contribution ends here.
201 parent = hammer2_inode_chain(xop->head.ip1, clindex,
202 HAMMER2_RESOLVE_ALWAYS |
203 HAMMER2_RESOLVE_SHARED);
204 if (parent == NULL) {
205 kprintf("xop_readdir: NULL parent\n");
206 goto done;
210 * Directory scan [re]start and loop, the feed inherits the chain's
211 * lock so do not unlock it on the iteration.
213 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
214 &error, HAMMER2_LOOKUP_SHARED);
215 if (chain == NULL) {
216 chain = hammer2_chain_lookup(&parent, &key_next,
217 lkey, HAMMER2_KEY_MAX,
218 &error, HAMMER2_LOOKUP_SHARED);
220 while (chain) {
221 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
222 if (error)
223 goto break2;
224 chain = hammer2_chain_next(&parent, chain, &key_next,
225 key_next, HAMMER2_KEY_MAX,
226 &error, HAMMER2_LOOKUP_SHARED);
228 break2:
229 if (chain) {
230 hammer2_chain_unlock(chain);
231 hammer2_chain_drop(chain);
233 hammer2_chain_unlock(parent);
234 hammer2_chain_drop(parent);
235 done:
236 hammer2_xop_feed(&xop->head, NULL, clindex, error);
240 * Backend for hammer2_vop_nresolve()
242 void
243 hammer2_xop_nresolve(hammer2_xop_t *arg, void *scratch, int clindex)
245 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
246 hammer2_chain_t *parent;
247 hammer2_chain_t *chain;
248 const char *name;
249 size_t name_len;
250 hammer2_key_t key_next;
251 hammer2_key_t lhc;
252 int error;
254 parent = hammer2_inode_chain(xop->head.ip1, clindex,
255 HAMMER2_RESOLVE_ALWAYS |
256 HAMMER2_RESOLVE_SHARED);
257 if (parent == NULL) {
258 kprintf("xop_nresolve: NULL parent\n");
259 chain = NULL;
260 error = HAMMER2_ERROR_EIO;
261 goto done;
263 name = xop->head.name1;
264 name_len = xop->head.name1_len;
267 * Lookup the directory entry
269 lhc = hammer2_dirhash(name, name_len);
270 chain = hammer2_chain_lookup(&parent, &key_next,
271 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
272 &error,
273 HAMMER2_LOOKUP_ALWAYS |
274 HAMMER2_LOOKUP_SHARED);
275 while (chain) {
276 if (hammer2_chain_dirent_test(chain, name, name_len))
277 break;
278 chain = hammer2_chain_next(&parent, chain, &key_next,
279 key_next,
280 lhc + HAMMER2_DIRHASH_LOMASK,
281 &error,
282 HAMMER2_LOOKUP_ALWAYS |
283 HAMMER2_LOOKUP_SHARED);
287 * Locate the target inode for a directory entry
289 if (chain && chain->error == 0) {
290 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
291 lhc = chain->bref.embed.dirent.inum;
292 error = hammer2_chain_inode_find(chain->pmp,
293 lhc,
294 clindex,
295 HAMMER2_LOOKUP_SHARED,
296 &parent,
297 &chain);
299 } else if (chain && error == 0) {
300 error = chain->error;
302 done:
303 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
304 if (chain) {
305 hammer2_chain_unlock(chain);
306 hammer2_chain_drop(chain);
308 if (parent) {
309 hammer2_chain_unlock(parent);
310 hammer2_chain_drop(parent);
315 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
316 * backend for pfs_delete.
318 * This function locates and removes a directory entry, and will lookup
319 * and return the underlying inode. For directory entries the underlying
320 * inode is not removed. If the directory entry is the actual inode itself,
321 * it may be conditonally removed and returned.
323 * WARNING! Any target inode's nlinks may not be synchronized to the
324 * in-memory inode. The frontend's hammer2_inode_unlink_finisher()
325 * is responsible for the final disposition of the actual inode.
327 void
328 hammer2_xop_unlink(hammer2_xop_t *arg, void *scratch, int clindex)
330 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
331 hammer2_chain_t *parent;
332 hammer2_chain_t *chain;
333 const char *name;
334 size_t name_len;
335 hammer2_key_t key_next;
336 hammer2_key_t lhc;
337 int error;
339 again:
341 * Requires exclusive lock
343 parent = hammer2_inode_chain(xop->head.ip1, clindex,
344 HAMMER2_RESOLVE_ALWAYS);
345 chain = NULL;
346 if (parent == NULL) {
347 kprintf("xop_unlink: NULL parent\n");
348 error = HAMMER2_ERROR_EIO;
349 goto done;
351 name = xop->head.name1;
352 name_len = xop->head.name1_len;
355 * Lookup the directory entry
357 lhc = hammer2_dirhash(name, name_len);
358 chain = hammer2_chain_lookup(&parent, &key_next,
359 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
360 &error, HAMMER2_LOOKUP_ALWAYS);
361 while (chain) {
362 if (hammer2_chain_dirent_test(chain, name, name_len))
363 break;
364 chain = hammer2_chain_next(&parent, chain, &key_next,
365 key_next,
366 lhc + HAMMER2_DIRHASH_LOMASK,
367 &error, HAMMER2_LOOKUP_ALWAYS);
371 * The directory entry will either be a BREF_TYPE_DIRENT or a
372 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but
373 * must go by xop->dopermanent for BREF_TYPE_INODE.
375 * Note that the target chain's nlinks may not be synchronized with
376 * the in-memory hammer2_inode_t structure, so we don't try to do
377 * anything fancy here. The frontend deals with nlinks
378 * synchronization.
380 if (chain && chain->error == 0) {
381 int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
382 int doforce = xop->dopermanent & H2DOPERM_FORCE;
383 uint8_t type;
386 * If the directory entry is the actual inode then use its
387 * type for the directory typing tests, otherwise if it is
388 * a directory entry, pull the type field from the entry.
390 * Directory entries are always permanently deleted
391 * (because they aren't the actual inode).
393 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
394 type = chain->bref.embed.dirent.type;
395 dopermanent |= HAMMER2_DELETE_PERMANENT;
396 } else {
397 type = chain->data->ipdata.meta.type;
401 * Check directory typing and delete the entry. Note that
402 * nlinks adjustments are made on the real inode by the
403 * frontend, not here.
405 * Unfortunately, checkdirempty() may have to unlock (parent).
406 * If it no longer matches chain->parent after re-locking,
407 * EAGAIN is returned.
409 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
411 * If doforce then execute the operation even if
412 * the directory is not empty or errored. We
413 * ignore chain->error here, allowing an errored
414 * chain (aka directory entry) to still be deleted.
416 error = hammer2_chain_delete(parent, chain,
417 xop->head.mtid, dopermanent);
418 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
419 xop->isdir == 0) {
420 error = HAMMER2_ERROR_EISDIR;
421 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
422 (error = checkdirempty(parent, chain, clindex)) != 0) {
424 * error may be EAGAIN or ENOTEMPTY
426 if (error == HAMMER2_ERROR_EAGAIN) {
427 hammer2_chain_unlock(chain);
428 hammer2_chain_drop(chain);
429 hammer2_chain_unlock(parent);
430 hammer2_chain_drop(parent);
431 goto again;
433 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
434 xop->isdir >= 1) {
435 error = HAMMER2_ERROR_ENOTDIR;
436 } else {
438 * Delete the directory entry. chain might also
439 * be a directly-embedded inode.
441 * Allow the deletion to proceed even if the chain
442 * is errored. Give priority to error-on-delete over
443 * chain->error.
445 error = hammer2_chain_delete(parent, chain,
446 xop->head.mtid,
447 dopermanent);
448 if (error == 0)
449 error = chain->error;
451 } else {
452 if (chain && error == 0)
453 error = chain->error;
457 * If chain is a directory entry we must resolve it. We do not try
458 * to manipulate the contents as it might not be synchronized with
459 * the frontend hammer2_inode_t, nor do we try to lookup the
460 * frontend hammer2_inode_t here (we are the backend!).
462 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
463 (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
464 int error2;
466 lhc = chain->bref.embed.dirent.inum;
468 error2 = hammer2_chain_inode_find(chain->pmp, lhc,
469 clindex, 0,
470 &parent, &chain);
471 if (error2) {
472 kprintf("xop_unlink: %016jx %p failed\n",
473 lhc, chain);
474 error2 = 0; /* silently ignore */
476 if (error == 0)
477 error = error2;
481 * Return the inode target for further action. Typically used by
482 * hammer2_inode_unlink_finisher().
484 done:
485 hammer2_xop_feed(&xop->head, chain, clindex, error);
486 if (chain) {
487 hammer2_chain_unlock(chain);
488 hammer2_chain_drop(chain);
489 chain = NULL;
491 if (parent) {
492 hammer2_chain_unlock(parent);
493 hammer2_chain_drop(parent);
494 parent = NULL;
499 * Backend for hammer2_vop_nrename()
501 * This handles the backend rename operation. Typically this renames
502 * directory entries but can also be used to rename embedded inodes.
504 * NOTE! The frontend is responsible for updating the inode meta-data in
505 * the file being renamed and for decrementing the target-replaced
506 * inode's nlinks, if present.
508 void
509 hammer2_xop_nrename(hammer2_xop_t *arg, void *scratch, int clindex)
511 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
512 hammer2_pfs_t *pmp;
513 hammer2_chain_t *parent;
514 hammer2_chain_t *chain;
515 hammer2_chain_t *tmp;
516 hammer2_inode_t *ip;
517 hammer2_key_t key_next;
518 int error;
521 * If ip4 is non-NULL we must check to see if the entry being
522 * overwritten is a non-empty directory.
524 ip = xop->head.ip4;
525 if (ip) {
526 uint8_t type;
528 chain = hammer2_inode_chain(ip, clindex,
529 HAMMER2_RESOLVE_ALWAYS);
530 if (chain == NULL) {
531 error = HAMMER2_ERROR_EIO;
532 parent = NULL;
533 goto done;
535 type = chain->data->ipdata.meta.type;
536 if (type == HAMMER2_OBJTYPE_DIRECTORY &&
537 (error = checkdirempty(NULL, chain, clindex)) != 0)
539 KKASSERT(error != HAMMER2_ERROR_EAGAIN);
540 parent = NULL;
541 goto done;
543 hammer2_chain_unlock(chain);
544 hammer2_chain_drop(chain);
548 * We need the precise parent chain to issue the deletion.
550 * If this is a directory entry we must locate the underlying
551 * inode. If it is an embedded inode we can act directly on it.
553 ip = xop->head.ip2;
554 pmp = ip->pmp;
555 chain = NULL;
556 error = 0;
558 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
560 * Find ip's direct parent chain.
562 chain = hammer2_inode_chain(ip, clindex,
563 HAMMER2_RESOLVE_ALWAYS);
564 if (chain == NULL) {
565 error = HAMMER2_ERROR_EIO;
566 parent = NULL;
567 goto done;
569 if (ip->flags & HAMMER2_INODE_CREATING) {
570 parent = NULL;
571 } else {
572 parent = hammer2_chain_getparent(chain,
573 HAMMER2_RESOLVE_ALWAYS);
574 if (parent == NULL) {
575 error = HAMMER2_ERROR_EIO;
576 goto done;
579 } else {
581 * The directory entry for the head.ip1 inode
582 * is in fdip, do a namespace search.
584 hammer2_key_t lhc;
585 const char *name;
586 size_t name_len;
588 parent = hammer2_inode_chain(xop->head.ip1, clindex,
589 HAMMER2_RESOLVE_ALWAYS);
590 if (parent == NULL) {
591 kprintf("xop_nrename: NULL parent\n");
592 error = HAMMER2_ERROR_EIO;
593 goto done;
595 name = xop->head.name1;
596 name_len = xop->head.name1_len;
599 * Lookup the directory entry
601 lhc = hammer2_dirhash(name, name_len);
602 chain = hammer2_chain_lookup(&parent, &key_next,
603 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
604 &error, HAMMER2_LOOKUP_ALWAYS);
605 while (chain) {
606 if (hammer2_chain_dirent_test(chain, name, name_len))
607 break;
608 chain = hammer2_chain_next(&parent, chain, &key_next,
609 key_next,
610 lhc + HAMMER2_DIRHASH_LOMASK,
611 &error,
612 HAMMER2_LOOKUP_ALWAYS);
616 if (chain == NULL) {
617 /* XXX shouldn't happen, but does under fsstress */
618 kprintf("xop_nrename: \"%s\" -> \"%s\" ENOENT\n",
619 xop->head.name1,
620 xop->head.name2);
621 if (error == 0)
622 error = HAMMER2_ERROR_ENOENT;
623 goto done;
626 if (chain->error) {
627 error = chain->error;
628 goto done;
632 * Delete it, then create it in the new namespace.
634 * An error can occur if the chain being deleted requires
635 * modification and the media is full.
637 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
638 if (parent) {
639 hammer2_chain_unlock(parent);
640 hammer2_chain_drop(parent);
641 parent = NULL; /* safety */
642 } else {
643 kprintf("hammer2_xop_nrename() (debugging): parent was NULL\n");
644 error = EINVAL;
646 if (error)
647 goto done;
650 * Adjust fields in the deleted chain appropriate for the rename
651 * operation.
653 * NOTE! For embedded inodes, the frontend will officially replicate
654 * the field adjustments, but we also do it here to maintain
655 * consistency in case of a crash.
657 if (chain->bref.key != xop->lhc ||
658 xop->head.name1_len != xop->head.name2_len ||
659 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
660 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
661 hammer2_inode_data_t *wipdata;
663 error = hammer2_chain_modify(chain, xop->head.mtid,
664 0, 0);
665 if (error == 0) {
666 wipdata = &chain->data->ipdata;
668 bzero(wipdata->filename,
669 sizeof(wipdata->filename));
670 bcopy(xop->head.name2,
671 wipdata->filename,
672 xop->head.name2_len);
673 wipdata->meta.name_key = xop->lhc;
674 wipdata->meta.name_len = xop->head.name2_len;
677 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
678 if (xop->head.name2_len <=
679 sizeof(chain->bref.check.buf)) {
681 * Remove any related data buffer, we can
682 * embed the filename in the bref itself.
684 error = hammer2_chain_resize(
685 chain, xop->head.mtid, 0, 0, 0);
686 if (error == 0) {
687 error = hammer2_chain_modify(
688 chain, xop->head.mtid,
689 0, 0);
691 if (error == 0) {
692 bzero(chain->bref.check.buf,
693 sizeof(chain->bref.check.buf));
694 bcopy(xop->head.name2,
695 chain->bref.check.buf,
696 xop->head.name2_len);
698 } else {
700 * Associate a data buffer with the bref.
701 * Zero it for consistency. Note that the
702 * data buffer is not 64KB so use chain->bytes
703 * instead of sizeof().
705 error = hammer2_chain_resize(
706 chain, xop->head.mtid, 0,
707 hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
708 if (error == 0) {
709 error = hammer2_chain_modify(
710 chain, xop->head.mtid,
711 0, 0);
713 if (error == 0) {
714 bzero(chain->data->buf, chain->bytes);
715 bcopy(xop->head.name2,
716 chain->data->buf,
717 xop->head.name2_len);
720 if (error == 0) {
721 chain->bref.embed.dirent.namlen =
722 xop->head.name2_len;
728 * The frontend will replicate this operation and is the real final
729 * authority, but adjust the inode's iparent field too if the inode
730 * is embedded in the directory.
732 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
733 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
734 hammer2_inode_data_t *wipdata;
736 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
737 if (error == 0) {
738 wipdata = &chain->data->ipdata;
739 wipdata->meta.iparent = xop->head.ip3->meta.inum;
744 * Destroy any matching target(s) before creating the new entry.
745 * This will result in some ping-ponging of the directory key
746 * iterator but that is ok.
748 parent = hammer2_inode_chain(xop->head.ip3, clindex,
749 HAMMER2_RESOLVE_ALWAYS);
750 if (parent == NULL) {
751 error = HAMMER2_ERROR_EIO;
752 goto done;
756 * Delete all matching directory entries. That is, get rid of
757 * multiple duplicates if present, as a self-healing mechanism.
759 if (error == 0) {
760 tmp = hammer2_chain_lookup(&parent, &key_next,
761 xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
762 xop->lhc | HAMMER2_DIRHASH_LOMASK,
763 &error,
764 HAMMER2_LOOKUP_ALWAYS);
765 while (tmp) {
766 int e2;
767 if (hammer2_chain_dirent_test(tmp, xop->head.name2,
768 xop->head.name2_len)) {
769 e2 = hammer2_chain_delete(parent, tmp,
770 xop->head.mtid, 0);
771 if (error == 0 && e2)
772 error = e2;
774 tmp = hammer2_chain_next(&parent, tmp, &key_next,
775 key_next,
776 xop->lhc |
777 HAMMER2_DIRHASH_LOMASK,
778 &error,
779 HAMMER2_LOOKUP_ALWAYS);
782 if (error == 0) {
784 * A relookup is required before the create to properly
785 * position the parent chain.
787 tmp = hammer2_chain_lookup(&parent, &key_next,
788 xop->lhc, xop->lhc,
789 &error, 0);
790 KKASSERT(tmp == NULL);
791 error = hammer2_chain_create(&parent, &chain, NULL, pmp,
792 HAMMER2_METH_DEFAULT,
793 xop->lhc, 0,
794 HAMMER2_BREF_TYPE_INODE,
795 HAMMER2_INODE_BYTES,
796 xop->head.mtid, 0, 0);
798 done:
799 hammer2_xop_feed(&xop->head, NULL, clindex, error);
800 if (parent) {
801 hammer2_chain_unlock(parent);
802 hammer2_chain_drop(parent);
804 if (chain) {
805 hammer2_chain_unlock(chain);
806 hammer2_chain_drop(chain);
811 * Directory collision resolver scan helper (backend, threaded).
813 * Used by the inode create code to locate an unused lhc.
815 void
816 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex)
818 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
819 hammer2_chain_t *parent;
820 hammer2_chain_t *chain;
821 hammer2_key_t key_next;
822 int error = 0;
824 parent = hammer2_inode_chain(xop->head.ip1, clindex,
825 HAMMER2_RESOLVE_ALWAYS |
826 HAMMER2_RESOLVE_SHARED);
827 if (parent == NULL) {
828 kprintf("xop_scanlhc: NULL parent\n");
829 chain = NULL;
830 error = HAMMER2_ERROR_EIO;
831 goto done;
835 * Lookup all possibly conflicting directory entries, the feed
836 * inherits the chain's lock so do not unlock it on the iteration.
838 chain = hammer2_chain_lookup(&parent, &key_next,
839 xop->lhc,
840 xop->lhc + HAMMER2_DIRHASH_LOMASK,
841 &error,
842 HAMMER2_LOOKUP_ALWAYS |
843 HAMMER2_LOOKUP_SHARED);
844 while (chain) {
845 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
846 if (error) {
847 hammer2_chain_unlock(chain);
848 hammer2_chain_drop(chain);
849 chain = NULL; /* safety */
850 goto done;
852 chain = hammer2_chain_next(&parent, chain, &key_next,
853 key_next,
854 xop->lhc + HAMMER2_DIRHASH_LOMASK,
855 &error,
856 HAMMER2_LOOKUP_ALWAYS |
857 HAMMER2_LOOKUP_SHARED);
859 done:
860 hammer2_xop_feed(&xop->head, NULL, clindex, error);
861 if (parent) {
862 hammer2_chain_unlock(parent);
863 hammer2_chain_drop(parent);
868 * Generic lookup of a specific key.
870 void
871 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex)
873 hammer2_xop_lookup_t *xop = &arg->xop_lookup;
874 hammer2_chain_t *parent;
875 hammer2_chain_t *chain;
876 hammer2_key_t key_next;
877 int error = 0;
879 parent = hammer2_inode_chain(xop->head.ip1, clindex,
880 HAMMER2_RESOLVE_ALWAYS |
881 HAMMER2_RESOLVE_SHARED);
882 chain = NULL;
883 if (parent == NULL) {
884 error = HAMMER2_ERROR_EIO;
885 goto done;
889 * Lookup all possibly conflicting directory entries, the feed
890 * inherits the chain's lock so do not unlock it on the iteration.
892 chain = hammer2_chain_lookup(&parent, &key_next,
893 xop->lhc, xop->lhc,
894 &error,
895 HAMMER2_LOOKUP_ALWAYS |
896 HAMMER2_LOOKUP_SHARED);
897 if (error == 0) {
898 if (chain)
899 error = chain->error;
900 else
901 error = HAMMER2_ERROR_ENOENT;
903 hammer2_xop_feed(&xop->head, chain, clindex, error);
905 done:
906 if (chain) {
907 hammer2_chain_unlock(chain);
908 hammer2_chain_drop(chain);
910 if (parent) {
911 hammer2_chain_unlock(parent);
912 hammer2_chain_drop(parent);
916 void
917 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex)
919 hammer2_xop_lookup_t *xop = &arg->xop_lookup;
920 hammer2_chain_t *parent;
921 hammer2_chain_t *chain;
922 hammer2_key_t key_next;
923 int error = 0;
925 parent = hammer2_inode_chain(xop->head.ip1, clindex,
926 HAMMER2_RESOLVE_ALWAYS);
927 chain = NULL;
928 if (parent == NULL) {
929 error = HAMMER2_ERROR_EIO;
930 goto done;
934 * Lookup all possibly conflicting directory entries, the feed
935 * inherits the chain's lock so do not unlock it on the iteration.
937 chain = hammer2_chain_lookup(&parent, &key_next,
938 xop->lhc, xop->lhc,
939 &error,
940 HAMMER2_LOOKUP_NODATA);
941 if (error == 0) {
942 if (chain)
943 error = chain->error;
944 else
945 error = HAMMER2_ERROR_ENOENT;
947 if (chain) {
948 error = hammer2_chain_delete(parent, chain, xop->head.mtid,
949 HAMMER2_DELETE_PERMANENT);
951 hammer2_xop_feed(&xop->head, NULL, clindex, error);
953 done:
954 if (chain) {
955 hammer2_chain_unlock(chain);
956 hammer2_chain_drop(chain);
958 if (parent) {
959 hammer2_chain_unlock(parent);
960 hammer2_chain_drop(parent);
965 * Generic scan
967 * WARNING! Fed chains must be locked shared so ownership can be transfered
968 * and to prevent frontend/backend stalls that would occur with an
969 * exclusive lock. The shared lock also allows chain->data to be
970 * retained.
972 void
973 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex)
975 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
976 hammer2_chain_t *parent;
977 hammer2_chain_t *chain;
978 hammer2_key_t key_next;
979 int error = 0;
982 * Assert required flags.
984 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
985 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
988 * The inode's chain is the iterator. If we cannot acquire it our
989 * contribution ends here.
991 parent = hammer2_inode_chain(xop->head.ip1, clindex,
992 xop->resolve_flags);
993 if (parent == NULL) {
994 kprintf("xop_scanall: NULL parent\n");
995 goto done;
999 * Generic scan of exact records. Note that indirect blocks are
1000 * automatically recursed and will not be returned.
1002 chain = hammer2_chain_lookup(&parent, &key_next,
1003 xop->key_beg, xop->key_end,
1004 &error, xop->lookup_flags);
1005 while (chain) {
1006 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
1007 if (error)
1008 goto break2;
1009 chain = hammer2_chain_next(&parent, chain, &key_next,
1010 key_next, xop->key_end,
1011 &error, xop->lookup_flags);
1013 break2:
1014 if (chain) {
1015 hammer2_chain_unlock(chain);
1016 hammer2_chain_drop(chain);
1018 hammer2_chain_unlock(parent);
1019 hammer2_chain_drop(parent);
1020 done:
1021 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1024 /************************************************************************
1025 * INODE LAYER XOPS *
1026 ************************************************************************
1030 * Helper to create a directory entry.
1032 void
1033 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex)
1035 hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent;
1036 hammer2_chain_t *parent;
1037 hammer2_chain_t *chain;
1038 hammer2_key_t key_next;
1039 size_t data_len;
1040 int error;
1042 if (hammer2_debug & 0x0001)
1043 kprintf("xop_inode_mkdirent: lhc %016jx clindex %d\n",
1044 xop->lhc, clindex);
1046 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1047 HAMMER2_RESOLVE_ALWAYS);
1048 if (parent == NULL) {
1049 error = HAMMER2_ERROR_EIO;
1050 chain = NULL;
1051 goto fail;
1053 chain = hammer2_chain_lookup(&parent, &key_next,
1054 xop->lhc, xop->lhc,
1055 &error, 0);
1056 if (chain) {
1057 error = HAMMER2_ERROR_EEXIST;
1058 goto fail;
1062 * We may be able to embed the directory entry directly in the
1063 * blockref.
1065 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1066 data_len = 0;
1067 else
1068 data_len = HAMMER2_ALLOC_MIN;
1070 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1071 HAMMER2_METH_DEFAULT,
1072 xop->lhc, 0,
1073 HAMMER2_BREF_TYPE_DIRENT,
1074 data_len,
1075 xop->head.mtid, 0, 0);
1076 if (error == 0) {
1078 * WARNING: chain->data->buf is sized to chain->bytes,
1079 * do not use sizeof(chain->data->buf), which
1080 * will be much larger.
1082 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1083 if (error == 0) {
1084 chain->bref.embed.dirent = xop->dirent;
1085 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1086 bcopy(xop->head.name1, chain->bref.check.buf,
1087 xop->dirent.namlen);
1088 else
1089 bcopy(xop->head.name1, chain->data->buf,
1090 xop->dirent.namlen);
1093 fail:
1094 if (parent) {
1095 hammer2_chain_unlock(parent);
1096 hammer2_chain_drop(parent);
1098 hammer2_xop_feed(&xop->head, chain, clindex, error);
1099 if (chain) {
1100 hammer2_chain_unlock(chain);
1101 hammer2_chain_drop(chain);
1106 * Inode create helper (threaded, backend)
1108 * Used by ncreate, nmknod, nsymlink, nmkdir.
1109 * Used by nlink and rename to create HARDLINK pointers.
1111 * Frontend holds the parent directory ip locked exclusively. We
1112 * create the inode and feed the exclusively locked chain to the
1113 * frontend.
1115 void
1116 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex)
1118 hammer2_xop_create_t *xop = &arg->xop_create;
1119 hammer2_chain_t *parent;
1120 hammer2_chain_t *chain;
1121 hammer2_key_t key_next;
1122 int error;
1124 if (hammer2_debug & 0x0001)
1125 kprintf("xop_inode_create: lhc %016jx clindex %d\n",
1126 xop->lhc, clindex);
1128 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1129 HAMMER2_RESOLVE_ALWAYS);
1130 if (parent == NULL) {
1131 error = HAMMER2_ERROR_EIO;
1132 chain = NULL;
1133 goto fail;
1135 chain = hammer2_chain_lookup(&parent, &key_next,
1136 xop->lhc, xop->lhc,
1137 &error, 0);
1138 if (chain) {
1139 error = HAMMER2_ERROR_EEXIST;
1140 goto fail;
1143 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1144 HAMMER2_METH_DEFAULT,
1145 xop->lhc, 0,
1146 HAMMER2_BREF_TYPE_INODE,
1147 HAMMER2_INODE_BYTES,
1148 xop->head.mtid, 0, xop->flags);
1149 if (error == 0) {
1150 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1151 if (error == 0) {
1152 chain->data->ipdata.meta = xop->meta;
1153 if (xop->head.name1) {
1154 bcopy(xop->head.name1,
1155 chain->data->ipdata.filename,
1156 xop->head.name1_len);
1157 chain->data->ipdata.meta.name_len =
1158 xop->head.name1_len;
1160 chain->data->ipdata.meta.name_key = xop->lhc;
1163 fail:
1164 if (parent) {
1165 hammer2_chain_unlock(parent);
1166 hammer2_chain_drop(parent);
1168 hammer2_xop_feed(&xop->head, chain, clindex, error);
1169 if (chain) {
1170 hammer2_chain_unlock(chain);
1171 hammer2_chain_drop(chain);
1176 * Create inode as above but leave it detached from the hierarchy.
1178 void
1179 hammer2_xop_inode_create_det(hammer2_xop_t *arg, void *scratch, int clindex)
1181 hammer2_xop_create_t *xop = &arg->xop_create;
1182 hammer2_chain_t *parent;
1183 hammer2_chain_t *chain;
1184 hammer2_chain_t *null_parent;
1185 hammer2_key_t key_next;
1186 hammer2_inode_t *pip;
1187 hammer2_inode_t *iroot;
1188 int error;
1190 if (hammer2_debug & 0x0001)
1191 kprintf("xop_inode_create_det: lhc %016jx clindex %d\n",
1192 xop->lhc, clindex);
1194 pip = xop->head.ip1;
1195 iroot = pip->pmp->iroot;
1197 parent = hammer2_inode_chain(iroot, clindex, HAMMER2_RESOLVE_ALWAYS);
1199 if (parent == NULL) {
1200 error = HAMMER2_ERROR_EIO;
1201 chain = NULL;
1202 goto fail;
1204 chain = hammer2_chain_lookup(&parent, &key_next,
1205 xop->lhc, xop->lhc,
1206 &error, 0);
1207 if (chain) {
1208 error = HAMMER2_ERROR_EEXIST;
1209 goto fail;
1213 * Create as a detached chain with no parent. We must specify
1214 * methods
1216 null_parent = NULL;
1217 error = hammer2_chain_create(&null_parent, &chain,
1218 parent->hmp, pip->pmp,
1219 HAMMER2_ENC_COMP(pip->meta.comp_algo) +
1220 HAMMER2_ENC_CHECK(pip->meta.check_algo),
1221 xop->lhc, 0,
1222 HAMMER2_BREF_TYPE_INODE,
1223 HAMMER2_INODE_BYTES,
1224 xop->head.mtid, 0, xop->flags);
1225 if (error == 0) {
1226 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1227 if (error == 0) {
1228 chain->data->ipdata.meta = xop->meta;
1229 if (xop->head.name1) {
1230 bcopy(xop->head.name1,
1231 chain->data->ipdata.filename,
1232 xop->head.name1_len);
1233 chain->data->ipdata.meta.name_len =
1234 xop->head.name1_len;
1236 chain->data->ipdata.meta.name_key = xop->lhc;
1239 fail:
1240 if (parent) {
1241 hammer2_chain_unlock(parent);
1242 hammer2_chain_drop(parent);
1244 hammer2_xop_feed(&xop->head, chain, clindex, error);
1245 if (chain) {
1246 hammer2_chain_unlock(chain);
1247 hammer2_chain_drop(chain);
1252 * Take a detached chain and insert it into the topology
1254 void
1255 hammer2_xop_inode_create_ins(hammer2_xop_t *arg, void *scratch, int clindex)
1257 hammer2_xop_create_t *xop = &arg->xop_create;
1258 hammer2_chain_t *parent;
1259 hammer2_chain_t *chain;
1260 hammer2_key_t key_next;
1261 int error;
1263 if (hammer2_debug & 0x0001)
1264 kprintf("xop_inode_create_ins: lhc %016jx clindex %d\n",
1265 xop->lhc, clindex);
1268 * (parent) will be the insertion point for inode under iroot
1270 parent = hammer2_inode_chain(xop->head.ip1->pmp->iroot, clindex,
1271 HAMMER2_RESOLVE_ALWAYS);
1272 if (parent == NULL) {
1273 error = HAMMER2_ERROR_EIO;
1274 chain = NULL;
1275 goto fail;
1277 chain = hammer2_chain_lookup(&parent, &key_next,
1278 xop->lhc, xop->lhc,
1279 &error, 0);
1280 if (chain) {
1281 error = HAMMER2_ERROR_EEXIST;
1282 goto fail;
1286 * (chain) is the detached inode that is being inserted
1288 chain = hammer2_inode_chain(xop->head.ip1, clindex,
1289 HAMMER2_RESOLVE_ALWAYS);
1290 if (chain == NULL) {
1291 error = HAMMER2_ERROR_EIO;
1292 chain = NULL;
1293 goto fail;
1297 * This create call will insert the non-NULL chain into parent.
1298 * Most of the auxillary fields are ignored since the chain already
1299 * exists.
1301 error = hammer2_chain_create(&parent, &chain, NULL, xop->head.ip1->pmp,
1302 HAMMER2_METH_DEFAULT,
1303 xop->lhc, 0,
1304 HAMMER2_BREF_TYPE_INODE,
1305 HAMMER2_INODE_BYTES,
1306 xop->head.mtid, 0, xop->flags);
1307 #if 0
1308 if (error == 0) {
1309 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1310 if (error == 0) {
1311 chain->data->ipdata.meta = xop->meta;
1312 if (xop->head.name1) {
1313 bcopy(xop->head.name1,
1314 chain->data->ipdata.filename,
1315 xop->head.name1_len);
1316 chain->data->ipdata.meta.name_len =
1317 xop->head.name1_len;
1319 chain->data->ipdata.meta.name_key = xop->lhc;
1322 #endif
1323 fail:
1324 if (parent) {
1325 hammer2_chain_unlock(parent);
1326 hammer2_chain_drop(parent);
1328 hammer2_xop_feed(&xop->head, chain, clindex, error);
1329 if (chain) {
1330 hammer2_chain_unlock(chain);
1331 hammer2_chain_drop(chain);
1336 * Inode delete helper (backend, threaded)
1338 * Generally used by hammer2_run_sideq()
1340 void
1341 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex)
1343 hammer2_xop_destroy_t *xop = &arg->xop_destroy;
1344 hammer2_chain_t *parent;
1345 hammer2_chain_t *chain;
1346 hammer2_inode_t *ip;
1347 int error;
1350 * We need the precise parent chain to issue the deletion.
1352 ip = xop->head.ip1;
1354 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
1355 if (chain == NULL) {
1356 parent = NULL;
1357 error = HAMMER2_ERROR_EIO;
1358 goto done;
1361 if (ip->flags & HAMMER2_INODE_CREATING) {
1363 * Inode's chains are not linked into the media topology
1364 * because it is a new inode (which is now being destroyed).
1366 parent = NULL;
1367 } else {
1369 * Inode's chains are linked into the media topology
1371 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
1372 if (parent == NULL) {
1373 error = HAMMER2_ERROR_EIO;
1374 goto done;
1377 KKASSERT(chain->parent == parent);
1380 * We have the correct parent, we can issue the deletion.
1382 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
1383 error = 0;
1384 done:
1385 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1386 if (parent) {
1387 hammer2_chain_unlock(parent);
1388 hammer2_chain_drop(parent);
1390 if (chain) {
1391 hammer2_chain_unlock(chain);
1392 hammer2_chain_drop(chain);
1396 void
1397 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex)
1399 hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall;
1400 hammer2_chain_t *parent;
1401 hammer2_chain_t *chain;
1402 hammer2_key_t key_next;
1403 int error;
1406 * We need the precise parent chain to issue the deletion.
1408 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1409 HAMMER2_RESOLVE_ALWAYS);
1410 chain = NULL;
1411 if (parent == NULL) {
1412 error = 0;
1413 goto done;
1415 chain = hammer2_chain_lookup(&parent, &key_next,
1416 xop->key_beg, xop->key_end,
1417 &error, HAMMER2_LOOKUP_ALWAYS);
1418 while (chain) {
1419 hammer2_chain_delete(parent, chain,
1420 xop->head.mtid, HAMMER2_DELETE_PERMANENT);
1421 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
1422 /* depend on function to unlock the shared lock */
1423 chain = hammer2_chain_next(&parent, chain, &key_next,
1424 key_next, xop->key_end,
1425 &error,
1426 HAMMER2_LOOKUP_ALWAYS);
1428 done:
1429 if (error == 0)
1430 error = HAMMER2_ERROR_ENOENT;
1431 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1432 if (parent) {
1433 hammer2_chain_unlock(parent);
1434 hammer2_chain_drop(parent);
1436 if (chain) {
1437 hammer2_chain_unlock(chain);
1438 hammer2_chain_drop(chain);
1442 void
1443 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex)
1445 hammer2_xop_connect_t *xop = &arg->xop_connect;
1446 hammer2_inode_data_t *wipdata;
1447 hammer2_chain_t *parent;
1448 hammer2_chain_t *chain;
1449 hammer2_pfs_t *pmp;
1450 hammer2_key_t key_dummy;
1451 int error;
1454 * Get directory, then issue a lookup to prime the parent chain
1455 * for the create. The lookup is expected to fail.
1457 pmp = xop->head.ip1->pmp;
1458 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1459 HAMMER2_RESOLVE_ALWAYS);
1460 if (parent == NULL) {
1461 chain = NULL;
1462 error = HAMMER2_ERROR_EIO;
1463 goto fail;
1465 chain = hammer2_chain_lookup(&parent, &key_dummy,
1466 xop->lhc, xop->lhc,
1467 &error, 0);
1468 if (chain) {
1469 hammer2_chain_unlock(chain);
1470 hammer2_chain_drop(chain);
1471 chain = NULL;
1472 error = HAMMER2_ERROR_EEXIST;
1473 goto fail;
1475 if (error)
1476 goto fail;
1479 * Adjust the filename in the inode, set the name key.
1481 * NOTE: Frontend must also adjust ip2->meta on success, we can't
1482 * do it here.
1484 chain = hammer2_inode_chain(xop->head.ip2, clindex,
1485 HAMMER2_RESOLVE_ALWAYS);
1486 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1487 if (error)
1488 goto fail;
1490 wipdata = &chain->data->ipdata;
1492 hammer2_inode_modify(xop->head.ip2);
1493 if (xop->head.name1) {
1494 bzero(wipdata->filename, sizeof(wipdata->filename));
1495 bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len);
1496 wipdata->meta.name_len = xop->head.name1_len;
1498 wipdata->meta.name_key = xop->lhc;
1501 * Reconnect the chain to the new parent directory
1503 error = hammer2_chain_create(&parent, &chain, NULL, pmp,
1504 HAMMER2_METH_DEFAULT,
1505 xop->lhc, 0,
1506 HAMMER2_BREF_TYPE_INODE,
1507 HAMMER2_INODE_BYTES,
1508 xop->head.mtid, 0, 0);
1511 * Feed result back.
1513 fail:
1514 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1515 if (parent) {
1516 hammer2_chain_unlock(parent);
1517 hammer2_chain_drop(parent);
1519 if (chain) {
1520 hammer2_chain_unlock(chain);
1521 hammer2_chain_drop(chain);
1526 * Synchronize the in-memory inode with the chain. This does not flush
1527 * the chain to disk. Instead, it makes front-end inode changes visible
1528 * in the chain topology, thus visible to the backend. This is done in an
1529 * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled
1530 * manner inside the vfs_sync.
1532 void
1533 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex)
1535 hammer2_xop_fsync_t *xop = &arg->xop_fsync;
1536 hammer2_chain_t *parent;
1537 hammer2_chain_t *chain;
1538 int error;
1540 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1541 HAMMER2_RESOLVE_ALWAYS);
1542 chain = NULL;
1543 if (parent == NULL) {
1544 error = HAMMER2_ERROR_EIO;
1545 goto done;
1547 if (parent->error) {
1548 error = parent->error;
1549 goto done;
1552 error = 0;
1554 if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) {
1555 /* osize must be ignored */
1556 } else if (xop->meta.size < xop->osize) {
1558 * We must delete any chains beyond the EOF. The chain
1559 * straddling the EOF will be pending in the bioq.
1561 hammer2_key_t lbase;
1562 hammer2_key_t key_next;
1564 lbase = (xop->meta.size + HAMMER2_PBUFMASK64) &
1565 ~HAMMER2_PBUFMASK64;
1566 chain = hammer2_chain_lookup(&parent, &key_next,
1567 lbase, HAMMER2_KEY_MAX,
1568 &error,
1569 HAMMER2_LOOKUP_NODATA |
1570 HAMMER2_LOOKUP_NODIRECT);
1571 while (chain) {
1573 * Degenerate embedded case, nothing to loop on
1575 switch (chain->bref.type) {
1576 case HAMMER2_BREF_TYPE_DIRENT:
1577 case HAMMER2_BREF_TYPE_INODE:
1578 KKASSERT(0);
1579 break;
1580 case HAMMER2_BREF_TYPE_DATA:
1581 hammer2_chain_delete(parent, chain,
1582 xop->head.mtid,
1583 HAMMER2_DELETE_PERMANENT);
1584 break;
1586 chain = hammer2_chain_next(&parent, chain, &key_next,
1587 key_next, HAMMER2_KEY_MAX,
1588 &error,
1589 HAMMER2_LOOKUP_NODATA |
1590 HAMMER2_LOOKUP_NODIRECT);
1594 * Reset to point at inode for following code, if necessary.
1596 if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) {
1597 hammer2_chain_unlock(parent);
1598 hammer2_chain_drop(parent);
1599 parent = hammer2_inode_chain(xop->head.ip1,
1600 clindex,
1601 HAMMER2_RESOLVE_ALWAYS);
1602 kprintf("xop_inode_chain_sync: TRUNCATE RESET on '%s'\n",
1603 parent->data->ipdata.filename);
1608 * Sync the inode meta-data, potentially clear the blockset area
1609 * of direct data so it can be used for blockrefs.
1611 if (error == 0) {
1612 error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0);
1613 if (error == 0) {
1614 parent->data->ipdata.meta = xop->meta;
1615 if (xop->clear_directdata) {
1616 bzero(&parent->data->ipdata.u.blockset,
1617 sizeof(parent->data->ipdata.u.blockset));
1621 done:
1622 if (chain) {
1623 hammer2_chain_unlock(chain);
1624 hammer2_chain_drop(chain);
1626 if (parent) {
1627 hammer2_chain_unlock(parent);
1628 hammer2_chain_drop(parent);
1630 hammer2_xop_feed(&xop->head, NULL, clindex, error);