aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorKalpak Shah <kalpak@clusterfs.com>2007-07-18 09:15:20 -0400
committerTheodore Ts'o <tytso@mit.edu>2007-07-18 09:15:20 -0400
commitef7f38359ea8b3e9c7f2cae9a4d4935f55ca9e80 (patch)
treeee34a5821332cf70b89827eb872f08bc0dd43f89 /fs/ext4
parent0f49d5d019afa4e94253bfc92f0daca3badb990b (diff)
ext4: Add nanosecond timestamps
This patch adds nanosecond timestamps for ext4. This involves adding *time_extra fields to the ext4_inode to extend the timestamps to 64-bits. Creation time is also added by this patch. These extended fields will fit into an inode if the filesystem was formatted with large inodes (-I 256 or larger) and there are currently no EAs consuming all of the available space. For new inodes we always reserve enough space for the kernel's known extended fields, but for inodes created with an old kernel this might not have been the case. So this patch also adds the EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE feature flag(ro-compat so that older kernels can't create inodes with a smaller extra_isize). which indicates if the fields fitting inside s_min_extra_isize are available or not. If the expansion of inodes if unsuccessful then this feature will be disabled. This feature is only enabled if requested by the sysadmin. None of the extended inode fields is critical for correct filesystem operation. Signed-off-by: Andreas Dilger <adilger@clusterfs.com> Signed-off-by: Kalpak Shah <kalpak@clusterfs.com> Signed-off-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com> Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ialloc.c8
-rw-r--r--fs/ext4/inode.c22
-rw-r--r--fs/ext4/ioctl.c4
-rw-r--r--fs/ext4/namei.c16
-rw-r--r--fs/ext4/super.c28
-rw-r--r--fs/ext4/xattr.c2
6 files changed, 56 insertions, 24 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index c88b439ba5c..427f83066a0 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -563,7 +563,8 @@ got:
563 inode->i_ino = ino; 563 inode->i_ino = ino;
564 /* This is the optimal IO size (for stat), not the fs block size */ 564 /* This is the optimal IO size (for stat), not the fs block size */
565 inode->i_blocks = 0; 565 inode->i_blocks = 0;
566 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 566 inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
567 ext4_current_time(inode);
567 568
568 memset(ei->i_data, 0, sizeof(ei->i_data)); 569 memset(ei->i_data, 0, sizeof(ei->i_data));
569 ei->i_dir_start_lookup = 0; 570 ei->i_dir_start_lookup = 0;
@@ -595,9 +596,8 @@ got:
595 spin_unlock(&sbi->s_next_gen_lock); 596 spin_unlock(&sbi->s_next_gen_lock);
596 597
597 ei->i_state = EXT4_STATE_NEW; 598 ei->i_state = EXT4_STATE_NEW;
598 ei->i_extra_isize = 599
599 (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ? 600 ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
600 sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
601 601
602 ret = inode; 602 ret = inode;
603 if(DQUOT_ALLOC_INODE(inode)) { 603 if(DQUOT_ALLOC_INODE(inode)) {
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 49035c5a2c4..b83f91edebd 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -726,7 +726,7 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
726 726
727 /* We are done with atomic stuff, now do the rest of housekeeping */ 727 /* We are done with atomic stuff, now do the rest of housekeeping */
728 728
729 inode->i_ctime = CURRENT_TIME_SEC; 729 inode->i_ctime = ext4_current_time(inode);
730 ext4_mark_inode_dirty(handle, inode); 730 ext4_mark_inode_dirty(handle, inode);
731 731
732 /* had we spliced it onto indirect block? */ 732 /* had we spliced it onto indirect block? */
@@ -2375,7 +2375,7 @@ do_indirects:
2375 ext4_discard_reservation(inode); 2375 ext4_discard_reservation(inode);
2376 2376
2377 mutex_unlock(&ei->truncate_mutex); 2377 mutex_unlock(&ei->truncate_mutex);
2378 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; 2378 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
2379 ext4_mark_inode_dirty(handle, inode); 2379 ext4_mark_inode_dirty(handle, inode);
2380 2380
2381 /* 2381 /*
@@ -2629,10 +2629,6 @@ void ext4_read_inode(struct inode * inode)
2629 } 2629 }
2630 inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); 2630 inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
2631 inode->i_size = le32_to_cpu(raw_inode->i_size); 2631 inode->i_size = le32_to_cpu(raw_inode->i_size);
2632 inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
2633 inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
2634 inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
2635 inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
2636 2632
2637 ei->i_state = 0; 2633 ei->i_state = 0;
2638 ei->i_dir_start_lookup = 0; 2634 ei->i_dir_start_lookup = 0;
@@ -2710,6 +2706,11 @@ void ext4_read_inode(struct inode * inode)
2710 } else 2706 } else
2711 ei->i_extra_isize = 0; 2707 ei->i_extra_isize = 0;
2712 2708
2709 EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
2710 EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
2711 EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode);
2712 EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
2713
2713 if (S_ISREG(inode->i_mode)) { 2714 if (S_ISREG(inode->i_mode)) {
2714 inode->i_op = &ext4_file_inode_operations; 2715 inode->i_op = &ext4_file_inode_operations;
2715 inode->i_fop = &ext4_file_operations; 2716 inode->i_fop = &ext4_file_operations;
@@ -2791,9 +2792,12 @@ static int ext4_do_update_inode(handle_t *handle,
2791 } 2792 }
2792 raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); 2793 raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
2793 raw_inode->i_size = cpu_to_le32(ei->i_disksize); 2794 raw_inode->i_size = cpu_to_le32(ei->i_disksize);
2794 raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); 2795
2795 raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); 2796 EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
2796 raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); 2797 EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
2798 EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
2799 EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
2800
2797 raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); 2801 raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
2798 raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); 2802 raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
2799 raw_inode->i_flags = cpu_to_le32(ei->i_flags); 2803 raw_inode->i_flags = cpu_to_le32(ei->i_flags);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 5b00775d509..c04c7ccba9e 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -97,7 +97,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
97 ei->i_flags = flags; 97 ei->i_flags = flags;
98 98
99 ext4_set_inode_flags(inode); 99 ext4_set_inode_flags(inode);
100 inode->i_ctime = CURRENT_TIME_SEC; 100 inode->i_ctime = ext4_current_time(inode);
101 101
102 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 102 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
103flags_err: 103flags_err:
@@ -134,7 +134,7 @@ flags_err:
134 return PTR_ERR(handle); 134 return PTR_ERR(handle);
135 err = ext4_reserve_inode_write(handle, inode, &iloc); 135 err = ext4_reserve_inode_write(handle, inode, &iloc);
136 if (err == 0) { 136 if (err == 0) {
137 inode->i_ctime = CURRENT_TIME_SEC; 137 inode->i_ctime = ext4_current_time(inode);
138 inode->i_generation = generation; 138 inode->i_generation = generation;
139 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 139 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
140 } 140 }
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2de339dd755..40106b7ea4b 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1295,7 +1295,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
1295 * happen is that the times are slightly out of date 1295 * happen is that the times are slightly out of date
1296 * and/or different from the directory change time. 1296 * and/or different from the directory change time.
1297 */ 1297 */
1298 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 1298 dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
1299 ext4_update_dx_flag(dir); 1299 ext4_update_dx_flag(dir);
1300 dir->i_version++; 1300 dir->i_version++;
1301 ext4_mark_inode_dirty(handle, dir); 1301 ext4_mark_inode_dirty(handle, dir);
@@ -2056,7 +2056,7 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
2056 * recovery. */ 2056 * recovery. */
2057 inode->i_size = 0; 2057 inode->i_size = 0;
2058 ext4_orphan_add(handle, inode); 2058 ext4_orphan_add(handle, inode);
2059 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; 2059 inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
2060 ext4_mark_inode_dirty(handle, inode); 2060 ext4_mark_inode_dirty(handle, inode);
2061 drop_nlink(dir); 2061 drop_nlink(dir);
2062 ext4_update_dx_flag(dir); 2062 ext4_update_dx_flag(dir);
@@ -2106,13 +2106,13 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
2106 retval = ext4_delete_entry(handle, dir, de, bh); 2106 retval = ext4_delete_entry(handle, dir, de, bh);
2107 if (retval) 2107 if (retval)
2108 goto end_unlink; 2108 goto end_unlink;
2109 dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; 2109 dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
2110 ext4_update_dx_flag(dir); 2110 ext4_update_dx_flag(dir);
2111 ext4_mark_inode_dirty(handle, dir); 2111 ext4_mark_inode_dirty(handle, dir);
2112 drop_nlink(inode); 2112 drop_nlink(inode);
2113 if (!inode->i_nlink) 2113 if (!inode->i_nlink)
2114 ext4_orphan_add(handle, inode); 2114 ext4_orphan_add(handle, inode);
2115 inode->i_ctime = dir->i_ctime; 2115 inode->i_ctime = ext4_current_time(inode);
2116 ext4_mark_inode_dirty(handle, inode); 2116 ext4_mark_inode_dirty(handle, inode);
2117 retval = 0; 2117 retval = 0;
2118 2118
@@ -2203,7 +2203,7 @@ retry:
2203 if (IS_DIRSYNC(dir)) 2203 if (IS_DIRSYNC(dir))
2204 handle->h_sync = 1; 2204 handle->h_sync = 1;
2205 2205
2206 inode->i_ctime = CURRENT_TIME_SEC; 2206 inode->i_ctime = ext4_current_time(inode);
2207 inc_nlink(inode); 2207 inc_nlink(inode);
2208 atomic_inc(&inode->i_count); 2208 atomic_inc(&inode->i_count);
2209 2209
@@ -2305,7 +2305,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
2305 * Like most other Unix systems, set the ctime for inodes on a 2305 * Like most other Unix systems, set the ctime for inodes on a
2306 * rename. 2306 * rename.
2307 */ 2307 */
2308 old_inode->i_ctime = CURRENT_TIME_SEC; 2308 old_inode->i_ctime = ext4_current_time(old_inode);
2309 ext4_mark_inode_dirty(handle, old_inode); 2309 ext4_mark_inode_dirty(handle, old_inode);
2310 2310
2311 /* 2311 /*
@@ -2338,9 +2338,9 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
2338 2338
2339 if (new_inode) { 2339 if (new_inode) {
2340 drop_nlink(new_inode); 2340 drop_nlink(new_inode);
2341 new_inode->i_ctime = CURRENT_TIME_SEC; 2341 new_inode->i_ctime = ext4_current_time(new_inode);
2342 } 2342 }
2343 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; 2343 old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
2344 ext4_update_dx_flag(old_dir); 2344 ext4_update_dx_flag(old_dir);
2345 if (dir_bh) { 2345 if (dir_bh) {
2346 BUFFER_TRACE(dir_bh, "get_write_access"); 2346 BUFFER_TRACE(dir_bh, "get_write_access");
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index af0835187e7..b47259f6f39 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1651,6 +1651,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
1651 sbi->s_inode_size); 1651 sbi->s_inode_size);
1652 goto failed_mount; 1652 goto failed_mount;
1653 } 1653 }
1654 if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
1655 sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
1654 } 1656 }
1655 sbi->s_frag_size = EXT4_MIN_FRAG_SIZE << 1657 sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
1656 le32_to_cpu(es->s_log_frag_size); 1658 le32_to_cpu(es->s_log_frag_size);
@@ -1874,6 +1876,32 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
1874 } 1876 }
1875 1877
1876 ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY); 1878 ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
1879
1880 /* determine the minimum size of new large inodes, if present */
1881 if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
1882 sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
1883 EXT4_GOOD_OLD_INODE_SIZE;
1884 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
1885 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
1886 if (sbi->s_want_extra_isize <
1887 le16_to_cpu(es->s_want_extra_isize))
1888 sbi->s_want_extra_isize =
1889 le16_to_cpu(es->s_want_extra_isize);
1890 if (sbi->s_want_extra_isize <
1891 le16_to_cpu(es->s_min_extra_isize))
1892 sbi->s_want_extra_isize =
1893 le16_to_cpu(es->s_min_extra_isize);
1894 }
1895 }
1896 /* Check if enough inode space is available */
1897 if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
1898 sbi->s_inode_size) {
1899 sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
1900 EXT4_GOOD_OLD_INODE_SIZE;
1901 printk(KERN_INFO "EXT4-fs: required extra inode space not"
1902 "available.\n");
1903 }
1904
1877 /* 1905 /*
1878 * akpm: core read_super() calls in here with the superblock locked. 1906 * akpm: core read_super() calls in here with the superblock locked.
1879 * That deadlocks, because orphan cleanup needs to lock the superblock 1907 * That deadlocks, because orphan cleanup needs to lock the superblock
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e832e96095b..fe16a569d06 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1013,7 +1013,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
1013 } 1013 }
1014 if (!error) { 1014 if (!error) {
1015 ext4_xattr_update_super_block(handle, inode->i_sb); 1015 ext4_xattr_update_super_block(handle, inode->i_sb);
1016 inode->i_ctime = CURRENT_TIME_SEC; 1016 inode->i_ctime = ext4_current_time(inode);
1017 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 1017 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
1018 /* 1018 /*
1019 * The bh is consumed by ext4_mark_iloc_dirty, even with 1019 * The bh is consumed by ext4_mark_iloc_dirty, even with