[PATCH/RFC] reserved pool

David Woodhouse dwmw2 at infradead.org
Tue May 16 19:31:32 EDT 2006


On Wed, 2006-05-17 at 00:30 +0100, David Woodhouse wrote:
> I cleaned it up so it looks like this.... 

-ENOPATCH....

--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -61,6 +61,9 @@ struct jffs2_sb_info {
 	uint8_t resv_blocks_gcbad;	/* ... pick a block from the bad_list to GC */
 	uint8_t resv_blocks_gcmerge;	/* ... merge pages when garbage collecting */
 
+
+	uint32_t resv_blocks_root;	/* How many extra eraseblocks are reserved for root */
+
 	uint32_t nospc_dirty_size;
 
 	uint32_t nr_blocks;
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -191,7 +191,7 @@ int jffs2_setattr(struct dentry *dentry,
 int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
-	unsigned long avail;
+	unsigned long avail, size;
 
 	buf->f_type = JFFS2_SUPER_MAGIC;
 	buf->f_bsize = 1 << PAGE_SHIFT;
@@ -202,8 +202,9 @@ int jffs2_statfs(struct super_block *sb,
 
 	spin_lock(&c->erase_completion_lock);
 	avail = c->dirty_size + c->free_size;
-	if (avail > c->sector_size * c->resv_blocks_write)
-		avail -= c->sector_size * c->resv_blocks_write;
+	size = c->sector_size * (c->resv_blocks_write + c->resv_blocks_root);
+	if (avail > size)
+		avail -= size;
 	else
 		avail = 0;
 	spin_unlock(&c->erase_completion_lock);
@@ -348,10 +349,16 @@ void jffs2_dirty_inode(struct inode *ino
 int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+	int ret;
 
 	if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
 		return -EROFS;
 
+	/* Re-parse mount options */
+	ret = jffs2_parse_options(sb, data);
+	if (ret)
+		return ret;
+
 	/* We stop if it was running, then restart if it needs to.
 	   This also catches the case where it was stopped and this
 	   is just a remount to restart it.
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -400,6 +400,9 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 /* erase.c */
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
 
+/* super.c */
+int jffs2_parse_options(struct super_block *sb, char *opts);
+
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 /* wbuf.c */
 int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
 #include <linux/compiler.h>
+#include <linux/capability.h>
 #include <linux/sched.h> /* For cond_resched() */
 #include "nodelist.h"
 #include "debug.h"
@@ -47,6 +48,10 @@ int jffs2_reserve_space(struct jffs2_sb_
 {
 	int ret = -EAGAIN;
 	int blocksneeded = c->resv_blocks_write;
+
+	if (prio != ALLOC_DELETION && !capable(CAP_SYS_RESOURCE))
+		blocksneeded += c->resv_blocks_root;
+
 	/* align it */
 	minsize = PAD(minsize);
 
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -24,10 +24,13 @@
 #include <linux/mtd/mtd.h>
 #include <linux/ctype.h>
 #include <linux/namei.h>
+#include <linux/parser.h>
+#include <linux/seq_file.h>
 #include "compr.h"
 #include "nodelist.h"
 
 static void jffs2_put_super(struct super_block *);
+static int jffs2_show_options(struct seq_file *m, struct vfsmount *mnt);
 
 static kmem_cache_t *jffs2_inode_cachep;
 
@@ -78,6 +81,7 @@ static struct super_operations jffs2_sup
 	.clear_inode =	jffs2_clear_inode,
 	.dirty_inode =	jffs2_dirty_inode,
 	.sync_fs =	jffs2_sync_fs,
+	.show_options = jffs2_show_options,
 };
 
 static int jffs2_sb_compare(struct super_block *sb, void *data)
@@ -152,14 +156,14 @@ static struct super_block *jffs2_get_sb_
 	sb->s_op = &jffs2_super_operations;
 	sb->s_flags = flags | MS_NOATIME;
 
-	ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
-
-	if (ret) {
-		/* Failure case... */
-		up_write(&sb->s_umount);
-		deactivate_super(sb);
-		return ERR_PTR(ret);
-	}
+	/* Parse mount options */
+	ret = jffs2_parse_options(sb, data);
+	if (ret)
+		goto error;
+
+	ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
+	if (ret)
+		goto error;
 
 	sb->s_flags |= MS_ACTIVE;
 	return sb;
@@ -169,6 +173,12 @@ static struct super_block *jffs2_get_sb_
 	put_mtd_device(mtd);
 
 	return sb;
+
+ error:
+	/* Failure case... */
+	up_write(&sb->s_umount);
+	deactivate_super(sb);
+	return ERR_PTR(ret);
 }
 
 static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
@@ -273,6 +283,72 @@ out:
 	return ERR_PTR(err);
 }
 
+/*
+ * Mount option identifiers.
+ */
+enum {
+	JFFS2_OPT_RP_SIZE,
+	JFFS2_OPT_LAST_FAKE
+};
+
+/*
+ * Supported mount options.
+ */
+static struct match_token tokens[] = {
+	{JFFS2_OPT_RP_SIZE, "rpsize=%u"}, /* Size of the reserved pool in KiB */
+	{JFFS2_OPT_LAST_FAKE, NULL}       /* End of list marker */
+};
+
+#define JFFS2_MAX_ARGS	1
+
+int jffs2_parse_options(struct super_block *sb, char *opts)
+{
+	unsigned int opt;
+	char *p;
+	substring_t args[JFFS2_MAX_ARGS];
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+
+	if (!opts)
+		return 0;
+
+	while ((p = strsep(&opts, ","))) {
+		int token;
+
+		if (!*p)
+			continue;
+
+		token = match_token(p, tokens, args);
+
+		switch (token) {
+		case JFFS2_OPT_RP_SIZE:
+			if (match_int(&args[0], &opt))
+				return -EINVAL;
+			opt = (opt + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+			if (opt > c->mtd->size/c->mtd->erasesize) {
+				printk(KERN_ERR "Reserved pool too large; max is %lu %uKiB blocks\n",
+				       c->mtd->size/PAGE_CACHE_SIZE, 1 << (PAGE_CACHE_SHIFT - 10));
+				return -EINVAL;
+			}
+			c->resv_blocks_root = opt;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int jffs2_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(mnt->mnt_sb);
+
+	if (c->resv_blocks_root)
+		seq_printf(m, ",rpsize=%u", c->resv_blocks_root/c->sector_size);
+
+	return 0;
+}
+
 static void jffs2_put_super (struct super_block *sb)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);

-- 
dwmw2





More information about the linux-mtd mailing list