[lxc-devel] [PATCH] btrfs: support recursive subvolume deletion (v2)
Stéphane Graber
stgraber at ubuntu.com
Mon Aug 4 19:48:19 UTC 2014
On Fri, Aug 01, 2014 at 10:55:21PM +0000, Serge Hallyn wrote:
> Pull the #defines and struct definitions for btrfs into a separate
> .h file to not clutter bdev.c
>
> Implement btrfs recursive delete support
>
> A non-root user isn't allow to do the ioctls needed for searching (as you can
> verify with 'btrfs subvolume list'). So for an unprivileged user, if the
> rootfs has subvolumes under it, deletion will fail. Otherwise, it will
> succeed.
>
> Changelog: Aug 1:
> . Fix wrong objid passing when determining directory paths
> . In do_remove_btrfs_children, avoid dereferencing NULL dirid
> . Fix memleak in error case.
>
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
Acked-by: Stéphane Graber <stgraber at ubuntu.com>
> ---
> src/lxc/Makefile.am | 3 +-
> src/lxc/bdev.c | 421 ++++++++++++++++++++++++++++++++++++++++++++--------
> src/lxc/lxc-btrfs.h | 287 +++++++++++++++++++++++++++++++++++
> 3 files changed, 647 insertions(+), 64 deletions(-)
> create mode 100644 src/lxc/lxc-btrfs.h
>
> diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
> index cdc6833..56acba4 100644
> --- a/src/lxc/Makefile.am
> +++ b/src/lxc/Makefile.am
> @@ -15,6 +15,7 @@ noinst_HEADERS = \
> list.h \
> log.h \
> lxc.h \
> + lxc-btrfs.h \
> lxclock.h \
> monitor.h \
> namespace.h \
> @@ -53,7 +54,7 @@ endif
>
> liblxc_so_SOURCES = \
> arguments.c arguments.h \
> - bdev.c bdev.h \
> + bdev.c bdev.h lxc-btrfs.h \
> commands.c commands.h \
> start.c start.h \
> execute.c \
> diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c
> index e1ced1b..9f24994 100644
> --- a/src/lxc/bdev.c
> +++ b/src/lxc/bdev.c
> @@ -53,6 +53,7 @@
> #include "namespace.h"
> #include "parse.h"
> #include "lxclock.h"
> +#include "lxc-btrfs.h"
>
> #ifndef BLKGETSIZE64
> #define BLKGETSIZE64 _IOR(0x12,114,size_t)
> @@ -1181,26 +1182,82 @@ static const struct bdev_ops lvm_ops = {
> .can_snapshot = true,
> };
>
> +/*
> + * Return the full path of objid under dirid. Let's say dirid is
> + * /lxc/c1/rootfs, and objid is /lxc/c1/rootfs/a/b/c. Then we will
> + * return a/b/c. If instead objid is for /lxc/c1/rootfs/a, we will
> + * simply return a.
> + */
> +char *get_btrfs_subvol_path(int fd, u64 dir_id, u64 objid,
> + char *name, int name_len)
> +{
> + struct btrfs_ioctl_ino_lookup_args args;
> + int ret, e;
> + size_t len;
> + char *retpath;
> +
> + memset(&args, 0, sizeof(args));
> + args.treeid = dir_id;
> + args.objectid = objid;
> +
> + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
> + e = errno;
> + if (ret) {
> + ERROR("%s: ERROR: Failed to lookup path for %llu %llu %s - %s\n",
> + __func__, (unsigned long long) dir_id,
> + (unsigned long long) objid,
> + name, strerror(e));
> + return NULL;
> + } else
> + INFO("%s: got path for %llu %llu - %s\n", __func__,
> + (unsigned long long) objid, (unsigned long long) dir_id,
> + name);
> +
> + if (args.name[0]) {
> + /*
> + * we're in a subdirectory of ref_tree, the kernel ioctl
> + * puts a / in there for us
> + */
> + len = strlen(args.name) + name_len + 2;
> + retpath = malloc(len);
> + if (!retpath)
> + return NULL;
> + strcpy(retpath, args.name);
> + strcat(retpath, "/");
> + strncat(retpath, name, name_len);
> + } else {
> + /* we're at the root of ref_tree */
> + len = name_len + 1;
> + retpath = malloc(len);
> + if (!retpath)
> + return NULL;
> + *retpath = '\0';
> + strncat(retpath, name, name_len);
> + }
> + return retpath;
> +}
> +
> //
> // btrfs ops
> //
>
> -struct btrfs_ioctl_space_info {
> - unsigned long long flags;
> - unsigned long long total_bytes;
> - unsigned long long used_bytes;
> -};
> +int btrfs_list_get_path_rootid(int fd, u64 *treeid)
> +{
> + int ret;
> + struct btrfs_ioctl_ino_lookup_args args;
>
> -struct btrfs_ioctl_space_args {
> - unsigned long long space_slots;
> - unsigned long long total_spaces;
> - struct btrfs_ioctl_space_info spaces[0];
> -};
> + memset(&args, 0, sizeof(args));
> + args.objectid = BTRFS_FIRST_FREE_OBJECTID;
>
> -#define BTRFS_IOCTL_MAGIC 0x94
> -#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, unsigned long long)
> -#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
> - struct btrfs_ioctl_space_args)
> + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
> + if (ret < 0) {
> + WARN("Warning: can't perform the search -%s\n",
> + strerror(errno));
> + return ret;
> + }
> + *treeid = args.treeid;
> + return 0;
> +}
>
> static bool is_btrfs_fs(const char *path)
> {
> @@ -1270,41 +1327,6 @@ static int btrfs_umount(struct bdev *bdev)
> return umount(bdev->dest);
> }
>
> -#define BTRFS_SUBVOL_NAME_MAX 4039
> -#define BTRFS_PATH_NAME_MAX 4087
> -
> -struct btrfs_ioctl_vol_args {
> - signed long long fd;
> - char name[BTRFS_PATH_NAME_MAX + 1];
> -};
> -
> -#define BTRFS_IOCTL_MAGIC 0x94
> -#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \
> - struct btrfs_ioctl_vol_args_v2)
> -#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
> - struct btrfs_ioctl_vol_args_v2)
> -#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
> - struct btrfs_ioctl_vol_args)
> -#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
> - struct btrfs_ioctl_vol_args)
> -
> -#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0)
> -
> -struct btrfs_ioctl_vol_args_v2 {
> - signed long long fd;
> - unsigned long long transid;
> - unsigned long long flags;
> - union {
> - struct {
> - unsigned long long size;
> - //struct btrfs_qgroup_inherit *qgroup_inherit;
> - void *qgroup_inherit;
> - };
> - unsigned long long unused[4];
> - };
> - char name[BTRFS_SUBVOL_NAME_MAX + 1];
> -};
> -
> static int btrfs_subvolume_create(const char *path)
> {
> int ret, fd = -1;
> @@ -1342,17 +1364,6 @@ static int btrfs_subvolume_create(const char *path)
> return ret;
> }
>
> -#define BTRFS_FSID_SIZE 16
> -struct btrfs_ioctl_fs_info_args {
> - unsigned long long max_id;
> - unsigned long long num_devices;
> - char fsid[BTRFS_FSID_SIZE];
> - unsigned long long reserved[124];
> -};
> -
> -#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
> - struct btrfs_ioctl_fs_info_args)
> -
> static int btrfs_same_fs(const char *orig, const char *new) {
> int fd_orig = -1, fd_new = -1, ret = -1;
> struct btrfs_ioctl_fs_info_args orig_args, new_args;
> @@ -1506,11 +1517,10 @@ static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *old
> return btrfs_subvolume_create(new->dest);
> }
>
> -static int btrfs_destroy(struct bdev *orig)
> +static int btrfs_do_destroy_subvol(const char *path)
> {
> int ret, fd = -1;
> struct btrfs_ioctl_vol_args args;
> - char *path = orig->src;
> char *p, *newfull = strdup(path);
>
> if (!newfull) {
> @@ -1537,7 +1547,7 @@ static int btrfs_destroy(struct bdev *orig)
> strncpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
> args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
> ret = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
> - INFO("btrfs: snapshot destroy ioctl returned %d", ret);
> + INFO("btrfs: snapshot destroy ioctl returned %d for %s", ret, path);
> if (ret < 0 && errno == EPERM)
> INFO("Is the rootfs mounted with -o user_subvol_rm_allowed?");
>
> @@ -1546,6 +1556,291 @@ static int btrfs_destroy(struct bdev *orig)
> return ret;
> }
>
> +struct mytree_node {
> + u64 objid;
> + u64 parentid;
> + char *name;
> + char *dirname;
> +};
> +
> +struct my_btrfs_tree {
> + struct mytree_node *nodes;
> + int num;
> +};
> +
> +static int get_btrfs_tree_idx(struct my_btrfs_tree *tree, u64 id)
> +{
> + int i;
> + if (!tree)
> + return -1;
> + for (i = 0; i < tree->num; i++) {
> + if (tree->nodes[i].objid == id)
> + return i;
> + }
> + return -1;
> +}
> +
> +static struct my_btrfs_tree *create_my_btrfs_tree(u64 id, const char *path, int name_len)
> +{
> + struct my_btrfs_tree *tree;
> +
> + tree = malloc(sizeof(tree));
> + if (!tree)
> + return NULL;
> + tree->nodes = malloc(sizeof(struct mytree_node));
> + if (!tree->nodes) {
> + free(tree);
> + return NULL;
> + }
> + tree->num = 1;
> + tree->nodes[0].dirname = NULL;
> + tree->nodes[0].name = strdup(path);
> + if (!tree->nodes[0].name) {
> + free(tree->nodes);
> + free(tree);
> + return NULL;
> + }
> + tree->nodes[0].parentid = 0;
> + tree->nodes[0].objid = id;
> + return tree;
> +}
> +
> +static bool update_tree_node(struct mytree_node *n, u64 id, u64 parent, char *name,
> + int name_len, char *dirname)
> +{
> + if (id)
> + n->objid = id;
> + if (parent)
> + n->parentid = parent;
> + if (name) {
> + n->name = malloc(name_len + 1);
> + if (!n->name)
> + return false;
> + strncpy(n->name, name, name_len);
> + n->name[name_len] = '\0';
> + }
> + if (dirname) {
> + n->dirname = malloc(strlen(dirname) + 1);
> + if (!n->dirname) {
> + free(n->name);
> + return false;
> + }
> + strcpy(n->dirname, dirname);
> + }
> + return true;
> +}
> +
> +static bool add_btrfs_tree_node(struct my_btrfs_tree *tree, u64 id, u64 parent,
> + char *name, int name_len, char *dirname)
> +{
> + struct mytree_node *tmp;
> +
> + int i = get_btrfs_tree_idx(tree, id);
> + if (i != -1)
> + return update_tree_node(&tree->nodes[i], id, parent, name,
> + name_len, dirname);
> +
> + tmp = realloc(tree->nodes, (tree->num+1) * sizeof(struct mytree_node));
> + if (!tmp)
> + return false;
> + tree->nodes = tmp;
> + memset(&tree->nodes[tree->num], 0, sizeof(struct mytree_node));
> + if (!update_tree_node(&tree->nodes[tree->num], id, parent, name,
> + name_len, dirname))
> + return false;
> + tree->num++;
> + return true;
> +}
> +
> +static void free_btrfs_tree(struct my_btrfs_tree *tree)
> +{
> + int i;
> + if (!tree)
> + return;
> + for (i = 0; i < tree->num; i++) {
> + free(tree->nodes[i].name);
> + free(tree->nodes[i].dirname);
> + }
> + free(tree->nodes);
> + free(tree);
> +}
> +
> +/*
> + * Given a @tree of subvolumes under @path, ask btrfs to remove each
> + * subvolume
> + */
> +static bool do_remove_btrfs_children(struct my_btrfs_tree *tree, u64 root_id,
> + const char *path)
> +{
> + int i;
> + char *newpath;
> + size_t len;
> +
> + for (i = 0; i < tree->num; i++) {
> + if (tree->nodes[i].parentid == root_id) {
> + if (!tree->nodes[i].dirname) {
> + WARN("Odd condition: child objid with no name under %s\n", path);
> + continue;
> + }
> + len = strlen(path) + strlen(tree->nodes[i].dirname) + 2;
> + newpath = malloc(len);
> + if (!newpath) {
> + ERROR("Out of memory");
> + return false;
> + }
> + snprintf(newpath, len, "%s/%s", path, tree->nodes[i].dirname);
> + if (!do_remove_btrfs_children(tree, tree->nodes[i].objid, newpath)) {
> + ERROR("Failed to prune %s\n", tree->nodes[i].name);
> + free(newpath);
> + return false;
> + }
> + if (btrfs_do_destroy_subvol(newpath) != 0) {
> + ERROR("Failed to remove %s\n", newpath);
> + free(newpath);
> + return false;
> + }
> + free(newpath);
> + }
> + }
> + return true;
> +}
> +
> +static int btrfs_recursive_destroy(const char *path)
> +{
> + u64 root_id;
> + int fd;
> + struct btrfs_ioctl_search_args args;
> + struct btrfs_ioctl_search_key *sk = &args.key;
> + struct btrfs_ioctl_search_header *sh;
> + struct btrfs_root_ref *ref;
> + struct my_btrfs_tree *tree;
> + int ret, i;
> + unsigned long off = 0;
> + int name_len;
> + char *name;
> + char *tmppath;
> +
> + fd = open(path, O_RDONLY);
> + if (fd < 0) {
> + ERROR("Failed to open %s\n", path);
> + return -1;
> + }
> +
> + if (btrfs_list_get_path_rootid(fd, &root_id)) {
> + close(fd);
> + if (errno == EPERM || errno == EACCES) {
> + WARN("Will simply try removing");
> + goto ignore_search;
> + }
> +
> + return -1;
> + }
> +
> + tree = create_my_btrfs_tree(root_id, path, strlen(path));
> + if (!tree) {
> + ERROR("Out of memory\n");
> + close(fd);
> + return -1;
> + }
> + /* Walk all subvols looking for any under this id */
> + memset(&args, 0, sizeof(args));
> +
> + /* search in the tree of tree roots */
> + sk->tree_id = 1;
> +
> + sk->max_type = BTRFS_ROOT_REF_KEY;
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_objectid = 0;
> + sk->max_objectid = (u64)-1;
> + sk->max_offset = (u64)-1;
> + sk->min_offset = 0;
> + sk->max_transid = (u64)-1;
> + sk->nr_items = 4096;
> +
> + while(1) {
> + ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
> + if (ret < 0) {
> + close(fd);
> + ERROR("Error: can't perform the search under %s\n", path);
> + free_btrfs_tree(tree);
> + return -1;
> + }
> + if (sk->nr_items == 0)
> + break;
> +
> + off = 0;
> + for (i = 0; i < sk->nr_items; i++) {
> + sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
> + off += sizeof(*sh);
> + /*
> + * A backref key with the name and dirid of the parent
> + * comes followed by the reoot ref key which has the
> + * name of the child subvol in question.
> + */
> + if (sh->objectid != root_id && sh->type == BTRFS_ROOT_BACKREF_KEY) {
> + ref = (struct btrfs_root_ref *)(args.buf + off);
> + name_len = ref->name_len;
> + name = (char *)(ref + 1);
> + tmppath = get_btrfs_subvol_path(fd, sh->offset,
> + ref->dirid, name, name_len);
> + if (!add_btrfs_tree_node(tree, sh->objectid,
> + sh->offset, name,
> + name_len, tmppath)) {
> + ERROR("Out of memory");
> + free_btrfs_tree(tree);
> + free(tmppath);
> + close(fd);
> + return -1;
> + }
> + free(tmppath);
> + }
> + off += sh->len;
> +
> + /*
> + * record the mins in sk so we can make sure the
> + * next search doesn't repeat this root
> + */
> + sk->min_objectid = sh->objectid;
> + sk->min_type = sh->type;
> + sk->min_offset = sh->offset;
> + }
> + sk->nr_items = 4096;
> + sk->min_offset++;
> + if (!sk->min_offset)
> + sk->min_type++;
> + else
> + continue;
> +
> + if (sk->min_type > BTRFS_ROOT_BACKREF_KEY) {
> + sk->min_type = BTRFS_ROOT_ITEM_KEY;
> + sk->min_objectid++;
> + } else
> + continue;
> +
> + if (sk->min_objectid >= sk->max_objectid)
> + break;
> + }
> + close(fd);
> +
> + /* now actually remove them */
> +
> + if (!do_remove_btrfs_children(tree, root_id, path)) {
> + free_btrfs_tree(tree);
> + ERROR("failed pruning\n");
> + return -1;
> + }
> +
> + free_btrfs_tree(tree);
> + /* All child subvols have been removed, now remove this one */
> +ignore_search:
> + return btrfs_do_destroy_subvol(path);
> +}
> +
> +static int btrfs_destroy(struct bdev *orig)
> +{
> + return btrfs_recursive_destroy(orig->src);
> +}
> +
> static int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
> struct bdev_specs *specs)
> {
> diff --git a/src/lxc/lxc-btrfs.h b/src/lxc/lxc-btrfs.h
> new file mode 100644
> index 0000000..035479e
> --- /dev/null
> +++ b/src/lxc/lxc-btrfs.h
> @@ -0,0 +1,287 @@
> +typedef uint8_t u8;
> +typedef uint16_t u16;
> +typedef uint32_t u32;
> +typedef uint64_t u64;
> +
> +struct btrfs_ioctl_space_info {
> + unsigned long long flags;
> + unsigned long long total_bytes;
> + unsigned long long used_bytes;
> +};
> +
> +struct btrfs_ioctl_space_args {
> + unsigned long long space_slots;
> + unsigned long long total_spaces;
> + struct btrfs_ioctl_space_info spaces[0];
> +};
> +
> +#define BTRFS_IOCTL_MAGIC 0x94
> +#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, unsigned long long)
> +#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
> + struct btrfs_ioctl_space_args)
> +
> +#define BTRFS_FSID_SIZE 16
> +struct btrfs_ioctl_fs_info_args {
> + unsigned long long max_id;
> + unsigned long long num_devices;
> + char fsid[BTRFS_FSID_SIZE];
> + unsigned long long reserved[124];
> +};
> +
> +#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
> + struct btrfs_ioctl_fs_info_args)
> +
> +
> +#define BTRFS_SUBVOL_NAME_MAX 4039
> +#define BTRFS_PATH_NAME_MAX 4087
> +
> +struct btrfs_ioctl_vol_args {
> + signed long long fd;
> + char name[BTRFS_PATH_NAME_MAX + 1];
> +};
> +
> +#define BTRFS_IOCTL_MAGIC 0x94
> +#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \
> + struct btrfs_ioctl_vol_args_v2)
> +#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
> + struct btrfs_ioctl_vol_args_v2)
> +#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
> + struct btrfs_ioctl_vol_args)
> +#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
> + struct btrfs_ioctl_vol_args)
> +
> +#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0)
> +
> +struct btrfs_ioctl_vol_args_v2 {
> + signed long long fd;
> + unsigned long long transid;
> + unsigned long long flags;
> + union {
> + struct {
> + unsigned long long size;
> + //struct btrfs_qgroup_inherit *qgroup_inherit;
> + void *qgroup_inherit;
> + };
> + unsigned long long unused[4];
> + };
> + char name[BTRFS_SUBVOL_NAME_MAX + 1];
> +};
> +
> +/*
> + * root backrefs tie subvols and snapshots to the directory entries that
> + * reference them
> + */
> +#define BTRFS_ROOT_BACKREF_KEY 144
> +
> +/*
> + * root items point to tree roots. There are typically in the root
> + * tree used by the super block to find all the other trees
> + */
> +#define BTRFS_ROOT_ITEM_KEY 132
> +
> +/*
> + * root refs make a fast index for listing all of the snapshots and
> + * subvolumes referenced by a given root. They point directly to the
> + * directory item in the root that references the subvol
> + */
> +#define BTRFS_ROOT_REF_KEY 156
> +
> +#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
> +#define BTRFS_DIR_ITEM_KEY 84
> +
> +/*
> + * * this is used for both forward and backward root refs
> + * */
> +struct btrfs_root_ref {
> + __le64 dirid;
> + __le64 sequence;
> + __le16 name_len;
> +} __attribute__ ((__packed__));
> +
> +struct btrfs_disk_key {
> + __le64 objectid;
> + u8 type;
> + __le64 offset;
> +} __attribute__ ((__packed__));
> +
> +struct btrfs_dir_item {
> + struct btrfs_disk_key location;
> + __le64 transid;
> + __le16 data_len;
> + __le16 name_len;
> + u8 type;
> +} __attribute__ ((__packed__));
> +
> +#define BTRFS_IOCTL_MAGIC 0x94
> +#define BTRFS_VOL_NAME_MAX 255
> +#define BTRFS_PATH_NAME_MAX 4087
> +
> +struct btrfs_ioctl_search_key {
> + /* which root are we searching. 0 is the tree of tree roots */
> + __u64 tree_id;
> +
> + /* keys returned will be >= min and <= max */
> + __u64 min_objectid;
> + __u64 max_objectid;
> +
> + /* keys returned will be >= min and <= max */
> + __u64 min_offset;
> + __u64 max_offset;
> +
> + /* max and min transids to search for */
> + __u64 min_transid;
> + __u64 max_transid;
> +
> + /* keys returned will be >= min and <= max */
> + __u32 min_type;
> + __u32 max_type;
> +
> + /*
> + * how many items did userland ask for, and how many are we
> + * returning
> + */
> + __u32 nr_items;
> +
> + /* align to 64 bits */
> + __u32 unused;
> +
> + /* some extra for later */
> + __u64 unused1;
> + __u64 unused2;
> + __u64 unused3;
> + __u64 unused4;
> +};
> +
> +struct btrfs_ioctl_search_header {
> + __u64 transid;
> + __u64 objectid;
> + __u64 offset;
> + __u32 type;
> + __u32 len;
> +} __attribute__((may_alias));
> +
> +#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
> +/*
> + * the buf is an array of search headers where
> + * each header is followed by the actual item
> + * the type field is expanded to 32 bits for alignment
> + */
> +struct btrfs_ioctl_search_args {
> + struct btrfs_ioctl_search_key key;
> + char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
> +};
> +
> +#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
> + struct btrfs_ioctl_search_args)
> +#define BTRFS_UUID_SIZE 16
> +
> +struct btrfs_timespec {
> + __le64 sec;
> + __le32 nsec;
> +} __attribute__ ((__packed__));
> +
> +struct btrfs_inode_item {
> + /* nfs style generation number */
> + __le64 generation;
> + /* transid that last touched this inode */
> + __le64 transid;
> + __le64 size;
> + __le64 nbytes;
> + __le64 block_group;
> + __le32 nlink;
> + __le32 uid;
> + __le32 gid;
> + __le32 mode;
> + __le64 rdev;
> + __le64 flags;
> +
> + /* modification sequence number for NFS */
> + __le64 sequence;
> +
> + /*
> + * a little future expansion, for more than this we can
> + * just grow the inode item and version it
> + */
> + __le64 reserved[4];
> + struct btrfs_timespec atime;
> + struct btrfs_timespec ctime;
> + struct btrfs_timespec mtime;
> + struct btrfs_timespec otime;
> +} __attribute__ ((__packed__));
> +
> +struct btrfs_root_item_v0 {
> + struct btrfs_inode_item inode;
> + __le64 generation;
> + __le64 root_dirid;
> + __le64 bytenr;
> + __le64 byte_limit;
> + __le64 bytes_used;
> + __le64 last_snapshot;
> + __le64 flags;
> + __le32 refs;
> + struct btrfs_disk_key drop_progress;
> + u8 drop_level;
> + u8 level;
> +} __attribute__ ((__packed__));
> +
> +struct btrfs_root_item {
> + struct btrfs_inode_item inode;
> + __le64 generation;
> + __le64 root_dirid;
> + __le64 bytenr;
> + __le64 byte_limit;
> + __le64 bytes_used;
> + __le64 last_snapshot;
> + __le64 flags;
> + __le32 refs;
> + struct btrfs_disk_key drop_progress;
> + u8 drop_level;
> + u8 level;
> +
> + /*
> + * The following fields appear after subvol_uuids+subvol_times
> + * were introduced.
> + */
> +
> + /*
> + * This generation number is used to test if the new fields are valid
> + * and up to date while reading the root item. Everytime the root item
> + * is written out, the "generation" field is copied into this field. If
> + * anyone ever mounted the fs with an older kernel, we will have
> + * mismatching generation values here and thus must invalidate the
> + * new fields. See btrfs_update_root and btrfs_find_last_root for
> + * details.
> + * the offset of generation_v2 is also used as the start for the memset
> + * when invalidating the fields.
> + */
> + __le64 generation_v2;
> + u8 uuid[BTRFS_UUID_SIZE];
> + u8 parent_uuid[BTRFS_UUID_SIZE];
> + u8 received_uuid[BTRFS_UUID_SIZE];
> + __le64 ctransid; /* updated when an inode changes */
> + __le64 otransid; /* trans when created */
> + __le64 stransid; /* trans when sent. non-zero for received subvol */
> + __le64 rtransid; /* trans when received. non-zero for received subvol */
> + struct btrfs_timespec ctime;
> + struct btrfs_timespec otime;
> + struct btrfs_timespec stime;
> + struct btrfs_timespec rtime;
> + __le64 reserved[8]; /* for future */
> +} __attribute__ ((__packed__));
> +
> +#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
> + struct btrfs_ioctl_ino_lookup_args)
> +
> +#define BTRFS_INO_LOOKUP_PATH_MAX 4080
> +struct btrfs_ioctl_ino_lookup_args {
> + __u64 treeid;
> + __u64 objectid;
> + char name[BTRFS_INO_LOOKUP_PATH_MAX];
> +};
> +
> +/*
> + * All files have objectids in this range.
> + */
> +#define BTRFS_FIRST_FREE_OBJECTID 256ULL
> +#define BTRFS_LAST_FREE_OBJECTID -256ULL
> +#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
> --
> 2.0.1
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
--
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140804/d4383018/attachment.sig>
More information about the lxc-devel
mailing list