make vfs & filesystems use failable copying

Change the kernel to add features to vircopy and safecopies so that
transparent copy fixing won't happen to avoid deadlocks, and such copies
fail with EFAULT.

Transparently making copying work from filesystems (as normally done by
the kernel & VM when copying fails because of missing/readonly memory)
is problematic as it can happen that, for file-mapped ranges, that that
same filesystem that is blocked on the copy request is needed to satisfy
the memory range, leading to deadlock. Dito for VFS itself, if done with
a blocking call.

This change makes the copying done from a filesystem fail in such cases
with EFAULT by VFS adding the CPF_TRY flag to the grants. If a FS call
fails with EFAULT, VFS will then request the range to be made available
to VM after the FS is unblocked, allowing it to be used to satisfy the
range if need be in another VFS thread.

Similarly, for datacopies that VFS itself does, it uses the failable
vircopy variant and callers use a wrapper that talk to VM if necessary
to get the copy to work.

	. kernel: add CPF_TRY flag to safecopies
	. kernel: only request writable ranges to VM for the
	  target buffer when copying fails
	. do copying in VFS TRY-first
	. some fixes in VM to build SANITYCHECK mode
	. add regression test for the cases where
	  - a FS system call needs memory mapped in a process that the
	    FS itself must map.
	  - such a range covers more than one file-mapped region.
	. add 'try' mode to vircopy, physcopy
	. add flags field to copy kernel call messages
	. if CP_FLAG_TRY is set, do not transparently try
	  to fix memory ranges
	. for use by VFS when accessing user buffers to avoid
	  deadlock
	. remove some obsolete backwards compatability assignments
        . VFS: let thread scheduling work for VM requests too
          Allows VFS to make calls to VM while suspending and resuming
          the currently running thread. Does currently not work for the
          main thread.
        . VM: add fix memory range call for use by VFS

Change-Id: I295794269cea51a3163519a9cfe5901301d90b32
This commit is contained in:
Ben Gras 2014-01-16 14:22:13 +01:00 committed by Lionel Sambuc
parent 8c277f99f4
commit 565f13088f
58 changed files with 705 additions and 296 deletions

View file

@ -356,13 +356,12 @@
#define CP_DST_ENDPT m5_i2 /* process to copy to */
#define CP_DST_ADDR m5_l2 /* address where data go to */
#define CP_NR_BYTES m5_l3 /* number of bytes to copy */
#define CP_FLAGS m5_s2 /* number of bytes to copy */
#define CP_FLAG_TRY 0x01 /* do not transparently map */
#define UMAP_SEG m5_s1
/* only used for backwards compatability */
#define CP_SRC_SPACE_OBSOLETE m5_s1 /* T or D space (stack is also D) */
#define CP_DST_SPACE_OBSOLETE m5_s2 /* T or D space (stack is also D) */
/* Field names for SYS_VUMAP. */
#define VUMAP_ENDPT m10_i1 /* grant owner, or SELF for local addresses */
#define VUMAP_VADDR m10_l1 /* address of virtual (input) vector */
@ -476,7 +475,6 @@
/* Field names for SYS_SAFECOPY* */
#define SCP_FROM_TO m2_i1 /* from/to whom? */
#define SCP_SEG_OBSOLETE m2_i2 /* my own segment */
#define SCP_GID m2_i3 /* grant id */
#define SCP_OFFSET m2_l1 /* offset within grant */
#define SCP_ADDRESS m2_p1 /* my own address */
@ -493,8 +491,6 @@
#define VSCP_VEC_ADDR m2_p1 /* start of vector */
#define VSCP_VEC_SIZE m2_l2 /* elements in vector */
#define SMAP_SEG_OBSOLETE m2_p1
/* Field names for SYS_SPROF, _CPROF, _PROFBUF. */
#define PROF_ACTION m7_i1 /* start/stop/reset/get */
#define PROF_MEM_SIZE m7_i2 /* available memory for data */
@ -936,10 +932,14 @@
/* same args as VM_REMAP */
#define VM_PROCCTL (VM_RQ_BASE+45)
#define VMPCTL_PARAM m1_i1
#define VMPCTL_WHO m1_i2
#define VMPCTL_PARAM m9_l1
#define VMPCTL_WHO m9_l2
#define VMPCTL_M1 m9_l3
#define VMPCTL_LEN m9_l4
#define VMPCTL_FLAGS m9_l5
#define VMPPARAM_CLEAR 1 /* values for VMPCTL_PARAM */
#define VMPPARAM_HANDLEMEM 2
#define VM_VFS_MMAP (VM_RQ_BASE+46)

View file

@ -53,8 +53,6 @@
#define SEGMENT_TYPE 0xFF00 /* bit mask to get segment type */
#define SEGMENT_INDEX 0x00FF /* bit mask to get segment index */
#define D_OBSOLETE 1 /* proc[i].mem_map[D] is for data */
#define PHYS_SEG 0x0400 /* flag indicating entire physical memory */
#define LOCAL_VM_SEG 0x1000 /* same as LOCAL_SEG, but with vm lookup */

View file

@ -56,6 +56,9 @@ struct vscp_vec {
#define CPF_READ 0x000001 /* Granted process may read. */
#define CPF_WRITE 0x000002 /* Granted process may write. */
/* Grant flags. */
#define CPF_TRY 0x000010 /* Fail fast on unmapped memory. */
/* Internal flags. */
#define CPF_USED 0x000100 /* Grant slot in use. */
#define CPF_DIRECT 0x000200 /* Grant from this process to another. */

View file

@ -123,14 +123,15 @@ int sys_vtimer(endpoint_t proc_nr, int which, clock_t *newval, clock_t
int sys_irqctl(int request, int irq_vec, int policy, int *irq_hook_id);
/* Shorthands for sys_vircopy() and sys_physcopy() system calls. */
#define sys_datacopy sys_vircopy
#define sys_datacopy(p1, v1, p2, v2, len) sys_vircopy(p1, v1, p2, v2, len, 0)
#define sys_datacopy_try(p1, v1, p2, v2, len) sys_vircopy(p1, v1, p2, v2, len, CP_FLAG_TRY)
int sys_vircopy(endpoint_t src_proc, vir_bytes src_v,
endpoint_t dst_proc, vir_bytes dst_vir, phys_bytes bytes);
endpoint_t dst_proc, vir_bytes dst_vir, phys_bytes bytes, int flags);
#define sys_abscopy(src_phys, dst_phys, bytes) \
sys_physcopy(NONE, src_phys, NONE, dst_phys, bytes)
sys_physcopy(NONE, src_phys, NONE, dst_phys, bytes, 0)
int sys_physcopy(endpoint_t src_proc, vir_bytes src_vir,
endpoint_t dst_proc, vir_bytes dst_vir, phys_bytes bytes);
endpoint_t dst_proc, vir_bytes dst_vir, phys_bytes bytes, int flags);
/* Grant-based copy functions. */

View file

@ -67,7 +67,8 @@ int vm_info_stats(struct vm_stats_info *vfi);
int vm_info_usage(endpoint_t who, struct vm_usage_info *vui);
int vm_info_region(endpoint_t who, struct vm_region_info *vri, int
count, vir_bytes *next);
int vm_procctl(endpoint_t ep, int param);
int vm_procctl_clear(endpoint_t ep);
int vm_procctl_handlemem(endpoint_t ep, vir_bytes m1, vir_bytes m2, int wr);
int vm_set_cacheblock(void *block, dev_t dev, off_t dev_offset,
ino_t ino, off_t ino_offset, u32_t *flags, int blocksize);

View file

@ -398,7 +398,8 @@ size_t vm_lookup_range(const struct proc *proc, vir_bytes vir_addr,
* vm_suspend *
*===========================================================================*/
static void vm_suspend(struct proc *caller, const struct proc *target,
const vir_bytes linaddr, const vir_bytes len, const int type)
const vir_bytes linaddr, const vir_bytes len, const int type,
const int writeflag)
{
/* This range is not OK for this process. Set parameters
* of the request and notify VM about the pending request.
@ -412,7 +413,7 @@ static void vm_suspend(struct proc *caller, const struct proc *target,
caller->p_vmrequest.target = target->p_endpoint;
caller->p_vmrequest.params.check.start = linaddr;
caller->p_vmrequest.params.check.length = len;
caller->p_vmrequest.params.check.writeflag = 1;
caller->p_vmrequest.params.check.writeflag = writeflag;
caller->p_vmrequest.type = type;
/* Connect caller on vmrequest wait queue. */
@ -426,7 +427,7 @@ static void vm_suspend(struct proc *caller, const struct proc *target,
* vm_check_range *
*===========================================================================*/
int vm_check_range(struct proc *caller, struct proc *target,
vir_bytes vir_addr, size_t bytes)
vir_bytes vir_addr, size_t bytes, int writeflag)
{
/* Public interface to vm_suspend(), for use by kernel calls. On behalf
* of 'caller', call into VM to check linear virtual address range of
@ -442,7 +443,8 @@ int vm_check_range(struct proc *caller, struct proc *target,
(r = caller->p_vmrequest.vmresult) != OK)
return r;
vm_suspend(caller, target, vir_addr, bytes, VMSTYPE_KERNELCALL);
vm_suspend(caller, target, vir_addr, bytes, VMSTYPE_KERNELCALL,
writeflag);
return VMSUSPEND;
}
@ -520,7 +522,7 @@ int vm_memset(struct proc* caller, endpoint_t who, phys_bytes ph, int c,
/* If a process pagefaults, VM may help out */
if (whoptr) {
vm_suspend(caller, whoptr, ph, count,
VMSTYPE_KERNELCALL);
VMSTYPE_KERNELCALL, 1);
assert(catch_pagefaults);
catch_pagefaults = 0;
return VMSUSPEND;
@ -589,6 +591,7 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) {
int writeflag;
struct proc *target = NULL;
phys_bytes lin;
if(r != EFAULT_SRC && r != EFAULT_DST)
@ -600,9 +603,11 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
if(r == EFAULT_SRC) {
lin = vir_addr[_SRC_]->offset;
target = procs[_SRC_];
writeflag = 0;
} else if(r == EFAULT_DST) {
lin = vir_addr[_DST_]->offset;
target = procs[_DST_];
writeflag = 1;
} else {
panic("r strange: %d", r);
}
@ -610,7 +615,7 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
assert(caller);
assert(target);
vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL);
vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL, writeflag);
return VMSUSPEND;
}

View file

@ -72,7 +72,7 @@ int do_sdevio(struct proc * caller, message *m_ptr)
count,
req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ,
(vir_bytes) m_ptr->DIO_OFFSET,
&newoffset, &newep) != OK) {
&newoffset, &newep, NULL) != OK) {
printf("do_sdevio: verify_grant failed\n");
return EPERM;
}

View file

@ -421,7 +421,8 @@ size_t vm_lookup_range(const struct proc *proc, vir_bytes vir_addr,
* vm_suspend *
*===========================================================================*/
static void vm_suspend(struct proc *caller, const struct proc *target,
const vir_bytes linaddr, const vir_bytes len, const int type)
const vir_bytes linaddr, const vir_bytes len, const int type,
const int writeflag)
{
/* This range is not OK for this process. Set parameters
* of the request and notify VM about the pending request.
@ -437,7 +438,7 @@ static void vm_suspend(struct proc *caller, const struct proc *target,
caller->p_vmrequest.target = target->p_endpoint;
caller->p_vmrequest.params.check.start = linaddr;
caller->p_vmrequest.params.check.length = len;
caller->p_vmrequest.params.check.writeflag = 1;
caller->p_vmrequest.params.check.writeflag = writeflag;
caller->p_vmrequest.type = type;
/* Connect caller on vmrequest wait queue. */
@ -451,7 +452,7 @@ static void vm_suspend(struct proc *caller, const struct proc *target,
* vm_check_range *
*===========================================================================*/
int vm_check_range(struct proc *caller, struct proc *target,
vir_bytes vir_addr, size_t bytes)
vir_bytes vir_addr, size_t bytes, int writeflag)
{
/* Public interface to vm_suspend(), for use by kernel calls. On behalf
* of 'caller', call into VM to check linear virtual address range of
@ -467,7 +468,8 @@ int vm_check_range(struct proc *caller, struct proc *target,
(r = caller->p_vmrequest.vmresult) != OK)
return r;
vm_suspend(caller, target, vir_addr, bytes, VMSTYPE_KERNELCALL);
vm_suspend(caller, target, vir_addr, bytes, VMSTYPE_KERNELCALL,
writeflag);
return VMSUSPEND;
}
@ -619,7 +621,7 @@ int vm_memset(struct proc* caller, endpoint_t who, phys_bytes ph, int c,
/* If a process pagefaults, VM may help out */
if (whoptr) {
vm_suspend(caller, whoptr, ph, count,
VMSTYPE_KERNELCALL);
VMSTYPE_KERNELCALL, 1);
assert(catch_pagefaults);
catch_pagefaults = 0;
return VMSUSPEND;
@ -688,6 +690,7 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) {
int writeflag;
struct proc *target = NULL;
phys_bytes lin;
if(r != EFAULT_SRC && r != EFAULT_DST)
@ -699,9 +702,11 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
if(r == EFAULT_SRC) {
lin = vir_addr[_SRC_]->offset;
target = procs[_SRC_];
writeflag = 0;
} else if(r == EFAULT_DST) {
lin = vir_addr[_DST_]->offset;
target = procs[_DST_];
writeflag = 1;
} else {
panic("r strange: %d", r);
}
@ -709,7 +714,7 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
assert(caller);
assert(target);
vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL);
vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL, writeflag);
return VMSUSPEND;
}

View file

@ -138,7 +138,7 @@ void hook_ipc_clear(struct proc *proc);
/* system/do_safecopy.c */
int verify_grant(endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes, int,
vir_bytes, vir_bytes *, endpoint_t *);
vir_bytes, vir_bytes *, endpoint_t *, u32_t *);
/* system/do_diagctl.c */
int do_diagctl(struct proc * caller, message *m);
@ -211,7 +211,7 @@ int arch_phys_map_reply(int index, vir_bytes addr);
reg_t arch_get_sp(struct proc *p);
int arch_enable_paging(struct proc * caller);
int vm_check_range(struct proc *caller,
struct proc *target, vir_bytes vir_addr, size_t bytes);
struct proc *target, vir_bytes vir_addr, size_t bytes, int writable);
int copy_msg_from_user(message * user_mbuf, message * dst);
int copy_msg_to_user(message * src, message * user_mbuf);

View file

@ -10,7 +10,9 @@
*/
#include "kernel/system.h"
#include "kernel/vm.h"
#include <minix/type.h>
#include <assert.h>
#if (USE_VIRCOPY || USE_PHYSCOPY)
@ -75,8 +77,16 @@ int do_copy(struct proc * caller, message * m_ptr)
if (bytes != (phys_bytes) (vir_bytes) bytes) return(E2BIG);
/* Now try to make the actual virtual copy. */
return( virtual_copy_vmcheck(caller, &vir_addr[_SRC_],
if(m_ptr->CP_FLAGS & CP_FLAG_TRY) {
int r;
assert(caller->p_endpoint == VFS_PROC_NR);
r = virtual_copy(&vir_addr[_SRC_], &vir_addr[_DST_], bytes);
if(r == EFAULT_SRC || r == EFAULT_DST) return r = EFAULT;
return r;
} else {
return( virtual_copy_vmcheck(caller, &vir_addr[_SRC_],
&vir_addr[_DST_], bytes) );
}
}
#endif /* (USE_VIRCOPY || USE_PHYSCOPY) */

View file

@ -17,6 +17,7 @@
#include "kernel/system.h"
#include "kernel/kernel.h"
#include "kernel/vm.h"
#define MAX_INDIRECT_DEPTH 5 /* up to how many indirect grants to follow? */
@ -32,7 +33,7 @@ static int safecopy(struct proc *, endpoint_t, endpoint_t,
* verify_grant *
*===========================================================================*/
int verify_grant(granter, grantee, grant, bytes, access,
offset_in, offset_result, e_granter)
offset_in, offset_result, e_granter, flags)
endpoint_t granter, grantee; /* copyee, copyer */
cp_grant_id_t grant; /* grant id */
vir_bytes bytes; /* copy size */
@ -40,6 +41,7 @@ int access; /* direction (read/write) */
vir_bytes offset_in; /* copy offset within grant */
vir_bytes *offset_result; /* copy offset within virtual address space */
endpoint_t *e_granter; /* new granter (magic grants) */
u32_t *flags; /* CPF_* */
{
static cp_grant_t g;
static int proc_nr;
@ -96,6 +98,8 @@ endpoint_t *e_granter; /* new granter (magic grants) */
return EPERM;
}
if(flags) *flags = g.cp_flags;
/* Check validity. */
if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
(CPF_USED | CPF_VALID)) {
@ -241,6 +245,7 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
endpoint_t new_granter, *src, *dst;
struct proc *granter_p;
int r;
u32_t flags;
#if PERF_USE_COW_SAFECOPY
vir_bytes size;
#endif
@ -269,7 +274,7 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
/* Verify permission exists. */
if((r=verify_grant(granter, grantee, grantid, bytes, access,
g_offset, &v_offset, &new_granter)) != OK) {
g_offset, &v_offset, &new_granter, &flags)) != OK) {
printf(
"grant %d verify to copy %d->%d by %d failed: err %d\n",
grantid, *src, *dst, grantee, r);
@ -298,6 +303,13 @@ int access; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
}
/* Do the regular copy. */
if(flags & CPF_TRY) {
int r;
/* Try copy without transparently faulting in pages. */
r = virtual_copy(&v_src, &v_dst, bytes);
if(r == EFAULT_SRC || r == EFAULT_DST) return EFAULT;
return r;
}
return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
}

View file

@ -47,7 +47,7 @@ int do_safememset(struct proc *caller, message *m_ptr) {
/* Verify permission exists, memset always requires CPF_WRITE */
r = verify_grant(dst_endpt, caller_endpt, grantid, len, CPF_WRITE,
g_offset, &v_offset, &new_granter);
g_offset, &v_offset, &new_granter, NULL);
if (r != OK) {
printf("safememset: grant %d verify failed %d", grantid, r);

View file

@ -64,7 +64,7 @@ int do_umap_remote(struct proc * caller, message * m_ptr)
cp_grant_id_t grant = (cp_grant_id_t) offset;
if(verify_grant(targetpr->p_endpoint, grantee, grant, count,
0, 0, &newoffset, &newep) != OK) {
0, 0, &newoffset, &newep, NULL) != OK) {
printf("SYSTEM: do_umap: verify_grant in %s, grant %d, bytes 0x%lx, failed, caller %s\n", targetpr->p_name, offset, count, caller->p_name);
proc_stacktrace(caller);
return EFAULT;

View file

@ -78,7 +78,7 @@ int do_vumap(struct proc *caller, message *m_ptr)
if (source != SELF) {
r = verify_grant(source, endpt, vvec[i].vv_grant, size, access,
offset, &vir_addr, &granter);
offset, &vir_addr, &granter, NULL);
if (r != OK)
return r;
} else {
@ -103,7 +103,7 @@ int do_vumap(struct proc *caller, message *m_ptr)
/* This call may suspend the current call, or return an
* error for a previous invocation.
*/
return vm_check_range(caller, procp, vir_addr, size);
return vm_check_range(caller, procp, vir_addr, size, 1);
}
pvec[pcount].vp_addr = phys_addr;

View file

@ -53,7 +53,7 @@ int libexec_alloc_mmap_ondemand(struct exec_info *execi, vir_bytes vaddr, size_t
int libexec_clearproc_vm_procctl(struct exec_info *execi)
{
return vm_procctl(execi->proc_e, VMPPARAM_CLEAR);
return vm_procctl_clear(execi->proc_e);
}
int libexec_clear_sys_memset(struct exec_info *execi, vir_bytes vaddr, size_t len)

View file

@ -16,7 +16,7 @@
#include <string.h>
#define ACCESS_CHECK(a) { \
if((a) & ~(CPF_READ|CPF_WRITE)) { \
if((a) & ~(CPF_READ|CPF_WRITE|CPF_TRY)) { \
errno = EINVAL; \
return -1; \
} \

View file

@ -1,11 +1,12 @@
#include "syslib.h"
int sys_physcopy(src_proc, src_vir, dst_proc, dst_vir, bytes)
int sys_physcopy(src_proc, src_vir, dst_proc, dst_vir, bytes, flags)
endpoint_t src_proc; /* source process */
vir_bytes src_vir; /* source virtual address */
endpoint_t dst_proc; /* destination process */
vir_bytes dst_vir; /* destination virtual address */
phys_bytes bytes; /* how many bytes */
int flags; /* copy flags */
{
/* Transfer a block of data. The source and destination can each either be a
* process number or SELF (to indicate own process number). Virtual addresses
@ -21,12 +22,7 @@ phys_bytes bytes; /* how many bytes */
copy_mess.CP_DST_ENDPT = dst_proc;
copy_mess.CP_DST_ADDR = (long) dst_vir;
copy_mess.CP_NR_BYTES = (long) bytes;
/* provide backwards compatability arguments to old
* kernels based on process id's; NONE <=> physical
*/
copy_mess.CP_DST_SPACE_OBSOLETE = (dst_proc == NONE ? PHYS_SEG : D_OBSOLETE);
copy_mess.CP_SRC_SPACE_OBSOLETE = (src_proc == NONE ? PHYS_SEG : D_OBSOLETE);
copy_mess.CP_FLAGS = flags;
return(_kernel_call(SYS_PHYSCOPY, &copy_mess));
}

View file

@ -19,11 +19,6 @@ int sys_safecopyfrom(endpoint_t src_e,
copy_mess.SCP_ADDRESS = (char *) address;
copy_mess.SCP_BYTES = (long) bytes;
/* for older kernels that still need the 'seg' field
* provide the right value.
*/
copy_mess.SCP_SEG_OBSOLETE = D_OBSOLETE;
return(_kernel_call(SYS_SAFECOPYFROM, &copy_mess));
}
@ -44,11 +39,6 @@ int sys_safecopyto(endpoint_t dst_e,
copy_mess.SCP_ADDRESS = (char *) address;
copy_mess.SCP_BYTES = (long) bytes;
/* for older kernels that still need the 'seg' field
* provide the right value.
*/
copy_mess.SCP_SEG_OBSOLETE = D_OBSOLETE;
return(_kernel_call(SYS_SAFECOPYTO, &copy_mess));
}

View file

@ -1,30 +1,28 @@
#include "syslib.h"
int sys_vircopy(src_proc, src_vir,
dst_proc, dst_vir, bytes)
dst_proc, dst_vir, bytes, flags)
endpoint_t src_proc; /* source process */
vir_bytes src_vir; /* source virtual address */
endpoint_t dst_proc; /* destination process */
vir_bytes dst_vir; /* destination virtual address */
phys_bytes bytes; /* how many bytes */
int flags; /* copy flags */
{
/* Transfer a block of data. The source and destination can each either be a
* process number or SELF (to indicate own process number). Virtual addresses
* are offsets within LOCAL_SEG (text, stack, data), or BIOS_SEG.
* process number or SELF (to indicate own process number).
*/
message copy_mess;
if (bytes == 0L) return(OK);
memset(&copy_mess, 0, sizeof(copy_mess));
copy_mess.CP_SRC_ENDPT = src_proc;
copy_mess.CP_SRC_ADDR = (long) src_vir;
copy_mess.CP_DST_ENDPT = dst_proc;
copy_mess.CP_DST_ADDR = (long) dst_vir;
copy_mess.CP_NR_BYTES = (long) bytes;
/* backwards compatability D segs */
copy_mess.CP_DST_SPACE_OBSOLETE = D_OBSOLETE;
copy_mess.CP_SRC_SPACE_OBSOLETE = D_OBSOLETE;
copy_mess.CP_FLAGS = flags;
return(_kernel_call(SYS_VIRCOPY, &copy_mess));
}

View file

@ -5,9 +5,10 @@
#include <string.h>
/*===========================================================================*
* vm_exit *
* vm_procctl *
*===========================================================================*/
int vm_procctl(endpoint_t ep, int param)
static int vm_procctl(endpoint_t ep, int param,
vir_bytes m1, vir_bytes len, int flags)
{
message m;
int result;
@ -16,8 +17,22 @@ int vm_procctl(endpoint_t ep, int param)
m.VMPCTL_WHO = ep;
m.VMPCTL_PARAM = param;
m.VMPCTL_M1 = m1;
m.VMPCTL_LEN = len;
m.VMPCTL_FLAGS = flags;
result = _taskcall(VM_PROC_NR, VM_PROCCTL, &m);
return(result);
}
int vm_procctl_clear(endpoint_t ep)
{
return vm_procctl(ep, VMPPARAM_CLEAR, 0, 0, 0);
}
int vm_procctl_handlemem(endpoint_t ep, vir_bytes m1, vir_bytes len,
int writeflag)
{
return vm_procctl(ep, VMPPARAM_HANDLEMEM, m1, len, writeflag);
}

View file

@ -92,7 +92,7 @@ int do_sysuname()
/* Copy an uname string to the user. */
n = strlen(string) + 1;
if (n > m_in.PM_SYSUNAME_LEN) n = m_in.PM_SYSUNAME_LEN;
r = sys_vircopy(SELF, (phys_bytes) string,
r = sys_datacopy(SELF, (phys_bytes) string,
mp->mp_endpoint, (phys_bytes) m_in.PM_SYSUNAME_VALUE,
(phys_bytes) n);
if (r < 0) return(r);
@ -105,7 +105,7 @@ int do_sysuname()
if (mp->mp_effuid != 0 || len == 0) return(EPERM);
n = len < m_in.PM_SYSUNAME_LEN ? len : m_in.PM_SYSUNAME_LEN;
if (n <= 0) return(EINVAL);
r = sys_vircopy(mp->mp_endpoint, (phys_bytes) m_in.PM_SYSUNAME_VALUE,
r = sys_datacopy(mp->mp_endpoint, (phys_bytes) m_in.PM_SYSUNAME_VALUE,
SELF, (phys_bytes) tmp, (phys_bytes) n);
if (r < 0) return(r);
tmp[n-1] = 0;

View file

@ -175,11 +175,11 @@ int do_trace()
if (req == T_GETRANGE)
r = sys_vircopy(child->mp_endpoint, (vir_bytes) pr.pr_addr,
who_e, (vir_bytes) pr.pr_ptr,
(phys_bytes) pr.pr_size);
(phys_bytes) pr.pr_size, 0);
else
r = sys_vircopy(who_e, (vir_bytes) pr.pr_ptr,
child->mp_endpoint, (vir_bytes) pr.pr_addr,
(phys_bytes) pr.pr_size);
(phys_bytes) pr.pr_size, 0);
if (r != OK) return(r);

View file

@ -160,7 +160,7 @@ size_t seg_bytes /* how much is to be transferred? */
int r;
if (off+seg_bytes > execi->hdr_len) return ENOEXEC;
if((r= sys_vircopy(SELF, ((vir_bytes)execi->hdr)+off,
if((r= sys_datacopy(SELF, ((vir_bytes)execi->hdr)+off,
execi->proc_e, seg_addr, seg_bytes)) != OK) {
printf("RS: exec read_seg: copy 0x%x bytes into %i at 0x%08lx failed: %i\n",
seg_bytes, execi->proc_e, seg_addr, r);

View file

@ -913,7 +913,7 @@ message *m_ptr;
return EINVAL;
}
if((r=sys_vircopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_NAME,
if((r=sys_datacopy(m_ptr->m_source, (vir_bytes) m_ptr->RS_NAME,
SELF, (vir_bytes) namebuf, len)) != OK) {
printf("RS: name copy failed\n");
return r;

View file

@ -1,27 +1,29 @@
#include "fs.h"
#include <minix/vfsif.h>
#include <assert.h>
#include <string.h>
static int sendmsg(struct vmnt *vmp, struct worker_thread *wp);
static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp);
static int queuemsg(struct vmnt *vmp);
/*===========================================================================*
* sendmsg *
*===========================================================================*/
static int sendmsg(struct vmnt *vmp, struct worker_thread *wp)
static int sendmsg(struct vmnt *vmp, endpoint_t dst, struct worker_thread *wp)
{
/* This is the low level function that sends requests to FS processes.
/* This is the low level function that sends requests.
* Currently to FSes or VM.
*/
int r, transid;
vmp->m_comm.c_cur_reqs++; /* One more request awaiting a reply */
if(vmp) vmp->m_comm.c_cur_reqs++; /* One more request awaiting a reply */
transid = wp->w_tid + VFS_TRANSID;
wp->w_fs_sendrec->m_type = TRNS_ADD_ID(wp->w_fs_sendrec->m_type, transid);
wp->w_task = vmp->m_fs_e;
if ((r = asynsend3(vmp->m_fs_e, wp->w_fs_sendrec, AMF_NOREPLY)) != OK) {
wp->w_sendrec->m_type = TRNS_ADD_ID(wp->w_sendrec->m_type, transid);
wp->w_task = dst;
if ((r = asynsend3(dst, wp->w_sendrec, AMF_NOREPLY)) != OK) {
printf("VFS: sendmsg: error sending message. "
"FS_e: %d req_nr: %d err: %d\n", vmp->m_fs_e,
wp->w_fs_sendrec->m_type, r);
"dest: %d req_nr: %d err: %d\n", dst,
wp->w_sendrec->m_type, r);
util_stacktrace();
return(r);
}
@ -78,7 +80,7 @@ void fs_sendmore(struct vmnt *vmp)
worker->w_next = NULL;
sending--;
assert(sending >= 0);
(void) sendmsg(vmp, worker);
(void) sendmsg(vmp, vmp->m_fs_e, worker);
}
/*===========================================================================*
@ -139,13 +141,13 @@ int fs_sendrec(endpoint_t fs_e, message *reqmp)
}
if (fs_e == fp->fp_endpoint) return(EDEADLK);
self->w_fs_sendrec = reqmp; /* Where to store request and reply */
self->w_sendrec = reqmp; /* Where to store request and reply */
/* Find out whether we can send right away or have to enqueue */
if ( !(vmp->m_flags & VMNT_CALLBACK) &&
vmp->m_comm.c_cur_reqs < vmp->m_comm.c_max_reqs) {
/* There's still room to send more and no proc is queued */
r = sendmsg(vmp, self);
r = sendmsg(vmp, vmp->m_fs_e, self);
} else {
r = queuemsg(vmp);
}
@ -158,6 +160,53 @@ int fs_sendrec(endpoint_t fs_e, message *reqmp)
return(reqmp->m_type);
}
/*===========================================================================*
* vm_sendrec *
*===========================================================================*/
int vm_sendrec(message *reqmp)
{
int r;
assert(self);
assert(reqmp);
self->w_sendrec = reqmp; /* Where to store request and reply */
r = sendmsg(NULL, VM_PROC_NR, self);
self->w_next = NULL; /* End of list */
if (r != OK) return(r);
worker_wait(); /* Yield execution until we've received the reply. */
return(reqmp->m_type);
}
/*===========================================================================*
* vm_vfs_procctl_handlemem *
*===========================================================================*/
int vm_vfs_procctl_handlemem(endpoint_t ep,
vir_bytes mem, vir_bytes len, int flags)
{
message m;
/* main thread can not be suspended */
if(!self) return EFAULT;
memset(&m, 0, sizeof(m));
m.m_type = VM_PROCCTL;
m.VMPCTL_WHO = ep;
m.VMPCTL_PARAM = VMPPARAM_HANDLEMEM;
m.VMPCTL_M1 = mem;
m.VMPCTL_LEN = len;
m.VMPCTL_FLAGS = flags;
return vm_sendrec(&m);
}
/*===========================================================================*
* queuemsg *
*===========================================================================*/

View file

@ -303,7 +303,7 @@ static void dump_segments(struct filp *f, Elf_Phdr phdrs[], int phnum)
for (off = 0; off < (off_t) len; off += CLICK_SIZE) {
vir_bytes p = (vir_bytes) (seg_off + off);
r = sys_vircopy(fp->fp_endpoint, p,
r = sys_datacopy_try(fp->fp_endpoint, p,
SELF, (vir_bytes) buf,
(phys_bytes) CLICK_SIZE);

View file

@ -129,7 +129,8 @@ int do_mapdriver(void)
printf("VFS: do_mapdriver: label too long\n");
return(EINVAL);
}
r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len);
r = sys_vircopy(who_e, label_vir, SELF, (vir_bytes) label, label_len,
CP_FLAG_TRY);
if (r != OK) {
printf("VFS: do_mapdriver: sys_vircopy failed: %d\n", r);
return(EINVAL);

View file

@ -228,7 +228,7 @@ int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
if (frame_len > ARG_MAX)
FAILCHECK(ENOMEM); /* stack too big */
r = sys_datacopy(fp->fp_endpoint, (vir_bytes) frame, SELF, (vir_bytes) mbuf,
r = sys_datacopy_wrapper(fp->fp_endpoint, (vir_bytes) frame, SELF, (vir_bytes) mbuf,
(size_t) frame_len);
if (r != OK) { /* can't fetch stack (e.g. bad virtual addr) */
printf("VFS: pm_exec: sys_datacopy failed\n");
@ -362,7 +362,7 @@ int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
if(makestack) FAILCHECK(makestack(&execi, mbuf, &frame_len, &vsp));
/* Copy the stack from VFS to new core image. */
FAILCHECK(sys_datacopy(SELF, (vir_bytes) mbuf, fp->fp_endpoint,
FAILCHECK(sys_datacopy_wrapper(SELF, (vir_bytes) mbuf, fp->fp_endpoint,
(vir_bytes) vsp, (phys_bytes)frame_len));
/* Return new stack pointer to caller */

View file

@ -31,7 +31,7 @@ int req; /* either F_SETLK or F_SETLKW */
struct file_lock *flp, *flp2, *empty;
/* Fetch the flock structure from user space. */
r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer, VFS_PROC_NR,
r = sys_datacopy_wrapper(who_e, (vir_bytes) scratch(fp).io.io_buffer, VFS_PROC_NR,
(vir_bytes) &flock, sizeof(flock));
if (r != OK) return(EINVAL);
@ -141,7 +141,7 @@ int req; /* either F_SETLK or F_SETLKW */
}
/* Copy the flock structure back to the caller. */
r = sys_datacopy(VFS_PROC_NR, (vir_bytes) &flock, who_e,
r = sys_datacopy_wrapper(VFS_PROC_NR, (vir_bytes) &flock, who_e,
(vir_bytes) scratch(fp).io.io_buffer, sizeof(flock));
return(r);
}

View file

@ -35,7 +35,7 @@ EXTERN unsigned long calls_stats[NR_VFS_CALLS];
#endif
/* Thread related prototypes */
static void do_fs_reply(struct worker_thread *wp);
static void do_reply(struct worker_thread *wp);
static void do_work(void);
static void do_init_root(void);
static void handle_work(void (*func)(void));
@ -86,7 +86,7 @@ int main(void)
continue;
}
m_in.m_type = TRNS_DEL_ID(m_in.m_type);
do_fs_reply(wp);
do_reply(wp);
continue;
} else if (who_e == PM_PROC_NR) { /* Calls from PM */
/* Special control messages from PM */
@ -179,22 +179,22 @@ static void handle_work(void (*func)(void))
/*===========================================================================*
* do_fs_reply *
* do_reply *
*===========================================================================*/
static void do_fs_reply(struct worker_thread *wp)
static void do_reply(struct worker_thread *wp)
{
struct vmnt *vmp;
struct vmnt *vmp = NULL;
if ((vmp = find_vmnt(who_e)) == NULL)
if(who_e != VM_PROC_NR && (vmp = find_vmnt(who_e)) == NULL)
panic("Couldn't find vmnt for endpoint %d", who_e);
if (wp->w_task != who_e) {
printf("VFS: expected %d to reply, not %d\n", wp->w_task, who_e);
return;
printf("VFS: tid %d: expected %d to reply, not %d\n",
wp->w_tid, wp->w_task, who_e);
}
*wp->w_fs_sendrec = m_in;
*wp->w_sendrec = m_in;
wp->w_task = NONE;
vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */
if(vmp) vmp->m_comm.c_cur_reqs--; /* We've got our reply, make room for others */
worker_signal(wp); /* Continue this thread */
}

View file

@ -89,7 +89,7 @@ int do_getsysinfo(void)
if (len != buf_size)
return(EINVAL);
return sys_datacopy(SELF, src_addr, who_e, dst_addr, len);
return sys_datacopy_wrapper(SELF, src_addr, who_e, dst_addr, len);
}
/*===========================================================================*
@ -170,7 +170,7 @@ int do_fcntl(void)
else if (!(f->filp_mode & W_BIT)) r = EBADF;
else {
/* Copy flock data from userspace. */
r = sys_datacopy(who_e, (vir_bytes) scratch(fp).io.io_buffer,
r = sys_datacopy_wrapper(who_e, (vir_bytes) scratch(fp).io.io_buffer,
SELF, (vir_bytes) &flock_arg, sizeof(flock_arg));
}
@ -709,7 +709,7 @@ gid_t *groups;
rfp = &fproc[slot];
if (ngroups * sizeof(gid_t) > sizeof(rfp->fp_sgroups))
panic("VFS: pm_setgroups: too much data to copy");
if (sys_datacopy(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups,
if (sys_datacopy_wrapper(who_e, (vir_bytes) groups, SELF, (vir_bytes) rfp->fp_sgroups,
ngroups * sizeof(gid_t)) == OK) {
rfp->fp_ngroups = ngroups;
} else
@ -775,7 +775,7 @@ int do_svrctl(void)
int r, s;
/* Copy sysgetenv structure to VFS */
if (sys_datacopy(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
if (sys_datacopy_wrapper(who_e, ptr, SELF, (vir_bytes) &sysgetenv,
sizeof(sysgetenv)) != OK)
return(EFAULT);
@ -790,7 +790,7 @@ int do_svrctl(void)
}
/* Copy parameter "key" */
if ((s = sys_datacopy(who_e, (vir_bytes) sysgetenv.key,
if ((s = sys_datacopy_wrapper(who_e, (vir_bytes) sysgetenv.key,
SELF, (vir_bytes) search_key,
sysgetenv.keylen)) != OK)
return(s);
@ -800,7 +800,7 @@ int do_svrctl(void)
if (svrctl == VFSSETPARAM) {
if (!strcmp(search_key, "verbose")) {
int verbose_val;
if ((s = sys_datacopy(who_e,
if ((s = sys_datacopy_wrapper(who_e,
(vir_bytes) sysgetenv.val, SELF,
(vir_bytes) &val, sysgetenv.vallen)) != OK)
return(s);
@ -832,12 +832,12 @@ int do_svrctl(void)
}
if (r == OK) {
if ((s = sys_datacopy(SELF,
if ((s = sys_datacopy_wrapper(SELF,
(vir_bytes) &sysgetenv, who_e, ptr,
sizeof(sysgetenv))) != OK)
return(s);
if (sysgetenv.val != 0) {
if ((s = sys_datacopy(SELF,
if ((s = sys_datacopy_wrapper(SELF,
(vir_bytes) small_buf, who_e,
(vir_bytes) sysgetenv.val,
sysgetenv.vallen)) != OK)
@ -875,7 +875,7 @@ int pm_dumpcore(int csig, vir_bytes exe_name)
if (core_fd < 0) { r = core_fd; goto core_exit; }
/* get process' name */
r = sys_datacopy(PM_PROC_NR, exe_name, VFS_PROC_NR, (vir_bytes) proc_name,
r = sys_datacopy_wrapper(PM_PROC_NR, exe_name, VFS_PROC_NR, (vir_bytes) proc_name,
PROC_NAME_LEN);
if (r != OK) goto core_exit;
proc_name[PROC_NAME_LEN - 1] = '\0';
@ -943,7 +943,7 @@ int do_getrusage(void)
int res;
struct rusage r_usage;
if ((res = sys_datacopy(who_e, (vir_bytes) m_in.RU_RUSAGE_ADDR, SELF,
if ((res = sys_datacopy_wrapper(who_e, (vir_bytes) m_in.RU_RUSAGE_ADDR, SELF,
(vir_bytes) &r_usage, (vir_bytes) sizeof(r_usage))) < 0)
return res;
@ -953,6 +953,6 @@ int do_getrusage(void)
r_usage.ru_idrss = fp->data_size;
r_usage.ru_isrss = DEFAULT_STACK_LIMIT;
return sys_datacopy(SELF, (vir_bytes) &r_usage, who_e,
return sys_datacopy_wrapper(SELF, (vir_bytes) &r_usage, who_e,
(vir_bytes) m_in.RU_RUSAGE_ADDR, (phys_bytes) sizeof(r_usage));
}

View file

@ -109,7 +109,7 @@ int do_mount(void)
/* Get the label from the caller, and ask DS for the endpoint of the FS. */
if (label_len > sizeof(mount_label))
return EINVAL;
r = sys_datacopy(who_e, label, SELF, (vir_bytes) mount_label,
r = sys_datacopy_wrapper(who_e, label, SELF, (vir_bytes) mount_label,
sizeof(mount_label));
if (r != OK) return(r);
@ -446,7 +446,7 @@ int do_umount(void)
*/
if (strlen(label) >= label_len)
label[label_len-1] = 0;
return sys_datacopy(SELF, (vir_bytes) label, who_e, label_addr,
return sys_datacopy_wrapper(SELF, (vir_bytes) label, who_e, label_addr,
strlen(label) + 1);
}

View file

@ -24,8 +24,10 @@ struct job;
int drv_sendrec(endpoint_t drv_e, message *reqm);
void fs_cancel(struct vmnt *vmp);
int fs_sendrec(endpoint_t fs_e, message *reqm);
int vm_sendrec(message *reqm);
void fs_sendmore(struct vmnt *vmp);
void send_work(void);
int vm_vfs_procctl_handlemem(endpoint_t ep, vir_bytes mem, vir_bytes len, int flags);
/* device.c */
int cdev_open(dev_t dev, int flags);
@ -277,6 +279,8 @@ int copy_path(char *dest, size_t size);
int fetch_name(vir_bytes path, size_t len, char *dest);
int isokendpt_f(const char *f, int l, endpoint_t e, int *p, int ft);
int in_group(struct fproc *rfp, gid_t grp);
int sys_datacopy_wrapper(endpoint_t src, vir_bytes srcv, endpoint_t dst, vir_bytes dstv,
size_t len);
#define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1)
#define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0)

View file

@ -25,26 +25,18 @@
/*===========================================================================*
* req_breadwrite *
* req_breadwrite_actual *
*===========================================================================*/
int req_breadwrite(
endpoint_t fs_e,
endpoint_t user_e,
dev_t dev,
off_t pos,
unsigned int num_of_bytes,
vir_bytes user_addr,
int rw_flag,
off_t *new_pos,
unsigned int *cum_iop
)
static int req_breadwrite_actual(endpoint_t fs_e, endpoint_t user_e, dev_t dev, off_t pos,
unsigned int num_of_bytes, vir_bytes user_addr, int rw_flag,
off_t *new_pos, unsigned int *cum_iop, int cpflag)
{
int r;
cp_grant_id_t grant_id;
message m;
grant_id = cpf_grant_magic(fs_e, user_e, user_addr, num_of_bytes,
(rw_flag == READING ? CPF_WRITE : CPF_READ));
(rw_flag == READING ? CPF_WRITE : CPF_READ) | cpflag);
if(grant_id == -1)
panic("req_breadwrite: cpf_grant_magic failed");
@ -67,6 +59,28 @@ int req_breadwrite(
return(OK);
}
int req_breadwrite(endpoint_t fs_e, endpoint_t user_e, dev_t dev, off_t pos,
unsigned int num_of_bytes, vir_bytes user_addr, int rw_flag,
off_t *new_pos, unsigned int *cum_iop)
{
int r;
r = req_breadwrite_actual(fs_e, user_e, dev, pos, num_of_bytes,
user_addr, rw_flag, new_pos, cum_iop, CPF_TRY);
if(r == EFAULT) {
if((r=vm_vfs_procctl_handlemem(user_e, user_addr, num_of_bytes,
rw_flag == READING)) != OK) {
return r;
}
r = req_breadwrite_actual(fs_e, user_e, dev, pos, num_of_bytes,
user_addr, rw_flag, new_pos, cum_iop, 0);
}
return r;
}
/*===========================================================================*
* req_bpeek *
*===========================================================================*/
@ -267,16 +281,17 @@ int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end)
/*===========================================================================*
* req_getdents *
* req_getdents_actual *
*===========================================================================*/
int req_getdents(
static int req_getdents_actual(
endpoint_t fs_e,
ino_t inode_nr,
off_t pos,
char *buf,
size_t size,
off_t *new_pos,
int direct
int direct,
int cpflag
)
{
int r;
@ -291,7 +306,7 @@ int req_getdents(
grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, CPF_WRITE);
} else {
grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size,
CPF_WRITE);
CPF_WRITE | cpflag);
}
if (grant_id < 0)
@ -319,6 +334,36 @@ int req_getdents(
return(r);
}
/*===========================================================================*
* req_getdents *
*===========================================================================*/
int req_getdents(
endpoint_t fs_e,
ino_t inode_nr,
off_t pos,
char *buf,
size_t size,
off_t *new_pos,
int direct)
{
int r;
r = req_getdents_actual(fs_e, inode_nr, pos, buf, size, new_pos,
direct, CPF_TRY);
if(r == EFAULT && !direct) {
if((r=vm_vfs_procctl_handlemem(who_e, (vir_bytes) buf,
size, 1)) != OK) {
return r;
}
r = req_getdents_actual(fs_e, inode_nr, pos, buf, size,
new_pos, direct, 0);
}
return r;
}
/*===========================================================================*
* req_inhibread *
*===========================================================================*/
@ -665,15 +710,12 @@ int count;
/*===========================================================================*
* req_rdlink *
* req_rdlink_actual *
*===========================================================================*/
int req_rdlink(fs_e, inode_nr, proc_e, buf, len, direct)
endpoint_t fs_e;
ino_t inode_nr;
endpoint_t proc_e;
vir_bytes buf;
size_t len;
int direct; /* set to 1 to use direct grants instead of magic grants */
static int req_rdlink_actual(endpoint_t fs_e, ino_t inode_nr,
endpoint_t proc_e, vir_bytes buf, size_t len,
int direct, /* set to 1 to use direct grants instead of magic grants */
int cpflag)
{
message m;
int r;
@ -682,7 +724,7 @@ int direct; /* set to 1 to use direct grants instead of magic grants */
if (direct) {
grant_id = cpf_grant_direct(fs_e, buf, len, CPF_WRITE);
} else {
grant_id = cpf_grant_magic(fs_e, proc_e, buf, len, CPF_WRITE);
grant_id = cpf_grant_magic(fs_e, proc_e, buf, len, CPF_WRITE | cpflag);
}
if (grant_id == -1)
panic("req_rdlink: cpf_grant_magic failed");
@ -702,6 +744,30 @@ int direct; /* set to 1 to use direct grants instead of magic grants */
return(r);
}
/*===========================================================================*
* req_rdlink *
*===========================================================================*/
int req_rdlink(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
vir_bytes buf, size_t len,
int direct /* set to 1 to use direct grants instead of magic grants */
)
{
int r;
r = req_rdlink_actual(fs_e, inode_nr, proc_e, buf, len, direct,
CPF_TRY);
if(r == EFAULT && !direct) {
if((r=vm_vfs_procctl_handlemem(proc_e, buf, len, 1)) != OK) {
return r;
}
r = req_rdlink_actual(fs_e, inode_nr, proc_e, buf, len,
direct, 0);
}
return r;
}
/*===========================================================================*
* req_readsuper *
@ -758,18 +824,12 @@ int req_readsuper(
/*===========================================================================*
* req_readwrite *
* req_readwrite_actual *
*===========================================================================*/
int req_readwrite(
endpoint_t fs_e,
ino_t inode_nr,
off_t pos,
int rw_flag,
endpoint_t user_e,
vir_bytes user_addr,
unsigned int num_of_bytes,
off_t *new_posp,
unsigned int *cum_iop)
static int req_readwrite_actual(endpoint_t fs_e, ino_t inode_nr, off_t pos,
int rw_flag, endpoint_t user_e, vir_bytes user_addr,
unsigned int num_of_bytes, off_t *new_posp, unsigned int *cum_iop,
int cpflag)
{
struct vmnt *vmp;
int r;
@ -779,7 +839,7 @@ unsigned int *cum_iop)
vmp = find_vmnt(fs_e);
grant_id = cpf_grant_magic(fs_e, user_e, user_addr, num_of_bytes,
(rw_flag==READING ? CPF_WRITE:CPF_READ));
(rw_flag==READING ? CPF_WRITE:CPF_READ) | cpflag);
if (grant_id == -1)
panic("req_readwrite: cpf_grant_magic failed");
@ -806,6 +866,31 @@ unsigned int *cum_iop)
return(r);
}
/*===========================================================================*
* req_readwrite *
*===========================================================================*/
int req_readwrite(endpoint_t fs_e, ino_t inode_nr, off_t pos,
int rw_flag, endpoint_t user_e, vir_bytes user_addr,
unsigned int num_of_bytes, off_t *new_posp, unsigned int *cum_iop)
{
int r;
r = req_readwrite_actual(fs_e, inode_nr, pos, rw_flag, user_e,
user_addr, num_of_bytes, new_posp, cum_iop, CPF_TRY);
if(r == EFAULT) {
if((r=vm_vfs_procctl_handlemem(user_e, (vir_bytes) user_addr, num_of_bytes,
rw_flag == READING)) != OK) {
return r;
}
r = req_readwrite_actual(fs_e, inode_nr, pos, rw_flag, user_e,
user_addr, num_of_bytes, new_posp, cum_iop, 0);
}
return r;
}
/*===========================================================================*
* req_peek *
*===========================================================================*/
@ -905,9 +990,9 @@ char *lastc;
/*===========================================================================*
* req_slink *
* req_slink_actual *
*===========================================================================*/
int req_slink(
static int req_slink_actual(
endpoint_t fs_e,
ino_t inode_nr,
char *lastc,
@ -915,7 +1000,8 @@ int req_slink(
vir_bytes path_addr,
size_t path_length,
uid_t uid,
gid_t gid
gid_t gid,
int cpflag
)
{
int r;
@ -928,7 +1014,9 @@ int req_slink(
if (gid_name == GRANT_INVALID)
panic("req_slink: cpf_grant_direct failed");
gid_buf = cpf_grant_magic(fs_e, proc_e, path_addr, path_length, CPF_READ);
gid_buf = cpf_grant_magic(fs_e, proc_e, path_addr, path_length,
CPF_READ | cpflag);
if (gid_buf == GRANT_INVALID) {
cpf_revoke(gid_name);
panic("req_slink: cpf_grant_magic failed");
@ -952,18 +1040,51 @@ int req_slink(
return(r);
}
/*===========================================================================*
* req_slink *
*===========================================================================*/
int req_slink(
endpoint_t fs_e,
ino_t inode_nr,
char *lastc,
endpoint_t proc_e,
vir_bytes path_addr,
size_t path_length,
uid_t uid,
gid_t gid
)
{
int r;
r = req_slink_actual(fs_e, inode_nr, lastc, proc_e, path_addr,
path_length, uid, gid, CPF_TRY);
if(r == EFAULT) {
if((r=vm_vfs_procctl_handlemem(proc_e, (vir_bytes) path_addr,
path_length, 0)) != OK) {
return r;
}
r = req_slink_actual(fs_e, inode_nr, lastc, proc_e, path_addr,
path_length, uid, gid, 0);
}
return r;
}
/*===========================================================================*
* req_stat *
* req_stat_actual *
*===========================================================================*/
int req_stat(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e, vir_bytes buf)
int req_stat_actual(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
vir_bytes buf, int cpflag)
{
cp_grant_id_t grant_id;
int r;
message m;
/* Grant FS access to copy straight into user provided buffer */
grant_id = cpf_grant_magic(fs_e, proc_e, buf, sizeof(struct stat), CPF_WRITE);
grant_id = cpf_grant_magic(fs_e, proc_e, buf, sizeof(struct stat),
CPF_WRITE | cpflag);
if (grant_id < 0)
panic("req_stat: cpf_grant_* failed");
@ -981,6 +1102,28 @@ int req_stat(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e, vir_bytes buf)
}
/*===========================================================================*
* req_stat *
*===========================================================================*/
int req_stat(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
vir_bytes buf)
{
int r;
r = req_stat_actual(fs_e, inode_nr, proc_e, buf, CPF_TRY);
if(r == EFAULT) {
if((r=vm_vfs_procctl_handlemem(proc_e, (vir_bytes) buf,
sizeof(struct stat), 1)) != OK) {
return r;
}
r = req_stat_actual(fs_e, inode_nr, proc_e, buf, 0);
}
return r;
}
/*===========================================================================*
* req_sync *
*===========================================================================*/

View file

@ -126,7 +126,7 @@ int do_select(void)
/* Did the process set a timeout value? If so, retrieve it. */
if (vtimeout != 0) {
do_timeout = 1;
r = sys_vircopy(who_e, (vir_bytes) vtimeout, SELF,
r = sys_datacopy_wrapper(who_e, (vir_bytes) vtimeout, SELF,
(vir_bytes) &timeout, sizeof(timeout));
if (r != OK) {
se->requestor = NULL;
@ -535,7 +535,7 @@ static int copy_fdsets(struct selectentry *se, int nfds, int direction)
src_fds = (direction == FROM_PROC) ? se->vir_readfds : &se->ready_readfds;
dst_fds = (direction == FROM_PROC) ? &se->readfds : se->vir_readfds;
if (se->vir_readfds) {
r = sys_vircopy(src_e, (vir_bytes) src_fds, dst_e,
r = sys_datacopy_wrapper(src_e, (vir_bytes) src_fds, dst_e,
(vir_bytes) dst_fds, fd_setsize);
if (r != OK) return(r);
}
@ -544,7 +544,7 @@ static int copy_fdsets(struct selectentry *se, int nfds, int direction)
src_fds = (direction == FROM_PROC) ? se->vir_writefds : &se->ready_writefds;
dst_fds = (direction == FROM_PROC) ? &se->writefds : se->vir_writefds;
if (se->vir_writefds) {
r = sys_vircopy(src_e, (vir_bytes) src_fds, dst_e,
r = sys_datacopy_wrapper(src_e, (vir_bytes) src_fds, dst_e,
(vir_bytes) dst_fds, fd_setsize);
if (r != OK) return(r);
}
@ -553,7 +553,7 @@ static int copy_fdsets(struct selectentry *se, int nfds, int direction)
src_fds = (direction == FROM_PROC) ? se->vir_errorfds : &se->ready_errorfds;
dst_fds = (direction == FROM_PROC) ? &se->errorfds : se->vir_errorfds;
if (se->vir_errorfds) {
r = sys_vircopy(src_e, (vir_bytes) src_fds, dst_e,
r = sys_datacopy_wrapper(src_e, (vir_bytes) src_fds, dst_e,
(vir_bytes) dst_fds, fd_setsize);
if (r != OK) return(r);
}

View file

@ -284,7 +284,8 @@ static int fill_statvfs(struct vmnt *vmp, endpoint_t endpt, vir_bytes buf_addr,
strlcpy(buf.f_mntonname, vmp->m_mount_path, sizeof(buf.f_mntonname));
strlcpy(buf.f_mntfromname, vmp->m_mount_dev, sizeof(buf.f_mntfromname));
return sys_datacopy(SELF, (vir_bytes) &buf, endpt, buf_addr, sizeof(buf));
return sys_datacopy_wrapper(SELF, (vir_bytes) &buf,
endpt, buf_addr, sizeof(buf));
}
/*===========================================================================*

View file

@ -31,7 +31,7 @@ struct worker_thread {
message w_m_in;
message w_m_out;
int w_err_code;
message *w_fs_sendrec;
message *w_sendrec;
message *w_drv_sendrec;
endpoint_t w_task;
struct dmap *w_dmap;

View file

@ -75,7 +75,7 @@ int fetch_name(vir_bytes path, size_t len, char *dest)
}
/* String is not contained in the message. Get it from user space. */
r = sys_datacopy(who_e, path, VFS_PROC_NR, (vir_bytes) dest, len);
r = sys_datacopy_wrapper(who_e, path, VFS_PROC_NR, (vir_bytes) dest, len);
if (r != OK) {
err_code = EINVAL;
return(r);
@ -164,3 +164,52 @@ int in_group(struct fproc *rfp, gid_t grp)
return(EINVAL);
}
/*===========================================================================*
* sys_datacopy_wrapper *
*===========================================================================*/
int sys_datacopy_wrapper(endpoint_t src, vir_bytes srcv,
endpoint_t dst, vir_bytes dstv, size_t len)
{
/* Safe function to copy data from or to a user buffer.
* VFS has to be a bit more careful as a regular copy
* might trigger VFS action needed by VM while it's
* blocked on the kernel call. This wrapper tries the
* copy, invokes VM itself asynchronously if necessary,
* then tries the copy again.
*
* This function assumes it's between VFS and a user process,
* and therefore one of the endpoints is SELF (VFS).
*/
int r;
endpoint_t them = NONE;
vir_bytes themv = -1;
int writable = -1;
r = sys_datacopy_try(src, srcv, dst, dstv, len);
if(src == VFS_PROC_NR) src = SELF;
if(dst == VFS_PROC_NR) dst = SELF;
assert(src == SELF || dst == SELF);
if(src == SELF) { them = dst; themv = dstv; writable = 1; }
if(dst == SELF) { them = src; themv = srcv; writable = 0; }
assert(writable >= 0);
assert(them != SELF);
if(r == EFAULT) {
/* The copy has failed with EFAULT, this means the kernel has
* given up but it might not be a legitimate error. Ask VM.
*/
if((r=vm_vfs_procctl_handlemem(them, themv, len, writable)) != OK) {
return r;
}
r = sys_datacopy_try(src, srcv, dst, dstv, len);
}
return r;
}

View file

@ -47,7 +47,7 @@ void check_vnode_locks_by_me(struct fproc *rfp)
for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) {
if (tll_locked_by_me(&vp->v_lock)) {
panic("Thread %d still holds vnode lock on vp %x call_nr=%d\n",
panic("Thread %d still holds vnode lock on vp %p call_nr=%d\n",
mthread_self(), vp, job_call_nr);
}
}

View file

@ -37,6 +37,7 @@ void worker_init(void)
wp->w_fp = NULL; /* Mark not in use */
wp->w_next = NULL;
wp->w_task = NONE;
if (mutex_init(&wp->w_event_mutex, NULL) != 0)
panic("failed to initialize mutex");
if (cond_init(&wp->w_event, NULL) != 0)
@ -397,8 +398,8 @@ void worker_stop(struct worker_thread *worker)
/* This thread is communicating with a driver or file server */
if (worker->w_drv_sendrec != NULL) { /* Driver */
worker->w_drv_sendrec->m_type = EIO;
} else if (worker->w_fs_sendrec != NULL) { /* FS */
worker->w_fs_sendrec->m_type = EIO;
} else if (worker->w_sendrec != NULL) { /* FS */
worker->w_sendrec->m_type = EIO;
} else {
panic("reply storage consistency error"); /* Oh dear */
}

View file

@ -46,7 +46,7 @@ static phys_bytes alloc_pages(int pages, int flags);
#if SANITYCHECKS
struct {
int used;
char *file;
const char *file;
int line;
} pagemap[NUMBER_PHYSICAL_PAGES];
#endif
@ -335,7 +335,7 @@ void mem_init(struct memory *chunks)
}
#if SANITYCHECKS
void mem_sanitycheck(char *file, int line)
void mem_sanitycheck(const char *file, int line)
{
int i;
for(i = 0; i < NUMBER_PHYSICAL_PAGES; i++) {
@ -506,7 +506,7 @@ void usedpages_reset(void)
/*===========================================================================*
* usedpages_add *
*===========================================================================*/
int usedpages_add_f(phys_bytes addr, phys_bytes len, char *file, int line)
int usedpages_add_f(phys_bytes addr, phys_bytes len, const char *file, int line)
{
u32_t pagestart, pages;
@ -525,7 +525,6 @@ int usedpages_add_f(phys_bytes addr, phys_bytes len, char *file, int line)
assert(pagestart > 0);
assert(pagestart < NUMBER_PHYSICAL_PAGES);
thisaddr = pagestart * VM_PAGE_SIZE;
assert(pagestart >= 0);
assert(pagestart < NUMBER_PHYSICAL_PAGES);
if(pagemap[pagestart].used) {
static int warnings = 0;

View file

@ -111,13 +111,13 @@ int do_willexit(message *msg)
return OK;
}
int do_procctl(message *msg)
int do_procctl(message *msg, int transid)
{
endpoint_t proc;
struct vmproc *vmp;
if(vm_isokendpt(msg->VMPCTL_WHO, &proc) != OK) {
printf("VM: bogus endpoint VM_PROCCTL %d\n",
printf("VM: bogus endpoint VM_PROCCTL %ld\n",
msg->VMPCTL_WHO);
return EINVAL;
}
@ -133,11 +133,21 @@ int do_procctl(message *msg)
panic("VMPPARAM_CLEAR: pt_new failed");
pt_bind(&vmp->vm_pt, vmp);
return OK;
case VMPPARAM_HANDLEMEM:
{
if(msg->m_source != VFS_PROC_NR)
return EPERM;
handle_memory_start(vmp, msg->VMPCTL_M1,
msg->VMPCTL_LEN, msg->VMPCTL_FLAGS,
VFS_PROC_NR, VFS_PROC_NR, transid, 1);
return SUSPEND;
}
default:
return EINVAL;
}
return OK;
}

View file

@ -101,10 +101,10 @@ int do_fork(message *msg)
* and its return value needn't be checked.
*/
vir = msgaddr;
if (handle_memory(vmc, vir, sizeof(message), 1, NULL, 0, 0) != OK)
if (handle_memory_once(vmc, vir, sizeof(message), 1) != OK)
panic("do_fork: handle_memory for child failed\n");
vir = msgaddr;
if (handle_memory(vmp, vir, sizeof(message), 1, NULL, 0, 0) != OK)
if (handle_memory_once(vmp, vir, sizeof(message), 1) != OK)
panic("do_fork: handle_memory for parent failed\n");
}

View file

@ -25,7 +25,7 @@ EXTERN kinfo_t kernel_boot_info;
EXTERN int nocheck;
EXTERN int incheck;
EXTERN int sc_lastline;
EXTERN char *sc_lastfile;
EXTERN const char *sc_lastfile;
#endif
extern struct minix_kerninfo *_minix_kerninfo;

View file

@ -15,6 +15,7 @@
#include <minix/const.h>
#include <minix/bitmap.h>
#include <minix/rs.h>
#include <minix/vfsif.h>
#include <sys/exec.h>
@ -90,7 +91,8 @@ int main(void)
/* This is VM's main loop. */
while (TRUE) {
int r, c;
int type, param;
int type;
int transid = 0; /* VFS transid if any */
SANITYCHECK(SCL_TOP);
if(missing_spares > 0) {
@ -109,13 +111,22 @@ int main(void)
if(vm_isokendpt(who_e, &caller_slot) != OK)
panic("invalid caller %d", who_e);
type = param = msg.m_type;
type &= 0x0000FFFF;
param >>= 16;
/* We depend on this being false for the initialized value. */
assert(!IS_VFS_FS_TRANSID(transid));
type = msg.m_type;
c = CALLNUMBER(type);
result = ENOSYS; /* Out of range or restricted calls return this. */
if(msg.m_type == RS_INIT && msg.m_source == RS_PROC_NR) {
transid = TRNS_GET_ID(msg.m_type);
if((msg.m_source == VFS_PROC_NR) && IS_VFS_FS_TRANSID(transid)) {
/* If it's a request from VFS, it might have a transaction id. */
msg.m_type = TRNS_DEL_ID(msg.m_type);
/* Calls that use the transid */
result = do_procctl(&msg, transid);
} else if(msg.m_type == RS_INIT && msg.m_source == RS_PROC_NR) {
result = do_rs_init(&msg);
} else if (msg.m_type == VM_PAGEFAULT) {
if (!IPC_STATUS_FLAGS_TEST(rcv_sts, IPC_FLG_MSG_FROM_KERNEL)) {
@ -147,6 +158,9 @@ int main(void)
*/
if(result != SUSPEND) {
msg.m_type = result;
assert(!IS_VFS_FS_TRANSID(transid));
if((r=ipc_send(who_e, &msg)) != OK) {
printf("VM: couldn't send %d to %d (err %d)\n",
msg.m_type, who_e, r);
@ -223,7 +237,7 @@ static int libexec_copy_physcopy(struct exec_info *execi,
end = ei->ip->start_addr + ei->ip->len;
assert(ei->ip->start_addr + off + len <= end);
return sys_physcopy(NONE, ei->ip->start_addr + off,
execi->proc_e, vaddr, len);
execi->proc_e, vaddr, len, 0);
}
static void boot_alloc(struct exec_info *execi, off_t vaddr,
@ -279,7 +293,7 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
panic("VM: pt_bind failed");
if(sys_physcopy(NONE, ip->start_addr, SELF,
(vir_bytes) hdr, sizeof(hdr)) != OK)
(vir_bytes) hdr, sizeof(hdr), 0) != OK)
panic("can't look at boot proc header");
execi->stack_high = kernel_boot_info.user_sp;
@ -320,7 +334,7 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
minix_stack_fill(path, argc, argv, envc, envp, frame_size, frame, &vsp,
&psp);
if(handle_memory(vmp, vsp, frame_size, 1, NULL, NULL, 0) != OK)
if(handle_memory_once(vmp, vsp, frame_size, 1) != OK)
panic("vm: could not map stack for boot process %s (ep=%d)\n",
execi->progname, vmp->vm_endpoint);
@ -338,6 +352,15 @@ static void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
panic("VMCTL_BOOTINHIBIT_CLEAR failed");
}
static int do_procctl_notrans(message *msg)
{
int transid = 0;
assert(!IS_VFS_FS_TRANSID(transid));
return do_procctl(msg, transid);
}
void init_vm(void)
{
int s, i;
@ -459,6 +482,8 @@ void init_vm(void)
CALLMAP(VM_WILLEXIT, do_willexit);
CALLMAP(VM_NOTIFY_SIG, do_notify_sig);
CALLMAP(VM_PROCCTL, do_procctl_notrans);
/* Calls from VFS. */
CALLMAP(VM_VFS_REPLY, do_vfs_reply);
CALLMAP(VM_VFS_MMAP, do_vfs_mmap);
@ -468,9 +493,6 @@ void init_vm(void)
CALLMAP(VM_RS_UPDATE, do_rs_update);
CALLMAP(VM_RS_MEMCTL, do_rs_memctl);
/* Calls from RS/VFS */
CALLMAP(VM_PROCCTL, do_procctl);
/* Generic calls. */
CALLMAP(VM_REMAP, do_remap);
CALLMAP(VM_REMAP_RO, do_remap);

View file

@ -24,7 +24,7 @@ static int anon_unreference(struct phys_region *pr);
static int anon_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write, vfs_callback_t cb, void *state,
int len, int *io);
static int anon_sanitycheck(struct phys_region *pr, char *file, int line);
static int anon_sanitycheck(struct phys_region *pr, const char *file, int line);
static int anon_writable(struct phys_region *pr);
static int anon_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
static u32_t anon_regionid(struct vir_region *region);
@ -87,8 +87,7 @@ static int anon_pagefault(struct vmproc *vmp, struct vir_region *region,
}
if(ph->ph->refcount < 2 || !write) {
printf("anon_pagefault: %d refcount, %d write - not handling pagefault\n",
ph->ph->refcount, write);
/* memory is ready already */
return OK;
}
@ -97,7 +96,7 @@ static int anon_pagefault(struct vmproc *vmp, struct vir_region *region,
return mem_cow(region, ph, new_page_cl, new_page);
}
static int anon_sanitycheck(struct phys_region *pr, char *file, int line)
static int anon_sanitycheck(struct phys_region *pr, const char *file, int line)
{
MYASSERT(usedpages_add(pr->ph->phys, VM_PAGE_SIZE) == OK);
return OK;

View file

@ -13,7 +13,7 @@ static int anon_contig_unreference(struct phys_region *pr);
static int anon_contig_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write, vfs_callback_t cb, void *state,
int len, int *io);
static int anon_contig_sanitycheck(struct phys_region *pr, char *file, int line);
static int anon_contig_sanitycheck(struct phys_region *pr, const char *file, int line);
static int anon_contig_writable(struct phys_region *pr);
static int anon_contig_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
static int anon_contig_new(struct vir_region *vr);
@ -111,7 +111,7 @@ static int anon_contig_unreference(struct phys_region *pr)
return mem_type_anon.ev_unreference(pr);
}
static int anon_contig_sanitycheck(struct phys_region *pr, char *file, int line)
static int anon_contig_sanitycheck(struct phys_region *pr, const char *file, int line)
{
return mem_type_anon.ev_sanitycheck(pr, file, line);
}

View file

@ -27,7 +27,7 @@
static int cache_reference(struct phys_region *pr, struct phys_region *pr2);
static int cache_unreference(struct phys_region *pr);
static int cache_sanitycheck(struct phys_region *pr, char *file, int line);
static int cache_sanitycheck(struct phys_region *pr, const char *file, int line);
static int cache_writable(struct phys_region *pr);
static int cache_resize(struct vmproc *vmp, struct vir_region *vr, vir_bytes l);
static int cache_pagefault(struct vmproc *vmp, struct vir_region *region,
@ -65,7 +65,7 @@ static int cache_unreference(struct phys_region *pr)
return mem_type_anon.ev_unreference(pr);
}
static int cache_sanitycheck(struct phys_region *pr, char *file, int line)
static int cache_sanitycheck(struct phys_region *pr, const char *file, int line)
{
MYASSERT(usedpages_add(pr->ph->phys, VM_PAGE_SIZE) == OK);
return OK;

View file

@ -20,7 +20,7 @@ static int mappedfile_unreference(struct phys_region *pr);
static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write, vfs_callback_t callback, void *state,
int len, int *io);
static int mappedfile_sanitycheck(struct phys_region *pr, char *file, int line);
static int mappedfile_sanitycheck(struct phys_region *pr, const char *file, int line);
static int mappedfile_writable(struct phys_region *pr);
static int mappedfile_copy(struct vir_region *vr, struct vir_region *newvr);
static int mappedfile_lowshrink(struct vir_region *vr, vir_bytes len);
@ -124,7 +124,9 @@ static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region,
}
if(!cb) {
#if 0
printf("VM: mem_file: no callback, returning EFAULT\n");
#endif
sys_diagctl_stacktrace(vmp->vm_endpoint);
return EFAULT;
}
@ -139,14 +141,16 @@ static int mappedfile_pagefault(struct vmproc *vmp, struct vir_region *region,
}
if(!write) {
#if 0
printf("mappedfile_pagefault: nonwrite fault?\n");
return EFAULT;
#endif
return OK;
}
return cow_block(vmp, region, ph, 0);
}
static int mappedfile_sanitycheck(struct phys_region *pr, char *file, int line)
static int mappedfile_sanitycheck(struct phys_region *pr, const char *file, int line)
{
MYASSERT(usedpages_add(pr->ph->phys, VM_PAGE_SIZE) == OK);
return OK;

View file

@ -17,7 +17,7 @@ static int shared_unreference(struct phys_region *pr);
static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
struct phys_region *ph, int write, vfs_callback_t cb, void *state,
int len, int *io);
static int shared_sanitycheck(struct phys_region *pr, char *file, int line);
static int shared_sanitycheck(struct phys_region *pr, const char *file, int line);
static int shared_writable(struct phys_region *pr);
static void shared_delete(struct vir_region *region);
static u32_t shared_regionid(struct vir_region *region);
@ -149,7 +149,7 @@ static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
return OK;
}
static int shared_sanitycheck(struct phys_region *pr, char *file, int line)
static int shared_sanitycheck(struct phys_region *pr, const char *file, int line)
{
return OK;
}

View file

@ -22,7 +22,7 @@ typedef struct mem_type {
void (*ev_split)(struct vmproc *vmp, struct vir_region *vr,
struct vir_region *r1, struct vir_region *r2);
int (*writable)(struct phys_region *pr);
int (*ev_sanitycheck)(struct phys_region *pr, char *file, int line);
int (*ev_sanitycheck)(struct phys_region *pr, const char *file, int line);
int (*ev_copy)(struct vir_region *vr, struct vir_region *newvr);
int (*ev_lowshrink)(struct vir_region *vr, vir_bytes len);
u32_t (*regionid)(struct vir_region *vr);

View file

@ -14,6 +14,9 @@
#include <minix/syslib.h>
#include <minix/safecopies.h>
#include <minix/bitmap.h>
#include <minix/vfsif.h>
#include <machine/vmparam.h>
#include <errno.h>
#include <string.h>
@ -28,6 +31,29 @@
#include "util.h"
#include "region.h"
struct pf_state {
endpoint_t ep;
vir_bytes vaddr;
u32_t err;
};
struct hm_state {
endpoint_t caller; /* KERNEL or process? if NONE, no callback */
endpoint_t requestor; /* on behalf of whom? */
int transid; /* VFS transaction id if valid */
struct vmproc *vmp; /* target address space */
vir_bytes mem, len; /* memory range */
int wrflag; /* must it be writable or not */
int valid; /* sanity check */
int vfs_avail; /* may vfs be called to satisfy this range? */
#define VALID 0xc0ff1
};
static void handle_memory_continue(struct vmproc *vmp, message *m,
void *arg, void *statearg);
static int handle_memory_step(struct hm_state *hmstate);
static void handle_memory_final(struct hm_state *state, int result);
/*===========================================================================*
* pf_errstr *
*===========================================================================*/
@ -44,23 +70,9 @@ char *pf_errstr(u32_t err)
return buf;
}
struct pf_state {
endpoint_t ep;
vir_bytes vaddr;
u32_t err;
};
struct hm_state {
endpoint_t requestor;
struct vmproc *vmp;
vir_bytes mem;
vir_bytes len;
int wrflag;
};
static void pf_cont(struct vmproc *vmp, message *m, void *arg, void *statearg);
static void hm_cont(struct vmproc *vmp, message *m, void *arg, void *statearg);
static void handle_memory_continue(struct vmproc *vmp, message *m, void *arg, void *statearg);
static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry)
{
@ -156,25 +168,65 @@ static void pf_cont(struct vmproc *vmp, message *m,
handle_pagefault(state->ep, state->vaddr, state->err, 1);
}
static void hm_cont(struct vmproc *vmp, message *m,
static void handle_memory_continue(struct vmproc *vmp, message *m,
void *arg, void *statearg)
{
int r;
struct hm_state *state = statearg;
printf("hm_cont: result %d\n", m->VMV_RESULT);
r = handle_memory(vmp, state->mem, state->len, state->wrflag,
hm_cont, &state, sizeof(state));
if(r == SUSPEND) {
printf("VM: hm_cont: damnit: hm_cont: more SUSPEND\n");
assert(state);
assert(state->caller != NONE);
assert(state->valid == VALID);
if(m->VMV_RESULT != OK) {
printf("VM: handle_memory_continue: vfs request failed\n");
handle_memory_final(state, m->VMV_RESULT);
return;
}
printf("VM: hm_cont: ok, result %d, requestor %d\n", r, state->requestor);
r = handle_memory_step(state);
if(sys_vmctl(state->requestor, VMCTL_MEMREQ_REPLY, r) != OK)
panic("hm_cont: sys_vmctl failed: %d", r);
assert(state->valid == VALID);
printf("MEMREQ_REPLY sent\n");
if(r == SUSPEND) {
return;
}
assert(state->valid == VALID);
handle_memory_final(state, r);
}
static void handle_memory_final(struct hm_state *state, int result)
{
int r;
assert(state);
assert(state->valid == VALID);
if(state->caller == KERNEL) {
if((r=sys_vmctl(state->requestor, VMCTL_MEMREQ_REPLY, result)) != OK)
panic("handle_memory_continue: sys_vmctl failed: %d", r);
} else if(state->caller != NONE) {
/* Send a reply msg */
message msg;
memset(&msg, 0, sizeof(msg));
msg.m_type = result;
if(IS_VFS_FS_TRANSID(state->transid)) {
assert(state->caller == VFS_PROC_NR);
/* If a transaction ID was set, reset it */
msg.m_type = TRNS_ADD_ID(msg.m_type, state->transid);
}
if(asynsend3(state->caller, &msg, 0) != OK) {
panic("handle_memory_final: asynsend3 failed");
}
assert(state->valid == VALID);
/* fail fast if anyone tries to access this state again */
memset(state, 0, sizeof(*state));
}
}
/*===========================================================================*
@ -185,6 +237,52 @@ void do_pagefaults(message *m)
handle_pagefault(m->m_source, m->VPF_ADDR, m->VPF_FLAGS, 0);
}
int handle_memory_once(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
int wrflag)
{
int r;
r = handle_memory_start(vmp, mem, len, wrflag, NONE, NONE, 0, 0);
assert(r != SUSPEND);
return r;
}
int handle_memory_start(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
int wrflag, endpoint_t caller, endpoint_t requestor, int transid,
int vfs_avail)
{
int r;
struct hm_state state;
vir_bytes o;
if((o = mem % PAGE_SIZE)) {
mem -= o;
len += o;
}
len = roundup(len, PAGE_SIZE);
state.vmp = vmp;
state.mem = mem;
state.len = len;
state.wrflag = wrflag;
state.requestor = requestor;
state.caller = caller;
state.transid = transid;
state.valid = VALID;
state.vfs_avail = vfs_avail;
r = handle_memory_step(&state);
if(r == SUSPEND) {
assert(caller != NONE);
assert(vfs_avail);
} else {
handle_memory_final(&state, r);
}
return r;
}
/*===========================================================================*
* do_memory *
*===========================================================================*/
@ -205,21 +303,21 @@ void do_memory(void)
switch(r) {
case VMPTYPE_CHECK:
{
struct hm_state state;
int transid = 0;
int vfs_avail;
if(vm_isokendpt(who, &p) != OK)
panic("do_memory: bad endpoint: %d", who);
vmp = &vmproc[p];
assert(!IS_VFS_FS_TRANSID(transid));
state.vmp = vmp;
state.mem = mem;
state.len = len;
state.wrflag = wrflag;
state.requestor = requestor;
/* is VFS blocked? */
if(requestor == VFS_PROC_NR) vfs_avail = 0;
else vfs_avail = 1;
r = handle_memory(vmp, mem, len,
wrflag, hm_cont, &state, sizeof(state));
handle_memory_start(vmp, mem, len, wrflag,
KERNEL, requestor, transid, vfs_avail);
break;
}
@ -227,69 +325,56 @@ void do_memory(void)
default:
return;
}
if(r != SUSPEND) {
if(sys_vmctl(requestor, VMCTL_MEMREQ_REPLY, r) != OK)
panic("do_memory: sys_vmctl failed: %d", r);
}
}
}
int handle_memory(struct vmproc *vmp, vir_bytes mem, vir_bytes len, int wrflag,
vfs_callback_t callback, void *state, int statelen)
static int handle_memory_step(struct hm_state *hmstate)
{
struct vir_region *region;
vir_bytes o;
struct hm_state *hmstate = (struct hm_state *) state;
/* Page-align memory and length. */
o = mem % VM_PAGE_SIZE;
mem -= o;
len += o;
o = len % VM_PAGE_SIZE;
if(o > 0) len += VM_PAGE_SIZE - o;
assert(hmstate);
assert(hmstate->valid == VALID);
assert(!(hmstate->mem % VM_PAGE_SIZE));
assert(!(hmstate->len % VM_PAGE_SIZE));
while(len > 0) {
while(hmstate->len > 0) {
int r;
if(!(region = map_lookup(vmp, mem, NULL))) {
if(!(region = map_lookup(hmstate->vmp, hmstate->mem, NULL))) {
#if VERBOSE
map_printmap(vmp);
map_printmap(hmstate->vmp);
printf("VM: do_memory: memory doesn't exist\n");
#endif
r = EFAULT;
} else if(!(region->flags & VR_WRITABLE) && wrflag) {
return EFAULT;
} else if(!(region->flags & VR_WRITABLE) && hmstate->wrflag) {
#if VERBOSE
printf("VM: do_memory: write to unwritable map\n");
#endif
r = EFAULT;
return EFAULT;
} else {
vir_bytes offset, sublen;
assert(region->vaddr <= mem);
assert(region->vaddr <= hmstate->mem);
assert(!(region->vaddr % VM_PAGE_SIZE));
offset = mem - region->vaddr;
sublen = len;
offset = hmstate->mem - region->vaddr;
sublen = hmstate->len;
if(offset + sublen > region->length)
sublen = region->length - offset;
if(hmstate && hmstate->requestor == VFS_PROC_NR
&& region->def_memtype == &mem_type_mappedfile) {
r = map_handle_memory(vmp, region, offset,
sublen, wrflag, NULL, NULL, 0);
if((region->def_memtype == &mem_type_mappedfile &&
!hmstate->vfs_avail) || hmstate->caller == NONE) {
r = map_handle_memory(hmstate->vmp, region, offset,
sublen, hmstate->wrflag, NULL, NULL, 0);
assert(r != SUSPEND);
} else {
r = map_handle_memory(vmp, region, offset,
sublen, wrflag, callback, state, sizeof(state));
r = map_handle_memory(hmstate->vmp, region, offset,
sublen, hmstate->wrflag, handle_memory_continue,
hmstate, sizeof(*hmstate));
}
len -= sublen;
mem += sublen;
}
if(r != OK) {
#if VERBOSE
printf("VM: memory range 0x%lx-0x%lx not available in %d\n",
mem, mem+len, vmp->vm_endpoint);
#endif
return r;
if(r != OK) return r;
hmstate->len -= sublen;
hmstate->mem += sublen;
}
}

View file

@ -65,12 +65,15 @@ struct vmproc *vmprocess = &vmproc[VM_PROC_NR];
# define SPAREPAGES 150
# define STATIC_SPAREPAGES 140
#else
static u32_t global_bit = 0;
# define SPAREPAGES 20
# define STATIC_SPAREPAGES 15
#endif /* __arm__ */
#endif
#ifdef __i386__
static u32_t global_bit = 0;
#endif
#define SPAREPAGEDIRS 1
#define STATIC_SPAREPAGEDIRS 1
@ -115,7 +118,7 @@ static char static_sparepagedirs[ARCH_PAGEDIR_SIZE*STATIC_SPAREPAGEDIRS + ARCH_P
/*===========================================================================*
* pt_sanitycheck *
*===========================================================================*/
void pt_sanitycheck(pt_t *pt, char *file, int line)
void pt_sanitycheck(pt_t *pt, const char *file, int line)
{
/* Basic pt sanity check. */
int slot;
@ -1234,10 +1237,10 @@ void pt_init(void)
panic("VM: sys_vmctl_get_pdbr failed");
#if defined(__i386__)
if(sys_vircopy(NONE, mypdbr, SELF,
(vir_bytes) currentpagedir, VM_PAGE_SIZE) != OK)
(vir_bytes) currentpagedir, VM_PAGE_SIZE, 0) != OK)
#elif defined(__arm__)
if(sys_vircopy(NONE, myttbr, SELF,
(vir_bytes) currentpagedir, ARCH_PAGEDIR_SIZE) != OK)
(vir_bytes) currentpagedir, ARCH_PAGEDIR_SIZE, 0) != OK)
#endif
panic("VM: sys_vircopy failed");

View file

@ -28,12 +28,12 @@ void *reservedqueue_new(int, int, int, int);
int reservedqueue_alloc(void *, phys_bytes *, void **);
void reservedqueue_add(void *, void *, phys_bytes);
void alloc_cycle(void);
void mem_sanitycheck(char *file, int line);
void mem_sanitycheck(const char *file, int line);
phys_clicks alloc_mem(phys_clicks clicks, u32_t flags);
void memstats(int *nodes, int *pages, int *largest);
void printmemstats(void);
void usedpages_reset(void);
int usedpages_add_f(phys_bytes phys, phys_bytes len, char *file, int
int usedpages_add_f(phys_bytes phys, phys_bytes len, const char *file, int
line);
void free_mem(phys_clicks base, phys_clicks clicks);
void mem_add_total_pages(int pages);
@ -54,7 +54,7 @@ int do_getrusage(message *m);
void clear_proc(struct vmproc *vmp);
int do_exit(message *msg);
int do_willexit(message *msg);
int do_procctl(message *msg);
int do_procctl(message *msg, int transid);
void free_proc(struct vmproc *vmp);
/* fork.c */
@ -84,8 +84,11 @@ int do_vfs_mmap(message *m);
void do_pagefaults(message *m);
void do_memory(void);
char *pf_errstr(u32_t err);
int handle_memory(struct vmproc *vmp, vir_bytes mem, vir_bytes len, int
wrflag, vfs_callback_t cb, void *state, int statelen);
int handle_memory_start(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
int wrflag, endpoint_t caller, endpoint_t requestor, int transid,
int vfs_avail);
int handle_memory_once(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
int wrflag);
/* $(ARCH)/pagetable.c */
void pt_init(void);
@ -115,21 +118,21 @@ int get_vm_self_pages(void);
int pt_writable(struct vmproc *vmp, vir_bytes v);
#if SANITYCHECKS
void pt_sanitycheck(pt_t *pt, char *file, int line);
void pt_sanitycheck(pt_t *pt, const char *file, int line);
#endif
/* slaballoc.c */
void *slaballoc(int bytes);
void slabfree(void *mem, int bytes);
void slabstats(void);
void slab_sanitycheck(char *file, int line);
void slab_sanitycheck(const char *file, int line);
#define SLABALLOC(var) (var = slaballoc(sizeof(*var)))
#define SLABFREE(ptr) do { slabfree(ptr, sizeof(*(ptr))); (ptr) = NULL; } while(0)
#if SANITYCHECKS
void slabunlock(void *mem, int bytes);
void slablock(void *mem, int bytes);
int slabsane_f(char *file, int line, void *mem, int bytes);
int slabsane_f(const char *file, int line, void *mem, int bytes);
#endif
/* region.c */
@ -184,7 +187,7 @@ int get_region_info(struct vmproc *vmp, struct vm_region_info *vri, int
int copy_abs2region(phys_bytes abs, struct vir_region *destregion,
phys_bytes offset, phys_bytes len);
#if SANITYCHECKS
void map_sanitycheck(char *file, int line);
void map_sanitycheck(const char *file, int line);
#endif
/* rs.c */

View file

@ -165,7 +165,7 @@ static int map_sanitycheck_pt(struct vmproc *vmp,
/*===========================================================================*
* map_sanitycheck *
*===========================================================================*/
void map_sanitycheck(char *file, int line)
void map_sanitycheck(const char *file, int line)
{
struct vmproc *vmp;
@ -723,7 +723,9 @@ int map_pf(struct vmproc *vmp,
}
if(r != OK) {
#if 0
printf("map_pf: pagefault in %s failed\n", ph->memtype->name);
#endif
if(ph)
pb_unreferenced(region, ph, 1);
return r;
@ -812,7 +814,7 @@ struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region *vr)
struct phys_region *ph;
int r;
#if SANITYCHECKS
int cr;
unsigned int cr;
cr = physregions(vr);
#endif
vir_bytes p;

View file

@ -16,7 +16,7 @@
printf("VM:%s:%d: %s failed (last sanity check %s:%d)\n", file, line, #c, sc_lastfile, sc_lastline); \
panic("sanity check failed"); } } while(0)
#define SLABSANITYCHECK(l) if(_minix_kerninfo && 0) { \
#define SLABSANITYCHECK(l) if(_minix_kerninfo) { \
slab_sanitycheck(__FILE__, __LINE__); }
#define SANITYCHECK(l) if(!nocheck && _minix_kerninfo && 0) { \

View file

@ -190,7 +190,7 @@ static struct slabdata *newslabdata(void)
/*===========================================================================*
* checklist *
*===========================================================================*/
static int checklist(char *file, int line,
static int checklist(const char *file, int line,
struct slabheader *s, int bytes)
{
struct slabdata *n = s->list_head;
@ -225,7 +225,7 @@ static int checklist(char *file, int line,
/*===========================================================================*
* void slab_sanitycheck *
*===========================================================================*/
void slab_sanitycheck(char *file, int line)
void slab_sanitycheck(const char *file, int line)
{
int s;
for(s = 0; s < SLABSIZES; s++) {
@ -236,7 +236,7 @@ void slab_sanitycheck(char *file, int line)
/*===========================================================================*
* int slabsane *
*===========================================================================*/
int slabsane_f(char *file, int line, void *mem, int bytes)
int slabsane_f(const char *file, int line, void *mem, int bytes)
{
struct slabheader *s;
struct slabdata *f;

View file

@ -170,7 +170,7 @@ int do_info(message *m)
* deadlock. Note that no memory mapping can be undone without the
* involvement of VM, so we are safe until we're done.
*/
r = handle_memory(vmp, ptr, size, 1 /*wrflag*/, NULL, NULL, 0);
r = handle_memory_once(vmp, ptr, size, 1 /*wrflag*/);
if (r != OK) return r;
/* Now that we know the copy out will succeed, perform the actual copy