hc
2024-02-20 e636c8d336489bf3eed5878299e6cc045bbad077
kernel/drivers/block/brd.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Ram backed block device driver.
34 *
....@@ -79,11 +80,9 @@
7980 }
8081
8182 /*
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.
8584 */
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)
8786 {
8887 pgoff_t idx;
8988 struct page *page;
....@@ -91,7 +90,7 @@
9190
9291 page = brd_lookup_page(brd, sector);
9392 if (page)
94
- return page;
93
+ return 0;
9594
9695 /*
9796 * Must use NOIO because we don't want to recurse back into the
....@@ -100,11 +99,11 @@
10099 gfp_flags = GFP_NOIO | __GFP_ZERO | __GFP_HIGHMEM;
101100 page = alloc_page(gfp_flags);
102101 if (!page)
103
- return NULL;
102
+ return -ENOMEM;
104103
105104 if (radix_tree_preload(GFP_NOIO)) {
106105 __free_page(page);
107
- return NULL;
106
+ return -ENOMEM;
108107 }
109108
110109 spin_lock(&brd->brd_lock);
....@@ -119,8 +118,7 @@
119118 spin_unlock(&brd->brd_lock);
120119
121120 radix_tree_preload_end();
122
-
123
- return page;
121
+ return 0;
124122 }
125123
126124 /*
....@@ -153,6 +151,12 @@
153151 pos++;
154152
155153 /*
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
+ /*
156160 * This assumes radix_tree_gang_lookup always returns as
157161 * many pages as possible. If the radix-tree code changes,
158162 * so will this have to.
....@@ -167,16 +171,17 @@
167171 {
168172 unsigned int offset = (sector & (PAGE_SECTORS-1)) << SECTOR_SHIFT;
169173 size_t copy;
174
+ int ret;
170175
171176 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;
174180 if (copy < n) {
175181 sector += copy >> SECTOR_SHIFT;
176
- if (!brd_insert_page(brd, sector))
177
- return -ENOSPC;
182
+ ret = brd_insert_page(brd, sector);
178183 }
179
- return 0;
184
+ return ret;
180185 }
181186
182187 /*
....@@ -275,7 +280,7 @@
275280 return err;
276281 }
277282
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)
279284 {
280285 struct brd_device *brd = bio->bi_disk->private_data;
281286 struct bio_vec bvec;
....@@ -289,6 +294,10 @@
289294 bio_for_each_segment(bvec, bio, iter) {
290295 unsigned int len = bvec.bv_len;
291296 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)));
292301
293302 err = brd_do_bvec(brd, bvec.bv_page, len, bvec.bv_offset,
294303 bio_op(bio), sector);
....@@ -319,6 +328,7 @@
319328
320329 static const struct block_device_operations brd_fops = {
321330 .owner = THIS_MODULE,
331
+ .submit_bio = brd_submit_bio,
322332 .rw_page = brd_rw_page,
323333 };
324334
....@@ -370,12 +380,9 @@
370380 spin_lock_init(&brd->brd_lock);
371381 INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
372382
373
- brd->brd_queue = blk_alloc_queue(GFP_KERNEL);
383
+ brd->brd_queue = blk_alloc_queue(NUMA_NO_NODE);
374384 if (!brd->brd_queue)
375385 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);
379386
380387 /* This is so fdisk will align partitions on 4k, because of
381388 * direct_access API needing 4k alignment, returning a PFN
....@@ -394,7 +401,6 @@
394401 disk->flags = GENHD_FL_EXT_DEVT;
395402 sprintf(disk->disk_name, "ram%d", i);
396403 set_capacity(disk, rd_size * 2);
397
- brd->brd_queue->backing_dev_info->capabilities |= BDI_CAP_SYNCHRONOUS_IO;
398404
399405 /* Tell the block layer that this is not a rotational device */
400406 blk_queue_flag_set(QUEUE_FLAG_NONROT, brd->brd_queue);