Skip to contentSkip to conversation

mm: introduce VM_MIXEDMAP mappings

RFC PATCH In review Nick Piggin 9 participants 79 messages Dec 14, 2007 – Jan 17, 2008 2 messages not in the archive

Subsystems (9)
Memory management VFS MM core s390 +5 more subsystems
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/2 mm: introduce VM_MIXEDMAP mappings

Hi,

These 2 patches are an rfc only at this point. I've done some basic testing of them with my brd device driver, but it will probably take more work to get a real setup working...

This is one of the things Jared might need to better support some of his non volatile memory work in the pipeline, however we're hoping that it might be of some use to s390 systems too.

Thanks,
Nick

---
From: Jared Hulbert <[email protected]>

mm: introduce VM_MIXEDMAP

Introduce a new type of mapping, VM_MIXEDMAP. This is unlike VM_PFNMAP in that it can support COW mappings of arbitrary ranges including ranges without struct page (PFNMAP can only support COW in those cases where the un-COW-ed translations are mapped linearly in the virtual address).

VM_MIXEDMAP achieves this by refcounting all pfn_valid pages, and not refcounting !pfn_valid pages (which is not an option for VM_PFNMAP, because it needs to avoid refcounting pfn_valid pages eg. for /dev/mem mappings).

---

include/linux/mm.h +1 -0
Index: linux-2.6/include/linux/mm.h
===================================================================
@@ -106,6 +106,7 @@ extern unsigned int kobjsize(const void 
 #define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
 
 #define VM_CAN_NONLINEAR 0x08000000	/* Has ->fault & does nonlinear pages */
+#define VM_MIXEDMAP	0x10000000	/* Can contain "struct page" and pure PFN pages */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
mm/memory.c +58 -21

117 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

RFC PATCH 2/2 xip: support non-struct page memory

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

---

Convert XIP to support non-struct page backed memory, using VM_MIXEDMAP for the user mappings.

This requires the get_xip_page API to be changed to an address based one.

(The kaddr->pfn conversion may not be quite right for all architectures or XIP memory mappings, and the cacheflushing may need to be updated for some archs).

fs/ext2/inode.c +1 -1
Index: linux-2.6/fs/ext2/inode.c
===================================================================
@@ -800,7 +800,7 @@ const struct address_space_operations ex
 
 const struct address_space_operations ext2_aops_xip = {
 	.bmap			= ext2_bmap,
-	.get_xip_page		= ext2_get_xip_page,
+	.get_xip_address	= ext2_get_xip_address,
 };
 
 const struct address_space_operations ext2_nobh_aops = {
fs/ext2/xip.c +18 -18
Index: linux-2.6/fs/ext2/xip.c
===================================================================
@@ -15,24 +15,25 @@
 #include "xip.h"
 
 static inline int
-__inode_direct_access(struct inode *inode, sector_t sector,
-		      unsigned long *data)
+__inode_direct_access(struct inode *inode, sector_t block, unsigned long *data)
 {
+	sector_t sector;
 	BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+
+	sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
 	return inode->i_sb->s_bdev->bd_disk->fops
-		->direct_access(inode->i_sb->s_bdev,sector,data);
+		->direct_access(inode->i_sb->s_bdev, sector, data);
 }
 
 static inline int
-__ext2_get_sector(struct inode *inode, sector_t offset, int create,
+__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
 		   sector_t *result)
 {
 	struct buffer_head tmp;
 	int rc;
 
 	memset(&tmp, 0, sizeof(struct buffer_head));
-	rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &tmp,
-			    create);
+	rc = ext2_get_block(inode, pgoff, &tmp, create);
 	*result = tmp.b_blocknr;
 
 	/* did we get a sparse block (hole in the file)? */
@@ -45,13 +46,12 @@ __ext2_get_sector(struct inode *inode, s
 }
 
 int
-ext2_clear_xip_target(struct inode *inode, int block)
+ext2_clear_xip_target(struct inode *inode, sector_t block)
 {
-	sector_t sector = block * (PAGE_SIZE/512);
 	unsigned long data;
 	int rc;
 
-	rc = __inode_direct_access(inode, sector, &data);
+	rc = __inode_direct_access(inode, block, &data);
 	if (!rc)
 		clear_page((void*)data);
 	return rc;
@@ -69,24 +69,24 @@ void ext2_xip_verify_sb(struct super_blo
 	}
 }
 
-struct page *
-ext2_get_xip_page(struct address_space *mapping, sector_t offset,
-		   int create)
+void *
+ext2_get_xip_address(struct address_space *mapping, pgoff_t pgoff, int create)
 {
 	int rc;
 	unsigned long data;
-	sector_t sector;
+	sector_t block;
 
 	/* first, retrieve the sector number */
-	rc = __ext2_get_sector(mapping->host, offset, create, &sector);
+	rc = __ext2_get_block(mapping->host, pgoff, create, &block);
 	if (rc)
 		goto error;
 
 	/* retrieve address of the target data */
-	rc = __inode_direct_access
-		(mapping->host, sector * (PAGE_SIZE/512), &data);
-	if (!rc)
-		return virt_to_page(data);
+	rc = __inode_direct_access(mapping->host, block, &data);
+	if (rc)
+		goto error;
+
+	return (void *)data;
 
  error:
 	return ERR_PTR(rc);
fs/ext2/xip.h +3 -3
Index: linux-2.6/fs/ext2/xip.h
===================================================================
@@ -7,15 +7,15 @@
 
 #ifdef CONFIG_EXT2_FS_XIP
 extern void ext2_xip_verify_sb (struct super_block *);
-extern int ext2_clear_xip_target (struct inode *, int);
+extern int ext2_clear_xip_target (struct inode *, sector_t);
 
 static inline int ext2_use_xip (struct super_block *sb)
 {
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
 }
-struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
-#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+void *ext2_get_xip_address(struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_address)
 #else
 #define mapping_is_xip(map)			0
 #define ext2_xip_verify_sb(sb)			do { } while (0)
fs/open.c +1 -1
Index: linux-2.6/fs/open.c
===================================================================
@@ -778,7 +778,7 @@ static struct file *__dentry_open(struct
 	if (f->f_flags & O_DIRECT) {
 		if (!f->f_mapping->a_ops ||
 		    ((!f->f_mapping->a_ops->direct_IO) &&
-		    (!f->f_mapping->a_ops->get_xip_page))) {
+		    (!f->f_mapping->a_ops->get_xip_address))) {
 			fput(f);
 			f = ERR_PTR(-EINVAL);
 		}
include/linux/fs.h +1 -2
Index: linux-2.6/include/linux/fs.h
===================================================================
@@ -473,8 +473,7 @@ struct address_space_operations {
 	int (*releasepage) (struct page *, gfp_t);
 	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
-	struct page* (*get_xip_page)(struct address_space *, sector_t,
-			int);
+	void * (*get_xip_address)(struct address_space *, pgoff_t, int);
 	/* migrate the contents of a page to the specified target */
 	int (*migratepage) (struct address_space *,
 			struct page *, struct page *);
mm/fadvise.c +1 -1
Index: linux-2.6/mm/fadvise.c
===================================================================
@@ -49,7 +49,7 @@ asmlinkage long sys_fadvise64_64(int fd,
 		goto out;
 	}
 
-	if (mapping->a_ops->get_xip_page)
+	if (mapping->a_ops->get_xip_address)
 		/* no bad return value, but ignore advice */
 		goto out;
 
mm/filemap_xip.c +90 -92

340 lines not on this page · raw message

mm/madvise.c +1 -1
Index: linux-2.6/mm/madvise.c
===================================================================
@@ -112,7 +112,7 @@ static long madvise_willneed(struct vm_a
 	if (!file)
 		return -EBADF;
 
-	if (file->f_mapping->a_ops->get_xip_page) {
+	if (file->f_mapping->a_ops->get_xip_address) {
 		/* no bad return value, but ignore advice */
 		return 0;
 	}

--
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

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

Seems to be christmas time, I get a feature that has been on my most wanted list for years :-). Will play with it and test it asap :-).

--
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

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 6 lines
Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

Seems to be christmas time, I get a feature that has been on my most wanted list for years :-). Will play with it and test it asap :-).

That's exactly how I feel. I'm testing it out right now.

One thing I would love is for a way for get_xip_address to be able to punt. To be able to tell filemap_xip.c functions that the filemap.c or generic functions should be used instead. For example xip_file_fault() calls filemap_fault() when get_xip_address() returns NULL. Can we do that for a return value of NULL?

--
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

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 8 lines · Jared Hulbert
Quoted 6 lines
Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

Seems to be christmas time, I get a feature that has been on my most wanted list for years :-). Will play with it and test it asap :-).

That's exactly how I feel. I'm testing it out right now.

Well, then call me Saint Nick ;)

Quoted 5 lines

One thing I would love is for a way for get_xip_address to be able to punt. To be able to tell filemap_xip.c functions that the filemap.c or generic functions should be used instead. For example xip_file_fault() calls filemap_fault() when get_xip_address() returns NULL. Can we do that for a return value of NULL?

I was thinking about that, but I wonder if it shouldn't be done in the filesystem. Eg. if your filesystem mixes both pagecache and XIP, then it would call into either filemap or filemap_xip...

--
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>

#5 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 9 lines
Quoted 5 lines

One thing I would love is for a way for get_xip_address to be able to punt. To be able to tell filemap_xip.c functions that the filemap.c or generic functions should be used instead. For example xip_file_fault() calls filemap_fault() when get_xip_address() returns NULL. Can we do that for a return value of NULL?

I was thinking about that, but I wonder if it shouldn't be done in the filesystem. Eg. if your filesystem mixes both pagecache and XIP, then it would call into either filemap or filemap_xip...

Well yeah it can be done in the filesystem. I just hate to have an axfs_mmap() that is identical to xip_file_mmap() if it can be avoided.
Is there some reason not to do the NULL thing?

--
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>

#6 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

In reply to Nick Piggin
Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

I've tested your patch series on s390 with dcssblk block device and ext2 file system with -o xip. Everything seems to work fine. I will now patch my kernel not to build struct page for the shared segment and see if that works too.

so long,
Carsten

--
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>

#7 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 8 lines · Carsten Otte
Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

I've tested your patch series on s390 with dcssblk block device and ext2 file system with -o xip. Everything seems to work fine. I will now patch my kernel not to build struct page for the shared segment and see if that works too.

I tested it with AXFS for ARM on NOR flash (pfn) and with a UML build on x86 using the UML iomem interface (struct page). Works slick. Cleans up the nastiest part of AXFS and makes a MTD patch unnecessary.
Very nice.

So we've got some documentation to do and you missed this, it won't compile with EXT2 XIP off.

fs/ext2/xip.h Thu Dec 20 01:14:41 2007 -0800 renamed from fs/ext2/xip.h Thu Dec 20 00:53:18 2007 -0800 +1 -1
diff -r e677a09f65e2 fs/ext2/xip.h
@@ -21,5 +21,5 @@ void *ext2_get_xip_address(struct addres
 #define ext2_xip_verify_sb(sb)                 do { } while (0)
 #define ext2_use_xip(sb)                       0
 #define ext2_clear_xip_target(inode, chain)    0
-#define ext2_get_xip_page                      NULL
+#define ext2_get_xip_address                   NULL
 #endif

--
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>

#8 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 10 lines · Jared Hulbert
Quoted 8 lines · Carsten Otte
Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

I've tested your patch series on s390 with dcssblk block device and ext2 file system with -o xip. Everything seems to work fine. I will now patch my kernel not to build struct page for the shared segment and see if that works too.

Quoted 4 lines

I tested it with AXFS for ARM on NOR flash (pfn) and with a UML build on x86 using the UML iomem interface (struct page). Works slick. Cleans up the nastiest part of AXFS and makes a MTD patch unnecessary.
Very nice.

Ah, excellent. Thanks for testing! I may not have a lot more time to spend on this before next year, but feel free to do what you please with it until then.

Quoted 2 lines

So we've got some documentation to do and you missed this, it won't compile with EXT2 XIP off.

Yep, thanks.

fs/ext2/xip.h Thu Dec 20 01:14:41 2007 -0800 void *ext2_get_xip_address(struct addres · line 25

Quoted 11 lines

diff -r e677a09f65e2 fs/ext2/xip.h

fs/ext2/xip.h Thu Dec 20 01:14:41 2007 -0800 renamed from fs/ext2/xip.h Thu Dec 20 00:53:18 2007 -0800 +1 -1
@@ -21,5 +21,5 @@ void *ext2_get_xip_address(struct addres
 #define ext2_xip_verify_sb(sb)                 do { } while (0)
 #define ext2_use_xip(sb)                       0
 #define ext2_clear_xip_target(inode, chain)    0
-#define ext2_get_xip_page                      NULL
+#define ext2_get_xip_address                   NULL
 #endif

--
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>

#9 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

In reply to Nick Piggin
Quoted 3 lines · Nick Piggin

This is just a prototype for one possible way of supporting this. I may be missing some important detail or eg. have missed some requirement of the s390 XIP block device that makes the idea infeasible... comments?

I've tested things now without initialization of our struct page entries for s390. This does'nt work out, as you can see below. free_hot_cold_page apparently still uses the struct page behind our shared memory segment. Please don't get confused by the process name "mount": this is _not_ the mount that has mounted the xip file system but rather an elf binary of /bin/mount [on ext3] which is linked against a library in /usr/lib64 [on ext2 -o xip]. I'll drill down deeper here to see why it does'nt work as expected...
<6>extmem info:segment_load: loaded segment COTTE range
0000000020000000 .. 000000007fe00fff type SW in shared mode

    <6>dcssblk info: Loaded segment COTTE, size = 1608519680 Byte, 

capacity = 3141640 (512 Byte) sectors
<4>EXT2-fs warning: checktime reached, running e2fsck is recommended <0>Bad page state in process 'mount' <0>page:000003fffedd7a50 flags:0x0000000000000000
mapping:0000000000000000 mapcount:1 count:0

    <0>Trying to fix it up, but a reboot is needed
    <0>Backtrace:
    <4>0000000000000000 000000000fbd5b58 0000000000000002 
0000000000000000
    <4>       000000000fbd5bf8 000000000fbd5b70 000000000fbd5b70 
000000000012b882
    <4>       0000000000000000 0000000000000000 000003fffe6f76f8 
0000000000000000
    <4>       0000000000000000 000000000fbd5b58 000000000000000d 
000000000fbd5bc8
    <4>       0000000000415f30 00000000001037b8 000000000fbd5b58 
000000000fbd5ba0
    <4>Call Trace:
    <4>([<0000000000103736>] show_trace+0x12e/0x148)
    <4> [<0000000000171e10>] bad_page+0x94/0xd0
    <4> [<0000000000172c80>] free_hot_cold_page+0x218/0x230
    <4> [<0000000000180082>] unmap_vmas+0x4e6/0xc50
    <4> [<0000000000185fa0>] exit_mmap+0x128/0x408
    <4> [<0000000000127e90>] mmput+0x70/0xe4
    <4> [<000000000012f606>] do_exit+0x1b6/0x8ac
    <4> [<000000000012fd48>] do_group_exit+0x4c/0xa4
    <4> [<00000000001102b8>] sysc_noemu+0x10/0x16
    <4> [<0000020000108272>] 0x20000108272

...and here the patch I use to get rid of the struct page entries in our vmmem_map array:

---

arch/s390/mm/vmem.c +0 -16
Index: linux-2.6/arch/s390/mm/vmem.c
===================================================================
@@ -310,8 +310,6 @@ out:
 int add_shared_memory(unsigned long start, unsigned long size)
 {
        struct memory_segment *seg;
-       struct page *page;
-       unsigned long pfn, num_pfn, end_pfn;
        int ret;
 
        mutex_lock(&vmem_mutex);
@@ -330,20 +328,6 @@ int add_shared_memory(unsigned long star
        if (ret)
                goto out_remove;
 
-       pfn = PFN_DOWN(start);
-       num_pfn = PFN_DOWN(size);
-       end_pfn = pfn + num_pfn;
-
-       page = pfn_to_page(pfn);
-       memset(page, 0, num_pfn * sizeof(struct page));
-
-       for (; pfn < end_pfn; pfn++) {
-               page = pfn_to_page(pfn);
-               init_page_count(page);
-               reset_page_mapcount(page);
-               SetPageReserved(page);
-               INIT_LIST_HEAD(&page->lru);
-       }
        goto out;
 
 out_remove:

--
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>

#10 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 1 line · Carsten Otte

I'll drill down deeper here to see why it does'nt work as expected...

Apparently pfn_valid() is true for our shared memory segment. The s390 implementation checks if the pfn is within max_pfn, which reflects the size of the kernel page table 1:1 mapping. If that is the case, we use one of our many magic instructions "lra" to ask our mmu if there is memory we can access at subject address. Both is true for our shared memory segment. Thus, the page gets refcounted regular on a struct page entry that is not initialized.

Even worse, changing the semantic of pfn_valid() on s390 to be false for shared segments is no option. We'll want to use the same memory segment for memory hotplug. And in that case we do want refcounting because it becomes regular linux memory.

So bottom line I think we do need a different trigger then pfn_valid() to select which pages within VM_MIXEDMAP get refcounted and which don't.

cheers,
Carsten

--
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>

#11 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 1 line · Carsten Otte

So bottom line I think we do need a different trigger then pfn_valid() to select which pages within VM_MIXEDMAP get refcounted and which don't.

A poor man's solution could be, to store a pfn range of the flash chip and/or shared memory segment inside vm_area_struct, and in case of VM_MIXEDMAP we check if the pfn matches that range. If so: no refcounting. If not: regular refcounting. Is that an option?

--
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>

#12 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 4 lines

A poor man's solution could be, to store a pfn range of the flash chip and/or shared memory segment inside vm_area_struct, and in case of VM_MIXEDMAP we check if the pfn matches that range. If so: no refcounting. If not: regular refcounting. Is that an option?

I'm not picturing what is responsible for configuring this stored pfn range. Does the fs do it on mount? Does the MTD or your funky direct_access block driver do it?

What if you use VM_PFNMAP instead of VM_MIXEDMAP?

--
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>

#13 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 10 lines · Jared Hulbert
Quoted 4 lines

A poor man's solution could be, to store a pfn range of the flash chip and/or shared memory segment inside vm_area_struct, and in case of VM_MIXEDMAP we check if the pfn matches that range. If so: no refcounting. If not: regular refcounting. Is that an option?

I'm not picturing what is responsible for configuring this stored pfn range. Does the fs do it on mount? Does the MTD or your funky direct_access block driver do it?

What if you use VM_PFNMAP instead of VM_MIXEDMAP?

Though that might _work_ for ext2 it doesn't fix VM_MIXEDMAP.

vm_normal_page() needs to know if a VM_MIXEDMAP pfn has a struct page or not. Somebody had suggested we'd need a pfn_normal() or something.
Maybe it should be called pfn_has_page() instead. For ARM
pfn_has_page() == pfn_valid() near as I can tell. What about on s390?
If pfn_valid() doesn't work, then can you check if the pfn is
hotplugged in? What would pfn_to_page() return if the associated struct page entry was not initialized? Can we use what is returned to check if the pfn has no page?

--
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>

#14 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 6 lines · Jared Hulbert
Quoted 5 lines · Jared Hulbert
Quoted 4 lines

A poor man's solution could be, to store a pfn range of the flash chip and/or shared memory segment inside vm_area_struct, and in case of VM_MIXEDMAP we check if the pfn matches that range. If so: no refcounting. If not: regular refcounting. Is that an option?

Quoted 7 lines
Quoted 5 lines

I'm not picturing what is responsible for configuring this stored pfn range. Does the fs do it on mount? Does the MTD or your funky direct_access block driver do it?

What if you use VM_PFNMAP instead of VM_MIXEDMAP?

Though that might _work_ for ext2 it doesn't fix VM_MIXEDMAP.

Yeah, I guess they have the same problem as you: they want to be able to support COW of non contiguous physical memory mappings as well (which PFNMAP can't do).

Quoted 8 lines

vm_normal_page() needs to know if a VM_MIXEDMAP pfn has a struct page or not. Somebody had suggested we'd need a pfn_normal() or something.
Maybe it should be called pfn_has_page() instead. For ARM
pfn_has_page() == pfn_valid() near as I can tell. What about on s390?
If pfn_valid() doesn't work, then can you check if the pfn is
hotplugged in? What would pfn_to_page() return if the associated struct page entry was not initialized? Can we use what is returned to check if the pfn has no page?

As fas as I know, that's what pfn_valid() should tell you (ie. that you have a struct page allocated). So I think this is kind of a quirk of the s390 memory model and I'd rather not "legitimize" it by calling it pfn_normal (because then what's pfn_valid for?).

But definitely I think we could support a hack for them one way or the other.

--
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>

#15 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

In reply to Jared Hulbert
Quoted 4 lines · Jared Hulbert

vm_normal_page() needs to know if a VM_MIXEDMAP pfn has a struct page or not. Somebody had suggested we'd need a pfn_normal() or something.
Maybe it should be called pfn_has_page() instead. For ARM
pfn_has_page() == pfn_valid() near as I can tell. What about on s390?

Well, pfn_valid does'nt work for us as I pointed out before.

Quoted 2 lines

If pfn_valid() doesn't work, then can you check if the pfn is
hotplugged in?

Since the same memory segment may either be used as hotplug memory or as shared segment for xip, and since we'd want regular refcounting in one scenario and we'd not want regular refcounting in the other, I don't see an easy way. And walking a list of ranges to figure out is definetly too slow.

Quoted 2 lines

What would pfn_to_page() return if the associated
struct page entry was not initialized?

A pointer to the entry that is not initialized.

Quoted 2 lines

Can we use what is returned to
check if the pfn has no page?

As far as I undstand Heiko's vmem_map magic, when we do access the vmem_map array to check, a struct page entry is created as reaction to the page fault. Therefore, this scenario gets us back the disatvantage of having struct page in the first place: memory consumption.

I think pfn_valid() or pfn_has_page() or similar arch callback does'nt work. We need a place to store the information whether or not a page needs refcounting or not. Either in the pte, or in vm_area_struct.

--
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>

#16 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

In reply to Jared Hulbert
Quoted 3 lines · Jared Hulbert

I'm not picturing what is responsible for configuring this stored pfn range. Does the fs do it on mount? Does the MTD or your funky direct_access block driver do it?

We could set it up at mmap() time, where we do set VM_MIXEDMAP alltogehter.

--
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>

#17 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

In reply to Carsten Otte
Quoted 7 lines · Carsten Otte
Quoted 2 lines · Carsten Otte

So bottom line I think we do need a different trigger then pfn_valid() to select which pages within VM_MIXEDMAP get refcounted and which don't.

A poor man's solution could be, to store a pfn range of the flash chip and/or shared memory segment inside vm_area_struct, and in case of VM_MIXEDMAP we check if the pfn matches that range. If so: no refcounting. If not: regular refcounting. Is that an option?

Yeah, although I'd not particularly like to touch generic code for such a thing (except of course we could add an extra test to VM_MIXEDMAP, which would be a noop for all other architectures).

You wouldn't even need to store it in the vm_area_struct -- you could just set up eg. an rb tree of flash extents, and have a function that looks up that tree for you.

--
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>

#18 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 3 lines · Nick Piggin

You wouldn't even need to store it in the vm_area_struct -- you could just set up eg. an rb tree of flash extents, and have a function that looks up that tree for you.

We have a list aready, and I don't see the number of plugged extents get so large that rb tree saves us CPU cycles over a list implementation.
Martin Schwidefsky suggested to use a bit in the page table entry to prevent refcounting. fault() could set it up proper for xip pages. That would be way faster then walking a list. Would that be an option?

--
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>

#19 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 9 lines · Carsten Otte
Quoted 3 lines · Nick Piggin

You wouldn't even need to store it in the vm_area_struct -- you could just set up eg. an rb tree of flash extents, and have a function that looks up that tree for you.

We have a list aready, and I don't see the number of plugged extents get so large that rb tree saves us CPU cycles over a list implementation. Martin Schwidefsky suggested to use a bit in the page table entry to prevent refcounting. fault() could set it up proper for xip pages. That would be way faster then walking a list. Would that be an option?

I thought s390 was short on OS-available pte bits. There are a couple of other nice things to use them for, so I'd rather not for this if possible (it is not so critical if you can use a list, I would have thought)

--
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>

#20 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 3 lines · Nick Piggin

I thought s390 was short on OS-available pte bits. There are a couple of other nice things to use them for, so I'd rather not for this if possible (it is not so critical if you can use a list, I would have thought)

OS-available bits are only short for invalid ptes. For valid ptes however, there are quite a few spare.

--
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>

#21 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 7 lines · Carsten Otte
Quoted 4 lines · Nick Piggin

I thought s390 was short on OS-available pte bits. There are a couple of other
nice things to use them for, so I'd rather not for this if possible (it is not so critical if you can use a list, I would have thought)

OS-available bits are only short for invalid ptes. For valid ptes however, there are quite a few spare.

OK, that's good news for my lockless get_user_pages ;)

And also potentially good news for the whole vm_normal_page scheme... though I'd prefer to start simple (ie. don't use the pte bit, rather walk the list), and see if it works first.

But whatever you think I guess, either way it would go in arch specific code where your opinion outweighs mine ;)

--
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>

#22 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 8 lines · Nick Piggin

OK, that's good news for my lockless get_user_pages ;)

And also potentially good news for the whole vm_normal_page scheme... though I'd prefer to start simple (ie. don't use the pte bit, rather walk the list), and see if it works first.

But whatever you think I guess, either way it would go in arch specific code where your opinion outweighs mine ;)

You clearly overestimate my influence on Martin. I rather keep my fingers off the memory management backend there.
But either way, what we'd need is an arch callback that can map to pfn_valid() for ARM and maybe others, and that we could map different. I'll try to come up with a patch that implements such callback using list-walk for s390. Hopefully we can safely grab the list lock everywhere we need to check.
Btw: I will also continue to work on this next year, and take two weeks christmas vacation.

--
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>

#23 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

In reply to Carsten Otte
Quoted 10 lines · Carsten Otte
Quoted 1 line · Carsten Otte

I'll drill down deeper here to see why it does'nt work as expected...

Apparently pfn_valid() is true for our shared memory segment. The s390 implementation checks if the pfn is within max_pfn, which reflects the size of the kernel page table 1:1 mapping. If that is the case, we use one of our many magic instructions "lra" to ask our mmu if there is memory we can access at subject address. Both is true for our shared memory segment. Thus, the page gets refcounted regular on a struct page entry that is not initialized.

Quoted 4 lines

Even worse, changing the semantic of pfn_valid() on s390 to be false for shared segments is no option. We'll want to use the same memory segment for memory hotplug. And in that case we do want refcounting because it becomes regular linux memory.

So then you're back to needing struct pages again. Do you allocate them at hotplug time?

AFAIK, sparsemem keeps track of all sections for pfn_valid(), which would work. Any plans to convert s390 to it? ;)

--
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>

#24 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 2 lines · Nick Piggin

So then you're back to needing struct pages again. Do you allocate them at hotplug time?

They get allocated by cathing kernel page faults when accessing the mem_map array and filling in pages on demand. This happens at hotplug time, where we initialize the content of struct page.

Quoted 2 lines

AFAIK, sparsemem keeps track of all sections for pfn_valid(), which would work. Any plans to convert s390 to it? ;)

I think vmem_map is superior to sparsemem, because a single-dimensional mem_map array is faster work with (single step lookup). And we've got plenty of virtual address space for the vmem_map array on 64bit.

--
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>

#25 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 6 lines · Carsten Otte
Quoted 2 lines · Nick Piggin

So then you're back to needing struct pages again. Do you allocate them at hotplug time?

They get allocated by cathing kernel page faults when accessing the mem_map array and filling in pages on demand. This happens at hotplug time, where we initialize the content of struct page.

Yep OK.

Quoted 6 lines
Quoted 2 lines

AFAIK, sparsemem keeps track of all sections for pfn_valid(), which would work. Any plans to convert s390 to it? ;)

I think vmem_map is superior to sparsemem, because a single-dimensional mem_map array is faster work with (single step lookup). And we've got plenty of virtual address space for the vmem_map array on 64bit.

But it doesn't still retain sparsemem sections behind that? Ie. so that pfn_valid could be used? (I admittedly don't know enough eabout the memory model code).

--
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>

#26 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 7 lines · Nick Piggin
Quoted 3 lines
Quoted 2 lines

AFAIK, sparsemem keeps track of all sections for pfn_valid(), which would work. Any plans to convert s390 to it? ;)

I think vmem_map is superior to sparsemem, because a single-dimensional mem_map array is faster work with (single step lookup). And we've got plenty of virtual address space for the vmem_map array on 64bit.

But it doesn't still retain sparsemem sections behind that? Ie. so that pfn_valid could be used? (I admittedly don't know enough eabout the memory model code).

Not as far as I know. But arch/s390/mm/vmem.c has:

struct memory_segment {
        struct list_head list;
        unsigned long start;
        unsigned long size;
};

static LIST_HEAD(mem_segs);

This is maintained every time we map a segment/unmap a segment. And we could add a bit to struct memory_segment meaning "refcount this one". This way, we could tell core mm whether or not a pfn should be refcounted.

--
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>

#27 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Quoted 19 lines · Carsten Otte
Quoted 10 lines · Nick Piggin
Quoted 6 lines
Quoted 2 lines

AFAIK, sparsemem keeps track of all sections for pfn_valid(), which would work. Any plans to convert s390 to it? ;)

I think vmem_map is superior to sparsemem, because a single-dimensional mem_map array is faster work with (single step lookup). And we've got plenty of virtual address space for the vmem_map array on 64bit.

But it doesn't still retain sparsemem sections behind that? Ie. so that pfn_valid could be used? (I admittedly don't know enough eabout the memory model code).

Not as far as I know. But arch/s390/mm/vmem.c has:

struct memory_segment {
        struct list_head list;
        unsigned long start;
        unsigned long size;
};
Quoted 5 lines

static LIST_HEAD(mem_segs);

This is maintained every time we map a segment/unmap a segment. And we could add a bit to struct memory_segment meaning "refcount this one". This way, we could tell core mm whether or not a pfn should be refcounted.

Right, this should work.

BTW. having a per-arch function sounds reasonable for a start. I'd just give it a long name, so that people don't start using it for weird things ;) mixedmap_refcount_pfn() or something.

--
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>

#28 lore raw

Re: [rfc][patch 2/2] xip: support non-struct page memory

Nick Piggin <[email protected]> wrote on 12/21/2007 11:47:01 AM:

Quoted 3 lines · Carsten Otte
Quoted 2 lines
Quoted 1 line · Nick Piggin

But it doesn't still retain sparsemem sections behind that? Ie. so

that

Quoted 1 line
Quoted 1 line
Quoted 1 line

pfn_valid could be used? (I admittedly don't know enough eabout the

memory

Quoted 9 lines
Quoted 9 lines
Quoted 1 line

model code).

Not as far as I know. But arch/s390/mm/vmem.c has:

struct memory_segment {
        struct list_head list;
        unsigned long start;
        unsigned long size;
};
Quoted 5 lines
Quoted 5 lines

static LIST_HEAD(mem_segs);

This is maintained every time we map a segment/unmap a segment. And we could add a bit to struct memory_segment meaning "refcount this one". This way, we could tell core mm whether or not a pfn should be

refcounted.

Quoted 4 lines

Right, this should work.

BTW. having a per-arch function sounds reasonable for a start. I'd just

give

Quoted 2 lines

it a long name, so that people don't start using it for weird things ;) mixedmap_refcount_pfn() or something.

Hmm, I would prefer to have a pte bit, it seem much more natural to me. We know that this is a special pte when it gets mapped, but we "forgot" that fact when the pte is picked up again in vm_normal_page. To search a list when a simple bit in the pte get the job done just feels wrong. By the way, for s390 the lower 8 bits of the pte are OS defined. The lowest two bits are used in addition to the hardware invalid and the hardware read-
only bit to define the pte type. For valid ptes the remaining 6 bits are unused. Pick one, e.g. 2**2 for the bit that says "don't-refcount-this-pte".

blue skies,
Martin

--
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>

#29 lore raw

RFC PATCH 1/1 mm: use a pte bit to flag normal pages

Quoted 30 lines · Martin Schwidefsky

Nick Piggin <[email protected]> wrote on 12/21/2007 11:47:01 AM:

Quoted 3 lines · Carsten Otte
Quoted 2 lines
Quoted 1 line · Nick Piggin

But it doesn't still retain sparsemem sections behind that? Ie. so

that

Quoted 1 line
Quoted 1 line
Quoted 1 line

pfn_valid could be used? (I admittedly don't know enough eabout the

memory

Quoted 9 lines
Quoted 9 lines
Quoted 1 line

model code).

Not as far as I know. But arch/s390/mm/vmem.c has:

struct memory_segment {
        struct list_head list;
        unsigned long start;
        unsigned long size;
};
Quoted 5 lines
Quoted 5 lines

static LIST_HEAD(mem_segs);

This is maintained every time we map a segment/unmap a segment. And we could add a bit to struct memory_segment meaning "refcount this one". This way, we could tell core mm whether or not a pfn should be

refcounted.

Quoted 4 lines

Right, this should work.

BTW. having a per-arch function sounds reasonable for a start. I'd just

give

Quoted 2 lines

it a long name, so that people don't start using it for weird things ;) mixedmap_refcount_pfn() or something.

Quoted 10 lines

Hmm, I would prefer to have a pte bit, it seem much more natural to me. We know that this is a special pte when it gets mapped, but we "forgot" that fact when the pte is picked up again in vm_normal_page. To search a list when a simple bit in the pte get the job done just feels wrong. By the way, for s390 the lower 8 bits of the pte are OS defined. The lowest two bits are used in addition to the hardware invalid and the hardware read-
only bit to define the pte type. For valid ptes the remaining 6 bits are unused. Pick one, e.g. 2**2 for the bit that says "don't-refcount-this-pte".

This would be nice if we can do it, although I would prefer to make everything work without any pte bits first, in order to make sure all architectures have a chance at implementing it (although I guess for s390 specific memory map stuff, it is reasonable for you to do your own thing there...).

We initially wanted to do the whole vm_normal_page thing this way, with another pte bit, but we thought there were one or two archs with no spare bits. BTW. I also need this bit in order to implement my lockless get_user_pages, so I do hope to get it in. I'd like to know what architectures cannot spare a software bit in their pte_present ptes...

---

Rather than play interesting games with vmas to work out whether the mapped page should be refcounted or not, use a new bit in the "present" pte to distinguish such pages.

This allows much simpler "vm_normal_page" implementation, and more flexible rules for COW pages in pfn mappings (eg. our proposed VM_MIXEDMAP mode would becomes a noop). It also provides one of the required pieces for the lockless get_user_pages.

Unfortunately, maybe not all architectures can spare a bit in the pte for this. So we probably have to end up with some ifdefs (if we even want to add this approach at all). For this reason, I would prefer for now to avoid using a new pte bit to implement any of this stuff, and get VM_MIXEDMAP and its callers working nicely on all architectures first.

Thanks,
Nick

---

include/asm-powerpc/pgtable-ppc64.h +5 -1
Index: linux-2.6/include/asm-powerpc/pgtable-ppc64.h
===================================================================
@@ -93,6 +93,7 @@
 #define _PAGE_RW	0x0200 /* software: user write access allowed */
 #define _PAGE_HASHPTE	0x0400 /* software: pte has an associated HPTE */
 #define _PAGE_BUSY	0x0800 /* software: PTE & hash are busy */
+#define _PAGE_SPECIAL	0x1000 /* software: pte associated with special page */
 
 #define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
 
@@ -233,12 +234,13 @@ static inline pte_t pfn_pte(unsigned lon
 
 /*
  * The following only work if pte_present() is true.
- * Undefined behaviour if not..
+ * Undefined behaviour if not.. (XXX: comment wrong eg. for pte_file())
  */
 static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
 static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -257,6 +259,8 @@ static inline pte_t pte_mkyoung(pte_t pt
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkhuge(pte_t pte) {
 	return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+	pte_val(pte) |= _PAGE_SPECIAL; return pte; }
 
 /* Atomic PTE updates */
 static inline unsigned long pte_update(struct mm_struct *mm,
include/asm-um/pgtable.h +12 -0
Index: linux-2.6/include/asm-um/pgtable.h
===================================================================
@@ -21,6 +21,7 @@
 #define _PAGE_USER	0x040
 #define _PAGE_ACCESSED	0x080
 #define _PAGE_DIRTY	0x100
+#define _PAGE_SPECIAL	0x200
 /* If _PAGE_PRESENT is clear, we use these: */
 #define _PAGE_FILE	0x008	/* nonlinear file mapping, saved PTE; unset:swap */
 #define _PAGE_PROTNONE	0x010	/* if the user mapped it with PROT_NONE;
@@ -220,6 +221,11 @@ static inline int pte_newprot(pte_t pte)
 	return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT)));
 }
 
+static inline int pte_special(pte_t pte)
+{
+	return pte_get_bits(pte, _PAGE_SPECIAL);
+}
+
 /*
  * =================================
  * Flags setting section.
@@ -288,6 +294,12 @@ static inline pte_t pte_mknewpage(pte_t 
 	return(pte);
 }
 
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	pte_set_bits(pte, _PAGE_SPECIAL);
+	return(pte);
+}
+
 static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
 	pte_copy(*pteptr, pteval);
include/asm-x86/pgtable_32.h +4 -0
Index: linux-2.6/include/asm-x86/pgtable_32.h
===================================================================
@@ -102,6 +102,7 @@ void paging_init(void);
 #define _PAGE_BIT_UNUSED2	10
 #define _PAGE_BIT_UNUSED3	11
 #define _PAGE_BIT_NX		63
+#define _PAGE_BIT_SPECIAL	_PAGE_BIT_UNUSED1
 
 #define _PAGE_PRESENT	0x001
 #define _PAGE_RW	0x002
@@ -115,6 +116,7 @@ void paging_init(void);
 #define _PAGE_UNUSED1	0x200	/* available for programmer */
 #define _PAGE_UNUSED2	0x400
 #define _PAGE_UNUSED3	0x800
+#define _PAGE_SPECIAL	PAGE_UNUSED1
 
 /* If _PAGE_PRESENT is clear, we use these: */
 #define _PAGE_FILE	0x040	/* nonlinear file mapping, saved PTE; unset:swap */
@@ -219,6 +221,7 @@ static inline int pte_dirty(pte_t pte)		
 static inline int pte_young(pte_t pte)		{ return (pte).pte_low & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)		{ return (pte).pte_low & _PAGE_RW; }
 static inline int pte_huge(pte_t pte)		{ return (pte).pte_low & _PAGE_PSE; }
+static inline int pte_special(pte_t pte)	{ return (pte).pte_low & _PAGE_SPECIAL; }
 
 /*
  * The following only works if pte_present() is not true.
@@ -232,6 +235,7 @@ static inline pte_t pte_mkdirty(pte_t pt
 static inline pte_t pte_mkyoung(pte_t pte)	{ (pte).pte_low |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ (pte).pte_low |= _PAGE_RW; return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)	{ (pte).pte_low |= _PAGE_PSE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ (pte).pte_low |= _PAGE_SPECIAL; return pte; }
 
 #ifdef CONFIG_X86_PAE
 # include <asm/pgtable-3level.h>
include/asm-x86/pgtable_64.h +4 -0
Index: linux-2.6/include/asm-x86/pgtable_64.h
===================================================================
@@ -151,6 +151,7 @@ static inline pte_t ptep_get_and_clear_f
 #define _PAGE_BIT_DIRTY		6
 #define _PAGE_BIT_PSE		7	/* 4 MB (or 2MB) page */
 #define _PAGE_BIT_GLOBAL	8	/* Global TLB entry PPro+ */
+#define _PAGE_BIT_SPECIAL	9
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
 #define _PAGE_PRESENT	0x001
@@ -163,6 +164,7 @@ static inline pte_t ptep_get_and_clear_f
 #define _PAGE_PSE	0x080	/* 2MB page */
 #define _PAGE_FILE	0x040	/* nonlinear file mapping, saved PTE; unset:swap */
 #define _PAGE_GLOBAL	0x100	/* Global TLB entry */
+#define _PAGE_SPECIAL	0x200
 
 #define _PAGE_PROTNONE	0x080	/* If not present */
 #define _PAGE_NX        (_AC(1,UL)<<_PAGE_BIT_NX)
@@ -272,6 +274,7 @@ static inline int pte_young(pte_t pte)		
 static inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_RW; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_huge(pte_t pte)		{ return pte_val(pte) & _PAGE_PSE; }
+static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
@@ -282,6 +285,7 @@ static inline pte_t pte_mkyoung(pte_t pt
 static inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_PSE)); return pte; }
 static inline pte_t pte_clrhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_PSE)); return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SPECIAL)); return pte; }
 
 struct vm_area_struct;
 
include/linux/mm.h +14 -1
Index: linux-2.6/include/linux/mm.h
===================================================================
@@ -698,7 +698,20 @@ struct zap_details {
 	unsigned long truncate_count;		/* Compare vm_truncate_count */
 };
 
-struct page *vm_normal_page(struct vm_area_struct *, unsigned long, pte_t);
+/*
+ * This function gets the "struct page" associated with a pte.
+ *
+ * "Special" mappings do not wish to be associated with a "struct page" (either
+ * it doesn't exist, or it exists but they don't want to touch it). In this
+ * case, NULL is returned here.
+ */
+static inline struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+	if (likely(!pte_special(pte)))
+		return pte_page(pte);
+	return NULL;
+}
+
 unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size, struct zap_details *);
 unsigned long unmap_vmas(struct mmu_gather **tlb,
mm/memory.c +2 -81

117 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>

#30 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 5 lines · Nick Piggin

We initially wanted to do the whole vm_normal_page thing this way, with another pte bit, but we thought there were one or two archs with no spare bits. BTW. I also need this bit in order to implement my lockless get_user_pages, so I do hope to get it in. I'd like to know what architectures cannot spare a software bit in their pte_present ptes...

ARM is going to have to use the three remaining bits we have in the PTE to store the memory type to resolve bugs on later platforms. Once they're used, ARM will no longer have any room for any further PTE expansion.

Signature · 9 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

--
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>
#31 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 10 lines · Russell King
Quoted 5 lines · Nick Piggin

We initially wanted to do the whole vm_normal_page thing this way, with another pte bit, but we thought there were one or two archs with no spare bits. BTW. I also need this bit in order to implement my lockless get_user_pages, so I do hope to get it in. I'd like to know what architectures cannot spare a software bit in their pte_present ptes...

ARM is going to have to use the three remaining bits we have in the PTE to store the memory type to resolve bugs on later platforms. Once they're used, ARM will no longer have any room for any further PTE expansion.

OK, it is good to have a negative confirmed. So I think we should definitely get the non-pte-bit based mapping schemes working and tested on all platforms before using a pte bit mapping...

FWIW, it might be possible for platforms to implement lockless get_user_pages in other ways too. But that's getting ahead of myself.

Thanks.

--
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>

#32 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

In reply to Russell King
Quoted 3 lines

ARM is going to have to use the three remaining bits we have in the PTE to store the memory type to resolve bugs on later platforms. Once they're used, ARM will no longer have any room for any further PTE expansion.

Russell,

Can you explain this a little more.

--
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>

#33 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 7 lines · Jared Hulbert
Quoted 3 lines

ARM is going to have to use the three remaining bits we have in the PTE to store the memory type to resolve bugs on later platforms. Once they're used, ARM will no longer have any room for any further PTE expansion.

Russell,

Can you explain this a little more.

In old ARM CPUs, there were two bits that defined the characteristics of the mapping - the C and B bits (C = cacheable, B = bufferable)

Some ARMv5 (particularly Xscale-based) and all ARMv6 CPUs extend this to five bits and introduce "memory types" - 3 bits of TEX, and C and B.

Between these bits, it defines:

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Of course, not all CPUs support all the above - for example, if write back caches aren't supported then the result is a write through cache. The write allocation setting is a "hint" - if the hardware doesn't support write allocate, it'll just be read allocate.

There are now CPUs out there where the old combinations (TEX=0) are broken - and causes nasty effects like writes to bypass the write protection under certain circumstances, or the data cache to hang if you're using a strongly ordered mapping.

The "workaround" for these is to avoid the problematical mapping mode - which is CPU specific, and depends on knowledge of what's being mapped. For instance, you might use a sharable device mapping instead of strongly ordered for devices. However, you might want to use an outer cacheable but inner uncacheable mapping instead of strongly ordered for memory.

Now, couple this with the fix for shared mmaps - where we normally turn a cacheable mapping into a bufferable mapping, or if the write buffer has visible side effects, a strongly ordered mapping, or if strongly ordered mappings are buggy... etc.

Also note that there are devices (typically "unshared" devices) on some ARM CPUs that you can only access if you set the TEX bits correctly.

Currently, Linux is able to setup mappings in kernel space to cover any combination of settings. However, userspace is much more limited because we don't carry the additional bits around in the Linux version of the PTE - and as such shared mmaps on some systems can end up locking the CPU.

A few attempts have been made at solving these without using the additional PTE bits, but they've been less that robust.

Signature · 9 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

--
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>
#34 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 8 lines

Currently, Linux is able to setup mappings in kernel space to cover any combination of settings. However, userspace is much more limited because we don't carry the additional bits around in the Linux version of the PTE - and as such shared mmaps on some systems can end up locking the CPU.

A few attempts have been made at solving these without using the additional PTE bits, but they've been less that robust.

Do these new ARM implementations use more bits than most archs?

Most ARM implementations can spare a PTE bit for this, right? Is the use of these 3 extra bits to cover a few buggy processors or is this caused by consolidating the needs of widely differing architectures?

I just can't get over the idea that you _have_ use up all available bits. Oh well.

#35 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

In reply to Russell King
Quoted 10 lines

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Do you need all of those in user space? Perhaps you could give the bits different meanings depending on user or kernel space. I think Nick et.al. just need the bits for user space; they won't care about kernel mappings.

-Andi

--
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>

#36 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 11 lines · Andi Kleen
Quoted 10 lines

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Quoted 4 lines

Do you need all of those in user space? Perhaps you could give the bits different meanings depending on user or kernel space. I think Nick et.al. just need the bits for user space; they won't care about kernel mappings.

Yes correct -- they are only for userspace mappings. Though that includes mmaps of /dev/mem and device drivers etc.

--
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>

#37 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 12 lines · Nick Piggin
Quoted 11 lines · Andi Kleen
Quoted 10 lines

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Quoted 7 lines
Quoted 4 lines

Do you need all of those in user space? Perhaps you could give the bits different meanings depending on user or kernel space. I think Nick et.al. just need the bits for user space; they won't care about kernel mappings.

Yes correct -- they are only for userspace mappings. Though that includes mmaps of /dev/mem and device drivers etc.

/dev/mem can be always special cased by checking the VMA flags, can't it?

-Andi

--
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>

#38 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 18 lines · Andi Kleen
Quoted 17 lines · Nick Piggin
Quoted 15 lines · Andi Kleen
Quoted 10 lines

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Do you need all of those in user space? Perhaps you could give the bits different meanings depending on user or kernel space. I think Nick et.al. just need the bits for user space; they won't care about kernel mappings.

Quoted 4 lines
Quoted 2 lines

Yes correct -- they are only for userspace mappings. Though that includes mmaps of /dev/mem and device drivers etc.

/dev/mem can be always special cased by checking the VMA flags, can't it?

That's basically what we do today with COW support for VM_PFNMAP. Once you have that, I don't think there is a huge reason to _also_ use the pte bit for other mappings (because you need to have the VM_PFNMAP support there anyway).

For lockless get_user_pages, I don't take mmap_sem, look up any vmas, or even take any page table locks, so it doesn't help there either. (though in the case of lockless gup, architectues that cannot support it can simply revert to the regular gup).

--
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>

#39 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

In reply to Russell King
Quoted 8 lines · Russell King

In old ARM CPUs, there were two bits that defined the characteristics of the mapping - the C and B bits (C = cacheable, B = bufferable)

Some ARMv5 (particularly Xscale-based) and all ARMv6 CPUs extend this to five bits and introduce "memory types" - 3 bits of TEX, and C and B.

Between these bits, it defines:

Quoted 10 lines

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Can we not restrict these to a maximum of 8 base types at run-time? If yes, we can only use 3 bits for encoding and also benefit from the automatic remapping in later ARM CPUs. For those not familiar with ARM, 8 combinations of the TEX, C, B and S (shared) bits can be specified in separate registers and the pte would only use 3 bits to refer to those. Even older cores would benefit from this as I think it is faster to read the encoding from an array in set_pte than doing all the bit comparisons to calculate the hardware pte in the current implementation.

Signature · 7 lines
Catalin

--
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>
#40 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 20 lines · Catalin Marinas
Quoted 8 lines · Russell King

In old ARM CPUs, there were two bits that defined the characteristics of the mapping - the C and B bits (C = cacheable, B = bufferable)

Some ARMv5 (particularly Xscale-based) and all ARMv6 CPUs extend this to five bits and introduce "memory types" - 3 bits of TEX, and C and B.

Between these bits, it defines:

Quoted 10 lines

- strongly ordered
- bufferable only *
- device, sharable *
- device, unsharable
- memory, bufferable and cacheable, write through, no write allocate
- memory, bufferable and cacheable, write back, no write allocate
- memory, bufferable and cacheable, write back, write allocate
- implementation defined combinations (eg, selecting "minicache")
- and a set of 16 states to allow the policy of inner and outer levels of cache to be defined (two bits per level).

Quoted 8 lines

Can we not restrict these to a maximum of 8 base types at run-time? If yes, we can only use 3 bits for encoding and also benefit from the automatic remapping in later ARM CPUs. For those not familiar with ARM, 8 combinations of the TEX, C, B and S (shared) bits can be specified in separate registers and the pte would only use 3 bits to refer to those. Even older cores would benefit from this as I think it is faster to read the encoding from an array in set_pte than doing all the bit comparisons to calculate the hardware pte in the current implementation.

So basically that gives us the following combinations:

TEXCB
00000 - /dev/mem and device uncachable mappings (strongly ordered) 00001 - frame buffers
00010 - write through mappings (selectable via kernel command line)
and also work-around for user read-only write-back mappings on PXA2.
00011 - normal write back mappings
00101 - Xscale3 "shared device" work-around for strongly ordered mappings 00110 - PXA3 mini-cache or other "implementation defined features" 00111 - write back write allocate mappings
01000 - non-shared device (will be required to map some devices to userspace)
and also Xscale3 work-around for strongly ordered mappings
10111 - Xscale3 L2 cache-enabled mappings

It's unclear at present what circumstances you'd use each of the two Xscale3 work-around bit combinations - or indeed whether there's a printing error in the documentation concerning TEXCB=00101.

It's also unclear how to squeeze these down into a bit pattern in such a way that we avoid picking out bits from the Linux PTE, and recombining them so we can look them up in a table or whatever - especially given that set_pte is a fast path and extra cycles there have a VERY noticable impact on overall system performance.

However, until we get around to sorting out the implementation of the Xscale3 strongly ordered work-around which seems to be the highest priority (and hardest to resolve) I don't think there's much more to discuss; we don't have a clear way ahead on these issues at the moment. All we current have is the errata entry, and we know people are seeing data corruption on Xscale3 platforms.

And no, I don't think we can keep it contained within the Xscale3 support file - the set_pte method isn't passed sufficient information for that. Conversely, setting the TEX bits behind set_pte's back by using set_pte_ext results in loss of that information when the page is aged - again resulting in data corruption.

Signature · 9 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

--
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>
#41 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 11 lines · Russell King
Quoted 8 lines · Catalin Marinas

Can we not restrict these to a maximum of 8 base types at run-time? If yes, we can only use 3 bits for encoding and also benefit from the automatic remapping in later ARM CPUs. For those not familiar with ARM, 8 combinations of the TEX, C, B and S (shared) bits can be specified in separate registers and the pte would only use 3 bits to refer to those. Even older cores would benefit from this as I think it is faster to read the encoding from an array in set_pte than doing all the bit comparisons to calculate the hardware pte in the current implementation.

So basically that gives us the following combinations:

I reordered them a bit for easier commenting.

Quoted 6 lines

TEXCB
00010 - write through mappings (selectable via kernel command line)
and also work-around for user read-only write-back mappings on PXA2.
00011 - normal write back mappings
00111 - write back write allocate mappings

Do you need to use all of the above at the same time? We could have only one type, "normal memory", and configure the desired TEX encoding at boot time.

Quoted 5 lines

00000 - /dev/mem and device uncachable mappings (strongly ordered) 00101 - Xscale3 "shared device" work-around for strongly ordered mappings 01000 - non-shared device (will be required to map some devices to userspace)
and also Xscale3 work-around for strongly ordered mappings

I don't know the details of the Xscale3 bug but would you need all of these encodings at run-time? Do you need both "strongly ordered" and the workaround? We could only have the "strongly ordered" type and configure the TEX bits at boot time to be "shared device" if the workaround is needed.

For the last one, we could have the "non-shared device" type.

Quoted 1 line

00001 - frame buffers

This would be "shared device" on newer CPUs.

Quoted 2 lines

00110 - PXA3 mini-cache or other "implementation defined features" 10111 - Xscale3 L2 cache-enabled mappings

It depends on how many of these you would need at run-time. If the base types are "normal", "strongly ordered", "shared device", "non-shared device", you still have 4 more left (or 3 on ARMv6 with TEX remapping enabled since one encoding is implementation defined).

Quoted 3 lines

It's unclear at present what circumstances you'd use each of the two Xscale3 work-around bit combinations - or indeed whether there's a printing error in the documentation concerning TEXCB=00101.

As I said, I don't know the details of this bug and can't comment.

Quoted 5 lines

It's also unclear how to squeeze these down into a bit pattern in such a way that we avoid picking out bits from the Linux PTE, and recombining them so we can look them up in a table or whatever - especially given that set_pte is a fast path and extra cycles there have a VERY noticable impact on overall system performance.

As with the automatic remapping on ARMv6, we could use TEX[0], C and B to for the 3 bit index in the table. For pre-ARMv6 hardware, we need a bit of shifting and masking before looking up in the 8 32bit words table but, for subsequent calls to set_pte, it is likely that the table would be in cache anyway. There is also the option of choosing 3 consecutive bits to avoid shifting on pre-ARMv6.

I agree there would be a delay on pre-ARMv6 CPUs but the impact might not be that big since the current set_pte implementations still do additional bit shifting/comparison for the access permissions. The advantage is that we free 2 bits from the TEXCB encoding.

I haven't run any benchmarks and I can't say how big the impact is but, based on some past discussions, 3-4 more cycles in set_pte might go unnoticed because of other, bigger overheads.

Signature · 7 lines
Catalin

--
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>
#42 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 6 lines · Catalin Marinas
Quoted 3 lines · Russell King

It's unclear at present what circumstances you'd use each of the two Xscale3 work-around bit combinations - or indeed whether there's a printing error in the documentation concerning TEXCB=00101.

As I said, I don't know the details of this bug and can't comment.

As I said I don't think there's anything further that can be usefully added to this discussion until we're further down the road with this.

Even though you don't know the details of the bug report, I've mentioned as much as I know about it at present - and that includes with access to Marvells spec update document. When I'm further down the line with PXA3 work maybe I'll know more, but my priority at the moment on PXA3 is suspend/resume support.

Quoted 3 lines

I haven't run any benchmarks and I can't say how big the impact is but, based on some past discussions, 3-4 more cycles in set_pte might go unnoticed because of other, bigger overheads.

Except when you're clearing out page tables - for instance when a thread exits. It's very noticable and shows up rather well in fork+exit tests - even shell scripts.

This was certainly the case with 2.2 kernels. Whether 2.6 kernels are soo heavy weight that it's been swapped into non-existence I don't know.

Signature · 9 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:

--
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>
#43 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

In reply to Nick Piggin
Quoted 5 lines · Nick Piggin

We initially wanted to do the whole vm_normal_page thing this way, with another pte bit, but we thought there were one or two archs with no spare bits. BTW. I also need this bit in order to implement my lockless get_user_pages, so I do hope to get it in. I'd like to know what architectures cannot spare a software bit in their pte_present ptes...

I've been playing with the original PAGE_SPECIAL patch a little bit, and you can find the corresponding s390 definition below that you might want to add to your patch queue.
It is a little unclear to me, how you'd like to proceed from here:
- with PTE_SPECIAL, do we still have VM_MIXEDMAP or similar flag to distinguish our new type of mapping from VM_PFNMAP? Which vma flags are we supposed to use for xip mappings?
- does VM_PFNMAP work as before, or do you intend to replace it?
- what about vm_normal_page? Do you intend to have one per arch? The one proposed by this patch breaks Jared's pfn_valid() thing and VM_PFNMAP for archs that don't have PAGE_SPECIAL as far as I can tell.

---

include/asm-s390/pgtable.h +14 -0
Index: linux-2.6/include/asm-s390/pgtable.h
===================================================================
@@ -228,6 +228,7 @@ extern unsigned long vmalloc_end;
 /* Software bits in the page table entry */
 #define _PAGE_SWT	0x001		/* SW pte type bit t */
 #define _PAGE_SWX	0x002		/* SW pte type bit x */
+#define _PAGE_SPECIAL	0x004		/* SW associated with special page */
 
 /* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY	0x400
@@ -504,6 +505,12 @@ static inline int pte_file(pte_t pte)
 	return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
 }
 
+static inline int pte_special(pte_t pte)
+{
+	BUG_ON(!pte_present(pte));
+	return (pte_val(pte) & _PAGE_SPECIAL);
+}
+
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(a,b)  (pte_val(a) == pte_val(b))
 
@@ -654,6 +661,13 @@ static inline pte_t pte_mkyoung(pte_t pt
 	return pte;
 }
 
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	BUG_ON(!pte_present(pte));
+	pte_val(pte) |= _PAGE_SPECIAL;
+	return pte;
+}
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 					    unsigned long addr, pte_t *ptep)

--
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>

#44 lore raw

Re: [rfc][patch] mm: use a pte bit to flag normal pages

Quoted 6 lines · Carsten Otte
Quoted 5 lines · Nick Piggin

We initially wanted to do the whole vm_normal_page thing this way, with another pte bit, but we thought there were one or two archs with no spare bits. BTW. I also need this bit in order to implement my lockless get_user_pages, so I do hope to get it in. I'd like to know what architectures cannot spare a software bit in their pte_present ptes...

Quoted 7 lines

I've been playing with the original PAGE_SPECIAL patch a little bit, and you can find the corresponding s390 definition below that you might want to add to your patch queue.
It is a little unclear to me, how you'd like to proceed from here:
- with PTE_SPECIAL, do we still have VM_MIXEDMAP or similar flag to distinguish our new type of mapping from VM_PFNMAP? Which vma flags are we supposed to use for xip mappings?

We should not need anything in the VMA, because the vm can get all the required information from the pte. However, we still need to keep the MIXEMAP and PFNMAP stuff around for architectures that don't provide a pte_special.

Quoted 1 line

- does VM_PFNMAP work as before, or do you intend to replace it?

PFNMAP can be replaced with pte_special as well. They are all schemes used to exempt a pte from having its struct page refcounted... if we use a bit per pte, then we need nothing else.

Quoted 3 lines

- what about vm_normal_page? Do you intend to have one per arch? The one proposed by this patch breaks Jared's pfn_valid() thing and VM_PFNMAP for archs that don't have PAGE_SPECIAL as far as I can tell.

I think just have 2 in the core code. Switched by ifdef. I'll work on a more polished patch for that.

Quoted 32 lines

---
Index: linux-2.6/include/asm-s390/pgtable.h
===================================================================

include/asm-s390/pgtable.h +7 -0
@@ -228,6 +228,7 @@ extern unsigned long vmalloc_end;
 /* Software bits in the page table entry */
 #define _PAGE_SWT	0x001		/* SW pte type bit t */
 #define _PAGE_SWX	0x002		/* SW pte type bit x */
+#define _PAGE_SPECIAL	0x004		/* SW associated with special page */
 
 /* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY	0x400
@@ -504,6 +505,12 @@ static inline int pte_file(pte_t pte)
 	return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
 }
 
+static inline int pte_special(pte_t pte)
+{
+	BUG_ON(!pte_present(pte));
+	return (pte_val(pte) & _PAGE_SPECIAL);
+}
+
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(a,b)  (pte_val(a) == pte_val(b))
 
@@ -654,6 +661,13 @@ static inline pte_t pte_mkyoung(pte_t pt
 	return pte;
 }
 

include/asm-s390/pgtable.h static inline pte_t pte_mkyoung(pte_t pt · line 673

Quoted 10 lines
include/asm-s390/pgtable.h +7 -0
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	BUG_ON(!pte_present(pte));
+	pte_val(pte) |= _PAGE_SPECIAL;
+	return pte;
+}
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 					    unsigned long addr, pte_t *ptep)

--
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>

#45 lore raw

cover VM_MIXEDMAP patchset with s390 backend

In reply to Nick Piggin

Am Freitag, den 21.12.2007, 11:47 +0100 schrieb Nick Piggin:

Quoted 3 lines

BTW. having a per-arch function sounds reasonable for a start. I'd just give it a long name, so that people don't start using it for weird things ;) mixedmap_refcount_pfn() or something.

Based on our previous discussion, and based on previous patches by Jared and Nick, this patch series makes XIP without struct page backing usable on s390 architecture.
This patch set includes:
1/4: mm: introduce VM_MIXEDMAP mappings from Jared Hulbert, modified to use an arch-callback to identify whether or not a pfn needs refcounting 2/4: xip: support non-struct page memory from Nick Piggin, modified to use an arch-callback to identify whether or not a pfn needs refcounting 3/4: s390: remove struct page entries for z/VM DCSS memory segments 4/4: s390: proof of concept implementation of mixedmap_refcount_pfn() for s390 using list-walk

Above stack seems to work well, I did some sniff-testing applied on top of Linus' current git tree. We do want to spend a precious pte bit to speed up this callback, therefore patch 4/4 will get replaced.

--
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>

#46 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 4 lines · Carsten Otte

Am Freitag, den 21.12.2007, 11:47 +0100 schrieb Nick Piggin:

Quoted 3 lines

BTW. having a per-arch function sounds reasonable for a start. I'd just give it a long name, so that people don't start using it for weird things ;) mixedmap_refcount_pfn() or something.

Quoted 11 lines

Based on our previous discussion, and based on previous patches by Jared and Nick, this patch series makes XIP without struct page backing usable on s390 architecture.
This patch set includes:
1/4: mm: introduce VM_MIXEDMAP mappings from Jared Hulbert, modified to use an arch-callback to identify whether or not a pfn needs refcounting 2/4: xip: support non-struct page memory from Nick Piggin, modified to use an arch-callback to identify whether or not a pfn needs refcounting 3/4: s390: remove struct page entries for z/VM DCSS memory segments 4/4: s390: proof of concept implementation of mixedmap_refcount_pfn() for s390 using list-walk

Nice! I'm glad that the xip support didn't need anything further than the mixedmap_refcount_pfn for s390. Hopefully it proves to be stable under further testing.

I'm just curious (or forgetful) as to why s390's pfn_valid does not walk your memory segments? (That would allow the s390 proof of concept to be basically a noop, and mixedmap_refcount_pfn will only be required when we start using another pte bit.

Quoted 3 lines

Above stack seems to work well, I did some sniff-testing applied on top of Linus' current git tree. We do want to spend a precious pte bit to speed up this callback, therefore patch 4/4 will get replaced.

I think using another bit in the pte for special mappings is reasonable. As I posted in my earlier patch, we can also use it to simplify vm_normal_page, and it facilitates a lock free get_user_pages.

Anyway, hmm... I guess we should probably get these patches into -mm and then upstream soon. Any objections from anyone? Do you guys have performance / stress testing for xip?

--
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>

#47 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 4 lines · Nick Piggin

I'm just curious (or forgetful) as to why s390's pfn_valid does not walk your memory segments? (That would allow the s390 proof of concept to be basically a noop, and mixedmap_refcount_pfn will only be required when we start using another pte bit.

Our pfn_valid uses a hardware instruction, which does check if there is memory behind a pfn which we can access. And we'd like to use the very same memory segment for both regular memory hotplug where the memory ends up in ZONE_NORMAL (in this case the memory would be read+write, and not shared with other guests), and for backing xip file systems (in this case the memory would be read-only, and shared). And in both cases, our instruction does consider the pfn to be valid. Thus, pfn_valid is not the right indicator for us to check if we need refcounting or not.

Quoted 3 lines

I think using another bit in the pte for special mappings is reasonable. As I posted in my earlier patch, we can also use it to simplify vm_normal_page, and it facilitates a lock free get_user_pages.

That patch looks very nice. I am going to define PTE_SPECIAL for s390 arch next...

Quoted 3 lines

Anyway, hmm... I guess we should probably get these patches into -mm and then upstream soon. Any objections from anyone? Do you guys have performance / stress testing for xip?

I think it is mature enough to push upstream, I've booted a distro with /usr on it. But I really really want to exchange patch #4 with a pte-bit based one before pushing this.

--
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>

#48 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 5 lines · Carsten Otte
Quoted 4 lines · Nick Piggin

I'm just curious (or forgetful) as to why s390's pfn_valid does not walk your memory segments? (That would allow the s390 proof of concept to be basically a noop, and mixedmap_refcount_pfn will only be required when we start using another pte bit.

Quoted 9 lines

Our pfn_valid uses a hardware instruction, which does check if there is memory behind a pfn which we can access. And we'd like to use the very same memory segment for both regular memory hotplug where the memory ends up in ZONE_NORMAL (in this case the memory would be read+write, and not shared with other guests), and for backing xip file systems (in this case the memory would be read-only, and shared). And in both cases, our instruction does consider the pfn to be valid. Thus, pfn_valid is not the right indicator for us to check if we need refcounting or not.

Sure, but I think pfn_valid is _supposed_ to indicate whether the pfn has a struct page, isn't it? I think that is the case with the other standard memory models. That would make it applicable for you (ie. if it were implemented as mixedmap_refcount_pfn).

Is it used in any performance critical paths that it needs to be really fast?

(Anyway, this is just an aside -- I have no real problem with mixedmap_refcount_pfn, or using a special pte bit...)

Quoted 6 lines
Quoted 4 lines

I think using another bit in the pte for special mappings is reasonable. As I posted in my earlier patch, we can also use it to simplify vm_normal_page,
and it facilitates a lock free get_user_pages.

That patch looks very nice. I am going to define PTE_SPECIAL for s390 arch next...

Great.

Quoted 6 lines
Quoted 4 lines

Anyway, hmm... I guess we should probably get these patches into -mm and then upstream soon. Any objections from anyone? Do you guys have performance /
stress testing for xip?

I think it is mature enough to push upstream, I've booted a distro with /usr on it.

Oh good. So just to clarify -- I guess you guys have a readonly filesystem containing the distro on the host, and mount it XIP on each guest... avoiding struct page means you save a bit of memory on each guest?

Quoted 2 lines

But I really really want to exchange patch #4 with a pte-bit based one before pushing this.

OK fair enough, let's do that.

--
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>

#49 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 3 lines · Nick Piggin

Oh good. So just to clarify -- I guess you guys have a readonly filesystem containing the distro on the host, and mount it XIP on each guest... avoiding struct page means you save a bit of memory on each guest?

That's right. It's quite a bit of memory for struct page entries, because we'd love to have an entire distro with a superset of packages for each guest being installed on the filesystem (-- large shared segment). And we're talking 3 digits amount of guests here. This is a real benefit in our scenario.

Quoted 2 lines
Quoted 1 line

But I really really want to exchange patch #4 with a pte-bit based one before pushing this.

OK fair enough, let's do that.

Thanks, am on it...

--
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>

#50 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

In reply to Carsten Otte
Quoted 3 lines · Carsten Otte

That patch looks very nice. I am going to define PTE_SPECIAL for s390 arch next...

"PTE_SPECIAL" does not sound too descriptive. Maybe PTE_MIXEDMAP? It may not be great, but at least it give a hint in the right direction.

JA?rn

Signature · 8 lines
Good warriors cause others to come to them and do not go to others.
-- Sun Tzu

--
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>
#51 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 2 lines · JA?rn Engel

"PTE_SPECIAL" does not sound too descriptive. Maybe PTE_MIXEDMAP? It may not be great, but at least it give a hint in the right direction.

True, I've chosen a different name. PTE_SPECIAL is the name in Nick's original patch (see patch in this thread).

--
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>

#52 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 5 lines
Quoted 2 lines · Jorn Engel

"PTE_SPECIAL" does not sound too descriptive. Maybe PTE_MIXEDMAP? It may not be great, but at least it give a hint in the right direction.

True, I've chosen a different name. PTE_SPECIAL is the name in Nick's original patch (see patch in this thread).

Nick also want's to use that bit to "implement my lockless get_user_page" I assume that's why the name is a little vague.

--
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>

#53 lore raw

Re: [rfc][patch 0/4] VM_MIXEDMAP patchset with s390 backend

Quoted 8 lines · Jared Hulbert
Quoted 5 lines
Quoted 2 lines · Jorn Engel

"PTE_SPECIAL" does not sound too descriptive. Maybe PTE_MIXEDMAP? It may not be great, but at least it give a hint in the right direction.

True, I've chosen a different name. PTE_SPECIAL is the name in Nick's original patch (see patch in this thread).

Nick also want's to use that bit to "implement my lockless get_user_page" I assume that's why the name is a little vague.

Yeah, and to simplify vm_normal_page on those architectures which provide it. So it isn't just for VM_MIXEDMAP mappings (unless you're implementing a bit specifically for that as an s390 specific thing -- which is reasonable for now).

We have 2 types of user mappings in the VM; "normal" and not-normal. I don't think the latter have a name, so I call them special. If you're used to "normal" then I think special is descriptive enough ;)

--
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>

#54 lore raw

cover VM_MIXEDMAP patchset with s390 backend v2

In reply to Carsten Otte

This patchset is an improved version of yesterday's patchset, which does contain the following patches:

1/4: add arch callbacks to toggle reference counting for VM_MIXEDMAP pages
2/4: patch from Jared Hulbert that introduces VM_MIXEDMAP 3/4: patch from Nick Piggin, which uses VM_MIXEDMAP for XIP mappings 4/4: remove struct page entries for z/VM DCSS memory segments

This patch series is tested on top of Linus' git tree with ext2 -o xip and dcssblk on s390x.

--
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>

A message that is not in the archive (sent off-list or not yet received): [email protected]

#56 lore raw

RFC PATCH 1/4 include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

This patch introduces two arch callbacks, which may optionally be implemented in case the architecutre does define __HAVE_ARCH_PTEP_NOREFCOUNT.

The first callback, pte_set_norefcount(__pte) is called by core-vm to indicate that subject page table entry is going to be inserted into a VM_MIXEDMAP vma.
default implementation: noop
s390 implementation: set sw defined bit in pte
proposed arm implementation: noop

The second callback, mixedmap_refcount_pte(__pte) is called by core-vm to figure out whether or not subject pte requires reference counting in the corresponding struct page entry. A non-zero result indicates reference counting is required.
default implementation: (1)
s390 implementation: query sw defined bit in pte
proposed arm implementation: convert pte_t to pfn, use pfn_valid()

---

include/asm-generic/pgtable.h +5 -0
Index: linux-2.6/include/asm-generic/pgtable.h
===================================================================
@@ -99,6 +99,11 @@ static inline void ptep_set_wrprotect(st
 }
 #endif
 
+#ifndef __HAVE_ARCH_PTEP_NOREFCOUNT
+#define pte_set_norefcount(__pte)	(__pte)
+#define mixedmap_refcount_pte(__pte) 	(1)
+#endif
+
 #ifndef __HAVE_ARCH_PTE_SAME
 #define pte_same(A,B)	(pte_val(A) == pte_val(B))
 #endif
include/asm-s390/pgtable.h +9 -0
Index: linux-2.6/include/asm-s390/pgtable.h
===================================================================
@@ -228,6 +228,7 @@ extern unsigned long vmalloc_end;
 /* Software bits in the page table entry */
 #define _PAGE_SWT	0x001		/* SW pte type bit t */
 #define _PAGE_SWX	0x002		/* SW pte type bit x */
+#define _PAGE_NOREFCNT	0x004		/* SW prevent refcount for xip */
 
 /* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY	0x400
@@ -773,6 +774,14 @@ static inline pte_t ptep_get_and_clear_f
 	__changed;							\
 })
 
+#define __HAVE_ARCH_PTEP_NOREFCOUNT
+#define pte_set_norefcount(__pte)					\
+({									\
+	pte_val(__pte) |= _PAGE_NOREFCNT;				\
+	__pte;								\
+})
+#define mixedmap_refcount_pte(__pte)	(!(pte_val(__pte) & _PAGE_NOREFCNT))
+
 /*
  * Test and clear dirty bit in storage key.
  * We can't clear the changed bit atomically. This is a potential

--
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>

Acked-by on v1 1/4
#57 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 19 lines · Carsten Otte

include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

This patch introduces two arch callbacks, which may optionally be implemented in case the architecutre does define __HAVE_ARCH_PTEP_NOREFCOUNT.

The first callback, pte_set_norefcount(__pte) is called by core-vm to indicate that subject page table entry is going to be inserted into a VM_MIXEDMAP vma.
default implementation: noop
s390 implementation: set sw defined bit in pte
proposed arm implementation: noop

The second callback, mixedmap_refcount_pte(__pte) is called by core-vm to figure out whether or not subject pte requires reference counting in the corresponding struct page entry. A non-zero result indicates reference counting is required.
default implementation: (1)
s390 implementation: query sw defined bit in pte
proposed arm implementation: convert pte_t to pfn, use pfn_valid()

Quoted 1 line

For the s390 pieces of this patch:

Signature · 11 lines
blue skies,
  Martin.

"Reality continues to ruin my life." - Calvin.


--
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>
#58 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

In reply to Carsten Otte
Quoted 13 lines · Carsten Otte

From: Carsten Otte <[email protected]>

include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

This patch introduces two arch callbacks, which may optionally be implemented in case the architecutre does define __HAVE_ARCH_PTEP_NOREFCOUNT.

The first callback, pte_set_norefcount(__pte) is called by core-vm to indicate that subject page table entry is going to be inserted into a VM_MIXEDMAP vma.

default implementation:         noop
s390 implementation:            set sw defined bit in pte
proposed arm implementation:    noop
Quoted 5 lines

The second callback, mixedmap_refcount_pte(__pte) is called by core-vm to figure out whether or not subject pte requires reference counting in the corresponding struct page entry. A non-zero result indicates reference counting is required.
default implementation: (1)

I think this should be:

default implementation: convert pte_t to pfn, use pfn_valid()

Keep in mind the reason we are talking about using anything other than pfn_valid() in vm_normal_page() is because s390 has a non-standard pfn_valid() implementation. It's s390 that's broken, not the rest of the world. So lets not break everything else to fix s390:) Or am I missing something?

Quoted 2 lines
s390 implementation:            query sw defined bit in pte
proposed arm implementation:    convert pte_t to pfn, use pfn_valid()

proposed arm implementation: default

include/asm-generic/pgtable.h static inline void ptep_set_wrprotect(st · line 104

Quoted 13 lines

---
Index: linux-2.6/include/asm-generic/pgtable.h
===================================================================

include/asm-generic/pgtable.h +3 -0
@@ -99,6 +99,11 @@ static inline void ptep_set_wrprotect(st
 }
 #endif
 
+#ifndef __HAVE_ARCH_PTEP_NOREFCOUNT
+#define pte_set_norefcount(__pte)      (__pte)
+#define mixedmap_refcount_pte(__pte)   (1)

+#define mixedmap_refcount_pte(__pte) pfn_valid(pte_pfn(__pte))

Should we rename "mixedmap_refcount_pte" to "mixedmap_normal_pte" or something else more neutral? To me "mixedmap_refcount_pte" sounds like it's altering the pte.

--
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>

#59 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 9 lines · Jared Hulbert

I think this should be:

default implementation: convert pte_t to pfn, use pfn_valid()

Keep in mind the reason we are talking about using anything other than pfn_valid() in vm_normal_page() is because s390 has a non-standard pfn_valid() implementation. It's s390 that's broken, not the rest of the world. So lets not break everything else to fix s390:) Or am I missing something?

I think you're bending the original meaning of pfn_valid() in this case: it is supposed to be true when a pfn refers to an accessable mapping. In fact, I consider pfn_valid() broken on arm if it returns false for a pfn that is perfectly valid for use in a pfnmap/mixedmap mapping. I think you're looking for pfn_has_struct_page_entry_for_it(), and that's different from the original meaning described above. I think it would be plain wrong to assume all architectures have this meaning of pfn_valid() that arm has today.

Quoted 21 lines
Quoted 2 lines
s390 implementation:            query sw defined bit in pte
proposed arm implementation:    convert pte_t to pfn, use pfn_valid()

proposed arm implementation: default

include/asm-generic/pgtable.h static inline void ptep_set_wrprotect(st · line 104

Quoted 13 lines

---
Index: linux-2.6/include/asm-generic/pgtable.h
===================================================================

include/asm-generic/pgtable.h +3 -0
@@ -99,6 +99,11 @@ static inline void ptep_set_wrprotect(st
 }
 #endif
 
+#ifndef __HAVE_ARCH_PTEP_NOREFCOUNT
+#define pte_set_norefcount(__pte)      (__pte)
+#define mixedmap_refcount_pte(__pte)   (1)

+#define mixedmap_refcount_pte(__pte) pfn_valid(pte_pfn(__pte))

Quoted 3 lines

Should we rename "mixedmap_refcount_pte" to "mixedmap_normal_pte" or something else more neutral? To me "mixedmap_refcount_pte" sounds like it's altering the pte.

Hmmmmh. Indeed, the wording is confusing here.
But anyway, I do want to play with Nick's PTE_SPECIAL thing next. Therefore, I'm not going to change that unless we conclude we want to go down this path. Jared, did you try this on arm? Did it work for you with my proposed callback implementation?

--
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>

#60 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 3 lines

I think you're looking for pfn_has_struct_page_entry_for_it(), and that's different from the original meaning described above.

Yes. That's what I'm looking for.

Carsten,

I think I get the problem now. You've been saying over and over, I just didn't hear it. We are not using the same assumptions for what VM_MIXEDMAP means.

Look's like today most architectures just use pfn_valid() to see if a pfn is in a valid RAM segment. The assumption used in vm_normal_page() is that valid_RAM == has_page_struct. That's fine by me for VM_MIXEDMAP because I'm only assuming 2 states a page can be
in: (1) page struct RAM (2) pfn only Flash memory ioremap()'ed in. You are wanting to add a third: (3) valid RAM, pfn only mapping with the ability to add a page struct when needed.

Is this right?

Quoted 1 line

Jared, did you try this on arm?

No. I'm not sure where we stand. Shall I bother or do I wait for the next patch?

Quoted 2 lines

Did it work for you with my proposed
callback implementation?

I'm sure I can make a callback work kind of like I proposed above.

--
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>

#61 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 20 lines · Jared Hulbert
Quoted 3 lines

I think you're looking for pfn_has_struct_page_entry_for_it(), and that's different from the original meaning described above.

Yes. That's what I'm looking for.

Carsten,

I think I get the problem now. You've been saying over and over, I just didn't hear it. We are not using the same assumptions for what VM_MIXEDMAP means.

Look's like today most architectures just use pfn_valid() to see if a pfn is in a valid RAM segment. The assumption used in vm_normal_page() is that valid_RAM == has_page_struct. That's fine by me for VM_MIXEDMAP because I'm only assuming 2 states a page can be
in: (1) page struct RAM (2) pfn only Flash memory ioremap()'ed in. You are wanting to add a third: (3) valid RAM, pfn only mapping with the ability to add a page struct when needed.

Quoted 1 line

Is this right?

About right. There are a few differences between "valid ram" and our DCSS segments, but yes. Our segments are not present at system startup, and can be "loaded" afterwards by hypercall. Thus, they're not detected and initialized as regular memory. We have the option to add struct page entries for them. In case of using the segment for xip, we don't want struct page entries and rather prefer VM_MIXEDMAP, but with regular memory (with struct page) being used after cow.
The segments can either be exclusive for one Linux image, or shared between multiple. And they can be read-only or read+write. A memory store to a read-only segment would fail. For xip, we either use "shared, read-only" or "exclusive, read+write". I think in your categories we're like
(3) valid RAM that may be read-only, pfn only mapping, no struct page

Quoted 4 lines
Quoted 1 line

Jared, did you try this on arm?

No. I'm not sure where we stand. Shall I bother or do I wait for the next patch?

I guess we should wait for Nick's patch. He has already decided not to go down this path.

--
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>

#62 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 22 lines · Carsten Otte
Quoted 20 lines · Jared Hulbert
Quoted 3 lines

I think you're looking for pfn_has_struct_page_entry_for_it(), and that's different from the original meaning described above.

Yes. That's what I'm looking for.

Carsten,

I think I get the problem now. You've been saying over and over, I just didn't hear it. We are not using the same assumptions for what VM_MIXEDMAP means.

Look's like today most architectures just use pfn_valid() to see if a pfn is in a valid RAM segment. The assumption used in vm_normal_page() is that valid_RAM == has_page_struct. That's fine by me for VM_MIXEDMAP because I'm only assuming 2 states a page can be
in: (1) page struct RAM (2) pfn only Flash memory ioremap()'ed in. You are wanting to add a third: (3) valid RAM, pfn only mapping with the ability to add a page struct when needed.

Quoted 1 line

Is this right?

Quoted 8 lines

About right. There are a few differences between "valid ram" and our DCSS segments, but yes. Our segments are not present at system startup, and can be "loaded" afterwards by hypercall. Thus, they're not detected and initialized as regular memory.
We have the option to add struct page entries for them. In case of using the segment for xip, we don't want struct page entries and rather prefer VM_MIXEDMAP, but with regular memory (with struct page) being used after cow.

You know that pfn_valid() can be changed at runtime depending on what your intentions are for that page. It can remain false if you don't want struct pages for it, then you can switch a flag...

Quoted 6 lines
Quoted 4 lines
Quoted 1 line

Jared, did you try this on arm?

No. I'm not sure where we stand. Shall I bother or do I wait for the next patch?

I guess we should wait for Nick's patch. He has already decided not to go down this path.

I've just been looking at putting everything together (including the pte_special patch). I still hit one problem with your required modification to the filemap_xip patch.

You need to unconditionally do a vm_insert_pfn in xip_file_fault, and rely on the pte bit to tell the rest of the VM that the page has not been refcounted. For architectures without such a bit, this breaks VM_MIXEDMAP, because it relies on testing pfn_valid() rather than a pte bit here. We can go 2 ways here: either s390 can make pfn_valid() work like we'd like; or we can have a vm_insert_mixedmap_pfn(), which has #ifdef __HAVE_ARCH_PTE_SPECIAL
in order to do the right thing (ie. those architectures which do have pte special can just do vm_insert_pfn, and those that don't will either do a vm_insert_pfn or vm_insert_page depending on the result of pfn_valid).

The latter I guess is more efficient for those that do implement pte_special, however if anything I would rather investigate that as an incremental patch after the basics are working. It would also break the dependency of the xip stuff on the pte_special patch, and basically make everything much more likely to get merged IMO.

--
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>

#63 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 3 lines · Nick Piggin

You know that pfn_valid() can be changed at runtime depending on what your intentions are for that page. It can remain false if you don't want struct pages for it, then you can switch a flag...

We would'nt need to switch at runtime: it is sufficient to make that decision when the segment gets attched.

Quoted 2 lines

I've just been looking at putting everything together (including the pte_special patch).

Yippieh. I am going to try it out next :-).

Quoted 13 lines

I still hit one problem with your required modification to the filemap_xip patch.

You need to unconditionally do a vm_insert_pfn in xip_file_fault, and rely on the pte bit to tell the rest of the VM that the page has not been refcounted. For architectures without such a bit, this breaks VM_MIXEDMAP, because it relies on testing pfn_valid() rather than a pte bit here. We can go 2 ways here: either s390 can make pfn_valid() work like we'd like; or we can have a vm_insert_mixedmap_pfn(), which has #ifdef __HAVE_ARCH_PTE_SPECIAL
in order to do the right thing (ie. those architectures which do have pte special can just do vm_insert_pfn, and those that don't will either do a vm_insert_pfn or vm_insert_page depending on the result of pfn_valid).

Of those two choices, I'd cleary favor vm_insert_mixedmap_pfn(). But we can #ifdef __HAVE_ARCH_PTE_SPECIAL in vm_insert_pfn() too, can't we? We can safely set the bit for both VM_MIXEDMAP and VM_PFNMAP. Did I miss something?

Quoted 5 lines

The latter I guess is more efficient for those that do implement pte_special, however if anything I would rather investigate that as an incremental patch after the basics are working. It would also break the dependency of the xip stuff on the pte_special patch, and basically make everything much more likely to get merged IMO.

I'll talk to Martin and see what he thinks. I really hate doing list walk in pfn_valid(), it just does'nt feel right.

--
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>

#64 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 10 lines · Carsten Otte
Quoted 3 lines · Nick Piggin

You know that pfn_valid() can be changed at runtime depending on what your intentions are for that page. It can remain false if you don't want struct pages for it, then you can switch a flag...

We would'nt need to switch at runtime: it is sufficient to make that decision when the segment gets attched.

Quoted 2 lines

I've just been looking at putting everything together (including the pte_special patch).

Yippieh. I am going to try it out next :-).

Just had a few things come up so I've been unable to finish this off earlier, but I'll have a look again tonight if I manage to make some progress on one more bug I'm working on.

Quoted 13 lines
Quoted 13 lines

I still hit one problem with your required modification to the filemap_xip patch.

You need to unconditionally do a vm_insert_pfn in xip_file_fault, and rely on the pte bit to tell the rest of the VM that the page has not been refcounted. For architectures without such a bit, this breaks VM_MIXEDMAP, because it relies on testing pfn_valid() rather than a pte bit here. We can go 2 ways here: either s390 can make pfn_valid() work like we'd like; or we can have a vm_insert_mixedmap_pfn(), which has #ifdef __HAVE_ARCH_PTE_SPECIAL
in order to do the right thing (ie. those architectures which do have pte special can just do vm_insert_pfn, and those that don't will either do a vm_insert_pfn or vm_insert_page depending on the result of pfn_valid).

Quoted 4 lines

Of those two choices, I'd cleary favor vm_insert_mixedmap_pfn(). But we can #ifdef __HAVE_ARCH_PTE_SPECIAL in vm_insert_pfn() too, can't we? We can safely set the bit for both VM_MIXEDMAP and VM_PFNMAP. Did I miss something?

I guess we could, but we have some good debug checking in vm_insert_pfn, and I'd like to make it clear that using it will not result in the struct page being touched.

vm_insert_mixedmap_pfn (maybe we could rename it to vm_insert_mixed) would be quite a specialised thing which is easier to audit if it is on its own IMO.

But you're right in that there is nothing technical preventing it.

Anyway, I'll post some patches soon.

--
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>

#65 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

In reply to Nick Piggin

Am Sonntag, den 13.01.2008, 03:44 +0100 schrieb Nick Piggin:

Quoted 15 lines

I've just been looking at putting everything together (including the pte_special patch). I still hit one problem with your required modification to the filemap_xip patch.

You need to unconditionally do a vm_insert_pfn in xip_file_fault, and rely on the pte bit to tell the rest of the VM that the page has not been refcounted. For architectures without such a bit, this breaks VM_MIXEDMAP, because it relies on testing pfn_valid() rather than a pte bit here. We can go 2 ways here: either s390 can make pfn_valid() work like we'd like; or we can have a vm_insert_mixedmap_pfn(), which has #ifdef __HAVE_ARCH_PTE_SPECIAL
in order to do the right thing (ie. those architectures which do have pte special can just do vm_insert_pfn, and those that don't will either do a vm_insert_pfn or vm_insert_page depending on the result of pfn_valid).

Quoted 5 lines

The latter I guess is more efficient for those that do implement pte_special, however if anything I would rather investigate that as an incremental patch after the basics are working. It would also break the dependency of the xip stuff on the pte_special patch, and basically make everything much more likely to get merged IMO.

The change in semantic of pfn_valid() for VM_MIXEDMAP keeps coming up, and I keep saying it's a bad idea. To figure how it really looks like, I've done the patch (at the end of this mail) to make pfn_valid() walk the list of dcss segments. I ran into a few issues:
a) it does'nt work because we need to grab a mutex in atomic This sanity check in vm_normal_page uses pfn_valid() in the fast path:

        /*
         * Add some anal sanity checks for now. Eventually, we should just do
         * "return pfn_to_page(pfn)", but in the meantime we check thaclarificationt we get
         * a valid pfn, and that the resulting page looks ok.
         */
        if (unlikely(!pfn_valid(pfn))) {
                print_bad_pte(vma, pte, addr);
                return NULL;
        }

And that is evaluated in context of get_user_pages() where we may not grab our list mutex. The result looks like this:
<3>BUG: sleeping function called from invalid context at
kernel/mutex.c:87

    <4>in_atomic():1, irqs_disabled():0
    <4>Call Trace:
    <4>([<0000000000103556>] show_trace+0x12e/0x148)
    <4> [<00000000001208da>] __might_sleep+0x10a/0x118
    <4> [<0000000000409024>] mutex_lock+0x30/0x6c
    <4> [<0000000000102158>] pfn_in_shared_memory+0x38/0xcc
    <4> [<000000000017f1be>] vm_normal_page+0xa2/0x140
    <4> [<000000000017fc9e>] follow_page+0x1da/0x274
    <4> [<0000000000182030>] get_user_pages+0x144/0x488
    <4> [<00000000001a2926>] get_arg_page+0x5a/0xc4
    <4> [<00000000001a2c60>] copy_strings+0x164/0x274
    <4> [<00000000001a2dcc>] copy_strings_kernel+0x5c/0xb0
    <4> [<00000000001a47a8>] do_execve+0x194/0x214
    <4> [<0000000000110262>] kernel_execve+0x28/0x70
    <4> [<0000000000100112>] init_post+0x72/0x114
    <4> [<000000000064e3f0>] kernel_init+0x288/0x398
    <4> [<0000000000107366>] kernel_thread_starter+0x6/0xc
    <4> [<0000000000107360>] kernel_thread_starter+0x0/0xc

The list protection could be changed to a spinlock to make this work.

b) is is a big performance penality in the fast path
Due to the fact that pfn_valid() is checked on regular minor faults without VM_MIXEDMAP, we'll have a lock and walking a potentially long list on a critical path.

