| From linux-kernel-owner@vger.kernel.org Tue Jan 8 20:59:05 2002 |
| Message-Id: <200201090245.g092jnt02235@mysql.sashanet.com> |
| Content-Type: text/plain; |
| charset="us-ascii" |
| From: Sasha Pachev <sasha@mysql.com> |
| Organization: MySQL |
| To: linux-kernel@vger.kernel.org |
| Subject: Test case for cache leak in 2.17.2-rc2 |
| Date: Tue, 8 Jan 2002 19:45:49 -0700 |
| X-Mailer: KMail [version 1.3.1] |
| MIME-Version: 1.0 |
| Content-Transfer-Encoding: 8bit |
| Sender: linux-kernel-owner@vger.kernel.org |
| Precedence: bulk |
| X-Mailing-List: linux-kernel@vger.kernel.org |
| Status: RO |
| Content-Length: 3887 |
| |
| The following test program demonstrates incorrect cache shrinking logic in |
| 2.17.2-rc2 with 0 swap. I suspect the same problem will happen if swap is not |
| zero but is filled up. I have not noticed anything relevant in the changelogs |
| between my version and 2.4.18-pre2, so I assume the bug is still there. It |
| would be nice if somebody could verify it. |
| |
| First the code: |
| |
| -------------------start--------------------- |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <unistd.h> |
| |
| #define BLOCK_SIZE 1024 |
| |
| int done_hog_cache=0; |
| int done_hog_free=0; |
| int go_pipe[2]; |
| pid_t child_pid=0; |
| |
| void stop_hog_cache() |
| { |
| done_hog_cache=1; |
| } |
| |
| void stop_hog_free() |
| { |
| done_hog_free=1; |
| } |
| |
| void stop_all() |
| { |
| done_hog_free=done_hog_cache=1; |
| if (child_pid>0) |
| kill(child_pid,SIGHUP); |
| } |
| |
| void hog_free(int blocks) |
| { |
| char* buf; |
| char go_buf[2]; |
| |
| signal(SIGHUP,stop_hog_free); |
| signal(SIGTERM,stop_hog_free); |
| printf("Hogging free mem, to stop, do kill -HUP %d in another terminal\n", |
| getpid()); |
| read(go_pipe[0],go_buf,2); |
| if (!(buf=(char*)malloc(blocks*BLOCK_SIZE))) |
| { |
| fprintf(stderr,"malloc() failed\n"); |
| exit(1); |
| } |
| memset(buf,0xff,blocks*BLOCK_SIZE); |
| while (!done_hog_free) |
| { |
| sleep(1); |
| } |
| } |
| |
| void hog_cache(int blocks) |
| { |
| FILE* fp; |
| char buf[BLOCK_SIZE]; |
| const char* hog_file="/tmp/hog-file"; |
| int i; |
| |
| memset(buf,0xff,sizeof(buf)); |
| if (!(fp=fopen(hog_file,"w+"))) |
| { |
| fprintf(stderr,"Could not open crash file\n"); |
| exit(1); |
| } |
| signal(SIGHUP,stop_hog_cache); |
| signal(SIGTERM,stop_hog_free); |
| printf("Hogging disk cache, to stop, do kill -HUP %d in another terminal\n", |
| getpid()); |
| for (i=0;i<blocks;i++) |
| { |
| fwrite(buf,1,sizeof(buf),fp); |
| } |
| fflush(fp); |
| write(go_pipe[1],"go",2); |
| while (!done_hog_cache) |
| { |
| fseek(fp,0L,SEEK_SET); |
| for (i=0;i<blocks;i++) |
| { |
| fread(buf,1,sizeof(buf),fp); |
| } |
| } |
| |
| fclose(fp); |
| unlink(hog_file); |
| printf("Finished cleanup of disk cache hog\n"); |
| } |
| |
| int main(int argc,char** argv) |
| { |
| int cache_blocks,free_blocks; |
| if (argc<3) |
| { |
| fprintf(stderr,"Usage: ./crash-kernel cache_blocks free_blocks\n"); |
| exit(1); |
| } |
| cache_blocks=atoi(argv[1]); |
| free_blocks=atoi(argv[2]); |
| if (pipe(go_pipe) == -1) |
| { |
| fprintf(stderr,"could not create pipe\n"); |
| exit(1); |
| } |
| signal(SIGINT,stop_all); |
| switch ((child_pid=fork())) |
| { |
| case 0: hog_cache(cache_blocks); break; |
| case -1: |
| fprintf(stderr, "cannot fork\n"); |
| exit(1); |
| default: hog_free(free_blocks); break; |
| } |
| } |
| -----------------end------ |
| |
| To see the problem, ./crash-kernel cache_blocks free_blocks |
| |
| set cache_blocks to eat up all of your physical RAM + swap, and free_blocks |
| to some sigficant amount, but less than what is actually available before you |
| run the test. |
| |
| As you can see from the source, crash-kernel first tries to bloat the cache |
| by creating a large file, and then tries to keep it bloated by reading the |
| file data in a loop. As soon as the file is created, the other fork tries to |
| allocate and initialize a chunk of memory, and then goes to sleep. |
| |
| The correct behaviour would be, of course, to shrink the bloated cache and |
| give memory from it. But what happens on 2.4.17-rc2 is that the memory thread |
| gets killed instead. |
| |
| Please CC me on replies as I do not subsribe to the list... |
| |
| -- |
| MySQL Development Team |
| For technical support contracts, visit https://order.mysql.com/ |
| __ ___ ___ ____ __ |
| / |/ /_ __/ __/ __ \/ / Sasha Pachev <sasha@mysql.com> |
| / /|_/ / // /\ \/ /_/ / /__ MySQL AB, http://www.mysql.com/ |
| /_/ /_/\_, /___/\___\_\___/ Provo, Utah, USA |
| <___/ |
| - |
| To unsubscribe from this list: send the line "unsubscribe linux-kernel" in |
| the body of a message to majordomo@vger.kernel.org |
| More majordomo info at http://vger.kernel.org/majordomo-info.html |
| Please read the FAQ at http://www.tux.org/lkml/ |
| |
| |