diff -uNr 4-1-ac7/Documentation/Changes c1/Documentation/Changes
--- 4-1-ac7/Documentation/Changes	Wed May 31 20:29:23 2000
+++ c1/Documentation/Changes	Fri Jun  2 13:22:23 2000
@@ -72,6 +72,18 @@
 General Information
 ===================
 
+   System V shared memory is now implemented via a filesystem.  You do
+not have to mount it to use it as long as you can live with the
+default maxima for shared memory and segments.  If you wish to change
+these variables, you have to mount it with the options nr_blocks
+and/or nr_inodes.  If you want to use POSIX shm, then it needs to be
+mounted somewhere.  The recommended place is /dev/shm and this can be
+done by adding the following line to /etc/fstab:
+
+none		/dev/shm	shm		defaults	0 0
+
+Remember to create the directory that you intend to mount shm on.
+
    <CTRL><ALT><DEL> now performs a cold reboot instead of a warm reboot
 for increased hardware compatibility.  If you want a warm reboot and
 know it works on your hardware, add a "reboot=warm" command line option
diff -uNr 4-1-ac7/Documentation/Configure.help c1/Documentation/Configure.help
--- 4-1-ac7/Documentation/Configure.help	Wed May 31 20:29:23 2000
+++ c1/Documentation/Configure.help	Fri Jun  2 13:22:34 2000
@@ -2581,11 +2581,10 @@
   http://www.linuxdoc.org/docs.html#guide .
 
   Shared memory is now implemented using a new (minimal) virtual file
-  system, which you need to mount before programs can use shared
-  memory. To do this automatically at system startup just add the
+  system. To mount it automatically at system startup just add the
   following line to your /etc/fstab:
 
-  none	/var/shm	shm	defaults	0 0
+  none	/dev/shm	shm	defaults	0 0
 
   Saying Y here enlarges your kernel by about 18 KB. Just say Y.
 
diff -uNr 4-1-ac7/include/asm-s390/pgtable.h c1/include/asm-s390/pgtable.h
--- 4-1-ac7/include/asm-s390/pgtable.h	Mon May 22 15:02:03 2000
+++ c1/include/asm-s390/pgtable.h	Wed May 31 20:38:47 2000
@@ -270,6 +270,7 @@
 extern inline int pte_none(pte_t pte)           { return ((pte_val(pte) & (_PAGE_INVALID | _PAGE_RO)) == _PAGE_INVALID); } 
 extern inline int pte_present(pte_t pte)        { return pte_val(pte) & _PAGE_PRESENT; }
 extern inline void pte_clear(pte_t *ptep)       { pte_val(*ptep) = _PAGE_INVALID; }
+#define PTE_INIT(x) pte_clear(x)
 extern inline int pte_pagenr(pte_t pte)	        { return ((unsigned long)((pte_val(pte) >> PAGE_SHIFT))); }
 
 extern inline int pmd_none(pmd_t pmd)           { return pmd_val(pmd) & _PAGE_TABLE_INV; }
diff -uNr 4-1-ac7/ipc/shm.c c1/ipc/shm.c
--- 4-1-ac7/ipc/shm.c	Wed May 24 09:10:57 2000
+++ c1/ipc/shm.c	Fri Jun  2 12:58:57 2000
@@ -16,11 +16,9 @@
  *
  * The filesystem has the following restrictions/bugs:
  * 1) It only can handle one directory.
- * 2) Because the directory is represented by the SYSV shm array it
- *    can only be mounted one time.
- * 3) Private writeable mappings are not supported
- * 4) Read and write are not implemented (should they?)
- * 5) No special nodes are supported
+ * 2) Private writeable mappings are not supported
+ * 3) Read and write are not implemented (should they?)
+ * 4) No special nodes are supported
  *
  * There are the following mount options:
  * - nr_blocks (^= shmall) is the number of blocks of size PAGE_SIZE
