Commit 0390131b authored by Frank Mayhar's avatar Frank Mayhar Committed by Theodore Ts'o

ext4: Allow ext4 to run without a journal

A few weeks ago I posted a patch for discussion that allowed ext4 to run
without a journal.  Since that time I've integrated the excellent
comments from Andreas and fixed several serious bugs.  We're currently
running with this patch and generating some performance numbers against
both ext2 (with backported reservations code) and ext4 with and without
a journal.  It just so happens that running without a journal is
slightly faster for most everything.

We did
	iozone -T -t 4 s 2g -r 256k -T -I -i0 -i1 -i2

which creates 4 threads, each of which create and do reads and writes on
a 2G file, with a buffer size of 256K, using O_DIRECT for all file opens
to bypass the page cache.  Results:

                     ext2        ext4, default   ext4, no journal
  initial writes   13.0 MB/s        15.4 MB/s          15.7 MB/s
  rewrites         13.1 MB/s        15.6 MB/s          15.9 MB/s
  reads            15.2 MB/s        16.9 MB/s          17.2 MB/s
  re-reads         15.3 MB/s        16.9 MB/s          17.2 MB/s
  random readers    5.6 MB/s         5.6 MB/s           5.7 MB/s
  random writers    5.1 MB/s         5.3 MB/s           5.4 MB/s 

