.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Ram backed block device driver. |
---|
3 | 4 | * |
---|
.. | .. |
---|
79 | 80 | } |
---|
80 | 81 | |
---|
81 | 82 | /* |
---|
82 | | - * Look up and return a brd's page for a given sector. |
---|
83 | | - * If one does not exist, allocate an empty page, and insert that. Then |
---|
84 | | - * return it. |
---|
| 83 | + * Insert a new page for a given sector, if one does not already exist. |
---|
85 | 84 | */ |
---|
86 | | -static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) |
---|
| 85 | +static int brd_insert_page(struct brd_device *brd, sector_t sector) |
---|
87 | 86 | { |
---|
88 | 87 | pgoff_t idx; |
---|
89 | 88 | struct page *page; |
---|
.. | .. |
---|
91 | 90 | |
---|
92 | 91 | page = brd_lookup_page(brd, sector); |
---|
93 | 92 | if (page) |
---|
94 | | - return page; |
---|
| 93 | + return 0; |
---|
95 | 94 | |
---|
96 | 95 | /* |
---|
97 | 96 | * Must use NOIO because we don't want to recurse back into the |
---|
.. | .. |
---|
100 | 99 | gfp_flags = GFP_NOIO | __GFP_ZERO | __GFP_HIGHMEM; |
---|
101 | 100 | page = alloc_page(gfp_flags); |
---|
102 | 101 | if (!page) |
---|
103 | | - return NULL; |
---|
| 102 | + return -ENOMEM; |
---|
104 | 103 | |
---|
105 | 104 | if (radix_tree_preload(GFP_NOIO)) { |
---|
106 | 105 | __free_page(page); |
---|
107 | | - return NULL; |
---|
| 106 | + return -ENOMEM; |
---|
108 | 107 | } |
---|
109 | 108 | |
---|
110 | 109 | spin_lock(&brd->brd_lock); |
---|
.. | .. |
---|
119 | 118 | spin_unlock(&brd->brd_lock); |
---|
120 | 119 | |
---|
121 | 120 | radix_tree_preload_end(); |
---|
122 | | - |
---|
123 | | - return page; |
---|
| 121 | + return 0; |
---|
124 | 122 | } |
---|
125 | 123 | |
---|
126 | 124 | /* |
---|
.. | .. |
---|
153 | 151 | pos++; |
---|
154 | 152 | |
---|
155 | 153 | /* |
---|
| 154 | + * It takes 3.4 seconds to remove 80GiB ramdisk. |
---|
| 155 | + * So, we need cond_resched to avoid stalling the CPU. |
---|
| 156 | + */ |
---|
| 157 | + cond_resched(); |
---|
| 158 | + |
---|
| 159 | + /* |
---|
156 | 160 | * This assumes radix_tree_gang_lookup always returns as |
---|
157 | 161 | * many pages as possible. If the radix-tree code changes, |
---|
158 | 162 | * so will this have to. |
---|
.. | .. |
---|
167 | 171 | { |
---|
168 | 172 | unsigned int offset = (sector & (PAGE_SECTORS-1)) << SECTOR_SHIFT; |
---|
169 | 173 | size_t copy; |
---|
| 174 | + int ret; |
---|
170 | 175 | |
---|
171 | 176 | copy = min_t(size_t, n, PAGE_SIZE - offset); |
---|
172 | | - if (!brd_insert_page(brd, sector)) |
---|
173 | | - return -ENOSPC; |
---|
| 177 | + ret = brd_insert_page(brd, sector); |
---|
| 178 | + if (ret) |
---|
| 179 | + return ret; |
---|
174 | 180 | if (copy < n) { |
---|
175 | 181 | sector += copy >> SECTOR_SHIFT; |
---|
176 | | - if (!brd_insert_page(brd, sector)) |
---|
177 | | - return -ENOSPC; |
---|
| 182 | + ret = brd_insert_page(brd, sector); |
---|
178 | 183 | } |
---|
179 | | - return 0; |
---|
| 184 | + return ret; |
---|
180 | 185 | } |
---|
181 | 186 | |
---|
182 | 187 | /* |
---|
.. | .. |
---|
275 | 280 | return err; |
---|
276 | 281 | } |
---|
277 | 282 | |
---|
278 | | -static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio) |
---|
| 283 | +static blk_qc_t brd_submit_bio(struct bio *bio) |
---|
279 | 284 | { |
---|
280 | 285 | struct brd_device *brd = bio->bi_disk->private_data; |
---|
281 | 286 | struct bio_vec bvec; |
---|
.. | .. |
---|
289 | 294 | bio_for_each_segment(bvec, bio, iter) { |
---|
290 | 295 | unsigned int len = bvec.bv_len; |
---|
291 | 296 | int err; |
---|
| 297 | + |
---|
| 298 | + /* Don't support un-aligned buffer */ |
---|
| 299 | + WARN_ON_ONCE((bvec.bv_offset & (SECTOR_SIZE - 1)) || |
---|
| 300 | + (len & (SECTOR_SIZE - 1))); |
---|
292 | 301 | |
---|
293 | 302 | err = brd_do_bvec(brd, bvec.bv_page, len, bvec.bv_offset, |
---|
294 | 303 | bio_op(bio), sector); |
---|
.. | .. |
---|
319 | 328 | |
---|
320 | 329 | static const struct block_device_operations brd_fops = { |
---|
321 | 330 | .owner = THIS_MODULE, |
---|
| 331 | + .submit_bio = brd_submit_bio, |
---|
322 | 332 | .rw_page = brd_rw_page, |
---|
323 | 333 | }; |
---|
324 | 334 | |
---|
.. | .. |
---|
370 | 380 | spin_lock_init(&brd->brd_lock); |
---|
371 | 381 | INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC); |
---|
372 | 382 | |
---|
373 | | - brd->brd_queue = blk_alloc_queue(GFP_KERNEL); |
---|
| 383 | + brd->brd_queue = blk_alloc_queue(NUMA_NO_NODE); |
---|
374 | 384 | if (!brd->brd_queue) |
---|
375 | 385 | goto out_free_dev; |
---|
376 | | - |
---|
377 | | - blk_queue_make_request(brd->brd_queue, brd_make_request); |
---|
378 | | - blk_queue_max_hw_sectors(brd->brd_queue, 1024); |
---|
379 | 386 | |
---|
380 | 387 | /* This is so fdisk will align partitions on 4k, because of |
---|
381 | 388 | * direct_access API needing 4k alignment, returning a PFN |
---|
.. | .. |
---|
394 | 401 | disk->flags = GENHD_FL_EXT_DEVT; |
---|
395 | 402 | sprintf(disk->disk_name, "ram%d", i); |
---|
396 | 403 | set_capacity(disk, rd_size * 2); |
---|
397 | | - brd->brd_queue->backing_dev_info->capabilities |= BDI_CAP_SYNCHRONOUS_IO; |
---|
398 | 404 | |
---|
399 | 405 | /* Tell the block layer that this is not a rotational device */ |
---|
400 | 406 | blk_queue_flag_set(QUEUE_FLAG_NONROT, brd->brd_queue); |
---|