Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFS: Add COPY nfs operation

This adds the copy_range file_ops function pointer used by the
sys_copy_range() function call. This patch only implements sync copies,
so if an async copy happens we decode the stateid and ignore it.

Signed-off-by: Anna Schumaker <bjschuma@netapp.com>

authored by

Anna Schumaker and committed by
Anna Schumaker
2e72448b 67911c8f

+305
+1
fs/nfs/nfs42.h
··· 13 13 14 14 /* nfs4.2proc.c */ 15 15 int nfs42_proc_allocate(struct file *, loff_t, loff_t); 16 + ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t); 16 17 int nfs42_proc_deallocate(struct file *, loff_t, loff_t); 17 18 loff_t nfs42_proc_llseek(struct file *, loff_t, int); 18 19 int nfs42_proc_layoutstats_generic(struct nfs_server *,
+105
fs/nfs/nfs42proc.c
··· 126 126 return err; 127 127 } 128 128 129 + static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src, 130 + struct nfs_lock_context *src_lock, 131 + struct file *dst, loff_t pos_dst, 132 + struct nfs_lock_context *dst_lock, 133 + size_t count) 134 + { 135 + struct nfs42_copy_args args = { 136 + .src_fh = NFS_FH(file_inode(src)), 137 + .src_pos = pos_src, 138 + .dst_fh = NFS_FH(file_inode(dst)), 139 + .dst_pos = pos_dst, 140 + .count = count, 141 + }; 142 + struct nfs42_copy_res res; 143 + struct rpc_message msg = { 144 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY], 145 + .rpc_argp = &args, 146 + .rpc_resp = &res, 147 + }; 148 + struct inode *dst_inode = file_inode(dst); 149 + struct nfs_server *server = NFS_SERVER(dst_inode); 150 + int status; 151 + 152 + status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context, 153 + src_lock, FMODE_READ); 154 + if (status) 155 + return status; 156 + 157 + status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context, 158 + dst_lock, FMODE_WRITE); 159 + if (status) 160 + return status; 161 + 162 + status = nfs4_call_sync(server->client, server, &msg, 163 + &args.seq_args, &res.seq_res, 0); 164 + if (status == -ENOTSUPP) 165 + server->caps &= ~NFS_CAP_COPY; 166 + if (status) 167 + return status; 168 + 169 + if (res.write_res.verifier.committed != NFS_FILE_SYNC) { 170 + status = nfs_commit_file(dst, &res.write_res.verifier.verifier); 171 + if (status) 172 + return status; 173 + } 174 + 175 + truncate_pagecache_range(dst_inode, pos_dst, 176 + pos_dst + res.write_res.count); 177 + 178 + return res.write_res.count; 179 + } 180 + 181 + ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src, 182 + struct file *dst, loff_t pos_dst, 183 + size_t count) 184 + { 185 + struct nfs_server *server = NFS_SERVER(file_inode(dst)); 186 + struct nfs_lock_context *src_lock; 187 + struct nfs_lock_context *dst_lock; 188 + struct nfs4_exception src_exception = { }; 189 + struct nfs4_exception dst_exception = { }; 190 + ssize_t err, err2; 191 + 192 + if (!nfs_server_capable(file_inode(dst), NFS_CAP_COPY)) 193 + return -EOPNOTSUPP; 194 + 195 + src_lock = nfs_get_lock_context(nfs_file_open_context(src)); 196 + if (IS_ERR(src_lock)) 197 + return PTR_ERR(src_lock); 198 + 199 + src_exception.inode = file_inode(src); 200 + src_exception.state = src_lock->open_context->state; 201 + 202 + dst_lock = nfs_get_lock_context(nfs_file_open_context(dst)); 203 + if (IS_ERR(dst_lock)) { 204 + err = PTR_ERR(dst_lock); 205 + goto out_put_src_lock; 206 + } 207 + 208 + dst_exception.inode = file_inode(dst); 209 + dst_exception.state = dst_lock->open_context->state; 210 + 211 + do { 212 + mutex_lock(&file_inode(dst)->i_mutex); 213 + err = _nfs42_proc_copy(src, pos_src, src_lock, 214 + dst, pos_dst, dst_lock, count); 215 + mutex_unlock(&file_inode(dst)->i_mutex); 216 + 217 + if (err == -ENOTSUPP) { 218 + err = -EOPNOTSUPP; 219 + break; 220 + } 221 + 222 + err2 = nfs4_handle_exception(server, err, &src_exception); 223 + err = nfs4_handle_exception(server, err, &dst_exception); 224 + if (!err) 225 + err = err2; 226 + } while (src_exception.retry || dst_exception.retry); 227 + 228 + nfs_put_lock_context(dst_lock); 229 + out_put_src_lock: 230 + nfs_put_lock_context(src_lock); 231 + return err; 232 + } 233 + 129 234 static loff_t _nfs42_proc_llseek(struct file *filep, 130 235 struct nfs_lock_context *lock, loff_t offset, int whence) 131 236 {
+146
fs/nfs/nfs42xdr.c
··· 9 9 #define encode_fallocate_maxsz (encode_stateid_maxsz + \ 10 10 2 /* offset */ + \ 11 11 2 /* length */) 12 + #define NFS42_WRITE_RES_SIZE (1 /* wr_callback_id size */ +\ 13 + XDR_QUADLEN(NFS4_STATEID_SIZE) + \ 14 + 2 /* wr_count */ + \ 15 + 1 /* wr_committed */ + \ 16 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) 12 17 #define encode_allocate_maxsz (op_encode_hdr_maxsz + \ 13 18 encode_fallocate_maxsz) 14 19 #define decode_allocate_maxsz (op_decode_hdr_maxsz) 20 + #define encode_copy_maxsz (op_encode_hdr_maxsz + \ 21 + XDR_QUADLEN(NFS4_STATEID_SIZE) + \ 22 + XDR_QUADLEN(NFS4_STATEID_SIZE) + \ 23 + 2 + 2 + 2 + 1 + 1 + 1) 24 + #define decode_copy_maxsz (op_decode_hdr_maxsz + \ 25 + NFS42_WRITE_RES_SIZE + \ 26 + 1 /* cr_consecutive */ + \ 27 + 1 /* cr_synchronous */) 15 28 #define encode_deallocate_maxsz (op_encode_hdr_maxsz + \ 16 29 encode_fallocate_maxsz) 17 30 #define decode_deallocate_maxsz (op_decode_hdr_maxsz) ··· 62 49 decode_putfh_maxsz + \ 63 50 decode_allocate_maxsz + \ 64 51 decode_getattr_maxsz) 52 + #define NFS4_enc_copy_sz (compound_encode_hdr_maxsz + \ 53 + encode_putfh_maxsz + \ 54 + encode_savefh_maxsz + \ 55 + encode_putfh_maxsz + \ 56 + encode_copy_maxsz) 57 + #define NFS4_dec_copy_sz (compound_decode_hdr_maxsz + \ 58 + decode_putfh_maxsz + \ 59 + decode_savefh_maxsz + \ 60 + decode_putfh_maxsz + \ 61 + decode_copy_maxsz) 65 62 #define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \ 66 63 encode_putfh_maxsz + \ 67 64 encode_deallocate_maxsz + \ ··· 123 100 { 124 101 encode_op_hdr(xdr, OP_ALLOCATE, decode_allocate_maxsz, hdr); 125 102 encode_fallocate(xdr, args); 103 + } 104 + 105 + static void encode_copy(struct xdr_stream *xdr, 106 + struct nfs42_copy_args *args, 107 + struct compound_hdr *hdr) 108 + { 109 + encode_op_hdr(xdr, OP_COPY, decode_copy_maxsz, hdr); 110 + encode_nfs4_stateid(xdr, &args->src_stateid); 111 + encode_nfs4_stateid(xdr, &args->dst_stateid); 112 + 113 + encode_uint64(xdr, args->src_pos); 114 + encode_uint64(xdr, args->dst_pos); 115 + encode_uint64(xdr, args->count); 116 + 117 + encode_uint32(xdr, 1); /* consecutive = true */ 118 + encode_uint32(xdr, 1); /* synchronous = true */ 119 + encode_uint32(xdr, 0); /* src server list */ 126 120 } 127 121 128 122 static void encode_deallocate(struct xdr_stream *xdr, ··· 218 178 encode_putfh(xdr, args->falloc_fh, &hdr); 219 179 encode_allocate(xdr, args, &hdr); 220 180 encode_getfattr(xdr, args->falloc_bitmask, &hdr); 181 + encode_nops(&hdr); 182 + } 183 + 184 + /* 185 + * Encode COPY request 186 + */ 187 + static void nfs4_xdr_enc_copy(struct rpc_rqst *req, 188 + struct xdr_stream *xdr, 189 + struct nfs42_copy_args *args) 190 + { 191 + struct compound_hdr hdr = { 192 + .minorversion = nfs4_xdr_minorversion(&args->seq_args), 193 + }; 194 + 195 + encode_compound_hdr(xdr, req, &hdr); 196 + encode_sequence(xdr, &args->seq_args, &hdr); 197 + encode_putfh(xdr, args->src_fh, &hdr); 198 + encode_savefh(xdr, &hdr); 199 + encode_putfh(xdr, args->dst_fh, &hdr); 200 + encode_copy(xdr, args, &hdr); 221 201 encode_nops(&hdr); 222 202 } 223 203 ··· 326 266 return decode_op_hdr(xdr, OP_ALLOCATE); 327 267 } 328 268 269 + static int decode_write_response(struct xdr_stream *xdr, 270 + struct nfs42_write_res *res) 271 + { 272 + __be32 *p; 273 + int stateids; 274 + 275 + p = xdr_inline_decode(xdr, 4 + 8 + 4); 276 + if (unlikely(!p)) 277 + goto out_overflow; 278 + 279 + stateids = be32_to_cpup(p++); 280 + p = xdr_decode_hyper(p, &res->count); 281 + res->verifier.committed = be32_to_cpup(p); 282 + return decode_verifier(xdr, &res->verifier.verifier); 283 + 284 + out_overflow: 285 + print_overflow_msg(__func__, xdr); 286 + return -EIO; 287 + } 288 + 289 + static int decode_copy_requirements(struct xdr_stream *xdr, 290 + struct nfs42_copy_res *res) { 291 + __be32 *p; 292 + 293 + p = xdr_inline_decode(xdr, 4 + 4); 294 + if (unlikely(!p)) 295 + goto out_overflow; 296 + 297 + res->consecutive = be32_to_cpup(p++); 298 + res->synchronous = be32_to_cpup(p++); 299 + return 0; 300 + out_overflow: 301 + print_overflow_msg(__func__, xdr); 302 + return -EIO; 303 + } 304 + 305 + static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res) 306 + { 307 + int status; 308 + 309 + status = decode_op_hdr(xdr, OP_COPY); 310 + if (status == NFS4ERR_OFFLOAD_NO_REQS) { 311 + status = decode_copy_requirements(xdr, res); 312 + if (status) 313 + return status; 314 + return NFS4ERR_OFFLOAD_NO_REQS; 315 + } else if (status) 316 + return status; 317 + 318 + status = decode_write_response(xdr, &res->write_res); 319 + if (status) 320 + return status; 321 + 322 + return decode_copy_requirements(xdr, res); 323 + } 324 + 329 325 static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) 330 326 { 331 327 return decode_op_hdr(xdr, OP_DEALLOCATE); ··· 442 326 if (status) 443 327 goto out; 444 328 decode_getfattr(xdr, res->falloc_fattr, res->falloc_server); 329 + out: 330 + return status; 331 + } 332 + 333 + /* 334 + * Decode COPY response 335 + */ 336 + static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp, 337 + struct xdr_stream *xdr, 338 + struct nfs42_copy_res *res) 339 + { 340 + struct compound_hdr hdr; 341 + int status; 342 + 343 + status = decode_compound_hdr(xdr, &hdr); 344 + if (status) 345 + goto out; 346 + status = decode_sequence(xdr, &res->seq_res, rqstp); 347 + if (status) 348 + goto out; 349 + status = decode_putfh(xdr); 350 + if (status) 351 + goto out; 352 + status = decode_savefh(xdr); 353 + if (status) 354 + goto out; 355 + status = decode_putfh(xdr); 356 + if (status) 357 + goto out; 358 + status = decode_copy(xdr, res); 445 359 out: 446 360 return status; 447 361 }
+23
fs/nfs/nfs4file.c
··· 129 129 } 130 130 131 131 #ifdef CONFIG_NFS_V4_2 132 + static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, 133 + struct file *file_out, loff_t pos_out, 134 + size_t count, unsigned int flags) 135 + { 136 + struct inode *in_inode = file_inode(file_in); 137 + struct inode *out_inode = file_inode(file_out); 138 + int ret; 139 + 140 + if (in_inode == out_inode) 141 + return -EINVAL; 142 + 143 + /* flush any pending writes */ 144 + ret = nfs_sync_inode(in_inode); 145 + if (ret) 146 + return ret; 147 + ret = nfs_sync_inode(out_inode); 148 + if (ret) 149 + return ret; 150 + 151 + return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count); 152 + } 153 + 132 154 static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) 133 155 { 134 156 loff_t ret; ··· 265 243 .check_flags = nfs_check_flags, 266 244 .setlease = simple_nosetlease, 267 245 #ifdef CONFIG_NFS_V4_2 246 + .copy_file_range = nfs4_copy_file_range, 268 247 .llseek = nfs4_file_llseek, 269 248 .fallocate = nfs42_fallocate, 270 249 .clone_file_range = nfs42_clone_file_range,
+1
fs/nfs/nfs4proc.c
··· 8797 8797 | NFS_CAP_STATEID_NFSV41 8798 8798 | NFS_CAP_ATOMIC_OPEN_V1 8799 8799 | NFS_CAP_ALLOCATE 8800 + | NFS_CAP_COPY 8800 8801 | NFS_CAP_DEALLOCATE 8801 8802 | NFS_CAP_SEEK 8802 8803 | NFS_CAP_LAYOUTSTATS
+1
fs/nfs/nfs4xdr.c
··· 7515 7515 PROC(DEALLOCATE, enc_deallocate, dec_deallocate), 7516 7516 PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats), 7517 7517 PROC(CLONE, enc_clone, dec_clone), 7518 + PROC(COPY, enc_copy, dec_copy), 7518 7519 #endif /* CONFIG_NFS_V4_2 */ 7519 7520 }; 7520 7521
+1
include/linux/nfs4.h
··· 504 504 NFSPROC4_CLNT_DEALLOCATE, 505 505 NFSPROC4_CLNT_LAYOUTSTATS, 506 506 NFSPROC4_CLNT_CLONE, 507 + NFSPROC4_CLNT_COPY, 507 508 }; 508 509 509 510 /* nfs41 types */
+1
include/linux/nfs_fs_sb.h
··· 246 246 #define NFS_CAP_DEALLOCATE (1U << 21) 247 247 #define NFS_CAP_LAYOUTSTATS (1U << 22) 248 248 #define NFS_CAP_CLONE (1U << 23) 249 + #define NFS_CAP_COPY (1U << 24) 249 250 250 251 #endif
+26
include/linux/nfs_xdr.h
··· 1343 1343 const struct nfs_server *falloc_server; 1344 1344 }; 1345 1345 1346 + struct nfs42_copy_args { 1347 + struct nfs4_sequence_args seq_args; 1348 + 1349 + struct nfs_fh *src_fh; 1350 + nfs4_stateid src_stateid; 1351 + u64 src_pos; 1352 + 1353 + struct nfs_fh *dst_fh; 1354 + nfs4_stateid dst_stateid; 1355 + u64 dst_pos; 1356 + 1357 + u64 count; 1358 + }; 1359 + 1360 + struct nfs42_write_res { 1361 + u64 count; 1362 + struct nfs_writeverf verifier; 1363 + }; 1364 + 1365 + struct nfs42_copy_res { 1366 + struct nfs4_sequence_res seq_res; 1367 + struct nfs42_write_res write_res; 1368 + bool consecutive; 1369 + bool synchronous; 1370 + }; 1371 + 1346 1372 struct nfs42_seek_args { 1347 1373 struct nfs4_sequence_args seq_args; 1348 1374