Merge uncontroversial parts of branch 'readlink' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

Pull partial readlink cleanups from Miklos Szeredi.

This is the uncontroversial part of the readlink cleanup patch-set that
simplifies the default readlink handling.

Miklos and Al are still discussing the rest of the series.

* git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  vfs: make generic_readlink() static
  vfs: remove ".readlink = generic_readlink" assignments
  vfs: default to generic_readlink()
  vfs: replace calling i_op->readlink with vfs_readlink()
  proc/self: use generic_readlink
  ecryptfs: use vfs_get_link()
  bad_inode: add missing i_op initializers
This commit is contained in:
Linus Torvalds 2016-12-17 19:16:12 -08:00
commit 231753ef78
46 changed files with 120 additions and 110 deletions

View File

@ -596,3 +596,7 @@ in your dentry operations instead.
[mandatory] [mandatory]
->rename() has an added flags argument. Any flags not handled by the ->rename() has an added flags argument. Any flags not handled by the
filesystem should result in EINVAL being returned. filesystem should result in EINVAL being returned.
--
[recommended]
->readlink is optional for symlinks. Don't set, unless filesystem needs
to fake something for readlink(2).

View File

@ -451,9 +451,6 @@ otherwise noted.
exist; this is checked by the VFS. Unlike plain rename, exist; this is checked by the VFS. Unlike plain rename,
source and target may be of different type. source and target may be of different type.
readlink: called by the readlink(2) system call. Only required if
you want to support reading symbolic links
get_link: called by the VFS to follow a symbolic link to the get_link: called by the VFS to follow a symbolic link to the
inode it points to. Only required if you want to support inode it points to. Only required if you want to support
symbolic links. This method returns the symlink body symbolic links. This method returns the symlink body
@ -468,6 +465,12 @@ otherwise noted.
argument. If request can't be handled without leaving RCU mode, argument. If request can't be handled without leaving RCU mode,
have it return ERR_PTR(-ECHILD). have it return ERR_PTR(-ECHILD).
readlink: this is now just an override for use by readlink(2) for the
cases when ->get_link uses nd_jump_link() or object is not in
fact a symlink. Normally filesystems should only implement
->get_link for symlinks and readlink(2) will automatically use
that.
permission: called by the VFS to check for access rights on a POSIX-like permission: called by the VFS to check for access rights on a POSIX-like
filesystem. filesystem.

View File

@ -149,7 +149,6 @@ static const char *ll_get_link(struct dentry *dentry,
} }
const struct inode_operations ll_fast_symlink_inode_operations = { const struct inode_operations ll_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.setattr = ll_setattr, .setattr = ll_setattr,
.get_link = ll_get_link, .get_link = ll_get_link,
.getattr = ll_getattr, .getattr = ll_getattr,

View File

@ -1464,7 +1464,6 @@ static const struct inode_operations v9fs_file_inode_operations = {
}; };
static const struct inode_operations v9fs_symlink_inode_operations = { static const struct inode_operations v9fs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = v9fs_vfs_get_link, .get_link = v9fs_vfs_get_link,
.getattr = v9fs_vfs_getattr, .getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr, .setattr = v9fs_vfs_setattr,

View File

@ -979,7 +979,6 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
}; };
const struct inode_operations v9fs_symlink_inode_operations_dotl = { const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.readlink = generic_readlink,
.get_link = v9fs_vfs_get_link_dotl, .get_link = v9fs_vfs_get_link_dotl,
.getattr = v9fs_vfs_getattr_dotl, .getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl, .setattr = v9fs_vfs_setattr_dotl,

View File

@ -70,7 +70,6 @@ const struct address_space_operations affs_symlink_aops = {
}; };
const struct inode_operations affs_symlink_inode_operations = { const struct inode_operations affs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = affs_notify_change, .setattr = affs_notify_change,
}; };

View File

@ -25,6 +25,5 @@ static const char *autofs4_get_link(struct dentry *dentry,
} }
const struct inode_operations autofs4_symlink_inode_operations = { const struct inode_operations autofs4_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = autofs4_get_link .get_link = autofs4_get_link
}; };

View File

@ -106,6 +106,50 @@ static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer,
return -EIO; return -EIO;
} }
static const char *bad_inode_get_link(struct dentry *dentry,
struct inode *inode,
struct delayed_call *done)
{
return ERR_PTR(-EIO);
}
static struct posix_acl *bad_inode_get_acl(struct inode *inode, int type)
{
return ERR_PTR(-EIO);
}
static int bad_inode_fiemap(struct inode *inode,
struct fiemap_extent_info *fieinfo, u64 start,
u64 len)
{
return -EIO;
}
static int bad_inode_update_time(struct inode *inode, struct timespec *time,
int flags)
{
return -EIO;
}
static int bad_inode_atomic_open(struct inode *inode, struct dentry *dentry,
struct file *file, unsigned int open_flag,
umode_t create_mode, int *opened)
{
return -EIO;
}
static int bad_inode_tmpfile(struct inode *inode, struct dentry *dentry,
umode_t mode)
{
return -EIO;
}
static int bad_inode_set_acl(struct inode *inode, struct posix_acl *acl,
int type)
{
return -EIO;
}
static const struct inode_operations bad_inode_ops = static const struct inode_operations bad_inode_ops =
{ {
.create = bad_inode_create, .create = bad_inode_create,
@ -118,14 +162,17 @@ static const struct inode_operations bad_inode_ops =
.mknod = bad_inode_mknod, .mknod = bad_inode_mknod,
.rename = bad_inode_rename2, .rename = bad_inode_rename2,
.readlink = bad_inode_readlink, .readlink = bad_inode_readlink,
/* follow_link must be no-op, otherwise unmounting this inode
won't work */
/* put_link returns void */
/* truncate returns void */
.permission = bad_inode_permission, .permission = bad_inode_permission,
.getattr = bad_inode_getattr, .getattr = bad_inode_getattr,
.setattr = bad_inode_setattr, .setattr = bad_inode_setattr,
.listxattr = bad_inode_listxattr, .listxattr = bad_inode_listxattr,
.get_link = bad_inode_get_link,
.get_acl = bad_inode_get_acl,
.fiemap = bad_inode_fiemap,
.update_time = bad_inode_update_time,
.atomic_open = bad_inode_atomic_open,
.tmpfile = bad_inode_tmpfile,
.set_acl = bad_inode_set_acl,
}; };

View File

@ -10653,7 +10653,6 @@ static const struct inode_operations btrfs_special_inode_operations = {
.update_time = btrfs_update_time, .update_time = btrfs_update_time,
}; };
static const struct inode_operations btrfs_symlink_inode_operations = { static const struct inode_operations btrfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.getattr = btrfs_getattr, .getattr = btrfs_getattr,
.setattr = btrfs_setattr, .setattr = btrfs_setattr,

View File

@ -1869,7 +1869,6 @@ retry:
* symlinks * symlinks
*/ */
static const struct inode_operations ceph_symlink_iops = { static const struct inode_operations ceph_symlink_iops = {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = ceph_setattr, .setattr = ceph_setattr,
.getattr = ceph_getattr, .getattr = ceph_getattr,

View File

@ -914,7 +914,6 @@ const struct inode_operations cifs_file_inode_ops = {
}; };
const struct inode_operations cifs_symlink_inode_ops = { const struct inode_operations cifs_symlink_inode_ops = {
.readlink = generic_readlink,
.get_link = cifs_get_link, .get_link = cifs_get_link,
.permission = cifs_permission, .permission = cifs_permission,
.listxattr = cifs_listxattr, .listxattr = cifs_listxattr,

View File

@ -17,7 +17,6 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
} }
static const struct inode_operations coda_symlink_inode_operations = { static const struct inode_operations coda_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = coda_setattr, .setattr = coda_setattr,
}; };

View File

@ -305,7 +305,6 @@ static const char *configfs_get_link(struct dentry *dentry,
const struct inode_operations configfs_symlink_inode_operations = { const struct inode_operations configfs_symlink_inode_operations = {
.get_link = configfs_get_link, .get_link = configfs_get_link,
.readlink = generic_readlink,
.setattr = configfs_setattr, .setattr = configfs_setattr,
}; };

View File

@ -631,28 +631,23 @@ out_lock:
static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz) static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz)
{ {
DEFINE_DELAYED_CALL(done);
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
char *lower_buf; const char *link;
char *buf; char *buf;
mm_segment_t old_fs;
int rc; int rc;
lower_buf = kmalloc(PATH_MAX, GFP_KERNEL); link = vfs_get_link(lower_dentry, &done);
if (!lower_buf) if (IS_ERR(link))
return ERR_PTR(-ENOMEM); return ERR_CAST(link);
old_fs = get_fs();
set_fs(get_ds());
rc = d_inode(lower_dentry)->i_op->readlink(lower_dentry,
(char __user *)lower_buf,
PATH_MAX);
set_fs(old_fs);
if (rc < 0)
goto out;
rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb, rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb,
lower_buf, rc); link, strlen(link));
out: do_delayed_call(&done);
kfree(lower_buf); if (rc)
return rc ? ERR_PTR(rc) : buf; return ERR_PTR(rc);
return buf;
} }
static const char *ecryptfs_get_link(struct dentry *dentry, static const char *ecryptfs_get_link(struct dentry *dentry,
@ -1089,7 +1084,6 @@ out:
} }
const struct inode_operations ecryptfs_symlink_iops = { const struct inode_operations ecryptfs_symlink_iops = {
.readlink = generic_readlink,
.get_link = ecryptfs_get_link, .get_link = ecryptfs_get_link,
.permission = ecryptfs_permission, .permission = ecryptfs_permission,
.setattr = ecryptfs_setattr, .setattr = ecryptfs_setattr,

View File

@ -21,7 +21,6 @@
#include "xattr.h" #include "xattr.h"
const struct inode_operations ext2_symlink_inode_operations = { const struct inode_operations ext2_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = ext2_setattr, .setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR #ifdef CONFIG_EXT2_FS_XATTR
@ -30,7 +29,6 @@ const struct inode_operations ext2_symlink_inode_operations = {
}; };
const struct inode_operations ext2_fast_symlink_inode_operations = { const struct inode_operations ext2_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = ext2_setattr, .setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR #ifdef CONFIG_EXT2_FS_XATTR

View File

@ -83,21 +83,18 @@ errout:
} }
const struct inode_operations ext4_encrypted_symlink_inode_operations = { const struct inode_operations ext4_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = ext4_encrypted_get_link, .get_link = ext4_encrypted_get_link,
.setattr = ext4_setattr, .setattr = ext4_setattr,
.listxattr = ext4_listxattr, .listxattr = ext4_listxattr,
}; };
const struct inode_operations ext4_symlink_inode_operations = { const struct inode_operations ext4_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = ext4_setattr, .setattr = ext4_setattr,
.listxattr = ext4_listxattr, .listxattr = ext4_listxattr,
}; };
const struct inode_operations ext4_fast_symlink_inode_operations = { const struct inode_operations ext4_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = ext4_setattr, .setattr = ext4_setattr,
.listxattr = ext4_listxattr, .listxattr = ext4_listxattr,

View File

@ -1075,7 +1075,6 @@ errout:
} }
const struct inode_operations f2fs_encrypted_symlink_inode_operations = { const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = f2fs_encrypted_get_link, .get_link = f2fs_encrypted_get_link,
.getattr = f2fs_getattr, .getattr = f2fs_getattr,
.setattr = f2fs_setattr, .setattr = f2fs_setattr,
@ -1105,7 +1104,6 @@ const struct inode_operations f2fs_dir_inode_operations = {
}; };
const struct inode_operations f2fs_symlink_inode_operations = { const struct inode_operations f2fs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = f2fs_get_link, .get_link = f2fs_get_link,
.getattr = f2fs_getattr, .getattr = f2fs_getattr,
.setattr = f2fs_setattr, .setattr = f2fs_setattr,

View File

@ -1831,7 +1831,6 @@ static const struct inode_operations fuse_common_inode_operations = {
static const struct inode_operations fuse_symlink_inode_operations = { static const struct inode_operations fuse_symlink_inode_operations = {
.setattr = fuse_setattr, .setattr = fuse_setattr,
.get_link = fuse_get_link, .get_link = fuse_get_link,
.readlink = generic_readlink,
.getattr = fuse_getattr, .getattr = fuse_getattr,
.listxattr = fuse_listxattr, .listxattr = fuse_listxattr,
}; };

View File

@ -2067,7 +2067,6 @@ const struct inode_operations gfs2_dir_iops = {
}; };
const struct inode_operations gfs2_symlink_iops = { const struct inode_operations gfs2_symlink_iops = {
.readlink = generic_readlink,
.get_link = gfs2_get_link, .get_link = gfs2_get_link,
.permission = gfs2_permission, .permission = gfs2_permission,
.setattr = gfs2_setattr, .setattr = gfs2_setattr,

View File

@ -920,7 +920,6 @@ static const char *hostfs_get_link(struct dentry *dentry,
} }
static const struct inode_operations hostfs_link_iops = { static const struct inode_operations hostfs_link_iops = {
.readlink = generic_readlink,
.get_link = hostfs_get_link, .get_link = hostfs_get_link,
}; };

View File

@ -13,7 +13,6 @@
const struct inode_operations jffs2_symlink_inode_operations = const struct inode_operations jffs2_symlink_inode_operations =
{ {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = jffs2_setattr, .setattr = jffs2_setattr,
.listxattr = jffs2_listxattr, .listxattr = jffs2_listxattr,

View File

@ -22,14 +22,12 @@
#include "jfs_xattr.h" #include "jfs_xattr.h"
const struct inode_operations jfs_fast_symlink_inode_operations = { const struct inode_operations jfs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = jfs_setattr, .setattr = jfs_setattr,
.listxattr = jfs_listxattr, .listxattr = jfs_listxattr,
}; };
const struct inode_operations jfs_symlink_inode_operations = { const struct inode_operations jfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = jfs_setattr, .setattr = jfs_setattr,
.listxattr = jfs_listxattr, .listxattr = jfs_listxattr,

View File

@ -135,7 +135,6 @@ static const char *kernfs_iop_get_link(struct dentry *dentry,
const struct inode_operations kernfs_symlink_iops = { const struct inode_operations kernfs_symlink_iops = {
.listxattr = kernfs_iop_listxattr, .listxattr = kernfs_iop_listxattr,
.readlink = generic_readlink,
.get_link = kernfs_iop_get_link, .get_link = kernfs_iop_get_link,
.setattr = kernfs_iop_setattr, .setattr = kernfs_iop_setattr,
.getattr = kernfs_iop_getattr, .getattr = kernfs_iop_getattr,

View File

@ -1131,7 +1131,6 @@ EXPORT_SYMBOL(simple_get_link);
const struct inode_operations simple_symlink_inode_operations = { const struct inode_operations simple_symlink_inode_operations = {
.get_link = simple_get_link, .get_link = simple_get_link,
.readlink = generic_readlink
}; };
EXPORT_SYMBOL(simple_symlink_inode_operations); EXPORT_SYMBOL(simple_symlink_inode_operations);

View File

@ -434,7 +434,6 @@ static const struct address_space_operations minix_aops = {
}; };
static const struct inode_operations minix_symlink_inode_operations = { static const struct inode_operations minix_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.getattr = minix_getattr, .getattr = minix_getattr,
}; };

View File

@ -4606,7 +4606,8 @@ out:
* have ->get_link() not calling nd_jump_link(). Using (or not using) it * have ->get_link() not calling nd_jump_link(). Using (or not using) it
* for any given inode is up to filesystem. * for any given inode is up to filesystem.
*/ */
int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) static int generic_readlink(struct dentry *dentry, char __user *buffer,
int buflen)
{ {
DEFINE_DELAYED_CALL(done); DEFINE_DELAYED_CALL(done);
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
@ -4622,7 +4623,36 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
do_delayed_call(&done); do_delayed_call(&done);
return res; return res;
} }
EXPORT_SYMBOL(generic_readlink);
/**
* vfs_readlink - copy symlink body into userspace buffer
* @dentry: dentry on which to get symbolic link
* @buffer: user memory pointer
* @buflen: size of buffer
*
* Does not touch atime. That's up to the caller if necessary
*
* Does not call security hook.
*/
int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
struct inode *inode = d_inode(dentry);
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 generic_readlink(dentry, buffer, buflen);
}
EXPORT_SYMBOL(vfs_readlink);
/** /**
* vfs_get_link - get symlink body * vfs_get_link - get symlink body
@ -4739,7 +4769,6 @@ int page_symlink(struct inode *inode, const char *symname, int len)
EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink);
const struct inode_operations page_symlink_inode_operations = { const struct inode_operations page_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
}; };
EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(page_symlink_inode_operations);

View File

@ -243,7 +243,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
static const struct inode_operations ncp_symlink_inode_operations = { static const struct inode_operations ncp_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = ncp_notify_change, .setattr = ncp_notify_change,
}; };

View File

@ -77,7 +77,6 @@ static const char *nfs_get_link(struct dentry *dentry,
* symlinks can't do much... * symlinks can't do much...
*/ */
const struct inode_operations nfs_symlink_inode_operations = { const struct inode_operations nfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = nfs_get_link, .get_link = nfs_get_link,
.getattr = nfs_getattr, .getattr = nfs_getattr,
.setattr = nfs_setattr, .setattr = nfs_setattr,

View File

@ -3605,10 +3605,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
if (!p) if (!p)
return nfserr_resource; return nfserr_resource;
/* /*
* XXX: By default, the ->readlink() VFS op will truncate symlinks * XXX: By default, vfs_readlink() will truncate symlinks if they
* if they would overflow the buffer. Is this kosher in NFSv4? If * would overflow the buffer. Is this kosher in NFSv4? If not, one
* not, one easy fix is: if ->readlink() precisely fills the buffer, * easy fix is: if vfs_readlink() precisely fills the buffer, assume
* assume that truncation occurred, and return NFS4ERR_RESOURCE. * that truncation occurred, and return NFS4ERR_RESOURCE.
*/ */
nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
(char *)p, &maxcount); (char *)p, &maxcount);

View File

@ -1450,7 +1450,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
__be32 __be32
nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
{ {
struct inode *inode;
mm_segment_t oldfs; mm_segment_t oldfs;
__be32 err; __be32 err;
int host_err; int host_err;
@ -1462,10 +1461,9 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
path.mnt = fhp->fh_export->ex_path.mnt; path.mnt = fhp->fh_export->ex_path.mnt;
path.dentry = fhp->fh_dentry; path.dentry = fhp->fh_dentry;
inode = d_inode(path.dentry);
err = nfserr_inval; err = nfserr_inval;
if (!inode->i_op->readlink) if (!d_is_symlink(path.dentry))
goto out; goto out;
touch_atime(&path); touch_atime(&path);
@ -1474,7 +1472,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
*/ */
oldfs = get_fs(); set_fs(KERNEL_DS); oldfs = get_fs(); set_fs(KERNEL_DS);
host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp); host_err = vfs_readlink(path.dentry, (char __user *)buf, *lenp);
set_fs(oldfs); set_fs(oldfs);
if (host_err < 0) if (host_err < 0)

View File

@ -568,7 +568,6 @@ const struct inode_operations nilfs_special_inode_operations = {
}; };
const struct inode_operations nilfs_symlink_inode_operations = { const struct inode_operations nilfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.permission = nilfs_permission, .permission = nilfs_permission,
}; };

View File

@ -87,7 +87,6 @@ const struct address_space_operations ocfs2_fast_symlink_aops = {
}; };
const struct inode_operations ocfs2_symlink_inode_operations = { const struct inode_operations ocfs2_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.getattr = ocfs2_getattr, .getattr = ocfs2_getattr,
.setattr = ocfs2_setattr, .setattr = ocfs2_setattr,

View File

@ -9,7 +9,6 @@
#include "orangefs-bufmap.h" #include "orangefs-bufmap.h"
const struct inode_operations orangefs_symlink_inode_operations = { const struct inode_operations orangefs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = orangefs_setattr, .setattr = orangefs_setattr,
.getattr = orangefs_getattr, .getattr = orangefs_getattr,

View File

@ -296,7 +296,6 @@ static const struct inode_operations ovl_file_inode_operations = {
static const struct inode_operations ovl_symlink_inode_operations = { static const struct inode_operations ovl_symlink_inode_operations = {
.setattr = ovl_setattr, .setattr = ovl_setattr,
.get_link = ovl_get_link, .get_link = ovl_get_link,
.readlink = generic_readlink,
.getattr = ovl_getattr, .getattr = ovl_getattr,
.listxattr = ovl_listxattr, .listxattr = ovl_listxattr,
.update_time = ovl_update_time, .update_time = ovl_update_time,

View File

@ -425,7 +425,6 @@ static const char *proc_get_link(struct dentry *dentry,
} }
const struct inode_operations proc_link_inode_operations = { const struct inode_operations proc_link_inode_operations = {
.readlink = generic_readlink,
.get_link = proc_get_link, .get_link = proc_get_link,
}; };

View File

@ -6,18 +6,6 @@
/* /*
* /proc/self: * /proc/self:
*/ */
static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
int buflen)
{
struct pid_namespace *ns = dentry->d_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
char tmp[PROC_NUMBUF];
if (!tgid)
return -ENOENT;
sprintf(tmp, "%d", tgid);
return readlink_copy(buffer, buflen, tmp);
}
static const char *proc_self_get_link(struct dentry *dentry, static const char *proc_self_get_link(struct dentry *dentry,
struct inode *inode, struct inode *inode,
struct delayed_call *done) struct delayed_call *done)
@ -38,7 +26,6 @@ static const char *proc_self_get_link(struct dentry *dentry,
} }
static const struct inode_operations proc_self_inode_operations = { static const struct inode_operations proc_self_inode_operations = {
.readlink = proc_self_readlink,
.get_link = proc_self_get_link, .get_link = proc_self_get_link,
}; };

View File

@ -6,19 +6,6 @@
/* /*
* /proc/thread_self: * /proc/thread_self:
*/ */
static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
int buflen)
{
struct pid_namespace *ns = dentry->d_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
pid_t pid = task_pid_nr_ns(current, ns);
char tmp[PROC_NUMBUF + 6 + PROC_NUMBUF];
if (!pid)
return -ENOENT;
sprintf(tmp, "%d/task/%d", tgid, pid);
return readlink_copy(buffer, buflen, tmp);
}
static const char *proc_thread_self_get_link(struct dentry *dentry, static const char *proc_thread_self_get_link(struct dentry *dentry,
struct inode *inode, struct inode *inode,
struct delayed_call *done) struct delayed_call *done)
@ -40,7 +27,6 @@ static const char *proc_thread_self_get_link(struct dentry *dentry,
} }
static const struct inode_operations proc_thread_self_inode_operations = { static const struct inode_operations proc_thread_self_inode_operations = {
.readlink = proc_thread_self_readlink,
.get_link = proc_thread_self_get_link, .get_link = proc_thread_self_get_link,
}; };

