changeset 1562:8bafb5f8a697

Merge changes from MTD - fix file truncate issue
author gthomas
date Thu, 01 Apr 2004 03:17:55 +0000
parents 31dd38f564ec
children 4e2a59620a29
files packages/fs/jffs2/current/ChangeLog packages/fs/jffs2/current/doc/TODO packages/fs/jffs2/current/src/compr.c packages/fs/jffs2/current/src/fs-ecos.c packages/fs/jffs2/current/src/gc.c packages/fs/jffs2/current/src/nodelist.h packages/fs/jffs2/current/src/read.c packages/fs/jffs2/current/src/scan.c packages/fs/jffs2/current/src/write.c
diffstat 9 files changed, 142 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/packages/fs/jffs2/current/ChangeLog
+++ b/packages/fs/jffs2/current/ChangeLog
@@ -1,3 +1,8 @@
+2004-03-31  David Woodhouse  <dwmw2@infradead.org>
+
+	* src/fs-ecos.c (jffs2_fo_write): Set ri.isize so that non-append
+	writes don't truncate the file.
+	
 2004-03-03  Thomas Koeller  <thomas.koeller@baslerweb.com>
 
         * src/fs-ecos.c: 
--- a/packages/fs/jffs2/current/doc/TODO
+++ b/packages/fs/jffs2/current/doc/TODO
@@ -1,5 +1,11 @@
-$Id: TODO,v 1.15 2003/10/06 14:50:37 dwmw2 Exp $
+$Id: TODO,v 1.16 2004/03/20 15:01:34 dwmw2 Exp $
 
+ - support asynchronous operation -- add a per-fs 'reserved_space' count,
+   let each outstanding write reserve the _maximum_ amount of physical
+   space it could take. Let GC flush the outstanding writes because the
+   reservations will necessarily be pessimistic. With this we could even
+   do shared writable mmap, if we can have a fs hook for do_wp_page() to
+   make the reservation.
  - disable compression in commit_write()?
  - fine-tune the allocation / GC thresholds
  - chattr support - turning on/off and tuning compression per-inode
--- a/packages/fs/jffs2/current/src/compr.c
+++ b/packages/fs/jffs2/current/src/compr.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.33 2003/11/28 17:22:54 dwmw2 Exp $
+ * $Id: compr.c,v 1.34 2004/03/08 15:29:09 dwmw2 Exp $
  *
  */
 
@@ -46,8 +46,9 @@ void jffs2_dynrubin_decompress(unsigned 
  * jffs2_compress should compress as much as will fit, and should set 
  * *datalen accordingly to show the amount of data which were compressed.
  */
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, 
-		    uint32_t *datalen, uint32_t *cdatalen)
+unsigned char jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+			     unsigned char *data_in, unsigned char **cpage_out, 
+			     uint32_t *datalen, uint32_t *cdatalen)
 {
 #ifdef JFFS2_COMPRESSION
 	int ret;
@@ -97,7 +98,8 @@ void jffs2_free_comprbuf(unsigned char *
 		kfree(comprbuf);
 }
 
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, 
+int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+		     unsigned char comprtype, unsigned char *cdata_in, 
 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 {
 	switch (comprtype) {
--- a/packages/fs/jffs2/current/src/fs-ecos.c
+++ b/packages/fs/jffs2/current/src/fs-ecos.c
@@ -8,7 +8,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs-ecos.c,v 1.33 2003/12/02 10:43:03 dwmw2 Exp $
+ * $Id: fs-ecos.c,v 1.34 2004/03/31 12:17:09 dwmw2 Exp $
  *
  */
 
@@ -1347,6 +1347,7 @@ static int jffs2_fo_write(struct CYG_FIL
 		if (err)
 			return -err;
 	}
+	ri.isize = cpu_to_je32(inode->i_size);
 
 	// Now loop over the iovecs until they are all done, or
 	// we get an error.
--- a/packages/fs/jffs2/current/src/gc.c
+++ b/packages/fs/jffs2/current/src/gc.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.132 2003/12/01 11:32:11 dwmw2 Exp $
+ * $Id: gc.c,v 1.133 2004/03/08 15:29:09 dwmw2 Exp $
  *
  */
 
@@ -674,7 +674,7 @@ static int jffs2_garbage_collect_metadat
 			printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
 			return -ENOMEM;
 		}
-		ret = jffs2_read_dnode(c, fn, mdata, 0, mdatalen);
+		ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen);
 		if (ret) {
 			printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);
 			kfree(mdata);
@@ -1190,7 +1190,7 @@ static int jffs2_garbage_collect_dnode(s
 
 		writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
 
-		comprtype = jffs2_compress(writebuf, &comprbuf, &datalen, &cdatalen);
+		comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);
 
 		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
--- a/packages/fs/jffs2/current/src/nodelist.h
+++ b/packages/fs/jffs2/current/src/nodelist.h
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.115 2003/11/26 15:30:58 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.116 2004/03/08 15:29:09 dwmw2 Exp $
  *
  */
 
@@ -432,16 +432,20 @@ void jffs2_free_inode_cache(struct jffs2
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
 /* read.c */
-int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len);
+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+		     struct jffs2_full_dnode *fd, unsigned char *buf,
+		     int ofs, int len);
 int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 			   unsigned char *buf, uint32_t offset, uint32_t len);
 char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
 
 /* compr.c */
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, 
+unsigned char jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+			     unsigned char *data_in, unsigned char **cpage_out, 
 			     uint32_t *datalen, uint32_t *cdatalen);
 void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig);
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, 
+int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+		     unsigned char comprtype, unsigned char *cdata_in, 
 		     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
 
 /* scan.c */
--- a/packages/fs/jffs2/current/src/read.c
+++ b/packages/fs/jffs2/current/src/read.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: read.c,v 1.35 2004/03/08 15:29:09 dwmw2 Exp $
  *
  */
 
@@ -19,7 +19,9 @@
 #include <linux/compiler.h>
 #include "nodelist.h"
 
-int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+		     struct jffs2_full_dnode *fd, unsigned char *buf,
+		     int ofs, int len)
 {
 	struct jffs2_raw_inode *ri;
 	size_t readlen;
@@ -127,7 +129,7 @@ int jffs2_read_dnode(struct jffs2_sb_inf
 	if (ri->compr != JFFS2_COMPR_NONE) {
 		D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
 			  je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); 
-		ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
+		ret = jffs2_decompress(c, f, ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
 		if (ret) {
 			printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
 			goto out_decomprbuf;
@@ -195,7 +197,7 @@ int jffs2_read_inode_range(struct jffs2_
 			D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
 				  frag->ofs+fragofs, frag->ofs+fragofs+readlen,
 				  ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
-			ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
+			ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
 			D2(printk(KERN_DEBUG "node read done\n"));
 			if (ret) {
 				D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
@@ -231,7 +233,7 @@ char *jffs2_getlink(struct jffs2_sb_info
 	}
 	buf[f->metadata->size]=0;
 
-	ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size);
+	ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
 
 	up(&f->sem);
 
--- a/packages/fs/jffs2/current/src/scan.c
+++ b/packages/fs/jffs2/current/src/scan.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.106 2003/10/28 17:01:13 dwmw2 Exp $
+ * $Id: scan.c,v 1.109 2004/03/19 16:40:50 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
@@ -285,8 +285,6 @@ static int jffs2_scan_eraseblock (struct
 	uint32_t hdr_crc, buf_ofs, buf_len;
 	int err;
 	int noise = 0;
-	int wasempty = 0;
-	uint32_t empty_start = 0;
 #ifdef CONFIG_JFFS2_FS_NAND
 	int cleanmarkerfound = 0;
 #endif
@@ -359,6 +357,7 @@ static int jffs2_scan_eraseblock (struct
 
 	noise = 10;
 
+scan_more:	
 	while(ofs < jeb->offset + c->sector_size) {
 
 		D1(ACCT_PARANOIA_CHECK(jeb));
@@ -398,42 +397,52 @@ static int jffs2_scan_eraseblock (struct
 		node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
 
 		if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
-			uint32_t inbuf_ofs = ofs - buf_ofs + 4;
-			uint32_t scanend;
+			uint32_t inbuf_ofs;
+			uint32_t empty_start;
 
 			empty_start = ofs;
 			ofs += 4;
 
-			/* If scanning empty space after only a cleanmarker, don't
-			   bother scanning the whole block */
-			if (unlikely(empty_start == jeb->offset + c->cleanmarker_size &&
-				     jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len))
-				scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs;
-			else
-				scanend = buf_len;
-
 			D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
-			while (inbuf_ofs < scanend) {
-				if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)
-					goto emptyends;
+		more_empty:
+			inbuf_ofs = ofs - buf_ofs;
+			while (inbuf_ofs < buf_len) {
+				if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
+					printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
+					       empty_start, ofs);
+					DIRTY_SPACE(ofs-empty_start);
+					goto scan_more;
+				}
 
 				inbuf_ofs+=4;
 				ofs += 4;
 			}
 			/* Ran off end. */
-			D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
+			D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));
 
-			if (buf_ofs == jeb->offset &&  jeb->used_size == PAD(c->cleanmarker_size) && 
-			    c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size)
+			/* If we're only checking the beginning of a block with a cleanmarker,
+			   bail now */
+			if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && 
+			    c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
+				D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE));
 				return BLK_STATE_CLEANMARKER;
-			wasempty = 1;
-			continue;
-		} else if (wasempty) {
-		emptyends:
-			printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs);
-			DIRTY_SPACE(ofs-empty_start);
-			wasempty = 0;
-			continue;
+			}
+
+			/* See how much more there is to read in this eraseblock... */
+			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+			if (!buf_len) {
+				/* No more to read. Break out of main loop without marking 
+				   this range of empty space as dirty (because it's not) */
+				D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
+					  empty_start));
+				break;
+			}
+			D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
+			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+			if (err)
+				return err;
+			buf_ofs = ofs;
+			goto more_empty;
 		}
 
 		if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
