mirror of
https://github.com/torvalds/linux.git
synced 2024-12-24 20:01:55 +00:00
IB/ipath: Don't allow QPs 0 and 1 to be opened multiple times
Signed-off-by: Robert Walsh <robert.walsh@qlogic.com> Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
53c1d2c943
commit
662af5813b
@ -81,11 +81,51 @@ static u32 credit_table[31] = {
|
|||||||
32768 /* 1E */
|
32768 /* 1E */
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 alloc_qpn(struct ipath_qp_table *qpt)
|
|
||||||
|
static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map)
|
||||||
|
{
|
||||||
|
unsigned long page = get_zeroed_page(GFP_KERNEL);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the page if someone raced with us installing it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
spin_lock_irqsave(&qpt->lock, flags);
|
||||||
|
if (map->page)
|
||||||
|
free_page(page);
|
||||||
|
else
|
||||||
|
map->page = (void *)page;
|
||||||
|
spin_unlock_irqrestore(&qpt->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type)
|
||||||
{
|
{
|
||||||
u32 i, offset, max_scan, qpn;
|
u32 i, offset, max_scan, qpn;
|
||||||
struct qpn_map *map;
|
struct qpn_map *map;
|
||||||
u32 ret;
|
u32 ret = -1;
|
||||||
|
|
||||||
|
if (type == IB_QPT_SMI)
|
||||||
|
ret = 0;
|
||||||
|
else if (type == IB_QPT_GSI)
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
if (ret != -1) {
|
||||||
|
map = &qpt->map[0];
|
||||||
|
if (unlikely(!map->page)) {
|
||||||
|
get_map_page(qpt, map);
|
||||||
|
if (unlikely(!map->page)) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!test_and_set_bit(ret, map->page))
|
||||||
|
atomic_dec(&map->n_free);
|
||||||
|
else
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
qpn = qpt->last + 1;
|
qpn = qpt->last + 1;
|
||||||
if (qpn >= QPN_MAX)
|
if (qpn >= QPN_MAX)
|
||||||
@ -95,19 +135,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt)
|
|||||||
max_scan = qpt->nmaps - !offset;
|
max_scan = qpt->nmaps - !offset;
|
||||||
for (i = 0;;) {
|
for (i = 0;;) {
|
||||||
if (unlikely(!map->page)) {
|
if (unlikely(!map->page)) {
|
||||||
unsigned long page = get_zeroed_page(GFP_KERNEL);
|
get_map_page(qpt, map);
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free the page if someone raced with us
|
|
||||||
* installing it:
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave(&qpt->lock, flags);
|
|
||||||
if (map->page)
|
|
||||||
free_page(page);
|
|
||||||
else
|
|
||||||
map->page = (void *)page;
|
|
||||||
spin_unlock_irqrestore(&qpt->lock, flags);
|
|
||||||
if (unlikely(!map->page))
|
if (unlikely(!map->page))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -151,7 +179,7 @@ static u32 alloc_qpn(struct ipath_qp_table *qpt)
|
|||||||
qpn = mk_qpn(qpt, map, offset);
|
qpn = mk_qpn(qpt, map, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = -ENOMEM;
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
return ret;
|
return ret;
|
||||||
@ -180,29 +208,19 @@ static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp,
|
|||||||
enum ib_qp_type type)
|
enum ib_qp_type type)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 qpn;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (type == IB_QPT_SMI)
|
ret = alloc_qpn(qpt, type);
|
||||||
qpn = 0;
|
if (ret < 0)
|
||||||
else if (type == IB_QPT_GSI)
|
goto bail;
|
||||||
qpn = 1;
|
qp->ibqp.qp_num = ret;
|
||||||
else {
|
|
||||||
/* Allocate the next available QPN */
|
|
||||||
qpn = alloc_qpn(qpt);
|
|
||||||
if (qpn == 0) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qp->ibqp.qp_num = qpn;
|
|
||||||
|
|
||||||
/* Add the QP to the hash table. */
|
/* Add the QP to the hash table. */
|
||||||
spin_lock_irqsave(&qpt->lock, flags);
|
spin_lock_irqsave(&qpt->lock, flags);
|
||||||
|
|
||||||
qpn %= qpt->max;
|
ret %= qpt->max;
|
||||||
qp->next = qpt->table[qpn];
|
qp->next = qpt->table[ret];
|
||||||
qpt->table[qpn] = qp;
|
qpt->table[ret] = qp;
|
||||||
atomic_inc(&qp->refcount);
|
atomic_inc(&qp->refcount);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&qpt->lock, flags);
|
spin_unlock_irqrestore(&qpt->lock, flags);
|
||||||
@ -245,9 +263,7 @@ static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp)
|
|||||||
if (!fnd)
|
if (!fnd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If QPN is not reserved, mark QPN free in the bitmap. */
|
free_qpn(qpt, qp->ibqp.qp_num);
|
||||||
if (qp->ibqp.qp_num > 1)
|
|
||||||
free_qpn(qpt, qp->ibqp.qp_num);
|
|
||||||
|
|
||||||
wait_event(qp->wait, !atomic_read(&qp->refcount));
|
wait_event(qp->wait, !atomic_read(&qp->refcount));
|
||||||
}
|
}
|
||||||
@ -270,8 +286,7 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt)
|
|||||||
|
|
||||||
while (qp) {
|
while (qp) {
|
||||||
nqp = qp->next;
|
nqp = qp->next;
|
||||||
if (qp->ibqp.qp_num > 1)
|
free_qpn(qpt, qp->ibqp.qp_num);
|
||||||
free_qpn(qpt, qp->ibqp.qp_num);
|
|
||||||
if (!atomic_dec_and_test(&qp->refcount) ||
|
if (!atomic_dec_and_test(&qp->refcount) ||
|
||||||
!ipath_destroy_qp(&qp->ibqp))
|
!ipath_destroy_qp(&qp->ibqp))
|
||||||
ipath_dbg("QP memory leak!\n");
|
ipath_dbg("QP memory leak!\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user