EXT2的文件操作方法

const struct file_operations ext2_file_operations = {
 .llseek  = generic_file_llseek,
 .read  = do_sync_read,
 .write  = do_sync_write,
 .aio_read = generic_file_aio_read,
 .aio_write = generic_file_aio_write,
 .unlocked_ioctl = ext2_ioctl,
 .mmap  = generic_file_mmap,
 .open  = generic_file_open,
 .release = ext2_release_file,
 .fsync  = ext2_sync_file,
 .splice_read = generic_file_splice_read,
 .splice_write = generic_file_splice_write,
};
======================================
loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
{
 loff_t rval;
 mutex_lock(&file->f_dentry->d_inode->i_mutex);
 rval = generic_file_llseek_unlocked(file, offset, origin);
 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
 return rval;
}
这个函数,只用于普通的文件,然后调用generic_file_llseek_unlocked函数,来更新文件的偏移指针。通过指定参数offset和origin。
loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
{
01 struct inode *inode = file->f_mapping->host;
02 switch (origin) {
03 case SEEK_END:
04  offset += inode->i_size;
05  break;
06 case SEEK_CUR:
07  if (offset == 0)
08   return file->f_pos;
09  offset += file->f_pos;
10  break;
11 }
12 if (offset < 0 || offset > inode->i_sb->s_maxbytes)
13  return -EINVAL;
14 if (offset != file->f_pos) {
15  file->f_pos = offset;
16  file->f_version = 0;
17 }
18 return offset;
19}
根据origin参数的值的,是文件的开始,或结尾,然后指针指向相应的位置。
=======================================
ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
01 struct iovec iov = { .iov_base = buf, .iov_len = len };
02 struct kiocb kiocb;
03 ssize_t ret;
05 init_sync_kiocb(&kiocb, filp);
06 kiocb.ki_pos = *ppos;
07 kiocb.ki_left = len;
09 for (;;) {
10  ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
11  if (ret != -EIOCBRETRY)
12   break;
13  wait_on_retry_sync_kiocb(&kiocb);
14 }
15
16 if (-EIOCBQUEUED == ret)
17  ret = wait_on_sync_kiocb(&kiocb);
18 *ppos = kiocb.ki_pos;
19 return ret;
20}
=======================================
ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
01 struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
02 struct kiocb kiocb;
03 ssize_t ret;
04
05 init_sync_kiocb(&kiocb, filp);
06 kiocb.ki_pos = *ppos;
07 kiocb.ki_left = len;
08
09 for (;;) {
10  ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
11  if (ret != -EIOCBRETRY)
12   break;
13  wait_on_retry_sync_kiocb(&kiocb);
14 }
15
16 if (-EIOCBQUEUED == ret)
17  ret = wait_on_sync_kiocb(&kiocb);
18 *ppos = kiocb.ki_pos;
19 return ret;
20}
第1行iovec局部变量,包含用户态缓冲区的地址和长度。
第2行kiocb描述符用来跟踪正在运行的同步和异步I/O操作的完成状态。
第5行调用宏init_sync_kiocb来初始化描述符kiocb,并设置一个同步操作对象的有关字段。主要设置ki_key字段和ki_filp字段及ki_obj字段。
第10行这个函数指针会调用generic_file_aio_read()函数将刚填完的iovec和kiocb描述符地址传给它。后面这个函数返回一个值,这个值通常就是从文件有效读入的字节数。
第13行等待,测试&(iocb)->ki_flags标识位,如果为假,则进程切换。然后设置进程为运行状态。
第19行返回。
=======================================
ssize_t generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos)
{
01 struct file *filp = iocb->ki_filp;
02 ssize_t retval;
03 unsigned long seg;
04 size_t count;
05 loff_t *ppos = &iocb->ki_pos;
07 count = 0;
08 retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
09 if (retval)
10  return retval;
13 if (filp->f_flags & O_DIRECT) {
14  loff_t size;
15  struct address_space *mapping;
16  struct inode *inode;
18  mapping = filp->f_mapping;
19  inode = mapping->host;
20  if (!count)
21   goto out; /* skip atime */
22  size = i_size_read(inode);
23  if (pos < size) {
24   retval = filemap_write_and_wait_range(mapping, pos,
25     pos + iov_length(iov, nr_segs) - 1);
26   if (!retval) {
27    retval = mapping->a_ops->direct_IO(READ, iocb,iov, pos, nr_segs);
29   }
30   if (retval > 0)
31    *ppos = pos + retval;
32   if (retval) {
33    file_accessed(filp);
34    goto out;
35   }
36  }
37 }
39 for (seg = 0; seg < nr_segs; seg++) {
40  read_descriptor_t desc;
42  desc.written = 0;
43  desc.arg.buf = iov[seg].iov_base;
44  desc.count = iov[seg].iov_len;
45  if (desc.count == 0)
46   continue;
47  desc.error = 0;
48  do_generic_file_read(filp, ppos, &desc, file_read_actor);
49  retval += desc.written;
50  if (desc.error) {
51   retval = retval ?: desc.error;
52   break;
53  }
54  if (desc.count > 0)
55   break;
56 }
57out:
58 return retval;
59}
第8行使用generic_segment_checks执行必要的检查。调整一些段和字节的写。
第13行判断是否为直接读。
第24行等待文件的范围
第27行直接读取
第39-55行循环读取段,调用do_generic_file_read函数,通过传递给它对象指针,文件偏移,刚分配的读操作符的地址和函数file_read_actor函数的地址,来进行读取。
=======================================
ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
  unsigned long nr_segs, loff_t pos)
{
01 struct file *file = iocb->ki_filp;
02 struct address_space *mapping = file->f_mapping;
03 struct inode *inode = mapping->host;
04 ssize_t ret;
05 BUG_ON(iocb->ki_pos != pos);
06 mutex_lock(&inode->i_mutex);
07 ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
08   &iocb->ki_pos);
09 mutex_unlock(&inode->i_mutex);
10 if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
11  ssize_t err;
12  err = sync_page_range(inode, mapping, pos, ret);
13  if (err < 0)
14   ret = err;
15 }
16 return ret;
17}
写函数和读函数有点类似的。
第6行调用__generic_file_aio_write_nolock将涉及的页标记为脏,并传递相应的参数,iovec和kiocb类型的局部变量地址、用户态缓冲区的段数和ppos.
第12行函数sync_page_range()用来强制内核将页高速缓存中的的页刷新,阻塞当前进程直到I/O数据传输结束。
=======================================

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值