[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;
+}
pgpyaQ9ZTwCyP.pgp
Description: PGP signature
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH] shmfs: A System V shared memory filesystem,
Neal H Walfield <=