写文件的流程

【文件管理】文件的写write() 在打开了文件以后 ,或者说建立起进程与文件之间的连接zhihou 阅读详情

许多文件系统都是通过generic_file_write()函数来实现文件对象的write方法,即write(库函数)->sys_write()->generic_file_write():

ssize_t generic_file_write(struct file *file, const char __user *buf,
			   size_t count, loff_t *ppos)
{
	struct address_space *mapping = file->f_mapping;
	struct inode *inode = mapping->host;
	ssize_t	ret;
	struct iovec local_iov = { .iov_base = (void __user *)buf,
					.iov_len = count };

	down(&inode->i_sem);
	ret = __generic_file_write_nolock(file, &local_iov, 1, ppos);
	up(&inode->i_sem);

	if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
		ssize_t err;

		err = sync_page_range(inode, mapping, *ppos - ret, ret);
		if (err < 0)
			ret = err;
	}
	return ret;
}


generic_file_write会调用__generic_file_write_nolock(),即write(库函数)->sys_write()->generic_file_write()->__generic_file_write_nolock:

ssize_t
__generic_file_write_nolock(struct file *file, const struct iovec *iov,
				unsigned long nr_segs, loff_t *ppos)
{
	struct kiocb kiocb;
	ssize_t ret;

	init_sync_kiocb(&kiocb, file);
	ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
	if (ret == -EIOCBQUEUED)
		ret = wait_on_sync_kiocb(&kiocb);
	return ret;
}


write(库函数)->sys_write()->generic_file_write()->__generic_file_write_nolock()->__generic_file_aio_write_nolock():

ssize_t
__generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
				unsigned long nr_segs, loff_t *ppos)
{
	struct file *file = iocb->ki_filp;
	struct address_space * mapping = file->f_mapping;
	size_t ocount;		/* original count */
	size_t count;		/* after file limit checks */
	struct inode 	*inode = mapping->host;
	unsigned long	seg;
	loff_t		pos;
	ssize_t		written;
	ssize_t		err;

	ocount = 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.
		 */
		ocount += iv->iov_len;
		if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
			return -EINVAL;
		if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
			continue;
		if (seg == 0)
			return -EFAULT;
		nr_segs = seg;
		ocount -= iv->iov_len;	/* This segment is no good */
		break;
	}

	count = ocount;
	pos = *ppos;

	/* We can write back this queue in page reclaim */
	current->backing_dev_info = mapping->backing_dev_info;
	written = 0;

	err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
	if (err)
		goto out;

	if (count == 0)
		goto out;

	err = remove_suid(file->f_dentry);
	if (err)
		goto out;

	inode_update_time(inode, 1);

	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
	if (unlikely(file->f_flags & O_DIRECT)) {
		written = generic_file_direct_write(iocb, iov,
				&nr_segs, pos, ppos, count, ocount);
		if (written < 0 || written == count)
			goto out;
		/*
		 * direct-io write to a hole: fall through to buffered I/O
		 * for completing the rest of the request.
		 */
		pos += written;
		count -= written;
	}

	written = generic_file_buffered_write(iocb, iov, nr_segs,
			pos, ppos, count, written);
out:
	current->backing_dev_info = NULL;
	return written ? written : err;
}


write(库函数)->sys_write()->generic_file_write()->__generic_file_write_nolock()->__generic_file_aio_write_nolock()->generic_file_buffered_write():

