From patchwork Fri Jan 1 06:38:15 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Al Viro X-Patchwork-Id: 7938581 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id DC5719F38D for ; Fri, 1 Jan 2016 06:40:54 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0779F20544 for ; Fri, 1 Jan 2016 06:40:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DF76E2053D for ; Fri, 1 Jan 2016 06:40:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751846AbcAAGjW (ORCPT ); Fri, 1 Jan 2016 01:39:22 -0500 Received: from zeniv.linux.org.uk ([195.92.253.2]:36732 "EHLO ZenIV.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751427AbcAAGiX (ORCPT ); Fri, 1 Jan 2016 01:38:23 -0500 Received: from viro by ZenIV.linux.org.uk with local (Exim 4.76 #1 (Red Hat Linux)) id 1aEtLx-0007ye-Vy; Fri, 01 Jan 2016 06:38:22 +0000 From: Al Viro To: Linus Torvalds Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [PATCH 07/13] replace ->follow_link() with new method that could stay in RCU mode Date: Fri, 1 Jan 2016 06:38:15 +0000 Message-Id: <1451630301-30618-7-git-send-email-viro@ZenIV.linux.org.uk> X-Mailer: git-send-email 1.7.7.6 In-Reply-To: <20160101063624.GG9938@ZenIV.linux.org.uk> References: <20160101063624.GG9938@ZenIV.linux.org.uk> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Al Viro 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 --- 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,