-
Categories
Archives
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- March 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- July 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- August 2009
- June 2009
- May 2009
- April 2009
- March 2009
- December 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- November 2007
- August 2007
Meta
-
Author Archives: tek-life
配置wsgi运行环境
我想用python写web. 之前最拿手的应该是用asp写,后来,学了php。总感觉,用这些脚本写网站,不太geek。所以,就摸索着用python写。 昨天,申请了支持python的SAE,其安装手册上的例子是用wsgi跑一个helloworld. 我对这些东西还不懂,纯菜鸟。SAE用的版本系统是svn,蛋疼的很。每次svn ci的时候,总感觉很不习惯,不如git那样舒服。 so.想在local上学习python web开发。python写web方式有很多,因为SAE上支持WSGI,所以,就先玩玩WSGI吧。可是在配置WSGI方面,网上有很多垃圾文章,明明很简单的东西,非要再加个Django,而我只是想运行个hello world而已,用不上这么厚重的东西。 下面是配置总结,整个过程比较简单: 依次安装apache2和libapache2-mod-wsgi后,我还安装了libapache2-mod-wsgi-py3. 然后,在/etc/apache2/mods-enabled/下面应该能够看到俩个文件: wsgi.conf wsgi.load 然后在/etc/apache2/apache2.conf结尾加上: 231 <Directory /var/www/> 232 order deny,allow 233 Allow from all 234 </Directory> 235 WSGIScriptAlias / /var/www/index.wsgi 于是,就OK了。这个时候,怎么测试是OK的呢?我们先重启apache2,然后写个简单的hello world程序。 重启apache2: $sudo /etc/init.d/apache2 restart Hello world程序: 在/var/www/下 … Continue reading
Posted in Web Dev
Leave a comment
SD卡读写操作浅析
一个读写请求何时被读写,怎样读写,全看请求队列。以Goldfish平台上的MMC卡,我们来看看其请求队列都怎样设置的: mmc_blk_probe() 597 struct mmc_blk_data *md; 598 int err; 599 600 char cap_str[10]; 601 602 /* 603 * Check that the card supports the command class(es) we need. 604 … Continue reading
Posted in File System
Leave a comment
从Nand驱动到文件读写
Nand属于块设备。那么nand块设备是否像其他块设备那样,每次读写都经历一个“C/S”的过程呢? 我们在Goldfish Platform上,从nand的驱动注册开始,看看nand之上的yaffs2文件读写到底是怎样的一个过程。 本文主要是对自己在学习过程中遇到疑问做一个记录,同以前的文章一样,基本上只有流程,那些原理之类的东西,请同学们google吧。在下文中,有些代码可能会有重复,主要目的是不想让各位看官看的太累,跳来跳去,眼镜受不了啊。 代码是Android Kernel 2.6.29.整个记录过程比较仓促,难免会由认识上的错误,欢迎大家指正。 下面是Android在Goldfish Platform上的执行流程: <1> 377 static int __init init_mtdblock(void) 378 { 379 return register_mtd_blktrans(&mtdblock_tr); 380 } 在代码片段<1>中注册了一个struct mtd_blktrans_ops结构的mtdblock_tr,这个模块是系统在启动过程中加载的,从模块的init名字,可以看出,是针对mtd块设备的。由于在Linux中,Nand被归为MTD设备,MTD设备就是将nand设备封装了一下,让上层没有直接看到nand,而是看到的MTD。实际上,通过MTD来操作Nand,还是通过nand内部的驱动函数。不要把MTD看的太过神秘。如果还需要了解,请Google吧,我之前就是太较真了,一直没有弄明白,read the fucking code之后才算明白过来了。 这个mtd_blktrans_ops结构如下: <2> 32 struct mtd_blktrans_ops { 33 char *name; 34 int major; 35 … Continue reading
Posted in File System
4 Comments
SD卡读写流程
本流程分析针对2.6.29Kernel on Goldfish Platform. SD卡的读写操作同其他块设备一样,都是异步的过程。当进程把request发到块设备请求队列后,在真正读写时,mq->thread进程会被激活。这个进程准确说属于内核线程,其函数执行主体如下: 44 static int mmc_queue_thread(void *d) 45 { 46 struct mmc_queue *mq = d; 47 struct request_queue *q = mq->queue; 48 49 current->flags |= PF_MEMALLOC; 50 51 down(&mq->thread_sem); 52 do { 53 struct request *req = … Continue reading
Posted in File System
Leave a comment
文件读写,从请求到IO启动
在Linux中,块设备的读写是一个比较复杂的过程。如果再加上VFS的话,层次就更多了。实际上VFS和块设备驱动联系的不是非常密切。在VFS中,我们会看到当发生读写请求的时候,会调用ll_rw_block函数或者submit_bh函数,其中ll_rw_block是对submit_bh的封装。这个函数,实际上就是从VFS到实际设备读写的必经之路。关于这一点,有很多用systemtap来观测io的脚本就是在submit_bh函数安装一个stub(有关io检测的相关的文章,可以参看淘宝的大牛诸霸的博客)。 在这里,我们不再谈论VFS的东西,而是从submit_bh开始看起,然后到数据被读出,进程又继续执行的流程。 submit_bh的功能正如其函数的名字那样–“提交buffer head”。那么,具体提交给谁呢?由谁来提交呢?其实块设备的读写似乎是一个C/S架构的服务器。客户端是各个进行io操作的进程,服务器端就是设备的请求队列。进程把请求的信息包装成一个request的数据结构,然后,挂载在服务端,即块设备的请求队列中。我前面说的那句话“似乎是一个C/S架构的”,而不是真正C/S架构的。因为,C/S架构来源于网络程序,客户端进程把数据发往正在监听的服务端,然后服务端的进程从网络缓冲区中经过网络协议的层层解压“剥皮”,拿到数据。而我们谈论这个文件数据的读写并不真正是C/S架构的,原因就是,客户端的发送和服务端的接收请求全由一个进程,即用户进程来完成的。这一点应该很好理解,因为在OS中,除了中断以及异常处理没有上下文外,其他的都有进程上下文,因此,从submit读写请求到接收读写请求,当然就是进程自己的事情了,当然,如果你要是抬杠“在内核中完全可以由一个专门的线程用来处理服务端的事情”,我也无话可说。原理上,你这个抬杠当然是行得通的。说到这里,我想起了微内核的MINIX,就此打住,继续回到他们的处理过程中。 当用户进程提交请求,并挂载到块设备队列的过程中,还涉及一个IO调度的问题,即是,用户进程在提交一个请求时,遇到了调度算法,这个调度算法做的事情很简单,它检查这个请求和正在排队的请求能否合二为一。如果不能合二为一,那就直接挂上去。至此,一个进程所要做的工作基本上就结束了。可是,请求被相应的时机呢?什么时候,它的请求才能满足? 我们清楚,一个硬件设备,特别是块设备,让它来读取数据然后内核再从端口里面把数据提出来,或者说,通过DMA的方式,直接从磁盘中拿到数据,这个数据读出来的过程是很漫长的,这个漫长是相对于CPU来说的,绝对时间其实是很短暂的。一般情况下,用户进程在往块设备的请求队列上挂请求的时候,发现队列为空的话,会将该队列插入到一个全局的队列中(tq_disk,从名字中,我们也能够看出来是task queue for disk的缩写)。如果队列不为空,那么说明该队列已经加入到tq_disk的全局队列中了,既然该块设备的读写请求队列不为空,那么要利用调度策略,看时候能够和正在该块设备上排队的读写请求和二为一了。这里有一个很恰当的比方:当我们去饭店吃饭的时候,如果你要点的菜如果和师傅正在炒或者准备炒的菜一样的话,炒菜师傅会把两个人点的菜一块炒,特别是学校的食堂,每到吃饭高峰期,人很多,因此,学生们一般都会问服务员,下面要做的是什么菜,如果要节省时间的话,就要师傅下面要炒的菜了。在这里,磁盘的调度原理就是这个样子,貌似很简单哇。其实,有些时候,我们可能并不需要一个请求队列,比如,将来计算机的磁盘全部是SSD了,不再用机械磁盘了,都是电读写的,那么这个IO调度说不定就要被废除了。然后,也就不再需要请求队列了。一个请求到了,然后马上就发送到驱动程序,驱动程序想设备发送命令,读取数据。而在Linux的内核中,已经考虑到这一点了,如果进程进行同步IO的话,就直接启动驱动程序进行IO读写了(请参考代码段一)。 前面说到,将读写请求挂载在块设备的请求队列时,如果不为空的话,会看能否进行IO调度,不能调度的话,会向块设备请求队列插入一个请求。然后进程的任务就完成了。如果插入请求的时候,发现这个队列上的请求非常多,那么怎么办呢?进程就会主动的启动磁盘IO让这些请求队列赶紧执行(请参考代码片段二)。 上面设计到的进程启动磁盘IO,都算是主动的。除了主动的时候,还有被动的情况。当进程将请求挂载在块设备请求队列的时候,它是要用其中的数据的。什么时候用呢?该用的时候就用呀,不过用的时候,会检测相关的数据是否被读出了,如果没有读出,那么进程就被阻塞,然后启动磁盘IO(请参考代码片段三)。这一点在Linux2.6的内核中稍微进行了改进,设置了一个request数量阈值,如果大于这个阈值,那么就启动磁盘IO。 在Linux2.6的内核中,还增加了一个启动IO磁盘的时机,即,读写请求被插入到某个块设备的请求队列时,设置了一个定时器,保证在某个时间点之内,一定要启动磁盘IO。 启动磁盘IO后,数据怎么读出就跟进程没什么关系了。进程在使用的时候,就会查看它要用的buffer缓冲区是否locked,如果否,就说明已经读好了,如果是,那么就继续启动磁盘然后等待(代码片段三)。 以上基本上就分析完了。在2.6的内核中,在request和buffer head中又加了一个bio,不过仅仅加了个bio并不影响理解。另外,单单看块设备驱动,并不能够解决读写请求发送到块设备请求队列,然后块设备又怎样的把读写的数据读入到buffer中。当然了,在这一个南大富士通的赵磊大牛写过一个系列的文章“写一个块设备驱动”,一共120页。对我的帮助还是蛮大,当初凌晨看到2点半,然后又加上一个上午,基本上算是一口气看完了。写得不错,希望对块设备驱动有兴趣的同学,可以google一下,看看。 注:本文还非常naive,错误难免,如果发现,请批评指正。 附件:参考2.4.31内核 代码片段一: submit_bh->__make_request 1000 static int __make_request(request_queue_t * q, int rw, 1001 struct buffer_head * bh) 1002 { 1003 unsigned int sector, count, … Continue reading
Posted in File System, Linux Kernel
Leave a comment