Commit d9acf5fe authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds

[PATCH] shmem_file_setup when MAP_NORESERVE

If we support mmap MAP_NORESERVE, we should support it on shared
anonymous objects: too bad that needs a few changes.  do_mmap_pgoff pass
VM_ACCOUNT (or not) down to shmem_file_setup, flag stored into shmem
info, for use by shmem_delete_inode later.  Also removed a harmless but
pointless call to shmem_truncate.
parent de16834e
...@@ -331,7 +331,7 @@ extern void show_free_areas(void); ...@@ -331,7 +331,7 @@ extern void show_free_areas(void);
extern int fail_writepage(struct page *); extern int fail_writepage(struct page *);
struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int unused); struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int unused);
struct file *shmem_file_setup(char * name, loff_t size); struct file *shmem_file_setup(char * name, loff_t size, unsigned long flags);
extern void shmem_lock(struct file * file, int lock); extern void shmem_lock(struct file * file, int lock);
extern int shmem_zero_setup(struct vm_area_struct *); extern int shmem_zero_setup(struct vm_area_struct *);
......
...@@ -16,7 +16,7 @@ struct shmem_inode_info { ...@@ -16,7 +16,7 @@ struct shmem_inode_info {
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */ swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
void **i_indirect; /* indirect blocks */ void **i_indirect; /* indirect blocks */
unsigned long swapped; unsigned long swapped;
int locked; /* into memory */ unsigned long flags;
struct list_head list; struct list_head list;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
...@@ -186,7 +186,7 @@ static int newseg (key_t key, int shmflg, size_t size) ...@@ -186,7 +186,7 @@ static int newseg (key_t key, int shmflg, size_t size)
shp->shm_flags = (shmflg & S_IRWXUGO); shp->shm_flags = (shmflg & S_IRWXUGO);
sprintf (name, "SYSV%08x", key); sprintf (name, "SYSV%08x", key);
file = shmem_file_setup(name, size); file = shmem_file_setup(name, size, VM_ACCOUNT);
error = PTR_ERR(file); error = PTR_ERR(file);
if (IS_ERR(file)) if (IS_ERR(file))
goto no_file; goto no_file;
......
...@@ -528,7 +528,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, ...@@ -528,7 +528,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
return -ENOMEM; return -ENOMEM;
if (!(flags & MAP_NORESERVE) || sysctl_overcommit_memory > 1) { if (!(flags & MAP_NORESERVE) || sysctl_overcommit_memory > 1) {
if ((vm_flags & (VM_SHARED|VM_WRITE)) == VM_WRITE) { if (vm_flags & VM_SHARED) {
/* Check memory availability in shmem_file_setup? */
vm_flags |= VM_ACCOUNT;
} else if (vm_flags & VM_WRITE) {
/* Private writable mapping: check memory availability */ /* Private writable mapping: check memory availability */
charged = len >> PAGE_SHIFT; charged = len >> PAGE_SHIFT;
if (!vm_enough_memory(charged)) if (!vm_enough_memory(charged))
...@@ -583,6 +586,14 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, ...@@ -583,6 +586,14 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
goto free_vma; goto free_vma;
} }
/* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform
* shmem_zero_setup (perhaps called through /dev/zero's ->mmap)
* that memory reservation must be checked; but that reservation
* belongs to shared memory object, not to vma: so now clear it.
*/
if ((vm_flags & (VM_SHARED|VM_ACCOUNT)) == (VM_SHARED|VM_ACCOUNT))
vma->vm_flags &= ~VM_ACCOUNT;
/* Can addr have changed?? /* Can addr have changed??
* *
* Answer: Yes, several device drivers can do it in their * Answer: Yes, several device drivers can do it in their
......
...@@ -392,12 +392,14 @@ static int shmem_notify_change(struct dentry * dentry, struct iattr *attr) ...@@ -392,12 +392,14 @@ static int shmem_notify_change(struct dentry * dentry, struct iattr *attr)
static void shmem_delete_inode(struct inode * inode) static void shmem_delete_inode(struct inode * inode)
{ {
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
struct shmem_inode_info *info = SHMEM_I(inode);
if (inode->i_op->truncate == shmem_truncate) { if (inode->i_op->truncate == shmem_truncate) {
spin_lock (&shmem_ilock); spin_lock(&shmem_ilock);
list_del (&SHMEM_I(inode)->list); list_del(&info->list);
spin_unlock (&shmem_ilock); spin_unlock(&shmem_ilock);
vm_unacct_memory(VM_ACCT(inode->i_size)); if (info->flags & VM_ACCOUNT)
vm_unacct_memory(VM_ACCT(inode->i_size));
inode->i_size = 0; inode->i_size = 0;
shmem_truncate (inode); shmem_truncate (inode);
} }
...@@ -526,7 +528,7 @@ static int shmem_writepage(struct page * page) ...@@ -526,7 +528,7 @@ static int shmem_writepage(struct page * page)
index = page->index; index = page->index;
inode = mapping->host; inode = mapping->host;
info = SHMEM_I(inode); info = SHMEM_I(inode);
if (info->locked) if (info->flags & VM_LOCKED)
return fail_writepage(page); return fail_writepage(page);
swap = get_swap_page(); swap = get_swap_page();
if (!swap.val) if (!swap.val)
...@@ -743,9 +745,12 @@ void shmem_lock(struct file * file, int lock) ...@@ -743,9 +745,12 @@ void shmem_lock(struct file * file, int lock)
struct inode * inode = file->f_dentry->d_inode; struct inode * inode = file->f_dentry->d_inode;
struct shmem_inode_info * info = SHMEM_I(inode); struct shmem_inode_info * info = SHMEM_I(inode);
down(&info->sem); spin_lock(&info->lock);
info->locked = lock; if (lock)
up(&info->sem); info->flags |= VM_LOCKED;
else
info->flags &= ~VM_LOCKED;
spin_unlock(&info->lock);
} }
static int shmem_mmap(struct file * file, struct vm_area_struct * vma) static int shmem_mmap(struct file * file, struct vm_area_struct * vma)
...@@ -792,7 +797,7 @@ struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev) ...@@ -792,7 +797,7 @@ struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
memset (info->i_direct, 0, sizeof(info->i_direct)); memset (info->i_direct, 0, sizeof(info->i_direct));
info->i_indirect = NULL; info->i_indirect = NULL;
info->swapped = 0; info->swapped = 0;
info->locked = 0; info->flags = VM_ACCOUNT;
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
default: default:
init_special_inode(inode, mode, dev); init_special_inode(inode, mode, dev);
...@@ -1652,7 +1657,7 @@ module_exit(exit_shmem_fs) ...@@ -1652,7 +1657,7 @@ module_exit(exit_shmem_fs)
* @size: size to be set for the file * @size: size to be set for the file
* *
*/ */
struct file *shmem_file_setup(char * name, loff_t size) struct file *shmem_file_setup(char * name, loff_t size, unsigned long flags)
{ {
int error; int error;
struct file *file; struct file *file;
...@@ -1663,7 +1668,7 @@ struct file *shmem_file_setup(char * name, loff_t size) ...@@ -1663,7 +1668,7 @@ struct file *shmem_file_setup(char * name, loff_t size)
if (size > SHMEM_MAX_BYTES) if (size > SHMEM_MAX_BYTES)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
if (!vm_enough_memory(VM_ACCT(size))) if ((flags & VM_ACCOUNT) && !vm_enough_memory(VM_ACCT(size)))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
error = -ENOMEM; error = -ENOMEM;
...@@ -1685,14 +1690,14 @@ struct file *shmem_file_setup(char * name, loff_t size) ...@@ -1685,14 +1690,14 @@ struct file *shmem_file_setup(char * name, loff_t size)
if (!inode) if (!inode)
goto close_file; goto close_file;
SHMEM_I(inode)->flags &= flags;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
dentry->d_inode->i_size = size; inode->i_size = size;
shmem_truncate(inode); inode->i_nlink = 0; /* It is unlinked */
file->f_vfsmnt = mntget(shm_mnt); file->f_vfsmnt = mntget(shm_mnt);
file->f_dentry = dentry; file->f_dentry = dentry;
file->f_op = &shmem_file_operations; file->f_op = &shmem_file_operations;
file->f_mode = FMODE_WRITE | FMODE_READ; file->f_mode = FMODE_WRITE | FMODE_READ;
inode->i_nlink = 0; /* It is unlinked */
return(file); return(file);
close_file: close_file:
...@@ -1700,7 +1705,8 @@ struct file *shmem_file_setup(char * name, loff_t size) ...@@ -1700,7 +1705,8 @@ struct file *shmem_file_setup(char * name, loff_t size)
put_dentry: put_dentry:
dput (dentry); dput (dentry);
put_memory: put_memory:
vm_unacct_memory(VM_ACCT(size)); if (flags & VM_ACCOUNT)
vm_unacct_memory(VM_ACCT(size));
return ERR_PTR(error); return ERR_PTR(error);
} }
...@@ -1714,7 +1720,7 @@ int shmem_zero_setup(struct vm_area_struct *vma) ...@@ -1714,7 +1720,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
struct file *file; struct file *file;
loff_t size = vma->vm_end - vma->vm_start; loff_t size = vma->vm_end - vma->vm_start;
file = shmem_file_setup("dev/zero", size); file = shmem_file_setup("dev/zero", size, vma->vm_flags);
if (IS_ERR(file)) if (IS_ERR(file))
return PTR_ERR(file); return PTR_ERR(file);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment