Commit 2b559a3e authored by Daniel Wagner's avatar Daniel Wagner Committed by Christoph Hellwig
Browse files

nvmet-fcloop: prevent double port deletion



The delete callback can be called either via the unregister function or
from the transport directly. Thus it is necessary ensure resources are
not freed multiple times.

Signed-off-by: default avatarDaniel Wagner <wagi@kernel.org>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 47a827cd
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -215,6 +215,9 @@ struct fcloop_lport_priv {
	struct fcloop_lport *lport;
};

/* The port is already being removed, avoid double free */
#define PORT_DELETED	0

struct fcloop_rport {
	struct nvme_fc_remote_port	*remoteport;
	struct nvmet_fc_target_port	*targetport;
@@ -223,6 +226,7 @@ struct fcloop_rport {
	spinlock_t			lock;
	struct list_head		ls_list;
	struct work_struct		ls_work;
	unsigned long			flags;
};

struct fcloop_tport {
@@ -233,6 +237,7 @@ struct fcloop_tport {
	spinlock_t			lock;
	struct list_head		ls_list;
	struct work_struct		ls_work;
	unsigned long			flags;
};

struct fcloop_nport {
@@ -1061,14 +1066,18 @@ static void
fcloop_remoteport_delete(struct nvme_fc_remote_port *remoteport)
{
	struct fcloop_rport *rport = remoteport->private;
	bool put_port = false;
	unsigned long flags;

	flush_work(&rport->ls_work);

	spin_lock_irqsave(&fcloop_lock, flags);
	if (!test_and_set_bit(PORT_DELETED, &rport->flags))
		put_port = true;
	rport->nport->rport = NULL;
	spin_unlock_irqrestore(&fcloop_lock, flags);

	if (put_port)
		fcloop_nport_put(rport->nport);
}

@@ -1076,14 +1085,18 @@ static void
fcloop_targetport_delete(struct nvmet_fc_target_port *targetport)
{
	struct fcloop_tport *tport = targetport->private;
	bool put_port = false;
	unsigned long flags;

	flush_work(&tport->ls_work);

	spin_lock_irqsave(&fcloop_lock, flags);
	if (!test_and_set_bit(PORT_DELETED, &tport->flags))
		put_port = true;
	tport->nport->tport = NULL;
	spin_unlock_irqrestore(&fcloop_lock, flags);

	if (put_port)
		fcloop_nport_put(tport->nport);
}

@@ -1427,6 +1440,7 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr,
	rport->nport = nport;
	rport->lport = nport->lport;
	nport->rport = rport;
	rport->flags = 0;
	spin_lock_init(&rport->lock);
	INIT_WORK(&rport->ls_work, fcloop_rport_lsrqst_work);
	INIT_LIST_HEAD(&rport->ls_list);
@@ -1524,6 +1538,7 @@ fcloop_create_target_port(struct device *dev, struct device_attribute *attr,
	tport->nport = nport;
	tport->lport = nport->lport;
	nport->tport = tport;
	tport->flags = 0;
	spin_lock_init(&tport->lock);
	INIT_WORK(&tport->ls_work, fcloop_tport_lsrqst_work);
	INIT_LIST_HEAD(&tport->ls_list);