首页 | Linux 基础 | 资讯动态 | Linux 应用 | Linux 服务器 | Linux 开发 | Linux 安全 | 专题 | 联盟论坛
  当前位置:主页>Linux 开发>linux 内核>文章内容
Linux 2.6.11内核文件IO系统调用详解
来源:www.unix5.com 作者:riechelr_hl 发布时间:2007-05-20  

 

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 < PATH_MAX)
                        len = TASK_SIZE - (unsigned long) filename;
        }

        // 把filename拷贝len长度到page中,返回实际拷贝长度
        retval = strncpy_from_user(page, filename, len);
        if (retval >; 0) {
                // 如果retval大于等于len,则返回-ENAMETOOLONG
                if (retval < len)
                        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 < 0) {
                        // 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

这后面的函数使用了一个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;
}

共6页: 上一页 [1] [2] 3 [4] [5] [6] 下一页
 
如果您对本文有任何疑问或者建议,请到论坛讨论区发表您的意见: >> 论坛入口
[收藏] [推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
  热点文章
·使用 Linux 系统调用的内核命令
·Linux操作系统的源代码目录树结
·Linux用户态与内核态的交互讲解
·Linux内核对I/O端口的管理实现(
·深入分析 Linux操作系统的内核链
·Linux内核可装载模块对设备驱动
·概述Linux系统的驱动框架及驱动
·详解Linux 2.6内核新文件系统变
·Linux系统可卸载内核模块完全指
·FreeBSD手册讲解(一)--配置FreeB
·编译Linux操作系统的内核讲解
·Linux系统可卸载内核模块完全指
  相关文章
·定制Linux内核 充分发挥系统的潜
·Linux内核模块和驱动程序的详细
·剖析Linux 2.6内核在嵌入式上的
·Linux操作系统内核启动参数详细
·详细解析Linux操作系统的内核空
·Linux内核可装载模块对设备驱动
·走向Linux系统高手之路 编译内核
·深入分析 Linux操作系统的内核链
·Linux内核入侵检测安全增强实现
·Linux内核入侵检测安全增强实现
·Linux操作系统的源代码目录树结
·使用 Linux 系统调用的内核命令

本站信息源至:互联网络,均为学习,交流所用,如有版权问题,请联系我们.
站长QQ:397422079 E_mail:riechelr_hl@unix5.com
转载本站内容请注明原作者名.谢谢!