]> Zhao Yanbai Git Server - minix.git/commitdiff
Merge of Wu's GSOC 09 branch (src.20090525.r4372.wu)
authorCristiano Giuffrida <cristiano@minix3.org>
Thu, 14 Jan 2010 15:24:16 +0000 (15:24 +0000)
committerCristiano Giuffrida <cristiano@minix3.org>
Thu, 14 Jan 2010 15:24:16 +0000 (15:24 +0000)
Main changes:
- COW optimization for safecopy.
- safemap, a grant-based interface for sharing memory regions between processes.
- Integration with safemap and complete rework of DS, supporting new data types
  natively (labels, memory ranges, memory mapped ranges).
- For further information:
  http://wiki.minix3.org/en/SummerOfCode2009/MemoryGrants

Additional changes not included in the original Wu's branch:
- Fixed unhandled case in VM when using COW optimization for safecopy in case
  of a block that has already been shared as SMAP.
- Better interface and naming scheme for sys_saferevmap and ds_retrieve_map
  calls.
- Better input checking in syslib: check for page alignment when creating
  memory mapping grants.
- DS notifies subscribers when an entry is deleted.
- Documented the behavior of indirect grants in case of memory mapping.
- Test suite in /usr/src/test/safeperf|safecopy|safemap|ds/* reworked
  and extended.
- Minor fixes and general cleanup.
- TO-DO: Grant ids should be generated and managed the way endpoints are to make
sure grant slots are never misreused.

99 files changed:
drivers/audio/framework/audio_fw.c
drivers/e1000/e1000.c
drivers/fxp/fxp.c
drivers/orinoco/orinoco.c
drivers/rtl8139/rtl8139.c
drivers/ti1225/ti1225.c
include/minix/com.h
include/minix/const.h
include/minix/ds.h
include/minix/safecopies.h
include/minix/syslib.h
include/minix/sysutil.h
include/unistd.h
kernel/arch/i386/memory.c
kernel/arch/i386/protect.c
kernel/main.c
kernel/proc.h
kernel/proto.h
kernel/system.c
kernel/system.h
kernel/system/Makefile
kernel/system/do_fork.c
kernel/system/do_privctl.c
kernel/system/do_safecopy.c
kernel/system/do_safemap.c [new file with mode: 0644]
kernel/system/do_vmctl.c
lib/Makefile
lib/syslib/Makefile.in
lib/syslib/ds.c
lib/syslib/pci_del_acl.c
lib/syslib/pci_init1.c
lib/syslib/pci_set_acl.c
lib/syslib/safecopies.c
lib/syslib/sys_safemap.c [new file with mode: 0644]
lib/syslib/sys_vmctl.c
lib/sysutil/Makefile.in
lib/sysutil/tsc_util.c [moved from lib/sysutil/micro_delay.c with 80% similarity]
servers/ds/inc.h
servers/ds/main.c
servers/ds/proto.h
servers/ds/store.c
servers/ds/store.h
servers/inet/inet.c
servers/inet/mnx_eth.c
servers/is/dmp_ds.c
servers/mfs/mount.c
servers/rs/memory.c
servers/rs/service.c
servers/rs/table.c
servers/rs/utility.c
servers/vfs/dmap.c
servers/vfs/mount.c
servers/vm/Makefile
servers/vm/break.c
servers/vm/exec.c
servers/vm/i386/pagetable.c
servers/vm/main.c
servers/vm/map_mem.c [new file with mode: 0644]
servers/vm/mmap.c
servers/vm/pagefaults.c
servers/vm/proto.h
servers/vm/queryexit.c
servers/vm/region.c
servers/vm/region.h
servers/vm/rs.c
servers/vm/utility.c
servers/vm/vfs.c
test/ds/Makefile [new file with mode: 0644]
test/ds/README [new file with mode: 0644]
test/ds/down [new file with mode: 0644]
test/ds/dstest.c [new file with mode: 0644]
test/ds/inc.h [new file with mode: 0644]
test/ds/run [new file with mode: 0644]
test/ds/subs.c [new file with mode: 0644]
test/ds/system.conf [new file with mode: 0644]
test/safecopy/Makefile [new file with mode: 0644]
test/safecopy/README [new file with mode: 0644]
test/safecopy/down [new file with mode: 0644]
test/safecopy/grantor.c [new file with mode: 0644]
test/safecopy/inc.h [new file with mode: 0644]
test/safecopy/requestor.c [new file with mode: 0644]
test/safecopy/run [new file with mode: 0644]
test/safecopy/system.conf [new file with mode: 0644]
test/safemap/Makefile [new file with mode: 0644]
test/safemap/README [new file with mode: 0644]
test/safemap/down [new file with mode: 0644]
test/safemap/grantor.c [new file with mode: 0644]
test/safemap/inc.h [new file with mode: 0644]
test/safemap/requestor.c [new file with mode: 0644]
test/safemap/run [new file with mode: 0644]
test/safemap/system.conf [new file with mode: 0644]
test/safeperf/Makefile [new file with mode: 0644]
test/safeperf/README [new file with mode: 0644]
test/safeperf/down [new file with mode: 0644]
test/safeperf/grantor.c [new file with mode: 0644]
test/safeperf/inc.h [new file with mode: 0644]
test/safeperf/requestor.c [new file with mode: 0644]
test/safeperf/run [new file with mode: 0644]
test/safeperf/system.conf [new file with mode: 0644]

index e01526c99bb0b970dc78f2255482570b3b67854c..50bacc235fd63822dd348118991cb9fd87d9c83a 100644 (file)
@@ -1027,11 +1027,11 @@ int pci_func;
        u32_t u32;
        message m;
 
-       r= ds_retrieve_u32("amddev", &u32);
+       r= ds_retrieve_label_num("amddev", &u32);
        if (r != OK)
        {
 #if 0
-               printf("tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
+               printf("tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
                        r);
 #endif
                return;
index 28ed13d30b2fddb0bc8bc035118ddccfa306be23..0734461af094eebab78a2741379ae3678dc0da18 100644 (file)
@@ -157,9 +157,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
     memset(e1000_table, 0, sizeof(e1000_table));
 
     /* Perform calibration. */
-    if((r = micro_delay_calibrate()) != OK)
+    if((r = tsc_calibrate()) != OK)
     {
-        panic("e1000", "rmicro_delay_calibrate failed", r);
+        panic("e1000", "tsc_calibrate failed", r);
     }
     /* Try to notify inet that we are present (again) */
     if ((r = ds_retrieve_u32("inet", &tasknr)) == OK)
index 1d3dbba6e69c6c78411be547f1d1559620d99c39..3be1788bb1ef2fd4c00bdce2cefb98ea65f3cc07 100644 (file)
@@ -414,15 +414,15 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
 
        memset(fxp_table, 0, ft);
 
-       if((r=micro_delay_calibrate()) != OK)
-               panic("FXP","rmicro_delay_calibrate failed", r);
+       if((r=tsc_calibrate()) != OK)
+               panic("FXP","tsc_calibrate failed", r);
 
        /* Try to notify inet that we are present (again) */
-       r= ds_retrieve_u32("inet", &tasknr);
+       r= ds_retrieve_label_num("inet", &tasknr);
        if (r == OK)
                notify(tasknr);
        else if (r != ESRCH)
-               printf("fxp: ds_retrieve_u32 failed for 'inet': %d\n", r);
+               printf("fxp: ds_retrieve_label_num failed for 'inet': %d\n", r);
 
        return(OK);
 }
@@ -3013,12 +3013,12 @@ int pci_func;
        u32_t u32;
        message m;
 
-       r= ds_retrieve_u32("amddev", &u32);
+       r= ds_retrieve_label_num("amddev", &u32);
        if (r != OK)
        {
 #if 0
                printf(
-               "fxp`tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
+               "fxp`tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
                        r);
 #endif
                return;
index 515246ad2fe4bca08313e4fb5844b5711f36eaab..c09a844679da5f1db24bafa22d188ecf5bea432e 100644 (file)
@@ -367,11 +367,11 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
        /* Try to notify INET that we are present (again). If INET cannot
         * be found, assume this is the first time we started and INET is
         * not yet alive. */
-       r = ds_retrieve_u32("inet", &inet_proc_nr);
+       r = ds_retrieve_label_num("inet", &inet_proc_nr);
        if (r == OK) 
                notify(inet_proc_nr);
        else if (r != ESRCH)
-               printf("orinoco: ds_retrieve_u32 failed for 'inet': %d\n", r);
+               printf("orinoco: ds_retrieve_label_num failed for 'inet': %d\n", r);
 
        return(OK);
 }
index e709ea43f81e80016ffe04d44f2596fb1b84e7e7..888acf6b5f39c555e6a32843e7d8e8b91989c7ac 100644 (file)
@@ -336,11 +336,11 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
         * be found, assume this is the first time we started and INET is
         * not yet alive.
         */
-       r= ds_retrieve_u32("inet", &inet_proc_nr);
+       r= ds_retrieve_label_num("inet", &inet_proc_nr);
        if (r == OK)
                notify(inet_proc_nr);
        else if (r != ESRCH)
-               printf("rtl8139: ds_retrieve_u32 failed for 'inet': %d\n", r);
+               printf("rtl8139: ds_retrieve_label_num failed for 'inet': %d\n", r);
 
        return(OK);
 }
@@ -3017,12 +3017,12 @@ int pci_func;
        u32_t u32;
        message m;
 
-       r= ds_retrieve_u32("amddev", &u32);
+       r= ds_retrieve_label_num("amddev", &u32);
        if (r != OK)
        {
 #if 0
                printf(
-               "rtl8139`tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
+               "rtl8139`tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
                        r);
 #endif
                return;
index 83e5a8fe818e64675d00bbb3bd4528579a7f70ca..9ada092e6c714603df4dee6e2c34c78f11a0f7f1 100644 (file)
@@ -117,8 +117,8 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
        (progname=strrchr(env_argv[0],'/')) ? progname++
                : (progname=env_argv[0]);
 
-       if((r=micro_delay_calibrate()) != OK)
-               panic("ti1225", "micro_delay_calibrate failed", r);
+       if((r=tsc_calibrate()) != OK)
+               panic("ti1225", "tsc_calibrate failed", r);
 
        debug= 0;
        while (c= getopt(env_argc, env_argv, "d?"), c != -1)
index 318ee380d21595f0a8fe5379eb57ef65aae5fa34..0386e6c24ece03b2301fa422279a1215b018e030 100644 (file)
 
 #  define SYS_VTIMER     (KERNEL_CALL + 45)    /* sys_vtimer() */
 #  define SYS_RUNCTL     (KERNEL_CALL + 46)    /* sys_runctl() */
+#  define SYS_SAFEMAP   (KERNEL_CALL + 47)     /* sys_safemap() */
+#  define SYS_SAFEREVMAP (KERNEL_CALL + 48)    /* sys_saferevmap() sys_saferevmap2() */
+#  define SYS_SAFEUNMAP         (KERNEL_CALL + 49)     /* sys_safeunmap() */
 
-#define NR_SYS_CALLS   47      /* number of system calls */ 
+#define NR_SYS_CALLS   50      /* number of system calls */ 
 #define SYS_CALL_MASK_SIZE BITMAP_CHUNKS(NR_SYS_CALLS)
 
 /* Field names for SYS_MEMSET. */
 #define VSCP_VEC_ADDR  m2_p1   /* start of vector */
 #define VSCP_VEC_SIZE  m2_l2   /* elements in vector */
 
+/* Field names for SYS_SAFEMAPs */
+#define SMAP_EP                m2_i1
+#define SMAP_GID       m2_i2
+#define SMAP_OFFSET    m2_i3
+#define SMAP_SEG       m2_p1
+#define SMAP_ADDRESS   m2_l1
+#define SMAP_BYTES     m2_l2
+#define SMAP_FLAG      m2_s1
+
 /* 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 */ 
 #define SVMCTL_PF_WHO          m1_i1   /* GET_PAGEFAULT reply: process ep */
 #define SVMCTL_PF_I386_CR2     m1_i2   /* GET_PAGEFAULT reply: CR2 */
 #define SVMCTL_PF_I386_ERR     m1_i3   /* GET_PAGEFAULT reply: error code */
-#define SVMCTL_MRG_ADDR                m1_p1   /* MEMREQ_GET reply: address */
-#define SVMCTL_MRG_LEN         m1_i1   /* MEMREQ_GET reply: length */
-#define SVMCTL_MRG_WRITE       m1_i2   /* MEMREQ_GET reply: writeflag */
-#define SVMCTL_MRG_EP          m1_i3   /* MEMREQ_GET reply: process */
-#define SVMCTL_MRG_REQUESTOR   m1_p2   /* MEMREQ_GET reply: requestor */
+#define        SVMCTL_MRG_TARGET       m2_i1   /* MEMREQ_GET reply: target process */
+#define        SVMCTL_MRG_ADDR         m2_i2   /* MEMREQ_GET reply: address */
+#define        SVMCTL_MRG_LENGTH       m2_i3   /* MEMREQ_GET reply: length */
+#define        SVMCTL_MRG_FLAG         m2_s1   /* MEMREQ_GET reply: flag */
+#define        SVMCTL_MRG_EP2          m2_l1   /* MEMREQ_GET reply: source process */
+#define        SVMCTL_MRG_ADDR2        m2_l2   /* MEMREQ_GET reply: source address */
+#define SVMCTL_MRG_REQUESTOR   m2_p1   /* MEMREQ_GET reply: requestor */
 #define SVMCTL_MAP_VIR_ADDR    m1_p1
 
 /* Reply message for VMCTL_KERN_PHYSMAP */
 
 #define DS_RQ_BASE             0x800
 
-#define DS_PUBLISH     (DS_RQ_BASE + 0)        /* publish information */
-#define DS_SUBSCRIBE   (DS_RQ_BASE + 1)        /* subscribe to information */
-#define DS_RETRIEVE    (DS_RQ_BASE + 2)        /* retrieve information by name */
-#define DS_CHECK       (DS_RQ_BASE + 3)        /* retrieve updated information */
-
-/* DS field names: DS_SUBSCRIBE, DS_PUBLISH, DS_RETRIEVE */
-#  define DS_KEY_GRANT         m2_p1           /* key for the information */
-#  define DS_KEY_LEN           m2_i1           /* length of key incl. '\0' */
+#define DS_PUBLISH     (DS_RQ_BASE + 0)        /* publish data */
+#define DS_RETRIEVE    (DS_RQ_BASE + 1)        /* retrieve data by name */
+#define DS_SUBSCRIBE   (DS_RQ_BASE + 2)        /* subscribe to data updates */
+#define DS_CHECK       (DS_RQ_BASE + 3)        /* retrieve updated data */
+#define DS_DELETE      (DS_RQ_BASE + 4)        /* delete data */
+#define DS_SNAPSHOT    (DS_RQ_BASE + 5)        /* take a snapshot */
+#define DS_RETRIEVE_LABEL  (DS_RQ_BASE + 6)    /* retrieve label's name */
+
+/* DS field names */
+#  define DS_KEY_GRANT         m2_i1           /* key for the data */
+#  define DS_KEY_LEN           m2_s1           /* length of key incl. '\0' */
 #  define DS_FLAGS             m2_i2           /* flags provided by caller */
 
-/* DS_PUBLISH, DS_RETRIEVE */
 #  define DS_VAL               m2_l1           /* data (u32, char *, etc.) */
 #  define DS_VAL_LEN           m2_l2           /* data length */
+#  define DS_NR_SNAPSHOT       m2_i3           /* number of snapshot */
+#  define DS_STRING            m2_i3           /* inline string */
 
 /*===========================================================================*
  *                Miscellaneous messages used by TTY                        *
index 38252b33399c38cb0bc3326c8222fe6b672086c4..1a495a74b152fd7f96fbfec8e1b3baa4185be8c9 100644 (file)
 #define CLICK_SHIFT      12    /* log2 of CLICK_SIZE */
 #endif
 
+/* Click alignment macros. */
+#define CLICK_FLOOR(n)  (((vir_bytes)(n) / CLICK_SIZE) * CLICK_SIZE)
+#define CLICK_CEIL(n)   CLICK_FLOOR((vir_bytes)(n) + CLICK_SIZE-1)
+
 /* Sizes of memory tables. The boot monitor distinguishes three memory areas,
  * namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed
  * for DOS MINIX.
index ce6453b9554a9fb1600895f713bffa1daf1572cc..fd9f42296c595385e25cded63bc0ccfd366a3688 100644 (file)
@@ -5,34 +5,68 @@
 
 #include <minix/types.h>
 
-/* DS Flag values. */
-#define DS_IN_USE       0x0001 /* Internal use only. */
-#define DS_PUBLIC       0x0002 /* Publically retrievable value. */
-#define DS_INITIAL      0x0004 /* On subscription, send initial contents. */
+/* Flags. */
+#define DSF_IN_USE             0x001   /* entry is in use */
+#define DSF_PRIV_RETRIEVE      0x002   /* only owner can retrieve */
+#define DSF_PRIV_OVERWRITE     0x004   /* only owner can overwrite */
+#define DSF_PRIV_SNAPSHOT      0x004   /* only owner can take a snapshot */
+#define DSF_PRIV_SUBSCRIBE     0x008   /* only owner can subscribe */
+#define DSF_TYPE_U32           0x010   /* u32 data type */
+#define DSF_TYPE_STR           0x020   /* string data type */
+#define DSF_TYPE_MEM           0x040   /* memory range data type */
+#define DSF_TYPE_MAP           0x080   /* mapped memory range data type */
+#define DSF_TYPE_LABEL         0x100   /* label data type */
 
-/* These type flags are mutually exclusive. Give as args to ds_subscribe. */
-#define DS_TYPE_U32     0x0100
-#define DS_TYPE_STR     0x0200
-#define DS_TYPE_MASK    0xff00 /* All type info. */
+#define DSF_MASK_TYPE          0xFF0   /* mask for type flags. */
+#define DSF_MASK_INTERNAL      0xFFF   /* mask for internal flags. */
+
+#define DSF_OVERWRITE          0x01000 /* overwrite if entry exists */
+#define DSF_INITIAL            0x02000 /* check subscriptions immediately */
+
+#define DSMF_MAP_MAPPED                0x10000 /* map mapped memory range */
+#define DSMF_COPY_MAPPED       0x20000 /* copy mapped memory range */
+#define DSMF_COPY_SNAPSHOT     0x40000 /* copy snapshot */
 
 /* DS constants. */
-#define DS_MAX_KEYLEN 80        /* Max length for a key, including '\0'. */
-#define DS_MAX_VALLEN 100      /* Max legnth for a str value, incl '\0'. */ 
+#define DS_MAX_KEYLEN 80        /* Max length of a key, including '\0'. */
+#define DS_MAX_STRLEN 16        /* Max length of string, including '\0'. */
 
 /* ds.c */
-_PROTOTYPE( int ds_subscribe, (char *name_regexp, int type, int flags));
 
-/* publish/update item */
-_PROTOTYPE( int ds_publish_u32, (char *name, u32_t val));
-_PROTOTYPE( int ds_publish_str, (char *name, char *val));
+/* U32 */
+_PROTOTYPE( int ds_publish_u32, (const char *name, u32_t val, int flags));
+_PROTOTYPE( int ds_retrieve_u32, (const char *name, u32_t *val));
+_PROTOTYPE( int ds_delete_u32, (const char *ds_name));
+
+/* STRING */
+_PROTOTYPE( int ds_publish_str, (const char *name, char *val, int flags));
+_PROTOTYPE( int ds_retrieve_str, (const char *name, char *val, size_t len));
+_PROTOTYPE( int ds_delete_str, (const char *ds_name));
+
+/* MEM */
+_PROTOTYPE( int ds_publish_mem, (const char *ds_name, void *vaddr,
+               size_t length, int flags));
+_PROTOTYPE( int ds_retrieve_mem, (const char *ds_name, char *vaddr,
+               size_t *length));
+_PROTOTYPE( int ds_delete_mem, (const char *ds_name));
+
+/* MAP */
+_PROTOTYPE( int ds_publish_map, (const char *ds_name, void *vaddr,
+               size_t length, int flags));
+_PROTOTYPE( int ds_snapshot_map, (const char *ds_name, int *nr_snapshot));
+_PROTOTYPE( int ds_retrieve_map, (const char *ds_name, char *vaddr,
+               size_t *length, int nr_snapshot, int flags));
+_PROTOTYPE( int ds_delete_map, (const char *ds_name));
 
-/* retrieve item by name + type */
-_PROTOTYPE( int ds_retrieve_u32, (char *name, u32_t *val)          );
-_PROTOTYPE( int ds_retrieve_str, (char *name, char *val, size_t len));
+/* LABEL */
+_PROTOTYPE( int ds_publish_label, (const char *ds_name, u32_t value,int flags));
+_PROTOTYPE( int ds_retrieve_label_name, (char *ds_name, u32_t num));
+_PROTOTYPE( int ds_retrieve_label_num, (const char *ds_name, u32_t *value));
+_PROTOTYPE( int ds_delete_label, (const char *ds_name));
 
-/* retrieve updates for item */
-_PROTOTYPE( int ds_check_u32, (char *n, size_t namelen, u32_t *val));
-_PROTOTYPE( int ds_check_str, (char *n, size_t namelen, char *v, size_t vlen));
+/* Subscribe and check. */
+_PROTOTYPE( int ds_subscribe, (const char *regex, int flags));
+_PROTOTYPE( int ds_check, (char *ds_name, int *type));
 
 #endif /* _MINIX_DS_H */
 
index 697d77889e0dceed01ca553aaf3f995bf8caf04c..50b8623d7b15eab9a5e22351017551b82ec1d02a 100644 (file)
@@ -49,6 +49,13 @@ struct vscp_vec {
         size_t          v_bytes;        /* no. of bytes */
 };
 
+/* Types on VM invocation. */
+#define VMPTYPE_NONE           0
+#define VMPTYPE_CHECK          1
+#define VMPTYPE_COWMAP         2
+#define VMPTYPE_SMAP           3
+#define VMPTYPE_SUNMAP         4
+
 /* Invalid grant number. */
 #define GRANT_INVALID  -1
 #define GRANT_VALID(g) ((g) > GRANT_INVALID)
@@ -56,6 +63,7 @@ struct vscp_vec {
 /* Operations: any combination is ok. */
 #define CPF_READ       0x000001 /* Granted process may read. */
 #define CPF_WRITE      0x000002 /* Granted process may write. */
+#define CPF_MAP                0x000004 /* Granted process may map. */
 
 /* Internal flags. */
 #define CPF_USED       0x000100 /* Grant slot in use. */
index 6ff557a3f2d18015cc0ece7142bffb9bb9c75d0a..c0c1df9ffe1c3ab443d161df9ca10da9851e0b1f 100644 (file)
@@ -62,7 +62,8 @@ _PROTOTYPE( int sys_vmctl, (endpoint_t who, int param, u32_t value));
 _PROTOTYPE( int sys_vmctl_get_pagefault_i386, (endpoint_t *who, u32_t *cr2, u32_t *err));
 _PROTOTYPE( int sys_vmctl_get_cr3_i386, (endpoint_t who, u32_t *cr3)  );
 _PROTOTYPE( int sys_vmctl_get_memreq, (endpoint_t *who, vir_bytes *mem,
-        vir_bytes *len, int *wrflag, endpoint_t *) );
+        vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
+        endpoint_t *) );
 _PROTOTYPE( int sys_vmctl_enable_paging, (struct mem_map *));
 
 _PROTOTYPE( int sys_readbios, (phys_bytes address, void *buf, size_t size));
@@ -149,6 +150,14 @@ _PROTOTYPE(int sys_vsafecopy, (struct vscp_vec *copyvec, int elements));
 _PROTOTYPE(int sys_memset, (unsigned long pattern, 
                phys_bytes base, phys_bytes bytes));
 
+/* Grant-based map functions. */
+_PROTOTYPE(int sys_safemap, (endpoint_t grantor, cp_grant_id_t grant,
+       vir_bytes grant_offset, vir_bytes my_address, size_t bytes, int my_seg,
+       int writable));
+_PROTOTYPE(int sys_saferevmap_gid, (cp_grant_id_t grant));
+_PROTOTYPE(int sys_saferevmap_addr, (vir_bytes addr));
+_PROTOTYPE(int sys_safeunmap, (int my_seg, vir_bytes my_address));
+
 _PROTOTYPE(int sys_umap, (endpoint_t proc_ep, int seg, vir_bytes vir_addr,
         vir_bytes bytes, phys_bytes *phys_addr));
 _PROTOTYPE(int sys_umap_data_fb, (endpoint_t proc_ep, vir_bytes vir_addr,
index 487c6b864921ad28f1fda6ce44be2f29ac3f3eac..cc09c2dd452dabe958734224d92e4655d6cc655e 100644 (file)
@@ -49,13 +49,15 @@ _PROTOTYPE( void panic, (char *who, char *mess, int num));
 _PROTOTYPE( int getuptime, (clock_t *ticks));
 _PROTOTYPE( int getuptime2, (clock_t *ticks, time_t *boottime));
 _PROTOTYPE( int tickdelay, (clock_t ticks));
-_PROTOTYPE( int micro_delay_calibrate, (void));
+_PROTOTYPE( int tsc_calibrate, (void));
 _PROTOTYPE( u32_t sys_hz, (void));
 _PROTOTYPE( double getidle, (void));
 _PROTOTYPE( void util_stacktrace, (void));
 _PROTOTYPE( void util_nstrcat, (char *str, unsigned long n) );
 _PROTOTYPE( void util_stacktrace_strcat, (char *));
 _PROTOTYPE( int micro_delay, (u32_t micros));
+_PROTOTYPE( u32_t tsc_64_to_micros, (u64_t tsc));
+_PROTOTYPE( u32_t tsc_to_micros, (u32_t low, u32_t high));
 _PROTOTYPE( u32_t micros_to_ticks, (u32_t micros));
 _PROTOTYPE( void ser_putc, (char c));
 _PROTOTYPE( void get_randomness, (struct k_randomness *, int));
index 5c25f64fc916fe2d0e1b17adf7ca8c7fde8ef993..e7c8bd682332ce7ee0a9c8d42c065d2cb6e240c4 100644 (file)
 #define SI_PROC_TAB       2    /* copy of entire process table */
 #define SI_DMAP_TAB       3    /* get device <-> driver mappings */
 #define SI_MEM_ALLOC      4    /* get memory allocation data */
-#define SI_DATA_STORE     5    /* get copy of data store */
-#define SI_LOADINFO       6    /* get copy of load average structure */
-#define SI_KPROC_TAB      7    /* copy of kernel process table */
-#define SI_CALL_STATS     8    /* system call statistics */
-#define SI_PCI_INFO       9    /* get kernel info via PM */
-#define SI_PROCPUB_TAB   10    /* copy of public entries of process table */
+#define SI_DATA_STORE     5    /* get copy of data store mappings */
+#define SI_SUBSCRIPTION           6    /* get copy of data store subscriptions */
+#define SI_LOADINFO       7    /* get copy of load average structure */
+#define SI_KPROC_TAB      8    /* copy of kernel process table */
+#define SI_CALL_STATS     9    /* system call statistics */
+#define SI_PCI_INFO       10   /* get kernel info via PM */
+#define SI_PROCPUB_TAB    11   /* copy of public entries of process table */
 
 /* NULL must be defined in <unistd.h> according to POSIX Sec. 2.7.1. */
 #define NULL    ((void *)0)
index 4f2b44ec7f664777de9a21cacb04fa921030890c..4b5793b6b2f4967e96dd556c209ab2df42cfe40b 100644 (file)
@@ -613,10 +613,11 @@ PUBLIC int vm_suspend(struct proc *caller, struct proc *target,
        util_stacktrace_strcat(caller->p_vmrequest.stacktrace);
 #endif
 
-       caller->p_vmrequest.writeflag = 1;
-       caller->p_vmrequest.start = linaddr;
-       caller->p_vmrequest.length = len;
-       caller->p_vmrequest.who = target->p_endpoint;
+       caller->p_vmrequest.req_type = VMPTYPE_CHECK;
+       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.type = type;
                                                        
        /* Connect caller on vmrequest wait queue. */   
index 203865e34e0843875bc1b65cf60fe1d39a54a3c0..afb142cde9c789f25734742154f67d7e11cb0418 100644 (file)
@@ -137,12 +137,7 @@ PUBLIC void prot_init(void)
   /* Click-round kernel. */
   if(kinfo.data_base % CLICK_SIZE)
        minix_panic("kinfo.data_base not aligned", NO_NUM);
-  kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
-
-  /* Click-round kernel. */
-  if(kinfo.data_base % CLICK_SIZE)
-       minix_panic("kinfo.data_base not aligned", NO_NUM);
-  kinfo.data_size = ((kinfo.data_size+CLICK_SIZE-1)/CLICK_SIZE) * CLICK_SIZE;
+  kinfo.data_size = (phys_bytes) (CLICK_CEIL(kinfo.data_size));
 
   /* Build gdt and idt pointers in GDT where the BIOS expects them. */
   dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
index 988fb1f71213a2ae7b3dd3333dad700a1a4c49f2..589645578a296a0d9e493b50e75f8fca2f95a402 100644 (file)
@@ -154,13 +154,14 @@ PUBLIC void main()
 
        /* Convert addresses to clicks and build process memory map */
        text_base = e_hdr.a_syms >> CLICK_SHIFT;
-       text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT;
-       data_clicks = (e_hdr.a_data+e_hdr.a_bss + CLICK_SIZE-1) >> CLICK_SHIFT;
-       st_clicks= (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
+       text_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_text) >> CLICK_SHIFT);
+       data_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_data
+               + e_hdr.a_bss) >> CLICK_SHIFT);
+       st_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_total) >> CLICK_SHIFT);
        if (!(e_hdr.a_flags & A_SEP))
        {
-               data_clicks= (e_hdr.a_text+e_hdr.a_data+e_hdr.a_bss +
-                       CLICK_SIZE-1) >> CLICK_SHIFT;
+               data_clicks = (vir_clicks) (CLICK_CEIL(e_hdr.a_text +
+                       e_hdr.a_data + e_hdr.a_bss) >> CLICK_SHIFT);
                text_clicks = 0;           /* common I&D */
        }
        rp->p_memmap[T].mem_phys = text_base;
index 092edbe06ae4198f438531f3262a9514170541cb..788f7b2c47651b7100a8d558ff7f0ba1aa40e955 100644 (file)
@@ -61,7 +61,7 @@ struct proc {
    * memory that isn't present, VM has to fix it. Until it has asked
    * what needs to be done and fixed it, save necessary state here.
    *
-   * The requester gets a copy of its request message in reqmsg and gets
+   * The requestor gets a copy of its request message in reqmsg and gets
    * VMREQUEST set.
    */
   struct {
@@ -70,6 +70,8 @@ struct proc {
 #define VMSTYPE_SYS_NONE       0
 #define VMSTYPE_KERNELCALL     1
 #define VMSTYPE_DELIVERMSG     2
+#define VMSTYPE_MAP            3
+
        int             type;           /* suspended operation */
        union {
                /* VMSTYPE_SYS_MESSAGE */
@@ -77,10 +79,20 @@ struct proc {
        } saved;
 
        /* Parameters of request to VM */
-       vir_bytes       start, length;  /* memory range */
-       u8_t            writeflag;      /* nonzero for write access */
-       endpoint_t      who;
-
+       int             req_type;
+       endpoint_t      target;
+       union {
+               struct {
+                       vir_bytes       start, length;  /* memory range */
+                       u8_t            writeflag;      /* nonzero for write access */
+               } check;
+               struct {
+                       char            writeflag;
+                       endpoint_t      ep_s;
+                       vir_bytes       vir_s, vir_d;
+                       vir_bytes       length;
+               } map;
+       } params;
        /* VM result when available */
        int             vmresult;
 
index 3c8fb3c7fed61c92c323a8f6484916f7a4e51e98..2ca58ec92de013c43b3ae98d20e388d5b16694a5 100644 (file)
@@ -89,6 +89,12 @@ _PROTOTYPE( void check_runqueues_f, (char *file, int line) );
 _PROTOTYPE( char *rtsflagstr, (int flags) );
 _PROTOTYPE( char *miscflagstr, (int flags) );
 
+/* system/do_safemap.c */
+_PROTOTYPE( int map_invoke_vm, (int req_type,
+               endpoint_t end_d, int seg_d, vir_bytes off_d,
+               endpoint_t end_s, int seg_s, vir_bytes off_s,
+               size_t size, int flag));
+
 /* system/do_safecopy.c */
 _PROTOTYPE( int verify_grant, (endpoint_t, endpoint_t, cp_grant_id_t, vir_bytes,
        int, vir_bytes, vir_bytes *, endpoint_t *));
index 589f5c9c7a2187020972a96f1247ae5f9f110f35..cb0ab8d5dc606fcf553b1db13cd505d58f83b79a 100644 (file)
@@ -208,6 +208,11 @@ PRIVATE void initialize(void)
   map(SYS_SAFECOPYTO, do_safecopy);    /* copy with pre-granted permission */
   map(SYS_VSAFECOPY, do_vsafecopy);    /* vectored safecopy */
 
+  /* Mapping. */
+  map(SYS_SAFEMAP, do_safemap);                /* map pages from other process */
+  map(SYS_SAFEREVMAP, do_saferevmap);  /* grantor revokes the map grant */
+  map(SYS_SAFEUNMAP, do_safeunmap);    /* requestor unmaps the mapped pages */
+
   /* Clock functionality. */
   map(SYS_TIMES, do_times);            /* get uptime and process times */
   map(SYS_SETALARM, do_setalarm);      /* schedule a synchronous alarm */
@@ -262,10 +267,6 @@ int priv_id;                               /* privilege id */
   }
   rc->p_priv = sp;                         /* assign new slot */
   rc->p_priv->s_proc_nr = proc_nr(rc);     /* set association */
-  
-  /* Clear some fields */
-  sp->s_asyntab= -1;
-  sp->s_asynsize= 0;
 
   return(OK);
 }
@@ -482,9 +483,11 @@ register struct proc *rc;          /* slot of process to clean up */
   if (priv(rc)->s_flags & SYS_PROC)
   {
        if (priv(rc)->s_asynsize) {
+#if 0
                kprintf("clear_endpoint: clearing s_asynsize of %s / %d\n",
                        rc->p_name, rc->p_endpoint);
                proc_stacktrace(rc);
+#endif
        }
        priv(rc)->s_asynsize= 0;
   }
index 5fcd116f3b77518d4a2f163c4a1b6bbcd5bc27d5..ac13bb908cc688ac1b0742d63895043615f9c7c0 100644 (file)
@@ -181,6 +181,10 @@ _PROTOTYPE( int do_setgrant, (message *m_ptr) );
 _PROTOTYPE( int do_readbios, (message *m_ptr) );       
 _PROTOTYPE( int do_mapdma, (message *m_ptr) ); 
 
+_PROTOTYPE( int do_safemap, (message *m_ptr) );        
+_PROTOTYPE( int do_saferevmap, (message *m_ptr) );     
+_PROTOTYPE( int do_safeunmap, (message *m_ptr) );      
+
 _PROTOTYPE( int do_sprofile, (message *m_ptr) );
 #if ! SPROFILE
 #define do_sprofile do_unused
index ec46ebe8e22f933f3294319339bfb358041f278b..67bddfb89f78ab956697cdbb6aa7b81147074d27 100644 (file)
@@ -44,6 +44,7 @@ OBJECTS       = \
        $(SYSTEM)(do_privctl.o) \
        $(SYSTEM)(do_segctl.o) \
        $(SYSTEM)(do_safecopy.o) \
+       $(SYSTEM)(do_safemap.o) \
        $(SYSTEM)(do_sysctl.o) \
        $(SYSTEM)(do_getksig.o) \
        $(SYSTEM)(do_endksig.o) \
@@ -155,6 +156,9 @@ $(SYSTEM)(do_privctl.o):    do_privctl.c
 $(SYSTEM)(do_safecopy.o):      do_safecopy.c
        $(CC) do_safecopy.c
 
+$(SYSTEM)(do_safemap.o):       do_safemap.c
+       $(CC) do_safemap.c
+
 $(SYSTEM)(do_sysctl.o):        do_sysctl.c
        $(CC) do_sysctl.c
 
index 6d9c39cb0da2eaf5dd9dc0dba4a8d97aae994a7f..ef67d6d24c4c2365d2626723e440e4c59cbdae86 100644 (file)
@@ -49,12 +49,6 @@ register message *m_ptr;     /* pointer to request message */
        return EINVAL;
   }
 
-  /* memory becomes readonly */
-  if (priv(rpp)->s_asynsize > 0) {
-       printf("kernel: process with waiting asynsend table can't fork\n");
-       return EINVAL;
-  }
-
   map_ptr= (struct mem_map *) m_ptr->PR_MEM_PTR;
 
   /* Copy parent 'proc' struct to child. And reinitialize some fields. */
index 7081d31906339a54df91f099ac07565afe3a01d4..4cf90084c03d1d4928ffcc694c41169057ad4c04 100644 (file)
@@ -101,6 +101,8 @@ message *m_ptr;                     /* pointer to request message */
              priv(rp)->s_notify_pending.chunk[i] = 0;  /* - notifications */
        priv(rp)->s_int_pending = 0;                    /* - interrupts */
        sigemptyset(&priv(rp)->s_sig_pending);          /* - signals */
+       priv(rp)->s_asyntab= -1;                        /* - asynsends */
+       priv(rp)->s_asynsize= 0;
 
        /* Set defaults for privilege bitmaps. */
        priv(rp)->s_flags= DEF_SYS_F;           /* privilege flags */
index aa171551fe2f019baf1667d2834f37cf955feeeb..9306cd650abb148aec029c191f64dc0ed8586a43 100644 (file)
@@ -24,6 +24,8 @@
 
 #define MEM_TOP 0xFFFFFFFFUL
 
+#define USE_COW_SAFECOPY 0
+
 FORWARD _PROTOTYPE(int safecopy, (endpoint_t, endpoint_t, cp_grant_id_t, int, int, size_t, vir_bytes, vir_bytes, int));
 
 #define HASGRANTTABLE(gr) \
@@ -229,9 +231,10 @@ int access;                        /* CPF_READ for a copy from granter to grantee, CPF_WRITE
 {
        static struct vir_addr v_src, v_dst;
        static vir_bytes v_offset;
-       int r;
        endpoint_t new_granter, *src, *dst;
        struct proc *granter_p;
+       vir_bytes size;
+       int r;
 
        /* See if there is a reasonable grant table. */
        if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
@@ -279,8 +282,48 @@ int access;                        /* CPF_READ for a copy from granter to grantee, CPF_WRITE
        }
 
        /* Do the regular copy. */
-       return virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+#if USE_COW_SAFECOPY
+       if(v_offset % CLICK_SIZE != addr % CLICK_SIZE || bytes < CLICK_SIZE) {
+               /* Give up on COW immediately when offsets are not aligned
+                * or we are copying less than a page.
+                */
+               return virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+       }
 
+       if((size = v_offset % CLICK_SIZE) != 0) {
+               /* Normal copy for everything before the first page boundary. */
+               size = CLICK_SIZE - size;
+               r = virtual_copy_vmcheck(&v_src, &v_dst, size);
+               if(r != OK)
+                       return r;
+               v_src.offset += size;
+               v_dst.offset += size;
+               bytes -= size;
+       }
+       if((size = bytes / CLICK_SIZE) != 0) {
+               /* Use COW optimization when copying entire pages. */
+               size *= CLICK_SIZE;
+               r = map_invoke_vm(VMPTYPE_COWMAP,
+                       v_dst.proc_nr_e, v_dst.segment, v_dst.offset,
+                       v_src.proc_nr_e, v_src.segment, v_src.offset,
+                       size, 0);
+               if(r != OK)
+                       return r;
+               v_src.offset += size;
+               v_dst.offset += size;
+               bytes -= size;
+       }
+       if(bytes != 0) {
+               /* Normal copy for everything after the last page boundary. */
+               r = virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+               if(r != OK)
+                       return r;
+       }
+
+       return OK;
+#else
+       return virtual_copy_vmcheck(&v_src, &v_dst, bytes);
+#endif
 }
 
 /*===========================================================================*
diff --git a/kernel/system/do_safemap.c b/kernel/system/do_safemap.c
new file mode 100644 (file)
index 0000000..95b448c
--- /dev/null
@@ -0,0 +1,285 @@
+/* The kernel call implemented in this file:
+ *   m_type:   SYS_SAFEMAP or SYS_SAFEREVMAP or SYS_SAFEUNMAP
+ *
+ * The parameters for this kernel call are:
+ *     SMAP_EP         endpoint of the grantor
+ *     SMAP_GID        grant id
+ *     SMAP_OFFSET     offset of the grant space
+ *     SMAP_SEG        segment
+ *     SMAP_ADDRESS    address
+ *     SMAP_BYTES      bytes to be copied
+ *     SMAP_FLAG       access, writable map or not?
+ */
+
+#include <minix/type.h>
+#include <minix/safecopies.h>
+
+#include "../system.h"
+#include "../vm.h"
+
+
+struct map_info_s {
+       int flag;
+
+       /* Grantor. */
+       endpoint_t grantor;
+       int gid;
+       vir_bytes offset;
+       vir_bytes address_Dseg; /* seg always is D */
+
+       /* Grantee. */
+       endpoint_t grantee;
+       int seg;
+       vir_bytes address;
+
+       /* Length. */
+       vir_bytes bytes;
+};
+
+#define MAX_MAP_INFO 20
+static struct map_info_s map_info[MAX_MAP_INFO];
+
+/*===========================================================================*
+ *                             add_info                                     *
+ *===========================================================================*/
+static int add_info(endpoint_t grantor, endpoint_t grantee, int gid,
+               vir_bytes offset, vir_bytes address_Dseg,
+               int seg, vir_bytes address, vir_bytes bytes)
+{
+       int i;
+
+       for(i = 0; i < MAX_MAP_INFO; i++) {
+               if(map_info[i].flag == 0)
+                       break;
+       }
+       if(i == MAX_MAP_INFO)
+               return EBUSY;
+
+       map_info[i].flag = 1;
+       map_info[i].grantor = grantor;
+       map_info[i].grantee = grantee;
+       map_info[i].gid = gid;
+       map_info[i].address_Dseg = address_Dseg;
+       map_info[i].offset = offset;
+       map_info[i].seg = seg;
+       map_info[i].address = address;
+       map_info[i].bytes = bytes;
+
+       return OK;
+}
+
+/*===========================================================================*
+ *                             get_revoke_info                              *
+ *===========================================================================*/
+static struct map_info_s *get_revoke_info(endpoint_t grantor, int flag, int arg)
+{
+       int i;
+       for(i = 0; i < MAX_MAP_INFO; i++) {
+               if(map_info[i].flag == 1
+                       && map_info[i].grantor == grantor
+                       && (flag ? (map_info[i].gid == arg)
+                                : (map_info[i].address_Dseg == arg)))
+                       return &map_info[i];
+       }
+
+       return NULL;
+}
+
+/*===========================================================================*
+ *                             get_unmap_info                               *
+ *===========================================================================*/
+static struct map_info_s *get_unmap_info(endpoint_t grantee, int seg,
+       vir_bytes address)
+{
+       int i;
+       for(i = 0; i < MAX_MAP_INFO; i++) {
+               if(map_info[i].flag == 1
+                       && map_info[i].grantee == grantee
+                       && map_info[i].seg == seg
+                       && map_info[i].address == address)
+                       return &map_info[i];
+       }
+
+       return NULL;
+}
+
+/*===========================================================================*
+ *                             clear_info                                   *
+ *===========================================================================*/
+static int clear_info(struct map_info_s *p)
+{
+       p->flag = 0;
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                             map_invoke_vm                                *
+ *===========================================================================*/
+PUBLIC int map_invoke_vm(int req_type, /* VMPTYPE_... COWMAP, SMAP, SUNMAP */
+               endpoint_t end_d, int seg_d, vir_bytes off_d,
+               endpoint_t end_s, int seg_s, vir_bytes off_s,
+               size_t size, int flag)
+{
+       struct proc *caller, *src, *dst;
+       vir_bytes lin_src, lin_dst;
+
+       src = endpoint_lookup(end_s);
+       dst = endpoint_lookup(end_d);
+       caller = endpoint_lookup(who_e);
+
+       lin_src = umap_local(src, seg_s, off_s, size);
+       lin_dst = umap_local(dst, seg_d, off_d, size);
+       if(lin_src == 0 || lin_dst == 0) {
+               kprintf("map_invoke_vm: error in umap_local.\n");
+               return EINVAL;
+       }
+
+       /* Make sure the linear addresses are both page aligned. */
+       if(lin_src % CLICK_SIZE != 0
+               || lin_dst % CLICK_SIZE != 0) {
+               kprintf("map_invoke_vm: linear addresses not page aligned.\n");
+               return EINVAL;
+       }
+
+       vmassert(!RTS_ISSET(caller, RTS_VMREQUEST));
+       vmassert(!RTS_ISSET(caller, RTS_VMREQTARGET));
+       vmassert(!RTS_ISSET(dst, RTS_VMREQUEST));
+       vmassert(!RTS_ISSET(dst, RTS_VMREQTARGET));
+       RTS_LOCK_SET(caller, RTS_VMREQUEST);
+       RTS_LOCK_SET(dst, RTS_VMREQTARGET);
+
+       /* Map to the destination. */
+       caller->p_vmrequest.req_type = req_type;
+       caller->p_vmrequest.target = end_d;             /* destination proc */
+       caller->p_vmrequest.params.map.vir_d = lin_dst; /* destination addr */
+       caller->p_vmrequest.params.map.ep_s = end_s;    /* source process */
+       caller->p_vmrequest.params.map.vir_s = lin_src; /* source address */
+       caller->p_vmrequest.params.map.length = size;
+       caller->p_vmrequest.params.map.writeflag = flag;
+
+       caller->p_vmrequest.type = VMSTYPE_MAP;
+
+       /* Connect caller on vmrequest wait queue. */
+       if(!(caller->p_vmrequest.nextrequestor = vmrequest))
+               lock_notify(SYSTEM, VM_PROC_NR);
+       vmrequest = caller;
+
+       return OK;
+}
+
+/*===========================================================================*
+ *                             do_safemap                                   *
+ *===========================================================================*/
+PUBLIC int do_safemap(m_ptr)
+register message *m_ptr;
+{
+       endpoint_t grantor      = m_ptr->SMAP_EP;
+       cp_grant_id_t gid       = m_ptr->SMAP_GID;
+       vir_bytes offset        = m_ptr->SMAP_OFFSET;
+       int seg                 = (int)m_ptr->SMAP_SEG;
+       vir_bytes address       = m_ptr->SMAP_ADDRESS;
+       vir_bytes bytes         = m_ptr->SMAP_BYTES;
+       int flag                = m_ptr->SMAP_FLAG;
+
+       vir_bytes offset_result;
+       endpoint_t new_grantor;
+       int r;
+       int access = CPF_MAP | CPF_READ;
+
+       /* Check the grant. We currently support safemap with both direct and
+        * indirect grants, as verify_grant() stores the original grantor
+        * transparently in new_grantor below. However, we maintain the original
+        * semantics associated to indirect grants only here at safemap time.
+        * After the mapping has been set up, if a process part of the chain
+        * of trust crashes or exits without revoking the mapping, the mapping
+        * can no longer be manually or automatically revoked for any of the
+        * processes lower in the chain. This solution reduces complexity but
+        * could be improved if we make the assumption that only one process in
+        * the chain of trust can effectively map the original memory region.
+        */
+       if(flag != 0)
+               access |= CPF_WRITE;
+       r = verify_grant(grantor, who_e, gid, bytes, access,
+               offset, &offset_result, &new_grantor);
+       if(r != OK) {
+               kprintf("verify_grant for gid %d from %d to %d failed: %d\n",
+                       gid, grantor, who_e, r);
+               return r;
+       }
+
+       /* Add map info. */
+       r = add_info(new_grantor, who_e, gid, offset, offset_result, seg,
+               address, bytes);
+       if(r != OK)
+               return r;
+
+       /* Invoke VM. */
+       return map_invoke_vm(VMPTYPE_SMAP,
+               who_e, seg, address, new_grantor, D, offset_result, bytes,flag);
+}
+
+/*===========================================================================*
+ *                             safeunmap                                    *
+ *===========================================================================*/
+PRIVATE int safeunmap(struct map_info_s *p)
+{
+       vir_bytes offset_result;
+       endpoint_t new_grantor;
+       int r;
+
+       r = verify_grant(p->grantor, p->grantee, p->gid, p->bytes, CPF_MAP,
+               p->offset, &offset_result, &new_grantor);
+       if(r != OK) {
+           kprintf("safeunmap: error in verify_grant.\n");
+               return r;
+       }
+
+       r = map_invoke_vm(VMPTYPE_SUNMAP,
+               p->grantee, p->seg, p->address,
+               new_grantor, D, offset_result,
+               p->bytes, 0);
+       clear_info(p);
+       if(r != OK) {
+               kprintf("safeunmap: error in map_invoke_vm.\n");
+               return r;
+       }
+       return OK;
+}
+
+/*===========================================================================*
+ *                             do_saferevmap                                *
+ *===========================================================================*/
+PUBLIC int do_saferevmap(m_ptr)
+register message *m_ptr;
+{
+       struct map_info_s *p;
+       int flag = m_ptr->SMAP_FLAG;
+       int arg = m_ptr->SMAP_GID; /* gid or address_Dseg */
+       int r;
+
+       while((p = get_revoke_info(who_e, flag, arg)) != NULL) {
+               if((r = safeunmap(p)) != OK)
+                       return r;
+       }
+       return OK;
+}
+
+/*===========================================================================*
+ *                             do_safeunmap                                 *
+ *===========================================================================*/
+PUBLIC int do_safeunmap(m_ptr)
+register message *m_ptr;
+{
+       vir_bytes address = m_ptr->SMAP_ADDRESS;
+       int seg = (int)m_ptr->SMAP_SEG;
+       struct map_info_s *p;
+       int r;
+
+       while((p = get_unmap_info(who_e, seg, address)) != NULL) {
+               if((r = safeunmap(p)) != OK)
+                       return r;
+       }
+       return OK;
+}
+
index 9ab15789519e78f5113714784d3b9f2dc5e86b0a..afc2729a84ca462892096d6fa0b8a9c47f3375a5 100644 (file)
@@ -65,21 +65,51 @@ register message *m_ptr;    /* pointer to request message */
 #endif
 
                /* Reply with request fields. */
-               m_ptr->SVMCTL_MRG_ADDR = (char *) rp->p_vmrequest.start;
-               m_ptr->SVMCTL_MRG_LEN = rp->p_vmrequest.length;
-               m_ptr->SVMCTL_MRG_WRITE = rp->p_vmrequest.writeflag;
-               m_ptr->SVMCTL_MRG_EP = rp->p_vmrequest.who;
-               m_ptr->SVMCTL_MRG_REQUESTOR = (void *) rp->p_endpoint;
+               switch(rp->p_vmrequest.req_type) {
+               case VMPTYPE_CHECK:
+                       m_ptr->SVMCTL_MRG_TARGET        =
+                               rp->p_vmrequest.target;
+                       m_ptr->SVMCTL_MRG_ADDR          =
+                               rp->p_vmrequest.params.check.start;
+                       m_ptr->SVMCTL_MRG_LENGTH        =
+                               rp->p_vmrequest.params.check.length;
+                       m_ptr->SVMCTL_MRG_FLAG          =
+                               rp->p_vmrequest.params.check.writeflag;
+                       m_ptr->SVMCTL_MRG_REQUESTOR     =
+                               (void *) rp->p_endpoint;
+                       break;
+               case VMPTYPE_COWMAP:
+               case VMPTYPE_SMAP:
+               case VMPTYPE_SUNMAP:
+                       m_ptr->SVMCTL_MRG_TARGET        =
+                               rp->p_vmrequest.target;
+                       m_ptr->SVMCTL_MRG_ADDR          =
+                               rp->p_vmrequest.params.map.vir_d;
+                       m_ptr->SVMCTL_MRG_EP2           =
+                               rp->p_vmrequest.params.map.ep_s;
+                       m_ptr->SVMCTL_MRG_ADDR2         =
+                               rp->p_vmrequest.params.map.vir_s;
+                       m_ptr->SVMCTL_MRG_LENGTH        =
+                               rp->p_vmrequest.params.map.length;
+                       m_ptr->SVMCTL_MRG_FLAG          =
+                               rp->p_vmrequest.params.map.writeflag;
+                       m_ptr->SVMCTL_MRG_REQUESTOR     =
+                               (void *) rp->p_endpoint;
+                       break;
+               default:
+                       minix_panic("VMREQUEST wrong type", NO_NUM);
+               }
+
                rp->p_vmrequest.vmresult = VMSUSPEND;
 
                /* Remove from request chain. */
                vmrequest = vmrequest->p_vmrequest.nextrequestor;
 
-               return OK;
+               return rp->p_vmrequest.req_type;
        case VMCTL_MEMREQ_REPLY:
                vmassert(RTS_ISSET(p, RTS_VMREQUEST));
                vmassert(p->p_vmrequest.vmresult == VMSUSPEND);
-               okendpt(p->p_vmrequest.who, &proc_nr);
+               okendpt(p->p_vmrequest.target, &proc_nr);
                target = proc_addr(proc_nr);
                p->p_vmrequest.vmresult = m_ptr->SVMCTL_VALUE;
                vmassert(p->p_vmrequest.vmresult != VMSUSPEND);
@@ -94,21 +124,28 @@ register message *m_ptr;   /* pointer to request message */
                        p->p_vmrequest.start + p->p_vmrequest.length,
                        p->p_vmrequest.writeflag, p->p_vmrequest.stacktrace);
                printf("type %d\n", p->p_vmrequest.type);
+#endif
 
                vmassert(RTS_ISSET(target, RTS_VMREQTARGET));
                RTS_LOCK_UNSET(target, RTS_VMREQTARGET);
-#endif
 
-               if(p->p_vmrequest.type == VMSTYPE_KERNELCALL) {
+               switch(p->p_vmrequest.type) {
+               case VMSTYPE_KERNELCALL:
                        /* Put on restart chain. */
                        p->p_vmrequest.nextrestart = vmrestart;
                        vmrestart = p;
-               } else if(p->p_vmrequest.type == VMSTYPE_DELIVERMSG) {
+                       break;
+               case VMSTYPE_DELIVERMSG:
                        vmassert(p->p_misc_flags & MF_DELIVERMSG);
                        vmassert(p == target);
                        vmassert(RTS_ISSET(p, RTS_VMREQUEST));
                        RTS_LOCK_UNSET(p, RTS_VMREQUEST);
-               } else {
+                       break;
+               case VMSTYPE_MAP:
+                       vmassert(RTS_ISSET(p, RTS_VMREQUEST));
+                       RTS_LOCK_UNSET(p, RTS_VMREQUEST);
+                       break;
+               default:
 #if DEBUG_VMASSERT
                        printf("suspended with stack: %s\n",
                                p->p_vmrequest.stacktrace);
index cc8b0a0722fa4b2bc6c52ef689037149bbf3790c..9d36f2b770340e09f6dd2c56acec3b3791fc82c8 100644 (file)
@@ -6,10 +6,10 @@ all-gnu:
 
 makefiles: Makefile
 Makedepend-ack Makedepend-gnu: 
-       sh generate.sh . obj-ack/ obj-gnu
+       sh ./generate.sh . obj-ack obj-gnu
 
 Makefile: Makefile.in Makedepend-ack Makedepend-gnu
-       sh generate.sh . obj-ack/ obj-gnu
+       sh ./generate.sh . obj-ack obj-gnu
        @echo
        @echo *Attention*
        @echo Makefile is regenerated... rerun command to see changes
@@ -17,47 +17,47 @@ Makefile: Makefile.in Makedepend-ack Makedepend-gnu
        @echo
 
 all-ack: makefiles
-       mkdir -p obj-ack//./ansi
+       mkdir -p obj-ack/./ansi
        cd ansi && $(MAKE) $@
-       mkdir -p obj-ack//./curses
+       mkdir -p obj-ack/./curses
        cd curses && $(MAKE) $@
-       mkdir -p obj-ack//./dummy
+       mkdir -p obj-ack/./dummy
        cd dummy && $(MAKE) $@
-       mkdir -p obj-ack//./editline
+       mkdir -p obj-ack/./editline
        cd editline && $(MAKE) $@
-       mkdir -p obj-ack//./end
+       mkdir -p obj-ack/./end
        cd end && $(MAKE) $@
-       mkdir -p obj-ack//./ip
+       mkdir -p obj-ack/./ip
        cd ip && $(MAKE) $@
-       mkdir -p obj-ack//./math
+       mkdir -p obj-ack/./math
        cd math && $(MAKE) $@
-       mkdir -p obj-ack//./other
+       mkdir -p obj-ack/./other
        cd other && $(MAKE) $@
-       mkdir -p obj-ack//./posix
+       mkdir -p obj-ack/./posix
        cd posix && $(MAKE) $@
-       mkdir -p obj-ack//./regex
+       mkdir -p obj-ack/./regex
        cd regex && $(MAKE) $@
-       mkdir -p obj-ack//./stdio
+       mkdir -p obj-ack/./stdio
        cd stdio && $(MAKE) $@
-       mkdir -p obj-ack//./stdtime
+       mkdir -p obj-ack/./stdtime
        cd stdtime && $(MAKE) $@
-       mkdir -p obj-ack//./syscall
+       mkdir -p obj-ack/./syscall
        cd syscall && $(MAKE) $@
-       mkdir -p obj-ack//./syslib
+       mkdir -p obj-ack/./syslib
        cd syslib && $(MAKE) $@
-       mkdir -p obj-ack//./util
+       mkdir -p obj-ack/./util
        cd util && $(MAKE) $@
-       mkdir -p obj-ack//./sysutil
+       mkdir -p obj-ack/./sysutil
        cd sysutil && $(MAKE) $@
-       mkdir -p obj-ack//./sysvipc
+       mkdir -p obj-ack/./sysvipc
        cd sysvipc && $(MAKE) $@
-       mkdir -p obj-ack//./timers
+       mkdir -p obj-ack/./timers
        cd timers && $(MAKE) $@
-       mkdir -p obj-ack//./i386
+       mkdir -p obj-ack/./i386
        cd i386 && $(MAKE) $@
-       mkdir -p obj-ack//./ack
+       mkdir -p obj-ack/./ack
        cd ack && $(MAKE) $@
-       mkdir -p obj-ack//./gnu
+       mkdir -p obj-ack/./gnu
        cd gnu && $(MAKE) $@
 
 all-gnu: makefiles
@@ -150,56 +150,56 @@ makefiles: ack/Makefile
 makefiles: gnu/Makefile
 
 ansi/Makefile: ansi/Makefile.in
-       cd ansi && sh ../generate.sh ./ansi ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd ansi && sh .././generate.sh ./ansi ../obj-ack ../obj-gnu && $(MAKE) makefiles
 curses/Makefile: curses/Makefile.in
-       cd curses && sh ../generate.sh ./curses ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd curses && sh .././generate.sh ./curses ../obj-ack ../obj-gnu && $(MAKE) makefiles
 dummy/Makefile: dummy/Makefile.in
-       cd dummy && sh ../generate.sh ./dummy ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd dummy && sh .././generate.sh ./dummy ../obj-ack ../obj-gnu && $(MAKE) makefiles
 editline/Makefile: editline/Makefile.in
-       cd editline && sh ../generate.sh ./editline ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd editline && sh .././generate.sh ./editline ../obj-ack ../obj-gnu && $(MAKE) makefiles
 end/Makefile: end/Makefile.in
-       cd end && sh ../generate.sh ./end ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd end && sh .././generate.sh ./end ../obj-ack ../obj-gnu && $(MAKE) makefiles
 ip/Makefile: ip/Makefile.in
-       cd ip && sh ../generate.sh ./ip ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd ip && sh .././generate.sh ./ip ../obj-ack ../obj-gnu && $(MAKE) makefiles
 math/Makefile: math/Makefile.in
-       cd math && sh ../generate.sh ./math ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd math && sh .././generate.sh ./math ../obj-ack ../obj-gnu && $(MAKE) makefiles
 other/Makefile: other/Makefile.in
-       cd other && sh ../generate.sh ./other ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd other && sh .././generate.sh ./other ../obj-ack ../obj-gnu && $(MAKE) makefiles
 posix/Makefile: posix/Makefile.in
-       cd posix && sh ../generate.sh ./posix ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd posix && sh .././generate.sh ./posix ../obj-ack ../obj-gnu && $(MAKE) makefiles
 regex/Makefile: regex/Makefile.in
-       cd regex && sh ../generate.sh ./regex ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd regex && sh .././generate.sh ./regex ../obj-ack ../obj-gnu && $(MAKE) makefiles
 stdio/Makefile: stdio/Makefile.in
-       cd stdio && sh ../generate.sh ./stdio ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd stdio && sh .././generate.sh ./stdio ../obj-ack ../obj-gnu && $(MAKE) makefiles
 stdtime/Makefile: stdtime/Makefile.in
-       cd stdtime && sh ../generate.sh ./stdtime ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd stdtime && sh .././generate.sh ./stdtime ../obj-ack ../obj-gnu && $(MAKE) makefiles
 syscall/Makefile: syscall/Makefile.in
-       cd syscall && sh ../generate.sh ./syscall ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd syscall && sh .././generate.sh ./syscall ../obj-ack ../obj-gnu && $(MAKE) makefiles
 syslib/Makefile: syslib/Makefile.in
-       cd syslib && sh ../generate.sh ./syslib ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd syslib && sh .././generate.sh ./syslib ../obj-ack ../obj-gnu && $(MAKE) makefiles
 util/Makefile: util/Makefile.in
-       cd util && sh ../generate.sh ./util ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd util && sh .././generate.sh ./util ../obj-ack ../obj-gnu && $(MAKE) makefiles
 sysutil/Makefile: sysutil/Makefile.in
-       cd sysutil && sh ../generate.sh ./sysutil ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd sysutil && sh .././generate.sh ./sysutil ../obj-ack ../obj-gnu && $(MAKE) makefiles
 sysvipc/Makefile: sysvipc/Makefile.in
-       cd sysvipc && sh ../generate.sh ./sysvipc ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd sysvipc && sh .././generate.sh ./sysvipc ../obj-ack ../obj-gnu && $(MAKE) makefiles
 timers/Makefile: timers/Makefile.in
-       cd timers && sh ../generate.sh ./timers ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd timers && sh .././generate.sh ./timers ../obj-ack ../obj-gnu && $(MAKE) makefiles
 i386/Makefile: i386/Makefile.in
-       cd i386 && sh ../generate.sh ./i386 ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd i386 && sh .././generate.sh ./i386 ../obj-ack ../obj-gnu && $(MAKE) makefiles
 ack/Makefile: ack/Makefile.in
-       cd ack && sh ../generate.sh ./ack ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd ack && sh .././generate.sh ./ack ../obj-ack ../obj-gnu && $(MAKE) makefiles
 gnu/Makefile: gnu/Makefile.in
-       cd gnu && sh ../generate.sh ./gnu ../obj-ack/ ../obj-gnu && $(MAKE) makefiles
+       cd gnu && sh .././generate.sh ./gnu ../obj-ack ../obj-gnu && $(MAKE) makefiles
 
 clean::
-       rm -f obj-ack//./*
+       rm -f obj-ack/./*
        rm -f obj-gnu/./*
 
 install: install-ack
 
 install-ack: all-ack
-       cp obj-ack//*.[ao] /usr/lib/i386
+       cp obj-ack/*.[ao] /usr/lib/i386
 
 install-gnu: all-gnu
        cp obj-gnu/*.[ao] /usr/gnu/lib
index da20eba465ffdd3942d63867033c0f92cf4caaf0..9549cc31b578ba9c39296a7bf7979e230cbfd758 100644 (file)
@@ -52,6 +52,7 @@ libsys_FILES=" \
        sys_readbios.c \
        sys_runctl.c \
        sys_safecopy.c \
+       sys_safemap.c \
        sys_sysctl.c \
        sys_vsafecopy.c \
        sys_profbuf.c \
index d647c41d508ec5f8f1e8fa1b239fe7bb0f5618f8..ec82595cab437e180c8b8cfd14078d9da35ffa23 100644 (file)
 
 #include "syslib.h"
 
-#define GRANTBAD -1001
+static message m;
 
-int
-ds_subscribe(ds_name_regexp, type, flags)
-char *ds_name_regexp;
-int type;
-int flags;
+PRIVATE int do_invoke_ds(int type, const char *ds_name)
 {
-       int r;
-       message m;
-       cp_grant_id_t g;
-       size_t len;
-
-       len = strlen(ds_name_regexp)+1;
-       g = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_name_regexp, len, CPF_READ);
-
-       if(!GRANT_VALID(g)) 
-               return GRANTBAD;
-
-       flags &= DS_INITIAL;
+       cp_grant_id_t g_key;
+       size_t len_key;
+       int access, r;
+
+       if(type == DS_CHECK || type == DS_RETRIEVE_LABEL) {
+               len_key = DS_MAX_KEYLEN;
+               access = CPF_WRITE;
+       } else {
+               len_key = strlen(ds_name)+1;
+               access = CPF_READ;
+       }
 
-       m.DS_KEY_GRANT = (char *) g;
-       m.DS_KEY_LEN = len;
-       m.DS_FLAGS = flags | (type & DS_TYPE_MASK);
+       /* Grant for key. */
+       g_key = cpf_grant_direct(DS_PROC_NR, (vir_bytes) ds_name,
+               len_key, access);
+       if(!GRANT_VALID(g_key)) 
+               return errno;
 
-       r = _taskcall(DS_PROC_NR, DS_SUBSCRIBE, &m);
+       m.DS_KEY_GRANT = g_key;
+       m.DS_KEY_LEN = len_key;
 
-       cpf_revoke(g);
+       r = _taskcall(DS_PROC_NR, type, &m);
 
+       cpf_revoke(g_key);
        return r;
 }
 
-int ds_publish_u32(ds_name, value)
-char *ds_name;
-u32_t value;
+int ds_publish_label(const char *ds_name, u32_t value, int flags)
 {
-       int r;
-       message m;
-       cp_grant_id_t g;
-       size_t len;
-
-       len = strlen(ds_name)+1;
-       g = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_name, len, CPF_READ);
-
-       if(!GRANT_VALID(g)) 
-               return GRANTBAD;
-
-       m.DS_KEY_GRANT = (char *) g;
-       m.DS_KEY_LEN = len;
-       m.DS_FLAGS = DS_TYPE_U32;
        m.DS_VAL = value;
-       m.DS_VAL_LEN = sizeof(value);
-
-       r = _taskcall(DS_PROC_NR, DS_PUBLISH, &m);
+       m.DS_FLAGS = DSF_TYPE_LABEL | flags;
+       return do_invoke_ds(DS_PUBLISH, ds_name);
+}
 
-       cpf_revoke(g);
+int ds_publish_u32(const char *ds_name, u32_t value, int flags)
+{
+       m.DS_VAL = value;
+       m.DS_FLAGS = DSF_TYPE_U32 | flags;
+       return do_invoke_ds(DS_PUBLISH, ds_name);
+}
 
-       return r;
+int ds_publish_str(const char *ds_name, char *value, int flags)
+{
+       if(strlen(value) >= DS_MAX_STRLEN)
+               return EINVAL;
+       strcpy((char *)(&m.DS_STRING), value);
+       m.DS_FLAGS = DSF_TYPE_STR | flags;
+       return do_invoke_ds(DS_PUBLISH, ds_name);
 }
 
-int ds_publish_str(ds_name, value)
-char *ds_name;
-char *value;
+int ds_publish_mem(const char *ds_name, void *vaddr, size_t length, int flags)
 {
+       cp_grant_id_t gid;
        int r;
-       message m;
-       cp_grant_id_t g_key, g_str;
-       size_t len_key, len_str;
 
-       /* Grant for key. */
-       len_key = strlen(ds_name)+1;
-       g_key = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_name, len_key, CPF_READ);
-       if(!GRANT_VALID(g_key)) 
-               return GRANTBAD;
+       /* Grant for memory range. */
+       gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length, CPF_READ);
+       if(!GRANT_VALID(gid))
+               return errno;
 
-       /* Grant for value. */
-       len_str = strlen(value)+1;
-       g_str = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) value, len_str, CPF_READ);
+       m.DS_VAL = gid;
+       m.DS_VAL_LEN = length;
+       m.DS_FLAGS = DSF_TYPE_MEM | flags;
 
-       if(!GRANT_VALID(g_str))  {
-               cpf_revoke(g_key);
-               return GRANTBAD;
-       }
-
-       m.DS_KEY_GRANT = (char *) g_key;
-       m.DS_KEY_LEN = len_key;
-       m.DS_FLAGS = DS_TYPE_STR;
-       m.DS_VAL = g_str;
-       m.DS_VAL_LEN = len_str;
-
-       r = _taskcall(DS_PROC_NR, DS_PUBLISH, &m);
-
-       cpf_revoke(g_key);
-       cpf_revoke(g_str);
+       r = do_invoke_ds(DS_PUBLISH, ds_name);
+       cpf_revoke(gid);
 
        return r;
 }
 
-int ds_retrieve_u32(ds_name, value)
-char *ds_name;
-u32_t *value;
+int ds_publish_map(const char *ds_name, void *vaddr, size_t length, int flags)
 {
+       cp_grant_id_t gid;
        int r;
-       message m;
-       cp_grant_id_t g_key;
-       size_t len_key;
 
-       /* Grant for key. */
-       len_key = strlen(ds_name)+1;
-       g_key = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_name, len_key, CPF_READ);
-       if(!GRANT_VALID(g_key)) 
-               return GRANTBAD;
-
-       /* Do request. */
-       m.DS_KEY_GRANT = (char *) g_key;
-       m.DS_KEY_LEN = len_key;
-       m.DS_FLAGS = DS_TYPE_U32;
+       if(((vir_bytes)vaddr % CLICK_SIZE != 0) || (length % CLICK_SIZE != 0))
+               return EINVAL;
 
-       r = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m);
+       /* Grant for mapped memory range. */
+       gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, length,
+                       CPF_READ | CPF_MAP);
+       if(!GRANT_VALID(gid))
+               return errno;
 
-       cpf_revoke(g_key);
+       m.DS_VAL = gid;
+       m.DS_VAL_LEN = length;
+       m.DS_FLAGS = DSF_TYPE_MAP | flags;
 
-       if(r == OK) {
-               /* Assign u32 value. */
-               *value = m.DS_VAL;
-       }
+       r = do_invoke_ds(DS_PUBLISH, ds_name);
+       cpf_revoke(gid);
 
        return r;
 }
 
-int ds_retrieve_str(ds_name, value, len_str)
-char *ds_name;
-char *value;
-size_t len_str;
+int ds_snapshot_map(const char *ds_name, int *nr_snapshot)
 {
        int r;
-       message m;
-       cp_grant_id_t g_key, g_str;
-       size_t len_key;
+       r = do_invoke_ds(DS_SNAPSHOT, ds_name);
+       *nr_snapshot = m.DS_NR_SNAPSHOT;
+       return r;
+}
 
-       /* Grant for key. */
-       len_key = strlen(ds_name)+1;
-       g_key = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_name, len_key, CPF_READ);
-       if(!GRANT_VALID(g_key)) 
-               return GRANTBAD;
+int ds_retrieve_label_name(char *ds_name, u32_t num)
+{
+       int r;
+       m.DS_VAL = num;
+       r = do_invoke_ds(DS_RETRIEVE_LABEL, ds_name);
+       return r;
+}
 
-       /* Grant for value. */
-       g_str = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) value, len_str, CPF_WRITE);
+int ds_retrieve_label_num(const char *ds_name, u32_t *value)
+{
+       int r;
+       m.DS_FLAGS = DSF_TYPE_LABEL;
+       r = do_invoke_ds(DS_RETRIEVE, ds_name);
+       *value = m.DS_VAL;
+       return r;
+}
 
-       if(!GRANT_VALID(g_str))  {
-               cpf_revoke(g_key);
-               return GRANTBAD;
-       }
+int ds_retrieve_u32(const char *ds_name, u32_t *value)
+{
+       int r;
+       m.DS_FLAGS = DSF_TYPE_U32;
+       r = do_invoke_ds(DS_RETRIEVE, ds_name);
+       *value = m.DS_VAL;
+       return r;
+}
 
-       /* Do request. */
+int ds_retrieve_str(const char *ds_name, char *value, size_t len_str)
+{
+       int r;
+       m.DS_FLAGS = DSF_TYPE_STR;
+       r = do_invoke_ds(DS_RETRIEVE, ds_name);
+       strncpy(value, (char *)(&m.DS_STRING), DS_MAX_STRLEN);
+       value[DS_MAX_STRLEN - 1] = '\0';
+       return r;
+}
 
-       m.DS_KEY_GRANT = (char *) g_key;
-       m.DS_KEY_LEN = len_key;
-       m.DS_FLAGS = DS_TYPE_STR;
-       m.DS_VAL = g_str;
-       m.DS_VAL_LEN = len_str;
+int ds_retrieve_mem(const char *ds_name, char *vaddr, size_t *length)
+{
+       cp_grant_id_t gid;
+       int r;
 
-       r = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m);
+       /* Grant for memory range. */
+       gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr, *length, CPF_WRITE);
+       if(!GRANT_VALID(gid))
+               return errno;
 
-       cpf_revoke(g_key);
-       cpf_revoke(g_str);
+       m.DS_VAL = gid;
+       m.DS_VAL_LEN = *length;
+       m.DS_FLAGS = DSF_TYPE_MEM;
+       r = do_invoke_ds(DS_RETRIEVE, ds_name);
+       *length = m.DS_VAL_LEN;
+       cpf_revoke(gid);
 
        return r;
 }
 
-int ds_check_str(ds_key, len_key, value, len_str)
-char *ds_key;
-size_t len_key;
-char *value;
-size_t len_str;
+int ds_retrieve_map(const char *ds_name, char *vaddr, size_t *length,
+               int nr_snapshot, int flags)
 {
+       cp_grant_id_t gid;
        int r;
-       message m;
-       cp_grant_id_t g_key, g_str;
-
-       if(len_key < 1 || len_str < 1) return -1002;
-
-       /* Grant for key. */
-       g_key = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_key, len_key, CPF_WRITE);
-       if(!GRANT_VALID(g_key)) 
-               return GRANTBAD;
-
-       /* Grant for value. */
-       g_str = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) value, len_str, CPF_WRITE);
 
-       if(!GRANT_VALID(g_str))  {
-               cpf_revoke(g_key);
-               return GRANTBAD;
+       /* Map a mapped memory range. */
+       if(flags & DSMF_MAP_MAPPED) {
+               /* Request DS to grant. */
+               m.DS_FLAGS = DSF_TYPE_MAP | DSMF_MAP_MAPPED;
+               r = do_invoke_ds(DS_RETRIEVE, ds_name);
+               if(r != OK)
+                       return r;
+
+               /* Do the safemap. */
+               if(*length > m.DS_VAL_LEN)
+                       *length = m.DS_VAL_LEN;
+               *length = (size_t) CLICK_FLOOR(*length);
+               r = sys_safemap(DS_PROC_NR, m.DS_VAL, 0,
+                               (vir_bytes)vaddr, *length, D, 0);
+
+       /* Copy mapped memory range or a snapshot. */
+       } else if(flags & (DSMF_COPY_MAPPED|DSMF_COPY_SNAPSHOT)) {
+               /* Grant for memory range first. */
+               gid = cpf_grant_direct(DS_PROC_NR, (vir_bytes)vaddr,
+                               *length, CPF_WRITE);
+               if(!GRANT_VALID(gid))
+                       return errno;
+
+               m.DS_VAL = gid;
+               m.DS_VAL_LEN = *length;
+               if(flags & DSMF_COPY_MAPPED) {
+                       m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_MAPPED;
+               }
+               else {
+                       m.DS_NR_SNAPSHOT = nr_snapshot;
+                       m.DS_FLAGS = DSF_TYPE_MAP | DSMF_COPY_SNAPSHOT;
+               }
+               r = do_invoke_ds(DS_RETRIEVE, ds_name);
+               *length = m.DS_VAL_LEN;
+               cpf_revoke(gid);
+       }
+       else {
+               return EINVAL;
        }
-
-       /* Do request. */
-
-       m.DS_KEY_GRANT = (char *) g_key;
-       m.DS_KEY_LEN = len_key;
-       m.DS_FLAGS = DS_TYPE_STR;
-       m.DS_VAL = g_str;
-       m.DS_VAL_LEN = len_str;
-
-       r = _taskcall(DS_PROC_NR, DS_CHECK, &m);
-
-       cpf_revoke(g_key);
-       cpf_revoke(g_str);
-
-       ds_key[len_key-1] = '\0';
-       value[len_str-1] = '\0';
 
        return r;
 }
 
-int ds_check_u32(ds_key, len_key, value)
-char *ds_key;
-size_t len_key;
-u32_t *value;
+int ds_delete_u32(const char *ds_name)
 {
-       int r;
-       message m;
-       cp_grant_id_t g_key;
-
-       if(len_key < 1) return -1;
-
-       /* Grant for key. */
-       g_key = cpf_grant_direct(DS_PROC_NR,
-               (vir_bytes) ds_key, len_key, CPF_WRITE);
-       if(!GRANT_VALID(g_key)) 
-               return GRANTBAD;
+       m.DS_FLAGS = DSF_TYPE_U32;
+       return do_invoke_ds(DS_DELETE, ds_name);
+}
 
-       /* Do request. */
-       m.DS_KEY_GRANT = (char *) g_key;
-       m.DS_KEY_LEN = len_key;
-       m.DS_FLAGS = DS_TYPE_U32;
+int ds_delete_str(const char *ds_name)
+{
+       m.DS_FLAGS = DSF_TYPE_STR;
+       return do_invoke_ds(DS_DELETE, ds_name);
+}
 
-       r = _taskcall(DS_PROC_NR, DS_CHECK, &m);
+int ds_delete_mem(const char *ds_name)
+{
+       m.DS_FLAGS = DSF_TYPE_MEM;
+       return do_invoke_ds(DS_DELETE, ds_name);
+}
 
-       cpf_revoke(g_key);
+int ds_delete_map(const char *ds_name)
+{
+       m.DS_FLAGS = DSF_TYPE_MAP;
+       return do_invoke_ds(DS_DELETE, ds_name);
+}
 
-       ds_key[len_key-1] = '\0';
+int ds_delete_label(const char *ds_name)
+{
+       m.DS_FLAGS = DSF_TYPE_LABEL;
+       return do_invoke_ds(DS_DELETE, ds_name);
+}
 
-       /* Assign u32 value. */
-       *value = m.DS_VAL;
+int ds_subscribe(const char *regexp, int flags)
+{
+       m.DS_FLAGS = flags;
+       return do_invoke_ds(DS_SUBSCRIBE, regexp);
+}
 
+int ds_check(char *ds_key, int *type)
+{
+       int r;
+       r = do_invoke_ds(DS_CHECK, ds_key);
+       *type = m.DS_FLAGS;
        return r;
 }
-
index b50d355f0763466c39ae9f64be20cdcbe2936e0d..9fc5db49450c4f917ff299762b508baf88b0f747 100644 (file)
@@ -21,7 +21,7 @@ endpoint_t proc_ep;
 
        if (pci_procnr == ANY)
        {
-               r= ds_retrieve_u32("pci", &u32);
+               r= ds_retrieve_label_num("pci", &u32);
                if (r != 0)
                {
                        panic("syslib/" __FILE__,
index 11b2fb91395e52aabd0faeb94683ccd7bec9747f..758d88b0ddbe2a7f3cd5c481ca482316eb6690c9 100644 (file)
@@ -22,9 +22,9 @@ char *name;
        size_t len;
        message m;
 
-       r= ds_retrieve_u32("pci", &u32);
+       r= ds_retrieve_label_num("pci", &u32);
        if (r != 0)
-               panic("syslib/" __FILE__, "pci_init1: ds_retrieve_u32 failed for 'pci'", r);
+               panic("syslib/" __FILE__, "pci_init1: ds_retrieve_label_num failed for 'pci'", r);
        pci_procnr= u32;
 
        m.m_type= BUSC_PCI_INIT;
index 8e88853223118f8333d9da771e97af17cd4aa678..12cafbca075c23f695fbd1ab59797bda1bc4588c 100644 (file)
@@ -22,11 +22,11 @@ struct rs_pci *rs_pci;
 
        if (pci_procnr == ANY)
        {
-               r= ds_retrieve_u32("pci", &u32);
+               r= ds_retrieve_label_num("pci", &u32);
                if (r != 0)
                {
                        panic("syslib/" __FILE__,
-                               "pci_set_acl: ds_retrieve_u32 failed for 'pci'",
+                               "pci_set_acl: ds_retrieve_label_num failed for 'pci'",
                                r);
                }
                pci_procnr = u32;
index 3159f6f09e8a684b0c789c2a620dc4ec018c886d..91dae250e2dd38485aa1e35da887874897d79835 100644 (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_MAP)) {       \
                errno = EINVAL;                 \
                return -1;                      \
        }                                       \
        }                                                       \
    }
 
+#define CLICK_ALIGNMENT_CHECK(addr, bytes) {                                 \
+       if(((vir_bytes)(addr) % CLICK_SIZE != 0)                              \
+               || ((vir_bytes)(bytes) % CLICK_SIZE != 0)) {                  \
+               return EINVAL;                                                \
+       }                                                                     \
+   }
+
 #define NR_STATIC_GRANTS 2
 PRIVATE cp_grant_t static_grants[NR_STATIC_GRANTS];
 PRIVATE cp_grant_t *grants = NULL;
@@ -206,8 +213,16 @@ PUBLIC int
 cpf_revoke(cp_grant_id_t g)
 {
 /* Revoke previously granted access, identified by grant id. */
+       int r;
        GID_CHECK_USED(g);
 
+       /* If this grant is for memory mapping, revoke the mapping first. */
+       if(grants[g].cp_flags & CPF_MAP) {
+               r = sys_saferevmap_gid(g);
+               if(r != 0)
+                       return r;
+       }
+
        /* Make grant invalid by setting flags to 0, clearing CPF_USED.
         * This invalidates the grant.
         */
@@ -262,6 +277,12 @@ int access;
        GID_CHECK(gid);
        ACCESS_CHECK(access);
 
+       /* Check click alignment in case of memory mapping grant. */
+       if(access & CPF_MAP) {
+               CLICK_ALIGNMENT_CHECK(addr, bytes);
+       }
+
+       /* Fill in new slot data. */
        grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID;
        grants[gid].cp_u.cp_direct.cp_who_to = who;
        grants[gid].cp_u.cp_direct.cp_start = addr;
@@ -298,6 +319,11 @@ int access;
        GID_CHECK(gid);
        ACCESS_CHECK(access);
 
+       /* Check click alignment in case of memory mapping grant. */
+       if(access & CPF_MAP) {
+               CLICK_ALIGNMENT_CHECK(addr, bytes);
+       }
+
        /* Fill in new slot data. */
        grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access;
        grants[gid].cp_u.cp_magic.cp_who_to = who_to;
diff --git a/lib/syslib/sys_safemap.c b/lib/syslib/sys_safemap.c
new file mode 100644 (file)
index 0000000..8621dfe
--- /dev/null
@@ -0,0 +1,72 @@
+
+#include "syslib.h"
+
+#include <minix/safecopies.h>
+
+/*===========================================================================*
+ *                             sys_safemap                                  *
+ *===========================================================================*/
+PUBLIC int sys_safemap(endpoint_t grantor, cp_grant_id_t grant,
+       vir_bytes grant_offset, vir_bytes my_address,
+       size_t bytes, int my_seg, int writable)
+{
+/* Map a block of data for which the other process has previously
+ * granted permission. 
+ */
+
+       message copy_mess;
+
+       copy_mess.SMAP_EP = grantor;
+       copy_mess.SMAP_GID = grant;
+       copy_mess.SMAP_OFFSET = grant_offset;
+       copy_mess.SMAP_SEG = (void*) my_seg;
+       copy_mess.SMAP_ADDRESS = my_address;
+       copy_mess.SMAP_BYTES = bytes;
+       copy_mess.SMAP_FLAG = writable;
+
+       return(_taskcall(SYSTASK, SYS_SAFEMAP, &copy_mess));
+
+}
+
+/*===========================================================================*
+ *                          sys_saferevmap_gid                              *
+ *===========================================================================*/
+PUBLIC int sys_saferevmap_gid(cp_grant_id_t grant)
+{
+/* Grantor revokes safemap by grant id. */
+       message copy_mess;
+
+       copy_mess.SMAP_FLAG = 1;
+       copy_mess.SMAP_GID = grant;
+
+       return(_taskcall(SYSTASK, SYS_SAFEREVMAP, &copy_mess));
+}
+
+/*===========================================================================*
+ *                         sys_saferevmap_addr                              *
+ *===========================================================================*/
+PUBLIC int sys_saferevmap_addr(vir_bytes addr)
+{
+/* Grantor revokes safemap by address. */
+       message copy_mess;
+
+       copy_mess.SMAP_FLAG = 0;
+       copy_mess.SMAP_GID = addr;
+
+       return(_taskcall(SYSTASK, SYS_SAFEREVMAP, &copy_mess));
+}
+
+/*===========================================================================*
+ *                             sys_safeunmap                                *
+ *===========================================================================*/
+PUBLIC int sys_safeunmap(int my_seg, vir_bytes my_address)
+{
+/* Requestor unmaps safemap. */
+       message copy_mess;
+
+       copy_mess.SMAP_SEG = (void*) my_seg;
+       copy_mess.SMAP_ADDRESS = my_address;
+
+       return(_taskcall(SYSTASK, SYS_SAFEUNMAP, &copy_mess));
+}
+
index 5e93bace5eb386cdd5845f513a913e862b334e11..a6aa159feb0f003c8f6cd0d233a1a0d3ad693573 100644 (file)
@@ -43,7 +43,8 @@ PUBLIC int sys_vmctl_get_cr3_i386(endpoint_t who, u32_t *cr3)
 }
 
 PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem,
-       vir_bytes *len, int *wrflag, endpoint_t *requestor)
+        vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
+        endpoint_t *requestor)
 {
   message m;
   int r;
@@ -51,11 +52,13 @@ PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem,
   m.SVMCTL_WHO = SELF;
   m.SVMCTL_PARAM = VMCTL_MEMREQ_GET;
   r = _taskcall(SYSTASK, SYS_VMCTL, &m);
-  if(r == OK) {
-       *who = m.SVMCTL_MRG_EP;
-       *mem = (vir_bytes) m.SVMCTL_MRG_ADDR;
-       *len = m.SVMCTL_MRG_LEN;
-       *wrflag = m.SVMCTL_MRG_WRITE;
+  if(r >= 0) {
+       *who = m.SVMCTL_MRG_TARGET;
+       *mem = m.SVMCTL_MRG_ADDR;
+       *len = m.SVMCTL_MRG_LENGTH;
+       *wrflag = m.SVMCTL_MRG_FLAG;
+       *who_s = m.SVMCTL_MRG_EP2;
+       *mem_s = m.SVMCTL_MRG_ADDR2;
        *requestor = (endpoint_t) m.SVMCTL_MRG_REQUESTOR;
   }
   return r;
index c5baf71f6264df9d3289da9985157057c615b74f..2680b4ee1fec0e0b3cd81d0442567a1c41842edd 100644 (file)
@@ -18,7 +18,7 @@ libsys_FILES=" \
        env_panic.c \
        env_prefix.c \
        fkey_ctl.c \
-       micro_delay.c \
+       tsc_util.c \
        report.c \
        taskcall.c \
        read_tsc.s \
similarity index 80%
rename from lib/sysutil/micro_delay.c
rename to lib/sysutil/tsc_util.c
index b549510f901c2431e22bfb70dcdddf389ca98aeb..b21bfdf0686b1e001cb8175756d53c534b0d5289 100644 (file)
 #define CALIBRATE                                              \
        if(!calibrated) {                                       \
                int r;                                          \
-               if((r=micro_delay_calibrate()) != OK)           \
-                       panic(__FILE__, "micro_delay: calibrate failed\n", r); \
+               if((r=tsc_calibrate()) != OK)                   \
+                       panic(__FILE__, "calibrate failed\n", r); \
        }
 
 static u32_t calib_tsc, Hz = 0;
 static int calibrated = 0;
 
 int
-micro_delay_calibrate(void)
+tsc_calibrate(void)
 {
        u64_t start, end, diff;
        struct tms tms;
@@ -50,11 +50,11 @@ micro_delay_calibrate(void)
        diff = sub64(end, start);
        if(ex64hi(diff) != 0)
          panic(__FILE__,
-               "micro_delay_calibrate: CALIBRATE_TICKS too high "
+               "tsc_calibrate: CALIBRATE_TICKS too high "
                        "for TSC frequency\n", NO_NUM);
        calib_tsc = ex64lo(diff);
 #if 0
-       printf("micro_delay_calibrate: "
+       printf("tsc_calibrate: "
                "%lu cycles/%d ticks of %d Hz; %lu cycles/s\n",
                        calib_tsc, CALIBRATE_TICKS(Hz), Hz,
                        div64u(mul64u(calib_tsc, Hz), CALIBRATE_TICKS(Hz)));
@@ -94,3 +94,23 @@ micro_delay(u32_t micros)
        return OK;
 }
 
+u32_t tsc_64_to_micros(u64_t tsc)
+{
+       return tsc_to_micros(ex64lo(tsc), ex64hi(tsc));
+}
+
+u32_t tsc_to_micros(u32_t low, u32_t high)
+{
+       u32_t micros;
+
+       if(high) {
+               return 0;
+       }
+       CALIBRATE;
+
+       micros = (div64u(mul64u(low, MICROHZ * CALIBRATE_TICKS(Hz)),
+               calib_tsc)/Hz);
+
+       return micros;
+}
+
index 9aef23a354dfdfdbdae451417332045da4eca925..c2fae762105c8f5eceb13964aeaf919579897c50 100644 (file)
@@ -7,12 +7,14 @@
 #include <sys/types.h>
 #include <limits.h>
 #include <errno.h>
+#include <regex.h>
 
 #include <minix/callnr.h>
 #include <minix/config.h>
 #include <minix/type.h>
 #include <minix/const.h>
 #include <minix/com.h>
+#include <minix/ds.h>
 #include <minix/syslib.h>
 #include <minix/sysutil.h>
 #include <minix/keymap.h>
@@ -27,5 +29,4 @@
 
 #include "proto.h"
 #include "glo.h"
-#include "store.h"
 
index 655e1f7c2b1541dd1a8e7daca610fc298a028466..9ba8c57f9854e96d8db66c57f0af620e46a6f124 100644 (file)
@@ -71,12 +71,21 @@ PUBLIC int main(int argc, char **argv)
       case DS_RETRIEVE:
          result = do_retrieve(&m);
          break;
+      case DS_RETRIEVE_LABEL:
+         result = do_retrieve_label(&m);
+         break;
+      case DS_DELETE:
+         result = do_delete(&m);
+         break;
       case DS_SUBSCRIBE:
          result = do_subscribe(&m);
          break;
       case DS_CHECK:
          result = do_check(&m);
          break;
+      case DS_SNAPSHOT:
+         result = do_snapshot(&m);
+         break;
       case GETSYSINFO:
          result = do_getsysinfo(&m);
          break;
index 6844e976f1a076080e910754b9f8d3d5bd25feb8..f15edaafe4defe9ba4678ec24374a36563eb5622 100644 (file)
@@ -6,8 +6,11 @@ _PROTOTYPE(int main, (int argc, char **argv));
 /* store.c */
 _PROTOTYPE(int do_publish, (message *m_ptr));
 _PROTOTYPE(int do_retrieve, (message *m_ptr));
+_PROTOTYPE(int do_retrieve_label, (message *m_ptr));
 _PROTOTYPE(int do_subscribe, (message *m_ptr));
 _PROTOTYPE(int do_check, (message *m_ptr));
+_PROTOTYPE(int do_delete, (message *m_ptr));
+_PROTOTYPE(int do_snapshot, (message *m_ptr));
 _PROTOTYPE(int do_getsysinfo, (message *m_ptr));
 _PROTOTYPE(int sef_cb_init_fresh, (int type, sef_init_info_t *info));
 _PROTOTYPE(int map_service, (struct rprocpub *rpub));
index a150e97ab46fdee88f000e5764d2cd5c62e10ebb..0aa253799e9f7048cb501eec74d045ec40f6976d 100644 (file)
-/* Implementation of the Data Store. */
-
 #include "inc.h"
+#include "store.h"
 
 /* Allocate space for the data store. */
 PRIVATE struct data_store ds_store[NR_DS_KEYS];
 PRIVATE struct subscription ds_subs[NR_DS_SUBS];
-PRIVATE int nr_in_use;
 
-PRIVATE _PROTOTYPE(int find_key, (char *key, struct data_store **dsp, int t));
-PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, int auth));
-PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, int auth));
-PRIVATE _PROTOTYPE(void check_subscribers, (struct data_store *dsp));
+/*===========================================================================*
+ *                           alloc_data_slot                                *
+ *===========================================================================*/
+PRIVATE struct data_store *alloc_data_slot(void)
+{
+/* Allocate a new data slot. */
+  int i;
+
+  for (i = 0; i < NR_DS_KEYS; i++) {
+       if (!(ds_store[i].flags & DSF_IN_USE))
+               return &ds_store[i];
+  }
+
+  return NULL;
+}
+
+/*===========================================================================*
+ *                             alloc_sub_slot                               *
+ *===========================================================================*/
+PRIVATE struct subscription *alloc_sub_slot(void)
+{
+/* Allocate a new subscription slot. */
+  int i;
+
+  for (i = 0; i < NR_DS_SUBS; i++) {
+       if (!(ds_subs[i].flags & DSF_IN_USE))
+               return &ds_subs[i];
+  }
+
+  return NULL;
+}
+
+/*===========================================================================*
+ *                             lookup_entry                                 *
+ *===========================================================================*/
+PRIVATE struct data_store *lookup_entry(const char *key_name, int type)
+{
+/* Lookup an existing entry by key and type. */
+  int i;
+
+  for (i = 0; i < NR_DS_KEYS; i++) {
+       if ((ds_store[i].flags & DSF_IN_USE) /* used */
+               && (ds_store[i].flags & type) /* same type*/
+               && !strcmp(ds_store[i].key, key_name)) /* same key*/
+               return &ds_store[i];
+  }
 
+  return NULL;
+}
+
+/*===========================================================================*
+ *                          lookup_label_entry                              *
+ *===========================================================================*/
+PRIVATE struct data_store *lookup_label_entry(unsigned num)
+{
+/* Lookup an existing label entry by num. */
+  int i;
+
+  for (i = 0; i < NR_DS_KEYS; i++) {
+       if ((ds_store[i].flags & DSF_IN_USE)
+               && (ds_store[i].flags & DSF_TYPE_LABEL)
+               && (ds_store[i].u.u32 == num))
+               return &ds_store[i];
+  }
+
+  return NULL;
+}
+
+/*===========================================================================*
+ *                           lookup_sub                                     *
+ *===========================================================================*/
+PRIVATE struct subscription *lookup_sub(const char *owner)
+{
+/* Lookup an existing subscription given its owner. */
+  int i;
+
+  for (i = 0; i < NR_DS_SUBS; i++) {
+       if ((ds_subs[i].flags & DSF_IN_USE) /* used */
+               && !strcmp(ds_subs[i].owner, owner)) /* same key*/
+               return &ds_subs[i];
+  }
+
+  return NULL;
+}
+
+/*===========================================================================*
+ *                             ds_getprocname                               *
+ *===========================================================================*/
+PRIVATE char *ds_getprocname(endpoint_t e)
+{
+/* Get a process name given its endpoint. */
+       struct data_store *dsp;
+
+       static char *first_proc_name = "ds";
+       endpoint_t first_proc_ep = DS_PROC_NR;
+
+       if(e == first_proc_ep)
+               return first_proc_name;
+
+       if((dsp = lookup_label_entry(e)) != NULL)
+               return dsp->key;
+
+       return NULL;
+}
+
+/*===========================================================================*
+ *                             ds_getprocep                                 *
+ *===========================================================================*/
+PRIVATE endpoint_t ds_getprocep(char *s)
+{
+/* Get a process endpoint given its name. */
+       struct data_store *dsp;
+
+       if((dsp = lookup_entry(s, DSF_TYPE_LABEL)) != NULL)
+               return dsp->u.u32;
+       return -1;
+}
+
+/*===========================================================================*
+ *                              check_auth                                  *
+ *===========================================================================*/
+PRIVATE int check_auth(struct data_store *p, endpoint_t ep, int perm)
+{
+/* Check authorization for a given type of permission. */
+       if(!(p->flags & perm))
+               return 1;
+
+       return !strcmp(p->owner, ds_getprocname(ep));
+}
+
+/*===========================================================================*
+ *                             get_key_name                                 *
+ *===========================================================================*/
+PRIVATE int get_key_name(message *m_ptr, char *key_name)
+{
+/* Get key name given an input message. */
+  int r;
+
+  if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
+       printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
+               m_ptr->m_source);
+       return EINVAL;
+  }
+
+  /* Copy name from caller. */
+  r = sys_safecopyfrom(m_ptr->m_source,
+       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
+       (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D);
+  if(r != OK) {
+       printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r);
+       return r;
+  }
+
+  key_name[DS_MAX_KEYLEN-1] = '\0';
+
+  return OK;
+}
+
+/*===========================================================================*
+ *                          check_snapshot_index                            *
+ *===========================================================================*/
+PRIVATE int check_snapshot_index(struct data_store *dsp, int index)
+{
+/* See if the given snapshot index is valid. */
+  int min;
+
+  min = dsp->u.map.sindex < NR_DS_SNAPSHOT
+       ? 0
+       : dsp->u.map.sindex - NR_DS_SNAPSHOT + 1;
+
+  return (index >= min && index <= dsp->u.map.sindex) ? 0 : 1;
+}
+
+/*===========================================================================*
+ *                             check_sub_match                              *
+ *===========================================================================*/
+PRIVATE int check_sub_match(struct subscription *subp,
+               struct data_store *dsp, endpoint_t ep)
+{
+/* Check if an entry matches a subscription. Return 1 in case of match. */
+  return (check_auth(dsp, ep, DSF_PRIV_SUBSCRIBE)
+         && regexec(&subp->regex, dsp->key, 0, NULL, 0) == 0)
+         ? 1 : 0;
+}
+
+/*===========================================================================*
+ *                          update_subscribers                              *
+ *===========================================================================*/
+PRIVATE void update_subscribers(struct data_store *dsp, int set)
+{
+/* If set = 1, set bit in the sub bitmap of any subscription matching the given
+ * entry, otherwise clear it. In both cases, notify the subscriber.
+ */
+       int i;
+       int nr = dsp - ds_store;
+       endpoint_t ep;
+
+       for(i = 0; i < NR_DS_SUBS; i++) {
+               if(!(ds_subs[i].flags & DSF_IN_USE))
+                       continue;
+               if(!(ds_subs[i].flags & dsp->flags & DSF_MASK_TYPE))
+                       continue;
+
+               ep = ds_getprocep(ds_subs[i].owner);
+               if(!check_sub_match(&ds_subs[i], dsp, ep))
+                       continue;
+
+               if(set == 1) {
+                       SET_BIT(ds_subs[i].old_subs, nr);
+               } else {
+                       UNSET_BIT(ds_subs[i].old_subs, nr);
+               }
+               notify(ep);
+       }
+}
 
 /*===========================================================================*
  *                         sef_cb_init_fresh                                *
@@ -24,14 +232,11 @@ PUBLIC int sef_cb_init_fresh(int type, sef_init_info_t *info)
 
        /* Reset data store: data and subscriptions. */
        for(i = 0; i < NR_DS_KEYS; i++) {
-               int b;
-               ds_store[i].ds_flags = 0;
-               for(b = 0; b < BITMAP_CHUNKS(NR_DS_SUBS); b++) {
-                       ds_store[i].ds_old_subs[b] = 0;
-               }
+               ds_store[i].flags = 0;
+       }
+       for(i = 0; i < NR_DS_SUBS; i++) {
+               ds_subs[i].flags = 0;
        }
-       for(i = 0; i < NR_DS_SUBS; i++)
-               ds_subs[i].sub_flags = 0;
 
        /* Map all the services in the boot image. */
        if((r = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
@@ -58,397 +263,498 @@ struct rprocpub *rpub;
 /* Map a new service by registering its label. */
   struct data_store *dsp;
 
-  dsp = &ds_store[nr_in_use];                  /* new slot found */
-  strcpy(dsp->ds_key, rpub->label);
-  dsp->ds_flags = DS_IN_USE | DS_TYPE_U32;     /* initialize slot */
-  nr_in_use++;
+  /* Allocate a new data slot. */
+  if((dsp = alloc_data_slot()) == NULL) {
+       return ENOMEM;
+  }
 
-  dsp->ds_val.ds_val_u32 = (u32_t) rpub->endpoint;     /* store data */
+  /* Set attributes. */
+  strcpy(dsp->key, rpub->label);
+  dsp->u.u32 = (u32_t) rpub->endpoint;
+  strcpy(dsp->owner, ds_getprocname(DS_PROC_NR));
+  dsp->flags = DSF_IN_USE | DSF_TYPE_LABEL;
 
-  /* If anyone has a matching subscription, update them. */
-  check_subscribers(dsp);
+  /* Update subscribers having a matching subscription. */
+  update_subscribers(dsp, 1);
 
   return(OK);
 }
 
-PRIVATE int set_owner(dsp, auth)
-struct data_store *dsp;                                /* data store structure */
-int auth;
-{
-  return(TRUE);
-}
-
-
-PRIVATE int is_authorized(dsp, ap)
-struct data_store *dsp;                                /* data store structure */
-int ap;                                                /* authorization value */
-{
-  /* Authorize the caller. */
-  return(TRUE);
-}
-
-
-PRIVATE int find_key(key_name, dsp, type)
-char *key_name;                                        /* key to look up */
-struct data_store **dsp;                       /* store pointer here */
-int type;                                      /* type info */
-{
-  register int i;
-
-  *dsp = NULL;
-  for (i=0; i<NR_DS_KEYS; i++) {
-      if ((ds_store[i].ds_flags & DS_IN_USE)           /* valid slot? */
-      &&  ((ds_store[i].ds_flags & type) == type)      /* right type? */
-      && !strcmp(ds_store[i].ds_key, key_name)) {      /* matching name? */
-         *dsp = &ds_store[i];
-          return(TRUE);                                /* report success */
-      }
-  }
-  return(FALSE);                               /* report not found */
-}
-
-
-PUBLIC int do_publish(m_ptr)
-message *m_ptr;                                        /* request message */
+/*===========================================================================*
+ *                             do_publish                                   *
+ *===========================================================================*/
+PUBLIC int do_publish(message *m_ptr)
 {
   struct data_store *dsp;
   char key_name[DS_MAX_KEYLEN];
-  int r, type;
+  int flags = m_ptr->DS_FLAGS;
+  size_t length;
+  int nr, r;
 
-  /* Store (key,value)-pair. First see if key already exists. If so, 
-   * check if the caller is allowed to overwrite the value. Otherwise
-   * find a new slot and store the new value. 
-   */
-  if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 2) {
-       printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
-               m_ptr->m_source);
+  /* MAP should not be overwritten. */
+  if((flags & DSF_TYPE_MAP) && (flags & DSF_OVERWRITE))
        return EINVAL;
-  }
-
-  /* Check type info. */
-  type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
-  if(type != DS_TYPE_U32 && type != DS_TYPE_STR) {
-       printf("DS: bogus type code %lx from %d\n", type, m_ptr->m_source);
-       return EINVAL;
-  }
 
