In erofs umount scenario, erofs_fscache_unregister_cookie() is called
twice in kill_sb() and put_super().
It works for original semantics, cause 'ctx' will be set to NULL in
put_super() and will not be unregister again in kill_sb().
However, in shared domain scenario, we use refcount to maintain the
lifecycle of cookie. Unregister the cookie twice will cause it to be
released early.
For the above reasons, this patch removes duplicate unregister_cookie
and move fscache_unregister_* before shotdown_super() to prevent busy
inode(ctx->inode) when umount.
Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
---
fs/erofs/super.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/fs/erofs/super.c b/fs/erofs/super.c
index 69de1731f454..667a78f0ee70 100644
--- a/fs/erofs/super.c
+++ b/fs/erofs/super.c
@@ -919,19 +919,20 @@ static void erofs_kill_sb(struct super_block *sb)
kill_litter_super(sb);
return;
}
- if (erofs_is_fscache_mode(sb))
- generic_shutdown_super(sb);
- else
- kill_block_super(sb);
-
sbi = EROFS_SB(sb);
if (!sbi)
return;
+ if (erofs_is_fscache_mode(sb)) {
+ erofs_fscache_unregister_cookie(&sbi->s_fscache);
+ erofs_fscache_unregister_fs(sb);
+ generic_shutdown_super(sb);
+ } else {
+ kill_block_super(sb);
+ }
+
erofs_free_dev_context(sbi->devs);
fs_put_dax(sbi->dax_dev, NULL);
- erofs_fscache_unregister_cookie(&sbi->s_fscache);
- erofs_fscache_unregister_fs(sb);
kfree(sbi->opt.fsid);
kfree(sbi->opt.domain_id);
kfree(sbi);
@@ -951,7 +952,6 @@ static void erofs_put_super(struct super_block *sb)
iput(sbi->managed_cache);
sbi->managed_cache = NULL;
#endif
- erofs_fscache_unregister_cookie(&sbi->s_fscache);
}
struct file_system_type erofs_fs_type = {
--
2.20.1
On 9/2/22 6:53 PM, Jia Zhu wrote:
> In erofs umount scenario, erofs_fscache_unregister_cookie() is called
> twice in kill_sb() and put_super().
>
> It works for original semantics, cause 'ctx' will be set to NULL in
> put_super() and will not be unregister again in kill_sb().
> However, in shared domain scenario, we use refcount to maintain the
> lifecycle of cookie. Unregister the cookie twice will cause it to be
> released early.
>
> For the above reasons, this patch removes duplicate unregister_cookie
> and move fscache_unregister_* before shotdown_super() to prevent busy
> inode(ctx->inode) when umount.
>
> Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
> ---
> fs/erofs/super.c | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 69de1731f454..667a78f0ee70 100644
> --- a/fs/erofs/super.c
> +++ b/fs/erofs/super.c
> @@ -919,19 +919,20 @@ static void erofs_kill_sb(struct super_block *sb)
> kill_litter_super(sb);
> return;
> }
> - if (erofs_is_fscache_mode(sb))
> - generic_shutdown_super(sb);
> - else
> - kill_block_super(sb);
> -
> sbi = EROFS_SB(sb);
> if (!sbi)
> return;
>
> + if (erofs_is_fscache_mode(sb)) {
> + erofs_fscache_unregister_cookie(&sbi->s_fscache);
> + erofs_fscache_unregister_fs(sb);
> + generic_shutdown_super(sb);
Generally we can't do clean ups before generic_shutdown_super(), since
generic_shutdown_super() may trigger IO, e.g. in sync_filesystem(),
though it's not the case for erofs (read-only).
How about embedding erofs_fscache_unregister_cookie() into
erofs_fscache_unregister_fs(), and thus we can check domain_id in
erofs_fscache_unregister_fs()?
> + } else {
> + kill_block_super(sb);
> + }
> +
> erofs_free_dev_context(sbi->devs);
> fs_put_dax(sbi->dax_dev, NULL);
> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
> - erofs_fscache_unregister_fs(sb);
> kfree(sbi->opt.fsid);
> kfree(sbi->opt.domain_id);
> kfree(sbi);
> @@ -951,7 +952,6 @@ static void erofs_put_super(struct super_block *sb)
> iput(sbi->managed_cache);
> sbi->managed_cache = NULL;
> #endif
> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
> }
>
> struct file_system_type erofs_fs_type = {
--
Thanks,
Jingbo
On 9/9/22 5:55 PM, JeffleXu wrote:
>
>
> On 9/2/22 6:53 PM, Jia Zhu wrote:
>> In erofs umount scenario, erofs_fscache_unregister_cookie() is called
>> twice in kill_sb() and put_super().
>>
>> It works for original semantics, cause 'ctx' will be set to NULL in
>> put_super() and will not be unregister again in kill_sb().
>> However, in shared domain scenario, we use refcount to maintain the
>> lifecycle of cookie. Unregister the cookie twice will cause it to be
>> released early.
Sorry, why can't we also set sbi->s_fscache to NULL after decrementing
the refcount in shared domain mode, to avoid the refcount being
decremented twice?
>>
>> For the above reasons, this patch removes duplicate unregister_cookie
>> and move fscache_unregister_* before shotdown_super() to prevent busy
>> inode(ctx->inode) when umount.
>>
>> Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
>> ---
>> fs/erofs/super.c | 16 ++++++++--------
>> 1 file changed, 8 insertions(+), 8 deletions(-)
>>
>> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
>> index 69de1731f454..667a78f0ee70 100644
>> --- a/fs/erofs/super.c
>> +++ b/fs/erofs/super.c
>> @@ -919,19 +919,20 @@ static void erofs_kill_sb(struct super_block *sb)
>> kill_litter_super(sb);
>> return;
>> }
>> - if (erofs_is_fscache_mode(sb))
>> - generic_shutdown_super(sb);
>> - else
>> - kill_block_super(sb);
>> -
>> sbi = EROFS_SB(sb);
>> if (!sbi)
>> return;
>>
>> + if (erofs_is_fscache_mode(sb)) {
>> + erofs_fscache_unregister_cookie(&sbi->s_fscache);
>> + erofs_fscache_unregister_fs(sb);
>> + generic_shutdown_super(sb);
>
> Generally we can't do clean ups before generic_shutdown_super(), since
> generic_shutdown_super() may trigger IO, e.g. in sync_filesystem(),
> though it's not the case for erofs (read-only).
>
> How about embedding erofs_fscache_unregister_cookie() into
> erofs_fscache_unregister_fs(), and thus we can check domain_id in
> erofs_fscache_unregister_fs()?
>
>> + } else {
>> + kill_block_super(sb);
>> + }
>> +
>> erofs_free_dev_context(sbi->devs);
>> fs_put_dax(sbi->dax_dev, NULL);
>> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
>> - erofs_fscache_unregister_fs(sb);
>> kfree(sbi->opt.fsid);
>> kfree(sbi->opt.domain_id);
>> kfree(sbi);
>> @@ -951,7 +952,6 @@ static void erofs_put_super(struct super_block *sb)
>> iput(sbi->managed_cache);
>> sbi->managed_cache = NULL;
>> #endif
>> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
>> }
>>
>> struct file_system_type erofs_fs_type = {
>
--
Thanks,
Jingbo
在 2022/9/9 18:28, JeffleXu 写道:
>
>
> On 9/9/22 5:55 PM, JeffleXu wrote:
>>
>>
>> On 9/2/22 6:53 PM, Jia Zhu wrote:
>>> In erofs umount scenario, erofs_fscache_unregister_cookie() is called
>>> twice in kill_sb() and put_super().
>>>
>>> It works for original semantics, cause 'ctx' will be set to NULL in
>>> put_super() and will not be unregister again in kill_sb().
>>> However, in shared domain scenario, we use refcount to maintain the
>>> lifecycle of cookie. Unregister the cookie twice will cause it to be
>>> released early.
>
> Sorry, why can't we also set sbi->s_fscache to NULL after decrementing
> the refcount in shared domain mode, to avoid the refcount being
> decremented twice?
>
In below case:
1. mount -t erofs none -o fsid=bootstrap.img -o device=blob.img -o
domain_id=1 mnt
2. mount -t erofs none -o fsid=bootstrap.img -o device=blob.img -o
domain_id=1 mnt2
3. Procedure 2 will fail since we can't mount erofs with the same sysfs
entry.
4. Mount()'s error handling path will step into put_super().
5. Domain's refcnt will be decremented even if it has not yet
been incremented.
>>>
>>> For the above reasons, this patch removes duplicate unregister_cookie
>>> and move fscache_unregister_* before shotdown_super() to prevent busy
>>> inode(ctx->inode) when umount.
>>>
>>> Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
>>> ---
>>> fs/erofs/super.c | 16 ++++++++--------
>>> 1 file changed, 8 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
>>> index 69de1731f454..667a78f0ee70 100644
>>> --- a/fs/erofs/super.c
>>> +++ b/fs/erofs/super.c
>>> @@ -919,19 +919,20 @@ static void erofs_kill_sb(struct super_block *sb)
>>> kill_litter_super(sb);
>>> return;
>>> }
>>> - if (erofs_is_fscache_mode(sb))
>>> - generic_shutdown_super(sb);
>>> - else
>>> - kill_block_super(sb);
>>> -
>>> sbi = EROFS_SB(sb);
>>> if (!sbi)
>>> return;
>>>
>>> + if (erofs_is_fscache_mode(sb)) {
>>> + erofs_fscache_unregister_cookie(&sbi->s_fscache);
>>> + erofs_fscache_unregister_fs(sb);
>>> + generic_shutdown_super(sb);
>>
>> Generally we can't do clean ups before generic_shutdown_super(), since
>> generic_shutdown_super() may trigger IO, e.g. in sync_filesystem(),
>> though it's not the case for erofs (read-only).
>>
>> How about embedding erofs_fscache_unregister_cookie() into
>> erofs_fscache_unregister_fs(), and thus we can check domain_id in
>> erofs_fscache_unregister_fs()?
>>
>>> + } else {
>>> + kill_block_super(sb);
>>> + }
>>> +
>>> erofs_free_dev_context(sbi->devs);
>>> fs_put_dax(sbi->dax_dev, NULL);
>>> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
>>> - erofs_fscache_unregister_fs(sb);
>>> kfree(sbi->opt.fsid);
>>> kfree(sbi->opt.domain_id);
>>> kfree(sbi);
>>> @@ -951,7 +952,6 @@ static void erofs_put_super(struct super_block *sb)
>>> iput(sbi->managed_cache);
>>> sbi->managed_cache = NULL;
>>> #endif
>>> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
>>> }
>>>
>>> struct file_system_type erofs_fs_type = {
>>
>
在 2022/9/9 17:55, JeffleXu 写道:
>
>
> On 9/2/22 6:53 PM, Jia Zhu wrote:
>> In erofs umount scenario, erofs_fscache_unregister_cookie() is called
>> twice in kill_sb() and put_super().
>>
>> It works for original semantics, cause 'ctx' will be set to NULL in
>> put_super() and will not be unregister again in kill_sb().
>> However, in shared domain scenario, we use refcount to maintain the
>> lifecycle of cookie. Unregister the cookie twice will cause it to be
>> released early.
>>
>> For the above reasons, this patch removes duplicate unregister_cookie
>> and move fscache_unregister_* before shotdown_super() to prevent busy
>> inode(ctx->inode) when umount.
>>
>> Signed-off-by: Jia Zhu <zhujia.zj@bytedance.com>
>> ---
>> fs/erofs/super.c | 16 ++++++++--------
>> 1 file changed, 8 insertions(+), 8 deletions(-)
>>
>> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
>> index 69de1731f454..667a78f0ee70 100644
>> --- a/fs/erofs/super.c
>> +++ b/fs/erofs/super.c
>> @@ -919,19 +919,20 @@ static void erofs_kill_sb(struct super_block *sb)
>> kill_litter_super(sb);
>> return;
>> }
>> - if (erofs_is_fscache_mode(sb))
>> - generic_shutdown_super(sb);
>> - else
>> - kill_block_super(sb);
>> -
>> sbi = EROFS_SB(sb);
>> if (!sbi)
>> return;
>>
>> + if (erofs_is_fscache_mode(sb)) {
>> + erofs_fscache_unregister_cookie(&sbi->s_fscache);
>> + erofs_fscache_unregister_fs(sb);
>> + generic_shutdown_super(sb);
>
> Generally we can't do clean ups before generic_shutdown_super(), since
> generic_shutdown_super() may trigger IO, e.g. in sync_filesystem(),
> though it's not the case for erofs (read-only).
>
> How about embedding erofs_fscache_unregister_cookie() into
> erofs_fscache_unregister_fs(), and thus we can check domain_id in
> erofs_fscache_unregister_fs()?
>
Thanks.
>> + } else {
>> + kill_block_super(sb);
>> + }
>> +
>> erofs_free_dev_context(sbi->devs);
>> fs_put_dax(sbi->dax_dev, NULL);
>> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
>> - erofs_fscache_unregister_fs(sb);
>> kfree(sbi->opt.fsid);
>> kfree(sbi->opt.domain_id);
>> kfree(sbi);
>> @@ -951,7 +952,6 @@ static void erofs_put_super(struct super_block *sb)
>> iput(sbi->managed_cache);
>> sbi->managed_cache = NULL;
>> #endif
>> - erofs_fscache_unregister_cookie(&sbi->s_fscache);
>> }
>>
>> struct file_system_type erofs_fs_type = {
>
© 2016 - 2026 Red Hat, Inc.