Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: $Revision: 1.6.2.16 $; site ISM780B.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!decvax!yale!ISM780B!tim From: tim@ISM780B.UUCP Newsgroups: net.unix-wizards Subject: Re: /dev/null Message-ID: <28500053@ISM780B.UUCP> Date: Tue, 26-Nov-85 18:00:00 EST Article-I.D.: ISM780B.28500053 Posted: Tue Nov 26 18:00:00 1985 Date-Received: Sat, 30-Nov-85 00:31:15 EST References: <593@ttrdc.UUCP> Lines: 66 Nf-ID: #R:ttrdc:-59300:ISM780B:28500053:000:2523 Nf-From: ISM780B!tim Nov 26 18:00:00 1985 All IO system calls eventually end up as a call to a device driver. Which driver is determined by the major device number, via a table called bdevsw[] for block devices, and cdevsw[] character devices. The items in these tables are structures that contain, among other things, pointers to the routines to handle read and write ( for character devices ), or a routine called the strategy routine ( for block devices ( this is sort of a combined read and write routine ) ). When the routine for the device driver is called, it is given the minor device number, which it uses in whatever way it wants. A typical device, such as a magtape, will use some bits of the minor device number to determine which of several tape drives to use, and the other bits to indicate things like density, write-enable, or whatever. It is the job of the device driver to transfer the data to/from the device. Let's concentrate on character devices ( like /dev/{null,mem, kmem} ). When the read or write routine is called, u.u_base will point to the data to transfer, u.u_count will tell how may bytes to transfer, and u.u_segflg will tell if u.u_base is a kernel address or a user address. u.u_offset tells where in the device to read/write from/to. For /dev/{mem,kmem,null}, the write routine looks something like this: mwrite( minor ) { switch ( minor ) { case KMEM: /* * verify that the requested address is part of kernel * memory, make sure that the user address is in the * users address space. Transfer the data. */ break; case NULL: u.u_offset += u.u_count; /* ?not sure */ u.u_count = 0; /* means all data xfered */ break; case MEM: /* * a lot like KMEM */ } Note that to most of the kernel, this looks just like a write to any other character device, such as a line printer. The sequence from the system call to the device goes something like this: 1. you do a write system call 2. UNIX figures out it is a write system call 3. Sets up u.u_base, u.u_count and u.u_segflg from yur parameters to write 4. uses the file descriptor you gave it to find out the inode 5. notes that inode is for a character device 6. gets the major and minor device number from the inode 7. Does something like (*cdevsw[ major ].write_routine)( minor ); Block devices are very similar, except that they are given a pointer to a buffer to transfer, and the system will not call the device if the data is in the buffer cache. Tim Smith ima!ism780!tim ihnp4!cithep!tim