diff options
author | David Sterba <dsterba@suse.com> | 2017-01-31 23:13:54 +0100 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-03-08 13:00:46 +0100 |
commit | ed4c7428b74a73f07d11bf298b327c8f3119ce72 (patch) | |
tree | 0a7f1234d85be8f12485f0fafd8e125d416c5e0c /mkfs | |
parent | 11c83cefb8b4a03b1835efaf603ddc95430a0c9e (diff) |
btrfs-progs: move mkfs helper implementation out of utils
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'mkfs')
-rw-r--r-- | mkfs/common.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/mkfs/common.c b/mkfs/common.c index 588712d7..8d92eae2 100644 --- a/mkfs/common.c +++ b/mkfs/common.c @@ -16,6 +16,8 @@ #include <unistd.h> #include <uuid/uuid.h> +#include <blkid/blkid.h> +#include <fcntl.h> #include "ctree.h" #include "disk-io.h" #include "volumes.h" @@ -437,3 +439,284 @@ out: return ret; } +u64 btrfs_min_dev_size(u32 nodesize) +{ + return 2 * (BTRFS_MKFS_SYSTEM_GROUP_SIZE + + btrfs_min_global_blk_rsv_size(nodesize)); +} + +/* + * Btrfs minimum size calculation is complicated, it should include at least: + * 1. system group size + * 2. minimum global block reserve + * 3. metadata used at mkfs + * 4. space reservation to create uuid for first mount. + * Also, raid factor should also be taken into consideration. + * To avoid the overkill calculation, (system group + global block rsv) * 2 + * for *EACH* device should be good enough. + */ +u64 btrfs_min_global_blk_rsv_size(u32 nodesize) +{ + return (u64)nodesize << 10; +} + +#define isoctal(c) (((c) & ~7) == '0') + +static inline void translate(char *f, char *t) +{ + while (*f != '\0') { + if (*f == '\\' && + isoctal(f[1]) && isoctal(f[2]) && isoctal(f[3])) { + *t++ = 64*(f[1] & 7) + 8*(f[2] & 7) + (f[3] & 7); + f += 4; + } else + *t++ = *f++; + } + *t = '\0'; + return; +} + +/* + * Checks if the swap device. + * Returns 1 if swap device, < 0 on error or 0 if not swap device. + */ +static int is_swap_device(const char *file) +{ + FILE *f; + struct stat st_buf; + dev_t dev; + ino_t ino = 0; + char tmp[PATH_MAX]; + char buf[PATH_MAX]; + char *cp; + int ret = 0; + + if (stat(file, &st_buf) < 0) + return -errno; + if (S_ISBLK(st_buf.st_mode)) + dev = st_buf.st_rdev; + else if (S_ISREG(st_buf.st_mode)) { + dev = st_buf.st_dev; + ino = st_buf.st_ino; + } else + return 0; + + if ((f = fopen("/proc/swaps", "r")) == NULL) + return 0; + + /* skip the first line */ + if (fgets(tmp, sizeof(tmp), f) == NULL) + goto out; + + while (fgets(tmp, sizeof(tmp), f) != NULL) { + if ((cp = strchr(tmp, ' ')) != NULL) + *cp = '\0'; + if ((cp = strchr(tmp, '\t')) != NULL) + *cp = '\0'; + translate(tmp, buf); + if (stat(buf, &st_buf) != 0) + continue; + if (S_ISBLK(st_buf.st_mode)) { + if (dev == st_buf.st_rdev) { + ret = 1; + break; + } + } else if (S_ISREG(st_buf.st_mode)) { + if (dev == st_buf.st_dev && ino == st_buf.st_ino) { + ret = 1; + break; + } + } + } + +out: + fclose(f); + + return ret; +} + +/* + * Check for existing filesystem or partition table on device. + * Returns: + * 1 for existing fs or partition + * 0 for nothing found + * -1 for internal error + */ +static int check_overwrite(const char *device) +{ + const char *type; + blkid_probe pr = NULL; + int ret; + blkid_loff_t size; + + if (!device || !*device) + return 0; + + ret = -1; /* will reset on success of all setup calls */ + + pr = blkid_new_probe_from_filename(device); + if (!pr) + goto out; + + size = blkid_probe_get_size(pr); + if (size < 0) + goto out; + + /* nothing to overwrite on a 0-length device */ + if (size == 0) { + ret = 0; + goto out; + } + + ret = blkid_probe_enable_partitions(pr, 1); + if (ret < 0) + goto out; + + ret = blkid_do_fullprobe(pr); + if (ret < 0) + goto out; + + /* + * Blkid returns 1 for nothing found and 0 when it finds a signature, + * but we want the exact opposite, so reverse the return value here. + * + * In addition print some useful diagnostics about what actually is + * on the device. + */ + if (ret) { + ret = 0; + goto out; + } + + if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) { + fprintf(stderr, + "%s appears to contain an existing " + "filesystem (%s).\n", device, type); + } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) { + fprintf(stderr, + "%s appears to contain a partition " + "table (%s).\n", device, type); + } else { + fprintf(stderr, + "%s appears to contain something weird " + "according to blkid\n", device); + } + ret = 1; + +out: + if (pr) + blkid_free_probe(pr); + if (ret == -1) + fprintf(stderr, + "probe of %s failed, cannot detect " + "existing filesystem.\n", device); + return ret; +} + +/* + * Check if a device is suitable for btrfs + * returns: + * 1: something is wrong, an error is printed + * 0: all is fine + */ +int test_dev_for_mkfs(const char *file, int force_overwrite) +{ + int ret, fd; + struct stat st; + + ret = is_swap_device(file); + if (ret < 0) { + error("checking status of %s: %s", file, strerror(-ret)); + return 1; + } + if (ret == 1) { + error("%s is a swap device", file); + return 1; + } + if (!force_overwrite) { + if (check_overwrite(file)) { + error("use the -f option to force overwrite of %s", + file); + return 1; + } + } + ret = check_mounted(file); + if (ret < 0) { + error("cannot check mount status of %s: %s", file, + strerror(-ret)); + return 1; + } + if (ret == 1) { + error("%s is mounted", file); + return 1; + } + /* check if the device is busy */ + fd = open(file, O_RDWR|O_EXCL); + if (fd < 0) { + error("unable to open %s: %s", file, strerror(errno)); + return 1; + } + if (fstat(fd, &st)) { + error("unable to stat %s: %s", file, strerror(errno)); + close(fd); + return 1; + } + if (!S_ISBLK(st.st_mode)) { + error("%s is not a block device", file); + close(fd); + return 1; + } + close(fd); + return 0; +} + +int is_vol_small(const char *file) +{ + int fd = -1; + int e; + struct stat st; + u64 size; + + fd = open(file, O_RDONLY); + if (fd < 0) + return -errno; + if (fstat(fd, &st) < 0) { + e = -errno; + close(fd); + return e; + } + size = btrfs_device_size(fd, &st); + if (size == 0) { + close(fd); + return -1; + } + if (size < BTRFS_MKFS_SMALL_VOLUME_SIZE) { + close(fd); + return 1; + } else { + close(fd); + return 0; + } +} + +int test_minimum_size(const char *file, u32 nodesize) +{ + int fd; + struct stat statbuf; + + fd = open(file, O_RDONLY); + if (fd < 0) + return -errno; + if (stat(file, &statbuf) < 0) { + close(fd); + return -errno; + } + if (btrfs_device_size(fd, &statbuf) < btrfs_min_dev_size(nodesize)) { + close(fd); + return 1; + } + close(fd); + return 0; +} + + |