Device Drivers & Kernel Modules

the file_operations table

When you open a file or a device and call read() or write(), how does the kernel know which code to run? Different devices need totally different behavior for the same call. The file_operations table is the driver's answer card: a struct full of function pointers, one per operation, that tells the kernel 'when someone reads me, call THIS function; when someone writes me, call THAT one.' It is how one universal syscall, read(), reaches the right driver-specific handler.

Concretely, struct file_operations has members like .read, .write, .open, .release, .unlocked_ioctl, .mmap, and .llseek, each a pointer to a function with a fixed signature. A driver fills in only the operations it supports and leaves the rest NULL; a NULL slot means that operation is unsupported (and the kernel returns an error or a sensible default). When userspace calls read(fd, ...), the kernel looks up the struct file behind that descriptor, follows it to the file_operations table, and calls table->read(...). This is plain function-pointer dispatch — the kernel's version of an interface or vtable, written by hand in C. The .owner = THIS_MODULE field lets the kernel pin your module in memory while a file is open so it cannot be unloaded out from under an active call.

It matters because the file_operations table is the seam where the unified everything-is-a-file model meets device-specific code, and it is the first thing you write for any character driver. A subtle correctness point: these handlers run in the context of whatever process called in, can sleep (for most fops), and may be entered by many processes at once — so any shared state a handler touches needs its own locking. NULLing out an operation is a deliberate choice, not laziness: it is how you say 'this device does not do seeks.'

static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off) { ... } static const struct file_operations fops = { .owner = THIS_MODULE, .read = my_read, // read() lands here // .write left NULL -> writing returns an error };

A table of function pointers maps each syscall to the driver's handler; a NULL slot means that operation is unsupported.

Handlers can run concurrently for the same device (many openers), so shared state needs locking. Set .owner = THIS_MODULE so the module cannot be unloaded while a file is open.

Also called
fopsstruct file_operations檔案操作表