Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 139645
b: refs/heads/master
c: 695f6ae
h: refs/heads/master
i:
  139643: 7674fa5
v: v3
  • Loading branch information
Jan Kara authored and Linus Torvalds committed Apr 3, 2009
1 parent 3969f8d commit 8df1731
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 66 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: de18f3b2d68c1f3481839be760a5ff93f6a9a5e5
refs/heads/master: 695f6ae0dcea3dd83bfbb9634ff067f780649ba8
139 changes: 74 additions & 65 deletions trunk/fs/ext3/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1149,12 +1149,15 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping,
struct page **pagep, void **fsdata)
{
struct inode *inode = mapping->host;
int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
int ret;
handle_t *handle;
int retries = 0;
struct page *page;
pgoff_t index;
unsigned from, to;
/* Reserve one block more for addition to orphan list in case
* we allocate blocks but write fails for some reason */
int needed_blocks = ext3_writepage_trans_blocks(inode) + 1;

index = pos >> PAGE_CACHE_SHIFT;
from = pos & (PAGE_CACHE_SIZE - 1);
Expand Down Expand Up @@ -1184,14 +1187,19 @@ static int ext3_write_begin(struct file *file, struct address_space *mapping,
}
write_begin_failed:
if (ret) {
ext3_journal_stop(handle);
unlock_page(page);
page_cache_release(page);
/*
* block_write_begin may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex.
*
* Add inode to orphan list in case we crash before truncate
* finishes.
*/
if (pos + len > inode->i_size)
ext3_orphan_add(handle, inode);
ext3_journal_stop(handle);
unlock_page(page);
page_cache_release(page);
if (pos + len > inode->i_size)
vmtruncate(inode, inode->i_size);
}
Expand All @@ -1211,6 +1219,18 @@ int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
return err;
}

/* For ordered writepage and write_end functions */
static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
{
/*
* Write could have mapped the buffer but it didn't copy the data in
* yet. So avoid filing such buffer into a transaction.
*/
if (buffer_mapped(bh) && buffer_uptodate(bh))
return ext3_journal_dirty_data(handle, bh);
return 0;
}

/* For write_end() in data=journal mode */
static int write_end_fn(handle_t *handle, struct buffer_head *bh)
{
Expand All @@ -1221,26 +1241,20 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh)
}

/*
* Generic write_end handler for ordered and writeback ext3 journal modes.
* We can't use generic_write_end, because that unlocks the page and we need to
* unlock the page after ext3_journal_stop, but ext3_journal_stop must run
* after block_write_end.
* This is nasty and subtle: ext3_write_begin() could have allocated blocks
* for the whole page but later we failed to copy the data in. Update inode
* size according to what we managed to copy. The rest is going to be
* truncated in write_end function.
*/
static int ext3_generic_write_end(struct file *file,
struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
static void update_file_sizes(struct inode *inode, loff_t pos, unsigned copied)
{
struct inode *inode = file->f_mapping->host;

copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);

if (pos+copied > inode->i_size) {
i_size_write(inode, pos+copied);
/* What matters to us is i_disksize. We don't write i_size anywhere */
if (pos + copied > inode->i_size)
i_size_write(inode, pos + copied);
if (pos + copied > EXT3_I(inode)->i_disksize) {
EXT3_I(inode)->i_disksize = pos + copied;
mark_inode_dirty(inode);
}

return copied;
}

/*
Expand All @@ -1260,35 +1274,29 @@ static int ext3_ordered_write_end(struct file *file,
unsigned from, to;
int ret = 0, ret2;

from = pos & (PAGE_CACHE_SIZE - 1);
to = from + len;
copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);

from = pos & (PAGE_CACHE_SIZE - 1);
to = from + copied;
ret = walk_page_buffers(handle, page_buffers(page),
from, to, NULL, ext3_journal_dirty_data);
from, to, NULL, journal_dirty_data_fn);

if (ret == 0) {
/*
* generic_write_end() will run mark_inode_dirty() if i_size
* changes. So let's piggyback the i_disksize mark_inode_dirty
* into that.
*/
loff_t new_i_size;

new_i_size = pos + copied;
if (new_i_size > EXT3_I(inode)->i_disksize)
EXT3_I(inode)->i_disksize = new_i_size;
ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
copied = ret2;
if (ret2 < 0)
ret = ret2;
}
if (ret == 0)
update_file_sizes(inode, pos, copied);
/*
* There may be allocated blocks outside of i_size because
* we failed to copy some data. Prepare for truncate.
*/
if (pos + len > inode->i_size)
ext3_orphan_add(handle, inode);
ret2 = ext3_journal_stop(handle);
if (!ret)
ret = ret2;
unlock_page(page);
page_cache_release(page);

