lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <200703010036.28166.dtor@insightbb.com>
Date:	Thu, 1 Mar 2007 00:36:26 -0500
From:	Dmitry Torokhov <dtor@...ightbb.com>
To:	linux-input@...ey.karlin.mff.cuni.cz
Cc:	"Rafael J. Wysocki" <rjw@...k.pl>,
	Kristian Grønfeldt Sørensen 
	<kriller@....dk>,
	Linux kernel mailing list <linux-kernel@...r.kernel.org>
Subject: Re: PROBLEM: "BUG:" when resuming from suspend-to-ram

On Wednesday 28 February 2007 07:45, Rafael J. Wysocki wrote:
> 
> > This gives:
> > 
> > (gdb) l *evdev_disconnect+0xb1
> > 0xa81 is in evdev_disconnect (include/asm/processor.h:716).
> > 711        However we don't do prefetches for pre XP Athlons currently
> > 712        That should be fixed. */
> > 713     #define ARCH_HAS_PREFETCH
> > 714     static inline void prefetch(const void *x)
> > 715     {
> > 716             alternative_input(ASM_NOP4,
> > 717                               "prefetchnta (%1)",
> > 718                               X86_FEATURE_XMM,
> > 719                               "r" (x));
> > 720     }
> 
> Hm, interesting.  Looks like a pointer points to nowhere in
> input_unregister_device(), but I don't know which one.  This may be
> an evdev problem ...
> 

Please try the patch below.

-- 
Dmitry

Input: use krefs for refcounting in input handlers

This should fix problems whith accessing memory already freed by
another thread.

Signed-off-by: Dmitry Torokhov <dtor@...l.ru>
---

 drivers/input/evdev.c    |   62 ++++++++++-------
 drivers/input/joydev.c   |   51 +++++++++-----
 drivers/input/mousedev.c |  166 +++++++++++++++++++++++++++++++++--------------
 drivers/input/tsdev.c    |   65 +++++++++++-------
 4 files changed, 227 insertions(+), 117 deletions(-)

Index: work/drivers/input/evdev.c
===================================================================
--- work.orig/drivers/input/evdev.c
+++ work/drivers/input/evdev.c
@@ -29,8 +29,10 @@ struct evdev {
 	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
-	struct evdev_list *grab;
+	struct kref kref;
 	struct list_head list;
+
+	struct evdev_list *grab;
 };
 
 struct evdev_list {
@@ -94,53 +96,62 @@ static int evdev_flush(struct file *file
 	return input_flush_device(&list->evdev->handle, file);
 }
 
-static void evdev_free(struct evdev *evdev)
+static void evdev_free(struct kref *kref)
 {
+	struct evdev *evdev = container_of(kref, struct evdev, kref);
+
 	evdev_table[evdev->minor] = NULL;
 	kfree(evdev);
 }
 
-static int evdev_release(struct inode * inode, struct file * file)
+static int evdev_release(struct inode *inode, struct file *file)
 {
 	struct evdev_list *list = file->private_data;
+	struct evdev *evdev = list->evdev;
 
-	if (list->evdev->grab == list) {
-		input_release_device(&list->evdev->handle);
-		list->evdev->grab = NULL;
+	if (evdev->grab == list) {
+		input_release_device(&evdev->handle);
+		evdev->grab = NULL;
 	}
 
 	evdev_fasync(-1, file, 0);
+
 	list_del(&list->node);
+	kfree(list);
 
-	if (!--list->evdev->open) {
-		if (list->evdev->exist)
-			input_close_device(&list->evdev->handle);
-		else
-			evdev_free(list->evdev);
-	}
+	if (!--evdev->open && evdev->exist)
+		input_close_device(&evdev->handle);
+
+	kref_put(&evdev->kref, evdev_free);
 
-	kfree(list);
 	return 0;
 }
 
-static int evdev_open(struct inode * inode, struct file * file)
+static int evdev_open(struct inode *inode, struct file *file)
 {
 	struct evdev_list *list;
+	struct evdev *evdev;
 	int i = iminor(inode) - EVDEV_MINOR_BASE;
 
-	if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
+	if (i >= EVDEV_MINORS)
+		return -ENODEV;
+
+	evdev = evdev_table[i];
+	if (!evdev || !evdev->exist)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
+	list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL);
+	if (!list)
 		return -ENOMEM;
 
-	list->evdev = evdev_table[i];
-	list_add_tail(&list->node, &evdev_table[i]->list);
+	kref_get(&evdev->kref);
+
+	list->evdev = evdev;
+	list_add_tail(&list->node, &evdev->list);
 	file->private_data = list;
 
-	if (!list->evdev->open++)
-		if (list->evdev->exist)
-			input_open_device(&list->evdev->handle);
+	if (!evdev->open++ && evdev->exist)
+		input_open_device(&evdev->handle);
 
 	return 0;
 }
@@ -629,9 +640,11 @@ static struct input_handle *evdev_connec
 		return NULL;
 	}
 
