Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
[linux-2.6-microblaze.git] / fs / pstore / platform.c
index 408277e..a9e297e 100644 (file)
@@ -44,7 +44,7 @@ static int pstore_update_ms = -1;
 module_param_named(update_ms, pstore_update_ms, int, 0600);
 MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
                 "(default is -1, which means runtime updates are disabled; "
-                "enabling this option is not safe, it may lead to further "
+                "enabling this option may not be safe; it may lead to further "
                 "corruption on Oopses)");
 
 /* Names should be in the same order as the enum pstore_type_id */
@@ -69,19 +69,25 @@ static void pstore_dowork(struct work_struct *);
 static DECLARE_WORK(pstore_work, pstore_dowork);
 
 /*
- * pstore_lock just protects "psinfo" during
- * calls to pstore_register()
+ * psinfo_lock protects "psinfo" during calls to
+ * pstore_register(), pstore_unregister(), and
+ * the filesystem mount/unmount routines.
  */
-static DEFINE_SPINLOCK(pstore_lock);
+static DEFINE_MUTEX(psinfo_lock);
 struct pstore_info *psinfo;
 
 static char *backend;
+module_param(backend, charp, 0444);
+MODULE_PARM_DESC(backend, "specific backend to use");
+
 static char *compress =
 #ifdef CONFIG_PSTORE_COMPRESS_DEFAULT
                CONFIG_PSTORE_COMPRESS_DEFAULT;
 #else
                NULL;
 #endif
+module_param(compress, charp, 0444);
+MODULE_PARM_DESC(compress, "compression to use");
 
 /* Compression parameters */
 static struct crypto_comp *tfm;
@@ -129,24 +135,12 @@ enum pstore_type_id pstore_name_to_type(const char *name)
 }
 EXPORT_SYMBOL_GPL(pstore_name_to_type);
 
-static const char *get_reason_str(enum kmsg_dump_reason reason)
+static void pstore_timer_kick(void)
 {
-       switch (reason) {
-       case KMSG_DUMP_PANIC:
-               return "Panic";
-       case KMSG_DUMP_OOPS:
-               return "Oops";
-       case KMSG_DUMP_EMERG:
-               return "Emergency";
-       case KMSG_DUMP_RESTART:
-               return "Restart";
-       case KMSG_DUMP_HALT:
-               return "Halt";
-       case KMSG_DUMP_POWEROFF:
-               return "Poweroff";
-       default:
-               return "Unknown";
-       }
+       if (pstore_update_ms < 0)
+               return;
+
+       mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
 }
 
 /*
@@ -393,7 +387,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
        unsigned int    part = 1;
        int             ret;
 
-       why = get_reason_str(reason);
+       why = kmsg_dump_reason_str(reason);
 
        if (down_trylock(&psinfo->buf_lock)) {
                /* Failed to acquire lock: give up if we cannot wait. */
@@ -459,8 +453,10 @@ static void pstore_dump(struct kmsg_dumper *dumper,
                }
 
                ret = psinfo->write(&record);
-               if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
+               if (ret == 0 && reason == KMSG_DUMP_OOPS) {
                        pstore_new_entry = 1;
+                       pstore_timer_kick();
+               }
 
                total += record.size;
                part++;
@@ -503,14 +499,20 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c)
 }
 
 static struct console pstore_console = {
-       .name   = "pstore",
        .write  = pstore_console_write,
-       .flags  = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
        .index  = -1,
 };
 
 static void pstore_register_console(void)
 {
+       /* Show which backend is going to get console writes. */
+       strscpy(pstore_console.name, psinfo->name,
+               sizeof(pstore_console.name));
+       /*
+        * Always initialize flags here since prior unregister_console()
+        * calls may have changed settings (specifically CON_ENABLED).
+        */
+       pstore_console.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME;
        register_console(&pstore_console);
 }
 
