shm cleanup (2)
Subsystems (9)
A message that is not in the archive (sent off-list or not yet received): [email protected]
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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/