diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-25 16:48:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-25 16:48:29 -0400 |
commit | 74eb94b218d087798a52c0b4f1379b635287a4b8 (patch) | |
tree | 4e467c3014c2b1169f6f71d88cf5d1598f3ce28e /fs/nfs/nfs4xdr.c | |
parent | 7b6181e06841f5ad15c4ff708b967b4db65a64de (diff) | |
parent | 9a84d38031c258a17bb39beed1e500eadee67407 (diff) |
Merge branch 'nfs-for-2.6.37' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'nfs-for-2.6.37' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (67 commits)
SUNRPC: Cleanup duplicate assignment in rpcauth_refreshcred
nfs: fix unchecked value
Ask for time_delta during fsinfo probe
Revalidate caches on lock
SUNRPC: After calling xprt_release(), we must restart from call_reserve
NFSv4: Fix up the 'dircount' hint in encode_readdir
NFSv4: Clean up nfs4_decode_dirent
NFSv4: nfs4_decode_dirent must clear entry->fattr->valid
NFSv4: Fix a regression in decode_getfattr
NFSv4: Fix up decode_attr_filehandle() to handle the case of empty fh pointer
NFS: Ensure we check all allocation return values in new readdir code
NFS: Readdir plus in v4
NFS: introduce generic decode_getattr function
NFS: check xdr_decode for errors
NFS: nfs_readdir_filler catch all errors
NFS: readdir with vmapped pages
NFS: remove page size checking code
NFS: decode_dirent should use an xdr_stream
SUNRPC: Add a helper function xdr_inline_peek
NFS: remove readdir plus limit
...
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 340 |
1 files changed, 197 insertions, 143 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 08ef91291132..bd2101d918c8 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -816,7 +816,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
816 | if (iap->ia_valid & ATTR_MODE) | 816 | if (iap->ia_valid & ATTR_MODE) |
817 | len += 4; | 817 | len += 4; |
818 | if (iap->ia_valid & ATTR_UID) { | 818 | if (iap->ia_valid & ATTR_UID) { |
819 | owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name); | 819 | owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name, IDMAP_NAMESZ); |
820 | if (owner_namelen < 0) { | 820 | if (owner_namelen < 0) { |
821 | dprintk("nfs: couldn't resolve uid %d to string\n", | 821 | dprintk("nfs: couldn't resolve uid %d to string\n", |
822 | iap->ia_uid); | 822 | iap->ia_uid); |
@@ -828,7 +828,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
828 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); | 828 | len += 4 + (XDR_QUADLEN(owner_namelen) << 2); |
829 | } | 829 | } |
830 | if (iap->ia_valid & ATTR_GID) { | 830 | if (iap->ia_valid & ATTR_GID) { |
831 | owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group); | 831 | owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group, IDMAP_NAMESZ); |
832 | if (owner_grouplen < 0) { | 832 | if (owner_grouplen < 0) { |
833 | dprintk("nfs: couldn't resolve gid %d to string\n", | 833 | dprintk("nfs: couldn't resolve gid %d to string\n", |
834 | iap->ia_gid); | 834 | iap->ia_gid); |
@@ -1385,24 +1385,35 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1385 | 1385 | ||
1386 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1386 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
1387 | { | 1387 | { |
1388 | uint32_t attrs[2] = { | 1388 | uint32_t attrs[2] = {0, 0}; |
1389 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | 1389 | uint32_t dircount = readdir->count >> 1; |
1390 | FATTR4_WORD1_MOUNTED_ON_FILEID, | ||
1391 | }; | ||
1392 | __be32 *p; | 1390 | __be32 *p; |
1393 | 1391 | ||
1392 | if (readdir->plus) { | ||
1393 | attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE| | ||
1394 | FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE; | ||
1395 | attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER| | ||
1396 | FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV| | ||
1397 | FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS| | ||
1398 | FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | ||
1399 | dircount >>= 1; | ||
1400 | } | ||
1401 | attrs[0] |= FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID; | ||
1402 | attrs[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
1403 | /* Switch to mounted_on_fileid if the server supports it */ | ||
1404 | if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
1405 | attrs[0] &= ~FATTR4_WORD0_FILEID; | ||
1406 | else | ||
1407 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | ||
1408 | |||
1394 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); | 1409 | p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20); |
1395 | *p++ = cpu_to_be32(OP_READDIR); | 1410 | *p++ = cpu_to_be32(OP_READDIR); |
1396 | p = xdr_encode_hyper(p, readdir->cookie); | 1411 | p = xdr_encode_hyper(p, readdir->cookie); |
1397 | p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE); | 1412 | 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 */ | 1413 | *p++ = cpu_to_be32(dircount); |
1399 | *p++ = cpu_to_be32(readdir->count); | 1414 | *p++ = cpu_to_be32(readdir->count); |
1400 | *p++ = cpu_to_be32(2); | 1415 | *p++ = cpu_to_be32(2); |
1401 | /* Switch to mounted_on_fileid if the server supports it */ | 1416 | |
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]); | 1417 | *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); |
1407 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); | 1418 | *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); |
1408 | hdr->nops++; | 1419 | hdr->nops++; |
@@ -1823,7 +1834,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1823 | /* | 1834 | /* |
1824 | * Encode RENAME request | 1835 | * Encode RENAME request |
1825 | */ | 1836 | */ |
1826 | static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args) | 1837 | static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs_renameargs *args) |
1827 | { | 1838 | { |
1828 | struct xdr_stream xdr; | 1839 | struct xdr_stream xdr; |
1829 | struct compound_hdr hdr = { | 1840 | struct compound_hdr hdr = { |
@@ -2676,7 +2687,10 @@ out_overflow: | |||
2676 | static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) | 2687 | static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask) |
2677 | { | 2688 | { |
2678 | if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) { | 2689 | if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) { |
2679 | decode_attr_bitmap(xdr, bitmask); | 2690 | int ret; |
2691 | ret = decode_attr_bitmap(xdr, bitmask); | ||
2692 | if (unlikely(ret < 0)) | ||
2693 | return ret; | ||
2680 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; | 2694 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; |
2681 | } else | 2695 | } else |
2682 | bitmask[0] = bitmask[1] = 0; | 2696 | bitmask[0] = bitmask[1] = 0; |
@@ -2848,6 +2862,56 @@ out_overflow: | |||
2848 | return -EIO; | 2862 | return -EIO; |
2849 | } | 2863 | } |
2850 | 2864 | ||
2865 | static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap) | ||
2866 | { | ||
2867 | __be32 *p; | ||
2868 | |||
2869 | if (unlikely(bitmap[0] & (FATTR4_WORD0_RDATTR_ERROR - 1U))) | ||
2870 | return -EIO; | ||
2871 | if (likely(bitmap[0] & FATTR4_WORD0_RDATTR_ERROR)) { | ||
2872 | p = xdr_inline_decode(xdr, 4); | ||
2873 | if (unlikely(!p)) | ||
2874 | goto out_overflow; | ||
2875 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | ||
2876 | } | ||
2877 | return 0; | ||
2878 | out_overflow: | ||
2879 | print_overflow_msg(__func__, xdr); | ||
2880 | return -EIO; | ||
2881 | } | ||
2882 | |||
2883 | static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh) | ||
2884 | { | ||
2885 | __be32 *p; | ||
2886 | int len; | ||
2887 | |||
2888 | if (fh != NULL) | ||
2889 | memset(fh, 0, sizeof(*fh)); | ||
2890 | |||
2891 | if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEHANDLE - 1U))) | ||
2892 | return -EIO; | ||
2893 | if (likely(bitmap[0] & FATTR4_WORD0_FILEHANDLE)) { | ||
2894 | p = xdr_inline_decode(xdr, 4); | ||
2895 | if (unlikely(!p)) | ||
2896 | goto out_overflow; | ||
2897 | len = be32_to_cpup(p); | ||
2898 | if (len > NFS4_FHSIZE) | ||
2899 | return -EIO; | ||
2900 | p = xdr_inline_decode(xdr, len); | ||
2901 | if (unlikely(!p)) | ||
2902 | goto out_overflow; | ||
2903 | if (fh != NULL) { | ||
2904 | memcpy(fh->data, p, len); | ||
2905 | fh->size = len; | ||
2906 | } | ||
2907 | bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE; | ||
2908 | } | ||
2909 | return 0; | ||
2910 | out_overflow: | ||
2911 | print_overflow_msg(__func__, xdr); | ||
2912 | return -EIO; | ||
2913 | } | ||
2914 | |||
2851 | static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) | 2915 | static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res) |
2852 | { | 2916 | { |
2853 | __be32 *p; | 2917 | __be32 *p; |
@@ -3521,6 +3585,24 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s | |||
3521 | return status; | 3585 | return status; |
3522 | } | 3586 | } |
3523 | 3587 | ||
3588 | static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap, | ||
3589 | struct timespec *time) | ||
3590 | { | ||
3591 | int status = 0; | ||
3592 | |||
3593 | time->tv_sec = 0; | ||
3594 | time->tv_nsec = 0; | ||
3595 | if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U))) | ||
3596 | return -EIO; | ||
3597 | if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) { | ||
3598 | status = decode_attr_time(xdr, time); | ||
3599 | bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA; | ||
3600 | } | ||
3601 | dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec, | ||
3602 | (long)time->tv_nsec); | ||
3603 | return status; | ||
3604 | } | ||
3605 | |||
3524 | static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) | 3606 | static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) |
3525 | { | 3607 | { |
3526 | int status = 0; | 3608 | int status = 0; |
@@ -3744,29 +3826,14 @@ xdr_error: | |||
3744 | return status; | 3826 | return status; |
3745 | } | 3827 | } |
3746 | 3828 | ||
3747 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | 3829 | static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, |
3830 | struct nfs_fattr *fattr, struct nfs_fh *fh, | ||
3748 | const struct nfs_server *server, int may_sleep) | 3831 | const struct nfs_server *server, int may_sleep) |
3749 | { | 3832 | { |
3750 | __be32 *savep; | ||
3751 | uint32_t attrlen, | ||
3752 | bitmap[2] = {0}, | ||
3753 | type; | ||
3754 | int status; | 3833 | int status; |
3755 | umode_t fmode = 0; | 3834 | umode_t fmode = 0; |
3756 | uint64_t fileid; | 3835 | uint64_t fileid; |
3757 | 3836 | 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 | 3837 | ||
3771 | status = decode_attr_type(xdr, bitmap, &type); | 3838 | status = decode_attr_type(xdr, bitmap, &type); |
3772 | if (status < 0) | 3839 | if (status < 0) |
@@ -3792,6 +3859,14 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | |||
3792 | goto xdr_error; | 3859 | goto xdr_error; |
3793 | fattr->valid |= status; | 3860 | fattr->valid |= status; |
3794 | 3861 | ||
3862 | status = decode_attr_error(xdr, bitmap); | ||
3863 | if (status < 0) | ||
3864 | goto xdr_error; | ||
3865 | |||
3866 | status = decode_attr_filehandle(xdr, bitmap, fh); | ||
3867 | if (status < 0) | ||
3868 | goto xdr_error; | ||
3869 | |||
3795 | status = decode_attr_fileid(xdr, bitmap, &fattr->fileid); | 3870 | status = decode_attr_fileid(xdr, bitmap, &fattr->fileid); |
3796 | if (status < 0) | 3871 | if (status < 0) |
3797 | goto xdr_error; | 3872 | goto xdr_error; |
@@ -3862,12 +3937,46 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | |||
3862 | fattr->valid |= status; | 3937 | fattr->valid |= status; |
3863 | } | 3938 | } |
3864 | 3939 | ||
3940 | xdr_error: | ||
3941 | dprintk("%s: xdr returned %d\n", __func__, -status); | ||
3942 | return status; | ||
3943 | } | ||
3944 | |||
3945 | static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, | ||
3946 | struct nfs_fh *fh, const struct nfs_server *server, int may_sleep) | ||
3947 | { | ||
3948 | __be32 *savep; | ||
3949 | uint32_t attrlen, | ||
3950 | bitmap[2] = {0}; | ||
3951 | int status; | ||
3952 | |||
3953 | status = decode_op_hdr(xdr, OP_GETATTR); | ||
3954 | if (status < 0) | ||
3955 | goto xdr_error; | ||
3956 | |||
3957 | status = decode_attr_bitmap(xdr, bitmap); | ||
3958 | if (status < 0) | ||
3959 | goto xdr_error; | ||
3960 | |||
3961 | status = decode_attr_length(xdr, &attrlen, &savep); | ||
3962 | if (status < 0) | ||
3963 | goto xdr_error; | ||
3964 | |||
3965 | status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep); | ||
3966 | if (status < 0) | ||
3967 | goto xdr_error; | ||
3968 | |||
3865 | status = verify_attr_len(xdr, savep, attrlen); | 3969 | status = verify_attr_len(xdr, savep, attrlen); |
3866 | xdr_error: | 3970 | xdr_error: |
3867 | dprintk("%s: xdr returned %d\n", __func__, -status); | 3971 | dprintk("%s: xdr returned %d\n", __func__, -status); |
3868 | return status; | 3972 | return status; |
3869 | } | 3973 | } |
3870 | 3974 | ||
3975 | static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, | ||
3976 | const struct nfs_server *server, int may_sleep) | ||
3977 | { | ||
3978 | return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep); | ||
3979 | } | ||
3871 | 3980 | ||
3872 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | 3981 | static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) |
3873 | { | 3982 | { |
@@ -3894,6 +4003,9 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo) | |||
3894 | if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) | 4003 | if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0) |
3895 | goto xdr_error; | 4004 | goto xdr_error; |
3896 | fsinfo->wtpref = fsinfo->wtmax; | 4005 | fsinfo->wtpref = fsinfo->wtmax; |
4006 | status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta); | ||
4007 | if (status != 0) | ||
4008 | goto xdr_error; | ||
3897 | 4009 | ||
3898 | status = verify_attr_len(xdr, savep, attrlen); | 4010 | status = verify_attr_len(xdr, savep, attrlen); |
3899 | xdr_error: | 4011 | xdr_error: |
@@ -3950,13 +4062,13 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
3950 | __be32 *p; | 4062 | __be32 *p; |
3951 | uint32_t namelen, type; | 4063 | uint32_t namelen, type; |
3952 | 4064 | ||
3953 | p = xdr_inline_decode(xdr, 32); | 4065 | p = xdr_inline_decode(xdr, 32); /* read 32 bytes */ |
3954 | if (unlikely(!p)) | 4066 | if (unlikely(!p)) |
3955 | goto out_overflow; | 4067 | goto out_overflow; |
3956 | p = xdr_decode_hyper(p, &offset); | 4068 | p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */ |
3957 | p = xdr_decode_hyper(p, &length); | 4069 | p = xdr_decode_hyper(p, &length); |
3958 | type = be32_to_cpup(p++); | 4070 | type = be32_to_cpup(p++); /* 4 byte read */ |
3959 | if (fl != NULL) { | 4071 | if (fl != NULL) { /* manipulate file lock */ |
3960 | fl->fl_start = (loff_t)offset; | 4072 | fl->fl_start = (loff_t)offset; |
3961 | fl->fl_end = fl->fl_start + (loff_t)length - 1; | 4073 | fl->fl_end = fl->fl_start + (loff_t)length - 1; |
3962 | if (length == ~(uint64_t)0) | 4074 | if (length == ~(uint64_t)0) |
@@ -3966,9 +4078,9 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
3966 | fl->fl_type = F_RDLCK; | 4078 | fl->fl_type = F_RDLCK; |
3967 | fl->fl_pid = 0; | 4079 | fl->fl_pid = 0; |
3968 | } | 4080 | } |
3969 | p = xdr_decode_hyper(p, &clientid); | 4081 | p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */ |
3970 | namelen = be32_to_cpup(p); | 4082 | namelen = be32_to_cpup(p); /* read 4 bytes */ /* have read all 32 bytes now */ |
3971 | p = xdr_inline_decode(xdr, namelen); | 4083 | p = xdr_inline_decode(xdr, namelen); /* variable size field */ |
3972 | if (likely(p)) | 4084 | if (likely(p)) |
3973 | return -NFS4ERR_DENIED; | 4085 | return -NFS4ERR_DENIED; |
3974 | out_overflow: | 4086 | out_overflow: |
@@ -4200,12 +4312,9 @@ out_overflow: | |||
4200 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) | 4312 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) |
4201 | { | 4313 | { |
4202 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | 4314 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; |
4203 | struct page *page = *rcvbuf->pages; | ||
4204 | struct kvec *iov = rcvbuf->head; | 4315 | struct kvec *iov = rcvbuf->head; |
4205 | size_t hdrlen; | 4316 | size_t hdrlen; |
4206 | u32 recvd, pglen = rcvbuf->page_len; | 4317 | u32 recvd, pglen = rcvbuf->page_len; |
4207 | __be32 *end, *entry, *p, *kaddr; | ||
4208 | unsigned int nr = 0; | ||
4209 | int status; | 4318 | int status; |
4210 | 4319 | ||
4211 | status = decode_op_hdr(xdr, OP_READDIR); | 4320 | status = decode_op_hdr(xdr, OP_READDIR); |
@@ -4225,71 +4334,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
4225 | pglen = recvd; | 4334 | pglen = recvd; |
4226 | xdr_read_pages(xdr, pglen); | 4335 | xdr_read_pages(xdr, pglen); |
4227 | 4336 | ||
4228 | BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); | 4337 | |
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; | 4338 | 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 | } | 4339 | } |
4294 | 4340 | ||
4295 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | 4341 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) |
@@ -4299,7 +4345,6 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
4299 | size_t hdrlen; | 4345 | size_t hdrlen; |
4300 | u32 len, recvd; | 4346 | u32 len, recvd; |
4301 | __be32 *p; | 4347 | __be32 *p; |
4302 | char *kaddr; | ||
4303 | int status; | 4348 | int status; |
4304 | 4349 | ||
4305 | status = decode_op_hdr(xdr, OP_READLINK); | 4350 | status = decode_op_hdr(xdr, OP_READLINK); |
@@ -4330,9 +4375,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | |||
4330 | * and and null-terminate the text (the VFS expects | 4375 | * and and null-terminate the text (the VFS expects |
4331 | * null-termination). | 4376 | * null-termination). |
4332 | */ | 4377 | */ |
4333 | kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0); | 4378 | xdr_terminate_string(rcvbuf, len); |
4334 | kaddr[len+rcvbuf->page_base] = '\0'; | ||
4335 | kunmap_atomic(kaddr, KM_USER0); | ||
4336 | return 0; | 4379 | return 0; |
4337 | out_overflow: | 4380 | out_overflow: |
4338 | print_overflow_msg(__func__, xdr); | 4381 | print_overflow_msg(__func__, xdr); |
@@ -4668,7 +4711,6 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4668 | struct rpc_rqst *rqstp) | 4711 | struct rpc_rqst *rqstp) |
4669 | { | 4712 | { |
4670 | #if defined(CONFIG_NFS_V4_1) | 4713 | #if defined(CONFIG_NFS_V4_1) |
4671 | struct nfs4_slot *slot; | ||
4672 | struct nfs4_sessionid id; | 4714 | struct nfs4_sessionid id; |
4673 | u32 dummy; | 4715 | u32 dummy; |
4674 | int status; | 4716 | int status; |
@@ -4700,15 +4742,14 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4700 | goto out_overflow; | 4742 | goto out_overflow; |
4701 | 4743 | ||
4702 | /* seqid */ | 4744 | /* seqid */ |
4703 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4704 | dummy = be32_to_cpup(p++); | 4745 | dummy = be32_to_cpup(p++); |
4705 | if (dummy != slot->seq_nr) { | 4746 | if (dummy != res->sr_slot->seq_nr) { |
4706 | dprintk("%s Invalid sequence number\n", __func__); | 4747 | dprintk("%s Invalid sequence number\n", __func__); |
4707 | goto out_err; | 4748 | goto out_err; |
4708 | } | 4749 | } |
4709 | /* slot id */ | 4750 | /* slot id */ |
4710 | dummy = be32_to_cpup(p++); | 4751 | dummy = be32_to_cpup(p++); |
4711 | if (dummy != res->sr_slotid) { | 4752 | if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) { |
4712 | dprintk("%s Invalid slot id\n", __func__); | 4753 | dprintk("%s Invalid slot id\n", __func__); |
4713 | goto out_err; | 4754 | goto out_err; |
4714 | } | 4755 | } |
@@ -4873,7 +4914,7 @@ out: | |||
4873 | /* | 4914 | /* |
4874 | * Decode RENAME response | 4915 | * Decode RENAME response |
4875 | */ | 4916 | */ |
4876 | static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res) | 4917 | static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs_renameres *res) |
4877 | { | 4918 | { |
4878 | struct xdr_stream xdr; | 4919 | struct xdr_stream xdr; |
4879 | struct compound_hdr hdr; | 4920 | struct compound_hdr hdr; |
@@ -5760,23 +5801,35 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p, | |||
5760 | } | 5801 | } |
5761 | #endif /* CONFIG_NFS_V4_1 */ | 5802 | #endif /* CONFIG_NFS_V4_1 */ |
5762 | 5803 | ||
5763 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5804 | __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, |
5805 | struct nfs_server *server, int plus) | ||
5764 | { | 5806 | { |
5765 | uint32_t bitmap[2] = {0}; | 5807 | uint32_t bitmap[2] = {0}; |
5766 | uint32_t len; | 5808 | uint32_t len; |
5767 | 5809 | __be32 *p = xdr_inline_decode(xdr, 4); | |
5768 | if (!*p++) { | 5810 | if (unlikely(!p)) |
5769 | if (!*p) | 5811 | goto out_overflow; |
5812 | if (!ntohl(*p++)) { | ||
5813 | p = xdr_inline_decode(xdr, 4); | ||
5814 | if (unlikely(!p)) | ||
5815 | goto out_overflow; | ||
5816 | if (!ntohl(*p++)) | ||
5770 | return ERR_PTR(-EAGAIN); | 5817 | return ERR_PTR(-EAGAIN); |
5771 | entry->eof = 1; | 5818 | entry->eof = 1; |
5772 | return ERR_PTR(-EBADCOOKIE); | 5819 | return ERR_PTR(-EBADCOOKIE); |
5773 | } | 5820 | } |
5774 | 5821 | ||
5822 | p = xdr_inline_decode(xdr, 12); | ||
5823 | if (unlikely(!p)) | ||
5824 | goto out_overflow; | ||
5775 | entry->prev_cookie = entry->cookie; | 5825 | entry->prev_cookie = entry->cookie; |
5776 | p = xdr_decode_hyper(p, &entry->cookie); | 5826 | p = xdr_decode_hyper(p, &entry->cookie); |
5777 | entry->len = ntohl(*p++); | 5827 | entry->len = ntohl(*p++); |
5828 | |||
5829 | p = xdr_inline_decode(xdr, entry->len); | ||
5830 | if (unlikely(!p)) | ||
5831 | goto out_overflow; | ||
5778 | entry->name = (const char *) p; | 5832 | entry->name = (const char *) p; |
5779 | p += XDR_QUADLEN(entry->len); | ||
5780 | 5833 | ||
5781 | /* | 5834 | /* |
5782 | * In case the server doesn't return an inode number, | 5835 | * In case the server doesn't return an inode number, |
@@ -5784,32 +5837,33 @@ __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | |||
5784 | * since glibc seems to choke on it...) | 5837 | * since glibc seems to choke on it...) |
5785 | */ | 5838 | */ |
5786 | entry->ino = 1; | 5839 | entry->ino = 1; |
5840 | entry->fattr->valid = 0; | ||
5787 | 5841 | ||
5788 | len = ntohl(*p++); /* bitmap length */ | 5842 | if (decode_attr_bitmap(xdr, bitmap) < 0) |
5789 | if (len-- > 0) { | 5843 | goto out_overflow; |
5790 | bitmap[0] = ntohl(*p++); | 5844 | |
5791 | if (len-- > 0) { | 5845 | if (decode_attr_length(xdr, &len, &p) < 0) |
5792 | bitmap[1] = ntohl(*p++); | 5846 | goto out_overflow; |
5793 | p += len; | 5847 | |
5794 | } | 5848 | if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, server, 1) < 0) |
5795 | } | 5849 | goto out_overflow; |
5796 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ | 5850 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) |
5797 | if (len > 0) { | 5851 | entry->ino = entry->fattr->fileid; |
5798 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { | 5852 | |
5799 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | 5853 | if (verify_attr_len(xdr, p, len) < 0) |
5800 | /* Ignore the return value of rdattr_error for now */ | 5854 | goto out_overflow; |
5801 | p++; | 5855 | |
5802 | len--; | 5856 | p = xdr_inline_peek(xdr, 8); |
5803 | } | 5857 | if (p != NULL) |
5804 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) | 5858 | entry->eof = !p[0] && p[1]; |
5805 | xdr_decode_hyper(p, &entry->ino); | 5859 | else |
5806 | else if (bitmap[0] == FATTR4_WORD0_FILEID) | 5860 | entry->eof = 0; |
5807 | xdr_decode_hyper(p, &entry->ino); | ||
5808 | p += len; | ||
5809 | } | ||
5810 | 5861 | ||
5811 | entry->eof = !p[0] && p[1]; | ||
5812 | return p; | 5862 | return p; |
5863 | |||
5864 | out_overflow: | ||
5865 | print_overflow_msg(__func__, xdr); | ||
5866 | return ERR_PTR(-EIO); | ||
5813 | } | 5867 | } |
5814 | 5868 | ||
5815 | /* | 5869 | /* |