btrfs-progs: qgroup: cleanup __qgroup_search
[platform/upstream/btrfs-progs.git] / utils.c
diff --git a/utils.c b/utils.c
index e7bbefb..80071e2 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -24,6 +24,7 @@
 #include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/sysinfo.h>
 #include <uuid/uuid.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -179,7 +180,8 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
                      u32 sectorsize)
 {
        struct btrfs_super_block *disk_super;
-       struct btrfs_super_block *super = root->fs_info->super_copy;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_super_block *super = fs_info->super_copy;
        struct btrfs_device *device;
        struct btrfs_dev_item *dev_item;
        char *buf = NULL;
@@ -214,7 +216,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
        device->total_bytes = device_total_bytes;
        device->bytes_used = 0;
        device->total_ios = 0;
-       device->dev_root = root->fs_info->dev_root;
+       device->dev_root = fs_info->dev_root;
        device->name = strdup(path);
        if (!device->name) {
                ret = -ENOMEM;
@@ -222,7 +224,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
        }
 
        INIT_LIST_HEAD(&device->dev_list);
-       ret = btrfs_add_device(trans, root, device);
+       ret = btrfs_add_device(trans, fs_info, device);
        if (ret)
                goto out;
 
@@ -248,8 +250,8 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
        BUG_ON(ret != sectorsize);
 
        free(buf);
-       list_add(&device->dev_list, &root->fs_info->fs_devices->devices);
-       device->fs_devices = root->fs_info->fs_devices;
+       list_add(&device->dev_list, &fs_info->fs_devices->devices);
+       device->fs_devices = fs_info->fs_devices;
        return 0;
 
 out:
@@ -378,7 +380,7 @@ int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
        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->nodesize);
+       btrfs_set_stack_inode_nbytes(&inode_item, root->fs_info->nodesize);
        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);
@@ -445,7 +447,7 @@ int is_mount_point(const char *path)
        return ret;
 }
 
-static int is_reg_file(const char *path)
+int is_reg_file(const char *path)
 {
        struct stat statbuf;
 
@@ -454,6 +456,21 @@ static int is_reg_file(const char *path)
        return S_ISREG(statbuf.st_mode);
 }
 
+int is_path_exist(const char *path)
+{
+       struct stat statbuf;
+       int ret;
+
+       ret = stat(path, &statbuf);
+       if (ret < 0) {
+               if (errno == ENOENT)
+                       return 0;
+               else
+                       return -errno;
+       }
+       return 1;
+}
+
 /*
  * This function checks if the given input parameter is
  * an uuid or a path
@@ -567,9 +584,9 @@ int open_path_or_dev_mnt(const char *path, DIR **dirstream, int verbose)
 /*
  * Do the following checks before calling open_file_or_dir():
  * 1: path is in a btrfs filesystem
- * 2: path is a directory
+ * 2: path is a directory if dir_only is 1
  */
-int btrfs_open_dir(const char *path, DIR **dirstream, int verbose)
+int btrfs_open(const char *path, DIR **dirstream, int verbose, int dir_only)
 {
        struct statfs stfs;
        struct stat st;
@@ -592,7 +609,7 @@ int btrfs_open_dir(const char *path, DIR **dirstream, int verbose)
                return -1;
        }
 
-       if (!S_ISDIR(st.st_mode)) {
+       if (dir_only && !S_ISDIR(st.st_mode)) {
                error_on(verbose, "not a directory: %s", path);
                return -3;
        }
@@ -606,6 +623,16 @@ int btrfs_open_dir(const char *path, DIR **dirstream, int verbose)
        return ret;
 }
 
