forked from Minki/linux
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: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
20a308f09e
commit
16263ff6c7
@ -17,6 +17,7 @@
|
||||
|
||||
#include <linux/badblocks.h>
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/stddef.h>
|
||||
@ -522,6 +523,28 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(badblocks_store);
|
||||
|
||||
static int __badblocks_init(struct device *dev, struct badblocks *bb,
|
||||
int enable)
|
||||
{
|
||||
bb->dev = dev;
|
||||
bb->count = 0;
|
||||
if (enable)
|
||||
bb->shift = 0;
|
||||
else
|
||||
bb->shift = -1;
|
||||
if (dev)
|
||||
bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL);
|
||||
else
|
||||
bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!bb->page) {
|
||||
bb->shift = -1;
|
||||
return -ENOMEM;
|
||||
}
|
||||
seqlock_init(&bb->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* badblocks_init() - initialize the badblocks structure
|
||||
* @bb: the badblocks structure that holds all badblock information
|
||||
@ -533,22 +556,18 @@ EXPORT_SYMBOL_GPL(badblocks_store);
|
||||
*/
|
||||
int badblocks_init(struct badblocks *bb, int enable)
|
||||
{
|
||||
bb->count = 0;
|
||||
if (enable)
|
||||
bb->shift = 0;
|
||||
else
|
||||
bb->shift = -1;
|
||||
bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (bb->page == (u64 *)0) {
|
||||
bb->shift = -1;
|
||||
return -ENOMEM;
|
||||
}
|
||||
seqlock_init(&bb->lock);
|
||||
|
||||
return 0;
|
||||
return __badblocks_init(NULL, bb, enable);
|
||||
}
|
||||
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
|
||||
* @bb: the badblocks structure that holds all badblock information
|
||||
@ -557,6 +576,9 @@ void badblocks_exit(struct badblocks *bb)
|
||||
{
|
||||
if (!bb)
|
||||
return;
|
||||
if (bb->dev)
|
||||
devm_kfree(bb->dev, bb->page);
|
||||
else
|
||||
kfree(bb->page);
|
||||
bb->page = NULL;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define _LINUX_BADBLOCKS_H
|
||||
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
@ -23,6 +24,7 @@
|
||||
#define MAX_BADBLOCKS (PAGE_SIZE/8)
|
||||
|
||||
struct badblocks {
|
||||
struct device *dev; /* set by devm_init_badblocks */
|
||||
int count; /* count of bad blocks */
|
||||
int unacked_exist; /* there probably are unacknowledged
|
||||
* bad blocks. This is only cleared
|
||||
@ -49,5 +51,15 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
|
||||
int unack);
|
||||
int badblocks_init(struct badblocks *bb, int enable);
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user