]> Pileus Git - ~andy/linux/blobdiff - fs/udf/namei.c
lockd: convert nsm_mutex to a spinlock
[~andy/linux] / fs / udf / namei.c
index 23e530659fa5d3d19d37c22017cd4b6dbef1ad5b..ba5537d4bc151fcbe9575d89a30b2b0c860e92ae 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
+#include <linux/crc-itu-t.h>
 
 static inline int udf_match(int len1, const char *name1, int len2,
                            const char *name2)
@@ -97,25 +98,23 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
                memset(fibh->ebh->b_data, 0x00, padlen + offset);
        }
 
-       crc = udf_crc((uint8_t *)cfi + sizeof(tag),
-                     sizeof(struct fileIdentDesc) - sizeof(tag), 0);
+       crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag),
+                     sizeof(struct fileIdentDesc) - sizeof(tag));
 
        if (fibh->sbh == fibh->ebh) {
-               crc = udf_crc((uint8_t *)sfi->impUse,
+               crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
                              crclen + sizeof(tag) -
-                             sizeof(struct fileIdentDesc), crc);
+                             sizeof(struct fileIdentDesc));
        } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
-               crc = udf_crc(fibh->ebh->b_data +
+               crc = crc_itu_t(crc, fibh->ebh->b_data +
                                        sizeof(struct fileIdentDesc) +
                                        fibh->soffset,
                              crclen + sizeof(tag) -
-                                       sizeof(struct fileIdentDesc),
-                             crc);
+                                       sizeof(struct fileIdentDesc));
        } else {
-               crc = udf_crc((uint8_t *)sfi->impUse,
-                             -fibh->soffset - sizeof(struct fileIdentDesc),
-                             crc);
-               crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+               crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
+                             -fibh->soffset - sizeof(struct fileIdentDesc));
+               crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
        }
 
        cfi->descTag.descCRC = cpu_to_le16(crc);
@@ -149,7 +148,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;
@@ -158,47 +157,40 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
        uint32_t elen;
        sector_t offset;
        struct extent_position epos = {};
+       struct udf_inode_info *dinfo = UDF_I(dir);
 
-       size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
-       f_pos = (udf_ext0_offset(dir) >> 2);
+       size = udf_ext0_offset(dir) + dir->i_size;
+       f_pos = udf_ext0_offset(dir);
 
-       fibh->soffset = fibh->eoffset =
-               (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-       if (UDF_I(dir)->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 - 2),
-                             &epos, &eloc, &elen, &offset) ==
-                                       (EXT_RECORDED_ALLOCATED >> 30)) {
+       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) {
+               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 (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+                       if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
-                       else if (UDF_I(dir)->i_alloc_type ==
-                                                       ICBTAG_FLAG_AD_LONG)
+                       else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
                } else
                        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;
        }
 
-       while ((f_pos < size)) {
+       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;
@@ -238,53 +230,22 @@ 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;
 }
 