c) the patch looks ugly
Primitives like pfn_valid() should be a small check or a small inline assembly. The need to call back to high level kernel code from core-vm looks wrong to me. Read the patch, and I think you'll come to the same conclusion.

d) timing
pfn_valid() is evaluated before our dcss list got initialized. We could circumvent this by adding an extra check like "if the list was not initialized, and we have memory behind the pfn we assume that the pfn is valid without reading the list", but that would make this thing even more ugly.

I've talked this over with Martin, and we concluded that:
- the semantics of pfn_valid() are unclear and need to be clarified
- using pfn_valid() to tell which pages have a struct page backing is not an option for s390. We'd rather prefer to keep our struct page entries that we'd love to get rid of over this ugly hack.

Thus, I think we have a dependency on pte_special as a prereqisite to VM_PFNMAP for xip.

---

arch/s390/mm/vmem.c +21 -0
Index: linux-2.6/arch/s390/mm/vmem.c
===================================================================
@@ -339,6 +339,27 @@ out:
 	return ret;
 }
 
+int pfn_in_shared_memory(unsigned long pfn)
+{
+	int rc;
+	struct memory_segment *tmp;
+
+	mutex_lock(&vmem_mutex);
+
+	list_for_each_entry(tmp, &mem_segs, list) {
+		if ((tmp->start >= pfn << PAGE_SHIFT) &&
+		    (tmp->start + tmp->size - 1 < pfn << PAGE_SHIFT)) {
+			rc = 1;
+			goto out;
+		}
+	}
+	rc = 0;
+out:
+	mutex_unlock(&vmem_mutex);
+	return rc;
+}
+
+
 /*
  * map whole physical memory to virtual memory (identity mapping)
  */
