uid-Another Problem in writing to /proc/loadavg file
Hi Robin,
Though I was able to run my code and get good results as a kernel module (This was everytime only one set of results per loading of the module).
Anyway I felt that it was hanging on a bit while values being calculated. (It looks like the host computer sends some messages to the users)
Thinking everything was well, I then integrated it to the kernel code with those extra loops of mine, this time there was nothing written to /proc/loadavg file.
First I thought that this was because the long list(5) of USER's UIDs I am saving in that file. (only 5)
Anyway it looks like that is not the real problem as I do calculate every 5 seconds and that seems to be enough time.
Robin for further Real testing I thought of first running it as a kernel module. Then this code has to be called every 5 seconds and will have to be scheduled as a task.?
I made the following attempt.
I have 2 questions for you.
What is this error about? THE ERROR WAS sched.o: unresolved symbol proc_unregister
Thanks
Sena Seneviratene
Computer Engineering Lab
Sydney University
sched.c
/* The necessary header files */
/* Standard in kernel modules */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif
/* Necessary because we use the proc fs */
#include <linux/proc_fs.h>
/* We scheduale tasks here */
#include <linux/tqueue.h>
/* We also need the ability to put ourselves to sleep * and wake up later */ #include <linux/sched.h>
/* In 2.2.3 /usr/include/linux/version.h includes a * macro for this, but 2.0.35 doesn't - so I add it * here if necessary. */ #ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif
/* The number of times the timer interrupt has been * called so far */ static int TimerIntrpt = 0;
/* This is used by cleanup, to prevent the module from * being unloaded while intrpt_routine is still in * the task queue */ static struct wait_queue *WaitQ = NULL;
static void intrpt_routine(void *);
/* The task queue structure for this task, from tqueue.h */ static struct tq_struct Task = {
NULL, /* Next item in list - queue_task will do
* this for us */
0, /* A flag meaning we haven't been inserted
* into a task queue yet */
intrpt_routine, /* The function to run */
NULL /* The void* parameter for that function */
};
/*IN THIS FUNCTION LOAD AVERAGE CALCULATIONS BE INCLUDED*/ static void intrpt_routine(void *irrelevant)
{
/* Increment the counter */
TimerIntrpt++;
/* If cleanup wants us to die */
if (WaitQ != NULL)
wake_up(&WaitQ); /* Now cleanup_module can return */
else
/* Put ourselves back in the task queue */
queue_task(&Task, &tq_timer);
}
/* Put data into the proc fs file. */
int procfile_read(char *buffer,
char **buffer_location, off_t offset, int buffer_length, int zero)
{
int len; /* The number of bytes actually used */
static char my_buffer[80];
static int count = 1;
if (offset > 0)
return 0;
/* Fill the buffer and get its length */ len = sprintf(my_buffer,
"Timer was called %d times so far\n", TimerIntrpt);
count++;
/* Tell the function which called us where the
* buffer is */
*buffer_location = my_buffer;
/* Return the length */
return len;
}
struct proc_dir_entry Our_Proc_File =
{
0, /* Inode number - ignore, it will be filled by
* proc_register_dynamic */
5, /* Length of the file name */
"sched", /* The file name */
S_IFREG | S_IRUGO,
/* File mode - this is a regular file which can
* be read by its owner, its group, and everybody
* else */
1, /* Number of links (directories where
* the file is referenced) */
0, 0, /* The uid and gid for the file - we give
* it to root */
80, /* The size of the file reported by ls. */ NULL, /* functions which can be done on the
* inode (linking, removing, etc.) - we don't
* support any. */
procfile_read,
/* The read function for this file, the function called
* when somebody tries to read something from it. */
NULL
/* We could have here a function to fill the
* file's inode, to enable us to play with
* permissions, ownership, etc. */
};
/* Initialize the module - register the proc file */ int init_module()
{
/* Put the task in the tq_timer task queue, so it
* will be executed at next timer interrupt */
queue_task(&Task, &tq_timer);
/* Success if proc_register_dynamic is a success,
* failure otherwise */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)
return proc_register(&proc_root, &Our_Proc_File);
#else
return proc_register_dynamic(&proc_root, &Our_Proc_File);
#endif
}
/* Cleanup */
void cleanup_module()
{
/* Unregister our /proc file */ proc_unregister(&proc_root, Our_Proc_File.low_ino);
/* Sleep until intrpt_routine is called one last
* time. This is necessary, because otherwise we'll
* deallocate the memory holding intrpt_routine and
* Task while tq_timer still references them.
* Notice that here we don't allow signals to
* interrupt us.
*
* Since WaitQ is now not NULL, this automatically
* tells the interrupt routine it's time to die. */sleep_on(&WaitQ);
}
A message that is not in the archive (sent off-list or not yet received): 20040113120727.GB7506@lnx-holt
A message that is not in the archive (sent off-list or not yet received): 20040114114900.GB14674@lnx-holt
Hi Robin,
That is done and the name of the new file is /proc/loadavgus. I hope that does not sound like usa.
Never mind the data is being collected without any problem.
Thanks
Sena Seneviratne
Computer Engineering Lab
Sydney University
Quoted 353 lines · you
Quoted 10 lines · sena
Hi Robin,
Thanks for the reply and for your time.
My previous observation about hanging on is not correct. There is no hanging on whatsoever.
I had put some printks in my kernel code and according to them the load averages per user are being calculated correctly.
Quoted 6 lines
I found the values in
/var/log/messagesThis means my calculation code every 5 seconds do their part.
I find the problem with the writing to
/proc/loadavgfile.Did you specify your read handler in the
create_proc_read_entry()call? If you didn't usecreate_proc_read_entry, you need to point the resulting file structures read handler to your read routine.You should probably not use
/proc/loadavg. It is an already existing file. Try using your own directory with seperate read handler(s). Maybe something like /proc/loadavg_per_user/<uid> which gives the load averages per user.Good Luck,
RobinQuoted 5 lines
My loadavg file is empty. ?
(I experienced this situation only with this compilation.)Quoted 95 lines
Thanks
Sena Seneviratne
Computer Engineering Lab
Sydney UniversityQuoted 86 lines · Robin Holt
Sena,
Let's keep this off the lkml. This is _NOT_ the type of chatter that should be going on at that list. That forum is for kernel developers to discuss features that relate to the kernel proper. This will never go in without some serious discussion about _WHAT_ is being accomplished and _WHY_. The what is weak at best since this is limited to a certain number of users. The why is completely vague to me.
Quoted 7 lines · sena
Hi Robin,
Though I was able to run my code and get good results as a kernel module (This was everytime only one set of results per loading of the module).
You should write your routine to calculate load averages as a timer service routine.
Look at struct
timer_list. That might give you some ideas of how to use it:I guess I would write something like:
static struct
timer_listloadavg_per_user_timer;...
/* during module init, register the timer */ loadavg_per_user_timer.function = loadavg_per_user_calc; loadavg_per_user_calc(0);...
static void
loadavg_per_user_calc(unsigned long _dummy){ loadavg_per_user_timer.expires = (5 * HZ) + jiffies; /* Body of calculating loadavg_per_user goes here */ }This type of timer would run every 5 seconds and calculate your load averages.
One thing we haven't talked about doing is using an extremely simple lookup instead of searching a list for the uid. Since the uids you are concerned with are always in the range of 500-504, Why don't you just do something like:
int loadavg_bucket; loadavg_bucket = p->uid - 499; if ((loadavg_bucket < 0) || (loadavg_bucket > 5)) { loadavg_bucket = 0; }With this, any process that has a uid in the range of 500-504 gets mapped to entries 1-5 in your array and entry 0 is used for everyone else. Certainly simpler than the looping lookup you are doing.
Quoted 5 lines
Anyway I felt that it was hanging on a bit while values being calculated. (It looks like the host computer sends some messages to the users)
Describe what you think you felt. There are all types of hangs. Did it feel like the kernel wasn't starting new processes or did it feel like interrupts were not being serviced? I sort of need to know which way it responded to help further.
Quoted 5 lines
Thinking everything was well, I then integrated it to the kernel code with those extra loops of mine, this time there was nothing written to
/proc/loadavgfile.You should probably consider creating your own /proc file since the
loadavg
Quoted 223 lines
Quoted 221 lines
is really meant for the
proc_psstuff to consume. You might consider creating a /proc/loadavg_per_user/<pid> type directory.Quoted 4 lines
First I thought that this was because the long list(5) of USER's UIDs I am saving in that file. (only 5)
I doubt that anyone would consider 5 too long.
Quoted 9 lines
Anyway it looks like that is not the real problem as I do calculate every 5 seconds and that seems to be enough time.
Robin for further Real testing I thought of first running it as a kernel module. Then this code has to be called every 5 seconds and will have to be scheduled as a task.?
You should be able to use a timer for this.
Quoted 8 lines
I made the following attempt.
I have 2 questions for you.
What is this error about? THE ERROR WAS sched.o: unresolved symbol
proc_unregister
proc_registerandproc_unregisterhave been going away for some time. You should be usingcreate_proc_entryandremove_proc_entry. These are pointed out in theDocumentation/DocBook/procfs_example.cfile.Quoted 175 lines
Thanks
Sena Seneviratene
Computer Engineering Lab
Sydney University
sched.c
/* The necessary header files *//* Standard in kernel modules */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module *//* Deal with
CONFIG_MODVERSIONS*/
#ifCONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif/* Necessary because we use the proc fs */
#include <linux/proc_fs.h>/* We scheduale tasks here */
#include <linux/tqueue.h>/* We also need the ability to put ourselves to sleep
* and wake up later */
#include <linux/sched.h>/* In 2.2.3
/usr/include/linux/version.hincludes a
* macro for this, but 2.0.35 doesn't - so I add it
* here if necessary. */
#ifndefKERNEL_VERSION
#defineKERNEL_VERSION(a,b,c)((a)*65536+(b)*256+(c)) #endif/* The number of times the timer interrupt has been
* called so far */
static int TimerIntrpt = 0;/* This is used by cleanup, to prevent the module from
* being unloaded whileintrpt_routineis still in
* the task queue */
static structwait_queue*WaitQ = NULL;static void
intrpt_routine(void *);/* The task queue structure for this task, from
tqueue.h*/ static structtq_structTask = {
NULL, /* Next item in list -queue_taskwill do
* this for us */
0, /* A flag meaning we haven't been inserted
* into a task queue yet */intrpt_routine, /* The function to run */
NULL /* The void* parameter for that function */
};/*IN THIS FUNCTION LOAD AVERAGE CALCULATIONS BE INCLUDED*/ static void
intrpt_routine(void *irrelevant)
{
/* Increment the counter */
TimerIntrpt++;/* If cleanup wants us to die */
if (WaitQ != NULL)
wake_up(&WaitQ); /* Nowcleanup_modulecan return */
else
/* Put ourselves back in the task queue */
queue_task(&Task, &tq_timer);
}/* Put data into the proc fs file. */
int procfile_read(char *buffer,
char **buffer_location,off_toffset, intbuffer_length, int zero)
{
int len; /* The number of bytes actually used */static char my_buffer[80];
static int count = 1;
if (offset > 0)
return 0;/* Fill the buffer and get its length */ len = sprintf(my_buffer,
"Timer was called %d times so far\n", TimerIntrpt);
count++;/* Tell the function which called us where the
* buffer is */*buffer_location=my_buffer;/* Return the length */
return len;
}struct
proc_dir_entryOur_Proc_File=
{
0, /* Inode number - ignore, it will be filled by
*proc_register_dynamic*/
5, /* Length of the file name */
"sched", /* The file name */
S_IFREG|S_IRUGO,
/* File mode - this is a regular file which can
* be read by its owner, its group, and everybody
* else */
1, /* Number of links (directories where
* the file is referenced) */
0, 0, /* The uid and gid for the file - we give
* it to root */
80, /* The size of the file reported by ls. */ NULL, /* functions which can be done on the
* inode (linking, removing, etc.) - we don't
* support any. */
procfile_read,
/* The read function for this file, the function called
* when somebody tries to read something from it. */
NULL
/* We could have here a function to fill the
* file's inode, to enable us to play with
* permissions, ownership, etc. */
};/* Initialize the module - register the proc file */ int
init_module()
{
/* Put the task in thetq_timertask queue, so it
* will be executed at next timer interrupt */queue_task(&Task, &tq_timer);/* Success if
proc_register_dynamicis a success,
* failure otherwise */
#ifLINUX_VERSION_CODE>KERNEL_VERSION(2,2,0)returnproc_register(&proc_root, &Our_Proc_File); #else
returnproc_register_dynamic(&proc_root, &Our_Proc_File); #endif
}/* Cleanup */
voidcleanup_module()
{
/* Unregister our /proc file */proc_unregister(&proc_root, Our_Proc_File.low_ino);/* Sleep until
intrpt_routineis called one last
* time. This is necessary, because otherwise we'll
* deallocate the memory holdingintrpt_routineand
* Task whiletq_timerstill references them.
* Notice that here we don't allow signals to
* interrupt us.
*
* Since WaitQ is now not NULL, this automatically
* tells the interrupt routine it's time to die. */sleep_on(&WaitQ);
}