diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-08-14 06:19:59 -0400 |
| commit | 8d7ccaa545490cdffdfaff0842436a8dd85cf47b (patch) | |
| tree | 8129b5907161bc6ae26deb3645ce1e280c5e1f51 /fs/ext4/inode.c | |
| parent | b2139aa0eec330c711c5a279db361e5ef1178e78 (diff) | |
| parent | 30a2f3c60a84092c8084dfe788b710f8d0768cd4 (diff) | |
Merge commit 'v2.6.27-rc3' into x86/prototypes
Conflicts:
include/asm-x86/dma-mapping.h
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs/ext4/inode.c')
| -rw-r--r-- | fs/ext4/inode.c | 256 |
1 files changed, 161 insertions, 95 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8ca2763df091..59fbbe899acc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -191,6 +191,7 @@ static int ext4_journal_test_restart(handle_t *handle, struct inode *inode) | |||
| 191 | void ext4_delete_inode (struct inode * inode) | 191 | void ext4_delete_inode (struct inode * inode) |
| 192 | { | 192 | { |
| 193 | handle_t *handle; | 193 | handle_t *handle; |
| 194 | int err; | ||
| 194 | 195 | ||
| 195 | if (ext4_should_order_data(inode)) | 196 | if (ext4_should_order_data(inode)) |
| 196 | ext4_begin_ordered_truncate(inode, 0); | 197 | ext4_begin_ordered_truncate(inode, 0); |
| @@ -199,8 +200,9 @@ void ext4_delete_inode (struct inode * inode) | |||
| 199 | if (is_bad_inode(inode)) | 200 | if (is_bad_inode(inode)) |
| 200 | goto no_delete; | 201 | goto no_delete; |
| 201 | 202 | ||
| 202 | handle = start_transaction(inode); | 203 | handle = ext4_journal_start(inode, blocks_for_truncate(inode)+3); |
| 203 | if (IS_ERR(handle)) { | 204 | if (IS_ERR(handle)) { |
| 205 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); | ||
| 204 | /* | 206 | /* |
| 205 | * If we're going to skip the normal cleanup, we still need to | 207 | * If we're going to skip the normal cleanup, we still need to |
| 206 | * make sure that the in-core orphan linked list is properly | 208 | * make sure that the in-core orphan linked list is properly |
| @@ -213,8 +215,34 @@ void ext4_delete_inode (struct inode * inode) | |||
| 213 | if (IS_SYNC(inode)) | 215 | if (IS_SYNC(inode)) |
| 214 | handle->h_sync = 1; | 216 | handle->h_sync = 1; |
| 215 | inode->i_size = 0; | 217 | inode->i_size = 0; |
| 218 | err = ext4_mark_inode_dirty(handle, inode); | ||
| 219 | if (err) { | ||
| 220 | ext4_warning(inode->i_sb, __func__, | ||
| 221 | "couldn't mark inode dirty (err %d)", err); | ||
| 222 | goto stop_handle; | ||
| 223 | } | ||
| 216 | if (inode->i_blocks) | 224 | if (inode->i_blocks) |
| 217 | ext4_truncate(inode); | 225 | ext4_truncate(inode); |
| 226 | |||
| 227 | /* | ||
| 228 | * ext4_ext_truncate() doesn't reserve any slop when it | ||
| 229 | * restarts journal transactions; therefore there may not be | ||
| 230 | * enough credits left in the handle to remove the inode from | ||
| 231 | * the orphan list and set the dtime field. | ||
| 232 | */ | ||
| 233 | if (handle->h_buffer_credits < 3) { | ||
| 234 | err = ext4_journal_extend(handle, 3); | ||
| 235 | if (err > 0) | ||
| 236 | err = ext4_journal_restart(handle, 3); | ||
| 237 | if (err != 0) { | ||
| 238 | ext4_warning(inode->i_sb, __func__, | ||
| 239 | "couldn't extend journal (err %d)", err); | ||
| 240 | stop_handle: | ||
| 241 | ext4_journal_stop(handle); | ||
| 242 | goto no_delete; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 218 | /* | 246 | /* |
| 219 | * Kill off the orphan record which ext4_truncate created. | 247 | * Kill off the orphan record which ext4_truncate created. |
| 220 | * AKPM: I think this can be inside the above `if'. | 248 | * AKPM: I think this can be inside the above `if'. |
| @@ -952,6 +980,67 @@ out: | |||
| 952 | return err; | 980 | return err; |
| 953 | } | 981 | } |
| 954 | 982 | ||
| 983 | /* | ||
| 984 | * Calculate the number of metadata blocks need to reserve | ||
| 985 | * to allocate @blocks for non extent file based file | ||
| 986 | */ | ||
| 987 | static int ext4_indirect_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 988 | { | ||
| 989 | int icap = EXT4_ADDR_PER_BLOCK(inode->i_sb); | ||
| 990 | int ind_blks, dind_blks, tind_blks; | ||
| 991 | |||
| 992 | /* number of new indirect blocks needed */ | ||
| 993 | ind_blks = (blocks + icap - 1) / icap; | ||
| 994 | |||
| 995 | dind_blks = (ind_blks + icap - 1) / icap; | ||
| 996 | |||
| 997 | tind_blks = 1; | ||
| 998 | |||
| 999 | return ind_blks + dind_blks + tind_blks; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | /* | ||
| 1003 | * Calculate the number of metadata blocks need to reserve | ||
| 1004 | * to allocate given number of blocks | ||
| 1005 | */ | ||
| 1006 | static int ext4_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 1007 | { | ||
| 1008 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) | ||
| 1009 | return ext4_ext_calc_metadata_amount(inode, blocks); | ||
| 1010 | |||
| 1011 | return ext4_indirect_calc_metadata_amount(inode, blocks); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | static void ext4_da_update_reserve_space(struct inode *inode, int used) | ||
| 1015 | { | ||
| 1016 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
| 1017 | int total, mdb, mdb_free; | ||
| 1018 | |||
| 1019 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | ||
| 1020 | /* recalculate the number of metablocks still need to be reserved */ | ||
| 1021 | total = EXT4_I(inode)->i_reserved_data_blocks - used; | ||
| 1022 | mdb = ext4_calc_metadata_amount(inode, total); | ||
| 1023 | |||
| 1024 | /* figure out how many metablocks to release */ | ||
| 1025 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | ||
| 1026 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; | ||
| 1027 | |||
| 1028 | /* Account for allocated meta_blocks */ | ||
| 1029 | mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; | ||
| 1030 | |||
| 1031 | /* update fs free blocks counter for truncate case */ | ||
| 1032 | percpu_counter_add(&sbi->s_freeblocks_counter, mdb_free); | ||
| 1033 | |||
| 1034 | /* update per-inode reservations */ | ||
| 1035 | BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks); | ||
| 1036 | EXT4_I(inode)->i_reserved_data_blocks -= used; | ||
| 1037 | |||
| 1038 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | ||
| 1039 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; | ||
| 1040 | EXT4_I(inode)->i_allocated_meta_blocks = 0; | ||
| 1041 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | ||
| 1042 | } | ||
| 1043 | |||
| 955 | /* Maximum number of blocks we map for direct IO at once. */ | 1044 | /* Maximum number of blocks we map for direct IO at once. */ |
| 956 | #define DIO_MAX_BLOCKS 4096 | 1045 | #define DIO_MAX_BLOCKS 4096 |
| 957 | /* | 1046 | /* |
| @@ -965,10 +1054,9 @@ out: | |||
| 965 | 1054 | ||
| 966 | 1055 | ||
| 967 | /* | 1056 | /* |
| 1057 | * The ext4_get_blocks_wrap() function try to look up the requested blocks, | ||
| 1058 | * and returns if the blocks are already mapped. | ||
| 968 | * | 1059 | * |
| 969 | * | ||
| 970 | * ext4_ext4 get_block() wrapper function | ||
| 971 | * It will do a look up first, and returns if the blocks already mapped. | ||
| 972 | * Otherwise it takes the write lock of the i_data_sem and allocate blocks | 1060 | * Otherwise it takes the write lock of the i_data_sem and allocate blocks |
| 973 | * and store the allocated blocks in the result buffer head and mark it | 1061 | * and store the allocated blocks in the result buffer head and mark it |
| 974 | * mapped. | 1062 | * mapped. |
| @@ -1069,7 +1157,7 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, | |||
| 1069 | * which were deferred till now | 1157 | * which were deferred till now |
| 1070 | */ | 1158 | */ |
| 1071 | if ((retval > 0) && buffer_delay(bh)) | 1159 | if ((retval > 0) && buffer_delay(bh)) |
| 1072 | ext4_da_release_space(inode, retval, 0); | 1160 | ext4_da_update_reserve_space(inode, retval); |
| 1073 | } | 1161 | } |
| 1074 | 1162 | ||
| 1075 | up_write((&EXT4_I(inode)->i_data_sem)); | 1163 | up_write((&EXT4_I(inode)->i_data_sem)); |
| @@ -1336,12 +1424,8 @@ static int ext4_ordered_write_end(struct file *file, | |||
| 1336 | { | 1424 | { |
| 1337 | handle_t *handle = ext4_journal_current_handle(); | 1425 | handle_t *handle = ext4_journal_current_handle(); |
| 1338 | struct inode *inode = mapping->host; | 1426 | struct inode *inode = mapping->host; |
| 1339 | unsigned from, to; | ||
| 1340 | int ret = 0, ret2; | 1427 | int ret = 0, ret2; |
| 1341 | 1428 | ||
| 1342 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
| 1343 | to = from + len; | ||
| 1344 | |||
| 1345 | ret = ext4_jbd2_file_inode(handle, inode); | 1429 | ret = ext4_jbd2_file_inode(handle, inode); |
| 1346 | 1430 | ||
| 1347 | if (ret == 0) { | 1431 | if (ret == 0) { |
| @@ -1437,36 +1521,6 @@ static int ext4_journalled_write_end(struct file *file, | |||
| 1437 | 1521 | ||
| 1438 | return ret ? ret : copied; | 1522 | return ret ? ret : copied; |
| 1439 | } | 1523 | } |
| 1440 | /* | ||
| 1441 | * Calculate the number of metadata blocks need to reserve | ||
| 1442 | * to allocate @blocks for non extent file based file | ||
| 1443 | */ | ||
| 1444 | static int ext4_indirect_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 1445 | { | ||
| 1446 | int icap = EXT4_ADDR_PER_BLOCK(inode->i_sb); | ||
| 1447 | int ind_blks, dind_blks, tind_blks; | ||
| 1448 | |||
| 1449 | /* number of new indirect blocks needed */ | ||
| 1450 | ind_blks = (blocks + icap - 1) / icap; | ||
| 1451 | |||
| 1452 | dind_blks = (ind_blks + icap - 1) / icap; | ||
| 1453 | |||
| 1454 | tind_blks = 1; | ||
| 1455 | |||
| 1456 | return ind_blks + dind_blks + tind_blks; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | /* | ||
| 1460 | * Calculate the number of metadata blocks need to reserve | ||
| 1461 | * to allocate given number of blocks | ||
| 1462 | */ | ||
| 1463 | static int ext4_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 1464 | { | ||
| 1465 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) | ||
| 1466 | return ext4_ext_calc_metadata_amount(inode, blocks); | ||
| 1467 | |||
| 1468 | return ext4_indirect_calc_metadata_amount(inode, blocks); | ||
| 1469 | } | ||
| 1470 | 1524 | ||
| 1471 | static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | 1525 | static int ext4_da_reserve_space(struct inode *inode, int nrblocks) |
| 1472 | { | 1526 | { |
| @@ -1490,7 +1544,6 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | |||
| 1490 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1544 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
| 1491 | return -ENOSPC; | 1545 | return -ENOSPC; |
| 1492 | } | 1546 | } |
| 1493 | |||
| 1494 | /* reduce fs free blocks counter */ | 1547 | /* reduce fs free blocks counter */ |
| 1495 | percpu_counter_sub(&sbi->s_freeblocks_counter, total); | 1548 | percpu_counter_sub(&sbi->s_freeblocks_counter, total); |
| 1496 | 1549 | ||
| @@ -1501,35 +1554,31 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | |||
| 1501 | return 0; /* success */ | 1554 | return 0; /* success */ |
| 1502 | } | 1555 | } |
| 1503 | 1556 | ||
| 1504 | void ext4_da_release_space(struct inode *inode, int used, int to_free) | 1557 | static void ext4_da_release_space(struct inode *inode, int to_free) |
| 1505 | { | 1558 | { |
| 1506 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 1559 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
| 1507 | int total, mdb, mdb_free, release; | 1560 | int total, mdb, mdb_free, release; |
| 1508 | 1561 | ||
| 1509 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | 1562 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); |
| 1510 | /* recalculate the number of metablocks still need to be reserved */ | 1563 | /* recalculate the number of metablocks still need to be reserved */ |
| 1511 | total = EXT4_I(inode)->i_reserved_data_blocks - used - to_free; | 1564 | total = EXT4_I(inode)->i_reserved_data_blocks - to_free; |
| 1512 | mdb = ext4_calc_metadata_amount(inode, total); | 1565 | mdb = ext4_calc_metadata_amount(inode, total); |
| 1513 | 1566 | ||
| 1514 | /* figure out how many metablocks to release */ | 1567 | /* figure out how many metablocks to release */ |
| 1515 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | 1568 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); |
| 1516 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; | 1569 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; |
| 1517 | 1570 | ||
| 1518 | /* Account for allocated meta_blocks */ | ||
| 1519 | mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; | ||
| 1520 | |||
| 1521 | release = to_free + mdb_free; | 1571 | release = to_free + mdb_free; |
| 1522 | 1572 | ||
| 1523 | /* update fs free blocks counter for truncate case */ | 1573 | /* update fs free blocks counter for truncate case */ |
| 1524 | percpu_counter_add(&sbi->s_freeblocks_counter, release); | 1574 | percpu_counter_add(&sbi->s_freeblocks_counter, release); |
| 1525 | 1575 | ||
| 1526 | /* update per-inode reservations */ | 1576 | /* update per-inode reservations */ |
| 1527 | BUG_ON(used + to_free > EXT4_I(inode)->i_reserved_data_blocks); | 1577 | BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks); |
| 1528 | EXT4_I(inode)->i_reserved_data_blocks -= (used + to_free); | 1578 | EXT4_I(inode)->i_reserved_data_blocks -= to_free; |
| 1529 | 1579 | ||
| 1530 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | 1580 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); |
| 1531 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; | 1581 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; |
| 1532 | EXT4_I(inode)->i_allocated_meta_blocks = 0; | ||
| 1533 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1582 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
| 1534 | } | 1583 | } |
| 1535 | 1584 | ||
| @@ -1551,7 +1600,7 @@ static void ext4_da_page_release_reservation(struct page *page, | |||
| 1551 | } | 1600 | } |
| 1552 | curr_off = next_off; | 1601 | curr_off = next_off; |
| 1553 | } while ((bh = bh->b_this_page) != head); | 1602 | } while ((bh = bh->b_this_page) != head); |
| 1554 | ext4_da_release_space(page->mapping->host, 0, to_release); | 1603 | ext4_da_release_space(page->mapping->host, to_release); |
| 1555 | } | 1604 | } |
| 1556 | 1605 | ||
| 1557 | /* | 1606 | /* |
| @@ -2280,8 +2329,11 @@ retry: | |||
| 2280 | } | 2329 | } |
| 2281 | 2330 | ||
| 2282 | page = __grab_cache_page(mapping, index); | 2331 | page = __grab_cache_page(mapping, index); |
| 2283 | if (!page) | 2332 | if (!page) { |
| 2284 | return -ENOMEM; | 2333 | ext4_journal_stop(handle); |
| 2334 | ret = -ENOMEM; | ||
| 2335 | goto out; | ||
| 2336 | } | ||
| 2285 | *pagep = page; | 2337 | *pagep = page; |
| 2286 | 2338 | ||
| 2287 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 2339 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| @@ -2806,59 +2858,63 @@ static int ext4_journalled_set_page_dirty(struct page *page) | |||
| 2806 | } | 2858 | } |
| 2807 | 2859 | ||
| 2808 | static const struct address_space_operations ext4_ordered_aops = { | 2860 | static const struct address_space_operations ext4_ordered_aops = { |
| 2809 | .readpage = ext4_readpage, | 2861 | .readpage = ext4_readpage, |
| 2810 | .readpages = ext4_readpages, | 2862 | .readpages = ext4_readpages, |
| 2811 | .writepage = ext4_normal_writepage, | 2863 | .writepage = ext4_normal_writepage, |
| 2812 | .sync_page = block_sync_page, | 2864 | .sync_page = block_sync_page, |
| 2813 | .write_begin = ext4_write_begin, | 2865 | .write_begin = ext4_write_begin, |
| 2814 | .write_end = ext4_ordered_write_end, | 2866 | .write_end = ext4_ordered_write_end, |
| 2815 | .bmap = ext4_bmap, | 2867 | .bmap = ext4_bmap, |
| 2816 | .invalidatepage = ext4_invalidatepage, | 2868 | .invalidatepage = ext4_invalidatepage, |
| 2817 | .releasepage = ext4_releasepage, | 2869 | .releasepage = ext4_releasepage, |
| 2818 | .direct_IO = ext4_direct_IO, | 2870 | .direct_IO = ext4_direct_IO, |
| 2819 | .migratepage = buffer_migrate_page, | 2871 | .migratepage = buffer_migrate_page, |
| 2872 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2820 | }; | 2873 | }; |
| 2821 | 2874 | ||
| 2822 | static const struct address_space_operations ext4_writeback_aops = { | 2875 | static const struct address_space_operations ext4_writeback_aops = { |
| 2823 | .readpage = ext4_readpage, | 2876 | .readpage = ext4_readpage, |
| 2824 | .readpages = ext4_readpages, | 2877 | .readpages = ext4_readpages, |
| 2825 | .writepage = ext4_normal_writepage, | 2878 | .writepage = ext4_normal_writepage, |
| 2826 | .sync_page = block_sync_page, | 2879 | .sync_page = block_sync_page, |
| 2827 | .write_begin = ext4_write_begin, | 2880 | .write_begin = ext4_write_begin, |
| 2828 | .write_end = ext4_writeback_write_end, | 2881 | .write_end = ext4_writeback_write_end, |
| 2829 | .bmap = ext4_bmap, | 2882 | .bmap = ext4_bmap, |
| 2830 | .invalidatepage = ext4_invalidatepage, | 2883 | .invalidatepage = ext4_invalidatepage, |
| 2831 | .releasepage = ext4_releasepage, | 2884 | .releasepage = ext4_releasepage, |
| 2832 | .direct_IO = ext4_direct_IO, | 2885 | .direct_IO = ext4_direct_IO, |
| 2833 | .migratepage = buffer_migrate_page, | 2886 | .migratepage = buffer_migrate_page, |
| 2887 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2834 | }; | 2888 | }; |
| 2835 | 2889 | ||
| 2836 | static const struct address_space_operations ext4_journalled_aops = { | 2890 | static const struct address_space_operations ext4_journalled_aops = { |
| 2837 | .readpage = ext4_readpage, | 2891 | .readpage = ext4_readpage, |
| 2838 | .readpages = ext4_readpages, | 2892 | .readpages = ext4_readpages, |
| 2839 | .writepage = ext4_journalled_writepage, | 2893 | .writepage = ext4_journalled_writepage, |
| 2840 | .sync_page = block_sync_page, | 2894 | .sync_page = block_sync_page, |
| 2841 | .write_begin = ext4_write_begin, | 2895 | .write_begin = ext4_write_begin, |
| 2842 | .write_end = ext4_journalled_write_end, | 2896 | .write_end = ext4_journalled_write_end, |
| 2843 | .set_page_dirty = ext4_journalled_set_page_dirty, | 2897 | .set_page_dirty = ext4_journalled_set_page_dirty, |
| 2844 | .bmap = ext4_bmap, | 2898 | .bmap = ext4_bmap, |
| 2845 | .invalidatepage = ext4_invalidatepage, | 2899 | .invalidatepage = ext4_invalidatepage, |
| 2846 | .releasepage = ext4_releasepage, | 2900 | .releasepage = ext4_releasepage, |
| 2901 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2847 | }; | 2902 | }; |
| 2848 | 2903 | ||
| 2849 | static const struct address_space_operations ext4_da_aops = { | 2904 | static const struct address_space_operations ext4_da_aops = { |
| 2850 | .readpage = ext4_readpage, | 2905 | .readpage = ext4_readpage, |
| 2851 | .readpages = ext4_readpages, | 2906 | .readpages = ext4_readpages, |
| 2852 | .writepage = ext4_da_writepage, | 2907 | .writepage = ext4_da_writepage, |
| 2853 | .writepages = ext4_da_writepages, | 2908 | .writepages = ext4_da_writepages, |
| 2854 | .sync_page = block_sync_page, | 2909 | .sync_page = block_sync_page, |
| 2855 | .write_begin = ext4_da_write_begin, | 2910 | .write_begin = ext4_da_write_begin, |
| 2856 | .write_end = ext4_da_write_end, | 2911 | .write_end = ext4_da_write_end, |
| 2857 | .bmap = ext4_bmap, | 2912 | .bmap = ext4_bmap, |
| 2858 | .invalidatepage = ext4_da_invalidatepage, | 2913 | .invalidatepage = ext4_da_invalidatepage, |
| 2859 | .releasepage = ext4_releasepage, | 2914 | .releasepage = ext4_releasepage, |
| 2860 | .direct_IO = ext4_direct_IO, | 2915 | .direct_IO = ext4_direct_IO, |
| 2861 | .migratepage = buffer_migrate_page, | 2916 | .migratepage = buffer_migrate_page, |
| 2917 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2862 | }; | 2918 | }; |
| 2863 | 2919 | ||
| 2864 | void ext4_set_aops(struct inode *inode) | 2920 | void ext4_set_aops(struct inode *inode) |
| @@ -3586,6 +3642,16 @@ static int __ext4_get_inode_loc(struct inode *inode, | |||
| 3586 | } | 3642 | } |
| 3587 | if (!buffer_uptodate(bh)) { | 3643 | if (!buffer_uptodate(bh)) { |
| 3588 | lock_buffer(bh); | 3644 | lock_buffer(bh); |
| 3645 | |||
| 3646 | /* | ||
| 3647 | * If the buffer has the write error flag, we have failed | ||
| 3648 | * to write out another inode in the same block. In this | ||
| 3649 | * case, we don't have to read the block because we may | ||
| 3650 | * read the old inode data successfully. | ||
| 3651 | */ | ||
| 3652 | if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) | ||
| 3653 | set_buffer_uptodate(bh); | ||
| 3654 | |||
| 3589 | if (buffer_uptodate(bh)) { | 3655 | if (buffer_uptodate(bh)) { |
| 3590 | /* someone brought it uptodate while we waited */ | 3656 | /* someone brought it uptodate while we waited */ |
| 3591 | unlock_buffer(bh); | 3657 | unlock_buffer(bh); |
