CS 4513 Distributed Computing Systems WPI, D Term 2001
Craig E. Wills Project 2 (30 pts)
Assigned: Thursday, March 29, 2001 Due: Monday, April 9, 2001

Introduction

This project is intended for you to add Linux kernel support for a more efficient mechanism, in comparison to the previous project, for determining when a file is modified.

WatchFile System Calls

In the latter portion of the previous project, you logged a message in the system log file for every modified file in the wpi file system. In the the first part of this project you will develop new system calls for better control on which files are watched in the kernel for modification. The two system calls RegisterWatchFile() and UnRegisterWatchFile() should be added to the virtual file system level of the Linux kernel, similar to the GetFileModTime() system call of the previous project. The system calls have the following interfaces

int RegisterWatchFile(char *file_name)
int UnRegisterWatchFile(char *file_name)

where each takes a file name and returns a zero on success and -1 if an error occurs.

The RegisterWatchFile() routine should map the given file name to its inode and add this inode to a list of inodes being watched. You will also need to save the process id (pid) of the process doing the registration. This value can be obtained from the global variable current, which is a pointer to a task_struct in the kernel. The value of current->pid contains the pid of the current process. It is possible that more than one process can register interest in the same file. It is suggested that you simply treat these as two separate entries in the list. If a process tries to register the same file more than once then your system call should ignore the second request.

The UnRegisterWatchFile() routine should simply remove the given file's inode from the watch list.

Given that your list of watched files is a shared resource and you do not want an interrupt while these tables are being updated, you should disable/enable interrupts during access using the cli() and sti() calls documented on the Fossil Web page for adding a system call. You can see a simple use of these routines in the file kernel/info.c.

In addition to writing the two system calls, you also need to create a kernel-level function CheckWatchFile() with the following interface

void CheckWatchFile(struct inode *inode)

This function should also be implemented in the virtual file system of Linux. It checks the watch file list for the inode number of the given inode pointer and if the inode number is in the list then the function should printk() to print a message to the system log as done in the previous project. The message should look like the following:

FILEMOD inode# systime

where FILEMOD is for easy identification in the log. The remainder of the line is the numeric inode of the modified file (st_ino field of the stat structure) and the system time in seconds.

You will need to modify the code for the wpi file system so that whenever an existing file is modified (not when a new file is created), you should call the CheckWatchFile() routine and not use printk() to log the modification directly. The idea of this approach is to only log files that have been explicitly put on the watch list rather than modifications to all files.

Filewatch2 Application

At this point you should modify your filewatch2 application from the previous project to use the new RegisterWatchFile() system call. The new application should use UnRegisterWatchFile() system call to unregister all files before it exits. Your filewatch2 application can periodically read the system log file as you did in the revised project 1.

Process Notification

Your revised kernel and application work well to only track a set of watched files, but your filewatch2 application is inefficient in that it needs to continually read the system log file to see if new messages are available. In the next portion of the project you will improve upon this aspect.

The improvement will be to send a software interrupt (use SIGIO) to the process that has registered a file to be watched. Sending this software interrupt will be done in the CheckWatchFile() routine in addition to adding a line to the system log file with printk(). When the CheckWatchFile() routine matches an inode number, it will use the pid stored with the inode number to notify that pid.

The way in which notification should be done is loosely modeled on the code for the routine send_sigio() in the file fs/fcntl.c. The system call fcntl() controls information about a file descriptor. One of the features is to control sending the SIGIO software interrupt to a process that sets the O_ASYNC flag on a file descriptor when input is available on the file descriptor. Unfortunately this feature does not work for file descriptors associated with regular files so you will mimic this feature.

Once your CheckWatchFile() routine knows that a watched file has been modified then it should call invoke the routine for_each_task(p) (as done in send_sigio()). This routine is actually a macro defined in include/linux/sched.h that iterates through the set of current processes (p). You should perform this loop and look to match the pid you have stored in your watch list with a pid for a current process. Once you have made a match then you can send the signal using the statement

send_sig(SIGIO, p, 1);

This statement will cause the SIGIO interrupt to be sent to the process p, which is a pointer to a task structure with the matched pid. Note your watch list may have more than one entry for a given inode number. Also you may want to delete an entry from your watch list if there is not current process with the given pid.

Filewatch3 Application

At this point you should create a new application filewatch3, which uses the new notification method. You will need to create an interrupt handler for the SIGIO signal where this handler will then continue reading from the system log file looking for new entries to match inodes of interest. All of the primary work for this application will now reside in the interrupt handler with the main routine only needing to be an infinite loop with a long sleep() built into it. This application will now avoid having to periodically poll the contents of the system log.

Evaluation

As part of your project, you need to compare the results of your three applications (filewatch, filewatch2 and filewatch3) in terms of the total miss time and the total number of modifications detected. What are inefficiencies in each approach?

Basic Objective

The basic objective of the project is to complete the user-level and kernel-level work needed to implement the filewatch2 and filewatch3 applications (although completing filewatch3 will make filewatch2 unneeded). Successful completion of the filewatch2 application with needed kernel modifications is worth 18 points. Additional completion of the needed user-level and kernel-level work for filewatch3 is worth 26 points.

Suggestion: How you manage the watch file list is up to you, but we suggest you test your code for managing the list in a user-level test program before compiling it into the kernel. Debugging code in the kernel is more difficult than in user space.

Additional Work

To receive full credit for the project you again need to handle an arbitrary number of files on the command line.

You also need to use a different log file for logging file modifications. Rather than use the standard system log of /var/log/messages, you should use a different log where only file modifications will be logged. To do so you will need to edit /etc/syslog.config and add the following line at the end

kern.info        /var/log/kerninfo

and then execute sudo /etc/rc.d/syslogd restart

This change will cause log messages from kernel that have LOG_INFO priority to be put in the file /var/log/kerninfo. For example, the following printk() statement in the kernel will print a line containing ``FOSSIL: Test Message'' in /var/log/kerninfo.

printk(KERN_INFO "FOSSIL: Test Message\n");

Make sure you use the newline character at the end of the message to flush out the buffer. See the man pages for syslog, syslog.conf and printk for more details. You should also modify your filewatch2 and filewatch3 applications to use this log file.

You can also instrument other file systems, such as the ext2 file system to call CheckFileMod() when files from those file systems are modified. This change would allow all files to be watched (but don't watch the system log file--think about it!).

Submission of Assignment

Details on submission of the project will be provided near the project completion date. They will be similar to the last project.