diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2010-10-20 15:44:29 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-10-23 15:27:33 -0400 |
commit | babddc72a9468884ce1a23db3c3d54b0afa299f0 (patch) | |
tree | b176e5795b47c73c47543acdc546da0c38619ddc /fs/nfs/nfs4xdr.c | |
parent | ba8e452a4fe64a51b74d43761e14d99f0666cc45 (diff) |
NFS: decode_dirent should use an xdr_stream
Convert nfs*xdr.c to use an xdr stream in decode_dirent. This will prevent a
kernel oops that has been occuring when reading a vmapped page.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 71 |
1 files changed, 54 insertions, 17 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6ea5c9392fe4..a4919e999354 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -3950,13 +3950,13 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
3950 | __be32 *p; | 3950 | __be32 *p; |
3951 | uint32_t namelen, type; | 3951 | uint32_t namelen, type; |
3952 | 3952 | ||
3953 | p = xdr_inline_decode(xdr, 32); | 3953 | p = xdr_inline_decode(xdr, 32); /* read 32 bytes */ |
3954 | if (unlikely(!p)) | 3954 | if (unlikely(!p)) |
3955 | goto out_overflow; | 3955 | goto out_overflow; |
3956 | p = xdr_decode_hyper(p, &offset); | 3956 | p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */ |
3957 | p = xdr_decode_hyper(p, &length); | 3957 | p = xdr_decode_hyper(p, &length); |
3958 | type = be32_to_cpup(p++); | 3958 | type = be32_to_cpup(p++); /* 4 byte read */ |
3959 | if (fl != NULL) { | 3959 | if (fl != NULL) { /* manipulate file lock */ |
3960 | fl->fl_start = (loff_t)offset; | 3960 | fl->fl_start = (loff_t)offset; |
3961 | fl->fl_end = fl->fl_start + (loff_t)length - 1; | 3961 | fl->fl_end = fl->fl_start + (loff_t)length - 1; |
3962 | if (length == ~(uint64_t)0) | 3962 | if (length == ~(uint64_t)0) |
@@ -3966,9 +3966,9 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl) | |||
3966 | fl->fl_type = F_RDLCK; | 3966 | fl->fl_type = F_RDLCK; |
3967 | fl->fl_pid = 0; | 3967 | fl->fl_pid = 0; |
3968 | } | 3968 | } |
3969 | p = xdr_decode_hyper(p, &clientid); | 3969 | p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */ |
3970 | namelen = be32_to_cpup(p); | 3970 | namelen = be32_to_cpup(p); /* read 4 bytes */ /* have read all 32 bytes now */ |
3971 | p = xdr_inline_decode(xdr, namelen); | 3971 | p = xdr_inline_decode(xdr, namelen); /* variable size field */ |
3972 | if (likely(p)) | 3972 | if (likely(p)) |
3973 | return -NFS4ERR_DENIED; | 3973 | return -NFS4ERR_DENIED; |
3974 | out_overflow: | 3974 | out_overflow: |
@@ -5755,21 +5755,33 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p, | |||
5755 | } | 5755 | } |
5756 | #endif /* CONFIG_NFS_V4_1 */ | 5756 | #endif /* CONFIG_NFS_V4_1 */ |
5757 | 5757 | ||
5758 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5758 | __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, int plus) |
5759 | { | 5759 | { |
5760 | uint32_t bitmap[2] = {0}; | 5760 | uint32_t bitmap[2] = {0}; |
5761 | uint32_t len; | 5761 | uint32_t len; |
5762 | 5762 | __be32 *p = xdr_inline_decode(xdr, 4); | |
5763 | if (!*p++) { | 5763 | if (unlikely(!p)) |
5764 | if (!*p) | 5764 | goto out_overflow; |
5765 | if (!ntohl(*p++)) { | ||
5766 | p = xdr_inline_decode(xdr, 4); | ||
5767 | if (unlikely(!p)) | ||
5768 | goto out_overflow; | ||
5769 | if (!ntohl(*p++)) | ||
5765 | return ERR_PTR(-EAGAIN); | 5770 | return ERR_PTR(-EAGAIN); |
5766 | entry->eof = 1; | 5771 | entry->eof = 1; |
5767 | return ERR_PTR(-EBADCOOKIE); | 5772 | return ERR_PTR(-EBADCOOKIE); |
5768 | } | 5773 | } |
5769 | 5774 | ||
5775 | p = xdr_inline_decode(xdr, 12); | ||
5776 | if (unlikely(!p)) | ||
5777 | goto out_overflow; | ||
5770 | entry->prev_cookie = entry->cookie; | 5778 | entry->prev_cookie = entry->cookie; |
5771 | p = xdr_decode_hyper(p, &entry->cookie); | 5779 | p = xdr_decode_hyper(p, &entry->cookie); |
5772 | entry->len = ntohl(*p++); | 5780 | entry->len = ntohl(*p++); |
5781 | |||
5782 | p = xdr_inline_decode(xdr, entry->len + 4); | ||
5783 | if (unlikely(!p)) | ||
5784 | goto out_overflow; | ||
5773 | entry->name = (const char *) p; | 5785 | entry->name = (const char *) p; |
5774 | p += XDR_QUADLEN(entry->len); | 5786 | p += XDR_QUADLEN(entry->len); |
5775 | 5787 | ||
@@ -5782,29 +5794,54 @@ __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | |||
5782 | 5794 | ||
5783 | len = ntohl(*p++); /* bitmap length */ | 5795 | len = ntohl(*p++); /* bitmap length */ |
5784 | if (len-- > 0) { | 5796 | if (len-- > 0) { |
5797 | p = xdr_inline_decode(xdr, 4); | ||
5798 | if (unlikely(!p)) | ||
5799 | goto out_overflow; | ||
5785 | bitmap[0] = ntohl(*p++); | 5800 | bitmap[0] = ntohl(*p++); |
5786 | if (len-- > 0) { | 5801 | if (len-- > 0) { |
5802 | p = xdr_inline_decode(xdr, 4); | ||
5803 | if (unlikely(!p)) | ||
5804 | goto out_overflow; | ||
5787 | bitmap[1] = ntohl(*p++); | 5805 | bitmap[1] = ntohl(*p++); |
5788 | p += len; | 5806 | p += len; |
5789 | } | 5807 | } |
5790 | } | 5808 | } |
5809 | p = xdr_inline_decode(xdr, 4); | ||
5810 | if (unlikely(!p)) | ||
5811 | goto out_overflow; | ||
5791 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ | 5812 | len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */ |
5792 | if (len > 0) { | 5813 | if (len > 0) { |
5793 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { | 5814 | if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) { |
5794 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; | 5815 | bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; |
5795 | /* Ignore the return value of rdattr_error for now */ | 5816 | /* Ignore the return value of rdattr_error for now */ |
5796 | p++; | 5817 | p = xdr_inline_decode(xdr, 4); |
5797 | len--; | 5818 | if (unlikely(!p)) |
5819 | goto out_overflow; | ||
5798 | } | 5820 | } |
5799 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) | 5821 | if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID) { |
5822 | p = xdr_inline_decode(xdr, 8); | ||
5823 | if (unlikely(!p)) | ||
5824 | goto out_overflow; | ||
5800 | xdr_decode_hyper(p, &entry->ino); | 5825 | xdr_decode_hyper(p, &entry->ino); |
5801 | else if (bitmap[0] == FATTR4_WORD0_FILEID) | 5826 | } else if (bitmap[0] == FATTR4_WORD0_FILEID) { |
5827 | p = xdr_inline_decode(xdr, 8); | ||
5828 | if (unlikely(!p)) | ||
5829 | goto out_overflow; | ||
5802 | xdr_decode_hyper(p, &entry->ino); | 5830 | xdr_decode_hyper(p, &entry->ino); |
5803 | p += len; | 5831 | } |
5804 | } | 5832 | } |
5805 | 5833 | ||
5806 | entry->eof = !p[0] && p[1]; | 5834 | p = xdr_inline_peek(xdr, 8); |
5835 | if (p != NULL) | ||
5836 | entry->eof = !p[0] && p[1]; | ||
5837 | else | ||
5838 | entry->eof = 0; | ||
5839 | |||
5807 | return p; | 5840 | return p; |
5841 | |||
5842 | out_overflow: | ||
5843 | print_overflow_msg(__func__, xdr); | ||
5844 | return ERR_PTR(-EIO); | ||
5808 | } | 5845 | } |
5809 | 5846 | ||
5810 | /* | 5847 | /* |