aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Dilger <adilger@clusterfs.com>2007-07-18 08:38:01 -0400
committerTheodore Ts'o <tytso@mit.edu>2007-07-18 08:38:01 -0400
commitf8628a14a27eb4512a1ede43de1d9db4d9f92bc3 (patch)
tree45719452db34112382a1b3e83dc648abe45eac70
parent6dd4ee7cab7e3a17c571aebd444f4344c8c4946e (diff)
ext4: Remove 65000 subdirectory limit
This patch adds support to ext4 for allowing more than 65000 subdirectories. Currently the maximum number of subdirectories is capped at 32000. If we exceed 65000 subdirectories in an htree directory it sets the inode link count to 1 and no longer counts subdirectories. The directory link count is not actually used when determining if a directory is empty, as that only counts subdirectories and not regular files that might be in there. A EXT4_FEATURE_RO_COMPAT_DIR_NLINK flag has been added and it is set if the subdir count for any directory crosses 65000. A later fsck will clear EXT4_FEATURE_RO_COMPAT_DIR_NLINK if there are no longer any directory with >65000 subdirs. Signed-off-by: Andreas Dilger <adilger@clusterfs.com> Signed-off-by: Kalpak Shah <kalpak@clusterfs.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/namei.c60
-rw-r--r--include/linux/ext4_fs.h4
2 files changed, 49 insertions, 15 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 40106b7ea4b8..da224974af78 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1629,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle,
1629 return -ENOENT; 1629 return -ENOENT;
1630} 1630}
1631 1631
1632/*
1633 * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
1634 * since this indicates that nlinks count was previously 1.
1635 */
1636static void ext4_inc_count(handle_t *handle, struct inode *inode)
1637{
1638 inc_nlink(inode);
1639 if (is_dx(inode) && inode->i_nlink > 1) {
1640 /* limit is 16-bit i_links_count */
1641 if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
1642 inode->i_nlink = 1;
1643 EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
1644 EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
1645 }
1646 }
1647}
1648
1649/*
1650 * If a directory had nlink == 1, then we should let it be 1. This indicates
1651 * directory has >EXT4_LINK_MAX subdirs.
1652 */
1653static void ext4_dec_count(handle_t *handle, struct inode *inode)
1654{
1655 drop_nlink(inode);
1656 if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
1657 inc_nlink(inode);
1658}
1659
1660
1632static int ext4_add_nondir(handle_t *handle, 1661static int ext4_add_nondir(handle_t *handle,
1633 struct dentry *dentry, struct inode *inode) 1662 struct dentry *dentry, struct inode *inode)
1634{ 1663{
@@ -1725,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
1725 struct ext4_dir_entry_2 * de; 1754 struct ext4_dir_entry_2 * de;
1726 int err, retries = 0; 1755 int err, retries = 0;
1727 1756
1728 if (dir->i_nlink >= EXT4_LINK_MAX) 1757 if (EXT4_DIR_LINK_MAX(dir))
1729 return -EMLINK; 1758 return -EMLINK;
1730 1759
1731retry: 1760retry:
@@ -1748,7 +1777,7 @@ retry:
1748 inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; 1777 inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
1749 dir_block = ext4_bread (handle, inode, 0, 1, &err); 1778 dir_block = ext4_bread (handle, inode, 0, 1, &err);
1750 if (!dir_block) { 1779 if (!dir_block) {
1751 drop_nlink(inode); /* is this nlink == 0? */ 1780 ext4_dec_count(handle, inode); /* is this nlink == 0? */
1752 ext4_mark_inode_dirty(handle, inode); 1781 ext4_mark_inode_dirty(handle, inode);
1753 iput (inode); 1782 iput (inode);
1754 goto out_stop; 1783 goto out_stop;
@@ -1780,7 +1809,7 @@ retry:
1780 iput (inode); 1809 iput (inode);
1781 goto out_stop; 1810 goto out_stop;
1782 } 1811 }
1783 inc_nlink(dir); 1812 ext4_inc_count(handle, dir);
1784 ext4_update_dx_flag(dir); 1813 ext4_update_dx_flag(dir);
1785 ext4_mark_inode_dirty(handle, dir); 1814 ext4_mark_inode_dirty(handle, dir);
1786 d_instantiate(dentry, inode); 1815 d_instantiate(dentry, inode);
@@ -2045,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
2045 retval = ext4_delete_entry(handle, dir, de, bh); 2074 retval = ext4_delete_entry(handle, dir, de, bh);
2046 if (retval) 2075 if (retval)
2047 goto end_rmdir; 2076 goto end_rmdir;
2048 if (inode->i_nlink != 2) 2077 if (!EXT4_DIR_LINK_EMPTY(inode))
2049 ext4_warning (inode->i_sb, "ext4_rmdir", 2078 ext4_warning (inode->i_sb, "ext4_rmdir",
2050 "empty directory has nlink!=2 (%d)", 2079 "empty directory has too many links (%d)",
2051 inode->i_nlink); 2080 inode->i_nlink);
2052 inode->i_version++; 2081 inode->i_version++;
2053 clear_nlink(inode); 2082 clear_nlink(inode);
@@ -2058,7 +2087,7 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
2058 ext4_orphan_add(handle, inode); 2087 ext4_orphan_add(handle, inode);
2059 inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode); 2088 inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
2060 ext4_mark_inode_dirty(handle, inode); 2089 ext4_mark_inode_dirty(handle, inode);
2061 drop_nlink(dir); 2090 ext4_dec_count(handle, dir);
2062 ext4_update_dx_flag(dir); 2091 ext4_update_dx_flag(dir);
2063 ext4_mark_inode_dirty(handle, dir); 2092 ext4_mark_inode_dirty(handle, dir);
2064 2093
@@ -2109,7 +2138,7 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
2109 dir->i_ctime = dir->i_mtime = ext4_current_time(dir); 2138 dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
2110 ext4_update_dx_flag(dir); 2139 ext4_update_dx_flag(dir);
2111 ext4_mark_inode_dirty(handle, dir); 2140 ext4_mark_inode_dirty(handle, dir);
2112 drop_nlink(inode); 2141 ext4_dec_count(handle, inode);
2113 if (!inode->i_nlink) 2142 if (!inode->i_nlink)
2114 ext4_orphan_add(handle, inode); 2143 ext4_orphan_add(handle, inode);
2115 inode->i_ctime = ext4_current_time(inode); 2144 inode->i_ctime = ext4_current_time(inode);
@@ -2159,7 +2188,7 @@ retry:
2159 err = __page_symlink(inode, symname, l, 2188 err = __page_symlink(inode, symname, l,
2160 mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); 2189 mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
2161 if (err) { 2190 if (err) {
2162 drop_nlink(inode); 2191 ext4_dec_count(handle, inode);
2163 ext4_mark_inode_dirty(handle, inode); 2192 ext4_mark_inode_dirty(handle, inode);
2164 iput (inode); 2193 iput (inode);
2165 goto out_stop; 2194 goto out_stop;
@@ -2185,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry,
2185 struct inode *inode = old_dentry->d_inode; 2214 struct inode *inode = old_dentry->d_inode;
2186 int err, retries = 0; 2215 int err, retries = 0;
2187 2216
2188 if (inode->i_nlink >= EXT4_LINK_MAX) 2217 if (EXT4_DIR_LINK_MAX(inode))
2189 return -EMLINK; 2218 return -EMLINK;
2219
2190 /* 2220 /*
2191 * Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing 2221 * Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
2192 * otherwise has the potential to corrupt the orphan inode list. 2222 * otherwise has the potential to corrupt the orphan inode list.
@@ -2204,7 +2234,7 @@ retry:
2204 handle->h_sync = 1; 2234 handle->h_sync = 1;
2205 2235
2206 inode->i_ctime = ext4_current_time(inode); 2236 inode->i_ctime = ext4_current_time(inode);
2207 inc_nlink(inode); 2237 ext4_inc_count(handle, inode);
2208 atomic_inc(&inode->i_count); 2238 atomic_inc(&inode->i_count);
2209 2239
2210 err = ext4_add_nondir(handle, dentry, inode); 2240 err = ext4_add_nondir(handle, dentry, inode);
@@ -2337,7 +2367,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
2337 } 2367 }
2338 2368
2339 if (new_inode) { 2369 if (new_inode) {
2340 drop_nlink(new_inode); 2370 ext4_dec_count(handle, new_inode);
2341 new_inode->i_ctime = ext4_current_time(new_inode); 2371 new_inode->i_ctime = ext4_current_time(new_inode);
2342 } 2372 }
2343 old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); 2373 old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
@@ -2348,11 +2378,13 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
2348 PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); 2378 PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
2349 BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata"); 2379 BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
2350 ext4_journal_dirty_metadata(handle, dir_bh); 2380 ext4_journal_dirty_metadata(handle, dir_bh);
2351 drop_nlink(old_dir); 2381 ext4_dec_count(handle, old_dir);
2352 if (new_inode) { 2382 if (new_inode) {
2353 drop_nlink(new_inode); 2383 /* checked empty_dir above, can't have another parent,
2384 * ext3_dec_count() won't work for many-linked dirs */
2385 new_inode->i_nlink = 0;
2354 } else { 2386 } else {
2355 inc_nlink(new_dir); 2387 ext4_inc_count(handle, new_dir);
2356 ext4_update_dx_flag(new_dir); 2388 ext4_update_dx_flag(new_dir);
2357 ext4_mark_inode_dirty(handle, new_dir); 2389 ext4_mark_inode_dirty(handle, new_dir);
2358 } 2390 }
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index 52dcc24dd986..cdee7aaa57aa 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -71,7 +71,7 @@
71/* 71/*
72 * Maximal count of links to a file 72 * Maximal count of links to a file
73 */ 73 */
74#define EXT4_LINK_MAX 32000 74#define EXT4_LINK_MAX 65000
75 75
76/* 76/*
77 * Macro-instructions used to manage several block sizes 77 * Macro-instructions used to manage several block sizes
@@ -692,6 +692,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
692#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 692#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
693#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 693#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
694#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 694#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
695#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
695#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 696#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
696 697
697#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 698#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
@@ -710,6 +711,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
710 EXT4_FEATURE_INCOMPAT_64BIT) 711 EXT4_FEATURE_INCOMPAT_64BIT)
711#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ 712#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
712 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ 713 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
714 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
713 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \ 715 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
714 EXT4_FEATURE_RO_COMPAT_BTREE_DIR) 716 EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
715 717