CSCI 401 Operating Systems

10 Dec

CSCI 401 Operating Systems Instructor: Gedare Bloom Project 2 (100 points)
You must do this assignment in collaboration with your assigned team members, if any. You may not use code downloaded from the Internet. Always watch the course website for updates on the assignments.
Read all instructions carefully. Start early. I recommend completing one Part each week.
Due Sunday, October 30
Part 0 (0 points): Due Wednesday, October 12
This project will be completed in teams of 2. Both team members will receive the same grade subject to participation. You are expected to work together, in person, at the same computer. You may choose your own team member. You and your team member must arrange to join the same Project2_Groups on Blackboard prior to submitting. Send the instructor an e-mail if you have trouble and need a manual adjustment of your group.
You will need a Linux development environment for this assignment, in particular you need to be able to boot and run the Linux kernel version 3.16.0. I recommend that you install Virtualbox and download the virtual machine (VM) available from the text book’s companion site — You have to select the “Operating Systems Concepts” book and find the link to the Linux Virtual Machine. While you’re on the site I highly recommend you browse around. The VM is a big file (almost 3 GB) so you will want to start the download immediately.
The LKD book and supplemental LDD book (available as PDF) will be helpful.
If you do use the VM from the text book web site, you need to do a little bit of system administration to add some additional hard drive space, because the hard disk it comes with is not large enough to recompile Linux. Without starting the VM, but after you download it and import it into Virtualbox, open Virtualbox, right-click on the OSC-2016 machine, and select “Settings”. Go to the Storage menu, right-click on the SATA controller, and add another Hard Disk. You can select the VMDK format, and probably should use at least a 16 GiB drive. You should see “NewVirtualDisk1.vmdk” under the Controller: SATA item. Now boot the VM. The new disk should be available as /dev/sdb, but it needs to be partitioned and formatted to be usable. Run sudo gdisk and type device filename /dev/sdb to select the new disk. Type p to see the current disk information, it should show you on the first line the name “Disk /dev/sdb: … 16.0 GiB”, and further down that the “Total free space … sectors”. If not, you have the wrong disk and need to seek help elsewhere. Now you will create a partition by entering command n. Then just hit enter a few times to accept the defaults, and when you get the “Command” prompt again, type p and you should see a partition now. Write out the partition with the w command. Now you have a partition, and you need to create a filesystem on it. We will
use the ext3 file system, so just run sudo mkfs.ext3 /dev/sdb1 Note sdb1 this time, because we’re making the file system on partition 1 that we just created. Congratulations, you made a file system! Now create a mount point for it, and mount it. Let’s use sudo mkdir /linux and then sudo mount /dev/sdb1 /linux followed by sudo chown -R oscreader /linux and finally cd /linux. Eventually you will want to add this mount point to the /etc/fstab file, so open it and add the line:
/dev/sdb1 /linux ext3
Download the kernel source for 3.16.0 from and move it into /linux, then uncompress and untar it to get /linux/linux-3.16 directory.
Enter the linux-3.16 directory, open the Makefile in a text editor, and modify EXTRAVERSION= by adding a . and an extra version number or string, “EXTRAVERSION=.project2”.
Configure the kernel:
cp /boot/config-* .config
make oldconfig
You may need to answer a few questions, but the default should be OK so just hit “Enter” through all of the prompts. Now compile the kernel:
make –j2
Coffee Break.
Install the kernel and modules:
mkdir /linux/mykernels
make INSTALL_PATH=/linux/mykernels install
make INSTALL_MOD_PATH=/linux/mykernels modules_install
cd /linux/mykernels
sudo cp vmlinuz-3.16.0.project2 /boot/
sudo cp /boot/
sudo cp –r ~/mykernels/lib/modules/3.16.0.project2 /lib/modules
sudo mkinitramfs -o /boot/initrd-3.16.0.project2.img 3.16.0.project2 sudo update-grub
Reboot the machine and enter the advanced options in the grub menu and then select the newly compiled kernel to boot it.
You can check the running kernel by executing the command uname –a in the shell.
You’re ready to start hacking (this version of) Linux!
Part 1: Informative kernel modules (40 points)
(a) The pid_info module.
You will write a simple kernel module called pid_info. The module should cleanly load and unload an unlimited number of times. The module should take a parameter of the pid of a specific process. When loaded, the module will lookup the process task_struct of the specified process and print out, using the printk() function, the following information nicely formatted.
 pid
 uid, gid of process
 parent process id and name
 all of the children processes pid and name
 any flags that are set. Make sure to translate them to readable names.
You can find the struct task_struct defined in the file linux/sched.h The LKD chapters on processes, modules and appendix A on linked lists can be helpful. There is also an example of a module and Makefile already available on the virtual machine, located at ${HOME}/osc9e-src/ch2/.
The c source file with your module should have two global variables (pid parameter and module name) and only two functions (the module init and cleanup). Use the MODULE_ macros (linux/module.h) to document the license (GPL), author, and description of your module. Your makefile should have a default target to build your modules and a clean target to remove all compiled files. Your modules should have the exact name given in the assignment.
(b) The pid_vminfo module.
Now you will write a module called pid_vminfo that creates a /proc entry file that when read, prints out the virtual memory state of a process. The virtual memory state of the process can be found by looking at the mm field of the task struct you used in the first module. You should print out at least enough information to identify the process (pid, name, …) and all of the vm_area structs that are listed in the mmap list. Additional information that is displayed in a useful format will be a bonus.
The module should print out the state of whatever process is running when its proc file is read. So it does not need to lookup a pid like the first module. Creating and destroying /proc entries is easy; you can do it with a single function call. Documentation on how can be found on page 11-14 of Chapter 4 Debugging of the Linux Device Drivers 3rd Edition available online.
Part 2: Implementing System Calls (40 points)
You will create three new system calls and test them. You will need to implement the system call in an existing kernel source file, add the system call to the appropriate
headers, and write or use a userspace test program to verify your system calls work correctly. Your system calls will set and retrieve the value of several variables stored in kernel space. The first variable is a variable length string, call it my_string. The second variable is an integer, call it my_accumulator.
Implementing system calls requires that you add the code for the actual call (prefixed with sys_) to an existing kernel source file, add the system call to the system call table, and add the header for the call to syscalls.h.
Make sure that your system calls have exactly the same signatures as below. Otherwise our test programs will fail to call your system calls and they will appear to fail. Function and variable names are case sensitive. All system calls should return an error code of EINVAL for inputs that are invalid. All error return values should be real Linux kernel error values (such as those found in include/linux/errno.h) that most closely match the error you are reporting. We specify a few specific errors that must be used, such as EINVAL and EOVERFLOW.
System call 1: sys_my_set_state
long my_set_state(char *the_string, int accumulator)
This call sets the value of an integer and one string. The accumulator integer passed as input must always be non-negative. The string can be arbitrarily long, but is always null terminated, so you must dynamically allocate memory to store it when set. If a string is already stored in the kernel string variable, the memory allocated to it must be correctly freed. Strings stored in the kernel variable must be null terminated. The return value should be 0 for success, or a negative error value.
System call 2: sys my_get_and_sum
long my_get_and_sum(int *my_value, int inc_value)
Take the value stored in the kernel variable my_accumulator and add the value passed in the inc_value parameter, which is always non-negative. Return the result in the my_value return value. The my_accumulator should store the updated value. If the resulting value is greater than MAX INT, then EOVERFLOW error should be returned. The return value should be 0 for success, or a negative error value.
System call 3: sys_my_get_string
long my_get_string(char *buf, int bsize)
Take the kernel string variable stored in the kernel and copy it into the user provided buffer buf of size bsize. If the kernel string variable is empty, an error of ENODATA should be returned. The returned string will always be NUL terminated and therefore the following rule should be followed for selecting the string length to return:
If slen is the length of the current string stored in the kernel variable, copy the leftmost copylen = min( slen, bsize -1) characters and append a NUL terminator to the end.
The system call should return the length of the string copied if successful, or a negative error value.
Because you will be modifying existing kernel source files, you will use the kernel build commands from Part 0 to re-compile your modified kernel.
Kernel Patches
It is very useful to be able to create kernel “patches” which show only the specific changes made and not all of the unchanged code. Since many modifications to the kernel are small (compared to the total kernel source size), such a patch can be many orders of magnitude smaller then the whole kernel. When you submit your changes to the kernel for assignments, you will submit a patch that we will apply to our copy of the kernel. So if you generate a bad patch, we may not get a working kernel even if you had it working yourself. So test applying your own patch before sending it. For this part of the assignment you need to generate a patch with only your changes to the kernel.
Testing (10 points)
You should write your own small (less than 50 line) programs that will let you test additional system call cases, such as calling your system calls in different sequences.
You should also write test programs for using your kernel modules.
Documentation (10 points)
Comment your code with /* */ style comments. Explain each function’s purpose and the use of parameters. Include your name and a brief description at the top of each source file. If something doesn’t work, you may get partial credit if your comments show that you were on the right track.
Write a README file that explains how to build and run your program, gives a brief description of your solutions, and contains any notes from discussions with others. Document any places where you received help from others.
Some helpful functions/macros are printk, kmalloc, kfree, copy from user, for_each_process, list_for_each, list_entry (man or Google these if necessary. Pay attention to return values!)
Cross-linked Linux source:
Submission Instructions (read carefully)
Your submission must consist of your README, module source code and makefiles, and kernel patch(es); do not include compiled output!. Your source code must use UNIX style EOL characters \n not DOS style \n\r. You can write code on Windows, but you must convert it to Unix text files before submitting. The dos2unix command may be useful for this. Put all of your files in a single directory with both team members last names as Lastname1Lastname2/.
Make a tar and gzip file with both team members last names in the file name.
– tar -zcvf Lastname1Lastname2.tgz Lastname1Lastname2/.
Where all of your files are in the Lastname1Lastname2 directory. Upload the tgz file to Project 2 on Blackboard.
Grading Rubric
Part 1. pid_info – 20 points
 (5) Module parameter handling correct
 (5) Task structure lookup is efficient and correct (at most once through list)
 (10) Requested fields printed using printk
