Commit 28d49f8c authored by Brian King's avatar Brian King Committed by Greg Kroah-Hartman

hvcs: Synchronize hotplug remove with port free

Synchronizes hotplug remove with the freeing of the port.
This ensures we have freed all the memory associated with
this port and are not leaking memory.
Signed-off-by: default avatarBrian King <brking@linux.vnet.ibm.com>
Link: https://lore.kernel.org/r/20230203155802.404324-6-brking@linux.vnet.ibm.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d432228b
......@@ -52,6 +52,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/kref.h>
......@@ -285,6 +286,7 @@ struct hvcs_struct {
char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
struct list_head next; /* list management */
struct vio_dev *vdev;
struct completion *destroyed;
};
static LIST_HEAD(hvcs_structs);
......@@ -663,11 +665,13 @@ static void hvcs_destruct_port(struct tty_port *p)
{
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
struct completion *comp;
unsigned long flags;
spin_lock(&hvcs_structs_lock);
spin_lock_irqsave(&hvcsd->lock, flags);
comp = hvcsd->destroyed;
/* the list_del poisons the pointers */
list_del(&(hvcsd->next));
......@@ -687,6 +691,7 @@ static void hvcs_destruct_port(struct tty_port *p)
hvcsd->p_unit_address = 0;
hvcsd->p_partition_ID = 0;
hvcsd->destroyed = NULL;
hvcs_return_index(hvcsd->index);
memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
......@@ -694,6 +699,8 @@ static void hvcs_destruct_port(struct tty_port *p)
spin_unlock(&hvcs_structs_lock);
kfree(hvcsd);
if (comp)
complete(comp);
}
static const struct tty_port_operations hvcs_port_ops = {
......@@ -792,6 +799,7 @@ static int hvcs_probe(
static void hvcs_remove(struct vio_dev *dev)
{
struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
DECLARE_COMPLETION_ONSTACK(comp);
unsigned long flags;
struct tty_struct *tty;
......@@ -799,16 +807,11 @@ static void hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
hvcsd->destroyed = &comp;
tty = tty_port_tty_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
/*
* Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below.
*/
tty_port_put(&hvcsd->port);
/*
* The tty should always be valid at this time unless a
* simultaneous tty close already cleaned up the hvcs_struct.
......@@ -818,6 +821,8 @@ static void hvcs_remove(struct vio_dev *dev)
tty_kref_put(tty);
}
tty_port_put(&hvcsd->port);
wait_for_completion(&comp);
printk(KERN_INFO "HVCS: vty-server@%X removed from the"
" vio bus.\n", dev->unit_address);
};
......@@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
if (--hvcsd->port.count == 0) {
if (hvcsd->port.count == 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
return;
} else if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
......@@ -1227,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty)
vio_disable_interrupts(hvcsd->vdev);
hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
tty->driver_data = NULL;
hvcsd->port.tty = NULL;
hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment