X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libbcachefs%2Ffs-io.c;h=02ef3430a30b69f4d321d162f3b2d52b52fedfb4;hb=e0a51ccce8533a91c7cc0cd0adc5662697c9bcfa;hp=020e603c3faa0a1a769f8e636721da3320b4a7b7;hpb=0766bee8fdf3973953fd3184f63dfe2a0760c08d;p=bcachefs-tools-debian diff --git a/libbcachefs/fs-io.c b/libbcachefs/fs-io.c index 020e603..02ef343 100644 --- a/libbcachefs/fs-io.c +++ b/libbcachefs/fs-io.c @@ -151,7 +151,7 @@ static void bch2_quota_reservation_put(struct bch_fs *c, static int bch2_quota_reservation_add(struct bch_fs *c, struct bch_inode_info *inode, struct quota_res *res, - unsigned sectors, + u64 sectors, bool check_enospc) { int ret; @@ -409,7 +409,7 @@ retry: offset = iter.pos.offset; bch2_trans_iter_exit(&trans, &iter); err: - if (ret == -EINTR) + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) goto retry; bch2_trans_exit(&trans); @@ -434,22 +434,20 @@ static void mark_pagecache_unallocated(struct bch_inode_info *inode, { pgoff_t index = start >> PAGE_SECTORS_SHIFT; pgoff_t end_index = (end - 1) >> PAGE_SECTORS_SHIFT; - struct pagevec pvec; + struct folio_batch fbatch; + unsigned i, j; if (end <= start) return; - pagevec_init(&pvec); - - do { - unsigned nr_pages, i, j; + folio_batch_init(&fbatch); - nr_pages = pagevec_lookup_range(&pvec, inode->v.i_mapping, - &index, end_index); - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - u64 pg_start = page->index << PAGE_SECTORS_SHIFT; - u64 pg_end = (page->index + 1) << PAGE_SECTORS_SHIFT; + while (filemap_get_folios(inode->v.i_mapping, + &index, end_index, &fbatch)) { + for (i = 0; i < folio_batch_count(&fbatch); i++) { + struct folio *folio = fbatch.folios[i]; + u64 pg_start = folio->index << PAGE_SECTORS_SHIFT; + u64 pg_end = (folio->index + 1) << PAGE_SECTORS_SHIFT; unsigned pg_offset = max(start, pg_start) - pg_start; unsigned pg_len = min(end, pg_end) - pg_offset - pg_start; struct bch_page_state *s; @@ -458,8 +456,8 @@ static void mark_pagecache_unallocated(struct bch_inode_info *inode, BUG_ON(pg_offset >= PAGE_SECTORS); BUG_ON(pg_offset + pg_len > PAGE_SECTORS); - lock_page(page); - s = bch2_page_state(page); + folio_lock(folio); + s = bch2_page_state(&folio->page); if (s) { spin_lock(&s->lock); @@ -468,10 +466,11 @@ static void mark_pagecache_unallocated(struct bch_inode_info *inode, spin_unlock(&s->lock); } - unlock_page(page); + folio_unlock(folio); } - pagevec_release(&pvec); - } while (index <= end_index); + folio_batch_release(&fbatch); + cond_resched(); + } } static void mark_pagecache_reserved(struct bch_inode_info *inode, @@ -480,23 +479,21 @@ static void mark_pagecache_reserved(struct bch_inode_info *inode, struct bch_fs *c = inode->v.i_sb->s_fs_info; pgoff_t index = start >> PAGE_SECTORS_SHIFT; pgoff_t end_index = (end - 1) >> PAGE_SECTORS_SHIFT; - struct pagevec pvec; + struct folio_batch fbatch; s64 i_sectors_delta = 0; + unsigned i, j; if (end <= start) return; - pagevec_init(&pvec); + folio_batch_init(&fbatch); - do { - unsigned nr_pages, i, j; - - nr_pages = pagevec_lookup_range(&pvec, inode->v.i_mapping, - &index, end_index); - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - u64 pg_start = page->index << PAGE_SECTORS_SHIFT; - u64 pg_end = (page->index + 1) << PAGE_SECTORS_SHIFT; + while (filemap_get_folios(inode->v.i_mapping, + &index, end_index, &fbatch)) { + for (i = 0; i < folio_batch_count(&fbatch); i++) { + struct folio *folio = fbatch.folios[i]; + u64 pg_start = folio->index << PAGE_SECTORS_SHIFT; + u64 pg_end = (folio->index + 1) << PAGE_SECTORS_SHIFT; unsigned pg_offset = max(start, pg_start) - pg_start; unsigned pg_len = min(end, pg_end) - pg_offset - pg_start; struct bch_page_state *s; @@ -505,8 +502,8 @@ static void mark_pagecache_reserved(struct bch_inode_info *inode, BUG_ON(pg_offset >= PAGE_SECTORS); BUG_ON(pg_offset + pg_len > PAGE_SECTORS); - lock_page(page); - s = bch2_page_state(page); + folio_lock(folio); + s = bch2_page_state(&folio->page); if (s) { spin_lock(&s->lock); @@ -525,10 +522,11 @@ static void mark_pagecache_reserved(struct bch_inode_info *inode, spin_unlock(&s->lock); } - unlock_page(page); + folio_unlock(folio); } - pagevec_release(&pvec); - } while (index <= end_index); + folio_batch_release(&fbatch); + cond_resched(); + } i_sectors_acct(c, inode, NULL, i_sectors_delta); } @@ -842,47 +840,22 @@ out: return ret; } -void bch2_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) +void bch2_invalidate_folio(struct folio *folio, size_t offset, size_t length) { - if (offset || length < PAGE_SIZE) + if (offset || length < folio_size(folio)) return; - bch2_clear_page_bits(page); -} - -int bch2_releasepage(struct page *page, gfp_t gfp_mask) -{ - if (PageDirty(page)) - return 0; - - bch2_clear_page_bits(page); - return 1; + bch2_clear_page_bits(&folio->page); } -#ifdef CONFIG_MIGRATION -int bch2_migrate_page(struct address_space *mapping, struct page *newpage, - struct page *page, enum migrate_mode mode) +bool bch2_release_folio(struct folio *folio, gfp_t gfp_mask) { - int ret; - - EBUG_ON(!PageLocked(page)); - EBUG_ON(!PageLocked(newpage)); - - ret = migrate_page_move_mapping(mapping, newpage, page, 0); - if (ret != MIGRATEPAGE_SUCCESS) - return ret; - - if (PagePrivate(page)) - attach_page_private(newpage, detach_page_private(page)); + if (folio_test_dirty(folio) || folio_test_writeback(folio)) + return false; - if (mode != MIGRATE_SYNC_NO_COPY) - migrate_page_copy(newpage, page); - else - migrate_page_states(newpage, page); - return MIGRATEPAGE_SUCCESS; + bch2_clear_page_bits(&folio->page); + return true; } -#endif /* readpage(s): */ @@ -1046,10 +1019,9 @@ retry: * read_extent -> io_time_reset may cause a transaction restart * without returning an error, we need to check for that here: */ - if (!bch2_trans_relock(trans)) { - ret = -EINTR; + ret = bch2_trans_relock(trans); + if (ret) break; - } bch2_btree_iter_set_pos(&iter, POS(inum.inum, rbio->bio.bi_iter.bi_sector)); @@ -1102,7 +1074,7 @@ retry: err: bch2_trans_iter_exit(trans, &iter); - if (ret == -EINTR) + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) goto retry; if (ret) { @@ -1139,12 +1111,12 @@ void bch2_readahead(struct readahead_control *ractl) readpages_iter.idx, BIO_MAX_VECS); struct bch_read_bio *rbio = - rbio_init(bio_alloc_bioset(GFP_NOFS, n, &c->bio_read), + rbio_init(bio_alloc_bioset(NULL, n, REQ_OP_READ, + GFP_NOFS, &c->bio_read), opts); readpages_iter.idx++; - bio_set_op_attrs(&rbio->bio, REQ_OP_READ, 0); rbio->bio.bi_iter.bi_sector = (sector_t) index << PAGE_SECTORS_SHIFT; rbio->bio.bi_end_io = bch2_readpages_end_io; BUG_ON(!bio_add_page(&rbio->bio, page, PAGE_SIZE, 0)); @@ -1176,20 +1148,6 @@ static void __bchfs_readpage(struct bch_fs *c, struct bch_read_bio *rbio, bch2_trans_exit(&trans); } -int bch2_readpage(struct file *file, struct page *page) -{ - struct bch_inode_info *inode = to_bch_ei(page->mapping->host); - struct bch_fs *c = inode->v.i_sb->s_fs_info; - struct bch_io_opts opts = io_opts(c, &inode->ei_inode); - struct bch_read_bio *rbio; - - 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_inum(inode), page); - return 0; -} - static void bch2_read_single_page_end_io(struct bio *bio) { complete(bio->bi_private); @@ -1204,7 +1162,7 @@ static int bch2_read_single_page(struct page *page, int ret; DECLARE_COMPLETION_ONSTACK(done); - rbio = rbio_init(bio_alloc_bioset(GFP_NOFS, 1, &c->bio_read), + rbio = rbio_init(bio_alloc_bioset(NULL, 1, REQ_OP_READ, GFP_NOFS, &c->bio_read), io_opts(c, &inode->ei_inode)); rbio->bio.bi_private = &done; rbio->bio.bi_end_io = bch2_read_single_page_end_io; @@ -1222,6 +1180,16 @@ static int bch2_read_single_page(struct page *page, return 0; } +int bch2_read_folio(struct file *file, struct folio *folio) +{ + struct page *page = &folio->page; + int ret; + + ret = bch2_read_single_page(page, page->mapping); + folio_unlock(folio); + return bch2_err_class(ret); +} + /* writepages: */ struct bch_writepage_state { @@ -1255,8 +1223,6 @@ static void bch2_writepage_io_done(struct closure *cl) struct bio_vec *bvec; unsigned i; - up(&io->op.c->io_in_flight); - if (io->op.error) { set_bit(EI_INODE_ERROR, &io->inode->ei_flags); @@ -1319,8 +1285,6 @@ static void bch2_writepage_do_io(struct bch_writepage_state *w) { struct bch_writepage_io *io = w->io; - down(&io->op.c->io_in_flight); - w->io = NULL; closure_call(&io->op.cl, bch2_write, NULL, &io->cl); continue_at(&io->cl, bch2_writepage_io_done, NULL); @@ -1339,7 +1303,9 @@ static void bch2_writepage_io_alloc(struct bch_fs *c, { struct bch_write_op *op; - w->io = container_of(bio_alloc_bioset(GFP_NOFS, BIO_MAX_VECS, + w->io = container_of(bio_alloc_bioset(NULL, BIO_MAX_VECS, + REQ_OP_WRITE, + GFP_NOFS, &c->writepage_bioset), struct bch_writepage_io, op.wbio.bio); @@ -1505,13 +1471,13 @@ int bch2_writepages(struct address_space *mapping, struct writeback_control *wbc if (w.io) bch2_writepage_do_io(&w); blk_finish_plug(&plug); - return ret; + return bch2_err_class(ret); } /* buffered writes: */ int bch2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, + loff_t pos, unsigned len, struct page **pagep, void **fsdata) { struct bch_inode_info *inode = to_bch_ei(mapping->host); @@ -1531,7 +1497,7 @@ int bch2_write_begin(struct file *file, struct address_space *mapping, bch2_pagecache_add_get(&inode->ei_pagecache_lock); - page = grab_cache_page_write_begin(mapping, index, flags); + page = grab_cache_page_write_begin(mapping, index); if (!page) goto err_unlock; @@ -1561,7 +1527,7 @@ out: if (!bch2_page_state_create(page, __GFP_NOFAIL)->uptodate) { ret = bch2_page_state_set(c, inode_inum(inode), &page, 1); if (ret) - goto out; + goto err; } ret = bch2_page_reservation_get(c, inode, page, res, @@ -1590,7 +1556,7 @@ err_unlock: bch2_pagecache_add_put(&inode->ei_pagecache_lock); kfree(res); *fsdata = NULL; - return ret; + return bch2_err_class(ret); } int bch2_write_end(struct file *file, struct address_space *mapping, @@ -1662,7 +1628,7 @@ static int __bch2_buffered_write(struct bch_inode_info *inode, bch2_page_reservation_init(c, inode, &res); for (i = 0; i < nr_pages; i++) { - pages[i] = grab_cache_page_write_begin(mapping, index + i, 0); + pages[i] = grab_cache_page_write_begin(mapping, index + i); if (!pages[i]) { nr_pages = i; if (!i) { @@ -1916,8 +1882,10 @@ static int bch2_direct_IO_read(struct kiocb *req, struct iov_iter *iter) shorten = iov_iter_count(iter) - round_up(ret, block_bytes(c)); iter->count -= shorten; - bio = bio_alloc_bioset(GFP_KERNEL, + bio = bio_alloc_bioset(NULL, bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS), + REQ_OP_READ, + GFP_KERNEL, &c->dio_read_bioset); bio->bi_end_io = bch2_direct_IO_read_endio; @@ -1951,8 +1919,10 @@ static int bch2_direct_IO_read(struct kiocb *req, struct iov_iter *iter) goto start; while (iter->count) { - bio = bio_alloc_bioset(GFP_KERNEL, + bio = bio_alloc_bioset(NULL, bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS), + REQ_OP_READ, + GFP_KERNEL, &c->bio_read); bio->bi_end_io = bch2_direct_IO_read_split_endio; start: @@ -2010,7 +1980,7 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter) iocb->ki_pos, iocb->ki_pos + count - 1); if (ret < 0) - return ret; + goto out; file_accessed(file); @@ -2025,8 +1995,8 @@ ssize_t bch2_read_iter(struct kiocb *iocb, struct iov_iter *iter) ret = generic_file_read_iter(iocb, iter); bch2_pagecache_add_put(&inode->ei_pagecache_lock); } - - return ret; +out: + return bch2_err_class(ret); } /* O_DIRECT writes */ @@ -2068,7 +2038,7 @@ retry: offset = iter.pos.offset; bch2_trans_iter_exit(&trans, &iter); err: - if (err == -EINTR) + if (bch2_err_matches(err, BCH_ERR_transaction_restart)) goto retry; bch2_trans_exit(&trans); @@ -2094,8 +2064,6 @@ static long bch2_dio_write_loop(struct dio_write *dio) if (dio->loop) goto loop; - down(&c->io_in_flight); - while (1) { iter_count = dio->iter.count; @@ -2220,13 +2188,12 @@ loop: if (!dio->iter.count) break; - bio_reset(bio); + bio_reset(bio, NULL, REQ_OP_WRITE); reinit_completion(&dio->done); } ret = dio->op.error ?: ((long) dio->written << 9); err: - up(&c->io_in_flight); bch2_pagecache_block_put(&inode->ei_pagecache_lock); bch2_quota_reservation_put(c, inode, &dio->quota_res); @@ -2241,6 +2208,9 @@ err: /* inode->i_dio_count is our ref on inode and thus bch_fs */ inode_dio_end(&inode->v); + if (ret < 0) + ret = bch2_err_class(ret); + if (!sync) { req->ki_complete(req, ret); ret = -EIOCBQUEUED; @@ -2301,8 +2271,10 @@ ssize_t bch2_direct_write(struct kiocb *req, struct iov_iter *iter) locked = false; } - bio = bio_alloc_bioset(GFP_KERNEL, + bio = bio_alloc_bioset(NULL, bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS), + REQ_OP_WRITE, + GFP_KERNEL, &c->dio_write_bioset); dio = container_of(bio, struct dio_write, op.wbio.bio); init_completion(&dio->done); @@ -2345,8 +2317,10 @@ ssize_t bch2_write_iter(struct kiocb *iocb, struct iov_iter *from) struct bch_inode_info *inode = file_bch_inode(file); ssize_t ret; - if (iocb->ki_flags & IOCB_DIRECT) - return bch2_direct_write(iocb, from); + if (iocb->ki_flags & IOCB_DIRECT) { + ret = bch2_direct_write(iocb, from); + goto out; + } /* We can write back this queue in page reclaim */ current->backing_dev_info = inode_to_bdi(&inode->v); @@ -2373,8 +2347,8 @@ unlock: if (ret > 0) ret = generic_write_sync(iocb, ret); - - return ret; +out: + return bch2_err_class(ret); } /* fsync: */ @@ -2408,7 +2382,7 @@ int bch2_fsync(struct file *file, loff_t start, loff_t end, int datasync) ret2 = sync_inode_metadata(&inode->v, 1); ret3 = bch2_flush_inode(c, inode_inum(inode)); - return ret ?: ret2 ?: ret3; + return bch2_err_class(ret ?: ret2 ?: ret3); } /* truncate: */ @@ -2442,7 +2416,7 @@ retry: start = iter.pos; bch2_trans_iter_exit(&trans, &iter); err: - if (ret == -EINTR) + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) goto retry; bch2_trans_exit(&trans); @@ -2714,7 +2688,7 @@ int bch2_truncate(struct user_namespace *mnt_userns, ret = bch2_setattr_nonsize(mnt_userns, inode, iattr); err: bch2_pagecache_block_put(&inode->ei_pagecache_lock); - return ret; + return bch2_err_class(ret); } /* fallocate: */ @@ -2832,7 +2806,8 @@ static long bchfs_fcollapse_finsert(struct bch_inode_info *inode, bch2_trans_copy_iter(&dst, &src); bch2_trans_copy_iter(&del, &src); - while (ret == 0 || ret == -EINTR) { + while (ret == 0 || + bch2_err_matches(ret, BCH_ERR_transaction_restart)) { struct disk_reservation disk_res = bch2_disk_reservation_init(c, 0); struct bkey_i delete; @@ -3034,14 +3009,14 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode, bkey_err: bch2_quota_reservation_put(c, inode, "a_res); bch2_disk_reservation_put(c, &disk_res); - if (ret == -EINTR) + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) ret = 0; } bch2_trans_unlock(&trans); /* lock ordering, before taking pagecache locks: */ mark_pagecache_reserved(inode, start_sector, iter.pos.offset); - if (ret == -ENOSPC && (mode & FALLOC_FL_ZERO_RANGE)) { + if (bch2_err_matches(ret, ENOSPC) && (mode & FALLOC_FL_ZERO_RANGE)) { struct quota_res quota_res = { 0 }; s64 i_sectors_delta = 0; @@ -3092,7 +3067,7 @@ static long bchfs_fallocate(struct bch_inode_info *inode, int mode, * so that the VFS cache i_size is consistent with the btree i_size: */ if (ret && - !(ret == -ENOSPC && (mode & FALLOC_FL_ZERO_RANGE))) + !(bch2_err_matches(ret, ENOSPC) && (mode & FALLOC_FL_ZERO_RANGE))) return ret; if (mode & FALLOC_FL_KEEP_SIZE && end > inode->v.i_size) @@ -3120,13 +3095,17 @@ long bch2_fallocate_dispatch(struct file *file, int mode, struct bch_fs *c = inode->v.i_sb->s_fs_info; long ret; - if (!percpu_ref_tryget(&c->writes)) + if (!percpu_ref_tryget_live(&c->writes)) return -EROFS; inode_lock(&inode->v); inode_dio_wait(&inode->v); bch2_pagecache_block_get(&inode->ei_pagecache_lock); + ret = file_modified(file); + if (ret) + goto err; + if (!(mode & ~(FALLOC_FL_KEEP_SIZE|FALLOC_FL_ZERO_RANGE))) ret = bchfs_fallocate(inode, mode, offset, len); else if (mode == (FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE)) @@ -3137,13 +3116,61 @@ long bch2_fallocate_dispatch(struct file *file, int mode, ret = bchfs_fcollapse_finsert(inode, offset, len, false); else ret = -EOPNOTSUPP; - - +err: bch2_pagecache_block_put(&inode->ei_pagecache_lock); inode_unlock(&inode->v); percpu_ref_put(&c->writes); - return ret; + return bch2_err_class(ret); +} + +static int quota_reserve_range(struct bch_inode_info *inode, + struct quota_res *res, + u64 start, u64 end) +{ + struct bch_fs *c = inode->v.i_sb->s_fs_info; + struct btree_trans trans; + struct btree_iter iter; + struct bkey_s_c k; + u32 snapshot; + u64 sectors = end - start; + u64 pos = start; + int ret; + + bch2_trans_init(&trans, c, 0, 0); +retry: + bch2_trans_begin(&trans); + + ret = bch2_subvolume_get_snapshot(&trans, inode->ei_subvol, &snapshot); + if (ret) + goto err; + + bch2_trans_iter_init(&trans, &iter, BTREE_ID_extents, + SPOS(inode->v.i_ino, pos, snapshot), 0); + + while (!(ret = btree_trans_too_many_iters(&trans)) && + (k = bch2_btree_iter_peek_upto(&iter, POS(inode->v.i_ino, end - 1))).k && + !(ret = bkey_err(k))) { + if (bkey_extent_is_allocation(k.k)) { + u64 s = min(end, k.k->p.offset) - + max(start, bkey_start_offset(k.k)); + BUG_ON(s > sectors); + sectors -= s; + } + bch2_btree_iter_advance(&iter); + } + pos = iter.pos.offset; + bch2_trans_iter_exit(&trans, &iter); +err: + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) + goto retry; + + bch2_trans_exit(&trans); + + if (ret) + return ret; + + return bch2_quota_reservation_add(c, inode, res, sectors, true); } loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, @@ -3153,6 +3180,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; + struct quota_res quota_res = { 0 }; s64 i_sectors_delta = 0; u64 aligned_len; loff_t ret = 0; @@ -3173,8 +3201,6 @@ 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); @@ -3191,6 +3217,13 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, if (ret) goto err; + ret = quota_reserve_range(dst, "a_res, pos_dst >> 9, + (pos_dst + aligned_len) >> 9); + if (ret) + goto err; + + file_update_time(file_dst); + mark_pagecache_unallocated(src, pos_src >> 9, (pos_src + aligned_len) >> 9); @@ -3207,8 +3240,7 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, */ ret = min((u64) ret << 9, (u64) len); - /* XXX get a quota reservation */ - i_sectors_acct(c, dst, NULL, i_sectors_delta); + i_sectors_acct(c, dst, "a_res, i_sectors_delta); spin_lock(&dst->v.i_lock); if (pos_dst + ret > dst->v.i_size) @@ -3219,9 +3251,10 @@ loff_t bch2_remap_file_range(struct file *file_src, loff_t pos_src, IS_SYNC(file_inode(file_dst))) ret = bch2_flush_inode(c, inode_inum(dst)); err: + bch2_quota_reservation_put(c, dst, "a_res); bch2_unlock_inodes(INODE_LOCK|INODE_PAGECACHE_BLOCK, src, dst); - return ret; + return bch2_err_class(ret); } /* fseek: */ @@ -3243,36 +3276,40 @@ static loff_t bch2_seek_pagecache_data(struct inode *vinode, loff_t start_offset, loff_t end_offset) { - struct address_space *mapping = vinode->i_mapping; - struct page *page; + struct folio_batch fbatch; pgoff_t start_index = start_offset >> PAGE_SHIFT; pgoff_t end_index = end_offset >> PAGE_SHIFT; pgoff_t index = start_index; + unsigned i; loff_t ret; int offset; - while (index <= end_index) { - if (find_get_pages_range(mapping, &index, end_index, 1, &page)) { - lock_page(page); + folio_batch_init(&fbatch); + + while (filemap_get_folios(vinode->i_mapping, + &index, end_index, &fbatch)) { + for (i = 0; i < folio_batch_count(&fbatch); i++) { + struct folio *folio = fbatch.folios[i]; - offset = page_data_offset(page, - page->index == start_index + folio_lock(folio); + + offset = page_data_offset(&folio->page, + folio->index == start_index ? start_offset & (PAGE_SIZE - 1) : 0); if (offset >= 0) { - ret = clamp(((loff_t) page->index << PAGE_SHIFT) + + ret = clamp(((loff_t) folio->index << PAGE_SHIFT) + offset, start_offset, end_offset); - unlock_page(page); - put_page(page); + folio_unlock(folio); + folio_batch_release(&fbatch); return ret; } - unlock_page(page); - put_page(page); - } else { - break; + folio_unlock(folio); } + folio_batch_release(&fbatch); + cond_resched(); } return end_offset; @@ -3314,7 +3351,7 @@ retry: } bch2_trans_iter_exit(&trans, &iter); err: - if (ret == -EINTR) + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) goto retry; bch2_trans_exit(&trans); @@ -3429,7 +3466,7 @@ retry: } bch2_trans_iter_exit(&trans, &iter); err: - if (ret == -EINTR) + if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) goto retry; bch2_trans_exit(&trans); @@ -3444,18 +3481,26 @@ err: loff_t bch2_llseek(struct file *file, loff_t offset, int whence) { + loff_t ret; + switch (whence) { case SEEK_SET: case SEEK_CUR: case SEEK_END: - return generic_file_llseek(file, offset, whence); + ret = generic_file_llseek(file, offset, whence); + break; case SEEK_DATA: - return bch2_seek_data(file, offset); + ret = bch2_seek_data(file, offset); + break; case SEEK_HOLE: - return bch2_seek_hole(file, offset); + ret = bch2_seek_hole(file, offset); + break; + default: + ret = -EINVAL; + break; } - return -EINVAL; + return bch2_err_class(ret); } void bch2_fs_fsio_exit(struct bch_fs *c)