Commit 0b50b731 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: Fix refcounting in discard path

bch_dev->io_ref does not protect against the filesystem going away;
bch_fs->writes does.

Thus the filesystem write ref needs to be the last ref we release.

Reported-by: syzbot+9e0404b505e604f67e41@syzkaller.appspotmail.com
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 8ed823b1
...@@ -1874,26 +1874,26 @@ static void bch2_do_discards_work(struct work_struct *work) ...@@ -1874,26 +1874,26 @@ static void bch2_do_discards_work(struct work_struct *work)
trace_discard_buckets(c, s.seen, s.open, s.need_journal_commit, s.discarded, trace_discard_buckets(c, s.seen, s.open, s.need_journal_commit, s.discarded,
bch2_err_str(ret)); bch2_err_str(ret));
bch2_write_ref_put(c, BCH_WRITE_REF_discard);
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
bch2_write_ref_put(c, BCH_WRITE_REF_discard);
} }
void bch2_dev_do_discards(struct bch_dev *ca) void bch2_dev_do_discards(struct bch_dev *ca)
{ {
struct bch_fs *c = ca->fs; struct bch_fs *c = ca->fs;
if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE)) if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_discard))
return; return;
if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_discard)) if (!bch2_dev_get_ioref(c, ca->dev_idx, WRITE))
goto put_ioref; goto put_write_ref;
if (queue_work(c->write_ref_wq, &ca->discard_work)) if (queue_work(c->write_ref_wq, &ca->discard_work))
return; return;
bch2_write_ref_put(c, BCH_WRITE_REF_discard);
put_ioref:
percpu_ref_put(&ca->io_ref); percpu_ref_put(&ca->io_ref);
put_write_ref:
bch2_write_ref_put(c, BCH_WRITE_REF_discard);
} }
void bch2_do_discards(struct bch_fs *c) void bch2_do_discards(struct bch_fs *c)
......
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