Why when I plug in a disc it doesn't work in the OS, a flash drive is not read by the system? And the network interface refuses to appear in the device list? How to connect discs and configure their work or allow to use a certain list of devices? To all these and other questions we will consider the answer, having analysed the architecture and the principle of working with devices in Linux. After this tutorial you will be able to configure, manage the state and permission of devices on your system by yourself.
How does disc mapping work in Linux?
Let's break down the full cycle of mounting a disc in Linux, in order to understand how it works on the system. And what can be done to solve problems that arise?
We physically or virtually connect the disc to our system, and then information about the new device comes to the kernel. The kernel selects a driver for its operation and collects information about the device. In Linux, any device is a "file" and this means that the kernel, after collecting the information, writes the data to a file in the /dev folder. But this is not an ordinary file description of the connected device, but a point of access to the disc!
Programs can open, read, write and manipulate these device files using standard system calls such as open(), read(), write() and ioctl(). These calls are passed through the device file to the device driver, which then communicates with the hardware through the kernel.
The device driver converts the system calls into hardware commands, which the kernel passes to the device. Feedback from the device also passes through the driver back to the software.
After that the kernel creates the uevents event control passes to Udev, which is a device manager with a prepared set of rules. These are used to change the device name, user access rights, blocking, and scripts when connecting or disconnecting devices. If there are criteria that require changes to be made, Udev will go to the /dev directory and perform the necessary actions.
How do I connect a drive to Linux?
All steps in the tutorial can be performed on powerful cloud servers. Serverspace provides isolated VPS / VDS servers for common and virtualize usage.
It will take some time to deploy server capacity. After that you can connect in any of the convenient ways!
Now let's look at the situation in practice, we need to mount a disc and give it a special name, prohibit connection of devices with a certain UUID, and execute a script to automate our tasks. This can be anything: partitioning a new disc, rotating old files or notifying the administrator.
Let's connect the disc and do some basic configuration: partition and set the file system. Use the lsblk command to examine the mounted discs:
lsblk
The new disc appears as vdb with no logical volumes or partitioning. To start using it you need to create a table and volumes, and then select a file system for the logical partition that will be supported by the OS. After that mount the disc in the OS. To do this, go to the fdisk utility and type the command:
fdisk /dev/vdb
By default, an MBR table is created for the disc, which can be overwritten and it is preferable to use GPT partitioning instead. To do this, specify the letter g, after that the table will be recreated and the disc will be repartitioned. To create a new volume in the current table, press n to define its parameters:
Select the type for the partition and specify the first and the last sector to create one volume. After that we will see the result that a 10 GB volume has been created, it remains to write the changes and save them with the w command. In order for the disc to be processed by the OS it is necessary to initialise the file system for the volume. To do this, use the mkfs.ext4 utility:
mkfs.ext4 /dev/vdb1
To mount a disc temporarily, we can use the mount command, where we must first specify the disc itself and the mount point. But this solution will be valid until reboot, in order to mount a new disc automatically each time - go to the /etc/fstab folder and make changes:
nano /etc/fstab
/dev/vdb1 /home ext4 defaults,noexec 0 2
To initialise a drive, you need to specify its UUID or direct path in our case /dev/vdb1. To view the current discs, type lsblk.
Great, the drive is mounted and ready to use! Now, it will go through the mount step on every restart, however, what if you need to rename it? Or allow a limited number of people to use it?
How to manage the drive and use udev?
To manage block, symbolic devices use udev utility, which communicates with the kernel through uevent events. All settings for devices are made in configuration files for each device separately. In order to create a symbolic link or restrict access you need to know the unique parameters of the disc to be searched:
udevadm info -a -p /sys/block/vdb
In order to write a rule it is necessary to find a unique value for a disc, in this case it is ATTR{serial} with a certain number. To write a rule, let's go to the rules.d folder, where all previously written algorithms for working with each device are stored. Let's create a rule called:
nano 98-local.rules
Let's write the following syntax, which will first find the correct device and then apply the settings from udev rules:
SUBSYSTEM=="block", ID_SERIAL="BHYVE-2C94-9746-08F9", SYMLINK+="NewDisk"
Then save the file and restart the udev service:
systemctl daemon-restart && systemctl restart systemd-udevd
And check the relevant parameters through the command:
udevadm test /dev/vdb1
In the udev rule file, you can use different validation conditions such as:
- SUBSYSTEM: Checks the subsystem of the device. Example: SUBSYSTEM=="block" (the device belongs to the block subsystem).
- KERNEL:Checks the device name specified by the kernel. Example: KERNEL=="sd*" (the device name starts with "sd").
- ATTR{attribute}:Checks the attribute of the device. Example: ATTR{size}=="1024" (the device size attribute is 1024).
- ENV{environment_variable}:Checks an environment variable. Example: ENV{ID_SERIAL}=="1234567890" (the serial number of the device is 1234567890).
- DRIVER:Checks the driver of the device.Example: DRIVER=="usb-storage" (the device uses the usb-storage driver).
- ACTION:Checks the action performed on the device. Example: ACTION=="add" (the device was added) or ACTION=="remove" (the device was removed).
- PROGRAM:Executes a command and checks the result. Example: PROGRAM="/path/to/script" (executes a script at the specified path).
- RESULT:Checks the result of the programme execution. Example: RESULT=="1" (the result of programme execution is 1).
- TEST:Checks the existence of a file or directory. Example: TEST=="/path/to/file" (checks for the existence of a file at the specified path).
All of the above attributes can be used to filter the device. Also for each of them logical elements are used, for example == or != in the condition. The action parameters are then specified:
- SYMLINK+=:Creates a character reference to the device. Example: SYMLINK+="mydevice" (creates a symbolic link /dev/mydevice).
- NAME=:Assigns a name to the device. Example: NAME="mydisk" (assigns the device name to mydisk).
- OWNER=:Sets the owner of the device. Example: OWNER="username" (sets the device owner to username).
- GROUP=:Sets the group of the device. Example: GROUP="disk" (sets the device group to disk).
- MODE=:Sets the access rights of the device. Example: MODE="0660" (sets the access rights to 0660).
- RUN+=:Runs the specified programme or script. Example: RUN+="/path/to/script" (runs the script at the specified path).
- IMPORT=:Imports environment variables from the specified programme or file. Example:
- IMPORT{program}="/path/to/program" (imports variables from a programme).
- OPTIONS=:Sets additional options for the device. Example: OPTIONS+="last_rule" (specifies that this is the last rule for this device).
- ATTR{attribute}=:Sets the value of the device attribute. Example: ATTR{power/control}="auto" (sets the value of the power/control attribute to "auto").
- ENV{environment_variable}=:Sets the value of an environment variable. Example: ENV{UDISKS_IGNORE}="1" (sets the environment variable UDISKS_IGNORE to 1).
- TEST=:Checks the existence of a file or directory. Example: TEST=="/path/to/file" (checks for the existence of a file at the specified path).