include/asm-s390/page.h +13 -2
Index: linux-2.6/include/asm-s390/page.h
===================================================================
@@ -135,7 +135,11 @@ page_get_storage_key(unsigned long addr)
 
 extern unsigned long max_pfn;
 
-static inline int pfn_valid(unsigned long pfn)
+extern int add_shared_memory(unsigned long start, unsigned long size);
+extern int remove_shared_memory(unsigned long start, unsigned long size);
+extern int pfn_in_shared_memory(unsigned long pfn);
+
+static inline int __pfn_in_kmap(unsigned long pfn)
 {
 	unsigned long dummy;
 	int ccode;
@@ -153,6 +157,13 @@ static inline int pfn_valid(unsigned lon
 	return !ccode;
 }
 
+static inline int pfn_valid(unsigned long pfn)
+{
+	if (__pfn_in_kmap(pfn) && !pfn_in_shared_memory(pfn))
+		return 1;
+	return 0;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
@@ -164,7 +175,7 @@ static inline int pfn_valid(unsigned lon
 #define __va(x)                 (void *)(unsigned long)(x)
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
-#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define virt_addr_valid(kaddr)	__pfn_in_kmap(__pa(kaddr) >> PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
include/asm-s390/pgtable.h +0 -3
Index: linux-2.6/include/asm-s390/pgtable.h
===================================================================
@@ -957,9 +957,6 @@ static inline pte_t mk_swap_pte(unsigned
 
 #define kern_addr_valid(addr)   (1)
 
-extern int add_shared_memory(unsigned long start, unsigned long size);
-extern int remove_shared_memory(unsigned long start, unsigned long size);
-
 /*
  * No page table caches to initialise
  */

--
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>

#66 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 21 lines · Carsten Otte

Am Sonntag, den 13.01.2008, 03:44 +0100 schrieb Nick Piggin:

Quoted 15 lines

I've just been looking at putting everything together (including the pte_special patch). I still hit one problem with your required modification to the filemap_xip patch.

You need to unconditionally do a vm_insert_pfn in xip_file_fault, and rely on the pte bit to tell the rest of the VM that the page has not been refcounted. For architectures without such a bit, this breaks VM_MIXEDMAP, because it relies on testing pfn_valid() rather than a pte bit here. We can go 2 ways here: either s390 can make pfn_valid() work like we'd like; or we can have a vm_insert_mixedmap_pfn(), which has #ifdef __HAVE_ARCH_PTE_SPECIAL
in order to do the right thing (ie. those architectures which do have pte special can just do vm_insert_pfn, and those that don't will either do a vm_insert_pfn or vm_insert_page depending on the result of pfn_valid).

Quoted 5 lines

The latter I guess is more efficient for those that do implement pte_special, however if anything I would rather investigate that as an incremental patch after the basics are working. It would also break the dependency of the xip stuff on the pte_special patch, and basically make everything much more likely to get merged IMO.

Quoted 4 lines

The change in semantic of pfn_valid() for VM_MIXEDMAP keeps coming up, and I keep saying it's a bad idea. To figure how it really looks like, I've done the patch (at the end of this mail) to make pfn_valid() walk the list of dcss segments. I ran into a few issues:

OK, thanks. That's very thorough of you ;)

Quoted 33 lines

a) it does'nt work because we need to grab a mutex in atomic This sanity check in vm_normal_page uses pfn_valid() in the fast path:

        /*
         * Add some anal sanity checks for now. Eventually, we should just do
         * "return pfn_to_page(pfn)", but in the meantime we check thaclarificationt we get
         * a valid pfn, and that the resulting page looks ok.
         */
        if (unlikely(!pfn_valid(pfn))) {
                print_bad_pte(vma, pte, addr);
                return NULL;
        }

And that is evaluated in context of get_user_pages() where we may not grab our list mutex. The result looks like this:
<3>BUG: sleeping function called from invalid context at
kernel/mutex.c:87

    <4>in_atomic():1, irqs_disabled():0
    <4>Call Trace:
    <4>([<0000000000103556>] show_trace+0x12e/0x148)
    <4> [<00000000001208da>] __might_sleep+0x10a/0x118
    <4> [<0000000000409024>] mutex_lock+0x30/0x6c
    <4> [<0000000000102158>] pfn_in_shared_memory+0x38/0xcc
    <4> [<000000000017f1be>] vm_normal_page+0xa2/0x140
    <4> [<000000000017fc9e>] follow_page+0x1da/0x274
    <4> [<0000000000182030>] get_user_pages+0x144/0x488
    <4> [<00000000001a2926>] get_arg_page+0x5a/0xc4
    <4> [<00000000001a2c60>] copy_strings+0x164/0x274
    <4> [<00000000001a2dcc>] copy_strings_kernel+0x5c/0xb0
    <4> [<00000000001a47a8>] do_execve+0x194/0x214
    <4> [<0000000000110262>] kernel_execve+0x28/0x70
    <4> [<0000000000100112>] init_post+0x72/0x114
    <4> [<000000000064e3f0>] kernel_init+0x288/0x398
    <4> [<0000000000107366>] kernel_thread_starter+0x6/0xc
    <4> [<0000000000107360>] kernel_thread_starter+0x0/0xc
Quoted 6 lines

The list protection could be changed to a spinlock to make this work.

b) is is a big performance penality in the fast path
Due to the fact that pfn_valid() is checked on regular minor faults without VM_MIXEDMAP, we'll have a lock and walking a potentially long list on a critical path.

We could put that under CONFIG_DEBUG_VM; with sparsemem, it is relatively expensive too, and I have seen it cost nearly 5% kernel time on x86 in fork/exec/exit stuff...

Quoted 5 lines

c) the patch looks ugly
Primitives like pfn_valid() should be a small check or a small inline assembly. The need to call back to high level kernel code from core-vm looks wrong to me. Read the patch, and I think you'll come to the same conclusion.

Well, in the sparsemem model, it needs to call in and evaluate whether the segment is valid. Granted that it is an array lookup rather than a list walk AFAIKS, but the idea is the same (query the "memory model" to ask whether the pfn is valid)

Quoted 6 lines

d) timing
pfn_valid() is evaluated before our dcss list got initialized. We could circumvent this by adding an extra check like "if the list was not initialized, and we have memory behind the pfn we assume that the pfn is valid without reading the list", but that would make this thing even more ugly.

Hmm, this is interesting. Do you know how eg. SPARSEMEM architectures can get away with this? I'd say it would be possible to init your structures before pfn_valid is called, but I'm not too familiar with memory models or the setup code...

Quoted 2 lines

I've talked this over with Martin, and we concluded that:
- the semantics of pfn_valid() are unclear and need to be clarified

Most of the core code seems to use it just in debug checking. Some parts of mm/page_alloc.c use it in a way that definitely looks like it means "is there a valid struct page" (and that's also what implementations do, eg. flatmem can easily have pfn_valid even if there is no real memory). However most of those callers are setup things, which s390 maye avoids.

Quoted 6 lines

- using pfn_valid() to tell which pages have a struct page backing is not an option for s390. We'd rather prefer to keep our struct page entries that we'd love to get rid of over this ugly hack.

Thus, I think we have a dependency on pte_special as a prereqisite to VM_PFNMAP for xip.

Although it could be *possible* to implement pfn_valid as such, I agree that we should allow the option of using pte_special. I think it is quite reasonable to want to have a runtime-dynamic data structure of memory regions like s390, and I don't think VM_MIXEDMAP is such a slowpath that we can just say "it's fine to take a global lock and search a long list for each fault". Eg. because if you have your distro running out of there, then every exec()/exit()/etc is going to do this hundreds of times.

So I'm convinced. And thanks for spending the time to help me with that ;)

--
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>

#67 lore raw

[rft] updated xip patch rollup

Quoted 10 lines · Nick Piggin

Although it could be *possible* to implement pfn_valid as such, I agree that we should allow the option of using pte_special. I think it is quite reasonable to want to have a runtime-dynamic data structure of memory regions like s390, and I don't think VM_MIXEDMAP is such a slowpath that we can just say "it's fine to take a global lock and search a long list for each fault". Eg. because if you have your distro running out of there, then every exec()/exit()/etc is going to do this hundreds of times.

Quoted 2 lines

So I'm convinced. And thanks for spending the time to help me with that ;)

Hi guys,

I'm just lumping all these patches together, sorry... I just want to get something out that can be tested, and it is time for bed so I didn't get around to making a proper patchset. It's against mainline.

Nothing major changed since you've last seen it. It is a rollup of everything, with vm_normal_page and vm_insert_mixed etc. stuff in mm/memory.c, and the vm_insert_mixed caller in mm/filemap_xip.c having all the real changes.

I've tested it with XIP on brd on x86, both with and without pte_special. This covers many (but not all) cases of refcounting.

Anyway, here it is... assuming no problems, I'll work on making the patchset. I'm still hoping we can convince Linus to like it ;)

Is this all still looking OK for you, Jared?

Thanks,
Nick

mm/memory.c +141 -56
Index: linux-2.6/mm/memory.c
===================================================================
@@ -361,55 +361,97 @@ static inline int is_cow_mapping(unsigne
 }
 
 /*
- * This function gets the "struct page" associated with a pte.
+ * vm_normal_page -- This function gets the "struct page" associated with a pte.
  *
- * NOTE! Some mappings do not have "struct pages". A raw PFN mapping
- * will have each page table entry just pointing to a raw page frame
- * number, and as far as the VM layer is concerned, those do not have
- * pages associated with them - even if the PFN might point to memory
- * that otherwise is perfectly fine and has a "struct page".
- *
- * The way we recognize those mappings is through the rules set up
- * by "remap_pfn_range()": the vma will have the VM_PFNMAP bit set,
- * and the vm_pgoff will point to the first PFN mapped: thus every
- * page that is a raw mapping will always honor the rule
+ * "Special" mappings do not wish to be associated with a "struct page" (either
+ * it doesn't exist, or it exists but they don't want to touch it). In this
+ * case, NULL is returned here. "Normal" mappings do have a struct page.
+ *
+ * There are 2 broad cases. Firstly, an architecture may define a pte_special()
+ * pte bit, in which case this function is trivial. Secondly, an architecture
+ * may not have a spare pte bit, which requires a more complicated scheme,
+ * described below.
+ *
+ * A raw VM_PFNMAP mapping (ie. one that is not COWed) is always considered a
+ * special mapping (even if there are underlying and valid "struct pages").
+ * COWed pages of a VM_PFNMAP are always normal.
+ *
+ * The way we recognize COWed pages within VM_PFNMAP mappings is through the
+ * rules set up by "remap_pfn_range()": the vma will have the VM_PFNMAP bit
+ * set, and the vm_pgoff will point to the first PFN mapped: thus every special
+ * mapping will always honor the rule
  *
  *	pfn_of_page == vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT)
  *
- * and if that isn't true, the page has been COW'ed (in which case it
- * _does_ have a "struct page" associated with it even if it is in a
- * VM_PFNMAP range).
+ * And for normal mappings this is false.
+ *
+ * This restricts such mappings to be a linear translation from virtual address
+ * to pfn. To get around this restriction, we allow arbitrary mappings so long
+ * as the vma is not a COW mapping; in that case, we know that all ptes are
+ * special (because none can have been COWed).
+ *
+ *
+ * In order to support COW of arbitrary special mappings, we have VM_MIXEDMAP.
+ *
+ * VM_MIXEDMAP mappings can likewise contain memory with or without "struct
+ * page" backing, however the difference is that _all_ pages with a struct
+ * page (that is, those where pfn_valid is true) are refcounted and considered
+ * normal pages by the VM. The disadvantage is that pages are refcounted
+ * (which can be slower and simply not an option for some PFNMAP users). The
+ * advantage is that we don't have to follow the strict linearity rule of
+ * PFNMAP mappings in order to support COWable mappings.
+ *
  */
+#ifdef __HAVE_ARCH_PTE_SPECIAL
+# define __HAVE_PTE_SPECIAL 1
+#else
+# define __HAVE_PTE_SPECIAL 0
+#endif
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
 {
-	unsigned long pfn = pte_pfn(pte);
+	unsigned long pfn;
+
+	if (__HAVE_PTE_SPECIAL) {
+		if (likely(!pte_special(pte))) {
+			VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+			return pte_page(pte);
+		}
+		VM_BUG_ON(!(vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP)));
+		return NULL;
+	}
+
+	/* !__HAVE_PTE_SPECIAL case follows: */
+
+	pfn = pte_pfn(pte);
 
-	if (unlikely(vma->vm_flags & VM_PFNMAP)) {
-		unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
-		if (pfn == vma->vm_pgoff + off)
-			return NULL;
-		if (!is_cow_mapping(vma->vm_flags))
-			return NULL;
+	if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) {
+		if (vma->vm_flags & VM_MIXEDMAP) {
+			if (!pfn_valid(pfn))
+				return NULL;
+			goto out;
+		} else {
+			unsigned long off = (addr-vma->vm_start) >> PAGE_SHIFT;
+			if (pfn == vma->vm_pgoff + off)
+				return NULL;
+			if (!is_cow_mapping(vma->vm_flags))
+				return NULL;
+		}
 	}
 
-	/*
-	 * Add some anal sanity checks for now. Eventually,
-	 * we should just do "return pfn_to_page(pfn)", but
-	 * in the meantime we check that we get a valid pfn,
-	 * and that the resulting page looks ok.
-	 */
+#ifdef CONFIG_DEBUG_VM
+	/* Check that we get a valid pfn. */
 	if (unlikely(!pfn_valid(pfn))) {
 		print_bad_pte(vma, pte, addr);
 		return NULL;
 	}
+#endif
 
 	/*
-	 * NOTE! We still have PageReserved() pages in the page 
-	 * tables. 
+	 * NOTE! We still have PageReserved() pages in the page tables.
 	 *
-	 * The PAGE_ZERO() pages and various VDSO mappings can
-	 * cause them to exist.
+	 * eg. VDSO mappings can cause them to exist.
 	 */
+out:
 	return pfn_to_page(pfn);
 }
 
