Skip to contentSkip to conversation

drivers/char/mem: byte generating devices and poisoned mappings

RFC PATCH In review Konstantin Khlebnikov 3 participants 6 messages Mar 31, 2014 – Apr 1, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 drivers/char/mem: byte generating devices and poisoned mappings

This patch adds 256 virtual character devices: /dev/byte0, ..., /dev/byte255. Each works like /dev/zero but generates memory filled with particular byte.

Features/use cases:
* handy source of non-zero bytes for 'dd' (dd if=/dev/byte1 ...)
* effective way for allocating poisoned memory (just mmap, without memset)
* /dev/byte42 is full of stars (*)

Memory filled by default with non-zero bytes might help optimize logic in some applications. For example (according to Yury Gribov) Address Sanitizer generates additional conditional jump for each memory access just to handle default zero byte as '0x8' to avoid memset`ing huge shadow memory map at the beginning. In this case allocating memory via mapping /dev/byte8 will reduce size and overhead of instrumented code without adding any memory usage overhead.

/dev/byteX devices have the same performance optimizations like /dev/zero. Shared read-only pages are allocated lazily at the first request and freed by the memory shrinker (design inspired by huge-zero-page). Private mappings are organized as normal anonymous mappings with special page-fault handler which allocates, initializes and installs pages like do_anonymous_page().

Unlike to /dev/zero shared ro-pages are installed into PTEs as normal pages and accounted into file-RSS: vm_normal_page() allows only zero-page to be installed as 'special'. This difference is fixable, but I don't see why it's matters.

This patch also (mostly) implements effective non-zero-filled shmem/tmpfs files, (they are used for shared mappings) but here is no interface for the userspace. This feature mught be exported as ioctl or fcntl call.

Cc Alexandr Andreev <[email protected]>
Cc Vassili Karpov <[email protected]>
Cc Yury Gribov <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Kirill A. Shutemov <[email protected]>
---
 drivers/char/Kconfig     |    7 +
 drivers/char/mem.c       |  285 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/shmem_fs.h |    4 +
 mm/shmem.c               |   58 ++++++++-
 4 files changed, 346 insertions(+), 8 deletions(-)
drivers/char/Kconfig +7 -0
index 1386749..e52cb4e 100644
@@ -15,6 +15,13 @@ config DEVKMEM
 	  kind of kernel debugging operations.
 	  When in doubt, say "N".
 
+config DEVBYTES
+	bool "Byte generating devices"
+	depends on SHMEM
+	help
+	  This option adds 256 virual devices similar to /dev/zero,
+	  one for each byte value: /dev/byte0, /dev/byte1, ..., /dev/byte255.
+
 config SGI_SNSC
 	bool "SGI Altix system controller communication support"
 	depends on (IA64_SGI_SN2 || IA64_GENERIC)
drivers/char/mem.c +285 -0

303 lines not on this page · raw message

include/linux/shmem_fs.h +4 -0
index 9d55438..9fe850b 100644
@@ -11,6 +11,7 @@
 
 struct shmem_inode_info {
 	spinlock_t		lock;
+	unsigned char		byte;		/* byte for filling new pages */
 	unsigned long		flags;
 	unsigned long		alloced;	/* data pages alloced to file */
 	union {
@@ -57,6 +58,9 @@ extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
 extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end);
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
 
+extern struct page *get_byte_page(unsigned char byte);
+extern int shmem_byte_setup(struct vm_area_struct *vma, unsigned char byte);
+
 static inline struct page *shmem_read_mapping_page(
 				struct address_space *mapping, pgoff_t index)
 {
mm/shmem.c +50 -8

88 lines not on this page · raw message

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw
Quoted 2 lines · Konstantin Khlebnikov

This patch adds 256 virtual character devices: /dev/byte0, ..., /dev/byte255. Each works like /dev/zero but generates memory filled with particular byte.

Shouldn't /dev/byte0 be an alias for /dev/zero?
I see you reuse ZERO_PAGE(0) for that, but what about all these special cases /dev/zero has?

Quoted 18 lines

Features/use cases:
* handy source of non-zero bytes for 'dd' (dd if=/dev/byte1 ...)
* effective way for allocating poisoned memory (just mmap, without memset)
* /dev/byte42 is full of stars (*)

Memory filled by default with non-zero bytes might help optimize logic in some applications. For example (according to Yury Gribov) Address Sanitizer generates additional conditional jump for each memory access just to handle default zero byte as '0x8' to avoid memset`ing huge shadow memory map at the beginning. In this case allocating memory via mapping /dev/byte8 will reduce size and overhead of instrumented code without adding any memory usage overhead.

