cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

blk.c (9277B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Implements pstore backend driver that write to block (or non-block) storage
      4 * devices, using the pstore/zone API.
      5 */
      6
      7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      8
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/blkdev.h>
     12#include <linux/string.h>
     13#include <linux/of.h>
     14#include <linux/of_address.h>
     15#include <linux/platform_device.h>
     16#include <linux/pstore_blk.h>
     17#include <linux/fs.h>
     18#include <linux/file.h>
     19#include <linux/init_syscalls.h>
     20#include <linux/mount.h>
     21
     22static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE;
     23module_param(kmsg_size, long, 0400);
     24MODULE_PARM_DESC(kmsg_size, "kmsg dump record size in kbytes");
     25
     26static int max_reason = CONFIG_PSTORE_BLK_MAX_REASON;
     27module_param(max_reason, int, 0400);
     28MODULE_PARM_DESC(max_reason,
     29		 "maximum reason for kmsg dump (default 2: Oops and Panic)");
     30
     31#if IS_ENABLED(CONFIG_PSTORE_PMSG)
     32static long pmsg_size = CONFIG_PSTORE_BLK_PMSG_SIZE;
     33#else
     34static long pmsg_size = -1;
     35#endif
     36module_param(pmsg_size, long, 0400);
     37MODULE_PARM_DESC(pmsg_size, "pmsg size in kbytes");
     38
     39#if IS_ENABLED(CONFIG_PSTORE_CONSOLE)
     40static long console_size = CONFIG_PSTORE_BLK_CONSOLE_SIZE;
     41#else
     42static long console_size = -1;
     43#endif
     44module_param(console_size, long, 0400);
     45MODULE_PARM_DESC(console_size, "console size in kbytes");
     46
     47#if IS_ENABLED(CONFIG_PSTORE_FTRACE)
     48static long ftrace_size = CONFIG_PSTORE_BLK_FTRACE_SIZE;
     49#else
     50static long ftrace_size = -1;
     51#endif
     52module_param(ftrace_size, long, 0400);
     53MODULE_PARM_DESC(ftrace_size, "ftrace size in kbytes");
     54
     55static bool best_effort;
     56module_param(best_effort, bool, 0400);
     57MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require storage driver pstore support, default: off)");
     58
     59/*
     60 * blkdev - the block device to use for pstore storage
     61 * See Documentation/admin-guide/pstore-blk.rst for details.
     62 */
     63static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV;
     64module_param_string(blkdev, blkdev, 80, 0400);
     65MODULE_PARM_DESC(blkdev, "block device for pstore storage");
     66
     67/*
     68 * All globals must only be accessed under the pstore_blk_lock
     69 * during the register/unregister functions.
     70 */
     71static DEFINE_MUTEX(pstore_blk_lock);
     72static struct file *psblk_file;
     73static struct pstore_device_info *pstore_device_info;
     74
     75#define check_size(name, alignsize) ({				\
     76	long _##name_ = (name);					\
     77	_##name_ = _##name_ <= 0 ? 0 : (_##name_ * 1024);	\
     78	if (_##name_ & ((alignsize) - 1)) {			\
     79		pr_info(#name " must align to %d\n",		\
     80				(alignsize));			\
     81		_##name_ = ALIGN(name, (alignsize));		\
     82	}							\
     83	_##name_;						\
     84})
     85
     86#define verify_size(name, alignsize, enabled) {			\
     87	long _##name_;						\
     88	if (enabled)						\
     89		_##name_ = check_size(name, alignsize);		\
     90	else							\
     91		_##name_ = 0;					\
     92	/* Synchronize module parameters with resuls. */	\
     93	name = _##name_ / 1024;					\
     94	dev->zone.name = _##name_;				\
     95}
     96
     97static int __register_pstore_device(struct pstore_device_info *dev)
     98{
     99	int ret;
    100
    101	lockdep_assert_held(&pstore_blk_lock);
    102
    103	if (!dev) {
    104		pr_err("NULL device info\n");
    105		return -EINVAL;
    106	}
    107	if (!dev->zone.total_size) {
    108		pr_err("zero sized device\n");
    109		return -EINVAL;
    110	}
    111	if (!dev->zone.read) {
    112		pr_err("no read handler for device\n");
    113		return -EINVAL;
    114	}
    115	if (!dev->zone.write) {
    116		pr_err("no write handler for device\n");
    117		return -EINVAL;
    118	}
    119
    120	/* someone already registered before */
    121	if (pstore_device_info)
    122		return -EBUSY;
    123
    124	/* zero means not limit on which backends to attempt to store. */
    125	if (!dev->flags)
    126		dev->flags = UINT_MAX;
    127
    128	/* Copy in module parameters. */
    129	verify_size(kmsg_size, 4096, dev->flags & PSTORE_FLAGS_DMESG);
    130	verify_size(pmsg_size, 4096, dev->flags & PSTORE_FLAGS_PMSG);
    131	verify_size(console_size, 4096, dev->flags & PSTORE_FLAGS_CONSOLE);
    132	verify_size(ftrace_size, 4096, dev->flags & PSTORE_FLAGS_FTRACE);
    133	dev->zone.max_reason = max_reason;
    134
    135	/* Initialize required zone ownership details. */
    136	dev->zone.name = KBUILD_MODNAME;
    137	dev->zone.owner = THIS_MODULE;
    138
    139	ret = register_pstore_zone(&dev->zone);
    140	if (ret == 0)
    141		pstore_device_info = dev;
    142
    143	return ret;
    144}
    145/**
    146 * register_pstore_device() - register non-block device to pstore/blk
    147 *
    148 * @dev: non-block device information
    149 *
    150 * Return:
    151 * * 0		- OK
    152 * * Others	- something error.
    153 */
    154int register_pstore_device(struct pstore_device_info *dev)
    155{
    156	int ret;
    157
    158	mutex_lock(&pstore_blk_lock);
    159	ret = __register_pstore_device(dev);
    160	mutex_unlock(&pstore_blk_lock);
    161
    162	return ret;
    163}
    164EXPORT_SYMBOL_GPL(register_pstore_device);
    165
    166static void __unregister_pstore_device(struct pstore_device_info *dev)
    167{
    168	lockdep_assert_held(&pstore_blk_lock);
    169	if (pstore_device_info && pstore_device_info == dev) {
    170		unregister_pstore_zone(&dev->zone);
    171		pstore_device_info = NULL;
    172	}
    173}
    174
    175/**
    176 * unregister_pstore_device() - unregister non-block device from pstore/blk
    177 *
    178 * @dev: non-block device information
    179 */
    180void unregister_pstore_device(struct pstore_device_info *dev)
    181{
    182	mutex_lock(&pstore_blk_lock);
    183	__unregister_pstore_device(dev);
    184	mutex_unlock(&pstore_blk_lock);
    185}
    186EXPORT_SYMBOL_GPL(unregister_pstore_device);
    187
    188static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos)
    189{
    190	return kernel_read(psblk_file, buf, bytes, &pos);
    191}
    192
    193static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes,
    194		loff_t pos)
    195{
    196	/* Console/Ftrace backend may handle buffer until flush dirty zones */
    197	if (in_interrupt() || irqs_disabled())
    198		return -EBUSY;
    199	return kernel_write(psblk_file, buf, bytes, &pos);
    200}
    201
    202/*
    203 * This takes its configuration only from the module parameters now.
    204 */
    205static int __register_pstore_blk(struct pstore_device_info *dev,
    206				 const char *devpath)
    207{
    208	int ret = -ENODEV;
    209
    210	lockdep_assert_held(&pstore_blk_lock);
    211
    212	psblk_file = filp_open(devpath, O_RDWR | O_DSYNC | O_NOATIME | O_EXCL, 0);
    213	if (IS_ERR(psblk_file)) {
    214		ret = PTR_ERR(psblk_file);
    215		pr_err("failed to open '%s': %d!\n", devpath, ret);
    216		goto err;
    217	}
    218
    219	if (!S_ISBLK(file_inode(psblk_file)->i_mode)) {
    220		pr_err("'%s' is not block device!\n", devpath);
    221		goto err_fput;
    222	}
    223
    224	dev->zone.total_size =
    225		bdev_nr_bytes(I_BDEV(psblk_file->f_mapping->host));
    226
    227	ret = __register_pstore_device(dev);
    228	if (ret)
    229		goto err_fput;
    230
    231	return 0;
    232
    233err_fput:
    234	fput(psblk_file);
    235err:
    236	psblk_file = NULL;
    237
    238	return ret;
    239}
    240
    241/* get information of pstore/blk */
    242int pstore_blk_get_config(struct pstore_blk_config *info)
    243{
    244	strncpy(info->device, blkdev, 80);
    245	info->max_reason = max_reason;
    246	info->kmsg_size = check_size(kmsg_size, 4096);
    247	info->pmsg_size = check_size(pmsg_size, 4096);
    248	info->ftrace_size = check_size(ftrace_size, 4096);
    249	info->console_size = check_size(console_size, 4096);
    250
    251	return 0;
    252}
    253EXPORT_SYMBOL_GPL(pstore_blk_get_config);
    254
    255
    256#ifndef MODULE
    257static const char devname[] = "/dev/pstore-blk";
    258static __init const char *early_boot_devpath(const char *initial_devname)
    259{
    260	/*
    261	 * During early boot the real root file system hasn't been
    262	 * mounted yet, and no device nodes are present yet. Use the
    263	 * same scheme to find the device that we use for mounting
    264	 * the root file system.
    265	 */
    266	dev_t dev = name_to_dev_t(initial_devname);
    267
    268	if (!dev) {
    269		pr_err("failed to resolve '%s'!\n", initial_devname);
    270		return initial_devname;
    271	}
    272
    273	init_unlink(devname);
    274	init_mknod(devname, S_IFBLK | 0600, new_encode_dev(dev));
    275
    276	return devname;
    277}
    278#else
    279static inline const char *early_boot_devpath(const char *initial_devname)
    280{
    281	return initial_devname;
    282}
    283#endif
    284
    285static int __init __best_effort_init(void)
    286{
    287	struct pstore_device_info *best_effort_dev;
    288	int ret;
    289
    290	/* No best-effort mode requested. */
    291	if (!best_effort)
    292		return 0;
    293
    294	/* Reject an empty blkdev. */
    295	if (!blkdev[0]) {
    296		pr_err("blkdev empty with best_effort=Y\n");
    297		return -EINVAL;
    298	}
    299
    300	best_effort_dev = kzalloc(sizeof(*best_effort_dev), GFP_KERNEL);
    301	if (!best_effort_dev)
    302		return -ENOMEM;
    303
    304	best_effort_dev->zone.read = psblk_generic_blk_read;
    305	best_effort_dev->zone.write = psblk_generic_blk_write;
    306
    307	ret = __register_pstore_blk(best_effort_dev,
    308				    early_boot_devpath(blkdev));
    309	if (ret)
    310		kfree(best_effort_dev);
    311	else
    312		pr_info("attached %s (%lu) (no dedicated panic_write!)\n",
    313			blkdev, best_effort_dev->zone.total_size);
    314
    315	return ret;
    316}
    317
    318static void __exit __best_effort_exit(void)
    319{
    320	/*
    321	 * Currently, the only user of psblk_file is best_effort, so
    322	 * we can assume that pstore_device_info is associated with it.
    323	 * Once there are "real" blk devices, there will need to be a
    324	 * dedicated pstore_blk_info, etc.
    325	 */
    326	if (psblk_file) {
    327		struct pstore_device_info *dev = pstore_device_info;
    328
    329		__unregister_pstore_device(dev);
    330		kfree(dev);
    331		fput(psblk_file);
    332		psblk_file = NULL;
    333	}
    334}
    335
    336static int __init pstore_blk_init(void)
    337{
    338	int ret;
    339
    340	mutex_lock(&pstore_blk_lock);
    341	ret = __best_effort_init();
    342	mutex_unlock(&pstore_blk_lock);
    343
    344	return ret;
    345}
    346late_initcall(pstore_blk_init);
    347
    348static void __exit pstore_blk_exit(void)
    349{
    350	mutex_lock(&pstore_blk_lock);
    351	__best_effort_exit();
    352	/* If we've been asked to unload, unregister any remaining device. */
    353	__unregister_pstore_device(pstore_device_info);
    354	mutex_unlock(&pstore_blk_lock);
    355}
    356module_exit(pstore_blk_exit);
    357
    358MODULE_LICENSE("GPL");
    359MODULE_AUTHOR("WeiXiong Liao <liaoweixiong@allwinnertech.com>");
    360MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
    361MODULE_DESCRIPTION("pstore backend for block devices");