summaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2010-11-25 03:56:24 +0100
committerJan Kara <jack@suse.cz>2011-01-06 17:03:57 +0100
commit4651c5900e7a3c84d4b70412f8bbc40c1bcb50cf (patch)
treebba6310572481952bb03079909712bf664a054fc /fs/udf
parentudf: Protect udf_file_aio_write from possible races (diff)
downloadlinux-4651c5900e7a3c84d4b70412f8bbc40c1bcb50cf.tar.xz
linux-4651c5900e7a3c84d4b70412f8bbc40c1bcb50cf.zip
udf: Fix directory corruption after extent merging
If udf_bread() called from udf_add_entry() managed to merge created extent to an already existing one (or if previous extents could be merged), the code truncating the last extent to proper size would just overwrite the freshly allocated extent with an extent that used to be in that place. This obviously results in a directory corruption. Fix the problem by properly reloading the last extent. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/namei.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 26815a25379d..a2974f7563a2 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -471,15 +471,19 @@ add:
f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
if (!fibh->ebh)
goto out_err;
+ /* Extents could have been merged, invalidate our position */
+ brelse(epos.bh);
+ epos.bh = NULL;
+ epos.block = dinfo->i_location;
+ epos.offset = udf_file_entry_alloc_offset(dir);
if (!fibh->soffset) {
- if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
- (EXT_RECORDED_ALLOCATED >> 30)) {
- block = eloc.logicalBlockNum + ((elen - 1) >>
+ /* Find the freshly allocated block */
+ while (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
+ (EXT_RECORDED_ALLOCATED >> 30))
+ ;
+ block = eloc.logicalBlockNum + ((elen - 1) >>
dir->i_sb->s_blocksize_bits);
- } else
- block++;
-
brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
fi = (struct fileIdentDesc *)(fibh->sbh->b_data);