fs: nfs: fix a possible sleep-in-atomic-context bug in _pnfs_grab_empty_layout()
diff mbox series

Message ID 20191217133319.11861-1-baijiaju1990@gmail.com
State New
Headers show
Series
  • fs: nfs: fix a possible sleep-in-atomic-context bug in _pnfs_grab_empty_layout()
Related show

Commit Message

Jia-Ju Bai Dec. 17, 2019, 1:33 p.m. UTC
The filesystem may sleep while holding a spinlock.
The function call path (from bottom to top) in Linux 4.19 is:

fs/nfs/pnfs.c, 2052: 
	pnfs_find_alloc_layout(GFP_KERNEL) in _pnfs_grab_empty_layout
fs/nfs/pnfs.c, 2051: 
	spin_lock in _pnfs_grab_empty_layout

pnfs_find_alloc_layout(GFP_KERNEL) can sleep at runtime.

To fix this possible bug, GFP_KERNEL is replaced with GFP_ATOMIC for
pnfs_find_alloc_layout().

This bug is found by a static analysis tool STCheck written by myself.

Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com>
---
 fs/nfs/pnfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Trond Myklebust Dec. 17, 2019, 2:37 p.m. UTC | #1
On Tue, 2019-12-17 at 21:33 +0800, Jia-Ju Bai wrote:
> The filesystem may sleep while holding a spinlock.
> The function call path (from bottom to top) in Linux 4.19 is:
> 
> fs/nfs/pnfs.c, 2052: 
> 	pnfs_find_alloc_layout(GFP_KERNEL) in _pnfs_grab_empty_layout
> fs/nfs/pnfs.c, 2051: 
> 	spin_lock in _pnfs_grab_empty_layout
> 
> pnfs_find_alloc_layout(GFP_KERNEL) can sleep at runtime.
> 
> To fix this possible bug, GFP_KERNEL is replaced with GFP_ATOMIC for
> pnfs_find_alloc_layout().
> 
> This bug is found by a static analysis tool STCheck written by
> myself.
> 
> Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com>
> ---
>  fs/nfs/pnfs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
> index cec3070ab577..cfbe170f0651 100644
> --- a/fs/nfs/pnfs.c
> +++ b/fs/nfs/pnfs.c
> @@ -2138,7 +2138,7 @@ _pnfs_grab_empty_layout(struct inode *ino,
> struct nfs_open_context *ctx)
>  	struct pnfs_layout_hdr *lo;
>  
>  	spin_lock(&ino->i_lock);
> -	lo = pnfs_find_alloc_layout(ino, ctx, GFP_KERNEL);
> +	lo = pnfs_find_alloc_layout(ino, ctx, GFP_ATOMIC);
>  	if (!lo)
>  		goto out_unlock;
>  	if (!test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))

I'm not seeing why this is necessary. As far as I can see,
pnfs_find_alloc_layout() will release the ino->i_lock before sleeping.

False positive?
Jia-Ju Bai Dec. 18, 2019, 1:54 a.m. UTC | #2
On 2019/12/17 22:37, Trond Myklebust wrote:
> On Tue, 2019-12-17 at 21:33 +0800, Jia-Ju Bai wrote:
>> The filesystem may sleep while holding a spinlock.
>> The function call path (from bottom to top) in Linux 4.19 is:
>>
>> fs/nfs/pnfs.c, 2052:
>> 	pnfs_find_alloc_layout(GFP_KERNEL) in _pnfs_grab_empty_layout
>> fs/nfs/pnfs.c, 2051:
>> 	spin_lock in _pnfs_grab_empty_layout
>>
>> pnfs_find_alloc_layout(GFP_KERNEL) can sleep at runtime.
>>
>> To fix this possible bug, GFP_KERNEL is replaced with GFP_ATOMIC for
>> pnfs_find_alloc_layout().
>>
>> This bug is found by a static analysis tool STCheck written by
>> myself.
>>
>> Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com>
>> ---
>>   fs/nfs/pnfs.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
>> index cec3070ab577..cfbe170f0651 100644
>> --- a/fs/nfs/pnfs.c
>> +++ b/fs/nfs/pnfs.c
>> @@ -2138,7 +2138,7 @@ _pnfs_grab_empty_layout(struct inode *ino,
>> struct nfs_open_context *ctx)
>>   	struct pnfs_layout_hdr *lo;
>>   
>>   	spin_lock(&ino->i_lock);
>> -	lo = pnfs_find_alloc_layout(ino, ctx, GFP_KERNEL);
>> +	lo = pnfs_find_alloc_layout(ino, ctx, GFP_ATOMIC);
>>   	if (!lo)
>>   		goto out_unlock;
>>   	if (!test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))
> I'm not seeing why this is necessary. As far as I can see,
> pnfs_find_alloc_layout() will release the ino->i_lock before sleeping.
>
> False positive?
>

Thanks for the reply.
You are right, my report is false...
I did not check the definition of pnfs_find_alloc_layout(), sorry...


Best wishes,
Jia-Ju Bai

Patch
diff mbox series

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index cec3070ab577..cfbe170f0651 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -2138,7 +2138,7 @@  _pnfs_grab_empty_layout(struct inode *ino, struct nfs_open_context *ctx)
 	struct pnfs_layout_hdr *lo;
 
 	spin_lock(&ino->i_lock);
-	lo = pnfs_find_alloc_layout(ino, ctx, GFP_KERNEL);
+	lo = pnfs_find_alloc_layout(ino, ctx, GFP_ATOMIC);
 	if (!lo)
 		goto out_unlock;
 	if (!test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))