diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-04-11 18:39:16 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2018-05-22 00:44:18 -0400 |
commit | 51768abe7638c3e8fe8aed86db4d582f74911b2e (patch) | |
tree | b7c37649c6a7fb32bc8ecceeb54a5a23f5f0d143 | |
parent | b5189c85527cd13ca46640bf3206678346154118 (diff) |
bcachefs: Fix a locking bug
bch2_releasepage() can't take locks that are held while allocating
memory, unless GFP_NOFS is used - ei_update_lock is held while calling
into btree code that uses GFP_NOIO
-rw-r--r-- | fs/bcachefs/fs-io.c | 25 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 1 | ||||
-rw-r--r-- | fs/bcachefs/fs.h | 2 |
3 files changed, 13 insertions, 15 deletions
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index e2855743540a..a5e70e3d7ff9 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -124,13 +124,13 @@ static void bch2_quota_reservation_put(struct bch_fs *c, if (!res->sectors) return; - mutex_lock(&inode->ei_update_lock); + mutex_lock(&inode->ei_quota_lock); BUG_ON(res->sectors > inode->ei_quota_reserved); bch2_quota_acct(c, inode->ei_qid, Q_SPC, -((s64) res->sectors), BCH_QUOTA_PREALLOC); inode->ei_quota_reserved -= res->sectors; - mutex_unlock(&inode->ei_update_lock); + mutex_unlock(&inode->ei_quota_lock); res->sectors = 0; } @@ -143,14 +143,14 @@ static int bch2_quota_reservation_add(struct bch_fs *c, { int ret; - mutex_lock(&inode->ei_update_lock); + mutex_lock(&inode->ei_quota_lock); ret = bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors, check_enospc ? BCH_QUOTA_PREALLOC : BCH_QUOTA_NOCHECK); if (likely(!ret)) { inode->ei_quota_reserved += sectors; res->sectors += sectors; } - mutex_unlock(&inode->ei_update_lock); + mutex_unlock(&inode->ei_quota_lock); return ret; } @@ -195,9 +195,10 @@ static int __must_check bch2_write_inode_size(struct bch_fs *c, return __bch2_write_inode(c, inode, inode_set_size, &new_size); } -static void __i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, - struct quota_res *quota_res, int sectors) +static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, + struct quota_res *quota_res, int sectors) { + mutex_lock(&inode->ei_quota_lock); #ifdef CONFIG_BCACHEFS_QUOTA if (quota_res && sectors > 0) { BUG_ON(sectors > quota_res->sectors); @@ -210,14 +211,7 @@ static void __i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, } #endif inode->v.i_blocks += sectors; -} - -static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, - struct quota_res *quota_res, int sectors) -{ - mutex_lock(&inode->ei_update_lock); - __i_sectors_acct(c, inode, quota_res, sectors); - mutex_unlock(&inode->ei_update_lock); + mutex_unlock(&inode->ei_quota_lock); } /* i_sectors accounting: */ @@ -265,7 +259,7 @@ static int i_sectors_dirty_finish(struct bch_fs *c, struct i_sectors_hook *h) if (h->new_i_size != U64_MAX) i_size_write(&h->inode->v, h->new_i_size); - __i_sectors_acct(c, h->inode, &h->quota_res, h->sectors); + i_sectors_acct(c, h->inode, &h->quota_res, h->sectors); ret = __bch2_write_inode(c, h->inode, i_sectors_dirty_finish_fn, h); mutex_unlock(&h->inode->ei_update_lock); @@ -773,6 +767,7 @@ void bch2_invalidatepage(struct page *page, unsigned int offset, int bch2_releasepage(struct page *page, gfp_t gfp_mask) { + /* XXX: this can't take locks that are held while we allocate memory */ EBUG_ON(!PageLocked(page)); EBUG_ON(PageWriteback(page)); diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index c7e842ee8437..fb30f0d95377 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -1028,6 +1028,7 @@ static struct inode *bch2_alloc_inode(struct super_block *sb) inode_init_once(&inode->v); mutex_init(&inode->ei_update_lock); + mutex_init(&inode->ei_quota_lock); inode->ei_journal_seq = 0; return &inode->v; diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h index fddfb2d2fcaf..fbbc7a3a3cb7 100644 --- a/fs/bcachefs/fs.h +++ b/fs/bcachefs/fs.h @@ -15,6 +15,8 @@ struct bch_inode_info { u64 ei_journal_seq; u64 ei_quota_reserved; unsigned long ei_last_dirtied; + + struct mutex ei_quota_lock; struct bch_qid ei_qid; struct bch_hash_info ei_str_hash; |