static int alloc_sg(struct sock *sk, int len, struct scatterlist *sg, int *sg_num_elem, unsigned int *sg_size, int first_coalesce) { struct page_frag *pfrag; unsigned int size = *sg_size; int num_elem = *sg_num_elem, use = 0, rc = 0; struct scatterlist *sge; unsigned int orig_offset; len -= size; pfrag = sk_page_frag(sk); while (len > 0) { if (!sk_page_frag_refill(sk, pfrag)) { rc = -ENOMEM; goto out; } use = min_t(int, len, pfrag->size - pfrag->offset); if (!sk_wmem_schedule(sk, use)) { rc = -ENOMEM; goto out; } sk_mem_charge(sk, use); size += use; orig_offset = pfrag->offset; pfrag->offset += use; sge = sg + num_elem - 1; if (num_elem > first_coalesce && sg_page(sg) == pfrag->page && sg->offset + sg->length == orig_offset) { sg->length += use; } else { sge++; sg_unmark_end(sge); sg_set_page(sge, pfrag->page, use, orig_offset); get_page(pfrag->page); ++num_elem; if (num_elem == MAX_SKB_FRAGS) { rc = -ENOSPC; break; } } len -= use; } goto out; out: *sg_size = size; *sg_num_elem = num_elem; return rc; }
bool rtl_sk_wmem_schedule(struct sock *sk, int size) { return sk_wmem_schedule(sk, size); }