| .. | .. |
|---|
| 54 | 54 | struct inode *inode, |
|---|
| 55 | 55 | ext4_lblk_t *block) |
|---|
| 56 | 56 | { |
|---|
| 57 | + struct ext4_map_blocks map; |
|---|
| 57 | 58 | struct buffer_head *bh; |
|---|
| 58 | 59 | int err; |
|---|
| 59 | 60 | |
|---|
| .. | .. |
|---|
| 63 | 64 | return ERR_PTR(-ENOSPC); |
|---|
| 64 | 65 | |
|---|
| 65 | 66 | *block = inode->i_size >> inode->i_sb->s_blocksize_bits; |
|---|
| 67 | + map.m_lblk = *block; |
|---|
| 68 | + map.m_len = 1; |
|---|
| 69 | + |
|---|
| 70 | + /* |
|---|
| 71 | + * We're appending new directory block. Make sure the block is not |
|---|
| 72 | + * allocated yet, otherwise we will end up corrupting the |
|---|
| 73 | + * directory. |
|---|
| 74 | + */ |
|---|
| 75 | + err = ext4_map_blocks(NULL, inode, &map, 0); |
|---|
| 76 | + if (err < 0) |
|---|
| 77 | + return ERR_PTR(err); |
|---|
| 78 | + if (err) { |
|---|
| 79 | + EXT4_ERROR_INODE(inode, "Logical block already allocated"); |
|---|
| 80 | + return ERR_PTR(-EFSCORRUPTED); |
|---|
| 81 | + } |
|---|
| 66 | 82 | |
|---|
| 67 | 83 | bh = ext4_bread(handle, inode, *block, EXT4_GET_BLOCKS_CREATE); |
|---|
| 68 | 84 | if (IS_ERR(bh)) |
|---|
| .. | .. |
|---|
| 109 | 125 | struct ext4_dir_entry *dirent; |
|---|
| 110 | 126 | int is_dx_block = 0; |
|---|
| 111 | 127 | |
|---|
| 112 | | - bh = ext4_bread(NULL, inode, block, 0); |
|---|
| 128 | + if (block >= inode->i_size >> inode->i_blkbits) { |
|---|
| 129 | + ext4_error_inode(inode, func, line, block, |
|---|
| 130 | + "Attempting to read directory block (%u) that is past i_size (%llu)", |
|---|
| 131 | + block, inode->i_size); |
|---|
| 132 | + return ERR_PTR(-EFSCORRUPTED); |
|---|
| 133 | + } |
|---|
| 134 | + |
|---|
| 135 | + if (ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_EIO)) |
|---|
| 136 | + bh = ERR_PTR(-EIO); |
|---|
| 137 | + else |
|---|
| 138 | + bh = ext4_bread(NULL, inode, block, 0); |
|---|
| 113 | 139 | if (IS_ERR(bh)) { |
|---|
| 114 | 140 | __ext4_warning(inode->i_sb, func, line, |
|---|
| 115 | 141 | "inode #%lu: lblock %lu: comm %s: " |
|---|
| .. | .. |
|---|
| 153 | 179 | * caller is sure it should be an index block. |
|---|
| 154 | 180 | */ |
|---|
| 155 | 181 | if (is_dx_block && type == INDEX) { |
|---|
| 156 | | - if (ext4_dx_csum_verify(inode, dirent)) |
|---|
| 182 | + if (ext4_dx_csum_verify(inode, dirent) && |
|---|
| 183 | + !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) |
|---|
| 157 | 184 | set_buffer_verified(bh); |
|---|
| 158 | 185 | else { |
|---|
| 159 | | - ext4_error_inode(inode, func, line, block, |
|---|
| 160 | | - "Directory index failed checksum"); |
|---|
| 186 | + ext4_error_inode_err(inode, func, line, block, |
|---|
| 187 | + EFSBADCRC, |
|---|
| 188 | + "Directory index failed checksum"); |
|---|
| 161 | 189 | brelse(bh); |
|---|
| 162 | 190 | return ERR_PTR(-EFSBADCRC); |
|---|
| 163 | 191 | } |
|---|
| 164 | 192 | } |
|---|
| 165 | 193 | if (!is_dx_block) { |
|---|
| 166 | | - if (ext4_dirent_csum_verify(inode, dirent)) |
|---|
| 194 | + if (ext4_dirblock_csum_verify(inode, bh) && |
|---|
| 195 | + !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) |
|---|
| 167 | 196 | set_buffer_verified(bh); |
|---|
| 168 | 197 | else { |
|---|
| 169 | | - ext4_error_inode(inode, func, line, block, |
|---|
| 170 | | - "Directory block failed checksum"); |
|---|
| 198 | + ext4_error_inode_err(inode, func, line, block, |
|---|
| 199 | + EFSBADCRC, |
|---|
| 200 | + "Directory block failed checksum"); |
|---|
| 171 | 201 | brelse(bh); |
|---|
| 172 | 202 | return ERR_PTR(-EFSBADCRC); |
|---|
| 173 | 203 | } |
|---|
| .. | .. |
|---|
| 226 | 256 | u8 unused_flags; |
|---|
| 227 | 257 | } |
|---|
| 228 | 258 | info; |
|---|
| 229 | | - struct dx_entry entries[0]; |
|---|
| 259 | + struct dx_entry entries[]; |
|---|
| 230 | 260 | }; |
|---|
| 231 | 261 | |
|---|
| 232 | 262 | struct dx_node |
|---|
| 233 | 263 | { |
|---|
| 234 | 264 | struct fake_dirent fake; |
|---|
| 235 | | - struct dx_entry entries[0]; |
|---|
| 265 | + struct dx_entry entries[]; |
|---|
| 236 | 266 | }; |
|---|
| 237 | 267 | |
|---|
| 238 | 268 | |
|---|
| .. | .. |
|---|
| 295 | 325 | struct inode *dir, struct inode *inode); |
|---|
| 296 | 326 | |
|---|
| 297 | 327 | /* checksumming functions */ |
|---|
| 298 | | -void initialize_dirent_tail(struct ext4_dir_entry_tail *t, |
|---|
| 299 | | - unsigned int blocksize) |
|---|
| 328 | +void ext4_initialize_dirent_tail(struct buffer_head *bh, |
|---|
| 329 | + unsigned int blocksize) |
|---|
| 300 | 330 | { |
|---|
| 331 | + struct ext4_dir_entry_tail *t = EXT4_DIRENT_TAIL(bh->b_data, blocksize); |
|---|
| 332 | + |
|---|
| 301 | 333 | memset(t, 0, sizeof(struct ext4_dir_entry_tail)); |
|---|
| 302 | 334 | t->det_rec_len = ext4_rec_len_to_disk( |
|---|
| 303 | 335 | sizeof(struct ext4_dir_entry_tail), blocksize); |
|---|
| .. | .. |
|---|
| 306 | 338 | |
|---|
| 307 | 339 | /* Walk through a dirent block to find a checksum "dirent" at the tail */ |
|---|
| 308 | 340 | static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode, |
|---|
| 309 | | - struct ext4_dir_entry *de) |
|---|
| 341 | + struct buffer_head *bh) |
|---|
| 310 | 342 | { |
|---|
| 311 | 343 | struct ext4_dir_entry_tail *t; |
|---|
| 312 | 344 | |
|---|
| 313 | 345 | #ifdef PARANOID |
|---|
| 314 | 346 | struct ext4_dir_entry *d, *top; |
|---|
| 315 | 347 | |
|---|
| 316 | | - d = de; |
|---|
| 317 | | - top = (struct ext4_dir_entry *)(((void *)de) + |
|---|
| 348 | + d = (struct ext4_dir_entry *)bh->b_data; |
|---|
| 349 | + top = (struct ext4_dir_entry *)(bh->b_data + |
|---|
| 318 | 350 | (EXT4_BLOCK_SIZE(inode->i_sb) - |
|---|
| 319 | | - sizeof(struct ext4_dir_entry_tail))); |
|---|
| 351 | + sizeof(struct ext4_dir_entry_tail))); |
|---|
| 320 | 352 | while (d < top && d->rec_len) |
|---|
| 321 | 353 | d = (struct ext4_dir_entry *)(((void *)d) + |
|---|
| 322 | 354 | le16_to_cpu(d->rec_len)); |
|---|
| .. | .. |
|---|
| 326 | 358 | |
|---|
| 327 | 359 | t = (struct ext4_dir_entry_tail *)d; |
|---|
| 328 | 360 | #else |
|---|
| 329 | | - t = EXT4_DIRENT_TAIL(de, EXT4_BLOCK_SIZE(inode->i_sb)); |
|---|
| 361 | + t = EXT4_DIRENT_TAIL(bh->b_data, EXT4_BLOCK_SIZE(inode->i_sb)); |
|---|
| 330 | 362 | #endif |
|---|
| 331 | 363 | |
|---|
| 332 | 364 | if (t->det_reserved_zero1 || |
|---|
| .. | .. |
|---|
| 338 | 370 | return t; |
|---|
| 339 | 371 | } |
|---|
| 340 | 372 | |
|---|
| 341 | | -static __le32 ext4_dirent_csum(struct inode *inode, |
|---|
| 342 | | - struct ext4_dir_entry *dirent, int size) |
|---|
| 373 | +static __le32 ext4_dirblock_csum(struct inode *inode, void *dirent, int size) |
|---|
| 343 | 374 | { |
|---|
| 344 | 375 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
|---|
| 345 | 376 | struct ext4_inode_info *ei = EXT4_I(inode); |
|---|
| .. | .. |
|---|
| 359 | 390 | "No space for directory leaf checksum. Please run e2fsck -D."); |
|---|
| 360 | 391 | } |
|---|
| 361 | 392 | |
|---|
| 362 | | -int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) |
|---|
| 393 | +int ext4_dirblock_csum_verify(struct inode *inode, struct buffer_head *bh) |
|---|
| 363 | 394 | { |
|---|
| 364 | 395 | struct ext4_dir_entry_tail *t; |
|---|
| 365 | 396 | |
|---|
| 366 | 397 | if (!ext4_has_metadata_csum(inode->i_sb)) |
|---|
| 367 | 398 | return 1; |
|---|
| 368 | 399 | |
|---|
| 369 | | - t = get_dirent_tail(inode, dirent); |
|---|
| 400 | + t = get_dirent_tail(inode, bh); |
|---|
| 370 | 401 | if (!t) { |
|---|
| 371 | 402 | warn_no_space_for_csum(inode); |
|---|
| 372 | 403 | return 0; |
|---|
| 373 | 404 | } |
|---|
| 374 | 405 | |
|---|
| 375 | | - if (t->det_checksum != ext4_dirent_csum(inode, dirent, |
|---|
| 376 | | - (void *)t - (void *)dirent)) |
|---|
| 406 | + if (t->det_checksum != ext4_dirblock_csum(inode, bh->b_data, |
|---|
| 407 | + (char *)t - bh->b_data)) |
|---|
| 377 | 408 | return 0; |
|---|
| 378 | 409 | |
|---|
| 379 | 410 | return 1; |
|---|
| 380 | 411 | } |
|---|
| 381 | 412 | |
|---|
| 382 | | -static void ext4_dirent_csum_set(struct inode *inode, |
|---|
| 383 | | - struct ext4_dir_entry *dirent) |
|---|
| 413 | +static void ext4_dirblock_csum_set(struct inode *inode, |
|---|
| 414 | + struct buffer_head *bh) |
|---|
| 384 | 415 | { |
|---|
| 385 | 416 | struct ext4_dir_entry_tail *t; |
|---|
| 386 | 417 | |
|---|
| 387 | 418 | if (!ext4_has_metadata_csum(inode->i_sb)) |
|---|
| 388 | 419 | return; |
|---|
| 389 | 420 | |
|---|
| 390 | | - t = get_dirent_tail(inode, dirent); |
|---|
| 421 | + t = get_dirent_tail(inode, bh); |
|---|
| 391 | 422 | if (!t) { |
|---|
| 392 | 423 | warn_no_space_for_csum(inode); |
|---|
| 393 | 424 | return; |
|---|
| 394 | 425 | } |
|---|
| 395 | 426 | |
|---|
| 396 | | - t->det_checksum = ext4_dirent_csum(inode, dirent, |
|---|
| 397 | | - (void *)t - (void *)dirent); |
|---|
| 427 | + t->det_checksum = ext4_dirblock_csum(inode, bh->b_data, |
|---|
| 428 | + (char *)t - bh->b_data); |
|---|
| 398 | 429 | } |
|---|
| 399 | 430 | |
|---|
| 400 | | -int ext4_handle_dirty_dirent_node(handle_t *handle, |
|---|
| 401 | | - struct inode *inode, |
|---|
| 402 | | - struct buffer_head *bh) |
|---|
| 431 | +int ext4_handle_dirty_dirblock(handle_t *handle, |
|---|
| 432 | + struct inode *inode, |
|---|
| 433 | + struct buffer_head *bh) |
|---|
| 403 | 434 | { |
|---|
| 404 | | - ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); |
|---|
| 435 | + ext4_dirblock_csum_set(inode, bh); |
|---|
| 405 | 436 | return ext4_handle_dirty_metadata(handle, inode, bh); |
|---|
| 406 | 437 | } |
|---|
| 407 | 438 | |
|---|
| .. | .. |
|---|
| 639 | 670 | |
|---|
| 640 | 671 | name = de->name; |
|---|
| 641 | 672 | len = de->name_len; |
|---|
| 642 | | - if (IS_ENCRYPTED(dir)) |
|---|
| 643 | | - res = fscrypt_get_encryption_info(dir); |
|---|
| 644 | | - if (res) { |
|---|
| 645 | | - printk(KERN_WARNING "Error setting up" |
|---|
| 646 | | - " fname crypto: %d\n", res); |
|---|
| 647 | | - } |
|---|
| 648 | | - if (!fscrypt_has_encryption_key(dir)) { |
|---|
| 673 | + if (!IS_ENCRYPTED(dir)) { |
|---|
| 649 | 674 | /* Directory is not encrypted */ |
|---|
| 650 | 675 | ext4fs_dirhash(dir, de->name, |
|---|
| 651 | 676 | de->name_len, &h); |
|---|
| .. | .. |
|---|
| 659 | 684 | |
|---|
| 660 | 685 | /* Directory is encrypted */ |
|---|
| 661 | 686 | res = fscrypt_fname_alloc_buffer( |
|---|
| 662 | | - dir, len, |
|---|
| 663 | | - &fname_crypto_str); |
|---|
| 687 | + len, &fname_crypto_str); |
|---|
| 664 | 688 | if (res) |
|---|
| 665 | 689 | printk(KERN_WARNING "Error " |
|---|
| 666 | 690 | "allocating crypto " |
|---|
| .. | .. |
|---|
| 756 | 780 | dx_probe(struct ext4_filename *fname, struct inode *dir, |
|---|
| 757 | 781 | struct dx_hash_info *hinfo, struct dx_frame *frame_in) |
|---|
| 758 | 782 | { |
|---|
| 759 | | - unsigned count, indirect; |
|---|
| 783 | + unsigned count, indirect, level, i; |
|---|
| 760 | 784 | struct dx_entry *at, *entries, *p, *q, *m; |
|---|
| 761 | 785 | struct dx_root *root; |
|---|
| 762 | 786 | struct dx_frame *frame = frame_in; |
|---|
| 763 | 787 | struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); |
|---|
| 764 | 788 | u32 hash; |
|---|
| 789 | + ext4_lblk_t block; |
|---|
| 790 | + ext4_lblk_t blocks[EXT4_HTREE_LEVEL]; |
|---|
| 765 | 791 | |
|---|
| 766 | 792 | memset(frame_in, 0, EXT4_HTREE_LEVEL * sizeof(frame_in[0])); |
|---|
| 767 | 793 | frame->bh = ext4_read_dirblock(dir, 0, INDEX); |
|---|
| .. | .. |
|---|
| 833 | 859 | } |
|---|
| 834 | 860 | |
|---|
| 835 | 861 | dxtrace(printk("Look up %x", hash)); |
|---|
| 862 | + level = 0; |
|---|
| 863 | + blocks[0] = 0; |
|---|
| 836 | 864 | while (1) { |
|---|
| 837 | 865 | count = dx_get_count(entries); |
|---|
| 838 | 866 | if (!count || count > dx_get_limit(entries)) { |
|---|
| .. | .. |
|---|
| 874 | 902 | dx_get_block(at))); |
|---|
| 875 | 903 | frame->entries = entries; |
|---|
| 876 | 904 | frame->at = at; |
|---|
| 877 | | - if (!indirect--) |
|---|
| 905 | + |
|---|
| 906 | + block = dx_get_block(at); |
|---|
| 907 | + for (i = 0; i <= level; i++) { |
|---|
| 908 | + if (blocks[i] == block) { |
|---|
| 909 | + ext4_warning_inode(dir, |
|---|
| 910 | + "dx entry: tree cycle block %u points back to block %u", |
|---|
| 911 | + blocks[level], block); |
|---|
| 912 | + goto fail; |
|---|
| 913 | + } |
|---|
| 914 | + } |
|---|
| 915 | + if (++level > indirect) |
|---|
| 878 | 916 | return frame; |
|---|
| 917 | + blocks[level] = block; |
|---|
| 879 | 918 | frame++; |
|---|
| 880 | | - frame->bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX); |
|---|
| 919 | + frame->bh = ext4_read_dirblock(dir, block, INDEX); |
|---|
| 881 | 920 | if (IS_ERR(frame->bh)) { |
|---|
| 882 | 921 | ret_err = (struct dx_frame *) frame->bh; |
|---|
| 883 | 922 | frame->bh = NULL; |
|---|
| 884 | 923 | goto fail; |
|---|
| 885 | 924 | } |
|---|
| 925 | + |
|---|
| 886 | 926 | entries = ((struct dx_node *) frame->bh->b_data)->entries; |
|---|
| 887 | 927 | |
|---|
| 888 | 928 | if (dx_get_limit(entries) != dx_node_limit(dir)) { |
|---|
| .. | .. |
|---|
| 1027 | 1067 | dir->i_sb->s_blocksize - |
|---|
| 1028 | 1068 | ext4_dir_rec_len(0, |
|---|
| 1029 | 1069 | csum ? NULL : dir)); |
|---|
| 1030 | | -#ifdef CONFIG_FS_ENCRYPTION |
|---|
| 1031 | 1070 | /* Check if the directory is encrypted */ |
|---|
| 1032 | 1071 | if (IS_ENCRYPTED(dir)) { |
|---|
| 1033 | | - err = fscrypt_get_encryption_info(dir); |
|---|
| 1072 | + err = fscrypt_prepare_readdir(dir); |
|---|
| 1034 | 1073 | if (err < 0) { |
|---|
| 1035 | 1074 | brelse(bh); |
|---|
| 1036 | 1075 | return err; |
|---|
| 1037 | 1076 | } |
|---|
| 1038 | | - err = fscrypt_fname_alloc_buffer(dir, EXT4_NAME_LEN, |
|---|
| 1039 | | - &fname_crypto_str); |
|---|
| 1077 | + err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN, |
|---|
| 1078 | + &fname_crypto_str); |
|---|
| 1040 | 1079 | if (err < 0) { |
|---|
| 1041 | 1080 | brelse(bh); |
|---|
| 1042 | 1081 | return err; |
|---|
| 1043 | 1082 | } |
|---|
| 1044 | 1083 | } |
|---|
| 1045 | | -#endif |
|---|
| 1084 | + |
|---|
| 1046 | 1085 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { |
|---|
| 1047 | 1086 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
|---|
| 1048 | 1087 | bh->b_data, bh->b_size, block, |
|---|
| .. | .. |
|---|
| 1100 | 1139 | } |
|---|
| 1101 | 1140 | errout: |
|---|
| 1102 | 1141 | brelse(bh); |
|---|
| 1103 | | -#ifdef CONFIG_FS_ENCRYPTION |
|---|
| 1104 | 1142 | fscrypt_fname_free_buffer(&fname_crypto_str); |
|---|
| 1105 | | -#endif |
|---|
| 1106 | 1143 | return count; |
|---|
| 1107 | 1144 | } |
|---|
| 1108 | 1145 | |
|---|
| .. | .. |
|---|
| 1143 | 1180 | hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; |
|---|
| 1144 | 1181 | if (ext4_has_inline_data(dir)) { |
|---|
| 1145 | 1182 | int has_inline_data = 1; |
|---|
| 1146 | | - count = htree_inlinedir_to_tree(dir_file, dir, 0, |
|---|
| 1147 | | - &hinfo, start_hash, |
|---|
| 1148 | | - start_minor_hash, |
|---|
| 1149 | | - &has_inline_data); |
|---|
| 1183 | + count = ext4_inlinedir_to_tree(dir_file, dir, 0, |
|---|
| 1184 | + &hinfo, start_hash, |
|---|
| 1185 | + start_minor_hash, |
|---|
| 1186 | + &has_inline_data); |
|---|
| 1150 | 1187 | if (has_inline_data) { |
|---|
| 1151 | 1188 | *next_hash = ~0; |
|---|
| 1152 | 1189 | return count; |
|---|
| .. | .. |
|---|
| 1354 | 1391 | /* Handle invalid character sequence as either an error |
|---|
| 1355 | 1392 | * or as an opaque byte sequence. |
|---|
| 1356 | 1393 | */ |
|---|
| 1357 | | - if (sb_has_enc_strict_mode(sb)) |
|---|
| 1394 | + if (sb_has_strict_encoding(sb)) |
|---|
| 1358 | 1395 | ret = -EINVAL; |
|---|
| 1359 | 1396 | else if (name->len != entry.len) |
|---|
| 1360 | 1397 | ret = 1; |
|---|
| .. | .. |
|---|
| 1373 | 1410 | struct dx_hash_info *hinfo = &name->hinfo; |
|---|
| 1374 | 1411 | int len; |
|---|
| 1375 | 1412 | |
|---|
| 1376 | | - if (!needs_casefold(dir)) { |
|---|
| 1413 | + if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding || |
|---|
| 1414 | + (IS_ENCRYPTED(dir) && !fscrypt_has_encryption_key(dir))) { |
|---|
| 1377 | 1415 | cf_name->name = NULL; |
|---|
| 1378 | 1416 | return 0; |
|---|
| 1379 | 1417 | } |
|---|
| .. | .. |
|---|
| 1424 | 1462 | #endif |
|---|
| 1425 | 1463 | |
|---|
| 1426 | 1464 | #ifdef CONFIG_UNICODE |
|---|
| 1427 | | - if (needs_casefold(parent)) { |
|---|
| 1465 | + if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent) && |
|---|
| 1466 | + (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) { |
|---|
| 1428 | 1467 | if (fname->cf_name.name) { |
|---|
| 1429 | 1468 | struct qstr cf = {.name = fname->cf_name.name, |
|---|
| 1430 | 1469 | .len = fname->cf_name.len}; |
|---|
| .. | .. |
|---|
| 1461 | 1500 | |
|---|
| 1462 | 1501 | de = (struct ext4_dir_entry_2 *)search_buf; |
|---|
| 1463 | 1502 | dlimit = search_buf + buf_size; |
|---|
| 1464 | | - while ((char *) de < dlimit) { |
|---|
| 1503 | + while ((char *) de < dlimit - EXT4_BASE_DIR_LEN) { |
|---|
| 1465 | 1504 | /* this code is executed quadratically often */ |
|---|
| 1466 | 1505 | /* do minimal checking `by hand' */ |
|---|
| 1467 | | - if ((char *) de + de->name_len <= dlimit && |
|---|
| 1506 | + if (de->name + de->name_len <= dlimit && |
|---|
| 1468 | 1507 | ext4_match(dir, fname, de)) { |
|---|
| 1469 | 1508 | /* found a match - just to be sure, do |
|---|
| 1470 | 1509 | * a full check */ |
|---|
| .. | .. |
|---|
| 1606 | 1645 | goto next; |
|---|
| 1607 | 1646 | wait_on_buffer(bh); |
|---|
| 1608 | 1647 | if (!buffer_uptodate(bh)) { |
|---|
| 1609 | | - EXT4_ERROR_INODE(dir, "reading directory lblock %lu", |
|---|
| 1610 | | - (unsigned long) block); |
|---|
| 1648 | + EXT4_ERROR_INODE_ERR(dir, EIO, |
|---|
| 1649 | + "reading directory lblock %lu", |
|---|
| 1650 | + (unsigned long) block); |
|---|
| 1611 | 1651 | brelse(bh); |
|---|
| 1612 | 1652 | ret = ERR_PTR(-EIO); |
|---|
| 1613 | 1653 | goto cleanup_and_exit; |
|---|
| .. | .. |
|---|
| 1615 | 1655 | if (!buffer_verified(bh) && |
|---|
| 1616 | 1656 | !is_dx_internal_node(dir, block, |
|---|
| 1617 | 1657 | (struct ext4_dir_entry *)bh->b_data) && |
|---|
| 1618 | | - !ext4_dirent_csum_verify(dir, |
|---|
| 1619 | | - (struct ext4_dir_entry *)bh->b_data)) { |
|---|
| 1620 | | - EXT4_ERROR_INODE(dir, "checksumming directory " |
|---|
| 1621 | | - "block %lu", (unsigned long)block); |
|---|
| 1658 | + !ext4_dirblock_csum_verify(dir, bh)) { |
|---|
| 1659 | + EXT4_ERROR_INODE_ERR(dir, EFSBADCRC, |
|---|
| 1660 | + "checksumming directory " |
|---|
| 1661 | + "block %lu", (unsigned long)block); |
|---|
| 1622 | 1662 | brelse(bh); |
|---|
| 1623 | 1663 | ret = ERR_PTR(-EFSBADCRC); |
|---|
| 1624 | 1664 | goto cleanup_and_exit; |
|---|
| .. | .. |
|---|
| 1690 | 1730 | struct buffer_head *bh; |
|---|
| 1691 | 1731 | |
|---|
| 1692 | 1732 | err = ext4_fname_prepare_lookup(dir, dentry, &fname); |
|---|
| 1693 | | - generic_set_encrypted_ci_d_ops(dir, dentry); |
|---|
| 1733 | + generic_set_encrypted_ci_d_ops(dentry); |
|---|
| 1694 | 1734 | if (err == -ENOENT) |
|---|
| 1695 | 1735 | return NULL; |
|---|
| 1696 | 1736 | if (err) |
|---|
| .. | .. |
|---|
| 1768 | 1808 | |
|---|
| 1769 | 1809 | bh = ext4_lookup_entry(dir, dentry, &de); |
|---|
| 1770 | 1810 | if (IS_ERR(bh)) |
|---|
| 1771 | | - return (struct dentry *) bh; |
|---|
| 1811 | + return ERR_CAST(bh); |
|---|
| 1772 | 1812 | inode = NULL; |
|---|
| 1773 | 1813 | if (bh) { |
|---|
| 1774 | 1814 | __u32 ino = le32_to_cpu(de->inode); |
|---|
| .. | .. |
|---|
| 1823 | 1863 | |
|---|
| 1824 | 1864 | bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL, NULL); |
|---|
| 1825 | 1865 | if (IS_ERR(bh)) |
|---|
| 1826 | | - return (struct dentry *) bh; |
|---|
| 1866 | + return ERR_CAST(bh); |
|---|
| 1827 | 1867 | if (!bh) |
|---|
| 1828 | 1868 | return ERR_PTR(-ENOENT); |
|---|
| 1829 | 1869 | ino = le32_to_cpu(de->inode); |
|---|
| .. | .. |
|---|
| 1900 | 1940 | struct dx_hash_info *hinfo, ext4_lblk_t *newblock) |
|---|
| 1901 | 1941 | { |
|---|
| 1902 | 1942 | unsigned blocksize = dir->i_sb->s_blocksize; |
|---|
| 1903 | | - unsigned count, continued; |
|---|
| 1943 | + unsigned continued; |
|---|
| 1944 | + int count; |
|---|
| 1904 | 1945 | struct buffer_head *bh2; |
|---|
| 1905 | 1946 | u32 hash2; |
|---|
| 1906 | 1947 | struct dx_map_entry *map; |
|---|
| 1907 | 1948 | char *data1 = (*bh)->b_data, *data2; |
|---|
| 1908 | 1949 | unsigned split, move, size; |
|---|
| 1909 | 1950 | struct ext4_dir_entry_2 *de = NULL, *de2; |
|---|
| 1910 | | - struct ext4_dir_entry_tail *t; |
|---|
| 1911 | 1951 | int csum_size = 0; |
|---|
| 1912 | 1952 | int err = 0, i; |
|---|
| 1913 | 1953 | |
|---|
| .. | .. |
|---|
| 1978 | 2018 | (char *) de2, |
|---|
| 1979 | 2019 | blocksize); |
|---|
| 1980 | 2020 | if (csum_size) { |
|---|
| 1981 | | - t = EXT4_DIRENT_TAIL(data2, blocksize); |
|---|
| 1982 | | - initialize_dirent_tail(t, blocksize); |
|---|
| 1983 | | - |
|---|
| 1984 | | - t = EXT4_DIRENT_TAIL(data1, blocksize); |
|---|
| 1985 | | - initialize_dirent_tail(t, blocksize); |
|---|
| 2021 | + ext4_initialize_dirent_tail(*bh, blocksize); |
|---|
| 2022 | + ext4_initialize_dirent_tail(bh2, blocksize); |
|---|
| 1986 | 2023 | } |
|---|
| 1987 | 2024 | |
|---|
| 1988 | 2025 | dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data1, |
|---|
| .. | .. |
|---|
| 1996 | 2033 | de = de2; |
|---|
| 1997 | 2034 | } |
|---|
| 1998 | 2035 | dx_insert_block(frame, hash2 + continued, *newblock); |
|---|
| 1999 | | - err = ext4_handle_dirty_dirent_node(handle, dir, bh2); |
|---|
| 2036 | + err = ext4_handle_dirty_dirblock(handle, dir, bh2); |
|---|
| 2000 | 2037 | if (err) |
|---|
| 2001 | 2038 | goto journal_error; |
|---|
| 2002 | 2039 | err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
|---|
| .. | .. |
|---|
| 2097 | 2134 | { |
|---|
| 2098 | 2135 | unsigned int blocksize = dir->i_sb->s_blocksize; |
|---|
| 2099 | 2136 | int csum_size = 0; |
|---|
| 2100 | | - int err; |
|---|
| 2137 | + int err, err2; |
|---|
| 2101 | 2138 | |
|---|
| 2102 | 2139 | if (ext4_has_metadata_csum(inode->i_sb)) |
|---|
| 2103 | 2140 | csum_size = sizeof(struct ext4_dir_entry_tail); |
|---|
| .. | .. |
|---|
| 2132 | 2169 | dir->i_mtime = dir->i_ctime = current_time(dir); |
|---|
| 2133 | 2170 | ext4_update_dx_flag(dir); |
|---|
| 2134 | 2171 | inode_inc_iversion(dir); |
|---|
| 2135 | | - ext4_mark_inode_dirty(handle, dir); |
|---|
| 2172 | + err2 = ext4_mark_inode_dirty(handle, dir); |
|---|
| 2136 | 2173 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
|---|
| 2137 | | - err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
|---|
| 2174 | + err = ext4_handle_dirty_dirblock(handle, dir, bh); |
|---|
| 2138 | 2175 | if (err) |
|---|
| 2139 | 2176 | ext4_std_error(dir->i_sb, err); |
|---|
| 2140 | | - return 0; |
|---|
| 2177 | + return err ? err : err2; |
|---|
| 2141 | 2178 | } |
|---|
| 2142 | 2179 | |
|---|
| 2143 | 2180 | /* |
|---|
| .. | .. |
|---|
| 2153 | 2190 | struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; |
|---|
| 2154 | 2191 | struct dx_entry *entries; |
|---|
| 2155 | 2192 | struct ext4_dir_entry_2 *de, *de2; |
|---|
| 2156 | | - struct ext4_dir_entry_tail *t; |
|---|
| 2157 | | - char *data1, *top; |
|---|
| 2193 | + char *data2, *top; |
|---|
| 2158 | 2194 | unsigned len; |
|---|
| 2159 | 2195 | int retval; |
|---|
| 2160 | 2196 | unsigned blocksize; |
|---|
| .. | .. |
|---|
| 2194 | 2230 | return PTR_ERR(bh2); |
|---|
| 2195 | 2231 | } |
|---|
| 2196 | 2232 | ext4_set_inode_flag(dir, EXT4_INODE_INDEX); |
|---|
| 2197 | | - data1 = bh2->b_data; |
|---|
| 2233 | + data2 = bh2->b_data; |
|---|
| 2198 | 2234 | |
|---|
| 2199 | | - memcpy (data1, de, len); |
|---|
| 2200 | | - de = (struct ext4_dir_entry_2 *) data1; |
|---|
| 2201 | | - top = data1 + len; |
|---|
| 2202 | | - while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) |
|---|
| 2235 | + memcpy(data2, de, len); |
|---|
| 2236 | + de = (struct ext4_dir_entry_2 *) data2; |
|---|
| 2237 | + top = data2 + len; |
|---|
| 2238 | + while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) { |
|---|
| 2239 | + if (ext4_check_dir_entry(dir, NULL, de, bh2, data2, len, block, |
|---|
| 2240 | + (data2 + (blocksize - csum_size) - |
|---|
| 2241 | + (char *) de))) { |
|---|
| 2242 | + brelse(bh2); |
|---|
| 2243 | + brelse(bh); |
|---|
| 2244 | + return -EFSCORRUPTED; |
|---|
| 2245 | + } |
|---|
| 2203 | 2246 | de = de2; |
|---|
| 2204 | | - de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - |
|---|
| 2205 | | - (char *) de, |
|---|
| 2206 | | - blocksize); |
|---|
| 2207 | | - |
|---|
| 2208 | | - if (csum_size) { |
|---|
| 2209 | | - t = EXT4_DIRENT_TAIL(data1, blocksize); |
|---|
| 2210 | | - initialize_dirent_tail(t, blocksize); |
|---|
| 2211 | 2247 | } |
|---|
| 2248 | + de->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) - |
|---|
| 2249 | + (char *) de, blocksize); |
|---|
| 2250 | + |
|---|
| 2251 | + if (csum_size) |
|---|
| 2252 | + ext4_initialize_dirent_tail(bh2, blocksize); |
|---|
| 2212 | 2253 | |
|---|
| 2213 | 2254 | /* Initialize the root; the dot dirents already exist */ |
|---|
| 2214 | 2255 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); |
|---|
| .. | .. |
|---|
| 2247 | 2288 | retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
|---|
| 2248 | 2289 | if (retval) |
|---|
| 2249 | 2290 | goto out_frames; |
|---|
| 2250 | | - retval = ext4_handle_dirty_dirent_node(handle, dir, bh2); |
|---|
| 2291 | + retval = ext4_handle_dirty_dirblock(handle, dir, bh2); |
|---|
| 2251 | 2292 | if (retval) |
|---|
| 2252 | 2293 | goto out_frames; |
|---|
| 2253 | 2294 | |
|---|
| .. | .. |
|---|
| 2287 | 2328 | struct inode *dir = d_inode(dentry->d_parent); |
|---|
| 2288 | 2329 | struct buffer_head *bh = NULL; |
|---|
| 2289 | 2330 | struct ext4_dir_entry_2 *de; |
|---|
| 2290 | | - struct ext4_dir_entry_tail *t; |
|---|
| 2291 | 2331 | struct super_block *sb; |
|---|
| 2292 | 2332 | struct ext4_filename fname; |
|---|
| 2293 | 2333 | int retval; |
|---|
| .. | .. |
|---|
| 2304 | 2344 | if (!dentry->d_name.len) |
|---|
| 2305 | 2345 | return -EINVAL; |
|---|
| 2306 | 2346 | |
|---|
| 2347 | + if (fscrypt_is_nokey_name(dentry)) |
|---|
| 2348 | + return -ENOKEY; |
|---|
| 2349 | + |
|---|
| 2307 | 2350 | #ifdef CONFIG_UNICODE |
|---|
| 2308 | | - if (sb_has_enc_strict_mode(sb) && IS_CASEFOLDED(dir) && |
|---|
| 2351 | + if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) && |
|---|
| 2309 | 2352 | sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name)) |
|---|
| 2310 | 2353 | return -EINVAL; |
|---|
| 2311 | 2354 | #endif |
|---|
| 2312 | | - |
|---|
| 2313 | | - if (fscrypt_is_nokey_name(dentry)) |
|---|
| 2314 | | - return -ENOKEY; |
|---|
| 2315 | 2355 | |
|---|
| 2316 | 2356 | retval = ext4_fname_setup_filename(dir, &dentry->d_name, 0, &fname); |
|---|
| 2317 | 2357 | if (retval) |
|---|
| .. | .. |
|---|
| 2340 | 2380 | } |
|---|
| 2341 | 2381 | ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); |
|---|
| 2342 | 2382 | dx_fallback++; |
|---|
| 2343 | | - ext4_mark_inode_dirty(handle, dir); |
|---|
| 2383 | + retval = ext4_mark_inode_dirty(handle, dir); |
|---|
| 2384 | + if (unlikely(retval)) |
|---|
| 2385 | + goto out; |
|---|
| 2344 | 2386 | } |
|---|
| 2345 | 2387 | blocks = dir->i_size >> sb->s_blocksize_bits; |
|---|
| 2346 | 2388 | for (block = 0; block < blocks; block++) { |
|---|
| .. | .. |
|---|
| 2380 | 2422 | de->inode = 0; |
|---|
| 2381 | 2423 | de->rec_len = ext4_rec_len_to_disk(blocksize - csum_size, blocksize); |
|---|
| 2382 | 2424 | |
|---|
| 2383 | | - if (csum_size) { |
|---|
| 2384 | | - t = EXT4_DIRENT_TAIL(bh->b_data, blocksize); |
|---|
| 2385 | | - initialize_dirent_tail(t, blocksize); |
|---|
| 2386 | | - } |
|---|
| 2425 | + if (csum_size) |
|---|
| 2426 | + ext4_initialize_dirent_tail(bh, blocksize); |
|---|
| 2387 | 2427 | |
|---|
| 2388 | 2428 | retval = add_dirent_to_buf(handle, &fname, dir, inode, de, block, bh); |
|---|
| 2389 | 2429 | out: |
|---|
| .. | .. |
|---|
| 2573 | 2613 | * ext4_generic_delete_entry deletes a directory entry by merging it |
|---|
| 2574 | 2614 | * with the previous entry |
|---|
| 2575 | 2615 | */ |
|---|
| 2576 | | -int ext4_generic_delete_entry(handle_t *handle, |
|---|
| 2577 | | - struct inode *dir, |
|---|
| 2616 | +int ext4_generic_delete_entry(struct inode *dir, |
|---|
| 2578 | 2617 | struct ext4_dir_entry_2 *de_del, |
|---|
| 2579 | 2618 | ext4_lblk_t lblk, |
|---|
| 2580 | 2619 | struct buffer_head *bh, |
|---|
| .. | .. |
|---|
| 2637 | 2676 | if (unlikely(err)) |
|---|
| 2638 | 2677 | goto out; |
|---|
| 2639 | 2678 | |
|---|
| 2640 | | - err = ext4_generic_delete_entry(handle, dir, de_del, lblk, |
|---|
| 2641 | | - bh, bh->b_data, |
|---|
| 2679 | + err = ext4_generic_delete_entry(dir, de_del, lblk, bh, bh->b_data, |
|---|
| 2642 | 2680 | dir->i_sb->s_blocksize, csum_size); |
|---|
| 2643 | 2681 | if (err) |
|---|
| 2644 | 2682 | goto out; |
|---|
| 2645 | 2683 | |
|---|
| 2646 | 2684 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
|---|
| 2647 | | - err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
|---|
| 2685 | + err = ext4_handle_dirty_dirblock(handle, dir, bh); |
|---|
| 2648 | 2686 | if (unlikely(err)) |
|---|
| 2649 | 2687 | goto out; |
|---|
| 2650 | 2688 | |
|---|
| .. | .. |
|---|
| 2666 | 2704 | * for checking S_ISDIR(inode) (since the INODE_INDEX feature will not be set |
|---|
| 2667 | 2705 | * on regular files) and to avoid creating huge/slow non-HTREE directories. |
|---|
| 2668 | 2706 | */ |
|---|
| 2669 | | -static void ext4_inc_count(handle_t *handle, struct inode *inode) |
|---|
| 2707 | +static void ext4_inc_count(struct inode *inode) |
|---|
| 2670 | 2708 | { |
|---|
| 2671 | 2709 | inc_nlink(inode); |
|---|
| 2672 | 2710 | if (is_dx(inode) && |
|---|
| .. | .. |
|---|
| 2678 | 2716 | * If a directory had nlink == 1, then we should let it be 1. This indicates |
|---|
| 2679 | 2717 | * directory has >EXT4_LINK_MAX subdirs. |
|---|
| 2680 | 2718 | */ |
|---|
| 2681 | | -static void ext4_dec_count(handle_t *handle, struct inode *inode) |
|---|
| 2719 | +static void ext4_dec_count(struct inode *inode) |
|---|
| 2682 | 2720 | { |
|---|
| 2683 | 2721 | if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) |
|---|
| 2684 | 2722 | drop_nlink(inode); |
|---|
| 2685 | 2723 | } |
|---|
| 2686 | 2724 | |
|---|
| 2687 | 2725 | |
|---|
| 2726 | +/* |
|---|
| 2727 | + * Add non-directory inode to a directory. On success, the inode reference is |
|---|
| 2728 | + * consumed by dentry is instantiation. This is also indicated by clearing of |
|---|
| 2729 | + * *inodep pointer. On failure, the caller is responsible for dropping the |
|---|
| 2730 | + * inode reference in the safe context. |
|---|
| 2731 | + */ |
|---|
| 2688 | 2732 | static int ext4_add_nondir(handle_t *handle, |
|---|
| 2689 | | - struct dentry *dentry, struct inode *inode) |
|---|
| 2733 | + struct dentry *dentry, struct inode **inodep) |
|---|
| 2690 | 2734 | { |
|---|
| 2735 | + struct inode *dir = d_inode(dentry->d_parent); |
|---|
| 2736 | + struct inode *inode = *inodep; |
|---|
| 2691 | 2737 | int err = ext4_add_entry(handle, dentry, inode); |
|---|
| 2692 | 2738 | if (!err) { |
|---|
| 2693 | | - ext4_mark_inode_dirty(handle, inode); |
|---|
| 2739 | + err = ext4_mark_inode_dirty(handle, inode); |
|---|
| 2740 | + if (IS_DIRSYNC(dir)) |
|---|
| 2741 | + ext4_handle_sync(handle); |
|---|
| 2694 | 2742 | d_instantiate_new(dentry, inode); |
|---|
| 2695 | | - return 0; |
|---|
| 2743 | + *inodep = NULL; |
|---|
| 2744 | + return err; |
|---|
| 2696 | 2745 | } |
|---|
| 2697 | 2746 | drop_nlink(inode); |
|---|
| 2747 | + ext4_orphan_add(handle, inode); |
|---|
| 2698 | 2748 | unlock_new_inode(inode); |
|---|
| 2699 | | - iput(inode); |
|---|
| 2700 | 2749 | return err; |
|---|
| 2701 | 2750 | } |
|---|
| 2702 | 2751 | |
|---|
| .. | .. |
|---|
| 2730 | 2779 | inode->i_op = &ext4_file_inode_operations; |
|---|
| 2731 | 2780 | inode->i_fop = &ext4_file_operations; |
|---|
| 2732 | 2781 | ext4_set_aops(inode); |
|---|
| 2733 | | - err = ext4_add_nondir(handle, dentry, inode); |
|---|
| 2734 | | - if (!err && IS_DIRSYNC(dir)) |
|---|
| 2735 | | - ext4_handle_sync(handle); |
|---|
| 2782 | + err = ext4_add_nondir(handle, dentry, &inode); |
|---|
| 2783 | + if (!err) |
|---|
| 2784 | + ext4_fc_track_create(handle, dentry); |
|---|
| 2736 | 2785 | } |
|---|
| 2737 | 2786 | if (handle) |
|---|
| 2738 | 2787 | ext4_journal_stop(handle); |
|---|
| 2788 | + if (!IS_ERR_OR_NULL(inode)) |
|---|
| 2789 | + iput(inode); |
|---|
| 2739 | 2790 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
|---|
| 2740 | 2791 | goto retry; |
|---|
| 2741 | 2792 | return err; |
|---|
| .. | .. |
|---|
| 2762 | 2813 | if (!IS_ERR(inode)) { |
|---|
| 2763 | 2814 | init_special_inode(inode, inode->i_mode, rdev); |
|---|
| 2764 | 2815 | inode->i_op = &ext4_special_inode_operations; |
|---|
| 2765 | | - err = ext4_add_nondir(handle, dentry, inode); |
|---|
| 2766 | | - if (!err && IS_DIRSYNC(dir)) |
|---|
| 2767 | | - ext4_handle_sync(handle); |
|---|
| 2816 | + err = ext4_add_nondir(handle, dentry, &inode); |
|---|
| 2817 | + if (!err) |
|---|
| 2818 | + ext4_fc_track_create(handle, dentry); |
|---|
| 2768 | 2819 | } |
|---|
| 2769 | 2820 | if (handle) |
|---|
| 2770 | 2821 | ext4_journal_stop(handle); |
|---|
| 2822 | + if (!IS_ERR_OR_NULL(inode)) |
|---|
| 2823 | + iput(inode); |
|---|
| 2771 | 2824 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
|---|
| 2772 | 2825 | goto retry; |
|---|
| 2773 | 2826 | return err; |
|---|
| .. | .. |
|---|
| 2842 | 2895 | return ext4_next_entry(de, blocksize); |
|---|
| 2843 | 2896 | } |
|---|
| 2844 | 2897 | |
|---|
| 2845 | | -static int ext4_init_new_dir(handle_t *handle, struct inode *dir, |
|---|
| 2898 | +int ext4_init_new_dir(handle_t *handle, struct inode *dir, |
|---|
| 2846 | 2899 | struct inode *inode) |
|---|
| 2847 | 2900 | { |
|---|
| 2848 | 2901 | struct buffer_head *dir_block = NULL; |
|---|
| 2849 | 2902 | struct ext4_dir_entry_2 *de; |
|---|
| 2850 | | - struct ext4_dir_entry_tail *t; |
|---|
| 2851 | 2903 | ext4_lblk_t block = 0; |
|---|
| 2852 | 2904 | unsigned int blocksize = dir->i_sb->s_blocksize; |
|---|
| 2853 | 2905 | int csum_size = 0; |
|---|
| .. | .. |
|---|
| 2871 | 2923 | de = (struct ext4_dir_entry_2 *)dir_block->b_data; |
|---|
| 2872 | 2924 | ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); |
|---|
| 2873 | 2925 | set_nlink(inode, 2); |
|---|
| 2874 | | - if (csum_size) { |
|---|
| 2875 | | - t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize); |
|---|
| 2876 | | - initialize_dirent_tail(t, blocksize); |
|---|
| 2877 | | - } |
|---|
| 2926 | + if (csum_size) |
|---|
| 2927 | + ext4_initialize_dirent_tail(dir_block, blocksize); |
|---|
| 2878 | 2928 | |
|---|
| 2879 | 2929 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); |
|---|
| 2880 | | - err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); |
|---|
| 2930 | + err = ext4_handle_dirty_dirblock(handle, inode, dir_block); |
|---|
| 2881 | 2931 | if (err) |
|---|
| 2882 | 2932 | goto out; |
|---|
| 2883 | 2933 | set_buffer_verified(dir_block); |
|---|
| .. | .. |
|---|
| 2890 | 2940 | { |
|---|
| 2891 | 2941 | handle_t *handle; |
|---|
| 2892 | 2942 | struct inode *inode; |
|---|
| 2893 | | - int err, credits, retries = 0; |
|---|
| 2943 | + int err, err2 = 0, credits, retries = 0; |
|---|
| 2894 | 2944 | |
|---|
| 2895 | 2945 | if (EXT4_DIR_LINK_MAX(dir)) |
|---|
| 2896 | 2946 | return -EMLINK; |
|---|
| .. | .. |
|---|
| 2921 | 2971 | if (err) { |
|---|
| 2922 | 2972 | out_clear_inode: |
|---|
| 2923 | 2973 | clear_nlink(inode); |
|---|
| 2974 | + ext4_orphan_add(handle, inode); |
|---|
| 2924 | 2975 | unlock_new_inode(inode); |
|---|
| 2925 | | - ext4_mark_inode_dirty(handle, inode); |
|---|
| 2976 | + err2 = ext4_mark_inode_dirty(handle, inode); |
|---|
| 2977 | + if (unlikely(err2)) |
|---|
| 2978 | + err = err2; |
|---|
| 2979 | + ext4_journal_stop(handle); |
|---|
| 2926 | 2980 | iput(inode); |
|---|
| 2927 | | - goto out_stop; |
|---|
| 2981 | + goto out_retry; |
|---|
| 2928 | 2982 | } |
|---|
| 2929 | | - ext4_inc_count(handle, dir); |
|---|
| 2983 | + ext4_inc_count(dir); |
|---|
| 2984 | + |
|---|
| 2930 | 2985 | ext4_update_dx_flag(dir); |
|---|
| 2931 | 2986 | err = ext4_mark_inode_dirty(handle, dir); |
|---|
| 2932 | 2987 | if (err) |
|---|
| 2933 | 2988 | goto out_clear_inode; |
|---|
| 2934 | 2989 | d_instantiate_new(dentry, inode); |
|---|
| 2990 | + ext4_fc_track_create(handle, dentry); |
|---|
| 2935 | 2991 | if (IS_DIRSYNC(dir)) |
|---|
| 2936 | 2992 | ext4_handle_sync(handle); |
|---|
| 2937 | 2993 | |
|---|
| 2938 | 2994 | out_stop: |
|---|
| 2939 | 2995 | if (handle) |
|---|
| 2940 | 2996 | ext4_journal_stop(handle); |
|---|
| 2997 | +out_retry: |
|---|
| 2941 | 2998 | if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
|---|
| 2942 | 2999 | goto retry; |
|---|
| 2943 | 3000 | return err; |
|---|
| .. | .. |
|---|
| 2966 | 3023 | if (inode->i_size < ext4_dir_rec_len(1, NULL) + |
|---|
| 2967 | 3024 | ext4_dir_rec_len(2, NULL)) { |
|---|
| 2968 | 3025 | EXT4_ERROR_INODE(inode, "invalid size"); |
|---|
| 2969 | | - return true; |
|---|
| 3026 | + return false; |
|---|
| 2970 | 3027 | } |
|---|
| 2971 | 3028 | /* The first directory block must not be a hole, |
|---|
| 2972 | 3029 | * so treat it as DIRENT_HTREE |
|---|
| 2973 | 3030 | */ |
|---|
| 2974 | 3031 | bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE); |
|---|
| 2975 | 3032 | if (IS_ERR(bh)) |
|---|
| 2976 | | - return true; |
|---|
| 3033 | + return false; |
|---|
| 2977 | 3034 | |
|---|
| 2978 | 3035 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
|---|
| 2979 | 3036 | if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size, 0, |
|---|
| .. | .. |
|---|
| 2981 | 3038 | le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) { |
|---|
| 2982 | 3039 | ext4_warning_inode(inode, "directory missing '.'"); |
|---|
| 2983 | 3040 | brelse(bh); |
|---|
| 2984 | | - return true; |
|---|
| 3041 | + return false; |
|---|
| 2985 | 3042 | } |
|---|
| 2986 | 3043 | offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); |
|---|
| 2987 | 3044 | de = ext4_next_entry(de, sb->s_blocksize); |
|---|
| .. | .. |
|---|
| 2990 | 3047 | le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) { |
|---|
| 2991 | 3048 | ext4_warning_inode(inode, "directory missing '..'"); |
|---|
| 2992 | 3049 | brelse(bh); |
|---|
| 2993 | | - return true; |
|---|
| 3050 | + return false; |
|---|
| 2994 | 3051 | } |
|---|
| 2995 | 3052 | offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); |
|---|
| 2996 | 3053 | while (offset < inode->i_size) { |
|---|
| .. | .. |
|---|
| 3004 | 3061 | continue; |
|---|
| 3005 | 3062 | } |
|---|
| 3006 | 3063 | if (IS_ERR(bh)) |
|---|
| 3007 | | - return true; |
|---|
| 3064 | + return false; |
|---|
| 3008 | 3065 | } |
|---|
| 3009 | 3066 | de = (struct ext4_dir_entry_2 *) (bh->b_data + |
|---|
| 3010 | 3067 | (offset & (sb->s_blocksize - 1))); |
|---|
| 3011 | 3068 | if (ext4_check_dir_entry(inode, NULL, de, bh, |
|---|
| 3012 | | - bh->b_data, bh->b_size, 0, offset)) { |
|---|
| 3013 | | - offset = (offset | (sb->s_blocksize - 1)) + 1; |
|---|
| 3014 | | - continue; |
|---|
| 3015 | | - } |
|---|
| 3016 | | - if (le32_to_cpu(de->inode)) { |
|---|
| 3069 | + bh->b_data, bh->b_size, 0, offset) || |
|---|
| 3070 | + le32_to_cpu(de->inode)) { |
|---|
| 3017 | 3071 | brelse(bh); |
|---|
| 3018 | 3072 | return false; |
|---|
| 3019 | 3073 | } |
|---|
| .. | .. |
|---|
| 3263 | 3317 | inode->i_size = 0; |
|---|
| 3264 | 3318 | ext4_orphan_add(handle, inode); |
|---|
| 3265 | 3319 | inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); |
|---|
| 3266 | | - ext4_mark_inode_dirty(handle, inode); |
|---|
| 3267 | | - ext4_dec_count(handle, dir); |
|---|
| 3320 | + retval = ext4_mark_inode_dirty(handle, inode); |
|---|
| 3321 | + if (retval) |
|---|
| 3322 | + goto end_rmdir; |
|---|
| 3323 | + ext4_dec_count(dir); |
|---|
| 3268 | 3324 | ext4_update_dx_flag(dir); |
|---|
| 3269 | | - ext4_mark_inode_dirty(handle, dir); |
|---|
| 3325 | + ext4_fc_track_unlink(handle, dentry); |
|---|
| 3326 | + retval = ext4_mark_inode_dirty(handle, dir); |
|---|
| 3270 | 3327 | |
|---|
| 3271 | 3328 | #ifdef CONFIG_UNICODE |
|---|
| 3272 | 3329 | /* VFS negative dentries are incompatible with Encoding and |
|---|
| .. | .. |
|---|
| 3286 | 3343 | return retval; |
|---|
| 3287 | 3344 | } |
|---|
| 3288 | 3345 | |
|---|
| 3289 | | -static int ext4_unlink(struct inode *dir, struct dentry *dentry) |
|---|
| 3346 | +int __ext4_unlink(handle_t *handle, struct inode *dir, const struct qstr *d_name, |
|---|
| 3347 | + struct inode *inode) |
|---|
| 3290 | 3348 | { |
|---|
| 3291 | | - int retval; |
|---|
| 3292 | | - struct inode *inode; |
|---|
| 3349 | + int retval = -ENOENT; |
|---|
| 3293 | 3350 | struct buffer_head *bh; |
|---|
| 3294 | 3351 | struct ext4_dir_entry_2 *de; |
|---|
| 3295 | | - handle_t *handle = NULL; |
|---|
| 3352 | + int skip_remove_dentry = 0; |
|---|
| 3296 | 3353 | ext4_lblk_t lblk; |
|---|
| 3297 | 3354 | |
|---|
| 3298 | | - if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) |
|---|
| 3299 | | - return -EIO; |
|---|
| 3300 | | - |
|---|
| 3301 | | - trace_ext4_unlink_enter(dir, dentry); |
|---|
| 3302 | | - /* Initialize quotas before so that eventual writes go |
|---|
| 3303 | | - * in separate transaction */ |
|---|
| 3304 | | - retval = dquot_initialize(dir); |
|---|
| 3305 | | - if (retval) |
|---|
| 3306 | | - return retval; |
|---|
| 3307 | | - retval = dquot_initialize(d_inode(dentry)); |
|---|
| 3308 | | - if (retval) |
|---|
| 3309 | | - return retval; |
|---|
| 3310 | | - |
|---|
| 3311 | | - retval = -ENOENT; |
|---|
| 3312 | | - bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL, &lblk); |
|---|
| 3355 | + bh = ext4_find_entry(dir, d_name, &de, NULL, &lblk); |
|---|
| 3313 | 3356 | if (IS_ERR(bh)) |
|---|
| 3314 | 3357 | return PTR_ERR(bh); |
|---|
| 3358 | + |
|---|
| 3315 | 3359 | if (!bh) |
|---|
| 3316 | | - goto end_unlink; |
|---|
| 3360 | + return -ENOENT; |
|---|
| 3317 | 3361 | |
|---|
| 3318 | | - inode = d_inode(dentry); |
|---|
| 3319 | | - |
|---|
| 3320 | | - retval = -EFSCORRUPTED; |
|---|
| 3321 | | - if (le32_to_cpu(de->inode) != inode->i_ino) |
|---|
| 3322 | | - goto end_unlink; |
|---|
| 3323 | | - |
|---|
| 3324 | | - handle = ext4_journal_start(dir, EXT4_HT_DIR, |
|---|
| 3325 | | - EXT4_DATA_TRANS_BLOCKS(dir->i_sb)); |
|---|
| 3326 | | - if (IS_ERR(handle)) { |
|---|
| 3327 | | - retval = PTR_ERR(handle); |
|---|
| 3328 | | - handle = NULL; |
|---|
| 3329 | | - goto end_unlink; |
|---|
| 3362 | + if (le32_to_cpu(de->inode) != inode->i_ino) { |
|---|
| 3363 | + /* |
|---|
| 3364 | + * It's okay if we find dont find dentry which matches |
|---|
| 3365 | + * the inode. That's because it might have gotten |
|---|
| 3366 | + * renamed to a different inode number |
|---|
| 3367 | + */ |
|---|
| 3368 | + if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) |
|---|
| 3369 | + skip_remove_dentry = 1; |
|---|
| 3370 | + else |
|---|
| 3371 | + goto out; |
|---|
| 3330 | 3372 | } |
|---|
| 3331 | 3373 | |
|---|
| 3332 | 3374 | if (IS_DIRSYNC(dir)) |
|---|
| 3333 | 3375 | ext4_handle_sync(handle); |
|---|
| 3334 | 3376 | |
|---|
| 3335 | | - retval = ext4_delete_entry(handle, dir, de, lblk, bh); |
|---|
| 3336 | | - if (retval) |
|---|
| 3337 | | - goto end_unlink; |
|---|
| 3338 | | - dir->i_ctime = dir->i_mtime = current_time(dir); |
|---|
| 3339 | | - ext4_update_dx_flag(dir); |
|---|
| 3340 | | - ext4_mark_inode_dirty(handle, dir); |
|---|
| 3377 | + if (!skip_remove_dentry) { |
|---|
| 3378 | + retval = ext4_delete_entry(handle, dir, de, lblk, bh); |
|---|
| 3379 | + if (retval) |
|---|
| 3380 | + goto out; |
|---|
| 3381 | + dir->i_ctime = dir->i_mtime = current_time(dir); |
|---|
| 3382 | + ext4_update_dx_flag(dir); |
|---|
| 3383 | + retval = ext4_mark_inode_dirty(handle, dir); |
|---|
| 3384 | + if (retval) |
|---|
| 3385 | + goto out; |
|---|
| 3386 | + } else { |
|---|
| 3387 | + retval = 0; |
|---|
| 3388 | + } |
|---|
| 3341 | 3389 | if (inode->i_nlink == 0) |
|---|
| 3342 | 3390 | ext4_warning_inode(inode, "Deleting file '%.*s' with no links", |
|---|
| 3343 | | - dentry->d_name.len, dentry->d_name.name); |
|---|
| 3391 | + d_name->len, d_name->name); |
|---|
| 3344 | 3392 | else |
|---|
| 3345 | 3393 | drop_nlink(inode); |
|---|
| 3346 | 3394 | if (!inode->i_nlink) |
|---|
| 3347 | 3395 | ext4_orphan_add(handle, inode); |
|---|
| 3348 | 3396 | inode->i_ctime = current_time(inode); |
|---|
| 3349 | | - ext4_mark_inode_dirty(handle, inode); |
|---|
| 3397 | + retval = ext4_mark_inode_dirty(handle, inode); |
|---|
| 3350 | 3398 | |
|---|
| 3399 | +out: |
|---|
| 3400 | + brelse(bh); |
|---|
| 3401 | + return retval; |
|---|
| 3402 | +} |
|---|
| 3403 | + |
|---|
| 3404 | +static int ext4_unlink(struct inode *dir, struct dentry *dentry) |
|---|
| 3405 | +{ |
|---|
| 3406 | + handle_t *handle; |
|---|
| 3407 | + int retval; |
|---|
| 3408 | + |
|---|
| 3409 | + if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) |
|---|
| 3410 | + return -EIO; |
|---|
| 3411 | + |
|---|
| 3412 | + trace_ext4_unlink_enter(dir, dentry); |
|---|
| 3413 | + /* |
|---|
| 3414 | + * Initialize quotas before so that eventual writes go |
|---|
| 3415 | + * in separate transaction |
|---|
| 3416 | + */ |
|---|
| 3417 | + retval = dquot_initialize(dir); |
|---|
| 3418 | + if (retval) |
|---|
| 3419 | + goto out_trace; |
|---|
| 3420 | + retval = dquot_initialize(d_inode(dentry)); |
|---|
| 3421 | + if (retval) |
|---|
| 3422 | + goto out_trace; |
|---|
| 3423 | + |
|---|
| 3424 | + handle = ext4_journal_start(dir, EXT4_HT_DIR, |
|---|
| 3425 | + EXT4_DATA_TRANS_BLOCKS(dir->i_sb)); |
|---|
| 3426 | + if (IS_ERR(handle)) { |
|---|
| 3427 | + retval = PTR_ERR(handle); |
|---|
| 3428 | + goto out_trace; |
|---|
| 3429 | + } |
|---|
| 3430 | + |
|---|
| 3431 | + retval = __ext4_unlink(handle, dir, &dentry->d_name, d_inode(dentry)); |
|---|
| 3432 | + if (!retval) |
|---|
| 3433 | + ext4_fc_track_unlink(handle, dentry); |
|---|
| 3351 | 3434 | #ifdef CONFIG_UNICODE |
|---|
| 3352 | 3435 | /* VFS negative dentries are incompatible with Encoding and |
|---|
| 3353 | 3436 | * Case-insensitiveness. Eventually we'll want avoid |
|---|
| .. | .. |
|---|
| 3358 | 3441 | if (IS_CASEFOLDED(dir)) |
|---|
| 3359 | 3442 | d_invalidate(dentry); |
|---|
| 3360 | 3443 | #endif |
|---|
| 3361 | | - |
|---|
| 3362 | | -end_unlink: |
|---|
| 3363 | | - brelse(bh); |
|---|
| 3364 | 3444 | if (handle) |
|---|
| 3365 | 3445 | ext4_journal_stop(handle); |
|---|
| 3446 | + |
|---|
| 3447 | +out_trace: |
|---|
| 3366 | 3448 | trace_ext4_unlink_exit(dentry, retval); |
|---|
| 3367 | 3449 | return retval; |
|---|
| 3368 | 3450 | } |
|---|
| .. | .. |
|---|
| 3442 | 3524 | */ |
|---|
| 3443 | 3525 | drop_nlink(inode); |
|---|
| 3444 | 3526 | err = ext4_orphan_add(handle, inode); |
|---|
| 3445 | | - ext4_journal_stop(handle); |
|---|
| 3527 | + if (handle) |
|---|
| 3528 | + ext4_journal_stop(handle); |
|---|
| 3446 | 3529 | handle = NULL; |
|---|
| 3447 | 3530 | if (err) |
|---|
| 3448 | 3531 | goto err_drop_inode; |
|---|
| .. | .. |
|---|
| 3477 | 3560 | inode->i_size = disk_link.len - 1; |
|---|
| 3478 | 3561 | } |
|---|
| 3479 | 3562 | EXT4_I(inode)->i_disksize = inode->i_size; |
|---|
| 3480 | | - err = ext4_add_nondir(handle, dentry, inode); |
|---|
| 3481 | | - if (!err && IS_DIRSYNC(dir)) |
|---|
| 3482 | | - ext4_handle_sync(handle); |
|---|
| 3483 | | - |
|---|
| 3563 | + err = ext4_add_nondir(handle, dentry, &inode); |
|---|
| 3484 | 3564 | if (handle) |
|---|
| 3485 | 3565 | ext4_journal_stop(handle); |
|---|
| 3566 | + if (inode) |
|---|
| 3567 | + iput(inode); |
|---|
| 3486 | 3568 | goto out_free_encrypted_link; |
|---|
| 3487 | 3569 | |
|---|
| 3488 | 3570 | err_drop_inode: |
|---|
| .. | .. |
|---|
| 3497 | 3579 | return err; |
|---|
| 3498 | 3580 | } |
|---|
| 3499 | 3581 | |
|---|
| 3582 | +int __ext4_link(struct inode *dir, struct inode *inode, struct dentry *dentry) |
|---|
| 3583 | +{ |
|---|
| 3584 | + handle_t *handle; |
|---|
| 3585 | + int err, retries = 0; |
|---|
| 3586 | +retry: |
|---|
| 3587 | + handle = ext4_journal_start(dir, EXT4_HT_DIR, |
|---|
| 3588 | + (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + |
|---|
| 3589 | + EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1); |
|---|
| 3590 | + if (IS_ERR(handle)) |
|---|
| 3591 | + return PTR_ERR(handle); |
|---|
| 3592 | + |
|---|
| 3593 | + if (IS_DIRSYNC(dir)) |
|---|
| 3594 | + ext4_handle_sync(handle); |
|---|
| 3595 | + |
|---|
| 3596 | + inode->i_ctime = current_time(inode); |
|---|
| 3597 | + ext4_inc_count(inode); |
|---|
| 3598 | + ihold(inode); |
|---|
| 3599 | + |
|---|
| 3600 | + err = ext4_add_entry(handle, dentry, inode); |
|---|
| 3601 | + if (!err) { |
|---|
| 3602 | + err = ext4_mark_inode_dirty(handle, inode); |
|---|
| 3603 | + /* this can happen only for tmpfile being |
|---|
| 3604 | + * linked the first time |
|---|
| 3605 | + */ |
|---|
| 3606 | + if (inode->i_nlink == 1) |
|---|
| 3607 | + ext4_orphan_del(handle, inode); |
|---|
| 3608 | + d_instantiate(dentry, inode); |
|---|
| 3609 | + ext4_fc_track_link(handle, dentry); |
|---|
| 3610 | + } else { |
|---|
| 3611 | + drop_nlink(inode); |
|---|
| 3612 | + iput(inode); |
|---|
| 3613 | + } |
|---|
| 3614 | + ext4_journal_stop(handle); |
|---|
| 3615 | + if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
|---|
| 3616 | + goto retry; |
|---|
| 3617 | + return err; |
|---|
| 3618 | +} |
|---|
| 3619 | + |
|---|
| 3500 | 3620 | static int ext4_link(struct dentry *old_dentry, |
|---|
| 3501 | 3621 | struct inode *dir, struct dentry *dentry) |
|---|
| 3502 | 3622 | { |
|---|
| 3503 | | - handle_t *handle; |
|---|
| 3504 | 3623 | struct inode *inode = d_inode(old_dentry); |
|---|
| 3505 | | - int err, retries = 0; |
|---|
| 3624 | + int err; |
|---|
| 3506 | 3625 | |
|---|
| 3507 | 3626 | if (inode->i_nlink >= EXT4_LINK_MAX) |
|---|
| 3508 | 3627 | return -EMLINK; |
|---|
| .. | .. |
|---|
| 3519 | 3638 | err = dquot_initialize(dir); |
|---|
| 3520 | 3639 | if (err) |
|---|
| 3521 | 3640 | return err; |
|---|
| 3522 | | - |
|---|
| 3523 | | -retry: |
|---|
| 3524 | | - handle = ext4_journal_start(dir, EXT4_HT_DIR, |
|---|
| 3525 | | - (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + |
|---|
| 3526 | | - EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1); |
|---|
| 3527 | | - if (IS_ERR(handle)) |
|---|
| 3528 | | - return PTR_ERR(handle); |
|---|
| 3529 | | - |
|---|
| 3530 | | - if (IS_DIRSYNC(dir)) |
|---|
| 3531 | | - ext4_handle_sync(handle); |
|---|
| 3532 | | - |
|---|
| 3533 | | - inode->i_ctime = current_time(inode); |
|---|
| 3534 | | - ext4_inc_count(handle, inode); |
|---|
| 3535 | | - ihold(inode); |
|---|
| 3536 | | - |
|---|
| 3537 | | - err = ext4_add_entry(handle, dentry, inode); |
|---|
| 3538 | | - if (!err) { |
|---|
| 3539 | | - ext4_mark_inode_dirty(handle, inode); |
|---|
| 3540 | | - /* this can happen only for tmpfile being |
|---|
| 3541 | | - * linked the first time |
|---|
| 3542 | | - */ |
|---|
| 3543 | | - if (inode->i_nlink == 1) |
|---|
| 3544 | | - ext4_orphan_del(handle, inode); |
|---|
| 3545 | | - d_instantiate(dentry, inode); |
|---|
| 3546 | | - } else { |
|---|
| 3547 | | - drop_nlink(inode); |
|---|
| 3548 | | - iput(inode); |
|---|
| 3549 | | - } |
|---|
| 3550 | | - ext4_journal_stop(handle); |
|---|
| 3551 | | - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) |
|---|
| 3552 | | - goto retry; |
|---|
| 3553 | | - return err; |
|---|
| 3641 | + return __ext4_link(dir, inode, dentry); |
|---|
| 3554 | 3642 | } |
|---|
| 3555 | | - |
|---|
| 3556 | 3643 | |
|---|
| 3557 | 3644 | /* |
|---|
| 3558 | 3645 | * Try to find buffer head where contains the parent block. |
|---|
| .. | .. |
|---|
| 3568 | 3655 | struct buffer_head *bh; |
|---|
| 3569 | 3656 | |
|---|
| 3570 | 3657 | if (!ext4_has_inline_data(inode)) { |
|---|
| 3658 | + struct ext4_dir_entry_2 *de; |
|---|
| 3659 | + unsigned int offset; |
|---|
| 3660 | + |
|---|
| 3571 | 3661 | /* The first directory block must not be a hole, so |
|---|
| 3572 | 3662 | * treat it as DIRENT_HTREE |
|---|
| 3573 | 3663 | */ |
|---|
| .. | .. |
|---|
| 3576 | 3666 | *retval = PTR_ERR(bh); |
|---|
| 3577 | 3667 | return NULL; |
|---|
| 3578 | 3668 | } |
|---|
| 3579 | | - *parent_de = ext4_next_entry( |
|---|
| 3580 | | - (struct ext4_dir_entry_2 *)bh->b_data, |
|---|
| 3581 | | - inode->i_sb->s_blocksize); |
|---|
| 3669 | + |
|---|
| 3670 | + de = (struct ext4_dir_entry_2 *) bh->b_data; |
|---|
| 3671 | + if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, |
|---|
| 3672 | + bh->b_size, 0, 0) || |
|---|
| 3673 | + le32_to_cpu(de->inode) != inode->i_ino || |
|---|
| 3674 | + strcmp(".", de->name)) { |
|---|
| 3675 | + EXT4_ERROR_INODE(inode, "directory missing '.'"); |
|---|
| 3676 | + brelse(bh); |
|---|
| 3677 | + *retval = -EFSCORRUPTED; |
|---|
| 3678 | + return NULL; |
|---|
| 3679 | + } |
|---|
| 3680 | + offset = ext4_rec_len_from_disk(de->rec_len, |
|---|
| 3681 | + inode->i_sb->s_blocksize); |
|---|
| 3682 | + de = ext4_next_entry(de, inode->i_sb->s_blocksize); |
|---|
| 3683 | + if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, |
|---|
| 3684 | + bh->b_size, 0, offset) || |
|---|
| 3685 | + le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) { |
|---|
| 3686 | + EXT4_ERROR_INODE(inode, "directory missing '..'"); |
|---|
| 3687 | + brelse(bh); |
|---|
| 3688 | + *retval = -EFSCORRUPTED; |
|---|
| 3689 | + return NULL; |
|---|
| 3690 | + } |
|---|
| 3691 | + *parent_de = de; |
|---|
| 3692 | + |
|---|
| 3582 | 3693 | return bh; |
|---|
| 3583 | 3694 | } |
|---|
| 3584 | 3695 | |
|---|
| .. | .. |
|---|
| 3633 | 3744 | ent->inode, |
|---|
| 3634 | 3745 | ent->dir_bh); |
|---|
| 3635 | 3746 | } else { |
|---|
| 3636 | | - retval = ext4_handle_dirty_dirent_node(handle, |
|---|
| 3637 | | - ent->inode, |
|---|
| 3638 | | - ent->dir_bh); |
|---|
| 3747 | + retval = ext4_handle_dirty_dirblock(handle, ent->inode, |
|---|
| 3748 | + ent->dir_bh); |
|---|
| 3639 | 3749 | } |
|---|
| 3640 | 3750 | } else { |
|---|
| 3641 | 3751 | retval = ext4_mark_inode_dirty(handle, ent->inode); |
|---|
| .. | .. |
|---|
| 3650 | 3760 | static int ext4_setent(handle_t *handle, struct ext4_renament *ent, |
|---|
| 3651 | 3761 | unsigned ino, unsigned file_type) |
|---|
| 3652 | 3762 | { |
|---|
| 3653 | | - int retval; |
|---|
| 3763 | + int retval, retval2; |
|---|
| 3654 | 3764 | |
|---|
| 3655 | 3765 | BUFFER_TRACE(ent->bh, "get write access"); |
|---|
| 3656 | 3766 | retval = ext4_journal_get_write_access(handle, ent->bh); |
|---|
| .. | .. |
|---|
| 3662 | 3772 | inode_inc_iversion(ent->dir); |
|---|
| 3663 | 3773 | ent->dir->i_ctime = ent->dir->i_mtime = |
|---|
| 3664 | 3774 | current_time(ent->dir); |
|---|
| 3665 | | - ext4_mark_inode_dirty(handle, ent->dir); |
|---|
| 3775 | + retval = ext4_mark_inode_dirty(handle, ent->dir); |
|---|
| 3666 | 3776 | BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata"); |
|---|
| 3667 | 3777 | if (!ent->inlined) { |
|---|
| 3668 | | - retval = ext4_handle_dirty_dirent_node(handle, |
|---|
| 3669 | | - ent->dir, ent->bh); |
|---|
| 3670 | | - if (unlikely(retval)) { |
|---|
| 3671 | | - ext4_std_error(ent->dir->i_sb, retval); |
|---|
| 3672 | | - return retval; |
|---|
| 3778 | + retval2 = ext4_handle_dirty_dirblock(handle, ent->dir, ent->bh); |
|---|
| 3779 | + if (unlikely(retval2)) { |
|---|
| 3780 | + ext4_std_error(ent->dir->i_sb, retval2); |
|---|
| 3781 | + return retval2; |
|---|
| 3673 | 3782 | } |
|---|
| 3674 | 3783 | } |
|---|
| 3675 | | - |
|---|
| 3676 | | - return 0; |
|---|
| 3784 | + return retval; |
|---|
| 3677 | 3785 | } |
|---|
| 3678 | 3786 | |
|---|
| 3679 | 3787 | static void ext4_resetent(handle_t *handle, struct ext4_renament *ent, |
|---|
| .. | .. |
|---|
| 3757 | 3865 | { |
|---|
| 3758 | 3866 | if (ent->dir_nlink_delta) { |
|---|
| 3759 | 3867 | if (ent->dir_nlink_delta == -1) |
|---|
| 3760 | | - ext4_dec_count(handle, ent->dir); |
|---|
| 3868 | + ext4_dec_count(ent->dir); |
|---|
| 3761 | 3869 | else |
|---|
| 3762 | | - ext4_inc_count(handle, ent->dir); |
|---|
| 3870 | + ext4_inc_count(ent->dir); |
|---|
| 3763 | 3871 | ext4_mark_inode_dirty(handle, ent->dir); |
|---|
| 3764 | 3872 | } |
|---|
| 3765 | 3873 | } |
|---|
| .. | .. |
|---|
| 3935 | 4043 | EXT4_FT_CHRDEV); |
|---|
| 3936 | 4044 | if (retval) |
|---|
| 3937 | 4045 | goto end_rename; |
|---|
| 3938 | | - ext4_mark_inode_dirty(handle, whiteout); |
|---|
| 4046 | + retval = ext4_mark_inode_dirty(handle, whiteout); |
|---|
| 4047 | + if (unlikely(retval)) |
|---|
| 4048 | + goto end_rename; |
|---|
| 4049 | + |
|---|
| 3939 | 4050 | } |
|---|
| 3940 | 4051 | if (!new.bh) { |
|---|
| 3941 | 4052 | retval = ext4_add_entry(handle, new.dentry, old.inode); |
|---|
| .. | .. |
|---|
| 3956 | 4067 | * rename. |
|---|
| 3957 | 4068 | */ |
|---|
| 3958 | 4069 | old.inode->i_ctime = current_time(old.inode); |
|---|
| 3959 | | - ext4_mark_inode_dirty(handle, old.inode); |
|---|
| 4070 | + retval = ext4_mark_inode_dirty(handle, old.inode); |
|---|
| 4071 | + if (unlikely(retval)) |
|---|
| 4072 | + goto end_rename; |
|---|
| 3960 | 4073 | |
|---|
| 3961 | 4074 | if (!whiteout) { |
|---|
| 3962 | 4075 | /* |
|---|
| .. | .. |
|---|
| 3966 | 4079 | } |
|---|
| 3967 | 4080 | |
|---|
| 3968 | 4081 | if (new.inode) { |
|---|
| 3969 | | - ext4_dec_count(handle, new.inode); |
|---|
| 4082 | + ext4_dec_count(new.inode); |
|---|
| 3970 | 4083 | new.inode->i_ctime = current_time(new.inode); |
|---|
| 3971 | 4084 | } |
|---|
| 3972 | 4085 | old.dir->i_ctime = old.dir->i_mtime = current_time(old.dir); |
|---|
| .. | .. |
|---|
| 3976 | 4089 | if (retval) |
|---|
| 3977 | 4090 | goto end_rename; |
|---|
| 3978 | 4091 | |
|---|
| 3979 | | - ext4_dec_count(handle, old.dir); |
|---|
| 4092 | + ext4_dec_count(old.dir); |
|---|
| 3980 | 4093 | if (new.inode) { |
|---|
| 3981 | 4094 | /* checked ext4_empty_dir above, can't have another |
|---|
| 3982 | 4095 | * parent, ext4_dec_count() won't work for many-linked |
|---|
| 3983 | 4096 | * dirs */ |
|---|
| 3984 | 4097 | clear_nlink(new.inode); |
|---|
| 3985 | 4098 | } else { |
|---|
| 3986 | | - ext4_inc_count(handle, new.dir); |
|---|
| 4099 | + ext4_inc_count(new.dir); |
|---|
| 3987 | 4100 | ext4_update_dx_flag(new.dir); |
|---|
| 3988 | | - ext4_mark_inode_dirty(handle, new.dir); |
|---|
| 4101 | + retval = ext4_mark_inode_dirty(handle, new.dir); |
|---|
| 4102 | + if (unlikely(retval)) |
|---|
| 4103 | + goto end_rename; |
|---|
| 3989 | 4104 | } |
|---|
| 3990 | 4105 | } |
|---|
| 3991 | | - ext4_mark_inode_dirty(handle, old.dir); |
|---|
| 4106 | + retval = ext4_mark_inode_dirty(handle, old.dir); |
|---|
| 4107 | + if (unlikely(retval)) |
|---|
| 4108 | + goto end_rename; |
|---|
| 4109 | + |
|---|
| 4110 | + if (S_ISDIR(old.inode->i_mode)) { |
|---|
| 4111 | + /* |
|---|
| 4112 | + * We disable fast commits here that's because the |
|---|
| 4113 | + * replay code is not yet capable of changing dot dot |
|---|
| 4114 | + * dirents in directories. |
|---|
| 4115 | + */ |
|---|
| 4116 | + ext4_fc_mark_ineligible(old.inode->i_sb, |
|---|
| 4117 | + EXT4_FC_REASON_RENAME_DIR); |
|---|
| 4118 | + } else { |
|---|
| 4119 | + if (new.inode) |
|---|
| 4120 | + ext4_fc_track_unlink(handle, new.dentry); |
|---|
| 4121 | + __ext4_fc_track_link(handle, old.inode, new.dentry); |
|---|
| 4122 | + __ext4_fc_track_unlink(handle, old.inode, old.dentry); |
|---|
| 4123 | + if (whiteout) |
|---|
| 4124 | + __ext4_fc_track_create(handle, whiteout, old.dentry); |
|---|
| 4125 | + } |
|---|
| 4126 | + |
|---|
| 3992 | 4127 | if (new.inode) { |
|---|
| 3993 | | - ext4_mark_inode_dirty(handle, new.inode); |
|---|
| 4128 | + retval = ext4_mark_inode_dirty(handle, new.inode); |
|---|
| 4129 | + if (unlikely(retval)) |
|---|
| 4130 | + goto end_rename; |
|---|
| 3994 | 4131 | if (!new.inode->i_nlink) |
|---|
| 3995 | 4132 | ext4_orphan_add(handle, new.inode); |
|---|
| 3996 | 4133 | } |
|---|
| .. | .. |
|---|
| 4130 | 4267 | ctime = current_time(old.inode); |
|---|
| 4131 | 4268 | old.inode->i_ctime = ctime; |
|---|
| 4132 | 4269 | new.inode->i_ctime = ctime; |
|---|
| 4133 | | - ext4_mark_inode_dirty(handle, old.inode); |
|---|
| 4134 | | - ext4_mark_inode_dirty(handle, new.inode); |
|---|
| 4135 | | - |
|---|
| 4270 | + retval = ext4_mark_inode_dirty(handle, old.inode); |
|---|
| 4271 | + if (unlikely(retval)) |
|---|
| 4272 | + goto end_rename; |
|---|
| 4273 | + retval = ext4_mark_inode_dirty(handle, new.inode); |
|---|
| 4274 | + if (unlikely(retval)) |
|---|
| 4275 | + goto end_rename; |
|---|
| 4276 | + ext4_fc_mark_ineligible(new.inode->i_sb, |
|---|
| 4277 | + EXT4_FC_REASON_CROSS_RENAME); |
|---|
| 4136 | 4278 | if (old.dir_bh) { |
|---|
| 4137 | 4279 | retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); |
|---|
| 4138 | 4280 | if (retval) |
|---|