/dev/byteX devices have the same performance optimizations like /dev/zero. Shared read-only pages are allocated lazily at the first request and freed by the memory shrinker (design inspired by huge-zero-page). Private mappings are organized as normal anonymous mappings with special page-fault handler which allocates, initializes and installs pages like do_anonymous_page().

Quoted 3 lines

Unlike to /dev/zero shared ro-pages are installed into PTEs as normal pages and accounted into file-RSS: vm_normal_page() allows only zero-page to be installed as 'special'. This difference is fixable, but I don't see why it's matters.

One thing that could surprise is unexpectedly big core dump files caused by /dev/byteX mappings. We have special handling for FOLL_DUMP && zero_page. Not sure if /dev/byteX should be handled this way too.

Quoted 23 lines

This patch also (mostly) implements effective non-zero-filled shmem/tmpfs files, (they are used for shared mappings) but here is no interface for the userspace. This feature mught be exported as ioctl or fcntl call.

Cc Alexandr Andreev <[email protected]>
Cc Vassili Karpov <[email protected]>
Cc Yury Gribov <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Kirill A. Shutemov <[email protected]>
---
 drivers/char/Kconfig     |    7 +
 drivers/char/mem.c       |  285 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/shmem_fs.h |    4 +
 mm/shmem.c               |   58 ++++++++-
 4 files changed, 346 insertions(+), 8 deletions(-)
drivers/char/Kconfig +0 -0
index 1386749..e52cb4e 100644

drivers/char/Kconfig config DEVKMEM · line 18

Quoted 4 lines
drivers/char/Kconfig +1 -0
@@ -15,6 +15,13 @@ config DEVKMEM
 	  kind of kernel debugging operations.
 	  When in doubt, say "N".
 
+config DEVBYTES

I don't think we want new option for this.

Quoted 6 lines
drivers/char/Kconfig +6 -0
+	bool "Byte generating devices"
+	depends on SHMEM
+	help
+	  This option adds 256 virual devices similar to /dev/zero,
+	  one for each byte value: /dev/byte0, /dev/byte1, ..., /dev/byte255.
+

...

Quoted 17 lines
drivers/char/Kconfig +17 -0
+static ssize_t byte_read(struct file *file, char __user *buf,
+			 size_t count, loff_t *ppos)
+{
+	unsigned byte = (unsigned long)file->private_data;
+	size_t written;
+
+	if (!count)
+		return 0;
+
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+
+	written = 0;
+	while (count) {
+		size_t chunk = min(count, PAGE_SIZE);
+
+		if (__memset_user(buf, byte, chunk))

drivers/char/Kconfig

Quoted 10 lines
drivers/char/Kconfig +10 -0
+			return -EFAULT;
+		if (signal_pending(current))
+			return written ? written : -ERESTARTSYS;
+		written += chunk;
+		buf += chunk;
+		count -= chunk;
+		cond_resched();
+	}
+	return written;
+}

Shouldn't this code be shared with read_zero()?

Quoted 8 lines
drivers/char/Kconfig +8 -0
+
+static ssize_t byte_aio_read(struct kiocb *iocb, const struct iovec *iov,
+			     unsigned long nr_segs, loff_t pos)
+{
+	size_t written = 0;
+	unsigned long i;
+	ssize_t ret;
+

drivers/char/Kconfig

Quoted 10 lines
drivers/char/Kconfig +10 -0
+	for (i = 0; i < nr_segs; i++) {
+		ret = byte_read(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len,
+				&pos);
+		if (ret < 0)
+			break;
+		written += ret;
+	}
+
+	return written ? written : -EFAULT;
+}

Ditto.

