| From 8f52450f144ba68f24eb23d37c940c7098889391 Mon Sep 17 00:00:00 2001 |
| From: Curt Wohlgemuth <curtw@google.com> |
| Date: Tue, 29 Sep 2009 11:01:03 -0400 |
| Subject: [PATCH 48/85] ext4: Handle nested ext4_journal_start/stop calls without a journal |
| |
| (cherry picked from commit d3d1faf6a74496ea4435fd057c6a2cad49f3e523) |
| |
| This patch fixes a problem with handling nested calls to |
| ext4_journal_start/ext4_journal_stop, when there is no journal present. |
| |
| Signed-off-by: Curt Wohlgemuth <curtw@google.com> |
| Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| fs/ext4/ext4_jbd2.h | 6 ++++-- |
| fs/ext4/namei.c | 3 ++- |
| fs/ext4/super.c | 42 ++++++++++++++++++++++++++++++++---------- |
| 3 files changed, 38 insertions(+), 13 deletions(-) |
| |
| --- a/fs/ext4/ext4_jbd2.h |
| +++ b/fs/ext4/ext4_jbd2.h |
| @@ -161,11 +161,13 @@ int __ext4_handle_dirty_metadata(const c |
| handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); |
| int __ext4_journal_stop(const char *where, handle_t *handle); |
| |
| -#define EXT4_NOJOURNAL_HANDLE ((handle_t *) 0x1) |
| +#define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096) |
| |
| +/* Note: Do not use this for NULL handles. This is only to determine if |
| + * a properly allocated handle is using a journal or not. */ |
| static inline int ext4_handle_valid(handle_t *handle) |
| { |
| - if (handle == EXT4_NOJOURNAL_HANDLE) |
| + if ((unsigned long)handle < EXT4_NOJOURNAL_MAX_REF_COUNT) |
| return 0; |
| return 1; |
| } |
| --- a/fs/ext4/namei.c |
| +++ b/fs/ext4/namei.c |
| @@ -2068,7 +2068,8 @@ int ext4_orphan_del(handle_t *handle, st |
| struct ext4_iloc iloc; |
| int err = 0; |
| |
| - if (!ext4_handle_valid(handle)) |
| + /* ext4_handle_valid() assumes a valid handle_t pointer */ |
| + if (handle && !ext4_handle_valid(handle)) |
| return 0; |
| |
| mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -189,6 +189,36 @@ void ext4_itable_unused_set(struct super |
| bg->bg_itable_unused_hi = cpu_to_le16(count >> 16); |
| } |
| |
| + |
| +/* Just increment the non-pointer handle value */ |
| +static handle_t *ext4_get_nojournal(void) |
| +{ |
| + handle_t *handle = current->journal_info; |
| + unsigned long ref_cnt = (unsigned long)handle; |
| + |
| + BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); |
| + |
| + ref_cnt++; |
| + handle = (handle_t *)ref_cnt; |
| + |
| + current->journal_info = handle; |
| + return handle; |
| +} |
| + |
| + |
| +/* Decrement the non-pointer handle value */ |
| +static void ext4_put_nojournal(handle_t *handle) |
| +{ |
| + unsigned long ref_cnt = (unsigned long)handle; |
| + |
| + BUG_ON(ref_cnt == 0); |
| + |
| + ref_cnt--; |
| + handle = (handle_t *)ref_cnt; |
| + |
| + current->journal_info = handle; |
| +} |
| + |
| /* |
| * Wrappers for jbd2_journal_start/end. |
| * |
| @@ -215,11 +245,7 @@ handle_t *ext4_journal_start_sb(struct s |
| } |
| return jbd2_journal_start(journal, nblocks); |
| } |
| - /* |
| - * We're not journaling, return the appropriate indication. |
| - */ |
| - current->journal_info = EXT4_NOJOURNAL_HANDLE; |
| - return current->journal_info; |
| + return ext4_get_nojournal(); |
| } |
| |
| /* |
| @@ -235,11 +261,7 @@ int __ext4_journal_stop(const char *wher |
| 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; |
| + ext4_put_nojournal(handle); |
| return 0; |
| } |
| sb = handle->h_transaction->t_journal->j_private; |