Commit 9d0e8524 authored by Jens Axboe's avatar Jens Axboe

Merge tag 'nvme-6.9-2024-04-04' of git://git.infradead.org/nvme into block-6.9

Pull NVMe fixes from Keith:

"nvme fixes for Linux 6.9

 - Atomic queue limits fixes (Christoph)
 - Fabrics fixes (Hannes, Daniel)"

* tag 'nvme-6.9-2024-04-04' of git://git.infradead.org/nvme:
  nvme-fc: rename free_ctrl callback to match name pattern
  nvmet-fc: move RCU read lock to nvmet_fc_assoc_exists
  nvmet: implement unique discovery NQN
  nvme: don't create a multipath node for zero capacity devices
  nvme: split nvme_update_zone_info
  nvme-multipath: don't inherit LBA-related fields for the multipath node
parents 22d24a54 205fb5fa
...@@ -2076,6 +2076,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, ...@@ -2076,6 +2076,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
bool vwc = ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT; bool vwc = ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT;
struct queue_limits lim; struct queue_limits lim;
struct nvme_id_ns_nvm *nvm = NULL; struct nvme_id_ns_nvm *nvm = NULL;
struct nvme_zone_info zi = {};
struct nvme_id_ns *id; struct nvme_id_ns *id;
sector_t capacity; sector_t capacity;
unsigned lbaf; unsigned lbaf;
...@@ -2088,9 +2089,10 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, ...@@ -2088,9 +2089,10 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
if (id->ncap == 0) { if (id->ncap == 0) {
/* namespace not allocated or attached */ /* namespace not allocated or attached */
info->is_removed = true; info->is_removed = true;
ret = -ENODEV; ret = -ENXIO;
goto out; goto out;
} }
lbaf = nvme_lbaf_index(id->flbas);
if (ns->ctrl->ctratt & NVME_CTRL_ATTR_ELBAS) { if (ns->ctrl->ctratt & NVME_CTRL_ATTR_ELBAS) {
ret = nvme_identify_ns_nvm(ns->ctrl, info->nsid, &nvm); ret = nvme_identify_ns_nvm(ns->ctrl, info->nsid, &nvm);
...@@ -2098,8 +2100,14 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, ...@@ -2098,8 +2100,14 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
goto out; goto out;
} }
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
ns->head->ids.csi == NVME_CSI_ZNS) {
ret = nvme_query_zone_info(ns, lbaf, &zi);
if (ret < 0)
goto out;
}
blk_mq_freeze_queue(ns->disk->queue); blk_mq_freeze_queue(ns->disk->queue);
lbaf = nvme_lbaf_index(id->flbas);
ns->head->lba_shift = id->lbaf[lbaf].ds; ns->head->lba_shift = id->lbaf[lbaf].ds;
ns->head->nuse = le64_to_cpu(id->nuse); ns->head->nuse = le64_to_cpu(id->nuse);
capacity = nvme_lba_to_sect(ns->head, le64_to_cpu(id->nsze)); capacity = nvme_lba_to_sect(ns->head, le64_to_cpu(id->nsze));
...@@ -2112,13 +2120,8 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, ...@@ -2112,13 +2120,8 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
capacity = 0; capacity = 0;
nvme_config_discard(ns, &lim); nvme_config_discard(ns, &lim);
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
ns->head->ids.csi == NVME_CSI_ZNS) { ns->head->ids.csi == NVME_CSI_ZNS)
ret = nvme_update_zone_info(ns, lbaf, &lim); nvme_update_zone_info(ns, &lim, &zi);
if (ret) {
blk_mq_unfreeze_queue(ns->disk->queue);
goto out;
}
}
ret = queue_limits_commit_update(ns->disk->queue, &lim); ret = queue_limits_commit_update(ns->disk->queue, &lim);
if (ret) { if (ret) {
blk_mq_unfreeze_queue(ns->disk->queue); blk_mq_unfreeze_queue(ns->disk->queue);
...@@ -2201,6 +2204,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info) ...@@ -2201,6 +2204,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
} }
if (!ret && nvme_ns_head_multipath(ns->head)) { if (!ret && nvme_ns_head_multipath(ns->head)) {
struct queue_limits *ns_lim = &ns->disk->queue->limits;
struct queue_limits lim; struct queue_limits lim;
blk_mq_freeze_queue(ns->head->disk->queue); blk_mq_freeze_queue(ns->head->disk->queue);
...@@ -2212,7 +2216,26 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info) ...@@ -2212,7 +2216,26 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info)); set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
nvme_mpath_revalidate_paths(ns); nvme_mpath_revalidate_paths(ns);
/*
* queue_limits mixes values that are the hardware limitations
* for bio splitting with what is the device configuration.
*
* For NVMe the device configuration can change after e.g. a
* Format command, and we really want to pick up the new format
* value here. But we must still stack the queue limits to the
* least common denominator for multipathing to split the bios
* properly.
*
* To work around this, we explicitly set the device
* configuration to those that we just queried, but only stack
* the splitting limits in to make sure we still obey possibly
* lower limitations of other controllers.
*/
lim = queue_limits_start_update(ns->head->disk->queue); lim = queue_limits_start_update(ns->head->disk->queue);
lim.logical_block_size = ns_lim->logical_block_size;
lim.physical_block_size = ns_lim->physical_block_size;
lim.io_min = ns_lim->io_min;
lim.io_opt = ns_lim->io_opt;
queue_limits_stack_bdev(&lim, ns->disk->part0, 0, queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
ns->head->disk->disk_name); ns->head->disk->disk_name);
ret = queue_limits_commit_update(ns->head->disk->queue, &lim); ret = queue_limits_commit_update(ns->head->disk->queue, &lim);
......
...@@ -2428,7 +2428,7 @@ nvme_fc_ctrl_get(struct nvme_fc_ctrl *ctrl) ...@@ -2428,7 +2428,7 @@ nvme_fc_ctrl_get(struct nvme_fc_ctrl *ctrl)
* controller. Called after last nvme_put_ctrl() call * controller. Called after last nvme_put_ctrl() call
*/ */
static void static void
nvme_fc_nvme_ctrl_freed(struct nvme_ctrl *nctrl) nvme_fc_free_ctrl(struct nvme_ctrl *nctrl)
{ {
struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl); struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
...@@ -3384,7 +3384,7 @@ static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = { ...@@ -3384,7 +3384,7 @@ static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = {
.reg_read32 = nvmf_reg_read32, .reg_read32 = nvmf_reg_read32,
.reg_read64 = nvmf_reg_read64, .reg_read64 = nvmf_reg_read64,
.reg_write32 = nvmf_reg_write32, .reg_write32 = nvmf_reg_write32,
.free_ctrl = nvme_fc_nvme_ctrl_freed, .free_ctrl = nvme_fc_free_ctrl,
.submit_async_event = nvme_fc_submit_async_event, .submit_async_event = nvme_fc_submit_async_event,
.delete_ctrl = nvme_fc_delete_ctrl, .delete_ctrl = nvme_fc_delete_ctrl,
.get_address = nvmf_get_address, .get_address = nvmf_get_address,
......
...@@ -1036,10 +1036,18 @@ static inline bool nvme_disk_is_ns_head(struct gendisk *disk) ...@@ -1036,10 +1036,18 @@ static inline bool nvme_disk_is_ns_head(struct gendisk *disk)
} }
#endif /* CONFIG_NVME_MULTIPATH */ #endif /* CONFIG_NVME_MULTIPATH */
struct nvme_zone_info {
u64 zone_size;
unsigned int max_open_zones;
unsigned int max_active_zones;
};
int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector, int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector,
unsigned int nr_zones, report_zones_cb cb, void *data); unsigned int nr_zones, report_zones_cb cb, void *data);
int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf, int nvme_query_zone_info(struct nvme_ns *ns, unsigned lbaf,
struct queue_limits *lim); struct nvme_zone_info *zi);
void nvme_update_zone_info(struct nvme_ns *ns, struct queue_limits *lim,
struct nvme_zone_info *zi);
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns, struct request *req, blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns, struct request *req,
struct nvme_command *cmnd, struct nvme_command *cmnd,
......
...@@ -35,8 +35,8 @@ static int nvme_set_max_append(struct nvme_ctrl *ctrl) ...@@ -35,8 +35,8 @@ static int nvme_set_max_append(struct nvme_ctrl *ctrl)
return 0; return 0;
} }
int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf, int nvme_query_zone_info(struct nvme_ns *ns, unsigned lbaf,
struct queue_limits *lim) struct nvme_zone_info *zi)
{ {
struct nvme_effects_log *log = ns->head->effects; struct nvme_effects_log *log = ns->head->effects;
struct nvme_command c = { }; struct nvme_command c = { };
...@@ -89,27 +89,34 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf, ...@@ -89,27 +89,34 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf,
goto free_data; goto free_data;
} }
ns->head->zsze = zi->zone_size = le64_to_cpu(id->lbafe[lbaf].zsze);
nvme_lba_to_sect(ns->head, le64_to_cpu(id->lbafe[lbaf].zsze)); if (!is_power_of_2(zi->zone_size)) {
if (!is_power_of_2(ns->head->zsze)) {
dev_warn(ns->ctrl->device, dev_warn(ns->ctrl->device,
"invalid zone size:%llu for namespace:%u\n", "invalid zone size: %llu for namespace: %u\n",
ns->head->zsze, ns->head->ns_id); zi->zone_size, ns->head->ns_id);
status = -ENODEV; status = -ENODEV;
goto free_data; goto free_data;
} }
zi->max_open_zones = le32_to_cpu(id->mor) + 1;
zi->max_active_zones = le32_to_cpu(id->mar) + 1;
blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, ns->queue);
lim->zoned = 1;
lim->max_open_zones = le32_to_cpu(id->mor) + 1;
lim->max_active_zones = le32_to_cpu(id->mar) + 1;
lim->chunk_sectors = ns->head->zsze;
lim->max_zone_append_sectors = ns->ctrl->max_zone_append;
free_data: free_data:
kfree(id); kfree(id);
return status; return status;
} }
void nvme_update_zone_info(struct nvme_ns *ns, struct queue_limits *lim,
struct nvme_zone_info *zi)
{
lim->zoned = 1;
lim->max_open_zones = zi->max_open_zones;
lim->max_active_zones = zi->max_active_zones;
lim->max_zone_append_sectors = ns->ctrl->max_zone_append;
lim->chunk_sectors = ns->head->zsze =
nvme_lba_to_sect(ns->head, zi->zone_size);
blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, ns->queue);
}
static void *nvme_zns_alloc_report_buffer(struct nvme_ns *ns, static void *nvme_zns_alloc_report_buffer(struct nvme_ns *ns,
unsigned int nr_zones, size_t *buflen) unsigned int nr_zones, size_t *buflen)
{ {
......
...@@ -1613,6 +1613,11 @@ static struct config_group *nvmet_subsys_make(struct config_group *group, ...@@ -1613,6 +1613,11 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (sysfs_streq(name, nvmet_disc_subsys->subsysnqn)) {
pr_err("can't create subsystem using unique discovery NQN\n");
return ERR_PTR(-EINVAL);
}
subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME); subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
if (IS_ERR(subsys)) if (IS_ERR(subsys))
return ERR_CAST(subsys); return ERR_CAST(subsys);
...@@ -2159,7 +2164,49 @@ static const struct config_item_type nvmet_hosts_type = { ...@@ -2159,7 +2164,49 @@ static const struct config_item_type nvmet_hosts_type = {
static struct config_group nvmet_hosts_group; static struct config_group nvmet_hosts_group;
static ssize_t nvmet_root_discovery_nqn_show(struct config_item *item,
char *page)
{
return snprintf(page, PAGE_SIZE, "%s\n", nvmet_disc_subsys->subsysnqn);
}
static ssize_t nvmet_root_discovery_nqn_store(struct config_item *item,
const char *page, size_t count)
{
struct list_head *entry;
size_t len;
len = strcspn(page, "\n");
if (!len || len > NVMF_NQN_FIELD_LEN - 1)
return -EINVAL;
down_write(&nvmet_config_sem);
list_for_each(entry, &nvmet_subsystems_group.cg_children) {
struct config_item *item =
container_of(entry, struct config_item, ci_entry);
if (!strncmp(config_item_name(item), page, len)) {
pr_err("duplicate NQN %s\n", config_item_name(item));
up_write(&nvmet_config_sem);
return -EINVAL;
}
}
memset(nvmet_disc_subsys->subsysnqn, 0, NVMF_NQN_FIELD_LEN);
memcpy(nvmet_disc_subsys->subsysnqn, page, len);
up_write(&nvmet_config_sem);
return len;
}
CONFIGFS_ATTR(nvmet_root_, discovery_nqn);
static struct configfs_attribute *nvmet_root_attrs[] = {
&nvmet_root_attr_discovery_nqn,
NULL,
};
static const struct config_item_type nvmet_root_type = { static const struct config_item_type nvmet_root_type = {
.ct_attrs = nvmet_root_attrs,
.ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE,
}; };
......
...@@ -1541,6 +1541,13 @@ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port, ...@@ -1541,6 +1541,13 @@ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port,
} }
down_read(&nvmet_config_sem); down_read(&nvmet_config_sem);
if (!strncmp(nvmet_disc_subsys->subsysnqn, subsysnqn,
NVMF_NQN_SIZE)) {
if (kref_get_unless_zero(&nvmet_disc_subsys->ref)) {
up_read(&nvmet_config_sem);
return nvmet_disc_subsys;
}
}
list_for_each_entry(p, &port->subsystems, entry) { list_for_each_entry(p, &port->subsystems, entry) {
if (!strncmp(p->subsys->subsysnqn, subsysnqn, if (!strncmp(p->subsys->subsysnqn, subsysnqn,
NVMF_NQN_SIZE)) { NVMF_NQN_SIZE)) {
......
...@@ -1115,16 +1115,21 @@ nvmet_fc_schedule_delete_assoc(struct nvmet_fc_tgt_assoc *assoc) ...@@ -1115,16 +1115,21 @@ nvmet_fc_schedule_delete_assoc(struct nvmet_fc_tgt_assoc *assoc)
} }
static bool static bool
nvmet_fc_assoc_exits(struct nvmet_fc_tgtport *tgtport, u64 association_id) nvmet_fc_assoc_exists(struct nvmet_fc_tgtport *tgtport, u64 association_id)
{ {
struct nvmet_fc_tgt_assoc *a; struct nvmet_fc_tgt_assoc *a;
bool found = false;
rcu_read_lock();
list_for_each_entry_rcu(a, &tgtport->assoc_list, a_list) { list_for_each_entry_rcu(a, &tgtport->assoc_list, a_list) {
if (association_id == a->association_id) if (association_id == a->association_id) {
return true; found = true;
break;
}
} }
rcu_read_unlock();
return false; return found;
} }
static struct nvmet_fc_tgt_assoc * static struct nvmet_fc_tgt_assoc *
...@@ -1164,13 +1169,11 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle) ...@@ -1164,13 +1169,11 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle)
ran = ran << BYTES_FOR_QID_SHIFT; ran = ran << BYTES_FOR_QID_SHIFT;
spin_lock_irqsave(&tgtport->lock, flags); spin_lock_irqsave(&tgtport->lock, flags);
rcu_read_lock(); if (!nvmet_fc_assoc_exists(tgtport, ran)) {
if (!nvmet_fc_assoc_exits(tgtport, ran)) {
assoc->association_id = ran; assoc->association_id = ran;
list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list); list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list);
done = true; done = true;
} }
rcu_read_unlock();
spin_unlock_irqrestore(&tgtport->lock, flags); spin_unlock_irqrestore(&tgtport->lock, flags);
} while (!done); } while (!done);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment