scsi: Rework handling of scsi_device.vpd_pg8[03]

Introduce struct scsi_vpd for the VPD page length, data and the RCU head
that will be used to free the VPD data. Use kfree_rcu() instead of
kfree() to free VPD data. Move the VPD buffer pointer check inside the
RCU read lock in the sysfs code. Only annotate pointers that are shared
across threads with __rcu. Use rcu_dereference() when dereferencing an
RCU pointer. This patch suppresses about twenty sparse complaints about
the vpd_pg8[03] pointers. This patch also fixes a race condition, namely
that updating of the VPD pointers and length variables in struct
scsi_device was not atomic with reference to the code reading these
variables. See also "Does the update code tolerate concurrent accesses?"
in Documentation/RCU/checklist.txt.

Fixes: commit 09e2b0b146 ("scsi: rescan VPD attributes")
Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
Acked-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Shane Seymour <shane.seymour@hpe.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Johannes Thumshirn <jthumshirn@suse.de>
Cc: Shane Seymour <shane.seymour@hpe.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Bart Van Assche
2017-08-29 08:50:13 -07:00
committed by Martin K. Petersen
parent 1e3f720a67
commit ccf1e0045e
4 changed files with 60 additions and 47 deletions

View File

@@ -80,6 +80,18 @@ struct scsi_event {
*/
};
/**
* struct scsi_vpd - SCSI Vital Product Data
* @rcu: For kfree_rcu().
* @len: Length in bytes of @data.
* @data: VPD data as defined in various T10 SCSI standard documents.
*/
struct scsi_vpd {
struct rcu_head rcu;
int len;
unsigned char data[];
};
struct scsi_device {
struct Scsi_Host *host;
struct request_queue *request_queue;
@@ -122,10 +134,8 @@ struct scsi_device {
const char * rev; /* ... "nullnullnullnull" before scan */
#define SCSI_VPD_PG_LEN 255
int vpd_pg83_len;
unsigned char __rcu *vpd_pg83;
int vpd_pg80_len;
unsigned char __rcu *vpd_pg80;
struct scsi_vpd __rcu *vpd_pg83;
struct scsi_vpd __rcu *vpd_pg80;
unsigned char current_tag; /* current tag */
struct scsi_target *sdev_target; /* used only for single_lun */