Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] fc_transport: fix sysfs deadlock on vport delete

When the vport attribute "delete" is used to delete the vport, sysfs
deadlocks waiting for the write to complete, which is waiting for the
sysfs teardown to complete. Moved this effort to a work_q element.

Took the opportunity to make some other cosmetic changes:
- removed tabs in Doc file - replaced with expanded spaces
- minor copyright text and author text updates
- removed a bunch of trailing whitespace

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

authored by

James Smart and committed by
James Bottomley
9ef3e4a4 bee4fe8e

+105 -93
+63 -63
Documentation/scsi/scsi_fc_transport.txt
··· 119 119 120 120 The new fc_vport class object has the following attributes 121 121 122 - node_name: Read_Only 122 + node_name: Read_Only 123 123 The WWNN of the vport 124 124 125 - port_name: Read_Only 125 + port_name: Read_Only 126 126 The WWPN of the vport 127 127 128 - roles: Read_Only 128 + roles: Read_Only 129 129 Indicates the FC4 roles enabled on the vport. 130 130 131 - symbolic_name: Read_Write 131 + symbolic_name: Read_Write 132 132 A string, appended to the driver's symbolic port name string, which 133 133 is registered with the switch to identify the vport. For example, 134 134 a hypervisor could set this string to "Xen Domain 2 VM 5 Vport 2", 135 135 and this set of identifiers can be seen on switch management screens 136 136 to identify the port. 137 137 138 - vport_delete: Write_Only 138 + vport_delete: Write_Only 139 139 When written with a "1", will tear down the vport. 140 140 141 - vport_disable: Write_Only 141 + vport_disable: Write_Only 142 142 When written with a "1", will transition the vport to a disabled. 143 143 state. The vport will still be instantiated with the Linux kernel, 144 144 but it will not be active on the FC link. 145 145 When written with a "0", will enable the vport. 146 146 147 - vport_last_state: Read_Only 147 + vport_last_state: Read_Only 148 148 Indicates the previous state of the vport. See the section below on 149 149 "Vport States". 150 150 151 - vport_state: Read_Only 151 + vport_state: Read_Only 152 152 Indicates the state of the vport. See the section below on 153 153 "Vport States". 154 154 155 - vport_type: Read_Only 155 + vport_type: Read_Only 156 156 Reflects the FC mechanism used to create the virtual port. 157 157 Only NPIV is supported currently. 158 158 159 159 160 160 For the fc_host class object, the following attributes are added for vports: 161 161 162 - max_npiv_vports: Read_Only 162 + max_npiv_vports: Read_Only 163 163 Indicates the maximum number of NPIV-based vports that the 164 164 driver/adapter can support on the fc_host. 165 165 166 - npiv_vports_inuse: Read_Only 166 + npiv_vports_inuse: Read_Only 167 167 Indicates how many NPIV-based vports have been instantiated on the 168 168 fc_host. 169 169 170 - vport_create: Write_Only 170 + vport_create: Write_Only 171 171 A "simple" create interface to instantiate a vport on an fc_host. 172 172 A "<WWPN>:<WWNN>" string is written to the attribute. The transport 173 173 then instantiates the vport object and calls the LLDD to create the 174 174 vport with the role of FCP_Initiator. Each WWN is specified as 16 175 175 hex characters and may *not* contain any prefixes (e.g. 0x, x, etc). 176 176 177 - vport_delete: Write_Only 177 + vport_delete: Write_Only 178 178 A "simple" delete interface to teardown a vport. A "<WWPN>:<WWNN>" 179 - string is written to the attribute. The transport will locate the 180 - vport on the fc_host with the same WWNs and tear it down. Each WWN 181 - is specified as 16 hex characters and may *not* contain any prefixes 182 - (e.g. 0x, x, etc). 179 + string is written to the attribute. The transport will locate the 180 + vport on the fc_host with the same WWNs and tear it down. Each WWN 181 + is specified as 16 hex characters and may *not* contain any prefixes 182 + (e.g. 0x, x, etc). 183 183 184 184 185 185 Vport States: ··· 198 198 Once a vport has been instantiated with the kernel/LLDD, a vport state 199 199 can be reported via the sysfs attribute. The following states exist: 200 200 201 - FC_VPORT_UNKNOWN - Unknown 201 + FC_VPORT_UNKNOWN - Unknown 202 202 An temporary state, typically set only while the vport is being 203 203 instantiated with the kernel and LLDD. 204 204 205 - FC_VPORT_ACTIVE - Active 205 + FC_VPORT_ACTIVE - Active 206 206 The vport has been successfully been created on the FC link. 207 207 It is fully functional. 208 208 209 - FC_VPORT_DISABLED - Disabled 209 + FC_VPORT_DISABLED - Disabled 210 210 The vport instantiated, but "disabled". The vport is not instantiated 211 211 on the FC link. This is equivalent to a physical port with the 212 212 link "down". 213 213 214 - FC_VPORT_LINKDOWN - Linkdown 214 + FC_VPORT_LINKDOWN - Linkdown 215 215 The vport is not operational as the physical link is not operational. 216 216 217 - FC_VPORT_INITIALIZING - Initializing 217 + FC_VPORT_INITIALIZING - Initializing 218 218 The vport is in the process of instantiating on the FC link. 219 219 The LLDD will set this state just prior to starting the ELS traffic 220 220 to create the vport. This state will persist until the vport is ··· 222 222 (state is one of the values below). As this state is transitory, 223 223 it will not be preserved in the "vport_last_state". 224 224 225 - FC_VPORT_NO_FABRIC_SUPP - No Fabric Support 225 + FC_VPORT_NO_FABRIC_SUPP - No Fabric Support 226 226 The vport is not operational. One of the following conditions were 227 227 encountered: 228 228 - The FC topology is not Point-to-Point 229 229 - The FC port is not connected to an F_Port 230 230 - The F_Port has indicated that NPIV is not supported. 231 231 232 - FC_VPORT_NO_FABRIC_RSCS - No Fabric Resources 232 + FC_VPORT_NO_FABRIC_RSCS - No Fabric Resources 233 233 The vport is not operational. The Fabric failed FDISC with a status 234 234 indicating that it does not have sufficient resources to complete 235 235 the operation. 236 236 237 - FC_VPORT_FABRIC_LOGOUT - Fabric Logout 237 + FC_VPORT_FABRIC_LOGOUT - Fabric Logout 238 238 The vport is not operational. The Fabric has LOGO'd the N_Port_ID 239 239 associated with the vport. 240 240 241 - FC_VPORT_FABRIC_REJ_WWN - Fabric Rejected WWN 241 + FC_VPORT_FABRIC_REJ_WWN - Fabric Rejected WWN 242 242 The vport is not operational. The Fabric failed FDISC with a status 243 243 indicating that the WWN's are not valid. 244 244 245 - FC_VPORT_FAILED - VPort Failed 245 + FC_VPORT_FAILED - VPort Failed 246 246 The vport is not operational. This is a catchall for all other 247 247 error conditions. 248 248 249 249 250 250 The following state table indicates the different state transitions: 251 251 252 - State Event New State 252 + State Event New State 253 253 -------------------------------------------------------------------- 254 - n/a Initialization Unknown 255 - Unknown: Link Down Linkdown 256 - Link Up & Loop No Fabric Support 257 - Link Up & no Fabric No Fabric Support 258 - Link Up & FLOGI response No Fabric Support 259 - indicates no NPIV support 260 - Link Up & FDISC being sent Initializing 261 - Disable request Disable 262 - Linkdown: Link Up Unknown 263 - Initializing: FDISC ACC Active 264 - FDISC LS_RJT w/ no resources No Fabric Resources 265 - FDISC LS_RJT w/ invalid Fabric Rejected WWN 266 - pname or invalid nport_id 267 - FDISC LS_RJT failed for Vport Failed 268 - other reasons 269 - Link Down Linkdown 270 - Disable request Disable 271 - Disable: Enable request Unknown 272 - Active: LOGO received from fabric Fabric Logout 273 - Link Down Linkdown 274 - Disable request Disable 275 - Fabric Logout: Link still up Unknown 254 + n/a Initialization Unknown 255 + Unknown: Link Down Linkdown 256 + Link Up & Loop No Fabric Support 257 + Link Up & no Fabric No Fabric Support 258 + Link Up & FLOGI response No Fabric Support 259 + indicates no NPIV support 260 + Link Up & FDISC being sent Initializing 261 + Disable request Disable 262 + Linkdown: Link Up Unknown 263 + Initializing: FDISC ACC Active 264 + FDISC LS_RJT w/ no resources No Fabric Resources 265 + FDISC LS_RJT w/ invalid Fabric Rejected WWN 266 + pname or invalid nport_id 267 + FDISC LS_RJT failed for Vport Failed 268 + other reasons 269 + Link Down Linkdown 270 + Disable request Disable 271 + Disable: Enable request Unknown 272 + Active: LOGO received from fabric Fabric Logout 273 + Link Down Linkdown 274 + Disable request Disable 275 + Fabric Logout: Link still up Unknown 276 276 277 277 The following 4 error states all have the same transitions: 278 278 No Fabric Support: 279 279 No Fabric Resources: 280 280 Fabric Rejected WWN: 281 281 Vport Failed: 282 - Disable request Disable 283 - Link goes down Linkdown 282 + Disable request Disable 283 + Link goes down Linkdown 284 284 285 285 286 286 Transport <-> LLDD Interfaces : ··· 303 303 int vport_create(struct fc_vport *vport, bool disable) 304 304 305 305 where: 306 - vport: Is the newly allocated vport object 307 - disable: If "true", the vport is to be created in a disabled stated. 308 - If "false", the vport is to be enabled upon creation. 306 + vport: Is the newly allocated vport object 307 + disable: If "true", the vport is to be created in a disabled stated. 308 + If "false", the vport is to be enabled upon creation. 309 309 310 310 When a request is made to create a new vport (via sgio/netlink, or the 311 311 vport_create fc_host attribute), the transport will validate that the LLDD ··· 342 342 - Validate Infrastructure: 343 343 - If the driver or adapter cannot support another vport, whether 344 344 due to improper firmware, (a lie about) max_npiv, or a lack of 345 - some other resource - return VPCERR_UNSUPPORTED. 345 + some other resource - return VPCERR_UNSUPPORTED. 346 346 - If the driver validates the WWN's against those already active on 347 347 the adapter and detects an overlap - return VPCERR_BAD_WWN. 348 348 - If the driver detects the topology is loop, non-fabric, or the ··· 351 351 of memory conditions, return the respective negative Exxx error code. 352 352 - If the role is FCP Initiator, the LLDD is to : 353 353 - Call scsi_host_alloc() to allocate a scsi_host for the vport. 354 - - Call scsi_add_host(new_shost, &vport->dev) to start the scsi_host 355 - and bind it as a child of the vport device. 356 - - Initializes the fc_host attribute values. 354 + - Call scsi_add_host(new_shost, &vport->dev) to start the scsi_host 355 + and bind it as a child of the vport device. 356 + - Initializes the fc_host attribute values. 357 357 - Kick of further vport state transitions based on the disable flag and 358 358 link state - and return success (zero). 359 359 ··· 376 376 int vport_disable(struct fc_vport *vport, bool disable) 377 377 378 378 where: 379 - vport: Is vport to to be enabled or disabled 380 - disable: If "true", the vport is to be disabled. 381 - If "false", the vport is to be enabled. 379 + vport: Is vport to to be enabled or disabled 380 + disable: If "true", the vport is to be disabled. 381 + If "false", the vport is to be enabled. 382 382 383 383 When a request is made to change the disabled state on a vport, the 384 384 transport will validate the request against the existing vport state. ··· 404 404 int vport_delete(struct fc_vport *vport) 405 405 406 406 where: 407 - vport: Is vport to delete 407 + vport: Is vport to delete 408 408 409 409 When a request is made to delete a vport (via sgio/netlink, or via the 410 410 fc_host or fc_vport vport_delete attributes), the transport will call
+35 -24
drivers/scsi/scsi_transport_fc.c
··· 1 - /* 1 + /* 2 2 * FiberChannel transport specific attributes exported to sysfs. 3 3 * 4 4 * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. ··· 22 22 * Copyright (C) 2004-2007 James Smart, Emulex Corporation 23 23 * Rewrite for host, target, device, and remote port attributes, 24 24 * statistics, and service functions... 25 + * Add vports, etc 25 26 * 26 27 */ 27 28 #include <linux/module.h> ··· 38 37 #include "scsi_priv.h" 39 38 40 39 static int fc_queue_work(struct Scsi_Host *, struct work_struct *); 40 + static void fc_vport_sched_delete(struct work_struct *work); 41 41 42 42 /* 43 43 * This is a temporary carrier for creating a vport. It will eventually ··· 379 377 struct Scsi_Host *shost = dev_to_shost(dev); 380 378 struct fc_host_attrs *fc_host = shost_to_fc_host(shost); 381 379 382 - /* 380 + /* 383 381 * Set default values easily detected by the midlayer as 384 382 * failure cases. The scsi lldd is responsible for initializing 385 383 * all transport attributes to valid values per host. ··· 1200 1198 size_t count) 1201 1199 { 1202 1200 struct fc_vport *vport = transport_class_to_vport(cdev); 1203 - int stat; 1201 + struct Scsi_Host *shost = vport_to_shost(vport); 1204 1202 1205 - stat = fc_vport_terminate(vport); 1206 - if (stat) 1207 - return stat; 1208 - 1203 + fc_queue_work(shost, &vport->vport_delete_work); 1209 1204 return count; 1210 1205 } 1211 1206 static FC_CLASS_DEVICE_ATTR(vport, vport_delete, S_IWUSR, ··· 1995 1996 i->t.eh_timed_out = fc_timed_out; 1996 1997 1997 1998 i->t.user_scan = fc_user_scan; 1998 - 1999 + 1999 2000 /* 2000 2001 * Setup SCSI Target Attributes. 2001 2002 */ ··· 2214 2215 struct workqueue_struct *work_q; 2215 2216 struct fc_host_attrs *fc_host = shost_to_fc_host(shost); 2216 2217 unsigned long flags; 2217 - int stat; 2218 2218 2219 2219 spin_lock_irqsave(shost->host_lock, flags); 2220 2220 2221 2221 /* Remove any vports */ 2222 - list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) { 2223 - spin_unlock_irqrestore(shost->host_lock, flags); 2224 - /* this must be called synchronously */ 2225 - stat = fc_vport_terminate(vport); 2226 - spin_lock_irqsave(shost->host_lock, flags); 2227 - if (stat) 2228 - dev_printk(KERN_ERR, vport->dev.parent, 2229 - "%s: %s could not be deleted created via " 2230 - "shost%d channel %d\n", __FUNCTION__, 2231 - vport->dev.bus_id, vport->shost->host_no, 2232 - vport->channel); 2233 - } 2222 + list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) 2223 + fc_queue_work(shost, &vport->vport_delete_work); 2234 2224 2235 2225 /* Remove any remote ports */ 2236 2226 list_for_each_entry_safe(rport, next_rport, ··· 2296 2308 unsigned long flags; 2297 2309 2298 2310 /* 2299 - * if a scan is pending, flush the SCSI Host work_q so that 2311 + * if a scan is pending, flush the SCSI Host work_q so that 2300 2312 * that we can reclaim the rport scan work element. 2301 2313 */ 2302 2314 if (rport->flags & FC_RPORT_SCAN_PENDING) ··· 2846 2858 * fc_timeout_deleted_rport - Timeout handler for a deleted remote port, 2847 2859 * which we blocked, and has now failed to return 2848 2860 * in the allotted time. 2849 - * 2861 + * 2850 2862 * @work: rport target that failed to reappear in the allotted time. 2851 2863 **/ 2852 2864 static void ··· 3049 3061 vport->shost = shost; 3050 3062 vport->channel = channel; 3051 3063 vport->flags = FC_VPORT_CREATING; 3064 + INIT_WORK(&vport->vport_delete_work, fc_vport_sched_delete); 3052 3065 3053 3066 spin_lock_irqsave(shost->host_lock, flags); 3054 3067 ··· 3196 3207 } 3197 3208 EXPORT_SYMBOL(fc_vport_terminate); 3198 3209 3210 + /** 3211 + * fc_vport_sched_delete - workq-based delete request for a vport 3212 + * 3213 + * @work: vport to be deleted. 3214 + **/ 3215 + static void 3216 + fc_vport_sched_delete(struct work_struct *work) 3217 + { 3218 + struct fc_vport *vport = 3219 + container_of(work, struct fc_vport, vport_delete_work); 3220 + int stat; 3199 3221 3200 - MODULE_AUTHOR("Martin Hicks"); 3222 + stat = fc_vport_terminate(vport); 3223 + if (stat) 3224 + dev_printk(KERN_ERR, vport->dev.parent, 3225 + "%s: %s could not be deleted created via " 3226 + "shost%d channel %d - error %d\n", __FUNCTION__, 3227 + vport->dev.bus_id, vport->shost->host_no, 3228 + vport->channel, stat); 3229 + } 3230 + 3231 + 3232 + /* Original Author: Martin Hicks */ 3233 + MODULE_AUTHOR("James Smart"); 3201 3234 MODULE_DESCRIPTION("FC Transport Attributes"); 3202 3235 MODULE_LICENSE("GPL"); 3203 3236
+7 -6
include/scsi/scsi_transport_fc.h
··· 1 - /* 1 + /* 2 2 * FiberChannel transport specific attributes exported to sysfs. 3 3 * 4 4 * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. ··· 104 104 105 105 106 106 107 - /* 107 + /* 108 108 * FC Classes of Service 109 109 * Note: values are not enumerated, as they can be "or'd" together 110 110 * for reporting (e.g. report supported_classes). If you alter this list, ··· 117 117 #define FC_COS_CLASS4 0x10 118 118 #define FC_COS_CLASS6 0x40 119 119 120 - /* 120 + /* 121 121 * FC Port Speeds 122 122 * Note: values are not enumerated, as they can be "or'd" together 123 123 * for reporting (e.g. report supported_speeds). If you alter this list, ··· 223 223 u8 flags; 224 224 struct list_head peers; 225 225 struct device dev; 226 + struct work_struct vport_delete_work; 226 227 } __attribute__((aligned(sizeof(unsigned long)))); 227 228 228 229 /* bit field values for struct fc_vport "flags" field: */ ··· 398 397 u64 prim_seq_protocol_err_count; 399 398 u64 invalid_tx_word_count; 400 399 u64 invalid_crc_count; 401 - 400 + 402 401 /* fc4 statistics (only FCP supported currently) */ 403 402 u64 fcp_input_requests; 404 403 u64 fcp_output_requests; ··· 593 592 u32 dd_fcrport_size; 594 593 u32 dd_fcvport_size; 595 594 596 - /* 595 + /* 597 596 * The driver sets these to tell the transport class it 598 597 * wants the attributes displayed in sysfs. If the show_ flag 599 598 * is not set, the attribute will be private to the transport 600 - * class 599 + * class 601 600 */ 602 601 603 602 /* remote port fixed attributes */