diff options
| author | Curt Wohlgemuth <curtw@google.com> | 2009-09-29 11:01:03 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2009-09-29 11:01:03 -0400 |
| commit | d3d1faf6a74496ea4435fd057c6a2cad49f3e523 (patch) | |
| tree | 9f1cc0e2efb9a4fe42bb6b57c087d8450a854dc1 | |
| parent | f3dc272fd5e2ae08244796bb39e7e1ce4b25d3b3 (diff) | |
ext4: Handle nested ext4_journal_start/stop calls without a journal
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>
| -rw-r--r-- | fs/ext4/ext4_jbd2.h | 6 | ||||
| -rw-r--r-- | fs/ext4/namei.c | 3 | ||||
| -rw-r--r-- | fs/ext4/super.c | 42 |
3 files changed, 38 insertions, 13 deletions
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index 139fb8cb87e4..a2865980342f 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
| @@ -161,11 +161,13 @@ int __ext4_handle_dirty_metadata(const char *where, handle_t *handle, | |||
| 161 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); | 161 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); |
| 162 | int __ext4_journal_stop(const char *where, handle_t *handle); | 162 | int __ext4_journal_stop(const char *where, handle_t *handle); |
| 163 | 163 | ||
| 164 | #define EXT4_NOJOURNAL_HANDLE ((handle_t *) 0x1) | 164 | #define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096) |
| 165 | 165 | ||
| 166 | /* Note: Do not use this for NULL handles. This is only to determine if | ||
| 167 | * a properly allocated handle is using a journal or not. */ | ||
| 166 | static inline int ext4_handle_valid(handle_t *handle) | 168 | static inline int ext4_handle_valid(handle_t *handle) |
| 167 | { | 169 | { |
| 168 | if (handle == EXT4_NOJOURNAL_HANDLE) | 170 | if ((unsigned long)handle < EXT4_NOJOURNAL_MAX_REF_COUNT) |
| 169 | return 0; | 171 | return 0; |
| 170 | return 1; | 172 | return 1; |
| 171 | } | 173 | } |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 42f81d285cd5..7c8fe80bacdd 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -2076,7 +2076,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
| 2076 | struct ext4_iloc iloc; | 2076 | struct ext4_iloc iloc; |
| 2077 | int err = 0; | 2077 | int err = 0; |
| 2078 | 2078 | ||
| 2079 | if (!ext4_handle_valid(handle)) | 2079 | /* ext4_handle_valid() assumes a valid handle_t pointer */ |
| 2080 | if (handle && !ext4_handle_valid(handle)) | ||
| 2080 | return 0; | 2081 | return 0; |
| 2081 | 2082 | ||
| 2082 | mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); | 2083 | mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f095c60b569e..3f7e7010c098 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -189,6 +189,36 @@ void ext4_itable_unused_set(struct super_block *sb, | |||
| 189 | bg->bg_itable_unused_hi = cpu_to_le16(count >> 16); | 189 | bg->bg_itable_unused_hi = cpu_to_le16(count >> 16); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | |||
| 193 | /* Just increment the non-pointer handle value */ | ||
| 194 | static handle_t *ext4_get_nojournal(void) | ||
| 195 | { | ||
| 196 | handle_t *handle = current->journal_info; | ||
| 197 | unsigned long ref_cnt = (unsigned long)handle; | ||
| 198 | |||
| 199 | BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); | ||
| 200 | |||
| 201 | ref_cnt++; | ||
| 202 | handle = (handle_t *)ref_cnt; | ||
| 203 | |||
| 204 | current->journal_info = handle; | ||
| 205 | return handle; | ||
| 206 | } | ||
| 207 | |||
| 208 | |||
| 209 | /* Decrement the non-pointer handle value */ | ||
| 210 | static void ext4_put_nojournal(handle_t *handle) | ||
| 211 | { | ||
| 212 | unsigned long ref_cnt = (unsigned long)handle; | ||
| 213 | |||
| 214 | BUG_ON(ref_cnt == 0); | ||
| 215 | |||
| 216 | ref_cnt--; | ||
| 217 | handle = (handle_t *)ref_cnt; | ||
| 218 | |||
| 219 | current->journal_info = handle; | ||
| 220 | } | ||
| 221 | |||
| 192 | /* | 222 | /* |
| 193 | * Wrappers for jbd2_journal_start/end. | 223 | * Wrappers for jbd2_journal_start/end. |
| 194 | * | 224 | * |
| @@ -215,11 +245,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) | |||
| 215 | } | 245 | } |
| 216 | return jbd2_journal_start(journal, nblocks); | 246 | return jbd2_journal_start(journal, nblocks); |
| 217 | } | 247 | } |
| 218 | /* | 248 | return ext4_get_nojournal(); |
| 219 | * We're not journaling, return the appropriate indication. | ||
| 220 | */ | ||
| 221 | current->journal_info = EXT4_NOJOURNAL_HANDLE; | ||
| 222 | return current->journal_info; | ||
| 223 | } | 249 | } |
| 224 | 250 | ||
| 225 | /* | 251 | /* |
| @@ -235,11 +261,7 @@ int __ext4_journal_stop(const char *where, handle_t *handle) | |||
| 235 | int rc; | 261 | int rc; |
| 236 | 262 | ||
| 237 | if (!ext4_handle_valid(handle)) { | 263 | if (!ext4_handle_valid(handle)) { |
| 238 | /* | 264 | ext4_put_nojournal(handle); |
| 239 | * Do this here since we don't call jbd2_journal_stop() in | ||
| 240 | * no-journal mode. | ||
| 241 | */ | ||
| 242 | current->journal_info = NULL; | ||
| 243 | return 0; | 265 | return 0; |
| 244 | } | 266 | } |
| 245 | sb = handle->h_transaction->t_journal->j_private; | 267 | sb = handle->h_transaction->t_journal->j_private; |