-	if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
+	evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
+	if (!evdev)
 		return NULL;
 
+	kref_init(&evdev->kref);
 	INIT_LIST_HEAD(&evdev->list);
 	init_waitqueue_head(&evdev->wait);
 
@@ -672,8 +685,9 @@ static void evdev_disconnect(struct inpu
 		wake_up_interruptible(&evdev->wait);
 		list_for_each_entry(list, &evdev->list, node)
 			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-	} else
-		evdev_free(evdev);
+	}
+
+	kref_put(&evdev->kref, evdev_free);
 }
 
 static const struct input_device_id evdev_ids[] = {
Index: work/drivers/input/joydev.c
===================================================================
--- work.orig/drivers/input/joydev.c
+++ work/drivers/input/joydev.c
@@ -43,7 +43,9 @@ struct joydev {
 	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
+	struct kref kref;
 	struct list_head list;
+
 	struct js_corr corr[ABS_MAX + 1];
 	struct JS_DATA_SAVE_TYPE glue;
 	int nabs;
@@ -139,8 +141,10 @@ static int joydev_fasync(int fd, struct 
 	return retval < 0 ? retval : 0;
 }
 
-static void joydev_free(struct joydev *joydev)
+static void joydev_free(struct kref *kref)
 {
+	struct joydev *joydev = container_of(kref, struct joydev, kref);
+
 	joydev_table[joydev->minor] = NULL;
 	kfree(joydev);
 }
@@ -148,40 +152,46 @@ static void joydev_free(struct joydev *j
 static int joydev_release(struct inode * inode, struct file * file)
 {
 	struct joydev_list *list = file->private_data;
+	struct joydev *joydev = list->joydev;
 
 	joydev_fasync(-1, file, 0);
 
 	list_del(&list->node);
+	kfree(list);
 
-	if (!--list->joydev->open) {
-		if (list->joydev->exist)
-			input_close_device(&list->joydev->handle);
-		else
-			joydev_free(list->joydev);
-	}
+	if (!--joydev->open && joydev->exist)
+		input_close_device(&list->joydev->handle);
+
+	kref_put(&joydev->kref, joydev_free);
 
-	kfree(list);
 	return 0;
 }
 
 static int joydev_open(struct inode *inode, struct file *file)
 {
 	struct joydev_list *list;
+	struct joydev *joydev;
 	int i = iminor(inode) - JOYDEV_MINOR_BASE;
 
-	if (i >= JOYDEV_MINORS || !joydev_table[i])
+	if (i >= JOYDEV_MINORS)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL)))
+	joydev = joydev_table[i];
+	if (!joydev || !joydev->exist)
+		return -ENODEV;
+
+	list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL);
+	if (!list)
 		return -ENOMEM;
 
-	list->joydev = joydev_table[i];
-	list_add_tail(&list->node, &joydev_table[i]->list);
+	kref_get(&joydev->kref);
+
+	list->joydev = joydev;
+	list_add_tail(&list->node, &joydev->list);
 	file->private_data = list;
 
-	if (!list->joydev->open++)
-		if (list->joydev->exist)
-			input_open_device(&list->joydev->handle);
+	if (!joydev->open++ && joydev->exist)
+		input_open_device(&list->joydev->handle);
 
 	return 0;
 }
@@ -198,7 +208,7 @@ static ssize_t joydev_read(struct file *
 	struct input_dev *input = joydev->handle.dev;
 	int retval = 0;
 
-	if (!list->joydev->exist)
+	if (!joydev->exist)
 		return -ENODEV;
 
 	if (count < sizeof(struct js_event))
@@ -478,9 +488,11 @@ static struct input_handle *joydev_conne
 		return NULL;
 	}
 
-	if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
+	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
+	if (!joydev)
 		return NULL;
 
+	kref_init(&joydev->kref);
 	INIT_LIST_HEAD(&joydev->list);
 	init_waitqueue_head(&joydev->wait);
 
@@ -559,8 +571,9 @@ static void joydev_disconnect(struct inp
 		wake_up_interruptible(&joydev->wait);
 		list_for_each_entry(list, &joydev->list, node)
 			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-	} else
