diff options
Diffstat (limited to 'fs/ext3')
-rw-r--r-- | fs/ext3/balloc.c | 2 | ||||
-rw-r--r-- | fs/ext3/inode.c | 85 | ||||
-rw-r--r-- | fs/ext3/xattr.c | 43 |
3 files changed, 38 insertions, 92 deletions
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 22161740ba29..ca8aee6efe37 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -32,7 +32,7 @@ * The file system contains group descriptors which are located after the * super block. Each descriptor contains the number of the bitmap block and * the free blocks count in the block. The descriptors are loaded in memory - * when a file system is mounted (see ext3_read_super). + * when a file system is mounted (see ext3_fill_super). */ diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 8a824f4ce5c6..a5b150f7e8a2 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1148,102 +1148,37 @@ static int do_journal_get_write_access(handle_t *handle, return ext3_journal_get_write_access(handle, bh); } -/* - * The idea of this helper function is following: - * if prepare_write has allocated some blocks, but not all of them, the - * transaction must include the content of the newly allocated blocks. - * This content is expected to be set to zeroes by block_prepare_write(). - * 2006/10/14 SAW - */ -static int ext3_prepare_failure(struct file *file, struct page *page, - unsigned from, unsigned to) -{ - struct address_space *mapping; - struct buffer_head *bh, *head, *next; - unsigned block_start, block_end; - unsigned blocksize; - int ret; - handle_t *handle = ext3_journal_current_handle(); - - mapping = page->mapping; - if (ext3_should_writeback_data(mapping->host)) { - /* optimization: no constraints about data */ -skip: - return ext3_journal_stop(handle); - } - - head = page_buffers(page); - blocksize = head->b_size; - for ( bh = head, block_start = 0; - bh != head || !block_start; - block_start = block_end, bh = next) - { - next = bh->b_this_page; - block_end = block_start + blocksize; - if (block_end <= from) - continue; - if (block_start >= to) { - block_start = to; - break; - } - if (!buffer_mapped(bh)) - /* prepare_write failed on this bh */ - break; - if (ext3_should_journal_data(mapping->host)) { - ret = do_journal_get_write_access(handle, bh); - if (ret) { - ext3_journal_stop(handle); - return ret; - } - } - /* - * block_start here becomes the first block where the current iteration - * of prepare_write failed. - */ - } - if (block_start <= from) - goto skip; - - /* commit allocated and zeroed buffers */ - return mapping->a_ops->commit_write(file, page, from, block_start); -} - static int ext3_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { struct inode *inode = page->mapping->host; - int ret, ret2; - int needed_blocks = ext3_writepage_trans_blocks(inode); + int ret, needed_blocks = ext3_writepage_trans_blocks(inode); handle_t *handle; int retries = 0; retry: handle = ext3_journal_start(inode, needed_blocks); - if (IS_ERR(handle)) - return PTR_ERR(handle); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode)) ret = nobh_prepare_write(page, from, to, ext3_get_block); else ret = block_prepare_write(page, from, to, ext3_get_block); if (ret) - goto failure; + goto prepare_write_failed; if (ext3_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, do_journal_get_write_access); - if (ret) - /* fatal error, just put the handle and return */ - journal_stop(handle); } - return ret; - -failure: - ret2 = ext3_prepare_failure(file, page, from, to); - if (ret2 < 0) - return ret2; +prepare_write_failed: + if (ret) + ext3_journal_stop(handle); if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; - /* retry number exceeded, or other error like -EDQUOT */ +out: return ret; } diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 99857a400f4b..f58cbb26323e 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c @@ -475,8 +475,15 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode, struct buffer_head *bh) { struct mb_cache_entry *ce = NULL; + int error = 0; ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr); + error = ext3_journal_get_write_access(handle, bh); + if (error) + goto out; + + lock_buffer(bh); + if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { ea_bdebug(bh, "refcount now=0; freeing"); if (ce) @@ -485,21 +492,21 @@ ext3_xattr_release_block(handle_t *handle, struct inode *inode, get_bh(bh); ext3_forget(handle, 1, inode, bh, bh->b_blocknr); } else { - if (ext3_journal_get_write_access(handle, bh) == 0) { - lock_buffer(bh); - BHDR(bh)->h_refcount = cpu_to_le32( + BHDR(bh)->h_refcount = cpu_to_le32( le32_to_cpu(BHDR(bh)->h_refcount) - 1); - ext3_journal_dirty_metadata(handle, bh); - if (IS_SYNC(inode)) - handle->h_sync = 1; - DQUOT_FREE_BLOCK(inode, 1); - unlock_buffer(bh); - ea_bdebug(bh, "refcount now=%d; releasing", - le32_to_cpu(BHDR(bh)->h_refcount)); - } + error = ext3_journal_dirty_metadata(handle, bh); + if (IS_SYNC(inode)) + handle->h_sync = 1; + DQUOT_FREE_BLOCK(inode, 1); + ea_bdebug(bh, "refcount now=%d; releasing", + le32_to_cpu(BHDR(bh)->h_refcount)); if (ce) mb_cache_entry_release(ce); } + unlock_buffer(bh); +out: + ext3_std_error(inode->i_sb, error); + return; } struct ext3_xattr_info { @@ -675,7 +682,7 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, struct buffer_head *new_bh = NULL; struct ext3_xattr_search *s = &bs->s; struct mb_cache_entry *ce = NULL; - int error; + int error = 0; #define header(x) ((struct ext3_xattr_header *)(x)) @@ -684,16 +691,17 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, if (s->base) { ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev, bs->bh->b_blocknr); + error = ext3_journal_get_write_access(handle, bs->bh); + if (error) + goto cleanup; + lock_buffer(bs->bh); + if (header(s->base)->h_refcount == cpu_to_le32(1)) { if (ce) { mb_cache_entry_free(ce); ce = NULL; } ea_bdebug(bs->bh, "modifying in-place"); - error = ext3_journal_get_write_access(handle, bs->bh); - if (error) - goto cleanup; - lock_buffer(bs->bh); error = ext3_xattr_set_entry(i, s); if (!error) { if (!IS_LAST_ENTRY(s->first)) @@ -713,6 +721,9 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, } else { int offset = (char *)s->here - bs->bh->b_data; + unlock_buffer(bs->bh); + journal_release_buffer(handle, bs->bh); + if (ce) { mb_cache_entry_release(ce); ce = NULL; |