#include <linux/module.h>
#include <linux/fs.h>
#include <linux/time.h>
-#include <linux/ext4_jbd.h>
-#include <linux/jbd.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/jbd2.h>
#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
#include "xattr.h"
#include "acl.h"
-static int ext4_writepage_trans_blocks(struct inode *inode);
-
/*
* Test whether an inode is a fast symlink.
*/
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
(!is_metadata && !ext4_should_journal_data(inode))) {
if (bh) {
- BUFFER_TRACE(bh, "call journal_forget");
+ BUFFER_TRACE(bh, "call jbd2_journal_forget");
return ext4_journal_forget(handle, bh);
}
return 0;
failed:
/* Allocation failed, free what we already allocated */
for (i = 1; i <= n ; i++) {
- BUFFER_TRACE(branch[i].bh, "call journal_forget");
+ BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget");
ext4_journal_forget(handle, branch[i].bh);
}
for (i = 0; i <indirect_blks; i++)
err_out:
for (i = 1; i <= num; i++) {
- BUFFER_TRACE(where[i].bh, "call journal_forget");
+ BUFFER_TRACE(where[i].bh, "call jbd2_journal_forget");
ext4_journal_forget(handle, where[i].bh);
ext4_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1);
}
ext4_fsblk_t first_block = 0;
+ J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL));
J_ASSERT(handle != NULL || create == 0);
depth = ext4_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
get_block:
if (ret == 0) {
- ret = ext4_get_blocks_handle(handle, inode, iblock,
+ ret = ext4_get_blocks_wrap(handle, inode, iblock,
max_blocks, bh_result, create, 0);
if (ret > 0) {
bh_result->b_size = (ret << inode->i_blkbits);
dummy.b_state = 0;
dummy.b_blocknr = -1000;
buffer_trace_init(&dummy.b_history);
- err = ext4_get_blocks_handle(handle, inode, block, 1,
+ err = ext4_get_blocks_wrap(handle, inode, block, 1,
&dummy, create, 1);
/*
* ext4_get_blocks_handle() returns number of blocks
* To preserve ordering, it is essential that the hole instantiation and
* the data write be encapsulated in a single transaction. We cannot
* close off a transaction and start a new one between the ext4_get_block()
- * and the commit_write(). So doing the journal_start at the start of
+ * and the commit_write(). So doing the jbd2_journal_start at the start of
* prepare_write() is the right place.
*
* Also, this function can nest inside ext4_writepage() ->
* transaction open and was blocking on the quota lock - a ranking
* violation.
*
- * So what we do is to rely on the fact that journal_stop/journal_start
+ * So what we do is to rely on the fact that jbd2_journal_stop/journal_start
* will _not_ run commit under these circumstances because handle->h_ref
* is elevated. We'll still have enough credits for the tiny quotafile
* write.
return ext4_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 ext4_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 = ext4_journal_current_handle();
+
+ mapping = page->mapping;
+ if (ext4_should_writeback_data(mapping->host)) {
+ /* optimization: no constraints about data */
+skip:
+ return ext4_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 (ext4_should_journal_data(mapping->host)) {
+ ret = do_journal_get_write_access(handle, bh);
+ if (ret) {
+ ext4_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 ext4_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
struct inode *inode = page->mapping->host;
- int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
+ int ret, ret2;
+ int needed_blocks = ext4_writepage_trans_blocks(inode);
handle_t *handle;
int retries = 0;
retry:
handle = ext4_journal_start(inode, needed_blocks);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- goto out;
- }
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
ret = nobh_prepare_write(page, from, to, ext4_get_block);
else
ret = block_prepare_write(page, from, to, ext4_get_block);
if (ret)
- goto prepare_write_failed;
+ goto failure;
if (ext4_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 */
+ ext4_journal_stop(handle);
}
-prepare_write_failed:
- if (ret)
- ext4_journal_stop(handle);
+ return ret;
+
+failure:
+ ret2 = ext4_prepare_failure(file, page, from, to);
+ if (ret2 < 0)
+ return ret2;
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;
-out:
+ /* retry number exceeded, or other error like -EDQUOT */
return ret;
}
int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
{
- int err = journal_dirty_data(handle, bh);
+ int err = jbd2_journal_dirty_data(handle, bh);
if (err)
ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__,
bh, handle,err);
EXT4_I(inode)->i_state &= ~EXT4_STATE_JDATA;
journal = EXT4_JOURNAL(inode);
- journal_lock_updates(journal);
- err = journal_flush(journal);
- journal_unlock_updates(journal);
+ jbd2_journal_lock_updates(journal);
+ err = jbd2_journal_flush(journal);
+ jbd2_journal_unlock_updates(journal);
if (err)
return 0;
return 0;
}
-static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
+static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
{
if (buffer_mapped(bh))
return ext4_journal_dirty_data(handle, bh);
*/
if (ret == 0) {
err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
- NULL, journal_dirty_data_fn);
+ NULL, jbd2_journal_dirty_data_fn);
if (!ret)
ret = err;
}
if (offset == 0)
ClearPageChecked(page);
- journal_invalidatepage(journal, page, offset);
+ jbd2_journal_invalidatepage(journal, page, offset);
}
static int ext4_releasepage(struct page *page, gfp_t wait)
WARN_ON(PageChecked(page));
if (!page_has_buffers(page))
return 0;
- return journal_try_to_free_buffers(journal, page, wait);
+ return jbd2_journal_try_to_free_buffers(journal, page, wait);
}
/*
* This required during truncate. We need to physically zero the tail end
* of that block so it doesn't yield old data if the file is later grown.
*/
-static int ext4_block_truncate_page(handle_t *handle, struct page *page,
+int ext4_block_truncate_page(handle_t *handle, struct page *page,
struct address_space *mapping, loff_t from)
{
ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
/*
* Any buffers which are on the journal will be in memory. We find
- * them on the hash table so journal_revoke() will run journal_forget()
+ * them on the hash table so jbd2_journal_revoke() will run jbd2_journal_forget()
* on them. We've already detached each block from the file, so
- * bforget() in journal_forget() should be safe.
+ * bforget() in jbd2_journal_forget() should be safe.
*
- * AKPM: turn on bforget in journal_forget()!!!
+ * AKPM: turn on bforget in jbd2_journal_forget()!!!
*/
for (p = first; p < last; p++) {
u32 nr = le32_to_cpu(*p);
*/
if (!bh) {
ext4_error(inode->i_sb, "ext4_free_branches",
- "Read failure, inode=%lu, block="E3FSBLK,
+ "Read failure, inode=%lu, block=%llu",
inode->i_ino, nr);
continue;
}
* We've probably journalled the indirect block several
* times during the truncate. But it's no longer
* needed and we now drop it from the transaction via
- * journal_revoke().
+ * jbd2_journal_revoke().
*
* That's easy if it's exclusively part of this
* transaction. But if it's part of the committing
- * transaction then journal_forget() will simply
+ * transaction then jbd2_journal_forget() will simply
* brelse() it. That means that if the underlying
* block is reallocated in ext4_get_block(),
* unmap_underlying_metadata() will find this block
/*
* We have to lock the EOF page here, because lock_page() nests
- * outside journal_start().
+ * outside jbd2_journal_start().
*/
if ((inode->i_size & (blocksize - 1)) == 0) {
/* Block boundary? Nothing to do */
return;
}
+ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+ return ext4_ext_truncate(inode, page);
+
handle = start_transaction(inode);
if (IS_ERR(handle)) {
if (page) {
return 0;
}
- gdp = (struct ext4_group_desc *)bh->b_data;
+ gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data +
+ desc * EXT4_DESC_SIZE(sb));
/*
* Figure out the offset within the block group inode table
*/
offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
EXT4_INODE_SIZE(sb);
- block = le32_to_cpu(gdp[desc].bg_inode_table) +
+ block = ext4_inode_table(sb, gdp) +
(offset >> EXT4_BLOCK_SIZE_BITS(sb));
iloc->block_group = block_group;
if (!bh) {
ext4_error (inode->i_sb, "ext4_get_inode_loc",
"unable to read inode block - "
- "inode=%lu, block="E3FSBLK,
+ "inode=%lu, block=%llu",
inode->i_ino, block);
return -EIO;
}
goto make_io;
bitmap_bh = sb_getblk(inode->i_sb,
- le32_to_cpu(desc->bg_inode_bitmap));
+ ext4_inode_bitmap(inode->i_sb, desc));
if (!bitmap_bh)
goto make_io;
if (!buffer_uptodate(bh)) {
ext4_error(inode->i_sb, "ext4_get_inode_loc",
"unable to read inode block - "
- "inode=%lu, block="E3FSBLK,
+ "inode=%lu, block=%llu",
inode->i_ino, block);
brelse(bh);
return -EIO;
ei->i_frag_size = raw_inode->i_fsize;
#endif
ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+ cpu_to_le32(EXT4_OS_HURD))
+ ei->i_file_acl |=
+ ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
if (!S_ISREG(inode->i_mode)) {
ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
} else {
raw_inode->i_frag = ei->i_frag_no;
raw_inode->i_fsize = ei->i_frag_size;
#endif
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+ cpu_to_le32(EXT4_OS_HURD))
+ raw_inode->i_file_acl_high =
+ cpu_to_le16(ei->i_file_acl >> 32);
raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
if (!S_ISREG(inode->i_mode)) {
raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
* block and work out the exact number of indirects which are touched. Pah.
*/
-static int ext4_writepage_trans_blocks(struct inode *inode)
+int ext4_writepage_trans_blocks(struct inode *inode)
{
int bpp = ext4_journal_blocks_per_page(inode);
int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3;
int ret;
+ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+ return ext4_ext_writepage_trans_blocks(inode, bpp);
+
if (ext4_should_journal_data(inode))
ret = 3 * (bpp + indirects) + 2;
else
/* the do_update_inode consumes one bh->b_count */
get_bh(iloc->bh);
- /* ext4_do_update_inode() does journal_dirty_metadata */
+ /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */
err = ext4_do_update_inode(handle, inode, iloc);
put_bh(iloc->bh);
return err;
err = ext4_get_inode_loc(inode, &iloc);
if (!err) {
BUFFER_TRACE(iloc.bh, "get_write_access");
- err = journal_get_write_access(handle, iloc.bh);
+ err = jbd2_journal_get_write_access(handle, iloc.bh);
if (!err)
err = ext4_journal_dirty_metadata(handle,
iloc.bh);
if (is_journal_aborted(journal) || IS_RDONLY(inode))
return -EROFS;
- journal_lock_updates(journal);
- journal_flush(journal);
+ jbd2_journal_lock_updates(journal);
+ jbd2_journal_flush(journal);
/*
* OK, there are no updates running now, and all cached data is
EXT4_I(inode)->i_flags &= ~EXT4_JOURNAL_DATA_FL;
ext4_set_aops(inode);
- journal_unlock_updates(journal);
+ jbd2_journal_unlock_updates(journal);
/* Finally we can mark the inode as dirty. */