Homework 3
Due November 30th via handin
In this assignment you'll be modifying several system calls, so it will be useful to know where these calls are defined. A handy program for navigating large coding projects is Cscope, which builds a database of your code and allows you to intelligently search it. I'll describe how to use Cscope in case you are interested -- it is completely optional, and takes some practice to use. Another option is an online cross reference, such as the one at linux.no.
First you'll need to install it:
sudo apt-get install cscope
Then you'll need to tell it to build a database (this may take a while):
cd linux cscope -b -q -k -R
Finally, to invoke cscope, make sure you're in your linux source code directory and run:
cscope -d
You'll need to be in your linux source directory every time you run it, since that's where it will build its symbol database. You can experiment with different command line options to store the database elsewhere.
Cscope is a text-based program that divides the window into 2 panes. The top pane contains search results, and the bottom pane allows you to perform different types of searches. You can navigate between panes using the tab key, and between items within a pane using the arrow keys. The bottom pane looks something like this:Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file:
It takes some getting used to, but try this: open Cscope, use the down arrow to select "global definition", then type in sys_read and hit enter. Cscope will open up your editor at the line where sys_read is defined. By default your editor is vi, so you can use :q to return to Cscope. When there are multiple search results, you will move to the top pane and can select a result with the arrow keys.
To quit Cscope, press control-d.
Inside a variety of system calls, you'll be checking if a flag is set (similar to PA2), and if so then using printk to output statistics to the system log. The assignment sheet tells you what to print out for each call.
Some information is available directly from the system call parameters, and some must be obtained using additional functions to obtain pointers to kernel data structures. As a starting point, you'll want to be familiar with the file structure, given below.
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;
unsigned long f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
};
You'll need to figure out how to grab the inode number associated with a file structure. There's a chain of pointers that will lead you there. I would start with file->f_dentry, and follow the chain until you can access the file's inode->i_ino. You can verify the inode by using the -i flag of the ls command, shown below with abbreviated dmesg output.
# dmesg [ 74.457862] open path urandom inode 3293 flags 0 # ls -i /dev/urandom 3293 /dev/urandom
struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};
struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILING
struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
struct qstr {
unsigned int hash;
unsigned int len;
const unsigned char *name;
};
struct inode {
struct hlist_node i_hash;
struct list_head i_list;
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
atomic_t i_count;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
unsigned long i_version;
loff_t i_size;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
unsigned int i_blkbits;
blkcnt_t i_blocks;
unsigned short i_bytes;
umode_t i_mode;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
struct mutex i_mutex;
struct rw_semaphore i_alloc_sem;
struct inode_operations *i_op;
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
struct file_lock *i_flock;
struct address_space *i_mapping;
struct address_space i_data;
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
};
int i_cindex;
__u32 i_generation;
#ifdef CONFIG_DNOTIFY
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
#endif
#ifdef CONFIG_INOTIFY
struct list_head inotify_watches; /* watches on this inode */
struct mutex inotify_mutex; /* protects the watches list */
#endif
unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned int i_flags;
atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
void *i_private; /* fs or device private pointer */
};
You may find the do_gettimeofday function useful. It takes a struct timeval pointer as a parameter. Afterwards, the struct will contain the number of seconds since the Unix epoch (Jan. 1 1970) in the tv_sec variable.