diff mbox series

btrfs-progs: subvolume: destroy associated qgroup when delete subvolume

Message ID 20210515023624.8065-1-realwakka@gmail.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: subvolume: destroy associated qgroup when delete subvolume | expand

Commit Message

Sidong Yang May 15, 2021, 2:36 a.m. UTC
This patch adds the options --delete-qgroup and --no-delete-qgroup. When
the option is enabled, delete subvolume command destroies associated
qgroup together. This patch make it as default option. Even though quota
is disabled, it enables quota temporary and restore it after.

Signed-off-by: Sidong Yang <realwakka@gmail.com>
---

I wrote a patch that adds command to delete associated qgroup when
delete subvolume together. It also works when quota disabled. How it
works is enable quota temporary and restore it. I don't know it's good
way. Is there any better way than this?

 cmds/subvolume.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

Comments

Qu Wenruo May 15, 2021, 2:42 a.m. UTC | #1
On 2021/5/15 上午10:36, Sidong Yang wrote:
> This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> the option is enabled, delete subvolume command destroies associated
> qgroup together. This patch make it as default option. Even though quota
> is disabled, it enables quota temporary and restore it after.

No, this is not a good idea at all.

First thing first, if quota is disabled, all qgroup info including the
level 0 qgroups will also be deleted, thus no need to enable in the
first place.

Secondly, there is already a patch in the past to delete level 0 qgroups
in kernel space, which should be a much better solution.

I didn't remember when, but I'm pretty sure I did send out such patch in
the past.

Maybe it's time to revive the patch now.

Thanks,
Qu

