mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-11-17 15:14:35 +08:00
Merge branch 'pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
* 'pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux: pstore: make pstore write function return normal success/fail value pstore: change mutex locking to spin_locks pstore: defer inserting OOPS entries into pstore
This commit is contained in:
commit
1c39865151
@ -933,7 +933,7 @@ static int erst_open_pstore(struct pstore_info *psi);
|
||||
static int erst_close_pstore(struct pstore_info *psi);
|
||||
static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
|
||||
struct timespec *time, struct pstore_info *psi);
|
||||
static u64 erst_writer(enum pstore_type_id type, unsigned int part,
|
||||
static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part,
|
||||
size_t size, struct pstore_info *psi);
|
||||
static int erst_clearer(enum pstore_type_id type, u64 id,
|
||||
struct pstore_info *psi);
|
||||
@ -1040,11 +1040,12 @@ out:
|
||||
return (rc < 0) ? rc : (len - sizeof(*rcd));
|
||||
}
|
||||
|
||||
static u64 erst_writer(enum pstore_type_id type, unsigned int part,
|
||||
static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part,
|
||||
size_t size, struct pstore_info *psi)
|
||||
{
|
||||
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
|
||||
(erst_info.buf - sizeof(*rcd));
|
||||
int ret;
|
||||
|
||||
memset(rcd, 0, sizeof(*rcd));
|
||||
memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
|
||||
@ -1079,9 +1080,10 @@ static u64 erst_writer(enum pstore_type_id type, unsigned int part,
|
||||
}
|
||||
rcd->sec_hdr.section_severity = CPER_SEV_FATAL;
|
||||
|
||||
erst_write(&rcd->hdr);
|
||||
ret = erst_write(&rcd->hdr);
|
||||
*id = rcd->hdr.record_id;
|
||||
|
||||
return rcd->hdr.record_id;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int erst_clearer(enum pstore_type_id type, u64 id,
|
||||
@ -1165,7 +1167,7 @@ static int __init erst_init(void)
|
||||
goto err_release_erange;
|
||||
|
||||
buf = kmalloc(erst_erange.size, GFP_KERNEL);
|
||||
mutex_init(&erst_info.buf_mutex);
|
||||
spin_lock_init(&erst_info.buf_lock);
|
||||
if (buf) {
|
||||
erst_info.buf = buf + sizeof(struct cper_pstore_record);
|
||||
erst_info.bufsize = erst_erange.size -
|
||||
|
@ -490,8 +490,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part,
|
||||
size_t size, struct pstore_info *psi)
|
||||
static int efi_pstore_write(enum pstore_type_id type, u64 *id,
|
||||
unsigned int part, size_t size, struct pstore_info *psi)
|
||||
{
|
||||
char name[DUMP_NAME_LEN];
|
||||
char stub_name[DUMP_NAME_LEN];
|
||||
@ -499,7 +499,7 @@ static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part,
|
||||
efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
|
||||
struct efivars *efivars = psi->data;
|
||||
struct efivar_entry *entry, *found = NULL;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
sprintf(stub_name, "dump-type%u-%u-", type, part);
|
||||
sprintf(name, "%s%lu", stub_name, get_seconds());
|
||||
@ -548,18 +548,19 @@ static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part,
|
||||
efivar_unregister(found);
|
||||
|
||||
if (size)
|
||||
efivar_create_sysfs_entry(efivars,
|
||||
ret = efivar_create_sysfs_entry(efivars,
|
||||
utf16_strsize(efi_name,
|
||||
DUMP_NAME_LEN * 2),
|
||||
efi_name, &vendor);
|
||||
|
||||
return part;
|
||||
*id = part;
|
||||
return ret;
|
||||
};
|
||||
|
||||
static int efi_pstore_erase(enum pstore_type_id type, u64 id,
|
||||
struct pstore_info *psi)
|
||||
{
|
||||
efi_pstore_write(type, id, 0, psi);
|
||||
efi_pstore_write(type, &id, (unsigned int)id, 0, psi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -580,8 +581,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part,
|
||||
size_t size, struct pstore_info *psi)
|
||||
static int efi_pstore_write(enum pstore_type_id type, u64 *id,
|
||||
unsigned int part, size_t size, struct pstore_info *psi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -978,7 +979,7 @@ int register_efivars(struct efivars *efivars,
|
||||
if (efivars->efi_pstore_info.buf) {
|
||||
efivars->efi_pstore_info.bufsize = 1024;
|
||||
efivars->efi_pstore_info.data = efivars;
|
||||
mutex_init(&efivars->efi_pstore_info.buf_mutex);
|
||||
spin_lock_init(&efivars->efi_pstore_info.buf_lock);
|
||||
pstore_register(&efivars->efi_pstore_info);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/ramfs.h>
|
||||
@ -32,13 +33,18 @@
|
||||
#include <linux/magic.h>
|
||||
#include <linux/pstore.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define PSTORE_NAMELEN 64
|
||||
|
||||
static DEFINE_SPINLOCK(allpstore_lock);
|
||||
static LIST_HEAD(allpstore);
|
||||
|
||||
struct pstore_private {
|
||||
struct list_head list;
|
||||
struct pstore_info *psi;
|
||||
enum pstore_type_id type;
|
||||
u64 id;
|
||||
@ -81,8 +87,16 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
|
||||
|
||||
static void pstore_evict_inode(struct inode *inode)
|
||||
{
|
||||
struct pstore_private *p = inode->i_private;
|
||||
unsigned long flags;
|
||||
|
||||
end_writeback(inode);
|
||||
kfree(inode->i_private);
|
||||
if (p) {
|
||||
spin_lock_irqsave(&allpstore_lock, flags);
|
||||
list_del(&p->list);
|
||||
spin_unlock_irqrestore(&allpstore_lock, flags);
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct inode_operations pstore_dir_inode_operations = {
|
||||
@ -182,9 +196,23 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
|
||||
struct dentry *root = pstore_sb->s_root;
|
||||
struct dentry *dentry;
|
||||
struct inode *inode;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
char name[PSTORE_NAMELEN];
|
||||
struct pstore_private *private;
|
||||
struct pstore_private *private, *pos;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&allpstore_lock, flags);
|
||||
list_for_each_entry(pos, &allpstore, list) {
|
||||
if (pos->type == type &&
|
||||
pos->id == id &&
|
||||
pos->psi == psi) {
|
||||
rc = -EEXIST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&allpstore_lock, flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = -ENOMEM;
|
||||
inode = pstore_get_inode(pstore_sb, root->d_inode, S_IFREG | 0444, 0);
|
||||
@ -229,6 +257,10 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
|
||||
|
||||
d_add(dentry, inode);
|
||||
|
||||
spin_lock_irqsave(&allpstore_lock, flags);
|
||||
list_add(&private->list, &allpstore);
|
||||
spin_unlock_irqrestore(&allpstore_lock, flags);
|
||||
|
||||
mutex_unlock(&root->d_inode->i_mutex);
|
||||
|
||||
return 0;
|
||||
@ -277,7 +309,7 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pstore_get_records();
|
||||
pstore_get_records(0);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
|
@ -1,5 +1,5 @@
|
||||
extern void pstore_set_kmsg_bytes(int);
|
||||
extern void pstore_get_records(void);
|
||||
extern void pstore_get_records(int);
|
||||
extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
|
||||
char *data, size_t size,
|
||||
struct timespec time, struct pstore_info *psi);
|
||||
|
@ -25,11 +25,29 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/pstore.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* We defer making "oops" entries appear in pstore - see
|
||||
* whether the system is actually still running well enough
|
||||
* to let someone see the entry
|
||||
*/
|
||||
#define PSTORE_INTERVAL (60 * HZ)
|
||||
|
||||
static int pstore_new_entry;
|
||||
|
||||
static void pstore_timefunc(unsigned long);
|
||||
static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0);
|
||||
|
||||
static void pstore_dowork(struct work_struct *);
|
||||
static DECLARE_WORK(pstore_work, pstore_dowork);
|
||||
|
||||
/*
|
||||
* pstore_lock just protects "psinfo" during
|
||||
* calls to pstore_register()
|
||||
@ -69,15 +87,22 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
unsigned long size, total = 0;
|
||||
char *dst, *why;
|
||||
u64 id;
|
||||
int hsize;
|
||||
int hsize, ret;
|
||||
unsigned int part = 1;
|
||||
unsigned long flags = 0;
|
||||
int is_locked = 0;
|
||||
|
||||
if (reason < ARRAY_SIZE(reason_str))
|
||||
why = reason_str[reason];
|
||||
else
|
||||
why = "Unknown";
|
||||
|
||||
mutex_lock(&psinfo->buf_mutex);
|
||||
if (in_nmi()) {
|
||||
is_locked = spin_trylock(&psinfo->buf_lock);
|
||||
if (!is_locked)
|
||||
pr_err("pstore dump routine blocked in NMI, may corrupt error record\n");
|
||||
} else
|
||||
spin_lock_irqsave(&psinfo->buf_lock, flags);
|
||||
oopscount++;
|
||||
while (total < kmsg_bytes) {
|
||||
dst = psinfo->buf;
|
||||
@ -97,18 +122,20 @@ static void pstore_dump(struct kmsg_dumper *dumper,
|
||||
memcpy(dst, s1 + s1_start, l1_cpy);
|
||||
memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
|
||||
|
||||
id = psinfo->write(PSTORE_TYPE_DMESG, part,
|
||||
ret = psinfo->write(PSTORE_TYPE_DMESG, &id, part,
|
||||
hsize + l1_cpy + l2_cpy, psinfo);
|
||||
if (reason == KMSG_DUMP_OOPS && pstore_is_mounted())
|
||||
pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id,
|
||||
psinfo->buf, hsize + l1_cpy + l2_cpy,
|
||||
CURRENT_TIME, psinfo);
|
||||
if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
|
||||
pstore_new_entry = 1;
|
||||
l1 -= l1_cpy;
|
||||
l2 -= l2_cpy;
|
||||
total += l1_cpy + l2_cpy;
|
||||
part++;
|
||||
}
|
||||
mutex_unlock(&psinfo->buf_mutex);
|
||||
if (in_nmi()) {
|
||||
if (is_locked)
|
||||
spin_unlock(&psinfo->buf_lock);
|
||||
} else
|
||||
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
|
||||
}
|
||||
|
||||
static struct kmsg_dumper pstore_dumper = {
|
||||
@ -148,19 +175,24 @@ int pstore_register(struct pstore_info *psi)
|
||||
}
|
||||
|
||||
if (pstore_is_mounted())
|
||||
pstore_get_records();
|
||||
pstore_get_records(0);
|
||||
|
||||
kmsg_dump_register(&pstore_dumper);
|
||||
|
||||
pstore_timer.expires = jiffies + PSTORE_INTERVAL;
|
||||
add_timer(&pstore_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pstore_register);
|
||||
|
||||
/*
|
||||
* Read all the records from the persistent store. Create and
|
||||
* file files in our filesystem.
|
||||
* Read all the records from the persistent store. Create
|
||||
* files in our filesystem. Don't warn about -EEXIST errors
|
||||
* when we are re-scanning the backing store looking to add new
|
||||
* error records.
|
||||
*/
|
||||
void pstore_get_records(void)
|
||||
void pstore_get_records(int quiet)
|
||||
{
|
||||
struct pstore_info *psi = psinfo;
|
||||
ssize_t size;
|
||||
@ -168,36 +200,55 @@ void pstore_get_records(void)
|
||||
enum pstore_type_id type;
|
||||
struct timespec time;
|
||||
int failed = 0, rc;
|
||||
unsigned long flags;
|
||||
|
||||
if (!psi)
|
||||
return;
|
||||
|
||||
mutex_lock(&psinfo->buf_mutex);
|
||||
spin_lock_irqsave(&psinfo->buf_lock, flags);
|
||||
rc = psi->open(psi);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
while ((size = psi->read(&id, &type, &time, psi)) > 0) {
|
||||
if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size,
|
||||
time, psi))
|
||||
rc = pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size,
|
||||
time, psi);
|
||||
if (rc && (rc != -EEXIST || !quiet))
|
||||
failed++;
|
||||
}
|
||||
psi->close(psi);
|
||||
out:
|
||||
mutex_unlock(&psinfo->buf_mutex);
|
||||
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
|
||||
|
||||
if (failed)
|
||||
printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n",
|
||||
failed, psi->name);
|
||||
}
|
||||
|
||||
static void pstore_dowork(struct work_struct *work)
|
||||
{
|
||||
pstore_get_records(1);
|
||||
}
|
||||
|
||||
static void pstore_timefunc(unsigned long dummy)
|
||||
{
|
||||
if (pstore_new_entry) {
|
||||
pstore_new_entry = 0;
|
||||
schedule_work(&pstore_work);
|
||||
}
|
||||
|
||||
mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call platform driver to write a record to the
|
||||
* persistent store.
|
||||
*/
|
||||
int pstore_write(enum pstore_type_id type, char *buf, size_t size)
|
||||
{
|
||||
u64 id;
|
||||
u64 id;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (!psinfo)
|
||||
return -ENODEV;
|
||||
@ -205,13 +256,13 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size)
|
||||
if (size > psinfo->bufsize)
|
||||
return -EFBIG;
|
||||
|
||||
mutex_lock(&psinfo->buf_mutex);
|
||||
spin_lock_irqsave(&psinfo->buf_lock, flags);
|
||||
memcpy(psinfo->buf, buf, size);
|
||||
id = psinfo->write(type, 0, size, psinfo);
|
||||
if (pstore_is_mounted())
|
||||
ret = psinfo->write(type, &id, 0, size, psinfo);
|
||||
if (ret == 0 && pstore_is_mounted())
|
||||
pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf,
|
||||
size, CURRENT_TIME, psinfo);
|
||||
mutex_unlock(&psinfo->buf_mutex);
|
||||
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,15 +32,15 @@ enum pstore_type_id {
|
||||
struct pstore_info {
|
||||
struct module *owner;
|
||||
char *name;
|
||||
struct mutex buf_mutex; /* serialize access to 'buf' */
|
||||
spinlock_t buf_lock; /* serialize access to 'buf' */
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
int (*open)(struct pstore_info *psi);
|
||||
int (*close)(struct pstore_info *psi);
|
||||
ssize_t (*read)(u64 *id, enum pstore_type_id *type,
|
||||
struct timespec *time, struct pstore_info *psi);
|
||||
u64 (*write)(enum pstore_type_id type, unsigned int part,
|
||||
size_t size, struct pstore_info *psi);
|
||||
int (*write)(enum pstore_type_id type, u64 *id,
|
||||
unsigned int part, size_t size, struct pstore_info *psi);
|
||||
int (*erase)(enum pstore_type_id type, u64 id,
|
||||
struct pstore_info *psi);
|
||||
void *data;
|
||||
|
Loading…
Reference in New Issue
Block a user