Heim > System-Tutorial > LINUX > Hauptteil

Gerätedateien in Linux-Systemen: Inode, Datei und Dateioperationen

WBOY
Freigeben: 2024-02-13 10:20:38
nach vorne
533 Leute haben es durchsucht

Eine Gerätedatei ist eine spezielle Datei im Linux-System. Sie wird verwendet, um die Schnittstelle des Geräts darzustellen, damit Benutzerraumprogramme über Dateioperationen auf das Gerät zugreifen können. Die Implementierung von Gerätedateien umfasst drei wichtige Strukturen: Inode, Datei und Dateioperationen. Die Inode-Struktur wird zum Speichern von Metadaten von Gerätedateien verwendet, wie z. B. Gerätenummer, Berechtigungen, Größe usw. Die Dateistruktur wird zum Speichern von Statusinformationen von Gerätedateien verwendet, wie z. B. aktueller Standort, Öffnungsmodus, private Daten usw. Die Struktur file_operations wird zum Speichern von Gerätedateioperationsfunktionen wie Öffnen, Lesen, Schreiben, Schließen usw. verwendet. In diesem Artikel stellen wir die Definitionen und Funktionen dieser drei Strukturen vor und geben Beispiele für ihre Verwendung und Vorsichtsmaßnahmen.

Gerätedateien in Linux-Systemen: Inode, Datei und Dateioperationen

Der Treiber steuert die Hardware nach unten und stellt Schnittstellen nach oben bereit. Die hier bereitgestellten Schnittstellen entsprechen letztendlich der Anwendungsschicht auf drei Arten: Gerätedateien, /proc, /sys, wobei die am häufigsten verwendete davon die Verwendung von Gerätedateien ist, und Linux Das am häufigsten verwendete Gerät ist das Zeichengerät. In diesem Artikel wird das Zeichengerät als Beispiel verwendet, um den internen Mechanismus zum Erstellen und Öffnen einer Zeichengerätedatei zu analysieren.

Inode strukturieren

Alles in Linux ist eine Datei. Wenn wir eine Datei in Linux erstellen, wird im entsprechenden Dateisystem ein Inode erstellt, der ihr entspricht. Die Dateientität und der Inode der Datei stehen in einer Eins-zu-eins-Entsprechung Sobald ein Inode erstellt und im Speicher gespeichert wird, wird beim ersten Öffnen eine Sicherungskopie des Inodes im Speicher erstellt. Wenn alle geöffneten Dateien geschlossen werden, wird dieselbe Datei mehrmals geöffnet wird im Speicher sein. Wenn wir in diesem Fall mknod (oder andere Methoden) zum Erstellen einer Gerätedatei verwenden, wird auch ein Inode im Dateisystem erstellt. Dieser Inode wird wie andere Inodes zum Speichern statischer Informationen (unveränderlicher Informationen) über die Datei verwendet . ), einschließlich der Gerätenummer, die dieser Gerätedatei entspricht, dem Pfad der Datei und dem entsprechenden Treiberobjekt usw. Als eines der vier Hauptobjekte von VFS muss der Inode bei der Treiberentwicklung selten von uns selbst gefüllt werden. Es ist vielmehr notwendig, ihn in der open()-Methode anzuzeigen und unsere Dateistruktur nach Bedarf auszufüllen. Für verschiedene Dateitypen ist der Inhalt der gefüllten Mitglieder des Inodes unterschiedlich. Wenn wir beispielsweise ein Zeichengerät erstellen, wissen wir, dass add_chrdev_region tatsächlich ein
Laufwerksobjekt und eine (Gruppen-) Gerätenummer verbindet. Beim Erstellen einer Gerätedatei werden tatsächlich die Gerätedatei und die Gerätenummer miteinander verknüpft. An diesem Punkt sind diese drei miteinander verbunden. Auf diese Weise hat der Kernel die Möglichkeit, eine Instanz von struct inode zu erstellen. Das Folgende ist der Inode im 4.8.5-Kernel. Dieser Inode ist der Inode von VFS, der eine weitere Kapselung des Inodes des spezifischsten Dateisystems darstellt. Er ist auch der Inode, der bei der Treiberentwicklung betroffen ist. Für bestimmte Dateisysteme gibt es auch Strukturen wie struct ext2_inode_info.

//include/linux/fs.h
 596 /*
 597  * Keep mostly read-only and often accessed (especially for
 598  * the RCU path lookup and 'stat' data) fields at the beginning
 599  * of the 'struct inode'
 600  */
 601 struct inode {
 602         umode_t                 i_mode;
 603         unsigned short          i_opflags;
 604         kuid_t                  i_uid;
 605         kgid_t                  i_gid;
 606         unsigned int            i_flags;
 607 
 608 #ifdef CONFIG_FS_POSIX_ACL
 609         struct posix_acl        *i_acl;
 610         struct posix_acl        *i_default_acl;
 611 #endif
 612 
 613         const struct inode_operations   *i_op;
 614         struct super_block      *i_sb;
 615         struct address_space    *i_mapping;
 616 
 617 #ifdef CONFIG_SECURITY
 618         void                    *i_security;
 619 #endif
 620 
 621         /* Stat data, not accessed from path walking */
 622         unsigned long           i_ino;
 623         /*
 624          * Filesystems may only read i_nlink directly.  They shall use the
 625          * following functions for modification:
 626          *
 627          *    (set|clear|inc|drop)_nlink
 628          *    inode_(inc|dec)_link_count
 629          */
 630         union {
 631                 const unsigned int i_nlink;
 632                 unsigned int __i_nlink;
 633         };
 634         dev_t                   i_rdev;
 635         loff_t                  i_size;
 636         struct timespec         i_atime;
 637         struct timespec         i_mtime;
 638         struct timespec         i_ctime;
 639         spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
 640         unsigned short          i_bytes;
 641         unsigned int            i_blkbits;
 642         blkcnt_t                i_blocks;
 643                                 
 644 #ifdef __NEED_I_SIZE_ORDERED
 645         seqcount_t              i_size_seqcount;
 646 #endif
 647 
 648         /* Misc */
 649         unsigned long           i_state;
 650         struct rw_semaphore     i_rwsem;
 651 
 652         unsigned long           dirtied_when;   /* jiffies of first dirtying */
 653         unsigned long           dirtied_time_when;
 654 
 655         struct hlist_node       i_hash;
 656         struct list_head        i_io_list;      /* backing dev IO list */
 657 #ifdef CONFIG_CGROUP_WRITEBACK
 658         struct bdi_writeback    *i_wb;          /* the associated cgroup wb */
 659 
 660         /* foreign inode detection, see wbc_detach_inode() */
 661         int                     i_wb_frn_winner;
 662         u16                     i_wb_frn_avg_time;
 663         u16                     i_wb_frn_history;
 664 #endif
 665         struct list_head        i_lru;          /* inode LRU list */
 666         struct list_head        i_sb_list;
 667         struct list_head        i_wb_list;      /* backing dev writeback list */
 668         union {
 669                 struct hlist_head       i_dentry;
 670                 struct rcu_head         i_rcu;
 671         };
 672         u64                     i_version;
 673         atomic_t                i_count;
 674         atomic_t                i_dio_count;
 675         atomic_t                i_writecount;
 676 #ifdef CONFIG_IMA
 677         atomic_t                i_readcount; /* struct files open RO */
 678 #endif
 679         const struct file_operations    *i_fop; /* former ->i_op->default_file_ops */
 680         struct file_lock_context        *i_flctx;
 681         struct address_space    i_data;
 682         struct list_head        i_devices;
 683         union {
 684                 struct pipe_inode_info  *i_pipe;
 685                 struct block_device     *i_bdev;
 686                 struct cdev             *i_cdev;
 687                 char                    *i_link;
 688                 unsigned                i_dir_seq;
 689         };
 690 
 691         __u32                   i_generation;
 692 
 693 #ifdef CONFIG_FSNOTIFY
 694         __u32                   i_fsnotify_mask; /* all events this inode cares about */
 695         struct hlist_head       i_fsnotify_marks;
 696 #endif
 697 
 698 #if IS_ENABLED(CONFIG_FS_ENCRYPTION)
 699         struct fscrypt_info     *i_crypt_info;
 700 #endif
 701 
 702         void                    *i_private; /* fs or device private pointer */
 703 };    
Nach dem Login kopieren

Die Hauptmitglieder im Zusammenhang mit diesem Artikel sind:

Inode strukturieren –602–>i_mode gibt die Zugriffsberechtigungskontrolle an
–604–>UID
–605–>GID
–606–>i_flags Dateisystem-Flags
–630–> Hard-Link-Anzahl
–635–>i_size Dateigröße in Bytes
–636–>Letzte Zugriffszeit
–637–>Letzte Änderungszeit
–638–>Letzte Änderungszeit
–669–>i_dentry; //Katalog-Halskettenliste
–673–>i_count Referenzzähler, wenn der Referenzzähler 0 wird, wird die Inode-Instanz freigegeben
–675–>i_writecount Autorenanzahl
–679–>Beim Erstellen einer Gerätedatei wird i_fops mit einem von def_chr_fops, blk_blk_fops, def_fifo_fops und bad_sock_fops gefüllt, siehe init_special_inode(), der während des Erstellungsprozesses aufgerufen wird
–683–>Spezielle Dateitypen wie Union, Pipe, cdev, blk.link usw. i_cdev gibt an, dass dieser Inode zu einer Zeichengerätedatei gehört. Beim Erstellen der Gerätedatei in diesem Artikel wird das Treiberobjekt cdev mit der zugehörigen Gerätenummer angegeben Füllung
wird verwendet –702–>private Daten von Inode

Von den oben genannten Mitgliedern lohnt es sich nur,

struct def_chr_fops zu verfolgen, es wird später von großem Nutzen sein:

