2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org>
5 * Copyright (c) 2011-2022 The DragonFly Project. All rights reserved.
7 * This code is derived from software contributed to The DragonFly Project
8 * by Matthew Dillon <dillon@dragonflybsd.org>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
20 * 3. Neither the name of The DragonFly Project nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific, prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/types.h>
44 #include <sys/dirent.h>
49 * Return the directory entry type for an inode.
52 hammer2_get_dtype(uint8_t type
)
55 case HAMMER2_OBJTYPE_UNKNOWN
:
57 case HAMMER2_OBJTYPE_DIRECTORY
:
59 case HAMMER2_OBJTYPE_REGFILE
:
61 case HAMMER2_OBJTYPE_FIFO
:
63 case HAMMER2_OBJTYPE_CDEV
:
65 case HAMMER2_OBJTYPE_BDEV
:
67 case HAMMER2_OBJTYPE_SOFTLINK
:
69 case HAMMER2_OBJTYPE_SOCKET
:
71 case HAMMER2_OBJTYPE_WHITEOUT
: /* not supported */
80 * Return the directory entry type for an inode
83 hammer2_get_vtype(uint8_t type
)
86 case HAMMER2_OBJTYPE_UNKNOWN
:
88 case HAMMER2_OBJTYPE_DIRECTORY
:
90 case HAMMER2_OBJTYPE_REGFILE
:
92 case HAMMER2_OBJTYPE_FIFO
:
94 case HAMMER2_OBJTYPE_CDEV
:
96 case HAMMER2_OBJTYPE_BDEV
:
98 case HAMMER2_OBJTYPE_SOFTLINK
:
100 case HAMMER2_OBJTYPE_SOCKET
:
102 case HAMMER2_OBJTYPE_WHITEOUT
: /* not supported */
111 hammer2_get_obj_type(enum vtype vtype
)
115 return(HAMMER2_OBJTYPE_DIRECTORY
);
117 return(HAMMER2_OBJTYPE_REGFILE
);
119 return(HAMMER2_OBJTYPE_FIFO
);
121 return(HAMMER2_OBJTYPE_SOCKET
);
123 return(HAMMER2_OBJTYPE_CDEV
);
125 return(HAMMER2_OBJTYPE_BDEV
);
127 return(HAMMER2_OBJTYPE_SOFTLINK
);
129 return(HAMMER2_OBJTYPE_UNKNOWN
);
135 * Convert a hammer2 64-bit time to a timespec.
138 hammer2_time_to_timespec(uint64_t xtime
, struct timespec
*ts
)
140 ts
->tv_sec
= (unsigned long)(xtime
/ 1000000);
141 ts
->tv_nsec
= (unsigned int)(xtime
% 1000000) * 1000L;
145 hammer2_timespec_to_time(const struct timespec
*ts
)
149 xtime
= (unsigned)(ts
->tv_nsec
/ 1000) +
150 (unsigned long)ts
->tv_sec
* 1000000ULL;
155 * Convert a uuid to a unix uid or gid
158 hammer2_to_unix_xid(const uuid_t
*uuid
)
160 return(*(const uint32_t *)&uuid
->node
[2]);
164 hammer2_guid_to_uuid(uuid_t
*uuid
, uint32_t guid
)
166 bzero(uuid
, sizeof(*uuid
));
167 *(uint32_t *)&uuid
->node
[2] = guid
;
171 * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
172 * The filename is split into fields which are hashed separately and then
175 * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
176 * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
177 * (This means we do not need to do a 0-check/or-with-0x100000000 either).
179 * Also, the iscsi crc code is used instead of the old crc32 code.
182 hammer2_dirhash(const char *aname
, size_t len
)
195 for (i
= j
= 0; i
< len
; ++i
) {
196 if (aname
[i
] == '.' ||
201 crcx
+= hammer2_icrc32(aname
+ j
, i
- j
);
206 crcx
+= hammer2_icrc32(aname
+ j
, i
- j
);
209 * The directory hash utilizes the top 32 bits of the 64-bit key.
210 * Bit 63 must be set to 1.
213 key
|= (uint64_t)crcx
<< 32;
216 * l16 - crc of entire filename
218 * This crc reduces degenerate hash collision conditions.
220 crcx
= hammer2_icrc32(aname
, len
);
221 crcx
= crcx
^ (crcx
<< 16);
222 key
|= crcx
& 0xFFFF0000U
;
225 * Set bit 15. This allows readdir to strip bit 63 so a positive
226 * 64-bit cookie/offset can always be returned, and still guarantee
227 * that the values 0x0000-0x7FFF are available for artificial entries.
236 * Convert bytes to radix with no limitations.
238 * 0 bytes is special-cased to a radix of zero (which would normally
239 * translate to (1 << 0) == 1).
242 hammer2_getradix(size_t bytes
)
247 * Optimize the iteration by pre-checking commonly used radii.
249 if (bytes
== HAMMER2_PBUFSIZE
)
250 radix
= HAMMER2_PBUFRADIX
;
251 else if (bytes
>= HAMMER2_LBUFSIZE
)
252 radix
= HAMMER2_LBUFRADIX
;
253 else if (bytes
>= HAMMER2_ALLOC_MIN
) /* clamp */
254 radix
= HAMMER2_RADIX_MIN
;
259 * Iterate as needed. Note that bytes == 0 is expected to return
260 * a radix of 0 as a special case.
262 while (((size_t)1 << radix
) < bytes
)
268 * The logical block size is currently always PBUFSIZE.
271 hammer2_calc_logical(hammer2_inode_t
*ip
, hammer2_off_t uoff
,
272 hammer2_key_t
*lbasep
, hammer2_key_t
*leofp
)
275 *lbasep
= uoff
& ~HAMMER2_PBUFMASK64
;
277 *leofp
= (ip
->meta
.size
+ HAMMER2_PBUFMASK64
) &
280 return (HAMMER2_PBUFSIZE
);
284 * Calculate the physical block size. pblksize <= lblksize. Primarily
285 * used to calculate a smaller physical block for the logical block
286 * containing the file EOF.
288 * Returns 0 if the requested base offset is beyond the file EOF.
291 hammer2_calc_physical(hammer2_inode_t
*ip
, hammer2_key_t lbase
)
297 lblksize
= hammer2_calc_logical(ip
, lbase
, NULL
, NULL
);
298 if (lbase
+ lblksize
<= ip
->meta
.size
)
300 if (lbase
>= ip
->meta
.size
)
302 eofbytes
= (int)(ip
->meta
.size
- lbase
);
304 while (pblksize
>= eofbytes
&& pblksize
>= HAMMER2_ALLOC_MIN
)
312 hammer2_update_time(uint64_t *timep
, bool is_mtime
)
317 assert(hammer2_curnode
);
318 st
= stampst
.st_ino
!= 0 ? &stampst
: &hammer2_curnode
->inode
->st
;
319 ts
= is_mtime
? &st
->st_mtim
: &st
->st_ctim
;
321 *timep
= (uint64_t)ts
->tv_sec
* 1000000 + ts
->tv_nsec
/ 1000;
325 hammer2_adjreadcounter(int btype
, size_t bytes
)
330 case HAMMER2_BREF_TYPE_DATA
:
331 counterp
= &hammer2_iod_file_read
;
333 case HAMMER2_BREF_TYPE_DIRENT
:
334 case HAMMER2_BREF_TYPE_INODE
:
335 counterp
= &hammer2_iod_meta_read
;
337 case HAMMER2_BREF_TYPE_INDIRECT
:
338 counterp
= &hammer2_iod_indr_read
;
340 case HAMMER2_BREF_TYPE_FREEMAP_NODE
:
341 case HAMMER2_BREF_TYPE_FREEMAP_LEAF
:
342 counterp
= &hammer2_iod_fmap_read
;
344 case HAMMER2_BREF_TYPE_FREEMAP
:
345 case HAMMER2_BREF_TYPE_VOLUME
:
346 counterp
= &hammer2_iod_volu_read
;
348 case HAMMER2_BREF_TYPE_EMPTY
:
356 hammer2_adjwritecounter(int btype
, size_t bytes
)
361 case HAMMER2_BREF_TYPE_DATA
:
362 counterp
= &hammer2_iod_file_write
;
364 case HAMMER2_BREF_TYPE_DIRENT
:
365 case HAMMER2_BREF_TYPE_INODE
:
366 counterp
= &hammer2_iod_meta_write
;
368 case HAMMER2_BREF_TYPE_INDIRECT
:
369 counterp
= &hammer2_iod_indr_write
;
371 case HAMMER2_BREF_TYPE_FREEMAP_NODE
:
372 case HAMMER2_BREF_TYPE_FREEMAP_LEAF
:
373 counterp
= &hammer2_iod_fmap_write
;
375 case HAMMER2_BREF_TYPE_FREEMAP
:
376 case HAMMER2_BREF_TYPE_VOLUME
:
377 counterp
= &hammer2_iod_volu_write
;
379 case HAMMER2_BREF_TYPE_EMPTY
:
388 * Check for pending signal to allow interruption. This function will
389 * return immediately if the calling thread is a kernel thread and not
393 hammer2_signal_check(time_t *timep
)
395 thread_t td
= curthread
;
400 if (*timep
!= time_second
) {
401 *timep
= time_second
;
402 if (CURSIG_NOBLOCK(curthread
->td_lwp
) != 0)
403 error
= HAMMER2_ERROR_ABORTED
;
413 hammer2_error_str(int error
)
415 if (error
& HAMMER2_ERROR_EIO
)
417 if (error
& HAMMER2_ERROR_CHECK
)
418 return("Check Error");
419 if (error
& HAMMER2_ERROR_INCOMPLETE
)
420 return("Cluster Quorum Error");
421 if (error
& HAMMER2_ERROR_DEPTH
)
422 return("Chain Depth Error");
423 if (error
& HAMMER2_ERROR_BADBREF
)
424 return("Bad Blockref Error");
425 if (error
& HAMMER2_ERROR_ENOSPC
)
426 return("No Space on Device");
427 if (error
& HAMMER2_ERROR_ENOENT
)
428 return("Entry Not Found");
429 if (error
& HAMMER2_ERROR_ENOTEMPTY
)
430 return("Directory Not Empty");
431 if (error
& HAMMER2_ERROR_EAGAIN
)
433 if (error
& HAMMER2_ERROR_ENOTDIR
)
434 return("Not a Directory");
435 if (error
& HAMMER2_ERROR_EISDIR
)
436 return("Is a Directory");
437 if (error
& HAMMER2_ERROR_EINPROGRESS
)
438 return("Operation in Progress");
439 if (error
& HAMMER2_ERROR_ABORTED
)
440 return("Operation Aborted");
441 if (error
& HAMMER2_ERROR_EOF
)
442 return("Operation Complete");
443 if (error
& HAMMER2_ERROR_EINVAL
)
444 return("Invalid Operation");
445 if (error
& HAMMER2_ERROR_EEXIST
)
446 return("Object Exists");
447 if (error
& HAMMER2_ERROR_EDEADLK
)
448 return("Deadlock Detected");
449 if (error
& HAMMER2_ERROR_ESRCH
)
450 return("Object Not Found");
451 if (error
& HAMMER2_ERROR_ETIMEDOUT
)
453 return("Unknown Error");
457 hammer2_bref_type_str(int btype
)
460 case HAMMER2_BREF_TYPE_EMPTY
:
462 case HAMMER2_BREF_TYPE_INODE
:
464 case HAMMER2_BREF_TYPE_INDIRECT
:
466 case HAMMER2_BREF_TYPE_DATA
:
468 case HAMMER2_BREF_TYPE_DIRENT
:
470 case HAMMER2_BREF_TYPE_FREEMAP_NODE
:
471 return("freemap_node");
472 case HAMMER2_BREF_TYPE_FREEMAP_LEAF
:
473 return("freemap_leaf");
474 case HAMMER2_BREF_TYPE_INVALID
:
476 case HAMMER2_BREF_TYPE_FREEMAP
:
478 case HAMMER2_BREF_TYPE_VOLUME
: