All of lore.kernel.org
 help / color / mirror / Atom feed
From: glider@google.com
To: Alexander Potapenko <glider@google.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Jens Axboe <axboe@kernel.dk>,  "Theodore Ts'o" <tytso@mit.edu>,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>,
	 "Martin K . Petersen" <martin.petersen@oracle.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	 Christoph Hellwig <hch@lst.de>,
	Eric Dumazet <edumazet@google.com>,
	Eric Van Hensbergen <ericvh@gmail.com>,
	 Takashi Iwai <tiwai@suse.com>,
	Vegard Nossum <vegard.nossum@oracle.com>,
	 Dmitry Vyukov <dvyukov@google.com>,
	linux-mm@kvack.org
Subject: [PATCH RFC v1 23/26] kmsan: unpoisoning buffers from devices etc.
Date: Fri, 18 Oct 2019 11:43:01 +0200	[thread overview]
Message-ID: <20191018094304.37056-24-glider@google.com> (raw)
In-Reply-To: <20191018094304.37056-1-glider@google.com>

When data is copied to memory from a device KMSAN should treat it as
initialized. In most cases it's enough to just unpoison the buffer that
is known to come from a device.
In the case with __do_page_cache_readahead() and bio_copy_user_iov() we
have to mark the whole pages as ignored by KMSAN, as it's not obvious
where these pages are read again.

Signed-off-by: Alexander Potapenko <glider@google.com>
To: Alexander Potapenko <glider@google.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: "Theodore Ts'o" <tytso@mit.edu>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Eric Van Hensbergen <ericvh@gmail.com>
Cc: Takashi Iwai <tiwai@suse.com>
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: linux-mm@kvack.org

---
Suggestions on how to avoid scattering too many annotations over the
code are welcome. Perhaps annotating DMA reads/writes is enough to get
rid of most of these annotations.

Change-Id: Id460e7a86ce564f1357469f53d0c7410ca08f0e9
---
 block/bio.c                  | 20 ++++++++++++++++++++
 block/partition-generic.c    |  9 ++++++++-
 drivers/char/random.c        |  2 ++
 drivers/input/serio/libps2.c |  6 +++++-
 drivers/scsi/scsi_lib.c      |  4 ++++
 drivers/usb/core/message.c   |  6 +++++-
 drivers/virtio/virtio_ring.c | 14 ++++++++++++++
 fs/buffer.c                  |  7 ++++++-
 include/linux/dma-mapping.h  |  2 ++
 include/linux/skbuff.h       |  5 ++++-
 mm/filemap.c                 |  3 +++
 mm/readahead.c               |  6 ++++++
 net/9p/protocol.c            |  2 ++
 sound/core/oss/pcm_oss.c     |  7 +++++++
 14 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index 8f0ed6228fc5..40773cf4b50c 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/export.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
@@ -900,6 +901,13 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
 			__bio_add_page(bio, page, len, offset);
 		}
 		offset = 0;
+		/*
+		 * TODO(glider): these pages will be soon passed to block
+		 * device for reading, so consider them initialized.
+		 */
+		if (iov_iter_rw(iter) == READ)
+			kmsan_unpoison_shadow(page_address(page),
+						PAGE_SIZE);
 	}
 
 	iov_iter_advance(iter, size);
@@ -1274,11 +1282,16 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
 
 			i++;
 		} else {
+			/*
+			 * TODO(glider): KMSAN doesn't track the pages
+			 * allocated for bio here.
+			 */
 			page = alloc_page(q->bounce_gfp | gfp_mask);
 			if (!page) {
 				ret = -ENOMEM;
 				break;
 			}
+			kmsan_ignore_page(page, /*order*/0);
 		}
 
 		if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) {
@@ -1574,6 +1587,13 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
 		if (!page)
 			goto cleanup;
 
+		/*
+		 * TODO(glider): if we're about to read data from a SCSI device,
+		 * assume the page allocated for that is already initialized.
+		 */
+		if (reading)
+			kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);
+
 		if (!reading)
 			memcpy(page_address(page), p, bytes);
 
