From b80697c14dcacd83ed1b78e26ad93b25ecc52c5e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 4 Mar 2008 14:14:05 +0100 Subject: [PATCH] udf: Remove declarations of arrays of size UDF_NAME_LEN (256 bytes) There are several places in UDF where we declared temporary arrays of UDF_NAME_LEN bytes on stack. This is not nice to stack usage so this patch changes those places to use kmalloc() instead. Also clean up bail-out paths in those functions when we are changing them. Signed-off-by: Jan Kara --- fs/udf/dir.c | 57 ++++++++++++------------- fs/udf/namei.c | 128 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 93 insertions(+), 92 deletions(-) diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 31feef9..62dc270 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -39,13 +39,13 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, filldir_t filldir, void *dirent) { - struct udf_fileident_bh fibh; + struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL}; struct fileIdentDesc *fi = NULL; struct fileIdentDesc cfi; int block, iblock; loff_t nf_pos = (filp->f_pos - 1) << 2; int flen; - char fname[UDF_NAME_LEN]; + char *fname = NULL; char *nameptr; uint16_t liu; uint8_t lfi; @@ -54,23 +54,32 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, kernel_lb_addr eloc; uint32_t elen; sector_t offset; - int i, num; + int i, num, ret = 0; unsigned int dt_type; struct extent_position epos = { NULL, 0, {0, 0} }; struct udf_inode_info *iinfo; if (nf_pos >= size) - return 0; + goto out; + + fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!fname) { + ret = -ENOMEM; + goto out; + } if (nf_pos == 0) nf_pos = udf_ext0_offset(dir); fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); iinfo = UDF_I(dir); - if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { - fibh.sbh = fibh.ebh = NULL; - } else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, - &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) { + if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, + &epos, &eloc, &elen, &offset) + != (EXT_RECORDED_ALLOCATED >> 30)) { + ret = -ENOENT; + goto out; + } block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -83,8 +92,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, } if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { - brelse(epos.bh); - return -EIO; + ret = -EIO; + goto out; } if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { @@ -105,9 +114,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, brelse(bha[i]); } } - } else { - brelse(epos.bh); - return -ENOENT; } while (nf_pos < size) { @@ -115,13 +121,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset); - if (!fi) { - if (fibh.sbh != fibh.ebh) - brelse(fibh.ebh); - brelse(fibh.sbh); - brelse(epos.bh); - return 0; - } + if (!fi) + goto out; liu = le16_to_cpu(cfi.lengthOfImpUse); lfi = cfi.lengthFileIdent; @@ -167,25 +168,21 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, dt_type = DT_UNKNOWN; } - if (flen) { - if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) { - if (fibh.sbh != fibh.ebh) - brelse(fibh.ebh); - brelse(fibh.sbh); - brelse(epos.bh); - return 0; - } - } + if (flen && filldir(dirent, fname, flen, filp->f_pos, + iblock, dt_type) < 0) + goto out; } /* end while */ filp->f_pos = (nf_pos >> 2) + 1; +out: if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); brelse(epos.bh); + kfree(fname); - return 0; + return ret; } static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index e9f5872..68686b7 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -149,7 +149,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, struct fileIdentDesc *fi = NULL; loff_t f_pos; int block, flen; - char fname[UDF_NAME_LEN]; + char *fname = NULL; char *nameptr; uint8_t lfi; uint16_t liu; @@ -163,12 +163,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, size = udf_ext0_offset(dir) + dir->i_size; f_pos = udf_ext0_offset(dir); + fibh->sbh = fibh->ebh = NULL; fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); - if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) - fibh->sbh = fibh->ebh = NULL; - else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, - &epos, &eloc, &elen, &offset) == - (EXT_RECORDED_ALLOCATED >> 30)) { + if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, + &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) + goto out_err; block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -179,25 +179,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, offset = 0; fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); - if (!fibh->sbh) { - brelse(epos.bh); - return NULL; - } - } else { - brelse(epos.bh); - return NULL; + if (!fibh->sbh) + goto out_err; } + fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!fname) + goto out_err; + while (f_pos < size) { fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset); - if (!fi) { - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); - brelse(epos.bh); - return NULL; - } + if (!fi) + goto out_err; liu = le16_to_cpu(cfi->lengthOfImpUse); lfi = cfi->lengthFileIdent; @@ -237,18 +231,20 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); if (flen && udf_match(flen, fname, dentry->d_name.len, - dentry->d_name.name)) { - brelse(epos.bh); - return fi; - } + dentry->d_name.name)) + goto out_ok; } +out_err: + fi = NULL; if (fibh->sbh != fibh->ebh) brelse(fibh->ebh); brelse(fibh->sbh); +out_ok: brelse(epos.bh); + kfree(fname); - return NULL; + return fi; } static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, @@ -303,7 +299,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, { struct super_block *sb = dir->i_sb; struct fileIdentDesc *fi = NULL; - char name[UDF_NAME_LEN]; + char *name = NULL; int namelen; loff_t f_pos; loff_t size = udf_ext0_offset(dir) + dir->i_size; @@ -317,16 +313,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, struct extent_position epos = {}; struct udf_inode_info *dinfo; + fibh->sbh = fibh->ebh = NULL; + name = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!name) { + *err = -ENOMEM; + goto out_err; + } + if (dentry) { if (!dentry->d_name.len) { *err = -EINVAL; - return NULL; + goto out_err; } namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len); if (!namelen) { *err = -ENAMETOOLONG; - return NULL; + goto out_err; } } else { namelen = 0; @@ -338,11 +341,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); dinfo = UDF_I(dir); - if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) - fibh->sbh = fibh->ebh = NULL; - else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, - &epos, &eloc, &elen, &offset) == - (EXT_RECORDED_ALLOCATED >> 30)) { + if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, + &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { + block = udf_get_lb_pblock(dir->i_sb, + dinfo->i_location, 0); + fibh->soffset = fibh->eoffset = sb->s_blocksize; + goto add; + } block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -354,17 +360,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); if (!fibh->sbh) { - brelse(epos.bh); *err = -EIO; - return NULL; + goto out_err; } block = dinfo->i_location.logicalBlockNum; - } else { - block = udf_get_lb_pblock(dir->i_sb, dinfo->i_location, 0); - fibh->sbh = fibh->ebh = NULL; - fibh->soffset = fibh->eoffset = sb->s_blocksize; - goto add; } while (f_pos < size) { @@ -372,12 +372,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, &elen, &offset); if (!fi) { - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); - brelse(epos.bh); *err = -EIO; - return NULL; + goto out_err; } liu = le16_to_cpu(cfi->lengthOfImpUse); @@ -386,7 +382,6 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) { - brelse(epos.bh); cfi->descTag.tagSerialNum = cpu_to_le16(1); cfi->fileVersionNum = cpu_to_le16(1); cfi->fileCharacteristics = 0; @@ -394,10 +389,10 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, cfi->lengthOfImpUse = cpu_to_le16(0); if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) - return fi; + goto out_ok; else { *err = -EIO; - return NULL; + goto out_err; } } } @@ -427,7 +422,7 @@ add: fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err); if (!fibh->sbh) - return NULL; + goto out_err; epos.block = dinfo->i_location; epos.offset = udf_file_entry_alloc_offset(dir); /* Load extent udf_expand_dir_adinicb() has created */ @@ -468,11 +463,8 @@ add: dir->i_sb->s_blocksize_bits); fibh->ebh = udf_bread(dir, f_pos >> dir->i_sb->s_blocksize_bits, 1, err); - if (!fibh->ebh) { - brelse(epos.bh); - brelse(fibh->sbh); - return NULL; - } + if (!fibh->ebh) + goto out_err; if (!fibh->soffset) { if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == @@ -503,20 +495,25 @@ add: cfi->lengthFileIdent = namelen; cfi->lengthOfImpUse = cpu_to_le16(0); if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { - brelse(epos.bh); dir->i_size += nfidlen; if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) dinfo->i_lenAlloc += nfidlen; mark_inode_dirty(dir); - return fi; + goto out_ok; } else { - brelse(epos.bh); - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); *err = -EIO; - return NULL; + goto out_err; } + +out_err: + fi = NULL; + if (fibh->sbh != fibh->ebh) + brelse(fibh->ebh); + brelse(fibh->sbh); +out_ok: + brelse(epos.bh); + kfree(name); + return fi; } static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, @@ -871,7 +868,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, char *ea; int err; int block; - char name[UDF_NAME_LEN]; + char *name = NULL; int namelen; struct buffer_head *bh; struct udf_inode_info *iinfo; @@ -881,6 +878,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, if (!inode) goto out; + name = kmalloc(UDF_NAME_LEN, GFP_NOFS); + if (!name) { + err = -ENOMEM; + goto out_no_entry; + } + iinfo = UDF_I(inode); inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_data.a_ops = &udf_symlink_aops; @@ -1020,6 +1023,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, err = 0; out: + kfree(name); unlock_kernel(); return err; -- 1.8.2.3