September 20, 2012 / ArchLinux, Chinese, filename, messy, utorrent

晚上看师弟机器上的新版utorrent的界面看起来比我机器上的友好,于是用yaourt utorrent安装了新版的utorrent(aur/utserver 27079-1),安装很顺利,安装完成后修改/etc/conf.d/utserver文件中的以下内容: 将utserver换成我的用户名,然后运行以下命令启动utserver: 然后在浏览器输入地址http://127.0.0.1:8080/gui/,很正常,修改下载目录和临时目录。找了几个种子进行试验,界面能显示中文信息,也能正常下载,下载完成后,发现问题来了:文件名中的中文字符全成了问号(???)?好像很久很久之前也遇到这个问题,但忘了怎么解决,只悔当时没做笔记。 接着,逐步排查问题,先看看utserver的日志文件/var/log/utserver/utserver.log,发现第一行如下所示: 这样原因就很明确了,locale没设置正确,utserver启动后,我期望能看到的第一条日志是下面这样: 有目标就好办了,首先,我尝试在命令行运行utserver,我所期待的结果出现了,进一步确定是运行后台daemon时locale没设置正确,与该问题相关的是/etc/rc.conf配置文件中的两个环境变量: DAEMON_LOCALE="yes" 如果DAEMON_LOCALE设置为“yes”,那么运行daemon时使用LOCALELOCALE为空,使用locale C;如果DAEMON_LOCALE设置为“no”,使用locale C。但是我的/etc/rc.conf配置文件没有问题。 接着我想是不是应该在运行utserver时设置环境变量LANG,于是在/etc/conf.d/utserver文件中添加以下内容: 发现不奏效,最后只能去看/etc/rc.d/utserver这个脚本里的内容,内容不多, 很快就将目标锁定到下面这条命令: 这条命令的作用是切换到$UTSERVER_USER这个用户,利用/bin/sh来运行utserver,那问题就应该出在切换用户后locale没正确设置,于是我将命令改为: su -l -s /bin/sh -c “export LANG=en_US.UTF-8; /usr/bin/utserver $UTSERVER_ARGS >/dev/null 2>&1” $UTSERVER_USER 重新启动utserver,我所期待的结果出现了,至此,问题解决了。 在Linux系统上,出现各种问题是很正常的现象,在这种情况下不要慌,先查看日志,寻找解决之道,也可以上Google搜索已观察到的现象,看看别人是如何解决我们所遇到的问题。

read more »

前提 Hadoop版本:hadoop-0.20.2 概述 在上一篇文章中HDFS源码分析(9):DFSClient初步介绍了HDFS客户端的相关内容,但由于篇幅关系,没有对HDFS的输入/输出流进行介绍,而这正是本文的重点。数据的读取和写入是客户端最重要的功能,也是最主要的逻辑,本文将分成输入和输出两部分对HDFS的文件流进行分析。主要的类位于org.apache.hadoop.hdfs.DFSClient类中。 DFSInputStream DFSInputStream的主要功能是向namenode获取块信息,并且从datanode读取数据,但涉及到的问题也不少:一个文件被分割成多个块,每个块可能存储在不同的datanode;如果一个datanode挂了,要尝试另一个datanode;文件损坏了……因此,我们必须仔细地进行分析,那么,当要在客户端添加或修改功能时才不至于无从下手。 先来看看类图,从总体上把握类之间的关系,由于类比较多,所以略去了不少类,只剩下一些重要的类,因此下面的类图并不完整: DataChecksum这个类的说明可见HDFS源码分析(5):datanode数据块的读与写。 1. FSInputChecker FSInputChecker是一个通用的输入流,继承FSInputStream,用于在返回数据给用户之前校验数据checksum。关键的属性有如下这些: file:读取的数据所在的文件 buf:数据缓冲区 checkum:checksum缓冲区 pos:数据缓冲区的当前位置 count:数据缓冲区中数据的长度 chunkPos:输入流的位置 为了做得更通用,有两个与具体的实现细节相关的抽象方法将由子类去实现: readChunk: 从文件中读取一个chunk放到数据缓冲区,并把该chunk的checksum放到checksum缓冲区 getChunkPosition:得到包含位置pos的chunk的起始位置 剩下的比较重要的操作有read、skip和seek。 read操作有两种方式:一种是一次只读取一个字节,只需要从缓冲区中读出一个字节即可,如果缓冲区空了,就从输入流中读取一批数据到缓冲区;一种是一次读取多个字节,并把数据存到用户缓冲区,会重复调用更底层的读取方法来读取尽可能多的数据。 无论是使用哪种方式的read方法,都会调用readChecksumChunk这个方法。readChecksumChunk方法又会进一步调用readChunk来从输入流中读出chunk和checksum,如果需要,可以对checksum进行验证,如果读数据失败,可以尝试另一副本,重新读取数据。 skip操作会从输入流中跳过和忽略指定数量的字节,在实现上调用了seek操作。 如果seek的位置所在的chunk在当前缓冲区内,那么只要修改当前的位置pos即可;否则需要重新计算chunkPos,并跳过从chunk起始位置到指定位置之间的数据。 2. BlockReader BlockReader继承FSInputChecker,封装了Client和Datanode之间的连接,知道块的checksum、offset等信息。关键的属性有如下这些: in:数据输入流 checksum: lastChunkOffset:最后一个读取的chunk的偏移量 lastChunkLen:最后一个读取的chunk的长度 lastSeqNo:最后一个packet的编号 startOffset:欲读取数据在块中的偏移量 firstChunkOffset:读取的第一个chunk在块中的偏移量 bytesPerChecksum:chunk的大小 checksumSize:checksum的大小 isLastPacket:是否是最后一个packet BlockReader覆盖了父类的很多方法,但不支持seekToNewSource、seek、getChunkPosition及读取单个字节。 首先,我们来看看如何创建一个新的BlockReader实例,所做的事情其实很简单,只是向datanode请求一个OP_READ_BLOCK操作,如果操作成功,那么创建一个数据输入流并根据返回的数据创建一个DataChecksum实例。 read方法只比FSInputChecker多了一些检查。在读取第一个chunk时,可能需要跳过startOffset之前的一些字节。如果到了块的结尾并且需要验证checksum,要向datanode发送OP_STATUS_CHECKSUM_OK,以确认块未损坏。 skip方法通过读取当前位置到目标位置之间的字节来路过这些数据,而不是调用seek。 好了,只剩下最重要的readChunk方法: 如果到达块结尾,将startOffset置为-1,返回-1 计算新chunk的偏移量 如果前一个包的数据已读取完毕,读取下一个packet的头部及checksum 从输入流中读取一个chunk,多缓冲区中读出该chunk的checksum 如果当前packet是最后一个并且当前packet的数据已全部读完,将gotEOS置为true,标志着到达块结尾 3. DFSInputStream 经过前面的预热,我们可以正式进入输入流的主题,DFSInputStream从文件中读取数据,在必要时与namenode和不同的datanode协商。关键的属性有如下这些: closed:流是否已关闭 src:文件 prefetchSize:从namenode预取数据的大小,默认是10个块,可以通过配置项dfs.read.prefetch.size来设置 blockReader:用于读取块的数据 verifyChecksum:是否验证数据的checksum locatedBlocks:存储块的信息 currentNode:当前读取数据的datanode

read more »
July 26, 2012 / DFSClient, Hadoop, HDFS

