2 * Copyright (c) 2011-2014 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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/types.h>
46 RB_GENERATE2(hammer2_inode_tree
, hammer2_inode
, rbnode
, hammer2_inode_cmp
,
47 hammer2_tid_t
, meta
.inum
);
50 hammer2_inode_cmp(hammer2_inode_t
*ip1
, hammer2_inode_t
*ip2
)
52 if (ip1
->meta
.inum
< ip2
->meta
.inum
)
54 if (ip1
->meta
.inum
> ip2
->meta
.inum
)
61 hammer2_knote(struct vnode
*vp
, int flags
)
64 KNOTE(&vp
->v_pollinfo
.vpi_kqinfo
.ki_note
, flags
);
69 hammer2_inode_delayed_sideq(hammer2_inode_t
*ip
)
71 hammer2_inode_sideq_t
*ipul
;
72 hammer2_pfs_t
*pmp
= ip
->pmp
;
74 if ((ip
->flags
& HAMMER2_INODE_ONSIDEQ
) == 0) {
75 ipul
= kmalloc(sizeof(*ipul
), pmp
->minode
,
78 hammer2_spin_ex(&pmp
->list_spin
);
79 if ((ip
->flags
& HAMMER2_INODE_ONSIDEQ
) == 0) {
80 hammer2_inode_ref(ip
);
81 atomic_set_int(&ip
->flags
,
82 HAMMER2_INODE_ONSIDEQ
);
83 TAILQ_INSERT_TAIL(&pmp
->sideq
, ipul
, entry
);
84 hammer2_spin_unex(&pmp
->list_spin
);
86 hammer2_spin_unex(&pmp
->list_spin
);
87 kfree(ipul
, pmp
->minode
);
95 * HAMMER2 offers shared and exclusive locks on inodes. Pass a mask of
98 * - pass HAMMER2_RESOLVE_SHARED if a shared lock is desired. The
99 * inode locking function will automatically set the RDONLY flag.
101 * - pass HAMMER2_RESOLVE_ALWAYS if you need the inode's meta-data.
102 * Most front-end inode locks do.
104 * - pass HAMMER2_RESOLVE_NEVER if you do not want to require that
105 * the inode data be resolved. This is used by the syncthr because
106 * it can run on an unresolved/out-of-sync cluster, and also by the
107 * vnode reclamation code to avoid unnecessary I/O (particularly when
108 * disposing of hundreds of thousands of cached vnodes).
110 * The inode locking function locks the inode itself, resolves any stale
111 * chains in the inode's cluster, and allocates a fresh copy of the
112 * cluster with 1 ref and all the underlying chains locked.
114 * ip->cluster will be stable while the inode is locked.
116 * NOTE: We don't combine the inode/chain lock because putting away an
117 * inode would otherwise confuse multiple lock holders of the inode.
119 * NOTE: In-memory inodes always point to hardlink targets (the actual file),
120 * and never point to a hardlink pointer.
122 * NOTE: If caller passes HAMMER2_RESOLVE_RDONLY the exclusive locking code
123 * will feel free to reduce the chain set in the cluster as an
124 * optimization. It will still be validated against the quorum if
125 * appropriate, but the optimization might be able to reduce data
126 * accesses to one node. This flag is automatically set if the inode
127 * is locked with HAMMER2_RESOLVE_SHARED.
130 hammer2_inode_lock(hammer2_inode_t
*ip
, int how
)
132 hammer2_inode_ref(ip
);
135 * Inode structure mutex
137 if (how
& HAMMER2_RESOLVE_SHARED
) {
138 /*how |= HAMMER2_RESOLVE_RDONLY; not used */
139 hammer2_mtx_sh(&ip
->lock
);
141 hammer2_mtx_ex(&ip
->lock
);
146 * Select a chain out of an inode's cluster and lock it.
148 * The inode does not have to be locked.
151 hammer2_inode_chain(hammer2_inode_t
*ip
, int clindex
, int how
)
153 hammer2_chain_t
*chain
;
154 hammer2_cluster_t
*cluster
;
156 hammer2_spin_sh(&ip
->cluster_spin
);
157 cluster
= &ip
->cluster
;
158 if (clindex
>= cluster
->nchains
)
161 chain
= cluster
->array
[clindex
].chain
;
163 hammer2_chain_ref(chain
);
164 hammer2_spin_unsh(&ip
->cluster_spin
);
165 hammer2_chain_lock(chain
, how
);
167 hammer2_spin_unsh(&ip
->cluster_spin
);
173 hammer2_inode_chain_and_parent(hammer2_inode_t
*ip
, int clindex
,
174 hammer2_chain_t
**parentp
, int how
)
176 hammer2_chain_t
*chain
;
177 hammer2_chain_t
*parent
;
180 hammer2_spin_sh(&ip
->cluster_spin
);
181 if (clindex
>= ip
->cluster
.nchains
)
184 chain
= ip
->cluster
.array
[clindex
].chain
;
186 hammer2_chain_ref(chain
);
187 hammer2_spin_unsh(&ip
->cluster_spin
);
188 hammer2_chain_lock(chain
, how
);
190 hammer2_spin_unsh(&ip
->cluster_spin
);
194 * Get parent, lock order must be (parent, chain).
196 parent
= chain
->parent
;
198 hammer2_chain_ref(parent
);
199 hammer2_chain_unlock(chain
);
200 hammer2_chain_lock(parent
, how
);
201 hammer2_chain_lock(chain
, how
);
203 if (ip
->cluster
.array
[clindex
].chain
== chain
&&
204 chain
->parent
== parent
) {
211 hammer2_chain_unlock(chain
);
212 hammer2_chain_drop(chain
);
214 hammer2_chain_unlock(parent
);
215 hammer2_chain_drop(parent
);
224 hammer2_inode_unlock(hammer2_inode_t
*ip
)
226 hammer2_mtx_unlock(&ip
->lock
);
227 hammer2_inode_drop(ip
);
231 * Temporarily release a lock held shared or exclusive. Caller must
232 * hold the lock shared or exclusive on call and lock will be released
235 * Restore a lock that was temporarily released.
238 hammer2_inode_lock_temp_release(hammer2_inode_t
*ip
)
240 return hammer2_mtx_temp_release(&ip
->lock
);
244 hammer2_inode_lock_temp_restore(hammer2_inode_t
*ip
, hammer2_mtx_state_t ostate
)
246 hammer2_mtx_temp_restore(&ip
->lock
, ostate
);
250 * Upgrade a shared inode lock to exclusive and return. If the inode lock
251 * is already held exclusively this is a NOP.
253 * The caller MUST hold the inode lock either shared or exclusive on call
254 * and will own the lock exclusively on return.
256 * Returns non-zero if the lock was already exclusive prior to the upgrade.
259 hammer2_inode_lock_upgrade(hammer2_inode_t
*ip
)
263 if (mtx_islocked_ex(&ip
->lock
)) {
266 hammer2_mtx_unlock(&ip
->lock
);
267 hammer2_mtx_ex(&ip
->lock
);
274 * Downgrade an inode lock from exclusive to shared only if the inode
275 * lock was previously shared. If the inode lock was previously exclusive,
279 hammer2_inode_lock_downgrade(hammer2_inode_t
*ip
, int wasexclusive
)
281 if (wasexclusive
== 0)
282 mtx_downgrade(&ip
->lock
);
286 * Lookup an inode by inode number
289 hammer2_inode_lookup(hammer2_pfs_t
*pmp
, hammer2_tid_t inum
)
297 hammer2_spin_ex(&pmp
->inum_spin
);
298 ip
= RB_LOOKUP(hammer2_inode_tree
, &pmp
->inum_tree
, inum
);
300 hammer2_inode_ref(ip
);
301 hammer2_spin_unex(&pmp
->inum_spin
);
307 * Adding a ref to an inode is only legal if the inode already has at least
310 * (can be called with spinlock held)
313 hammer2_inode_ref(hammer2_inode_t
*ip
)
315 atomic_add_int(&ip
->refs
, 1);
316 if (hammer2_debug
& 0x80000) {
317 kprintf("INODE+1 %p (%d->%d)\n", ip
, ip
->refs
- 1, ip
->refs
);
323 * Drop an inode reference, freeing the inode when the last reference goes
327 hammer2_inode_drop(hammer2_inode_t
*ip
)
333 if (hammer2_debug
& 0x80000) {
334 kprintf("INODE-1 %p (%d->%d)\n",
335 ip
, ip
->refs
, ip
->refs
- 1);
342 * Transition to zero, must interlock with
343 * the inode inumber lookup tree (if applicable).
344 * It should not be possible for anyone to race
345 * the transition to 0.
349 hammer2_spin_ex(&pmp
->inum_spin
);
351 if (atomic_cmpset_int(&ip
->refs
, 1, 0)) {
352 KKASSERT(hammer2_mtx_refs(&ip
->lock
) == 0);
353 if (ip
->flags
& HAMMER2_INODE_ONRBTREE
) {
354 atomic_clear_int(&ip
->flags
,
355 HAMMER2_INODE_ONRBTREE
);
356 RB_REMOVE(hammer2_inode_tree
,
357 &pmp
->inum_tree
, ip
);
359 hammer2_spin_unex(&pmp
->inum_spin
);
364 * Cleaning out ip->cluster isn't entirely
367 hammer2_inode_repoint(ip
, NULL
, NULL
);
369 kfree(ip
, pmp
->minode
);
370 atomic_add_long(&pmp
->inmem_inodes
, -1);
371 ip
= NULL
; /* will terminate loop */
373 hammer2_spin_unex(&ip
->pmp
->inum_spin
);
377 * Non zero transition
379 if (atomic_cmpset_int(&ip
->refs
, refs
, refs
- 1))
386 * Get the vnode associated with the given inode, allocating the vnode if
387 * necessary. The vnode will be returned exclusively locked.
389 * The caller must lock the inode (shared or exclusive).
391 * Great care must be taken to avoid deadlocks and vnode acquisition/reclaim
395 hammer2_igetv(hammer2_inode_t
*ip
, int *errorp
)
401 KKASSERT(pmp
!= NULL
);
406 * Attempt to reuse an existing vnode assignment. It is
407 * possible to race a reclaim so the vget() may fail. The
408 * inode must be unlocked during the vget() to avoid a
409 * deadlock against a reclaim.
416 * Inode must be unlocked during the vget() to avoid
417 * possible deadlocks, but leave the ip ref intact.
419 * vnode is held to prevent destruction during the
420 * vget(). The vget() can still fail if we lost
421 * a reclaim race on the vnode.
423 hammer2_mtx_state_t ostate
;
426 ostate
= hammer2_inode_lock_temp_release(ip
);
427 if (vget(vp
, LK_EXCLUSIVE
)) {
429 hammer2_inode_lock_temp_restore(ip
, ostate
);
432 hammer2_inode_lock_temp_restore(ip
, ostate
);
434 /* vp still locked and ref from vget */
436 kprintf("hammer2: igetv race %p/%p\n",
446 * No vnode exists, allocate a new vnode. Beware of
447 * allocation races. This function will return an
448 * exclusively locked and referenced vnode.
450 *errorp
= getnewvnode(VT_HAMMER2
, pmp
->mp
, &vp
, 0, 0);
452 kprintf("hammer2: igetv getnewvnode failed %d\n",
459 * Lock the inode and check for an allocation race.
461 wasexclusive
= hammer2_inode_lock_upgrade(ip
);
462 if (ip
->vp
!= NULL
) {
465 hammer2_inode_lock_downgrade(ip
, wasexclusive
);
469 switch (ip
->meta
.type
) {
470 case HAMMER2_OBJTYPE_DIRECTORY
:
473 case HAMMER2_OBJTYPE_REGFILE
:
475 vinitvmio(vp
, ip
->meta
.size
,
477 (int)ip
->meta
.size
& HAMMER2_LBUFMASK
);
479 case HAMMER2_OBJTYPE_SOFTLINK
:
481 * XXX for now we are using the generic file_read
482 * and file_write code so we need a buffer cache
486 vinitvmio(vp
, ip
->meta
.size
,
488 (int)ip
->meta
.size
& HAMMER2_LBUFMASK
);
490 case HAMMER2_OBJTYPE_CDEV
:
493 case HAMMER2_OBJTYPE_BDEV
:
494 vp
->v_ops
= &pmp
->mp
->mnt_vn_spec_ops
;
495 if (ip
->meta
.type
!= HAMMER2_OBJTYPE_CDEV
)
501 case HAMMER2_OBJTYPE_FIFO
:
503 vp
->v_ops
= &pmp
->mp
->mnt_vn_fifo_ops
;
505 case HAMMER2_OBJTYPE_SOCKET
:
509 panic("hammer2: unhandled objtype %d",
514 if (ip
== pmp
->iroot
)
515 vsetflags(vp
, VROOT
);
519 hammer2_inode_ref(ip
); /* vp association */
520 hammer2_inode_lock_downgrade(ip
, wasexclusive
);
525 * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0.
527 if (hammer2_debug
& 0x0002) {
528 kprintf("igetv vp %p refs 0x%08x aux 0x%08x\n",
529 vp
, vp
->v_refcnt
, vp
->v_auxrefs
);
535 * Returns the inode associated with the passed-in cluster, creating the
536 * inode if necessary and synchronizing it to the passed-in cluster otherwise.
537 * When synchronizing, if idx >= 0, only cluster index (idx) is synchronized.
538 * Otherwise the whole cluster is synchronized.
540 * The passed-in cluster must be locked and will remain locked on return.
541 * The returned inode will be locked and the caller may dispose of both
542 * via hammer2_inode_unlock() + hammer2_inode_drop(). However, if the caller
543 * needs to resolve a hardlink it must ref/unlock/relock/drop the inode.
545 * The hammer2_inode structure regulates the interface between the high level
546 * kernel VNOPS API and the filesystem backend (the chains).
548 * On return the inode is locked with the supplied cluster.
551 hammer2_inode_get(hammer2_pfs_t
*pmp
, hammer2_inode_t
*dip
,
552 hammer2_cluster_t
*cluster
, int idx
)
554 hammer2_inode_t
*nip
;
555 const hammer2_inode_data_t
*iptmp
;
556 const hammer2_inode_data_t
*nipdata
;
558 KKASSERT(cluster
== NULL
||
559 hammer2_cluster_type(cluster
) == HAMMER2_BREF_TYPE_INODE
);
563 * Interlocked lookup/ref of the inode. This code is only needed
564 * when looking up inodes with nlinks != 0 (TODO: optimize out
565 * otherwise and test for duplicates).
567 * Cluster can be NULL during the initial pfs allocation.
571 iptmp
= &hammer2_cluster_rdata(cluster
)->ipdata
;
572 nip
= hammer2_inode_lookup(pmp
, iptmp
->meta
.inum
);
576 hammer2_mtx_ex(&nip
->lock
);
579 * Handle SMP race (not applicable to the super-root spmp
580 * which can't index inodes due to duplicative inode numbers).
582 if (pmp
->spmp_hmp
== NULL
&&
583 (nip
->flags
& HAMMER2_INODE_ONRBTREE
) == 0) {
584 hammer2_mtx_unlock(&nip
->lock
);
585 hammer2_inode_drop(nip
);
589 hammer2_inode_repoint_one(nip
, cluster
, idx
);
591 hammer2_inode_repoint(nip
, NULL
, cluster
);
597 * We couldn't find the inode number, create a new inode.
599 nip
= kmalloc(sizeof(*nip
), pmp
->minode
, M_WAITOK
| M_ZERO
);
600 spin_init(&nip
->cluster_spin
, "h2clspin");
601 atomic_add_long(&pmp
->inmem_inodes
, 1);
602 hammer2_pfs_memory_inc(pmp
);
603 hammer2_pfs_memory_wakeup(pmp
);
605 nip
->flags
= HAMMER2_INODE_SROOT
;
608 * Initialize nip's cluster. A cluster is provided for normal
609 * inodes but typically not for the super-root or PFS inodes.
611 nip
->cluster
.refs
= 1;
612 nip
->cluster
.pmp
= pmp
;
613 nip
->cluster
.flags
|= HAMMER2_CLUSTER_INODE
;
615 nipdata
= &hammer2_cluster_rdata(cluster
)->ipdata
;
616 nip
->meta
= nipdata
->meta
;
617 atomic_set_int(&nip
->flags
, HAMMER2_INODE_METAGOOD
);
618 hammer2_inode_repoint(nip
, NULL
, cluster
);
620 nip
->meta
.inum
= 1; /* PFS inum is always 1 XXX */
621 /* mtime will be updated when a cluster is available */
622 atomic_set_int(&nip
->flags
, HAMMER2_INODE_METAGOOD
);/*XXX*/
628 * ref and lock on nip gives it state compatible to after a
629 * hammer2_inode_lock() call.
632 hammer2_mtx_init(&nip
->lock
, "h2inode");
633 hammer2_mtx_ex(&nip
->lock
);
634 /* combination of thread lock and chain lock == inode lock */
637 * Attempt to add the inode. If it fails we raced another inode
638 * get. Undo all the work and try again.
640 if (pmp
->spmp_hmp
== NULL
) {
641 hammer2_spin_ex(&pmp
->inum_spin
);
642 if (RB_INSERT(hammer2_inode_tree
, &pmp
->inum_tree
, nip
)) {
643 hammer2_spin_unex(&pmp
->inum_spin
);
644 hammer2_mtx_unlock(&nip
->lock
);
645 hammer2_inode_drop(nip
);
648 atomic_set_int(&nip
->flags
, HAMMER2_INODE_ONRBTREE
);
649 hammer2_spin_unex(&pmp
->inum_spin
);
658 * Create a new inode using the vattr to figure out the type. A non-zero
659 * type field overrides vattr. We need the directory to set iparent or to
660 * use when the inode is directly embedded in a directory (typically super-root
661 * entries), but note that this really only applies OBJTYPE_DIRECTORY as
662 * non-directory inodes can be hardlinked.
664 * If no error occurs the new inode with its cluster locked is returned.
666 * If vap and/or cred are NULL the related fields are not set and the
667 * inode type defaults to a directory. This is used when creating PFSs
668 * under the super-root, so the inode number is set to 1 in this case.
670 * dip is not locked on entry.
672 * NOTE: This function is used to create all manners of inodes, including
673 * super-root entries for snapshots and PFSs. When used to create a
674 * snapshot the inode will be temporarily associated with the spmp.
676 * NOTE: When creating a normal file or directory the name/name_len/lhc
677 * is optional, but is typically specified to make debugging and
681 hammer2_inode_create(hammer2_inode_t
*dip
, hammer2_inode_t
*pip
,
682 struct vattr
*vap
, struct ucred
*cred
,
683 const uint8_t *name
, size_t name_len
, hammer2_key_t lhc
,
685 uint8_t type
, uint8_t target_type
,
686 int flags
, int *errorp
)
688 hammer2_xop_create_t
*xop
;
689 hammer2_inode_t
*nip
;
695 uint8_t pip_comp_algo
;
696 uint8_t pip_check_algo
;
697 hammer2_tid_t pip_inum
;
700 lhc
= hammer2_dirhash(name
, name_len
);
705 * Locate the inode or indirect block to create the new
706 * entry in. At the same time check for key collisions
707 * and iterate until we don't get one.
709 * Lock the directory exclusively for now to guarantee that
710 * we can find an unused lhc for the name. Due to collisions,
711 * two different creates can end up with the same lhc so we
712 * cannot depend on the OS to prevent the collision.
714 hammer2_inode_lock(dip
, 0);
716 pip_uid
= pip
->meta
.uid
;
717 pip_gid
= pip
->meta
.gid
;
718 pip_mode
= pip
->meta
.mode
;
719 pip_comp_algo
= pip
->meta
.comp_algo
;
720 pip_check_algo
= pip
->meta
.check_algo
;
721 pip_inum
= (pip
== pip
->pmp
->iroot
) ? 1 : pip
->meta
.inum
;
724 * If name specified, locate an unused key in the collision space.
725 * Otherwise use the passed-in lhc directly.
728 hammer2_xop_scanlhc_t
*sxop
;
729 hammer2_key_t lhcbase
;
732 sxop
= hammer2_xop_alloc(dip
, HAMMER2_XOP_MODIFYING
);
734 hammer2_xop_start(&sxop
->head
, hammer2_xop_scanlhc
);
735 while ((error
= hammer2_xop_collect(&sxop
->head
, 0)) == 0) {
736 if (lhc
!= sxop
->head
.cluster
.focus
->bref
.key
)
740 hammer2_xop_retire(&sxop
->head
, HAMMER2_XOPMASK_VOP
);
748 if ((lhcbase
^ lhc
) & ~HAMMER2_DIRHASH_LOMASK
) {
755 * Create the inode with the lhc as the key.
757 xop
= hammer2_xop_alloc(dip
, HAMMER2_XOP_MODIFYING
);
760 bzero(&xop
->meta
, sizeof(xop
->meta
));
763 xop
->meta
.type
= hammer2_get_obj_type(vap
->va_type
);
765 switch (xop
->meta
.type
) {
766 case HAMMER2_OBJTYPE_CDEV
:
767 case HAMMER2_OBJTYPE_BDEV
:
768 xop
->meta
.rmajor
= vap
->va_rmajor
;
769 xop
->meta
.rminor
= vap
->va_rminor
;
774 type
= xop
->meta
.type
;
776 xop
->meta
.type
= type
;
777 xop
->meta
.target_type
= target_type
;
779 xop
->meta
.inum
= inum
;
780 xop
->meta
.iparent
= pip_inum
;
782 /* Inherit parent's inode compression mode. */
783 xop
->meta
.comp_algo
= pip_comp_algo
;
784 xop
->meta
.check_algo
= pip_check_algo
;
785 xop
->meta
.version
= HAMMER2_INODE_VERSION_ONE
;
786 hammer2_update_time(&xop
->meta
.ctime
);
787 xop
->meta
.mtime
= xop
->meta
.ctime
;
789 xop
->meta
.mode
= vap
->va_mode
;
790 xop
->meta
.nlinks
= 1;
793 xuid
= hammer2_to_unix_xid(&pip_uid
);
794 xuid
= vop_helper_create_uid(dip
->pmp
->mp
,
800 /* super-root has no dip and/or pmp */
803 if (vap
->va_vaflags
& VA_UID_UUID_VALID
)
804 xop
->meta
.uid
= vap
->va_uid_uuid
;
805 else if (vap
->va_uid
!= (uid_t
)VNOVAL
)
806 hammer2_guid_to_uuid(&xop
->meta
.uid
, vap
->va_uid
);
808 hammer2_guid_to_uuid(&xop
->meta
.uid
, xuid
);
810 if (vap
->va_vaflags
& VA_GID_UUID_VALID
)
811 xop
->meta
.gid
= vap
->va_gid_uuid
;
812 else if (vap
->va_gid
!= (gid_t
)VNOVAL
)
813 hammer2_guid_to_uuid(&xop
->meta
.gid
, vap
->va_gid
);
815 xop
->meta
.gid
= pip_gid
;
819 * Regular files and softlinks allow a small amount of data to be
820 * directly embedded in the inode. This flag will be cleared if
821 * the size is extended past the embedded limit.
823 if (xop
->meta
.type
== HAMMER2_OBJTYPE_REGFILE
||
824 xop
->meta
.type
== HAMMER2_OBJTYPE_SOFTLINK
) {
825 xop
->meta
.op_flags
|= HAMMER2_OPFLAG_DIRECTDATA
;
828 hammer2_xop_setname(&xop
->head
, name
, name_len
);
830 name_len
= hammer2_xop_setname_inum(&xop
->head
, inum
);
831 KKASSERT(lhc
== inum
);
833 xop
->meta
.name_len
= name_len
;
834 xop
->meta
.name_key
= lhc
;
835 KKASSERT(name_len
< HAMMER2_INODE_MAXNAME
);
837 hammer2_xop_start(&xop
->head
, hammer2_inode_xop_create
);
839 error
= hammer2_xop_collect(&xop
->head
, 0);
841 kprintf("CREATE INODE %*.*s\n",
842 (int)name_len
, (int)name_len
, name
);
851 * Set up the new inode if not a hardlink pointer.
853 * NOTE: *_get() integrates chain's lock into the inode lock.
855 * NOTE: Only one new inode can currently be created per
856 * transaction. If the need arises we can adjust
857 * hammer2_trans_init() to allow more.
859 * NOTE: nipdata will have chain's blockset data.
861 nip
= hammer2_inode_get(dip
->pmp
, dip
, &xop
->head
.cluster
, -1);
862 nip
->comp_heuristic
= 0;
864 hammer2_xop_retire(&xop
->head
, HAMMER2_XOPMASK_VOP
);
866 hammer2_inode_unlock(dip
);
872 * Create a directory entry under dip with the specified name, inode number,
873 * and OBJTYPE (type).
876 hammer2_dirent_create(hammer2_inode_t
*dip
, const char *name
, size_t name_len
,
877 hammer2_key_t inum
, uint8_t type
)
879 hammer2_xop_mkdirent_t
*xop
;
886 KKASSERT(name
!= NULL
);
887 lhc
= hammer2_dirhash(name
, name_len
);
890 * Locate the inode or indirect block to create the new
891 * entry in. At the same time check for key collisions
892 * and iterate until we don't get one.
894 * Lock the directory exclusively for now to guarantee that
895 * we can find an unused lhc for the name. Due to collisions,
896 * two different creates can end up with the same lhc so we
897 * cannot depend on the OS to prevent the collision.
899 hammer2_inode_lock(dip
, 0);
902 * If name specified, locate an unused key in the collision space.
903 * Otherwise use the passed-in lhc directly.
906 hammer2_xop_scanlhc_t
*sxop
;
907 hammer2_key_t lhcbase
;
910 sxop
= hammer2_xop_alloc(dip
, HAMMER2_XOP_MODIFYING
);
912 hammer2_xop_start(&sxop
->head
, hammer2_xop_scanlhc
);
913 while ((error
= hammer2_xop_collect(&sxop
->head
, 0)) == 0) {
914 if (lhc
!= sxop
->head
.cluster
.focus
->bref
.key
)
918 hammer2_xop_retire(&sxop
->head
, HAMMER2_XOPMASK_VOP
);
926 if ((lhcbase
^ lhc
) & ~HAMMER2_DIRHASH_LOMASK
) {
933 * Create the directory entry with the lhc as the key.
935 xop
= hammer2_xop_alloc(dip
, HAMMER2_XOP_MODIFYING
);
937 bzero(&xop
->dirent
, sizeof(xop
->dirent
));
938 xop
->dirent
.inum
= inum
;
939 xop
->dirent
.type
= type
;
940 xop
->dirent
.namlen
= name_len
;
942 KKASSERT(name_len
< HAMMER2_INODE_MAXNAME
);
943 hammer2_xop_setname(&xop
->head
, name
, name_len
);
945 hammer2_xop_start(&xop
->head
, hammer2_inode_xop_mkdirent
);
947 error
= hammer2_xop_collect(&xop
->head
, 0);
949 hammer2_xop_retire(&xop
->head
, HAMMER2_XOPMASK_VOP
);
951 hammer2_inode_unlock(dip
);
957 * Repoint ip->cluster's chains to cluster's chains and fixup the default
958 * focus. All items, valid or invalid, are repointed. hammer2_xop_start()
959 * filters out invalid or non-matching elements.
961 * Caller must hold the inode and cluster exclusive locked, if not NULL,
962 * must also be locked.
964 * Cluster may be NULL to clean out any chains in ip->cluster.
967 hammer2_inode_repoint(hammer2_inode_t
*ip
, hammer2_inode_t
*pip
,
968 hammer2_cluster_t
*cluster
)
970 hammer2_chain_t
*dropch
[HAMMER2_MAXCLUSTER
];
971 hammer2_chain_t
*ochain
;
972 hammer2_chain_t
*nchain
;
975 bzero(dropch
, sizeof(dropch
));
978 * Replace chains in ip->cluster with chains from cluster and
979 * adjust the focus if necessary.
981 * NOTE: nchain and/or ochain can be NULL due to gaps
982 * in the cluster arrays.
984 hammer2_spin_ex(&ip
->cluster_spin
);
985 for (i
= 0; cluster
&& i
< cluster
->nchains
; ++i
) {
987 * Do not replace elements which are the same. Also handle
988 * element count discrepancies.
990 nchain
= cluster
->array
[i
].chain
;
991 if (i
< ip
->cluster
.nchains
) {
992 ochain
= ip
->cluster
.array
[i
].chain
;
993 if (ochain
== nchain
)
1002 ip
->cluster
.array
[i
].chain
= nchain
;
1003 ip
->cluster
.array
[i
].flags
&= ~HAMMER2_CITEM_INVALID
;
1004 ip
->cluster
.array
[i
].flags
|= cluster
->array
[i
].flags
&
1005 HAMMER2_CITEM_INVALID
;
1007 hammer2_chain_ref(nchain
);
1012 * Release any left-over chains in ip->cluster.
1014 while (i
< ip
->cluster
.nchains
) {
1015 nchain
= ip
->cluster
.array
[i
].chain
;
1017 ip
->cluster
.array
[i
].chain
= NULL
;
1018 ip
->cluster
.array
[i
].flags
|= HAMMER2_CITEM_INVALID
;
1025 * Fixup fields. Note that the inode-embedded cluster is never
1029 ip
->cluster
.nchains
= cluster
->nchains
;
1030 ip
->cluster
.focus
= cluster
->focus
;
1031 ip
->cluster
.flags
= cluster
->flags
& ~HAMMER2_CLUSTER_LOCKED
;
1033 ip
->cluster
.nchains
= 0;
1034 ip
->cluster
.focus
= NULL
;
1035 ip
->cluster
.flags
&= ~HAMMER2_CLUSTER_ZFLAGS
;
1038 hammer2_spin_unex(&ip
->cluster_spin
);
1041 * Cleanup outside of spinlock
1045 hammer2_chain_drop(dropch
[i
]);
1050 * Repoint a single element from the cluster to the ip. Used by the
1051 * synchronization threads to piecemeal update inodes. Does not change
1052 * focus and requires inode to be re-locked to clean-up flags (XXX).
1055 hammer2_inode_repoint_one(hammer2_inode_t
*ip
, hammer2_cluster_t
*cluster
,
1058 hammer2_chain_t
*ochain
;
1059 hammer2_chain_t
*nchain
;
1062 hammer2_spin_ex(&ip
->cluster_spin
);
1063 KKASSERT(idx
< cluster
->nchains
);
1064 if (idx
< ip
->cluster
.nchains
) {
1065 ochain
= ip
->cluster
.array
[idx
].chain
;
1066 nchain
= cluster
->array
[idx
].chain
;
1069 nchain
= cluster
->array
[idx
].chain
;
1070 ip
->cluster
.nchains
= idx
+ 1;
1071 for (i
= ip
->cluster
.nchains
; i
<= idx
; ++i
) {
1072 bzero(&ip
->cluster
.array
[i
],
1073 sizeof(ip
->cluster
.array
[i
]));
1074 ip
->cluster
.array
[i
].flags
|= HAMMER2_CITEM_INVALID
;
1077 if (ochain
!= nchain
) {
1081 ip
->cluster
.array
[idx
].chain
= nchain
;
1082 ip
->cluster
.array
[idx
].flags
&= ~HAMMER2_CITEM_INVALID
;
1083 ip
->cluster
.array
[idx
].flags
|= cluster
->array
[idx
].flags
&
1084 HAMMER2_CITEM_INVALID
;
1086 hammer2_spin_unex(&ip
->cluster_spin
);
1087 if (ochain
!= nchain
) {
1089 hammer2_chain_ref(nchain
);
1091 hammer2_chain_drop(ochain
);
1096 * Called with a locked inode to finish unlinking an inode after xop_unlink
1097 * had been run. This function is responsible for decrementing nlinks.
1099 * We don't bother decrementing nlinks if the file is not open and this was
1102 * If the inode is a hardlink target it's chain has not yet been deleted,
1103 * otherwise it's chain has been deleted.
1105 * If isopen then any prior deletion was not permanent and the inode is
1106 * left intact with nlinks == 0;
1109 hammer2_inode_unlink_finisher(hammer2_inode_t
*ip
, int isopen
)
1117 * Decrement nlinks. If this is the last link and the file is
1118 * not open we can just delete the inode and not bother dropping
1119 * nlinks to 0 (avoiding unnecessary block updates).
1121 if (ip
->meta
.nlinks
== 1) {
1122 atomic_set_int(&ip
->flags
, HAMMER2_INODE_ISUNLINKED
);
1127 hammer2_inode_modify(ip
);
1129 if ((int64_t)ip
->meta
.nlinks
< 0)
1130 ip
->meta
.nlinks
= 0; /* safety */
1133 * If nlinks is not zero we are done. However, this should only be
1134 * possible with a hardlink target. If the inode is an embedded
1135 * hardlink nlinks should have dropped to zero, warn and proceed
1136 * with the next step.
1138 if (ip
->meta
.nlinks
) {
1139 if ((ip
->meta
.name_key
& HAMMER2_DIRHASH_VISIBLE
) == 0)
1141 kprintf("hammer2_inode_unlink: nlinks was not 0 (%jd)\n",
1142 (intmax_t)ip
->meta
.nlinks
);
1147 hammer2_knote(ip
->vp
, NOTE_DELETE
);
1150 * nlinks is now zero, delete the inode if not open.
1153 hammer2_xop_destroy_t
*xop
;
1156 atomic_set_int(&ip
->flags
, HAMMER2_INODE_ISDELETED
);
1157 xop
= hammer2_xop_alloc(ip
, HAMMER2_XOP_MODIFYING
);
1158 hammer2_xop_start(&xop
->head
, hammer2_inode_xop_destroy
);
1159 error
= hammer2_xop_collect(&xop
->head
, 0);
1160 hammer2_xop_retire(&xop
->head
, HAMMER2_XOPMASK_VOP
);
1167 * Mark an inode as being modified, meaning that the caller will modify
1170 * If a vnode is present we set the vnode dirty and the nominal filesystem
1171 * sync will also handle synchronizing the inode meta-data. If no vnode
1172 * is present we must ensure that the inode is on pmp->sideq.
1174 * NOTE: No mtid (modify_tid) is passed into this routine. The caller is
1175 * only modifying the in-memory inode. A modify_tid is synchronized
1176 * later when the inode gets flushed.
1179 hammer2_inode_modify(hammer2_inode_t
*ip
)
1183 atomic_set_int(&ip
->flags
, HAMMER2_INODE_MODIFIED
);
1185 vsetisdirty(ip
->vp
);
1186 } else if ((pmp
= ip
->pmp
) != NULL
) {
1187 hammer2_inode_delayed_sideq(ip
);
1192 * Synchronize the inode's frontend state with the chain state prior
1193 * to any explicit flush of the inode or any strategy write call.
1195 * Called with a locked inode inside a transaction.
1198 hammer2_inode_chain_sync(hammer2_inode_t
*ip
)
1200 if (ip
->flags
& (HAMMER2_INODE_RESIZED
| HAMMER2_INODE_MODIFIED
)) {
1201 hammer2_xop_fsync_t
*xop
;
1204 xop
= hammer2_xop_alloc(ip
, HAMMER2_XOP_MODIFYING
);
1205 xop
->clear_directdata
= 0;
1206 if (ip
->flags
& HAMMER2_INODE_RESIZED
) {
1207 if ((ip
->meta
.op_flags
& HAMMER2_OPFLAG_DIRECTDATA
) &&
1208 ip
->meta
.size
> HAMMER2_EMBEDDED_BYTES
) {
1209 ip
->meta
.op_flags
&= ~HAMMER2_OPFLAG_DIRECTDATA
;
1210 xop
->clear_directdata
= 1;
1212 xop
->osize
= ip
->osize
;
1214 xop
->osize
= ip
->meta
.size
; /* safety */
1216 xop
->ipflags
= ip
->flags
;
1217 xop
->meta
= ip
->meta
;
1219 atomic_clear_int(&ip
->flags
, HAMMER2_INODE_RESIZED
|
1220 HAMMER2_INODE_MODIFIED
);
1221 hammer2_xop_start(&xop
->head
, hammer2_inode_xop_chain_sync
);
1222 error
= hammer2_xop_collect(&xop
->head
, 0);
1223 hammer2_xop_retire(&xop
->head
, HAMMER2_XOPMASK_VOP
);
1224 if (error
== ENOENT
)
1227 kprintf("hammer2: unable to fsync inode %p\n", ip
);
1229 atomic_set_int(&ip->flags,
1230 xop->ipflags & (HAMMER2_INODE_RESIZED |
1231 HAMMER2_INODE_MODIFIED));
1233 /* XXX return error somehow? */
1239 * The normal filesystem sync no longer has visibility to an inode structure
1240 * after its vnode has been reclaimed. In this situation an unlinked-but-open
1241 * inode or a dirty inode may require additional processing to synchronize
1242 * ip->meta to its underlying cluster nodes.
1244 * In particular, reclaims can occur in almost any state (for example, when
1245 * doing operations on unrelated vnodes) and flushing the reclaimed inode
1246 * in the reclaim path itself is a non-starter.
1248 * Caller must be in a transaction.
1251 hammer2_inode_run_sideq(hammer2_pfs_t
*pmp
)
1253 hammer2_xop_destroy_t
*xop
;
1254 hammer2_inode_sideq_t
*ipul
;
1255 hammer2_inode_t
*ip
;
1258 if (TAILQ_EMPTY(&pmp
->sideq
))
1261 hammer2_spin_ex(&pmp
->list_spin
);
1262 while ((ipul
= TAILQ_FIRST(&pmp
->sideq
)) != NULL
) {
1263 TAILQ_REMOVE(&pmp
->sideq
, ipul
, entry
);
1265 KKASSERT(ip
->flags
& HAMMER2_INODE_ONSIDEQ
);
1266 atomic_clear_int(&ip
->flags
, HAMMER2_INODE_ONSIDEQ
);
1267 hammer2_spin_unex(&pmp
->list_spin
);
1268 kfree(ipul
, pmp
->minode
);
1270 hammer2_inode_lock(ip
, 0);
1271 if (ip
->flags
& HAMMER2_INODE_ISUNLINKED
) {
1273 * The inode was unlinked while open. The inode must
1274 * be deleted and destroyed.
1276 xop
= hammer2_xop_alloc(ip
, HAMMER2_XOP_MODIFYING
);
1277 hammer2_xop_start(&xop
->head
,
1278 hammer2_inode_xop_destroy
);
1279 error
= hammer2_xop_collect(&xop
->head
, 0);
1280 hammer2_xop_retire(&xop
->head
, HAMMER2_XOPMASK_VOP
);
1283 * The inode was dirty as-of the reclaim, requiring
1284 * synchronization of ip->meta with its underlying
1287 hammer2_inode_chain_sync(ip
);
1290 hammer2_inode_unlock(ip
);
1291 hammer2_inode_drop(ip
); /* ipul ref */
1293 hammer2_spin_ex(&pmp
->list_spin
);
1295 hammer2_spin_unex(&pmp
->list_spin
);
1299 * Helper to create a directory entry.
1302 hammer2_inode_xop_mkdirent(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
1304 hammer2_xop_mkdirent_t
*xop
= &arg
->xop_mkdirent
;
1305 hammer2_chain_t
*parent
;
1306 hammer2_chain_t
*chain
;
1307 hammer2_key_t key_next
;
1309 int cache_index
= -1;
1312 if (hammer2_debug
& 0x0001)
1313 kprintf("dirent_create lhc %016jx clindex %d\n",
1314 xop
->lhc
, thr
->clindex
);
1316 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
1317 HAMMER2_RESOLVE_ALWAYS
);
1318 if (parent
== NULL
) {
1323 chain
= hammer2_chain_lookup(&parent
, &key_next
,
1332 * We may be able to embed the directory entry directly in the
1335 if (xop
->dirent
.namlen
<= sizeof(chain
->bref
.check
.buf
))
1338 data_len
= HAMMER2_ALLOC_MIN
;
1340 error
= hammer2_chain_create(&parent
, &chain
,
1341 xop
->head
.ip1
->pmp
, HAMMER2_METH_DEFAULT
,
1343 HAMMER2_BREF_TYPE_DIRENT
,
1345 xop
->head
.mtid
, 0, 0);
1348 * WARNING: chain->data->buf is sized to chain->bytes,
1349 * do not use sizeof(chain->data->buf), which
1350 * will be much larger.
1352 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
1354 chain
->bref
.embed
.dirent
= xop
->dirent
;
1355 if (xop
->dirent
.namlen
<= sizeof(chain
->bref
.check
.buf
))
1356 bcopy(xop
->head
.name1
, chain
->bref
.check
.buf
,
1357 xop
->dirent
.namlen
);
1359 bcopy(xop
->head
.name1
, chain
->data
->buf
,
1360 xop
->dirent
.namlen
);
1364 hammer2_chain_unlock(parent
);
1365 hammer2_chain_drop(parent
);
1367 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
1369 hammer2_chain_unlock(chain
);
1370 hammer2_chain_drop(chain
);
1375 * Inode create helper (threaded, backend)
1377 * Used by ncreate, nmknod, nsymlink, nmkdir.
1378 * Used by nlink and rename to create HARDLINK pointers.
1380 * Frontend holds the parent directory ip locked exclusively. We
1381 * create the inode and feed the exclusively locked chain to the
1385 hammer2_inode_xop_create(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
1387 hammer2_xop_create_t
*xop
= &arg
->xop_create
;
1388 hammer2_chain_t
*parent
;
1389 hammer2_chain_t
*chain
;
1390 hammer2_key_t key_next
;
1391 int cache_index
= -1;
1394 if (hammer2_debug
& 0x0001)
1395 kprintf("inode_create lhc %016jx clindex %d\n",
1396 xop
->lhc
, thr
->clindex
);
1398 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
1399 HAMMER2_RESOLVE_ALWAYS
);
1400 if (parent
== NULL
) {
1405 chain
= hammer2_chain_lookup(&parent
, &key_next
,
1413 error
= hammer2_chain_create(&parent
, &chain
,
1414 xop
->head
.ip1
->pmp
, HAMMER2_METH_DEFAULT
,
1416 HAMMER2_BREF_TYPE_INODE
,
1417 HAMMER2_INODE_BYTES
,
1418 xop
->head
.mtid
, 0, xop
->flags
);
1420 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
1421 chain
->data
->ipdata
.meta
= xop
->meta
;
1422 if (xop
->head
.name1
) {
1423 bcopy(xop
->head
.name1
,
1424 chain
->data
->ipdata
.filename
,
1425 xop
->head
.name1_len
);
1426 chain
->data
->ipdata
.meta
.name_len
= xop
->head
.name1_len
;
1428 chain
->data
->ipdata
.meta
.name_key
= xop
->lhc
;
1432 hammer2_chain_unlock(parent
);
1433 hammer2_chain_drop(parent
);
1435 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, error
);
1437 hammer2_chain_unlock(chain
);
1438 hammer2_chain_drop(chain
);
1443 * Inode delete helper (backend, threaded)
1445 * Generally used by hammer2_run_sideq()
1448 hammer2_inode_xop_destroy(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
1450 hammer2_xop_destroy_t
*xop
= &arg
->xop_destroy
;
1452 hammer2_chain_t
*parent
;
1453 hammer2_chain_t
*chain
;
1454 hammer2_inode_t
*ip
;
1458 * We need the precise parent chain to issue the deletion.
1463 chain
= hammer2_inode_chain(ip
, thr
->clindex
, HAMMER2_RESOLVE_ALWAYS
);
1464 if (chain
== NULL
) {
1469 parent
= hammer2_chain_getparent(chain
, HAMMER2_RESOLVE_ALWAYS
);
1470 if (parent
== NULL
) {
1474 KKASSERT(chain
->parent
== parent
);
1477 * We have the correct parent, we can issue the deletion.
1479 hammer2_chain_delete(parent
, chain
, xop
->head
.mtid
, 0);
1482 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
1484 hammer2_chain_unlock(parent
);
1485 hammer2_chain_drop(parent
);
1488 hammer2_chain_unlock(chain
);
1489 hammer2_chain_drop(chain
);
1494 hammer2_inode_xop_unlinkall(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
1496 hammer2_xop_unlinkall_t
*xop
= &arg
->xop_unlinkall
;
1497 hammer2_chain_t
*parent
;
1498 hammer2_chain_t
*chain
;
1499 hammer2_key_t key_next
;
1500 int cache_index
= -1;
1503 * We need the precise parent chain to issue the deletion.
1505 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
1506 HAMMER2_RESOLVE_ALWAYS
);
1508 if (parent
== NULL
) {
1512 chain
= hammer2_chain_lookup(&parent
, &key_next
,
1513 xop
->key_beg
, xop
->key_end
,
1515 HAMMER2_LOOKUP_ALWAYS
);
1517 hammer2_chain_delete(parent
, chain
,
1518 xop
->head
.mtid
, HAMMER2_DELETE_PERMANENT
);
1519 hammer2_xop_feed(&xop
->head
, chain
, thr
->clindex
, chain
->error
);
1520 /* depend on function to unlock the shared lock */
1521 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
1522 key_next
, xop
->key_end
,
1524 HAMMER2_LOOKUP_ALWAYS
);
1527 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, ENOENT
);
1529 hammer2_chain_unlock(parent
);
1530 hammer2_chain_drop(parent
);
1533 hammer2_chain_unlock(chain
);
1534 hammer2_chain_drop(chain
);
1539 hammer2_inode_xop_connect(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
1541 hammer2_xop_connect_t
*xop
= &arg
->xop_connect
;
1542 hammer2_inode_data_t
*wipdata
;
1543 hammer2_chain_t
*parent
;
1544 hammer2_chain_t
*chain
;
1546 hammer2_key_t key_dummy
;
1547 int cache_index
= -1;
1551 * Get directory, then issue a lookup to prime the parent chain
1552 * for the create. The lookup is expected to fail.
1554 pmp
= xop
->head
.ip1
->pmp
;
1555 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
1556 HAMMER2_RESOLVE_ALWAYS
);
1557 if (parent
== NULL
) {
1562 chain
= hammer2_chain_lookup(&parent
, &key_dummy
,
1566 hammer2_chain_unlock(chain
);
1567 hammer2_chain_drop(chain
);
1574 * Adjust the filename in the inode, set the name key.
1576 * NOTE: Frontend must also adjust ip2->meta on success, we can't
1579 chain
= hammer2_inode_chain(xop
->head
.ip2
, thr
->clindex
,
1580 HAMMER2_RESOLVE_ALWAYS
);
1581 hammer2_chain_modify(chain
, xop
->head
.mtid
, 0, 0);
1582 wipdata
= &chain
->data
->ipdata
;
1584 hammer2_inode_modify(xop
->head
.ip2
);
1585 if (xop
->head
.name1
) {
1586 bzero(wipdata
->filename
, sizeof(wipdata
->filename
));
1587 bcopy(xop
->head
.name1
, wipdata
->filename
, xop
->head
.name1_len
);
1588 wipdata
->meta
.name_len
= xop
->head
.name1_len
;
1590 wipdata
->meta
.name_key
= xop
->lhc
;
1593 * Reconnect the chain to the new parent directory
1595 error
= hammer2_chain_create(&parent
, &chain
,
1596 pmp
, HAMMER2_METH_DEFAULT
,
1598 HAMMER2_BREF_TYPE_INODE
,
1599 HAMMER2_INODE_BYTES
,
1600 xop
->head
.mtid
, 0, 0);
1606 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);
1608 hammer2_chain_unlock(parent
);
1609 hammer2_chain_drop(parent
);
1612 hammer2_chain_unlock(chain
);
1613 hammer2_chain_drop(chain
);
1618 * Synchronize the in-memory inode with the chain.
1621 hammer2_inode_xop_chain_sync(hammer2_thread_t
*thr
, hammer2_xop_t
*arg
)
1623 hammer2_xop_fsync_t
*xop
= &arg
->xop_fsync
;
1624 hammer2_chain_t
*parent
;
1625 hammer2_chain_t
*chain
;
1628 parent
= hammer2_inode_chain(xop
->head
.ip1
, thr
->clindex
,
1629 HAMMER2_RESOLVE_ALWAYS
);
1631 if (parent
== NULL
) {
1635 if (parent
->error
) {
1636 error
= parent
->error
;
1642 if ((xop
->ipflags
& HAMMER2_INODE_RESIZED
) == 0) {
1643 /* osize must be ignored */
1644 } else if (xop
->meta
.size
< xop
->osize
) {
1646 * We must delete any chains beyond the EOF. The chain
1647 * straddling the EOF will be pending in the bioq.
1649 hammer2_key_t lbase
;
1650 hammer2_key_t key_next
;
1651 int cache_index
= -1;
1653 lbase
= (xop
->meta
.size
+ HAMMER2_PBUFMASK64
) &
1654 ~HAMMER2_PBUFMASK64
;
1655 chain
= hammer2_chain_lookup(&parent
, &key_next
,
1656 lbase
, HAMMER2_KEY_MAX
,
1658 HAMMER2_LOOKUP_NODATA
|
1659 HAMMER2_LOOKUP_NODIRECT
);
1662 * Degenerate embedded case, nothing to loop on
1664 switch (chain
->bref
.type
) {
1665 case HAMMER2_BREF_TYPE_DIRENT
:
1666 case HAMMER2_BREF_TYPE_INODE
:
1669 case HAMMER2_BREF_TYPE_DATA
:
1670 hammer2_chain_delete(parent
, chain
,
1672 HAMMER2_DELETE_PERMANENT
);
1675 chain
= hammer2_chain_next(&parent
, chain
, &key_next
,
1676 key_next
, HAMMER2_KEY_MAX
,
1678 HAMMER2_LOOKUP_NODATA
|
1679 HAMMER2_LOOKUP_NODIRECT
);
1683 * Reset to point at inode for following code, if necessary.
1685 if (parent
->bref
.type
!= HAMMER2_BREF_TYPE_INODE
) {
1686 hammer2_chain_unlock(parent
);
1687 hammer2_chain_drop(parent
);
1688 parent
= hammer2_inode_chain(xop
->head
.ip1
,
1690 HAMMER2_RESOLVE_ALWAYS
);
1691 kprintf("hammer2: TRUNCATE RESET on '%s'\n",
1692 parent
->data
->ipdata
.filename
);
1697 * Sync the inode meta-data, potentially clear the blockset area
1698 * of direct data so it can be used for blockrefs.
1700 hammer2_chain_modify(parent
, xop
->head
.mtid
, 0, 0);
1701 parent
->data
->ipdata
.meta
= xop
->meta
;
1702 if (xop
->clear_directdata
) {
1703 bzero(&parent
->data
->ipdata
.u
.blockset
,
1704 sizeof(parent
->data
->ipdata
.u
.blockset
));
1708 hammer2_chain_unlock(chain
);
1709 hammer2_chain_drop(chain
);
1712 hammer2_chain_unlock(parent
);
1713 hammer2_chain_drop(parent
);
1715 hammer2_xop_feed(&xop
->head
, NULL
, thr
->clindex
, error
);