So it seems that, so far, this was a useful exercise.
Signed-off-by: default avatarFrank Mayhar <fmayhar@google.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent ff7ef329
...@@ -531,11 +531,11 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb, ...@@ -531,11 +531,11 @@ void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
/* We dirtied the bitmap block */ /* We dirtied the bitmap block */
BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
err = ext4_journal_dirty_metadata(handle, bitmap_bh); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
/* And the group descriptor block */ /* And the group descriptor block */
BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
ret = ext4_journal_dirty_metadata(handle, gd_bh); ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);
if (!err) err = ret; if (!err) err = ret;
*pdquot_freed_blocks += group_freed; *pdquot_freed_blocks += group_freed;
......
...@@ -7,53 +7,96 @@ ...@@ -7,53 +7,96 @@
int __ext4_journal_get_undo_access(const char *where, handle_t *handle, int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
struct buffer_head *bh) struct buffer_head *bh)
{ {
int err = jbd2_journal_get_undo_access(handle, bh); int err = 0;
if (err)
ext4_journal_abort_handle(where, __func__, bh, handle, err); if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_undo_access(handle, bh);
if (err)
ext4_journal_abort_handle(where, __func__, bh,
handle, err);
}
return err; return err;
} }
int __ext4_journal_get_write_access(const char *where, handle_t *handle, int __ext4_journal_get_write_access(const char *where, handle_t *handle,
struct buffer_head *bh) struct buffer_head *bh)
{ {
int err = jbd2_journal_get_write_access(handle, bh); int err = 0;
if (err)
ext4_journal_abort_handle(where, __func__, bh, handle, err); if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_write_access(handle, bh);
if (err)
ext4_journal_abort_handle(where, __func__, bh,
handle, err);
}
return err; return err;
} }
int __ext4_journal_forget(const char *where, handle_t *handle, int __ext4_journal_forget(const char *where, handle_t *handle,
struct buffer_head *bh) struct buffer_head *bh)
{ {
int err = jbd2_journal_forget(handle, bh); int err = 0;
if (err)
ext4_journal_abort_handle(where, __func__, bh, handle, err); if (ext4_handle_valid(handle)) {
err = jbd2_journal_forget(handle, bh);
if (err)
ext4_journal_abort_handle(where, __func__, bh,
handle, err);
}
return err; return err;
} }
int __ext4_journal_revoke(const char *where, handle_t *handle, int __ext4_journal_revoke(const char *where, handle_t *handle,
ext4_fsblk_t blocknr, struct buffer_head *bh) ext4_fsblk_t blocknr, struct buffer_head *bh)
{ {
int err = jbd2_journal_revoke(handle, blocknr, bh); int err = 0;
if (err)
ext4_journal_abort_handle(where, __func__, bh, handle, err); if (ext4_handle_valid(handle)) {
err = jbd2_journal_revoke(handle, blocknr, bh);
if (err)
ext4_journal_abort_handle(where, __func__, bh,
handle, err);
}
return err; return err;
} }
int __ext4_journal_get_create_access(const char *where, int __ext4_journal_get_create_access(const char *where,
handle_t *handle, struct buffer_head *bh) handle_t *handle, struct buffer_head *bh)
{ {
int err = jbd2_journal_get_create_access(handle, bh); int err = 0;
if (err)
ext4_journal_abort_handle(where, __func__, bh, handle, err); if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_create_access(handle, bh);
if (err)
ext4_journal_abort_handle(where, __func__, bh,
handle, err);
}
return err; return err;
} }
int __ext4_journal_dirty_metadata(const char *where, int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
handle_t *handle, struct buffer_head *bh) struct inode *inode, struct buffer_head *bh)
{ {
int err = jbd2_journal_dirty_metadata(handle, bh); int err = 0;
if (err)
ext4_journal_abort_handle(where, __func__, bh, handle, err); if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
if (err)
ext4_journal_abort_handle(where, __func__, bh,
handle, err);
} else {
mark_buffer_dirty(bh);
if (inode && inode_needs_sync(inode)) {
sync_dirty_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh)) {
ext4_error(inode->i_sb, __func__,
"IO error syncing inode, "
"inode=%lu, block=%llu",
inode->i_ino,
(unsigned long long) bh->b_blocknr);
err = -EIO;
}
}
}
return err; return err;
} }
...@@ -122,12 +122,6 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); ...@@ -122,12 +122,6 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
* been done yet. * been done yet.
*/ */
static inline void ext4_journal_release_buffer(handle_t *handle,
struct buffer_head *bh)
{
jbd2_journal_release_buffer(handle, bh);
}
void ext4_journal_abort_handle(const char *caller, const char *err_fn, void ext4_journal_abort_handle(const char *caller, const char *err_fn,
struct buffer_head *bh, handle_t *handle, int err); struct buffer_head *bh, handle_t *handle, int err);
...@@ -146,8 +140,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle, ...@@ -146,8 +140,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle,
int __ext4_journal_get_create_access(const char *where, int __ext4_journal_get_create_access(const char *where,
handle_t *handle, struct buffer_head *bh); handle_t *handle, struct buffer_head *bh);
int __ext4_journal_dirty_metadata(const char *where, int __ext4_handle_dirty_metadata(const char *where, handle_t *handle,
handle_t *handle, struct buffer_head *bh); struct inode *inode, struct buffer_head *bh);
#define ext4_journal_get_undo_access(handle, bh) \ #define ext4_journal_get_undo_access(handle, bh) \
__ext4_journal_get_undo_access(__func__, (handle), (bh)) __ext4_journal_get_undo_access(__func__, (handle), (bh))
...@@ -157,14 +151,57 @@ int __ext4_journal_dirty_metadata(const char *where, ...@@ -157,14 +151,57 @@ int __ext4_journal_dirty_metadata(const char *where,
__ext4_journal_revoke(__func__, (handle), (blocknr), (bh)) __ext4_journal_revoke(__func__, (handle), (blocknr), (bh))
#define ext4_journal_get_create_access(handle, bh) \ #define ext4_journal_get_create_access(handle, bh) \
__ext4_journal_get_create_access(__func__, (handle), (bh)) __ext4_journal_get_create_access(__func__, (handle), (bh))
#define ext4_journal_dirty_metadata(handle, bh) \
__ext4_journal_dirty_metadata(__func__, (handle), (bh))
#define ext4_journal_forget(handle, bh) \ #define ext4_journal_forget(handle, bh) \
__ext4_journal_forget(__func__, (handle), (bh)) __ext4_journal_forget(__func__, (handle), (bh))
#define ext4_handle_dirty_metadata(handle, inode, bh) \
__ext4_handle_dirty_metadata(__func__, (handle), (inode), (bh))
handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
int __ext4_journal_stop(const char *where, handle_t *handle); int __ext4_journal_stop(const char *where, handle_t *handle);
#define EXT4_NOJOURNAL_HANDLE ((handle_t *) 0x1)
static inline int ext4_handle_valid(handle_t *handle)
{
if (handle == EXT4_NOJOURNAL_HANDLE)
return 0;
return 1;
}
static inline void ext4_handle_sync(handle_t *handle)
{
if (ext4_handle_valid(handle))
handle->h_sync = 1;
}
static inline void ext4_handle_release_buffer(handle_t *handle,
struct buffer_head *bh)
{
if (ext4_handle_valid(handle))
jbd2_journal_release_buffer(handle, bh);
}
static inline int ext4_handle_is_aborted(handle_t *handle)
{
if (ext4_handle_valid(handle))
return is_handle_aborted(handle);
return 0;
}
static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed)
{
if (ext4_handle_valid(handle) && handle->h_buffer_credits < needed)
return 0;
return 1;
}
static inline void ext4_journal_release_buffer(handle_t *handle,
struct buffer_head *bh)
{
if (ext4_handle_valid(handle))
jbd2_journal_release_buffer(handle, bh);
}
static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks) static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
{ {
return ext4_journal_start_sb(inode->i_sb, nblocks); return ext4_journal_start_sb(inode->i_sb, nblocks);
...@@ -180,27 +217,37 @@ static inline handle_t *ext4_journal_current_handle(void) ...@@ -180,27 +217,37 @@ static inline handle_t *ext4_journal_current_handle(void)
static inline int ext4_journal_extend(handle_t *handle, int nblocks) static inline int ext4_journal_extend(handle_t *handle, int nblocks)
{ {
return jbd2_journal_extend(handle, nblocks); if (ext4_handle_valid(handle))
return jbd2_journal_extend(handle, nblocks);
return 0;
} }
static inline int ext4_journal_restart(handle_t *handle, int nblocks) static inline int ext4_journal_restart(handle_t *handle, int nblocks)
{ {
return jbd2_journal_restart(handle, nblocks); if (ext4_handle_valid(handle))
return jbd2_journal_restart(handle, nblocks);
return 0;
} }
static inline int ext4_journal_blocks_per_page(struct inode *inode) static inline int ext4_journal_blocks_per_page(struct inode *inode)
{ {
return jbd2_journal_blocks_per_page(inode); if (EXT4_JOURNAL(inode) != NULL)
return jbd2_journal_blocks_per_page(inode);
return 0;
} }
static inline int ext4_journal_force_commit(journal_t *journal) static inline int ext4_journal_force_commit(journal_t *journal)
{ {
return jbd2_journal_force_commit(journal); if (journal)
return jbd2_journal_force_commit(journal);
return 0;
} }
static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode) static inline int ext4_jbd2_file_inode(handle_t *handle, struct inode *inode)
{ {
return jbd2_journal_file_inode(handle, &EXT4_I(inode)->jinode); if (ext4_handle_valid(handle))
return jbd2_journal_file_inode(handle, &EXT4_I(inode)->jinode);
return 0;
} }
/* super.c */ /* super.c */
...@@ -208,6 +255,8 @@ int ext4_force_commit(struct super_block *sb); ...@@ -208,6 +255,8 @@ int ext4_force_commit(struct super_block *sb);
static inline int ext4_should_journal_data(struct inode *inode) static inline int ext4_should_journal_data(struct inode *inode)
{ {
if (EXT4_JOURNAL(inode) == NULL)
return 0;
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return 1; return 1;
if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
...@@ -219,6 +268,8 @@ static inline int ext4_should_journal_data(struct inode *inode) ...@@ -219,6 +268,8 @@ static inline int ext4_should_journal_data(struct inode *inode)
static inline int ext4_should_order_data(struct inode *inode) static inline int ext4_should_order_data(struct inode *inode)
{ {
if (EXT4_JOURNAL(inode) == NULL)
return 0;
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return 0; return 0;
if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
...@@ -230,6 +281,8 @@ static inline int ext4_should_order_data(struct inode *inode) ...@@ -230,6 +281,8 @@ static inline int ext4_should_order_data(struct inode *inode)
static inline int ext4_should_writeback_data(struct inode *inode) static inline int ext4_should_writeback_data(struct inode *inode)
{ {
if (EXT4_JOURNAL(inode) == NULL)
return 0;
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return 0; return 0;
if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
......
...@@ -97,6 +97,8 @@ static int ext4_ext_journal_restart(handle_t *handle, int needed) ...@@ -97,6 +97,8 @@ static int ext4_ext_journal_restart(handle_t *handle, int needed)
{ {
int err; int err;
if (!ext4_handle_valid(handle))
return 0;
if (handle->h_buffer_credits > needed) if (handle->h_buffer_credits > needed)
return 0; return 0;
err = ext4_journal_extend(handle, needed); err = ext4_journal_extend(handle, needed);
...@@ -134,7 +136,7 @@ static int ext4_ext_dirty(handle_t *handle, struct inode *inode, ...@@ -134,7 +136,7 @@ static int ext4_ext_dirty(handle_t *handle, struct inode *inode,
int err; int err;
if (path->p_bh) { if (path->p_bh) {
/* path points to block */ /* path points to block */
err = ext4_journal_dirty_metadata(handle, path->p_bh); err = ext4_handle_dirty_metadata(handle, inode, path->p_bh);
} else { } else {
/* path points to leaf/index in inode body */ /* path points to leaf/index in inode body */
err = ext4_mark_inode_dirty(handle, inode); err = ext4_mark_inode_dirty(handle, inode);
...@@ -780,7 +782,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, ...@@ -780,7 +782,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
if (err) if (err)
goto cleanup; goto cleanup;
brelse(bh); brelse(bh);
...@@ -859,7 +861,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, ...@@ -859,7 +861,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
if (err) if (err)
goto cleanup; goto cleanup;
brelse(bh); brelse(bh);
...@@ -955,7 +957,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, ...@@ -955,7 +957,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
if (err) if (err)
goto out; goto out;
...@@ -2947,7 +2949,7 @@ void ext4_ext_truncate(struct inode *inode) ...@@ -2947,7 +2949,7 @@ void ext4_ext_truncate(struct inode *inode)
* transaction synchronous. * transaction synchronous.
*/ */
if (IS_SYNC(inode)) if (IS_SYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
out_stop: out_stop:
up_write(&EXT4_I(inode)->i_data_sem); up_write(&EXT4_I(inode)->i_data_sem);
......
...@@ -253,12 +253,12 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) ...@@ -253,12 +253,12 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
spin_unlock(sb_bgl_lock(sbi, flex_group)); spin_unlock(sb_bgl_lock(sbi, flex_group));
} }
} }
BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, bh2); err = ext4_handle_dirty_metadata(handle, NULL, bh2);
if (!fatal) fatal = err; if (!fatal) fatal = err;
} }
BUFFER_TRACE(bitmap_bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, bitmap_bh); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
if (!fatal) if (!fatal)
fatal = err; fatal = err;
sb->s_dirt = 1; sb->s_dirt = 1;
...@@ -656,15 +656,16 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) ...@@ -656,15 +656,16 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
ino, bitmap_bh->b_data)) { ino, bitmap_bh->b_data)) {
/* we won it */ /* we won it */
BUFFER_TRACE(bitmap_bh, BUFFER_TRACE(bitmap_bh,
"call ext4_journal_dirty_metadata"); "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, err = ext4_handle_dirty_metadata(handle,
inode,
bitmap_bh); bitmap_bh);
if (err) if (err)
goto fail; goto fail;
goto got; goto got;
} }
/* we lost it */ /* we lost it */
jbd2_journal_release_buffer(handle, bitmap_bh); ext4_handle_release_buffer(handle, bitmap_bh);
if (++ino < EXT4_INODES_PER_GROUP(sb)) if (++ino < EXT4_INODES_PER_GROUP(sb))
goto repeat_in_this_group; goto repeat_in_this_group;
...@@ -726,7 +727,8 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) ...@@ -726,7 +727,8 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
/* Don't need to dirty bitmap block if we didn't change it */ /* Don't need to dirty bitmap block if we didn't change it */
if (free) { if (free) {
BUFFER_TRACE(block_bh, "dirty block bitmap"); BUFFER_TRACE(block_bh, "dirty block bitmap");
err = ext4_journal_dirty_metadata(handle, block_bh); err = ext4_handle_dirty_metadata(handle,
NULL, block_bh);
} }
brelse(block_bh); brelse(block_bh);
...@@ -771,8 +773,8 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) ...@@ -771,8 +773,8 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
} }
gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
spin_unlock(sb_bgl_lock(sbi, group)); spin_unlock(sb_bgl_lock(sbi, group));
BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, bh2); err = ext4_handle_dirty_metadata(handle, NULL, bh2);
if (err) goto fail; if (err) goto fail;
percpu_counter_dec(&sbi->s_freeinodes_counter); percpu_counter_dec(&sbi->s_freeinodes_counter);
...@@ -825,7 +827,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) ...@@ -825,7 +827,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
ext4_set_inode_flags(inode); ext4_set_inode_flags(inode);
if (IS_DIRSYNC(inode)) if (IS_DIRSYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
if (insert_inode_locked(inode) < 0) { if (insert_inode_locked(inode) < 0) {
err = -EINVAL; err = -EINVAL;
goto fail_drop; goto fail_drop;
...@@ -1028,4 +1030,3 @@ unsigned long ext4_count_dirs(struct super_block * sb) ...@@ -1028,4 +1030,3 @@ unsigned long ext4_count_dirs(struct super_block * sb)
} }
return count; return count;
} }
...@@ -72,12 +72,17 @@ static int ext4_inode_is_fast_symlink(struct inode *inode) ...@@ -72,12 +72,17 @@ static int ext4_inode_is_fast_symlink(struct inode *inode)
* "bh" may be NULL: a metadata block may have been freed from memory * "bh" may be NULL: a metadata block may have been freed from memory
* but there may still be a record of it in the journal, and that record * but there may still be a record of it in the journal, and that record
* still needs to be revoked. * still needs to be revoked.
*
* If the handle isn't valid we're not journaling so there's nothing to do.
*/ */
int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
struct buffer_head *bh, ext4_fsblk_t blocknr) struct buffer_head *bh, ext4_fsblk_t blocknr)
{ {
int err; int err;
if (!ext4_handle_valid(handle))
return 0;
might_sleep(); might_sleep();
BUFFER_TRACE(bh, "enter"); BUFFER_TRACE(bh, "enter");
...@@ -170,7 +175,9 @@ static handle_t *start_transaction(struct inode *inode) ...@@ -170,7 +175,9 @@ static handle_t *start_transaction(struct inode *inode)
*/ */
static int try_to_extend_transaction(handle_t *handle, struct inode *inode) static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
{ {
if (handle->h_buffer_credits > EXT4_RESERVE_TRANS_BLOCKS) if (!ext4_handle_valid(handle))
return 0;
if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
return 0; return 0;
if (!ext4_journal_extend(handle, blocks_for_truncate(inode))) if (!ext4_journal_extend(handle, blocks_for_truncate(inode)))
return 0; return 0;
...@@ -184,6 +191,7 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) ...@@ -184,6 +191,7 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
*/ */
static int ext4_journal_test_restart(handle_t *handle, struct inode *inode) static int ext4_journal_test_restart(handle_t *handle, struct inode *inode)
{ {
BUG_ON(EXT4_JOURNAL(inode) == NULL);
jbd_debug(2, "restarting handle %p\n", handle); jbd_debug(2, "restarting handle %p\n", handle);
return ext4_journal_restart(handle, blocks_for_truncate(inode)); return ext4_journal_restart(handle, blocks_for_truncate(inode));
} }
...@@ -216,7 +224,7 @@ void ext4_delete_inode(struct inode *inode) ...@@ -216,7 +224,7 @@ void ext4_delete_inode(struct inode *inode)
} }
if (IS_SYNC(inode)) if (IS_SYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
inode->i_size = 0; inode->i_size = 0;
err = ext4_mark_inode_dirty(handle, inode); err = ext4_mark_inode_dirty(handle, inode);
if (err) { if (err) {
...@@ -233,7 +241,7 @@ void ext4_delete_inode(struct inode *inode) ...@@ -233,7 +241,7 @@ void ext4_delete_inode(struct inode *inode)
* enough credits left in the handle to remove the inode from * enough credits left in the handle to remove the inode from
* the orphan list and set the dtime field. * the orphan list and set the dtime field.
*/ */
if (handle->h_buffer_credits < 3) { if (!ext4_handle_has_enough_credits(handle, 3)) {
err = ext4_journal_extend(handle, 3); err = ext4_journal_extend(handle, 3);
if (err > 0) if (err > 0)
err = ext4_journal_restart(handle, 3); err = ext4_journal_restart(handle, 3);
...@@ -717,8 +725,8 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -717,8 +725,8 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
if (err) if (err)
goto failed; goto failed;
} }
...@@ -800,8 +808,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, ...@@ -800,8 +808,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
* generic_commit_write->__mark_inode_dirty->ext4_dirty_inode. * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode.
*/ */
jbd_debug(5, "splicing indirect only\n"); jbd_debug(5, "splicing indirect only\n");
BUFFER_TRACE(where->bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, where->bh); err = ext4_handle_dirty_metadata(handle, inode, where->bh);
if (err) if (err)
goto err_out; goto err_out;
} else { } else {
...@@ -1229,8 +1237,8 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, ...@@ -1229,8 +1237,8 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
} }
unlock_buffer(bh); unlock_buffer(bh);
BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
if (!fatal) if (!fatal)
fatal = err; fatal = err;
} else { } else {
...@@ -1395,7 +1403,7 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh) ...@@ -1395,7 +1403,7 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh)
if (!buffer_mapped(bh) || buffer_freed(bh)) if (!buffer_mapped(bh) || buffer_freed(bh))
return 0; return 0;
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
return ext4_journal_dirty_metadata(handle, bh); return ext4_handle_dirty_metadata(handle, NULL, bh);
} }
/* /*
...@@ -2762,7 +2770,10 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) ...@@ -2762,7 +2770,10 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
filemap_write_and_wait(mapping); filemap_write_and_wait(mapping);
} }
if (EXT4_I(inode)->i_state & EXT4_STATE_JDATA) { BUG_ON(!EXT4_JOURNAL(inode) &&
EXT4_I(inode)->i_state & EXT4_STATE_JDATA);
if (EXT4_JOURNAL(inode) && EXT4_I(inode)->i_state & EXT4_STATE_JDATA) {
/* /*
* This is a REALLY heavyweight approach, but the use of * This is a REALLY heavyweight approach, but the use of
* bmap on dirty files is expected to be extremely rare: * bmap on dirty files is expected to be extremely rare:
...@@ -3033,7 +3044,10 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset) ...@@ -3033,7 +3044,10 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset)
if (offset == 0) if (offset == 0)
ClearPageChecked(page); ClearPageChecked(page);
jbd2_journal_invalidatepage(journal, page, offset); if (journal)
jbd2_journal_invalidatepage(journal, page, offset);
else
block_invalidatepage(page, offset);
} }
static int ext4_releasepage(struct page *page, gfp_t wait) static int ext4_releasepage(struct page *page, gfp_t wait)
...@@ -3043,7 +3057,10 @@ static int ext4_releasepage(struct page *page, gfp_t wait) ...@@ -3043,7 +3057,10 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
WARN_ON(PageChecked(page)); WARN_ON(PageChecked(page));
if (!page_has_buffers(page)) if (!page_has_buffers(page))
return 0; return 0;
return jbd2_journal_try_to_free_buffers(journal, page, wait); if (journal)
return jbd2_journal_try_to_free_buffers(journal, page, wait);
else
return try_to_free_buffers(page);
} }
/* /*
...@@ -3315,7 +3332,7 @@ int ext4_block_truncate_page(handle_t *handle, ...@@ -3315,7 +3332,7 @@ int ext4_block_truncate_page(handle_t *handle,
err = 0; err = 0;
if (ext4_should_journal_data(inode)) { if (ext4_should_journal_data(inode)) {
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, inode, bh);
} else { } else {
if (ext4_should_order_data(inode)) if (ext4_should_order_data(inode))
err = ext4_jbd2_file_inode(handle, inode); err = ext4_jbd2_file_inode(handle, inode);
...@@ -3439,8 +3456,8 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, ...@@ -3439,8 +3456,8 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
__le32 *p; __le32 *p;
if (try_to_extend_transaction(handle, inode)) { if (try_to_extend_transaction(handle, inode)) {
if (bh) { if (bh) {
BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
ext4_journal_dirty_metadata(handle, bh); ext4_handle_dirty_metadata(handle, inode, bh);
} }
ext4_mark_inode_dirty(handle, inode); ext4_mark_inode_dirty(handle, inode);
ext4_journal_test_restart(handle, inode); ext4_journal_test_restart(handle, inode);
...@@ -3540,7 +3557,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, ...@@ -3540,7 +3557,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
count, block_to_free_p, p); count, block_to_free_p, p);
if (this_bh) { if (this_bh) {
BUFFER_TRACE(this_bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata");
/* /*
* The buffer head should have an attached journal head at this * The buffer head should have an attached journal head at this
...@@ -3549,7 +3566,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode, ...@@ -3549,7 +3566,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
* the block was cleared. Check for this instead of OOPSing. * the block was cleared. Check for this instead of OOPSing.
*/ */
if (bh2jh(this_bh)) if (bh2jh(this_bh))
ext4_journal_dirty_metadata(handle, this_bh); ext4_handle_dirty_metadata(handle, inode, this_bh);
else else
ext4_error(inode->i_sb, __func__, ext4_error(inode->i_sb, __func__,
"circular indirect block detected, " "circular indirect block detected, "
...@@ -3579,7 +3596,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, ...@@ -3579,7 +3596,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
ext4_fsblk_t nr; ext4_fsblk_t nr;
__le32 *p; __le32 *p;
if (is_handle_aborted(handle)) if (ext4_handle_is_aborted(handle))
return; return;
if (depth--) { if (depth--) {
...@@ -3649,7 +3666,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, ...@@ -3649,7 +3666,7 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
* will merely complain about releasing a free block, * will merely complain about releasing a free block,
* rather than leaking blocks. * rather than leaking blocks.
*/ */
if (is_handle_aborted(handle)) if (ext4_handle_is_aborted(handle))
return; return;
if (try_to_extend_transaction(handle, inode)) { if (try_to_extend_transaction(handle, inode)) {
ext4_mark_inode_dirty(handle, inode); ext4_mark_inode_dirty(handle, inode);
...@@ -3668,9 +3685,10 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode, ...@@ -3668,9 +3685,10 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
parent_bh)){ parent_bh)){
*p = 0; *p = 0;
BUFFER_TRACE(parent_bh, BUFFER_TRACE(parent_bh,
"call ext4_journal_dirty_metadata"); "call ext4_handle_dirty_metadata");
ext4_journal_dirty_metadata(handle, ext4_handle_dirty_metadata(handle,
parent_bh); inode,
parent_bh);
} }
} }
} }
...@@ -3858,7 +3876,7 @@ void ext4_truncate(struct inode *inode) ...@@ -3858,7 +3876,7 @@ void ext4_truncate(struct inode *inode)
* synchronous * synchronous
*/ */
if (IS_SYNC(inode)) if (IS_SYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
out_stop: out_stop:
/* /*
* If this was a simple ftruncate(), and the file will remain alive * If this was a simple ftruncate(), and the file will remain alive
...@@ -4357,8 +4375,8 @@ static int ext4_do_update_inode(handle_t *handle, ...@@ -4357,8 +4375,8 @@ static int ext4_do_update_inode(handle_t *handle,
EXT4_SET_RO_COMPAT_FEATURE(sb, EXT4_SET_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_LARGE_FILE); EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
sb->s_dirt = 1; sb->s_dirt = 1;
handle->h_sync = 1; ext4_handle_sync(handle);
err = ext4_journal_dirty_metadata(handle, err = ext4_handle_dirty_metadata(handle, inode,
EXT4_SB(sb)->s_sbh); EXT4_SB(sb)->s_sbh);
} }
} }
...@@ -4385,9 +4403,8 @@ static int ext4_do_update_inode(handle_t *handle, ...@@ -4385,9 +4403,8 @@ static int ext4_do_update_inode(handle_t *handle,
raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
} }
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); rc = ext4_handle_dirty_metadata(handle, inode, bh);
rc = ext4_journal_dirty_metadata(handle, bh);
if (!err) if (!err)
err = rc; err = rc;
ei->i_state &= ~EXT4_STATE_NEW; ei->i_state &= ~EXT4_STATE_NEW;
...@@ -4450,6 +4467,25 @@ int ext4_write_inode(struct inode *inode, int wait) ...@@ -4450,6 +4467,25 @@ int ext4_write_inode(struct inode *inode, int wait)
return ext4_force_commit(inode->i_sb); return ext4_force_commit(inode->i_sb);
} }
int __ext4_write_dirty_metadata(struct inode *inode, struct buffer_head *bh)
{
int err = 0;
mark_buffer_dirty(bh);
if (inode && inode_needs_sync(inode)) {
sync_dirty_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh)) {
ext4_error(inode->i_sb, __func__,
"IO error syncing inode, "
"inode=%lu, block=%llu",
inode->i_ino,
(unsigned long long)bh->b_blocknr);
err = -EIO;
}
}
return err;
}
/* /*
* ext4_setattr() * ext4_setattr()
* *
...@@ -4754,16 +4790,15 @@ int ...@@ -4754,16 +4790,15 @@ int
ext4_reserve_inode_write(handle_t *handle, struct inode *inode, ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
struct ext4_iloc *iloc) struct ext4_iloc *iloc)
{ {
int err = 0; int err;
if (handle) {
err = ext4_get_inode_loc(inode, iloc); err = ext4_get_inode_loc(inode, iloc);
if (!err) { if (!err) {
BUFFER_TRACE(iloc->bh, "get_write_access"); BUFFER_TRACE(iloc->bh, "get_write_access");
err = ext4_journal_get_write_access(handle, iloc->bh); err = ext4_journal_get_write_access(handle, iloc->bh);
if (err) { if (err) {
brelse(iloc->bh); brelse(iloc->bh);
iloc->bh = NULL; iloc->bh = NULL;
}
} }
} }
ext4_std_error(inode->i_sb, err); ext4_std_error(inode->i_sb, err);
...@@ -4835,7 +4870,8 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) ...@@ -4835,7 +4870,8 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
might_sleep(); might_sleep();
err = ext4_reserve_inode_write(handle, inode, &iloc); err = ext4_reserve_inode_write(handle, inode, &iloc);
if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && if (ext4_handle_valid(handle) &&
EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
!(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) { !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
/* /*
* We need extra buffer credits since we may write into EA block * We need extra buffer credits since we may write into EA block
...@@ -4887,6 +4923,11 @@ void ext4_dirty_inode(struct inode *inode) ...@@ -4887,6 +4923,11 @@ void ext4_dirty_inode(struct inode *inode)
handle_t *current_handle = ext4_journal_current_handle(); handle_t *current_handle = ext4_journal_current_handle();
handle_t *handle; handle_t *handle;
if (!ext4_handle_valid(current_handle)) {
ext4_mark_inode_dirty(current_handle, inode);
return;
}
handle = ext4_journal_start(inode, 2); handle = ext4_journal_start(inode, 2);
if (IS_ERR(handle)) if (IS_ERR(handle))
goto out; goto out;
...@@ -4924,8 +4965,9 @@ static int ext4_pin_inode(handle_t *handle, struct inode *inode) ...@@ -4924,8 +4965,9 @@ static int ext4_pin_inode(handle_t *handle, struct inode *inode)
BUFFER_TRACE(iloc.bh, "get_write_access"); BUFFER_TRACE(iloc.bh, "get_write_access");
err = jbd2_journal_get_write_access(handle, iloc.bh); err = jbd2_journal_get_write_access(handle, iloc.bh);
if (!err) if (!err)
err = ext4_journal_dirty_metadata(handle, err = ext4_handle_dirty_metadata(handle,
iloc.bh); inode,
iloc.bh);
brelse(iloc.bh); brelse(iloc.bh);
} }
} }
...@@ -4951,6 +4993,8 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) ...@@ -4951,6 +4993,8 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
*/ */
journal = EXT4_JOURNAL(inode); journal = EXT4_JOURNAL(inode);
if (!journal)
return 0;
if (is_journal_aborted(journal)) if (is_journal_aborted(journal))
return -EROFS; return -EROFS;
...@@ -4980,7 +5024,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val) ...@@ -4980,7 +5024,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
return PTR_ERR(handle); return PTR_ERR(handle);
err = ext4_mark_inode_dirty(handle, inode); err = ext4_mark_inode_dirty(handle, inode);
handle->h_sync = 1; ext4_handle_sync(handle);
ext4_journal_stop(handle); ext4_journal_stop(handle);
ext4_std_error(inode->i_sb, err); ext4_std_error(inode->i_sb, err);
......
...@@ -99,7 +99,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -99,7 +99,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto flags_out; goto flags_out;
} }
if (IS_SYNC(inode)) if (IS_SYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
err = ext4_reserve_inode_write(handle, inode, &iloc); err = ext4_reserve_inode_write(handle, inode, &iloc);
if (err) if (err)
goto flags_err; goto flags_err;
......
...@@ -2553,7 +2553,8 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) ...@@ -2553,7 +2553,8 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
ext4_mb_init_per_dev_proc(sb); ext4_mb_init_per_dev_proc(sb);
ext4_mb_history_init(sb); ext4_mb_history_init(sb);
sbi->s_journal->j_commit_callback = release_blocks_on_commit; if (sbi->s_journal)
sbi->s_journal->j_commit_callback = release_blocks_on_commit;
printk(KERN_INFO "EXT4-fs: mballoc enabled\n"); printk(KERN_INFO "EXT4-fs: mballoc enabled\n");
return 0; return 0;
...@@ -2854,7 +2855,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ...@@ -2854,7 +2855,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group), mb_set_bits(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group),
bitmap_bh->b_data, ac->ac_b_ex.fe_start, bitmap_bh->b_data, ac->ac_b_ex.fe_start,
ac->ac_b_ex.fe_len); ac->ac_b_ex.fe_len);
err = ext4_journal_dirty_metadata(handle, bitmap_bh); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
if (!err) if (!err)
err = -EAGAIN; err = -EAGAIN;
goto out_err; goto out_err;
...@@ -2901,10 +2902,10 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ...@@ -2901,10 +2902,10 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
spin_unlock(sb_bgl_lock(sbi, flex_group)); spin_unlock(sb_bgl_lock(sbi, flex_group));
} }
err = ext4_journal_dirty_metadata(handle, bitmap_bh); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
if (err) if (err)
goto out_err; goto out_err;
err = ext4_journal_dirty_metadata(handle, gdp_bh); err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh);
out_err: out_err:
sb->s_dirt = 1; sb->s_dirt = 1;
...@@ -4414,7 +4415,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, ...@@ -4414,7 +4415,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
struct rb_node **n = &db->bb_free_root.rb_node, *node; struct rb_node **n = &db->bb_free_root.rb_node, *node;
struct rb_node *parent = NULL, *new_node; struct rb_node *parent = NULL, *new_node;
BUG_ON(!ext4_handle_valid(handle));
BUG_ON(e4b->bd_bitmap_page == NULL); BUG_ON(e4b->bd_bitmap_page == NULL);
BUG_ON(e4b->bd_buddy_page == NULL); BUG_ON(e4b->bd_buddy_page == NULL);
...@@ -4600,7 +4601,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, ...@@ -4600,7 +4601,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
/* We dirtied the bitmap block */ /* We dirtied the bitmap block */
BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
err = ext4_journal_dirty_metadata(handle, bitmap_bh); err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
if (ac) { if (ac) {
ac->ac_b_ex.fe_group = block_group; ac->ac_b_ex.fe_group = block_group;
...@@ -4609,7 +4610,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, ...@@ -4609,7 +4610,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
ext4_mb_store_history(ac); ext4_mb_store_history(ac);
} }
if (metadata) { if (metadata && ext4_handle_valid(handle)) {
/* blocks being freed are metadata. these blocks shouldn't /* blocks being freed are metadata. these blocks shouldn't
* be used until this transaction is committed */ * be used until this transaction is committed */
ext4_mb_free_metadata(handle, &e4b, block_group, bit, count); ext4_mb_free_metadata(handle, &e4b, block_group, bit, count);
...@@ -4639,7 +4640,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, ...@@ -4639,7 +4640,7 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode,
/* And the group descriptor block */ /* And the group descriptor block */
BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
ret = ext4_journal_dirty_metadata(handle, gd_bh); ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh);
if (!err) if (!err)
err = ret; err = ret;
......
...@@ -59,7 +59,8 @@ static int finish_range(handle_t *handle, struct inode *inode, ...@@ -59,7 +59,8 @@ static int finish_range(handle_t *handle, struct inode *inode,
/* /*
* Make sure the credit we accumalated is not really high * Make sure the credit we accumalated is not really high
*/ */
if (needed && handle->h_buffer_credits >= EXT4_RESERVE_TRANS_BLOCKS) { if (needed && ext4_handle_has_enough_credits(handle,
EXT4_RESERVE_TRANS_BLOCKS)) {
retval = ext4_journal_restart(handle, needed); retval = ext4_journal_restart(handle, needed);
if (retval) if (retval)
goto err_out; goto err_out;
...@@ -229,7 +230,7 @@ static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode) ...@@ -229,7 +230,7 @@ static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode)
{ {
int retval = 0, needed; int retval = 0, needed;
if (handle->h_buffer_credits > EXT4_RESERVE_TRANS_BLOCKS) if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1))
return 0; return 0;
/* /*
* We are freeing a blocks. During this we touch * We are freeing a blocks. During this we touch
......
...@@ -1233,10 +1233,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, ...@@ -1233,10 +1233,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
de = de2; de = de2;
} }
dx_insert_block(frame, hash2 + continued, newblock); dx_insert_block(frame, hash2 + continued, newblock);
err = ext4_journal_dirty_metadata(handle, bh2); err = ext4_handle_dirty_metadata(handle, dir, bh2);
if (err) if (err)
goto journal_error; goto journal_error;
err = ext4_journal_dirty_metadata(handle, frame->bh); err = ext4_handle_dirty_metadata(handle, dir, frame->bh);
if (err) if (err)
goto journal_error; goto journal_error;
brelse(bh2); brelse(bh2);
...@@ -1340,8 +1340,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, ...@@ -1340,8 +1340,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
ext4_update_dx_flag(dir); ext4_update_dx_flag(dir);
dir->i_version++; dir->i_version++;
ext4_mark_inode_dirty(handle, dir); ext4_mark_inode_dirty(handle, dir);
BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, dir, bh);
if (err) if (err)
ext4_std_error(dir->i_sb, err); ext4_std_error(dir->i_sb, err);
brelse(bh); brelse(bh);
...@@ -1581,7 +1581,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, ...@@ -1581,7 +1581,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
dxtrace(dx_show_index("node", frames[1].entries)); dxtrace(dx_show_index("node", frames[1].entries));
dxtrace(dx_show_index("node", dxtrace(dx_show_index("node",
((struct dx_node *) bh2->b_data)->entries)); ((struct dx_node *) bh2->b_data)->entries));
err = ext4_journal_dirty_metadata(handle, bh2); err = ext4_handle_dirty_metadata(handle, inode, bh2);
if (err) if (err)
goto journal_error; goto journal_error;
brelse (bh2); brelse (bh2);
...@@ -1607,7 +1607,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, ...@@ -1607,7 +1607,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
if (err) if (err)
goto journal_error; goto journal_error;
} }
ext4_journal_dirty_metadata(handle, frames[0].bh); ext4_handle_dirty_metadata(handle, inode, frames[0].bh);
} }
de = do_split(handle, dir, &bh, frame, &hinfo, &err); de = do_split(handle, dir, &bh, frame, &hinfo, &err);
if (!de) if (!de)
...@@ -1653,8 +1653,8 @@ static int ext4_delete_entry(handle_t *handle, ...@@ -1653,8 +1653,8 @@ static int ext4_delete_entry(handle_t *handle,
else else
de->inode = 0; de->inode = 0;
dir->i_version++; dir->i_version++;
BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
ext4_journal_dirty_metadata(handle, bh); ext4_handle_dirty_metadata(handle, dir, bh);
return 0; return 0;
} }
i += ext4_rec_len_from_disk(de->rec_len); i += ext4_rec_len_from_disk(de->rec_len);
...@@ -1732,7 +1732,7 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -1732,7 +1732,7 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, int mode,
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
inode = ext4_new_inode (handle, dir, mode); inode = ext4_new_inode (handle, dir, mode);
err = PTR_ERR(inode); err = PTR_ERR(inode);
...@@ -1766,7 +1766,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, ...@@ -1766,7 +1766,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry,
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
inode = ext4_new_inode(handle, dir, mode); inode = ext4_new_inode(handle, dir, mode);
err = PTR_ERR(inode); err = PTR_ERR(inode);
...@@ -1802,7 +1802,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -1802,7 +1802,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
inode = ext4_new_inode(handle, dir, S_IFDIR | mode); inode = ext4_new_inode(handle, dir, S_IFDIR | mode);
err = PTR_ERR(inode); err = PTR_ERR(inode);
...@@ -1831,8 +1831,8 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -1831,8 +1831,8 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
strcpy(de->name, ".."); strcpy(de->name, "..");
ext4_set_de_type(dir->i_sb, de, S_IFDIR); ext4_set_de_type(dir->i_sb, de, S_IFDIR);
inode->i_nlink = 2; inode->i_nlink = 2;
BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
ext4_journal_dirty_metadata(handle, dir_block); ext4_handle_dirty_metadata(handle, dir, dir_block);
brelse(dir_block); brelse(dir_block);
ext4_mark_inode_dirty(handle, inode); ext4_mark_inode_dirty(handle, inode);
err = ext4_add_entry(handle, dentry, inode); err = ext4_add_entry(handle, dentry, inode);
...@@ -1944,6 +1944,9 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) ...@@ -1944,6 +1944,9 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
struct ext4_iloc iloc; struct ext4_iloc iloc;
int err = 0, rc; int err = 0, rc;
if (!ext4_handle_valid(handle))
return 0;
lock_super(sb); lock_super(sb);
if (!list_empty(&EXT4_I(inode)->i_orphan)) if (!list_empty(&EXT4_I(inode)->i_orphan))
goto out_unlock; goto out_unlock;
...@@ -1972,7 +1975,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) ...@@ -1972,7 +1975,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
/* Insert this inode at the head of the on-disk orphan list... */ /* Insert this inode at the head of the on-disk orphan list... */
NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan);
EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); err = ext4_handle_dirty_metadata(handle, inode, EXT4_SB(sb)->s_sbh);
rc = ext4_mark_iloc_dirty(handle, inode, &iloc); rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
if (!err) if (!err)
err = rc; err = rc;
...@@ -2010,6 +2013,9 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) ...@@ -2010,6 +2013,9 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
struct ext4_iloc iloc; struct ext4_iloc iloc;
int err = 0; int err = 0;
if (!ext4_handle_valid(handle))
return 0;
lock_super(inode->i_sb); lock_super(inode->i_sb);
if (list_empty(&ei->i_orphan)) { if (list_empty(&ei->i_orphan)) {
unlock_super(inode->i_sb); unlock_super(inode->i_sb);
...@@ -2028,7 +2034,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) ...@@ -2028,7 +2034,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
* transaction handle with which to update the orphan list on * transaction handle with which to update the orphan list on
* disk, but we still need to remove the inode from the linked * disk, but we still need to remove the inode from the linked
* list in memory. */ * list in memory. */
if (!handle) if (sbi->s_journal && !handle)
goto out; goto out;
err = ext4_reserve_inode_write(handle, inode, &iloc); err = ext4_reserve_inode_write(handle, inode, &iloc);
...@@ -2042,7 +2048,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) ...@@ -2042,7 +2048,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
if (err) if (err)
goto out_brelse; goto out_brelse;
sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
err = ext4_journal_dirty_metadata(handle, sbi->s_sbh); err = ext4_handle_dirty_metadata(handle, inode, sbi->s_sbh);
} else { } else {
struct ext4_iloc iloc2; struct ext4_iloc iloc2;
struct inode *i_prev = struct inode *i_prev =
...@@ -2093,7 +2099,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -2093,7 +2099,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
goto end_rmdir; goto end_rmdir;
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
inode = dentry->d_inode; inode = dentry->d_inode;
...@@ -2147,7 +2153,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) ...@@ -2147,7 +2153,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
retval = -ENOENT; retval = -ENOENT;
bh = ext4_find_entry(dir, &dentry->d_name, &de); bh = ext4_find_entry(dir, &dentry->d_name, &de);
...@@ -2204,7 +2210,7 @@ static int ext4_symlink(struct inode *dir, ...@@ -2204,7 +2210,7 @@ static int ext4_symlink(struct inode *dir,
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO); inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO);
err = PTR_ERR(inode); err = PTR_ERR(inode);
...@@ -2267,7 +2273,7 @@ static int ext4_link(struct dentry *old_dentry, ...@@ -2267,7 +2273,7 @@ static int ext4_link(struct dentry *old_dentry,
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(dir)) if (IS_DIRSYNC(dir))
handle->h_sync = 1; ext4_handle_sync(handle);
inode->i_ctime = ext4_current_time(inode); inode->i_ctime = ext4_current_time(inode);
ext4_inc_count(handle, inode); ext4_inc_count(handle, inode);
...@@ -2316,7 +2322,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2316,7 +2322,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
return PTR_ERR(handle); return PTR_ERR(handle);
if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
handle->h_sync = 1; ext4_handle_sync(handle);
old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de); old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de);
/* /*
...@@ -2370,8 +2376,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2370,8 +2376,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_ctime = new_dir->i_mtime =
ext4_current_time(new_dir); ext4_current_time(new_dir);
ext4_mark_inode_dirty(handle, new_dir); ext4_mark_inode_dirty(handle, new_dir);
BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata");
ext4_journal_dirty_metadata(handle, new_bh); ext4_handle_dirty_metadata(handle, new_dir, new_bh);
brelse(new_bh); brelse(new_bh);
new_bh = NULL; new_bh = NULL;
} }
...@@ -2421,8 +2427,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2421,8 +2427,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
BUFFER_TRACE(dir_bh, "get_write_access"); BUFFER_TRACE(dir_bh, "get_write_access");
ext4_journal_get_write_access(handle, dir_bh); ext4_journal_get_write_access(handle, dir_bh);
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata"); BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
ext4_journal_dirty_metadata(handle, dir_bh); ext4_handle_dirty_metadata(handle, old_dir, dir_bh);
ext4_dec_count(handle, old_dir); ext4_dec_count(handle, old_dir);
if (new_inode) { if (new_inode) {
/* checked empty_dir above, can't have another parent, /* checked empty_dir above, can't have another parent,
......
...@@ -149,7 +149,7 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh, ...@@ -149,7 +149,7 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh,
{ {
int err; int err;
if (handle->h_buffer_credits >= thresh) if (ext4_handle_has_enough_credits(handle, thresh))
return 0; return 0;
err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA); err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA);
...@@ -232,7 +232,7 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -232,7 +232,7 @@ static int setup_new_group_blocks(struct super_block *sb,
memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size); memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size);
set_buffer_uptodate(gdb); set_buffer_uptodate(gdb);
unlock_buffer(gdb); unlock_buffer(gdb);
ext4_journal_dirty_metadata(handle, gdb); ext4_handle_dirty_metadata(handle, NULL, gdb);
ext4_set_bit(bit, bh->b_data); ext4_set_bit(bit, bh->b_data);
brelse(gdb); brelse(gdb);
} }
...@@ -251,7 +251,7 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -251,7 +251,7 @@ static int setup_new_group_blocks(struct super_block *sb,
err = PTR_ERR(bh); err = PTR_ERR(bh);
goto exit_bh; goto exit_bh;
} }
ext4_journal_dirty_metadata(handle, gdb); ext4_handle_dirty_metadata(handle, NULL, gdb);
ext4_set_bit(bit, bh->b_data); ext4_set_bit(bit, bh->b_data);
brelse(gdb); brelse(gdb);
} }
...@@ -276,7 +276,7 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -276,7 +276,7 @@ static int setup_new_group_blocks(struct super_block *sb,
err = PTR_ERR(it); err = PTR_ERR(it);
goto exit_bh; goto exit_bh;
} }
ext4_journal_dirty_metadata(handle, it); ext4_handle_dirty_metadata(handle, NULL, it);
brelse(it); brelse(it);
ext4_set_bit(bit, bh->b_data); ext4_set_bit(bit, bh->b_data);
} }
...@@ -286,7 +286,7 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -286,7 +286,7 @@ static int setup_new_group_blocks(struct super_block *sb,
mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb), mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),
bh->b_data); bh->b_data);
ext4_journal_dirty_metadata(handle, bh); ext4_handle_dirty_metadata(handle, NULL, bh);
brelse(bh); brelse(bh);
/* Mark unused entries in inode bitmap used */ /* Mark unused entries in inode bitmap used */
...@@ -299,7 +299,7 @@ static int setup_new_group_blocks(struct super_block *sb, ...@@ -299,7 +299,7 @@ static int setup_new_group_blocks(struct super_block *sb,
mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb), mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb),
bh->b_data); bh->b_data);
ext4_journal_dirty_metadata(handle, bh); ext4_handle_dirty_metadata(handle, NULL, bh);
exit_bh: exit_bh:
brelse(bh); brelse(bh);
...@@ -486,12 +486,12 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, ...@@ -486,12 +486,12 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
* reserved inode, and will become GDT blocks (primary and backup). * reserved inode, and will become GDT blocks (primary and backup).
*/ */
data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0; data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0;
ext4_journal_dirty_metadata(handle, dind); ext4_handle_dirty_metadata(handle, NULL, dind);
brelse(dind); brelse(dind);
inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9;
ext4_mark_iloc_dirty(handle, inode, &iloc); ext4_mark_iloc_dirty(handle, inode, &iloc);
memset((*primary)->b_data, 0, sb->s_blocksize); memset((*primary)->b_data, 0, sb->s_blocksize);
ext4_journal_dirty_metadata(handle, *primary); ext4_handle_dirty_metadata(handle, NULL, *primary);
o_group_desc = EXT4_SB(sb)->s_group_desc; o_group_desc = EXT4_SB(sb)->s_group_desc;
memcpy(n_group_desc, o_group_desc, memcpy(n_group_desc, o_group_desc,
...@@ -502,7 +502,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, ...@@ -502,7 +502,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
kfree(o_group_desc); kfree(o_group_desc);
le16_add_cpu(&es->s_reserved_gdt_blocks, -1); le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
return 0; return 0;
...@@ -618,7 +618,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode, ...@@ -618,7 +618,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
primary[i]->b_blocknr, gdbackups, primary[i]->b_blocknr, gdbackups,
blk + primary[i]->b_blocknr); */ blk + primary[i]->b_blocknr); */
data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr);
err2 = ext4_journal_dirty_metadata(handle, primary[i]); err2 = ext4_handle_dirty_metadata(handle, NULL, primary[i]);
if (!err) if (!err)
err = err2; err = err2;
} }
...@@ -676,7 +676,8 @@ static void update_backups(struct super_block *sb, ...@@ -676,7 +676,8 @@ static void update_backups(struct super_block *sb,
struct buffer_head *bh; struct buffer_head *bh;
/* Out of journal space, and can't get more - abort - so sad */ /* Out of journal space, and can't get more - abort - so sad */
if (handle->h_buffer_credits == 0 && if (ext4_handle_valid(handle) &&
handle->h_buffer_credits == 0 &&
ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) && ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) &&
(err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
break; break;
...@@ -696,7 +697,7 @@ static void update_backups(struct super_block *sb, ...@@ -696,7 +697,7 @@ static void update_backups(struct super_block *sb,
memset(bh->b_data + size, 0, rest); memset(bh->b_data + size, 0, rest);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
ext4_journal_dirty_metadata(handle, bh); ext4_handle_dirty_metadata(handle, NULL, bh);
brelse(bh); brelse(bh);
} }
if ((err2 = ext4_journal_stop(handle)) && !err) if ((err2 = ext4_journal_stop(handle)) && !err)
...@@ -916,7 +917,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ...@@ -916,7 +917,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
/* Update the global fs size fields */ /* Update the global fs size fields */
sbi->s_groups_count++; sbi->s_groups_count++;
ext4_journal_dirty_metadata(handle, primary); ext4_handle_dirty_metadata(handle, NULL, primary);
/* Update the reserved block counts only once the new group is /* Update the reserved block counts only once the new group is
* active. */ * active. */
...@@ -938,7 +939,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) ...@@ -938,7 +939,7 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
EXT4_INODES_PER_GROUP(sb); EXT4_INODES_PER_GROUP(sb);
} }
ext4_journal_dirty_metadata(handle, sbi->s_sbh); ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh);
sb->s_dirt = 1; sb->s_dirt = 1;
exit_journal: exit_journal:
...@@ -1072,7 +1073,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, ...@@ -1072,7 +1073,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
goto exit_put; goto exit_put;
} }
ext4_blocks_count_set(es, o_blocks_count + add); ext4_blocks_count_set(es, o_blocks_count + add);
ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
sb->s_dirt = 1; sb->s_dirt = 1;
unlock_super(sb); unlock_super(sb);
ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count,
......
...@@ -136,13 +136,19 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) ...@@ -136,13 +136,19 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
* backs (eg. EIO in the commit thread), then we still need to * backs (eg. EIO in the commit thread), then we still need to
* take the FS itself readonly cleanly. */ * take the FS itself readonly cleanly. */
journal = EXT4_SB(sb)->s_journal; journal = EXT4_SB(sb)->s_journal;
if (is_journal_aborted(journal)) { if (journal) {
ext4_abort(sb, __func__, if (is_journal_aborted(journal)) {
"Detected aborted journal"); ext4_abort(sb, __func__,
return ERR_PTR(-EROFS); "Detected aborted journal");
return ERR_PTR(-EROFS);
}
return jbd2_journal_start(journal, nblocks);
} }
/*
return jbd2_journal_start(journal, nblocks); * We're not journaling, return the appropriate indication.
*/
current->journal_info = EXT4_NOJOURNAL_HANDLE;
return current->journal_info;
} }
/* /*
...@@ -157,6 +163,14 @@ int __ext4_journal_stop(const char *where, handle_t *handle) ...@@ -157,6 +163,14 @@ int __ext4_journal_stop(const char *where, handle_t *handle)
int err; int err;
int rc; int rc;
if (!ext4_handle_valid(handle)) {
/*
* Do this here since we don't call jbd2_journal_stop() in
* no-journal mode.
*/
current->journal_info = NULL;
return 0;
}
sb = handle->h_transaction->t_journal->j_private; sb = handle->h_transaction->t_journal->j_private;
err = handle->h_err; err = handle->h_err;
rc = jbd2_journal_stop(handle); rc = jbd2_journal_stop(handle);
...@@ -174,6 +188,8 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn, ...@@ -174,6 +188,8 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn,
char nbuf[16]; char nbuf[16];
const char *errstr = ext4_decode_error(NULL, err, nbuf); const char *errstr = ext4_decode_error(NULL, err, nbuf);
BUG_ON(!ext4_handle_valid(handle));
if (bh) if (bh)
BUFFER_TRACE(bh, "abort"); BUFFER_TRACE(bh, "abort");
...@@ -448,11 +464,13 @@ static void ext4_put_super(struct super_block *sb) ...@@ -448,11 +464,13 @@ static void ext4_put_super(struct super_block *sb)
ext4_mb_release(sb); ext4_mb_release(sb);
ext4_ext_release(sb); ext4_ext_release(sb);
ext4_xattr_put_super(sb); ext4_xattr_put_super(sb);
err = jbd2_journal_destroy(sbi->s_journal); if (sbi->s_journal) {
sbi->s_journal = NULL; err = jbd2_journal_destroy(sbi->s_journal);
if (err < 0) sbi->s_journal = NULL;
ext4_abort(sb, __func__, "Couldn't clean up the journal"); if (err < 0)
ext4_abort(sb, __func__,
"Couldn't clean up the journal");
}
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
es->s_state = cpu_to_le16(sbi->s_mount_state); es->s_state = cpu_to_le16(sbi->s_mount_state);
...@@ -522,6 +540,11 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) ...@@ -522,6 +540,11 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
INIT_LIST_HEAD(&ei->i_prealloc_list); INIT_LIST_HEAD(&ei->i_prealloc_list);
spin_lock_init(&ei->i_prealloc_lock); spin_lock_init(&ei->i_prealloc_lock);
/*
* Note: We can be called before EXT4_SB(sb)->s_journal is set,
* therefore it can be null here. Don't check it, just initialize
* jinode.
*/
jbd2_journal_init_jbd_inode(&ei->jinode, &ei->vfs_inode); jbd2_journal_init_jbd_inode(&ei->jinode, &ei->vfs_inode);
ei->i_reserved_data_blocks = 0; ei->i_reserved_data_blocks = 0;
ei->i_reserved_meta_blocks = 0; ei->i_reserved_meta_blocks = 0;
...@@ -588,7 +611,8 @@ static void ext4_clear_inode(struct inode *inode) ...@@ -588,7 +611,8 @@ static void ext4_clear_inode(struct inode *inode)
} }
#endif #endif
ext4_discard_preallocations(inode); ext4_discard_preallocations(inode);
jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal, if (EXT4_JOURNAL(inode))
jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
&EXT4_I(inode)->jinode); &EXT4_I(inode)->jinode);
} }
...@@ -1406,20 +1430,15 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, ...@@ -1406,20 +1430,15 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
printk(KERN_WARNING printk(KERN_WARNING
"EXT4-fs warning: checktime reached, " "EXT4-fs warning: checktime reached, "
"running e2fsck is recommended\n"); "running e2fsck is recommended\n");
#if 0 if (!sbi->s_journal)
/* @@@ We _will_ want to clear the valid bit if we find es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
* inconsistencies, to force a fsck at reboot. But for
* a plain journaled filesystem we can keep it set as
* valid forever! :)
*/
es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
#endif
if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
le16_add_cpu(&es->s_mnt_count, 1); le16_add_cpu(&es->s_mnt_count, 1);
es->s_mtime = cpu_to_le32(get_seconds()); es->s_mtime = cpu_to_le32(get_seconds());
ext4_update_dynamic_rev(sb); ext4_update_dynamic_rev(sb);
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); if (sbi->s_journal)
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
ext4_commit_super(sb, es, 1); ext4_commit_super(sb, es, 1);
if (test_opt(sb, DEBUG)) if (test_opt(sb, DEBUG))
...@@ -1431,9 +1450,13 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, ...@@ -1431,9 +1450,13 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
EXT4_INODES_PER_GROUP(sb), EXT4_INODES_PER_GROUP(sb),
sbi->s_mount_opt); sbi->s_mount_opt);
printk(KERN_INFO "EXT4 FS on %s, %s journal on %s\n", if (EXT4_SB(sb)->s_journal) {
sb->s_id, EXT4_SB(sb)->s_journal->j_inode ? "internal" : printk(KERN_INFO "EXT4 FS on %s, %s journal on %s\n",
"external", EXT4_SB(sb)->s_journal->j_devname); sb->s_id, EXT4_SB(sb)->s_journal->j_inode ? "internal" :
"external", EXT4_SB(sb)->s_journal->j_devname);
} else {
printk(KERN_INFO "EXT4 FS on %s, no journal\n", sb->s_id);
}
return res; return res;
} }
...@@ -1867,6 +1890,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1867,6 +1890,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
unsigned long def_mount_opts; unsigned long def_mount_opts;
struct inode *root; struct inode *root;
char *cp; char *cp;
const char *descr;
int ret = -EINVAL; int ret = -EINVAL;
int blocksize; int blocksize;
int db_count; int db_count;
...@@ -2278,21 +2302,23 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2278,21 +2302,23 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
es->s_state |= cpu_to_le16(EXT4_ERROR_FS); es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
ext4_commit_super(sb, es, 1); ext4_commit_super(sb, es, 1);
printk(KERN_CRIT
"EXT4-fs (device %s): mount failed\n",
sb->s_id);
goto failed_mount4; goto failed_mount4;
} }
} }
} else if (journal_inum) { } else if (journal_inum) {
if (ext4_create_journal(sb, es, journal_inum)) if (ext4_create_journal(sb, es, journal_inum))
goto failed_mount3; goto failed_mount3;
} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
printk(KERN_ERR "EXT4-fs: required journal recovery "
"suppressed and not mounted read-only\n");
goto failed_mount4;
} else { } else {
if (!silent) clear_opt(sbi->s_mount_opt, DATA_FLAGS);
printk(KERN_ERR set_opt(sbi->s_mount_opt, WRITEBACK_DATA);
"ext4: No journal on filesystem on %s\n", sbi->s_journal = NULL;
sb->s_id); needs_recovery = 0;
goto failed_mount3; goto no_journal;
} }
if (ext4_blocks_count(es) > 0xffffffffULL && if (ext4_blocks_count(es) > 0xffffffffULL &&
...@@ -2344,6 +2370,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2344,6 +2370,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
break; break;
} }
no_journal:
if (test_opt(sb, NOBH)) { if (test_opt(sb, NOBH)) {
if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) { if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
printk(KERN_WARNING "EXT4-fs: Ignoring nobh option - " printk(KERN_WARNING "EXT4-fs: Ignoring nobh option - "
...@@ -2428,13 +2456,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2428,13 +2456,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS; EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS;
ext4_orphan_cleanup(sb, es); ext4_orphan_cleanup(sb, es);
EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS; EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS;
if (needs_recovery) if (needs_recovery) {
printk(KERN_INFO "EXT4-fs: recovery complete.\n"); printk(KERN_INFO "EXT4-fs: recovery complete.\n");
ext4_mark_recovery_complete(sb, es); ext4_mark_recovery_complete(sb, es);
printk(KERN_INFO "EXT4-fs: mounted filesystem with %s data mode.\n", }
test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ? "journal": if (EXT4_SB(sb)->s_journal) {
test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
"writeback"); descr = " journalled data mode";
else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
descr = " ordered data mode";
else
descr = " writeback data mode";
} else
descr = "out journal";
printk(KERN_INFO "EXT4-fs: mounted filesystem %s with%s\n",
sb->s_id, descr);
lock_kernel(); lock_kernel();
return 0; return 0;
...@@ -2446,8 +2483,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2446,8 +2483,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount; goto failed_mount;
failed_mount4: failed_mount4:
jbd2_journal_destroy(sbi->s_journal); printk(KERN_ERR "EXT4-fs (device %s): mount failed\n", sb->s_id);
sbi->s_journal = NULL; if (sbi->s_journal) {
jbd2_journal_destroy(sbi->s_journal);
sbi->s_journal = NULL;
}
failed_mount3: failed_mount3:
percpu_counter_destroy(&sbi->s_freeblocks_counter); percpu_counter_destroy(&sbi->s_freeblocks_counter);
percpu_counter_destroy(&sbi->s_freeinodes_counter); percpu_counter_destroy(&sbi->s_freeinodes_counter);
...@@ -2508,6 +2548,8 @@ static journal_t *ext4_get_journal(struct super_block *sb, ...@@ -2508,6 +2548,8 @@ static journal_t *ext4_get_journal(struct super_block *sb,
struct inode *journal_inode; struct inode *journal_inode;
journal_t *journal; journal_t *journal;
BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
/* First, test for the existence of a valid inode on disk. Bad /* First, test for the existence of a valid inode on disk. Bad
* things happen if we iget() an unused inode, as the subsequent * things happen if we iget() an unused inode, as the subsequent
* iput() will try to delete it. */ * iput() will try to delete it. */
...@@ -2556,6 +2598,8 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, ...@@ -2556,6 +2598,8 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
struct ext4_super_block *es; struct ext4_super_block *es;
struct block_device *bdev; struct block_device *bdev;
BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
bdev = ext4_blkdev_get(j_dev); bdev = ext4_blkdev_get(j_dev);
if (bdev == NULL) if (bdev == NULL)
return NULL; return NULL;
...@@ -2643,6 +2687,8 @@ static int ext4_load_journal(struct super_block *sb, ...@@ -2643,6 +2687,8 @@ static int ext4_load_journal(struct super_block *sb,
int err = 0; int err = 0;
int really_read_only; int really_read_only;
BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
if (journal_devnum && if (journal_devnum &&
journal_devnum != le32_to_cpu(es->s_journal_dev)) { journal_devnum != le32_to_cpu(es->s_journal_dev)) {
printk(KERN_INFO "EXT4-fs: external journal device major/minor " printk(KERN_INFO "EXT4-fs: external journal device major/minor "
...@@ -2817,6 +2863,10 @@ static void ext4_mark_recovery_complete(struct super_block *sb, ...@@ -2817,6 +2863,10 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
{ {
journal_t *journal = EXT4_SB(sb)->s_journal; journal_t *journal = EXT4_SB(sb)->s_journal;
if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
BUG_ON(journal != NULL);
return;
}
jbd2_journal_lock_updates(journal); jbd2_journal_lock_updates(journal);
if (jbd2_journal_flush(journal) < 0) if (jbd2_journal_flush(journal) < 0)
goto out; goto out;
...@@ -2846,6 +2896,8 @@ static void ext4_clear_journal_err(struct super_block *sb, ...@@ -2846,6 +2896,8 @@ static void ext4_clear_journal_err(struct super_block *sb,
int j_errno; int j_errno;
const char *errstr; const char *errstr;
BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
journal = EXT4_SB(sb)->s_journal; journal = EXT4_SB(sb)->s_journal;
/* /*
...@@ -2878,14 +2930,17 @@ static void ext4_clear_journal_err(struct super_block *sb, ...@@ -2878,14 +2930,17 @@ static void ext4_clear_journal_err(struct super_block *sb,
int ext4_force_commit(struct super_block *sb) int ext4_force_commit(struct super_block *sb)
{ {
journal_t *journal; journal_t *journal;
int ret; int ret = 0;
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
return 0; return 0;
journal = EXT4_SB(sb)->s_journal; journal = EXT4_SB(sb)->s_journal;
sb->s_dirt = 0; if (journal) {
ret = ext4_journal_force_commit(journal); sb->s_dirt = 0;
ret = ext4_journal_force_commit(journal);
}
return ret; return ret;
} }
...@@ -2897,9 +2952,13 @@ int ext4_force_commit(struct super_block *sb) ...@@ -2897,9 +2952,13 @@ int ext4_force_commit(struct super_block *sb)
*/ */
static void ext4_write_super(struct super_block *sb) static void ext4_write_super(struct super_block *sb)
{ {
if (mutex_trylock(&sb->s_lock) != 0) if (EXT4_SB(sb)->s_journal) {
BUG(); if (mutex_trylock(&sb->s_lock) != 0)
sb->s_dirt = 0; BUG();
sb->s_dirt = 0;
} else {
ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
}
} }
static int ext4_sync_fs(struct super_block *sb, int wait) static int ext4_sync_fs(struct super_block *sb, int wait)
...@@ -2908,10 +2967,14 @@ static int ext4_sync_fs(struct super_block *sb, int wait) ...@@ -2908,10 +2967,14 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait); trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait);
sb->s_dirt = 0; sb->s_dirt = 0;
if (wait) if (EXT4_SB(sb)->s_journal) {
ret = ext4_force_commit(sb); if (wait)
else ret = ext4_force_commit(sb);
jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL); else
jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL);
} else {
ext4_commit_super(sb, EXT4_SB(sb)->s_es, wait);
}
return ret; return ret;
} }
...@@ -2926,15 +2989,17 @@ static void ext4_write_super_lockfs(struct super_block *sb) ...@@ -2926,15 +2989,17 @@ static void ext4_write_super_lockfs(struct super_block *sb)
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
journal_t *journal = EXT4_SB(sb)->s_journal; journal_t *journal = EXT4_SB(sb)->s_journal;
/* Now we set up the journal barrier. */ if (journal) {
jbd2_journal_lock_updates(journal); /* Now we set up the journal barrier. */
jbd2_journal_lock_updates(journal);
/* /*
* We don't want to clear needs_recovery flag when we failed * We don't want to clear needs_recovery flag when we
* to flush the journal. * failed to flush the journal.
*/ */
if (jbd2_journal_flush(journal) < 0) if (jbd2_journal_flush(journal) < 0)
return; return;
}
/* Journal blocked and flushed, clear needs_recovery flag. */ /* Journal blocked and flushed, clear needs_recovery flag. */
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
...@@ -2948,7 +3013,7 @@ static void ext4_write_super_lockfs(struct super_block *sb) ...@@ -2948,7 +3013,7 @@ static void ext4_write_super_lockfs(struct super_block *sb)
*/ */
static void ext4_unlockfs(struct super_block *sb) static void ext4_unlockfs(struct super_block *sb)
{ {
if (!(sb->s_flags & MS_RDONLY)) { if (EXT4_SB(sb)->s_journal && !(sb->s_flags & MS_RDONLY)) {
lock_super(sb); lock_super(sb);
/* Reser the needs_recovery flag before the fs is unlocked. */ /* Reser the needs_recovery flag before the fs is unlocked. */
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
...@@ -2999,7 +3064,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) ...@@ -2999,7 +3064,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
es = sbi->s_es; es = sbi->s_es;
ext4_init_journal_params(sb, sbi->s_journal); if (sbi->s_journal)
ext4_init_journal_params(sb, sbi->s_journal);
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
n_blocks_count > ext4_blocks_count(es)) { n_blocks_count > ext4_blocks_count(es)) {
...@@ -3028,9 +3094,11 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) ...@@ -3028,9 +3094,11 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
* We have to unlock super so that we can wait for * We have to unlock super so that we can wait for
* transactions. * transactions.
*/ */
unlock_super(sb); if (sbi->s_journal) {
ext4_mark_recovery_complete(sb, es); unlock_super(sb);
lock_super(sb); ext4_mark_recovery_complete(sb, es);
lock_super(sb);
}
} else { } else {
__le32 ret; __le32 ret;
if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb, if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb,
...@@ -3084,7 +3152,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) ...@@ -3084,7 +3152,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
* been changed by e2fsck since we originally mounted * been changed by e2fsck since we originally mounted
* the partition.) * the partition.)
*/ */
ext4_clear_journal_err(sb, es); if (sbi->s_journal)
ext4_clear_journal_err(sb, es);
sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_mount_state = le16_to_cpu(es->s_state);
if ((err = ext4_group_extend(sb, es, n_blocks_count))) if ((err = ext4_group_extend(sb, es, n_blocks_count)))
goto restore_opts; goto restore_opts;
...@@ -3092,6 +3161,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) ...@@ -3092,6 +3161,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
sb->s_flags &= ~MS_RDONLY; sb->s_flags &= ~MS_RDONLY;
} }
} }
if (sbi->s_journal == NULL)
ext4_commit_super(sb, es, 1);
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
/* Release old quota file names */ /* Release old quota file names */
for (i = 0; i < MAXQUOTAS; i++) for (i = 0; i < MAXQUOTAS; i++)
...@@ -3368,7 +3440,8 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, ...@@ -3368,7 +3440,8 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
* When we journal data on quota file, we have to flush journal to see * When we journal data on quota file, we have to flush journal to see
* all updates to the file when we bypass pagecache... * all updates to the file when we bypass pagecache...
*/ */
if (ext4_should_journal_data(path.dentry->d_inode)) { if (EXT4_SB(sb)->s_journal &&
ext4_should_journal_data(path.dentry->d_inode)) {
/* /*
* We don't need to lock updates but journal_flush() could * We don't need to lock updates but journal_flush() could
* otherwise be livelocked... * otherwise be livelocked...
...@@ -3442,7 +3515,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, ...@@ -3442,7 +3515,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
struct buffer_head *bh; struct buffer_head *bh;
handle_t *handle = journal_current_handle(); handle_t *handle = journal_current_handle();
if (!handle) { if (EXT4_SB(sb)->s_journal && !handle) {
printk(KERN_WARNING "EXT4-fs: Quota write (off=%llu, len=%llu)" printk(KERN_WARNING "EXT4-fs: Quota write (off=%llu, len=%llu)"
" cancelled because transaction is not started.\n", " cancelled because transaction is not started.\n",
(unsigned long long)off, (unsigned long long)len); (unsigned long long)off, (unsigned long long)len);
...@@ -3467,7 +3540,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type, ...@@ -3467,7 +3540,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
flush_dcache_page(bh->b_page); flush_dcache_page(bh->b_page);
unlock_buffer(bh); unlock_buffer(bh);
if (journal_quota) if (journal_quota)
err = ext4_journal_dirty_metadata(handle, bh); err = ext4_handle_dirty_metadata(handle, NULL, bh);
else { else {
/* Always do at least ordered writes for quotas */ /* Always do at least ordered writes for quotas */
err = ext4_jbd2_file_inode(handle, inode); err = ext4_jbd2_file_inode(handle, inode);
......
...@@ -457,7 +457,7 @@ static void ext4_xattr_update_super_block(handle_t *handle, ...@@ -457,7 +457,7 @@ static void ext4_xattr_update_super_block(handle_t *handle,
if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR); EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR);
sb->s_dirt = 1; sb->s_dirt = 1;
ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh); ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh);
} }
} }
...@@ -487,9 +487,9 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, ...@@ -487,9 +487,9 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
ext4_forget(handle, 1, inode, bh, bh->b_blocknr); ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
} else { } else {
le32_add_cpu(&BHDR(bh)->h_refcount, -1); le32_add_cpu(&BHDR(bh)->h_refcount, -1);
error = ext4_journal_dirty_metadata(handle, bh); error = ext4_handle_dirty_metadata(handle, inode, bh);
if (IS_SYNC(inode)) if (IS_SYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
DQUOT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1);
ea_bdebug(bh, "refcount now=%d; releasing", ea_bdebug(bh, "refcount now=%d; releasing",
le32_to_cpu(BHDR(bh)->h_refcount)); le32_to_cpu(BHDR(bh)->h_refcount));
...@@ -724,8 +724,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -724,8 +724,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
if (error == -EIO) if (error == -EIO)
goto bad_block; goto bad_block;
if (!error) if (!error)
error = ext4_journal_dirty_metadata(handle, error = ext4_handle_dirty_metadata(handle,
bs->bh); inode,
bs->bh);
if (error) if (error)
goto cleanup; goto cleanup;
goto inserted; goto inserted;
...@@ -794,8 +795,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -794,8 +795,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
ea_bdebug(new_bh, "reusing; refcount now=%d", ea_bdebug(new_bh, "reusing; refcount now=%d",
le32_to_cpu(BHDR(new_bh)->h_refcount)); le32_to_cpu(BHDR(new_bh)->h_refcount));
unlock_buffer(new_bh); unlock_buffer(new_bh);
error = ext4_journal_dirty_metadata(handle, error = ext4_handle_dirty_metadata(handle,
new_bh); inode,
new_bh);
if (error) if (error)
goto cleanup_dquot; goto cleanup_dquot;
} }
...@@ -833,7 +835,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -833,7 +835,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
set_buffer_uptodate(new_bh); set_buffer_uptodate(new_bh);
unlock_buffer(new_bh); unlock_buffer(new_bh);
ext4_xattr_cache_insert(new_bh); ext4_xattr_cache_insert(new_bh);
error = ext4_journal_dirty_metadata(handle, new_bh); error = ext4_handle_dirty_metadata(handle,
inode, new_bh);
if (error) if (error)
goto cleanup; goto cleanup;
} }
...@@ -1040,7 +1043,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, ...@@ -1040,7 +1043,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
*/ */
is.iloc.bh = NULL; is.iloc.bh = NULL;
if (IS_SYNC(inode)) if (IS_SYNC(inode))
handle->h_sync = 1; ext4_handle_sync(handle);
} }
cleanup: cleanup:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment