Skip to content

Commit fb265c9

Browse files
committed
ext4: add ext4_sb_bread() to disambiguate ENOMEM cases
Today, when sb_bread() returns NULL, this can either be because of an I/O error or because the system failed to allocate the buffer. Since it's an old interface, changing would require changing many call sites. So instead we create our own ext4_sb_bread(), which also allows us to set the REQ_META flag. Also fixed a problem in the xattr code where a NULL return in a function could also mean that the xattr was not found, which could lead to the wrong error getting returned to userspace. Fixes: ac27a0e ("ext4: initial copy of files from ext3") Cc: stable@kernel.org # 2.6.19 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 2e6e902 commit fb265c9

File tree

5 files changed

+115
-94
lines changed

5 files changed

+115
-94
lines changed

fs/ext4/ext4.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,6 +2538,8 @@ extern int ext4_group_extend(struct super_block *sb,
25382538
extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
25392539

25402540
/* super.c */
2541+
extern struct buffer_head *ext4_sb_bread(struct super_block *sb,
2542+
sector_t block, int op_flags);
25412543
extern int ext4_seq_options_show(struct seq_file *seq, void *offset);
25422544
extern int ext4_calculate_overhead(struct super_block *sb);
25432545
extern void ext4_superblock_csum_set(struct super_block *sb);

fs/ext4/migrate.c

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ static int update_ind_extent_range(handle_t *handle, struct inode *inode,
116116
int i, retval = 0;
117117
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
118118

119-
bh = sb_bread(inode->i_sb, pblock);
120-
if (!bh)
121-
return -EIO;
119+
bh = ext4_sb_bread(inode->i_sb, pblock, 0);
120+
if (IS_ERR(bh))
121+
return PTR_ERR(bh);
122122

123123
i_data = (__le32 *)bh->b_data;
124124
for (i = 0; i < max_entries; i++) {
@@ -145,9 +145,9 @@ static int update_dind_extent_range(handle_t *handle, struct inode *inode,
145145
int i, retval = 0;
146146
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
147147

148-
bh = sb_bread(inode->i_sb, pblock);
149-
if (!bh)
150-
return -EIO;
148+
bh = ext4_sb_bread(inode->i_sb, pblock, 0);
149+
if (IS_ERR(bh))
150+
return PTR_ERR(bh);
151151

152152
i_data = (__le32 *)bh->b_data;
153153
for (i = 0; i < max_entries; i++) {
@@ -175,9 +175,9 @@ static int update_tind_extent_range(handle_t *handle, struct inode *inode,
175175
int i, retval = 0;
176176
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
177177

178-
bh = sb_bread(inode->i_sb, pblock);
179-
if (!bh)
180-
return -EIO;
178+
bh = ext4_sb_bread(inode->i_sb, pblock, 0);
179+
if (IS_ERR(bh))
180+
return PTR_ERR(bh);
181181

182182
i_data = (__le32 *)bh->b_data;
183183
for (i = 0; i < max_entries; i++) {
@@ -224,9 +224,9 @@ static int free_dind_blocks(handle_t *handle,
224224
struct buffer_head *bh;
225225
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
226226

227-
bh = sb_bread(inode->i_sb, le32_to_cpu(i_data));
228-
if (!bh)
229-
return -EIO;
227+
bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0);
228+
if (IS_ERR(bh))
229+
return PTR_ERR(bh);
230230

231231
tmp_idata = (__le32 *)bh->b_data;
232232
for (i = 0; i < max_entries; i++) {
@@ -254,9 +254,9 @@ static int free_tind_blocks(handle_t *handle,
254254
struct buffer_head *bh;
255255
unsigned long max_entries = inode->i_sb->s_blocksize >> 2;
256256

257-
bh = sb_bread(inode->i_sb, le32_to_cpu(i_data));
258-
if (!bh)
259-
return -EIO;
257+
bh = ext4_sb_bread(inode->i_sb, le32_to_cpu(i_data), 0);
258+
if (IS_ERR(bh))
259+
return PTR_ERR(bh);
260260

261261
tmp_idata = (__le32 *)bh->b_data;
262262
for (i = 0; i < max_entries; i++) {
@@ -382,9 +382,9 @@ static int free_ext_idx(handle_t *handle, struct inode *inode,
382382
struct ext4_extent_header *eh;
383383

384384
block = ext4_idx_pblock(ix);
385-
bh = sb_bread(inode->i_sb, block);
386-
if (!bh)
387-
return -EIO;
385+
bh = ext4_sb_bread(inode->i_sb, block, 0);
386+
if (IS_ERR(bh))
387+
return PTR_ERR(bh);
388388

389389
eh = (struct ext4_extent_header *)bh->b_data;
390390
if (eh->eh_depth != 0) {

fs/ext4/resize.c

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,12 @@ static int verify_group_input(struct super_block *sb,
127127
else if (free_blocks_count < 0)
128128
ext4_warning(sb, "Bad blocks count %u",
129129
input->blocks_count);
130-
else if (!(bh = sb_bread(sb, end - 1)))
130+
else if (IS_ERR(bh = ext4_sb_bread(sb, end - 1, 0))) {
131+
err = PTR_ERR(bh);
132+
bh = NULL;
131133
ext4_warning(sb, "Cannot read last block (%llu)",
132134
end - 1);
133-
else if (outside(input->block_bitmap, start, end))
135+
} else if (outside(input->block_bitmap, start, end))
134136
ext4_warning(sb, "Block bitmap not in group (block %llu)",
135137
(unsigned long long)input->block_bitmap);
136138
else if (outside(input->inode_bitmap, start, end))
@@ -781,11 +783,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
781783
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
782784
unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb);
783785
ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
784-
struct buffer_head **o_group_desc, **n_group_desc;
785-
struct buffer_head *dind;
786-
struct buffer_head *gdb_bh;
786+
struct buffer_head **o_group_desc, **n_group_desc = NULL;
787+
struct buffer_head *dind = NULL;
788+
struct buffer_head *gdb_bh = NULL;
787789
int gdbackups;
788-
struct ext4_iloc iloc;
790+
struct ext4_iloc iloc = { .bh = NULL };
789791
__le32 *data;
790792
int err;
791793

@@ -794,40 +796,41 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
794796
"EXT4-fs: ext4_add_new_gdb: adding group block %lu\n",
795797
gdb_num);
796798

797-
gdb_bh = sb_bread(sb, gdblock);
798-
if (!gdb_bh)
799-
return -EIO;
799+
gdb_bh = ext4_sb_bread(sb, gdblock, 0);
800+
if (IS_ERR(gdb_bh))
801+
return PTR_ERR(gdb_bh);
800802

801803
gdbackups = verify_reserved_gdb(sb, group, gdb_bh);
802804
if (gdbackups < 0) {
803805
err = gdbackups;
804-
goto exit_bh;
806+
goto errout;
805807
}
806808

807809
data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK;
808-
dind = sb_bread(sb, le32_to_cpu(*data));
809-
if (!dind) {
810-
err = -EIO;
811-
goto exit_bh;
810+
dind = ext4_sb_bread(sb, le32_to_cpu(*data), 0);
811+
if (IS_ERR(dind)) {
812+
err = PTR_ERR(dind);
813+
dind = NULL;
814+
goto errout;
812815
}
813816

814817
data = (__le32 *)dind->b_data;
815818
if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) {
816819
ext4_warning(sb, "new group %u GDT block %llu not reserved",
817820
group, gdblock);
818821
err = -EINVAL;
819-
goto exit_dind;
822+
goto errout;
820823
}
821824

822825
BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
823826
err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
824827
if (unlikely(err))
825-
goto exit_dind;
828+
goto errout;
826829

827830
BUFFER_TRACE(gdb_bh, "get_write_access");
828831
err = ext4_journal_get_write_access(handle, gdb_bh);
829832
if (unlikely(err))
830-
goto exit_dind;
833+
goto errout;
831834

832835
BUFFER_TRACE(dind, "get_write_access");
833836
err = ext4_journal_get_write_access(handle, dind);
@@ -837,7 +840,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
837840
/* ext4_reserve_inode_write() gets a reference on the iloc */
838841
err = ext4_reserve_inode_write(handle, inode, &iloc);
839842
if (unlikely(err))
840-
goto exit_dind;
843+
goto errout;
841844

842845
n_group_desc = ext4_kvmalloc((gdb_num + 1) *
843846
sizeof(struct buffer_head *),
@@ -846,7 +849,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
846849
err = -ENOMEM;
847850
ext4_warning(sb, "not enough memory for %lu groups",
848851
gdb_num + 1);
849-
goto exit_inode;
852+
goto errout;
850853
}
851854

852855
/*
@@ -862,7 +865,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
862865
err = ext4_handle_dirty_metadata(handle, NULL, dind);
863866
if (unlikely(err)) {
864867
ext4_std_error(sb, err);
865-
goto exit_inode;
868+
goto errout;
866869
}
867870
inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >>
868871
(9 - EXT4_SB(sb)->s_cluster_bits);
@@ -871,8 +874,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
871874
err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh);
872875
if (unlikely(err)) {
873876
ext4_std_error(sb, err);
874-
iloc.bh = NULL;
875-
goto exit_inode;
877+
goto errout;
876878
}
877879
brelse(dind);
878880

@@ -888,15 +890,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
888890
err = ext4_handle_dirty_super(handle, sb);
889891
if (err)
890892
ext4_std_error(sb, err);
891-
892893
return err;
893-
894-
exit_inode:
894+
errout:
895895
kvfree(n_group_desc);
896896
brelse(iloc.bh);
897-
exit_dind:
898897
brelse(dind);
899-
exit_bh:
900898
brelse(gdb_bh);
901899

902900
ext4_debug("leaving with error %d\n", err);
@@ -916,9 +914,9 @@ static int add_new_gdb_meta_bg(struct super_block *sb,
916914

917915
gdblock = ext4_meta_bg_first_block_no(sb, group) +
918916
ext4_bg_has_super(sb, group);
919-
gdb_bh = sb_bread(sb, gdblock);
920-
if (!gdb_bh)
921-
return -EIO;
917+
gdb_bh = ext4_sb_bread(sb, gdblock, 0);
918+
if (IS_ERR(gdb_bh))
919+
return PTR_ERR(gdb_bh);
922920
n_group_desc = ext4_kvmalloc((gdb_num + 1) *
923921
sizeof(struct buffer_head *),
924922
GFP_NOFS);
@@ -975,9 +973,10 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
975973
return -ENOMEM;
976974

977975
data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK;
978-
dind = sb_bread(sb, le32_to_cpu(*data));
979-
if (!dind) {
980-
err = -EIO;
976+
dind = ext4_sb_bread(sb, le32_to_cpu(*data), 0);
977+
if (IS_ERR(dind)) {
978+
err = PTR_ERR(dind);
979+
dind = NULL;
981980
goto exit_free;
982981
}
983982

@@ -996,9 +995,10 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
996995
err = -EINVAL;
997996
goto exit_bh;
998997
}
999-
primary[res] = sb_bread(sb, blk);
1000-
if (!primary[res]) {
1001-
err = -EIO;
998+
primary[res] = ext4_sb_bread(sb, blk, 0);
999+
if (IS_ERR(primary[res])) {
1000+
err = PTR_ERR(primary[res]);
1001+
primary[res] = NULL;
10021002
goto exit_bh;
10031003
}
10041004
gdbackups = verify_reserved_gdb(sb, group, primary[res]);

fs/ext4/super.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,29 @@ MODULE_ALIAS_FS("ext3");
140140
MODULE_ALIAS("ext3");
141141
#define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type)
142142

143+
/*
144+
* This works like sb_bread() except it uses ERR_PTR for error
145+
* returns. Currently with sb_bread it's impossible to distinguish
146+
* between ENOMEM and EIO situations (since both result in a NULL
147+
* return.
148+
*/
149+
struct buffer_head *
150+
ext4_sb_bread(struct super_block *sb, sector_t block, int op_flags)
151+
{
152+
struct buffer_head *bh = sb_getblk(sb, block);
153+
154+
if (bh == NULL)
155+
return ERR_PTR(-ENOMEM);
156+
if (buffer_uptodate(bh))
157+
return bh;
158+
ll_rw_block(REQ_OP_READ, REQ_META | op_flags, 1, &bh);
159+
wait_on_buffer(bh);
160+
if (buffer_uptodate(bh))
161+
return bh;
162+
put_bh(bh);
163+
return ERR_PTR(-EIO);
164+
}
165+
143166
static int ext4_verify_csum_type(struct super_block *sb,
144167
struct ext4_super_block *es)
145168
{

0 commit comments

Comments
 (0)