1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com> |
4 | */ |
5 | #include <linux/sunrpc/svc.h> |
6 | #include <linux/nfs4.h> |
7 | |
8 | #include "nfsd.h" |
9 | #include "flexfilelayoutxdr.h" |
10 | |
11 | #define NFSDDBG_FACILITY NFSDDBG_PNFS |
12 | |
13 | struct ff_idmap { |
14 | char buf[11]; |
15 | int len; |
16 | }; |
17 | |
18 | __be32 |
19 | nfsd4_ff_encode_layoutget(struct xdr_stream *xdr, |
20 | const struct nfsd4_layoutget *lgp) |
21 | { |
22 | const struct pnfs_ff_layout *fl = lgp->lg_content; |
23 | int len, mirror_len, ds_len, fh_len; |
24 | __be32 *p; |
25 | |
26 | /* |
27 | * Unlike nfsd4_encode_user, we know these will |
28 | * always be stringified. |
29 | */ |
30 | struct ff_idmap uid; |
31 | struct ff_idmap gid; |
32 | |
33 | fh_len = 4 + fl->fh.size; |
34 | |
35 | uid.len = sprintf(buf: uid.buf, fmt: "%u" , from_kuid(to: &init_user_ns, uid: fl->uid)); |
36 | gid.len = sprintf(buf: gid.buf, fmt: "%u" , from_kgid(to: &init_user_ns, gid: fl->gid)); |
37 | |
38 | /* 8 + len for recording the length, name, and padding */ |
39 | ds_len = 20 + sizeof(stateid_opaque_t) + 4 + fh_len + |
40 | 8 + uid.len + 8 + gid.len; |
41 | |
42 | mirror_len = 4 + ds_len; |
43 | |
44 | /* The layout segment */ |
45 | len = 20 + mirror_len; |
46 | |
47 | p = xdr_reserve_space(xdr, nbytes: sizeof(__be32) + len); |
48 | if (!p) |
49 | return nfserr_toosmall; |
50 | |
51 | *p++ = cpu_to_be32(len); |
52 | p = xdr_encode_hyper(p, val: 0); /* stripe unit of 1 */ |
53 | |
54 | *p++ = cpu_to_be32(1); /* single mirror */ |
55 | *p++ = cpu_to_be32(1); /* single data server */ |
56 | |
57 | p = xdr_encode_opaque_fixed(p, ptr: &fl->deviceid, |
58 | len: sizeof(struct nfsd4_deviceid)); |
59 | |
60 | *p++ = cpu_to_be32(1); /* efficiency */ |
61 | |
62 | *p++ = cpu_to_be32(fl->stateid.si_generation); |
63 | p = xdr_encode_opaque_fixed(p, ptr: &fl->stateid.si_opaque, |
64 | len: sizeof(stateid_opaque_t)); |
65 | |
66 | *p++ = cpu_to_be32(1); /* single file handle */ |
67 | p = xdr_encode_opaque(p, ptr: fl->fh.data, len: fl->fh.size); |
68 | |
69 | p = xdr_encode_opaque(p, ptr: uid.buf, len: uid.len); |
70 | p = xdr_encode_opaque(p, ptr: gid.buf, len: gid.len); |
71 | |
72 | *p++ = cpu_to_be32(fl->flags); |
73 | *p++ = cpu_to_be32(0); /* No stats collect hint */ |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | __be32 |
79 | nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr, |
80 | const struct nfsd4_getdeviceinfo *gdp) |
81 | { |
82 | struct pnfs_ff_device_addr *da = gdp->gd_device; |
83 | int len; |
84 | int ver_len; |
85 | int addr_len; |
86 | __be32 *p; |
87 | |
88 | /* |
89 | * See paragraph 5 of RFC 8881 S18.40.3. |
90 | */ |
91 | if (!gdp->gd_maxcount) { |
92 | if (xdr_stream_encode_u32(xdr, n: 0) != XDR_UNIT) |
93 | return nfserr_resource; |
94 | return nfs_ok; |
95 | } |
96 | |
97 | /* len + padding for two strings */ |
98 | addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len; |
99 | ver_len = 20; |
100 | |
101 | len = 4 + ver_len + 4 + addr_len; |
102 | |
103 | p = xdr_reserve_space(xdr, nbytes: len + sizeof(__be32)); |
104 | if (!p) |
105 | return nfserr_resource; |
106 | |
107 | /* |
108 | * Fill in the overall length and number of volumes at the beginning |
109 | * of the layout. |
110 | */ |
111 | *p++ = cpu_to_be32(len); |
112 | *p++ = cpu_to_be32(1); /* 1 netaddr */ |
113 | p = xdr_encode_opaque(p, ptr: da->netaddr.netid, len: da->netaddr.netid_len); |
114 | p = xdr_encode_opaque(p, ptr: da->netaddr.addr, len: da->netaddr.addr_len); |
115 | |
116 | *p++ = cpu_to_be32(1); /* 1 versions */ |
117 | |
118 | *p++ = cpu_to_be32(da->version); |
119 | *p++ = cpu_to_be32(da->minor_version); |
120 | *p++ = cpu_to_be32(da->rsize); |
121 | *p++ = cpu_to_be32(da->wsize); |
122 | *p++ = cpu_to_be32(da->tightly_coupled); |
123 | |
124 | return 0; |
125 | } |
126 | |