Hi,

not suggesting the diff below, or anything, as i'm not familiar w/that
device_lookup() refcounting, nor have time to find out about it right now
by opening subr_autoconf.c, but is it even necessary, at all?
to unref while erroring out like that? or acceptable, but w/only devices
like gpio which don't move around often? :)

-Artturi


diff --git a/sys/dev/gpio/gpio.c b/sys/dev/gpio/gpio.c
index 0aa7ed5c69b..71b83e44227 100644
--- a/sys/dev/gpio/gpio.c
+++ b/sys/dev/gpio/gpio.c
@@ -254,8 +254,10 @@ gpioopen(dev_t dev, int flag, int mode, struct proc *p)
        if (sc == NULL)
                return (ENXIO);
 
-       if (sc->sc_opened)
+       if (sc->sc_opened) {
+               device_unref((struct device *)sc);
                return (EBUSY);
+       }
        sc->sc_opened = 1;
 
        return (0);
@@ -272,6 +274,7 @@ gpioclose(dev_t dev, int flag, int mode, struct proc *p)
 
        sc->sc_opened = 0;
 
+       device_unref((struct device *)sc);
        return (0);
 }
 
@@ -300,6 +303,7 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
        struct gpio_pin_set *set;
        struct device *dv;
        int pin, value, flags, npins, found;
+       int rv = 0;
 
        sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
        if (sc == NULL)
@@ -324,47 +328,65 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
 
                if (op->gp_name[0] != '\0') {
                        pin = gpio_pinbyname(sc, op->gp_name);
-                       if (pin == -1)
-                               return (EINVAL);
+                       if (pin == -1) {
+                               rv = EINVAL;
+                               goto _fail_unref;
+                       }
                } else
                        pin = op->gp_pin;
 
-               if (pin < 0 || pin >= sc->sc_npins)
-                       return (EINVAL);
+               if (pin < 0 || pin >= sc->sc_npins) {
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
 
                if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
-                   securelevel > 0)
-                       return (EPERM);
+                   securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                /* return read value */
                op->gp_value = gpiobus_pin_read(gc, pin);
                break;
        case GPIOPINWRITE:
-               if ((flag & FWRITE) == 0)
-                       return (EBADF);
+               if ((flag & FWRITE) == 0) {
+                       rv = EBADF;
+                       goto _fail_unref;
+               }
 
                op = (struct gpio_pin_op *)data;
 
                if (op->gp_name[0] != '\0') {
                        pin = gpio_pinbyname(sc, op->gp_name);
-                       if (pin == -1)
-                               return (EINVAL);
+                       if (pin == -1) {
+                               rv = EINVAL;
+                               goto _fail_unref;
+                       }
                } else
                        pin = op->gp_pin;
 
-               if (pin < 0 || pin >= sc->sc_npins)
-                       return (EINVAL);
+               if (pin < 0 || pin >= sc->sc_npins) {
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
 
-               if (sc->sc_pins[pin].pin_mapped)
-                       return (EBUSY);
+               if (sc->sc_pins[pin].pin_mapped) {
+                       rv = EBUSY;
+                       goto _fail_unref;
+               }
 
                if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
-                   securelevel > 0)
-                       return (EPERM);
+                   securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                value = op->gp_value;
-               if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
-                       return (EINVAL);
+               if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) {
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
 
                gpiobus_pin_write(gc, pin, value);
                /* return old value */
@@ -373,27 +395,37 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                sc->sc_pins[pin].pin_state = value;
                break;
        case GPIOPINTOGGLE:
-               if ((flag & FWRITE) == 0)
-                       return (EBADF);
+               if ((flag & FWRITE) == 0) {
+                       rv = EBADF;
+                       goto _fail_unref;
+               }
 
                op = (struct gpio_pin_op *)data;
 
                if (op->gp_name[0] != '\0') {
                        pin = gpio_pinbyname(sc, op->gp_name);
-                       if (pin == -1)
-                               return (EINVAL);
+                       if (pin == -1) {
+                               rv = EINVAL;
+                               goto _fail_unref;
+                       }
                } else
                        pin = op->gp_pin;
 
-               if (pin < 0 || pin >= sc->sc_npins)
-                       return (EINVAL);
+               if (pin < 0 || pin >= sc->sc_npins) {
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
 
-               if (sc->sc_pins[pin].pin_mapped)
-                       return (EBUSY);
+               if (sc->sc_pins[pin].pin_mapped) {
+                       rv = EBUSY;
+                       goto _fail_unref;
+               }
 
                if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
-                   securelevel > 0)
-                       return (EPERM);
+                   securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
                    GPIO_PIN_HIGH : GPIO_PIN_LOW);
