[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Maximal file size



Dear All,

Here is a patch which allows the developer to limit the created file 
size. It can be usefull on embadded devices where there are users who 
don't know too much about the system.

If the user uses too big files JFFS2 can run out of RAM easily - and 
simply hangs the system (dd if=/dev/zero of=/mnt/flash bs=4K hangs the 
system quickly) I know that the the memory requirements of JFFS2 depends 
on not only the size of the opened file but I have no better idea - and 
it solves a part of the problem.

This limitation can be understood by the user, and is not too dificult 
to implement. (see the small patch I attached)

David, can I commit it? Or wait for JFFS3? When will it happen?

Regards,
Ferenc
diff --unified --recursive --new-file mtd2/fs/Kconfig mtd/fs/Kconfig
--- mtd2/fs/Kconfig	2004-11-03 13:57:37.000000000 +0100
+++ mtd/fs/Kconfig	2004-12-07 09:58:31.000000000 +0100
@@ -77,6 +77,21 @@
 		 ECC for JFFS2.  This type of flash chip is not common, however it is
 		 available from STMicro.
 
+config JFFS2_MAXFILESIZE
+	bool "Use a file size limit"
+	depends on JFFS2_FS
+	default n
+	help
+	  Storing too large files can consume much memory.
+
+config JFFS2_MAXFILESIZE_VALUE
+	int "File size limit to use (in bytes, 0=no limit)"
+	depends on JFFS2_MAXFILESIZE
+	default "0"
+	help
+          It is the default value of maximal file size. 
+          You can modify it using the mount option 'maxfilesize'.
+
 config JFFS2_COMPRESSION_OPTIONS
 	bool "Advanced compression options for JFFS2"
 	default n
diff --unified --recursive --new-file mtd2/fs/jffs2/fs.c mtd/fs/jffs2/fs.c
--- mtd2/fs/jffs2/fs.c	2004-11-28 13:19:37.000000000 +0100
+++ mtd/fs/jffs2/fs.c	2004-12-07 09:57:11.000000000 +0100
@@ -341,10 +341,58 @@
 	jffs2_do_setattr(inode, &iattr);
 }
 
+/* Mount options added by Patrik Kluba <pajko@xxxxxxx.hu> */
+/* (University of Szeged, Hungary) based on affs source */
+
+#ifdef CONFIG_JFFS2_MAXFILESIZE
+
+#include <linux/string.h>
+#include <linux/parser.h>
+
+enum {
+  Opt_maxfilesize, Opt_err,
+};
+
+static match_table_t tokens = {
+  {Opt_maxfilesize, "maxfilesize=%d"},
+  {Opt_err, NULL},
+};
+
+static int parse_options(char *options, int *maxsize) {
+  char *p;
+  substring_t args[MAX_OPT_ARGS];
+  *maxsize = CONFIG_JFFS2_MAXFILESIZE_VALUE;
+  if (!options) return 1;
+  while ((p = strsep(&options, ",")) != NULL) {
+    int token, n;
+    if (!*p) continue;
+    token = match_token(p, tokens, args);
+    switch (token) {
+      case Opt_maxfilesize:
+        if (match_int(&args[0], &n)) return -EINVAL;
+	*maxsize = n;
+	break;
+      default:
+        printk("JFFS2: Unrecognized mount option \"%s\" or missing value\n", p);
+	return 0;
+    }
+  }
+  return 1;
+}
+
+#endif
+
 int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
 
+#ifdef CONFIG_JFFS2_MAXFILESIZE
+	if (!parse_options(data, &c->max_file_size)) {
+	  printk(KERN_ERR "JFFS2: error parsing options\n");
+	  return -EINVAL;
+	}
+#endif
+
 	if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY))
 		return -EROFS;
 
@@ -439,7 +487,6 @@
 	return inode;
 }
 
-
 int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct jffs2_sb_info *c;
@@ -449,6 +496,13 @@
 
 	c = JFFS2_SB_INFO(sb);
 
+#ifdef CONFIG_JFFS2_MAXFILESIZE
+	if (!parse_options(data, &c->max_file_size)) {
+	  printk(KERN_ERR "JFFS2: error parsing options\n");
+	  return -EINVAL;
+	}
+#endif
+
 #ifndef CONFIG_JFFS2_FS_NAND
 	if (c->mtd->type == MTD_NANDFLASH) {
 		printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
diff --unified --recursive --new-file mtd2/fs/jffs2/write.c mtd/fs/jffs2/write.c
--- mtd2/fs/jffs2/write.c	2004-11-16 21:36:12.000000000 +0100
+++ mtd/fs/jffs2/write.c	2004-12-07 09:57:11.000000000 +0100
@@ -366,18 +366,31 @@
 		uint16_t comprtype = JFFS2_COMPR_NONE;
 		uint32_t phys_ofs, alloclen;
 		uint32_t datalen, cdatalen;
+		uint32_t isize;
 		int retried = 0;
 
 	retry:
 		D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
 
+		datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
+		isize = max(je32_to_cpu(ri->isize), offset + datalen);
+
+#ifdef CONFIG_JFFS2_MAXFILESIZE
+		if (c->max_file_size) {
+			if (isize > c->max_file_size) {
+				D1(printk(KERN_DEBUG "reached file size limit\n"));
+				ret = -EFBIG;
+				break;
+			}
+		}
+#endif
+
 		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
 		if (ret) {
 			D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
 			break;
 		}
 		down(&f->sem);
-		datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
 		cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
 
 		comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
@@ -389,7 +402,7 @@
 
 		ri->ino = cpu_to_je32(f->inocache->ino);
 		ri->version = cpu_to_je32(++f->highest_version);
-		ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen));
+		ri->isize = cpu_to_je32(isize);
 		ri->offset = cpu_to_je32(offset);
 		ri->csize = cpu_to_je32(cdatalen);
 		ri->dsize = cpu_to_je32(datalen);
diff --unified --recursive --new-file mtd2/include/linux/jffs2_fs_sb.h mtd/include/linux/jffs2_fs_sb.h
--- mtd2/include/linux/jffs2_fs_sb.h	2004-11-20 11:41:12.000000000 +0100
+++ mtd/include/linux/jffs2_fs_sb.h	2004-12-07 09:57:11.000000000 +0100
@@ -111,6 +111,10 @@
 	uint32_t fsdata_len;
 #endif
 
+#ifdef CONFIG_JFFS2_MAXFILESIZE
+	uint32_t max_file_size;
+#endif
+
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };