History

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.

Frank van der Linden committed 6 years ago

Commit 3e1f0211 parent b78ef843 files · +430 −3Browse files

Unified · Split

3 files
  1. fs/nfs/nfs42xdr.c +366 −2
  2. fs/nfs/nfs4xdr.c +6 −0
  3. include/linux/nfs_xdr.h +58 −1
fs/nfs/nfs42xdr.c+366−2
@@ -169,7 +169,6 @@ · 168 unmodified lines
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 + · 65 unmodified lines
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, · 159 unmodified lines
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 @@ out: · 649 unmodified lines
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 */
fs/nfs/nfs4xdr.c+6−0
@@ -7481,6 +7481,8 @@ static struct { · 7480 unmodified lines
74817481 { NFS4ERR_SYMLINK, -ELOOP },
74827482 { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP },
74837483 { NFS4ERR_DEADLOCK, -EDEADLK },
7484+ { NFS4ERR_NOXATTR, -ENODATA },
7485+ { NFS4ERR_XATTR2BIG, -E2BIG },
74847486 { -1, -EIO }
74857487 };
74867488
@@ -7609,6 +7611,10 @@ const struct rpc_procinfo nfs4_procedures[] = { · 122 unmodified lines
76097611 PROC42(COPY_NOTIFY, enc_copy_notify, dec_copy_notify),
76107612 PROC(LOOKUPP, enc_lookupp, dec_lookupp),
76117613 PROC42(LAYOUTERROR, enc_layouterror, dec_layouterror),
7614+ PROC42(GETXATTR, enc_getxattr, dec_getxattr),
7615+ PROC42(SETXATTR, enc_setxattr, dec_setxattr),
7616+ PROC42(LISTXATTRS, enc_listxattrs, dec_listxattrs),
7617+ PROC42(REMOVEXATTR, enc_removexattr, dec_removexattr),
76127618 };
76137619
76147620 static unsigned int nfs_version4_counts[ARRAY_SIZE(nfs4_procedures)];
include/linux/nfs_xdr.h+58−1
@@ -1498,7 +1498,64 @@ struct nfs42_seek_res { · 1497 unmodified lines
14981498 u32 sr_eof;
14991499 u64 sr_offset;
15001500 };
1501−#endif
1501+
1502+struct nfs42_setxattrargs {
1503+ struct nfs4_sequence_args seq_args;
1504+ struct nfs_fh *fh;
1505+ const char *xattr_name;
1506+ u32 xattr_flags;
1507+ size_t xattr_len;
1508+ struct page **xattr_pages;
1509+};
1510+
1511+struct nfs42_setxattrres {
1512+ struct nfs4_sequence_res seq_res;
1513+ struct nfs4_change_info cinfo;
1514+};
1515+
1516+struct nfs42_getxattrargs {
1517+ struct nfs4_sequence_args seq_args;
1518+ struct nfs_fh *fh;
1519+ const char *xattr_name;
1520+ size_t xattr_len;
1521+ struct page **xattr_pages;
1522+};
1523+
1524+struct nfs42_getxattrres {
1525+ struct nfs4_sequence_res seq_res;
1526+ size_t xattr_len;
1527+};
1528+
1529+struct nfs42_listxattrsargs {
1530+ struct nfs4_sequence_args seq_args;
1531+ struct nfs_fh *fh;
1532+ u32 count;
1533+ u64 cookie;
1534+ struct page **xattr_pages;
1535+};
1536+
1537+struct nfs42_listxattrsres {
1538+ struct nfs4_sequence_res seq_res;
1539+ struct page *scratch;
1540+ void *xattr_buf;
1541+ size_t xattr_len;
1542+ u64 cookie;
1543+ bool eof;
1544+ size_t copied;
1545+};
1546+
1547+struct nfs42_removexattrargs {
1548+ struct nfs4_sequence_args seq_args;
1549+ struct nfs_fh *fh;
1550+ const char *xattr_name;
1551+};
1552+
1553+struct nfs42_removexattrres {
1554+ struct nfs4_sequence_res seq_res;
1555+ struct nfs4_change_info cinfo;
1556+};
1557+
1558+#endif /* CONFIG_NFS_V4_2 */
15021559
15031560 struct nfs_page;
15041561

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t