Skip to content

Commit f8628a1

Browse files
Andreas Dilgertytso
authored andcommitted
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 <[email protected]> Signed-off-by: Kalpak Shah <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 6dd4ee7 commit f8628a1

File tree

2 files changed

+49
-15
lines changed

2 files changed

+49
-15
lines changed

fs/ext4/namei.c

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle,
16291629
return -ENOENT;
16301630
}
16311631

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+
*/
1636+
static 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+
*/
1653+
static 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+
16321661
static int ext4_add_nondir(handle_t *handle,
16331662
struct dentry *dentry, struct inode *inode)
16341663
{
@@ -1725,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
17251754
struct ext4_dir_entry_2 * de;
17261755
int err, retries = 0;
17271756

1728-
if (dir->i_nlink >= EXT4_LINK_MAX)
1757+
if (EXT4_DIR_LINK_MAX(dir))
17291758
return -EMLINK;
17301759

17311760
retry:
@@ -1748,7 +1777,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
17481777
inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
17491778
dir_block = ext4_bread (handle, inode, 0, 1, &err);
17501779
if (!dir_block) {
1751-
drop_nlink(inode); /* is this nlink == 0? */
1780+
ext4_dec_count(handle, inode); /* is this nlink == 0? */
17521781
ext4_mark_inode_dirty(handle, inode);
17531782
iput (inode);
17541783
goto out_stop;
@@ -1780,7 +1809,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
17801809
iput (inode);
17811810
goto out_stop;
17821811
}
1783-
inc_nlink(dir);
1812+
ext4_inc_count(handle, dir);
17841813
ext4_update_dx_flag(dir);
17851814
ext4_mark_inode_dirty(handle, dir);
17861815
d_instantiate(dentry, inode);
@@ -2045,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
20452074
retval = ext4_delete_entry(handle, dir, de, bh);
20462075
if (retval)
20472076
goto end_rmdir;
2048-
if (inode->i_nlink != 2)
2077+
if (!EXT4_DIR_LINK_EMPTY(inode))
20492078
ext4_warning (inode->i_sb, "ext4_rmdir",
2050-
"empty directory has nlink!=2 (%d)",
2079+
"empty directory has too many links (%d)",
20512080
inode->i_nlink);
20522081
inode->i_version++;
20532082
clear_nlink(inode);
@@ -2058,7 +2087,7 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
20582087
ext4_orphan_add(handle, inode);
20592088
inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
20602089
ext4_mark_inode_dirty(handle, inode);
2061-
drop_nlink(dir);
2090+
ext4_dec_count(handle, dir);
20622091
ext4_update_dx_flag(dir);
20632092
ext4_mark_inode_dirty(handle, dir);
20642093

@@ -2109,7 +2138,7 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
21092138
dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
21102139
ext4_update_dx_flag(dir);
21112140
ext4_mark_inode_dirty(handle, dir);
2112-
drop_nlink(inode);
2141+
ext4_dec_count(handle, inode);
21132142
if (!inode->i_nlink)
21142143
ext4_orphan_add(handle, inode);
21152144
inode->i_ctime = ext4_current_time(inode);
@@ -2159,7 +2188,7 @@ static int ext4_symlink (struct inode * dir,
21592188
err = __page_symlink(inode, symname, l,
21602189
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
21612190
if (err) {
2162-
drop_nlink(inode);
2191+
ext4_dec_count(handle, inode);
21632192
ext4_mark_inode_dirty(handle, inode);
21642193
iput (inode);
21652194
goto out_stop;
@@ -2185,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry,
21852214
struct inode *inode = old_dentry->d_inode;
21862215
int err, retries = 0;
21872216

2188-
if (inode->i_nlink >= EXT4_LINK_MAX)
2217+
if (EXT4_DIR_LINK_MAX(inode))
21892218
return -EMLINK;
2219+
21902220
/*
21912221
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
21922222
* otherwise has the potential to corrupt the orphan inode list.
@@ -2204,7 +2234,7 @@ static int ext4_link (struct dentry * old_dentry,
22042234
handle->h_sync = 1;
22052235

22062236
inode->i_ctime = ext4_current_time(inode);
2207-
inc_nlink(inode);
2237+
ext4_inc_count(handle, inode);
22082238
atomic_inc(&inode->i_count);
22092239

22102240
err = ext4_add_nondir(handle, dentry, inode);
@@ -2337,7 +2367,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
23372367
}
23382368

23392369
if (new_inode) {
2340-
drop_nlink(new_inode);
2370+
ext4_dec_count(handle, new_inode);
23412371
new_inode->i_ctime = ext4_current_time(new_inode);
23422372
}
23432373
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,
23482378
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
23492379
BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
23502380
ext4_journal_dirty_metadata(handle, dir_bh);
2351-
drop_nlink(old_dir);
2381+
ext4_dec_count(handle, old_dir);
23522382
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;
23542386
} else {
2355-
inc_nlink(new_dir);
2387+
ext4_inc_count(handle, new_dir);
23562388
ext4_update_dx_flag(new_dir);
23572389
ext4_mark_inode_dirty(handle, new_dir);
23582390
}

include/linux/ext4_fs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
/*
7272
* Maximal count of links to a file
7373
*/
74-
#define EXT4_LINK_MAX 32000
74+
#define EXT4_LINK_MAX 65000
7575

7676
/*
7777
* 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)
692692
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
693693
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
694694
#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
695+
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
695696
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
696697

697698
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
@@ -710,6 +711,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
710711
EXT4_FEATURE_INCOMPAT_64BIT)
711712
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
712713
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
714+
EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
713715
EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
714716
EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
715717

0 commit comments

Comments
 (0)