diff options
author | Jörn Engel <joern@logfs.org> | 2012-04-25 11:17:29 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-05-17 10:08:56 +0100 |
commit | 035d12e658fba287a223361bc7dd442dd6737b68 (patch) | |
tree | 1017b20cd9432b9507c485098171c74ee478aeb1 /drivers/scsi/sg.c | |
parent | b499e5249eb80e4a7e71cfd04c6f628abdb27498 (diff) | |
download | lwn-035d12e658fba287a223361bc7dd442dd6737b68.tar.gz lwn-035d12e658fba287a223361bc7dd442dd6737b68.zip |
[SCSI] sg: completely protect sfds
sfds is protected by sg_index_lock - except for sg_open(), where it
isn't. Change that and add some documentation.
Signed-off-by: Joern Engel <joern@logfs.org>
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 8e15c448a761..53af8089dcb9 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -146,6 +146,7 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ } Sg_request; typedef struct sg_fd { /* holds the state of a file descriptor */ + /* sfd_siblings is protected by sg_index_lock */ struct list_head sfd_siblings; struct sg_device *parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ @@ -172,6 +173,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ u32 index; /* device index number */ + /* sfds is protected by sg_index_lock */ struct list_head sfds; volatile char detached; /* 0->attached, 1->detached pending removal */ /* exclude protected by sg_open_exclusive_lock */ @@ -244,6 +246,17 @@ static int set_exclude(Sg_device *sdp, char val) return val; } +static int sfds_list_empty(Sg_device *sdp) +{ + unsigned long flags; + int ret; + + read_lock_irqsave(&sg_index_lock, flags); + ret = list_empty(&sdp->sfds); + read_unlock_irqrestore(&sg_index_lock, flags); + return ret; +} + static int sg_open(struct inode *inode, struct file *filp) { @@ -287,12 +300,12 @@ sg_open(struct inode *inode, struct file *filp) retval = -EPERM; /* Can't lock it with read only access */ goto error_out; } - if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) { + if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) { retval = -EBUSY; goto error_out; } res = wait_event_interruptible(sdp->o_excl_wait, - ((!list_empty(&sdp->sfds) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1))); + ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1))); if (res) { retval = res; /* -ERESTARTSYS because signal hit process */ goto error_out; @@ -312,7 +325,7 @@ sg_open(struct inode *inode, struct file *filp) retval = -ENODEV; goto error_out; } - if (list_empty(&sdp->sfds)) { /* no existing opens on this device */ + if (sfds_list_empty(sdp)) { /* no existing opens on this device */ sdp->sgdebug = 0; q = sdp->device->request_queue; sdp->sg_tablesize = queue_max_segments(q); |