diff options
Diffstat (limited to 'include/linux/bio.h')
| -rw-r--r-- | include/linux/bio.h | 60 | 
1 files changed, 56 insertions, 4 deletions
| diff --git a/include/linux/bio.h b/include/linux/bio.h index fe6bdfbbef66..117d7f248ac9 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -124,7 +124,7 @@ void __bio_advance(struct bio *, unsigned bytes);  /**   * bio_advance - increment/complete a bio by some number of bytes   * @bio:	bio to advance - * @bytes:	number of bytes to complete + * @nbytes:	number of bytes to complete   *   * This updates bi_sector, bi_size and bi_idx; if the number of bytes to   * complete doesn't align with a bvec boundary, then bv_len and bv_offset will @@ -166,7 +166,7 @@ static inline void bio_advance(struct bio *bio, unsigned int nbytes)   */  #define bio_for_each_bvec_all(bvl, bio, i)		\  	for (i = 0, bvl = bio_first_bvec_all(bio);	\ -	     i < (bio)->bi_vcnt; i++, bvl++)		\ +	     i < (bio)->bi_vcnt; i++, bvl++)  #define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) @@ -260,6 +260,57 @@ static inline struct bio_vec *bio_last_bvec_all(struct bio *bio)  	return &bio->bi_io_vec[bio->bi_vcnt - 1];  } +/** + * struct folio_iter - State for iterating all folios in a bio. + * @folio: The current folio we're iterating.  NULL after the last folio. + * @offset: The byte offset within the current folio. + * @length: The number of bytes in this iteration (will not cross folio + *	boundary). + */ +struct folio_iter { +	struct folio *folio; +	size_t offset; +	size_t length; +	/* private: for use by the iterator */ +	size_t _seg_count; +	int _i; +}; + +static inline void bio_first_folio(struct folio_iter *fi, struct bio *bio, +				   int i) +{ +	struct bio_vec *bvec = bio_first_bvec_all(bio) + i; + +	fi->folio = page_folio(bvec->bv_page); +	fi->offset = bvec->bv_offset + +			PAGE_SIZE * (bvec->bv_page - &fi->folio->page); +	fi->_seg_count = bvec->bv_len; +	fi->length = min(folio_size(fi->folio) - fi->offset, fi->_seg_count); +	fi->_i = i; +} + +static inline void bio_next_folio(struct folio_iter *fi, struct bio *bio) +{ +	fi->_seg_count -= fi->length; +	if (fi->_seg_count) { +		fi->folio = folio_next(fi->folio); +		fi->offset = 0; +		fi->length = min(folio_size(fi->folio), fi->_seg_count); +	} else if (fi->_i + 1 < bio->bi_vcnt) { +		bio_first_folio(fi, bio, fi->_i + 1); +	} else { +		fi->folio = NULL; +	} +} + +/** + * bio_for_each_folio_all - Iterate over each folio in a bio. + * @fi: struct folio_iter which is updated for each folio. + * @bio: struct bio to iterate over. + */ +#define bio_for_each_folio_all(fi, bio)				\ +	for (bio_first_folio(&fi, bio, 0); fi.folio; bio_next_folio(&fi, bio)) +  enum bip_flags {  	BIP_BLOCK_INTEGRITY	= 1 << 0, /* block layer owns integrity data */  	BIP_MAPPED_INTEGRITY	= 1 << 1, /* ref tag has been remapped */ @@ -332,7 +383,7 @@ extern struct bio *bio_split(struct bio *bio, int sectors,   * @gfp:	gfp mask   * @bs:		bio set to allocate from   * - * Returns a bio representing the next @sectors of @bio - if the bio is smaller + * Return: a bio representing the next @sectors of @bio - if the bio is smaller   * than @sectors, returns the original bio unchanged.   */  static inline struct bio *bio_next_split(struct bio *bio, int sectors, @@ -409,7 +460,8 @@ extern void bio_uninit(struct bio *);  extern void bio_reset(struct bio *);  void bio_chain(struct bio *, struct bio *); -extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); +int bio_add_page(struct bio *, struct page *, unsigned len, unsigned off); +bool bio_add_folio(struct bio *, struct folio *, size_t len, size_t off);  extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,  			   unsigned int, unsigned int);  int bio_add_zone_append_page(struct bio *bio, struct page *page, |