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

Jeremy Allison jra at samba.org
Thu Jan 14 00:37:59 UTC 2016


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).

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