Re: [PATCH 05/19] Add io_uring IO interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 9 Feb 2019, Jens Axboe wrote:
> +static void io_commit_cqring(struct io_ring_ctx *ctx)
> +{
> +	struct io_cq_ring *ring = ctx->cq_ring;
> +
> +	if (ctx->cached_cq_tail != READ_ONCE(ring->r.tail)) {
> +		/* order cqe stores with ring update */

This lacks a reference to the matching rmb()

> +		smp_wmb();
> +		WRITE_ONCE(ring->r.tail, ctx->cached_cq_tail);
> +		/* write side barrier of tail update, app has read side */

That's a bit meager. Can you please document the barriers which are paired
with user space barriers very elaborate?

> +		smp_wmb();
> +
> +		if (wq_has_sleeper(&ctx->cq_wait)) {
> +			wake_up_interruptible(&ctx->cq_wait);
> +			kill_fasync(&ctx->cq_fasync, SIGIO, POLL_IN);
> +		}
> +	}
> +}
> +
> +static struct io_uring_cqe *io_get_cqring(struct io_ring_ctx *ctx)
> +{
> +	struct io_cq_ring *ring = ctx->cq_ring;
> +	unsigned tail;
> +
> +	tail = ctx->cached_cq_tail;
> +	smp_rmb();

Undocumented barrier

> +	if (tail + 1 == READ_ONCE(ring->r.head))
> +		return NULL;

> +static void io_commit_sqring(struct io_ring_ctx *ctx)
> +{
> +	struct io_sq_ring *ring = ctx->sq_ring;
> +
> +	if (ctx->cached_sq_head != READ_ONCE(ring->r.head)) {
> +		WRITE_ONCE(ring->r.head, ctx->cached_sq_head);
> +		/* write side barrier of head update, app has read side */

See above.

> +		smp_wmb();
> +	}
> +}


> +static bool io_get_sqring(struct io_ring_ctx *ctx, struct sqe_submit *s)
> +{
> +	struct io_sq_ring *ring = ctx->sq_ring;
> +	unsigned head;
> +
> +	/*
> +	 * The cached sq head (or cq tail) serves two purposes:
> +	 *
> +	 * 1) allows us to batch the cost of updating the user visible
> +	 *    head updates.
> +	 * 2) allows the kernel side to track the head on its own, even
> +	 *    though the application is the one updating it.
> +	 */
> +	head = ctx->cached_sq_head;
> +	smp_rmb();

Undocumented barrier

> +	if (head == READ_ONCE(ring->r.tail))
> +		return false;
> +
> +	head = READ_ONCE(ring->array[head & ctx->sq_mask]);
> +	if (head < ctx->sq_entries) {
> +		s->index = head;
> +		s->sqe = &ctx->sq_sqes[head];
> +		ctx->cached_sq_head++;
> +		return true;
> +	}
> +
> +	/* drop invalid entries */
> +	ctx->cached_sq_head++;
> +	ring->dropped++;
> +	smp_wmb();

Undocumented barrier

> +	return false;
> +}
> +

> +static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
> +			  const sigset_t __user *sig, size_t sigsz)
> +{
> +	struct io_cq_ring *ring = ctx->cq_ring;
> +	sigset_t ksigmask, sigsaved;
> +	DEFINE_WAIT(wait);
> +	int ret = 0;
> +
> +	smp_rmb();
> +	if (READ_ONCE(ring->r.head) != READ_ONCE(ring->r.tail))
> +		return 0;
> +	if (!min_events)
> +		return 0;
> +
> +	if (sig) {
> +		ret = set_user_sigmask(sig, &ksigmask, &sigsaved, sigsz);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	do {
> +		prepare_to_wait(&ctx->wait, &wait, TASK_INTERRUPTIBLE);
> +
> +		ret = 0;
> +		smp_rmb();

Undocumented barrier

> +		if (READ_ONCE(ring->r.head) != READ_ONCE(ring->r.tail))
> +			break;
> +

There are undocumented smp_wmb()'s in 'io_uring: Add submission polling' as
well. It's really hard to tell where the corresponding barriers are and
what they are supposed to order.

Especially the barriers which are paired with user space barriers need some
careful documentation. What are the side effects if user space is missing a
barrier? Just user space seing unconsistent data or is there something
which goes the other way round and might cause havoc in the kernel?

Thanks,

	tglx



[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux