Ext2文件系统—文件读写

本文详细介绍了Linux Ext2文件系统中文件读写的过程,包括从`sys_write()`开始,经过`fget_light()`、`vfs_write()`等一系列函数调用,直到数据写入缓冲区和物理磁盘。文件写操作涉及到缓冲区管理、锁检查、文件位置更新和预读策略等,整个流程复杂而高效,确保了文件读写的效率和安全性。
摘要由CSDN通过智能技术生成

1、定义

只有在“打开”了文件以后,或者说建立了进程与文件的“连接”之后,才能对文件进行读写。为了提高效率,Linux的读写操作都是带缓冲的,即写的时候先写到缓冲副本中,读的时候也从缓冲副本中读入。在多进程的系统中,由于同一文件可为多个进程共享,缓冲的作用就更加显著。

Linux文件缓冲设置在文件层的inode结构中。它里面有一个指针i_mapping,它指向一个address_space数据结构(通常这个结构就是inode中的i_data),缓冲区队列就在这个数据结构中。不过,挂载缓冲区队列中的并不是记录块(逻辑磁盘块)而是内存页面。也就是说,文件的内容并不是以逻辑磁盘块为单位而是以页面为单位进行缓冲的。如果一个记录块的大小为1K字节,那么一个页面就相当于4个逻辑磁盘块(记录块)。至于为什么这么做,是为了把文件内容的缓冲与文件的内存映射结合在一起(这也是为什么取名叫i_mapping、address_space,详细参考情景分析P580)。

在文件层是以页面为单位缓冲,但在设备层则是以逻辑磁盘块为单位缓冲。在一个记录块的缓冲区头部即buffer_head结构中有一个指针b_data指向记录块缓冲区,而buffer_head结构本身则不在缓冲区中。

以一个缓冲页面为例,在文件层它通过一个page数据结构挂入所属inode结构的缓冲页面队列,并且同时又可以通过各个进程的页面映射表映射到这些进程的内存空间;而在设备层则有通过若干buffer_head结构挂入其所在设备的缓冲区队列。

数据缓冲区的大小等于逻辑磁盘块(记录块)的大小,为物理磁盘块(扇区)大小的整数倍;同时内存页(文件层缓冲页page)的大小又为逻辑磁盘块的整数倍。在从磁盘读取数据时,文件系统一次读取若干个磁盘扇区大小的数据存放在记录块中,若干个记录块再组成一个内存页。如下图所示:

上面这些都是为了讲明白内存页page与逻辑磁盘块在文件系统所处的位置以及它们之间的关系(因此说到文件缓冲,要分清楚是文件层的缓冲页page还是设备层的逻辑磁盘块缓冲区buffer_head)。缓冲页面page结构除链入附属于inode结构的缓冲页面队列外,同时也链入到一个杂凑表page_hash_table中的杂凑队列中,所以寻找目标页面的的操作也是很高效的。

除了通过缓冲来提高文件读写效率外,还有个措施是“预读”。如果一个进程发动了对某一个缓冲页面的读写操作,并且该页面上不再内存中而需要从设备读入,那么就可以预测,通常情况下它接下去可能会继续往下读写,因此不妨预先将后面几个页面也一起读进来。其实以页面单位的缓冲本身就隐含着预读,因为一个页面包含着多个记录块(通常是4块),只不过预读的量很小而已。现在file结构中其实要维持两个上下文了。一个就是由“当前位置”f_pos代表的真正的读写上下文,而另一个就是预读的上下文。为此目的,在file结构中增设了f_reada、f_ramax、f_raend、f_rawin等几个字段(ra表示read ahead)。

2、文件写

2.1代码分析

1sys_write()                                       

注意,在调用参数中并不指明在文件中写的位置,因为文件的file结构代表着上下文,记录着在文件中的“当前位置”。

2→→fget_light ()                                     

根据打开文件号fd找到该已打开文件的file结构。而它实质上就是通过调用下面函数实现的。

3→→→fcheck_files ()                                              

struct fdtable *fdt = files_fdtable(files);

if (fd < fdt->max_fds)

         file = rcu_dereference(fdt->fd[fd]);

即通过fdtable,根据数组下标fd得到file结构。

fget_file()返回打开的文件file结构后,便开始为写做准备。

2→→file_pos_read ()                                 

很简单,就是返回file中的文件“当前位置”file->f_pos。再就是通过vfs_write()开始了真正的写流程。

2→→vfs_write ()                                     

if (!(file->f_mode & FMODE_WRITE))

         return -EBADF;

if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))

         return -EINVAL;

一个进程要对一个已打开的文件进行写操作,应该满足几个必要条件。其一是相应file结构里f_mode字段中的标志位FMODE_WRITE为1.这个字段的内容是在打开文件时根据对系统调用open()的参数flags经过变换而来的。若标志位FMODE_WRITE为0,则表示这个文件是按“只读”方式打开的,所以该标志位为1是写操作的一个必要条件。另外file结构必须包含有具体文件系统的写操作函数。

3→→rw_verify_area ()                              

这是检查文件是否加锁以及是否允许使用强制锁。

检查了锁之后,就是写操作本身了。具体的文件系统通过其中file_operation数据结构提供用于写操作的函数指针。在2.6内核中,Ext2文件系统的写操作函数指针指向的就是do_sync_write()

3→→→do_sync_write()                           

struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };

struct kiocb kiocb;

init_sync_kiocb(&kiocb, filp);

kiocb.ki_pos = *ppos;

kiocb.ki_left = len;

首先这段代码是对iovec结构和kiocb结构的初始化。 iovec 主要是用于存放两个内容:用来接收所读取数据的用户地址空间缓冲区的地址(iov_base)和缓冲区的大小(iov_len)。kiocb描述符用来跟踪正在运行的同步和异步I/O操作的完成状态。在Linux内核中,每个IO请求都对应一个kiocb结构体,其ki_filp成员指向对应的file指针,通过is_sync_kiocb可以判断某Kiocb是否为同步IO请求,如果非真,表示是异步IO请求。块设备和网络设备本身就是异步的。调用宏init_sync_kiocb来初始化描述符kiocb,并设置一个同步操作对象的有关字段。主要设置ki_filp字段和ki_obj字段以及在kiocb中设置io读写的位置和长度。

接下来又是调用ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos),进行真正的写,参数就是kiocb和iovec结构变量。可见linux的块设备也是异步IO。

4→→→→generic_file_aio_write ()                              

5→→→→→__generic_file_aio_write_nolock ()                              

struct file *file = iocb->ki_filp;

struct address_space * mapping = file->f_mapping;

先从kiocb中获得file结构和address_space结构。

6→→→→→→generic_segment_checks ()               

针对iovec段做一些检查。传下来的nr_segs值为1。

 /* Performs necessary checks before doing a write

 * @iov:  io vector request

 * @nr_segs:  number of segments in the iovec

 * @count:      number of bytes to write

 * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE

 *

 * Adjust number of segments and amount of bytes to write (nr_segs should be

 * properly initialized first). Returns appropriate error code that caller

 * should return or zero in case that write should be allowed.

 */                     

6→→→→→→generic_write_checks ()                         

针对写文件位置和长度做一些检查。

/*

 * Performs necessary checks before doing a write

 *

 * Can adjust writing

可以读写Ext2,以Ext2方式挂载Ext3文件系统(不支持Ext3日志),不支持中文! It provides Windows NT4.0/2000/XP/2003/Vista/2008 with full access to Linux Ext2 volumes (read access andwrite access). This may be useful if you have installed both Windows and Linux as a dual boot environment on your computer. What features are supported? Complete reading and writing access to files and directories of volumes with theExt2 orExt3 file system. Supports features which are specific to the I/O-system of Windows: Byte Range Locks, Directory Notfication (so the Explorer updates the view of a directory on changes within that directory), Oplocks (so SMB clients are able to cache the content of files). Allows Windows to run with paging files on Ext2 volumes. UTF-8 encoded file names are supported. The driver treats files with file names that start with a dot "." character ashidden. Supports GPT disks if the Windows version used also does. Supports use of the Windows mountvol utility to create or delete drive letters for Ext2 volumes (except on Windows NT 4.0). See also section"Can drive letters also be configured from scripts?". What features are *not* supported? Inodes that are larger than 128 bytes are not supported. Access rights are not maintained. All users can access all the directories and files of an Ext2 volume. If a new file or directory is created, it inherits all the permissions, the GID and the UID from the directory where it has been created. There is one exception to this rule: a file (but not a directory) the driver has created always has cleared "x" permissions, it inherits the "r" and the "w" permissions only. See also section"What limitations arise from not maintaining access rights?". The driver does not allow accessing special files at Ext2 volumes, the access will be always denied. (Special files are sockets, soft links, block devices, character devices and pipes.) Alternate 8.3-DOS names are not supported (just because there is no place to store them in an Ext2 file system). This can prevent legacy DOS applications, executed by the NTVDM of Windows, from accessing some files or directories. Currently the driver does not implement defragging support. So defragmentation applications will neither show fragmentation information nor defragment any Ext2 volume. This software does not achieve booting a Windows operating system from an Ext2 volume. LVM volumes are not supported, so it is not possible to access them.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值