[JFFS2] Fix JFFS2 [mc]time handling

From: David Woodhouse <dwmw2@infradead.org>

Signed-off-by: Artem B. Bityutskiy <dedekind@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 5738df2..0fd15aa 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.87 2005/07/17 11:13:46 dedekind Exp $
+ * $Id: dir.c,v 1.88 2005/08/17 13:46:22 dedekind Exp $
  *
  */
 
@@ -232,11 +232,14 @@
 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
 	struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode);
 	int ret;
+	uint32_t now = get_seconds();
 
 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, 
-			       dentry->d_name.len, dead_f);
+			      dentry->d_name.len, dead_f, now);
 	if (dead_f->inocache)
 		dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+	if (!ret)
+		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
 	return ret;
 }
 /***********************************************************************/
@@ -249,6 +252,7 @@
 	struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
 	int ret;
 	uint8_t type;
+	uint32_t now;
 
 	/* Don't let people make hard links to bad inodes. */
 	if (!f->inocache)
@@ -261,13 +265,15 @@
 	type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
 	if (!type) type = DT_REG;
 
-	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len);
+	now = get_seconds();
+	ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
 
 	if (!ret) {
 		down(&f->sem);
 		old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
 		up(&f->sem);
 		d_instantiate(dentry, old_dentry->d_inode);
+		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
 		atomic_inc(&old_dentry->d_inode->i_count);
 	}
 	return ret;
@@ -716,6 +722,7 @@
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
 	struct jffs2_inode_info *victim_f = NULL;
 	uint8_t type;
+	uint32_t now;
 
 	/* The VFS will check for us and prevent trying to rename a 
 	 * file over a directory and vice versa, but if it's a directory,
@@ -749,9 +756,10 @@
 	type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
 	if (!type) type = DT_REG;
 
+	now = get_seconds();
 	ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), 
 			    old_dentry->d_inode->i_ino, type,
-			    new_dentry->d_name.name, new_dentry->d_name.len);
+			    new_dentry->d_name.name, new_dentry->d_name.len, now);
 
 	if (ret)
 		return ret;
@@ -775,7 +783,7 @@
 
 	/* Unlink the original */
 	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), 
-		      old_dentry->d_name.name, old_dentry->d_name.len, NULL);
+			      old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
 
 	/* We don't touch inode->i_nlink */
 
@@ -792,12 +800,15 @@
 		/* Might as well let the VFS know */
 		d_instantiate(new_dentry, old_dentry->d_inode);
 		atomic_inc(&old_dentry->d_inode->i_count);
+		new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
 		return ret;
 	}
 
 	if (S_ISDIR(old_dentry->d_inode->i_mode))
 		old_dir_i->i_nlink--;
 
+	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
+
 	return 0;
 }
 
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 362cfee..def9715 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.152 2005/07/24 15:14:14 dedekind Exp $
+ * $Id: gc.c,v 1.153 2005/08/17 13:46:22 dedekind Exp $
  *
  */
 
@@ -771,7 +771,12 @@
 	rd.pino = cpu_to_je32(f->inocache->ino);
 	rd.version = cpu_to_je32(++f->highest_version);
 	rd.ino = cpu_to_je32(fd->ino);
-	rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)));
+	/* If the times on this inode were set by explicit utime() they can be different,
+	   so refrain from splatting them. */
+	if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f))
+		rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f));
+	else 
+		rd.mctime = cpu_to_je32(0);
 	rd.type = fd->type;
 	rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
 	rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
@@ -883,6 +888,9 @@
 		kfree(rd);
 	}
 
+	/* FIXME: If we're deleting a dirent which contains the current mtime and ctime, 
+	   we should update the metadata node with those times accordingly */
+
 	/* No need for it any more. Just mark it obsolete and remove it from the list */
 	while (*fdp) {
 		if ((*fdp) == fd) {
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index adee3c6..ce47d55 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.137 2005/08/01 12:05:19 dedekind Exp $
+ * $Id: nodelist.h,v 1.138 2005/08/17 13:46:23 dedekind Exp $
  *
  */
 
@@ -336,8 +336,8 @@
 			    struct jffs2_raw_inode *ri, unsigned char *buf, 
 			    uint32_t offset, uint32_t writelen, uint32_t *retlen);
 int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen);
-int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f);
-int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen);
+int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f, uint32_t time);
+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time);
 
 
 /* readinode.c */
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 50a62dd..6d5adab 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.139 2005/08/04 11:41:31 dedekind Exp $
+ * $Id: readinode.c,v 1.140 2005/08/17 13:46:23 dedekind Exp $
  *
  */
 
@@ -139,7 +139,7 @@
 	fd->type = rd->type;
 
 	/* Pick out the mctime of the latest dirent */
-	if(fd->version > *mctime_ver) {
+	if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) {
 		*mctime_ver = fd->version;
 		*latest_mctime = je32_to_cpu(rd->mctime);
 	}
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 4c418e6..0a19475 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.94 2005/07/20 15:50:51 dedekind Exp $
+ * $Id: write.c,v 1.95 2005/08/17 13:46:23 dedekind Exp $
  *
  */
 
@@ -533,7 +533,8 @@
 
 
 int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
-		    const char *name, int namelen, struct jffs2_inode_info *dead_f)
+		    const char *name, int namelen, struct jffs2_inode_info *dead_f,
+		    uint32_t time)
 {
 	struct jffs2_raw_dirent *rd;
 	struct jffs2_full_dirent *fd;
@@ -565,7 +566,7 @@
 		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->mctime = cpu_to_je32(time);
 		rd->nsize = namelen;
 		rd->type = DT_UNKNOWN;
 		rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
@@ -646,7 +647,7 @@
 }
 
 
-int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen)
+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time)
 {
 	struct jffs2_raw_dirent *rd;
 	struct jffs2_full_dirent *fd;
@@ -674,7 +675,7 @@
 	rd->pino = cpu_to_je32(dir_f->inocache->ino);
 	rd->version = cpu_to_je32(++dir_f->highest_version);
 	rd->ino = cpu_to_je32(ino);
-	rd->mctime = cpu_to_je32(get_seconds());
+	rd->mctime = cpu_to_je32(time);
 	rd->nsize = namelen;
 
 	rd->type = type;