Skip to contentSkip to conversation

shm cleanup (2)

PATCH New Christoph Rohland 1 participant 1 message Dec 13, 2000 1 message not in the archive

Subsystems (9)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 1/1 shm cleanup (2)

Hi all,

Here is my latest patch. It survived ten hours stress testing on my 8way/870MB without oops. (The highmem stuff is too much io/kmap limited and I will come back to this if we have the mm cleanup ready :-( )

It apparently has some race condition left since I had some undead swap entries afterwards. Also the fs accounting was screwed.

I am pretty unsure how shmem_writepage and shmem_nopage can race and nopage hold the inode semaphore against races against itself and truncate. Somebody out there to enlighten me?

Greetings
Christoph

drivers/char/mem.c +1 -1
diff -uNr 4-12-8/drivers/char/mem.c c/drivers/char/mem.c
@@ -438,7 +438,7 @@
 static int mmap_zero(struct file * file, struct vm_area_struct * vma)
 {
 	if (vma->vm_flags & VM_SHARED)
-		return map_zero_setup(vma);
+		return shmem_zero_setup(vma);
 	if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
include/linux/fs.h +4 -0
diff -uNr 4-12-8/include/linux/fs.h c/include/linux/fs.h
@@ -283,6 +283,7 @@
 #include <linux/efs_fs_i.h>
 #include <linux/coda_fs_i.h>
 #include <linux/romfs_fs_i.h>
+#include <linux/shmem_fs.h>
 #include <linux/smb_fs_i.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/adfs_fs_i.h>
@@ -354,6 +355,7 @@
 struct address_space_operations {
 	int (*writepage)(struct page *);
 	int (*readpage)(struct file *, struct page *);
+	struct page * (*getpage)(struct address_space *, unsigned long); /* readpage with alloc */
 	int (*sync_page)(struct page *);
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
@@ -441,6 +443,7 @@
 		struct ufs_inode_info		ufs_i;
 		struct efs_inode_info		efs_i;
 		struct romfs_inode_info		romfs_i;
+		struct shmem_inode_info		shmem_i;
 		struct coda_inode_info		coda_i;
 		struct smb_inode_info		smbfs_i;
 		struct hfs_inode_info		hfs_i;
@@ -685,6 +688,7 @@
 		struct affs_sb_info	affs_sb;
 		struct ufs_sb_info	ufs_sb;
 		struct efs_sb_info	efs_sb;
+		struct shmem_sb_info	shmem_sb;
 		struct romfs_sb_info	romfs_sb;
 		struct smb_sb_info	smbfs_sb;
 		struct hfs_sb_info	hfs_sb;
include/linux/mm.h +4 -10
diff -uNr 4-12-8/include/linux/mm.h c/include/linux/mm.h
@@ -129,15 +129,6 @@
 };
 
 /*
- * A swap entry has to fit into a "unsigned long", as
- * the entry is hidden in the "index" field of the
- * swapper address space.
- */
-typedef struct {
-	unsigned long val;
-} swp_entry_t;
-
-/*
  * Try to keep the most commonly accessed fields in single cache lines
  * here (16 bytes or greater).  This ordering should be particularly
  * beneficial on 32-bit processors.
@@ -390,7 +381,10 @@
 
 extern void clear_page_tables(struct mm_struct *, unsigned long, int);
 
-extern int map_zero_setup(struct vm_area_struct *);
+int shmem_swapout(struct page * page, struct file *file);
+struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share);
+struct file *shmem_file_setup(char * name, loff_t size);
+extern int shmem_zero_setup(struct vm_area_struct *);
 
 extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
 extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
include/linux/pagemap.h +2 -0
diff -uNr 4-12-8/include/linux/pagemap.h c/include/linux/pagemap.h
@@ -67,6 +67,8 @@
 
 #define page_hash(mapping,index) (page_hash_table+_page_hashfn(mapping,index))
 
+extern struct page * __find_get_page(struct address_space *mapping,
+				     unsigned long offset, struct page **hash);
 extern struct page * __find_lock_page (struct address_space * mapping,
 				unsigned long index, struct page **hash);
 extern void lock_page(struct page *page);
include/linux/shmem_fs.h +37 -0
diff -uNr 4-12-8/include/linux/shmem_fs.h c/include/linux/shmem_fs.h
@@ -0,0 +1,37 @@
+#ifndef __SHMEM_FS_H
+#define __SHMEM_FS_H
+
+/* inode in-kernel data */
+
+#define SHMEM_NR_DIRECT 16
+
+/*
+ * A swap entry has to fit into a "unsigned long", as
+ * the entry is hidden in the "index" field of the
+ * swapper address space.
+ */
+typedef struct {
+	unsigned long val;
+} swp_entry_t;
+
+struct shmem_inode_info {
+	swp_entry_t	i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
+	swp_entry_t    *i_indirect; /* indirect blocks	  */
+	swp_entry_t   **i_double;   /* doubly indirect blocks */
+	struct list_head	list;
+	spinlock_t	stat_lock; /* This protects the swapped
+                                      field. We need it since
+                                      shmem_writepage has to modify it
+                                      and cannot get inode->i_sem */
+        unsigned long	swapped;
+};
+
+struct shmem_sb_info {
+	unsigned long max_blocks;   /* How many blocks are allowed */
+	unsigned long free_blocks;  /* How many are left for allocation */
+	unsigned long max_inodes;   /* How many inodes are allowed */
+	unsigned long free_inodes;  /* How many are left for allocation */
+	spinlock_t    stat_lock;
+};
+
+#endif
include/linux/swap.h +2 -0
diff -uNr 4-12-8/include/linux/swap.h c/include/linux/swap.h
@@ -291,6 +291,8 @@
 #define swap_device_lock(p)	spin_lock(&p->sdev_lock)
 #define swap_device_unlock(p)	spin_unlock(&p->sdev_lock)
 
+extern void shmem_unuse(swp_entry_t entry, struct page *page);
+
 #endif /* __KERNEL__*/
 
 #endif /* _LINUX_SWAP_H */
ipc/shm.c +168 -1222

1,644 lines not on this page · raw message

ipc/util.c +0 -14
diff -uNr 4-12-8/ipc/util.c c/ipc/util.c
@@ -345,11 +345,6 @@
     return;
 }
 
-int shm_swap (int prio, int gfp_mask)
-{
-    return 0;
-}
-
 asmlinkage long sys_semget (key_t key, int nsems, int semflg)
 {
 	return -ENOSYS;
@@ -404,15 +399,6 @@
 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 {
 	return -ENOSYS;
-}
-
-void shm_unuse(swp_entry_t entry, struct page *page)
-{
-}
-
-int map_zero_setup(struct vm_area_struct *vma)
-{
-	return -EINVAL;
 }
 
 #endif /* CONFIG_SYSVIPC */
kernel/sysctl.c +6 -0
diff -uNr 4-12-8/kernel/sysctl.c c/kernel/sysctl.c
@@ -63,6 +63,8 @@
 #endif
 #ifdef CONFIG_SYSVIPC
 extern size_t shm_ctlmax;
+extern size_t shm_ctlall;
+extern int shm_ctlmni;
 extern int msg_ctlmax;
 extern int msg_ctlmnb;
 extern int msg_ctlmni;
@@ -208,6 +210,10 @@
 #ifdef CONFIG_SYSVIPC
 	{KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
 	 0644, NULL, &proc_doulongvec_minmax},
+	{KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t),
+	 0644, NULL, &proc_doulongvec_minmax},
+	{KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
+	 0644, NULL, &proc_dointvec},
 	{KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
mm/Makefile +2 -1
diff -uNr 4-12-8/mm/Makefile c/mm/Makefile
@@ -10,7 +10,8 @@
 O_TARGET := mm.o
 O_OBJS	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
-	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o
+	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
+	    shmem.o
 
 ifeq ($(CONFIG_HIGHMEM),y)
 O_OBJS += highmem.o
mm/filemap.c +2 -2
diff -uNr 4-12-8/mm/filemap.c c/mm/filemap.c
@@ -542,8 +542,8 @@
  * a rather lightweight function, finding and getting a reference to a
  * hashed page atomically, waiting for it if it's locked.
  */
-static struct page * __find_get_page(struct address_space *mapping,
-				unsigned long offset, struct page **hash)
+struct page * __find_get_page(struct address_space *mapping,
+			      unsigned long offset, struct page **hash)
 {
 	struct page *page;
 
mm/mmap.c +1 -1
diff -uNr 4-12-8/mm/mmap.c c/mm/mmap.c
@@ -333,7 +333,7 @@
 		if (error)
 			goto unmap_and_free_vma;
 	} else if (flags & MAP_SHARED) {
-		error = map_zero_setup(vma);
+		error = shmem_zero_setup(vma);
 		if (error)
 			goto free_vma;
 	}
mm/shmem.c +897 -0

897 lines not on this page · raw message

mm/swapfile.c +1 -1
diff -uNr 4-12-8/mm/swapfile.c c/mm/swapfile.c
@@ -375,7 +375,7 @@
 		for_each_task(p)
 			unuse_process(p->mm, entry, page);
 		read_unlock(&tasklist_lock);
-		shm_unuse(entry, page);
+		shmem_unuse(entry, page);
 		/* Now get rid of the extra reference to the temporary
                    page we've been using. */
 		if (PageSwapCache(page))

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
Please read the FAQ at http://www.tux.org/lkml/