diff -drupN a/fs/pstore/blkoops.c b/fs/pstore/blkoops.c --- a/fs/pstore/blkoops.c 1970-01-01 03:00:00.000000000 +0300 +++ b/fs/pstore/blkoops.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * + * blkoops.c: Block device Oops logger + * + * Copyright (C) 2019 liaoweixiong + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#define MODNAME "blkoops" +#define pr_fmt(fmt) MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +static long dmesg_size = -1; +module_param(dmesg_size, long, 0400); +MODULE_PARM_DESC(dmesg_size, "demsg size in kbytes"); + +static long pmsg_size = -1; +module_param(pmsg_size, long, 0400); +MODULE_PARM_DESC(pmsg_size, "pmsg size in kbytes"); + +static long total_size = -1; +module_param(total_size, long, 0400); +MODULE_PARM_DESC(total_size, "total size in kbytes"); + +static int dump_oom = -1; +module_param(dump_oom, int, 0400); +MODULE_PARM_DESC(total_size, "whether dump oom"); + +static int dump_oops = -1; +module_param(dump_oops, int, 0400); +MODULE_PARM_DESC(total_size, "whether dump oops"); + +#define BLKDEV_INVALID "INVALID" +static char blkdev[80] = {BLKDEV_INVALID}; +module_param_string(blkdev, blkdev, 80, 0400); +MODULE_PARM_DESC(blkdev, "the block device for general read/write"); + +struct blkz_info blkz_info = { + .owner = THIS_MODULE, + .name = "blkoops", +}; + +struct blkoops_info { + unsigned long dmesg_size; + unsigned long pmsg_size; + unsigned long total_size; + int dump_oops; + int dump_oom; + const char *blkdev; +}; +struct blkoops_info blkoops_info = { + .dmesg_size = CONFIG_PSTORE_BLKOOPS_DMESG_SIZE * 1024, + .pmsg_size = CONFIG_PSTORE_BLKOOPS_PMSG_SIZE * 1024, + .total_size = CONFIG_PSTORE_BLKOOPS_TOTAL_SIZE * 1024, + .blkdev = CONFIG_PSTORE_BLKOOPS_BLKDEV, +#if IS_ENABLED(CONFIG_PSTORE_BLKOOPS_DUMP_OOPS) + .dump_oops = CONFIG_PSTORE_BLKOOPS_DUMP_OOPS, +#endif +#if IS_ENABLED(CONFIG_PSTORE_BLKOOPS_DUMP_OOM) + .dump_oom = CONFIG_PSTORE_BLKOOPS_DUMP_OOM, +#endif +}; + +static struct platform_device *dummy; +DEFINE_SPINLOCK(modify_blkzinfo); + +/** + * Block driver use this function to add panic read/write apis to blkoops. + * By this, block driver can do the least work that just provides panic ops. + */ +int blkoops_add_panic_ops(blkz_read_op panic_read, blkz_write_op panic_write) +{ + struct blkz_info *info = &blkz_info; + + spin_lock(&modify_blkzinfo); + if (info->panic_read || info->panic_write) { + spin_unlock(&modify_blkzinfo); + return -EBUSY; + } + + info->panic_read = panic_read; + info->panic_write = panic_write; + + spin_unlock(&modify_blkzinfo); + return 0; +} +EXPORT_SYMBOL_GPL(blkoops_add_panic_ops); + +static int blkoops_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct blkoops_info *info = dev->platform_data; + + if (info->blkdev[0] == '\0' || !strcmp(info->blkdev, BLKDEV_INVALID)) { + pr_info("no block device, use ram buffer only\n"); + } else { + pr_debug("block device: %s\n", info->blkdev); + blkz_info.blkdev = info->blkdev; + } + + blkz_info.dump_oom = !!info->dump_oom; + blkz_info.dump_oops = !!info->dump_oops; +#define check_size(name, size) { \ + if (info->name & (size - 1)) { \ + pr_err(#name " must be a multiple of %d\n", \ + (size)); \ + return -EINVAL; \ + } \ + blkz_info.name = info->name; \ + } + + check_size(total_size, 4096); + check_size(dmesg_size, 4096); + check_size(pmsg_size, 4096); + +#undef check_size + + /* + * Update the module parameter variables as well so they are visible + * through /sys/module/blkoops/parameters/ + */ + dmesg_size = blkz_info.dmesg_size; + pmsg_size = blkz_info.pmsg_size; + total_size = blkz_info.total_size; + dump_oops = blkz_info.dump_oops; + dump_oom = blkz_info.dump_oom; + if (blkz_info.blkdev) + strncpy(blkdev, blkz_info.blkdev, 80 - 1); + else + blkdev[0] = '\0'; + return blkz_register(&blkz_info); +} + +static int blkoops_remove(struct platform_device *pdev) +{ + blkz_unregister(&blkz_info); + return 0; +} + +static const struct of_device_id dt_match[] = { + { .compatible = MODNAME}, + {} +}; + +static struct platform_driver blkoops_driver = { + .probe = blkoops_probe, + .remove = blkoops_remove, + .driver = { + .name = MODNAME, + .of_match_table = dt_match, + }, +}; + +void blkoops_register_dummy(void) +{ + struct blkoops_info *info = &blkoops_info; + + /* + * Prepare a dummy platform data structure to carry the module + * parameters or kconfig value. + */ + if (total_size > 0 || strcmp(blkdev, BLKDEV_INVALID)) { + pr_info("using module parameters\n"); + if (total_size >= 0) + info->total_size = (unsigned long)total_size * 1024; + if (strcmp(blkdev, BLKDEV_INVALID)) + info->blkdev = (const char *)blkdev; + if (dmesg_size >= 0) + info->dmesg_size = (unsigned long)dmesg_size * 1024; + if (pmsg_size >= 0) + info->pmsg_size = (unsigned long)pmsg_size * 1024; + if (dump_oops >= 0) + info->dump_oops = dump_oops; + if (dump_oom >= 0) + info->dump_oops = dump_oom; + } else if (info->total_size > 0 || strlen(info->blkdev)) { + pr_info("using kconfig value\n"); + } else { + return; + } + + dummy = platform_device_register_data(NULL, MODNAME, -1, info, + sizeof(*info)); + if (IS_ERR(dummy)) { + pr_err("could not create platform device: %ld\n", + PTR_ERR(dummy)); + dummy = NULL; + } +} + +static int __init blkoops_init(void) +{ + int ret; + + blkoops_register_dummy(); + ret = platform_driver_register(&blkoops_driver); + if (ret != 0) { + platform_device_unregister(dummy); + dummy = NULL; + } + return ret; +} +late_initcall(blkoops_init); + +static void __exit blkoops_exit(void) +{ + platform_driver_unregister(&blkoops_driver); + platform_device_unregister(dummy); + dummy = NULL; +} +module_exit(blkoops_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("liaoweixiong "); +MODULE_DESCRIPTION("Sample for Pstore BLK with Oops logger");