diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index fdf954c2107f..4eba6135394c 100644
--- a/drivers/misc/lkdtm.h
+++ b/drivers/misc/lkdtm.h
@@ -3,10 +3,49 @@
 
 #define pr_fmt(fmt) "lkdtm: " fmt
 
+#include <linux/fs.h>
 #include <linux/kernel.h>
 
+/*
+ * Handle the various atomic function prototypes (potentially ignoring
+ * return values).
+ */
+#define ATOMIC_ARG_X(func, x)		func(x)
+#define ATOMIC_ARG_1_X(func, x)		func(1, x)
+#define ATOMIC_RET_ARG_X(func, x)	if (func(x)) ;
+#define ATOMIC_RET_ARG_1_X(func, x)	if (func(1, x)) ;
+#define ATOMIC_RET_ARG_X_1_0(func, x)	if (func(x, 1, 0)) ;
+
+/* The list of all tested atomic operations. */
+#define LKDTM_ATOMIC_OPERATIONS(macro)					\
+	macro(UNDERFLOW, dec,		ATOMIC_ARG_X)			\
+	macro(UNDERFLOW, dec_return,	ATOMIC_RET_ARG_X)		\
+	macro(UNDERFLOW, sub,		ATOMIC_ARG_1_X)			\
+	macro(UNDERFLOW, sub_return,	ATOMIC_RET_ARG_1_X)		\
+	macro(UNDERFLOW, sub_and_test,	ATOMIC_RET_ARG_1_X)		\
+	macro(OVERFLOW,  inc,		ATOMIC_ARG_X)			\
+	macro(OVERFLOW,  inc_return,	ATOMIC_RET_ARG_X)		\
+	macro(OVERFLOW,  add,		ATOMIC_ARG_1_X)			\
+	macro(OVERFLOW,  add_return,	ATOMIC_RET_ARG_1_X)		\
+	macro(OVERFLOW,  add_unless,	ATOMIC_RET_ARG_X_1_0)		\
+	macro(OVERFLOW,  inc_and_test,	ATOMIC_RET_ARG_X)
+
+/* The list of all tested atomic types. */
+#define LKDTM_ATOMIC_TYPES(macro, name, operation)			\
+	macro(name,	atomic,		operation)			\
+	macro(name,	atomic_long,	operation)			\
+	macro(name,	local,		operation)			\
+	macro(name,	atomic64,	operation)
+
+/* Generate function prototypes for all atomic operation/type combinations. */
+#define LKDTM_ATOMIC_FUNCDECL(name, atomic_type, operation)		\
+	void lkdtm_##name##_##atomic_type##_##operation(void);
+
+#define LKDTM_ATOMIC_FUNCDECLS(name, operation, ignored)		\
+	LKDTM_ATOMIC_TYPES(LKDTM_ATOMIC_FUNCDECL, name, operation)
+
 /* lkdtm_bugs.c */
-void __init lkdtm_bugs_init(int *recur_param);
+void __init lkdtm_bugs_init(int *recur_param, struct dentry *parent);
 void lkdtm_PANIC(void);
 void lkdtm_BUG(void);
 void lkdtm_WARNING(void);
@@ -19,8 +58,7 @@ void lkdtm_SOFTLOCKUP(void);  void lkdtm_HARDLOCKUP(void);  void lkdtm_SPINLOCKUP(void);  void lkdtm_HUNG_TASK(void); -void lkdtm_ATOMIC_UNDERFLOW(void); -void lkdtm_ATOMIC_OVERFLOW(void);
+LKDTM_ATOMIC_OPERATIONS(LKDTM_ATOMIC_FUNCDECLS);
 
 /* lkdtm_heap.c */
 void lkdtm_OVERWRITE_ALLOCATION(void);
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c index 182ae1894b32..39cbd0effcf2 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm_bugs.c
@@ -5,7 +5,9 @@
  * test source files.
  */
 #include "lkdtm.h"
+#include <linux/debugfs.h>
 #include <linux/sched.h>
+#include <asm/local.h>
 
 /*
  * Make sure our attempts to over run the kernel stack doesn't trigger @@ -35,15 +37,6 @@ static int recursive_loop(int remaining)
 		return recursive_loop(remaining - 1);  }
 
-/* If the depth is negative, use the default, otherwise keep parameter. */ -void __init lkdtm_bugs_init(int *recur_param) -{
-	if (*recur_param < 0)
-		*recur_param = recur_count;
-	else
-		recur_count = *recur_param;
-}
-
 void lkdtm_PANIC(void)
 {
 	panic("dumptest");
@@ -123,26 +116,101 @@ void lkdtm_HUNG_TASK(void)
 	schedule();
 }
 