ssize_t
generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
		unsigned long nr_segs, loff_t pos, loff_t *ppos,
		size_t count, ssize_t written)
{
	struct file *file = iocb->ki_filp;
	struct address_space * mapping = file->f_mapping;
	struct address_space_operations *a_ops = mapping->a_ops;
	struct inode 	*inode = mapping->host;
	long		status = 0;
	struct page	*page;
	struct page	*cached_page = NULL;
	size_t		bytes;
	struct pagevec	lru_pvec;
	const struct iovec *cur_iov = iov; /* current iovec */
	size_t		iov_base = 0;	   /* offset in the current iovec */
	char __user	*buf;

	pagevec_init(&lru_pvec, 0);

	buf = iov->iov_base + written;	/* handle partial DIO write */
	do {
		unsigned long index;
		unsigned long offset;
		size_t copied;

		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
		//获取要写的缓冲页面索引(如何根据页索引在radix树中获取到指定页描述符,ULK-PAGE600)
		index = pos >> PAGE_CACHE_SHIFT;
		bytes = PAGE_CACHE_SIZE - offset;
		//最后剩一点写入内容的处理
		if (bytes > count)
			bytes = count;

		/*
		 * Bring in the user page that we will copy from _first_.
		 * Otherwise there's a nasty deadlock on copying from the
		 * same page as we're writing to, without it being marked
		 * up-to-date.
		 */
		fault_in_pages_readable(buf, bytes);
		//在radix树里面查找要被写的page,如果不存在则创建一个,见下面分析
		page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec);
		if (!page) {
			status = -ENOMEM;
			break;
		}
		//为这个page准备一组buffer_head结构,用于描述组成这个page的数据块,见下面分析
		status = a_ops->prepare_write(file, page, offset, offset+bytes);
		if (unlikely(status)) {
			loff_t isize = i_size_read(inode);
			/*
			 * prepare_write() may have instantiated a few blocks
			 * outside i_size.  Trim these off again.
			 */
			unlock_page(page);
			page_cache_release(page);
			if (pos + bytes > isize)
				vmtruncate(inode, isize);
			break;
		}
		if (likely(nr_segs == 1))
			copied =  (page, offset,
							buf, bytes);
		else
			copied = filemap_copy_from_user_iovec(page, offset,
						cur_iov, iov_base, bytes);
		flush_dcache_page(page);
		//把基础缓冲区标记为脏,以便随后把他们都写到磁盘。
		status = a_ops->commit_write(file, page, offset, offset+bytes);
		if (likely(copied > 0)) {
			if (!status)
				status = copied;

			if (status >= 0) {
				written += status;
				count -= status;
				pos += status;
				buf += status;
				if (unlikely(nr_segs > 1))
					filemap_set_next_iovec(&cur_iov,
							&iov_base, status);
			}
		}
		if (unlikely(copied != bytes))
			if (status >= 0)
				status = -EFAULT;
		unlock_page(page);
		mark_page_accessed(page);
		page_cache_release(page);
		if (status < 0)
			break;
		balance_dirty_pages_ratelimited(mapping);
		cond_resched();
	} while (count);
	*ppos = pos;

	if (cached_page)
		page_cache_release(cached_page);

	/*
	 * For now, when the user asks for O_SYNC, we'll actually give O_DSYNC
	 */
	if (likely(status >= 0)) {
		if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
			if (!a_ops->writepage || !is_sync_kiocb(iocb))
				status = generic_osync_inode(inode, mapping,
						OSYNC_METADATA|OSYNC_DATA);
		}
  	}
	
	/*
	 * If we get here for O_DIRECT writes then we must have fallen through
	 * to buffered writes (block instantiation inside i_size).  So we sync
	 * the file data here, to try to honour O_DIRECT expectations.
	 */
	if (unlikely(file->f_flags & O_DIRECT) && written)
		status = filemap_write_and_wait(mapping);

	pagevec_lru_add(&lru_pvec);
	return written ? written : status;
}

static inline struct page *
__grab_cache_page(struct address_space *mapping, unsigned long index,
			struct page **cached_page, struct pagevec *lru_pvec)
{
	int err;
	struct page *page;
repeat:
	//根据address_space地址和缓冲页的索引,获取缓冲页面的描述符(ULK-PAGE602)
	page = find_lock_page(mapping, index);
	if (!page) {
		if (!*cached_page) {
			*cached_page = page_cache_alloc(mapping);
			if (!*cached_page)
				return NULL;
		}
		//把一个新页的描述符插入到页高速缓存--在radix树中出入新节点
		err = add_to_page_cache(*cached_page, mapping,
					index, GFP_KERNEL);
		if (err == -EEXIST)
			goto repeat;
		if (err == 0) {
			page = *cached_page;
			page_cache_get(page);
			if (!pagevec_add(lru_pvec, page))
				__pagevec_lru_add(lru_pvec);
			*cached_page = NULL;
		}
	}
	return page;
}


