Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/block/null_blk/zoned.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/vmalloc.h>
3
#include <linux/bitmap.h>
4
#include "null_blk.h"
5
6
#define CREATE_TRACE_POINTS
7
#include "trace.h"
8
9
#undef pr_fmt
10
#define pr_fmt(fmt) "null_blk: " fmt
11
12
#define NULL_ZONE_INVALID_WP ((sector_t)-1)
13
14
static inline sector_t mb_to_sects(unsigned long mb)
15
{
16
return ((sector_t)mb * SZ_1M) >> SECTOR_SHIFT;
17
}
18
19
static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
20
{
21
return sect >> ilog2(dev->zone_size_sects);
22
}
23
24
static inline void null_init_zone_lock(struct nullb_device *dev,
25
struct nullb_zone *zone)
26
{
27
if (!dev->memory_backed)
28
spin_lock_init(&zone->spinlock);
29
else
30
mutex_init(&zone->mutex);
31
}
32
33
static inline void null_lock_zone(struct nullb_device *dev,
34
struct nullb_zone *zone)
35
{
36
if (!dev->memory_backed)
37
spin_lock_irq(&zone->spinlock);
38
else
39
mutex_lock(&zone->mutex);
40
}
41
42
static inline void null_unlock_zone(struct nullb_device *dev,
43
struct nullb_zone *zone)
44
{
45
if (!dev->memory_backed)
46
spin_unlock_irq(&zone->spinlock);
47
else
48
mutex_unlock(&zone->mutex);
49
}
50
51
int null_init_zoned_dev(struct nullb_device *dev,
52
struct queue_limits *lim)
53
{
54
sector_t dev_capacity_sects, zone_capacity_sects;
55
struct nullb_zone *zone;
56
sector_t sector = 0;
57
unsigned int i;
58
59
if (!is_power_of_2(dev->zone_size)) {
60
pr_err("zone_size must be power-of-two\n");
61
return -EINVAL;
62
}
63
if (dev->zone_size > dev->size) {
64
pr_err("Zone size larger than device capacity\n");
65
return -EINVAL;
66
}
67
68
if (!dev->zone_capacity)
69
dev->zone_capacity = dev->zone_size;
70
71
if (dev->zone_capacity > dev->zone_size) {
72
pr_err("zone capacity (%lu MB) larger than zone size (%lu MB)\n",
73
dev->zone_capacity, dev->zone_size);
74
return -EINVAL;
75
}
76
77
/*
78
* If a smaller zone capacity was requested, do not allow a smaller last
79
* zone at the same time as such zone configuration does not correspond
80
* to any real zoned device.
81
*/
82
if (dev->zone_capacity != dev->zone_size &&
83
dev->size & (dev->zone_size - 1)) {
84
pr_err("A smaller last zone is not allowed with zone capacity smaller than zone size.\n");
85
return -EINVAL;
86
}
87
88
zone_capacity_sects = mb_to_sects(dev->zone_capacity);
89
dev_capacity_sects = mb_to_sects(dev->size);
90
dev->zone_size_sects = mb_to_sects(dev->zone_size);
91
dev->nr_zones = round_up(dev_capacity_sects, dev->zone_size_sects)
92
>> ilog2(dev->zone_size_sects);
93
94
dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct nullb_zone),
95
GFP_KERNEL | __GFP_ZERO);
96
if (!dev->zones)
97
return -ENOMEM;
98
99
spin_lock_init(&dev->zone_res_lock);
100
101
if (dev->zone_nr_conv >= dev->nr_zones) {
102
dev->zone_nr_conv = dev->nr_zones - 1;
103
pr_info("changed the number of conventional zones to %u",
104
dev->zone_nr_conv);
105
}
106
107
dev->zone_append_max_sectors =
108
min(ALIGN_DOWN(dev->zone_append_max_sectors,
109
dev->blocksize >> SECTOR_SHIFT),
110
zone_capacity_sects);
111
112
/* Max active zones has to be < nbr of seq zones in order to be enforceable */
113
if (dev->zone_max_active >= dev->nr_zones - dev->zone_nr_conv) {
114
dev->zone_max_active = 0;
115
pr_info("zone_max_active limit disabled, limit >= zone count\n");
116
}
117
118
/* Max open zones has to be <= max active zones */
119
if (dev->zone_max_active && dev->zone_max_open > dev->zone_max_active) {
120
dev->zone_max_open = dev->zone_max_active;
121
pr_info("changed the maximum number of open zones to %u\n",
122
dev->zone_max_open);
123
} else if (dev->zone_max_open >= dev->nr_zones - dev->zone_nr_conv) {
124
dev->zone_max_open = 0;
125
pr_info("zone_max_open limit disabled, limit >= zone count\n");
126
}
127
dev->need_zone_res_mgmt = dev->zone_max_active || dev->zone_max_open;
128
dev->imp_close_zone_no = dev->zone_nr_conv;
129
130
for (i = 0; i < dev->zone_nr_conv; i++) {
131
zone = &dev->zones[i];
132
133
null_init_zone_lock(dev, zone);
134
zone->start = sector;
135
zone->len = dev->zone_size_sects;
136
zone->capacity = zone->len;
137
zone->wp = zone->start + zone->len;
138
zone->type = BLK_ZONE_TYPE_CONVENTIONAL;
139
zone->cond = BLK_ZONE_COND_NOT_WP;
140
141
sector += dev->zone_size_sects;
142
}
143
144
for (i = dev->zone_nr_conv; i < dev->nr_zones; i++) {
145
zone = &dev->zones[i];
146
147
null_init_zone_lock(dev, zone);
148
zone->start = sector;
149
if (zone->start + dev->zone_size_sects > dev_capacity_sects)
150
zone->len = dev_capacity_sects - zone->start;
151
else
152
zone->len = dev->zone_size_sects;
153
zone->capacity =
154
min_t(sector_t, zone->len, zone_capacity_sects);
155
zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
156
if (dev->zone_full) {
157
zone->cond = BLK_ZONE_COND_FULL;
158
zone->wp = zone->start + zone->capacity;
159
} else{
160
zone->cond = BLK_ZONE_COND_EMPTY;
161
zone->wp = zone->start;
162
}
163
164
sector += dev->zone_size_sects;
165
}
166
167
lim->features |= BLK_FEAT_ZONED;
168
lim->chunk_sectors = dev->zone_size_sects;
169
lim->max_hw_zone_append_sectors = dev->zone_append_max_sectors;
170
lim->max_open_zones = dev->zone_max_open;
171
lim->max_active_zones = dev->zone_max_active;
172
return 0;
173
}
174
175
int null_register_zoned_dev(struct nullb *nullb)
176
{
177
struct request_queue *q = nullb->q;
178
struct gendisk *disk = nullb->disk;
179
180
pr_info("%s: using %s zone append\n",
181
disk->disk_name,
182
queue_emulates_zone_append(q) ? "emulated" : "native");
183
184
return blk_revalidate_disk_zones(disk);
185
}
186
187
void null_free_zoned_dev(struct nullb_device *dev)
188
{
189
kvfree(dev->zones);
190
dev->zones = NULL;
191
}
192
193
int null_report_zones(struct gendisk *disk, sector_t sector,
194
unsigned int nr_zones, report_zones_cb cb, void *data)
195
{
196
struct nullb *nullb = disk->private_data;
197
struct nullb_device *dev = nullb->dev;
198
unsigned int first_zone, i;
199
struct nullb_zone *zone;
200
struct blk_zone blkz;
201
int error;
202
203
first_zone = null_zone_no(dev, sector);
204
if (first_zone >= dev->nr_zones)
205
return 0;
206
207
nr_zones = min(nr_zones, dev->nr_zones - first_zone);
208
trace_nullb_report_zones(nullb, nr_zones);
209
210
memset(&blkz, 0, sizeof(struct blk_zone));
211
zone = &dev->zones[first_zone];
212
for (i = 0; i < nr_zones; i++, zone++) {
213
/*
214
* Stacked DM target drivers will remap the zone information by
215
* modifying the zone information passed to the report callback.
216
* So use a local copy to avoid corruption of the device zone
217
* array.
218
*/
219
null_lock_zone(dev, zone);
220
blkz.start = zone->start;
221
blkz.len = zone->len;
222
blkz.wp = zone->wp;
223
blkz.type = zone->type;
224
blkz.cond = zone->cond;
225
blkz.capacity = zone->capacity;
226
null_unlock_zone(dev, zone);
227
228
error = cb(&blkz, i, data);
229
if (error)
230
return error;
231
}
232
233
return nr_zones;
234
}
235
236
/*
237
* This is called in the case of memory backing from null_process_cmd()
238
* with the target zone already locked.
239
*/
240
size_t null_zone_valid_read_len(struct nullb *nullb,
241
sector_t sector, unsigned int len)
242
{
243
struct nullb_device *dev = nullb->dev;
244
struct nullb_zone *zone = &dev->zones[null_zone_no(dev, sector)];
245
unsigned int nr_sectors = len >> SECTOR_SHIFT;
246
247
/* Read must be below the write pointer position */
248
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL ||
249
sector + nr_sectors <= zone->wp)
250
return len;
251
252
if (sector > zone->wp)
253
return 0;
254
255
return (zone->wp - sector) << SECTOR_SHIFT;
256
}
257
258
static void null_close_imp_open_zone(struct nullb_device *dev)
259
{
260
struct nullb_zone *zone;
261
unsigned int zno, i;
262
263
zno = dev->imp_close_zone_no;
264
if (zno >= dev->nr_zones)
265
zno = dev->zone_nr_conv;
266
267
for (i = dev->zone_nr_conv; i < dev->nr_zones; i++) {
268
zone = &dev->zones[zno];
269
zno++;
270
if (zno >= dev->nr_zones)
271
zno = dev->zone_nr_conv;
272
273
if (zone->cond == BLK_ZONE_COND_IMP_OPEN) {
274
dev->nr_zones_imp_open--;
275
if (zone->wp == zone->start) {
276
zone->cond = BLK_ZONE_COND_EMPTY;
277
} else {
278
zone->cond = BLK_ZONE_COND_CLOSED;
279
dev->nr_zones_closed++;
280
}
281
dev->imp_close_zone_no = zno;
282
return;
283
}
284
}
285
}
286
287
static blk_status_t null_check_active(struct nullb_device *dev)
288
{
289
if (!dev->zone_max_active)
290
return BLK_STS_OK;
291
292
if (dev->nr_zones_exp_open + dev->nr_zones_imp_open +
293
dev->nr_zones_closed < dev->zone_max_active)
294
return BLK_STS_OK;
295
296
return BLK_STS_ZONE_ACTIVE_RESOURCE;
297
}
298
299
static blk_status_t null_check_open(struct nullb_device *dev)
300
{
301
if (!dev->zone_max_open)
302
return BLK_STS_OK;
303
304
if (dev->nr_zones_exp_open + dev->nr_zones_imp_open < dev->zone_max_open)
305
return BLK_STS_OK;
306
307
if (dev->nr_zones_imp_open) {
308
if (null_check_active(dev) == BLK_STS_OK) {
309
null_close_imp_open_zone(dev);
310
return BLK_STS_OK;
311
}
312
}
313
314
return BLK_STS_ZONE_OPEN_RESOURCE;
315
}
316
317
/*
318
* This function matches the manage open zone resources function in the ZBC standard,
319
* with the addition of max active zones support (added in the ZNS standard).
320
*
321
* The function determines if a zone can transition to implicit open or explicit open,
322
* while maintaining the max open zone (and max active zone) limit(s). It may close an
323
* implicit open zone in order to make additional zone resources available.
324
*
325
* ZBC states that an implicit open zone shall be closed only if there is not
326
* room within the open limit. However, with the addition of an active limit,
327
* it is not certain that closing an implicit open zone will allow a new zone
328
* to be opened, since we might already be at the active limit capacity.
329
*/
330
static blk_status_t null_check_zone_resources(struct nullb_device *dev,
331
struct nullb_zone *zone)
332
{
333
blk_status_t ret;
334
335
switch (zone->cond) {
336
case BLK_ZONE_COND_EMPTY:
337
ret = null_check_active(dev);
338
if (ret != BLK_STS_OK)
339
return ret;
340
fallthrough;
341
case BLK_ZONE_COND_CLOSED:
342
return null_check_open(dev);
343
default:
344
/* Should never be called for other states */
345
WARN_ON(1);
346
return BLK_STS_IOERR;
347
}
348
}
349
350
static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
351
unsigned int nr_sectors, bool append)
352
{
353
struct nullb_device *dev = cmd->nq->dev;
354
unsigned int zno = null_zone_no(dev, sector);
355
struct nullb_zone *zone = &dev->zones[zno];
356
blk_status_t badblocks_ret = BLK_STS_OK;
357
blk_status_t ret;
358
359
trace_nullb_zone_op(cmd, zno, zone->cond);
360
361
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) {
362
if (append)
363
return BLK_STS_IOERR;
364
return null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);
365
}
366
367
null_lock_zone(dev, zone);
368
369
/*
370
* Regular writes must be at the write pointer position. Zone append
371
* writes are automatically issued at the write pointer and the position
372
* returned using the request sector. Note that we do not check the zone
373
* condition because for FULL, READONLY and OFFLINE zones, the sector
374
* check against the zone write pointer will always result in failing
375
* the command.
376
*/
377
if (append) {
378
if (WARN_ON_ONCE(!dev->zone_append_max_sectors) ||
379
zone->wp == NULL_ZONE_INVALID_WP) {
380
ret = BLK_STS_IOERR;
381
goto unlock_zone;
382
}
383
sector = zone->wp;
384
blk_mq_rq_from_pdu(cmd)->__sector = sector;
385
}
386
387
if (sector != zone->wp ||
388
zone->wp + nr_sectors > zone->start + zone->capacity) {
389
ret = BLK_STS_IOERR;
390
goto unlock_zone;
391
}
392
393
if (zone->cond == BLK_ZONE_COND_CLOSED ||
394
zone->cond == BLK_ZONE_COND_EMPTY) {
395
if (dev->need_zone_res_mgmt) {
396
spin_lock(&dev->zone_res_lock);
397
398
ret = null_check_zone_resources(dev, zone);
399
if (ret != BLK_STS_OK) {
400
spin_unlock(&dev->zone_res_lock);
401
goto unlock_zone;
402
}
403
if (zone->cond == BLK_ZONE_COND_CLOSED) {
404
dev->nr_zones_closed--;
405
dev->nr_zones_imp_open++;
406
} else if (zone->cond == BLK_ZONE_COND_EMPTY) {
407
dev->nr_zones_imp_open++;
408
}
409
410
spin_unlock(&dev->zone_res_lock);
411
}
412
413
zone->cond = BLK_ZONE_COND_IMP_OPEN;
414
}
415
416
if (dev->badblocks.shift != -1) {
417
badblocks_ret = null_handle_badblocks(cmd, sector, &nr_sectors);
418
if (badblocks_ret != BLK_STS_OK && !nr_sectors) {
419
ret = badblocks_ret;
420
goto unlock_zone;
421
}
422
}
423
424
if (dev->memory_backed) {
425
ret = null_handle_memory_backed(cmd, REQ_OP_WRITE, sector,
426
nr_sectors);
427
if (ret != BLK_STS_OK)
428
goto unlock_zone;
429
}
430
431
zone->wp += nr_sectors;
432
if (zone->wp == zone->start + zone->capacity) {
433
if (dev->need_zone_res_mgmt) {
434
spin_lock(&dev->zone_res_lock);
435
if (zone->cond == BLK_ZONE_COND_EXP_OPEN)
436
dev->nr_zones_exp_open--;
437
else if (zone->cond == BLK_ZONE_COND_IMP_OPEN)
438
dev->nr_zones_imp_open--;
439
spin_unlock(&dev->zone_res_lock);
440
}
441
zone->cond = BLK_ZONE_COND_FULL;
442
}
443
444
ret = badblocks_ret;
445
446
unlock_zone:
447
null_unlock_zone(dev, zone);
448
449
return ret;
450
}
451
452
static blk_status_t null_open_zone(struct nullb_device *dev,
453
struct nullb_zone *zone)
454
{
455
blk_status_t ret = BLK_STS_OK;
456
457
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
458
return BLK_STS_IOERR;
459
460
switch (zone->cond) {
461
case BLK_ZONE_COND_EXP_OPEN:
462
/* Open operation on exp open is not an error */
463
return BLK_STS_OK;
464
case BLK_ZONE_COND_EMPTY:
465
case BLK_ZONE_COND_IMP_OPEN:
466
case BLK_ZONE_COND_CLOSED:
467
break;
468
case BLK_ZONE_COND_FULL:
469
default:
470
return BLK_STS_IOERR;
471
}
472
473
if (dev->need_zone_res_mgmt) {
474
spin_lock(&dev->zone_res_lock);
475
476
switch (zone->cond) {
477
case BLK_ZONE_COND_EMPTY:
478
ret = null_check_zone_resources(dev, zone);
479
if (ret != BLK_STS_OK) {
480
spin_unlock(&dev->zone_res_lock);
481
return ret;
482
}
483
break;
484
case BLK_ZONE_COND_IMP_OPEN:
485
dev->nr_zones_imp_open--;
486
break;
487
case BLK_ZONE_COND_CLOSED:
488
ret = null_check_zone_resources(dev, zone);
489
if (ret != BLK_STS_OK) {
490
spin_unlock(&dev->zone_res_lock);
491
return ret;
492
}
493
dev->nr_zones_closed--;
494
break;
495
default:
496
break;
497
}
498
499
dev->nr_zones_exp_open++;
500
501
spin_unlock(&dev->zone_res_lock);
502
}
503
504
zone->cond = BLK_ZONE_COND_EXP_OPEN;
505
506
return BLK_STS_OK;
507
}
508
509
static blk_status_t null_close_zone(struct nullb_device *dev,
510
struct nullb_zone *zone)
511
{
512
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
513
return BLK_STS_IOERR;
514
515
switch (zone->cond) {
516
case BLK_ZONE_COND_CLOSED:
517
/* close operation on closed is not an error */
518
return BLK_STS_OK;
519
case BLK_ZONE_COND_IMP_OPEN:
520
case BLK_ZONE_COND_EXP_OPEN:
521
break;
522
case BLK_ZONE_COND_EMPTY:
523
case BLK_ZONE_COND_FULL:
524
default:
525
return BLK_STS_IOERR;
526
}
527
528
if (dev->need_zone_res_mgmt) {
529
spin_lock(&dev->zone_res_lock);
530
531
switch (zone->cond) {
532
case BLK_ZONE_COND_IMP_OPEN:
533
dev->nr_zones_imp_open--;
534
break;
535
case BLK_ZONE_COND_EXP_OPEN:
536
dev->nr_zones_exp_open--;
537
break;
538
default:
539
break;
540
}
541
542
if (zone->wp > zone->start)
543
dev->nr_zones_closed++;
544
545
spin_unlock(&dev->zone_res_lock);
546
}
547
548
if (zone->wp == zone->start)
549
zone->cond = BLK_ZONE_COND_EMPTY;
550
else
551
zone->cond = BLK_ZONE_COND_CLOSED;
552
553
return BLK_STS_OK;
554
}
555
556
static blk_status_t null_finish_zone(struct nullb_device *dev,
557
struct nullb_zone *zone)
558
{
559
blk_status_t ret = BLK_STS_OK;
560
561
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
562
return BLK_STS_IOERR;
563
564
if (dev->need_zone_res_mgmt) {
565
spin_lock(&dev->zone_res_lock);
566
567
switch (zone->cond) {
568
case BLK_ZONE_COND_FULL:
569
/* Finish operation on full is not an error */
570
spin_unlock(&dev->zone_res_lock);
571
return BLK_STS_OK;
572
case BLK_ZONE_COND_EMPTY:
573
ret = null_check_zone_resources(dev, zone);
574
if (ret != BLK_STS_OK) {
575
spin_unlock(&dev->zone_res_lock);
576
return ret;
577
}
578
break;
579
case BLK_ZONE_COND_IMP_OPEN:
580
dev->nr_zones_imp_open--;
581
break;
582
case BLK_ZONE_COND_EXP_OPEN:
583
dev->nr_zones_exp_open--;
584
break;
585
case BLK_ZONE_COND_CLOSED:
586
ret = null_check_zone_resources(dev, zone);
587
if (ret != BLK_STS_OK) {
588
spin_unlock(&dev->zone_res_lock);
589
return ret;
590
}
591
dev->nr_zones_closed--;
592
break;
593
default:
594
spin_unlock(&dev->zone_res_lock);
595
return BLK_STS_IOERR;
596
}
597
598
spin_unlock(&dev->zone_res_lock);
599
}
600
601
zone->cond = BLK_ZONE_COND_FULL;
602
zone->wp = zone->start + zone->len;
603
604
return BLK_STS_OK;
605
}
606
607
static blk_status_t null_reset_zone(struct nullb_device *dev,
608
struct nullb_zone *zone)
609
{
610
if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
611
return BLK_STS_IOERR;
612
613
if (dev->need_zone_res_mgmt) {
614
spin_lock(&dev->zone_res_lock);
615
616
switch (zone->cond) {
617
case BLK_ZONE_COND_IMP_OPEN:
618
dev->nr_zones_imp_open--;
619
break;
620
case BLK_ZONE_COND_EXP_OPEN:
621
dev->nr_zones_exp_open--;
622
break;
623
case BLK_ZONE_COND_CLOSED:
624
dev->nr_zones_closed--;
625
break;
626
case BLK_ZONE_COND_EMPTY:
627
case BLK_ZONE_COND_FULL:
628
break;
629
default:
630
spin_unlock(&dev->zone_res_lock);
631
return BLK_STS_IOERR;
632
}
633
634
spin_unlock(&dev->zone_res_lock);
635
}
636
637
zone->cond = BLK_ZONE_COND_EMPTY;
638
zone->wp = zone->start;
639
640
if (dev->memory_backed)
641
return null_handle_discard(dev, zone->start, zone->len);
642
643
return BLK_STS_OK;
644
}
645
646
static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
647
sector_t sector)
648
{
649
struct nullb_device *dev = cmd->nq->dev;
650
unsigned int zone_no;
651
struct nullb_zone *zone;
652
blk_status_t ret;
653
size_t i;
654
655
if (op == REQ_OP_ZONE_RESET_ALL) {
656
for (i = dev->zone_nr_conv; i < dev->nr_zones; i++) {
657
zone = &dev->zones[i];
658
null_lock_zone(dev, zone);
659
if (zone->cond != BLK_ZONE_COND_EMPTY &&
660
zone->cond != BLK_ZONE_COND_READONLY &&
661
zone->cond != BLK_ZONE_COND_OFFLINE) {
662
null_reset_zone(dev, zone);
663
trace_nullb_zone_op(cmd, i, zone->cond);
664
}
665
null_unlock_zone(dev, zone);
666
}
667
return BLK_STS_OK;
668
}
669
670
zone_no = null_zone_no(dev, sector);
671
zone = &dev->zones[zone_no];
672
673
null_lock_zone(dev, zone);
674
675
if (zone->cond == BLK_ZONE_COND_READONLY ||
676
zone->cond == BLK_ZONE_COND_OFFLINE) {
677
ret = BLK_STS_IOERR;
678
goto unlock;
679
}
680
681
switch (op) {
682
case REQ_OP_ZONE_RESET:
683
ret = null_reset_zone(dev, zone);
684
break;
685
case REQ_OP_ZONE_OPEN:
686
ret = null_open_zone(dev, zone);
687
break;
688
case REQ_OP_ZONE_CLOSE:
689
ret = null_close_zone(dev, zone);
690
break;
691
case REQ_OP_ZONE_FINISH:
692
ret = null_finish_zone(dev, zone);
693
break;
694
default:
695
ret = BLK_STS_NOTSUPP;
696
break;
697
}
698
699
if (ret == BLK_STS_OK)
700
trace_nullb_zone_op(cmd, zone_no, zone->cond);
701
702
unlock:
703
null_unlock_zone(dev, zone);
704
705
return ret;
706
}
707
708
blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
709
sector_t sector, sector_t nr_sectors)
710
{
711
struct nullb_device *dev;
712
struct nullb_zone *zone;
713
blk_status_t sts;
714
715
switch (op) {
716
case REQ_OP_WRITE:
717
return null_zone_write(cmd, sector, nr_sectors, false);
718
case REQ_OP_ZONE_APPEND:
719
return null_zone_write(cmd, sector, nr_sectors, true);
720
case REQ_OP_ZONE_RESET:
721
case REQ_OP_ZONE_RESET_ALL:
722
case REQ_OP_ZONE_OPEN:
723
case REQ_OP_ZONE_CLOSE:
724
case REQ_OP_ZONE_FINISH:
725
return null_zone_mgmt(cmd, op, sector);
726
default:
727
dev = cmd->nq->dev;
728
zone = &dev->zones[null_zone_no(dev, sector)];
729
if (zone->cond == BLK_ZONE_COND_OFFLINE)
730
return BLK_STS_IOERR;
731
732
null_lock_zone(dev, zone);
733
sts = null_process_cmd(cmd, op, sector, nr_sectors);
734
null_unlock_zone(dev, zone);
735
return sts;
736
}
737
}
738
739
/*
740
* Set a zone in the read-only or offline condition.
741
*/
742
static void null_set_zone_cond(struct nullb_device *dev,
743
struct nullb_zone *zone, enum blk_zone_cond cond)
744
{
745
if (WARN_ON_ONCE(cond != BLK_ZONE_COND_READONLY &&
746
cond != BLK_ZONE_COND_OFFLINE))
747
return;
748
749
null_lock_zone(dev, zone);
750
751
/*
752
* If the read-only condition is requested again to zones already in
753
* read-only condition, restore back normal empty condition. Do the same
754
* if the offline condition is requested for offline zones. Otherwise,
755
* set the specified zone condition to the zones. Finish the zones
756
* beforehand to free up zone resources.
757
*/
758
if (zone->cond == cond) {
759
zone->cond = BLK_ZONE_COND_EMPTY;
760
zone->wp = zone->start;
761
if (dev->memory_backed)
762
null_handle_discard(dev, zone->start, zone->len);
763
} else {
764
if (zone->cond != BLK_ZONE_COND_READONLY &&
765
zone->cond != BLK_ZONE_COND_OFFLINE)
766
null_finish_zone(dev, zone);
767
zone->cond = cond;
768
zone->wp = NULL_ZONE_INVALID_WP;
769
}
770
771
null_unlock_zone(dev, zone);
772
}
773
774
/*
775
* Identify a zone from the sector written to configfs file. Then set zone
776
* condition to the zone.
777
*/
778
ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
779
size_t count, enum blk_zone_cond cond)
780
{
781
unsigned long long sector;
782
unsigned int zone_no;
783
int ret;
784
785
if (!dev->zoned) {
786
pr_err("null_blk device is not zoned\n");
787
return -EINVAL;
788
}
789
790
if (!dev->zones) {
791
pr_err("null_blk device is not yet powered\n");
792
return -EINVAL;
793
}
794
795
ret = kstrtoull(page, 0, &sector);
796
if (ret < 0)
797
return ret;
798
799
zone_no = null_zone_no(dev, sector);
800
if (zone_no >= dev->nr_zones) {
801
pr_err("Sector out of range\n");
802
return -EINVAL;
803
}
804
805
if (dev->zones[zone_no].type == BLK_ZONE_TYPE_CONVENTIONAL) {
806
pr_err("Can not change condition of conventional zones\n");
807
return -EINVAL;
808
}
809
810
null_set_zone_cond(dev, &dev->zones[zone_no], cond);
811
812
return count;
813
}
814
815