/***********************************************************************************
*
* volatile,container_of,file_operations,file,inode
*
* 声明:
* 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会
* 不对齐,从而影响阅读.
* 2. 本文的结构体的注释主要是参考网络上的解释,几乎无任何个人理解,主要是为后续
* 代码编辑提供参考.
*
* 2015-3-8 阴 深圳 尚观 Etc 曾剑锋
**********************************************************************************/ \\\\\\\\\\\\\\--*目录*--//////////////
| 一. volatile修饰字段:
| 二. container_of:
| 三. 驱动错误返回值:
| 四. struct file_operations注释:
| 五. struct file注释:
| 六. struct inode注释:
\\\\\\\\\\\\\\\\\\\/////////////////// 一. volatile修饰字段:
告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问. 二. container_of:
. container_of定义:
#define __offset(type, mem) \
((unsigned long)&(((type *))->mem))
#define container_of(addr, type, mem) \
((type *)((void *)addr - __offset(type, mem)))
. container_of使用:
static int test_open(struct inode *inode, struct file *file)
{
test_t *p;
p = container_of(file->f_op, test_t, fops);
file->private_data = p; return ;
} 三. 驱动错误返回值:
#ifnder _ASM_GENERIC_ERRNO_BASE_H
#define _ASM_GENERIC_ERRNO_BASE_H #define EPERM 1 /* Operation not permitted --> 操作不允许 */
#define ENOENT 2 /* No such file or directory --> 找不到对应文件或文件夹 */
#define ESRCH 3 /* No such process --> 找不到对应的进程 */
#define EINTR 4 /* Interrupted system call --> 被系统调用中断 */
#define EIO 5 /* I/O error --> IO错误 */
#define ENXIO 6 /* No such device or address --> 找不到对应的设备或者地址 */
#define E2BIG 7 /* Argument list too long --> 参数列表太长 */
#define ENOEXEC 8 /* Exec format error --> 执行格式错误 */
#define EBADF 9 /* Bad file number --> 错误的文件数 */
#define ECHILD 10 /* No child processes --> 没有子进程 */
#define EAGAIN 11 /* Try again --> 重新调用该函数调用 */
#define ENOMEM 12 /* Out of memory --> 内存溢出 */
#define EACCES 13 /* Permission denied --> 权限被拒绝 */
#define EFAULT 14 /* Bad address --> 错误地址 */
#define ENOTBLK 15 /* Block device required --> 需要块设备 */
#define EBUSY 16 /* Device or resource busy --> 设备或者资源正在被使用 */
#define EEXIST 17 /* File exists --> 文件已经存在 */
#define EXDEV 18 /* Cross-device link --> 交叉设备链接 */
#define ENODEV 19 /* No such device --> 找不到设备 */
#define ENOTDIR 20 /* Not a directory --> 不是一个目录 */
#define EISDIR 21 /* Is a directory --> 是一个目录 */
#define EINVAL 22 /* Invalid argument --> 非法的参数 */
#define ENFILE 23 /* File table overflow --> 文件表溢出 */
#define EMFILE 24 /* Too many open files --> 打开太多的文件 */
#define ENOTTY 25 /* Not a typewriter --> 不是设备命令 */
#define ETXTBSY 26 /* Text file busy --> 文本文件忙 */
#define EFBIG 27 /* File too large --> 文件太大 */
#define ENOSPC 28 /* No space left on device --> 设备空间不足 */
#define ESPIPE 29 /* Illegal seek --> 非法的偏移 */
#define EROFS 30 /* Read-only file system --> 只读文件系统 */
#define EMLINK 31 /* Too many links --> 链接太多 */
#define EPIPE 32 /* Broken pipe --> 损坏的管道 */
#define EDOM 33 /* Math argument out of domain of func --> 数字参数超出函数域 */
#define ERANGE 34 /* Math result not representable --> 数字结果不能表示 */
#endif 四. struct file_operations注释:
struct file_operations {
/* 指向拥有这个结构模块的指针,当模块被使用时,阻止模块被卸载,它被简单初始化为THIS_MODULE */
struct module *owner; /* 用作改变文件当前读/写位置,并返回更改后新的位置 */
loff_t (*llseek) (struct file *, loff_t, int); /* 用于从设备中获取数据,返回成功读取的字节数 */
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); /* 用于发送数据给设备,返回成功写入的字节数 */
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); /* 初始化一个异步读--可能在函数返回前不结束读操作 */
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); /* 初始化一个异步写--可能在函数返回前不结束写操作 */
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); /* 对于设备文件这个成员应当为NULL,它用来读取目录,并且仅对文件系统有用 */
int (*readdir) (struct file *, void *, filldir_t); /* poll,epoll,select系统调用的后端,都用作查询对一个或多个文件描述符的读写是否阻塞 */
unsigned int (*poll) (struct file *, struct poll_table_struct *); /* 提供了发出设备特定命令的方法 */
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); /* 用来请求将设备内存映射到进程的地址空间 */
int (*mmap) (struct file *, struct vm_area_struct *); /* 对设备文件进行的第一个操作 */
int (*open) (struct inode *, struct file *); /* 在进程关闭它的设备文件描述符的拷贝时调用,它应当执行设备的任何未完成的操作 */
int (*flush) (struct file *, fl_owner_t id); /* 在文件结构被释放时引用这个操作 */
int (*release) (struct inode *, struct file *); /* fsync系统调用的后端,用户调用来刷新任何挂着的数据 */
int (*fsync) (struct file *, loff_t, loff_t, int datasync); /* 这是fsync方法的异步版本 */
int (*aio_fsync) (struct kiocb *, int datasync); /* 这个操作用来通知设备的FASYNC标志的改变 */
int (*fasync) (int, struct file *, int); /* 用来实现文件加锁,加锁对常规文件是必不可少的特性,但设备驱动几乎从不是先它 */
int (*lock) (struct file *, int, struct file_lock *); /* sendpage是sendfile的另一半,它由内核调用来发送数据,一次一页到对应的文件,设备驱动实际上不实现sendpage */
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); /* 这个方法的目的是在进程空间找一个合适的位置来映射在底层设备上的内存段中,大部分驱动不实现 */
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); /* 该方法允许模块检查传递给fcntl(F_SETFL...)调用的标志 */
int (*check_flags)(int); /* 应用程序使用fcntl来请求目录改变通知时,调用该方法,仅对文件系统有效,驱动程序不实现 */
int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
}; 五. struct file注释:
struct file {
/**
* 1. 其中struct list_head是内核链表;
* 2. RCU(Read-Copy Update)是Linux 2.6内核中新的锁机制;
*/
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
/**
* 在早些版本内核中没有此结构,而是直接将path的两个数据成员作为struct file的数据成员
* 1. struct vfsmount *mnt的作用是指出该文件的已安装的文件系统;
* 2. struct dentry *dentry是与文件相关的目录项对象;
*/
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
/* 包含着与文件相关的操作 */
const struct file_operations *f_op; /**
* Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
#ifdef CONFIG_SMP
int f_sb_list_cpu;
#endif
/* 记录对文件对象的引用计数,也就是当前有多少个进程在使用该文件 */
atomic_long_t f_count;
/**
* 打开文件时指定的标志,对应系统调用open的int flags参数,
* 驱动程序为了支持非阻塞型操作需要检查该标志
*/
unsigned int f_flags;
/* 打开文件的读写模式,对应系统调用的open的mod_t mode参数 */
fmode_t f_mode;
/* 当前的文件指针位置,即文件的读写位置 */
loff_t f_pos;
/* 该结构的作用是通过信号进行I/O时间通知的数据 */
struct fown_struct f_owner;
/* 保存进程的GID,UID等信息 */
const struct cred *f_cred;
/* 文件预读算法使用的主要数据结构 */
struct file_ra_state f_ra; /* 记录文件的版本号,每次使用后都自动递增 */
u64 f_version;
#ifdef CONFIG_SECURITY
/**
* 如果在编译内核时配置了安全措施,那么struct file结构中就会有
* void *f_security数据项,用来描述安全措施或者是记录与安全有关的信息
*/
void *f_security;
#endif
/* needed for tty driver, and maybe others */
/**
* 系统在调用驱动程序的open()前将这个指针置为NULL,驱动程序可以将这个字段用于任何目的,
* 也可以用这个字段指向已分配的数据,但一定要在内核释放file结构之前release()中清楚它.
*/
void *private_data; #ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
/**
* 被用在fs/eventpoll.c来链接所有钩到这个文件上,其中f_ep_links是文件的时间轮询等待者链表的头,
* f_ep_lock是保护f_ep_links链表的自旋锁.
*/
struct list_head f_ep_links;
struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
/* 指向文件地址空间的指针 */
struct address_space *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
}; 六. struct inode注释:
struct inode {
/* 访问权限控制 */
umode_t i_mode;
unsigned short i_opflags;
/* 使用者id */
kuid_t i_uid;
/* 使用者id组 */
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;
/* 以字节为单位的文件大小 */
loff_t i_size;
/* 最后访问时间 */
struct timespec i_atime;
/* 最后修改时间 */
struct timespec i_mtime;
/* 最后改变时间 */
struct timespec i_ctime;
/* 自旋锁 */
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
/* 使用的字节数 */
unsigned short i_bytes;
/* 以位为单位的块的大小 */
unsigned int i_blkbits;
/* 文件的块数 */
blkcnt_t i_blocks; #ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif /* Misc */
/* 状态标志 */
unsigned long i_state;
struct mutex i_mutex; /* 首次修改时间 */
unsigned long dirtied_when; /* jiffies of first dirtying */ /* 哈希表 */
struct hlist_node i_hash;
struct list_head i_wb_list; /* backing dev IO list */
struct list_head i_lru; /* inode LRU list */
struct list_head i_sb_list;
union {
struct list_head i_dentry;
struct rcu_head i_rcu;
};
u64 i_version;
/* 引用计数 */
atomic_t i_count;
atomic_t i_dio_count;
atomic_t i_writecount;
/* 默认的索引节点操作 */
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
/* 文件锁链表 */
struct file_lock *i_flock;
/* 设备地址映射 */
struct address_space i_data;
#ifdef CONFIG_QUOTA
/* 节点的磁盘限额 */
struct dquot *i_dquot[MAXQUOTAS];
#endif
/* 块设备链表 */
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
}; /* 索引节点版本号 */
__u32 i_generation; #ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
struct hlist_head i_fsnotify_marks;
#endif #ifdef CONFIG_IMA
/* 读数据计数 */
atomic_t i_readcount; /* struct files open RO */
#endif
/* 私有数据指针 */
void *i_private; /* fs or device private pointer */
};