Skip to content

Commit

Permalink
knfsd: exportfs: remove iget abuse
Browse files Browse the repository at this point in the history
When the exportfs interface was added the expectation was that filesystems
provide an operation to convert from a file handle to an inode/dentry, but it
kept a backwards compat option that still calls into iget.

Calling into iget from non-filesystem code is very bad, because it gives too
little information to filesystem, and simply crashes if the filesystem doesn't
implement the ->read_inode routine.

Fortunately there are only two filesystems left using this fallback: efs and
jfs.  This patch moves a copy of export_iget to each of those to implement the
get_dentry method.

While this is a temporary increase of lines of code in the kernel it allows
for a much cleaner interface and important code restructuring in later
patches.

[akpm@linux-foundation.org: add jfs_get_inode_flags() declaration]
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Christoph Hellwig authored and Linus Torvalds committed Jul 17, 2007
1 parent a569425 commit 5ca2960
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 53 deletions.
32 changes: 32 additions & 0 deletions fs/efs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,38 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
return NULL;
}

struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp)
{
__u32 *objp = vobjp;
unsigned long ino = objp[0];
__u32 generation = objp[1];
struct inode *inode;
struct dentry *result;

if (ino == 0)
return ERR_PTR(-ESTALE);
inode = iget(sb, ino);
if (inode == NULL)
return ERR_PTR(-ENOMEM);

if (is_bad_inode(inode) ||
(generation && inode->i_generation != generation)) {
result = ERR_PTR(-ESTALE);
goto out_iput;
}

result = d_alloc_anon(inode);
if (!result) {
result = ERR_PTR(-ENOMEM);
goto out_iput;
}
return result;

out_iput:
iput(inode);
return result;
}

struct dentry *efs_get_parent(struct dentry *child)
{
struct dentry *parent;
Expand Down
1 change: 1 addition & 0 deletions fs/efs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static const struct super_operations efs_superblock_operations = {
};

static struct export_operations efs_export_ops = {
.get_dentry = efs_get_dentry,
.get_parent = efs_get_parent,
};

Expand Down
56 changes: 3 additions & 53 deletions fs/exportfs/expfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,61 +391,11 @@ static int get_name(struct dentry *dentry, char *name,
return error;
}


static struct dentry *export_iget(struct super_block *sb, unsigned long ino, __u32 generation)
static struct dentry *get_dentry(struct super_block *sb, void *vobjp)
{

/* iget isn't really right if the inode is currently unallocated!!
* This should really all be done inside each filesystem
*
* ext2fs' read_inode has been strengthed to return a bad_inode if
* the inode had been deleted.
*
* Currently we don't know the generation for parent directory, so
* a generation of 0 means "accept any"
*/
struct inode *inode;
struct dentry *result;
if (ino == 0)
return ERR_PTR(-ESTALE);
inode = iget(sb, ino);
if (inode == NULL)
return ERR_PTR(-ENOMEM);
if (is_bad_inode(inode)
|| (generation && inode->i_generation != generation)
) {
/* we didn't find the right inode.. */
dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n",
inode->i_ino,
inode->i_nlink, atomic_read(&inode->i_count),
inode->i_generation,
generation);

iput(inode);
return ERR_PTR(-ESTALE);
}
/* now to find a dentry.
* If possible, get a well-connected one
*/
result = d_alloc_anon(inode);
if (!result) {
iput(inode);
return ERR_PTR(-ENOMEM);
}
return result;
return ERR_PTR(-ESTALE);
}


static struct dentry *get_object(struct super_block *sb, void *vobjp)
{
__u32 *objp = vobjp;
unsigned long ino = objp[0];
__u32 generation = objp[1];

return export_iget(sb, ino, generation);
}


/**
* export_encode_fh - default export_operations->encode_fh function
* @dentry: the dentry to encode
Expand Down Expand Up @@ -524,7 +474,7 @@ struct export_operations export_op_default = {

.get_name = get_name,
.get_parent = get_parent,
.get_dentry = get_object,
.get_dentry = get_dentry,
};

EXPORT_SYMBOL(export_op_default);
Expand Down
1 change: 1 addition & 0 deletions fs/jfs/jfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern void jfs_truncate_nolock(struct inode *, loff_t);
extern void jfs_free_zero_link(struct inode *);
extern struct dentry *jfs_get_parent(struct dentry *dentry);
extern void jfs_get_inode_flags(struct jfs_inode_info *);
extern struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp);
extern void jfs_set_inode_flags(struct inode *);
extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);

Expand Down
32 changes: 32 additions & 0 deletions fs/jfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,38 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
return dentry;
}

struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp)
{
__u32 *objp = vobjp;
unsigned long ino = objp[0];
__u32 generation = objp[1];
struct inode *inode;
struct dentry *result;

if (ino == 0)
return ERR_PTR(-ESTALE);
inode = iget(sb, ino);
if (inode == NULL)
return ERR_PTR(-ENOMEM);

if (is_bad_inode(inode) ||
(generation && inode->i_generation != generation)) {
result = ERR_PTR(-ESTALE);
goto out_iput;
}

result = d_alloc_anon(inode);
if (!result) {
result = ERR_PTR(-ENOMEM);
goto out_iput;
}
return result;

out_iput:
iput(inode);
return result;
}

struct dentry *jfs_get_parent(struct dentry *dentry)
{
struct super_block *sb = dentry->d_inode->i_sb;
Expand Down
1 change: 1 addition & 0 deletions fs/jfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ static const struct super_operations jfs_super_operations = {
};

static struct export_operations jfs_export_operations = {
.get_dentry = jfs_get_dentry,
.get_parent = jfs_get_parent,
};

Expand Down
1 change: 1 addition & 0 deletions include/linux/efs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ extern efs_block_t efs_map_block(struct inode *, efs_block_t);
extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);

extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
extern struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp);
extern struct dentry *efs_get_parent(struct dentry *);
extern int efs_bmap(struct inode *, int);

Expand Down

0 comments on commit 5ca2960

Please sign in to comment.