Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

+49 -15
+36 -14
block/badblocks.c
··· 17 17 18 18 #include <linux/badblocks.h> 19 19 #include <linux/seqlock.h> 20 + #include <linux/device.h> 20 21 #include <linux/kernel.h> 21 22 #include <linux/module.h> 22 23 #include <linux/stddef.h> ··· 523 522 } 524 523 EXPORT_SYMBOL_GPL(badblocks_store); 525 524 525 + static int __badblocks_init(struct device *dev, struct badblocks *bb, 526 + int enable) 527 + { 528 + bb->dev = dev; 529 + bb->count = 0; 530 + if (enable) 531 + bb->shift = 0; 532 + else 533 + bb->shift = -1; 534 + if (dev) 535 + bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL); 536 + else 537 + bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL); 538 + if (!bb->page) { 539 + bb->shift = -1; 540 + return -ENOMEM; 541 + } 542 + seqlock_init(&bb->lock); 543 + 544 + return 0; 545 + } 546 + 526 547 /** 527 548 * badblocks_init() - initialize the badblocks structure 528 549 * @bb: the badblocks structure that holds all badblock information ··· 556 533 */ 557 534 int badblocks_init(struct badblocks *bb, int enable) 558 535 { 559 - bb->count = 0; 560 - if (enable) 561 - bb->shift = 0; 562 - else 563 - bb->shift = -1; 564 - bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL); 565 - if (bb->page == (u64 *)0) { 566 - bb->shift = -1; 567 - return -ENOMEM; 568 - } 569 - seqlock_init(&bb->lock); 570 - 571 - return 0; 536 + return __badblocks_init(NULL, bb, enable); 572 537 } 573 538 EXPORT_SYMBOL_GPL(badblocks_init); 539 + 540 + int devm_init_badblocks(struct device *dev, struct badblocks *bb) 541 + { 542 + if (!bb) 543 + return -EINVAL; 544 + return __badblocks_init(dev, bb, 1); 545 + } 546 + EXPORT_SYMBOL_GPL(devm_init_badblocks); 574 547 575 548 /** 576 549 * badblocks_exit() - free the badblocks structure ··· 576 557 { 577 558 if (!bb) 578 559 return; 579 - kfree(bb->page); 560 + if (bb->dev) 561 + devm_kfree(bb->dev, bb->page); 562 + else 563 + kfree(bb->page); 580 564 bb->page = NULL; 581 565 } 582 566 EXPORT_SYMBOL_GPL(badblocks_exit);
+13 -1
include/linux/badblocks.h
··· 2 2 #define _LINUX_BADBLOCKS_H 3 3 4 4 #include <linux/seqlock.h> 5 + #include <linux/device.h> 5 6 #include <linux/kernel.h> 6 7 #include <linux/stddef.h> 7 8 #include <linux/types.h> ··· 24 23 #define MAX_BADBLOCKS (PAGE_SIZE/8) 25 24 26 25 struct badblocks { 26 + struct device *dev; /* set by devm_init_badblocks */ 27 27 int count; /* count of bad blocks */ 28 28 int unacked_exist; /* there probably are unacknowledged 29 29 * bad blocks. This is only cleared ··· 51 49 int unack); 52 50 int badblocks_init(struct badblocks *bb, int enable); 53 51 void badblocks_exit(struct badblocks *bb); 54 - 52 + struct device; 53 + int devm_init_badblocks(struct device *dev, struct badblocks *bb); 54 + static inline void devm_exit_badblocks(struct device *dev, struct badblocks *bb) 55 + { 56 + if (bb->dev != dev) { 57 + dev_WARN_ONCE(dev, 1, "%s: badblocks instance not associated\n", 58 + __func__); 59 + return; 60 + } 61 + badblocks_exit(bb); 62 + } 55 63 #endif