]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.6.2/scsi-zfcp-restore-refcount-check-on-port_remove.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.6.2 / scsi-zfcp-restore-refcount-check-on-port_remove.patch
1 From d99b601b63386f3395dc26a699ae703a273d9982 Mon Sep 17 00:00:00 2001
2 From: Steffen Maier <maier@linux.vnet.ibm.com>
3 Date: Tue, 4 Sep 2012 15:23:34 +0200
4 Subject: SCSI: zfcp: restore refcount check on port_remove
5
6 From: Steffen Maier <maier@linux.vnet.ibm.com>
7
8 commit d99b601b63386f3395dc26a699ae703a273d9982 upstream.
9
10 Upstream commit f3450c7b917201bb49d67032e9f60d5125675d6a
11 "[SCSI] zfcp: Replace local reference counting with common kref"
12 accidentally dropped a reference count check before tearing down
13 zfcp_ports that are potentially in use by zfcp_units.
14 Even remote ports in use can be removed causing
15 unreachable garbage objects zfcp_ports with zfcp_units.
16 Thus units won't come back even after a manual port_rescan.
17 The kref of zfcp_port->dev.kobj is already used by the driver core.
18 We cannot re-use it to track the number of zfcp_units.
19 Re-introduce our own counter for units per port
20 and check on port_remove.
21
22 Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
23 Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
24 Signed-off-by: James Bottomley <JBottomley@Parallels.com>
25 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
26
27 ---
28 drivers/s390/scsi/zfcp_aux.c | 1 +
29 drivers/s390/scsi/zfcp_def.h | 1 +
30 drivers/s390/scsi/zfcp_ext.h | 1 +
31 drivers/s390/scsi/zfcp_sysfs.c | 18 ++++++++++++++++--
32 drivers/s390/scsi/zfcp_unit.c | 36 ++++++++++++++++++++++++++----------
33 5 files changed, 45 insertions(+), 12 deletions(-)
34
35 --- a/drivers/s390/scsi/zfcp_aux.c
36 +++ b/drivers/s390/scsi/zfcp_aux.c
37 @@ -519,6 +519,7 @@ struct zfcp_port *zfcp_port_enqueue(stru
38
39 rwlock_init(&port->unit_list_lock);
40 INIT_LIST_HEAD(&port->unit_list);
41 + atomic_set(&port->units, 0);
42
43 INIT_WORK(&port->gid_pn_work, zfcp_fc_port_did_lookup);
44 INIT_WORK(&port->test_link_work, zfcp_fc_link_test_work);
45 --- a/drivers/s390/scsi/zfcp_def.h
46 +++ b/drivers/s390/scsi/zfcp_def.h
47 @@ -205,6 +205,7 @@ struct zfcp_port {
48 struct zfcp_adapter *adapter; /* adapter used to access port */
49 struct list_head unit_list; /* head of logical unit list */
50 rwlock_t unit_list_lock; /* unit list lock */
51 + atomic_t units; /* zfcp_unit count */
52 atomic_t status; /* status of this remote port */
53 u64 wwnn; /* WWNN if known */
54 u64 wwpn; /* WWPN */
55 --- a/drivers/s390/scsi/zfcp_ext.h
56 +++ b/drivers/s390/scsi/zfcp_ext.h
57 @@ -159,6 +159,7 @@ extern void zfcp_scsi_dif_sense_error(st
58 extern struct attribute_group zfcp_sysfs_unit_attrs;
59 extern struct attribute_group zfcp_sysfs_adapter_attrs;
60 extern struct attribute_group zfcp_sysfs_port_attrs;
61 +extern struct mutex zfcp_sysfs_port_units_mutex;
62 extern struct device_attribute *zfcp_sysfs_sdev_attrs[];
63 extern struct device_attribute *zfcp_sysfs_shost_attrs[];
64
65 --- a/drivers/s390/scsi/zfcp_sysfs.c
66 +++ b/drivers/s390/scsi/zfcp_sysfs.c
67 @@ -227,6 +227,8 @@ static ssize_t zfcp_sysfs_port_rescan_st
68 static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL,
69 zfcp_sysfs_port_rescan_store);
70
71 +DEFINE_MUTEX(zfcp_sysfs_port_units_mutex);
72 +
73 static ssize_t zfcp_sysfs_port_remove_store(struct device *dev,
74 struct device_attribute *attr,
75 const char *buf, size_t count)
76 @@ -249,6 +251,16 @@ static ssize_t zfcp_sysfs_port_remove_st
77 else
78 retval = 0;
79
80 + mutex_lock(&zfcp_sysfs_port_units_mutex);
81 + if (atomic_read(&port->units) > 0) {
82 + retval = -EBUSY;
83 + mutex_unlock(&zfcp_sysfs_port_units_mutex);
84 + goto out;
85 + }
86 + /* port is about to be removed, so no more unit_add */
87 + atomic_set(&port->units, -1);
88 + mutex_unlock(&zfcp_sysfs_port_units_mutex);
89 +
90 write_lock_irq(&adapter->port_list_lock);
91 list_del(&port->list);
92 write_unlock_irq(&adapter->port_list_lock);
93 @@ -289,12 +301,14 @@ static ssize_t zfcp_sysfs_unit_add_store
94 {
95 struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
96 u64 fcp_lun;
97 + int retval;
98
99 if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
100 return -EINVAL;
101
102 - if (zfcp_unit_add(port, fcp_lun))
103 - return -EINVAL;
104 + retval = zfcp_unit_add(port, fcp_lun);
105 + if (retval)
106 + return retval;
107
108 return count;
109 }
110 --- a/drivers/s390/scsi/zfcp_unit.c
111 +++ b/drivers/s390/scsi/zfcp_unit.c
112 @@ -104,7 +104,7 @@ static void zfcp_unit_release(struct dev
113 {
114 struct zfcp_unit *unit = container_of(dev, struct zfcp_unit, dev);
115
116 - put_device(&unit->port->dev);
117 + atomic_dec(&unit->port->units);
118 kfree(unit);
119 }
120
121 @@ -119,16 +119,27 @@ static void zfcp_unit_release(struct dev
122 int zfcp_unit_add(struct zfcp_port *port, u64 fcp_lun)
123 {
124 struct zfcp_unit *unit;
125 + int retval = 0;
126 +
127 + mutex_lock(&zfcp_sysfs_port_units_mutex);
128 + if (atomic_read(&port->units) == -1) {
129 + /* port is already gone */
130 + retval = -ENODEV;
131 + goto out;
132 + }
133
134 unit = zfcp_unit_find(port, fcp_lun);
135 if (unit) {
136 put_device(&unit->dev);
137 - return -EEXIST;
138 + retval = -EEXIST;
139 + goto out;
140 }
141
142 unit = kzalloc(sizeof(struct zfcp_unit), GFP_KERNEL);
143 - if (!unit)
144 - return -ENOMEM;
145 + if (!unit) {
146 + retval = -ENOMEM;
147 + goto out;
148 + }
149
150 unit->port = port;
151 unit->fcp_lun = fcp_lun;
152 @@ -139,28 +150,33 @@ int zfcp_unit_add(struct zfcp_port *port
153 if (dev_set_name(&unit->dev, "0x%016llx",
154 (unsigned long long) fcp_lun)) {
155 kfree(unit);
156 - return -ENOMEM;
157 + retval = -ENOMEM;
158 + goto out;
159 }
160
161 - get_device(&port->dev);
162 -
163 if (device_register(&unit->dev)) {
164 put_device(&unit->dev);
165 - return -ENOMEM;
166 + retval = -ENOMEM;
167 + goto out;
168 }
169
170 if (sysfs_create_group(&unit->dev.kobj, &zfcp_sysfs_unit_attrs)) {
171 device_unregister(&unit->dev);
172 - return -EINVAL;
173 + retval = -EINVAL;
174 + goto out;
175 }
176
177 + atomic_inc(&port->units); /* under zfcp_sysfs_port_units_mutex ! */
178 +
179 write_lock_irq(&port->unit_list_lock);
180 list_add_tail(&unit->list, &port->unit_list);
181 write_unlock_irq(&port->unit_list_lock);
182
183 zfcp_unit_scsi_scan(unit);
184
185 - return 0;
186 +out:
187 + mutex_unlock(&zfcp_sysfs_port_units_mutex);
188 + return retval;
189 }
190
191 /**