#include <fcntl.h>
#include <unistd.h>
#include <mntent.h>
+#include <ctype.h>
#include <linux/loop.h>
#include <linux/major.h>
#include <linux/kdev_t.h>
static inline int ioctl(int fd, int define, u64 *size) { return 0; }
#endif
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+static int
+discard_blocks(int fd, u64 start, u64 len)
+{
+ u64 range[2] = { start, len };
+
+ if (ioctl(fd, BLKDISCARD, &range) < 0)
+ return errno;
+ return 0;
+}
+
static u64 reference_root_table[] = {
[1] = BTRFS_ROOT_TREE_OBJECTID,
[2] = BTRFS_EXTENT_TREE_OBJECTID,
BUG_ON(ret != leafsize);
/* create the items for the extent tree */
+ memset(buf->data+sizeof(struct btrfs_header), 0,
+ leafsize-sizeof(struct btrfs_header));
nritems = 0;
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize);
for (i = 1; i < 7; i++) {
BUG_ON(ret != leafsize);
/* create the chunk tree */
+ memset(buf->data+sizeof(struct btrfs_header), 0,
+ leafsize-sizeof(struct btrfs_header));
nritems = 0;
item_size = sizeof(*dev_item);
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) - item_size;
ret = pwrite(fd, buf->data, leafsize, blocks[3]);
/* create the device tree */
+ memset(buf->data+sizeof(struct btrfs_header), 0,
+ leafsize-sizeof(struct btrfs_header));
nritems = 0;
itemoff = __BTRFS_LEAF_DATA_SIZE(leafsize) -
sizeof(struct btrfs_dev_extent);
ret = pwrite(fd, buf->data, leafsize, blocks[4]);
/* create the FS root */
+ memset(buf->data+sizeof(struct btrfs_header), 0,
+ leafsize-sizeof(struct btrfs_header));
btrfs_set_header_bytenr(buf, blocks[5]);
btrfs_set_header_owner(buf, BTRFS_FS_TREE_OBJECTID);
btrfs_set_header_nritems(buf, 0);
BUG_ON(ret != leafsize);
/* finally create the csum root */
+ memset(buf->data+sizeof(struct btrfs_header), 0,
+ leafsize-sizeof(struct btrfs_header));
btrfs_set_header_bytenr(buf, blocks[6]);
btrfs_set_header_owner(buf, BTRFS_CSUM_TREE_OBJECTID);
btrfs_set_header_nritems(buf, 0);
}
int btrfs_prepare_device(int fd, char *file, int zero_end, u64 *block_count_ret,
- int *mixed)
+ u64 max_block_count, int *mixed, int nodiscard)
{
u64 block_count;
u64 bytenr;
fprintf(stderr, "unable to find %s size\n", file);
exit(1);
}
+ if (max_block_count)
+ block_count = min(block_count, max_block_count);
zero_end = 1;
if (block_count < 1024 * 1024 * 1024 && !(*mixed)) {
printf("SMALL VOLUME: forcing mixed metadata/data groups\n");
*mixed = 1;
}
+
+ if (!nodiscard) {
+ /*
+ * We intentionally ignore errors from the discard ioctl. It is
+ * not necessary for the mkfs functionality but just an optimization.
+ */
+ discard_blocks(fd, 0, block_count);
+ }
+
ret = zero_dev_start(fd);
if (ret) {
fprintf(stderr, "failed to zero device start %d\n", ret);
{
int ret;
struct btrfs_inode_item inode_item;
+ time_t now = time(NULL);
memset(&inode_item, 0, sizeof(inode_item));
btrfs_set_stack_inode_generation(&inode_item, trans->transid);
btrfs_set_stack_inode_size(&inode_item, 0);
btrfs_set_stack_inode_nlink(&inode_item, 1);
btrfs_set_stack_inode_nbytes(&inode_item, root->leafsize);
- btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0555);
+ btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755);
+ btrfs_set_stack_timespec_sec(&inode_item.atime, now);
+ btrfs_set_stack_timespec_nsec(&inode_item.atime, 0);
+ btrfs_set_stack_timespec_sec(&inode_item.ctime, now);
+ btrfs_set_stack_timespec_nsec(&inode_item.ctime, 0);
+ btrfs_set_stack_timespec_sec(&inode_item.mtime, now);
+ btrfs_set_stack_timespec_nsec(&inode_item.mtime, 0);
+ btrfs_set_stack_timespec_sec(&inode_item.otime, 0);
+ btrfs_set_stack_timespec_nsec(&inode_item.otime, 0);
if (root->fs_info->tree_root == root)
btrfs_set_super_root_dir(&root->fs_info->super_copy, objectid);
ret_ioctl = ioctl(loop_fd, LOOP_GET_STATUS, &loopinfo);
close(loop_fd);
- if (ret_ioctl == 0)
+ if (ret_ioctl == 0) {
strncpy(loop_file, loopinfo.lo_name, max_len);
- else
+ if (max_len > 0)
+ loop_file[max_len-1] = 0;
+ } else
return -errno;
return 0;
if(stat(a, &st_buf_a) < 0 ||
stat(b, &st_buf_b) < 0)
{
+ if (errno == ENOENT)
+ return 0;
return -errno;
}
/* Resolve a if it is a loop device */
if((ret = is_loop_device(a)) < 0) {
- return ret;
- } else if(ret) {
- if((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0)
+ if (ret == -ENOENT)
+ return 0;
+ return ret;
+ } else if (ret) {
+ if ((ret = resolve_loop_device(a, res_a, sizeof(res_a))) < 0)
return ret;
final_a = res_a;
}
/* Resolve b if it is a loop device */
- if((ret = is_loop_device(b)) < 0) {
- return ret;
- } else if(ret) {
+ if ((ret = is_loop_device(b)) < 0) {
+ if (ret == -ENOENT)
+ return 0;
+ return ret;
+ } else if (ret) {
if((ret = resolve_loop_device(b, res_b, sizeof(res_b))) < 0)
return ret;
*/
int check_mounted(const char* file)
{
- int ret;
int fd;
- u64 total_devs = 1;
- int is_btrfs;
- struct btrfs_fs_devices* fs_devices_mnt = NULL;
- FILE *f;
- struct mntent *mnt;
+ int ret;
fd = open(file, O_RDONLY);
if (fd < 0) {
return -errno;
}
+ ret = check_mounted_where(fd, file, NULL, 0, NULL);
+ close(fd);
+
+ return ret;
+}
+
+int check_mounted_where(int fd, const char *file, char *where, int size,
+ struct btrfs_fs_devices **fs_dev_ret)
+{
+ int ret;
+ u64 total_devs = 1;
+ int is_btrfs;
+ struct btrfs_fs_devices *fs_devices_mnt = NULL;
+ FILE *f;
+ struct mntent *mnt;
+
/* scan the initial device */
ret = btrfs_scan_one_device(fd, file, &fs_devices_mnt,
&total_devs, BTRFS_SUPER_INFO_OFFSET);
is_btrfs = (ret >= 0);
- close(fd);
/* scan other devices */
if (is_btrfs && total_devs > 1) {
}
/* Did we find an entry in mnt table? */
+ if (mnt && size && where) {
+ strncpy(where, mnt->mnt_dir, size);
+ where[size-1] = 0;
+ }
+ if (fs_dev_ret)
+ *fs_dev_ret = fs_devices_mnt;
+
ret = (mnt != NULL);
out_mntloop_err:
return ret;
}
+/* Gets the mount point of btrfs filesystem that is using the specified device.
+ * Returns 0 is everything is good, <0 if we have an error.
+ * TODO: Fix this fucntion and check_mounted to work with multiple drive BTRFS
+ * setups.
+ */
+int get_mountpt(char *dev, char *mntpt, size_t size)
+{
+ struct mntent *mnt;
+ FILE *f;
+ int ret = 0;
+
+ f = setmntent("/proc/mounts", "r");
+ if (f == NULL)
+ return -errno;
+
+ while ((mnt = getmntent(f)) != NULL )
+ {
+ if (strcmp(dev, mnt->mnt_fsname) == 0)
+ {
+ strncpy(mntpt, mnt->mnt_dir, size);
+ if (size)
+ mntpt[size-1] = 0;
+ break;
+ }
+ }
+
+ if (mnt == NULL)
+ {
+ /* We didn't find an entry so lets report an error */
+ ret = -1;
+ }
+
+ return ret;
+}
+
struct pending_dir {
struct list_head list;
char name[256];
return;
}
strncpy(args.name, fname, BTRFS_PATH_NAME_MAX);
+ args.name[BTRFS_PATH_NAME_MAX-1] = 0;
ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
e = errno;
if(ret<0){
list);
list_del(&pending->list);
closedir(dirp);
+ dirp = NULL;
goto again;
}
ret = 0;
int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
int run_ioctls)
{
- return btrfs_scan_one_dir("/dev", run_ioctls);
+ int ret;
+
+ ret = btrfs_scan_block_devices(run_ioctls);
+ if (ret)
+ ret = btrfs_scan_one_dir("/dev", run_ioctls);
+ return ret;
}
int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
{
int num_divs = 0;
int pretty_len = 16;
- u64 last_size = size;
- u64 fract_size = size;
float fraction;
char *pretty;
- while(size > 0) {
- fract_size = last_size;
- last_size = size;
- size /= 1024;
- num_divs++;
- }
- if (num_divs == 0)
- num_divs = 1;
- if (num_divs > ARRAY_SIZE(size_strs))
- return NULL;
+ if( size < 1024 ){
+ fraction = size;
+ num_divs = 0;
+ } else {
+ u64 last_size = size;
+ num_divs = 0;
+ while(size >= 1024){
+ last_size = size;
+ size /= 1024;
+ num_divs ++;
+ }
- fraction = (float)fract_size / 1024;
+ if (num_divs > ARRAY_SIZE(size_strs))
+ return NULL;
+ fraction = (float)last_size / 1024;
+ }
pretty = malloc(pretty_len);
- snprintf(pretty, pretty_len, "%.2f%s", fraction, size_strs[num_divs-1]);
+ snprintf(pretty, pretty_len, "%.2f%s", fraction, size_strs[num_divs]);
return pretty;
}
+/*
+ * Checks to make sure that the label matches our requirements.
+ * Returns:
+ 0 if everything is safe and usable
+ -1 if the label is too long
+ -2 if the label contains an invalid character
+ */
+int check_label(char *input)
+{
+ int i;
+ int len = strlen(input);
+
+ if (len > BTRFS_LABEL_SIZE) {
+ return -1;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (input[i] == '/' || input[i] == '\\') {
+ return -2;
+ }
+ }
+
+ return 0;
+}
+
+int btrfs_scan_block_devices(int run_ioctl)
+{
+
+ struct stat st;
+ int ret;
+ int fd;
+ struct btrfs_fs_devices *tmp_devices;
+ u64 num_devices;
+ FILE *proc_partitions;
+ int i;
+ char buf[1024];
+ char fullpath[110];
+ int scans = 0;
+ int special;
+
+scan_again:
+ proc_partitions = fopen("/proc/partitions","r");
+ if (!proc_partitions) {
+ fprintf(stderr, "Unable to open '/proc/partitions' for scanning\n");
+ return -ENOENT;
+ }
+ /* skip the header */
+ for(i=0; i < 2 ; i++)
+ if(!fgets(buf, 1023, proc_partitions)){
+ fprintf(stderr, "Unable to read '/proc/partitions' for scanning\n");
+ fclose(proc_partitions);
+ return -ENOENT;
+ }
+
+ strcpy(fullpath,"/dev/");
+ while(fgets(buf, 1023, proc_partitions)) {
+ i = sscanf(buf," %*d %*d %*d %99s", fullpath+5);
+
+ /*
+ * multipath and MD devices may register as a btrfs filesystem
+ * both through the original block device and through
+ * the special (/dev/mapper or /dev/mdX) entry.
+ * This scans the special entries last
+ */
+ special = strncmp(fullpath, "/dev/dm-", strlen("/dev/dm-")) == 0;
+ if (!special)
+ special = strncmp(fullpath, "/dev/md", strlen("/dev/md")) == 0;
+
+ if (scans == 0 && special)
+ continue;
+ if (scans > 0 && !special)
+ continue;
+
+ ret = lstat(fullpath, &st);
+ if (ret < 0) {
+ fprintf(stderr, "failed to stat %s\n", fullpath);
+ continue;
+ }
+ if (!S_ISBLK(st.st_mode)) {
+ continue;
+ }
+
+ fd = open(fullpath, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "failed to read %s\n", fullpath);
+ continue;
+ }
+ ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices,
+ &num_devices,
+ BTRFS_SUPER_INFO_OFFSET);
+ if (ret == 0 && run_ioctl > 0) {
+ btrfs_register_one_device(fullpath);
+ }
+ close(fd);
+ }
+
+ fclose(proc_partitions);
+
+ if (scans == 0) {
+ scans++;
+ goto scan_again;
+ }
+ return 0;
+}
+
+u64 parse_size(char *s)
+{
+ int i;
+ char c;
+ u64 mult = 1;
+
+ for (i=0 ; s[i] && isdigit(s[i]) ; i++) ;
+ if (!i) {
+ fprintf(stderr, "ERROR: size value is empty\n");
+ exit(50);
+ }
+
+ if (s[i]) {
+ c = tolower(s[i]);
+ switch (c) {
+ case 'e':
+ mult *= 1024;
+ case 'p':
+ mult *= 1024;
+ case 't':
+ mult *= 1024;
+ case 'g':
+ mult *= 1024;
+ case 'm':
+ mult *= 1024;
+ case 'k':
+ mult *= 1024;
+ case 'b':
+ break;
+ default:
+ fprintf(stderr, "ERROR: Unknown size descriptor "
+ "'%c'\n", c);
+ exit(1);
+ }
+ }
+ if (s[i] && s[i+1]) {
+ fprintf(stderr, "ERROR: Illegal suffix contains "
+ "character '%c' in wrong position\n",
+ s[i+1]);
+ exit(51);
+ }
+ return strtoull(s, NULL, 10) * mult;
+}
+