Skip to content

Commit

Permalink
Merge tag 'nvme-6.9-2024-04-04' of git://git.infradead.org/nvme into …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
axboe committed Apr 4, 2024
2 parents 22d24a5 + 205fb5f commit 9d0e852
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 33 deletions.
41 changes: 32 additions & 9 deletions drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2076,6 +2076,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
bool vwc = ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT;
struct queue_limits lim;
struct nvme_id_ns_nvm *nvm = NULL;
struct nvme_zone_info zi = {};
struct nvme_id_ns *id;
sector_t capacity;
unsigned lbaf;
Expand All @@ -2088,18 +2089,25 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
if (id->ncap == 0) {
/* namespace not allocated or attached */
info->is_removed = true;
ret = -ENODEV;
ret = -ENXIO;
goto out;
}
lbaf = nvme_lbaf_index(id->flbas);

if (ns->ctrl->ctratt & NVME_CTRL_ATTR_ELBAS) {
ret = nvme_identify_ns_nvm(ns->ctrl, info->nsid, &nvm);
if (ret < 0)
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);
lbaf = nvme_lbaf_index(id->flbas);
ns->head->lba_shift = id->lbaf[lbaf].ds;
ns->head->nuse = le64_to_cpu(id->nuse);
capacity = nvme_lba_to_sect(ns->head, le64_to_cpu(id->nsze));
Expand All @@ -2112,13 +2120,8 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
capacity = 0;
nvme_config_discard(ns, &lim);
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
ns->head->ids.csi == NVME_CSI_ZNS) {
ret = nvme_update_zone_info(ns, lbaf, &lim);
if (ret) {
blk_mq_unfreeze_queue(ns->disk->queue);
goto out;
}
}
ns->head->ids.csi == NVME_CSI_ZNS)
nvme_update_zone_info(ns, &lim, &zi);
ret = queue_limits_commit_update(ns->disk->queue, &lim);
if (ret) {
blk_mq_unfreeze_queue(ns->disk->queue);
Expand Down Expand Up @@ -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)) {
struct queue_limits *ns_lim = &ns->disk->queue->limits;
struct queue_limits lim;

blk_mq_freeze_queue(ns->head->disk->queue);
Expand All @@ -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));
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.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,
ns->head->disk->disk_name);
ret = queue_limits_commit_update(ns->head->disk->queue, &lim);
Expand Down
4 changes: 2 additions & 2 deletions drivers/nvme/host/fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2428,7 +2428,7 @@ nvme_fc_ctrl_get(struct nvme_fc_ctrl *ctrl)
* controller. Called after last nvme_put_ctrl() call
*/
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);

Expand Down Expand Up @@ -3384,7 +3384,7 @@ static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = {
.reg_read32 = nvmf_reg_read32,
.reg_read64 = nvmf_reg_read64,
.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,
.delete_ctrl = nvme_fc_delete_ctrl,
.get_address = nvmf_get_address,
Expand Down
12 changes: 10 additions & 2 deletions drivers/nvme/host/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -1036,10 +1036,18 @@ static inline bool nvme_disk_is_ns_head(struct gendisk *disk)
}
#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,
unsigned int nr_zones, report_zones_cb cb, void *data);
int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf,
struct queue_limits *lim);
int nvme_query_zone_info(struct nvme_ns *ns, unsigned lbaf,
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
blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns, struct request *req,
struct nvme_command *cmnd,
Expand Down
33 changes: 20 additions & 13 deletions drivers/nvme/host/zns.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ static int nvme_set_max_append(struct nvme_ctrl *ctrl)
return 0;
}

int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf,
struct queue_limits *lim)
int nvme_query_zone_info(struct nvme_ns *ns, unsigned lbaf,
struct nvme_zone_info *zi)
{
struct nvme_effects_log *log = ns->head->effects;
struct nvme_command c = { };
Expand Down Expand Up @@ -89,27 +89,34 @@ int nvme_update_zone_info(struct nvme_ns *ns, unsigned lbaf,
goto free_data;
}

ns->head->zsze =
nvme_lba_to_sect(ns->head, le64_to_cpu(id->lbafe[lbaf].zsze));
if (!is_power_of_2(ns->head->zsze)) {
zi->zone_size = le64_to_cpu(id->lbafe[lbaf].zsze);
if (!is_power_of_2(zi->zone_size)) {
dev_warn(ns->ctrl->device,
"invalid zone size:%llu for namespace:%u\n",
ns->head->zsze, ns->head->ns_id);
"invalid zone size: %llu for namespace: %u\n",
zi->zone_size, ns->head->ns_id);
status = -ENODEV;
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:
kfree(id);
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,
unsigned int nr_zones, size_t *buflen)
{
Expand Down
47 changes: 47 additions & 0 deletions drivers/nvme/target/configfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,11 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
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);
if (IS_ERR(subsys))
return ERR_CAST(subsys);
Expand Down Expand Up @@ -2159,7 +2164,49 @@ static const struct config_item_type nvmet_hosts_type = {

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 = {
.ct_attrs = nvmet_root_attrs,
.ct_owner = THIS_MODULE,
};

Expand Down
7 changes: 7 additions & 0 deletions drivers/nvme/target/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,13 @@ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port,
}

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) {
if (!strncmp(p->subsys->subsysnqn, subsysnqn,
NVMF_NQN_SIZE)) {
Expand Down
17 changes: 10 additions & 7 deletions drivers/nvme/target/fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1115,16 +1115,21 @@ nvmet_fc_schedule_delete_assoc(struct nvmet_fc_tgt_assoc *assoc)
}

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;
bool found = false;

rcu_read_lock();
list_for_each_entry_rcu(a, &tgtport->assoc_list, a_list) {
if (association_id == a->association_id)
return true;
if (association_id == a->association_id) {
found = true;
break;
}
}
rcu_read_unlock();

return false;
return found;
}

static struct nvmet_fc_tgt_assoc *
Expand Down Expand Up @@ -1164,13 +1169,11 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle)
ran = ran << BYTES_FOR_QID_SHIFT;

spin_lock_irqsave(&tgtport->lock, flags);
rcu_read_lock();
if (!nvmet_fc_assoc_exits(tgtport, ran)) {
if (!nvmet_fc_assoc_exists(tgtport, ran)) {
assoc->association_id = ran;
list_add_tail_rcu(&assoc->a_list, &tgtport->assoc_list);
done = true;
}
rcu_read_unlock();
spin_unlock_irqrestore(&tgtport->lock, flags);
} while (!done);

Expand Down

0 comments on commit 9d0e852

Please sign in to comment.