diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2016-12-09 16:45:04 +0100 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2016-12-09 16:45:04 +0100 |
commit | 76fca90e9f3abc82114d9d02d8e14e0324a18ca2 (patch) | |
tree | 9dc26cb4603b4c93cd6b5b1bb7b538c30d19e438 /fs/namei.c | |
parent | fd4a0edf2a3d781c6ae07d2810776ce22302ee1c (diff) | |
download | lwn-76fca90e9f3abc82114d9d02d8e14e0324a18ca2.tar.gz lwn-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/namei.c')
-rw-r--r-- | fs/namei.c | 15 |
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); |