aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/super.c
diff options
context:
space:
mode:
authorAndres Salomon <dilinger@queued.net>2011-10-16 21:15:16 -0400
committerArtem Bityutskiy <artem.bityutskiy@intel.com>2011-10-19 10:22:20 -0400
commit92abc475d8de1c29373f6d96ed63d8ecaa199d25 (patch)
tree44f4d9d04fd04ccee9877e28d8fff5e472bba7d2 /fs/jffs2/super.c
parent23b1a99b87f3fc9e4242b98b2af3c9bed210f048 (diff)
jffs2: implement mount option parsing and compression overriding
Currently jffs2 has compile-time constants (and .config options) controlling whether or not the various compression/decompression drivers are built in and enabled. This is fine for embedded systems, but it clashes with distribution kernels. Distro kernels tend to turn on everything; this causes OpenFirmware to fall over, as it understands ZLIB-compressed inodes. Booting a kernel that has LZO compression enabled, writing to the boot partition, and then rebooting causes OFW to fail to read the kernel from the filesystem. This is because LZO compression has priority when writing new data to jffs2, if LZO is enabled. This patch adds mount option parsing, and a single supported option ("compr=none"). This adds the flexibility of being able to specify which compressor overrides on a per-superblock basis. For now, we can simply disable compression; additional flexibility coming soon. v2: kill some printks, and implement show_options as suggested by Artem Bityutskiy. Signed-off-by: Andres Salomon <dilinger@queued.net> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@intel.com>
Diffstat (limited to 'fs/jffs2/super.c')
-rw-r--r--fs/jffs2/super.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 853b8e300084..40f6e6385fd1 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -17,11 +17,13 @@
17#include <linux/fs.h> 17#include <linux/fs.h>
18#include <linux/err.h> 18#include <linux/err.h>
19#include <linux/mount.h> 19#include <linux/mount.h>
20#include <linux/parser.h>
20#include <linux/jffs2.h> 21#include <linux/jffs2.h>
21#include <linux/pagemap.h> 22#include <linux/pagemap.h>
22#include <linux/mtd/super.h> 23#include <linux/mtd/super.h>
23#include <linux/ctype.h> 24#include <linux/ctype.h>
24#include <linux/namei.h> 25#include <linux/namei.h>
26#include <linux/seq_file.h>
25#include <linux/exportfs.h> 27#include <linux/exportfs.h>
26#include "compr.h" 28#include "compr.h"
27#include "nodelist.h" 29#include "nodelist.h"
@@ -75,6 +77,29 @@ static void jffs2_write_super(struct super_block *sb)
75 unlock_super(sb); 77 unlock_super(sb);
76} 78}
77 79
80static const char *jffs2_compr_name(unsigned int compr)
81{
82 switch (compr) {
83 case JFFS2_COMPR_MODE_NONE:
84 return "none";
85 default:
86 /* should never happen; programmer error */
87 WARN_ON(1);
88 return "";
89 }
90}
91
92static int jffs2_show_options(struct seq_file *s, struct vfsmount *mnt)
93{
94 struct jffs2_sb_info *c = JFFS2_SB_INFO(mnt->mnt_sb);
95 struct jffs2_mount_opts *opts = &c->mount_opts;
96
97 if (opts->override_compr)
98 seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
99
100 return 0;
101}
102
78static int jffs2_sync_fs(struct super_block *sb, int wait) 103static int jffs2_sync_fs(struct super_block *sb, int wait)
79{ 104{
80 struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 105 struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
@@ -133,6 +158,71 @@ static const struct export_operations jffs2_export_ops = {
133 .fh_to_parent = jffs2_fh_to_parent, 158 .fh_to_parent = jffs2_fh_to_parent,
134}; 159};
135 160
161/*
162 * JFFS2 mount options.
163 *
164 * Opt_override_compr: override default compressor
165 * Opt_err: just end of array marker
166 */
167enum {
168 Opt_override_compr,
169 Opt_err,
170};
171
172static const match_table_t tokens = {
173 {Opt_override_compr, "compr=%s"},
174 {Opt_err, NULL},
175};
176
177static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
178{
179 substring_t args[MAX_OPT_ARGS];
180 char *p, *name;
181
182 if (!data)
183 return 0;
184
185 while ((p = strsep(&data, ","))) {
186 int token;
187
188 if (!*p)
189 continue;
190
191 token = match_token(p, tokens, args);
192 switch (token) {
193 case Opt_override_compr:
194 name = match_strdup(&args[0]);
195
196 if (!name)
197 return -ENOMEM;
198 if (!strcmp(name, "none")) {
199 c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
200 c->mount_opts.override_compr = true;
201 }
202 kfree(name);
203 break;
204 default:
205 printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
206 p);
207 return -EINVAL;
208 }
209 }
210
211 return 0;
212}
213
214static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
215{
216 struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
217 int err;
218
219 err = jffs2_parse_options(c, data);
220 if (err)
221 return -EINVAL;
222
223 return jffs2_do_remount_fs(sb, flags, data);
224}
225
136static const struct super_operations jffs2_super_operations = 226static const struct super_operations jffs2_super_operations =
137{ 227{
138 .alloc_inode = jffs2_alloc_inode, 228 .alloc_inode = jffs2_alloc_inode,
@@ -143,6 +233,7 @@ static const struct super_operations jffs2_super_operations =
143 .remount_fs = jffs2_remount_fs, 233 .remount_fs = jffs2_remount_fs,
144 .evict_inode = jffs2_evict_inode, 234 .evict_inode = jffs2_evict_inode,
145 .dirty_inode = jffs2_dirty_inode, 235 .dirty_inode = jffs2_dirty_inode,
236 .show_options = jffs2_show_options,
146 .sync_fs = jffs2_sync_fs, 237 .sync_fs = jffs2_sync_fs,
147}; 238};
148 239
@@ -166,6 +257,12 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
166 c->os_priv = sb; 257 c->os_priv = sb;
167 sb->s_fs_info = c; 258 sb->s_fs_info = c;
168 259
260 ret = jffs2_parse_options(c, data);
261 if (ret) {
262 kfree(c);
263 return -EINVAL;
264 }
265
169 /* Initialize JFFS2 superblock locks, the further initialization will 266 /* Initialize JFFS2 superblock locks, the further initialization will
170 * be done later */ 267 * be done later */
171 mutex_init(&c->alloc_sem); 268 mutex_init(&c->alloc_sem);