devices / fjlesystems (start) 1
last time practical LRU approximations second chance SEQ: active/inactive list CLOCK algorithms generally (scanning accessed bits) being proactive writeback in advance readahead maintaining little list of pre-evicted pages recall: bufgers in the kernel device fjles 2
ways to talk to I/O devices user program read/write/mmap/etc. fjle interface regular fjles fjlesystems device fjles device drivers 3
devices as fjles talking to device? open/read/write/close typically similar interface within the kernel device driver implements the fjle interface 4
example device fjles from a Linux desktop /dev/snd/pcmC0D0p — audio playback confjgure, then write audio data /dev/sda , /dev/sdb — SATA-based SSD and hard drive usually access via fjlesystem, but can mmap/read/write directly /dev/input/event3 , /dev/input/event10 — mouse and keyboard can read list of keypress/mouse movement/etc. events /dev/dri/renderD128 — builtin graphics DRI = direct rendering infrastructure 5
devices: extra operations? read/write/mmap not enough? audio output device — set format of audio? headphones plugged in? terminal — whether to echo back what user types? CD/DVD — open the disk tray? is a disk present? … extra POSIX fjle descriptor operations: ioctl (general I/O control) — device driver-specifjc interface tcsetattr (for terminal settings) fcntl … also possibly extra device fjles for same device: /dev/snd/controlC0 to confjgure audio settings for /dev/snd/pcmC0D0p , /dev/snd/pcmC0D10p , … 6
Linux example: fjle operations (selected subset — table of pointers to functions) }; ... ... unsigned long mmap_supported_flags; ... ... ... struct file_operations { 7 ssize_t (*read) ( struct file *, char __user *, size_t, loff_t *); ssize_t (*write) ( struct file *, const char __user *,x size_t, loff_t *); long (*unlocked_ioctl) ( struct file *, unsigned int , unsigned long ); int (*mmap) ( struct file *, struct vm_area_struct *); int (*open) ( struct inode *, struct file *); int (*release) ( struct inode *, struct file *);
special case: block devices devices like disks often have a difgerent interface unlike normal fjle interface, works in terms of ‘blocks’ block size usually equal to page size read/write page at a time 8 for working with page cache
Linux example: block device operations struct block_device_operations { ... }; read/write a page for a sector number (= block number) 9 int (*open) ( struct block_device *, fmode_t); void (*release) ( struct gendisk *, fmode_t); int (*rw_page)( struct block_device *, sector_t, struct page *, bool ); int (*ioctl) ( struct block_device *, fmode_t, unsigned , unsigned long );
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 10
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 10
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 10
xv6: device fjles (1) struct devsw { }; extern struct devsw devsw[]; inode = represents fjle on disk pointed to by struct fjle referenced by fd 11 int (*read)( struct inode*, char *, int ); int (*write)( struct inode*, char *, int );
xv6: device fjles (2) struct devsw { }; extern struct devsw devsw[]; array of types of devices special type of fjle on disk has index into array “device number” created via mknod() system call similar scheme used on real Unix/Linux two numbers: major + minor device number 12 int (*read)( struct inode*, char *, int ); int (*write)( struct inode*, char *, int );
xv6: console devsw code run at boot: devsw[CONSOLE].write = consolewrite; devsw[CONSOLE].read = consoleread; CONSOLE is the constant 1 consoleread/consolewrite: run when you read/write console 13
xv6: console devsw code run at boot: devsw[CONSOLE].write = consolewrite; devsw[CONSOLE].read = consoleread; CONSOLE is the constant 1 consoleread/consolewrite: run when you read/write console 13
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 14
xv6: console top half (read) sleep(&input.r, &cons.lock); put thread to sleep r = reading location, w = writing location if at end of bufger } ... release(&cons.lock) } ... } } int ... while (input.r == input.w){ while (n > 0){ acquire(&cons.lock); target = n; ... { 15 consoleread( struct inode *ip, char *dst, int n) if (myproc() − >killed){ return − 1;
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 16
xv6: console top half (read) int to user bufger (passed to read) copy from kernel bufger } ... release(&cons.lock) } break ; if (c == '\n') *dst++ = c; ... c = input.buf[input.r++ % INPUT_BUF]; ... while (n > 0){ acquire(&cons.lock); target = n; ... { 17 consoleread( struct inode *ip, char *dst, int n) −− n; return target − n;
xv6: console top half (read) int to user bufger (passed to read) copy from kernel bufger } ... release(&cons.lock) } break ; if (c == '\n') *dst++ = c; ... c = input.buf[input.r++ % INPUT_BUF]; ... while (n > 0){ acquire(&cons.lock); target = n; ... { 17 consoleread( struct inode *ip, char *dst, int n) −− n; return target − n;
xv6: console top half wait for bufger to fjll no special work to request data — keyboard input always sent copy from bufger check if done (newline or enough chars), if not repeat 18
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 19
xv6: console interrupt (one case) break ; lapcieoi: tell CPU “I’m done with this interrupt” kbdintr: actually read from keyboard device } ... } ... lapcieoi(); void kbdintr(); case T_IRQ0 + IRQ_KBD: ... ... 20 trap( struct trapframe *tf) { switch (tf − >trapno) {
xv6: console interrupt (one case) break ; lapcieoi: tell CPU “I’m done with this interrupt” kbdintr: actually read from keyboard device } ... } ... lapcieoi(); void kbdintr(); case T_IRQ0 + IRQ_KBD: ... ... 20 trap( struct trapframe *tf) { switch (tf − >trapno) {
device driver fmow get interrupt from device trap handler “bottom half” device hardware store and return request result send more to device (if needed) wake up thread (if needed) update bufgers put thread to sleep (if needed) thread making read/write/etc. “top half” send or queue I/O operation (e.g. previous keypresses to keyboard) check if satisfjed from bufgers page cache miss/eviction… read/write/… system call or get I/O request 21
xv6: console interrupt reading kbdintr fuction actually reads from device adds data to bufger (if room) wakes up sleeping thread (if any) 22
Recommend
More recommend