diff -u --recursive --new-file linux-2.4.19-fix_kmap1/arch/i386/kernel/i386_ksyms.c linux-2.4.19-fix_kmap2/arch/i386/kernel/i386_ksyms.c --- linux-2.4.19-fix_kmap1/arch/i386/kernel/i386_ksyms.c Sun Jul 7 11:31:54 2002 +++ linux-2.4.19-fix_kmap2/arch/i386/kernel/i386_ksyms.c Thu Jul 25 17:35:23 2002 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -173,6 +174,11 @@ EXPORT_SYMBOL(atomic_dec_and_lock); #endif +#ifdef CONFIG_HIGHMEM +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); +#endif + extern int is_sony_vaio_laptop; EXPORT_SYMBOL(is_sony_vaio_laptop); diff -u --recursive --new-file linux-2.4.19-fix_kmap1/arch/mips/kernel/mips_ksyms.c linux-2.4.19-fix_kmap2/arch/mips/kernel/mips_ksyms.c --- linux-2.4.19-fix_kmap1/arch/mips/kernel/mips_ksyms.c Fri Jun 28 17:00:10 2002 +++ linux-2.4.19-fix_kmap2/arch/mips/kernel/mips_ksyms.c Thu Jul 25 17:35:23 2002 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -127,3 +128,8 @@ #endif EXPORT_SYMBOL(get_wchan); + +#ifdef CONFIG_HIGHMEM +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); +#endif diff -u --recursive --new-file linux-2.4.19-fix_kmap1/arch/ppc/kernel/ppc_ksyms.c linux-2.4.19-fix_kmap2/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.19-fix_kmap1/arch/ppc/kernel/ppc_ksyms.c Mon Mar 11 15:13:27 2002 +++ linux-2.4.19-fix_kmap2/arch/ppc/kernel/ppc_ksyms.c Thu Jul 25 17:35:23 2002 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -364,3 +365,8 @@ EXPORT_SYMBOL_NOVERS(agp_special_page); #endif /* defined(CONFIG_ALL_PPC) */ +#ifdef CONFIG_HIGHMEM +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); +#endif + diff -u --recursive --new-file linux-2.4.19-fix_kmap1/arch/sparc/kernel/sparc_ksyms.c linux-2.4.19-fix_kmap2/arch/sparc/kernel/sparc_ksyms.c --- linux-2.4.19-fix_kmap1/arch/sparc/kernel/sparc_ksyms.c Wed Apr 24 19:18:05 2002 +++ linux-2.4.19-fix_kmap2/arch/sparc/kernel/sparc_ksyms.c Thu Jul 25 17:35:24 2002 @@ -23,6 +23,7 @@ #include #endif #include +#include #include #include @@ -300,3 +301,8 @@ /* Sun Power Management Idle Handler */ EXPORT_SYMBOL(pm_idle); + +#ifdef CONFIG_HIGHMEM +EXPORT_SYMBOL(kmap_prot); +EXPORT_SYMBOL(kmap_pte); +#endif diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/dir.c linux-2.4.19-fix_kmap2/fs/nfs/dir.c --- linux-2.4.19-fix_kmap1/fs/nfs/dir.c Tue Mar 12 16:35:02 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/dir.c Thu Jul 25 17:35:24 2002 @@ -99,13 +99,12 @@ struct file *file = desc->file; struct inode *inode = file->f_dentry->d_inode; struct rpc_cred *cred = nfs_file_cred(file); - void *buffer = kmap(page); int error; dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); again: - error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, buffer, + error = NFS_PROTO(inode)->readdir(inode, cred, desc->entry->cookie, page, NFS_SERVER(inode)->dtsize, desc->plus); /* We requested READDIRPLUS, but the server doesn't grok it */ if (desc->plus && error == -ENOTSUPP) { @@ -116,7 +115,6 @@ if (error < 0) goto error; SetPageUptodate(page); - kunmap(page); /* Ensure consistent page alignment of the data. * Note: assumes we have exclusive access to this mapping either * throught inode->i_sem or some other mechanism. @@ -315,12 +313,12 @@ status = -ENOMEM; goto out; } - desc->page = page; - desc->ptr = kmap(page); desc->error = NFS_PROTO(inode)->readdir(inode, cred, desc->target, - desc->ptr, + page, NFS_SERVER(inode)->dtsize, desc->plus); + desc->page = page; + desc->ptr = kmap(page); if (desc->error >= 0) { if ((status = dir_decode(desc)) == 0) desc->entry->prev_cookie = desc->target; diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/nfs2xdr.c linux-2.4.19-fix_kmap2/fs/nfs/nfs2xdr.c --- linux-2.4.19-fix_kmap1/fs/nfs/nfs2xdr.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/nfs2xdr.c Wed Jul 31 16:26:52 2002 @@ -220,35 +220,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; } @@ -269,7 +254,7 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; 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; @@ -281,7 +266,6 @@ dprintk("RPC: readres OK count %d\n", count); if (count < res->count) { - xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count); res->count = count; res->eof = 1; /* Silly NFSv3ism which can't be helped */ } else @@ -376,32 +360,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; } @@ -413,12 +389,15 @@ * 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; + int status, nr; + unsigned int len, pglen; + u32 *end, *entry; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); @@ -426,13 +405,13 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; 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; + page = rcvbuf->pages; + p = kmap(*page); + end = (u32 *)((char *)p + pglen); for (nr = 0; *p++; nr++) { entry = p - 1; if (p + 2 > end) @@ -443,16 +422,21 @@ 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; } + kunmap(*page); return nr; short_pkt: printk(KERN_NOTICE "NFS: short packet in readdir reply!\n"); entry[0] = entry[1] = 0; + kunmap(*page); return nr; +err_unmap: + kunmap(*page); + return -errno_NFSERR_IO; } u32 * @@ -538,21 +522,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; } @@ -560,32 +539,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; } diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/nfs3proc.c linux-2.4.19-fix_kmap2/fs/nfs/nfs3proc.c --- linux-2.4.19-fix_kmap1/fs/nfs/nfs3proc.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/nfs3proc.c Thu Jul 25 17:35:24 2002 @@ -151,17 +151,16 @@ } static int -nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen) +nfs3_proc_readlink(struct inode *inode, struct page *page) { struct nfs_fattr fattr; - struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen }; - struct nfs3_readlinkres res = { &fattr, buffer, buflen }; + struct nfs3_readlinkargs args = { NFS_FH(inode), PAGE_CACHE_SIZE, &page }; int status; dprintk("NFS call readlink\n"); fattr.valid = 0; status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, - &args, &res, 0); + &args, &fattr, 0); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply readlink: %d\n", status); return status; @@ -170,11 +169,12 @@ static int nfs3_proc_read(struct inode *inode, struct rpc_cred *cred, struct nfs_fattr *fattr, int flags, - loff_t offset, unsigned int count, void *buffer, int *eofp) + unsigned int base, unsigned int count, struct page *page, + int *eofp) { - struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1, - {{buffer, count}, {0,0}, {0,0}, {0,0}, - {0,0}, {0,0}, {0,0}, {0,0}} }; + u64 offset = page_offset(page) + base; + struct nfs_readargs arg = { NFS_FH(inode), offset, count, + base, &page }; struct nfs_readres res = { fattr, count, 0 }; struct rpc_message msg = { NFS3PROC_READ, &arg, &res, cred }; int status; @@ -433,26 +433,16 @@ */ static int nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred, - u64 cookie, void *entry, - unsigned int size, int plus) + u64 cookie, struct page *page, unsigned int count, int plus) { struct nfs_fattr dir_attr; - struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 }; - struct nfs3_readdirres res = { &dir_attr, 0, 0, 0, 0 }; - struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred }; u32 *verf = NFS_COOKIEVERF(dir); + struct nfs3_readdirargs arg = { NFS_FH(dir), cookie, {verf[0], verf[1]}, + plus, count, &page }; + struct nfs3_readdirres res = { &dir_attr, verf, plus }; + struct rpc_message msg = { NFS3PROC_READDIR, &arg, &res, cred }; int status; - arg.buffer = entry; - arg.bufsiz = size; - arg.verf[0] = verf[0]; - arg.verf[1] = verf[1]; - arg.plus = plus; - res.buffer = entry; - res.bufsiz = size; - res.verf = verf; - res.plus = plus; - if (plus) msg.rpc_proc = NFS3PROC_READDIRPLUS; diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/nfs3xdr.c linux-2.4.19-fix_kmap2/fs/nfs/nfs3xdr.c --- linux-2.4.19-fix_kmap1/fs/nfs/nfs3xdr.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/nfs3xdr.c Wed Jul 31 16:27:14 2002 @@ -347,35 +347,18 @@ nfs3_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 count = args->count; p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_hyper(p, args->offset); - *p++ = htonl(args->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 + NFS3_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; } @@ -500,7 +483,8 @@ nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args) { struct rpc_auth *auth = req->rq_task->tk_auth; - int buflen, replen; + unsigned int replen; + u32 count = args->count; p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_hyper(p, args->cookie); @@ -509,22 +493,14 @@ if (args->plus) { /* readdirplus: need dircount + buffer size. * We just make sure we make dircount big enough */ - *p++ = htonl(args->bufsiz >> 3); + *p++ = htonl(count >> 3); } - *p++ = htonl(args->bufsiz); + *p++ = htonl(count); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); - /* set up reply iovec */ + /* Inline the page array */ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_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; } @@ -535,11 +511,13 @@ static int nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res) { - struct iovec *iov = req->rq_rvec; - int hdrlen; - int status, nr; - unsigned int len; - u32 *entry, *end; + struct xdr_buf *rcvbuf = &req->rq_rcv_buf; + struct iovec *iov = rcvbuf->head; + struct page **page; + int hdrlen; + int status, nr; + unsigned int len, pglen; + u32 *entry, *end; status = ntohl(*p++); /* Decode post_op_attrs */ @@ -557,11 +535,13 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; 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); } - p = (u32 *) iov[1].iov_base; - end = (u32 *) ((u8 *) p + iov[1].iov_len); + pglen = rcvbuf->page_len; + page = rcvbuf->pages; + p = kmap(*page); + end = (u32 *)((char *)p + pglen); for (nr = 0; *p++; nr++) { entry = p - 1; if (p + 3 > end) @@ -572,7 +552,7 @@ if (len > NFS3_MAXNAMLEN) { printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n", len); - return -errno_NFSERR_IO; + goto err_unmap; } if (res->plus) { @@ -592,7 +572,7 @@ if (len > NFS3_FHSIZE) { printk(KERN_WARNING "NFS: giant filehandle in " "readdir (len %x)!\n", len); - return -errno_NFSERR_IO; + goto err_unmap; } p += XDR_QUADLEN(len); } @@ -601,13 +581,17 @@ if (p + 2 > end) goto short_pkt; } - + kunmap(*page); return nr; short_pkt: printk(KERN_NOTICE "NFS: short packet in readdir reply!\n"); /* truncate listing */ entry[0] = entry[1] = 0; + kunmap(*page); return nr; +err_unmap: + kunmap(*page); + return -errno_NFSERR_IO; } u32 * @@ -742,21 +726,16 @@ static int nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_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 + NFS3_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; } @@ -764,17 +743,17 @@ * Decode READLINK reply */ static int -nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res) +nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) { - struct iovec *iov = req->rq_rvec; - int hdrlen; - u32 *strlen; + struct xdr_buf *rcvbuf = &req->rq_rcv_buf; + struct iovec *iov = rcvbuf->head; + unsigned int hdrlen; + u32 *strlen, len; char *string; int status; - unsigned int len; status = ntohl(*p++); - p = xdr_decode_post_op_attr(p, res->fattr); + p = xdr_decode_post_op_attr(p, fattr); if (status != 0) return -nfs_stat_to_errno(status); @@ -782,18 +761,19 @@ 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; } @@ -827,7 +807,7 @@ hdrlen = (u8 *) p - (u8 *) iov->iov_base; 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; @@ -837,10 +817,8 @@ count = recvd; } - if (count < res->count) { - xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count); + if (count < res->count) res->count = count; - } return count; } diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/proc.c linux-2.4.19-fix_kmap2/fs/nfs/proc.c --- linux-2.4.19-fix_kmap1/fs/nfs/proc.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/proc.c Thu Jul 25 17:35:24 2002 @@ -106,15 +106,13 @@ } static int -nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz) +nfs_proc_readlink(struct inode *inode, struct page *page) { - struct nfs_readlinkargs args = { NFS_FH(inode), buffer, bufsiz }; - struct nfs_readlinkres res = { buffer, bufsiz }; + struct nfs_readlinkargs args = { NFS_FH(inode), PAGE_CACHE_SIZE, &page }; int status; dprintk("NFS call readlink\n"); - status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, - &args, &res, 0); + status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK, &args, NULL, 0); dprintk("NFS reply readlink: %d\n", status); return status; } @@ -122,11 +120,12 @@ static int nfs_proc_read(struct inode *inode, struct rpc_cred *cred, struct nfs_fattr *fattr, int flags, - loff_t offset, unsigned int count, void *buffer, int *eofp) + unsigned int base, unsigned int count, + struct page *page, int *eofp) { - struct nfs_readargs arg = { NFS_FH(inode), offset, count, 1, - {{ buffer, count }, {0,0}, {0,0}, {0,0}, - {0,0}, {0,0}, {0,0}, {0,0}} }; + u64 offset = page_offset(page) + base; + struct nfs_readargs arg = { NFS_FH(inode), offset, count, + base, &page }; struct nfs_readres res = { fattr, count, 0}; struct rpc_message msg = { NFSPROC_READ, &arg, &res, cred }; int status; @@ -336,21 +335,13 @@ */ static int nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred, - __u64 cookie, void *entry, - unsigned int size, int plus) + __u64 cookie, struct page *page, + unsigned int count, int plus) { - struct nfs_readdirargs arg; - struct nfs_readdirres res; - struct rpc_message msg = { NFSPROC_READDIR, &arg, &res, cred }; + struct nfs_readdirargs arg = { NFS_FH(dir), cookie, count, &page }; + struct rpc_message msg = { NFSPROC_READDIR, &arg, NULL, cred }; int status; - arg.fh = NFS_FH(dir); - arg.cookie = cookie; - arg.buffer = entry; - arg.bufsiz = size; - res.buffer = entry; - res.bufsiz = size; - dprintk("NFS call readdir %d\n", (unsigned int)cookie); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/read.c linux-2.4.19-fix_kmap2/fs/nfs/read.c --- linux-2.4.19-fix_kmap1/fs/nfs/read.c Tue Mar 12 16:34:24 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/read.c Thu Jul 25 17:35:24 2002 @@ -42,6 +42,7 @@ struct nfs_readres res; /* ... and result struct */ struct nfs_fattr fattr; /* fattr storage */ struct list_head pages; /* Coalesced read requests */ + struct page *pagevec[NFS_READ_MAXIOV]; }; /* @@ -63,6 +64,7 @@ if (p) { memset(p, 0, sizeof(*p)); INIT_LIST_HEAD(&p->pages); + p->args.pages = p->pagevec; } return p; } @@ -86,8 +88,7 @@ { struct rpc_cred *cred = NULL; struct nfs_fattr fattr; - loff_t offset = page_offset(page); - char *buffer; + unsigned int offset = 0; int rsize = NFS_SERVER(inode)->rsize; int result; int count = PAGE_CACHE_SIZE; @@ -103,19 +104,18 @@ * This works now because the socket layer never tries to DMA * into this buffer directly. */ - buffer = kmap(page); do { if (count < rsize) rsize = count; - dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n", + dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %u, %u, %p)\n", NFS_SERVER(inode)->hostname, inode->i_dev, (long long)NFS_FILEID(inode), - (long long)offset, rsize, buffer); + offset, rsize, page); lock_kernel(); result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags, - offset, rsize, buffer, &eof); + offset, rsize, page, &eof); nfs_refresh_inode(inode, &fattr); unlock_kernel(); @@ -130,12 +130,15 @@ } count -= result; offset += result; - buffer += result; if (result < rsize) /* NFSv2ism */ break; } while (count); - memset(buffer, 0, count); + if (count) { + char *kaddr = kmap(page); + memset(kaddr + offset, 0, count); + kunmap(page); + } flush_dcache_page(page); SetPageUptodate(page); if (PageError(page)) @@ -143,7 +146,6 @@ result = 0; io_error: - kunmap(page); UnlockPage(page); return result; } @@ -186,26 +188,24 @@ nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data) { struct nfs_page *req; - struct iovec *iov; + struct page **pages; unsigned int count; - iov = data->args.iov; + pages = data->args.pages; count = 0; while (!list_empty(head)) { struct nfs_page *req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_list_add_request(req, &data->pages); - iov->iov_base = kmap(req->wb_page) + req->wb_offset; - iov->iov_len = req->wb_bytes; + *pages++ = req->wb_page; count += req->wb_bytes; - iov++; - data->args.nriov++; } req = nfs_list_entry(data->pages.next); data->inode = req->wb_inode; data->cred = req->wb_cred; data->args.fh = NFS_FH(req->wb_inode); data->args.offset = page_offset(req->wb_page) + req->wb_offset; + data->args.pgbase = req->wb_offset; data->args.count = count; data->res.fattr = &data->fattr; data->res.count = count; @@ -266,10 +266,10 @@ msg.rpc_cred = data->cred; /* Start the async call */ - dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n", + dprintk("NFS: %4d initiated read call (req %x/%Ld count %u.\n", task->tk_pid, inode->i_dev, (long long)NFS_FILEID(inode), - data->args.count, data->args.nriov); + data->args.count); rpc_clnt_sigmask(clnt, &oldset); rpc_call_setup(task, &msg, 0); @@ -424,7 +424,6 @@ } else SetPageError(page); flush_dcache_page(page); - kunmap(page); UnlockPage(page); dprintk("NFS: read (%x/%Ld %d@%Ld)\n", diff -u --recursive --new-file linux-2.4.19-fix_kmap1/fs/nfs/symlink.c linux-2.4.19-fix_kmap2/fs/nfs/symlink.c --- linux-2.4.19-fix_kmap1/fs/nfs/symlink.c Tue Feb 5 08:37:25 2002 +++ linux-2.4.19-fix_kmap2/fs/nfs/symlink.c Thu Jul 25 17:35:25 2002 @@ -29,7 +29,6 @@ */ static int nfs_symlink_filler(struct inode *inode, struct page *page) { - void *buffer = kmap(page); int error; /* We place the length at the beginning of the page, @@ -37,13 +36,11 @@ * XDR response verification will NULL terminate it. */ lock_kernel(); - error = NFS_PROTO(inode)->readlink(inode, buffer, - PAGE_CACHE_SIZE - sizeof(u32)-4); + error = NFS_PROTO(inode)->readlink(inode, page); unlock_kernel(); if (error < 0) goto error; SetPageUptodate(page); - kunmap(page); UnlockPage(page); return 0; diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/asm-i386/kmap_types.h linux-2.4.19-fix_kmap2/include/asm-i386/kmap_types.h --- linux-2.4.19-fix_kmap1/include/asm-i386/kmap_types.h Tue Feb 5 08:45:30 2002 +++ linux-2.4.19-fix_kmap2/include/asm-i386/kmap_types.h Thu Jul 25 17:35:25 2002 @@ -3,7 +3,7 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/asm-mips/kmap_types.h linux-2.4.19-fix_kmap2/include/asm-mips/kmap_types.h --- linux-2.4.19-fix_kmap1/include/asm-mips/kmap_types.h Thu Mar 14 00:31:05 2002 +++ linux-2.4.19-fix_kmap2/include/asm-mips/kmap_types.h Thu Jul 25 17:35:25 2002 @@ -3,7 +3,7 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/asm-ppc/kmap_types.h linux-2.4.19-fix_kmap2/include/asm-ppc/kmap_types.h --- linux-2.4.19-fix_kmap1/include/asm-ppc/kmap_types.h Tue Feb 5 08:45:30 2002 +++ linux-2.4.19-fix_kmap2/include/asm-ppc/kmap_types.h Thu Jul 25 17:35:25 2002 @@ -7,7 +7,7 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/asm-sparc/kmap_types.h linux-2.4.19-fix_kmap2/include/asm-sparc/kmap_types.h --- linux-2.4.19-fix_kmap1/include/asm-sparc/kmap_types.h Tue Feb 5 08:45:30 2002 +++ linux-2.4.19-fix_kmap2/include/asm-sparc/kmap_types.h Thu Jul 25 17:35:26 2002 @@ -3,7 +3,7 @@ enum km_type { KM_BOUNCE_READ, - KM_SKB_DATA, + KM_SKB_SUNRPC_DATA, KM_SKB_DATA_SOFTIRQ, KM_USER0, KM_USER1, diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/linux/nfs_xdr.h linux-2.4.19-fix_kmap2/include/linux/nfs_xdr.h --- linux-2.4.19-fix_kmap1/include/linux/nfs_xdr.h Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/include/linux/nfs_xdr.h Thu Jul 25 17:35:26 2002 @@ -68,8 +68,8 @@ struct nfs_fh * fh; __u64 offset; __u32 count; - unsigned int nriov; - struct iovec iov[NFS_READ_MAXIOV]; + unsigned int pgbase; + struct page ** pages; }; struct nfs_readres { @@ -165,8 +165,8 @@ struct nfs_readdirargs { struct nfs_fh * fh; __u32 cookie; - void * buffer; - unsigned int bufsiz; + unsigned int count; + struct page ** pages; }; struct nfs_diropok { @@ -176,18 +176,8 @@ struct nfs_readlinkargs { struct nfs_fh * fh; - void * buffer; - unsigned int bufsiz; -}; - -struct nfs_readlinkres { - void * buffer; - unsigned int bufsiz; -}; - -struct nfs_readdirres { - void * buffer; - unsigned int bufsiz; + unsigned int count; + struct page ** pages; }; struct nfs3_sattrargs { @@ -262,9 +252,9 @@ struct nfs_fh * fh; __u64 cookie; __u32 verf[2]; - void * buffer; - unsigned int bufsiz; int plus; + unsigned int count; + struct page ** pages; }; struct nfs3_diropres { @@ -280,14 +270,8 @@ struct nfs3_readlinkargs { struct nfs_fh * fh; - void * buffer; - unsigned int bufsiz; -}; - -struct nfs3_readlinkres { - struct nfs_fattr * fattr; - void * buffer; - unsigned int bufsiz; + unsigned int count; + struct page ** pages; }; struct nfs3_renameres { @@ -303,8 +287,6 @@ struct nfs3_readdirres { struct nfs_fattr * dir_attr; __u32 * verf; - void * buffer; - unsigned int bufsiz; int plus; }; @@ -322,11 +304,11 @@ int (*lookup) (struct inode *, struct qstr *, struct nfs_fh *, struct nfs_fattr *); int (*access) (struct inode *, int , int); - int (*readlink)(struct inode *, void *, unsigned int); + int (*readlink)(struct inode *, struct page *); int (*read) (struct inode *, struct rpc_cred *, struct nfs_fattr *, - int, loff_t, unsigned int, - void *buffer, int *eofp); + int, unsigned int, unsigned int, + struct page *, int *eofp); int (*write) (struct inode *, struct rpc_cred *, struct nfs_fattr *, int, unsigned int, unsigned int, @@ -349,7 +331,7 @@ struct nfs_fh *, struct nfs_fattr *); int (*rmdir) (struct inode *, struct qstr *); int (*readdir) (struct inode *, struct rpc_cred *, - u64, void *, unsigned int, int); + u64, struct page *, unsigned int, int); int (*mknod) (struct inode *, struct qstr *, struct iattr *, dev_t, struct nfs_fh *, struct nfs_fattr *); int (*statfs) (struct nfs_server *, struct nfs_fh *, diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/linux/sunrpc/xdr.h linux-2.4.19-fix_kmap2/include/linux/sunrpc/xdr.h --- linux-2.4.19-fix_kmap1/include/linux/sunrpc/xdr.h Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/include/linux/sunrpc/xdr.h Thu Jul 25 18:11:25 2002 @@ -94,6 +94,8 @@ void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int, unsigned int); +void xdr_inline_pages(struct xdr_buf *, unsigned int, + struct page **, unsigned int, unsigned int); /* * Decode 64bit quantities (NFSv3 support) @@ -127,10 +129,38 @@ void xdr_zero_iovec(struct iovec *, int, size_t); /* + * Maximum number of iov's we use. + */ +#define MAX_IOVEC (12) + +/* * XDR buffer helper functions */ extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int); extern void xdr_kunmap(struct xdr_buf *, unsigned int); +extern void xdr_shift_buf(struct xdr_buf *, unsigned int); +extern void xdr_zero_buf(struct xdr_buf *, unsigned int); + +/* + * Helper structure for copying from an sk_buff. + */ +typedef struct { + struct sk_buff *skb; + unsigned int offset; + size_t count; + unsigned int csum; +} skb_reader_t; + +typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len); + +extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, + skb_reader_t *, skb_read_actor_t); + +extern int xdr_copy_skb(struct xdr_buf *xdr, unsigned int base, + struct sk_buff *skb, unsigned int offset); + +extern int xdr_copy_and_csum_skb(struct xdr_buf *xdr, unsigned int base, + struct sk_buff *skb, unsigned int offset, unsigned int csum); #endif /* __KERNEL__ */ diff -u --recursive --new-file linux-2.4.19-fix_kmap1/include/linux/sunrpc/xprt.h linux-2.4.19-fix_kmap2/include/linux/sunrpc/xprt.h --- linux-2.4.19-fix_kmap1/include/linux/sunrpc/xprt.h Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/include/linux/sunrpc/xprt.h Thu Jul 25 17:35:26 2002 @@ -16,11 +16,6 @@ #include /* - * Maximum number of iov's we use. - */ -#define MAX_IOVEC 10 - -/* * The transport code maintains an estimate on the maximum number of out- * standing RPC requests, using a smoothed version of the congestion * avoidance implemented in 44BSD. This is basically the Van Jacobson @@ -89,7 +84,7 @@ struct rpc_xprt * rq_xprt; /* RPC client */ struct rpc_timeout rq_timeout; /* timeout parms */ struct xdr_buf rq_snd_buf; /* send buffer */ - struct rpc_iov rq_rcv_buf; /* recv buffer */ + struct xdr_buf rq_rcv_buf; /* recv buffer */ /* * This is the private part @@ -116,9 +111,8 @@ }; #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len -#define rq_rvec rq_rcv_buf.io_vec -#define rq_rnr rq_rcv_buf.io_nr -#define rq_rlen rq_rcv_buf.io_len +#define rq_rvec rq_rcv_buf.head +#define rq_rlen rq_rcv_buf.len #define XPRT_LAST_FRAG (1 << 0) #define XPRT_COPY_RECM (1 << 1) diff -u --recursive --new-file linux-2.4.19-fix_kmap1/net/sunrpc/clnt.c linux-2.4.19-fix_kmap2/net/sunrpc/clnt.c --- linux-2.4.19-fix_kmap1/net/sunrpc/clnt.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/net/sunrpc/clnt.c Thu Jul 25 17:35:26 2002 @@ -466,6 +466,7 @@ struct rpc_clnt *clnt = task->tk_client; struct rpc_rqst *req = task->tk_rqstp; struct xdr_buf *sndbuf = &req->rq_snd_buf; + struct xdr_buf *rcvbuf = &req->rq_rcv_buf; unsigned int bufsiz; kxdrproc_t encode; int status; @@ -483,10 +484,11 @@ sndbuf->tail[0].iov_len = 0; sndbuf->page_len = 0; sndbuf->len = 0; - req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz); - req->rq_rvec[0].iov_len = bufsiz; - req->rq_rlen = bufsiz; - req->rq_rnr = 1; + rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz); + rcvbuf->head[0].iov_len = bufsiz; + rcvbuf->tail[0].iov_len = 0; + rcvbuf->page_len = 0; + rcvbuf->len = bufsiz; /* Zero buffer so we have automatic zero-padding of opaque & string */ memset(task->tk_buffer, 0, bufsiz); diff -u --recursive --new-file linux-2.4.19-fix_kmap1/net/sunrpc/sunrpc_syms.c linux-2.4.19-fix_kmap2/net/sunrpc/sunrpc_syms.c --- linux-2.4.19-fix_kmap1/net/sunrpc/sunrpc_syms.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/net/sunrpc/sunrpc_syms.c Thu Jul 25 17:35:26 2002 @@ -96,8 +96,8 @@ EXPORT_SYMBOL(xdr_decode_netobj); EXPORT_SYMBOL(xdr_encode_netobj); EXPORT_SYMBOL(xdr_encode_pages); -EXPORT_SYMBOL(xdr_shift_iovec); -EXPORT_SYMBOL(xdr_zero_iovec); +EXPORT_SYMBOL(xdr_inline_pages); +EXPORT_SYMBOL(xdr_shift_buf); /* Debugging symbols */ #ifdef RPC_DEBUG diff -u --recursive --new-file linux-2.4.19-fix_kmap1/net/sunrpc/xdr.c linux-2.4.19-fix_kmap2/net/sunrpc/xdr.c --- linux-2.4.19-fix_kmap1/net/sunrpc/xdr.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/net/sunrpc/xdr.c Thu Jul 25 17:35:26 2002 @@ -121,6 +121,27 @@ xdr->len += len; } +void +xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, + struct page **pages, unsigned int base, unsigned int len) +{ + struct iovec *head = xdr->head; + struct iovec *tail = xdr->tail; + char *buf = (char *)head->iov_base; + unsigned int buflen = head->iov_len; + + head->iov_len = offset; + + xdr->pages = pages; + xdr->page_base = base; + xdr->page_len = len; + + tail->iov_base = buf + offset; + tail->iov_len = buflen - offset; + + xdr->len += len; +} + /* * Realign the iovec if the server missed out some reply elements * (such as post-op attributes,...) @@ -251,3 +272,72 @@ ppage++; } } + +void +xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base, + skb_reader_t *desc, + skb_read_actor_t copy_actor) +{ + struct page **ppage = xdr->pages; + unsigned int len, pglen = xdr->page_len; + int ret; + + len = xdr->head[0].iov_len; + if (base < len) { + len -= base; + ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len); + if (ret != len || !desc->count) + return; + base = 0; + } else + base -= len; + + if (pglen == 0) + goto copy_tail; + if (base >= pglen) { + base -= pglen; + goto copy_tail; + } + if (base || xdr->page_base) { + pglen -= base; + base += xdr->page_base; + ppage += base >> PAGE_CACHE_SHIFT; + base &= ~PAGE_CACHE_MASK; + } + do { + char *kaddr; + + len = PAGE_CACHE_SIZE; + kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA); + if (base) { + len -= base; + if (pglen < len) + len = pglen; + ret = copy_actor(desc, kaddr + base, len); + base = 0; + } else { + if (pglen < len) + len = pglen; + ret = copy_actor(desc, kaddr, len); + } + kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA); + if (ret != len || !desc->count) + return; + ppage++; + } while ((pglen -= len) != 0); +copy_tail: + len = xdr->tail[0].iov_len; + if (len) + copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len); +} + +void +xdr_shift_buf(struct xdr_buf *xdr, size_t len) +{ + struct iovec iov[MAX_IOVEC]; + unsigned int nr; + + nr = xdr_kmap(iov, xdr, 0); + xdr_shift_iovec(iov, nr, len); + xdr_kunmap(xdr, 0); +} diff -u --recursive --new-file linux-2.4.19-fix_kmap1/net/sunrpc/xprt.c linux-2.4.19-fix_kmap2/net/sunrpc/xprt.c --- linux-2.4.19-fix_kmap1/net/sunrpc/xprt.c Thu Jul 25 17:34:51 2002 +++ linux-2.4.19-fix_kmap2/net/sunrpc/xprt.c Thu Jul 25 17:35:26 2002 @@ -566,58 +566,60 @@ return; } +static size_t +skb_read_bits(skb_reader_t *desc, void *to, size_t len) +{ + if (len > desc->count) + len = desc->count; + skb_copy_bits(desc->skb, desc->offset, to, len); + desc->count -= len; + desc->offset += len; + return len; +} + +static size_t +skb_read_and_csum_bits(skb_reader_t *desc, void *to, size_t len) +{ + unsigned int csum2, pos; + + if (len > desc->count) + len = desc->count; + pos = desc->offset; + csum2 = skb_copy_and_csum_bits(desc->skb, pos, to, len, 0); + desc->csum = csum_block_add(desc->csum, csum2, pos); + desc->count -= len; + desc->offset += len; + return len; +} + /* * We have set things up such that we perform the checksum of the UDP * packet in parallel with the copies into the RPC client iovec. -DaveM */ -static int csum_partial_copy_to_page_cache(struct iovec *iov, - struct sk_buff *skb, - int copied) +static int +csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) { - int offset = sizeof(struct udphdr); - __u8 *cur_ptr = iov->iov_base; - __kernel_size_t cur_len = iov->iov_len; - unsigned int csum = skb->csum; - int need_csum = (skb->ip_summed != CHECKSUM_UNNECESSARY); - int slack = skb->len - copied - sizeof(struct udphdr); - - if (need_csum) - csum = csum_partial(skb->data, sizeof(struct udphdr), csum); - while (copied > 0) { - if (cur_len) { - int to_move = cur_len; - if (to_move > copied) - to_move = copied; - if (need_csum) { - unsigned int csum2; - - csum2 = skb_copy_and_csum_bits(skb, offset, - cur_ptr, - to_move, 0); - csum = csum_block_add(csum, csum2, offset); - } else - skb_copy_bits(skb, offset, cur_ptr, to_move); - offset += to_move; - copied -= to_move; - cur_ptr += to_move; - cur_len -= to_move; - } - if (cur_len <= 0) { - iov++; - cur_len = iov->iov_len; - cur_ptr = iov->iov_base; - } - } - if (need_csum) { - if (slack > 0) { - unsigned int csum2; + skb_reader_t desc; - csum2 = skb_checksum(skb, offset, slack, 0); - csum = csum_block_add(csum, csum2, offset); - } - if ((unsigned short)csum_fold(csum)) - return -1; + desc.skb = skb; + desc.offset = sizeof(struct udphdr); + desc.count = skb->len - desc.offset; + + if (skb->ip_summed == CHECKSUM_UNNECESSARY) + goto no_checksum; + + desc.csum = csum_partial(skb->data, desc.offset, skb->csum); + xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits); + if (desc.offset != skb->len) { + unsigned int csum2; + csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0); + desc.csum = csum_block_add(desc.csum, csum2, desc.offset); } + if ((unsigned short)csum_fold(desc.csum)) + return -1; + return 0; +no_checksum: + xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits); return 0; } @@ -668,7 +670,7 @@ copied = repsize; /* Suck it into the iovec, verify checksum if not done by hw. */ - if (csum_partial_copy_to_page_cache(rovr->rq_rvec, skb, copied)) + if (csum_partial_copy_to_xdr(&rovr->rq_rcv_buf, skb)) goto out_unlock; /* Something worked... */ @@ -686,12 +688,6 @@ wake_up_interruptible(sk->sleep); } -typedef struct { - struct sk_buff *skb; - unsigned offset; - size_t count; -} skb_reader_t; - /* * Copy from an skb into memory and shrink the skb. */ @@ -782,11 +778,8 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc) { struct rpc_rqst *req; - struct iovec *iov; - char *p; - unsigned long skip; - size_t len, used; - int n; + struct xdr_buf *rcvbuf; + size_t len; /* Find and lock the request corresponding to this xid */ req = xprt_lookup_rqst(xprt, xprt->tcp_xid); @@ -796,36 +789,30 @@ xprt->tcp_xid); return; } - skip = xprt->tcp_copied; - iov = req->rq_rvec; - for (n = req->rq_rnr; n != 0; n--, iov++) { - if (skip >= iov->iov_len) { - skip -= iov->iov_len; - continue; - } - p = iov->iov_base; - len = iov->iov_len; - if (skip) { - p += skip; - len -= skip; - skip = 0; - } - if (xprt->tcp_offset + len > xprt->tcp_reclen) - len = xprt->tcp_reclen - xprt->tcp_offset; - used = tcp_copy_data(desc, p, len); - xprt->tcp_copied += used; - xprt->tcp_offset += used; - if (used != len) - break; - if (xprt->tcp_copied == req->rq_rlen) { + + rcvbuf = &req->rq_rcv_buf; + len = desc->count; + if (len > xprt->tcp_reclen - xprt->tcp_offset) { + skb_reader_t my_desc; + + len = xprt->tcp_reclen - xprt->tcp_offset; + memcpy(&my_desc, desc, sizeof(my_desc)); + my_desc.count = len; + xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + &my_desc, tcp_copy_data); + desc->count -= len; + desc->offset += len; + } else + xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied, + desc, tcp_copy_data); + xprt->tcp_copied += len; + xprt->tcp_offset += len; + + if (xprt->tcp_copied == req->rq_rlen) + xprt->tcp_flags &= ~XPRT_COPY_DATA; + else if (xprt->tcp_offset == xprt->tcp_reclen) { + if (xprt->tcp_flags & XPRT_LAST_FRAG) xprt->tcp_flags &= ~XPRT_COPY_DATA; - break; - } - if (xprt->tcp_offset == xprt->tcp_reclen) { - if (xprt->tcp_flags & XPRT_LAST_FRAG) - xprt->tcp_flags &= ~XPRT_COPY_DATA; - break; - } } if (!(xprt->tcp_flags & XPRT_COPY_DATA)) {