diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 2 | ||||
-rw-r--r-- | fs/ext4/extents.c | 14 | ||||
-rw-r--r-- | fs/ext4/inode.c | 85 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 41 |
4 files changed, 43 insertions, 99 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index c4dd1103ccf1..8a23483ca8d0 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -50,7 +50,7 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, | |||
50 | * The file system contains group descriptors which are located after the | 50 | * The file system contains group descriptors which are located after the |
51 | * super block. Each descriptor contains the number of the bitmap block and | 51 | * super block. Each descriptor contains the number of the bitmap block and |
52 | * the free blocks count in the block. The descriptors are loaded in memory | 52 | * the free blocks count in the block. The descriptors are loaded in memory |
53 | * when a file system is mounted (see ext4_read_super). | 53 | * when a file system is mounted (see ext4_fill_super). |
54 | */ | 54 | */ |
55 | 55 | ||
56 | 56 | ||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index dc2724fa7622..7916b50f9a13 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -222,7 +222,7 @@ static int ext4_ext_space_block(struct inode *inode) | |||
222 | 222 | ||
223 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) | 223 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) |
224 | / sizeof(struct ext4_extent); | 224 | / sizeof(struct ext4_extent); |
225 | #ifdef AGRESSIVE_TEST | 225 | #ifdef AGGRESSIVE_TEST |
226 | if (size > 6) | 226 | if (size > 6) |
227 | size = 6; | 227 | size = 6; |
228 | #endif | 228 | #endif |
@@ -235,7 +235,7 @@ static int ext4_ext_space_block_idx(struct inode *inode) | |||
235 | 235 | ||
236 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) | 236 | size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) |
237 | / sizeof(struct ext4_extent_idx); | 237 | / sizeof(struct ext4_extent_idx); |
238 | #ifdef AGRESSIVE_TEST | 238 | #ifdef AGGRESSIVE_TEST |
239 | if (size > 5) | 239 | if (size > 5) |
240 | size = 5; | 240 | size = 5; |
241 | #endif | 241 | #endif |
@@ -249,7 +249,7 @@ static int ext4_ext_space_root(struct inode *inode) | |||
249 | size = sizeof(EXT4_I(inode)->i_data); | 249 | size = sizeof(EXT4_I(inode)->i_data); |
250 | size -= sizeof(struct ext4_extent_header); | 250 | size -= sizeof(struct ext4_extent_header); |
251 | size /= sizeof(struct ext4_extent); | 251 | size /= sizeof(struct ext4_extent); |
252 | #ifdef AGRESSIVE_TEST | 252 | #ifdef AGGRESSIVE_TEST |
253 | if (size > 3) | 253 | if (size > 3) |
254 | size = 3; | 254 | size = 3; |
255 | #endif | 255 | #endif |
@@ -263,7 +263,7 @@ static int ext4_ext_space_root_idx(struct inode *inode) | |||
263 | size = sizeof(EXT4_I(inode)->i_data); | 263 | size = sizeof(EXT4_I(inode)->i_data); |
264 | size -= sizeof(struct ext4_extent_header); | 264 | size -= sizeof(struct ext4_extent_header); |
265 | size /= sizeof(struct ext4_extent_idx); | 265 | size /= sizeof(struct ext4_extent_idx); |
266 | #ifdef AGRESSIVE_TEST | 266 | #ifdef AGGRESSIVE_TEST |
267 | if (size > 4) | 267 | if (size > 4) |
268 | size = 4; | 268 | size = 4; |
269 | #endif | 269 | #endif |
@@ -1118,7 +1118,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | |||
1118 | */ | 1118 | */ |
1119 | if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN) | 1119 | if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN) |
1120 | return 0; | 1120 | return 0; |
1121 | #ifdef AGRESSIVE_TEST | 1121 | #ifdef AGGRESSIVE_TEST |
1122 | if (le16_to_cpu(ex1->ee_len) >= 4) | 1122 | if (le16_to_cpu(ex1->ee_len) >= 4) |
1123 | return 0; | 1123 | return 0; |
1124 | #endif | 1124 | #endif |
@@ -1891,8 +1891,8 @@ void ext4_ext_init(struct super_block *sb) | |||
1891 | 1891 | ||
1892 | if (test_opt(sb, EXTENTS)) { | 1892 | if (test_opt(sb, EXTENTS)) { |
1893 | printk("EXT4-fs: file extents enabled"); | 1893 | printk("EXT4-fs: file extents enabled"); |
1894 | #ifdef AGRESSIVE_TEST | 1894 | #ifdef AGGRESSIVE_TEST |
1895 | printk(", agressive tests"); | 1895 | printk(", aggressive tests"); |
1896 | #endif | 1896 | #endif |
1897 | #ifdef CHECK_BINSEARCH | 1897 | #ifdef CHECK_BINSEARCH |
1898 | printk(", check binsearch"); | 1898 | printk(", check binsearch"); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index fbff4b9e122a..810b6d6474bf 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -1147,102 +1147,37 @@ static int do_journal_get_write_access(handle_t *handle, | |||
1147 | return ext4_journal_get_write_access(handle, bh); | 1147 | return ext4_journal_get_write_access(handle, bh); |
1148 | } | 1148 | } |
1149 | 1149 | ||
1150 | /* | ||
1151 | * The idea of this helper function is following: | ||
1152 | * if prepare_write has allocated some blocks, but not all of them, the | ||
1153 | * transaction must include the content of the newly allocated blocks. | ||
1154 | * This content is expected to be set to zeroes by block_prepare_write(). | ||
1155 | * 2006/10/14 SAW | ||
1156 | */ | ||
1157 | static int ext4_prepare_failure(struct file *file, struct page *page, | ||
1158 | unsigned from, unsigned to) | ||
1159 | { | ||
1160 | struct address_space *mapping; | ||
1161 | struct buffer_head *bh, *head, *next; | ||
1162 | unsigned block_start, block_end; | ||
1163 | unsigned blocksize; | ||
1164 | int ret; | ||
1165 | handle_t *handle = ext4_journal_current_handle(); | ||
1166 | |||
1167 | mapping = page->mapping; | ||
1168 | if (ext4_should_writeback_data(mapping->host)) { | ||
1169 | /* optimization: no constraints about data */ | ||
1170 | skip: | ||
1171 | return ext4_journal_stop(handle); | ||
1172 | } | ||
1173 | |||
1174 | head = page_buffers(page); | ||
1175 | blocksize = head->b_size; | ||
1176 | for ( bh = head, block_start = 0; | ||
1177 | bh != head || !block_start; | ||
1178 | block_start = block_end, bh = next) | ||
1179 | { | ||
1180 | next = bh->b_this_page; | ||
1181 | block_end = block_start + blocksize; | ||
1182 | if (block_end <= from) | ||
1183 | continue; | ||
1184 | if (block_start >= to) { | ||
1185 | block_start = to; | ||
1186 | break; | ||
1187 | } | ||
1188 | if (!buffer_mapped(bh)) | ||
1189 | /* prepare_write failed on this bh */ | ||
1190 | break; | ||
1191 | if (ext4_should_journal_data(mapping->host)) { | ||
1192 | ret = do_journal_get_write_access(handle, bh); | ||
1193 | if (ret) { | ||
1194 | ext4_journal_stop(handle); | ||
1195 | return ret; | ||
1196 | } | ||
1197 | } | ||
1198 | /* | ||
1199 | * block_start here becomes the first block where the current iteration | ||
1200 | * of prepare_write failed. | ||
1201 | */ | ||
1202 | } | ||
1203 | if (block_start <= from) | ||
1204 | goto skip; | ||
1205 | |||
1206 | /* commit allocated and zeroed buffers */ | ||
1207 | return mapping->a_ops->commit_write(file, page, from, block_start); | ||
1208 | } | ||
1209 | |||
1210 | static int ext4_prepare_write(struct file *file, struct page *page, | 1150 | static int ext4_prepare_write(struct file *file, struct page *page, |
1211 | unsigned from, unsigned to) | 1151 | unsigned from, unsigned to) |
1212 | { | 1152 | { |
1213 | struct inode *inode = page->mapping->host; | 1153 | struct inode *inode = page->mapping->host; |
1214 | int ret, ret2; | 1154 | int ret, needed_blocks = ext4_writepage_trans_blocks(inode); |
1215 | int needed_blocks = ext4_writepage_trans_blocks(inode); | ||
1216 | handle_t *handle; | 1155 | handle_t *handle; |
1217 | int retries = 0; | 1156 | int retries = 0; |
1218 | 1157 | ||
1219 | retry: | 1158 | retry: |
1220 | handle = ext4_journal_start(inode, needed_blocks); | 1159 | handle = ext4_journal_start(inode, needed_blocks); |
1221 | if (IS_ERR(handle)) | 1160 | if (IS_ERR(handle)) { |
1222 | return PTR_ERR(handle); | 1161 | ret = PTR_ERR(handle); |
1162 | goto out; | ||
1163 | } | ||
1223 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) | 1164 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) |
1224 | ret = nobh_prepare_write(page, from, to, ext4_get_block); | 1165 | ret = nobh_prepare_write(page, from, to, ext4_get_block); |
1225 | else | 1166 | else |
1226 | ret = block_prepare_write(page, from, to, ext4_get_block); | 1167 | ret = block_prepare_write(page, from, to, ext4_get_block); |
1227 | if (ret) | 1168 | if (ret) |
1228 | goto failure; | 1169 | goto prepare_write_failed; |
1229 | 1170 | ||
1230 | if (ext4_should_journal_data(inode)) { | 1171 | if (ext4_should_journal_data(inode)) { |
1231 | ret = walk_page_buffers(handle, page_buffers(page), | 1172 | ret = walk_page_buffers(handle, page_buffers(page), |
1232 | from, to, NULL, do_journal_get_write_access); | 1173 | from, to, NULL, do_journal_get_write_access); |
1233 | if (ret) | ||
1234 | /* fatal error, just put the handle and return */ | ||
1235 | ext4_journal_stop(handle); | ||
1236 | } | 1174 | } |
1237 | return ret; | 1175 | prepare_write_failed: |
1238 | 1176 | if (ret) | |
1239 | failure: | 1177 | ext4_journal_stop(handle); |
1240 | ret2 = ext4_prepare_failure(file, page, from, to); | ||
1241 | if (ret2 < 0) | ||
1242 | return ret2; | ||
1243 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | 1178 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) |
1244 | goto retry; | 1179 | goto retry; |
1245 | /* retry number exceeded, or other error like -EDQUOT */ | 1180 | out: |
1246 | return ret; | 1181 | return ret; |
1247 | } | 1182 | } |
1248 | 1183 | ||
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index dc969c357aa1..e832e96095b3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -475,8 +475,14 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, | |||
475 | struct buffer_head *bh) | 475 | struct buffer_head *bh) |
476 | { | 476 | { |
477 | struct mb_cache_entry *ce = NULL; | 477 | struct mb_cache_entry *ce = NULL; |
478 | int error = 0; | ||
478 | 479 | ||
479 | ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr); | 480 | ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr); |
481 | error = ext4_journal_get_write_access(handle, bh); | ||
482 | if (error) | ||
483 | goto out; | ||
484 | |||
485 | lock_buffer(bh); | ||
480 | if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { | 486 | if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { |
481 | ea_bdebug(bh, "refcount now=0; freeing"); | 487 | ea_bdebug(bh, "refcount now=0; freeing"); |
482 | if (ce) | 488 | if (ce) |
@@ -485,21 +491,21 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, | |||
485 | get_bh(bh); | 491 | get_bh(bh); |
486 | ext4_forget(handle, 1, inode, bh, bh->b_blocknr); | 492 | ext4_forget(handle, 1, inode, bh, bh->b_blocknr); |
487 | } else { | 493 | } else { |
488 | if (ext4_journal_get_write_access(handle, bh) == 0) { | 494 | BHDR(bh)->h_refcount = cpu_to_le32( |
489 | lock_buffer(bh); | ||
490 | BHDR(bh)->h_refcount = cpu_to_le32( | ||
491 | le32_to_cpu(BHDR(bh)->h_refcount) - 1); | 495 | le32_to_cpu(BHDR(bh)->h_refcount) - 1); |
492 | ext4_journal_dirty_metadata(handle, bh); | 496 | error = ext4_journal_dirty_metadata(handle, bh); |
493 | if (IS_SYNC(inode)) | 497 | if (IS_SYNC(inode)) |
494 | handle->h_sync = 1; | 498 | handle->h_sync = 1; |
495 | DQUOT_FREE_BLOCK(inode, 1); | 499 | DQUOT_FREE_BLOCK(inode, 1); |
496 | unlock_buffer(bh); | 500 | ea_bdebug(bh, "refcount now=%d; releasing", |
497 | ea_bdebug(bh, "refcount now=%d; releasing", | 501 | le32_to_cpu(BHDR(bh)->h_refcount)); |
498 | le32_to_cpu(BHDR(bh)->h_refcount)); | ||
499 | } | ||
500 | if (ce) | 502 | if (ce) |
501 | mb_cache_entry_release(ce); | 503 | mb_cache_entry_release(ce); |
502 | } | 504 | } |
505 | unlock_buffer(bh); | ||
506 | out: | ||
507 | ext4_std_error(inode->i_sb, error); | ||
508 | return; | ||
503 | } | 509 | } |
504 | 510 | ||
505 | struct ext4_xattr_info { | 511 | struct ext4_xattr_info { |
@@ -675,7 +681,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
675 | struct buffer_head *new_bh = NULL; | 681 | struct buffer_head *new_bh = NULL; |
676 | struct ext4_xattr_search *s = &bs->s; | 682 | struct ext4_xattr_search *s = &bs->s; |
677 | struct mb_cache_entry *ce = NULL; | 683 | struct mb_cache_entry *ce = NULL; |
678 | int error; | 684 | int error = 0; |
679 | 685 | ||
680 | #define header(x) ((struct ext4_xattr_header *)(x)) | 686 | #define header(x) ((struct ext4_xattr_header *)(x)) |
681 | 687 | ||
@@ -684,16 +690,17 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
684 | if (s->base) { | 690 | if (s->base) { |
685 | ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev, | 691 | ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev, |
686 | bs->bh->b_blocknr); | 692 | bs->bh->b_blocknr); |
693 | error = ext4_journal_get_write_access(handle, bs->bh); | ||
694 | if (error) | ||
695 | goto cleanup; | ||
696 | lock_buffer(bs->bh); | ||
697 | |||
687 | if (header(s->base)->h_refcount == cpu_to_le32(1)) { | 698 | if (header(s->base)->h_refcount == cpu_to_le32(1)) { |
688 | if (ce) { | 699 | if (ce) { |
689 | mb_cache_entry_free(ce); | 700 | mb_cache_entry_free(ce); |
690 | ce = NULL; | 701 | ce = NULL; |
691 | } | 702 | } |
692 | ea_bdebug(bs->bh, "modifying in-place"); | 703 | ea_bdebug(bs->bh, "modifying in-place"); |
693 | error = ext4_journal_get_write_access(handle, bs->bh); | ||
694 | if (error) | ||
695 | goto cleanup; | ||
696 | lock_buffer(bs->bh); | ||
697 | error = ext4_xattr_set_entry(i, s); | 704 | error = ext4_xattr_set_entry(i, s); |
698 | if (!error) { | 705 | if (!error) { |
699 | if (!IS_LAST_ENTRY(s->first)) | 706 | if (!IS_LAST_ENTRY(s->first)) |
@@ -713,6 +720,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
713 | } else { | 720 | } else { |
714 | int offset = (char *)s->here - bs->bh->b_data; | 721 | int offset = (char *)s->here - bs->bh->b_data; |
715 | 722 | ||
723 | unlock_buffer(bs->bh); | ||
724 | jbd2_journal_release_buffer(handle, bs->bh); | ||
716 | if (ce) { | 725 | if (ce) { |
717 | mb_cache_entry_release(ce); | 726 | mb_cache_entry_release(ce); |
718 | ce = NULL; | 727 | ce = NULL; |