]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/fs-io.c
Update bcachefs sources to 386f00b639 bcachefs: Snapshot creation, deletion
[bcachefs-tools-debian] / libbcachefs / fs-io.c
index 2921037713d12677d1e02ba7d2151411469aa64e..c07755c6916d2a6b010679e55b13cd35f8bc4713 100644 (file)
@@ -786,23 +786,35 @@ static void readpage_bio_extend(struct readpages_iter *iter,
        }
 }
 
-static void bchfs_read(struct btree_trans *trans, struct btree_iter *iter,
-                      struct bch_read_bio *rbio, u64 inum,
+static void bchfs_read(struct btree_trans *trans,
+                      struct bch_read_bio *rbio,
+                      subvol_inum inum,
                       struct readpages_iter *readpages_iter)
 {
        struct bch_fs *c = trans->c;
+       struct btree_iter iter;
        struct bkey_buf sk;
        int flags = BCH_READ_RETRY_IF_STALE|
                BCH_READ_MAY_PROMOTE;
+       u32 snapshot;
        int ret = 0;
 
        rbio->c = c;
        rbio->start_time = local_clock();
+       rbio->subvol = inum.subvol;
 
        bch2_bkey_buf_init(&sk);
 retry:
        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) {
                struct bkey_s_c k;
                unsigned bytes, sectors, offset_into_extent;
@@ -817,15 +829,15 @@ retry:
                        break;
                }
 
-               bch2_btree_iter_set_pos(iter,
-                               POS(inum, rbio->bio.bi_iter.bi_sector));
+               bch2_btree_iter_set_pos(&iter,
+                               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);
                if (ret)
                        break;
 
-               offset_into_extent = iter->pos.offset -
+               offset_into_extent = iter.pos.offset -
                        bkey_start_offset(k.k);
                sectors = k.k->size - offset_into_extent;
 
@@ -855,7 +867,7 @@ retry:
                if (bkey_extent_is_allocation(k.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);
 
                if (flags & BCH_READ_LAST_FRAGMENT)
@@ -864,12 +876,14 @@ retry:
                swap(rbio->bio.bi_iter.bi_size, bytes);
                bio_advance(&rbio->bio, bytes);
        }
+err:
+       bch2_trans_iter_exit(trans, &iter);
 
        if (ret == -EINTR)
                goto retry;
 
        if (ret) {
-               bch_err_inum_ratelimited(c, inum,
+               bch_err_inum_ratelimited(c, inum.inum,
                                "read error %i from btree lookup", ret);
                rbio->bio.bi_status = BLK_STS_IOERR;
                bio_endio(&rbio->bio);
@@ -884,7 +898,6 @@ void bch2_readahead(struct readahead_control *ractl)
        struct bch_fs *c = inode->v.i_sb->s_fs_info;
        struct bch_io_opts opts = io_opts(c, &inode->ei_inode);
        struct btree_trans trans;
-       struct btree_iter iter;
        struct page *page;
        struct readpages_iter readpages_iter;
        int ret;
@@ -893,8 +906,6 @@ void bch2_readahead(struct readahead_control *ractl)
        BUG_ON(ret);
 
        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);
 
@@ -915,22 +926,20 @@ void bch2_readahead(struct readahead_control *ractl)
                rbio->bio.bi_end_io = bch2_readpages_end_io;
                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);
        }
 
        bch2_pagecache_add_put(&inode->ei_pagecache_lock);
 
-       bch2_trans_iter_exit(&trans, &iter);
        bch2_trans_exit(&trans);
        kfree(readpages_iter.pages);
 }
 
 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_iter iter;
 
        bch2_page_state_create(page, __GFP_NOFAIL);
 
@@ -940,12 +949,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));
 
        bch2_trans_init(&trans, c, 0, 0);
-       bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents, POS_MIN,
-                            BTREE_ITER_SLOTS);
-
-       bchfs_read(&trans, &iter, rbio, inum, NULL);
-
-       bch2_trans_iter_exit(&trans, &iter);
+       bchfs_read(&trans, rbio, inum, NULL);
        bch2_trans_exit(&trans);
 }
 
