diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/scsi/sg.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d4af13269e85..4efa9b5884b7 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
| @@ -105,6 +105,8 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ; | |||
| 105 | static int sg_add(struct device *, struct class_interface *); | 105 | static int sg_add(struct device *, struct class_interface *); |
| 106 | static void sg_remove(struct device *, struct class_interface *); | 106 | static void sg_remove(struct device *, struct class_interface *); |
| 107 | 107 | ||
| 108 | static DEFINE_SPINLOCK(sg_open_exclusive_lock); | ||
| 109 | |||
| 108 | static DEFINE_IDR(sg_index_idr); | 110 | static DEFINE_IDR(sg_index_idr); |
| 109 | static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock | 111 | static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock |
| 110 | file descriptor list for device */ | 112 | file descriptor list for device */ |
| @@ -174,6 +176,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ | |||
| 174 | struct list_head sfds; | 176 | struct list_head sfds; |
| 175 | struct rw_semaphore o_sem; /* exclude open should hold this rwsem */ | 177 | struct rw_semaphore o_sem; /* exclude open should hold this rwsem */ |
| 176 | volatile char detached; /* 0->attached, 1->detached pending removal */ | 178 | volatile char detached; /* 0->attached, 1->detached pending removal */ |
| 179 | /* exclude protected by sg_open_exclusive_lock */ | ||
| 177 | char exclude; /* opened for exclusive access */ | 180 | char exclude; /* opened for exclusive access */ |
| 178 | char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ | 181 | char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ |
| 179 | struct gendisk *disk; | 182 | struct gendisk *disk; |
| @@ -222,6 +225,27 @@ static int sg_allow_access(struct file *filp, unsigned char *cmd) | |||
| 222 | return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE); | 225 | return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE); |
| 223 | } | 226 | } |
| 224 | 227 | ||
| 228 | static 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 | |||
| 239 | static 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 | |||
| 225 | static int sfds_list_empty(Sg_device *sdp) | 249 | static int sfds_list_empty(Sg_device *sdp) |
| 226 | { | 250 | { |
| 227 | unsigned long flags; | 251 | unsigned long flags; |
| @@ -293,7 +317,7 @@ sg_open(struct inode *inode, struct file *filp) | |||
| 293 | } | 317 | } |
| 294 | /* Since write lock is held, no need to check sfd_list */ | 318 | /* Since write lock is held, no need to check sfd_list */ |
| 295 | if (flags & O_EXCL) | 319 | if (flags & O_EXCL) |
| 296 | sdp->exclude = 1; /* used by release lock */ | 320 | set_exclude(sdp, 1); |
| 297 | 321 | ||
| 298 | if (sdp->detached) { | 322 | if (sdp->detached) { |
| 299 | retval = -ENODEV; | 323 | retval = -ENODEV; |
| @@ -313,7 +337,7 @@ sg_open(struct inode *inode, struct file *filp) | |||
| 313 | retval = -ENOMEM; | 337 | retval = -ENOMEM; |
| 314 | sem_out: | 338 | sem_out: |
| 315 | if (flags & O_EXCL) { | 339 | if (flags & O_EXCL) { |
| 316 | sdp->exclude = 0; /* undo if error */ | 340 | set_exclude(sdp, 0); /* undo if error */ |
| 317 | up_write(&sdp->o_sem); | 341 | up_write(&sdp->o_sem); |
| 318 | } else | 342 | } else |
| 319 | up_read(&sdp->o_sem); | 343 | up_read(&sdp->o_sem); |
| @@ -340,8 +364,8 @@ sg_release(struct inode *inode, struct file *filp) | |||
| 340 | return -ENXIO; | 364 | return -ENXIO; |
| 341 | SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); | 365 | SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); |
| 342 | 366 | ||
| 343 | excl = sdp->exclude; | 367 | excl = get_exclude(sdp); |
| 344 | sdp->exclude = 0; | 368 | set_exclude(sdp, 0); |
| 345 | if (excl) | 369 | if (excl) |
| 346 | up_write(&sdp->o_sem); | 370 | up_write(&sdp->o_sem); |
| 347 | else | 371 | else |
| @@ -2598,7 +2622,7 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) | |||
| 2598 | scsidp->lun, | 2622 | scsidp->lun, |
| 2599 | scsidp->host->hostt->emulated); | 2623 | scsidp->host->hostt->emulated); |
| 2600 | seq_printf(s, " sg_tablesize=%d excl=%d\n", | 2624 | seq_printf(s, " sg_tablesize=%d excl=%d\n", |
| 2601 | sdp->sg_tablesize, sdp->exclude); | 2625 | sdp->sg_tablesize, get_exclude(sdp)); |
| 2602 | sg_proc_debug_helper(s, sdp); | 2626 | sg_proc_debug_helper(s, sdp); |
| 2603 | } | 2627 | } |
| 2604 | read_unlock_irqrestore(&sg_index_lock, iflags); | 2628 | read_unlock_irqrestore(&sg_index_lock, iflags); |
