From mboxrd@z Thu Jan 1 00:00:00 1970 From: menage-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org Subject: [PATCH 20/29] memory controller resource counters v7 fix Date: Tue, 11 Sep 2007 12:52:59 -0700 Message-ID: <20070911200147.904884000@menage.corp.google.com> References: <20070911195239.997111000@menage.corp.google.com> Return-path: Content-Disposition: inline; filename=memory-controller-resource-counters-v7-fix.patch List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org Errors-To: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org To: containers-qjLDD68F18O7TbgM5vRIOg@public.gmane.org Cc: Andrew Morton , Pavel Emelianov , Balbir Singh , David Rientjes List-Id: containers.vger.kernel.org From: David Rientjes There's a gotcha in res_counter_charge_locked() because of C99 6.3.1.8(1) since both counter->limit and 'val' are of unsigned long type, the result of the subtraction will be the same; no promotion is required. So if 'val' is greater than counter->limit, it will always be larger than counter->usage and the conditional will fail. Simply casting this to signed doesn't work since counter->usage is also unsigned and thus the result of the subtraction will be promoted to unsigned since the ranks are the same. Even though the only (current) use of res_counter_charge() is with a 'val' actual of 1, this still fails if you set counter->limit to 0. No chance of overflow unless you're running on a machine with 4KB pages and 16TB of memory. Signed-off-by: David Rientjes Cc: Pavel Emelianov Cc: Balbir Singh Signed-off-by: Andrew Morton --- kernel/res_counter.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) diff -puN kernel/res_counter.c~memory-controller-resource-counters-v7-fix kernel/res_counter.c --- a/kernel/res_counter.c~memory-controller-resource-counters-v7-fix +++ a/kernel/res_counter.c @@ -21,7 +21,7 @@ void res_counter_init(struct res_counter int res_counter_charge_locked(struct res_counter *counter, unsigned long val) { - if (counter->usage > (counter->limit - val)) { + if (counter->usage + val > counter->limit) { counter->failcnt++; return -ENOMEM; } _ --