From 26afd0f31d59853f51120622b0121cdfc72cd398 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 24 Mar 2008 15:04:49 -0400 Subject: ioctls to scan for btrfs filesystems --- btrfsctl.c | 14 +++++- ctree.h | 16 ++++++ ioctl.h | 6 ++- mkfs.c | 161 ++++++++++++++++++++--------------------------------------- utils.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- utils.h | 5 ++ volumes.c | 1 + volumes.h | 3 ++ 8 files changed, 259 insertions(+), 111 deletions(-) diff --git a/btrfsctl.c b/btrfsctl.c index 22f253a0..1518a13e 100644 --- a/btrfsctl.c +++ b/btrfsctl.c @@ -47,6 +47,7 @@ void print_usage(void) printf("\t-s snap_name existing_subvol creates a new snapshot\n"); printf("\t-s snap_name tree_root creates a new subvolume\n"); printf("\t-r [+-]size[gkm] resize the FS\n"); + printf("\t-a device scans the device for a Btrfs filesystem\n"); exit(1); } @@ -88,6 +89,12 @@ int main(int ac, char **av) print_usage(); } command = BTRFS_IOC_DEFRAG; + } else if (strcmp(av[i], "-a") == 0) { + if (i >= ac - 1) { + fprintf(stderr, "-a requires an arg\n"); + print_usage(); + } + command = BTRFS_IOC_SCAN_DEV; } else if (strcmp(av[i], "-r") == 0) { if (i >= ac - 1) { fprintf(stderr, "-r requires an arg\n"); @@ -119,9 +126,14 @@ int main(int ac, char **av) exit(1); } fd = dirfd(dirstream); + } else if (command == BTRFS_IOC_SCAN_DEV) { + fd = open("/dev/btrfs-control", O_RDWR); + printf("scanning %s command %lu\n", fname, BTRFS_IOC_SCAN_DEV); + name = fname; } else { fd = open(fname, O_RDWR); - } if (fd < 0) { + } + if (fd < 0) { perror("open"); exit(1); } diff --git a/ctree.h b/ctree.h index a8c1b5fa..55d2961d 100644 --- a/ctree.h +++ b/ctree.h @@ -227,6 +227,7 @@ struct btrfs_super_block { __le64 total_bytes; __le64 bytes_used; __le64 root_dir_objectid; + __le64 num_devices; __le32 sectorsize; __le32 nodesize; __le32 leafsize; @@ -630,6 +631,19 @@ BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32); BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item, + total_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item, + bytes_used, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item, + io_align, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item, + io_width, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item, + sector_size, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64); + static inline char *btrfs_device_uuid(struct btrfs_dev_item *d) { return (char *)d + offsetof(struct btrfs_dev_item, uuid); @@ -1092,6 +1106,8 @@ BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block, stripesize, 32); BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, root_dir_objectid, 64); +BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block, + num_devices, 64); static inline unsigned long btrfs_leaf_data(struct extent_buffer *l) { diff --git a/ioctl.h b/ioctl.h index 8c629066..4551e820 100644 --- a/ioctl.h +++ b/ioctl.h @@ -22,8 +22,10 @@ #define BTRFS_IOCTL_MAGIC 0x94 #define BTRFS_VOL_NAME_MAX 255 +#define BTRFS_PATH_NAME_MAX 4095 + struct btrfs_ioctl_vol_args { - char name[BTRFS_VOL_NAME_MAX + 1]; + char name[BTRFS_PATH_NAME_MAX + 1]; }; #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ @@ -32,4 +34,6 @@ struct btrfs_ioctl_vol_args { struct btrfs_ioctl_vol_args) #define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \ struct btrfs_ioctl_vol_args) +#define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \ + struct btrfs_ioctl_vol_args) #endif diff --git a/mkfs.c b/mkfs.c index d5cefac8..6de35cc6 100644 --- a/mkfs.c +++ b/mkfs.c @@ -17,10 +17,6 @@ */ #define _XOPEN_SOURCE 500 -#ifndef __CHECKER__ -#include -#include -#endif #include #include #include @@ -37,11 +33,6 @@ #include "transaction.h" #include "utils.h" -#ifdef __CHECKER__ -#define BLKGETSIZE64 0 -static inline int ioctl(int fd, int define, u64 *size) { return 0; } -#endif - static u64 parse_size(char *s) { int len = strlen(s); @@ -68,43 +59,6 @@ static u64 parse_size(char *s) return atol(s) * mult; } -static int zero_blocks(int fd, off_t start, size_t len) -{ - char *buf = malloc(len); - int ret = 0; - ssize_t written; - - if (!buf) - return -ENOMEM; - memset(buf, 0, len); - written = pwrite(fd, buf, len, start); - if (written != len) - ret = -EIO; - free(buf); - return ret; -} - -static int zero_dev_start(int fd) -{ - off_t start = 0; - size_t len = 2 * 1024 * 1024; - -#ifdef __sparc__ - /* don't overwrite the disk labels on sparc */ - start = 1024; - len -= 1024; -#endif - return zero_blocks(fd, start, len); -} - -static int zero_dev_end(int fd, u64 dev_size) -{ - size_t len = 2 * 1024 * 1024; - off_t start = dev_size - len; - - return zero_blocks(fd, start, len); -} - static int make_root_dir(int fd) { struct btrfs_root *root; struct btrfs_trans_handle *trans; @@ -183,21 +137,6 @@ err: return ret; } -u64 device_size(int fd, struct stat *st) -{ - u64 size; - if (S_ISREG(st->st_mode)) { - return st->st_size; - } - if (!S_ISBLK(st->st_mode)) { - return 0; - } - if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { - return size; - } - return 0; -} - static void print_usage(void) { fprintf(stderr, "usage: mkfs.btrfs [ -l leafsize ] [ -n nodesize] dev [ blocks ]\n"); @@ -208,8 +147,9 @@ int main(int ac, char **av) { char *file; u64 block_count = 0; + u64 dev_block_count = 0; int fd; - struct stat st; + int first_fd; int ret; int i; u32 leafsize = 16 * 1024; @@ -217,11 +157,13 @@ int main(int ac, char **av) u32 nodesize = 16 * 1024; u32 stripesize = 4096; u64 blocks[6]; - int zero_end = 0; + int zero_end = 1; + struct btrfs_root *root; + struct btrfs_trans_handle *trans; while(1) { int c; - c = getopt(ac, av, "l:n:s:"); + c = getopt(ac, av, "b:l:n:s:"); if (c < 0) break; switch(c) { @@ -234,6 +176,10 @@ int main(int ac, char **av) case 's': stripesize = parse_size(optarg); break; + case 'b': + block_count = parse_size(optarg); + zero_end = 0; + break; default: print_usage(); } @@ -247,56 +193,20 @@ int main(int ac, char **av) exit(1); } ac = ac - optind; - if (ac >= 1) { - file = av[optind]; - if (ac == 2) { - block_count = parse_size(av[optind + 1]); - if (!block_count) { - fprintf(stderr, "error finding block count\n"); - exit(1); - } - } - } else { + if (ac == 0) print_usage(); - } + + file = av[optind++]; + ac--; fd = open(file, O_RDWR); if (fd < 0) { fprintf(stderr, "unable to open %s\n", file); exit(1); } - ret = fstat(fd, &st); - if (ret < 0) { - fprintf(stderr, "unable to stat %s\n", file); - exit(1); - } - if (block_count == 0) { - block_count = device_size(fd, &st); - if (block_count == 0) { - fprintf(stderr, "unable to find %s size\n", file); - exit(1); - } - zero_end = 1; - } - block_count /= sectorsize; - block_count *= sectorsize; - - if (block_count < 256 * 1024 * 1024) { - fprintf(stderr, "device %s is too small\n", file); - exit(1); - } - ret = zero_dev_start(fd); - if (ret) { - fprintf(stderr, "failed to zero device start %d\n", ret); - exit(1); - } - - if (zero_end) { - ret = zero_dev_end(fd, block_count); - if (ret) { - fprintf(stderr, "failed to zero device end %d\n", ret); - exit(1); - } - } + first_fd = fd; + ret = btrfs_prepare_device(fd, file, zero_end, &dev_block_count); + if (block_count == 0) + block_count = dev_block_count; for (i = 0; i < 6; i++) blocks[i] = BTRFS_SUPER_INFO_OFFSET + leafsize * i; @@ -315,6 +225,41 @@ int main(int ac, char **av) printf("fs created on %s nodesize %u leafsize %u sectorsize %u bytes %llu\n", file, nodesize, leafsize, sectorsize, (unsigned long long)block_count); + + if (ac == 0) + goto done; + + root = open_ctree(file, 0); + + if (!root) { + fprintf(stderr, "ctree init failed\n"); + return -1; + } + trans = btrfs_start_transaction(root, 1); + + zero_end = 1; + while(ac-- > 0) { + file = av[optind++]; + fd = open(file, O_RDWR); + if (fd < 0) { + fprintf(stderr, "unable to open %s\n", file); + exit(1); + } + fprintf(stderr, "adding device %s\n", file); + ret = btrfs_prepare_device(fd, file, zero_end, + &dev_block_count); + + BUG_ON(ret); + + ret = btrfs_add_to_fsid(trans, root, fd, dev_block_count, + sectorsize, sectorsize, sectorsize); + BUG_ON(ret); + close(fd); + } + btrfs_commit_transaction(trans, root); + ret = close_ctree(root); + BUG_ON(ret); +done: return 0; } diff --git a/utils.c b/utils.c index bb8f9442..80d1d036 100644 --- a/utils.c +++ b/utils.c @@ -20,6 +20,10 @@ #define __USE_XOPEN2K #include #include +#ifndef __CHECKER__ +#include +#include +#endif #include #include #include @@ -32,6 +36,13 @@ #include "transaction.h" #include "crc32c.h" #include "utils.h" +#include "volumes.h" + +#ifdef __CHECKER__ +#define BLKGETSIZE64 0 +static inline int ioctl(int fd, int define, u64 *size) { return 0; } +#endif + static u64 reference_root_table[6] = { [1] = BTRFS_ROOT_TREE_OBJECTID, [2] = BTRFS_EXTENT_TREE_OBJECTID, @@ -72,6 +83,7 @@ int make_btrfs(int fd, char *device_name, num_bytes = (num_bytes / sectorsize) * sectorsize; uuid_generate(super.fsid); btrfs_set_super_bytenr(&super, blocks[0]); + btrfs_set_super_num_devices(&super, 1); strncpy((char *)&super.magic, BTRFS_MAGIC, sizeof(super.magic)); btrfs_set_super_generation(&super, 1); btrfs_set_super_root(&super, blocks[1]); @@ -256,7 +268,7 @@ int make_btrfs(int fd, char *device_name, /* then device 1 (there is no device 0) */ nritems++; - item_size = sizeof(*dev_item) + strlen(device_name); + item_size = sizeof(*dev_item); itemoff = itemoff - item_size; btrfs_set_disk_key_objectid(&disk_key, BTRFS_DEV_ITEMS_OBJECTID); btrfs_set_disk_key_offset(&disk_key, 1); @@ -331,6 +343,156 @@ int make_btrfs(int fd, char *device_name, return 0; } +static u64 device_size(int fd, struct stat *st) +{ + u64 size; + if (S_ISREG(st->st_mode)) { + return st->st_size; + } + if (!S_ISBLK(st->st_mode)) { + return 0; + } + if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { + return size; + } + return 0; +} + +static int zero_blocks(int fd, off_t start, size_t len) +{ + char *buf = malloc(len); + int ret = 0; + ssize_t written; + + if (!buf) + return -ENOMEM; + memset(buf, 0, len); + written = pwrite(fd, buf, len, start); + if (written != len) + ret = -EIO; + free(buf); + return ret; +} + +static int zero_dev_start(int fd) +{ + off_t start = 0; + size_t len = 2 * 1024 * 1024; + +#ifdef __sparc__ + /* don't overwrite the disk labels on sparc */ + start = 1024; + len -= 1024; +#endif + return zero_blocks(fd, start, len); +} + +static int zero_dev_end(int fd, u64 dev_size) +{ + size_t len = 2 * 1024 * 1024; + off_t start = dev_size - len; + + return zero_blocks(fd, start, len); +} + +int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, + struct btrfs_root *root, int fd, u64 block_count, + u32 io_width, u32 io_align, u32 sectorsize) +{ + struct btrfs_super_block *disk_super; + struct btrfs_super_block *super = &root->fs_info->super_copy; + struct btrfs_device device; + struct btrfs_dev_item *dev_item; + char *buf; + u64 total_bytes; + u64 num_devs; + int ret; + + buf = malloc(sectorsize); + BUG_ON(sizeof(*disk_super) > sectorsize); + memset(buf, 0, sectorsize); + + disk_super = (struct btrfs_super_block *)buf; + dev_item = &disk_super->dev_item; + + uuid_generate(device.uuid); + device.devid = 0; + device.type = 0; + device.io_width = io_width; + device.io_align = io_align; + device.sector_size = sectorsize; + device.fd = 0; + device.total_bytes = block_count; + device.bytes_used = 0; + + ret = btrfs_add_device(trans, root, &device); + BUG_ON(ret); + + total_bytes = btrfs_super_total_bytes(super) + block_count; + btrfs_set_super_total_bytes(super, total_bytes); + + num_devs = btrfs_super_num_devices(super) + 1; + btrfs_set_super_num_devices(super, num_devs); + + memcpy(disk_super, super, sizeof(*disk_super)); + + printf("adding device id %Lu\n", device.devid); + btrfs_set_stack_device_id(dev_item, device.devid); + btrfs_set_stack_device_type(dev_item, device.type); + btrfs_set_stack_device_io_align(dev_item, device.io_align); + btrfs_set_stack_device_io_width(dev_item, device.io_width); + btrfs_set_stack_device_sector_size(dev_item, device.sector_size); + btrfs_set_stack_device_total_bytes(dev_item, device.total_bytes); + btrfs_set_stack_device_bytes_used(dev_item, device.bytes_used); + memcpy(&dev_item->uuid, device.uuid, BTRFS_DEV_UUID_SIZE); + + ret = pwrite(fd, buf, sectorsize, BTRFS_SUPER_INFO_OFFSET); + BUG_ON(ret != sectorsize); + + free(buf); + return 0; +} + +int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret) +{ + u64 block_count; + struct stat st; + int ret; + + ret = fstat(fd, &st); + if (ret < 0) { + fprintf(stderr, "unable to stat %s\n", file); + exit(1); + } + + block_count = device_size(fd, &st); + if (block_count == 0) { + fprintf(stderr, "unable to find %s size\n", file); + exit(1); + } + zero_end = 1; + + if (block_count < 256 * 1024 * 1024) { + fprintf(stderr, "device %s is too small\n", file); + exit(1); + } + ret = zero_dev_start(fd); + if (ret) { + fprintf(stderr, "failed to zero device start %d\n", ret); + exit(1); + } + + if (zero_end) { + ret = zero_dev_end(fd, block_count); + if (ret) { + fprintf(stderr, "failed to zero device end %d\n", ret); + exit(1); + } + } + *block_count_ret = block_count; + return 0; +} + int btrfs_make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid) { diff --git a/utils.h b/utils.h index 9dc8cf86..28e71e3d 100644 --- a/utils.h +++ b/utils.h @@ -26,4 +26,9 @@ int make_btrfs(int fd, char *device_name, u32 leafsize, u32 sectorsize, u32 stripesize); int btrfs_make_root_dir(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid); +int btrfs_prepare_device(int fd, char *file, int zero_end, + u64 *block_count_ret); +int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, + struct btrfs_root *root, int fd, u64 block_count, + u32 io_width, u32 io_align, u32 sectorsize); #endif diff --git a/volumes.c b/volumes.c index 6dc0eb1a..59664b4d 100644 --- a/volumes.c +++ b/volumes.c @@ -283,6 +283,7 @@ int btrfs_add_device(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); + device->devid = free_devid; btrfs_set_device_id(leaf, dev_item, device->devid); btrfs_set_device_type(leaf, dev_item, device->type); btrfs_set_device_io_align(leaf, dev_item, device->io_align); diff --git a/volumes.h b/volumes.h index 760f2cde..c585b15d 100644 --- a/volumes.h +++ b/volumes.h @@ -61,4 +61,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *extent_root, u64 *start, u64 *num_bytes, u64 type); int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); +int btrfs_add_device(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_device *device); #endif -- cgit v1.2.3