home *** CD-ROM | disk | FTP | other *** search
Wrap
Newsgroups: comp.unix.aix Path: sparky!uunet!zaphod.mps.ohio-state.edu!saimiri.primate.wisc.edu!ames!purdue!yuma!csn!news.den.mmc.com!pgl-devsvr.den.mmc.com!jzwiebel From: jzwiebel@pgl-devsvr.den.mmc.com (John Zwiebel (303)977-1480) Subject: ODM access gobbles memory Message-ID: <1992Nov22.012329.20501@den.mmc.com> Sender: news@den.mmc.com (News) Nntp-Posting-Host: pgl-netmgr.den.mmc.com Organization: PAGE @ Martin-Marietta Date: Sun, 22 Nov 1992 01:23:29 GMT Lines: 388 I have built an SMUX daemon to retrieve kernel information on our in-house protocol called RTP (for real-time). I'm a bit confused on all the calls to the odm that are required to get information to finally query the kernel. I've followed the example code in the IBM device drivers manual and I am successful in retrieving the information I want. The problem is that every time through my function to grab the RTP information, calls to the odm (odm_get_first and odm_lock, odm_terminate, odm_initiate etc. as well as genmajor()) all allocate additional memory which I can't free. I don't know what structures are being allocated for these processes and I don't know where they are being allocated. Nor can I find any reference in Info or in the device driver manual that discusses freeing this additional memory. There is a vague reference in odm_get_first that states I have to specifially free memory if I use a NULL pointer and I've tried that option too, still the process starts growing and growing until it uses up all available swap space and then it freezes up the host until it finally can't get any more memory and it dies. Below is a test application that I've built that anyone should be able to build on any RS6000. I'd really appreciate it if someone would take the time to look at it and tell me about the 'blahblah()' function that will solve my problems. Or maybe you can see the big mistake I'm making. BTW, I tried to run through the ODM calls once and store the devno information as a global. It seemed to work for a while but it then caused the host to '888' which of course isn't acceptable. If you do come up with a solution, please mail it to me as well as posting it here. Thanks a lot. John Zwiebel ----------------------------------------------------- First, here's a make file for my test program: OBJS = TestProgram.o CFLAGS = -g -D_BSD -D_BSD_INCLUDES $(INC) -DDEBUG LIBS = -lisode -lsnmp -lodm -lcfg -lcom rtpd: $(OBJS) $(CC) -o TestProgram $(OBJS) $(LIBS) clean: rm -f *.o TestProgram -------------------------------------------------------- And TestProgram.c Some of the calls here are specific to the isode SMUX agent but don't interfere with the TestProgram. -------------------------------------------------------- /* This test program uses certain calls to the odm to obtain information * from the kernel. It was origonally developed to retrieve information * on the PAGE internally developed RTP (Real-Time Protocol). The global * "logical_name" determines the object searched for the in CuDv_CLASS of * the odm. In this test program this has been changed from "PageRtp0" to * "ent0". Both of these objects are device drivers and both have links to * the PdDv_CLASS objects. Each call to the odm (using odm_initialize(); * odm_get_first(); or odm_terminate()) causes the process to grow in size. * This was determined by loading the program into dbx and stepping through * one line at a time then running "ps aux" to obtain the process size. * Normally this would be expected providing the memory allocated by these * calls is 'freed' after leaving the 'cacheRTP()' function call. At any * rate, the process should obtain some sort of an equilibrium in the amount * of memory it requires. This does not happen. The process continues to * run, allocating more memory each time through cacheRTP(), until all of * the available paging space is used. When the process can no longer * allocate additional memory it finally dies. */ /***************************** * The call 'maj = genmajor(preobj.DvDr);' also adds to * the size of the process. *************************/ /* The calls to the odm were origonally based on example code provided * in the AIX systems manual. This included locking and unlocking the database * using odm_lock() and odm_unlock() and explicitly opening and closing an * object class using the appropriate calls. When these calls were included * the process grew significantly faster than it does using only the current * calls included in this test program. After closly reading 'info', I * determined I could eliminate the extra calls and still obtain the information * I required. The correct information is in fact returned. */ /* There are several lines of code that have been commented out in cacheRTP(). * I was trying to experiment with alternative ways of structuring the odm * requests. The first method was to declare "cusobj" as an automatic and * the second was to declare it as a pointer to the structure returned by * odm_get_first(). Info states the the use of the second method requires * the application program to explicitly free the data structure, which suggests * that under the first method there is no requirement for releasing the * memory. cacheRTP() gets information from two odm classes, CuDv_CLASS and * PdDv_CLASS. The odm calls are summarized below: * * rc = odm_get_first(CuDv_CLASS,sstring,&cusobj); Method one * cusobj = odm_get_first(CuDv_CLASS,sstring,NULL); Method two * rc = odm_get_first(PdDv_CLASS, sstring, &preobj); Method one * preobj = odm_get_first(PdDv_CLASS, sstring, NULL); Method two */ /* THE TESTPROGRAM IS CURRENTLY COMMENTED TO USE METHOD TWO */ /* This test program currently loops through cacheRTP once per minute. * If you run 'ps aux |grep TestProgram' once every minute, you will see that * the process size grows every minute and by the same amount. Under the 'old' * version of cacheRTP(), it did not grow by the same size each loop but it * did develop a pattern in its size growth. This can be explained by the * way the kernel allocates paging space to a process. */ /* You may wish to comment out portions of this program as outline below to * see where the specific memory leaks are occurring. For instance, if * you leave only the 'odm_' calls in the loop the memory leak is much * much smaller but it still exists * # ps aux |grep TestProgram * root 11196 0.0 1.0 108 132 pts/1 S 11:26:14 0:00 ./TestProgram * root 12925 0.0 1.0 92 136 pts/0 S 12:19:04 0:00 grep TestProgram * # date * Fri Nov 20 13:08:56 MST 1992 * # ps aux |grep TestProgram * root 11196 0.0 1.0 112 136 pts/1 S 11:26:14 0:01 ./TestProgram * root 12832 0.0 1.0 92 136 pts/0 S 13:09:02 0:00 grep TestProgram * # date * Fri Nov 20 13:22:37 MST 1992 * # ps aux |grep TestProgram * root 11196 0.0 1.0 116 140 pts/1 S 11:26:14 0:01 ./TestProgram * root 12954 0.0 1.0 92 136 pts/0 S 13:22:40 0:00 grep TestProgram */ /* Some of the following #include files are probably not required for this * TestProgram (especially the isode includes ) but they do not prevent * correct operation of the program. * All of these should be available on an RS6000. * * I explicitly added odmi.h but it doesn't seem to make any difference in * compilation nor in process growth. */ #include <errno.h> #include <signal.h> #include <stdio.h> #include <varargs.h> #include <isode/snmp/smux.h> #include <isode/snmp/objects.h> #include <sys/ioctl.h> #include <odmi.h> #ifdef BSD42 #include <sys/file.h> #endif #ifdef SYS5 #include <fcntl.h> #endif #include <isode/tailor.h> /* * Additional PAGE required includes */ #include <sys/types.h> #include <sys/cfgdb.h> #include <sys/cfgodm.h> #include <cf.h> #ifdef SYS5 #include <fcntl.h> #endif #include <sys/sysconfig.h> #include <sys/mode.h> #include <sys/device.h> #include <sys/ldr.h> #include <sys/stat.h> #include <sys/errno.h> /* DATA */ static char *myname = "TestProgram"; #ifdef DEBUG #define TRAPTIME 60L #else #define TRAPTIME 600L /* how often 'rtp' is queried */ #endif /* Defined name for the RTP used in cacheRTP */ #define logical_name "ent0" /* PAGE CSU's */ extern int cacheRTP (); /* Read the 'vpdrtp' output */ extern void err_exit (); /* Used by cacheRTP to report errors */ /* Global Assignments */ /* START OF TEST STUB */ main(){ printf( " beginning........\n"); while (1){ cacheRTP(); sleep(20); } } int cacheRTP () { extern long *genminor(); char sstring[256]; /* search criteria string */ struct Class *cusdev; /* customized devices class ptr */ struct Class *predev; /* predefined devices class ptr */ struct CuDv *cusobj; /* customized device object storage */ struct PdDv *preobj; /* predefined device object storage */ /* int rc; /* return codes go here */ struct cfg_load load; /* code saved that shows how to load */ /* the device driver a different way */ struct cfg_dd dd; /* used to configure or unconfigure */ long maj; /* major number */ long *min; /* minor number */ dev_t devno; /* device number */ int status; /* return code */ printf("LOOP\n"); /* start up odm */ if (odm_initialize() == NOTOK){ /* initialization failed */ err_exit(E_ODMINIT); return (NOTOK); } /* search for customized object with this logical name */ sprintf(sstring, "name = '%s'", logical_name); /* rc = odm_get_first(cusdev,sstring,&cusobj); */ cusobj = odm_get_first(CuDv_CLASS,sstring,NULL); /* if ((int)rc==0) { */ if ((int)cusobj==0) { /* No CuDv object with this name */ err_exit(E_NOCuDv); return (NOTOK); } /* else if ((int)rc==NOTOK) { */ else if ((int)cusobj==NOTOK) { /* ODM failure */ err_exit(E_ODMGET); return (NOTOK); } /* get predefined device object for this logical name */ /* sprintf(sstring, "uniquetype = '%s'", cusobj.PdDvLn_Lvalue); */ sprintf(sstring, "uniquetype = '%s'", cusobj->PdDvLn_Lvalue); /* rc = odm_get_first(predev, sstring, &preobj); */ preobj = odm_get_first(PdDv_CLASS, sstring, NULL); /* if ((int)rc==0) { */ if ((int)preobj==0) { /* No PdDv object for this device */ err_exit(E_NOPdDv); return (NOTOK); } /* else if ((int)rc==NOTOK) { */ else if ((int)preobj==NOTOK) { /* ODM failure */ err_exit(E_ODMGET); return (NOTOK); } /************************************************************************ * The code beyond this point uses the information obtained from * the odm queries to obtain kernel information. ************************************************************************/ /* if (cusobj.status == AVAILABLE) { */ if (cusobj->status == AVAILABLE) { load.path = "/etc/drivers/entdd"; load.libpath = ""; load.kmid = 0; status = sysconfig(SYS_QUERYLOAD, &load, sizeof(load)); if (status == NOTOK) { advise(LLOG_EXCEPTIONS, NULLCP, "vpdrtp: SYS_QUERYLOAD failed [%s]", strerror(errno)); err_exit(errno); return (NOTOK); } if (load.kmid == 0) { advise(LLOG_EXCEPTIONS, NULLCP, "vpdrtp: SYS_QUERYLOAD returned a 0 kmid\n"); err_exit(errno); return (NOTOK); } /********************************************************************** * With the following segment commented out the LOOP does not eat up * memory quite as fast. (See above). The major device number returned * is alway the same. The 'genmajor' command seems to be the culprit. ***********************************************************************/ /* maj = genmajor(preobj.DvDr); */ maj = genmajor(preobj->DvDr); printf( "The Major Device Driver Number is: %d \n", maj); if (maj == NOTOK) { advise(LLOG_EXCEPTIONS, NULLCP, "vpdrtp: genmajor failed\n"); err_exit(errno); return (NOTOK); } min = genminor(logical_name, maj, -1, 1, 1, 1); printf( "The Minor Device Driver Number is: %d \n", min); if (*min == NOTOK) { advise(LLOG_EXCEPTIONS, NULLCP, "vpdrtp: genminor failed\n"); err_exit(errno); return (NOTOK); } devno = makedev(maj, *min); printf( "The devno Number is: %d \n", devno); /******************************************************* * Most of the following code is commented out. It does not affect the * size of the process but does show how I wanted to use the information * retrieved from the odm. This code doesn't make the size of the process * grow. (Or it doesn't seem to). Also I've been happy with the information * returned here. *******************************************************/ /* Fill in device driver structure.*/ /* dd.devno = devno; dd.kmid = load.kmid; dd.cmd = CFG_QVPD; dd.ddsptr = (caddr_t)&rtpvpd; dd.ddslen = sizeof(RTPVitalProdData_t); */ /* * Get the Vital Product Data from the device driver * using sysconfig and command CFG_QVPD. */ /* status = sysconfig(SYS_CFGDD, &dd, sizeof(dd)); if (status == NOTOK) { advise(LLOG_EXCEPTIONS, NULLCP, "vpdrtp: SYS_CFGDD failed"); err_exit(errno); return (NOTOK); } */ } else { /* CODE REMOVED */ } /* THESE LINES FREE THE ALLOCATED MEMORY WHEN WE USE METHOD TWO (POINTERS) */ free(cusobj); free(preobj); if (odm_terminate() == NOTOK) advise(LLOG_EXCEPTIONS, NULLCP, "odm_terminate failed: %d", odmerrno); return (OK); } void err_exit(exitcode) char exitcode; { /* Terminate the ODM */ odm_terminate(); /* Log the error */ advise (LLOG_EXCEPTIONS, NULLCP, "cacheRTP() failed: %d [%s]", exitcode, strerror(exitcode)); }