@@ -959,7 +963,7 @@ int bch2_readpage(struct file *file, struct page *page)
        rbio = rbio_init(bio_alloc_bioset(GFP_NOFS, 1, &c->bio_read), opts);
        rbio->bio.bi_end_io = bch2_readpages_end_io;
 
-       __bchfs_readpage(c, rbio, inode->v.i_ino, page);
+       __bchfs_readpage(c, rbio, inode_inum(inode), page);
        return 0;
 }
 
@@ -982,7 +986,7 @@ static int bch2_read_single_page(struct page *page,
        rbio->bio.bi_private = &done;
        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);
 
        ret = blk_status_to_errno(rbio->bio.bi_status);
@@ -1126,6 +1130,7 @@ static void bch2_writepage_io_alloc(struct bch_fs *c,
        op->nr_replicas         = nr_replicas;
        op->res.nr_replicas     = nr_replicas;
        op->write_point         = writepoint_hashed(inode->ei_last_dirtied);
+       op->subvol              = inode->ei_subvol;
        op->pos                 = POS(inode->v.i_ino, sector);
        op->wbio.bio.bi_iter.bi_sector = sector;
        op->wbio.bio.bi_opf     = wbc_to_write_flags(wbc);
@@ -1758,7 +1763,7 @@ start:
                if (iter->count)
                        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;
@@ -1813,6 +1818,50 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 
 /* O_DIRECT writes */
 
+static bool bch2_check_range_allocated(struct bch_fs *c, subvol_inum inum,
+                                      u64 offset, u64 size,
+                                      unsigned nr_replicas, bool compressed)
+{
+       struct btree_trans trans;
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       u64 end = offset + size;
+       u32 snapshot;
+       bool ret = true;
+       int err;
+
+       bch2_trans_init(&trans, c, 0, 0);
+retry:
+       bch2_trans_begin(&trans);
+
+       err = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
+       if (err)
+               goto err;
+
+       for_each_btree_key(&trans, iter, BTREE_ID_extents,
+                          SPOS(inum.inum, offset, snapshot),
+                          BTREE_ITER_SLOTS, k, err) {
+               if (bkey_cmp(bkey_start_pos(k.k), POS(inum.inum, end)) >= 0)
+                       break;
+
+               if (k.k->p.snapshot != snapshot ||
+                   nr_replicas > bch2_bkey_replicas(c, k) ||
+                   (!compressed && bch2_bkey_sectors_compressed(k))) {
+                       ret = false;
+                       break;
+               }
+       }
+
+       offset = iter.pos.offset;
+       bch2_trans_iter_exit(&trans, &iter);
+err:
+       if (err == -EINTR)
+               goto retry;
+       bch2_trans_exit(&trans);
+
+       return err ? false : ret;
+}
+
 static void bch2_dio_write_loop_async(struct bch_write_op *);
 
 static long bch2_dio_write_loop(struct dio_write *dio)
@@ -1891,6 +1940,7 @@ static long bch2_dio_write_loop(struct dio_write *dio)
                op_journal_seq_set(&dio->op, &inode->ei_journal_seq);
                dio->op.write_point     = writepoint_hashed((unsigned long) current);
                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);
 
                if ((req->ki_flags & IOCB_DSYNC) &&
@@ -1901,8 +1951,8 @@ static long bch2_dio_write_loop(struct dio_write *dio)
                ret = bch2_disk_reservation_get(c, &dio->op.res, bio_sectors(bio),
                                                dio->op.opts.data_replicas, 0);
                if (unlikely(ret) &&
-                   !bch2_check_range_allocated(c, dio->op.pos,
-                               bio_sectors(bio),
+                   !bch2_check_range_allocated(c, inode_inum(inode),
+                               dio->op.pos.offset, bio_sectors(bio),
                                dio->op.opts.data_replicas,
                                dio->op.opts.compression != 0))
                        goto err;
@@ -2146,9 +2196,9 @@ out:
 
 /* truncate: */
 
-static inline int range_has_data(struct bch_fs *c,
-                                 struct bpos start,
-                                 struct bpos end)
+static inline int range_has_data(struct bch_fs *c, u32 subvol,
+                                struct bpos start,
+                                struct bpos end)
 {
        struct btree_trans trans;
        struct btree_iter iter;
@@ -2156,6 +2206,12 @@ static inline int range_has_data(struct bch_fs *c,
        int ret = 0;
 
        bch2_trans_init(&trans, c, 0, 0);
+retry:
+       bch2_trans_begin(&trans);
+
+       ret = bch2_subvolume_get_snapshot(&trans, subvol, &start.snapshot);
+       if (ret)
+               goto err;
 
        for_each_btree_key(&trans, iter, BTREE_ID_extents, start, 0, k, ret) {
                if (bkey_cmp(bkey_start_pos(k.k), end) >= 0)
@@ -2166,7 +2222,11 @@ static inline int range_has_data(struct bch_fs *c,
                        break;
                }
        }
+       start = iter.pos;
        bch2_trans_iter_exit(&trans, &iter);
+err:
+       if (ret == -EINTR)
+               goto retry;
 
        return bch2_trans_exit(&trans) ?: ret;
 }
@@ -2198,7 +2258,7 @@ static int __bch2_truncate_page(struct bch_inode_info *inode,
                 * XXX: we're doing two index lookups when we end up reading the
                 * page
                 */
-               ret = range_has_data(c,
+               ret = range_has_data(c, inode->ei_subvol,
                                POS(inode->v.i_ino, index << PAGE_SECTOR_SHIFT),
                                POS(inode->v.i_ino, (index + 1) << PAGE_SECTOR_SHIFT));
                if (ret <= 0)
@@ -2332,7 +2392,7 @@ int bch2_truncate(struct user_namespace *mnt_userns,
        inode_dio_wait(&inode->v);
        bch2_pagecache_block_get(&inode->ei_pagecache_lock);
 
-       ret = bch2_inode_find_by_inum(c, inode->v.i_ino, &inode_u);
+       ret = bch2_inode_find_by_inum(c, inode_inum(inode), &inode_u);
        if (ret)
                goto err;
 
@@ -2390,7 +2450,7 @@ int bch2_truncate(struct user_namespace *mnt_userns,
 
        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,
                        U64_MAX, &inode->ei_journal_seq, &i_sectors_delta);
        i_sectors_acct(c, inode, NULL, i_sectors_delta);
@@ -2450,7 +2510,7 @@ static long bchfs_fpunch(struct bch_inode_info *inode, loff_t offset, loff_t len
        if (discard_start < discard_end) {
                s64 i_sectors_delta = 0;
 
-               ret = bch2_fpunch(c, inode->v.i_ino,
+               ret = bch2_fpunch(c, inode_inum(inode),
                                  discard_start, discard_end,
                                  &inode->ei_journal_seq,
                                  &i_sectors_delta);
@@ -2529,7 +2589,7 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode,
        } else {
                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,
                                  &inode->ei_journal_seq,
                                  &i_sectors_delta);
@@ -2556,6 +2616,18 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode,
                struct bpos move_pos = POS(inode->v.i_ino, offset >> 9);
                struct bpos atomic_end;
                unsigned trigger_flags = 0;
+               u32 snapshot;
+
+               bch2_trans_begin(&trans);
+
+               ret = bch2_subvolume_get_snapshot(&trans,
+                                       inode->ei_subvol, &snapshot);
+               if (ret)
+                       continue;
+
+               bch2_btree_iter_set_snapshot(&src, snapshot);
+               bch2_btree_iter_set_snapshot(&dst, snapshot);
+               bch2_btree_iter_set_snapshot(&del, snapshot);
 
                bch2_trans_begin(&trans);
 
@@ -2676,9 +2748,17 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
                struct bkey_i_reservation reservation;
                struct bkey_s_c k;
                unsigned sectors;
+               u32 snapshot;
 
                bch2_trans_begin(&trans);
 
+               ret = bch2_subvolume_get_snapshot(&trans,
+                                       inode->ei_subvol, &snapshot);
+               if (ret)
+                       goto bkey_err;
+
+               bch2_btree_iter_set_snapshot(&iter, snapshot);
+
                k = bch2_btree_iter_peek_slot(&iter);
                if ((ret = bkey_err(k)))
                        goto bkey_err;
@@ -2725,7 +2805,8 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
                        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,
                                0, &i_sectors_delta, true);
                i_sectors_acct(c, inode, &quota_res, i_sectors_delta);
@@ -2927,8 +3008,8 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src,
        mark_range_unallocated(src, pos_src, pos_src + aligned_len);
 
        ret = bch2_remap_range(c,
-                              POS(dst->v.i_ino, pos_dst >> 9),
-                              POS(src->v.i_ino, pos_src >> 9),
+                              inode_inum(dst), pos_dst >> 9,
+                              inode_inum(src), pos_src >> 9,
                               aligned_len >> 9,
                               &dst->ei_journal_seq,
                               pos_dst + len, &i_sectors_delta);
@@ -3019,7 +3100,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
        struct btree_trans trans;
        struct btree_iter iter;
        struct bkey_s_c k;
+       subvol_inum inum = inode_inum(inode);
        u64 isize, next_data = MAX_LFS_FILESIZE;
+       u32 snapshot;
        int ret;
 
        isize = i_size_read(&inode->v);
@@ -3027,9 +3110,15 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
                return -ENXIO;
 
        bch2_trans_init(&trans, c, 0, 0);
+retry:
+       bch2_trans_begin(&trans);
+
+       ret = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
+       if (ret)
+               goto err;
 
        for_each_btree_key(&trans, iter, BTREE_ID_extents,
-                          POS(inode->v.i_ino, offset >> 9), 0, k, ret) {
+                          SPOS(inode->v.i_ino, offset >> 9, snapshot), 0, k, ret) {
                if (k.k->p.inode != inode->v.i_ino) {
                        break;
                } else if (bkey_extent_is_data(k.k)) {
@@ -3039,6 +3128,9 @@ static loff_t bch2_seek_data(struct file *file, u64 offset)
                        break;
        }
        bch2_trans_iter_exit(&trans, &iter);
+err:
+       if (ret == -EINTR)
+               goto retry;
 
        ret = bch2_trans_exit(&trans) ?: ret;
        if (ret)
@@ -3115,7 +3207,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
        struct btree_trans trans;
        struct btree_iter iter;
        struct bkey_s_c k;
+       subvol_inum inum = inode_inum(inode);
        u64 isize, next_hole = MAX_LFS_FILESIZE;
+       u32 snapshot;
        int ret;
 
        isize = i_size_read(&inode->v);
@@ -3123,9 +3217,15 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
                return -ENXIO;
 
        bch2_trans_init(&trans, c, 0, 0);
+retry:
+       bch2_trans_begin(&trans);
+
+       ret = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
+       if (ret)
+               goto err;
 
        for_each_btree_key(&trans, iter, BTREE_ID_extents,
-                          POS(inode->v.i_ino, offset >> 9),
+                          SPOS(inode->v.i_ino, offset >> 9, snapshot),
                           BTREE_ITER_SLOTS, k, ret) {
                if (k.k->p.inode != inode->v.i_ino) {
                        next_hole = bch2_seek_pagecache_hole(&inode->v,
@@ -3143,6 +3243,9 @@ static loff_t bch2_seek_hole(struct file *file, u64 offset)
                }
        }
        bch2_trans_iter_exit(&trans, &iter);
+err:
+       if (ret == -EINTR)
+               goto retry;
 
        ret = bch2_trans_exit(&trans) ?: ret;
        if (ret)