Ext2层读文件入口函数

本文详细介绍了Ext2文件系统读文件的入口函数generic_file_read的工作流程,包括从__generic_file_aio_read开始,经过access_ok()安全检查,到do_generic_file_read函数中对页高速缓存的处理。文章通过分析do_generic_mapping_read函数,揭示了文件页高速缓存的结构和预读机制,并最终指向ext2_readpage函数,完成数据的读取。
摘要由CSDN通过智能技术生成

1.2.5 Ext2层读文件入口函数

好了,我们知道了Ext2文件系统的磁盘布局,以及始终缓存的磁盘超级拷贝块结构ext2_super_block和动态缓存的已分配磁盘索引节点结构ext2_inode这些预备知识。接下来就假设一个文件的inode已经分配好,并且包含该文件所有块号的对应宿主ext2_inode_info结构也在内存中初始化好了。那么如何读这个文件?

 

前面讲了,ext2层,也就是第二扩展文件系统的入口函数 generic_file_read,下面我们就从它开始,进入读文件操作的Ext2层:

 

ssize_t

generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)

{

       struct iovec local_iov = { .iov_base = buf, .iov_len = count };

       struct kiocb kiocb;

       ssize_t ret;

 

       init_sync_kiocb(&kiocb, filp);

       ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);

       if (-EIOCBQUEUED == ret)

              ret = wait_on_sync_kiocb(&kiocb);

       return ret;

}

 

我们看到,generic_file_read调用函数__generic_file_aio_read,来自mm/filemap.c

 

1134ssize_t

1135__generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,

1136                unsigned long nr_segs, loff_t *ppos)

1137{

1138        struct file *filp = iocb->ki_filp;

1139        ssize_t retval;

1140        unsigned long seg;

1141        size_t count;

1142

1143        count = 0;

1144        for (seg = 0; seg < nr_segs; seg++) {

1145                const struct iovec *iv = &iov[seg];

1146

1147                /*

1148                 * If any segment has a negative length, or the cumulative

1149                 * length ever wraps negative then return -EINVAL.

1150                 */

1151                count += iv->iov_len;

1152                if (unlikely((ssize_t)(count|iv->iov_len) < 0))

1153                        return -EINVAL;

1154                if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))

1155                        continue;

1156                if (seg == 0)

1157                        return -EFAULT;

1158                nr_segs = seg;

1159                count -= iv->iov_len;   /* This segment is no good */

1160                break;

1161        }

1162

1163        /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */

1164        if (filp->f_flags & O_DIRECT) {

1165                loff_t pos = *ppos, size;

1166                struct address_space *mapping;

1167                struct inode *inode;

1168

1169                mapping = filp->f_mapping;

1170                inode = mapping->host;

1171                retval = 0;

1172                if (!count)

1173                        goto out; /* skip atime */

1174                size = i_size_read(inode);

1175                if (pos < size) {

1176                        retval = generic_file_direct_IO(READ, iocb,

1177                                                iov, pos, nr_segs);

1178                        if (retval > 0 && !is_sync_kiocb(iocb))

1179                                retval = -EIOCBQUEUED;

1180                        if (retval > 0)

1181                                *ppos = pos + retval;

1182                }

1183                file_accessed(filp);

1184                goto out;

1185        }

1186

1187        retval = 0;

1188        if (count) {

1189                for (seg = 0; seg < nr_segs; seg++) {

1190                        read_descriptor_t desc;

1191

1192                        desc.written = 0;

1193                        desc.arg.buf = iov[seg].iov_base;

1194                        desc.count = iov[seg].iov_len;

1195                        if (desc.count == 0)

1196                                continue;

1197                        desc.error = 0;

1198                        do_generic_file_read(filp,ppos,&desc,file_read_actor);

1199                        retval += desc.written;

1200                        if (desc.error) {

1201                                retval = retval ?: desc.error;

1202                                break;

1203                        }

1204                }

1205        }

1206out:

1207        return retval;

1208}

 

函数__generic_file_aio_read()是所有文件系统实现同步和异步读操作所使用的通用例程。该函数接受四个参数:kiocb描述符的地址iocbiovec描述符数组的地址iov、数组的长度和存放文件当前指针的一个变量的地址pposiovec描述符数组被函数generic_file_read()调用时只有一个元素,该元素描述待接收数据的用户态缓冲区。

 

为什么只有一个元素呢?read()系统调用的一个叫做readv()的变体允许应用程序定义多个用户态缓冲区,从文件读出的数据分散存放在其中;__generic_file_aio_read()函数也实现这种功能,只不过从文件读出的数据将只烤贝到一个用户态缓冲区,所以只有一个元素。不过,可以想象,使用多个缓冲区虽然简单,但需要执行更多的步骤。

 

我们现在来说明函数__generic_file_aio_read()的操作。为简单起见,我们只针对最常见的情形,即对页高速缓存文件的系统调用read()所引发的同步操作。我们不讨论如何对错误和异常的处理。

 

我们看到,1154行调用access_ok()来检查iovec描述符所描述的用户态缓冲区是否有效。因为起始地址和长度已经从sys_read()系统调用得到,因此在使用前需要对它们进行检查。如何检查呢?access_ok宏实际上是__range_not_ok宏:

 

#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))

#define __range_not_ok(addr, size)                                  /

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值