Skip to content

Commit 0491567

Browse files
olgakorn1Olga Kornievskaia
authored andcommitted
NFS: add COPY_NOTIFY operation
Try using the delegation stateid, then the open stateid. Only NL4_NETATTR, No support for NL4_NAME and NL4_URL. Allow only one source server address to be returned for now. To distinguish between same server copy offload ("intra") and a copy between different server ("inter"), do a check of server owner identity and also make sure server is capable of doing a copy offload. Signed-off-by: Andy Adamson <[email protected]> Signed-off-by: Olga Kornievskaia <[email protected]>
1 parent f9bdad8 commit 0491567

File tree

11 files changed

+323
-2
lines changed

11 files changed

+323
-2
lines changed

fs/nfs/nfs42.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define PNFS_LAYOUTSTATS_MAXDEV (4)
1414

1515
/* nfs4.2proc.c */
16+
#ifdef CONFIG_NFS_V4_2
1617
int nfs42_proc_allocate(struct file *, loff_t, loff_t);
1718
ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t);
1819
int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
@@ -23,5 +24,16 @@ int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t);
2324
int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
2425
const struct nfs42_layout_error *errors,
2526
size_t n);
27+
int nfs42_proc_copy_notify(struct file *, struct file *,
28+
struct nfs42_copy_notify_res *);
29+
static inline bool nfs42_files_from_same_server(struct file *in,
30+
struct file *out)
31+
{
32+
struct nfs_client *c_in = (NFS_SERVER(file_inode(in)))->nfs_client;
33+
struct nfs_client *c_out = (NFS_SERVER(file_inode(out)))->nfs_client;
2634

35+
return nfs4_check_serverowner_major_id(c_in->cl_serverowner,
36+
c_out->cl_serverowner);
37+
}
38+
#endif /* CONFIG_NFS_V4_2 */
2739
#endif /* __LINUX_FS_NFS_NFS4_2_H */

fs/nfs/nfs42proc.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (c) 2014 Anna Schumaker <[email protected]>
44
*/
55
#include <linux/fs.h>
6+
#include <linux/sunrpc/addr.h>
67
#include <linux/sunrpc/sched.h>
78
#include <linux/nfs.h>
89
#include <linux/nfs3.h>
@@ -15,10 +16,30 @@
1516
#include "pnfs.h"
1617
#include "nfs4session.h"
1718
#include "internal.h"
19+
#include "delegation.h"
1820

1921
#define NFSDBG_FACILITY NFSDBG_PROC
2022
static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
2123

24+
static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr)
25+
{
26+
struct nfs_client *clp = (NFS_SERVER(file_inode(filep)))->nfs_client;
27+
unsigned short port = 2049;
28+
29+
rcu_read_lock();
30+
naddr->netid_len = scnprintf(naddr->netid,
31+
sizeof(naddr->netid), "%s",
32+
rpc_peeraddr2str(clp->cl_rpcclient,
33+
RPC_DISPLAY_NETID));
34+
naddr->addr_len = scnprintf(naddr->addr,
35+
sizeof(naddr->addr),
36+
"%s.%u.%u",
37+
rpc_peeraddr2str(clp->cl_rpcclient,
38+
RPC_DISPLAY_ADDR),
39+
port >> 8, port & 255);
40+
rcu_read_unlock();
41+
}
42+
2243
static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
2344
struct nfs_lock_context *lock, loff_t offset, loff_t len)
2445
{
@@ -459,6 +480,76 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
459480
return status;
460481
}
461482