前提 Hadoop版本:hadoop-0.20.2 概述 在上一篇文章中HDFS源码分析(8):FileSystem已对Hadoop的文件系统接口进行了简单的介绍,相信读者也能猜到HDFS会对外提供什么样的接口。为了让读者对HDFS有个总体的把握,本文将对DistributedFileSystem和DFSClient进行分析,这两个类都位于包org.apache.hadoop.hdfs下。 好了,废话不多说,真奔主题吧。 DistributedFileSystem DistributedFileSystem是用于DFS系统的抽象文件系统的实现,继承自FileSystem,用户在使用HDFS时,所使用的文件系统就是该实现。但是DistributedFileSystem的实现并不复杂,没有过多的逻辑,大部分方法会间接调用DFSClient的方法,使DFSClient能兼容Hadoop的FileSystem接口,从而能在Hadoop系统中工作,这不就是设计模式中的Adapter(适配器)模式吗? 我们先来看看与DistributedFileSystem相关的类图,由于涉及到的类繁多,因此只列出关键类的属性和方法,其它的类只有类名: 从上图可以看出依赖或关联的类基本是HDFS中通用的类和org.apache.hadoop.fs包下的与文件系统相关的类,DistributedFileSystem的大部分方法会调用DFSClien对应的方法,待下方分析DFSClient时再进行介绍。 先来看看类的初始,在静态初始化块中加载了hdfs-default.xml和hdfs-site.xml配置文件,其中包含了namenode的信息以及一些与HDFS相关的参数;在初始化对象时,从uri中得到namenode地址,设置默认工作目录为用户目录。 有三个方法频繁被其它方法调用: checkPath,检查路径的scheme、port和authority,允许显式指定默认端口的路径; makeQualified,归一化显式指定默认端口的路径; getPathName,检查路径的合法性,并将相对路径转换成绝对路径。 DFSClient DFSClient是一个真正实现了客户端功能的类,它能够连接到一个Hadoop文件系统并执行基本的文件任务。它使用ClientProtocol来和NameNode通信,并且使用Socket直接连接到DataNode来完成块数据的读/写。Hadoop 用户应该得到一个DistributedFileSystem实例,该实现使用了DFSClient来处理文件系统任务,而不是直接使用DFSClient。 我们先来看看与DFSClient相关的类图,由于涉及到的类繁多,因此只列出关键类的属性和方法,其它的类只有类名: 看着上图这么多类,一下子就没有头绪,先来看看DFSClient一些重要的属性: MAX_BLOCK_ACQUIRE_FAILURES:块最大请求失败次数,值为3 TCP_WINDOW_SIZE:TCP窗口的大小,值为128KB,在seek操作中会用到,假如目标位置在当前块内及在当前位置之后,并且与当前位置的距离不超过TCP_WINDOW_SIZE,那么这些数据很可能在TCP缓冲区中,只需要通过读取操作来跳过这些数据 rpcNamenode:通过建立一个RPC代理来和namenode通信 namenode:在rcpNamenode基础上封装了一个Retry代理,添加了一些RetryPolicy leasechecker:租约管理,用于管理正被写入的文件输出流 defaultBlockSize:块大小,默认是64MB defaultReplication:副本数,默认是3 socketTimeout:socket超时时间,默认是60秒 datanodeWriteTimeout:datanode写超时时间,默认是480秒 writePacketSize:写数据时,一个packet的大小,默认是64KB maxBlockAcquireFailures:块最大请求失败次数,默认是3,主要用于向datanode请求块时,失败了可以重试 DSClient的属性主要是在初始化对象时设置,其中涉及到几个参数,如下所示: dfs.socket.timeout:读超时 dfs.datanode.socket.write.timeout:写超时 dfs.write.packet.size:一个的packet大小 dfs.client.max.block.acquire.failures:块最大请求失败次数 mapred.task.id:map reduce的ID,如果不为空,clientName设置为“DFSClient_”,否则clientName设置为“DFSClient_” dfs.block.size:块大小 dfs.replication:副本数 接下来,可以来看看DFSClient的方法,笔者发现很多方法是通过RPC调namenode的方法,这些方法不需赘述了,相信读者都能看出要实现什么操作,下面着重说一下部分方法: checkOpen:这个方法被频繁调用,但过程很简单,只是检查一下clientRunning的值 getBlockLocations:由于从namenode得到的所有块以LocatedBlocks来描述,那么需要从LocatedBlocks从提取出每个块及拥有该块的datanode信息,并以BlockLocation来描述每个块,最后返回的是BlockLocation数组 getFileChecksum:得到文件的checksum,过程稍微复杂了一点 得到文件所有块的位置 对于每个块,向datanode请求checksum信息,返回的信息中包括块的所有checksum的MD5摘要,如果向一个datanode请求失败,会向另一datanode请求 将所有块的MD5合并,并计算这些内容的MD5摘要 bestNode:挑选一个不在deadNodes中的节点 HftpFileSystem HftpFileSystem是一种用于通过HTTP方式访问文件系统的协议实现,该实现提供了一个有限的、只读的文件系统接口。 实现时,HftpFileSystem通过打开一个到namenode的HTTP连接来读取数据和元信息,主要支持三种操作: open:向namenode发出http请求,地址是/data/path/to/file,并带有查询串,形式如query1=val1&query2=val2,相信了解http协议的GET方法肯定不觉得陌生 listStatus和getFileStatus:都是向namenode发出http请求,地址是/listPaths/path/to/file getFileChecksum:向namdenode发现http请求,地址是/fileChecksum/path/to/file HftpFileSystem的工作目录是根目录,不能设置根目录,不支持append、create、rename、delete、mkdirs等操作。 还有一个HsftpFileSystem类,继承自HftpFileSystem,通过https与namenode连接,需要建立ssl。 类图如下: 后记 关于文件的输入流和输出流,敬请关注下一篇文章。 文中若有错误或疏漏之处,烦请批评指正。

read more »
July 14, 2012 / filesystem, Hadoop, HDFS

前提 Hadoop版本:hadoop-0.20.2 概述 之前已对HDFS的datanode部分的源码进行了分析,还剩client和namenode这个最最重要的部分,本着从简单入手,打算继续把namenode当成是一个黑盒,先分析client的代码,毕竟client的代码行数与namenode相比要少得多。 很粗地把client的代码浏览了一下,发现client暴露给用户的接口是DistributedFileSystem这个东东,该类实现了FileSystem这个通用文件系统的抽象类。FileSystem位于core中,并不是HDFS专用的,先对FileSystem进行分析,有助于从宏观上去剖析DFS。 本以为把FileSystem这个类的代码看一遍应该就差不多了,看着看着才发觉FileSystem这个类好庞大、关联依赖的类好多,从下面的类图就可以看出来。虽说类多、方法多,但逻辑相对简单,比较容易理解。 本文所涉及到的类的包结构如下: org.apache.hadoop.fs BlockLocation ContentSummary FileChecksum FileSystem FileStatus FSDataInputStream FSDataOutputStream FSPermission GlobExpander Path PositionedReadable Seekable Syncable org.apache.hadoop.fs.permission FsAction FsPermission 下面将简单介绍几个重要的类。 FileSystem 上文已说过FileSystem是一个通用文件系统的抽象基类,它可能被实现为分布式文件系统或本地文件系统。 先来看其重要成员: CACHE: 静态成员,对打开的文件系统实例做cache,在计算机领域里面,cache是非常重要的,做文件系统怎么能少得了它呢! statisticsTable: 静态成员,保存各文件系统实例的统计信息 key: 文件系统实例在CACHE中的键 statistics: 文件系统实例在读写统计 deleteOnExit: 退出时需要删除的文件,这个功能很实用,Java里的文件也有这么个功能 clientFinalizer: 一个线程,用于在退出时关闭所有缓存的文件系统 从其成员,我们可以看到FileSystem有两个功能:缓存和统计。 下面我们来瞧瞧FileSystem的方法,总共有70多个,够吓人的,不过不能被吓倒了,要硬着头皮去看看究竟在做些什么事情,传统的文件系统里都会有的创建目录、创建文件、打开文件、列举目录的文件、重命名文件、关闭文件等功能都覆盖到,除此还有其它一些重要的方法: getFileBlockLocations: 取得文件中某个区域的内容所在块(可能会存储在多个块中)的位置 exists: 检查路径是否存在 isFile: 检查给定路径是否是一个文件 getContentSummary: 取得给定路径的统计情况,包括文件总大小、文件数目和目录数目,会递归统计子目录的情况 listStatus: 如果给定路径是目录,列举该目录的文件和子目录的状态 globStatus: 返回匹配特定模式的所有文件,跟Linux的命令行很像,可以使用通配来扩展 getHomeDirectory: 取得用户的主目录 *etWorkingDirectory: 设置和取得当前工作目录 copyFromLocalFile:

read more »
July 5, 2012 / Driver, Linux, Reading Note, TTY

简介 tty设备的名称是从过去的电传打字机缩写而来,最初是指连接到Unix系统上的物理或虚拟终端 Linux tty驱动程序的核心紧挨在标准字符设备驱动层之下,并提供了一系列的功能,作为接口被终端类型设备使用 有三种类型的tty驱动程序:控制台、串口和pty /proc/tty/drivers 当前注册并存在于内核的tty设备在/sys/class/tty下都有自己的子目录 小型TTY驱动程序 <linux/tty_driver.h> struct tty_driver tiny_tty_driver = alloc_tty_driver(TINY_TTY_MINORS); static struct tty_operations serial_ops = {.open=tiny_open, .close=tiny_close, .write=tiny_write, .write_room=tiny_write_room, .set_termios=tiny_set_termios,} tiny_tty_driver->owner=THIS_MODULE; tiny_tty_driver->driver_name=“tiny_tty”; tiny_tty_driver->name=“ttty”; tiny_tty_driver->devfs_name=“tty/ttty%d”; tiny_tty_driver->major=TINY_TTY_MAJOR; tiny_tty_driver->type=TTY_DRIVER_TYPE_SERIAL; tiny_tty_driver->subtype=SERIAL_TYPE_NORMAL; tiny_tty_driver->flags=TTY_DRIVER_REAL_RAW|TTY_DRIVER_NO_DEVFS; tiny_tty_driver->init_termios=tty_std_termios; tiny_tty_driver->init_termios.c_cflag=B9600|CS8|CREAD|HUPCL|CLOCAL; tty_set_operaions(tiny_tty_driver, &serial_ops); retval = tty_register_driver(tiny_tty_driver); for (i=0;i<TINY_TTY_MINORS; ++i) tty_unregister_device(tiny_tty_driver, i); tty_unregister_driver(tiny_tty_driver); termios结构 用来提供一系列安全的设置值 struct termios tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_c c_lflag; cc_t c_line;

read more »
July 5, 2012 / Driver, Linux, network, Reading Note

简介 网络接口是第三类标准Linux设备,本章将描述网络接口是如何与内核其余的部分交互的 网络接口必须使用特定的内核数据结构注册自身,以备与外界进行数据线包交换时调用 对网络接口的常用文件操作是没有意义的,因此在它们身上无法体现Unix的“一切都是文件”的思想 网络驱动程序异步自外部世界的数据包 网络设备向内核请求把外部获得的数据包发送给内核 Linux内核中的网络子系统被设计成完全与协议无关 在网络世界中使用术语“octet”指一组8个的数据位,它是能为网络设备和协议所能理解的最小单位 协议头(header)是在数据包中的一系列字节,它将通过网络子系统的不同层 连接到内核 loopback.c、plip.c和e100.c 设备注册 驱动程序对每个新检测到的接口,向全局的网络设备链表中插入一个数据结构 <linux/netdevice.h> struct net_device struct net_device alloc_netdev(int sizeof_priv, const char name, void (setup) (struct net_device )); name是接口的名字,这个名字可以使用类似printf中%d的格式,内核将用下一个可用的接口号替代%d <linux/etherdevie.h> struct net_device *alloc_etherdev(int sizeof_priv); 光纤通道设备使用alloc_fcdev(<linux/fcdevice.h>) FDDI设备使用alloc_fddidev(<linux/fddidevice.h>) 令牌环设备使用alloc_trdev(<linux/trdevice.h>) register_netdev函数 初始化每个设备 example ether_setup(dev); dev->open = open_function; dev->stop = release_function; dev->set_config = config_function; dev->hard_start_xmid = tx_function; dev->do_ioctl = ioctl_function; dev->get_stats = stats_function; dev->rebuild_header

