xref: /openbmc/linux/fs/xfs/xfs_bio_io.c (revision 5f7136db82996089cdfb2939c7664b29e9da141d)
16ad5b325SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
26ad5b325SChristoph Hellwig /*
36ad5b325SChristoph Hellwig  * Copyright (c) 2019 Christoph Hellwig.
46ad5b325SChristoph Hellwig  */
56ad5b325SChristoph Hellwig #include "xfs.h"
66ad5b325SChristoph Hellwig 
76ad5b325SChristoph Hellwig static inline unsigned int bio_max_vecs(unsigned int count)
86ad5b325SChristoph Hellwig {
9*5f7136dbSMatthew Wilcox (Oracle) 	return bio_max_segs(howmany(count, PAGE_SIZE));
106ad5b325SChristoph Hellwig }
116ad5b325SChristoph Hellwig 
126ad5b325SChristoph Hellwig int
136ad5b325SChristoph Hellwig xfs_rw_bdev(
146ad5b325SChristoph Hellwig 	struct block_device	*bdev,
156ad5b325SChristoph Hellwig 	sector_t		sector,
166ad5b325SChristoph Hellwig 	unsigned int		count,
176ad5b325SChristoph Hellwig 	char			*data,
186ad5b325SChristoph Hellwig 	unsigned int		op)
196ad5b325SChristoph Hellwig 
206ad5b325SChristoph Hellwig {
216ad5b325SChristoph Hellwig 	unsigned int		is_vmalloc = is_vmalloc_addr(data);
226ad5b325SChristoph Hellwig 	unsigned int		left = count;
236ad5b325SChristoph Hellwig 	int			error;
246ad5b325SChristoph Hellwig 	struct bio		*bio;
256ad5b325SChristoph Hellwig 
266ad5b325SChristoph Hellwig 	if (is_vmalloc && op == REQ_OP_WRITE)
276ad5b325SChristoph Hellwig 		flush_kernel_vmap_range(data, count);
286ad5b325SChristoph Hellwig 
296ad5b325SChristoph Hellwig 	bio = bio_alloc(GFP_KERNEL, bio_max_vecs(left));
306ad5b325SChristoph Hellwig 	bio_set_dev(bio, bdev);
316ad5b325SChristoph Hellwig 	bio->bi_iter.bi_sector = sector;
326ad5b325SChristoph Hellwig 	bio->bi_opf = op | REQ_META | REQ_SYNC;
336ad5b325SChristoph Hellwig 
346ad5b325SChristoph Hellwig 	do {
356ad5b325SChristoph Hellwig 		struct page	*page = kmem_to_page(data);
366ad5b325SChristoph Hellwig 		unsigned int	off = offset_in_page(data);
376ad5b325SChristoph Hellwig 		unsigned int	len = min_t(unsigned, left, PAGE_SIZE - off);
386ad5b325SChristoph Hellwig 
396ad5b325SChristoph Hellwig 		while (bio_add_page(bio, page, len, off) != len) {
406ad5b325SChristoph Hellwig 			struct bio	*prev = bio;
416ad5b325SChristoph Hellwig 
426ad5b325SChristoph Hellwig 			bio = bio_alloc(GFP_KERNEL, bio_max_vecs(left));
436ad5b325SChristoph Hellwig 			bio_copy_dev(bio, prev);
446ad5b325SChristoph Hellwig 			bio->bi_iter.bi_sector = bio_end_sector(prev);
456ad5b325SChristoph Hellwig 			bio->bi_opf = prev->bi_opf;
46488ca3d8SChristoph Hellwig 			bio_chain(prev, bio);
476ad5b325SChristoph Hellwig 
486ad5b325SChristoph Hellwig 			submit_bio(prev);
496ad5b325SChristoph Hellwig 		}
506ad5b325SChristoph Hellwig 
516ad5b325SChristoph Hellwig 		data += len;
526ad5b325SChristoph Hellwig 		left -= len;
536ad5b325SChristoph Hellwig 	} while (left > 0);
546ad5b325SChristoph Hellwig 
556ad5b325SChristoph Hellwig 	error = submit_bio_wait(bio);
566ad5b325SChristoph Hellwig 	bio_put(bio);
576ad5b325SChristoph Hellwig 
586ad5b325SChristoph Hellwig 	if (is_vmalloc && op == REQ_OP_READ)
596ad5b325SChristoph Hellwig 		invalidate_kernel_vmap_range(data, count);
606ad5b325SChristoph Hellwig 	return error;
616ad5b325SChristoph Hellwig }
62