diff options
-rw-r--r-- | fs/bcachefs/fs-io.c | 156 | ||||
-rw-r--r-- | fs/bcachefs/fs-io.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/io.c | 71 | ||||
-rw-r--r-- | fs/bcachefs/io.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/reflink.c | 53 | ||||
-rw-r--r-- | fs/bcachefs/reflink.h | 6 |
6 files changed, 163 insertions, 129 deletions
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index 92cab285698c..19793745edf9 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -2145,78 +2145,6 @@ out: /* truncate: */ -int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter, - struct bpos end, struct bch_inode_info *inode) -{ - struct bch_fs *c = trans->c; - unsigned max_sectors = KEY_SIZE_MAX & (~0 << c->block_bits); - struct bkey_s_c k; - int ret = 0, ret2 = 0; - - while ((k = bch2_btree_iter_peek(iter)).k && - bkey_cmp(iter->pos, end) < 0) { - struct disk_reservation disk_res = - bch2_disk_reservation_init(c, 0); - struct bkey_i delete; - - ret = bkey_err(k); - if (ret) - goto btree_err; - - bkey_init(&delete.k); - delete.k.p = iter->pos; - - /* create the biggest key we can */ - bch2_key_resize(&delete.k, max_sectors); - bch2_cut_back(end, &delete.k); - - bch2_trans_begin_updates(trans); - - ret = bchfs_extent_update(trans, inode, - &disk_res, NULL, iter, &delete, - 0, false, true, NULL); - bch2_disk_reservation_put(c, &disk_res); -btree_err: - if (ret == -EINTR) { - ret2 = ret; - ret = 0; - } - if (ret) - break; - } - - if (bkey_cmp(iter->pos, end) > 0) { - bch2_btree_iter_set_pos(iter, end); - ret = bch2_btree_iter_traverse(iter); - } - - return ret ?: ret2; -} - -static int __bch2_fpunch(struct bch_fs *c, struct bch_inode_info *inode, - u64 start_offset, u64 end_offset) -{ - struct btree_trans trans; - struct btree_iter *iter; - int ret = 0; - - bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024); - - iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS, - POS(inode->v.i_ino, start_offset), - BTREE_ITER_INTENT); - - ret = bch2_fpunch_at(&trans, iter, - POS(inode->v.i_ino, end_offset), inode); - - bch2_trans_exit(&trans); - - if (ret == -EINTR) - ret = 0; - - return ret; -} - static inline int range_has_data(struct bch_fs *c, struct bpos start, struct bpos end) @@ -2388,6 +2316,7 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr) struct btree_trans trans; struct btree_iter *iter; u64 new_i_size = iattr->ia_size; + s64 i_sectors_delta = 0; int ret = 0; inode_dio_wait(&inode->v); @@ -2447,9 +2376,11 @@ int bch2_truncate(struct bch_inode_info *inode, struct iattr *iattr) truncate_setsize(&inode->v, iattr->ia_size); - ret = __bch2_fpunch(c, inode, + ret = bch2_fpunch(c, inode->v.i_ino, round_up(iattr->ia_size, block_bytes(c)) >> 9, - U64_MAX); + U64_MAX, &inode->ei_journal_seq, &i_sectors_delta); + i_sectors_acct(c, inode, NULL, i_sectors_delta); + if (unlikely(ret)) goto err; @@ -2467,7 +2398,7 @@ err: /* fallocate: */ -static long bch2_fpunch(struct bch_inode_info *inode, loff_t offset, loff_t len) +static long bchfs_fpunch(struct bch_inode_info *inode, loff_t offset, loff_t len) { struct bch_fs *c = inode->v.i_sb->s_fs_info; u64 discard_start = round_up(offset, block_bytes(c)) >> 9; @@ -2495,8 +2426,15 @@ static long bch2_fpunch(struct bch_inode_info *inode, loff_t offset, loff_t len) truncate_pagecache_range(&inode->v, offset, offset + len - 1); - if (discard_start < discard_end) - ret = __bch2_fpunch(c, inode, discard_start, discard_end); + if (discard_start < discard_end) { + s64 i_sectors_delta = 0; + + ret = bch2_fpunch(c, inode->v.i_ino, + discard_start, discard_end, + &inode->ei_journal_seq, + &i_sectors_delta); + i_sectors_acct(c, inode, NULL, i_sectors_delta); + } err: bch2_pagecache_block_put(&inode->ei_pagecache_lock); inode_unlock(&inode->v); @@ -2504,7 +2442,7 @@ err: return ret; } -static long bch2_fcollapse_finsert(struct bch_inode_info *inode, +static long bchfs_fcollapse_finsert(struct bch_inode_info *inode, loff_t offset, loff_t len, bool insert) { @@ -2564,8 +2502,14 @@ static long bch2_fcollapse_finsert(struct bch_inode_info *inode, ATTR_MTIME|ATTR_CTIME); mutex_unlock(&inode->ei_update_lock); } else { - ret = __bch2_fpunch(c, inode, offset >> 9, - (offset + len) >> 9); + s64 i_sectors_delta = 0; + + ret = bch2_fpunch(c, inode->v.i_ino, + offset >> 9, (offset + len) >> 9, + &inode->ei_journal_seq, + &i_sectors_delta); + i_sectors_acct(c, inode, NULL, i_sectors_delta); + if (ret) goto err; } @@ -2715,8 +2659,8 @@ err: return ret; } -static long bch2_fallocate(struct bch_inode_info *inode, int mode, - loff_t offset, loff_t len) +static long bchfs_fallocate(struct bch_inode_info *inode, int mode, + loff_t offset, loff_t len) { struct address_space *mapping = inode->v.i_mapping; struct bch_fs *c = inode->v.i_sb->s_fs_info; @@ -2765,6 +2709,7 @@ static long bch2_fallocate(struct bch_inode_info *inode, int mode, end_pos = POS(inode->v.i_ino, block_end >> 9); while (bkey_cmp(iter->pos, end_pos) < 0) { + s64 i_sectors_delta = 0; struct disk_reservation disk_res = { 0 }; struct quota_res quota_res = { 0 }; struct bkey_i_reservation reservation; @@ -2818,10 +2763,10 @@ static long bch2_fallocate(struct bch_inode_info *inode, int mode, bch2_trans_begin_updates(&trans); - ret = bchfs_extent_update(&trans, inode, - &disk_res, "a_res, - iter, &reservation.k_i, - 0, true, true, NULL); + ret = bch2_extent_update(&trans, iter, &reservation.k_i, + &disk_res, &inode->ei_journal_seq, + 0, &i_sectors_delta); + i_sectors_acct(c, inode, "a_res, i_sectors_delta); bkey_err: bch2_quota_reservation_put(c, inode, "a_res); bch2_disk_reservation_put(c, &disk_res); @@ -2887,16 +2832,16 @@ long bch2_fallocate_dispatch(struct file *file, int mode, struct bch_inode_info *inode = file_bch_inode(file); if (!(mode & ~(FALLOC_FL_KEEP_SIZE|FALLOC_FL_ZERO_RANGE))) - return bch2_fallocate(inode, mode, offset, len); + return bchfs_fallocate(inode, mode, offset, len); if (mode == (FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE)) - return bch2_fpunch(inode, offset, len); + return bchfs_fpunch(inode, offset, len); if (mode == FALLOC_FL_INSERT_RANGE) - return bch2_fcollapse_finsert(inode, offset, len, true); + return bchfs_fcollapse_finsert(inode, offset, len, true); if (mode == FALLOC_FL_COLLAPSE_RANGE) - return bch2_fcollapse_finsert(inode, offset, len, false); + return bchfs_fcollapse_finsert(inode, offset, len, false); return -EOPNOTSUPP; } @@ -2941,6 +2886,7 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, struct bch_inode_info *src = file_bch_inode(file_src); struct bch_inode_info *dst = file_bch_inode(file_dst); struct bch_fs *c = src->v.i_sb->s_fs_info; + s64 i_sectors_delta = 0; loff_t ret = 0; loff_t aligned_len; @@ -2960,6 +2906,8 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, bch2_lock_inodes(INODE_LOCK|INODE_PAGECACHE_BLOCK, src, dst); + file_update_time(file_dst); + inode_dio_wait(&src->v); inode_dio_wait(&dst->v); @@ -2967,26 +2915,40 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, file_dst, pos_dst, &len, remap_flags); if (ret < 0 || len == 0) - goto out_unlock; + goto err; aligned_len = round_up(len, block_bytes(c)); ret = write_invalidate_inode_pages_range(dst->v.i_mapping, pos_dst, pos_dst + aligned_len); if (ret) - goto out_unlock; + goto err; mark_range_unallocated(src, pos_src, pos_src + aligned_len); - ret = bch2_remap_range(c, dst, + ret = bch2_remap_range(c, POS(dst->v.i_ino, pos_dst >> 9), POS(src->v.i_ino, pos_src >> 9), aligned_len >> 9, - pos_dst + len); - if (ret > 0) - ret = min(ret << 9, len); + &dst->ei_journal_seq, + pos_dst + len, &i_sectors_delta); + if (ret < 0) + goto err; -out_unlock: + ret <<= 9; + /* + * due to alignment, we might have remapped slightly more than requsted + */ + ret = min(ret, len); + + /* XXX get a quota reservation */ + i_sectors_acct(c, dst, NULL, i_sectors_delta); + + spin_lock(&dst->v.i_lock); + if (pos_dst + len > dst->v.i_size) + i_size_write(&dst->v, pos_dst + len); + spin_unlock(&dst->v.i_lock); +err: bch2_unlock_inodes(INODE_LOCK|INODE_PAGECACHE_BLOCK, src, dst); return ret; diff --git a/fs/bcachefs/fs-io.h b/fs/bcachefs/fs-io.h index 090d1c86de37..f823810d4971 100644 --- a/fs/bcachefs/fs-io.h +++ b/fs/bcachefs/fs-io.h @@ -18,8 +18,6 @@ int bchfs_extent_update(struct btree_trans *, struct btree_iter *, struct bkey_i *, u64, bool, bool, s64 *); -int bch2_fpunch_at(struct btree_trans *, struct btree_iter *, - struct bpos, struct bch_inode_info *); int __must_check bch2_write_inode_size(struct bch_fs *, struct bch_inode_info *, diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c index a9b1c21dd9a7..c60e52fbf4fe 100644 --- a/fs/bcachefs/io.c +++ b/fs/bcachefs/io.c @@ -319,6 +319,77 @@ int bch2_extent_update(struct btree_trans *trans, return ret; } +int bch2_fpunch_at(struct btree_trans *trans, struct btree_iter *iter, + struct bpos end, u64 *journal_seq, + s64 *i_sectors_delta) +{ + struct bch_fs *c = trans->c; + unsigned max_sectors = KEY_SIZE_MAX & (~0 << c->block_bits); + struct bkey_s_c k; + int ret = 0, ret2 = 0; + + while ((k = bch2_btree_iter_peek(iter)).k && + bkey_cmp(iter->pos, end) < 0) { + struct disk_reservation disk_res = + bch2_disk_reservation_init(c, 0); + struct bkey_i delete; + + ret = bkey_err(k); + if (ret) + goto btree_err; + + bkey_init(&delete.k); + delete.k.p = iter->pos; + + /* create the biggest key we can */ + bch2_key_resize(&delete.k, max_sectors); + bch2_cut_back(end, &delete.k); + + bch2_trans_begin_updates(trans); + + ret = bch2_extent_update(trans, iter, &delete, + &disk_res, journal_seq, + 0, i_sectors_delta); + bch2_disk_reservation_put(c, &disk_res); +btree_err: + if (ret == -EINTR) { + ret2 = ret; + ret = 0; + } + if (ret) + break; + } + + if (bkey_cmp(iter->pos, end) > 0) { + bch2_btree_iter_set_pos(iter, end); + ret = bch2_btree_iter_traverse(iter); + } + + return ret ?: ret2; +} + +int bch2_fpunch(struct bch_fs *c, u64 inum, u64 start, u64 end, + u64 *journal_seq, s64 *i_sectors_delta) +{ + struct btree_trans trans; + struct btree_iter *iter; + int ret = 0; + + bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024); + iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS, + POS(inum, start), + BTREE_ITER_INTENT); + + ret = bch2_fpunch_at(&trans, iter, POS(inum, end), + journal_seq, i_sectors_delta); + bch2_trans_exit(&trans); + + if (ret == -EINTR) + ret = 0; + + return ret; +} + /* Writes */ void bch2_submit_wbio_replicas(struct bch_write_bio *wbio, struct bch_fs *c, diff --git a/fs/bcachefs/io.h b/fs/bcachefs/io.h index e53f9ecc082d..97cc661420c6 100644 --- a/fs/bcachefs/io.h +++ b/fs/bcachefs/io.h @@ -61,6 +61,10 @@ static inline struct workqueue_struct *index_update_wq(struct bch_write_op *op) int bch2_extent_update(struct btree_trans *, struct btree_iter *, struct bkey_i *, struct disk_reservation *, u64 *, u64, s64 *); +int bch2_fpunch_at(struct btree_trans *, struct btree_iter *, + struct bpos, u64 *, s64 *); +int bch2_fpunch(struct bch_fs *c, u64, u64, u64, u64 *, s64 *); + int bch2_write_index_default(struct bch_write_op *); static inline void bch2_write_op_init(struct bch_write_op *op, struct bch_fs *c, diff --git a/fs/bcachefs/reflink.c b/fs/bcachefs/reflink.c index c9ff467cc0d9..4a4b17f93a2e 100644 --- a/fs/bcachefs/reflink.c +++ b/fs/bcachefs/reflink.c @@ -2,8 +2,8 @@ #include "bcachefs.h" #include "btree_update.h" #include "extents.h" -#include "fs.h" -#include "fs-io.h" +#include "inode.h" +#include "io.h" #include "reflink.h" #include <linux/sched/signal.h> @@ -70,12 +70,6 @@ void bch2_reflink_v_to_text(struct printbuf *out, struct bch_fs *c, bch2_bkey_ptrs_to_text(out, c, k); } -/* - * bch2_remap_range() depends on bch2_extent_update(), which depends on various - * things tied to the linux vfs for inode updates, for now: - */ -#ifndef NO_BCACHEFS_FS - static int bch2_make_extent_indirect(struct btree_trans *trans, struct btree_iter *extent_iter, struct bkey_i_extent *e) @@ -159,9 +153,9 @@ static struct bkey_s_c get_next_src(struct btree_iter *iter, struct bpos end) } s64 bch2_remap_range(struct bch_fs *c, - struct bch_inode_info *dst_inode, struct bpos dst_start, struct bpos src_start, - u64 remap_sectors, u64 new_i_size) + u64 remap_sectors, u64 *journal_seq, + u64 new_i_size, s64 *i_sectors_delta) { struct btree_trans trans; struct btree_iter *dst_iter, *src_iter; @@ -170,7 +164,7 @@ s64 bch2_remap_range(struct bch_fs *c, struct bpos dst_end = dst_start, src_end = src_start; struct bpos dst_want, src_want; u64 src_done, dst_done; - int ret = 0; + int ret = 0, ret2 = 0; if (!(c->sb.features & (1ULL << BCH_FEATURE_REFLINK))) { mutex_lock(&c->sb_lock); @@ -213,7 +207,7 @@ s64 bch2_remap_range(struct bch_fs *c, if (bkey_cmp(dst_iter->pos, dst_want) < 0) { ret = bch2_fpunch_at(&trans, dst_iter, dst_want, - dst_inode); + journal_seq, i_sectors_delta); if (ret) goto btree_err; continue; @@ -259,9 +253,9 @@ s64 bch2_remap_range(struct bch_fs *c, min(src_k.k->p.offset - src_iter->pos.offset, dst_end.offset - dst_iter->pos.offset)); - ret = bchfs_extent_update(&trans, dst_inode, NULL, NULL, - dst_iter, &new_dst.k, - new_i_size, false, true, NULL); + ret = bch2_extent_update(&trans, dst_iter, &new_dst.k, + NULL, journal_seq, + new_i_size, i_sectors_delta); if (ret) goto btree_err; @@ -282,17 +276,24 @@ err: dst_done = dst_iter->pos.offset - dst_start.offset; new_i_size = min(dst_iter->pos.offset << 9, new_i_size); - ret = bch2_trans_exit(&trans) ?: ret; + bch2_trans_begin(&trans); - mutex_lock(&dst_inode->ei_update_lock); - if (dst_inode->v.i_size < new_i_size) { - i_size_write(&dst_inode->v, new_i_size); - ret = bch2_write_inode_size(c, dst_inode, new_i_size, - ATTR_MTIME|ATTR_CTIME); - } - mutex_unlock(&dst_inode->ei_update_lock); + do { + struct bch_inode_unpacked inode_u; + struct btree_iter *inode_iter; - return dst_done ?: ret; -} + inode_iter = bch2_inode_peek(&trans, &inode_u, + dst_start.inode, BTREE_ITER_INTENT); + ret2 = PTR_ERR_OR_ZERO(inode_iter); -#endif /* NO_BCACHEFS_FS */ + if (!ret2 && + inode_u.bi_size < new_i_size) + ret2 = bch2_inode_write(&trans, inode_iter, &inode_u) ?: + bch2_trans_commit(&trans, NULL, journal_seq, + BTREE_INSERT_ATOMIC); + } while (ret2 == -EINTR); + + ret = bch2_trans_exit(&trans) ?: ret; + + return dst_done ?: ret ?: ret2; +} diff --git a/fs/bcachefs/reflink.h b/fs/bcachefs/reflink.h index 327618c36d33..ac23b855858c 100644 --- a/fs/bcachefs/reflink.h +++ b/fs/bcachefs/reflink.h @@ -24,9 +24,7 @@ void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *, .val_to_text = bch2_reflink_v_to_text, \ } -#ifndef NO_BCACHEFS_FS -s64 bch2_remap_range(struct bch_fs *, struct bch_inode_info *, - struct bpos, struct bpos, u64, u64); -#endif /* NO_BCACHEFS_FS */ +s64 bch2_remap_range(struct bch_fs *, struct bpos, struct bpos, + u64, u64 *, u64, s64 *); #endif /* _BCACHEFS_REFLINK_H */ |