Commit 16263ff6 authored by Dan Williams's avatar Dan Williams

block, badblocks: introduce devm_init_badblocks

Provide a devres interface for initializing a badblocks instance.  The
pmem driver has several scenarios where it will be beneficial to have
this structure automatically freed when the device is disabled / fails
probe.
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 20a308f0
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/badblocks.h> #include <linux/badblocks.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
#include <linux/device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/stddef.h> #include <linux/stddef.h>
...@@ -522,24 +523,20 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len, ...@@ -522,24 +523,20 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
} }
EXPORT_SYMBOL_GPL(badblocks_store); EXPORT_SYMBOL_GPL(badblocks_store);
/** static int __badblocks_init(struct device *dev, struct badblocks *bb,
* badblocks_init() - initialize the badblocks structure int enable)
* @bb: the badblocks structure that holds all badblock information
* @enable: weather to enable badblocks accounting
*
* Return:
* 0: success
* -ve errno: on error
*/
int badblocks_init(struct badblocks *bb, int enable)
{ {
bb->dev = dev;
bb->count = 0; bb->count = 0;
if (enable) if (enable)
bb->shift = 0; bb->shift = 0;
else else
bb->shift = -1; bb->shift = -1;
bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL); if (dev)
if (bb->page == (u64 *)0) { bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
else
bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!bb->page) {
bb->shift = -1; bb->shift = -1;
return -ENOMEM; return -ENOMEM;
} }
...@@ -547,8 +544,30 @@ int badblocks_init(struct badblocks *bb, int enable) ...@@ -547,8 +544,30 @@ int badblocks_init(struct badblocks *bb, int enable)
return 0; return 0;
} }
/**
* badblocks_init() - initialize the badblocks structure
* @bb: the badblocks structure that holds all badblock information
* @enable: weather to enable badblocks accounting
*
* Return:
* 0: success
* -ve errno: on error
*/
int badblocks_init(struct badblocks *bb, int enable)
{
return __badblocks_init(NULL, bb, enable);
}
EXPORT_SYMBOL_GPL(badblocks_init); EXPORT_SYMBOL_GPL(badblocks_init);
int devm_init_badblocks(struct device *dev, struct badblocks *bb)
{
if (!bb)
return -EINVAL;
return __badblocks_init(dev, bb, 1);
}
EXPORT_SYMBOL_GPL(devm_init_badblocks);
/** /**
* badblocks_exit() - free the badblocks structure * badblocks_exit() - free the badblocks structure
* @bb: the badblocks structure that holds all badblock information * @bb: the badblocks structure that holds all badblock information
...@@ -557,7 +576,10 @@ void badblocks_exit(struct badblocks *bb) ...@@ -557,7 +576,10 @@ void badblocks_exit(struct badblocks *bb)
{ {
if (!bb) if (!bb)
return; return;
kfree(bb->page); if (bb->dev)
devm_kfree(bb->dev, bb->page);
else
kfree(bb->page);
bb->page = NULL; bb->page = NULL;
} }
EXPORT_SYMBOL_GPL(badblocks_exit); EXPORT_SYMBOL_GPL(badblocks_exit);
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _LINUX_BADBLOCKS_H #define _LINUX_BADBLOCKS_H
#include <linux/seqlock.h> #include <linux/seqlock.h>
#include <linux/device.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#define MAX_BADBLOCKS (PAGE_SIZE/8) #define MAX_BADBLOCKS (PAGE_SIZE/8)
struct badblocks { struct badblocks {
struct device *dev; /* set by devm_init_badblocks */
int count; /* count of bad blocks */ int count; /* count of bad blocks */
int unacked_exist; /* there probably are unacknowledged int unacked_exist; /* there probably are unacknowledged
* bad blocks. This is only cleared * bad blocks. This is only cleared
...@@ -49,5 +51,15 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len, ...@@ -49,5 +51,15 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
int unack); int unack);
int badblocks_init(struct badblocks *bb, int enable); int badblocks_init(struct badblocks *bb, int enable);
void badblocks_exit(struct badblocks *bb); void badblocks_exit(struct badblocks *bb);
struct device;
int devm_init_badblocks(struct device *dev, struct badblocks *bb);
static inline void devm_exit_badblocks(struct device *dev, struct badblocks *bb)
{
if (bb->dev != dev) {
dev_WARN_ONCE(dev, 1, "%s: badblocks instance not associated\n",
__func__);
return;
}
badblocks_exit(bb);
}
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment