patch-2.4.20 linux-2.4.20/fs/nfs/nfs2xdr.c
Next file: linux-2.4.20/fs/nfs/nfs3proc.c
Previous file: linux-2.4.20/fs/nfs/mount_clnt.c
Back to the patch index
Back to the overall index
- Lines: 437
- Date:
Thu Nov 28 15:53:15 2002
- Orig file:
linux-2.4.19/fs/nfs/nfs2xdr.c
- Orig date:
Mon Feb 25 11:38:09 2002
diff -urN linux-2.4.19/fs/nfs/nfs2xdr.c linux-2.4.20/fs/nfs/nfs2xdr.c
@@ -24,9 +24,6 @@
#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
-/* Uncomment this to support servers requiring longword lengths */
-#define NFS_PAD_WRITES 1
-
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
@@ -90,17 +87,6 @@
return p + XDR_QUADLEN(NFS2_FHSIZE);
}
-static inline u32 *
-xdr_decode_string2(u32 *p, char **string, unsigned int *len,
- unsigned int maxlen)
-{
- *len = ntohl(*p++);
- if (*len > maxlen)
- return NULL;
- *string = (char *) p;
- return p + XDR_QUADLEN(*len);
-}
-
static inline u32*
xdr_decode_time(u32 *p, u64 *timep)
{
@@ -109,7 +95,7 @@
return p;
}
-static inline u32 *
+static u32 *
xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
{
fattr->type = (enum nfs_ftype) ntohl(*p++);
@@ -223,35 +209,20 @@
nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
- int buflen, replen;
- unsigned int nr;
+ unsigned int replen;
+ u32 offset = (u32)args->offset;
+ u32 count = args->count;
p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->offset);
- *p++ = htonl(args->count);
- *p++ = htonl(args->count);
+ *p++ = htonl(offset);
+ *p++ = htonl(count);
+ *p++ = htonl(count);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Get the number of buffers in the receive iovec */
- nr = args->nriov;
-
- if (nr+2 > MAX_IOVEC) {
- printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
- return -EINVAL;
- }
-
- /* set up reply iovec */
+ /* Inline the page array */
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
- buflen = req->rq_rvec[0].iov_len;
- req->rq_rvec[0].iov_len = replen;
- /* Copy the iovec */
- memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
-
- req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
- req->rq_rvec[nr+1].iov_len = buflen - replen;
- req->rq_rlen = args->count + buflen;
- req->rq_rnr += nr+1;
-
+ xdr_inline_pages(&req->rq_rcv_buf, replen,
+ args->pages, args->pgbase, count);
return 0;
}
@@ -261,6 +232,7 @@
static int
nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
{
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct iovec *iov = req->rq_rvec;
int status, count, recvd, hdrlen;
@@ -269,26 +241,33 @@
p = xdr_decode_fattr(p, res->fattr);
count = ntohl(*p++);
+ res->eof = 0;
+ if (rcvbuf->page_len) {
+ u32 end = page_offset(rcvbuf->pages[0]) + rcvbuf->page_base + count;
+ if (end >= res->fattr->size)
+ res->eof = 1;
+ }
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- if (iov->iov_len > hdrlen) {
+ if (iov->iov_len < hdrlen) {
+ printk(KERN_WARNING "NFS: READ reply header overflowed:"
+ "length %d > %Zu\n", hdrlen, iov->iov_len);
+ return -errno_NFSERR_IO;
+ } else if (iov->iov_len != hdrlen) {
dprintk("NFS: READ header is short. iovec will be shifted.\n");
- xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+ xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
}
- recvd = req->rq_rlen - hdrlen;
+ recvd = req->rq_received - hdrlen;
if (count > recvd) {
printk(KERN_WARNING "NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd);
count = recvd;
+ res->eof = 0;
}
dprintk("RPC: readres OK count %d\n", count);
- if (count < res->count) {
- xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+ if (count < res->count)
res->count = count;
- res->eof = 1; /* Silly NFSv3ism which can't be helped */
- } else
- res->eof = 0;
return count;
}
@@ -300,46 +279,19 @@
static int
nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
{
- unsigned int nr;
+ struct xdr_buf *sndbuf = &req->rq_snd_buf;
+ u32 offset = (u32)args->offset;
u32 count = args->count;
p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->offset);
- *p++ = htonl(args->offset);
+ *p++ = htonl(offset);
+ *p++ = htonl(offset);
*p++ = htonl(count);
*p++ = htonl(count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
-
- /* Get the number of buffers in the send iovec */
- nr = args->nriov;
-
- if (nr+2 > MAX_IOVEC) {
- printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
- "(nr %d max %d)\n", nr, MAX_IOVEC);
- return -EINVAL;
- }
-
- /* Copy the iovec */
- memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
-
-#ifdef NFS_PAD_WRITES
- /*
- * Some old servers require that the message length
- * be a multiple of 4, so we pad it here if needed.
- */
- if (count & 3) {
- struct iovec *iov = req->rq_svec + nr + 1;
- int pad = 4 - (count & 3);
-
- iov->iov_base = (void *) "\0\0\0";
- iov->iov_len = pad;
- count += pad;
- nr++;
- }
-#endif
- req->rq_slen += count;
- req->rq_snr += nr;
+ sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
+ /* Copy the page array */
+ xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
return 0;
}
@@ -406,32 +358,24 @@
{
struct rpc_task *task = req->rq_task;
struct rpc_auth *auth = task->tk_auth;
- u32 bufsiz = args->bufsiz;
- int buflen, replen;
+ unsigned int replen;
+ u32 count = args->count;
/*
* Some servers (e.g. HP OS 9.5) seem to expect the buffer size
* to be in longwords ... check whether to convert the size.
*/
if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
- bufsiz = bufsiz >> 2;
+ count = count >> 2;
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->cookie);
- *p++ = htonl(bufsiz); /* see above */
+ *p++ = htonl(count); /* see above */
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* set up reply iovec */
+ /* Inline the page array */
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
- buflen = req->rq_rvec[0].iov_len;
- req->rq_rvec[0].iov_len = replen;
- req->rq_rvec[1].iov_base = args->buffer;
- req->rq_rvec[1].iov_len = args->bufsiz;
- req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
- req->rq_rvec[2].iov_len = buflen - replen;
- req->rq_rlen = buflen + args->bufsiz;
- req->rq_rnr += 2;
-
+ xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
return 0;
}
@@ -443,28 +387,38 @@
* from nfs_readdir for each entry.
*/
static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
+nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
{
- struct iovec *iov = req->rq_rvec;
- int hdrlen;
- int status, nr;
- u32 *end, *entry, len;
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct iovec *iov = rcvbuf->head;
+ struct page **page;
+ int hdrlen, recvd;
+ int status, nr;
+ unsigned int len, pglen;
+ u32 *end, *entry;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- if (iov->iov_len > hdrlen) {
+ if (iov->iov_len < hdrlen) {
+ printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
+ "length %d > %Zu\n", hdrlen, iov->iov_len);
+ return -errno_NFSERR_IO;
+ } else if (iov->iov_len != hdrlen) {
dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
- xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+ xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
}
-
- /* Get start and end address of XDR data */
- p = (u32 *) iov[1].iov_base;
- end = (u32 *) ((u8 *) p + iov[1].iov_len);
+ pglen = rcvbuf->page_len;
+ recvd = req->rq_received - hdrlen;
+ if (pglen > recvd)
+ pglen = recvd;
+ page = rcvbuf->pages;
+ p = kmap(*page);
+ entry = p;
+ end = (u32 *)((char *)p + pglen);
for (nr = 0; *p++; nr++) {
- entry = p - 1;
if (p + 2 > end)
goto short_pkt;
p++; /* fileid */
@@ -473,16 +427,28 @@
if (len > NFS2_MAXNAMLEN) {
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
len);
- return -errno_NFSERR_IO;
+ goto err_unmap;
}
if (p + 2 > end)
goto short_pkt;
+ entry = p;
}
+ if (!nr && (entry[0] != 0 || entry[1] == 0))
+ goto short_pkt;
+ out:
+ kunmap(*page);
return nr;
short_pkt:
- printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
entry[0] = entry[1] = 0;
- return nr;
+ /* truncate listing ? */
+ if (!nr) {
+ printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
+ entry[1] = 1;
+ }
+ goto out;
+err_unmap:
+ kunmap(*page);
+ return -errno_NFSERR_IO;
}
u32 *
@@ -568,21 +534,16 @@
static int
nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
{
- struct rpc_task *task = req->rq_task;
- struct rpc_auth *auth = task->tk_auth;
- int buflen, replen;
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+ u32 count = args->count - 4;
p = xdr_encode_fhandle(p, args->fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+ /* Inline the page array */
replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
- buflen = req->rq_rvec[0].iov_len;
- req->rq_rvec[0].iov_len = replen;
- req->rq_rvec[1].iov_base = args->buffer;
- req->rq_rvec[1].iov_len = args->bufsiz;
- req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
- req->rq_rvec[2].iov_len = buflen - replen;
- req->rq_rlen = buflen + args->bufsiz;
- req->rq_rnr += 2;
+ xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
return 0;
}
@@ -590,32 +551,33 @@
* Decode READLINK reply
*/
static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
{
- struct iovec *iov = req->rq_rvec;
- u32 *strlen;
+ struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+ struct iovec *iov = rcvbuf->head;
+ unsigned int hdrlen;
+ u32 *strlen, len;
char *string;
- int hdrlen;
int status;
- unsigned int len;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len > hdrlen) {
dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
- xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+ xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
}
- strlen = (u32*)res->buffer;
+ strlen = (u32*)kmap(rcvbuf->pages[0]);
/* Convert length of symlink */
len = ntohl(*strlen);
- if (len > res->bufsiz - 5)
- len = res->bufsiz - 5;
+ if (len > rcvbuf->page_len)
+ len = rcvbuf->page_len;
*strlen = len;
/* NULL terminate the string we got */
string = (char *)(strlen + 1);
string[len] = 0;
+ kunmap(rcvbuf->pages[0]);
return 0;
}
@@ -732,33 +694,32 @@
# define MAX(a, b) (((a) > (b))? (a) : (b))
#endif
-#define PROC(proc, argtype, restype) \
- { "nfs_" #proc, \
- (kxdrproc_t) nfs_xdr_##argtype, \
- (kxdrproc_t) nfs_xdr_##restype, \
- MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
- 0 \
+#define PROC(proc, argtype, restype, timer) \
+ { .p_procname = "nfs_" #proc, \
+ .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
+ .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
+ .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
+ .p_timer = timer \
}
-
static struct rpc_procinfo nfs_procedures[18] = {
- PROC(null, enc_void, dec_void),
- PROC(getattr, fhandle, attrstat),
- PROC(setattr, sattrargs, attrstat),
- PROC(root, enc_void, dec_void),
- PROC(lookup, diropargs, diropres),
- PROC(readlink, readlinkargs, readlinkres),
- PROC(read, readargs, readres),
- PROC(writecache, enc_void, dec_void),
- PROC(write, writeargs, writeres),
- PROC(create, createargs, diropres),
- PROC(remove, diropargs, stat),
- PROC(rename, renameargs, stat),
- PROC(link, linkargs, stat),
- PROC(symlink, symlinkargs, stat),
- PROC(mkdir, createargs, diropres),
- PROC(rmdir, diropargs, stat),
- PROC(readdir, readdirargs, readdirres),
- PROC(statfs, fhandle, statfsres),
+ PROC(null, enc_void, dec_void, 0),
+ PROC(getattr, fhandle, attrstat, 1),
+ PROC(setattr, sattrargs, attrstat, 0),
+ PROC(root, enc_void, dec_void, 0),
+ PROC(lookup, diropargs, diropres, 2),
+ PROC(readlink, readlinkargs, readlinkres, 3),
+ PROC(read, readargs, readres, 3),
+ PROC(writecache, enc_void, dec_void, 0),
+ PROC(write, writeargs, writeres, 4),
+ PROC(create, createargs, diropres, 0),
+ PROC(remove, diropargs, stat, 0),
+ PROC(rename, renameargs, stat, 0),
+ PROC(link, linkargs, stat, 0),
+ PROC(symlink, symlinkargs, stat, 0),
+ PROC(mkdir, createargs, diropres, 0),
+ PROC(rmdir, diropargs, stat, 0),
+ PROC(readdir, readdirargs, readdirres, 3),
+ PROC(statfs, fhandle, statfsres, 0),
};
struct rpc_version nfs_version2 = {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)