version 1.63, 2016/09/29 19:08:48 |
version 1.63.2.1, 2017/04/21 16:54:03 |
Line 129 genfs_getpages(void *v) |
|
Line 129 genfs_getpages(void *v) |
|
const bool overwrite = (flags & PGO_OVERWRITE) != 0; |
const bool overwrite = (flags & PGO_OVERWRITE) != 0; |
const bool blockalloc = memwrite && (flags & PGO_NOBLOCKALLOC) == 0; |
const bool blockalloc = memwrite && (flags & PGO_NOBLOCKALLOC) == 0; |
const bool glocked = (flags & PGO_GLOCKHELD) != 0; |
const bool glocked = (flags & PGO_GLOCKHELD) != 0; |
const bool need_wapbl = blockalloc && vp->v_mount->mnt_wapbl; |
bool holds_wapbl = false; |
bool has_trans_wapbl = false; |
struct mount *trans_mount = NULL; |
UVMHIST_FUNC("genfs_getpages"); UVMHIST_CALLED(ubchist); |
UVMHIST_FUNC("genfs_getpages"); UVMHIST_CALLED(ubchist); |
|
|
UVMHIST_LOG(ubchist, "vp %p off 0x%x/%x count %d", |
UVMHIST_LOG(ubchist, "vp %p off 0x%x/%x count %d", |
|
|
UVMHIST_LOG(ubchist, "ridx %d npages %d startoff %ld endoff %ld", |
UVMHIST_LOG(ubchist, "ridx %d npages %d startoff %ld endoff %ld", |
ridx, npages, startoffset, endoffset); |
ridx, npages, startoffset, endoffset); |
|
|
if (!has_trans_wapbl) { |
if (trans_mount == NULL) { |
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
trans_mount = vp->v_mount; |
|
fstrans_start(trans_mount, FSTRANS_SHARED); |
|
/* |
|
* check if this vnode is still valid. |
|
*/ |
|
mutex_enter(vp->v_interlock); |
|
error = vdead_check(vp, 0); |
|
mutex_exit(vp->v_interlock); |
|
if (error) |
|
goto out_err_free; |
/* |
/* |
* XXX: This assumes that we come here only via |
* XXX: This assumes that we come here only via |
* the mmio path |
* the mmio path |
*/ |
*/ |
if (need_wapbl) { |
if (blockalloc && vp->v_mount->mnt_wapbl) { |
error = WAPBL_BEGIN(vp->v_mount); |
error = WAPBL_BEGIN(trans_mount); |
if (error) { |
if (error) |
fstrans_done(vp->v_mount); |
|
goto out_err_free; |
goto out_err_free; |
} |
holds_wapbl = true; |
} |
} |
has_trans_wapbl = true; |
|
} |
} |
|
|
/* |
/* |
|
|
mutex_exit(uobj->vmobjlock); |
mutex_exit(uobj->vmobjlock); |
error = genfs_getpages_read(vp, pgs, npages, startoffset, diskeof, |
error = genfs_getpages_read(vp, pgs, npages, startoffset, diskeof, |
async, memwrite, blockalloc, glocked); |
async, memwrite, blockalloc, glocked); |
if (error == 0 && async) |
|
goto out_err_free; |
|
if (!glocked) { |
if (!glocked) { |
genfs_node_unlock(vp); |
genfs_node_unlock(vp); |
} |
} |
|
if (error == 0 && async) |
|
goto out_err_free; |
mutex_enter(uobj->vmobjlock); |
mutex_enter(uobj->vmobjlock); |
|
|
/* |
/* |
|
|
if (pgs != NULL && pgs != pgs_onstack) |
if (pgs != NULL && pgs != pgs_onstack) |
kmem_free(pgs, pgs_size); |
kmem_free(pgs, pgs_size); |
out_err: |
out_err: |
if (has_trans_wapbl) { |
if (trans_mount != NULL) { |
if (need_wapbl) |
if (holds_wapbl) |
WAPBL_END(vp->v_mount); |
WAPBL_END(trans_mount); |
fstrans_done(vp->v_mount); |
fstrans_done(trans_mount); |
} |
} |
return error; |
return error; |
} |
} |
|
|
/* |
/* |
* genfs_getpages_read: Read the pages in with VOP_BMAP/VOP_STRATEGY. |
* genfs_getpages_read: Read the pages in with VOP_BMAP/VOP_STRATEGY. |
|
* |
|
* "glocked" (which is currently not actually used) tells us not whether |
|
* the genfs_node is locked on entry (it always is) but whether it was |
|
* locked on entry to genfs_getpages. |
*/ |
*/ |
static int |
static int |
genfs_getpages_read(struct vnode *vp, struct vm_page **pgs, int npages, |
genfs_getpages_read(struct vnode *vp, struct vm_page **pgs, int npages, |
|
|
nestiobuf_done(mbp, skipbytes, error); |
nestiobuf_done(mbp, skipbytes, error); |
if (async) { |
if (async) { |
UVMHIST_LOG(ubchist, "returning 0 (async)",0,0,0,0); |
UVMHIST_LOG(ubchist, "returning 0 (async)",0,0,0,0); |
if (!glocked) { |
|
genfs_node_unlock(vp); |
|
} |
|
return 0; |
return 0; |
} |
} |
if (bp != NULL) { |
if (bp != NULL) { |
Line 835 genfs_do_putpages(struct vnode *vp, off_ |
|
Line 843 genfs_do_putpages(struct vnode *vp, off_ |
|
bool pagedaemon = curlwp == uvm.pagedaemon_lwp; |
bool pagedaemon = curlwp == uvm.pagedaemon_lwp; |
struct lwp * const l = curlwp ? curlwp : &lwp0; |
struct lwp * const l = curlwp ? curlwp : &lwp0; |
struct genfs_node * const gp = VTOG(vp); |
struct genfs_node * const gp = VTOG(vp); |
|
struct mount *trans_mp; |
int flags; |
int flags; |
int dirtygen; |
int dirtygen; |
bool modified; |
bool modified; |
bool need_wapbl; |
bool holds_wapbl; |
bool has_trans; |
|
bool cleanall; |
bool cleanall; |
bool onworklst; |
bool onworklst; |
|
|
Line 852 genfs_do_putpages(struct vnode *vp, off_ |
|
Line 860 genfs_do_putpages(struct vnode *vp, off_ |
|
UVMHIST_LOG(ubchist, "vp %p pages %d off 0x%x len 0x%x", |
UVMHIST_LOG(ubchist, "vp %p pages %d off 0x%x len 0x%x", |
vp, uobj->uo_npages, startoff, endoff - startoff); |
vp, uobj->uo_npages, startoff, endoff - startoff); |
|
|
has_trans = false; |
trans_mp = NULL; |
need_wapbl = (!pagedaemon && vp->v_mount && vp->v_mount->mnt_wapbl && |
holds_wapbl = false; |
(origflags & PGO_JOURNALLOCKED) == 0); |
|
|
|
retry: |
retry: |
modified = false; |
modified = false; |
|
|
if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL) |
if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL) |
vn_syncer_remove_from_worklist(vp); |
vn_syncer_remove_from_worklist(vp); |
} |
} |
if (has_trans) { |
if (trans_mp) { |
if (need_wapbl) |
if (holds_wapbl) |
WAPBL_END(vp->v_mount); |
WAPBL_END(trans_mp); |
fstrans_done(vp->v_mount); |
fstrans_done(trans_mp); |
} |
} |
mutex_exit(slock); |
mutex_exit(slock); |
return (0); |
return (0); |
|
|
* the vnode has pages, set up to process the request. |
* the vnode has pages, set up to process the request. |
*/ |
*/ |
|
|
if (!has_trans && (flags & PGO_CLEANIT) != 0) { |
if (trans_mp == NULL && (flags & PGO_CLEANIT) != 0) { |
mutex_exit(slock); |
|
if (pagedaemon) { |
if (pagedaemon) { |
error = fstrans_start_nowait(vp->v_mount, FSTRANS_LAZY); |
/* Pagedaemon must not sleep here. */ |
if (error) |
trans_mp = vp->v_mount; |
return error; |
error = fstrans_start_nowait(trans_mp, FSTRANS_SHARED); |
} else |
|
fstrans_start(vp->v_mount, FSTRANS_LAZY); |
|
if (need_wapbl) { |
|
error = WAPBL_BEGIN(vp->v_mount); |
|
if (error) { |
if (error) { |
fstrans_done(vp->v_mount); |
mutex_exit(slock); |
return error; |
return error; |
} |
} |
|
} else { |
|
/* |
|
* Cannot use vdeadcheck() here as this operation |
|
* usually gets used from VOP_RECLAIM(). Test for |
|
* change of v_mount instead and retry on change. |
|
*/ |
|
mutex_exit(slock); |
|
trans_mp = vp->v_mount; |
|
fstrans_start(trans_mp, FSTRANS_SHARED); |
|
if (vp->v_mount != trans_mp) { |
|
fstrans_done(trans_mp); |
|
trans_mp = NULL; |
|
} else { |
|
holds_wapbl = (trans_mp->mnt_wapbl && |
|
(origflags & PGO_JOURNALLOCKED) == 0); |
|
if (holds_wapbl) { |
|
error = WAPBL_BEGIN(trans_mp); |
|
if (error) { |
|
fstrans_done(trans_mp); |
|
return error; |
|
} |
|
} |
|
} |
|
mutex_enter(slock); |
|
goto retry; |
} |
} |
has_trans = true; |
|
mutex_enter(slock); |
|
goto retry; |
|
} |
} |
|
|
error = 0; |
error = 0; |
|
|
goto retry; |
goto retry; |
} |
} |
|
|
if (has_trans) { |
if (trans_mp) { |
if (need_wapbl) |
if (holds_wapbl) |
WAPBL_END(vp->v_mount); |
WAPBL_END(trans_mp); |
fstrans_done(vp->v_mount); |
fstrans_done(trans_mp); |
} |
} |
|
|
return (error); |
return (error); |