Sie sind eigentlich genau das - Schnittstellen. Codiert durch eine "Major" - und eine "Minor" -Nummer bieten sie einen Hook für den Kernel.
Sie gibt es in zwei Varianten (nun, drei, aber Named Pipes sind im Moment nicht Gegenstand dieser Erklärung): Character Devices und Block Devices.
Blockgeräte sind in der Regel Speichergeräte, die in der Lage sind, Ausgaben zu puffern und Daten für den späteren Abruf zu speichern.
Zeichengeräte sind Dinge wie Audio- oder Grafikkarten oder Eingabegeräte wie Tastatur und Maus.
In jedem Fall durchsucht der Kernel beim Laden des richtigen Treibers (entweder beim Booten oder über Programme wie udev ) die verschiedenen Busse, um festzustellen, ob Geräte, die von diesem Treiber behandelt werden, tatsächlich auf dem System vorhanden sind. In diesem Fall wird ein Gerät eingerichtet, das die entsprechende Haupt- / Nebennummer abhört.
(Beispielsweise erhält der digitale Signalprozessor der ersten von Ihrem System gefundenen Audiokarte das Major / Minor-Zahlenpaar von 14/3; der zweite erhält 14,35 usw.)
Es liegt an udev, einen Eintrag in /dev
named dsp
als Zeichengerät mit der Bezeichnung major 14 minor 3 zu erstellen .
(In deutlich älteren Versionen oder Versionen mit minimalem Speicherbedarf von Linux wird /dev/
möglicherweise nicht dynamisch geladen, sondern enthält nur statisch alle möglichen Gerätedateien.)
Wenn dann ein Userspace-Programm versucht, auf eine Datei zuzugreifen, die als 'Character Special File' mit der entsprechenden Major / Minor-Nummer markiert ist (z. B. Ihr Audio-Player, der versucht, digitales Audio zu senden /dev/dsp
), weiß der Kernel, dass diese Daten benötigt werden über den Fahrer übertragen werden, an den die Haupt- / Nebennummer angehängt ist; vermutlich weiß besagter fahrer was man damit wiederum macht.
Jede Datei, jedes Gerät oder sonstige Element unterstützt 6 grundlegende Vorgänge innerhalb des VFS:
Darüber hinaus unterstützen Gerätedateien die E / A-Steuerung, die andere verschiedene Vorgänge ermöglicht, die von den ersten 6 nicht abgedeckt werden.
Im Fall eines speziellen Zeichens wird das Suchen und Sagen nicht implementiert, da es eine Streaming-Schnittstelle unterstützt . Das heißt, direktes Lesen oder Schreiben wie bei der Umleitung in der Shell:
quelle
Minimal lauffähiges
file_operations
BeispielSobald Sie ein minimales Beispiel sehen, wird alles offensichtlich.
Die Schlüsselideen sind:
file_operations
enthält die Rückrufe für jeden dateibezogenen Systemaufrufmknod <path> c <major> <minor>
erstellt ein Zeichengerät, das diese verwendetfile_operations
cat /proc/devices
character_device.ko
Kernel-Modul:Userland Testprogramm:
GitHub QEMU + Buildroot upstream mit Boilerplate, um es tatsächlich auszuführen:
Komplexere Beispiele:
read
,write
,lseek
Mit einer festen Größe und internen Puffer auf debugfs anstelle eines Zeichengerät: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/fops.cpoll
: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/poll.cioctl
: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/poll.canon_inode_getfd
Verknüpft afile_operations
mit einem Dateideskriptor ohne Dateisystemdatei: /programming/4508998/what-is-anonymous-inode/44388030#44388030quelle
*off = 1;
und warum ist es geplant1
?read
Aufrufe an denselbenopen(
Dateideskriptor übergeben. Der Fahrer kann damit machen, was er will. Die übliche Semantik besteht darin, die Anzahl der gelesenen Bytes zu enthalten. In diesem Beispiel haben wir jedoch nur eine einfachere Semantik:0
für das erste Lesen1
nach dem ersten Lesen. Versuchen Sie, es auszuführen und einen printk- oder GDB-Schritt zum Debuggen zu erstellen."Character at a time" ist eine falsche Bezeichnung (ebenso wie die Vorstellung, dass Zeichengeräte das Suchen und Erkennen nicht unbedingt unterstützen). In der Tat, „Block zu einer Zeit“ (also streng satzorientierte, wie beispielsweise ein Bandlaufwerk *) Geräte müssen Zeichenvorrichtungen sein. Die Idee ist also, dass ein Zeichengerät unbedingt nicht suchbar sein muss - Zeichengerätetreiber definieren eine vollständige
file_operations
Struktur, die frei definiert werden kann, je nachdem, ob das Gerät die Operation unterstützt oder nicht. Die Zeichengeräte, die die meisten Leute als Beispiele ansehen, sind null, urandom, TTY-Geräte, Soundkarten, Mäuse usw., die alle aufgrund der Besonderheiten dieser Geräte nicht zu finden sind, aber / dev / vcs, / dev / fb0 , und / dev / kmem sind ebenfalls Zeichengeräte und können gesucht werden.Wie bereits erwähnt, definiert ein Zeichengerätetreiber eine file_operations-Struktur, die Funktionszeiger für alle Vorgänge enthält, die für eine Datei ausgeführt werden sollen (Suchen, Lesen, Schreiben, Ioctl usw.). Diese werden jeweils beim entsprechenden Systemaufruf einmal aufgerufen wird bei geöffneter Gerätedatei ausgeführt. Und Lesen und Schreiben kann daher mit seinen Argumenten tun, was immer es will - es kann sich weigern, ein zu großes Schreiben zu akzeptieren oder nur das zu schreiben, was passt; Es kann nur die Daten lesen, die einem Datensatz entsprechen, und nicht die gesamte angeforderte Anzahl von Bytes.
Was ist also ein Blockgerät? Blockgeräte sind grundsätzlich Festplatten. Keine andere Art von Gerät (mit Ausnahme von virtuellen Laufwerken wie Ramdisk und Loopback) ist ein Blockgerät. Sie sind in das E / A-Anforderungssystem, die Dateisystemschicht, das Puffer- / Cache-System und das virtuelle Speichersystem so integriert, wie es Zeichengeräte nicht tun , selbst wenn Sie von einem Benutzerprozess aus auf z. B. / dev / sda zugreifen . Sogar die "Raw-Geräte", die auf dieser Seite als Ausnahme erwähnt werden, sind Zeichengeräte .
* Einige UNIX-Systeme implementierten den sogenannten "Fixed-Block-Modus", mit dem die Kernel-Gruppen- und E / A-Anforderungen so aufgeteilt werden können, dass sie den konfigurierten Blockgrenzen in etwa wie bei Festplatten entsprechen - als Block Gerät. Für den "Variablen-Block-Modus" wird ein Zeichengerät benötigt, das die Blockgrenzen aus dem Anwenderprogramm beibehält, da ein einzelner Write (2) -Aufruf einen Block schreibt und ein einzelner Read (2) -Aufruf einen Block zurückgibt. Da die Modusumschaltung jetzt als ioctl und nicht als separate Gerätedatei implementiert ist, wird ein Zeichengerät verwendet. Bandlaufwerke mit variablen Datensätzen sind meistens "nicht suchbar", da das Suchen das Zählen einer Anzahl von Datensätzen anstelle einer Anzahl von Bytes umfasst und die native Suchoperation als ioctl implementiert ist.
quelle
Zeichengeräte können von Kernelmodulen (oder vom Kernel selbst) erstellt werden. Wenn ein Gerät erstellt wird, stellt der Ersteller Zeiger auf Funktionen bereit, die Standardaufrufe wie open, read usw. verarbeiten. Der Linux-Kernel ordnet diese Funktionen dann dem Zeichengerät zu, z. B. wenn eine Anwendung im Benutzermodus read () aufruft. Wenn eine Zeichengerätedatei bearbeitet wird, führt dies zu einem Systemaufruf, und der Kernel leitet diesen Aufruf an eine Lesefunktion weiter, die beim Erstellen des Treibers angegeben wurde. Es gibt ein Schritt- für -Schritt - Tutorial eine Zeichengerät zum Erstellen von hier können Sie ein Beispielprojekt und den Schritt durch sie schaffen einen Debugger zu verstehen , wie das Geräteobjekt wird erstellt und wenn die Handler aufgerufen werden.
quelle