aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4xdr.c
diff options
context:
space:
mode:
authorBryan Schumaker <bjschuma@netapp.com>2010-10-20 15:44:29 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-10-23 15:27:33 -0400
commitbabddc72a9468884ce1a23db3c3d54b0afa299f0 (patch)
treeb176e5795b47c73c47543acdc546da0c38619ddc /fs/nfs/nfs4xdr.c
parentba8e452a4fe64a51b74d43761e14d99f0666cc45 (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.c71
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;
3974out_overflow: 3974out_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
5842out_overflow:
5843 print_overflow_msg(__func__, xdr);
5844 return ERR_PTR(-EIO);
5808} 5845}
5809 5846
5810/* 5847/*