History

pipe: Add notification lossage handling

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.

David Howells committed 6 years ago

Commit e7d553d1 parent 8cfba764 files · +40 −0Browse files

Unified · Split

4 files
  1. fs/pipe.c +28 −0
  2. include/linux/pipe_fs_i.h +7 −0
  3. kernel/watch_queue.c +2 −0
  4. samples/watch_queue/watch_test.c +3 −0
fs/pipe.c+28−0
@@ -314,6 +314,30 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) · 313 unmodified lines
314314 unsigned int tail = pipe->tail;
315315 unsigned int mask = pipe->ring_size - 1;
316316
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+
317341 if (!pipe_empty(head, tail)) {
318342 struct pipe_buffer *buf = &pipe->bufs[tail & mask];
319343 size_t chars = buf->len;
@@ -355,6 +379,10 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) · 35 unmodified lines
355379 if (!buf->len) {
356380 pipe_buf_release(pipe, buf);
357381 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
358386 tail++;
359387 pipe->tail = tail;
360388 spin_unlock_irq(&pipe->rd_wait.lock);
include/linux/pipe_fs_i.h+7−0
@@ -9,6 +9,9 @@ · 8 unmodified lines
99 #define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */
1010 #define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */
1111 #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
1215
1316 /**
1417 * struct pipe_buffer - a linux kernel pipe buffer
@@ -34,6 +37,7 @@ struct pipe_buffer { · 19 unmodified lines
3437 * @wr_wait: writer wait point in case of full pipe
3538 * @head: The point of buffer production
3639 * @tail: The point of buffer consumption
40+ * @note_loss: The next read() should insert a data-lost message
3741 * @max_usage: The maximum number of slots that may be used in the ring
3842 * @ring_size: total number of buffers (should be a power of 2)
3943 * @nr_accounted: The amount this pipe accounts for in user->pipe_bufs
@@ -56,6 +60,9 @@ struct pipe_inode_info { · 16 unmodified lines
5660 unsigned int tail;
5761 unsigned int max_usage;
5862 unsigned int ring_size;
63+#ifdef CONFIG_WATCH_QUEUE
64+ bool note_loss;
65+#endif
5966 unsigned int nr_accounted;
6067 unsigned int readers;
6168 unsigned int writers;
kernel/watch_queue.c+2−0
@@ -132,6 +132,8 @@ out: · 131 unmodified lines
132132 return done;
133133
134134 lost:
135+ buf = &pipe->bufs[(head - 1) & mask];
136+ buf->flags |= PIPE_BUF_FLAG_LOSS;
135137 goto out;
136138 }
137139
samples/watch_queue/watch_test.c+3−0
@@ -120,6 +120,9 @@ static void consumer(int fd) · 119 unmodified lines
120120 (n.n.info & WATCH_INFO_ID) >>
121121 WATCH_INFO_ID__SHIFT);
122122 break;
123+ case WATCH_META_LOSS_NOTIFICATION:
124+ printf("-- LOSS --\n");
125+ break;
123126 default:
124127 printf("other meta record\n");
125128 break;