minor patch for 2.1.87 NFS client

Bill Hawes (whawes@star.net)
Mon, 23 Feb 1998 09:28:50 -0500


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

Hi Linus,

The attached minor patch provides a workaround for problems reported with
certain HP NFS servers. It appears that the servers are treating the readdir
buffer size as a longword rather than byte count, and then overrun the available
buffer. The patch works by detecting the first overrun and then passes the size
in longwords on subsequent readdir messages. I've added a flags field to the RPC
client structure that we can use for future server-specific bug workarounds as
well.

The patch also includes conditionally-enabled code to pad RPC write messages to
a longword length. This provides a workaround for a few older servers that
return a "garbage args" error if the total RPC message length isn't a longword
multiple.

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

--- linux-2.1.87/include/linux/nfs_fs.h.old Tue Jan 27 09:36:36 1998
+++ linux-2.1.87/include/linux/nfs_fs.h Wed Feb 18 12:26:11 1998
@@ -85,6 +85,9 @@
*/
#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)

+/* Flags in the RPC client structure */
+#define NFS_CLNTF_BUFSIZE 0x0001 /* readdir buffer in longwords */
+
#ifdef __KERNEL__

/*
--- linux-2.1.87/fs/nfs/nfs2xdr.c.old Tue Jan 27 09:36:34 1998
+++ linux-2.1.87/fs/nfs/nfs2xdr.c Wed Feb 18 12:49:59 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 */

@@ -181,7 +184,7 @@
/*
* Arguments to a READ call. Since we read data directly into the page
* cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page wewant to fetch.
+ * exactly to the page we want to fetch.
*/
static int
nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
@@ -258,18 +261,34 @@
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) {
+ 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;
}

@@ -334,12 +353,21 @@
static int
nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_task *task = req->rq_task;
+ struct rpc_auth *auth = task->tk_auth;
+ u32 bufsiz = args->bufsiz;
int replen;

+ /*
+ * 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;
+
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->cookie);
- *p++ = htonl(args->bufsiz);
+ *p++ = htonl(bufsiz); /* see above */
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);

/* set up reply iovec */
@@ -380,10 +408,9 @@
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
struct iovec *iov = req->rq_rvec;
- int status, nr, len;
+ int status, nr;
char *string, *start;
- u32 *end;
- __u32 fileid, cookie, *entry;
+ u32 *end, *entry, len, fileid, cookie;

if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
@@ -398,17 +425,25 @@
end = (u32 *) ((u8 *) p + iov[1].iov_len);

/* Get start and end of dirent buffer */
- entry = (__u32 *) res->buffer;
+ entry = (u32 *) res->buffer;
start = (char *) res->buffer;
string = (char *) res->buffer + res->bufsiz;
for (nr = 0; *p++; nr++) {
fileid = ntohl(*p++);

len = ntohl(*p++);
+ /*
+ * Check whether the server has exceeded our reply buffer,
+ * and set a flag to convert the size to longwords.
+ */
if ((p + QUADLEN(len) + 3) > end) {
- printk(KERN_WARNING "NFS: short readdir reply! "
- "nr=%d, slots=%d, len=%d\n",
+ struct rpc_clnt *clnt = req->rq_task->tk_client;
+ printk(KERN_WARNING
+ "NFS: server %s, readdir reply truncated\n",
+ clnt->cl_server);
+ printk(KERN_WARNING "NFS: nr=%d, slots=%d, len=%d\n",
nr, (end - p), len);
+ clnt->cl_flags |= NFS_CLNTF_BUFSIZE;
break;
}
if (len > NFS_MAXNAMLEN) {
--- linux-2.1.87/include/linux/sunrpc/clnt.h.old Tue Feb 17 11:26:40 1998
+++ linux-2.1.87/include/linux/sunrpc/clnt.h Wed Feb 18 12:39:39 1998
@@ -30,6 +30,7 @@
* The high-level client handle
*/
struct rpc_clnt {
+ unsigned int cl_users; /* number of references */
struct rpc_xprt * cl_xprt; /* transport */
struct rpc_procinfo * cl_procinfo; /* procedure info */
u32 cl_maxproc; /* max procedure number */
@@ -37,7 +38,6 @@
char * cl_server; /* server machine name */
char * cl_protname; /* protocol name */
struct rpc_auth * cl_auth; /* authenticator */
- struct rpc_portmap cl_pmap; /* port mapping */
struct rpc_stat * cl_stats; /* statistics */

unsigned int cl_softrtry : 1,/* soft timeouts */
@@ -47,10 +47,11 @@
cl_binding : 1,/* doing a getport() */
cl_oneshot : 1,/* dispose after use */
cl_dead : 1;/* abandoned */
+ unsigned int cl_flags; /* misc client flags */
unsigned long cl_hardmax; /* max hard timeout */

+ struct rpc_portmap cl_pmap; /* port mapping */
struct rpc_wait_queue cl_bindwait; /* waiting on getport() */
- unsigned int cl_users; /* number of references */
};
#define cl_timeout cl_xprt->timeout
#define cl_prog cl_pmap.pm_prog

--------------AE4FEA2A6C6590ED330F6A28--

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