linux内核文件IO的系统调用实现分析(open)

http://blog.chinaunix.net/uid-23969156-id-3086824.html

1.          引言
      从事Linux环境工作2年有余,一直懵懵懂懂,1年前拜读了《莱昂氏UNIX源代码分析》一书,感觉自己的学习道路漫漫且修远。最近受chinaunix的精华文帖启发,拟将近来的部分内核调用分析笔记拿出来与各前辈先进共同探讨学习,以壮个人学习之路。
      本部分主要讲述的是文件I/O操作的2.6.11内核版本实现,包括了主要的数据结构、宏定义和函数流程。以下分别讲述open,create,close,read,write,lseek系统调用。
2.          主要参考
《莱昂氏UNIX源代码分析》
《UNIX环境高级编程》
    www.kernel.org
3.          主要数据结构
3.1.          FD
        对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。
      当读、写一个文件时,用open或creat返回的文件描述符fd标识该文件,将其作为参数传送给read或write。在POSIX.1应用程序中,文件描述符为常数0、1和2分别代表STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO,意即标准输入,标准输出和标准出错输出,这些常数都定义在头文件;中。
文件描述符的范围是0~OPEN_MAX,在目前常用的linux系统中,是32位整形所能表示的整数,即65535,64位机上则更多。
3.2.          File
struct file {
     struct list_head          f_list; //文件链表指针
    struct dentry                  *f_dentry; // 文件对应的目录结构
    struct vfsmount           *f_vfsmnt; // 虚拟文件系统挂载点
    struct file_operations          *f_op; // 文件操作函数指针
    atomic_t                  f_count;
     unsigned int                   f_flags;
     mode_t                          f_mode; // 文件模式
    int                          f_error;
     loff_t                          f_pos; // 文件offset
     struct fown_struct          f_owner; //文件owner 结构
    unsigned int                  f_uid, f_gid;
     struct file_ra_state          f_ra; // 跟踪上次文件操作状态的结构指针
    size_t                          f_maxcount; // 文件大小
    unsigned long                  f_version;
     void                          *f_security; // hook 文件操作的security结构指针
    void                          *private_data; // tty 驱动器所需数据
#ifdef CONFIG_EPOLL
     struct list_head          f_ep_links; // EPOLL 机制检测所需链表结构
    spinlock_t                  f_ep_lock; // 兼容早期gcc bug 的标志
#endif /* #ifdef CONFIG_EPOLL */
     struct address_space          *f_mapping; // 地址映射表
}
3.3.          File_struct
File_struct结构保存了进程打开的所有文件表数据。
struct files_struct {
     atomic_t count; // 自动增量
    spinlock_t file_lock; // 低位成员保护标识
    int max_fds; // 最大文件句柄数目
    int max_fdset; // 最大的fd集合容量
    int next_fd; // 下一个空闲fd
     struct file ** fd; // 当前fd对应的文件结构指针列表
    fd_set *close_on_exec; // 可执行close的fd集合
    fd_set *open_fds; // 打开的fd集合
    fd_set close_on_exec_init; //
     fd_set open_fds_init;
     struct file * fd_array[NR_OPEN_DEFAULT]; // 默认打开的fd队列
};
4.          open 函数
4.1.          原型与参数
     int open(const char * pathname,    int oflag, .../*, mode_t mode * / )    -1代表错误。
     这里的oflag是一个整形,主要供open 函数使用,部分fcntl函数也会使用。详细的说明请用 man 2 open就可以看到了。以下列出了2.6内核定义的open和fcntl函数所使用的flag宏定义,说明的格式如宏定义名称;: 描述。
O_ACCMODE          ;: 读写文件操作时,用于取出flag的低2位。
O_RDONLY;: 只读打开
O_WRONLY;: 只写打开
O_RDWR;: 读写打开
O_CREAT;: 文件不存在则创建,需要mode_t,not fcntl
O_EXCL;: 如果同时指定了O_CREAT,而文件已经存在,则出错, not fcntl
O_NOCTTY;:
如果pathname指终端设备,则不将此设备分配作为此进程的控制终端。O_TRUNC;:
如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。      O_APPEND;:
每次写时都加到文件的尾端
O_NONBLOCK;: 如果p a t h n a m e指的是一个F I F O、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞方式。
O_NDELAY;;
O_SYNC;: 使每次write都等到物理I/O操作完成。
FASYNC;: 兼容BSD的fcntl同步操作
O_DIRECT;: 直接磁盘操作标识
O_LARGEFILE;: 大文件标识
O_DIRECTORY;:          必须是目录
O_NOFOLLOW;: 不获取连接文件
O_NOATIME;: 暂无
当新创建一个文件时,需要指定mode 参数,以下说明的格式如宏定义名称;: 描述。
     S_IRWXU;:文件拥有者有读写执行权限
     S_IRUSR (S_IREAD);:文件拥有者仅有读权限
     S_IWUSR (S_IWRITE);:文件拥有者仅有写权限
     S_IXUSR (S_IEXEC);:文件拥有者仅有执行权限
     S_IRWXG;:组用户有读写执行权限
     S_IRGRP;:组用户仅有读权限
     S_IWGRP;:组用户仅有写权限
     S_IXGRP;:组用户仅有执行权限
     S_IRWXO;:其他用户有读写执行权限
     S_IROTH;:其他用户仅有读权限
     S_IWOTH;:其他用户仅有写权限
     S_IXOTH;:其他用户仅有执行权限
4.2.         实现分析
4.2.1.         主要函数调用关系图
    sys_open( 见4.2.2 节)
    | ----------- getname( 见4.2.3 节 )
    | ----------- filp_open( 见4.2.4节 )
    |                         | ------------ open_namei( 见4.2.4.1节 )
    |                         |                   | ----------- may_open
    |                         | ------------ dentry_open( 见4.2.4.2节 )
4.2.2.         主调用函数sys_open,函数定义在/fs/open.c文件
asmlinkage long sys_open(const char __user * filename, int flags, int mode){
         char * tmp;
         int fd, error;

// 如果不是32位处理器,则增加大文件标识
#if BITS_PER_LONG != 32
         flags |= O_LARGEFILE;
#endif
         // 为了提高使用效率,在使用之前先将文件名拷贝到内核数据区。见3.2.2说明
         tmp = getname(filename);
         // 获取到返回值,如果出错,则返回,否则执行打开操作。
         fd = PTR_ERR(tmp);
         if (!IS_ERR(tmp)) {
                 // 从进程的文件表中找出一个空闲的文件表指针,如果出错,则返回
                 fd = get_unused_fd();
                 if (fd >= 0) {
                         // 执行打开操作。见3.2.3说明
                         struct file *f = filp_open(tmp, flags, mode);
                         // 获取返回结果,如果出错,则跳转至out_error,否则执行fd_install
                         error = PTR_ERR(f);
                         if (IS_ERR(f))
                                 goto out_error;
                         // 添加打开的文件表 f 到当前进程的文件表队列中。见3.2.4说明
                         fd_install(fd, f);
                 }
out:
                 // 释放getname分配的内存空间
                 putname(tmp);
         }
         return fd;
out_error:
                 // 将文件表指针返回到进程的文件表中,并返回错误代码。
         put_unused_fd(fd);
         fd = error;
         goto out;
}

4.2.3.         sys_open子函数getname
getname函数主要功能是在使用文件名之前将其拷贝到内核数据区,正常结束时返回内核分配的空间首地址,出错时返回错误代码。其调用了函数do_getname来实现。
static inline int do_getname(const char __user *filename, char *page){
         int retval;
         unsigned long len = PATH_MAX; // 内核允许的最大路径长度

// 如果进程的地址限制是否和KERNEL_DS相等,则检查文件名是否小于用户进程空间
         if (!segment_eq(get_fs(), KERNEL_DS)) {
                 // 文件名地址大于用户进程空间,则返回错误-EFAULT
                 if ((unsigned long) filename >= TASK_SIZE)
                         return -EFAULT;
                 // 获取较小的地址长度
                 if (TASK_SIZE - (unsigned long) filename                          len = TASK_SIZE - (unsigned long) filename;
         }

// 将filename拷贝len长度到page中,返回实际拷贝长度
         retval = strncpy_from_user(page, filename, len);
         if (retval >0) {
                 // 如果retval大于等于len,则返回-ENAMETOOLONG
                 if (retval                          return 0;
                 return -ENAMETOOLONG;
         } else if (!retval)
                 // filename 为空,则返回-ENOENT
                 retval = -ENOENT;
         return retval;
}

char * getname(const char __user * filename){
         char *tmp, *result;

result = ERR_PTR(-ENOMEM);
         // 从内核缓存中分配空间,如果成功,则执行do_getname
         tmp = __getname();
         if (tmp)   {
                 // 执行文件名拷贝操作
                 int retval = do_getname(filename, tmp);

result = tmp;
                 if (retval                          // do_getname出错,则释放空间,并返回错误代码
                         __putname(tmp);
                         result = ERR_PTR(retval);
                 }
         }
         // 如果前面操作成功,且audit_context不为空,则将当前文件名添加到audit列表中
         if (unlikely(current->;audit_context) && !IS_ERR(result) && result)
                 audit_getname(result);
         // 返回处理结果
         return result;
}
4.2.4.         sys_open子函数filp_open

在较高版本的内核里函数名改为do_filp_open,但是函数内容一样。
这后面的函数使用了一个nameidata的数据结构来描述文件相关的操作数据。
struct nameidata {
         struct dentry         *dentry; // 目录数据
         struct vfsmount *mnt; // 虚拟文件挂载点数据
         struct qstr         last; // hash值
         unsigned int         flags; // 文件操作标识
         int                 last_type; // 类型
         unsigned         depth;
         char *saved_names[MAX_NESTED_LINKS + 1];
         union {
                 struct open_intent open;
         } intent; // 专用数据
};
struct file *filp_open(const char * filename, int flags, int mode){
         int namei_flags, error;
         struct nameidata nd;

namei_flags = flags;
         if ((namei_flags+1) & O_ACCMODE)
                 namei_flags++; // 如果flags有O_WRONLY,则增加O_RDONLY
         if (namei_flags & O_TRUNC)
                 namei_flags |= 2; // 如果有O_TRUNC,则增加O_RDWR

error = open_namei(filename, namei_flags, mode, &nd); // 如3.2.3.1 描述
         if (!error)
                 return dentry_open(nd.dentry, nd.mnt, flags); // 如3.2.3.2描述

return ERR_PTR(error); // 返回错误代码
}
4.2.4.1.         filp_open子函数open_namei
open_namei函数主要执行文件操作的inode部分的打开等操作。
int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd){
         int acc_mode, error = 0;
         struct dentry *dentry;
         struct dentry *dir;
         int count = 0;

acc_mode = ACC_MODE(flag); // 取出低2位操作标识

if (flag & O_APPEND) // 取出O_APPEND操作标识
                 acc_mode |= MAY_APPEND;

//赋值open函数的专用数据
         nd->;intent.open.flags = flag;
         nd->;intent.open.create_mode = mode;

// 如果不需要创建文件,则在进程目录文件表搜索已有文件,并把结果拷贝到nd中
         if (!(flag & O_CREAT)) {
                 error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd);
                 if (error) // 错误代码有ENOENT,ENOTDIR,EAGAIN,ESTALE,
                         return error;
                 goto ok; // 否则执行打开函数,更新inode数据
         }

// 在进程文件表中搜索该文件,如果不存在,则创建,结果由nd保存
         error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);
         if (error)
                 return error;

// 检测nd的结果是否是一个目录文件,是则返回
         error = -EISDIR;
         if (nd->;last_type != LAST_NORM || nd->;last.name[nd->;last.len])
                 goto exit;
         // 获取文件的相关目录数据,结果返回到dentry中。
         dir = nd->;dentry;
         nd->;flags &= ~LOOKUP_PARENT;
         down(&dir->;d_inode->;i_sem);
         dentry = __lookup_hash(&nd->;last, nd->;dentry, nd);

do_last:
         // 如果dentry是一个错误值,则返回
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
                 up(&dir->;d_inode->;i_sem);
                 goto exit;
         }

// 如果dentry不存在,则创建他
         if (!dentry->;d_inode) {
                 if (!IS_POSIXACL(dir->;d_inode))
                         mode &= ~current->;fs->;umask;
                 error = vfs_create(dir->;d_inode, dentry, mode, nd); // 创建inode
                 up(&dir->;d_inode->;i_sem);
                 dput(nd->;dentry);
                 nd->;dentry = dentry;
                 if (error)
                         goto exit;
                 acc_mode = 0;
                 flag &= ~O_TRUNC;
                 goto ok;
         }

up(&dir->;d_inode->;i_sem);

error = -EEXIST; // 如果指定了O_EXCL和O_CREAT,文件存在时,出错
         if (flag & O_EXCL)
                 goto exit_dput;

if (d_mountpoint(dentry)) { // 检测文件是否是连接文件
                 error = -ELOOP;
                 if (flag & O_NOFOLLOW) // 如果指定不遍历连接文件,则返回
                         goto exit_dput;
                 // 检测dentry挂载点
                 while (__follow_down(&nd->;mnt,&dentry) && d_mountpoint(dentry));
         }
         error = -ENOENT;
         if (!dentry->;d_inode) // inode 不存在,则返回
                 goto exit_dput;
         if (dentry->;d_inode->;i_op && dentry->;d_inode->;i_op->;follow_link)
                 goto do_link; // 允许遍历连接文件,则手工找到连接文件对应的文件
        
         // 将处理后的dentry复制到nd结构中,并判断其是否是目录,是则返回错误
         dput(nd->;dentry);
         nd->;dentry = dentry;
         error = -EISDIR;
         if (dentry->;d_inode && S_ISDIR(dentry->;d_inode->;i_mode))
                 goto exit;
ok:
         error = may_open(nd, acc_mode, flag); // 打开文件,返回处理结果代码。如3.2.3.1.1描述
         if (error)
                 goto exit;
         return 0;

exit_dput:
         dput(dentry); // 释放dentry
exit:
         path_release(nd); // 释放nd结构
         return error; // 返回错误代码

do_link:
         error = -ELOOP;
         if (flag & O_NOFOLLOW)
                 goto exit_dput; // 不允许遍历连接文件,则返回错误
        
         // 以下代码是手工找到连接文件对应的文件dentry数据
         nd->;flags |= LOOKUP_PARENT;
         error = security_inode_follow_link(dentry, nd);
         if (error)
                 goto exit_dput;
         error = __do_follow_link(dentry, nd);
         dput(dentry);
         if (error)
                 return error;
         nd->;flags &= ~LOOKUP_PARENT;
         if (nd->;last_type == LAST_BIND) {
                 dentry = nd->;dentry;
                 goto ok;
         }
         error = -EISDIR;
         if (nd->;last_type != LAST_NORM)
                 goto exit;
         if (nd->;last.name[nd->;last.len]) {
                 putname(nd->;last.name);
                 goto exit;
         }
         error = -ELOOP;
         if (count++==32) {
                 putname(nd->;last.name);
                 goto exit;
         }
         dir = nd->;dentry;
         down(&dir->;d_inode->;i_sem);
         dentry = __lookup_hash(&nd->;last, nd->;dentry, nd);
         putname(nd->;last.name);
         goto do_last;
}
4.2.4.1.1.         filp_open子函数may_open

在较高版本的内核里作为open_namei的子函数。。。
may_open执行权限检测和文件打开,和truncate的操作。
int may_open(struct nameidata *nd, int acc_mode, int flag){
         struct dentry *dentry = nd->;dentry;
         struct inode *inode = dentry->;d_inode;
         int error;

if (!inode) return -ENOENT; // inode为空,则返回错误

if (S_ISLNK(inode->;i_mode)) // 连接文件,返回错误
                 return -ELOOP;
        
         if (S_ISDIR(inode->;i_mode) && (flag & FMODE_WRITE))
                 return -EISDIR; // 是目录且仅有写权限,返回错误

error = permission(inode, acc_mode, nd); // 见擦inode的accmode
         if (error)
                 return error;

if (S_ISFIFO(inode->;i_mode) || S_ISSOCK(inode->;i_mode)) {
                     flag &= ~O_TRUNC; // 如果是FIFO文件,则不允许truncate
         } else if (S_ISBLK(inode->;i_mode) || S_ISCHR(inode->;i_mode)) {
                 if (nd->;mnt->;mnt_flags & MNT_NODEV)
                         return -EACCES; // 如果是设备,则不允许truncate,否则返回错误
                 flag &= ~O_TRUNC;
         } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
                 return -EROFS; 如果flag标识和inode权限冲突,则返回错误
        
         // 如果inode只允许append方式写入,则不允许truncate和非append写入方式。
if (IS_APPEND(inode)) {
                 if   ((flag & FMODE_WRITE) && !(flag & O_APPEND))
                         return -EPERM;
                 if (flag & O_TRUNC)
                         return -EPERM;
         }

// O_NOATIME方式仅在inode用户是文件拥有者或者超级用户情况下才被允许
         if (flag & O_NOATIME)
                 if (current->;fsuid != inode->;i_uid && !capable(CAP_FOWNER))
                         return -EPERM;

// 检查是否有其他进程在使用该文件
         error = break_lease(inode, flag);
         if (error)
                 return error;

if (flag & O_TRUNC) {
                 error = get_write_access(inode); // 获取一次inode写操作权限
                 if (error)
                         return error;

// 锁定inode
                 error = locks_verify_locked(inode);
                 if (!error) {
                         DQUOT_INIT(inode); // 对inode执行配额初始化
                        
                         error = do_truncate(dentry, 0); // truncate dentry
                 }
                 put_write_access(inode); // 释放当前写操作权限
                 if (error)
                         return error;
         } else
                 if (flag & FMODE_WRITE) // 如果有写标识,则对inode执行配额初始化
                         DQUOT_INIT(inode);

return 0;
}
4.2.4.2.         open_namei子函数dentry_open
dentry_open函数主要实现文件表的对应打开等操作,返回文件指针。
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags){
         struct file * f;
         struct inode *inode;
         int error;

error = -ENFILE;
         f = get_empty_filp(); // 从进程文件表中获取一个未使用的文件结构指针,空则出错返回
         if (!f)
                 goto cleanup_dentry;
         // 设置文件的flags和mode标识
         f->;f_flags = flags;
         f->;f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
         inode = dentry->;d_inode;
         if (f->;f_mode & FMODE_WRITE) {
                 error = get_write_access(inode); // 获取一次inode写操作权限
                 if (error)
                         goto cleanup_file;
         }
         // 初始化文件结构
         f->;f_mapping = inode->;i_mapping;
         f->;f_dentry = dentry;
         f->;f_vfsmnt = mnt;
         f->;f_pos = 0;
         f->;f_op = fops_get(inode->;i_fop);
         file_move(f, &inode->;i_sb->;s_files);

// 调用文件驱动模块初始化物理磁盘
         if (f->;f_op && f->;f_op->;open) {
                 error = f->;f_op->;open(inode,f);
                 if (error)
                         goto cleanup_all;
         }
         f->;f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);

// 初始化上次读取状态
         file_ra_state_init(&f->;f_ra, f->;f_mapping->;host->;i_mapping);

// 如果设置了O_DIRECT,则检测文件结构中是否有驱动的操作函数指针
         if (f->;f_flags & O_DIRECT) {
                 if (!f->;f_mapping->;a_ops || !f->;f_mapping->;a_ops->;direct_IO) {
                         fput(f);
                         f = ERR_PTR(-EINVAL);
                 }
         }

return f; // 返回文件结构

cleanup_all: // 出错,则释放资源并返回
         fops_put(f->;f_op);
         if (f->;f_mode & FMODE_WRITE)
                 put_write_access(inode);
         file_kill(f);
         f->;f_dentry = NULL;
         f->;f_vfsmnt = NULL;
cleanup_file:
         put_filp(f);
cleanup_dentry:
         dput(dentry);
         mntput(mnt);
         return ERR_PTR(error);
}
4.3.         总结
open函数的主要操作就是为文件初始化inode,初始化文件结构,刷新进程文件链表。
5.         creat 函数
asmlinkage long sys_creat(const char __user * pathname, int mode){
         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
         从上面的简短的实现代码可以看出,creat的系统调用直接以O_CREAT|O_WRONLY|O_TRUNC标识调用open函数实现的。

阅读(349) | 评论(0) | 转发(2) |

0

上一篇:MySQL性能优化的最佳20+条经验

下一篇:委员联名提案停止评选三好学生 网友评论超2000

相关热门文章

  • SHTML是什么_SSI有什么用...
  • shell中字符串操作
  • 卡尔曼滤波的原理说明...
  • 关于java中的“错误:找不到或...
  • shell中的特殊字符

热门推荐

    -->

    给主人留下些什么吧!~~

    评论热议

    linux内核文件IO的系统调用实现分析(open)

    时间: 2024-08-08 05:19:02

    linux内核文件IO的系统调用实现分析(open)的相关文章

    linux内核启动第二阶段之setup_arch()函数分析-2.6.36

    执行setup_arch()函数 回到start_kernel当中,569行,调用setup_arch函数,传给他的参数是那个未被初始化的内部变量command_line.这个setup_arch()函数是start_kernel阶段最重要的一个函数,每个体系都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个体系的setup_arch()函数,由顶层Makefile中的ARCH变量决定: 它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init

    linux内核设计与实现 系统调用

    系统调用的实现过程:触发软终端,调用系统调用处理函数:在处理函数中,从寄存器中读取系统调用号以及参数,根据系统调用号,读取系统调用表:系统调用号就是系统调用函数的位置,取该位置值,就找到真正的系统调用函数,最后执行. arm系统调用:r0-r5传递参数 r0保存返回值 系统调用的绑定过程: 1.系统调用函数asmlinkage 2.在系统调用表中添加系统调用 3.在asm/unistd.h中添加系统调用号 4.编译内核 即可 系统调用使用:1.包含系统调用实现文件 或者2._syscallN()

    《linux 内核完全剖析》 void free_page() 分析

    最近在做项目开发时用到了MySql数据库,在看了一些有关MySql的文章后,很快就上手使用了.在使用的过程中还是出现了一些问题,因为使用的是绿色免安装版的MySql所以在配置的时候出现了一些问题,该篇文章就主要针对MySql绿色版的配置及其使用进行讨论. 一.MySql概述 MySql数据库是有瑞典MySql AB公司开发,现在该公司被Oracle收购属于Oracle所有.同SQL Server类似,它也是基于关系型数据库的数据库管理系统,在Web应用方面MySQL是最好的RDBMS之一,因为它

    linux c 文件打开并创建代码分析

    [[email protected] 03]# cat ex03-open-03.c/*文件ex03-open-03.c,O_CREAT和O_EXCL的使用*/#include #include #include #include int main(void){ int fd = -1; char filename[] = "test.txt"; /*打开文件,如果文件不存在,则报错*/ fd = open(filename,O_RDWR|O_CREAT|O_EXCL,S_IRWXU)

    跟踪分析Linux内核的启动过程--实验报告 分析 及知识重点

    跟踪分析Linux内核的启动过程 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ) 知识总结: ****Linux内核中关键目录: arch:不同cpu的支持,我们主要关注的是其中x86文件夹 init:内核启动的相关代码,期中main.c是内核启动的起点,main.c中的start_kernel是内核初始化的起点 ker

    【内核】几个重要的linux内核文件【转】

    转自:http://www.cnblogs.com/lcw/p/3159394.html Preface 当用户编译一个linux内核代码后,会产生几个文件:vmlinz.initrd.img, 以及System.map,如果配置过grub引导管理器程序,会在/boot目录下看到这几个文件. vmlinuz vmlinuz是可引导的.压缩的内核文件. 该文件包含了一个最小功能的内核,在PC上通常是先执行vmlinuz,之后加载initrd.img文件,最后加载根分区. 实际上initrd.img

    在linux内核文件中添加自己的驱动,添加自己的linux驱动,编译自己的linux驱动程序方法和例子图文

    此文章为done原创,转载请写明出处,尊重原创. 写这个文章,我参考了网上的一些博客: http://bbs.chinaunix.net/thread-3634524-1-1.html http://www.bkjia.com/gjrj/800182.html 也参考了参考了 <linux驱动开发详解>3.4章节,实现建立自己驱动目录. 文章中的驱动范例是:linux设备驱动开发详解第二版 的 global mem tow,宋宝华主编的书本光盘源码 在我们学习了linux的驱动之后,我们都想编

    Linux内核spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析

    转自:http://blog.csdn.net/wh_19910525/article/details/11536279 在Linux内核中何时使用spin_lock,何时使用spin_lock_irqsave很容易混淆.首先看一下代码是如何实现的. spin_lock的调用关系 spin_lock  ----->  raw_spin_lock 1 static inline void __raw_spin_lock(raw_spinlock_t *lock) 2 { 3 preempt_dis

    【C++】linux下头文件io.h的巨坑

    摘要:采用 io.h 头文件提供的函数读取指定文件夹中多个文件(文件名没有规律) 系统配置:ubuntu16.04, cmake编译 读取文件的代码如下, void getFilesAll(string path, vector<string>& files) { //文件句柄 long hFile = 0; //文件信息 struct _finddata_t fileinfo; string p; if ((hFile = _findfirst(p.assign(path).appe