/* fetch the pages addr resides in into pg and initialise sg with them */ int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, unsigned int pgcount, struct page **pg, struct scatterlist *sg, struct task_struct *task, struct mm_struct *mm) { int ret, pglen, i = 0; struct scatterlist *sgp; if (unlikely(!pgcount || !len || !addr)) { sg_mark_end(sg); return 0; } down_read(&mm->mmap_sem); ret = get_user_pages(task, mm, (unsigned long)addr, pgcount, write, 0, pg, NULL); up_read(&mm->mmap_sem); if (ret != pgcount) return -EINVAL; sg_init_table(sg, pgcount); pglen = min((ptrdiff_t)(PAGE_SIZE - PAGEOFFSET(addr)), (ptrdiff_t)len); sg_set_page(sg, pg[i++], pglen, PAGEOFFSET(addr)); len -= pglen; for (sgp = sg_next(sg); len; sgp = sg_next(sgp)) { pglen = min((uint32_t)PAGE_SIZE, len); sg_set_page(sgp, pg[i++], pglen, 0); len -= pglen; } sg_mark_end(sg_last(sg, pgcount)); return 0; }
/*---------------------------------------------------------------------------*/ static struct scatterlist *xio_sg_last(struct sg_table *tbl) { #ifdef XIO_DEBUG_SG verify_tbl(tbl); #endif return (!tbl || tbl->nents == 0) ? NULL : sg_last(tbl->sgl, tbl->nents); }