483+
int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
484+
struct nfs42_copy_notify_args *args,
485+
struct nfs42_copy_notify_res *res)
486+
{
487+
struct nfs_server *src_server = NFS_SERVER(file_inode(src));
488+
struct rpc_message msg = {
489+
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY],
490+
.rpc_argp = args,
491+
.rpc_resp = res,
492+
};
493+
int status;
494+
struct nfs_open_context *ctx;
495+
struct nfs_lock_context *l_ctx;
496+
497+
ctx = get_nfs_open_context(nfs_file_open_context(src));
498+
l_ctx = nfs_get_lock_context(ctx);
499+
if (IS_ERR(l_ctx))
500+
return PTR_ERR(l_ctx);
501+
502+
status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
503+
FMODE_READ);
504+
nfs_put_lock_context(l_ctx);
505+
if (status)
506+
return status;
507+
508+
status = nfs4_call_sync(src_server->client, src_server, &msg,
509+
&args->cna_seq_args, &res->cnr_seq_res, 0);
510+
if (status == -ENOTSUPP)
511+
src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
512+
513+
put_nfs_open_context(nfs_file_open_context(src));
514+
return status;
515+
}
516+
517+
int nfs42_proc_copy_notify(struct file *src, struct file *dst,
518+
struct nfs42_copy_notify_res *res)
519+
{
520+
struct nfs_server *src_server = NFS_SERVER(file_inode(src));
521+
struct nfs42_copy_notify_args *args;
522+
struct nfs4_exception exception = {
523+
.inode = file_inode(src),
524+
};
525+
int status;
526+
527+
if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
528+
return -EOPNOTSUPP;
529+
530+
args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS);
531+
if (args == NULL)
532+
return -ENOMEM;
533+
534+
args->cna_src_fh = NFS_FH(file_inode(src)),
535+
args->cna_dst.nl4_type = NL4_NETADDR;
536+
nfs42_set_netaddr(dst, &args->cna_dst.u.nl4_addr);
537+
exception.stateid = &args->cna_src_stateid;
538+
539+
do {
540+
status = _nfs42_proc_copy_notify(src, dst, args, res);
541+
if (status == -ENOTSUPP) {
542+
status = -EOPNOTSUPP;
543+
goto out;
544+
}
545+
status = nfs4_handle_exception(src_server, status, &exception);
546+
} while (exception.retry);
547+
548+
out:
549+
kfree(args);
550+
return status;
551+
}
552+
462553
static loff_t _nfs42_proc_llseek(struct file *filep,
463554
struct nfs_lock_context *lock, loff_t offset, int whence)
464555
{

fs/nfs/nfs42xdr.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929
#define encode_offload_cancel_maxsz (op_encode_hdr_maxsz + \
3030
XDR_QUADLEN(NFS4_STATEID_SIZE))
3131
#define decode_offload_cancel_maxsz (op_decode_hdr_maxsz)
32+
#define encode_copy_notify_maxsz (op_encode_hdr_maxsz + \
33+
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
34+
1 + /* nl4_type */ \
35+
1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
36+
#define decode_copy_notify_maxsz (op_decode_hdr_maxsz + \
37+
3 + /* cnr_lease_time */\
38+
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
39+
1 + /* Support 1 cnr_source_server */\
40+
1 + /* nl4_type */ \
41+
1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
3242
#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
3343
encode_fallocate_maxsz)
3444
#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
@@ -99,6 +109,12 @@
99109
decode_sequence_maxsz + \
100110
decode_putfh_maxsz + \
101111
decode_offload_cancel_maxsz)
112+
#define NFS4_enc_copy_notify_sz (compound_encode_hdr_maxsz + \
113+
encode_putfh_maxsz + \
114+
encode_copy_notify_maxsz)
115+
#define NFS4_dec_copy_notify_sz (compound_decode_hdr_maxsz + \
116+
decode_putfh_maxsz + \
117+
decode_copy_notify_maxsz)
102118
#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
103119
encode_sequence_maxsz + \
104120
encode_putfh_maxsz + \
@@ -166,6 +182,26 @@ static void encode_allocate(struct xdr_stream *xdr,
166182
encode_fallocate(xdr, args);
167183
}
168184

185+
static void encode_nl4_server(struct xdr_stream *xdr,
186+
const struct nl4_server *ns)
187+
{
188+
encode_uint32(xdr, ns->nl4_type);
189+
switch (ns->nl4_type) {
190+
case NL4_NAME:
191+
case NL4_URL:
192+
encode_string(xdr, ns->u.nl4_str_sz, ns->u.nl4_str);
193+
break;
194+
case NL4_NETADDR:
195+
encode_string(xdr, ns->u.nl4_addr.netid_len,
196+
ns->u.nl4_addr.netid);
197+
encode_string(xdr, ns->u.nl4_addr.addr_len,
198+
ns->u.nl4_addr.addr);
199+
break;
200+
default:
201+
WARN_ON_ONCE(1);
202+
}
203+
}
204+
169205
static void encode_copy(struct xdr_stream *xdr,
170206
const struct nfs42_copy_args *args,
171207
struct compound_hdr *hdr)
@@ -191,6 +227,15 @@ static void encode_offload_cancel(struct xdr_stream *xdr,
191227
encode_nfs4_stateid(xdr, &args->osa_stateid);
192228
}
193229

230+
static void encode_copy_notify(struct xdr_stream *xdr,
231+
const struct nfs42_copy_notify_args *args,
232+
struct compound_hdr *hdr)
233+
{
234+
encode_op_hdr(xdr, OP_COPY_NOTIFY, decode_copy_notify_maxsz, hdr);
235+
encode_nfs4_stateid(xdr, &args->cna_src_stateid);
236+
encode_nl4_server(xdr, &args->cna_dst);
237+
}
238+
194239
static void encode_deallocate(struct xdr_stream *xdr,
195240
const struct nfs42_falloc_args *args,
196241
struct compound_hdr *hdr)
@@ -354,6 +399,25 @@ static void nfs4_xdr_enc_offload_cancel(struct rpc_rqst *req,
354399
encode_nops(&hdr);
355400
}
356401

402+
/*
403+
* Encode COPY_NOTIFY request
404+
*/
405+
static void nfs4_xdr_enc_copy_notify(struct rpc_rqst *req,
406+
struct xdr_stream *xdr,
407+
const void *data)
408+
{
409+
const struct nfs42_copy_notify_args *args = data;
410+
struct compound_hdr hdr = {
411+
.minorversion = nfs4_xdr_minorversion(&args->cna_seq_args),
412+
};
413+
414+
encode_compound_hdr(xdr, req, &hdr);
415+
encode_sequence(xdr, &args->cna_seq_args, &hdr);
416+
encode_putfh(xdr, args->cna_src_fh, &hdr);
417+
encode_copy_notify(xdr, args, &hdr);
418+
encode_nops(&hdr);
419+
}
420+
357421
/*
358422
* Encode DEALLOCATE request
359423
*/
@@ -490,6 +554,58 @@ static int decode_write_response(struct xdr_stream *xdr,
490554
return decode_verifier(xdr, &res->verifier.verifier);
491555
}
492556

