Skip to content

Commit 3e1f021

Browse files
fllindenTrond Myklebust
authored andcommitted
NFSv4.2: add client side XDR handling for extended attributes
Define the argument and response structures that will be used for RFC 8276 extended attribute RPC calls, and implement the necessary functions to encode/decode the extended attribute operations. Signed-off-by: Frank van der Linden <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent b78ef84 commit 3e1f021

File tree

3 files changed

+430
-3
lines changed

3 files changed

+430
-3
lines changed

fs/nfs/nfs42xdr.c

Lines changed: 366 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@
169169
decode_clone_maxsz + \
170170
decode_getattr_maxsz)
171171

172-
#ifdef CONFIG_NFS_V4_2
173172
/* Not limited by NFS itself, limited by the generic xattr code */
174173
#define nfs4_xattr_name_maxsz XDR_QUADLEN(XATTR_NAME_MAX)
175174

@@ -241,7 +240,6 @@ const u32 nfs42_maxlistxattrs_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
241240
compound_decode_hdr_maxsz +
242241
decode_sequence_maxsz +
243242
decode_putfh_maxsz + 3) * XDR_UNIT);
244-
#endif
245243

246244
static void encode_fallocate(struct xdr_stream *xdr,
247245
const struct nfs42_falloc_args *args)
@@ -407,6 +405,210 @@ static void encode_layouterror(struct xdr_stream *xdr,
407405
encode_device_error(xdr, &args->errors[0]);
408406
}
409407

408+
static void encode_setxattr(struct xdr_stream *xdr,
409+
const struct nfs42_setxattrargs *arg,
410+
struct compound_hdr *hdr)
411+
{
412+
__be32 *p;
413+
414+
BUILD_BUG_ON(XATTR_CREATE != SETXATTR4_CREATE);
415+
BUILD_BUG_ON(XATTR_REPLACE != SETXATTR4_REPLACE);
416+
417+
encode_op_hdr(xdr, OP_SETXATTR, decode_setxattr_maxsz, hdr);
418+
p = reserve_space(xdr, 4);
419+
*p = cpu_to_be32(arg->xattr_flags);
420+
encode_string(xdr, strlen(arg->xattr_name), arg->xattr_name);
421+
p = reserve_space(xdr, 4);
422+
*p = cpu_to_be32(arg->xattr_len);
423+
if (arg->xattr_len)
424+
xdr_write_pages(xdr, arg->xattr_pages, 0, arg->xattr_len);
425+
}
426+
427+
static int decode_setxattr(struct xdr_stream *xdr,
428+
struct nfs4_change_info *cinfo)
429+
{
430+
int status;
431+
432+
status = decode_op_hdr(xdr, OP_SETXATTR);
433+
if (status)
434+
goto out;
435+
status = decode_change_info(xdr, cinfo);
436+
out:
437+
return status;
438+
}
439+
440+
441+
static void encode_getxattr(struct xdr_stream *xdr, const char *name,
442+
struct compound_hdr *hdr)
443+
{
444+
encode_op_hdr(xdr, OP_GETXATTR, decode_getxattr_maxsz, hdr);
445+
encode_string(xdr, strlen(name), name);
446+
}
447+
448+
static int decode_getxattr(struct xdr_stream *xdr,
449+
struct nfs42_getxattrres *res,
450+
struct rpc_rqst *req)
451+
{
452+
int status;
453+
__be32 *p;
454+
u32 len, rdlen;
455+
456+
status = decode_op_hdr(xdr, OP_GETXATTR);
457+
if (status)
458+
return status;
459+
460+
p = xdr_inline_decode(xdr, 4);
461+
if (unlikely(!p))
462+
return -EIO;
463+
464+
len = be32_to_cpup(p);
465+
if (len > req->rq_rcv_buf.page_len)
466+
return -ERANGE;
467+
468+
res->xattr_len = len;
469+
470+
if (len > 0) {
471+
rdlen = xdr_read_pages(xdr, len);
472+
if (rdlen < len)
473+
return -EIO;
474+
}
475+
476+
return 0;
477+
}
478+
479+
static void encode_removexattr(struct xdr_stream *xdr, const char *name,
480+
struct compound_hdr *hdr)
481+
{
482+
encode_op_hdr(xdr, OP_REMOVEXATTR, decode_removexattr_maxsz, hdr);
483+
encode_string(xdr, strlen(name), name);
484+
}
485+
486+
487+
static int decode_removexattr(struct xdr_stream *xdr,
488+
struct nfs4_change_info *cinfo)
489+
{
490+
int status;
491+
492+
status = decode_op_hdr(xdr, OP_REMOVEXATTR);
493+
if (status)
494+
goto out;
495+
496+
status = decode_change_info(xdr, cinfo);
497+
out:
498+
return status;
499+
}
500+
501+
static void encode_listxattrs(struct xdr_stream *xdr,
502+
const struct nfs42_listxattrsargs *arg,
503+
struct compound_hdr *hdr)
504+
{
505+
__be32 *p;
506+
507+
encode_op_hdr(xdr, OP_LISTXATTRS, decode_listxattrs_maxsz + 1, hdr);
508+
509+
p = reserve_space(xdr, 12);
510+
if (unlikely(!p))
511+
return;
512+
513+
p = xdr_encode_hyper(p, arg->cookie);
514+
/*
515+
* RFC 8276 says to specify the full max length of the LISTXATTRS
516+
* XDR reply. Count is set to the XDR length of the names array
517+
* plus the EOF marker. So, add the cookie and the names count.
518+
*/
519+
*p = cpu_to_be32(arg->count + 8 + 4);
520+
}
521+
522+
static int decode_listxattrs(struct xdr_stream *xdr,
523+
struct nfs42_listxattrsres *res)
524+
{
525+
int status;
526+
__be32 *p;
527+
u32 count, len, ulen;
528+
size_t left, copied;
529+
char *buf;
530+
531+
status = decode_op_hdr(xdr, OP_LISTXATTRS);
532+
if (status) {
533+
/*
534+
* Special case: for LISTXATTRS, NFS4ERR_TOOSMALL
535+
* should be translated to ERANGE.
536+
*/
537+
if (status == -ETOOSMALL)
538+
status = -ERANGE;
539+
goto out;
540+
}
541+
542+
p = xdr_inline_decode(xdr, 8);
543+
if (unlikely(!p))
544+
return -EIO;
545+
546+
xdr_decode_hyper(p, &res->cookie);
547+
548+
p = xdr_inline_decode(xdr, 4);
549+
if (unlikely(!p))
550+
return -EIO;
551+
552+
left = res->xattr_len;
553+
buf = res->xattr_buf;
554+
555+
count = be32_to_cpup(p);
556+
copied = 0;
557+
558+
/*
559+
* We have asked for enough room to encode the maximum number
560+
* of possible attribute names, so everything should fit.
561+
*
562+
* But, don't rely on that assumption. Just decode entries
563+
* until they don't fit anymore, just in case the server did
564+
* something odd.
565+
*/
566+
while (count--) {
567+
p = xdr_inline_decode(xdr, 4);
568+
if (unlikely(!p))
569+
return -EIO;
570+
571+
len = be32_to_cpup(p);
572+
if (len > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) {
573+
status = -ERANGE;
574+
goto out;
575+
}
576+
577+
p = xdr_inline_decode(xdr, len);
578+
if (unlikely(!p))
579+
return -EIO;
580+
581+
ulen = len + XATTR_USER_PREFIX_LEN + 1;
582+
if (buf) {
583+
if (ulen > left) {
584+
status = -ERANGE;
585+
goto out;
586+
}
587+
588+
memcpy(buf, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
589+
memcpy(buf + XATTR_USER_PREFIX_LEN, p, len);
590+
591+
buf[ulen - 1] = 0;
592+
buf += ulen;
593+
left -= ulen;
594+
}
595+
copied += ulen;
596+
}
597+
598+
p = xdr_inline_decode(xdr, 4);
599+
if (unlikely(!p))
600+
return -EIO;
601+
602+
res->eof = be32_to_cpup(p);
603+
res->copied = copied;
604+
605+
out:
606+
if (status == -ERANGE && res->xattr_len == XATTR_LIST_MAX)
607+
status = -E2BIG;
608+
609+
return status;
610+
}
611+
410612
/*
411613
* Encode ALLOCATE request
412614
*/
@@ -1062,4 +1264,166 @@ static int nfs4_xdr_dec_layouterror(struct rpc_rqst *rqstp,
10621264
return status;
10631265
}
10641266

1267+
#ifdef CONFIG_NFS_V4_2
1268+
static void nfs4_xdr_enc_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr,
1269+
const void *data)
1270+
{
1271+
const struct nfs42_setxattrargs *args = data;
1272+
struct compound_hdr hdr = {
1273+
.minorversion = nfs4_xdr_minorversion(&args->seq_args),
1274+
};
1275+
1276+
encode_compound_hdr(xdr, req, &hdr);
1277+
encode_sequence(xdr, &args->seq_args, &hdr);
1278+
encode_putfh(xdr, args->fh, &hdr);
1279+
encode_setxattr(xdr, args, &hdr);
1280+
encode_nops(&hdr);
1281+
}
1282+
1283+
static int nfs4_xdr_dec_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr,
1284+
void *data)
1285+
{
1286+
struct nfs42_setxattrres *res = data;
1287+
struct compound_hdr hdr;
1288+
int status;
1289+
1290+
status = decode_compound_hdr(xdr, &hdr);
1291+
if (status)
1292+
goto out;
1293+
status = decode_sequence(xdr, &res->seq_res, req);
1294+
if (status)
1295+
goto out;
1296+
status = decode_putfh(xdr);
1297+
if (status)
1298+
goto out;
1299+
1300+
status = decode_setxattr(xdr, &res->cinfo);
1301+
out:
1302+
return status;
1303+
}
1304+
1305+
static void nfs4_xdr_enc_getxattr(struct rpc_rqst *req, struct xdr_stream *xdr,
1306+
const void *data)
1307+
{
1308+
const struct nfs42_getxattrargs *args = data;
1309+
struct compound_hdr hdr = {
1310+
.minorversion = nfs4_xdr_minorversion(&args->seq_args),
1311+
};
1312+
size_t plen;
1313+
1314+
encode_compound_hdr(xdr, req, &hdr);
1315+
encode_sequence(xdr, &args->seq_args, &hdr);
1316+
encode_putfh(xdr, args->fh, &hdr);
1317+
encode_getxattr(xdr, args->xattr_name, &hdr);
1318+
1319+
plen = args->xattr_len ? args->xattr_len : XATTR_SIZE_MAX;
1320+
1321+
rpc_prepare_reply_pages(req, args->xattr_pages, 0, plen,
1322+
hdr.replen);
1323+
req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
1324+
1325+
encode_nops(&hdr);
1326+
}
1327+
1328+
static int nfs4_xdr_dec_getxattr(struct rpc_rqst *rqstp,
1329+
struct xdr_stream *xdr, void *data)
1330+
{
1331+
struct nfs42_getxattrres *res = data;
1332+
struct compound_hdr hdr;
1333+
int status;
1334+
1335+
status = decode_compound_hdr(xdr, &hdr);
1336+
if (status)
1337+
goto out;
1338+
status = decode_sequence(xdr, &res->seq_res, rqstp);
1339+
if (status)
1340+
goto out;
1341+
status = decode_putfh(xdr);
1342+
if (status)
1343+
goto out;
1344+
status = decode_getxattr(xdr, res, rqstp);
1345+
out:
1346+
return status;
1347+
}
1348+
1349+
static void nfs4_xdr_enc_listxattrs(struct rpc_rqst *req,
1350+
struct xdr_stream *xdr, const void *data)
1351+
{
1352+
const struct nfs42_listxattrsargs *args = data;
1353+
struct compound_hdr hdr = {
1354+
.minorversion = nfs4_xdr_minorversion(&args->seq_args),
1355+
};
1356+
1357+
encode_compound_hdr(xdr, req, &hdr);
1358+
encode_sequence(xdr, &args->seq_args, &hdr);
1359+
encode_putfh(xdr, args->fh, &hdr);
1360+
encode_listxattrs(xdr, args, &hdr);
1361+
1362+
rpc_prepare_reply_pages(req, args->xattr_pages, 0, args->count,
1363+
hdr.replen);
1364+
req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
1365+
1366+
encode_nops(&hdr);
1367+
}
1368+
1369+
static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp,
1370+
struct xdr_stream *xdr, void *data)
1371+
{
1372+
struct nfs42_listxattrsres *res = data;
1373+
struct compound_hdr hdr;
1374+
int status;
1375+
1376+
xdr_set_scratch_buffer(xdr, page_address(res->scratch), PAGE_SIZE);
1377+
1378+
status = decode_compound_hdr(xdr, &hdr);
1379+
if (status)
1380+
goto out;
1381+
status = decode_sequence(xdr, &res->seq_res, rqstp);
1382+
if (status)
1383+
goto out;
1384+
status = decode_putfh(xdr);
1385+
if (status)
1386+
goto out;
1387+
status = decode_listxattrs(xdr, res);
1388+
out:
1389+
return status;
1390+
}
1391+
1392+
static void nfs4_xdr_enc_removexattr(struct rpc_rqst *req,
1393+
struct xdr_stream *xdr, const void *data)
1394+
{
1395+
const struct nfs42_removexattrargs *args = data;
1396+
struct compound_hdr hdr = {
1397+
.minorversion = nfs4_xdr_minorversion(&args->seq_args),
1398+
};
1399+
1400+
encode_compound_hdr(xdr, req, &hdr);
1401+
encode_sequence(xdr, &args->seq_args, &hdr);
1402+
encode_putfh(xdr, args->fh, &hdr);
1403+
encode_removexattr(xdr, args->xattr_name, &hdr);
1404+
encode_nops(&hdr);
1405+
}
1406+
1407+
static int nfs4_xdr_dec_removexattr(struct rpc_rqst *req,
1408+
struct xdr_stream *xdr, void *data)
1409+
{
1410+
struct nfs42_removexattrres *res = data;
1411+
struct compound_hdr hdr;
1412+
int status;
1413+
1414+
status = decode_compound_hdr(xdr, &hdr);
1415+
if (status)
1416+
goto out;
1417+
status = decode_sequence(xdr, &res->seq_res, req);
1418+
if (status)
1419+
goto out;
1420+
status = decode_putfh(xdr);
1421+
if (status)
1422+
goto out;
1423+
1424+
status = decode_removexattr(xdr, &res->cinfo);
1425+
out:
1426+
return status;
1427+
}
1428+
#endif
10651429
#endif /* __LINUX_FS_NFS_NFS4_2XDR_H */

0 commit comments

Comments
 (0)