diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2018-07-27 11:19:10 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2018-08-09 16:11:21 -0400 |
commit | 11b4d66ea3313d9b03a83b80458ddee64990e3c3 (patch) | |
tree | d2558f204fe319fc365c07756bfd48a055a0580d /fs/nfsd | |
parent | 3fd9557aec919e2db99365ad5a2c00d04ae8893c (diff) |
NFSD: Handle full-length symlinks
I've given up on the idea of zero-copy handling of SYMLINK on the
server side. This is because the Linux VFS symlink API requires the
symlink pathname to be in a NUL-terminated kmalloc'd buffer. The
NUL-termination is going to be problematic (watching out for
landing on a page boundary and dealing with a 4096-byte pathname).
I don't believe that SYMLINK creation is on a performance path or is
requested frequently enough that it will cause noticeable CPU cache
pollution due to data copies.
There will be two places where a transport callout will be necessary
to fill in the rqstp: one will be in the svc_fill_symlink_pathname()
helper that is used by NFSv2 and NFSv3, and the other will be in
nfsd4_decode_create().
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs3proc.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 2 |
2 files changed, 4 insertions, 0 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 8d1c2d1a159b..9eb8086ea841 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -290,6 +290,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) | |||
290 | RETURN_STATUS(nfserr_nametoolong); | 290 | RETURN_STATUS(nfserr_nametoolong); |
291 | 291 | ||
292 | argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, | 292 | argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, |
293 | page_address(rqstp->rq_arg.pages[0]), | ||
293 | argp->tlen); | 294 | argp->tlen); |
294 | if (IS_ERR(argp->tname)) | 295 | if (IS_ERR(argp->tname)) |
295 | RETURN_STATUS(nfserrno(PTR_ERR(argp->tname))); | 296 | RETURN_STATUS(nfserrno(PTR_ERR(argp->tname))); |
@@ -303,6 +304,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) | |||
303 | fh_init(&resp->fh, NFS3_FHSIZE); | 304 | fh_init(&resp->fh, NFS3_FHSIZE); |
304 | nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, | 305 | nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, |
305 | argp->tname, &resp->fh); | 306 | argp->tname, &resp->fh); |
307 | kfree(argp->tname); | ||
306 | RETURN_STATUS(nfserr); | 308 | RETURN_STATUS(nfserr); |
307 | } | 309 | } |
308 | 310 | ||
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index a6faee562b31..0d20fd161225 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -454,6 +454,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) | |||
454 | return nfserr_nametoolong; | 454 | return nfserr_nametoolong; |
455 | 455 | ||
456 | argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, | 456 | argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, |
457 | page_address(rqstp->rq_arg.pages[0]), | ||
457 | argp->tlen); | 458 | argp->tlen); |
458 | if (IS_ERR(argp->tname)) | 459 | if (IS_ERR(argp->tname)) |
459 | return nfserrno(PTR_ERR(argp->tname)); | 460 | return nfserrno(PTR_ERR(argp->tname)); |
@@ -466,6 +467,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) | |||
466 | nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, | 467 | nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, |
467 | argp->tname, &newfh); | 468 | argp->tname, &newfh); |
468 | 469 | ||
470 | kfree(argp->tname); | ||
469 | fh_put(&argp->ffh); | 471 | fh_put(&argp->ffh); |
470 | fh_put(&newfh); | 472 | fh_put(&newfh); |
471 | return nfserr; | 473 | return nfserr; |