linux内核分析--异步io(二)

简介:

该分析sys_io_submit函数了,这个函数有点复杂,但是条理很清晰,先说一句就是提交异步io,具体怎么提交呢?我们知道,对于异步io,一次性可以提交多个请求,那么可以想象的就是在sys_io_submit中会把我们用户程序的多个请求分解成一个一个的请求,依次提交,这是很合理的假设,内核实际上也是这么做的,刚才的建立异步io的阶段只是建立了一个可以让异步io表演的大的环境,现在的提交请求和将来的读取数据便是大戏了,准备好了吗?马上开演!

asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr
struct iocb __user * __user *iocbpp) 

struct kioctx *ctx
long ret = 0; 
int i
if (unlikely(nr < 0)) 
return -EINVAL
if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) 
return -EFAULT
ctx = lookup_ioctx(ctx_id);//这里查找我们刚才建立的kioctx 
if (unlikely(!ctx)) { 
… 
for (i=0; i<nri++) {//这个循环实质上分解了用户请求 
struct iocb __user *user_iocb; 
struct iocb tmp
if (unlikely(__get_user(user_iocb, iocbpp + i))) { 
ret = -EFAULT
break; 

if (unlikely(copy_from_user(&tmp, user_iocb, sizeof(tmp))))

… 
ret = io_submit_one(ctx, user_iocb, &tmp);//一次提交一个,直到全部提交完毕 
if (ret) 
break; 

put_ioctx(ctx); 
return i ? i : ret; 
}

上面的函数提到了查找kioctx结构,这个函数猜也能猜到怎么实现的,就是在进程的mm中的ioctx_list中寻找id和sunmit参数的id相 同的kioctx,说了半天,到底什么是kioctx,它到底有什么用?它实际上正如前面说的那样,是一个大舞台,提供了一个工作体,提供了一个运行队列 等等,所有属于这个大舞台的请求必须纳入它的管理范畴,它的字段决定了谁应该被调度,以及调度后应该做甚。下面来看看完成实际工作的io_submit_one函数:

1476 int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, 
struct iocb *iocb

struct kiocb *req
struct file *file
ssize_t ret; 
/* enforce forwards compatibility on users */ 
if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 || 
… 
/* prevent overflows */ 
if (unlikely
(iocb->aio_buf != (unsigned long)iocb->aio_buf) || 
(iocb->aio_nbytes != (size_t)iocb->aio_nbytes) || 
((ssize_t)iocb->aio_nbytes < 0) 
)) { 
… 
file = fget(iocb->aio_fildes); 
req = aio_get_req(ctx); /* returns with 2 references to req */ 
if (unlikely(!req)) { 
… 
req->ki_filp = file
ret = put_user(req->ki_key, &user_iocb->aio_key); 
if (unlikely(ret)) { 
dprintk("EFAULT: aio_key/n"); 
goto out_put_req; 

req->ki_obj.user = user_iocb; 
req->ki_user_data = iocb->aio_data; 
req->ki_pos = iocb->aio_offset; 
req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf; 
req->ki_left = req->ki_nbytes = iocb->aio_nbytes; 
req->ki_opcode = iocb->aio_lio_opcode; 
init_waitqueue_func_entry(&req->ki_wait, aio_wake_function);//注册唤醒时的回调函数 
INIT_LIST_HEAD(&req->ki_wait.task_list); 
req->ki_retried = 0; 
ret = aio_setup_iocb(req);//设置retry回调函数 
if (ret) 
goto out_put_req; 
spin_lock_irq(&ctx->ctx_lock); 
aio_run_iocb(req);//首先先执行一次,没准一次就能成功,要不怕做无用功,内核真是精打细算啊 
if (!list_empty(&ctx->run_list)) { 
/* drain the run list */ 
while (__aio_run_iocbs(ctx))//如果当前异步上下文的运行队列有请求,执行之! 


spin_unlock_irq(&ctx->ctx_lock); 
aio_put_req(req); /* drop extra ref to req */ 
return 0; 
… 

我们来看看aio_run_iocb函数,实际上__aio_run_iocbs(ctx)最终也是要调用aio_run_iocb函数的: 
static ssize_t aio_run_iocb(struct kiocb *iocb

struct kioctx *ctx = iocb->ki_ctx; 
ssize_t (*retry)(struct kiocb *); 
ssize_t ret; 
if (iocb->ki_retried++ > 1024*1024) { 
… 

if (!(iocb->ki_retried & 0xff)) { 

if (!(retry = iocb->ki_retry)) { 
… 

kiocbClearKicked(iocb); 
iocb->ki_run_list.next = iocb->ki_run_list.prev = NULL
spin_unlock_irq(&ctx->ctx_lock); 
/* Quit retrying if the i/o has been cancelled */ 
if (kiocbIsCancelled(iocb)) { 
… 

BUG_ON(current->io_wait != NULL); 
current->io_wait = &iocb->ki_wait;//以下3行很重要,如果当前请求未果,则可能睡眠在io_wait,当被唤醒的时候执行aio_wake_function 
ret = retry(iocb); 
current->io_wait = NULL
if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) { 
… 


注意aio_wake_function是唤醒回调函数,这个函数本质上也是执行将上下文挂入工作队列的任务,为什么呢?为何不让它直接把任务完成呢?因为它可能在中断上下文中,这又很多限制,比如不能睡眠,于是乎就把任务挂入一个工作队列,这样就有了进程的上下文,一切变得明朗!到这基本上就完事了,不用用户进程操心了,到了实在闲来无事的时候来取数据吧!如果实在觉得这篇文章到此意尤未尽,那么请看《linux工作队列和异步io 》下面将要进行的就是取数据了。一会回来,更精彩!



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1274055

相关文章
|
6天前
|
算法 Linux 调度
深入理解Linux内核调度器:从基础到优化####
本文旨在通过剖析Linux操作系统的心脏——内核调度器,为读者揭开其高效管理CPU资源的神秘面纱。不同于传统的摘要概述,本文将直接以一段精简代码片段作为引子,展示一个简化版的任务调度逻辑,随后逐步深入,详细探讨Linux内核调度器的工作原理、关键数据结构、调度算法演变以及性能调优策略,旨在为开发者与系统管理员提供一份实用的技术指南。 ####
26 4
|
9天前
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
30 6
|
8天前
|
缓存 资源调度 安全
深入探索Linux操作系统的心脏——内核配置与优化####
本文作为一篇技术性深度解析文章,旨在引领读者踏上一场揭秘Linux内核配置与优化的奇妙之旅。不同于传统的摘要概述,本文将以实战为导向,直接跳入核心内容,探讨如何通过精细调整内核参数来提升系统性能、增强安全性及实现资源高效利用。从基础概念到高级技巧,逐步揭示那些隐藏在命令行背后的强大功能,为系统管理员和高级用户打开一扇通往极致性能与定制化体验的大门。 --- ###
29 9
|
7天前
|
缓存 负载均衡 Linux
深入理解Linux内核调度器
本文探讨了Linux操作系统核心组件之一——内核调度器的工作原理和设计哲学。不同于常规的技术文章,本摘要旨在提供一种全新的视角来审视Linux内核的调度机制,通过分析其对系统性能的影响以及在多核处理器环境下的表现,揭示调度器如何平衡公平性和效率。文章进一步讨论了完全公平调度器(CFS)的设计细节,包括它如何处理不同优先级的任务、如何进行负载均衡以及它是如何适应现代多核架构的挑战。此外,本文还简要概述了Linux调度器的未来发展方向,包括对实时任务支持的改进和对异构计算环境的适应性。
26 6
|
8天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
26 5
|
8天前
|
算法 Unix Linux
深入理解Linux内核调度器:原理与优化
本文探讨了Linux操作系统的心脏——内核调度器(Scheduler)的工作原理,以及如何通过参数调整和代码优化来提高系统性能。不同于常规摘要仅概述内容,本摘要旨在激发读者对Linux内核调度机制深层次运作的兴趣,并简要介绍文章将覆盖的关键话题,如调度算法、实时性增强及节能策略等。
|
9天前
|
存储 监控 安全
Linux内核调优的艺术:从基础到高级###
本文深入探讨了Linux操作系统的心脏——内核的调优方法。文章首先概述了Linux内核的基本结构与工作原理,随后详细阐述了内核调优的重要性及基本原则。通过具体的参数调整示例(如sysctl、/proc/sys目录中的设置),文章展示了如何根据实际应用场景优化系统性能,包括提升CPU利用率、内存管理效率以及I/O性能等关键方面。最后,介绍了一些高级工具和技术,如perf、eBPF和SystemTap,用于更深层次的性能分析和问题定位。本文旨在为系统管理员和高级用户提供实用的内核调优策略,以最大化Linux系统的效率和稳定性。 ###
|
8天前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
8天前
|
缓存 运维 网络协议
深入Linux内核架构:操作系统的核心奥秘
深入Linux内核架构:操作系统的核心奥秘
24 2
|
10天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####