File Index
Files and directories
Sign in
FILE

zoned.c

File preview with syntax highlighting.

linux-6.19.14/drivers/block/null_blk/zoned.c C
  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
 14static inline sector_t mb_to_sects(unsigned long mb)
 15{
 16	return ((sector_t)mb * SZ_1M) >> SECTOR_SHIFT;
 17}
 18
 19static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
 20{
 21	return sect >> ilog2(dev->zone_size_sects);
 22}
 23
 24static 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
 33static 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
 42static 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
 51int 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
175int 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
187void null_free_zoned_dev(struct nullb_device *dev)
188{
189	kvfree(dev->zones);
190	dev->zones = NULL;
191}
192
193int null_report_zones(struct gendisk *disk, sector_t sector,
194		unsigned int nr_zones, struct blk_report_zones_args *args)
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 = disk_report_zone(disk, &blkz, i, args);
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 */
240size_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 = DIV_ROUND_UP(len, SECTOR_SIZE);
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
258static 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
287static 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
299static 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 */
330static 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
350static 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
446unlock_zone:
447	null_unlock_zone(dev, zone);
448
449	return ret;
450}
451
452static 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
509static 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
556static 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
607static 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
646static 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
702unlock:
703	null_unlock_zone(dev, zone);
704
705	return ret;
706}
707
708blk_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 */
742static 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 */
778ssize_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}
~/ Read-only file preview.