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; |