-void lkdtm_ATOMIC_UNDERFLOW(void)
-{
-	atomic_t under = ATOMIC_INIT(INT_MIN);
-
-	pr_info("attempting good atomic increment\n");
-	atomic_inc(&under);
-	atomic_dec(&under);
-
-	pr_info("attempting bad atomic underflow\n");
-	atomic_dec(&under);
-}
-
-void lkdtm_ATOMIC_OVERFLOW(void)
-{
-	atomic_t over = ATOMIC_INIT(INT_MAX);
-
-	pr_info("attempting good atomic decrement\n");
-	atomic_dec(&over);
-	atomic_inc(&over);
+#define GENERATE_LKDTM_ATOMIC_TYPE(ignore1, atomic_name, ignore2)	\
+									\
+static atomic_name##_t atomic_name##_var;				\
+									\
+static int debugfs_##atomic_name##_get(void *data, u64 *val)		\
+{									\
+	*val = atomic_name##_read((atomic_name##_t *)data);		\
+	return 0;							\
+}									\
+									\
+DEFINE_DEBUGFS_ATTRIBUTE(fops_##atomic_name,				\
+			 debugfs_##atomic_name##_get,			\
+			 NULL, "%lld\n");				\
+									\
+static struct dentry *debugfs_create_##atomic_name(const char *item,	\
+				umode_t mode,				\
+				struct dentry *parent,			\
+				atomic_name##_t *value)			\
+{									\
+	return debugfs_create_file_unsafe(item, mode, parent, value,	\
+					&fops_##atomic_name);		\
+}
+
+LKDTM_ATOMIC_TYPES(GENERATE_LKDTM_ATOMIC_TYPE, 0, 0)
+
+#define ATOMIC_TEST(name, atomic_name, init_func, start, safe_func,	\
+		    test_func_proto, testfunc)				\
+									\
+void lkdtm_##name##_##testfunc(void)					\
+{									\
+	atomic_name##_set(&atomic_name##_var, start);			\
+									\
+	pr_info("attempting good " #testfunc "\n");			\
+	safe_func(&atomic_name##_var);					\
+	test_func_proto(testfunc, &atomic_name##_var);			\
+									\
+	pr_info("attempting bad " #testfunc "\n");			\
+	test_func_proto(testfunc, &atomic_name##_var);			\
+}
+
+/* Declare underflow test functions for atomic_t and atomic_long_t types. */
+#define LKDTM_ATOMIC_UNDERFLOW(operation, test_func_proto)		\
+	ATOMIC_TEST(UNDERFLOW, atomic, ATOMIC_INIT, INT_MIN,		\
+		    atomic_inc, test_func_proto, atomic_##operation)	\
+	ATOMIC_TEST(UNDERFLOW, atomic_long, ATOMIC_LONG_INIT,		\
+		    LONG_MIN, atomic_long_inc, test_func_proto,		\
+		    atomic_long_##operation)				\
+	ATOMIC_TEST(UNDERFLOW, atomic64, ATOMIC64_INIT,			\
+		    S64_MIN, atomic64_inc, test_func_proto,		\
+		    atomic64_##operation)				\
+	ATOMIC_TEST(UNDERFLOW, local, LOCAL_INIT,			\
+		    LONG_MIN, local_inc, test_func_proto,		\
+		    local_##operation)
+
+/* Declare overflow test functions for atomic_t and atomic_long_t types. */
+#define LKDTM_ATOMIC_OVERFLOW(operation, test_func_proto)		\
+	ATOMIC_TEST(OVERFLOW, atomic, ATOMIC_INIT, INT_MAX,		\
+		    atomic_dec, test_func_proto, atomic_##operation)	\
+	ATOMIC_TEST(OVERFLOW, atomic_long, ATOMIC_LONG_INIT,		\
+		    LONG_MAX, atomic_long_dec, test_func_proto,		\
+		    atomic_long_##operation)				\
+	ATOMIC_TEST(OVERFLOW, atomic64, ATOMIC64_INIT,			\
+		    S64_MAX, atomic64_dec, test_func_proto,		\
+		    atomic64_##operation)				\
+	ATOMIC_TEST(OVERFLOW, local, LOCAL_INIT,			\
+		    LONG_MAX, local_dec, test_func_proto,		\
+		    local_##operation)
+
+#define GENERATE_LKDTM_ATOMIC_TEST(name, operation, test_func_proto)	\
+	LKDTM_ATOMIC_##name(operation, test_func_proto)
+
+LKDTM_ATOMIC_OPERATIONS(GENERATE_LKDTM_ATOMIC_TEST)
+
+#define GENERATE_LKDTM_ATOMIC_DEBUGFS(ignore1, atomic_name, ignore2)	\
+	de = debugfs_create_##atomic_name(#atomic_name, 0644,		\
+					  atomic_dir,			\
+					  &atomic_name##_var);		\
+	if (de == NULL)							\
+		pr_err("could not create " #atomic_name " in debugfs\n");
+
+void __init lkdtm_bugs_init(int *recur_param, struct dentry *parent) {
+	struct dentry *atomic_dir, *de;
+
+	/* If the depth is negative, use default, otherwise keep parameter. */
+	if (*recur_param < 0)
+		*recur_param = recur_count;
+	else
+		recur_count = *recur_param;
 
-	pr_info("attempting bad atomic overflow\n");
-	atomic_inc(&over);
+	/* Don't treat failures to create the atomic value tree as fatal. */
+	atomic_dir = debugfs_create_dir("atomic", parent);
+	if (atomic_dir) {
+		LKDTM_ATOMIC_TYPES(GENERATE_LKDTM_ATOMIC_DEBUGFS, 0, 0);
+	} else {
+		pr_err("creating atomic dir failed\n");
+	}
 }
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index f9154b8d67f6..defa1af01e52 100644
--- a/drivers/misc/lkdtm_core.c
+++ b/drivers/misc/lkdtm_core.c
@@ -189,6 +189,13 @@ struct crashtype {
 		.func = lkdtm_ ## _name,	\
 	}
 
+/* Generate crashtype entries for all atomic operation/type combinations. */
+#define CRASHTYPE_ATOMIC(name, atomic_name, operation)		\
+	CRASHTYPE(name##_##atomic_name##_##operation),		\
+
+#define CRASHTYPE_ATOMICS(name, operation, ignored)		\
+	LKDTM_ATOMIC_TYPES(CRASHTYPE_ATOMIC, name, operation)
+
 /* Define the possible types of crashes that can be triggered. */  struct crashtype crashtypes[] = {
 	CRASHTYPE(PANIC),
@@ -218,8 +225,6 @@ struct crashtype crashtypes[] = {
