2 * Copyright (c) 2011-2012 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>
45 * Adding a ref to an inode is only legal if the inode already has at least
49 hammer2_inode_ref(hammer2_inode_t *ip)
51 hammer2_chain_ref(ip->hmp, &ip->chain);
55 * Drop an inode reference, freeing the inode when the last reference goes
59 hammer2_inode_drop(hammer2_inode_t *ip)
61 hammer2_chain_drop(ip->hmp, &ip->chain);
65 * Get the vnode associated with the given inode, allocating the vnode if
68 * Great care must be taken to avoid deadlocks and vnode acquisition/reclaim
71 * The vnode will be returned exclusively locked and referenced. The
72 * reference on the vnode prevents it from being reclaimed.
74 * The inode (ip) must be referenced by the caller and not locked to avoid
75 * it getting ripped out from under us or deadlocked.
78 hammer2_igetv(hammer2_inode_t *ip, int *errorp)
81 hammer2_pfsmount_t *pmp;
84 KKASSERT(pmp != NULL);
89 * Attempt to reuse an existing vnode assignment. It is
90 * possible to race a reclaim so the vget() may fail. The
91 * inode must be unlocked during the vget() to avoid a
92 * deadlock against a reclaim.
97 * Lock the inode and check for a reclaim race
99 hammer2_inode_lock_ex(ip);
101 hammer2_inode_unlock_ex(ip);
106 * Inode must be unlocked during the vget() to avoid
107 * possible deadlocks, vnode is held to prevent
108 * destruction during the vget(). The vget() can
109 * still fail if we lost a reclaim race on the vnode.
111 vhold_interlocked(vp);
112 hammer2_inode_unlock_ex(ip);
113 if (vget(vp, LK_EXCLUSIVE)) {
118 /* vp still locked and ref from vget */
124 * No vnode exists, allocate a new vnode. Beware of
125 * allocation races. This function will return an
126 * exclusively locked and referenced vnode.
128 *errorp = getnewvnode(VT_HAMMER2, pmp->mp, &vp, 0, 0);
135 * Lock the inode and check for an allocation race.
137 hammer2_inode_lock_ex(ip);
138 if (ip->vp != NULL) {
141 hammer2_inode_unlock_ex(ip);
145 switch (ip->ip_data.type) {
146 case HAMMER2_OBJTYPE_DIRECTORY:
149 case HAMMER2_OBJTYPE_REGFILE:
151 vinitvmio(vp, ip->ip_data.size,
153 (int)ip->ip_data.size & HAMMER2_LBUFMASK);
155 case HAMMER2_OBJTYPE_SOFTLINK:
157 * XXX for now we are using the generic file_read
158 * and file_write code so we need a buffer cache
162 vinitvmio(vp, ip->ip_data.size,
164 (int)ip->ip_data.size & HAMMER2_LBUFMASK);
168 panic("hammer2: unhandled objtype %d",
173 if (ip == pmp->iroot)
174 vsetflags(vp, VROOT);
178 hammer2_chain_ref(ip->hmp, &ip->chain); /* vp association */
179 hammer2_inode_unlock_ex(ip);
184 * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0.
186 if (hammer2_debug & 0x0002) {
187 kprintf("igetv vp %p refs %d aux %d\n",
188 vp, vp->v_sysref.refcnt, vp->v_auxrefs);
194 * Create a new inode in the specified directory using the vattr to
195 * figure out the type of inode.
197 * If no error occurs the new inode with its chain locked is returned in
198 * *nipp, otherwise an error is returned and *nipp is set to NULL.
200 * If vap and/or cred are NULL the related fields are not set and the
201 * inode type defaults to a directory. This is used when creating PFSs
202 * under the super-root, so the inode number is set to 1 in this case.
205 hammer2_inode_create(hammer2_inode_t *dip,
206 struct vattr *vap, struct ucred *cred,
207 const uint8_t *name, size_t name_len,
208 hammer2_inode_t **nipp)
210 hammer2_mount_t *hmp = dip->hmp;
211 hammer2_chain_t *chain;
212 hammer2_chain_t *parent;
213 hammer2_inode_t *nip;
218 lhc = hammer2_dirhash(name, name_len);
221 * Locate the inode or indirect block to create the new
222 * entry in. At the same time check for key collisions
223 * and iterate until we don't get one.
225 parent = &dip->chain;
226 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
230 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
233 if ((lhc & HAMMER2_DIRHASH_VISIBLE) == 0)
235 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
237 hammer2_chain_unlock(hmp, chain);
242 chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0,
243 HAMMER2_BREF_TYPE_INODE,
244 HAMMER2_INODE_BYTES);
248 hammer2_chain_unlock(hmp, parent);
251 * Handle the error case
254 KKASSERT(chain == NULL);
260 * Set up the new inode
265 hammer2_voldata_lock(hmp);
267 nip->ip_data.type = hammer2_get_obj_type(vap->va_type);
268 nip->ip_data.inum = hmp->voldata.alloc_tid++;
269 /* XXX modify/lock */
271 nip->ip_data.type = HAMMER2_OBJTYPE_DIRECTORY;
272 nip->ip_data.inum = 1;
274 hammer2_voldata_unlock(hmp);
275 nip->ip_data.version = HAMMER2_INODE_VERSION_ONE;
276 hammer2_update_time(&nip->ip_data.ctime);
277 nip->ip_data.mtime = nip->ip_data.ctime;
279 nip->ip_data.mode = vap->va_mode;
280 nip->ip_data.nlinks = 1;
283 xuid = hammer2_to_unix_xid(&dip->ip_data.uid);
284 xuid = vop_helper_create_uid(dip->pmp->mp,
292 if (vap->va_vaflags & VA_UID_UUID_VALID)
293 nip->ip_data.uid = vap->va_uid_uuid;
294 else if (vap->va_uid != (uid_t)VNOVAL)
295 hammer2_guid_to_uuid(&nip->ip_data.uid, vap->va_uid);
297 hammer2_guid_to_uuid(&nip->ip_data.uid, xuid);
299 if (vap->va_vaflags & VA_GID_UUID_VALID)
300 nip->ip_data.gid = vap->va_gid_uuid;
301 else if (vap->va_gid != (gid_t)VNOVAL)
302 hammer2_guid_to_uuid(&nip->ip_data.gid, vap->va_gid);
304 nip->ip_data.gid = dip->ip_data.gid;
308 * Regular files and softlinks allow a small amount of data to be
309 * directly embedded in the inode. This flag will be cleared if
310 * the size is extended past the embedded limit.
312 if (nip->ip_data.type == HAMMER2_OBJTYPE_REGFILE ||
313 nip->ip_data.type == HAMMER2_OBJTYPE_SOFTLINK) {
314 nip->ip_data.op_flags |= HAMMER2_OPFLAG_DIRECTDATA;
317 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
318 bcopy(name, nip->ip_data.filename, name_len);
319 nip->ip_data.name_key = lhc;
320 nip->ip_data.name_len = name_len;
326 * Duplicate the specified existing inode in the specified target directory.
327 * If name is NULL the inode is duplicated as a hidden directory entry.
329 * Returns the new inode. The old inode is left alone.
331 * XXX name needs to be NULL for now.
334 hammer2_inode_duplicate(hammer2_inode_t *dip, hammer2_inode_t *oip,
335 hammer2_inode_t **nipp,
336 const uint8_t *name, size_t name_len)
338 hammer2_mount_t *hmp = dip->hmp;
339 hammer2_inode_t *nip;
340 hammer2_chain_t *parent;
341 hammer2_chain_t *chain;
346 lhc = hammer2_dirhash(name, name_len);
348 lhc = oip->ip_data.inum;
349 KKASSERT((lhc & HAMMER2_DIRHASH_VISIBLE) == 0);
353 * Locate the inode or indirect block to create the new
354 * entry in. At the same time check for key collisions
355 * and iterate until we don't get one.
358 parent = &dip->chain;
359 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
363 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
366 /* XXX bcmp name if not NULL */
367 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
369 if ((lhc & HAMMER2_DIRHASH_VISIBLE) == 0) /* shouldn't happen */
371 hammer2_chain_unlock(hmp, chain);
377 * Create entry in common parent directory.
380 chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0,
381 HAMMER2_BREF_TYPE_INODE /* n/a */,
382 HAMMER2_INODE_BYTES); /* n/a */
386 hammer2_chain_unlock(hmp, parent);
389 * Handle the error case
392 KKASSERT(chain == NULL);
397 * XXX This is currently a horrible hack. Well, if we wanted to
398 * duplicate a file, i.e. as in a snapshot, we definitely
399 * would have to flush it first.
401 * For hardlink target generation we can theoretically move any
402 * active chain structures without flushing, but that gets really
403 * iffy for code which follows chain->parent and ip->pip links.
405 * XXX only works with files. Duplicating a directory hierarchy
406 * requires a flush but doesn't deal with races post-flush.
407 * Well, it would work I guess, but you might catch some files
410 * We cannot leave oip with any in-memory chains because (for a
411 * hardlink), oip will become a OBJTYPE_HARDLINK which is just a
412 * pointer to the real hardlink's inum and can't have any sub-chains.
414 hammer2_inode_lock_ex(oip);
415 hammer2_chain_flush(hmp, &oip->chain, 0);
416 hammer2_inode_unlock_ex(oip);
417 KKASSERT(SPLAY_EMPTY(&oip->chain.shead));
420 hammer2_chain_modify(hmp, chain, 0);
421 nip->ip_data = oip->ip_data; /* sync media data after flush */
425 * Directory entries are inodes so if the name has changed
426 * we have to update the inode.
428 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
429 bcopy(name, nip->ip_data.filename, name_len);
430 nip->ip_data.name_key = lhc;
431 nip->ip_data.name_len = name_len;
434 * Directory entries are inodes but this is a hidden hardlink
435 * target. The name isn't used but to ease debugging give it
436 * a name after its inode number.
438 ksnprintf(nip->ip_data.filename, sizeof(nip->ip_data.filename),
439 "0x%016jx", (intmax_t)nip->ip_data.inum);
440 nip->ip_data.name_len = strlen(nip->ip_data.filename);
441 nip->ip_data.name_key = lhc;
450 * Connect inode (oip) to the specified directory using the specified name.
451 * (oip) must be locked.
453 * If (oip) is not currently connected we simply connect it up.
455 * If (oip) is already connected we create a OBJTYPE_HARDLINK entry which
456 * points to (oip)'s inode number. (oip) is expected to be the terminus of
457 * the hardlink sitting as a hidden file in a common parent directory
458 * in this situation (thus the lock order is correct).
461 hammer2_inode_connect(hammer2_inode_t *dip, hammer2_inode_t *oip,
462 const uint8_t *name, size_t name_len)
464 hammer2_mount_t *hmp = dip->hmp;
465 hammer2_chain_t *chain;
466 hammer2_chain_t *parent;
467 hammer2_inode_t *nip;
472 lhc = hammer2_dirhash(name, name_len);
473 hlink = (oip->chain.parent != NULL);
476 * In fake mode flush oip so we can just snapshot it downbelow.
478 if (hlink && hammer2_hardlink_enable < 0)
479 hammer2_chain_flush(hmp, &oip->chain, 0);
482 * Locate the inode or indirect block to create the new
483 * entry in. At the same time check for key collisions
484 * and iterate until we don't get one.
486 parent = &dip->chain;
487 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
491 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
494 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
496 hammer2_chain_unlock(hmp, chain);
502 * Passing a non-NULL chain to hammer2_chain_create() reconnects the
503 * existing chain instead of creating a new one. The chain's bref
504 * will be properly updated.
508 chain = hammer2_chain_create(hmp, parent,
510 HAMMER2_BREF_TYPE_INODE,
511 HAMMER2_INODE_BYTES);
513 chain = hammer2_chain_create(hmp, parent,
515 HAMMER2_BREF_TYPE_INODE,
516 HAMMER2_INODE_BYTES);
518 KKASSERT(chain == &oip->chain);
523 hammer2_chain_unlock(hmp, parent);
526 * Handle the error case
529 KKASSERT(chain == NULL);
534 * Directory entries are inodes so if the name has changed we have
535 * to update the inode.
537 * When creating an OBJTYPE_HARDLINK entry remember to unlock the
538 * chain, the caller will access the hardlink via the actual hardlink
539 * target file and not the hardlink pointer entry.
541 if (hlink && hammer2_hardlink_enable >= 0) {
543 * Create the HARDLINK pointer. oip represents the hardlink
544 * target in this situation.
547 hammer2_chain_modify(hmp, chain, 0);
548 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
549 bcopy(name, nip->ip_data.filename, name_len);
550 nip->ip_data.name_key = lhc;
551 nip->ip_data.name_len = name_len;
552 nip->ip_data.target_type = oip->ip_data.type;
553 nip->ip_data.type = HAMMER2_OBJTYPE_HARDLINK;
554 nip->ip_data.inum = oip->ip_data.inum;
555 nip->ip_data.nlinks = 1;
556 kprintf("created hardlink %*.*s\n",
557 (int)name_len, (int)name_len, name);
558 hammer2_chain_unlock(hmp, chain);
559 } else if (hlink && hammer2_hardlink_enable < 0) {
561 * Create a snapshot (hardlink fake mode for debugging).
564 nip->ip_data = oip->ip_data;
565 hammer2_chain_modify(hmp, chain, 0);
566 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
567 bcopy(name, nip->ip_data.filename, name_len);
568 nip->ip_data.name_key = lhc;
569 nip->ip_data.name_len = name_len;
570 kprintf("created fake hardlink %*.*s\n",
571 (int)name_len, (int)name_len, name);
572 hammer2_chain_unlock(hmp, chain);
575 * Normally disconnected inode (e.g. during a rename) that
576 * was reconnected. We must fixup the name stored in
579 * We are using oip as chain, already locked by caller,
582 hammer2_chain_modify(hmp, chain, 0);
583 if (oip->ip_data.name_len != name_len ||
584 bcmp(oip->ip_data.filename, name, name_len) != 0) {
585 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
586 bcopy(name, oip->ip_data.filename, name_len);
587 oip->ip_data.name_key = lhc;
588 oip->ip_data.name_len = name_len;
590 oip->ip_data.nlinks = 1;
597 * Unlink the file from the specified directory inode. The directory inode
598 * does not need to be locked.
600 * isdir determines whether a directory/non-directory check should be made.
601 * No check is made if isdir is set to -1.
604 hammer2_unlink_file(hammer2_inode_t *dip,
605 const uint8_t *name, size_t name_len,
606 int isdir, hammer2_inode_t *retain_ip)
608 hammer2_mount_t *hmp;
609 hammer2_chain_t *parent;
610 hammer2_chain_t *chain;
611 hammer2_chain_t *dparent;
612 hammer2_chain_t *dchain;
615 hammer2_inode_t *oip;
622 lhc = hammer2_dirhash(name, name_len);
625 * Search for the filename in the directory
627 parent = &dip->chain;
628 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
629 chain = hammer2_chain_lookup(hmp, &parent,
630 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
633 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
635 name_len == chain->data->ipdata.name_len &&
636 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
639 chain = hammer2_chain_next(hmp, &parent, chain,
640 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
645 * Not found or wrong type (isdir < 0 disables the type check).
648 hammer2_chain_unlock(hmp, parent);
651 if ((type = chain->data->ipdata.type) == HAMMER2_OBJTYPE_HARDLINK)
652 type = chain->data->ipdata.target_type;
654 if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir == 0) {
658 if (type != HAMMER2_OBJTYPE_DIRECTORY && isdir == 1) {
664 * Hardlink must be resolved. We can't hold parent locked while we
665 * do this or we could deadlock.
667 if (chain->data->ipdata.type == HAMMER2_OBJTYPE_HARDLINK) {
668 hammer2_chain_unlock(hmp, parent);
670 error = hammer2_hardlink_find(dip, &chain, &oip);
674 * If this is a directory the directory must be empty. However, if
675 * isdir < 0 we are doing a rename and the directory does not have
678 * NOTE: We check the full key range here which covers both visible
679 * and invisible entries. Theoretically there should be no
680 * invisible (hardlink target) entries if there are no visible
683 if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir >= 0) {
685 hammer2_chain_lock(hmp, dparent, HAMMER2_RESOLVE_ALWAYS);
686 dchain = hammer2_chain_lookup(hmp, &dparent,
687 0, (hammer2_key_t)-1,
688 HAMMER2_LOOKUP_NODATA);
690 hammer2_chain_unlock(hmp, dchain);
691 hammer2_chain_unlock(hmp, dparent);
695 hammer2_chain_unlock(hmp, dparent);
701 * Ok, we can now unlink the chain. We always decrement nlinks even
702 * if the entry can be deleted in case someone has the file open and
705 * The chain itself will no longer be in the on-media topology but
706 * can still be flushed to the media (e.g. if an open descriptor
707 * remains). When the last vnode/ip ref goes away the chain will
708 * be marked unmodified, avoiding any further (now unnecesary) I/O.
712 * If this was a hardlink we first delete the hardlink
715 parent = oip->chain.parent;
716 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
717 hammer2_chain_lock(hmp, &oip->chain, HAMMER2_RESOLVE_ALWAYS);
718 hammer2_chain_delete(hmp, parent, &oip->chain,
720 hammer2_chain_unlock(hmp, &oip->chain);
721 hammer2_chain_unlock(hmp, parent);
725 * Then decrement nlinks on hardlink target.
728 if (ip->ip_data.nlinks == 1) {
729 dparent = chain->parent;
730 hammer2_chain_ref(hmp, chain);
731 hammer2_chain_unlock(hmp, chain);
732 hammer2_chain_lock(hmp, dparent,
733 HAMMER2_RESOLVE_ALWAYS);
734 hammer2_chain_lock(hmp, chain, HAMMER2_RESOLVE_ALWAYS);
735 hammer2_chain_drop(hmp, chain);
736 hammer2_chain_modify(hmp, chain, 0);
737 --ip->ip_data.nlinks;
738 hammer2_chain_delete(hmp, dparent, chain, 0);
739 hammer2_chain_unlock(hmp, dparent);
741 hammer2_chain_modify(hmp, chain, 0);
742 --ip->ip_data.nlinks;
746 * Otherwise this was not a hardlink and we can just
747 * remove the entry and decrement nlinks.
750 hammer2_chain_modify(hmp, chain, 0);
751 --ip->ip_data.nlinks;
752 hammer2_chain_delete(hmp, parent, chain,
760 hammer2_chain_unlock(hmp, chain);
762 hammer2_chain_unlock(hmp, parent);
764 hammer2_chain_drop(oip->hmp, &oip->chain);
770 * Calculate the allocation size for the file fragment straddling EOF
773 hammer2_inode_calc_alloc(hammer2_key_t filesize)
775 int frag = (int)filesize & HAMMER2_PBUFMASK;
780 for (radix = HAMMER2_MINALLOCRADIX; frag > (1 << radix); ++radix)
786 hammer2_inode_lock_nlinks(hammer2_inode_t *ip)
788 hammer2_chain_ref(ip->hmp, &ip->chain);
792 hammer2_inode_unlock_nlinks(hammer2_inode_t *ip)
794 hammer2_chain_drop(ip->hmp, &ip->chain);
798 * Consolidate for hard link creation. This moves the specified terminal
799 * hardlink inode to a directory common to its current directory and tdip
800 * if necessary, replacing *ipp with the new inode chain element and
801 * modifying the original inode chain element to OBJTYPE_HARDLINK.
803 * If the original inode chain element was a prior incarnation of a hidden
804 * inode it can simply be deleted instead of converted.
806 * (*ipp)'s nlinks field is locked on entry and the new (*ipp)'s nlinks
807 * field will be locked on return (with the original's unlocked).
809 * The link count is bumped if requested.
812 hammer2_hardlink_consolidate(hammer2_inode_t **ipp, hammer2_inode_t *tdip)
814 hammer2_mount_t *hmp;
815 hammer2_inode_t *oip = *ipp;
816 hammer2_inode_t *nip = NULL;
817 hammer2_inode_t *fdip;
818 hammer2_chain_t *parent;
823 if (hammer2_hardlink_enable < 0)
825 if (hammer2_hardlink_enable == 0)
829 * Find the common parent directory
832 while (fdip->depth > tdip->depth) {
834 KKASSERT(fdip != NULL);
836 while (tdip->depth > fdip->depth) {
838 KKASSERT(tdip != NULL);
840 while (fdip != tdip) {
843 KKASSERT(fdip != NULL);
844 KKASSERT(tdip != NULL);
848 * Nothing to do (except bump the link count) if the hardlink has
849 * already been consolidated in the correct place.
851 if (oip->pip == fdip &&
852 (oip->ip_data.name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
853 kprintf("hardlink already consolidated correctly\n");
855 hammer2_inode_lock_ex(nip);
856 hammer2_chain_modify(hmp, &nip->chain, 0);
857 ++nip->ip_data.nlinks;
858 hammer2_inode_unlock_ex(nip);
863 * Create a hidden inode directory entry in the parent, copying
864 * (*oip)'s state. Then replace oip with OBJTYPE_HARDLINK.
866 * The duplication function will either flush or move any chains
867 * under oip to the new hardlink target inode, retiring all chains
868 * related to oip before returning. XXX vp->ip races.
870 error = hammer2_inode_duplicate(fdip, oip, &nip, NULL, 0);
873 * Bump nlinks on duplicated hidden inode.
875 kprintf("hardlink consolidation success in parent dir %s\n",
876 fdip->ip_data.filename);
877 hammer2_inode_lock_nlinks(nip);
878 hammer2_inode_unlock_nlinks(oip);
879 hammer2_chain_modify(hmp, &nip->chain, 0);
880 ++nip->ip_data.nlinks;
881 hammer2_inode_unlock_ex(nip);
883 if (oip->ip_data.name_key & HAMMER2_DIRHASH_VISIBLE) {
885 * Replace the old inode with an OBJTYPE_HARDLINK
888 hammer2_inode_lock_ex(oip);
889 hammer2_chain_modify(hmp, &oip->chain, 0);
890 oip->ip_data.target_type = oip->ip_data.type;
891 oip->ip_data.type = HAMMER2_OBJTYPE_HARDLINK;
892 oip->ip_data.uflags = 0;
893 oip->ip_data.rmajor = 0;
894 oip->ip_data.rminor = 0;
895 oip->ip_data.ctime = 0;
896 oip->ip_data.mtime = 0;
897 oip->ip_data.atime = 0;
898 oip->ip_data.btime = 0;
899 bzero(&oip->ip_data.uid, sizeof(oip->ip_data.uid));
900 bzero(&oip->ip_data.gid, sizeof(oip->ip_data.gid));
901 oip->ip_data.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
902 oip->ip_data.cap_flags = 0;
903 oip->ip_data.mode = 0;
904 oip->ip_data.size = 0;
905 oip->ip_data.nlinks = 1;
906 oip->ip_data.iparent = 0; /* XXX */
907 oip->ip_data.pfs_type = 0;
908 oip->ip_data.pfs_inum = 0;
909 bzero(&oip->ip_data.pfs_id,
910 sizeof(oip->ip_data.pfs_id));
911 bzero(&oip->ip_data.pfs_fsid,
912 sizeof(oip->ip_data.pfs_fsid));
913 oip->ip_data.data_quota = 0;
914 oip->ip_data.data_count = 0;
915 oip->ip_data.inode_quota = 0;
916 oip->ip_data.inode_count = 0;
917 oip->ip_data.attr_tid = 0;
918 oip->ip_data.dirent_tid = 0;
919 bzero(&oip->ip_data.u, sizeof(oip->ip_data.u));
920 /* XXX transaction ids */
922 hammer2_inode_unlock_ex(oip);
925 * The old inode was a hardlink target, which we
926 * have now moved. We must delete it so the new
927 * hardlink target at a higher directory level
928 * becomes the only hardlink target for this inode.
930 kprintf("DELETE INVISIBLE\n");
931 parent = oip->chain.parent;
932 hammer2_chain_lock(hmp, parent,
933 HAMMER2_RESOLVE_ALWAYS);
934 hammer2_chain_lock(hmp, &oip->chain,
935 HAMMER2_RESOLVE_ALWAYS);
936 hammer2_chain_delete(hmp, parent, &oip->chain, 0);
937 hammer2_chain_unlock(hmp, &oip->chain);
938 hammer2_chain_unlock(hmp, parent);
942 KKASSERT(nip == NULL);
949 * If (*ipp) is non-NULL it points to the forward OBJTYPE_HARDLINK inode while
950 * (*chainp) points to the resolved (hidden hardlink target) inode. In this
951 * situation when nlinks is 1 we wish to deconsolidate the hardlink, moving
952 * it back to the directory that now represents the only remaining link.
955 hammer2_hardlink_deconsolidate(hammer2_inode_t *dip, hammer2_chain_t **chainp,
956 hammer2_inode_t **ipp)
965 * When presented with a (*chainp) representing an inode of type
966 * OBJTYPE_HARDLINK this code will save the original inode (with a ref)
967 * in (*ipp), and then locate the hidden hardlink target in (dip) or
968 * any parent directory above (dip). The locked (*chainp) is replaced
969 * with a new locked (*chainp) representing the hardlink target.
972 hammer2_hardlink_find(hammer2_inode_t *dip, hammer2_chain_t **chainp,
973 hammer2_inode_t **ipp)
975 hammer2_mount_t *hmp = dip->hmp;
976 hammer2_chain_t *chain = *chainp;
977 hammer2_chain_t *parent;
978 hammer2_inode_t *pip;
982 hammer2_inode_ref(chain->u.ip);
983 lhc = chain->u.ip->ip_data.inum;
985 hammer2_inode_unlock_ex(chain->u.ip);
986 pip = chain->u.ip->pip;
990 parent = &pip->chain;
991 KKASSERT(parent->bref.type == HAMMER2_BREF_TYPE_INODE);
993 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
994 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
995 hammer2_chain_unlock(hmp, parent);
1002 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE);
1003 /* already locked */