bcachefs: Fix missing write refs in fs fio paths
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 13 Apr 2024 04:26:01 +0000 (00:26 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 14 Apr 2024 02:48:17 +0000 (22:48 -0400)
bch2_journal_flush_seq requires us to have a write ref

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs.h
fs/bcachefs/fs-io-direct.c
fs/bcachefs/fs-io.c

index a31a5f706929eb2006e4867a38123b9526639cee..91c3c1fef233d118fb083dae3a60a5e779e3cdaf 100644 (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)                                                   \
index f49e6c0f0f6835968202ab2f1fa194933945554a..b889370a5088113a2417787bdbb4b98a16597063 100644 (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)
index 8c70123b6a0c809b6d50040593281c2e9c115828..20b40477425f49449499b11d63930d92e10ed3ba 100644 (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)