aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/sg.c50
1 files changed, 14 insertions, 36 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index d45ac4aab92f..7bf54c9a33bb 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -140,7 +140,7 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
140} Sg_request; 140} Sg_request;
141 141
142typedef struct sg_fd { /* holds the state of a file descriptor */ 142typedef struct sg_fd { /* holds the state of a file descriptor */
143 struct sg_fd *nextfp; /* NULL when last opened fd on this device */ 143 struct list_head sfd_siblings;
144 struct sg_device *parentdp; /* owning device */ 144 struct sg_device *parentdp; /* owning device */
145 wait_queue_head_t read_wait; /* queue read until command done */ 145 wait_queue_head_t read_wait; /* queue read until command done */
146 rwlock_t rq_list_lock; /* protect access to list in req_arr */ 146 rwlock_t rq_list_lock; /* protect access to list in req_arr */
@@ -167,7 +167,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
167 wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ 167 wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
168 int sg_tablesize; /* adapter's max scatter-gather table size */ 168 int sg_tablesize; /* adapter's max scatter-gather table size */
169 u32 index; /* device index number */ 169 u32 index; /* device index number */
170 Sg_fd *headfp; /* first open fd belonging to this device */ 170 struct list_head sfds;
171 volatile char detached; /* 0->attached, 1->detached pending removal */ 171 volatile char detached; /* 0->attached, 1->detached pending removal */
172 volatile char exclude; /* opened for exclusive access */ 172 volatile char exclude; /* opened for exclusive access */
173 char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ 173 char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
@@ -258,13 +258,13 @@ sg_open(struct inode *inode, struct file *filp)
258 retval = -EPERM; /* Can't lock it with read only access */ 258 retval = -EPERM; /* Can't lock it with read only access */
259 goto error_out; 259 goto error_out;
260 } 260 }
261 if (sdp->headfp && (flags & O_NONBLOCK)) { 261 if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) {
262 retval = -EBUSY; 262 retval = -EBUSY;
263 goto error_out; 263 goto error_out;
264 } 264 }
265 res = 0; 265 res = 0;
266 __wait_event_interruptible(sdp->o_excl_wait, 266 __wait_event_interruptible(sdp->o_excl_wait,
267 ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); 267 ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
268 if (res) { 268 if (res) {
269 retval = res; /* -ERESTARTSYS because signal hit process */ 269 retval = res; /* -ERESTARTSYS because signal hit process */
270 goto error_out; 270 goto error_out;
@@ -286,7 +286,7 @@ sg_open(struct inode *inode, struct file *filp)
286 retval = -ENODEV; 286 retval = -ENODEV;
287 goto error_out; 287 goto error_out;
288 } 288 }
289 if (!sdp->headfp) { /* no existing opens on this device */ 289 if (list_empty(&sdp->sfds)) { /* no existing opens on this device */
290 sdp->sgdebug = 0; 290 sdp->sgdebug = 0;
291 q = sdp->device->request_queue; 291 q = sdp->device->request_queue;
292 sdp->sg_tablesize = min(q->max_hw_segments, 292 sdp->sg_tablesize = min(q->max_hw_segments,
@@ -1375,6 +1375,7 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
1375 disk->first_minor = k; 1375 disk->first_minor = k;
1376 sdp->disk = disk; 1376 sdp->disk = disk;
1377 sdp->device = scsidp; 1377 sdp->device = scsidp;
1378 INIT_LIST_HEAD(&sdp->sfds);
1378 init_waitqueue_head(&sdp->o_excl_wait); 1379 init_waitqueue_head(&sdp->o_excl_wait);
1379 sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); 1380 sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
1380 sdp->index = k; 1381 sdp->index = k;
@@ -1517,7 +1518,7 @@ static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
1517 /* Need a write lock to set sdp->detached. */ 1518 /* Need a write lock to set sdp->detached. */
1518 write_lock_irqsave(&sg_index_lock, iflags); 1519 write_lock_irqsave(&sg_index_lock, iflags);
1519 sdp->detached = 1; 1520 sdp->detached = 1;
1520 for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) { 1521 list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
1521 wake_up_interruptible(&sfp->read_wait); 1522 wake_up_interruptible(&sfp->read_wait);
1522 kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); 1523 kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
1523 } 1524 }
@@ -2024,14 +2025,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
2024 sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; 2025 sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
2025 sfp->parentdp = sdp; 2026 sfp->parentdp = sdp;
2026 write_lock_irqsave(&sg_index_lock, iflags); 2027 write_lock_irqsave(&sg_index_lock, iflags);
2027 if (!sdp->headfp) 2028 list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
2028 sdp->headfp = sfp;
2029 else { /* add to tail of existing list */
2030 Sg_fd *pfp = sdp->headfp;
2031 while (pfp->nextfp)
2032 pfp = pfp->nextfp;
2033 pfp->nextfp = sfp;
2034 }
2035 write_unlock_irqrestore(&sg_index_lock, iflags); 2029 write_unlock_irqrestore(&sg_index_lock, iflags);
2036 SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); 2030 SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
2037 if (unlikely(sg_big_buff != def_reserved_size)) 2031 if (unlikely(sg_big_buff != def_reserved_size))
@@ -2080,28 +2074,10 @@ static void sg_remove_sfp(struct kref *kref)
2080{ 2074{
2081 struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref); 2075 struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref);
2082 struct sg_device *sdp = sfp->parentdp; 2076 struct sg_device *sdp = sfp->parentdp;
2083 Sg_fd *fp;
2084 Sg_fd *prev_fp;
2085 unsigned long iflags; 2077 unsigned long iflags;
2086 2078
2087 /* CAUTION! Note that sfp can still be found by walking sdp->headfp
2088 * even though the refcount is now 0. Therefore, unlink sfp from
2089 * sdp->headfp BEFORE doing any other cleanup.
2090 */
2091
2092 write_lock_irqsave(&sg_index_lock, iflags); 2079 write_lock_irqsave(&sg_index_lock, iflags);
2093 prev_fp = sdp->headfp; 2080 list_del(&sfp->sfd_siblings);
2094 if (sfp == prev_fp)
2095 sdp->headfp = prev_fp->nextfp;
2096 else {
2097 while ((fp = prev_fp->nextfp)) {
2098 if (sfp == fp) {
2099 prev_fp->nextfp = fp->nextfp;
2100 break;
2101 }
2102 prev_fp = fp;
2103 }
2104 }
2105 write_unlock_irqrestore(&sg_index_lock, iflags); 2081 write_unlock_irqrestore(&sg_index_lock, iflags);
2106 wake_up_interruptible(&sdp->o_excl_wait); 2082 wake_up_interruptible(&sdp->o_excl_wait);
2107 2083
@@ -2486,10 +2462,12 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
2486 const char * cp; 2462 const char * cp;
2487 unsigned int ms; 2463 unsigned int ms;
2488 2464
2489 for (k = 0, fp = sdp->headfp; fp != NULL; ++k, fp = fp->nextfp) { 2465 k = 0;
2466 list_for_each_entry(fp, &sdp->sfds, sfd_siblings) {
2467 k++;
2490 read_lock(&fp->rq_list_lock); /* irqs already disabled */ 2468 read_lock(&fp->rq_list_lock); /* irqs already disabled */
2491 seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " 2469 seq_printf(s, " FD(%d): timeout=%dms bufflen=%d "
2492 "(res)sgat=%d low_dma=%d\n", k + 1, 2470 "(res)sgat=%d low_dma=%d\n", k,
2493 jiffies_to_msecs(fp->timeout), 2471 jiffies_to_msecs(fp->timeout),
2494 fp->reserve.bufflen, 2472 fp->reserve.bufflen,
2495 (int) fp->reserve.k_use_sg, 2473 (int) fp->reserve.k_use_sg,
@@ -2559,7 +2537,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
2559 2537
2560 read_lock_irqsave(&sg_index_lock, iflags); 2538 read_lock_irqsave(&sg_index_lock, iflags);
2561 sdp = it ? sg_lookup_dev(it->index) : NULL; 2539 sdp = it ? sg_lookup_dev(it->index) : NULL;
2562 if (sdp && sdp->headfp) { 2540 if (sdp && !list_empty(&sdp->sfds)) {
2563 struct scsi_device *scsidp = sdp->device; 2541 struct scsi_device *scsidp = sdp->device;
2564 2542
2565 seq_printf(s, " >>> device=%s ", sdp->disk->disk_name); 2543 seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);