@@ -335,7 +333,7 @@
 	return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
 }
 
-static __inline__ int shm_addid(struct shmid_kernel *shp)
+static inline int shm_addid(struct shmid_kernel *shp)
 {
 	return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1);
 }
@@ -544,13 +542,37 @@
 	return 0;
 }
 
-#define SHM_ENTRY(shp, index) (shp)->shm_dir[(index)/PTRS_PER_PTE][(index)%PTRS_PER_PTE]
+/*
+ * We cannot use kmalloc for shm_alloc since this restricts the
+ * maximum size of the segments.
+ *
+ * We also cannot use vmalloc, since this uses too much of the vmalloc
+ * space and we run out of this on highend machines.
+ *
+ * So we have to use this complicated indirect scheme to alloc the shm
+ * page tables.
+ *
+ */
+
+#ifdef PTE_INIT
+static inline void init_ptes (pte_t *pte, int number) {
+	while (number--)
+		PTE_INIT (pte++);
+}
+#else
+static inline void init_ptes (pte_t *pte, int number) {
+	memset (pte, 0, number*sizeof(*pte));
+}
+#endif
+
+#define PTES_PER_PAGE (PAGE_SIZE/sizeof(pte_t))
+#define SHM_ENTRY(shp, index) (shp)->shm_dir[(index)/PTES_PER_PAGE][(index)%PTES_PER_PAGE]
 
 static pte_t **shm_alloc(unsigned long pages, int doacc)
 {
-	unsigned short dir  = pages / PTRS_PER_PTE;
-	unsigned short last = pages % PTRS_PER_PTE;
-	pte_t **ret, **ptr, *pte;
+	unsigned short dir  = pages / PTES_PER_PAGE;
+	unsigned short last = pages % PTES_PER_PAGE;
+	pte_t **ret, **ptr;
 
 	if (pages == 0)
 		return NULL;
@@ -564,8 +586,7 @@
 		*ptr = (pte_t *)__get_free_page (GFP_KERNEL);
 		if (!*ptr)
 			goto free;
-		for (pte = *ptr; pte < *ptr + PTRS_PER_PTE; pte++)
-			pte_clear (pte);
+		init_ptes (*ptr, PTES_PER_PAGE);
 	}
 
 	/* The last one is probably not of PAGE_SIZE: we use kmalloc */
@@ -573,8 +594,7 @@
 		*ptr = kmalloc (last*sizeof(pte_t), GFP_KERNEL);
 		if (!*ptr)
 			goto free;
-		for (pte = *ptr; pte < *ptr + last; pte++)
-			pte_clear (pte);
+		init_ptes (*ptr, last);
 	}
 	if (doacc) {
 		shm_lockall();
@@ -597,14 +617,14 @@
 static void shm_free(pte_t** dir, unsigned long pages, int doacc)
 {
 	int i, rss, swp;
-	pte_t **ptr = dir+pages/PTRS_PER_PTE;
+	pte_t **ptr = dir+pages/PTES_PER_PAGE;
 
 	if (!dir)
 		return;
 
 	for (i = 0, rss = 0, swp = 0; i < pages ; i++) {
 		pte_t pte;
-		pte = dir[i/PTRS_PER_PTE][i%PTRS_PER_PTE];
+		pte = dir[i/PTES_PER_PAGE][i%PTES_PER_PAGE];
 		if (pte_none(pte))
 			continue;
 		if (pte_present(pte)) {
@@ -617,7 +637,7 @@
 	}
 
 	/* first the last page */
-	if (pages%PTRS_PER_PTE)
+	if (pages%PTES_PER_PAGE)
 		kfree (*ptr);
 	/* now the whole pages */
 	while (--ptr >= dir)
@@ -663,10 +683,10 @@
 		BUG();
 	error = -ENOSPC;
 	if (shm_tot - shp->shm_npages >= shm_ctlall)
-		goto out;
+		goto size_out;
 	error = 0;
 	if (shp->shm_segsz == attr->ia_size)
-		goto out;
+		goto size_out;
 	/* Now we set them to the real values */
 	old_dir = shp->shm_dir;
 	old_pages = shp->shm_npages;
@@ -674,8 +694,8 @@
 		pte_t *swap;
 		int i,j;
 		i = old_pages < new_pages ? old_pages : new_pages;
-		j = i % PTRS_PER_PTE;
-		i /= PTRS_PER_PTE;
+		j = i % PTES_PER_PAGE;
+		i /= PTES_PER_PAGE;
 		if (j)
 			memcpy (new_dir[i], old_dir[i], j * sizeof (pte_t));
 		while (i--) {
@@ -687,10 +707,21 @@
 	shp->shm_dir = new_dir;
 	shp->shm_npages = new_pages;
 	shp->shm_segsz = attr->ia_size;
-out:
+size_out:
 	shm_unlock(inode->i_ino);
 	shm_free (old_dir, old_pages, 1);
+
 set_attr:
+	if (!(shp = shm_lock(inode->i_ino)))
+		BUG();
+	if (attr->ia_valid & ATTR_MODE)
+		shp->shm_perm.mode = attr->ia_mode;
+	if (attr->ia_valid & ATTR_UID)
+		shp->shm_perm.uid = attr->ia_uid;
+	if (attr->ia_valid & ATTR_GID)
+		shp->shm_perm.gid = attr->ia_gid;
+	shm_unlock (inode->i_ino);
+
 	inode_setattr(inode, attr);
 	return error;
 }
@@ -1073,6 +1104,9 @@
 
 	case IPC_SET:
 	{
+		struct dentry * dentry;
+		char name[SHM_FMT_LEN+1];
+
 		if ((shmid % SEQ_MULTIPLIER)== zero_id)
 			return -EINVAL;
 
@@ -1098,7 +1132,29 @@
 		shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
 			| (setbuf.mode & S_IRWXUGO);
 		shp->shm_ctim = CURRENT_TIME;
-		break;
+		shm_unlock(shmid);
+		up(&shm_ids.sem);
+
+		sprintf (name, SHM_FMT, shmid);
+		lock_kernel();
+		dentry = lookup_one(name, lock_parent(shm_sb->s_root));
+		unlock_dir(shm_sb->s_root);
+		err = PTR_ERR(dentry);
+		if (IS_ERR(dentry))
+			goto bad_dentry;
+		err = -ENOENT;
+		if (dentry->d_inode) {
+			struct inode *ino = dentry->d_inode;
+			ino->i_uid   = setbuf.uid;
+			ino->i_gid   = setbuf.gid;
+			ino->i_mode  = (setbuf.mode & S_IRWXUGO) | (ino->i_mode & ~S_IALLUGO);;
+			ino->i_atime = ino->i_mtime = ino->i_ctime = CURRENT_TIME;
+			err = 0;
+		}
+		dput (dentry);
+	bad_dentry:
+		unlock_kernel();
+		return err;
 	}
 
 	default:
@@ -1492,7 +1548,7 @@
 	shm_lockall();
 check_id:
 	shp = shm_get(swap_id);
-	if(shp==NULL || shp->shm_flags & SHM_LOCKED) {
+	if(shp==NULL || shp->shm_flags & PRV_LOCKED) {
 next_id:
 		swap_idx = 0;
 		if (++swap_id > shm_ids.max_id) {
diff -uNr 4-1-ac7/ipc/util.c c1/ipc/util.c
--- 4-1-ac7/ipc/util.c	Wed May 24 09:10:57 2000
+++ c1/ipc/util.c	Wed May 31 20:30:48 2000
@@ -310,7 +310,7 @@
 
 int map_zero_setup(struct vm_area_struct *vma)
 {
-	return -EINVAL;
+	return -ENOSYS;
 }
 
 #endif /* CONFIG_SYSVIPC */