diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2012-08-28 10:51:19 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-09-26 09:45:01 -0400 |
commit | 0d804b20735d974534abb422f723d404b779433a (patch) | |
tree | 5ca065600a604eec5c45878cb0f432fb5c2b397d /drivers/s390/block | |
parent | f30664e2c85c7804f07c636bbe99f35e0b2d4c76 (diff) |
s390/scm_block: force cluster writes
Force writes to Storage Class Memory (SCM) to be in done in clusters.
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block')
-rw-r--r-- | drivers/s390/block/Kconfig | 7 | ||||
-rw-r--r-- | drivers/s390/block/Makefile | 3 | ||||
-rw-r--r-- | drivers/s390/block/scm_blk.c | 37 | ||||
-rw-r--r-- | drivers/s390/block/scm_blk.h | 38 | ||||
-rw-r--r-- | drivers/s390/block/scm_blk_cluster.c | 228 |
5 files changed, 310 insertions, 3 deletions
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index 18178b64e89a..4a3b62326183 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig | |||
@@ -81,3 +81,10 @@ config SCM_BLOCK | |||
81 | 81 | ||
82 | To compile this driver as a module, choose M here: the | 82 | To compile this driver as a module, choose M here: the |
83 | module will be called scm_block. | 83 | module will be called scm_block. |
84 | |||
85 | config SCM_BLOCK_CLUSTER_WRITE | ||
86 | def_bool y | ||
87 | prompt "SCM force cluster writes" | ||
88 | depends on SCM_BLOCK | ||
89 | help | ||
90 | Force writes to Storage Class Memory (SCM) to be in done in clusters. | ||
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index b64e2b32c753..c2f4e673e031 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile | |||
@@ -19,4 +19,7 @@ obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o | |||
19 | obj-$(CONFIG_DCSSBLK) += dcssblk.o | 19 | obj-$(CONFIG_DCSSBLK) += dcssblk.o |
20 | 20 | ||
21 | scm_block-objs := scm_drv.o scm_blk.o | 21 | scm_block-objs := scm_drv.o scm_blk.o |
22 | ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
23 | scm_block-objs += scm_blk_cluster.o | ||
24 | endif | ||
22 | obj-$(CONFIG_SCM_BLOCK) += scm_block.o | 25 | obj-$(CONFIG_SCM_BLOCK) += scm_block.o |
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 634ad58cbef6..9978ad4433cb 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c | |||
@@ -37,6 +37,7 @@ static void __scm_free_rq(struct scm_request *scmrq) | |||
37 | 37 | ||
38 | free_page((unsigned long) scmrq->aob); | 38 | free_page((unsigned long) scmrq->aob); |
39 | free_page((unsigned long) scmrq->aidaw); | 39 | free_page((unsigned long) scmrq->aidaw); |
40 | __scm_free_rq_cluster(scmrq); | ||
40 | kfree(aobrq); | 41 | kfree(aobrq); |
41 | } | 42 | } |
42 | 43 | ||
@@ -70,6 +71,12 @@ static int __scm_alloc_rq(void) | |||
70 | __scm_free_rq(scmrq); | 71 | __scm_free_rq(scmrq); |
71 | return -ENOMEM; | 72 | return -ENOMEM; |
72 | } | 73 | } |
74 | |||
75 | if (__scm_alloc_rq_cluster(scmrq)) { | ||
76 | __scm_free_rq(scmrq); | ||
77 | return -ENOMEM; | ||
78 | } | ||
79 | |||
73 | INIT_LIST_HEAD(&scmrq->list); | 80 | INIT_LIST_HEAD(&scmrq->list); |
74 | spin_lock_irq(&list_lock); | 81 | spin_lock_irq(&list_lock); |
75 | list_add(&scmrq->list, &inactive_requests); | 82 | list_add(&scmrq->list, &inactive_requests); |
@@ -170,6 +177,7 @@ static inline void scm_request_init(struct scm_blk_dev *bdev, | |||
170 | scmrq->bdev = bdev; | 177 | scmrq->bdev = bdev; |
171 | scmrq->retries = 4; | 178 | scmrq->retries = 4; |
172 | scmrq->error = 0; | 179 | scmrq->error = 0; |
180 | scm_request_cluster_init(scmrq); | ||
173 | } | 181 | } |
174 | 182 | ||
175 | static void scm_ensure_queue_restart(struct scm_blk_dev *bdev) | 183 | static void scm_ensure_queue_restart(struct scm_blk_dev *bdev) |
@@ -181,17 +189,19 @@ static void scm_ensure_queue_restart(struct scm_blk_dev *bdev) | |||
181 | blk_delay_queue(bdev->rq, SCM_QUEUE_DELAY); | 189 | blk_delay_queue(bdev->rq, SCM_QUEUE_DELAY); |
182 | } | 190 | } |
183 | 191 | ||
184 | static void scm_request_requeue(struct scm_request *scmrq) | 192 | void scm_request_requeue(struct scm_request *scmrq) |
185 | { | 193 | { |
186 | struct scm_blk_dev *bdev = scmrq->bdev; | 194 | struct scm_blk_dev *bdev = scmrq->bdev; |
187 | 195 | ||
196 | scm_release_cluster(scmrq); | ||
188 | blk_requeue_request(bdev->rq, scmrq->request); | 197 | blk_requeue_request(bdev->rq, scmrq->request); |
189 | scm_request_done(scmrq); | 198 | scm_request_done(scmrq); |
190 | scm_ensure_queue_restart(bdev); | 199 | scm_ensure_queue_restart(bdev); |
191 | } | 200 | } |
192 | 201 | ||
193 | static void scm_request_finish(struct scm_request *scmrq) | 202 | void scm_request_finish(struct scm_request *scmrq) |
194 | { | 203 | { |
204 | scm_release_cluster(scmrq); | ||
195 | blk_end_request_all(scmrq->request, scmrq->error); | 205 | blk_end_request_all(scmrq->request, scmrq->error); |
196 | scm_request_done(scmrq); | 206 | scm_request_done(scmrq); |
197 | } | 207 | } |
@@ -215,6 +225,16 @@ static void scm_blk_request(struct request_queue *rq) | |||
215 | return; | 225 | return; |
216 | } | 226 | } |
217 | scm_request_init(bdev, scmrq, req); | 227 | scm_request_init(bdev, scmrq, req); |
228 | if (!scm_reserve_cluster(scmrq)) { | ||
229 | SCM_LOG(5, "cluster busy"); | ||
230 | scm_request_done(scmrq); | ||
231 | return; | ||
232 | } | ||
233 | if (scm_need_cluster_request(scmrq)) { | ||
234 | blk_start_request(req); | ||
235 | scm_initiate_cluster_request(scmrq); | ||
236 | return; | ||
237 | } | ||
218 | scm_request_prepare(scmrq); | 238 | scm_request_prepare(scmrq); |
219 | blk_start_request(req); | 239 | blk_start_request(req); |
220 | 240 | ||
@@ -282,6 +302,13 @@ static void scm_blk_tasklet(struct scm_blk_dev *bdev) | |||
282 | spin_lock_irqsave(&bdev->lock, flags); | 302 | spin_lock_irqsave(&bdev->lock, flags); |
283 | continue; | 303 | continue; |
284 | } | 304 | } |
305 | |||
306 | if (scm_test_cluster_request(scmrq)) { | ||
307 | scm_cluster_request_irq(scmrq); | ||
308 | spin_lock_irqsave(&bdev->lock, flags); | ||
309 | continue; | ||
310 | } | ||
311 | |||
285 | scm_request_finish(scmrq); | 312 | scm_request_finish(scmrq); |
286 | atomic_dec(&bdev->queued_reqs); | 313 | atomic_dec(&bdev->queued_reqs); |
287 | spin_lock_irqsave(&bdev->lock, flags); | 314 | spin_lock_irqsave(&bdev->lock, flags); |
@@ -325,6 +352,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) | |||
325 | blk_queue_max_hw_sectors(rq, nr_max_blk << 3); /* 8 * 512 = blk_size */ | 352 | blk_queue_max_hw_sectors(rq, nr_max_blk << 3); /* 8 * 512 = blk_size */ |
326 | blk_queue_max_segments(rq, nr_max_blk); | 353 | blk_queue_max_segments(rq, nr_max_blk); |
327 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rq); | 354 | queue_flag_set_unlocked(QUEUE_FLAG_NONROT, rq); |
355 | scm_blk_dev_cluster_setup(bdev); | ||
328 | 356 | ||
329 | bdev->gendisk = alloc_disk(SCM_NR_PARTS); | 357 | bdev->gendisk = alloc_disk(SCM_NR_PARTS); |
330 | if (!bdev->gendisk) | 358 | if (!bdev->gendisk) |
@@ -370,7 +398,10 @@ void scm_blk_dev_cleanup(struct scm_blk_dev *bdev) | |||
370 | 398 | ||
371 | static int __init scm_blk_init(void) | 399 | static int __init scm_blk_init(void) |
372 | { | 400 | { |
373 | int ret; | 401 | int ret = -EINVAL; |
402 | |||
403 | if (!scm_cluster_size_valid()) | ||
404 | goto out; | ||
374 | 405 | ||
375 | ret = register_blkdev(0, "scm"); | 406 | ret = register_blkdev(0, "scm"); |
376 | if (ret < 0) | 407 | if (ret < 0) |
diff --git a/drivers/s390/block/scm_blk.h b/drivers/s390/block/scm_blk.h index 5aba5612588f..7ac6bad919ef 100644 --- a/drivers/s390/block/scm_blk.h +++ b/drivers/s390/block/scm_blk.h | |||
@@ -22,6 +22,9 @@ struct scm_blk_dev { | |||
22 | spinlock_t lock; /* guard the rest of the blockdev */ | 22 | spinlock_t lock; /* guard the rest of the blockdev */ |
23 | atomic_t queued_reqs; | 23 | atomic_t queued_reqs; |
24 | struct list_head finished_requests; | 24 | struct list_head finished_requests; |
25 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
26 | struct list_head cluster_list; | ||
27 | #endif | ||
25 | }; | 28 | }; |
26 | 29 | ||
27 | struct scm_request { | 30 | struct scm_request { |
@@ -32,6 +35,13 @@ struct scm_request { | |||
32 | struct list_head list; | 35 | struct list_head list; |
33 | u8 retries; | 36 | u8 retries; |
34 | int error; | 37 | int error; |
38 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
39 | struct { | ||
40 | enum {CLUSTER_NONE, CLUSTER_READ, CLUSTER_WRITE} state; | ||
41 | struct list_head list; | ||
42 | void **buf; | ||
43 | } cluster; | ||
44 | #endif | ||
35 | }; | 45 | }; |
36 | 46 | ||
37 | #define to_aobrq(rq) container_of((void *) rq, struct aob_rq_header, data) | 47 | #define to_aobrq(rq) container_of((void *) rq, struct aob_rq_header, data) |
@@ -40,9 +50,37 @@ int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *); | |||
40 | void scm_blk_dev_cleanup(struct scm_blk_dev *); | 50 | void scm_blk_dev_cleanup(struct scm_blk_dev *); |
41 | void scm_blk_irq(struct scm_device *, void *, int); | 51 | void scm_blk_irq(struct scm_device *, void *, int); |
42 | 52 | ||
53 | void scm_request_finish(struct scm_request *); | ||
54 | void scm_request_requeue(struct scm_request *); | ||
55 | |||
43 | int scm_drv_init(void); | 56 | int scm_drv_init(void); |
44 | void scm_drv_cleanup(void); | 57 | void scm_drv_cleanup(void); |
45 | 58 | ||
59 | #ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE | ||
60 | void __scm_free_rq_cluster(struct scm_request *); | ||
61 | int __scm_alloc_rq_cluster(struct scm_request *); | ||
62 | void scm_request_cluster_init(struct scm_request *); | ||
63 | bool scm_reserve_cluster(struct scm_request *); | ||
64 | void scm_release_cluster(struct scm_request *); | ||
65 | void scm_blk_dev_cluster_setup(struct scm_blk_dev *); | ||
66 | bool scm_need_cluster_request(struct scm_request *); | ||
67 | void scm_initiate_cluster_request(struct scm_request *); | ||
68 | void scm_cluster_request_irq(struct scm_request *); | ||
69 | bool scm_test_cluster_request(struct scm_request *); | ||
70 | bool scm_cluster_size_valid(void); | ||
71 | #else | ||
72 | #define __scm_free_rq_cluster(scmrq) {} | ||
73 | #define __scm_alloc_rq_cluster(scmrq) 0 | ||
74 | #define scm_request_cluster_init(scmrq) {} | ||
75 | #define scm_reserve_cluster(scmrq) true | ||
76 | #define scm_release_cluster(scmrq) {} | ||
77 | #define scm_blk_dev_cluster_setup(bdev) {} | ||
78 | #define scm_need_cluster_request(scmrq) false | ||
79 | #define scm_initiate_cluster_request(scmrq) {} | ||
80 | #define scm_cluster_request_irq(scmrq) {} | ||
81 | #define scm_test_cluster_request(scmrq) false | ||
82 | #define scm_cluster_size_valid() true | ||
83 | #endif | ||
46 | 84 | ||
47 | extern debug_info_t *scm_debug; | 85 | extern debug_info_t *scm_debug; |
48 | 86 | ||
diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c new file mode 100644 index 000000000000..f4bb61b0cea1 --- /dev/null +++ b/drivers/s390/block/scm_blk_cluster.c | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * Block driver for s390 storage class memory. | ||
3 | * | ||
4 | * Copyright IBM Corp. 2012 | ||
5 | * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/spinlock.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/blkdev.h> | ||
11 | #include <linux/genhd.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <asm/eadm.h> | ||
15 | #include "scm_blk.h" | ||
16 | |||
17 | static unsigned int write_cluster_size = 64; | ||
18 | module_param(write_cluster_size, uint, S_IRUGO); | ||
19 | MODULE_PARM_DESC(write_cluster_size, | ||
20 | "Number of pages used for contiguous writes."); | ||
21 | |||
22 | #define CLUSTER_SIZE (write_cluster_size * PAGE_SIZE) | ||
23 | |||
24 | void __scm_free_rq_cluster(struct scm_request *scmrq) | ||
25 | { | ||
26 | int i; | ||
27 | |||
28 | if (!scmrq->cluster.buf) | ||
29 | return; | ||
30 | |||
31 | for (i = 0; i < 2 * write_cluster_size; i++) | ||
32 | free_page((unsigned long) scmrq->cluster.buf[i]); | ||
33 | |||
34 | kfree(scmrq->cluster.buf); | ||
35 | } | ||
36 | |||
37 | int __scm_alloc_rq_cluster(struct scm_request *scmrq) | ||
38 | { | ||
39 | int i; | ||
40 | |||
41 | scmrq->cluster.buf = kzalloc(sizeof(void *) * 2 * write_cluster_size, | ||
42 | GFP_KERNEL); | ||
43 | if (!scmrq->cluster.buf) | ||
44 | return -ENOMEM; | ||
45 | |||
46 | for (i = 0; i < 2 * write_cluster_size; i++) { | ||
47 | scmrq->cluster.buf[i] = (void *) get_zeroed_page(GFP_DMA); | ||
48 | if (!scmrq->cluster.buf[i]) | ||
49 | return -ENOMEM; | ||
50 | } | ||
51 | INIT_LIST_HEAD(&scmrq->cluster.list); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | void scm_request_cluster_init(struct scm_request *scmrq) | ||
56 | { | ||
57 | scmrq->cluster.state = CLUSTER_NONE; | ||
58 | } | ||
59 | |||
60 | static bool clusters_intersect(struct scm_request *A, struct scm_request *B) | ||
61 | { | ||
62 | unsigned long firstA, lastA, firstB, lastB; | ||
63 | |||
64 | firstA = ((u64) blk_rq_pos(A->request) << 9) / CLUSTER_SIZE; | ||
65 | lastA = (((u64) blk_rq_pos(A->request) << 9) + | ||
66 | blk_rq_bytes(A->request) - 1) / CLUSTER_SIZE; | ||
67 | |||
68 | firstB = ((u64) blk_rq_pos(B->request) << 9) / CLUSTER_SIZE; | ||
69 | lastB = (((u64) blk_rq_pos(B->request) << 9) + | ||
70 | blk_rq_bytes(B->request) - 1) / CLUSTER_SIZE; | ||
71 | |||
72 | return (firstB <= lastA && firstA <= lastB); | ||
73 | } | ||
74 | |||
75 | bool scm_reserve_cluster(struct scm_request *scmrq) | ||
76 | { | ||
77 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
78 | struct scm_request *iter; | ||
79 | |||
80 | if (write_cluster_size == 0) | ||
81 | return true; | ||
82 | |||
83 | spin_lock(&bdev->lock); | ||
84 | list_for_each_entry(iter, &bdev->cluster_list, cluster.list) { | ||
85 | if (clusters_intersect(scmrq, iter) && | ||
86 | (rq_data_dir(scmrq->request) == WRITE || | ||
87 | rq_data_dir(iter->request) == WRITE)) { | ||
88 | spin_unlock(&bdev->lock); | ||
89 | return false; | ||
90 | } | ||
91 | } | ||
92 | list_add(&scmrq->cluster.list, &bdev->cluster_list); | ||
93 | spin_unlock(&bdev->lock); | ||
94 | |||
95 | return true; | ||
96 | } | ||
97 | |||
98 | void scm_release_cluster(struct scm_request *scmrq) | ||
99 | { | ||
100 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
101 | unsigned long flags; | ||
102 | |||
103 | if (write_cluster_size == 0) | ||
104 | return; | ||
105 | |||
106 | spin_lock_irqsave(&bdev->lock, flags); | ||
107 | list_del(&scmrq->cluster.list); | ||
108 | spin_unlock_irqrestore(&bdev->lock, flags); | ||
109 | } | ||
110 | |||
111 | void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev) | ||
112 | { | ||
113 | INIT_LIST_HEAD(&bdev->cluster_list); | ||
114 | blk_queue_io_opt(bdev->rq, CLUSTER_SIZE); | ||
115 | } | ||
116 | |||
117 | static void scm_prepare_cluster_request(struct scm_request *scmrq) | ||
118 | { | ||
119 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
120 | struct scm_device *scmdev = bdev->gendisk->private_data; | ||
121 | struct request *req = scmrq->request; | ||
122 | struct aidaw *aidaw = scmrq->aidaw; | ||
123 | struct msb *msb = &scmrq->aob->msb[0]; | ||
124 | struct req_iterator iter; | ||
125 | struct bio_vec *bv; | ||
126 | int i = 0; | ||
127 | u64 addr; | ||
128 | |||
129 | switch (scmrq->cluster.state) { | ||
130 | case CLUSTER_NONE: | ||
131 | scmrq->cluster.state = CLUSTER_READ; | ||
132 | /* fall through */ | ||
133 | case CLUSTER_READ: | ||
134 | scmrq->aob->request.msb_count = 1; | ||
135 | msb->bs = MSB_BS_4K; | ||
136 | msb->oc = MSB_OC_READ; | ||
137 | msb->flags = MSB_FLAG_IDA; | ||
138 | msb->data_addr = (u64) aidaw; | ||
139 | msb->blk_count = write_cluster_size; | ||
140 | |||
141 | addr = scmdev->address + ((u64) blk_rq_pos(req) << 9); | ||
142 | msb->scm_addr = round_down(addr, CLUSTER_SIZE); | ||
143 | |||
144 | if (msb->scm_addr != | ||
145 | round_down(addr + (u64) blk_rq_bytes(req) - 1, | ||
146 | CLUSTER_SIZE)) | ||
147 | msb->blk_count = 2 * write_cluster_size; | ||
148 | |||
149 | for (i = 0; i < msb->blk_count; i++) { | ||
150 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
151 | aidaw++; | ||
152 | } | ||
153 | |||
154 | break; | ||
155 | case CLUSTER_WRITE: | ||
156 | msb->oc = MSB_OC_WRITE; | ||
157 | |||
158 | for (addr = msb->scm_addr; | ||
159 | addr < scmdev->address + ((u64) blk_rq_pos(req) << 9); | ||
160 | addr += PAGE_SIZE) { | ||
161 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
162 | aidaw++; | ||
163 | i++; | ||
164 | } | ||
165 | rq_for_each_segment(bv, req, iter) { | ||
166 | aidaw->data_addr = (u64) page_address(bv->bv_page); | ||
167 | aidaw++; | ||
168 | i++; | ||
169 | } | ||
170 | for (; i < msb->blk_count; i++) { | ||
171 | aidaw->data_addr = (u64) scmrq->cluster.buf[i]; | ||
172 | aidaw++; | ||
173 | } | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | bool scm_need_cluster_request(struct scm_request *scmrq) | ||
179 | { | ||
180 | if (rq_data_dir(scmrq->request) == READ) | ||
181 | return false; | ||
182 | |||
183 | return blk_rq_bytes(scmrq->request) < CLUSTER_SIZE; | ||
184 | } | ||
185 | |||
186 | /* Called with queue lock held. */ | ||
187 | void scm_initiate_cluster_request(struct scm_request *scmrq) | ||
188 | { | ||
189 | scm_prepare_cluster_request(scmrq); | ||
190 | if (scm_start_aob(scmrq->aob)) | ||
191 | scm_request_requeue(scmrq); | ||
192 | } | ||
193 | |||
194 | bool scm_test_cluster_request(struct scm_request *scmrq) | ||
195 | { | ||
196 | return scmrq->cluster.state != CLUSTER_NONE; | ||
197 | } | ||
198 | |||
199 | void scm_cluster_request_irq(struct scm_request *scmrq) | ||
200 | { | ||
201 | struct scm_blk_dev *bdev = scmrq->bdev; | ||
202 | unsigned long flags; | ||
203 | |||
204 | switch (scmrq->cluster.state) { | ||
205 | case CLUSTER_NONE: | ||
206 | BUG(); | ||
207 | break; | ||
208 | case CLUSTER_READ: | ||
209 | if (scmrq->error) { | ||
210 | scm_request_finish(scmrq); | ||
211 | break; | ||
212 | } | ||
213 | scmrq->cluster.state = CLUSTER_WRITE; | ||
214 | spin_lock_irqsave(&bdev->rq_lock, flags); | ||
215 | scm_initiate_cluster_request(scmrq); | ||
216 | spin_unlock_irqrestore(&bdev->rq_lock, flags); | ||
217 | break; | ||
218 | case CLUSTER_WRITE: | ||
219 | scm_request_finish(scmrq); | ||
220 | break; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | bool scm_cluster_size_valid(void) | ||
225 | { | ||
226 | return write_cluster_size == 0 || write_cluster_size == 32 || | ||
227 | write_cluster_size == 64 || write_cluster_size == 128; | ||
228 | } | ||