Skip to content

Commit 59eaa01

Browse files
ps-ushankaraxboe
authored andcommitted
ublk: support device recovery without I/O queueing
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 The behavior A + 2 is currently unsupported. Add support for this behavior under the new flag combination UBLK_F_USER_RECOVERY|UBLK_F_USER_RECOVERY_FAIL_IO. Signed-off-by: Uday Shankar <[email protected]> Reviewed-by: Ming Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 27b5d41 commit 59eaa01

File tree

2 files changed

+81
-15
lines changed

2 files changed

+81
-15
lines changed

drivers/block/ublk_drv.c

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,12 @@
6060
| UBLK_F_UNPRIVILEGED_DEV \
6161
| UBLK_F_CMD_IOCTL_ENCODE \
6262
| UBLK_F_USER_COPY \
63-
| UBLK_F_ZONED)
63+
| UBLK_F_ZONED \
64+
| UBLK_F_USER_RECOVERY_FAIL_IO)
6465

6566
#define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \
66-
| UBLK_F_USER_RECOVERY_REISSUE)
67+
| UBLK_F_USER_RECOVERY_REISSUE \
68+
| UBLK_F_USER_RECOVERY_FAIL_IO)
6769

6870
/* All UBLK_PARAM_TYPE_* should be included here */
6971
#define UBLK_PARAM_TYPE_ALL \
@@ -146,6 +148,7 @@ struct ublk_queue {
146148
bool force_abort;
147149
bool timeout;
148150
bool canceling;
151+
bool fail_io; /* copy of dev->state == UBLK_S_DEV_FAIL_IO */
149152
unsigned short nr_io_ready; /* how many ios setup */
150153
spinlock_t cancel_lock;
151154
struct ublk_device *dev;
@@ -690,7 +693,8 @@ static inline bool ublk_nosrv_should_reissue_outstanding(struct ublk_device *ub)
690693
*/
691694
static inline bool ublk_nosrv_dev_should_queue_io(struct ublk_device *ub)
692695
{
693-
return ub->dev_info.flags & UBLK_F_USER_RECOVERY;
696+
return (ub->dev_info.flags & UBLK_F_USER_RECOVERY) &&
697+
!(ub->dev_info.flags & UBLK_F_USER_RECOVERY_FAIL_IO);
694698
}
695699

696700
/*
@@ -700,7 +704,8 @@ static inline bool ublk_nosrv_dev_should_queue_io(struct ublk_device *ub)
700704
*/
701705
static inline bool ublk_nosrv_should_queue_io(struct ublk_queue *ubq)
702706
{
703-
return ubq->flags & UBLK_F_USER_RECOVERY;
707+
return (ubq->flags & UBLK_F_USER_RECOVERY) &&
708+
!(ubq->flags & UBLK_F_USER_RECOVERY_FAIL_IO);
704709
}
705710

706711
/*
@@ -714,6 +719,12 @@ static inline bool ublk_nosrv_should_stop_dev(struct ublk_device *ub)
714719
return !(ub->dev_info.flags & UBLK_F_USER_RECOVERY);
715720
}
716721

722+
static inline bool ublk_dev_in_recoverable_state(struct ublk_device *ub)
723+
{
724+
return ub->dev_info.state == UBLK_S_DEV_QUIESCED ||
725+
ub->dev_info.state == UBLK_S_DEV_FAIL_IO;
726+
}
727+
717728
static void ublk_free_disk(struct gendisk *disk)
718729
{
719730
struct ublk_device *ub = disk->private_data;
@@ -1275,6 +1286,10 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx,
12751286
struct request *rq = bd->rq;
12761287
blk_status_t res;
12771288

1289+
if (unlikely(ubq->fail_io)) {
1290+
return BLK_STS_TARGET;
1291+
}
1292+
12781293
/* fill iod to slot in io cmd buffer */
12791294
res = ublk_setup_iod(ubq, rq);
12801295
if (unlikely(res != BLK_STS_OK))
@@ -1625,6 +1640,7 @@ static void ublk_nosrv_work(struct work_struct *work)
16251640
{
16261641
struct ublk_device *ub =
16271642
container_of(work, struct ublk_device, nosrv_work);
1643+
int i;
16281644

16291645
if (ublk_nosrv_should_stop_dev(ub)) {
16301646
ublk_stop_dev(ub);
@@ -1634,7 +1650,18 @@ static void ublk_nosrv_work(struct work_struct *work)
16341650
mutex_lock(&ub->mutex);
16351651
if (ub->dev_info.state != UBLK_S_DEV_LIVE)
16361652
goto unlock;
1637-
__ublk_quiesce_dev(ub);
1653+
1654+
if (ublk_nosrv_dev_should_queue_io(ub)) {
1655+
__ublk_quiesce_dev(ub);
1656+
} else {
1657+
blk_mq_quiesce_queue(ub->ub_disk->queue);
1658+
ub->dev_info.state = UBLK_S_DEV_FAIL_IO;
1659+
for (i = 0; i < ub->dev_info.nr_hw_queues; i++) {
1660+
ublk_get_queue(ub, i)->fail_io = true;
1661+
}
1662+
blk_mq_unquiesce_queue(ub->ub_disk->queue);
1663+
}
1664+
16381665
unlock:
16391666
mutex_unlock(&ub->mutex);
16401667
ublk_cancel_dev(ub);
@@ -2387,8 +2414,13 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
23872414
return -EPERM;
23882415

23892416
/* forbid nonsense combinations of recovery flags */
2390-
if ((info.flags & UBLK_F_USER_RECOVERY_REISSUE) &&
2391-
!(info.flags & UBLK_F_USER_RECOVERY)) {
2417+
switch (info.flags & UBLK_F_ALL_RECOVERY_FLAGS) {
2418+
case 0:
2419+
case UBLK_F_USER_RECOVERY:
2420+
case (UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE):
2421+
case (UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_FAIL_IO):
2422+
break;
2423+
default:
23922424
pr_warn("%s: invalid recovery flags %llx\n", __func__,
23932425
info.flags & UBLK_F_ALL_RECOVERY_FLAGS);
23942426
return -EINVAL;
@@ -2729,14 +2761,18 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub,
27292761
* and related io_uring ctx is freed so file struct of /dev/ublkcX is
27302762
* released.
27312763
*
2764+
* and one of the following holds
2765+
*
27322766
* (2) UBLK_S_DEV_QUIESCED is set, which means the quiesce_work:
27332767
* (a)has quiesced request queue
27342768
* (b)has requeued every inflight rqs whose io_flags is ACTIVE
27352769
* (c)has requeued/aborted every inflight rqs whose io_flags is NOT ACTIVE
27362770
* (d)has completed/camceled all ioucmds owned by ther dying process
2771+
*
2772+
* (3) UBLK_S_DEV_FAIL_IO is set, which means the queue is not
2773+
* quiesced, but all I/O is being immediately errored
27372774
*/
2738-
if (test_bit(UB_STATE_OPEN, &ub->state) ||
2739-
ub->dev_info.state != UBLK_S_DEV_QUIESCED) {
2775+
if (test_bit(UB_STATE_OPEN, &ub->state) || !ublk_dev_in_recoverable_state(ub)) {
27402776
ret = -EBUSY;
27412777
goto out_unlock;
27422778
}
@@ -2760,6 +2796,7 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
27602796
const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe);
27612797
int ublksrv_pid = (int)header->data[0];
27622798
int ret = -EINVAL;
2799+
int i;
27632800

27642801
pr_devel("%s: Waiting for new ubq_daemons(nr: %d) are ready, dev id %d...\n",
27652802
__func__, ub->dev_info.nr_hw_queues, header->dev_id);
@@ -2774,18 +2811,29 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
27742811
if (ublk_nosrv_should_stop_dev(ub))
27752812
goto out_unlock;
27762813

2777-
if (ub->dev_info.state != UBLK_S_DEV_QUIESCED) {
2814+
if (!ublk_dev_in_recoverable_state(ub)) {
27782815
ret = -EBUSY;
27792816
goto out_unlock;
27802817
}
27812818
ub->dev_info.ublksrv_pid = ublksrv_pid;
27822819
pr_devel("%s: new ublksrv_pid %d, dev id %d\n",
27832820
__func__, ublksrv_pid, header->dev_id);
2784-
blk_mq_unquiesce_queue(ub->ub_disk->queue);
2785-
pr_devel("%s: queue unquiesced, dev id %d.\n",
2786-
__func__, header->dev_id);
2787-
blk_mq_kick_requeue_list(ub->ub_disk->queue);
2788-
ub->dev_info.state = UBLK_S_DEV_LIVE;
2821+
2822+
if (ublk_nosrv_dev_should_queue_io(ub)) {
2823+
ub->dev_info.state = UBLK_S_DEV_LIVE;
2824+
blk_mq_unquiesce_queue(ub->ub_disk->queue);
2825+
pr_devel("%s: queue unquiesced, dev id %d.\n",
2826+
__func__, header->dev_id);
2827+
blk_mq_kick_requeue_list(ub->ub_disk->queue);
2828+
} else {
2829+
blk_mq_quiesce_queue(ub->ub_disk->queue);
2830+
ub->dev_info.state = UBLK_S_DEV_LIVE;
2831+
for (i = 0; i < ub->dev_info.nr_hw_queues; i++) {
2832+
ublk_get_queue(ub, i)->fail_io = false;
2833+
}
2834+
blk_mq_unquiesce_queue(ub->ub_disk->queue);
2835+
}
2836+
27892837
ret = 0;
27902838
out_unlock:
27912839
mutex_unlock(&ub->mutex);

include/uapi/linux/ublk_cmd.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,18 @@
147147
*/
148148
#define UBLK_F_NEED_GET_DATA (1UL << 2)
149149

150+
/*
151+
* - Block devices are recoverable if ublk server exits and restarts
152+
* - Outstanding I/O when ublk server exits is met with errors
153+
* - I/O issued while there is no ublk server queues
154+
*/
150155
#define UBLK_F_USER_RECOVERY (1UL << 3)
151156

157+
/*
158+
* - Block devices are recoverable if ublk server exits and restarts
159+
* - Outstanding I/O when ublk server exits is reissued
160+
* - I/O issued while there is no ublk server queues
161+
*/
152162
#define UBLK_F_USER_RECOVERY_REISSUE (1UL << 4)
153163

154164
/*
@@ -190,10 +200,18 @@
190200
*/
191201
#define UBLK_F_ZONED (1ULL << 8)
192202

203+
/*
204+
* - Block devices are recoverable if ublk server exits and restarts
205+
* - Outstanding I/O when ublk server exits is met with errors
206+
* - I/O issued while there is no ublk server is met with errors
207+
*/
208+
#define UBLK_F_USER_RECOVERY_FAIL_IO (1ULL << 9)
209+
193210
/* device state */
194211
#define UBLK_S_DEV_DEAD 0
195212
#define UBLK_S_DEV_LIVE 1
196213
#define UBLK_S_DEV_QUIESCED 2
214+
#define UBLK_S_DEV_FAIL_IO 3
197215

198216
/* shipped via sqe->cmd of io_uring command */
199217
struct ublksrv_ctrl_cmd {

0 commit comments

Comments
 (0)