Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0390f0c0 authored by Stephen M. Cameron's avatar Stephen M. Cameron Committed by James Bottomley
Browse files

[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: default avatarStephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent e06c8e5c
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -3222,6 +3222,36 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
			c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
		(void) check_for_unit_attention(h, c);
}

static int increment_passthru_count(struct ctlr_info *h)
{
	unsigned long flags;

	spin_lock_irqsave(&h->passthru_count_lock, flags);
	if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) {
		spin_unlock_irqrestore(&h->passthru_count_lock, flags);
		return -1;
	}
	h->passthru_count++;
	spin_unlock_irqrestore(&h->passthru_count_lock, flags);
	return 0;
}

static void decrement_passthru_count(struct ctlr_info *h)
{
	unsigned long flags;

	spin_lock_irqsave(&h->passthru_count_lock, flags);
	if (h->passthru_count <= 0) {
		spin_unlock_irqrestore(&h->passthru_count_lock, flags);
		/* not expecting to get here. */
		dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n");
		return;
	}
	h->passthru_count--;
	spin_unlock_irqrestore(&h->passthru_count_lock, flags);
}

/*
 * ioctl
 */
@@ -3229,6 +3259,7 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
{
	struct ctlr_info *h;
	void __user *argp = (void __user *)arg;
	int rc;

	h = sdev_to_hba(dev);

@@ -3243,9 +3274,17 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
	case CCISS_GETDRIVVER:
		return hpsa_getdrivver_ioctl(h, argp);
	case CCISS_PASSTHRU:
		return hpsa_passthru_ioctl(h, argp);
		if (increment_passthru_count(h))
			return -EAGAIN;
		rc = hpsa_passthru_ioctl(h, argp);
		decrement_passthru_count(h);
		return rc;
	case CCISS_BIG_PASSTHRU:
		return hpsa_big_passthru_ioctl(h, argp);
		if (increment_passthru_count(h))
			return -EAGAIN;
		rc = hpsa_big_passthru_ioctl(h, argp);
		decrement_passthru_count(h);
		return rc;
	default:
		return -ENOTTY;
	}
@@ -4835,6 +4874,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
	INIT_LIST_HEAD(&h->reqQ);
	spin_lock_init(&h->lock);
	spin_lock_init(&h->scan_lock);
	spin_lock_init(&h->passthru_count_lock);
	rc = hpsa_pci_init(h);
	if (rc != 0)
		goto clean1;
+5 −0
Original line number Diff line number Diff line
@@ -114,6 +114,11 @@ struct ctlr_info {
	struct TransTable_struct *transtable;
	unsigned long transMethod;

	/* cap concurrent passthrus at some reasonable maximum */
#define HPSA_MAX_CONCURRENT_PASSTHRUS (20)
	spinlock_t passthru_count_lock; /* protects passthru_count */
	int passthru_count;

	/*
	 * Performant mode completion buffers
	 */