内核模块代码中的特性"/>
内核模块代码中的特性
标记了__init和__exit的函数,都是作用于模块的;
__init:是载入模块时执行的操作
__exit:是卸载模块时的操作
printk是用来打印内核信息的函数,会将信息保存在系统日志,或是打印在控制台上;是否打印在控制台是取决于当前控制台日志级别,具体baidu
已下是printk的日志级别
#define KERN_EMERG"<0>"/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/
#define KERN_ALERT"<1>"/*报告消息,表示必须立即采取措施*/
#define KERN_CRIT"<2>"/*临界条件,通常涉及严重的硬件或软件操作失败*/
#define KERN_ERR"<3>"/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/
#define KERN_WARNING"<4>"/*警告条件,对可能出现问题的情况进行警告*/
#define KERN_NOTICE"<5>"/*正常但又重要的条件,用于提醒。常 用于与安全相关的消息*/
#define KERN_INFO"<6>"/*提示信息,如驱动程序启动时,打印硬件信息*/
#define KERN_DEBUG"<7>"/*调试级别的消息*/
module结构体:
linux/module.c
try_module_get()函数:
struct module {enum module_state state;/* Member of list of modules */struct list_head list;/* Unique handle for this module */char name[MODULE_NAME_LEN];/* Sysfs stuff. */struct module_kobject mkobj;struct module_attribute *modinfo_attrs;const char *version;const char *srcversion;struct kobject *holders_dir;/* Exported symbols */const struct kernel_symbol *syms;const s32 *crcs;unsigned int num_syms;/* Kernel parameters. */
#ifdef CONFIG_SYSFSstruct mutex param_lock;
#endifstruct kernel_param *kp;unsigned int num_kp;/* GPL-only exported symbols. */unsigned int num_gpl_syms;const struct kernel_symbol *gpl_syms;const s32 *gpl_crcs;#ifdef CONFIG_UNUSED_SYMBOLS/* unused exported symbols. */const struct kernel_symbol *unused_syms;const s32 *unused_crcs;unsigned int num_unused_syms;/* GPL-only, unused exported symbols. */unsigned int num_unused_gpl_syms;const struct kernel_symbol *unused_gpl_syms;const s32 *unused_gpl_crcs;
#endif#ifdef CONFIG_MODULE_SIG/* Signature was verified. */bool sig_ok;
#endifbool async_probe_requested;/* symbols that will be GPL-only in the near future. */const struct kernel_symbol *gpl_future_syms;const s32 *gpl_future_crcs;unsigned int num_gpl_future_syms;/* Exception table */unsigned int num_exentries;struct exception_table_entry *extable;/* Startup function. */int (*init)(void);/* Core layout: rbtree is accessed frequently, so keep together. */struct module_layout core_layout __module_layout_align;struct module_layout init_layout;/* Arch-specific module values */struct mod_arch_specific arch;unsigned long taints; /* same bits as kernel:taint_flags */#ifdef CONFIG_GENERIC_BUG/* Support for BUG */unsigned num_bugs;struct list_head bug_list;struct bug_entry *bug_table;
#endif#ifdef CONFIG_KALLSYMS/* Protected by RCU and/or module_mutex: use rcu_dereference() */struct mod_kallsyms __rcu *kallsyms;struct mod_kallsyms core_kallsyms;/* Section attributes */struct module_sect_attrs *sect_attrs;/* Notes attributes */struct module_notes_attrs *notes_attrs;
#endif/* The command line arguments (may be mangled). People likekeeping pointers to this stuff */char *args;#ifdef CONFIG_SMP/* Per-cpu data. */void __percpu *percpu;unsigned int percpu_size;
#endif#ifdef CONFIG_TRACEPOINTSunsigned int num_tracepoints;tracepoint_ptr_t *tracepoints_ptrs;
#endif
#ifdef CONFIG_TREE_SRCUunsigned int num_srcu_structs;struct srcu_struct **srcu_struct_ptrs;
#endif
#ifdef CONFIG_BPF_EVENTSunsigned int num_bpf_raw_events;struct bpf_raw_event_map *bpf_raw_events;
#endif
#ifdef CONFIG_JUMP_LABELstruct jump_entry *jump_entries;unsigned int num_jump_entries;
#endif
#ifdef CONFIG_TRACINGunsigned int num_trace_bprintk_fmt;const char **trace_bprintk_fmt_start;
#endif
#ifdef CONFIG_EVENT_TRACINGstruct trace_event_call **trace_events;unsigned int num_trace_events;struct trace_eval_map **trace_evals;unsigned int num_trace_evals;
#endif
#ifdef CONFIG_FTRACE_MCOUNT_RECORDunsigned int num_ftrace_callsites;unsigned long *ftrace_callsites;
#endif#ifdef CONFIG_LIVEPATCHbool klp; /* Is this a livepatch module? */bool klp_alive;/* Elf information */struct klp_modinfo *klp_info;
#endif#ifdef CONFIG_MODULE_UNLOAD/* What modules depend on me? */struct list_head source_list;/* What modules do I depend on? */struct list_head target_list;/* Destruction function. */void (*exit)(void);atomic_t refcnt;
#endif#ifdef CONFIG_CONSTRUCTORS/* Constructor functions. */ctor_fn_t *ctors;unsigned int num_ctors;
#endif#ifdef CONFIG_FUNCTION_ERROR_INJECTIONstruct error_injection_entry *ei_funcs;unsigned int num_ei_funcs;
#endif
} ____cacheline_aligned __randomize_layout;
#ifndef MODULE_ARCH_INIT
module结构体相当亢长,值得注意的几个:
里面的state是个枚举:
enum module_state {MODULE_STATE_LIVE, /* Normal state. */MODULE_STATE_COMING, /* Full formed, running module_init. */MODULE_STATE_GOING, /* Going away. */MODULE_STATE_UNFORMED, /* Still setting it up. */
};
refcnt为reference count,也就是module的被关联数;在module结构体中被定义为是个具有原子操作特性的atomic_t类型;
atomic_t refcnt;
try_module_get()函数用于判断module的状态(module_is_alive),以及atomic_inc_not_zero()函数判断module的refcnt是否大于0(等于0的话说明module目前是MODULE_STATE_GOING的状态,没办法get),大于0的话就将refcnt+1;
bool try_module_get(struct module *module)
{bool ret = true;if (module) {preempt_disable();/* Note: here, we can fail to get a reference */if (likely(module_is_live(module) &&atomic_inc_not_zero(&module->refcnt) != 0))trace_module_get(module, _RET_IP_);elseret = false;preempt_enable();}return ret;
}
若module在内核中,通过atomic_dec_if_positive()函数,在module的refcnt>0的时候将refcnt-1;
若对一个module做refcnt-1之后,ret<0了将会通过WARN_ON()来报warning;
void module_put(struct module *module)
{int ret;if (module) {preempt_disable();//下面是个原子操作,需要关闭抢占ret = atomic_dec_if_positive(&module->refcnt);WARN_ON(ret < 0); /* Failed to put refcount */trace_module_put(module, _RET_IP_);preempt_enable();}
}
关于文件操作:
file_operations结构用于建立,设备编号和驱动程序之间的连接,结构定义在linux/fs.h中;
在Linux中,指向file_operation结构的指针称为fops,在file_operations这个结构中,每个字段都要指向驱动程序中实现特定操作的函数,对于不支持的操作可以指向NULL;
很多参数带有__user,__user这个前缀是用于表明指针是一个用户空间地址,检查防止对用户空间的错误使用;
struct file_operations {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 (*read_iter) (struct kiocb *, struct iov_iter *);ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);int (*iopoll)(struct kiocb *kiocb, bool spin);int (*iterate) (struct file *, struct dir_context *);int (*iterate_shared) (struct file *, struct dir_context *);__poll_t (*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 *);unsigned long mmap_supported_flags;int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, loff_t, loff_t, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);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);int (*check_flags)(int);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 **, void **);long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMUunsigned (*mmap_capabilities)(struct file *);
#endifssize_t (*copy_file_range)(struct file *, loff_t, struct file *,loff_t, size_t, unsigned int);loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,struct file *file_out, loff_t pos_out,loff_t len, unsigned int remap_flags);int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout;
linux/fs.h中还定义了一个非常重要的结构体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_SECURITYvoid *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;
} __randomize_layout__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
file结构代表的是一个打开的文件(不限于设备驱动程序,linux中每个打开的文件在内核空间都有一个对应的file结构)这个file结构体在调用open函数时建立,并在close之后释放;
在内核源码中,用filp文件指针来指向file结构体;
以rcu为前缀的,是Linux提供的一种lockless机制,Read-copy Update,是rwlcok读写锁的强化版;和rwlcok不同的是,rcu在写入的时候也可以读;
它适用于读多写少的情况,允许多个进程对文件同时进行读操作,用rcu_read_lock()和rcu_read_unlock()这两个API来保持一个读者的RCU临界区.在该临界区内不允许发生上下文切换;
对于写操作的时候,需要先复制一份原来的文件的备份(copy),然后在对副本文件修改,当确保执行了rcu_read_unlock之后才能够去用副本去覆盖;
这个文章写的很好;
并且file结构体中还定义了指向inode结构体的指针f_inode
struct inode *f_inode;
还有指向file_operation的指针f_op;
const struct file_operations *f_op;
关于inode结构体:
linux用inode在内部表示文件,而前面提到的file是每打开一个文件就会建立一个file结构体,是打开文件的文件描述符; 对单个文件,可能会有许多个表示打开文件的文件描述符file结构,但他们都指向单个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_ACLstruct posix_acl *i_acl;struct posix_acl *i_default_acl;
#endifconst struct inode_operations *i_op;struct super_block *i_sb;struct address_space *i_mapping;#ifdef CONFIG_SECURITYvoid *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 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_ORDEREDseqcount_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_WRITEBACKstruct 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;
#endifstruct 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 */
#endifunion {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_ENCRYPTIONstruct fscrypt_info *i_crypt_info;
#endif#ifdef CONFIG_FS_VERITYstruct fsverity_info *i_verity_info;
#endifvoid *i_private; /* fs or device private pointer */
} __randomize_layout;
在indoe中定义了指向file_operations的指针i_fop
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
更多推荐
内核模块代码中的特性
发布评论