diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 700 |
1 files changed, 557 insertions, 143 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 08ef91291132..f313c4cce7e4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include <linux/nfs_idmap.h> | 52 | #include <linux/nfs_idmap.h> |
53 | #include "nfs4_fs.h" | 53 | #include "nfs4_fs.h" |
54 | #include "internal.h" | 54 | #include "internal.h" |
55 | #include "pnfs.h" | ||
55 | 56 | ||
56 | #define NFSDBG_FACILITY NFSDBG_XDR | 57 | #define NFSDBG_FACILITY NFSDBG_XDR |
57 | 58 | ||
@@ -310,6 +311,19 @@ static int nfs4_stat_to_errno(int); | |||
310 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | 311 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) |
311 | #define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4) | 312 | #define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4) |
312 | #define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4) | 313 | #define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4) |
314 | #define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \ | ||
315 | XDR_QUADLEN(NFS4_DEVICEID4_SIZE)) | ||
316 | #define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \ | ||
317 | 1 /* layout type */ + \ | ||
318 | 1 /* opaque devaddr4 length */ + \ | ||
319 | /* devaddr4 payload is read into page */ \ | ||
320 | 1 /* notification bitmap length */ + \ | ||
321 | 1 /* notification bitmap */) | ||
322 | #define encode_layoutget_maxsz (op_encode_hdr_maxsz + 10 + \ | ||
323 | encode_stateid_maxsz) | ||
324 | #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ | ||
325 | decode_stateid_maxsz + \ | ||
326 | XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) | ||
313 | #else /* CONFIG_NFS_V4_1 */ | 327 | #else /* CONFIG_NFS_V4_1 */ |
314 | #define encode_sequence_maxsz 0 | 328 | #define encode_sequence_maxsz 0 |
315 | #define decode_sequence_maxsz 0 | 329 | #define decode_sequence_maxsz 0 |
@@ -699,6 +713,20 @@ static int nfs4_stat_to_errno(int); | |||
699 | #define NFS4_dec_reclaim_complete_sz (compound_decode_hdr_maxsz + \ | 713 | #define NFS4_dec_reclaim_complete_sz (compound_decode_hdr_maxsz + \ |
700 | decode_sequence_maxsz + \ | 714 | decode_sequence_maxsz + \ |
701 | decode_reclaim_complete_maxsz) | 715 | decode_reclaim_complete_maxsz) |
716 | #define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz + \ | ||
717 | encode_sequence_maxsz +\ | ||
718 | encode_getdeviceinfo_maxsz) | ||
719 | #define NFS4_dec_getdeviceinfo_sz (compound_decode_hdr_maxsz + \ | ||
720 | decode_sequence_maxsz + \ | ||
721 | decode_getdeviceinfo_maxsz) | ||
722 | #define NFS4_enc_layoutget_sz (compound_encode_hdr_maxsz + \ | ||
723 | encode_sequence_maxsz + \ | ||
724 | encode_putfh_maxsz + \ | ||
725 | encode_layoutget_maxsz) | ||
726 | #define NFS4_dec_layoutget_sz (compound_decode_hdr_maxsz + \ | ||
727 | decode_sequence_maxsz + \ | ||
728 | decode_putfh_maxsz + \ | ||
729 | decode_layoutget_maxsz) | ||
702 | 730 | ||
703 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | 731 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
704 | compound_encode_hdr_maxsz + | 732 | compound_encode_hdr_maxsz + |
@@ -816,7 +844,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
816 | if (iap->ia_valid & ATTR_MODE) | 844 | if (iap->ia_valid & ATTR_MODE) |
817 | len += 4; | 845 | len += 4; |
818 | if (iap->ia_valid & ATTR_UID) { | 846 | if (iap->ia_valid & ATTR_UID) { |
819 | owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name); | 847 | owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name, IDMAP_NAMESZ); |
820 | if (owner_namelen < 0) { | 848 | if (owner_namelen < 0) { |
821 | dprintk("nfs: couldn't resolve uid %d to string\n", | 849 | dprintk("nfs: couldn't resolve uid %d to string\n", |
822 | iap->ia_uid); | 850 | iap->ia_uid); |
@@ -828,7 +856,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
828 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); | 856 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); |
829 | } | 857 | } |
830 | if (iap->ia_valid & ATTR_GID) { | 858 | if (iap->ia_valid & ATTR_GID) { |
831 | owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group); | 859 | owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group, IDMAP_NAMESZ); |
832 | if (owner_grouplen < 0) { | 860 | if (owner_grouplen < 0) { |
833 | dprintk("nfs: couldn't resolve gid %d to string\n", | 861 | dprintk("nfs: couldn't resolve gid %d to string\n", |
834 | iap->ia_gid); | 862 | iap->ia_gid); |
@@ -1385,24 +1413,35 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1385 | 1413 | ||
1386 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1414 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
1387 | { | 1415 | { |
1388 | uint32_t attrs[2] = { | 1416 | uint32_t attrs[2] = {0, 0}; |
1389 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | 1417 | uint32_t dircount = readdir->count >> 1; |
1390 | FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
1391 | }; | ||
1392 | __be32 *p; | 1418 | __be32 *p; |
1393 | 1419 | ||
1420 | if (readdir->plus) { | ||
1421 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| | ||
1422 | FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE; | ||
1423 | attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| | ||
1424 | FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| | ||
1425 | FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| | ||
1426 | FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | ||
1427 | dircount >>= 1; | ||
1428 | } | ||
1429 | attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID; | ||
1430 | attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
1431 | /* Switch to mounted_on_fileid if the server supports it */ | ||
1432 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
1433 | attrs[0] &= ~FATTR4_WORD0_FILEID; | ||
1434 | else | ||
1435 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
1436 | |||
1394 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); | 1437 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); |
1395 | *p++ = cpu_to_be32(OP_READDIR); | 1438 | *p++ = cpu_to_be32(OP_READDIR); |
1396 | p = xdr_encode_hyper(p, readdir->cookie); | 1439 | p = xdr_encode_hyper(p, readdir->cookie); |
1397 | p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); | 1440 | p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); |
1398 | *p++ = cpu_to_be32(readdir->count >> 1); /* We're not doing readdirplus */ | 1441 | *p++ = cpu_to_be32(dircount); |
1399 | *p++ = cpu_to_be32(readdir->count); | 1442 | *p++ = cpu_to_be32(readdir->count); |
1400 | *p++ = cpu_to_be32(2); | 1443 | *p++ = cpu_to_be32(2); |
1401 | /* Switch to mounted_on_fileid if the server supports it */ | 1444 | |
1402 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
1403 | attrs[0] &= ~FATTR4_WORD0_FILEID; | ||
1404 | else | ||
1405 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
1406 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); | 1445 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); |
1407 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); | 1446 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); |
1408 | hdr->nops++; | 1447 | hdr->nops++; |
@@ -1726,6 +1765,58 @@ static void encode_sequence(struct xdr_stream *xdr, | |||
1726 | #endif /* CONFIG_NFS_V4_1 */ | 1765 | #endif /* CONFIG_NFS_V4_1 */ |
1727 | } | 1766 | } |
1728 | 1767 | ||
1768 | #ifdef CONFIG_NFS_V4_1 | ||
1769 | static void | ||
1770 | encode_getdeviceinfo(struct xdr_stream *xdr, | ||
1771 | const struct nfs4_getdeviceinfo_args *args, | ||
1772 | struct compound_hdr *hdr) | ||
1773 | { | ||
1774 | __be32 *p; | ||
1775 | |||
1776 | p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE); | ||
1777 | *p++ = cpu_to_be32(OP_GETDEVICEINFO); | ||
1778 | p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data, | ||
1779 | NFS4_DEVICEID4_SIZE); | ||
1780 | *p++ = cpu_to_be32(args->pdev->layout_type); | ||
1781 | *p++ = cpu_to_be32(args->pdev->pglen); /* gdia_maxcount */ | ||
1782 | *p++ = cpu_to_be32(0); /* bitmap length 0 */ | ||
1783 | hdr->nops++; | ||
1784 | hdr->replen += decode_getdeviceinfo_maxsz; | ||
1785 | } | ||
1786 | |||
1787 | static void | ||
1788 | encode_layoutget(struct xdr_stream *xdr, | ||
1789 | const struct nfs4_layoutget_args *args, | ||
1790 | struct compound_hdr *hdr) | ||
1791 | { | ||
1792 | nfs4_stateid stateid; | ||
1793 | __be32 *p; | ||
1794 | |||
1795 | p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE); | ||
1796 | *p++ = cpu_to_be32(OP_LAYOUTGET); | ||
1797 | *p++ = cpu_to_be32(0); /* Signal layout available */ | ||
1798 | *p++ = cpu_to_be32(args->type); | ||
1799 | *p++ = cpu_to_be32(args->range.iomode); | ||
1800 | p = xdr_encode_hyper(p, args->range.offset); | ||
1801 | p = xdr_encode_hyper(p, args->range.length); | ||
1802 | p = xdr_encode_hyper(p, args->minlength); | ||
1803 | pnfs_get_layout_stateid(&stateid, NFS_I(args->inode)->layout, | ||
1804 | args->ctx->state); | ||
1805 | p = xdr_encode_opaque_fixed(p, &stateid.data, NFS4_STATEID_SIZE); | ||
1806 | *p = cpu_to_be32(args->maxcount); | ||
1807 | |||
1808 | dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n", | ||
1809 | __func__, | ||
1810 | args->type, | ||
1811 | args->range.iomode, | ||
1812 | (unsigned long)args->range.offset, | ||
1813 | (unsigned long)args->range.length, | ||
1814 | args->maxcount); | ||
1815 | hdr->nops++; | ||
1816 | hdr->replen += decode_layoutget_maxsz; | ||
1817 | } | ||
1818 | #endif /* CONFIG_NFS_V4_1 */ | ||
1819 | |||
1729 | /* | 1820 | /* |
1730 | * END OF "GENERIC" ENCODE ROUTINES. | 1821 | * END OF "GENERIC" ENCODE ROUTINES. |
1731 | */ | 1822 | */ |
@@ -1823,7 +1914,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1823 | /* | 1914 | /* |
1824 | * Encode RENAME request | 1915 | * Encode RENAME request |
1825 | */ | 1916 | */ |
1826 | static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args) | 1917 | static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs_renameargs *args) |
1827 | { | 1918 | { |
1828 | struct xdr_stream xdr; | 1919 | struct xdr_stream xdr; |
1829 | struct compound_hdr hdr = { | 1920 | struct compound_hdr hdr = { |
@@ -2543,6 +2634,51 @@ static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p, | |||
2543 | return 0; | 2634 | return 0; |
2544 | } | 2635 | } |
2545 | 2636 | ||
2637 | /* | ||
2638 | * Encode GETDEVICEINFO request | ||
2639 | */ | ||
2640 | static int nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req, uint32_t *p, | ||
2641 | struct nfs4_getdeviceinfo_args *args) | ||
2642 | { | ||
2643 | struct xdr_stream xdr; | ||
2644 | struct compound_hdr hdr = { | ||
2645 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2646 | }; | ||
2647 | |||
2648 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2649 | encode_compound_hdr(&xdr, req, &hdr); | ||
2650 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2651 | encode_getdeviceinfo(&xdr, args, &hdr); | ||
2652 | |||
2653 | /* set up reply kvec. Subtract notification bitmap max size (2) | ||
2654 | * so that notification bitmap is put in xdr_buf tail */ | ||
2655 | xdr_inline_pages(&req->rq_rcv_buf, (hdr.replen - 2) << 2, | ||
2656 | args->pdev->pages, args->pdev->pgbase, | ||
2657 | args->pdev->pglen); | ||
2658 | |||
2659 | encode_nops(&hdr); | ||
2660 | return 0; | ||
2661 | } | ||
2662 | |||
2663 | /* | ||
2664 | * Encode LAYOUTGET request | ||
2665 | */ | ||
2666 | static int nfs4_xdr_enc_layoutget(struct rpc_rqst *req, uint32_t *p, | ||
2667 | struct nfs4_layoutget_args *args) | ||
2668 | { | ||
2669 | struct xdr_stream xdr; | ||
2670 | struct compound_hdr hdr = { | ||
2671 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2672 | }; | ||
2673 | |||
2674 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2675 | encode_compound_hdr(&xdr, req, &hdr); | ||
2676 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2677 | encode_putfh(&xdr, NFS_FH(args->inode), &hdr); | ||
2678 | encode_layoutget(&xdr, args, &hdr); | ||
2679 | encode_nops(&hdr); | ||
2680 | return 0; | ||
2681 | } | ||
2546 | #endif /* CONFIG_NFS_V4_1 */ | 2682 | #endif /* CONFIG_NFS_V4_1 */ |
2547 | 2683 | ||
2548 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 2684 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
@@ -2676,7 +2812,10 @@ out_overflow: | |||
2676 | static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) | 2812 | static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) |
2677 | { | 2813 | { |
2678 | if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) { | 2814 | if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) { |
2679 | decode_attr_bitmap(xdr, bitmask); | 2815 | int ret; |
2816 | ret = decode_attr_bitmap(xdr, bitmask); | ||
2817 | if (unlikely(ret < 0)) | ||
2818 | return ret; | ||
2680 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; | 2819 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; |
2681 | } else | 2820 | } else |
2682 | bitmask[0] = bitmask[1] = 0; | 2821 | bitmask[0] = bitmask[1] = 0; |
@@ -2848,6 +2987,56 @@ out_overflow: | |||
2848 | return -EIO; | 2987 | return -EIO; |
2849 | } | 2988 | } |
2850 | 2989 | ||
2990 | static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap) | ||
2991 | { | ||
2992 | __be32 *p; | ||
2993 | |||
2994 | if (unlikely(bitmap[0] & (FATTR4_WORD0_RDATTR_ERROR - 1U))) | ||
2995 | return -EIO; | ||
2996 | if (likely(bitmap[0] & FATTR4_WORD0_RDATTR_ERROR)) { | ||
2997 | p = xdr_inline_decode(xdr, 4); | ||
2998 | if (unlikely(!p)) | ||
2999 | goto out_overflow; | ||
3000 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | ||
3001 | } | ||
3002 | return 0; | ||
3003 | out_overflow: | ||
3004 | print_overflow_msg(__func__, xdr); | ||
3005 | return -EIO; | ||
3006 | } | ||
3007 | |||
3008 | static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh) | ||
3009 | { | ||
3010 | __be32 *p; | ||
3011 | int len; | ||
3012 | |||
3013 | if (fh != NULL) | ||
3014 | memset(fh, 0, sizeof(*fh)); | ||
3015 | |||
3016 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEHANDLE - 1U))) | ||
3017 | return -EIO; | ||
3018 | if (likely(bitmap[0] & FATTR4_WORD0_FILEHANDLE)) { | ||
3019 | p = xdr_inline_decode(xdr, 4); | ||
3020 | if (unlikely(!p)) | ||
3021 | goto out_overflow; | ||
3022 | len = be32_to_cpup(p); | ||
3023 | if (len > NFS4_FHSIZE) | ||
3024 | return -EIO; | ||
3025 | p = xdr_inline_decode(xdr, len); | ||
3026 | if (unlikely(!p)) | ||
3027 | goto out_overflow; | ||
3028 | if (fh != NULL) { | ||
3029 | memcpy(fh->data, p, len); | ||
3030 | fh->size = len; | ||
3031 | } | ||
3032 | bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE; | ||
3033 | } | ||
3034 | return 0; | ||
3035 | out_overflow: | ||
3036 | print_overflow_msg(__func__, xdr); | ||
3037 | return -EIO; | ||
3038 | } | ||
3039 | |||
2851 | static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 3040 | static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
2852 | { | 3041 | { |
2853 | __be32 *p; | 3042 | __be32 *p; |
@@ -3521,6 +3710,24 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s | |||
3521 | return status; | 3710 | return status; |
3522 | } | 3711 | } |
3523 | 3712 | ||
3713 | static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap, | ||
3714 | struct timespec *time) | ||
3715 | { | ||
3716 | int status = 0; | ||
3717 | |||
3718 | time->tv_sec = 0; | ||
3719 | time->tv_nsec = 0; | ||
3720 | if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U))) | ||
3721 | return -EIO; | ||
3722 | if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) { | ||
3723 | status = decode_attr_time(xdr, time); | ||
3724 | bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA; | ||
3725 | } | ||
3726 | dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec, | ||
3727 | (long)time->tv_nsec); | ||
3728 | return status; | ||
3729 | } | ||
3730 | |||
3524 | static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) | 3731 | static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) |
3525 | { | 3732 | { |
3526 | int status = 0; | 3733 | int status = 0; |
@@ -3744,29 +3951,14 @@ xdr_error: | |||
3744 | return status; | 3951 | return status; |
3745 | } | 3952 | } |
3746 | 3953 | ||
3747 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 3954 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, |
3955 | struct nfs_fattr *fattr, struct nfs_fh *fh, | ||
3748 | const struct nfs_server *server, int may_sleep) | 3956 | const struct nfs_server *server, int may_sleep) |
3749 | { | 3957 | { |
3750 | __be32 *savep; | ||
3751 | uint32_t attrlen, | ||
3752 | bitmap[2] = {0}, | ||
3753 | type; | ||
3754 | int status; | 3958 | int status; |
3755 | umode_t fmode = 0; | 3959 | umode_t fmode = 0; |
3756 | uint64_t fileid; | 3960 | uint64_t fileid; |
3757 | 3961 | uint32_t type; | |
3758 | status = decode_op_hdr(xdr, OP_GETATTR); | ||
3759 | if (status < 0) | ||
3760 | goto xdr_error; | ||
3761 | |||
3762 | status = decode_attr_bitmap(xdr, bitmap); | ||
3763 | if (status < 0) | ||
3764 | goto xdr_error; | ||
3765 | |||
3766 | status = decode_attr_length(xdr, &attrlen, &savep); | ||
3767 | if (status < 0) | ||
3768 | goto xdr_error; | ||
3769 | |||
3770 | 3962 | ||
3771 | status = decode_attr_type(xdr, bitmap, &type); | 3963 | status = decode_attr_type(xdr, bitmap, &type); |
3772 | if (status < 0) | 3964 | if (status < 0) |
@@ -3792,6 +3984,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | |||
3792 | goto xdr_error; | 3984 | goto xdr_error; |
3793 | fattr->valid |= status; | 3985 | fattr->valid |= status; |
3794 | 3986 | ||
3987 | status = decode_attr_error(xdr, bitmap); | ||
3988 | if (status < 0) | ||
3989 | goto xdr_error; | ||
3990 | |||
3991 | status = decode_attr_filehandle(xdr, bitmap, fh); | ||
3992 | if (status < 0) | ||
3993 | goto xdr_error; | ||
3994 | |||
3795 | status = decode_attr_fileid(xdr, bitmap, &fattr->fileid); | 3995 | status = decode_attr_fileid(xdr, bitmap, &fattr->fileid); |
3796 | if (status < 0) | 3996 | if (status < 0) |
3797 | goto xdr_error; | 3997 | goto xdr_error; |
@@ -3862,12 +4062,101 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | |||
3862 | fattr->valid |= status; | 4062 | fattr->valid |= status; |
3863 | } | 4063 | } |
3864 | 4064 | ||
4065 | xdr_error: | ||
4066 | dprintk("%s: xdr returned %d\n", __func__, -status); | ||
4067 | return status; | ||
4068 | } | ||
4069 | |||
4070 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, | ||
4071 | struct nfs_fh *fh, const struct nfs_server *server, int may_sleep) | ||
4072 | { | ||
4073 | __be32 *savep; | ||
4074 | uint32_t attrlen, | ||
4075 | bitmap[2] = {0}; | ||
4076 | int status; | ||
4077 | |||
4078 | status = decode_op_hdr(xdr, OP_GETATTR); | ||
4079 | if (status < 0) | ||
4080 | goto xdr_error; | ||
4081 | |||
4082 | status = decode_attr_bitmap(xdr, bitmap); | ||
4083 | if (status < 0) | ||
4084 | goto xdr_error; | ||
4085 | |||
4086 | status = decode_attr_length(xdr, &attrlen, &savep); | ||
4087 | if (status < 0) | ||
4088 | goto xdr_error; | ||
4089 | |||
4090 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep); | ||
4091 | if (status < 0) | ||
4092 | goto xdr_error; | ||
4093 | |||
3865 | status = verify_attr_len(xdr, savep, attrlen); | 4094 | status = verify_attr_len(xdr, savep, attrlen); |
3866 | xdr_error: | 4095 | xdr_error: |
3867 | dprintk("%s: xdr returned %d\n", __func__, -status); | 4096 | dprintk("%s: xdr returned %d\n", __func__, -status); |
3868 | return status; | 4097 | return status; |
3869 | } | 4098 | } |
3870 | 4099 | ||
4100 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | ||
4101 | const struct nfs_server *server, int may_sleep) | ||
4102 | { | ||
4103 | return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep); | ||
4104 | } | ||
4105 | |||
4106 | /* | ||
4107 | * Decode potentially multiple layout types. Currently we only support | ||
4108 | * one layout driver per file system. | ||
4109 | */ | ||
4110 | static int decode_first_pnfs_layout_type(struct xdr_stream *xdr, | ||
4111 | uint32_t *layouttype) | ||
4112 | { | ||
4113 | uint32_t *p; | ||
4114 | int num; | ||
4115 | |||
4116 | p = xdr_inline_decode(xdr, 4); | ||
4117 | if (unlikely(!p)) | ||
4118 | goto out_overflow; | ||
4119 | num = be32_to_cpup(p); | ||
4120 | |||
4121 | /* pNFS is not supported by the underlying file system */ | ||
4122 | if (num == 0) { | ||
4123 | *layouttype = 0; | ||
4124 | return 0; | ||
4125 | } | ||
4126 | if (num > 1) | ||
4127 | printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers " | ||
4128 | "per filesystem not supported\n", __func__); | ||
4129 | |||
4130 | /* Decode and set first layout type, move xdr->p past unused types */ | ||
4131 | p = xdr_inline_decode(xdr, num * 4); | ||
4132 | if (unlikely(!p)) | ||
4133 | goto out_overflow; | ||
4134 | *layouttype = be32_to_cpup(p); | ||
4135 | return 0; | ||
4136 | out_overflow: | ||
4137 | print_overflow_msg(__func__, xdr); | ||
4138 | return -EIO; | ||
4139 | } | ||
4140 | |||
4141 | /* | ||
4142 | * The type of file system exported. | ||
4143 | * Note we must ensure that layouttype is set in any non-error case. | ||
4144 | */ | ||
4145 | static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap, | ||
4146 | uint32_t *layouttype) | ||
4147 | { | ||
4148 | int status = 0; | ||
4149 | |||
4150 | dprintk("%s: bitmap is %x\n", __func__, bitmap[1]); | ||
4151 | if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U))) | ||
4152 | return -EIO; | ||
4153 | if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) { | ||
4154 | status = decode_first_pnfs_layout_type(xdr, layouttype); | ||
4155 | bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES; | ||
4156 | } else | ||
4157 | *layouttype = 0; | ||
4158 | return status; | ||
4159 | } | ||
3871 | 4160 | ||
3872 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | 4161 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) |
3873 | { | 4162 | { |
@@ -3894,6 +4183,12 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | |||
3894 | if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) | 4183 | if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) |
3895 | goto xdr_error; | 4184 | goto xdr_error; |
3896 | fsinfo->wtpref = fsinfo->wtmax; | 4185 | fsinfo->wtpref = fsinfo->wtmax; |
4186 | status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta); | ||
4187 | if (status != 0) | ||
4188 | goto xdr_error; | ||
4189 | status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype); | ||
4190 | if (status != 0) | ||
4191 | goto xdr_error; | ||
3897 | 4192 | ||
3898 | status = verify_attr_len(xdr, savep, attrlen); | 4193 | status = verify_attr_len(xdr, savep, attrlen); |
3899 | xdr_error: | 4194 | xdr_error: |
@@ -3950,13 +4245,13 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
3950 | __be32 *p; | 4245 | __be32 *p; |
3951 | uint32_t namelen, type; | 4246 | uint32_t namelen, type; |
3952 | 4247 | ||
3953 | p = xdr_inline_decode(xdr, 32); | 4248 | p = xdr_inline_decode(xdr, 32); /* read 32 bytes */ |
3954 | if (unlikely(!p)) | 4249 | if (unlikely(!p)) |
3955 | goto out_overflow; | 4250 | goto out_overflow; |
3956 | p = xdr_decode_hyper(p, &offset); | 4251 | p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */ |
3957 | p = xdr_decode_hyper(p, &length); | 4252 | p = xdr_decode_hyper(p, &length); |
3958 | type = be32_to_cpup(p++); | 4253 | type = be32_to_cpup(p++); /* 4 byte read */ |
3959 | if (fl != NULL) { | 4254 | if (fl != NULL) { /* manipulate file lock */ |
3960 | fl->fl_start = (loff_t)offset; | 4255 | fl->fl_start = (loff_t)offset; |
3961 | fl->fl_end = fl->fl_start + (loff_t)length - 1; | 4256 | fl->fl_end = fl->fl_start + (loff_t)length - 1; |
3962 | if (length == ~(uint64_t)0) | 4257 | if (length == ~(uint64_t)0) |
@@ -3966,9 +4261,9 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
3966 | fl->fl_type = F_RDLCK; | 4261 | fl->fl_type = F_RDLCK; |
3967 | fl->fl_pid = 0; | 4262 | fl->fl_pid = 0; |
3968 | } | 4263 | } |
3969 | p = xdr_decode_hyper(p, &clientid); | 4264 | p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */ |
3970 | namelen = be32_to_cpup(p); | 4265 | namelen = be32_to_cpup(p); /* read 4 bytes */ /* have read all 32 bytes now */ |
3971 | p = xdr_inline_decode(xdr, namelen); | 4266 | p = xdr_inline_decode(xdr, namelen); /* variable size field */ |
3972 | if (likely(p)) | 4267 | if (likely(p)) |
3973 | return -NFS4ERR_DENIED; | 4268 | return -NFS4ERR_DENIED; |
3974 | out_overflow: | 4269 | out_overflow: |
@@ -4200,12 +4495,9 @@ out_overflow: | |||
4200 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) | 4495 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) |
4201 | { | 4496 | { |
4202 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 4497 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
4203 | struct page *page = *rcvbuf->pages; | ||
4204 | struct kvec *iov = rcvbuf->head; | 4498 | struct kvec *iov = rcvbuf->head; |
4205 | size_t hdrlen; | 4499 | size_t hdrlen; |
4206 | u32 recvd, pglen = rcvbuf->page_len; | 4500 | u32 recvd, pglen = rcvbuf->page_len; |
4207 | __be32 *end, *entry, *p, *kaddr; | ||
4208 | unsigned int nr = 0; | ||
4209 | int status; | 4501 | int status; |
4210 | 4502 | ||
4211 | status = decode_op_hdr(xdr, OP_READDIR); | 4503 | status = decode_op_hdr(xdr, OP_READDIR); |
@@ -4225,71 +4517,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
4225 | pglen = recvd; | 4517 | pglen = recvd; |
4226 | xdr_read_pages(xdr, pglen); | 4518 | xdr_read_pages(xdr, pglen); |
4227 | 4519 | ||
4228 | BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); | 4520 | |
4229 | kaddr = p = kmap_atomic(page, KM_USER0); | ||
4230 | end = p + ((pglen + readdir->pgbase) >> 2); | ||
4231 | entry = p; | ||
4232 | |||
4233 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
4234 | if ((entry + 1) > end) | ||
4235 | goto short_pkt; | ||
4236 | |||
4237 | for (; *p++; nr++) { | ||
4238 | u32 len, attrlen, xlen; | ||
4239 | if (end - p < 3) | ||
4240 | goto short_pkt; | ||
4241 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | ||
4242 | p += 2; /* cookie */ | ||
4243 | len = ntohl(*p++); /* filename length */ | ||
4244 | if (len > NFS4_MAXNAMLEN) { | ||
4245 | dprintk("NFS: giant filename in readdir (len 0x%x)\n", | ||
4246 | len); | ||
4247 | goto err_unmap; | ||
4248 | } | ||
4249 | xlen = XDR_QUADLEN(len); | ||
4250 | if (end - p < xlen + 1) | ||
4251 | goto short_pkt; | ||
4252 | dprintk("filename = %*s\n", len, (char *)p); | ||
4253 | p += xlen; | ||
4254 | len = ntohl(*p++); /* bitmap length */ | ||
4255 | if (end - p < len + 1) | ||
4256 | goto short_pkt; | ||
4257 | p += len; | ||
4258 | attrlen = XDR_QUADLEN(ntohl(*p++)); | ||
4259 | if (end - p < attrlen + 2) | ||
4260 | goto short_pkt; | ||
4261 | p += attrlen; /* attributes */ | ||
4262 | entry = p; | ||
4263 | } | ||
4264 | /* | ||
4265 | * Apparently some server sends responses that are a valid size, but | ||
4266 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
4267 | * those, just set the EOF marker. | ||
4268 | */ | ||
4269 | if (!nr && entry[1] == 0) { | ||
4270 | dprintk("NFS: readdir reply truncated!\n"); | ||
4271 | entry[1] = 1; | ||
4272 | } | ||
4273 | out: | ||
4274 | kunmap_atomic(kaddr, KM_USER0); | ||
4275 | return 0; | 4521 | return 0; |
4276 | short_pkt: | ||
4277 | /* | ||
4278 | * When we get a short packet there are 2 possibilities. We can | ||
4279 | * return an error, or fix up the response to look like a valid | ||
4280 | * response and return what we have so far. If there are no | ||
4281 | * entries and the packet was short, then return -EIO. If there | ||
4282 | * are valid entries in the response, return them and pretend that | ||
4283 | * the call was successful, but incomplete. The caller can retry the | ||
4284 | * readdir starting at the last cookie. | ||
4285 | */ | ||
4286 | dprintk("%s: short packet at entry %d\n", __func__, nr); | ||
4287 | entry[0] = entry[1] = 0; | ||
4288 | if (nr) | ||
4289 | goto out; | ||
4290 | err_unmap: | ||
4291 | kunmap_atomic(kaddr, KM_USER0); | ||
4292 | return -errno_NFSERR_IO; | ||
4293 | } | 4522 | } |
4294 | 4523 | ||
4295 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | 4524 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) |
@@ -4299,7 +4528,6 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
4299 | size_t hdrlen; | 4528 | size_t hdrlen; |
4300 | u32 len, recvd; | 4529 | u32 len, recvd; |
4301 | __be32 *p; | 4530 | __be32 *p; |
4302 | char *kaddr; | ||
4303 | int status; | 4531 | int status; |
4304 | 4532 | ||
4305 | status = decode_op_hdr(xdr, OP_READLINK); | 4533 | status = decode_op_hdr(xdr, OP_READLINK); |
@@ -4330,9 +4558,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
4330 | * and and null-terminate the text (the VFS expects | 4558 | * and and null-terminate the text (the VFS expects |
4331 | * null-termination). | 4559 | * null-termination). |
4332 | */ | 4560 | */ |
4333 | kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0); | 4561 | xdr_terminate_string(rcvbuf, len); |
4334 | kaddr[len+rcvbuf->page_base] = '\0'; | ||
4335 | kunmap_atomic(kaddr, KM_USER0); | ||
4336 | return 0; | 4562 | return 0; |
4337 | out_overflow: | 4563 | out_overflow: |
4338 | print_overflow_msg(__func__, xdr); | 4564 | print_overflow_msg(__func__, xdr); |
@@ -4668,7 +4894,6 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4668 | struct rpc_rqst *rqstp) | 4894 | struct rpc_rqst *rqstp) |
4669 | { | 4895 | { |
4670 | #if defined(CONFIG_NFS_V4_1) | 4896 | #if defined(CONFIG_NFS_V4_1) |
4671 | struct nfs4_slot *slot; | ||
4672 | struct nfs4_sessionid id; | 4897 | struct nfs4_sessionid id; |
4673 | u32 dummy; | 4898 | u32 dummy; |
4674 | int status; | 4899 | int status; |
@@ -4700,15 +4925,14 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4700 | goto out_overflow; | 4925 | goto out_overflow; |
4701 | 4926 | ||
4702 | /* seqid */ | 4927 | /* seqid */ |
4703 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4704 | dummy = be32_to_cpup(p++); | 4928 | dummy = be32_to_cpup(p++); |
4705 | if (dummy != slot->seq_nr) { | 4929 | if (dummy != res->sr_slot->seq_nr) { |
4706 | dprintk("%s Invalid sequence number\n", __func__); | 4930 | dprintk("%s Invalid sequence number\n", __func__); |
4707 | goto out_err; | 4931 | goto out_err; |
4708 | } | 4932 | } |
4709 | /* slot id */ | 4933 | /* slot id */ |
4710 | dummy = be32_to_cpup(p++); | 4934 | dummy = be32_to_cpup(p++); |
4711 | if (dummy != res->sr_slotid) { | 4935 | if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) { |
4712 | dprintk("%s Invalid slot id\n", __func__); | 4936 | dprintk("%s Invalid slot id\n", __func__); |
4713 | goto out_err; | 4937 | goto out_err; |
4714 | } | 4938 | } |
@@ -4731,6 +4955,134 @@ out_overflow: | |||
4731 | #endif /* CONFIG_NFS_V4_1 */ | 4955 | #endif /* CONFIG_NFS_V4_1 */ |
4732 | } | 4956 | } |
4733 | 4957 | ||
4958 | #if defined(CONFIG_NFS_V4_1) | ||
4959 | |||
4960 | static int decode_getdeviceinfo(struct xdr_stream *xdr, | ||
4961 | struct pnfs_device *pdev) | ||
4962 | { | ||
4963 | __be32 *p; | ||
4964 | uint32_t len, type; | ||
4965 | int status; | ||
4966 | |||
4967 | status = decode_op_hdr(xdr, OP_GETDEVICEINFO); | ||
4968 | if (status) { | ||
4969 | if (status == -ETOOSMALL) { | ||
4970 | p = xdr_inline_decode(xdr, 4); | ||
4971 | if (unlikely(!p)) | ||
4972 | goto out_overflow; | ||
4973 | pdev->mincount = be32_to_cpup(p); | ||
4974 | dprintk("%s: Min count too small. mincnt = %u\n", | ||
4975 | __func__, pdev->mincount); | ||
4976 | } | ||
4977 | return status; | ||
4978 | } | ||
4979 | |||
4980 | p = xdr_inline_decode(xdr, 8); | ||
4981 | if (unlikely(!p)) | ||
4982 | goto out_overflow; | ||
4983 | type = be32_to_cpup(p++); | ||
4984 | if (type != pdev->layout_type) { | ||
4985 | dprintk("%s: layout mismatch req: %u pdev: %u\n", | ||
4986 | __func__, pdev->layout_type, type); | ||
4987 | return -EINVAL; | ||
4988 | } | ||
4989 | /* | ||
4990 | * Get the length of the opaque device_addr4. xdr_read_pages places | ||
4991 | * the opaque device_addr4 in the xdr_buf->pages (pnfs_device->pages) | ||
4992 | * and places the remaining xdr data in xdr_buf->tail | ||
4993 | */ | ||
4994 | pdev->mincount = be32_to_cpup(p); | ||
4995 | xdr_read_pages(xdr, pdev->mincount); /* include space for the length */ | ||
4996 | |||
4997 | /* Parse notification bitmap, verifying that it is zero. */ | ||
4998 | p = xdr_inline_decode(xdr, 4); | ||
4999 | if (unlikely(!p)) | ||
5000 | goto out_overflow; | ||
5001 | len = be32_to_cpup(p); | ||
5002 | if (len) { | ||
5003 | int i; | ||
5004 | |||
5005 | p = xdr_inline_decode(xdr, 4 * len); | ||
5006 | if (unlikely(!p)) | ||
5007 | goto out_overflow; | ||
5008 | for (i = 0; i < len; i++, p++) { | ||
5009 | if (be32_to_cpup(p)) { | ||
5010 | dprintk("%s: notifications not supported\n", | ||
5011 | __func__); | ||
5012 | return -EIO; | ||
5013 | } | ||
5014 | } | ||
5015 | } | ||
5016 | return 0; | ||
5017 | out_overflow: | ||
5018 | print_overflow_msg(__func__, xdr); | ||
5019 | return -EIO; | ||
5020 | } | ||
5021 | |||
5022 | static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | ||
5023 | struct nfs4_layoutget_res *res) | ||
5024 | { | ||
5025 | __be32 *p; | ||
5026 | int status; | ||
5027 | u32 layout_count; | ||
5028 | |||
5029 | status = decode_op_hdr(xdr, OP_LAYOUTGET); | ||
5030 | if (status) | ||
5031 | return status; | ||
5032 | p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE); | ||
5033 | if (unlikely(!p)) | ||
5034 | goto out_overflow; | ||
5035 | res->return_on_close = be32_to_cpup(p++); | ||
5036 | p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE); | ||
5037 | layout_count = be32_to_cpup(p); | ||
5038 | if (!layout_count) { | ||
5039 | dprintk("%s: server responded with empty layout array\n", | ||
5040 | __func__); | ||
5041 | return -EINVAL; | ||
5042 | } | ||
5043 | |||
5044 | p = xdr_inline_decode(xdr, 24); | ||
5045 | if (unlikely(!p)) | ||
5046 | goto out_overflow; | ||
5047 | p = xdr_decode_hyper(p, &res->range.offset); | ||
5048 | p = xdr_decode_hyper(p, &res->range.length); | ||
5049 | res->range.iomode = be32_to_cpup(p++); | ||
5050 | res->type = be32_to_cpup(p++); | ||
5051 | |||
5052 | status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p); | ||
5053 | if (unlikely(status)) | ||
5054 | return status; | ||
5055 | |||
5056 | dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n", | ||
5057 | __func__, | ||
5058 | (unsigned long)res->range.offset, | ||
5059 | (unsigned long)res->range.length, | ||
5060 | res->range.iomode, | ||
5061 | res->type, | ||
5062 | res->layout.len); | ||
5063 | |||
5064 | /* nfs4_proc_layoutget allocated a single page */ | ||
5065 | if (res->layout.len > PAGE_SIZE) | ||
5066 | return -ENOMEM; | ||
5067 | memcpy(res->layout.buf, p, res->layout.len); | ||
5068 | |||
5069 | if (layout_count > 1) { | ||
5070 | /* We only handle a length one array at the moment. Any | ||
5071 | * further entries are just ignored. Note that this means | ||
5072 | * the client may see a response that is less than the | ||
5073 | * minimum it requested. | ||
5074 | */ | ||
5075 | dprintk("%s: server responded with %d layouts, dropping tail\n", | ||
5076 | __func__, layout_count); | ||
5077 | } | ||
5078 | |||
5079 | return 0; | ||
5080 | out_overflow: | ||
5081 | print_overflow_msg(__func__, xdr); | ||
5082 | return -EIO; | ||
5083 | } | ||
5084 | #endif /* CONFIG_NFS_V4_1 */ | ||
5085 | |||
4734 | /* | 5086 | /* |
4735 | * END OF "GENERIC" DECODE ROUTINES. | 5087 | * END OF "GENERIC" DECODE ROUTINES. |
4736 | */ | 5088 | */ |
@@ -4873,7 +5225,7 @@ out: | |||
4873 | /* | 5225 | /* |
4874 | * Decode RENAME response | 5226 | * Decode RENAME response |
4875 | */ | 5227 | */ |
4876 | static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res) | 5228 | static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs_renameres *res) |
4877 | { | 5229 | { |
4878 | struct xdr_stream xdr; | 5230 | struct xdr_stream xdr; |
4879 | struct compound_hdr hdr; | 5231 | struct compound_hdr hdr; |
@@ -5758,25 +6110,84 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p, | |||
5758 | status = decode_reclaim_complete(&xdr, (void *)NULL); | 6110 | status = decode_reclaim_complete(&xdr, (void *)NULL); |
5759 | return status; | 6111 | return status; |
5760 | } | 6112 | } |
6113 | |||
6114 | /* | ||
6115 | * Decode GETDEVINFO response | ||
6116 | */ | ||
6117 | static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp, uint32_t *p, | ||
6118 | struct nfs4_getdeviceinfo_res *res) | ||
6119 | { | ||
6120 | struct xdr_stream xdr; | ||
6121 | struct compound_hdr hdr; | ||
6122 | int status; | ||
6123 | |||
6124 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
6125 | status = decode_compound_hdr(&xdr, &hdr); | ||
6126 | if (status != 0) | ||
6127 | goto out; | ||
6128 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
6129 | if (status != 0) | ||
6130 | goto out; | ||
6131 | status = decode_getdeviceinfo(&xdr, res->pdev); | ||
6132 | out: | ||
6133 | return status; | ||
6134 | } | ||
6135 | |||
6136 | /* | ||
6137 | * Decode LAYOUTGET response | ||
6138 | */ | ||
6139 | static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp, uint32_t *p, | ||
6140 | struct nfs4_layoutget_res *res) | ||
6141 | { | ||
6142 | struct xdr_stream xdr; | ||
6143 | struct compound_hdr hdr; | ||
6144 | int status; | ||
6145 | |||
6146 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
6147 | status = decode_compound_hdr(&xdr, &hdr); | ||
6148 | if (status) | ||
6149 | goto out; | ||
6150 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
6151 | if (status) | ||
6152 | goto out; | ||
6153 | status = decode_putfh(&xdr); | ||
6154 | if (status) | ||
6155 | goto out; | ||
6156 | status = decode_layoutget(&xdr, rqstp, res); | ||
6157 | out: | ||
6158 | return status; | ||
6159 | } | ||
5761 | #endif /* CONFIG_NFS_V4_1 */ | 6160 | #endif /* CONFIG_NFS_V4_1 */ |
5762 | 6161 | ||
5763 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 6162 | __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, |
6163 | struct nfs_server *server, int plus) | ||
5764 | { | 6164 | { |
5765 | uint32_t bitmap[2] = {0}; | 6165 | uint32_t bitmap[2] = {0}; |
5766 | uint32_t len; | 6166 | uint32_t len; |
5767 | 6167 | __be32 *p = xdr_inline_decode(xdr, 4); | |
5768 | if (!*p++) { | 6168 | if (unlikely(!p)) |
5769 | if (!*p) | 6169 | goto out_overflow; |
6170 | if (!ntohl(*p++)) { | ||
6171 | p = xdr_inline_decode(xdr, 4); | ||
6172 | if (unlikely(!p)) | ||
6173 | goto out_overflow; | ||
6174 | if (!ntohl(*p++)) | ||
5770 | return ERR_PTR(-EAGAIN); | 6175 | return ERR_PTR(-EAGAIN); |
5771 | entry->eof = 1; | 6176 | entry->eof = 1; |
5772 | return ERR_PTR(-EBADCOOKIE); | 6177 | return ERR_PTR(-EBADCOOKIE); |
5773 | } | 6178 | } |
5774 | 6179 | ||
6180 | p = xdr_inline_decode(xdr, 12); | ||
6181 | if (unlikely(!p)) | ||
6182 | goto out_overflow; | ||
5775 | entry->prev_cookie = entry->cookie; | 6183 | entry->prev_cookie = entry->cookie; |
5776 | p = xdr_decode_hyper(p, &entry->cookie); | 6184 | p = xdr_decode_hyper(p, &entry->cookie); |
5777 | entry->len = ntohl(*p++); | 6185 | entry->len = ntohl(*p++); |
6186 | |||
6187 | p = xdr_inline_decode(xdr, entry->len); | ||
6188 | if (unlikely(!p)) | ||
6189 | goto out_overflow; | ||
5778 | entry->name = (const char *) p; | 6190 | entry->name = (const char *) p; |
5779 | p += XDR_QUADLEN(entry->len); | ||
5780 | 6191 | ||
5781 | /* | 6192 | /* |
5782 | * In case the server doesn't return an inode number, | 6193 | * In case the server doesn't return an inode number, |
@@ -5784,32 +6195,33 @@ __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | |||
5784 | * since glibc seems to choke on it...) | 6195 | * since glibc seems to choke on it...) |
5785 | */ | 6196 | */ |
5786 | entry->ino = 1; | 6197 | entry->ino = 1; |
6198 | entry->fattr->valid = 0; | ||
5787 | 6199 | ||
5788 | len = ntohl(*p++); /* bitmap length */ | 6200 | if (decode_attr_bitmap(xdr, bitmap) < 0) |
5789 | if (len-- > 0) { | 6201 | goto out_overflow; |
5790 | bitmap[0] = ntohl(*p++); | 6202 | |
5791 | if (len-- > 0) { | 6203 | if (decode_attr_length(xdr, &len, &p) < 0) |
5792 | bitmap[1] = ntohl(*p++); | 6204 | goto out_overflow; |
5793 | p += len; | 6205 | |
5794 | } | 6206 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, server, 1) < 0) |
5795 | } | 6207 | goto out_overflow; |
5796 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ | 6208 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) |
5797 | if (len > 0) { | 6209 | entry->ino = entry->fattr->fileid; |
5798 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { | 6210 | |
5799 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | 6211 | if (verify_attr_len(xdr, p, len) < 0) |
5800 | /* Ignore the return value of rdattr_error for now */ | 6212 | goto out_overflow; |
5801 | p++; | 6213 | |
5802 | len--; | 6214 | p = xdr_inline_peek(xdr, 8); |
5803 | } | 6215 | if (p != NULL) |
5804 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) | 6216 | entry->eof = !p[0] && p[1]; |
5805 | xdr_decode_hyper(p, &entry->ino); | 6217 | else |
5806 | else if (bitmap[0] == FATTR4_WORD0_FILEID) | 6218 | entry->eof = 0; |
5807 | xdr_decode_hyper(p, &entry->ino); | ||
5808 | p += len; | ||
5809 | } | ||
5810 | 6219 | ||
5811 | entry->eof = !p[0] && p[1]; | ||
5812 | return p; | 6220 | return p; |
6221 | |||
6222 | out_overflow: | ||
6223 | print_overflow_msg(__func__, xdr); | ||
6224 | return ERR_PTR(-EIO); | ||
5813 | } | 6225 | } |
5814 | 6226 | ||
5815 | /* | 6227 | /* |
@@ -5936,6 +6348,8 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
5936 | PROC(SEQUENCE, enc_sequence, dec_sequence), | 6348 | PROC(SEQUENCE, enc_sequence, dec_sequence), |
5937 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | 6349 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), |
5938 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), | 6350 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), |
6351 | PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), | ||
6352 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), | ||
5939 | #endif /* CONFIG_NFS_V4_1 */ | 6353 | #endif /* CONFIG_NFS_V4_1 */ |
5940 | }; | 6354 | }; |
5941 | 6355 | ||