diff options
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 86 |
1 files changed, 64 insertions, 22 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 2811e5720ad0..da224974af78 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1017,6 +1017,11 @@ static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, str | |||
1017 | 1017 | ||
1018 | if (!inode) | 1018 | if (!inode) |
1019 | return ERR_PTR(-EACCES); | 1019 | return ERR_PTR(-EACCES); |
1020 | |||
1021 | if (is_bad_inode(inode)) { | ||
1022 | iput(inode); | ||
1023 | return ERR_PTR(-ENOENT); | ||
1024 | } | ||
1020 | } | 1025 | } |
1021 | return d_splice_alias(inode, dentry); | 1026 | return d_splice_alias(inode, dentry); |
1022 | } | 1027 | } |
@@ -1052,6 +1057,11 @@ struct dentry *ext4_get_parent(struct dentry *child) | |||
1052 | if (!inode) | 1057 | if (!inode) |
1053 | return ERR_PTR(-EACCES); | 1058 | return ERR_PTR(-EACCES); |
1054 | 1059 | ||
1060 | if (is_bad_inode(inode)) { | ||
1061 | iput(inode); | ||
1062 | return ERR_PTR(-ENOENT); | ||
1063 | } | ||
1064 | |||
1055 | parent = d_alloc_anon(inode); | 1065 | parent = d_alloc_anon(inode); |
1056 | if (!parent) { | 1066 | if (!parent) { |
1057 | iput(inode); | 1067 | iput(inode); |
@@ -1285,7 +1295,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1285 | * happen is that the times are slightly out of date | 1295 | * happen is that the times are slightly out of date |
1286 | * and/or different from the directory change time. | 1296 | * and/or different from the directory change time. |
1287 | */ | 1297 | */ |
1288 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 1298 | dir->i_mtime = dir->i_ctime = ext4_current_time(dir); |
1289 | ext4_update_dx_flag(dir); | 1299 | ext4_update_dx_flag(dir); |
1290 | dir->i_version++; | 1300 | dir->i_version++; |
1291 | ext4_mark_inode_dirty(handle, dir); | 1301 | ext4_mark_inode_dirty(handle, dir); |
@@ -1619,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle, | |||
1619 | return -ENOENT; | 1629 | return -ENOENT; |
1620 | } | 1630 | } |
1621 | 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 | |||
1622 | static int ext4_add_nondir(handle_t *handle, | 1661 | static int ext4_add_nondir(handle_t *handle, |
1623 | struct dentry *dentry, struct inode *inode) | 1662 | struct dentry *dentry, struct inode *inode) |
1624 | { | 1663 | { |
@@ -1715,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode) | |||
1715 | struct ext4_dir_entry_2 * de; | 1754 | struct ext4_dir_entry_2 * de; |
1716 | int err, retries = 0; | 1755 | int err, retries = 0; |
1717 | 1756 | ||
1718 | if (dir->i_nlink >= EXT4_LINK_MAX) | 1757 | if (EXT4_DIR_LINK_MAX(dir)) |
1719 | return -EMLINK; | 1758 | return -EMLINK; |
1720 | 1759 | ||
1721 | retry: | 1760 | retry: |
@@ -1738,7 +1777,7 @@ retry: | |||
1738 | 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; |
1739 | dir_block = ext4_bread (handle, inode, 0, 1, &err); | 1778 | dir_block = ext4_bread (handle, inode, 0, 1, &err); |
1740 | if (!dir_block) { | 1779 | if (!dir_block) { |
1741 | drop_nlink(inode); /* is this nlink == 0? */ | 1780 | ext4_dec_count(handle, inode); /* is this nlink == 0? */ |
1742 | ext4_mark_inode_dirty(handle, inode); | 1781 | ext4_mark_inode_dirty(handle, inode); |
1743 | iput (inode); | 1782 | iput (inode); |
1744 | goto out_stop; | 1783 | goto out_stop; |
@@ -1770,7 +1809,7 @@ retry: | |||
1770 | iput (inode); | 1809 | iput (inode); |
1771 | goto out_stop; | 1810 | goto out_stop; |
1772 | } | 1811 | } |
1773 | inc_nlink(dir); | 1812 | ext4_inc_count(handle, dir); |
1774 | ext4_update_dx_flag(dir); | 1813 | ext4_update_dx_flag(dir); |
1775 | ext4_mark_inode_dirty(handle, dir); | 1814 | ext4_mark_inode_dirty(handle, dir); |
1776 | d_instantiate(dentry, inode); | 1815 | d_instantiate(dentry, inode); |
@@ -2035,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry) | |||
2035 | retval = ext4_delete_entry(handle, dir, de, bh); | 2074 | retval = ext4_delete_entry(handle, dir, de, bh); |
2036 | if (retval) | 2075 | if (retval) |
2037 | goto end_rmdir; | 2076 | goto end_rmdir; |
2038 | if (inode->i_nlink != 2) | 2077 | if (!EXT4_DIR_LINK_EMPTY(inode)) |
2039 | ext4_warning (inode->i_sb, "ext4_rmdir", | 2078 | ext4_warning (inode->i_sb, "ext4_rmdir", |
2040 | "empty directory has nlink!=2 (%d)", | 2079 | "empty directory has too many links (%d)", |
2041 | inode->i_nlink); | 2080 | inode->i_nlink); |
2042 | inode->i_version++; | 2081 | inode->i_version++; |
2043 | clear_nlink(inode); | 2082 | clear_nlink(inode); |
@@ -2046,9 +2085,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry) | |||
2046 | * recovery. */ | 2085 | * recovery. */ |
2047 | inode->i_size = 0; | 2086 | inode->i_size = 0; |
2048 | ext4_orphan_add(handle, inode); | 2087 | ext4_orphan_add(handle, inode); |
2049 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | 2088 | inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode); |
2050 | ext4_mark_inode_dirty(handle, inode); | 2089 | ext4_mark_inode_dirty(handle, inode); |
2051 | drop_nlink(dir); | 2090 | ext4_dec_count(handle, dir); |
2052 | ext4_update_dx_flag(dir); | 2091 | ext4_update_dx_flag(dir); |
2053 | ext4_mark_inode_dirty(handle, dir); | 2092 | ext4_mark_inode_dirty(handle, dir); |
2054 | 2093 | ||
@@ -2096,13 +2135,13 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry) | |||
2096 | retval = ext4_delete_entry(handle, dir, de, bh); | 2135 | retval = ext4_delete_entry(handle, dir, de, bh); |
2097 | if (retval) | 2136 | if (retval) |
2098 | goto end_unlink; | 2137 | goto end_unlink; |
2099 | dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | 2138 | dir->i_ctime = dir->i_mtime = ext4_current_time(dir); |
2100 | ext4_update_dx_flag(dir); | 2139 | ext4_update_dx_flag(dir); |
2101 | ext4_mark_inode_dirty(handle, dir); | 2140 | ext4_mark_inode_dirty(handle, dir); |
2102 | drop_nlink(inode); | 2141 | ext4_dec_count(handle, inode); |
2103 | if (!inode->i_nlink) | 2142 | if (!inode->i_nlink) |
2104 | ext4_orphan_add(handle, inode); | 2143 | ext4_orphan_add(handle, inode); |
2105 | inode->i_ctime = dir->i_ctime; | 2144 | inode->i_ctime = ext4_current_time(inode); |
2106 | ext4_mark_inode_dirty(handle, inode); | 2145 | ext4_mark_inode_dirty(handle, inode); |
2107 | retval = 0; | 2146 | retval = 0; |
2108 | 2147 | ||
@@ -2149,7 +2188,7 @@ retry: | |||
2149 | err = __page_symlink(inode, symname, l, | 2188 | err = __page_symlink(inode, symname, l, |
2150 | mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); | 2189 | mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); |
2151 | if (err) { | 2190 | if (err) { |
2152 | drop_nlink(inode); | 2191 | ext4_dec_count(handle, inode); |
2153 | ext4_mark_inode_dirty(handle, inode); | 2192 | ext4_mark_inode_dirty(handle, inode); |
2154 | iput (inode); | 2193 | iput (inode); |
2155 | goto out_stop; | 2194 | goto out_stop; |
@@ -2175,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry, | |||
2175 | struct inode *inode = old_dentry->d_inode; | 2214 | struct inode *inode = old_dentry->d_inode; |
2176 | int err, retries = 0; | 2215 | int err, retries = 0; |
2177 | 2216 | ||
2178 | if (inode->i_nlink >= EXT4_LINK_MAX) | 2217 | if (EXT4_DIR_LINK_MAX(inode)) |
2179 | return -EMLINK; | 2218 | return -EMLINK; |
2219 | |||
2180 | /* | 2220 | /* |
2181 | * 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 |
2182 | * otherwise has the potential to corrupt the orphan inode list. | 2222 | * otherwise has the potential to corrupt the orphan inode list. |
@@ -2193,8 +2233,8 @@ retry: | |||
2193 | if (IS_DIRSYNC(dir)) | 2233 | if (IS_DIRSYNC(dir)) |
2194 | handle->h_sync = 1; | 2234 | handle->h_sync = 1; |
2195 | 2235 | ||
2196 | inode->i_ctime = CURRENT_TIME_SEC; | 2236 | inode->i_ctime = ext4_current_time(inode); |
2197 | inc_nlink(inode); | 2237 | ext4_inc_count(handle, inode); |
2198 | atomic_inc(&inode->i_count); | 2238 | atomic_inc(&inode->i_count); |
2199 | 2239 | ||
2200 | err = ext4_add_nondir(handle, dentry, inode); | 2240 | err = ext4_add_nondir(handle, dentry, inode); |
@@ -2295,7 +2335,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2295 | * Like most other Unix systems, set the ctime for inodes on a | 2335 | * Like most other Unix systems, set the ctime for inodes on a |
2296 | * rename. | 2336 | * rename. |
2297 | */ | 2337 | */ |
2298 | old_inode->i_ctime = CURRENT_TIME_SEC; | 2338 | old_inode->i_ctime = ext4_current_time(old_inode); |
2299 | ext4_mark_inode_dirty(handle, old_inode); | 2339 | ext4_mark_inode_dirty(handle, old_inode); |
2300 | 2340 | ||
2301 | /* | 2341 | /* |
@@ -2327,10 +2367,10 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2327 | } | 2367 | } |
2328 | 2368 | ||
2329 | if (new_inode) { | 2369 | if (new_inode) { |
2330 | drop_nlink(new_inode); | 2370 | ext4_dec_count(handle, new_inode); |
2331 | new_inode->i_ctime = CURRENT_TIME_SEC; | 2371 | new_inode->i_ctime = ext4_current_time(new_inode); |
2332 | } | 2372 | } |
2333 | old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; | 2373 | old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); |
2334 | ext4_update_dx_flag(old_dir); | 2374 | ext4_update_dx_flag(old_dir); |
2335 | if (dir_bh) { | 2375 | if (dir_bh) { |
2336 | BUFFER_TRACE(dir_bh, "get_write_access"); | 2376 | BUFFER_TRACE(dir_bh, "get_write_access"); |
@@ -2338,11 +2378,13 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2338 | 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); |
2339 | BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata"); | 2379 | BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata"); |
2340 | ext4_journal_dirty_metadata(handle, dir_bh); | 2380 | ext4_journal_dirty_metadata(handle, dir_bh); |
2341 | drop_nlink(old_dir); | 2381 | ext4_dec_count(handle, old_dir); |
2342 | if (new_inode) { | 2382 | if (new_inode) { |
2343 | 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; | ||
2344 | } else { | 2386 | } else { |
2345 | inc_nlink(new_dir); | 2387 | ext4_inc_count(handle, new_dir); |
2346 | ext4_update_dx_flag(new_dir); | 2388 | ext4_update_dx_flag(new_dir); |
2347 | ext4_mark_inode_dirty(handle, new_dir); | 2389 | ext4_mark_inode_dirty(handle, new_dir); |
2348 | } | 2390 | } |