免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2636 | 回复: 1
打印 上一主题 下一主题

linux 2.6.11内核文件IO的系统调用实现分析(flseek&close) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-05-23 11:40 |只看该作者 |倒序浏览
    本帖是《linux 2.6.11内核文件IO的系统调用实现分析》的第三个部分,主要说明lseek函数和close的系统调用。前面两部分说明如下:
    a)《linux 2.6.11内核文件IO的系统调用实现分析(open&creat)》,主要说明open和creat两个文件IO的系统调用实现。
    b) 《linux 2.6.11内核文件IO的系统调用实现分析(read&write)》,主要说明read和write两个文件IO的系统调用实现。

    8.        lseek函数
    8.1.        原型与参数
    off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
    每个打开文件都有一个与其相关联的“当前文件位移量”。它是一个非负整数,用以度量从文件开始处计算的字节数。(本节稍后将对“非负”这一修饰词的某些例外进行说明。)通常,读、写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0。可以调用lseek显式地定位一个打开文件。
    对参数offset 的解释与参数origin的值有关。
    • 若origin是SEEK_SET,则将该文件的位移量设置为距文件开始处offset 个字节。
    • 若origin是SEEK_CUR,则将该文件的位移量设置为其当前值加offset, offset可为正或负。
    • 若origin是SEEK_END,则将该文件的位移量设置为文件长度加offset, offset可为正或负。
    若lseek成功执行,则返回新的文件位移量,为此可以用下列方式确定一个打开文件的当前位移量。这种方法也可用来确定所涉及的文件是否可以设置位移量。如果文件描述符引用的是一个管道或FIFO,则lseek返回-1,并将errno设置为EPIPE。
    以下文字引用《UNIX高级编程》,在以前的内核版本,origin参数名为whence:
    三个符号常数SEEK_SET,SEEK_CUR和SEEK_END是由系统V引进的。在系统V之前, whence被指定为0 (绝对位移量),1 ( 相对于当前位置的位移量)或2 (相对文件尾端的位移量)。很多软件仍直接使用这些数字进行编码。在lseek中的字符l表示长整型。在引入off_t数据类型之前, offset参数和返回值是长整型的。lseek是由V7引进的,当时C语言中增加了长整型。(在V6中,用函数seek和tell提供类似功能。)
    8.2.        实现分析
    8.2.1.        主要函数调用关系图
    sys_lseek (参见8.2.2 )
    | ------------- vfs_llseek (参见8.2.3)
            |                         | ------------ default_llseek (参见8.2.4)
    8.2.2.        主调用函数sys_lseek
    asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
    {
            off_t retval;
            struct file * file;
            int fput_needed;

            retval = -EBADF;
    // 从进程文件链表中根据fd获取file文件表,如果没有这个文件表,则返回EBADF错误
            file = fget_light(fd, &fput_needed); // fput_needed标识是否需要更新file结构的使用计数器
            if (!file)
                    goto bad;

            retval = -EINVAL;
            if (origin <= 2) {
                    loff_t res = vfs_llseek(file, offset, origin); // 底层文件偏移操作,见8.2.3描述
                    retval = res;
                    if (res != (loff_t)retval)
                            retval = -EOVERFLOW;        /* LFS: should only happen on 32 bit platforms */
            }
            // 如果origin不是0.1.2,则释放标识,返回EINVAL
            fput_light(file, fput_needed);
    bad:
            return retval; // 返回错误代码
    }

    8.2.3.        sys_lseek子函数vfs_llseek
    loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
    {
            loff_t (*fn)(struct file *, loff_t, int); // 文件系统统一的底层lseek函数接口

            fn = no_llseek; // 如果操作权限不够或者驱动没有实现该接口,则返回ESPIPE错误
            if (file->;f_mode & FMODE_LSEEK) {// 检测是否有LSEEK的操作权限
                    fn = default_llseek; // 默认的LSEEK实现函数,见8.2.4描述
                    if (file->;f_op && file->;f_op->;llseek)
                            fn = file->;f_op->;llseek; // 文件模块实现的LSEEK函数
            }
            return fn(file, offset, origin); // 按照前面的接口函数执行LSEEK操作并返回结果。
    }

    8.2.4.        vfs_llseek子函数default_llseek
    loff_t default_llseek(struct file *file, loff_t offset, int origin)
    {
            long long retval;

            lock_kernel();
            switch (origin) {
                    case 2: // 文件结尾向后偏移offset个字节
                            offset += i_size_read(file->;f_dentry->;d_inode);
                            break;
                    case 1: // 当前位置向后偏移offset个字节
                            offset += file->;f_pos;
            }
            retval = -EINVAL;
            if (offset >;= 0) {
                    if (offset != file->;f_pos) {
                            file->;f_pos = offset; // 刷新文件当前位置记录
                            file->;f_version = 0; // 更新文件version记录
                    }
                    retval = offset;
            }
            unlock_kernel();
            return retval;
    }

    9.        close函数
    9.1.        函数原型与参数
    int close (int f i l e d e s)
    关闭一个文件时也释放该进程加在该文件上的所有记录锁。当一个进程终止时,它所有的打开文件都由内核自动关闭。很多程序都使用这一功能而不显式地用c l o s e关闭打开的文件。对于对个任务同时操作该文件时,需要先释放该句柄,才能关闭。
    9.2.        实现分析
    9.2.1.        主要函数调用关系图
    sys_close (参见9.2.2 )
    | ------------- filp_close (参见9.2.3)
    9.2.2.        主调用函数sys_close
    asmlinkage long sys_close(unsigned int fd)
    {
            struct file * filp;
            struct files_struct *files = current->;files; // 进程的文件指针向量表

            spin_lock(&files->;file_lock);
            if (fd >;= files->;max_fds) // 超过进程最大句柄数,则返回EBADF
                    goto out_unlock;
            filp = files->;fd[fd];  // 从向量表中获取当前文件句柄对应的文件结构
            if (!filp) // 不存在,则返回EBADF
                    goto out_unlock;
            files->;fd[fd] = NULL; // 从句柄列表中清除该fd记录
            FD_CLR(fd, files->;close_on_exec); // 从关闭队列中清除该记录
            __put_unused_fd(files, fd); // 刷新进程文件指针向量表
            spin_unlock(&files->;file_lock);
            return filp_close(filp, files); // 调用子函数关闭,参见9.2.3说明

    out_unlock:
            spin_unlock(&files->;file_lock);
            return -EBADF;
    }

    9.2.3.        sys_clsoe子函数filp_close
    int filp_close(struct file *filp, fl_owner_t id)
    {
            int retval;

            retval = filp->;f_error; //清除出错标识
            if (retval)
                    filp->;f_error = 0;

            if (!file_count(filp)) {// 获取当前使用文件句柄的任务数目,如果有其他任务占用,则返回
                    printk(KERN_ERR "VFS: Close: file count is 0\n";
                    return retval;
            }

            if (filp->;f_op && filp->;f_op->;flush) {
                    int err = filp->;f_op->;flush(filp); //调用文件模块函数执行flush操作。
                    if (!retval)
                            retval = err;
            }

            dnotify_flush(filp, id); // 释放内核缓存
            locks_remove_posix(filp, id); // 释放该文件结构实例的posix同步锁
            fput(filp);
            return retval;
    }

    9.3.        小结
    主调用函数主要实现进程文件指针向量表的刷新。而filp_close则实现了内核和具体的文件驱动模块对文件结构的关闭操作。

论坛徽章:
0
2 [报告]
发表于 2005-05-31 17:09 |只看该作者

linux 2.6.11内核文件IO的系统调用实现分析(flseek&close)

看来lseek函数的实现要简单一点,大致是从管理层更改文件结构中对应的位置指针标识啊。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP