d9796e0fa21ad1b0fe49dd658462c3d86447f622
[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(uint8_t type)
73 {
74         switch(type) {
75         case HAMMER2_OBJTYPE_UNKNOWN:
76                 return (DT_UNKNOWN);
77         case HAMMER2_OBJTYPE_DIRECTORY:
78                 return (DT_DIR);
79         case HAMMER2_OBJTYPE_REGFILE:
80                 return (DT_REG);
81         case HAMMER2_OBJTYPE_FIFO:
82                 return (DT_FIFO);
83         case HAMMER2_OBJTYPE_CDEV:      /* not supported */
84                 return (DT_CHR);
85         case HAMMER2_OBJTYPE_BDEV:      /* not supported */
86                 return (DT_BLK);
87         case HAMMER2_OBJTYPE_SOFTLINK:
88                 return (DT_LNK);
89         case HAMMER2_OBJTYPE_SOCKET:
90                 return (DT_SOCK);
91         case HAMMER2_OBJTYPE_WHITEOUT:  /* not supported */
92                 return (DT_UNKNOWN);
93         default:
94                 return (DT_UNKNOWN);
95         }
96         /* not reached */
97 }
98
99 /*
100  * Return the directory entry type for an inode
101  */
102 int
103 hammer2_get_vtype(uint8_t type)
104 {
105         switch(type) {
106         case HAMMER2_OBJTYPE_UNKNOWN:
107                 return (VBAD);
108         case HAMMER2_OBJTYPE_DIRECTORY:
109                 return (VDIR);
110         case HAMMER2_OBJTYPE_REGFILE:
111                 return (VREG);
112         case HAMMER2_OBJTYPE_FIFO:
113                 return (VFIFO);
114         case HAMMER2_OBJTYPE_CDEV:      /* not supported */
115                 return (VCHR);
116         case HAMMER2_OBJTYPE_BDEV:      /* not supported */
117                 return (VBLK);
118         case HAMMER2_OBJTYPE_SOFTLINK:
119                 return (VLNK);
120         case HAMMER2_OBJTYPE_SOCKET:
121                 return (VSOCK);
122         case HAMMER2_OBJTYPE_WHITEOUT:  /* not supported */
123                 return (DT_UNKNOWN);
124         default:
125                 return (DT_UNKNOWN);
126         }
127         /* not reached */
128 }
129
130 uint8_t
131 hammer2_get_obj_type(enum vtype vtype)
132 {
133         switch(vtype) {
134         case VDIR:
135                 return(HAMMER2_OBJTYPE_DIRECTORY);
136         case VREG:
137                 return(HAMMER2_OBJTYPE_REGFILE);
138         case VFIFO:
139                 return(HAMMER2_OBJTYPE_FIFO);
140         case VSOCK:
141                 return(HAMMER2_OBJTYPE_SOCKET);
142         case VCHR:
143                 return(HAMMER2_OBJTYPE_CDEV);
144         case VBLK:
145                 return(HAMMER2_OBJTYPE_BDEV);
146         case VLNK:
147                 return(HAMMER2_OBJTYPE_SOFTLINK);
148         default:
149                 return(HAMMER2_OBJTYPE_UNKNOWN);
150         }
151         /* not reached */
152 }
153
154 /*
155  * Convert a hammer2 64-bit time to a timespec.
156  */
157 void
158 hammer2_time_to_timespec(uint64_t xtime, struct timespec *ts)
159 {
160         ts->tv_sec = (unsigned long)(xtime / 1000000);
161         ts->tv_nsec = (unsigned int)(xtime % 1000000) * 1000L;
162 }
163
164 uint64_t
165 hammer2_timespec_to_time(const struct timespec *ts)
166 {
167         uint64_t xtime;
168
169         xtime = (unsigned)(ts->tv_nsec / 1000) +
170                 (unsigned long)ts->tv_sec * 1000000ULL;
171         return(xtime);
172 }
173
174 /*
175  * Convert a uuid to a unix uid or gid
176  */
177 uint32_t
178 hammer2_to_unix_xid(const uuid_t *uuid)
179 {
180         return(*(const uint32_t *)&uuid->node[2]);
181 }
182
183 void
184 hammer2_guid_to_uuid(uuid_t *uuid, uint32_t guid)
185 {
186         bzero(uuid, sizeof(*uuid));
187         *(uint32_t *)&uuid->node[2] = guid;
188 }
189
190 /*
191  * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
192  * The filename is split into fields which are hashed separately and then
193  * added together.
194  *
195  * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
196  * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
197  * (This means we do not need to do a 0-check/or-with-0x100000000 either).
198  *
199  * Also, the iscsi crc code is used instead of the old crc32 code.
200  */
201 hammer2_key_t
202 hammer2_dirhash(const unsigned char *name, size_t len)
203 {
204         const unsigned char *aname = name;
205         uint32_t crcx;
206         uint64_t key;
207         size_t i;
208         size_t j;
209
210         key = 0;
211
212         /*
213          * m32
214          */
215         crcx = 0;
216         for (i = j = 0; i < len; ++i) {
217                 if (aname[i] == '.' ||
218                     aname[i] == '-' ||
219                     aname[i] == '_' ||
220                     aname[i] == '~') {
221                         if (i != j)
222                                 crcx += hammer2_icrc32(aname + j, i - j);
223                         j = i + 1;
224                 }
225         }
226         if (i != j)
227                 crcx += hammer2_icrc32(aname + j, i - j);
228
229         /*
230          * The directory hash utilizes the top 32 bits of the 64-bit key.
231          * Bit 63 must be set to 1.
232          */
233         crcx |= 0x80000000U;
234         key |= (uint64_t)crcx << 32;
235
236         /*
237          * l16 - crc of entire filename
238          *
239          * This crc reduces degenerate hash collision conditions
240          */
241         crcx = hammer2_icrc32(aname, len);
242         crcx = crcx ^ (crcx << 16);
243         key |= crcx & 0xFFFF0000U;
244
245         /*
246          * Set bit 15.  This allows readdir to strip bit 63 so a positive
247          * 64-bit cookie/offset can always be returned, and still guarantee
248          * that the values 0x0000-0x7FFF are available for artificial entries.
249          * ('.' and '..').
250          */
251         key |= 0x8000U;
252
253         return (key);
254 }
255
256 #if 0
257 /*
258  * Return the power-of-2 radix greater or equal to
259  * the specified number of bytes.
260  *
261  * Always returns at least the minimum media allocation
262  * size radix, HAMMER2_RADIX_MIN (10), which is 1KB.
263  */
264 int
265 hammer2_allocsize(size_t bytes)
266 {
267         int radix;
268
269         if (bytes < HAMMER2_ALLOC_MIN)
270                 bytes = HAMMER2_ALLOC_MIN;
271         if (bytes == HAMMER2_PBUFSIZE)
272                 radix = HAMMER2_PBUFRADIX;
273         else if (bytes >= 16384)
274                 radix = 14;
275         else if (bytes >= 1024)
276                 radix = 10;
277         else
278                 radix = HAMMER2_RADIX_MIN;
279
280         while (((size_t)1 << radix) < bytes)
281                 ++radix;
282         return (radix);
283 }
284
285 #endif
286
287 /*
288  * Convert bytes to radix with no limitations.
289  *
290  * 0 bytes is special-cased to a radix of zero (which would normally
291  * translate to (1 << 0) == 1).
292  */
293 int
294 hammer2_getradix(size_t bytes)
295 {
296         int radix;
297
298         /*
299          * Optimize the iteration by pre-checking commonly used radii.
300          */
301         if (bytes == HAMMER2_PBUFSIZE)
302                 radix = HAMMER2_PBUFRADIX;
303         else if (bytes >= HAMMER2_LBUFSIZE)
304                 radix = HAMMER2_LBUFRADIX;
305         else if (bytes >= HAMMER2_ALLOC_MIN)    /* clamp */
306                 radix = HAMMER2_RADIX_MIN;
307         else
308                 radix = 0;
309
310         /*
311          * Iterate as needed.  Note that bytes == 0 is expected to return
312          * a radix of 0 as a special case.
313          */
314         while (((size_t)1 << radix) < bytes)
315                 ++radix;
316         return (radix);
317 }
318
319 /*
320  * The logical block size is currently always PBUFSIZE.
321  */
322 int
323 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
324                      hammer2_key_t *lbasep, hammer2_key_t *leofp)
325 {
326         KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD);
327         if (lbasep)
328                 *lbasep = uoff & ~HAMMER2_PBUFMASK64;
329         if (leofp) {
330                 *leofp = (ip->meta.size + HAMMER2_PBUFMASK64) &
331                          ~HAMMER2_PBUFMASK64;
332         }
333         return (HAMMER2_PBUFSIZE);
334 }
335
336 /*
337  * Calculate the physical block size.  pblksize <= lblksize.  Primarily
338  * used to calculate a smaller physical block for the logical block
339  * containing the file EOF.
340  *
341  * Returns 0 if the requested base offset is beyond the file EOF.
342  */
343 int
344 hammer2_calc_physical(hammer2_inode_t *ip, hammer2_key_t lbase)
345 {
346         int lblksize;
347         int pblksize;
348         int eofbytes;
349
350         KKASSERT(ip->flags & HAMMER2_INODE_METAGOOD);
351         lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL);
352         if (lbase + lblksize <= ip->meta.size)
353                 return (lblksize);
354         if (lbase >= ip->meta.size)
355                 return (0);
356         eofbytes = (int)(ip->meta.size - lbase);
357         pblksize = lblksize;
358         while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN)
359                 pblksize >>= 1;
360         pblksize <<= 1;
361
362         return (pblksize);
363 }
364
365 void
366 hammer2_update_time(uint64_t *timep)
367 {
368         struct timeval tv;
369
370         getmicrotime(&tv);
371         *timep = (unsigned long)tv.tv_sec * 1000000 + tv.tv_usec;
372 }
373
374 void
375 hammer2_adjreadcounter(hammer2_blockref_t *bref, size_t bytes)
376 {
377         long *counterp;
378
379         switch(bref->type) {
380         case HAMMER2_BREF_TYPE_DATA:
381                 counterp = &hammer2_iod_file_read;
382                 break;
383         case HAMMER2_BREF_TYPE_DIRENT:
384         case HAMMER2_BREF_TYPE_INODE:
385                 counterp = &hammer2_iod_meta_read;
386                 break;
387         case HAMMER2_BREF_TYPE_INDIRECT:
388                 counterp = &hammer2_iod_indr_read;
389                 break;
390         case HAMMER2_BREF_TYPE_FREEMAP_NODE:
391         case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
392                 counterp = &hammer2_iod_fmap_read;
393                 break;
394         default:
395                 counterp = &hammer2_iod_volu_read;
396                 break;
397         }
398         *counterp += bytes;
399 }
400
401 /*
402  * Check for pending signal to allow interruption.  This function will
403  * return immediately if the calling thread is a kernel thread and not
404  * a user thread.
405  */
406 int
407 hammer2_signal_check(time_t *timep)
408 {
409         thread_t td = curthread;
410         int error = 0;
411
412         if (td->td_lwp) {
413                 lwkt_user_yield();
414                 if (*timep != time_second) {
415                         *timep = time_second;
416                         if (CURSIG_NOBLOCK(curthread->td_lwp) != 0)
417                                 error = HAMMER2_ERROR_ABORTED;
418                 }
419         } else {
420                 lwkt_yield();
421         }
422         return error;
423 }
424
425 const char *
426 hammer2_error_str(int error)
427 {
428         if (error & HAMMER2_ERROR_EIO)
429                 return("I/O Error");
430         if (error & HAMMER2_ERROR_CHECK)
431                 return("Check Error");
432         if (error & HAMMER2_ERROR_INCOMPLETE)
433                 return("Cluster Quorum Error");
434         if (error & HAMMER2_ERROR_DEPTH)
435                 return("Chain Depth Error");
436         if (error & HAMMER2_ERROR_BADBREF)
437                 return("Bad Blockref Error");
438         if (error & HAMMER2_ERROR_ENOSPC)
439                 return("No Space on Device");
440         if (error & HAMMER2_ERROR_ENOENT)
441                 return("Entry Not Found");
442         if (error & HAMMER2_ERROR_ENOTEMPTY)
443                 return("Directory Not Empty");
444         if (error & HAMMER2_ERROR_EAGAIN)
445                 return("EAGAIN");
446         if (error & HAMMER2_ERROR_ENOTDIR)
447                 return("Not a Directory");
448         if (error & HAMMER2_ERROR_EISDIR)
449                 return("Is a Directory");
450         if (error & HAMMER2_ERROR_EINPROGRESS)
451                 return("Operation in Progress");
452         if (error & HAMMER2_ERROR_ABORTED)
453                 return("Operation Aborted");
454         if (error & HAMMER2_ERROR_EOF)
455                 return("Operation Complete");
456         if (error & HAMMER2_ERROR_EINVAL)
457                 return("Invalid Operation");
458         if (error & HAMMER2_ERROR_EEXIST)
459                 return("Object Exists");
460         if (error & HAMMER2_ERROR_EDEADLK)
461                 return("Deadlock Detected");
462         if (error & HAMMER2_ERROR_ESRCH)
463                 return("Object Not Found");
464         if (error & HAMMER2_ERROR_ETIMEDOUT)
465                 return("Timeout");
466         return("Unknown Error");
467 }