//fs/char_dev.c
429 const struct file_operations def_chr_fops = { 
430         .open = chrdev_open,
431         .llseek = noop_llseek,
432 };
Nach dem Login kopieren

struct file

Linux内核会为每一个进程维护一个文件描述符表,这个表其实就是struct file[]的索引。open()的过程其实就是根据传入的路径填充好一个file结构并将其赋值到数组中并返回其索引。下面是file的主要内容

//include/linux/fs.h
 877 struct file {
 878         union {
 879                 struct llist_node       fu_llist;
 880                 struct rcu_head         fu_rcuhead;
 881         } f_u;
 882         struct path             f_path;
 883         struct inode            *f_inode;       /* cached value */
 884         const struct file_operations    *f_op;
 885 
 886         /*                                            
 887          * Protects f_ep_links, f_flags.
 888          * Must not be taken from IRQ context.
 889          */
 890         spinlock_t              f_lock;
 891         atomic_long_t           f_count;
 892         unsigned int            f_flags;
 893         fmode_t                 f_mode;
 894         struct mutex            f_pos_lock;
 895         loff_t                  f_pos;
 896         struct fown_struct      f_owner;
 897         const struct cred       *f_cred;
 898         struct file_ra_state    f_ra;f
 904         /* needed for tty driver, and maybe others */
 905         void                    *private_data;
 912         struct address_space    *f_mapping;
 913 } __attribute__((aligned(4)));  /* lest something weird decides that 2 is OK */
Nach dem Login kopieren

struct file
–882–>f_path里存储的是open传入的路径,VFS就是根据这个路径逐层找到相应的inode
–883–>f_inode里存储的是找到的inode
–884–>f_op里存储的就是驱动提供的file_operations对象,这个对象在open的时候被填充,具体地,应用层的open通过层层搜索会调用inode.i_fops->open,即chrdev_open()
–891–>f_count的作用是记录对文件对象的引用计数,也即当前有多少个使用CLONE_FILES标志克隆的进程在使用该文件。典型的应用是在POSIX线程中。就像在内核中普通的引用计数模块一样,最后一个进程调用put_files_struct()来释放文件描述符。
–892–>f_flags当打开文件时指定的标志,对应系统调用open的int flags,比如驱动程序为了支持非阻塞型操作需要检查这个标志是否有O_NONBLOCK。
–893–>f_mode;对文件的读写模式,对应系统调用open的mod_t mode参数,比如O_RDWR。如果驱动程序需要这个值,可以直接读取这个字段。
–905–>private_data表示file结构的私有数据

我在Linux设备管理(二)_从cdev_add说起一文中已经分析过chrdev_open(),这里仅作概述。

//fs/chr_dev.c
348 /*
349  * Called every time a character special file is opened
350  */
351 static int chrdev_open(struct inode *inode, struct file *filp)
352 {
            /* 搜索cdev */
            ...
390         replace_fops(filp, fops);
391         if (filp->f_op->open) {
392                 ret = filp->f_op->open(inode, filp);
393                 if (ret)
394                         goto out_cdev_put;
395         } 
            ...
402 }
Nach dem Login kopieren

可以看出,这个函数有三个任务(划重点!!!):

chrdev_open()
–352-389–>利用container_of等根据inode中的成员找到相应的cdev
–390–>用cdev.fops替换filp->f_op,即填充了一个空的struct file的f_op成员。
–392–>回调替换之后的filp->f_op->open,由于替换,这个其实就是cdev.fops

至此,我们知道了我们写的驱动中的open()在何时会被回调,这样我们就可以实现很多有意思的功能,比如,
我们可以在open中通过inode->cdev来识别具体的设备,并将其私有数据隐藏到file结构的private_data中,进而识别同一个驱动操作一类设备;
我们也可以在回调cdev.fops->open()阶段重新填充file结构的fop,进而实现同一个驱动操作不同的设备,这种思想就是内核驱动中常用的分层!
最后总结一下这些结构之间的关系:

Gerätedateien in Linux-Systemen: Inode, Datei und Dateioperationen

Durch diesen Artikel haben wir die drei wichtigen Strukturen von Gerätedateien kennengelernt: Inode, Datei und Dateioperationen. Mit ihnen können Gerätedateien verwaltet und bedient werden. Wir sollten die geeignete Struktur entsprechend den tatsächlichen Anforderungen auswählen und einige Grundprinzipien befolgen, z. B. die Verwendung der richtigen Gerätenummer, die Verwendung angemessener Berechtigungen, die Verwendung effektiver Betriebsfunktionen usw. Die drei Strukturen von Gerätedateien sind eines der grundlegendsten Konzepte im Linux-System. Sie können das Gerät abstrahieren und kapseln und auch die Einheit und Flexibilität des Systems verbessern. Ich hoffe, dass dieser Artikel für Sie hilfreich und inspirierend sein kann.

Das obige ist der detaillierte Inhalt vonGerätedateien in Linux-Systemen: Inode, Datei und Dateioperationen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:lxlinux.net
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!