Browse Source

[scsi] Avoid duplicate calls to scsicmd_close()

When a SCSI device is closed in error, the shutdown of the device's
block data interface will probably lead to any outstanding commands
being closed (by whichever object is currently connected to the block
data interface).  However, commands remain in the list of outstanding
commands until the final reference is dropped.  The result is that
scsidev_close() will make a second call to scsicmd_close() for each
command.  This is harmless, but produces confusing debug messages.

Fix by treating the outstanding command list as holding an explicit
reference to each command, and removing the command from the list of
outstanding commands in scsicmd_close().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
9db9221ea0
1 changed files with 7 additions and 8 deletions
  1. 7
    8
      src/drivers/block/scsi.c

+ 7
- 8
src/drivers/block/scsi.c View File

371
 	struct scsi_command *scsicmd =
371
 	struct scsi_command *scsicmd =
372
 		container_of ( refcnt, struct scsi_command, refcnt );
372
 		container_of ( refcnt, struct scsi_command, refcnt );
373
 
373
 
374
-	/* Remove from list of commands */
375
-	list_del ( &scsicmd->list );
374
+	/* Drop reference to SCSI device */
376
 	scsidev_put ( scsicmd->scsidev );
375
 	scsidev_put ( scsicmd->scsidev );
377
 
376
 
378
 	/* Free command */
377
 	/* Free command */
395
 
394
 
396
 	/* Shut down interfaces */
395
 	/* Shut down interfaces */
397
 	intfs_shutdown ( rc, &scsicmd->scsi, &scsicmd->block, NULL );
396
 	intfs_shutdown ( rc, &scsicmd->scsi, &scsicmd->block, NULL );
397
+
398
+	/* Remove from list of commands and drop list's reference */
399
+	list_del ( &scsicmd->list );
400
+	scsicmd_put ( scsicmd );
398
 }
401
 }
399
 
402
 
400
 /**
403
 /**
733
 	if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 )
736
 	if ( ( rc = scsicmd_command ( scsicmd ) ) != 0 )
734
 		goto err_command;
737
 		goto err_command;
735
 
738
 
736
-	/* Attach to parent interface, mortalise self, and return */
739
+	/* Attach to parent interface, transfer reference to list, and return */
737
 	intf_plug_plug ( &scsicmd->block, block );
740
 	intf_plug_plug ( &scsicmd->block, block );
738
-	ref_put ( &scsicmd->refcnt );
739
 	return 0;
741
 	return 0;
740
 
742
 
741
  err_command:
743
  err_command:
843
 			 NULL );
845
 			 NULL );
844
 
846
 
845
 	/* Shut down any remaining commands */
847
 	/* Shut down any remaining commands */
846
-	list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list ) {
847
-		scsicmd_get ( scsicmd );
848
+	list_for_each_entry_safe ( scsicmd, tmp, &scsidev->cmds, list )
848
 		scsicmd_close ( scsicmd, rc );
849
 		scsicmd_close ( scsicmd, rc );
849
-		scsicmd_put ( scsicmd );
850
-	}
851
 }
850
 }
852
 
851
 
853
 /** SCSI device block interface operations */
852
 /** SCSI device block interface operations */

Loading…
Cancel
Save