diff --git a/Makefile b/Makefile index 30bd01f2..4ee385b6 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,8 @@ cmds_objects = cmds-subvolume.o cmds-filesystem.o cmds-device.o cmds-scrub.o \ cmds-quota.o cmds-qgroup.o cmds-replace.o cmds-check.o \ cmds-restore.o cmds-rescue.o chunk-recover.o super-recover.o \ cmds-property.o cmds-fi-usage.o cmds-inspect-dump-tree.o \ - cmds-inspect-dump-super.o cmds-inspect-tree-stats.o cmds-fi-du.o + cmds-inspect-dump-super.o cmds-inspect-tree-stats.o cmds-fi-du.o \ + mkfs/common.o libbtrfs_objects = send-stream.o send-utils.o kernel-lib/rbtree.o btrfs-list.o \ kernel-lib/crc32c.o \ uuid-tree.o utils-lib.o rbtree-utils.o 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 #include +#include +#include #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; +} + + diff --git a/utils.c b/utils.c index 20cddd9d..e7bbefbb 100644 --- a/utils.c +++ b/utils.c @@ -1746,159 +1746,6 @@ out: return ret; } -#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; -} - static int group_profile_devs_min(u64 flag) { switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) { @@ -1987,84 +1834,6 @@ int group_profile_max_safe_loss(u64 flags) } } -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; -} - -/* - * 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 btrfs_scan_devices(void) { int fd = -1; @@ -2117,35 +1886,6 @@ int btrfs_scan_devices(void) 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; - } -} - /* * This reads a line from the stdin and only returns non-zero if the * first whitespace delimited token is a case insensitive match with yes @@ -2219,27 +1959,6 @@ int find_mount_root(const char *path, char **mount_root) return ret; } -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; -} - - /* * Test if path is a directory * Returns: