bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] shmfs: A System V shared memory filesystem


From: Neal H Walfield
Subject: [PATCH] shmfs: A System V shared memory filesystem
Date: Tue, 1 May 2001 17:37:30 +0200
User-agent: Mutt/1.3.15i

This patch adds a shared memory filesystem to the Hurd based on the
recently proposed interface.  This code is based off of tmpfs.  It
allows conformance to SUSv2 except where noted (and where I have made
mistakes).

I have made the assumption that standard conformance will occur in libc
and, as such, have only provided the mechanisms to do so.  Here are the
known limitations:

  o  We cannot get the pid of the creating process or the processes
     doing operations.
  o  Since we pass a memory object port to a processes when it wishes to
     map in a shared memory segment, we have no way to determine when
     the detach happens, nor, to correctly update shmid_ds->shm_nattch.
     Additionally, due to this behavior, we have no way to preserve the
     shmid_ds until all processes have detached.
  o  The bugs in tmpfs, i.e. if you resize a file too quickly, it
     crashes.  This, however, is not actually a problem as, in the
     normal case, shared memory cannot be resized.

When extracted, this patch also creates a directory named shmfs-tests.
In that directory, you will find:

  o a file named shm.c.
      - This provides implementations of shmget, shmat, shmctl and
        shmdt.
      - I envision code similar to this eventually going into glibc.
      - Adding code to implement shmopen and shmunlink will be trivial.
  o ipcs and ipcrm
      - SUSv2 conforming (as far as I can tell).
      - I expect that this code will, eventually, go into hurd/utils.
  o several test programs
      - I did most of my debugging using gdb as a shell, so these
        programs, by themselves, do not fully exercise the code.

Here is a run of the test programs:

Script started on Tue May  1 14:55:34 200
neal@hurd:~/build/shmfs-tests (0)$ ./get 0 4096 600
1
neal@hurd:~/build/shmfs-tests (0)$ ./get 100 4096 600
./get: shmget: No such file or directory
neal@hurd:~/build/shmfs-tests (1)$ ./get 100 4096 1600
2
neal@hurd:~/build/shmfs-tests (0)$ ./get 100 4096 3600
./get: shmget: File exists
neal@hurd:~/build/shmfs-tests (1)$ ./get 100 0 0
2
neal@hurd:~/build/shmfs-tests (0)$ ./ipcs -m 
IPC status from hurd:/var/run/sysvshm as of Tue May  1 14:56:51 2001
Shared Memory:
T ID       KEY          MODE        OWNER    GROUP    
m 1        0x0          --rw------- neal     neal     
m 2        0x64         --rw------- neal     neal     
neal@hurd:~/build/shmfs-tests (0)$ ./write 1 Foo
neal@hurd:~/build/shmfs-tests (0)$ ./write 2 Bar
neal@hurd:~/build/shmfs-tests (0)$ ./read 2 
Bar
neal@hurd:~/build/shmfs-tests (0)$ ./read 1
Foo
neal@hurd:~/build/shmfs-tests (0)$ ./read 2
Bar
neal@hurd:~/build/shmfs-tests (0)$ rmauth --pid=$$ neal
neal@hurd:~/build/shmfs-tests (0)$ ./read 1
./read: shmat: Permission denied
neal@hurd:~/build/shmfs-tests (1)$ ./read 2
./read: shmat: Permission denied
neal@hurd:~/build/shmfs-tests (1)$ addauth --pid=$$ neal
neal@hurd:~/build/shmfs-tests (0)$ ./read 1
Foo
neal@hurd:~/build/shmfs-tests (0)$ ./ipcs -m -a
IPC status from hurd:/var/run/sysvshm as of Tue May  1 14:57:53 2001
Shared Memory:
T ID       KEY          MODE        OWNER    GROUP    CREATOR  CGROUP   NATTCH  
SEGSZ    CPID     LPID     ATIME     CTIME
m 1        0x0          --rw------- neal     neal     neal     neal     1       
4096    0        0       14:57:44  no-entry
m 2        0x64         --rw------- neal     neal     neal     neal     1       
4096    0        0       14:57:19  no-entry
neal@hurd:~/build/shmfs-tests (0)$ ./ipcrm -m 1
neal@hurd:~/build/shmfs-tests (0)$ ./ipcs
IPC status from hurd:/var/run/sysvshm as of Tue May  1 14:58:22 2001
neal@hurd:~/build/shmfs-tests (0)$ ./ipcs -m -a
IPC status from hurd:/var/run/sysvshm as of Tue May  1 14:58:27 2001
Shared Memory:
T ID       KEY          MODE        OWNER    GROUP    CREATOR  CGROUP   NATTCH  
SEGSZ    CPID     LPID     ATIME     CTIME
m 2        0x64         --rw------- neal     neal     neal     neal     1       
4096    0        0       14:57:19  no-entry
neal@hurd:~/build/shmfs-tests (0)$ ./ipcrm -m 2
neal@hurd:~/build/shmfs-tests (0)$ ./ipcs -m -q -s
IPC status from hurd:/var/run/sysvshm as of Tue May  1 14:59:04 2001
Message queues facility not in system.
Shared Memory:
T ID       KEY          MODE        OWNER    GROUP    
Semaphore facility not in system.
neal@hurd:~/build/shmfs-tests (5)$ exit

Script done on Tue May  1 14:59:08 200

Here, are the change logs:

2001-05-01  Neal H Walfield  <neal@cs.uml.edu>

        * Makefile: New file.  Derived from tmpfs.
        * dir.c: Likewise.
        * node.c: Likewise.
        * pager-stubs.c: Likewise.
        * shmfs.c: New file.  Derived from tmpfs/tmpfs.c.
        * shmfs.h: New file.  Derived from tmpfs/tmpfs.h.
        * demuxer.c: New file.
        * fsmutations.h: New file.
        * keymap.c: New file.
        * keymap.h: New file.
        * mig.h: New file.
        * shm.c : New file.
        * ChangeLog: New file mentioning itself in this sentence.


2001-05-01  Neal H Walfield <neal@cs.uml.edu>

        * Makefile: New file.
        * get.c: New file.
        * ipcrm.c: New file.
        * ipcs.c: New file.
        * read.c: New file.
        * shm.c: New file.
        * write.c: New file.
        * ChangeLog: New file mentioning itself in this sentence.

And, finally, the patch:

Index: hurd/shmfs/Makefile
diff -u /dev/null hurd/shmfs/Makefile:1.1.2.2
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/Makefile Tue Apr 24 19:37:59 2001
@@ -0,0 +1,33 @@
+# Makefile for shmfs
+#
+#   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+#
+#   This program is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU General Public License as
+#   published by the Free Software Foundation; either version 2, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := shmfs
+makemode := server
+
+target = shmfs
+SRCS = shmfs.c node.c dir.c pager-stubs.c shm.c keymap.c demuxer.c
+MIGSTUBS = sysvshmServer.o
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+LCLHDRS = shmfs.h keymap.h mig.h
+# XXX The shared libdiskfs requires libstore even though we don't use it here.
+HURDLIBS = diskfs pager iohelp fshelp store threads ports ihash shouldbeinlibc
+
+sysvshm-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
+MIGCOMSFLAGS = -prefix shmfs_
+
+include ../Makeconf
Index: hurd/shmfs/demuxer.c
diff -u /dev/null hurd/shmfs/demuxer.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/demuxer.c        Tue May  1 14:17:28 2001
@@ -0,0 +1,33 @@
+/* Demultiplexer for shmfs
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "sysvshm_S.h"
+#include <hurd/diskfs.h>
+
+int
+shmfs_demuxer (mach_msg_header_t *inp,
+              mach_msg_header_t *outp)
+{
+  int shmfs_sysvshm_server (mach_msg_header_t *, mach_msg_header_t *);
+  
+  return (diskfs_demuxer (inp, outp)
+         || shmfs_sysvshm_server (inp, outp));
+}
+
+  
Index: hurd/shmfs/dir.c
diff -u /dev/null hurd/shmfs/dir.c:1.1.2.3
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/dir.c    Tue May  1 14:17:29 2001
@@ -0,0 +1,298 @@
+/* Directories for shmfs.
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "shmfs.h"
+#include "keymap.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+error_t
+diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred)
+{
+  dp->dn->u.dir.dotdot = pdp->dn;
+  dp->dn->u.dir.entries = 0;
+  return 0;
+}
+
+error_t
+diskfs_clear_directory (struct node *dp, struct node *pdp,
+                       struct protid *cred)
+{
+  if (dp->dn->u.dir.entries != 0)
+    return ENOTEMPTY;
+  assert (dp->dn_stat.st_size == 0);
+  assert (dp->dn->u.dir.dotdot == pdp->dn);
+  return 0;
+}
+
+int
+diskfs_dirempty (struct node *dp, struct protid *cred)
+{
+  return dp->dn->u.dir.entries == 0;
+}
+
+error_t
+diskfs_get_directs (struct node *dp, int entry, int n,
+                   char **data, u_int *datacnt,
+                   vm_size_t bufsiz, int *amt)
+{
+  struct shmfs_dirent *d;
+  struct dirent *entp;
+  int i;
+
+  assert (offsetof (struct shmfs_dirent, name)
+         >= offsetof (struct dirent, d_name));
+
+  if (bufsiz == 0)
+    bufsiz = dp->dn_stat.st_size
+            + 2 * ((offsetof (struct dirent, d_name[3]) + 7) & ~7);
+  if (bufsiz > *datacnt)
+    {
+      *data = mmap (0, bufsiz, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+      if (*data == MAP_FAILED)
+       return ENOMEM;
+    }
+
+  /* We always synthesize the first two entries (. and ..) on the fly.  */
+  entp = (struct dirent *) *data;
+  i = 0;
+  if (i++ >= entry)
+    {
+      entp->d_fileno = dp->dn_stat.st_ino;
+      entp->d_type = DT_DIR;
+      entp->d_namlen = 1;
+      entp->d_name[0] = '.';
+      entp->d_name[1] = '\0';
+      entp->d_reclen = (&entp->d_name[2] - (char *) entp + 7) & ~7;
+      entp = (void *) entp + entp->d_reclen;
+    }
+  if (i++ >= entry)
+    {
+      if (dp->dn->u.dir.dotdot == 0)
+       {
+         assert (dp == diskfs_root_node);
+         /* Use something not zero and not an st_ino value for any node in
+            this filesystem.  Since we use pointer values, 2 will never
+            be a valid number.  */
+         entp->d_fileno = 2;
+       }
+      else
+       entp->d_fileno = (ino_t) dp->dn->u.dir.dotdot;
+      entp->d_type = DT_DIR;
+      entp->d_namlen = 2;
+      entp->d_name[0] = '.';
+      entp->d_name[1] = '.';
+      entp->d_name[2] = '\0';
+      entp->d_reclen = (&entp->d_name[3] - (char *) entp + 7) & ~7;
+      entp = (void *) entp + entp->d_reclen;
+    }
+
+  /* Skip ahead to the desired entry.  */
+  for (d = dp->dn->u.dir.entries; i < entry && d != 0; d = d->next)
+    ++i;
+
+  if (i < entry)
+    {
+      assert (d == 0);
+      *datacnt = 0;
+      *amt = 0;
+      return 0;
+    }
+
+  /* Now fill in the buffer with real entries.  */
+  for (; d != 0; d = d->next, i++)
+    {
+      size_t rlen = (offsetof (struct dirent, d_name[1]) + d->namelen + 7) & 
~7;
+      if (rlen + (char *) entp - *data > bufsiz || (n >= 0 && i > n))
+       break;
+      entp->d_fileno = (ino_t) d->dn;
+      entp->d_type = DT_UNKNOWN;
+      entp->d_namlen = d->namelen;
+      memcpy (entp->d_name, d->name, d->namelen + 1);
+      entp->d_reclen = rlen;
+      entp = (void *) entp + rlen;
+    }
+
+  *datacnt = (char *) entp - *data;
+  *amt = i - entry;
+
+  return 0;
+}
+
+const size_t diskfs_dirstat_size = sizeof (struct dirstat);
+
+void
+diskfs_null_dirstat (struct dirstat *ds)
+{
+  ds->prevp = 0;
+}
+
+error_t
+diskfs_drop_dirstat (struct node *dp, struct dirstat *ds)
+{
+  /* No need to clear the pointers.  */
+  return 0;
+}
+
+error_t
+diskfs_lookup_hard (struct node *dp,
+                   const char *name, enum lookup_type type,
+                   struct node **np, struct dirstat *ds,
+                   struct protid *cred)
+{
+  const size_t namelen = strlen (name);
+  struct shmfs_dirent *d, **prevp;
+
+  if (type == REMOVE || type == RENAME)
+    assert (np);
+
+  if (namelen == 1 && name[0] == '.')
+    {
+      if (np != 0)
+       {
+         *np = dp;
+         diskfs_nref (dp);
+       }
+      return 0;
+    }
+  if (namelen == 2 && name[0] == '.' && name[1] == '.')
+    {
+      struct disknode *dddn = dp->dn->u.dir.dotdot;
+      error_t err;
+
+      assert (np != 0);
+      if (dddn == 0)           /* root directory */
+       return EAGAIN;
+
+      if (type == (REMOVE|SPEC_DOTDOT) || type == (RENAME|SPEC_DOTDOT))
+        {
+         *np = *dddn->hprevp;
+         assert (*np);
+         assert ((*np)->dn == dddn);
+         assert (*dddn->hprevp == *np);
+         return 0;
+       }
+      else
+        {
+         mutex_unlock (&dp->lock);
+          err = diskfs_cached_lookup ((int) dddn, np);
+
+         if (type == (LOOKUP|SPEC_DOTDOT))
+           diskfs_nrele (dp);
+         else
+           mutex_lock (&dp->lock);
+
+         if (err)
+           *np = 0;
+
+          return err;
+       }
+    }
+
+  for (d = *(prevp = &dp->dn->u.dir.entries); d != 0;
+       d = *(prevp = &d->next))
+    if (d->namelen == namelen && !memcmp (d->name, name, namelen))
+      {
+       if (ds)
+         ds->prevp = prevp;
+
+       if (np)
+         return diskfs_cached_lookup ((ino_t) d->dn, np);
+       else
+         return 0;
+      }
+
+  if (ds)
+    ds->prevp = prevp;
+  if (np)
+    *np = 0;
+  return ENOENT;
+}
+
+
+error_t
+diskfs_direnter_hard (struct node *dp, const char *name,
+                     struct node *np, struct dirstat *ds,
+                     struct protid *cred)
+{
+  const size_t namelen = strlen (name);
+  const size_t entsize
+         = (offsetof (struct dirent, d_name[1]) + namelen + 7) & ~7;
+  struct shmfs_dirent *new;
+
+  if (round_page (shmfs_space_used + entsize) / vm_page_size
+      > shmfs_page_limit)
+    return ENOSPC;
+
+  new = malloc (entsize);
+  if (new == 0)
+    return ENOSPC;
+
+  new->next = 0;
+  new->dn = np->dn;
+  new->namelen = namelen;
+  memcpy (new->name, name, namelen + 1);
+  *ds->prevp = new;
+
+  dp->dn_stat.st_size += entsize;
+  adjust_used (entsize);
+
+  dp->dn_stat.st_blocks = ((sizeof *dp->dn + dp->dn->translen
+                           + dp->dn_stat.st_size + 511)
+                          / 512);
+  return 0;
+}
+
+error_t
+diskfs_dirrewrite_hard (struct node *dp, struct node *np,
+                       struct dirstat *ds)
+{
+  (*ds->prevp)->dn = np->dn;
+  if (np->dn->type == DT_REG)
+    drop_shmid (np->dn);
+  return 0;
+}
+
+error_t
+diskfs_dirremove_hard (struct node *dp, struct dirstat *ds)
+{
+  struct shmfs_dirent *d = *ds->prevp;
+  const size_t entsize
+         = (offsetof (struct dirent, d_name[1]) + d->namelen + 7) & ~7;
+
+  *ds->prevp = d->next;
+
+  if (dp->dirmod_reqs != 0)
+    diskfs_notice_dirchange (dp, DIR_CHANGED_UNLINK, d->name);
+
+  if (d->dn->type == DT_REG)
+    drop_shmid (d->dn);
+
+  free (d);
+
+  adjust_used (-entsize);
+  dp->dn_stat.st_size -= entsize;
+  dp->dn_stat.st_blocks = ((sizeof *dp->dn + dp->dn->translen
+                           + dp->dn_stat.st_size + 511)
+                          / 512);
+
+  return 0;
+}
Index: hurd/shmfs/fsmutations.h
diff -u /dev/null hurd/shmfs/fsmutations.h:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/fsmutations.h    Tue May  1 14:17:29 2001
@@ -0,0 +1,24 @@
+/* 
+   Copyright (C) 2001 Free Software Foundation
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Only CPP macro definitions should go in this file. */
+
+#define SYSVSHM_INTRAN protid_t diskfs_begin_using_protid_port (svipc_t)
+#define SYSVSHM_DESTRUCTOR diskfs_end_using_protid_port (protid_t)
+
+#define SYSVSHM_IMPORTS import "mig.h";
+
Index: hurd/shmfs/keymap.c
diff -u /dev/null hurd/shmfs/keymap.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/keymap.c Tue May  1 14:17:30 2001
@@ -0,0 +1,43 @@
+/* Shared memory identifiers and user key management.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "keymap.h"
+
+#include <assert.h>
+#include <cthreads.h>
+#include <hurd/ihash.h>
+
+ihash_t keyhash;
+struct mutex keyhash_lock = MUTEX_INITIALIZER;
+int key_count;
+
+static void keyhash_init (void) __attribute__ ((constructor));
+
+static void
+keyhash_init (void)
+{
+  error_t err;
+
+  (void) &keyhash_init;
+
+  err = ihash_create (&keyhash);
+  assert (! err);
+}
Index: hurd/shmfs/keymap.h
diff -u /dev/null hurd/shmfs/keymap.h:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/keymap.h Tue May  1 14:17:30 2001
@@ -0,0 +1,54 @@
+/* Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef SHMFS_KEYMAP_H
+#define SHMFS_KEYMAP_H
+
+#include "shmfs.h"
+
+#include <assert.h>
+#include <cthreads.h>
+#include <hurd/ihash.h>
+
+extern ihash_t keyhash;
+extern struct mutex keyhash_lock;
+extern int key_count;
+
+/* Drop the association of KEY with any shmid.  */
+extern inline void
+drop_shmid (struct disknode *dn)
+{
+  if (dn->u.reg.shmid == 0)
+    /* Not even an shm object.  */
+    return;
+
+  mutex_lock (&keyhash_lock);
+  if (dn->u.reg.key != 0)
+    {
+      ihash_remove (keyhash, dn->u.reg.key);
+      dn->u.reg.key = 0;
+    }
+  assert (key_count > 0);
+  key_count --;
+  dn->u.reg.shmid = 0;
+  mutex_unlock (&keyhash_lock);
+}
+
+#endif /* SHMFS_KEYMAP_H  */
Index: hurd/shmfs/mig.h
diff -u /dev/null hurd/shmfs/mig.h:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/mig.h    Tue May  1 14:17:31 2001
@@ -0,0 +1,25 @@
+/* MiG guck.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <hurd/diskfs.h>
+
+typedef struct protid *protid_t;
+
Index: hurd/shmfs/node.c
diff -u /dev/null hurd/shmfs/node.c:1.1.2.4
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/node.c   Tue May  1 15:01:59 2001
@@ -0,0 +1,562 @@
+/* Node state and file contents for shmfs.
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "shmfs.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <mach/default_pager.h>
+
+unsigned int num_files;
+static unsigned int gen;
+
+struct node *all_nodes;
+
+error_t
+diskfs_alloc_node (struct node *dp, mode_t mode, struct node **npp)
+{
+  struct disknode *dn;
+
+  dn = calloc (1, sizeof *dn);
+  if (dn == 0)
+    return ENOSPC;
+  spin_lock (&diskfs_node_refcnt_lock);
+  if (round_page (shmfs_space_used + sizeof *dn) / vm_page_size
+      > shmfs_page_limit)
+    {
+      spin_unlock (&diskfs_node_refcnt_lock);
+      free (dn);
+      return ENOSPC;
+    }
+  dn->gen = gen++;
+  ++num_files;
+  shmfs_space_used += sizeof *dn;
+  spin_unlock (&diskfs_node_refcnt_lock);
+
+  dn->type = IFTODT (mode & S_IFMT);
+
+  return diskfs_cached_lookup ((ino_t) dn, npp);
+}
+
+void
+diskfs_free_node (struct node *np, mode_t mode)
+{
+  switch (np->dn->type)
+    {
+    case DT_REG:
+      if (np->dn->u.reg.memobj != MACH_PORT_NULL)
+       mach_port_deallocate (mach_task_self (), np->dn->u.reg.memobj);
+      break;
+    case DT_DIR:
+      assert (np->dn->u.dir.entries == 0);
+      break;
+    case DT_LNK:
+      free (np->dn->u.lnk);
+      break;
+    }
+  *np->dn->hprevp = np->dn->hnext;
+  if (np->dn->hnext != 0)
+    np->dn->hnext->dn->hprevp = np->dn->hprevp;
+  free (np->dn);
+  np->dn = 0;
+
+  --num_files;
+  shmfs_space_used -= sizeof *np->dn;
+}
+
+void
+diskfs_node_norefs (struct node *np)
+{
+  if (np->dn != 0)
+    {
+      /* We don't bother to do this in diskfs_write_disknode, since it only
+        ever matters here.  The node state goes back into the `struct
+        disknode' while it has no associated diskfs node.  */
+
+      np->dn->size = np->dn_stat.st_size;
+      np->dn->mode = np->dn_stat.st_mode;
+      np->dn->nlink = np->dn_stat.st_nlink;
+      np->dn->uid = np->dn_stat.st_uid;
+      np->dn->author = np->dn_stat.st_author;
+      np->dn->gid = np->dn_stat.st_gid;
+      np->dn->atime = np->dn_stat.st_atime;
+      np->dn->mtime = np->dn_stat.st_mtime;
+      np->dn->ctime = np->dn_stat.st_ctime;
+      np->dn->flags = np->dn_stat.st_flags;
+
+      switch (np->dn->type)
+       {
+       case DT_REG:
+         assert (np->allocsize % vm_page_size == 0);
+         np->dn->u.reg.allocpages = np->allocsize / vm_page_size;
+         break;
+       case DT_CHR:
+       case DT_BLK:
+         np->dn->u.chr = np->dn_stat.st_rdev;
+         break;
+       }
+
+      /* Remove this node from the cache list rooted at `all_nodes'.  */
+      *np->dn->hprevp = np->dn->hnext;
+      if (np->dn->hnext != 0)
+       np->dn->hnext->dn->hprevp = np->dn->hprevp;
+      np->dn->hnext = 0;
+      np->dn->hprevp = 0;
+    }
+
+  free (np);
+}
+
+static void
+recompute_blocks (struct node *np)
+{
+  struct disknode *const dn = np->dn;
+  struct stat *const st = &np->dn_stat;
+
+  st->st_blocks = sizeof *dn + dn->translen;
+  switch (dn->type)
+    {
+    case DT_REG:
+      np->allocsize = dn->u.reg.allocpages * vm_page_size;
+      st->st_blocks += np->allocsize;
+      break;
+    case DT_LNK:
+      st->st_blocks += st->st_size + 1;
+      break;
+    case DT_CHR:
+    case DT_BLK:
+      st->st_rdev = dn->u.chr;
+      break;
+    case DT_DIR:
+      st->st_blocks += dn->size;
+      break;
+    }
+  st->st_blocks = (st->st_blocks + 511) / 512;
+}
+
+/* Fetch inode INUM, set *NPP to the node structure;
+   gain one user reference and lock the node.  */
+error_t
+diskfs_cached_lookup (int inum, struct node **npp)
+{
+  struct disknode *dn = (void *) inum;
+  struct node *np;
+
+  assert (npp);
+
+  if (dn->hprevp != 0)
+    /* There is already a node.  */
+    {
+      np = *dn->hprevp;
+      assert (np->dn == dn);
+      assert (*dn->hprevp == np);
+
+      diskfs_nref (np);
+    }
+  else
+    /* Create the new node.  */
+    {
+      struct stat *st;
+
+      np = diskfs_make_node (dn);
+      np->cache_id = (ino_t) dn;
+
+      spin_lock (&diskfs_node_refcnt_lock);
+      dn->hnext = all_nodes;
+      if (dn->hnext)
+       dn->hnext->dn->hprevp = &dn->hnext;
+      dn->hprevp = &all_nodes;
+      all_nodes = np;
+      spin_unlock (&diskfs_node_refcnt_lock);
+
+      st = &np->dn_stat;
+      memset (st, 0, sizeof *st);
+      st->st_fstype = FSTYPE_MEMFS;
+      st->st_fsid = getpid ();
+      st->st_blksize = vm_page_size;
+
+      st->st_ino = (ino_t) dn;
+      st->st_gen = dn->gen;
+
+      st->st_size = dn->size;
+      st->st_mode = dn->mode;
+      st->st_nlink = dn->nlink;
+      st->st_uid = dn->uid;
+      st->st_author = dn->author;
+      st->st_gid = dn->gid;
+      st->st_atime = dn->atime;
+      st->st_mtime = dn->mtime;
+      st->st_ctime = dn->ctime;
+      st->st_flags = dn->flags;
+
+      st->st_rdev = 0;
+      np->allocsize = 0;
+      recompute_blocks (np);
+    }
+
+  mutex_lock (&np->lock);
+  *npp = np;
+  return 0;
+}
+
+error_t
+diskfs_node_iterate (error_t (*fun) (struct node *))
+{
+  error_t err = 0;
+  unsigned int num_nodes = 0;
+  struct node *node, **node_list, **p;
+
+  spin_lock (&diskfs_node_refcnt_lock);
+
+  /* We must copy everything from the hash table into another data structure
+     to avoid running into any problems with the hash-table being modified
+     during processing (normally we delegate access to hash-table with
+     diskfs_node_refcnt_lock, but we can't hold this while locking the
+     individual node locks).  */
+
+  for (node = all_nodes; node != 0; node = node->dn->hnext)
+    num_nodes++;
+
+  p = node_list = alloca (num_nodes * sizeof (struct node *));
+  if (! p)
+    return ENOMEM;
+
+  for (node = all_nodes; node != 0; node = node->dn->hnext)
+    {
+      *p++ = node;
+      node->references++;
+    }
+
+  spin_unlock (&diskfs_node_refcnt_lock);
+
+  p = node_list;
+  while (num_nodes-- > 0)
+    {
+      node = *p++;
+      if (!err)
+       {
+         mutex_lock (&node->lock);
+         err = (*fun) (node);
+         mutex_unlock (&node->lock);
+       }
+      diskfs_nrele (node);
+    }
+
+  return err;
+}
+
+/* The user must define this function.  Node NP has some light
+   references, but has just lost its last hard references.  Take steps
+   so that if any light references can be freed, they are.  NP is locked
+   as is the pager refcount lock.  This function will be called after
+   diskfs_lost_hardrefs.  */
+void
+diskfs_try_dropping_softrefs (struct node *np)
+{
+}
+
+/* The user must define this funcction.  Node NP has some light
+   references but has just lost its last hard reference.  NP is locked. */
+void
+diskfs_lost_hardrefs (struct node *np)
+{
+}
+
+/* The user must define this function.  Node NP has just acquired
+   a hard reference where it had none previously.  It is thus now
+   OK again to have light references without real users.  NP is
+   locked. */
+void
+diskfs_new_hardrefs (struct node *np)
+{
+}
+
+
+
+error_t
+diskfs_get_translator (struct node *np, char **namep, u_int *namelen)
+{
+  *namelen = np->dn->translen;
+  if (*namelen == 0)
+    return 0;
+  *namep = malloc (*namelen);
+  if (*namep == 0)
+    return ENOMEM;
+  memcpy (*namep, np->dn->trans, *namelen);
+  return 0;
+}
+
+error_t
+diskfs_set_translator (struct node *np,
+                      const char *name, u_int namelen,
+                      struct protid *cred)
+{
+  char *new;
+  if (namelen == 0)
+    {
+      free (np->dn->trans);
+      new = 0;
+      np->dn_stat.st_mode &= ~S_IPTRANS;
+    }
+  else
+    {
+      new = realloc (np->dn->trans, namelen);
+      if (new == 0)
+       return ENOSPC;
+      memcpy (new, name, namelen);
+      np->dn_stat.st_mode |= S_IPTRANS;
+    }
+  adjust_used (namelen - np->dn->translen);
+  np->dn->trans = new;
+  np->dn->translen = namelen;
+  recompute_blocks (np);
+  return 0;
+}
+
+static error_t
+create_symlink_hook (struct node *np, const char *target)
+{
+  assert (np->dn->u.lnk == 0);
+  if (np->dn_stat.st_size > 0)
+    {
+      const size_t size = np->dn_stat.st_size + 1;
+      np->dn->u.lnk = malloc (size);
+      if (np->dn->u.lnk == 0)
+       return ENOSPC;
+      memcpy (np->dn->u.lnk, target, size);
+      adjust_used (size);
+      recompute_blocks (np);
+    }
+  return 0;
+}
+error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target)
+     = create_symlink_hook;
+
+static error_t
+read_symlink_hook (struct node *np, char *target)
+{
+  memcpy (target, np->dn->u.lnk, np->dn_stat.st_size + 1);
+  return 0;
+}
+error_t (*diskfs_read_symlink_hook)(struct node *np, char *target)
+     = read_symlink_hook;
+
+void
+diskfs_write_disknode (struct node *np, int wait)
+{
+}
+
+void
+diskfs_file_update (struct node *np, int wait)
+{
+  diskfs_node_update (np, wait);
+}
+
+error_t
+diskfs_node_reload (struct node *node)
+{
+  return 0;
+}
+
+
+/* The user must define this function.  Truncate locked node NP to be SIZE
+   bytes long.  (If NP is already less than or equal to SIZE bytes
+   long, do nothing.)  If this is a symlink (and diskfs_shortcut_symlink
+   is set) then this should clear the symlink, even if
+   diskfs_create_symlink_hook stores the link target elsewhere.  */
+error_t
+diskfs_truncate (struct node *np, off_t size)
+{
+  if (np->allocsize <= size)
+    return 0;
+
+  if (np->dn->type == DT_LNK)
+    {
+      free (np->dn->u.lnk);
+      adjust_used (size - np->dn_stat.st_size);
+      np->dn->u.lnk = 0;
+      np->dn_stat.st_size = size;
+      return 0;
+    }
+
+  assert (np->dn->type == DT_REG);
+
+  if (default_pager == MACH_PORT_NULL)
+    return EIO;
+
+  size = round_page (size);
+
+#if 0
+  if (np->dn->u.reg.memobj != MACH_PORT_NULL)
+    {
+      /* XXX We have no way to really truncate the memory object.  */
+      return 0;
+    }
+#endif
+  /* Otherwise it never had any real contents.  */
+
+  adjust_used (size - np->allocsize);
+  np->dn_stat.st_blocks += (size - np->allocsize) / 512;
+  np->dn_stat.st_size = size;
+  np->allocsize = size;
+
+  return 0;
+}
+
+/* The user must define this function.  Grow the disk allocated to locked node
+   NP to be at least SIZE bytes, and set NP->allocsize to the actual
+   allocated size.  (If the allocated size is already SIZE bytes, do
+   nothing.)  CRED identifies the user responsible for the call.  */
+error_t
+diskfs_grow (struct node *np, off_t size, struct protid *cred)
+{
+  assert (np->dn->type == DT_REG);
+
+  if (np->allocsize >= size)
+    return 0;
+
+  size = round_page (size);
+  if (round_page (shmfs_space_used + size) / vm_page_size > shmfs_page_limit)
+    return ENOSPC;
+
+  if (default_pager == MACH_PORT_NULL)
+    return EIO;
+
+  adjust_used (size - np->allocsize);
+  np->dn_stat.st_blocks += (size - np->allocsize) / 512;
+  np->allocsize = size;
+  return 0;
+}
+
+mach_port_t
+diskfs_get_filemap (struct node *np, vm_prot_t prot)
+{
+  error_t err;
+
+  if (np->dn->type != DT_REG)
+    {
+      errno = EOPNOTSUPP;      /* ? */
+      return MACH_PORT_NULL;
+    }
+
+  if (default_pager == MACH_PORT_NULL)
+    {
+      errno = EIO;
+      return MACH_PORT_NULL;
+    }
+
+  /* We don't bother to create the memory object until the first time we
+     need it (i.e. first mapping or i/o).  This way we might have a clue
+     what size it's going to be beforehand, so we can tell the default
+     pager how big to make its bitmaps.  This is just an optimization for
+     the default pager; the memory object can be expanded at any time just
+     by accessing more of it.  (It also optimizes the case of empty files
+     so we might never make a memory object at all.)  If a user accesses
+     areas outside the bounds of the file, he will just get to diddle the
+     contents of the future larger file.  */
+  if (np->dn->u.reg.memobj == MACH_PORT_NULL)
+    {
+      error_t err = default_pager_object_create (default_pager,
+                                                &np->dn->u.reg.memobj,
+                                                np->allocsize);
+      if (err)
+       {
+         errno = err;
+         return MACH_PORT_NULL;
+       }
+      assert (np->dn->u.reg.memobj != MACH_PORT_NULL);
+    }
+
+  /* XXX always writable */
+
+  np->dn->u.reg.atime = diskfs_mtime->seconds; 
+
+  /* Add a reference for each call, the caller will deallocate it.  */
+  err = mach_port_mod_refs (mach_task_self (), np->dn->u.reg.memobj,
+                           MACH_PORT_RIGHT_SEND, +1);
+  assert_perror (err);
+
+  return np->dn->u.reg.memobj;
+}
+
+/* The user must define this function.  Return a `struct pager *' suitable
+   for use as an argument to diskfs_register_memory_fault_area that
+   refers to the pager returned by diskfs_get_filemap for node NP.
+   NP is locked.  */
+struct pager *
+diskfs_get_filemap_pager_struct (struct node *np)
+{
+  return 0;
+}
+
+/* We have no pager of our own, so there is no need to worry about
+   users of it, or to shut it down.  */
+int
+diskfs_pager_users ()
+{
+  return 0;
+}
+void
+diskfs_shutdown_pager ()
+{
+}
+
+/* The purpose of this is to decide that it's ok to make the fs read-only.
+   Turning a temporary filesystem read-only seem pretty useless.  */
+vm_prot_t
+diskfs_max_user_pager_prot ()
+{
+  return VM_PROT_READ;         /* Probable lie that lets us go read-only.  */
+}
+
+error_t
+diskfs_S_file_get_storage_info (struct protid *cred,
+                               mach_port_t **ports,
+                               mach_msg_type_name_t *ports_type,
+                               mach_msg_type_number_t *num_ports,
+                               int **ints, mach_msg_type_number_t *num_ints,
+                               off_t **offsets,
+                               mach_msg_type_number_t *num_offsets,
+                               char **data, mach_msg_type_number_t *data_len)
+{
+  return EOPNOTSUPP;
+}
+
+error_t
+diskfs_validate_mode_change (struct node *np, mode_t mode)
+{
+  if (np->dn->type == DT_REG && np->dn->u.reg.shmid)
+    np->dn->ctime = diskfs_mtime->seconds;
+  return 0;
+}
+
+error_t
+diskfs_validate_owner_change (struct node *np, uid_t uid)
+{
+  if (np->dn->type == DT_REG && np->dn->u.reg.shmid)
+    np->dn->ctime = diskfs_mtime->seconds;
+  return 0;
+}
+
+error_t
+diskfs_validate_group_change (struct node *np, gid_t gid)
+{
+  if (np->dn->type == DT_REG && np->dn->u.reg.shmid)
+    np->dn->ctime = diskfs_mtime->seconds;
+  return 0;
+}
Index: hurd/shmfs/pager-stubs.c
diff -u /dev/null hurd/shmfs/pager-stubs.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/pager-stubs.c    Sat Apr 21 17:11:28 2001
@@ -0,0 +1,88 @@
+/* stupid stub functions never called, needed because libdiskfs uses libpager
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include <hurd/pager.h>
+#include <stdlib.h>
+
+/* The user must define this function.  For pager PAGER, read one
+   page from offset PAGE.  Set *BUF to be the address of the page,
+   and set *WRITE_LOCK if the page must be provided read-only.
+   The only permissable error returns are EIO, EDQUOT, and ENOSPC. */
+error_t
+pager_read_page (struct user_pager_info *pager,
+                vm_offset_t page,
+                vm_address_t *buf,
+                int *write_lock)
+{
+  abort();
+  return EIEIO;
+}
+
+/* The user must define this function.  For pager PAGER, synchronously
+   write one page from BUF to offset PAGE.  In addition, mfree
+   (or equivalent) BUF.  The only permissable error returns are EIO,
+   EDQUOT, and ENOSPC. */
+error_t
+pager_write_page (struct user_pager_info *pager,
+                 vm_offset_t page,
+                 vm_address_t buf)
+{
+  abort();
+  return EIEIO;
+}
+
+/* The user must define this function.  A page should be made writable. */
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+                  vm_offset_t address)
+{
+  abort();
+  return EIEIO;
+}
+
+/* The user must define this function.  It should report back (in
+   *OFFSET and *SIZE the minimum valid address the pager will accept
+   and the size of the object.   */
+error_t
+pager_report_extent (struct user_pager_info *pager,
+                    vm_address_t *offset,
+                    vm_size_t *size)
+{
+  abort();
+  return EIEIO;
+}
+
+/* The user must define this function.  This is called when a pager is
+   being deallocated after all extant send rights have been destroyed.  */
+void
+pager_clear_user_data (struct user_pager_info *pager)
+{
+  abort();
+}
+
+/* The use must define this function.  This will be called when the ports
+   library wants to drop weak references.  The pager library creates no
+   weak references itself.  If the user doesn't either, then it's OK for
+   this function to do nothing.  */
+void
+pager_dropweak (struct user_pager_info *p)
+{
+  abort();
+}
Index: hurd/shmfs/shm.c
diff -u /dev/null hurd/shmfs/shm.c:1.1.2.2
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/shm.c    Tue May  1 15:01:59 2001
@@ -0,0 +1,321 @@
+/* Shared Memory Interface.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "keymap.h"
+#include "shmfs.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+#include <cthreads.h>
+#include <hurd/diskfs.h>
+#include <hurd/ihash.h>
+
+kern_return_t
+shmfs_S_shm_getid (struct protid *cred, key_t key, size_t size,
+                  mode_t flags, shmid_t *shmid)
+{
+  static int nextid;
+
+  error_t err;
+  struct dirstat ds;
+  struct node *np;
+  char name[21];
+  struct disknode *dn;
+
+  if (! cred || cred->po->np != diskfs_root_node)
+    return EOPNOTSUPP;
+
+  mutex_lock (&keyhash_lock);
+
+  if (key != 0)
+    {
+      dn = ihash_find (keyhash, key);
+      if (dn)
+       {
+         assert (dn->type == DT_REG);
+         *shmid = dn->u.reg.shmid;
+       }
+      else
+       *shmid = 0;
+
+      if (flags & IPC_CREAT && flags & IPC_EXCL && *shmid)
+       /* This is an exclusive create, however, SHMID already exists.  */
+       {
+         mutex_unlock (&keyhash_lock);
+         return EEXIST;
+       }
+
+      if (! (flags & IPC_CREAT) && ! *shmid)
+       /* We were told not to create it and it does not exist!  */
+       {
+         mutex_unlock (&keyhash_lock);
+         return ENOENT;
+       }
+
+      if (*shmid)
+       /* It exists; all done.  */
+       {
+         mutex_unlock (&keyhash_lock);
+         return 0;
+       }
+    }
+
+  diskfs_null_dirstat (&ds);
+
+  for (;;)
+    {
+      while (ihash_find (keyhash, ++ nextid) || nextid == 0)
+        ;
+      *shmid = nextid;
+      mutex_unlock (&keyhash_lock);
+
+      snprintf (name, sizeof (name), "%d", *shmid);
+
+      mutex_lock (&diskfs_root_node->lock);
+      err = diskfs_lookup_hard (diskfs_root_node, name, CREATE, NULL,
+                               &ds, cred);
+      if (err == ENOENT)
+       break;
+      mutex_unlock (&diskfs_root_node->lock);
+      if (err)
+       {
+         diskfs_drop_dirstat (diskfs_root_node, &ds);
+         return err;
+       }
+
+      mutex_lock (&keyhash_lock);
+    }
+
+  err = diskfs_create_node (diskfs_root_node, name,
+                           S_IFREG
+                           | (~(S_IFMT | IPC_CREAT | IPC_EXCL) & flags),
+                           &np, cred, &ds);
+  if (err)
+    {
+      mutex_unlock (&diskfs_root_node->lock);
+
+      /* As per SUSv2.  */
+      if (err == ENOSPC)
+       err = ENOMEM;
+      return err;
+    }
+
+  err = diskfs_grow (np, size, cred);
+  if (err)
+    {
+      diskfs_nput (np);
+      mutex_unlock (&diskfs_root_node->lock);
+
+      /* As per SUSv2.  */
+      if (err == ENOSPC)
+       err = ENOMEM;
+      return err;
+    }
+
+  np->dn_stat.st_size = size;
+
+  np->dn->u.reg.key = key;
+  np->dn->u.reg.shmid = *shmid;
+
+  /* Remember creator's uid.  */
+  if (cred->user->uids->num)
+    np->dn->u.reg.cuid = cred->user->uids->ids[0];
+  else
+    np->dn->u.reg.cuid = -1;
+
+  /* And his gid.  */
+  if (cred->user->gids->num)
+    np->dn->u.reg.cgid = cred->user->gids->ids[0];
+  else
+    np->dn->u.reg.cgid = -1;
+
+#if 0
+  /* XXX FIX ME!!! */
+  np->dn->u.reg.cpid = cred->pid;
+#endif
+
+  /* As per SUSv2, set ctime to the current time.  */
+  np->dn->u.reg.ctime = diskfs_mtime->seconds;
+
+  err = diskfs_direnter_hard (diskfs_root_node, name, np, &ds, cred);
+  mutex_unlock (&diskfs_root_node->lock);
+  if (err)
+    {
+      diskfs_nput (np);
+      return err;
+    }
+
+  mutex_lock (&keyhash_lock);
+  key_count ++;
+  if (key != 0)
+    err = ihash_add (keyhash, key, np->dn, NULL);
+  mutex_unlock (&keyhash_lock);
+
+  diskfs_nput (np);
+
+  return err;
+}
+
+static inline error_t
+do_stat (struct protid *cred, struct node *np, struct shmid_ds *shmid_ds)
+{
+  error_t err;
+
+  err = fshelp_access (&np->dn_stat, S_IREAD, cred->user);
+  if (err)
+    return err;
+
+  shmid_ds->shm_perm.__key = np->dn->u.reg.key;
+  shmid_ds->shm_perm.uid = np->dn_stat.st_uid;
+  shmid_ds->shm_perm.gid = np->dn_stat.st_gid;
+  shmid_ds->shm_perm.cuid = np->dn->u.reg.cuid;
+  shmid_ds->shm_perm.cgid = np->dn->u.reg.cgid;
+  shmid_ds->shm_perm.mode = ~S_IFMT & np->dn_stat.st_mode;
+  shmid_ds->shm_segsz = np->dn_stat.st_size;
+  shmid_ds->shm_lpid = np->dn->u.reg.lpid;
+  shmid_ds->shm_cpid = np->dn->u.reg.cpid;
+  shmid_ds->shm_nattch = np->dn_stat.st_nlink;
+  shmid_ds->shm_atime = np->dn->u.reg.atime;
+  shmid_ds->shm_dtime = np->dn->u.reg.dtime;
+  shmid_ds->shm_ctime = np->dn->u.reg.ctime;
+
+  return 0;
+}
+
+kern_return_t
+shmfs_S_shm_stat (struct protid *cred, shmid_t shmid,
+                 struct shmid_ds *shmid_ds)
+{
+  error_t err;
+  char name[21];
+  struct node *np;
+
+  if (! cred || cred->po->np != diskfs_root_node)
+    return EOPNOTSUPP;
+
+  snprintf (name, sizeof (name), "%d", shmid);
+  err = diskfs_lookup_hard (diskfs_root_node, name, LOOKUP, &np, 0,
+                           cred);
+  if (err)
+    {
+      if (err == ENOENT)
+       /* As per SUSv2.  */
+       err = EINVAL;
+      return err;
+    }
+
+  if (np->dn->type != DT_REG)
+    {
+      diskfs_nput (np);
+      return EOPNOTSUPP;
+    }
+
+  err = do_stat (cred, np, shmid_ds);
+  diskfs_nput (np);
+  return err;
+}
+
+kern_return_t
+shmfs_S_shm_statall (struct protid *cred, shmid_t **shmids, int *shmidscount,
+                    struct shmid_ds **shmids_ds, int *shmids_dscount,
+                    int *lackperm)
+{
+  error_t err = 0;
+  int i = 0;
+  struct shmfs_dirent *e;
+
+  mutex_lock (&keyhash_lock);
+
+  if (*shmids_dscount < key_count)
+    {
+      *shmids_ds = mmap (0, sizeof (struct shmid_ds) * key_count,
+                        PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+      if (*shmids_ds == MAP_FAILED)
+       {
+         mutex_unlock (&keyhash_lock);
+         return ENOMEM;
+       }
+    }
+  if (*shmidscount < key_count)
+    {
+      *shmids = mmap (0, sizeof (shmid_t) * key_count,
+                     PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+      if (*shmids == MAP_FAILED)
+       {
+         if (*shmids_dscount < key_count)
+           munmap (*shmids_ds, sizeof (struct shmid_ds) * key_count);
+         mutex_unlock (&keyhash_lock);
+         return ENOMEM;
+       }
+    }
+
+  *lackperm = 0;
+
+  mutex_lock (&diskfs_root_node->lock);
+  for (e = diskfs_root_node->dn->u.dir.entries; e; e = e->next)
+    {
+      struct node *np;
+      shmid_t id;
+
+      err = diskfs_cached_lookup ((int) e->dn, &np);
+      assert (err == 0);
+
+      if (np->dn->type != DT_REG || np->dn->u.reg.shmid == 0)
+       {
+         diskfs_nput (np);
+         continue;
+       }
+
+      id = np->dn->u.reg.shmid;
+      err = do_stat (cred, np, &(*shmids_ds)[i]);
+      diskfs_nput (np);
+      if (err == EACCES)
+       {
+         err = 0;
+         ++ *lackperm;
+         continue;
+       }
+      if (err)
+       break;
+
+      (*shmids)[i] = id;
+
+      i ++;
+    }
+  mutex_unlock (&diskfs_root_node->lock);
+
+  if (err)
+    {
+      if (*shmids_dscount < key_count)
+       munmap (*shmids_ds, sizeof (struct shmid_ds) * key_count);
+      if (*shmidscount < key_count)
+       munmap (*shmids, sizeof (shmid_t) * key_count);
+      i = 0;
+    }
+  mutex_unlock (&keyhash_lock);
+
+  *shmidscount = i;
+  *shmids_dscount = i;
+
+  return err;
+}
Index: hurd/shmfs/shmfs.c
diff -u /dev/null hurd/shmfs/shmfs.c:1.1.2.2
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/shmfs.c  Tue Apr 24 19:38:00 2001
@@ -0,0 +1,302 @@
+/* Main program and global state for shmfs.
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <argp.h>
+#include <argz.h>
+#include <string.h>
+#include <inttypes.h>
+#include <error.h>
+
+#include "shmfs.h"
+#include <limits.h>
+#include <version.h>
+
+char *diskfs_server_name = "shmfs";
+char *diskfs_server_version = HURD_VERSION;
+char *diskfs_disk_name = "shm";
+
+/* We ain't got to show you no stinkin' sync'ing.  */
+int diskfs_default_sync_interval = 0;
+
+/* We must supply some claimed limits, though we don't impose any new ones.  */
+int diskfs_link_max = (1ULL << (sizeof (nlink_t) * CHAR_BIT)) - 1;
+int diskfs_name_max = 255;     /* dirent d_namlen limit */
+int diskfs_maxsymlinks = 8;
+
+/* Yeah, baby, we do it all!  */
+int diskfs_shortcut_symlink = 1;
+int diskfs_shortcut_chrdev = 1;
+int diskfs_shortcut_blkdev = 1;
+int diskfs_shortcut_fifo = 1;
+int diskfs_shortcut_ifsock = 1;
+
+struct node *diskfs_root_node;
+mach_port_t default_pager;
+
+off_t shmfs_page_limit, shmfs_space_used;
+
+error_t
+diskfs_set_statfs (struct statfs *st)
+{
+  fsblkcnt_t pages;
+
+  st->f_type = FSTYPE_MEMFS;
+  st->f_fsid = getpid ();
+
+  st->f_bsize = vm_page_size;
+  st->f_blocks = shmfs_page_limit;
+
+  spin_lock (&diskfs_node_refcnt_lock);
+  st->f_files = num_files;
+  pages = round_page (shmfs_space_used) / vm_page_size;
+  spin_unlock (&diskfs_node_refcnt_lock);
+
+  st->f_bfree = pages < shmfs_page_limit ? shmfs_page_limit - pages : 0;
+  st->f_bavail = st->f_bfree;
+  st->f_ffree = st->f_bavail / sizeof (struct disknode); /* Well, sort of.  */
+
+  return 0;
+}
+
+
+error_t
+diskfs_set_hypermetadata (int wait, int clean)
+{
+  /* All the state always just lives in core, so we have nothing to do.  */
+  return 0;
+}
+
+void
+diskfs_sync_everything (int wait)
+{
+}
+
+error_t
+diskfs_reload_global_state ()
+{
+  return 0;
+}
+
+int diskfs_synchronous = 0;
+
+
+/* Parse a command line option.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  /* We save our parsed values in this structure, hung off STATE->hook.
+     Only after parsing all options successfully will we use these values.  */
+  struct
+  {
+    off_t size;
+  } *values = state->hook;
+
+  switch (key)
+    {
+    case ARGP_KEY_INIT:
+      state->child_inputs[0] = state->input;
+      values = malloc (sizeof *values);
+      if (values == 0)
+       return ENOMEM;
+      state->hook = values;
+      memset (values, 0, sizeof *values);
+      break;
+
+    case ARGP_KEY_NO_ARGS:
+      argp_error (state, "must supply maximum size");
+      return EINVAL;
+
+    case ARGP_KEY_ARGS:
+      if (state->argv[state->next + 1] != 0)
+       {
+         argp_error (state, "too many arguments");
+         return EINVAL;
+       }
+      else
+       {
+         char *end = NULL;
+         intmax_t size = strtoimax (state->argv[state->next], &end, 0);
+         if (end == NULL || end == arg)
+           {
+             argp_error (state, "argument must be a number");
+             return EINVAL;
+           }
+         if (size < 0)
+           {
+             argp_error (state, "negative size not meaningful");
+             return EINVAL;
+           }
+         switch (*end)
+           {
+           case 'g':
+           case 'G':
+             size <<= 10;
+           case 'm':
+           case 'M':
+             size <<= 10;
+           case 'k':
+           case 'K':
+             size <<= 10;
+             break;
+           }
+         size = (off_t) size;
+         if (size < 0)
+           {
+             argp_error (state, "size too large");
+             return EINVAL;
+           }
+         values->size = size;
+       }
+      break;
+
+    case ARGP_KEY_SUCCESS:
+      /* All options parse successfully, so implement ours if possible.  */
+      shmfs_page_limit = values->size / vm_page_size;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+/* Override the standard diskfs routine so we can add our own output.  */
+error_t
+diskfs_append_args (char **argz, unsigned *argz_len)
+{
+  error_t err;
+
+  /* Get the standard things.  */
+  err = diskfs_append_std_options (argz, argz_len);
+
+  if (!err)
+    {
+      off_t lim = shmfs_page_limit * vm_page_size;
+      char buf[100], sfx;
+#define S(n, c) if ((lim & ((1 << n) - 1)) == 0) sfx = c, lim >>= n
+      S (30, 'G'); else S (20, 'M'); else S (10, 'K'); else sfx = '\0';
+#undef S
+      snprintf (buf, sizeof buf, "%ld%c", lim, sfx);
+      err = argz_add (argz, argz_len, buf);
+    }
+
+  return err;
+}
+
+/* Add our startup arguments to the standard diskfs set.  */
+static const struct argp_child startup_children[] =
+  {{&diskfs_startup_argp}, {0}};
+static struct argp startup_argp = {0, parse_opt, "MAX-BYTES", "\
+\v\
+MAX-BYTES may be followed by k or K for kilobytes,\n\
+m or M for megabytes, g or G for gigabytes.",
+                                  startup_children};
+
+/* Similarly at runtime.  */
+static const struct argp_child runtime_children[] =
+  {{&diskfs_std_runtime_argp}, {0}};
+static struct argp runtime_argp = {0, parse_opt, 0, 0, runtime_children};
+
+struct argp *diskfs_runtime_argp = (struct argp *)&runtime_argp;
+
+
+
+int
+main (int argc, char **argv)
+{
+  error_t err;
+  mach_port_t bootstrap, realnode, host_priv;
+  struct stat st;
+
+  err = argp_parse (&startup_argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
+  assert_perror (err);
+
+  task_get_bootstrap_port (mach_task_self (), &bootstrap);
+  if (bootstrap == MACH_PORT_NULL)
+    error (2, 0, "Must be started as a translator");
+
+  /* Get our port to the default pager.  Without that,
+     we have no place to put file contents.  */
+  err = get_privileged_ports (&host_priv, NULL);
+  if (err)
+    error (0, err, "Cannot get host privileged port");
+  else
+    {
+      err = vm_set_default_memory_manager (host_priv, &default_pager);
+      mach_port_deallocate (mach_task_self (), host_priv);
+      if (err)
+       error (0, err, "Cannot get default pager port");
+    }
+  if (default_pager == MACH_PORT_NULL)
+    error (0, 0, "files cannot have contents with no default pager port");
+
+  /* Initialize the diskfs library.  Must come before any other diskfs call. */
+  err = diskfs_init_diskfs ();
+  if (err)
+    error (4, err, "init");
+
+  err = diskfs_alloc_node (0, S_IFDIR, &diskfs_root_node);
+  if (err)
+    error (4, err, "cannot create root directory");
+
+  diskfs_spawn_first_thread (shmfs_demuxer);
+
+  /* Now that we are all set up to handle requests, and diskfs_root_node is
+     set properly, it is safe to export our fsys control port to the
+     outside world.  */
+  realnode = diskfs_startup_diskfs (bootstrap, 0);
+
+  /* Propagate permissions, owner, etc. from underlying node to
+     the root directory of the new (empty) filesystem.  */
+  err = io_stat (realnode, &st);
+  if (err)
+    {
+      error (0, err, "cannot stat underlying node");
+      diskfs_root_node->dn_stat.st_mode = S_IFDIR | 0777 | S_ISVTX;
+      diskfs_root_node->dn_set_ctime = 1;
+      diskfs_root_node->dn_set_mtime = 1;
+      diskfs_root_node->dn_set_atime = 1;
+    }
+  else
+    {
+      diskfs_root_node->dn_stat.st_mode = S_IFDIR | (st.st_mode &~ S_IFMT);
+      if (S_ISREG(st.st_mode) && (st.st_mode & 0111) == 0)
+       /* There are no execute bits set, as by default on a plain file.
+          For the virtual directory, set execute bits where read bits are
+          set on the underlying plain file.  */
+       diskfs_root_node->dn_stat.st_mode |= (st.st_mode & 0444) >> 2;
+      diskfs_root_node->dn_stat.st_uid = st.st_uid;
+      diskfs_root_node->dn_stat.st_author = st.st_author;
+      diskfs_root_node->dn_stat.st_gid = st.st_gid;
+      diskfs_root_node->dn_stat.st_atime = st.st_atime;
+      diskfs_root_node->dn_stat.st_mtime = st.st_mtime;
+      diskfs_root_node->dn_stat.st_ctime = st.st_ctime;
+      diskfs_root_node->dn_stat.st_flags = st.st_flags;
+    }
+  diskfs_root_node->dn_stat.st_mode &= ~S_ITRANS;
+  diskfs_root_node->dn_stat.st_mode |= S_IROOT;
+  diskfs_root_node->dn_stat.st_nlink = 2;
+
+  mutex_unlock (&diskfs_root_node->lock);
+
+  /* and so we die, leaving others to do the real work.  */
+  cthread_exit (0);
+  /* NOTREACHED */
+  return 0;
+}
Index: hurd/shmfs/shmfs.h
diff -u /dev/null hurd/shmfs/shmfs.h:1.1.2.4
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs/shmfs.h  Tue May  1 15:02:00 2001
@@ -0,0 +1,101 @@
+/* Private data structures for shmfs.
+   Copyright (C) 2000,01 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _shmfs_h
+#define _shmfs_h 1
+
+#include <hurd/diskfs.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdint.h>
+#include <sys/shm.h>
+
+struct disknode
+{
+  uint_fast8_t type;           /* DT_REG et al */
+
+  unsigned int gen;
+  off_t size;
+  mode_t mode;
+  nlink_t nlink;
+  uid_t uid, author;
+  gid_t gid;
+  time_t atime, mtime, ctime;
+  unsigned int flags;
+
+  char *trans;
+  size_t translen;
+
+  union
+  {
+    char *lnk;                 /* malloc'd symlink target */
+    struct
+    {
+      mach_port_t memobj;
+      unsigned int allocpages; /* largest size while memobj was live */
+      time_t atime;
+      time_t dtime;
+      time_t ctime;
+      key_t key;
+      int shmid;
+      pid_t lpid;
+      pid_t cpid;
+      uid_t cuid;
+      gid_t cgid;
+    } reg;
+    struct
+    {
+      struct shmfs_dirent *entries;
+      struct disknode *dotdot;
+    } dir;
+    dev_t chr, blk;
+  } u;
+
+  struct node *hnext, **hprevp;
+};
+
+struct shmfs_dirent
+{
+  struct shmfs_dirent *next;
+  struct disknode *dn;
+  uint8_t namelen;
+  char name[0];
+};
+
+struct dirstat
+{
+  struct shmfs_dirent **prevp;
+};
+
+extern unsigned int num_files;
+extern off_t shmfs_page_limit, shmfs_space_used;
+
+extern mach_port_t default_pager;
+
+extern inline void
+adjust_used (off_t change)
+{
+  spin_lock (&diskfs_node_refcnt_lock);
+  shmfs_space_used += change;
+  spin_unlock (&diskfs_node_refcnt_lock);
+}
+ 
+int shmfs_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp);
+
+#endif
Index: hurd/shmfs-tests/Makefile
diff -u /dev/null hurd/shmfs-tests/Makefile:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/Makefile   Tue May  1 14:18:27 2001
@@ -0,0 +1,38 @@
+# Makefile shmfs test cases
+#
+#   Copyright (C) 2001 Free Software Foundation, Inc.
+#
+#   This program is free software; you can redistribute it and/or
+#   modify it under the terms of the GNU General Public License as
+#   published by the Free Software Foundation; either version 2, or (at
+#   your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#   General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := shmfs-tests
+makemode := utilities
+
+targets = get ipcs ipcrm read write
+SRCS = get.c ipcs.c ipcrm.c read.c write.c shm.c
+
+MIGSTUBS = sysvshmUser.o fsUser.o
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+HURDLIBS =
+
+include ../Makeconf
+
+get: get.o sysvshmUser.o shm.o
+ipcs: ipcs.o sysvshmUser.o shm.o
+ipcs-LDFLAGS=-lshouldbeinlibc
+ipcrm: ipcrm.o sysvshmUser.o shm.o
+read: read.o sysvshmUser.o shm.o
+write: write.o sysvshmUser.o shm.o
+
+shm.o: fsUser.o
Index: hurd/shmfs-tests/get.c
diff -u /dev/null hurd/shmfs-tests/get.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/get.c      Tue May  1 14:18:28 2001
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/shm.h>
+
+int main (int argc, char *argv[])
+{
+  key_t key;
+  int mode;
+  size_t size;
+  int id;
+
+  if (argc != 4)
+    {
+      fprintf (stderr, "Usage: %s key size mode\n"
+              "\tIPC_CREAT =\t%o\n\tIPC_EXCL =\t%o\n",
+              argv[0], IPC_CREAT, IPC_EXCL);
+      return 1;
+    }
+
+  key = strtol (argv[1], 0, 0);
+  size = strtol (argv[2], 0, 0);
+  mode = strtol (argv[3], 0, 8);
+
+  id = shmget (key, size, mode);
+  if (id == -1)
+    error (1, errno, "shmget");
+
+  printf ("%d\n", id);
+  return 0;
+}
Index: hurd/shmfs-tests/ipcrm.c
diff -u /dev/null hurd/shmfs-tests/ipcrm.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/ipcrm.c    Tue May  1 14:18:28 2001
@@ -0,0 +1,135 @@
+/* SUSv2 compliant ipcs
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "sysvshm_U.h"
+
+#include <argp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <error.h>
+#include <sys/shm.h>
+
+static const struct argp_option options[] = {
+  {"msgid", 'q', "MSGID", 0,
+   "Remove the messages queue named by the given id"},
+  {"msgkey",'Q', "MSGKEY", 0,
+   "Remove the messages queue named by the given key"},
+  {"shmid", 'm', "SHMID", 0,
+   "Remove the shared memory object named by the given id"},
+  {"shmkey",'M', "SHMKEY", 0,
+   "Remove the shared memory object named by the given key"},
+  {"semid", 's', "SEMID", 0,
+   "Remove the semaphores named by the given id"},
+  {"semkey",'S', "SEMKEY", 0,
+   "Remove the semaphores named by the given key"},
+  {0}
+};
+
+static const char *args_doc = "";
+static const char *doc = "Remove a System V IPC object.\
+\vMultiple objects may be specified.";
+
+int
+main (int argc, char *argv[])
+{
+  error_t rt = 0;
+  int warn_sem = 0;
+  int warn_msg = 0;
+
+  error_t
+    parse_opt (int key, char *arg, struct argp_state *state)
+      {
+        int iskey = 0;  /* 0 = ID; 1 = KEY  */
+
+        switch (key)
+         {
+         case ARGP_KEY_ARG:
+           argp_usage (state);
+
+         case 'Q':
+         case 'q':
+           if (! warn_msg)
+             {
+               warn_msg = 1;
+               printf ("Message queues not yet implemented.\n");
+             }
+           break;
+
+         case 'S':
+         case 's':
+           if (! warn_sem)
+             {
+               warn_sem = 1;
+               printf ("Semaphores not yet implemented.\n");
+             }
+           break;
+
+         case 'M':
+           iskey = 1;
+         case 'm':
+           {
+             error_t err;
+             int id;
+             char *end;
+
+             id = strtol (arg, &end, 0);
+             if (! end || *end != '\0')
+               {
+                 printf ("Invalid identifier: `%s'.\n", arg);
+                 if (! rt)
+                   rt = 2;
+                 break;
+               }
+
+             if (iskey && id != 0)
+               {
+                 id = shmget (id, 0, 0);
+                 if (id == -1)
+                   {
+                     error (0, errno, "shmget");
+                     rt = 1;
+                     break;
+                   }
+               }
+               
+               err = shmctl (id, IPC_RMID, NULL);
+               if (err == -1)
+                 {
+                   rt = 1;
+                   error (0, errno, "removing %d", id);
+                 }
+
+             break;
+           }
+
+         default:
+           return ARGP_ERR_UNKNOWN;
+         }
+       return 0;
+      }
+
+  const struct argp argp = { options, parse_opt, args_doc, doc };
+  argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
+  return rt;
+}
+
Index: hurd/shmfs-tests/ipcs.c
diff -u /dev/null hurd/shmfs-tests/ipcs.c:1.1.2.2
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/ipcs.c     Tue May  1 15:02:11 2001
@@ -0,0 +1,277 @@
+/* SUSv2 compliant ipcs
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+   Written by Neal H Walfield <neal@cs.uml.edu>
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "sysvshm_U.h"
+
+#include <argp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <error.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <hurd.h>
+#include <sys/shm.h>
+#include <hurd/paths.h>
+
+static const struct argp_option options[] = {
+  {"shm",      'm', 0, 0, "Shared memory objects", 0},
+  {"sem",      's', 0, 0, "Semaphores", 0},
+  {"msg",      'q', 0, 0, "Messages queues", 0},
+
+  {"all",      'a', 0, 0, "Print all statistics", 1},
+  {"limits",   'b', 0, 0, "Print maximun allowable sizes", 1},
+  {"creator",  'c', 0, 0, "Print creator's user name and group", 1},
+  {"out",      'o', 0, 0, "Print outstanding usage", 1},
+  {"process",  'p', 0, 0, "Print process information", 1},
+  {"time",     't', 0, 0, "Print time information", 1},
+  {0}
+};
+
+static const char *args_doc = "[ID...]";
+static const char *doc = "Get System V IPC statistics.";
+
+/* What to print.  */
+#define B (1 << 0)
+#define C (1 << 1)
+#define O (1 << 2)
+#define P (1 << 3)
+#define T (1 << 4)
+#define A (B | C | O | P | T)
+
+void intro (void)
+{
+  time_t t;
+  extern char *localhost (void);
+
+  t = time (NULL);
+  printf ("IPC status from %s:%s as of %s", localhost (), _SERVERS_SYSVSHM,
+         ctime (&t));
+}
+
+int
+msg_report (int print)
+{
+  printf ("Message queues facility not in system.\n");
+  return 1;
+}
+
+int
+shm_report (int print)
+{
+  error_t err;
+  file_t server;
+  struct shmid_ds sbuf[10];
+  struct shmid_ds *stats = sbuf;
+  int ibuf[10];
+  int *ids = ibuf;
+  int ds_count = sizeof (sbuf) / sizeof (struct shmid_ds);
+  int id_count = sizeof (ibuf) / sizeof (int);
+  int lackperm;
+  int i;
+
+  server = file_name_lookup (_SERVERS_SYSVSHM, 0, 0);
+  if (server == MACH_PORT_NULL)
+    {
+      printf ("Shared Memory facility not in system.\n");
+      return 1;
+    }
+
+  err = shm_statall (server, &ids, &id_count, &stats,
+                    &ds_count, &lackperm);
+  if (err)
+    {
+      printf ("Failed to collect the shared memory statistics: %m");
+      return 1;
+    }
+
+  printf ("Shared Memory:\n");
+
+  printf ("T ID       KEY          MODE        OWNER    GROUP    ");
+  if (print & C)
+    printf ("CREATOR  CGROUP   ");
+  if (print & O)
+    printf ("NATTCH  ");
+  if (print & B)
+    printf ("SEGSZ    ");
+  if (print & P)
+    printf ("CPID     LPID     ");
+  if (print & T)
+    printf ("ATIME     DTIME");
+  printf ("\n");
+
+  for (i = 0; i < id_count; i ++)
+    {
+      int id = ids[i];
+      struct shmid_ds *ds = &stats[i];
+      struct passwd *u;
+      struct group *g;
+
+      printf ("m %-9d0x%-11lx--%c%c-%c%c-%c%c- ", id,
+             ds->shm_perm.__key,
+             S_IRUSR & ds->shm_perm.mode ? 'r' : '-',
+             S_IWUSR & ds->shm_perm.mode ? 'w' : '-',
+             S_IRGRP & ds->shm_perm.mode ? 'r' : '-',
+             S_IWGRP & ds->shm_perm.mode ? 'w' : '-',
+             S_IROTH & ds->shm_perm.mode ? 'r' : '-',
+             S_IWOTH & ds->shm_perm.mode ? 'w' : '-');
+
+      u = getpwuid (ds->shm_perm.uid);
+      if (u)
+       printf ("%-9s", u->pw_name);
+      else
+       printf ("%-9d", ds->shm_perm.uid);
+      
+      g = getgrgid (ds->shm_perm.gid);
+      if (g)
+       printf ("%-9s", g->gr_name);
+      else
+       printf ("%-9d", ds->shm_perm.gid);
+      
+      if (print & C)
+       {
+         u = getpwuid (ds->shm_perm.cuid);
+         if (u)
+           printf ("%-9s", u->pw_name);
+         else
+           printf ("%-9d", ds->shm_perm.cuid);
+         
+         g = getgrgid (ds->shm_perm.cgid);
+         if (g)
+           printf ("%-9s", g->gr_name);
+         else
+           printf ("%-9d", ds->shm_perm.cgid);
+       }
+
+      if (print & O)
+       printf ("%-8d", ds->shm_nattch);
+
+      if (print & B)
+       printf ("%-8d", ds->shm_segsz);
+
+      if (print & P)
+       printf ("%-8d %-8d", ds->shm_cpid, ds->shm_lpid);
+
+      if (print & T)
+       {
+         if (ds->shm_atime)
+           {
+             struct tm *tm;
+             char buffer[10];
+             tm = localtime (&ds->shm_atime);
+             strftime (buffer, sizeof (buffer), "%H:%M:%S", tm);
+             printf ("%s ", buffer);
+           }
+         else
+           printf (" no-entry ");
+
+         if (ds->shm_dtime)
+           {
+             struct tm *tm;
+             char buffer[10];
+             tm = localtime (&ds->shm_dtime);
+             strftime (buffer, sizeof (buffer), "%H:%M:%S", tm);
+             printf ("%s", buffer);
+           }
+         else
+           printf (" no-entry");
+       }
+
+      printf ("\n");
+    }
+  return 0;
+}
+
+int
+sem_report (int print)
+{
+  printf ("Semaphore facility not in system.\n");
+  return 1;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int output = 0;  /* What to print: bit wise or of B, C, O, P, T.  */
+
+  int do_shm = 0;
+  int do_sem = 0;
+  int do_msg = 0;
+
+  int rt = 0;
+
+  error_t
+    parse_opt (int key, char *arg, struct argp_state *state)
+      {
+        switch (key)
+         {
+         case 'm':
+           do_shm = 1;
+           break;
+         case 's':
+           do_sem = 1;
+           break;
+         case 'q':
+           do_msg = 1;
+           break;
+
+         case 'a':
+           output = A;
+           break;
+         case 'b':
+           output |= B;
+           break;
+         case 'c':
+           output |= C;
+           break;
+         case 'o':
+           output |= O;
+           break;
+         case 'p':
+           output |= P;
+           break;
+         case 't':
+           output |= T;
+           break;
+
+         case ARGP_KEY_NO_ARGS:
+           intro ();
+           if (do_msg)
+             rt |= (msg_report (output) & 1) << 0;
+           if (do_shm)
+             rt |= (shm_report (output) & 1) << 1;
+           if (do_sem)
+             rt |= (sem_report (output) & 1) << 2;
+           break;
+
+         default:
+           return ARGP_ERR_UNKNOWN;
+         }
+       return 0;
+      }
+           
+  const struct argp argp = { options, parse_opt, args_doc, doc };
+
+  argp_parse (&argp, argc, argv, 0, 0, 0);
+
+  return rt;
+}
Index: hurd/shmfs-tests/read.c
diff -u /dev/null hurd/shmfs-tests/read.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/read.c     Tue May  1 14:18:29 2001
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/shm.h>
+
+int main (int argc, char *argv[])
+{
+  error_t err;
+  key_t key;
+  int id;
+  char *data;
+
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage: %s key\n", argv[0]);
+      return 1;
+    }
+
+  id = strtol (argv[1], 0, 0);
+  data = shmat (id, 0, 0);
+  if (data == (void *) -1)
+    error (1, errno, "shmat");
+
+  printf ("%s\n", data);
+
+  err = shmdt (data);
+  if (err == -1)
+    error (1, errno, "shmdt");
+    
+  return 0;
+}
Index: hurd/shmfs-tests/shm.c
diff -u /dev/null hurd/shmfs-tests/shm.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/shm.c      Tue May  1 14:18:30 2001
@@ -0,0 +1,246 @@
+#include "sysvshm_U.h"
+#include "fs_U.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <error.h>
+#include <cthreads.h>
+#include <hurd.h>
+#include <hurd/paths.h>
+
+struct liste
+{
+  struct liste *next;
+  void *addr;
+  struct liste **prevp;
+  size_t size;
+};
+
+static struct liste *addr2size;
+static struct mutex addr2size_lock= MUTEX_INITIALIZER;
+
+/* Shared memory control operation.  */
+int shmctl (int shmid, int cmd, struct shmid_ds *buf)
+{
+  switch (cmd)
+    {
+    case IPC_STAT:
+      {
+       error_t err;
+        file_t shm;
+
+       shm = file_name_lookup (_SERVERS_SYSVSHM, 0, 0);
+       if (shm == MACH_PORT_NULL)
+         return EINVAL;
+
+       err = shm_stat (shm, shmid, buf);
+       mach_port_deallocate (mach_task_self (), shm);
+       if (err)
+         {
+           errno = err;
+           return -1;
+         }
+
+       return 0;
+      }
+
+    case IPC_SET:
+      {
+        error_t err;
+       file_t shm;
+       char name[sizeof (_SERVERS_SYSVSHM) + 22];
+
+       sprintf (name, "%s/%d", _SERVERS_SYSVSHM, shmid);
+
+       shm = file_name_lookup (name, 0, 0);
+       if (shm == MACH_PORT_NULL)
+         /* SUSv2.  */
+         return EINVAL;
+
+       err = file_chown (shm, buf->shm_perm.uid, buf->shm_perm.gid);
+       if (err)
+         {
+           mach_port_deallocate (mach_task_self (), shm);
+           errno = err;
+           return -1;
+         }
+
+       err = file_chmod (shm, buf->shm_perm.mode);
+       mach_port_deallocate (mach_task_self (), shm);
+       if (err)
+         /* Ekk.  If we were able to chown, we should have been able to
+            chmod!  */
+         {
+           errno = err;
+           return -1;
+         }
+
+       return 0;
+      }
+
+    case IPC_RMID:
+      {
+        error_t err;
+       char name[sizeof (_SERVERS_SYSVSHM) + 22];
+
+       sprintf (name, "%s/%d", _SERVERS_SYSVSHM, shmid);
+
+        err = unlink (name);
+       if (err == -1
+           && (errno == ENOENT || errno == ENOTDIR || errno == EISDIR))
+         /* SUSv2.  */
+         errno = EINVAL;
+       if (err == -1)
+         return -1;
+      }
+
+    default:
+      return EINVAL;
+    }
+}
+
+/* Get shared memory segment.  */
+int
+shmget (key_t key, size_t size, int flags)
+{
+  error_t err;
+  file_t server;
+  shmid_t shmid;
+
+  server = file_name_lookup (_SERVERS_SYSVSHM, 0, 0);
+  if (server == MACH_PORT_NULL)
+    {
+      if (errno == ENOENT)
+       /* SUSv2.  */
+       errno = EINVAL;
+      return -1;
+    }
+
+  err = shm_getid (server, key, size, flags, &shmid);
+  mach_port_deallocate (mach_task_self (), server);
+  if (err)
+    {
+      errno = err;
+      return -1;
+    }
+
+  return shmid;
+}
+
+/* Attach shared memory segment.  */
+void *
+shmat (int shmid, const void *shmaddr, int shmflg)
+{
+  error_t err;
+  struct liste *e;
+  char name[sizeof (_SERVERS_SYSVSHM) + 22];
+  int fd;
+  int prot;
+  struct stat stat;
+  void *target;
+  int mmapflg;
+
+  e = malloc (sizeof (struct liste));
+  if (! e)
+    {
+      errno = ENOMEM;
+      return (void *) -1;
+    }
+
+  sprintf (name, "%s/%d", _SERVERS_SYSVSHM, shmid);
+
+  if (! (shmflg & SHM_RDONLY))
+    {
+      fd = open (name, O_RDWR);
+      if (fd == -1)
+       {
+         free (e);
+         return (void *) -1;
+       }
+      prot = PROT_READ | PROT_WRITE;
+    }
+  else
+    {
+      fd = open (name, O_READ);
+      if (fd == -1)
+       {
+         free (e);
+         return (void *) -1;
+       }
+      prot = PROT_READ;
+    }
+
+  err = fstat (fd, &stat);
+  if (err)
+    {
+      close (fd);
+      free (e);
+      return (void *) -1;
+    }
+  e->size = stat.st_size;
+
+  mmapflg = MAP_SHARED;
+  if (shmaddr)
+    {
+      if (shmflg & SHM_RND)
+        shmaddr -= (uintptr_t) shmaddr % SHMLBA;
+      mmapflg |= MAP_FIXED;
+    }
+
+  target = mmap (shmaddr, e->size, prot, mmapflg, fd, 0);
+  close (fd);
+  if (target == MAP_FAILED)
+    {
+      free (e);
+      return (void *) -1;
+    }
+  e->addr = target;
+
+  mutex_lock (&addr2size_lock);
+  e->next = addr2size;
+  if (e->next)
+    e->next->prevp = &e->next;
+  e->prevp = &addr2size;
+  addr2size = e;
+  mutex_unlock (&addr2size_lock);
+
+  return target;
+}
+
+/* Detach shared memory segment.  */
+int
+shmdt (const void *addr)
+{
+  error_t err;
+  struct liste *e;
+
+  mutex_lock (&addr2size_lock);
+
+  for (e = addr2size; e && addr != e->addr; e = e->next)
+    ;
+
+  if (! e)
+    {
+      mutex_unlock (&addr2size_lock);
+      err = EINVAL;
+      return -1;
+    }
+
+  err = munmap (e->addr, e->size);
+
+  *e->prevp = e->next;
+  if (e->next)
+    e->next->prevp = e->prevp;
+  free (e);
+  mutex_unlock (&addr2size_lock);
+
+  return err;
+}
Index: hurd/shmfs-tests/write.c
diff -u /dev/null hurd/shmfs-tests/write.c:1.1.2.1
--- /dev/null   Tue May  1 17:14:34 2001
+++ hurd/shmfs-tests/write.c    Tue May  1 14:18:31 2001
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <error.h>
+#include <errno.h>
+#include <sys/shm.h>
+
+int main (int argc, char *argv[])
+{
+  error_t err;
+  int id;
+  char *data;
+
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: %s id message\n", argv[0]);
+      return 1;
+    }
+
+  id = strtol (argv[1], 0, 0);
+  data = shmat (id, 0, 0);
+  if (data == (void *) -1)
+    error (1, errno, "shmat");
+
+  sprintf (data, "%s", argv[2]);
+
+  err = shmdt (data);
+  if (err == -1)
+    error (1, errno, "shmdt");
+    
+  return 0;
+}

Attachment: pgpyaQ9ZTwCyP.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]