5.1 API和libc规范
linux:create/open/close/write/read/lseek/
libc fopen/fgetc/fputc/fgets/fputs/fread/fwrite/fgetpos/fsetpos/fseek/fclose/
5.2 文件系统目录结构
1./bin 2./sbin 3./dev 4./etc 5./lib 6./mnt
7./opt 8./proc 9./tmp 10./usr 11./var 12./sys
5.2.1 文件系统与驱动
VFS、FS、Devices接口是file_operations结构体成员函数:包含打开、关闭、读写、控制等一些列函数
*********文件系统与驱动之间关系***********
**********APP与VFS与Dev_drivers关系*******************
一般只关注file和inode两个结构体
1.file结构体
struct file {
union {
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;
/*
* Protects f_ep_links, f_flags.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
enum rw_hint f_write_hint;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
errseq_t f_wb_err;
errseq_t f_sb_err; /* for syncfs */
} __randomize_layout
__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
2.inode结构体
VFS inode包含访问权限/属主/组/大小/生成时间/访问时间等.是linux管理fs的基本单元,也是fs连接子目录、文件的桥梁、inode定义
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
* of the 'struct inode'
*/
struct inode {
umode_t i_mode;
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
unsigned int i_flags;
#ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
#endif
const struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
/* Stat data, not accessed from path walking */
unsigned long i_ino;
/*
* Filesystems may only read i_nlink directly. They shall use the
* following functions for modification:
*
* (set|clear|inc|drop)_nlink
* inode_(inc|dec)_link_count
*/
union {
const unsigned int i_nlink;
unsigned int __i_nlink;
};
dev_t i_rdev; //主设备为dev_t高12位、次设备号为dev_t的低20位
loff_t i_size;
struct timespec64 i_atime;
struct timespec64 i_mtime;
struct timespec64 i_ctime;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes;
u8 i_blkbits;
u8 i_write_hint;
blkcnt_t i_blocks;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
/* Misc */
unsigned long i_state;
struct rw_semaphore i_rwsem;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned long dirtied_time_when;
struct hlist_node i_hash;
struct list_head i_io_list; /* backing dev IO list */
#ifdef CONFIG_CGROUP_WRITEBACK
struct bdi_writeback *i_wb; /* the associated cgroup wb */
/* foreign inode detection, see wbc_detach_inode() */
int i_wb_frn_winner;
u16 i_wb_frn_avg_time;
u16 i_wb_frn_history;
#endif
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
struct list_head i_wb_list; /* backing dev writeback list */
union {
struct hlist_head i_dentry;
struct rcu_head i_rcu;
};
atomic64_t i_version;
atomic64_t i_sequence; /* see futex */
atomic_t i_count;
atomic_t i_dio_count;
atomic_t i_writecount;
#if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
atomic_t i_readcount; /* struct files open RO */
#endif
union {
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
void (*free_inode)(struct inode *);
};
struct file_lock_context *i_flctx;
struct address_space i_data;
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
char *i_link;
unsigned i_dir_seq;
};
__u32 i_generation;
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct fsnotify_mark_connector __rcu *i_fsnotify_marks;
#endif
#ifdef CONFIG_FS_ENCRYPTION
struct fscrypt_info *i_crypt_info;
#endif
#ifdef CONFIG_FS_VERITY
struct fsverity_info *i_verity_info;
#endif
void *i_private; /* fs or device private pointer */
} __randomize_layout;
--/proc/devices可获知文件系统注册的设备号,第一列为主设备号、第二列为设备名
--统一驱动可支持多个同类设备、故用次设备号描述使用该驱动的设备的序号,一般从0开始
5.3 devfs(2.4)和udev(2.6)
5.3.1 devfs实现设备驱动程序自主管理自己的设备文件。
优点如下
1.可通过程序在设备初始化时在/dev目录下创建设备文件,卸载设备时将它删除
2.驱动可指定设备名称、所有者、权限位、用户空间程序仍可修改所有者和权限位
3.不再需要为驱动分配主设备号以及处理次设备号,在程序中可直接给register_chrdev()传递0主设备以及获得可用主设备号,并在devfs_register()中指定次设备号
devfs_handle_t devfs_mk_dir(devfs_handle_t dir,const char* name, void *info);
devfs_handle_t devfs_register(devfs_handle_t dir,...);
void devfs_unregister(devfs_handle_t de);
4. static devfs_handle_t devfs_handle;
static int __init xxx_init(void){
int ret;
int i;
ret = register_chrdev(xxx_MAJOR,DEVICE_MAME,&xxx_fops);
if(ret<0){
}
//创建设备文件
devfs_handle = devfs_register(NULL,DEVICE_NAME,DEVFS_FL_DEVFAULT,XXX_MAJOR,0,S_IFCHR|S_IRUSR|S_IWUSR,&xxx_fops,NULL);
...
printk(DEVICE_NAME"initialized\n);
return 0;
}
static void __exit xxx_exit(void){
devfs_unregister(devfs_handle);
unregister_chrdev(XXX_MAJOR,DEVICE_NAME);
}
module_init(xxx_init);
module_exit(xxx_exit);
udev取代devfs的原因
1.devfs所做工作在用户态可完成
2.devfs被加入内核时大家期望其质量可赶上
3.devfs存在无法修复的bug
devfs作者停止维护
5.4 设备驱动模型、sysfs、udev规则
linux设计强调的基本观点是机制和策略分离。机制是做某件事的固定步骤、方法
策略是没一个步骤所采取的不同方式。
机制相对固定、稳定
策略不固定、也不稳定
采用devfs,当一个并不存在的/dev节点被打开时,devfs能自动加载对应的驱动,而udev则不这么做.因为udev认为linux应该在设备被发现时加载驱动模块,而不是被访问时。udev认为devfs是多余的。系统中所有设备都应该差生热插拔事件并加载恰当的驱动。而udev能够为创建对应的设备结点。
5.4.2 sysfs与linux设备模型
1. 2.6以后引入,同级别proc/devfs/devpty等,是虚拟fs
2. 可产生一个包括所有系统硬件的层级视图,与提供进程和状态信息的proc文件系统十分类似.
3.展示设备驱动模型中各组件的层次关系,顶级目录block/bus/dev/devices/class/fs/kernel/power/firmware等
4.驱动和设备必然依赖于总线,故都包含struct bus_type指针.内核中设备和驱动是分开注册,注册1个设备时,并不需要驱动已经工作,而却用被注册时,也不需要设备已经注册,各自涌向内核,每个设备和驱动涌入内核时,都会寻找另一半,这里正是bus_type的match()成员函数将两者捆绑在一起.
5.总线、驱动和设备最终都会落实为sysfs中的1个目录,追踪发现都是kobject派生的.故kobject可看做总线/设备/驱动的抽象基类,1个kobject对应1个sysfs的1个目录.
*****attribute_bus_attribute_driver_attribute_device_attribute结构体****************
5.4.3 udev的组成
1.udev和systemd合并,在用户空间执行,动态建立/删除设备文件,允许用户不必关心主次设备号而提供LSB名称,可根据需要固定名称
2.udev工作过程。
1.内核检测到设备通过netlink套接字发送uevent
2.udev获取信息,匹配规则(Subsystem/action/attribute/内核提供的名称-KERNEL=)以及其他环境变量
3.根据netlink检测信息创建命名规则,
#Kingston USB mass storage
SUBSYSTEM=="block",ACTION="add",KERNEL=="sd",ENV(ID_TYPE)=="disk",ENV(ID_VENDOR)=="Kingston",ENV(ID_USB_DRIVER)=="usb-storage",SYMLINK+="kingstonUD"
5.4.4 udev规则文件
5.5 总结
linux 2.6 通过一些列数据结构定义了设备模型,设备模型与sysfs文件系统中的目录和文件存在一种对应关系.设备和驱动分离,并通过总线进行匹配
2.udev可利用内核通过netlink发出的uevent信息动态创建设备文件节点。