read more »
July 4, 2012 / Driver, Linux, Reading Note, USB

简介 通用串行总线(USB)是主机和外围设备之间的一种连接 从拓扑上来看,一个USB子系统并不是以总线的方式来布置的;它是一棵由几个点对点的连接构建而成的树 这些连接是连接设备和集线器(hub)的四线电缆(地线、电源线和两根信号线) USB协议规范定义了一套任何特定类型的设备都可以遵循的标准,如果一个设备遵循该标准,就不需要一个特殊的驱动程序 Linux内核支持两种主要类型的USB驱动程序 宿主系统上的驱动程序 控制插入其中的USB设备 设备上的驱动程序 控制该设备如何作为一个USB设备和主机通信 USB设备基础 Linux内核提供了一个称为USB核心的子系统来处理大部分的复杂性 端点 USB通信最基本的形式是通过一个名为端点(endpoint)的东西 USB端点只能往一个方向传送数据,从主机到设备(输出端点)或者从设备到主机(输入端点) USB端点有四种不同的类型 控制 控制端点用来控制对USB设备不同部分的访问 每个USB设备都有一个名为“端点0”的控制端点 中断 每当USB宿主要求设备传输数据时,中断端点就以一个固定的速率来传送少量的数据 批量 批量(bulk)端点传输大批量的数据 等时 等时(isochronous)端点同样可以传送大批量的数据,但数据是否到达是没有保证的 控制和批量端点用于异步的数据传输,只要驱动程序决定使用它们 内核中使用struct usb_host_endpoint结构体来描述USB端点,该结构体在另一个名为struct usb_endpoint_descriptor的结构体中包含了真正的端点信息 struct usb_host_endpoint bEndpointAddress bmAttributes wMaxPacketSize bInterval 接口 USB端口被捆绑为接口 USB接口只处理一种USB逻辑连接 struct usb_interface struct usb_host_interface *altsetting unsigned num_altsetting struct usb_host_interface *cur_altsetting int minor 配置 USB接口本身被捆绑为配置 一个USB设备可以有多个配置,而且可以配置之间切换以改变设备的状态 struct usb_host_config struct usb_device include/linux/usb.h. USB设备是非常复杂的,它由许多不同的逻辑单元组成 设备通常具有一个或者更多的配置

read more »

简介 一个块设备驱动程序主要通过传输固定大小的随机数据来访问设备 Linux内核视块设备为与字符设备相异的基本设备类型 Linux块设备驱动程序接口使得块设备可以发挥其最大的功效,但是其复杂程序又是编程者必须面对的一个问题 一个数据块指的是固定大小的数据,而大小的值由内核确定 数据块的大小通常是4096个字节,但是可以根据体系结构和所使用的文件系统进行改变 与数据块对应的是扇区,它是由底层硬件决定大小的一个块,内核所处理的设备扇区大小是512字节 如果要使用不同的硬件扇区大小,用户必须对内核的扇区数做相应的修改 注册 注册块设备驱动程序 <linux/fs.h> int register_blkdev(unsigned int major, const char *name); 如果需要的话分配一个动态的主设备号 在/proc/devices中创建一个入口项 int unregister_blkdev(unsigned int major, const char *name); 注册磁盘 struct block_device_operations int (open) (struct inode inode, struct file *filp); int (release) (struct inode inode, struct file *filp); int (ioctl) (struct inode inode, struct file *filp, unsigned int cmd, unsigned long arg);

