Commit 6b1b186a authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Minor dio write path improvements

This switches where we take quota reservations to be per bch_wirte_op
instead of per dio_write, so we can drop the quota reservation in the
same place as we call i_sectors_acct(), and only take/release
ei_quota_lock once.

In the future we'd like ei_quota_lock to not be a mutex, so that we can
avoid punting to process context before deliving write completions in
nocow mode.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 84fea8e5
...@@ -77,6 +77,7 @@ struct dio_write { ...@@ -77,6 +77,7 @@ struct dio_write {
struct bch_inode_info *inode; struct bch_inode_info *inode;
struct mm_struct *mm; struct mm_struct *mm;
unsigned loop:1, unsigned loop:1,
extending:1,
sync:1, sync:1,
flush:1, flush:1,
free_iov:1; free_iov:1;
...@@ -131,24 +132,29 @@ static noinline int write_invalidate_inode_pages_range(struct address_space *map ...@@ -131,24 +132,29 @@ static noinline int write_invalidate_inode_pages_range(struct address_space *map
#ifdef CONFIG_BCACHEFS_QUOTA #ifdef CONFIG_BCACHEFS_QUOTA
static void bch2_quota_reservation_put(struct bch_fs *c, static void __bch2_quota_reservation_put(struct bch_fs *c,
struct bch_inode_info *inode, struct bch_inode_info *inode,
struct quota_res *res) struct quota_res *res)
{ {
if (!res->sectors)
return;
mutex_lock(&inode->ei_quota_lock);
BUG_ON(res->sectors > inode->ei_quota_reserved); BUG_ON(res->sectors > inode->ei_quota_reserved);
bch2_quota_acct(c, inode->ei_qid, Q_SPC, bch2_quota_acct(c, inode->ei_qid, Q_SPC,
-((s64) res->sectors), KEY_TYPE_QUOTA_PREALLOC); -((s64) res->sectors), KEY_TYPE_QUOTA_PREALLOC);
inode->ei_quota_reserved -= res->sectors; inode->ei_quota_reserved -= res->sectors;
mutex_unlock(&inode->ei_quota_lock);
res->sectors = 0; res->sectors = 0;
} }
static void bch2_quota_reservation_put(struct bch_fs *c,
struct bch_inode_info *inode,
struct quota_res *res)
{
if (res->sectors) {
mutex_lock(&inode->ei_quota_lock);
__bch2_quota_reservation_put(c, inode, res);
mutex_unlock(&inode->ei_quota_lock);
}
}
static int bch2_quota_reservation_add(struct bch_fs *c, static int bch2_quota_reservation_add(struct bch_fs *c,
struct bch_inode_info *inode, struct bch_inode_info *inode,
struct quota_res *res, struct quota_res *res,
...@@ -171,11 +177,13 @@ static int bch2_quota_reservation_add(struct bch_fs *c, ...@@ -171,11 +177,13 @@ static int bch2_quota_reservation_add(struct bch_fs *c,
#else #else
static void __bch2_quota_reservation_put(struct bch_fs *c,
struct bch_inode_info *inode,
struct quota_res *res) {}
static void bch2_quota_reservation_put(struct bch_fs *c, static void bch2_quota_reservation_put(struct bch_fs *c,
struct bch_inode_info *inode, struct bch_inode_info *inode,
struct quota_res *res) struct quota_res *res) {}
{
}
static int bch2_quota_reservation_add(struct bch_fs *c, static int bch2_quota_reservation_add(struct bch_fs *c,
struct bch_inode_info *inode, struct bch_inode_info *inode,
...@@ -226,13 +234,9 @@ int __must_check bch2_write_inode_size(struct bch_fs *c, ...@@ -226,13 +234,9 @@ int __must_check bch2_write_inode_size(struct bch_fs *c,
return bch2_write_inode(c, inode, inode_set_size, &s, fields); return bch2_write_inode(c, inode, inode_set_size, &s, fields);
} }
static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, static void __i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
struct quota_res *quota_res, s64 sectors) struct quota_res *quota_res, s64 sectors)
{ {
if (!sectors)
return;
mutex_lock(&inode->ei_quota_lock);
bch2_fs_inconsistent_on((s64) inode->v.i_blocks + sectors < 0, c, bch2_fs_inconsistent_on((s64) inode->v.i_blocks + sectors < 0, c,
"inode %lu i_blocks underflow: %llu + %lli < 0 (ondisk %lli)", "inode %lu i_blocks underflow: %llu + %lli < 0 (ondisk %lli)",
inode->v.i_ino, (u64) inode->v.i_blocks, sectors, inode->v.i_ino, (u64) inode->v.i_blocks, sectors,
...@@ -250,7 +254,16 @@ static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, ...@@ -250,7 +254,16 @@ static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors, KEY_TYPE_QUOTA_WARN); bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors, KEY_TYPE_QUOTA_WARN);
} }
#endif #endif
}
static void i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
struct quota_res *quota_res, s64 sectors)
{
if (sectors) {
mutex_lock(&inode->ei_quota_lock);
__i_sectors_acct(c, inode, quota_res, sectors);
mutex_unlock(&inode->ei_quota_lock); mutex_unlock(&inode->ei_quota_lock);
}
} }
/* page state: */ /* page state: */
...@@ -2137,7 +2150,6 @@ static noinline void bch2_dio_write_flush(struct dio_write *dio) ...@@ -2137,7 +2150,6 @@ static noinline void bch2_dio_write_flush(struct dio_write *dio)
static __always_inline long bch2_dio_write_done(struct dio_write *dio) static __always_inline long bch2_dio_write_done(struct dio_write *dio)
{ {
struct bch_fs *c = dio->op.c;
struct kiocb *req = dio->req; struct kiocb *req = dio->req;
struct bch_inode_info *inode = dio->inode; struct bch_inode_info *inode = dio->inode;
bool sync = dio->sync; bool sync = dio->sync;
...@@ -2150,7 +2162,6 @@ static __always_inline long bch2_dio_write_done(struct dio_write *dio) ...@@ -2150,7 +2162,6 @@ static __always_inline long bch2_dio_write_done(struct dio_write *dio)
} }
bch2_pagecache_block_put(inode); bch2_pagecache_block_put(inode);
bch2_quota_reservation_put(c, inode, &dio->quota_res);
if (dio->free_iov) if (dio->free_iov)
kfree(dio->iter.__iov); kfree(dio->iter.__iov);
...@@ -2178,14 +2189,22 @@ static __always_inline void bch2_dio_write_end(struct dio_write *dio) ...@@ -2178,14 +2189,22 @@ static __always_inline void bch2_dio_write_end(struct dio_write *dio)
struct bch_inode_info *inode = dio->inode; struct bch_inode_info *inode = dio->inode;
struct bio *bio = &dio->op.wbio.bio; struct bio *bio = &dio->op.wbio.bio;
i_sectors_acct(c, inode, &dio->quota_res, dio->op.i_sectors_delta);
req->ki_pos += (u64) dio->op.written << 9; req->ki_pos += (u64) dio->op.written << 9;
dio->written += dio->op.written; dio->written += dio->op.written;
if (dio->extending) {
spin_lock(&inode->v.i_lock); spin_lock(&inode->v.i_lock);
if (req->ki_pos > inode->v.i_size) if (req->ki_pos > inode->v.i_size)
i_size_write(&inode->v, req->ki_pos); i_size_write(&inode->v, req->ki_pos);
spin_unlock(&inode->v.i_lock); spin_unlock(&inode->v.i_lock);
}
if (dio->op.i_sectors_delta || dio->quota_res.sectors) {
mutex_lock(&inode->ei_quota_lock);
__i_sectors_acct(c, inode, &dio->quota_res, dio->op.i_sectors_delta);
__bch2_quota_reservation_put(c, inode, &dio->quota_res);
mutex_unlock(&inode->ei_quota_lock);
}
bio_release_pages(bio, false); bio_release_pages(bio, false);
...@@ -2265,6 +2284,11 @@ static long bch2_dio_write_loop(struct dio_write *dio) ...@@ -2265,6 +2284,11 @@ static long bch2_dio_write_loop(struct dio_write *dio)
dio->op.flags |= BCH_WRITE_SYNC; dio->op.flags |= BCH_WRITE_SYNC;
dio->op.flags |= BCH_WRITE_CHECK_ENOSPC; dio->op.flags |= BCH_WRITE_CHECK_ENOSPC;
ret = bch2_quota_reservation_add(c, inode, &dio->quota_res,
bio_sectors(bio), true);
if (unlikely(ret))
goto err;
ret = bch2_disk_reservation_get(c, &dio->op.res, bio_sectors(bio), ret = bch2_disk_reservation_get(c, &dio->op.res, bio_sectors(bio),
dio->op.opts.data_replicas, 0); dio->op.opts.data_replicas, 0);
if (unlikely(ret) && if (unlikely(ret) &&
...@@ -2298,6 +2322,8 @@ static long bch2_dio_write_loop(struct dio_write *dio) ...@@ -2298,6 +2322,8 @@ static long bch2_dio_write_loop(struct dio_write *dio)
dio->op.error = ret; dio->op.error = ret;
bio_release_pages(bio, false); bio_release_pages(bio, false);
bch2_quota_reservation_put(c, inode, &dio->quota_res);
goto out; goto out;
} }
...@@ -2376,6 +2402,7 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter) ...@@ -2376,6 +2402,7 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
dio->inode = inode; dio->inode = inode;
dio->mm = current->mm; dio->mm = current->mm;
dio->loop = false; dio->loop = false;
dio->extending = extending;
dio->sync = is_sync_kiocb(req) || extending; dio->sync = is_sync_kiocb(req) || extending;
dio->flush = iocb_is_dsync(req) && !c->opts.journal_flush_disabled; dio->flush = iocb_is_dsync(req) && !c->opts.journal_flush_disabled;
dio->free_iov = false; dio->free_iov = false;
...@@ -2384,11 +2411,6 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter) ...@@ -2384,11 +2411,6 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
dio->iter = *iter; dio->iter = *iter;
dio->op.c = c; dio->op.c = c;
ret = bch2_quota_reservation_add(c, inode, &dio->quota_res,
iter->count >> 9, true);
if (unlikely(ret))
goto err_put_bio;
if (unlikely(mapping->nrpages)) { if (unlikely(mapping->nrpages)) {
ret = write_invalidate_inode_pages_range(mapping, ret = write_invalidate_inode_pages_range(mapping,
req->ki_pos, req->ki_pos,
...@@ -2404,7 +2426,6 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter) ...@@ -2404,7 +2426,6 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
return ret; return ret;
err_put_bio: err_put_bio:
bch2_pagecache_block_put(inode); bch2_pagecache_block_put(inode);
bch2_quota_reservation_put(c, inode, &dio->quota_res);
bio_put(bio); bio_put(bio);
inode_dio_end(&inode->v); inode_dio_end(&inode->v);
goto err; goto err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment