nfsd_readlink(): switch to vfs_get_link()
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 27 May 2017 20:11:23 +0000 (16:11 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 27 May 2017 20:11:23 +0000 (16:11 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/nfsd/vfs.c

index 2be3295..6eef95c 100644 (file)
@@ -1464,41 +1464,34 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
 __be32
 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
 {
-       mm_segment_t    oldfs;
        __be32          err;
-       int             host_err;
+       const char *link;
        struct path path;
+       DEFINE_DELAYED_CALL(done);
+       int len;
 
        err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP);
-       if (err)
-               goto out;
+       if (unlikely(err))
+               return err;
 
        path.mnt = fhp->fh_export->ex_path.mnt;
        path.dentry = fhp->fh_dentry;
 
-       err = nfserr_inval;
-       if (!d_is_symlink(path.dentry))
-               goto out;
+       if (unlikely(!d_is_symlink(path.dentry)))
+               return nfserr_inval;
 
        touch_atime(&path);
-       /* N.B. Why does this call need a get_fs()??
-        * Remove the set_fs and watch the fireworks:-) --okir
-        */
 
-       oldfs = get_fs(); set_fs(KERNEL_DS);
-       host_err = vfs_readlink(path.dentry, (char __user *)buf, *lenp);
-       set_fs(oldfs);
+       link = vfs_get_link(path.dentry, &done);
+       if (IS_ERR(link))
+               return nfserrno(PTR_ERR(link));
 
-       if (host_err < 0)
-               goto out_nfserr;
-       *lenp = host_err;
-       err = 0;
-out:
-       return err;
-
-out_nfserr:
-       err = nfserrno(host_err);
-       goto out;
+       len = strlen(link);
+       if (len < *lenp)
+               *lenp = len;
+       memcpy(buf, link, *lenp);
+       do_delayed_call(&done);
+       return 0;
 }
 
 /*