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

[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
...@@ -120,20 +120,26 @@ static void clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int tag, ...@@ -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, 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) 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); spin_lock(&ddp->map_lock);
for (i = start; i <= max;) { for (i = start; i < max;) {
for (j = 0; j < count; j++) { for (j = 0, k = i; j < count; j++, k++) {
if (ddp->gl_map[i + j]) if (ddp->gl_map[k])
break; break;
} }
if (j == count) { if (j == count) {
for (j = 0; j < count; j++) for (j = 0, k = i; j < count; j++, k++)
ddp->gl_map[i + j] = gl; ddp->gl_map[k] = gl;
spin_unlock(&ddp->map_lock); spin_unlock(&ddp->map_lock);
return i; return i;
} }
...@@ -354,7 +360,7 @@ int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid, ...@@ -354,7 +360,7 @@ int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid,
struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi; struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;
struct pagepod_hdr hdr; struct pagepod_hdr hdr;
unsigned int npods; unsigned int npods;
int idx = -1, idx_max; int idx = -1;
int err = -ENOMEM; int err = -ENOMEM;
u32 sw_tag = *tagp; u32 sw_tag = *tagp;
u32 tag; u32 tag;
...@@ -367,18 +373,18 @@ int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid, ...@@ -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; npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;
idx_max = ddp->nppods - npods + 1;
if (ddp->idx_last == ddp->nppods) 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 { else {
idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1,
idx_max, npods, gl); ddp->nppods, npods, gl);
if (idx < 0 && ddp->idx_last >= npods) if (idx < 0 && ddp->idx_last >= npods) {
idx = ddp_find_unused_entries(ddp, 0, idx = ddp_find_unused_entries(ddp, 0,
ddp->idx_last - npods + 1, min(ddp->idx_last + npods, ddp->nppods),
npods, gl); npods, gl);
} }
}
if (idx < 0) { if (idx < 0) {
ddp_log_debug("xferlen %u, gl %u, npods %u NO DDP.\n", ddp_log_debug("xferlen %u, gl %u, npods %u NO DDP.\n",
gl->length, gl->nelem, npods); gl->length, gl->nelem, npods);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment