Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 May 2008 17:48:03 +0000 (10:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 8 May 2008 17:48:03 +0000 (10:48 -0700)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6:
  udf: Fix memory corruption when fs mounted with noadinicb option
  udf: Make udf exportable
  udf: fs/udf/partition.c:udf_get_pblock() mustn't be inline

1  2 
fs/udf/namei.c
fs/udf/super.c

diff --combined fs/udf/namei.c
@@@ -32,6 -32,7 +32,7 @@@
  #include <linux/buffer_head.h>
  #include <linux/sched.h>
  #include <linux/crc-itu-t.h>
+ #include <linux/exportfs.h>
  
  static inline int udf_match(int len1, const char *name1, int len2,
                            const char *name2)
@@@ -158,6 -159,8 +159,8 @@@ static struct fileIdentDesc *udf_find_e
        sector_t offset;
        struct extent_position epos = {};
        struct udf_inode_info *dinfo = UDF_I(dir);
+       int isdotdot = dentry->d_name.len == 2 &&
+               dentry->d_name.name[0] == '.' && dentry->d_name.name[1] == '.';
  
        size = udf_ext0_offset(dir) + dir->i_size;
        f_pos = udf_ext0_offset(dir);
                                continue;
                }
  
+               if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
+                   isdotdot) {
+                       brelse(epos.bh);
+                       return fi;
+               }
                if (!lfi)
                        continue;
  
@@@ -286,9 -295,8 +295,8 @@@ static struct dentry *udf_lookup(struc
                }
        }
        unlock_kernel();
-       d_add(dentry, inode);
  
-       return NULL;
+       return d_splice_alias(inode, dentry);
  }
  
  static struct fileIdentDesc *udf_add_entry(struct inode *dir,
        uint16_t liu;
        int block;
        kernel_lb_addr eloc;
-       uint32_t elen;
+       uint32_t elen = 0;
        sector_t offset;
        struct extent_position epos = {};
        struct udf_inode_info *dinfo;
        }
  
  add:
