syzbot is reporting that __getblk_gfp() cannot be called from atomic context. Fix this problem by converting pointers_lock from rw_lock to rw_sem. Reported-by: syzbot <syzbot+69b40dc5fd40f32c199f@xxxxxxxxxxxxxxxxxxxxxxxxx> Link: https://syzkaller.appspot.com/bug?extid=69b40dc5fd40f32c199f Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx> Tested-by: syzbot <syzbot+69b40dc5fd40f32c199f@xxxxxxxxxxxxxxxxxxxxxxxxx> --- fs/sysv/itree.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index b22764fe669c..513b20e30afd 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -62,7 +62,7 @@ typedef struct { struct buffer_head *bh; } Indirect; -static DEFINE_RWLOCK(pointers_lock); +static DECLARE_RWSEM(pointers_lock); static inline void add_chain(Indirect *p, struct buffer_head *bh, sysv_zone_t *v) { @@ -83,7 +83,7 @@ static inline sysv_zone_t *block_end(struct buffer_head *bh) } /* - * Requires read_lock(&pointers_lock) or write_lock(&pointers_lock) + * Requires down_read(&pointers_lock) or down_write(&pointers_lock) */ static Indirect *get_branch(struct inode *inode, int depth, @@ -173,11 +173,11 @@ static inline int splice_branch(struct inode *inode, int i; /* Verify that place we are splicing to is still there and vacant */ - write_lock(&pointers_lock); + down_write(&pointers_lock); if (!verify_chain(chain, where-1) || *where->p) goto changed; *where->p = where->key; - write_unlock(&pointers_lock); + up_write(&pointers_lock); inode->i_ctime = current_time(inode); @@ -192,7 +192,7 @@ static inline int splice_branch(struct inode *inode, return 0; changed: - write_unlock(&pointers_lock); + up_write(&pointers_lock); for (i = 1; i < num; i++) bforget(where[i].bh); for (i = 0; i < num; i++) @@ -214,9 +214,9 @@ static int get_block(struct inode *inode, sector_t iblock, struct buffer_head *b goto out; reread: - read_lock(&pointers_lock); + down_read(&pointers_lock); partial = get_branch(inode, depth, offsets, chain, &err); - read_unlock(&pointers_lock); + up_read(&pointers_lock); /* Simplest case - block found, no allocation needed */ if (!partial) { @@ -287,7 +287,7 @@ static Indirect *find_shared(struct inode *inode, for (k = depth; k > 1 && !offsets[k-1]; k--) ; - write_lock(&pointers_lock); + down_write(&pointers_lock); partial = get_branch(inode, k, offsets, chain, &err); if (!partial) partial = chain + k-1; @@ -296,7 +296,7 @@ static Indirect *find_shared(struct inode *inode, * fine, it should all survive and (new) top doesn't belong to us. */ if (!partial->key && *partial->p) { - write_unlock(&pointers_lock); + up_write(&pointers_lock); goto no_top; } for (p=partial; p>chain && all_zeroes((sysv_zone_t*)p->bh->b_data,p->p); p--) @@ -313,7 +313,7 @@ static Indirect *find_shared(struct inode *inode, *top = *p->p; *p->p = 0; } - write_unlock(&pointers_lock); + up_write(&pointers_lock); while (partial > p) { brelse(partial->bh); -- 2.18.4