Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 1 | ------------- |
| 2 | MDEV Primer |
| 3 | ------------- |
| 4 | |
| 5 | For those of us who know how to use mdev, a primer might seem lame. For |
| 6 | everyone else, mdev is a weird black box that they hear is awesome, but can't |
| 7 | seem to get their head around how it works. Thus, a primer. |
| 8 | |
| 9 | ----------- |
| 10 | Basic Use |
| 11 | ----------- |
| 12 | |
| 13 | Mdev has two primary uses: initial population and dynamic updates. Both |
| 14 | require sysfs support in the kernel and have it mounted at /sys. For dynamic |
| 15 | updates, you also need to have hotplugging enabled in your kernel. |
| 16 | |
| 17 | Here's a typical code snippet from the init script: |
Bernhard Reutner-Fischer | 9c3052a | 2008-05-16 11:36:32 +0000 | [diff] [blame] | 18 | [0] mount -t proc proc /proc |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 19 | [1] mount -t sysfs sysfs /sys |
Denys Vlasenko | f92874e | 2009-12-05 15:59:05 +0100 | [diff] [blame] | 20 | [2] echo /sbin/mdev > /proc/sys/kernel/hotplug |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 21 | [3] mdev -s |
| 22 | |
Bernhard Reutner-Fischer | 9c3052a | 2008-05-16 11:36:32 +0000 | [diff] [blame] | 23 | Alternatively, without procfs the above becomes: |
| 24 | [1] mount -t sysfs sysfs /sys |
Denys Vlasenko | f92874e | 2009-12-05 15:59:05 +0100 | [diff] [blame] | 25 | [2] sysctl -w kernel.hotplug=/sbin/mdev |
Bernhard Reutner-Fischer | 9c3052a | 2008-05-16 11:36:32 +0000 | [diff] [blame] | 26 | [3] mdev -s |
| 27 | |
| 28 | |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 29 | Of course, a more "full" setup would entail executing this before the previous |
| 30 | code snippet: |
Bernhard Reutner-Fischer | 9c3052a | 2008-05-16 11:36:32 +0000 | [diff] [blame] | 31 | [4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 32 | [5] mkdir /dev/pts |
| 33 | [6] mount -t devpts devpts /dev/pts |
| 34 | |
| 35 | The simple explanation here is that [1] you need to have /sys mounted before |
Denys Vlasenko | f92874e | 2009-12-05 15:59:05 +0100 | [diff] [blame] | 36 | executing mdev. Then you [2] instruct the kernel to execute /sbin/mdev whenever |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 37 | a device is added or removed so that the device node can be created or |
| 38 | destroyed. Then you [3] seed /dev with all the device nodes that were created |
| 39 | while the system was booting. |
| 40 | |
| 41 | For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem |
| 42 | (assuming you're running out of flash). Then you want to [5] create the |
| 43 | /dev/pts mount point and finally [6] mount the devpts filesystem on it. |
| 44 | |
| 45 | ------------- |
| 46 | MDEV Config (/etc/mdev.conf) |
| 47 | ------------- |
| 48 | |
| 49 | Mdev has an optional config file for controlling ownership/permissions of |
| 50 | device nodes if your system needs something more than the default root/root |
| 51 | 660 permissions. |
| 52 | |
| 53 | The file has the format: |
Denys Vlasenko | 40b97fb | 2013-02-26 00:40:46 +0100 | [diff] [blame] | 54 | [-][envmatch]<device regex> <uid>:<gid> <permissions> |
Denys Vlasenko | 5c6ba6c | 2011-09-19 12:18:11 +0200 | [diff] [blame] | 55 | or |
Denys Vlasenko | 40b97fb | 2013-02-26 00:40:46 +0100 | [diff] [blame] | 56 | [envmatch]@<maj[,min1[-min2]]> <uid>:<gid> <permissions> |
Denys Vlasenko | 5c6ba6c | 2011-09-19 12:18:11 +0200 | [diff] [blame] | 57 | or |
| 58 | $envvar=<regex> <uid>:<gid> <permissions> |
Denis Vlasenko | 8d89bed | 2008-09-07 23:22:08 +0000 | [diff] [blame] | 59 | |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 60 | For example: |
Denys Vlasenko | 5c6ba6c | 2011-09-19 12:18:11 +0200 | [diff] [blame] | 61 | hd[a-z][0-9]* 0:3 660 |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 62 | |
Martin Kaiser | d1cd3da | 2018-09-24 21:01:51 +0200 | [diff] [blame] | 63 | The config file parsing stops at the first matching line unless this line |
| 64 | starts with "-". If no line is matched, then the default of 0:0 660 is used. |
| 65 | To set your own default, simply create your own total match like so: |
Denys Vlasenko | 5c6ba6c | 2011-09-19 12:18:11 +0200 | [diff] [blame] | 66 | |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 67 | .* 1:1 777 |
| 68 | |
Denis Vlasenko | df96df9 | 2008-07-26 18:35:10 +0000 | [diff] [blame] | 69 | You can rename/move device nodes by using the next optional field. |
Denys Vlasenko | 5c6ba6c | 2011-09-19 12:18:11 +0200 | [diff] [blame] | 70 | |
Denys Vlasenko | b38af7b | 2010-04-02 06:47:14 +0200 | [diff] [blame] | 71 | <device regex> <uid>:<gid> <permissions> [=path] |
Denys Vlasenko | 5c6ba6c | 2011-09-19 12:18:11 +0200 | [diff] [blame] | 72 | |
Mike Frysinger | f0044c4 | 2008-02-01 06:53:50 +0000 | [diff] [blame] | 73 | So if you want to place the device node into a subdirectory, make sure the path |
| 74 | has a trailing /. If you want to rename the device node, just place the name. |
Denis Vlasenko | df96df9 | 2008-07-26 18:35:10 +0000 | [diff] [blame] | 75 | hda 0:3 660 =drives/ |
| 76 | This will move "hda" into the drives/ subdirectory. |
| 77 | hdb 0:3 660 =cdrom |
Mike Frysinger | f0044c4 | 2008-02-01 06:53:50 +0000 | [diff] [blame] | 78 | This will rename "hdb" to "cdrom". |
| 79 | |
Denis Vlasenko | df96df9 | 2008-07-26 18:35:10 +0000 | [diff] [blame] | 80 | Similarly, ">path" renames/moves the device but it also creates |
| 81 | a direct symlink /dev/DEVNAME to the renamed/moved device. |
| 82 | |
Denys Vlasenko | b38af7b | 2010-04-02 06:47:14 +0200 | [diff] [blame] | 83 | You can also prevent creation of device nodes with the 4th field as "!": |
| 84 | tty[a-z]. 0:0 660 ! |
| 85 | pty[a-z]. 0:0 660 ! |
| 86 | |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 87 | If you also enable support for executing your own commands, then the file has |
| 88 | the format: |
Denys Vlasenko | b38af7b | 2010-04-02 06:47:14 +0200 | [diff] [blame] | 89 | <device regex> <uid>:<gid> <permissions> [=path] [@|$|*<command>] |
Denis Vlasenko | df96df9 | 2008-07-26 18:35:10 +0000 | [diff] [blame] | 90 | or |
Denys Vlasenko | b38af7b | 2010-04-02 06:47:14 +0200 | [diff] [blame] | 91 | <device regex> <uid>:<gid> <permissions> [>path] [@|$|*<command>] |
| 92 | or |
| 93 | <device regex> <uid>:<gid> <permissions> [!] [@|$|*<command>] |
Bernhard Reutner-Fischer | db57fc2 | 2009-09-08 14:16:00 +0200 | [diff] [blame] | 94 | |
| 95 | For example: |
| 96 | ---8<--- |
| 97 | # block devices |
| 98 | ([hs]d[a-z]) root:disk 660 >disk/%1/0 |
| 99 | ([hs]d[a-z])([0-9]+) root:disk 660 >disk/%1/%2 |
| 100 | mmcblk([0-9]+) root:disk 660 >disk/mmc/%1/0 |
| 101 | mmcblk([0-9]+)p([0-9]+) root:disk 660 >disk/mmc/%1/%2 |
| 102 | # network devices |
| 103 | (tun|tap) root:network 660 >net/%1 |
| 104 | ---8<--- |
| 105 | |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 106 | The special characters have the meaning: |
| 107 | @ Run after creating the device. |
| 108 | $ Run before removing the device. |
| 109 | * Run both after creating and before removing the device. |
| 110 | |
| 111 | The command is executed via the system() function (which means you're giving a |
Mike Frysinger | c348e0b | 2008-02-01 01:41:57 +0000 | [diff] [blame] | 112 | command to the shell), so make sure you have a shell installed at /bin/sh. You |
| 113 | should also keep in mind that the kernel executes hotplug helpers with stdin, |
| 114 | stdout, and stderr connected to /dev/null. |
Mike Frysinger | ae30210 | 2007-02-14 13:20:29 +0000 | [diff] [blame] | 115 | |
| 116 | For your convenience, the shell env var $MDEV is set to the device name. So if |
Mike Frysinger | c348e0b | 2008-02-01 01:41:57 +0000 | [diff] [blame] | 117 | the device "hdc" was matched, MDEV would be set to "hdc". |
Mike Frysinger | ae7f7eb | 2007-06-28 17:13:51 +0000 | [diff] [blame] | 118 | |
| 119 | ---------- |
| 120 | FIRMWARE |
| 121 | ---------- |
| 122 | |
| 123 | Some kernel device drivers need to request firmware at runtime in order to |
| 124 | properly initialize a device. Place all such firmware files into the |
| 125 | /lib/firmware/ directory. At runtime, the kernel will invoke mdev with the |
| 126 | filename of the firmware which mdev will load out of /lib/firmware/ and into |
| 127 | the kernel via the sysfs interface. The exact filename is hardcoded in the |
Bernhard Reutner-Fischer | 9c3052a | 2008-05-16 11:36:32 +0000 | [diff] [blame] | 128 | kernel, so look there if you need to know how to name the file in userspace. |
Denis Vlasenko | 018bee6 | 2008-07-15 22:33:13 +0000 | [diff] [blame] | 129 | |
| 130 | ------------ |
| 131 | SEQUENCING |
| 132 | ------------ |
| 133 | |
| 134 | Kernel does not serialize hotplug events. It increments SEQNUM environmental |
| 135 | variable for each successive hotplug invocation. Normally, mdev doesn't care. |
| 136 | This may reorder hotplug and hot-unplug events, with typical symptoms of |
| 137 | device nodes sometimes not created as expected. |
| 138 | |
| 139 | However, if /dev/mdev.seq file is found, mdev will compare its |
| 140 | contents with SEQNUM. It will retry up to two seconds, waiting for them |
| 141 | to match. If they match exactly (not even trailing '\n' is allowed), |
| 142 | or if two seconds pass, mdev runs as usual, then it rewrites /dev/mdev.seq |
| 143 | with SEQNUM+1. |
| 144 | |
| 145 | IOW: this will serialize concurrent mdev invocations. |
| 146 | |
| 147 | If you want to activate this feature, execute "echo >/dev/mdev.seq" prior to |
| 148 | setting mdev to be the hotplug handler. This writes single '\n' to the file. |
Denys Vlasenko | 5370bfb | 2009-09-06 02:58:59 +0200 | [diff] [blame] | 149 | NB: mdev recognizes /dev/mdev.seq consisting of single '\n' character |
Denis Vlasenko | 018bee6 | 2008-07-15 22:33:13 +0000 | [diff] [blame] | 150 | as a special case. IOW: this will not make your first hotplug event |
| 151 | to stall for two seconds. |