linux/fs/pstore/platform.c
<<
>>
Prefs
   1/*
   2 * Persistent Storage - platform driver interface parts.
   3 *
   4 * Copyright (C) 2007-2008 Google, Inc.
   5 * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License version 2 as
   9 *  published by the Free Software Foundation.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21#include <linux/atomic.h>
  22#include <linux/types.h>
  23#include <linux/errno.h>
  24#include <linux/init.h>
  25#include <linux/kmsg_dump.h>
  26#include <linux/console.h>
  27#include <linux/module.h>
  28#include <linux/pstore.h>
  29#include <linux/string.h>
  30#include <linux/timer.h>
  31#include <linux/slab.h>
  32#include <linux/uaccess.h>
  33#include <linux/hardirq.h>
  34#include <linux/jiffies.h>
  35#include <linux/workqueue.h>
  36
  37#include "internal.h"
  38
  39/*
  40 * We defer making "oops" entries appear in pstore - see
  41 * whether the system is actually still running well enough
  42 * to let someone see the entry
  43 */
  44static int pstore_update_ms = -1;
  45module_param_named(update_ms, pstore_update_ms, int, 0600);
  46MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
  47                 "(default is -1, which means runtime updates are disabled; "
  48                 "enabling this option is not safe, it may lead to further "
  49                 "corruption on Oopses)");
  50
  51static int pstore_new_entry;
  52
  53static void pstore_timefunc(unsigned long);
  54static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0);
  55
  56static void pstore_dowork(struct work_struct *);
  57static DECLARE_WORK(pstore_work, pstore_dowork);
  58
  59/*
  60 * pstore_lock just protects "psinfo" during
  61 * calls to pstore_register()
  62 */
  63static DEFINE_SPINLOCK(pstore_lock);
  64struct pstore_info *psinfo;
  65
  66static char *backend;
  67
  68/* How much of the console log to snapshot */
  69static unsigned long kmsg_bytes = 10240;
  70
  71void pstore_set_kmsg_bytes(int bytes)
  72{
  73        kmsg_bytes = bytes;
  74}
  75
  76/* Tag each group of saved records with a sequence number */
  77static int      oopscount;
  78
  79static const char *get_reason_str(enum kmsg_dump_reason reason)
  80{
  81        switch (reason) {
  82        case KMSG_DUMP_PANIC:
  83                return "Panic";
  84        case KMSG_DUMP_OOPS:
  85                return "Oops";
  86        case KMSG_DUMP_EMERG:
  87                return "Emergency";
  88        case KMSG_DUMP_RESTART:
  89                return "Restart";
  90        case KMSG_DUMP_HALT:
  91                return "Halt";
  92        case KMSG_DUMP_POWEROFF:
  93                return "Poweroff";
  94        default:
  95                return "Unknown";
  96        }
  97}
  98
  99/*
 100 * callback from kmsg_dump. (s2,l2) has the most recently
 101 * written bytes, older bytes are in (s1,l1). Save as much
 102 * as we can from the end of the buffer.
 103 */
 104static void pstore_dump(struct kmsg_dumper *dumper,
 105                        enum kmsg_dump_reason reason)
 106{
 107        unsigned long   total = 0;
 108        const char      *why;
 109        u64             id;
 110        unsigned int    part = 1;
 111        unsigned long   flags = 0;
 112        int             is_locked = 0;
 113        int             ret;
 114
 115        why = get_reason_str(reason);
 116
 117        if (in_nmi()) {
 118                is_locked = spin_trylock(&psinfo->buf_lock);
 119                if (!is_locked)
 120                        pr_err("pstore dump routine blocked in NMI, may corrupt error record\n");
 121        } else
 122                spin_lock_irqsave(&psinfo->buf_lock, flags);
 123        oopscount++;
 124        while (total < kmsg_bytes) {
 125                char *dst;
 126                unsigned long size;
 127                int hsize;
 128                size_t len;
 129
 130                dst = psinfo->buf;
 131                hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
 132                size = psinfo->bufsize - hsize;
 133                dst += hsize;
 134
 135                if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len))
 136                        break;
 137
 138                ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
 139                                    hsize + len, psinfo);
 140                if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
 141                        pstore_new_entry = 1;
 142
 143                total += hsize + len;
 144                part++;
 145        }
 146        if (in_nmi()) {
 147                if (is_locked)
 148                        spin_unlock(&psinfo->buf_lock);
 149        } else
 150                spin_unlock_irqrestore(&psinfo->buf_lock, flags);
 151}
 152
 153static struct kmsg_dumper pstore_dumper = {
 154        .dump = pstore_dump,
 155};
 156
 157#ifdef CONFIG_PSTORE_CONSOLE
 158static void pstore_console_write(struct console *con, const char *s, unsigned c)
 159{
 160        const char *e = s + c;
 161
 162        while (s < e) {
 163                unsigned long flags;
 164                u64 id;
 165
 166                if (c > psinfo->bufsize)
 167                        c = psinfo->bufsize;
 168
 169                if (oops_in_progress) {
 170                        if (!spin_trylock_irqsave(&psinfo->buf_lock, flags))
 171                                break;
 172                } else {
 173                        spin_lock_irqsave(&psinfo->buf_lock, flags);
 174                }
 175                memcpy(psinfo->buf, s, c);
 176                psinfo->write(PSTORE_TYPE_CONSOLE, 0, &id, 0, c, psinfo);
 177                spin_unlock_irqrestore(&psinfo->buf_lock, flags);
 178                s += c;
 179                c = e - s;
 180        }
 181}
 182
 183static struct console pstore_console = {
 184        .name   = "pstore",
 185        .write  = pstore_console_write,
 186        .flags  = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
 187        .index  = -1,
 188};
 189
 190static void pstore_register_console(void)
 191{
 192        register_console(&pstore_console);
 193}
 194#else
 195static void pstore_register_console(void) {}
 196#endif
 197
 198static int pstore_write_compat(enum pstore_type_id type,
 199                               enum kmsg_dump_reason reason,
 200                               u64 *id, unsigned int part,
 201                               size_t size, struct pstore_info *psi)
 202{
 203        return psi->write_buf(type, reason, id, part, psinfo->buf, size, psi);
 204}
 205
 206/*
 207 * platform specific persistent storage driver registers with
 208 * us here. If pstore is already mounted, call the platform
 209 * read function right away to populate the file system. If not
 210 * then the pstore mount code will call us later to fill out
 211 * the file system.
 212 *
 213 * Register with kmsg_dump to save last part of console log on panic.
 214 */
 215int pstore_register(struct pstore_info *psi)
 216{
 217        struct module *owner = psi->owner;
 218
 219        spin_lock(&pstore_lock);
 220        if (psinfo) {
 221                spin_unlock(&pstore_lock);
 222                return -EBUSY;
 223        }
 224
 225        if (backend && strcmp(backend, psi->name)) {
 226                spin_unlock(&pstore_lock);
 227                return -EINVAL;
 228        }
 229
 230        if (!psi->write)
 231                psi->write = pstore_write_compat;
 232        psinfo = psi;
 233        mutex_init(&psinfo->read_mutex);
 234        spin_unlock(&pstore_lock);
 235
 236        if (owner && !try_module_get(owner)) {
 237                psinfo = NULL;
 238                return -EINVAL;
 239        }
 240
 241        if (pstore_is_mounted())
 242                pstore_get_records(0);
 243
 244        kmsg_dump_register(&pstore_dumper);
 245        pstore_register_console();
 246        pstore_register_ftrace();
 247
 248        if (pstore_update_ms >= 0) {
 249                pstore_timer.expires = jiffies +
 250                        msecs_to_jiffies(pstore_update_ms);
 251                add_timer(&pstore_timer);
 252        }
 253
 254        return 0;
 255}
 256EXPORT_SYMBOL_GPL(pstore_register);
 257
 258/*
 259 * Read all the records from the persistent store. Create
 260 * files in our filesystem.  Don't warn about -EEXIST errors
 261 * when we are re-scanning the backing store looking to add new
 262 * error records.
 263 */
 264void pstore_get_records(int quiet)
 265{
 266        struct pstore_info *psi = psinfo;
 267        char                    *buf = NULL;
 268        ssize_t                 size;
 269        u64                     id;
 270        enum pstore_type_id     type;
 271        struct timespec         time;
 272        int                     failed = 0, rc;
 273
 274        if (!psi)
 275                return;
 276
 277        mutex_lock(&psi->read_mutex);
 278        if (psi->open && psi->open(psi))
 279                goto out;
 280
 281        while ((size = psi->read(&id, &type, &time, &buf, psi)) > 0) {
 282                rc = pstore_mkfile(type, psi->name, id, buf, (size_t)size,
 283                                  time, psi);
 284                kfree(buf);
 285                buf = NULL;
 286                if (rc && (rc != -EEXIST || !quiet))
 287                        failed++;
 288        }
 289        if (psi->close)
 290                psi->close(psi);
 291out:
 292        mutex_unlock(&psi->read_mutex);
 293
 294        if (failed)
 295                printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n",
 296                       failed, psi->name);
 297}
 298
 299static void pstore_dowork(struct work_struct *work)
 300{
 301        pstore_get_records(1);
 302}
 303
 304static void pstore_timefunc(unsigned long dummy)
 305{
 306        if (pstore_new_entry) {
 307                pstore_new_entry = 0;
 308                schedule_work(&pstore_work);
 309        }
 310
 311        mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
 312}
 313
 314module_param(backend, charp, 0444);
 315MODULE_PARM_DESC(backend, "Pstore backend to use");
 316
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.