From patchwork Wed Oct 14 06:29:02 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Torokhov X-Patchwork-Id: 53603 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n9E6YWZW020084 for ; Wed, 14 Oct 2009 06:34:32 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754393AbZJNGaS (ORCPT ); Wed, 14 Oct 2009 02:30:18 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753953AbZJNGaR (ORCPT ); Wed, 14 Oct 2009 02:30:17 -0400 Received: from qw-out-2122.google.com ([74.125.92.24]:55488 "EHLO qw-out-2122.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753477AbZJNGaP (ORCPT ); Wed, 14 Oct 2009 02:30:15 -0400 Received: by qw-out-2122.google.com with SMTP id 9so1135062qwb.37 for ; Tue, 13 Oct 2009 23:29:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:date:from:to:cc:subject :message-id:references:mime-version:content-type:content-disposition :in-reply-to:user-agent; bh=WtdVV0WyBTeQAY3HsWwJjaT8lAAONPowiyqjXt6ajIU=; b=n9fB6E8q1o/hfrr9GxEO9JmnoRlTbLOKhPp9hVmewovLORCJ+5hOvkyJGNKUwVqOL6 JD28ksHO4bmhjmt8g3EJWSo8NeexMSBEZriq4MZ6BtdE4AeqB+puUYlgPUqcA86L8jbi osUuhax5YS2aOtmZZ7I/2RetmY1UxKsuw+8Yc= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:in-reply-to:user-agent; b=jyeidjOd44MiHYlJIgEJqj/IJXtoo3axjbIf2BPCgy5B9DQW7191PC9bfCgA9rAdf8 k7VJi1bBKPVcq6TDAAfXK19BCaBHsNvX/xzdT+wj+4sw3WXA1XSgurAR4rTJHV28QO53 WKhtHxYmeTY9cWVj8w7ZEYWg5UlABIOy8TKD0= Received: by 10.224.50.130 with SMTP id z2mr6711176qaf.206.1255501748867; Tue, 13 Oct 2009 23:29:08 -0700 (PDT) Received: from mailhub.coreip.homeip.net (c-24-6-153-137.hsd1.ca.comcast.net [24.6.153.137]) by mx.google.com with ESMTPS id 8sm1761594qwj.6.2009.10.13.23.29.07 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 13 Oct 2009 23:29:07 -0700 (PDT) Date: Tue, 13 Oct 2009 23:29:02 -0700 From: Dmitry Torokhov To: Jiri Kosina Cc: iceberg , Vojtech Pavlik , Linux Kernlel Mailing List , linux-input@vger.kernel.org Subject: Re: [BUG] ati_remote2.c: possible mutex_lock without mutex_unlock Message-ID: <20091014062902.GA2971@core.coreip.homeip.net> References: <1255456327.22233.0@pamir> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.19 (2009-01-05) Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org diff --git a/drivers/input/input.c b/drivers/input/input.c index c6f88eb..cc763c9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -782,10 +782,29 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) return 0; } +union input_seq_state { + struct { + unsigned short pos; + bool mutex_acquired; + }; + void *p; +}; + static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) { - if (mutex_lock_interruptible(&input_mutex)) - return NULL; + union input_seq_state *state = (union input_seq_state *)&seq->private; + int error; + + /* We need to fit into seq->private pointer */ + BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private)); + + error = mutex_lock_interruptible(&input_mutex); + if (error) { + state->mutex_acquired = false; + return ERR_PTR(error); + } + + state->mutex_acquired = true; return seq_list_start(&input_dev_list, *pos); } @@ -795,9 +814,12 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos) return seq_list_next(v, &input_dev_list, pos); } -static void input_devices_seq_stop(struct seq_file *seq, void *v) +static void input_seq_stop(struct seq_file *seq, void *v) { - mutex_unlock(&input_mutex); + union input_seq_state *state = (union input_seq_state *)&seq->private; + + if (state->mutex_acquired) + mutex_unlock(&input_mutex); } static void input_seq_print_bitmap(struct seq_file *seq, const char *name, @@ -861,7 +883,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v) static const struct seq_operations input_devices_seq_ops = { .start = input_devices_seq_start, .next = input_devices_seq_next, - .stop = input_devices_seq_stop, + .stop = input_seq_stop, .show = input_devices_seq_show, }; @@ -881,40 +903,49 @@ static const struct file_operations input_devices_fileops = { static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) { - if (mutex_lock_interruptible(&input_mutex)) - return NULL; + union input_seq_state *state = (union input_seq_state *)&seq->private; + int error; + + /* We need to fit into seq->private pointer */ + BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private)); + + error = mutex_lock_interruptible(&input_mutex); + if (error) { + state->mutex_acquired = false; + return ERR_PTR(error); + } + + state->mutex_acquired = true; + state->pos = *pos; - seq->private = (void *)(unsigned long)*pos; return seq_list_start(&input_handler_list, *pos); } static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - seq->private = (void *)(unsigned long)(*pos + 1); - return seq_list_next(v, &input_handler_list, pos); -} + union input_seq_state *state = (union input_seq_state *)&seq->private; -static void input_handlers_seq_stop(struct seq_file *seq, void *v) -{ - mutex_unlock(&input_mutex); + state->pos = *pos + 1; + return seq_list_next(v, &input_handler_list, pos); } static int input_handlers_seq_show(struct seq_file *seq, void *v) { struct input_handler *handler = container_of(v, struct input_handler, node); + union input_seq_state *state = (union input_seq_state *)&seq->private; - seq_printf(seq, "N: Number=%ld Name=%s", - (unsigned long)seq->private, handler->name); + seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); if (handler->fops) seq_printf(seq, " Minor=%d", handler->minor); seq_putc(seq, '\n'); return 0; } + static const struct seq_operations input_handlers_seq_ops = { .start = input_handlers_seq_start, .next = input_handlers_seq_next, - .stop = input_handlers_seq_stop, + .stop = input_seq_stop, .show = input_handlers_seq_show, };