-       if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+       /* Is there any extent whose size we need to round up? */
+       if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && elen) {
                elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
                if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                        epos.offset -= sizeof(short_ad);
@@@ -890,7 -899,7 +899,7 @@@ static int udf_symlink(struct inode *di
  
        if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
                kernel_lb_addr eloc;
 -              uint32_t elen;
 +              uint32_t bsize;
  
                block = udf_new_block(inode->i_sb, inode,
                                iinfo->i_location.partitionReferenceNum,
                eloc.logicalBlockNum = block;
                eloc.partitionReferenceNum =
                                iinfo->i_location.partitionReferenceNum;
 -              elen = inode->i_sb->s_blocksize;
 -              iinfo->i_lenExtents = elen;
 -              udf_add_aext(inode, &epos, eloc, elen, 0);
 +              bsize = inode->i_sb->s_blocksize;
 +              iinfo->i_lenExtents = bsize;
 +              udf_add_aext(inode, &epos, eloc, bsize, 0);
                brelse(epos.bh);
  
                block = udf_get_pblock(inode->i_sb, block,
@@@ -1232,6 -1241,134 +1241,134 @@@ end_rename
        return retval;
  }
  
+ static struct dentry *udf_get_parent(struct dentry *child)
+ {
+       struct dentry *parent;
+       struct inode *inode = NULL;
+       struct dentry dotdot;
+       struct fileIdentDesc cfi;
+       struct udf_fileident_bh fibh;
+       dotdot.d_name.name = "..";
+       dotdot.d_name.len = 2;
+       lock_kernel();
+       if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
+               goto out_unlock;
+       if (fibh.sbh != fibh.ebh)
+               brelse(fibh.ebh);
+       brelse(fibh.sbh);
+       inode = udf_iget(child->d_inode->i_sb,
+                        lelb_to_cpu(cfi.icb.extLocation));
+       if (!inode)
+               goto out_unlock;
+       unlock_kernel();
+       parent = d_alloc_anon(inode);
+       if (!parent) {
+               iput(inode);
+               parent = ERR_PTR(-ENOMEM);
+       }
+       return parent;
+ out_unlock:
+       unlock_kernel();
+       return ERR_PTR(-EACCES);
+ }
+ static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
+                                       u16 partref, __u32 generation)
+ {
+       struct inode *inode;
+       struct dentry *result;
+       kernel_lb_addr loc;
+       if (block == 0)
+               return ERR_PTR(-ESTALE);
+       loc.logicalBlockNum = block;
+       loc.partitionReferenceNum = partref;
+       inode = udf_iget(sb, loc);
+       if (inode == NULL)
+               return ERR_PTR(-ENOMEM);
+       if (generation && inode->i_generation != generation) {
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
+       result = d_alloc_anon(inode);
+       if (!result) {
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       return result;
+ }
+ static struct dentry *udf_fh_to_dentry(struct super_block *sb,
+                                      struct fid *fid, int fh_len, int fh_type)
+ {
+       if ((fh_len != 3 && fh_len != 5) ||
+           (fh_type != FILEID_UDF_WITH_PARENT &&
+            fh_type != FILEID_UDF_WITHOUT_PARENT))
+               return NULL;
+       return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
+                       fid->udf.generation);
+ }
+ static struct dentry *udf_fh_to_parent(struct super_block *sb,
+                                      struct fid *fid, int fh_len, int fh_type)
+ {
+       if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
+               return NULL;
+       return udf_nfs_get_inode(sb, fid->udf.parent_block,
+                                fid->udf.parent_partref,
+                                fid->udf.parent_generation);
+ }
+ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
+                        int connectable)
+ {
+       int len = *lenp;
+       struct inode *inode =  de->d_inode;
+       kernel_lb_addr location = UDF_I(inode)->i_location;
+       struct fid *fid = (struct fid *)fh;
+       int type = FILEID_UDF_WITHOUT_PARENT;
+       if (len < 3 || (connectable && len < 5))
+               return 255;
+       *lenp = 3;
+       fid->udf.block = location.logicalBlockNum;
+       fid->udf.partref = location.partitionReferenceNum;
+       fid->udf.generation = inode->i_generation;
+       if (connectable && !S_ISDIR(inode->i_mode)) {
+               spin_lock(&de->d_lock);
+               inode = de->d_parent->d_inode;
+               location = UDF_I(inode)->i_location;
+               fid->udf.parent_block = location.logicalBlockNum;
+               fid->udf.parent_partref = location.partitionReferenceNum;
+               fid->udf.parent_generation = inode->i_generation;
+               spin_unlock(&de->d_lock);
+               *lenp = 5;
+               type = FILEID_UDF_WITH_PARENT;
+       }
+       return type;
+ }
+ const struct export_operations udf_export_ops = {
+       .encode_fh      = udf_encode_fh,
+       .fh_to_dentry   = udf_fh_to_dentry,
+       .fh_to_parent   = udf_fh_to_parent,
+       .get_parent     = udf_get_parent,
+ };
  const struct inode_operations udf_dir_inode_operations = {
        .lookup                         = udf_lookup,
        .create                         = udf_create,
diff --combined fs/udf/super.c
@@@ -240,7 -240,7 +240,7 @@@ static int udf_sb_alloc_partition_maps(
        sbi->s_partmaps = kcalloc(count, sizeof(struct udf_part_map),
                                  GFP_KERNEL);
        if (!sbi->s_partmaps) {
 -              udf_error(sb, __FUNCTION__,
 +              udf_error(sb, __func__,
                          "Unable to allocate space for %d partition maps",
                          count);
                sbi->s_partitions = 0;
@@@ -1086,7 -1086,7 +1086,7 @@@ static struct udf_bitmap *udf_sb_alloc_
                bitmap = vmalloc(size); /* TODO: get rid of vmalloc */
  
        if (bitmap == NULL) {
 -              udf_error(sb, __FUNCTION__,
 +              udf_error(sb, __func__,
                          "Unable to allocate space for bitmap "
                          "and %d buffer_head pointers", nr_groups);
                return NULL;
@@@ -1933,6 -1933,7 +1933,7 @@@ static int udf_fill_super(struct super_
  
        /* Fill in the rest of the superblock */
        sb->s_op = &udf_sb_ops;
+       sb->s_export_op = &udf_export_ops;
        sb->dq_op = NULL;
        sb->s_dirt = 0;
        sb->s_magic = UDF_SUPER_MAGIC;