linux/fs/pstore/blk.c
<<
>>
Prefs
   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 "../../block/blk.h"
  12#include <linux/blkdev.h>
  13#include <linux/string.h>
  14#include <linux/of.h>
  15#include <linux/of_address.h>
  16#include <linux/platform_device.h>
  17#include <linux/pstore_blk.h>
  18#include <linux/mount.h>
  19#include <linux/uio.h>
  20
  21static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE;
  22module_param(kmsg_size, long, 0400);
  23MODULE_PARM_DESC(kmsg_size, "kmsg dump record size in kbytes");
  24
  25static int max_reason = CONFIG_PSTORE_BLK_MAX_REASON;
  26module_param(max_reason, int, 0400);
  27MODULE_PARM_DESC(max_reason,
  28                 "maximum reason for kmsg dump (default 2: Oops and Panic)");
  29
  30#if IS_ENABLED(CONFIG_PSTORE_PMSG)
  31static long pmsg_size = CONFIG_PSTORE_BLK_PMSG_SIZE;
  32#else
  33static long pmsg_size = -1;
  34#endif
  35module_param(pmsg_size, long, 0400);
  36MODULE_PARM_DESC(pmsg_size, "pmsg size in kbytes");
  37
  38#if IS_ENABLED(CONFIG_PSTORE_CONSOLE)
  39static long console_size = CONFIG_PSTORE_BLK_CONSOLE_SIZE;
  40#else
  41static long console_size = -1;
  42#endif
  43module_param(console_size, long, 0400);
  44MODULE_PARM_DESC(console_size, "console size in kbytes");
  45
  46#if IS_ENABLED(CONFIG_PSTORE_FTRACE)
  47static long ftrace_size = CONFIG_PSTORE_BLK_FTRACE_SIZE;
  48#else
  49static long ftrace_size = -1;
  50#endif
  51module_param(ftrace_size, long, 0400);
  52MODULE_PARM_DESC(ftrace_size, "ftrace size in kbytes");
  53
  54static bool best_effort;
  55module_param(best_effort, bool, 0400);
  56MODULE_PARM_DESC(best_effort, "use best effort to write (i.e. do not require storage driver pstore support, default: off)");
  57
  58/*
  59 * blkdev - the block device to use for pstore storage
  60 *
  61 * Usually, this will be a partition of a block device.
  62 *
  63 * blkdev accepts the following variants:
  64 * 1) <hex_major><hex_minor> device number in hexadecimal representation,
  65 *    with no leading 0x, for example b302.
  66 * 2) /dev/<disk_name> represents the device number of disk
  67 * 3) /dev/<disk_name><decimal> represents the device number
  68 *    of partition - device number of disk plus the partition number
  69 * 4) /dev/<disk_name>p<decimal> - same as the above, that form is
  70 *    used when disk name of partitioned disk ends on a digit.
  71 * 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
  72 *    unique id of a partition if the partition table provides it.
  73 *    The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
  74 *    partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
  75 *    filled hex representation of the 32-bit "NT disk signature", and PP
  76 *    is a zero-filled hex representation of the 1-based partition number.
  77 * 6) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
  78 *    a partition with a known unique id.
  79 * 7) <major>:<minor> major and minor number of the device separated by
  80 *    a colon.
  81 */
  82static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV;
  83module_param_string(blkdev, blkdev, 80, 0400);
  84MODULE_PARM_DESC(blkdev, "block device for pstore storage");
  85
  86/*
  87 * All globals must only be accessed under the pstore_blk_lock
  88 * during the register/unregister functions.
  89 */
  90static DEFINE_MUTEX(pstore_blk_lock);
  91static struct block_device *psblk_bdev;
  92static struct pstore_zone_info *pstore_zone_info;
  93static pstore_blk_panic_write_op blkdev_panic_write;
  94
  95struct bdev_info {
  96        dev_t devt;
  97        sector_t nr_sects;
  98        sector_t start_sect;
  99};
 100
 101#define check_size(name, alignsize) ({                          \
 102        long _##name_ = (name);                                 \
 103        _##name_ = _##name_ <= 0 ? 0 : (_##name_ * 1024);       \
 104        if (_##name_ & ((alignsize) - 1)) {                     \
 105                pr_info(#name " must align to %d\n",            \
 106                                (alignsize));                   \
 107                _##name_ = ALIGN(name, (alignsize));            \
 108        }                                                       \
 109        _##name_;                                               \
 110})
 111
 112static int __register_pstore_device(struct pstore_device_info *dev)
 113{
 114        int ret;
 115
 116        lockdep_assert_held(&pstore_blk_lock);
 117
 118        if (!dev || !dev->total_size || !dev->read || !dev->write)
 119                return -EINVAL;
 120
 121        /* someone already registered before */
 122        if (pstore_zone_info)
 123                return -EBUSY;
 124
 125        pstore_zone_info = kzalloc(sizeof(struct pstore_zone_info), GFP_KERNEL);
 126        if (!pstore_zone_info)
 127                return -ENOMEM;
 128
 129        /* zero means not limit on which backends to attempt to store. */
 130        if (!dev->flags)
 131                dev->flags = UINT_MAX;
 132
 133#define verify_size(name, alignsize, enabled) {                         \
 134                long _##name_;                                          \
 135                if (enabled)                                            \
 136                        _##name_ = check_size(name, alignsize);         \
 137                else                                                    \
 138                        _##name_ = 0;                                   \
 139                name = _##name_ / 1024;                                 \
 140                pstore_zone_info->name = _##name_;                      \
 141        }
 142
 143        verify_size(kmsg_size, 4096, dev->flags & PSTORE_FLAGS_DMESG);
 144        verify_size(pmsg_size, 4096, dev->flags & PSTORE_FLAGS_PMSG);
 145        verify_size(console_size, 4096, dev->flags & PSTORE_FLAGS_CONSOLE);
 146        verify_size(ftrace_size, 4096, dev->flags & PSTORE_FLAGS_FTRACE);
 147#undef verify_size
 148
 149        pstore_zone_info->total_size = dev->total_size;
 150        pstore_zone_info->max_reason = max_reason;
 151        pstore_zone_info->read = dev->read;
 152        pstore_zone_info->write = dev->write;
 153        pstore_zone_info->erase = dev->erase;
 154        pstore_zone_info->panic_write = dev->panic_write;
 155        pstore_zone_info->name = KBUILD_MODNAME;
 156        pstore_zone_info->owner = THIS_MODULE;
 157
 158        ret = register_pstore_zone(pstore_zone_info);
 159        if (ret) {
 160                kfree(pstore_zone_info);
 161                pstore_zone_info = NULL;
 162        }
 163        return ret;
 164}
 165/**
 166 * register_pstore_device() - register non-block device to pstore/blk
 167 *
 168 * @dev: non-block device information
 169 *
 170 * Return:
 171 * * 0          - OK
 172 * * Others     - something error.
 173 */
 174int register_pstore_device(struct pstore_device_info *dev)
 175{
 176        int ret;
 177
 178        mutex_lock(&pstore_blk_lock);
 179        ret = __register_pstore_device(dev);
 180        mutex_unlock(&pstore_blk_lock);
 181
 182        return ret;
 183}
 184EXPORT_SYMBOL_GPL(register_pstore_device);
 185
 186static void __unregister_pstore_device(struct pstore_device_info *dev)
 187{
 188        lockdep_assert_held(&pstore_blk_lock);
 189        if (pstore_zone_info && pstore_zone_info->read == dev->read) {
 190                unregister_pstore_zone(pstore_zone_info);
 191                kfree(pstore_zone_info);
 192                pstore_zone_info = NULL;
 193        }
 194}
 195
 196/**
 197 * unregister_pstore_device() - unregister non-block device from pstore/blk
 198 *
 199 * @dev: non-block device information
 200 */
 201void unregister_pstore_device(struct pstore_device_info *dev)
 202{
 203        mutex_lock(&pstore_blk_lock);
 204        __unregister_pstore_device(dev);
 205        mutex_unlock(&pstore_blk_lock);
 206}
 207EXPORT_SYMBOL_GPL(unregister_pstore_device);
 208
 209/**
 210 * psblk_get_bdev() - open block device
 211 *
 212 * @holder:     Exclusive holder identifier
 213 * @info:       Information about bdev to fill in
 214 *
 215 * Return: pointer to block device on success and others on error.
 216 *
 217 * On success, the returned block_device has reference count of one.
 218 */
 219static struct block_device *psblk_get_bdev(void *holder,
 220                                           struct bdev_info *info)
 221{
 222        struct block_device *bdev = ERR_PTR(-ENODEV);
 223        fmode_t mode = FMODE_READ | FMODE_WRITE;
 224        sector_t nr_sects;
 225
 226        lockdep_assert_held(&pstore_blk_lock);
 227
 228        if (pstore_zone_info)
 229                return ERR_PTR(-EBUSY);
 230
 231        if (!blkdev[0])
 232                return ERR_PTR(-ENODEV);
 233
 234        if (holder)
 235                mode |= FMODE_EXCL;
 236        bdev = blkdev_get_by_path(blkdev, mode, holder);
 237        if (IS_ERR(bdev)) {
 238                dev_t devt;
 239
 240                devt = name_to_dev_t(blkdev);
 241                if (devt == 0)
 242                        return ERR_PTR(-ENODEV);
 243                bdev = blkdev_get_by_dev(devt, mode, holder);
 244                if (IS_ERR(bdev))
 245                        return bdev;
 246        }
 247
 248        nr_sects = part_nr_sects_read(bdev->bd_part);
 249        if (!nr_sects) {
 250                pr_err("not enough space for '%s'\n", blkdev);
 251                blkdev_put(bdev, mode);
 252                return ERR_PTR(-ENOSPC);
 253        }
 254
 255        if (info) {
 256                info->devt = bdev->bd_dev;
 257                info->nr_sects = nr_sects;
 258                info->start_sect = get_start_sect(bdev);
 259        }
 260
 261        return bdev;
 262}
 263
 264static void psblk_put_bdev(struct block_device *bdev, void *holder)
 265{
 266        fmode_t mode = FMODE_READ | FMODE_WRITE;
 267
 268        lockdep_assert_held(&pstore_blk_lock);
 269
 270        if (!bdev)
 271                return;
 272
 273        if (holder)
 274                mode |= FMODE_EXCL;
 275        blkdev_put(bdev, mode);
 276}
 277
 278static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos)
 279{
 280        struct block_device *bdev = psblk_bdev;
 281        struct file file;
 282        struct kiocb kiocb;
 283        struct iov_iter iter;
 284        struct kvec iov = {.iov_base = buf, .iov_len = bytes};
 285
 286        if (!bdev)
 287                return -ENODEV;
 288
 289        memset(&file, 0, sizeof(struct file));
 290        file.f_mapping = bdev->bd_inode->i_mapping;
 291        file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
 292        file.f_inode = bdev->bd_inode;
 293        file_ra_state_init(&file.f_ra, file.f_mapping);
 294
 295        init_sync_kiocb(&kiocb, &file);
 296        kiocb.ki_pos = pos;
 297        iov_iter_kvec(&iter, READ, &iov, 1, bytes);
 298
 299        return generic_file_read_iter(&kiocb, &iter);
 300}
 301
 302static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes,
 303                loff_t pos)
 304{
 305        struct block_device *bdev = psblk_bdev;
 306        struct iov_iter iter;
 307        struct kiocb kiocb;
 308        struct file file;
 309        ssize_t ret;
 310        struct kvec iov = {.iov_base = (void *)buf, .iov_len = bytes};
 311
 312        if (!bdev)
 313                return -ENODEV;
 314
 315        /* Console/Ftrace backend may handle buffer until flush dirty zones */
 316        if (in_interrupt() || irqs_disabled())
 317                return -EBUSY;
 318
 319        memset(&file, 0, sizeof(struct file));
 320        file.f_mapping = bdev->bd_inode->i_mapping;
 321        file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME;
 322        file.f_inode = bdev->bd_inode;
 323
 324        init_sync_kiocb(&kiocb, &file);
 325        kiocb.ki_pos = pos;
 326        iov_iter_kvec(&iter, WRITE, &iov, 1, bytes);
 327
 328        inode_lock(bdev->bd_inode);
 329        ret = generic_write_checks(&kiocb, &iter);
 330        if (ret > 0)
 331                ret = generic_perform_write(&file, &iter, pos);
 332        inode_unlock(bdev->bd_inode);
 333
 334        if (likely(ret > 0)) {
 335                const struct file_operations f_op = {.fsync = blkdev_fsync};
 336
 337                file.f_op = &f_op;
 338                kiocb.ki_pos += ret;
 339                ret = generic_write_sync(&kiocb, ret);
 340        }
 341        return ret;
 342}
 343
 344static ssize_t psblk_blk_panic_write(const char *buf, size_t size,
 345                loff_t off)
 346{
 347        int ret;
 348
 349        if (!blkdev_panic_write)
 350                return -EOPNOTSUPP;
 351
 352        /* size and off must align to SECTOR_SIZE for block device */
 353        ret = blkdev_panic_write(buf, off >> SECTOR_SHIFT,
 354                        size >> SECTOR_SHIFT);
 355        /* try next zone */
 356        if (ret == -ENOMSG)
 357                return ret;
 358        return ret ? -EIO : size;
 359}
 360
 361static int __register_pstore_blk(struct pstore_blk_info *info)
 362{
 363        char bdev_name[BDEVNAME_SIZE];
 364        struct block_device *bdev;
 365        struct pstore_device_info dev;
 366        struct bdev_info binfo;
 367        void *holder = blkdev;
 368        int ret = -ENODEV;
 369
 370        lockdep_assert_held(&pstore_blk_lock);
 371
 372        /* hold bdev exclusively */
 373        memset(&binfo, 0, sizeof(binfo));
 374        bdev = psblk_get_bdev(holder, &binfo);
 375        if (IS_ERR(bdev)) {
 376                pr_err("failed to open '%s'!\n", blkdev);
 377                return PTR_ERR(bdev);
 378        }
 379
 380        /* only allow driver matching the @blkdev */
 381        if (!binfo.devt || (!best_effort &&
 382                            MAJOR(binfo.devt) != info->major)) {
 383                pr_debug("invalid major %u (expect %u)\n",
 384                                info->major, MAJOR(binfo.devt));
 385                ret = -ENODEV;
 386                goto err_put_bdev;
 387        }
 388
 389        /* psblk_bdev must be assigned before register to pstore/blk */
 390        psblk_bdev = bdev;
 391        blkdev_panic_write = info->panic_write;
 392
 393        /* Copy back block device details. */
 394        info->devt = binfo.devt;
 395        info->nr_sects = binfo.nr_sects;
 396        info->start_sect = binfo.start_sect;
 397
 398        memset(&dev, 0, sizeof(dev));
 399        dev.total_size = info->nr_sects << SECTOR_SHIFT;
 400        dev.flags = info->flags;
 401        dev.read = psblk_generic_blk_read;
 402        dev.write = psblk_generic_blk_write;
 403        dev.erase = NULL;
 404        dev.panic_write = info->panic_write ? psblk_blk_panic_write : NULL;
 405
 406        ret = __register_pstore_device(&dev);
 407        if (ret)
 408                goto err_put_bdev;
 409
 410        bdevname(bdev, bdev_name);
 411        pr_info("attached %s%s\n", bdev_name,
 412                info->panic_write ? "" : " (no dedicated panic_write!)");
 413        return 0;
 414
 415err_put_bdev:
 416        psblk_bdev = NULL;
 417        blkdev_panic_write = NULL;
 418        psblk_put_bdev(bdev, holder);
 419        return ret;
 420}
 421
 422/**
 423 * register_pstore_blk() - register block device to pstore/blk
 424 *
 425 * @info: details on the desired block device interface
 426 *
 427 * Return:
 428 * * 0          - OK
 429 * * Others     - something error.
 430 */
 431int register_pstore_blk(struct pstore_blk_info *info)
 432{
 433        int ret;
 434
 435        mutex_lock(&pstore_blk_lock);
 436        ret = __register_pstore_blk(info);
 437        mutex_unlock(&pstore_blk_lock);
 438
 439        return ret;
 440}
 441EXPORT_SYMBOL_GPL(register_pstore_blk);
 442
 443static void __unregister_pstore_blk(unsigned int major)
 444{
 445        struct pstore_device_info dev = { .read = psblk_generic_blk_read };
 446        void *holder = blkdev;
 447
 448        lockdep_assert_held(&pstore_blk_lock);
 449        if (psblk_bdev && MAJOR(psblk_bdev->bd_dev) == major) {
 450                __unregister_pstore_device(&dev);
 451                psblk_put_bdev(psblk_bdev, holder);
 452                blkdev_panic_write = NULL;
 453                psblk_bdev = NULL;
 454        }
 455}
 456
 457/**
 458 * unregister_pstore_blk() - unregister block device from pstore/blk
 459 *
 460 * @major: the major device number of device
 461 */
 462void unregister_pstore_blk(unsigned int major)
 463{
 464        mutex_lock(&pstore_blk_lock);
 465        __unregister_pstore_blk(major);
 466        mutex_unlock(&pstore_blk_lock);
 467}
 468EXPORT_SYMBOL_GPL(unregister_pstore_blk);
 469
 470/* get information of pstore/blk */
 471int pstore_blk_get_config(struct pstore_blk_config *info)
 472{
 473        strncpy(info->device, blkdev, 80);
 474        info->max_reason = max_reason;
 475        info->kmsg_size = check_size(kmsg_size, 4096);
 476        info->pmsg_size = check_size(pmsg_size, 4096);
 477        info->ftrace_size = check_size(ftrace_size, 4096);
 478        info->console_size = check_size(console_size, 4096);
 479
 480        return 0;
 481}
 482EXPORT_SYMBOL_GPL(pstore_blk_get_config);
 483
 484static int __init pstore_blk_init(void)
 485{
 486        struct pstore_blk_info info = { };
 487        int ret = 0;
 488
 489        mutex_lock(&pstore_blk_lock);
 490        if (!pstore_zone_info && best_effort && blkdev[0])
 491                ret = __register_pstore_blk(&info);
 492        mutex_unlock(&pstore_blk_lock);
 493
 494        return ret;
 495}
 496late_initcall(pstore_blk_init);
 497
 498static void __exit pstore_blk_exit(void)
 499{
 500        mutex_lock(&pstore_blk_lock);
 501        if (psblk_bdev)
 502                __unregister_pstore_blk(MAJOR(psblk_bdev->bd_dev));
 503        else {
 504                struct pstore_device_info dev = { };
 505
 506                if (pstore_zone_info)
 507                        dev.read = pstore_zone_info->read;
 508                __unregister_pstore_device(&dev);
 509        }
 510        mutex_unlock(&pstore_blk_lock);
 511}
 512module_exit(pstore_blk_exit);
 513
 514MODULE_LICENSE("GPL");
 515MODULE_AUTHOR("WeiXiong Liao <liaoweixiong@allwinnertech.com>");
 516MODULE_AUTHOR("Kees Cook <keescook@chromium.org>");
 517MODULE_DESCRIPTION("pstore backend for block devices");
 518