int skb_kvec_recv_datagram(struct sock * sk, kvec_cb_t cb, int len, void (*finish)(struct sock *sk, kvec_cb_t cb, int len, struct sk_buff *skb)) { struct skb_async_info *info = kmalloc(sizeof(struct skb_async_info), GFP_KERNEL); if (info) { wtd_set_action(&info->wtd, skb_async_read_worker, info); info->sk = sk; info->len = len; info->finish = finish; info->cb = cb; skb_async_read_worker(info); return 0; } return -EAGAIN; }
int async_poll(struct kiocb *iocb, int events) { unsigned int mask; async_poll_table *pasync; poll_table *p; /* Fast path */ if (iocb->filp->f_op && iocb->filp->f_op->poll) { mask = iocb->filp->f_op->poll(iocb->filp, NULL); mask &= events | POLLERR | POLLHUP; if (mask & events) return mask; } pasync = kmem_cache_alloc(async_poll_table_cache, SLAB_KERNEL); if (!pasync) return -ENOMEM; p = (poll_table *)pasync; poll_initwait(p); wtd_set_action(&pasync->wtd, async_poll_complete, pasync); p->iocb = iocb; pasync->wake = 0; pasync->sync = 0; pasync->events = events; pasync->pt_page.entry = pasync->pt_page.entries; pasync->pt_page.size = sizeof(pasync->pt_page); p->table = &pasync->pt_page; iocb->data = p; iocb->users ++; wmb(); mask = DEFAULT_POLLMASK; if (iocb->filp->f_op && iocb->filp->f_op->poll) mask = iocb->filp->f_op->poll(iocb->filp, p); mask &= events | POLLERR | POLLHUP; if (mask && xchg(&iocb->data, NULL)) { poll_freewait(p); aio_complete(iocb, mask, 0); } iocb->cancel = async_poll_cancel; aio_put_req(iocb); return 0; }