-/*
- * udf_lookup
- *
- * PURPOSE
- *     Look-up the inode for a given name.
- *
- * DESCRIPTION
- *     Required - lookup_dentry() will return -ENOTDIR if this routine is not
- *     available for a directory. The filesystem is useless if this routine is
- *     not available for at least the filesystem's root directory.
- *
- *     This routine is passed an incomplete dentry - it must be completed by
- *     calling d_add(dentry, inode). If the name does not exist, then the
- *     specified inode must be set to null. An error should only be returned
- *     when the lookup fails for a reason other than the name not existing.
- *     Note that the directory inode semaphore is held during the call.
- *
- *     Refer to lookup_dentry() in fs/namei.c
- *     lookup_dentry() -> lookup() -> real_lookup() -> .
- *
- * PRE-CONDITIONS
- *     dir                     Pointer to inode of parent directory.
- *     dentry                  Pointer to dentry to complete.
- *     nd                      Pointer to lookup nameidata
- *
- * POST-CONDITIONS
- *     <return>                Zero on success.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
-
 static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
                                 struct nameidata *nd)
 {
@@ -337,12 +298,10 @@ 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], fname[UDF_NAME_LEN];
+       char *name = NULL;
        int namelen;
        loff_t f_pos;
-       int flen;
-       char *nameptr;
-       loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
+       loff_t size = udf_ext0_offset(dir) + dir->i_size;
        int nfidlen;
        uint8_t lfi;
        uint16_t liu;
@@ -351,17 +310,25 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
        uint32_t elen;
        sector_t offset;
        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;
@@ -369,81 +336,51 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
 
        nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
 
-       f_pos = (udf_ext0_offset(dir) >> 2);
-
-       fibh->soffset = fibh->eoffset =
-                       (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
-       if (UDF_I(dir)->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 - 2),
-                             &epos, &eloc, &elen, &offset) ==
-                                       (EXT_RECORDED_ALLOCATED >> 30)) {
+       f_pos = udf_ext0_offset(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) {
+               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 (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+                       if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
-                       else if (UDF_I(dir)->i_alloc_type ==
-                                                       ICBTAG_FLAG_AD_LONG)
+                       else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
                } else
                        offset = 0;
 
                fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
                if (!fibh->sbh) {
-                       brelse(epos.bh);
                        *err = -EIO;
-                       return NULL;
+                       goto out_err;
                }
 
-               block = UDF_I(dir)->i_location.logicalBlockNum;
-
-       } else {
-               block = udf_get_lb_pblock(dir->i_sb, UDF_I(dir)->i_location, 0);
-               fibh->sbh = fibh->ebh = NULL;
-               fibh->soffset = fibh->eoffset = sb->s_blocksize;
-               goto add;
+               block = dinfo->i_location.logicalBlockNum;
        }
 
-       while ((f_pos < size)) {
+       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);
                        *err = -EIO;
-                       return NULL;
+                       goto out_err;
                }
 
                liu = le16_to_cpu(cfi->lengthOfImpUse);
                lfi = cfi->lengthFileIdent;
 
-               if (fibh->sbh == fibh->ebh)
-                       nameptr = fi->fileIdent + liu;
-               else {
-                       int poffset;    /* Unpaded ending offset */
-
-                       poffset = fibh->soffset + sizeof(struct fileIdentDesc) +
-                                       liu + lfi;
-
-                       if (poffset >= lfi)
-                               nameptr = (char *)(fibh->ebh->b_data +
-                                                  poffset - lfi);
-                       else {
-                               nameptr = fname;
-                               memcpy(nameptr, fi->fileIdent + liu,
-                                       lfi - poffset);
-                               memcpy(nameptr + lfi - poffset,
-                                       fibh->ebh->b_data, poffset);
-                       }
-               }
-
                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;
@@ -451,56 +388,44 @@ 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;
                                }
                        }
                }
-
-               if (!lfi || !dentry)
-                       continue;
-
-               flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
-               if (flen && udf_match(flen, fname, dentry->d_name.len,
-                                     dentry->d_name.name)) {
-                       if (fibh->sbh != fibh->ebh)
-                               brelse(fibh->ebh);
-                       brelse(fibh->sbh);
-                       brelse(epos.bh);
-                       *err = -EEXIST;
-                       return NULL;
-               }
        }
 
 add:
+       if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+               elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
+               if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+                       epos.offset -= sizeof(short_ad);
+               else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+                       epos.offset -= sizeof(long_ad);
+               udf_write_aext(dir, &epos, eloc, elen, 1);
+       }
        f_pos += nfidlen;
 
-       if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
+       if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
            sb->s_blocksize - fibh->eoffset < nfidlen) {
                brelse(epos.bh);
                epos.bh = NULL;
                fibh->soffset -= udf_ext0_offset(dir);
                fibh->eoffset -= udf_ext0_offset(dir);
-               f_pos -= (udf_ext0_offset(dir) >> 2);
+               f_pos -= udf_ext0_offset(dir);
                if (fibh->sbh != fibh->ebh)
                        brelse(fibh->ebh);
                brelse(fibh->sbh);
                fibh->sbh = fibh->ebh =
                                udf_expand_dir_adinicb(dir, &block, err);
                if (!fibh->sbh)
-                       return NULL;
-               epos.block = UDF_I(dir)->i_location;
-               eloc.logicalBlockNum = block;
-               eloc.partitionReferenceNum =
-                               UDF_I(dir)->i_location.partitionReferenceNum;
-               elen = dir->i_sb->s_blocksize;
+                       goto out_err;
+               epos.block = dinfo->i_location;
                epos.offset = udf_file_entry_alloc_offset(dir);
-               if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
-                       epos.offset += sizeof(short_ad);
-               else if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
-                       epos.offset += sizeof(long_ad);
+               /* Load extent udf_expand_dir_adinicb() has created */
+               udf_current_aext(dir, &epos, &eloc, &elen, 1);
        }
 
        if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
@@ -511,13 +436,13 @@ add:
                        fibh->sbh = fibh->ebh;
                }
 
-               if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
-                       block = UDF_I(dir)->i_location.logicalBlockNum;
+               if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+                       block = dinfo->i_location.logicalBlockNum;
                        fi = (struct fileIdentDesc *)
