Loading fs/udf/namei.c +138 −2 Original line number Diff line number Diff line Loading @@ -32,6 +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) Loading Loading @@ -158,6 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, 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); Loading Loading @@ -225,6 +228,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, continue; } if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) && isdotdot) { brelse(epos.bh); return fi; } if (!lfi) continue; Loading Loading @@ -286,9 +295,8 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, } } unlock_kernel(); d_add(dentry, inode); return NULL; return d_splice_alias(inode, dentry); } static struct fileIdentDesc *udf_add_entry(struct inode *dir, Loading Loading @@ -1232,6 +1240,134 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, 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, Loading fs/udf/super.c +1 −0 Original line number Diff line number Diff line Loading @@ -1933,6 +1933,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) /* 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; Loading fs/udf/udfdecl.h +1 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ struct task_struct; struct buffer_head; struct super_block; extern const struct export_operations udf_export_ops; extern const struct inode_operations udf_dir_inode_operations; extern const struct file_operations udf_dir_operations; extern const struct inode_operations udf_file_inode_operations; Loading include/linux/exportfs.h +21 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,19 @@ enum fid_type { * 32 bit parent directory inode number. */ 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 { Loading @@ -43,6 +56,14 @@ struct fid { u32 parent_ino; u32 parent_gen; } i32; struct { u32 block; u16 partref; u16 parent_partref; u32 generation; u32 parent_block; u32 parent_generation; } udf; __u32 raw[0]; }; }; Loading Loading
fs/udf/namei.c +138 −2 Original line number Diff line number Diff line Loading @@ -32,6 +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) Loading Loading @@ -158,6 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, 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); Loading Loading @@ -225,6 +228,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, continue; } if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) && isdotdot) { brelse(epos.bh); return fi; } if (!lfi) continue; Loading Loading @@ -286,9 +295,8 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, } } unlock_kernel(); d_add(dentry, inode); return NULL; return d_splice_alias(inode, dentry); } static struct fileIdentDesc *udf_add_entry(struct inode *dir, Loading Loading @@ -1232,6 +1240,134 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, 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, Loading
fs/udf/super.c +1 −0 Original line number Diff line number Diff line Loading @@ -1933,6 +1933,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) /* 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; Loading
fs/udf/udfdecl.h +1 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ struct task_struct; struct buffer_head; struct super_block; extern const struct export_operations udf_export_ops; extern const struct inode_operations udf_dir_inode_operations; extern const struct file_operations udf_dir_operations; extern const struct inode_operations udf_file_inode_operations; Loading
include/linux/exportfs.h +21 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,19 @@ enum fid_type { * 32 bit parent directory inode number. */ 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 { Loading @@ -43,6 +56,14 @@ struct fid { u32 parent_ino; u32 parent_gen; } i32; struct { u32 block; u16 partref; u16 parent_partref; u32 generation; u32 parent_block; u32 parent_generation; } udf; __u32 raw[0]; }; }; Loading