[PATCH] vfs_btrfs: add qgroup-aware disk free support

Justin Maggard jmaggard10 at gmail.com
Thu Jan 14 02:35:37 UTC 2016


On Wed, Jan 13, 2016 at 4:37 PM, Jeremy Allison <jra at samba.org> wrote:
> On Wed, Jan 13, 2016 at 04:27:48PM -0800, Justin Maggard wrote:
>> Add support for qgroup-aware representation of disk free statistics to
>> vfs_btrfs.  If max_rfer has been defined on the subvolume, use metrics
>> from qgroups to represent disk free.
>>
>> This can be disabled by setting "btrfs:qgroup dfree" to false in smb.conf.
>
> Justin, can you rebase this on top of the dfree/quota changes
> that Uri has made recently (not in the tree yet, but the
> patches are available on the list).
>

I pulled Uri's patchset into my local tree, and this patch still
applies and everything still builds without errors.  Or was that not
the point? :-)

-Justin

> Cheers,
>
>         Jeremy.
>
>> Signed-off-by: Justin Maggard <jmaggard at netgear.com>
>> ---
>>  source3/modules/vfs_btrfs.c | 170 ++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 170 insertions(+)
>>
>> diff --git a/source3/modules/vfs_btrfs.c b/source3/modules/vfs_btrfs.c
>> index bd95637..435f08f 100644
>> --- a/source3/modules/vfs_btrfs.c
>> +++ b/source3/modules/vfs_btrfs.c
>> @@ -50,7 +50,13 @@ static uint32_t btrfs_fs_capabilities(struct vfs_handle_struct *handle,
>>
>>  #define BTRFS_SUBVOL_RDONLY          (1ULL << 1)
>>  #define BTRFS_SUBVOL_NAME_MAX                4039
>> +#define BTRFS_INO_LOOKUP_PATH_MAX    4080
>>  #define BTRFS_PATH_NAME_MAX          4087
>> +#define BTRFS_FIRST_FREE_OBJECTID    256ULL
>> +#define BTRFS_QUOTA_TREE_OBJECTID    8ULL
>> +#define BTRFS_QGROUP_INFO_KEY                242
>> +#define BTRFS_QGROUP_LIMIT_KEY               244
>> +#define BTRFS_SEARCH_ARGS_BUFSIZE    (4096 - sizeof(struct btrfs_ioctl_search_key))
>>  struct btrfs_ioctl_vol_args_v2 {
>>       int64_t fd;
>>       uint64_t transid;
>> @@ -70,11 +76,65 @@ struct btrfs_ioctl_clone_range_args {
>>       uint64_t dest_offset;
>>  };
>>
>> +struct btrfs_ioctl_search_key {
>> +     uint64_t tree_id;
>> +     uint64_t min_objectid;
>> +     uint64_t max_objectid;
>> +     uint64_t min_offset;
>> +     uint64_t max_offset;
>> +     uint64_t min_transid;
>> +     uint64_t max_transid;
>> +     uint32_t min_type;
>> +     uint32_t max_type;
>> +     uint32_t nr_items;
>> +     uint32_t unused;
>> +     uint64_t unused1[4];
>> +};
>> +
>> +struct btrfs_ioctl_search_header {
>> +     uint64_t transid;
>> +     uint64_t objectid;
>> +     uint64_t offset;
>> +     uint32_t type;
>> +     uint32_t len;
>> +} __attribute__((may_alias));
>> +
>> +struct btrfs_ioctl_search_args {
>> +     struct btrfs_ioctl_search_key key;
>> +     char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
>> +};
>> +
>> +struct btrfs_ioctl_ino_lookup_args {
>> +     uint64_t treeid;
>> +     uint64_t objectid;
>> +     char name[BTRFS_INO_LOOKUP_PATH_MAX];
>> +};
>> +
>> +struct btrfs_qgroup_info_item {
>> +     uint64_t generation;
>> +     uint64_t referenced;
>> +     uint64_t referenced_compressed;
>> +     uint64_t exclusive;
>> +     uint64_t exclusive_compressed;
>> +} __attribute__ ((__packed__, may_alias));
>> +
>> +struct btrfs_qgroup_limit_item {
>> +     uint64_t flags;
>> +     uint64_t max_referenced;
>> +     uint64_t max_exclusive;
>> +     uint64_t rsv_referenced;
>> +     uint64_t rsv_exclusive;
>> +} __attribute__ ((__packed__, may_alias));
>> +
>>  #define BTRFS_IOCTL_MAGIC 0x94
>>  #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \
>>                                  struct btrfs_ioctl_clone_range_args)
>>  #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
>>                                   struct btrfs_ioctl_vol_args)
>> +#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
>> +                                 struct btrfs_ioctl_search_args)
>> +#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
>> +                                struct btrfs_ioctl_ino_lookup_args)
>>  #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
>>                                     struct btrfs_ioctl_vol_args_v2)
>>
>> @@ -665,6 +725,115 @@ static NTSTATUS btrfs_snap_delete(struct vfs_handle_struct *handle,
>>       return NT_STATUS_OK;
>>  }
>>
>> +static uint64_t btrfs_get_path_rootid(int fd)
>> +{
>> +     int ret;
>> +     struct btrfs_ioctl_ino_lookup_args args;
>> +
>> +     memset(&args, 0, sizeof(args));
>> +     args.objectid = BTRFS_FIRST_FREE_OBJECTID;
>> +
>> +     ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
>> +     if (ret < 0) {
>> +             return (uint64_t)ret;
>> +     }
>> +     return args.treeid;
>> +}
>> +
>> +static int qgroup_search(int fd, uint64_t *used, uint64_t *quota, uint64_t qgroupid)
>> +{
>> +     struct btrfs_ioctl_search_args args;
>> +     struct btrfs_ioctl_search_key *sk = &args.key;
>> +     struct btrfs_ioctl_search_header *sh;
>> +     struct btrfs_qgroup_info_item *info;
>> +     struct btrfs_qgroup_limit_item *limit;
>> +     unsigned long off = 0;
>> +     unsigned int i;
>> +     int ret;
>> +
>> +     memset(&args, 0, sizeof(args));
>> +     sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
>> +     sk->min_type = BTRFS_QGROUP_INFO_KEY;
>> +     sk->max_type = BTRFS_QGROUP_LIMIT_KEY;
>> +     sk->max_objectid = (uint64_t)-1;
>> +     sk->max_offset = (uint64_t)-1;
>> +     sk->max_transid = (uint64_t)-1;
>> +     sk->nr_items = 4096;
>> +
>> +     while (true) {
>> +             ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
>> +             if (ret < 0) {
>> +                     return ret;
>> +             }
>> +             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);
>> +
>> +                     if (sh->type == BTRFS_QGROUP_INFO_KEY) {
>> +                             info = (struct btrfs_qgroup_info_item *)
>> +                                    (args.buf + off);
>> +                             if (sh->offset == qgroupid) {
>> +                                     *used = BVAL(&info->referenced, 0);
>> +                             }
>> +                     } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
>> +                             limit = (struct btrfs_qgroup_limit_item *)
>> +                                 (args.buf + off);
>> +                             if (sh->offset == qgroupid) {
>> +                                     *quota = BVAL(&limit->max_referenced, 0);
>> +                             }
>> +                     } else {
>> +                             return 0;
>> +                     }
>> +
>> +                     off += sh->len;
>> +                     sk->min_type = sh->type;
>> +                     sk->min_offset = sh->offset;
>> +                     sk->min_objectid = sh->objectid;
>> +             }
>> +             sk->nr_items = 4096;
>> +             if (sk->min_offset < (uint64_t)-1) {
>> +                     sk->min_offset++;
>> +             } else {
>> +                     break;
>> +             }
>> +     }
>> +     return 0;
>> +}
>> +
>> +static uint64_t btrfs_disk_free(vfs_handle_struct *handle,
>> +                             const char *path, uint64_t *bsize,
>> +                             uint64_t *dfree, uint64_t *dsize)
>> +{
>> +     int ret = -1, fd;
>> +     uint64_t used = UINT64_MAX, quota = 0, id;
>> +
>> +     if (lp_parm_bool(-1, "btrfs", "qgroup dfree", true)) {
>> +             become_root();
>> +             if ((fd = open(path, 0)) >= 0) {
>> +                     id = btrfs_get_path_rootid(fd);
>> +                     if (id != (uint64_t)-1) {
>> +                             ret = qgroup_search(fd, &used, &quota, id);
>> +                     }
>> +                     close(fd);
>> +             }
>> +             unbecome_root();
>> +     }
>> +     if (ret || used == UINT64_MAX || !quota) {
>> +             return SMB_VFS_NEXT_DISK_FREE(handle, path,
>> +                                           bsize, dfree, dsize);
>> +     }
>> +     *bsize = 4096;
>> +     *dfree = (quota - used)/4096;
>> +     *dsize = quota/4096;
>> +     return (quota - used)/1024;
>> +}
>> +
>> +
>>  static struct vfs_fn_pointers btrfs_fns = {
>>       .fs_capabilities_fn = btrfs_fs_capabilities,
>>       .copy_chunk_send_fn = btrfs_copy_chunk_send,
>> @@ -674,6 +843,7 @@ static struct vfs_fn_pointers btrfs_fns = {
>>       .snap_check_path_fn = btrfs_snap_check_path,
>>       .snap_create_fn = btrfs_snap_create,
>>       .snap_delete_fn = btrfs_snap_delete,
>> +     .disk_free_fn = btrfs_disk_free,
>>  };
>>
>>  NTSTATUS vfs_btrfs_init(void);
>> --
>> 2.7.0
>>
>>



More information about the samba-technical mailing list