summary refs log tree commit diff
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2007-05-08 18:23:28 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-05-09 17:57:59 -0400
commitaa3d1faebe6e214cd96be0e587571477ff6fd9fc (patch)
treed2295c15e30437a2bc693bd71b79a42c742ffc8b
parente70c490810dc683fad39e57cf00e69d5f120c542 (diff)
downloadlinux-aa3d1faebe6e214cd96be0e587571477ff6fd9fc.tar.gz
SUNRPC: Fix pointer arithmetic bug recently introduced in rpc_malloc/free
Use a cleaner method to find the size of an rpc_buffer.  This actually
works on x86-64!

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--net/sunrpc/sched.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 99014516b73c..b28a0b037f4f 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -736,6 +736,11 @@ static void rpc_async_schedule(struct work_struct *work)
 	__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
 }
 
+struct rpc_buffer {
+	size_t	len;
+	char	data[];
+};
+
 /**
  * rpc_malloc - allocate an RPC buffer
  * @task: RPC task that will use this buffer
@@ -754,18 +759,18 @@ static void rpc_async_schedule(struct work_struct *work)
  */
 void *rpc_malloc(struct rpc_task *task, size_t size)
 {
-	size_t *buf;
+	struct rpc_buffer *buf;
 	gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
 
-	size += sizeof(size_t);
+	size += sizeof(struct rpc_buffer);
 	if (size <= RPC_BUFFER_MAXSIZE)
 		buf = mempool_alloc(rpc_buffer_mempool, gfp);
 	else
 		buf = kmalloc(size, gfp);
-	*buf = size;
+	buf->len = size;
 	dprintk("RPC: %5u allocated buffer of size %zu at %p\n",
 			task->tk_pid, size, buf);
-	return ++buf;
+	return &buf->data;
 }
 
 /**
@@ -775,15 +780,18 @@ void *rpc_malloc(struct rpc_task *task, size_t size)
  */
 void rpc_free(void *buffer)
 {
-	size_t size, *buf = buffer;
+	size_t size;
+	struct rpc_buffer *buf;
 
 	if (!buffer)
 		return;
-	size = *buf;
-	buf--;
+
+	buf = container_of(buffer, struct rpc_buffer, data);
+	size = buf->len;
 
 	dprintk("RPC:       freeing buffer of size %zu at %p\n",
 			size, buf);
+
 	if (size <= RPC_BUFFER_MAXSIZE)
 		mempool_free(buf, rpc_buffer_mempool);
 	else