diff options
| -rw-r--r-- | fs/ext4/namei.c | 60 | ||||
| -rw-r--r-- | include/linux/ext4_fs.h | 4 |
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 | */ | ||
| 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 | |||
| 1632 | static int ext4_add_nondir(handle_t *handle, | 1661 | static 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 | ||
| 1731 | retry: | 1760 | retry: |
| @@ -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 | ||
