On (16/12/2015 21:30), Gleb Smirnoff wrote:
> Author: glebius
> Date: Wed Dec 16 21:30:45 2015
> New Revision: 292373
> URL: https://svnweb.freebsd.org/changeset/base/292373
> 
> Log:
>   A change to KPI of vm_pager_get_pages() and underlying VOP_GETPAGES().
>   
>   o With new KPI consumers can request contiguous ranges of pages, and
>     unlike before, all pages will be kept busied on return, like it was
>     done before with the 'reqpage' only. Now the reqpage goes away. With
>     new interface it is easier to implement code protected from race
>     conditions.
>   
>     Such arrayed requests for now should be preceeded by a call to
>     vm_pager_haspage() to make sure that request is possible. This
>     could be improved later, making vm_pager_haspage() obsolete.

vm_pager_haspage is essentially wrapper around VOP_BMAP. VOP_BMAP is a
stub for all non UFS-like file systems.  E.g. it's return (0) in zfs and
return (EOPNOTSUPP) in tmpfs.

Could you elaborate on how strong the requirement of "should be preceded
by a call to vm_pager_haspage" is. It's also not clear how to approach
it if file system doesn't have bmap and getpages/putpages, but uses
standard fallback pager through read/write.

You've added vm_pager_has_page to exec_map_first_page. Should we now
assume that vm_pager_get_pages(VM_INITIAL_PAGEIN) may fail if 'after'
returned by vm_pager_has_page is less than VM_INITIAL_PAGEIN?

Could you please take a look at 2 patches attached. I'd like to commit
the one fixing vnode_pager_haspage, but I'm not sure about
vm_pager_has_page usage in exec_map_first_page.


0001-Emulate-vop_stdbmap-in-vnode_pager_haspage-if-bmap-i.patch
        
'after' will be uninitialized if VOP_BMAP returns error.  KASSERT in
exec_map_first_page may fail because of it.  I'm not sure if after = 0
is currently expected in exec_map_first_page.

Extend the logic to treat EOPNOTSUPP as vop_stdbmap (set before and
after to 0). Then extend both to fs block size.


0002-Handle-vm_pager_has_page-failure-during-exec.patch

Patch may be dropped if vm_pager_has_page is required to succeed as
described above.

Thanks,
Gleb.
>From 40978eba392bcb20bf59704eac3d744d15f1e080 Mon Sep 17 00:00:00 2001
From: Gleb Kurtsou <gleb.kurt...@gmail.com>
Date: Sat, 13 Feb 2016 23:00:00 -0800
Subject: [PATCH 1/2] Emulate vop_stdbmap in vnode_pager_haspage if bmap is not
 supported fs.

Reset 'before' and 'after' to zero if VOP_BMAP fails. Assume no error
if bmap is not supported by file system and adjust 'before', 'after'
accordingly.
---
 sys/vm/vnode_pager.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 66dd29d7686..063d8d55495 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -321,32 +321,39 @@ vnode_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
 	if (IDX_TO_OFF(pindex) >= object->un_pager.vnp.vnp_size)
 		return FALSE;
 
 	bsize = vp->v_mount->mnt_stat.f_iosize;
 	pagesperblock = bsize / PAGE_SIZE;
 	blocksperpage = 0;
 	if (pagesperblock > 0) {
 		reqblock = pindex / pagesperblock;
 	} else {
 		blocksperpage = (PAGE_SIZE / bsize);
 		reqblock = pindex * blocksperpage;
 	}
 	VM_OBJECT_WUNLOCK(object);
 	err = VOP_BMAP(vp, reqblock, NULL, &bn, after, before);
 	VM_OBJECT_WLOCK(object);
-	if (err)
-		return TRUE;
+	if (err) {
+		if (before)
+			*before = 0;
+		if (after)
+			*after = 0;
+		if (err != EOPNOTSUPP)
+			return TRUE;
+		bn = reqblock;
+	}
 	if (bn == -1)
 		return FALSE;
 	if (pagesperblock > 0) {
 		poff = pindex - (reqblock * pagesperblock);
 		if (before) {
 			*before *= pagesperblock;
 			*before += poff;
 		}
 		if (after) {
 			/*
 			 * The BMAP vop can report a partial block in the
 			 * 'after', but must not report blocks after EOF.
 			 * Assert the latter, and truncate 'after' in case
 			 * of the former.
 			 */
-- 
2.4.2

>From 0d4ed2d975a796b612914ee70b82064ba5fa19e3 Mon Sep 17 00:00:00 2001
From: Gleb Kurtsou <gleb.kurt...@gmail.com>
Date: Sat, 13 Feb 2016 23:07:50 -0800
Subject: [PATCH 2/2] Handle vm_pager_has_page failure during exec.

Relax exec_map_first_page dependency on vm_pager_has_page to calculate
initial number of pages. r292373 changed behavior to completely rely on
vm_pager_has_page().

Fallback to VM_INITIAL_PAGEIN if vm_pager_has_page fails or number of
pages reported as available ('after' argument) is zero.
---
 sys/kern/kern_exec.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 741bc3e48c6..e71a32fca09 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -954,39 +954,34 @@ exec_map_first_page(imgp)
 	vm_page_t ma[VM_INITIAL_PAGEIN];
 	vm_object_t object;
 
 	if (imgp->firstpage != NULL)
 		exec_unmap_first_page(imgp);
 
 	object = imgp->vp->v_object;
 	if (object == NULL)
 		return (EACCES);
 	VM_OBJECT_WLOCK(object);
 #if VM_NRESERVLEVEL > 0
 	vm_object_color(object, 0);
 #endif
 	ma[0] = vm_page_grab(object, 0, VM_ALLOC_NORMAL);
 	if (ma[0]->valid != VM_PAGE_BITS_ALL) {
-		if (!vm_pager_has_page(object, 0, NULL, &after)) {
-			vm_page_lock(ma[0]);
-			vm_page_free(ma[0]);
-			vm_page_unlock(ma[0]);
-			vm_page_xunbusy(ma[0]);
-			VM_OBJECT_WUNLOCK(object);
-			return (EIO);
-		}
-		initial_pagein = min(after, VM_INITIAL_PAGEIN);
+		if (vm_pager_has_page(object, 0, NULL, &after) && after > 0)
+			initial_pagein = min(after, VM_INITIAL_PAGEIN);
+		else
+			initial_pagein = min(object->size, VM_INITIAL_PAGEIN);
 		KASSERT(initial_pagein <= object->size,
 		    ("%s: initial_pagein %d object->size %ju",
 		    __func__, initial_pagein, (uintmax_t )object->size));
 		for (i = 1; i < initial_pagein; i++) {
 			if ((ma[i] = vm_page_next(ma[i - 1])) != NULL) {
 				if (ma[i]->valid)
 					break;
 				if (vm_page_tryxbusy(ma[i]))
 					break;
 			} else {
 				ma[i] = vm_page_alloc(object, i,
 				    VM_ALLOC_NORMAL | VM_ALLOC_IFNOTCACHED);
 				if (ma[i] == NULL)
 					break;
 			}
-- 
2.4.2

_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to