2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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
36 #include <sys/types.h>
39 #include <sys/ioctl.h>
40 #include <sys/mount.h>
41 #include <sys/statvfs.h>
42 #include <sys/diskslice.h>
52 #include <vfs/hammer2/hammer2_disk.h>
53 #include <vfs/hammer2/hammer2_ioctl.h>
55 #include "hammer2_subs.h"
58 * Obtain a file descriptor that the caller can execute ioctl()'s on.
61 hammer2_ioctl_handle(const char *sel_path)
63 struct hammer2_ioc_version info;
69 fd = open(sel_path, O_RDONLY, 0);
71 fprintf(stderr, "hammer2: Unable to open %s: %s\n",
72 sel_path, strerror(errno));
75 if (ioctl(fd, HAMMER2IOC_VERSION_GET, &info) < 0) {
76 fprintf(stderr, "hammer2: '%s' is not a hammer2 filesystem\n",
85 hammer2_time64_to_str(uint64_t htime64, char **strp)
95 t = htime64 / 1000000;
97 strftime(*strp, 64, "%d-%b-%Y %H:%M:%S", tp);
102 hammer2_uuid_to_str(const uuid_t *uuid, char **strp)
109 uuid_to_string(uuid, strp, &status);
114 hammer2_iptype_to_str(uint8_t type)
117 case HAMMER2_OBJTYPE_UNKNOWN:
119 case HAMMER2_OBJTYPE_DIRECTORY:
121 case HAMMER2_OBJTYPE_REGFILE:
123 case HAMMER2_OBJTYPE_FIFO:
125 case HAMMER2_OBJTYPE_CDEV:
127 case HAMMER2_OBJTYPE_BDEV:
129 case HAMMER2_OBJTYPE_SOFTLINK:
131 case HAMMER2_OBJTYPE_SOCKET:
133 case HAMMER2_OBJTYPE_WHITEOUT:
141 hammer2_pfstype_to_str(uint8_t type)
144 case HAMMER2_PFSTYPE_NONE:
146 case HAMMER2_PFSTYPE_SUPROOT:
148 case HAMMER2_PFSTYPE_DUMMY:
150 case HAMMER2_PFSTYPE_CACHE:
152 case HAMMER2_PFSTYPE_SLAVE:
154 case HAMMER2_PFSTYPE_SOFT_SLAVE:
155 return("SOFT_SLAVE");
156 case HAMMER2_PFSTYPE_SOFT_MASTER:
157 return("SOFT_MASTER");
158 case HAMMER2_PFSTYPE_MASTER:
166 hammer2_pfssubtype_to_str(uint8_t subtype)
169 case HAMMER2_PFSSUBTYPE_NONE:
171 case HAMMER2_PFSSUBTYPE_SNAPSHOT:
173 case HAMMER2_PFSSUBTYPE_AUTOSNAP:
181 hammer2_breftype_to_str(uint8_t type)
184 case HAMMER2_BREF_TYPE_EMPTY:
186 case HAMMER2_BREF_TYPE_INODE:
188 case HAMMER2_BREF_TYPE_INDIRECT:
190 case HAMMER2_BREF_TYPE_DATA:
192 case HAMMER2_BREF_TYPE_DIRENT:
194 case HAMMER2_BREF_TYPE_FREEMAP_NODE:
195 return("freemap_node");
196 case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
197 return("freemap_leaf");
198 case HAMMER2_BREF_TYPE_INVALID:
200 case HAMMER2_BREF_TYPE_FREEMAP:
202 case HAMMER2_BREF_TYPE_VOLUME:
210 sizetostr(hammer2_off_t size)
214 if (size < 1024 / 2) {
215 snprintf(buf, sizeof(buf), "%6.2fB", (double)size);
216 } else if (size < 1024 * 1024 / 2) {
217 snprintf(buf, sizeof(buf), "%6.2fKB",
218 (double)size / 1024);
219 } else if (size < 1024 * 1024 * 1024LL / 2) {
220 snprintf(buf, sizeof(buf), "%6.2fMB",
221 (double)size / (1024 * 1024));
222 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
223 snprintf(buf, sizeof(buf), "%6.2fGB",
224 (double)size / (1024 * 1024 * 1024LL));
226 snprintf(buf, sizeof(buf), "%6.2fTB",
227 (double)size / (1024 * 1024 * 1024LL * 1024LL));
233 counttostr(hammer2_off_t size)
237 if (size < 1024 / 2) {
238 snprintf(buf, sizeof(buf), "%jd",
240 } else if (size < 1024 * 1024 / 2) {
241 snprintf(buf, sizeof(buf), "%jd",
243 } else if (size < 1024 * 1024 * 1024LL / 2) {
244 snprintf(buf, sizeof(buf), "%6.2fM",
245 (double)size / (1024 * 1024));
246 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
247 snprintf(buf, sizeof(buf), "%6.2fG",
248 (double)(size / (1024 * 1024 * 1024LL)));
250 snprintf(buf, sizeof(buf), "%6.2fT",
251 (double)(size / (1024 * 1024 * 1024LL * 1024LL)));
259 struct partinfo pinfo;
264 * Get basic information about the volume
266 if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
268 * Allow the formatting of regular files as HAMMER2 volumes
270 if (fstat(fd, &st) < 0)
271 err(1, "Unable to stat fd %d", fd);
272 if (!S_ISREG(st.st_mode))
273 errx(1, "Unsupported file type for fd %d", fd);
277 * When formatting a block device as a HAMMER2 volume the
278 * sector size must be compatible. HAMMER2 uses 64K
279 * filesystem buffers but logical buffers for direct I/O
280 * can be as small as HAMMER2_LOGSIZE (16KB).
282 if (pinfo.reserved_blocks) {
283 errx(1, "HAMMER2 cannot be placed in a partition "
284 "which overlaps the disklabel or MBR");
286 if (pinfo.media_blksize > HAMMER2_PBUFSIZE ||
287 HAMMER2_PBUFSIZE % pinfo.media_blksize) {
288 errx(1, "A media sector size of %d is not supported",
289 pinfo.media_blksize);
291 size = pinfo.media_size;
297 * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
298 * The filename is split into fields which are hashed separately and then
301 * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
302 * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
303 * (This means we do not need to do a 0-check/or-with-0x100000000 either).
305 * Also, the iscsi crc code is used instead of the old crc32 code.
308 dirhash(const unsigned char *name, size_t len)
310 const unsigned char *aname = name;
317 * Filesystem version 6 or better will create directories
318 * using the ALG1 dirhash. This hash breaks the filename
319 * up into domains separated by special characters and
320 * hashes each domain independently.
322 * We also do a simple sub-sort using the first character
323 * of the filename in the top 5-bits.
331 for (i = j = 0; i < len; ++i) {
332 if (aname[i] == '.' ||
337 crcx += hammer2_icrc32(aname + j, i - j);
342 crcx += hammer2_icrc32(aname + j, i - j);
345 * The directory hash utilizes the top 32 bits of the 64-bit key.
346 * Bit 63 must be set to 1.
349 key |= (uint64_t)crcx << 32;
352 * l16 - crc of entire filename
354 * This crc reduces degenerate hash collision conditions
356 crcx = hammer2_icrc32(aname, len);
357 crcx = crcx ^ (crcx << 16);
358 key |= crcx & 0xFFFF0000U;
361 * Set bit 15. This allows readdir to strip bit 63 so a positive
362 * 64-bit cookie/offset can always be returned, and still guarantee
363 * that the values 0x0000-0x7FFF are available for artificial entries.
372 get_hammer2_mounts(int *acp)
381 * Get a stable list of mount points
384 n = getfsstat(NULL, 0, MNT_NOWAIT);
385 av = calloc(n, sizeof(char *));
386 fs = calloc(n, sizeof(struct statfs));
387 if (getfsstat(fs, sizeof(*fs) * n, MNT_NOWAIT) != n) {
394 * Pull out hammer2 filesystems only
396 for (i = w = 0; i < n; ++i) {
397 if (strcmp(fs[i].f_fstypename, "hammer2") != 0)
399 av[w++] = strdup(fs[i].f_mntonname);
408 put_hammer2_mounts(int ac, char **av)