static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
			  struct io_submit_state *state, struct io_kiocb **link)
{
	const struct cred *old_creds = NULL;
	struct io_ring_ctx *ctx = req->ctx;
	unsigned int sqe_flags;
	int ret, id;

	sqe_flags = READ_ONCE(sqe->flags);

	/* enforce forwards compatibility on users */
	if (unlikely(sqe_flags & ~SQE_VALID_FLAGS)) {
		ret = -EINVAL;
		goto err_req;
	}

	id = READ_ONCE(sqe->personality);
	if (id) {
		const struct cred *personality_creds;

		personality_creds = idr_find(&ctx->personality_idr, id);
		if (unlikely(!personality_creds)) {
			ret = -EINVAL;
			goto err_req;
		}
		old_creds = override_creds(personality_creds);
	}

	/* same numerical values with corresponding REQ_F_*, safe to copy */
	req->flags |= sqe_flags & (IOSQE_IO_DRAIN|IOSQE_IO_HARDLINK|
					IOSQE_ASYNC);

	ret = io_req_set_file(state, req, sqe);
	if (unlikely(ret)) {
err_req:
		io_cqring_add_event(req, ret);
		io_double_put_req(req);
		if (old_creds)
			revert_creds(old_creds);
		return false;
	}

	/*
	 * If we already have a head request, queue this one for async
	 * submittal once the head completes. If we don't have a head but
	 * IOSQE_IO_LINK is set in the sqe, start a new head. This one will be
	 * submitted sync once the chain is complete. If none of those
	 * conditions are true (normal request), then just queue it.
	 */
	if (*link) {
		struct io_kiocb *head = *link;

		/*
		 * Taking sequential execution of a link, draining both sides
		 * of the link also fullfils IOSQE_IO_DRAIN semantics for all
		 * requests in the link. So, it drains the head and the
		 * next after the link request. The last one is done via
		 * drain_next flag to persist the effect across calls.
		 */
		if (sqe_flags & IOSQE_IO_DRAIN) {
			head->flags |= REQ_F_IO_DRAIN;
			ctx->drain_next = 1;
		}
		if (io_alloc_async_ctx(req)) {
			ret = -EAGAIN;
			goto err_req;
		}

		ret = io_req_defer_prep(req, sqe);
		if (ret) {
			/* fail even hard links since we don't submit */
			head->flags |= REQ_F_FAIL_LINK;
			goto err_req;
		}
		trace_io_uring_link(ctx, req, head);
		list_add_tail(&req->link_list, &head->link_list);

		/* last request of a link, enqueue the link */
		if (!(sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK))) {
			io_queue_link_head(head);
			*link = NULL;
		}
	} else {
		if (unlikely(ctx->drain_next)) {
			req->flags |= REQ_F_IO_DRAIN;
			req->ctx->drain_next = 0;
		}
		if (sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK)) {
			req->flags |= REQ_F_LINK;
			INIT_LIST_HEAD(&req->link_list);
			ret = io_req_defer_prep(req, sqe);
			if (ret)
				req->flags |= REQ_F_FAIL_LINK;
			*link = req;
		} else {
			io_queue_sqe(req, sqe);
		}
	}

	if (old_creds)
		revert_creds(old_creds);
	return true;
}
static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
			  struct io_submit_state *state, struct io_kiocb **link)
{
	const struct cred *old_creds = NULL;
	struct io_ring_ctx *ctx = req->ctx;
	unsigned int sqe_flags;
	int ret, id;

	sqe_flags = READ_ONCE(sqe->flags);

	 
	if (unlikely(sqe_flags & ~SQE_VALID_FLAGS)) {
		ret = -EINVAL;
		goto err_req;
	}

	id = READ_ONCE(sqe->personality);
	if (id) {
		const struct cred *personality_creds;

		personality_creds = idr_find(&ctx->personality_idr, id);
		if (unlikely(!personality_creds)) {
			ret = -EINVAL;
			goto err_req;
		}
		old_creds = override_creds(personality_creds);
	}

	 
	req->flags |= sqe_flags & (IOSQE_IO_DRAIN|IOSQE_IO_HARDLINK|
					IOSQE_ASYNC);

	ret = io_req_set_file(state, req, sqe);
	if (unlikely(ret)) {
err_req:
		io_cqring_add_event(req, ret);
		io_double_put_req(req);
		if (old_creds)
			revert_creds(old_creds);
		return false;
	}

	 
	if (*link) {
		struct io_kiocb *head = *link;

		 
		if (sqe_flags & IOSQE_IO_DRAIN) {
			head->flags |= REQ_F_IO_DRAIN;
			ctx->drain_next = 1;
		}
		if (io_alloc_async_ctx(req)) {
			ret = -EAGAIN;
			goto err_req;
		}

		ret = io_req_defer_prep(req, sqe);
		if (ret) {
			 
			head->flags |= REQ_F_FAIL_LINK;
			goto err_req;
		}
		trace_io_uring_link(ctx, req, head);
		list_add_tail(&req->link_list, &head->link_list);

		 
		if (!(sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK))) {
			io_queue_link_head(head);
			*link = NULL;
		}
	} else {
		if (unlikely(ctx->drain_next)) {
			req->flags |= REQ_F_IO_DRAIN;
			req->ctx->drain_next = 0;
		}
		if (sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK)) {
			req->flags |= REQ_F_LINK;
			INIT_LIST_HEAD(&req->link_list);
			ret = io_req_defer_prep(req, sqe);
			if (ret)
				req->flags |= REQ_F_FAIL_LINK;
			*link = req;
		} else {
			io_queue_sqe(req, sqe);
		}
	}

	if (old_creds)
		revert_creds(old_creds);
	return true;
}