read more »

简介 许多类型的驱动程序编程都需要了解一些虚拟内存子系统如何工作的知识 当遇到更为复杂、性能要求更为苛刻的子系统时,本章所讨论的内容迟早都要用到 本章的内容分成三个部分 讲述mmap系统调用的实现过程 讲述如何跨越边界直接访问用户空间的内存页 讲述了直接内存访问(DMA)I/O操作,它使得外设具有直接访问系统内存的能力 Linux的内存管理 地址类型 Linux是一个虚拟内存系统,这意味着用户程序所使用的地址与硬件使用的物理地址是不等同的 有了虚拟内存,在系统中运行的程序可以分配比物理内存更多的内存,甚至一个单独的进程都能拥有比系统物理内存更多的虚拟地址空间 下面是一个Linux使用的地址类型列表 用户虚拟地址 这是在用户空间程序所能看到的常规地址 物理地址 该地址在处理器和系统内存之间使用 总线地址 该地址在外围总线和内存之间使用,通常它们与处理器使用的物理地址相同 内核逻辑地址 内核逻辑地址组成了内核的常规地址空间 在大多数体系架构中,逻辑地址和与其相关联的物理地址不同,仅仅在它们之间存在一个固定的偏移量 kmalloc返回的内存就是内核逻辑地址 内核虚拟地址 和内核逻辑地址的相同之处在于,它们都将内核空间的地址映射到物理地址上 内核虚拟地址与物理地址的映射不必是线性的一对一的 所有的逻辑地址都是内核虚拟地址,但是很多内核虚拟地址不是逻辑地址 vmalloc分配的内存具有一个虚拟地址 <asm/page.h> __pa() 返回其对应的物理地址 __va() 将物理地址逆向映射到逻辑地址,但这只对低端内存页有效 物理地址和页 物理地址被分成离散的单元,称之为页 <asm/page.h> PAGE_SIZE 目前大多数系统都使用每页4096个字节 高端与低端内存 使用32位系统只能在4GB的内存中寻址 内核将4GB的虚拟地址空间分割为用户空间和内核空间,一个典型的分割是将3GB分配给用户空间,1GB分配给内核空间 低端内存 存在于内核空间上的逻辑地址内存 高端内存 那些不存在逻辑地址的内存 内存映射和页结构 <linux/mm.h> struct page atomic_t count; 对该页的访问计数。当计数值为0时,该页将返回给空闲链表 void *virtual; 如果页面被映射,则指向页的内核虚拟地址;如果未被映射则为NULL unsigned long flags; 描述页状态的一系列标志 PG_locked表示内存中的页已经被锁住 PG_reserved表示禁止内存管理系统访问该页

read more »

简介 2.6内核的设备模型提供一个对系统结构的一般性抽象描述,用以支持多种不同的任务 电源管理和系统关机 与用户空间通信 热插拔设备 设备类型 对象生命周期 kobject、kset和子系统 kobject是组成设备模型的基本结构 对象的引用计数 sysfs表述 数据结构关联 热插拔事件处理 kobject基础知识 <linux/kobject.h> 嵌入的kobject 内核代码很少去创建一个单独的kobject对象,kobject用于控制对大型域相关对象的访问 kobject的初始化 首先将kobject设置为0,通常使用memset void kobject_init(struct kobject *kobj); int kobject_set_name(struct kobject kobj, const char format, …); ktype、kset和parent 对引用计数的操作 struct kobject kobjct_get(struct kobject kobj); void kobject_put(struct kobject *kobj); release函数和kobject类型 void my_object_readse(struct kobject *kobj) struct my_object *mine = container_of(kobj, struct my_object, kobj); kfree(mine); struct kobj_type void (release)

read more »

« Newer Entries  
Older Entries »