linux 2.6.11内核文件IO的系统调用实现分析(read,write)(转载)

6.         read 函数
6.1.         原型与参数

ssize_t read(unsigned int fd, char * buf, size_t count)
         read函数是从打开的文件中读取数据。如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。如果失败,则返回-1。有多种情况可使实际读到的字节数少于要求读字节数:
• 读普通文件时,在读到要求字节数之前已到达了文件尾端。例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将返回0 (文件尾端)。
• 当从终端设备读时,通常一次最多读一行(第11章将介绍如何改变这一点)。
• 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
• 某些面向记录的设备,例如磁带,一次最多返回一个记录。
读操作从文件的当前位移量处开始,在成功返回之前,该位移量增加实际读得的字节数。

6.2.         实现分析

6.2.1.         主要函数调用关系图
sys_read (参见6.2.2 )
| ------------- vfs_read (参见6.2.3)

6.2.2.         主调用函数sys_read
asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
{
         struct file *file;
         ssize_t ret = -EBADF;
         int fput_needed;
        
// 从进程文件链表中根据fd获取file文件表,如果没有这个文件表,则返回EBADF错误
         file = fget_light(fd, &fput_needed); // fput_needed标识是否需要更新file结构的count
         if (file) {
                 loff_t pos = file_pos_read(file); // 获取file结构的pos位移参数
                 ret = vfs_read(file, buf, count, &pos); // 读取文件内容,参见6.2.2
                 file_pos_write(file, pos); // 更新file结构的pos位移参数
                 fput_light(file, fput_needed); // 更新文件count标识
         }

         return ret;
}

6.2.3.         sys_read子函数vfs_read
vfs_read将调用文件驱动模块的read函数从磁盘中读入数据并返回。
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
         ssize_t ret;

         if (!(file->;f_mode & FMODE_READ))
                 return -EBADF;// 如果文件不允许读模式,则返回EBADF错误
         if (!file->;f_op || (!file->;f_op->;read && !file->;f_op->;aio_read))
                 return -EINVAL;// 如果文件结构没有read函数指针,则返回EINVAL错误
         if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
                 return -EFAULT;// 检查传入的参数是否超出了用户空间地址,如果是则返回EFAULT错误

         // 通过inode结构lock当前要操作的区域,成功返回0
         ret = rw_verify_area(READ, file, pos, count);
         if (!ret) {
                 // 检查进程对文件是否有READ操作权限,成功,则返回0
                 ret = security_file_permission (file, MAY_READ);
                 if (!ret) {
                         if (file->;f_op->;read) // 调用文件驱动模块read函数读入数据
                                 ret = file->;f_op->;read(file, buf, count, pos);
                         else // 否则调用直接磁盘读操作
                                 ret = do_sync_read(file, buf, count, pos);
                         if (ret >; 0) {
                                 // 通知目录,当前文件已经被访问
                                 dnotify_parent(file->;f_dentry, DN_ACCESS);
                                 current->;rchar += ret; // 刷新进程读数据计数器
                         }
                         current->;syscr++;
                 }
         }

         return ret;
}


7.         write函数

7.1.         原型与参数
sys_write(unsigned int fd, const char * buf, size_t count)
         sys_write函数将数据写入到文件中。其返回值通常与参数nbytes的值不同,-1表示出错。write出错的一个常见原因是:磁盘已写满,或者 超过了对一个给定进程的文件长度限制。对于普通文件,写操作从文件的当前位移量处开始。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操 作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。

7.2.         实现分析

7.2.1.         主要函数调用关系图
sys_write (参见7.2.2 )
| ------------- vfs_write (参见7.2.3)

7.2.2.         主调用函数sys_write
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
{
         struct file *file;
         ssize_t ret = -EBADF;
         int fput_needed;

// 从进程文件链表中根据fd获取file文件表,如果没有这个文件表,则返回EBADF错误
         file = fget_light(fd, &fput_needed); // fput_needed标识是否需要更新file结构的count
         if (file) {
                 loff_t pos = file_pos_read(file); // 获取file结构的pos位移参数
                 ret = vfs_write(file, buf, count, &pos); // 写入文件,参见7.2.3 描述
                 file_pos_write(file, pos); // 更新file结构的pos位移参数
                 fput_light(file, fput_needed); // 更新文件count标识
         }

         return ret;
}

7.2.3.         sys_write子函数vfs_write
vfs_write将调用文件驱动模块的write函数向磁盘中写入数据并返回。如果在打开该文件时,指定了O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处再继续写入。
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
         ssize_t ret;

         if (!(file->;f_mode & FMODE_WRITE))
                 return -EBADF; // 如果文件不允许写模式,则返回EBADF错误
         if (!file->;f_op || (!file->;f_op->;write && !file->;f_op->;aio_write))
                 return -EINVAL; // 如果文件结构没有read函数指针,则返回EINVAL错误
         if (unlikely(!access_ok(VERIFY_READ, buf, count)))
                 return -EFAULT; // 检查传入的参数是否超出了用户空间地址,如果是则返回EFAULT错误

         // 通过inode结构lock当前要操作的区域,成功返回0
         ret = rw_verify_area(WRITE, file, pos, count);
         if (!ret) {
                 // 检查进程对文件是否有WRITE操作权限,成功,则返回0
                 ret = security_file_permission (file, MAY_WRITE);
                 if (!ret) {
                         if (file->;f_op->;write) // 调用文件驱动模块write函数写入数据
                                 ret = file->;f_op->;write(file, buf, count, pos);
                         else // 否则调用直接磁盘写操作
                                 ret = do_sync_write(file, buf, count, pos);
                         if (ret >; 0) {
                                 // 通知目录,当前文件已经被改写
                                 dnotify_parent(file->;f_dentry, DN_MODIFY);
                                 current->;wchar += ret; // 刷新进程写数据计数器
                         }
                         current->;syscw++;
                 }
         }

         return ret;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值