Major and Minor Numbers

Major and Minor Numbers

One of the basic features of the Linux kernel is that it abstracts the handling of devices. All hardware devices look like regular files; they can be opened, closed, read and written using the same, standard, system calls that are used to manipulate files. Every device in the system is represented by a file. For block (disk) and character devices, these device files are created by the mknod command and they describe the device using major and minor device numbers. Network devices are also represented by device special files but they are created by Linux as it finds and initializes the network controllers in the system.

To UNIX, everything is a file. To write to the hard disk, you write to a file. To read from the keyboard is to read from a file. To store backups on a tape device is to write to a file. Even to read from memory is to read from a file. If the file from which you are trying to read or to which you are trying to write is a “normal” file, the process is fairly easy to understand: the file is opened and you read or write data. If, however, the device you want to access is a special device file (also referred to as a device node), a fair bit of work needs to be done before the read or write operation can begin.

One key aspect of understanding device files lies in the fact that different devices behave and react differently. There are no keys on a hard disk and no sectors on a keyboard, though you can read from both. The system, therefore, needs a mechanism whereby it can distinguish between the various types of devices and behave accordingly.

To access a device accordingly, the operating system must be told what to do. Obviously, the manner in which the kernel accesses a hard disk will be different from the way it accesses a terminal. Both can be read from and written to, but that’s about where the similarities end. To access each of these totally different kinds of devices, the kernel needs to know that they are, in fact, different.

Inside the kernel are functions for each of the devices the kernel is going to access. All the routines for a specific device are jointly referred to as the device driver. Each device on the system has its own device driver. Within each device driver are the functions that are used to access the device. For devices such as a hard disk or terminal, the system needs to be able to (among other things) open the device, write to the device, read from the device, and close the device. Therefore, the respective drivers will contain the routines needed to open, write to, read from, and close (among other things) those devices.

The kernel needs to be told how to access the device. Not only does the kernel need to be told what kind of device is being accessed but also any special information, such as the partition number if it’s a hard disk or density if it’s a floppy, for example. This is accomplished by the major number and minor number of that device.

All devices controlled by the same device driver have a common major device number. The minor device numbers are used to distinguish between different devices and their controllers. Linux maps the device special file passed in system calls (say to mount a file system on a block device) to the device’s device driver using the major device number and a number of system tables, for example the character device table, chrdevs. The major number is actually the offset into the kernel’s device driver table, which tells the kernel what kind of device it is (whether it is a hard disk or a serial terminal). The minor number tells the kernel special characteristics of the device to be accessed. For example, the second hard disk has a different minor number than the first. The COM1 port has a different minor number than the COM2 port, each partition on the primary IDE disk has a different minor device number, and so forth. So, for example, /dev/hda2, the second partition of the primary IDE disk has a major number of 3 and a minor number of 2.

It is through this table that the routines are accessed that, in turn, access the physical hardware. Once the kernel has determined what kind of device to which it is talking, it determines the specific device, the specific location, or other characteristics of the device by means of the minor number.

The major number for the hd (IDE) driver is hard-coded at 3. The minor numbers have the format

(<unit>*64)+<part>

where <unit> is the IDE drive number on the first controller, either 0 or 1, which is then multiplied by 64. That means that all hd devices on the first IDE drive have a minor number less than 64. <part> is the partition number, which can be anything from 1 to 20. Which minor numbers you will be able to access will depend on how many partitions you have and what kind they are (extended, logical, etc.). The minor number of the device node that represents the whole disk is 0. This has the node name hda, whereas the other device nodes have a name equal to their minor number (i.e., /dev/hda6 has a minor number 6).

If you were to have a second IDE disk on the first controller, the unit number would be 1. Therefore, all of the minor numbers would be 64 or greater. The minor number of the device node representing the whole disk is 1. This has the node name hdb, whereas the other device nodes have a name equal to their minor number plus 64 (i.e., /dev/hdb6 has a minor number 70).

If you have more than one IDE controller, the principle is the same. The only difference is that the major number is 22.

For SCSI devices, the scheme is a little different. When you have a SCSI host adapter, you can have up to seven hard disks. Therefore, we need a different way to refer to the partitions. In general, the format of the device nodes is

sd<drive><partition>

where “sd” refers to the SCSI disk driver, <drive> is a letter for the physical drive, and <partition> is the partition number. Like the hd devices, when a device refers to the entire disk, for example the device “sda” refers to the first disk.

The major number for all SCSI drives is 8. The minor number is based on the drive number, which is multiplied by 16 instead of 64, like the IDE drives. The partition number is then added to this number to give the minor.

The partition numbers are not as simple to figure out. Partition 0 is for the whole disk (i.e., sda). The four DOS primary partitions are numbered 14. Then the extended partitions are numbered 58. We then add 16 for each drive. For example:

brw-rw—- 1 root disk 8, 22 Sep 12 1994 /dev/sdb6

Because b is after the sd, we know that this is on the second drive. Subtracting 16 from the minor, we get 6, which matches the partition number. Because it is between 4 and 8, we know that this is on an extended partition. This is the second partition on the first extended partition.

The floppy devices have an even more peculiar way of assigning minor numbers. The major number is fairly easy its 2. Because the names are a little easier to figure out, lets start with them. As you might guess, the device names all begin with fd. The general format is

fd<drive><density><capacity>

where <drive> is the drive number (0 for A:, 1 for B:), <density> is the density (d-double, h-high), and <capacity> is the capacity of the drive (360KiB, 1440KiB). You can also tell the size of the drive by the density letter, lowercase letter indicates that it is a 5.25″ drive and an uppercase letter indicates that it is a 3.5″ driver. For example, a low-density 5.25″ drive with a capacity of 360KiB would look like

fd0d360

If your second drive was a high-density 3.5″ drive with a capacity of 1440KiB, the device would look like

fd1H1440

What the minor numbers represents is a fairly complicated process. In the fd(4) man-page there is an explanatory table, but it is not obvious from the table why specific minor numbers go with each device. The problem is that there is no logical progression as with the hard disks. For example, there was never a 3.5″ with a capacity of 1200KiB nor has there been a 5.25″ with a capacity of 1.44MiB. So you will never find a device with H1200 or h1440. So to figure out the device names, the best thing is to look at the man-page.

The terminal devices come in a few forms. The first is the system console, which are the devices tty0-tty?. You can have up to 64 virtual terminals on you system console, although most systems that I have seen are limited five or six. All console terminals have a major number of 4. As we discussed earlier, you can reach the low numbered ones with ALT-Fn, where n is the number of the function key. So ALT-F4 gets you to the fourth virtual console. Both the minor number and the tty number are based on the function key, so /dev/tty4 has a minor number 4 and you get to it with ALT-F4. (Check the console(4) man-page to see how to use and get to the other virtual terminals.)

Serial devices can also have terminals hooked up to them. These terminals normally use the devices /dev/ttySn, where n is the number of the serial port (0, 1, 2, etc.). These also have a minor number of 4, but the minor numbers all start at 64. (Thats why you can only have 63 virtual consoles.) The minor numbers are this base of 64, plus the serial port number (04). Therefore, the minor number of the third serial port would be 64+3=67.

Related to these devices are the modem control devices, which are used to access modems. These have the same minor numbers but have a major number of 5. The names are also based on the device number. Therefore, the modem device attached to the third serial port has a minor number of 64+3=67 and its name is cua3.

Another device with a major number of 5 is /dev/tty, which has a minor number of 0. This is a special device and is referred to as the “controlling terminal. This is the terminal device for the currently running process. Therefore, no matter where you are, no matter what you are running, sending something to /dev/tty will always appear on your screen.

The pseudo-terminals (those that you use with network connections or X) actually come in pairs. The “slave” is the device at which you type and has a name like ttyp?, where ? is the tty number. The device that the process sees is the “master” and has a name like ptyn, where n is the device number. These also have a major number 4. However, the master devices all have minor numbers based on 128. Therefore, pty0 has a minor number of 128 and pty9 has a minor number of 137 (128+9). The slave device has minor numbers based on 192, so the slave device ttyp0 has a minor number of 192. Note that the tty numbers do not increase numerically after 9 but use the letter a-f.

Other oddities with the device numbering and naming scheme are the memory devices. These have a major number of 1. For example, the device to access physical memory is /dev/mem with a minor number of 1. The kernel memory device is /dev/kmem, and it has a minor number of 2. The device used to access IO ports is /dev/port and it has a minor number of 4.

What about minor number 3? This is for device /dev/null, which is nothing. If you direct output to this device, it goes into nothing, or just disappears. Often the error output of a command is directed here, as the errors generated are uninteresting. If you redirect from /dev/null, you get nothing as well. Often I do something like this:

cat /dev/null > file_name

This device is also used a lot in shell scripts where you do not want to see any output or error messages. You can then redirect standard out or standard error to /dev/null and the messages disappear. For details on standard out and error, see the section on redirection.

If file_name doesn’t exist yet, it is created with a length of zero. If it does exist, the file is truncated to 0 bytes.

The device /dev/zero has a major number of 5 and its minor number is 5. This behaves similarly to /dev/null in that redirecting output to this device is the same as making it disappear. However, if you direct input from this device, you get an unending stream of zeroes. Not the number ‘0’, which has an ASCII value of 48, this is an ASCII 0.

Are those all the devices? Unfortunately not. However, I hope that this has given you a start on how device names and minor numbers are configured. The file <linux/major.h> contains a list of the currently used (at least well known) major numbers. Some nonstandard package might add a major number of its own. Up to this point, they have been fairly good about not stomping on the existing major numbers.

As far as the minor numbers go, check out the various man-pages. If there is a man-page for a specific device, the minor number will probably be under the name of the driver. This is in major.h or often the first letter of the device name. For example, the parallel (printer) devices are lp?, so check out man lp.

The best overview of all the major and minor numbers is in the /usr/src/linux/Documentation directory. The devices.txt is considered the “authoritative” source for this information.