summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-12-09 16:45:04 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2016-12-09 16:45:04 +0100
commit76fca90e9f3abc82114d9d02d8e14e0324a18ca2 (patch)
tree9dc26cb4603b4c93cd6b5b1bb7b538c30d19e438 /fs
parentvfs: replace calling i_op->readlink with vfs_readlink() (diff)
downloadlinux-76fca90e9f3abc82114d9d02d8e14e0324a18ca2.tar.xz
linux-76fca90e9f3abc82114d9d02d8e14e0324a18ca2.zip
vfs: default to generic_readlink()
If i_op->readlink is NULL, but i_op->get_link is set then vfs_readlink() defaults to calling generic_readlink(). The IOP_DEFAULT_READLINK flag indicates that the above conditions are met and the default action can be taken. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 12a4159de72a..b87465d67c60 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4682,10 +4682,19 @@ int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
struct inode *inode = d_inode(dentry);
- if (!inode->i_op->readlink)
- return -EINVAL;
+ if (unlikely(!(inode->i_opflags & IOP_DEFAULT_READLINK))) {
+ if (unlikely(inode->i_op->readlink))
+ return inode->i_op->readlink(dentry, buffer, buflen);
+
+ if (!d_is_symlink(dentry))
+ return -EINVAL;
+
+ spin_lock(&inode->i_lock);
+ inode->i_opflags |= IOP_DEFAULT_READLINK;
+ spin_unlock(&inode->i_lock);
+ }
- return inode->i_op->readlink(dentry, buffer, buflen);
+ return generic_readlink(dentry, buffer, buflen);
}
EXPORT_SYMBOL(vfs_readlink);