Skip to content

Commit ab63089

Browse files
committed
libnvdimm, region: sysfs trigger for nvdimm_flush()
The nvdimm_flush() mechanism helps to reduce the impact of an ADR (asynchronous-dimm-refresh) failure. The ADR mechanism handles flushing platform WPQ (write-pending-queue) buffers when power is removed. The nvdimm_flush() mechanism performs that same function on-demand. When a pmem namespace is associated with a block device, an nvdimm_flush() is triggered with every block-layer REQ_FUA, or REQ_FLUSH request. These requests are typically associated with filesystem metadata updates. However, when a namespace is in device-dax mode, userspace (think database metadata) needs another path to perform the same flushing. In other words this is not required to make data persistent, but in the case of metadata it allows for a smaller failure domain in the unlikely event of an ADR failure. The new 'deep_flush' attribute is visible when the individual DIMMs backing a given interleave-set are described by platform firmware. In ACPI terms this is "NVDIMM Region Mapping Structures" and associated "Flush Hint Address Structures". Reads return "1" if the region supports triggering WPQ flushes on all DIMMs. Reads return "0" the flush operation is a platform nop, and in that case the attribute is read-only. Why sysfs and not an ioctl? An ioctl requires establishing a new ioctl function number space for device-dax. Given that this would be called on a device-dax fd an application could be forgiven for accidentally calling this on a filesystem-dax fd. Placing this interface in libnvdimm sysfs removes that potential for collision with a filesystem ioctl, and it keeps ioctls out of the generic device-dax implementation. Cc: Jeff Moyer <jmoyer@redhat.com> Cc: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 97681f9 commit ab63089

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

drivers/nvdimm/region_devs.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,35 @@ static ssize_t size_show(struct device *dev,
255255
}
256256
static DEVICE_ATTR_RO(size);
257257

258+
static ssize_t deep_flush_show(struct device *dev,
259+
struct device_attribute *attr, char *buf)
260+
{
261+
struct nd_region *nd_region = to_nd_region(dev);
262+
263+
/*
264+
* NOTE: in the nvdimm_has_flush() error case this attribute is
265+
* not visible.
266+
*/
267+
return sprintf(buf, "%d\n", nvdimm_has_flush(nd_region));
268+
}
269+
270+
static ssize_t deep_flush_store(struct device *dev, struct device_attribute *attr,
271+
const char *buf, size_t len)
272+
{
273+
bool flush;
274+
int rc = strtobool(buf, &flush);
275+
struct nd_region *nd_region = to_nd_region(dev);
276+
277+
if (rc)
278+
return rc;
279+
if (!flush)
280+
return -EINVAL;
281+
nvdimm_flush(nd_region);
282+
283+
return len;
284+
}
285+
static DEVICE_ATTR_RW(deep_flush);
286+
258287
static ssize_t mappings_show(struct device *dev,
259288
struct device_attribute *attr, char *buf)
260289
{
@@ -479,6 +508,7 @@ static struct attribute *nd_region_attributes[] = {
479508
&dev_attr_btt_seed.attr,
480509
&dev_attr_pfn_seed.attr,
481510
&dev_attr_dax_seed.attr,
511+
&dev_attr_deep_flush.attr,
482512
&dev_attr_read_only.attr,
483513
&dev_attr_set_cookie.attr,
484514
&dev_attr_available_size.attr,
@@ -508,6 +538,17 @@ static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n)
508538
if (!is_nd_pmem(dev) && a == &dev_attr_resource.attr)
509539
return 0;
510540

541+
if (a == &dev_attr_deep_flush.attr) {
542+
int has_flush = nvdimm_has_flush(nd_region);
543+
544+
if (has_flush == 1)
545+
return a->mode;
546+
else if (has_flush == 0)
547+
return 0444;
548+
else
549+
return 0;
550+
}
551+
511552
if (a != &dev_attr_set_cookie.attr
512553
&& a != &dev_attr_available_size.attr)
513554
return a->mode;

0 commit comments

Comments
 (0)