lkml.org 
[lkml]   [2015]   [Dec]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 07/11] replace ->follow_link() with new method that could stay in RCU mode
    Date
    From: Al Viro <viro@zeniv.linux.org.uk>

    new method: ->get_link(); replacement of ->follow_link(). The differences
    are:
    * inode and dentry are passed separately
    * might be called both in RCU and non-RCU mode;
    the former is indicated by passing it a NULL dentry.
    * when called that way it isn't allowed to block
    and should return ERR_PTR(-ECHILD) if it needs to be called
    in non-RCU mode.

    It's a flagday change - the old method is gone, all in-tree instances
    converted. Conversion isn't hard; said that, so far very few instances
    do not immediately bail out when called in RCU mode. That'll change
    in the next commits.

    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
    ---
    Documentation/filesystems/Locking | 4 +--
    Documentation/filesystems/porting | 6 ++++
    drivers/staging/lustre/lustre/llite/symlink.c | 8 +++--
    fs/9p/vfs_inode.c | 17 +++++++---
    fs/9p/vfs_inode_dotl.c | 14 ++++++---
    fs/affs/symlink.c | 4 +--
    fs/autofs4/symlink.c | 13 +++++---
    fs/btrfs/inode.c | 2 +-
    fs/ceph/inode.c | 2 +-
    fs/cifs/cifsfs.c | 2 +-
    fs/cifs/cifsfs.h | 4 +--
    fs/cifs/link.c | 6 ++--
    fs/coda/cnode.c | 2 +-
    fs/configfs/symlink.c | 11 +++++--
    fs/dcache.c | 2 +-
    fs/ecryptfs/inode.c | 12 +++++--
    fs/ext2/symlink.c | 4 +--
    fs/ext4/symlink.c | 13 +++++---
    fs/f2fs/namei.c | 16 ++++++----
    fs/fuse/dir.c | 9 ++++--
    fs/gfs2/inode.c | 15 ++++++---
    fs/hostfs/hostfs_kern.c | 10 ++++--
    fs/jffs2/symlink.c | 2 +-
    fs/jfs/symlink.c | 4 +--
    fs/kernfs/symlink.c | 11 +++++--
    fs/libfs.c | 9 +++---
    fs/minix/inode.c | 2 +-
    fs/namei.c | 45 +++++++++++++++++----------
    fs/ncpfs/inode.c | 2 +-
    fs/nfs/symlink.c | 9 ++++--
    fs/nilfs2/namei.c | 2 +-
    fs/ocfs2/symlink.c | 2 +-
    fs/overlayfs/inode.c | 12 ++++---
    fs/proc/base.c | 22 +++++++------
    fs/proc/inode.c | 7 +++--
    fs/proc/namespaces.c | 9 ++++--
    fs/proc/self.c | 9 ++++--
    fs/proc/thread_self.c | 9 ++++--
    fs/reiserfs/namei.c | 2 +-
    fs/squashfs/symlink.c | 2 +-
    fs/sysv/inode.c | 2 +-
    fs/ubifs/file.c | 2 +-
    fs/xfs/xfs_iops.c | 8 +++--
    include/linux/fs.h | 6 ++--
    mm/shmem.c | 12 ++++---
    45 files changed, 234 insertions(+), 132 deletions(-)

    diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
    index 06d4434..4fba54b 100644
    --- a/Documentation/filesystems/Locking
    +++ b/Documentation/filesystems/Locking
    @@ -50,7 +50,7 @@ prototypes:
    int (*rename2) (struct inode *, struct dentry *,
    struct inode *, struct dentry *, unsigned int);
    int (*readlink) (struct dentry *, char __user *,int);
    - const char *(*follow_link) (struct dentry *, void **);
    + const char *(*get_link) (struct dentry *, struct inode *, void **);
    void (*put_link) (struct inode *, void *);
    void (*truncate) (struct inode *);
    int (*permission) (struct inode *, int, unsigned int);
    @@ -83,7 +83,7 @@ rmdir: yes (both) (see below)
    rename: yes (all) (see below)
    rename2: yes (all) (see below)
    readlink: no
    -follow_link: no
    +get_link: no
    put_link: no
    setattr: yes
    permission: no (may not block if called in rcu-walk mode)
    diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
    index 3eb7c35..cf92a8c 100644
    --- a/Documentation/filesystems/porting
    +++ b/Documentation/filesystems/porting
    @@ -509,3 +509,9 @@ in your dentry operations instead.
    any symlink that might use page_follow_link_light/page_put_link() must
    have inode_nohighmem(inode) called before anything might start playing with
    its pagecache.
    +--
    +[mandatory]
    + ->follow_link() is replaced with ->get_link(); same API, except that
    + * ->get_link() gets inode as a separate argument
    + * ->get_link() may be called in RCU mode - in that case NULL
    + dentry is passed
    diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
    index 69b2036..153fdf9 100644
    --- a/drivers/staging/lustre/lustre/llite/symlink.c
    +++ b/drivers/staging/lustre/lustre/llite/symlink.c
    @@ -118,12 +118,14 @@ failed:
    return rc;
    }

    -static const char *ll_follow_link(struct dentry *dentry, void **cookie)
    +static const char *ll_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct inode *inode = d_inode(dentry);
    struct ptlrpc_request *request = NULL;
    int rc;
    char *symname = NULL;
    + if (!dentry)
    + return ERR_PTR(-ECHILD);

    CDEBUG(D_VFSTRACE, "VFS Op\n");
    ll_inode_size_lock(inode);
    @@ -149,7 +151,7 @@ static void ll_put_link(struct inode *unused, void *cookie)
    struct inode_operations ll_fast_symlink_inode_operations = {
    .readlink = generic_readlink,
    .setattr = ll_setattr,
    - .follow_link = ll_follow_link,
    + .get_link = ll_get_link,
    .put_link = ll_put_link,
    .getattr = ll_getattr,
    .permission = ll_inode_permission,
    diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
    index 699941e..8ba5a89 100644
    --- a/fs/9p/vfs_inode.c
    +++ b/fs/9p/vfs_inode.c
    @@ -1223,18 +1223,25 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
    }

    /**
    - * v9fs_vfs_follow_link - follow a symlink path
    + * v9fs_vfs_get_link - follow a symlink path
    * @dentry: dentry for symlink
    + * @inode: inode for symlink
    * @cookie: place to pass the data to put_link()
    */

    -static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
    +static const char *v9fs_vfs_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
    - struct p9_fid *fid = v9fs_fid_lookup(dentry);
    + struct v9fs_session_info *v9ses;
    + struct p9_fid *fid;
    struct p9_wstat *st;
    char *res;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    + v9ses = v9fs_dentry2v9ses(dentry);
    + fid = v9fs_fid_lookup(dentry);
    p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);

    if (IS_ERR(fid))
    @@ -1452,7 +1459,7 @@ static const struct inode_operations v9fs_file_inode_operations = {

    static const struct inode_operations v9fs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = v9fs_vfs_follow_link,
    + .get_link = v9fs_vfs_get_link,
    .put_link = kfree_put_link,
    .getattr = v9fs_vfs_getattr,
    .setattr = v9fs_vfs_setattr,
    diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
    index cb899af..0cc105d 100644
    --- a/fs/9p/vfs_inode_dotl.c
    +++ b/fs/9p/vfs_inode_dotl.c
    @@ -899,20 +899,26 @@ error:
    }

    /**
    - * v9fs_vfs_follow_link_dotl - follow a symlink path
    + * v9fs_vfs_get_link_dotl - follow a symlink path
    * @dentry: dentry for symlink
    + * @inode: inode for symlink
    * @cookie: place to pass the data to put_link()
    */

    static const char *
    -v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie)
    +v9fs_vfs_get_link_dotl(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct p9_fid *fid = v9fs_fid_lookup(dentry);
    + struct p9_fid *fid;
    char *target;
    int retval;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);

    + fid = v9fs_fid_lookup(dentry);
    if (IS_ERR(fid))
    return ERR_CAST(fid);
    retval = p9_client_readlink(fid, &target);
    @@ -984,7 +990,7 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {

    const struct inode_operations v9fs_symlink_inode_operations_dotl = {
    .readlink = generic_readlink,
    - .follow_link = v9fs_vfs_follow_link_dotl,
    + .get_link = v9fs_vfs_get_link_dotl,
    .put_link = kfree_put_link,
    .getattr = v9fs_vfs_getattr_dotl,
    .setattr = v9fs_vfs_setattr_dotl,
    diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
    index e3f9dc3..39d1194 100644
    --- a/fs/affs/symlink.c
    +++ b/fs/affs/symlink.c
    @@ -20,7 +20,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
    char c;
    char lc;

    - pr_debug("follow_link(ino=%lu)\n", inode->i_ino);
    + pr_debug("get_link(ino=%lu)\n", inode->i_ino);

    bh = affs_bread(inode->i_sb, inode->i_ino);
    if (!bh)
    @@ -71,7 +71,7 @@ const struct address_space_operations affs_symlink_aops = {

    const struct inode_operations affs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = affs_notify_change,
    };
    diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
    index da0c334..39e6f0b 100644
    --- a/fs/autofs4/symlink.c
    +++ b/fs/autofs4/symlink.c
    @@ -12,10 +12,15 @@

    #include "autofs_i.h"

    -static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
    +static const char *autofs4_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
    - struct autofs_info *ino = autofs4_dentry_ino(dentry);
    + struct autofs_sb_info *sbi;
    + struct autofs_info *ino;
    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    + sbi = autofs4_sbi(dentry->d_sb);
    + ino = autofs4_dentry_ino(dentry);
    if (ino && !autofs4_oz_mode(sbi))
    ino->last_used = jiffies;
    return d_inode(dentry)->i_private;
    @@ -23,5 +28,5 @@ static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)

    const struct inode_operations autofs4_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = autofs4_follow_link
    + .get_link = autofs4_get_link
    };
    diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
    index 70f98bf..3d4aa69 100644
    --- a/fs/btrfs/inode.c
    +++ b/fs/btrfs/inode.c
    @@ -10096,7 +10096,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
    };
    static const struct inode_operations btrfs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .getattr = btrfs_getattr,
    .setattr = btrfs_setattr,
    diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
    index 498dcfa..da55eb8 100644
    --- a/fs/ceph/inode.c
    +++ b/fs/ceph/inode.c
    @@ -1756,7 +1756,7 @@ retry:
    */
    static const struct inode_operations ceph_symlink_iops = {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .setattr = ceph_setattr,
    .getattr = ceph_getattr,
    .setxattr = ceph_setxattr,
    diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
    index cbc0f4b..4593f416 100644
    --- a/fs/cifs/cifsfs.c
    +++ b/fs/cifs/cifsfs.c
    @@ -900,7 +900,7 @@ const struct inode_operations cifs_file_inode_ops = {

    const struct inode_operations cifs_symlink_inode_ops = {
    .readlink = generic_readlink,
    - .follow_link = cifs_follow_link,
    + .get_link = cifs_get_link,
    .put_link = kfree_put_link,
    .permission = cifs_permission,
    /* BB add the following two eventually */
    diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
    index c3cc160..6886328 100644
    --- a/fs/cifs/cifsfs.h
    +++ b/fs/cifs/cifsfs.h
    @@ -120,9 +120,7 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
    #endif

    /* Functions related to symlinks */
    -extern const char *cifs_follow_link(struct dentry *direntry, void **cookie);
    -extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
    - int buflen);
    +extern const char *cifs_get_link(struct dentry *, struct inode *, void **);
    extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
    const char *symname);
    extern int cifs_removexattr(struct dentry *, const char *);
    diff --git a/fs/cifs/link.c b/fs/cifs/link.c
    index e3548f7..6f2439b5 100644
    --- a/fs/cifs/link.c
    +++ b/fs/cifs/link.c
    @@ -627,9 +627,8 @@ cifs_hl_exit:
    }

    const char *
    -cifs_follow_link(struct dentry *direntry, void **cookie)
    +cifs_get_link(struct dentry *direntry, struct inode *inode, void **cookie)
    {
    - struct inode *inode = d_inode(direntry);
    int rc = -ENOMEM;
    unsigned int xid;
    char *full_path = NULL;
    @@ -639,6 +638,9 @@ cifs_follow_link(struct dentry *direntry, void **cookie)
    struct cifs_tcon *tcon;
    struct TCP_Server_Info *server;

    + if (!direntry)
    + return ERR_PTR(-ECHILD);
    +
    xid = get_xid();

    tlink = cifs_sb_tlink(cifs_sb);
    diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
    index dd6a79e..f18139c 100644
    --- a/fs/coda/cnode.c
    +++ b/fs/coda/cnode.c
    @@ -18,7 +18,7 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)

    static const struct inode_operations coda_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = coda_setattr,
    };
    diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
    index ec5c832..b91c01e 100644
    --- a/fs/configfs/symlink.c
    +++ b/fs/configfs/symlink.c
    @@ -279,11 +279,16 @@ static int configfs_getlink(struct dentry *dentry, char * path)

    }

    -static const char *configfs_follow_link(struct dentry *dentry, void **cookie)
    +static const char *configfs_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - unsigned long page = get_zeroed_page(GFP_KERNEL);
    + unsigned long page;
    int error;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    + page = get_zeroed_page(GFP_KERNEL);
    if (!page)
    return ERR_PTR(-ENOMEM);

    @@ -297,7 +302,7 @@ static const char *configfs_follow_link(struct dentry *dentry, void **cookie)
    }

    const struct inode_operations configfs_symlink_inode_operations = {
    - .follow_link = configfs_follow_link,
    + .get_link = configfs_get_link,
    .readlink = generic_readlink,
    .put_link = free_page_put_link,
    .setattr = configfs_setattr,
    diff --git a/fs/dcache.c b/fs/dcache.c
    index 5c33aeb..d27f090 100644
    --- a/fs/dcache.c
    +++ b/fs/dcache.c
    @@ -1734,7 +1734,7 @@ static unsigned d_flags_for_inode(struct inode *inode)
    }

    if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
    - if (unlikely(inode->i_op->follow_link)) {
    + if (unlikely(inode->i_op->get_link)) {
    add_flags = DCACHE_SYMLINK_TYPE;
    goto type_determined;
    }
    diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
    index e2e47ba..5a05559 100644
    --- a/fs/ecryptfs/inode.c
    +++ b/fs/ecryptfs/inode.c
    @@ -674,10 +674,16 @@ out:
    return rc ? ERR_PTR(rc) : buf;
    }

    -static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie)
    +static const char *ecryptfs_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    size_t len;
    - char *buf = ecryptfs_readlink_lower(dentry, &len);
    + char *buf;
    +
    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    + buf = ecryptfs_readlink_lower(dentry, &len);
    if (IS_ERR(buf))
    return buf;
    fsstack_copy_attr_atime(d_inode(dentry),
    @@ -1095,7 +1101,7 @@ out:

    const struct inode_operations ecryptfs_symlink_iops = {
    .readlink = generic_readlink,
    - .follow_link = ecryptfs_follow_link,
    + .get_link = ecryptfs_get_link,
    .put_link = kfree_put_link,
    .permission = ecryptfs_permission,
    .setattr = ecryptfs_setattr,
    diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
    index ae17179..4690511 100644
    --- a/fs/ext2/symlink.c
    +++ b/fs/ext2/symlink.c
    @@ -22,7 +22,7 @@

    const struct inode_operations ext2_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = ext2_setattr,
    #ifdef CONFIG_EXT2_FS_XATTR
    @@ -35,7 +35,7 @@ const struct inode_operations ext2_symlink_inode_operations = {

    const struct inode_operations ext2_fast_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .setattr = ext2_setattr,
    #ifdef CONFIG_EXT2_FS_XATTR
    .setxattr = generic_setxattr,
    diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
    index 0e6dc44..3b4bfe2 100644
    --- a/fs/ext4/symlink.c
    +++ b/fs/ext4/symlink.c
    @@ -23,17 +23,20 @@
    #include "xattr.h"

    #ifdef CONFIG_EXT4_FS_ENCRYPTION
    -static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cookie)
    +static const char *ext4_encrypted_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    struct page *cpage = NULL;
    char *caddr, *paddr = NULL;
    struct ext4_str cstr, pstr;
    - struct inode *inode = d_inode(dentry);
    struct ext4_encrypted_symlink_data *sd;
    loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
    int res;
    u32 plen, max_size = inode->i_sb->s_blocksize;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    res = ext4_get_encryption_info(inode);
    if (res)
    return ERR_PTR(res);
    @@ -87,7 +90,7 @@ errout:

    const struct inode_operations ext4_encrypted_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = ext4_encrypted_follow_link,
    + .get_link = ext4_encrypted_get_link,
    .put_link = kfree_put_link,
    .setattr = ext4_setattr,
    .setxattr = generic_setxattr,
    @@ -99,7 +102,7 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {

    const struct inode_operations ext4_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = ext4_setattr,
    .setxattr = generic_setxattr,
    @@ -110,7 +113,7 @@ const struct inode_operations ext4_symlink_inode_operations = {

    const struct inode_operations ext4_fast_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .setattr = ext4_setattr,
    .setxattr = generic_setxattr,
    .getxattr = generic_getxattr,
    diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
    index 484df68..2a8d84b 100644
    --- a/fs/f2fs/namei.c
    +++ b/fs/f2fs/namei.c
    @@ -315,9 +315,10 @@ fail:
    return err;
    }

    -static const char *f2fs_follow_link(struct dentry *dentry, void **cookie)
    +static const char *f2fs_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - const char *link = page_follow_link_light(dentry, cookie);
    + const char *link = page_get_link(dentry, inode, cookie);
    if (!IS_ERR(link) && !*link) {
    /* this is broken symlink case */
    page_put_link(NULL, *cookie);
    @@ -924,18 +925,21 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
    }

    #ifdef CONFIG_F2FS_FS_ENCRYPTION
    -static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cookie)
    +static const char *f2fs_encrypted_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    struct page *cpage = NULL;
    char *caddr, *paddr = NULL;
    struct f2fs_str cstr;
    struct f2fs_str pstr = FSTR_INIT(NULL, 0);
    - struct inode *inode = d_inode(dentry);
    struct f2fs_encrypted_symlink_data *sd;
    loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
    u32 max_size = inode->i_sb->s_blocksize;
    int res;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    res = f2fs_get_encryption_info(inode);
    if (res)
    return ERR_PTR(res);
    @@ -994,7 +998,7 @@ errout:

    const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = f2fs_encrypted_follow_link,
    + .get_link = f2fs_encrypted_get_link,
    .put_link = kfree_put_link,
    .getattr = f2fs_getattr,
    .setattr = f2fs_setattr,
    @@ -1030,7 +1034,7 @@ const struct inode_operations f2fs_dir_inode_operations = {

    const struct inode_operations f2fs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = f2fs_follow_link,
    + .get_link = f2fs_get_link,
    .put_link = page_put_link,
    .getattr = f2fs_getattr,
    .setattr = f2fs_setattr,
    diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
    index 5e2e087..148e8ef 100644
    --- a/fs/fuse/dir.c
    +++ b/fs/fuse/dir.c
    @@ -1365,14 +1365,17 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
    return err;
    }

    -static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
    +static const char *fuse_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct inode *inode = d_inode(dentry);
    struct fuse_conn *fc = get_fuse_conn(inode);
    FUSE_ARGS(args);
    char *link;
    ssize_t ret;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    link = (char *) __get_free_page(GFP_KERNEL);
    if (!link)
    return ERR_PTR(-ENOMEM);
    @@ -1909,7 +1912,7 @@ static const struct inode_operations fuse_common_inode_operations = {

    static const struct inode_operations fuse_symlink_inode_operations = {
    .setattr = fuse_setattr,
    - .follow_link = fuse_follow_link,
    + .get_link = fuse_get_link,
    .put_link = free_page_put_link,
    .readlink = generic_readlink,
    .getattr = fuse_getattr,
    diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
    index 063fdfc..10950560 100644
    --- a/fs/gfs2/inode.c
    +++ b/fs/gfs2/inode.c
    @@ -1712,24 +1712,29 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry,
    }

    /**
    - * gfs2_follow_link - Follow a symbolic link
    + * gfs2_get_link - Follow a symbolic link
    * @dentry: The dentry of the link
    - * @nd: Data that we pass to vfs_follow_link()
    + * @inode: The inode of the link
    + * @cookie: place to store the information for ->put_link()
    *
    * This can handle symlinks of any size.
    *
    * Returns: 0 on success or error code
    */

    -static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
    +static const char *gfs2_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
    + struct gfs2_inode *ip = GFS2_I(inode);
    struct gfs2_holder i_gh;
    struct buffer_head *dibh;
    unsigned int size;
    char *buf;
    int error;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
    error = gfs2_glock_nq(&i_gh);
    if (error) {
    @@ -2132,7 +2137,7 @@ const struct inode_operations gfs2_dir_iops = {

    const struct inode_operations gfs2_symlink_iops = {
    .readlink = generic_readlink,
    - .follow_link = gfs2_follow_link,
    + .get_link = gfs2_get_link,
    .put_link = kfree_put_link,
    .permission = gfs2_permission,
    .setattr = gfs2_setattr,
    diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
    index 2ac99db..6ce5309 100644
    --- a/fs/hostfs/hostfs_kern.c
    +++ b/fs/hostfs/hostfs_kern.c
    @@ -892,9 +892,13 @@ static const struct inode_operations hostfs_dir_iops = {
    .setattr = hostfs_setattr,
    };

    -static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
    +static const char *hostfs_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - char *link = __getname();
    + char *link;
    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    + link = __getname();
    if (link) {
    char *path = dentry_name(dentry);
    int err = -ENOMEM;
    @@ -922,7 +926,7 @@ static void hostfs_put_link(struct inode *unused, void *cookie)

    static const struct inode_operations hostfs_link_iops = {
    .readlink = generic_readlink,
    - .follow_link = hostfs_follow_link,
    + .get_link = hostfs_get_link,
    .put_link = hostfs_put_link,
    };

    diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
    index 8ce2f24..2cabd64 100644
    --- a/fs/jffs2/symlink.c
    +++ b/fs/jffs2/symlink.c
    @@ -14,7 +14,7 @@
    const struct inode_operations jffs2_symlink_inode_operations =
    {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .setattr = jffs2_setattr,
    .setxattr = jffs2_setxattr,
    .getxattr = jffs2_getxattr,
    diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
    index 5929e23..0211328 100644
    --- a/fs/jfs/symlink.c
    +++ b/fs/jfs/symlink.c
    @@ -23,7 +23,7 @@

    const struct inode_operations jfs_fast_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .setattr = jfs_setattr,
    .setxattr = jfs_setxattr,
    .getxattr = jfs_getxattr,
    @@ -33,7 +33,7 @@ const struct inode_operations jfs_fast_symlink_inode_operations = {

    const struct inode_operations jfs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = jfs_setattr,
    .setxattr = jfs_setxattr,
    diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
    index db27252..ffae857 100644
    --- a/fs/kernfs/symlink.c
    +++ b/fs/kernfs/symlink.c
    @@ -112,10 +112,15 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
    return error;
    }

    -static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie)
    +static const char *kernfs_iop_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    int error = -ENOMEM;
    - unsigned long page = get_zeroed_page(GFP_KERNEL);
    + unsigned long page;
    +
    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    + page = get_zeroed_page(GFP_KERNEL);
    if (!page)
    return ERR_PTR(-ENOMEM);
    error = kernfs_getlink(dentry, (char *)page);
    @@ -132,7 +137,7 @@ const struct inode_operations kernfs_symlink_iops = {
    .getxattr = kernfs_iop_getxattr,
    .listxattr = kernfs_iop_listxattr,
    .readlink = generic_readlink,
    - .follow_link = kernfs_iop_follow_link,
    + .get_link = kernfs_iop_get_link,
    .put_link = free_page_put_link,
    .setattr = kernfs_iop_setattr,
    .getattr = kernfs_iop_getattr,
    diff --git a/fs/libfs.c b/fs/libfs.c
    index c7cbfb0..8dc37fc 100644
    --- a/fs/libfs.c
    +++ b/fs/libfs.c
    @@ -1092,14 +1092,15 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
    }
    EXPORT_SYMBOL(simple_nosetlease);

    -const char *simple_follow_link(struct dentry *dentry, void **cookie)
    +const char *simple_get_link(struct dentry *dentry, struct inode *inode,
    + void **cookie)
    {
    - return d_inode(dentry)->i_link;
    + return inode->i_link;
    }
    -EXPORT_SYMBOL(simple_follow_link);
    +EXPORT_SYMBOL(simple_get_link);

    const struct inode_operations simple_symlink_inode_operations = {
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .readlink = generic_readlink
    };
    EXPORT_SYMBOL(simple_symlink_inode_operations);
    diff --git a/fs/minix/inode.c b/fs/minix/inode.c
    index 67a23bf..3cce709 100644
    --- a/fs/minix/inode.c
    +++ b/fs/minix/inode.c
    @@ -435,7 +435,7 @@ static const struct address_space_operations minix_aops = {

    static const struct inode_operations minix_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .getattr = minix_getattr,
    };
    diff --git a/fs/namei.c b/fs/namei.c
    index 2808958..1da3064 100644
    --- a/fs/namei.c
    +++ b/fs/namei.c
    @@ -842,7 +842,7 @@ static inline void path_to_nameidata(const struct path *path,
    }

    /*
    - * Helper to directly jump to a known parsed path from ->follow_link,
    + * Helper to directly jump to a known parsed path from ->get_link,
    * caller must have taken a reference to path beforehand.
    */
    void nd_jump_link(struct path *path)
    @@ -1005,10 +1005,18 @@ const char *get_link(struct nameidata *nd)
    res = inode->i_link;
    if (!res) {
    if (nd->flags & LOOKUP_RCU) {
    - if (unlikely(unlazy_walk(nd, NULL, 0)))
    - return ERR_PTR(-ECHILD);
    + res = inode->i_op->get_link(NULL, inode,
    + &last->cookie);
    + if (res == ERR_PTR(-ECHILD)) {
    + if (unlikely(unlazy_walk(nd, NULL, 0)))
    + return ERR_PTR(-ECHILD);
    + res = inode->i_op->get_link(dentry, inode,
    + &last->cookie);
    + }
    + } else {
    + res = inode->i_op->get_link(dentry, inode,
    + &last->cookie);
    }
    - res = inode->i_op->follow_link(dentry, &last->cookie);
    if (IS_ERR_OR_NULL(res)) {
    last->cookie = NULL;
    return res;
    @@ -4495,8 +4503,8 @@ EXPORT_SYMBOL(readlink_copy);

    /*
    * A helper for ->readlink(). This should be used *ONLY* for symlinks that
    - * have ->follow_link() touching nd only in nd_set_link(). Using (or not
    - * using) it for any given inode is up to filesystem.
    + * have ->get_link() not calling nd_jump_link(). Using (or not using) it
    + * for any given inode is up to filesystem.
    */
    int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
    {
    @@ -4506,7 +4514,7 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
    int res;

    if (!link) {
    - link = inode->i_op->follow_link(dentry, &cookie);
    + link = inode->i_op->get_link(dentry, inode, &cookie);
    if (IS_ERR(link))
    return PTR_ERR(link);
    }
    @@ -4518,26 +4526,27 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
    EXPORT_SYMBOL(generic_readlink);

    /* get the link contents into pagecache */
    -static const char *page_getlink(struct dentry * dentry, void **cookie)
    +const char *page_get_link(struct dentry *dentry, struct inode *inode,
    + void **cookie)
    {
    char *kaddr;
    struct page *page;
    - struct address_space *mapping = dentry->d_inode->i_mapping;
    + struct address_space *mapping = inode->i_mapping;
    +
    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    page = read_mapping_page(mapping, 0, NULL);
    if (IS_ERR(page))
    return (char*)page;
    *cookie = page;
    BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM);
    kaddr = page_address(page);
    - nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
    + nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1);
    return kaddr;
    }

    -const char *page_follow_link_light(struct dentry *dentry, void **cookie)
    -{
    - return page_getlink(dentry, cookie);
    -}
    -EXPORT_SYMBOL(page_follow_link_light);
    +EXPORT_SYMBOL(page_get_link);

    void page_put_link(struct inode *unused, void *cookie)
    {
    @@ -4549,7 +4558,9 @@ EXPORT_SYMBOL(page_put_link);
    int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
    {
    void *cookie = NULL;
    - int res = readlink_copy(buffer, buflen, page_getlink(dentry, &cookie));
    + int res = readlink_copy(buffer, buflen,
    + page_get_link(dentry, d_inode(dentry),
    + &cookie));
    if (cookie)
    page_put_link(NULL, cookie);
    return res;
    @@ -4600,7 +4611,7 @@ EXPORT_SYMBOL(page_symlink);

    const struct inode_operations page_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    };
    EXPORT_SYMBOL(page_symlink_inode_operations);
    diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
    index bb856f7..3ab6cdb 100644
    --- a/fs/ncpfs/inode.c
    +++ b/fs/ncpfs/inode.c
    @@ -244,7 +244,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
    #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
    static const struct inode_operations ncp_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = ncp_notify_change,
    };
    diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
    index abd93bf..8ade8a8 100644
    --- a/fs/nfs/symlink.c
    +++ b/fs/nfs/symlink.c
    @@ -42,12 +42,15 @@ error:
    return -EIO;
    }

    -static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
    +static const char *nfs_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct inode *inode = d_inode(dentry);
    struct page *page;
    void *err;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
    if (err)
    return err;
    @@ -64,7 +67,7 @@ static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
    */
    const struct inode_operations nfs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = nfs_follow_link,
    + .get_link = nfs_get_link,
    .put_link = page_put_link,
    .getattr = nfs_getattr,
    .setattr = nfs_setattr,
    diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
    index 90b3ba9..63dddb7 100644
    --- a/fs/nilfs2/namei.c
    +++ b/fs/nilfs2/namei.c
    @@ -569,7 +569,7 @@ const struct inode_operations nilfs_special_inode_operations = {

    const struct inode_operations nilfs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .permission = nilfs_permission,
    };
    diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
    index 66edce7..b4e79bc 100644
    --- a/fs/ocfs2/symlink.c
    +++ b/fs/ocfs2/symlink.c
    @@ -88,7 +88,7 @@ const struct address_space_operations ocfs2_fast_symlink_aops = {

    const struct inode_operations ocfs2_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .getattr = ocfs2_getattr,
    .setattr = ocfs2_setattr,
    diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
    index 4060ffd..38a0b8b 100644
    --- a/fs/overlayfs/inode.c
    +++ b/fs/overlayfs/inode.c
    @@ -137,17 +137,21 @@ struct ovl_link_data {
    void *cookie;
    };

    -static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
    +static const char *ovl_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    struct dentry *realdentry;
    struct inode *realinode;
    struct ovl_link_data *data = NULL;
    const char *ret;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    realdentry = ovl_dentry_real(dentry);
    realinode = realdentry->d_inode;

    - if (WARN_ON(!realinode->i_op->follow_link))
    + if (WARN_ON(!realinode->i_op->get_link))
    return ERR_PTR(-EPERM);

    if (realinode->i_op->put_link) {
    @@ -157,7 +161,7 @@ static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
    data->realdentry = realdentry;
    }

    - ret = realinode->i_op->follow_link(realdentry, cookie);
    + ret = realinode->i_op->get_link(realdentry, realinode, cookie);
    if (IS_ERR_OR_NULL(ret)) {
    kfree(data);
    return ret;
    @@ -378,7 +382,7 @@ static const struct inode_operations ovl_file_inode_operations = {

    static const struct inode_operations ovl_symlink_inode_operations = {
    .setattr = ovl_setattr,
    - .follow_link = ovl_follow_link,
    + .get_link = ovl_get_link,
    .put_link = ovl_put_link,
    .readlink = ovl_readlink,
    .getattr = ovl_getattr,
    diff --git a/fs/proc/base.c b/fs/proc/base.c
    index bd3e9e6..1a489e2 100644
    --- a/fs/proc/base.c
    +++ b/fs/proc/base.c
    @@ -1564,12 +1564,15 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
    return -ENOENT;
    }

    -static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie)
    +static const char *proc_pid_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct inode *inode = d_inode(dentry);
    struct path path;
    int error = -EACCES;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    /* Are we allowed to snoop on the tasks file descriptors? */
    if (!proc_fd_access_allowed(inode))
    goto out;
    @@ -1630,7 +1633,7 @@ out:

    const struct inode_operations proc_pid_link_inode_operations = {
    .readlink = proc_pid_readlink,
    - .follow_link = proc_pid_follow_link,
    + .get_link = proc_pid_get_link,
    .setattr = proc_setattr,
    };

    @@ -1895,7 +1898,7 @@ static const struct dentry_operations tid_map_files_dentry_operations = {
    .d_delete = pid_delete_dentry,
    };

    -static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
    +static int map_files_get_link(struct dentry *dentry, struct path *path)
    {
    unsigned long vm_start, vm_end;
    struct vm_area_struct *vma;
    @@ -1945,20 +1948,21 @@ struct map_files_info {
    * path to the file in question.
    */
    static const char *
    -proc_map_files_follow_link(struct dentry *dentry, void **cookie)
    +proc_map_files_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    if (!capable(CAP_SYS_ADMIN))
    return ERR_PTR(-EPERM);

    - return proc_pid_follow_link(dentry, NULL);
    + return proc_pid_get_link(dentry, inode, NULL);
    }

    /*
    - * Identical to proc_pid_link_inode_operations except for follow_link()
    + * Identical to proc_pid_link_inode_operations except for get_link()
    */
    static const struct inode_operations proc_map_files_link_inode_operations = {
    .readlink = proc_pid_readlink,
    - .follow_link = proc_map_files_follow_link,
    + .get_link = proc_map_files_get_link,
    .setattr = proc_setattr,
    };

    @@ -1975,7 +1979,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
    return -ENOENT;

    ei = PROC_I(inode);
    - ei->op.proc_get_link = proc_map_files_get_link;
    + ei->op.proc_get_link = map_files_get_link;

    inode->i_op = &proc_map_files_link_inode_operations;
    inode->i_size = 64;
    diff --git a/fs/proc/inode.c b/fs/proc/inode.c
    index bd95b9f..10360b2 100644
    --- a/fs/proc/inode.c
    +++ b/fs/proc/inode.c
    @@ -393,9 +393,10 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
    };
    #endif

    -static const char *proc_follow_link(struct dentry *dentry, void **cookie)
    +static const char *proc_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct proc_dir_entry *pde = PDE(d_inode(dentry));
    + struct proc_dir_entry *pde = PDE(inode);
    if (unlikely(!use_pde(pde)))
    return ERR_PTR(-EINVAL);
    *cookie = pde;
    @@ -409,7 +410,7 @@ static void proc_put_link(struct inode *unused, void *p)

    const struct inode_operations proc_link_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = proc_follow_link,
    + .get_link = proc_get_link,
    .put_link = proc_put_link,
    };

    diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
    index f6e8354..63861c1 100644
    --- a/fs/proc/namespaces.c
    +++ b/fs/proc/namespaces.c
    @@ -30,14 +30,17 @@ static const struct proc_ns_operations *ns_entries[] = {
    &mntns_operations,
    };

    -static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie)
    +static const char *proc_ns_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct inode *inode = d_inode(dentry);
    const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
    struct task_struct *task;
    struct path ns_path;
    void *error = ERR_PTR(-EACCES);

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    task = get_proc_task(inode);
    if (!task)
    return error;
    @@ -74,7 +77,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl

    static const struct inode_operations proc_ns_link_inode_operations = {
    .readlink = proc_ns_readlink,
    - .follow_link = proc_ns_follow_link,
    + .get_link = proc_ns_get_link,
    .setattr = proc_setattr,
    };

    diff --git a/fs/proc/self.c b/fs/proc/self.c
    index 113b8d0..9dd0ae6 100644
    --- a/fs/proc/self.c
    +++ b/fs/proc/self.c
    @@ -18,12 +18,15 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
    return readlink_copy(buffer, buflen, tmp);
    }

    -static const char *proc_self_follow_link(struct dentry *dentry, void **cookie)
    +static const char *proc_self_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct pid_namespace *ns = dentry->d_sb->s_fs_info;
    + struct pid_namespace *ns = inode->i_sb->s_fs_info;
    pid_t tgid = task_tgid_nr_ns(current, ns);
    char *name;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    if (!tgid)
    return ERR_PTR(-ENOENT);
    /* 11 for max length of signed int in decimal + NULL term */
    @@ -36,7 +39,7 @@ static const char *proc_self_follow_link(struct dentry *dentry, void **cookie)

    static const struct inode_operations proc_self_inode_operations = {
    .readlink = proc_self_readlink,
    - .follow_link = proc_self_follow_link,
    + .get_link = proc_self_get_link,
    .put_link = kfree_put_link,
    };

    diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
    index 947b0f4..50eef6f 100644
    --- a/fs/proc/thread_self.c
    +++ b/fs/proc/thread_self.c
    @@ -19,13 +19,16 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
    return readlink_copy(buffer, buflen, tmp);
    }

    -static const char *proc_thread_self_follow_link(struct dentry *dentry, void **cookie)
    +static const char *proc_thread_self_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    - struct pid_namespace *ns = dentry->d_sb->s_fs_info;
    + struct pid_namespace *ns = inode->i_sb->s_fs_info;
    pid_t tgid = task_tgid_nr_ns(current, ns);
    pid_t pid = task_pid_nr_ns(current, ns);
    char *name;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    if (!pid)
    return ERR_PTR(-ENOENT);
    name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
    @@ -37,7 +40,7 @@ static const char *proc_thread_self_follow_link(struct dentry *dentry, void **co

    static const struct inode_operations proc_thread_self_inode_operations = {
    .readlink = proc_thread_self_readlink,
    - .follow_link = proc_thread_self_follow_link,
    + .get_link = proc_thread_self_get_link,
    .put_link = kfree_put_link,
    };

    diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
    index 4fc2326..ecbf11e 100644
    --- a/fs/reiserfs/namei.c
    +++ b/fs/reiserfs/namei.c
    @@ -1665,7 +1665,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
    */
    const struct inode_operations reiserfs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .setattr = reiserfs_setattr,
    .setxattr = reiserfs_setxattr,
    diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
    index 12806df..7c635a5 100644
    --- a/fs/squashfs/symlink.c
    +++ b/fs/squashfs/symlink.c
    @@ -119,7 +119,7 @@ const struct address_space_operations squashfs_symlink_aops = {

    const struct inode_operations squashfs_symlink_inode_ops = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .getxattr = generic_getxattr,
    .listxattr = squashfs_listxattr
    diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
    index ef8bcdb..80a40bc 100644
    --- a/fs/sysv/inode.c
    +++ b/fs/sysv/inode.c
    @@ -146,7 +146,7 @@ static inline void write3byte(struct sysv_sb_info *sbi,

    static const struct inode_operations sysv_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = page_follow_link_light,
    + .get_link = page_get_link,
    .put_link = page_put_link,
    .getattr = sysv_getattr,
    };
    diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
    index 0edc128..eff6280 100644
    --- a/fs/ubifs/file.c
    +++ b/fs/ubifs/file.c
    @@ -1608,7 +1608,7 @@ const struct inode_operations ubifs_file_inode_operations = {

    const struct inode_operations ubifs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    .setattr = ubifs_setattr,
    .getattr = ubifs_getattr,
    .setxattr = ubifs_setxattr,
    diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
    index 245268a..f638fd5 100644
    --- a/fs/xfs/xfs_iops.c
    +++ b/fs/xfs/xfs_iops.c
    @@ -414,13 +414,17 @@ xfs_vn_rename(
    * uio is kmalloced for this reason...
    */
    STATIC const char *
    -xfs_vn_follow_link(
    +xfs_vn_get_link(
    struct dentry *dentry,
    + struct inode *inode,
    void **cookie)
    {
    char *link;
    int error = -ENOMEM;

    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    +
    link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
    if (!link)
    goto out_err;
    @@ -1172,7 +1176,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {

    static const struct inode_operations xfs_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = xfs_vn_follow_link,
    + .get_link = xfs_vn_get_link,
    .put_link = kfree_put_link,
    .getattr = xfs_vn_getattr,
    .setattr = xfs_vn_setattr,
    diff --git a/include/linux/fs.h b/include/linux/fs.h
    index dfeda44..d2fdf09 100644
    --- a/include/linux/fs.h
    +++ b/include/linux/fs.h
    @@ -1633,7 +1633,7 @@ struct file_operations {

    struct inode_operations {
    struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
    - const char * (*follow_link) (struct dentry *, void **);
    + const char * (*get_link) (struct dentry *, struct inode *, void **);
    int (*permission) (struct inode *, int);
    struct posix_acl * (*get_acl)(struct inode *, int);

    @@ -2736,7 +2736,7 @@ extern const struct file_operations generic_ro_fops;

    extern int readlink_copy(char __user *, int, const char *);
    extern int page_readlink(struct dentry *, char __user *, int);
    -extern const char *page_follow_link_light(struct dentry *, void **);
    +extern const char *page_get_link(struct dentry *, struct inode *, void **);
    extern void page_put_link(struct inode *, void *);
    extern int __page_symlink(struct inode *inode, const char *symname, int len,
    int nofs);
    @@ -2754,7 +2754,7 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
    void inode_sub_bytes(struct inode *inode, loff_t bytes);
    loff_t inode_get_bytes(struct inode *inode);
    void inode_set_bytes(struct inode *inode, loff_t bytes);
    -const char *simple_follow_link(struct dentry *, void **);
    +const char *simple_get_link(struct dentry *, struct inode *, void **);
    extern const struct inode_operations simple_symlink_inode_operations;

    extern int iterate_dir(struct file *, struct dir_context *);
    diff --git a/mm/shmem.c b/mm/shmem.c
    index 64bf5ac..684dbc3 100644
    --- a/mm/shmem.c
    +++ b/mm/shmem.c
    @@ -2496,10 +2496,14 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
    return 0;
    }

    -static const char *shmem_follow_link(struct dentry *dentry, void **cookie)
    +static const char *shmem_get_link(struct dentry *dentry,
    + struct inode *inode, void **cookie)
    {
    struct page *page = NULL;
    - int error = shmem_getpage(d_inode(dentry), 0, &page, SGP_READ, NULL);
    + int error;
    + if (!dentry)
    + return ERR_PTR(-ECHILD);
    + error = shmem_getpage(inode, 0, &page, SGP_READ, NULL);
    if (error)
    return ERR_PTR(error);
    unlock_page(page);
    @@ -2656,7 +2660,7 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)

    static const struct inode_operations shmem_short_symlink_operations = {
    .readlink = generic_readlink,
    - .follow_link = simple_follow_link,
    + .get_link = simple_get_link,
    #ifdef CONFIG_TMPFS_XATTR
    .setxattr = shmem_setxattr,
    .getxattr = shmem_getxattr,
    @@ -2667,7 +2671,7 @@ static const struct inode_operations shmem_short_symlink_operations = {

    static const struct inode_operations shmem_symlink_inode_operations = {
    .readlink = generic_readlink,
    - .follow_link = shmem_follow_link,
    + .get_link = shmem_get_link,
    .put_link = shmem_put_link,
    #ifdef CONFIG_TMPFS_XATTR
    .setxattr = shmem_setxattr,
    --
    2.1.4


    \
     
     \ /
      Last update: 2015-12-09 07:21    [W:4.137 / U:0.340 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site