hammer2 - serialized flush work part 4
[dragonfly.git] / sys / vfs / hammer2 / hammer2_inode.c
CommitLineData
7cfa8da5
MD
1/*
2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
3 *
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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
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
17 * distribution.
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.
21 *
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
33 * SUCH DAMAGE.
34 */
35#include <sys/cdefs.h>
7cfa8da5
MD
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/types.h>
39#include <sys/lock.h>
40#include <sys/uuid.h>
41
42#include "hammer2.h"
43
44/*
45 * Adding a ref to an inode is only legal if the inode already has at least
46 * one ref.
47 */
48void
49hammer2_inode_ref(hammer2_inode_t *ip)
50{
476d2aad 51 atomic_add_int(&ip->refs, 1);
7cfa8da5
MD
52}
53
54/*
55 * Drop an inode reference, freeing the inode when the last reference goes
56 * away.
57 */
58void
59hammer2_inode_drop(hammer2_inode_t *ip)
60{
476d2aad 61 hammer2_mount_t *hmp;
10252dc7
MD
62 hammer2_inode_t *pip;
63 hammer2_chain_t *chain;
64 u_int refs;
476d2aad
MD
65
66 for (;;) {
67 refs = ip->refs;
68 cpu_ccfence();
69 if (refs == 1) {
70 if (atomic_cmpset_int(&ip->refs, 1, 0)) {
476d2aad 71 KKASSERT(ip->topo_cst.count == 0);
10252dc7 72
476d2aad
MD
73 hmp = ip->hmp;
74 ip->hmp = NULL;
10252dc7
MD
75 pip = ip->pip;
76 ip->pip = NULL;
77 chain = ip->chain;
78 ip->chain = NULL;
79 if (chain)
80 hammer2_chain_drop(hmp, chain);
81
82 /*
83 * We have to drop pip (if non-NULL) to
84 * dispose of our implied reference from
85 * ip->pip. We can simply loop on it.
86 */
476d2aad 87 kfree(ip, hmp->minode);
10252dc7
MD
88 if (pip == NULL)
89 break;
90 ip = pip;
91 /* continue */
476d2aad
MD
92 }
93 } else {
94 if (atomic_cmpset_int(&ip->refs, refs, refs - 1))
95 break;
96 }
97 }
7cfa8da5
MD
98}
99
100/*
101 * Get the vnode associated with the given inode, allocating the vnode if
a0ed3c24
MD
102 * necessary. The vnode will be returned exclusively locked.
103 *
104 * The caller must lock the inode (shared or exclusive).
7cfa8da5
MD
105 *
106 * Great care must be taken to avoid deadlocks and vnode acquisition/reclaim
107 * races.
7cfa8da5
MD
108 */
109struct vnode *
110hammer2_igetv(hammer2_inode_t *ip, int *errorp)
111{
476d2aad 112 hammer2_inode_data_t *ipdata;
e4e20f48 113 hammer2_pfsmount_t *pmp;
476d2aad 114 struct vnode *vp;
a0ed3c24 115 ccms_state_t ostate;
7cfa8da5 116
e4e20f48
MD
117 pmp = ip->pmp;
118 KKASSERT(pmp != NULL);
7cfa8da5 119 *errorp = 0;
476d2aad 120 ipdata = &ip->chain->data->ipdata;
7cfa8da5
MD
121
122 for (;;) {
123 /*
124 * Attempt to reuse an existing vnode assignment. It is
125 * possible to race a reclaim so the vget() may fail. The
126 * inode must be unlocked during the vget() to avoid a
127 * deadlock against a reclaim.
128 */
129 vp = ip->vp;
130 if (vp) {
7cfa8da5
MD
131 /*
132 * Inode must be unlocked during the vget() to avoid
476d2aad
MD
133 * possible deadlocks, but leave the ip ref intact.
134 *
135 * vnode is held to prevent destruction during the
136 * vget(). The vget() can still fail if we lost
137 * a reclaim race on the vnode.
7cfa8da5
MD
138 */
139 vhold_interlocked(vp);
476d2aad 140 ostate = hammer2_inode_lock_temp_release(ip);
7cfa8da5
MD
141 if (vget(vp, LK_EXCLUSIVE)) {
142 vdrop(vp);
476d2aad 143 hammer2_inode_lock_restore(ip, ostate);
7cfa8da5
MD
144 continue;
145 }
476d2aad 146 hammer2_inode_lock_restore(ip, ostate);
7cfa8da5
MD
147 vdrop(vp);
148 /* vp still locked and ref from vget */
3fc4c63d
MD
149 if (ip->vp != vp) {
150 kprintf("hammer2: igetv race %p/%p\n",
151 ip->vp, vp);
152 vput(vp);
153 continue;
154 }
7cfa8da5
MD
155 *errorp = 0;
156 break;
157 }
158
159 /*
160 * No vnode exists, allocate a new vnode. Beware of
161 * allocation races. This function will return an
162 * exclusively locked and referenced vnode.
163 */
e4e20f48 164 *errorp = getnewvnode(VT_HAMMER2, pmp->mp, &vp, 0, 0);
7cfa8da5 165 if (*errorp) {
3fc4c63d
MD
166 kprintf("hammer2: igetv getnewvnode failed %d\n",
167 *errorp);
7cfa8da5
MD
168 vp = NULL;
169 break;
170 }
171
172 /*
173 * Lock the inode and check for an allocation race.
174 */
476d2aad 175 ostate = hammer2_inode_lock_upgrade(ip);
7cfa8da5
MD
176 if (ip->vp != NULL) {
177 vp->v_type = VBAD;
178 vx_put(vp);
476d2aad 179 hammer2_inode_lock_restore(ip, ostate);
7cfa8da5
MD
180 continue;
181 }
182
476d2aad 183 switch (ipdata->type) {
df9ea374 184 case HAMMER2_OBJTYPE_DIRECTORY:
7cfa8da5
MD
185 vp->v_type = VDIR;
186 break;
df9ea374 187 case HAMMER2_OBJTYPE_REGFILE:
7cfa8da5 188 vp->v_type = VREG;
476d2aad 189 vinitvmio(vp, ipdata->size,
6ba3b984 190 HAMMER2_LBUFSIZE,
476d2aad 191 (int)ipdata->size & HAMMER2_LBUFMASK);
7cfa8da5 192 break;
4e2004ea
MD
193 case HAMMER2_OBJTYPE_SOFTLINK:
194 /*
195 * XXX for now we are using the generic file_read
196 * and file_write code so we need a buffer cache
197 * association.
198 */
199 vp->v_type = VLNK;
476d2aad 200 vinitvmio(vp, ipdata->size,
6ba3b984 201 HAMMER2_LBUFSIZE,
476d2aad 202 (int)ipdata->size & HAMMER2_LBUFMASK);
4e2004ea 203 break;
7cfa8da5
MD
204 /* XXX FIFO */
205 default:
476d2aad 206 panic("hammer2: unhandled objtype %d", ipdata->type);
7cfa8da5
MD
207 break;
208 }
209
e4e20f48 210 if (ip == pmp->iroot)
7cfa8da5
MD
211 vsetflags(vp, VROOT);
212
213 vp->v_data = ip;
214 ip->vp = vp;
476d2aad
MD
215 hammer2_inode_ref(ip); /* vp association */
216 hammer2_inode_lock_restore(ip, ostate);
7cfa8da5
MD
217 break;
218 }
219
220 /*
221 * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0.
222 */
37aa19df
MD
223 if (hammer2_debug & 0x0002) {
224 kprintf("igetv vp %p refs %d aux %d\n",
225 vp, vp->v_sysref.refcnt, vp->v_auxrefs);
226 }
7cfa8da5
MD
227 return (vp);
228}
229
476d2aad 230/*
476d2aad 231 * The passed-in chain must be locked and the returned inode will also be
10252dc7
MD
232 * locked. A ref is added to both the chain and the inode.
233 *
234 * The hammer2_inode structure regulates the interface between the high level
235 * kernel VNOPS API and the filesystem backend (the chains).
236 *
237 * NOTE! This routine allocates the hammer2_inode structure
238 * unconditionally, and thus there might be several which
239 * are associated with the same chain. Particularly for hardlinks
240 * but this can also happen temporarily for normal files and
241 * directories.
476d2aad
MD
242 *
243 * WARNING! This routine sucks up the chain's lock (makes it part of the
10252dc7
MD
244 * inode lock from the point of view of the inode lock API),
245 * so callers need to be careful.
476d2aad 246 *
10252dc7
MD
247 * WARNING! The mount code is allowed to pass dip == NULL for iroot and
248 * is allowed to pass pmp == NULL and dip == NULL for sroot.
476d2aad
MD
249 */
250hammer2_inode_t *
10252dc7
MD
251hammer2_inode_get(hammer2_mount_t *hmp, hammer2_pfsmount_t *pmp,
252 hammer2_inode_t *dip, hammer2_chain_t *chain)
476d2aad 253{
476d2aad
MD
254 hammer2_inode_t *nip;
255
256 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE);
10252dc7
MD
257
258 nip = kmalloc(sizeof(*nip), hmp->minode, M_WAITOK | M_ZERO);
259
260 nip->chain = chain;
261 hammer2_chain_ref(hmp, chain); /* nip->chain */
262 nip->pip = dip; /* can be NULL */
263 if (dip)
264 hammer2_inode_ref(dip); /* ref dip for nip->pip */
265
266 nip->pmp = pmp;
267 nip->hmp = hmp;
268
269 /*
270 * ref and lock on nip gives it state compatible to after a
271 * hammer2_inode_lock_ex() call.
272 */
273 nip->refs = 1;
274 ccms_cst_init(&nip->topo_cst, &nip->chain);
476d2aad
MD
275 ccms_thread_lock(&nip->topo_cst, CCMS_STATE_EXCLUSIVE);
276 /* combination of thread lock and chain lock == inode lock */
277
278 return (nip);
279}
280
281/*
282 * Put away an inode, disconnecting it from its chain. The inode must be
283 * exclusively locked.
284 *
285 * The inode will be unlocked by this function. Note however that any related
286 * chain returned by the hammer2_inode_lock_*() call will NOT be unlocked
10252dc7
MD
287 * by this function. The related chain is dropped to undo the ref that
288 * hammer2_inode_get() put on it.
289 *
290 * passed_chain is unlocked normally and does not have to be directly
291 * associated with (ip). This is simply so the API works the same as
292 * the hammer2_inode_unlock_ex() API. NULL is ok.
476d2aad
MD
293 */
294void
10252dc7 295hammer2_inode_put(hammer2_inode_t *ip, hammer2_chain_t *passed_chain)
476d2aad
MD
296{
297 hammer2_mount_t *hmp = ip->hmp;
476d2aad 298 hammer2_inode_t *pip;
10252dc7 299 hammer2_chain_t *chain;
476d2aad 300
10252dc7
MD
301 /*
302 * Disconnect chain
303 */
304 if ((chain = ip->chain) != NULL) {
305 ip->chain = NULL;
306 hammer2_chain_drop(hmp, chain); /* from *_get() */
307 }
476d2aad 308 KKASSERT(ip->topo_cst.count == -1); /* one excl lock allowed */
476d2aad
MD
309
310 /*
10252dc7 311 * Disconnect pip
476d2aad
MD
312 */
313 if ((pip = ip->pip) != NULL) {
314 ip->pip = NULL;
476d2aad 315 hammer2_inode_drop(pip);
476d2aad 316 }
10252dc7
MD
317
318 /*
319 * clean up the ip, we use an inode_unlock_ex-compatible API.
320 */
321 hammer2_inode_unlock_ex(ip, passed_chain);
476d2aad
MD
322}
323
7cfa8da5 324/*
37494cab
MD
325 * Create a new inode in the specified directory using the vattr to
326 * figure out the type of inode.
7cfa8da5 327 *
db71f61f
MD
328 * If no error occurs the new inode with its chain locked is returned in
329 * *nipp, otherwise an error is returned and *nipp is set to NULL.
ae183399
MD
330 *
331 * If vap and/or cred are NULL the related fields are not set and the
332 * inode type defaults to a directory. This is used when creating PFSs
333 * under the super-root, so the inode number is set to 1 in this case.
476d2aad
MD
334 *
335 * dip is not locked on entry.
7cfa8da5 336 */
37494cab 337int
e4e20f48 338hammer2_inode_create(hammer2_inode_t *dip,
37494cab 339 struct vattr *vap, struct ucred *cred,
37494cab 340 const uint8_t *name, size_t name_len,
e2e9e2db 341 hammer2_inode_t **nipp, hammer2_chain_t **nchainp)
7cfa8da5 342{
476d2aad
MD
343 hammer2_inode_data_t *nipdata;
344 hammer2_mount_t *hmp;
37494cab
MD
345 hammer2_chain_t *chain;
346 hammer2_chain_t *parent;
347 hammer2_inode_t *nip;
348 hammer2_key_t lhc;
349 int error;
b2b78aaa 350 uid_t xuid;
476d2aad
MD
351 uuid_t dip_uid;
352 uuid_t dip_gid;
353 uint32_t dip_mode;
7cfa8da5 354
476d2aad 355 hmp = dip->hmp;
37494cab 356 lhc = hammer2_dirhash(name, name_len);
7cfa8da5 357
37494cab
MD
358 /*
359 * Locate the inode or indirect block to create the new
360 * entry in. At the same time check for key collisions
361 * and iterate until we don't get one.
362 */
5f6853df 363retry:
e2e9e2db
MD
364 parent = hammer2_inode_lock_ex(dip);
365
366 dip_uid = parent->data->ipdata.uid;
367 dip_gid = parent->data->ipdata.gid;
368 dip_mode = parent->data->ipdata.mode;
7cfa8da5 369
37494cab
MD
370 error = 0;
371 while (error == 0) {
c667909f 372 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
37494cab
MD
373 if (chain == NULL)
374 break;
92a2bc79
MD
375 if ((lhc & HAMMER2_DIRHASH_VISIBLE) == 0)
376 error = ENOSPC;
37494cab
MD
377 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
378 error = ENOSPC;
01eabad4 379 hammer2_chain_unlock(hmp, chain);
37494cab
MD
380 chain = NULL;
381 ++lhc;
382 }
383 if (error == 0) {
6934ae32 384 chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0,
37494cab 385 HAMMER2_BREF_TYPE_INODE,
5f6853df
MD
386 HAMMER2_INODE_BYTES,
387 &error);
37494cab 388 }
7cfa8da5 389
e2e9e2db 390 hammer2_inode_unlock_ex(dip, parent);
476d2aad 391
37494cab
MD
392 /*
393 * Handle the error case
394 */
395 if (error) {
396 KKASSERT(chain == NULL);
5f6853df
MD
397 if (error == EAGAIN) {
398 hammer2_chain_wait(hmp, parent);
399 goto retry;
400 }
37494cab 401 *nipp = NULL;
e2e9e2db 402 *nchainp = NULL;
37494cab
MD
403 return (error);
404 }
7cfa8da5 405
37494cab 406 /*
476d2aad
MD
407 * Set up the new inode.
408 *
409 * NOTE: *_get() integrates chain's lock into the inode lock.
37494cab 410 */
10252dc7 411 nip = hammer2_inode_get(dip->hmp, dip->pmp, dip, chain);
37494cab 412 *nipp = nip;
e2e9e2db
MD
413 *nchainp = chain;
414 nipdata = &chain->data->ipdata;
7cfa8da5 415
2910a90c 416 hammer2_voldata_lock(hmp);
ae183399 417 if (vap) {
476d2aad
MD
418 nipdata->type = hammer2_get_obj_type(vap->va_type);
419 nipdata->inum = hmp->voldata.alloc_tid++;
ae183399
MD
420 /* XXX modify/lock */
421 } else {
476d2aad
MD
422 nipdata->type = HAMMER2_OBJTYPE_DIRECTORY;
423 nipdata->inum = 1;
ae183399 424 }
2910a90c 425 hammer2_voldata_unlock(hmp);
476d2aad
MD
426 nipdata->version = HAMMER2_INODE_VERSION_ONE;
427 hammer2_update_time(&nipdata->ctime);
428 nipdata->mtime = nipdata->ctime;
ae183399 429 if (vap)
476d2aad
MD
430 nipdata->mode = vap->va_mode;
431 nipdata->nlinks = 1;
b2b78aaa
MD
432 if (vap) {
433 if (dip) {
476d2aad 434 xuid = hammer2_to_unix_xid(&dip_uid);
b2b78aaa 435 xuid = vop_helper_create_uid(dip->pmp->mp,
476d2aad 436 dip_mode,
b2b78aaa
MD
437 xuid,
438 cred,
439 &vap->va_mode);
440 } else {
441 xuid = 0;
442 }
443 if (vap->va_vaflags & VA_UID_UUID_VALID)
476d2aad 444 nipdata->uid = vap->va_uid_uuid;
b2b78aaa 445 else if (vap->va_uid != (uid_t)VNOVAL)
476d2aad 446 hammer2_guid_to_uuid(&nipdata->uid, vap->va_uid);
b2b78aaa 447 else
476d2aad 448 hammer2_guid_to_uuid(&nipdata->uid, xuid);
b2b78aaa
MD
449
450 if (vap->va_vaflags & VA_GID_UUID_VALID)
476d2aad 451 nipdata->gid = vap->va_gid_uuid;
b2b78aaa 452 else if (vap->va_gid != (gid_t)VNOVAL)
476d2aad 453 hammer2_guid_to_uuid(&nipdata->gid, vap->va_gid);
b2b78aaa 454 else if (dip)
476d2aad 455 nipdata->gid = dip_gid;
b2b78aaa 456 }
232a50f9 457
3ac6a319
MD
458 /*
459 * Regular files and softlinks allow a small amount of data to be
460 * directly embedded in the inode. This flag will be cleared if
461 * the size is extended past the embedded limit.
462 */
476d2aad
MD
463 if (nipdata->type == HAMMER2_OBJTYPE_REGFILE ||
464 nipdata->type == HAMMER2_OBJTYPE_SOFTLINK) {
465 nipdata->op_flags |= HAMMER2_OPFLAG_DIRECTDATA;
3ac6a319
MD
466 }
467
37494cab 468 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
476d2aad
MD
469 bcopy(name, nipdata->filename, name_len);
470 nipdata->name_key = lhc;
471 nipdata->name_len = name_len;
7cfa8da5 472
37494cab 473 return (0);
7cfa8da5 474}
6934ae32 475
99535653 476/*
51bf8e9b
MD
477 * Create a duplicate of the inode (chain) in the specified target directory
478 * (dip), return the duplicated chain in *nchainp (locked). chain is locked
479 * on call and remains locked on return.
99535653 480 *
51bf8e9b 481 * If name is NULL the inode is duplicated as a hidden directory entry.
004f88b4
MD
482 *
483 * XXX name needs to be NULL for now.
99535653
MD
484 */
485int
51bf8e9b
MD
486hammer2_inode_duplicate(hammer2_inode_t *dip,
487 hammer2_chain_t *ochain, hammer2_chain_t **nchainp)
99535653 488{
476d2aad
MD
489 hammer2_inode_data_t *nipdata;
490 hammer2_mount_t *hmp;
99535653 491 hammer2_chain_t *parent;
28ee5f14 492 hammer2_chain_t *chain;
99535653 493 hammer2_key_t lhc;
51bf8e9b 494 int error = 0;
99535653 495
476d2aad 496 hmp = dip->hmp;
51bf8e9b
MD
497 lhc = ochain->data->ipdata.inum;
498 *nchainp = NULL;
499 KKASSERT((lhc & HAMMER2_DIRHASH_VISIBLE) == 0);
99535653
MD
500
501 /*
502 * Locate the inode or indirect block to create the new
51bf8e9b
MD
503 * entry in.
504 *
505 * There should be no key collisions with invisible inode keys.
99535653 506 */
5f6853df 507retry:
51bf8e9b
MD
508 parent = dip->chain;
509 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
510 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
511 if (chain) {
99535653
MD
512 hammer2_chain_unlock(hmp, chain);
513 chain = NULL;
51bf8e9b 514 error = ENOSPC;
99535653
MD
515 }
516
517 /*
004f88b4 518 * Create entry in common parent directory.
99535653
MD
519 */
520 if (error == 0) {
521 chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0,
5f6853df
MD
522 HAMMER2_BREF_TYPE_INODE, /* n/a */
523 HAMMER2_INODE_BYTES, /* n/a */
524 &error);
99535653 525 }
e2e9e2db
MD
526
527 /*
528 * Clean up, but we need to retain a ref on parent so we can wait
529 * on it for certain errors.
530 */
531 if (error == EAGAIN)
532 hammer2_chain_ref(hmp, parent);
51bf8e9b 533 hammer2_chain_unlock(hmp, parent);
99535653
MD
534
535 /*
536 * Handle the error case
537 */
538 if (error) {
539 KKASSERT(chain == NULL);
5f6853df
MD
540 if (error == EAGAIN) {
541 hammer2_chain_wait(hmp, parent);
e2e9e2db 542 hammer2_chain_drop(hmp, parent);
5f6853df
MD
543 goto retry;
544 }
99535653
MD
545 return (error);
546 }
99535653 547
28ee5f14
MD
548 /*
549 * XXX This is currently a horrible hack. Well, if we wanted to
550 * duplicate a file, i.e. as in a snapshot, we definitely
551 * would have to flush it first.
552 *
553 * For hardlink target generation we can theoretically move any
554 * active chain structures without flushing, but that gets really
555 * iffy for code which follows chain->parent and ip->pip links.
556 *
557 * XXX only works with files. Duplicating a directory hierarchy
558 * requires a flush but doesn't deal with races post-flush.
559 * Well, it would work I guess, but you might catch some files
560 * mid-operation.
561 *
51bf8e9b
MD
562 * We cannot leave ochain with any in-memory chains because (for a
563 * hardlink), ochain will become a OBJTYPE_HARDLINK which is just a
28ee5f14 564 * pointer to the real hardlink's inum and can't have any sub-chains.
a0ed3c24 565 * XXX might be 0-ref chains left.
28ee5f14 566 */
51bf8e9b
MD
567 hammer2_chain_flush(hmp, ochain, 0);
568 /*KKASSERT(RB_EMPTY(&ochain.rbhead));*/
28ee5f14 569
004f88b4 570 hammer2_chain_modify(hmp, chain, 0);
476d2aad 571 nipdata = &chain->data->ipdata;
51bf8e9b
MD
572 *nipdata = ochain->data->ipdata;
573
574 /*
575 * Directory entries are inodes but this is a hidden hardlink
576 * target. The name isn't used but to ease debugging give it
577 * a name after its inode number.
578 */
579 ksnprintf(nipdata->filename, sizeof(nipdata->filename),
580 "0x%016jx", (intmax_t)nipdata->inum);
581 nipdata->name_len = strlen(nipdata->filename);
582 nipdata->name_key = lhc;
004f88b4 583
e2e9e2db 584 *nchainp = chain;
99535653
MD
585
586 return (0);
587}
588
6934ae32 589/*
51bf8e9b
MD
590 * Connect *chainp to the media topology represented by (dip, name, len).
591 * A directory entry is created which points to *chainp. *chainp is then
592 * unlocked and set to NULL.
e708f8b9 593 *
51bf8e9b 594 * If *chainp is not currently connected we simply connect it up.
99535653 595 *
51bf8e9b
MD
596 * If *chainp is already connected we create a OBJTYPE_HARDLINK entry which
597 * points to chain's inode number. *chainp is expected to be the terminus of
99535653 598 * the hardlink sitting as a hidden file in a common parent directory
f3843dc2 599 * in this situation.
51bf8e9b
MD
600 *
601 * The caller always wants to reference the hardlink terminus, not the
602 * hardlink pointer that we might be creating, so we do NOT replace
603 * *chainp here, we simply unlock and NULL it out.
6934ae32
MD
604 */
605int
51bf8e9b 606hammer2_inode_connect(hammer2_inode_t *dip, hammer2_chain_t **chainp,
6934ae32
MD
607 const uint8_t *name, size_t name_len)
608{
51bf8e9b 609 hammer2_inode_data_t *ipdata;
476d2aad 610 hammer2_mount_t *hmp;
51bf8e9b 611 hammer2_chain_t *nchain;
6934ae32 612 hammer2_chain_t *parent;
e2e9e2db 613 hammer2_chain_t *ochain;
6934ae32
MD
614 hammer2_key_t lhc;
615 int error;
99535653 616 int hlink;
6934ae32 617
51bf8e9b
MD
618 hmp = dip->hmp;
619
620 ochain = *chainp;
621 *chainp = NULL;
622
f3843dc2 623 /*
51bf8e9b
MD
624 * Since ochain is either disconnected from the topology or represents
625 * a hardlink terminus which is always a parent of or equal to dip,
626 * we should be able to safely lock dip->chain for our setup.
f3843dc2 627 */
5f6853df 628retry:
51bf8e9b
MD
629 parent = dip->chain;
630 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
f3843dc2 631
6934ae32 632 lhc = hammer2_dirhash(name, name_len);
e2e9e2db 633 hlink = (ochain->parent != NULL);
004f88b4
MD
634
635 /*
636 * In fake mode flush oip so we can just snapshot it downbelow.
637 */
638 if (hlink && hammer2_hardlink_enable < 0)
e2e9e2db 639 hammer2_chain_flush(hmp, ochain, 0);
6934ae32
MD
640
641 /*
642 * Locate the inode or indirect block to create the new
643 * entry in. At the same time check for key collisions
644 * and iterate until we don't get one.
645 */
6934ae32
MD
646 error = 0;
647 while (error == 0) {
51bf8e9b
MD
648 nchain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
649 if (nchain == NULL)
6934ae32
MD
650 break;
651 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
652 error = ENOSPC;
51bf8e9b
MD
653 hammer2_chain_unlock(hmp, nchain);
654 nchain = NULL;
6934ae32
MD
655 ++lhc;
656 }
657
658 /*
659 * Passing a non-NULL chain to hammer2_chain_create() reconnects the
660 * existing chain instead of creating a new one. The chain's bref
661 * will be properly updated.
662 */
663 if (error == 0) {
99535653 664 if (hlink) {
51bf8e9b 665 nchain = hammer2_chain_create(hmp, parent,
99535653
MD
666 NULL, lhc, 0,
667 HAMMER2_BREF_TYPE_INODE,
5f6853df
MD
668 HAMMER2_INODE_BYTES,
669 &error);
99535653 670 } else {
51bf8e9b
MD
671 /*
672 * NOTE: reconnects oip->chain to the media
673 * topology and returns its argument
674 * (oip->chain).
675 *
676 * No additional locks or refs are obtained on
677 * the returned chain so don't double-unlock!
678 */
679 nchain = hammer2_chain_create(hmp, parent,
680 ochain, lhc, 0,
99535653 681 HAMMER2_BREF_TYPE_INODE,
5f6853df
MD
682 HAMMER2_INODE_BYTES,
683 &error);
99535653 684 }
6934ae32 685 }
476d2aad
MD
686
687 /*
688 * Unlock stuff. This is a bit messy, if we have an EAGAIN error
689 * we need to wait for operations on parent to finish.
690 */
691 if (error == EAGAIN)
692 hammer2_chain_ref(hmp, parent);
51bf8e9b 693 hammer2_chain_unlock(hmp, parent);
6934ae32
MD
694
695 /*
51bf8e9b 696 * ochain still active.
e2e9e2db 697 *
6934ae32
MD
698 * Handle the error case
699 */
700 if (error) {
51bf8e9b 701 KKASSERT(nchain == NULL);
5f6853df
MD
702 if (error == EAGAIN) {
703 hammer2_chain_wait(hmp, parent);
476d2aad 704 hammer2_chain_drop(hmp, parent);
5f6853df
MD
705 goto retry;
706 }
51bf8e9b 707 hammer2_chain_unlock(hmp, ochain);
6934ae32
MD
708 return (error);
709 }
710
711 /*
712 * Directory entries are inodes so if the name has changed we have
713 * to update the inode.
99535653
MD
714 *
715 * When creating an OBJTYPE_HARDLINK entry remember to unlock the
716 * chain, the caller will access the hardlink via the actual hardlink
717 * target file and not the hardlink pointer entry.
6934ae32 718 */
004f88b4 719 if (hlink && hammer2_hardlink_enable >= 0) {
92a2bc79
MD
720 /*
721 * Create the HARDLINK pointer. oip represents the hardlink
722 * target in this situation.
476d2aad
MD
723 *
724 * NOTE: *_get() integrates chain's lock into the inode lock.
92a2bc79 725 */
51bf8e9b 726 hammer2_chain_modify(hmp, nchain, 0);
6934ae32 727 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
51bf8e9b
MD
728 ipdata = &nchain->data->ipdata;
729 bcopy(name, ipdata->filename, name_len);
730 ipdata->name_key = lhc;
731 ipdata->name_len = name_len;
732 ipdata->target_type = ochain->data->ipdata.type;
733 ipdata->type = HAMMER2_OBJTYPE_HARDLINK;
734 ipdata->inum = ochain->data->ipdata.inum;
735 ipdata->nlinks = 1;
99535653
MD
736 kprintf("created hardlink %*.*s\n",
737 (int)name_len, (int)name_len, name);
51bf8e9b 738 hammer2_chain_unlock(hmp, nchain);
004f88b4
MD
739 } else if (hlink && hammer2_hardlink_enable < 0) {
740 /*
741 * Create a snapshot (hardlink fake mode for debugging).
476d2aad 742 *
51bf8e9b 743 * NOTE: *_get() integrates nchain's lock into the inode lock.
004f88b4 744 */
51bf8e9b 745 hammer2_chain_modify(hmp, nchain, 0);
004f88b4 746 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
51bf8e9b
MD
747 ipdata = &nchain->data->ipdata;
748 *ipdata = ochain->data->ipdata;
749 bcopy(name, ipdata->filename, name_len);
750 ipdata->name_key = lhc;
751 ipdata->name_len = name_len;
004f88b4
MD
752 kprintf("created fake hardlink %*.*s\n",
753 (int)name_len, (int)name_len, name);
51bf8e9b 754 hammer2_chain_unlock(hmp, nchain);
99535653 755 } else {
92a2bc79 756 /*
004f88b4
MD
757 * Normally disconnected inode (e.g. during a rename) that
758 * was reconnected. We must fixup the name stored in
759 * oip.
92a2bc79
MD
760 *
761 * We are using oip as chain, already locked by caller,
762 * do not unlock it.
763 */
51bf8e9b
MD
764 hammer2_chain_modify(hmp, ochain, 0);
765 ipdata = &ochain->data->ipdata;
476d2aad 766
51bf8e9b
MD
767 if (ipdata->name_len != name_len ||
768 bcmp(ipdata->filename, name, name_len) != 0) {
99535653 769 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
51bf8e9b
MD
770 bcopy(name, ipdata->filename, name_len);
771 ipdata->name_key = lhc;
772 ipdata->name_len = name_len;
99535653 773 }
51bf8e9b 774 ipdata->nlinks = 1;
6934ae32 775 }
51bf8e9b 776 hammer2_chain_unlock(hmp, ochain);
6934ae32
MD
777 return (0);
778}
db0c2eb3 779
ae183399
MD
780/*
781 * Unlink the file from the specified directory inode. The directory inode
10252dc7
MD
782 * does not need to be locked. The caller should pass a non-NULL (ip)
783 * representing the object being removed only if the related vnode is
784 * potentially inactive (not referenced in the caller's active path),
785 * so we can vref/vrele it to trigger the VOP_INACTIVE path and properly
786 * recycle it.
ae183399
MD
787 *
788 * isdir determines whether a directory/non-directory check should be made.
789 * No check is made if isdir is set to -1.
5f6853df 790 *
10252dc7 791 * If retain_chain is non-NULL this function can fail with an EAGAIN if it
5f6853df 792 * catches the object in the middle of a flush.
ae183399
MD
793 */
794int
e708f8b9 795hammer2_unlink_file(hammer2_inode_t *dip,
004f88b4 796 const uint8_t *name, size_t name_len,
10252dc7 797 int isdir, hammer2_chain_t *retain_chain)
ae183399 798{
476d2aad 799 hammer2_inode_data_t *ipdata;
ae183399
MD
800 hammer2_mount_t *hmp;
801 hammer2_chain_t *parent;
476d2aad 802 hammer2_chain_t *ochain;
ae183399
MD
803 hammer2_chain_t *chain;
804 hammer2_chain_t *dparent;
805 hammer2_chain_t *dchain;
806 hammer2_key_t lhc;
807 int error;
e2e9e2db 808 int parent_ref;
99535653 809 uint8_t type;
ae183399 810
e2e9e2db 811 parent_ref = 0;
ae183399 812 error = 0;
476d2aad 813 ochain = NULL;
ae183399
MD
814 hmp = dip->hmp;
815 lhc = hammer2_dirhash(name, name_len);
816
817 /*
818 * Search for the filename in the directory
819 */
e2e9e2db 820 parent = hammer2_inode_lock_ex(dip);
ae183399
MD
821 chain = hammer2_chain_lookup(hmp, &parent,
822 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
5f6853df 823 0);
ae183399
MD
824 while (chain) {
825 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
ae183399
MD
826 name_len == chain->data->ipdata.name_len &&
827 bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
828 break;
829 }
830 chain = hammer2_chain_next(hmp, &parent, chain,
831 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
5f6853df 832 0);
ae183399 833 }
e2e9e2db 834 hammer2_inode_unlock_ex(dip, NULL); /* retain parent */
ae183399
MD
835
836 /*
837 * Not found or wrong type (isdir < 0 disables the type check).
51bf8e9b 838 * If a hardlink pointer, type checks use the hardlink target.
ae183399
MD
839 */
840 if (chain == NULL) {
e2e9e2db
MD
841 error = ENOENT;
842 goto done;
ae183399 843 }
99535653
MD
844 if ((type = chain->data->ipdata.type) == HAMMER2_OBJTYPE_HARDLINK)
845 type = chain->data->ipdata.target_type;
846
847 if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir == 0) {
ae183399
MD
848 error = ENOTDIR;
849 goto done;
850 }
99535653 851 if (type != HAMMER2_OBJTYPE_DIRECTORY && isdir == 1) {
ae183399
MD
852 error = EISDIR;
853 goto done;
854 }
855
99535653
MD
856 /*
857 * Hardlink must be resolved. We can't hold parent locked while we
858 * do this or we could deadlock.
476d2aad
MD
859 *
860 * On success chain will be adjusted to point at the hardlink target
861 * and ochain will point to the hardlink pointer in the original
862 * directory. Otherwise chain remains pointing to the original.
99535653
MD
863 */
864 if (chain->data->ipdata.type == HAMMER2_OBJTYPE_HARDLINK) {
e2e9e2db 865 KKASSERT(parent_ref == 0);
99535653
MD
866 hammer2_chain_unlock(hmp, parent);
867 parent = NULL;
476d2aad 868 error = hammer2_hardlink_find(dip, &chain, &ochain);
99535653
MD
869 }
870
ae183399
MD
871 /*
872 * If this is a directory the directory must be empty. However, if
873 * isdir < 0 we are doing a rename and the directory does not have
874 * to be empty.
26b047fa
MD
875 *
876 * NOTE: We check the full key range here which covers both visible
877 * and invisible entries. Theoretically there should be no
878 * invisible (hardlink target) entries if there are no visible
879 * entries.
ae183399 880 */
99535653 881 if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir >= 0) {
ae183399
MD
882 dparent = chain;
883 hammer2_chain_lock(hmp, dparent, HAMMER2_RESOLVE_ALWAYS);
884 dchain = hammer2_chain_lookup(hmp, &dparent,
885 0, (hammer2_key_t)-1,
886 HAMMER2_LOOKUP_NODATA);
887 if (dchain) {
888 hammer2_chain_unlock(hmp, dchain);
889 hammer2_chain_unlock(hmp, dparent);
890 error = ENOTEMPTY;
891 goto done;
892 }
893 hammer2_chain_unlock(hmp, dparent);
894 dparent = NULL;
895 /* dchain NULL */
896 }
897
ae183399 898 /*
99535653
MD
899 * Ok, we can now unlink the chain. We always decrement nlinks even
900 * if the entry can be deleted in case someone has the file open and
901 * does an fstat().
902 *
004f88b4
MD
903 * The chain itself will no longer be in the on-media topology but
904 * can still be flushed to the media (e.g. if an open descriptor
905 * remains). When the last vnode/ip ref goes away the chain will
906 * be marked unmodified, avoiding any further (now unnecesary) I/O.
476d2aad
MD
907 *
908 * A non-NULL ochain indicates a hardlink.
ae183399 909 */
476d2aad 910 if (ochain) {
99535653 911 /*
476d2aad 912 * Delete the original hardlink pointer.
e2e9e2db
MD
913 *
914 * NOTE: parent from above is NULL when ochain != NULL
915 * so we can reuse it.
99535653 916 */
476d2aad 917 hammer2_chain_lock(hmp, ochain, HAMMER2_RESOLVE_ALWAYS);
e2e9e2db 918 parent_ref = 1;
476d2aad
MD
919 for (;;) {
920 parent = ochain->parent;
921 hammer2_chain_ref(hmp, parent);
922 hammer2_chain_unlock(hmp, ochain);
923 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
924 hammer2_chain_lock(hmp, ochain, HAMMER2_RESOLVE_ALWAYS);
925 if (ochain->parent == parent)
926 break;
927 hammer2_chain_unlock(hmp, parent);
928 hammer2_chain_drop(hmp, parent);
929 }
930
10252dc7 931 if (ochain == retain_chain && ochain->flushing) {
476d2aad 932 hammer2_chain_unlock(hmp, ochain);
5f6853df
MD
933 error = EAGAIN;
934 goto done;
935 }
476d2aad 936 hammer2_chain_delete(hmp, parent, ochain,
10252dc7 937 (ochain == retain_chain));
51bf8e9b 938 hammer2_chain_unlock(hmp, ochain);
99535653 939 hammer2_chain_unlock(hmp, parent);
476d2aad 940 hammer2_chain_drop(hmp, parent);
99535653
MD
941 parent = NULL;
942
943 /*
476d2aad
MD
944 * Then decrement nlinks on hardlink target, deleting
945 * the target when nlinks drops to 0.
99535653 946 */
476d2aad 947 if (chain->data->ipdata.nlinks == 1) {
99535653
MD
948 dparent = chain->parent;
949 hammer2_chain_ref(hmp, chain);
950 hammer2_chain_unlock(hmp, chain);
5f6853df
MD
951 hammer2_chain_lock(hmp, dparent,
952 HAMMER2_RESOLVE_ALWAYS);
953 hammer2_chain_lock(hmp, chain,
954 HAMMER2_RESOLVE_ALWAYS);
99535653
MD
955 hammer2_chain_drop(hmp, chain);
956 hammer2_chain_modify(hmp, chain, 0);
476d2aad 957 --chain->data->ipdata.nlinks;
004f88b4 958 hammer2_chain_delete(hmp, dparent, chain, 0);
99535653
MD
959 hammer2_chain_unlock(hmp, dparent);
960 } else {
961 hammer2_chain_modify(hmp, chain, 0);
476d2aad 962 --chain->data->ipdata.nlinks;
99535653
MD
963 }
964 } else {
965 /*
966 * Otherwise this was not a hardlink and we can just
967 * remove the entry and decrement nlinks.
476d2aad
MD
968 *
969 * NOTE: *_get() integrates chain's lock into the inode lock.
99535653 970 */
10252dc7
MD
971 ipdata = &chain->data->ipdata;
972 if (chain == retain_chain && chain->flushing) {
5f6853df
MD
973 error = EAGAIN;
974 goto done;
975 }
99535653 976 hammer2_chain_modify(hmp, chain, 0);
476d2aad 977 --ipdata->nlinks;
004f88b4 978 hammer2_chain_delete(hmp, parent, chain,
10252dc7 979 (retain_chain == chain));
99535653 980 }
ae183399 981
ae183399 982 error = 0;
ae183399 983done:
99535653
MD
984 if (chain)
985 hammer2_chain_unlock(hmp, chain);
476d2aad 986 if (parent) {
99535653 987 hammer2_chain_unlock(hmp, parent);
e2e9e2db
MD
988 if (parent_ref)
989 hammer2_chain_drop(hmp, parent);
476d2aad
MD
990 }
991 if (ochain)
992 hammer2_chain_drop(hmp, ochain);
ae183399
MD
993
994 return error;
995}
996
01eabad4
MD
997/*
998 * Calculate the allocation size for the file fragment straddling EOF
999 */
866d5273
MD
1000int
1001hammer2_inode_calc_alloc(hammer2_key_t filesize)
1002{
1003 int frag = (int)filesize & HAMMER2_PBUFMASK;
1004 int radix;
1005
1006 if (frag == 0)
1007 return(0);
01eabad4 1008 for (radix = HAMMER2_MINALLOCRADIX; frag > (1 << radix); ++radix)
866d5273
MD
1009 ;
1010 return (radix);
1011}
e708f8b9 1012
e708f8b9 1013/*
51bf8e9b
MD
1014 * Given an unlocked ip consolidate for hardlink creation, adding (nlinks)
1015 * to the file's link count and potentially relocating the file to a
1016 * directory common to ip->pip and tdip.
99535653 1017 *
51bf8e9b 1018 * If the file has to be relocated ip->chain will also be adjusted.
e708f8b9
MD
1019 */
1020int
51bf8e9b
MD
1021hammer2_hardlink_consolidate(hammer2_inode_t *ip, hammer2_chain_t **chainp,
1022 hammer2_inode_t *tdip, int nlinks)
e708f8b9 1023{
51bf8e9b 1024 hammer2_inode_data_t *ipdata;
99535653 1025 hammer2_mount_t *hmp;
99535653 1026 hammer2_inode_t *fdip;
f3843dc2 1027 hammer2_inode_t *cdip;
51bf8e9b 1028 hammer2_chain_t *chain;
e2e9e2db 1029 hammer2_chain_t *nchain;
99535653
MD
1030 hammer2_chain_t *parent;
1031 int error;
1032
1033 hmp = tdip->hmp;
51bf8e9b
MD
1034 *chainp = NULL;
1035 chain = hammer2_inode_lock_ex(ip);
99535653 1036
51bf8e9b
MD
1037 if (nlinks == 0 && /* no hardlink needed */
1038 (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE)) {
1039 hammer2_inode_unlock_ex(ip, NULL);
1040 *chainp = chain;
1041 return (0);
1042 }
1043 if (hammer2_hardlink_enable < 0) { /* fake hardlinks */
1044 hammer2_inode_unlock_ex(ip, NULL);
1045 *chainp = chain;
e708f8b9 1046 return (0);
51bf8e9b
MD
1047 }
1048 if (hammer2_hardlink_enable == 0) { /* disallow hardlinks */
1049 hammer2_inode_unlock_ex(ip, chain);
e708f8b9 1050 return (ENOTSUP);
51bf8e9b 1051 }
99535653 1052
10252dc7
MD
1053 /*
1054 * cdip will be returned with a ref, but not locked.
1055 */
51bf8e9b 1056 fdip = ip->pip;
f3843dc2 1057 cdip = hammer2_inode_common_parent(hmp, fdip, tdip);
99535653
MD
1058
1059 /*
51bf8e9b
MD
1060 * If no change in the hardlink's target directory is required and
1061 * this is already a hardlink target, all we need to do is adjust
1062 * the link count.
99535653 1063 */
51bf8e9b
MD
1064 if (cdip == fdip &&
1065 (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
1066 if (nlinks) {
1067 hammer2_chain_modify(hmp, chain, 0);
1068 chain->data->ipdata.nlinks += nlinks;
476d2aad 1069 }
51bf8e9b
MD
1070 *chainp = chain;
1071 error = 0;
1072 goto done;
99535653
MD
1073 }
1074
1075 /*
51bf8e9b
MD
1076 * We either have to move an existing hardlink target or we have
1077 * to create a fresh hardlink target.
28ee5f14 1078 *
51bf8e9b
MD
1079 * Hardlink targets are hidden inodes in a parent directory common
1080 * to all directory entries referencing the hardlink.
99535653 1081 */
51bf8e9b 1082 error = hammer2_inode_duplicate(cdip, chain, &nchain);
99535653
MD
1083 if (error == 0) {
1084 /*
1085 * Bump nlinks on duplicated hidden inode.
1086 */
e2e9e2db 1087 hammer2_chain_modify(hmp, nchain, 0);
51bf8e9b 1088 nchain->data->ipdata.nlinks += nlinks;
99535653 1089
51bf8e9b
MD
1090 /*
1091 * If the old chain is not a hardlink target then replace
1092 * it with a OBJTYPE_HARDLINK pointer.
1093 *
1094 * If the old chain IS a hardlink target then delete it.
1095 */
1096 if (chain->data->ipdata.name_key & HAMMER2_DIRHASH_VISIBLE) {
1097 hammer2_chain_modify(hmp, chain, 0);
1098 ipdata = &chain->data->ipdata;
1099 ipdata->target_type = ipdata->type;
1100 ipdata->type = HAMMER2_OBJTYPE_HARDLINK;
1101 ipdata->uflags = 0;
1102 ipdata->rmajor = 0;
1103 ipdata->rminor = 0;
1104 ipdata->ctime = 0;
1105 ipdata->mtime = 0;
1106 ipdata->atime = 0;
1107 ipdata->btime = 0;
1108 bzero(&ipdata->uid, sizeof(ipdata->uid));
1109 bzero(&ipdata->gid, sizeof(ipdata->gid));
1110 ipdata->op_flags = HAMMER2_OPFLAG_DIRECTDATA;
1111 ipdata->cap_flags = 0;
1112 ipdata->mode = 0;
1113 ipdata->size = 0;
1114 ipdata->nlinks = 1;
1115 ipdata->iparent = 0; /* XXX */
1116 ipdata->pfs_type = 0;
1117 ipdata->pfs_inum = 0;
1118 bzero(&ipdata->pfs_clid, sizeof(ipdata->pfs_clid));
1119 bzero(&ipdata->pfs_fsid, sizeof(ipdata->pfs_fsid));
1120 ipdata->data_quota = 0;
1121 ipdata->data_count = 0;
1122 ipdata->inode_quota = 0;
1123 ipdata->inode_count = 0;
1124 ipdata->attr_tid = 0;
1125 ipdata->dirent_tid = 0;
1126 bzero(&ipdata->u, sizeof(ipdata->u));
99535653 1127 /* XXX transaction ids */
99535653 1128 } else {
99535653 1129 kprintf("DELETE INVISIBLE\n");
476d2aad 1130 for (;;) {
51bf8e9b 1131 parent = chain->parent;
476d2aad 1132 hammer2_chain_ref(hmp, parent);
51bf8e9b
MD
1133 hammer2_chain_ref(hmp, chain);
1134 hammer2_chain_unlock(hmp, chain);
476d2aad
MD
1135 hammer2_chain_lock(hmp, parent,
1136 HAMMER2_RESOLVE_ALWAYS);
51bf8e9b
MD
1137 hammer2_chain_lock(hmp, chain,
1138 HAMMER2_RESOLVE_ALWAYS);
1139 hammer2_chain_drop(hmp, chain);
1140 if (chain->parent == parent)
476d2aad
MD
1141 break;
1142 hammer2_chain_unlock(hmp, parent);
1143 hammer2_chain_drop(hmp, parent);
1144 }
51bf8e9b 1145 hammer2_chain_delete(hmp, parent, chain, 0);
99535653 1146 hammer2_chain_unlock(hmp, parent);
476d2aad 1147 hammer2_chain_drop(hmp, parent);
99535653 1148 }
51bf8e9b
MD
1149
1150 /*
1151 * Replace ip->chain with nchain (ip is still locked).
1152 */
1153 hammer2_chain_ref(hmp, nchain); /* ip->chain */
1154 if (ip->chain)
1155 hammer2_chain_drop(hmp, ip->chain); /* ip->chain */
1156 ip->chain = nchain;
1157
1158 hammer2_chain_unlock(hmp, chain);
1159 *chainp = nchain;
99535653 1160 } else {
51bf8e9b 1161 hammer2_chain_unlock(hmp, chain);
99535653 1162 }
51bf8e9b
MD
1163
1164 /*
1165 * Cleanup, chain/nchain already dealt with.
1166 */
1167done:
1168 hammer2_inode_unlock_ex(ip, NULL);
f3843dc2 1169 hammer2_inode_drop(cdip);
99535653
MD
1170
1171 return (error);
e708f8b9
MD
1172}
1173
1174/*
476d2aad
MD
1175 * If (*ochainp) is non-NULL it points to the forward OBJTYPE_HARDLINK
1176 * inode while (*chainp) points to the resolved (hidden hardlink
1177 * target) inode. In this situation when nlinks is 1 we wish to
1178 * deconsolidate the hardlink, moving it back to the directory that now
1179 * represents the only remaining link.
e708f8b9
MD
1180 */
1181int
476d2aad
MD
1182hammer2_hardlink_deconsolidate(hammer2_inode_t *dip,
1183 hammer2_chain_t **chainp,
1184 hammer2_chain_t **ochainp)
e708f8b9 1185{
476d2aad 1186 if (*ochainp == NULL)
e708f8b9
MD
1187 return (0);
1188 /* XXX */
1189 return (0);
1190}
1191
1192/*
476d2aad
MD
1193 * The caller presents a locked *chainp pointing to a HAMMER2_BREF_TYPE_INODE
1194 * with an obj_type of HAMMER2_OBJTYPE_HARDLINK. This routine will gobble
1195 * the *chainp and return a new locked *chainp representing the file target
1196 * (the original *chainp will be unlocked).
1197 *
1198 * When a match is found the chain representing the original HARDLINK
1199 * will be returned in *ochainp with a ref, but not locked.
1200 *
1201 * When no match is found *chainp is set to NULL and EIO is returned.
1202 * (*ochainp) will still be set to the original chain with a ref but not
1203 * locked.
e708f8b9
MD
1204 */
1205int
1206hammer2_hardlink_find(hammer2_inode_t *dip, hammer2_chain_t **chainp,
476d2aad 1207 hammer2_chain_t **ochainp)
e708f8b9 1208{
99535653
MD
1209 hammer2_mount_t *hmp = dip->hmp;
1210 hammer2_chain_t *chain = *chainp;
1211 hammer2_chain_t *parent;
476d2aad 1212 hammer2_inode_t *ip;
99535653
MD
1213 hammer2_inode_t *pip;
1214 hammer2_key_t lhc;
1215
476d2aad
MD
1216 pip = dip;
1217 hammer2_inode_ref(pip); /* for loop */
1218 hammer2_chain_ref(hmp, chain); /* for (*ochainp) */
99535653 1219
476d2aad 1220 *ochainp = chain;
99535653 1221
476d2aad
MD
1222 /*
1223 * Locate the hardlink. pip is referenced and not locked,
1224 * ipp.
1225 *
1226 * chain is reused.
1227 */
1228 lhc = chain->data->ipdata.inum;
1229 hammer2_chain_unlock(hmp, chain);
99535653 1230 chain = NULL;
99535653 1231
476d2aad 1232 while ((ip = pip) != NULL) {
e2e9e2db 1233 parent = hammer2_inode_lock_ex(ip);
10252dc7 1234 hammer2_inode_drop(ip); /* loop */
476d2aad 1235 KKASSERT(parent->bref.type == HAMMER2_BREF_TYPE_INODE);
99535653 1236 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
99535653
MD
1237 hammer2_chain_unlock(hmp, parent);
1238 if (chain)
1239 break;
476d2aad
MD
1240 pip = ip->pip; /* safe, ip held locked */
1241 if (pip)
10252dc7 1242 hammer2_inode_ref(pip); /* loop */
e2e9e2db 1243 hammer2_inode_unlock_ex(ip, NULL);
99535653 1244 }
476d2aad
MD
1245
1246 /*
1247 * chain is locked, ip is locked. Unlock ip, return the locked
1248 * chain. *ipp is already set w/a ref count and not locked.
e2e9e2db
MD
1249 *
1250 * (parent is already unlocked).
476d2aad 1251 */
e2e9e2db 1252 hammer2_inode_unlock_ex(ip, NULL);
99535653
MD
1253 *chainp = chain;
1254 if (chain) {
1255 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE);
1256 /* already locked */
1257 return (0);
1258 } else {
1259 return (EIO);
1260 }
e708f8b9 1261}
f3843dc2
MD
1262
1263/*
1264 * Find the directory common to both fdip and tdip, hold and return
1265 * its inode.
1266 */
1267hammer2_inode_t *
1268hammer2_inode_common_parent(hammer2_mount_t *hmp,
1269 hammer2_inode_t *fdip, hammer2_inode_t *tdip)
1270{
1271 hammer2_inode_t *scan1;
1272 hammer2_inode_t *scan2;
1273
1274 /*
1275 * We used to have a depth field but it complicated matters too
1276 * much for directory renames. So now its ugly. Check for
1277 * simple cases before giving up and doing it the expensive way.
1278 *
1279 * XXX need a bottom-up topology stability lock
1280 */
1281 if (fdip == tdip || fdip == tdip->pip) {
1282 hammer2_inode_ref(fdip);
1283 return(fdip);
1284 }
1285 if (fdip->pip == tdip) {
1286 hammer2_inode_ref(tdip);
1287 return(tdip);
1288 }
51bf8e9b
MD
1289
1290 /*
1291 * XXX not MPSAFE
1292 */
f3843dc2
MD
1293 for (scan1 = fdip; scan1->pmp == fdip->pmp; scan1 = scan1->pip) {
1294 scan2 = tdip;
1295 while (scan2->pmp == tdip->pmp) {
1296 if (scan1 == scan2) {
1297 hammer2_inode_ref(scan1);
1298 return(scan1);
1299 }
1300 scan2 = scan2->pip;
1301 }
1302 }
1303 panic("hammer2_inode_common_parent: no common parent %p %p\n",
1304 fdip, tdip);
1305 /* NOT REACHED */
1306 return(NULL);
1307}