[PATCH] nvme: make sending wall-clock time to NVMe opt-in
Daniel Colascione
dancol at dancol.org
Mon Jul 13 13:34:43 PDT 2026
Some NVMe devices maintain a persistent log, the PEL, of events like
power-on and thermal excursions. The NVMe Set Features (Timestamp)
command allows an operating system to inform the NVMe of the current
wall-clock time. Wall-clock timestamp updates are logged to the PEL
alongside other events. By correlating PEL records, an attacker can
infer a user's usage patterns and even guess at time zone changes.
This change adds a per-controller NVMe flag accessible via sysfs that
controls whether we send the device the time. The flag is always present
and does nothing if the Timestamp feature is not supported. We update
the NVMe device's wall-clock time during controller initialization (if
the flag is enabled) and whenever the flag transitions from 0 to 1 on a
live controller. The flag latches the requested value. Sending the
timestamp to the device is best-effort and warns on every failure.
The nvme_core.timestamps_enabled_default module parameter supplies the
default value of the per-controller flag. Default it to false as the
privacy-preserving choice. Users who want to provide controllers with
real-world time can set the module parameter to true or enable
the per-controller sysfs flag, perhaps via udev.
As an alternative, we could also get the timestamp updates out of the
kernel entirely and have interested users run nvme(1) to
update timestamps.
Signed-off-by: Daniel Colascione <dancol at dancol.org>
---
Documentation/ABI/testing/sysfs-nvme | 21 ++++++++++++++++++
MAINTAINERS | 2 +-
drivers/nvme/host/core.c | 22 +++++++++++--------
drivers/nvme/host/nvme.h | 2 ++
drivers/nvme/host/sysfs.c | 32 ++++++++++++++++++++++++++++
5 files changed, 69 insertions(+), 10 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-nvme
diff --git a/Documentation/ABI/testing/sysfs-nvme b/Documentation/ABI/testing/sysfs-nvme
new file mode 100644
index 0000000000000..bb98974f22b7f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-nvme
@@ -0,0 +1,21 @@
+What: /sys/class/nvme/nvmeX/timestamps_enabled
+Date: July 2026
+KernelVersion: 7.3
+Contact: Linux NVMe mailing list <linux-nvme at lists.infradead.org>
+Description:
+ Shows or sets whether the kernel sends wall-clock time to the
+ controller using the NVMe Timestamp feature. Reading returns 1
+ (enabled) or 0 (disabled). Writing accepts a boolean value. The
+ attribute is present for every controller. On controllers that
+ do not support the Timestamp feature, the setting has no effect.
+
+ The per-controller value is initialized from
+ nvme_core.timestamps_enabled_default, which defaults to false. When
+ enabled, the kernel sends a timestamp whenever the controller
+ starts, including on controller resets and resume from suspend.
+ Changing the value from 0 to 1 on a live controller
+ sends a timestamp immediately. Disabling does not affect a
+ timestamp already sent.
+
+ Writes latch the requested value. Sending timestamps to the
+ controller is best-effort; every failure generates a warning.
diff --git a/MAINTAINERS b/MAINTAINERS
index 5bbc5b49d36a3..c6f46a4e8dd37 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19207,7 +19207,7 @@ L: linux-nvme at lists.infradead.org
S: Supported
W: http://git.infradead.org/nvme.git
T: git git://git.infradead.org/nvme.git
-F: Documentation/ABI/stable/sysfs-nvme
+F: Documentation/ABI/*/sysfs-nvme
F: Documentation/admin-guide/nvme-multipath.rst
F: Documentation/fault-injection/nvme-fault-injection.rst
F: Documentation/nvme/
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index db0c8ad4628a7..a49f71563e112 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -71,6 +71,11 @@ module_param(default_ps_max_latency_us, ulong, 0644);
MODULE_PARM_DESC(default_ps_max_latency_us,
"max power saving latency for new devices; use PM QOS to change per device");
+static bool timestamps_enabled_default;
+module_param(timestamps_enabled_default, bool, 0644);
+MODULE_PARM_DESC(timestamps_enabled_default,
+ "default value of the per-controller timestamps_enabled sysfs attribute");
+
static bool force_apst;
module_param(force_apst, bool, 0644);
MODULE_PARM_DESC(force_apst, "allow APST for newly enumerated devices even if quirked off");
@@ -2824,21 +2829,21 @@ int nvme_enable_ctrl(struct nvme_ctrl *ctrl)
}
EXPORT_SYMBOL_GPL(nvme_enable_ctrl);
-static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)
+void nvme_configure_timestamp(struct nvme_ctrl *ctrl)
{
__le64 ts;
int ret;
- if (!(ctrl->oncs & NVME_CTRL_ONCS_TIMESTAMP))
- return 0;
+ if (!READ_ONCE(ctrl->timestamps_enabled) ||
+ !(ctrl->oncs & NVME_CTRL_ONCS_TIMESTAMP))
+ return;
ts = cpu_to_le64(ktime_to_ms(ktime_get_real()));
ret = nvme_set_features(ctrl, NVME_FEAT_TIMESTAMP, 0, &ts, sizeof(ts),
NULL);
if (ret)
- dev_warn_once(ctrl->device,
- "could not set timestamp (%d)\n", ret);
- return ret;
+ dev_warn(ctrl->device,
+ "could not set timestamp (%d)\n", ret);
}
static int nvme_configure_host_options(struct nvme_ctrl *ctrl)
@@ -3771,9 +3776,7 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl, bool was_suspended)
if (ret < 0)
return ret;
- ret = nvme_configure_timestamp(ctrl);
- if (ret < 0)
- return ret;
+ nvme_configure_timestamp(ctrl);
ret = nvme_configure_host_options(ctrl);
if (ret < 0)
@@ -5168,6 +5171,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
WRITE_ONCE(ctrl->state, NVME_CTRL_NEW);
ctrl->passthru_err_log_enabled = false;
+ ctrl->timestamps_enabled = READ_ONCE(timestamps_enabled_default);
clear_bit(NVME_CTRL_FAILFAST_EXPIRED, &ctrl->flags);
spin_lock_init(&ctrl->lock);
mutex_init(&ctrl->namespaces_lock);
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index a679a4c61462d..47f7d6e7c5438 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -335,6 +335,7 @@ struct nvme_ctrl {
bool comp_seen;
bool identified;
bool passthru_err_log_enabled;
+ bool timestamps_enabled;
enum nvme_ctrl_state state;
spinlock_t lock;
struct mutex scan_lock;
@@ -891,6 +892,7 @@ void nvme_uninit_ctrl(struct nvme_ctrl *ctrl);
void nvme_start_ctrl(struct nvme_ctrl *ctrl);
void nvme_stop_ctrl(struct nvme_ctrl *ctrl);
int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl, bool was_suspended);
+void nvme_configure_timestamp(struct nvme_ctrl *ctrl);
int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
const struct blk_mq_ops *ops, unsigned int cmd_size);
void nvme_remove_admin_tag_set(struct nvme_ctrl *ctrl);
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index abf8edaae371b..fe62747630014 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -36,6 +36,37 @@ static ssize_t nvme_sysfs_rescan(struct device *dev,
}
static DEVICE_ATTR(rescan_controller, S_IWUSR, NULL, nvme_sysfs_rescan);
+static ssize_t timestamps_enabled_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", READ_ONCE(ctrl->timestamps_enabled));
+}
+
+static ssize_t timestamps_enabled_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+ bool enabled, was_enabled;
+ int ret;
+
+ ret = kstrtobool(buf, &enabled);
+ if (ret)
+ return ret;
+
+ was_enabled = READ_ONCE(ctrl->timestamps_enabled);
+ WRITE_ONCE(ctrl->timestamps_enabled, enabled);
+
+ if (enabled && !was_enabled &&
+ nvme_ctrl_state(ctrl) == NVME_CTRL_LIVE)
+ nvme_configure_timestamp(ctrl);
+
+ return count;
+}
+static DEVICE_ATTR_RW(timestamps_enabled);
+
static ssize_t nvme_adm_passthru_err_log_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -929,6 +960,7 @@ static DEVICE_ATTR(dhchap_ctrl_secret, S_IRUGO | S_IWUSR,
static struct attribute *nvme_dev_attrs[] = {
&dev_attr_reset_controller.attr,
&dev_attr_rescan_controller.attr,
+ &dev_attr_timestamps_enabled.attr,
&dev_attr_model.attr,
&dev_attr_serial.attr,
&dev_attr_firmware_rev.attr,
base-commit: cdf9a65e80ec874b630502946d269fac38dc5de8
--
2.53.0
More information about the Linux-nvme
mailing list