Operating Systems 2015F: Tutorial 2

From Soma-notes
Revision as of 14:31, 23 September 2015 by Soma (talk | contribs)

In this tutorial you will be learning about device files, filesystems, and simple kernel modules.

Device files

  1. Look at the details of files in /dev. What kind of filesystem stores these files? (Hint: look at the output of df.)
  2. How can you tell the difference between block and character devices using ls?
  3. What block device is used for the root filesystem on your system (the class VM or other Linux system)?
  4. When you type commands in a terminal window, you are interacting with a "pseudo tty" character device. Specifically, what device file(s) are being used by the terminal window, and what are the permissions and special file attributes (major, minor numbers) of these files? Are the permissions important?


Filesystems

  1. [1] dd if=/dev/zero of=foo bs=8192 count=32K What is the logical size of the file? How much space does it consume on disk? (Hint: Look at the size option to ls.)
  2. [1] Run mkfs.ext4 foo. (Say "yes" to operating on a regular file.) Does foo consume any more space?
  3. [1] What command do you run to check the filesystem in foo for errors?
  4. [1] Run mount foo /mnt. How does this command change what files are accessible?
  5. [1] Run df. What device is mounted on /mnt? What is this device?
  6. [1] Run rsync -a -v /etc /mnt. What does this command do? Explain the arguments as well.
  7. [1] Run umount /mnt. What files can you still access, and what have gone away?
  8. [1] Run dd if=/dev/zero of=foo conv=notrunc count=10 bs=512. How does the "conv=notrunc" change dd's behavior (versus the command in question 1)?
  9. [1] Run sudo mount foo /mnt. What error do you get?
  10. [1] What command can you run to make foo mountable again? What characteristic of the file system enables this command to work?
  11. [1] Run the command truncate -s 1G bar. What is the logical size of bar, and how much space does it consume on disk? How does this compare with foo?
  12. [1] How does the logical size of bar change when you create an ext4 filesystem in it? What about the space consumed on disk?


A simple kernel module

  1. Download the source for this simple module, unpack, and build it by typing "make".
  2. Install the module using "sudo insmod simple.ko". The hello message is recorded in the kernel logs. How do you view the kernel logs?
  3. Check to see that the module has been loaded. How do you do this?
  4. Remove the module from the kernel. What did you do?

A character device kernel module

  1. Download the source for ones, a kernel module implementing a character device that ouputs an unbounded string of "1"'s. Build, compile, and run it as before.
  2. What kernel messages does the module generate? Does it create any new files (other than /dev/ones)? If so, where?
  3. What happens when you "cat" the device /dev/ones? How can you limit the output?
  4. How can you modify your module to generate a kernel "Oops" as reported in the kernel logs or outright crash the kernel?

Simple module

simple.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

static int __init simple_init(void)
{
        printk ("Hello kernel world!\n");
        return 0;
}

static void __exit simple_exit(void)
{
        printk ("Goodbye kernel world.\n");
        return;
}

module_init(simple_init);
module_exit(simple_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Somayaji <soma@scs.carleton.ca>");
MODULE_DESCRIPTION("A simple module");


Makefile

obj-m := simple.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules


Ones module

ones.c

/* Code derived from:
  https://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/
  and
  http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html
*/

#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>

#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME ": %s: " format, __FUNCTION__, ## arg); } while (0)
#define err(format, arg...) pr_err(CLASS_NAME ": " format, ## arg)
#define info(format, arg...) pr_info(CLASS_NAME ": " format, ## arg)
#define warn(format, arg...) pr_warn(CLASS_NAME ": " format, ## arg)


#define DEVICE_NAME "ones"
#define CLASS_NAME "comp3000"

static struct class* ones_class = NULL;
static struct device* ones_device = NULL;
static int ones_major;

static int ones_open(struct inode *the_inode, struct file *f)
{
        return 0;
}

static ssize_t ones_read(struct file *f, char *buf, size_t len, loff_t *offset)
{
        size_t i;

        for (i = 0; i < len; i++) {
                put_user('1', buf++);
        }

        return i;
}

static int ones_release(struct inode *the_inode, struct file *f)
{
        printk(KERN_ALERT "Ones device closed\n");
        return 0;
}


static struct file_operations ones_fops = {
        .open = ones_open,
        .read = ones_read,
        .release = ones_release,
};


static char *ones_devnode(struct device *dev, umode_t *mode)
{
        if (mode)
	        *mode = 0444;
        return NULL;
}

static int __init ones_init(void)
{
        int retval;
  
        ones_major = register_chrdev(0, DEVICE_NAME, &ones_fops);
        if (ones_major < 0) {
                err("failed to register device: error %d\n", ones_major);
                retval = ones_major;
                goto failed_chrdevreg;
        }
 
        ones_class = class_create(THIS_MODULE, CLASS_NAME);
        if (IS_ERR(ones_class)) {
                err("failed to register device class '%s'\n", CLASS_NAME);
                retval = PTR_ERR(ones_class);
                goto failed_classreg;
        }
 
	ones_class->devnode = ones_devnode;

        ones_device = device_create(ones_class, NULL, MKDEV(ones_major, 0),
                                    NULL, DEVICE_NAME);

        if (IS_ERR(ones_device)) {
                err("failed to create device '%s'\n", DEVICE_NAME);
                retval = PTR_ERR(ones_device);
                goto failed_devreg;
        }
        
        info("Ones device registered using major %d.\n", ones_major);
        
        return 0;
        
 failed_devreg:
        class_unregister(ones_class);
        class_destroy(ones_class);
 failed_classreg:
        unregister_chrdev(ones_major, DEVICE_NAME);
 failed_chrdevreg:
        return -1;
}

static void __exit ones_exit(void)
{
        device_destroy(ones_class, MKDEV(ones_major, 0));
        class_unregister(ones_class);
        class_destroy(ones_class);
        unregister_chrdev(ones_major, "ones");
        info("Unloading Ones module.\n");
        return;
}

module_init(ones_init);
module_exit(ones_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Somayaji <soma@scs.carleton.ca>");
MODULE_DESCRIPTION("A write ones character device module");


Makefile

obj-m := ones.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules