mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Curt Wohlgemuth <curtw@google.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
		
							parent
							
								
									f6f50e28f0
								
							
						
					
					
						commit
						6487a9d3b5
					
				
					 2 changed files with 14 additions and 5 deletions
				
			
		| 
						 | 
					@ -762,8 +762,9 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
 | 
				
			||||||
		BUFFER_TRACE(bh, "call get_create_access");
 | 
							BUFFER_TRACE(bh, "call get_create_access");
 | 
				
			||||||
		err = ext4_journal_get_create_access(handle, bh);
 | 
							err = ext4_journal_get_create_access(handle, bh);
 | 
				
			||||||
		if (err) {
 | 
							if (err) {
 | 
				
			||||||
 | 
								/* Don't brelse(bh) here; it's done in
 | 
				
			||||||
 | 
								 * ext4_journal_forget() below */
 | 
				
			||||||
			unlock_buffer(bh);
 | 
								unlock_buffer(bh);
 | 
				
			||||||
			brelse(bh);
 | 
					 | 
				
			||||||
			goto failed;
 | 
								goto failed;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1518,8 +1518,12 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
 | 
				
			||||||
			return retval;
 | 
								return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (blocks == 1 && !dx_fallback &&
 | 
							if (blocks == 1 && !dx_fallback &&
 | 
				
			||||||
		    EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
 | 
							    EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
 | 
				
			||||||
			return make_indexed_dir(handle, dentry, inode, bh);
 | 
								retval = make_indexed_dir(handle, dentry, inode, bh);
 | 
				
			||||||
 | 
								if (retval == -ENOSPC)
 | 
				
			||||||
 | 
									brelse(bh);
 | 
				
			||||||
 | 
								return retval;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		brelse(bh);
 | 
							brelse(bh);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bh = ext4_append(handle, dir, &block, &retval);
 | 
						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 = (struct ext4_dir_entry_2 *) bh->b_data;
 | 
				
			||||||
	de->inode = 0;
 | 
						de->inode = 0;
 | 
				
			||||||
	de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
 | 
						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,7 +1664,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
 | 
				
			||||||
	if (!de)
 | 
						if (!de)
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
	err = add_dirent_to_buf(handle, dentry, inode, de, bh);
 | 
						err = add_dirent_to_buf(handle, dentry, inode, de, bh);
 | 
				
			||||||
	bh = NULL;
 | 
						if (err != -ENOSPC)
 | 
				
			||||||
 | 
							bh = NULL;
 | 
				
			||||||
	goto cleanup;
 | 
						goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
journal_error:
 | 
					journal_error:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue