Assignment 3: Tape Device¶
Announcement date: 05.05.2026
Warning
Make sure you have the latest version of QEMU:
commit 0855a81f6f1c6f5700e30cc9c5a46ce1b096fc10
Published on May 09.
After pulling, make sure to recompile QEMU. Otherwise, read/write commands may not work correctly with some pagetable configurations.
Due date: 02.06.2026 (final due date 16.06.2026)
Additional materials¶
tapedev.h- header with basic device constantsz3-tests-2026.tar.gzpublic tests for the driver
Introduction¶
Storage is a hard problem that spawned many different hardware and software solutions, often tailored for a very niche, specific use case. One of these use cases is long-term data storage, for example, archives or backups.
A hardware solution often used for such archives is a tape library. While Using magnetic tapes for data storage may seem dated, new solutions based on tapes are still being developed. LTO-10 magnetic tape specification was released in January 2026, and it supports tapes with up to 40 TB of capacity. While the maximum speed of 400 MB/s may seem relatively low for today's SSD standards (and remember that tape is basically a rotational drive), the capacity is very impressive. A single tape library is meant to store many such tapes, allowing the user to reach petabytes of backup/archive capacity easily.
While such devices usually communicate over interfaces like Fibre Channel or SAS, our device consists of two parts: a PCI card that exposes a special proprietary interface, and the tape library itself, connected to the PCI card. To expose the functionality of the device to the operating system in a convenient way, you will use the abstraction of the block device layer.
In this task, you will implement a Linux PCI driver for this imaginary tape library, called tapedev. To make testing convenient, the tapes used by the device are small.
The kernel driver should expose the device as a block device. For every
Tapedev device attached, it should create a /dev/tapedevX block
device, where X is the number of the attached device, starting from 0.
Every tapedev consists of up to 8 separate, independent sections.
Each section of the tape device should be represented by a file named
/dev/tapedevXsN where N is the number of the section starting from 0.
Block device interface¶
Your task is to write a block layer driver for this device. Each section of the device should be exposed as a separate block device, all tapes in a single section are meant to form a single continuous block device.
The driver should support REQ_OP_READ and REQ_OP_WRITE block layer operations,
support for other operations is not required.
Each section file should also support two ioctl calls:
ioctl(TAPEDEV_IOCTL_GET_INFO)- copy information about section (number of tapes type of tape, currently inserted tape) into a structure in the userspace.ioctl(TAPEDEV_IOCTL_EJECT_TAPE)- wait until driver stops processing current read/write request, eject tape (if inserted).
The device should also expose three read-only sysfs attributes:
/sys/block/tapedevXsN/tape/tape_type- type of the tape (from 0 to 4)/sys/block/tapedevXsN/tape/tapes- number of tapes/sys/block/tapedevXsN/tape/current_tape- currently inserted tape or 0
The driver should utilize zero-copy techniques wherever possible - the device should write the data directly into (DMA-mapped) biovec buffers. The driver should Support reading/writing at least 512 segments in a single request/command. It is permitted to handle a request that spans many tapes in multiple commands.
Hints¶
Useful sources:
The following functions may be useful:
register_blkdevblk_mq_alloc_sq_tag_setblk_mq_alloc_diskset_capacitydevice_add_diskblk_rq_map_sg
Other hints:
It is okay to handle only a single block layer request at once.
You may want to be careful with DMA alignment restrictions.
You may want to use WARN macros to make sure that your assumptions hold during tests.
Solution format¶
The device driver should be implemented in C as a Linux kernel module, working
with the lab's kernel version. The compiled module should be called
tapedev.ko.
Submit an archive named ab123456.tar.gz
(where ab123456 is your student's login).
After unpacking, the package should create the ab123456 directory
with the following contents:
the module source files
MakefileandKbuildfiles—runningmakeshould build thetapedev.komodulea README file with a brief description of your solution, including driver design choices (e.g., regarding locking, fences) and code structure
Grading¶
You can obtain up to 10 points. The assignment is graded based on automated tests and code review. The tests include the provided examples but also some other undisclosed tests that are variations of the provided examples
For the code review, points may be deducted for:
detected errors, e.g., regarding locking or memory leaks
minor deductions for issues like unclear or convoluted code structure or misusing the block layer interface
The driver may consist of a single source file.
Please try to adhere to the Kernel coding style. You may want to try scripts/checkpatch.pl, although remember that it requires the submission to be formatted as a patch, not as a .c file.
QEMU¶
Tapedev is implemented as a PCI device in QEMU.
To use the Tapedev device, a modified version of QEMU is required. It is available in source code form.
Warning
Make sure you have the latest version of QEMU:
commit 0855a81f6f1c6f5700e30cc9c5a46ce1b096fc10
Published on May 09.
After pulling, make sure to recompile QEMU. Otherwise, read/write commands may not work correctly with some pagetable configurations.
To compile it:
Clone the repository: https://gitlab.uw.edu.pl/zso/2026l-public/zad3-public.git
Ensure that the following dependencies are installed: ncurses, libsdl, curl, and in some distributions also ncurses-dev, libsdl-dev, curl-dev (package names may vary).
Run
./configurewith the desired options. Suggested flags:--target-list=x86_64-softmmu --enable-virtfs --enable-gtk --extra-cflags='-Wno-discarded-qualifiers -Wno-unused-but-set-variable'
Change into the build directory:
cd build
Run
make(orninjaif installed).Install with
make installor run the binary directly (build/qemu-system-x86_64).
To emulate Tapedev:
Pass the option
-device {"driver":"tapedev", ...}to QEMU. Repeat it to emulate multiple devices.
The device takes arguments formatted as JSON, for example:
-device '{"driver":"tapedev","data_dir":"data","tape_types":[0,1,2,3,4],"tapes":[50,40,30,20,10]}'
data_dir- directory on the host where tape data will be storedtape_types- array of tape type (0-4) of each sectiontapes- array of numbers of tapes for each sectionfast_mode- if set to false, the device will take more time to execute commands
To add the Tapedev device live (while QEMU is running):
Make sure you passed
-qmp tcp:localhost:4444,server,wait=offas an argument when starting qemuOpen a netcat connection to the QMP socket: nc -v localhost 4444
Paste
{ "execute": "qmp_capabilities" }Paste
{"execute": "device_add", "arguments": {"driver": "tapedev", "data_dir": "data", "tape_types": [0,1,2,3,4], "tapes": [50,40,30,20,10] } }Run
echo 1 > /sys/bus/pci/rescanto detect the device in Linux.
To simulate device removal:
Run:
echo 1 > /sys/bus/pci/devices/0000:<device_id>/remove