aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/jffs2_fs_sb.h7
-rw-r--r--fs/jffs2/nodemgmt.c42
-rw-r--r--fs/jffs2/super.c17
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;
32struct jffs2_mount_opts { 32struct 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 */
24static 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
202out:
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 */
176enum { 179enum {
177 Opt_override_compr, 180 Opt_override_compr,
181 Opt_rp_size,
178 Opt_err, 182 Opt_err,
179}; 183};
180 184
181static const match_table_t tokens = { 185static 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);