bcachefs: Fix missing write refs in fs fio paths

bch2_journal_flush_seq requires us to have a write ref

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2024-04-13 00:26:01 -04:00
parent 82cf18f23e
commit 9e203c43dc
3 changed files with 23 additions and 14 deletions

View File

@ -709,6 +709,8 @@ struct btree_trans_buf {
x(stripe_delete) \
x(reflink) \
x(fallocate) \
x(fsync) \
x(dio_write) \
x(discard) \
x(discard_fast) \
x(invalidate) \

View File

@ -387,6 +387,8 @@ static __always_inline long bch2_dio_write_done(struct dio_write *dio)
ret = dio->op.error ?: ((long) dio->written << 9);
bio_put(&dio->op.wbio.bio);
bch2_write_ref_put(dio->op.c, BCH_WRITE_REF_dio_write);
/* inode->i_dio_count is our ref on inode and thus bch_fs */
inode_dio_end(&inode->v);
@ -590,22 +592,25 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
prefetch(&inode->ei_inode);
prefetch((void *) &inode->ei_inode + 64);
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_dio_write))
return -EROFS;
inode_lock(&inode->v);
ret = generic_write_checks(req, iter);
if (unlikely(ret <= 0))
goto err;
goto err_put_write_ref;
ret = file_remove_privs(file);
if (unlikely(ret))
goto err;
goto err_put_write_ref;
ret = file_update_time(file);
if (unlikely(ret))
goto err;
goto err_put_write_ref;
if (unlikely((req->ki_pos|iter->count) & (block_bytes(c) - 1)))
goto err;
goto err_put_write_ref;
inode_dio_begin(&inode->v);
bch2_pagecache_block_get(inode);
@ -645,7 +650,7 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
}
ret = bch2_dio_write_loop(dio);
err:
out:
if (locked)
inode_unlock(&inode->v);
return ret;
@ -653,7 +658,9 @@ err_put_bio:
bch2_pagecache_block_put(inode);
bio_put(bio);
inode_dio_end(&inode->v);
goto err;
err_put_write_ref:
bch2_write_ref_put(c, BCH_WRITE_REF_dio_write);
goto out;
}
void bch2_fs_fs_io_direct_exit(struct bch_fs *c)

View File

@ -174,18 +174,18 @@ void __bch2_i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode,
static int bch2_flush_inode(struct bch_fs *c,
struct bch_inode_info *inode)
{
struct bch_inode_unpacked u;
int ret;
if (c->opts.journal_flush_disabled)
return 0;
ret = bch2_inode_find_by_inum(c, inode_inum(inode), &u);
if (ret)
return ret;
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_fsync))
return -EROFS;
return bch2_journal_flush_seq(&c->journal, u.bi_journal_seq) ?:
bch2_inode_flush_nocow_writes(c, inode);
struct bch_inode_unpacked u;
int ret = bch2_inode_find_by_inum(c, inode_inum(inode), &u) ?:
bch2_journal_flush_seq(&c->journal, u.bi_journal_seq) ?:
bch2_inode_flush_nocow_writes(c, inode);
bch2_write_ref_put(c, BCH_WRITE_REF_fsync);
return ret;
}
int bch2_fsync(struct file *file, loff_t start, loff_t end, int datasync)