Description
In this assignment you are going to check a simple character device driver (code snippet given below, minimal code provided on CANVAS, files/assignments/assignment6.c) for concurrency errors: deadlocks and race conditions. The driver aims to support two modes of operation: MODE1 and MODE2. In MODE1 only one user process can open and access the devices whereas in MODE2 multiple processes/threads can interact with the device concurrently. Additionally, the mode of operation can be changed at run-time via the ioctl function. We would like you to come up with tests to check for 4 different potential deadlock scenarios of your choice. The tests should include a user-space program (possibly using pthreads) that uses the original or a modified version of the driver. Please note that not every deadlock scenario may require you to insert sleep statements in the driver. So you are required to provide the modified version of the driver only if such modifications are necessary to reproduce the deadlock scenario. You should also provide a README file for each test case explaining which deadlock scenario you’re checking by specifying the line numbers of wait statements. For race conditions, we would like you to come up with 4 pairs of critical regions that may run in parallel and perform a code review rather than crafting a test program. In your review, for each critical region you should identify the data accessed in the critical region, the locks held at the the time it is entered, and your reasoning about the possibility or absence of race conditions.
int e2_open(struct inode *inode, struct file *filp) { struct e2_dev *ev; dev = container_of(inode-i_cdev, struct e2_dev, cdev); filp-private_data = dev;
down_interruptible(&dev-sem1); if (dev-mode == MODE1) { dev-count1++; up(&dev-sem1); down_interruptible(&dev-sem2); return; }
1
else if (dev-mode == MODE2) { dev-count2++; } up(&dev-sem1);
}
int e2_release(struct inode *inode, struct file *filp) { struct e2_dev *dev; dev = container_of(inode-i_cdev, struct e2_dev, cdev);
down_interruptible(&dev-sem1); if (dev-mode == MODE1) { dev-count1–; if (dev-count1 == 1) wake_up_interruptible(&dev-queue1); up(&dev-sem2); } else if (dev-mode == MODE2) { dev-count2–; if (dev-count2 == 1) wake_up_interruptible(&dev-queue2); } up(&dev-sem1);
}
// similar for write static ssize_t e2_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct e2_dev *dev = filp-private_data;
down_interruptible(&dev-sem1); if (dev-mode == MODE1) { up(&dev-sem1); // read } else { // read up(&dev-sem1); }
}
int e2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct e2_dev *dev; dev = container_of(inode-i_cdev, struct e2_dev, cdev);
… switch(cmd) {
case E2_IOCMODE2: down_interruptible(&dev-sem1); if (dev-mode == MODE2) { up(&dev-sem1);
2
break;
} if (dev-count1 1) { while (dev-count1 1) { up(&dev-sem1); wait_event_interruptible(dev-queue1, (dev-count1 == 1)); down_interruptible(&dev-sem1); } } dev-mode = MODE2; up(&dev-sem2); up(&dev-sem1);
break;
case E2_IOCMODE1: down_interruptible(&dev-sem1); if (dev-mode == MODE1) { up(&dev-sem1); break; } if (dev-count2 0) { while (dev-count2 0) { up(&dev-sem1); wait_event_interruptible(dev-queue2, (dev-count2 == 0)); down_interruptible(&dev-sem1); } } dev-mode = MODE1; down(&dev-sem2); up(&dev-sem1);
break;
…
}
The assignment is due Wednesday, April 11th by midnight. Please submit all your test programs, modified versions of the driver, and README files on CANVAS.