]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Staging: comedi: serial2002: handle allocation failures on 'open'
authorIan Abbott <abbotti@mev.co.uk>
Wed, 19 May 2010 13:10:01 +0000 (14:10 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 17 Jun 2010 20:28:56 +0000 (13:28 -0700)
The comedi device 'open' method for the serial2002 driver frees any old
'maxdata_list' and 'range_table_list' arrays belonging to a subdevice
and allocates them again, but was missing checks for allocation failure.

If an allocation fails, free the 'maxdata_list' and 'range_table_list'
arrays for all subdevices and return an error.

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/comedi/drivers/serial2002.c

index a4a99b870369b270a6ae7db29c6ff2d89eeca728..880fe89e866fdfbe1ab826235cb3b720a308e8e4 100644 (file)
@@ -418,6 +418,7 @@ static int serial_2002_open(struct comedi_device *dev)
                struct config_t chan_out_config[32];
                int i;
 
+               result = 0;
                for (i = 0; i < 32; i++) {
                        dig_in_config[i].kind = 0;
                        dig_in_config[i].bits = 0;
@@ -633,22 +634,23 @@ static int serial_2002_open(struct comedi_device *dev)
                                s = &dev->subdevices[i];
                                s->n_chan = chan;
                                s->maxdata = 0;
-                               if (s->maxdata_list) {
-                                       kfree(s->maxdata_list);
-                               }
+                               kfree(s->maxdata_list);
                                s->maxdata_list = maxdata_list =
                                    kmalloc(sizeof(unsigned int) * s->n_chan,
                                            GFP_KERNEL);
-                               if (s->range_table_list) {
-                                       kfree(s->range_table_list);
-                               }
+                               if (!s->maxdata_list)
+                                       break;  /* error handled below */
+                               kfree(s->range_table_list);
+                               s->range_table = NULL;
+                               s->range_table_list = NULL;
                                if (range) {
-                                       s->range_table = 0;
                                        s->range_table_list = range_table_list =
                                            kmalloc(sizeof
                                                    (struct
                                                     serial2002_range_table_t) *
                                                    s->n_chan, GFP_KERNEL);
+                                       if (!s->range_table_list)
+                                               break;  /* err handled below */
                                }
                                for (chan = 0, j = 0; j < 32; j++) {
                                        if (c[j].kind == kind) {
@@ -674,7 +676,26 @@ static int serial_2002_open(struct comedi_device *dev)
                                }
                        }
                }
-               result = 0;
+               if (i <= 4) {
+                       /* Failed to allocate maxdata_list or range_table_list
+                        * for a subdevice that needed it.  */
+                       result = -ENOMEM;
+                       for (i = 0; i <= 4; i++) {
+                               struct comedi_subdevice *s;
+
+                               s = &dev->subdevices[i];
+                               kfree(s->maxdata_list);
+                               s->maxdata_list = NULL;
+                               kfree(s->range_table_list);
+                               s->range_table_list = NULL;
+                       }
+               }
+               if (result) {
+                       if (devpriv->tty) {
+                               filp_close(devpriv->tty, 0);
+                               devpriv->tty = NULL;
+                       }
+               }
        }
        return result;
 }