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