mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-18 02:46:06 +00:00
bcachefs: Convert io paths for snapshots
This plumbs around the subvolume ID as was done previously for other filesystem code, but now for the IO paths - the control flow in the IO paths is trickier so the changes in this patch are more involved. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
parent
ef1669ffc6
commit
8c6d298ab2
@ -769,23 +769,35 @@ static void readpage_bio_extend(struct readpages_iter *iter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bchfs_read(struct btree_trans *trans, struct btree_iter *iter,
|
static void bchfs_read(struct btree_trans *trans,
|
||||||
struct bch_read_bio *rbio, u64 inum,
|
struct bch_read_bio *rbio,
|
||||||
|
subvol_inum inum,
|
||||||
struct readpages_iter *readpages_iter)
|
struct readpages_iter *readpages_iter)
|
||||||
{
|
{
|
||||||
struct bch_fs *c = trans->c;
|
struct bch_fs *c = trans->c;
|
||||||
|
struct btree_iter iter;
|
||||||
struct bkey_buf sk;
|
struct bkey_buf sk;
|
||||||
int flags = BCH_READ_RETRY_IF_STALE|
|
int flags = BCH_READ_RETRY_IF_STALE|
|
||||||
BCH_READ_MAY_PROMOTE;
|
BCH_READ_MAY_PROMOTE;
|
||||||
|
u32 snapshot;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
rbio->c = c;
|
rbio->c = c;
|
||||||
rbio->start_time = local_clock();
|
rbio->start_time = local_clock();
|
||||||
|
rbio->subvol = inum.subvol;
|
||||||
|
|
||||||
bch2_bkey_buf_init(&sk);
|
bch2_bkey_buf_init(&sk);
|
||||||
retry:
|
retry:
|
||||||
bch2_trans_begin(trans);
|
bch2_trans_begin(trans);
|
||||||
|
iter = (struct btree_iter) { NULL };
|
||||||
|
|
||||||
|
ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
bch2_trans_iter_init(trans, &iter, BTREE_ID_extents,
|
||||||
|
SPOS(inum.inum, rbio->bio.bi_iter.bi_sector, snapshot),
|
||||||
|
BTREE_ITER_SLOTS|BTREE_ITER_FILTER_SNAPSHOTS);
|
||||||
while (1) {
|
while (1) {
|
||||||
struct bkey_s_c k;
|
struct bkey_s_c k;
|
||||||
unsigned bytes, sectors, offset_into_extent;
|
unsigned bytes, sectors, offset_into_extent;
|
||||||
@ -800,15 +812,15 @@ retry:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bch2_btree_iter_set_pos(iter,
|
bch2_btree_iter_set_pos(&iter,
|
||||||
POS(inum, rbio->bio.bi_iter.bi_sector));
|
POS(inum.inum, rbio->bio.bi_iter.bi_sector));
|
||||||
|
|
||||||
k = bch2_btree_iter_peek_slot(iter);
|
k = bch2_btree_iter_peek_slot(&iter);
|
||||||
ret = bkey_err(k);
|
ret = bkey_err(k);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
offset_into_extent = iter->pos.offset -
|
offset_into_extent = iter.pos.offset -
|
||||||
bkey_start_offset(k.k);
|
bkey_start_offset(k.k);
|
||||||
sectors = k.k->size - offset_into_extent;
|
sectors = k.k->size - offset_into_extent;
|
||||||
|
|
||||||
@ -838,7 +850,7 @@ retry:
|
|||||||
if (bkey_extent_is_allocation(k.k))
|
if (bkey_extent_is_allocation(k.k))
|
||||||
bch2_add_page_sectors(&rbio->bio, k);
|
bch2_add_page_sectors(&rbio->bio, k);
|
||||||
|
|
||||||
bch2_read_extent(trans, rbio, iter->pos,
|
bch2_read_extent(trans, rbio, iter.pos,
|
||||||
data_btree, k, offset_into_extent, flags);
|
data_btree, k, offset_into_extent, flags);
|
||||||
|
|
||||||
if (flags & BCH_READ_LAST_FRAGMENT)
|
if (flags & BCH_READ_LAST_FRAGMENT)
|
||||||
@ -847,12 +859,14 @@ retry:
|
|||||||
swap(rbio->bio.bi_iter.bi_size, bytes);
|
swap(rbio->bio.bi_iter.bi_size, bytes);
|
||||||
bio_advance(&rbio->bio, bytes);
|
bio_advance(&rbio->bio, bytes);
|
||||||
}
|
}
|
||||||
|
err:
|
||||||
|
bch2_trans_iter_exit(trans, &iter);
|
||||||
|
|
||||||
if (ret == -EINTR)
|
if (ret == -EINTR)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
bch_err_inum_ratelimited(c, inum,
|
bch_err_inum_ratelimited(c, inum.inum,
|
||||||
"read error %i from btree lookup", ret);
|
"read error %i from btree lookup", ret);
|
||||||
rbio->bio.bi_status = BLK_STS_IOERR;
|
rbio->bio.bi_status = BLK_STS_IOERR;
|
||||||
bio_endio(&rbio->bio);
|
bio_endio(&rbio->bio);
|
||||||
@ -867,7 +881,6 @@ void bch2_readahead(struct readahead_control *ractl)
|
|||||||
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
struct bch_fs *c = inode->v.i_sb->s_fs_info;
|
||||||
struct bch_io_opts opts = io_opts(c, &inode->ei_inode);
|
struct bch_io_opts opts = io_opts(c, &inode->ei_inode);
|
||||||
struct btree_trans trans;
|
struct btree_trans trans;
|
||||||
struct btree_iter iter;
|
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct readpages_iter readpages_iter;
|
struct readpages_iter readpages_iter;
|
||||||
int ret;
|
int ret;
|
||||||
@ -876,8 +889,6 @@ void bch2_readahead(struct readahead_control *ractl)
|
|||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
bch2_trans_init(&trans, c, 0, 0);
|
bch2_trans_init(&trans, c, 0, 0);
|
||||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents, POS_MIN,
|
|
||||||
BTREE_ITER_SLOTS);
|
|
||||||
|
|
||||||
bch2_pagecache_add_get(&inode->ei_pagecache_lock);
|
bch2_pagecache_add_get(&inode->ei_pagecache_lock);
|
||||||
|
|
||||||
@ -898,22 +909,20 @@ void bch2_readahead(struct readahead_control *ractl)
|
|||||||
rbio->bio.bi_end_io = bch2_readpages_end_io;
|
rbio->bio.bi_end_io = bch2_readpages_end_io;
|
||||||
BUG_ON(!bio_add_page(&rbio->bio, page, PAGE_SIZE, 0));
|
BUG_ON(!bio_add_page(&rbio->bio, page, PAGE_SIZE, 0));
|
||||||
|
|
||||||
bchfs_read(&trans, &iter, rbio, inode->v.i_ino,
|
bchfs_read(&trans, rbio, inode_inum(inode),
|
||||||
&readpages_iter);
|
&readpages_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bch2_pagecache_add_put(&inode->ei_pagecache_lock);
|
bch2_pagecache_add_put(&inode->ei_pagecache_lock);
|
||||||
|
|
||||||
bch2_trans_iter_exit(&trans, &iter);
|
|
||||||
bch2_trans_exit(&trans);
|
bch2_trans_exit(&trans);
|
||||||
kfree(readpages_iter.pages);
|
kfree(readpages_iter.pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __bchfs_readpage(struct bch_fs *c, struct bch_read_bio *rbio,
|
static void __bchfs_readpage(struct bch_fs *c, struct bch_read_bio *rbio,
|
||||||
u64 inum, struct page *page)
|
subvol_inum inum, struct page *page)
|
||||||
{
|
{
|
||||||
struct btree_trans trans;
|
struct btree_trans trans;
|
||||||
struct btree_iter iter;
|
|
||||||
|
|
||||||
bch2_page_state_create(page, __GFP_NOFAIL);
|
bch2_page_state_create(page, __GFP_NOFAIL);
|
||||||
|
|
||||||
@ -923,12 +932,7 @@ static void __bchfs_readpage(struct bch_fs *c, struct bch_read_bio *rbio,
|
|||||||
BUG_ON(!bio_add_page(&rbio->bio, page, PAGE_SIZE, 0));
|
BUG_ON(!bio_add_page(&rbio->bio, page, PAGE_SIZE, 0));
|
||||||
|
|
||||||
bch2_trans_init(&trans, c, 0, 0);
|
bch2_trans_init(&trans, c, 0, 0);
|
||||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents, POS_MIN,
|
bchfs_read(&trans, rbio, inum, NULL);
|
||||||
BTREE_ITER_SLOTS);
|
|
||||||
|
|
||||||
bchfs_read(&trans, &iter, rbio, inum, NULL);
|
|
||||||
|
|
||||||
bch2_trans_iter_exit(&trans, &iter);
|
|
||||||
bch2_trans_exit(&trans);
|
bch2_trans_exit(&trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -951,7 +955,7 @@ static int bch2_read_single_page(struct page *page,
|
|||||||
rbio->bio.bi_private = &done;
|
rbio->bio.bi_private = &done;
|
||||||
rbio->bio.bi_end_io = bch2_read_single_page_end_io;
|
rbio->bio.bi_end_io = bch2_read_single_page_end_io;
|
||||||
|
|
||||||
__bchfs_readpage(c, rbio, inode->v.i_ino, page);
|
__bchfs_readpage(c, rbio, inode_inum(inode), page);
|
||||||
wait_for_completion(&done);
|
wait_for_completion(&done);
|
||||||
|
|
||||||
ret = blk_status_to_errno(rbio->bio.bi_status);
|
ret = blk_status_to_errno(rbio->bio.bi_status);
|
||||||
@ -1096,6 +1100,7 @@ static void bch2_writepage_io_alloc(struct bch_fs *c,
|
|||||||
op->nr_replicas = nr_replicas;
|
op->nr_replicas = nr_replicas;
|
||||||
op->res.nr_replicas = nr_replicas;
|
op->res.nr_replicas = nr_replicas;
|
||||||
op->write_point = writepoint_hashed(inode->ei_last_dirtied);
|
op->write_point = writepoint_hashed(inode->ei_last_dirtied);
|
||||||
|
op->subvol = inode->ei_subvol;
|
||||||
op->pos = POS(inode->v.i_ino, sector);
|
op->pos = POS(inode->v.i_ino, sector);
|
||||||
op->end_io = bch2_writepage_io_done;
|
op->end_io = bch2_writepage_io_done;
|
||||||
op->wbio.bio.bi_iter.bi_sector = sector;
|
op->wbio.bio.bi_iter.bi_sector = sector;
|
||||||
@ -1733,7 +1738,7 @@ start:
|
|||||||
if (iter->count)
|
if (iter->count)
|
||||||
closure_get(&dio->cl);
|
closure_get(&dio->cl);
|
||||||
|
|
||||||
bch2_read(c, rbio_init(bio, opts), inode->v.i_ino);
|
bch2_read(c, rbio_init(bio, opts), inode_inum(inode));
|
||||||
}
|
}
|
||||||
|
|
||||||
iter->count += shorten;
|
iter->count += shorten;
|
||||||
@ -1816,7 +1821,8 @@ retry:
|
|||||||
if (bkey_cmp(bkey_start_pos(k.k), POS(inum.inum, end)) >= 0)
|
if (bkey_cmp(bkey_start_pos(k.k), POS(inum.inum, end)) >= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (nr_replicas > bch2_bkey_replicas(c, k) ||
|
if (k.k->p.snapshot != snapshot ||
|
||||||
|
nr_replicas > bch2_bkey_replicas(c, k) ||
|
||||||
(!compressed && bch2_bkey_sectors_compressed(k))) {
|
(!compressed && bch2_bkey_sectors_compressed(k))) {
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
@ -1944,6 +1950,7 @@ static long bch2_dio_write_loop(struct dio_write *dio)
|
|||||||
op_journal_seq_set(&dio->op, &inode->ei_journal_seq);
|
op_journal_seq_set(&dio->op, &inode->ei_journal_seq);
|
||||||
dio->op.write_point = writepoint_hashed((unsigned long) current);
|
dio->op.write_point = writepoint_hashed((unsigned long) current);
|
||||||
dio->op.nr_replicas = dio->op.opts.data_replicas;
|
dio->op.nr_replicas = dio->op.opts.data_replicas;
|
||||||
|
dio->op.subvol = inode->ei_subvol;
|
||||||
dio->op.pos = POS(inode->v.i_ino, (u64) req->ki_pos >> 9);
|
dio->op.pos = POS(inode->v.i_ino, (u64) req->ki_pos >> 9);
|
||||||
|
|
||||||
if ((req->ki_flags & IOCB_DSYNC) &&
|
if ((req->ki_flags & IOCB_DSYNC) &&
|
||||||
@ -2438,7 +2445,7 @@ int bch2_truncate(struct mnt_idmap *idmap,
|
|||||||
|
|
||||||
truncate_setsize(&inode->v, iattr->ia_size);
|
truncate_setsize(&inode->v, iattr->ia_size);
|
||||||
|
|
||||||
ret = bch2_fpunch(c, inode->v.i_ino,
|
ret = bch2_fpunch(c, inode_inum(inode),
|
||||||
round_up(iattr->ia_size, block_bytes(c)) >> 9,
|
round_up(iattr->ia_size, block_bytes(c)) >> 9,
|
||||||
U64_MAX, &inode->ei_journal_seq, &i_sectors_delta);
|
U64_MAX, &inode->ei_journal_seq, &i_sectors_delta);
|
||||||
i_sectors_acct(c, inode, NULL, i_sectors_delta);
|
i_sectors_acct(c, inode, NULL, i_sectors_delta);
|
||||||
@ -2498,7 +2505,7 @@ static long bchfs_fpunch(struct bch_inode_info *inode, loff_t offset, loff_t len
|
|||||||
if (discard_start < discard_end) {
|
if (discard_start < discard_end) {
|
||||||
s64 i_sectors_delta = 0;
|
s64 i_sectors_delta = 0;
|
||||||
|
|
||||||
ret = bch2_fpunch(c, inode->v.i_ino,
|
ret = bch2_fpunch(c, inode_inum(inode),
|
||||||
discard_start, discard_end,
|
discard_start, discard_end,
|
||||||
&inode->ei_journal_seq,
|
&inode->ei_journal_seq,
|
||||||
&i_sectors_delta);
|
&i_sectors_delta);
|
||||||
@ -2577,7 +2584,7 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode,
|
|||||||
} else {
|
} else {
|
||||||
s64 i_sectors_delta = 0;
|
s64 i_sectors_delta = 0;
|
||||||
|
|
||||||
ret = bch2_fpunch(c, inode->v.i_ino,
|
ret = bch2_fpunch(c, inode_inum(inode),
|
||||||
offset >> 9, (offset + len) >> 9,
|
offset >> 9, (offset + len) >> 9,
|
||||||
&inode->ei_journal_seq,
|
&inode->ei_journal_seq,
|
||||||
&i_sectors_delta);
|
&i_sectors_delta);
|
||||||
@ -2793,7 +2800,8 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
|
|||||||
reservation.v.nr_replicas = disk_res.nr_replicas;
|
reservation.v.nr_replicas = disk_res.nr_replicas;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bch2_extent_update(&trans, &iter, &reservation.k_i,
|
ret = bch2_extent_update(&trans, inode_inum(inode), &iter,
|
||||||
|
&reservation.k_i,
|
||||||
&disk_res, &inode->ei_journal_seq,
|
&disk_res, &inode->ei_journal_seq,
|
||||||
0, &i_sectors_delta, true);
|
0, &i_sectors_delta, true);
|
||||||
i_sectors_acct(c, inode, "a_res, i_sectors_delta);
|
i_sectors_acct(c, inode, "a_res, i_sectors_delta);
|
||||||
|
128
fs/bcachefs/io.c
128
fs/bcachefs/io.c
@ -27,6 +27,7 @@
|
|||||||
#include "keylist.h"
|
#include "keylist.h"
|
||||||
#include "move.h"
|
#include "move.h"
|
||||||
#include "rebalance.h"
|
#include "rebalance.h"
|
||||||
|
#include "subvolume.h"
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
#include "super-io.h"
|
#include "super-io.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
@ -230,7 +231,8 @@ int bch2_sum_sector_overwrites(struct btree_trans *trans,
|
|||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
if (!*usage_increasing &&
|
if (!*usage_increasing &&
|
||||||
(new_replicas > bch2_bkey_replicas(c, old) ||
|
(new->k.p.snapshot != old.k->p.snapshot ||
|
||||||
|
new_replicas > bch2_bkey_replicas(c, old) ||
|
||||||
(!new_compressed && bch2_bkey_sectors_compressed(old))))
|
(!new_compressed && bch2_bkey_sectors_compressed(old))))
|
||||||
*usage_increasing = true;
|
*usage_increasing = true;
|
||||||
|
|
||||||
@ -266,6 +268,7 @@ int bch2_sum_sector_overwrites(struct btree_trans *trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int bch2_extent_update(struct btree_trans *trans,
|
int bch2_extent_update(struct btree_trans *trans,
|
||||||
|
subvol_inum inum,
|
||||||
struct btree_iter *iter,
|
struct btree_iter *iter,
|
||||||
struct bkey_i *k,
|
struct bkey_i *k,
|
||||||
struct disk_reservation *disk_res,
|
struct disk_reservation *disk_res,
|
||||||
@ -324,11 +327,8 @@ int bch2_extent_update(struct btree_trans *trans,
|
|||||||
struct btree_iter inode_iter;
|
struct btree_iter inode_iter;
|
||||||
struct bch_inode_unpacked inode_u;
|
struct bch_inode_unpacked inode_u;
|
||||||
|
|
||||||
ret = bch2_inode_peek(trans, &inode_iter, &inode_u,
|
ret = bch2_inode_peek(trans, &inode_iter, &inode_u, inum,
|
||||||
(subvol_inum) {
|
BTREE_ITER_INTENT);
|
||||||
.subvol = BCACHEFS_ROOT_SUBVOL,
|
|
||||||
.inum = k->k.p.inode,
|
|
||||||
}, BTREE_ITER_INTENT);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -384,22 +384,37 @@ int bch2_extent_update(struct btree_trans *trans,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns -EINTR if we had to drop locks:
|
||||||
|
*/
|
||||||
int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter,
|
int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter,
|
||||||
struct bpos end, u64 *journal_seq,
|
subvol_inum inum, u64 end,
|
||||||
s64 *i_sectors_delta)
|
u64 *journal_seq, s64 *i_sectors_delta)
|
||||||
{
|
{
|
||||||
struct bch_fs *c = trans->c;
|
struct bch_fs *c = trans->c;
|
||||||
unsigned max_sectors = KEY_SIZE_MAX & (~0 << c->block_bits);
|
unsigned max_sectors = KEY_SIZE_MAX & (~0 << c->block_bits);
|
||||||
|
struct bpos end_pos = POS(inum.inum, end);
|
||||||
struct bkey_s_c k;
|
struct bkey_s_c k;
|
||||||
int ret = 0, ret2 = 0;
|
int ret = 0, ret2 = 0;
|
||||||
|
u32 snapshot;
|
||||||
|
|
||||||
while ((bch2_trans_begin(trans),
|
while (1) {
|
||||||
(k = bch2_btree_iter_peek(iter)).k) &&
|
|
||||||
bkey_cmp(iter->pos, end) < 0) {
|
|
||||||
struct disk_reservation disk_res =
|
struct disk_reservation disk_res =
|
||||||
bch2_disk_reservation_init(c, 0);
|
bch2_disk_reservation_init(c, 0);
|
||||||
struct bkey_i delete;
|
struct bkey_i delete;
|
||||||
|
|
||||||
|
bch2_trans_begin(trans);
|
||||||
|
|
||||||
|
ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
|
||||||
|
if (ret)
|
||||||
|
goto btree_err;
|
||||||
|
|
||||||
|
bch2_btree_iter_set_snapshot(iter, snapshot);
|
||||||
|
|
||||||
|
k = bch2_btree_iter_peek(iter);
|
||||||
|
if (bkey_cmp(iter->pos, end_pos) >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
ret = bkey_err(k);
|
ret = bkey_err(k);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto btree_err;
|
goto btree_err;
|
||||||
@ -409,9 +424,9 @@ int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter,
|
|||||||
|
|
||||||
/* create the biggest key we can */
|
/* create the biggest key we can */
|
||||||
bch2_key_resize(&delete.k, max_sectors);
|
bch2_key_resize(&delete.k, max_sectors);
|
||||||
bch2_cut_back(end, &delete);
|
bch2_cut_back(end_pos, &delete);
|
||||||
|
|
||||||
ret = bch2_extent_update(trans, iter, &delete,
|
ret = bch2_extent_update(trans, inum, iter, &delete,
|
||||||
&disk_res, journal_seq,
|
&disk_res, journal_seq,
|
||||||
0, i_sectors_delta, false);
|
0, i_sectors_delta, false);
|
||||||
bch2_disk_reservation_put(c, &disk_res);
|
bch2_disk_reservation_put(c, &disk_res);
|
||||||
@ -424,36 +439,31 @@ btree_err:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bkey_cmp(iter->pos, end) > 0) {
|
if (bkey_cmp(iter->pos, end_pos) > 0)
|
||||||
bch2_btree_iter_set_pos(iter, end);
|
bch2_btree_iter_set_pos(iter, end_pos);
|
||||||
ret = bch2_btree_iter_traverse(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret ?: ret2;
|
return ret ?: ret2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_fpunch(struct bch_fs *c, u64 inum, u64 start, u64 end,
|
int bch2_fpunch(struct bch_fs *c, subvol_inum inum, u64 start, u64 end,
|
||||||
u64 *journal_seq, s64 *i_sectors_delta)
|
u64 *journal_seq, s64 *i_sectors_delta)
|
||||||
{
|
{
|
||||||
struct btree_trans trans;
|
struct btree_trans trans;
|
||||||
struct btree_iter iter;
|
struct btree_iter iter;
|
||||||
int ret = 0;
|
int ret;
|
||||||
|
|
||||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024);
|
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024);
|
||||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
||||||
POS(inum, start),
|
POS(inum.inum, start),
|
||||||
BTREE_ITER_INTENT);
|
BTREE_ITER_INTENT);
|
||||||
|
|
||||||
ret = bch2_fpunch_at(&trans, &iter, POS(inum, end),
|
ret = bch2_fpunch_at(&trans, &iter, inum, end,
|
||||||
journal_seq, i_sectors_delta);
|
journal_seq, i_sectors_delta);
|
||||||
|
|
||||||
bch2_trans_iter_exit(&trans, &iter);
|
bch2_trans_iter_exit(&trans, &iter);
|
||||||
bch2_trans_exit(&trans);
|
bch2_trans_exit(&trans);
|
||||||
|
|
||||||
if (ret == -EINTR)
|
return ret == -EINTR ? 0 : ret;
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bch2_write_index_default(struct bch_write_op *op)
|
static int bch2_write_index_default(struct bch_write_op *op)
|
||||||
@ -464,40 +474,51 @@ static int bch2_write_index_default(struct bch_write_op *op)
|
|||||||
struct bkey_i *k = bch2_keylist_front(keys);
|
struct bkey_i *k = bch2_keylist_front(keys);
|
||||||
struct btree_trans trans;
|
struct btree_trans trans;
|
||||||
struct btree_iter iter;
|
struct btree_iter iter;
|
||||||
|
subvol_inum inum = {
|
||||||
|
.subvol = op->subvol,
|
||||||
|
.inum = k->k.p.inode,
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
BUG_ON(!inum.subvol);
|
||||||
|
|
||||||
bch2_bkey_buf_init(&sk);
|
bch2_bkey_buf_init(&sk);
|
||||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024);
|
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024);
|
||||||
|
|
||||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
|
||||||
bkey_start_pos(&k->k),
|
|
||||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
bch2_trans_begin(&trans);
|
bch2_trans_begin(&trans);
|
||||||
|
|
||||||
k = bch2_keylist_front(keys);
|
k = bch2_keylist_front(keys);
|
||||||
|
bch2_bkey_buf_copy(&sk, c, k);
|
||||||
|
|
||||||
k->k.p.snapshot = iter.snapshot;
|
ret = bch2_subvolume_get_snapshot(&trans, inum.subvol,
|
||||||
|
&sk.k->k.p.snapshot);
|
||||||
|
if (ret == -EINTR)
|
||||||
|
continue;
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
|
||||||
bch2_bkey_buf_realloc(&sk, c, k->k.u64s);
|
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
||||||
bkey_copy(sk.k, k);
|
bkey_start_pos(&sk.k->k),
|
||||||
bch2_cut_front(iter.pos, sk.k);
|
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
|
||||||
|
|
||||||
ret = bch2_extent_update(&trans, &iter, sk.k,
|
ret = bch2_extent_update(&trans, inum, &iter, sk.k,
|
||||||
&op->res, op_journal_seq(op),
|
&op->res, op_journal_seq(op),
|
||||||
op->new_i_size, &op->i_sectors_delta,
|
op->new_i_size, &op->i_sectors_delta,
|
||||||
op->flags & BCH_WRITE_CHECK_ENOSPC);
|
op->flags & BCH_WRITE_CHECK_ENOSPC);
|
||||||
|
bch2_trans_iter_exit(&trans, &iter);
|
||||||
|
|
||||||
if (ret == -EINTR)
|
if (ret == -EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (bkey_cmp(iter.pos, k->k.p) >= 0)
|
if (bkey_cmp(iter.pos, k->k.p) >= 0)
|
||||||
bch2_keylist_pop_front(keys);
|
bch2_keylist_pop_front(&op->insert_keys);
|
||||||
|
else
|
||||||
|
bch2_cut_front(iter.pos, k);
|
||||||
} while (!bch2_keylist_empty(keys));
|
} while (!bch2_keylist_empty(keys));
|
||||||
|
|
||||||
bch2_trans_iter_exit(&trans, &iter);
|
|
||||||
bch2_trans_exit(&trans);
|
bch2_trans_exit(&trans);
|
||||||
bch2_bkey_buf_exit(&sk, c);
|
bch2_bkey_buf_exit(&sk, c);
|
||||||
|
|
||||||
@ -1645,7 +1666,7 @@ static void bch2_rbio_done(struct bch_read_bio *rbio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void bch2_read_retry_nodecode(struct bch_fs *c, struct bch_read_bio *rbio,
|
static void bch2_read_retry_nodecode(struct bch_fs *c, struct bch_read_bio *rbio,
|
||||||
struct bvec_iter bvec_iter, u64 inode,
|
struct bvec_iter bvec_iter,
|
||||||
struct bch_io_failures *failed,
|
struct bch_io_failures *failed,
|
||||||
unsigned flags)
|
unsigned flags)
|
||||||
{
|
{
|
||||||
@ -1709,7 +1730,10 @@ static void bch2_rbio_retry(struct work_struct *work)
|
|||||||
struct bch_fs *c = rbio->c;
|
struct bch_fs *c = rbio->c;
|
||||||
struct bvec_iter iter = rbio->bvec_iter;
|
struct bvec_iter iter = rbio->bvec_iter;
|
||||||
unsigned flags = rbio->flags;
|
unsigned flags = rbio->flags;
|
||||||
u64 inode = rbio->read_pos.inode;
|
subvol_inum inum = {
|
||||||
|
.subvol = rbio->subvol,
|
||||||
|
.inum = rbio->read_pos.inode,
|
||||||
|
};
|
||||||
struct bch_io_failures failed = { .nr = 0 };
|
struct bch_io_failures failed = { .nr = 0 };
|
||||||
|
|
||||||
trace_read_retry(&rbio->bio);
|
trace_read_retry(&rbio->bio);
|
||||||
@ -1725,12 +1749,12 @@ static void bch2_rbio_retry(struct work_struct *work)
|
|||||||
flags &= ~BCH_READ_MAY_PROMOTE;
|
flags &= ~BCH_READ_MAY_PROMOTE;
|
||||||
|
|
||||||
if (flags & BCH_READ_NODECODE) {
|
if (flags & BCH_READ_NODECODE) {
|
||||||
bch2_read_retry_nodecode(c, rbio, iter, inode, &failed, flags);
|
bch2_read_retry_nodecode(c, rbio, iter, &failed, flags);
|
||||||
} else {
|
} else {
|
||||||
flags &= ~BCH_READ_LAST_FRAGMENT;
|
flags &= ~BCH_READ_LAST_FRAGMENT;
|
||||||
flags |= BCH_READ_MUST_CLONE;
|
flags |= BCH_READ_MUST_CLONE;
|
||||||
|
|
||||||
__bch2_read(c, rbio, iter, inode, &failed, flags);
|
__bch2_read(c, rbio, iter, inum, &failed, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2174,6 +2198,7 @@ get_bio:
|
|||||||
/* XXX: only initialize this if needed */
|
/* XXX: only initialize this if needed */
|
||||||
rbio->devs_have = bch2_bkey_devs(k);
|
rbio->devs_have = bch2_bkey_devs(k);
|
||||||
rbio->pick = pick;
|
rbio->pick = pick;
|
||||||
|
rbio->subvol = orig->subvol;
|
||||||
rbio->read_pos = read_pos;
|
rbio->read_pos = read_pos;
|
||||||
rbio->data_btree = data_btree;
|
rbio->data_btree = data_btree;
|
||||||
rbio->data_pos = data_pos;
|
rbio->data_pos = data_pos;
|
||||||
@ -2281,25 +2306,31 @@ out_read_done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void __bch2_read(struct bch_fs *c, struct bch_read_bio *rbio,
|
void __bch2_read(struct bch_fs *c, struct bch_read_bio *rbio,
|
||||||
struct bvec_iter bvec_iter, u64 inode,
|
struct bvec_iter bvec_iter, subvol_inum inum,
|
||||||
struct bch_io_failures *failed, unsigned flags)
|
struct bch_io_failures *failed, unsigned flags)
|
||||||
{
|
{
|
||||||
struct btree_trans trans;
|
struct btree_trans trans;
|
||||||
struct btree_iter iter;
|
struct btree_iter iter;
|
||||||
struct bkey_buf sk;
|
struct bkey_buf sk;
|
||||||
struct bkey_s_c k;
|
struct bkey_s_c k;
|
||||||
|
u32 snapshot;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BUG_ON(flags & BCH_READ_NODECODE);
|
BUG_ON(flags & BCH_READ_NODECODE);
|
||||||
|
|
||||||
bch2_bkey_buf_init(&sk);
|
bch2_bkey_buf_init(&sk);
|
||||||
bch2_trans_init(&trans, c, 0, 0);
|
bch2_trans_init(&trans, c, 0, 0);
|
||||||
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
|
||||||
POS(inode, bvec_iter.bi_sector),
|
|
||||||
BTREE_ITER_SLOTS);
|
|
||||||
retry:
|
retry:
|
||||||
bch2_trans_begin(&trans);
|
bch2_trans_begin(&trans);
|
||||||
|
iter = (struct btree_iter) { NULL };
|
||||||
|
|
||||||
|
ret = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents,
|
||||||
|
SPOS(inum.inum, bvec_iter.bi_sector, snapshot),
|
||||||
|
BTREE_ITER_SLOTS|BTREE_ITER_FILTER_SNAPSHOTS);
|
||||||
while (1) {
|
while (1) {
|
||||||
unsigned bytes, sectors, offset_into_extent;
|
unsigned bytes, sectors, offset_into_extent;
|
||||||
enum btree_id data_btree = BTREE_ID_extents;
|
enum btree_id data_btree = BTREE_ID_extents;
|
||||||
@ -2314,7 +2345,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bch2_btree_iter_set_pos(&iter,
|
bch2_btree_iter_set_pos(&iter,
|
||||||
POS(inode, bvec_iter.bi_sector));
|
POS(inum.inum, bvec_iter.bi_sector));
|
||||||
|
|
||||||
k = bch2_btree_iter_peek_slot(&iter);
|
k = bch2_btree_iter_peek_slot(&iter);
|
||||||
ret = bkey_err(k);
|
ret = bkey_err(k);
|
||||||
@ -2364,16 +2395,17 @@ retry:
|
|||||||
swap(bvec_iter.bi_size, bytes);
|
swap(bvec_iter.bi_size, bytes);
|
||||||
bio_advance_iter(&rbio->bio, &bvec_iter, bytes);
|
bio_advance_iter(&rbio->bio, &bvec_iter, bytes);
|
||||||
}
|
}
|
||||||
|
err:
|
||||||
|
bch2_trans_iter_exit(&trans, &iter);
|
||||||
|
|
||||||
if (ret == -EINTR || ret == READ_RETRY || ret == READ_RETRY_AVOID)
|
if (ret == -EINTR || ret == READ_RETRY || ret == READ_RETRY_AVOID)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
bch2_trans_iter_exit(&trans, &iter);
|
|
||||||
bch2_trans_exit(&trans);
|
bch2_trans_exit(&trans);
|
||||||
bch2_bkey_buf_exit(&sk, c);
|
bch2_bkey_buf_exit(&sk, c);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
bch_err_inum_ratelimited(c, inode,
|
bch_err_inum_ratelimited(c, inum.inum,
|
||||||
"read error %i from btree lookup", ret);
|
"read error %i from btree lookup", ret);
|
||||||
rbio->bio.bi_status = BLK_STS_IOERR;
|
rbio->bio.bi_status = BLK_STS_IOERR;
|
||||||
bch2_rbio_done(rbio);
|
bch2_rbio_done(rbio);
|
||||||
|
@ -83,12 +83,13 @@ static inline struct workqueue_struct *index_update_wq(struct bch_write_op *op)
|
|||||||
|
|
||||||
int bch2_sum_sector_overwrites(struct btree_trans *, struct btree_iter *,
|
int bch2_sum_sector_overwrites(struct btree_trans *, struct btree_iter *,
|
||||||
struct bkey_i *, bool *, bool *, s64 *, s64 *);
|
struct bkey_i *, bool *, bool *, s64 *, s64 *);
|
||||||
int bch2_extent_update(struct btree_trans *, struct btree_iter *,
|
int bch2_extent_update(struct btree_trans *, subvol_inum,
|
||||||
struct bkey_i *, struct disk_reservation *,
|
struct btree_iter *, struct bkey_i *,
|
||||||
u64 *, u64, s64 *, bool);
|
struct disk_reservation *, u64 *, u64, s64 *, bool);
|
||||||
|
|
||||||
int bch2_fpunch_at(struct btree_trans *, struct btree_iter *,
|
int bch2_fpunch_at(struct btree_trans *, struct btree_iter *,
|
||||||
struct bpos, u64 *, s64 *);
|
subvol_inum, u64, u64 *, s64 *);
|
||||||
int bch2_fpunch(struct bch_fs *c, u64, u64, u64, u64 *, s64 *);
|
int bch2_fpunch(struct bch_fs *c, subvol_inum, u64, u64, u64 *, s64 *);
|
||||||
|
|
||||||
static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c,
|
static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c,
|
||||||
struct bch_io_opts opts)
|
struct bch_io_opts opts)
|
||||||
@ -108,6 +109,7 @@ static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c,
|
|||||||
op->devs_have.nr = 0;
|
op->devs_have.nr = 0;
|
||||||
op->target = 0;
|
op->target = 0;
|
||||||
op->opts = opts;
|
op->opts = opts;
|
||||||
|
op->subvol = 0;
|
||||||
op->pos = POS_MAX;
|
op->pos = POS_MAX;
|
||||||
op->version = ZERO_VERSION;
|
op->version = ZERO_VERSION;
|
||||||
op->write_point = (struct write_point_specifier) { 0 };
|
op->write_point = (struct write_point_specifier) { 0 };
|
||||||
@ -174,10 +176,10 @@ static inline void bch2_read_extent(struct btree_trans *trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void __bch2_read(struct bch_fs *, struct bch_read_bio *, struct bvec_iter,
|
void __bch2_read(struct bch_fs *, struct bch_read_bio *, struct bvec_iter,
|
||||||
u64, struct bch_io_failures *, unsigned flags);
|
subvol_inum, struct bch_io_failures *, unsigned flags);
|
||||||
|
|
||||||
static inline void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio,
|
static inline void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio,
|
||||||
u64 inode)
|
subvol_inum inum)
|
||||||
{
|
{
|
||||||
struct bch_io_failures failed = { .nr = 0 };
|
struct bch_io_failures failed = { .nr = 0 };
|
||||||
|
|
||||||
@ -185,8 +187,9 @@ static inline void bch2_read(struct bch_fs *c, struct bch_read_bio *rbio,
|
|||||||
|
|
||||||
rbio->c = c;
|
rbio->c = c;
|
||||||
rbio->start_time = local_clock();
|
rbio->start_time = local_clock();
|
||||||
|
rbio->subvol = inum.subvol;
|
||||||
|
|
||||||
__bch2_read(c, rbio, rbio->bio.bi_iter, inode, &failed,
|
__bch2_read(c, rbio, rbio->bio.bi_iter, inum, &failed,
|
||||||
BCH_READ_RETRY_IF_STALE|
|
BCH_READ_RETRY_IF_STALE|
|
||||||
BCH_READ_MAY_PROMOTE|
|
BCH_READ_MAY_PROMOTE|
|
||||||
BCH_READ_USER_MAPPED);
|
BCH_READ_USER_MAPPED);
|
||||||
|
@ -62,6 +62,7 @@ struct bch_read_bio {
|
|||||||
/*
|
/*
|
||||||
* pos we read from - different from data_pos for indirect extents:
|
* pos we read from - different from data_pos for indirect extents:
|
||||||
*/
|
*/
|
||||||
|
u32 subvol;
|
||||||
struct bpos read_pos;
|
struct bpos read_pos;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -124,6 +125,7 @@ struct bch_write_op {
|
|||||||
u16 nonce;
|
u16 nonce;
|
||||||
struct bch_io_opts opts;
|
struct bch_io_opts opts;
|
||||||
|
|
||||||
|
u32 subvol;
|
||||||
struct bpos pos;
|
struct bpos pos;
|
||||||
struct bversion version;
|
struct bversion version;
|
||||||
|
|
||||||
|
@ -212,6 +212,7 @@ s64 bch2_remap_range(struct bch_fs *c,
|
|||||||
struct bpos dst_end = dst_start, src_end = src_start;
|
struct bpos dst_end = dst_start, src_end = src_start;
|
||||||
struct bpos src_want;
|
struct bpos src_want;
|
||||||
u64 dst_done;
|
u64 dst_done;
|
||||||
|
u32 dst_snapshot, src_snapshot;
|
||||||
int ret = 0, ret2 = 0;
|
int ret = 0, ret2 = 0;
|
||||||
|
|
||||||
if (!percpu_ref_tryget(&c->writes))
|
if (!percpu_ref_tryget(&c->writes))
|
||||||
@ -243,15 +244,19 @@ s64 bch2_remap_range(struct bch_fs *c,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = bch2_subvolume_get_snapshot(&trans, src_inum.subvol,
|
ret = bch2_subvolume_get_snapshot(&trans, src_inum.subvol,
|
||||||
&src_iter.snapshot);
|
&src_snapshot);
|
||||||
if (ret)
|
if (ret)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
bch2_btree_iter_set_snapshot(&src_iter, src_snapshot);
|
||||||
|
|
||||||
ret = bch2_subvolume_get_snapshot(&trans, dst_inum.subvol,
|
ret = bch2_subvolume_get_snapshot(&trans, dst_inum.subvol,
|
||||||
&dst_iter.snapshot);
|
&dst_snapshot);
|
||||||
if (ret)
|
if (ret)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
bch2_btree_iter_set_snapshot(&dst_iter, dst_snapshot);
|
||||||
|
|
||||||
dst_done = dst_iter.pos.offset - dst_start.offset;
|
dst_done = dst_iter.pos.offset - dst_start.offset;
|
||||||
src_want = POS(src_start.inode, src_start.offset + dst_done);
|
src_want = POS(src_start.inode, src_start.offset + dst_done);
|
||||||
bch2_btree_iter_set_pos(&src_iter, src_want);
|
bch2_btree_iter_set_pos(&src_iter, src_want);
|
||||||
@ -262,11 +267,11 @@ s64 bch2_remap_range(struct bch_fs *c,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bkey_cmp(src_want, src_iter.pos) < 0) {
|
if (bkey_cmp(src_want, src_iter.pos) < 0) {
|
||||||
ret = bch2_fpunch_at(&trans, &dst_iter,
|
ret = bch2_fpunch_at(&trans, &dst_iter, dst_inum,
|
||||||
bpos_min(dst_end,
|
min(dst_end.offset,
|
||||||
POS(dst_iter.pos.inode, dst_iter.pos.offset +
|
dst_iter.pos.offset +
|
||||||
src_iter.pos.offset - src_want.offset)),
|
src_iter.pos.offset - src_want.offset),
|
||||||
journal_seq, i_sectors_delta);
|
journal_seq, i_sectors_delta);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,8 +308,9 @@ s64 bch2_remap_range(struct bch_fs *c,
|
|||||||
bch2_key_resize(&new_dst.k->k,
|
bch2_key_resize(&new_dst.k->k,
|
||||||
min(src_k.k->p.offset - src_want.offset,
|
min(src_k.k->p.offset - src_want.offset,
|
||||||
dst_end.offset - dst_iter.pos.offset));
|
dst_end.offset - dst_iter.pos.offset));
|
||||||
ret = bch2_extent_update(&trans, &dst_iter, new_dst.k,
|
|
||||||
&disk_res, journal_seq,
|
ret = bch2_extent_update(&trans, dst_inum, &dst_iter,
|
||||||
|
new_dst.k, &disk_res, journal_seq,
|
||||||
new_i_size, i_sectors_delta,
|
new_i_size, i_sectors_delta,
|
||||||
true);
|
true);
|
||||||
bch2_disk_reservation_put(c, &disk_res);
|
bch2_disk_reservation_put(c, &disk_res);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user