HWPOISON: Add soft page offline support
[linux-2.6-block.git] / drivers / base / memory.c
index 989429cfed88a7395f38a4d1dd44d8d8ff8745ac..c4c8f2e1dd15d3afdd8261fe325c09a64d379d39 100644 (file)
@@ -341,6 +341,64 @@ static inline int memory_probe_init(void)
 }
 #endif
 
+#ifdef CONFIG_MEMORY_FAILURE
+/*
+ * Support for offlining pages of memory
+ */
+
+/* Soft offline a page */
+static ssize_t
+store_soft_offline_page(struct class *class, const char *buf, size_t count)
+{
+       int ret;
+       u64 pfn;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (strict_strtoull(buf, 0, &pfn) < 0)
+               return -EINVAL;
+       pfn >>= PAGE_SHIFT;
+       if (!pfn_valid(pfn))
+               return -ENXIO;
+       ret = soft_offline_page(pfn_to_page(pfn), 0);
+       return ret == 0 ? count : ret;
+}
+
+/* Forcibly offline a page, including killing processes. */
+static ssize_t
+store_hard_offline_page(struct class *class, const char *buf, size_t count)
+{
+       int ret;
+       u64 pfn;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (strict_strtoull(buf, 0, &pfn) < 0)
+               return -EINVAL;
+       pfn >>= PAGE_SHIFT;
+       ret = __memory_failure(pfn, 0, 0);
+       return ret ? ret : count;
+}
+
+static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page);
+static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page);
+
+static __init int memory_fail_init(void)
+{
+       int err;
+
+       err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
+                               &class_attr_soft_offline_page.attr);
+       if (!err)
+               err = sysfs_create_file(&memory_sysdev_class.kset.kobj,
+                               &class_attr_hard_offline_page.attr);
+       return err;
+}
+#else
+static inline int memory_fail_init(void)
+{
+       return 0;
+}
+#endif
+
 /*
  * Note that phys_device is optional.  It is here to allow for
  * differentiation between which *physical* devices each
@@ -471,6 +529,9 @@ int __init memory_dev_init(void)
        }
 
        err = memory_probe_init();
+       if (!ret)
+               ret = err;
+       err = memory_fail_init();
        if (!ret)
                ret = err;
        err = block_size_init();