| /* | |
| * tiny-shmem.c: simple shmemfs and tmpfs using ramfs code | |
| * | |
| * Matt Mackall <mpm@selenic.com> January, 2004 | |
| * derived from mm/shmem.c and fs/ramfs/inode.c | |
| * | |
| * This is intended for small system where the benefits of the full | |
| * shmem code (swap-backed and resource-limited) are outweighed by | |
| * their complexity. On systems without swap this code should be | |
| * effectively equivalent, but much lighter weight. | |
| */ | |
| #include <linux/fs.h> | |
| #include <linux/init.h> | |
| #include <linux/vfs.h> | |
| #include <linux/mount.h> | |
| #include <linux/file.h> | |
| #include <linux/mm.h> | |
| #include <linux/module.h> | |
| #include <linux/swap.h> | |
| #include <linux/ramfs.h> | |
| static struct file_system_type tmpfs_fs_type = { | |
| .name = "tmpfs", | |
| .get_sb = ramfs_get_sb, | |
| .kill_sb = kill_litter_super, | |
| }; | |
| static struct vfsmount *shm_mnt; | |
| static int __init init_tmpfs(void) | |
| { | |
| BUG_ON(register_filesystem(&tmpfs_fs_type) != 0); | |
| shm_mnt = kern_mount(&tmpfs_fs_type); | |
| BUG_ON(IS_ERR(shm_mnt)); | |
| return 0; | |
| } | |
| module_init(init_tmpfs) | |
| /* | |
| * shmem_file_setup - get an unlinked file living in tmpfs | |
| * | |
| * @name: name for dentry (to be seen in /proc/<pid>/maps | |
| * @size: size to be set for the file | |
| * | |
| */ | |
| struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) | |
| { | |
| int error; | |
| struct file *file; | |
| struct inode *inode; | |
| struct dentry *dentry, *root; | |
| struct qstr this; | |
| if (IS_ERR(shm_mnt)) | |
| return (void *)shm_mnt; | |
| error = -ENOMEM; | |
| this.name = name; | |
| this.len = strlen(name); | |
| this.hash = 0; /* will go */ | |
| root = shm_mnt->mnt_root; | |
| dentry = d_alloc(root, &this); | |
| if (!dentry) | |
| goto put_memory; | |
| error = -ENFILE; | |
| file = get_empty_filp(); | |
| if (!file) | |
| goto put_dentry; | |
| error = -ENOSPC; | |
| inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); | |
| if (!inode) | |
| goto close_file; | |
| d_instantiate(dentry, inode); | |
| inode->i_nlink = 0; /* It is unlinked */ | |
| file->f_vfsmnt = mntget(shm_mnt); | |
| file->f_dentry = dentry; | |
| file->f_mapping = inode->i_mapping; | |
| file->f_op = &ramfs_file_operations; | |
| file->f_mode = FMODE_WRITE | FMODE_READ; | |
| /* notify everyone as to the change of file size */ | |
| error = do_truncate(dentry, size, 0, file); | |
| if (error < 0) | |
| goto close_file; | |
| return file; | |
| close_file: | |
| put_filp(file); | |
| put_dentry: | |
| dput(dentry); | |
| put_memory: | |
| return ERR_PTR(error); | |
| } | |
| /* | |
| * shmem_zero_setup - setup a shared anonymous mapping | |
| * | |
| * @vma: the vma to be mmapped is prepared by do_mmap_pgoff | |
| */ | |
| int shmem_zero_setup(struct vm_area_struct *vma) | |
| { | |
| struct file *file; | |
| loff_t size = vma->vm_end - vma->vm_start; | |
| file = shmem_file_setup("dev/zero", size, vma->vm_flags); | |
| if (IS_ERR(file)) | |
| return PTR_ERR(file); | |
| if (vma->vm_file) | |
| fput(vma->vm_file); | |
| vma->vm_file = file; | |
| vma->vm_ops = &generic_file_vm_ops; | |
| return 0; | |
| } | |
| int shmem_unuse(swp_entry_t entry, struct page *page) | |
| { | |
| return 0; | |
| } | |
| int shmem_mmap(struct file *file, struct vm_area_struct *vma) | |
| { | |
| file_accessed(file); | |
| #ifndef CONFIG_MMU | |
| return ramfs_nommu_mmap(file, vma); | |
| #else | |
| return 0; | |
| #endif | |
| } | |
| #ifndef CONFIG_MMU | |
| unsigned long shmem_get_unmapped_area(struct file *file, | |
| unsigned long addr, | |
| unsigned long len, | |
| unsigned long pgoff, | |
| unsigned long flags) | |
| { | |
| return ramfs_nommu_get_unmapped_area(file, addr, len, pgoff, flags); | |
| } | |
| #endif |