diff options
author | Christoph Hellwig <hch@lst.de> | 2015-12-03 06:59:52 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-07 23:12:00 -0500 |
commit | ffa0160a103917defd5d9c097ae0455a59166e03 (patch) | |
tree | fd4eeefca064c0a072e214fde0262fe8dbbff8a4 /fs/nfsd | |
parent | aa0d6aed45ff48bd41439211f2bda1d54585aba3 (diff) |
nfsd: implement the NFSv4.2 CLONE operation
This is basically a remote version of the btrfs CLONE operation,
so the implementation is fairly trivial. Made even more trivial
by stealing the XDR code and general framework Anna Schumaker's
COPY prototype.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: J. Bruce Fields <bfields@fieldses.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 47 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 21 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 8 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 2 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 10 |
5 files changed, 88 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3ba10a3534f1..819ad812c71b 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -1012,6 +1012,47 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1012 | } | 1012 | } |
1013 | 1013 | ||
1014 | static __be32 | 1014 | static __be32 |
1015 | nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
1016 | struct nfsd4_clone *clone) | ||
1017 | { | ||
1018 | struct file *src, *dst; | ||
1019 | __be32 status; | ||
1020 | |||
1021 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh, | ||
1022 | &clone->cl_src_stateid, RD_STATE, | ||
1023 | &src, NULL); | ||
1024 | if (status) { | ||
1025 | dprintk("NFSD: %s: couldn't process src stateid!\n", __func__); | ||
1026 | goto out; | ||
1027 | } | ||
1028 | |||
1029 | status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, | ||
1030 | &clone->cl_dst_stateid, WR_STATE, | ||
1031 | &dst, NULL); | ||
1032 | if (status) { | ||
1033 | dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__); | ||
1034 | goto out_put_src; | ||
1035 | } | ||
1036 | |||
1037 | /* fix up for NFS-specific error code */ | ||
1038 | if (!S_ISREG(file_inode(src)->i_mode) || | ||
1039 | !S_ISREG(file_inode(dst)->i_mode)) { | ||
1040 | status = nfserr_wrong_type; | ||
1041 | goto out_put_dst; | ||
1042 | } | ||
1043 | |||
1044 | status = nfsd4_clone_file_range(src, clone->cl_src_pos, | ||
1045 | dst, clone->cl_dst_pos, clone->cl_count); | ||
1046 | |||
1047 | out_put_dst: | ||
1048 | fput(dst); | ||
1049 | out_put_src: | ||
1050 | fput(src); | ||
1051 | out: | ||
1052 | return status; | ||
1053 | } | ||
1054 | |||
1055 | static __be32 | ||
1015 | nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1056 | nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1016 | struct nfsd4_fallocate *fallocate, int flags) | 1057 | struct nfsd4_fallocate *fallocate, int flags) |
1017 | { | 1058 | { |
@@ -2281,6 +2322,12 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
2281 | .op_name = "OP_DEALLOCATE", | 2322 | .op_name = "OP_DEALLOCATE", |
2282 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 2323 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
2283 | }, | 2324 | }, |
2325 | [OP_CLONE] = { | ||
2326 | .op_func = (nfsd4op_func)nfsd4_clone, | ||
2327 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | ||
2328 | .op_name = "OP_CLONE", | ||
2329 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
2330 | }, | ||
2284 | [OP_SEEK] = { | 2331 | [OP_SEEK] = { |
2285 | .op_func = (nfsd4op_func)nfsd4_seek, | 2332 | .op_func = (nfsd4op_func)nfsd4_seek, |
2286 | .op_name = "OP_SEEK", | 2333 | .op_name = "OP_SEEK", |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 51c9e9ca39a4..924416f91fdd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1675,6 +1675,25 @@ nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, | |||
1675 | } | 1675 | } |
1676 | 1676 | ||
1677 | static __be32 | 1677 | static __be32 |
1678 | nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone) | ||
1679 | { | ||
1680 | DECODE_HEAD; | ||
1681 | |||
1682 | status = nfsd4_decode_stateid(argp, &clone->cl_src_stateid); | ||
1683 | if (status) | ||
1684 | return status; | ||
1685 | status = nfsd4_decode_stateid(argp, &clone->cl_dst_stateid); | ||
1686 | if (status) | ||
1687 | return status; | ||
1688 | |||
1689 | READ_BUF(8 + 8 + 8); | ||
1690 | p = xdr_decode_hyper(p, &clone->cl_src_pos); | ||
1691 | p = xdr_decode_hyper(p, &clone->cl_dst_pos); | ||
1692 | p = xdr_decode_hyper(p, &clone->cl_count); | ||
1693 | DECODE_TAIL; | ||
1694 | } | ||
1695 | |||
1696 | static __be32 | ||
1678 | nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) | 1697 | nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) |
1679 | { | 1698 | { |
1680 | DECODE_HEAD; | 1699 | DECODE_HEAD; |
@@ -1785,6 +1804,7 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1785 | [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, | 1804 | [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, |
1786 | [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, | 1805 | [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, |
1787 | [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, | 1806 | [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, |
1807 | [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone, | ||
1788 | }; | 1808 | }; |
1789 | 1809 | ||
1790 | static inline bool | 1810 | static inline bool |
@@ -4292,6 +4312,7 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
4292 | [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, | 4312 | [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, |
4293 | [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, | 4313 | [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, |
4294 | [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, | 4314 | [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, |
4315 | [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop, | ||
4295 | }; | 4316 | }; |
4296 | 4317 | ||
4297 | /* | 4318 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 994d66fbb446..5411bf09b810 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #endif /* CONFIG_NFSD_V3 */ | 36 | #endif /* CONFIG_NFSD_V3 */ |
37 | 37 | ||
38 | #ifdef CONFIG_NFSD_V4 | 38 | #ifdef CONFIG_NFSD_V4 |
39 | #include "../internal.h" | ||
39 | #include "acl.h" | 40 | #include "acl.h" |
40 | #include "idmap.h" | 41 | #include "idmap.h" |
41 | #endif /* CONFIG_NFSD_V4 */ | 42 | #endif /* CONFIG_NFSD_V4 */ |
@@ -498,6 +499,13 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
498 | } | 499 | } |
499 | #endif | 500 | #endif |
500 | 501 | ||
502 | __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst, | ||
503 | u64 dst_pos, u64 count) | ||
504 | { | ||
505 | return nfserrno(vfs_clone_file_range(src, src_pos, dst, dst_pos, | ||
506 | count)); | ||
507 | } | ||
508 | |||
501 | __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp, | 509 | __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp, |
502 | struct file *file, loff_t offset, loff_t len, | 510 | struct file *file, loff_t offset, loff_t len, |
503 | int flags) | 511 | int flags) |
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index fcfc48cbe136..c11ba316f23f 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -56,6 +56,8 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, | |||
56 | struct xdr_netobj *); | 56 | struct xdr_netobj *); |
57 | __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *, | 57 | __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *, |
58 | struct file *, loff_t, loff_t, int); | 58 | struct file *, loff_t, loff_t, int); |
59 | __be32 nfsd4_clone_file_range(struct file *, u64, struct file *, | ||
60 | u64, u64); | ||
59 | #endif /* CONFIG_NFSD_V4 */ | 61 | #endif /* CONFIG_NFSD_V4 */ |
60 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, | 62 | __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, |
61 | char *name, int len, struct iattr *attrs, | 63 | char *name, int len, struct iattr *attrs, |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index ce7362c88b48..d9554813e58a 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -491,6 +491,15 @@ struct nfsd4_fallocate { | |||
491 | u64 falloc_length; | 491 | u64 falloc_length; |
492 | }; | 492 | }; |
493 | 493 | ||
494 | struct nfsd4_clone { | ||
495 | /* request */ | ||
496 | stateid_t cl_src_stateid; | ||
497 | stateid_t cl_dst_stateid; | ||
498 | u64 cl_src_pos; | ||
499 | u64 cl_dst_pos; | ||
500 | u64 cl_count; | ||
501 | }; | ||
502 | |||
494 | struct nfsd4_seek { | 503 | struct nfsd4_seek { |
495 | /* request */ | 504 | /* request */ |
496 | stateid_t seek_stateid; | 505 | stateid_t seek_stateid; |
@@ -555,6 +564,7 @@ struct nfsd4_op { | |||
555 | /* NFSv4.2 */ | 564 | /* NFSv4.2 */ |
556 | struct nfsd4_fallocate allocate; | 565 | struct nfsd4_fallocate allocate; |
557 | struct nfsd4_fallocate deallocate; | 566 | struct nfsd4_fallocate deallocate; |
567 | struct nfsd4_clone clone; | ||
558 | struct nfsd4_seek seek; | 568 | struct nfsd4_seek seek; |
559 | } u; | 569 | } u; |
560 | struct nfs4_replay * replay; | 570 | struct nfs4_replay * replay; |