updated patch for 2.1.89 nfs write padding

Bill Hawes (whawes@star.net)
Sat, 07 Mar 1998 15:22:23 -0500


This is a multi-part message in MIME format.
--------------988699B14E137A4BD103351C
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Based on further analysis of the iovec copy/checksum code, I think the attached
patch may correct the problem with adding pad bytes to NFS writes. The iovec
code was incorrectly exiting too soon in the case where a short non-longword
multiple iovec was followed by another iovec, leading to an incorrect checksum
(and truncated data, for that matter.)

This would occur frequently when a padding iovec was added, and the incorrect
checksums were then being reported as "RPC task timed out" errors on the client
side.

I'd appreciate it if the people who can trigger the "task timed out" messages
could give this a test and see if both the original 'garbage args" and checksum
problems are fixed.

Regards,
Bill
--------------988699B14E137A4BD103351C
Content-Type: text/plain; charset=us-ascii; name="nfs_pad89-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="nfs_pad89-patch"

--- linux-2.1.89/fs/nfs/nfs2xdr.c.old Tue Jan 27 09:36:34 1998
+++ linux-2.1.89/fs/nfs/nfs2xdr.c Sat Mar 7 15:20:58 1998
@@ -22,6 +22,9 @@
#include <linux/sunrpc/clnt.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 */

@@ -258,18 +261,38 @@
static int
nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
{
+ u32 count = args->count;
+
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->offset);
*p++ = htonl(args->offset);
- *p++ = htonl(args->count);
- *p++ = htonl(args->count);
+ *p++ = htonl(count);
+ *p++ = htonl(count);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);

req->rq_svec[1].iov_base = (void *) args->buffer;
- req->rq_svec[1].iov_len = args->count;
- req->rq_slen += args->count;
+ req->rq_svec[1].iov_len = count;
+ req->rq_slen += count;
req->rq_snr = 2;

+#ifdef NFS_PAD_WRITES
+ /*
+ * Some old servers require that the message length
+ * be a multiple of 4, so we pad it here if needed.
+ */
+ count = ((count + 3) & ~3) - count;
+ if (count) {
+#if 0
+printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n",
+req->rq_svec[1].iov_len, req->rq_slen, count);
+#endif
+ req->rq_svec[2].iov_base = (void *) "\0\0\0";
+ req->rq_svec[2].iov_len = count;
+ req->rq_slen += count;
+ req->rq_snr = 3;
+ }
+#endif
+
return 0;
}

--- linux-2.1.89/net/core/iovec.c.old Sat Mar 7 11:32:22 1998
+++ linux-2.1.89/net/core/iovec.c Sat Mar 7 15:28:17 1998
@@ -80,6 +80,8 @@

/*
* Copy kernel to iovec.
+ *
+ * Note: this modifies the original iovec.
*/

int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
@@ -107,6 +109,8 @@

/*
* Copy iovec to kernel.
+ *
+ * Note: this modifies the original iovec.
*/

int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
@@ -187,9 +191,8 @@
* call to this function will be unaligned also.
*/

-int csum_partial_copy_fromiovecend(unsigned char *kdata,
- struct iovec *iov, int offset,
- unsigned int len, int *csump)
+int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
+ int offset, unsigned int len, int *csump)
{
int partial_cnt = 0;
int err = 0;
@@ -246,9 +249,9 @@
if (copy_from_user(kdata, base, copy))
goto out_fault;
kdata += copy;
- base += copy;
+ base += copy;
partial_cnt += copy;
- len -= copy;
+ len -= copy;
iov++;
if (len)
continue;
@@ -260,9 +263,9 @@
goto out_fault;
csum = csum_partial(kdata - partial_cnt, 4, csum);
kdata += par_len;
- base += par_len;
- copy -= par_len;
- len -= par_len;
+ base += par_len;
+ copy -= par_len;
+ len -= par_len;
partial_cnt = 0;
}

@@ -278,16 +281,12 @@
}
}

- /* Why do we want to break?? There may be more to copy ... */
- if (copy == 0) {
-if (len > partial_cnt)
-printk("csum_iovec: early break? len=%d, partial=%d\n", len, partial_cnt);
- break;
+ if (copy) {
+ csum = csum_and_copy_from_user(base, kdata, copy,
+ csum, &err);
+ if (err)
+ goto out;
}
-
- csum = csum_and_copy_from_user(base, kdata, copy, csum, &err);
- if (err)
- goto out;
len -= copy + partial_cnt;
kdata += copy + partial_cnt;
iov++;

--------------988699B14E137A4BD103351C--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu