diff mbox series

[for-next,v2,3/4] null_blk: move write pointers for partial writes

Message ID 20241225100949.930897-4-shinichiro.kawasaki@wdc.com (mailing list archive)
State New, archived
Headers show
Series null_blk: improve write failure simulation | expand

Commit Message

Shinichiro Kawasaki Dec. 25, 2024, 10:09 a.m. UTC
The previous commit modified bad blocks handling to do the partial IOs.
When such partial IOs happen for zoned null_blk devices, it is expected
that the write pointers also move partially. To test and debug partial
write by userland tools for zoned block devices, move write pointers
partially.

Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
---
 drivers/block/null_blk/main.c     |  5 ++++-
 drivers/block/null_blk/null_blk.h |  6 ++++++
 drivers/block/null_blk/zoned.c    | 10 ++++++++++
 3 files changed, 20 insertions(+), 1 deletion(-)

Comments

Damien Le Moal Jan. 6, 2025, 5:56 a.m. UTC | #1
On 12/25/24 7:09 PM, Shin'ichiro Kawasaki wrote:
> The previous commit modified bad blocks handling to do the partial IOs.
> When such partial IOs happen for zoned null_blk devices, it is expected
> that the write pointers also move partially. To test and debug partial
> write by userland tools for zoned block devices, move write pointers
> partially.
> 
> Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
> ---
>  drivers/block/null_blk/main.c     |  5 ++++-
>  drivers/block/null_blk/null_blk.h |  6 ++++++
>  drivers/block/null_blk/zoned.c    | 10 ++++++++++
>  3 files changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
> index d155eb040077..1675dec0b0e6 100644
> --- a/drivers/block/null_blk/main.c
> +++ b/drivers/block/null_blk/main.c
> @@ -1330,6 +1330,7 @@ static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
>  }
>  
>  static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
> +						 enum req_op op,
>  						 sector_t sector,
>  						 sector_t nr_sectors)
>  {
> @@ -1347,6 +1348,8 @@ static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
>  			transfer_bytes = (first_bad - sector) << SECTOR_SHIFT;
>  			__null_handle_rq(cmd, transfer_bytes);
>  		}
> +		if (dev->zoned && op == REQ_OP_WRITE)

Forgot REQ_OP_ZONE_APPEND ?

> +			null_move_zone_wp(dev, sector, first_bad - sector);
>  		return BLK_STS_IOERR;
>  	}
>  
> @@ -1413,7 +1416,7 @@ blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
>  	blk_status_t ret;
>  
>  	if (dev->badblocks.shift != -1) {
> -		ret = null_handle_badblocks(cmd, sector, nr_sectors);
> +		ret = null_handle_badblocks(cmd, op, sector, nr_sectors);
>  		if (ret != BLK_STS_OK)
>  			return ret;
>  	}
> diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
> index 6f9fe6171087..c6ceede691ba 100644
> --- a/drivers/block/null_blk/null_blk.h
> +++ b/drivers/block/null_blk/null_blk.h
> @@ -144,6 +144,8 @@ size_t null_zone_valid_read_len(struct nullb *nullb,
>  				sector_t sector, unsigned int len);
>  ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
>  			size_t count, enum blk_zone_cond cond);
> +void null_move_zone_wp(struct nullb_device *dev, sector_t zone_sector,
> +		       sector_t nr_sectors);
>  #else
>  static inline int null_init_zoned_dev(struct nullb_device *dev,
>  		struct queue_limits *lim)
> @@ -173,6 +175,10 @@ static inline ssize_t zone_cond_store(struct nullb_device *dev,
>  {
>  	return -EOPNOTSUPP;
>  }
> +static inline void null_move_zone_wp(struct nullb_device *dev,
> +				     sector_t zone_sector, sector_t nr_sectors)
> +{
> +}
>  #define null_report_zones	NULL
>  #endif /* CONFIG_BLK_DEV_ZONED */
>  #endif /* __NULL_BLK_H */
> diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
> index 0d5f9bf95229..e2b8396aa318 100644
> --- a/drivers/block/null_blk/zoned.c
> +++ b/drivers/block/null_blk/zoned.c
> @@ -347,6 +347,16 @@ static blk_status_t null_check_zone_resources(struct nullb_device *dev,
>  	}
>  }
>  
> +void null_move_zone_wp(struct nullb_device *dev, sector_t zone_sector,
> +		       sector_t nr_sectors)
> +{
> +	unsigned int zno = null_zone_no(dev, zone_sector);
> +	struct nullb_zone *zone = &dev->zones[zno];
> +
> +	if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL)
> +		zone->wp += nr_sectors;
> +}

I do not think this is correct. We need to deal with the zone implicit open and
zone resources as well, exactly like for a regular write. So it is not that simple.

I think that overall, a simpler approach would be to reuse
null_handle_badblocks() inside null_process_zoned_cmd(), similar to
null_process_cmd(). If reusing null_handle_badblocks() inside
null_process_zoned_cmd() is not possible, then let's write a
null_handle_zone_badblocks() helper.

> +
>  static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
>  				    unsigned int nr_sectors, bool append)
>  {
Shinichiro Kawasaki Jan. 15, 2025, 1:23 a.m. UTC | #2
On Jan 06, 2025 / 14:56, Damien Le Moal wrote:
> On 12/25/24 7:09 PM, Shin'ichiro Kawasaki wrote:
> > The previous commit modified bad blocks handling to do the partial IOs.
> > When such partial IOs happen for zoned null_blk devices, it is expected
> > that the write pointers also move partially. To test and debug partial
> > write by userland tools for zoned block devices, move write pointers
> > partially.
> > 
> > Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
> > ---
> >  drivers/block/null_blk/main.c     |  5 ++++-
> >  drivers/block/null_blk/null_blk.h |  6 ++++++
> >  drivers/block/null_blk/zoned.c    | 10 ++++++++++
> >  3 files changed, 20 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
> > index d155eb040077..1675dec0b0e6 100644
> > --- a/drivers/block/null_blk/main.c
> > +++ b/drivers/block/null_blk/main.c
> > @@ -1330,6 +1330,7 @@ static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
> >  }
> >  
> >  static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
> > +						 enum req_op op,
> >  						 sector_t sector,
> >  						 sector_t nr_sectors)
> >  {
> > @@ -1347,6 +1348,8 @@ static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
> >  			transfer_bytes = (first_bad - sector) << SECTOR_SHIFT;
> >  			__null_handle_rq(cmd, transfer_bytes);
> >  		}
> > +		if (dev->zoned && op == REQ_OP_WRITE)
> 
> Forgot REQ_OP_ZONE_APPEND ?

Actually, null_process_zoned_cmd() handles both REQ_OP_WRITE and
REQ_OP_ZONE_APPEND in the same way, and both case results in op == REQ_OP_WRITE
here. Anyway, this if branch will not be required in the v3 series since this
patch is totally rewritten to follow your the other suggestion.

> 
> > +			null_move_zone_wp(dev, sector, first_bad - sector);
> >  		return BLK_STS_IOERR;
> >  	}
> >  
> > @@ -1413,7 +1416,7 @@ blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
> >  	blk_status_t ret;
> >  
> >  	if (dev->badblocks.shift != -1) {
> > -		ret = null_handle_badblocks(cmd, sector, nr_sectors);
> > +		ret = null_handle_badblocks(cmd, op, sector, nr_sectors);
> >  		if (ret != BLK_STS_OK)
> >  			return ret;
> >  	}
> > diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
> > index 6f9fe6171087..c6ceede691ba 100644
> > --- a/drivers/block/null_blk/null_blk.h
> > +++ b/drivers/block/null_blk/null_blk.h
> > @@ -144,6 +144,8 @@ size_t null_zone_valid_read_len(struct nullb *nullb,
> >  				sector_t sector, unsigned int len);
> >  ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
> >  			size_t count, enum blk_zone_cond cond);
> > +void null_move_zone_wp(struct nullb_device *dev, sector_t zone_sector,
> > +		       sector_t nr_sectors);
> >  #else
> >  static inline int null_init_zoned_dev(struct nullb_device *dev,
> >  		struct queue_limits *lim)
> > @@ -173,6 +175,10 @@ static inline ssize_t zone_cond_store(struct nullb_device *dev,
> >  {
> >  	return -EOPNOTSUPP;
> >  }
> > +static inline void null_move_zone_wp(struct nullb_device *dev,
> > +				     sector_t zone_sector, sector_t nr_sectors)
> > +{
> > +}
> >  #define null_report_zones	NULL
> >  #endif /* CONFIG_BLK_DEV_ZONED */
> >  #endif /* __NULL_BLK_H */
> > diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
> > index 0d5f9bf95229..e2b8396aa318 100644
> > --- a/drivers/block/null_blk/zoned.c
> > +++ b/drivers/block/null_blk/zoned.c
> > @@ -347,6 +347,16 @@ static blk_status_t null_check_zone_resources(struct nullb_device *dev,
> >  	}
> >  }
> >  
> > +void null_move_zone_wp(struct nullb_device *dev, sector_t zone_sector,
> > +		       sector_t nr_sectors)
> > +{
> > +	unsigned int zno = null_zone_no(dev, zone_sector);
> > +	struct nullb_zone *zone = &dev->zones[zno];
> > +
> > +	if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL)
> > +		zone->wp += nr_sectors;
> > +}
> 
> I do not think this is correct. We need to deal with the zone implicit open and
> zone resources as well, exactly like for a regular write. So it is not that simple.
> 
> I think that overall, a simpler approach would be to reuse
> null_handle_badblocks() inside null_process_zoned_cmd(), similar to
> null_process_cmd(). If reusing null_handle_badblocks() inside
> null_process_zoned_cmd() is not possible, then let's write a
> null_handle_zone_badblocks() helper.