557+
static int decode_nl4_server(struct xdr_stream *xdr, struct nl4_server *ns)
558+
{
559+
struct nfs42_netaddr *naddr;
560+
uint32_t dummy;
561+
char *dummy_str;
562+
__be32 *p;
563+
int status;
564+
565+
/* nl_type */
566+
p = xdr_inline_decode(xdr, 4);
567+
if (unlikely(!p))
568+
return -EIO;
569+
ns->nl4_type = be32_to_cpup(p);
570+
switch (ns->nl4_type) {
571+
case NL4_NAME:
572+
case NL4_URL:
573+
status = decode_opaque_inline(xdr, &dummy, &dummy_str);
574+
if (unlikely(status))
575+
return status;
576+
if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
577+
return -EIO;
578+
memcpy(&ns->u.nl4_str, dummy_str, dummy);
579+
ns->u.nl4_str_sz = dummy;
580+
break;
581+
case NL4_NETADDR:
582+
naddr = &ns->u.nl4_addr;
583+
584+
/* netid string */
585+
status = decode_opaque_inline(xdr, &dummy, &dummy_str);
586+
if (unlikely(status))
587+
return status;
588+
if (unlikely(dummy > RPCBIND_MAXNETIDLEN))
589+
return -EIO;
590+
naddr->netid_len = dummy;
591+
memcpy(naddr->netid, dummy_str, naddr->netid_len);
592+
593+
/* uaddr string */
594+
status = decode_opaque_inline(xdr, &dummy, &dummy_str);
595+
if (unlikely(status))
596+
return status;
597+
if (unlikely(dummy > RPCBIND_MAXUADDRLEN))
598+
return -EIO;
599+
naddr->addr_len = dummy;
600+
memcpy(naddr->addr, dummy_str, naddr->addr_len);
601+
break;
602+
default:
603+
WARN_ON_ONCE(1);
604+
return -EIO;
605+
}
606+
return 0;
607+
}
608+
493609
static int decode_copy_requirements(struct xdr_stream *xdr,
494610
struct nfs42_copy_res *res) {
495611
__be32 *p;
@@ -529,6 +645,42 @@ static int decode_offload_cancel(struct xdr_stream *xdr,
529645
return decode_op_hdr(xdr, OP_OFFLOAD_CANCEL);
530646
}
531647

648+
static int decode_copy_notify(struct xdr_stream *xdr,
649+
struct nfs42_copy_notify_res *res)
650+
{
651+
__be32 *p;
652+
int status, count;
653+
654+
status = decode_op_hdr(xdr, OP_COPY_NOTIFY);
655+
if (status)
656+
return status;
657+
/* cnr_lease_time */
658+
p = xdr_inline_decode(xdr, 12);
659+
if (unlikely(!p))
660+
return -EIO;
661+
p = xdr_decode_hyper(p, &res->cnr_lease_time.seconds);
662+
res->cnr_lease_time.nseconds = be32_to_cpup(p);
663+
664+
status = decode_opaque_fixed(xdr, &res->cnr_stateid, NFS4_STATEID_SIZE);
665+
if (unlikely(status))
666+
return -EIO;
667+
668+
/* number of source addresses */
669+
p = xdr_inline_decode(xdr, 4);
670+
if (unlikely(!p))
671+
return -EIO;
672+
673+
count = be32_to_cpup(p);
674+
if (count > 1)
675+
pr_warn("NFS: %s: nsvr %d > Supported. Use first servers\n",
676+
__func__, count);
677+
678+
status = decode_nl4_server(xdr, &res->cnr_src);
679+
if (unlikely(status))
680+
return -EIO;
681+
return 0;
682+
}
683+
532684
static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
533685
{
534686
return decode_op_hdr(xdr, OP_DEALLOCATE);
@@ -656,6 +808,32 @@ static int nfs4_xdr_dec_offload_cancel(struct rpc_rqst *rqstp,
656808
return status;
657809
}
658810

811+
/*
812+
* Decode COPY_NOTIFY response
813+
*/
814+
static int nfs4_xdr_dec_copy_notify(struct rpc_rqst *rqstp,
815+
struct xdr_stream *xdr,
816+
void *data)
817+
{
818+
struct nfs42_copy_notify_res *res = data;
819+
struct compound_hdr hdr;
820+
int status;
821+
822+
status = decode_compound_hdr(xdr, &hdr);
823+
if (status)
824+
goto out;
825+
status = decode_sequence(xdr, &res->cnr_seq_res, rqstp);
826+
if (status)
827+
goto out;
828+
status = decode_putfh(xdr);
829+
if (status)
830+
goto out;
831+
status = decode_copy_notify(xdr, res);
832+
833+
out:
834+
return status;
835+
}
836+
659837
/*
660838
* Decode DEALLOCATE request
661839
*/

fs/nfs/nfs4_fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
457457
struct nfs_client **, const struct cred *);
458458
extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
459459
extern void nfs41_notify_server(struct nfs_client *);
460+
bool nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
461+
struct nfs41_server_owner *o2);
460462
#else
461463
static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
462464
{

fs/nfs/nfs4client.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
629629
/*
630630
* Returns true if the server major ids match
631631
*/
632-
static bool
632+
bool
633633
nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
634634
struct nfs41_server_owner *o2)
635635
{

0 commit comments

Comments
 (0)