>
> Signed-off-by: Sidong Yang <realwakka@gmail.com>
> ---
>
> I wrote a patch that adds command to delete associated qgroup when
> delete subvolume together. It also works when quota disabled. How it
> works is enable quota temporary and restore it. I don't know it's good
> way. Is there any better way than this?
>
>   cmds/subvolume.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 51 insertions(+)
>
> diff --git a/cmds/subvolume.c b/cmds/subvolume.c
> index 9bd17808..18c75083 100644
> --- a/cmds/subvolume.c
> +++ b/cmds/subvolume.c
> @@ -239,6 +239,8 @@ static const char * const cmd_subvol_delete_usage[] = {
>   	"-c|--commit-after      wait for transaction commit at the end of the operation",
>   	"-C|--commit-each       wait for transaction commit after deleting each subvolume",
>   	"-i|--subvolid          subvolume id of the to be removed subvolume",
> +	"--delete-qgroup        delete associated qgroup together",
> +	"--no-delete-qgroup     don't delete associated qgroup",
>   	"-v|--verbose           deprecated, alias for global -v option",
>   	HELPINFO_INSERT_GLOBALS,
>   	HELPINFO_INSERT_VERBOSE,
> @@ -266,14 +268,18 @@ static int cmd_subvol_delete(const struct cmd_struct *cmd,
>   	enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
>   	enum btrfs_util_error err;
>   	uint64_t default_subvol_id = 0, target_subvol_id = 0;
> +	bool delete_qgroup = false;
>
>   	optind = 0;
>   	while (1) {
>   		int c;
> +		enum { GETOPT_VAL_DEL_QGROUP = 256, GETOPT_VAL_NO_DEL_QGROUP };
>   		static const struct option long_options[] = {
>   			{"commit-after", no_argument, NULL, 'c'},
>   			{"commit-each", no_argument, NULL, 'C'},
>   			{"subvolid", required_argument, NULL, 'i'},
> +			{"delete-qgroup", no_argument, NULL, GETOPT_VAL_DEL_QGROUP},
> +			{"no-delete-qgroup", no_argument, NULL, GETOPT_VAL_NO_DEL_QGROUP},
>   			{"verbose", no_argument, NULL, 'v'},
>   			{NULL, 0, NULL, 0}
>   		};
> @@ -295,6 +301,12 @@ static int cmd_subvol_delete(const struct cmd_struct *cmd,
>   		case 'v':
>   			bconf_be_verbose();
>   			break;
> +		case GETOPT_VAL_DEL_QGROUP:
> +			delete_qgroup = true;
> +			break;
> +		case GETOPT_VAL_NO_DEL_QGROUP:
> +			delete_qgroup = false;
> +			break;
>   		default:
>   			usage_unknown_option(cmd, argv);
>   		}
> @@ -388,6 +400,44 @@ again:
>   		goto out;
>   	}
>
> +	if (delete_qgroup) {
> +		struct btrfs_ioctl_qgroup_create_args args;
> +		memset(&args, 0, sizeof(args));
> +		args.create = 0;
> +		args.qgroupid = target_subvol_id;
> +
> +		if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
> +			if (errno == ENOTCONN) {
> +				struct btrfs_ioctl_quota_ctl_args quota_ctl_args;
> +				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_ENABLE;
> +				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &quota_ctl_args) < 0) {
> +					error("unable to enable quota: %s",
> +						  strerror(errno));
> +					goto out;
> +				}
> +
> +				if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
> +					quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
> +					ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args);
> +					error("unable to destroy quota group: %s",
> +						  strerror(errno));
> +					goto out;
> +				}
> +
> +				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
> +				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0) {
> +					error("unable to disable quota: %s",
> +						  strerror(errno));
> +					goto out;
> +				}
> +			} else {
> +				error("unable to destroy quota group: %s",
> +					  strerror(errno));
> +				goto out;
> +			}
> +		}
> +	}
> +
>   	pr_verbose(MUST_LOG, "Delete subvolume (%s): ",
>   		commit_mode == COMMIT_EACH ||
>   		(commit_mode == COMMIT_AFTER && cnt + 1 == argc) ?
> @@ -412,6 +462,7 @@ again:
>   		goto out;
>   	}
>
> +
>   	if (commit_mode == COMMIT_EACH) {
>   		res = wait_for_commit(fd);
>   		if (res < 0) {
>
Sidong Yang May 15, 2021, 5:30 a.m. UTC | #2
On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
> 
> 
> On 2021/5/15 上午10:36, Sidong Yang wrote:
> > This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> > the option is enabled, delete subvolume command destroies associated
> > qgroup together. This patch make it as default option. Even though quota
> > is disabled, it enables quota temporary and restore it after.
> 

Thanks for reply!

> No, this is not a good idea at all.
> 
> First thing first, if quota is disabled, all qgroup info including the
> level 0 qgroups will also be deleted, thus no need to enable in the
> first place.
> 
> Secondly, there is already a patch in the past to delete level 0 qgroups
> in kernel space, which should be a much better solution.

Good, I think there is no need to make changes for userspace.

Thanks,
Sidong
> 
> I didn't remember when, but I'm pretty sure I did send out such patch in
> the past.
> 
> Maybe it's time to revive the patch now.
> 
> Thanks,
> Qu
> 
> > 
> > Signed-off-by: Sidong Yang <realwakka@gmail.com>
> > ---
> > 
> > I wrote a patch that adds command to delete associated qgroup when
> > delete subvolume together. It also works when quota disabled. How it
> > works is enable quota temporary and restore it. I don't know it's good
> > way. Is there any better way than this?
> > 
> >   cmds/subvolume.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 51 insertions(+)
> > 
> > diff --git a/cmds/subvolume.c b/cmds/subvolume.c
> > index 9bd17808..18c75083 100644
> > --- a/cmds/subvolume.c
> > +++ b/cmds/subvolume.c
> > @@ -239,6 +239,8 @@ static const char * const cmd_subvol_delete_usage[] = {
> >   	"-c|--commit-after      wait for transaction commit at the end of the operation",
> >   	"-C|--commit-each       wait for transaction commit after deleting each subvolume",
> >   	"-i|--subvolid          subvolume id of the to be removed subvolume",
> > +	"--delete-qgroup        delete associated qgroup together",
> > +	"--no-delete-qgroup     don't delete associated qgroup",
> >   	"-v|--verbose           deprecated, alias for global -v option",
> >   	HELPINFO_INSERT_GLOBALS,
> >   	HELPINFO_INSERT_VERBOSE,
> > @@ -266,14 +268,18 @@ static int cmd_subvol_delete(const struct cmd_struct *cmd,
> >   	enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
> >   	enum btrfs_util_error err;
> >   	uint64_t default_subvol_id = 0, target_subvol_id = 0;
> > +	bool delete_qgroup = false;
> > 
> >   	optind = 0;
> >   	while (1) {
> >   		int c;
> > +		enum { GETOPT_VAL_DEL_QGROUP = 256, GETOPT_VAL_NO_DEL_QGROUP };
> >   		static const struct option long_options[] = {
> >   			{"commit-after", no_argument, NULL, 'c'},
> >   			{"commit-each", no_argument, NULL, 'C'},
> >   			{"subvolid", required_argument, NULL, 'i'},
> > +			{"delete-qgroup", no_argument, NULL, GETOPT_VAL_DEL_QGROUP},
> > +			{"no-delete-qgroup", no_argument, NULL, GETOPT_VAL_NO_DEL_QGROUP},
> >   			{"verbose", no_argument, NULL, 'v'},
> >   			{NULL, 0, NULL, 0}
> >   		};
> > @@ -295,6 +301,12 @@ static int cmd_subvol_delete(const struct cmd_struct *cmd,
> >   		case 'v':
> >   			bconf_be_verbose();
> >   			break;
> > +		case GETOPT_VAL_DEL_QGROUP:
> > +			delete_qgroup = true;
> > +			break;
> > +		case GETOPT_VAL_NO_DEL_QGROUP:
> > +			delete_qgroup = false;
> > +			break;
> >   		default:
> >   			usage_unknown_option(cmd, argv);
> >   		}
> > @@ -388,6 +400,44 @@ again:
> >   		goto out;
> >   	}
> > 
> > +	if (delete_qgroup) {
> > +		struct btrfs_ioctl_qgroup_create_args args;
> > +		memset(&args, 0, sizeof(args));
> > +		args.create = 0;
> > +		args.qgroupid = target_subvol_id;
> > +
> > +		if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
> > +			if (errno == ENOTCONN) {
> > +				struct btrfs_ioctl_quota_ctl_args quota_ctl_args;
> > +				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_ENABLE;
> > +				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &quota_ctl_args) < 0) {
> > +					error("unable to enable quota: %s",
> > +						  strerror(errno));
> > +					goto out;
> > +				}
> > +
> > +				if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
> > +					quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
> > +					ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args);
> > +					error("unable to destroy quota group: %s",
> > +						  strerror(errno));
> > +					goto out;
> > +				}
> > +
> > +				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
> > +				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0) {
> > +					error("unable to disable quota: %s",
> > +						  strerror(errno));
> > +					goto out;
> > +				}
> > +			} else {
> > +				error("unable to destroy quota group: %s",
> > +					  strerror(errno));
> > +				goto out;
> > +			}
> > +		}
> > +	}
> > +
> >   	pr_verbose(MUST_LOG, "Delete subvolume (%s): ",
> >   		commit_mode == COMMIT_EACH ||
> >   		(commit_mode == COMMIT_AFTER && cnt + 1 == argc) ?
> > @@ -412,6 +462,7 @@ again:
> >   		goto out;
> >   	}
> > 
> > +
> >   	if (commit_mode == COMMIT_EACH) {
> >   		res = wait_for_commit(fd);
> >   		if (res < 0) {
> >
David Sterba May 15, 2021, 1:35 p.m. UTC | #3
On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
> On 2021/5/15 上午10:36, Sidong Yang wrote:
> > This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> > the option is enabled, delete subvolume command destroies associated
> > qgroup together. This patch make it as default option. Even though quota
> > is disabled, it enables quota temporary and restore it after.
> 
> No, this is not a good idea at all.
> 
> First thing first, if quota is disabled, all qgroup info including the
> level 0 qgroups will also be deleted, thus no need to enable in the
> first place.
> 
> Secondly, there is already a patch in the past to delete level 0 qgroups
> in kernel space, which should be a much better solution.

I've filed the issue to do it in the userspace because it gives user
more control whether to do the deletion or not and to also cover all
kernels that won't get the patch (ie. old stable kernels).

Changing the default behaviour is always risky and has a potential to
break user scripts. IMO adding the option to progs and changing the
default there is safer in this case.
David Sterba May 15, 2021, 1:38 p.m. UTC | #4
On Sat, May 15, 2021 at 02:36:24AM +0000, Sidong Yang wrote:
> This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> the option is enabled, delete subvolume command destroies associated
> qgroup together. This patch make it as default option. Even though quota
> is disabled, it enables quota temporary and restore it after.
> 
> Signed-off-by: Sidong Yang <realwakka@gmail.com>
> ---
> 
> I wrote a patch that adds command to delete associated qgroup when
> delete subvolume together. It also works when quota disabled. How it
> works is enable quota temporary and restore it. I don't know it's good
> way. Is there any better way than this?

As Qu pointed out, nothing needs to be done in case quotas are not
enabled.

> +		if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
> +			if (errno == ENOTCONN) {

Which turns this into
			if (errno !=  ENOTCONN
				error("...");

> +				struct btrfs_ioctl_quota_ctl_args quota_ctl_args;
> +				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_ENABLE;
> +				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &quota_ctl_args) < 0) {
> +					error("unable to enable quota: %s",
> +						  strerror(errno));
> +					goto out;
> +				}
> +
> +				if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
> +					quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
> +					ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args);
> +					error("unable to destroy quota group: %s",
> +						  strerror(errno));
> +					goto out;
> +				}
> +
> +				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
> +				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0) {
> +					error("unable to disable quota: %s",
> +						  strerror(errno));
> +					goto out;
> +				}
> +			} else {
> +				error("unable to destroy quota group: %s",
> +					  strerror(errno));

strerror(errno) should be replaced by %m in the format string

> +				goto out;
> +			}
> +		}
> +	}
> +
>  	pr_verbose(MUST_LOG, "Delete subvolume (%s): ",
>  		commit_mode == COMMIT_EACH ||
>  		(commit_mode == COMMIT_AFTER && cnt + 1 == argc) ?
> @@ -412,6 +462,7 @@ again:
>  		goto out;
>  	}
>  
> +

