8ae794dab4eaa46e87d64039d6ddf7f1c76e107b
[dragonfly.git] / sys / vfs / hammer2 / hammer2_inode.c
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>
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  */
48 void
49 hammer2_inode_ref(hammer2_inode_t *ip)
50 {
51         hammer2_chain_ref(ip->hmp, &ip->chain);
52 }
53
54 /*
55  * Drop an inode reference, freeing the inode when the last reference goes
56  * away.
57  */
58 void
59 hammer2_inode_drop(hammer2_inode_t *ip)
60 {
61         hammer2_chain_drop(ip->hmp, &ip->chain);
62 }
63
64 /*
65  * Get the vnode associated with the given inode, allocating the vnode if
66  * necessary.
67  *
68  * Great care must be taken to avoid deadlocks and vnode acquisition/reclaim
69  * races.
70  *
71  * The vnode will be returned exclusively locked and referenced.  The
72  * reference on the vnode prevents it from being reclaimed.
73  *
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.
76  */
77 struct vnode *
78 hammer2_igetv(hammer2_inode_t *ip, int *errorp)
79 {
80         struct vnode *vp;
81         hammer2_pfsmount_t *pmp;
82
83         pmp = ip->pmp;
84         KKASSERT(pmp != NULL);
85         *errorp = 0;
86
87         for (;;) {
88                 /*
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.
93                  */
94                 vp = ip->vp;
95                 if (vp) {
96                         /*
97                          * Lock the inode and check for a reclaim race
98                          */
99                         hammer2_inode_lock_ex(ip);
100                         if (ip->vp != vp) {
101                                 hammer2_inode_unlock_ex(ip);
102                                 continue;
103                         }
104
105                         /*
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.
110                          */
111                         vhold_interlocked(vp);
112                         hammer2_inode_unlock_ex(ip);
113                         if (vget(vp, LK_EXCLUSIVE)) {
114                                 vdrop(vp);
115                                 continue;
116                         }
117                         vdrop(vp);
118                         /* vp still locked and ref from vget */
119                         *errorp = 0;
120                         break;
121                 }
122
123                 /*
124                  * No vnode exists, allocate a new vnode.  Beware of
125                  * allocation races.  This function will return an
126                  * exclusively locked and referenced vnode.
127                  */
128                 *errorp = getnewvnode(VT_HAMMER2, pmp->mp, &vp, 0, 0);
129                 if (*errorp) {
130                         vp = NULL;
131                         break;
132                 }
133
134                 /*
135                  * Lock the inode and check for an allocation race.
136                  */
137                 hammer2_inode_lock_ex(ip);
138                 if (ip->vp != NULL) {
139                         vp->v_type = VBAD;
140                         vx_put(vp);
141                         hammer2_inode_unlock_ex(ip);
142                         continue;
143                 }
144
145                 switch (ip->ip_data.type) {
146                 case HAMMER2_OBJTYPE_DIRECTORY:
147                         vp->v_type = VDIR;
148                         break;
149                 case HAMMER2_OBJTYPE_REGFILE:
150                         vp->v_type = VREG;
151                         vinitvmio(vp, ip->ip_data.size,
152                                   HAMMER2_LBUFSIZE,
153                                   (int)ip->ip_data.size & HAMMER2_LBUFMASK);
154                         break;
155                 case HAMMER2_OBJTYPE_SOFTLINK:
156                         /*
157                          * XXX for now we are using the generic file_read
158                          * and file_write code so we need a buffer cache
159                          * association.
160                          */
161                         vp->v_type = VLNK;
162                         vinitvmio(vp, ip->ip_data.size,
163                                   HAMMER2_LBUFSIZE,
164                                   (int)ip->ip_data.size & HAMMER2_LBUFMASK);
165                         break;
166                 /* XXX FIFO */
167                 default:
168                         panic("hammer2: unhandled objtype %d",
169                               ip->ip_data.type);
170                         break;
171                 }
172
173                 if (ip == pmp->iroot)
174                         vsetflags(vp, VROOT);
175
176                 vp->v_data = ip;
177                 ip->vp = vp;
178                 hammer2_chain_ref(ip->hmp, &ip->chain); /* vp association */
179                 hammer2_inode_unlock_ex(ip);
180                 break;
181         }
182
183         /*
184          * Return non-NULL vp and *errorp == 0, or NULL vp and *errorp != 0.
185          */
186         if (hammer2_debug & 0x0002) {
187                 kprintf("igetv vp %p refs %d aux %d\n",
188                         vp, vp->v_sysref.refcnt, vp->v_auxrefs);
189         }
190         return (vp);
191 }
192
193 /*
194  * Create a new inode in the specified directory using the vattr to
195  * figure out the type of inode.
196  *
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.
199  *
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.
203  */
204 int
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)
209 {
210         hammer2_mount_t *hmp = dip->hmp;
211         hammer2_chain_t *chain;
212         hammer2_chain_t *parent;
213         hammer2_inode_t *nip;
214         hammer2_key_t lhc;
215         int error;
216         uid_t xuid;
217
218         lhc = hammer2_dirhash(name, name_len);
219
220         /*
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.
224          */
225         parent = &dip->chain;
226         hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
227
228         error = 0;
229         while (error == 0) {
230                 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
231                 if (chain == NULL)
232                         break;
233                 if ((lhc & HAMMER2_DIRHASH_VISIBLE) == 0)
234                         error = ENOSPC;
235                 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
236                         error = ENOSPC;
237                 hammer2_chain_unlock(hmp, chain);
238                 chain = NULL;
239                 ++lhc;
240         }
241         if (error == 0) {
242                 chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0,
243                                              HAMMER2_BREF_TYPE_INODE,
244                                              HAMMER2_INODE_BYTES);
245                 if (chain == NULL)
246                         error = EIO;
247         }
248         hammer2_chain_unlock(hmp, parent);
249
250         /*
251          * Handle the error case
252          */
253         if (error) {
254                 KKASSERT(chain == NULL);
255                 *nipp = NULL;
256                 return (error);
257         }
258
259         /*
260          * Set up the new inode
261          */
262         nip = chain->u.ip;
263         *nipp = nip;
264
265         hammer2_voldata_lock(hmp);
266         if (vap) {
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 */
270         } else {
271                 nip->ip_data.type = HAMMER2_OBJTYPE_DIRECTORY;
272                 nip->ip_data.inum = 1;
273         }
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;
278         if (vap)
279                 nip->ip_data.mode = vap->va_mode;
280         nip->ip_data.nlinks = 1;
281         if (vap) {
282                 if (dip) {
283                         xuid = hammer2_to_unix_xid(&dip->ip_data.uid);
284                         xuid = vop_helper_create_uid(dip->pmp->mp,
285                                                      dip->ip_data.mode,
286                                                      xuid,
287                                                      cred,
288                                                      &vap->va_mode);
289                 } else {
290                         xuid = 0;
291                 }
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);
296                 else
297                         hammer2_guid_to_uuid(&nip->ip_data.uid, xuid);
298
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);
303                 else if (dip)
304                         nip->ip_data.gid = dip->ip_data.gid;
305         }
306
307         /*
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.
311          */
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;
315         }
316
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;
321
322         return (0);
323 }
324
325 /*
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.
328  *
329  * Returns the new inode.  The old inode is left alone.
330  */
331 int
332 hammer2_inode_duplicate(hammer2_inode_t *dip, hammer2_inode_t *oip,
333                         hammer2_inode_t **nipp,
334                         const uint8_t *name, size_t name_len)
335 {
336         hammer2_mount_t *hmp = dip->hmp;
337         hammer2_inode_t *nip;
338         hammer2_chain_t *parent;
339         hammer2_chain_t *chain;
340         hammer2_chain_t *scan;
341         hammer2_key_t lhc;
342         int error;
343
344         if (name) {
345                 lhc = hammer2_dirhash(name, name_len);
346         } else {
347                 lhc = oip->ip_data.inum;
348                 KKASSERT((lhc & HAMMER2_DIRHASH_VISIBLE) == 0);
349         }
350
351         /*
352          * Locate the inode or indirect block to create the new
353          * entry in.  At the same time check for key collisions
354          * and iterate until we don't get one.
355          */
356         nip = NULL;
357         parent = &dip->chain;
358         hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
359
360         error = 0;
361         while (error == 0) {
362                 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
363                 if (chain == NULL)
364                         break;
365                 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
366                         error = ENOSPC;
367                 hammer2_chain_unlock(hmp, chain);
368                 chain = NULL;
369                 ++lhc;
370         }
371
372         /*
373          * Passing a non-NULL chain to hammer2_chain_create() reconnects the
374          * existing chain instead of creating a new one.  The chain's bref
375          * will be properly updated.
376          */
377         if (error == 0) {
378                 chain = hammer2_chain_create(hmp, parent, NULL, lhc, 0,
379                                              HAMMER2_BREF_TYPE_INODE /* n/a */,
380                                              HAMMER2_INODE_BYTES);   /* n/a */
381                 if (chain == NULL)
382                         error = EIO;
383         }
384         hammer2_chain_unlock(hmp, parent);
385
386         /*
387          * Handle the error case
388          */
389         if (error) {
390                 KKASSERT(chain == NULL);
391                 return (error);
392         }
393         nip = chain->u.ip;
394         hammer2_chain_modify(hmp, chain, 0);
395         nip->ip_data = oip->ip_data;
396
397         /*
398          * XXX This is currently a horrible hack.  Well, if we wanted to
399          *     duplicate a file, i.e. as in a snapshot, we definitely
400          *     would have to flush it first.
401          *
402          *     For hardlink target generation we can theoretically move any
403          *     active chain structures without flushing, but that gets really
404          *     iffy for code which follows chain->parent and ip->pip links.
405          *
406          * XXX only works with files.  Duplicating a directory hierarchy
407          *     requires a flush but doesn't deal with races post-flush.
408          *     Well, it would work I guess, but you might catch some files
409          *     mid-operation.
410          *
411          * We cannot leave oip with any in-memory chains because (for a
412          * hardlink), oip will become a OBJTYPE_HARDLINK which is just a
413          * pointer to the real hardlink's inum and can't have any sub-chains.
414          */
415         hammer2_inode_lock_ex(oip);
416         hammer2_chain_flush(hmp, &oip->chain, 0);
417         hammer2_inode_unlock_ex(oip);
418         KKASSERT(SPLAY_EMPTY(&oip->chain.shead));
419
420         if (name) {
421                 /*
422                  * Directory entries are inodes so if the name has changed
423                  * we have to update the inode.
424                  */
425                 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
426                 bcopy(name, nip->ip_data.filename, name_len);
427                 nip->ip_data.name_key = lhc;
428                 nip->ip_data.name_len = name_len;
429         } else {
430                 /*
431                  * Directory entries are inodes but this is a hidden hardlink
432                  * target.  The name isn't used but to ease debugging give it
433                  * a name after its inode number.
434                  */
435                 ksnprintf(nip->ip_data.filename, sizeof(nip->ip_data.filename),
436                           "0x%016jx", (intmax_t)nip->ip_data.inum);
437                 nip->ip_data.name_len = strlen(nip->ip_data.filename);
438                 nip->ip_data.name_key = lhc;
439         }
440         *nipp = nip;
441
442         return (0);
443 }
444
445
446 /*
447  * Connect inode (oip) to the specified directory using the specified name.
448  * (oip) must be locked.
449  *
450  * If (oip) is not currently connected we simply connect it up.
451  *
452  * If (oip) is already connected we create a OBJTYPE_HARDLINK entry which
453  * points to (oip)'s inode number.  (oip) is expected to be the terminus of
454  * the hardlink sitting as a hidden file in a common parent directory
455  * in this situation (thus the lock order is correct).
456  */
457 int
458 hammer2_inode_connect(hammer2_inode_t *dip, hammer2_inode_t *oip,
459                       const uint8_t *name, size_t name_len)
460 {
461         hammer2_mount_t *hmp = dip->hmp;
462         hammer2_chain_t *chain;
463         hammer2_chain_t *parent;
464         hammer2_inode_t *nip;
465         hammer2_key_t lhc;
466         int error;
467         int hlink;
468
469         lhc = hammer2_dirhash(name, name_len);
470         hlink = ((oip->chain.flags & HAMMER2_CHAIN_DELETED) == 0);
471
472         /*
473          * Locate the inode or indirect block to create the new
474          * entry in.  At the same time check for key collisions
475          * and iterate until we don't get one.
476          */
477         parent = &dip->chain;
478         hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
479
480         error = 0;
481         while (error == 0) {
482                 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
483                 if (chain == NULL)
484                         break;
485                 if ((lhc & HAMMER2_DIRHASH_LOMASK) == HAMMER2_DIRHASH_LOMASK)
486                         error = ENOSPC;
487                 hammer2_chain_unlock(hmp, chain);
488                 chain = NULL;
489                 ++lhc;
490         }
491
492         /*
493          * Passing a non-NULL chain to hammer2_chain_create() reconnects the
494          * existing chain instead of creating a new one.  The chain's bref
495          * will be properly updated.
496          */
497         if (error == 0) {
498                 if (hlink) {
499                         chain = hammer2_chain_create(hmp, parent,
500                                                      NULL, lhc, 0,
501                                                      HAMMER2_BREF_TYPE_INODE,
502                                                      HAMMER2_INODE_BYTES);
503                 } else {
504                         chain = hammer2_chain_create(hmp, parent,
505                                                      &oip->chain, lhc, 0,
506                                                      HAMMER2_BREF_TYPE_INODE,
507                                                      HAMMER2_INODE_BYTES);
508                         if (chain)
509                                 KKASSERT(chain == &oip->chain);
510                 }
511                 if (chain == NULL)
512                         error = EIO;
513         }
514         hammer2_chain_unlock(hmp, parent);
515
516         /*
517          * Handle the error case
518          */
519         if (error) {
520                 KKASSERT(chain == NULL);
521                 return (error);
522         }
523
524         /*
525          * Directory entries are inodes so if the name has changed we have
526          * to update the inode.
527          *
528          * When creating an OBJTYPE_HARDLINK entry remember to unlock the
529          * chain, the caller will access the hardlink via the actual hardlink
530          * target file and not the hardlink pointer entry.
531          */
532         if (hlink) {
533                 /*
534                  * Create the HARDLINK pointer.  oip represents the hardlink
535                  * target in this situation.
536                  */
537                 nip = chain->u.ip;
538                 hammer2_chain_modify(hmp, chain, 0);
539                 KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
540                 bcopy(name, nip->ip_data.filename, name_len);
541                 nip->ip_data.name_key = lhc;
542                 nip->ip_data.name_len = name_len;
543                 nip->ip_data.target_type = oip->ip_data.type;
544                 nip->ip_data.type = HAMMER2_OBJTYPE_HARDLINK;
545                 nip->ip_data.inum = oip->ip_data.inum;
546                 nip->ip_data.nlinks = 1;
547                 kprintf("created hardlink %*.*s\n",
548                         (int)name_len, (int)name_len, name);
549                 hammer2_chain_unlock(hmp, chain);
550         } else {
551                 /*
552                  * The name may have changed on reconnect, adjust oip.
553                  *
554                  * We are using oip as chain, already locked by caller,
555                  * do not unlock it.
556                  */
557                 hammer2_chain_modify(hmp, chain, 0);
558                 if (oip->ip_data.name_len != name_len ||
559                     bcmp(oip->ip_data.filename, name, name_len) != 0) {
560                         KKASSERT(name_len < HAMMER2_INODE_MAXNAME);
561                         bcopy(name, oip->ip_data.filename, name_len);
562                         oip->ip_data.name_key = lhc;
563                         oip->ip_data.name_len = name_len;
564                 }
565                 oip->ip_data.nlinks = 1;
566         }
567
568         return (0);
569 }
570
571 /*
572  * Unlink the file from the specified directory inode.  The directory inode
573  * does not need to be locked.
574  *
575  * isdir determines whether a directory/non-directory check should be made.
576  * No check is made if isdir is set to -1.
577  */
578 int
579 hammer2_unlink_file(hammer2_inode_t *dip,
580                     const uint8_t *name, size_t name_len, int isdir)
581 {
582         hammer2_mount_t *hmp;
583         hammer2_chain_t *parent;
584         hammer2_chain_t *chain;
585         hammer2_chain_t *dparent;
586         hammer2_chain_t *dchain;
587         hammer2_key_t lhc;
588         hammer2_inode_t *ip;
589         hammer2_inode_t *oip;
590         int error;
591         uint8_t type;
592
593         error = 0;
594         oip = NULL;
595         hmp = dip->hmp;
596         lhc = hammer2_dirhash(name, name_len);
597
598         /*
599          * Search for the filename in the directory
600          */
601         parent = &dip->chain;
602         hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
603         chain = hammer2_chain_lookup(hmp, &parent,
604                                      lhc, lhc + HAMMER2_DIRHASH_LOMASK,
605                                      0);
606         while (chain) {
607                 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
608                     chain->u.ip &&
609                     name_len == chain->data->ipdata.name_len &&
610                     bcmp(name, chain->data->ipdata.filename, name_len) == 0) {
611                         break;
612                 }
613                 chain = hammer2_chain_next(hmp, &parent, chain,
614                                            lhc, lhc + HAMMER2_DIRHASH_LOMASK,
615                                            0);
616         }
617
618         /*
619          * Not found or wrong type (isdir < 0 disables the type check).
620          */
621         if (chain == NULL) {
622                 hammer2_chain_unlock(hmp, parent);
623                 return ENOENT;
624         }
625         if ((type = chain->data->ipdata.type) == HAMMER2_OBJTYPE_HARDLINK)
626                 type = chain->data->ipdata.target_type;
627
628         if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir == 0) {
629                 error = ENOTDIR;
630                 goto done;
631         }
632         if (type != HAMMER2_OBJTYPE_DIRECTORY && isdir == 1) {
633                 error = EISDIR;
634                 goto done;
635         }
636
637         /*
638          * Hardlink must be resolved.  We can't hold parent locked while we
639          * do this or we could deadlock.
640          */
641         if (chain->data->ipdata.type == HAMMER2_OBJTYPE_HARDLINK) {
642                 hammer2_chain_unlock(hmp, parent);
643                 parent = NULL;
644                 error = hammer2_hardlink_find(dip, &chain, &oip);
645         }
646
647         /*
648          * If this is a directory the directory must be empty.  However, if
649          * isdir < 0 we are doing a rename and the directory does not have
650          * to be empty.
651          */
652         if (type == HAMMER2_OBJTYPE_DIRECTORY && isdir >= 0) {
653                 dparent = chain;
654                 hammer2_chain_lock(hmp, dparent, HAMMER2_RESOLVE_ALWAYS);
655                 dchain = hammer2_chain_lookup(hmp, &dparent,
656                                               0, (hammer2_key_t)-1,
657                                               HAMMER2_LOOKUP_NODATA);
658                 if (dchain) {
659                         hammer2_chain_unlock(hmp, dchain);
660                         hammer2_chain_unlock(hmp, dparent);
661                         error = ENOTEMPTY;
662                         goto done;
663                 }
664                 hammer2_chain_unlock(hmp, dparent);
665                 dparent = NULL;
666                 /* dchain NULL */
667         }
668
669         /*
670          * Ok, we can now unlink the chain.  We always decrement nlinks even
671          * if the entry can be deleted in case someone has the file open and
672          * does an fstat().
673          *
674          * The chain itself will no longer have a media reference.  When the
675          * last vnode/ip ref goes away the chain will be marked unmodified,
676          * avoiding unnecessary I/O.
677          */
678         if (oip) {
679                 /*
680                  * If this was a hardlink we first delete the hardlink
681                  * pointer entry.
682                  */
683                 parent = oip->chain.parent;
684                 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
685                 hammer2_chain_lock(hmp, &oip->chain, HAMMER2_RESOLVE_ALWAYS);
686                 hammer2_chain_delete(hmp, parent, &oip->chain);
687                 hammer2_chain_unlock(hmp, &oip->chain);
688                 hammer2_chain_unlock(hmp, parent);
689                 parent = NULL;
690
691                 /*
692                  * Then decrement nlinks on hardlink target.
693                  */
694                 ip = chain->u.ip;
695                 if (ip->ip_data.nlinks == 1) {
696                         dparent = chain->parent;
697                         hammer2_chain_ref(hmp, chain);
698                         hammer2_chain_unlock(hmp, chain);
699                         hammer2_chain_lock(hmp, dparent,
700                                            HAMMER2_RESOLVE_ALWAYS);
701                         hammer2_chain_lock(hmp, chain, HAMMER2_RESOLVE_ALWAYS);
702                         hammer2_chain_drop(hmp, chain);
703                         hammer2_chain_modify(hmp, chain, 0);
704                         --ip->ip_data.nlinks;
705                         hammer2_chain_delete(hmp, dparent, chain);
706                         hammer2_chain_unlock(hmp, dparent);
707                 } else {
708                         hammer2_chain_modify(hmp, chain, 0);
709                         --ip->ip_data.nlinks;
710                 }
711         } else {
712                 /*
713                  * Otherwise this was not a hardlink and we can just
714                  * remove the entry and decrement nlinks.
715                  */
716                 ip = chain->u.ip;
717                 hammer2_chain_modify(hmp, chain, 0);
718                 --ip->ip_data.nlinks;
719                 hammer2_chain_delete(hmp, parent, chain);
720         }
721
722         error = 0;
723
724 done:
725         if (chain)
726                 hammer2_chain_unlock(hmp, chain);
727         if (parent)
728                 hammer2_chain_unlock(hmp, parent);
729         if (oip)
730                 hammer2_chain_drop(oip->hmp, &oip->chain);
731
732         return error;
733 }
734
735 /*
736  * Calculate the allocation size for the file fragment straddling EOF
737  */
738 int
739 hammer2_inode_calc_alloc(hammer2_key_t filesize)
740 {
741         int frag = (int)filesize & HAMMER2_PBUFMASK;
742         int radix;
743
744         if (frag == 0)
745                 return(0);
746         for (radix = HAMMER2_MINALLOCRADIX; frag > (1 << radix); ++radix)
747                 ;
748         return (radix);
749 }
750
751 void
752 hammer2_inode_lock_nlinks(hammer2_inode_t *ip)
753 {
754         hammer2_chain_ref(ip->hmp, &ip->chain);
755 }
756
757 void
758 hammer2_inode_unlock_nlinks(hammer2_inode_t *ip)
759 {
760         hammer2_chain_drop(ip->hmp, &ip->chain);
761 }
762
763 /*
764  * Consolidate for hard link creation.  This moves the specified terminal
765  * hardlink inode to a directory common to its current directory and tdip
766  * if necessary, replacing *ipp with the new inode chain element and
767  * modifying the original inode chain element to OBJTYPE_HARDLINK.
768  *
769  * If the original inode chain element was a prior incarnation of a hidden
770  * inode it can simply be deleted instead of converted.
771  *
772  * (*ipp)'s nlinks field is locked on entry and the new (*ipp)'s nlinks
773  * field will be locked on return (with the original's unlocked).
774  *
775  * The link count is bumped if requested.
776  */
777 int
778 hammer2_hardlink_consolidate(hammer2_inode_t **ipp, hammer2_inode_t *tdip)
779 {
780         hammer2_mount_t *hmp;
781         hammer2_inode_t *oip = *ipp;
782         hammer2_inode_t *nip = NULL;
783         hammer2_inode_t *fdip;
784         hammer2_chain_t *parent;
785         int error;
786
787         hmp = tdip->hmp;
788
789         if (hammer2_hardlink_enable < 0)
790                 return (0);
791         if (hammer2_hardlink_enable == 0)
792                 return (ENOTSUP);
793
794         /*
795          * Find the common parent directory
796          */
797         fdip = oip->pip;
798         while (fdip->depth > tdip->depth) {
799                 fdip = fdip->pip;
800                 KKASSERT(fdip != NULL);
801         }
802         while (tdip->depth > fdip->depth) {
803                 tdip = tdip->pip;
804                 KKASSERT(tdip != NULL);
805         }
806         while (fdip != tdip) {
807                 fdip = fdip->pip;
808                 tdip = tdip->pip;
809                 KKASSERT(fdip != NULL);
810                 KKASSERT(tdip != NULL);
811         }
812
813         /*
814          * Nothing to do (except bump the link count) if the hardlink has
815          * already been consolidated in the correct place.
816          */
817         if (oip->pip == fdip &&
818             (oip->ip_data.name_key & HAMMER2_DIRHASH_VISIBLE) == 0) {
819                 kprintf("hardlink already consolidated correctly\n");
820                 nip = oip;
821                 hammer2_inode_lock_ex(nip);
822                 hammer2_chain_modify(hmp, &nip->chain, 0);
823                 ++nip->ip_data.nlinks;
824                 hammer2_inode_unlock_ex(nip);
825                 return (0);
826         }
827
828         /*
829          * Create a hidden inode directory entry in the parent, copying
830          * (*oip)'s state.  Then replace oip with OBJTYPE_HARDLINK.
831          *
832          * The duplication function will either flush or move any chains
833          * under oip to the new hardlink target inode, retiring all chains
834          * related to oip before returning.  XXX vp->ip races.
835          */
836         error = hammer2_inode_duplicate(fdip, oip, &nip, NULL, 0);
837         if (error == 0) {
838                 /*
839                  * Bump nlinks on duplicated hidden inode.
840                  */
841                 kprintf("hardlink consolidation success in parent dir %s\n",
842                         fdip->ip_data.filename);
843                 hammer2_inode_lock_nlinks(nip);
844                 hammer2_inode_unlock_nlinks(oip);
845                 hammer2_chain_modify(hmp, &nip->chain, 0);
846                 ++nip->ip_data.nlinks;
847                 hammer2_inode_unlock_ex(nip);
848
849                 if (oip->ip_data.name_key & HAMMER2_DIRHASH_VISIBLE) {
850                         /*
851                          * Replace the old inode with an OBJTYPE_HARDLINK
852                          * pointer.
853                          */
854                         hammer2_inode_lock_ex(oip);
855                         hammer2_chain_modify(hmp, &oip->chain, 0);
856                         oip->ip_data.target_type = oip->ip_data.type;
857                         oip->ip_data.type = HAMMER2_OBJTYPE_HARDLINK;
858                         oip->ip_data.uflags = 0;
859                         oip->ip_data.rmajor = 0;
860                         oip->ip_data.rminor = 0;
861                         oip->ip_data.ctime = 0;
862                         oip->ip_data.mtime = 0;
863                         oip->ip_data.atime = 0;
864                         oip->ip_data.btime = 0;
865                         bzero(&oip->ip_data.uid, sizeof(oip->ip_data.uid));
866                         bzero(&oip->ip_data.gid, sizeof(oip->ip_data.gid));
867                         oip->ip_data.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
868                         oip->ip_data.cap_flags = 0;
869                         oip->ip_data.mode = 0;
870                         oip->ip_data.size = 0;
871                         oip->ip_data.nlinks = 1;
872                         oip->ip_data.iparent = 0;       /* XXX */
873                         oip->ip_data.pfs_type = 0;
874                         oip->ip_data.pfs_inum = 0;
875                         bzero(&oip->ip_data.pfs_id,
876                               sizeof(oip->ip_data.pfs_id));
877                         bzero(&oip->ip_data.pfs_fsid,
878                               sizeof(oip->ip_data.pfs_fsid));
879                         oip->ip_data.data_quota = 0;
880                         oip->ip_data.data_count = 0;
881                         oip->ip_data.inode_quota = 0;
882                         oip->ip_data.inode_count = 0;
883                         oip->ip_data.attr_tid = 0;
884                         oip->ip_data.dirent_tid = 0;
885                         bzero(&oip->ip_data.u, sizeof(oip->ip_data.u));
886                         /* XXX transaction ids */
887
888                         hammer2_inode_unlock_ex(oip);
889                 } else {
890                         /*
891                          * The old inode was a hardlink target, which we
892                          * have now moved.  We must delete it so the new
893                          * hardlink target at a higher directory level
894                          * becomes the only hardlink target for this inode.
895                          */
896                         kprintf("DELETE INVISIBLE\n");
897                         parent = oip->chain.parent;
898                         hammer2_chain_lock(hmp, parent,
899                                            HAMMER2_RESOLVE_ALWAYS);
900                         hammer2_chain_lock(hmp, &oip->chain,
901                                            HAMMER2_RESOLVE_ALWAYS);
902                         hammer2_chain_delete(hmp, parent, &oip->chain);
903                         hammer2_chain_unlock(hmp, &oip->chain);
904                         hammer2_chain_unlock(hmp, parent);
905                 }
906                 *ipp = nip;
907         } else {
908                 KKASSERT(nip == NULL);
909         }
910
911         return (error);
912 }
913
914 /*
915  * If (*ipp) is non-NULL it points to the forward OBJTYPE_HARDLINK inode while
916  * (*chainp) points to the resolved (hidden hardlink target) inode.  In this
917  * situation when nlinks is 1 we wish to deconsolidate the hardlink, moving
918  * it back to the directory that now represents the only remaining link.
919  */
920 int
921 hammer2_hardlink_deconsolidate(hammer2_inode_t *dip, hammer2_chain_t **chainp,
922                                hammer2_inode_t **ipp)
923 {
924         if (*ipp == NULL)
925                 return (0);
926         /* XXX */
927         return (0);
928 }
929
930 /*
931  * When presented with a (*chainp) representing an inode of type
932  * OBJTYPE_HARDLINK this code will save the original inode (with a ref)
933  * in (*ipp), and then locate the hidden hardlink target in (dip) or
934  * any parent directory above (dip).  The locked (*chainp) is replaced
935  * with a new locked (*chainp) representing the hardlink target.
936  */
937 int
938 hammer2_hardlink_find(hammer2_inode_t *dip, hammer2_chain_t **chainp,
939                       hammer2_inode_t **ipp)
940 {
941         hammer2_mount_t *hmp = dip->hmp;
942         hammer2_chain_t *chain = *chainp;
943         hammer2_chain_t *parent;
944         hammer2_inode_t *pip;
945         hammer2_key_t lhc;
946
947         *ipp = chain->u.ip;
948         hammer2_inode_ref(chain->u.ip);
949         lhc = chain->u.ip->ip_data.inum;
950
951         hammer2_inode_unlock_ex(chain->u.ip);
952         pip = chain->u.ip->pip;
953
954         chain = NULL;
955         while (pip) {
956                 parent = &pip->chain;
957                 KKASSERT(parent->bref.type == HAMMER2_BREF_TYPE_INODE);
958
959                 hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
960                 chain = hammer2_chain_lookup(hmp, &parent, lhc, lhc, 0);
961                 if (chain) {
962                         kprintf("found hardlink in dir %s\n",
963                                 pip->ip_data.filename);
964                 }
965                 hammer2_chain_unlock(hmp, parent);
966                 if (chain)
967                         break;
968                 pip = pip->pip;
969         }
970         *chainp = chain;
971         if (chain) {
972                 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE);
973                 /* already locked */
974                 return (0);
975         } else {
976                 return (EIO);
977         }
978 }