@@ -610,7 +619,7 @@ static int jffs2_scan_eraseblock (struct
 	}
 
 	if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
-		&& (!jeb->first_node || jeb->first_node->next_in_ino) )
+		&& (!jeb->first_node || !jeb->first_node->next_in_ino) )
 		return BLK_STATE_CLEANMARKER;
 		
 	/* move blocks with max 4 byte dirty space to cleanlist */	
--- a/packages/fs/jffs2/current/src/write.c
+++ b/packages/fs/jffs2/current/src/write.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.81 2004/02/17 14:58:16 dwmw2 Exp $
+ * $Id: write.c,v 1.83 2004/03/30 09:36:09 dwmw2 Exp $
  *
  */
 
@@ -375,7 +375,7 @@ int jffs2_write_inode_range(struct jffs2
 		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(buf, &comprbuf, &datalen, &cdatalen);
+		comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
 
 		ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 		ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -543,48 +543,75 @@ int jffs2_do_unlink(struct jffs2_sb_info
 	uint32_t alloclen, phys_ofs;
 	int ret;
 
-	rd = jffs2_alloc_raw_dirent();
-	if (!rd)
-		return -ENOMEM;
+	if (1 /* alternative branch needs testing */ || 
+	    !jffs2_can_mark_obsolete(c)) {
+		/* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
+
+		rd = jffs2_alloc_raw_dirent();
+		if (!rd)
+			return -ENOMEM;
+
+		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
+		if (ret) {
+			jffs2_free_raw_dirent(rd);
+			return ret;
+		}
+
+		down(&dir_f->sem);
+
+		/* Build a deletion node */
+		rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+		rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+		rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
+		rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
+		
+		rd->pino = cpu_to_je32(dir_f->inocache->ino);
+		rd->version = cpu_to_je32(++dir_f->highest_version);
+		rd->ino = cpu_to_je32(0);
+		rd->mctime = cpu_to_je32(get_seconds());
+		rd->nsize = namelen;
+		rd->type = DT_UNKNOWN;
+		rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
+		rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
 
-	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
-	if (ret) {
+		fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
+		
 		jffs2_free_raw_dirent(rd);
-		return ret;
+
+		if (IS_ERR(fd)) {
+			jffs2_complete_reservation(c);
+			up(&dir_f->sem);
+			return PTR_ERR(fd);
+		}
+
+		/* File it. This will mark the old one obsolete. */
+		jffs2_add_fd_to_list(c, fd, &dir_f->dents);
+		up(&dir_f->sem);
+	} else {
+		struct jffs2_full_dirent **prev = &dir_f->dents;
+		uint32_t nhash = full_name_hash(name, namelen);
+
+		down(&dir_f->sem);
+
+		while ((*prev) && (*prev)->nhash <= nhash) {
+			if ((*prev)->nhash == nhash && 
+			    !memcmp((*prev)->name, name, namelen) &&
+			    !(*prev)->name[namelen]) {
+				struct jffs2_full_dirent *this = *prev;
+
+				D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
+					  this->ino, ref_offset(this->raw)));
+
+				*prev = this->next;
+				jffs2_mark_node_obsolete(c, (this->raw));
+				jffs2_free_full_dirent(this);
+				break;
+			}
+			prev = &((*prev)->next);
+		}
+		up(&dir_f->sem);
 	}
 
-	down(&dir_f->sem);
-
-	/* Build a deletion node */
-	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-
-	rd->pino = cpu_to_je32(dir_f->inocache->ino);
-	rd->version = cpu_to_je32(++dir_f->highest_version);
-	rd->ino = cpu_to_je32(0);
-	rd->mctime = cpu_to_je32(get_seconds());
-	rd->nsize = namelen;
-	rd->type = DT_UNKNOWN;
-	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-	rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
-
-	fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
-	
-	jffs2_free_raw_dirent(rd);
-
-	if (IS_ERR(fd)) {
-		jffs2_complete_reservation(c);
-		up(&dir_f->sem);
-		return PTR_ERR(fd);
-	}
-
-	/* File it. This will mark the old one obsolete. */
-	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-
-	up(&dir_f->sem);
-	
 	/* dead_f is NULL if this was a rename not a real unlink */
 	/* Also catch the !f->inocache case, where there was a dirent
 	   pointing to an inode which didn't exist. */