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

Commit a53922dd authored by kxie@chelsio.com's avatar kxie@chelsio.com Committed by James Bottomley
Browse files

[SCSI] cxgb3i: fix ddp map overrun



(version 2)

Fixed a bug in calculating ddp map range when search for free entries:
it was going beyond the end by one, thus corrupting gl_skb[0].

Signed-off-by: default avatarKaren Xie <kxie@chelsio.com>
Signed-off-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 1393109f
Loading
Loading
Loading
Loading
+19 −13
Original line number Diff line number Diff line
@@ -120,20 +120,26 @@ static void clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int tag,
}

static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp,
					  int start, int max, int count,
					  unsigned int start, unsigned int max,
					  unsigned int count,
					  struct cxgb3i_gather_list *gl)
{
	unsigned int i, j;
	unsigned int i, j, k;

	/* not enough entries */
	if ((max - start) < count)
		return -EBUSY;

	max -= count;
	spin_lock(&ddp->map_lock);
	for (i = start; i <= max;) {
		for (j = 0; j < count; j++) {
			if (ddp->gl_map[i + j])
	for (i = start; i < max;) {
		for (j = 0, k = i; j < count; j++, k++) {
			if (ddp->gl_map[k])
				break;
		}
		if (j == count) {
			for (j = 0; j < count; j++)
				ddp->gl_map[i + j] = gl;
			for (j = 0, k = i; j < count; j++, k++)
				ddp->gl_map[k] = gl;
			spin_unlock(&ddp->map_lock);
			return i;
		}
@@ -354,7 +360,7 @@ int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid,
	struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;
	struct pagepod_hdr hdr;
	unsigned int npods;
	int idx = -1, idx_max;
	int idx = -1;
	int err = -ENOMEM;
	u32 sw_tag = *tagp;
	u32 tag;
@@ -367,18 +373,18 @@ int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid,
	}

	npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;
	idx_max = ddp->nppods - npods + 1;

	if (ddp->idx_last == ddp->nppods)
		idx = ddp_find_unused_entries(ddp, 0, idx_max, npods, gl);
		idx = ddp_find_unused_entries(ddp, 0, ddp->nppods, npods, gl);
	else {
		idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1,
					      idx_max, npods, gl);
		if (idx < 0 && ddp->idx_last >= npods)
					      ddp->nppods, npods, gl);
		if (idx < 0 && ddp->idx_last >= npods) {
			idx = ddp_find_unused_entries(ddp, 0,
						      ddp->idx_last - npods + 1,
				min(ddp->idx_last + npods, ddp->nppods),
						      npods, gl);
		}
	}
	if (idx < 0) {
		ddp_log_debug("xferlen %u, gl %u, npods %u NO DDP.\n",
			      gl->length, gl->nelem, npods);