aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r--drivers/scsi/sg.c176
1 files changed, 81 insertions, 95 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index df5e961484e1..5cbc4bb1b395 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -105,11 +105,8 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
105static int sg_add(struct device *, struct class_interface *); 105static int sg_add(struct device *, struct class_interface *);
106static void sg_remove(struct device *, struct class_interface *); 106static void sg_remove(struct device *, struct class_interface *);
107 107
108static DEFINE_SPINLOCK(sg_open_exclusive_lock);
109
110static DEFINE_IDR(sg_index_idr); 108static DEFINE_IDR(sg_index_idr);
111static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock 109static DEFINE_RWLOCK(sg_index_lock);
112 file descriptor list for device */
113 110
114static struct class_interface sg_interface = { 111static struct class_interface sg_interface = {
115 .add_dev = sg_add, 112 .add_dev = sg_add,
@@ -146,8 +143,7 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
146} Sg_request; 143} Sg_request;
147 144
148typedef struct sg_fd { /* holds the state of a file descriptor */ 145typedef struct sg_fd { /* holds the state of a file descriptor */
149 /* sfd_siblings is protected by sg_index_lock */ 146 struct list_head sfd_siblings; /* protected by sfd_lock of device */
150 struct list_head sfd_siblings;
151 struct sg_device *parentdp; /* owning device */ 147 struct sg_device *parentdp; /* owning device */
152 wait_queue_head_t read_wait; /* queue read until command done */ 148 wait_queue_head_t read_wait; /* queue read until command done */
153 rwlock_t rq_list_lock; /* protect access to list in req_arr */ 149 rwlock_t rq_list_lock; /* protect access to list in req_arr */
@@ -170,13 +166,12 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
170 166
171typedef struct sg_device { /* holds the state of each scsi generic device */ 167typedef struct sg_device { /* holds the state of each scsi generic device */
172 struct scsi_device *device; 168 struct scsi_device *device;
173 wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
174 int sg_tablesize; /* adapter's max scatter-gather table size */ 169 int sg_tablesize; /* adapter's max scatter-gather table size */
175 u32 index; /* device index number */ 170 u32 index; /* device index number */
176 /* sfds is protected by sg_index_lock */ 171 spinlock_t sfd_lock; /* protect file descriptor list for device */
177 struct list_head sfds; 172 struct list_head sfds;
173 struct rw_semaphore o_sem; /* exclude open should hold this rwsem */
178 volatile char detached; /* 0->attached, 1->detached pending removal */ 174 volatile char detached; /* 0->attached, 1->detached pending removal */
179 /* exclude protected by sg_open_exclusive_lock */
180 char exclude; /* opened for exclusive access */ 175 char exclude; /* opened for exclusive access */
181 char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ 176 char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
182 struct gendisk *disk; 177 struct gendisk *disk;
@@ -225,35 +220,14 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd)
225 return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE); 220 return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
226} 221}
227 222
228static int get_exclude(Sg_device *sdp)
229{
230 unsigned long flags;
231 int ret;
232
233 spin_lock_irqsave(&sg_open_exclusive_lock, flags);
234 ret = sdp->exclude;
235 spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
236 return ret;
237}
238
239static int set_exclude(Sg_device *sdp, char val)
240{
241 unsigned long flags;
242
243 spin_lock_irqsave(&sg_open_exclusive_lock, flags);
244 sdp->exclude = val;
245 spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
246 return val;
247}
248
249static int sfds_list_empty(Sg_device *sdp) 223static int sfds_list_empty(Sg_device *sdp)
250{ 224{
251 unsigned long flags; 225 unsigned long flags;
252 int ret; 226 int ret;
253 227
254 read_lock_irqsave(&sg_index_lock, flags); 228 spin_lock_irqsave(&sdp->sfd_lock, flags);
255 ret = list_empty(&sdp->sfds); 229 ret = list_empty(&sdp->sfds);
256 read_unlock_irqrestore(&sg_index_lock, flags); 230 spin_unlock_irqrestore(&sdp->sfd_lock, flags);
257 return ret; 231 return ret;
258} 232}
259 233
@@ -265,7 +239,6 @@ sg_open(struct inode *inode, struct file *filp)
265 struct request_queue *q; 239 struct request_queue *q;
266 Sg_device *sdp; 240 Sg_device *sdp;
267 Sg_fd *sfp; 241 Sg_fd *sfp;
268 int res;
269 int retval; 242 int retval;
270 243
271 nonseekable_open(inode, filp); 244 nonseekable_open(inode, filp);
@@ -294,54 +267,52 @@ sg_open(struct inode *inode, struct file *filp)
294 goto error_out; 267 goto error_out;
295 } 268 }
296 269
297 if (flags & O_EXCL) { 270 if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE))) {
298 if (O_RDONLY == (flags & O_ACCMODE)) { 271 retval = -EPERM; /* Can't lock it with read only access */
299 retval = -EPERM; /* Can't lock it with read only access */
300 goto error_out;
301 }
302 if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
303 retval = -EBUSY;
304 goto error_out;
305 }
306 res = wait_event_interruptible(sdp->o_excl_wait,
307 ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
308 if (res) {
309 retval = res; /* -ERESTARTSYS because signal hit process */
310 goto error_out;
311 }
312 } else if (get_exclude(sdp)) { /* some other fd has an exclusive lock on dev */
313 if (flags & O_NONBLOCK) {
314 retval = -EBUSY;
315 goto error_out;
316 }
317 res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
318 if (res) {
319 retval = res; /* -ERESTARTSYS because signal hit process */
320 goto error_out;
321 }
322 }
323 if (sdp->detached) {
324 retval = -ENODEV;
325 goto error_out; 272 goto error_out;
326 } 273 }
274 if (flags & O_NONBLOCK) {
275 if (flags & O_EXCL) {
276 if (!down_write_trylock(&sdp->o_sem)) {
277 retval = -EBUSY;
278 goto error_out;
279 }
280 } else {
281 if (!down_read_trylock(&sdp->o_sem)) {
282 retval = -EBUSY;
283 goto error_out;
284 }
285 }
286 } else {
287 if (flags & O_EXCL)
288 down_write(&sdp->o_sem);
289 else
290 down_read(&sdp->o_sem);
291 }
292 /* Since write lock is held, no need to check sfd_list */
293 if (flags & O_EXCL)
294 sdp->exclude = 1; /* used by release lock */
295
327 if (sfds_list_empty(sdp)) { /* no existing opens on this device */ 296 if (sfds_list_empty(sdp)) { /* no existing opens on this device */
328 sdp->sgdebug = 0; 297 sdp->sgdebug = 0;
329 q = sdp->device->request_queue; 298 q = sdp->device->request_queue;
330 sdp->sg_tablesize = queue_max_segments(q); 299 sdp->sg_tablesize = queue_max_segments(q);
331 } 300 }
332 if ((sfp = sg_add_sfp(sdp, dev))) 301 sfp = sg_add_sfp(sdp, dev);
302 if (!IS_ERR(sfp))
333 filp->private_data = sfp; 303 filp->private_data = sfp;
304 /* retval is already provably zero at this point because of the
305 * check after retval = scsi_autopm_get_device(sdp->device))
306 */
334 else { 307 else {
308 retval = PTR_ERR(sfp);
309
335 if (flags & O_EXCL) { 310 if (flags & O_EXCL) {
336 set_exclude(sdp, 0); /* undo if error */ 311 sdp->exclude = 0; /* undo if error */
337 wake_up_interruptible(&sdp->o_excl_wait); 312 up_write(&sdp->o_sem);
338 } 313 } else
339 retval = -ENOMEM; 314 up_read(&sdp->o_sem);
340 goto error_out;
341 }
342 retval = 0;
343error_out: 315error_out:
344 if (retval) {
345 scsi_autopm_put_device(sdp->device); 316 scsi_autopm_put_device(sdp->device);
346sdp_put: 317sdp_put:
347 scsi_device_put(sdp->device); 318 scsi_device_put(sdp->device);
@@ -358,13 +329,18 @@ sg_release(struct inode *inode, struct file *filp)
358{ 329{
359 Sg_device *sdp; 330 Sg_device *sdp;
360 Sg_fd *sfp; 331 Sg_fd *sfp;
332 int excl;
361 333
362 if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) 334 if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
363 return -ENXIO; 335 return -ENXIO;
364 SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); 336 SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
365 337
366 set_exclude(sdp, 0); 338 excl = sdp->exclude;
367 wake_up_interruptible(&sdp->o_excl_wait); 339 sdp->exclude = 0;
340 if (excl)
341 up_write(&sdp->o_sem);
342 else
343 up_read(&sdp->o_sem);
368 344
369 scsi_autopm_put_device(sdp->device); 345 scsi_autopm_put_device(sdp->device);
370 kref_put(&sfp->f_ref, sg_remove_sfp); 346 kref_put(&sfp->f_ref, sg_remove_sfp);
@@ -1415,8 +1391,9 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
1415 disk->first_minor = k; 1391 disk->first_minor = k;
1416 sdp->disk = disk; 1392 sdp->disk = disk;
1417 sdp->device = scsidp; 1393 sdp->device = scsidp;
1394 spin_lock_init(&sdp->sfd_lock);
1418 INIT_LIST_HEAD(&sdp->sfds); 1395 INIT_LIST_HEAD(&sdp->sfds);
1419 init_waitqueue_head(&sdp->o_excl_wait); 1396 init_rwsem(&sdp->o_sem);
1420 sdp->sg_tablesize = queue_max_segments(q); 1397 sdp->sg_tablesize = queue_max_segments(q);
1421 sdp->index = k; 1398 sdp->index = k;
1422 kref_init(&sdp->d_ref); 1399 kref_init(&sdp->d_ref);
@@ -1549,11 +1526,13 @@ static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
1549 1526
1550 /* Need a write lock to set sdp->detached. */ 1527 /* Need a write lock to set sdp->detached. */
1551 write_lock_irqsave(&sg_index_lock, iflags); 1528 write_lock_irqsave(&sg_index_lock, iflags);
1529 spin_lock(&sdp->sfd_lock);
1552 sdp->detached = 1; 1530 sdp->detached = 1;
1553 list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) { 1531 list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
1554 wake_up_interruptible(&sfp->read_wait); 1532 wake_up_interruptible(&sfp->read_wait);
1555 kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); 1533 kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
1556 } 1534 }
1535 spin_unlock(&sdp->sfd_lock);
1557 write_unlock_irqrestore(&sg_index_lock, iflags); 1536 write_unlock_irqrestore(&sg_index_lock, iflags);
1558 1537
1559 sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); 1538 sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
@@ -2064,7 +2043,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
2064 2043
2065 sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); 2044 sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
2066 if (!sfp) 2045 if (!sfp)
2067 return NULL; 2046 return ERR_PTR(-ENOMEM);
2068 2047
2069 init_waitqueue_head(&sfp->read_wait); 2048 init_waitqueue_head(&sfp->read_wait);
2070 rwlock_init(&sfp->rq_list_lock); 2049 rwlock_init(&sfp->rq_list_lock);
@@ -2078,9 +2057,13 @@ sg_add_sfp(Sg_device * sdp, int dev)
2078 sfp->cmd_q = SG_DEF_COMMAND_Q; 2057 sfp->cmd_q = SG_DEF_COMMAND_Q;
2079 sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; 2058 sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
2080 sfp->parentdp = sdp; 2059 sfp->parentdp = sdp;
2081 write_lock_irqsave(&sg_index_lock, iflags); 2060 spin_lock_irqsave(&sdp->sfd_lock, iflags);
2061 if (sdp->detached) {
2062 spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
2063 return ERR_PTR(-ENODEV);
2064 }
2082 list_add_tail(&sfp->sfd_siblings, &sdp->sfds); 2065 list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
2083 write_unlock_irqrestore(&sg_index_lock, iflags); 2066 spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
2084 SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); 2067 SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
2085 if (unlikely(sg_big_buff != def_reserved_size)) 2068 if (unlikely(sg_big_buff != def_reserved_size))
2086 sg_big_buff = def_reserved_size; 2069 sg_big_buff = def_reserved_size;
@@ -2130,10 +2113,9 @@ static void sg_remove_sfp(struct kref *kref)
2130 struct sg_device *sdp = sfp->parentdp; 2113 struct sg_device *sdp = sfp->parentdp;
2131 unsigned long iflags; 2114 unsigned long iflags;
2132 2115
2133 write_lock_irqsave(&sg_index_lock, iflags); 2116 spin_lock_irqsave(&sdp->sfd_lock, iflags);
2134 list_del(&sfp->sfd_siblings); 2117 list_del(&sfp->sfd_siblings);
2135 write_unlock_irqrestore(&sg_index_lock, iflags); 2118 spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
2136 wake_up_interruptible(&sdp->o_excl_wait);
2137 2119
2138 INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext); 2120 INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
2139 schedule_work(&sfp->ew.work); 2121 schedule_work(&sfp->ew.work);
@@ -2520,7 +2502,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
2520 return 0; 2502 return 0;
2521} 2503}
2522 2504
2523/* must be called while holding sg_index_lock */ 2505/* must be called while holding sg_index_lock and sfd_lock */
2524static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) 2506static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
2525{ 2507{
2526 int k, m, new_interface, blen, usg; 2508 int k, m, new_interface, blen, usg;
@@ -2605,22 +2587,26 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
2605 2587
2606 read_lock_irqsave(&sg_index_lock, iflags); 2588 read_lock_irqsave(&sg_index_lock, iflags);
2607 sdp = it ? sg_lookup_dev(it->index) : NULL; 2589 sdp = it ? sg_lookup_dev(it->index) : NULL;
2608 if (sdp && !list_empty(&sdp->sfds)) { 2590 if (sdp) {
2609 struct scsi_device *scsidp = sdp->device; 2591 spin_lock(&sdp->sfd_lock);
2592 if (!list_empty(&sdp->sfds)) {
2593 struct scsi_device *scsidp = sdp->device;
2610 2594
2611 seq_printf(s, " >>> device=%s ", sdp->disk->disk_name); 2595 seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
2612 if (sdp->detached) 2596 if (sdp->detached)
2613 seq_printf(s, "detached pending close "); 2597 seq_printf(s, "detached pending close ");
2614 else 2598 else
2615 seq_printf 2599 seq_printf
2616 (s, "scsi%d chan=%d id=%d lun=%d em=%d", 2600 (s, "scsi%d chan=%d id=%d lun=%d em=%d",
2617 scsidp->host->host_no, 2601 scsidp->host->host_no,
2618 scsidp->channel, scsidp->id, 2602 scsidp->channel, scsidp->id,
2619 scsidp->lun, 2603 scsidp->lun,
2620 scsidp->host->hostt->emulated); 2604 scsidp->host->hostt->emulated);
2621 seq_printf(s, " sg_tablesize=%d excl=%d\n", 2605 seq_printf(s, " sg_tablesize=%d excl=%d\n",
2622 sdp->sg_tablesize, get_exclude(sdp)); 2606 sdp->sg_tablesize, sdp->exclude);
2623 sg_proc_debug_helper(s, sdp); 2607 sg_proc_debug_helper(s, sdp);
2608 }
2609 spin_unlock(&sdp->sfd_lock);
2624 } 2610 }
2625 read_unlock_irqrestore(&sg_index_lock, iflags); 2611 read_unlock_irqrestore(&sg_index_lock, iflags);
2626 return 0; 2612 return 0;