Extra newline

>  	if (commit_mode == COMMIT_EACH) {
>  		res = wait_for_commit(fd);
>  		if (res < 0) {
> -- 
> 2.25.1
Qu Wenruo May 15, 2021, 11:55 p.m. UTC | #5
On 2021/5/15 下午9:35, David Sterba wrote:
> On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
>> On 2021/5/15 上午10:36, Sidong Yang wrote:
>>> This patch adds the options --delete-qgroup and --no-delete-qgroup. When
>>> the option is enabled, delete subvolume command destroies associated
>>> qgroup together. This patch make it as default option. Even though quota
>>> is disabled, it enables quota temporary and restore it after.
>>
>> No, this is not a good idea at all.
>>
>> First thing first, if quota is disabled, all qgroup info including the
>> level 0 qgroups will also be deleted, thus no need to enable in the
>> first place.
>>
>> Secondly, there is already a patch in the past to delete level 0 qgroups
>> in kernel space, which should be a much better solution.
>
> I've filed the issue to do it in the userspace because it gives user
> more control whether to do the deletion or not and to also cover all
> kernels that won't get the patch (ie. old stable kernels).
>
> Changing the default behaviour is always risky and has a potential to
> break user scripts. IMO adding the option to progs and changing the
> default there is safer in this case.
>
Then shouldn't it still go through ioctl options?

Doing it completely in user space doesn't seem correct to me.

Thanks,
Qu
Sidong Yang May 18, 2021, 4:06 p.m. UTC | #6
On Sun, May 16, 2021 at 07:55:25AM +0800, Qu Wenruo wrote:
> 
> 
> On 2021/5/15 下午9:35, David Sterba wrote:
> > On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
> > > On 2021/5/15 上午10:36, Sidong Yang wrote:
> > > > This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> > > > the option is enabled, delete subvolume command destroies associated
> > > > qgroup together. This patch make it as default option. Even though quota
> > > > is disabled, it enables quota temporary and restore it after.
> > > 
> > > No, this is not a good idea at all.
> > > 
> > > First thing first, if quota is disabled, all qgroup info including the
> > > level 0 qgroups will also be deleted, thus no need to enable in the
> > > first place.
> > > 
> > > Secondly, there is already a patch in the past to delete level 0 qgroups
> > > in kernel space, which should be a much better solution.
> > 
> > I've filed the issue to do it in the userspace because it gives user
> > more control whether to do the deletion or not and to also cover all
> > kernels that won't get the patch (ie. old stable kernels).
> > 
> > Changing the default behaviour is always risky and has a potential to
> > break user scripts. IMO adding the option to progs and changing the
> > default there is safer in this case.
> > 
> Then shouldn't it still go through ioctl options?
> 
> Doing it completely in user space doesn't seem correct to me.

Yes, It still use ioctl calls for destroying qgroup.
I think this code has pros and cons.
IMHO, as david said, It also has some benefits when doing it in userspace for
old kernel versions. and give a chance to change softly their codes
which use btrfs-progs with options. 

But when kernel supports this operation, maybe this code will always failed.
because the qgroup was already destroyed with it's subvolume in kernel.
and the code will be meaningless.

So in long run, I think it's better way to doing this in kernel. 

> 
> Thanks,
> Qu
Qu Wenruo May 19, 2021, 12:09 a.m. UTC | #7
On 2021/5/19 上午12:06, Sidong Yang wrote:
> On Sun, May 16, 2021 at 07:55:25AM +0800, Qu Wenruo wrote:
>>
>>
>> On 2021/5/15 下午9:35, David Sterba wrote:
>>> On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
>>>> On 2021/5/15 上午10:36, Sidong Yang wrote:
>>>>> This patch adds the options --delete-qgroup and --no-delete-qgroup. When
>>>>> the option is enabled, delete subvolume command destroies associated
>>>>> qgroup together. This patch make it as default option. Even though quota
>>>>> is disabled, it enables quota temporary and restore it after.
>>>>
>>>> No, this is not a good idea at all.
>>>>
>>>> First thing first, if quota is disabled, all qgroup info including the
>>>> level 0 qgroups will also be deleted, thus no need to enable in the
>>>> first place.
>>>>
>>>> Secondly, there is already a patch in the past to delete level 0 qgroups
>>>> in kernel space, which should be a much better solution.
>>>
>>> I've filed the issue to do it in the userspace because it gives user
>>> more control whether to do the deletion or not and to also cover all
>>> kernels that won't get the patch (ie. old stable kernels).
>>>
>>> Changing the default behaviour is always risky and has a potential to
>>> break user scripts. IMO adding the option to progs and changing the
>>> default there is safer in this case.
>>>
>> Then shouldn't it still go through ioctl options?
>>
>> Doing it completely in user space doesn't seem correct to me.
>
> Yes, It still use ioctl calls for destroying qgroup.

What I mean is to add new ioctl flags for the existing destory subvolume.

By that newer btrfs-progs can try to delete using the new flags,
If fails, go back to regular subovlume delete (without deleting qgroup)
and gives user a warning.

This still allows user to determine whether to delete qgroup along the
ioctl, and still keeps compatibility.

THanks,
Qu
> I think this code has pros and cons.
> IMHO, as david said, It also has some benefits when doing it in userspace for
> old kernel versions. and give a chance to change softly their codes
> which use btrfs-progs with options.
>
> But when kernel supports this operation, maybe this code will always failed.
> because the qgroup was already destroyed with it's subvolume in kernel.
> and the code will be meaningless.
>
> So in long run, I think it's better way to doing this in kernel.
>
>>
>> Thanks,
>> Qu
Qu Wenruo May 19, 2021, 12:56 a.m. UTC | #8
On 2021/5/19 上午8:09, Qu Wenruo wrote:
>
>
> On 2021/5/19 上午12:06, Sidong Yang wrote:
>> On Sun, May 16, 2021 at 07:55:25AM +0800, Qu Wenruo wrote:
>>>
>>>
>>> On 2021/5/15 下午9:35, David Sterba wrote:
>>>> On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
>>>>> On 2021/5/15 上午10:36, Sidong Yang wrote:
>>>>>> This patch adds the options --delete-qgroup and
>>>>>> --no-delete-qgroup. When
>>>>>> the option is enabled, delete subvolume command destroies associated
>>>>>> qgroup together. This patch make it as default option. Even though
>>>>>> quota
>>>>>> is disabled, it enables quota temporary and restore it after.
>>>>>
>>>>> No, this is not a good idea at all.
>>>>>
>>>>> First thing first, if quota is disabled, all qgroup info including the
>>>>> level 0 qgroups will also be deleted, thus no need to enable in the
>>>>> first place.
>>>>>
>>>>> Secondly, there is already a patch in the past to delete level 0
>>>>> qgroups
>>>>> in kernel space, which should be a much better solution.
>>>>
>>>> I've filed the issue to do it in the userspace because it gives user
>>>> more control whether to do the deletion or not and to also cover all
>>>> kernels that won't get the patch (ie. old stable kernels).
>>>>
>>>> Changing the default behaviour is always risky and has a potential to
>>>> break user scripts. IMO adding the option to progs and changing the
>>>> default there is safer in this case.
>>>>
>>> Then shouldn't it still go through ioctl options?
>>>
>>> Doing it completely in user space doesn't seem correct to me.
>>
>> Yes, It still use ioctl calls for destroying qgroup.
>
> What I mean is to add new ioctl flags for the existing destory subvolume.
>
> By that newer btrfs-progs can try to delete using the new flags,
> If fails, go back to regular subovlume delete (without deleting qgroup)
> and gives user a warning.
>
> This still allows user to determine whether to delete qgroup along the
> ioctl, and still keeps compatibility.

One more thing to add is, the qgroup delete should only happen when the
qgroup numbers get cleared to 0.

This is not completely impossible to be done in user space, but very
complex, needs extra ioctl to wait for the subvolume deletion.

Or we can hit a case where subvolume is still under deletion, but its
qgroup is already removed.
This can screw up the qgroup exclusive accounting.

Thus I still prefer to do the deletion in kernel side, where we have
pretty convenient timing to delete the qgroup, just after the subovlume
deletion is done.

Thanks,
Qu
>
> THanks,
> Qu
>> I think this code has pros and cons.
>> IMHO, as david said, It also has some benefits when doing it in
>> userspace for
>> old kernel versions. and give a chance to change softly their codes
>> which use btrfs-progs with options.
>>
>> But when kernel supports this operation, maybe this code will always
>> failed.
>> because the qgroup was already destroyed with it's subvolume in kernel.
>> and the code will be meaningless.
>>
>> So in long run, I think it's better way to doing this in kernel.
>>
>>>
>>> Thanks,
>>> Qu
David Sterba June 11, 2021, 2:23 p.m. UTC | #9
On Wed, May 19, 2021 at 08:09:45AM +0800, Qu Wenruo wrote:
> 
> 
> On 2021/5/19 上午12:06, Sidong Yang wrote:
> > On Sun, May 16, 2021 at 07:55:25AM +0800, Qu Wenruo wrote:
> >>
> >>
> >> On 2021/5/15 下午9:35, David Sterba wrote:
> >>> On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
> >>>> On 2021/5/15 上午10:36, Sidong Yang wrote:
> >>>>> This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> >>>>> the option is enabled, delete subvolume command destroies associated
> >>>>> qgroup together. This patch make it as default option. Even though quota
> >>>>> is disabled, it enables quota temporary and restore it after.
> >>>>
> >>>> No, this is not a good idea at all.
> >>>>
> >>>> First thing first, if quota is disabled, all qgroup info including the
> >>>> level 0 qgroups will also be deleted, thus no need to enable in the
> >>>> first place.
> >>>>
> >>>> Secondly, there is already a patch in the past to delete level 0 qgroups
> >>>> in kernel space, which should be a much better solution.
> >>>
> >>> I've filed the issue to do it in the userspace because it gives user
> >>> more control whether to do the deletion or not and to also cover all
> >>> kernels that won't get the patch (ie. old stable kernels).
> >>>
> >>> Changing the default behaviour is always risky and has a potential to
> >>> break user scripts. IMO adding the option to progs and changing the
> >>> default there is safer in this case.
> >>>
> >> Then shouldn't it still go through ioctl options?
> >>
> >> Doing it completely in user space doesn't seem correct to me.
> >
> > Yes, It still use ioctl calls for destroying qgroup.
> 
> What I mean is to add new ioctl flags for the existing destory subvolume.

Which is what I don't want to do. Why: it's doing more than operation so
the error code is unclear what it's related to. Either subvolume
deletion or qgroup deletion.

A similar suggestion was in for subvolume creation to force quota rescan,
https://lore.kernel.org/linux-btrfs/20210525162054.GE7604@twin.jikos.cz/333
same reason why not.
Sidong Yang June 11, 2021, 5:18 p.m. UTC | #10
On Fri, Jun 11, 2021 at 04:23:29PM +0200, David Sterba wrote:
> On Wed, May 19, 2021 at 08:09:45AM +0800, Qu Wenruo wrote:
> > 
> > 
> > On 2021/5/19 上午12:06, Sidong Yang wrote:
> > > On Sun, May 16, 2021 at 07:55:25AM +0800, Qu Wenruo wrote:
> > >>
> > >>
> > >> On 2021/5/15 下午9:35, David Sterba wrote:
> > >>> On Sat, May 15, 2021 at 10:42:15AM +0800, Qu Wenruo wrote:
> > >>>> On 2021/5/15 上午10:36, Sidong Yang wrote:
> > >>>>> This patch adds the options --delete-qgroup and --no-delete-qgroup. When
> > >>>>> the option is enabled, delete subvolume command destroies associated
> > >>>>> qgroup together. This patch make it as default option. Even though quota
> > >>>>> is disabled, it enables quota temporary and restore it after.
> > >>>>
> > >>>> No, this is not a good idea at all.
> > >>>>
> > >>>> First thing first, if quota is disabled, all qgroup info including the
> > >>>> level 0 qgroups will also be deleted, thus no need to enable in the
> > >>>> first place.
> > >>>>
> > >>>> Secondly, there is already a patch in the past to delete level 0 qgroups
> > >>>> in kernel space, which should be a much better solution.
> > >>>
> > >>> I've filed the issue to do it in the userspace because it gives user
> > >>> more control whether to do the deletion or not and to also cover all
> > >>> kernels that won't get the patch (ie. old stable kernels).
> > >>>
> > >>> Changing the default behaviour is always risky and has a potential to
> > >>> break user scripts. IMO adding the option to progs and changing the
> > >>> default there is safer in this case.
> > >>>
> > >> Then shouldn't it still go through ioctl options?
> > >>
> > >> Doing it completely in user space doesn't seem correct to me.
> > >
> > > Yes, It still use ioctl calls for destroying qgroup.
> > 
> > What I mean is to add new ioctl flags for the existing destory subvolume.
> 
> Which is what I don't want to do. Why: it's doing more than operation so
> the error code is unclear what it's related to. Either subvolume
> deletion or qgroup deletion.

IMO, If new ioctl will be added for this problem, maybe it operates that
delete subvolume and it's qgroup. I think it makes some problem. If it
fails only deleting qgroup but subvolume, it needs to return the error
that describes it. It is also duplicated with old ioctl that destroy
subvolume only.

I think the point is how to support additional operation that usually
executed with. If the solution is adding a new ioctl includes old ioctl,
there will be too many ioctls and it's hard to manage it.

> 
> A similar suggestion was in for subvolume creation to force quota rescan,
> https://lore.kernel.org/linux-btrfs/20210525162054.GE7604@twin.jikos.cz/333
> same reason why not.
diff mbox series

Patch

diff --git a/cmds/subvolume.c b/cmds/subvolume.c
index 9bd17808..18c75083 100644
--- a/cmds/subvolume.c
+++ b/cmds/subvolume.c
@@ -239,6 +239,8 @@  static const char * const cmd_subvol_delete_usage[] = {
 	"-c|--commit-after      wait for transaction commit at the end of the operation",
 	"-C|--commit-each       wait for transaction commit after deleting each subvolume",
 	"-i|--subvolid          subvolume id of the to be removed subvolume",
+	"--delete-qgroup        delete associated qgroup together",
+	"--no-delete-qgroup     don't delete associated qgroup",
 	"-v|--verbose           deprecated, alias for global -v option",
 	HELPINFO_INSERT_GLOBALS,
 	HELPINFO_INSERT_VERBOSE,
@@ -266,14 +268,18 @@  static int cmd_subvol_delete(const struct cmd_struct *cmd,
 	enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
 	enum btrfs_util_error err;
 	uint64_t default_subvol_id = 0, target_subvol_id = 0;
+	bool delete_qgroup = false;
 
 	optind = 0;
 	while (1) {
 		int c;
+		enum { GETOPT_VAL_DEL_QGROUP = 256, GETOPT_VAL_NO_DEL_QGROUP };
 		static const struct option long_options[] = {
 			{"commit-after", no_argument, NULL, 'c'},
 			{"commit-each", no_argument, NULL, 'C'},
 			{"subvolid", required_argument, NULL, 'i'},
+			{"delete-qgroup", no_argument, NULL, GETOPT_VAL_DEL_QGROUP},
+			{"no-delete-qgroup", no_argument, NULL, GETOPT_VAL_NO_DEL_QGROUP},
 			{"verbose", no_argument, NULL, 'v'},
 			{NULL, 0, NULL, 0}
 		};
@@ -295,6 +301,12 @@  static int cmd_subvol_delete(const struct cmd_struct *cmd,
 		case 'v':
 			bconf_be_verbose();
 			break;
+		case GETOPT_VAL_DEL_QGROUP:
+			delete_qgroup = true;
+			break;
+		case GETOPT_VAL_NO_DEL_QGROUP:
+			delete_qgroup = false;
+			break;
 		default:
 			usage_unknown_option(cmd, argv);
 		}
@@ -388,6 +400,44 @@  again:
 		goto out;
 	}
 
+	if (delete_qgroup) {
+		struct btrfs_ioctl_qgroup_create_args args;
+		memset(&args, 0, sizeof(args));
+		args.create = 0;
+		args.qgroupid = target_subvol_id;
+
+		if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
+			if (errno == ENOTCONN) {
+				struct btrfs_ioctl_quota_ctl_args quota_ctl_args;
+				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_ENABLE;
+				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &quota_ctl_args) < 0) {
+					error("unable to enable quota: %s",
+						  strerror(errno));
+					goto out;
+				}
+
+				if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
+					quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
+					ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args);
+					error("unable to destroy quota group: %s",
+						  strerror(errno));
+					goto out;
+				}
+
+				quota_ctl_args.cmd = BTRFS_QUOTA_CTL_DISABLE;
+				if (ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args) < 0) {
+					error("unable to disable quota: %s",
+						  strerror(errno));
+					goto out;
+				}
+			} else {
+				error("unable to destroy quota group: %s",
+					  strerror(errno));
+				goto out;
+			}
+		}
+	}
+
 	pr_verbose(MUST_LOG, "Delete subvolume (%s): ",
 		commit_mode == COMMIT_EACH ||
 		(commit_mode == COMMIT_AFTER && cnt + 1 == argc) ?
@@ -412,6 +462,7 @@  again:
 		goto out;
 	}
 
+
 	if (commit_mode == COMMIT_EACH) {
 		res = wait_for_commit(fd);
 		if (res < 0) {