Commit 0f1bce41 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6

* '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
parents da1ba891 9afadc4b
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/crc-itu-t.h> #include <linux/crc-itu-t.h>
#include <linux/exportfs.h>
static inline int udf_match(int len1, const char *name1, int len2, static inline int udf_match(int len1, const char *name1, int len2,
const char *name2) const char *name2)
...@@ -158,6 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, ...@@ -158,6 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
sector_t offset; sector_t offset;
struct extent_position epos = {}; struct extent_position epos = {};
struct udf_inode_info *dinfo = UDF_I(dir); 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; size = udf_ext0_offset(dir) + dir->i_size;
f_pos = udf_ext0_offset(dir); f_pos = udf_ext0_offset(dir);
...@@ -225,6 +228,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, ...@@ -225,6 +228,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
continue; continue;
} }
if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
isdotdot) {
brelse(epos.bh);
return fi;
}
if (!lfi) if (!lfi)
continue; continue;
...@@ -286,9 +295,8 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, ...@@ -286,9 +295,8 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
} }
} }
unlock_kernel(); unlock_kernel();
d_add(dentry, inode);
return NULL; return d_splice_alias(inode, dentry);
} }
static struct fileIdentDesc *udf_add_entry(struct inode *dir, static struct fileIdentDesc *udf_add_entry(struct inode *dir,
...@@ -307,7 +315,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -307,7 +315,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
uint16_t liu; uint16_t liu;
int block; int block;
kernel_lb_addr eloc; kernel_lb_addr eloc;
uint32_t elen; uint32_t elen = 0;
sector_t offset; sector_t offset;
struct extent_position epos = {}; struct extent_position epos = {};
struct udf_inode_info *dinfo; struct udf_inode_info *dinfo;
...@@ -398,7 +406,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -398,7 +406,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
} }
add: 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); elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(short_ad); epos.offset -= sizeof(short_ad);
...@@ -1232,6 +1241,134 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1232,6 +1241,134 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
return retval; 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 = { const struct inode_operations udf_dir_inode_operations = {
.lookup = udf_lookup, .lookup = udf_lookup,
.create = udf_create, .create = udf_create,
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
uint16_t partition, uint32_t offset) uint16_t partition, uint32_t offset)
{ {
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
......
...@@ -1933,6 +1933,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1933,6 +1933,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
/* Fill in the rest of the superblock */ /* Fill in the rest of the superblock */
sb->s_op = &udf_sb_ops; sb->s_op = &udf_sb_ops;
sb->s_export_op = &udf_export_ops;
sb->dq_op = NULL; sb->dq_op = NULL;
sb->s_dirt = 0; sb->s_dirt = 0;
sb->s_magic = UDF_SUPER_MAGIC; sb->s_magic = UDF_SUPER_MAGIC;
......
...@@ -73,6 +73,7 @@ struct task_struct; ...@@ -73,6 +73,7 @@ struct task_struct;
struct buffer_head; struct buffer_head;
struct super_block; struct super_block;
extern const struct export_operations udf_export_ops;
extern const struct inode_operations udf_dir_inode_operations; extern const struct inode_operations udf_dir_inode_operations;
extern const struct file_operations udf_dir_operations; extern const struct file_operations udf_dir_operations;
extern const struct inode_operations udf_file_inode_operations; extern const struct inode_operations udf_file_inode_operations;
......
...@@ -33,6 +33,19 @@ enum fid_type { ...@@ -33,6 +33,19 @@ enum fid_type {
* 32 bit parent directory inode number. * 32 bit parent directory inode number.
*/ */
FILEID_INO32_GEN_PARENT = 2, FILEID_INO32_GEN_PARENT = 2,
/*
* 32 bit block number, 16 bit partition reference,
* 16 bit unused, 32 bit generation number.
*/
FILEID_UDF_WITHOUT_PARENT = 0x51,
/*
* 32 bit block number, 16 bit partition reference,
* 16 bit unused, 32 bit generation number,
* 32 bit parent block number, 32 bit parent generation number
*/
FILEID_UDF_WITH_PARENT = 0x52,
}; };
struct fid { struct fid {
...@@ -43,6 +56,14 @@ struct fid { ...@@ -43,6 +56,14 @@ struct fid {
u32 parent_ino; u32 parent_ino;
u32 parent_gen; u32 parent_gen;
} i32; } i32;
struct {
u32 block;
u16 partref;
u16 parent_partref;
u32 generation;
u32 parent_block;
u32 parent_generation;
} udf;
__u32 raw[0]; __u32 raw[0];
}; };
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment