diff options
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 531 |
1 files changed, 356 insertions, 175 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 6d600a69fc9d..cac448282331 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -202,13 +202,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
202 | struct inode *inode); | 202 | struct inode *inode); |
203 | 203 | ||
204 | /* checksumming functions */ | 204 | /* checksumming functions */ |
205 | #define EXT4_DIRENT_TAIL(block, blocksize) \ | 205 | void initialize_dirent_tail(struct ext4_dir_entry_tail *t, |
206 | ((struct ext4_dir_entry_tail *)(((void *)(block)) + \ | 206 | unsigned int blocksize) |
207 | ((blocksize) - \ | ||
208 | sizeof(struct ext4_dir_entry_tail)))) | ||
209 | |||
210 | static void initialize_dirent_tail(struct ext4_dir_entry_tail *t, | ||
211 | unsigned int blocksize) | ||
212 | { | 207 | { |
213 | memset(t, 0, sizeof(struct ext4_dir_entry_tail)); | 208 | memset(t, 0, sizeof(struct ext4_dir_entry_tail)); |
214 | t->det_rec_len = ext4_rec_len_to_disk( | 209 | t->det_rec_len = ext4_rec_len_to_disk( |
@@ -261,6 +256,12 @@ static __le32 ext4_dirent_csum(struct inode *inode, | |||
261 | return cpu_to_le32(csum); | 256 | return cpu_to_le32(csum); |
262 | } | 257 | } |
263 | 258 | ||
259 | static void warn_no_space_for_csum(struct inode *inode) | ||
260 | { | ||
261 | ext4_warning(inode->i_sb, "no space in directory inode %lu leaf for " | ||
262 | "checksum. Please run e2fsck -D.", inode->i_ino); | ||
263 | } | ||
264 | |||
264 | int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) | 265 | int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) |
265 | { | 266 | { |
266 | struct ext4_dir_entry_tail *t; | 267 | struct ext4_dir_entry_tail *t; |
@@ -271,8 +272,7 @@ int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) | |||
271 | 272 | ||
272 | t = get_dirent_tail(inode, dirent); | 273 | t = get_dirent_tail(inode, dirent); |
273 | if (!t) { | 274 | if (!t) { |
274 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir " | 275 | warn_no_space_for_csum(inode); |
275 | "leaf for checksum. Please run e2fsck -D."); | ||
276 | return 0; | 276 | return 0; |
277 | } | 277 | } |
278 | 278 | ||
@@ -294,8 +294,7 @@ static void ext4_dirent_csum_set(struct inode *inode, | |||
294 | 294 | ||
295 | t = get_dirent_tail(inode, dirent); | 295 | t = get_dirent_tail(inode, dirent); |
296 | if (!t) { | 296 | if (!t) { |
297 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir " | 297 | warn_no_space_for_csum(inode); |
298 | "leaf for checksum. Please run e2fsck -D."); | ||
299 | return; | 298 | return; |
300 | } | 299 | } |
301 | 300 | ||
@@ -303,9 +302,9 @@ static void ext4_dirent_csum_set(struct inode *inode, | |||
303 | (void *)t - (void *)dirent); | 302 | (void *)t - (void *)dirent); |
304 | } | 303 | } |
305 | 304 | ||
306 | static inline int ext4_handle_dirty_dirent_node(handle_t *handle, | 305 | int ext4_handle_dirty_dirent_node(handle_t *handle, |
307 | struct inode *inode, | 306 | struct inode *inode, |
308 | struct buffer_head *bh) | 307 | struct buffer_head *bh) |
309 | { | 308 | { |
310 | ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); | 309 | ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); |
311 | return ext4_handle_dirty_metadata(handle, inode, bh); | 310 | return ext4_handle_dirty_metadata(handle, inode, bh); |
@@ -377,8 +376,7 @@ static int ext4_dx_csum_verify(struct inode *inode, | |||
377 | count = le16_to_cpu(c->count); | 376 | count = le16_to_cpu(c->count); |
378 | if (count_offset + (limit * sizeof(struct dx_entry)) > | 377 | if (count_offset + (limit * sizeof(struct dx_entry)) > |
379 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { | 378 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { |
380 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space for " | 379 | warn_no_space_for_csum(inode); |
381 | "tree checksum found. Run e2fsck -D."); | ||
382 | return 1; | 380 | return 1; |
383 | } | 381 | } |
384 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); | 382 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); |
@@ -408,8 +406,7 @@ static void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent) | |||
408 | count = le16_to_cpu(c->count); | 406 | count = le16_to_cpu(c->count); |
409 | if (count_offset + (limit * sizeof(struct dx_entry)) > | 407 | if (count_offset + (limit * sizeof(struct dx_entry)) > |
410 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { | 408 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { |
411 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space for " | 409 | warn_no_space_for_csum(inode); |
412 | "tree checksum. Run e2fsck -D."); | ||
413 | return; | 410 | return; |
414 | } | 411 | } |
415 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); | 412 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); |
@@ -890,6 +887,7 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
890 | EXT4_DIR_REC_LEN(0)); | 887 | EXT4_DIR_REC_LEN(0)); |
891 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { | 888 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { |
892 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 889 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
890 | bh->b_data, bh->b_size, | ||
893 | (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) | 891 | (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) |
894 | + ((char *)de - bh->b_data))) { | 892 | + ((char *)de - bh->b_data))) { |
895 | /* On error, skip the f_pos to the next block. */ | 893 | /* On error, skip the f_pos to the next block. */ |
@@ -1007,6 +1005,15 @@ errout: | |||
1007 | return (err); | 1005 | return (err); |
1008 | } | 1006 | } |
1009 | 1007 | ||
1008 | static inline int search_dirblock(struct buffer_head *bh, | ||
1009 | struct inode *dir, | ||
1010 | const struct qstr *d_name, | ||
1011 | unsigned int offset, | ||
1012 | struct ext4_dir_entry_2 **res_dir) | ||
1013 | { | ||
1014 | return search_dir(bh, bh->b_data, dir->i_sb->s_blocksize, dir, | ||
1015 | d_name, offset, res_dir); | ||
1016 | } | ||
1010 | 1017 | ||
1011 | /* | 1018 | /* |
1012 | * Directory block splitting, compacting | 1019 | * Directory block splitting, compacting |
@@ -1081,13 +1088,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) | |||
1081 | dx_set_count(entries, count + 1); | 1088 | dx_set_count(entries, count + 1); |
1082 | } | 1089 | } |
1083 | 1090 | ||
1084 | static void ext4_update_dx_flag(struct inode *inode) | ||
1085 | { | ||
1086 | if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb, | ||
1087 | EXT4_FEATURE_COMPAT_DIR_INDEX)) | ||
1088 | ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); | ||
1089 | } | ||
1090 | |||
1091 | /* | 1091 | /* |
1092 | * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. | 1092 | * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. |
1093 | * | 1093 | * |
@@ -1107,11 +1107,13 @@ static inline int ext4_match (int len, const char * const name, | |||
1107 | /* | 1107 | /* |
1108 | * Returns 0 if not found, -1 on failure, and 1 on success | 1108 | * Returns 0 if not found, -1 on failure, and 1 on success |
1109 | */ | 1109 | */ |
1110 | static inline int search_dirblock(struct buffer_head *bh, | 1110 | int search_dir(struct buffer_head *bh, |
1111 | struct inode *dir, | 1111 | char *search_buf, |
1112 | const struct qstr *d_name, | 1112 | int buf_size, |
1113 | unsigned int offset, | 1113 | struct inode *dir, |
1114 | struct ext4_dir_entry_2 ** res_dir) | 1114 | const struct qstr *d_name, |
1115 | unsigned int offset, | ||
1116 | struct ext4_dir_entry_2 **res_dir) | ||
1115 | { | 1117 | { |
1116 | struct ext4_dir_entry_2 * de; | 1118 | struct ext4_dir_entry_2 * de; |
1117 | char * dlimit; | 1119 | char * dlimit; |
@@ -1119,8 +1121,8 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
1119 | const char *name = d_name->name; | 1121 | const char *name = d_name->name; |
1120 | int namelen = d_name->len; | 1122 | int namelen = d_name->len; |
1121 | 1123 | ||
1122 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 1124 | de = (struct ext4_dir_entry_2 *)search_buf; |
1123 | dlimit = bh->b_data + dir->i_sb->s_blocksize; | 1125 | dlimit = search_buf + buf_size; |
1124 | while ((char *) de < dlimit) { | 1126 | while ((char *) de < dlimit) { |
1125 | /* this code is executed quadratically often */ | 1127 | /* this code is executed quadratically often */ |
1126 | /* do minimal checking `by hand' */ | 1128 | /* do minimal checking `by hand' */ |
@@ -1128,7 +1130,8 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
1128 | if ((char *) de + namelen <= dlimit && | 1130 | if ((char *) de + namelen <= dlimit && |
1129 | ext4_match (namelen, name, de)) { | 1131 | ext4_match (namelen, name, de)) { |
1130 | /* found a match - just to be sure, do a full check */ | 1132 | /* found a match - just to be sure, do a full check */ |
1131 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1133 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, |
1134 | bh->b_size, offset)) | ||
1132 | return -1; | 1135 | return -1; |
1133 | *res_dir = de; | 1136 | *res_dir = de; |
1134 | return 1; | 1137 | return 1; |
@@ -1144,6 +1147,21 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
1144 | return 0; | 1147 | return 0; |
1145 | } | 1148 | } |
1146 | 1149 | ||
1150 | static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, | ||
1151 | struct ext4_dir_entry *de) | ||
1152 | { | ||
1153 | struct super_block *sb = dir->i_sb; | ||
1154 | |||
1155 | if (!is_dx(dir)) | ||
1156 | return 0; | ||
1157 | if (block == 0) | ||
1158 | return 1; | ||
1159 | if (de->inode == 0 && | ||
1160 | ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) == | ||
1161 | sb->s_blocksize) | ||
1162 | return 1; | ||
1163 | return 0; | ||
1164 | } | ||
1147 | 1165 | ||
1148 | /* | 1166 | /* |
1149 | * ext4_find_entry() | 1167 | * ext4_find_entry() |
@@ -1158,7 +1176,8 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
1158 | */ | 1176 | */ |
1159 | static struct buffer_head * ext4_find_entry (struct inode *dir, | 1177 | static struct buffer_head * ext4_find_entry (struct inode *dir, |
1160 | const struct qstr *d_name, | 1178 | const struct qstr *d_name, |
1161 | struct ext4_dir_entry_2 ** res_dir) | 1179 | struct ext4_dir_entry_2 **res_dir, |
1180 | int *inlined) | ||
1162 | { | 1181 | { |
1163 | struct super_block *sb; | 1182 | struct super_block *sb; |
1164 | struct buffer_head *bh_use[NAMEI_RA_SIZE]; | 1183 | struct buffer_head *bh_use[NAMEI_RA_SIZE]; |
@@ -1179,6 +1198,18 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, | |||
1179 | namelen = d_name->len; | 1198 | namelen = d_name->len; |
1180 | if (namelen > EXT4_NAME_LEN) | 1199 | if (namelen > EXT4_NAME_LEN) |
1181 | return NULL; | 1200 | return NULL; |
1201 | |||
1202 | if (ext4_has_inline_data(dir)) { | ||
1203 | int has_inline_data = 1; | ||
1204 | ret = ext4_find_inline_entry(dir, d_name, res_dir, | ||
1205 | &has_inline_data); | ||
1206 | if (has_inline_data) { | ||
1207 | if (inlined) | ||
1208 | *inlined = 1; | ||
1209 | return ret; | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1182 | if ((namelen <= 2) && (name[0] == '.') && | 1213 | if ((namelen <= 2) && (name[0] == '.') && |
1183 | (name[1] == '.' || name[1] == '\0')) { | 1214 | (name[1] == '.' || name[1] == '\0')) { |
1184 | /* | 1215 | /* |
@@ -1244,6 +1275,8 @@ restart: | |||
1244 | goto next; | 1275 | goto next; |
1245 | } | 1276 | } |
1246 | if (!buffer_verified(bh) && | 1277 | if (!buffer_verified(bh) && |
1278 | !is_dx_internal_node(dir, block, | ||
1279 | (struct ext4_dir_entry *)bh->b_data) && | ||
1247 | !ext4_dirent_csum_verify(dir, | 1280 | !ext4_dirent_csum_verify(dir, |
1248 | (struct ext4_dir_entry *)bh->b_data)) { | 1281 | (struct ext4_dir_entry *)bh->b_data)) { |
1249 | EXT4_ERROR_INODE(dir, "checksumming directory " | 1282 | EXT4_ERROR_INODE(dir, "checksumming directory " |
@@ -1361,7 +1394,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi | |||
1361 | if (dentry->d_name.len > EXT4_NAME_LEN) | 1394 | if (dentry->d_name.len > EXT4_NAME_LEN) |
1362 | return ERR_PTR(-ENAMETOOLONG); | 1395 | return ERR_PTR(-ENAMETOOLONG); |
1363 | 1396 | ||
1364 | bh = ext4_find_entry(dir, &dentry->d_name, &de); | 1397 | bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); |
1365 | inode = NULL; | 1398 | inode = NULL; |
1366 | if (bh) { | 1399 | if (bh) { |
1367 | __u32 ino = le32_to_cpu(de->inode); | 1400 | __u32 ino = le32_to_cpu(de->inode); |
@@ -1395,7 +1428,7 @@ struct dentry *ext4_get_parent(struct dentry *child) | |||
1395 | struct ext4_dir_entry_2 * de; | 1428 | struct ext4_dir_entry_2 * de; |
1396 | struct buffer_head *bh; | 1429 | struct buffer_head *bh; |
1397 | 1430 | ||
1398 | bh = ext4_find_entry(child->d_inode, &dotdot, &de); | 1431 | bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL); |
1399 | if (!bh) | 1432 | if (!bh) |
1400 | return ERR_PTR(-ENOENT); | 1433 | return ERR_PTR(-ENOENT); |
1401 | ino = le32_to_cpu(de->inode); | 1434 | ino = le32_to_cpu(de->inode); |
@@ -1593,6 +1626,63 @@ errout: | |||
1593 | return NULL; | 1626 | return NULL; |
1594 | } | 1627 | } |
1595 | 1628 | ||
1629 | int ext4_find_dest_de(struct inode *dir, struct inode *inode, | ||
1630 | struct buffer_head *bh, | ||
1631 | void *buf, int buf_size, | ||
1632 | const char *name, int namelen, | ||
1633 | struct ext4_dir_entry_2 **dest_de) | ||
1634 | { | ||
1635 | struct ext4_dir_entry_2 *de; | ||
1636 | unsigned short reclen = EXT4_DIR_REC_LEN(namelen); | ||
1637 | int nlen, rlen; | ||
1638 | unsigned int offset = 0; | ||
1639 | char *top; | ||
1640 | |||
1641 | de = (struct ext4_dir_entry_2 *)buf; | ||
1642 | top = buf + buf_size - reclen; | ||
1643 | while ((char *) de <= top) { | ||
1644 | if (ext4_check_dir_entry(dir, NULL, de, bh, | ||
1645 | buf, buf_size, offset)) | ||
1646 | return -EIO; | ||
1647 | if (ext4_match(namelen, name, de)) | ||
1648 | return -EEXIST; | ||
1649 | nlen = EXT4_DIR_REC_LEN(de->name_len); | ||
1650 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); | ||
1651 | if ((de->inode ? rlen - nlen : rlen) >= reclen) | ||
1652 | break; | ||
1653 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); | ||
1654 | offset += rlen; | ||
1655 | } | ||
1656 | if ((char *) de > top) | ||
1657 | return -ENOSPC; | ||
1658 | |||
1659 | *dest_de = de; | ||
1660 | return 0; | ||
1661 | } | ||
1662 | |||
1663 | void ext4_insert_dentry(struct inode *inode, | ||
1664 | struct ext4_dir_entry_2 *de, | ||
1665 | int buf_size, | ||
1666 | const char *name, int namelen) | ||
1667 | { | ||
1668 | |||
1669 | int nlen, rlen; | ||
1670 | |||
1671 | nlen = EXT4_DIR_REC_LEN(de->name_len); | ||
1672 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); | ||
1673 | if (de->inode) { | ||
1674 | struct ext4_dir_entry_2 *de1 = | ||
1675 | (struct ext4_dir_entry_2 *)((char *)de + nlen); | ||
1676 | de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size); | ||
1677 | de->rec_len = ext4_rec_len_to_disk(nlen, buf_size); | ||
1678 | de = de1; | ||
1679 | } | ||
1680 | de->file_type = EXT4_FT_UNKNOWN; | ||
1681 | de->inode = cpu_to_le32(inode->i_ino); | ||
1682 | ext4_set_de_type(inode->i_sb, de, inode->i_mode); | ||
1683 | de->name_len = namelen; | ||
1684 | memcpy(de->name, name, namelen); | ||
1685 | } | ||
1596 | /* | 1686 | /* |
1597 | * Add a new entry into a directory (leaf) block. If de is non-NULL, | 1687 | * Add a new entry into a directory (leaf) block. If de is non-NULL, |
1598 | * it points to a directory entry which is guaranteed to be large | 1688 | * it points to a directory entry which is guaranteed to be large |
@@ -1608,12 +1698,10 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1608 | struct inode *dir = dentry->d_parent->d_inode; | 1698 | struct inode *dir = dentry->d_parent->d_inode; |
1609 | const char *name = dentry->d_name.name; | 1699 | const char *name = dentry->d_name.name; |
1610 | int namelen = dentry->d_name.len; | 1700 | int namelen = dentry->d_name.len; |
1611 | unsigned int offset = 0; | ||
1612 | unsigned int blocksize = dir->i_sb->s_blocksize; | 1701 | unsigned int blocksize = dir->i_sb->s_blocksize; |
1613 | unsigned short reclen; | 1702 | unsigned short reclen; |
1614 | int nlen, rlen, err; | ||
1615 | char *top; | ||
1616 | int csum_size = 0; | 1703 | int csum_size = 0; |
1704 | int err; | ||
1617 | 1705 | ||
1618 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 1706 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, |
1619 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | 1707 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) |
@@ -1621,22 +1709,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1621 | 1709 | ||
1622 | reclen = EXT4_DIR_REC_LEN(namelen); | 1710 | reclen = EXT4_DIR_REC_LEN(namelen); |
1623 | if (!de) { | 1711 | if (!de) { |
1624 | de = (struct ext4_dir_entry_2 *)bh->b_data; | 1712 | err = ext4_find_dest_de(dir, inode, |
1625 | top = bh->b_data + (blocksize - csum_size) - reclen; | 1713 | bh, bh->b_data, blocksize - csum_size, |
1626 | while ((char *) de <= top) { | 1714 | name, namelen, &de); |
1627 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1715 | if (err) |
1628 | return -EIO; | 1716 | return err; |
1629 | if (ext4_match(namelen, name, de)) | ||
1630 | return -EEXIST; | ||
1631 | nlen = EXT4_DIR_REC_LEN(de->name_len); | ||
1632 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); | ||
1633 | if ((de->inode? rlen - nlen: rlen) >= reclen) | ||
1634 | break; | ||
1635 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); | ||
1636 | offset += rlen; | ||
1637 | } | ||
1638 | if ((char *) de > top) | ||
1639 | return -ENOSPC; | ||
1640 | } | 1717 | } |
1641 | BUFFER_TRACE(bh, "get_write_access"); | 1718 | BUFFER_TRACE(bh, "get_write_access"); |
1642 | err = ext4_journal_get_write_access(handle, bh); | 1719 | err = ext4_journal_get_write_access(handle, bh); |
@@ -1646,19 +1723,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1646 | } | 1723 | } |
1647 | 1724 | ||
1648 | /* By now the buffer is marked for journaling */ | 1725 | /* By now the buffer is marked for journaling */ |
1649 | nlen = EXT4_DIR_REC_LEN(de->name_len); | 1726 | ext4_insert_dentry(inode, de, blocksize, name, namelen); |
1650 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); | 1727 | |
1651 | if (de->inode) { | ||
1652 | struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen); | ||
1653 | de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, blocksize); | ||
1654 | de->rec_len = ext4_rec_len_to_disk(nlen, blocksize); | ||
1655 | de = de1; | ||
1656 | } | ||
1657 | de->file_type = EXT4_FT_UNKNOWN; | ||
1658 | de->inode = cpu_to_le32(inode->i_ino); | ||
1659 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); | ||
1660 | de->name_len = namelen; | ||
1661 | memcpy(de->name, name, namelen); | ||
1662 | /* | 1728 | /* |
1663 | * XXX shouldn't update any times until successful | 1729 | * XXX shouldn't update any times until successful |
1664 | * completion of syscall, but too many callers depend | 1730 | * completion of syscall, but too many callers depend |
@@ -1831,6 +1897,17 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1831 | blocksize = sb->s_blocksize; | 1897 | blocksize = sb->s_blocksize; |
1832 | if (!dentry->d_name.len) | 1898 | if (!dentry->d_name.len) |
1833 | return -EINVAL; | 1899 | return -EINVAL; |
1900 | |||
1901 | if (ext4_has_inline_data(dir)) { | ||
1902 | retval = ext4_try_add_inline_entry(handle, dentry, inode); | ||
1903 | if (retval < 0) | ||
1904 | return retval; | ||
1905 | if (retval == 1) { | ||
1906 | retval = 0; | ||
1907 | return retval; | ||
1908 | } | ||
1909 | } | ||
1910 | |||
1834 | if (is_dx(dir)) { | 1911 | if (is_dx(dir)) { |
1835 | retval = ext4_dx_add_entry(handle, dentry, inode); | 1912 | retval = ext4_dx_add_entry(handle, dentry, inode); |
1836 | if (!retval || (retval != ERR_BAD_DX_DIR)) | 1913 | if (!retval || (retval != ERR_BAD_DX_DIR)) |
@@ -2036,36 +2113,29 @@ cleanup: | |||
2036 | } | 2113 | } |
2037 | 2114 | ||
2038 | /* | 2115 | /* |
2039 | * ext4_delete_entry deletes a directory entry by merging it with the | 2116 | * ext4_generic_delete_entry deletes a directory entry by merging it |
2040 | * previous entry | 2117 | * with the previous entry |
2041 | */ | 2118 | */ |
2042 | static int ext4_delete_entry(handle_t *handle, | 2119 | int ext4_generic_delete_entry(handle_t *handle, |
2043 | struct inode *dir, | 2120 | struct inode *dir, |
2044 | struct ext4_dir_entry_2 *de_del, | 2121 | struct ext4_dir_entry_2 *de_del, |
2045 | struct buffer_head *bh) | 2122 | struct buffer_head *bh, |
2123 | void *entry_buf, | ||
2124 | int buf_size, | ||
2125 | int csum_size) | ||
2046 | { | 2126 | { |
2047 | struct ext4_dir_entry_2 *de, *pde; | 2127 | struct ext4_dir_entry_2 *de, *pde; |
2048 | unsigned int blocksize = dir->i_sb->s_blocksize; | 2128 | unsigned int blocksize = dir->i_sb->s_blocksize; |
2049 | int csum_size = 0; | 2129 | int i; |
2050 | int i, err; | ||
2051 | |||
2052 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
2053 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2054 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
2055 | 2130 | ||
2056 | i = 0; | 2131 | i = 0; |
2057 | pde = NULL; | 2132 | pde = NULL; |
2058 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2133 | de = (struct ext4_dir_entry_2 *)entry_buf; |
2059 | while (i < bh->b_size - csum_size) { | 2134 | while (i < buf_size - csum_size) { |
2060 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) | 2135 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
2136 | bh->b_data, bh->b_size, i)) | ||
2061 | return -EIO; | 2137 | return -EIO; |
2062 | if (de == de_del) { | 2138 | if (de == de_del) { |
2063 | BUFFER_TRACE(bh, "get_write_access"); | ||
2064 | err = ext4_journal_get_write_access(handle, bh); | ||
2065 | if (unlikely(err)) { | ||
2066 | ext4_std_error(dir->i_sb, err); | ||
2067 | return err; | ||
2068 | } | ||
2069 | if (pde) | 2139 | if (pde) |
2070 | pde->rec_len = ext4_rec_len_to_disk( | 2140 | pde->rec_len = ext4_rec_len_to_disk( |
2071 | ext4_rec_len_from_disk(pde->rec_len, | 2141 | ext4_rec_len_from_disk(pde->rec_len, |
@@ -2076,12 +2146,6 @@ static int ext4_delete_entry(handle_t *handle, | |||
2076 | else | 2146 | else |
2077 | de->inode = 0; | 2147 | de->inode = 0; |
2078 | dir->i_version++; | 2148 | dir->i_version++; |
2079 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | ||
2080 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); | ||
2081 | if (unlikely(err)) { | ||
2082 | ext4_std_error(dir->i_sb, err); | ||
2083 | return err; | ||
2084 | } | ||
2085 | return 0; | 2149 | return 0; |
2086 | } | 2150 | } |
2087 | i += ext4_rec_len_from_disk(de->rec_len, blocksize); | 2151 | i += ext4_rec_len_from_disk(de->rec_len, blocksize); |
@@ -2091,6 +2155,48 @@ static int ext4_delete_entry(handle_t *handle, | |||
2091 | return -ENOENT; | 2155 | return -ENOENT; |
2092 | } | 2156 | } |
2093 | 2157 | ||
2158 | static int ext4_delete_entry(handle_t *handle, | ||
2159 | struct inode *dir, | ||
2160 | struct ext4_dir_entry_2 *de_del, | ||
2161 | struct buffer_head *bh) | ||
2162 | { | ||
2163 | int err, csum_size = 0; | ||
2164 | |||
2165 | if (ext4_has_inline_data(dir)) { | ||
2166 | int has_inline_data = 1; | ||
2167 | err = ext4_delete_inline_entry(handle, dir, de_del, bh, | ||
2168 | &has_inline_data); | ||
2169 | if (has_inline_data) | ||
2170 | return err; | ||
2171 | } | ||
2172 | |||
2173 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
2174 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2175 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
2176 | |||
2177 | BUFFER_TRACE(bh, "get_write_access"); | ||
2178 | err = ext4_journal_get_write_access(handle, bh); | ||
2179 | if (unlikely(err)) | ||
2180 | goto out; | ||
2181 | |||
2182 | err = ext4_generic_delete_entry(handle, dir, de_del, | ||
2183 | bh, bh->b_data, | ||
2184 | dir->i_sb->s_blocksize, csum_size); | ||
2185 | if (err) | ||
2186 | goto out; | ||
2187 | |||
2188 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | ||
2189 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); | ||
2190 | if (unlikely(err)) | ||
2191 | goto out; | ||
2192 | |||
2193 | return 0; | ||
2194 | out: | ||
2195 | if (err != -ENOENT) | ||
2196 | ext4_std_error(dir->i_sb, err); | ||
2197 | return err; | ||
2198 | } | ||
2199 | |||
2094 | /* | 2200 | /* |
2095 | * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2, | 2201 | * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2, |
2096 | * since this indicates that nlinks count was previously 1. | 2202 | * since this indicates that nlinks count was previously 1. |
@@ -2211,21 +2317,95 @@ retry: | |||
2211 | return err; | 2317 | return err; |
2212 | } | 2318 | } |
2213 | 2319 | ||
2214 | static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | 2320 | struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode, |
2321 | struct ext4_dir_entry_2 *de, | ||
2322 | int blocksize, int csum_size, | ||
2323 | unsigned int parent_ino, int dotdot_real_len) | ||
2324 | { | ||
2325 | de->inode = cpu_to_le32(inode->i_ino); | ||
2326 | de->name_len = 1; | ||
2327 | de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len), | ||
2328 | blocksize); | ||
2329 | strcpy(de->name, "."); | ||
2330 | ext4_set_de_type(inode->i_sb, de, S_IFDIR); | ||
2331 | |||
2332 | de = ext4_next_entry(de, blocksize); | ||
2333 | de->inode = cpu_to_le32(parent_ino); | ||
2334 | de->name_len = 2; | ||
2335 | if (!dotdot_real_len) | ||
2336 | de->rec_len = ext4_rec_len_to_disk(blocksize - | ||
2337 | (csum_size + EXT4_DIR_REC_LEN(1)), | ||
2338 | blocksize); | ||
2339 | else | ||
2340 | de->rec_len = ext4_rec_len_to_disk( | ||
2341 | EXT4_DIR_REC_LEN(de->name_len), blocksize); | ||
2342 | strcpy(de->name, ".."); | ||
2343 | ext4_set_de_type(inode->i_sb, de, S_IFDIR); | ||
2344 | |||
2345 | return ext4_next_entry(de, blocksize); | ||
2346 | } | ||
2347 | |||
2348 | static int ext4_init_new_dir(handle_t *handle, struct inode *dir, | ||
2349 | struct inode *inode) | ||
2215 | { | 2350 | { |
2216 | handle_t *handle; | ||
2217 | struct inode *inode; | ||
2218 | struct buffer_head *dir_block = NULL; | 2351 | struct buffer_head *dir_block = NULL; |
2219 | struct ext4_dir_entry_2 *de; | 2352 | struct ext4_dir_entry_2 *de; |
2220 | struct ext4_dir_entry_tail *t; | 2353 | struct ext4_dir_entry_tail *t; |
2221 | unsigned int blocksize = dir->i_sb->s_blocksize; | 2354 | unsigned int blocksize = dir->i_sb->s_blocksize; |
2222 | int csum_size = 0; | 2355 | int csum_size = 0; |
2223 | int err, retries = 0; | 2356 | int err; |
2224 | 2357 | ||
2225 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | 2358 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, |
2226 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | 2359 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) |
2227 | csum_size = sizeof(struct ext4_dir_entry_tail); | 2360 | csum_size = sizeof(struct ext4_dir_entry_tail); |
2228 | 2361 | ||
2362 | if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { | ||
2363 | err = ext4_try_create_inline_dir(handle, dir, inode); | ||
2364 | if (err < 0 && err != -ENOSPC) | ||
2365 | goto out; | ||
2366 | if (!err) | ||
2367 | goto out; | ||
2368 | } | ||
2369 | |||
2370 | inode->i_size = EXT4_I(inode)->i_disksize = blocksize; | ||
2371 | dir_block = ext4_bread(handle, inode, 0, 1, &err); | ||
2372 | if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) { | ||
2373 | if (!err) { | ||
2374 | err = -EIO; | ||
2375 | ext4_error(inode->i_sb, | ||
2376 | "Directory hole detected on inode %lu\n", | ||
2377 | inode->i_ino); | ||
2378 | } | ||
2379 | goto out; | ||
2380 | } | ||
2381 | BUFFER_TRACE(dir_block, "get_write_access"); | ||
2382 | err = ext4_journal_get_write_access(handle, dir_block); | ||
2383 | if (err) | ||
2384 | goto out; | ||
2385 | de = (struct ext4_dir_entry_2 *)dir_block->b_data; | ||
2386 | ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); | ||
2387 | set_nlink(inode, 2); | ||
2388 | if (csum_size) { | ||
2389 | t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize); | ||
2390 | initialize_dirent_tail(t, blocksize); | ||
2391 | } | ||
2392 | |||
2393 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); | ||
2394 | err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); | ||
2395 | if (err) | ||
2396 | goto out; | ||
2397 | set_buffer_verified(dir_block); | ||
2398 | out: | ||
2399 | brelse(dir_block); | ||
2400 | return err; | ||
2401 | } | ||
2402 | |||
2403 | static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | ||
2404 | { | ||
2405 | handle_t *handle; | ||
2406 | struct inode *inode; | ||
2407 | int err, retries = 0; | ||
2408 | |||
2229 | if (EXT4_DIR_LINK_MAX(dir)) | 2409 | if (EXT4_DIR_LINK_MAX(dir)) |
2230 | return -EMLINK; | 2410 | return -EMLINK; |
2231 | 2411 | ||
@@ -2249,47 +2429,9 @@ retry: | |||
2249 | 2429 | ||
2250 | inode->i_op = &ext4_dir_inode_operations; | 2430 | inode->i_op = &ext4_dir_inode_operations; |
2251 | inode->i_fop = &ext4_dir_operations; | 2431 | inode->i_fop = &ext4_dir_operations; |
2252 | inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; | 2432 | err = ext4_init_new_dir(handle, dir, inode); |
2253 | if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) { | ||
2254 | if (!err) { | ||
2255 | err = -EIO; | ||
2256 | ext4_error(inode->i_sb, | ||
2257 | "Directory hole detected on inode %lu\n", | ||
2258 | inode->i_ino); | ||
2259 | } | ||
2260 | goto out_clear_inode; | ||
2261 | } | ||
2262 | BUFFER_TRACE(dir_block, "get_write_access"); | ||
2263 | err = ext4_journal_get_write_access(handle, dir_block); | ||
2264 | if (err) | ||
2265 | goto out_clear_inode; | ||
2266 | de = (struct ext4_dir_entry_2 *) dir_block->b_data; | ||
2267 | de->inode = cpu_to_le32(inode->i_ino); | ||
2268 | de->name_len = 1; | ||
2269 | de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len), | ||
2270 | blocksize); | ||
2271 | strcpy(de->name, "."); | ||
2272 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | ||
2273 | de = ext4_next_entry(de, blocksize); | ||
2274 | de->inode = cpu_to_le32(dir->i_ino); | ||
2275 | de->rec_len = ext4_rec_len_to_disk(blocksize - | ||
2276 | (csum_size + EXT4_DIR_REC_LEN(1)), | ||
2277 | blocksize); | ||
2278 | de->name_len = 2; | ||
2279 | strcpy(de->name, ".."); | ||
2280 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | ||
2281 | set_nlink(inode, 2); | ||
2282 | |||
2283 | if (csum_size) { | ||
2284 | t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize); | ||
2285 | initialize_dirent_tail(t, blocksize); | ||
2286 | } | ||
2287 | |||
2288 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); | ||
2289 | err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); | ||
2290 | if (err) | 2433 | if (err) |
2291 | goto out_clear_inode; | 2434 | goto out_clear_inode; |
2292 | set_buffer_verified(dir_block); | ||
2293 | err = ext4_mark_inode_dirty(handle, inode); | 2435 | err = ext4_mark_inode_dirty(handle, inode); |
2294 | if (!err) | 2436 | if (!err) |
2295 | err = ext4_add_entry(handle, dentry, inode); | 2437 | err = ext4_add_entry(handle, dentry, inode); |
@@ -2309,7 +2451,6 @@ out_clear_inode: | |||
2309 | unlock_new_inode(inode); | 2451 | unlock_new_inode(inode); |
2310 | d_instantiate(dentry, inode); | 2452 | d_instantiate(dentry, inode); |
2311 | out_stop: | 2453 | out_stop: |
2312 | brelse(dir_block); | ||
2313 | ext4_journal_stop(handle); | 2454 | ext4_journal_stop(handle); |
2314 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) | 2455 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
2315 | goto retry; | 2456 | goto retry; |
@@ -2327,6 +2468,14 @@ static int empty_dir(struct inode *inode) | |||
2327 | struct super_block *sb; | 2468 | struct super_block *sb; |
2328 | int err = 0; | 2469 | int err = 0; |
2329 | 2470 | ||
2471 | if (ext4_has_inline_data(inode)) { | ||
2472 | int has_inline_data = 1; | ||
2473 | |||
2474 | err = empty_inline_dir(inode, &has_inline_data); | ||
2475 | if (has_inline_data) | ||
2476 | return err; | ||
2477 | } | ||
2478 | |||
2330 | sb = inode->i_sb; | 2479 | sb = inode->i_sb; |
2331 | if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || | 2480 | if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) || |
2332 | !(bh = ext4_bread(NULL, inode, 0, 0, &err))) { | 2481 | !(bh = ext4_bread(NULL, inode, 0, 0, &err))) { |
@@ -2393,7 +2542,8 @@ static int empty_dir(struct inode *inode) | |||
2393 | set_buffer_verified(bh); | 2542 | set_buffer_verified(bh); |
2394 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2543 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
2395 | } | 2544 | } |
2396 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { | 2545 | if (ext4_check_dir_entry(inode, NULL, de, bh, |
2546 | bh->b_data, bh->b_size, offset)) { | ||
2397 | de = (struct ext4_dir_entry_2 *)(bh->b_data + | 2547 | de = (struct ext4_dir_entry_2 *)(bh->b_data + |
2398 | sb->s_blocksize); | 2548 | sb->s_blocksize); |
2399 | offset = (offset | (sb->s_blocksize - 1)) + 1; | 2549 | offset = (offset | (sb->s_blocksize - 1)) + 1; |
@@ -2579,7 +2729,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) | |||
2579 | return PTR_ERR(handle); | 2729 | return PTR_ERR(handle); |
2580 | 2730 | ||
2581 | retval = -ENOENT; | 2731 | retval = -ENOENT; |
2582 | bh = ext4_find_entry(dir, &dentry->d_name, &de); | 2732 | bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); |
2583 | if (!bh) | 2733 | if (!bh) |
2584 | goto end_rmdir; | 2734 | goto end_rmdir; |
2585 | 2735 | ||
@@ -2644,7 +2794,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) | |||
2644 | ext4_handle_sync(handle); | 2794 | ext4_handle_sync(handle); |
2645 | 2795 | ||
2646 | retval = -ENOENT; | 2796 | retval = -ENOENT; |
2647 | bh = ext4_find_entry(dir, &dentry->d_name, &de); | 2797 | bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); |
2648 | if (!bh) | 2798 | if (!bh) |
2649 | goto end_unlink; | 2799 | goto end_unlink; |
2650 | 2800 | ||
@@ -2826,8 +2976,39 @@ retry: | |||
2826 | return err; | 2976 | return err; |
2827 | } | 2977 | } |
2828 | 2978 | ||
2829 | #define PARENT_INO(buffer, size) \ | 2979 | |
2830 | (ext4_next_entry((struct ext4_dir_entry_2 *)(buffer), size)->inode) | 2980 | /* |
2981 | * Try to find buffer head where contains the parent block. | ||
2982 | * It should be the inode block if it is inlined or the 1st block | ||
2983 | * if it is a normal dir. | ||
2984 | */ | ||
2985 | static struct buffer_head *ext4_get_first_dir_block(handle_t *handle, | ||
2986 | struct inode *inode, | ||
2987 | int *retval, | ||
2988 | struct ext4_dir_entry_2 **parent_de, | ||
2989 | int *inlined) | ||
2990 | { | ||
2991 | struct buffer_head *bh; | ||
2992 | |||
2993 | if (!ext4_has_inline_data(inode)) { | ||
2994 | if (!(bh = ext4_bread(handle, inode, 0, 0, retval))) { | ||
2995 | if (!*retval) { | ||
2996 | *retval = -EIO; | ||
2997 | ext4_error(inode->i_sb, | ||
2998 | "Directory hole detected on inode %lu\n", | ||
2999 | inode->i_ino); | ||
3000 | } | ||
3001 | return NULL; | ||
3002 | } | ||
3003 | *parent_de = ext4_next_entry( | ||
3004 | (struct ext4_dir_entry_2 *)bh->b_data, | ||
3005 | inode->i_sb->s_blocksize); | ||
3006 | return bh; | ||
3007 | } | ||
3008 | |||
3009 | *inlined = 1; | ||
3010 | return ext4_get_first_inline_block(inode, parent_de, retval); | ||
3011 | } | ||
2831 | 3012 | ||
2832 | /* | 3013 | /* |
2833 | * Anybody can rename anything with this: the permission checks are left to the | 3014 | * Anybody can rename anything with this: the permission checks are left to the |
@@ -2841,6 +3022,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2841 | struct buffer_head *old_bh, *new_bh, *dir_bh; | 3022 | struct buffer_head *old_bh, *new_bh, *dir_bh; |
2842 | struct ext4_dir_entry_2 *old_de, *new_de; | 3023 | struct ext4_dir_entry_2 *old_de, *new_de; |
2843 | int retval, force_da_alloc = 0; | 3024 | int retval, force_da_alloc = 0; |
3025 | int inlined = 0, new_inlined = 0; | ||
3026 | struct ext4_dir_entry_2 *parent_de; | ||
2844 | 3027 | ||
2845 | dquot_initialize(old_dir); | 3028 | dquot_initialize(old_dir); |
2846 | dquot_initialize(new_dir); | 3029 | dquot_initialize(new_dir); |
@@ -2860,7 +3043,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2860 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) | 3043 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) |
2861 | ext4_handle_sync(handle); | 3044 | ext4_handle_sync(handle); |
2862 | 3045 | ||
2863 | old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de); | 3046 | old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de, NULL); |
2864 | /* | 3047 | /* |
2865 | * Check for inode number is _not_ due to possible IO errors. | 3048 | * Check for inode number is _not_ due to possible IO errors. |
2866 | * We might rmdir the source, keep it as pwd of some process | 3049 | * We might rmdir the source, keep it as pwd of some process |
@@ -2873,7 +3056,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2873 | goto end_rename; | 3056 | goto end_rename; |
2874 | 3057 | ||
2875 | new_inode = new_dentry->d_inode; | 3058 | new_inode = new_dentry->d_inode; |
2876 | new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new_de); | 3059 | new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, |
3060 | &new_de, &new_inlined); | ||
2877 | if (new_bh) { | 3061 | if (new_bh) { |
2878 | if (!new_inode) { | 3062 | if (!new_inode) { |
2879 | brelse(new_bh); | 3063 | brelse(new_bh); |
@@ -2887,22 +3071,17 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2887 | goto end_rename; | 3071 | goto end_rename; |
2888 | } | 3072 | } |
2889 | retval = -EIO; | 3073 | retval = -EIO; |
2890 | if (!(dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval))) { | 3074 | dir_bh = ext4_get_first_dir_block(handle, old_inode, |
2891 | if (!retval) { | 3075 | &retval, &parent_de, |
2892 | retval = -EIO; | 3076 | &inlined); |
2893 | ext4_error(old_inode->i_sb, | 3077 | if (!dir_bh) |
2894 | "Directory hole detected on inode %lu\n", | ||
2895 | old_inode->i_ino); | ||
2896 | } | ||
2897 | goto end_rename; | 3078 | goto end_rename; |
2898 | } | 3079 | if (!inlined && !buffer_verified(dir_bh) && |
2899 | if (!buffer_verified(dir_bh) && | ||
2900 | !ext4_dirent_csum_verify(old_inode, | 3080 | !ext4_dirent_csum_verify(old_inode, |
2901 | (struct ext4_dir_entry *)dir_bh->b_data)) | 3081 | (struct ext4_dir_entry *)dir_bh->b_data)) |
2902 | goto end_rename; | 3082 | goto end_rename; |
2903 | set_buffer_verified(dir_bh); | 3083 | set_buffer_verified(dir_bh); |
2904 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, | 3084 | if (le32_to_cpu(parent_de->inode) != old_dir->i_ino) |
2905 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) | ||
2906 | goto end_rename; | 3085 | goto end_rename; |
2907 | retval = -EMLINK; | 3086 | retval = -EMLINK; |
2908 | if (!new_inode && new_dir != old_dir && | 3087 | if (!new_inode && new_dir != old_dir && |
@@ -2931,10 +3110,13 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2931 | ext4_current_time(new_dir); | 3110 | ext4_current_time(new_dir); |
2932 | ext4_mark_inode_dirty(handle, new_dir); | 3111 | ext4_mark_inode_dirty(handle, new_dir); |
2933 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); | 3112 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); |
2934 | retval = ext4_handle_dirty_dirent_node(handle, new_dir, new_bh); | 3113 | if (!new_inlined) { |
2935 | if (unlikely(retval)) { | 3114 | retval = ext4_handle_dirty_dirent_node(handle, |
2936 | ext4_std_error(new_dir->i_sb, retval); | 3115 | new_dir, new_bh); |
2937 | goto end_rename; | 3116 | if (unlikely(retval)) { |
3117 | ext4_std_error(new_dir->i_sb, retval); | ||
3118 | goto end_rename; | ||
3119 | } | ||
2938 | } | 3120 | } |
2939 | brelse(new_bh); | 3121 | brelse(new_bh); |
2940 | new_bh = NULL; | 3122 | new_bh = NULL; |
@@ -2962,7 +3144,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2962 | struct buffer_head *old_bh2; | 3144 | struct buffer_head *old_bh2; |
2963 | struct ext4_dir_entry_2 *old_de2; | 3145 | struct ext4_dir_entry_2 *old_de2; |
2964 | 3146 | ||
2965 | old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2); | 3147 | old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, |
3148 | &old_de2, NULL); | ||
2966 | if (old_bh2) { | 3149 | if (old_bh2) { |
2967 | retval = ext4_delete_entry(handle, old_dir, | 3150 | retval = ext4_delete_entry(handle, old_dir, |
2968 | old_de2, old_bh2); | 3151 | old_de2, old_bh2); |
@@ -2982,17 +3165,19 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2982 | old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); | 3165 | old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir); |
2983 | ext4_update_dx_flag(old_dir); | 3166 | ext4_update_dx_flag(old_dir); |
2984 | if (dir_bh) { | 3167 | if (dir_bh) { |
2985 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = | 3168 | parent_de->inode = cpu_to_le32(new_dir->i_ino); |
2986 | cpu_to_le32(new_dir->i_ino); | ||
2987 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); | 3169 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); |
2988 | if (is_dx(old_inode)) { | 3170 | if (!inlined) { |
2989 | retval = ext4_handle_dirty_dx_node(handle, | 3171 | if (is_dx(old_inode)) { |
2990 | old_inode, | 3172 | retval = ext4_handle_dirty_dx_node(handle, |
2991 | dir_bh); | 3173 | old_inode, |
3174 | dir_bh); | ||
3175 | } else { | ||
3176 | retval = ext4_handle_dirty_dirent_node(handle, | ||
3177 | old_inode, dir_bh); | ||
3178 | } | ||
2992 | } else { | 3179 | } else { |
2993 | retval = ext4_handle_dirty_dirent_node(handle, | 3180 | retval = ext4_mark_inode_dirty(handle, old_inode); |
2994 | old_inode, | ||
2995 | dir_bh); | ||
2996 | } | 3181 | } |
2997 | if (retval) { | 3182 | if (retval) { |
2998 | ext4_std_error(old_dir->i_sb, retval); | 3183 | ext4_std_error(old_dir->i_sb, retval); |
@@ -3043,23 +3228,19 @@ const struct inode_operations ext4_dir_inode_operations = { | |||
3043 | .mknod = ext4_mknod, | 3228 | .mknod = ext4_mknod, |
3044 | .rename = ext4_rename, | 3229 | .rename = ext4_rename, |
3045 | .setattr = ext4_setattr, | 3230 | .setattr = ext4_setattr, |
3046 | #ifdef CONFIG_EXT4_FS_XATTR | ||
3047 | .setxattr = generic_setxattr, | 3231 | .setxattr = generic_setxattr, |
3048 | .getxattr = generic_getxattr, | 3232 | .getxattr = generic_getxattr, |
3049 | .listxattr = ext4_listxattr, | 3233 | .listxattr = ext4_listxattr, |
3050 | .removexattr = generic_removexattr, | 3234 | .removexattr = generic_removexattr, |
3051 | #endif | ||
3052 | .get_acl = ext4_get_acl, | 3235 | .get_acl = ext4_get_acl, |
3053 | .fiemap = ext4_fiemap, | 3236 | .fiemap = ext4_fiemap, |
3054 | }; | 3237 | }; |
3055 | 3238 | ||
3056 | const struct inode_operations ext4_special_inode_operations = { | 3239 | const struct inode_operations ext4_special_inode_operations = { |
3057 | .setattr = ext4_setattr, | 3240 | .setattr = ext4_setattr, |
3058 | #ifdef CONFIG_EXT4_FS_XATTR | ||
3059 | .setxattr = generic_setxattr, | 3241 | .setxattr = generic_setxattr, |
3060 | .getxattr = generic_getxattr, | 3242 | .getxattr = generic_getxattr, |
3061 | .listxattr = ext4_listxattr, | 3243 | .listxattr = ext4_listxattr, |
3062 | .removexattr = generic_removexattr, | 3244 | .removexattr = generic_removexattr, |
3063 | #endif | ||
3064 | .get_acl = ext4_get_acl, | 3245 | .get_acl = ext4_get_acl, |
3065 | }; | 3246 | }; |