| .. | .. |
|---|
| 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); |
|---|