@@ -1127,8 +1169,9 @@ pte_t * fastcall get_locked_pte(struct m
  * old drivers should use this, and they needed to mark their
  * pages reserved for the old functions anyway.
  */
-static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *page, pgprot_t prot)
+static int insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot)
 {
+	struct mm_struct *mm = vma->vm_mm;
 	int retval;
 	pte_t *pte;
 	spinlock_t *ptl;  
@@ -1187,33 +1230,17 @@ int vm_insert_page(struct vm_area_struct
 	if (!page_count(page))
 		return -EINVAL;
 	vma->vm_flags |= VM_INSERTPAGE;
-	return insert_page(vma->vm_mm, addr, page, vma->vm_page_prot);
+	return insert_page(vma, addr, page, vma->vm_page_prot);
 }
 EXPORT_SYMBOL(vm_insert_page);
 
-/**
- * vm_insert_pfn - insert single pfn into user vma
- * @vma: user vma to map to
- * @addr: target user address of this page
- * @pfn: source kernel pfn
- *
- * Similar to vm_inert_page, this allows drivers to insert individual pages
- * they've allocated into a user vma. Same comments apply.
- *
- * This function should only be called from a vm_ops->fault handler, and
- * in that case the handler should return NULL.
- */
-int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
-		unsigned long pfn)
+static int insert_pfn(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, pgprot_t prot)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	int retval;
 	pte_t *pte, entry;
 	spinlock_t *ptl;
 
-	BUG_ON(!(vma->vm_flags & VM_PFNMAP));
-	BUG_ON(is_cow_mapping(vma->vm_flags));
-
 	retval = -ENOMEM;
 	pte = get_locked_pte(mm, addr, &ptl);
 	if (!pte)
@@ -1223,19 +1250,74 @@ int vm_insert_pfn(struct vm_area_struct 
 		goto out_unlock;
 
 	/* Ok, finally just insert the thing.. */
-	entry = pfn_pte(pfn, vma->vm_page_prot);
+	entry = pte_mkspecial(pfn_pte(pfn, prot));
 	set_pte_at(mm, addr, pte, entry);
-	update_mmu_cache(vma, addr, entry);
+	update_mmu_cache(vma, addr, entry); /* XXX: why not for insert_page? */
 
 	retval = 0;
 out_unlock:
 	pte_unmap_unlock(pte, ptl);
-
 out:
 	return retval;
 }
+
+/**
+ * vm_insert_pfn - insert single pfn into user vma
+ * @vma: user vma to map to
+ * @addr: target user address of this page
+ * @pfn: source kernel pfn
+ *
+ * Similar to vm_inert_page, this allows drivers to insert individual pages
+ * they've allocated into a user vma. Same comments apply.
+ *
+ * This function should only be called from a vm_ops->fault handler, and
+ * in that case the handler should return NULL.
+ */
+int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
+		unsigned long pfn)
+{
+	/*
+	 * Technically, architectures with pte_special can avoid all these
+	 * restrictions (same for remap_pfn_range).  However we would like
+	 * consistency in testing and feature parity among all, so we should
+	 * try to keep these invariants in place for everybody.
+	 */
+	BUG_ON(!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)));
+	BUG_ON((vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) ==
+						(VM_PFNMAP|VM_MIXEDMAP));
+	BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags));
+	BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn));
+
+	if (addr < vma->vm_start || addr >= vma->vm_end)
+		return -EFAULT;
+	return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+}
 EXPORT_SYMBOL(vm_insert_pfn);
 
+int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
+			unsigned long pfn)
+{
+	BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
+
+	if (addr < vma->vm_start || addr >= vma->vm_end)
+		return -EFAULT;
+
+	/*
+	 * If we don't have pte special, then we have to use the pfn_valid()
+	 * based VM_MIXEDMAP scheme (see vm_normal_page), and thus we *must*
+	 * refcount the page if pfn_valid is true (hence insert_page rather
+	 * than insert_pfn).
+	 */
+	if (!__HAVE_PTE_SPECIAL && pfn_valid(pfn)) {
+		struct page *page;
+
+		page = pfn_to_page(pfn);
+		return insert_page(vma, addr, page, vma->vm_page_prot);
+	}
+	return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_insert_mixed);
+
 /*
  * maps a range of physical memory into the requested pages. the old
  * mappings are removed. any references to nonexistent pages results
@@ -1254,7 +1336,7 @@ static int remap_pte_range(struct mm_str
 	arch_enter_lazy_mmu_mode();
 	do {
 		BUG_ON(!pte_none(*pte));
-		set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
+		set_pte_at(mm, addr, pte, pte_mkspecial(pfn_pte(pfn, prot)));
 		pfn++;
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 	arch_leave_lazy_mmu_mode();
@@ -2386,10 +2468,13 @@ static noinline int do_no_pfn(struct mm_
 	unsigned long pfn;
 
 	pte_unmap(page_table);
-	BUG_ON(!(vma->vm_flags & VM_PFNMAP));
-	BUG_ON(is_cow_mapping(vma->vm_flags));
+	BUG_ON(!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)));
+	BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags));
 
 	pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK);
+
+	BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn));
+
 	if (unlikely(pfn == NOPFN_OOM))
 		return VM_FAULT_OOM;
 	else if (unlikely(pfn == NOPFN_SIGBUS))
include/linux/mm.h +5 -1
Index: linux-2.6/include/linux/mm.h
===================================================================
@@ -106,6 +106,7 @@ extern unsigned int kobjsize(const void 
 #define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
 
 #define VM_CAN_NONLINEAR 0x08000000	/* Has ->fault & does nonlinear pages */
+#define VM_MIXEDMAP	0x10000000	/* Can contain "struct page" and pure PFN pages */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
@@ -698,7 +699,8 @@ struct zap_details {
 	unsigned long truncate_count;		/* Compare vm_truncate_count */
 };
 
-struct page *vm_normal_page(struct vm_area_struct *, unsigned long, pte_t);
+struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
+
 unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
 		unsigned long size, struct zap_details *);
 unsigned long unmap_vmas(struct mmu_gather **tlb,
@@ -1095,6 +1097,8 @@ int remap_pfn_range(struct vm_area_struc
 int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *);
 int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
 			unsigned long pfn);
+int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
+			unsigned long pfn);
 
 struct page *follow_page(struct vm_area_struct *, unsigned long address,
 			unsigned int foll_flags);
include/asm-um/pgtable.h +13 -0
Index: linux-2.6/include/asm-um/pgtable.h
===================================================================
@@ -21,6 +21,8 @@
 #define _PAGE_USER	0x040
 #define _PAGE_ACCESSED	0x080
 #define _PAGE_DIRTY	0x100
+#define _PAGE_SPECIAL	0x200
+#define __HAVE_ARCH_PTE_SPECIAL
 /* If _PAGE_PRESENT is clear, we use these: */
 #define _PAGE_FILE	0x008	/* nonlinear file mapping, saved PTE; unset:swap */
 #define _PAGE_PROTNONE	0x010	/* if the user mapped it with PROT_NONE;
@@ -220,6 +222,11 @@ static inline int pte_newprot(pte_t pte)
 	return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT)));
 }
 
+static inline int pte_special(pte_t pte)
+{
+	return pte_get_bits(pte, _PAGE_SPECIAL);
+}
+
 /*
  * =================================
  * Flags setting section.
@@ -288,6 +295,12 @@ static inline pte_t pte_mknewpage(pte_t 
 	return(pte);
 }
 
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	pte_set_bits(pte, _PAGE_SPECIAL);
+	return(pte);
+}
+
 static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
 	pte_copy(*pteptr, pteval);
include/asm-x86/pgtable_32.h +5 -0
Index: linux-2.6/include/asm-x86/pgtable_32.h
===================================================================
@@ -102,6 +102,7 @@ void paging_init(void);
 #define _PAGE_BIT_UNUSED2	10
 #define _PAGE_BIT_UNUSED3	11
 #define _PAGE_BIT_NX		63
+#define _PAGE_BIT_SPECIAL	_PAGE_BIT_UNUSED1
 
 #define _PAGE_PRESENT	0x001
 #define _PAGE_RW	0x002
@@ -115,6 +116,8 @@ void paging_init(void);
 #define _PAGE_UNUSED1	0x200	/* available for programmer */
 #define _PAGE_UNUSED2	0x400
 #define _PAGE_UNUSED3	0x800
+#define _PAGE_SPECIAL	PAGE_UNUSED1
+#define __HAVE_ARCH_PTE_SPECIAL
 
 /* If _PAGE_PRESENT is clear, we use these: */
 #define _PAGE_FILE	0x040	/* nonlinear file mapping, saved PTE; unset:swap */
@@ -219,6 +222,7 @@ static inline int pte_dirty(pte_t pte)		
 static inline int pte_young(pte_t pte)		{ return (pte).pte_low & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)		{ return (pte).pte_low & _PAGE_RW; }
 static inline int pte_huge(pte_t pte)		{ return (pte).pte_low & _PAGE_PSE; }
+static inline int pte_special(pte_t pte)	{ return (pte).pte_low & _PAGE_SPECIAL; }
 
 /*
  * The following only works if pte_present() is not true.
@@ -232,6 +236,7 @@ static inline pte_t pte_mkdirty(pte_t pt
 static inline pte_t pte_mkyoung(pte_t pte)	{ (pte).pte_low |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ (pte).pte_low |= _PAGE_RW; return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)	{ (pte).pte_low |= _PAGE_PSE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ (pte).pte_low |= _PAGE_SPECIAL; return pte; }
 
 #ifdef CONFIG_X86_PAE
 # include <asm/pgtable-3level.h>
include/asm-x86/pgtable_64.h +5 -0
Index: linux-2.6/include/asm-x86/pgtable_64.h
===================================================================
@@ -151,6 +151,7 @@ static inline pte_t ptep_get_and_clear_f
 #define _PAGE_BIT_DIRTY		6
 #define _PAGE_BIT_PSE		7	/* 4 MB (or 2MB) page */
 #define _PAGE_BIT_GLOBAL	8	/* Global TLB entry PPro+ */
+#define _PAGE_BIT_SPECIAL	9
 #define _PAGE_BIT_NX           63       /* No execute: only valid after cpuid check */
 
 #define _PAGE_PRESENT	0x001
@@ -163,6 +164,8 @@ static inline pte_t ptep_get_and_clear_f
 #define _PAGE_PSE	0x080	/* 2MB page */
 #define _PAGE_FILE	0x040	/* nonlinear file mapping, saved PTE; unset:swap */
 #define _PAGE_GLOBAL	0x100	/* Global TLB entry */
+#define _PAGE_SPECIAL	0x200
+#define __HAVE_ARCH_PTE_SPECIAL
 
 #define _PAGE_PROTNONE	0x080	/* If not present */
 #define _PAGE_NX        (_AC(1,UL)<<_PAGE_BIT_NX)
@@ -272,6 +275,7 @@ static inline int pte_young(pte_t pte)		
 static inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_RW; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_huge(pte_t pte)		{ return pte_val(pte) & _PAGE_PSE; }
+static inline int pte_special(pte_t pte)	{ return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkold(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
@@ -282,6 +286,7 @@ static inline pte_t pte_mkyoung(pte_t pt
 static inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_PSE)); return pte; }
 static inline pte_t pte_clrhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_PSE)); return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SPECIAL)); return pte; }
 
 struct vm_area_struct;
 
include/asm-alpha/pgtable.h +2 -0
Index: linux-2.6/include/asm-alpha/pgtable.h
===================================================================
@@ -268,6 +268,7 @@ extern inline int pte_write(pte_t pte)		
 extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
 extern inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
+extern inline int pte_special(pte_t pte)	{ return 0; }
 
 extern inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_FOW; return pte; }
 extern inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
@@ -275,6 +276,7 @@ extern inline pte_t pte_mkold(pte_t pte)
 extern inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) &= ~_PAGE_FOW; return pte; }
 extern inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= __DIRTY_BITS; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= __ACCESS_BITS; return pte; }
+extern inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
include/asm-avr32/pgtable.h +8 -0
Index: linux-2.6/include/asm-avr32/pgtable.h
===================================================================
@@ -211,6 +211,10 @@ static inline int pte_young(pte_t pte)
 {
 	return pte_val(pte) & _PAGE_ACCESSED;
 }
