[PATCH 00/32] Remove iget() and read_inode() [try #2] - Kernel

This is a discussion on [PATCH 00/32] Remove iget() and read_inode() [try #2] - Kernel ; Hi Christoph, Al, Here's a set of patches that remove all calls to iget() and all read_inode() functions. They should be removed for two reasons: firstly they don't lend themselves to good error handling, and secondly their presence is a ...

+ Reply to Thread
Page 1 of 3 1 2 3 LastLast
Results 1 to 20 of 43

Thread: [PATCH 00/32] Remove iget() and read_inode() [try #2]

  1. [PATCH 00/32] Remove iget() and read_inode() [try #2]



    Hi Christoph, Al,

    Here's a set of patches that remove all calls to iget() and all read_inode()
    functions. They should be removed for two reasons: firstly they don't lend
    themselves to good error handling, and secondly their presence is a temptation
    for code outside a filesystem to call iget() to access inodes within that
    filesystem.

    There are a few benefits to this:

    (1) Error handling gets simpler as you can return an error code rather than
    having to call is_bad_inode().

    (2) You can now tell the difference between ENOMEM and EIO occurring in the
    read_inode() path.

    (3) The code should get smaller. iget() is an inline function that is
    typically called 2-3 times per filesystem that uses it. By folding the
    iget code into the read_inode code for each filesystem, it eliminates
    some duplication.

    A tarball of the patches can be retrieved from:

    http://people.redhat.com/~dhowells/iget-remove.tar.bz2


    Additionally, there are a couple of patches that introduce an ERR_CAST() macro
    to be used instead of ERR_PTR(PTR_ERR(p)) constructs and apply it to all such
    instances in the kernel.

    Of the patches directly relevant to the subject:

    The first patch adds a function, iget_failed() that is a canned piece of code
    for killing an inode when the inode construction path fails.

    The second and third patches makes AFS and GFS2 use iget_failed() rather than
    interpolating the sequence directly.

    The fourth patch marks iget() and read_inode() as being deprecated.

    The final patch removes iget() and read_inode() completely.

    Each of the other patches modify a filesystem that used iget() and read_inode()
    to use iget_locked() instead. The standard procedure was to convert:

    void thingyfs_read_inode(struct inode *inode)
    {
    ...
    }

    into:

    struct inode *thingyfs_iget(struct super_block *sp, unsigned long ino)
    {
    struct inode *inode;
    int ret;

    inode = iget_locked(sb, ino);
    if (!inode)
    return ERR_PTR(-ENOMEM);
    if (!(inode->i_state & I_NEW))
    return inode;

    ...
    unlock_new_inode(inode);
    return inode;
    error:
    iget_failed(inode);
    return ERR_PTR(ret);
    }

    and then call thingyfs_iget() rather than iget():

    ret = -EINVAL;
    inode = iget(sb, ino);
    if (!inode || is_bad_inode(inode))
    goto error;

    becomes:

    inode = thingyfs_iget(sb, ino);
    if (IS_ERR(inode)) {
    ret = PTR_ERR(inode);
    goto error;
    }

    There were exceptions; most notably it appeared FAT should be calling ilookup()
    not iget().

    Additionally, HPPFS and HOSTFS (UM-specific filesystems) really need checking:

    hostfs_kern.c:

    (*) hostfs_iget() should perhaps subsume init_inode() and hostfs_read_inode().

    (*) It would appear that all hostfs inodes are the same inode because iget()
    was being called with inode number 0 - which forms the lookup key.

    hppfs_kern.c:

    (*) The HPPFS inode retains a pointer to the proc dentry it is shadowing, but
    whilst it does appear to retain a reference to it, it doesn't appear to
    destroy the reference if the inode goes away.

    (*) hppfs_iget() should perhaps subsume init_inode() and hppfs_read_inode().

    (*) It would appear that all hppfs inodes are the same inode because iget()
    was being called with inode number 0, which forms the lookup key.

    In addition to the introduction of ERR_CAST, the ext2, ext3 and ext4 patches
    have been fixed from Jan Kara's review.

    David
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [PATCH 04/32] IGET: Use iget_failed() in AFS [try #2]

    Use iget_failed() in AFS to kill a failed inode.

    Signed-off-by: David Howells
    ---

    fs/afs/inode.c | 5 +----
    1 files changed, 1 insertions(+), 4 deletions(-)

    diff --git a/fs/afs/inode.c b/fs/afs/inode.c
    index d196840..ca9b02f 100644
    --- a/fs/afs/inode.c
    +++ b/fs/afs/inode.c
    @@ -196,10 +196,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,

    /* failure */
    bad_inode:
    - make_bad_inode(inode);
    - unlock_new_inode(inode);
    - iput(inode);
    -
    + iget_failed(inode);
    _leave(" = %d [bad]", ret);
    return ERR_PTR(ret);
    }

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [PATCH 10/32] IGET: Stop BFS from using iget() and read_inode() [try #2]

    Stop the BFS filesystem from using iget() and read_inode(). Replace
    bfs_read_inode() with bfs_iget(), and call that instead of iget().
    bfs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    bfs_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/bfs/bfs.h | 2 ++
    fs/bfs/dir.c | 6 +++---
    fs/bfs/inode.c | 32 ++++++++++++++++++++++----------
    3 files changed, 27 insertions(+), 13 deletions(-)

    diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h
    index 130f6c6..5cf50d4 100644
    --- a/fs/bfs/bfs.h
    +++ b/fs/bfs/bfs.h
    @@ -46,6 +46,8 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode)
    #define printf(format, args...) \
    printk(KERN_ERR "BFS-fs: %s(): " format, __FUNCTION__, ## args)

    +/* inode.c */
    +extern struct inode *bfs_iget(struct super_block *sb, unsigned long ino);

    /* file.c */
    extern const struct inode_operations bfs_file_inops;
    diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
    index 097f149..03c8bdb 100644
    --- a/fs/bfs/dir.c
    +++ b/fs/bfs/dir.c
    @@ -141,10 +141,10 @@ static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry, st
    if (bh) {
    unsigned long ino = (unsigned long)le16_to_cpu(de->ino);
    brelse(bh);
    - inode = iget(dir->i_sb, ino);
    - if (!inode) {
    + inode = bfs_iget(dir->i_sb, ino);
    + if (IS_ERR(inode)) {
    unlock_kernel();
    - return ERR_PTR(-EACCES);
    + return ERR_CAST(inode);
    }
    }
    unlock_kernel();
    diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
    index f346eb1..76798c9 100644
    --- a/fs/bfs/inode.c
    +++ b/fs/bfs/inode.c
    @@ -32,25 +32,29 @@ MODULE_LICENSE("GPL");

    void dump_imap(const char *prefix, struct super_block * s);

    -static void bfs_read_inode(struct inode * inode)
    +struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
    {
    - unsigned long ino = inode->i_ino;
    struct bfs_inode * di;
    struct buffer_head * bh;
    + struct inode *inode;
    int block, off;

    + inode = iget_locked(sb, ino);
    + if (IS_ERR(inode))
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    if (ino < BFS_ROOT_INO || ino > BFS_SB(inode->i_sb)->si_lasti) {
    printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);
    - make_bad_inode(inode);
    - return;
    + goto error;
    }

    block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
    bh = sb_bread(inode->i_sb, block);
    if (!bh) {
    printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id, ino);
    - make_bad_inode(inode);
    - return;
    + goto error;
    }

    off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
    @@ -85,6 +89,12 @@ static void bfs_read_inode(struct inode * inode)
    BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino); /* can be 0 so we store a copy */

    brelse(bh);
    + unlock_new_inode(inode);
    + return inode;
    +
    +error:
    + iget_failed(inode);
    + return ERR_PTR(-EIO);
    }

    static int bfs_write_inode(struct inode * inode, int unused)
    @@ -271,7 +281,6 @@ static void destroy_inodecache(void)
    static const struct super_operations bfs_sops = {
    .alloc_inode = bfs_alloc_inode,
    .destroy_inode = bfs_destroy_inode,
    - .read_inode = bfs_read_inode,
    .write_inode = bfs_write_inode,
    .delete_inode = bfs_delete_inode,
    .put_super = bfs_put_super,
    @@ -306,6 +315,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
    struct inode * inode;
    unsigned i, imap_len;
    struct bfs_sb_info * info;
    + long ret = -EINVAL;

    info = kzalloc(sizeof(*info), GFP_KERNEL);
    if (!info)
    @@ -340,14 +350,16 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
    set_bit(i, info->si_imap);

    s->s_op = &bfs_sops;
    - inode = iget(s, BFS_ROOT_INO);
    - if (!inode) {
    + inode = bfs_iget(s, BFS_ROOT_INO);
    + if (IS_ERR(inode)) {
    + ret = PTR_ERR(inode);
    kfree(info->si_imap);
    goto out;
    }
    s->s_root = d_alloc_root(inode);
    if (!s->s_root) {
    iput(inode);
    + ret = -ENOMEM;
    kfree(info->si_imap);
    goto out;
    }
    @@ -402,7 +414,7 @@ out:
    brelse(bh);
    kfree(info);
    s->s_fs_info = NULL;
    - return -EINVAL;
    + return ret;
    }

    static int bfs_get_sb(struct file_system_type *fs_type,

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [PATCH 12/32] IGET: Stop EFS from using iget() and read_inode() [try #2]

    Stop the EFS filesystem from using iget() and read_inode(). Replace
    efs_read_inode() with efs_iget(), and call that instead of iget().
    efs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    efs_fill_super() returns any error incurred when getting the root inode
    instead of EACCES.

    Signed-off-by: David Howells
    ---

    fs/efs/inode.c | 25 +++++++++++++++++--------
    fs/efs/namei.c | 23 ++++++++++++-----------
    fs/efs/super.c | 18 ++++++++++++------
    include/linux/efs_fs.h | 2 +-
    4 files changed, 42 insertions(+), 26 deletions(-)

    diff --git a/fs/efs/inode.c b/fs/efs/inode.c
    index 174696f..627c302 100644
    --- a/fs/efs/inode.c
    +++ b/fs/efs/inode.c
    @@ -45,17 +45,26 @@ static inline void extent_copy(efs_extent *src, efs_extent *dst) {
    return;
    }

    -void efs_read_inode(struct inode *inode)
    +struct inode *efs_iget(struct super_block *super, unsigned long ino)
    {
    int i, inode_index;
    dev_t device;
    u32 rdev;
    struct buffer_head *bh;
    - struct efs_sb_info *sb = SUPER_INFO(inode->i_sb);
    - struct efs_inode_info *in = INODE_INFO(inode);
    + struct efs_sb_info *sb = SUPER_INFO(super);
    + struct efs_inode_info *in;
    efs_block_t block, offset;
    struct efs_dinode *efs_inode;
    -
    + struct inode *inode;
    +
    + inode = iget_locked(super, ino);
    + if (IS_ERR(inode))
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    + in = INODE_INFO(inode);
    +
    /*
    ** EFS layout:
    **
    @@ -159,13 +168,13 @@ void efs_read_inode(struct inode *inode)
    break;
    }

    - return;
    + unlock_new_inode(inode);
    + return inode;

    read_inode_error:
    printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
    - make_bad_inode(inode);
    -
    - return;
    + iget_failed(inode);
    + return ERR_PTR(-EIO);
    }

    static inline efs_block_t
    diff --git a/fs/efs/namei.c b/fs/efs/namei.c
    index 5276b19..77d7106 100644
    --- a/fs/efs/namei.c
    +++ b/fs/efs/namei.c
    @@ -64,9 +64,10 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
    lock_kernel();
    inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
    if (inodenum) {
    - if (!(inode = iget(dir->i_sb, inodenum))) {
    + inode = efs_iget(dir->i_sb, inodenum);
    + if (IS_ERR(inode)) {
    unlock_kernel();
    - return ERR_PTR(-EACCES);
    + return ERR_CAST(inode);
    }
    }
    unlock_kernel();
    @@ -85,12 +86,11 @@ struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp)

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

    - if (is_bad_inode(inode) ||
    - (generation && inode->i_generation != generation)) {
    + if (generation && inode->i_generation != generation) {
    result = ERR_PTR(-ESTALE);
    goto out_iput;
    }
    @@ -112,7 +112,7 @@ struct dentry *efs_get_parent(struct dentry *child)
    struct dentry *parent;
    struct inode *inode;
    efs_ino_t ino;
    - int error;
    + long error;

    lock_kernel();

    @@ -121,10 +121,11 @@ struct dentry *efs_get_parent(struct dentry *child)
    if (!ino)
    goto fail;

    - error = -EACCES;
    - inode = iget(child->d_inode->i_sb, ino);
    - if (!inode)
    + inode = efs_iget(child->d_inode->i_sb, ino);
    + if (IS_ERR(inode)) {
    + error = PTR_ERR(inode);
    goto fail;
    + }

    error = -ENOMEM;
    parent = d_alloc_anon(inode);
    diff --git a/fs/efs/super.c b/fs/efs/super.c
    index ce4acb8..685279d 100644
    --- a/fs/efs/super.c
    +++ b/fs/efs/super.c
    @@ -107,7 +107,6 @@ static int efs_remount(struct super_block *sb, int *flags, char *data)
    static const struct super_operations efs_superblock_operations = {
    .alloc_inode = efs_alloc_inode,
    .destroy_inode = efs_destroy_inode,
    - .read_inode = efs_read_inode,
    .put_super = efs_put_super,
    .statfs = efs_statfs,
    .remount_fs = efs_remount,
    @@ -246,6 +245,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
    struct efs_sb_info *sb;
    struct buffer_head *bh;
    struct inode *root;
    + int ret = -EINVAL;

    sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
    if (!sb)
    @@ -302,12 +302,18 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
    }
    s->s_op = &efs_superblock_operations;
    s->s_export_op = &efs_export_ops;
    - root = iget(s, EFS_ROOTINODE);
    - s->s_root = d_alloc_root(root);
    -
    - if (!(s->s_root)) {
    + root = efs_iget(s, EFS_ROOTINODE);
    + if (IS_ERR(root)) {
    printk(KERN_ERR "EFS: get root inode failed\n");
    + ret = PTR_ERR(root);
    + goto out_no_fs;
    + }
    +
    + s->s_root = d_alloc_root(root);
    + if (!(s->s_root)) {
    + printk(KERN_ERR "EFS: get root dentry failed\n");
    iput(root);
    + ret = -ENOMEM;
    goto out_no_fs;
    }

    @@ -317,7 +323,7 @@ out_no_fs_ul:
    out_no_fs:
    s->s_fs_info = NULL;
    kfree(sb);
    - return -EINVAL;
    + return ret;
    }

    static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
    diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
    index 16cb25c..18b725f 100644
    --- a/include/linux/efs_fs.h
    +++ b/include/linux/efs_fs.h
    @@ -40,7 +40,7 @@ extern const struct inode_operations efs_dir_inode_operations;
    extern const struct file_operations efs_dir_operations;
    extern const struct address_space_operations efs_symlink_aops;

    -extern void efs_read_inode(struct inode *);
    +extern struct inode *efs_iget(struct super_block *, unsigned long);
    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);


    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. [PATCH 09/32] IGET: Stop BEFS from using iget() and read_inode() [try #2]

    Stop the BEFS filesystem from using iget() and read_inode(). Replace
    befs_read_inode() with befs_iget(), and call that instead of iget().
    befs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    befs_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    Acked-by: Will Dyson
    ---

    fs/befs/linuxvfs.c | 39 +++++++++++++++++++++++++--------------
    1 files changed, 25 insertions(+), 14 deletions(-)

    diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
    index a451418..fd9866e 100644
    --- a/fs/befs/linuxvfs.c
    +++ b/fs/befs/linuxvfs.c
    @@ -35,7 +35,7 @@ static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
    static int befs_readpage(struct file *file, struct page *page);
    static sector_t befs_bmap(struct address_space *mapping, sector_t block);
    static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
    -static void befs_read_inode(struct inode *ino);
    +static struct inode *befs_iget(struct super_block *, unsigned long);
    static struct inode *befs_alloc_inode(struct super_block *sb);
    static void befs_destroy_inode(struct inode *inode);
    static int befs_init_inodecache(void);
    @@ -52,7 +52,6 @@ static int befs_statfs(struct dentry *, struct kstatfs *);
    static int parse_options(char *, befs_mount_options *);

    static const struct super_operations befs_sops = {
    - .read_inode = befs_read_inode, /* initialize & read inode */
    .alloc_inode = befs_alloc_inode, /* allocate a new inode */
    .destroy_inode = befs_destroy_inode, /* deallocate an inode */
    .put_super = befs_put_super, /* uninit super */
    @@ -198,9 +197,9 @@ befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
    return ERR_PTR(-ENODATA);
    }

    - inode = iget(dir->i_sb, (ino_t) offset);
    - if (!inode)
    - return ERR_PTR(-EACCES);
    + inode = befs_iget(dir->i_sb, (ino_t) offset);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);

    d_add(dentry, inode);

    @@ -296,17 +295,23 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
    inode_init_once(&bi->vfs_inode);
    }

    -static void
    -befs_read_inode(struct inode *inode)
    +static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
    {
    struct buffer_head *bh = NULL;
    befs_inode *raw_inode = NULL;

    - struct super_block *sb = inode->i_sb;
    befs_sb_info *befs_sb = BEFS_SB(sb);
    befs_inode_info *befs_ino = NULL;
    + struct inode *inode;
    + long ret = -EIO;

    - befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino);
    + befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino);
    +
    + inode = iget_locked(sb, ino);
    + if (IS_ERR(inode))
    + return inode;
    + if (!(inode->i_state & I_NEW))
    + return inode;

    befs_ino = BEFS_I(inode);

    @@ -402,15 +407,16 @@ befs_read_inode(struct inode *inode)

    brelse(bh);
    befs_debug(sb, "<--- befs_read_inode()");
    - return;
    + unlock_new_inode(inode);
    + return inode;

    unacquire_bh:
    brelse(bh);

    unacquire_none:
    - make_bad_inode(inode);
    + iget_failed(inode);
    befs_debug(sb, "<--- befs_read_inode() - Bad inode");
    - return;
    + return ERR_PTR(ret);
    }

    /* Initialize the inode cache. Called at fs setup.
    @@ -752,6 +758,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
    befs_sb_info *befs_sb;
    befs_super_block *disk_sb;
    struct inode *root;
    + long ret = -EINVAL;

    const unsigned long sb_block = 0;
    const off_t x86_sb_off = 512;
    @@ -833,7 +840,11 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
    /* Set real blocksize of fs */
    sb_set_blocksize(sb, (ulong) befs_sb->block_size);
    sb->s_op = (struct super_operations *) &befs_sops;
    - root = iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
    + root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
    + if (IS_ERR(root)) {
    + ret = PTR_ERR(root);
    + goto unacquire_priv_sbp;
    + }
    sb->s_root = d_alloc_root(root);
    if (!sb->s_root) {
    iput(root);
    @@ -868,7 +879,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)

    unacquire_none:
    sb->s_fs_info = NULL;
    - return -EINVAL;
    + return ret;
    }

    static int

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. [PATCH 15/32] IGET: Stop EXT4 from using iget() and read_inode() [try #2]

    Stop the EXT4 filesystem from using iget() and read_inode(). Replace
    ext4_read_inode() with ext4_iget(), and call that instead of iget().
    ext4_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    ext4_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/ext4/ialloc.c | 58 ++++++++++++++++++++++++++++-------------------
    fs/ext4/inode.c | 25 +++++++++++++++-----
    fs/ext4/namei.c | 29 +++++++-----------------
    fs/ext4/resize.c | 7 ++----
    fs/ext4/super.c | 36 ++++++++++++++++-------------
    include/linux/ext4_fs.h | 2 +-
    6 files changed, 87 insertions(+), 70 deletions(-)

    diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
    index 427f830..4fba007 100644
    --- a/fs/ext4/ialloc.c
    +++ b/fs/ext4/ialloc.c
    @@ -659,14 +659,15 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
    unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
    unsigned long block_group;
    int bit;
    - struct buffer_head *bitmap_bh = NULL;
    + struct buffer_head *bitmap_bh;
    struct inode *inode = NULL;
    + long err = -EIO;

    /* Error cases - e2fsck has already cleaned up for us */
    if (ino > max_ino) {
    ext4_warning(sb, __FUNCTION__,
    "bad orphan ino %lu! e2fsck was run?", ino);
    - goto out;
    + goto error;
    }

    block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
    @@ -675,38 +676,49 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
    if (!bitmap_bh) {
    ext4_warning(sb, __FUNCTION__,
    "inode bitmap error for orphan %lu", ino);
    - goto out;
    + goto error;
    }

    /* Having the inode bit set should be a 100% indicator that this
    * is a valid orphan (no e2fsck run on fs). Orphans also include
    * inodes that were being truncated, so we can't check i_nlink==0.
    */
    - if (!ext4_test_bit(bit, bitmap_bh->b_data) ||
    - !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
    - NEXT_ORPHAN(inode) > max_ino) {
    - ext4_warning(sb, __FUNCTION__,
    - "bad orphan inode %lu! e2fsck was run?", ino);
    - printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
    - bit, (unsigned long long)bitmap_bh->b_blocknr,
    - ext4_test_bit(bit, bitmap_bh->b_data));
    - printk(KERN_NOTICE "inode=%p\n", inode);
    - if (inode) {
    - printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
    - is_bad_inode(inode));
    - printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
    - NEXT_ORPHAN(inode));
    - printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
    - }
    + if (!ext4_test_bit(bit, bitmap_bh->b_data))
    + goto bad_orphan;
    +
    + inode = ext4_iget(sb, ino);
    + if (IS_ERR(inode))
    + goto iget_failed;
    +
    + if (NEXT_ORPHAN(inode) > max_ino)
    + goto bad_orphan;
    + brelse(bitmap_bh);
    + return inode;
    +
    +iget_failed:
    + err = PTR_ERR(inode);
    + inode = NULL;
    +bad_orphan:
    + ext4_warning(sb, __FUNCTION__,
    + "bad orphan inode %lu! e2fsck was run?", ino);
    + printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
    + bit, (unsigned long long)bitmap_bh->b_blocknr,
    + ext4_test_bit(bit, bitmap_bh->b_data));
    + printk(KERN_NOTICE "inode=%p\n", inode);
    + if (inode) {
    + printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
    + is_bad_inode(inode));
    + printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
    + NEXT_ORPHAN(inode));
    + printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
    /* Avoid freeing blocks if we got a bad deleted inode */
    - if (inode && inode->i_nlink == 0)
    + if (inode->i_nlink == 0)
    inode->i_blocks = 0;
    iput(inode);
    - inode = NULL;
    }
    -out:
    brelse(bitmap_bh);
    - return inode;
    +error:
    + return ERR_PTR(err);
    }

    unsigned long ext4_count_free_inodes (struct super_block * sb)
    diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
    index a4848e0..c4fb1eb 100644
    --- a/fs/ext4/inode.c
    +++ b/fs/ext4/inode.c
    @@ -2595,21 +2595,31 @@ void ext4_get_inode_flags(struct ext4_inode_info *ei)
    ei->i_flags |= EXT4_DIRSYNC_FL;
    }

    -void ext4_read_inode(struct inode * inode)
    +struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
    {
    struct ext4_iloc iloc;
    struct ext4_inode *raw_inode;
    - struct ext4_inode_info *ei = EXT4_I(inode);
    + struct ext4_inode_info *ei;
    struct buffer_head *bh;
    + struct inode *inode;
    + long ret;
    int block;

    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    + ei = EXT4_I(inode);
    #ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
    ei->i_acl = EXT4_ACL_NOT_CACHED;
    ei->i_default_acl = EXT4_ACL_NOT_CACHED;
    #endif
    ei->i_block_alloc_info = NULL;

    - if (__ext4_get_inode_loc(inode, &iloc, 0))
    + ret = __ext4_get_inode_loc(inode, &iloc, 0);
    + if (ret < 0)
    goto bad_inode;
    bh = iloc.bh;
    raw_inode = ext4_raw_inode(&iloc);
    @@ -2636,6 +2646,7 @@ void ext4_read_inode(struct inode * inode)
    !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
    /* this inode is deleted */
    brelse (bh);
    + ret = -ESTALE;
    goto bad_inode;
    }
    /* The only unlinked inodes we let through here have
    @@ -2683,6 +2694,7 @@ void ext4_read_inode(struct inode * inode)
    if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
    EXT4_INODE_SIZE(inode->i_sb)) {
    brelse (bh);
    + ret = -EIO;
    goto bad_inode;
    }
    if (ei->i_extra_isize == 0) {
    @@ -2729,11 +2741,12 @@ void ext4_read_inode(struct inode * inode)
    }
    brelse (iloc.bh);
    ext4_set_inode_flags(inode);
    - return;
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    - make_bad_inode(inode);
    - return;
    + iget_failed(inode);
    + return ERR_PTR(ret);
    }

    /*
    diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
    index 5fdb862..301f41f 100644
    --- a/fs/ext4/namei.c
    +++ b/fs/ext4/namei.c
    @@ -1044,17 +1044,11 @@ static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, str
    if (!ext4_valid_inum(dir->i_sb, ino)) {
    ext4_error(dir->i_sb, "ext4_lookup",
    "bad inode number: %lu", ino);
    - inode = NULL;
    - } else
    - inode = iget(dir->i_sb, ino);
    -
    - if (!inode)
    - return ERR_PTR(-EACCES);
    -
    - if (is_bad_inode(inode)) {
    - iput(inode);
    - return ERR_PTR(-ENOENT);
    + return ERR_PTR(-EIO);
    }
    + inode = ext4_iget(dir->i_sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    }
    return d_splice_alias(inode, dentry);
    }
    @@ -1083,18 +1077,13 @@ struct dentry *ext4_get_parent(struct dentry *child)
    if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
    ext4_error(child->d_inode->i_sb, "ext4_get_parent",
    "bad inode number: %lu", ino);
    - inode = NULL;
    - } else
    - inode = iget(child->d_inode->i_sb, ino);
    -
    - if (!inode)
    - return ERR_PTR(-EACCES);
    -
    - if (is_bad_inode(inode)) {
    - iput(inode);
    - return ERR_PTR(-ENOENT);
    + return ERR_PTR(-EIO);
    }

    + inode = ext4_iget(child->d_inode->i_sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    +
    parent = d_alloc_anon(inode);
    if (!parent) {
    iput(inode);
    diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
    index aa11d7d..345f901 100644
    --- a/fs/ext4/resize.c
    +++ b/fs/ext4/resize.c
    @@ -757,12 +757,11 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
    "No reserved GDT blocks, can't resize");
    return -EPERM;
    }
    - inode = iget(sb, EXT4_RESIZE_INO);
    - if (!inode || is_bad_inode(inode)) {
    + inode = ext4_iget(sb, EXT4_RESIZE_INO);
    + if (IS_ERR(inode)) {
    ext4_warning(sb, __FUNCTION__,
    "Error opening resize inode");
    - iput(inode);
    - return -ENOENT;
    + return PTR_ERR(inode);
    }
    }

    diff --git a/fs/ext4/super.c b/fs/ext4/super.c
    index 3c1397f..05434a1 100644
    --- a/fs/ext4/super.c
    +++ b/fs/ext4/super.c
    @@ -634,11 +634,10 @@ static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
    * Currently we don't know the generation for parent directory, so
    * a generation of 0 means "accept any"
    */
    - inode = iget(sb, ino);
    - if (inode == NULL)
    - return ERR_PTR(-ENOMEM);
    - if (is_bad_inode(inode) ||
    - (generation && inode->i_generation != generation)) {
    + inode = ext4_iget(sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    + if (generation && inode->i_generation != generation) {
    iput(inode);
    return ERR_PTR(-ESTALE);
    }
    @@ -700,7 +699,6 @@ static struct quotactl_ops ext4_qctl_operations = {
    static const struct super_operations ext4_sops = {
    .alloc_inode = ext4_alloc_inode,
    .destroy_inode = ext4_destroy_inode,
    - .read_inode = ext4_read_inode,
    .write_inode = ext4_write_inode,
    .dirty_inode = ext4_dirty_inode,
    .delete_inode = ext4_delete_inode,
    @@ -1472,6 +1470,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
    unsigned long journal_devnum = 0;
    unsigned long def_mount_opts;
    struct inode *root;
    + int ret = -EINVAL;
    int blocksize;
    int hblock;
    int db_count;
    @@ -1862,19 +1861,24 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
    * so we can safely mount the rest of the filesystem now.
    */

    - root = iget(sb, EXT4_ROOT_INO);
    - sb->s_root = d_alloc_root(root);
    - if (!sb->s_root) {
    + root = ext4_iget(sb, EXT4_ROOT_INO);
    + if (IS_ERR(root)) {
    printk(KERN_ERR "EXT4-fs: get root inode failed\n");
    - iput(root);
    + ret = PTR_ERR(root);
    goto failed_mount4;
    }
    if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
    - dput(sb->s_root);
    - sb->s_root = NULL;
    + iput(root);
    printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
    goto failed_mount4;
    }
    + sb->s_root = d_alloc_root(root);
    + if (!sb->s_root) {
    + printk(KERN_ERR "EXT4-fs: get root dentry failed\n");
    + iput(root);
    + ret = -ENOMEM;
    + goto failed_mount4;
    + }

    ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);

    @@ -1954,7 +1958,7 @@ out_fail:
    sb->s_fs_info = NULL;
    kfree(sbi);
    lock_kernel();
    - return -EINVAL;
    + return ret;
    }

    /*
    @@ -1990,8 +1994,8 @@ static journal_t *ext4_get_journal(struct super_block *sb,
    * things happen if we iget() an unused inode, as the subsequent
    * iput() will try to delete it. */

    - journal_inode = iget(sb, journal_inum);
    - if (!journal_inode) {
    + journal_inode = ext4_iget(sb, journal_inum);
    + if (IS_ERR(journal_inode)) {
    printk(KERN_ERR "EXT4-fs: no journal found.\n");
    return NULL;
    }
    @@ -2004,7 +2008,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,

    jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
    journal_inode, journal_inode->i_size);
    - if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
    + if (!S_ISREG(journal_inode->i_mode)) {
    printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
    iput(journal_inode);
    return NULL;
    diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
    index cdee7aa..12354d5 100644
    --- a/include/linux/ext4_fs.h
    +++ b/include/linux/ext4_fs.h
    @@ -944,7 +944,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
    sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
    int create, int extend_disksize);

    -extern void ext4_read_inode (struct inode *);
    +extern struct inode *ext4_iget(struct super_block *, unsigned long);
    extern int ext4_write_inode (struct inode *, int);
    extern int ext4_setattr (struct dentry *, struct iattr *);
    extern void ext4_delete_inode (struct inode *);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. [PATCH 13/32] IGET: Stop EXT2 from using iget() and read_inode() [try #2]

    Stop the EXT2 filesystem from using iget() and read_inode(). Replace
    ext2_read_inode() with ext2_iget(), and call that instead of iget().
    ext2_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    ext2_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/ext2/ext2.h | 2 +-
    fs/ext2/inode.c | 30 ++++++++++++++++++++++--------
    fs/ext2/namei.c | 12 ++++++------
    fs/ext2/super.c | 32 ++++++++++++++++++--------------
    4 files changed, 47 insertions(+), 29 deletions(-)

    diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
    index 9fd0ec5..85ca3de 100644
    --- a/fs/ext2/ext2.h
    +++ b/fs/ext2/ext2.h
    @@ -123,7 +123,7 @@ extern void ext2_check_inodes_bitmap (struct super_block *);
    extern unsigned long ext2_count_free (struct buffer_head *, unsigned);

    /* inode.c */
    -extern void ext2_read_inode (struct inode *);
    +extern struct inode *ext2_iget (struct super_block *, unsigned long);
    extern int ext2_write_inode (struct inode *, int);
    extern void ext2_put_inode (struct inode *);
    extern void ext2_delete_inode (struct inode *);
    diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
    index 0079b2c..fa5e115 100644
    --- a/fs/ext2/inode.c
    +++ b/fs/ext2/inode.c
    @@ -1074,20 +1074,32 @@ void ext2_get_inode_flags(struct ext2_inode_info *ei)
    ei->i_flags |= EXT2_DIRSYNC_FL;
    }

    -void ext2_read_inode (struct inode * inode)
    +struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
    {
    - struct ext2_inode_info *ei = EXT2_I(inode);
    - ino_t ino = inode->i_ino;
    + struct ext2_inode_info *ei;
    struct buffer_head * bh;
    - struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
    + struct ext2_inode * raw_inode;
    + struct inode *inode;
    + long ret = -EIO;
    int n;

    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    + ei = EXT2_I(inode);
    #ifdef CONFIG_EXT2_FS_POSIX_ACL
    ei->i_acl = EXT2_ACL_NOT_CACHED;
    ei->i_default_acl = EXT2_ACL_NOT_CACHED;
    #endif
    - if (IS_ERR(raw_inode))
    +
    + raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);
    + if (IS_ERR(raw_inode)) {
    + ret = PTR_ERR(raw_inode);
    goto bad_inode;
    + }

    inode->i_mode = le16_to_cpu(raw_inode->i_mode);
    inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
    @@ -1111,6 +1123,7 @@ void ext2_read_inode (struct inode * inode)
    if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
    /* this inode is deleted */
    brelse (bh);
    + ret = -ESTALE;
    goto bad_inode;
    }
    inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
    @@ -1180,11 +1193,12 @@ void ext2_read_inode (struct inode * inode)
    }
    brelse (bh);
    ext2_set_inode_flags(inode);
    - return;
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    - make_bad_inode(inode);
    - return;
    + iget_failed(inode);
    + return ERR_PTR(ret);
    }

    static int ext2_update_inode(struct inode * inode, int do_sync)
    diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
    index e69beed..80c97fd 100644
    --- a/fs/ext2/namei.c
    +++ b/fs/ext2/namei.c
    @@ -63,9 +63,9 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
    ino = ext2_inode_by_name(dir, dentry);
    inode = NULL;
    if (ino) {
    - inode = iget(dir->i_sb, ino);
    - if (!inode)
    - return ERR_PTR(-EACCES);
    + inode = ext2_iget(dir->i_sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    }
    return d_splice_alias(inode, dentry);
    }
    @@ -83,10 +83,10 @@ struct dentry *ext2_get_parent(struct dentry *child)
    ino = ext2_inode_by_name(child->d_inode, &dotdot);
    if (!ino)
    return ERR_PTR(-ENOENT);
    - inode = iget(child->d_inode->i_sb, ino);
    + inode = ext2_iget(child->d_inode->i_sb, ino);

    - if (!inode)
    - return ERR_PTR(-EACCES);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    parent = d_alloc_anon(inode);
    if (!parent) {
    iput(inode);
    diff --git a/fs/ext2/super.c b/fs/ext2/super.c
    index 639a32c..33e8b29 100644
    --- a/fs/ext2/super.c
    +++ b/fs/ext2/super.c
    @@ -232,7 +232,6 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *da
    static const struct super_operations ext2_sops = {
    .alloc_inode = ext2_alloc_inode,
    .destroy_inode = ext2_destroy_inode,
    - .read_inode = ext2_read_inode,
    .write_inode = ext2_write_inode,
    .put_inode = ext2_put_inode,
    .delete_inode = ext2_delete_inode,
    @@ -266,11 +265,10 @@ static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp)
    * it might be "neater" to call ext2_get_inode first and check
    * if the inode is valid.....
    */
    - inode = iget(sb, ino);
    - if (inode == NULL)
    - return ERR_PTR(-ENOMEM);
    - if (is_bad_inode(inode) ||
    - (generation && inode->i_generation != generation)) {
    + inode = ext2_iget(sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    + if (generation && inode->i_generation != generation) {
    /* we didn't find the right inode.. */
    iput(inode);
    return ERR_PTR(-ESTALE);
    @@ -649,6 +647,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
    unsigned long logic_sb_block;
    unsigned long offset = 0;
    unsigned long def_mount_opts;
    + long ret = -EINVAL;
    int blocksize = BLOCK_SIZE;
    int db_count;
    int i, j;
    @@ -918,19 +917,24 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
    sb->s_op = &ext2_sops;
    sb->s_export_op = &ext2_export_ops;
    sb->s_xattr = ext2_xattr_handlers;
    - root = iget(sb, EXT2_ROOT_INO);
    - sb->s_root = d_alloc_root(root);
    - if (!sb->s_root) {
    - iput(root);
    - printk(KERN_ERR "EXT2-fs: get root inode failed\n");
    + root = ext2_iget(sb, EXT2_ROOT_INO);
    + if (IS_ERR(root)) {
    + ret = PTR_ERR(root);
    goto failed_mount3;
    }
    if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
    - dput(sb->s_root);
    - sb->s_root = NULL;
    + iput(root);
    printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
    goto failed_mount3;
    }
    +
    + sb->s_root = d_alloc_root(root);
    + if (!sb->s_root) {
    + iput(root);
    + printk(KERN_ERR "EXT2-fs: get root inode failed\n");
    + ret = -ENOMEM;
    + goto failed_mount3;
    + }
    if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
    ext2_warning(sb, __FUNCTION__,
    "mounting ext3 filesystem as ext2");
    @@ -957,7 +961,7 @@ failed_mount:
    failed_sbi:
    sb->s_fs_info = NULL;
    kfree(sbi);
    - return -EINVAL;
    + return ret;
    }

    static void ext2_commit_super (struct super_block * sb,

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. [PATCH 11/32] IGET: Stop CIFS from using iget() and read_inode() [try #2]

    Stop the CIFS filesystem from using iget() and read_inode(). Replace
    cifs_read_inode() with cifs_iget(), and call that instead of iget().
    cifs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    cifs_read_super() now returns any error incurred when getting the root inode
    instead of ENOMEM.

    Signed-off-by: David Howells
    ---

    fs/cifs/cifsfs.c | 8 ++++----
    fs/cifs/cifsfs.h | 1 +
    fs/cifs/inode.c | 35 ++++++++++++++++++++++++++---------
    3 files changed, 31 insertions(+), 13 deletions(-)

    diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
    index cabb6a5..1cb13f5 100644
    --- a/fs/cifs/cifsfs.c
    +++ b/fs/cifs/cifsfs.c
    @@ -126,10 +126,11 @@ cifs_read_super(struct super_block *sb, void *data,
    #endif
    sb->s_blocksize = CIFS_MAX_MSGSIZE;
    sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
    - inode = iget(sb, ROOT_I);
    + inode = cifs_iget(sb, ROOT_I);

    - if (!inode) {
    - rc = -ENOMEM;
    + if (IS_ERR(inode)) {
    + rc = PTR_ERR(inode);
    + inode = NULL;
    goto out_no_root;
    }

    @@ -481,7 +482,6 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data)
    }

    static const struct super_operations cifs_super_ops = {
    - .read_inode = cifs_read_inode,
    .put_super = cifs_put_super,
    .statfs = cifs_statfs,
    .alloc_inode = cifs_alloc_inode,
    diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
    index a20de77..74a3190 100644
    --- a/fs/cifs/cifsfs.h
    +++ b/fs/cifs/cifsfs.h
    @@ -43,6 +43,7 @@ extern void cifs_read_inode(struct inode *);

    /* Functions related to inodes */
    extern const struct inode_operations cifs_dir_inode_ops;
    +extern struct inode *cifs_iget(struct super_block *, unsigned long);
    extern int cifs_create(struct inode *, struct dentry *, int,
    struct nameidata *);
    extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
    diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
    index dd41677..48966b9 100644
    --- a/fs/cifs/inode.c
    +++ b/fs/cifs/inode.c
    @@ -576,20 +576,37 @@ int cifs_get_inode_info(struct inode **pinode,
    }

    /* gets root inode */
    -void cifs_read_inode(struct inode *inode)
    +struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
    {
    int xid;
    struct cifs_sb_info *cifs_sb;
    + struct inode *inode;
    + long ret;

    - cifs_sb = CIFS_SB(inode->i_sb);
    - xid = GetXid();
    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (inode->i_state & I_NEW) {
    + cifs_sb = CIFS_SB(inode->i_sb);
    + xid = GetXid();

    - if (cifs_sb->tcon->unix_ext)
    - cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
    - else
    - cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
    - /* can not call macro FreeXid here since in a void func */
    - _FreeXid(xid);
    + if (cifs_sb->tcon->unix_ext)
    + ret = cifs_get_inode_info_unix(&inode, "", inode->i_sb,
    + xid);
    + else
    + ret = cifs_get_inode_info(&inode, "", NULL, inode->i_sb,
    + xid);
    + /* can not call macro FreeXid here since in a void func */
    + _FreeXid(xid);
    + if (ret < 0) {
    + iget_failed(inode);
    + inode = ERR_PTR(ret);
    + } else {
    + unlock_new_inode(inode);
    + }
    + }
    +
    + return inode;
    }

    int cifs_unlink(struct inode *inode, struct dentry *direntry)

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. [PATCH 14/32] IGET: Stop EXT3 from using iget() and read_inode() [try #2]

    Stop the EXT3 filesystem from using iget() and read_inode(). Replace
    ext3_read_inode() with ext3_iget(), and call that instead of iget().
    ext3_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    ext3_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/ext3/ialloc.c | 58 ++++++++++++++++++++++++++++-------------------
    fs/ext3/inode.c | 25 +++++++++++++++-----
    fs/ext3/namei.c | 29 +++++++-----------------
    fs/ext3/resize.c | 7 ++----
    fs/ext3/super.c | 40 ++++++++++++++++++--------------
    include/linux/ext3_fs.h | 2 +-
    6 files changed, 89 insertions(+), 72 deletions(-)

    diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
    index e45dbd6..5724adb 100644
    --- a/fs/ext3/ialloc.c
    +++ b/fs/ext3/ialloc.c
    @@ -645,14 +645,15 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
    unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
    unsigned long block_group;
    int bit;
    - struct buffer_head *bitmap_bh = NULL;
    + struct buffer_head *bitmap_bh;
    struct inode *inode = NULL;
    + long err = -EIO;

    /* Error cases - e2fsck has already cleaned up for us */
    if (ino > max_ino) {
    ext3_warning(sb, __FUNCTION__,
    "bad orphan ino %lu! e2fsck was run?", ino);
    - goto out;
    + goto error;
    }

    block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
    @@ -661,38 +662,49 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
    if (!bitmap_bh) {
    ext3_warning(sb, __FUNCTION__,
    "inode bitmap error for orphan %lu", ino);
    - goto out;
    + goto error;
    }

    /* Having the inode bit set should be a 100% indicator that this
    * is a valid orphan (no e2fsck run on fs). Orphans also include
    * inodes that were being truncated, so we can't check i_nlink==0.
    */
    - if (!ext3_test_bit(bit, bitmap_bh->b_data) ||
    - !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
    - NEXT_ORPHAN(inode) > max_ino) {
    - ext3_warning(sb, __FUNCTION__,
    - "bad orphan inode %lu! e2fsck was run?", ino);
    - printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
    - bit, (unsigned long long)bitmap_bh->b_blocknr,
    - ext3_test_bit(bit, bitmap_bh->b_data));
    - printk(KERN_NOTICE "inode=%p\n", inode);
    - if (inode) {
    - printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
    - is_bad_inode(inode));
    - printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
    - NEXT_ORPHAN(inode));
    - printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
    - }
    + if (!ext3_test_bit(bit, bitmap_bh->b_data))
    + goto bad_orphan;
    +
    + inode = ext3_iget(sb, ino);
    + if (IS_ERR(inode))
    + goto iget_failed;
    +
    + if (NEXT_ORPHAN(inode) > max_ino)
    + goto bad_orphan;
    + brelse(bitmap_bh);
    + return inode;
    +
    +iget_failed:
    + err = PTR_ERR(inode);
    + inode = NULL;
    +bad_orphan:
    + ext3_warning(sb, __FUNCTION__,
    + "bad orphan inode %lu! e2fsck was run?", ino);
    + printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n",
    + bit, (unsigned long long)bitmap_bh->b_blocknr,
    + ext3_test_bit(bit, bitmap_bh->b_data));
    + printk(KERN_NOTICE "inode=%p\n", inode);
    + if (inode) {
    + printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
    + is_bad_inode(inode));
    + printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
    + NEXT_ORPHAN(inode));
    + printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
    /* Avoid freeing blocks if we got a bad deleted inode */
    - if (inode && inode->i_nlink == 0)
    + if (inode->i_nlink == 0)
    inode->i_blocks = 0;
    iput(inode);
    - inode = NULL;
    }
    -out:
    brelse(bitmap_bh);
    - return inode;
    +error:
    + return ERR_PTR(err);
    }

    unsigned long ext3_count_free_inodes (struct super_block * sb)
    diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
    index de4e316..6c74622 100644
    --- a/fs/ext3/inode.c
    +++ b/fs/ext3/inode.c
    @@ -2591,21 +2591,31 @@ void ext3_get_inode_flags(struct ext3_inode_info *ei)
    ei->i_flags |= EXT3_DIRSYNC_FL;
    }

    -void ext3_read_inode(struct inode * inode)
    +struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
    {
    struct ext3_iloc iloc;
    struct ext3_inode *raw_inode;
    - struct ext3_inode_info *ei = EXT3_I(inode);
    + struct ext3_inode_info *ei;
    struct buffer_head *bh;
    + struct inode *inode;
    + long ret;
    int block;

    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    + ei = EXT3_I(inode);
    #ifdef CONFIG_EXT3_FS_POSIX_ACL
    ei->i_acl = EXT3_ACL_NOT_CACHED;
    ei->i_default_acl = EXT3_ACL_NOT_CACHED;
    #endif
    ei->i_block_alloc_info = NULL;

    - if (__ext3_get_inode_loc(inode, &iloc, 0))
    + ret = __ext3_get_inode_loc(inode, &iloc, 0);
    + if (ret < 0)
    goto bad_inode;
    bh = iloc.bh;
    raw_inode = ext3_raw_inode(&iloc);
    @@ -2636,6 +2646,7 @@ void ext3_read_inode(struct inode * inode)
    !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ORPHAN_FS)) {
    /* this inode is deleted */
    brelse (bh);
    + ret = -ESTALE;
    goto bad_inode;
    }
    /* The only unlinked inodes we let through here have
    @@ -2679,6 +2690,7 @@ void ext3_read_inode(struct inode * inode)
    if (EXT3_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
    EXT3_INODE_SIZE(inode->i_sb)) {
    brelse (bh);
    + ret = -EIO;
    goto bad_inode;
    }
    if (ei->i_extra_isize == 0) {
    @@ -2720,11 +2732,12 @@ void ext3_read_inode(struct inode * inode)
    }
    brelse (iloc.bh);
    ext3_set_inode_flags(inode);
    - return;
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    - make_bad_inode(inode);
    - return;
    + iget_failed(inode);
    + return ERR_PTR(ret);
    }

    /*
    diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
    index c1fa190..6919a18 100644
    --- a/fs/ext3/namei.c
    +++ b/fs/ext3/namei.c
    @@ -1046,17 +1046,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
    if (!ext3_valid_inum(dir->i_sb, ino)) {
    ext3_error(dir->i_sb, "ext3_lookup",
    "bad inode number: %lu", ino);
    - inode = NULL;
    - } else
    - inode = iget(dir->i_sb, ino);
    -
    - if (!inode)
    - return ERR_PTR(-EACCES);
    -
    - if (is_bad_inode(inode)) {
    - iput(inode);
    - return ERR_PTR(-ENOENT);
    + return ERR_PTR(-EIO);
    }
    + inode = ext3_iget(dir->i_sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    }
    return d_splice_alias(inode, dentry);
    }
    @@ -1085,18 +1079,13 @@ struct dentry *ext3_get_parent(struct dentry *child)
    if (!ext3_valid_inum(child->d_inode->i_sb, ino)) {
    ext3_error(child->d_inode->i_sb, "ext3_get_parent",
    "bad inode number: %lu", ino);
    - inode = NULL;
    - } else
    - inode = iget(child->d_inode->i_sb, ino);
    -
    - if (!inode)
    - return ERR_PTR(-EACCES);
    -
    - if (is_bad_inode(inode)) {
    - iput(inode);
    - return ERR_PTR(-ENOENT);
    + return ERR_PTR(-EIO);
    }

    + inode = ext3_iget(child->d_inode->i_sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    +
    parent = d_alloc_anon(inode);
    if (!parent) {
    iput(inode);
    diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
    index 2c97e09..60b6530 100644
    --- a/fs/ext3/resize.c
    +++ b/fs/ext3/resize.c
    @@ -748,12 +748,11 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
    "No reserved GDT blocks, can't resize");
    return -EPERM;
    }
    - inode = iget(sb, EXT3_RESIZE_INO);
    - if (!inode || is_bad_inode(inode)) {
    + inode = ext3_iget(sb, EXT3_RESIZE_INO);
    + if (IS_ERR(inode)) {
    ext3_warning(sb, __FUNCTION__,
    "Error opening resize inode");
    - iput(inode);
    - return -ENOENT;
    + return PTR_ERR(inode);
    }
    }

    diff --git a/fs/ext3/super.c b/fs/ext3/super.c
    index 9537316..add683b 100644
    --- a/fs/ext3/super.c
    +++ b/fs/ext3/super.c
    @@ -583,11 +583,10 @@ static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp)
    * Currently we don't know the generation for parent directory, so
    * a generation of 0 means "accept any"
    */
    - inode = iget(sb, ino);
    - if (inode == NULL)
    - return ERR_PTR(-ENOMEM);
    - if (is_bad_inode(inode) ||
    - (generation && inode->i_generation != generation)) {
    + inode = ext3_iget(sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    + if (generation && inode->i_generation != generation) {
    iput(inode);
    return ERR_PTR(-ESTALE);
    }
    @@ -649,7 +648,6 @@ static struct quotactl_ops ext3_qctl_operations = {
    static const struct super_operations ext3_sops = {
    .alloc_inode = ext3_alloc_inode,
    .destroy_inode = ext3_destroy_inode,
    - .read_inode = ext3_read_inode,
    .write_inode = ext3_write_inode,
    .dirty_inode = ext3_dirty_inode,
    .delete_inode = ext3_delete_inode,
    @@ -1309,8 +1307,8 @@ static void ext3_orphan_cleanup (struct super_block * sb,
    while (es->s_last_orphan) {
    struct inode *inode;

    - if (!(inode =
    - ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
    + inode = ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
    + if (IS_ERR(inode)) {
    es->s_last_orphan = 0;
    break;
    }
    @@ -1415,6 +1413,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
    int db_count;
    int i;
    int needs_recovery;
    + int ret = -EINVAL;
    __le32 features;

    sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
    @@ -1770,19 +1769,24 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
    * so we can safely mount the rest of the filesystem now.
    */

    - root = iget(sb, EXT3_ROOT_INO);
    - sb->s_root = d_alloc_root(root);
    - if (!sb->s_root) {
    + root = ext3_iget(sb, EXT3_ROOT_INO);
    + if (IS_ERR(root)) {
    printk(KERN_ERR "EXT3-fs: get root inode failed\n");
    - iput(root);
    + ret = PTR_ERR(root);
    goto failed_mount4;
    }
    if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
    - dput(sb->s_root);
    - sb->s_root = NULL;
    + iput(root);
    printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
    goto failed_mount4;
    }
    + sb->s_root = d_alloc_root(root);
    + if (!sb->s_root) {
    + printk(KERN_ERR "EXT3-fs: get root dentry failed\n");
    + iput(root);
    + ret = -ENOMEM;
    + goto failed_mount4;
    + }

    ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
    /*
    @@ -1834,7 +1838,7 @@ out_fail:
    sb->s_fs_info = NULL;
    kfree(sbi);
    lock_kernel();
    - return -EINVAL;
    + return ret;
    }

    /*
    @@ -1870,8 +1874,8 @@ static journal_t *ext3_get_journal(struct super_block *sb,
    * things happen if we iget() an unused inode, as the subsequent
    * iput() will try to delete it. */

    - journal_inode = iget(sb, journal_inum);
    - if (!journal_inode) {
    + journal_inode = ext3_iget(sb, journal_inum);
    + if (IS_ERR(journal_inode)) {
    printk(KERN_ERR "EXT3-fs: no journal found.\n");
    return NULL;
    }
    @@ -1884,7 +1888,7 @@ static journal_t *ext3_get_journal(struct super_block *sb,

    jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
    journal_inode, journal_inode->i_size);
    - if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
    + if (!S_ISREG(journal_inode->i_mode)) {
    printk(KERN_ERR "EXT3-fs: invalid journal inode.\n");
    iput(journal_inode);
    return NULL;
    diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
    index ece49a8..a5ccfea 100644
    --- a/include/linux/ext3_fs.h
    +++ b/include/linux/ext3_fs.h
    @@ -813,7 +813,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
    sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
    int create, int extend_disksize);

    -extern void ext3_read_inode (struct inode *);
    +extern struct inode *ext3_iget (struct super_block *, unsigned long);
    extern int ext3_write_inode (struct inode *, int);
    extern int ext3_setattr (struct dentry *, struct iattr *);
    extern void ext3_delete_inode (struct inode *);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. [PATCH 17/32] IGET: Stop FreeVXFS from using iget() and read_inode() [try #2]

    Stop the FreeVXFS filesystem from using iget() and read_inode(). Replace
    vxfs_read_inode() with vxfs_iget(), and call that instead of iget().
    vxfs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    vxfs_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/freevxfs/vxfs_extern.h | 2 +-
    fs/freevxfs/vxfs_inode.c | 45 +++++++++++++++++++++++++++++----------------
    fs/freevxfs/vxfs_lookup.c | 6 +++---
    fs/freevxfs/vxfs_super.c | 10 +++++++---
    4 files changed, 40 insertions(+), 23 deletions(-)

    diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
    index 91ccee8..f307694 100644
    --- a/fs/freevxfs/vxfs_extern.h
    +++ b/fs/freevxfs/vxfs_extern.h
    @@ -58,7 +58,7 @@ extern struct inode * vxfs_get_fake_inode(struct super_block *,
    extern void vxfs_put_fake_inode(struct inode *);
    extern struct vxfs_inode_info * vxfs_blkiget(struct super_block *, u_long, ino_t);
    extern struct vxfs_inode_info * vxfs_stiget(struct super_block *, ino_t);
    -extern void vxfs_read_inode(struct inode *);
    +extern struct inode * vxfs_iget(struct super_block *, unsigned long);
    extern void vxfs_clear_inode(struct inode *);

    /* vxfs_lookup.c */
    diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
    index d1f7c5b..95a0af9 100644
    --- a/fs/freevxfs/vxfs_inode.c
    +++ b/fs/freevxfs/vxfs_inode.c
    @@ -129,7 +129,7 @@ fail:
    * Description:
    * Search the for inode number @ino in the filesystem
    * described by @sbp. Use the specified inode table (@ilistp).
    - * Returns the matching VxFS inode on success, else a NULL pointer.
    + * Returns the matching VxFS inode on success, else an error code.
    */
    static struct vxfs_inode_info *
    __vxfs_iget(ino_t ino, struct inode *ilistp)
    @@ -157,12 +157,12 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
    }

    printk(KERN_WARNING "vxfs: error on page %p\n", pp);
    - return NULL;
    + return ERR_CAST(pp);

    fail:
    printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino);
    vxfs_put_page(pp);
    - return NULL;
    + return ERR_PTR(-ENOMEM);
    }

    /**
    @@ -178,7 +178,10 @@ fail:
    struct vxfs_inode_info *
    vxfs_stiget(struct super_block *sbp, ino_t ino)
    {
    - return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
    + struct vxfs_inode_info *vip;
    +
    + vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
    + return IS_ERR(vip) ? NULL : vip;
    }

    /**
    @@ -282,23 +285,32 @@ vxfs_put_fake_inode(struct inode *ip)
    }

    /**
    - * vxfs_read_inode - fill in inode information
    - * @ip: inode pointer to fill
    + * vxfs_iget - get an inode
    + * @sbp: the superblock to get the inode for
    + * @ino: the number of the inode to get
    *
    * Description:
    - * vxfs_read_inode reads the disk inode for @ip and fills
    - * in all relevant fields in @ip.
    + * vxfs_read_inode creates an inode, reads the disk inode for @ino and fills
    + * in all relevant fields in the new inode.
    */
    -void
    -vxfs_read_inode(struct inode *ip)
    +struct inode *
    +vxfs_iget(struct super_block *sbp, ino_t ino)
    {
    - struct super_block *sbp = ip->i_sb;
    struct vxfs_inode_info *vip;
    const struct address_space_operations *aops;
    - ino_t ino = ip->i_ino;
    -
    - if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
    - return;
    + struct inode *ip;
    +
    + ip = iget_locked(sbp, ino);
    + if (!ip)
    + return ERR_PTR(-ENOMEM);
    + if (!(ip->i_state & I_NEW))
    + return ip;
    +
    + vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist);
    + if (IS_ERR(vip)) {
    + iget_failed(ip);
    + return ERR_CAST(vip);
    + }

    vxfs_iinit(ip, vip);

    @@ -323,7 +335,8 @@ vxfs_read_inode(struct inode *ip)
    } else
    init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));

    - return;
    + unlock_new_inode(ip);
    + return ip;
    }

    /**
    diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
    index bf86e54..aee049c 100644
    --- a/fs/freevxfs/vxfs_lookup.c
    +++ b/fs/freevxfs/vxfs_lookup.c
    @@ -213,10 +213,10 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
    lock_kernel();
    ino = vxfs_inode_by_name(dip, dp);
    if (ino) {
    - ip = iget(dip->i_sb, ino);
    - if (!ip) {
    + ip = vxfs_iget(dip->i_sb, ino);
    + if (IS_ERR(ip)) {
    unlock_kernel();
    - return ERR_PTR(-EACCES);
    + return ERR_CAST(ip);
    }
    }
    unlock_kernel();
    diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
    index 4f95572..1dacda8 100644
    --- a/fs/freevxfs/vxfs_super.c
    +++ b/fs/freevxfs/vxfs_super.c
    @@ -60,7 +60,6 @@ static int vxfs_statfs(struct dentry *, struct kstatfs *);
    static int vxfs_remount(struct super_block *, int *, char *);

    static const struct super_operations vxfs_super_ops = {
    - .read_inode = vxfs_read_inode,
    .clear_inode = vxfs_clear_inode,
    .put_super = vxfs_put_super,
    .statfs = vxfs_statfs,
    @@ -153,6 +152,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
    struct buffer_head *bp = NULL;
    u_long bsize;
    struct inode *root;
    + int ret = -EINVAL;

    sbp->s_flags |= MS_RDONLY;

    @@ -219,7 +219,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
    }

    sbp->s_op = &vxfs_super_ops;
    - root = iget(sbp, VXFS_ROOT_INO);
    + root = vxfs_iget(sbp, VXFS_ROOT_INO);
    + if (IS_ERR(root)) {
    + ret = PTR_ERR(root);
    + goto out;
    + }
    sbp->s_root = d_alloc_root(root);
    if (!sbp->s_root) {
    iput(root);
    @@ -236,7 +240,7 @@ out_free_ilist:
    out:
    brelse(bp);
    kfree(infp);
    - return -EINVAL;
    + return ret;
    }

    /*

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. [PATCH 16/32] IGET: Stop FAT from using iget() and read_inode() [try #2]

    Stop the FAT filesystem from using iget() and read_inode(). Replace
    the call to iget() with a call to ilookup().

    Signed-off-by: David Howells
    ---

    fs/fat/inode.c | 6 ++----
    1 files changed, 2 insertions(+), 4 deletions(-)

    diff --git a/fs/fat/inode.c b/fs/fat/inode.c
    index 960ed3d..9ae2e9f 100644
    --- a/fs/fat/inode.c
    +++ b/fs/fat/inode.c
    @@ -629,8 +629,6 @@ static const struct super_operations fat_sops = {
    .clear_inode = fat_clear_inode,
    .remount_fs = fat_remount,

    - .read_inode = make_bad_inode,
    -
    .show_options = fat_show_options,
    };

    @@ -667,8 +665,8 @@ static struct dentry *fat_get_dentry(struct super_block *sb, void *inump)
    struct dentry *result;
    __u32 *fh = inump;

    - inode = iget(sb, fh[0]);
    - if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) {
    + inode = ilookup(sb, fh[0]);
    + if (!inode || inode->i_generation != fh[1]) {
    if (inode)
    iput(inode);
    inode = NULL;

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. [PATCH 08/32] IGET: Stop autofs from using iget() and read_inode() [try #2]

    Stop the autofs filesystem from using iget() and read_inode(). Replace
    autofs_read_inode() with autofs_iget(), and call that instead of iget().
    autofs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    Signed-off-by: David Howells
    ---

    fs/autofs/autofs_i.h | 1 +
    fs/autofs/inode.c | 27 ++++++++++++++++++---------
    fs/autofs/root.c | 22 ++++++++++++++++++----
    3 files changed, 37 insertions(+), 13 deletions(-)

    diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
    index 8b4cca3..901a3e6 100644
    --- a/fs/autofs/autofs_i.h
    +++ b/fs/autofs/autofs_i.h
    @@ -150,6 +150,7 @@ extern const struct file_operations autofs_root_operations;

    int autofs_fill_super(struct super_block *, void *, int);
    void autofs_kill_sb(struct super_block *sb);
    +struct inode *autofs_iget(struct super_block *, unsigned long);

    /* Queue management functions */

    diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
    index e7204d7..fc6a15e 100644
    --- a/fs/autofs/inode.c
    +++ b/fs/autofs/inode.c
    @@ -52,10 +52,7 @@ out_kill_sb:
    kill_anon_super(sb);
    }

    -static void autofs_read_inode(struct inode *inode);
    -
    static const struct super_operations autofs_sops = {
    - .read_inode = autofs_read_inode,
    .statfs = simple_statfs,
    };

    @@ -164,7 +161,9 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
    s->s_time_gran = 1;
    sbi->sb = s;

    - root_inode = iget(s, AUTOFS_ROOT_INO);
    + root_inode = autofs_iget(s, AUTOFS_ROOT_INO);
    + if (IS_ERR(root_inode))
    + goto fail_free;
    root = d_alloc_root(root_inode);
    pipe = NULL;

    @@ -230,11 +229,17 @@ fail_unlock:
    return -EINVAL;
    }

    -static void autofs_read_inode(struct inode *inode)
    +struct inode *autofs_iget(struct super_block *sb, unsigned long ino)
    {
    - ino_t ino = inode->i_ino;
    unsigned int n;
    - struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
    + struct autofs_sb_info *sbi = autofs_sbi(sb);
    + struct inode *inode;
    +
    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;

    /* Initialize to the default case (stub directory) */

    @@ -250,7 +255,7 @@ static void autofs_read_inode(struct inode *inode)
    inode->i_op = &autofs_root_inode_operations;
    inode->i_fop = &autofs_root_operations;
    inode->i_uid = inode->i_gid = 0; /* Changed in read_super */
    - return;
    + goto done;
    }

    inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
    @@ -263,7 +268,7 @@ static void autofs_read_inode(struct inode *inode)
    n = ino - AUTOFS_FIRST_SYMLINK;
    if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
    printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino);
    - return;
    + goto done;
    }

    inode->i_op = &autofs_symlink_inode_operations;
    @@ -275,4 +280,8 @@ static void autofs_read_inode(struct inode *inode)
    inode->i_size = sl->len;
    inode->i_nlink = 1;
    }
    +
    +done:
    + unlock_new_inode(inode);
    + return inode;
    }
    diff --git a/fs/autofs/root.c b/fs/autofs/root.c
    index c148953..3aec567 100644
    --- a/fs/autofs/root.c
    +++ b/fs/autofs/root.c
    @@ -114,8 +114,8 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
    dentry->d_time = (unsigned long) ent;

    if (!dentry->d_inode) {
    - inode = iget(sb, ent->ino);
    - if (!inode) {
    + inode = autofs_iget(sb, ent->ino);
    + if (IS_ERR(inode)) {
    /* Failed, but leave pending for next time */
    return 1;
    }
    @@ -274,6 +274,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
    unsigned int n;
    int slsize;
    struct autofs_symlink *sl;
    + struct inode *inode;

    DPRINTK(("autofs_root_symlink: %s <- ", symname));
    autofs_say(dentry->d_name.name,dentry->d_name.len);
    @@ -331,7 +332,12 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c
    ent->dentry = NULL; /* We don't keep the dentry for symlinks */

    autofs_hash_insert(dh,ent);
    - d_instantiate(dentry, iget(dir->i_sb,ent->ino));
    +
    + inode = autofs_iget(dir->i_sb, ent->ino);
    + if (IS_ERR(inode))
    + return PTR_ERR(inode);
    +
    + d_instantiate(dentry, inode);
    unlock_kernel();
    return 0;
    }
    @@ -428,6 +434,7 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
    struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
    struct autofs_dirhash *dh = &sbi->dirhash;
    struct autofs_dir_ent *ent;
    + struct inode *inode;
    ino_t ino;

    lock_kernel();
    @@ -469,7 +476,14 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
    autofs_hash_insert(dh,ent);

    inc_nlink(dir);
    - d_instantiate(dentry, iget(dir->i_sb,ino));
    +
    + inode = autofs_iget(dir->i_sb, ino);
    + if (IS_ERR(inode)) {
    + drop_nlink(dir);
    + return PTR_ERR(inode);
    + }
    +
    + d_instantiate(dentry, inode);
    unlock_kernel();

    return 0;

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. [PATCH 07/32] IGET: Stop AFFS from using iget() and read_inode() [try #2]

    Stop the AFFS filesystem from using iget() and read_inode(). Replace
    affs_read_inode() with affs_iget(), and call that instead of iget().
    affs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    affs_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/affs/affs.h | 2 +-
    fs/affs/amigaffs.c | 6 ++++--
    fs/affs/inode.c | 20 +++++++++++++-------
    fs/affs/namei.c | 10 ++++------
    fs/affs/super.c | 12 +++++++++---
    5 files changed, 31 insertions(+), 19 deletions(-)

    diff --git a/fs/affs/affs.h b/fs/affs/affs.h
    index 232c694..0bce4ff 100644
    --- a/fs/affs/affs.h
    +++ b/fs/affs/affs.h
    @@ -174,7 +174,7 @@ extern void affs_put_inode(struct inode *inode);
    extern void affs_drop_inode(struct inode *inode);
    extern void affs_delete_inode(struct inode *inode);
    extern void affs_clear_inode(struct inode *inode);
    -extern void affs_read_inode(struct inode *inode);
    +extern struct inode *affs_iget(struct super_block *sb, unsigned long ino);
    extern int affs_write_inode(struct inode *inode, int);
    extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s32 type);

    diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
    index f4de4b9..8055730 100644
    --- a/fs/affs/amigaffs.c
    +++ b/fs/affs/amigaffs.c
    @@ -170,9 +170,11 @@ affs_remove_link(struct dentry *dentry)
    if (!link_bh)
    goto done;

    - dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
    - if (!dir)
    + dir = affs_iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
    + if (IS_ERR(dir)) {
    + retval = PTR_ERR(dir);
    goto done;
    + }

    affs_lock_dir(dir);
    affs_fix_dcache(dentry, link_ino);
    diff --git a/fs/affs/inode.c b/fs/affs/inode.c
    index 4609a6c..edea76c 100644
    --- a/fs/affs/inode.c
    +++ b/fs/affs/inode.c
    @@ -15,20 +15,25 @@
    extern const struct inode_operations affs_symlink_inode_operations;
    extern struct timezone sys_tz;

    -void
    -affs_read_inode(struct inode *inode)
    +struct inode *affs_iget(struct super_block *sb, unsigned long ino)
    {
    - struct super_block *sb = inode->i_sb;
    struct affs_sb_info *sbi = AFFS_SB(sb);
    struct buffer_head *bh;
    struct affs_head *head;
    struct affs_tail *tail;
    + struct inode *inode;
    u32 block;
    u32 size;
    u32 prot;
    u16 id;

    - pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    + pr_debug("AFFS: affs_iget(%lu)\n",inode->i_ino);

    block = inode->i_ino;
    bh = affs_bread(sb, block);
    @@ -154,12 +159,13 @@ affs_read_inode(struct inode *inode)
    sys_tz.tz_minuteswest * 60;
    inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_atime.tv_nsec = 0;
    affs_brelse(bh);
    - return;
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    - make_bad_inode(inode);
    affs_brelse(bh);
    - return;
    + iget_failed(inode);
    + return ERR_PTR(-EIO);
    }

    int
    diff --git a/fs/affs/namei.c b/fs/affs/namei.c
    index b407e9e..2218f1e 100644
    --- a/fs/affs/namei.c
    +++ b/fs/affs/namei.c
    @@ -208,9 +208,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
    affs_lock_dir(dir);
    bh = affs_find_entry(dir, dentry);
    affs_unlock_dir(dir);
    - if (IS_ERR(bh)) {
    + if (IS_ERR(bh))
    return ERR_CAST(bh);
    - }
    if (bh) {
    u32 ino = bh->b_blocknr;

    @@ -223,10 +222,9 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
    ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
    }
    affs_brelse(bh);
    - inode = iget(sb, ino);
    - if (!inode) {
    - return ERR_PTR(-EACCES);
    - }
    + inode = affs_iget(sb, ino);
    + if (IS_ERR(inode))
    + return ERR_PTR(PTR_ERR(inode));
    }
    dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
    d_add(dentry, inode);
    diff --git a/fs/affs/super.c b/fs/affs/super.c
    index c80191a..f005050 100644
    --- a/fs/affs/super.c
    +++ b/fs/affs/super.c
    @@ -113,7 +113,6 @@ static void destroy_inodecache(void)
    static const struct super_operations affs_sops = {
    .alloc_inode = affs_alloc_inode,
    .destroy_inode = affs_destroy_inode,
    - .read_inode = affs_read_inode,
    .write_inode = affs_write_inode,
    .put_inode = affs_put_inode,
    .drop_inode = affs_drop_inode,
    @@ -271,6 +270,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
    unsigned long mount_flags;
    int tmp_flags; /* fix remount prototype... */
    u8 sig[4];
    + int ret = -EINVAL;

    pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");

    @@ -444,7 +444,12 @@ got_root:

    /* set up enough so that it can read an inode */

    - root_inode = iget(sb, root_block);
    + root_inode = affs_iget(sb, root_block);
    + if (IS_ERR(root_inode)) {
    + ret = PTR_ERR(root_inode);
    + goto out_error_noinode;
    + }
    +
    sb->s_root = d_alloc_root(root_inode);
    if (!sb->s_root) {
    printk(KERN_ERR "AFFS: Get root inode failed\n");
    @@ -461,12 +466,13 @@ got_root:
    out_error:
    if (root_inode)
    iput(root_inode);
    +out_error_noinode:
    kfree(sbi->s_bitmap);
    affs_brelse(root_bh);
    kfree(sbi->s_prefix);
    kfree(sbi);
    sb->s_fs_info = NULL;
    - return -EINVAL;
    + return ret;
    }

    static int

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. [PATCH 06/32] IGET: Mark iget() and read_inode() as being obsolete [try #2]

    Mark iget() and read_inode() as being obsolete and remove references to them
    from the documentation.

    Typically a filesystem will be modified such that the read_inode function
    becomes an internal iget function, for example the following:

    void thingyfs_read_inode(struct inode *inode)
    {
    ...
    }

    would be changed into something like:

    struct inode *thingyfs_iget(struct super_block *sp, unsigned long ino)
    {
    struct inode *inode;
    int ret;

    inode = iget_locked(sb, ino);
    if (!inode)
    return ERR_PTR(-ENOMEM);
    if (!(inode->i_state & I_NEW))
    return inode;

    ...
    unlock_new_inode(inode);
    return inode;
    error:
    iget_failed(inode);
    return ERR_PTR(ret);
    }

    and then thingyfs_iget() would be called rather than iget(), for example:

    ret = -EINVAL;
    inode = iget(sb, ino);
    if (!inode || is_bad_inode(inode))
    goto error;

    becomes:

    inode = thingyfs_iget(sb, ino);
    if (IS_ERR(inode)) {
    ret = PTR_ERR(inode);
    goto error;
    }

    Signed-off-by: David Howells
    ---

    Documentation/filesystems/Exporting | 5 -----
    Documentation/filesystems/Locking | 3 ---
    Documentation/filesystems/vfs.txt | 16 +++++-----------
    fs/inode.c | 16 ++++++++++++++++
    include/linux/fs.h | 16 +++-------------
    5 files changed, 24 insertions(+), 32 deletions(-)

    diff --git a/Documentation/filesystems/Exporting b/Documentation/filesystems/Exporting
    index 31047e0..22ce3b2 100644
    --- a/Documentation/filesystems/Exporting
    +++ b/Documentation/filesystems/Exporting
    @@ -144,11 +144,6 @@ filesystem:
    decode_fh passes two datums through find_exported_dentry. One that
    should be used to identify the target object, and one that can be
    used to identify the object's parent, should that be necessary.
    - The default get_dentry function assumes that the datum contains an
    - inode number and a generation number, and it attempts to get the
    - inode using "iget" and check it's validity by matching the
    - generation number. A filesystem should only depend on the default
    - if iget can safely be used this way.

    If decode_fh and/or encode_fh are left as NULL, then default
    implementations are used. These defaults are suitable for ext2 and
    diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
    index f0f8258..d155893 100644
    --- a/Documentation/filesystems/Locking
    +++ b/Documentation/filesystems/Locking
    @@ -90,7 +90,6 @@ of the locking scheme for directory operations.
    prototypes:
    struct inode *(*alloc_inode)(struct super_block *sb);
    void (*destroy_inode)(struct inode *);
    - void (*read_inode) (struct inode *);
    void (*dirty_inode) (struct inode *);
    int (*write_inode) (struct inode *, int);
    void (*put_inode) (struct inode *);
    @@ -114,7 +113,6 @@ locking rules:
    BKL s_lock s_umount
    alloc_inode: no no no
    destroy_inode: no
    -read_inode: no (see below)
    dirty_inode: no (must not sleep)
    write_inode: no
    put_inode: no
    @@ -133,7 +131,6 @@ show_options: no (vfsmount->sem)
    quota_read: no no no (see below)
    quota_write: no no no (see below)

    -->read_inode() is not a method - it's a callback used in iget().
    ->remount_fs() will have the s_umount lock if it's already mounted.
    When called from get_sb_single, it does NOT have the s_umount lock.
    ->quota_read() and ->quota_write() functions are both guaranteed to
    diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
    index 045f3e0..63c7e91 100644
    --- a/Documentation/filesystems/vfs.txt
    +++ b/Documentation/filesystems/vfs.txt
    @@ -242,14 +242,8 @@ or bottom half).
    ->alloc_inode was defined and simply undoes anything done by
    ->alloc_inode.

    - read_inode: this method is called to read a specific inode from the
    - mounted filesystem. The i_ino member in the struct inode is
    - initialized by the VFS to indicate which inode to read. Other
    - members are filled in by this method.
    -
    - You can set this to NULL and use iget5_locked() instead of iget()
    - to read inodes. This is necessary for filesystems for which the
    - inode number is not sufficient to identify an inode.
    + read_inode: deprecated, do not use. Use iget_locked() instead of iget() and
    + return a proper error value.

    dirty_inode: this method is called by the VFS to mark an inode dirty.

    @@ -308,9 +302,9 @@ or bottom half).

    quota_write: called by the VFS to write to filesystem quota file.

    -The read_inode() method is responsible for filling in the "i_op"
    -field. This is a pointer to a "struct inode_operations" which
    -describes the methods that can be performed on individual inodes.
    +Whoever sets up the inode is responsible for filling in the "i_op" field. This
    +is a pointer to a "struct inode_operations" which describes the methods that
    +can be performed on individual inodes.


    The Inode Object
    diff --git a/fs/inode.c b/fs/inode.c
    index 29f5068..f78db20 100644
    --- a/fs/inode.c
    +++ b/fs/inode.c
    @@ -1427,3 +1427,19 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
    mode);
    }
    EXPORT_SYMBOL(init_special_inode);
    +
    +/*
    + * old deprecated inode creator
    + */
    +struct inode *iget(struct super_block *sb, unsigned long ino)
    +{
    + struct inode *inode = iget_locked(sb, ino);
    +
    + if (inode && (inode->i_state & I_NEW)) {
    + sb->s_op->read_inode(inode);
    + unlock_new_inode(inode);
    + }
    +
    + return inode;
    +}
    +EXPORT_SYMBOL(iget);
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index c24d433..dfa07d2 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -1181,7 +1181,7 @@ struct super_operations {
    struct inode *(*alloc_inode)(struct super_block *sb);
    void (*destroy_inode)(struct inode *);

    - void (*read_inode) (struct inode *);
    + void (*read_inode) (struct inode *) __deprecated;

    void (*dirty_inode) (struct inode *);
    int (*write_inode) (struct inode *, int);
    @@ -1618,18 +1618,8 @@ extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*te
    extern struct inode * iget_locked(struct super_block *, unsigned long);
    extern void unlock_new_inode(struct inode *);

    -static inline struct inode *iget(struct super_block *sb, unsigned long ino)
    -{
    - struct inode *inode = iget_locked(sb, ino);
    -
    - if (inode && (inode->i_state & I_NEW)) {
    - sb->s_op->read_inode(inode);
    - unlock_new_inode(inode);
    - }
    -
    - return inode;
    -}
    -
    +extern struct inode *iget(struct super_block *sb, unsigned long ino)
    + __deprecated;
    extern void __iget(struct inode * inode);
    extern void iget_failed(struct inode *);
    extern void clear_inode(struct inode *);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. [PATCH 32/32] IGET: Remove iget() and the read_inode() super op as being obsolete [try #2]

    Remove the old iget() call and the read_inode() superblock operation it uses
    as these are really obsolete, and the use of read_inode() does not produce
    proper error handling (no distinction between ENOMEM and EIO when marking
    an inode bad).

    Furthermore, this removes the temptation to use iget() to find an inode by
    number in a filesystem from code outside that filesystem.

    iget_locked() should be used instead. A new function is added (iget_failed)
    that is to be called to mark an inode as bad, unlock it and release it should
    the get routine fail.

    Signed-off-by: David Howells
    ---

    Documentation/filesystems/porting | 4 ++--
    Documentation/filesystems/vfs.txt | 5 -----
    fs/inode.c | 16 ----------------
    include/linux/fs.h | 4 ----
    4 files changed, 2 insertions(+), 27 deletions(-)

    diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
    index 3b0fb22..c20eae9 100644
    --- a/Documentation/filesystems/porting
    +++ b/Documentation/filesystems/porting
    @@ -34,8 +34,8 @@ FOO_I(inode) (see in-tree filesystems for examples).

    Make them ->alloc_inode and ->destroy_inode in your super_operations.

    -Keep in mind that now you need explicit initialization of private data -
    -typically in ->read_inode() and after getting an inode from new_inode().
    +Keep in mind that now you need explicit initialization of private data
    +typically between calling iget_locked() and calling unlocking the inode.

    At some point that will become mandatory.

    diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
    index 63c7e91..133bc88 100644
    --- a/Documentation/filesystems/vfs.txt
    +++ b/Documentation/filesystems/vfs.txt
    @@ -203,8 +203,6 @@ struct super_operations {
    struct inode *(*alloc_inode)(struct super_block *sb);
    void (*destroy_inode)(struct inode *);

    - void (*read_inode) (struct inode *);
    -
    void (*dirty_inode) (struct inode *);
    int (*write_inode) (struct inode *, int);
    void (*put_inode) (struct inode *);
    @@ -242,9 +240,6 @@ or bottom half).
    ->alloc_inode was defined and simply undoes anything done by
    ->alloc_inode.

    - read_inode: deprecated, do not use. Use iget_locked() instead of iget() and
    - return a proper error value.
    -
    dirty_inode: this method is called by the VFS to mark an inode dirty.

    write_inode: this method is called when the VFS needs to write an
    diff --git a/fs/inode.c b/fs/inode.c
    index f78db20..29f5068 100644
    --- a/fs/inode.c
    +++ b/fs/inode.c
    @@ -1427,19 +1427,3 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
    mode);
    }
    EXPORT_SYMBOL(init_special_inode);
    -
    -/*
    - * old deprecated inode creator
    - */
    -struct inode *iget(struct super_block *sb, unsigned long ino)
    -{
    - struct inode *inode = iget_locked(sb, ino);
    -
    - if (inode && (inode->i_state & I_NEW)) {
    - sb->s_op->read_inode(inode);
    - unlock_new_inode(inode);
    - }
    -
    - return inode;
    -}
    -EXPORT_SYMBOL(iget);
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index dfa07d2..42aabc1 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -1181,8 +1181,6 @@ struct super_operations {
    struct inode *(*alloc_inode)(struct super_block *sb);
    void (*destroy_inode)(struct inode *);

    - void (*read_inode) (struct inode *) __deprecated;
    -
    void (*dirty_inode) (struct inode *);
    int (*write_inode) (struct inode *, int);
    void (*put_inode) (struct inode *);
    @@ -1618,8 +1616,6 @@ extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*te
    extern struct inode * iget_locked(struct super_block *, unsigned long);
    extern void unlock_new_inode(struct inode *);

    -extern struct inode *iget(struct super_block *sb, unsigned long ino)
    - __deprecated;
    extern void __iget(struct inode * inode);
    extern void iget_failed(struct inode *);
    extern void clear_inode(struct inode *);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. [PATCH 26/32] IGET: Stop ROMFS from using iget() and read_inode() [try #2]

    Stop the ROMFS filesystem from using iget() and read_inode(). Replace
    romfs_read_inode() with romfs_iget(), and call that instead of iget().
    romfs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    romfs_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/romfs/inode.c | 45 +++++++++++++++++++++++++++++++--------------
    1 files changed, 31 insertions(+), 14 deletions(-)

    diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
    index dae7945..5071c9a 100644
    --- a/fs/romfs/inode.c
    +++ b/fs/romfs/inode.c
    @@ -84,6 +84,8 @@ struct romfs_inode_info {
    struct inode vfs_inode;
    };

    +static struct inode *romfs_iget(struct super_block *, unsigned long);
    +
    /* instead of private superblock data */
    static inline unsigned long romfs_maxsize(struct super_block *sb)
    {
    @@ -117,7 +119,7 @@ static int romfs_fill_super(struct super_block *s, void *data, int silent)
    struct buffer_head *bh;
    struct romfs_super_block *rsb;
    struct inode *root;
    - int sz;
    + int sz, ret = -EINVAL;

    /* I would parse the options here, but there are none.. */

    @@ -157,10 +159,13 @@ static int romfs_fill_super(struct super_block *s, void *data, int silent)
    & ROMFH_MASK;

    s->s_op = &romfs_ops;
    - root = iget(s, sz);
    - if (!root)
    + root = romfs_iget(s, sz);
    + if (IS_ERR(root)) {
    + ret = PTR_ERR(root);
    goto out;
    + }

    + ret = -ENOMEM;
    s->s_root = d_alloc_root(root);
    if (!s->s_root)
    goto outiput;
    @@ -173,7 +178,7 @@ outiput:
    out:
    brelse(bh);
    outnobh:
    - return -EINVAL;
    + return ret;
    }

    /* That's simple too. */
    @@ -389,8 +394,11 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
    if ((be32_to_cpu(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
    offset = be32_to_cpu(ri.spec) & ROMFH_MASK;

    - if ((inode = iget(dir->i_sb, offset)))
    - goto outi;
    + inode = romfs_iget(dir->i_sb, offset);
    + if (IS_ERR(inode)) {
    + res = PTR_ERR(inode);
    + goto out;
    + }

    /*
    * it's a bit funky, _lookup needs to return an error code
    @@ -402,7 +410,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
    */

    out0: inode = NULL;
    -outi: res = 0;
    + res = 0;
    d_add (dentry, inode);

    out: unlock_kernel();
    @@ -478,20 +486,28 @@ static mode_t romfs_modemap[] =
    S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
    };

    -static void
    -romfs_read_inode(struct inode *i)
    +static struct inode *
    +romfs_iget(struct super_block *sb, unsigned long ino)
    {
    - int nextfh, ino;
    + int nextfh;
    struct romfs_inode ri;
    + struct inode *i;
    +
    + ino &= ROMFH_MASK;
    + i = iget_locked(sb, ino);
    + if (!i)
    + return ERR_PTR(-ENOMEM);
    + if (!(i->i_state & I_NEW))
    + return i;

    - ino = i->i_ino & ROMFH_MASK;
    i->i_mode = 0;

    /* Loop for finding the real hard link */
    for(; {
    if (romfs_copyfrom(i, &ri, ino, ROMFH_SIZE) <= 0) {
    - printk("romfs: read error for inode 0x%x\n", ino);
    - return;
    + printk("romfs: read error for inode 0x%lx\n", ino);
    + iget_failed(i);
    + return ERR_PTR(-EIO);
    }
    /* XXX: do romfs_checksum here too (with name) */

    @@ -548,6 +564,8 @@ romfs_read_inode(struct inode *i)
    init_special_inode(i, ino,
    MKDEV(nextfh>>16,nextfh&0xffff));
    }
    + unlock_new_inode(i);
    + return i;
    }

    static struct kmem_cache * romfs_inode_cachep;
    @@ -599,7 +617,6 @@ static int romfs_remount(struct super_block *sb, int *flags, char *data)
    static const struct super_operations romfs_ops = {
    .alloc_inode = romfs_alloc_inode,
    .destroy_inode = romfs_destroy_inode,
    - .read_inode = romfs_read_inode,
    .statfs = romfs_statfs,
    .remount_fs = romfs_remount,
    };

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  17. [PATCH 31/32] IGET: Stop HPPFS from using iget() and read_inode() [try #2]

    Stop the HPPFS filesystem from using iget() and read_inode(). Provide an
    hppfs_iget(), and call that instead of iget(). hppfs_iget() then uses
    iget_locked() directly and returns a proper error code instead of an inode in
    the event of an error.

    hppfs_fill_sb_common() returns any error incurred when getting the root inode
    instead of EINVAL.

    Note that the contents of hppfs_kern.c need to be examined:

    (*) The HPPFS inode retains a pointer to the proc dentry it is shadowing, but
    whilst it does appear to retain a reference to it, it doesn't appear to
    destroy the reference if the inode goes away.

    (*) hppfs_iget() should perhaps subsume init_inode() and hppfs_read_inode().

    (*) It would appear that all hppfs inodes are the same inode because iget()
    was being called with inode number 0, which forms the lookup key.

    Signed-off-by: David Howells
    ---

    fs/hppfs/hppfs_kern.c | 27 ++++++++++++++++++++++-----
    1 files changed, 22 insertions(+), 5 deletions(-)

    diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
    index affb741..a1e1f0f 100644
    --- a/fs/hppfs/hppfs_kern.c
    +++ b/fs/hppfs/hppfs_kern.c
    @@ -155,6 +155,20 @@ static void hppfs_read_inode(struct inode *ino)
    ino->i_blocks = proc_ino->i_blocks;
    }

    +static struct inode *hppfs_iget(struct super_block *sb)
    +{
    + struct inode *inode;
    +
    + inode = iget_locked(sb, 0);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (inode->i_state & I_NEW) {
    + hppfs_read_inode(inode);
    + unlock_new_inode(inode);
    + }
    + return inode;
    +}
    +
    static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
    struct nameidata *nd)
    {
    @@ -190,9 +204,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
    if(IS_ERR(proc_dentry))
    return(proc_dentry);

    - inode = iget(ino->i_sb, 0);
    - if(inode == NULL)
    + inode = hppfs_iget(ino->i_sb);
    + if (IS_ERR(inode)) {
    + err = PTR_ERR(inode);
    goto out_dput;
    + }

    err = init_inode(inode, proc_dentry);
    if(err)
    @@ -652,7 +668,6 @@ static void hppfs_destroy_inode(struct inode *inode)
    static const struct super_operations hppfs_sbops = {
    .alloc_inode = hppfs_alloc_inode,
    .destroy_inode = hppfs_destroy_inode,
    - .read_inode = hppfs_read_inode,
    .delete_inode = hppfs_delete_inode,
    .statfs = hppfs_statfs,
    };
    @@ -745,9 +760,11 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
    sb->s_magic = HPPFS_SUPER_MAGIC;
    sb->s_op = &hppfs_sbops;

    - root_inode = iget(sb, 0);
    - if(root_inode == NULL)
    + root_inode = hppfs_iget(sb);
    + if (IS_ERR(root_inode)) {
    + err = PTR_ERR(root_inode);
    goto out;
    + }

    err = init_inode(root_inode, proc_sb->s_root);
    if(err)

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  18. [PATCH 19/32] IGET: Stop HFSPLUS from using iget() and read_inode() [try #2]

    Stop the HFSPLUS filesystem from using iget() and read_inode(). Replace
    hfsplus_read_inode() with hfsplus_iget(), and call that instead of iget().
    hfsplus_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    hfsplus_fill_super() returns any error incurred when getting the root inode.

    Signed-off-by: David Howells
    ---

    fs/hfsplus/btree.c | 6 ++++--
    fs/hfsplus/dir.c | 6 +++---
    fs/hfsplus/hfsplus_fs.h | 3 +++
    fs/hfsplus/super.c | 44 ++++++++++++++++++++++++++++++++------------
    4 files changed, 42 insertions(+), 17 deletions(-)

    diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
    index 050d29c..bb54336 100644
    --- a/fs/hfsplus/btree.c
    +++ b/fs/hfsplus/btree.c
    @@ -22,6 +22,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
    struct hfs_btree *tree;
    struct hfs_btree_header_rec *head;
    struct address_space *mapping;
    + struct inode *inode;
    struct page *page;
    unsigned int size;

    @@ -33,9 +34,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
    spin_lock_init(&tree->hash_lock);
    tree->sb = sb;
    tree->cnid = id;
    - tree->inode = iget(sb, id);
    - if (!tree->inode)
    + inode = hfsplus_iget(sb, id);
    + if (IS_ERR(inode))
    goto free_tree;
    + tree->inode = inode;

    mapping = tree->inode->i_mapping;
    page = read_mapping_page(mapping, 0, NULL);
    diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
    index 1955ee6..2968364 100644
    --- a/fs/hfsplus/dir.c
    +++ b/fs/hfsplus/dir.c
    @@ -97,9 +97,9 @@ again:
    goto fail;
    }
    hfs_find_exit(&fd);
    - inode = iget(dir->i_sb, cnid);
    - if (!inode)
    - return ERR_PTR(-EACCES);
    + inode = hfsplus_iget(dir->i_sb, cnid);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    if (S_ISREG(inode->i_mode))
    HFSPLUS_I(inode).dev = linkid;
    out:
    diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
    index d9f5eda..d72d0a8 100644
    --- a/fs/hfsplus/hfsplus_fs.h
    +++ b/fs/hfsplus/hfsplus_fs.h
    @@ -345,6 +345,9 @@ int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
    void hfsplus_fill_defaults(struct hfsplus_sb_info *);
    int hfsplus_show_options(struct seq_file *, struct vfsmount *);

    +/* super.c */
    +struct inode *hfsplus_iget(struct super_block *, unsigned long);
    +
    /* tables.c */
    extern u16 hfsplus_case_fold_table[];
    extern u16 hfsplus_decompose_table[];
    diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
    index 7b0f2e5..0b45d97 100644
    --- a/fs/hfsplus/super.c
    +++ b/fs/hfsplus/super.c
    @@ -20,11 +20,18 @@ static void hfsplus_destroy_inode(struct inode *inode);

    #include "hfsplus_fs.h"

    -static void hfsplus_read_inode(struct inode *inode)
    +struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
    {
    struct hfs_find_data fd;
    struct hfsplus_vh *vhdr;
    - int err;
    + struct inode *inode;
    + long err = -EIO;
    +
    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;

    INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
    init_MUTEX(&HFSPLUS_I(inode).extents_lock);
    @@ -41,7 +48,7 @@ static void hfsplus_read_inode(struct inode *inode)
    hfs_find_exit(&fd);
    if (err)
    goto bad_inode;
    - return;
    + goto done;
    }
    vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
    switch(inode->i_ino) {
    @@ -70,10 +77,14 @@ static void hfsplus_read_inode(struct inode *inode)
    goto bad_inode;
    }

    - return;
    +done:
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    make_bad_inode(inode);
    + iput(inode);
    + return ERR_PTR(err);
    }

    static int hfsplus_write_inode(struct inode *inode, int unused)
    @@ -262,7 +273,6 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
    static const struct super_operations hfsplus_sops = {
    .alloc_inode = hfsplus_alloc_inode,
    .destroy_inode = hfsplus_destroy_inode,
    - .read_inode = hfsplus_read_inode,
    .write_inode = hfsplus_write_inode,
    .clear_inode = hfsplus_clear_inode,
    .put_super = hfsplus_put_super,
    @@ -278,7 +288,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
    struct hfsplus_sb_info *sbi;
    hfsplus_cat_entry entry;
    struct hfs_find_data fd;
    - struct inode *root;
    + struct inode *root, *inode;
    struct qstr str;
    struct nls_table *nls = NULL;
    int err = -EINVAL;
    @@ -366,18 +376,25 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
    goto cleanup;
    }

    - HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID);
    - if (!HFSPLUS_SB(sb).alloc_file) {
    + inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
    + if (IS_ERR(inode)) {
    printk(KERN_ERR "hfs: failed to load allocation file\n");
    + err = PTR_ERR(inode);
    goto cleanup;
    }
    + HFSPLUS_SB(sb).alloc_file = inode;

    /* Load the root directory */
    - root = iget(sb, HFSPLUS_ROOT_CNID);
    + root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
    + if (IS_ERR(root)) {
    + printk(KERN_ERR "hfs: failed to load root directory\n");
    + err = PTR_ERR(root);
    + goto cleanup;
    + }
    sb->s_root = d_alloc_root(root);
    if (!sb->s_root) {
    - printk(KERN_ERR "hfs: failed to load root directory\n");
    iput(root);
    + err = -ENOMEM;
    goto cleanup;
    }
    sb->s_root->d_op = &hfsplus_dentry_operations;
    @@ -390,9 +407,12 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
    hfs_find_exit(&fd);
    if (entry.type != cpu_to_be16(HFSPLUS_FOLDER))
    goto cleanup;
    - HFSPLUS_SB(sb).hidden_dir = iget(sb, be32_to_cpu(entry.folder.id));
    - if (!HFSPLUS_SB(sb).hidden_dir)
    + inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
    + if (IS_ERR(inode)) {
    + err = PTR_ERR(inode);
    goto cleanup;
    + }
    + HFSPLUS_SB(sb).hidden_dir = inode;
    } else
    hfs_find_exit(&fd);


    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  19. [PATCH 27/32] IGET: Stop the SYSV filesystem from using iget() and read_inode() [try #2]

    Stop the SYSV filesystem from using iget() and read_inode(). Replace
    sysv_read_inode() with sysv_iget(), and call that instead of iget().
    sysv_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    Signed-off-by: David Howells
    ---

    fs/sysv/inode.c | 25 ++++++++++++++++---------
    fs/sysv/namei.c | 6 +++---
    fs/sysv/super.c | 4 ++--
    fs/sysv/sysv.h | 1 +
    4 files changed, 22 insertions(+), 14 deletions(-)

    diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
    index 7c4e5d3..9d512a8 100644
    --- a/fs/sysv/inode.c
    +++ b/fs/sysv/inode.c
    @@ -169,20 +169,27 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
    init_special_inode(inode, inode->i_mode, rdev);
    }

    -static void sysv_read_inode(struct inode *inode)
    +struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
    {
    - struct super_block * sb = inode->i_sb;
    struct sysv_sb_info * sbi = SYSV_SB(sb);
    struct buffer_head * bh;
    struct sysv_inode * raw_inode;
    struct sysv_inode_info * si;
    - unsigned int block, ino = inode->i_ino;
    + struct inode *inode;
    + unsigned int block;

    if (!ino || ino > sbi->s_ninodes) {
    printk("Bad inode number on dev %s: %d is out of range\n",
    - inode->i_sb->s_id, ino);
    - goto bad_inode;
    + sb->s_id, ino);
    + return ERR_PTR(-EIO);
    }
    +
    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    raw_inode = sysv_raw_inode(sb, ino, &bh);
    if (!raw_inode) {
    printk("Major problem: unable to read inode from dev %s\n",
    @@ -214,11 +221,12 @@ static void sysv_read_inode(struct inode *inode)
    old_decode_dev(fs32_to_cpu(sbi, si->i_data[0])));
    else
    sysv_set_inode(inode, 0);
    - return;
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    - make_bad_inode(inode);
    - return;
    + iget_failed(inode);
    + return ERR_PTR(-EIO);
    }

    static struct buffer_head * sysv_update_inode(struct inode * inode)
    @@ -328,7 +336,6 @@ static void init_once(void *p, struct kmem_cache *cachep, unsigned long flags)
    const struct super_operations sysv_sops = {
    .alloc_inode = sysv_alloc_inode,
    .destroy_inode = sysv_destroy_inode,
    - .read_inode = sysv_read_inode,
    .write_inode = sysv_write_inode,
    .delete_inode = sysv_delete_inode,
    .put_super = sysv_put_super,
    diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
    index 6bd850b..a1f1ef3 100644
    --- a/fs/sysv/namei.c
    +++ b/fs/sysv/namei.c
    @@ -53,9 +53,9 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, st
    ino = sysv_inode_by_name(dentry);

    if (ino) {
    - inode = iget(dir->i_sb, ino);
    - if (!inode)
    - return ERR_PTR(-EACCES);
    + inode = sysv_iget(dir->i_sb, ino);
    + if (IS_ERR(inode))
    + return ERR_CAST(inode);
    }
    d_add(dentry, inode);
    return NULL;
    diff --git a/fs/sysv/super.c b/fs/sysv/super.c
    index 6f9707a..a92d104 100644
    --- a/fs/sysv/super.c
    +++ b/fs/sysv/super.c
    @@ -332,8 +332,8 @@ static int complete_read_super(struct super_block *sb, int silent, int size)
    sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type;
    /* set up enough so that it can read an inode */
    sb->s_op = &sysv_sops;
    - root_inode = iget(sb,SYSV_ROOT_INO);
    - if (!root_inode || is_bad_inode(root_inode)) {
    + root_inode = sysv_iget(sb,SYSV_ROOT_INO);
    + if (IS_ERR(root_inode)) {
    printk("SysV FS: get root inode failed\n");
    return 0;
    }
    diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
    index 5b4fedf..71ebdbc 100644
    --- a/fs/sysv/sysv.h
    +++ b/fs/sysv/sysv.h
    @@ -138,6 +138,7 @@ extern unsigned long sysv_count_free_blocks(struct super_block *);
    extern void sysv_truncate(struct inode *);

    /* inode.c */
    +extern struct inode *sysv_iget(struct super_block *, unsigned int);
    extern int sysv_write_inode(struct inode *, int);
    extern int sysv_sync_inode(struct inode *);
    extern int sysv_sync_file(struct file *, struct dentry *, int);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  20. [PATCH 28/32] IGET: Stop UFS from using iget() and read_inode() [try #2]

    Stop the UFS filesystem from using iget() and read_inode(). Replace
    ufs_read_inode() with ufs_iget(), and call that instead of iget().
    ufs_iget() then uses iget_locked() directly and returns a proper error code
    instead of an inode in the event of an error.

    ufs_fill_super() returns any error incurred when getting the root inode
    instead of EINVAL.

    Signed-off-by: David Howells
    ---

    fs/ufs/inode.c | 34 ++++++++++++++++++++--------------
    fs/ufs/namei.c | 6 +++---
    fs/ufs/super.c | 14 +++++++++-----
    include/linux/ufs_fs.h | 2 +-
    4 files changed, 33 insertions(+), 23 deletions(-)

    diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
    index f18b791..d7c2d3c 100644
    --- a/fs/ufs/inode.c
    +++ b/fs/ufs/inode.c
    @@ -698,26 +698,30 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
    return 0;
    }

    -void ufs_read_inode(struct inode * inode)
    +struct inode *ufs_iget (struct super_block *sb, unsigned long ino)
    {
    - struct ufs_inode_info *ufsi = UFS_I(inode);
    - struct super_block * sb;
    - struct ufs_sb_private_info * uspi;
    + struct ufs_inode_info *ufsi;
    + struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
    struct buffer_head * bh;
    + struct inode *inode;
    int err;

    - UFSD("ENTER, ino %lu\n", inode->i_ino);
    -
    - sb = inode->i_sb;
    - uspi = UFS_SB(sb)->s_uspi;
    + UFSD("ENTER, ino %lu\n", ino);

    - if (inode->i_ino < UFS_ROOTINO ||
    - inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
    + if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) {
    ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
    - inode->i_ino);
    - goto bad_inode;
    + ino);
    + return ERR_PTR(-EIO);
    }

    + inode = iget_locked(sb, ino);
    + if (!inode)
    + return ERR_PTR(-ENOMEM);
    + if (!(inode->i_state & I_NEW))
    + return inode;
    +
    + ufsi = UFS_I(inode);
    +
    bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
    if (!bh) {
    ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n",
    @@ -749,10 +753,12 @@ void ufs_read_inode(struct inode * inode)
    brelse(bh);

    UFSD("EXIT\n");
    - return;
    + unlock_new_inode(inode);
    + return inode;

    bad_inode:
    - make_bad_inode(inode);
    + iget_failed(inode);
    + return ERR_PTR(-EIO);
    }

    static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode)
    diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
    index a059ccd..a00cec1 100644
    --- a/fs/ufs/namei.c
    +++ b/fs/ufs/namei.c
    @@ -57,10 +57,10 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
    lock_kernel();
    ino = ufs_inode_by_name(dir, dentry);
    if (ino) {
    - inode = iget(dir->i_sb, ino);
    - if (!inode) {
    + inode = ufs_iget(dir->i_sb, ino);
    + if (IS_ERR(inode)) {
    unlock_kernel();
    - return ERR_PTR(-EACCES);
    + return ERR_CAST(inode);
    }
    }
    unlock_kernel();
    diff --git a/fs/ufs/super.c b/fs/ufs/super.c
    index 38eb0b7..8e157ab 100644
    --- a/fs/ufs/super.c
    +++ b/fs/ufs/super.c
    @@ -613,6 +613,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
    unsigned block_size, super_block_size;
    unsigned flags;
    unsigned super_block_offset;
    + int ret = -EINVAL;

    uspi = NULL;
    ubh = NULL;
    @@ -1026,12 +1027,16 @@ magic_found:
    uspi->s_maxsymlinklen =
    fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_maxsymlinklen);

    - inode = iget(sb, UFS_ROOTINO);
    - if (!inode || is_bad_inode(inode))
    + inode = ufs_iget(sb, UFS_ROOTINO);
    + if (IS_ERR(inode)) {
    + ret = PTR_ERR(inode);
    goto failed;
    + }
    sb->s_root = d_alloc_root(inode);
    - if (!sb->s_root)
    + if (!sb->s_root) {
    + ret = -ENOMEM;
    goto dalloc_failed;
    + }

    ufs_setup_cstotal(sb);
    /*
    @@ -1053,7 +1058,7 @@ failed:
    kfree(sbi);
    sb->s_fs_info = NULL;
    UFSD("EXIT (FAILED)\n");
    - return -EINVAL;
    + return ret;

    failed_nomem:
    UFSD("EXIT (NOMEM)\n");
    @@ -1264,7 +1269,6 @@ static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t,
    static const struct super_operations ufs_super_ops = {
    .alloc_inode = ufs_alloc_inode,
    .destroy_inode = ufs_destroy_inode,
    - .read_inode = ufs_read_inode,
    .write_inode = ufs_write_inode,
    .delete_inode = ufs_delete_inode,
    .put_super = ufs_put_super,
    diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
    index daeba22..2a61fa3 100644
    --- a/include/linux/ufs_fs.h
    +++ b/include/linux/ufs_fs.h
    @@ -979,7 +979,7 @@ extern void ufs_free_inode (struct inode *inode);
    extern struct inode * ufs_new_inode (struct inode *, int);

    /* inode.c */
    -extern void ufs_read_inode (struct inode *);
    +extern struct inode *ufs_iget (struct super_block *, unsigned long);
    extern void ufs_put_inode (struct inode *);
    extern int ufs_write_inode (struct inode *, int);
    extern int ufs_sync_inode (struct inode *);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread
Page 1 of 3 1 2 3 LastLast