Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6487a9d3 authored by Curt Wohlgemuth's avatar Curt Wohlgemuth Committed by Theodore Ts'o
Browse files

ext4: More buffer head reference leaks



After the patch I posted last week regarding buffer head ref leaks in
no-journal mode, I looked at all the code that uses buffer heads and
searched for more potential leaks.

The patch below fixes the issues I found; these can occur even when a
journal is present.

The change to inode.c fixes a double release if
ext4_journal_get_create_access() fails.

The changes to namei.c are more complicated.  add_dirent_to_buf() will
release the input buffer head EXCEPT when it returns -ENOSPC.  There are
some callers of this routine that don't always do the brelse() in the event
that -ENOSPC is returned.  Unfortunately, to put this fix into ext4_add_entry()
required capturing the return value of make_indexed_dir() and
add_dirent_to_buf().

Signed-off-by: default avatarCurt Wohlgemuth <curtw@google.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent f6f50e28
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -762,8 +762,9 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
		BUFFER_TRACE(bh, "call get_create_access");
		err = ext4_journal_get_create_access(handle, bh);
		if (err) {
			/* Don't brelse(bh) here; it's done in
			 * ext4_journal_forget() below */
			unlock_buffer(bh);
			brelse(bh);
			goto failed;
		}

+12 −4
Original line number Diff line number Diff line
@@ -1518,8 +1518,12 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
			return retval;

		if (blocks == 1 && !dx_fallback &&
		    EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
			return make_indexed_dir(handle, dentry, inode, bh);
		    EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
			retval = make_indexed_dir(handle, dentry, inode, bh);
			if (retval == -ENOSPC)
				brelse(bh);
			return retval;
		}
		brelse(bh);
	}
	bh = ext4_append(handle, dir, &block, &retval);
@@ -1528,7 +1532,10 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
	de = (struct ext4_dir_entry_2 *) bh->b_data;
	de->inode = 0;
	de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
	return add_dirent_to_buf(handle, dentry, inode, de, bh);
	retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
	if (retval == -ENOSPC)
		brelse(bh);
	return retval;
}

/*
@@ -1657,6 +1664,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
	if (!de)
		goto cleanup;
	err = add_dirent_to_buf(handle, dentry, inode, de, bh);
	if (err != -ENOSPC)
		bh = NULL;
	goto cleanup;