+static inline int pte_special(pte_t pte)
+{
+	return 0;
+}
 
 /*
  * The following only work if pte_present() is not true.
@@ -251,6 +255,10 @@ static inline pte_t pte_mkyoung(pte_t pt
 	set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED));
 	return pte;
 }
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	return pte;
+}
 
 #define pmd_none(x)	(!pmd_val(x))
 #define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
include/asm-cris/pgtable.h +2 -0
Index: linux-2.6/include/asm-cris/pgtable.h
===================================================================
@@ -115,6 +115,7 @@ static inline int pte_write(pte_t pte)  
 static inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
 static inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)           { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
@@ -162,6 +163,7 @@ static inline pte_t pte_mkyoung(pte_t pt
         }
         return pte;
 }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
include/asm-frv/pgtable.h +2 -0
Index: linux-2.6/include/asm-frv/pgtable.h
===================================================================
@@ -380,6 +380,7 @@ static inline pmd_t *pmd_offset(pud_t *d
 static inline int pte_dirty(pte_t pte)		{ return (pte).pte & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)		{ return (pte).pte & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)		{ return !((pte).pte & _PAGE_WP); }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline pte_t pte_mkclean(pte_t pte)	{ (pte).pte &= ~_PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkold(pte_t pte)	{ (pte).pte &= ~_PAGE_ACCESSED; return pte; }
@@ -387,6 +388,7 @@ static inline pte_t pte_wrprotect(pte_t 
 static inline pte_t pte_mkdirty(pte_t pte)	{ (pte).pte |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)	{ (pte).pte |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ (pte).pte &= ~_PAGE_WP; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
include/asm-ia64/pgtable.h +3 -0
Index: linux-2.6/include/asm-ia64/pgtable.h
===================================================================
@@ -302,6 +302,8 @@ ia64_phys_addr_valid (unsigned long addr
 #define pte_dirty(pte)		((pte_val(pte) & _PAGE_D) != 0)
 #define pte_young(pte)		((pte_val(pte) & _PAGE_A) != 0)
 #define pte_file(pte)		((pte_val(pte) & _PAGE_FILE) != 0)
+#define pte_special(pte)	0
+
 /*
  * Note: we convert AR_RWX to AR_RX and AR_RW to AR_R by clearing the 2nd bit in the
  * access rights:
@@ -313,6 +315,7 @@ ia64_phys_addr_valid (unsigned long addr
 #define pte_mkclean(pte)	(__pte(pte_val(pte) & ~_PAGE_D))
 #define pte_mkdirty(pte)	(__pte(pte_val(pte) | _PAGE_D))
 #define pte_mkhuge(pte)		(__pte(pte_val(pte)))
+#define pte_mkspecial(pte)	(pte)
 
 /*
  * Because ia64's Icache and Dcache is not coherent (on a cpu), we need to
include/asm-m32r/pgtable.h +10 -0
Index: linux-2.6/include/asm-m32r/pgtable.h
===================================================================
@@ -214,6 +214,11 @@ static inline int pte_file(pte_t pte)
 	return pte_val(pte) & _PAGE_FILE;
 }
 
+static inline int pte_special(pte_t pte)
+{
+	return 0;
+}
+
 static inline pte_t pte_mkclean(pte_t pte)
 {
 	pte_val(pte) &= ~_PAGE_DIRTY;
@@ -250,6 +255,11 @@ static inline pte_t pte_mkwrite(pte_t pt
 	return pte;
 }
 
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	return pte;
+}
+
 static inline  int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
include/asm-m68k/motorola_pgtable.h +2 -0
Index: linux-2.6/include/asm-m68k/motorola_pgtable.h
===================================================================
@@ -168,6 +168,7 @@ static inline int pte_write(pte_t pte)		
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) |= _PAGE_RONLY; return pte; }
 static inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
@@ -185,6 +186,7 @@ static inline pte_t pte_mkcache(pte_t pt
 	pte_val(pte) = (pte_val(pte) & _CACHEMASK040) | m68k_supervisor_cachemode;
 	return pte;
 }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
 
include/asm-m68k/sun3_pgtable.h +2 -0
Index: linux-2.6/include/asm-m68k/sun3_pgtable.h
===================================================================
@@ -169,6 +169,7 @@ static inline int pte_write(pte_t pte)		
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & SUN3_PAGE_MODIFIED; }
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & SUN3_PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & SUN3_PAGE_ACCESSED; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~SUN3_PAGE_WRITEABLE; return pte; }
 static inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~SUN3_PAGE_MODIFIED; return pte; }
@@ -181,6 +182,7 @@ static inline pte_t pte_mknocache(pte_t 
 //static inline pte_t pte_mkcache(pte_t pte)	{ pte_val(pte) &= SUN3_PAGE_NOCACHE; return pte; }
 // until then, use:
 static inline pte_t pte_mkcache(pte_t pte)	{ return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern pgd_t kernel_pg_dir[PTRS_PER_PGD];
include/asm-mips/pgtable.h +2 -0
Index: linux-2.6/include/asm-mips/pgtable.h
===================================================================
@@ -285,6 +285,8 @@ static inline pte_t pte_mkyoung(pte_t pt
 	return pte;
 }
 #endif
+static inline int pte_special(pte_t pte)	{ return 0; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 /*
  * Macro to make mark a page protection value as "uncacheable".  Note
include/asm-parisc/pgtable.h +2 -0
Index: linux-2.6/include/asm-parisc/pgtable.h
===================================================================
@@ -331,6 +331,7 @@ static inline int pte_dirty(pte_t pte)		
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_WRITE; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline pte_t pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkold(pte_t pte)	{ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
@@ -338,6 +339,7 @@ static inline pte_t pte_wrprotect(pte_t 
 static inline pte_t pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _PAGE_WRITE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
include/asm-powerpc/pgtable-ppc32.h +3 -0
Index: linux-2.6/include/asm-powerpc/pgtable-ppc32.h
===================================================================
@@ -514,6 +514,7 @@ static inline int pte_write(pte_t pte)		
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline void pte_uncache(pte_t pte)       { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)         { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -531,6 +532,8 @@ static inline pte_t pte_mkdirty(pte_t pt
 	pte_val(pte) |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte) {
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+	return pte; }
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
include/asm-powerpc/pgtable-ppc64.h +3 -0
Index: linux-2.6/include/asm-powerpc/pgtable-ppc64.h
===================================================================
@@ -239,6 +239,7 @@ static inline int pte_write(pte_t pte) {
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
 static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+static inline int pte_special(pte_t pte) { return 0; }
 
 static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)   { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -257,6 +258,8 @@ static inline pte_t pte_mkyoung(pte_t pt
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkhuge(pte_t pte) {
 	return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+	return pte; }
 
 /* Atomic PTE updates */
 static inline unsigned long pte_update(struct mm_struct *mm,
include/asm-ppc/pgtable.h +3 -0
Index: linux-2.6/include/asm-ppc/pgtable.h
===================================================================
@@ -537,6 +537,7 @@ static inline int pte_write(pte_t pte)		
 static inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)		{ return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline void pte_uncache(pte_t pte)       { pte_val(pte) |= _PAGE_NO_CACHE; }
 static inline void pte_cache(pte_t pte)         { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -554,6 +555,8 @@ static inline pte_t pte_mkdirty(pte_t pt
 	pte_val(pte) |= _PAGE_DIRTY; return pte; }
 static inline pte_t pte_mkyoung(pte_t pte) {
 	pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) {
+	return pte; }
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
include/asm-s390/pgtable.h +13 -0
Index: linux-2.6/include/asm-s390/pgtable.h
===================================================================
@@ -228,6 +228,8 @@ extern unsigned long vmalloc_end;
 /* Software bits in the page table entry */
 #define _PAGE_SWT	0x001		/* SW pte type bit t */
 #define _PAGE_SWX	0x002		/* SW pte type bit x */
+#define _PAGE_SPECIAL	0x004		/* SW associated with special page */
+#define __HAVE_ARCH_PTE_SPECIAL
 
 /* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY	0x400
@@ -504,6 +506,11 @@ static inline int pte_file(pte_t pte)
 	return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
 }
 
+static inline int pte_special(pte_t pte)
+{
+	return (pte_val(pte) & _PAGE_SPECIAL);
+}
+
 #define __HAVE_ARCH_PTE_SAME
 #define pte_same(a,b)  (pte_val(a) == pte_val(b))
 
@@ -654,6 +661,12 @@ static inline pte_t pte_mkyoung(pte_t pt
 	return pte;
 }
 
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	pte_val(pte) |= _PAGE_SPECIAL;
+	return pte;
+}
+
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
 					    unsigned long addr, pte_t *ptep)
include/asm-sh64/pgtable.h +2 -0
Index: linux-2.6/include/asm-sh64/pgtable.h
===================================================================
@@ -419,6 +419,7 @@ static inline int pte_dirty(pte_t pte){ 
 static inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_WRITE; }
+static inline int pte_special(pte_t pte)	{ return 0; }
 
 static inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
 static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -427,6 +428,7 @@ static inline pte_t pte_mkwrite(pte_t pt
 static inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
 
 
 /*
include/asm-sparc/pgtable.h +7 -0
Index: linux-2.6/include/asm-sparc/pgtable.h
===================================================================
@@ -219,6 +219,11 @@ static inline int pte_file(pte_t pte)
 	return pte_val(pte) & BTFIXUP_HALF(pte_filei);
 }
 
+static inline int pte_special(pte_t pte)
+{
+	return 0;
+}
+
 /*
  */
 BTFIXUPDEF_HALF(pte_wrprotecti)
@@ -251,6 +256,8 @@ BTFIXUPDEF_CALL_CONST(pte_t, pte_mkyoung
 #define pte_mkdirty(pte) BTFIXUP_CALL(pte_mkdirty)(pte)
 #define pte_mkyoung(pte) BTFIXUP_CALL(pte_mkyoung)(pte)
 
+#define pte_mkspecial(pte_t pte)    (pte)
+
 #define pfn_pte(pfn, prot)		mk_pte(pfn_to_page(pfn), prot)
 
 BTFIXUPDEF_CALL(unsigned long,	 pte_pfn, pte_t)
include/asm-sparc64/pgtable.h +10 -0
Index: linux-2.6/include/asm-sparc64/pgtable.h
===================================================================
@@ -506,6 +506,11 @@ static inline pte_t pte_mkyoung(pte_t pt
 	return __pte(pte_val(pte) | mask);
 }
 
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+	return pte;
+}
+
 static inline unsigned long pte_young(pte_t pte)
 {
 	unsigned long mask;
@@ -608,6 +613,11 @@ static inline unsigned long pte_present(
 	return val;
 }
 
+static inline int pte_special(pte_t pte)
+{
+	return 0;
+}
+
 #define pmd_set(pmdp, ptep)	\
 	(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
 #define pud_set(pudp, pmdp)	\
include/asm-xtensa/pgtable.h +4 -0
Index: linux-2.6/include/asm-xtensa/pgtable.h
===================================================================
@@ -212,6 +212,8 @@ static inline int pte_write(pte_t pte) {
 static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)  { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
+
 static inline pte_t pte_wrprotect(pte_t pte)	
 	{ pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; }
 static inline pte_t pte_mkclean(pte_t pte)
@@ -224,6 +226,8 @@ static inline pte_t pte_mkyoung(pte_t pt
 	{ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)
 	{ pte_val(pte) |= _PAGE_WRITABLE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte)
+	{ return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
fs/ext2/super.c +1 -2
Index: linux-2.6/fs/ext2/super.c
===================================================================
@@ -844,8 +844,7 @@ static int ext2_fill_super(struct super_
 
 	blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
 
-	if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
-				  (sb->s_blocksize != blocksize))) {
+	if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) {
 		if (!silent)
 			printk("XIP: Unsupported blocksize\n");
 		goto failed_mount;
fs/ext2/inode.c +1 -1
Index: linux-2.6/fs/ext2/inode.c
===================================================================
@@ -800,7 +800,7 @@ const struct address_space_operations ex
 
 const struct address_space_operations ext2_aops_xip = {
 	.bmap			= ext2_bmap,
-	.get_xip_page		= ext2_get_xip_page,
+	.get_xip_address	= ext2_get_xip_address,
 };
 
 const struct address_space_operations ext2_nobh_aops = {
fs/ext2/xip.c +18 -18
Index: linux-2.6/fs/ext2/xip.c
===================================================================
@@ -15,24 +15,25 @@
 #include "xip.h"
 
 static inline int
-__inode_direct_access(struct inode *inode, sector_t sector,
-		      unsigned long *data)
+__inode_direct_access(struct inode *inode, sector_t block, unsigned long *data)
 {
+	sector_t sector;
 	BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+
+	sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
 	return inode->i_sb->s_bdev->bd_disk->fops
-		->direct_access(inode->i_sb->s_bdev,sector,data);
+		->direct_access(inode->i_sb->s_bdev, sector, data);
 }
 
 static inline int
-__ext2_get_sector(struct inode *inode, sector_t offset, int create,
+__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
 		   sector_t *result)
 {
 	struct buffer_head tmp;
 	int rc;
 
 	memset(&tmp, 0, sizeof(struct buffer_head));
-	rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &tmp,
-			    create);
+	rc = ext2_get_block(inode, pgoff, &tmp, create);
 	*result = tmp.b_blocknr;
 
 	/* did we get a sparse block (hole in the file)? */
@@ -45,13 +46,12 @@ __ext2_get_sector(struct inode *inode, s
 }
 
 int
-ext2_clear_xip_target(struct inode *inode, int block)
+ext2_clear_xip_target(struct inode *inode, sector_t block)
 {
-	sector_t sector = block * (PAGE_SIZE/512);
 	unsigned long data;
 	int rc;
 
-	rc = __inode_direct_access(inode, sector, &data);
+	rc = __inode_direct_access(inode, block, &data);
 	if (!rc)
 		clear_page((void*)data);
 	return rc;
@@ -69,24 +69,24 @@ void ext2_xip_verify_sb(struct super_blo
 	}
 }
 
-struct page *
-ext2_get_xip_page(struct address_space *mapping, sector_t offset,
-		   int create)
+void *
+ext2_get_xip_address(struct address_space *mapping, pgoff_t pgoff, int create)
 {
 	int rc;
 	unsigned long data;
-	sector_t sector;
+	sector_t block;
 
 	/* first, retrieve the sector number */
-	rc = __ext2_get_sector(mapping->host, offset, create, &sector);
+	rc = __ext2_get_block(mapping->host, pgoff, create, &block);
 	if (rc)
 		goto error;
 
 	/* retrieve address of the target data */
-	rc = __inode_direct_access
-		(mapping->host, sector * (PAGE_SIZE/512), &data);
-	if (!rc)
-		return virt_to_page(data);
+	rc = __inode_direct_access(mapping->host, block, &data);
+	if (rc)
+		goto error;
+
+	return (void *)data;
 
  error:
 	return ERR_PTR(rc);
fs/ext2/xip.h +4 -4
Index: linux-2.6/fs/ext2/xip.h
===================================================================
@@ -7,19 +7,19 @@
 
 #ifdef CONFIG_EXT2_FS_XIP
 extern void ext2_xip_verify_sb (struct super_block *);
-extern int ext2_clear_xip_target (struct inode *, int);
+extern int ext2_clear_xip_target (struct inode *, sector_t);
 
 static inline int ext2_use_xip (struct super_block *sb)
 {
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
 }
-struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
-#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+void *ext2_get_xip_address(struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_address)
 #else
 #define mapping_is_xip(map)			0
 #define ext2_xip_verify_sb(sb)			do { } while (0)
 #define ext2_use_xip(sb)			0
 #define ext2_clear_xip_target(inode, chain)	0
-#define ext2_get_xip_page			NULL
+#define ext2_get_xip_address			NULL
 #endif
fs/open.c +1 -1
Index: linux-2.6/fs/open.c
===================================================================
@@ -778,7 +778,7 @@ static struct file *__dentry_open(struct
 	if (f->f_flags & O_DIRECT) {
 		if (!f->f_mapping->a_ops ||
 		    ((!f->f_mapping->a_ops->direct_IO) &&
-		    (!f->f_mapping->a_ops->get_xip_page))) {
+		    (!f->f_mapping->a_ops->get_xip_address))) {
 			fput(f);
 			f = ERR_PTR(-EINVAL);
 		}
include/linux/fs.h +1 -2
Index: linux-2.6/include/linux/fs.h
===================================================================
@@ -473,8 +473,7 @@ struct address_space_operations {
 	int (*releasepage) (struct page *, gfp_t);
 	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
-	struct page* (*get_xip_page)(struct address_space *, sector_t,
-			int);
+	void * (*get_xip_address)(struct address_space *, pgoff_t, int);
 	/* migrate the contents of a page to the specified target */
 	int (*migratepage) (struct address_space *,
 			struct page *, struct page *);
mm/fadvise.c +1 -1
Index: linux-2.6/mm/fadvise.c
===================================================================
@@ -49,7 +49,7 @@ asmlinkage long sys_fadvise64_64(int fd,
 		goto out;
 	}
 
-	if (mapping->a_ops->get_xip_page)
+	if (mapping->a_ops->get_xip_address)
 		/* no bad return value, but ignore advice */
 		goto out;
 
mm/filemap_xip.c +95 -96

349 lines not on this page · raw message

mm/madvise.c +1 -1
Index: linux-2.6/mm/madvise.c
===================================================================
@@ -112,7 +112,7 @@ static long madvise_willneed(struct vm_a
 	if (!file)
 		return -EBADF;
 
-	if (file->f_mapping->a_ops->get_xip_page) {
+	if (file->f_mapping->a_ops->get_xip_address) {
 		/* no bad return value, but ignore advice */
 		return 0;
 	}
arch/s390/mm/vmem.c +1 -17
Index: linux-2.6/arch/s390/mm/vmem.c
===================================================================
@@ -310,8 +310,6 @@ out:
 int add_shared_memory(unsigned long start, unsigned long size)
 {
 	struct memory_segment *seg;
-	struct page *page;
-	unsigned long pfn, num_pfn, end_pfn;
 	int ret;
 
 	mutex_lock(&vmem_mutex);
@@ -326,24 +324,10 @@ int add_shared_memory(unsigned long star
 	if (ret)
 		goto out_free;
 
-	ret = vmem_add_mem(start, size);
+	ret = vmem_add_range(start, size);
 	if (ret)
 		goto out_remove;
 
-	pfn = PFN_DOWN(start);
-	num_pfn = PFN_DOWN(size);
-	end_pfn = pfn + num_pfn;
-
-	page = pfn_to_page(pfn);
-	memset(page, 0, num_pfn * sizeof(struct page));
-
-	for (; pfn < end_pfn; pfn++) {
-		page = pfn_to_page(pfn);
-		init_page_count(page);
-		reset_page_mapcount(page);
-		SetPageReserved(page);
-		INIT_LIST_HEAD(&page->lru);
-	}
 	goto out;
 
 out_remove:

--
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>

#68 lore raw

Re: [rft] updated xip patch rollup

Quoted 5 lines · Nick Piggin

I've tested it with XIP on brd on x86, both with and without pte_special. This covers many (but not all) cases of refcounting.

Anyway, here it is... assuming no problems, I'll work on making the patchset. I'm still hoping we can convince Linus to like it ;)

Works for me. I have tested with dcssblk, and ext2 -o xip on s390x. I have bootet a distro and built a kernel with the gcc/glibc being on xip file system. Thumbs up :-).

--
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>

#69 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

In reply to Carsten Otte
Quoted 3 lines

In fact, I consider pfn_valid() broken on arm if it returns false for a pfn that is perfectly valid for use in a pfnmap/mixedmap mapping.

Remember, my interest in creating VM_MIXEDMAP is in mapping Flash into these pfnmap/mixedmap regions. I don't think it's fair to let pfn_valid() work for Flash pages, at least for now, because there are many things you can't do with them that you can do with RAM.

--
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>

#70 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 8 lines · Jared Hulbert
Quoted 3 lines

In fact, I consider pfn_valid() broken on arm if it returns false for a pfn that is perfectly valid for use in a pfnmap/mixedmap mapping.

Remember, my interest in creating VM_MIXEDMAP is in mapping Flash into these pfnmap/mixedmap regions. I don't think it's fair to let pfn_valid() work for Flash pages, at least for now, because there are many things you can't do with them that you can do with RAM.

You've got a point there. Our memory segments don't differ from regular RAM too much, other then Flash. I think I have to withdraw my statement.

--
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>

#71 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

In reply to Carsten Otte
Quoted 21 lines · Carsten Otte

From: Carsten Otte <[email protected]>

include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

This patch introduces two arch callbacks, which may optionally be implemented in case the architecutre does define __HAVE_ARCH_PTEP_NOREFCOUNT.

The first callback, pte_set_norefcount(__pte) is called by core-vm to indicate that subject page table entry is going to be inserted into a VM_MIXEDMAP vma.
default implementation: noop
s390 implementation: set sw defined bit in pte
proposed arm implementation: noop

The second callback, mixedmap_refcount_pte(__pte) is called by core-vm to figure out whether or not subject pte requires reference counting in the corresponding struct page entry. A non-zero result indicates reference counting is required.
default implementation: (1)
s390 implementation: query sw defined bit in pte
proposed arm implementation: convert pte_t to pfn, use pfn_valid()

Quoted 1 line

Hmm, I had it in my mind that this would be entirely hidden in the s390's mixedmap_refcount_pfn, but of course you actually need to set the pte too....

In that case, I would rather prefer to go along the lines of my pte_special patch, which would replace all of vm_normal_page (on a per-arch basis), and you wouldn't need this mixedmap_refcount_* stuff (it can stay pfn_valid for those architectures that don't implement pte_special).

--
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>

#72 lore raw

Re: [rfc][patch 1/4] include: add callbacks to toggle reference counting for VM_MIXEDMAP pages

Quoted 2 lines · Nick Piggin

Hmm, I had it in my mind that this would be entirely hidden in the s390's mixedmap_refcount_pfn, but of course you actually need to set the pte too....

I did'nt think about that upfront too.

Quoted 4 lines

In that case, I would rather prefer to go along the lines of my pte_special patch, which would replace all of vm_normal_page (on a per-arch basis), and you wouldn't need this mixedmap_refcount_* stuff (it can stay pfn_valid for those architectures that don't implement pte_special).

I am going to play with PTE_SPECIAL next. I tend to agree with you that the PTE_SPECIAL path looks more promising than the one implemented in this patch series because it offers a more generic meaning for our valuable pte bit which can be used for various purposes by core-vm.
Let's just implement them all, and figure the best one after that ;-).

--
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>

#73 lore raw

RFC PATCH 2/4 mm: introduce VM_MIXEDMAP

In reply to a message not in the archive

mm: introduce VM_MIXEDMAP

Introduce a new type of mapping, VM_MIXEDMAP. This is unlike VM_PFNMAP in that it can support COW mappings of arbitrary ranges including ranges without struct page (PFNMAP can only support COW in those cases where the un-COW-ed translations are mapped linearly in the virtual address).

VM_MIXEDMAP achieves this by refcounting pages with mixedmap_refcount_pte(pte) being non-zero, and not refcounting !mixedmap_refcount_pte(pte) pages (which is not an option for VM_PFNMAP, because it needs to avoid refcounting pfn_valid pages eg. for /dev/mem mappings).

The core VM calls pte_set_norefcount(__pte) for each PTE that is being created by vm_insert_pfn and do_no_pfn for a vma that has VM_MIXEDMAP set.

---

include/linux/mm.h +1 -0
Index: linux-2.6/include/linux/mm.h
===================================================================
@@ -106,6 +106,7 @@ extern unsigned int kobjsize(const void 
 #define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
 
 #define VM_CAN_NONLINEAR 0x08000000	/* Has ->fault & does nonlinear pages */
+#define VM_MIXEDMAP	0x10000000	/* Can contain "struct page" and pure PFN pages */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
mm/memory.c +60 -21

133 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>

#74 lore raw

RFC PATCH 3/4 Convert XIP to support non-struct page backed memory

In reply to a message not in the archive

Convert XIP to support non-struct page backed memory, using VM_MIXEDMAP for the user mappings.

This requires the get_xip_page API to be changed to an address based one.

(The kaddr->pfn conversion may not be quite right for all architectures or XIP memory mappings, and the cacheflushing may need to be updated for some archs).

---

fs/ext2/inode.c +1 -1
Index: linux-2.6/fs/ext2/inode.c
===================================================================
@@ -800,7 +800,7 @@ const struct address_space_operations ex
 
 const struct address_space_operations ext2_aops_xip = {
 	.bmap			= ext2_bmap,
-	.get_xip_page		= ext2_get_xip_page,
+	.get_xip_address	= ext2_get_xip_address,
 };
 
 const struct address_space_operations ext2_nobh_aops = {
fs/ext2/xip.c +18 -18
Index: linux-2.6/fs/ext2/xip.c
===================================================================
@@ -15,24 +15,25 @@
 #include "xip.h"
 
 static inline int
-__inode_direct_access(struct inode *inode, sector_t sector,
-		      unsigned long *data)
+__inode_direct_access(struct inode *inode, sector_t block, unsigned long *data)
 {
+	sector_t sector;
 	BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+
+	sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
 	return inode->i_sb->s_bdev->bd_disk->fops
-		->direct_access(inode->i_sb->s_bdev,sector,data);
+		->direct_access(inode->i_sb->s_bdev, sector, data);
 }
 
 static inline int
-__ext2_get_sector(struct inode *inode, sector_t offset, int create,
+__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
 		   sector_t *result)
 {
 	struct buffer_head tmp;
 	int rc;
 
 	memset(&tmp, 0, sizeof(struct buffer_head));
-	rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &tmp,
-			    create);
+	rc = ext2_get_block(inode, pgoff, &tmp, create);
 	*result = tmp.b_blocknr;
 
 	/* did we get a sparse block (hole in the file)? */
@@ -45,13 +46,12 @@ __ext2_get_sector(struct inode *inode, s
 }
 
 int
-ext2_clear_xip_target(struct inode *inode, int block)
+ext2_clear_xip_target(struct inode *inode, sector_t block)
 {
-	sector_t sector = block * (PAGE_SIZE/512);
 	unsigned long data;
 	int rc;
 
-	rc = __inode_direct_access(inode, sector, &data);
+	rc = __inode_direct_access(inode, block, &data);
 	if (!rc)
 		clear_page((void*)data);
 	return rc;
@@ -69,24 +69,24 @@ void ext2_xip_verify_sb(struct super_blo
 	}
 }
 
-struct page *
-ext2_get_xip_page(struct address_space *mapping, sector_t offset,
-		   int create)
+void *
+ext2_get_xip_address(struct address_space *mapping, pgoff_t pgoff, int create)
 {
 	int rc;
 	unsigned long data;
-	sector_t sector;
+	sector_t block;
 
 	/* first, retrieve the sector number */
-	rc = __ext2_get_sector(mapping->host, offset, create, &sector);
+	rc = __ext2_get_block(mapping->host, pgoff, create, &block);
 	if (rc)
 		goto error;
 
 	/* retrieve address of the target data */
-	rc = __inode_direct_access
-		(mapping->host, sector * (PAGE_SIZE/512), &data);
-	if (!rc)
-		return virt_to_page(data);
+	rc = __inode_direct_access(mapping->host, block, &data);
+	if (rc)
+		goto error;
+
+	return (void *)data;
 
  error:
 	return ERR_PTR(rc);
fs/ext2/xip.h +3 -3
Index: linux-2.6/fs/ext2/xip.h
===================================================================
@@ -7,15 +7,15 @@
 
 #ifdef CONFIG_EXT2_FS_XIP
 extern void ext2_xip_verify_sb (struct super_block *);
-extern int ext2_clear_xip_target (struct inode *, int);
+extern int ext2_clear_xip_target (struct inode *, sector_t);
 
 static inline int ext2_use_xip (struct super_block *sb)
 {
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
 }
-struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
-#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+void *ext2_get_xip_address(struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_address)
 #else
 #define mapping_is_xip(map)			0
 #define ext2_xip_verify_sb(sb)			do { } while (0)
fs/open.c +1 -1
Index: linux-2.6/fs/open.c
===================================================================
@@ -778,7 +778,7 @@ static struct file *__dentry_open(struct
 	if (f->f_flags & O_DIRECT) {
 		if (!f->f_mapping->a_ops ||
 		    ((!f->f_mapping->a_ops->direct_IO) &&
-		    (!f->f_mapping->a_ops->get_xip_page))) {
+		    (!f->f_mapping->a_ops->get_xip_address))) {
 			fput(f);
 			f = ERR_PTR(-EINVAL);
 		}
include/linux/fs.h +1 -2
Index: linux-2.6/include/linux/fs.h
===================================================================
@@ -473,8 +473,7 @@ struct address_space_operations {
 	int (*releasepage) (struct page *, gfp_t);
 	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
-	struct page* (*get_xip_page)(struct address_space *, sector_t,
-			int);
+	void * (*get_xip_address)(struct address_space *, pgoff_t, int);
 	/* migrate the contents of a page to the specified target */
 	int (*migratepage) (struct address_space *,
 			struct page *, struct page *);
mm/fadvise.c +1 -1
Index: linux-2.6/mm/fadvise.c
===================================================================
@@ -49,7 +49,7 @@ asmlinkage long sys_fadvise64_64(int fd,
 		goto out;
 	}
 
-	if (mapping->a_ops->get_xip_page)
+	if (mapping->a_ops->get_xip_address)
 		/* no bad return value, but ignore advice */
 		goto out;
 
mm/filemap_xip.c +87 -92

337 lines not on this page · raw message

mm/madvise.c +1 -1
Index: linux-2.6/mm/madvise.c
===================================================================
@@ -112,7 +112,7 @@ static long madvise_willneed(struct vm_a
 	if (!file)
 		return -EBADF;
 
-	if (file->f_mapping->a_ops->get_xip_page) {
+	if (file->f_mapping->a_ops->get_xip_address) {
 		/* no bad return value, but ignore advice */
 		return 0;
 	}

--
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>

#75 lore raw

RFC PATCH 4/4 s390: remove struct page entries for DCSS memory segments

In reply to a message not in the archive

s390: remove struct page entries for DCSS memory segments

This patch removes struct page entries for DCSS segments that are being loaded.

---

arch/s390/mm/vmem.c +1 -17
Index: linux-2.6/arch/s390/mm/vmem.c
===================================================================
@@ -310,8 +310,6 @@ out:
 int add_shared_memory(unsigned long start, unsigned long size)
 {
 	struct memory_segment *seg;
-	struct page *page;
-	unsigned long pfn, num_pfn, end_pfn;
 	int ret;
 
 	mutex_lock(&vmem_mutex);
@@ -326,24 +324,10 @@ int add_shared_memory(unsigned long star
 	if (ret)
 		goto out_free;
 
-	ret = vmem_add_mem(start, size);
+	ret = vmem_add_range(start, size);
 	if (ret)
 		goto out_remove;
 
-	pfn = PFN_DOWN(start);
-	num_pfn = PFN_DOWN(size);
-	end_pfn = pfn + num_pfn;
-
-	page = pfn_to_page(pfn);
-	memset(page, 0, num_pfn * sizeof(struct page));
-
-	for (; pfn < end_pfn; pfn++) {
-		page = pfn_to_page(pfn);
-		init_page_count(page);
-		reset_page_mapcount(page);
-		SetPageReserved(page);
-		INIT_LIST_HEAD(&page->lru);
-	}
 	goto out;
 
 out_remove:

--
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>

A message that is not in the archive (sent off-list or not yet received): [email protected]

#77 lore raw

RFC PATCH 1/4 mm: introduce VM_MIXEDMAP

mm: introduce VM_MIXEDMAP

Introduce a new type of mapping, VM_MIXEDMAP. This is unlike VM_PFNMAP in that it can support COW mappings of arbitrary ranges including ranges without struct page (PFNMAP can only support COW in those cases where the un-COW-ed translations are mapped linearly in the virtual address).

VM_MIXEDMAP achieves this by refcounting pages with mixedmap_refcount_pfn(pfn) being non-zero, and not refcounting !mixedmap_refcount_pfn(pfn) pages (which is not an option for VM_PFNMAP, because it needs to avoid refcounting pfn_valid pages eg. for /dev/mem mappings).

---

include/linux/mm.h +1 -0
Index: linux-2.6/include/linux/mm.h
===================================================================
@@ -106,6 +106,7 @@ extern unsigned int kobjsize(const void 
 #define VM_ALWAYSDUMP	0x04000000	/* Always include in core dumps */
 
 #define VM_CAN_NONLINEAR 0x08000000	/* Has ->fault & does nonlinear pages */
+#define VM_MIXEDMAP	0x10000000	/* Can contain "struct page" and pure PFN pages */
 
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
mm/memory.c +59 -21

118 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>

#78 lore raw

RFC PATCH 2/4 xip: support non-struct page memory

In reply to a message not in the archive

Convert XIP to support non-struct page backed memory, using VM_MIXEDMAP for the user mappings.

This requires the get_xip_page API to be changed to an address based one.

(The kaddr->pfn conversion may not be quite right for all architectures or XIP memory mappings, and the cacheflushing may need to be updated for some archs).

---

fs/ext2/inode.c +1 -1
Index: linux-2.6/fs/ext2/inode.c
===================================================================
@@ -800,7 +800,7 @@ const struct address_space_operations ex
 
 const struct address_space_operations ext2_aops_xip = {
 	.bmap			= ext2_bmap,
-	.get_xip_page		= ext2_get_xip_page,
+	.get_xip_address	= ext2_get_xip_address,
 };
 
 const struct address_space_operations ext2_nobh_aops = {
fs/ext2/xip.c +18 -18
Index: linux-2.6/fs/ext2/xip.c
===================================================================
@@ -15,24 +15,25 @@
 #include "xip.h"
 
 static inline int
-__inode_direct_access(struct inode *inode, sector_t sector,
-		      unsigned long *data)
+__inode_direct_access(struct inode *inode, sector_t block, unsigned long *data)
 {
+	sector_t sector;
 	BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+
+	sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */
 	return inode->i_sb->s_bdev->bd_disk->fops
-		->direct_access(inode->i_sb->s_bdev,sector,data);
+		->direct_access(inode->i_sb->s_bdev, sector, data);
 }
 
 static inline int
-__ext2_get_sector(struct inode *inode, sector_t offset, int create,
+__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create,
 		   sector_t *result)
 {
 	struct buffer_head tmp;
 	int rc;
 
 	memset(&tmp, 0, sizeof(struct buffer_head));
-	rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &tmp,
-			    create);
+	rc = ext2_get_block(inode, pgoff, &tmp, create);
 	*result = tmp.b_blocknr;
 
 	/* did we get a sparse block (hole in the file)? */
@@ -45,13 +46,12 @@ __ext2_get_sector(struct inode *inode, s
 }
 
 int
-ext2_clear_xip_target(struct inode *inode, int block)
+ext2_clear_xip_target(struct inode *inode, sector_t block)
 {
-	sector_t sector = block * (PAGE_SIZE/512);
 	unsigned long data;
 	int rc;
 
-	rc = __inode_direct_access(inode, sector, &data);
+	rc = __inode_direct_access(inode, block, &data);
 	if (!rc)
 		clear_page((void*)data);
 	return rc;
@@ -69,24 +69,24 @@ void ext2_xip_verify_sb(struct super_blo
 	}
 }
 
-struct page *
-ext2_get_xip_page(struct address_space *mapping, sector_t offset,
-		   int create)
+void *
+ext2_get_xip_address(struct address_space *mapping, pgoff_t pgoff, int create)
 {
 	int rc;
 	unsigned long data;
-	sector_t sector;
+	sector_t block;
 
 	/* first, retrieve the sector number */
-	rc = __ext2_get_sector(mapping->host, offset, create, &sector);
+	rc = __ext2_get_block(mapping->host, pgoff, create, &block);
 	if (rc)
 		goto error;
 
 	/* retrieve address of the target data */
-	rc = __inode_direct_access
-		(mapping->host, sector * (PAGE_SIZE/512), &data);
-	if (!rc)
-		return virt_to_page(data);
+	rc = __inode_direct_access(mapping->host, block, &data);
+	if (rc)
+		goto error;
+
+	return (void *)data;
 
  error:
 	return ERR_PTR(rc);
fs/ext2/xip.h +3 -3
Index: linux-2.6/fs/ext2/xip.h
===================================================================
@@ -7,15 +7,15 @@
 
 #ifdef CONFIG_EXT2_FS_XIP
 extern void ext2_xip_verify_sb (struct super_block *);
-extern int ext2_clear_xip_target (struct inode *, int);
+extern int ext2_clear_xip_target (struct inode *, sector_t);
 
 static inline int ext2_use_xip (struct super_block *sb)
 {
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
 }
-struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
-#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+void *ext2_get_xip_address(struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_address)
 #else
 #define mapping_is_xip(map)			0
 #define ext2_xip_verify_sb(sb)			do { } while (0)
fs/open.c +1 -1
Index: linux-2.6/fs/open.c
===================================================================
@@ -778,7 +778,7 @@ static struct file *__dentry_open(struct
 	if (f->f_flags & O_DIRECT) {
 		if (!f->f_mapping->a_ops ||
 		    ((!f->f_mapping->a_ops->direct_IO) &&
-		    (!f->f_mapping->a_ops->get_xip_page))) {
+		    (!f->f_mapping->a_ops->get_xip_address))) {
 			fput(f);
 			f = ERR_PTR(-EINVAL);
 		}
include/linux/fs.h +1 -2
Index: linux-2.6/include/linux/fs.h
===================================================================
@@ -473,8 +473,7 @@ struct address_space_operations {
 	int (*releasepage) (struct page *, gfp_t);
 	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
-	struct page* (*get_xip_page)(struct address_space *, sector_t,
-			int);
+	void * (*get_xip_address)(struct address_space *, pgoff_t, int);
 	/* migrate the contents of a page to the specified target */
 	int (*migratepage) (struct address_space *,
 			struct page *, struct page *);
mm/fadvise.c +1 -1
Index: linux-2.6/mm/fadvise.c
===================================================================
@@ -49,7 +49,7 @@ asmlinkage long sys_fadvise64_64(int fd,
 		goto out;
 	}
 
-	if (mapping->a_ops->get_xip_page)
+	if (mapping->a_ops->get_xip_address)
 		/* no bad return value, but ignore advice */
 		goto out;
 
mm/filemap_xip.c +90 -92

340 lines not on this page · raw message

mm/madvise.c +1 -1
Index: linux-2.6/mm/madvise.c
===================================================================
@@ -112,7 +112,7 @@ static long madvise_willneed(struct vm_a
 	if (!file)
 		return -EBADF;
 
-	if (file->f_mapping->a_ops->get_xip_page) {
+	if (file->f_mapping->a_ops->get_xip_address) {
 		/* no bad return value, but ignore advice */
 		return 0;
 	}

--
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>

#79 lore raw

RFC PATCH 3/4 s390: remove sturct page entries for z/VM DCSS memory segments

In reply to a message not in the archive

This patch removes the creation of struct page entries for z/VM DCSS memory segments that are being loaded.

---

arch/s390/mm/vmem.c +1 -17
Index: linux-2.6/arch/s390/mm/vmem.c
===================================================================
@@ -310,8 +310,6 @@ out:
 int add_shared_memory(unsigned long start, unsigned long size)
 {
 	struct memory_segment *seg;
-	struct page *page;
-	unsigned long pfn, num_pfn, end_pfn;
 	int ret;
 
 	mutex_lock(&vmem_mutex);
@@ -326,24 +324,10 @@ int add_shared_memory(unsigned long star
 	if (ret)
 		goto out_free;
 
-	ret = vmem_add_mem(start, size);
+	ret = vmem_add_range(start, size);
 	if (ret)
 		goto out_remove;
 
-	pfn = PFN_DOWN(start);
-	num_pfn = PFN_DOWN(size);
-	end_pfn = pfn + num_pfn;
-
-	page = pfn_to_page(pfn);
-	memset(page, 0, num_pfn * sizeof(struct page));
-
-	for (; pfn < end_pfn; pfn++) {
-		page = pfn_to_page(pfn);
-		init_page_count(page);
-		reset_page_mapcount(page);
-		SetPageReserved(page);
-		INIT_LIST_HEAD(&page->lru);
-	}
 	goto out;
 
 out_remove:

--
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>

#80 lore raw

RFC PATCH 4/4 s390: mixedmap_refcount_pfn implementation using list walk

In reply to a message not in the archive

This patch implements mixedmap_refcount_pfn() for s390 architecture using list-walk. This is merely meant to be a proof of concept, because we do prefer spending one valuable pte bit to speed this up.

---

arch/s390/mm/vmem.c +20 -0
Index: linux-2.6/arch/s390/mm/vmem.c
===================================================================
@@ -339,6 +339,26 @@ out:
 	return ret;
 }
 
+int mixedmap_refcount_pfn(unsigned long pfn)
+{
+	int rc;
+	struct memory_segment *tmp;
+
+	mutex_lock(&vmem_mutex);
+
+	list_for_each_entry(tmp, &mem_segs, list) {
+		if ((tmp->start >= pfn << PAGE_SHIFT) &&
+		    (tmp->start + tmp->size - 1 < pfn << PAGE_SHIFT)) {
+			rc = 0;
+			goto out;
+		}
+	}
+	rc = 1;
+out:
+	mutex_unlock(&vmem_mutex);
+	return rc;
+}
+
 /*
  * map whole physical memory to virtual memory (identity mapping)
  */
include/linux/mm.h +7 -0
Index: linux-2.6/include/linux/mm.h
===================================================================
@@ -28,6 +28,13 @@ extern unsigned long num_physpages;
 extern void * high_memory;
 extern int page_cluster;
 
+/*
+ * This callback is only needed when using VM_MIXEDMAP. It is used by common
+ * code to check if a pfn needs refcounting in the corresponding struct page.
+ */
+extern int mixedmap_refcount_pfn(unsigned long pfn);
+
+
 #ifdef CONFIG_SYSCTL
 extern int sysctl_legacy_va_layout;
 #else

--
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>