aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hpsa.c
diff options
context:
space:
mode:
authorStephen M. Cameron <scameron@beardog.cce.hp.com>2013-09-23 14:34:12 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-12-19 10:38:56 -0500
commit0390f0c0dfb540149d7369276b17ec53caf506cb (patch)
tree2a621fff7b52ca27a9e1a66c168b940d599222f2 /drivers/scsi/hpsa.c
parente06c8e5c34498d1ea0468401012be8d1c853c585 (diff)
[SCSI] hpsa: cap CCISS_PASSTHRU at 20 concurrent commands.
Cap CCISS_BIG_PASSTHRU as well. If an attempt is made to exceed this, ioctl() will return -1 with errno == EAGAIN. This is to prevent a userland program from exhausting all of pci_alloc_consistent memory. I've only seen this problem when running a special test program designed to provoke it. 20 concurrent commands via the passthru ioctls (not counting SG_IO) should be more than enough. Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r--drivers/scsi/hpsa.c44
1 files changed, 42 insertions, 2 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6cc91f83aa69..9acfce3bbe78 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -3222,6 +3222,36 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
3222 c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) 3222 c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
3223 (void) check_for_unit_attention(h, c); 3223 (void) check_for_unit_attention(h, c);
3224} 3224}
3225
3226static int increment_passthru_count(struct ctlr_info *h)
3227{
3228 unsigned long flags;
3229
3230 spin_lock_irqsave(&h->passthru_count_lock, flags);
3231 if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) {
3232 spin_unlock_irqrestore(&h->passthru_count_lock, flags);
3233 return -1;
3234 }
3235 h->passthru_count++;
3236 spin_unlock_irqrestore(&h->passthru_count_lock, flags);
3237 return 0;
3238}
3239
3240static void decrement_passthru_count(struct ctlr_info *h)
3241{
3242 unsigned long flags;
3243
3244 spin_lock_irqsave(&h->passthru_count_lock, flags);
3245 if (h->passthru_count <= 0) {
3246 spin_unlock_irqrestore(&h->passthru_count_lock, flags);
3247 /* not expecting to get here. */
3248 dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n");
3249 return;
3250 }
3251 h->passthru_count--;
3252 spin_unlock_irqrestore(&h->passthru_count_lock, flags);
3253}
3254
3225/* 3255/*
3226 * ioctl 3256 * ioctl
3227 */ 3257 */
@@ -3229,6 +3259,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
3229{ 3259{
3230 struct ctlr_info *h; 3260 struct ctlr_info *h;
3231 void __user *argp = (void __user *)arg; 3261 void __user *argp = (void __user *)arg;
3262 int rc;
3232 3263
3233 h = sdev_to_hba(dev); 3264 h = sdev_to_hba(dev);
3234 3265
@@ -3243,9 +3274,17 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
3243 case CCISS_GETDRIVVER: 3274 case CCISS_GETDRIVVER:
3244 return hpsa_getdrivver_ioctl(h, argp); 3275 return hpsa_getdrivver_ioctl(h, argp);
3245 case CCISS_PASSTHRU: 3276 case CCISS_PASSTHRU:
3246 return hpsa_passthru_ioctl(h, argp); 3277 if (increment_passthru_count(h))
3278 return -EAGAIN;
3279 rc = hpsa_passthru_ioctl(h, argp);
3280 decrement_passthru_count(h);
3281 return rc;
3247 case CCISS_BIG_PASSTHRU: 3282 case CCISS_BIG_PASSTHRU:
3248 return hpsa_big_passthru_ioctl(h, argp); 3283 if (increment_passthru_count(h))
3284 return -EAGAIN;
3285 rc = hpsa_big_passthru_ioctl(h, argp);
3286 decrement_passthru_count(h);
3287 return rc;
3249 default: 3288 default:
3250 return -ENOTTY; 3289 return -ENOTTY;
3251 } 3290 }
@@ -4835,6 +4874,7 @@ reinit_after_soft_reset:
4835 INIT_LIST_HEAD(&h->reqQ); 4874 INIT_LIST_HEAD(&h->reqQ);
4836 spin_lock_init(&h->lock); 4875 spin_lock_init(&h->lock);
4837 spin_lock_init(&h->scan_lock); 4876 spin_lock_init(&h->scan_lock);
4877 spin_lock_init(&h->passthru_count_lock);
4838 rc = hpsa_pci_init(h); 4878 rc = hpsa_pci_init(h);
4839 if (rc != 0) 4879 if (rc != 0)
4840 goto clean1; 4880 goto clean1;