diff options
author | Stephen M. Cameron <scameron@beardog.cce.hp.com> | 2013-09-23 14:34:12 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-12-19 10:38:56 -0500 |
commit | 0390f0c0dfb540149d7369276b17ec53caf506cb (patch) | |
tree | 2a621fff7b52ca27a9e1a66c168b940d599222f2 | |
parent | e06c8e5c34498d1ea0468401012be8d1c853c585 (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>
-rw-r--r-- | drivers/scsi/hpsa.c | 44 | ||||
-rw-r--r-- | drivers/scsi/hpsa.h | 5 |
2 files changed, 47 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 | |||
3226 | static 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 | |||
3240 | static 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; |
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index bc85e7244f40..6eabf08ca672 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h | |||
@@ -114,6 +114,11 @@ struct ctlr_info { | |||
114 | struct TransTable_struct *transtable; | 114 | struct TransTable_struct *transtable; |
115 | unsigned long transMethod; | 115 | unsigned long transMethod; |
116 | 116 | ||
117 | /* cap concurrent passthrus at some reasonable maximum */ | ||
118 | #define HPSA_MAX_CONCURRENT_PASSTHRUS (20) | ||
119 | spinlock_t passthru_count_lock; /* protects passthru_count */ | ||
120 | int passthru_count; | ||
121 | |||
117 | /* | 122 | /* |
118 | * Performant mode completion buffers | 123 | * Performant mode completion buffers |
119 | */ | 124 | */ |