@@ -404,8 +436,10 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                sc->sc_pins[pin].pin_state = value;
                break;
        case GPIOATTACH:
-               if (securelevel > 0)
-                       return (EPERM);
+               if (securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                attach = (struct gpio_attach *)data;
                bzero(&ga, sizeof(ga));
@@ -424,8 +458,10 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                }
                break;
        case GPIODETACH:
-               if (securelevel > 0)
-                       return (EPERM);
+               if (securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                attach = (struct gpio_attach *)data;
                LIST_FOREACH(gdev, &sc->sc_devs, sc_next) {
@@ -440,23 +476,32 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                }
                break;
        case GPIOPINSET:
-               if (securelevel > 0)
-                       return (EPERM);
+               if (securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                set = (struct gpio_pin_set *)data;
 
                if (set->gp_name[0] != '\0') {
                        pin = gpio_pinbyname(sc, set->gp_name);
-                       if (pin == -1)
-                               return (EINVAL);
+                       if (pin == -1) {
+                               rv = EINVAL;
+                               goto _fail_unref;
+                       }
                } else
                        pin = set->gp_pin;
-               if (pin < 0 || pin >= sc->sc_npins)
-                       return (EINVAL);
+               if (pin < 0 || pin >= sc->sc_npins) {
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
                flags = set->gp_flags;
                /* check that the controller supports all requested flags */
-               if ((flags & sc->sc_pins[pin].pin_caps) != flags)
-                       return (ENODEV);
+               if ((flags & sc->sc_pins[pin].pin_caps) != flags) {
+                       rv = ENODEV;
+                       goto _fail_unref;
+               }
+
                flags = set->gp_flags | GPIO_PIN_SET;
 
                set->gp_caps = sc->sc_pins[pin].pin_caps;
@@ -488,24 +533,33 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                }
                break;
        case GPIOPINUNSET:
-               if (securelevel > 0)
-                       return (EPERM);
+               if (securelevel > 0) {
+                       rv = EPERM;
+                       goto _fail_unref;
+               }
 
                set = (struct gpio_pin_set *)data;
                if (set->gp_name[0] != '\0') {
                        pin = gpio_pinbyname(sc, set->gp_name);
-                       if (pin == -1)
-                               return (EINVAL);
+                       if (pin == -1) {
+                               rv = EINVAL;
+                               goto _fail_unref;
+                       }
                } else
                        pin = set->gp_pin;
                
-               if (pin < 0 || pin >= sc->sc_npins)
-                       return (EINVAL);
-               if (sc->sc_pins[pin].pin_mapped)
-                       return (EBUSY);
-               if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET))
-                       return (EINVAL);
-
+               if (pin < 0 || pin >= sc->sc_npins){
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
+               if (sc->sc_pins[pin].pin_mapped) {
+                       rv EBUSY;
+                       goto _fail_unref;
+               }
+               if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)) {
+                       rv = EINVAL;
+                       goto _fail_unref;
+               }
                LIST_FOREACH(nm, &sc->sc_names, gp_next) {
                        if (nm->gp_pin == pin) {
                                LIST_REMOVE(nm, gp_next);
@@ -516,8 +570,10 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                sc->sc_pins[pin].pin_flags &= ~GPIO_PIN_SET;
                break;
        default:
-               return (ENOTTY);
+               rv = ENOTTY;
+               break;
        }
-
-       return (0);
+_fail_unref:
+       device_unref((struct device *)sc);
+       return (rv);
 }

Reply via email to