Re: [PATCH] null_blk: support readonly and offline zone conditions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 11/30/22 18:41, Shin'ichiro Kawasaki wrote:

[...]

> @@ -627,6 +631,12 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
>  
>  	null_lock_zone(dev, zone);
>  
> +	if (zone->cond == BLK_ZONE_COND_READONLY ||
> +	    zone->cond == BLK_ZONE_COND_OFFLINE) {
> +		ret = BLK_STS_IOERR;
> +		goto unlock;
> +	}
> +
>  	switch (op) {
>  	case REQ_OP_ZONE_RESET:
>  		ret = null_reset_zone(dev, zone);
> @@ -648,6 +658,7 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_op op,
>  	if (ret == BLK_STS_OK)
>  		trace_nullb_zone_op(cmd, zone_no, zone->cond);
>  
> +unlock:
>  	null_unlock_zone(dev, zone);
>  
>  	return ret;
> @@ -674,10 +685,103 @@ blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op,
>  	default:
>  		dev = cmd->nq->dev;
>  		zone = &dev->zones[null_zone_no(dev, sector)];
> -

I would prefer keeping this blank line after the "return BLK_STS_IOERR" below.

> +		if (zone->cond == BLK_ZONE_COND_OFFLINE)
> +			return BLK_STS_IOERR;
>  		null_lock_zone(dev, zone);
>  		sts = null_process_cmd(cmd, op, sector, nr_sectors);
>  		null_unlock_zone(dev, zone);
>  		return sts;
>  	}
>  }
> +
> +/*
> + * Set specified condition COND_READONLY or COND_OFFLINE to a zone.

May be "Set a zone in the read-only or offline condition."

> + */
> +static int null_set_zone_cond(struct nullb_device *dev, struct nullb_zone *zone,
> +			      enum blk_zone_cond cond)
> +{
> +	enum blk_zone_cond old_cond;
> +	int ret;
> +
> +	if (WARN_ON_ONCE(cond != BLK_ZONE_COND_READONLY &&
> +			 cond != BLK_ZONE_COND_OFFLINE))
> +		return -EINVAL;
> +
> +	null_lock_zone(dev, zone);
> +
> +	/*
> +	 * When current zone condition is readonly or offline, handle the zone
> +	 * as full condition to avoid failure of zone reset or zone finish.
> +	 */
> +	old_cond = zone->cond;
> +	if (zone->cond == BLK_ZONE_COND_READONLY ||
> +	    zone->cond == BLK_ZONE_COND_OFFLINE)
> +		zone->cond = BLK_ZONE_COND_FULL;
> +
> +	/*
> +	 * If readonly condition is requested again to zones already in readonly

If the...

> +	 * condition, reset the zones to restore back normal empty condition.
> +	 * Do same if offline condition is requested for offline zones.

Do the same if the...

> +	 * Otherwise, set desired zone condition to the zones. Finish the zones

Otherwise, set the specified zone condition. Finish...

> +	 * beforehand to free up zone resources.
> +	 */
> +	if (old_cond == cond) {
> +		ret = null_reset_zone(dev, zone);

This will not restore conventional zones since reset will be an error for
these... So you need to do the reset "manually":

You could simply do:

		/* Restore the zone to a usable condition */
		if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) {
			zone->cond = BLK_ZONE_COND_NOT_WP;
			zone->wp = (sector_t)-1;
		} else {
			zone->cond = BLK_ZONE_COND_EMPTY;
			zone->wp = zone->start;
		}

Then the hunk above that set the zone to FULL is not needed, and the
variable "old_cond" is also not needed as the "if" above can be:

	if (zone->cond == cond)

> +	} else {
> +		ret = null_finish_zone(dev, zone);

Do the finish only for seq zones. Otherwise, setting a conventional zone
to read only or offline will always fail.

> +		if (!ret) {
> +			zone->cond = cond;
> +			zone->wp = (sector_t)-1;
> +		}
> +	}
> +
> +	if (ret)
> +		zone->cond = old_cond;

There should never be any failure with this. So we should not need this.

> +
> +	null_unlock_zone(dev, zone);
> +	return ret;
> +}
> +
> +/*
> + * Identify a zone from the sector written to configfs file. Then set zone
> + * condition to the zone.
> + */
> +ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
> +			size_t count, enum blk_zone_cond cond)
> +{
> +	unsigned long long sector;
> +	unsigned int zone_no;
> +	int ret;
> +
> +	if (!dev->zoned) {
> +		pr_err("null_blk device is not zoned\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!dev->zones) {
> +		pr_err("null_blk device is not yet powered\n");
> +		return -EINVAL;
> +	}
> +
> +	ret = kstrtoull(page, 0, &sector);
> +	if (ret < 0)
> +		return ret;
> +
> +	zone_no = null_zone_no(dev, sector);
> +

Remove the blank line here.

> +	if (zone_no >= dev->nr_zones) {
> +		pr_err("Sector out of range\n");
> +		return -EINVAL;
> +	}
> +
> +	if (dev->zones[zone_no].type == BLK_ZONE_TYPE_CONVENTIONAL) {
> +		pr_err("Can not change condition of conventional zones\n");

Why ? Conventional zones can go read-only or offline too. At least on
ZBC/ZAC SMR HDDs, they can. So allowing this to happen with null_blk is
desired too.

> +		return -EINVAL;
> +	}
> +
> +	ret = null_set_zone_cond(dev, &dev->zones[zone_no], cond);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}

-- 
Damien Le Moal
Western Digital Research




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux