On Mon, Sep 16, 2024 at 06:21:53PM -0600, Uday Shankar wrote: > ublk currently supports the following behaviors on ublk server exit: > > A: outstanding I/Os get errors, subsequently issued I/Os get errors > B: outstanding I/Os get errors, subsequently issued I/Os queue > C: outstanding I/Os get reissued, subsequently issued I/Os queue > > and the following behaviors for recovery of preexisting block devices by > a future incarnation of the ublk server: > > 1: ublk devices stopped on ublk server exit (no recovery possible) > 2: ublk devices are recoverable using start/end_recovery commands > > The userspace interface allows selection of combinations of these > behaviors using flags specified at device creation time, namely: > > default behavior: A + 1 > UBLK_F_USER_RECOVERY: B + 2 > UBLK_F_USER_RECOVERY|UBLK_F_USER_RECOVERY_REISSUE: C + 2 > > We can't easily change the userspace interface to allow independent > selection of one of {A, B, C} and one of {1, 2}, but we can refactor the > internal helpers which test for the flags. Replace the existing helpers > with the following set: > > ublk_nosrv_should_reissue_outstanding: tests for behavior C > ublk_nosrv_[dev_]should_queue_io: tests for behavior B > ublk_nosrv_should_stop_dev: tests for behavior 1 > > Signed-off-by: Uday Shankar <ushankar@xxxxxxxxxxxxxxx> > --- > Changes since v1 (https://lore.kernel.org/linux-block/20240617194451.435445-3-ushankar@xxxxxxxxxxxxxxx/): > - Make the fast-path test in ublk_queue_rq access the queue-local copy > of the device flags. > > drivers/block/ublk_drv.c | 63 +++++++++++++++++++++++++++------------- > 1 file changed, 43 insertions(+), 20 deletions(-) > > diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c > index 5e04a0fcd0b7..b069f4d2b9d2 100644 > --- a/drivers/block/ublk_drv.c > +++ b/drivers/block/ublk_drv.c > @@ -675,22 +675,45 @@ static inline int ublk_queue_cmd_buf_size(struct ublk_device *ub, int q_id) > PAGE_SIZE); > } > > -static inline bool ublk_queue_can_use_recovery_reissue( > - struct ublk_queue *ubq) > +/* > + * Should I/O outstanding to the ublk server when it exits be reissued? > + * If not, outstanding I/O will get errors. > + */ > +static inline bool ublk_nosrv_should_reissue_outstanding(struct ublk_device *ub) > { > - return (ubq->flags & UBLK_F_USER_RECOVERY) && > - (ubq->flags & UBLK_F_USER_RECOVERY_REISSUE); > + return (ub->dev_info.flags & UBLK_F_USER_RECOVERY) && > + (ub->dev_info.flags & UBLK_F_USER_RECOVERY_REISSUE); > } > > -static inline bool ublk_queue_can_use_recovery( > - struct ublk_queue *ubq) > +/* > + * Should I/O issued while there is no ublk server queue? If not, I/O > + * issued while there is no ublk server will get errors. > + */ > +static inline bool ublk_nosrv_dev_should_queue_io(struct ublk_device *ub) > +{ > + return ub->dev_info.flags & UBLK_F_USER_RECOVERY; > +} > + > +/* > + * Same as ublk_nosrv_dev_should_queue_io, but uses a queue-local copy > + * of the device flags for smaller cache footprint - better for fast > + * paths. > + */ > +static inline bool ublk_nosrv_should_queue_io(struct ublk_queue *ubq) > { > return ubq->flags & UBLK_F_USER_RECOVERY; > } > > -static inline bool ublk_can_use_recovery(struct ublk_device *ub) > +/* > + * Should ublk devices be stopped (i.e. no recovery possible) when the > + * ublk server exits? If not, devices can be used again by a future > + * incarnation of a ublk server via the start_recovery/end_recovery > + * commands. > + */ > +static inline bool ublk_nosrv_should_stop_dev(struct ublk_device *ub) > { > - return ub->dev_info.flags & UBLK_F_USER_RECOVERY; > + return (!(ub->dev_info.flags & UBLK_F_USER_RECOVERY)) && > + (!(ub->dev_info.flags & UBLK_F_USER_RECOVERY_REISSUE)); > } It should be enough to check UBLK_F_USER_RECOVERY only since UBLK_F_USER_RECOVERY_REISSUE implies UBLK_F_USER_RECOVERY. Otherwise, this patch looks fine. Thanks, Ming