Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b0a0806 authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds
Browse files

shmem: fix shared anonymous accounting



Each time I exit Firefox, /proc/meminfo's Committed_AS goes down almost
400 kB: OVERCOMMIT_NEVER would be allowing overcommits it should
prohibit.

Commit fc8744ad "Stop playing silly
games with the VM_ACCOUNT flag" changed shmem_file_setup() to set the
shmem file's VM_ACCOUNT flag according to VM_NORESERVE not being set in
the vma flags; but did so only _after_ the shmem_acct_size(flags, size)
call which is expected to pre-account a shared anonymous object.

It's all clearer if we switch shmem.c over to use VM_NORESERVE
throughout in place of !VM_ACCOUNT.

But I very nearly sent in a patch which mistakenly removed the
accounting from tmpfs files: shmem_get_inode()'s memset was good for not
setting VM_ACCOUNT, but now it needs to set VM_NORESERVE.

Rather than setting that by default, then perhaps clearing it again in
shmem_file_setup(), let's pass it as a flag to shmem_get_inode(): that
allows us to remove the #ifdef CONFIG_SHMEM from shmem_file_setup().

Signed-off-by: default avatarHugh Dickins <hugh@veritas.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c15d8a64
Loading
Loading
Loading
Loading
+21 −22
Original line number Original line Diff line number Diff line
@@ -169,13 +169,13 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
 */
 */
static inline int shmem_acct_size(unsigned long flags, loff_t size)
static inline int shmem_acct_size(unsigned long flags, loff_t size)
{
{
	return (flags & VM_ACCOUNT) ?
	return (flags & VM_NORESERVE) ?
		security_vm_enough_memory_kern(VM_ACCT(size)) : 0;
		0 : security_vm_enough_memory_kern(VM_ACCT(size));
}
}


static inline void shmem_unacct_size(unsigned long flags, loff_t size)
static inline void shmem_unacct_size(unsigned long flags, loff_t size)
{
{
	if (flags & VM_ACCOUNT)
	if (!(flags & VM_NORESERVE))
		vm_unacct_memory(VM_ACCT(size));
		vm_unacct_memory(VM_ACCT(size));
}
}


@@ -187,13 +187,13 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
 */
 */
static inline int shmem_acct_block(unsigned long flags)
static inline int shmem_acct_block(unsigned long flags)
{
{
	return (flags & VM_ACCOUNT) ?
	return (flags & VM_NORESERVE) ?
		0 : security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE));
		security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0;
}
}


static inline void shmem_unacct_blocks(unsigned long flags, long pages)
static inline void shmem_unacct_blocks(unsigned long flags, long pages)
{
{
	if (!(flags & VM_ACCOUNT))
	if (flags & VM_NORESERVE)
		vm_unacct_memory(pages * VM_ACCT(PAGE_CACHE_SIZE));
		vm_unacct_memory(pages * VM_ACCT(PAGE_CACHE_SIZE));
}
}


@@ -1515,8 +1515,8 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
	return 0;
	return 0;
}
}


static struct inode *
static struct inode *shmem_get_inode(struct super_block *sb, int mode,
shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
					dev_t dev, unsigned long flags)
{
{
	struct inode *inode;
	struct inode *inode;
	struct shmem_inode_info *info;
	struct shmem_inode_info *info;
@@ -1537,6 +1537,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
		info = SHMEM_I(inode);
		info = SHMEM_I(inode);
		memset(info, 0, (char *)inode - (char *)info);
		memset(info, 0, (char *)inode - (char *)info);
		spin_lock_init(&info->lock);
		spin_lock_init(&info->lock);
		info->flags = flags & VM_NORESERVE;
		INIT_LIST_HEAD(&info->swaplist);
		INIT_LIST_HEAD(&info->swaplist);


		switch (mode & S_IFMT) {
		switch (mode & S_IFMT) {
@@ -1779,9 +1780,10 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
static int
static int
shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
{
	struct inode *inode = shmem_get_inode(dir->i_sb, mode, dev);
	struct inode *inode;
	int error = -ENOSPC;
	int error = -ENOSPC;


	inode = shmem_get_inode(dir->i_sb, mode, dev, VM_NORESERVE);
	if (inode) {
	if (inode) {
		error = security_inode_init_security(inode, dir, NULL, NULL,
		error = security_inode_init_security(inode, dir, NULL, NULL,
						     NULL);
						     NULL);
@@ -1920,7 +1922,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
	if (len > PAGE_CACHE_SIZE)
	if (len > PAGE_CACHE_SIZE)
		return -ENAMETOOLONG;
		return -ENAMETOOLONG;


	inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
	inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
	if (!inode)
	if (!inode)
		return -ENOSPC;
		return -ENOSPC;


@@ -2332,7 +2334,7 @@ static int shmem_fill_super(struct super_block *sb,
	sb->s_flags |= MS_POSIXACL;
	sb->s_flags |= MS_POSIXACL;
#endif
#endif


	inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0);
	inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
	if (!inode)
	if (!inode)
		goto failed;
		goto failed;
	inode->i_uid = sbinfo->uid;
	inode->i_uid = sbinfo->uid;
@@ -2574,11 +2576,11 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
	return 0;
	return 0;
}
}


#define shmem_file_operations ramfs_file_operations
#define shmem_vm_ops				generic_file_vm_ops
#define shmem_vm_ops				generic_file_vm_ops
#define shmem_get_inode ramfs_get_inode
#define shmem_file_operations			ramfs_file_operations
#define shmem_acct_size(a, b) 0
#define shmem_get_inode(sb, mode, dev, flags)	ramfs_get_inode(sb, mode, dev)
#define shmem_unacct_size(a, b) do {} while (0)
#define shmem_acct_size(flags, size)		0
#define shmem_unacct_size(flags, size)		do {} while (0)
#define SHMEM_MAX_BYTES				LLONG_MAX
#define SHMEM_MAX_BYTES				LLONG_MAX


#endif /* CONFIG_SHMEM */
#endif /* CONFIG_SHMEM */
@@ -2589,7 +2591,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
 * shmem_file_setup - get an unlinked file living in tmpfs
 * shmem_file_setup - get an unlinked file living in tmpfs
 * @name: name for dentry (to be seen in /proc/<pid>/maps
 * @name: name for dentry (to be seen in /proc/<pid>/maps
 * @size: size to be set for the file
 * @size: size to be set for the file
 * @flags: vm_flags
 * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
 */
 */
struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
{
{
@@ -2623,13 +2625,10 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
		goto put_dentry;
		goto put_dentry;


	error = -ENOSPC;
	error = -ENOSPC;
	inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);
	inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags);
	if (!inode)
	if (!inode)
		goto close_file;
		goto close_file;


#ifdef CONFIG_SHMEM
	SHMEM_I(inode)->flags = (flags & VM_NORESERVE) ? 0 : VM_ACCOUNT;
#endif
	d_instantiate(dentry, inode);
	d_instantiate(dentry, inode);
	inode->i_size = size;
	inode->i_size = size;
	inode->i_nlink = 0;	/* It is unlinked */
	inode->i_nlink = 0;	/* It is unlinked */