View File

@ -1665,7 +1665,6 @@ const struct inode_operations reiserfs_dir_inode_operations = {
* stuff added * stuff added
*/ */
const struct inode_operations reiserfs_symlink_inode_operations = { const struct inode_operations reiserfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.setattr = reiserfs_setattr, .setattr = reiserfs_setattr,
.listxattr = reiserfs_listxattr, .listxattr = reiserfs_listxattr,

View File

@ -118,7 +118,6 @@ const struct address_space_operations squashfs_symlink_aops = {
}; };
const struct inode_operations squashfs_symlink_inode_ops = { const struct inode_operations squashfs_symlink_inode_ops = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.listxattr = squashfs_listxattr .listxattr = squashfs_listxattr
}; };

View File

@ -329,12 +329,14 @@ retry:
struct inode *inode = d_backing_inode(path.dentry); struct inode *inode = d_backing_inode(path.dentry);
error = empty ? -ENOENT : -EINVAL; error = empty ? -ENOENT : -EINVAL;
if (inode->i_op->readlink) { /*
* AFS mountpoints allow readlink(2) but are not symlinks
*/
if (d_is_symlink(path.dentry) || inode->i_op->readlink) {
error = security_inode_readlink(path.dentry); error = security_inode_readlink(path.dentry);
if (!error) { if (!error) {
touch_atime(&path); touch_atime(&path);
error = inode->i_op->readlink(path.dentry, error = vfs_readlink(path.dentry, buf, bufsiz);
buf, bufsiz);
} }
} }
path_put(&path); path_put(&path);

View File

@ -145,7 +145,6 @@ static inline void write3byte(struct sysv_sb_info *sbi,
} }
static const struct inode_operations sysv_symlink_inode_operations = { static const struct inode_operations sysv_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = page_get_link, .get_link = page_get_link,
.getattr = sysv_getattr, .getattr = sysv_getattr,
}; };

View File

@ -1733,7 +1733,6 @@ const struct inode_operations ubifs_file_inode_operations = {
}; };
const struct inode_operations ubifs_symlink_inode_operations = { const struct inode_operations ubifs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = ubifs_get_link, .get_link = ubifs_get_link,
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,

View File

@ -287,7 +287,7 @@ xfs_readlink_by_handle(
return PTR_ERR(dentry); return PTR_ERR(dentry);
/* Restrict this handle operation to symlinks only. */ /* Restrict this handle operation to symlinks only. */
if (!d_inode(dentry)->i_op->readlink) { if (!d_is_symlink(dentry)) {
error = -EINVAL; error = -EINVAL;
goto out_dput; goto out_dput;
} }
@ -297,7 +297,7 @@ xfs_readlink_by_handle(
goto out_dput; goto out_dput;
} }
error = d_inode(dentry)->i_op->readlink(dentry, hreq->ohandle, olen); error = vfs_readlink(dentry, hreq->ohandle, olen);
out_dput: out_dput:
dput(dentry); dput(dentry);

View File

@ -1120,7 +1120,6 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
}; };
static const struct inode_operations xfs_symlink_inode_operations = { static const struct inode_operations xfs_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = xfs_vn_get_link, .get_link = xfs_vn_get_link,
.getattr = xfs_vn_getattr, .getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr, .setattr = xfs_vn_setattr,
@ -1129,7 +1128,6 @@ static const struct inode_operations xfs_symlink_inode_operations = {
}; };
static const struct inode_operations xfs_inline_symlink_inode_operations = { static const struct inode_operations xfs_inline_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = xfs_vn_get_link_inline, .get_link = xfs_vn_get_link_inline,
.getattr = xfs_vn_getattr, .getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr, .setattr = xfs_vn_setattr,

View File

@ -543,6 +543,7 @@ is_uncached_acl(struct posix_acl *acl)
#define IOP_LOOKUP 0x0002 #define IOP_LOOKUP 0x0002
#define IOP_NOFOLLOW 0x0004 #define IOP_NOFOLLOW 0x0004
#define IOP_XATTR 0x0008 #define IOP_XATTR 0x0008
#define IOP_DEFAULT_READLINK 0x0010
/* /*
* Keep mostly read-only and often accessed (especially for * Keep mostly read-only and often accessed (especially for
@ -2867,7 +2868,6 @@ extern int __page_symlink(struct inode *inode, const char *symname, int len,
extern int page_symlink(struct inode *inode, const char *symname, int len); extern int page_symlink(struct inode *inode, const char *symname, int len);
extern const struct inode_operations page_symlink_inode_operations; extern const struct inode_operations page_symlink_inode_operations;
extern void kfree_link(void *); extern void kfree_link(void *);
extern int generic_readlink(struct dentry *, char __user *, int);
extern void generic_fillattr(struct inode *, struct kstat *); extern void generic_fillattr(struct inode *, struct kstat *);
int vfs_getattr_nosec(struct path *path, struct kstat *stat); int vfs_getattr_nosec(struct path *path, struct kstat *stat);
extern int vfs_getattr(struct path *, struct kstat *); extern int vfs_getattr(struct path *, struct kstat *);
@ -2888,6 +2888,7 @@ extern int vfs_lstat(const char __user *, struct kstat *);
extern int vfs_fstat(unsigned int, struct kstat *); extern int vfs_fstat(unsigned int, struct kstat *);
extern int vfs_fstatat(int , const char __user *, struct kstat *, int); extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
extern const char *vfs_get_link(struct dentry *, struct delayed_call *); extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
extern int vfs_readlink(struct dentry *, char __user *, int);
extern int __generic_block_fiemap(struct inode *inode, extern int __generic_block_fiemap(struct inode *inode,
struct fiemap_extent_info *fieinfo, struct fiemap_extent_info *fieinfo,

View File

@ -3212,7 +3212,6 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
#endif /* CONFIG_TMPFS_XATTR */ #endif /* CONFIG_TMPFS_XATTR */
static const struct inode_operations shmem_short_symlink_operations = { static const struct inode_operations shmem_short_symlink_operations = {
.readlink = generic_readlink,
.get_link = simple_get_link, .get_link = simple_get_link,
#ifdef CONFIG_TMPFS_XATTR #ifdef CONFIG_TMPFS_XATTR
.listxattr = shmem_listxattr, .listxattr = shmem_listxattr,
@ -3220,7 +3219,6 @@ static const struct inode_operations shmem_short_symlink_operations = {
}; };
static const struct inode_operations shmem_symlink_inode_operations = { static const struct inode_operations shmem_symlink_inode_operations = {
.readlink = generic_readlink,
.get_link = shmem_get_link, .get_link = shmem_get_link,
#ifdef CONFIG_TMPFS_XATTR #ifdef CONFIG_TMPFS_XATTR
.listxattr = shmem_listxattr, .listxattr = shmem_listxattr,