summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/fs-io.c156
-rw-r--r--fs/bcachefs/fs-io.h2
-rw-r--r--fs/bcachefs/io.c71
-rw-r--r--fs/bcachefs/io.h4
-rw-r--r--fs/bcachefs/reflink.c53
-rw-r--r--fs/bcachefs/reflink.h6
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, &quota_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, &quota_res, i_sectors_delta);
bkey_err:
bch2_quota_reservation_put(c, inode, &quota_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 */