Linux VFS文件系统分析7

Linux VFS文件系统分析7(基于Linux6.6)---VFS与write接口介绍

一、write接口

write调用和read调用实现的功能类似,唯一不同的为read调用的是vfs_read实现文件读操作,而write调用的是vfs_write实现文件写操作。

write接口实现的内容如下:

1.该接口首先从当前进程的files指针中获取fd对应的文件描述符;

2.若获取文件描述符成功,则调用file_pos_read获取当前文件的offset;

3.调用vfs_write接口,从而调用该文件对应inode节点提供的write接口,实现write操作;

4.调用file_pos_write更新当前文件的offset;

5.调用fdput解除对文件描述符的引用计数。

该接口的实现流程图如下所示,该流程图说明了write接口的实现逻辑。

该接口的代码如下:

fs/read_write.c 

ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count)
{
	struct fd f = fdget_pos(fd);
	ssize_t ret = -EBADF;

	if (f.file) {
		loff_t pos, *ppos = file_ppos(f.file);
		if (ppos) {
			pos = *ppos;
			ppos = &pos;
		}
		ret = vfs_write(f.file, buf, count, ppos);
		if (ret >= 0 && ppos)
			f.file->f_pos = pos;
		fdput_pos(f);
	}

	return ret;
}

SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
		size_t, count)
{
	return ksys_write(fd, buf, count);
}

 

该接口中调用了vfs_write,关于vfs_write定义,我们再继续分析。

二、vfs_write接口分析

针对vfs_write接口,其实现的功能有:

1.若文件描述符不存在写取权限,返回失败;

2.若应用层传递的内存指针没有读权限,返回失败;

3.若该文件描述符没有write或aio_write接口,则返回失败;

4.调用rw_verify_area检测是否可对文件进行写取操作(如是否别的进程对文件加锁、要读取的大小是否合法等);

5.若file->f_op->write接口存在,则调用文件inode的write接口,进行文件读取操作;若不存在,则调用do_sync_write,调用aio_write;

6.调用fsnotify_access,发送文件被读取的通知;

7.增加写字符计数。

 fs/read_write.c

ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
	ssize_t ret;

	if (!(file->f_mode & FMODE_WRITE))
		return -EBADF;
	if (!(file->f_mode & FMODE_CAN_WRITE))
		return -EINVAL;
	if (unlikely(!access_ok(buf, count)))
		return -EFAULT;

	ret = rw_verify_area(WRITE, file, pos, count);
	if (ret)
		return ret;
	if (count > MAX_RW_COUNT)
		count =  MAX_RW_COUNT;
	file_start_write(file);
	if (file->f_op->write)
		ret = file->f_op->write(file, buf, count, pos);
	else if (file->f_op->write_iter)
		ret = new_sync_write(file, buf, count, pos);
	else
		ret = -EINVAL;
	if (ret > 0) {
		fsnotify_modify(file);
		add_wchar(current, ret);
	}
	inc_syscw(current);
	file_end_write(file);
	return ret;
}

三、应用举例

3.1、VFSwrite 接口的工作原理

当应用程序调用 write 系统调用时,VFS 层会根据文件描述符的类型,决定如何将数据写入具体的文件或设备。

  • 文件描述符write 操作需要一个已经打开的文件描述符,通常是通过 open 系统调用获取的。
  • VFS 层VFS 层会将 write 调用转发给具体的文件系统或设备驱动程序。对于不同类型的文件,VFS 会调用相应的操作方法。
  • 文件系统的具体实现:例如,对于普通文件(如 ext4、NTFS),会有 write 系统调用的实现;对于设备文件(如 /dev/null/dev/random),则由相应的设备驱动程序处理。

3.2、write 示例应用

以下是几种常见情景下的 write 调用示例,包括写入普通文件、设备文件和网络文件。

1.示例 1:向本地普通文件写入数据

这是一个常见的例子,我们通过 write 向本地普通文件写入数据。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main() {
    const char *file_path = "/tmp/testfile.txt";  // 假设这是一个文件路径
    int fd;
    const char *data = "Hello, Linux!\n";  // 要写入的内容
    ssize_t bytes_written;

    // 打开文件(如果文件不存在,则创建)
    fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 写入数据到文件
    bytes_written = write(fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("write");
        close(fd);
        return 1;
    }

    printf("Written %zd bytes to %s\n", bytes_written, file_path);

    // 关闭文件描述符
    close(fd);
    return 0;
}

