From nobody Sat Jul 25 20:47:03 2026 Received: from mail-pg1-f169.google.com (mail-pg1-f169.google.com [209.85.215.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 732FC358387 for ; Mon, 13 Jul 2026 20:35:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783974910; cv=none; b=S5m+dkrlX++r+ZeAThgvuCKRmxzMUo6zYoCv4DoMTHNyWQbUysfofGkUPc0rrrGDizZIbRVnsTB8Z8NT/OLuszAVzzWPRZDVM+2KvC3AeerM9XyQ6ImUaE+wPvg9GY56MXYdj3bD444TlEHGQcxEXBT5xvUEJr0ynaUTJ3PEW80= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783974910; c=relaxed/simple; bh=vBk5xDqVAwtfoBvssOFsvVnOQfYZB5mppbKSySiXAHg=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=u9ubKJuQCNKfKNjJ+zFagvj8F/wBzsYvUWpyUvVZL8N/CFV8SQdu+H+wo14coiMgGlGTM2zP0DuXvKAcRBDhwuLdp/AuEuhAH8bBmTuAxIl8s1JNsv/Sw4fdbkKN/6Hxarrcp0fl7YyyOxSLwVNCkjtYDWBxba/2pPvMeZjApD0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=dancol.org; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=dancol.org header.i=@dancol.org header.b=F6zY5rgG; arc=none smtp.client-ip=209.85.215.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=dancol.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=dancol.org header.i=@dancol.org header.b="F6zY5rgG" Received: by mail-pg1-f169.google.com with SMTP id 41be03b00d2f7-c89636920a3so136093a12.1 for ; Mon, 13 Jul 2026 13:35:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783974908; x=1784579708; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dkim-signature:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to:content-type; bh=pFE90n5MyELBH4c37ZN7/rXstYc+YP7GnIgiGCcWkow=; b=mMnBJme70yqir7do1KA0pmgHTRS4PJSL0zrYlnmOq4RuzyCi1knbxFZ/n6kliNDADE qogOEGkVqLZGoK/yldcoUwl1CdJmuSuDw9723mqpbMRORV1hfP6L6wmaOZFUPmvb6D2x +ya+m7po1I75cz9mpS3mITIG0onbIJLYwEHnYFZKOqsXZQvBiy7ne4wK3IDzu/ld7ZUZ 0q24TlYZA1F8e9mc/8Js07jHhtFXpc0Ah2bU1N1VvH59HSzqZ1jV6AMfqMtn1KmvdcBK jIGEaCRQHp5oNAXmUIIImBz8pTam9mh0AieMWxp2jzGdGXTqu7ntbF6vABSwkElWUA92 2O6Q== X-Forwarded-Encrypted: i=1; AHgh+RoRDWG3fhP81Q7ghidqR8+ymozcr+QAbpfGPdnydwedqtLfFLEfJ/+QebbCqngzOUo9DX6RR9tZXlUEDjo=@vger.kernel.org X-Gm-Message-State: AOJu0Yzug5vT6pQXe2OrCDSdrD0tSPTat+3cXcNbKnQTUl60xj/p4ToB flaxNTFwuucuoog3HFrN58ZV4meZLmgtgzhXUypFoDEWHthEKjBnm0dm X-Gm-Gg: AfdE7cnxPxid5G3+VNFjRDGNi3vcel4XJy0ED/iGA+tECp46cABMq80jDdlX/CeJx3w /kCSsSn0d43W3ebqLINS6v9K0T+yCYStJ+yTYKix0HVq8ccrR4A3e8oqIktxYuEcZ+pg1kjHcuO u+30H0BY84GwygAcNebJcL7U7kH0bpsm8GDakigW3Hz932ub008urSDcH/+WaLJMK716J4EPasi tZ9TN3A8S705WfQ6z4EiXbLDsQEnQ8pmDa/udIk1pSzhF1J649aK8lq70KAuV1f5pFZ1FrdQ8nE DRucY4n2cYBOLo4Ngc9HKRZn4i5ryRul0TZ3ImP/QdMEEqvJ8mY6l6KI13b6myyJw5k+BBJiOee DZW1W4mplNHWzsGx4C4m/dDPEzlgjEWE5TQLzJxMlcCSWQs/DvRGUk370nTZwiFD24UZWucSSfH Wu19RS2EEWoK+moII5JdnStymQ7Im3TKuUh/4WpPkhs3RRTDa+O0YM9jBoDhZ9vvLRTvAM4z/0m ftdQ6uJiRvDrP+K/1dCT87RGFN9kA== X-Received: by 2002:a05:6a21:140a:b0:3c0:9c19:b27d with SMTP id adf61e73a8af0-3c110cfefa5mr11289519637.75.1783974907685; Mon, 13 Jul 2026 13:35:07 -0700 (PDT) Received: from dancol.org (dancol.org. [2600:3c01:e000:3d8::1]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-31174839f89sm73242716eec.10.2026.07.13.13.35.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Jul 2026 13:35:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=dancol.org; s=x; h=MIME-Version:Message-ID:Date:Subject:To:From:Content-Type; bh=pFE90n5MyELBH4c37ZN7/rXstYc+YP7GnIgiGCcWkow=; b=F6zY5rgGB1exwn3WQgxTIAFDsa D14eHj/MfIMyC1Ht71sRsuz5tmMlTpDAzvMXIW9SBKvuG9NztwPUYjngA2omUOFpWCp9Vc6iLJsFm 6wC1BUVlHGOXkVXlBXl/zt/7NefMJGM0owL7ZeOsRcpgJI5g/R2zS2SaJQBudl/sJAC2jiUDeae1N uNw3AEmrUOelfYAeBE6/w5eCsgqe12yl6k7ezKBmjA86YdwTOsSGzbLnfR7i4A+U7oL8/PXBaqHaW GF8AYVbEYoGGjjQ27XqpB3cOJBH6eQ9yLWtr9vBIbT3p088/HT8HBDnvDvqwfn+0aKaRPBvPLt86w VHRf+W+g==; Received: from dancol by dancol.org with local (Exim 4.98.2) (envelope-from ) id 1wjNMn-00000000VJg-3rkE; Mon, 13 Jul 2026 16:35:05 -0400 From: Daniel Colascione To: Keith Busch , Jens Axboe , Christoph Hellwig , Sagi Grimberg Cc: linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org, Daniel Colascione Subject: [PATCH] nvme: make sending wall-clock time to NVMe opt-in Date: Mon, 13 Jul 2026 16:34:43 -0400 Message-ID: <20260713203443.322748-1-dancol@dancol.org> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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/testi= ng/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 +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@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 dev= ice"); =20 +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); =20 -static int nvme_configure_timestamp(struct nvme_ctrl *ctrl) +void nvme_configure_timestamp(struct nvme_ctrl *ctrl) { __le64 ts; int ret; =20 - if (!(ctrl->oncs & NVME_CTRL_ONCS_TIMESTAMP)) - return 0; + if (!READ_ONCE(ctrl->timestamps_enabled) || + !(ctrl->oncs & NVME_CTRL_ONCS_TIMESTAMP)) + return; =20 ts =3D cpu_to_le64(ktime_to_ms(ktime_get_real())); ret =3D 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); } =20 static int nvme_configure_host_options(struct nvme_ctrl *ctrl) @@ -3771,9 +3776,7 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl, boo= l was_suspended) if (ret < 0) return ret; =20 - ret =3D nvme_configure_timestamp(ctrl); - if (ret < 0) - return ret; + nvme_configure_timestamp(ctrl); =20 ret =3D nvme_configure_host_options(ctrl); if (ret < 0) @@ -5168,6 +5171,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct dev= ice *dev, =20 WRITE_ONCE(ctrl->state, NVME_CTRL_NEW); ctrl->passthru_err_log_enabled =3D false; + ctrl->timestamps_enabled =3D 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); =20 +static ssize_t timestamps_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nvme_ctrl *ctrl =3D 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 =3D dev_get_drvdata(dev); + bool enabled, was_enabled; + int ret; + + ret =3D kstrtobool(buf, &enabled); + if (ret) + return ret; + + was_enabled =3D READ_ONCE(ctrl->timestamps_enabled); + WRITE_ONCE(ctrl->timestamps_enabled, enabled); + + if (enabled && !was_enabled && + nvme_ctrl_state(ctrl) =3D=3D 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_IWUS= R, static struct attribute *nvme_dev_attrs[] =3D { &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 --=20 2.53.0