0f161e7454e9cd138b85ac3d73fb5a65b18bd925
[dragonfly.git] / sys / vfs / hammer2 / hammer2_subr.c
1 /*
2  * Copyright (c) 2011-2014 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 #include <sys/dirent.h>
42
43 #include "hammer2.h"
44
45 /*
46  * Mount-wide locks
47  */
48 void
49 hammer2_dev_exlock(hammer2_dev_t *hmp)
50 {
51         hammer2_mtx_ex(&hmp->vchain.lock);
52 }
53
54 void
55 hammer2_dev_shlock(hammer2_dev_t *hmp)
56 {
57         hammer2_mtx_sh(&hmp->vchain.lock);
58 }
59
60 void
61 hammer2_dev_unlock(hammer2_dev_t *hmp)
62 {
63         hammer2_mtx_unlock(&hmp->vchain.lock);
64 }
65
66 /*
67  * Return the directory entry type for an inode.
68  *
69  * ip must be locked sh/ex.
70  */
71 int
72 hammer2_get_dtype(const hammer2_inode_data_t *ipdata)
73 {
74         uint8_t type;
75
76         if ((type = ipdata->meta.type) == HAMMER2_OBJTYPE_HARDLINK)
77                 type = ipdata->meta.target_type;
78
79         switch(type) {
80         case HAMMER2_OBJTYPE_UNKNOWN:
81                 return (DT_UNKNOWN);
82         case HAMMER2_OBJTYPE_DIRECTORY:
83                 return (DT_DIR);
84         case HAMMER2_OBJTYPE_REGFILE:
85                 return (DT_REG);
86         case HAMMER2_OBJTYPE_FIFO:
87                 return (DT_FIFO);
88         case HAMMER2_OBJTYPE_CDEV:      /* not supported */
89                 return (DT_CHR);
90         case HAMMER2_OBJTYPE_BDEV:      /* not supported */
91                 return (DT_BLK);
92         case HAMMER2_OBJTYPE_SOFTLINK:
93                 return (DT_LNK);
94         case HAMMER2_OBJTYPE_HARDLINK:  /* (never directly associated w/vp) */
95                 return (DT_UNKNOWN);
96         case HAMMER2_OBJTYPE_SOCKET:
97                 return (DT_SOCK);
98         case HAMMER2_OBJTYPE_WHITEOUT:  /* not supported */
99                 return (DT_UNKNOWN);
100         default:
101                 return (DT_UNKNOWN);
102         }
103         /* not reached */
104 }
105
106 /*
107  * Return the directory entry type for an inode
108  */
109 int
110 hammer2_get_vtype(uint8_t type)
111 {
112         switch(type) {
113         case HAMMER2_OBJTYPE_UNKNOWN:
114                 return (VBAD);
115         case HAMMER2_OBJTYPE_DIRECTORY:
116                 return (VDIR);
117         case HAMMER2_OBJTYPE_REGFILE:
118                 return (VREG);
119         case HAMMER2_OBJTYPE_FIFO:
120                 return (VFIFO);
121         case HAMMER2_OBJTYPE_CDEV:      /* not supported */
122                 return (VCHR);
123         case HAMMER2_OBJTYPE_BDEV:      /* not supported */
124                 return (VBLK);
125         case HAMMER2_OBJTYPE_SOFTLINK:
126                 return (VLNK);
127         case HAMMER2_OBJTYPE_HARDLINK:  /* XXX */
128                 return (VBAD);
129         case HAMMER2_OBJTYPE_SOCKET:
130                 return (VSOCK);
131         case HAMMER2_OBJTYPE_WHITEOUT:  /* not supported */
132                 return (DT_UNKNOWN);
133         default:
134                 return (DT_UNKNOWN);
135         }
136         /* not reached */
137 }
138
139 u_int8_t
140 hammer2_get_obj_type(enum vtype vtype)
141 {
142         switch(vtype) {
143         case VDIR:
144                 return(HAMMER2_OBJTYPE_DIRECTORY);
145         case VREG:
146                 return(HAMMER2_OBJTYPE_REGFILE);
147         case VFIFO:
148                 return(HAMMER2_OBJTYPE_FIFO);
149         case VSOCK:
150                 return(HAMMER2_OBJTYPE_SOCKET);
151         case VCHR:
152                 return(HAMMER2_OBJTYPE_CDEV);
153         case VBLK:
154                 return(HAMMER2_OBJTYPE_BDEV);
155         case VLNK:
156                 return(HAMMER2_OBJTYPE_SOFTLINK);
157         default:
158                 return(HAMMER2_OBJTYPE_UNKNOWN);
159         }
160         /* not reached */
161 }
162
163 /*
164  * Convert a hammer2 64-bit time to a timespec.
165  */
166 void
167 hammer2_time_to_timespec(u_int64_t xtime, struct timespec *ts)
168 {
169         ts->tv_sec = (unsigned long)(xtime / 1000000);
170         ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L;
171 }
172
173 u_int64_t
174 hammer2_timespec_to_time(const struct timespec *ts)
175 {
176         u_int64_t xtime;
177
178         xtime = (unsigned)(ts->tv_nsec / 1000) +
179                 (unsigned long)ts->tv_sec * 1000000ULL;
180         return(xtime);
181 }
182
183 /*
184  * Convert a uuid to a unix uid or gid
185  */
186 u_int32_t
187 hammer2_to_unix_xid(const uuid_t *uuid)
188 {
189         return(*(const u_int32_t *)&uuid->node[2]);
190 }
191
192 void
193 hammer2_guid_to_uuid(uuid_t *uuid, u_int32_t guid)
194 {
195         bzero(uuid, sizeof(*uuid));
196         *(u_int32_t *)&uuid->node[2] = guid;
197 }
198
199 /*
200  * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
201  * The filename is split into fields which are hashed separately and then
202  * added together.
203  *
204  * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
205  * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
206  * (This means we do not need to do a 0-check/or-with-0x100000000 either).
207  *
208  * Also, the iscsi crc code is used instead of the old crc32 code.
209  */
210 hammer2_key_t
211 hammer2_dirhash(const unsigned char *name, size_t len)
212 {
213         const unsigned char *aname = name;
214         uint32_t crcx;
215         uint64_t key;
216         size_t i;
217         size_t j;
218
219         key = 0;
220
221         /*
222          * m32
223          */
224         crcx = 0;
225         for (i = j = 0; i < len; ++i) {
226                 if (aname[i] == '.' ||
227                     aname[i] == '-' ||
228                     aname[i] == '_' ||
229                     aname[i] == '~') {
230                         if (i != j)
231                                 crcx += hammer2_icrc32(aname + j, i - j);
232                         j = i + 1;
233                 }
234         }
235         if (i != j)
236                 crcx += hammer2_icrc32(aname + j, i - j);
237
238         /*
239          * The directory hash utilizes the top 32 bits of the 64-bit key.
240          * Bit 63 must be set to 1.
241          */
242         crcx |= 0x80000000U;
243         key |= (uint64_t)crcx << 32;
244
245         /*
246          * l16 - crc of entire filename
247          *
248          * This crc reduces degenerate hash collision conditions
249          */
250         crcx = hammer2_icrc32(aname, len);
251         crcx = crcx ^ (crcx << 16);
252         key |= crcx & 0xFFFF0000U;
253
254         /*
255          * Set bit 15.  This allows readdir to strip bit 63 so a positive
256          * 64-bit cookie/offset can always be returned, and still guarantee
257          * that the values 0x0000-0x7FFF are available for artificial entries.
258          * ('.' and '..').
259          */
260         key |= 0x8000U;
261
262         return (key);
263 }
264
265 #if 0
266 /*
267  * Return the power-of-2 radix greater or equal to
268  * the specified number of bytes.
269  *
270  * Always returns at least the minimum media allocation
271  * size radix, HAMMER2_RADIX_MIN (10), which is 1KB.
272  */
273 int
274 hammer2_allocsize(size_t bytes)
275 {
276         int radix;
277
278         if (bytes < HAMMER2_ALLOC_MIN)
279                 bytes = HAMMER2_ALLOC_MIN;
280         if (bytes == HAMMER2_PBUFSIZE)
281                 radix = HAMMER2_PBUFRADIX;
282         else if (bytes >= 16384)
283                 radix = 14;
284         else if (bytes >= 1024)
285                 radix = 10;
286         else
287                 radix = HAMMER2_RADIX_MIN;
288
289         while (((size_t)1 << radix) < bytes)
290                 ++radix;
291         return (radix);
292 }
293
294 #endif
295
296 /*
297  * Convert bytes to radix with no limitations
298  */
299 int
300 hammer2_getradix(size_t bytes)
301 {
302         int radix;
303
304         if (bytes == HAMMER2_PBUFSIZE)
305                 radix = HAMMER2_PBUFRADIX;
306         else if (bytes >= HAMMER2_LBUFSIZE)
307                 radix = HAMMER2_LBUFRADIX;
308         else if (bytes >= HAMMER2_ALLOC_MIN)    /* clamp */
309                 radix = HAMMER2_RADIX_MIN;
310         else
311                 radix = 0;
312
313         while (((size_t)1 << radix) < bytes)
314                 ++radix;
315         return (radix);
316 }
317
318 /*
319  * The logical block size is currently always PBUFSIZE.
320  */
321 int
322 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
323                      hammer2_key_t *lbasep, hammer2_key_t *leofp)
324 {
325         KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD);
326         if (lbasep)
327                 *lbasep = uoff & ~HAMMER2_PBUFMASK64;
328         if (leofp) {
329                 *leofp = (ip->meta.size + HAMMER2_PBUFMASK64) &
330                          ~HAMMER2_PBUFMASK64;
331         }
332         return (HAMMER2_PBUFSIZE);
333 }
334
335 /*
336  * Calculate the physical block size.  pblksize <= lblksize.  Primarily
337  * used to calculate a smaller physical block for the logical block
338  * containing the file EOF.
339  *
340  * Returns 0 if the requested base offset is beyond the file EOF.
341  */
342 int
343 hammer2_calc_physical(hammer2_inode_t *ip, hammer2_key_t lbase)
344 {
345         int lblksize;
346         int pblksize;
347         int eofbytes;
348
349         KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD);
350         lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL);
351         if (lbase + lblksize <= ip->meta.size)
352                 return (lblksize);
353         if (lbase >= ip->meta.size)
354                 return (0);
355         eofbytes = (int)(ip->meta.size - lbase);
356         pblksize = lblksize;
357         while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN)
358                 pblksize >>= 1;
359         pblksize <<= 1;
360
361         return (pblksize);
362 }
363
364 void
365 hammer2_update_time(uint64_t *timep)
366 {
367         struct timeval tv;
368
369         getmicrotime(&tv);
370         *timep = (unsigned long)tv.tv_sec * 1000000 + tv.tv_usec;
371 }
372
373 void
374 hammer2_adjreadcounter(hammer2_blockref_t *bref, size_t bytes)
375 {
376         long *counterp;
377
378         switch(bref->type) {
379         case HAMMER2_BREF_TYPE_DATA:
380                 counterp = &hammer2_iod_file_read;
381                 break;
382         case HAMMER2_BREF_TYPE_INODE:
383                 counterp = &hammer2_iod_meta_read;
384                 break;
385         case HAMMER2_BREF_TYPE_INDIRECT:
386                 counterp = &hammer2_iod_indr_read;
387                 break;
388         case HAMMER2_BREF_TYPE_FREEMAP_NODE:
389         case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
390                 counterp = &hammer2_iod_fmap_read;
391                 break;
392         default:
393                 counterp = &hammer2_iod_volu_read;
394                 break;
395         }
396         *counterp += bytes;
397 }
398
399 int
400 hammer2_signal_check(time_t *timep)
401 {
402         int error = 0;
403
404         lwkt_user_yield();
405         if (*timep != time_second) {
406                 *timep = time_second;
407                 if (CURSIG(curthread->td_lwp) != 0)
408                         error = EINTR;
409         }
410         return error;
411 }
412
413 const char *
414 hammer2_error_str(int error)
415 {
416         const char *str;
417
418         switch(error) {
419         case HAMMER2_ERROR_NONE:
420                 str = "0";
421                 break;
422         case HAMMER2_ERROR_IO:
423                 str = "I/O";
424                 break;
425         case HAMMER2_ERROR_CHECK:
426                 str = "check/crc";
427                 break;
428         case HAMMER2_ERROR_INCOMPLETE:
429                 str = "incomplete-node";
430                 break;
431         default:
432                 str = "unknown";
433                 break;
434         }
435         return (str);
436 }