nvme-multipath: revalidate paths during rescan
When triggering a rescan due to a namespace resize we will be receiving AENs on every controller, triggering a rescan of all attached namespaces. If multipath is active only the current path and the ns_head disk will be updated, the other paths will still refer to the old size until AENs for the remaining controllers are received. If I/O comes in before that it might be routed to one of the old paths, triggering an I/O failure with 'access beyond end of device'. With this patch the old paths are skipped from multipath path selection until the controller serving these paths has been rescanned. Signed-off-by: Hannes Reinecke <hare@suse.de> [dwagner: - introduce NVME_NS_READY flag instead of NVME_NS_INVALIDATE - use 'revalidate' instead of 'invalidate' which follows the zoned device code path. - clear NVME_NS_READY before clearing current_path] Signed-off-by: Daniel Wagner <dwagner@suse.de> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Родитель
d32d3d0b47
Коммит
e7d65803e2
|
@ -1874,6 +1874,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
|
||||||
goto out_unfreeze;
|
goto out_unfreeze;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_bit(NVME_NS_READY, &ns->flags);
|
||||||
blk_mq_unfreeze_queue(ns->disk->queue);
|
blk_mq_unfreeze_queue(ns->disk->queue);
|
||||||
|
|
||||||
if (blk_queue_is_zoned(ns->queue)) {
|
if (blk_queue_is_zoned(ns->queue)) {
|
||||||
|
@ -1885,6 +1886,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
|
||||||
if (nvme_ns_head_multipath(ns->head)) {
|
if (nvme_ns_head_multipath(ns->head)) {
|
||||||
blk_mq_freeze_queue(ns->head->disk->queue);
|
blk_mq_freeze_queue(ns->head->disk->queue);
|
||||||
nvme_update_disk_info(ns->head->disk, ns, id);
|
nvme_update_disk_info(ns->head->disk, ns, id);
|
||||||
|
nvme_mpath_revalidate_paths(ns);
|
||||||
blk_stack_limits(&ns->head->disk->queue->limits,
|
blk_stack_limits(&ns->head->disk->queue->limits,
|
||||||
&ns->queue->limits, 0);
|
&ns->queue->limits, 0);
|
||||||
disk_update_readahead(ns->head->disk);
|
disk_update_readahead(ns->head->disk);
|
||||||
|
@ -3795,6 +3797,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
|
||||||
if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
|
if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
clear_bit(NVME_NS_READY, &ns->flags);
|
||||||
set_capacity(ns->disk, 0);
|
set_capacity(ns->disk, 0);
|
||||||
nvme_fault_inject_fini(&ns->fault_inject);
|
nvme_fault_inject_fini(&ns->fault_inject);
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,21 @@ void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
|
||||||
mutex_unlock(&ctrl->scan_lock);
|
mutex_unlock(&ctrl->scan_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
|
||||||
|
{
|
||||||
|
struct nvme_ns_head *head = ns->head;
|
||||||
|
sector_t capacity = get_capacity(head->disk);
|
||||||
|
int node;
|
||||||
|
|
||||||
|
list_for_each_entry_rcu(ns, &head->list, siblings) {
|
||||||
|
if (capacity != get_capacity(ns->disk))
|
||||||
|
clear_bit(NVME_NS_READY, &ns->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_node(node)
|
||||||
|
rcu_assign_pointer(head->current_path[node], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static bool nvme_path_is_disabled(struct nvme_ns *ns)
|
static bool nvme_path_is_disabled(struct nvme_ns *ns)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -158,7 +173,7 @@ static bool nvme_path_is_disabled(struct nvme_ns *ns)
|
||||||
ns->ctrl->state != NVME_CTRL_DELETING)
|
ns->ctrl->state != NVME_CTRL_DELETING)
|
||||||
return true;
|
return true;
|
||||||
if (test_bit(NVME_NS_ANA_PENDING, &ns->flags) ||
|
if (test_bit(NVME_NS_ANA_PENDING, &ns->flags) ||
|
||||||
test_bit(NVME_NS_REMOVING, &ns->flags))
|
!test_bit(NVME_NS_READY, &ns->flags))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,6 +456,7 @@ struct nvme_ns {
|
||||||
#define NVME_NS_DEAD 1
|
#define NVME_NS_DEAD 1
|
||||||
#define NVME_NS_ANA_PENDING 2
|
#define NVME_NS_ANA_PENDING 2
|
||||||
#define NVME_NS_FORCE_RO 3
|
#define NVME_NS_FORCE_RO 3
|
||||||
|
#define NVME_NS_READY 4
|
||||||
|
|
||||||
struct cdev cdev;
|
struct cdev cdev;
|
||||||
struct device cdev_device;
|
struct device cdev_device;
|
||||||
|
@ -748,6 +749,7 @@ void nvme_mpath_init_ctrl(struct nvme_ctrl *ctrl);
|
||||||
void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
|
void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
|
||||||
void nvme_mpath_stop(struct nvme_ctrl *ctrl);
|
void nvme_mpath_stop(struct nvme_ctrl *ctrl);
|
||||||
bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
|
bool nvme_mpath_clear_current_path(struct nvme_ns *ns);
|
||||||
|
void nvme_mpath_revalidate_paths(struct nvme_ns *ns);
|
||||||
void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
|
void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl);
|
||||||
void nvme_mpath_shutdown_disk(struct nvme_ns_head *head);
|
void nvme_mpath_shutdown_disk(struct nvme_ns_head *head);
|
||||||
|
|
||||||
|
@ -795,6 +797,9 @@ static inline bool nvme_mpath_clear_current_path(struct nvme_ns *ns)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
static inline void nvme_mpath_revalidate_paths(struct nvme_ns *ns)
|
||||||
|
{
|
||||||
|
}
|
||||||
static inline void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
|
static inline void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче