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 { 95f7136dbSMatthew 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, 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