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