diff options
Diffstat (limited to 'fs/pstore')
-rw-r--r-- | fs/pstore/inode.c | 40 | ||||
-rw-r--r-- | fs/pstore/internal.h | 2 | ||||
-rw-r--r-- | fs/pstore/platform.c | 54 |
3 files changed, 82 insertions, 14 deletions
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..ca60ebcfb15f 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c | |||
@@ -25,12 +25,29 @@ | |||
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/workqueue.h> | ||
30 | 32 | ||
31 | #include "internal.h" | 33 | #include "internal.h" |
32 | 34 | ||
33 | /* | 35 | /* |
36 | * We defer making "oops" entries appear in pstore - see | ||
37 | * whether the system is actually still running well enough | ||
38 | * to let someone see the entry | ||
39 | */ | ||
40 | #define PSTORE_INTERVAL (60 * HZ) | ||
41 | |||
42 | static int pstore_new_entry; | ||
43 | |||
44 | static void pstore_timefunc(unsigned long); | ||
45 | static DEFINE_TIMER(pstore_timer, pstore_timefunc, 0, 0); | ||
46 | |||
47 | static void pstore_dowork(struct work_struct *); | ||
48 | static DECLARE_WORK(pstore_work, pstore_dowork); | ||
49 | |||
50 | /* | ||
34 | * pstore_lock just protects "psinfo" during | 51 | * pstore_lock just protects "psinfo" during |
35 | * calls to pstore_register() | 52 | * calls to pstore_register() |
36 | */ | 53 | */ |
@@ -100,9 +117,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, | |||
100 | id = psinfo->write(PSTORE_TYPE_DMESG, part, | 117 | id = psinfo->write(PSTORE_TYPE_DMESG, part, |
101 | hsize + l1_cpy + l2_cpy, psinfo); | 118 | hsize + l1_cpy + l2_cpy, psinfo); |
102 | if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) | 119 | if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) |
103 | pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, | 120 | pstore_new_entry = 1; |
104 | psinfo->buf, hsize + l1_cpy + l2_cpy, | ||
105 | CURRENT_TIME, psinfo); | ||
106 | l1 -= l1_cpy; | 121 | l1 -= l1_cpy; |
107 | l2 -= l2_cpy; | 122 | l2 -= l2_cpy; |
108 | total += l1_cpy + l2_cpy; | 123 | total += l1_cpy + l2_cpy; |
@@ -148,19 +163,24 @@ int pstore_register(struct pstore_info *psi) | |||
148 | } | 163 | } |
149 | 164 | ||
150 | if (pstore_is_mounted()) | 165 | if (pstore_is_mounted()) |
151 | pstore_get_records(); | 166 | pstore_get_records(0); |
152 | 167 | ||
153 | kmsg_dump_register(&pstore_dumper); | 168 | kmsg_dump_register(&pstore_dumper); |
154 | 169 | ||
170 | pstore_timer.expires = jiffies + PSTORE_INTERVAL; | ||
171 | add_timer(&pstore_timer); | ||
172 | |||
155 | return 0; | 173 | return 0; |
156 | } | 174 | } |
157 | EXPORT_SYMBOL_GPL(pstore_register); | 175 | EXPORT_SYMBOL_GPL(pstore_register); |
158 | 176 | ||
159 | /* | 177 | /* |
160 | * Read all the records from the persistent store. Create and | 178 | * Read all the records from the persistent store. Create |
161 | * file files in our filesystem. | 179 | * files in our filesystem. Don't warn about -EEXIST errors |
180 | * when we are re-scanning the backing store looking to add new | ||
181 | * error records. | ||
162 | */ | 182 | */ |
163 | void pstore_get_records(void) | 183 | void pstore_get_records(int quiet) |
164 | { | 184 | { |
165 | struct pstore_info *psi = psinfo; | 185 | struct pstore_info *psi = psinfo; |
166 | ssize_t size; | 186 | ssize_t size; |
@@ -178,8 +198,9 @@ void pstore_get_records(void) | |||
178 | goto out; | 198 | goto out; |
179 | 199 | ||
180 | while ((size = psi->read(&id, &type, &time, psi)) > 0) { | 200 | while ((size = psi->read(&id, &type, &time, psi)) > 0) { |
181 | if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, | 201 | rc = pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, |
182 | time, psi)) | 202 | time, psi); |
203 | if (rc && (rc != -EEXIST || !quiet)) | ||
183 | failed++; | 204 | failed++; |
184 | } | 205 | } |
185 | psi->close(psi); | 206 | psi->close(psi); |
@@ -191,6 +212,21 @@ out: | |||
191 | failed, psi->name); | 212 | failed, psi->name); |
192 | } | 213 | } |
193 | 214 | ||
215 | static void pstore_dowork(struct work_struct *work) | ||
216 | { | ||
217 | pstore_get_records(1); | ||
218 | } | ||
219 | |||
220 | static void pstore_timefunc(unsigned long dummy) | ||
221 | { | ||
222 | if (pstore_new_entry) { | ||
223 | pstore_new_entry = 0; | ||
224 | schedule_work(&pstore_work); | ||
225 | } | ||
226 | |||
227 | mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL); | ||
228 | } | ||
229 | |||
194 | /* | 230 | /* |
195 | * Call platform driver to write a record to the | 231 | * Call platform driver to write a record to the |
196 | * persistent store. | 232 | * persistent store. |