mirror of https://gitee.com/openkylin/linux.git
TTY: con3215, centralize allocation
There are two copies of allocations of device information. One of them is totally broken. See: raw->cdev = cdev; raw->inbuf = (char *) raw + sizeof(struct raw3215_info); memset(raw, 0, sizeof(struct raw3215_info)); It suggests that this path was never executed. The code uses both raw->cdev and raw->inbuf all over. And it is NULL due to the memset here, so it would panic immediately. I believe nobody used that driver without being a system console. Either way, let us fix it by moving the allocations (and initializations) to a single place. This will save us some double initializations later too. And while at it, initialize the timer properly -- once, at the allocation. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9f8c0b081d
commit
fe2fc9ca5d
|
@ -324,10 +324,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
|
|||
}
|
||||
} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
|
||||
/* delay small writes */
|
||||
init_timer(&raw->timer);
|
||||
raw->timer.expires = RAW3215_TIMEOUT + jiffies;
|
||||
raw->timer.data = (unsigned long) raw;
|
||||
raw->timer.function = raw3215_timeout;
|
||||
add_timer(&raw->timer);
|
||||
raw->flags |= RAW3215_TIMER_RUNS;
|
||||
}
|
||||
|
@ -648,6 +645,35 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
|||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
}
|
||||
|
||||
static struct raw3215_info *raw3215_alloc_info(void)
|
||||
{
|
||||
struct raw3215_info *info;
|
||||
|
||||
info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
if (!info->buffer || !info->inbuf) {
|
||||
kfree(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
|
||||
init_waitqueue_head(&info->empty_wait);
|
||||
tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void raw3215_free_info(struct raw3215_info *raw)
|
||||
{
|
||||
kfree(raw->inbuf);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
}
|
||||
|
||||
static int raw3215_probe (struct ccw_device *cdev)
|
||||
{
|
||||
struct raw3215_info *raw;
|
||||
|
@ -656,11 +682,15 @@ static int raw3215_probe (struct ccw_device *cdev)
|
|||
/* Console is special. */
|
||||
if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
|
||||
return 0;
|
||||
raw = kmalloc(sizeof(struct raw3215_info) +
|
||||
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
|
||||
|
||||
raw = raw3215_alloc_info();
|
||||
if (raw == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
raw->cdev = cdev;
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
spin_lock(&raw3215_device_lock);
|
||||
for (line = 0; line < NR_3215; line++) {
|
||||
if (!raw3215[line]) {
|
||||
|
@ -670,28 +700,10 @@ static int raw3215_probe (struct ccw_device *cdev)
|
|||
}
|
||||
spin_unlock(&raw3215_device_lock);
|
||||
if (line == NR_3215) {
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
raw->cdev = cdev;
|
||||
raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
|
||||
memset(raw, 0, sizeof(struct raw3215_info));
|
||||
raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
|
||||
GFP_KERNEL|GFP_DMA);
|
||||
if (raw->buffer == NULL) {
|
||||
spin_lock(&raw3215_device_lock);
|
||||
raw3215[line] = NULL;
|
||||
spin_unlock(&raw3215_device_lock);
|
||||
kfree(raw);
|
||||
return -ENOMEM;
|
||||
}
|
||||
init_waitqueue_head(&raw->empty_wait);
|
||||
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
|
||||
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -703,8 +715,7 @@ static void raw3215_remove (struct ccw_device *cdev)
|
|||
raw = dev_get_drvdata(&cdev->dev);
|
||||
if (raw) {
|
||||
dev_set_drvdata(&cdev->dev, NULL);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -897,23 +908,16 @@ static int __init con3215_init(void)
|
|||
if (IS_ERR(cdev))
|
||||
return -ENODEV;
|
||||
|
||||
raw3215[0] = raw = (struct raw3215_info *)
|
||||
kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
|
||||
raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
raw3215[0] = raw = raw3215_alloc_info();
|
||||
raw->cdev = cdev;
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
raw->flags |= RAW3215_FIXED;
|
||||
init_waitqueue_head(&raw->empty_wait);
|
||||
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
|
||||
|
||||
/* Request the console irq */
|
||||
if (raw3215_startup(raw) != 0) {
|
||||
kfree(raw->inbuf);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
raw3215[0] = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue