Commit 08a45173 authored by Jens Axboe's avatar Jens Axboe
Browse files

io_uring: allow sparse fixed file sets



This is in preparation for allowing updates to fixed file sets without
requiring a full unregister+register.

Reviewed-by: default avatarJeff Moyer <jmoyer@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent ba816ad6
Loading
Loading
Loading
Loading
+34 −15
Original line number Diff line number Diff line
@@ -2379,6 +2379,8 @@ static int io_req_set_file(struct io_ring_ctx *ctx, const struct sqe_submit *s,
		if (unlikely(!ctx->user_files ||
		    (unsigned) fd >= ctx->nr_user_files))
			return -EBADF;
		if (!ctx->user_files[fd])
			return -EBADF;
		req->file = ctx->user_files[fd];
		req->flags |= REQ_F_FIXED_FILE;
	} else {
@@ -2999,6 +3001,7 @@ static void __io_sqe_files_unregister(struct io_ring_ctx *ctx)
	int i;

	for (i = 0; i < ctx->nr_user_files; i++)
		if (ctx->user_files[i])
			fput(ctx->user_files[i]);
#endif
}
@@ -3067,7 +3070,7 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx, int nr, int offset)
	struct sock *sk = ctx->ring_sock->sk;
	struct scm_fp_list *fpl;
	struct sk_buff *skb;
	int i;
	int i, nr_files;

	if (!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
		unsigned long inflight = ctx->user->unix_inflight + nr;
@@ -3087,21 +3090,31 @@ static int __io_sqe_files_scm(struct io_ring_ctx *ctx, int nr, int offset)
	}

	skb->sk = sk;
	skb->destructor = io_destruct_skb;

	nr_files = 0;
	fpl->user = get_uid(ctx->user);
	for (i = 0; i < nr; i++) {
		fpl->fp[i] = get_file(ctx->user_files[i + offset]);
		unix_inflight(fpl->user, fpl->fp[i]);
		if (!ctx->user_files[i + offset])
			continue;
		fpl->fp[nr_files] = get_file(ctx->user_files[i + offset]);
		unix_inflight(fpl->user, fpl->fp[nr_files]);
		nr_files++;
	}

	fpl->max = fpl->count = nr;
	if (nr_files) {
		fpl->max = SCM_MAX_FD;
		fpl->count = nr_files;
		UNIXCB(skb).fp = fpl;
		skb->destructor = io_destruct_skb;
		refcount_add(skb->truesize, &sk->sk_wmem_alloc);
		skb_queue_head(&sk->sk_receive_queue, skb);

	for (i = 0; i < nr; i++)
		for (i = 0; i < nr_files; i++)
			fput(fpl->fp[i]);
	} else {
		kfree_skb(skb);
		kfree(fpl);
	}

	return 0;
}
@@ -3132,6 +3145,7 @@ static int io_sqe_files_scm(struct io_ring_ctx *ctx)
		return 0;

	while (total < ctx->nr_user_files) {
		if (ctx->user_files[total])
			fput(ctx->user_files[total]);
		total++;
	}
@@ -3163,10 +3177,15 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
	if (!ctx->user_files)
		return -ENOMEM;

	for (i = 0; i < nr_args; i++) {
	for (i = 0; i < nr_args; i++, ctx->nr_user_files++) {
		ret = -EFAULT;
		if (copy_from_user(&fd, &fds[i], sizeof(fd)))
			break;
		/* allow sparse sets */
		if (fd == -1) {
			ret = 0;
			continue;
		}

		ctx->user_files[i] = fget(fd);

@@ -3184,12 +3203,12 @@ static int io_sqe_files_register(struct io_ring_ctx *ctx, void __user *arg,
			fput(ctx->user_files[i]);
			break;
		}
		ctx->nr_user_files++;
		ret = 0;
	}

	if (ret) {
		for (i = 0; i < ctx->nr_user_files; i++)
			if (ctx->user_files[i])
				fput(ctx->user_files[i]);

		kfree(ctx->user_files);