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数据传输结束。
=======================================

ext2/3,扩展文件系统,常用于Linux操作系统。是很多Linux发行版的默认文件系统。 Linux ext2/ext3文件系统使用索引节点来记录文件信息,作用像windows的文件分配表。 索引节点(inode)是一个结构,它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息。 一个文件系统维护了一个索引节点的数组(GroupDesc),每个文件或目录都与索引节点数组中的唯一一个元素对应。 系统给每个索引节点分配了一个号码,也就是该节点在数组中的索引号,称为索引节点号。 linux文件系统将文件索引节点号和文件名同时保存在目录中。所以,目录只是将文件的名称和 它的索引节点号结合在一起的一张表,目录中每一对文件名称和索引节点号称为一个连接。 对于一个文件 来说有唯一的索引节点号与之对应,对于一个索引节点号,却可以有多个文件名与之对应。因此,在磁盘 上的同一个文件可以通过不同的路径去访问它。 本程序是一个ext2/ext3文件系统查看器(ext4暂不支持).可以打开镜像文件及硬盘设备文件查看具体的 文件系统结构信息,如超级块,块组信息,文件inode,目录信息,文件信息,提取文件内容等。本人写这个程序就是 为了学习一下ext2/3,也希望通过本程序能让读者了解ext2/3文件系统结构. 具体使用方法请看readme
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值