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"