Right, I overlooked the zone resource management. I think we can reuse
null_handle_badblolcks() from null_zone_write(). Please review v3 that I will
post soon.
diff mbox series

Patch

diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index d155eb040077..1675dec0b0e6 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -1330,6 +1330,7 @@  static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
 }
 
 static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
+						 enum req_op op,
 						 sector_t sector,
 						 sector_t nr_sectors)
 {
@@ -1347,6 +1348,8 @@  static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
 			transfer_bytes = (first_bad - sector) << SECTOR_SHIFT;
 			__null_handle_rq(cmd, transfer_bytes);
 		}
+		if (dev->zoned && op == REQ_OP_WRITE)
+			null_move_zone_wp(dev, sector, first_bad - sector);
 		return BLK_STS_IOERR;
 	}
 
@@ -1413,7 +1416,7 @@  blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
 	blk_status_t ret;
 
 	if (dev->badblocks.shift != -1) {
-		ret = null_handle_badblocks(cmd, sector, nr_sectors);
+		ret = null_handle_badblocks(cmd, op, sector, nr_sectors);
 		if (ret != BLK_STS_OK)
 			return ret;
 	}
diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
index 6f9fe6171087..c6ceede691ba 100644
--- a/drivers/block/null_blk/null_blk.h
+++ b/drivers/block/null_blk/null_blk.h
@@ -144,6 +144,8 @@  size_t null_zone_valid_read_len(struct nullb *nullb,
 				sector_t sector, unsigned int len);
 ssize_t zone_cond_store(struct nullb_device *dev, const char *page,
 			size_t count, enum blk_zone_cond cond);
+void null_move_zone_wp(struct nullb_device *dev, sector_t zone_sector,
+		       sector_t nr_sectors);
 #else
 static inline int null_init_zoned_dev(struct nullb_device *dev,
 		struct queue_limits *lim)
@@ -173,6 +175,10 @@  static inline ssize_t zone_cond_store(struct nullb_device *dev,
 {
 	return -EOPNOTSUPP;
 }
+static inline void null_move_zone_wp(struct nullb_device *dev,
+				     sector_t zone_sector, sector_t nr_sectors)
+{
+}
 #define null_report_zones	NULL
 #endif /* CONFIG_BLK_DEV_ZONED */
 #endif /* __NULL_BLK_H */
diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
index 0d5f9bf95229..e2b8396aa318 100644
--- a/drivers/block/null_blk/zoned.c
+++ b/drivers/block/null_blk/zoned.c
@@ -347,6 +347,16 @@  static blk_status_t null_check_zone_resources(struct nullb_device *dev,
 	}
 }
 
+void null_move_zone_wp(struct nullb_device *dev, sector_t zone_sector,
+		       sector_t nr_sectors)
+{
+	unsigned int zno = null_zone_no(dev, zone_sector);
+	struct nullb_zone *zone = &dev->zones[zno];
+
+	if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL)
+		zone->wp += nr_sectors;
+}
+
 static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
 				    unsigned int nr_sectors, bool append)
 {