Add handling for loss of notifications by having read() insert a loss-notification message after it has read the pipe buffer that was last in the ring when the loss occurred. Lossage can come about either by running out of notification descriptors or by running out of space in the pipe ring.
Unified · Split
| @@ -314,6 +314,30 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) · 313 unmodified lines | ||
| 314 | 314 | unsigned int tail = pipe->tail; |
| 315 | 315 | unsigned int mask = pipe->ring_size - 1; |
| 316 | 316 | |
| 317 | +#ifdef CONFIG_WATCH_QUEUE | |
| 318 | + if (pipe->note_loss) { | |
| 319 | + struct watch_notification n; | |
| 320 | + | |
| 321 | + if (total_len < 8) { | |
| 322 | + if (ret == 0) | |
| 323 | + ret = -ENOBUFS; | |
| 324 | + break; | |
| 325 | + } | |
| 326 | + | |
| 327 | + n.type = WATCH_TYPE_META; | |
| 328 | + n.subtype = WATCH_META_LOSS_NOTIFICATION; | |
| 329 | + n.info = watch_sizeof(n); | |
| 330 | + if (copy_to_iter(&n, sizeof(n), to) != sizeof(n)) { | |
| 331 | + if (ret == 0) | |
| 332 | + ret = -EFAULT; | |
| 333 | + break; | |
| 334 | + } | |
| 335 | + ret += sizeof(n); | |
| 336 | + total_len -= sizeof(n); | |
| 337 | + pipe->note_loss = false; | |
| 338 | + } | |
| 339 | +#endif | |
| 340 | + | |
| 317 | 341 | if (!pipe_empty(head, tail)) { |
| 318 | 342 | struct pipe_buffer *buf = &pipe->bufs[tail & mask]; |
| 319 | 343 | size_t chars = buf->len; |
| @@ -355,6 +379,10 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) · 35 unmodified lines | ||
| 355 | 379 | if (!buf->len) { |
| 356 | 380 | pipe_buf_release(pipe, buf); |
| 357 | 381 | spin_lock_irq(&pipe->rd_wait.lock); |
| 382 | +#ifdef CONFIG_WATCH_QUEUE | |
| 383 | + if (buf->flags & PIPE_BUF_FLAG_LOSS) | |
| 384 | + pipe->note_loss = true; | |
| 385 | +#endif | |
| 358 | 386 | tail++; |
| 359 | 387 | pipe->tail = tail; |
| 360 | 388 | spin_unlock_irq(&pipe->rd_wait.lock); |
| @@ -9,6 +9,9 @@ · 8 unmodified lines | ||
| 9 | 9 | #define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */ |
| 10 | 10 | #define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */ |
| 11 | 11 | #define PIPE_BUF_FLAG_WHOLE 0x10 /* read() must return entire buffer or error */ |
| 12 | +#ifdef CONFIG_WATCH_QUEUE | |
| 13 | +#define PIPE_BUF_FLAG_LOSS 0x20 /* Message loss happened after this buffer */ | |
| 14 | +#endif | |
| 12 | 15 | |
| 13 | 16 | /** |
| 14 | 17 | * struct pipe_buffer - a linux kernel pipe buffer |
| @@ -34,6 +37,7 @@ struct pipe_buffer { · 19 unmodified lines | ||
| 34 | 37 | * @wr_wait: writer wait point in case of full pipe |
| 35 | 38 | * @head: The point of buffer production |
| 36 | 39 | * @tail: The point of buffer consumption |
| 40 | + * @note_loss: The next read() should insert a data-lost message | |
| 37 | 41 | * @max_usage: The maximum number of slots that may be used in the ring |
| 38 | 42 | * @ring_size: total number of buffers (should be a power of 2) |
| 39 | 43 | * @nr_accounted: The amount this pipe accounts for in user->pipe_bufs |
| @@ -56,6 +60,9 @@ struct pipe_inode_info { · 16 unmodified lines | ||
| 56 | 60 | unsigned int tail; |
| 57 | 61 | unsigned int max_usage; |
| 58 | 62 | unsigned int ring_size; |
| 63 | +#ifdef CONFIG_WATCH_QUEUE | |
| 64 | + bool note_loss; | |
| 65 | +#endif | |
| 59 | 66 | unsigned int nr_accounted; |
| 60 | 67 | unsigned int readers; |
| 61 | 68 | unsigned int writers; |
| @@ -132,6 +132,8 @@ out: · 131 unmodified lines | ||
| 132 | 132 | return done; |
| 133 | 133 | |
| 134 | 134 | lost: |
| 135 | + buf = &pipe->bufs[(head - 1) & mask]; | |
| 136 | + buf->flags |= PIPE_BUF_FLAG_LOSS; | |
| 135 | 137 | goto out; |
| 136 | 138 | } |
| 137 | 139 | |
| @@ -120,6 +120,9 @@ static void consumer(int fd) · 119 unmodified lines | ||
| 120 | 120 | (n.n.info & WATCH_INFO_ID) >> |
| 121 | 121 | WATCH_INFO_ID__SHIFT); |
| 122 | 122 | break; |
| 123 | + case WATCH_META_LOSS_NOTIFICATION: | |
| 124 | + printf("-- LOSS --\n"); | |
| 125 | + break; | |
| 123 | 126 | default: |
| 124 | 127 | printf("other meta record\n"); |
| 125 | 128 | break; |