diff options
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 362 |
1 files changed, 342 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 15f7b73e0c0f..df5e66caf100 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include "state.h" | 47 | #include "state.h" |
| 48 | #include "cache.h" | 48 | #include "cache.h" |
| 49 | #include "netns.h" | 49 | #include "netns.h" |
| 50 | #include "pnfs.h" | ||
| 50 | 51 | ||
| 51 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | 52 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
| 52 | #include <linux/security.h> | 53 | #include <linux/security.h> |
| @@ -234,6 +235,26 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) | |||
| 234 | return ret; | 235 | return ret; |
| 235 | } | 236 | } |
| 236 | 237 | ||
| 238 | /* | ||
| 239 | * We require the high 32 bits of 'seconds' to be 0, and | ||
| 240 | * we ignore all 32 bits of 'nseconds'. | ||
| 241 | */ | ||
| 242 | static __be32 | ||
| 243 | nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec *tv) | ||
| 244 | { | ||
| 245 | DECODE_HEAD; | ||
| 246 | u64 sec; | ||
| 247 | |||
| 248 | READ_BUF(12); | ||
| 249 | p = xdr_decode_hyper(p, &sec); | ||
| 250 | tv->tv_sec = sec; | ||
| 251 | tv->tv_nsec = be32_to_cpup(p++); | ||
| 252 | if (tv->tv_nsec >= (u32)1000000000) | ||
| 253 | return nfserr_inval; | ||
| 254 | |||
| 255 | DECODE_TAIL; | ||
| 256 | } | ||
| 257 | |||
| 237 | static __be32 | 258 | static __be32 |
| 238 | nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | 259 | nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) |
| 239 | { | 260 | { |
| @@ -267,7 +288,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
| 267 | { | 288 | { |
| 268 | int expected_len, len = 0; | 289 | int expected_len, len = 0; |
| 269 | u32 dummy32; | 290 | u32 dummy32; |
| 270 | u64 sec; | ||
| 271 | char *buf; | 291 | char *buf; |
| 272 | 292 | ||
| 273 | DECODE_HEAD; | 293 | DECODE_HEAD; |
| @@ -358,15 +378,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
| 358 | dummy32 = be32_to_cpup(p++); | 378 | dummy32 = be32_to_cpup(p++); |
| 359 | switch (dummy32) { | 379 | switch (dummy32) { |
| 360 | case NFS4_SET_TO_CLIENT_TIME: | 380 | case NFS4_SET_TO_CLIENT_TIME: |
| 361 | /* We require the high 32 bits of 'seconds' to be 0, and we ignore | ||
| 362 | all 32 bits of 'nseconds'. */ | ||
| 363 | READ_BUF(12); | ||
| 364 | len += 12; | 381 | len += 12; |
| 365 | p = xdr_decode_hyper(p, &sec); | 382 | status = nfsd4_decode_time(argp, &iattr->ia_atime); |
| 366 | iattr->ia_atime.tv_sec = (time_t)sec; | 383 | if (status) |
| 367 | iattr->ia_atime.tv_nsec = be32_to_cpup(p++); | 384 | return status; |
| 368 | if (iattr->ia_atime.tv_nsec >= (u32)1000000000) | ||
| 369 | return nfserr_inval; | ||
| 370 | iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); | 385 | iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); |
| 371 | break; | 386 | break; |
| 372 | case NFS4_SET_TO_SERVER_TIME: | 387 | case NFS4_SET_TO_SERVER_TIME: |
| @@ -382,15 +397,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, | |||
| 382 | dummy32 = be32_to_cpup(p++); | 397 | dummy32 = be32_to_cpup(p++); |
| 383 | switch (dummy32) { | 398 | switch (dummy32) { |
| 384 | case NFS4_SET_TO_CLIENT_TIME: | 399 | case NFS4_SET_TO_CLIENT_TIME: |
| 385 | /* We require the high 32 bits of 'seconds' to be 0, and we ignore | ||
| 386 | all 32 bits of 'nseconds'. */ | ||
| 387 | READ_BUF(12); | ||
| 388 | len += 12; | 400 | len += 12; |
| 389 | p = xdr_decode_hyper(p, &sec); | 401 | status = nfsd4_decode_time(argp, &iattr->ia_mtime); |
| 390 | iattr->ia_mtime.tv_sec = sec; | 402 | if (status) |
| 391 | iattr->ia_mtime.tv_nsec = be32_to_cpup(p++); | 403 | return status; |
| 392 | if (iattr->ia_mtime.tv_nsec >= (u32)1000000000) | ||
| 393 | return nfserr_inval; | ||
| 394 | iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); | 404 | iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); |
| 395 | break; | 405 | break; |
| 396 | case NFS4_SET_TO_SERVER_TIME: | 406 | case NFS4_SET_TO_SERVER_TIME: |
| @@ -1513,6 +1523,127 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str | |||
| 1513 | DECODE_TAIL; | 1523 | DECODE_TAIL; |
| 1514 | } | 1524 | } |
| 1515 | 1525 | ||
| 1526 | #ifdef CONFIG_NFSD_PNFS | ||
| 1527 | static __be32 | ||
| 1528 | nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, | ||
| 1529 | struct nfsd4_getdeviceinfo *gdev) | ||
| 1530 | { | ||
| 1531 | DECODE_HEAD; | ||
| 1532 | u32 num, i; | ||
| 1533 | |||
| 1534 | READ_BUF(sizeof(struct nfsd4_deviceid) + 3 * 4); | ||
| 1535 | COPYMEM(&gdev->gd_devid, sizeof(struct nfsd4_deviceid)); | ||
| 1536 | gdev->gd_layout_type = be32_to_cpup(p++); | ||
| 1537 | gdev->gd_maxcount = be32_to_cpup(p++); | ||
| 1538 | num = be32_to_cpup(p++); | ||
| 1539 | if (num) { | ||
| 1540 | READ_BUF(4 * num); | ||
| 1541 | gdev->gd_notify_types = be32_to_cpup(p++); | ||
| 1542 | for (i = 1; i < num; i++) { | ||
| 1543 | if (be32_to_cpup(p++)) { | ||
| 1544 | status = nfserr_inval; | ||
| 1545 | goto out; | ||
| 1546 | } | ||
| 1547 | } | ||
| 1548 | } | ||
| 1549 | DECODE_TAIL; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | static __be32 | ||
| 1553 | nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, | ||
| 1554 | struct nfsd4_layoutget *lgp) | ||
| 1555 | { | ||
| 1556 | DECODE_HEAD; | ||
| 1557 | |||
| 1558 | READ_BUF(36); | ||
| 1559 | lgp->lg_signal = be32_to_cpup(p++); | ||
| 1560 | lgp->lg_layout_type = be32_to_cpup(p++); | ||
| 1561 | lgp->lg_seg.iomode = be32_to_cpup(p++); | ||
| 1562 | p = xdr_decode_hyper(p, &lgp->lg_seg.offset); | ||
| 1563 | p = xdr_decode_hyper(p, &lgp->lg_seg.length); | ||
| 1564 | p = xdr_decode_hyper(p, &lgp->lg_minlength); | ||
| 1565 | nfsd4_decode_stateid(argp, &lgp->lg_sid); | ||
| 1566 | READ_BUF(4); | ||
| 1567 | lgp->lg_maxcount = be32_to_cpup(p++); | ||
| 1568 | |||
| 1569 | DECODE_TAIL; | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | static __be32 | ||
| 1573 | nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, | ||
| 1574 | struct nfsd4_layoutcommit *lcp) | ||
| 1575 | { | ||
| 1576 | DECODE_HEAD; | ||
| 1577 | u32 timechange; | ||
| 1578 | |||
| 1579 | READ_BUF(20); | ||
| 1580 | p = xdr_decode_hyper(p, &lcp->lc_seg.offset); | ||
| 1581 | p = xdr_decode_hyper(p, &lcp->lc_seg.length); | ||
| 1582 | lcp->lc_reclaim = be32_to_cpup(p++); | ||
| 1583 | nfsd4_decode_stateid(argp, &lcp->lc_sid); | ||
| 1584 | READ_BUF(4); | ||
| 1585 | lcp->lc_newoffset = be32_to_cpup(p++); | ||
| 1586 | if (lcp->lc_newoffset) { | ||
| 1587 | READ_BUF(8); | ||
| 1588 | p = xdr_decode_hyper(p, &lcp->lc_last_wr); | ||
| 1589 | } else | ||
| 1590 | lcp->lc_last_wr = 0; | ||
| 1591 | READ_BUF(4); | ||
| 1592 | timechange = be32_to_cpup(p++); | ||
| 1593 | if (timechange) { | ||
| 1594 | status = nfsd4_decode_time(argp, &lcp->lc_mtime); | ||
| 1595 | if (status) | ||
| 1596 | return status; | ||
| 1597 | } else { | ||
| 1598 | lcp->lc_mtime.tv_nsec = UTIME_NOW; | ||
| 1599 | } | ||
| 1600 | READ_BUF(8); | ||
| 1601 | lcp->lc_layout_type = be32_to_cpup(p++); | ||
| 1602 | |||
| 1603 | /* | ||
| 1604 | * Save the layout update in XDR format and let the layout driver deal | ||
| 1605 | * with it later. | ||
| 1606 | */ | ||
| 1607 | lcp->lc_up_len = be32_to_cpup(p++); | ||
| 1608 | if (lcp->lc_up_len > 0) { | ||
| 1609 | READ_BUF(lcp->lc_up_len); | ||
| 1610 | READMEM(lcp->lc_up_layout, lcp->lc_up_len); | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | DECODE_TAIL; | ||
| 1614 | } | ||
| 1615 | |||
| 1616 | static __be32 | ||
| 1617 | nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, | ||
| 1618 | struct nfsd4_layoutreturn *lrp) | ||
| 1619 | { | ||
| 1620 | DECODE_HEAD; | ||
| 1621 | |||
| 1622 | READ_BUF(16); | ||
| 1623 | lrp->lr_reclaim = be32_to_cpup(p++); | ||
| 1624 | lrp->lr_layout_type = be32_to_cpup(p++); | ||
| 1625 | lrp->lr_seg.iomode = be32_to_cpup(p++); | ||
| 1626 | lrp->lr_return_type = be32_to_cpup(p++); | ||
| 1627 | if (lrp->lr_return_type == RETURN_FILE) { | ||
| 1628 | READ_BUF(16); | ||
| 1629 | p = xdr_decode_hyper(p, &lrp->lr_seg.offset); | ||
| 1630 | p = xdr_decode_hyper(p, &lrp->lr_seg.length); | ||
| 1631 | nfsd4_decode_stateid(argp, &lrp->lr_sid); | ||
| 1632 | READ_BUF(4); | ||
| 1633 | lrp->lrf_body_len = be32_to_cpup(p++); | ||
| 1634 | if (lrp->lrf_body_len > 0) { | ||
| 1635 | READ_BUF(lrp->lrf_body_len); | ||
| 1636 | READMEM(lrp->lrf_body, lrp->lrf_body_len); | ||
| 1637 | } | ||
| 1638 | } else { | ||
| 1639 | lrp->lr_seg.offset = 0; | ||
| 1640 | lrp->lr_seg.length = NFS4_MAX_UINT64; | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | DECODE_TAIL; | ||
| 1644 | } | ||
| 1645 | #endif /* CONFIG_NFSD_PNFS */ | ||
| 1646 | |||
| 1516 | static __be32 | 1647 | static __be32 |
| 1517 | nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, | 1648 | nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, |
| 1518 | struct nfsd4_fallocate *fallocate) | 1649 | struct nfsd4_fallocate *fallocate) |
| @@ -1607,11 +1738,19 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
| 1607 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, | 1738 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
| 1608 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, | 1739 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, |
| 1609 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, | 1740 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1741 | #ifdef CONFIG_NFSD_PNFS | ||
| 1742 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo, | ||
| 1743 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, | ||
| 1744 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit, | ||
| 1745 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget, | ||
| 1746 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn, | ||
| 1747 | #else | ||
| 1610 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, | 1748 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1611 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, | 1749 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1612 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, | 1750 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1613 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, | 1751 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1614 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, | 1752 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
| 1753 | #endif | ||
| 1615 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, | 1754 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, |
| 1616 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, | 1755 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
| 1617 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, | 1756 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
| @@ -2539,6 +2678,30 @@ out_acl: | |||
| 2539 | get_parent_attributes(exp, &stat); | 2678 | get_parent_attributes(exp, &stat); |
| 2540 | p = xdr_encode_hyper(p, stat.ino); | 2679 | p = xdr_encode_hyper(p, stat.ino); |
| 2541 | } | 2680 | } |
| 2681 | #ifdef CONFIG_NFSD_PNFS | ||
| 2682 | if ((bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) || | ||
| 2683 | (bmval2 & FATTR4_WORD2_LAYOUT_TYPES)) { | ||
| 2684 | if (exp->ex_layout_type) { | ||
| 2685 | p = xdr_reserve_space(xdr, 8); | ||
| 2686 | if (!p) | ||
| 2687 | goto out_resource; | ||
| 2688 | *p++ = cpu_to_be32(1); | ||
| 2689 | *p++ = cpu_to_be32(exp->ex_layout_type); | ||
| 2690 | } else { | ||
| 2691 | p = xdr_reserve_space(xdr, 4); | ||
| 2692 | if (!p) | ||
| 2693 | goto out_resource; | ||
| 2694 | *p++ = cpu_to_be32(0); | ||
| 2695 | } | ||
| 2696 | } | ||
| 2697 | |||
| 2698 | if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) { | ||
| 2699 | p = xdr_reserve_space(xdr, 4); | ||
| 2700 | if (!p) | ||
| 2701 | goto out_resource; | ||
| 2702 | *p++ = cpu_to_be32(stat.blksize); | ||
| 2703 | } | ||
| 2704 | #endif /* CONFIG_NFSD_PNFS */ | ||
| 2542 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { | 2705 | if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { |
| 2543 | status = nfsd4_encode_security_label(xdr, rqstp, context, | 2706 | status = nfsd4_encode_security_label(xdr, rqstp, context, |
| 2544 | contextlen); | 2707 | contextlen); |
| @@ -2768,16 +2931,17 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, | |||
| 2768 | if (entry_bytes > cd->rd_maxcount) | 2931 | if (entry_bytes > cd->rd_maxcount) |
| 2769 | goto fail; | 2932 | goto fail; |
| 2770 | cd->rd_maxcount -= entry_bytes; | 2933 | cd->rd_maxcount -= entry_bytes; |
| 2771 | if (!cd->rd_dircount) | ||
| 2772 | goto fail; | ||
| 2773 | /* | 2934 | /* |
| 2774 | * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so | 2935 | * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so |
| 2775 | * let's always let through the first entry, at least: | 2936 | * let's always let through the first entry, at least: |
| 2776 | */ | 2937 | */ |
| 2777 | name_and_cookie = 4 * XDR_QUADLEN(namlen) + 8; | 2938 | if (!cd->rd_dircount) |
| 2939 | goto fail; | ||
| 2940 | name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8; | ||
| 2778 | if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) | 2941 | if (name_and_cookie > cd->rd_dircount && cd->cookie_offset) |
| 2779 | goto fail; | 2942 | goto fail; |
| 2780 | cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); | 2943 | cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie); |
| 2944 | |||
| 2781 | cd->cookie_offset = cookie_offset; | 2945 | cd->cookie_offset = cookie_offset; |
| 2782 | skip_entry: | 2946 | skip_entry: |
| 2783 | cd->common.err = nfs_ok; | 2947 | cd->common.err = nfs_ok; |
| @@ -3814,6 +3978,156 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
| 3814 | return nfserr; | 3978 | return nfserr; |
| 3815 | } | 3979 | } |
| 3816 | 3980 | ||
| 3981 | #ifdef CONFIG_NFSD_PNFS | ||
| 3982 | static __be32 | ||
| 3983 | nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
| 3984 | struct nfsd4_getdeviceinfo *gdev) | ||
| 3985 | { | ||
| 3986 | struct xdr_stream *xdr = &resp->xdr; | ||
| 3987 | const struct nfsd4_layout_ops *ops = | ||
| 3988 | nfsd4_layout_ops[gdev->gd_layout_type]; | ||
| 3989 | u32 starting_len = xdr->buf->len, needed_len; | ||
| 3990 | __be32 *p; | ||
| 3991 | |||
| 3992 | dprintk("%s: err %d\n", __func__, nfserr); | ||
| 3993 | if (nfserr) | ||
| 3994 | goto out; | ||
| 3995 | |||
| 3996 | nfserr = nfserr_resource; | ||
| 3997 | p = xdr_reserve_space(xdr, 4); | ||
| 3998 | if (!p) | ||
| 3999 | goto out; | ||
| 4000 | |||
| 4001 | *p++ = cpu_to_be32(gdev->gd_layout_type); | ||
| 4002 | |||
| 4003 | /* If maxcount is 0 then just update notifications */ | ||
| 4004 | if (gdev->gd_maxcount != 0) { | ||
| 4005 | nfserr = ops->encode_getdeviceinfo(xdr, gdev); | ||
| 4006 | if (nfserr) { | ||
| 4007 | /* | ||
| 4008 | * We don't bother to burden the layout drivers with | ||
| 4009 | * enforcing gd_maxcount, just tell the client to | ||
| 4010 | * come back with a bigger buffer if it's not enough. | ||
| 4011 | */ | ||
| 4012 | if (xdr->buf->len + 4 > gdev->gd_maxcount) | ||
| 4013 | goto toosmall; | ||
| 4014 | goto out; | ||
| 4015 | } | ||
| 4016 | } | ||
| 4017 | |||
| 4018 | nfserr = nfserr_resource; | ||
| 4019 | if (gdev->gd_notify_types) { | ||
| 4020 | p = xdr_reserve_space(xdr, 4 + 4); | ||
| 4021 | if (!p) | ||
| 4022 | goto out; | ||
| 4023 | *p++ = cpu_to_be32(1); /* bitmap length */ | ||
| 4024 | *p++ = cpu_to_be32(gdev->gd_notify_types); | ||
| 4025 | } else { | ||
| 4026 | p = xdr_reserve_space(xdr, 4); | ||
| 4027 | if (!p) | ||
| 4028 | goto out; | ||
| 4029 | *p++ = 0; | ||
| 4030 | } | ||
| 4031 | |||
| 4032 | nfserr = 0; | ||
| 4033 | out: | ||
| 4034 | kfree(gdev->gd_device); | ||
| 4035 | dprintk("%s: done: %d\n", __func__, be32_to_cpu(nfserr)); | ||
| 4036 | return nfserr; | ||
| 4037 | |||
| 4038 | toosmall: | ||
| 4039 | dprintk("%s: maxcount too small\n", __func__); | ||
| 4040 | needed_len = xdr->buf->len + 4 /* notifications */; | ||
| 4041 | xdr_truncate_encode(xdr, starting_len); | ||
| 4042 | p = xdr_reserve_space(xdr, 4); | ||
| 4043 | if (!p) { | ||
| 4044 | nfserr = nfserr_resource; | ||
| 4045 | } else { | ||
| 4046 | *p++ = cpu_to_be32(needed_len); | ||
| 4047 | nfserr = nfserr_toosmall; | ||
| 4048 | } | ||
| 4049 | goto out; | ||
| 4050 | } | ||
| 4051 | |||
| 4052 | static __be32 | ||
| 4053 | nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
| 4054 | struct nfsd4_layoutget *lgp) | ||
| 4055 | { | ||
| 4056 | struct xdr_stream *xdr = &resp->xdr; | ||
| 4057 | const struct nfsd4_layout_ops *ops = | ||
| 4058 | nfsd4_layout_ops[lgp->lg_layout_type]; | ||
| 4059 | __be32 *p; | ||
| 4060 | |||
| 4061 | dprintk("%s: err %d\n", __func__, nfserr); | ||
| 4062 | if (nfserr) | ||
| 4063 | goto out; | ||
| 4064 | |||
| 4065 | nfserr = nfserr_resource; | ||
| 4066 | p = xdr_reserve_space(xdr, 36 + sizeof(stateid_opaque_t)); | ||
| 4067 | if (!p) | ||
| 4068 | goto out; | ||
| 4069 | |||
| 4070 | *p++ = cpu_to_be32(1); /* we always set return-on-close */ | ||
| 4071 | *p++ = cpu_to_be32(lgp->lg_sid.si_generation); | ||
| 4072 | p = xdr_encode_opaque_fixed(p, &lgp->lg_sid.si_opaque, | ||
| 4073 | sizeof(stateid_opaque_t)); | ||
| 4074 | |||
| 4075 | *p++ = cpu_to_be32(1); /* we always return a single layout */ | ||
| 4076 | p = xdr_encode_hyper(p, lgp->lg_seg.offset); | ||
| 4077 | p = xdr_encode_hyper(p, lgp->lg_seg.length); | ||
| 4078 | *p++ = cpu_to_be32(lgp->lg_seg.iomode); | ||
| 4079 | *p++ = cpu_to_be32(lgp->lg_layout_type); | ||
| 4080 | |||
| 4081 | nfserr = ops->encode_layoutget(xdr, lgp); | ||
| 4082 | out: | ||
| 4083 | kfree(lgp->lg_content); | ||
| 4084 | return nfserr; | ||
| 4085 | } | ||
| 4086 | |||
| 4087 | static __be32 | ||
| 4088 | nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
| 4089 | struct nfsd4_layoutcommit *lcp) | ||
| 4090 | { | ||
| 4091 | struct xdr_stream *xdr = &resp->xdr; | ||
| 4092 | __be32 *p; | ||
| 4093 | |||
| 4094 | if (nfserr) | ||
| 4095 | return nfserr; | ||
| 4096 | |||
| 4097 | p = xdr_reserve_space(xdr, 4); | ||
| 4098 | if (!p) | ||
| 4099 | return nfserr_resource; | ||
| 4100 | *p++ = cpu_to_be32(lcp->lc_size_chg); | ||
| 4101 | if (lcp->lc_size_chg) { | ||
| 4102 | p = xdr_reserve_space(xdr, 8); | ||
| 4103 | if (!p) | ||
| 4104 | return nfserr_resource; | ||
| 4105 | p = xdr_encode_hyper(p, lcp->lc_newsize); | ||
| 4106 | } | ||
| 4107 | |||
| 4108 | return nfs_ok; | ||
| 4109 | } | ||
| 4110 | |||
| 4111 | static __be32 | ||
| 4112 | nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, | ||
| 4113 | struct nfsd4_layoutreturn *lrp) | ||
| 4114 | { | ||
| 4115 | struct xdr_stream *xdr = &resp->xdr; | ||
| 4116 | __be32 *p; | ||
| 4117 | |||
| 4118 | if (nfserr) | ||
| 4119 | return nfserr; | ||
| 4120 | |||
| 4121 | p = xdr_reserve_space(xdr, 4); | ||
| 4122 | if (!p) | ||
| 4123 | return nfserr_resource; | ||
| 4124 | *p++ = cpu_to_be32(lrp->lrs_present); | ||
| 4125 | if (lrp->lrs_present) | ||
| 4126 | nfsd4_encode_stateid(xdr, &lrp->lr_sid); | ||
| 4127 | return nfs_ok; | ||
| 4128 | } | ||
| 4129 | #endif /* CONFIG_NFSD_PNFS */ | ||
| 4130 | |||
| 3817 | static __be32 | 4131 | static __be32 |
| 3818 | nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, | 4132 | nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, |
| 3819 | struct nfsd4_seek *seek) | 4133 | struct nfsd4_seek *seek) |
| @@ -3890,11 +4204,19 @@ static nfsd4_enc nfsd4_enc_ops[] = { | |||
| 3890 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop, | 4204 | [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop, |
| 3891 | [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, | 4205 | [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, |
| 3892 | [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, | 4206 | [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, |
| 4207 | #ifdef CONFIG_NFSD_PNFS | ||
| 4208 | [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo, | ||
| 4209 | [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, | ||
| 4210 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit, | ||
| 4211 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget, | ||
| 4212 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn, | ||
| 4213 | #else | ||
| 3893 | [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, | 4214 | [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, |
| 3894 | [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, | 4215 | [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, |
| 3895 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, | 4216 | [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, |
| 3896 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, | 4217 | [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, |
| 3897 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, | 4218 | [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, |
| 4219 | #endif | ||
| 3898 | [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, | 4220 | [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, |
| 3899 | [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, | 4221 | [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, |
| 3900 | [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, | 4222 | [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, |