+int btrfs_open_dir(const char *path, DIR **dirstream, int verbose)
+{
+       return btrfs_open(path, dirstream, verbose, 1);
+}
+
+int btrfs_open_file_or_dir(const char *path, DIR **dirstream, int verbose)
+{
+       return btrfs_open(path, dirstream, verbose, 0);
+}
+
 /* checks if a device is a loop device */
 static int is_loop_device (const char* device) {
        struct stat statbuf;
@@ -1228,6 +1255,7 @@ static int set_label_unmounted(const char *dev, const char *label)
                return -1;
 
        trans = btrfs_start_transaction(root, 1);
+       BUG_ON(IS_ERR(trans));
        __strncpy_null(root->fs_info->super_copy->label, label, BTRFS_LABEL_SIZE - 1);
 
        btrfs_commit_transaction(trans, root);
@@ -1746,6 +1774,109 @@ out:
        return ret;
 }
 
+int get_fsid(const char *path, u8 *fsid, int silent)
+{
+       int ret;
+       int fd;
+       struct btrfs_ioctl_fs_info_args args;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               ret = -errno;
+               if (!silent)
+                       error("failed to open %s: %s", path,
+                               strerror(-ret));
+               goto out;
+       }
+
+       ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
+       if (ret < 0) {
+               ret = -errno;
+               goto out;
+       }
+
+       memcpy(fsid, args.fsid, BTRFS_FSID_SIZE);
+       ret = 0;
+
+out:
+       if (fd != -1)
+               close(fd);
+       return ret;
+}
+
+int is_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[])
+{
+       u8 hash = fsid[0];
+       int slot = hash % SEEN_FSID_HASH_SIZE;
+       struct seen_fsid *seen = seen_fsid_hash[slot];
+
+       while (seen) {
+               if (memcmp(seen->fsid, fsid, BTRFS_FSID_SIZE) == 0)
+                       return 1;
+
+               seen = seen->next;
+       }
+
+       return 0;
+}
+
+int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[],
+               int fd, DIR *dirstream)
+{
+       u8 hash = fsid[0];
+       int slot = hash % SEEN_FSID_HASH_SIZE;
+       struct seen_fsid *seen = seen_fsid_hash[slot];
+       struct seen_fsid *alloc;
+
+       if (!seen)
+               goto insert;
+
+       while (1) {
+               if (memcmp(seen->fsid, fsid, BTRFS_FSID_SIZE) == 0)
+                       return -EEXIST;
+
+               if (!seen->next)
+                       break;
+
+               seen = seen->next;
+       }
+
+insert:
+       alloc = malloc(sizeof(*alloc));
+       if (!alloc)
+               return -ENOMEM;
+
+       alloc->next = NULL;
+       memcpy(alloc->fsid, fsid, BTRFS_FSID_SIZE);
+       alloc->fd = fd;
+       alloc->dirstream = dirstream;
+
+       if (seen)
+               seen->next = alloc;
+       else
+               seen_fsid_hash[slot] = alloc;
+
+       return 0;
+}
+
+void free_seen_fsid(struct seen_fsid *seen_fsid_hash[])
+{
+       int slot;
+       struct seen_fsid *seen;
+       struct seen_fsid *next;
+
+       for (slot = 0; slot < SEEN_FSID_HASH_SIZE; slot++) {
+               seen = seen_fsid_hash[slot];
+               while (seen) {
+                       next = seen->next;
+                       close_file_or_dir(seen->fd, seen->dirstream);
+                       free(seen);
+                       seen = next;
+               }
+               seen_fsid_hash[slot] = NULL;
+       }
+}
+
 static int group_profile_devs_min(u64 flag)
 {
        switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
@@ -2266,6 +2397,32 @@ unsigned int get_unit_mode_from_arg(int *argc, char *argv[], int df_mode)
        return unit_mode;
 }
 
+u64 div_factor(u64 num, int factor)
+{
+       if (factor == 10)
+               return num;
+       num *= factor;
+       num /= 10;
+       return num;
+}
+/*
+ * Get the length of the string converted from a u64 number.
+ *
+ * Result is equal to log10(num) + 1, but without the use of math library.
+ */
+int count_digits(u64 num)
+{
+       int ret = 0;
+
+       if (num == 0)
+               return 1;
+       while (num > 0) {
+               ret++;
+               num /= 10;
+       }
+       return ret;
+}
+
 int string_is_numerical(const char *str)
 {
        if (!str)
@@ -2279,6 +2436,15 @@ int string_is_numerical(const char *str)
        return 1;
 }
 
