fsck.f2fs: trigger fsck.f2fs when new change was made

This patch remains user specified triggering information in superblock.
Then, if the information was changed, fsck.f2fs is triggered.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
diff --git a/fsck/mount.c b/fsck/mount.c
index 9a9c842..37bd8c7 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -133,6 +133,7 @@
 	DISP_u32(sb, node_ino);
 	DISP_u32(sb, meta_ino);
 	DISP_u32(sb, cp_payload);
+	DISP("%s", sb, version);
 	printf("\n");
 }
 
@@ -225,6 +226,7 @@
 int validate_super_block(struct f2fs_sb_info *sbi, int block)
 {
 	u64 offset;
+
 	sbi->raw_super = malloc(sizeof(struct f2fs_super_block));
 
 	if (block == 0)
@@ -235,8 +237,35 @@
 	if (dev_read(sbi->raw_super, offset, sizeof(struct f2fs_super_block)))
 		return -1;
 
-	if (!sanity_check_raw_super(sbi->raw_super))
+	if (!sanity_check_raw_super(sbi->raw_super)) {
+		/* get kernel version */
+		if (config.kd >= 0) {
+			dev_read_version(config.version, 0, VERSION_LEN);
+			get_kernel_version(config.version);
+		} else {
+			memset(config.version, 0, VERSION_LEN);
+		}
+
+		/* build sb version */
+		memcpy(config.sb_version, sbi->raw_super->version, VERSION_LEN);
+		get_kernel_version(config.sb_version);
+
+		MSG(0, "Info: FSCK version\n  from \"%s\"\n    to \"%s\"\n",
+					config.sb_version, config.version);
+		if (memcmp(config.sb_version, config.version, VERSION_LEN)) {
+			int ret;
+
+			memcpy(sbi->raw_super->version,
+						config.version, VERSION_LEN);
+			ret = dev_write(sbi->raw_super, offset,
+					sizeof(struct f2fs_super_block));
+			ASSERT(ret >= 0);
+
+			config.auto_fix = 0;
+			config.fix_on = 1;
+		}
 		return 0;
+	}
 
 	free(sbi->raw_super);
 	MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", block);
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index b02002c..0ec9ee7 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -216,6 +216,8 @@
 #define	DEFAULT_BLOCKS_PER_SEGMENT	512
 #define DEFAULT_SEGMENTS_PER_SECTION	1
 
+#define VERSION_LEN	256
+
 enum f2fs_config_func {
 	FSCK,
 	DUMP,
@@ -232,9 +234,11 @@
 	u_int64_t total_sectors;
 	u_int32_t sectors_per_blk;
 	u_int32_t blks_per_seg;
+	__u8 sb_version[VERSION_LEN + 1];
+	__u8 version[VERSION_LEN + 1];
 	char *vol_label;
 	int heap;
-	int32_t fd;
+	int32_t fd, kd;
 	int32_t dump_fd;
 	char *device_name;
 	char *extension_list;
@@ -345,6 +349,7 @@
 	__le32 extension_count;		/* # of extensions below */
 	__u8 extension_list[F2FS_MAX_EXTENSION][8];	/* extension array */
 	__le32 cp_payload;
+	__u8 version[VERSION_LEN];	/* the kernel version */
 } __attribute__((packed));
 
 /*
@@ -773,6 +778,8 @@
 extern int dev_read_block(void *, __u64);
 extern int dev_read_blocks(void *, __u64, __u32 );
 
+extern int dev_read_version(void *, __u64, size_t);
+extern void get_kernel_version(__u8 *);
 f2fs_hash_t f2fs_dentry_hash(const unsigned char *, int);
 
 extern struct f2fs_configuration config;
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 73c551b..14e4164 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -418,6 +418,16 @@
 	return 0;
 }
 
+void get_kernel_version(__u8 *version)
+{
+	int i;
+	for (i = 0; i < VERSION_LEN; i++) {
+		if (version[i] == '\n')
+			break;
+	}
+	memset(version + i, 0, VERSION_LEN + 1 - i);
+}
+
 int f2fs_get_device_info(struct f2fs_configuration *c)
 {
 	int32_t fd = 0;
@@ -436,6 +446,10 @@
 	}
 	c->fd = fd;
 
+	c->kd = open("/proc/version", O_RDONLY);
+	if (c->kd < 0)
+		MSG(0, "\tInfo: No support kernel version!\n");
+
 	if (fstat(fd, &stat_buf) < 0 ) {
 		MSG(0, "\tError: Failed to get the device stat!\n");
 		return -1;
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 0c89ee4..6ed45fd 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -28,6 +28,15 @@
 /*
  * IO interfaces
  */
+int dev_read_version(void *buf, __u64 offset, size_t len)
+{
+	if (lseek64(config.kd, (off64_t)offset, SEEK_SET) < 0)
+		return -1;
+	if (read(config.kd, buf, len) < 0)
+		return -1;
+	return 0;
+}
+
 int dev_read(void *buf, __u64 offset, size_t len)
 {
 	if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
@@ -93,4 +102,6 @@
 
 	if (close(c->fd) < 0)
 		MSG(0, "\tError: Failed to close device file!!!\n");
+
+	close(c->kd);
 }