btrfs-progs: check the free space tree in btrfsck
[platform/upstream/btrfs-progs.git] / utils.c
diff --git a/utils.c b/utils.c
index 17f4757..03648db 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -154,7 +154,7 @@ int test_uuid_unique(char *fs_uuid)
        blkid_dev dev = NULL;
        blkid_cache cache = NULL;
 
-       if (blkid_get_cache(&cache, 0) < 0) {
+       if (blkid_get_cache(&cache, NULL) < 0) {
                printf("ERROR: lblkid cache get failed\n");
                return 1;
        }
@@ -552,12 +552,12 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
 
        /* and write out the super block */
        BUG_ON(sizeof(super) > cfg->sectorsize);
-       memset(buf->data, 0, cfg->sectorsize);
+       memset(buf->data, 0, BTRFS_SUPER_INFO_SIZE);
        memcpy(buf->data, &super, sizeof(super));
-       buf->len = cfg->sectorsize;
+       buf->len = BTRFS_SUPER_INFO_SIZE;
        csum_tree_block_size(buf, BTRFS_CRC32_SIZE, 0);
-       ret = pwrite(fd, buf->data, cfg->sectorsize, cfg->blocks[0]);
-       if (ret != cfg->sectorsize) {
+       ret = pwrite(fd, buf->data, BTRFS_SUPER_INFO_SIZE, cfg->blocks[0]);
+       if (ret != BTRFS_SUPER_INFO_SIZE) {
                ret = (ret < 0 ? -errno : -EIO);
                goto out;
        }
@@ -1172,6 +1172,34 @@ static int is_loop_device (const char* device) {
                MAJOR(statbuf.st_rdev) == LOOP_MAJOR);
 }
 
+/*
+ * Takes a loop device path (e.g. /dev/loop0) and returns
+ * the associated file (e.g. /images/my_btrfs.img) using
+ * loopdev API
+ */
+static int resolve_loop_device_with_loopdev(const char* loop_dev, char* loop_file)
+{
+       int fd;
+       int ret;
+       struct loop_info64 lo64;
+
+       fd = open(loop_dev, O_RDONLY | O_NONBLOCK);
+       if (fd < 0)
+               return -errno;
+       ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
+       if (ret < 0) {
+               ret = -errno;
+               goto out;
+       }
+
+       memcpy(loop_file, lo64.lo_file_name, sizeof(lo64.lo_file_name));
+       loop_file[sizeof(lo64.lo_file_name)] = 0;
+
+out:
+       close(fd);
+
+       return ret;
+}
 
 /* Takes a loop device path (e.g. /dev/loop0) and returns
  * the associated file (e.g. /images/my_btrfs.img) */
@@ -1187,8 +1215,15 @@ static int resolve_loop_device(const char* loop_dev, char* loop_file,
        if (!realpath(loop_dev, real_loop_dev))
                return -errno;
        snprintf(p, PATH_MAX, "/sys/block/%s/loop/backing_file", strrchr(real_loop_dev, '/'));
-       if (!(f = fopen(p, "r")))
+       if (!(f = fopen(p, "r"))) {
+               if (errno == ENOENT)
+                       /*
+                        * It's possibly a partitioned loop device, which is
+                        * resolvable with loopdev API.
+                        */
+                       return resolve_loop_device_with_loopdev(loop_dev, loop_file);
                return -errno;
+       }
 
        snprintf(fmt, 20, "%%%i[^\n]", max_len-1);
        ret = fscanf(f, fmt, loop_file);
@@ -2428,7 +2463,7 @@ static int group_profile_devs_min(u64 flag)
 }
 
 int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile,
-       u64 dev_cnt, int mixed)
+       u64 dev_cnt, int mixed, int ssd)
 {
        u64 allowed = 0;
 
@@ -2469,11 +2504,9 @@ int test_num_disk_vs_raid(u64 metadata_profile, u64 data_profile,
                return 1;
        }
 
-       if (!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP)) {
-               fprintf(stderr,
-                       "ERROR: DUP for data is allowed only in mixed mode\n");
-               return 1;
-       }
+       warning_on(!mixed && (data_profile & BTRFS_BLOCK_GROUP_DUP) && ssd,
+                  "DUP may not actually lead to 2 copies on the device, see manual page");
+
        return 0;
 }
 
@@ -2568,7 +2601,7 @@ int btrfs_scan_lblkid(void)
        if (btrfs_scan_done)
                return 0;
 
-       if (blkid_get_cache(&cache, 0) < 0) {
+       if (blkid_get_cache(&cache, NULL) < 0) {
                printf("ERROR: lblkid cache get failed\n");
                return 1;
        }