Unverified Commit 9bf5acd3 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!5617 v4 Fix I/O high when memory almost met memcg limit

Merge Pull Request from: @ci-robot 
 
PR sync from: Liu Shixin <liushixin2@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/YUWR62XI3GBUH5FRJUVDNM5LZHRE2FMI/ 
Recently, when install package in a docker which almost reached its memory
limit, the installer has no respond severely for more than 15 minutes.
During this period, I/O stays high(~1G/s) and influence the whole machine.
I've constructed a use case as follows:

  1. create a docker:

	$ cat test.sh
	#!/bin/bash
  
	docker rm centos7 --force

	docker create --name centos7 --memory 4G --memory-swap 6G centos:7 /usr/sbin/init
	docker start centos7
	sleep 1

	docker cp ./alloc_page centos7:/
	docker cp ./reproduce.sh centos7:/

	docker exec -it centos7 /bin/bash

  2. try reproduce the problem in docker:

	$ cat reproduce.sh
	#!/bin/bash
  
	while true; do
		if [ "$flag" -eq 0 ]; then
			/alloc_page &
		fi

		sleep 30

		start_time=$(date +%s)
		yum install -y expect > /dev/null 2>&1

		end_time=$(date +%s)

		elapsed_time=$((end_time - start_time))

		echo "$elapsed_time seconds"
		yum remove -y expect > /dev/null 2>&1
	done

	$ cat alloc_page.c:
	#include <stdio.h>
	#include <stdlib.h>
	#include <unistd.h>
	#include <string.h>

	#define SIZE 1*1024*1024 //1M

	int main()
	{
		void *addr = NULL;
		int i;

		for (i = 0; i < 1024 * 6 - 50;i++) {
			addr = (void *)malloc(SIZE);
			if (!addr)
				return -1;

			memset(addr, 0, SIZE);
		}

		sleep(99999);
		return 0;
	}


We found that this problem is caused by a lot ot meaningless read-ahead.
Since the docker is almost met memory limit, the page will be reclaimed
immediately after read-ahead and will read-ahead again immediately.
The program is executed slowly and waste a lot of I/O resource.

These patches aim to break the read-ahead in above scenario.


Liu Shixin (2):
  mm/readahead: break read-ahead loop if filemap_add_folio return
    -ENOMEM
  mm/readahead: don't decrease mmap_miss when folio has workingset flags


-- 
2.25.1
 
https://gitee.com/openeuler/kernel/issues/I8EXN6 
 
Link:https://gitee.com/openeuler/kernel/pulls/5617

 

Reviewed-by: default avatarKefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents ea5b0315 7de56c05
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -3168,7 +3168,14 @@ void filemap_map_pages(struct vm_fault *vmf,
		if (xas.xa_index >= max_idx)
			goto unlock;

		if (mmap_miss > 0)
		/*
		 * If there are too many pages that are recently evicted
		 * in a file, they will probably continue to be evicted.
		 * In such situation, read-ahead is only a waste of IO.
		 * Don't decrease mmap_miss in this scenario to make sure
		 * we can stop read-ahead.
		 */
		if (mmap_miss > 0 && !PageWorkingset(page))
			mmap_miss--;

		vmf->address += (xas.xa_index - last_pgoff) << PAGE_SHIFT;
+12 −5
Original line number Diff line number Diff line
@@ -220,12 +220,19 @@ void page_cache_ra_unbounded(struct readahead_control *ractl,
		if (mapping->a_ops->readpages) {
			page->index = index + i;
			list_add(&page->lru, &page_pool);
		} else if (add_to_page_cache_lru(page, mapping, index + i,
					gfp_mask) < 0) {
		} else {
			int ret;

			ret = add_to_page_cache_lru(page, mapping, index + i,
					gfp_mask);
			if (ret < 0) {
				put_page(page);
				if (ret == -ENOMEM)
					break;
				read_pages(ractl, &page_pool, true);
				continue;
			}
		}
		if (i == nr_to_read - lookahead_size)
			SetPageReadahead(page);
		ractl->_nr_pages++;