53e3f2844e3a9f4e9217e71867cc67904d0e9982
[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(const hammer2_inode_data_t *ipdata)
111 {
112         switch(ipdata->meta.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  * ip must be locked sh/ex
320  *
321  * Use 16KB logical buffers for file blocks <= 1MB and 64KB logical buffers
322  * otherwise.  The write code may utilize smaller device buffers when
323  * compressing or handling the EOF case, but is not able to coalesce smaller
324  * logical buffers into larger device buffers.
325  *
326  * For now this means that even large files will have a bunch of 16KB blocks
327  * at the beginning of the file.  On the plus side this tends to cause small
328  * files to cluster together in the freemap.
329  */
330 int
331 hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
332                      hammer2_key_t *lbasep, hammer2_key_t *leofp)
333 {
334 #if 0
335         if (uoff < (hammer2_off_t)1024 * 1024) {
336                 if (lbasep)
337                         *lbasep = uoff & ~HAMMER2_LBUFMASK64;
338                 if (leofp) {
339                         if (ip->size > (hammer2_key_t)1024 * 1024)
340                                 *leofp = (hammer2_key_t)1024 * 1024;
341                         else
342                                 *leofp = (ip->size + HAMMER2_LBUFMASK64) &
343                                          ~HAMMER2_LBUFMASK64;
344                 }
345                 return (HAMMER2_LBUFSIZE);
346         } else {
347 #endif
348                 if (lbasep)
349                         *lbasep = uoff & ~HAMMER2_PBUFMASK64;
350                 if (leofp) {
351                         *leofp = (ip->size + HAMMER2_PBUFMASK64) &
352                                  ~HAMMER2_PBUFMASK64;
353                 }
354                 return (HAMMER2_PBUFSIZE);
355 #if 0
356         }
357 #endif
358 }
359
360 /*
361  * Calculate the physical block size.  pblksize <= lblksize.  Primarily
362  * used to calculate a smaller physical block for the logical block
363  * containing the file EOF.
364  *
365  * Returns 0 if the requested base offset is beyond the file EOF.
366  */
367 int
368 hammer2_calc_physical(hammer2_inode_t *ip,
369                       const hammer2_inode_data_t *ipdata,
370                       hammer2_key_t lbase)
371 {
372         int lblksize;
373         int pblksize;
374         int eofbytes;
375
376         lblksize = hammer2_calc_logical(ip, lbase, NULL, NULL);
377         if (lbase + lblksize <= ipdata->meta.size)
378                 return (lblksize);
379         if (lbase >= ipdata->meta.size)
380                 return (0);
381         eofbytes = (int)(ipdata->meta.size - lbase);
382         pblksize = lblksize;
383         while (pblksize >= eofbytes && pblksize >= HAMMER2_ALLOC_MIN)
384                 pblksize >>= 1;
385         pblksize <<= 1;
386
387         return (pblksize);
388 }
389
390 void
391 hammer2_update_time(uint64_t *timep)
392 {
393         struct timeval tv;
394
395         getmicrotime(&tv);
396         *timep = (unsigned long)tv.tv_sec * 1000000 + tv.tv_usec;
397 }
398
399 void
400 hammer2_adjreadcounter(hammer2_blockref_t *bref, size_t bytes)
401 {
402         long *counterp;
403
404         switch(bref->type) {
405         case HAMMER2_BREF_TYPE_DATA:
406                 counterp = &hammer2_iod_file_read;
407                 break;
408         case HAMMER2_BREF_TYPE_INODE:
409                 counterp = &hammer2_iod_meta_read;
410                 break;
411         case HAMMER2_BREF_TYPE_INDIRECT:
412                 counterp = &hammer2_iod_indr_read;
413                 break;
414         case HAMMER2_BREF_TYPE_FREEMAP_NODE:
415         case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
416                 counterp = &hammer2_iod_fmap_read;
417                 break;
418         default:
419                 counterp = &hammer2_iod_volu_read;
420                 break;
421         }
422         *counterp += bytes;
423 }
424
425 int
426 hammer2_signal_check(time_t *timep)
427 {
428         int error = 0;
429
430         lwkt_user_yield();
431         if (*timep != time_second) {
432                 *timep = time_second;
433                 if (CURSIG(curthread->td_lwp) != 0)
434                         error = EINTR;
435         }
436         return error;
437 }
438
439 const char *
440 hammer2_error_str(int error)
441 {
442         const char *str;
443
444         switch(error) {
445         case HAMMER2_ERROR_NONE:
446                 str = "0";
447                 break;
448         case HAMMER2_ERROR_IO:
449                 str = "I/O";
450                 break;
451         case HAMMER2_ERROR_CHECK:
452                 str = "check/crc";
453                 break;
454         case HAMMER2_ERROR_INCOMPLETE:
455                 str = "incomplete-node";
456                 break;
457         default:
458                 str = "unknown";
459                 break;
460         }
461         return (str);
462 }