On 10/16/24 12:52 PM, David Wei wrote: > +static int io_zcrx_create_area(struct io_ring_ctx *ctx, > + struct io_zcrx_ifq *ifq, > + struct io_zcrx_area **res, > + struct io_uring_zcrx_area_reg *area_reg) > +{ > + struct io_zcrx_area *area; > + int i, ret, nr_pages; > + struct iovec iov; > + > + if (area_reg->flags || area_reg->rq_area_token) > + return -EINVAL; > + if (area_reg->__resv1 || area_reg->__resv2[0] || area_reg->__resv2[1]) > + return -EINVAL; > + if (area_reg->addr & ~PAGE_MASK || area_reg->len & ~PAGE_MASK) > + return -EINVAL; > + > + iov.iov_base = u64_to_user_ptr(area_reg->addr); > + iov.iov_len = area_reg->len; > + ret = io_buffer_validate(&iov); > + if (ret) > + return ret; > + > + ret = -ENOMEM; > + area = kzalloc(sizeof(*area), GFP_KERNEL); > + if (!area) > + goto err; > + > + area->pages = io_pin_pages((unsigned long)area_reg->addr, area_reg->len, > + &nr_pages); > + if (IS_ERR(area->pages)) { > + ret = PTR_ERR(area->pages); > + area->pages = NULL; > + goto err; > + } > + area->nia.num_niovs = nr_pages; > + > + area->nia.niovs = kvmalloc_array(nr_pages, sizeof(area->nia.niovs[0]), > + GFP_KERNEL | __GFP_ZERO); > + if (!area->nia.niovs) > + goto err; > + > + area->freelist = kvmalloc_array(nr_pages, sizeof(area->freelist[0]), > + GFP_KERNEL | __GFP_ZERO); > + if (!area->freelist) > + goto err; > + > + for (i = 0; i < nr_pages; i++) { > + area->freelist[i] = i; > + } > + > + area->free_count = nr_pages; > + area->ifq = ifq; > + /* we're only supporting one area per ifq for now */ > + area->area_id = 0; > + area_reg->rq_area_token = (u64)area->area_id << IORING_ZCRX_AREA_SHIFT; > + spin_lock_init(&area->freelist_lock); > + *res = area; > + return 0; > +err: > + if (area) > + io_zcrx_free_area(area); > + return ret; > +} Minor nit, but I think this would be nicer returning area and just using ERR_PTR() for the errors. Outside of that: Reviewed-by: Jens Axboe <axboe@xxxxxxxxx> -- Jens Axboe