if (pos + len > inode->i_size)
vmtruncate(inode, inode->i_size);
return ret ? ret : copied;
}

Expand All @@ -1299,25 +1307,22 @@ static int ext3_writeback_write_end(struct file *file,
{
handle_t *handle = ext3_journal_current_handle();
struct inode *inode = file->f_mapping->host;
int ret = 0, ret2;
loff_t new_i_size;

new_i_size = pos + copied;
if (new_i_size > EXT3_I(inode)->i_disksize)
EXT3_I(inode)->i_disksize = new_i_size;

ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
copied = ret2;
if (ret2 < 0)
ret = ret2;
int ret;

ret2 = ext3_journal_stop(handle);
if (!ret)
ret = ret2;
copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
update_file_sizes(inode, pos, copied);
/*
* There may be allocated blocks outside of i_size because
* we failed to copy some data. Prepare for truncate.
*/
if (pos + len > inode->i_size)
ext3_orphan_add(handle, inode);
ret = ext3_journal_stop(handle);
unlock_page(page);
page_cache_release(page);

if (pos + len > inode->i_size)
vmtruncate(inode, inode->i_size);
return ret ? ret : copied;
}

Expand All @@ -1338,15 +1343,23 @@ static int ext3_journalled_write_end(struct file *file,
if (copied < len) {
if (!PageUptodate(page))
copied = 0;
page_zero_new_buffers(page, from+copied, to);
page_zero_new_buffers(page, from + copied, to);
to = from + copied;
}

ret = walk_page_buffers(handle, page_buffers(page), from,
to, &partial, write_end_fn);
if (!partial)
SetPageUptodate(page);
if (pos+copied > inode->i_size)
i_size_write(inode, pos+copied);

if (pos + copied > inode->i_size)
i_size_write(inode, pos + copied);
/*
* There may be allocated blocks outside of i_size because
* we failed to copy some data. Prepare for truncate.
*/
if (pos + len > inode->i_size)
ext3_orphan_add(handle, inode);
EXT3_I(inode)->i_state |= EXT3_STATE_JDATA;
if (inode->i_size > EXT3_I(inode)->i_disksize) {
EXT3_I(inode)->i_disksize = inode->i_size;
Expand All @@ -1361,6 +1374,8 @@ static int ext3_journalled_write_end(struct file *file,
unlock_page(page);
page_cache_release(page);

if (pos + len > inode->i_size)
vmtruncate(inode, inode->i_size);
return ret ? ret : copied;
}

Expand Down Expand Up @@ -1428,17 +1443,11 @@ static int bput_one(handle_t *handle, struct buffer_head *bh)
return 0;
}

static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
{
if (buffer_mapped(bh))
return ext3_journal_dirty_data(handle, bh);
return 0;
}

static int buffer_unmapped(handle_t *handle, struct buffer_head *bh)
{
return !buffer_mapped(bh);
}

/*
* Note that we always start a transaction even if we're not journalling
* data. This is to preserve ordering: any hole instantiation within
Expand Down

0 comments on commit 8df1731

Please sign in to comment.