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

Commit 5a6fe125 authored by Mel Gorman's avatar Mel Gorman Committed by Linus Torvalds
Browse files

Do not account for the address space used by hugetlbfs using VM_ACCOUNT



When overcommit is disabled, the core VM accounts for pages used by anonymous
shared, private mappings and special mappings. It keeps track of VMAs that
should be accounted for with VM_ACCOUNT and VMAs that never had a reserve
with VM_NORESERVE.

Overcommit for hugetlbfs is much riskier than overcommit for base pages
due to contiguity requirements. It avoids overcommiting on both shared and
private mappings using reservation counters that are checked and updated
during mmap(). This ensures (within limits) that hugepages exist in the
future when faults occurs or it is too easy to applications to be SIGKILLed.

As hugetlbfs makes its own reservations of a different unit to the base page
size, VM_ACCOUNT should never be set. Even if the units were correct, we would
double account for the usage in the core VM and hugetlbfs. VM_NORESERVE may
be set because an application can request no reserves be made for hugetlbfs
at the risk of getting killed later.

With commit fc8744ad, VM_NORESERVE and
VM_ACCOUNT are getting unconditionally set for hugetlbfs-backed mappings. This
breaks the accounting for both the core VM and hugetlbfs, can trigger an
OOM storm when hugepage pools are too small lockups and corrupted counters
otherwise are used. This patch brings hugetlbfs more in line with how the
core VM treats VM_NORESERVE but prevents VM_ACCOUNT being set.

Signed-off-by: default avatarMel Gorman <mel@csn.ul.ie>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 4c098bcd
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -108,7 +108,8 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)

	if (hugetlb_reserve_pages(inode,
				vma->vm_pgoff >> huge_page_order(h),
				len >> huge_page_shift(h), vma))
				len >> huge_page_shift(h), vma,
				vma->vm_flags))
		goto out;

	ret = 0;
@@ -947,7 +948,7 @@ static int can_do_hugetlb_shm(void)
			can_do_mlock());
}

struct file *hugetlb_file_setup(const char *name, size_t size)
struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
{
	int error = -ENOMEM;
	struct file *file;
@@ -981,7 +982,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size)

	error = -ENOMEM;
	if (hugetlb_reserve_pages(inode, 0,
			size >> huge_page_shift(hstate_inode(inode)), NULL))
			size >> huge_page_shift(hstate_inode(inode)), NULL,
			acctflag))
		goto out_inode;

	d_instantiate(dentry, inode);
+3 −2
Original line number Diff line number Diff line
@@ -33,7 +33,8 @@ unsigned long hugetlb_total_pages(void);
int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
			unsigned long address, int write_access);
int hugetlb_reserve_pages(struct inode *inode, long from, long to,
						struct vm_area_struct *vma);
						struct vm_area_struct *vma,
						int acctflags);
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);

extern unsigned long hugepages_treat_as_movable;
@@ -138,7 +139,7 @@ static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb)

extern const struct file_operations hugetlbfs_file_operations;
extern struct vm_operations_struct hugetlb_vm_ops;
struct file *hugetlb_file_setup(const char *name, size_t);
struct file *hugetlb_file_setup(const char *name, size_t, int);
int hugetlb_get_quota(struct address_space *mapping, long delta);
void hugetlb_put_quota(struct address_space *mapping, long delta);

+1 −2
Original line number Diff line number Diff line
@@ -1129,8 +1129,7 @@ extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
	unsigned long flag, unsigned long pgoff);
extern unsigned long mmap_region(struct file *file, unsigned long addr,
	unsigned long len, unsigned long flags,
	unsigned int vm_flags, unsigned long pgoff,
	int accountable);
	unsigned int vm_flags, unsigned long pgoff);

static inline unsigned long do_mmap(struct file *file, unsigned long addr,
	unsigned long len, unsigned long prot,
+5 −3
Original line number Diff line number Diff line
@@ -340,6 +340,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
	struct file * file;
	char name[13];
	int id;
	int acctflag = 0;

	if (size < SHMMIN || size > ns->shm_ctlmax)
		return -EINVAL;
@@ -364,11 +365,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)

	sprintf (name, "SYSV%08x", key);
	if (shmflg & SHM_HUGETLB) {
		/* hugetlb_file_setup takes care of mlock user accounting */
		file = hugetlb_file_setup(name, size);
		/* hugetlb_file_setup applies strict accounting */
		if (shmflg & SHM_NORESERVE)
			acctflag = VM_NORESERVE;
		file = hugetlb_file_setup(name, size, acctflag);
		shp->mlock_user = current_user();
	} else {
		int acctflag = 0;
		/*
		 * Do not allow no accounting for OVERCOMMIT_NEVER, even
	 	 * if it's asked for.
+1 −1
Original line number Diff line number Diff line
@@ -198,7 +198,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
			flags &= MAP_NONBLOCK;
			get_file(file);
			addr = mmap_region(file, start, size,
					flags, vma->vm_flags, pgoff, 1);
					flags, vma->vm_flags, pgoff);
			fput(file);
			if (IS_ERR_VALUE(addr)) {
				err = addr;
Loading