diff --git a/block/partition-generic.c b/block/partition-generic.c
index aee643ce13d1..87b3ae9e7727 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -663,13 +663,20 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
 {
 	struct address_space *mapping = bdev->bd_inode->i_mapping;
 	struct page *page;
+	unsigned char *retval;
 
 	page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_SHIFT-9)), NULL);
 	if (!IS_ERR(page)) {
 		if (PageError(page))
 			goto fail;
 		p->v = page;
-		return (unsigned char *)page_address(page) +  ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << 9);
+		retval = (unsigned char *)page_address(page) +
+			 ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << 9);
+		/*
+		 * Unpoison sector-sized chunk of memory coming from the device.
+		 */
+		kmsan_unpoison_shadow(retval, SECTOR_SIZE);
+		return retval;
 fail:
 		put_page(page);
 	}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index de434feb873a..cc4afc0f1039 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -320,6 +320,7 @@
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/interrupt.h>
+#include <linux/kmsan-checks.h>
 #include <linux/mm.h>
 #include <linux/nodemask.h>
 #include <linux/spinlock.h>
@@ -1061,6 +1062,7 @@ static void _extract_crng(struct crng_state *crng,
 	spin_lock_irqsave(&crng->lock, flags);
 	if (arch_get_random_long(&v))
 		crng->state[14] ^= v;
+	kmsan_unpoison_shadow(crng->state, sizeof(crng->state));
 	chacha20_block(&crng->state[0], out);
 	if (crng->state[12] == 0)
 		crng->state[13]++;
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index a8c94a940a79..80a9e0a9d3c3 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -8,6 +8,7 @@
 
 
 #include <linux/delay.h>
+#include <linux/kmsan-checks.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -30,6 +31,7 @@ static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
 	int error;
 
 	lockdep_assert_held(&ps2dev->serio->lock);
+	kmsan_check_memory(&byte, 1);
 
 	do {
 		ps2dev->nak = 1;
@@ -294,9 +296,11 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 
 	serio_pause_rx(ps2dev->serio);
 
-	if (param)
+	if (param) {
 		for (i = 0; i < receive; i++)
 			param[i] = ps2dev->cmdbuf[(receive - 1) - i];
+		kmsan_unpoison_shadow(param, receive);
+	}
 
 	if (ps2dev->cmdcnt &&
 	    (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) {
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index dc210b9d4896..4235b317ac5f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -14,6 +14,7 @@
 #include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -296,6 +297,9 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 	ret = rq->result;
  out:
 	blk_put_request(req);
+	/* TODO(glider): this is a bit rough. */
+	if (data_direction == DMA_FROM_DEVICE)
+		kmsan_unpoison_shadow(buffer, bufflen);
 
 	return ret;
 }
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 5adf489428aa..f1c3f8b3cfae 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -9,6 +9,7 @@
 #include <linux/usb.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/kmsan-checks.h>
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
@@ -101,8 +102,11 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
 	retv = usb_start_wait_urb(urb, timeout, &length);
 	if (retv < 0)
 		return retv;
-	else
+	else {
+		/* TODO(glider): USB initializes |length| bytes? */
+		kmsan_unpoison_shadow(data, length);
 		return length;
+	}
 }
 
 /**
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index bdc08244a648..8b7ddc43618f 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/hrtimer.h>
 #include <linux/dma-mapping.h>
+#include <linux/kmsan-checks.h>
 #include <xen/xen.h>
 
 #ifdef DEBUG
@@ -387,6 +388,12 @@ static void vring_unmap_one_split(const struct vring_virtqueue *vq,
 			       (flags & VRING_DESC_F_WRITE) ?
 			       DMA_FROM_DEVICE : DMA_TO_DEVICE);
 	}
+	/*
+	 * Unmapping DMA memory after a transfer from device requires this
+	 * memory to be unpoisoned.
+	 */
+	if (flags & VRING_DESC_F_WRITE)
+		kmsan_unpoison_shadow((const void *)desc->addr, desc->len);
 }
 
 static struct vring_desc *alloc_indirect_split(struct virtqueue *_vq,
@@ -500,6 +507,13 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
 			desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE);
 			desc[i].addr = cpu_to_virtio64(_vq->vdev, addr);
 			desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length);
+			/*
+			 * It's hard to figure out the buffer's address upon
+			 * receive. Instead we unpoison it once, when exposing
+			 * it to the device, and hope nobody else will write to
+			 * it.
+			 */
+			kmsan_unpoison_shadow(sg_virt(sg), sg->length);
 			prev = i;
 			i = virtio16_to_cpu(_vq->vdev, desc[i].next);
 		}
diff --git a/fs/buffer.c b/fs/buffer.c
index 86a38b979323..c08fb1a77fa1 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1170,14 +1170,17 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
 	lock_buffer(bh);
 	if (buffer_uptodate(bh)) {
 		unlock_buffer(bh);
+		kmsan_unpoison_shadow(bh->b_data, bh->b_size);
 		return bh;
 	} else {
 		get_bh(bh);
 		bh->b_end_io = end_buffer_read_sync;
 		submit_bh(REQ_OP_READ, 0, bh);
 		wait_on_buffer(bh);
-		if (buffer_uptodate(bh))
+		if (buffer_uptodate(bh)) {
+			kmsan_unpoison_shadow(bh->b_data, bh->b_size);
 			return bh;
+		}
 	}
 	brelse(bh);
 	return NULL;
@@ -1320,6 +1323,8 @@ __getblk_gfp(struct block_device *bdev, sector_t block,
 	might_sleep();
 	if (bh == NULL)
 		bh = __getblk_slow(bdev, block, size, gfp);
+	if (bh)
+		kmsan_unpoison_shadow(bh->b_data, bh->b_size);
 	return bh;
 }
 EXPORT_SYMBOL(__getblk_gfp);
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a1c4fca475a..cc7b05eb024f 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -8,6 +8,7 @@
 #include <linux/err.h>
 #include <linux/dma-debug.h>
 #include <linux/dma-direction.h>
+#include <linux/kmsan-checks.h>
 #include <linux/scatterlist.h>
 #include <linux/bug.h>
 #include <linux/mem_encrypt.h>
@@ -281,6 +282,7 @@ static inline dma_addr_t dma_map_page_attrs(struct device *dev,
 	const struct dma_map_ops *ops = get_dma_ops(dev);
 	dma_addr_t addr;
 
+	kmsan_unpoison_shadow(page_address(page), size);
 	BUG_ON(!valid_dma_direction(dir));
 	if (dma_is_direct(ops))
 		addr = dma_direct_map_page(dev, page, offset, size, dir, attrs);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 4351577b14d7..b8e9cd697248 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -11,6 +11,7 @@
 #define _LINUX_SKBUFF_H
 
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/compiler.h>
 #include <linux/time.h>
 #include <linux/bug.h>
@@ -2214,6 +2215,8 @@ static inline void *skb_put_data(struct sk_buff *skb, const void *data,
 {
 	void *tmp = skb_put(skb, len);
 
+	/* Unpoison the data received from the network device. */
+	kmsan_unpoison_shadow(data, len);
 	memcpy(tmp, data, len);
 
 	return tmp;
@@ -2221,7 +2224,7 @@ static inline void *skb_put_data(struct sk_buff *skb, const void *data,
 
 static inline void skb_put_u8(struct sk_buff *skb, u8 val)
 {
-	*(u8 *)skb_put(skb, 1) = val;
+	*(u8 *)skb_put(skb, 1) = KMSAN_INIT_VALUE(val);
 }
 
 void *skb_push(struct sk_buff *skb, unsigned int len);
diff --git a/mm/filemap.c b/mm/filemap.c
index 1146fcfa3215..8a17f15806cc 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -18,6 +18,7 @@
 #include <linux/uaccess.h>
 #include <linux/capability.h>
 #include <linux/kernel_stat.h>
+#include <linux/kmsan-checks.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
@@ -2810,6 +2811,8 @@ static struct page *do_read_cache_page(struct address_space *mapping,
 		page = wait_on_page_read(page);
 		if (IS_ERR(page))
 			return page;
+		/* Assume all pages in page cache are initialized. */
+		kmsan_unpoison_shadow(page_address(page), PAGE_SIZE);
 		goto out;
 	}
 	if (PageUptodate(page))
diff --git a/mm/readahead.c b/mm/readahead.c
index 2fe72cd29b47..1fe61128095b 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -193,7 +193,13 @@ unsigned int __do_page_cache_readahead(struct address_space *mapping,
 			continue;
 		}
 
+		/*
+		 * The easiest way to handle these pages is to mark them
+		 * untracked by KMSAN, assuming they're never used by anything
+		 * else.
+		 */
 		page = __page_cache_alloc(gfp_mask);
+		kmsan_ignore_page(page, /*order*/0);
 		if (!page)
 			break;
 		page->index = page_offset;
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 03593eb240d8..5d88ed181422 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/kmsan-checks.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
@@ -46,6 +47,7 @@ EXPORT_SYMBOL(p9stat_free);
 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
 {
 	size_t len = min(pdu->size - pdu->offset, size);
+	kmsan_unpoison_shadow(&pdu->sdata[pdu->offset], len);
 	memcpy(data, &pdu->sdata[pdu->offset], len);
 	pdu->offset += len;
 	return size - len;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index f57c610d7523..c3795e495196 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -12,6 +12,7 @@
 #endif
 
 #include <linux/init.h>
+#include <linux/kmsan-checks.h>	/* for kmsan_unpoison_shadow() */
 #include <linux/slab.h>
 #include <linux/sched/signal.h>
 #include <linux/time.h>
@@ -1054,6 +1055,12 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
 		err = -ENOMEM;
 		goto failure;
 	}
+	/*
+	 * Unpoison the freshly created buffer to prevent KMSAN from reporting
+	 * uninit errors.
+	 * TODO(glider): unpoison it only when it's actually initialized.
+	 */
+	kmsan_unpoison_shadow(runtime->oss.buffer, runtime->oss.period_bytes);
 
 	runtime->oss.params = 0;
 	runtime->oss.prepare = 1;
-- 
2.23.0.866.gb869b98d4c-goog



  parent reply	other threads:[~2019-10-18  9:44 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-18  9:42 [PATCH RFC v1 00/26] Add KernelMemorySanitizer infrastructure glider
2019-10-18  9:42 ` [PATCH RFC v1 01/26] stackdepot: check depot_index before accessing the stack slab glider
2019-10-18  9:42 ` [PATCH RFC v1 02/26] stackdepot: prevent Clang from optimizing away stackdepot_memcmp() glider
2019-10-18  9:42 ` [PATCH RFC v1 03/26] kasan: stackdepot: move filter_irq_stacks() to stackdepot.c glider
2019-10-18  9:42 ` [PATCH RFC v1 04/26] stackdepot: reserve 5 extra bits in depot_stack_handle_t glider
2019-10-18  9:42 ` [PATCH RFC v1 05/26] printk_safe: externalize printk_context glider
2019-10-21  9:09   ` Petr Mladek
2019-10-23 17:57     ` Alexander Potapenko
2019-10-23 18:00       ` Alexander Potapenko
2019-10-24 12:46       ` Petr Mladek
2019-10-28 13:09         ` Alexander Potapenko
2019-10-29 12:02           ` Petr Mladek
2019-10-29 12:45             ` Alexander Potapenko
2019-10-18  9:42 ` [PATCH RFC v1 06/26] kasan: compiler.h: rename __no_kasan_or_inline into __no_memory_tool_or_inline glider
2019-10-18  9:42 ` [PATCH RFC v1 07/26] kmsan: add ReST documentation glider
2019-10-18  9:42 ` [PATCH RFC v1 08/26] kmsan: gfp: introduce __GFP_NO_KMSAN_SHADOW glider
2019-10-18  9:42 ` [PATCH RFC v1 09/26] kmsan: introduce __no_sanitize_memory and __SANITIZE_MEMORY__ glider
2019-10-18  9:42 ` [PATCH RFC v1 10/26] kmsan: reduce vmalloc space glider
2019-10-18  9:42 ` [PATCH RFC v1 11/26] kmsan: add KMSAN runtime glider
2019-10-18  9:42 ` [PATCH RFC v1 12/26] kmsan: x86: sync metadata pages on page fault glider
2019-10-18  9:42 ` [PATCH RFC v1 13/26] kmsan: add tests for KMSAN glider
2019-10-18  9:42 ` [PATCH RFC v1 14/26] kmsan: make READ_ONCE_TASK_STACK() return initialized values glider
2019-10-18  9:42 ` [PATCH RFC v1 15/26] kmsan: Kconfig changes to disable options incompatible with KMSAN glider
2019-10-21 14:11   ` Harry Wentland
2019-10-18  9:42 ` [PATCH RFC v1 16/26] kmsan: Changing existing files to enable KMSAN builds glider
2019-10-18  9:42 ` [PATCH RFC v1 17/26] kmsan: disable KMSAN instrumentation for certain kernel parts glider
2019-10-18  9:42 ` [PATCH RFC v1 18/26] kmsan: mm: call KMSAN hooks from SLUB code glider
2019-10-18 13:22   ` Qian Cai
2019-10-18 13:33     ` Alexander Potapenko
2019-10-18 13:41       ` Qian Cai
2019-10-18 13:55         ` Alexander Potapenko
2019-10-18 14:42           ` Qian Cai
2019-10-18 14:54             ` Alexander Potapenko
2019-10-18 15:13               ` Qian Cai
2019-10-18 15:30                 ` Alexander Potapenko
2019-10-18 16:08                   ` Qian Cai
2019-10-18  9:42 ` [PATCH RFC v1 19/26] kmsan: call KMSAN hooks where needed glider
2019-10-18 15:02   ` Qian Cai
2019-10-29 14:09     ` Alexander Potapenko
2019-10-29 14:56       ` Qian Cai
2019-10-21  9:25   ` Petr Mladek
2019-10-29 13:59     ` Alexander Potapenko
2019-10-18  9:42 ` [PATCH RFC v1 20/26] kmsan: disable instrumentation of certain functions glider
2019-10-18  9:42 ` [PATCH RFC v1 21/26] kmsan: unpoison |tlb| in arch_tlb_gather_mmu() glider
2019-10-18  9:43 ` [PATCH RFC v1 22/26] kmsan: use __msan_memcpy() where possible glider
2019-10-18  9:43 ` glider [this message]
2019-10-18 15:27   ` [PATCH RFC v1 23/26] kmsan: unpoisoning buffers from devices etc Christoph Hellwig
2019-10-18 16:22   ` Matthew Wilcox
2019-10-29 14:45     ` Alexander Potapenko
2019-10-30 12:43       ` Alexander Potapenko
2019-10-18  9:43 ` [PATCH RFC v1 24/26] kmsan: hooks for copy_to_user() and friends glider
2019-10-18  9:43 ` [PATCH RFC v1 25/26] kmsan: disable strscpy() optimization under KMSAN glider
2019-10-18  9:43 ` [PATCH RFC v1 26/26] net: kasan: kmsan: support CONFIG_GENERIC_CSUM on x86, enable it for KASAN/KMSAN glider
2019-10-19  3:20   ` Randy Dunlap

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191018094304.37056-24-glider@google.com \
    --to=glider@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=axboe@kernel.dk \
    --cc=dmitry.torokhov@gmail.com \
    --cc=dvyukov@google.com \
    --cc=edumazet@google.com \
    --cc=ericvh@gmail.com \
    --cc=hch@lst.de \
    --cc=linux-mm@kvack.org \
    --cc=martin.petersen@oracle.com \
    --cc=mst@redhat.com \
    --cc=tiwai@suse.com \
    --cc=tytso@mit.edu \
    --cc=vegard.nossum@oracle.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.