#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>
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;
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;
}
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;
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:
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);
/*
* 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;
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;
}
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;
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);
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) {
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
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)
{
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 */
+}