summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <jdike>2003-12-16 16:22:37 +0000
committerjdike <jdike>2003-12-16 16:22:37 +0000
commit7a324af8249ceb1048dbe7a98eac55e03ea29d71 (patch)
treec0a28c1cc7c9165de3c5b0fae3af245750d5c9ea
parentc9d8c123fdca02c3d20587050e27fc3fd70741bd (diff)
downloaduml-history-7a324af8249ceb1048dbe7a98eac55e03ea29d71.tar.gz
Added /dev/anon.v_2_4_22_7
-rw-r--r--include/linux/shmem_fs.h43
-rw-r--r--mm/shmem.c104
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
diff --git a/mm/shmem.c b/mm/shmem.c
index be770f9..a044222 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -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,
};