-		joydev_free(joydev);
+	}
+
+	kref_put(&joydev->kref, joydev_free);
 }
 
 static const struct input_device_id joydev_blacklist[] = {
Index: work/drivers/input/mousedev.c
===================================================================
--- work.orig/drivers/input/mousedev.c
+++ work/drivers/input/mousedev.c
@@ -62,9 +62,13 @@ struct mousedev {
 	int open;
 	int minor;
 	char name[16];
+	struct input_handle handle;
 	wait_queue_head_t wait;
+	struct kref kref;
 	struct list_head list;
-	struct input_handle handle;
+
+	struct list_head mixdev_node;
+	int mixdev_open;
 
 	struct mousedev_hw_data packet;
 	unsigned int pkt_count;
@@ -111,6 +115,8 @@ static struct input_handler mousedev_han
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
+static LIST_HEAD(mousedev_mix_list);
+static DEFINE_MUTEX(mousedev_mix_mutex);
 
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -358,55 +364,112 @@ static int mousedev_fasync(int fd, struc
 	return retval < 0 ? retval : 0;
 }
 
-static void mousedev_free(struct mousedev *mousedev)
+static void mousedev_free(struct kref *kref)
 {
+	struct mousedev *mousedev = container_of(kref, struct mousedev, kref);
+
 	mousedev_table[mousedev->minor] = NULL;
 	kfree(mousedev);
 }
 
-static void mixdev_release(void)
+static int mixdev_add_device(struct mousedev *mousedev)
+{
+	int retval = 0;
+
+	mutex_lock(&mousedev_mix_mutex);
+
+	if (mousedev_mix.open) {
+		if (!mousedev->open && mousedev->exist) {
+			retval = input_open_device(&mousedev->handle);
+			if (retval)
+				goto out;
+
+			mousedev->open++;
+		}
+		mousedev->mixdev_open++;
+	}
+
+	list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
+
+ out:
+	mutex_unlock(&mousedev_mix_mutex);
+	return retval;
+}
+
+static void mixdev_remove_device(struct mousedev *mousedev)
 {
-	struct input_handle *handle;
+	mutex_lock(&mousedev_mix_mutex);
 
-	list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
-		struct mousedev *mousedev = handle->private;
+	if (!--mousedev->mixdev_open)
+		if (!--mousedev->open && mousedev->exist)
+			input_close_device(&mousedev->handle);
 
-		if (!mousedev->open) {
-			if (mousedev->exist)
+	list_del_init(&mousedev->mixdev_node);
+
+	mutex_unlock(&mousedev_mix_mutex);
+}
+
+static void mixdev_open_devices(void)
+{
+	struct mousedev *mousedev;
+
+	mutex_lock(&mousedev_mix_mutex);
+
+	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+		if (!mousedev->mixdev_open)
+			if (!mousedev->open && mousedev->exist) {
+				if (input_open_device(&mousedev->handle))
+					continue;
+				mousedev->open++;
+			}
+		mousedev->mixdev_open++;
+	}
+
+	mutex_unlock(&mousedev_mix_mutex);
+}
+
+static void mixdev_close_devices(void)
+{
+	struct mousedev *mousedev, *next;
+
+	mutex_lock(&mousedev_mix_mutex);
+
+	list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) {
+		if (mousedev->mixdev_open) {
+			if (!--mousedev->open && mousedev->exist)
 				input_close_device(&mousedev->handle);
-			else
-				mousedev_free(mousedev);
+			mousedev->mixdev_open--;
 		}
 	}
+
+	mutex_unlock(&mousedev_mix_mutex);
 }
 
-static int mousedev_release(struct inode * inode, struct file * file)
+static int mousedev_release(struct inode *inode, struct file *file)
 {
 	struct mousedev_list *list = file->private_data;
+	struct mousedev *mousedev = list->mousedev;
 
 	mousedev_fasync(-1, file, 0);
 
 	list_del(&list->node);
+	kfree(list);
 
-	if (!--list->mousedev->open) {
-		if (list->mousedev->minor == MOUSEDEV_MIX)
-			mixdev_release();
-		else if (!mousedev_mix.open) {
-			if (list->mousedev->exist)
-				input_close_device(&list->mousedev->handle);
-			else
-				mousedev_free(list->mousedev);
-		}
+	if (!--mousedev->open) {
+		if (mousedev->minor == MOUSEDEV_MIX)
+			mixdev_close_devices();
+		else if (mousedev->exist)
+			input_close_device(&mousedev->handle);
 	}
 
-	kfree(list);
+	kref_put(&mousedev->kref, mousedev_free);
+
 	return 0;
 }
 
-static int mousedev_open(struct inode * inode, struct file * file)
+static int mousedev_open(struct inode *inode, struct file *file)
 {
 	struct mousedev_list *list;
-	struct input_handle *handle;
 	struct mousedev *mousedev;
 	int i;
 
@@ -417,29 +480,31 @@ static int mousedev_open(struct inode * 
 #endif
 		i = iminor(inode) - MOUSEDEV_MINOR_BASE;
 
-	if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
+	if (i >= MOUSEDEV_MINORS)
+		return -ENODEV;
+
+	mousedev =  mousedev_table[i];
+	if (!mousedev || !mousedev->exist)
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
+	list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL);
+	if (!list)
 		return -ENOMEM;
 
+	kref_get(&mousedev->kref);
+
 	spin_lock_init(&list->packet_lock);
 	list->pos_x = xres / 2;
 	list->pos_y = yres / 2;
-	list->mousedev = mousedev_table[i];
-	list_add_tail(&list->node, &mousedev_table[i]->list);
+	list->mousedev = mousedev;
+	list_add_tail(&list->node, &mousedev->list);
 	file->private_data = list;
 
-	if (!list->mousedev->open++) {
-		if (list->mousedev->minor == MOUSEDEV_MIX) {
-			list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
-				mousedev = handle->private;
-				if (!mousedev->open && mousedev->exist)
-					input_open_device(handle);
-			}
-		} else
-			if (!mousedev_mix.open && list->mousedev->exist)
-				input_open_device(&list->mousedev->handle);
+	if (!mousedev->open++) {
+		if (mousedev->minor == MOUSEDEV_MIX)
+			mixdev_open_devices();
+		else if (mousedev->exist)
+			input_open_device(&mousedev->handle);
 	}
 
 	return 0;
@@ -629,7 +694,7 @@ static struct input_handle *mousedev_con
 {
 	struct mousedev *mousedev;
 	struct class_device *cdev;
-	int minor = 0;
+	int minor;
 
 	for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
 	if (minor == MOUSEDEV_MINORS) {
@@ -637,10 +702,13 @@ static struct input_handle *mousedev_con
 		return NULL;
 	}
 
-	if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
+	mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
+	if (!mousedev)
 		return NULL;
 
+	kref_init(&mousedev->kref);
 	INIT_LIST_HEAD(&mousedev->list);
+	INIT_LIST_HEAD(&mousedev->mixdev_node);
 	init_waitqueue_head(&mousedev->wait);
 
 	mousedev->minor = minor;
@@ -651,8 +719,7 @@ static struct input_handle *mousedev_con
 	mousedev->handle.private = mousedev;
 	sprintf(mousedev->name, "mouse%d", minor);
 
-	if (mousedev_mix.open)
-		input_open_device(&mousedev->handle);
+	mixdev_add_device(mousedev);
 
 	mousedev_table[minor] = mousedev;
 
@@ -675,18 +742,18 @@ static void mousedev_disconnect(struct i
 	sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
 	class_device_destroy(&input_class,
 			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
-	mousedev->exist = 0;
 
+	mixdev_remove_device(mousedev);
+
+	mousedev->exist = 0;
 	if (mousedev->open) {
 		input_close_device(handle);
 		wake_up_interruptible(&mousedev->wait);
 		list_for_each_entry(list, &mousedev->list, node)
 			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-	} else {
-		if (mousedev_mix.open)
-			input_close_device(handle);
-		mousedev_free(mousedev);
 	}
+
+	kref_put(&mousedev->kref, mousedev_free);
 }
 
 static const struct input_device_id mousedev_ids[] = {
@@ -714,7 +781,7 @@ static const struct input_device_id mous
 		.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
 	},	/* A touchpad */
 
-	{ }, 	/* Terminating entry */
+	{ },	/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE(input, mousedev_ids);
@@ -745,13 +812,14 @@ static int __init mousedev_init(void)
 	if (error)
 		return error;
 
-	memset(&mousedev_mix, 0, sizeof(struct mousedev));
+	kref_init(&mousedev_mix.kref);
 	INIT_LIST_HEAD(&mousedev_mix.list);
 	init_waitqueue_head(&mousedev_mix.wait);
-	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
 	mousedev_mix.exist = 1;
 	mousedev_mix.minor = MOUSEDEV_MIX;
 
+	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
+
 	cdev = class_device_create(&input_class, NULL,
 			MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice");
 	if (IS_ERR(cdev)) {
Index: work/drivers/input/tsdev.c
===================================================================
--- work.orig/drivers/input/tsdev.c
+++ work/drivers/input/tsdev.c
@@ -110,9 +110,11 @@ struct tsdev {
 	int open;
 	int minor;
 	char name[8];
+	struct input_handle handle;
 	wait_queue_head_t wait;
+	struct kref kref;
 	struct list_head list;
-	struct input_handle handle;
+
 	int x, y, pressure;
 	struct ts_calibration cal;
 };
@@ -150,6 +152,7 @@ static int tsdev_open(struct inode *inod
 {
 	int i = iminor(inode) - TSDEV_MINOR_BASE;
 	struct tsdev_list *list;
+	struct tsdev *tsdev;
 
 	printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
 		"for removal.\nSee Documentation/feature-removal-schedule.txt "
@@ -158,24 +161,31 @@ static int tsdev_open(struct inode *inod
 	if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
 		return -ENODEV;
 
-	if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+	tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
+	if (!tsdev || !tsdev->exist)
+		return -ENODEV;
+
+	list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL);
+	if (!list)
 		return -ENOMEM;
 
-	list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
+	kref_get(&tsdev->kref);
 
-	i &= TSDEV_MINOR_MASK;
-	list->tsdev = tsdev_table[i];
-	list_add_tail(&list->node, &tsdev_table[i]->list);
+	list->tsdev = tsdev;
+	list->raw = (i >= TSDEV_MINORS / 2);
+	list_add_tail(&list->node, &tsdev->list);
 	file->private_data = list;
 
-	if (!list->tsdev->open++)
-		if (list->tsdev->exist)
-			input_open_device(&list->tsdev->handle);
+	if (!tsdev->open++ && tsdev->exist)
+		input_open_device(&list->tsdev->handle);
+
 	return 0;
 }
 
-static void tsdev_free(struct tsdev *tsdev)
+static void tsdev_free(struct kref *kref)
 {
+	struct tsdev *tsdev = container_of(kref, struct tsdev, kref);
+
 	tsdev_table[tsdev->minor] = NULL;
 	kfree(tsdev);
 }
@@ -183,17 +193,18 @@ static void tsdev_free(struct tsdev *tsd
 static int tsdev_release(struct inode *inode, struct file *file)
 {
 	struct tsdev_list *list = file->private_data;
+	struct tsdev *tsdev = list->tsdev;
 
 	tsdev_fasync(-1, file, 0);
-	list_del(&list->node);
 
-	if (!--list->tsdev->open) {
-		if (list->tsdev->exist)
-			input_close_device(&list->tsdev->handle);
-		else
-			tsdev_free(list->tsdev);
-	}
+	list_del(&list->node);
 	kfree(list);
+
+	if (!--tsdev->open && tsdev->exist)
+		input_close_device(&tsdev->handle);
+
+	kref_put(&tsdev->kref, tsdev_free);
+
 	return 0;
 }
 
@@ -201,22 +212,23 @@ static ssize_t tsdev_read(struct file *f
 			  loff_t * ppos)
 {
 	struct tsdev_list *list = file->private_data;
+	struct tsdev *tsdev = list->tsdev;
 	int retval = 0;
 
-	if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))
+	if (list->head == list->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
-	retval = wait_event_interruptible(list->tsdev->wait,
-			list->head != list->tail || !list->tsdev->exist);
+	retval = wait_event_interruptible(tsdev->wait,
+			list->head != list->tail || !tsdev->exist);
 
 	if (retval)
 		return retval;
 
-	if (!list->tsdev->exist)
+	if (!tsdev->exist)
 		return -ENODEV;
 
 	while (list->head != list->tail &&
-	       retval + sizeof (struct ts_event) <= count) {
+	       retval + sizeof(struct ts_event) <= count) {
 		if (copy_to_user (buffer + retval, list->event + list->tail,
 				  sizeof (struct ts_event)))
 			return -EFAULT;
@@ -385,9 +397,11 @@ static struct input_handle *tsdev_connec
 		return NULL;
 	}
 
-	if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
+	tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
+	if (!tsdev)
 		return NULL;
 
+	kref_init(&tsdev->kref);
 	INIT_LIST_HEAD(&tsdev->list);
 	init_waitqueue_head(&tsdev->wait);
 
@@ -441,8 +455,9 @@ static void tsdev_disconnect(struct inpu
 		wake_up_interruptible(&tsdev->wait);
 		list_for_each_entry(list, &tsdev->list, node)
 			kill_fasync(&list->fasync, SIGIO, POLL_HUP);
-	} else
-		tsdev_free(tsdev);
+	}
+
+	kref_put(&tsdev->kref, tsdev_free);
 }
 
 static const struct input_device_id tsdev_ids[] = {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