提交 28d49f8c 编写于 作者: B Brian King 提交者: 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: NBrian King <brking@linux.vnet.ibm.com>
Link: https://lore.kernel.org/r/20230203155802.404324-6-brking@linux.vnet.ibm.comSigned-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 d432228b
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/completion.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h> #include <linux/kref.h>
...@@ -285,6 +286,7 @@ struct hvcs_struct { ...@@ -285,6 +286,7 @@ struct hvcs_struct {
char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */ char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
struct list_head next; /* list management */ struct list_head next; /* list management */
struct vio_dev *vdev; struct vio_dev *vdev;
struct completion *destroyed;
}; };
static LIST_HEAD(hvcs_structs); static LIST_HEAD(hvcs_structs);
...@@ -663,11 +665,13 @@ static void hvcs_destruct_port(struct tty_port *p) ...@@ -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 hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev; struct vio_dev *vdev;
struct completion *comp;
unsigned long flags; unsigned long flags;
spin_lock(&hvcs_structs_lock); spin_lock(&hvcs_structs_lock);
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
comp = hvcsd->destroyed;
/* the list_del poisons the pointers */ /* the list_del poisons the pointers */
list_del(&(hvcsd->next)); list_del(&(hvcsd->next));
...@@ -687,6 +691,7 @@ static void hvcs_destruct_port(struct tty_port *p) ...@@ -687,6 +691,7 @@ static void hvcs_destruct_port(struct tty_port *p)
hvcsd->p_unit_address = 0; hvcsd->p_unit_address = 0;
hvcsd->p_partition_ID = 0; hvcsd->p_partition_ID = 0;
hvcsd->destroyed = NULL;
hvcs_return_index(hvcsd->index); hvcs_return_index(hvcsd->index);
memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1); memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
...@@ -694,6 +699,8 @@ static void hvcs_destruct_port(struct tty_port *p) ...@@ -694,6 +699,8 @@ static void hvcs_destruct_port(struct tty_port *p)
spin_unlock(&hvcs_structs_lock); spin_unlock(&hvcs_structs_lock);
kfree(hvcsd); kfree(hvcsd);
if (comp)
complete(comp);
} }
static const struct tty_port_operations hvcs_port_ops = { static const struct tty_port_operations hvcs_port_ops = {
...@@ -792,6 +799,7 @@ static int hvcs_probe( ...@@ -792,6 +799,7 @@ static int hvcs_probe(
static void hvcs_remove(struct vio_dev *dev) static void hvcs_remove(struct vio_dev *dev)
{ {
struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev); struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
DECLARE_COMPLETION_ONSTACK(comp);
unsigned long flags; unsigned long flags;
struct tty_struct *tty; struct tty_struct *tty;
...@@ -799,16 +807,11 @@ static void hvcs_remove(struct vio_dev *dev) ...@@ -799,16 +807,11 @@ static void hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags); spin_lock_irqsave(&hvcsd->lock, flags);
hvcsd->destroyed = &comp;
tty = tty_port_tty_get(&hvcsd->port); tty = tty_port_tty_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags); 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 * The tty should always be valid at this time unless a
* simultaneous tty close already cleaned up the hvcs_struct. * simultaneous tty close already cleaned up the hvcs_struct.
...@@ -818,6 +821,8 @@ static void hvcs_remove(struct vio_dev *dev) ...@@ -818,6 +821,8 @@ static void hvcs_remove(struct vio_dev *dev)
tty_kref_put(tty); tty_kref_put(tty);
} }
tty_port_put(&hvcsd->port);
wait_for_completion(&comp);
printk(KERN_INFO "HVCS: vty-server@%X removed from the" printk(KERN_INFO "HVCS: vty-server@%X removed from the"
" vio bus.\n", dev->unit_address); " vio bus.\n", dev->unit_address);
}; };
...@@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) ...@@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data; hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags); 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); vio_disable_interrupts(hvcsd->vdev);
...@@ -1227,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty) ...@@ -1227,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty)
vio_disable_interrupts(hvcsd->vdev); vio_disable_interrupts(hvcsd->vdev);
hvcsd->todo_mask = 0; 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.tty = NULL;
hvcsd->port.count = 0; hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup /* This will drop any buffered data on the floor which is OK in a hangup
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册