in rio_cm.c [1560:1611]
static int cm_ep_get_list(void __user *arg)
{
struct cm_dev *cm;
struct cm_peer *peer;
u32 info[2];
void *buf;
u32 nent;
u32 *entry_ptr;
u32 i = 0;
int ret = 0;
if (copy_from_user(&info, arg, sizeof(info)))
return -EFAULT;
if (info[1] >= RIO_MAX_MPORTS || info[0] > RIOCM_MAX_EP_COUNT)
return -EINVAL;
/* Find a matching cm_dev object */
down_read(&rdev_sem);
list_for_each_entry(cm, &cm_dev_list, list)
if (cm->mport->id == (u8)info[1])
goto found;
up_read(&rdev_sem);
return -ENODEV;
found:
nent = min(info[0], cm->npeers);
buf = kcalloc(nent + 2, sizeof(u32), GFP_KERNEL);
if (!buf) {
up_read(&rdev_sem);
return -ENOMEM;
}
entry_ptr = (u32 *)((uintptr_t)buf + 2*sizeof(u32));
list_for_each_entry(peer, &cm->peers, node) {
*entry_ptr = (u32)peer->rdev->destid;
entry_ptr++;
if (++i == nent)
break;
}
up_read(&rdev_sem);
((u32 *)buf)[0] = i; /* report an updated number of entries */
((u32 *)buf)[1] = info[1]; /* put back an mport ID */
if (copy_to_user(arg, buf, sizeof(u32) * (info[0] + 2)))
ret = -EFAULT;
kfree(buf);
return ret;
}