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
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.
66 * Returns 0 on success.
68 * Returns HAMMER_ERROR_EAGAIN if caller must re-lookup the entry and
69 * retry. (occurs if we race a ripup on oparent or ochain).
71 * Or returns a permanent HAMMER2_ERROR_* error mask.
73 * The caller must pass in an exclusively locked oparent and ochain. This
74 * function will handle the case where the chain is a directory entry or
75 * the inode itself. The original oparent,ochain will be locked upon return.
77 * This function will unlock the underlying oparent,ochain temporarily when
78 * doing an inode lookup to avoid deadlocks. The caller MUST handle the EAGAIN
79 * result as this means that oparent is no longer the parent of ochain, or
80 * that ochain was destroyed while it was unlocked.
84 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
86 hammer2_chain_t *parent;
87 hammer2_chain_t *chain;
88 hammer2_key_t key_next;
97 * Find the inode, set it up as a locked 'chain'. ochain can be the
98 * inode itself, or it can be a directory entry.
100 if (ochain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
101 inum = ochain->bref.embed.dirent.inum;
102 hammer2_chain_unlock(ochain);
103 hammer2_chain_unlock(oparent);
107 error = hammer2_chain_inode_find(ochain->pmp, inum,
111 hammer2_chain_unlock(parent);
112 hammer2_chain_drop(parent);
117 * The directory entry *is* the directory inode
119 chain = hammer2_chain_lookup_init(ochain, 0);
123 * Determine if the directory is empty or not by checking its
124 * visible namespace (the area which contains directory entries).
130 chain = hammer2_chain_lookup(&parent, &key_next,
131 HAMMER2_DIRHASH_VISIBLE,
136 error = HAMMER2_ERROR_ENOTEMPTY;
137 hammer2_chain_unlock(chain);
138 hammer2_chain_drop(chain);
140 hammer2_chain_lookup_done(parent);
144 hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
145 hammer2_chain_lock(ochain, HAMMER2_RESOLVE_ALWAYS);
146 if ((ochain->flags & HAMMER2_CHAIN_DELETED) ||
147 (oparent->flags & HAMMER2_CHAIN_DELETED) ||
148 ochain->parent != oparent) {
149 kprintf("hammer2: debug: CHECKDIR inum %jd RETRY\n",
151 error = HAMMER2_ERROR_EAGAIN;
158 * Backend for hammer2_vfs_root()
160 * This is called when a newly mounted PFS has not yet synchronized
161 * to the inode_tid and modify_tid.
164 hammer2_xop_ipcluster(hammer2_xop_t *arg, void *scratch, int clindex)
166 hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
167 hammer2_chain_t *chain;
170 chain = hammer2_inode_chain(xop->head.ip1, clindex,
171 HAMMER2_RESOLVE_ALWAYS |
172 HAMMER2_RESOLVE_SHARED);
174 error = chain->error;
176 error = HAMMER2_ERROR_EIO;
178 hammer2_xop_feed(&xop->head, chain, clindex, error);
180 hammer2_chain_unlock(chain);
181 hammer2_chain_drop(chain);
186 * Backend for hammer2_vop_readdir()
189 hammer2_xop_readdir(hammer2_xop_t *arg, void *scratch, int clindex)
191 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
192 hammer2_chain_t *parent;
193 hammer2_chain_t *chain;
194 hammer2_key_t key_next;
199 if (hammer2_debug & 0x0020)
200 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
203 * The inode's chain is the iterator. If we cannot acquire it our
204 * contribution ends here.
206 parent = hammer2_inode_chain(xop->head.ip1, clindex,
207 HAMMER2_RESOLVE_ALWAYS |
208 HAMMER2_RESOLVE_SHARED);
209 if (parent == NULL) {
210 kprintf("xop_readdir: NULL parent\n");
215 * Directory scan [re]start and loop, the feed inherits the chain's
216 * lock so do not unlock it on the iteration.
218 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
219 &error, HAMMER2_LOOKUP_SHARED);
221 chain = hammer2_chain_lookup(&parent, &key_next,
222 lkey, HAMMER2_KEY_MAX,
223 &error, HAMMER2_LOOKUP_SHARED);
226 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
229 chain = hammer2_chain_next(&parent, chain, &key_next,
230 key_next, HAMMER2_KEY_MAX,
231 &error, HAMMER2_LOOKUP_SHARED);
235 hammer2_chain_unlock(chain);
236 hammer2_chain_drop(chain);
238 hammer2_chain_unlock(parent);
239 hammer2_chain_drop(parent);
241 hammer2_xop_feed(&xop->head, NULL, clindex, error);
245 * Backend for hammer2_vop_nresolve()
248 hammer2_xop_nresolve(hammer2_xop_t *arg, void *scratch, int clindex)
250 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
251 hammer2_chain_t *parent;
252 hammer2_chain_t *chain;
255 hammer2_key_t key_next;
259 parent = hammer2_inode_chain(xop->head.ip1, clindex,
260 HAMMER2_RESOLVE_ALWAYS |
261 HAMMER2_RESOLVE_SHARED);
262 if (parent == NULL) {
263 kprintf("xop_nresolve: NULL parent\n");
265 error = HAMMER2_ERROR_EIO;
268 name = xop->head.name1;
269 name_len = xop->head.name1_len;
272 * Lookup the directory entry
274 lhc = hammer2_dirhash(name, name_len);
275 chain = hammer2_chain_lookup(&parent, &key_next,
276 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
278 HAMMER2_LOOKUP_ALWAYS |
279 HAMMER2_LOOKUP_SHARED);
281 if (hammer2_chain_dirent_test(chain, name, name_len))
283 chain = hammer2_chain_next(&parent, chain, &key_next,
285 lhc + HAMMER2_DIRHASH_LOMASK,
287 HAMMER2_LOOKUP_ALWAYS |
288 HAMMER2_LOOKUP_SHARED);
292 * If the entry is a hardlink pointer, resolve it.
294 if (chain && chain->error == 0) {
295 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
296 lhc = chain->bref.embed.dirent.inum;
297 error = hammer2_chain_inode_find(chain->pmp,
300 HAMMER2_LOOKUP_SHARED,
304 } else if (chain && error == 0) {
305 error = chain->error;
308 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
310 hammer2_chain_unlock(chain);
311 hammer2_chain_drop(chain);
314 hammer2_chain_unlock(parent);
315 hammer2_chain_drop(parent);
320 * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
321 * backend for pfs_delete.
323 * This function locates and removes a directory entry, and will lookup
324 * and return the underlying inode. For directory entries the underlying
325 * inode is not removed. If the directory entry is the actual inode itself,
326 * it may be conditonally removed and returned.
328 * WARNING! Any target inode's nlinks may not be synchronized to the
329 * in-memory inode. The frontend's hammer2_inode_unlink_finisher()
330 * is responsible for the final disposition of the actual inode.
333 hammer2_xop_unlink(hammer2_xop_t *arg, void *scratch, int clindex)
335 hammer2_xop_unlink_t *xop = &arg->xop_unlink;
336 hammer2_chain_t *parent;
337 hammer2_chain_t *chain;
340 hammer2_key_t key_next;
346 * Requires exclusive lock
348 parent = hammer2_inode_chain(xop->head.ip1, clindex,
349 HAMMER2_RESOLVE_ALWAYS);
351 if (parent == NULL) {
352 kprintf("xop_nresolve: NULL parent\n");
353 error = HAMMER2_ERROR_EIO;
356 name = xop->head.name1;
357 name_len = xop->head.name1_len;
360 * Lookup the directory entry
362 lhc = hammer2_dirhash(name, name_len);
363 chain = hammer2_chain_lookup(&parent, &key_next,
364 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
365 &error, HAMMER2_LOOKUP_ALWAYS);
367 if (hammer2_chain_dirent_test(chain, name, name_len))
369 chain = hammer2_chain_next(&parent, chain, &key_next,
371 lhc + HAMMER2_DIRHASH_LOMASK,
372 &error, HAMMER2_LOOKUP_ALWAYS);
376 * The directory entry will either be a BREF_TYPE_DIRENT or a
377 * BREF_TYPE_INODE. We always permanently delete DIRENTs, but
378 * must go by xop->dopermanent for BREF_TYPE_INODE.
380 * Note that the target chain's nlinks may not be synchronized with
381 * the in-memory hammer2_inode_t structure, so we don't try to do
382 * anything fancy here. The frontend deals with nlinks
385 if (chain && chain->error == 0) {
386 int dopermanent = xop->dopermanent & H2DOPERM_PERMANENT;
387 int doforce = xop->dopermanent & H2DOPERM_FORCE;
391 * If the directory entry is the actual inode then use its
392 * type for the directory typing tests, otherwise if it is
393 * a directory entry, pull the type field from the entry.
395 * Directory entries are always permanently deleted
396 * (because they aren't the actual inode).
398 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
399 type = chain->bref.embed.dirent.type;
400 dopermanent |= HAMMER2_DELETE_PERMANENT;
402 type = chain->data->ipdata.meta.type;
406 * Check directory typing and delete the entry. Note that
407 * nlinks adjustments are made on the real inode by the
408 * frontend, not here.
410 * Unfortunately, checkdirempty() may have to unlock (parent).
411 * If it no longer matches chain->parent after re-locking,
412 * EAGAIN is returned.
414 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
416 * If doforce then execute the operation even if
417 * the directory is not empty or errored. We
418 * ignore chain->error here, allowing an errored
419 * chain (aka directory entry) to still be deleted.
421 error = hammer2_chain_delete(parent, chain,
422 xop->head.mtid, dopermanent);
423 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
424 (error = checkdirempty(parent, chain, clindex)) != 0) {
426 * error may be EAGAIN or ENOTEMPTY
428 if (error == HAMMER2_ERROR_EAGAIN) {
429 hammer2_chain_unlock(chain);
430 hammer2_chain_drop(chain);
431 hammer2_chain_unlock(parent);
432 hammer2_chain_drop(parent);
435 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
437 error = HAMMER2_ERROR_ENOTDIR;
438 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
440 error = HAMMER2_ERROR_EISDIR;
443 * Delete the directory entry. chain might also
444 * be a directly-embedded inode.
446 * Allow the deletion to proceed even if the chain
447 * is errored. Give priority to error-on-delete over
450 error = hammer2_chain_delete(parent, chain,
454 error = chain->error;
457 if (chain && error == 0)
458 error = chain->error;
462 * If chain is a directory entry we must resolve it. We do not try
463 * to manipulate the contents as it might not be synchronized with
464 * the frontend hammer2_inode_t, nor do we try to lookup the
465 * frontend hammer2_inode_t here (we are the backend!).
467 if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT &&
468 (xop->dopermanent & H2DOPERM_IGNINO) == 0) {
471 lhc = chain->bref.embed.dirent.inum;
473 error2 = hammer2_chain_inode_find(chain->pmp, lhc,
477 kprintf("inode_find: %016jx %p failed\n",
479 error2 = 0; /* silently ignore */
486 * Return the inode target for further action. Typically used by
487 * hammer2_inode_unlink_finisher().
490 hammer2_xop_feed(&xop->head, chain, clindex, error);
492 hammer2_chain_unlock(chain);
493 hammer2_chain_drop(chain);
497 hammer2_chain_unlock(parent);
498 hammer2_chain_drop(parent);
504 * Backend for hammer2_vop_nrename()
506 * This handles the backend rename operation. Typically this renames
507 * directory entries but can also be used to rename embedded inodes.
509 * NOTE! The frontend is responsible for updating the inode meta-data in
510 * the file being renamed and for decrementing the target-replaced
511 * inode's nlinks, if present.
514 hammer2_xop_nrename(hammer2_xop_t *arg, void *scratch, int clindex)
516 hammer2_xop_nrename_t *xop = &arg->xop_nrename;
518 hammer2_chain_t *parent;
519 hammer2_chain_t *chain;
520 hammer2_chain_t *tmp;
522 hammer2_key_t key_next;
526 * We need the precise parent chain to issue the deletion.
528 * If this is a directory entry we must locate the underlying
529 * inode. If it is an embedded inode we can act directly on it.
536 if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
538 * Find ip's direct parent chain.
540 chain = hammer2_inode_chain(ip, clindex,
541 HAMMER2_RESOLVE_ALWAYS);
543 error = HAMMER2_ERROR_EIO;
547 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
548 if (parent == NULL) {
549 error = HAMMER2_ERROR_EIO;
554 * The directory entry for the head.ip1 inode
555 * is in fdip, do a namespace search.
561 parent = hammer2_inode_chain(xop->head.ip1, clindex,
562 HAMMER2_RESOLVE_ALWAYS);
563 if (parent == NULL) {
564 kprintf("xop_nrename: NULL parent\n");
565 error = HAMMER2_ERROR_EIO;
568 name = xop->head.name1;
569 name_len = xop->head.name1_len;
572 * Lookup the directory entry
574 lhc = hammer2_dirhash(name, name_len);
575 chain = hammer2_chain_lookup(&parent, &key_next,
576 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
577 &error, HAMMER2_LOOKUP_ALWAYS);
579 if (hammer2_chain_dirent_test(chain, name, name_len))
581 chain = hammer2_chain_next(&parent, chain, &key_next,
583 lhc + HAMMER2_DIRHASH_LOMASK,
585 HAMMER2_LOOKUP_ALWAYS);
590 /* XXX shouldn't happen, but does under fsstress */
591 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\" ENOENT\n",
595 error = HAMMER2_ERROR_ENOENT;
600 error = chain->error;
605 * Delete it, then create it in the new namespace.
607 * An error can occur if the chain being deleted requires
608 * modification and the media is full.
610 error = hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
611 hammer2_chain_unlock(parent);
612 hammer2_chain_drop(parent);
613 parent = NULL; /* safety */
618 * Adjust fields in the deleted chain appropriate for the rename
621 * NOTE! For embedded inodes, the frontend will officially replicate
622 * the field adjustments, but we also do it here to maintain
623 * consistency in case of a crash.
625 if (chain->bref.key != xop->lhc ||
626 xop->head.name1_len != xop->head.name2_len ||
627 bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
628 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
629 hammer2_inode_data_t *wipdata;
631 error = hammer2_chain_modify(chain, xop->head.mtid,
634 wipdata = &chain->data->ipdata;
636 bzero(wipdata->filename,
637 sizeof(wipdata->filename));
638 bcopy(xop->head.name2,
640 xop->head.name2_len);
641 wipdata->meta.name_key = xop->lhc;
642 wipdata->meta.name_len = xop->head.name2_len;
645 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
646 if (xop->head.name2_len <=
647 sizeof(chain->bref.check.buf)) {
649 * Remove any related data buffer, we can
650 * embed the filename in the bref itself.
652 error = hammer2_chain_resize(
653 chain, xop->head.mtid, 0, 0, 0);
655 error = hammer2_chain_modify(
656 chain, xop->head.mtid,
660 bzero(chain->bref.check.buf,
661 sizeof(chain->bref.check.buf));
662 bcopy(xop->head.name2,
663 chain->bref.check.buf,
664 xop->head.name2_len);
668 * Associate a data buffer with the bref.
669 * Zero it for consistency. Note that the
670 * data buffer is not 64KB so use chain->bytes
671 * instead of sizeof().
673 error = hammer2_chain_resize(
674 chain, xop->head.mtid, 0,
675 hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
677 error = hammer2_chain_modify(
678 chain, xop->head.mtid,
682 bzero(chain->data->buf, chain->bytes);
683 bcopy(xop->head.name2,
685 xop->head.name2_len);
689 chain->bref.embed.dirent.namlen =
696 * The frontend will replicate this operation and is the real final
697 * authority, but adjust the inode's iparent field too if the inode
698 * is embedded in the directory.
700 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
701 chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
702 hammer2_inode_data_t *wipdata;
704 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
706 wipdata = &chain->data->ipdata;
707 wipdata->meta.iparent = xop->head.ip3->meta.inum;
712 * Destroy any matching target(s) before creating the new entry.
713 * This will result in some ping-ponging of the directory key
714 * iterator but that is ok.
716 parent = hammer2_inode_chain(xop->head.ip3, clindex,
717 HAMMER2_RESOLVE_ALWAYS);
718 if (parent == NULL) {
719 error = HAMMER2_ERROR_EIO;
724 * Delete all matching directory entries. That is, get rid of
725 * multiple duplicates if present, as a self-healing mechanism.
728 tmp = hammer2_chain_lookup(&parent, &key_next,
729 xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
730 xop->lhc | HAMMER2_DIRHASH_LOMASK,
732 HAMMER2_LOOKUP_ALWAYS);
735 if (hammer2_chain_dirent_test(tmp, xop->head.name2,
736 xop->head.name2_len)) {
737 e2 = hammer2_chain_delete(parent, tmp,
739 if (error == 0 && e2)
742 tmp = hammer2_chain_next(&parent, tmp, &key_next,
745 HAMMER2_DIRHASH_LOMASK,
747 HAMMER2_LOOKUP_ALWAYS);
752 * A relookup is required before the create to properly
753 * position the parent chain.
755 tmp = hammer2_chain_lookup(&parent, &key_next,
758 KKASSERT(tmp == NULL);
759 error = hammer2_chain_create(&parent, &chain,
760 pmp, HAMMER2_METH_DEFAULT,
762 HAMMER2_BREF_TYPE_INODE,
764 xop->head.mtid, 0, 0);
767 hammer2_xop_feed(&xop->head, NULL, clindex, error);
769 hammer2_chain_unlock(parent);
770 hammer2_chain_drop(parent);
773 hammer2_chain_unlock(chain);
774 hammer2_chain_drop(chain);
779 * Directory collision resolver scan helper (backend, threaded).
781 * Used by the inode create code to locate an unused lhc.
784 hammer2_xop_scanlhc(hammer2_xop_t *arg, void *scratch, int clindex)
786 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
787 hammer2_chain_t *parent;
788 hammer2_chain_t *chain;
789 hammer2_key_t key_next;
792 parent = hammer2_inode_chain(xop->head.ip1, clindex,
793 HAMMER2_RESOLVE_ALWAYS |
794 HAMMER2_RESOLVE_SHARED);
795 if (parent == NULL) {
796 kprintf("xop_nresolve: NULL parent\n");
798 error = HAMMER2_ERROR_EIO;
803 * Lookup all possibly conflicting directory entries, the feed
804 * inherits the chain's lock so do not unlock it on the iteration.
806 chain = hammer2_chain_lookup(&parent, &key_next,
808 xop->lhc + HAMMER2_DIRHASH_LOMASK,
810 HAMMER2_LOOKUP_ALWAYS |
811 HAMMER2_LOOKUP_SHARED);
813 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
815 hammer2_chain_unlock(chain);
816 hammer2_chain_drop(chain);
817 chain = NULL; /* safety */
820 chain = hammer2_chain_next(&parent, chain, &key_next,
822 xop->lhc + HAMMER2_DIRHASH_LOMASK,
824 HAMMER2_LOOKUP_ALWAYS |
825 HAMMER2_LOOKUP_SHARED);
828 hammer2_xop_feed(&xop->head, NULL, clindex, error);
830 hammer2_chain_unlock(parent);
831 hammer2_chain_drop(parent);
836 * Generic lookup of a specific key.
839 hammer2_xop_lookup(hammer2_xop_t *arg, void *scratch, int clindex)
841 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
842 hammer2_chain_t *parent;
843 hammer2_chain_t *chain;
844 hammer2_key_t key_next;
847 parent = hammer2_inode_chain(xop->head.ip1, clindex,
848 HAMMER2_RESOLVE_ALWAYS |
849 HAMMER2_RESOLVE_SHARED);
851 if (parent == NULL) {
852 error = HAMMER2_ERROR_EIO;
857 * Lookup all possibly conflicting directory entries, the feed
858 * inherits the chain's lock so do not unlock it on the iteration.
860 chain = hammer2_chain_lookup(&parent, &key_next,
863 HAMMER2_LOOKUP_ALWAYS |
864 HAMMER2_LOOKUP_SHARED);
867 error = chain->error;
869 error = HAMMER2_ERROR_ENOENT;
871 hammer2_xop_feed(&xop->head, chain, clindex, error);
875 hammer2_chain_unlock(chain);
876 hammer2_chain_drop(chain);
879 hammer2_chain_unlock(parent);
880 hammer2_chain_drop(parent);
885 hammer2_xop_delete(hammer2_xop_t *arg, void *scratch, int clindex)
887 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
888 hammer2_chain_t *parent;
889 hammer2_chain_t *chain;
890 hammer2_key_t key_next;
893 parent = hammer2_inode_chain(xop->head.ip1, clindex,
894 HAMMER2_RESOLVE_ALWAYS);
896 if (parent == NULL) {
897 error = HAMMER2_ERROR_EIO;
902 * Lookup all possibly conflicting directory entries, the feed
903 * inherits the chain's lock so do not unlock it on the iteration.
905 chain = hammer2_chain_lookup(&parent, &key_next,
908 HAMMER2_LOOKUP_NODATA);
911 error = chain->error;
913 error = HAMMER2_ERROR_ENOENT;
916 error = hammer2_chain_delete(parent, chain, xop->head.mtid,
917 HAMMER2_DELETE_PERMANENT);
919 hammer2_xop_feed(&xop->head, NULL, clindex, error);
923 hammer2_chain_unlock(chain);
924 hammer2_chain_drop(chain);
927 hammer2_chain_unlock(parent);
928 hammer2_chain_drop(parent);
935 * WARNING! Fed chains must be locked shared so ownership can be transfered
936 * and to prevent frontend/backend stalls that would occur with an
937 * exclusive lock. The shared lock also allows chain->data to be
941 hammer2_xop_scanall(hammer2_xop_t *arg, void *scratch, int clindex)
943 hammer2_xop_scanall_t *xop = &arg->xop_scanall;
944 hammer2_chain_t *parent;
945 hammer2_chain_t *chain;
946 hammer2_key_t key_next;
950 * Assert required flags.
952 KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
953 KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
956 * The inode's chain is the iterator. If we cannot acquire it our
957 * contribution ends here.
959 parent = hammer2_inode_chain(xop->head.ip1, clindex,
961 if (parent == NULL) {
962 kprintf("xop_readdir: NULL parent\n");
967 * Generic scan of exact records. Note that indirect blocks are
968 * automatically recursed and will not be returned.
970 chain = hammer2_chain_lookup(&parent, &key_next,
971 xop->key_beg, xop->key_end,
972 &error, xop->lookup_flags);
974 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
977 chain = hammer2_chain_next(&parent, chain, &key_next,
978 key_next, xop->key_end,
979 &error, xop->lookup_flags);
983 hammer2_chain_unlock(chain);
984 hammer2_chain_drop(chain);
986 hammer2_chain_unlock(parent);
987 hammer2_chain_drop(parent);
989 hammer2_xop_feed(&xop->head, NULL, clindex, error);
992 /************************************************************************
994 ************************************************************************
998 * Helper to create a directory entry.
1001 hammer2_xop_inode_mkdirent(hammer2_xop_t *arg, void *scratch, int clindex)
1003 hammer2_xop_mkdirent_t *xop = &arg->xop_mkdirent;
1004 hammer2_chain_t *parent;
1005 hammer2_chain_t *chain;
1006 hammer2_key_t key_next;
1010 if (hammer2_debug & 0x0001)
1011 kprintf("dirent_create lhc %016jx clindex %d\n",
1014 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1015 HAMMER2_RESOLVE_ALWAYS);
1016 if (parent == NULL) {
1017 error = HAMMER2_ERROR_EIO;
1021 chain = hammer2_chain_lookup(&parent, &key_next,
1025 error = HAMMER2_ERROR_EEXIST;
1030 * We may be able to embed the directory entry directly in the
1033 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1036 data_len = HAMMER2_ALLOC_MIN;
1038 error = hammer2_chain_create(&parent, &chain,
1039 xop->head.ip1->pmp, HAMMER2_METH_DEFAULT,
1041 HAMMER2_BREF_TYPE_DIRENT,
1043 xop->head.mtid, 0, 0);
1046 * WARNING: chain->data->buf is sized to chain->bytes,
1047 * do not use sizeof(chain->data->buf), which
1048 * will be much larger.
1050 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1052 chain->bref.embed.dirent = xop->dirent;
1053 if (xop->dirent.namlen <= sizeof(chain->bref.check.buf))
1054 bcopy(xop->head.name1, chain->bref.check.buf,
1055 xop->dirent.namlen);
1057 bcopy(xop->head.name1, chain->data->buf,
1058 xop->dirent.namlen);
1063 hammer2_chain_unlock(parent);
1064 hammer2_chain_drop(parent);
1066 hammer2_xop_feed(&xop->head, chain, clindex, error);
1068 hammer2_chain_unlock(chain);
1069 hammer2_chain_drop(chain);
1074 * Inode create helper (threaded, backend)
1076 * Used by ncreate, nmknod, nsymlink, nmkdir.
1077 * Used by nlink and rename to create HARDLINK pointers.
1079 * Frontend holds the parent directory ip locked exclusively. We
1080 * create the inode and feed the exclusively locked chain to the
1084 hammer2_xop_inode_create(hammer2_xop_t *arg, void *scratch, int clindex)
1086 hammer2_xop_create_t *xop = &arg->xop_create;
1087 hammer2_chain_t *parent;
1088 hammer2_chain_t *chain;
1089 hammer2_key_t key_next;
1092 if (hammer2_debug & 0x0001)
1093 kprintf("inode_create lhc %016jx clindex %d\n",
1096 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1097 HAMMER2_RESOLVE_ALWAYS);
1098 if (parent == NULL) {
1099 error = HAMMER2_ERROR_EIO;
1103 chain = hammer2_chain_lookup(&parent, &key_next,
1107 error = HAMMER2_ERROR_EEXIST;
1111 error = hammer2_chain_create(&parent, &chain,
1112 xop->head.ip1->pmp, HAMMER2_METH_DEFAULT,
1114 HAMMER2_BREF_TYPE_INODE,
1115 HAMMER2_INODE_BYTES,
1116 xop->head.mtid, 0, xop->flags);
1118 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1120 chain->data->ipdata.meta = xop->meta;
1121 if (xop->head.name1) {
1122 bcopy(xop->head.name1,
1123 chain->data->ipdata.filename,
1124 xop->head.name1_len);
1125 chain->data->ipdata.meta.name_len =
1126 xop->head.name1_len;
1128 chain->data->ipdata.meta.name_key = xop->lhc;
1133 hammer2_chain_unlock(parent);
1134 hammer2_chain_drop(parent);
1136 hammer2_xop_feed(&xop->head, chain, clindex, error);
1138 hammer2_chain_unlock(chain);
1139 hammer2_chain_drop(chain);
1144 * Inode delete helper (backend, threaded)
1146 * Generally used by hammer2_run_sideq()
1149 hammer2_xop_inode_destroy(hammer2_xop_t *arg, void *scratch, int clindex)
1151 hammer2_xop_destroy_t *xop = &arg->xop_destroy;
1153 hammer2_chain_t *parent;
1154 hammer2_chain_t *chain;
1155 hammer2_inode_t *ip;
1159 * We need the precise parent chain to issue the deletion.
1164 chain = hammer2_inode_chain(ip, clindex, HAMMER2_RESOLVE_ALWAYS);
1165 if (chain == NULL) {
1167 error = HAMMER2_ERROR_EIO;
1170 parent = hammer2_chain_getparent(chain, HAMMER2_RESOLVE_ALWAYS);
1171 if (parent == NULL) {
1172 error = HAMMER2_ERROR_EIO;
1175 KKASSERT(chain->parent == parent);
1178 * We have the correct parent, we can issue the deletion.
1180 hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
1183 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1185 hammer2_chain_unlock(parent);
1186 hammer2_chain_drop(parent);
1189 hammer2_chain_unlock(chain);
1190 hammer2_chain_drop(chain);
1195 hammer2_xop_inode_unlinkall(hammer2_xop_t *arg, void *scratch, int clindex)
1197 hammer2_xop_unlinkall_t *xop = &arg->xop_unlinkall;
1198 hammer2_chain_t *parent;
1199 hammer2_chain_t *chain;
1200 hammer2_key_t key_next;
1204 * We need the precise parent chain to issue the deletion.
1206 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1207 HAMMER2_RESOLVE_ALWAYS);
1209 if (parent == NULL) {
1213 chain = hammer2_chain_lookup(&parent, &key_next,
1214 xop->key_beg, xop->key_end,
1215 &error, HAMMER2_LOOKUP_ALWAYS);
1217 hammer2_chain_delete(parent, chain,
1218 xop->head.mtid, HAMMER2_DELETE_PERMANENT);
1219 hammer2_xop_feed(&xop->head, chain, clindex, chain->error);
1220 /* depend on function to unlock the shared lock */
1221 chain = hammer2_chain_next(&parent, chain, &key_next,
1222 key_next, xop->key_end,
1224 HAMMER2_LOOKUP_ALWAYS);
1228 error = HAMMER2_ERROR_ENOENT;
1229 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1231 hammer2_chain_unlock(parent);
1232 hammer2_chain_drop(parent);
1235 hammer2_chain_unlock(chain);
1236 hammer2_chain_drop(chain);
1241 hammer2_xop_inode_connect(hammer2_xop_t *arg, void *scratch, int clindex)
1243 hammer2_xop_connect_t *xop = &arg->xop_connect;
1244 hammer2_inode_data_t *wipdata;
1245 hammer2_chain_t *parent;
1246 hammer2_chain_t *chain;
1248 hammer2_key_t key_dummy;
1252 * Get directory, then issue a lookup to prime the parent chain
1253 * for the create. The lookup is expected to fail.
1255 pmp = xop->head.ip1->pmp;
1256 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1257 HAMMER2_RESOLVE_ALWAYS);
1258 if (parent == NULL) {
1260 error = HAMMER2_ERROR_EIO;
1263 chain = hammer2_chain_lookup(&parent, &key_dummy,
1267 hammer2_chain_unlock(chain);
1268 hammer2_chain_drop(chain);
1270 error = HAMMER2_ERROR_EEXIST;
1277 * Adjust the filename in the inode, set the name key.
1279 * NOTE: Frontend must also adjust ip2->meta on success, we can't
1282 chain = hammer2_inode_chain(xop->head.ip2, clindex,
1283 HAMMER2_RESOLVE_ALWAYS);
1284 error = hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
1288 wipdata = &chain->data->ipdata;
1290 hammer2_inode_modify(xop->head.ip2);
1291 if (xop->head.name1) {
1292 bzero(wipdata->filename, sizeof(wipdata->filename));
1293 bcopy(xop->head.name1, wipdata->filename, xop->head.name1_len);
1294 wipdata->meta.name_len = xop->head.name1_len;
1296 wipdata->meta.name_key = xop->lhc;
1299 * Reconnect the chain to the new parent directory
1301 error = hammer2_chain_create(&parent, &chain,
1302 pmp, HAMMER2_METH_DEFAULT,
1304 HAMMER2_BREF_TYPE_INODE,
1305 HAMMER2_INODE_BYTES,
1306 xop->head.mtid, 0, 0);
1312 hammer2_xop_feed(&xop->head, NULL, clindex, error);
1314 hammer2_chain_unlock(parent);
1315 hammer2_chain_drop(parent);
1318 hammer2_chain_unlock(chain);
1319 hammer2_chain_drop(chain);
1324 * Synchronize the in-memory inode with the chain. This does not flush
1325 * the chain to disk. Instead, it makes front-end inode changes visible
1326 * in the chain topology, thus visible to the backend. This is done in an
1327 * ad-hoc manner outside of the filesystem vfs_sync, and in a controlled
1328 * manner inside the vfs_sync.
1331 hammer2_xop_inode_chain_sync(hammer2_xop_t *arg, void *scratch, int clindex)
1333 hammer2_xop_fsync_t *xop = &arg->xop_fsync;
1334 hammer2_chain_t *parent;
1335 hammer2_chain_t *chain;
1338 parent = hammer2_inode_chain(xop->head.ip1, clindex,
1339 HAMMER2_RESOLVE_ALWAYS);
1341 if (parent == NULL) {
1342 error = HAMMER2_ERROR_EIO;
1345 if (parent->error) {
1346 error = parent->error;
1352 if ((xop->ipflags & HAMMER2_INODE_RESIZED) == 0) {
1353 /* osize must be ignored */
1354 } else if (xop->meta.size < xop->osize) {
1356 * We must delete any chains beyond the EOF. The chain
1357 * straddling the EOF will be pending in the bioq.
1359 hammer2_key_t lbase;
1360 hammer2_key_t key_next;
1362 lbase = (xop->meta.size + HAMMER2_PBUFMASK64) &
1363 ~HAMMER2_PBUFMASK64;
1364 chain = hammer2_chain_lookup(&parent, &key_next,
1365 lbase, HAMMER2_KEY_MAX,
1367 HAMMER2_LOOKUP_NODATA |
1368 HAMMER2_LOOKUP_NODIRECT);
1371 * Degenerate embedded case, nothing to loop on
1373 switch (chain->bref.type) {
1374 case HAMMER2_BREF_TYPE_DIRENT:
1375 case HAMMER2_BREF_TYPE_INODE:
1378 case HAMMER2_BREF_TYPE_DATA:
1379 hammer2_chain_delete(parent, chain,
1381 HAMMER2_DELETE_PERMANENT);
1384 chain = hammer2_chain_next(&parent, chain, &key_next,
1385 key_next, HAMMER2_KEY_MAX,
1387 HAMMER2_LOOKUP_NODATA |
1388 HAMMER2_LOOKUP_NODIRECT);
1392 * Reset to point at inode for following code, if necessary.
1394 if (parent->bref.type != HAMMER2_BREF_TYPE_INODE) {
1395 hammer2_chain_unlock(parent);
1396 hammer2_chain_drop(parent);
1397 parent = hammer2_inode_chain(xop->head.ip1,
1399 HAMMER2_RESOLVE_ALWAYS);
1400 kprintf("hammer2: TRUNCATE RESET on '%s'\n",
1401 parent->data->ipdata.filename);
1406 * Sync the inode meta-data, potentially clear the blockset area
1407 * of direct data so it can be used for blockrefs.
1410 error = hammer2_chain_modify(parent, xop->head.mtid, 0, 0);
1412 parent->data->ipdata.meta = xop->meta;
1413 if (xop->clear_directdata) {
1414 bzero(&parent->data->ipdata.u.blockset,
1415 sizeof(parent->data->ipdata.u.blockset));
1421 hammer2_chain_unlock(chain);
1422 hammer2_chain_drop(chain);
1425 hammer2_chain_unlock(parent);
1426 hammer2_chain_drop(parent);
1428 hammer2_xop_feed(&xop->head, NULL, clindex, error);