udf: Remove declarations of arrays of size UDF_NAME_LEN (256 bytes)
authorJan Kara <jack@suse.cz>
Tue, 4 Mar 2008 13:14:05 +0000 (14:14 +0100)
committerJan Kara <jack@suse.cz>
Thu, 17 Apr 2008 12:23:04 +0000 (14:23 +0200)
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 <jack@suse.cz>
fs/udf/dir.c
fs/udf/namei.c

index 31feef9..62dc270 100644 (file)
 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)
index e9f5872..68686b7 100644 (file)
@@ -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;