//prepare_write分析
address_space对象的prepare_write和commit_write方法专用于由generic_file_write()实现的通用写操作,这个函数适用于普通文件和块设备文件。每个磁盘文件系统都定义了自己的prepare_write方法。与读操作类似,这个方法只是普通函数的封装。例如,Ext2文件系统通过下列函数实现prepare_write方法
//在fs/buffer.c目录中
int ext2_prepare_write(struct file *file,struct page *page,unsigned from ,unsigned to)
{
return block_prepare_write(page,from,to,ext2_get_block);
}
一旦prepare_write,generic_file_write()函数就用存放在用户地址空间中的数据更新高速缓存页面。接下来,调用address_space对象的commit_write方法。这个方法由generic_commit_write()函数实现。generic_commit_write()函数执行如下步骤:
1.调用__block_commit_write()函数,执行如下步骤:
A.考虑页中受写操作影响的所有缓冲区;对于其中的每个缓冲区,将对应缓冲区首部的BH_Uptodate和BH_Dirty标志置位。
B.标记相应索引节点为脏,将索引节点加入超级块脏的索引节点连接
C.如果缓冲区页中的所有缓冲区是最新的,则将PG_uptodate标志置位
D.将页的PG_Dirty标志置位,并在基树中将页标记成脏

PMFS内存文件系统的文件块组织方式以及写流程 由于最近做关于PMFS文件系统的实验,实现了pmfs写文件的数据一致性,还改了PMFS的空间管理,所以想对自己近两个月所做的工作进行一个总结,以下就简单谈谈自己对于PMFS以及拓展知识的理解,如有不对之处还请指出!或者还想了解更多的可以留言讨论。 文章目录介绍文件块组织Write 介绍 先简单介绍一下,物理块号,逻辑块号,物理地址,逻辑地址以及虚拟地址之间的关系。 这里围绕PMFS文件系统来展开介... 阅读详情

相关推荐

从FSBL到Flash:Vivado SDK完整bin文件烧写流程详解(2018.3版)

本文详细介绍了在Vivado SDK 2018.3环境下,从FSBL到Flash的完整bin文件烧写流程。通过环境准备、工程创建、关键代码修改、bin文件生成与合并技巧,以及烧写流程与调试技巧的全面解析,帮助开发者快速掌握Zynq芯片开发中的关键步骤,特别适合刚接触Xilinx平台的开发者。

yog99的博客 708

ext4 代码注释

