}
 EXPORT_SYMBOL_GPL(nvdimm_region_notify);
 
+struct clear_badblocks_context {
+       resource_size_t phys, cleared;
+};
+
+static int nvdimm_clear_badblocks_region(struct device *dev, void *data)
+{
+       struct clear_badblocks_context *ctx = data;
+       struct nd_region *nd_region;
+       resource_size_t ndr_end;
+       sector_t sector;
+
+       /* make sure device is a region */
+       if (!is_nd_pmem(dev))
+               return 0;
+
+       nd_region = to_nd_region(dev);
+       ndr_end = nd_region->ndr_start + nd_region->ndr_size - 1;
+
+       /* make sure we are in the region */
+       if (ctx->phys < nd_region->ndr_start
+                       || (ctx->phys + ctx->cleared) > ndr_end)
+               return 0;
+
+       sector = (ctx->phys - nd_region->ndr_start) / 512;
+       badblocks_clear(&nd_region->bb, sector, ctx->cleared / 512);
+
+       return 0;
+}
+
+static void nvdimm_clear_badblocks_regions(struct nvdimm_bus *nvdimm_bus,
+               phys_addr_t phys, u64 cleared)
+{
+       struct clear_badblocks_context ctx = {
+               .phys = phys,
+               .cleared = cleared,
+       };
+
+       device_for_each_child(&nvdimm_bus->dev, &ctx,
+                       nvdimm_clear_badblocks_region);
+}
+
+static void nvdimm_account_cleared_poison(struct nvdimm_bus *nvdimm_bus,
+               phys_addr_t phys, u64 cleared)
+{
+       if (cleared > 0)
+               nvdimm_forget_poison(nvdimm_bus, phys, cleared);
+
+       if (cleared > 0 && cleared / 512)
+               nvdimm_clear_badblocks_regions(nvdimm_bus, phys, cleared);
+}
+
 long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
                unsigned int len)
 {
        if (cmd_rc < 0)
                return cmd_rc;
 
-       if (clear_err.cleared > 0)
-               nvdimm_forget_poison(nvdimm_bus, phys, clear_err.cleared);
+       nvdimm_account_cleared_poison(nvdimm_bus, phys, clear_err.cleared);
 
        return clear_err.cleared;
 }
 EXPORT_SYMBOL_GPL(nvdimm_clear_poison);
 
-void __nvdimm_bus_badblocks_clear(struct nvdimm_bus *nvdimm_bus,
-               struct resource *res)
-{
-       lockdep_assert_held(&nvdimm_bus->reconfig_mutex);
-       device_for_each_child(&nvdimm_bus->dev, (void *)res,
-                       nvdimm_region_badblocks_clear);
-}
-EXPORT_SYMBOL_GPL(__nvdimm_bus_badblocks_clear);
-
 static int nvdimm_bus_match(struct device *dev, struct device_driver *drv);
 
 static struct bus_type nvdimm_bus_type = {
 
        if (!nvdimm && cmd == ND_CMD_CLEAR_ERROR && cmd_rc >= 0) {
                struct nd_cmd_clear_error *clear_err = buf;
-               struct resource res;
-
-               if (clear_err->cleared) {
-                       /* clearing the poison list we keep track of */
-                       nvdimm_forget_poison(nvdimm_bus, clear_err->address,
-                                       clear_err->cleared);
 
-                       /* now sync the badblocks lists */
-                       res.start = clear_err->address;
-                       res.end = clear_err->address + clear_err->cleared - 1;
-                       __nvdimm_bus_badblocks_clear(nvdimm_bus, &res);
-               }
+               nvdimm_account_cleared_poison(nvdimm_bus, clear_err->address,
+                               clear_err->cleared);
        }
        nvdimm_bus_unlock(&nvdimm_bus->dev);
 
 
        device_for_each_child(dev, &event, child_notify);
 }
 
-int nvdimm_region_badblocks_clear(struct device *dev, void *data)
-{
-       struct resource *res = (struct resource *)data;
-       struct nd_region *nd_region;
-       resource_size_t ndr_end;
-       sector_t sector;
-
-       /* make sure device is a region */
-       if (!is_nd_pmem(dev))
-               return 0;
-
-       nd_region = to_nd_region(dev);
-       ndr_end = nd_region->ndr_start + nd_region->ndr_size - 1;
-
-       /* make sure we are in the region */
-       if (res->start < nd_region->ndr_start || res->end > ndr_end)
-               return 0;
-
-       sector = (res->start - nd_region->ndr_start) >> 9;
-       badblocks_clear(&nd_region->bb, sector, resource_size(res) >> 9);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(nvdimm_region_badblocks_clear);
-
 static struct nd_device_driver nd_region_driver = {
        .probe = nd_region_probe,
        .remove = nd_region_remove,
 
 }
 static DEVICE_ATTR_RW(read_only);
 
-static ssize_t nd_badblocks_show(struct device *dev,
+static ssize_t region_badblocks_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct nd_region *nd_region = to_nd_region(dev);
 
        return badblocks_show(&nd_region->bb, buf, 0);
 }
-static struct device_attribute dev_attr_nd_badblocks = {
-       .attr = {
-               .name = "badblocks",
-               .mode = S_IRUGO
-       },
-       .show = nd_badblocks_show,
-};
+
+static DEVICE_ATTR(badblocks, 0444, region_badblocks_show, NULL);
 
 static ssize_t resource_show(struct device *dev,
                struct device_attribute *attr, char *buf)
        &dev_attr_available_size.attr,
        &dev_attr_namespace_seed.attr,
        &dev_attr_init_namespaces.attr,
-       &dev_attr_nd_badblocks.attr,
+       &dev_attr_badblocks.attr,
        &dev_attr_resource.attr,
        NULL,
 };
        if (!is_nd_pmem(dev) && a == &dev_attr_dax_seed.attr)
                return 0;
 
-       if (!is_nd_pmem(dev) && a == &dev_attr_nd_badblocks.attr)
+       if (!is_nd_pmem(dev) && a == &dev_attr_badblocks.attr)
                return 0;
 
        if (!is_nd_pmem(dev) && a == &dev_attr_resource.attr)