diff options
Diffstat (limited to 'drivers/rapidio')
-rw-r--r-- | drivers/rapidio/devices/rio_mport_cdev.c | 3 | ||||
-rw-r--r-- | drivers/rapidio/rio_cm.c | 34 |
2 files changed, 23 insertions, 14 deletions
diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c index 436dfe871d32..9013a585507e 100644 --- a/drivers/rapidio/devices/rio_mport_cdev.c +++ b/drivers/rapidio/devices/rio_mport_cdev.c @@ -892,7 +892,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode, down_read(¤t->mm->mmap_sem); pinned = get_user_pages( (unsigned long)xfer->loc_addr & PAGE_MASK, - nr_pages, dir == DMA_FROM_DEVICE, 0, + nr_pages, + dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0, page_list, NULL); up_read(¤t->mm->mmap_sem); diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c index 3fa17ac8df54..bad0e0ea4f30 100644 --- a/drivers/rapidio/rio_cm.c +++ b/drivers/rapidio/rio_cm.c @@ -1841,24 +1841,19 @@ static int cm_chan_msg_send(void __user *arg) { struct rio_cm_msg msg; void *buf; - int ret = 0; + int ret; if (copy_from_user(&msg, arg, sizeof(msg))) return -EFAULT; if (msg.size > RIO_MAX_MSG_SIZE) return -EINVAL; - buf = kmalloc(msg.size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, (void __user *)(uintptr_t)msg.msg, msg.size)) { - ret = -EFAULT; - goto out; - } + buf = memdup_user((void __user *)(uintptr_t)msg.msg, msg.size); + if (IS_ERR(buf)) + return PTR_ERR(buf); ret = riocm_ch_send(msg.ch_num, buf, msg.size); -out: + kfree(buf); return ret; } @@ -2247,17 +2242,30 @@ static int rio_cm_shutdown(struct notifier_block *nb, unsigned long code, { struct rio_channel *ch; unsigned int i; + LIST_HEAD(list); riocm_debug(EXIT, "."); + /* + * If there are any channels left in connected state send + * close notification to the connection partner. + * First build a list of channels that require a closing + * notification because function riocm_send_close() should + * be called outside of spinlock protected code. + */ spin_lock_bh(&idr_lock); idr_for_each_entry(&ch_idr, ch, i) { - riocm_debug(EXIT, "close ch %d", ch->id); - if (ch->state == RIO_CM_CONNECTED) - riocm_send_close(ch); + if (ch->state == RIO_CM_CONNECTED) { + riocm_debug(EXIT, "close ch %d", ch->id); + idr_remove(&ch_idr, ch->id); + list_add(&ch->ch_node, &list); + } } spin_unlock_bh(&idr_lock); + list_for_each_entry(ch, &list, ch_node) + riocm_send_close(ch); + return NOTIFY_DONE; } |