[LTP] Final version [Re: [PATCH v4] make pid_list dynamically sized with memory]

Caspar Zhang
2011-01-06T18:42:37Z

Hi Garrett, this is the *final* version, please review.

On 01/07/2011 02:40 AM, czhang@redhat.com wrote:
> From: Caspar Zhang <czhang@redhat.com>
>
> We get segfaults during testing mtest01 on a 5TB memory machine, the
> problem was traced to the array pid_list[] went to overflow and
> corrupted memory. This fix makes pid_list dynamically sized with
> correct memory size to avoid overflow.
>
> v2: not split into different bits when allocating pid_list.
> v3: 1) fix optargs: -b and -p should not be used at the same time.
> 2) pre_mem maybe not initialized before using if -p option not used.
> fix it by moving it outside ``if(maxpercent)'' block.
> v4: fix code format.
>
> Signed-off-by: Caspar Zhang <czhang@redhat.com>
> ---
> testcases/kernel/mem/mtest01/mtest01.c | 409 +++++++++++++++++---------------
> 1 files changed, 215 insertions(+), 194 deletions(-)
>
> diff --git a/testcases/kernel/mem/mtest01/mtest01.c b/testcases/kernel/mem/mtest01/mtest01.c
> index aee0d51..94b429a 100644
> --- a/testcases/kernel/mem/mtest01/mtest01.c
> +++ b/testcases/kernel/mem/mtest01/mtest01.c
> @@ -44,223 +44,244 @@
>
> #include "test.h"
>
> +#define FIVE_HUNDRED_KB (unsigned long long)(500*1024*1024)
> +#define ONE_MEGABYTE (unsigned long long)(1024*1024*1024)
> +#define THREE_MEGABYTES (unsigned long long)(3*ONE_MEGABYTE)
> +
> char *TCID = "mtest01";
> int TST_TOTAL = 1;
> -
> int pid_count = 0;
>
> void handler(int signo)
> {
> - pid_count++;
> + pid_count++;
> }
>
> -int main(int argc, char* argv[]) {
> - char* mem;
> - float percent;
> - unsigned int maxpercent=0, dowrite=0, verbose=0, j, c;
> - unsigned long bytecount, alloc_bytes;
> - unsigned long long original_maxbytes,maxbytes=0;
> - unsigned long long pre_mem, post_mem;
> - extern char* optarg;
> - int chunksize = 1024*1024; /* one meg at a time by default */
> - struct sysinfo sstats;
> - int i,pid_cntr;
> - pid_t pid,pid_list[1000];
> - struct sigaction act;
> -
> - act.sa_handler = handler;
> - act.sa_flags = 0;
> - sigemptyset(&act.sa_mask);
> - sigaction(SIGRTMIN, &act, 0);
> -
> - for (i=0;i<1000;i++)
> - pid_list[i]=(pid_t)0;
> -
> - while ((c=getopt(argc, argv, "c:b:p:wvh")) != EOF) {
> - switch((char)c) {
> - case 'c':
> - chunksize = atoi(optarg);
> - break;
> - case 'b':
> - maxbytes = atoll(optarg);
> - break;
> - case 'p':
> - maxpercent = atoi(optarg);
> - if (maxpercent <= 0) {
> - tst_resm(TFAIL, "ERROR: -p option requires number greater than 0");
> - exit(1);}
> - if (maxpercent > 99) {
> - tst_resm(TFAIL, "ERROR: -p option cannot be greater than 99");
> - exit(1);}
> - break;
> - case 'w':
> - dowrite = 1;
> - break;
> - case 'v':
> - verbose = 1;
> - break;
> - case 'h':
> - default:
> - printf("Usage: %s [-c <bytes>] [-b <bytes>|-p <percent>] [-v]\n", argv[0]);
> - printf("\t-c <num>\tsize of chunk in bytes to malloc on each pass\n");
> - printf("\t-b <bytes>\tmaximum number of bytes to allocate before stopping\n");
> - printf("\t-p <bytes>\tpercent of total memory used at which the program stops\n");
> - printf("\t-w\t\twrite to the memory after allocating\n");
> - printf("\t-v\t\tverbose\n");
> - printf("\t-h\t\tdisplay usage\n");
> - exit(-1);
> - }
> - }
> -
> - sysinfo(&sstats);
> - if (maxpercent) {
> +int main(int argc, char* argv[])
> +{
> + char* mem;
> + float percent;
> + unsigned int maxpercent = 0, dowrite = 0, verbose=0, j, c;
> + unsigned long bytecount, alloc_bytes, max_pids;
> + unsigned long long original_maxbytes, maxbytes = 0;
> + unsigned long long pre_mem, post_mem;
> unsigned long long total_ram, total_free, D, C;
> - percent=(float)maxpercent/100.00;
> -
> - total_ram=sstats.totalram;
> - total_ram=total_ram+sstats.totalswap;
> -
> - total_free=sstats.freeram;
> - total_free=total_free+sstats.freeswap;
> -
> - /* Total memory used needed to reach maxpercent */
> - D = percent*(sstats.mem_unit*total_ram);
> - tst_resm(TINFO, "Total memory used needed to reach maxpercent = %llu kbytes", D/1024);
> -
> - /* Total memory already used */
> - C = sstats.mem_unit*(total_ram-total_free);
> - tst_resm(TINFO, "Total memory already used on system = %llu kbytes", C/1024);
> + extern char* optarg;
> + int chunksize = 1024*1024; /* one meg at a time by default */
> + struct sysinfo sstats;
> + int i, pid_cntr;
> + pid_t pid, *pid_list;
> + struct sigaction act;
>
> + act.sa_handler = handler;
> + act.sa_flags = 0;
> + sigemptyset(&act.sa_mask);
> + sigaction(SIGRTMIN, &act, 0);
> +
> + while ((c = getopt(argc, argv, "c:b:p:wvh")) != EOF)
> + {
> + switch((char)c)
> + {
> + case 'c':
> + chunksize = atoi(optarg);
> + break;
> + case 'b':
> + if (maxpercent != 0) {
> + tst_resm(TFAIL, "ERROR: -b option cannot be used with -p option at the same time");
> + exit(1);
> + }
> + maxbytes = atoll(optarg);
> + break;
> + case 'p':
> + if (maxbytes != 0) {
> + tst_resm(TFAIL, "ERROR: -p option cannot be used with -b option at the same time");
> + exit(1);
> + }
> + maxpercent = atoi(optarg);
> + if (maxpercent <= 0) {
> + tst_resm(TFAIL, "ERROR: -p option requires number greater than 0");
> + exit(1);
> + }
> + if (maxpercent > 99) {
> + tst_resm(TFAIL, "ERROR: -p option cannot be greater than 99");
> + exit(1);
> + }
> + break;
> + case 'w':
> + dowrite = 1;
> + break;
> + case 'v':
> + verbose = 1;
> + break;
> + case 'h':
> + default:
> + printf("Usage: %s [-c <bytes>] [-b <bytes>|-p <percent>] [-v]\n", argv[0]);
> + printf("\t-c <num>\tsize of chunk in bytes to malloc on each pass\n");
> + printf("\t-b <bytes>\tmaximum number of bytes to allocate before stopping\n");
> + printf("\t-p <bytes>\tpercent of total memory used at which the program stops\n");
> + printf("\t-w\t\twrite to the memory after allocating\n");
> + printf("\t-v\t\tverbose\n");
> + printf("\t-h\t\tdisplay usage\n");
> + exit(-1);
> + }
> + }
> +
> + sysinfo(&sstats);
> + total_ram = sstats.totalram + sstats.totalswap;
> + total_free = sstats.freeram + sstats.freeswap;
> /* Total Free Pre-Test RAM */
> - pre_mem = sstats.mem_unit*total_free;
> -
> - /* Are we already using more than maxpercent? */
> - if (C>D) {
> - tst_resm(TFAIL, "More memory than the maximum amount you specified is already being used");
> - exit(1);
> + pre_mem = sstats.mem_unit * total_free;
> + max_pids = total_ram / (unsigned long)FIVE_HUNDRED_KB + 1;
> +
> + if ((pid_list = malloc(max_pids * sizeof(pid_t))) == NULL)
> + {
> + tst_resm(TBROK|TERRNO, "malloc failed.");
> + exit(1);
> }
> - else
> - pre_mem = sstats.mem_unit*total_free;
> + memset(pid_list, 0, max_pids * sizeof(pid_t));
> +
> + /* Currently used memory */
> + C = sstats.mem_unit * (total_ram - total_free);
> + tst_resm(TINFO, "Total memory already used on system = %llu kbytes", C/1024);
> +
> + if (maxpercent)
> + {
> + percent = (float)maxpercent / 100.00;
>
> - /* set maxbytes to the extra amount we want to allocate */
> - maxbytes = D-C;
> - tst_resm(TINFO, "Filling up %d%% of ram which is %llu kbytes", maxpercent, maxbytes/1024);
> - }
> - original_maxbytes=maxbytes;
> - i=0;
> - pid_cntr=0;
> - pid=fork();
> - if (pid != 0)
> - pid_cntr++;
> - pid_list[i]=pid;
> + /* Desired memory needed to reach maxpercent */
> + D = percent * (sstats.mem_unit * total_ram);
> + tst_resm(TINFO, "Total memory used needed to reach maxpercent = %llu kbytes", D/1024);
> +
> + /* Are we already using more than maxpercent? */
> + if (C > D)
> + {
> + tst_resm(TFAIL, "More memory than the maximum amount you specified is already being used");
> + free(pid_list);
> + exit(1);
> + }
> +
> + /* set maxbytes to the extra amount we want to allocate */
> + maxbytes = D - C;
> + tst_resm(TINFO, "Filling up %d%% of ram which is %llu kbytes", maxpercent, maxbytes/1024);
> + }
> + original_maxbytes = maxbytes;
> + i = 0;
> + pid_cntr = 0;
> + pid = fork();
> + if (pid != 0)
> + pid_cntr++;
> + pid_list[i] = pid;
>
> #if defined (_s390_) /* s390's 31bit addressing requires smaller chunks */
> -#define FIVE_HUNDRED_KB (500*1024*1024)
> -#define ONE_MEGABYTE (1024*1024*1024)
> -#define THREE_MEGABYTES (3*ONE_MEGABYTE)
> - while (pid != 0 && maxbytes > FIVE_HUNDRED_KB)
> - {
> - i++;
> - maxbytes -= FIVE_HUNDRED_KB;
> - pid = fork();
> - if (pid != 0) {
> - pid_cntr++;
> - pid_list[i] = pid;
> + while (pid != 0 && maxbytes > FIVE_HUNDRED_KB)
> + {
> + i++;
> + maxbytes -= FIVE_HUNDRED_KB;
> + pid = fork();
> + if (pid != 0)
> + {
> + pid_cntr++;
> + pid_list[i] = pid;
> + }
> }
> - }
> - if (maxbytes > FIVE_HUNDRED_KB)
> - alloc_bytes FIVE_HUNDRED_KB;
> - else
> - alloc_bytes = (unsigned long) maxbytes;
> -
> + if (maxbytes > FIVE_HUNDRED_KB)
> + alloc_bytes = FIVE_HUNDRED_KB;
> + else
> + alloc_bytes = (unsigned long) maxbytes;
> +
> #elif __WORDSIZE==32
> - while (pid != 0 && maxbytes > ONE_MEGABYTE)
> - {
> - i++;
> - maxbytes -= ONE_MEGABYTE;
> - pid = fork();
> - if (pid != 0) {
> - pid_cntr++;
> - pid_list[i]=pid;
> + while (pid != 0 && maxbytes > ONE_MEGABYTE)
> + {
> + i++;
> + maxbytes -= ONE_MEGABYTE;
> + pid = fork();
> + if (pid != 0)
> + {
> + pid_cntr++;
> + pid_list[i]=pid;
> + }
> }
> - }
> - if (maxbytes > ONE_MEGABYTE)
> - alloc_bytes = ONE_MEGABYTE;
> - else
> - alloc_bytes = (unsigned long)maxbytes;
> -
> + if (maxbytes > ONE_MEGABYTE)
> + alloc_bytes = ONE_MEGABYTE;
> + else
> + alloc_bytes = (unsigned long)maxbytes;
> +
> #elif __WORDSIZE==64
> - while (pid!=0 && maxbytes > THREE_MEGABYTES)
> - {
> - i++;
> - maxbytes -= THREE_MEGABYTES;
> - pid=fork();
> - if (pid != 0) {
> - pid_cntr++;
> - pid_list[i] = pid;
> - }
> - }
> - if (maxbytes > THREE_MEGABYTES)
> - alloc_bytes = THREE_MEGABYTES;
> - else
> - alloc_bytes = maxbytes;
> -#endif
> -
> - if (pid == 0) /** CHILD **/
> - {
> - bytecount=chunksize;
> - while (1) {
> - if ((mem = (char*)malloc(chunksize)) == NULL) {
> - tst_resm(TINFO, "stopped at %lu bytes", bytecount);
> - exit(1);
> - }
> - if (dowrite)
> - for (j=0; j<chunksize; j++)
> - *(mem+j)='a';
> - if (verbose)
> - tst_resm(TINFO, "allocated %lu bytes chunksize is %d", bytecount, chunksize);
> - bytecount+=chunksize;
> - if (alloc_bytes && (bytecount >= alloc_bytes))
> - break;
> + while (pid!=0 && maxbytes > THREE_MEGABYTES)
> + {
> + i++;
> + maxbytes -= THREE_MEGABYTES;
> + pid = fork();
> + if (pid != 0)
> + {
> + pid_cntr++;
> + pid_list[i] = pid;
> + }
> }
> - if (dowrite)
> - tst_resm(TINFO, "... %lu bytes allocated and used.", bytecount);
> + if (maxbytes > THREE_MEGABYTES)
> + alloc_bytes = THREE_MEGABYTES;
> else
> - tst_resm(TINFO, "... %lu bytes allocated only.", bytecount);
> - kill(getppid(),SIGRTMIN);
> - while (1)
> - sleep(1);
> - }
> - else /** PARENT **/
> - {
> -
> - i=0;
> - sysinfo(&sstats);
> + alloc_bytes = maxbytes;
> +#endif
>
> - if (dowrite)
> + if (pid == 0) /** CHILD **/
> {
> - /* Total Free Post-Test RAM */
> - post_mem = (unsigned long long)sstats.mem_unit*sstats.freeram;
> - post_mem = post_mem+((unsigned long long)sstats.mem_unit*sstats.freeswap);
> -
> - while ((((unsigned long long)pre_mem - post_mem) < (unsigned long long)original_maxbytes) &&
> - (pid_count < pid_cntr) )
> - {
> - sleep(1);
> - sysinfo(&sstats);
> - post_mem = (unsigned long long)sstats.mem_unit*sstats.freeram;
> - post_mem = post_mem+((unsigned long long)sstats.mem_unit*sstats.freeswap);
> - }
> + bytecount = chunksize;
> + while (1)
> + {
> + if ((mem = malloc(chunksize)) == NULL)
> + {
> + tst_resm(TBROK|TERRNO, "stopped at %lu bytes", bytecount);
> + free(pid_list);
> + exit(1);
> + }
> + if (dowrite)
> + for (j = 0; j < chunksize; j++)
> + *(mem+j) = 'a';
> + if (verbose)
> + tst_resm(TINFO, "allocated %lu bytes chunksize is %d", bytecount, chunksize);
> + bytecount += chunksize;
> + if (alloc_bytes && bytecount >= alloc_bytes)
> + break;
> + }
> + if (dowrite)
> + tst_resm(TINFO, "... %lu bytes allocated and used.", bytecount);
> + else
> + tst_resm(TINFO, "... %lu bytes allocated only.", bytecount);
> + kill(getppid(), SIGRTMIN);
> + while (1)
> + sleep(1);
> }
> - while (pid_list[i]!=0)
> + else /** PARENT **/
> {
> - kill(pid_list[i],SIGKILL);
> - i++;
> + i = 0;
> + sysinfo(&sstats);
> +
> + if (dowrite)
> + {
> + /* Total Free Post-Test RAM */
> + post_mem = (unsigned long long)sstats.mem_unit * sstats.freeram;
> + post_mem = post_mem + (unsigned long long)sstats.mem_unit * sstats.freeswap;
> +
> + while ((((unsigned long long)pre_mem - post_mem) < (unsigned long long)original_maxbytes) &&
> + (pid_count < pid_cntr))
> + {
> + sleep(1);
> + sysinfo(&sstats);
> + post_mem = (unsigned long long)sstats.mem_unit * sstats.freeram;
> + post_mem = post_mem + (unsigned long long)sstats.mem_unit * sstats.freeswap;
> + }
> + }
> + while (pid_list[i] != 0)
> + {
> + kill(pid_list[i], SIGKILL);
> + i++;
> + }
> + if (dowrite)
> + tst_resm(TPASS, "%llu kbytes allocated and used.", original_maxbytes/1024);
> + else
> + tst_resm(TPASS, "%llu kbytes allocated only.", original_maxbytes/1024);
> }
> - if (dowrite)
> - tst_resm(TPASS, "%llu kbytes allocated and used.", original_maxbytes/1024);
> - else
> - tst_resm(TPASS, "%llu kbytes allocated only.", original_maxbytes/1024);
> - }
> - exit(0);
> -}
> \ No newline at end of file
> + free(pid_list);
> + exit(0);
> +}

--
Quality Assurance Associate (Kernel) in
Red Hat Software (Beijing) Co., R&D Branch

TEL: +86-10-62608150
WEB: http://www.redhat.com/
--
C-A-S-P-A-R, Caspar /kæspɑ:/ ;-)

------------------------------------------------------------------------------
Learn how Oracle Real Application Clusters (RAC) One Node allows customers
to consolidate database storage, standardize their database environment, and,
should the need arise, upgrade to a full multi-node Oracle RAC database
without downtime or disruption