Commit e6b5d301 authored by Curt Wohlgemuth's avatar Curt Wohlgemuth Committed by Theodore Ts'o

ext4: Fix buffer head reference leak in no-journal mode

We found a problem with buffer head reference leaks when using an ext4
partition without a journal.  In particular, calls to ext4_forget() would
not to a brelse() on the input buffer head, which will cause pages they
belong to to not be reclaimable.

Further investigation showed that all places where ext4_journal_forget() and
ext4_journal_revoke() are called are subject to the same problem.  The patch
below changes __ext4_journal_forget/__ext4_journal_revoke to do an explicit
release of the buffer head when the journal handle isn't valid.
Signed-off-by: default avatarCurt Wohlgemuth <curtw@google.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 62e086be
...@@ -43,6 +43,8 @@ int __ext4_journal_forget(const char *where, handle_t *handle, ...@@ -43,6 +43,8 @@ int __ext4_journal_forget(const char *where, handle_t *handle,
ext4_journal_abort_handle(where, __func__, bh, ext4_journal_abort_handle(where, __func__, bh,
handle, err); handle, err);
} }
else
brelse(bh);
return err; return err;
} }
...@@ -57,6 +59,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle, ...@@ -57,6 +59,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle,
ext4_journal_abort_handle(where, __func__, bh, ext4_journal_abort_handle(where, __func__, bh,
handle, err); handle, err);
} }
else
brelse(bh);
return err; return err;
} }
......
...@@ -131,9 +131,11 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle, ...@@ -131,9 +131,11 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
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);
/* When called with an invalid handle, this will still do a put on the BH */
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);
/* When called with an invalid handle, this will still do a put on the BH */
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);
......
...@@ -78,16 +78,14 @@ static int ext4_inode_is_fast_symlink(struct inode *inode) ...@@ -78,16 +78,14 @@ static int ext4_inode_is_fast_symlink(struct inode *inode)
* 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. * If the handle isn't valid we're not journaling, but we still need to
* call into ext4_journal_revoke() to put the buffer head.
*/ */
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");
......
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