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