aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pstore
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2011-04-13 07:32:28 -0400
committerPatrick McHardy <kaber@trash.net>2011-04-13 07:32:28 -0400
commitb32e3dc7860d00124fa432dba09667e647cb9bcc (patch)
tree2fa6e56f389431dfb84609d3d7572cad76e88e71 /fs/pstore
parent6604271c5bc658a6067ed0c3deba4d89e0e50382 (diff)
parent96120d86fe302c006259baee9061eea9e1b9e486 (diff)
Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6
Diffstat (limited to 'fs/pstore')
-rw-r--r--fs/pstore/inode.c76
-rw-r--r--fs/pstore/internal.h3
-rw-r--r--fs/pstore/platform.c31
3 files changed, 69 insertions, 41 deletions
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 08342232cb1c..977ed2723845 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -27,6 +27,7 @@
27#include <linux/string.h> 27#include <linux/string.h>
28#include <linux/mount.h> 28#include <linux/mount.h>
29#include <linux/ramfs.h> 29#include <linux/ramfs.h>
30#include <linux/parser.h>
30#include <linux/sched.h> 31#include <linux/sched.h>
31#include <linux/magic.h> 32#include <linux/magic.h>
32#include <linux/pstore.h> 33#include <linux/pstore.h>
@@ -73,11 +74,16 @@ static int pstore_unlink(struct inode *dir, struct dentry *dentry)
73 struct pstore_private *p = dentry->d_inode->i_private; 74 struct pstore_private *p = dentry->d_inode->i_private;
74 75
75 p->erase(p->id); 76 p->erase(p->id);
76 kfree(p);
77 77
78 return simple_unlink(dir, dentry); 78 return simple_unlink(dir, dentry);
79} 79}
80 80
81static void pstore_evict_inode(struct inode *inode)
82{
83 end_writeback(inode);
84 kfree(inode->i_private);
85}
86
81static const struct inode_operations pstore_dir_inode_operations = { 87static const struct inode_operations pstore_dir_inode_operations = {
82 .lookup = simple_lookup, 88 .lookup = simple_lookup,
83 .unlink = pstore_unlink, 89 .unlink = pstore_unlink,
@@ -107,9 +113,52 @@ static struct inode *pstore_get_inode(struct super_block *sb,
107 return inode; 113 return inode;
108} 114}
109 115
116enum {
117 Opt_kmsg_bytes, Opt_err
118};
119
120static const match_table_t tokens = {
121 {Opt_kmsg_bytes, "kmsg_bytes=%u"},
122 {Opt_err, NULL}
123};
124
125static void parse_options(char *options)
126{
127 char *p;
128 substring_t args[MAX_OPT_ARGS];
129 int option;
130
131 if (!options)
132 return;
133
134 while ((p = strsep(&options, ",")) != NULL) {
135 int token;
136
137 if (!*p)
138 continue;
139
140 token = match_token(p, tokens, args);
141 switch (token) {
142 case Opt_kmsg_bytes:
143 if (!match_int(&args[0], &option))
144 pstore_set_kmsg_bytes(option);
145 break;
146 }
147 }
148}
149
150static int pstore_remount(struct super_block *sb, int *flags, char *data)
151{
152 parse_options(data);
153
154 return 0;
155}
156
110static const struct super_operations pstore_ops = { 157static const struct super_operations pstore_ops = {
111 .statfs = simple_statfs, 158 .statfs = simple_statfs,
112 .drop_inode = generic_delete_inode, 159 .drop_inode = generic_delete_inode,
160 .evict_inode = pstore_evict_inode,
161 .remount_fs = pstore_remount,
113 .show_options = generic_show_options, 162 .show_options = generic_show_options,
114}; 163};
115 164
@@ -209,6 +258,8 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent)
209 sb->s_op = &pstore_ops; 258 sb->s_op = &pstore_ops;
210 sb->s_time_gran = 1; 259 sb->s_time_gran = 1;
211 260
261 parse_options(data);
262
212 inode = pstore_get_inode(sb, NULL, S_IFDIR | 0755, 0); 263 inode = pstore_get_inode(sb, NULL, S_IFDIR | 0755, 0);
213 if (!inode) { 264 if (!inode) {
214 err = -ENOMEM; 265 err = -ENOMEM;
@@ -252,28 +303,7 @@ static struct file_system_type pstore_fs_type = {
252 303
253static int __init init_pstore_fs(void) 304static int __init init_pstore_fs(void)
254{ 305{
255 int rc = 0; 306 return register_filesystem(&pstore_fs_type);
256 struct kobject *pstorefs_kobj;
257
258 pstorefs_kobj = kobject_create_and_add("pstore", fs_kobj);
259 if (!pstorefs_kobj) {
260 rc = -ENOMEM;
261 goto done;
262 }
263
264 rc = sysfs_create_file(pstorefs_kobj, &pstore_kmsg_bytes_attr.attr);
265 if (rc)
266 goto done1;
267
268 rc = register_filesystem(&pstore_fs_type);
269 if (rc == 0)
270 goto done;
271
272 sysfs_remove_file(pstorefs_kobj, &pstore_kmsg_bytes_attr.attr);
273done1:
274 kobject_put(pstorefs_kobj);
275done:
276 return rc;
277} 307}
278module_init(init_pstore_fs) 308module_init(init_pstore_fs)
279 309
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 76c26d2fab29..8c9f23eb1645 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -1,7 +1,6 @@
1extern void pstore_set_kmsg_bytes(int);
1extern void pstore_get_records(void); 2extern void pstore_get_records(void);
2extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, 3extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
3 char *data, size_t size, 4 char *data, size_t size,
4 struct timespec time, int (*erase)(u64)); 5 struct timespec time, int (*erase)(u64));
5extern int pstore_is_mounted(void); 6extern int pstore_is_mounted(void);
6
7extern struct kobj_attribute pstore_kmsg_bytes_attr;
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 705fdf8abf6e..f835a25625ff 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -37,27 +37,21 @@
37static DEFINE_SPINLOCK(pstore_lock); 37static DEFINE_SPINLOCK(pstore_lock);
38static struct pstore_info *psinfo; 38static struct pstore_info *psinfo;
39 39
40/* How much of the console log to snapshot. /sys/fs/pstore/kmsg_bytes */ 40/* How much of the console log to snapshot */
41static unsigned long kmsg_bytes = 10240; 41static unsigned long kmsg_bytes = 10240;
42 42
43static ssize_t b_show(struct kobject *kobj, 43void pstore_set_kmsg_bytes(int bytes)
44 struct kobj_attribute *attr, char *buf)
45{ 44{
46 return snprintf(buf, PAGE_SIZE, "%lu\n", kmsg_bytes); 45 kmsg_bytes = bytes;
47} 46}
48 47
49static ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr,
50 const char *buf, size_t count)
51{
52 return (sscanf(buf, "%lu", &kmsg_bytes) > 0) ? count : 0;
53}
54
55struct kobj_attribute pstore_kmsg_bytes_attr =
56 __ATTR(kmsg_bytes, S_IRUGO | S_IWUSR, b_show, b_store);
57
58/* Tag each group of saved records with a sequence number */ 48/* Tag each group of saved records with a sequence number */
59static int oopscount; 49static int oopscount;
60 50
51static char *reason_str[] = {
52 "Oops", "Panic", "Kexec", "Restart", "Halt", "Poweroff", "Emergency"
53};
54
61/* 55/*
62 * callback from kmsg_dump. (s2,l2) has the most recently 56 * callback from kmsg_dump. (s2,l2) has the most recently
63 * written bytes, older bytes are in (s1,l1). Save as much 57 * written bytes, older bytes are in (s1,l1). Save as much
@@ -71,15 +65,20 @@ static void pstore_dump(struct kmsg_dumper *dumper,
71 unsigned long s1_start, s2_start; 65 unsigned long s1_start, s2_start;
72 unsigned long l1_cpy, l2_cpy; 66 unsigned long l1_cpy, l2_cpy;
73 unsigned long size, total = 0; 67 unsigned long size, total = 0;
74 char *dst; 68 char *dst, *why;
75 u64 id; 69 u64 id;
76 int hsize, part = 1; 70 int hsize, part = 1;
77 71
72 if (reason < ARRAY_SIZE(reason_str))
73 why = reason_str[reason];
74 else
75 why = "Unknown";
76
78 mutex_lock(&psinfo->buf_mutex); 77 mutex_lock(&psinfo->buf_mutex);
79 oopscount++; 78 oopscount++;
80 while (total < kmsg_bytes) { 79 while (total < kmsg_bytes) {
81 dst = psinfo->buf; 80 dst = psinfo->buf;
82 hsize = sprintf(dst, "Oops#%d Part%d\n", oopscount, part++); 81 hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part++);
83 size = psinfo->bufsize - hsize; 82 size = psinfo->bufsize - hsize;
84 dst += hsize; 83 dst += hsize;
85 84
@@ -96,7 +95,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
96 memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); 95 memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy);
97 96
98 id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy); 97 id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy);
99 if (pstore_is_mounted()) 98 if (reason == KMSG_DUMP_OOPS && pstore_is_mounted())
100 pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, 99 pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id,
101 psinfo->buf, hsize + l1_cpy + l2_cpy, 100 psinfo->buf, hsize + l1_cpy + l2_cpy,
102 CURRENT_TIME, psinfo->erase); 101 CURRENT_TIME, psinfo->erase);