From: Hannes Reinecke <hare@kernel.org>
To: Christoph Hellwig <hch@lst.de>
Cc: Keith Busch <kbusch@kernel.org>, Sagi Grimberg <sagi@grimberg.me>,
linux-nvme@lists.infradead.org, Hannes Reinecke <hare@kernel.org>
Subject: [PATCH 2/2] nvmet: implement persistent read-only namespace feature
Date: Thu, 3 Apr 2025 16:47:47 +0200 [thread overview]
Message-ID: <20250403144747.43043-3-hare@kernel.org> (raw)
In-Reply-To: <20250403144747.43043-1-hare@kernel.org>
Per default we try to open the 'device_path' read-write, which might
fail if the device is read-only. So retry with opening read-only, and
implement a new 'persistent_ro' flag if we did so.
And map that flag onto the 'Permanently Write Protect' setting in the
write protection feature.
Signed-off-by: Hannes Reinecke <hare@kernel.org>
---
drivers/nvme/target/admin-cmd.c | 15 +++++++++++----
drivers/nvme/target/configfs.c | 5 +++++
drivers/nvme/target/core.c | 2 ++
drivers/nvme/target/io-cmd-bdev.c | 11 +++++++++++
drivers/nvme/target/io-cmd-file.c | 21 +++++++++++++++++----
drivers/nvme/target/nvmet.h | 1 +
6 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 43f819b0f89b..2fea7ab05408 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -1098,7 +1098,7 @@ static void nvmet_execute_id_cs_indep(struct nvmet_req *req)
id->nstat = NVME_NSTAT_NRDY;
id->anagrpid = cpu_to_le32(req->ns->anagrpid);
id->nmic = NVME_NS_NMIC_SHARED;
- if (req->ns->readonly)
+ if (req->ns->readonly || req->ns->persistent_ro)
id->nsattr |= NVME_NS_ATTR_RO;
if (req->ns->bdev && !bdev_nonrot(req->ns->bdev))
id->nsfeat |= NVME_NS_ROTATIONAL;
@@ -1225,8 +1225,13 @@ static u16 nvmet_set_feat_write_protect(struct nvmet_req *req)
req->ns->readonly = false;
break;
case NVME_NS_NO_WRITE_PROTECT:
- req->ns->readonly = false;
- status = 0;
+ if (req->ns->persistent_ro)
+ status = NVME_SC_FEATURE_NOT_CHANGEABLE | \
+ NVME_STATUS_DNR;
+ else {
+ req->ns->readonly = false;
+ status = 0;
+ }
break;
default:
break;
@@ -1418,7 +1423,9 @@ static u16 nvmet_get_feat_write_protect(struct nvmet_req *req)
return result;
mutex_lock(&subsys->lock);
- if (req->ns->readonly == true)
+ if (req->ns->persistent_ro == true)
+ result = NVME_NS_WRITE_PROTECT_PERMANENT;
+ else if (req->ns->readonly == true)
result = NVME_NS_WRITE_PROTECT;
else
result = NVME_NS_NO_WRITE_PROTECT;
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index cb03b448ae6d..1efe1ed2ae50 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -840,6 +840,11 @@ static ssize_t nvmet_ns_readonly_store(struct config_item *item,
mutex_unlock(&ns->subsys->lock);
return -EINVAL;
}
+ if (ns->persistent_ro && val == false) {
+ pr_err("the ns:%d is permanently read-only\n", ns->nsid);
+ mutex_unlock(&ns->subsys->lock);
+ return -EACCES;
+ }
ns->readonly = val;
mutex_unlock(&ns->subsys->lock);
return count;
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 2e741696f371..42605c67cbeb 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -725,6 +725,8 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
uuid_gen(&ns->uuid);
ns->buffered_io = false;
+ ns->readonly = false;
+ ns->persistent_ro = false;
ns->csi = NVME_CSI_NVM;
return ns;
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 83be0657e6df..f28dfac2b9fe 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -91,6 +91,17 @@ int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
BLK_OPEN_READ | BLK_OPEN_WRITE, NULL, NULL);
if (IS_ERR(ns->bdev_file)) {
ret = PTR_ERR(ns->bdev_file);
+ if (ret == -EACCES) {
+ ns->bdev_file = bdev_file_open_by_path(ns->device_path,
+ BLK_OPEN_READ, NULL, NULL);
+ if (IS_ERR(ns->bdev_file)) {
+ ret = PTR_ERR(ns->bdev_file);
+ } else {
+ ns->readonly = true;
+ ns->persistent_ro = true;
+ ret = 0;
+ }
+ }
if (ret != -ENOTBLK) {
pr_err("failed to open block device %s: (%d)\n",
ns->device_path, ret);
diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c
index 2d068439b129..770dec653bab 100644
--- a/drivers/nvme/target/io-cmd-file.c
+++ b/drivers/nvme/target/io-cmd-file.c
@@ -41,10 +41,23 @@ int nvmet_file_ns_enable(struct nvmet_ns *ns)
ns->file = filp_open(ns->device_path, flags, 0);
if (IS_ERR(ns->file)) {
ret = PTR_ERR(ns->file);
- pr_err("failed to open file %s: (%d)\n",
- ns->device_path, ret);
- ns->file = NULL;
- return ret;
+ if (ret == -EACCES) {
+ flags = O_RDONLY | O_LARGEFILE;
+ ns->file = filp_open(ns->device_path, flags, 0);
+ if (IS_ERR(ns->file)) {
+ ret = PTR_ERR(ns->file);
+ } else {
+ ns->readonly = true;
+ ns->persistent_ro = true;
+ ret = 0;
+ }
+ }
+ if (ret) {
+ pr_err("failed to open file %s: (%d)\n",
+ ns->device_path, ret);
+ ns->file = NULL;
+ return ret;
+ }
}
nvmet_file_ns_revalidate(ns);
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 29ae0657ba8f..166add3c119f 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -103,6 +103,7 @@ struct nvmet_ns {
struct block_device *bdev;
struct file *file;
bool readonly;
+ bool persistent_ro;
u32 nsid;
u32 blksize_shift;
loff_t size;
--
2.35.3
next prev parent reply other threads:[~2025-04-03 14:47 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-03 14:47 [PATCH 0/2] nvmet: improve 'read-only' handling Hannes Reinecke
2025-04-03 14:47 ` [PATCH 1/2] nvmet: make 'readonly' setting configurable Hannes Reinecke
2025-04-03 15:44 ` Keith Busch
2025-04-03 15:51 ` Hannes Reinecke
2025-04-04 6:21 ` Christoph Hellwig
2025-04-08 14:24 ` Keith Busch
2025-04-04 6:25 ` Christoph Hellwig
2025-04-03 14:47 ` Hannes Reinecke [this message]
2025-04-04 6:26 ` [PATCH 2/2] nvmet: implement persistent read-only namespace feature Christoph Hellwig
2025-04-04 9:36 ` Hannes Reinecke
2025-04-04 6:19 ` [PATCH 0/2] nvmet: improve 'read-only' handling Christoph Hellwig
2025-04-04 6:25 ` Hannes Reinecke
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250403144747.43043-3-hare@kernel.org \
--to=hare@kernel.org \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=sagi@grimberg.me \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.