@@ -36,6 +36,7 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_inode *inode,
{
memset(bbio, 0, offsetof(struct btrfs_bio, bio));
bbio->inode = inode;
+ bbio->fs_info = inode->root->fs_info;
bbio->end_io = end_io;
bbio->private = private;
atomic_set(&bbio->pending_ios, 1);
@@ -61,6 +62,30 @@ struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
return bbio;
}
+/*
+ * Allocate a scrub specific btrfs_bio structure.
+ *
+ * This btrfs_bio would not go through any the btrfs special handling like
+ * checksum verification nor read-repair.
+ */
+struct btrfs_bio *btrfs_scrub_bio_alloc(blk_opf_t opf,
+ struct btrfs_fs_info *fs_info,
+ btrfs_bio_end_io_t end_io, void *private)
+{
+ struct btrfs_bio *bbio;
+ struct bio *bio;
+
+ bio = bio_alloc_bioset(NULL, BTRFS_STRIPE_LEN >> fs_info->sectorsize_bits,
+ opf, GFP_NOFS, &btrfs_bioset);
+ bbio = btrfs_bio(bio);
+ memset(bbio, 0, offsetof(struct btrfs_bio, bio));
+ bbio->fs_info = fs_info;
+ bbio->end_io = end_io;
+ bbio->private = private;
+ atomic_set(&bbio->pending_ios, 1);
+ return bbio;
+}
+
static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info,
struct btrfs_bio *orig_bbio,
u64 map_length, bool use_append)
@@ -30,7 +30,12 @@ typedef void (*btrfs_bio_end_io_t)(struct btrfs_bio *bbio);
* passed to btrfs_submit_bio for mapping to the physical devices.
*/
struct btrfs_bio {
- /* Inode and offset into it that this I/O operates on. */
+ /*
+ * Inode and offset into it that this I/O operates on.
+ *
+ * @inode can be NULL for callers who don't want any advanced features
+ * like read-time repair.
+ */
struct btrfs_inode *inode;
u64 file_offset;
@@ -58,6 +63,15 @@ struct btrfs_bio {
atomic_t pending_ios;
struct work_struct end_io_work;
+ /*
+ * For cases where callers only want to read/write from a logical
+ * bytenr, in that case @inode can be NULL, and we need such
+ * @fs_info pointer to grab the corresponding fs_info.
+ *
+ * Should always be populated.
+ */
+ struct btrfs_fs_info *fs_info;
+
/*
* This member must come last, bio_alloc_bioset will allocate enough
* bytes for entire btrfs_bio but relies on bio being last.
@@ -78,6 +92,9 @@ void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_inode *inode,
struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
struct btrfs_inode *inode,
btrfs_bio_end_io_t end_io, void *private);
+struct btrfs_bio *btrfs_scrub_bio_alloc(blk_opf_t opf,
+ struct btrfs_fs_info *fs_info,
+ btrfs_bio_end_io_t end_io, void *private);
static inline void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
{
Currently we're doing a lot of work for btrfs_bio: - Checksum verification for data read bios - Bio splits if it crosses stripe boundary - Read repair for data read bios However for the incoming scrub patches, we don't want those extra functionality at all, just pure logical + mirror -> physical mapping ability. Thus here we introduce: - btrfs_bio::fs_info This is for the new scrub specific btrfs_bio, which would not populate btrfs_bio::inode. Thus we need such new member to grab a fs_info This new member would always be populated. - btrfs_scrub_bio_alloc() helper The main differences between this and btrfs_bio_alloc() are: * No need for nr_vecs As we know scrub bio should not cross stripe boundary. * Use @fs_info to replace @inode parameter - An extra ASSERT() to make sure btrfs_bio::fs_info is populated Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/bio.c | 25 +++++++++++++++++++++++++ fs/btrfs/bio.h | 19 ++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-)