int ext4_bio_write_page(struct ext4_io_submit *io, struct page *page, int len, struct writeback_control *wbc,

jxfccee的专栏 666

Ext2文件系统写数据流程及代码分析

完成了创建文件流程的介绍,下面就是向文件写数据了。今天我们主要介绍一些Ext2文件系统写数据的主要流程及核心代码。 为了便于理解Ext2文件系统写数据的流程,本文先从整个Linux文件系统的角度分析一下写数据的流程,因此本文包含了部分VFS内容介绍。本文主要包含2部分内容,一部分是从总体上介绍一个写流程是如何从用户态接口到Ext2文件系统的,另一部分是Ext2文件的数据在磁盘上组织及函数流程。 写文件的操作通常由用户态的程序发起,比如在开发的过程中调用系统API(write)。如图是从用户态发起一直到调

shuningzhang的专栏 398

读写文件的一些操作(write,writelines,file.seek,file.tell)

目录 1.创建文件 2. file.write(str)和file.writelines(str) 1.创建文件 file= open("path", 'w') #eg: file = open('/home/rui/文件名.txt', 'w') 通过绝对路径打开文件,如果不存在会重新创建一个文件;如果存在会覆盖原文件 2. 文件写入file.write(str)和file.writelines(sequence) file.write('hello,world') file.

weixin_62848630的博客 3369

VxWorks环境搭建与学习:vxworks6.8和workbench3.2

VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统(RTOS),是嵌入式开发环境的关键组成部分。良好的持续能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、航天等高精尖技术及实时性要求极高的领域中,如卫星通讯、军事演习、弹道制导、飞机导航等。

qq_41854911的博客 8468

多边形裁剪算法

多边形裁剪算法 刚参加工作就跟多边形刚上了,对于多边形的裁剪做一些简单的总结。 多边形裁剪主要有四种算法 Greiner-Hormann裁剪算法 Sutherland-Hodgman算法 Vatti裁剪算法 Weiler-Atherton裁剪算法 作为一名想要成为优秀算法工程师的程序员,我们不能只会使用,而不知道其原理,倘若如此,我们无法做到应用于本身业务上的定制化的修改。 Greiner–H...

papalqi 6728

【Python】文件

1--文件概念 。--计算机的文件,就是存储在某种长期存储设备上的一段数据 。--长期存储设备包括:硬盘、U盘、移动硬盘、光盘等 2--文件的作用 。--将数据长期保存下来,以便使用 3--文件的存储方式 。--在计算机中,文件是以二进制的方式保存在磁盘上的 。--文件分为文本文件和二进制文件 。--文本文件 --可以使用文本编辑器软件查看 --本质上还是二...

qq_38930129的博客 1070

Keil MDK编译错误#541解决方案与ARM_Compiler包解析

在嵌入式开发中,编译器工具链的依赖管理是确保项目顺利构建的关键环节。以Keil MDK为例,其软件包依赖机制通过组件化设计实现功能解耦,其中ARM_Compiler包专门处理系统IO重定向等编译器扩展功能。这种架构既提升了模块复用性,也带来了版本兼容性挑战。当出现'Error #541: component missing'报错时,通常是由于中间件组件(如文件系统)在新版本中显式依赖了ARM_Compiler包。开发者需要通过Pack Installer安装该包,并在Run-Time Environment

weixin_32129187的博客 363

linux设备驱动程序之简单字符设备驱动

一、linux系统将设备分为3类:字符设备、块设备、网络设备。使用驱动程序: 1、字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。 2、块设备:是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。   每一

bbs598598的专栏 1155

qmt量化交易策略小白学习笔记第67期【qmt编程之获取ETF申赎清单】

qmt编程之获取ETF申赎清单

fanglue3705的博客 1773

obdumper和obloader迁移OceanBase业务库(一):实施手册

⭐️ 要求导出一致性数据时,建议在导出数据前,手动触发一次合并,在合并成功后再重新导出数据。:统计业务数据库下的所有业务对象清单(表/索引/分区/包/存储过程/同义词/序列/…:检查业务数据库下的所有业务对象清单(表/索引/分区/包/存储过程/同义词/序列/…:统计单个模式下所有业务对象清单(表/索引/分区/包/存储过程/同义词/序列/…如果单张表的数据量太大,会导出为多个文件,文件命名会加上数字后缀。该过程会导出所有表的定义、以及定义在表上的索引定义。如果有多种数据库对象,会导出到不同的子路径下。

Sebastien23的博客 1024

Hadoop——8、hdfs写文件流程

Hadoop ——8、hdfs写文件流程

s_hizhi的博客 179

库存优化技术提升电商效率

第一部分:库存优化技术基础 第1章:库存优化的基本概念 库存优化是现代电商运营中至关重要的一个环节。简单来说,库存优化指的是通过一系列的策略和技术手段,使得库存管理更加高效、准确,从而降低运营成本,提高销售额。 1.1 库存优化的定义与重要性

AI天才研究院 1248

HDFS写文件流程

HDFS写文件流程 调用客户端的 DistributedFileSystem 的 create() 方法; DistributedFileSystem 会发起对 namenode 的一个RPC连接,请求创建一个文件,不包含关于 block 块的请求。 namenode 会执行各种各样的检查,保证要创建的文件不存在,并且客户端有创建文件的权限。如果检查通过, namenode 会创建一个文件(在edits中,同时更新内存状态),否则创建失败,客户端抛异常IOException。 Distribu

星茗 484

【DRAM存储器六十二】DDR5介绍--引脚和基本功能简介

详述DDR5与DDR4的引脚区别和DDR5基本功能

highman110的博客 523

基于Simulink环境,提供一个关于如何对无人机电源DC-DC变换器进行仿真建模的示例

无人机电源要求:无人机的各个子系统(如电机、传感器、通信模块等)可能需要不同级别的电压供应。重要性稳定性:稳定的电源是保证无人机各部件正常工作的基础。效率:高效的电源管理可以显著增加飞行时间和任务执行能力。挑战多负载适应性:需要能够为不同负载提供合适的电压和电流。动态响应:快速响应负载变化的能力对于维持系统稳定性至关重要。首先明确要模拟的任务内容。设计一个能够在不同负载条件下为无人机提供稳定电压的DC-DC变换器。根据无人机的工作状态调整控制策略以维持最佳性能。

xiaoheshang_123的博客 134

Hdfs架构,文件写流程

伪分布式的HDFS 的NN,DN,SNN都是部署在同一台机器上的。 HDFS的启动:./start-dfs.sh HDFS查看内容 hdfs dfs -ls 1.block的概念 hdfs默认一个block(块)是134217728个字节(128M),数据被切分以块为单位存储在不同的机器上, 举个例子 每个瓶子容量128ML 1碗水260ML 需要3个瓶子 A 128ml B 128ml C...

qq_36459386的博客 304

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

HDFS的写文件流程

这篇来分析一下HDFS写文件的流程. 首先还是客户端调用DistributedFileSystem类中的方法,写文件调用的是create(). public FSDataOutputStream create(......) throws IOException { statistics.incrementWriteOps(1); Path absF = fixRelativ...

bujiujie8的博客 677

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Spark开发详细流程之二:如何写Parquet文件?

package App; import org.apache.commons.lang3.time.FastDateFormat; import org.apache.hadoop.fs.Path; import org.apache.parquet.column.ParquetProperties; import org.apache.parquet.example.data.Group; import org.apache.parquet.example.data.simple.SimpleGroup

深入浅出讲透复杂深奥的问题 867

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

HDFS部分:HDFS写文件的流程和HDFS读取文件的流程【文字说明+图片】

HDFS作为分布式文件系统,使用的是master/slave体系结构,角色有三种: NameNode:为HDFS提供元数据服务,NameNode可以控制所有文件的操作,它会把所有的文件元数据存储在文件系统树中,文件信息在硬盘上保存成两个文件:命名空间镜像文件(fsimage)和修改日志文件(edit log)。此外,NameNode还保存一个文件,用来存储数据块在数据节点的分布情况。系统启动之时...

wyqwilliam的博客 2300

HDFS——写文件流程

上篇文章讲了数据传输的格式,本文就来说说hdfs中写文件的流程。hdfs客户端写文件的流程,大体可以分为两个步骤:第一步是创建或打开文件,第二步是进行block的写操作。block的写操作...

hncscwc的博客 2042

Hadoop 文件写流程

1)流程图    2)流程解读    1. 客户端执行命令(或者代码读取),调用的是dfs的create的方法,输入的是要上传的文件目录    2. NN会验证这个目录是否存在和是否有权限去创建。    3. 校验完成后,NN会创建一个空文件,还没有数据流和block映射关系,返回给一个FSDataOutputStream的对象    4. 客户端调用write方法,将数据流一个一个块地写入   ...

qq_30130043的博客 369

outputstream 写入文件_简述HDFS写文件流程

Hello,大家好: 今天和大家简单聊聊Hadoop中的HDFS的写文件流程,以上图为参考:1) HDFS客户端想要将数据文件写入到hadoop的HDFS中,首先需要创建于Hadoop的连接;2) 分布式文件系统通知NameNode,此时判断此次上传的是否有权限以及要上传的文件是否已经存在了? 如果没有权限或文件已经存在,则判定此次上传就失败了。如果满足上传条件,将文件的...

weixin_39636609的博客 434

hadoop写文件流程分析

1.主要概念1.1 NameNode(NN): HDFS系统核心组件,负责分布式文件系统的名字空间管理、INode表的文件映射管理。如果不开启备份/故障恢复/Federation模式,一般的HDFS系统就只有1个NameNode,当然这样是存在单点故障隐患的。NN管理两个核心的表:文件到块序列的映射、块到机器序列的映射。 第一个表存储在磁盘中,第二表在NN每次启动后重建。1.2 NameNode

liu812769634的博客 1829

文件写流程

上传 hdfs dfs -put ruozedata.log /user/hadoop/day01/ (把本地文件ruozedata.log复制上传到hdfs下的/user/hadoop/day01/ 的文件夹下面) 注释流程 Client调filesystem.create(path),与nn rpc通信,check path是否已经存在及有没有权限创建;(rpc通信是面试题)假如OK,...

Deng0_huakai 263
上一篇: 文件读写的理论
下一篇: 内存映射
OS技术解密
博客等级 码龄16年 3760粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值