工作流程:

  1. open 系统调用VFS 层识别 /tmp/testfile.txt 为一个本地文件,并根据文件权限(O_WRONLY | O_CREAT | O_TRUNC)将文件打开。此时,VFS 会通过具体的文件系统(如 ext4)调用文件系统的 open 函数。
  2. write 系统调用write 将数据写入文件时,VFS 会调用具体文件系统(如 ext4)的 write 函数,最终通过磁盘 I/O 写入数据。
  3. 关闭文件描述符close 系统调用将释放文件描述符,VFS 会调用相应的文件系统实现来释放资源。
2.示例 2:写入设备文件(如 /dev/null

设备文件是一种特殊类型的文件,写入数据时会根据设备的特性做不同的处理。例如,向 /dev/null 写入任何数据时,数据都会被丢弃。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    const char *dev_path = "/dev/null";  // 特殊设备文件
    int fd;
    const char *data = "This will be discarded\n";  // 要写入的数据
    ssize_t bytes_written;

    // 打开设备文件
    fd = open(dev_path, O_WRONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 向设备写入数据
    bytes_written = write(fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("write");
        close(fd);
        return 1;
    }

    printf("Written %zd bytes to %s (data discarded)\n", bytes_written, dev_path);

    // 关闭文件描述符
    close(fd);
    return 0;
}

工作流程:

  1. open 系统调用VFS 层识别 /dev/null 为设备文件,并将操作传递给 null 设备驱动。
  2. write 系统调用:写入的数据会被丢弃,VFS 会通过设备驱动的 write 函数来处理。对于 /dev/null 设备,数据会直接丢弃,不会做任何存储。
  3. 关闭文件描述符:操作结束后,调用 close 来释放文件描述符。
3.示例 3:写入网络文件(如通过 NFS 挂载的文件)

如果你将远程文件系统(如 NFS)挂载到本地,你可以像访问本地文件一样向网络文件写入数据。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    const char *nfs_path = "/mnt/nfs/share/testfile.txt";  // NFS 挂载的路径
    int fd;
    const char *data = "Hello from NFS!\n";  // 要写入的数据
    ssize_t bytes_written;

    // 打开远程 NFS 文件
    fd = open(nfs_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 向 NFS 文件写入数据
    bytes_written = write(fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("write");
        close(fd);
        return 1;
    }

    printf("Written %zd bytes to %s (via NFS)\n", bytes_written, nfs_path);

    // 关闭文件描述符
    close(fd);
    return 0;
}

工作流程:

  1. open 系统调用VFS 层识别 /mnt/nfs/share/testfile.txt 为一个网络文件,并将操作转发给 NFS 客户端。
  2. write 系统调用:通过 VFS 层,写入操作会发送到远程 NFS 服务器,数据通过网络传输并存储到远程服务器上的文件系统。
  3. 关闭文件描述符:与本地文件一样,操作结束后通过 close 来释放文件描述符。
4.示例 4:向 /dev/random 写入数据

/dev/random 是一个只读设备文件,它用于提供高质量的随机数。尝试向其写入数据会导致错误。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    const char *dev_path = "/dev/random";  // 随机数设备
    int fd;
    const char *data = "This won't be written\n";  // 想要写入的数据
    ssize_t bytes_written;

    // 打开设备文件
    fd = open(dev_path, O_WRONLY);  // 以写方式打开
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 尝试写入数据(会失败)
    bytes_written = write(fd, data, strlen(data));
    if (bytes_written == -1) {
        perror("write");  // 会报告错误,因为 /dev/random 是只读设备
        close(fd);
        return 1;
    }

    printf("Written %zd bytes to %s\n", bytes_written, dev_path);

    // 关闭文件描述符
    close(fd);
    return 0;
}

工作流程:

  1. open 系统调用VFS 层识别 /dev/random 为只读设备,open 会失败,因为设备不允许写入。
  2. write 系统调用:如果应用程序尝试写入数据,write 会失败并返回 -1,并通过 perror 显示错误信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值