| .. | .. |
|---|
| 93 | 93 | #ifdef CONFIG_EXT4_FS_SECURITY |
|---|
| 94 | 94 | [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, |
|---|
| 95 | 95 | #endif |
|---|
| 96 | + [EXT4_XATTR_INDEX_HURD] = &ext4_xattr_hurd_handler, |
|---|
| 96 | 97 | }; |
|---|
| 97 | 98 | |
|---|
| 98 | 99 | const struct xattr_handler *ext4_xattr_handlers[] = { |
|---|
| .. | .. |
|---|
| 105 | 106 | #ifdef CONFIG_EXT4_FS_SECURITY |
|---|
| 106 | 107 | &ext4_xattr_security_handler, |
|---|
| 107 | 108 | #endif |
|---|
| 109 | + &ext4_xattr_hurd_handler, |
|---|
| 108 | 110 | NULL |
|---|
| 109 | 111 | }; |
|---|
| 110 | 112 | |
|---|
| .. | .. |
|---|
| 245 | 247 | bh->b_data); |
|---|
| 246 | 248 | errout: |
|---|
| 247 | 249 | if (error) |
|---|
| 248 | | - __ext4_error_inode(inode, function, line, 0, |
|---|
| 250 | + __ext4_error_inode(inode, function, line, 0, -error, |
|---|
| 249 | 251 | "corrupted xattr block %llu", |
|---|
| 250 | 252 | (unsigned long long) bh->b_blocknr); |
|---|
| 251 | 253 | else |
|---|
| .. | .. |
|---|
| 269 | 271 | error = ext4_xattr_check_entries(IFIRST(header), end, IFIRST(header)); |
|---|
| 270 | 272 | errout: |
|---|
| 271 | 273 | if (error) |
|---|
| 272 | | - __ext4_error_inode(inode, function, line, 0, |
|---|
| 274 | + __ext4_error_inode(inode, function, line, 0, -error, |
|---|
| 273 | 275 | "corrupted in-inode xattr"); |
|---|
| 274 | 276 | return error; |
|---|
| 275 | 277 | } |
|---|
| .. | .. |
|---|
| 967 | 969 | return credits; |
|---|
| 968 | 970 | } |
|---|
| 969 | 971 | |
|---|
| 970 | | -static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode, |
|---|
| 971 | | - int credits, struct buffer_head *bh, |
|---|
| 972 | | - bool dirty, bool block_csum) |
|---|
| 973 | | -{ |
|---|
| 974 | | - int error; |
|---|
| 975 | | - |
|---|
| 976 | | - if (!ext4_handle_valid(handle)) |
|---|
| 977 | | - return 0; |
|---|
| 978 | | - |
|---|
| 979 | | - if (handle->h_buffer_credits >= credits) |
|---|
| 980 | | - return 0; |
|---|
| 981 | | - |
|---|
| 982 | | - error = ext4_journal_extend(handle, credits - handle->h_buffer_credits); |
|---|
| 983 | | - if (!error) |
|---|
| 984 | | - return 0; |
|---|
| 985 | | - if (error < 0) { |
|---|
| 986 | | - ext4_warning(inode->i_sb, "Extend journal (error %d)", error); |
|---|
| 987 | | - return error; |
|---|
| 988 | | - } |
|---|
| 989 | | - |
|---|
| 990 | | - if (bh && dirty) { |
|---|
| 991 | | - if (block_csum) |
|---|
| 992 | | - ext4_xattr_block_csum_set(inode, bh); |
|---|
| 993 | | - error = ext4_handle_dirty_metadata(handle, NULL, bh); |
|---|
| 994 | | - if (error) { |
|---|
| 995 | | - ext4_warning(inode->i_sb, "Handle metadata (error %d)", |
|---|
| 996 | | - error); |
|---|
| 997 | | - return error; |
|---|
| 998 | | - } |
|---|
| 999 | | - } |
|---|
| 1000 | | - |
|---|
| 1001 | | - error = ext4_journal_restart(handle, credits); |
|---|
| 1002 | | - if (error) { |
|---|
| 1003 | | - ext4_warning(inode->i_sb, "Restart journal (error %d)", error); |
|---|
| 1004 | | - return error; |
|---|
| 1005 | | - } |
|---|
| 1006 | | - |
|---|
| 1007 | | - if (bh) { |
|---|
| 1008 | | - error = ext4_journal_get_write_access(handle, bh); |
|---|
| 1009 | | - if (error) { |
|---|
| 1010 | | - ext4_warning(inode->i_sb, |
|---|
| 1011 | | - "Get write access failed (error %d)", |
|---|
| 1012 | | - error); |
|---|
| 1013 | | - return error; |
|---|
| 1014 | | - } |
|---|
| 1015 | | - } |
|---|
| 1016 | | - return 0; |
|---|
| 1017 | | -} |
|---|
| 1018 | | - |
|---|
| 1019 | 972 | static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, |
|---|
| 1020 | 973 | int ref_change) |
|---|
| 1021 | 974 | { |
|---|
| .. | .. |
|---|
| 1028 | 981 | inode_lock(ea_inode); |
|---|
| 1029 | 982 | |
|---|
| 1030 | 983 | ret = ext4_reserve_inode_write(handle, ea_inode, &iloc); |
|---|
| 1031 | | - if (ret) { |
|---|
| 1032 | | - iloc.bh = NULL; |
|---|
| 984 | + if (ret) |
|---|
| 1033 | 985 | goto out; |
|---|
| 1034 | | - } |
|---|
| 1035 | 986 | |
|---|
| 1036 | 987 | ref_count = ext4_xattr_inode_get_ref(ea_inode); |
|---|
| 1037 | 988 | ref_count += ref_change; |
|---|
| .. | .. |
|---|
| 1077 | 1028 | } |
|---|
| 1078 | 1029 | |
|---|
| 1079 | 1030 | ret = ext4_mark_iloc_dirty(handle, ea_inode, &iloc); |
|---|
| 1080 | | - iloc.bh = NULL; |
|---|
| 1081 | 1031 | if (ret) |
|---|
| 1082 | 1032 | ext4_warning_inode(ea_inode, |
|---|
| 1083 | 1033 | "ext4_mark_iloc_dirty() failed ret=%d", ret); |
|---|
| 1084 | 1034 | out: |
|---|
| 1085 | | - brelse(iloc.bh); |
|---|
| 1086 | 1035 | inode_unlock(ea_inode); |
|---|
| 1087 | 1036 | return ret; |
|---|
| 1088 | 1037 | } |
|---|
| .. | .. |
|---|
| 1153 | 1102 | return saved_err; |
|---|
| 1154 | 1103 | } |
|---|
| 1155 | 1104 | |
|---|
| 1105 | +static int ext4_xattr_restart_fn(handle_t *handle, struct inode *inode, |
|---|
| 1106 | + struct buffer_head *bh, bool block_csum, bool dirty) |
|---|
| 1107 | +{ |
|---|
| 1108 | + int error; |
|---|
| 1109 | + |
|---|
| 1110 | + if (bh && dirty) { |
|---|
| 1111 | + if (block_csum) |
|---|
| 1112 | + ext4_xattr_block_csum_set(inode, bh); |
|---|
| 1113 | + error = ext4_handle_dirty_metadata(handle, NULL, bh); |
|---|
| 1114 | + if (error) { |
|---|
| 1115 | + ext4_warning(inode->i_sb, "Handle metadata (error %d)", |
|---|
| 1116 | + error); |
|---|
| 1117 | + return error; |
|---|
| 1118 | + } |
|---|
| 1119 | + } |
|---|
| 1120 | + return 0; |
|---|
| 1121 | +} |
|---|
| 1122 | + |
|---|
| 1156 | 1123 | static void |
|---|
| 1157 | 1124 | ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent, |
|---|
| 1158 | 1125 | struct buffer_head *bh, |
|---|
| .. | .. |
|---|
| 1189 | 1156 | continue; |
|---|
| 1190 | 1157 | } |
|---|
| 1191 | 1158 | |
|---|
| 1192 | | - err = ext4_xattr_ensure_credits(handle, parent, credits, bh, |
|---|
| 1193 | | - dirty, block_csum); |
|---|
| 1194 | | - if (err) { |
|---|
| 1159 | + err = ext4_journal_ensure_credits_fn(handle, credits, credits, |
|---|
| 1160 | + ext4_free_metadata_revoke_credits(parent->i_sb, 1), |
|---|
| 1161 | + ext4_xattr_restart_fn(handle, parent, bh, block_csum, |
|---|
| 1162 | + dirty)); |
|---|
| 1163 | + if (err < 0) { |
|---|
| 1195 | 1164 | ext4_warning_inode(ea_inode, "Ensure credits err=%d", |
|---|
| 1196 | 1165 | err); |
|---|
| 1197 | 1166 | continue; |
|---|
| 1167 | + } |
|---|
| 1168 | + if (err > 0) { |
|---|
| 1169 | + err = ext4_journal_get_write_access(handle, bh); |
|---|
| 1170 | + if (err) { |
|---|
| 1171 | + ext4_warning_inode(ea_inode, |
|---|
| 1172 | + "Re-get write access err=%d", |
|---|
| 1173 | + err); |
|---|
| 1174 | + continue; |
|---|
| 1175 | + } |
|---|
| 1198 | 1176 | } |
|---|
| 1199 | 1177 | |
|---|
| 1200 | 1178 | err = ext4_xattr_inode_dec_ref(handle, ea_inode); |
|---|
| .. | .. |
|---|
| 1351 | 1329 | int blocksize = ea_inode->i_sb->s_blocksize; |
|---|
| 1352 | 1330 | int max_blocks = (bufsize + blocksize - 1) >> ea_inode->i_blkbits; |
|---|
| 1353 | 1331 | int csize, wsize = 0; |
|---|
| 1354 | | - int ret = 0; |
|---|
| 1332 | + int ret = 0, ret2 = 0; |
|---|
| 1355 | 1333 | int retries = 0; |
|---|
| 1356 | 1334 | |
|---|
| 1357 | 1335 | retry: |
|---|
| .. | .. |
|---|
| 1378 | 1356 | |
|---|
| 1379 | 1357 | block = 0; |
|---|
| 1380 | 1358 | while (wsize < bufsize) { |
|---|
| 1381 | | - if (bh != NULL) |
|---|
| 1382 | | - brelse(bh); |
|---|
| 1359 | + brelse(bh); |
|---|
| 1383 | 1360 | csize = (bufsize - wsize) > blocksize ? blocksize : |
|---|
| 1384 | 1361 | bufsize - wsize; |
|---|
| 1385 | 1362 | bh = ext4_getblk(handle, ea_inode, block, 0); |
|---|
| .. | .. |
|---|
| 1409 | 1386 | ext4_update_i_disksize(ea_inode, wsize); |
|---|
| 1410 | 1387 | inode_unlock(ea_inode); |
|---|
| 1411 | 1388 | |
|---|
| 1412 | | - ext4_mark_inode_dirty(handle, ea_inode); |
|---|
| 1389 | + ret2 = ext4_mark_inode_dirty(handle, ea_inode); |
|---|
| 1390 | + if (unlikely(ret2 && !ret)) |
|---|
| 1391 | + ret = ret2; |
|---|
| 1413 | 1392 | |
|---|
| 1414 | 1393 | out: |
|---|
| 1415 | 1394 | brelse(bh); |
|---|
| .. | .. |
|---|
| 1483 | 1462 | WARN_ON_ONCE(ext4_handle_valid(journal_current_handle()) && |
|---|
| 1484 | 1463 | !(current->flags & PF_MEMALLOC_NOFS)); |
|---|
| 1485 | 1464 | |
|---|
| 1486 | | - ea_data = ext4_kvmalloc(value_len, GFP_NOFS); |
|---|
| 1465 | + ea_data = kvmalloc(value_len, GFP_KERNEL); |
|---|
| 1487 | 1466 | if (!ea_data) { |
|---|
| 1488 | 1467 | mb_cache_entry_put(ea_inode_cache, ce); |
|---|
| 1489 | 1468 | return NULL; |
|---|
| .. | .. |
|---|
| 2188 | 2167 | struct ext4_inode *raw_inode; |
|---|
| 2189 | 2168 | int error; |
|---|
| 2190 | 2169 | |
|---|
| 2191 | | - if (EXT4_I(inode)->i_extra_isize == 0) |
|---|
| 2170 | + if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) |
|---|
| 2192 | 2171 | return 0; |
|---|
| 2172 | + |
|---|
| 2193 | 2173 | raw_inode = ext4_raw_inode(&is->iloc); |
|---|
| 2194 | 2174 | header = IHDR(inode, raw_inode); |
|---|
| 2195 | 2175 | is->s.base = is->s.first = IFIRST(header); |
|---|
| .. | .. |
|---|
| 2217 | 2197 | struct ext4_xattr_search *s = &is->s; |
|---|
| 2218 | 2198 | int error; |
|---|
| 2219 | 2199 | |
|---|
| 2220 | | - if (EXT4_I(inode)->i_extra_isize == 0) |
|---|
| 2200 | + if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) |
|---|
| 2221 | 2201 | return -ENOSPC; |
|---|
| 2202 | + |
|---|
| 2222 | 2203 | error = ext4_xattr_set_entry(i, s, handle, inode, false /* is_block */); |
|---|
| 2223 | 2204 | if (error) |
|---|
| 2224 | 2205 | return error; |
|---|
| .. | .. |
|---|
| 2345 | 2326 | flags & XATTR_CREATE); |
|---|
| 2346 | 2327 | brelse(bh); |
|---|
| 2347 | 2328 | |
|---|
| 2348 | | - if (!ext4_handle_has_enough_credits(handle, credits)) { |
|---|
| 2329 | + if (jbd2_handle_buffer_credits(handle) < credits) { |
|---|
| 2349 | 2330 | error = -ENOSPC; |
|---|
| 2350 | 2331 | goto cleanup; |
|---|
| 2351 | 2332 | } |
|---|
| .. | .. |
|---|
| 2444 | 2425 | if (IS_SYNC(inode)) |
|---|
| 2445 | 2426 | ext4_handle_sync(handle); |
|---|
| 2446 | 2427 | } |
|---|
| 2428 | + ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR); |
|---|
| 2447 | 2429 | |
|---|
| 2448 | 2430 | cleanup: |
|---|
| 2449 | 2431 | brelse(is.iloc.bh); |
|---|
| .. | .. |
|---|
| 2521 | 2503 | if (error == 0) |
|---|
| 2522 | 2504 | error = error2; |
|---|
| 2523 | 2505 | } |
|---|
| 2506 | + ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR); |
|---|
| 2524 | 2507 | |
|---|
| 2525 | 2508 | return error; |
|---|
| 2526 | 2509 | } |
|---|
| .. | .. |
|---|
| 2873 | 2856 | struct inode *ea_inode; |
|---|
| 2874 | 2857 | int error; |
|---|
| 2875 | 2858 | |
|---|
| 2876 | | - error = ext4_xattr_ensure_credits(handle, inode, extra_credits, |
|---|
| 2877 | | - NULL /* bh */, |
|---|
| 2878 | | - false /* dirty */, |
|---|
| 2879 | | - false /* block_csum */); |
|---|
| 2880 | | - if (error) { |
|---|
| 2859 | + error = ext4_journal_ensure_credits(handle, extra_credits, |
|---|
| 2860 | + ext4_free_metadata_revoke_credits(inode->i_sb, 1)); |
|---|
| 2861 | + if (error < 0) { |
|---|
| 2881 | 2862 | EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error); |
|---|
| 2882 | 2863 | goto cleanup; |
|---|
| 2883 | 2864 | } |
|---|
| .. | .. |
|---|
| 2912 | 2893 | bh = ext4_sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl, REQ_PRIO); |
|---|
| 2913 | 2894 | if (IS_ERR(bh)) { |
|---|
| 2914 | 2895 | error = PTR_ERR(bh); |
|---|
| 2915 | | - if (error == -EIO) |
|---|
| 2916 | | - EXT4_ERROR_INODE(inode, "block %llu read error", |
|---|
| 2917 | | - EXT4_I(inode)->i_file_acl); |
|---|
| 2896 | + if (error == -EIO) { |
|---|
| 2897 | + EXT4_ERROR_INODE_ERR(inode, EIO, |
|---|
| 2898 | + "block %llu read error", |
|---|
| 2899 | + EXT4_I(inode)->i_file_acl); |
|---|
| 2900 | + } |
|---|
| 2918 | 2901 | bh = NULL; |
|---|
| 2919 | 2902 | goto cleanup; |
|---|
| 2920 | 2903 | } |
|---|
| .. | .. |
|---|
| 2953 | 2936 | error); |
|---|
| 2954 | 2937 | goto cleanup; |
|---|
| 2955 | 2938 | } |
|---|
| 2939 | + ext4_fc_mark_ineligible(inode->i_sb, EXT4_FC_REASON_XATTR); |
|---|
| 2956 | 2940 | } |
|---|
| 2957 | 2941 | error = 0; |
|---|
| 2958 | 2942 | cleanup: |
|---|