Re: [PATCH 2.6.20-rc5] Gigaset ISDN driver error handling fixes

2007-01-26 Thread Tilman Schmidt
Andrew Morton schrieb:
> On Wed, 17 Jan 2007 18:42:13 +0100 (CET)
> Tilman Schmidt <[EMAIL PROTECTED]> wrote:
> 
>> +mutex_init(>mutex);
>> +mutex_lock(>mutex);
> 
> I have vague memories of making rude comments about this a few months ago.

Rude comments from you? I must have missed that. ;-)

> It is very weird to lock a mutex just after intialising it.  I mean, if any 
> other
> thread can lock this mutex then there's a race.  If no other thread can
> lock it, then this thread doesn't need to either.

No other thread can lock it at this point, because the data structure
pointed to by cs is only just being created. The possibility for other
threads to access it is created a little later, however, specifically
by the calls to gigaset_if_init(cs) and gigaset_init_dev_sysfs(cs) in
line 741 and 744, so the mutex has to be locked before entering these.

But I admit the mutexed code section is cut a bit generously here.
Would something like the following reduce the weirdness sufficiently?
(compile tested only)


--- linux-2.6.20-rc6-work/drivers/isdn/gigaset/common.c 2007-01-25 
23:53:17.0 +0100
+++ local/drivers/isdn/gigaset/common.c 2007-01-26 13:38:42.0 +0100
@@ -640,7 +640,6 @@ struct cardstate *gigaset_initcs(struct
return NULL;
}
mutex_init(>mutex);
-   mutex_lock(>mutex);

gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
@@ -738,6 +737,9 @@ struct cardstate *gigaset_initcs(struct

++cs->cs_init;

+   mutex_lock(>mutex);
+
+   /* set up character device */
gigaset_if_init(cs);

/* set up device sysfs */
@@ -746,6 +748,9 @@ struct cardstate *gigaset_initcs(struct
spin_lock_irqsave(>lock, flags);
cs->running = 1;
spin_unlock_irqrestore(>lock, flags);
+
+   mutex_unlock(>mutex);
+
setup_timer(>timer, timer_tick, (unsigned long) cs);
cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
/* FIXME: can jiffies increase too much until the timer is added?
@@ -753,11 +758,9 @@ struct cardstate *gigaset_initcs(struct
add_timer(>timer);

gig_dbg(DEBUG_INIT, "cs initialized");
-   mutex_unlock(>mutex);
return cs;

 error:
-   mutex_unlock(>mutex);
gig_dbg(DEBUG_INIT, "failed");
gigaset_freecs(cs);
return NULL;


-- 
Tilman SchmidtE-Mail: [EMAIL PROTECTED]
Bonn, Germany
Diese Nachricht besteht zu 100% aus wiederverwerteten Bits.
Ungeöffnet mindestens haltbar bis: (siehe Rückseite)



signature.asc
Description: OpenPGP digital signature


Re: [PATCH 2.6.20-rc5] Gigaset ISDN driver error handling fixes

2007-01-26 Thread Tilman Schmidt
Andrew Morton schrieb:
 On Wed, 17 Jan 2007 18:42:13 +0100 (CET)
 Tilman Schmidt [EMAIL PROTECTED] wrote:
 
 +mutex_init(cs-mutex);
 +mutex_lock(cs-mutex);
 
 I have vague memories of making rude comments about this a few months ago.

Rude comments from you? I must have missed that. ;-)

 It is very weird to lock a mutex just after intialising it.  I mean, if any 
 other
 thread can lock this mutex then there's a race.  If no other thread can
 lock it, then this thread doesn't need to either.

No other thread can lock it at this point, because the data structure
pointed to by cs is only just being created. The possibility for other
threads to access it is created a little later, however, specifically
by the calls to gigaset_if_init(cs) and gigaset_init_dev_sysfs(cs) in
line 741 and 744, so the mutex has to be locked before entering these.

But I admit the mutexed code section is cut a bit generously here.
Would something like the following reduce the weirdness sufficiently?
(compile tested only)


--- linux-2.6.20-rc6-work/drivers/isdn/gigaset/common.c 2007-01-25 
23:53:17.0 +0100
+++ local/drivers/isdn/gigaset/common.c 2007-01-26 13:38:42.0 +0100
@@ -640,7 +640,6 @@ struct cardstate *gigaset_initcs(struct
return NULL;
}
mutex_init(cs-mutex);
-   mutex_lock(cs-mutex);

gig_dbg(DEBUG_INIT, allocating bcs[0..%d], channels - 1);
cs-bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
@@ -738,6 +737,9 @@ struct cardstate *gigaset_initcs(struct

++cs-cs_init;

+   mutex_lock(cs-mutex);
+
+   /* set up character device */
gigaset_if_init(cs);

/* set up device sysfs */
@@ -746,6 +748,9 @@ struct cardstate *gigaset_initcs(struct
spin_lock_irqsave(cs-lock, flags);
cs-running = 1;
spin_unlock_irqrestore(cs-lock, flags);
+
+   mutex_unlock(cs-mutex);
+
setup_timer(cs-timer, timer_tick, (unsigned long) cs);
cs-timer.expires = jiffies + msecs_to_jiffies(GIG_TICK);
/* FIXME: can jiffies increase too much until the timer is added?
@@ -753,11 +758,9 @@ struct cardstate *gigaset_initcs(struct
add_timer(cs-timer);

gig_dbg(DEBUG_INIT, cs initialized);
-   mutex_unlock(cs-mutex);
return cs;

 error:
-   mutex_unlock(cs-mutex);
gig_dbg(DEBUG_INIT, failed);
gigaset_freecs(cs);
return NULL;


-- 
Tilman SchmidtE-Mail: [EMAIL PROTECTED]
Bonn, Germany
Diese Nachricht besteht zu 100% aus wiederverwerteten Bits.
Ungeöffnet mindestens haltbar bis: (siehe Rückseite)



signature.asc
Description: OpenPGP digital signature


Re: [PATCH 2.6.20-rc5] Gigaset ISDN driver error handling fixes

2007-01-23 Thread Andrew Morton
On Wed, 17 Jan 2007 18:42:13 +0100 (CET)
Tilman Schmidt <[EMAIL PROTECTED]> wrote:

> + mutex_init(>mutex);
> + mutex_lock(>mutex);

I have vague memories of making rude comments about this a few months ago.

It is very weird to lock a mutex just after intialising it.  I mean, if any 
other
thread can lock this mutex then there's a race.  If no other thread can
lock it, then this thread doesn't need to either.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2.6.20-rc5] Gigaset ISDN driver error handling fixes

2007-01-23 Thread Andrew Morton
On Wed, 17 Jan 2007 18:42:13 +0100 (CET)
Tilman Schmidt [EMAIL PROTECTED] wrote:

 + mutex_init(cs-mutex);
 + mutex_lock(cs-mutex);

I have vague memories of making rude comments about this a few months ago.

It is very weird to lock a mutex just after intialising it.  I mean, if any 
other
thread can lock this mutex then there's a race.  If no other thread can
lock it, then this thread doesn't need to either.
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2.6.20-rc5] Gigaset ISDN driver error handling fixes (resend)

2007-01-18 Thread Tilman Schmidt
My apologies if anyone is getting this more than once. I still haven't
seen it appear on the list after two attempts, so I'm sending it again,
this time through a different server.

Subject: [PATCH] Gigaset ISDN driver error handling fixes
From: Tilman Schmidt <[EMAIL PROTECTED]>

Fix several flaws in the error handling of the Siemens Gigaset ISDN
driver, including one that would cause an Oops when connecting more
than one device of the same type.

Signed-off-by: Tilman Schmidt <[EMAIL PROTECTED]>

---

--- linux-2.6.20-rc5-orig/drivers/isdn/gigaset/common.c 2007-01-15 
00:50:22.0 +0100
+++ linux-2.6.20-rc5-work/drivers/isdn/gigaset/common.c 2007-01-17 
11:45:44.0 +0100
@@ -356,16 +356,17 @@ static struct cardstate *alloc_cs(struct
 {
unsigned long flags;
unsigned i;
-   static struct cardstate *ret = NULL;
+   struct cardstate *ret = NULL;
 
spin_lock_irqsave(>lock, flags);
for (i = 0; i < drv->minors; ++i) {
if (!(drv->flags[i] & VALID_MINOR)) {
-   drv->flags[i] = VALID_MINOR;
-   ret = drv->cs + i;
-   }
-   if (ret)
+   if (try_module_get(drv->owner)) {
+   drv->flags[i] = VALID_MINOR;
+   ret = drv->cs + i;
+   }
break;
+   }
}
spin_unlock_irqrestore(>lock, flags);
return ret;
@@ -376,6 +377,8 @@ static void free_cs(struct cardstate *cs
unsigned long flags;
struct gigaset_driver *drv = cs->driver;
spin_lock_irqsave(>lock, flags);
+   if (drv->flags[cs->minor_index] & VALID_MINOR)
+   module_put(drv->owner);
drv->flags[cs->minor_index] = 0;
spin_unlock_irqrestore(>lock, flags);
 }
@@ -579,7 +582,7 @@ static struct bc_state *gigaset_initbcs(
} else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs->skb, HW_HDR_LEN);
else {
-   warn("could not allocate skb\n");
+   warn("could not allocate skb");
bcs->inputstate |= INS_skip_frame;
}
 
@@ -632,17 +635,25 @@ struct cardstate *gigaset_initcs(struct 
int i;
 
gig_dbg(DEBUG_INIT, "allocating cs");
-   cs = alloc_cs(drv);
-   if (!cs)
-   goto error;
+   if (!(cs = alloc_cs(drv))) {
+   err("maximum number of devices exceeded");
+   return NULL;
+   }
+   mutex_init(>mutex);
+   mutex_lock(>mutex);
+
gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
-   if (!cs->bcs)
+   if (!cs->bcs) {
+   err("out of memory");
goto error;
+   }
gig_dbg(DEBUG_INIT, "allocating inbuf");
cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
-   if (!cs->inbuf)
+   if (!cs->inbuf) {
+   err("out of memory");
goto error;
+   }
 
cs->cs_init = 0;
cs->channels = channels;
@@ -654,8 +665,6 @@ struct cardstate *gigaset_initcs(struct 
spin_lock_init(>ev_lock);
cs->ev_tail = 0;
cs->ev_head = 0;
-   mutex_init(>mutex);
-   mutex_lock(>mutex);
 
tasklet_init(>event_tasklet, _handle_event,
 (unsigned long) cs);
@@ -684,8 +693,10 @@ struct cardstate *gigaset_initcs(struct 
 
for (i = 0; i < channels; ++i) {
gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i);
-   if (!gigaset_initbcs(cs->bcs + i, cs, i))
+   if (!gigaset_initbcs(cs->bcs + i, cs, i)) {
+   err("could not allocate channel %d data", i);
goto error;
+   }
}
 
++cs->cs_init;
@@ -720,8 +731,10 @@ struct cardstate *gigaset_initcs(struct 
make_valid(cs, VALID_ID);
++cs->cs_init;
gig_dbg(DEBUG_INIT, "setting up hw");
-   if (!cs->ops->initcshw(cs))
+   if (!cs->ops->initcshw(cs)) {
+   err("could not allocate device specific data");
goto error;
+   }
 
++cs->cs_init;
 
@@ -743,8 +756,8 @@ struct cardstate *gigaset_initcs(struct 
mutex_unlock(>mutex);
return cs;
 
-error: if (cs)
-   mutex_unlock(>mutex);
+error:
+   mutex_unlock(>mutex);
gig_dbg(DEBUG_INIT, "failed");
gigaset_freecs(cs);
return NULL;
@@ -1040,7 +1053,6 @@ void gigaset_freedriver(struct gigaset_d
spin_unlock_irqrestore(_lock, flags);
 
gigaset_if_freedriver(drv);
-   module_put(drv->owner);
 
kfree(drv->cs);
kfree(drv->flags);
@@ -1072,10 +1084,6 @@ struct gigaset_driver *gigaset_initdrive
if (!drv)
return NULL;
 
-   if (!try_module_get(owner))
-   goto out1;
-

[PATCH 2.6.20-rc5] Gigaset ISDN driver error handling fixes (resend)

2007-01-18 Thread Tilman Schmidt
My apologies if anyone is getting this more than once. I still haven't
seen it appear on the list after two attempts, so I'm sending it again,
this time through a different server.

Subject: [PATCH] Gigaset ISDN driver error handling fixes
From: Tilman Schmidt [EMAIL PROTECTED]

Fix several flaws in the error handling of the Siemens Gigaset ISDN
driver, including one that would cause an Oops when connecting more
than one device of the same type.

Signed-off-by: Tilman Schmidt [EMAIL PROTECTED]

---

--- linux-2.6.20-rc5-orig/drivers/isdn/gigaset/common.c 2007-01-15 
00:50:22.0 +0100
+++ linux-2.6.20-rc5-work/drivers/isdn/gigaset/common.c 2007-01-17 
11:45:44.0 +0100
@@ -356,16 +356,17 @@ static struct cardstate *alloc_cs(struct
 {
unsigned long flags;
unsigned i;
-   static struct cardstate *ret = NULL;
+   struct cardstate *ret = NULL;
 
spin_lock_irqsave(drv-lock, flags);
for (i = 0; i  drv-minors; ++i) {
if (!(drv-flags[i]  VALID_MINOR)) {
-   drv-flags[i] = VALID_MINOR;
-   ret = drv-cs + i;
-   }
-   if (ret)
+   if (try_module_get(drv-owner)) {
+   drv-flags[i] = VALID_MINOR;
+   ret = drv-cs + i;
+   }
break;
+   }
}
spin_unlock_irqrestore(drv-lock, flags);
return ret;
@@ -376,6 +377,8 @@ static void free_cs(struct cardstate *cs
unsigned long flags;
struct gigaset_driver *drv = cs-driver;
spin_lock_irqsave(drv-lock, flags);
+   if (drv-flags[cs-minor_index]  VALID_MINOR)
+   module_put(drv-owner);
drv-flags[cs-minor_index] = 0;
spin_unlock_irqrestore(drv-lock, flags);
 }
@@ -579,7 +582,7 @@ static struct bc_state *gigaset_initbcs(
} else if ((bcs-skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
skb_reserve(bcs-skb, HW_HDR_LEN);
else {
-   warn(could not allocate skb\n);
+   warn(could not allocate skb);
bcs-inputstate |= INS_skip_frame;
}
 
@@ -632,17 +635,25 @@ struct cardstate *gigaset_initcs(struct 
int i;
 
gig_dbg(DEBUG_INIT, allocating cs);
-   cs = alloc_cs(drv);
-   if (!cs)
-   goto error;
+   if (!(cs = alloc_cs(drv))) {
+   err(maximum number of devices exceeded);
+   return NULL;
+   }
+   mutex_init(cs-mutex);
+   mutex_lock(cs-mutex);
+
gig_dbg(DEBUG_INIT, allocating bcs[0..%d], channels - 1);
cs-bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
-   if (!cs-bcs)
+   if (!cs-bcs) {
+   err(out of memory);
goto error;
+   }
gig_dbg(DEBUG_INIT, allocating inbuf);
cs-inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL);
-   if (!cs-inbuf)
+   if (!cs-inbuf) {
+   err(out of memory);
goto error;
+   }
 
cs-cs_init = 0;
cs-channels = channels;
@@ -654,8 +665,6 @@ struct cardstate *gigaset_initcs(struct 
spin_lock_init(cs-ev_lock);
cs-ev_tail = 0;
cs-ev_head = 0;
-   mutex_init(cs-mutex);
-   mutex_lock(cs-mutex);
 
tasklet_init(cs-event_tasklet, gigaset_handle_event,
 (unsigned long) cs);
@@ -684,8 +693,10 @@ struct cardstate *gigaset_initcs(struct 
 
for (i = 0; i  channels; ++i) {
gig_dbg(DEBUG_INIT, setting up bcs[%d].read, i);
-   if (!gigaset_initbcs(cs-bcs + i, cs, i))
+   if (!gigaset_initbcs(cs-bcs + i, cs, i)) {
+   err(could not allocate channel %d data, i);
goto error;
+   }
}
 
++cs-cs_init;
@@ -720,8 +731,10 @@ struct cardstate *gigaset_initcs(struct 
make_valid(cs, VALID_ID);
++cs-cs_init;
gig_dbg(DEBUG_INIT, setting up hw);
-   if (!cs-ops-initcshw(cs))
+   if (!cs-ops-initcshw(cs)) {
+   err(could not allocate device specific data);
goto error;
+   }
 
++cs-cs_init;
 
@@ -743,8 +756,8 @@ struct cardstate *gigaset_initcs(struct 
mutex_unlock(cs-mutex);
return cs;
 
-error: if (cs)
-   mutex_unlock(cs-mutex);
+error:
+   mutex_unlock(cs-mutex);
gig_dbg(DEBUG_INIT, failed);
gigaset_freecs(cs);
return NULL;
@@ -1040,7 +1053,6 @@ void gigaset_freedriver(struct gigaset_d
spin_unlock_irqrestore(driver_lock, flags);
 
gigaset_if_freedriver(drv);
-   module_put(drv-owner);
 
kfree(drv-cs);
kfree(drv-flags);
@@ -1072,10 +1084,6 @@ struct gigaset_driver *gigaset_initdrive
if (!drv)
return NULL;
 
-   if (!try_module_get(owner))
-   goto out1;
-
-   drv-cs = NULL;