o Formatting is clear
o Children list lists all children
If module does not work correctly, up to 15 points can be received based on the code design and documentation.
Part 2: pid_vminfo – 20 points
 (5) Module finds currently executing process
 (5) Proc file entry created correctly
 (5) Read operation function handles short reads by returning partial information
o (+3) Bonus if read op handles repeated reads for different byte ranges
 (5) Requested vm information printed using printk
o Formatting is clear
o All vm_area_structs are printed with address range and perms (RWXS)
o (+5) Extra MM relevant information that is printed
If module does not work correctly, up to 15 points can be received based on the code design and documentation.
Part 3: System Calls – 40 points
 (5) Proper Modification of syscall_table.S – 5
 (10) my_set_state
o (5) Use copy_from_user to move data from user space to kernel space.
o (3) Use copy_from_user to move data from user space to kernel space (efficiency points deducted).
o (1) Use strnlen_user to find the string length of user space string.
 (10) my_get_and_sum
o (5) Use copy_to_user to move data from kernel space to user space.
 (10) my_get_string (using copylen)
o (2): correct return length
o (5): Use copy_to_user to move data from kernel space to user space.
o (3): Use copy_to_user to move data from kernel space to user space.
o Efficiency points may be lost if you forget to:
 (3) Use copy_to_user or put_user to set null-term.
 (3) Set null-term if copied amount is smaller than string stored.
 (3) Calculate the correctly shortened buffer.
 (5) Proper Patch File
o No extra files in patch, generated correctly from top level directory
o Applies cleanly to vanilla 3.16.0 kernel.
Up to 25 points may be earned for the quality of algorithms and explanations in code if the system calls are not implemented correctly.
Testing and evaluation of modules and syscalls – 10 points
 (7) Basic operation tested (loads, unloads, calls execute).
o (3) syscall test description.
o (4) Module test description.
 (3) Checks for error conditions and displays useful output.
Documentation and Writeup – 10 points
 (5): Writing Matters.
 (5) Documentation in comments and README are clear and sufficient. Document all functions, parameters, and files. Discuss any problems, features, and testing.
Miscellaneous reasons points may be lost:
* Module load/unload does not catch errors or crashes – 5
* Internal kernel functions error return are not always checked and handled – 10
* -5: Fails to check copy_to/from_user.
* -5: Fails to check kmalloc.
* Calling System Calls out of Order Crashes – 5
* -1: Get before Set string fails, but no crash.
* -3: Get before Set string causes seg fault
* -5: Get before Set fails for both string and accumulator.
* Error return values incorrect (EOVERFLOW, EINVAL, ENODATA, …) – 10
* -2: Didn’t use -ENOMEM for kmalloc failures.
* -2: Didn’t use -EFAULT for general failures.
* -2: Didn’t use negative of error conditions: e.g., return -ENOMEM;
* -3: Overflow not properly detected.
* Misuse of KMalloc – 5
* unnecessary free/realloc
* incorrect size of buffer for string

Leave a comment

Posted by on December 10, 2016 in academic writing



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: