diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2007-05-08 18:23:28 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-09 17:57:59 -0400 |
commit | aa3d1faebe6e214cd96be0e587571477ff6fd9fc (patch) | |
tree | d2295c15e30437a2bc693bd71b79a42c742ffc8b /net/sunrpc/sched.c | |
parent | e70c490810dc683fad39e57cf00e69d5f120c542 (diff) |
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>
Diffstat (limited to 'net/sunrpc/sched.c')
-rw-r--r-- | net/sunrpc/sched.c | 22 |
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) | |||
736 | __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); | 736 | __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); |
737 | } | 737 | } |
738 | 738 | ||
739 | struct rpc_buffer { | ||
740 | size_t len; | ||
741 | char data[]; | ||
742 | }; | ||
743 | |||
739 | /** | 744 | /** |
740 | * rpc_malloc - allocate an RPC buffer | 745 | * rpc_malloc - allocate an RPC buffer |
741 | * @task: RPC task that will use this buffer | 746 | * @task: RPC task that will use this buffer |
@@ -754,18 +759,18 @@ static void rpc_async_schedule(struct work_struct *work) | |||
754 | */ | 759 | */ |
755 | void *rpc_malloc(struct rpc_task *task, size_t size) | 760 | void *rpc_malloc(struct rpc_task *task, size_t size) |
756 | { | 761 | { |
757 | size_t *buf; | 762 | struct rpc_buffer *buf; |
758 | gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT; | 763 | gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT; |
759 | 764 | ||
760 | size += sizeof(size_t); | 765 | size += sizeof(struct rpc_buffer); |
761 | if (size <= RPC_BUFFER_MAXSIZE) | 766 | if (size <= RPC_BUFFER_MAXSIZE) |
762 | buf = mempool_alloc(rpc_buffer_mempool, gfp); | 767 | buf = mempool_alloc(rpc_buffer_mempool, gfp); |
763 | else | 768 | else |
764 | buf = kmalloc(size, gfp); | 769 | buf = kmalloc(size, gfp); |
765 | *buf = size; | 770 | buf->len = size; |
766 | dprintk("RPC: %5u allocated buffer of size %zu at %p\n", | 771 | dprintk("RPC: %5u allocated buffer of size %zu at %p\n", |
767 | task->tk_pid, size, buf); | 772 | task->tk_pid, size, buf); |
768 | return ++buf; | 773 | return &buf->data; |
769 | } | 774 | } |
770 | 775 | ||
771 | /** | 776 | /** |
@@ -775,15 +780,18 @@ void *rpc_malloc(struct rpc_task *task, size_t size) | |||
775 | */ | 780 | */ |
776 | void rpc_free(void *buffer) | 781 | void rpc_free(void *buffer) |
777 | { | 782 | { |
778 | size_t size, *buf = buffer; | 783 | size_t size; |
784 | struct rpc_buffer *buf; | ||
779 | 785 | ||
780 | if (!buffer) | 786 | if (!buffer) |
781 | return; | 787 | return; |
782 | size = *buf; | 788 | |
783 | buf--; | 789 | buf = container_of(buffer, struct rpc_buffer, data); |
790 | size = buf->len; | ||
784 | 791 | ||
785 | dprintk("RPC: freeing buffer of size %zu at %p\n", | 792 | dprintk("RPC: freeing buffer of size %zu at %p\n", |
786 | size, buf); | 793 | size, buf); |
794 | |||
787 | if (size <= RPC_BUFFER_MAXSIZE) | 795 | if (size <= RPC_BUFFER_MAXSIZE) |
788 | mempool_free(buf, rpc_buffer_mempool); | 796 | mempool_free(buf, rpc_buffer_mempool); |
789 | else | 797 | else |