- 访问文件的模式
模式 | 描述 |
---|---|
规范模式 | 规范模式下文件打开后, 标志O_SYNC与 O_DIRECT清0, 而且它的内容是由系统调用read()和write()来存取.系统调用read()将阻塞调用进程,直到数据被拷贝进用户态地址空间.但系统调用write()不同,它在数据被拷贝到高速缓存(延迟写)后就马上结束 |
同步模式 | 同步模式下文件打开后, 标志O_SYNC置1或稍后由系统调用fcntl对其置1. 这个标志只影响写操作(读操作总是会阻塞),它将阻塞调用进程,直到数据被有效地写入磁盘. |
异步模式 | 异步模式下, 文件的访问可以有两种方法, 即通过一组POSIX API或Linux特有的系统调用来实现. 所谓异步模式就是数据传送请求并不阻塞调用进程,而是在后台执行,同时应用程序继续它的正常运行. |
内存映射模式 | 内存映射模式下文件打开后,应用程序发出系统调用mmap()将文件映射到内存中. 因此, 文件就成为RAM中的一个字节数组, 应用程序就可以直接访问数组元素, 而不需要用系统调用read(), write()或lseek(). |
直接I/O模式 | 直接I/O模式下文件打开后,标志O_DIRECT置1.任何读写操作都将数据在用户态地址空间与磁盘间直接传送而不通过页高速缓存. |
-
数据结构
| 成员 | 描述 |
|–|--|
| struct kiocb | |
| struct iovec | | -
struct kiocb
| 成员 | 描述 |
|–|--|
| int (*ki_cancel)(struct kiocb *, struct io_event *); | |
| ssize_t (*ki_retry)(struct kiocb *); | |
| void (*ki_dtor)(struct kiocb *); | | -
struct iovec
| | |
|–|--|
| void __user *iov_base; | |
| __kernel_size_t iov_len; | | -
读文件
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;
}
ssize_t
__generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos)
{
struct file *filp = iocb->ki_filp;
ssize_t retval;
unsigned long seg;
size_t count;
count = 0;
for (seg = 0; seg < nr_segs; seg++) {
const struct iovec *iv = &iov[seg];
/*
* If any segment has a negative length, or the cumulative
* length ever wraps negative then return -EINVAL.
*/
count += iv->iov_len;
if (unlikely((ssize_t)(count|iv->iov_len) < 0))
return -EINVAL;
if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
continue;
if (seg == 0)
return -EFAULT;
nr_segs = seg;
count -= iv->iov_len; /* This segment is no good */
break;
}
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
if (filp->f_flags & O_DIRECT) {
loff_t pos = *ppos, size;
struct address_space *mapping;
struct inode *inode;
mapping = filp->f_mapping;
inode = mapping->host;
retval = 0;
if (!count)
goto out; /* skip atime */
size = i_size_read(inode);
if (pos < size) {
retval = generic_file_direct_IO(READ, iocb,
iov, pos, nr_segs);
if (retval >= 0 && !is_sync_kiocb(iocb))
retval = -EIOCBQUEUED;
if (retval > 0)
*ppos = pos + retval;
}
file_accessed(filp);
goto out;
}
retval = 0;
if (count) {
for (seg = 0; seg < nr_segs; seg++) {
read_descriptor_t desc;
desc.written = 0;
desc.arg.buf = iov[seg].iov_base;
desc.count = iov[seg].iov_len;
if (desc.count == 0)
continue;
desc.error = 0;
do_generic_file_read(filp,ppos,&desc,file_read_actor);
retval += desc.written;
if (!retval) {
retval = desc.error;
break;
}
}
}
out:
return retval;
}