diff options
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/vt.c | 14 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 67 |
2 files changed, 55 insertions, 26 deletions
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index fbd447b390f..740202d8a5c 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ con_set_default_unimap(vc); vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); if (!vc->vc_screenbuf) { - tty_port_destroy(&vc->port); kfree(vc); vc_cons[currcons].d = NULL; return -ENOMEM; @@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws) return ret; } -void vc_deallocate(unsigned int currcons) +struct vc_data *vc_deallocate(unsigned int currcons) { + struct vc_data *vc = NULL; + WARN_CONSOLE_UNLOCKED(); if (vc_cons_allocated(currcons)) { - struct vc_data *vc = vc_cons[currcons].d; - struct vt_notifier_param param = { .vc = vc }; + struct vt_notifier_param param; + param.vc = vc = vc_cons[currcons].d; atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m); vcs_remove_sysfs(currcons); vc->vc_sw->con_deinit(vc); put_pid(vc->vt_pid); module_put(vc->vc_sw->owner); kfree(vc->vc_screenbuf); - if (currcons >= MIN_NR_CONSOLES) { - tty_port_destroy(&vc->port); - kfree(vc); - } vc_cons[currcons].d = NULL; } + return vc; } /* diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 98ff1735eaf..fc2c06c66e8 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -283,6 +283,51 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ return 0; } +/* deallocate a single console, if possible (leave 0) */ +static int vt_disallocate(unsigned int vc_num) +{ + struct vc_data *vc = NULL; + int ret = 0; + + if (!vc_num) + return 0; + + console_lock(); + if (VT_BUSY(vc_num)) + ret = -EBUSY; + else + vc = vc_deallocate(vc_num); + console_unlock(); + + if (vc && vc_num >= MIN_NR_CONSOLES) { + tty_port_destroy(&vc->port); + kfree(vc); + } + + return ret; +} + +/* deallocate all unused consoles, but leave 0 */ +static void vt_disallocate_all(void) +{ + struct vc_data *vc[MAX_NR_CONSOLES]; + int i; + + console_lock(); + for (i = 1; i < MAX_NR_CONSOLES; i++) + if (!VT_BUSY(i)) + vc[i] = vc_deallocate(i); + else + vc[i] = NULL; + console_unlock(); + + for (i = 1; i < MAX_NR_CONSOLES; i++) { + if (vc[i] && i >= MIN_NR_CONSOLES) { + tty_port_destroy(&vc[i]->port); + kfree(vc[i]); + } + } +} /* @@ -769,24 +814,10 @@ int vt_ioctl(struct tty_struct *tty, ret = -ENXIO; break; } - if (arg == 0) { - /* deallocate all unused consoles, but leave 0 */ - console_lock(); - for (i=1; i<MAX_NR_CONSOLES; i++) - if (! VT_BUSY(i)) - vc_deallocate(i); - console_unlock(); - } else { - /* deallocate a single console, if possible */ - arg--; - if (VT_BUSY(arg)) - ret = -EBUSY; - else if (arg) { /* leave 0 */ - console_lock(); - vc_deallocate(arg); - console_unlock(); - } - } + if (arg == 0) + vt_disallocate_all(); + else + ret = vt_disallocate(--arg); break; case VT_RESIZE: |