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
314 unsigned int tail = pipe->tail;314 unsigned int tail = pipe->tail;
315 unsigned int mask = pipe->ring_size - 1;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 if (!pipe_empty(head, tail)) {341 if (!pipe_empty(head, tail)) {
318 struct pipe_buffer *buf = &pipe->bufs[tail & mask];342 struct pipe_buffer *buf = &pipe->bufs[tail & mask];
319 size_t chars = buf->len;343 size_t chars = buf->len;
@@ -355,6 +379,10 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) · 35 unmodified lines
355 if (!buf->len) {379 if (!buf->len) {
356 pipe_buf_release(pipe, buf);380 pipe_buf_release(pipe, buf);
357 spin_lock_irq(&pipe->rd_wait.lock);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 tail++;386 tail++;
359 pipe->tail = tail;387 pipe->tail = tail;
360 spin_unlock_irq(&pipe->rd_wait.lock);388 spin_unlock_irq(&pipe->rd_wait.lock);
include/linux/pipe_fs_i.h+7−0
@@ -9,6 +9,9 @@ · 8 unmodified lines
9#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */9#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */
10#define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */10#define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */
11#define PIPE_BUF_FLAG_WHOLE 0x10 /* read() must return entire buffer or error */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 * struct pipe_buffer - a linux kernel pipe buffer17 * struct pipe_buffer - a linux kernel pipe buffer
@@ -34,6 +37,7 @@ struct pipe_buffer { · 19 unmodified lines
34 * @wr_wait: writer wait point in case of full pipe37 * @wr_wait: writer wait point in case of full pipe
35 * @head: The point of buffer production38 * @head: The point of buffer production
36 * @tail: The point of buffer consumption39 * @tail: The point of buffer consumption
40 * @note_loss: The next read() should insert a data-lost message
37 * @max_usage: The maximum number of slots that may be used in the ring41 * @max_usage: The maximum number of slots that may be used in the ring
38 * @ring_size: total number of buffers (should be a power of 2)42 * @ring_size: total number of buffers (should be a power of 2)
39 * @nr_accounted: The amount this pipe accounts for in user->pipe_bufs43 * @nr_accounted: The amount this pipe accounts for in user->pipe_bufs
@@ -56,6 +60,9 @@ struct pipe_inode_info { · 16 unmodified lines
56 unsigned int tail;60 unsigned int tail;
57 unsigned int max_usage;61 unsigned int max_usage;
58 unsigned int ring_size;62 unsigned int ring_size;
63#ifdef CONFIG_WATCH_QUEUE
64 bool note_loss;
65#endif
59 unsigned int nr_accounted;66 unsigned int nr_accounted;
60 unsigned int readers;67 unsigned int readers;
61 unsigned int writers;68 unsigned int writers;
kernel/watch_queue.c+2−0
@@ -132,6 +132,8 @@ out: · 131 unmodified lines
132 return done;132 return done;
133 133
134lost:134lost:
135 buf = &pipe->bufs[(head - 1) & mask];
136 buf->flags |= PIPE_BUF_FLAG_LOSS;
135 goto out;137 goto out;
136}138}
137 139
samples/watch_queue/watch_test.c+3−0
@@ -120,6 +120,9 @@ static void consumer(int fd) · 119 unmodified lines
120 (n.n.info & WATCH_INFO_ID) >>120 (n.n.info & WATCH_INFO_ID) >>
121 WATCH_INFO_ID__SHIFT);121 WATCH_INFO_ID__SHIFT);
122 break;122 break;
123 case WATCH_META_LOSS_NOTIFICATION:
124 printf("-- LOSS --\n");
125 break;
123 default:126 default:
124 printf("other meta record\n");127 printf("other meta record\n");
125 break;128 break;