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
bio_max_vecs(unsigned int count)76ad5b325SChristoph Hellwig static inline unsigned int bio_max_vecs(unsigned int count)
86ad5b325SChristoph Hellwig {
95f7136dbSMatthew Wilcox (Oracle) return bio_max_segs(howmany(count, PAGE_SIZE));
106ad5b325SChristoph Hellwig }
116ad5b325SChristoph Hellwig
126ad5b325SChristoph Hellwig int
xfs_rw_bdev(struct block_device * bdev,sector_t sector,unsigned int count,char * data,enum req_op op)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,
18*d03025aeSBart Van Assche enum req_op 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
2907888c66SChristoph Hellwig bio = bio_alloc(bdev, bio_max_vecs(left), op | REQ_META | REQ_SYNC,
3007888c66SChristoph Hellwig GFP_KERNEL);
316ad5b325SChristoph Hellwig bio->bi_iter.bi_sector = sector;
326ad5b325SChristoph Hellwig
336ad5b325SChristoph Hellwig do {
346ad5b325SChristoph Hellwig struct page *page = kmem_to_page(data);
356ad5b325SChristoph Hellwig unsigned int off = offset_in_page(data);
366ad5b325SChristoph Hellwig unsigned int len = min_t(unsigned, left, PAGE_SIZE - off);
376ad5b325SChristoph Hellwig
386ad5b325SChristoph Hellwig while (bio_add_page(bio, page, len, off) != len) {
396ad5b325SChristoph Hellwig struct bio *prev = bio;
406ad5b325SChristoph Hellwig
4107888c66SChristoph Hellwig bio = bio_alloc(prev->bi_bdev, bio_max_vecs(left),
4207888c66SChristoph Hellwig prev->bi_opf, GFP_KERNEL);
436ad5b325SChristoph Hellwig bio->bi_iter.bi_sector = bio_end_sector(prev);
44488ca3d8SChristoph Hellwig bio_chain(prev, bio);
456ad5b325SChristoph Hellwig
466ad5b325SChristoph Hellwig submit_bio(prev);
476ad5b325SChristoph Hellwig }
486ad5b325SChristoph Hellwig
496ad5b325SChristoph Hellwig data += len;
506ad5b325SChristoph Hellwig left -= len;
516ad5b325SChristoph Hellwig } while (left > 0);
526ad5b325SChristoph Hellwig
536ad5b325SChristoph Hellwig error = submit_bio_wait(bio);
546ad5b325SChristoph Hellwig bio_put(bio);
556ad5b325SChristoph Hellwig
566ad5b325SChristoph Hellwig if (is_vmalloc && op == REQ_OP_READ)
576ad5b325SChristoph Hellwig invalidate_kernel_vmap_range(data, count);
586ad5b325SChristoph Hellwig return error;
596ad5b325SChristoph Hellwig }
60