diff --git a/.gitignore b/.gitignore
index 1016b3b..1601738 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@ daxctl/lib/libdaxctl.pc
 *.a
 ndctl/lib/libndctl.pc
 ndctl/ndctl
+ndctl/latch-shutdown
 rhel/
 sles/ndctl.spec
 util/log.lo
diff --git a/Makefile.am b/Makefile.am
index e0c463a..9d3913e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -42,6 +42,9 @@ bashcompletiondir = $(BASH_COMPLETION_DIR)
 dist_bashcompletion_DATA = contrib/ndctl
 endif
 
+udevrulesdir = $(UDEVDIR)/rules.d
+dist_udevrules_DATA = contrib/80-intel-pmem.rules
+
 noinst_LIBRARIES = libccan.a
 libccan_a_SOURCES = \
 	ccan/str/str.h \
diff --git a/configure.ac b/configure.ac
index cf44260..15f336b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -143,7 +143,16 @@ AC_CHECK_FUNCS([ \
 	secure_getenv\
 ])
 
+AC_ARG_WITH([tmpfsdir],
+  [AS_HELP_STRING([--with-tmpfsdir=DIR], [Directory for temporary runtime files])],
+  [tmpfsdir=$withval],
+  [tmpfsdir="/run"])
+
+UDEVDIR="$(pkg-config udev --variable=udevdir)"
+AC_SUBST([UDEVDIR])
+
 my_CFLAGS="\
+-D DEF_TMPFS_DIR='\"${tmpfsdir}/ndctl\"' \
 -Wall \
 -Wchar-subscripts \
 -Wformat-security \
@@ -182,6 +191,7 @@ AC_MSG_RESULT([
 
         prefix:                 ${prefix}
         sysconfdir:             ${sysconfdir}
+        tmpfsdir:               ${tmpfsdir}
         libdir:                 ${libdir}
         includedir:             ${includedir}
 
diff --git a/contrib/80-intel-pmem.rules b/contrib/80-intel-pmem.rules
new file mode 100644
index 0000000..20fcef9
--- /dev/null
+++ b/contrib/80-intel-pmem.rules
@@ -0,0 +1 @@
+ACTION=="add", KERNEL=="nmem*", RUN+="latch-shutdown $kernel"
diff --git a/ndctl.spec.in b/ndctl.spec.in
index e2c879c..25edf7e 100644
--- a/ndctl.spec.in
+++ b/ndctl.spec.in
@@ -90,7 +90,7 @@ control API for these devices.
 %build
 echo %{version} > version
 ./autogen.sh
-%configure --disable-static --disable-silent-rules
+%configure --disable-static --disable-silent-rules --with-tmpfsdir=%{_tmpfilesdir}
 make %{?_smp_mflags}
 
 %install
@@ -109,6 +109,7 @@ make check
 %postun -n DAX_LNAME -p /sbin/ldconfig
 
 %define bashcompdir %(pkg-config --variable=completionsdir bash-completion)
+%define udevdir  %(pkg-config --variable=udevdir udev)
 
 %files
 %defattr(-,root,root)
@@ -116,6 +117,8 @@ make check
 %{_bindir}/ndctl
 %{_mandir}/man1/ndctl*
 %{bashcompdir}/
+%{_udevrulesdir}/80-intel-pmem.rules
+%{udevdir}/latch-shutdown
 
 %files -n daxctl
 %defattr(-,root,root)
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 0f56871..155179b 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -41,3 +41,8 @@ ndctl_SOURCES += ../test/libndctl.c \
 		 ../test/core.c \
 		 test.c
 endif
+
+latch_shutdowndir = $(UDEVDIR)
+latch_shutdown_PROGRAMS = latch-shutdown
+latch_shutdown_SOURCES = latch-shutdown.c
+latch_shutdown_LDADD = lib/libndctl.la
diff --git a/ndctl/latch-shutdown.c b/ndctl/latch-shutdown.c
new file mode 100644
index 0000000..704fb8f
--- /dev/null
+++ b/ndctl/latch-shutdown.c
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018 Intel Corporation. All rights reserved. */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <ndctl/libndctl.h>
+
+/**
+ * mkdir_p
+ *
+ * Copied from util-linux lib/fileutils.c
+ */
+static int mkdir_p(const char *path, mode_t mode)
+{
+	char *p, *dir;
+	int rc = 0;
+
+	if (!path || !*path)
+		return -EINVAL;
+
+	dir = p = strdup(path);
+	if (!dir)
+		return -ENOMEM;
+
+	if (*p == '/')
+		p++;
+
+	while (p && *p) {
+		char *e = strchr(p, '/');
+		if (e)
+			*e = '\0';
+		if (*p) {
+			rc = mkdir(dir, mode);
+			if (rc && errno != EEXIST)
+				break;
+			rc = 0;
+		}
+		if (!e)
+			break;
+		*e = '/';
+		p = e + 1;
+	}
+
+	free(dir);
+	return rc;
+}
+
+static struct ndctl_dimm *find_dimm(struct ndctl_ctx *ctx, char *devname)
+{
+	struct ndctl_bus *bus;
+	struct ndctl_dimm *dimm;
+
+	ndctl_bus_foreach(ctx, bus) {
+		ndctl_dimm_foreach(bus, dimm) {
+			if (strcmp(ndctl_dimm_get_devname(dimm), devname) == 0)
+				return dimm;
+		}
+	}
+	return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+	struct ndctl_ctx *ctx;
+	struct ndctl_cmd *cmd;
+	struct ndctl_dimm *dimm = NULL;
+	char *path, *usc, count[16];
+	const char *id;
+	unsigned int shutdown;
+	int rc, fd;
+
+	if (argc < 2)
+		return EINVAL;
+
+	rc = ndctl_new(&ctx);
+	if (rc)
+		return ENOMEM;
+
+	dimm = find_dimm(ctx, argv[1]);
+	if (!dimm)
+		return ENODEV;
+
+	cmd = ndctl_dimm_cmd_new_ack_shutdown_count(dimm);
+	if (!cmd)
+		return ENOMEM;
+
+	rc = ndctl_cmd_submit(cmd);
+	if (rc)
+		return rc;
+	ndctl_cmd_unref(cmd);
+
+	id = ndctl_dimm_get_unique_id(dimm);
+	if (!id)
+		return ENXIO;
+
+	cmd = ndctl_dimm_cmd_new_smart(dimm);
+	if (!cmd)
+		return ENOMEM;
+
+	rc = ndctl_cmd_submit(cmd);
+	if (rc)
+		return rc;
+
+	shutdown = ndctl_cmd_smart_get_shutdown_count(cmd);
+	ndctl_cmd_unref(cmd);
+
+	rc = asprintf(&path, DEF_TMPFS_DIR "/%s", id);
+	if (rc < 0)
+		return ENOMEM;
+	ndctl_unref(ctx);
+
+	rc = mkdir_p(path, 0755);
+	if (rc)
+		return rc;
+
+	rc = asprintf(&usc, "%s/usc", path);
+	if (rc < 0)
+		return ENOMEM;
+	free(path);
+
+	fd = open(usc, O_WRONLY | O_CREAT, 0644);
+	if (!fd)
+		return errno;
+	free(usc);
+
+	rc = snprintf(count, sizeof(count), "%u\n", shutdown);
+	if (rc < 0)
+		return rc;
+
+	if (write(fd, count, strlen(count)))
+		return errno;
+	return 0;
+}
