diff options
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/jffs2_fs_sb.h | 7 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 42 | ||||
-rw-r--r-- | fs/jffs2/super.c | 17 |
3 files changed, 66 insertions, 0 deletions
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 55a0c1dceadf..0d00bf26923b 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
@@ -32,6 +32,13 @@ struct jffs2_inodirty; | |||
32 | struct jffs2_mount_opts { | 32 | struct jffs2_mount_opts { |
33 | bool override_compr; | 33 | bool override_compr; |
34 | unsigned int compr; | 34 | unsigned int compr; |
35 | |||
36 | /* The size of the reserved pool. The reserved pool is the JFFS2 flash | ||
37 | * space which may only be used by root cannot be used by the other | ||
38 | * users. This is implemented simply by means of not allowing the | ||
39 | * latter users to write to the file system if the amount if the | ||
40 | * available space is less then 'rp_size'. */ | ||
41 | unsigned int rp_size; | ||
35 | }; | 42 | }; |
36 | 43 | ||
37 | /* A struct for the overall file system control. Pointers to | 44 | /* A struct for the overall file system control. Pointers to |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 6784d1e7a7eb..0c96eb52c797 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -18,6 +18,37 @@ | |||
18 | #include "nodelist.h" | 18 | #include "nodelist.h" |
19 | #include "debug.h" | 19 | #include "debug.h" |
20 | 20 | ||
21 | /* | ||
22 | * Check whether the user is allowed to write. | ||
23 | */ | ||
24 | static int jffs2_rp_can_write(struct jffs2_sb_info *c) | ||
25 | { | ||
26 | uint32_t avail; | ||
27 | struct jffs2_mount_opts *opts = &c->mount_opts; | ||
28 | |||
29 | avail = c->dirty_size + c->free_size + c->unchecked_size + | ||
30 | c->erasing_size - c->resv_blocks_write * c->sector_size | ||
31 | - c->nospc_dirty_size; | ||
32 | |||
33 | if (avail < 2 * opts->rp_size) | ||
34 | jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, " | ||
35 | "erasing_size %u, unchecked_size %u, " | ||
36 | "nr_erasing_blocks %u, avail %u, resrv %u\n", | ||
37 | opts->rp_size, c->dirty_size, c->free_size, | ||
38 | c->erasing_size, c->unchecked_size, | ||
39 | c->nr_erasing_blocks, avail, c->nospc_dirty_size); | ||
40 | |||
41 | if (avail > opts->rp_size) | ||
42 | return 1; | ||
43 | |||
44 | /* Always allow root */ | ||
45 | if (capable(CAP_SYS_RESOURCE)) | ||
46 | return 1; | ||
47 | |||
48 | jffs2_dbg(1, "forbid writing\n"); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
21 | /** | 52 | /** |
22 | * jffs2_reserve_space - request physical space to write nodes to flash | 53 | * jffs2_reserve_space - request physical space to write nodes to flash |
23 | * @c: superblock info | 54 | * @c: superblock info |
@@ -55,6 +86,15 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
55 | 86 | ||
56 | spin_lock(&c->erase_completion_lock); | 87 | spin_lock(&c->erase_completion_lock); |
57 | 88 | ||
89 | /* | ||
90 | * Check if the free space is greater then size of the reserved pool. | ||
91 | * If not, only allow root to proceed with writing. | ||
92 | */ | ||
93 | if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) { | ||
94 | ret = -ENOSPC; | ||
95 | goto out; | ||
96 | } | ||
97 | |||
58 | /* this needs a little more thought (true <tglx> :)) */ | 98 | /* this needs a little more thought (true <tglx> :)) */ |
59 | while(ret == -EAGAIN) { | 99 | while(ret == -EAGAIN) { |
60 | while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { | 100 | while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { |
@@ -158,6 +198,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
158 | jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret); | 198 | jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret); |
159 | } | 199 | } |
160 | } | 200 | } |
201 | |||
202 | out: | ||
161 | spin_unlock(&c->erase_completion_lock); | 203 | spin_unlock(&c->erase_completion_lock); |
162 | if (!ret) | 204 | if (!ret) |
163 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); | 205 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index f9916f312bd8..66d44560f75d 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -105,6 +105,8 @@ static int jffs2_show_options(struct seq_file *s, struct dentry *root) | |||
105 | 105 | ||
106 | if (opts->override_compr) | 106 | if (opts->override_compr) |
107 | seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); | 107 | seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); |
108 | if (opts->rp_size) | ||
109 | seq_printf(s, ",rp_size=%u", opts->rp_size / 1024); | ||
108 | 110 | ||
109 | return 0; | 111 | return 0; |
110 | } | 112 | } |
@@ -171,15 +173,18 @@ static const struct export_operations jffs2_export_ops = { | |||
171 | * JFFS2 mount options. | 173 | * JFFS2 mount options. |
172 | * | 174 | * |
173 | * Opt_override_compr: override default compressor | 175 | * Opt_override_compr: override default compressor |
176 | * Opt_rp_size: size of reserved pool in KiB | ||
174 | * Opt_err: just end of array marker | 177 | * Opt_err: just end of array marker |
175 | */ | 178 | */ |
176 | enum { | 179 | enum { |
177 | Opt_override_compr, | 180 | Opt_override_compr, |
181 | Opt_rp_size, | ||
178 | Opt_err, | 182 | Opt_err, |
179 | }; | 183 | }; |
180 | 184 | ||
181 | static const match_table_t tokens = { | 185 | static const match_table_t tokens = { |
182 | {Opt_override_compr, "compr=%s"}, | 186 | {Opt_override_compr, "compr=%s"}, |
187 | {Opt_rp_size, "rp_size=%u"}, | ||
183 | {Opt_err, NULL}, | 188 | {Opt_err, NULL}, |
184 | }; | 189 | }; |
185 | 190 | ||
@@ -187,6 +192,7 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data) | |||
187 | { | 192 | { |
188 | substring_t args[MAX_OPT_ARGS]; | 193 | substring_t args[MAX_OPT_ARGS]; |
189 | char *p, *name; | 194 | char *p, *name; |
195 | unsigned int opt; | ||
190 | 196 | ||
191 | if (!data) | 197 | if (!data) |
192 | return 0; | 198 | return 0; |
@@ -224,6 +230,17 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data) | |||
224 | kfree(name); | 230 | kfree(name); |
225 | c->mount_opts.override_compr = true; | 231 | c->mount_opts.override_compr = true; |
226 | break; | 232 | break; |
233 | case Opt_rp_size: | ||
234 | if (match_int(&args[0], &opt)) | ||
235 | return -EINVAL; | ||
236 | opt *= 1024; | ||
237 | if (opt > c->mtd->size) { | ||
238 | pr_warn("Too large reserve pool specified, max " | ||
239 | "is %llu KB\n", c->mtd->size / 1024); | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | c->mount_opts.rp_size = opt; | ||
243 | break; | ||
227 | default: | 244 | default: |
228 | pr_err("Error: unrecognized mount option '%s' or missing value\n", | 245 | pr_err("Error: unrecognized mount option '%s' or missing value\n", |
229 | p); | 246 | p); |