-                                       (UDF_I(dir)->i_ext.i_data +
+                                       (dinfo->i_ext.i_data +
                                         fibh->soffset -
                                         udf_ext0_offset(dir) +
-                                        UDF_I(dir)->i_lenEAttr);
+                                        dinfo->i_lenEAttr);
                } else {
                        block = eloc.logicalBlockNum +
                                        ((elen - 1) >>
@@ -536,13 +461,9 @@ add:
                block = eloc.logicalBlockNum + ((elen - 1) >>
                                                dir->i_sb->s_blocksize_bits);
                fibh->ebh = udf_bread(dir,
-                               f_pos >> (dir->i_sb->s_blocksize_bits - 2),
-                               1, err);
-               if (!fibh->ebh) {
-                       brelse(epos.bh);
-                       brelse(fibh->sbh);
-                       return NULL;
-               }
+                               f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
+               if (!fibh->ebh)
+                       goto out_err;
 
                if (!fibh->soffset) {
                        if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
@@ -573,20 +494,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 (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-                       UDF_I(dir)->i_lenAlloc += 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,
@@ -608,6 +534,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
        struct inode *inode;
        struct fileIdentDesc cfi, *fi;
        int err;
+       struct udf_inode_info *iinfo;
 
        lock_kernel();
        inode = udf_new_inode(dir, mode, &err);
@@ -616,7 +543,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
                return err;
        }
 
-       if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+       iinfo = UDF_I(inode);
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
                inode->i_data.a_ops = &udf_adinicb_aops;
        else
                inode->i_data.a_ops = &udf_aops;
@@ -634,9 +562,9 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
                return err;
        }
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
-       cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
+       cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
        *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-               cpu_to_le32(UDF_I(inode)->i_unique & 0x00000000FFFFFFFFUL);
+               cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
        if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
                mark_inode_dirty(dir);
@@ -656,6 +584,7 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
        struct udf_fileident_bh fibh;
        struct fileIdentDesc cfi, *fi;
        int err;
+       struct udf_inode_info *iinfo;
 
        if (!old_valid_dev(rdev))
                return -EINVAL;
@@ -666,6 +595,7 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
        if (!inode)
                goto out;
 
+       iinfo = UDF_I(inode);
        inode->i_uid = current->fsuid;
        init_special_inode(inode, mode, rdev);
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
@@ -677,9 +607,9 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
                return err;
        }
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
-       cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
+       cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
        *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-               cpu_to_le32(UDF_I(inode)->i_unique & 0x00000000FFFFFFFFUL);
+               cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
        if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
                mark_inode_dirty(dir);
@@ -702,6 +632,8 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct udf_fileident_bh fibh;
        struct fileIdentDesc cfi, *fi;
        int err;
+       struct udf_inode_info *dinfo = UDF_I(dir);
+       struct udf_inode_info *iinfo;
 
        lock_kernel();
        err = -EMLINK;
@@ -713,6 +645,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (!inode)
                goto out;
 
+       iinfo = UDF_I(inode);
        inode->i_op = &udf_dir_inode_operations;
        inode->i_fop = &udf_dir_operations;
        fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
@@ -724,9 +657,9 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        }
        inode->i_nlink = 2;
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
-       cfi.icb.extLocation = cpu_to_lelb(UDF_I(dir)->i_location);
+       cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
        *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-               cpu_to_le32(UDF_I(dir)->i_unique & 0x00000000FFFFFFFFUL);
+               cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
        cfi.fileCharacteristics =
                        FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
        udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
@@ -744,9 +677,9 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                goto out;
        }
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
-       cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
+       cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
        *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
-               cpu_to_le32(UDF_I(inode)->i_unique & 0x00000000FFFFFFFFUL);
+               cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
        cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
        udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
        inc_nlink(dir);
@@ -767,29 +700,27 @@ static int empty_dir(struct inode *dir)
        struct fileIdentDesc *fi, cfi;
        struct udf_fileident_bh fibh;
        loff_t f_pos;
-       loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
+       loff_t size = udf_ext0_offset(dir) + dir->i_size;
        int block;
        kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
        struct extent_position epos = {};
+       struct udf_inode_info *dinfo = UDF_I(dir);
 
-       f_pos = (udf_ext0_offset(dir) >> 2);
-
-       fibh.soffset = fibh.eoffset =
-                       (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+       f_pos = udf_ext0_offset(dir);
+       fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
 
-       if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+       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 - 2),
+       else 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, eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
-                       if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+                       if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(short_ad);
-                       else if (UDF_I(dir)->i_alloc_type ==
-                                                       ICBTAG_FLAG_AD_LONG)
+                       else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
                                epos.offset -= sizeof(long_ad);
                } else
                        offset = 0;
@@ -804,7 +735,7 @@ static int empty_dir(struct inode *dir)
                return 0;
        }
 
-       while ((f_pos < size)) {
+       while (f_pos < size) {
                fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
                                        &elen, &offset);
                if (!fi) {
@@ -936,41 +867,49 @@ 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;
 
        lock_kernel();
        inode = udf_new_inode(dir, S_IFLNK, &err);
        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;
        inode->i_op = &page_symlink_inode_operations;
 
-       if (UDF_I(inode)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+       if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
                kernel_lb_addr eloc;
                uint32_t elen;
 
                block = udf_new_block(inode->i_sb, inode,
-                               UDF_I(inode)->i_location.partitionReferenceNum,
-                               UDF_I(inode)->i_location.logicalBlockNum, &err);
+                               iinfo->i_location.partitionReferenceNum,
+                               iinfo->i_location.logicalBlockNum, &err);
                if (!block)
                        goto out_no_entry;
-               epos.block = UDF_I(inode)->i_location;
+               epos.block = iinfo->i_location;
                epos.offset = udf_file_entry_alloc_offset(inode);
                epos.bh = NULL;
                eloc.logicalBlockNum = block;
                eloc.partitionReferenceNum =
-                               UDF_I(inode)->i_location.partitionReferenceNum;
+                               iinfo->i_location.partitionReferenceNum;
                elen = inode->i_sb->s_blocksize;
-               UDF_I(inode)->i_lenExtents = elen;
+               iinfo->i_lenExtents = elen;
                udf_add_aext(inode, &epos, eloc, elen, 0);
                brelse(epos.bh);
 
                block = udf_get_pblock(inode->i_sb, block,
-                               UDF_I(inode)->i_location.partitionReferenceNum,
+                               iinfo->i_location.partitionReferenceNum,
                                0);
                epos.bh = udf_tread(inode->i_sb, block);
                lock_buffer(epos.bh);
@@ -979,9 +918,8 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
                unlock_buffer(epos.bh);
                mark_buffer_dirty_inode(epos.bh, inode);
                ea = epos.bh->b_data + udf_ext0_offset(inode);
-       } else {
-               ea = UDF_I(inode)->i_ext.i_data + UDF_I(inode)->i_lenEAttr;
-       }
+       } else
+               ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
 
        eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
        pc = (struct pathComponent *)ea;
@@ -1049,15 +987,15 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
 
        brelse(epos.bh);
        inode->i_size = elen;
-       if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-               UDF_I(inode)->i_lenAlloc = inode->i_size;
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+               iinfo->i_lenAlloc = inode->i_size;
        mark_inode_dirty(inode);
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi)
                goto out_no_entry;
        cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
-       cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
+       cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
        bh = UDF_SB(inode->i_sb)->s_lvid_bh;
        if (bh) {
                struct logicalVolIntegrityDesc *lvid =
@@ -1084,6 +1022,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        err = 0;
 
 out:
+       kfree(name);
        unlock_kernel();
        return err;
 
@@ -1162,6 +1101,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct buffer_head *dir_bh = NULL;
        int retval = -ENOENT;
        kernel_lb_addr tloc;
+       struct udf_inode_info *old_iinfo = UDF_I(old_inode);
 
        lock_kernel();
        ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
@@ -1185,7 +1125,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
        if (S_ISDIR(old_inode->i_mode)) {
-               uint32_t offset = udf_ext0_offset(old_inode);
+               int offset = udf_ext0_offset(old_inode);
 
                if (new_inode) {
                        retval = -ENOTEMPTY;
@@ -1193,10 +1133,10 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                                goto end_rename;
                }
                retval = -EIO;
-               if (UDF_I(old_inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                        dir_fi = udf_get_fileident(
-                                       UDF_I(old_inode)->i_ext.i_data -
-                                         (UDF_I(old_inode)->i_efe ?
+                                       old_iinfo->i_ext.i_data -
+                                         (old_iinfo->i_efe ?
                                           sizeof(struct extendedFileEntry) :
                                           sizeof(struct fileEntry)),
                                        old_inode->i_sb->s_blocksize, &offset);
@@ -1258,7 +1198,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
                udf_update_tag((char *)dir_fi,
                                (sizeof(struct fileIdentDesc) +
                                le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
-               if (UDF_I(old_inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+               if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
                        mark_inode_dirty(old_inode);
                else
                        mark_buffer_dirty_inode(dir_bh, old_inode);