+int prefixcmp(const char *str, const char *prefix)
+{
+       for (; ; str++, prefix++)
+               if (!*prefix)
+                       return 0;
+               else if (*str != *prefix)
+                       return (unsigned char)*prefix - (unsigned char)*str;
+}
+
 /* Subvolume helper functions */
 /*
  * test if name is a correct subvolume name
@@ -2397,6 +2563,59 @@ out:
        return ret;
 }
 
+int get_subvol_info_by_rootid(const char *mnt, struct root_info *get_ri, u64 r_id)
+{
+       int fd;
+       int ret;
+       DIR *dirstream = NULL;
+
+       fd = btrfs_open_dir(mnt, &dirstream, 1);
+       if (fd < 0)
+               return -EINVAL;
+
+       memset(get_ri, 0, sizeof(*get_ri));
+       get_ri->root_id = r_id;
+
+       if (r_id == BTRFS_FS_TREE_OBJECTID)
+               ret = btrfs_get_toplevel_subvol(fd, get_ri);
+       else
+               ret = btrfs_get_subvol(fd, get_ri);
+
+       if (ret)
+               error("can't find rootid '%llu' on '%s': %d", r_id, mnt, ret);
+
+       close_file_or_dir(fd, dirstream);
+
+       return ret;
+}
+
+int get_subvol_info_by_uuid(const char *mnt, struct root_info *get_ri, u8 *uuid_arg)
+{
+       int fd;
+       int ret;
+       DIR *dirstream = NULL;
+
+       fd = btrfs_open_dir(mnt, &dirstream, 1);
+       if (fd < 0)
+               return -EINVAL;
+
+       memset(get_ri, 0, sizeof(*get_ri));
+       uuid_copy(get_ri->uuid, uuid_arg);
+
+       ret = btrfs_get_subvol(fd, get_ri);
+       if (ret) {
+               char uuid_parsed[BTRFS_UUID_UNPARSED_SIZE];
+               uuid_unparse(uuid_arg, uuid_parsed);
+               error("can't find uuid '%s' on '%s': %d",
+                                       uuid_parsed, mnt, ret);
+       }
+
+       close_file_or_dir(fd, dirstream);
+
+       return ret;
+}
+
+/* Set the seed manually */
 void init_rand_seed(u64 seed)
 {
        int i;
@@ -2446,6 +2665,7 @@ u32 rand_u32(void)
        return (u32)jrand48(rand_seed);
 }
 
+/* Return random number in range [0, upper) */
 unsigned int rand_range(unsigned int upper)
 {
        __init_seed();
@@ -2456,6 +2676,43 @@ unsigned int rand_range(unsigned int upper)
        return (unsigned int)(jrand48(rand_seed) % upper);
 }
 
+int rand_int(void)
+{
+       return (int)(rand_u32());
+}
+
+u64 rand_u64(void)
+{
+       u64 ret = 0;
+
+       ret += rand_u32();
+       ret <<= 32;
+       ret += rand_u32();
+       return ret;
+}
+
+u16 rand_u16(void)
+{
+       return (u16)(rand_u32());
+}
+
+u8 rand_u8(void)
+{
+       return (u8)(rand_u32());
+}
+
 void btrfs_config_init(void)
 {
 }
+
+/* Returns total size of main memory in bytes, -1UL if error. */
+unsigned long total_memory(void)
+{
+        struct sysinfo si;
+
+        if (sysinfo(&si) < 0) {
+                error("can't determine memory size");
+                return -1UL;
+        }
+        return si.totalram * si.mem_unit;       /* bytes */
+}