-  /* Copy name from caller. */
-  if ((r=sys_safecopyfrom(m_ptr->m_source,
-       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
-       (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
-       printf("DS: publish: copy failed from %d: %d\n", m_ptr->m_source, r);
+  /* Get key name. */
+  if((r = get_key_name(m_ptr, key_name)) != OK)
        return r;
+
+  /* Lookup the entry. */
+  dsp = lookup_entry(key_name, flags & DSF_MASK_TYPE);
+  /* If type is LABEL, also try to lookup the entry by num. */
+  if((flags & DSF_TYPE_LABEL) && (dsp == NULL))
+       dsp = lookup_label_entry(m_ptr->DS_VAL);
+
+  if(dsp == NULL) {
+       /* The entry doesn't exist, allocate a new data slot. */
+       if((dsp = alloc_data_slot()) == NULL)
+               return ENOMEM;
+  } else if (flags & DSF_OVERWRITE) {
+       /* Overwrite. */
+       if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_OVERWRITE))
+               return EPERM;
+  } else {
+       /* Don't overwrite and return error. */
+       return EEXIST;
   }
 
-  /* Make sure name is 0-terminated. */
-  key_name[DS_MAX_KEYLEN-1] = '\0';
+  /* Store! */
+  switch(flags & DSF_MASK_TYPE) {
+  case DSF_TYPE_U32:
+  case DSF_TYPE_LABEL:
+       dsp->u.u32 = m_ptr->DS_VAL;
+       break;
+  case DSF_TYPE_STR:
+       strncpy(dsp->u.string, (char *)(&m_ptr->DS_STRING), DS_MAX_STRLEN);
+       dsp->u.string[DS_MAX_KEYLEN - 1] = '\0';
+       break;
+  case DSF_TYPE_MEM:
+       length = m_ptr->DS_VAL_LEN;
+       /* Allocate a new data buffer if necessary. */
+       if(!(dsp->flags & DSF_IN_USE)) {
+               if((dsp->u.mem.data = malloc(length)) == NULL)
+                       return ENOMEM;
+               dsp->u.mem.reallen = length;
+       } else if(length > dsp->u.mem.reallen) {
+               free(dsp->u.mem.data);
+               if((dsp->u.mem.data = malloc(length)) == NULL)
+                       return ENOMEM;
+               dsp->u.mem.reallen = length;
+       }
 
-  /* See if it already exists. */
-  if (!find_key(key_name, &dsp, type)) {               /* look up key */
-      if (nr_in_use >= NR_DS_KEYS) {
-         return(EAGAIN);                               /* store is full */
-      } else {
-          dsp = &ds_store[nr_in_use];                  /* new slot found */
-         strcpy(dsp->ds_key, key_name);
-         dsp->ds_flags = DS_IN_USE | m_ptr->DS_FLAGS;  /* initialize slot */
-         nr_in_use ++;
-      }
+       /* Copy the memory range. */
+       r = sys_safecopyfrom(m_ptr->m_source, m_ptr->DS_VAL, 0,
+               (vir_bytes) dsp->u.mem.data, length, D);
+       if(r != OK) {
+               printf("DS: publish: memory map/copy failed from %d: %d\n",
+                       m_ptr->m_source, r);
+               free(dsp->u.mem.data);
+               return r;
+       }
+       dsp->u.mem.length = length;
+       break;
+  case DSF_TYPE_MAP:
+       /* Allocate buffer, the address should be aligned by CLICK_SIZE. */
+       length = m_ptr->DS_VAL_LEN;
+       if((dsp->u.map.realpointer = malloc(length + CLICK_SIZE)) == NULL)
+               return ENOMEM;
+       dsp->u.map.data = (void*) CLICK_CEIL(dsp->u.map.realpointer);
+
+       /* Map memory. */
+       r = sys_safemap(m_ptr->m_source, m_ptr->DS_VAL, 0,
+               (vir_bytes) dsp->u.map.data, length, D, 0);
+       if(r != OK) {
+               printf("DS: publish: memory map/copy failed from %d: %d\n",
+                       m_ptr->m_source, r);
+               free(dsp->u.map.realpointer);
+               return r;
+       }
+       dsp->u.map.length = length;
+       dsp->u.map.sindex = -1;
+       break;
+  default:
+       return EINVAL;
   }
 
-  /* At this point we have a data store pointer and know the caller is 
-   * authorize to write to it. Set all fields as requested.
-   */
-  switch(type) {
-       case DS_TYPE_U32:
-         dsp->ds_val.ds_val_u32 = (u32_t) m_ptr->DS_VAL;       /* store data */
-         break;
-       case DS_TYPE_STR:
-         /* store string data: check size, then do copy */
-         if(m_ptr->DS_VAL_LEN < 1 || m_ptr->DS_VAL_LEN > DS_MAX_VALLEN) {
-           printf("DS: publish: bogus len from %d: %d\n",
-             m_ptr->m_source, m_ptr->DS_VAL_LEN);
-           return EINVAL;
-         }
-
-         if((r=sys_safecopyfrom(m_ptr->m_source, m_ptr->DS_VAL, 0,
-                 (vir_bytes) dsp->ds_val.ds_val_str,
-                 m_ptr->DS_VAL_LEN, D)) != OK) {
-                 printf("DS: publish: str copy failed from %d: %d\n",
-                 m_ptr->m_source, r);
-                 return r;
-         }
-         break;
-       default:
-          panic(__FILE__, "Impossible type.", type);
-         break;
-  }
+  /* Set attributes. */
+  strcpy(dsp->key, key_name);
+  strcpy(dsp->owner, ds_getprocname(m_ptr->m_source));
+  dsp->flags = DSF_IN_USE | (flags & DSF_MASK_INTERNAL);
 
-  /* If anyone has a matching subscription, update them. */
-  check_subscribers(dsp);
+  /* Update subscribers having a matching subscription. */
+  update_subscribers(dsp, 1);
 
   return(OK);
 }
 
-
 /*===========================================================================*
  *                             do_retrieve                                  *
  *===========================================================================*/
-PUBLIC int do_retrieve(m_ptr)
-message *m_ptr;                                        /* request message */
+PUBLIC int do_retrieve(message *m_ptr)
 {
   struct data_store *dsp;
   char key_name[DS_MAX_KEYLEN];
-  int r, type;
-  size_t len;
-
-  if (m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN || m_ptr->DS_KEY_LEN < 1) {
-       printf("DS: bogus key length (%d) from %d\n", m_ptr->DS_KEY_LEN,
-               m_ptr->m_source);
-       return EINVAL;
-  }
-
-  /* Copy name from caller. */
-  if ((r=sys_safecopyfrom(m_ptr->m_source,
-       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
-       (vir_bytes) key_name, m_ptr->DS_KEY_LEN, D)) != OK) {
-       printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, r);
+  int flags = m_ptr->DS_FLAGS;
+  int type = flags & DSF_MASK_TYPE;
+  size_t length;
+  void *data;
+  int index, r;
+
+  /* Get key name. */
+  if((r = get_key_name(m_ptr, key_name)) != OK)
        return r;
-  }
 
-  /* Make sure name is 0-terminated. */
-  key_name[DS_MAX_KEYLEN-1] = '\0';
+  /* Lookup the entry. */
+  if((dsp = lookup_entry(key_name, type)) == NULL)
+       return ESRCH;
+  if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_RETRIEVE))
+       return EPERM;
 
+  /* Copy the requested data. */
+  switch(type) {
+  case DSF_TYPE_U32:
+  case DSF_TYPE_LABEL:
+       m_ptr->DS_VAL = dsp->u.u32;
+       break;
+  case DSF_TYPE_STR:
+       strncpy((char *)(&m_ptr->DS_STRING), dsp->u.string, DS_MAX_STRLEN);
+       break;
+  case DSF_TYPE_MEM:
+       length = MIN(m_ptr->DS_VAL_LEN, dsp->u.mem.length);
+       r = sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL, 0,
+               (vir_bytes) dsp->u.mem.data, length, D);
+       if(r != OK) {
+               printf("DS: retrieve: copy failed to %d: %d\n", 
+                       m_ptr->m_source, r);
+               return r;
+       }
+       m_ptr->DS_VAL_LEN = length;
+       break;
+  case DSF_TYPE_MAP:
+       /* The caller requested to map a mapped memory range.
+        * Create a MAP grant for the caller, the caller will do the
+        * safemap itself later.
+        */
+       if(flags & DSMF_MAP_MAPPED) {
+               cp_grant_id_t gid;
+               gid = cpf_grant_direct(m_ptr->m_source,
+                               (vir_bytes)dsp->u.map.data,
+                               dsp->u.map.length,
+                               CPF_READ|CPF_WRITE|CPF_MAP);
+               if(!GRANT_VALID(gid))
+                       return -1;
+               m_ptr->DS_VAL = gid;
+               m_ptr->DS_VAL_LEN = length;
+       }
 
-  /* Retrieve data. Look up the key in the data store. Return an error if it
-   * is not found. If this data is private, only the owner may retrieve it.
-   */ 
-  type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
-  if (find_key(key_name, &dsp, type)) {        /* look up key */
-      /* Data is public or the caller is authorized to retrieve it. */
-      switch(type) {
-       case DS_TYPE_U32:
-               m_ptr->DS_VAL = dsp->ds_val.ds_val_u32;  /* return value */
-               break;
-       case DS_TYPE_STR:
-               len = strlen(dsp->ds_val.ds_val_str) + 1;
-               if(len > m_ptr->DS_VAL_LEN)
-                       len = m_ptr->DS_VAL_LEN;
-               if ((r=sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL,
-                       0, (vir_bytes) dsp->ds_val.ds_val_str,len, D)) != OK) {
+       /* The caller requested a copy of a mapped mem range or a snapshot. */
+       else if(flags & (DSMF_COPY_MAPPED|DSMF_COPY_SNAPSHOT)) {
+               if(flags & DSMF_COPY_MAPPED) {
+                       data = dsp->u.map.data;
+               } else {
+                       index = m_ptr->DS_NR_SNAPSHOT;
+                       if(check_snapshot_index(dsp, index))
+                               return EINVAL;
+                       data = dsp->u.map.snapshots[index % NR_DS_SNAPSHOT];
+               }
+
+               length = MIN(m_ptr->DS_VAL_LEN, dsp->u.map.length);
+               r = sys_safecopyto(m_ptr->m_source, m_ptr->DS_VAL, 0,
+                       (vir_bytes) data, length, D);
+               if(r != OK) {
                        printf("DS: retrieve: copy failed to %d: %d\n", 
                                m_ptr->m_source, r);
                        return r;
                }
-               break;
-       default:
-                panic(__FILE__, "retrieve: impossible type.", type);
-               /* not reached. */
-               break;
-
-      }
-      return(OK);                                      /* report success */
+               m_ptr->DS_VAL_LEN = length;
+       }
+       else {
+               return EINVAL;
+       }
+       break;
+  default:
+       return EINVAL;
   }
-  return(ESRCH);                                       /* key not found */
+
+  return OK;
 }
 
 /*===========================================================================*
- *                             do_check                                     *
+ *                             do_retrieve_label                            *
  *===========================================================================*/
-PUBLIC int do_check(m_ptr)
-message *m_ptr;                                        /* request message */
+PUBLIC int do_retrieve_label(message *m_ptr)
 {
-/* This routine goes through all subscriptions for a client,
- * and checks all data items if it has been flagged (i.e.,
- * created or updated) matching that subscription. Return
- * a message and copy the key and value for every one.
- */
-       int r, s, d, type = m_ptr->DS_FLAGS & DS_TYPE_MASK;
-       if(!type) return EINVAL;
-       for(s = 0; s < NR_DS_SUBS; s++) {
-               int len;
-               if(!(ds_subs[s].sub_flags & DS_IN_USE))
-                       continue;
-               if(m_ptr->m_source != ds_subs[s].sub_owner)
-                       continue;
-               for(d = 0;  d < NR_DS_KEYS; d++) {
-                       
-                       /* No match if this is no value, it's
-                        * not flagged, or the type is wrong.
-                        */
-
-                       if(!(ds_store[d].ds_flags & DS_IN_USE))
-                               continue;
-                       if(!GET_BIT(ds_store[d].ds_old_subs, s))
-                               continue;
-                       if(type != (ds_store[d].ds_flags & DS_TYPE_MASK))
-                               continue;
-
-                       /* We have a match. Unflag it for this
-                        * subscription.
-                        */
-                       UNSET_BIT(ds_store[d].ds_old_subs, s);
-                       len = strlen(ds_store[d].ds_key)+1;
-                       if(len > m_ptr->DS_KEY_LEN) 
-                               len = m_ptr->DS_KEY_LEN;
-
-                       /* Copy the key into client. */
-                       if ((r=sys_safecopyto(m_ptr->m_source,
-                               (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
-                               (vir_bytes) ds_store[d].ds_key,
-                               len, D)) != OK)
-                               return r;
-
-                       /* Now copy the value. */
-                       switch(type) {
-                               case DS_TYPE_STR:
-                                       len = strlen(ds_store[d].
-                                               ds_val.ds_val_str)+1;
-                                       if(len > m_ptr->DS_VAL_LEN)
-                                               len = m_ptr->DS_VAL_LEN;
-                                       if ((r=sys_safecopyto(m_ptr->m_source,
-                                               m_ptr->DS_VAL, 0,
-                                               (vir_bytes) ds_store[d].
-                                                 ds_val.ds_val_str,
-                                               len, D)) != OK)
-                                               return r;
-                                       break;
-                               case DS_TYPE_U32:
-                                       m_ptr->DS_VAL =
-                                               ds_store[d].ds_val.ds_val_u32;
-                                       break;
-                               default:
-                                       panic(__FILE__,
-                                               "Check impossible type.",
-                                               type);
-                       }
-
-                       return OK;
-               }
-       }
+  struct data_store *dsp;
+  int r;
+
+  /* Lookup the label entry. */
+  if((dsp = lookup_label_entry(m_ptr->DS_VAL)) == NULL)
+       return ESRCH;
+
+  /* Copy the key name. */
+  r = sys_safecopyto(m_ptr->m_source,
+       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0,
+       (vir_bytes) dsp->key, strlen(dsp->key) + 1, D);
+  if(r != OK) {
+       printf("DS: copy failed from %d: %d\n", m_ptr->m_source, r);
+       return r;
+  }
 
-       return(ESRCH);                                  /* key not found */
+  return OK;
 }
 
-PUBLIC int do_subscribe(m_ptr)
-message *m_ptr;                                        /* request message */
+/*===========================================================================*
+ *                             do_subscribe                                 *
+ *===========================================================================*/
+PUBLIC int do_subscribe(message *m_ptr)
 {
   char regex[DS_MAX_KEYLEN+3];
-  int s, type, e, d, n = 0;
+  struct subscription *subp;
   char errbuf[80];
+  char *owner;
+  int type_set;
+  int r, e, b;
+
+  /* Find the owner. */
+  owner = ds_getprocname(m_ptr->m_source);
+  if(owner == NULL)
+         return ESRCH;
+
+  /* See if the owner already has an existing subscription. */
+  if((subp = lookup_sub(owner)) == NULL) {
+       /* The subscription doesn't exist, allocate a new one. */
+       if((subp = alloc_sub_slot()) == NULL)
+               return EAGAIN;
+  } else if(!(m_ptr->DS_FLAGS & DSF_OVERWRITE)) {
+       /* The subscription exists but we can't overwrite, return error. */
+       return EEXIST;
+  }
 
-  /* Subscribe to a key of interest.
-   * All updates to the key will cause a notification message
-   * to be sent to the subscribed. On success, directly return a copy of the
-   * data for the given key. 
-   */
-  if(m_ptr->DS_KEY_LEN < 2 || m_ptr->DS_KEY_LEN > DS_MAX_KEYLEN)
-       return EINVAL;
-
-  /* Copy name from caller. Anchor the subscription with "^regexp$" so
-   * substrings don't match. The caller probably will not expect this,
+  /* Copy key name from the caller. Anchor the subscription with "^regexp$" so
+   * substrings don't match. The caller will probably not expect this,
    * and the usual case is for a complete match.
    */
   regex[0] = '^';
-  if ((s=sys_safecopyfrom(m_ptr->m_source,
-       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
-       (vir_bytes) regex + 1, m_ptr->DS_KEY_LEN, D)) != OK) {
-       printf("DS: retrieve: copy failed from %d: %d\n", m_ptr->m_source, s);
-       return s;
-  }
-
+  if((r = get_key_name(m_ptr, regex)) != OK)
+       return r;
   regex[DS_MAX_KEYLEN-1] = '\0';
   strcat(regex, "$");
 
-  /* Find subscription slot. */
-  for(s = 0; s < NR_DS_SUBS; s++)
-       if(!(ds_subs[s].sub_flags & DS_IN_USE))
+  /* Compile regular expression. */
+  if((e=regcomp(&subp->regex, regex, REG_EXTENDED)) != 0) {
+       regerror(e, &subp->regex, errbuf, sizeof(errbuf));
+       printf("DS: subscribe: regerror: %s\n", errbuf);
+       return EINVAL;
+  }
+
+  /* If type_set = 0, then subscribe all types. */
+  type_set = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
+  if(type_set == 0)
+         type_set = DSF_MASK_TYPE;
+
+  subp->flags = DSF_IN_USE | type_set;
+  strcpy(subp->owner, owner);
+  for(b = 0; b < BITMAP_CHUNKS(NR_DS_SUBS); b++)
+       subp->old_subs[b] = 0;
+
+  /* See if caller requested an instant initial list. */
+  if(m_ptr->DS_FLAGS & DSF_INITIAL) {
+       int i, match_found = FALSE;
+       for(i = 0; i < NR_DS_KEYS; i++) {
+               if(!(ds_store[i].flags & DSF_IN_USE))
+                       continue;
+               if(!(ds_store[i].flags & type_set))
+                       continue;
+               if(!check_sub_match(subp, &ds_store[i], m_ptr->m_source))
+                       continue;
+
+               SET_BIT(subp->old_subs, i);
+               match_found = TRUE;
+       }
+
+       /* Notify in case of match. */
+       if(match_found)
+               notify(m_ptr->m_source);
+  }
+
+  return OK;
+}
+
+/*===========================================================================*
+ *                             do_check                                     *
+ *===========================================================================*/
+PUBLIC int do_check(message *m_ptr)
+{
+  struct subscription *subp;
+  char *owner;
+  int r, i;
+
+  /* Find the owner. */
+  owner = ds_getprocname(m_ptr->m_source);
+  if(owner == NULL)
+         return ESRCH;
+
+  /* Lookup the owner's subscription. */
+  if((subp = lookup_sub(owner)) == NULL)
+       return ESRCH;
+
+  /* Look for an updated entry the subscriber is interested in. */
+  for(i = 0; i < NR_DS_KEYS; i++) {
+       if(GET_BIT(subp->old_subs, i))
                break;
+  }
+  if(i == NR_DS_KEYS)
+       return ENOENT;
 
-  if(s >= NR_DS_SUBS) {
-       printf("DS: no space for subscription by %d.\n", m_ptr->m_source);
-       return ENOSPC;
+  /* Copy the key name. */
+  r = sys_safecopyto(m_ptr->m_source,
+       (cp_grant_id_t) m_ptr->DS_KEY_GRANT, 0, 
+       (vir_bytes) ds_store[i].key, strlen(ds_store[i].key), D);
+  if(r != OK) {
+       printf("DS: check: copy failed from %d: %d\n", m_ptr->m_source, r);
+       return r;
   }
 
-  /* Compile regular expression. */
-  if((e=regcomp(&ds_subs[s].sub_regex, regex, REG_EXTENDED)) != 0) {
-       regerror(e, &ds_subs[s].sub_regex, errbuf, sizeof(errbuf));
-       printf("DS: subscribe: regerror: %s\n", errbuf);
+  /* Copy the type. */
+  m_ptr->DS_FLAGS = ds_store[i].flags & DSF_MASK_TYPE;
+
+  /* Mark the entry as no longer updated for the subscriber. */
+  UNSET_BIT(subp->old_subs, i);
+
+  return OK;
+}
+
+/*===========================================================================*
+ *                             do_delete                                    *
+ *===========================================================================*/
+PUBLIC int do_delete(message *m_ptr)
+{
+  struct data_store *dsp;
+  char key_name[DS_MAX_KEYLEN];
+  int type = m_ptr->DS_FLAGS & DSF_MASK_TYPE;
+  int top, i, r;
+
+  /* Get key name. */
+  if((r = get_key_name(m_ptr, key_name)) != OK)
+       return r;
+
+  /* Lookup the entry. */
+  if((dsp = lookup_entry(key_name, type)) == NULL)
+       return ESRCH;
+
+  /* Only the owner can delete. */
+  if(strcmp(dsp->owner, ds_getprocname(m_ptr->m_source)))
+       return EPERM;
+
+  switch(type) {
+  case DSF_TYPE_U32:
+  case DSF_TYPE_STR:
+  case DSF_TYPE_LABEL:
+       break;
+  case DSF_TYPE_MEM:
+       free(dsp->u.mem.data);
+       break;
+  case DSF_TYPE_MAP:
+       /* Unmap the mapped data. */
+       r = sys_safeunmap(D, (vir_bytes)dsp->u.map.data);
+       if(r != OK)
+               return r;
+
+       /* Revoke all the mapped grants. */
+       r = sys_saferevmap_addr((vir_bytes)dsp->u.map.data);
+       if(r != OK)
+               return r;
+
+       /* Free snapshots. */
+       top = MIN(NR_DS_SNAPSHOT - 1, dsp->u.map.sindex);
+       for(i = 0; i <= top; i++) {
+               free(dsp->u.map.snapshots[i]);
+       }
+
+       free(dsp->u.map.realpointer);
+       break;
+  default:
        return EINVAL;
   }
-  type = (m_ptr->DS_FLAGS & DS_TYPE_MASK);
-  ds_subs[s].sub_flags = DS_IN_USE | type;
-  ds_subs[s].sub_owner = m_ptr->m_source;
-
-  /* Caller requested an instant initial list? */
-  if(m_ptr->DS_FLAGS & DS_INITIAL) {
-       for(d = 0; d < NR_DS_KEYS; d++) {
-         if(!(ds_store[d].ds_flags & DS_IN_USE))
-            continue;
-         if(regexec(&ds_subs[s].sub_regex, ds_store[d].ds_key,
-               0, NULL, 0) == 0) {
-               SET_BIT(ds_store[d].ds_old_subs, s);
-               n = 1;
-         }
-      }
-
-      /* Any matches? */
-      if(n) notify(ds_subs[s].sub_owner);
-   }
-
-   return OK;
+
+  /* Update subscribers having a matching subscription. */
+  update_subscribers(dsp, 0);
+
+  /* Clear the entry. */
+  dsp->flags = 0;
+
+  return OK;
 }
 
+/*===========================================================================*
+ *                             do_snapshot                                  *
+ *===========================================================================*/
+PUBLIC int do_snapshot(message *m_ptr)
+{
+  struct data_store *dsp;
+  struct dsi_map *p;
+  char key_name[DS_MAX_KEYLEN];
+  int i, r;
+
+  /* Get key name. */
+  if((r = get_key_name(m_ptr, key_name)) != OK)
+       return r;
+
+  /* Lookup the entry. */
+  if((dsp = lookup_entry(key_name, DSF_TYPE_MAP)) == NULL)
+       return ESRCH;
+
+  if(!check_auth(dsp, m_ptr->m_source, DSF_PRIV_SNAPSHOT))
+       return EPERM;
+
+  /* Find a snapshot slot. */
+  p = &dsp->u.map;
+  p->sindex++;
+  i = p->sindex % DS_MAX_KEYLEN;
+  if(p->sindex < DS_MAX_KEYLEN) {
+       if((p->snapshots[i] = malloc(p->length)) == NULL) {
+               p->sindex--;
+               return ENOMEM;
+       }
+  }
+
+  /* Store the snapshot. */
+  memcpy(p->snapshots[i], p->data, p->length);
+
+  /* Copy the snapshot index. */
+  m_ptr->DS_NR_SNAPSHOT = p->sindex;
+
+  return OK;
+}
 
 /*===========================================================================*
  *                             do_getsysinfo                                *
  *===========================================================================*/
-PUBLIC int do_getsysinfo(m_ptr)
-message *m_ptr;
+PUBLIC int do_getsysinfo(message *m_ptr)
 {
-  vir_bytes src_addr, dst_addr;
-  int dst_proc;
-  size_t len;
+  vir_bytes src_addr;
+  size_t length;
   int s;
 
   switch(m_ptr->m1_i1) {
   case SI_DATA_STORE:
-       src_addr = (vir_bytes) ds_store;
-       len = sizeof(struct data_store) * NR_DS_KEYS;
-       break; 
+       src_addr = (vir_bytes)ds_store;
+       length = sizeof(struct data_store) * NR_DS_KEYS;
+       break;
+  case SI_SUBSCRIPTION:
+       src_addr = (vir_bytes)ds_subs;
+       length = sizeof(struct subscription) * NR_DS_SUBS;
+       break;
   default:
-       return(EINVAL);
+       return EINVAL;
   }
 
-  dst_proc = m_ptr->m_source;
-  dst_addr = (vir_bytes) m_ptr->m1_p1;
-  if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len))) {
+  if (OK != (s=sys_datacopy(SELF, src_addr,
+               m_ptr->m_source, (vir_bytes)m_ptr->m1_p1, length))) {
        printf("DS: copy failed: %d\n", s);
-       return(s);
+       return s;
   }
-  return(OK);
-}
 
-/*===========================================================================*
- *                             check_subscribers                            *
- *===========================================================================*/
-PRIVATE void
-check_subscribers(struct data_store *dsp)
-{
-/* Send subscribers whose subscriptions match this (new
- * or updated) data item a notify(), and flag the subscriptions
- * as updated.
- */
-       int i;
-       for(i = 0; i < NR_DS_SUBS; i++) {
-               if(ds_subs[i].sub_flags & DS_IN_USE) {
-                       if(regexec(&ds_subs[i].sub_regex, dsp->ds_key, 
-                               0, NULL, 0) == 0) {
-                               SET_BIT(dsp->ds_old_subs, i);
-                               notify(ds_subs[i].sub_owner);
-                       } else {
-                               UNSET_BIT(dsp->ds_old_subs, i);
-                       }
-               } 
-       }
+  return OK;
 }
 
index d70d9e59fdfff0dbeafa3c0621c40e7809cf6108..6653318ff6b04236974dea417d90d8a10980e2c2 100644 (file)
@@ -1,33 +1,46 @@
-/* Type definitions for the Data Store Server. */
+#ifndef _DS_STORE_H_
+#define _DS_STORE_H_
 
+/* Type definitions for the Data Store Server. */
 #include <sys/types.h>
 #include <minix/sys_config.h>
 #include <minix/ds.h>
 #include <minix/bitmap.h>
 #include <regex.h>
 
-/* Constants for the Data Store Server. */
-#define NR_DS_KEYS               64    /* reserve space for so many items */
-#define NR_DS_SUBS   (4*_NR_SYS_PROCS) /* .. and so many subscriptions */
-
-/* Types. */
+#define NR_DS_KEYS     64      /* number of entries */
+#define NR_DS_SUBS     (4*_NR_SYS_PROCS)       /* number of subscriptions */
+#define NR_DS_SNAPSHOT 5       /* number of snapshots */
 
+/* Base 'class' for the following 3 structs. */
 struct data_store {
-  int ds_flags;                        /* flags for this store, includes type info */
-  char ds_key[DS_MAX_KEYLEN];  /* key to lookup information */
-  union {
-    u32_t ds_val_u32;                  /* u32 data (DS_TYPE_U32) */
-    char  ds_val_str[DS_MAX_VALLEN];   /* string data (DS_TYPE_STR) */
-  } ds_val;
-
-  /* out of date subscribers. */
-  bitchunk_t ds_old_subs[BITMAP_CHUNKS(NR_DS_SUBS)];   
+       int     flags;
+       char    key[DS_MAX_KEYLEN];     /* key to lookup information */
+       char    owner[DS_MAX_KEYLEN];
+
+       union {
+               unsigned u32;
+               char string[DS_MAX_STRLEN];
+               struct {
+                       void *data;
+                       size_t length;
+                       size_t reallen;
+               } mem;
+               struct dsi_map {
+                       void *data;
+                       size_t length;
+                       void *realpointer;
+                       void *snapshots[NR_DS_SNAPSHOT];
+                       int sindex;
+               } map;
+       } u;
 };
 
 struct subscription {
-  int sub_flags;               /* flags for this subscription */
-  regex_t sub_regex;           /* regular expression agains keys */
-  endpoint_t sub_owner;                /* who is subscribed */
+       int             flags;
+       char            owner[DS_MAX_KEYLEN];
+       regex_t         regex;
+       bitchunk_t      old_subs[BITMAP_CHUNKS(NR_DS_KEYS)];    
 };
 
-
+#endif /* _DS_STORE_H_ */
index 93c0fa40a513d4d08b1852df15c357dc3458530a..0e43e7f514d26081eab275a163ff6d8bcbf8130b 100644 (file)
@@ -257,9 +257,9 @@ PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
        init_rand256(randbits);
 
        /* Our new identity as a server. */
-       r= ds_retrieve_u32("inet", &tasknr);
+       r= ds_retrieve_label_num("inet", &tasknr);
        if (r != OK)
-               ip_panic(("inet: ds_retrieve_u32 failed for 'inet': %d", r));
+               ip_panic(("inet: ds_retrieve_label_num failed for 'inet': %d", r));
        this_proc= tasknr;
 
        /* Register the device group. */
index 241f659a9f1d9aba24b46ceb1c9f82bd7556ad74..9da1f0ddccde710d07ec46c1d179f55bbfcd1007 100644 (file)
@@ -99,10 +99,10 @@ PUBLIC void osdep_eth_init()
                }
                eth_port->etp_osdep.etp_rd_vec_grant= gid;
 
-               r= ds_retrieve_u32(ecp->ec_task, &tasknr);
+               r= ds_retrieve_label_num(ecp->ec_task, &tasknr);
                if (r != OK && r != ESRCH)
                {
-                       printf("inet: ds_retrieve_u32 failed for '%s': %d\n",
+                       printf("inet: ds_retrieve_label_num failed for '%s': %d\n",
                                ecp->ec_task, r);
                }
                if (r != OK)
index 27b337eb3db72b9c45a538a5c8e13b6881ae6cb2..5e9086cd16243ae8051d06cef35852cc048d98f5 100644 (file)
@@ -1,66 +1,54 @@
-/* This file contains procedures to dump DS data structures.
- *
- * The entry points into this file are
- *   data_store_dmp:           display DS data store contents 
- *
- * Created:
- *   Oct 18, 2005:     by Jorrit N. Herder
- */
-
 #include "inc.h"
 #include "../ds/store.h"
 
-PUBLIC struct data_store store[NR_DS_KEYS];
-
-FORWARD _PROTOTYPE( char *s_flags_str, (int flags)             );
+PRIVATE struct data_store ds_store[NR_DS_KEYS];
 
-/*===========================================================================*
- *                             data_store_dmp                               *
- *===========================================================================*/
 PUBLIC void data_store_dmp()
 {
-  struct data_store *dsp;
-  int i,j, n=0, s;
-  static int prev_i=0;
-
+  struct data_store *p;
+  static int prev_i = 0;
+  int r, i, n = 0;
 
-  printf("Data Store (DS) contents dump\n");
-
-  if((s=getsysinfo(DS_PROC_NR, SI_DATA_STORE, store)) != OK) {
-       printf("Couldn't talk to DS: %d.\n", s);
+  if((r=getsysinfo(DS_PROC_NR, SI_DATA_STORE, ds_store)) != OK) {
+       printf("Couldn't talk to DS: %d.\n", r);
        return;
   }
 
-  printf("slot key                  type value\n");
-
-  for (i=prev_i; i<NR_DS_KEYS; i++) {
-       dsp = &store[i];
-       if (! dsp->ds_flags & DS_IN_USE) continue;
-       if (++n > 22) break;
-       printf("%3d  %-20s ",
-               i, dsp->ds_key);
-       if(dsp->ds_flags & DS_TYPE_U32) {
-               printf("u32  %lu\n", dsp->ds_val.ds_val_u32);
-       } else if(dsp->ds_flags & DS_TYPE_STR) {
-               printf("str  \"%s\"\n", dsp->ds_val.ds_val_str);
-       } else {
-               printf("Bogus type\n");
+  printf("Data store contents:\n");
+  printf("-slot- ------key------ -----owner----- ---type--- ----value---\n");
+  for(i = prev_i; i < NR_DS_KEYS; i++) {
+       p = &ds_store[i];
+       if(!(p->flags & DSF_IN_USE))
+               continue;
+
+       printf("%6d %-15s %-15s ", i, p->key, p->owner);
+       switch(p->flags & DSF_MASK_TYPE) {
+       case DSF_TYPE_U32:
+               printf("%-10s %12u\n", "U32", p->u.u32);
+               break;
+       case DSF_TYPE_STR:
+               printf("%-10s %12s\n", "STR", p->u.string);
+               break;
+       case DSF_TYPE_MEM:
+               printf("%-10s %12u\n", "MEM", p->u.mem.length);
+               break;
+       case DSF_TYPE_MAP:
+               printf("%-10s %9u/%3u\n", "MAP", p->u.map.length,
+                       p->u.map.sindex);
+               break;
+       case DSF_TYPE_LABEL:
+               printf("%-10s %12u\n", "LABEL", p->u.u32);
+               break;
+       default:
+               return;
        }
+
+       if(n++ == 21)
+               break;
   }
+
   if (i >= NR_DS_KEYS) i = 0;
   else printf("--more--\r");
   prev_i = i;
 }
 
-
-PRIVATE char *s_flags_str(int flags)
-{
-       static char str[5];
-       str[0] = (flags & DS_IN_USE) ? 'U' : '-';
-       str[1] = (flags & DS_PUBLIC) ? 'P' : '-';
-       str[2] = '-';
-       str[3] = '\0';
-
-       return(str);
-}
-
index 4a9a58dc87bcbae7e620bed5c1a8f3b395090bc7..64e12900317d3e16d4a50e2929007a6f7bef199e 100644 (file)
@@ -49,11 +49,12 @@ PUBLIC int fs_readsuper()
        return(EINVAL);
   }
 
-  r = ds_retrieve_u32(fs_dev_label, &tasknr);
-  if (r != OK) {
-       printf("%s:%d fs_readsuper: ds_retrieve_u32 failed for '%s': %d\n",
-              __FILE__, __LINE__, fs_dev_label, r);
-       return(EINVAL);
+  r= ds_retrieve_label_num(fs_dev_label, &tasknr);
+  if (r != OK)
+  {
+       printf("mfs:fs_readsuper: ds_retrieve_label_num failed for '%s': %d\n",
+               fs_dev_label, r);
+       return EINVAL;
   }
 
   driver_e = tasknr;
index b805610586c3afb0a9c67e48770a73b0874b66db..53948027865d556a153fec383568061ad812197b 100644 (file)
@@ -45,8 +45,8 @@ PRIVATE int check_mem_available(char *new_brksize)
   mem_sp = &proc.p_memmap[S];            /* pointer to stack segment map */
 
   /* Compute how many clicks the data segment is to become. */
-  data_clicks = (vir_clicks) ( ((long) new_brksize + CLICK_SIZE - 1) >>
-      CLICK_SHIFT) - mem_dp->mem_vir;
+  data_clicks = (vir_clicks) (CLICK_CEIL(new_brksize) >> CLICK_SHIFT)
+       - mem_dp->mem_vir;
 
   /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
   base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
@@ -62,7 +62,7 @@ PRIVATE int check_mem_available(char *new_brksize)
 
   /* Add a safety margin for future stack growth. Impossible to do right. */
 #define SAFETY_BYTES  (384 * sizeof(char *))
-#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
+#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
   gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
   if (sp_lower < gap_base)
   {
index cb70749987b46b4ab2828368cadbfa88a72b4b0d..d6d26dc98807dc37c64955dda372705a70f0930a 100644 (file)
@@ -112,7 +112,7 @@ PRIVATE void print_usage(char *app_name, char *problem)
   fprintf(stderr, "Warning, %s\n", problem);
   fprintf(stderr, "Usage:\n");
   fprintf(stderr,
-  "    %s [-c] (up|run) <binary> [%s <args>] [%s <special>] [%s <ticks>]\n", 
+  "    %s [-c -r] (up|run) <binary> [%s <args>] [%s <special>] [%s <ticks>]\n", 
        app_name, ARG_ARGS, ARG_DEV, ARG_PERIOD);
   fprintf(stderr, "    %s down label\n", app_name);
   fprintf(stderr, "    %s refresh label\n", app_name);
@@ -729,6 +729,9 @@ struct
        { "GETINFO",            SYS_GETINFO },
        { "SAFECOPYFROM",       SYS_SAFECOPYFROM },
        { "SAFECOPYTO",         SYS_SAFECOPYTO },
+       { "SAFEMAP",            SYS_SAFEMAP },
+       { "SAFEREVMAP",         SYS_SAFEREVMAP },
+       { "SAFEUNMAP",          SYS_SAFEUNMAP },
        { "VSAFECOPY",          SYS_VSAFECOPY },
        { "SETGRANT",           SYS_SETGRANT },
        { "READBIOS",           SYS_READBIOS },
index de4c40e70bd146f1003d921f2f552d5e09b8efda..6217ba617ee6e1e0446759262e12503149146c3a 100644 (file)
@@ -15,7 +15,8 @@
  */
 #define FS_KC   SYS_KILL, SYS_VIRCOPY, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, \
     SYS_UMAP, SYS_GETINFO, SYS_EXIT, SYS_TIMES, SYS_SETALARM, \
-    SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL
+    SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL, \
+    SYS_SAFEMAP, SYS_SAFEREVMAP, SYS_SAFEUNMAP
 #define DRV_KC FS_KC, SYS_SEGCTL, SYS_IRQCTL, SYS_INT86, SYS_DEVIO, \
     SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT, SYS_PROFBUF, SYS_SYSCTL
 
index e58f3fdadf55bda3c901c820e5f1831c60cebb36..0845206d66e991dd11ca6dee3221218075459b2c 100644 (file)
@@ -45,7 +45,7 @@ struct rproc *rp;                             /* pointer to process slot */
   rpub = rp->r_pub;
 
   /* Register its label with DS. */
-  s= ds_publish_u32(rpub->label, rpub->endpoint);
+  s= ds_publish_label(rpub->label, rpub->endpoint, DSF_OVERWRITE);
   if (s != OK) {
       return s;
   }
index 14a6be49725058a2345e1268d272e6eb25f0bce1..645f8197ed768fa584091e02f6575efe1e7e2fba 100644 (file)
@@ -96,7 +96,7 @@ PUBLIC int do_mapdriver()
 
        label[label_len]= '\0';
 
-       r= ds_retrieve_u32(label, &tasknr);
+       r= ds_retrieve_label_num(label, &tasknr);
        if (r != OK)
        {
                printf("vfs:do_mapdriver: ds doesn't know '%s'\n", label);
index bb9e19ef2d12660a27b1a91231cc8402b4b4cd27..da8627899cf27974662594fc0391ac13bd9ef7b5 100644 (file)
@@ -96,7 +96,7 @@ PUBLIC int do_mount()
 
        mount_label[sizeof(mount_label)-1] = 0;
 
-       r = ds_retrieve_u32(mount_label, &fs_e);
+       r = ds_retrieve_label_num(mount_label, &fs_e);
        if (r != OK) return(r);
 
        if (isokendpt(fs_e, &proc_nr) != OK) return(EINVAL);
index 42091291b13c3fa1327ee65c0c648ca0e5bf9ee2..b3dc8d5b32226287f42849f6dcf41e2e399ddddf 100644 (file)
@@ -5,7 +5,7 @@ include /etc/make.conf
 
 OBJ = main.o alloc.o utility.o exec.o exit.o fork.o break.o \
        signal.o vfs.o mmap.o slaballoc.o region.o pagefaults.o addravl.o \
-       physravl.o rs.o queryexit.o
+       physravl.o rs.o queryexit.o map_mem.o
 ARCHOBJ =  $(ARCH)/vm.o $(ARCH)/pagetable.o $(ARCH)/arch_pagefaults.o $(ARCH)/util.o 
 
 CPPFLAGS=-I../../kernel/arch/$(ARCH)/include -I$(ARCH)
index 75a91e5eb9b72185a3ecad674cbe3465c651a59b..b6022f848603b7ffeea3090a75e4faed4f73c7b3 100644 (file)
@@ -96,7 +96,7 @@ vir_bytes sp;                 /* new value of sp */
 
   /* Add a safety margin for future stack growth. Impossible to do right. */
 #define SAFETY_BYTES  (384 * sizeof(char *))
-#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
+#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
   gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
   if (sp_lower < gap_base)
   {
@@ -165,7 +165,7 @@ vir_bytes v;
        vir_clicks new_clicks;
        int r;
 
-       new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT);
+       new_clicks = (vir_clicks) (CLICK_CEIL(v) >> CLICK_SHIFT);
        if (new_clicks < vmp->vm_arch.vm_seg[D].mem_vir) {
                printf("VM: real_brk failed because new_clicks too high: %d\n",
                        new_clicks);
index 65106af72cd5c52e9f84c961f0328f327055a7d3..264550cb9d8aa9cd1e4564f7932d051f9c764b69 100644 (file)
@@ -110,10 +110,10 @@ SANITYCHECK(SCL_DETAIL);
        }
 
        /* Check to see if segment sizes are feasible. */
-       tc = ((unsigned long) args.text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
-       dc = (args.data_bytes+args.bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
-       totc = (args.tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
-       sc = (args.args_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
+       tc = (vir_clicks) (CLICK_CEIL(args.text_bytes) >> CLICK_SHIFT);
+       dc = (vir_clicks) (CLICK_CEIL(args.data_bytes+args.bss_bytes) >> CLICK_SHIFT);
+       totc = (vir_clicks) (CLICK_CEIL(args.tot_bytes) >> CLICK_SHIFT);
+       sc = (vir_clicks) (CLICK_CEIL(args.args_bytes) >> CLICK_SHIFT);
        if (dc >= totc) {
                printf("VM: newmem: no stack?\n");
                return(ENOEXEC); /* stack must be at least 1 click */
@@ -204,10 +204,10 @@ vir_bytes *stack_top;             /* top of process stack */
    * and stack occupies an integral number of clicks, starting at click
    * boundary.  The data and bss parts are run together with no space.
    */
-  text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
-  data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
-  stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
-  tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
+  text_clicks = (vir_clicks) (CLICK_CEIL(text_bytes) >> CLICK_SHIFT);
+  data_clicks = (vir_clicks) (CLICK_CEIL(data_bytes + bss_bytes) >> CLICK_SHIFT);
+  stack_clicks = (vir_clicks) (CLICK_CEIL(stk_bytes) >> CLICK_SHIFT);
+  tot_clicks = (vir_clicks) (CLICK_CEIL(tot_bytes) >> CLICK_SHIFT);
   gap_clicks = tot_clicks - data_clicks - stack_clicks;
   if ( (int) gap_clicks < 0) {
        printf("VM: new_mem: no gap?\n");
index f2019f4bf4505b1d84e370687617f832663fd46e..f7fe853335589c5deb4639e8678a361fb263e06d 100644 (file)
@@ -2,8 +2,6 @@
 #define _SYSTEM 1
 #define _POSIX_SOURCE 1
 
-#define VERBOSE 0
-
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/config.h>
index 7524eb344b9e89b6103fe608c39289fcec4e8b98..fcf0976667f8ca397f138b3ceef58b021829538c 100644 (file)
@@ -1,8 +1,6 @@
 
 #define _SYSTEM 1
 
-#define VERBOSE 0
-
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/config.h>
diff --git a/servers/vm/map_mem.c b/servers/vm/map_mem.c
new file mode 100644 (file)
index 0000000..508dbcb
--- /dev/null
@@ -0,0 +1,330 @@
+
+#define _SYSTEM 1
+
+#include <minix/com.h>
+#include <minix/callnr.h>
+#include <minix/type.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/sysutil.h>
+#include <minix/syslib.h>
+
+#include <sys/mman.h>
+
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <memory.h>
+
+#include "vm.h"
+#include "proto.h"
+#include "util.h"
+#include "glo.h"
+#include "region.h"
+#include "sanitycheck.h"
+
+/*===========================================================================*
+ *                             split_phys                                   *
+ *===========================================================================*/
+PRIVATE int split_phys(struct phys_region *pr, vir_bytes point)
+{
+       struct phys_region *newpr, *q, *prev;
+       struct phys_block *newpb;
+       struct phys_block *pb = pr->ph;
+/* Split the phys region into 2 parts by @point. */
+
+       if(pr->offset >= point || pr->offset + pb->length <= point)
+               return OK;
+       if(!SLABALLOC(newpb))
+               return ENOMEM;
+
+       /* Split phys block. */
+       *newpb = *pb;
+       pb->length = point - pr->offset;
+       newpb->length -= pb->length;
+       newpb->phys += pb->length;
+
+       /* Split phys regions in a list. */
+       for(q = pb->firstregion; q; q = q->next_ph_list) {
+               if(!SLABALLOC(newpr))
+                       return ENOMEM;
+
+               *newpr = *q;
+               newpr->ph = newpb;
+               newpr->offset += pb->length;
+
+               /* Link to the vir region's phys region list. */
+               physr_insert(newpr->parent->phys, newpr);
+
+               /* Link to the next_ph_list. */
+               if(q == pb->firstregion) {
+                       newpb->firstregion = newpr;
+                       prev = newpr;
+               } else {
+                       prev->next_ph_list = newpr;
+                       prev = newpr;
+               }
+       }
+       prev->next_ph_list = NULL;
+
+       return OK;
+}
+
+/*===========================================================================*
+ *                             rm_phys_regions                              *
+ *===========================================================================*/
+PRIVATE void rm_phys_regions(struct vir_region *region,
+       vir_bytes begin, vir_bytes length)
+{
+/* Remove all phys regions between @begin and @begin+length.
+ *
+ * Don't update the page table, because we will update it at map_memory()
+ * later.
+ */
+       struct phys_region *pr;
+       physr_iter iter;
+
+       physr_start_iter(region->phys, &iter, begin, AVL_GREATER_EQUAL);
+       while((pr = physr_get_iter(&iter)) && pr->offset < begin + length) {
+               pb_unreferenced(region, pr);
+               physr_remove(region->phys, pr->offset);
+               physr_start_iter(region->phys, &iter, begin,
+                       AVL_GREATER_EQUAL);
+               SLABFREE(pr);
+       }
+}
+
+/*===========================================================================*
+ *                             clean_phys_regions                           *
+ *===========================================================================*/
+PRIVATE void clean_phys_regions(struct vir_region *region,
+       vir_bytes offset, vir_bytes length)
+{
+/* Consider @offset as the start address and @offset+length as the end address.
+ * If there are phys regions crossing the start address or the end address,
+ * split them into 2 parts.
+ *
+ * We assume that the phys regions are listed in order and don't overlap.
+ */
+       struct phys_region *pr;
+       physr_iter iter;
+
+       physr_start_iter_least(region->phys, &iter);
+       while((pr = physr_get_iter(&iter))) {
+               /* If this phys region crosses the start address, split it. */
+               if(pr->offset < offset
+                       && pr->offset + pr->ph->length > offset) {
+                       split_phys(pr, offset);
+                       physr_start_iter_least(region->phys, &iter);
+               }
+               /* If this phys region crosses the end address, split it. */
+               else if(pr->offset < offset + length
+                       && pr->offset + pr->ph->length > offset + length) {
+                       split_phys(pr, offset + length);
+                       physr_start_iter_least(region->phys, &iter);
+               }
+               else {
+                       physr_incr_iter(&iter);
+               }
+       }
+}
+
+/*===========================================================================*
+ *                             do_map_memory                                *
+ *===========================================================================*/
+PRIVATE int do_map_memory(struct vmproc *vms, struct vmproc *vmd,
+       struct vir_region *vrs, struct vir_region *vrd,
+       vir_bytes offset_s, vir_bytes offset_d,
+       vir_bytes length, int flag)
+{
+       struct phys_region *prs;
+       struct phys_region *newphysr;
+       struct phys_block *pb;
+       physr_iter iter;
+       u32_t pt_flag = PTF_PRESENT | PTF_USER;
+       vir_bytes end;
+
+       /* Search for the first phys region in the source process. */
+       physr_start_iter(vrs->phys, &iter, offset_s, AVL_EQUAL);
+       prs = physr_get_iter(&iter);
+       if(!prs)
+               vm_panic("map_memory: no aligned phys region.", 0);
+
+       /* flag: 0 -> read-only
+        *       1 -> writable
+        *      -1 -> share as COW, so read-only
+        */
+       if(flag > 0)
+               pt_flag |= PTF_WRITE;
+
+       /* Map phys blocks in the source process to the destination process. */
+       end = offset_d + length;
+       while((prs = physr_get_iter(&iter)) && offset_d < end) {
+               /* If a SMAP share was requested but the phys block has already
+                * been shared as COW, copy the block for the source phys region
+                * first.
+                */
+               pb = prs->ph;
+               if(flag >= 0 && pb->refcount > 1
+                       && pb->share_flag == PBSH_COW) {
+                       map_copy_ph_block(vms, vrs, prs);
+                       pb = prs->ph;
+               }
+
+               /* Allocate a new phys region. */
+               if(!SLABALLOC(newphysr))
+                       return ENOMEM;
+
+               /* Set and link the new phys region to the block. */
+               newphysr->ph = pb;
+               newphysr->offset = offset_d;
+               newphysr->parent = vrd;
+               newphysr->next_ph_list = pb->firstregion;
+               pb->firstregion = newphysr;
+               physr_insert(newphysr->parent->phys, newphysr);
+               pb->refcount++;
+
+               /* If a COW share was requested but the phys block has already
+                * been shared as SMAP, give up on COW and copy the block for
+                * the destination phys region now.
+                */
+               if(flag < 0 && pb->refcount > 1
+                       && pb->share_flag == PBSH_SMAP) {
+                       map_copy_ph_block(vmd, vrd, newphysr);
+               }
+               else {
+                       /* See if this is a COW share or SMAP share. */
+                       if(flag < 0) {                  /* COW share */
+                               pb->share_flag = PBSH_COW;
+                               /* Update the page table for the src process. */
+                               pt_writemap(&vms->vm_pt, offset_s + vrs->vaddr,
+                                       pb->phys, pb->length,
+                                       pt_flag, WMF_OVERWRITE);
+                       }
+                       else {                          /* SMAP share */
+                               pb->share_flag = PBSH_SMAP;
+                       }
+                       /* Update the page table for the destination process. */
+                       pt_writemap(&vmd->vm_pt, offset_d + vrd->vaddr,
+                               pb->phys, pb->length, pt_flag, WMF_OVERWRITE);
+               }
+
+               physr_incr_iter(&iter);
+               offset_d += pb->length;
+               offset_s += pb->length;
+       }
+}
+
+/*===========================================================================*
+ *                             map_memory                                   *
+ *===========================================================================*/
+PUBLIC int map_memory(endpoint_t sour, endpoint_t dest,
+       vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag)
+{
+/* This is the entry point. This function will be called by handle_memory() when
+ * VM recieves a map-memory request.
+ */
+       struct vmproc *vms, *vmd;
+       struct vir_region *vrs, *vrd;
+       struct phys_region *prs, *prd;
+       physr_iter iters, iterd;
+       vir_bytes offset_s, offset_d;
+       int p;
+
+       if(vm_isokendpt(sour, &p) != OK)
+               vm_panic("handle_memory: endpoint wrong", sour);
+       vms = &vmproc[p];
+       if(vm_isokendpt(dest, &p) != OK)
+               vm_panic("handle_memory: endpoint wrong", dest);
+       vmd = &vmproc[p];
+
+       vrs = map_lookup(vms, virt_s);
+       vm_assert(vrs);
+       vrd = map_lookup(vmd, virt_d);
+       vm_assert(vrd);
+
+       /* Linear address -> offset from start of vir region. */
+       offset_s = virt_s - vrs->vaddr;
+       offset_d = virt_d - vrd->vaddr;
+
+       /* Make sure that the range in the source process has been mapped
+        * to physical memory.
+        */
+       map_handle_memory(vms, vrs, offset_s, length, 0);
+
+       /* Prepare work. */
+       #define map_printregion(x, y) (x = x)
+       #define printf(x, y, z) (z = z)
+       printf("before clean with offset, length: %d, %d\n", offset_s, length);
+       map_printregion(vms, vrs);
+       clean_phys_regions(vrs, offset_s, length);
+       printf("after clean with offset, length: %d, %d\n", offset_s, length);
+       map_printregion(vms, vrs);
+
+       printf("before clean with offset, length: %d, %d\n", offset_d, length);
+       map_printregion(vmd, vrd);
+       clean_phys_regions(vrd, offset_d, length);
+       printf("after clean with offset, length: %d, %d\n", offset_d, length);
+       map_printregion(vmd, vrd);
+
+       rm_phys_regions(vrd, offset_d, length);
+       printf("after rm with offset, length: %d, %d\n", offset_d, length);
+       map_printregion(vmd, vrd);
+
+       /* Map memory. */
+       do_map_memory(vms, vmd, vrs, vrd, offset_s, offset_d, length, flag);
+       printf("after map (dst) with offset, length: %d, %d\n", offset_d, length);
+       map_printregion(vmd, vrd);
+       #undef map_printregion
+       #undef printf
+
+       return OK;
+}
+
+/*===========================================================================*
+ *                             unmap_memory                                 *
+ *===========================================================================*/
+PUBLIC int unmap_memory(endpoint_t sour, endpoint_t dest,
+       vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag)
+{
+       struct vmproc *vmd;
+       struct vir_region *vrd;
+       struct phys_region *pr;
+       struct phys_block *pb;
+       physr_iter iter;
+       vir_bytes off, end;
+       int p;
+
+       /* Use information on the destination process to unmap. */
+       if(vm_isokendpt(dest, &p) != OK)
+               vm_panic("handle_memory: endpoint wrong", dest);
+       vmd = &vmproc[p];
+
+       vrd = map_lookup(vmd, virt_d);
+       vm_assert(vrd);
+
+       /* Search for the first phys region in the destination process. */
+       off = virt_d - vrd->vaddr;
+       physr_start_iter(vrd->phys, &iter, off, AVL_EQUAL);
+       pr = physr_get_iter(&iter);
+       if(!pr)
+               vm_panic("map_memory: no aligned phys region.", 0);
+
+       /* Copy the phys block now rather than doing COW. */
+       end = off + length;
+       while((pr = physr_get_iter(&iter)) && off < end) {
+               pb = pr->ph;
+               vm_assert(pb->refcount > 1);
+               vm_assert(pb->share_flag == PBSH_SMAP);
+
+               map_copy_ph_block(vmd, vrd, pr);
+
+               physr_incr_iter(&iter);
+               off += pb->length;
+       }
+
+       return OK;
+}
+
index 686db47794b4dbc2a58e11f1a3cda4e5c7dbabff..5447f15fa3843f2dbe56f835ecc1f13bbc230098 100644 (file)
@@ -1,8 +1,6 @@
 
 #define _SYSTEM 1
 
-#define VERBOSE 0
-
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/config.h>
index 6c5fc47551fa08f727204a6ce8eacab8e40fdb65..34c6570d055db1ff5bf6c2a5ac0678ed3ae91253 100644 (file)
@@ -127,26 +127,42 @@ PUBLIC void do_pagefaults(void)
 }
 
 /*===========================================================================*
- *                             do_memory                            *
+ *                                do_memory                                 *
  *===========================================================================*/
 PUBLIC void do_memory(void)
 {
-       int r, s;
-       endpoint_t who, requestor;
-       vir_bytes mem;
+       endpoint_t who, who_s, requestor;
+       vir_bytes mem, mem_s;
        vir_bytes len;
        int wrflag;
 
-       while((r=sys_vmctl_get_memreq(&who, &mem, &len, &wrflag, &requestor))
-         == OK) {
+       while(1) {
                int p, r = OK;
                struct vmproc *vmp;
 
-               if(vm_isokendpt(who, &p) != OK)
-                       vm_panic("do_memory: endpoint wrong", who);
-               vmp = &vmproc[p];
-
-               r = handle_memory(vmp, mem, len, wrflag);
+               r = sys_vmctl_get_memreq(&who, &mem, &len, &wrflag, &who_s,
+                       &mem_s, &requestor);
+
+               switch(r) {
+               case VMPTYPE_CHECK:
+                       if(vm_isokendpt(who, &p) != OK)
+                               vm_panic("do_memory: bad endpoint", who);
+                       vmp = &vmproc[p];
+
+                       r = handle_memory(vmp, mem, len, wrflag);
+                       break;
+               case VMPTYPE_COWMAP:
+                       r = map_memory(who_s, who, mem_s, mem, len, -1);
+                       break;
+               case VMPTYPE_SMAP:
+                       r = map_memory(who_s, who, mem_s, mem, len, wrflag);
+                       break;
+               case VMPTYPE_SUNMAP:
+                       r = unmap_memory(who_s, who, mem_s, mem, len, wrflag);
+                       break;
+               default:
+                       return;
+               }
 
                if(sys_vmctl(requestor, VMCTL_MEMREQ_REPLY, r) != OK)
                        vm_panic("do_memory: sys_vmctl failed", r);
index 3ae0b205d5b002260038f2494cd92bad28c03bd8..daf6ac983a33698fb16fb8cf14c4ee7d5b15b0d8 100644 (file)
@@ -4,6 +4,8 @@ struct vmproc;
 struct stat;
 struct mem_map;
 struct memory;
+struct vir_region;
+struct phys_region;
 
 #include <minix/ipc.h>
 #include <minix/endpoint.h>
@@ -76,6 +78,12 @@ _PROTOTYPE( int vfs_open, (struct vmproc *for_who, callback_t callback,
 _PROTOTYPE( int vfs_close, (struct vmproc *for_who, callback_t callback,
        int fd));
 
+/* map_mem.c */
+_PROTOTYPE( int map_memory, (endpoint_t sour, endpoint_t dest,
+       vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag));
+_PROTOTYPE( int unmap_memory, (endpoint_t sour, endpoint_t dest,
+       vir_bytes virt_s, vir_bytes virt_d, vir_bytes length, int flag));
+
 /* mmap.c */
 _PROTOTYPE(int do_mmap, (message *msg)                                 );
 _PROTOTYPE(int do_munmap, (message *msg)                               );
@@ -156,6 +164,10 @@ _PROTOTYPE(int map_remap, (struct vmproc *dvmp, vir_bytes da, size_t size,
 _PROTOTYPE(int map_get_phys, (struct vmproc *vmp, vir_bytes addr, phys_bytes *r));
 _PROTOTYPE(int map_get_ref, (struct vmproc *vmp, vir_bytes addr, u8_t *cnt));
 
+_PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp,
+       struct vir_region *region, struct phys_region *ph));
+_PROTOTYPE(void pb_unreferenced, (struct vir_region *region,
+       struct phys_region *pr));
 #if SANITYCHECKS
 _PROTOTYPE(void map_sanitycheck,(char *file, int line));
 #endif
index 339d53789cc835263f4be4fb977350d77a8fd309..7d981a4ab63c86538633ba8accc91edcce6a1705 100644 (file)
@@ -1,8 +1,6 @@
 
 #define _SYSTEM 1
 
-#define VERBOSE 0
-
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/config.h>
index 559f3eecb2fd4b3a01caf7e4240f29270a4ac7a2..33768ada77abfe764bf4efdc60716df00ce5d2c7 100644 (file)
@@ -40,8 +40,6 @@ FORWARD _PROTOTYPE(struct phys_region *map_new_physblock, (struct vmproc *vmp,
 FORWARD _PROTOTYPE(int map_ph_writept, (struct vmproc *vmp, struct vir_region *vr,
        struct phys_region *pr));
 
-FORWARD _PROTOTYPE(int map_copy_ph_block, (struct vmproc *vmp, struct vir_region *region, struct phys_region *ph));
-
 FORWARD _PROTOTYPE(struct vir_region *map_copy_region, (struct vmproc *vmp, struct vir_region *vr));
 
 PRIVATE char *map_name(struct vir_region *vr)
@@ -422,7 +420,7 @@ USE(newregion,
 /*===========================================================================*
  *                             pb_unreferenced                              *
  *===========================================================================*/
-void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
+PUBLIC void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
 {
        struct phys_block *pb;
        int remap = 0;
@@ -460,20 +458,6 @@ void pb_unreferenced(struct vir_region *region, struct phys_region *pr)
                        vm_panic("strange phys flags", NO_NUM);
                }
                SLABFREE(pb);
-       } else if(WRITABLE(region, pb)) {
-               /* If a writable piece of physical memory is now only
-                * referenced once, map it writable right away instead of
-                * waiting for a page fault.
-                */
-                       vm_assert(pb);
-                       vm_assert(pb->firstregion);
-                       vm_assert(!pb->firstregion->next_ph_list);
-                       vm_assert(pb->firstregion->ph == pb);
-                       vm_assert(pb->firstregion->ph == pb);
-                       if(map_ph_writept(pb->firstregion->parent->parent,
-                               pb->firstregion->parent, pb->firstregion) != OK) {
-                               vm_panic("pb_unreferenced: writept", NO_NUM);
-                       }
        }
 }
 
@@ -709,7 +693,7 @@ phys_bytes what_mem;
 /*===========================================================================*
  *                             map_copy_ph_block                            *
  *===========================================================================*/
-PRIVATE int map_copy_ph_block(vmp, region, ph)
+PUBLIC int map_copy_ph_block(vmp, region, ph)
 struct vmproc *vmp;
 struct vir_region *region;
 struct phys_region *ph;
@@ -816,9 +800,13 @@ int write;
                        if(r != OK)
                                printf("map_ph_writept failed\n");
                } else {
-                       r = map_copy_ph_block(vmp, region, ph);
-                       if(r != OK)
-                               printf("map_copy_ph_block failed\n");
+                       if(ph->ph->refcount > 0
+                               && ph->ph->share_flag != PBSH_COW) {
+                               printf("VM: write RO mapped pages.\n");
+                               return EFAULT;
+                       } else {
+                               r = map_copy_ph_block(vmp, region, ph);
+                       }
                }
        } else {
                /* Pagefault in non-existing block. Map in new block. */
@@ -959,9 +947,12 @@ int write;
        SANITYCHECK(SCL_FUNCTIONS);
 
        if(changes < 1) {
+#if VERBOSE
                printf("region start at 0x%lx offset 0x%lx len 0x%lx write %d\n", 
                        region->vaddr, offset, length, write);
-               vm_panic("no changes in map_handle_memory", NO_NUM);
+               printf("no changes in map_handle_memory\n");
+#endif
+               return EFAULT;
        }
 
 #if SANITYCHECKS
@@ -1065,11 +1056,19 @@ PUBLIC int map_writept(struct vmproc *vmp)
                physr_iter iter;
                physr_start_iter_least(vr->phys, &iter);
                while((ph = physr_get_iter(&iter))) {
+                       physr_incr_iter(&iter);
+
+                       /* If this phys block is shared as SMAP, then do
+                        * not update the page table. */
+                       if(ph->ph->refcount > 1
+                               && ph->ph->share_flag == PBSH_SMAP) {
+                               continue;
+                       }
+
                        if((r=map_ph_writept(vmp, vr, ph)) != OK) {
                                printf("VM: map_writept: failed\n");
                                return r;
                        }
-                       physr_incr_iter(&iter);
                }
        }
 
@@ -1125,6 +1124,14 @@ struct vmproc *src;
                        USE(pb, pb->refcount++;);
                        vm_assert(pb->refcount > 1);
 
+                       /* If the phys block has been shared as SMAP,
+                        * do the regular copy. */
+                       if(pb->refcount > 2 && pb->share_flag == PBSH_SMAP) {
+                               map_copy_ph_block(dst, newvr, new_ph);
+                       } else {
+                               pb->share_flag = PBSH_COW;
+                       }
+
                        /* Get next new physregion */
                        physr_incr_iter(&iter_orig);
                        physr_incr_iter(&iter_new);
index 69419ec58acd4a2407c148eedf35558e74e47f14..948ce715a14c8df45cd984207df8fa091ec3acb4 100644 (file)
@@ -23,6 +23,9 @@ struct phys_block {
        vir_bytes               length; /* no. of contiguous bytes */
        phys_bytes              phys;   /* physical memory */
        u8_t                    refcount;       /* Refcount of these pages */
+#define PBSH_COW       1
+#define PBSH_SMAP      2
+       u8_t                    share_flag;     /* PBSH_COW or PBSH_SMAP */
 
        /* first in list of phys_regions that reference this block */
        struct phys_region      *firstregion;   
index 1eb194f6106522a279171023c3adfb80fcd6783b..6611a1e2b8b6a6460c6d45831c504de5c4006aec 100644 (file)
@@ -1,8 +1,6 @@
 
 #define _SYSTEM 1
 
-#define VERBOSE 0
-
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/config.h>
index 09b4dbbc05cff2912a0ca4c6fcb60dd1d796b959..a9d4182b65299b1c61f54b8e7c0d8794615cb67e 100644 (file)
@@ -76,8 +76,8 @@ struct memory *mem_chunks;                      /* store mem chunks here */
         base = mem_chunks[i].base;
         size = mem_chunks[i].size;
         limit = base + size;
-        base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
-        limit &= ~(long)(CLICK_SIZE-1);
+        base = (phys_bytes) (CLICK_CEIL(base));
+        limit = (phys_bytes) (CLICK_FLOOR(limit));
         if (limit <= base) {
                 memp->base = memp->size = 0;
         } else { 
index 9f8d34899838fc7a44c73810f56d0d9684b4ddbc..df2ec4e7936f685fcb974b12ea667c5c109298ff 100644 (file)
@@ -1,8 +1,6 @@
 
 #define _SYSTEM 1
 
-#define VERBOSE 0
-
 #include <minix/callnr.h>
 #include <minix/com.h>
 #include <minix/config.h>
diff --git a/test/ds/Makefile b/test/ds/Makefile
new file mode 100644 (file)
index 0000000..63bf396
--- /dev/null
@@ -0,0 +1,18 @@
+all: dstest subs
+       chmod +x down run
+
+dstest: dstest.c inc.h
+       cc -o $@ $< -lsys
+
+subs: subs.c inc.h
+       cc -o $@ $< -lsys
+
+run: all
+       sh run
+
+kill:
+       sh down
+
+clean:
+       rm -f dstest subs
+
diff --git a/test/ds/README b/test/ds/README
new file mode 100644 (file)
index 0000000..e8702ed
--- /dev/null
@@ -0,0 +1,23 @@
+Test Program for DataServer
+
+How to run
+==========
+
+  1. Type `make run` to prepare and run test.
+  2. When done testing, type `make clean` to clean up.
+
+How the test works
+==================
+
+`dstest` tests the new DS API (excluding ds_subscribe() and ds_check()).
+test_u32, test_str, test_mem, test_label, and test_map test U32, STR, MEM, LABEL
+and MAP type respectively.
+
+Invalid invokation is tested as well. Erroneous conditions are tested only once.
+For example, publishing an entry with same label name, but without 
+DSF_OVERWRITE set, is tested in test_u32 and nowhere else again.
+Type-specific features are always tested.
+
+`subs` tests ds_subscribe() and ds_check(). The server subscribes
+to a U32 type. When `dstest` runs, `subs` catches all the updates.
+
diff --git a/test/ds/down b/test/ds/down
new file mode 100644 (file)
index 0000000..ad9cd5b
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+service down dstest
+service down subs
diff --git a/test/ds/dstest.c b/test/ds/dstest.c
new file mode 100644 (file)
index 0000000..d6d13fe
--- /dev/null
@@ -0,0 +1,230 @@
+#include "inc.h"
+
+char *key_u32 = "test_u32";
+char *key_str = "test_str";
+char *key_mem = "test_mem";
+char *key_map = "test_map";
+char *key_label = "test_label";
+
+/*===========================================================================*
+ *                             test_u32                                     *
+ *===========================================================================*/
+void test_u32(void)
+{
+       int r;
+       unsigned long value;
+
+       /* Publish and retrieve. */
+       r = ds_publish_u32(key_u32, 1234, 0);
+       assert(r == OK);
+       r = ds_retrieve_u32(key_u32, &value);
+       assert(r == OK && value == 1234);
+
+       /* If dstest deletes 'test_u32' immediately after publishing it,
+        * subs will catch the event, but it can't check it immediately.
+        * So dstest will sleep 2 seconds to wait for subs to complete. */
+       sleep(2);
+
+       /* Publish again without DSF_OVERWRITE. */
+       r = ds_publish_u32(key_u32, 4321, 0);
+       assert(r == EEXIST);
+
+       /* Publish again with DSF_OVERWRITE to overwrite it. */
+       r = ds_publish_u32(key_u32, 4321, DSF_OVERWRITE);
+       assert(r == OK);
+       r = ds_retrieve_u32(key_u32, &value);
+       assert(r == OK && value == 4321);
+
+       /* Delete. */
+       r = ds_delete_u32(key_u32);
+       assert(r == OK);
+       r = ds_retrieve_u32(key_u32, &value);
+       assert(r == ESRCH);
+
+       printf("DSTEST: U32 test successful!\n");
+}
+
+/*===========================================================================*
+ *                             test_str                                     *
+ *===========================================================================*/
+void test_str(void)
+{
+       int r;
+       char *string = "little";
+       char *longstring = "verylooooooongstring";
+       char buf[17];
+
+       r = ds_publish_str(key_str, string, 0);
+       assert(r == OK);
+
+       r = ds_retrieve_str(key_str, buf, 0);
+       assert(r == OK && strcmp(string, buf) == 0);
+
+       r = ds_delete_str(key_str);
+       assert(r == OK);
+
+       /* Publish a long string. */
+       r = ds_publish_str(key_str, longstring, 0);
+       assert(r == EINVAL);
+
+       printf("DSTEST: STRING test successful!\n");
+}
+
+/*===========================================================================*
+ *                             test_mem                                     *
+ *===========================================================================*/
+void test_mem(void)
+{
+       char *string1 = "ok, this is a string";
+       char *string2 = "ok, this is a very looooong string";
+       size_t len1 = strlen(string1) + 1;
+       size_t len2 = strlen(string2) + 1;
+       char buf[100];
+       size_t get_len;
+       int r;
+
+       /* Publish and retrieve. */
+       r = ds_publish_mem(key_mem, string1, len1, 0);
+       assert(r == OK);
+       get_len = 100;
+       r = ds_retrieve_mem(key_mem, buf, &get_len);
+       assert(r == OK && strcmp(string1, buf) == 0);
+       assert(get_len == len1);
+
+       /* Let get_len=8, which is less than strlen(string1). */
+       get_len = 8;
+       r = ds_retrieve_mem(key_mem, buf, &get_len);
+       assert(r == OK && get_len == 8);
+
+       /* Publish again to overwrite with a bigger memory range. */
+       r = ds_publish_mem(key_mem, string2, len2, DSF_OVERWRITE);
+       assert(r == OK);
+
+       get_len = 100;
+       r = ds_retrieve_mem(key_mem, buf, &get_len);
+       assert(r == OK && strcmp(string2, buf) == 0);
+       assert(get_len == len2);
+
+       r = ds_delete_mem(key_mem);
+       assert(r == OK);
+
+       printf("DSTEST: MEM test successful!\n");
+}
+
+/*===========================================================================*
+ *                             test_label                                   *
+ *===========================================================================*/
+void test_label(void)
+{
+       int r;
+       char get_label[DS_MAX_KEYLEN];
+       unsigned long num;
+
+       /* Publish and retrieve. */
+       r = ds_publish_label(key_label, 1234, 0);
+       assert(r == OK);
+       r = ds_retrieve_label_num(key_label, &num);
+       assert(r == OK && num == 1234);
+
+       /* Here are the differences w.r.t. U32. */
+       r = ds_publish_label("hello", 1234, 0);
+       assert(r == EEXIST);
+       r = ds_retrieve_label_name(get_label, 1234);
+       assert(r == OK && strcmp(key_label, get_label) == 0);
+
+       r = ds_delete_label(key_label);
+       assert(r == OK);
+
+       printf("DSTEST: LABEL test successful!\n");
+}
+
+/*===========================================================================*
+ *                             test_map                                     *
+ *===========================================================================*/
+void test_map(void)
+{
+       char buf_buf[CLICK_SIZE * 2];
+       char buf_buf2[CLICK_SIZE * 2];
+       char *buf, *buf2;
+       char get_buf[CLICK_SIZE];
+       int *p;
+       volatile int *p2;
+       int *get_p;
+       size_t get_len;
+       int is;
+       int r;
+
+       buf = (char*) CLICK_CEIL(buf_buf);
+       buf2 = (char*) CLICK_CEIL(buf_buf2);
+
+       p = (int *)buf;
+       p2 = (int *)buf2;
+       get_p = (int *)get_buf;
+
+       *p = 1;
+       r = ds_publish_map(key_map, buf, CLICK_SIZE, 0);
+       assert(r == OK);
+
+       r = ds_snapshot_map(key_map, &is);
+       assert(r == OK);
+
+       /* Copy the mapped memory range.
+        * Set *p=2, then the mapped memory range should change too
+        * and *get_p should be 2.
+        */
+       *p = 2;
+       get_len = CLICK_SIZE;
+       r = ds_retrieve_map(key_map, get_buf, &get_len, 0, DSMF_COPY_MAPPED);
+       assert(r == OK && get_len == CLICK_SIZE && *get_p == 2);
+
+       /* Copy snapshot, where *get_p should still be 1. */
+       get_len = CLICK_SIZE;
+       r = ds_retrieve_map(key_map, get_buf, &get_len, is, DSMF_COPY_SNAPSHOT);
+       assert(r == OK && get_len == CLICK_SIZE && *get_p == 1);
+
+       /* Map the mapped memory range to @buf2, then set *p=3, which
+        * in turn should let *p2=3.
+        */
+       get_len = CLICK_SIZE;
+       r = ds_retrieve_map(key_map, buf2, &get_len, 0, DSMF_MAP_MAPPED);
+       assert(r == OK && get_len == CLICK_SIZE);
+       *p = 3;
+       assert(*p2 == 3);
+
+       r = ds_delete_map(key_map);
+       assert(r == OK);
+
+       printf("DSTEST: MAP test successful!\n");
+}
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                             main                                         *
+ *===========================================================================*/
+int main(void)
+{
+       /* SEF local startup. */
+       sef_local_startup();
+
+       /* Run all the tests. */
+       test_u32();
+       test_str();
+       test_mem();
+       test_map();
+       test_label();
+
+       return 0;
+}
+
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/ds/inc.h b/test/ds/inc.h
new file mode 100644 (file)
index 0000000..2f7907d
--- /dev/null
@@ -0,0 +1,15 @@
+#define _MINIX
+#define _SYSTEM
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/ds.h>
+#include <minix/syslib.h>
diff --git a/test/ds/run b/test/ds/run
new file mode 100644 (file)
index 0000000..46ab113
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+PWD=`pwd`
+
+service up ${PWD}/subs -config ${PWD}/system.conf -script ${PWD}/down
+service up ${PWD}/dstest -config ${PWD}/system.conf -script ${PWD}/down
diff --git a/test/ds/subs.c b/test/ds/subs.c
new file mode 100644 (file)
index 0000000..ad73776
--- /dev/null
@@ -0,0 +1,93 @@
+#include "inc.h"
+
+char *key_u32 = "test_u32";
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                             main                                         *
+ *===========================================================================*/
+int main(void)
+{
+       int r;
+       message mess;
+       char key[DS_MAX_KEYLEN];
+       int type;
+       unsigned long num;
+       char string[17];
+       char buf[1000];
+       size_t length = 1000;
+
+       /* SEF local startup. */
+       sef_local_startup();
+
+       /* Subscribe. */
+       r = ds_subscribe(key_u32, DSF_INITIAL);
+       if(r != OK && r != EEXIST) {
+               printf("SUBSCRIBER: error in ds_subscribe: %d\n", r);
+               return -1;
+       }
+
+       while(1) {
+               /* Wait for a message. */
+               r = sef_receive(ANY, &mess);
+               if(r != OK) {
+                       printf("SUBSCRIBER: sef_receive failed.\n");
+                       return 1;
+               }
+               /* Only handle notifications from DS. */
+               if(mess.m_source != DS_PROC_NR)
+                       continue;
+
+               /* Check which one was changed. */
+               r = ds_check(key, &type);
+               if(r == ENOENT) {
+                       printf("SUBSCRIBER: the key %s was deleted.\n",
+                               key);
+                       continue;
+               }
+               if(r != OK) {
+                       printf("SUBSCRIBER: error in ds_check.\n");
+                       continue;
+               }
+
+               /* Retrieve the entry. */
+               printf("SUBSCRIBER: key: %s, ", key);
+               switch(type) {
+               case DSF_TYPE_U32:
+                       r = ds_retrieve_u32(key, &num);
+                       if(r != OK)
+                               printf("error in ds_retrieve_u32.\n");
+                       printf("U32: %d\n", num);
+                       break;
+               case DSF_TYPE_STR:
+                       r = ds_retrieve_str(key, string, 0);
+                       if(r != OK)
+                               printf("error in ds_retrieve_str.\n");
+                       printf("STR: %s\n", string);
+                       break;
+               case DSF_TYPE_MEM:
+                       r = ds_retrieve_mem(key, buf, &length);
+                       if(r != OK)
+                               printf("error in ds_retrieve_mem.\n");
+                       break;
+               case DSF_TYPE_MAP:
+                       break;
+               default:
+                       printf("error in type! %d\n", type);
+               }
+       }
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/ds/system.conf b/test/ds/system.conf
new file mode 100644 (file)
index 0000000..17fba33
--- /dev/null
@@ -0,0 +1,25 @@
+
+service dstest
+{
+       system
+               UMAP
+               PRIVCTL
+               SAFEMAP
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
+
+service subs
+{
+       system
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
diff --git a/test/safecopy/Makefile b/test/safecopy/Makefile
new file mode 100644 (file)
index 0000000..67d7da7
--- /dev/null
@@ -0,0 +1,21 @@
+all: requestor grantor 1fifo 2fifo
+       chmod +x down run
+
+requestor: requestor.c inc.h
+       cc -o $@ $< -lsys
+
+grantor: grantor.c inc.h
+       cc -o $@ $< -lsys
+
+1fifo 2fifo:
+       mkfifo $@
+
+run: all
+       sh run
+
+kill:
+       sh down
+
+clean:
+       rm -f grantor requestor 1fifo 2fifo
+
diff --git a/test/safecopy/README b/test/safecopy/README
new file mode 100644 (file)
index 0000000..bc5da67
--- /dev/null
@@ -0,0 +1,19 @@
+Test Program for Safecopy with or without COW
+
+How to run
+==========
+
+Test safecopy with COW:
+  1. Set USE_COW_SAFECOPY to 1 in /usr/src/kernel/system/do_safecopy.c
+  2. Type `make run` to prepare and run test.
+  3. When done testing, type `make clean` to clean up.
+
+Test safecopy without COW:
+  1. Set USE_COW_SAFECOPY to 0 in /usr/src/kernel/system/do_safecopy.c
+  2. Type `make run` to prepare and run test.
+  3. When done testing, type `make clean` to clean up.
+
+If you want to modify the test buffer size:
+  1. Modify TEST_PAGE_NUM in inc.h
+  2. Modify TEST_PAGE_SHIFT in inc.h
+
diff --git a/test/safecopy/down b/test/safecopy/down
new file mode 100644 (file)
index 0000000..6ca8abe
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+service down grantor
+service down requestor
+
diff --git a/test/safecopy/grantor.c b/test/safecopy/grantor.c
new file mode 100644 (file)
index 0000000..51c700b
--- /dev/null
@@ -0,0 +1,59 @@
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                                 main                                     *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+       endpoint_t ep_self, ep_requestor;
+       int fid_send, fid_get;
+       cp_grant_id_t gid;
+       char *buf;
+       int i;
+
+       /* SEF local startup. */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Prepare work. */
+       buf = (char*) CLICK_CEIL(buf_buf);
+       fid_send = open(FIFO_GRANTOR, O_WRONLY);
+       fid_get = open(FIFO_REQUESTOR, O_RDONLY);
+       if(fid_get < 0 || fid_send < 0) {
+               printf("GRANTOR: can't open fifo files.\n");
+               return 1;
+       }
+       buf[0] = BUF_START;
+
+       /* Get the requestor's endpoint. */
+       read(fid_get, &ep_requestor, sizeof(ep_requestor));
+       dprint("GRANTOR: getting requestor's endpoint: %d\n", ep_requestor);
+
+       /* Grant. */
+       gid = cpf_grant_direct(ep_requestor, (long)buf, BUF_SIZE,
+               CPF_READ | CPF_WRITE);
+       ep_self = getprocnr();
+       dprint("GRANTOR: sending my endpoint %d and gid %d\n", ep_self, gid);
+       write(fid_send, &ep_self, sizeof(ep_self));
+       write(fid_send, &gid, sizeof(gid));
+
+       /* Wait till requestor is done. */
+       FIFO_WAIT(fid_get);
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/safecopy/inc.h b/test/safecopy/inc.h
new file mode 100644 (file)
index 0000000..b737c44
--- /dev/null
@@ -0,0 +1,50 @@
+#define _SYSTEM
+#define _MINIX
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/safecopies.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+/* TEST_PAGE_SHIFT =
+ * log2(CLICK_SIZE * TEST_PAGE_NUM) = CLICK_SHIFT + log2(TEST_PAGE_NUM)
+ */
+#define TEST_PAGE_NUM    8
+#define TEST_PAGE_SHIFT 15
+
+#define BUF_SIZE (TEST_PAGE_NUM * CLICK_SIZE)
+#define BUF_START 100
+
+#define FIFO_REQUESTOR "/usr/src/test/safecopy/1fifo"
+#define FIFO_GRANTOR   "/usr/src/test/safecopy/2fifo"
+
+#define FIFO_WAIT(fid) {                                                      \
+       int a;                                                                \
+       if(read(fid, &a, sizeof(a)) != sizeof(a))                             \
+               panic(__FILE__, "FIFO_WAIT failed", NO_NUM);                  \
+}
+#define FIFO_NOTIFY(fid) {                                                    \
+       int a = 1;                                                            \
+       if(write(fid, &a, sizeof(a)) != sizeof(a))                            \
+               panic(__FILE__, "FIFO_NOTIFY failed", NO_NUM);                \
+}
+
+#define DEBUG 0
+#if DEBUG
+#      define dprint printf
+#else
+#      define dprint (void)
+#endif
+
diff --git a/test/safecopy/requestor.c b/test/safecopy/requestor.c
new file mode 100644 (file)
index 0000000..f57bbf4
--- /dev/null
@@ -0,0 +1,96 @@
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+endpoint_t ep_granter;
+int gid;
+char *buf;
+
+/*===========================================================================*
+ *                                 test                                     *
+ *===========================================================================*/
+int test(size_t size)
+{
+       u32_t low1, high1;
+       u32_t low2, high2;
+       int r;
+
+       /* Timing. */
+       read_tsc(&high1, &low1);
+       r = sys_safecopyfrom(ep_granter, gid, 0, (long)buf, size, D);
+       read_tsc(&high2, &low2);
+       if(r != OK) {
+               printf("REQUESTOR: error in safecopy: %d\n", r);
+               return r;
+       }
+       printf("REQUESTOR: SAFECOPY 0x%-8x - %d\n", size, low2 -  low1);
+
+       /* Test. */
+       if(buf[0] != BUF_START) {
+               printf("REQUESTOR: error in safecopy!\n");
+               printf("        size, value: %d, %d\n", size, buf[0]);
+               return r;
+       }
+
+       return OK;
+}
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                                 main                                     *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+       endpoint_t ep_self;
+       int fid_send, fid_get;
+       int i;
+
+       /* SEF local startup. */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Prepare work. */
+       buf = (char*) CLICK_CEIL(buf_buf);
+       fid_get = open(FIFO_GRANTOR, O_RDONLY);
+       fid_send = open(FIFO_REQUESTOR, O_WRONLY);
+       if(fid_get < 0 || fid_send < 0) {
+               printf("REQUESTOR: can't open fifo files.\n");
+               return 1;
+       }
+
+       /* Sending the endpoint to the granter, in order to let him
+        * create the grant.
+        */
+       ep_self = getprocnr();
+       write(fid_send, &ep_self, sizeof(ep_self));
+       dprint("REQUESTOR: sending my endpoint: %d\n", ep_self);
+
+       /* Getting the granter's endpoint and gid. */
+       read(fid_get, &ep_granter, sizeof(ep_granter));
+       read(fid_get, &gid, sizeof(gid));
+       dprint("REQUESTOR: getting granter's endpoint %d and gid %d\n",
+               ep_granter, gid);
+
+       /* Test SAFECOPY. */
+       for(i = 0; i <= TEST_PAGE_SHIFT; i++) {
+               if(test(1 << i) != OK)
+                       break;
+       }
+
+       /* Notify grantor we are done. */
+       FIFO_NOTIFY(fid_send);
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/safecopy/run b/test/safecopy/run
new file mode 100644 (file)
index 0000000..1067ef7
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+PWD=`pwd`
+
+service up ${PWD}/grantor -config ${PWD}/system.conf -script ${PWD}/down
+service up ${PWD}/requestor -config ${PWD}/system.conf -script ${PWD}/down
+
diff --git a/test/safecopy/system.conf b/test/safecopy/system.conf
new file mode 100644 (file)
index 0000000..57f778f
--- /dev/null
@@ -0,0 +1,34 @@
+
+service requestor
+{
+       system
+               SAFECOPYFROM
+               SAFECOPYTO
+               SAFEMAP
+               SAFEREVMAP
+               SAFEUNMAP
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
+
+service grantor
+{
+       system
+               SAFECOPYFROM
+               SAFECOPYTO
+               SAFEMAP
+               SAFEREVMAP
+               SAFEUNMAP
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
diff --git a/test/safemap/Makefile b/test/safemap/Makefile
new file mode 100644 (file)
index 0000000..67d7da7
--- /dev/null
@@ -0,0 +1,21 @@
+all: requestor grantor 1fifo 2fifo
+       chmod +x down run
+
+requestor: requestor.c inc.h
+       cc -o $@ $< -lsys
+
+grantor: grantor.c inc.h
+       cc -o $@ $< -lsys
+
+1fifo 2fifo:
+       mkfifo $@
+
+run: all
+       sh run
+
+kill:
+       sh down
+
+clean:
+       rm -f grantor requestor 1fifo 2fifo
+
diff --git a/test/safemap/README b/test/safemap/README
new file mode 100644 (file)
index 0000000..a1076a9
--- /dev/null
@@ -0,0 +1,8 @@
+Test Program for Safemap
+
+How to run
+==========
+
+  1. Type `make run` to prepare and run test.
+  2. When done testing, type `make clean` to clean up.
+
diff --git a/test/safemap/down b/test/safemap/down
new file mode 100644 (file)
index 0000000..153041a
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+service down grantor
+service down requestor
diff --git a/test/safemap/grantor.c b/test/safemap/grantor.c
new file mode 100644 (file)
index 0000000..60052e1
--- /dev/null
@@ -0,0 +1,129 @@
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                                 main                                     *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+       endpoint_t ep_self, ep_requestor, ep_child;
+       cp_grant_id_t gid;
+       int i, r, pid;
+       char *buf;
+       int status;
+
+       /* SEF local startup. */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Prepare work. */
+       buf = (char*) CLICK_CEIL(buf_buf);
+       fid_send = open(FIFO_GRANTOR, O_WRONLY);
+       fid_get = open(FIFO_REQUESTOR, O_RDONLY);
+       if(fid_get < 0 || fid_send < 0) {
+               printf("GRANTOR: can't open fifo files.\n");
+               return 1;
+       }
+
+       /* Get the requestor's endpoint. */
+       read(fid_get, &ep_requestor, sizeof(ep_requestor));
+       dprint("GRANTOR: getting requestor's endpoint: %d\n", ep_requestor);
+
+       /* Grant. */
+       gid = cpf_grant_direct(ep_requestor, (long)buf, BUF_SIZE,
+               CPF_READ | CPF_WRITE | CPF_MAP);
+       ep_self = getprocnr();
+       dprint("GRANTOR: sending my endpoint %d and gid %d\n", ep_self, gid);
+       write(fid_send, &ep_self, sizeof(ep_self));
+       write(fid_send, &gid, sizeof(gid));
+
+       /* Test MAP. */
+       buf[0] = BUF_START_GRANTOR;
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("GRANTOR", buf[0], BUF_START_REQUESTOR, "MAP");
+
+       /* Test UNMAP. */
+       buf[0] = BUF_START_GRANTOR;
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR, "UNMAP");
+
+       /* Test REVOKE. */
+       r = sys_saferevmap_gid(gid);
+       if(r != OK) {
+               printf("GRANTOR: error in sys_saferevmap_gid: %d\n", r);
+               return 1;
+       }
+       buf[0] = BUF_START_GRANTOR+1;
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR+1, "REVOKE");
+
+       /* Test SMAP_COW. */
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       buf[0] = BUF_START_GRANTOR;
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR, "SMAP_COW");
+
+       /* Test COW_SMAP. */
+       r = sys_saferevmap_gid(gid);
+       if(r != OK) {
+               printf("GRANTOR: error in sys_saferevmap_gid: %d\n", r);
+               return 1;
+       }
+       buf[0] = BUF_START_GRANTOR+1;
+       pid = fork();
+       if(pid < 0) {
+               printf("GRANTOR: error in fork.\n");
+               return 1;
+       }
+       if(pid == 0) {
+               buf[0] = BUF_START_GRANTOR+2;
+               exit(0);
+       }
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       ep_child = getnprocnr(pid);
+       if ((r = sys_privctl(ep_child, SYS_PRIV_SET_USER, NULL)) != OK) {
+               printf("GRANTOR: unable to set privileges: %d\n", r);
+               return 1;
+       }
+       if ((r = sys_privctl(ep_child, SYS_PRIV_ALLOW, NULL)) != OK) {
+               printf("GRANTOR: child process can't run: %d\n", r);
+               return 1;
+       }
+       wait(&status);
+       FIFO_NOTIFY(fid_send);
+       CHECK_TEST("GRANTOR", buf[0], BUF_START_GRANTOR+1, "COW_SMAP");
+
+       /* Test COW_SMAP2 (with COW safecopy). */
+       r = sys_saferevmap_gid(gid);
+       if(r != OK) {
+               printf("GRANTOR: error in sys_saferevmap_gid: %d\n", r);
+               return 1;
+       }
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("GRANTOR", buf[0], BUF_START_REQUESTOR, "COW_SMAP2");
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/safemap/inc.h b/test/safemap/inc.h
new file mode 100644 (file)
index 0000000..32ef9c6
--- /dev/null
@@ -0,0 +1,54 @@
+#define _SYSTEM
+#define _MINIX
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/safecopies.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+#define TEST_PAGE_NUM    4
+#define BUF_SIZE (TEST_PAGE_NUM * CLICK_SIZE)
+#define BUF_START_REQUESTOR 10
+#define BUF_START_GRANTOR   20
+
+#define FIFO_REQUESTOR "/usr/src/test/safemap/1fifo"
+#define FIFO_GRANTOR   "/usr/src/test/safemap/2fifo"
+
+#define FIFO_WAIT(fid) {                                                      \
+       int a;                                                                \
+       if(read(fid, &a, sizeof(a)) != sizeof(a))                             \
+               panic(__FILE__, "FIFO_WAIT failed", NO_NUM);                  \
+}
+#define FIFO_NOTIFY(fid) {                                                    \
+       int a = 1;                                                            \
+       if(write(fid, &a, sizeof(a)) != sizeof(a))                            \
+               panic(__FILE__, "FIFO_NOTIFY failed", NO_NUM);                \
+}
+
+#define CHECK_TEST(who, result, expected, test_name) {                        \
+       printf("%-9s: test %s %s\n", who, test_name,                          \
+               (expected == result ? "succeeded" : "failed"));               \
+       if(expected != result) {                                              \
+               exit(1);                                                      \
+       }                                                                     \
+}
+
+#define DEBUG 0
+#if DEBUG
+#      define dprint printf
+#else
+#      define dprint (void)
+#endif
+
diff --git a/test/safemap/requestor.c b/test/safemap/requestor.c
new file mode 100644 (file)
index 0000000..89773c1
--- /dev/null
@@ -0,0 +1,153 @@
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+endpoint_t ep_granter;
+cp_grant_id_t gid;
+char *buf;
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                                 main                                     *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+       endpoint_t ep_self, ep_child;
+       size_t size = BUF_SIZE;
+       int i, r, pid;
+       int status;
+
+       /* SEF local startup. */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Prepare work. */
+       buf = (char*) CLICK_CEIL(buf_buf);
+       fid_get = open(FIFO_GRANTOR, O_RDONLY);
+       fid_send = open(FIFO_REQUESTOR, O_WRONLY);
+       if(fid_get < 0 || fid_send < 0) {
+               printf("REQUESTOR: can't open fifo files.\n");
+               return 1;
+       }
+
+       /* Send the endpoint to the granter, in order to let him to
+        * create the grant.
+        */
+       ep_self = getprocnr();
+       write(fid_send, &ep_self, sizeof(ep_self));
+       dprint("REQUESTOR: sending my endpoint: %d\n", ep_self);
+
+       /* Get the granter's endpoint and gid. */
+       read(fid_get, &ep_granter, sizeof(ep_granter));
+       read(fid_get, &gid, sizeof(gid));
+       dprint("REQUESTOR: getting granter's endpoint %d and gid %d\n",
+               ep_granter, gid);
+
+       /* Test MAP. */
+       FIFO_WAIT(fid_get);
+       r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+       if(r != OK) {
+               printf("REQUESTOR: error in sys_safemap: %d\n", r);
+               return 1;
+       }
+       CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR, "MAP");
+       buf[0] = BUF_START_REQUESTOR;
+       r = sys_safeunmap(D, (long)buf);
+       if(r != OK) {
+               printf("REQUESTOR: error in sys_safeunmap: %d\n", r);
+               return 1;
+       }
+       FIFO_NOTIFY(fid_send);
+
+       /* Test UNMAP. */
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("REQUESTOR", buf[0], BUF_START_REQUESTOR, "UNMAP");
+       r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+       if(r != 0) {
+               printf("REQUESTOR: error in sys_safemap: %d\n", r);
+               return 1;
+       }
+       FIFO_NOTIFY(fid_send);
+
+       /* Test REVOKE. */
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR, "REVOKE");
+       buf[0] = BUF_START_REQUESTOR;
+       FIFO_NOTIFY(fid_send);
+
+       /* Test SMAP_COW. */
+       FIFO_WAIT(fid_get);
+       r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+       if(r != OK) {
+               printf("REQUESTOR: error in sys_safemap: %d\n", r);
+               return 1;
+       }
+       buf[0] = BUF_START_REQUESTOR;
+       pid = fork();
+       if(pid < 0) {
+               printf("REQUESTOR: error in fork\n");
+               return 1;
+       }
+       if(pid == 0) {
+               exit(buf[0] != BUF_START_REQUESTOR);
+       }
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       ep_child = getnprocnr(pid);
+       if ((r = sys_privctl(ep_child, SYS_PRIV_SET_USER, NULL)) != OK) {
+               printf("REQUESTOR: unable to set privileges: %d\n", r);
+               return 1;
+       }
+       if ((r = sys_privctl(ep_child, SYS_PRIV_ALLOW, NULL)) != OK) {
+               printf("REQUESTOR: child process can't run: %d\n", r);
+               return 1;
+       }
+       wait(&status);
+       FIFO_NOTIFY(fid_send);
+       CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR, "SMAP_COW");
+       CHECK_TEST("REQUESTOR", 1, WIFEXITED(status)
+               && (WEXITSTATUS(status) == 0), "SMAP_COW child");
+
+       /* Test COW_SMAP. */
+       FIFO_WAIT(fid_get);
+       buf[0] = BUF_START_REQUESTOR;
+       r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+       if(r != OK) {
+               printf("REQUESTOR: error in sys_safemap: %d\n", r);
+               return 1;
+       }
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+       CHECK_TEST("REQUESTOR", buf[0], BUF_START_GRANTOR+1, "COW_SMAP");
+
+       /* Test COW_SMAP2 (with COW safecopy). */
+       FIFO_WAIT(fid_get);
+       buf[0] = BUF_START_REQUESTOR;
+       r = sys_safecopyto(ep_granter, gid, 0, (long)buf, size, D);
+       if(r != OK) {
+               printf("REQUESTOR: error in sys_safecopyto: %d\n", r);
+               return 1;
+       }
+       r = sys_safemap(ep_granter, gid, 0, (long)buf, size, D, 1);
+       if(r != OK) {
+               printf("REQUESTOR: error in sys_safemap: %d\n", r);
+               return 1;
+       }
+       FIFO_NOTIFY(fid_send);
+       CHECK_TEST("REQUESTOR", buf[0], BUF_START_REQUESTOR, "COW_SMAP2");
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/safemap/run b/test/safemap/run
new file mode 100644 (file)
index 0000000..b5600e0
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+PWD=`pwd`
+
+service up ${PWD}/grantor -config ${PWD}/system.conf -script ${PWD}/down
+service up ${PWD}/requestor -config ${PWD}/system.conf -script ${PWD}/down
diff --git a/test/safemap/system.conf b/test/safemap/system.conf
new file mode 100644 (file)
index 0000000..57f778f
--- /dev/null
@@ -0,0 +1,34 @@
+
+service requestor
+{
+       system
+               SAFECOPYFROM
+               SAFECOPYTO
+               SAFEMAP
+               SAFEREVMAP
+               SAFEUNMAP
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
+
+service grantor
+{
+       system
+               SAFECOPYFROM
+               SAFECOPYTO
+               SAFEMAP
+               SAFEREVMAP
+               SAFEUNMAP
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
diff --git a/test/safeperf/Makefile b/test/safeperf/Makefile
new file mode 100644 (file)
index 0000000..67d7da7
--- /dev/null
@@ -0,0 +1,21 @@
+all: requestor grantor 1fifo 2fifo
+       chmod +x down run
+
+requestor: requestor.c inc.h
+       cc -o $@ $< -lsys
+
+grantor: grantor.c inc.h
+       cc -o $@ $< -lsys
+
+1fifo 2fifo:
+       mkfifo $@
+
+run: all
+       sh run
+
+kill:
+       sh down
+
+clean:
+       rm -f grantor requestor 1fifo 2fifo
+
diff --git a/test/safeperf/README b/test/safeperf/README
new file mode 100644 (file)
index 0000000..a2d345a
--- /dev/null
@@ -0,0 +1,11 @@
+Performance Test Program for Safecopy and Safemap
+
+How to run
+==========
+
+  1. Set USE_COW_SAFECOPY to 1 or 0 in kernel/system/do_safecopy.c
+     to run safecopy tests with or without COW optimization.
+  2. Type `make run` to prepare and run tests. Configuration parameters
+     for performance tests are in ./run.
+  3. When done testing, type `make clean` to clean up.
+
diff --git a/test/safeperf/down b/test/safeperf/down
new file mode 100644 (file)
index 0000000..6ca8abe
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+service down grantor
+service down requestor
+
diff --git a/test/safeperf/grantor.c b/test/safeperf/grantor.c
new file mode 100644 (file)
index 0000000..2a2e908
--- /dev/null
@@ -0,0 +1,62 @@
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                                 main                                     *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+       endpoint_t ep_self, ep_requestor, ep_child;
+       cp_grant_id_t gid;
+       int i, r, pid;
+       char *buf;
+       int status;
+
+       /* SEF local startup. */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Prepare work. */
+       buf = (char*) CLICK_CEIL(buf_buf);
+       fid_send = open(FIFO_GRANTOR, O_WRONLY);
+       fid_get = open(FIFO_REQUESTOR, O_RDONLY);
+       if(fid_get < 0 || fid_send < 0) {
+               printf("GRANTOR: can't open fifo files.\n");
+               return 1;
+       }
+
+       /* Get the requestor's endpoint. */
+       read(fid_get, &ep_requestor, sizeof(ep_requestor));
+       dprint("GRANTOR: getting requestor's endpoint: %d\n", ep_requestor);
+
+       /* Grant. */
+       gid = cpf_grant_direct(ep_requestor, (long)buf, BUF_SIZE,
+               CPF_READ | CPF_WRITE | CPF_MAP);
+       ep_self = getprocnr();
+       dprint("GRANTOR: sending my endpoint %d and gid %d\n", ep_self, gid);
+       write(fid_send, &ep_self, sizeof(ep_self));
+       write(fid_send, &gid, sizeof(gid));
+
+       /* Test safemap. */
+       buf[0] = 0;
+       FIFO_NOTIFY(fid_send);
+       FIFO_WAIT(fid_get);
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/safeperf/inc.h b/test/safeperf/inc.h
new file mode 100644 (file)
index 0000000..893f29e
--- /dev/null
@@ -0,0 +1,51 @@
+#define _SYSTEM
+#define _MINIX
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <minix/config.h>
+#include <minix/com.h>
+#include <minix/type.h>
+#include <minix/const.h>
+#include <minix/endpoint.h>
+#include <minix/safecopies.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+#define TEST_PAGE_NUM    50
+#define BUF_SIZE (TEST_PAGE_NUM * CLICK_SIZE)
+
+#define NR_TEST_ITERATIONS 100
+
+#define FIFO_REQUESTOR "/usr/src/test/safeperf/1fifo"
+#define FIFO_GRANTOR   "/usr/src/test/safeperf/2fifo"
+
+#define FIFO_WAIT(fid) {                                                      \
+       int a;                                                                \
+       if(read(fid, &a, sizeof(a)) != sizeof(a))                             \
+               panic(__FILE__, "FIFO_WAIT failed", NO_NUM);                  \
+}
+#define FIFO_NOTIFY(fid) {                                                    \
+       int a = 1;                                                            \
+       if(write(fid, &a, sizeof(a)) != sizeof(a))                            \
+               panic(__FILE__, "FIFO_NOTIFY failed", NO_NUM);                \
+}
+
+#define REPORT_TEST(who, test_name, diff) {                                   \
+       printf("%-9s: test %s took an average of %d.%dus per page\n",         \
+           who, test_name, (int)diff, ((int)(diff*1000))%1000);              \
+}
+
+#define DEBUG 0
+#if DEBUG
+#      define dprint printf
+#else
+#      define dprint (void)
+#endif
+
diff --git a/test/safeperf/requestor.c b/test/safeperf/requestor.c
new file mode 100644 (file)
index 0000000..f348aae
--- /dev/null
@@ -0,0 +1,166 @@
+#include "inc.h"
+
+char buf_buf[BUF_SIZE + CLICK_SIZE];
+
+endpoint_t ep_granter;
+cp_grant_id_t gid;
+char *buf;
+int fid_send, fid_get;
+
+/* SEF functions and variables. */
+FORWARD _PROTOTYPE( void sef_local_startup, (void) );
+
+/*===========================================================================*
+ *                           read_write_buff                                *
+ *===========================================================================*/
+void read_write_buff(char* buff, int size, int is_write)
+{
+       int i;
+       char c;
+
+       if(size % CLICK_SIZE != 0) {
+               panic("REQUESTOR", "buff_size not page aligned", NO_NUM);
+       }
+       if(is_write) {
+           for(i=0;i<size;i+=CLICK_SIZE) buff[i] = 1;
+       }
+       else {
+           for(i=0;i<size;i+=CLICK_SIZE) c = buff[i];
+       }
+}
+
+/*===========================================================================*
+ *                              exit_usage                                  *
+ *===========================================================================*/
+void exit_usage(void)
+{
+       printf("Usage: requestor pages=<nr_pages> map=<0|1> write=<0|1>\n");
+       exit(1);
+}
+
+/*===========================================================================*
+ *                                 main                                     *
+ *===========================================================================*/
+int main(int argc, char **argv)
+{
+       endpoint_t ep_self, ep_child;
+       size_t size = BUF_SIZE;
+       int i, r, pid;
+       int status;
+       u64_t start, end, diff;
+       double micros;
+       char nr_pages_str[10], is_map_str[2], is_write_str[2];
+       int nr_pages, is_map, is_write;
+
+       /* SEF local startup. */
+       env_setargs(argc, argv);
+       sef_local_startup();
+
+       /* Parse the command line. */
+       r = env_get_param("pages", nr_pages_str, sizeof(nr_pages_str));
+       errno = 0;
+       nr_pages = atoi(nr_pages_str);
+       if (r != OK || errno || nr_pages <=0) {
+               exit_usage();
+       }
+       if(nr_pages > TEST_PAGE_NUM) {
+               printf("REQUESTOR: too many pages. Max allowed: %d\n",
+                       TEST_PAGE_NUM);
+               exit_usage();
+       }
+       r = env_get_param("map", is_map_str, sizeof(is_map_str));
+       errno = 0;
+       is_map = atoi(is_map_str);
+       if (r != OK || errno || (is_map!=0 && is_map!=1)) {
+               exit_usage();
+       }
+       r = env_get_param("write", is_write_str, sizeof(is_write_str));
+       errno = 0;
+       is_write = atoi(is_write_str);
+       if (r != OK || errno || (is_write!=0 && is_write!=1)) {
+               exit_usage();
+       }
+       printf("REQUESTOR: Running tests with pages=%d map=%d write=%d...\n",
+               nr_pages, is_map, is_write);
+
+       /* Prepare work. */
+       buf = (char*) CLICK_CEIL(buf_buf);
+       fid_get = open(FIFO_GRANTOR, O_RDONLY);
+       fid_send = open(FIFO_REQUESTOR, O_WRONLY);
+       if(fid_get < 0 || fid_send < 0) {
+               printf("REQUESTOR: can't open fifo files.\n");
+               return 1;
+       }
+
+       /* Send the endpoint to the granter, in order to let him to
+        * create the grant.
+        */
+       ep_self = getprocnr();
+       write(fid_send, &ep_self, sizeof(ep_self));
+       dprint("REQUESTOR: sending my endpoint: %d\n", ep_self);
+
+       /* Get the granter's endpoint and gid. */
+       read(fid_get, &ep_granter, sizeof(ep_granter));
+       read(fid_get, &gid, sizeof(gid));
+       dprint("REQUESTOR: getting granter's endpoint %d and gid %d\n",
+               ep_granter, gid);
+
+       FIFO_WAIT(fid_get);
+       diff = make64(0, 0);
+
+       if(is_map) {
+               /* Test safemap. */
+               for(i=0;i<NR_TEST_ITERATIONS;i++) {
+                       read_tsc_64(&start);
+                       r = sys_safemap(ep_granter, gid, 0, (long)buf,
+                               nr_pages*CLICK_SIZE, D, 1);
+                       if(r != OK) {
+                               printf("REQUESTOR: safemap error: %d\n", r);
+                               return 1;
+                       }
+                       read_write_buff(buf, nr_pages*CLICK_SIZE, is_write);
+                       read_tsc_64(&end);
+                       diff = add64(diff, (sub64(end, start)));
+                       r = sys_safeunmap(D, (long)buf);
+                       if(r != OK) {
+                               printf("REQUESTOR: safeunmap error: %d\n", r);
+                               return 1;
+                       }
+               }
+               micros = ((double)tsc_64_to_micros(diff))
+                       / (NR_TEST_ITERATIONS*nr_pages);
+               REPORT_TEST("REQUESTOR", "SAFEMAP", micros);
+       }
+       else {
+               /* Test safecopy. */
+               for(i=0;i<NR_TEST_ITERATIONS;i++) {
+                       read_tsc_64(&start);
+                       r = sys_safecopyfrom(ep_granter, gid, 0, (long)buf,
+                               nr_pages*CLICK_SIZE, D);
+                       if(r != OK) {
+                               printf("REQUESTOR: safecopy error: %d\n", r);
+                               return 1;
+                       }
+                       read_write_buff(buf, nr_pages*CLICK_SIZE, is_write);
+                       read_tsc_64(&end);
+                       diff = add64(diff, (sub64(end, start)));
+               }
+               micros = ((double)tsc_64_to_micros(diff))
+                       / (NR_TEST_ITERATIONS*nr_pages);
+               REPORT_TEST("REQUESTOR", "SAFECOPY", micros);
+       }
+
+       FIFO_NOTIFY(fid_send);
+
+       return 0;
+}
+
+/*===========================================================================*
+ *                            sef_local_startup                             *
+ *===========================================================================*/
+PRIVATE void sef_local_startup()
+{
+  /* Let SEF perform startup. */
+  sef_startup();
+}
+
diff --git a/test/safeperf/run b/test/safeperf/run
new file mode 100644 (file)
index 0000000..faf8408
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+PAGES="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50"
+MAP=0
+WRITE=1
+
+PWD=`pwd`
+
+for P in `echo $PAGES`
+do
+  service up ${PWD}/grantor -config ${PWD}/system.conf -script ${PWD}/down
+  service up ${PWD}/requestor -config ${PWD}/system.conf -script ${PWD}/down \
+               -args pages=${P}\ map=${MAP}\ write=${WRITE}
+  sleep 2
+done
+
diff --git a/test/safeperf/system.conf b/test/safeperf/system.conf
new file mode 100644 (file)
index 0000000..57f778f
--- /dev/null
@@ -0,0 +1,34 @@
+
+service requestor
+{
+       system
+               SAFECOPYFROM
+               SAFECOPYTO
+               SAFEMAP
+               SAFEREVMAP
+               SAFEUNMAP
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};
+
+service grantor
+{
+       system
+               SAFECOPYFROM
+               SAFECOPYTO
+               SAFEMAP
+               SAFEREVMAP
+               SAFEUNMAP
+               UMAP
+               PRIVCTL
+               SETGRANT
+               GETINFO
+               SYSCTL
+       ;
+       uid     0;
+};