Quoted 8 lines
drivers/char/Kconfig +8 -0
+
+static const struct file_operations byte_fops = {
+	.llseek		= byte_lseek,
+	.read		= byte_read,
+	.write		= byte_write,
+	.aio_read	= byte_aio_read,
+	.aio_write      = byte_aio_write,
+	.open		= byte_open,

drivers/char/Kconfig

Quoted 10 lines
drivers/char/Kconfig +10 -0
+	.mmap		= byte_mmap,
+};
+
+static int __init byte_init(void)
+{
+	int major, minor;
+
+	major  = __register_chrdev(0, 0, 256, "byte", &byte_fops);
+	if (major < 0) {
+		printk("unable to get major for byte devs\n");

Hm. Can we, instead of having 256 devnodes, have one /dev/byte? User can ask which byte it wants by write() byte to file descriptor before using it with zero by default.

Signature · 7 lines
 Kirill A. Shutemov

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#2 lore raw
Quoted 7 lines · Kirill A. Shutemov
Quoted 2 lines · Konstantin Khlebnikov

This patch adds 256 virtual character devices: /dev/byte0, ..., /dev/byte255. Each works like /dev/zero but generates memory filled with particular byte.

Shouldn't /dev/byte0 be an alias for /dev/zero?
I see you reuse ZERO_PAGE(0) for that, but what about all these special cases /dev/zero has?

What special cases? I found rss-accounting part, you've mentioned coredump.

Quoted 19 lines
Quoted 19 lines

Features/use cases:
* handy source of non-zero bytes for 'dd' (dd if=/dev/byte1 ...)
* effective way for allocating poisoned memory (just mmap, without memset)
* /dev/byte42 is full of stars (*)

Memory filled by default with non-zero bytes might help optimize logic in some applications. For example (according to Yury Gribov) Address Sanitizer generates additional conditional jump for each memory access just to handle default zero byte as '0x8' to avoid memset`ing huge shadow memory map at the beginning. In this case allocating memory via mapping /dev/byte8 will reduce size and overhead of instrumented code without adding any memory usage overhead.

/dev/byteX devices have the same performance optimizations like /dev/zero. Shared read-only pages are allocated lazily at the first request and freed by the memory shrinker (design inspired by huge-zero-page). Private mappings are organized as normal anonymous mappings with special page-fault handler which allocates, initializes and installs pages like do_anonymous_page().

Quoted 7 lines
Quoted 3 lines

Unlike to /dev/zero shared ro-pages are installed into PTEs as normal pages and accounted into file-RSS: vm_normal_page() allows only zero-page to be installed as 'special'. This difference is fixable, but I don't see why it's matters.

One thing that could surprise is unexpectedly big core dump files caused by /dev/byteX mappings. We have special handling for FOLL_DUMP && zero_page. Not sure if /dev/byteX should be handled this way too.

Seems like it should be. There is no reason for dumping it.

Quoted 61 lines
Quoted 24 lines

This patch also (mostly) implements effective non-zero-filled shmem/tmpfs files, (they are used for shared mappings) but here is no interface for the userspace. This feature mught be exported as ioctl or fcntl call.

Cc Alexandr Andreev <[email protected]>
Cc Vassili Karpov <[email protected]>
Cc Yury Gribov <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Kirill A. Shutemov <[email protected]>
---
 drivers/char/Kconfig     |    7 +
 drivers/char/mem.c       |  285 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/shmem_fs.h |    4 +
 mm/shmem.c               |   58 ++++++++-
 4 files changed, 346 insertions(+), 8 deletions(-)
drivers/char/Kconfig +0 -0
index 1386749..e52cb4e 100644

drivers/char/Kconfig config DEVKMEM · line 18

Quoted 4 lines
drivers/char/Kconfig +1 -0
@@ -15,6 +15,13 @@ config DEVKMEM
        kind of kernel debugging operations.
        When in doubt, say "N".
 
+config DEVBYTES

I don't think we want new option for this.

Quoted 6 lines
drivers/char/Kconfig +6 -0
+     bool "Byte generating devices"
+     depends on SHMEM
+     help
+       This option adds 256 virual devices similar to /dev/zero,
+       one for each byte value: /dev/byte0, /dev/byte1, ..., /dev/byte255.
+

...

Quoted 21 lines
drivers/char/Kconfig +21 -0
+static ssize_t byte_read(struct file *file, char __user *buf,
+                      size_t count, loff_t *ppos)
+{
+     unsigned byte = (unsigned long)file->private_data;
+     size_t written;
+
+     if (!count)
+             return 0;
+
+     if (!access_ok(VERIFY_WRITE, buf, count))
+             return -EFAULT;
+
+     written = 0;
+     while (count) {
+             size_t chunk = min(count, PAGE_SIZE);
+
+             if (__memset_user(buf, byte, chunk))
+                     return -EFAULT;
+             if (signal_pending(current))
+                     return written ? written : -ERESTARTSYS;
+             written += chunk;
Quoted 8 lines

drivers/char/Kconfig

Quoted 6 lines
drivers/char/Kconfig +6 -0
+             buf += chunk;
+             count -= chunk;
+             cond_resched();
+     }
+     return written;
+}

Shouldn't this code be shared with read_zero()?

yep. it might be merged.

Quoted 36 lines
Quoted 9 lines
drivers/char/Kconfig +8 -0
+
+static ssize_t byte_aio_read(struct kiocb *iocb, const struct iovec *iov,
+                          unsigned long nr_segs, loff_t pos)
+{
+     size_t written = 0;
+     unsigned long i;
+     ssize_t ret;
+

drivers/char/Kconfig

Quoted 10 lines
drivers/char/Kconfig +10 -0
+     for (i = 0; i < nr_segs; i++) {
+             ret = byte_read(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len,
+                             &pos);
+             if (ret < 0)
+                     break;
+             written += ret;
+     }
+
+     return written ? written : -EFAULT;
+}

Ditto.

Quoted 14 lines
drivers/char/Kconfig +14 -0
+
+static const struct file_operations byte_fops = {
+     .llseek         = byte_lseek,
+     .read           = byte_read,
+     .write          = byte_write,
+     .aio_read       = byte_aio_read,
+     .aio_write      = byte_aio_write,
+     .open           = byte_open,
+     .mmap           = byte_mmap,
+};
+
+static int __init byte_init(void)
+{
+     int major, minor;
Quoted 8 lines

drivers/char/Kconfig

Quoted 4 lines
drivers/char/Kconfig +4 -0
+
+     major  = __register_chrdev(0, 0, 256, "byte", &byte_fops);
+     if (major < 0) {
+             printk("unable to get major for byte devs\n");

Hm. Can we, instead of having 256 devnodes, have one /dev/byte? User can ask which byte it wants by write() byte to file descriptor before using it with zero by default.

In this case it wouldn't be usable for "dd" =)

poisoned mmap could be be done without devices at all, mmap(MAP_ANONYMOUS) has plenty unused arguments. For example this might looks like:
mmap(flags = MAP_ANONYMOUS | MAP_SHARED/PRIVATE | MAP_POISON, fd = poison)

Quoted 3 lines

--
Kirill A. Shutemov

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#3 lore raw
Quoted 10 lines · Konstantin Khlebnikov
Quoted 7 lines · Kirill A. Shutemov
Quoted 2 lines · Konstantin Khlebnikov

This patch adds 256 virtual character devices: /dev/byte0, ..., /dev/byte255. Each works like /dev/zero but generates memory filled with particular byte.

Shouldn't /dev/byte0 be an alias for /dev/zero?
I see you reuse ZERO_PAGE(0) for that, but what about all these special cases /dev/zero has?

What special cases? I found rss-accounting part, you've mentioned coredump.

I'm not sure what else is there. It's probably good idea to check all users of vm_normal_page().

One thing is zero page coloring which some archs have.

Signature · 7 lines
 Kirill A. Shutemov

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#4 lore raw
In reply to Konstantin Khlebnikov
Quoted 2 lines · On Tue, 01 Apr 2014 01:16:07 +0400 Konstantin Khlebnikov <[email protected]>…

This patch adds 256 virtual character devices: /dev/byte0, ..., /dev/byte255. Each works like /dev/zero but generates memory filled with particular byte.

More kernel code for an ultra-obscure corner case that can be done in user space

I don't see the point

Alan

#5 lore raw
Quoted 10 lines · One Thousand Gnomes
Quoted 2 lines · On Tue, 01 Apr 2014 01:16:07 +0400 Konstantin Khlebnikov <[email protected]>…

This patch adds 256 virtual character devices: /dev/byte0, ..., /dev/byte255. Each works like /dev/zero but generates memory filled with particular byte.

More kernel code for an ultra-obscure corner case that can be done in user space

I don't see the point

True. That was a long-planned joke.
But at the final moment I've found practical usage for it and overall design became not such funny.

Currently I'm thinking about single-device model proposed by Kirill.

Let's call it /dev/poison. Application can open it, write a poison (up to a page size) and after that this instance will generate pages filled with this pattern. I don't see how this can be done in userspace without major memory/cpu overhead caused by initial memset.

Default poison might be for example 0xff, so it still will be useful for 'dd'.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>