diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 9798e21ebe9d7f51ab813bc0ef2b50fcaea96218..83e2349e13626dc7c2af0329cf766e550ffbd19f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3124,7 +3124,7 @@ recovery_tree_root:
 		goto fail_block_groups;
 	goto retry_root_backup;
 }
-ALLOW_ERROR_INJECTION(open_ctree);
+ALLOW_ERROR_INJECTION(open_ctree, ERRNO);
 
 static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
 {
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index ef847699031acc8c6fa12aada129e5f1ed066596..586bb06472bb2840df6f4e0a831c7bbfec28b1e5 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -333,7 +333,7 @@ static int io_ctl_init(struct btrfs_io_ctl *io_ctl, struct inode *inode,
 
 	return 0;
 }
-ALLOW_ERROR_INJECTION(io_ctl_init);
+ALLOW_ERROR_INJECTION(io_ctl_init, ERRNO);
 
 static void io_ctl_free(struct btrfs_io_ctl *io_ctl)
 {
diff --git a/include/asm-generic/error-injection.h b/include/asm-generic/error-injection.h
index 08352c9d9f9761d209bcd5a6fdd38ffe496d1c10..296c65442f001810923fd3c3dc028cb2ac558fb1 100644
--- a/include/asm-generic/error-injection.h
+++ b/include/asm-generic/error-injection.h
@@ -3,17 +3,32 @@
 #define _ASM_GENERIC_ERROR_INJECTION_H
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+enum {
+	EI_ETYPE_NONE,		/* Dummy value for undefined case */
+	EI_ETYPE_NULL,		/* Return NULL if failure */
+	EI_ETYPE_ERRNO,		/* Return -ERRNO if failure */
+	EI_ETYPE_ERRNO_NULL,	/* Return -ERRNO or NULL if failure */
+};
+
+struct error_injection_entry {
+	unsigned long	addr;
+	int		etype;
+};
+
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
 /*
  * Whitelist ganerating macro. Specify functions which can be
  * error-injectable using this macro.
  */
-#define ALLOW_ERROR_INJECTION(fname)					\
-static unsigned long __used						\
+#define ALLOW_ERROR_INJECTION(fname, _etype)				\
+static struct error_injection_entry __used				\
 	__attribute__((__section__("_error_injection_whitelist")))	\
-	_eil_addr_##fname = (unsigned long)fname;
+	_eil_addr_##fname = {						\
+		.addr = (unsigned long)fname,				\
+		.etype = EI_ETYPE_##_etype,				\
+	};
 #else
-#define ALLOW_ERROR_INJECTION(fname)
+#define ALLOW_ERROR_INJECTION(fname, _etype)
 #endif
 #endif
 
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index f2068cca520668c7638ad50a068daabe22fb6d29..ebe544e048cd2358025989a682f46eb7c44f2c54 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -137,7 +137,7 @@
 #endif
 
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
-#define ERROR_INJECT_WHITELIST()	. = ALIGN(8);			      \
+#define ERROR_INJECT_WHITELIST()	STRUCT_ALIGN();			      \
 			VMLINUX_SYMBOL(__start_error_injection_whitelist) = .;\
 			KEEP(*(_error_injection_whitelist))		      \
 			VMLINUX_SYMBOL(__stop_error_injection_whitelist) = .;
diff --git a/include/linux/error-injection.h b/include/linux/error-injection.h
index 130a67c50dac5b0f01168f3efccd67bbc54cf53a..280c61ecbf20552b3fa68a99150b55e52c524905 100644
--- a/include/linux/error-injection.h
+++ b/include/linux/error-injection.h
@@ -7,6 +7,7 @@
 #include <asm/error-injection.h>
 
 extern bool within_error_injection_list(unsigned long addr);
+extern int get_injectable_error_type(unsigned long addr);
 
 #else /* !CONFIG_FUNCTION_ERROR_INJECTION */
 
@@ -16,6 +17,11 @@ static inline bool within_error_injection_list(unsigned long addr)
 	return false;
 }
 
+static inline int get_injectable_error_type(unsigned long addr)
+{
+	return EI_ETYPE_NONE;
+}
+
 #endif
 
 #endif /* _LINUX_ERROR_INJECTION_H */
diff --git a/include/linux/module.h b/include/linux/module.h
index 792e51d83bdae0f8ff1c36577567f4f5139a14ee..9642d3116718bf7e8720cc3804d11c18d5a7f29b 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -19,6 +19,7 @@
 #include <linux/jump_label.h>
 #include <linux/export.h>
 #include <linux/rbtree_latch.h>
+#include <linux/error-injection.h>
 
 #include <linux/percpu.h>
 #include <asm/module.h>
@@ -477,8 +478,8 @@ struct module {
 #endif
 
 #ifdef CONFIG_FUNCTION_ERROR_INJECTION
+	struct error_injection_entry *ei_funcs;
 	unsigned int num_ei_funcs;
-	unsigned long *ei_funcs;
 #endif
 } ____cacheline_aligned __randomize_layout;
 #ifndef MODULE_ARCH_INIT
diff --git a/lib/error-inject.c b/lib/error-inject.c
index bccadcf3c981f8255e5f7b399c3720aae2c72958..c0d4600f489603f232b8229d428decc756e0b453 100644
--- a/lib/error-inject.c
+++ b/lib/error-inject.c
@@ -16,6 +16,7 @@ struct ei_entry {
 	struct list_head list;
 	unsigned long start_addr;
 	unsigned long end_addr;
+	int etype;
 	void *priv;
 };
 
@@ -35,6 +36,17 @@ bool within_error_injection_list(unsigned long addr)
 	return ret;
 }
 
+int get_injectable_error_type(unsigned long addr)
+{
+	struct ei_entry *ent;
+
+	list_for_each_entry(ent, &error_injection_list, list) {
+		if (addr >= ent->start_addr && addr < ent->end_addr)
+			return ent->etype;
+	}
+	return EI_ETYPE_NONE;
+}
+
 /*
  * Lookup and populate the error_injection_list.
  *
@@ -42,16 +54,17 @@ bool within_error_injection_list(unsigned long addr)
  * bpf_error_injection, so we need to populate the list of the symbols that have
  * been marked as safe for overriding.
  */
-static void populate_error_injection_list(unsigned long *start,
-					  unsigned long *end, void *priv)
+static void populate_error_injection_list(struct error_injection_entry *start,
+					  struct error_injection_entry *end,
+					  void *priv)
 {
-	unsigned long *iter;
+	struct error_injection_entry *iter;
 	struct ei_entry *ent;
 	unsigned long entry, offset = 0, size = 0;
 
 	mutex_lock(&ei_mutex);
 	for (iter = start; iter < end; iter++) {
-		entry = arch_deref_entry_point((void *)*iter);
+		entry = arch_deref_entry_point((void *)iter->addr);
 
 		if (!kernel_text_address(entry) ||
 		    !kallsyms_lookup_size_offset(entry, &size, &offset)) {
@@ -65,6 +78,7 @@ static void populate_error_injection_list(unsigned long *start,
 			break;
 		ent->start_addr = entry;
 		ent->end_addr = entry + size;
+		ent->etype = iter->etype;
 		ent->priv = priv;
 		INIT_LIST_HEAD(&ent->list);
 		list_add_tail(&ent->list, &error_injection_list);
@@ -73,8 +87,8 @@ static void populate_error_injection_list(unsigned long *start,
 }
 
 /* Markers of the _error_inject_whitelist section */
-extern unsigned long __start_error_injection_whitelist[];
-extern unsigned long __stop_error_injection_whitelist[];
+extern struct error_injection_entry __start_error_injection_whitelist[];
+extern struct error_injection_entry __stop_error_injection_whitelist[];
 
 static void __init populate_kernel_ei_list(void)
 {
@@ -157,11 +171,26 @@ static void *ei_seq_next(struct seq_file *m, void *v, loff_t *pos)
 	return seq_list_next(v, &error_injection_list, pos);
 }
 
+static const char *error_type_string(int etype)
+{
+	switch (etype) {
+	case EI_ETYPE_NULL:
+		return "NULL";
+	case EI_ETYPE_ERRNO:
+		return "ERRNO";
+	case EI_ETYPE_ERRNO_NULL:
+		return "ERRNO_NULL";
+	default:
+		return "(unknown)";
+	}
+}
+
 static int ei_seq_show(struct seq_file *m, void *v)
 {
 	struct ei_entry *ent = list_entry(v, struct ei_entry, list);
 
-	seq_printf(m, "%pf\n", (void *)ent->start_addr);
+	seq_printf(m, "%pf\t%s\n", (void *)ent->start_addr,
+		   error_type_string(ent->etype));
 	return 0;
 }