diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-01 13:52:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-01 13:52:29 -0400 |
commit | 1c398651518c7e25a9fb3f08b456c73d5ca22469 (patch) | |
tree | 116ad4df5c8faa5f8e0d7982c479bf08ea01f2ec | |
parent | f470f8d4e702593ee1d0852871ad80373bce707b (diff) | |
parent | b238b8fa93353ab50c9a2b1e2fa47a0ab01c37cd (diff) |
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
-rw-r--r-- | drivers/acpi/apei/erst.c | 12 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 19 | ||||
-rw-r--r-- | fs/pstore/inode.c | 40 | ||||
-rw-r--r-- | fs/pstore/internal.h | 2 | ||||
-rw-r--r-- | fs/pstore/platform.c | 93 | ||||
-rw-r--r-- | include/linux/pstore.h | 6 |
6 files changed, 129 insertions, 43 deletions
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 2ca59dc69f7f..127408069ca7 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c | |||
@@ -933,7 +933,7 @@ static int erst_open_pstore(struct pstore_info *psi); | |||
933 | static int erst_close_pstore(struct pstore_info *psi); | 933 | static int erst_close_pstore(struct pstore_info *psi); |
934 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, | 934 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, |
935 | struct timespec *time, struct pstore_info *psi); | 935 | struct timespec *time, struct pstore_info *psi); |
936 | static u64 erst_writer(enum pstore_type_id type, unsigned int part, | 936 | static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, |
937 | size_t size, struct pstore_info *psi); | 937 | size_t size, struct pstore_info *psi); |
938 | static int erst_clearer(enum pstore_type_id type, u64 id, | 938 | static int erst_clearer(enum pstore_type_id type, u64 id, |
939 | struct pstore_info *psi); | 939 | struct pstore_info *psi); |
@@ -1040,11 +1040,12 @@ out: | |||
1040 | return (rc < 0) ? rc : (len - sizeof(*rcd)); | 1040 | return (rc < 0) ? rc : (len - sizeof(*rcd)); |
1041 | } | 1041 | } |
1042 | 1042 | ||
1043 | static u64 erst_writer(enum pstore_type_id type, unsigned int part, | 1043 | static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, |
1044 | size_t size, struct pstore_info *psi) | 1044 | size_t size, struct pstore_info *psi) |
1045 | { | 1045 | { |
1046 | struct cper_pstore_record *rcd = (struct cper_pstore_record *) | 1046 | struct cper_pstore_record *rcd = (struct cper_pstore_record *) |
1047 | (erst_info.buf - sizeof(*rcd)); | 1047 | (erst_info.buf - sizeof(*rcd)); |
1048 | int ret; | ||
1048 | 1049 | ||
1049 | memset(rcd, 0, sizeof(*rcd)); | 1050 | memset(rcd, 0, sizeof(*rcd)); |
1050 | memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE); | 1051 | 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, | |||
1079 | } | 1080 | } |
1080 | rcd->sec_hdr.section_severity = CPER_SEV_FATAL; | 1081 | rcd->sec_hdr.section_severity = CPER_SEV_FATAL; |
1081 | 1082 | ||
1082 | erst_write(&rcd->hdr); | 1083 | ret = erst_write(&rcd->hdr); |
1084 | *id = rcd->hdr.record_id; | ||
1083 | 1085 | ||
1084 | return rcd->hdr.record_id; | 1086 | return ret; |
1085 | } | 1087 | } |
1086 | 1088 | ||
1087 | static int erst_clearer(enum pstore_type_id type, u64 id, | 1089 | static int erst_clearer(enum pstore_type_id type, u64 id, |
@@ -1165,7 +1167,7 @@ static int __init erst_init(void) | |||
1165 | goto err_release_erange; | 1167 | goto err_release_erange; |
1166 | 1168 | ||
1167 | buf = kmalloc(erst_erange.size, GFP_KERNEL); | 1169 | buf = kmalloc(erst_erange.size, GFP_KERNEL); |
1168 | mutex_init(&erst_info.buf_mutex); | 1170 | spin_lock_init(&erst_info.buf_lock); |
1169 | if (buf) { | 1171 | if (buf) { |
1170 | erst_info.buf = buf + sizeof(struct cper_pstore_record); | 1172 | erst_info.buf = buf + sizeof(struct cper_pstore_record); |
1171 | erst_info.bufsize = erst_erange.size - | 1173 | erst_info.bufsize = erst_erange.size - |
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index eb80b549ed8d..8370f72d87ff 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
@@ -490,8 +490,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | |||
490 | return 0; | 490 | return 0; |
491 | } | 491 | } |
492 | 492 | ||
493 | static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, | 493 | static int efi_pstore_write(enum pstore_type_id type, u64 *id, |
494 | size_t size, struct pstore_info *psi) | 494 | unsigned int part, size_t size, struct pstore_info *psi) |
495 | { | 495 | { |
496 | char name[DUMP_NAME_LEN]; | 496 | char name[DUMP_NAME_LEN]; |
497 | char stub_name[DUMP_NAME_LEN]; | 497 | char stub_name[DUMP_NAME_LEN]; |
@@ -499,7 +499,7 @@ static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, | |||
499 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | 499 | efi_guid_t vendor = LINUX_EFI_CRASH_GUID; |
500 | struct efivars *efivars = psi->data; | 500 | struct efivars *efivars = psi->data; |
501 | struct efivar_entry *entry, *found = NULL; | 501 | struct efivar_entry *entry, *found = NULL; |
502 | int i; | 502 | int i, ret = 0; |
503 | 503 | ||
504 | sprintf(stub_name, "dump-type%u-%u-", type, part); | 504 | sprintf(stub_name, "dump-type%u-%u-", type, part); |
505 | sprintf(name, "%s%lu", stub_name, get_seconds()); | 505 | 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, | |||
548 | efivar_unregister(found); | 548 | efivar_unregister(found); |
549 | 549 | ||
550 | if (size) | 550 | if (size) |
551 | efivar_create_sysfs_entry(efivars, | 551 | ret = efivar_create_sysfs_entry(efivars, |
552 | utf16_strsize(efi_name, | 552 | utf16_strsize(efi_name, |
553 | DUMP_NAME_LEN * 2), | 553 | DUMP_NAME_LEN * 2), |
554 | efi_name, &vendor); | 554 | efi_name, &vendor); |
555 | 555 | ||
556 | return part; | 556 | *id = part; |
557 | return ret; | ||
557 | }; | 558 | }; |
558 | 559 | ||
559 | static int efi_pstore_erase(enum pstore_type_id type, u64 id, | 560 | static int efi_pstore_erase(enum pstore_type_id type, u64 id, |
560 | struct pstore_info *psi) | 561 | struct pstore_info *psi) |
561 | { | 562 | { |
562 | efi_pstore_write(type, id, 0, psi); | 563 | efi_pstore_write(type, &id, (unsigned int)id, 0, psi); |
563 | 564 | ||
564 | return 0; | 565 | return 0; |
565 | } | 566 | } |
@@ -580,8 +581,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | |||
580 | return -1; | 581 | return -1; |
581 | } | 582 | } |
582 | 583 | ||
583 | static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, | 584 | static int efi_pstore_write(enum pstore_type_id type, u64 *id, |
584 | size_t size, struct pstore_info *psi) | 585 | unsigned int part, size_t size, struct pstore_info *psi) |
585 | { | 586 | { |
586 | return 0; | 587 | return 0; |
587 | } | 588 | } |
@@ -978,7 +979,7 @@ int register_efivars(struct efivars *efivars, | |||
978 | if (efivars->efi_pstore_info.buf) { | 979 | if (efivars->efi_pstore_info.buf) { |
979 | efivars->efi_pstore_info.bufsize = 1024; | 980 | efivars->efi_pstore_info.bufsize = 1024; |
980 | efivars->efi_pstore_info.data = efivars; | 981 | efivars->efi_pstore_info.data = efivars; |
981 | mutex_init(&efivars->efi_pstore_info.buf_mutex); | 982 | spin_lock_init(&efivars->efi_pstore_info.buf_lock); |
982 | pstore_register(&efivars->efi_pstore_info); | 983 | pstore_register(&efivars->efi_pstore_info); |
983 | } | 984 | } |
984 | 985 | ||
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 893b961dcfd8..379a02dc1217 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/highmem.h> | 24 | #include <linux/highmem.h> |
25 | #include <linux/time.h> | 25 | #include <linux/time.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/list.h> | ||
27 | #include <linux/string.h> | 28 | #include <linux/string.h> |
28 | #include <linux/mount.h> | 29 | #include <linux/mount.h> |
29 | #include <linux/ramfs.h> | 30 | #include <linux/ramfs.h> |
@@ -32,13 +33,18 @@ | |||
32 | #include <linux/magic.h> | 33 | #include <linux/magic.h> |
33 | #include <linux/pstore.h> | 34 | #include <linux/pstore.h> |
34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/spinlock.h> | ||
35 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
36 | 38 | ||
37 | #include "internal.h" | 39 | #include "internal.h" |
38 | 40 | ||
39 | #define PSTORE_NAMELEN 64 | 41 | #define PSTORE_NAMELEN 64 |
40 | 42 | ||
43 | static DEFINE_SPINLOCK(allpstore_lock); | ||
44 | static LIST_HEAD(allpstore); | ||
45 | |||
41 | struct pstore_private { | 46 | struct pstore_private { |
47 | struct list_head list; | ||
42 | struct pstore_info *psi; | 48 | struct pstore_info *psi; |
43 | enum pstore_type_id type; | 49 | enum pstore_type_id type; |
44 | u64 id; | 50 | u64 id; |
@@ -81,8 +87,16 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry) | |||
81 | 87 | ||
82 | static void pstore_evict_inode(struct inode *inode) | 88 | static void pstore_evict_inode(struct inode *inode) |
83 | { | 89 | { |
90 | struct pstore_private *p = inode->i_private; | ||
91 | unsigned long flags; | ||
92 | |||
84 | end_writeback(inode); | 93 | end_writeback(inode); |
85 | kfree(inode->i_private); | 94 | if (p) { |
95 | spin_lock_irqsave(&allpstore_lock, flags); | ||
96 | list_del(&p->list); | ||
97 | spin_unlock_irqrestore(&allpstore_lock, flags); | ||
98 | kfree(p); | ||
99 | } | ||
86 | } | 100 | } |
87 | 101 | ||
88 | static const struct inode_operations pstore_dir_inode_operations = { | 102 | 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, | |||
182 | struct dentry *root = pstore_sb->s_root; | 196 | struct dentry *root = pstore_sb->s_root; |
183 | struct dentry *dentry; | 197 | struct dentry *dentry; |
184 | struct inode *inode; | 198 | struct inode *inode; |
185 | int rc; | 199 | int rc = 0; |
186 | char name[PSTORE_NAMELEN]; | 200 | char name[PSTORE_NAMELEN]; |
187 | struct pstore_private *private; | 201 | struct pstore_private *private, *pos; |
202 | unsigned long flags; | ||
203 | |||
204 | spin_lock_irqsave(&allpstore_lock, flags); | ||
205 | list_for_each_entry(pos, &allpstore, list) { | ||
206 | if (pos->type == type && | ||
207 | pos->id == id && | ||
208 | pos->psi == psi) { | ||
209 | rc = -EEXIST; | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | spin_unlock_irqrestore(&allpstore_lock, flags); | ||
214 | if (rc) | ||
215 | return rc; | ||
188 | 216 | ||
189 | rc = -ENOMEM; | 217 | rc = -ENOMEM; |
190 | inode = pstore_get_inode(pstore_sb, root->d_inode, S_IFREG | 0444, 0); | 218 | 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, | |||
229 | 257 | ||
230 | d_add(dentry, inode); | 258 | d_add(dentry, inode); |
231 | 259 | ||
260 | spin_lock_irqsave(&allpstore_lock, flags); | ||
261 | list_add(&private->list, &allpstore); | ||
262 | spin_unlock_irqrestore(&allpstore_lock, flags); | ||
263 | |||
232 | mutex_unlock(&root->d_inode->i_mutex); | 264 | mutex_unlock(&root->d_inode->i_mutex); |
233 | 265 | ||
234 | return 0; | 266 | return 0; |
@@ -277,7 +309,7 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent) | |||
277 | goto fail; | 309 | goto fail; |
278 | } | 310 | } |
279 | 311 | ||
280 | pstore_get_records(); | 312 | pstore_get_records(0); |
281 | 313 | ||
282 | return 0; | 314 | return 0; |
283 | fail: | 315 | fail: |
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 611c1b3c46fa..3bde461c3f34 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h | |||
@@ -1,5 +1,5 @@ | |||
1 | extern void pstore_set_kmsg_bytes(int); | 1 | extern void pstore_set_kmsg_bytes(int); |
2 | extern void pstore_get_records(void); | 2 | extern void pstore_get_records(int); |
3 | extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, | 3 | extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, |
4 | char *data, size_t size, | 4 | char *data, size_t size, |
5 | struct timespec time, struct pstore_info *psi); | 5 | struct timespec time, struct pstore_info *psi); |
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index c5300ec31696..2bd620f0d796 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c | |||
@@ -25,12 +25,30 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/pstore.h> | 26 | #include <linux/pstore.h> |
27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/timer.h> | ||
28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
29 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/hardirq.h> | ||
32 | #include <linux/workqueue.h> | ||
30 | 33 | ||
31 | #include "internal.h" | 34 | #include "internal.h" |
32 | 35 | ||
33 | /* | 36 | /* |
37 | * We defer making "oops" entries appear in pstore - see | ||
38 | * whether the system is actually still running well enough | ||
39 | * to let someone see the entry | ||
40 | */ | ||
41 | #define PSTORE_INTERVAL (60 * HZ) | ||
42 | |||
43 | static int pstore_new_entry; | ||
44 | |||
45 | static void pstore_timefunc(unsigned long); | ||
46 | static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0); | ||
47 | |||
48 | static void pstore_dowork(struct work_struct *); | ||
49 | static DECLARE_WORK(pstore_work, pstore_dowork); | ||
50 | |||
51 | /* | ||
34 | * pstore_lock just protects "psinfo" during | 52 | * pstore_lock just protects "psinfo" during |
35 | * calls to pstore_register() | 53 | * calls to pstore_register() |
36 | */ | 54 | */ |
@@ -69,15 +87,22 @@ static void pstore_dump(struct kmsg_dumper *dumper, | |||
69 | unsigned long size, total = 0; | 87 | unsigned long size, total = 0; |
70 | char *dst, *why; | 88 | char *dst, *why; |
71 | u64 id; | 89 | u64 id; |
72 | int hsize; | 90 | int hsize, ret; |
73 | unsigned int part = 1; | 91 | unsigned int part = 1; |
92 | unsigned long flags = 0; | ||
93 | int is_locked = 0; | ||
74 | 94 | ||
75 | if (reason < ARRAY_SIZE(reason_str)) | 95 | if (reason < ARRAY_SIZE(reason_str)) |
76 | why = reason_str[reason]; | 96 | why = reason_str[reason]; |
77 | else | 97 | else |
78 | why = "Unknown"; | 98 | why = "Unknown"; |
79 | 99 | ||
80 | mutex_lock(&psinfo->buf_mutex); | 100 | if (in_nmi()) { |
101 | is_locked = spin_trylock(&psinfo->buf_lock); | ||
102 | if (!is_locked) | ||
103 | pr_err("pstore dump routine blocked in NMI, may corrupt error record\n"); | ||
104 | } else | ||
105 | spin_lock_irqsave(&psinfo->buf_lock, flags); | ||
81 | oopscount++; | 106 | oopscount++; |
82 | while (total < kmsg_bytes) { | 107 | while (total < kmsg_bytes) { |
83 | dst = psinfo->buf; | 108 | dst = psinfo->buf; |
@@ -97,18 +122,20 @@ static void pstore_dump(struct kmsg_dumper *dumper, | |||
97 | memcpy(dst, s1 + s1_start, l1_cpy); | 122 | memcpy(dst, s1 + s1_start, l1_cpy); |
98 | memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); | 123 | memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); |
99 | 124 | ||
100 | id = psinfo->write(PSTORE_TYPE_DMESG, part, | 125 | ret = psinfo->write(PSTORE_TYPE_DMESG, &id, part, |
101 | hsize + l1_cpy + l2_cpy, psinfo); | 126 | hsize + l1_cpy + l2_cpy, psinfo); |
102 | if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) | 127 | if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) |
103 | pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, | 128 | pstore_new_entry = 1; |
104 | psinfo->buf, hsize + l1_cpy + l2_cpy, | ||
105 | CURRENT_TIME, psinfo); | ||
106 | l1 -= l1_cpy; | 129 | l1 -= l1_cpy; |
107 | l2 -= l2_cpy; | 130 | l2 -= l2_cpy; |
108 | total += l1_cpy + l2_cpy; | 131 | total += l1_cpy + l2_cpy; |
109 | part++; | 132 | part++; |
110 | } | 133 | } |
111 | mutex_unlock(&psinfo->buf_mutex); | 134 | if (in_nmi()) { |
135 | if (is_locked) | ||
136 | spin_unlock(&psinfo->buf_lock); | ||
137 | } else | ||
138 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); | ||
112 | } | 139 | } |
113 | 140 | ||
114 | static struct kmsg_dumper pstore_dumper = { | 141 | static struct kmsg_dumper pstore_dumper = { |
@@ -148,19 +175,24 @@ int pstore_register(struct pstore_info *psi) | |||
148 | } | 175 | } |
149 | 176 | ||
150 | if (pstore_is_mounted()) | 177 | if (pstore_is_mounted()) |
151 | pstore_get_records(); | 178 | pstore_get_records(0); |
152 | 179 | ||
153 | kmsg_dump_register(&pstore_dumper); | 180 | kmsg_dump_register(&pstore_dumper); |
154 | 181 | ||
182 | pstore_timer.expires = jiffies + PSTORE_INTERVAL; | ||
183 | add_timer(&pstore_timer); | ||
184 | |||
155 | return 0; | 185 | return 0; |
156 | } | 186 | } |
157 | EXPORT_SYMBOL_GPL(pstore_register); | 187 | EXPORT_SYMBOL_GPL(pstore_register); |
158 | 188 | ||
159 | /* | 189 | /* |
160 | * Read all the records from the persistent store. Create and | 190 | * Read all the records from the persistent store. Create |
161 | * file files in our filesystem. | 191 | * files in our filesystem. Don't warn about -EEXIST errors |
192 | * when we are re-scanning the backing store looking to add new | ||
193 | * error records. | ||
162 | */ | 194 | */ |
163 | void pstore_get_records(void) | 195 | void pstore_get_records(int quiet) |
164 | { | 196 | { |
165 | struct pstore_info *psi = psinfo; | 197 | struct pstore_info *psi = psinfo; |
166 | ssize_t size; | 198 | ssize_t size; |
@@ -168,36 +200,55 @@ void pstore_get_records(void) | |||
168 | enum pstore_type_id type; | 200 | enum pstore_type_id type; |
169 | struct timespec time; | 201 | struct timespec time; |
170 | int failed = 0, rc; | 202 | int failed = 0, rc; |
203 | unsigned long flags; | ||
171 | 204 | ||
172 | if (!psi) | 205 | if (!psi) |
173 | return; | 206 | return; |
174 | 207 | ||
175 | mutex_lock(&psinfo->buf_mutex); | 208 | spin_lock_irqsave(&psinfo->buf_lock, flags); |
176 | rc = psi->open(psi); | 209 | rc = psi->open(psi); |
177 | if (rc) | 210 | if (rc) |
178 | goto out; | 211 | goto out; |
179 | 212 | ||
180 | while ((size = psi->read(&id, &type, &time, psi)) > 0) { | 213 | while ((size = psi->read(&id, &type, &time, psi)) > 0) { |
181 | if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, | 214 | rc = pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, |
182 | time, psi)) | 215 | time, psi); |
216 | if (rc && (rc != -EEXIST || !quiet)) | ||
183 | failed++; | 217 | failed++; |
184 | } | 218 | } |
185 | psi->close(psi); | 219 | psi->close(psi); |
186 | out: | 220 | out: |
187 | mutex_unlock(&psinfo->buf_mutex); | 221 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); |
188 | 222 | ||
189 | if (failed) | 223 | if (failed) |
190 | printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n", | 224 | printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n", |
191 | failed, psi->name); | 225 | failed, psi->name); |
192 | } | 226 | } |
193 | 227 | ||
228 | static void pstore_dowork(struct work_struct *work) | ||
229 | { | ||
230 | pstore_get_records(1); | ||
231 | } | ||
232 | |||
233 | static void pstore_timefunc(unsigned long dummy) | ||
234 | { | ||
235 | if (pstore_new_entry) { | ||
236 | pstore_new_entry = 0; | ||
237 | schedule_work(&pstore_work); | ||
238 | } | ||
239 | |||
240 | mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL); | ||
241 | } | ||
242 | |||
194 | /* | 243 | /* |
195 | * Call platform driver to write a record to the | 244 | * Call platform driver to write a record to the |
196 | * persistent store. | 245 | * persistent store. |
197 | */ | 246 | */ |
198 | int pstore_write(enum pstore_type_id type, char *buf, size_t size) | 247 | int pstore_write(enum pstore_type_id type, char *buf, size_t size) |
199 | { | 248 | { |
200 | u64 id; | 249 | u64 id; |
250 | int ret; | ||
251 | unsigned long flags; | ||
201 | 252 | ||
202 | if (!psinfo) | 253 | if (!psinfo) |
203 | return -ENODEV; | 254 | return -ENODEV; |
@@ -205,13 +256,13 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size) | |||
205 | if (size > psinfo->bufsize) | 256 | if (size > psinfo->bufsize) |
206 | return -EFBIG; | 257 | return -EFBIG; |
207 | 258 | ||
208 | mutex_lock(&psinfo->buf_mutex); | 259 | spin_lock_irqsave(&psinfo->buf_lock, flags); |
209 | memcpy(psinfo->buf, buf, size); | 260 | memcpy(psinfo->buf, buf, size); |
210 | id = psinfo->write(type, 0, size, psinfo); | 261 | ret = psinfo->write(type, &id, 0, size, psinfo); |
211 | if (pstore_is_mounted()) | 262 | if (ret == 0 && pstore_is_mounted()) |
212 | pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, | 263 | pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, |
213 | size, CURRENT_TIME, psinfo); | 264 | size, CURRENT_TIME, psinfo); |
214 | mutex_unlock(&psinfo->buf_mutex); | 265 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); |
215 | 266 | ||
216 | return 0; | 267 | return 0; |
217 | } | 268 | } |
diff --git a/include/linux/pstore.h b/include/linux/pstore.h index cc03bbf5c4b8..ea567321ae3c 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h | |||
@@ -32,15 +32,15 @@ enum pstore_type_id { | |||
32 | struct pstore_info { | 32 | struct pstore_info { |
33 | struct module *owner; | 33 | struct module *owner; |
34 | char *name; | 34 | char *name; |
35 | struct mutex buf_mutex; /* serialize access to 'buf' */ | 35 | spinlock_t buf_lock; /* serialize access to 'buf' */ |
36 | char *buf; | 36 | char *buf; |
37 | size_t bufsize; | 37 | size_t bufsize; |
38 | int (*open)(struct pstore_info *psi); | 38 | int (*open)(struct pstore_info *psi); |
39 | int (*close)(struct pstore_info *psi); | 39 | int (*close)(struct pstore_info *psi); |
40 | ssize_t (*read)(u64 *id, enum pstore_type_id *type, | 40 | ssize_t (*read)(u64 *id, enum pstore_type_id *type, |
41 | struct timespec *time, struct pstore_info *psi); | 41 | struct timespec *time, struct pstore_info *psi); |
42 | u64 (*write)(enum pstore_type_id type, unsigned int part, | 42 | int (*write)(enum pstore_type_id type, u64 *id, |
43 | size_t size, struct pstore_info *psi); | 43 | unsigned int part, size_t size, struct pstore_info *psi); |
44 | int (*erase)(enum pstore_type_id type, u64 id, | 44 | int (*erase)(enum pstore_type_id type, u64 id, |
45 | struct pstore_info *psi); | 45 | struct pstore_info *psi); |
46 | void *data; | 46 | void *data; |