aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/jffs2/compr.c9
-rw-r--r--fs/jffs2/fs.c2
-rw-r--r--fs/jffs2/jffs2_fs_sb.h6
-rw-r--r--fs/jffs2/os-linux.h2
-rw-r--r--fs/jffs2/super.c97
5 files changed, 112 insertions, 4 deletions
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c
index de4247021d25..97bc74db2c96 100644
--- a/fs/jffs2/compr.c
+++ b/fs/jffs2/compr.c
@@ -76,13 +76,18 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
76 uint32_t *datalen, uint32_t *cdatalen) 76 uint32_t *datalen, uint32_t *cdatalen)
77{ 77{
78 int ret = JFFS2_COMPR_NONE; 78 int ret = JFFS2_COMPR_NONE;
79 int compr_ret; 79 int mode, compr_ret;
80 struct jffs2_compressor *this, *best=NULL; 80 struct jffs2_compressor *this, *best=NULL;
81 unsigned char *output_buf = NULL, *tmp_buf; 81 unsigned char *output_buf = NULL, *tmp_buf;
82 uint32_t orig_slen, orig_dlen; 82 uint32_t orig_slen, orig_dlen;
83 uint32_t best_slen=0, best_dlen=0; 83 uint32_t best_slen=0, best_dlen=0;
84 84
85 switch (jffs2_compression_mode) { 85 if (c->mount_opts.override_compr)
86 mode = c->mount_opts.compr;
87 else
88 mode = jffs2_compression_mode;
89
90 switch (mode) {
86 case JFFS2_COMPR_MODE_NONE: 91 case JFFS2_COMPR_MODE_NONE:
87 break; 92 break;
88 case JFFS2_COMPR_MODE_PRIORITY: 93 case JFFS2_COMPR_MODE_PRIORITY:
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index bbcb9755dd2b..5d54b4ed1b6c 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -379,7 +379,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags)
379 jffs2_do_setattr(inode, &iattr); 379 jffs2_do_setattr(inode, &iattr);
380} 380}
381 381
382int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) 382int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data)
383{ 383{
384 struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 384 struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
385 385
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index 0bc6a6c80a56..55a0c1dceadf 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -29,6 +29,11 @@
29 29
30struct jffs2_inodirty; 30struct jffs2_inodirty;
31 31
32struct jffs2_mount_opts {
33 bool override_compr;
34 unsigned int compr;
35};
36
32/* A struct for the overall file system control. Pointers to 37/* A struct for the overall file system control. Pointers to
33 jffs2_sb_info structs are named `c' in the source code. 38 jffs2_sb_info structs are named `c' in the source code.
34 Nee jffs_control 39 Nee jffs_control
@@ -126,6 +131,7 @@ struct jffs2_sb_info {
126#endif 131#endif
127 132
128 struct jffs2_summary *summary; /* Summary information */ 133 struct jffs2_summary *summary; /* Summary information */
134 struct jffs2_mount_opts mount_opts;
129 135
130#ifdef CONFIG_JFFS2_FS_XATTR 136#ifdef CONFIG_JFFS2_FS_XATTR
131#define XATTRINDEX_HASHSIZE (57) 137#define XATTRINDEX_HASHSIZE (57)
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 6c1755c59c0f..ab65ee3ec858 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -176,7 +176,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags);
176struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, 176struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode,
177 struct jffs2_raw_inode *ri); 177 struct jffs2_raw_inode *ri);
178int jffs2_statfs (struct dentry *, struct kstatfs *); 178int jffs2_statfs (struct dentry *, struct kstatfs *);
179int jffs2_remount_fs (struct super_block *, int *, char *); 179int jffs2_do_remount_fs(struct super_block *, int *, char *);
180int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); 180int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
181void jffs2_gc_release_inode(struct jffs2_sb_info *c, 181void jffs2_gc_release_inode(struct jffs2_sb_info *c,
182 struct jffs2_inode_info *f); 182 struct jffs2_inode_info *f);
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);