diff options
author | jdike <jdike> | 2003-12-16 16:22:37 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-12-16 16:22:37 +0000 |
commit | 7a324af8249ceb1048dbe7a98eac55e03ea29d71 (patch) | |
tree | c0a28c1cc7c9165de3c5b0fae3af245750d5c9ea | |
parent | c9d8c123fdca02c3d20587050e27fc3fd70741bd (diff) | |
download | uml-history-7a324af8249ceb1048dbe7a98eac55e03ea29d71.tar.gz |
Added /dev/anon.v_2_4_22_7
-rw-r--r-- | include/linux/shmem_fs.h | 43 | ||||
-rw-r--r-- | mm/shmem.c | 104 |
2 files changed, 131 insertions, 16 deletions
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h new file mode 100644 index 0000000..b0f71f5 --- /dev/null +++ b/include/linux/shmem_fs.h @@ -0,0 +1,43 @@ +#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. + * + * We have to move it here, since not every user of fs.h is including + * mm.h, but mm.h is including fs.h via sched .h :-/ + */ +typedef struct { + unsigned long val; +} swp_entry_t; + +struct shmem_inode_info { + spinlock_t lock; + unsigned long next_index; + swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */ + void **i_indirect; /* indirect blocks */ + unsigned long map_direct[SHMEM_NR_DIRECT]; + void **map_indirect; + unsigned long swapped; /* data pages assigned to swap */ + unsigned long flags; + struct list_head list; + struct inode *inode; +}; + +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; +}; + +#define SHMEM_I(inode) (&inode->u.shmem_i) + +#endif @@ -124,16 +124,17 @@ static void shmem_removepage(struct page *page) * +-> 48-51 * +-> 52-55 */ -static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page) +static void *shmem_block(unsigned long index, unsigned long *page, + unsigned long *direct, void ***indirect) { unsigned long offset; void **dir; if (index < SHMEM_NR_DIRECT) - return info->i_direct+index; - if (!info->i_indirect) { + return direct+index; + if (!*indirect) { if (page) { - info->i_indirect = (void **) *page; + *indirect = (void **) *page; *page = 0; } return NULL; /* need another page */ @@ -142,7 +143,7 @@ static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index -= SHMEM_NR_DIRECT; offset = index % ENTRIES_PER_PAGE; index /= ENTRIES_PER_PAGE; - dir = info->i_indirect; + dir = *indirect; if (index >= ENTRIES_PER_PAGE/2) { index -= ENTRIES_PER_PAGE/2; @@ -165,7 +166,21 @@ static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long *dir = (void *) *page; *page = 0; } - return (swp_entry_t *) *dir + offset; + return (unsigned long **) *dir + offset; +} + +static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page) +{ + return((swp_entry_t *) shmem_block(index, page, + (unsigned long *) info->i_direct, + &info->i_indirect)); +} + +static unsigned long *shmem_map_count(struct shmem_inode_info *info, + unsigned long index, unsigned long *page) +{ + return((unsigned long *) shmem_block(index, page, info->map_direct, + &info->map_indirect)); } /* @@ -801,6 +816,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma) ops = &shmem_vm_ops; if (!S_ISREG(inode->i_mode)) return -EACCES; + UPDATE_ATIME(inode); vma->vm_ops = ops; return 0; @@ -1677,6 +1693,35 @@ int shmem_zero_setup(struct vm_area_struct *vma) return 0; } +static int adjust_map_counts(struct shmem_inode_info *info, + unsigned long offset, unsigned long len, + int adjust) +{ + unsigned long idx, i, *count, page = 0; + + spin_lock(&info->lock); + offset >>= PAGE_SHIFT; + len >>= PAGE_SHIFT; + for(i = 0; i < len; i++){ + idx = (i + offset) >> (PAGE_CACHE_SHIFT - PAGE_SHIFT); + + while((count = shmem_map_count(info, idx, &page)) == NULL){ + spin_unlock(&info->lock); + page = get_zeroed_page(GFP_KERNEL); + if(page == 0) + return(-ENOMEM); + spin_lock(&info->lock); + } + + if(page != 0) + free_page(page); + + *count += adjust; + } + spin_unlock(&info->lock); + return(0); +} + EXPORT_SYMBOL(shmem_file_setup); struct file_operations anon_file_operations; @@ -1684,7 +1729,9 @@ struct file_operations anon_file_operations; static int anon_mmap(struct file *file, struct vm_area_struct *vma) { struct file *new; + struct inode *inode; loff_t size = vma->vm_end - vma->vm_start; + int err; if(file->private_data == NULL){ new = shmem_file_setup("dev/anon", size); @@ -1700,6 +1747,11 @@ static int anon_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_file = file->private_data; get_file(vma->vm_file); + inode = vma->vm_file->f_dentry->d_inode; + err = adjust_map_counts(SHMEM_I(inode), vma->vm_pgoff, size, 1); + if(err) + return(err); + vma->vm_ops = &shmem_vm_ops; return 0; } @@ -1707,13 +1759,25 @@ static int anon_mmap(struct file *file, struct vm_area_struct *vma) static void anon_munmap(struct file *file, struct vm_area_struct *vma, unsigned long start, unsigned long len) { + struct inode *inode = file->f_dentry->d_inode; + struct shmem_inode_info *info = SHMEM_I(inode); pgd_t *pgd; pmd_t *pmd; pte_t *pte; struct page *page; - unsigned long addr; + unsigned long addr, idx, *count; for(addr = start; addr < start + len; addr += PAGE_SIZE){ + idx = (addr - vma->vm_start + vma->vm_pgoff); + idx >>= PAGE_CACHE_SHIFT; + + count = shmem_map_count(info, idx, NULL); + BUG_ON(count == NULL); + + (*count)--; + if(*count > 0) + continue; + pgd = pgd_offset(vma->vm_mm, addr); if(pgd_none(*pgd)) continue; @@ -1726,20 +1790,28 @@ static void anon_munmap(struct file *file, struct vm_area_struct *vma, if(!pte_present(*pte)) /* XXX need to handle swapped pages */ continue; + *pte = pte_mkclean(*pte); + page = pte_page(*pte); - printk("shmem_unmap - page = 0x%p\n", page); - - if (page_count(page) == 2){ - LockPage(page); - lru_cache_del(page); - remove_inode_page(page); - UnlockPage(page); - page_cache_release(page); - } + LockPage(page); + lru_cache_del(page); + ClearPageDirty(page); + remove_inode_page(page); + UnlockPage(page); + + page_cache_release(page); } } +int anon_release(struct inode *inode, struct file *file) +{ + if(file->private_data != NULL) + fput(file->private_data); + return(0); +} + struct file_operations anon_file_operations = { .mmap = anon_mmap, .munmap = anon_munmap, + .release = anon_release, }; |