Commit f2eb8434 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: fix invalid free in dio write path

turns out iterate_iovec() mutates __iov, we need to save our own copy
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
Reported-by: default avatarMarcin Mirosław <marcin@mejor.pl>
parent fa014953
...@@ -216,11 +216,11 @@ struct dio_write { ...@@ -216,11 +216,11 @@ struct dio_write {
struct address_space *mapping; struct address_space *mapping;
struct bch_inode_info *inode; struct bch_inode_info *inode;
struct mm_struct *mm; struct mm_struct *mm;
const struct iovec *iov;
unsigned loop:1, unsigned loop:1,
extending:1, extending:1,
sync:1, sync:1,
flush:1, flush:1;
free_iov:1;
struct quota_res quota_res; struct quota_res quota_res;
u64 written; u64 written;
...@@ -312,12 +312,10 @@ static noinline int bch2_dio_write_copy_iov(struct dio_write *dio) ...@@ -312,12 +312,10 @@ static noinline int bch2_dio_write_copy_iov(struct dio_write *dio)
return -1; return -1;
if (dio->iter.nr_segs > ARRAY_SIZE(dio->inline_vecs)) { if (dio->iter.nr_segs > ARRAY_SIZE(dio->inline_vecs)) {
iov = kmalloc_array(dio->iter.nr_segs, sizeof(*iov), dio->iov = iov = kmalloc_array(dio->iter.nr_segs, sizeof(*iov),
GFP_KERNEL); GFP_KERNEL);
if (unlikely(!iov)) if (unlikely(!iov))
return -ENOMEM; return -ENOMEM;
dio->free_iov = true;
} }
memcpy(iov, dio->iter.__iov, dio->iter.nr_segs * sizeof(*iov)); memcpy(iov, dio->iter.__iov, dio->iter.nr_segs * sizeof(*iov));
...@@ -381,8 +379,7 @@ static __always_inline long bch2_dio_write_done(struct dio_write *dio) ...@@ -381,8 +379,7 @@ static __always_inline long bch2_dio_write_done(struct dio_write *dio)
bch2_pagecache_block_put(inode); bch2_pagecache_block_put(inode);
if (dio->free_iov) kfree(dio->iov);
kfree(dio->iter.__iov);
ret = dio->op.error ?: ((long) dio->written << 9); ret = dio->op.error ?: ((long) dio->written << 9);
bio_put(&dio->op.wbio.bio); bio_put(&dio->op.wbio.bio);
...@@ -626,11 +623,11 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter) ...@@ -626,11 +623,11 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter)
dio->mapping = mapping; dio->mapping = mapping;
dio->inode = inode; dio->inode = inode;
dio->mm = current->mm; dio->mm = current->mm;
dio->iov = NULL;
dio->loop = false; dio->loop = false;
dio->extending = extending; 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->quota_res.sectors = 0; dio->quota_res.sectors = 0;
dio->written = 0; dio->written = 0;
dio->iter = *iter; dio->iter = *iter;
......
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