Skip to content

Commit

Permalink
nvme: add csi, ms and nuse to sysfs
Browse files Browse the repository at this point in the history
libnvme is using the sysfs for enumarating the nvme resources. Though
there are few missing attritbutes in the sysfs. For these libnvme issues
commands during discovering.

As the kernel already knows all these attributes and we would like to
avoid libnvme to issue commands all the time, expose these missing
attributes.

The nuse value is updated on request because the nuse is a volatile
value. Since any user can read the sysfs attribute, a very simple rate
limit is added (update once every 5 seconds). A more sophisticated
update strategy can be added later if there is actually a need for it.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
  • Loading branch information
Daniel Wagner authored and Keith Busch committed Dec 19, 2023
1 parent 83ac678 commit a1a825a
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
6 changes: 5 additions & 1 deletion drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/ptrace.h>
#include <linux/nvme_ioctl.h>
#include <linux/pm_qos.h>
#include <linux/ratelimit.h>
#include <asm/unaligned.h>

#include "nvme.h"
Expand Down Expand Up @@ -1449,7 +1450,7 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl,
return status;
}

static int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid,
int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid,
struct nvme_id_ns **id)
{
struct nvme_command c = { };
Expand Down Expand Up @@ -2040,6 +2041,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
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);
nvme_set_queue_limits(ns->ctrl, ns->queue);

ret = nvme_configure_metadata(ns->ctrl, ns->head, id);
Expand Down Expand Up @@ -3420,6 +3422,8 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
head->ns_id = info->nsid;
head->ids = info->ids;
head->shared = info->is_shared;
ratelimit_state_init(&head->rs_nuse, 5 * HZ, 1);
ratelimit_set_flags(&head->rs_nuse, RATELIMIT_MSG_ON_RELEASE);
kref_init(&head->ref);

if (head->ids.csi) {
Expand Down
6 changes: 6 additions & 0 deletions drivers/nvme/host/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/rcupdate.h>
#include <linux/wait.h>
#include <linux/t10-pi.h>
#include <linux/ratelimit_types.h>

#include <trace/events/block.h>

Expand Down Expand Up @@ -451,13 +452,16 @@ struct nvme_ns_head {
u16 pi_size;
u16 sgs;
u32 sws;
u64 nuse;
u8 pi_type;
u8 guard_type;
#ifdef CONFIG_BLK_DEV_ZONED
u64 zsze;
#endif
unsigned long features;

struct ratelimit_state rs_nuse;

struct cdev cdev;
struct device cdev_device;

Expand Down Expand Up @@ -862,6 +866,8 @@ int nvme_ns_chr_uring_cmd(struct io_uring_cmd *ioucmd,
unsigned int issue_flags);
int nvme_ns_head_chr_uring_cmd(struct io_uring_cmd *ioucmd,
unsigned int issue_flags);
int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid,
struct nvme_id_ns **id);
int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo);
int nvme_dev_uring_cmd(struct io_uring_cmd *ioucmd, unsigned int issue_flags);

Expand Down
85 changes: 85 additions & 0 deletions drivers/nvme/host/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,97 @@ static ssize_t nsid_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(nsid);

static ssize_t csi_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ids.csi);
}
static DEVICE_ATTR_RO(csi);

static ssize_t metadata_bytes_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%u\n", dev_to_ns_head(dev)->ms);
}
static DEVICE_ATTR_RO(metadata_bytes);

static int ns_head_update_nuse(struct nvme_ns_head *head)
{
struct nvme_id_ns *id;
struct nvme_ns *ns;
int srcu_idx, ret = -EWOULDBLOCK;

/* Avoid issuing commands too often by rate limiting the update */
if (!__ratelimit(&head->rs_nuse))
return 0;

srcu_idx = srcu_read_lock(&head->srcu);
ns = nvme_find_path(head);
if (!ns)
goto out_unlock;

ret = nvme_identify_ns(ns->ctrl, head->ns_id, &id);
if (ret)
goto out_unlock;

head->nuse = le64_to_cpu(id->nuse);
kfree(id);

out_unlock:
srcu_read_unlock(&head->srcu, srcu_idx);
return ret;
}

static int ns_update_nuse(struct nvme_ns *ns)
{
struct nvme_id_ns *id;
int ret;

/* Avoid issuing commands too often by rate limiting the update. */
if (!__ratelimit(&ns->head->rs_nuse))
return 0;

ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, &id);
if (ret)
goto out_free_id;

ns->head->nuse = le64_to_cpu(id->nuse);

out_free_id:
kfree(id);

return ret;
}

static ssize_t nuse_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct nvme_ns_head *head = dev_to_ns_head(dev);
struct gendisk *disk = dev_to_disk(dev);
struct block_device *bdev = disk->part0;
int ret;

if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
bdev->bd_disk->fops == &nvme_ns_head_ops)
ret = ns_head_update_nuse(head);
else
ret = ns_update_nuse(bdev->bd_disk->private_data);
if (ret)
return ret;

return sysfs_emit(buf, "%llu\n", head->nuse);
}
static DEVICE_ATTR_RO(nuse);

static struct attribute *nvme_ns_attrs[] = {
&dev_attr_wwid.attr,
&dev_attr_uuid.attr,
&dev_attr_nguid.attr,
&dev_attr_eui.attr,
&dev_attr_csi.attr,
&dev_attr_nsid.attr,
&dev_attr_metadata_bytes.attr,
&dev_attr_nuse.attr,
#ifdef CONFIG_NVME_MULTIPATH
&dev_attr_ana_grpid.attr,
&dev_attr_ana_state.attr,
Expand Down

0 comments on commit a1a825a

Please sign in to comment.