2022-04-24 13:04:13

by Dai Ngo

[permalink] [raw]
Subject: [PATCH RFC v21 3/7] NFSD: move create/destroy of laundry_wq to init_nfsd and exit_nfsd

This patch moves create/destroy of laundry_wq from nfs4_state_start
and nfs4_state_shutdown_net to init_nfsd and exit_nfsd to prevent
the laundromat from being freed while a thread is processing a
conflicting lock.

Signed-off-by: Dai Ngo <[email protected]>
---
fs/nfsd/nfs4state.c | 15 ++-------------
fs/nfsd/nfsctl.c | 6 ++++++
fs/nfsd/nfsd.h | 1 +
3 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b08c132648b9..b70ba2eb5665 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -125,7 +125,7 @@ static void free_session(struct nfsd4_session *);
static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;

-static struct workqueue_struct *laundry_wq;
+struct workqueue_struct *laundry_wq;

static bool is_session_dead(struct nfsd4_session *ses)
{
@@ -7798,22 +7798,12 @@ nfs4_state_start(void)
{
int ret;

- laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
- if (laundry_wq == NULL) {
- ret = -ENOMEM;
- goto out;
- }
ret = nfsd4_create_callback_queue();
if (ret)
- goto out_free_laundry;
+ return ret;

set_max_delegations();
return 0;
-
-out_free_laundry:
- destroy_workqueue(laundry_wq);
-out:
- return ret;
}

void
@@ -7850,7 +7840,6 @@ nfs4_state_shutdown_net(struct net *net)
void
nfs4_state_shutdown(void)
{
- destroy_workqueue(laundry_wq);
nfsd4_destroy_callback_queue();
}

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 16920e4512bd..884e873b46ad 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1544,6 +1544,11 @@ static int __init init_nfsd(void)
retval = register_cld_notifier();
if (retval)
goto out_free_all;
+ laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
+ if (laundry_wq == NULL) {
+ retval = -ENOMEM;
+ goto out_free_all;
+ }
return 0;
out_free_all:
unregister_pernet_subsys(&nfsd_net_ops);
@@ -1566,6 +1571,7 @@ static int __init init_nfsd(void)

static void __exit exit_nfsd(void)
{
+ destroy_workqueue(laundry_wq);
unregister_cld_notifier();
unregister_pernet_subsys(&nfsd_net_ops);
nfsd_drc_slab_free();
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 23996c6ca75e..d41dcf1c4312 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -72,6 +72,7 @@ extern unsigned long nfsd_drc_max_mem;
extern unsigned long nfsd_drc_mem_used;

extern const struct seq_operations nfs_exports_op;
+extern struct workqueue_struct *laundry_wq;

/*
* Common void argument and result helpers
--
2.9.5


2022-04-25 21:10:09

by Dai Ngo

[permalink] [raw]
Subject: Re: [PATCH RFC v21 3/7] NFSD: move create/destroy of laundry_wq to init_nfsd and exit_nfsd


On 4/25/22 12:35 PM, J. Bruce Fields wrote:
> On Mon, Apr 25, 2022 at 08:27:22AM -0700, [email protected] wrote:
>> This patch has problem to build with this error:
>>
>>>> nfsctl.c:(.exit.text+0x0): undefined reference to `laundry_wq'
>>>> mipsel-linux-ld: nfsctl.c:(.exit.text+0x4): undefined reference to `laundry_wq'
>> This happens when CONFIG_NFSD is defined but CONFIG_NFSD_V4
>> is not. I think to fix this we need to also move the declaration
>> of laundry_wq from nfs4state.c to nfsctl.c. However this seems
>> odd since the laundry_wq is only used for v4, unless you have
>> any other suggestion.
> I'd just leave laundry_wq private to nfs4state.c. Define
> create_laundromat() and destroy_laundromat() in nfs4state.c too. And in
> nfsd.h, do the usual trick of defining no-op versions of those functions
> in the non-v4 case. (See e.g. what we do with nfsd4_init/free_slabs().)

ok, thanks.

-Dai

>
> --b.
>
>> -Dai
>>
>> On 4/23/22 11:44 AM, Dai Ngo wrote:
>>> This patch moves create/destroy of laundry_wq from nfs4_state_start
>>> and nfs4_state_shutdown_net to init_nfsd and exit_nfsd to prevent
>>> the laundromat from being freed while a thread is processing a
>>> conflicting lock.
>>>
>>> Signed-off-by: Dai Ngo <[email protected]>
>>> ---
>>> fs/nfsd/nfs4state.c | 15 ++-------------
>>> fs/nfsd/nfsctl.c | 6 ++++++
>>> fs/nfsd/nfsd.h | 1 +
>>> 3 files changed, 9 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>>> index b08c132648b9..b70ba2eb5665 100644
>>> --- a/fs/nfsd/nfs4state.c
>>> +++ b/fs/nfsd/nfs4state.c
>>> @@ -125,7 +125,7 @@ static void free_session(struct nfsd4_session *);
>>> static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
>>> static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;
>>> -static struct workqueue_struct *laundry_wq;
>>> +struct workqueue_struct *laundry_wq;
>>> static bool is_session_dead(struct nfsd4_session *ses)
>>> {
>>> @@ -7798,22 +7798,12 @@ nfs4_state_start(void)
>>> {
>>> int ret;
>>> - laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
>>> - if (laundry_wq == NULL) {
>>> - ret = -ENOMEM;
>>> - goto out;
>>> - }
>>> ret = nfsd4_create_callback_queue();
>>> if (ret)
>>> - goto out_free_laundry;
>>> + return ret;
>>> set_max_delegations();
>>> return 0;
>>> -
>>> -out_free_laundry:
>>> - destroy_workqueue(laundry_wq);
>>> -out:
>>> - return ret;
>>> }
>>> void
>>> @@ -7850,7 +7840,6 @@ nfs4_state_shutdown_net(struct net *net)
>>> void
>>> nfs4_state_shutdown(void)
>>> {
>>> - destroy_workqueue(laundry_wq);
>>> nfsd4_destroy_callback_queue();
>>> }
>>> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
>>> index 16920e4512bd..884e873b46ad 100644
>>> --- a/fs/nfsd/nfsctl.c
>>> +++ b/fs/nfsd/nfsctl.c
>>> @@ -1544,6 +1544,11 @@ static int __init init_nfsd(void)
>>> retval = register_cld_notifier();
>>> if (retval)
>>> goto out_free_all;
>>> + laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
>>> + if (laundry_wq == NULL) {
>>> + retval = -ENOMEM;
>>> + goto out_free_all;
>>> + }
>>> return 0;
>>> out_free_all:
>>> unregister_pernet_subsys(&nfsd_net_ops);
>>> @@ -1566,6 +1571,7 @@ static int __init init_nfsd(void)
>>> static void __exit exit_nfsd(void)
>>> {
>>> + destroy_workqueue(laundry_wq);
>>> unregister_cld_notifier();
>>> unregister_pernet_subsys(&nfsd_net_ops);
>>> nfsd_drc_slab_free();
>>> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
>>> index 23996c6ca75e..d41dcf1c4312 100644
>>> --- a/fs/nfsd/nfsd.h
>>> +++ b/fs/nfsd/nfsd.h
>>> @@ -72,6 +72,7 @@ extern unsigned long nfsd_drc_max_mem;
>>> extern unsigned long nfsd_drc_mem_used;
>>> extern const struct seq_operations nfs_exports_op;
>>> +extern struct workqueue_struct *laundry_wq;
>>> /*
>>> * Common void argument and result helpers

2022-04-26 00:05:23

by Dai Ngo

[permalink] [raw]
Subject: Re: [PATCH RFC v21 3/7] NFSD: move create/destroy of laundry_wq to init_nfsd and exit_nfsd

This patch has problem to build with this error:

>> nfsctl.c:(.exit.text+0x0): undefined reference to `laundry_wq'
>> mipsel-linux-ld: nfsctl.c:(.exit.text+0x4): undefined reference to `laundry_wq'

This happens when CONFIG_NFSD is defined but CONFIG_NFSD_V4
is not. I think to fix this we need to also move the declaration
of laundry_wq from nfs4state.c to nfsctl.c. However this seems
odd since the laundry_wq is only used for v4, unless you have
any other suggestion.

-Dai

On 4/23/22 11:44 AM, Dai Ngo wrote:
> This patch moves create/destroy of laundry_wq from nfs4_state_start
> and nfs4_state_shutdown_net to init_nfsd and exit_nfsd to prevent
> the laundromat from being freed while a thread is processing a
> conflicting lock.
>
> Signed-off-by: Dai Ngo <[email protected]>
> ---
> fs/nfsd/nfs4state.c | 15 ++-------------
> fs/nfsd/nfsctl.c | 6 ++++++
> fs/nfsd/nfsd.h | 1 +
> 3 files changed, 9 insertions(+), 13 deletions(-)
>
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index b08c132648b9..b70ba2eb5665 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -125,7 +125,7 @@ static void free_session(struct nfsd4_session *);
> static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
> static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;
>
> -static struct workqueue_struct *laundry_wq;
> +struct workqueue_struct *laundry_wq;
>
> static bool is_session_dead(struct nfsd4_session *ses)
> {
> @@ -7798,22 +7798,12 @@ nfs4_state_start(void)
> {
> int ret;
>
> - laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
> - if (laundry_wq == NULL) {
> - ret = -ENOMEM;
> - goto out;
> - }
> ret = nfsd4_create_callback_queue();
> if (ret)
> - goto out_free_laundry;
> + return ret;
>
> set_max_delegations();
> return 0;
> -
> -out_free_laundry:
> - destroy_workqueue(laundry_wq);
> -out:
> - return ret;
> }
>
> void
> @@ -7850,7 +7840,6 @@ nfs4_state_shutdown_net(struct net *net)
> void
> nfs4_state_shutdown(void)
> {
> - destroy_workqueue(laundry_wq);
> nfsd4_destroy_callback_queue();
> }
>
> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> index 16920e4512bd..884e873b46ad 100644
> --- a/fs/nfsd/nfsctl.c
> +++ b/fs/nfsd/nfsctl.c
> @@ -1544,6 +1544,11 @@ static int __init init_nfsd(void)
> retval = register_cld_notifier();
> if (retval)
> goto out_free_all;
> + laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
> + if (laundry_wq == NULL) {
> + retval = -ENOMEM;
> + goto out_free_all;
> + }
> return 0;
> out_free_all:
> unregister_pernet_subsys(&nfsd_net_ops);
> @@ -1566,6 +1571,7 @@ static int __init init_nfsd(void)
>
> static void __exit exit_nfsd(void)
> {
> + destroy_workqueue(laundry_wq);
> unregister_cld_notifier();
> unregister_pernet_subsys(&nfsd_net_ops);
> nfsd_drc_slab_free();
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 23996c6ca75e..d41dcf1c4312 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -72,6 +72,7 @@ extern unsigned long nfsd_drc_max_mem;
> extern unsigned long nfsd_drc_mem_used;
>
> extern const struct seq_operations nfs_exports_op;
> +extern struct workqueue_struct *laundry_wq;
>
> /*
> * Common void argument and result helpers

2022-04-26 09:30:25

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH RFC v21 3/7] NFSD: move create/destroy of laundry_wq to init_nfsd and exit_nfsd

On Mon, Apr 25, 2022 at 08:27:22AM -0700, [email protected] wrote:
> This patch has problem to build with this error:
>
> >>nfsctl.c:(.exit.text+0x0): undefined reference to `laundry_wq'
> >>mipsel-linux-ld: nfsctl.c:(.exit.text+0x4): undefined reference to `laundry_wq'
>
> This happens when CONFIG_NFSD is defined but CONFIG_NFSD_V4
> is not. I think to fix this we need to also move the declaration
> of laundry_wq from nfs4state.c to nfsctl.c. However this seems
> odd since the laundry_wq is only used for v4, unless you have
> any other suggestion.

I'd just leave laundry_wq private to nfs4state.c. Define
create_laundromat() and destroy_laundromat() in nfs4state.c too. And in
nfsd.h, do the usual trick of defining no-op versions of those functions
in the non-v4 case. (See e.g. what we do with nfsd4_init/free_slabs().)

--b.

>
> -Dai
>
> On 4/23/22 11:44 AM, Dai Ngo wrote:
> >This patch moves create/destroy of laundry_wq from nfs4_state_start
> >and nfs4_state_shutdown_net to init_nfsd and exit_nfsd to prevent
> >the laundromat from being freed while a thread is processing a
> >conflicting lock.
> >
> >Signed-off-by: Dai Ngo <[email protected]>
> >---
> > fs/nfsd/nfs4state.c | 15 ++-------------
> > fs/nfsd/nfsctl.c | 6 ++++++
> > fs/nfsd/nfsd.h | 1 +
> > 3 files changed, 9 insertions(+), 13 deletions(-)
> >
> >diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> >index b08c132648b9..b70ba2eb5665 100644
> >--- a/fs/nfsd/nfs4state.c
> >+++ b/fs/nfsd/nfs4state.c
> >@@ -125,7 +125,7 @@ static void free_session(struct nfsd4_session *);
> > static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
> > static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops;
> >-static struct workqueue_struct *laundry_wq;
> >+struct workqueue_struct *laundry_wq;
> > static bool is_session_dead(struct nfsd4_session *ses)
> > {
> >@@ -7798,22 +7798,12 @@ nfs4_state_start(void)
> > {
> > int ret;
> >- laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
> >- if (laundry_wq == NULL) {
> >- ret = -ENOMEM;
> >- goto out;
> >- }
> > ret = nfsd4_create_callback_queue();
> > if (ret)
> >- goto out_free_laundry;
> >+ return ret;
> > set_max_delegations();
> > return 0;
> >-
> >-out_free_laundry:
> >- destroy_workqueue(laundry_wq);
> >-out:
> >- return ret;
> > }
> > void
> >@@ -7850,7 +7840,6 @@ nfs4_state_shutdown_net(struct net *net)
> > void
> > nfs4_state_shutdown(void)
> > {
> >- destroy_workqueue(laundry_wq);
> > nfsd4_destroy_callback_queue();
> > }
> >diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> >index 16920e4512bd..884e873b46ad 100644
> >--- a/fs/nfsd/nfsctl.c
> >+++ b/fs/nfsd/nfsctl.c
> >@@ -1544,6 +1544,11 @@ static int __init init_nfsd(void)
> > retval = register_cld_notifier();
> > if (retval)
> > goto out_free_all;
> >+ laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4");
> >+ if (laundry_wq == NULL) {
> >+ retval = -ENOMEM;
> >+ goto out_free_all;
> >+ }
> > return 0;
> > out_free_all:
> > unregister_pernet_subsys(&nfsd_net_ops);
> >@@ -1566,6 +1571,7 @@ static int __init init_nfsd(void)
> > static void __exit exit_nfsd(void)
> > {
> >+ destroy_workqueue(laundry_wq);
> > unregister_cld_notifier();
> > unregister_pernet_subsys(&nfsd_net_ops);
> > nfsd_drc_slab_free();
> >diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> >index 23996c6ca75e..d41dcf1c4312 100644
> >--- a/fs/nfsd/nfsd.h
> >+++ b/fs/nfsd/nfsd.h
> >@@ -72,6 +72,7 @@ extern unsigned long nfsd_drc_max_mem;
> > extern unsigned long nfsd_drc_mem_used;
> > extern const struct seq_operations nfs_exports_op;
> >+extern struct workqueue_struct *laundry_wq;
> > /*
> > * Common void argument and result helpers