[UPDATE][13/24]ext3 enlarge file size

[email protected]
Newsgroups gmane.linux.kernel,gmane.comp.file-systems.ext2.devel
Message-ID <[email protected]>
Summary of this patch:
  [13/24] extend file size(ext3)
          - If the flag is set to super block, i_blocks of disk inode
            (ext3_inode) is filesystem-block unit, and i_blocks of VFS
            inode is sector unit.

          - If the flag is set to super block, max file size is set to
            (FS blocksize) * (2^32 -1).

Signed-off-by: Takashi Sato [email protected]
---
diff -upNr -X linux-2.6.17-rc4/Documentation/dontdiff linux-2.6.17-rc4/fs/ext3/inode.c linux-2.6.17-rc4.tmp/fs/ext3/inode.c
--- linux-2.6.17-rc4/fs/ext3/inode.c	2006-05-25 16:33:29.706776397 +0900
+++ linux-2.6.17-rc4.tmp/fs/ext3/inode.c	2006-05-25 16:34:09.854236842 +0900
@@ -2630,8 +2630,13 @@ void ext3_read_inode(struct inode * inod
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size
 					 * (for stat), not the fs block
 					 * size */  
-	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
 	ei->i_flags = le32_to_cpu(raw_inode->i_flags);
+	if (ei->i_flags & EXT3_HUGE_FILE_FL) {
+		inode->i_blocks = (blkcnt_t)le32_to_cpu(raw_inode->i_blocks)
+			<< (inode->i_blkbits - EXT3_SECTOR_BITS);
+	} else {
+		inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
+	} 
 #ifdef EXT3_FRAGMENTS
 	ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
 	ei->i_frag_no = raw_inode->i_frag;
@@ -2726,6 +2731,7 @@ static int ext3_do_update_inode(handle_t
 	struct ext3_inode *raw_inode = ext3_raw_inode(iloc);
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	struct buffer_head *bh = iloc->bh;
+	struct super_block *sb = inode->i_sb;
 	int err = 0, rc, block;
 
 	/* For fields not not tracking in the in-memory inode,
@@ -2763,9 +2769,30 @@ static int ext3_do_update_inode(handle_t
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
 	raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
 	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
-	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
-	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
 	raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+
+	if (inode->i_blocks <= ~0U) {
+		raw_inode->i_flags &= ~EXT3_HUGE_FILE_FL;
+		raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
+	} else {
+		err = ext3_journal_get_write_access(handle,
+				EXT3_SB(sb)->s_sbh);
+		if (err)
+			goto out_brelse;
+		ext3_update_dynamic_rev(sb);
+		EXT3_SET_RO_COMPAT_FEATURE(sb,
+				EXT3_FEATURE_RO_COMPAT_HUGE_FILE);
+		sb->s_dirt = 1;
+		handle->h_sync = 1;
+		err = ext3_journal_dirty_metadata(handle,
+				EXT3_SB(sb)->s_sbh);
+		printk("ext3_do_update_inode: Now the file size is "
+		       "more than 2TB on device (%s)!!\n", sb->s_id);
+		raw_inode->i_flags |= EXT3_HUGE_FILE_FL;
+		raw_inode->i_blocks = cpu_to_le32((inode->i_blocks)
+		 	>> (inode->i_blkbits - EXT3_SECTOR_BITS));			
+	}
+	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
 #ifdef EXT3_FRAGMENTS
 	raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
 	raw_inode->i_frag = ei->i_frag_no;
diff -upNr -X linux-2.6.17-rc4/Documentation/dontdiff linux-2.6.17-rc4/fs/ext3/super.c linux-2.6.17-rc4.tmp/fs/ext3/super.c
--- linux-2.6.17-rc4/fs/ext3/super.c	2006-05-25 16:34:05.950916578 +0900
+++ linux-2.6.17-rc4.tmp/fs/ext3/super.c	2006-05-25 16:34:09.856189967 +0900
@@ -1297,14 +1297,21 @@ static void ext3_orphan_cleanup (struct 
  * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
  * We need to be 1 filesystem block less than the 2^32 sector limit.
  */
-static loff_t ext3_max_size(int bits)
+static loff_t ext3_max_size(int bits, struct super_block *sb)
 {
 	loff_t res = EXT3_NDIR_BLOCKS;
 	/* This constant is calculated to be the largest file size for a
 	 * dense, 4k-blocksize file such that the total number of
 	 * sectors in the file, including data and all indirect blocks,
 	 * does not exceed 2^32. */
-	const loff_t upper_limit = 0x1ff7fffd000LL;
+	loff_t upper_limit;
+	if (sizeof(blkcnt_t) < sizeof(u64)) {
+		upper_limit = 0x1ff7fffd000LL;
+	}
+	/* With CONFIG_LSF on, file size is limited to blocksize*(4G-1) */
+	else { 
+		upper_limit = (1LL << (bits + 32)) - (1LL << bits);
+	}
 
 	res += 1LL << (bits-2);
 	res += 1LL << (2*(bits-2));
@@ -1465,7 +1472,7 @@ static int ext3_fill_super (struct super
 
 	if (blocksize > PAGE_SIZE) {
 		printk(KERN_ERR "EXT3-fs: cannot mount filesystem with "
-		       "blocksize %u larger than PAGE_SIZE %u on %s\n",
+		       "blocksize %u larger than PAGE_SIZE %lu on %s\n",
 		       blocksize, PAGE_SIZE, sb->s_id);
 		goto failed_mount;
 	}
@@ -1508,7 +1515,7 @@ static int ext3_fill_super (struct super
 		}
 	}
 
-	sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits);
+	sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits, sb);
 
 	if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) {
 		sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE;
@@ -1699,6 +1706,18 @@ static int ext3_fill_super (struct super
 	 */
 
 	root = iget(sb, EXT3_ROOT_INO);
+
+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
+	    EXT3_FEATURE_RO_COMPAT_HUGE_FILE)) {
+		if (sizeof(root->i_blocks) < sizeof(u64)) {
+			if (!(sb->s_flags & MS_RDONLY)) {
+				printk(KERN_ERR "EXT3-fs: %s: Having huge file with "
+						"LSF off, you must mount filesystem "
+						"read-only.\n", sb->s_id);
+				goto failed_mount;
+			}
+		}
+	}
 	sb->s_root = d_alloc_root(root);
 	if (!sb->s_root) {
 		printk(KERN_ERR "EXT3-fs: get root inode failed\n");
diff -upNr -X linux-2.6.17-rc4/Documentation/dontdiff linux-2.6.17-rc4/include/linux/ext3_fs.h linux-2.6.17-rc4.tmp/include/linux/ext3_fs.h
--- linux-2.6.17-rc4/include/linux/ext3_fs.h	2006-05-25 16:34:05.951893140 +0900
+++ linux-2.6.17-rc4.tmp/include/linux/ext3_fs.h	2006-05-25 16:34:09.857166530 +0900
@@ -99,6 +99,7 @@ struct statfs;
 #else
 # define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10)
 #endif
+#define EXT3_SECTOR_BITS        9       /* log2(SECTOR_SIZE) */
 #ifdef __KERNEL__
 #define	EXT3_ADDR_PER_BLOCK_BITS(s)	(EXT3_SB(s)->s_addr_per_block_bits)
 #define EXT3_INODE_SIZE(s)		(EXT3_SB(s)->s_inode_size)
@@ -187,6 +188,7 @@ struct ext3_group_desc
 #define EXT3_NOTAIL_FL			0x00008000 /* file tail should not be merged */
 #define EXT3_DIRSYNC_FL			0x00010000 /* dirsync behaviour (directories only) */
 #define EXT3_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
+#define EXT3_HUGE_FILE_FL		0x00040000 /* Set to each huge file */
 #define EXT3_RESERVED_FL		0x80000000 /* reserved for ext3 lib */
 
 #define EXT3_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */
@@ -558,6 +560,7 @@ static inline struct ext3_inode_info *EX
 #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
 #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
 #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+#define EXT3_FEATURE_RO_COMPAT_HUGE_FILE	0x0008
 
 #define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
 #define EXT3_FEATURE_INCOMPAT_FILETYPE		0x0002
@@ -573,8 +576,8 @@ static inline struct ext3_inode_info *EX
 					 EXT3_FEATURE_INCOMPAT_HUGE_FS)
 #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
-					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
-
+					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR| \
+					 EXT3_FEATURE_RO_COMPAT_HUGE_FILE)
 /*
  * Default values for user and/or group using reserved blocks
  */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.