diff options
author | Patrick McHardy <kaber@trash.net> | 2011-04-13 07:32:28 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-04-13 07:32:28 -0400 |
commit | b32e3dc7860d00124fa432dba09667e647cb9bcc (patch) | |
tree | 2fa6e56f389431dfb84609d3d7572cad76e88e71 /fs/pstore | |
parent | 6604271c5bc658a6067ed0c3deba4d89e0e50382 (diff) | |
parent | 96120d86fe302c006259baee9061eea9e1b9e486 (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.c | 76 | ||||
-rw-r--r-- | fs/pstore/internal.h | 3 | ||||
-rw-r--r-- | fs/pstore/platform.c | 31 |
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 | ||
81 | static void pstore_evict_inode(struct inode *inode) | ||
82 | { | ||
83 | end_writeback(inode); | ||
84 | kfree(inode->i_private); | ||
85 | } | ||
86 | |||
81 | static const struct inode_operations pstore_dir_inode_operations = { | 87 | static 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 | ||
116 | enum { | ||
117 | Opt_kmsg_bytes, Opt_err | ||
118 | }; | ||
119 | |||
120 | static const match_table_t tokens = { | ||
121 | {Opt_kmsg_bytes, "kmsg_bytes=%u"}, | ||
122 | {Opt_err, NULL} | ||
123 | }; | ||
124 | |||
125 | static 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 | |||
150 | static int pstore_remount(struct super_block *sb, int *flags, char *data) | ||
151 | { | ||
152 | parse_options(data); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
110 | static const struct super_operations pstore_ops = { | 157 | static 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 | ||
253 | static int __init init_pstore_fs(void) | 304 | static 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); | ||
273 | done1: | ||
274 | kobject_put(pstorefs_kobj); | ||
275 | done: | ||
276 | return rc; | ||
277 | } | 307 | } |
278 | module_init(init_pstore_fs) | 308 | module_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 @@ | |||
1 | extern void pstore_set_kmsg_bytes(int); | ||
1 | extern void pstore_get_records(void); | 2 | extern void pstore_get_records(void); |
2 | 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, |
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)); |
5 | extern int pstore_is_mounted(void); | 6 | extern int pstore_is_mounted(void); |
6 | |||
7 | extern 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 @@ | |||
37 | static DEFINE_SPINLOCK(pstore_lock); | 37 | static DEFINE_SPINLOCK(pstore_lock); |
38 | static struct pstore_info *psinfo; | 38 | static 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 */ |
41 | static unsigned long kmsg_bytes = 10240; | 41 | static unsigned long kmsg_bytes = 10240; |
42 | 42 | ||
43 | static ssize_t b_show(struct kobject *kobj, | 43 | void 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 | ||
49 | static 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 | |||
55 | struct 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 */ |
59 | static int oopscount; | 49 | static int oopscount; |
60 | 50 | ||
51 | static 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); |