@@ -555,8 +557,6 @@ out:
  */
 int pstore_register(struct pstore_info *psi)
 {
-       struct module *owner = psi->owner;
-
        if (backend && strcmp(backend, psi->name)) {
                pr_warn("ignoring unexpected backend '%s'\n", psi->name);
                return -EPERM;
@@ -576,11 +576,11 @@ int pstore_register(struct pstore_info *psi)
                return -EINVAL;
        }
 
-       spin_lock(&pstore_lock);
+       mutex_lock(&psinfo_lock);
        if (psinfo) {
                pr_warn("backend '%s' already loaded: ignoring '%s'\n",
                        psinfo->name, psi->name);
-               spin_unlock(&pstore_lock);
+               mutex_unlock(&psinfo_lock);
                return -EBUSY;
        }
 
@@ -589,21 +589,16 @@ int pstore_register(struct pstore_info *psi)
        psinfo = psi;
        mutex_init(&psinfo->read_mutex);
        sema_init(&psinfo->buf_lock, 1);
-       spin_unlock(&pstore_lock);
-
-       if (owner && !try_module_get(owner)) {
-               psinfo = NULL;
-               return -EINVAL;
-       }
 
        if (psi->flags & PSTORE_FLAGS_DMESG)
                allocate_buf_for_compression();
 
-       if (pstore_is_mounted())
-               pstore_get_records(0);
+       pstore_get_records(0);
 
-       if (psi->flags & PSTORE_FLAGS_DMESG)
+       if (psi->flags & PSTORE_FLAGS_DMESG) {
+               pstore_dumper.max_reason = psinfo->max_reason;
                pstore_register_kmsg();
+       }
        if (psi->flags & PSTORE_FLAGS_CONSOLE)
                pstore_register_console();
        if (psi->flags & PSTORE_FLAGS_FTRACE)
@@ -612,33 +607,36 @@ int pstore_register(struct pstore_info *psi)
                pstore_register_pmsg();
 
        /* Start watching for new records, if desired. */
-       if (pstore_update_ms >= 0) {
-               pstore_timer.expires = jiffies +
-                       msecs_to_jiffies(pstore_update_ms);
-               add_timer(&pstore_timer);
-       }
+       pstore_timer_kick();
 
        /*
         * Update the module parameter backend, so it is visible
         * through /sys/module/pstore/parameters/backend
         */
-       backend = psi->name;
+       backend = kstrdup(psi->name, GFP_KERNEL);
 
        pr_info("Registered %s as persistent store backend\n", psi->name);
 
-       module_put(owner);
-
+       mutex_unlock(&psinfo_lock);
        return 0;
 }
 EXPORT_SYMBOL_GPL(pstore_register);
 
 void pstore_unregister(struct pstore_info *psi)
 {
-       /* Stop timer and make sure all work has finished. */
-       pstore_update_ms = -1;
-       del_timer_sync(&pstore_timer);
-       flush_work(&pstore_work);
+       /* It's okay to unregister nothing. */
+       if (!psi)
+               return;
+
+       mutex_lock(&psinfo_lock);
+
+       /* Only one backend can be registered at a time. */
+       if (WARN_ON(psi != psinfo)) {
+               mutex_unlock(&psinfo_lock);
+               return;
+       }
 
+       /* Unregister all callbacks. */
        if (psi->flags & PSTORE_FLAGS_PMSG)
                pstore_unregister_pmsg();
        if (psi->flags & PSTORE_FLAGS_FTRACE)
@@ -648,10 +646,19 @@ void pstore_unregister(struct pstore_info *psi)
        if (psi->flags & PSTORE_FLAGS_DMESG)
                pstore_unregister_kmsg();
 
+       /* Stop timer and make sure all work has finished. */
+       del_timer_sync(&pstore_timer);
+       flush_work(&pstore_work);
+
+       /* Remove all backend records from filesystem tree. */
+       pstore_put_backend_records(psi);
+
        free_buf_for_compression();
 
        psinfo = NULL;
+       kfree(backend);
        backend = NULL;
+       mutex_unlock(&psinfo_lock);
 }
 EXPORT_SYMBOL_GPL(pstore_unregister);
 
@@ -788,9 +795,7 @@ static void pstore_timefunc(struct timer_list *unused)
                schedule_work(&pstore_work);
        }
 
-       if (pstore_update_ms >= 0)
-               mod_timer(&pstore_timer,
-                         jiffies + msecs_to_jiffies(pstore_update_ms));
+       pstore_timer_kick();
 }
 
 static void __init pstore_choose_compression(void)
@@ -835,11 +840,5 @@ static void __exit pstore_exit(void)
 }
 module_exit(pstore_exit)
 
-module_param(compress, charp, 0444);
-MODULE_PARM_DESC(compress, "Pstore compression to use");
-
-module_param(backend, charp, 0444);
-MODULE_PARM_DESC(backend, "Pstore backend to use");
-
 MODULE_AUTHOR("Tony Luck <tony.luck@intel.com>");
 MODULE_LICENSE("GPL");