bf7ec1c5c4ab60e9888a2db400553c0cb30e2f87
[dragonfly.git] / sys / vfs / hammer2 / hammer2_subr.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/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/types.h>
40 #include <sys/lock.h>
41 #include <sys/uuid.h>
42 #include <sys/dirent.h>
43
44 #include "hammer2.h"
45
46 /*
47  * HAMMER2 inode locks
48  *
49  * HAMMER2 offers shared locks, update locks, and exclusive locks on inodes.
50  *
51  * Shared locks allow concurrent access to an inode's fields, but exclude
52  * access by concurrent exclusive locks.
53  *
54  * Update locks are interesting -- an update lock will be taken after all
55  * shared locks on an inode are released, but once it is in place, shared
56  * locks may proceed. The update field is signalled by a busy flag in the
57  * inode. Only one update lock may be in place at a given time on an inode.
58  *
59  * Exclusive locks prevent concurrent access to the inode.
60  *
61  * XXX: What do we use each for? How is visibility to the inode controlled?
62  */
63
64
65 void
66 hammer2_inode_lock_ex(hammer2_inode_t *ip)
67 {
68         hammer2_chain_lock(ip->hmp, &ip->chain, HAMMER2_RESOLVE_ALWAYS);
69 }
70
71 void
72 hammer2_inode_unlock_ex(hammer2_inode_t *ip)
73 {
74         hammer2_chain_unlock(ip->hmp, &ip->chain);
75 }
76
77 void
78 hammer2_inode_lock_sh(hammer2_inode_t *ip)
79 {
80         KKASSERT(ip->chain.refs > 0);
81         lockmgr(&ip->chain.lk, LK_SHARED);
82 }
83
84 void
85 hammer2_inode_unlock_sh(hammer2_inode_t *ip)
86 {
87         lockmgr(&ip->chain.lk, LK_RELEASE);
88 }
89
90 /*
91  * Soft-busy an inode.
92  *
93  * The inode must be exclusively locked while soft-busying or soft-unbusying
94  * an inode.  Once busied or unbusied the caller can release the lock.
95  */
96 void
97 hammer2_inode_busy(hammer2_inode_t *ip)
98 {
99         if (ip->chain.busy++ == 0)
100                 hammer2_chain_ref(ip->hmp, &ip->chain);
101 }
102
103 void
104 hammer2_inode_unbusy(hammer2_inode_t *ip)
105 {
106         if (--ip->chain.busy == 0)
107                 hammer2_chain_drop(ip->hmp, &ip->chain);
108 }
109
110 /*
111  * Mount-wide locks
112  */
113
114 void
115 hammer2_mount_exlock(hammer2_mount_t *hmp)
116 {
117         lockmgr(&hmp->vchain.lk, LK_EXCLUSIVE);
118 }
119
120 void
121 hammer2_mount_shlock(hammer2_mount_t *hmp)
122 {
123         lockmgr(&hmp->vchain.lk, LK_SHARED);
124 }
125
126 void
127 hammer2_mount_unlock(hammer2_mount_t *hmp)
128 {
129         lockmgr(&hmp->vchain.lk, LK_RELEASE);
130 }
131
132 /*
133  * Return the directory entry type for an inode
134  */
135 int
136 hammer2_get_dtype(hammer2_inode_t *ip)
137 {
138         switch(ip->ip_data.type) {
139         case HAMMER2_OBJTYPE_UNKNOWN:
140                 return (DT_UNKNOWN);
141         case HAMMER2_OBJTYPE_DIRECTORY:
142                 return (DT_DIR);
143         case HAMMER2_OBJTYPE_REGFILE:
144                 return (DT_REG);
145         case HAMMER2_OBJTYPE_FIFO:
146                 return (DT_FIFO);
147         case HAMMER2_OBJTYPE_CDEV:      /* not supported */
148                 return (DT_CHR);
149         case HAMMER2_OBJTYPE_BDEV:      /* not supported */
150                 return (DT_BLK);
151         case HAMMER2_OBJTYPE_SOFTLINK:
152                 return (DT_LNK);
153         case HAMMER2_OBJTYPE_HARDLINK:  /* (never directly associated w/vp) */
154                 return (DT_UNKNOWN);
155         case HAMMER2_OBJTYPE_SOCKET:
156                 return (DT_SOCK);
157         case HAMMER2_OBJTYPE_WHITEOUT:  /* not supported */
158                 return (DT_UNKNOWN);
159         default:
160                 return (DT_UNKNOWN);
161         }
162         /* not reached */
163 }
164
165 /*
166  * Return the directory entry type for an inode
167  */
168 int
169 hammer2_get_vtype(hammer2_inode_t *ip)
170 {
171         switch(ip->ip_data.type) {
172         case HAMMER2_OBJTYPE_UNKNOWN:
173                 return (VBAD);
174         case HAMMER2_OBJTYPE_DIRECTORY:
175                 return (VDIR);
176         case HAMMER2_OBJTYPE_REGFILE:
177                 return (VREG);
178         case HAMMER2_OBJTYPE_FIFO:
179                 return (VFIFO);
180         case HAMMER2_OBJTYPE_CDEV:      /* not supported */
181                 return (VCHR);
182         case HAMMER2_OBJTYPE_BDEV:      /* not supported */
183                 return (VBLK);
184         case HAMMER2_OBJTYPE_SOFTLINK:
185                 return (VLNK);
186         case HAMMER2_OBJTYPE_HARDLINK:  /* XXX */
187                 return (VBAD);
188         case HAMMER2_OBJTYPE_SOCKET:
189                 return (VSOCK);
190         case HAMMER2_OBJTYPE_WHITEOUT:  /* not supported */
191                 return (DT_UNKNOWN);
192         default:
193                 return (DT_UNKNOWN);
194         }
195         /* not reached */
196 }
197
198 u_int8_t
199 hammer2_get_obj_type(enum vtype vtype)
200 {
201         switch(vtype) {
202         case VDIR:
203                 return(HAMMER2_OBJTYPE_DIRECTORY);
204         case VREG:
205                 return(HAMMER2_OBJTYPE_REGFILE);
206         case VFIFO:
207                 return(HAMMER2_OBJTYPE_FIFO);
208         case VSOCK:
209                 return(HAMMER2_OBJTYPE_SOCKET);
210         case VCHR:
211                 return(HAMMER2_OBJTYPE_CDEV);
212         case VBLK:
213                 return(HAMMER2_OBJTYPE_BDEV);
214         case VLNK:
215                 return(HAMMER2_OBJTYPE_SOFTLINK);
216         default:
217                 return(HAMMER2_OBJTYPE_UNKNOWN);
218         }
219         /* not reached */
220 }
221
222 /*
223  * Convert a hammer2 64-bit time to a timespec.
224  */
225 void
226 hammer2_time_to_timespec(u_int64_t xtime, struct timespec *ts)
227 {
228         ts->tv_sec = (unsigned long)(xtime / 1000000);
229         ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L;
230 }
231
232 /*
233  * Convert a uuid to a unix uid or gid
234  */
235 u_int32_t
236 hammer2_to_unix_xid(uuid_t *uuid)
237 {
238         return(*(u_int32_t *)&uuid->node[2]);
239 }
240
241 /*
242  * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
243  * The filename is split into fields which are hashed separately and then
244  * added together.
245  *
246  * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
247  * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
248  * (This means we do not need to do a 0-check/or-with-0x100000000 either).
249  *
250  * Also, the iscsi crc code is used instead of the old crc32 code.
251  */
252 hammer2_key_t
253 hammer2_dirhash(const unsigned char *name, size_t len)
254 {
255         const unsigned char *aname = name;
256         uint32_t crcx;
257         uint64_t key;
258         size_t i;
259         size_t j;
260
261         key = 0;
262
263         /*
264          * m32
265          */
266         crcx = 0;
267         for (i = j = 0; i < len; ++i) {
268                 if (aname[i] == '.' ||
269                     aname[i] == '-' ||
270                     aname[i] == '_' ||
271                     aname[i] == '~') {
272                         if (i != j)
273                                 crcx += hammer2_icrc32(aname + j, i - j);
274                         j = i + 1;
275                 }
276         }
277         if (i != j)
278                 crcx += hammer2_icrc32(aname + j, i - j);
279
280         /*
281          * The directory hash utilizes the top 32 bits of the 64-bit key.
282          * Bit 63 must be set to 1.
283          */
284         crcx |= 0x80000000U;
285         key |= (uint64_t)crcx << 32;
286
287         /*
288          * l16 - crc of entire filename
289          *
290          * This crc reduces degenerate hash collision conditions
291          */
292         crcx = hammer2_icrc32(aname, len);
293         crcx = crcx ^ (crcx << 16);
294         key |= crcx & 0xFFFF0000U;
295
296         /*
297          * Set bit 15.  This allows readdir to strip bit 63 so a positive
298          * 64-bit cookie/offset can always be returned, and still guarantee
299          * that the values 0x0000-0x7FFF are available for artificial entries.
300          * ('.' and '..').
301          */
302         key |= 0x8000U;
303
304         return (key);
305 }
306
307 /*
308  * Return the power-of-2 radix greater or equal to
309  * the specified number of bytes.
310  *
311  * Always returns at least HAMMER2_MIN_RADIX (2^6).
312  */
313 int
314 hammer2_bytes_to_radix(size_t bytes)
315 {
316         int radix;
317
318         if (bytes < HAMMER2_MIN_ALLOC)
319                 bytes = HAMMER2_MIN_ALLOC;
320         if (bytes == HAMMER2_PBUFSIZE)
321                 radix = HAMMER2_PBUFRADIX;
322         else if (bytes >= 1024)
323                 radix = 10;
324         else
325                 radix = HAMMER2_MIN_RADIX;
326
327         while (((size_t)1 << radix) < bytes)
328                 ++radix;
329         return (radix);
330 }
331
332 int
333 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
334                      hammer2_key_t *lbasep, hammer2_key_t *leofp)
335 {
336         int radix;
337
338         *lbasep = uoff & ~HAMMER2_PBUFMASK64;
339         *leofp = ip->ip_data.size & ~HAMMER2_PBUFMASK;
340         KKASSERT(*lbasep <= *leofp);
341         if (*lbasep == *leofp) {
342                 radix = hammer2_bytes_to_radix(
343                                 (size_t)(ip->ip_data.size - *leofp));
344                 if (radix < HAMMER2_MINALLOCRADIX)
345                         radix = HAMMER2_MINALLOCRADIX;
346                 *leofp += 1U << radix;
347                 return (1U << radix);
348         } else {
349                 return (HAMMER2_PBUFSIZE);
350         }
351 }