cp命令
该命令的功能是将给出的文件或目录拷贝到另一文件或目录中,同MSDOS下的命令一样,功能十分强大
语法: cp [选项] 源文件或目录 目标文件或目录
说明:该命令把指定的源文件复制到目标文件或把多个源文件复制到目标目录中
-r 若给出的源文件是一目录文件,此时cp将递归复制该目录下所有的子目录和文件
mv命令
用户可以使用mv命令来为文件或目录改名或将文件由一个目录移入另一个目录中。该命令如同MSDOS下的ren和move的组合
语法:mv [选项] 源文件或目录 目标文件或目录
rm命令
该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所有文件及子目录均删除
rm命令的一般形式为:
rm [选项] 文件…
如果没有使用-r选项,则rm不会删除目录
该命令的各选项含义如下:
-f 忽略不存在的文件,从不给出提示
-r 指示rm将参数中列出的全部目录和子目录均递归地删除
Vi命令
插入模式
按“i”切换进入插入模式“insert mode”,按“i”进入插入模式后是从光标当前位置开始输入文件
按“a”进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字
按“o”进入插入模式后,是插入新的一行,从行首开始输入文字
从插入模式切换为命令行模式
按“ESC”键
查找字符
“/关键字”:先按“/”键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按“n”会往后寻找到您要的关键字为止
“?关键字”:先按“?”键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按“n”会往前寻找到您要的关键字为止
离开vi
“q”:按“q”就是退出,如果无法离开vi,可以在“q”后跟一个“!”强制离开vi
“qw”:一般建议离开时,搭配“w”一起使用,这样在退出的时候还可以保存文件
mkdir命令
功能:创建一个目录(类似MSDOS下的md命令)
语法:mkdir [选项] dir-name
说明:该命令创建由dir-name命名的目录。要求创建目录的用户在当前目录中(dir-name的父目录中)具有写权限,并且dirname不能是当前目录中已有的目录或 文件名称。
命令中各选项的含义为:
-p 可以是一个路径名称。此时若路径中的某些目录尚不存在, 加上此选项后, 系统将自动建立好那些尚不存在的目录,即一次可以建立多个目录
cd 命令
功能:改变工作目录
语法:cd [directory]
说明:该命令将当前目录改变至directory所指定的目录。若没有指定directory, 则回到用户的主目录。为了改变到指定目录,用户必须拥有对指定目录的执行和读权限
ls 命令
功能: 列出目录的内容,该命令类似于DOS下的dir命令
语法:ls [选项] [目录或是文件]
对于每个目录,该命令将列出其中的所有子目录与文件。对于每个文件,ls将输出 其文件名以及所要求的其他信息。默认情况下,输出条目按字母顺序排序。当未给出目录名或是文件名时,就显示当前目录的信息。
命令中各选项的含义如下:
-a 显示指定目录下所有子目录与文件,包括隐藏文件
-c 按文件的修改时间排序
-t 显示时按修改时间(最近优先)而不是按名字排序。若文件修改时间相同,则 按字典顺序。修改时间取决于是否使用了c或u选顶。缺省的时间标记是最后一次修改时间
tar命令
tar可以为文件和目录创建档案。利用tar,用户可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件。tar最初被用来在磁带上创建档案,现在,用户可以在任何设备上创建档案,如软盘。利用tar命令,可以把一大堆的文件和目录全部打包成一个文件,这对于备份文件或将几个文件组合成为一个文件以便于网络传输是非常有用的。Linux上的tar是GNU版本的。
语法:tar [主选项+辅选项] 文件或者目录
使用该命令时,主选项是必须要有的,它告诉tar要做什么事情,辅选项是辅助使用的,可以选用。
主选项:
-c 创建新的档案文件。如果用户想备份一个目录或是一些文件,就要选择这个选项。
-x 从档案文件中释放文件。
-f 使用档案文件或设备,这个选项通常是必选的。
-v 详细报告tar处理的文件信息。如无此选项,tar不报告文件信息。
-z 用gzip来压缩/解压缩文件,加上该选项后可以将档案文件进行压缩,但还原时也一定要使用该选项进行解压缩
文件或目录的访问权限
Linux系统中的每个文件和目录都有访问许可权限,用它来确定谁可以通过何种方式对文件和目录进行访问和操作
文件或目录的访问权限分为只读,只写和可执行三种。以文件为例,只读权限表示只允许读其内容,而禁止对其做任何的更改操作。可执行权限表示允许将该文件作为一个程序执行。文件被创建时,文件所有者自动拥有对该文件的读、写和可执行权限,以便于对文件的阅读和修改。用户也可根据需要把访问权限设置为需要的任何组合
有三种不同类型的用户可对文件或目录进行访问:文件所有者,同组用户、其他用户。所有者一般是文件的创建者。所有者可以允许同组用户有权访问文件,还可以将文件的访问权限赋予系统中的其他用户。在这种情况下,系统中每一位用户都能访问该用户拥有的文件或目录
每一文件或目录的访问权限都有三组,每组用三位表示,分别为文件属主的读、写和执行权限;与属主同组的用户的读、写和执行权限;系统中其他用户的读、写和执行权限。当用ls -l命令显示文件或目录的详细信息时,最左边的一列为文件的访问权限。
例如:
$ ls -l sobsrc. tgz
-rw-r–r– 1 root root 483997 Ju1 l5 17:3l sobsrc. tgz
横线代表空许可。r代表只读,w代表写,x代表可执行。注意这里共有10个位置。第一个字符指定了文件类型。在通常意义上,一个目录也是一个文件。如果第一个字符是横线,表示是一个非目录的文件。如果是d,表示是一个目录
例如:
- rw- r– r–
普通文件 文件主 组用户 其他用户
是文件sobsrc.tgz 的访问权限,表示sobsrc.tgz是一个普通文件;sobsrc.tgz的属主有读写权限;与sobsrc.tgz属主同组的用户只有读权限;其他用户也只有读权限。
chmod 命令
chmod命令是非常重要的,用于改变文件或目录的访问权限。用户用它控制文件或目录的访问权限。
该命令有两种用法。一种是包含字母和操作符表达式的文字设定法;另一种是包含数字的数字设定法。
文字设定法
chmod [who] [+ | - | =] [mode] 文件名
命令中各选项的含义为:
操作对象who可是下述字母中的任一个或者它们的组合:
u 表示“用户(user)”,即文件或目录的所有者。
g 表示“同组(group)用户”,即与文件属主有相同组ID的所有用户。
o 表示“其他(others)用户”
a 表示“所有(all)用户”。它是系统默认值。
操作符号可以是:
+ 添加某个权限。
- 取消某个权限。
= 赋予给定权限并取消其他所有权限(如果有的话)
设置mode所表示的权限可用下述字母的任意组合:
r 可读
w 可写
x 可执行
X 只有目标文件对某些用户是可执行的或该目标文件是目录时才追加x 属性。
s 在文件执行时把进程的属主或组ID置为该文件的文件属主。方式“u+s”设置文件的用户ID位,“g+s”设置组ID位。
t 保存程序的文本到交换设备上。
u 与文件属主拥有一样的权限。
g 与和文件属主同组的用户拥有一样的权限。
o 与其他用户拥有一样的权限。
文件名:以空格分开的要改变权限的文件列表,支持通配符
在一个命令行中可给出多个权限方式,其间用逗号隔开。
例如:chmod g+r,o+r example
使同组和其他用户对文件example 有读权限
chgrp命令
功能:改变文件或目录所属的组。
语法:chgrp [选项] group filename
该命令改变指定指定文件所属的用户组。其中group可以是用户组ID,也可以是/etc/group文件中用户组的组名。文件名是以空格分开的要改变属组的文件列表,支持通配符。如果用户不是该文件的属主或超级用户,则不能改变该文件的组。
该命令的各选项含义为:
-R 递归式地改变指定目录及其下的所有子目录和文件的属组
chown 命令
功能:更改某个文件或目录的属主和属组。这个命令也很常用。例如root用户把自己的一个文件拷贝给用户xu,为了让用户xu能够存取这个文件,root用户应该把这个文件的属主设为xu,否则,用户xu无法存取这个文件。
语法:chown [选项] 用户或组 文件
说明:chown将指定文件的拥有者改为指定的用户或组。用户可以是用户名或用户ID。组可以是组名或组ID。文件是以空格分开的要改变权限的文件列表,支持通配符。
该命令的各选项含义如下:
-R 递归式地改变指定目录及其下的所有子目录和文件的拥有者
-v 显示chown命令所做的工作
passwd命令
出于系统安全考虑,Linux系统中的每一个用户除了有其用户名外,还有其对应的用户口令。因此使用useradd命令增加时,还需使用passwd命令为每一位新增加的用户设置口令;用户以后还可以随时用passwd命令改变自己的口令
该命令的一般格式为: passwd [用户名] 其中用户名为需要修改口令的用户名。只有超级用户可以使用“passwd 用户名”修改其他用户的口令,普通用户只能用不带参数的passwd命令修改自己的口令
该命令的使用方法如下:
输入passwd< Enter>;
在new password:提示下输入新的口令(在屏幕上看不到这个口令):
系统提示再次输入这个新口令
su命令
它可以让一个普通用户拥有超级用户或其他用户的权限,也可以让超级用户以普通用户的身份做一些事情。普通用户使用这个命令时必须有超级用户或其他用户的口令。如要离开当前用户的身份,可以打exit
该命令的一般形式为: su [选项] [使用者帐号]
说明:若没有指定使用者帐号,则系统预设值为超级用户root。 该命令中各选项的含义分别为:
-c 执行一个命令后就结束
- 加了这个减号的目的是使环境变量和欲转换的用户相同
-m 保留环境变量不变
shutdown命令
shutdown 命令可以安全地关闭或重启Linux系统,它在系统关闭之前给系统上的所有登录用户提示一条警告信息。该命令还允许用户指定一个时间参数,可以是一个精确的时间,也可以是从现在开始的一个时间段。精确时间的格式是hh:mm,表示小时和分钟;时间段由“+”和分钟数表示。系统执行该命令后,会自动进行数据同步的工作
该命令的一般格式为: shutdown [选项] [时间] [警告信息] 命令中各选项的含义为:
-k 并不真正关机,而只是发出警告信息给所有用户。
-r 关机后立即重新启动。
-h 关机后不重新启动。
-f 快速关机,重启动时跳过fsck。
-n 快速关机,不经过init程序。
-c 取消一个已经运行的shutdown
需要特别说明的是,该命令只能由超级用户使用
free命令
free命令的功能是查看当前系统内存的使用情况,它显示系统中剩余及已用的物理内存和交换内存,以及共享内存和被核心使用的缓冲区。
该命令的一般格式为: free [-b | -k | -m] 命令中各选项的含义如下:
-b 以字节为单位显示。
-k 以K字节为单位显示。
-m 以兆字节为单位显示
df命令
功能:检查文件系统的磁盘空间占用情况。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息
语法:df [选项]
说明:df命令可显示所有文件系统对i节点和磁盘块的使用情况。
该命令各个选项的含义如下:
-a 显示所有文件系统的磁盘使用情况,包括0块(block)的文件系统,如/proc文件系统。
-k 以k字节为单位显示。
-i 显示i节点信息,而不是磁盘块。
-t 显示各指定类型的文件系统的磁盘空间使用情况。
命令
的英文原义为“disk usage”,含义为显示磁盘空间的使用情况。
功能:统计目录(或文件)所占磁盘空间的大小。
语法: [选项] [Names…]
说明:该命令逐级进入指定目录的每一个子目录并显示该目录占用文件系统数据块(1024字节)的情况。若没有给出Names,则对当前目录进行统计。
该命令的各个选项含义如下:
-s 对每个Names参数只给出占用的数据块总数。
date命令
date命令的功能是显示和设置系统日期和时间。
该命令的一般格式为: date [选项] 显示时间格式(以+开头,后面接格式)
date 设置时间格式
命令中各选项的含义分别为:
-s datestr, –set datestr 设置datestr 描述的日期
注意:只有超级用户才有权限使用date命令设置时间,一般用户只能使用date命令显示时间。
ifconfig
作用
ifconfig用于查看和更改网络接口的地址和参数,包括IP地址、网络掩码、广播地址,使用权限是超级用户
格式
ifconfig -interface [options] address
主要参数
-interface:指定的网络接口名,如eth0和eth1
up:激活指定的网络接口卡
down:关闭指定的网络接口
address:设置指定接口设备的IP地址
netmask address:设置接口的子网掩码
应用说明
ifconfig是用来设置和配置网卡的命令行工具。为了手工配置网络,这是一个必须掌握的命令。使用该命令的好处是无须重新启动机器。
要赋给eth0接口IP地址207.164.186.2,并且马上激活它,使用下面命令:
#fconfig eth0 210.34.6.89 netmask 255.255.255.128
该命令的作用是设置网卡eth0的IP地址、网络掩码和网络的本地广播地址。若运行不带任何参数的ifconfig命令,这个命令将显示机器所有激活接口的信息。带有“-a”参数的命令则显示所有接口的信息,包括没有激活的接口。注意,用ifconfig命令配置的网络设备参数,机器重新启动以后将会丢失
如果要暂停某个网络接口的工作,可以使用down参数:
#ifconfig eth0 down
netstat
作用
检查整个Linux网络状态
格式
netstat [-acCeFghilMnNoprstuvVwx][-A][–ip]
主要参数
-a–all:显示所有连线中的Socket
-l–listening:显示监控中的服务器的Socket
-n–numeric:直接使用IP地址,而不通过域名服务器
-p–programs:显示正在使用Socket的程序识别码和程序名称
-t–tcp:显示TCP传输协议的连线状况
-u–udp:显示UDP传输协议的连线状况
-apn 查看开启的端口
应用实例
netstat主要用于Linux察看自身的网络状况,如开启的端口、在为哪些用户服务,以及服务的状态等。此外,它还显示系统路由表、网络接口状态等。可以说,它是一个综合性的网络状态的察看工具。在默认情况下,netstat只显示已建立连接的端口。如果要显示处于监听状态的所有端口,使用-a参数即可:
#netstat -a
lsof
作用
显示系统打开的文件
格式
lsof 〔options〕 filename
主要参数
lsof -a: 表示两个参数都必须满足时才显示结果
lsof -c string: 显示COMMAND列中包含指定字符的进程所有打开的文件
lsof -u username: 显示所属user进程打开的文件
lsof -g gid: 显示归属gid的进程情况
lsof +d /DIR/: 显示目录下被进程打开的文件
lsof +D /DIR/: 同上,但是会搜索目录下的所有目录,时间相对较长
lsof -d FD: 显示指定文件描述符的进程
lsof -n: 不将IP转换为hostname,缺省是不加上-n参数
lsof -i: 用以显示符合条件的进程情况
lsof -i:port: 查看端口运行的程序。
例如:查看22端口所运行的程序 #lsof -i:22
telnet
作用
telnet表示开启终端机阶段作业,并登入远端主机。telnet是一个Linux命令,同时也是一个协议(远程登陆协议)
格式
telnet [-8acdEfFKLrx][-b][-e][-k][-l][-n][-S][-X][主机名称IP地址<通信端口>]
ftp
作用
ftp命令进行远程文件传输。FTP是ARPANet的标准文件传输协议,该网络就是现今Internet的前身,所以ftp既是协议又是一个命令。
格式
ftp [-dignv][主机名称IP地址]
应用说明
ftp命令是标准的文件传输协议的用户接口,是在TCP/IP网络计算机之间传输文件简单有效的方法,它允许用户传输ASCⅡ文件和二进制文件。为了使用ftp 来传输文件,用户必须知道远程计算机上的合法用户名和口令。这个用户名/口令的组合用来确认ftp会话,并用来确定用户对要传输的文件进行什么样的访问。另外,用户需要知道对其进行ftp会话的计算机名字的IP地址
用户可以通过使用ftp客户程序,连接到另一台计算机上;可以在目录中上下移动、列出目录内容;可以把文件从远程计算机机拷贝到本地机上;还可以把文件从本地机传输到远程系统中。ftp内部命令有72个,下面列出主要几个内部命令:
ls:列出远程机的当前目录
cd:在远程机上改变工作目录
lcd:在本地机上改变工作目录
close:终止当前的ftp会话
get(mget):从远程机传送指定文件到本地机
put(mput):从本地机传送指定文件到远程机
quit:断开与远程机的连接,并退出ftp
route
作用
route表示手工产生、修改和查看路由表
格式
#route [-add][-net|-host] targetaddress [-netmask Nm][dev]If]
#route [-delete][-net|-host] targetaddress [gw Gw] [-netmask Nm] [dev]If]
主要参数
-add:增加路由
-delete:删除路由
-net:路由到达的是一个网络,而不是一台主机
-host:路由到达的是一台主机
-netmask Nm:指定路由的子网掩码
gw:指定路由的网关
[dev]If:强迫路由链指定接口。
应用实例
route命令是用来查看和设置Linux系统的路由信息,以实现与其它网络的通信。要实现两个不同的子网之间的通信,需要一台连接两个网络的路由器,或者同时位于两个网络的网关来实现
在Linux系统中,设置路由通常是为了解决以下问题:该Linux系统在一个局域网中,局域网中有一个网关,能够让机器访问Internet,那么就需要将这台机器的IP地址设置为Linux机器的默认路由。使用下面命令可以增加一个默认路由:
route add 0.0.0.0 192.168.1.1
top
作用
top命令用来显示执行中的程序进程,使用权限是所有用户。
格式
top [-] [d delay] [q] [c] [S] [s] [i] [n]
主要参数
d:指定更新的间隔,以秒计算
q:没有任何延迟的更新。如果使用者有超级用户,则top命令将会以最高的优先序执行
c:显示进程完整的路径与名称
i:不显示任何闲置(Idle)或无用(Zombie)的行程
n:显示更新的次数,完成后将会退出top。
说明
top命令是Linux系统管理的一个主要命令,通过它可以获得许多信息。这里我们结合图1来说明它给出的信息
下面列出了详细解释
PID(Process ID):进程标示号
USER:进程所有者的用户名
PR:进程的优先级别
NI:进程的优先级别数值
VIRT:进程占用的虚拟内存值
RES:进程占用的物理内存值
SHR:进程使用的共享内存值
S:进程的状态,其中S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值是负数
%CPU:该进程占用的CPU使用率
%MEM:该进程占用的物理内存和总内存的百分比
TIME+:该进程启动后占用的总的CPU时间
Command:进程启动的启动命令名称,如果这一行显示不下,进程会有一个完整的命令行。
❷ Linux系统I/O操作与零拷贝
Linux中传统的I/O操作是一种缓存I/O,I/O过程中产生的数据传输通常需要在缓冲区中进行多次拷贝。当应用程序需要访问某个数据(read()操作)时,操作系统会先判断这块数据是否在内核缓冲区中,如果在内核缓冲区中找不到这块数据,内核会先将这块数据从磁盘中读出来放到内核缓冲区中,应用程序再从缓冲区中读取。当应用程序需要将数据输出(write())时,同样需要先将数据拷贝到输出堆栈相关的内核缓冲区,再从内核缓冲区拷贝到输出设备中。
以一次网络请求为例,如下图。对于一次数据读取,用户应用程序只需要调用read()及write()两个系统调用就可以完成一次数据传输,但这个过程中数据经过了四次拷贝,且数据拷贝需要由CPU来调控。在某些情况下,这些数据拷贝会极大地降低系统数据传输的性能,比如文件服务器中,一个文件从磁盘读取后不加修改地回传给调用方,那么这占用CPU时间去处理这四次数据拷贝的性价比是极低的。
一次处理网络调用的系统I/O的流程:
以上可以发现,传统的Linux系统I/O 操作要进行4次内核空间与应用程序空间的上下文切换,以及4次数据拷贝。
直接内存访问(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术,允许某些电脑内部的硬件子系统独立地读取系统内存,而不需要中央处理器(CPU)的介入。在同等程度的处理器负担下,DMA是一种快速的数据传送方式。这类子系统包括硬盘控制器、显卡、网卡和声卡。
在Linux系统中,当应用程序需要读取文件中的数据时,操作系统先分配一些内存,将数据从存储设备读入到这些内存中,然后再将数据传递应用进程;当需要往文件中写数据时,操作系统先分配内存接收用户数据,然后再将数据从内存写入磁盘。文件cache管理就是对这些由操作系统分配并用开存储文件数据的内存的管理。
在Linux系统中,文件cache分为两个层面,page cache 与 Buffer cache,每个page cache包含若干个buffer cache。操作系统中,磁盘文件都是由一系列的数据块(Block)组成,buffer cache也叫块缓存,是对磁盘一个数据块的缓存,目的是为了在程序多次访问同一个磁盘块时减少访问时间;而文件系统对数据的组织形式为页,page cache为页缓存,是由多个块缓存构成,其对应的缓存数据块在磁盘上不一定是连续的。也就是说buffer cache缓存文件的具体内容--物理磁盘上的磁盘块,加速对磁盘的访问,而page cache缓存文件的逻辑内容,加速对文件内容的访问。
buffer cache的大小一般为1k,page cache在32位系统上一般为4k,在64位系统上一般为8k。磁盘数据块、buffer cache、page cache及文件的关系如下图:
文件cache的目的是加快对数据文件的访问,同时会有一个预读过程。对于每个文件的第一次读请求,系统会读入所请求的页面并读入紧随其后的几个页面;对于第二次读请求,如果所读页面在cache中,则会直接返回,同时又一个异步预读的过程(将读取页面的下几页读入cache中),如果不在cache中,说明读请求不是顺序读,则会从磁盘中读取文件内容并刷新cache。因此在顺序读取情况下,读取数据的性能近乎内存读取。
DMA允许硬件子系统直接将数据从磁盘读取到内核缓冲区,那么在一次数据传输中,磁盘与内核缓冲区,输出设备与内核缓冲区之间的两次数据拷贝就不需要CPU进行调度,CPU只需要进行缓冲区管理、以及创建和处理DMA。而Page Cache/Buffer Cache的预读取机制则加快了数据的访问效率。如下图所示,还是以文件服务器请求为例,此时CPU负责的数据拷贝次数减少了两次,数据传输性能有了较大的提高。
使用DMA的系统I/O操作要进行4次内核空间与应用程序空间的上下文切换,2次CPU数据拷贝及2次DMA数据拷贝。
Mmap内存映射与标准I/O操作的区别在于当应用程序需要访问数据时,不需要进行内核缓冲区到应用程序缓冲区之间的数据拷贝。Mmap使得应用程序和操作系统共享内核缓冲区,应用程序直接对内核缓冲区进行读写操作,不需要进行数据拷贝。Linux系统中通过调用mmap()替代read()操作。
同样以文件服务器获取文件(不加修改)为例,通过mmap操作的一次系统I/O过程如下:
通过以上流程可以看到,数据拷贝从原来的4次变为3次,2次DMA拷贝1次内核空间数据拷贝,CPU只需要调控1次内核空间之间的数据拷贝,CPU花费在数据拷贝上的时间进一步减少(4次上下文切换没有改变)。对于大容量文件读写,采用mmap的方式其读写效率和性能都比较高。(数据页较多,需要多次拷贝)
注:mmap()是让应用程序空间与内核空间共享DMA从磁盘中读取的文件缓冲,也就是应用程序能直接读写这部分PageCache,至于上图中从页缓存到socket缓冲区的数据拷贝只是文件服务器的处理,根据应用程序的不同会有不同的处理,应用程序也可以读取数据后进行修改。重点是虚拟内存映射,内核缓存共享。
djk中nio包下的MappedByteBuffer,官方注释为 A direct byte buffer whose content is a memory-mapped region of a file,即直接字节缓冲区,其内容是文件的内存映射区域。 FileChannel是是nio操作文件的类,其map()方法在在实现类中调用native map0()本地方法,该方法通过mmap()实现,因此是将文件从磁盘读取到内核缓冲区,用户应用程序空间直接操作内核空间共享的缓冲区,Java程序通过MappedByteBuffer的get()方法获取内存数据。
MappedByteBuffer允许Java程序直接从内存访问文件,可以将整个文件或文件的一部分映射到内存中,由操作系统进行相关的请求并将内存中的修改写入到磁盘中。
FileChannel map有三种模式
MappedByteBuffer的应用,以rocketMQ为例(简单介绍)。
procer端发送消息最终会被写入到commitLog文件中,consumer端消费时先从订阅的consumeQueue中读取持久化消息的commitLogOffset、size等内容,随后再根据offset、size从commitLog中读取消息的真正实体内容。其中,commitLog是混合部署的,所有topic下的消息队列共用一个commitLog日志数据文件,consumeQueue类似于索引,同时区分开不同topic下不同MessageQueue的消息。
rocketMQ利用MappedByteBuffer及PageCache加速对持久化文件的读写操作。rocketMQ通过MappedByteBuffer将日志数据文件映射到OS的虚拟内存中(PageCache),写消息时首先写入PageCache,通过刷盘方式(异步或同步)将消息批量持久化到磁盘;consumer消费消息时,读取consumeQueue是顺序读取的,虽然有多个消费者操作不同的consumeQueue,对混合部署的commitLog的访问时随机的,但整体上是从旧到新的有序读,加上PageCache的预读机制,大部分情况下消息还是从PageCache中读取,不会产生太多的缺页中断(要读取的消息不在pageCache中)而从磁盘中读取。
rocketMQ利用mmap()使程序与内核空间共享内核缓冲区,直接对PageCache中的文件进行读写操作,加速对消息的读写请求,这是其高吞吐量的重要手段。
使用mmap能减少CPU数据拷贝的次数,但也存在一些问题。
从Linux2.1开始,Linux引入sendfile()简化操作。取消read()/write(),mmap()/write()。
调用sendfile的流程如下:
通过sendfile()的I/O进行了2次应用程序空间与内核空间的上下文切换,以及3次数据拷贝,其中2次是DMA拷贝,1次是CPU拷贝。sendfile相比起mmap,数据信息没有进入到应用程序空间,所以能减少2次上下文切换的开销,而数据拷贝次数是一样的。
上述流程也可以看出,sendfile()适合对文件不加修改的I/O操作。
sendfile()只是减少应用程序空间与内核空间的上下文切换,并没有减少CPU数据拷贝的次数,还存在一次内核空间的两个缓冲区的数据拷贝。要实现CPU零数据拷贝,需要引入一些硬件上的支持。在上一小节的sendfile流程中,数据需要从内核缓冲区拷贝到内核空间socket缓冲区,数据都是在内核空间,如果socket缓冲区到网卡的这次DMA数据传输操作能直接读取到内核缓冲区中的数据,那么这一次的CPU数据拷贝也就能避免。要达到这个目的,DMA需要知道存有文件位置和长度信息的缓冲区描述符,即socket缓冲区需要从内核缓冲区接收这部分信息,DMA需要支持数据收集功能。
sendfile()调用后,数据从磁盘文件拷贝到内核缓冲区中,然后将文件位置和长度信息的缓冲区描述符传递到socket缓冲区,此时数据并没有被拷贝。之后网卡子系统根据socket缓冲区中的文件信息利用DMA技术收集拷贝数据。整个过程进行了2次内核空间和应用程序空间的上下文切换,及2次DMA数据拷贝,CPU不需要参与数据拷贝工作,从而实现零拷贝。当然DMA收集拷贝功能需要硬件和驱动程序的支持。
在操作系统中,硬件和软件之间的数据传输可以通过DMA来进行,DMA进行数据传输的过程几乎不需要CPU参与,但是在内核缓冲区(页缓存)与应用程序缓冲区之间的数据拷贝并没有类似于DMA之类的工具可以使用,mmap、sendfile都是为了减少数据在内核空间与应用程序空间传输时的数据拷贝和上下文切换次数,有效地改善数据在两者之间传递的效率。
linux操作系统的零拷贝技术并不单指某一种方式,现有的零拷贝技术种类非常多,在不同的Linux内核版本上有不同的支持。常见的,如果应用程序需要修改数据,则使用mmap(),如果只进行文件数据传输,则可选择sendfile()。
另外,关于零拷贝技术适用于什么场景?在上述的描述中,数据在传递过程中,除了mmap外,应用程序和操作系统几乎是没有改变数据的,mmap的内存映射也是没有改变数据的,也就是说在静态资源的读取场景下,零拷贝更能发挥作用。正如其名,拷贝是在不改变数据的情况下,零是利用手段去减少CPU参与数据拷贝的次数,以释放CPU去进行其他系统调用与计算。
❸ linux 文件描述符最大是多少
人们常说linux最大有65536个文件描述符,是由于常用linux内核的默认值决定的,实际上是可以通过修改内核突破的。
了解下文件描述符,内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
文件描述符的有效范围是 0 到 OPEN_MAX。一般来说,每个进程最多可以打开 64 个文件(0 — 63)。对于 FreeBSD 5.2.1、Mac OS X 10.3 和 Solaris 9 来说,每个进程最多可以打开文件的多少取决于系统内存的大小,int 的大小,以及系统管理员设定的限制。Linux 2.4.22 强制规定最多不能超过 1,048,576 。
❹ Linux中编写了内核模块的C源程序之后怎么编写makefile文件的内容
linux内核的源代码都在
的/pub/linux目录下
软件的源代码在该一般项目主页或发行版的“源”,或其他开源软件的网站
❺ linux内核态,在LSM框架中的文件操作hook接口中如何获取一个正在被操作的文件的内容(linux4.4版本)
LSM是Linux Secrity Mole的简称,即linux安全模块。其是一种轻量级通用访
问控制框架,适合于多种访问控制模型在它上面以内核可加载模块的形实现。用
户可以根据自己的需求选择合适的安全模块加载到内核上实现。
LSM设计思想:
LSM的设计思想:在最少改变内核代码的情况下,提供一个能够成功实现强制访
问控制模块需要的结构或者接口。LSM避免了利用如在systrace系统调用中的出
现过的系统调用干预,因为它不能扩展到多处理器内核,并且它受制于参数替换
攻击。还有LSM在设计时做了两点考虑:对不使用的人来说尽量少引入麻烦,对
使用的人来说要带来效率。以Linus Torvalds为代表的内核开发人员对Linux安
全模块(LSM)提出了三点要求:
1、真正的通用,当使用一个不同的安全模型的时候,只需要加载一个不同的内
核模块。
2、概念上简单,对Linux内核影响最小,高效,并且。
3、能够支持现存的POSIX.1e capabilities逻辑,作为一个可选的安全模块。
还有,针对linux上提出的各种不同的Linux安全增强系统对Linux安全模块(LSM
)提出的要求是:能够允许他们以可加载内核模块的形式重新实现其安全功能,
并且不会在安全性方面带来明显的损失,也不会带来额外的系统开销。
LSM框架结构:
LSM框架主要由五部分构成:
1、在特定的内核数据结构中加入安全域。
2、在内核源代码中不同的关键点插入对安全钩子函数的调用。
3、加入一个通用的安全系统调用。
4、提供了函数允许内核模块注册为安全模块或者注销。
5、5、将capabilities逻辑的大部分移植为一个可选的安全模块。
安全域是一个void*类型的指针,它使得安全模块把安全信息和内核内部对象联
系起来。下面列出被修改加入了安全域的内核数据结构,以及各自所代表的内核
内部对象:
task_struct结构:代表任务(进程)
linux_binprm结构:代表程序
super_block结构:代表文件系统
inode结构:代表管道,文件,或者Socket套接字
file结构:代表打开的文件
sk_buff结构:代表网络缓冲区(包)
net_device结构:代表网络设备
kern_ipc_perm结构:代表Semaphore信号,共享内存段,或者消息队列
msg_msg:代表单个的消息
Linux安全模块(LSM)提供了两类对安全钩子函数的调用:一类管理内核对象的
安全域,另一类仲裁对这些内核对象的访问。对安全钩子函数的调用通过钩子来
实现,钩子是全局表security_ops中的函数指针,这个全局表的类型是
security_operations结构,这个结构定义在include/linux/security.h这个头
文件中。
LSM接口的核心是security_ops,当系统启动时,他们被初始化为传统的DAC策略
。传统DAC访问控制是指控制系统中的主体(如进程)对系统中的客体(如文件
目录、文件)的访问(读、写和执行等)。自主访问控制DAC 是指主体(进程,
用户)对客体(文件、目录、特殊设备文件、IPC等)的访问权限是由客体的属
主或超级用户决定的,而且此权限一旦确定,将作为以后判断主体对客体是否有
访问权限的依据。
在加载安全模块时,我们必需先对模块进行注册,我们可以使用
register_security()函数向LSM注册一个安全模块。在我们的模块被加载成
功后,就可以进行访问控制操作。如果此时还有一个安全模块要使用
register_security()函数进行加载,则会出现错误,直到使用
unregister_security()函数向框架注销后,下一个模块才可以载入。当然LS
M还提供了mod_reg_security()函数和mod_unreg_security()函数,可以连续注
册多个安全模块。如果有其他后来的模块需要载入,可以通过mod_reg_security
()向第一个模块注册,形成支持不同策略的模块栈。
注:以上出现的函数均基于2.6.22以前的版本,对于后续的版本,出现了
register_security()函数未被导出或者取消掉了unregister_security()函数。
LSM执行过程:
根据下图的执行步骤:用户在执行系统调用时,先通过原有的内核接口依次执行
功能性的错误检查,接着进行传统的DAC检查,并在即将访问内核的内部对象之
前,通过LSM钩子函数调用LSM。LSM再调用具体的访问控制策略来决定访问的合
法性。图三显示了LSM钩子的调用:
图三:基于LSM的内核对象访问过程
Lilinux安全模块(LSM)主要支持"限制型"的访问控制决策:当Linux内核授予
文件或目录访问权限时,Linux安全模块(LSM)可能会拒绝,而当 Linux内核拒
绝访问时,可以跳过LSM。
========
使用LSM实现自己的访问控制
首先对LSM 进行简单介绍。虽然linux下的各位基本都知道一些,但是还要罗嗦
一下。
LSM中文全称是linux安全模块。英文全称:linux security mole.
LSM是一种轻量级、通用的访问控制框架,适合多种访问控制模型以内核模块的
形式实现。其特点是通用、简单、高效、支持POSIX。1e能力机制。
LSM的架构图如下:
通过系统调用进入内核之后,系统首先进行传统的权限检查(传统权限检查主要
是基于用户的,用户通过验证之后就可以访问资源),通过之后才会进行强制访
问控制。(强制访问控制是不允许主体干涉的一种访问控制,其采用安全标识、
信息分级等信息敏感性进行访问控制。并且通过比较主体的级别和资源的敏感性
来确定是否允许访问。比如说系统设置A用户不允许访问文件B,即便A是文件B的
所有者,访问也是受限制的。)从图上看来,LSM实现访问控制主要通过安全模
块的钩子函数实现。
LSM框架主要由五部分组成:这个网上资料很多。
在关键的特定内核数据结构中加入了安全域;
在内核源码中不同的关键点处插入对安全钩子函数的调用;
提供了一个通用的安全系统调用;
提供了注册和注销函数,使得访问控制策略可以以内核模块方式实现;
将capabilities逻辑的大部分功能移植为一个可选的安全模块。
我们这里重点结合源码对LSM框架进行解释。我使用的源码是3.5.4
首先介绍安全域字段,它是一个空类型的指针,在内核中的很多内核结构中都存
在,比如inode、superblock、dentry、file等等。类型字段为void *
security;
那么安全域怎么和安全模块中的信息关联起来?
当安全模块加载之后,安全域中的指针便指向安全模块中的安全信息。这里以
selinux为例进行介绍。
内核里面security/selinux/include/objsec.h中定义了不同对象的安全信息,
格式为XXX_security_strut.
上面的文件的安全信息里面包含打开文件描述符时的安全ID、文件所有者的安全
ID等等。
要联系安全模块中安全信息和安全域需要几个控制钩子函数。这些钩子函数实现
了对内核关键信息的设置和管理。这里主要介绍alloc_security、
free_security。
selinux里面通过实现安全信息空间分配实现关联。比如以文件安全信息为例
这里分配空间成功之后,通过file->f_security = fsec实现了关联。
撤销关联是在安全模块卸载之后调用file_free_security.
这里具体通过设置file->f_secrity为NULL,然后释放安全信息结构实现。
现在来看看内核如何实现selinux的访问控制。这里主要就是实现LSM里面的钩子
函数了。LSM里面给出了结构体security_operations,里面给出了很多钩子函数
,实现了相关钩子函数就可以实现访问控制了。
上面的函数就实现了file_permission钩子函数。可以看下inode结构体的获得,
感受内核是通过文件->目录项->inode。该函数主要实现自己的访问控制策略就
OK 了。
哪selinux来说,在获得文件安全ID之后,主要对掩码和文件打开时相关的安全
信息进行检测,符合就通过访问控制。
selinux基本实现了LSM里面的所有钩子函数,待钩子函数实现后,对LSM里面钩
子域进行填充就OK了。
做完以上这些还需要注册安全模块到LSM,这里注册和注销使用了
register_security和unregister_security。
比如selinux在注册时使用语句register_security(&selinux_ops)实现。
接下来通过上面的分析我们可以实现简单的基于LSM的访问控制。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mole.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
#include <linux/uaccess.h>
#include <linux/file.h>
#include <linux/namei.h>
static int lsm_test_file_permission(struct file *file,int mask)
{
int path=0;
struct file *filp;
struct nameidata nd;
path = path_lookup(FILENAME,LOOKUP_FOLLOW,&nd);
if(!mask)
return 0;
if(path)
{
printk("lookup file failed!\n");
return -1;
}
filp = filp_open("/home/yuyunchao/code/sb.c",O_RDONLY,0);
{
printk("open failed!\n");
}
return 0;
}
static struct security_operations lsm_test_security_ops = {
.file_permission = lsm_test_file_permission,
};
static int __init lsm_file_init(void)
{
if(register_security(&lsm_test_security_ops)){
printk("register error ..........\n");
return -1;
}
printk("lsm_file init..\n ");
return 0;
}
static void __exit lsm_file_exit(void)
{
if(unregister_security(&lsm_test_security_ops)){
printk("unregister error................\n");
return ;
}
printk("mole exit.......\n");
}
MODULE_LICENSE("GPL");
mole_init(lsm_file_init);
mole_exit(lsm_file_exit);
========
LSM(Linux Security Mole)应用方法(简单例子)
LSM在内核中很多地方已经插入了hook函数,并且在security.c函数中声明了
security_ops结构,要实现你自己的安全模块,只需要定义你自己的struct
security_operations,并且用register_security注册即可,下面举个简单例子
:
test.c代码如下:
/*
* Test Linux Security Mole
*
* Author: penghuan <[email protected]>
*
* Copyright (C) 2010 UbuntuKylin, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/
#include <linux/security.h>
#include <linux/sysctl.h>
#include <linux/ptrace.h>
#include <linux/prctl.h>
#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/path.h>
int test_file_permission(struct file *file, int mask)
{
char *name = file->f_path.dentry->d_name.name;
if(!strcmp(name, "test.txt"))
{
file->f_flags |= O_RDONLY;
printk("you can have your control code here!\n");
}
return 0;
}
static struct security_operations test_security_ops = {
.name = "test",
.file_permission = test_file_permission,
};
static __init int test_init(void)
{
printk("enter test init!\n");
printk(KERN_INFO "Test: becoming......\n")
if (register_security(&test_security_ops))
panic("Test: kernel registration failed.\n");
return 0;
}
security_initcall(test_init);
将该文件以模块的形式放到security/下编译进内核,启用新的内核后,当你操
作文件test.txt时,通过dmesg命令就能再终端看到”you can have your
control code here!“输出
所以一般的做法是:定义你自己的struct security_operations,实现你自己的
hook函数,具体有哪些hook函数可以查询include/linux/security.h文件,然后
调用register_security来用你的test_security_ops初始化全局的security_ops
指针
楼主,我刚开始研究LSM,但网上资料太少,您这个代码,我编译成ko文件老是
有警告,并且insmod时,说Unknown symbol register_security。我最近看了看
内核模块变成,没有对内核进行太深入的了解。不知能否把LSM的实验步骤给出
的再详细点,谢谢。
你需要把代码编进内核
是需要把那段源码拷到内核目录下,然后重新编译内核?。。没有不编译内核的
方法吗?。。直接按照模块进行编译。另外那个test.txt放在哪个文件夹里?。
是需要把那段源码拷到内核目录下,然后重新编译内核?。。没有不编译内核的
方法吗?。。直接按照模块进行 ...
是的,你去网上找下怎么把模块编进内核,lsm模块不能以模块方式加载,涉及
安全;test.txt是测试文件,当你把代码编进内核后,用新内核启动,然后操作
test.txt文件,就会有输出,test.txt随便放哪里
楼主,您好,我刚开始学习lsm模块,把您的模块编译进内核,新的内核加载后
,register_security总是失败,请问下可能是什么原因导致的。我的内核版本
是3.13.11。
register_security的返回值是-11
========
LSM在Linux中的实现方式
LSM(Linux Secure Model)一种轻量级访问控制机制.
其实现方式有如在系统调用中加入一个后门....
方式如下:
static struct file *__dentry_open(struct dentry *dentry, struct
vfsmount *mnt,
struct file *f,
int (*open)(struct inode *, struct file *),
const struct cred *cred)
{
struct inode *inode;
int error;
...............................................................
error = security_dentry_open(f, cred); //LSM机制实现方式,在此加入了
一个LSM函数.
//security_dentry_open的实现如下,相当于一个接口,对一个函数指针再
//封装一下.
//只返回是与否,这样的控制信息.
if (error)
goto cleanup_all;
................................................................
return f;
cleanup_all:
.................................................................
return ERR_PTR(error);
}
//========简单封装一个指针结构体===========================
int security_dentry_open(struct file *file, const struct cred *cred)
{
int ret;
ret = security_ops->dentry_open(file, cred);
if (ret)
return ret;
return fsnotify_perm(file, MAY_OPEN);
}
========
利用LSM实现更安全的linux
LSM的全称是Linux Security Moles,它是linux内核中用来支持更灵活的
安全策略的一个底层框架,虽然听起来比较复杂,但是可以就把它理解成一组安
插在linux内核的钩子函数和一些预留的被称为安全域的数据结构,下面先说说
这个框架的由来吧。
linux本身的机制就保证了linux拥有更好的安全机制,但是在这个机制下面
,还是隐藏了许多的问题:
1、权限粒度太大。用过linux的人应该对0644这样的访问权限设置不陌生,
它对能够操作这个文件的用户做了限制,但是这个只是限制到了组,而没有更进
一步的细分,当然,如果LSM只是用来限制这个的话,那么也就太没意思了,因
为实现文件更细的控制粒度,ACL就能够很出色的完成,顺便提一下,ACL有一个
分配的限制,如果哪位朋友需要用ACL进行粒度更细的访问权限控制的话,可能
需要注意一下这方面的东西。
2、root用户的权限太大。在linux中,root用户就是至高无上的,他拥有对
机器的完全控制权限,可以做他想做的一切事情。但是很多时候,我们可能并不
希望有root有这么大的权限,比如在现在比较流行的云存储中,用户肯定不希望
服务提供商能够随意访问我们的文件,那么这个时候,就需要对root用户进行一
定的设置了。
由于这些问题的存在,所以出现了像SE Linux(Securiy Enhanced Linux )
这样的增强补丁。但是每个系统对于具体安全细节的控制不尽相同, 所以Linus
Tovalds 提出应该要有一个 Linux 内核所能接受的安全框架来支持这些安全策
略,这个安全框架应该提供包含内核数据结构中的透明安全域以及用来控制、维
护安全域操作的安全钩子,于是就有了LSM。
LSM在内核中的位置,可以用下图来表示:
当用户态程序调用某些操作系统提供的函数的时候,比如read()函数,其会
对应于内核中的一个系统调用,然后该首先会进行一些常规的错误检测,接着进
行DAC(Discretionary Access Control)检测,再接着它会进行LSM检测。从上
图中能够看出来,LSM其实是一个非常底层的安全策略框架,利用LSM,可以接管
所有的系统调用,这样,我们就能对包括root在内的所有用户的权限进行控制,
并且实现粒度更细的访问权限控制。
当系统初始化的时候,LSM就是一个空的框架,它不提供任何的检测,其所
做的全部工作几乎就是返回0,当然,有些不带返回值的函数除外。而我们则可
以针对自己特定的需求来编写LSM,然后将我们编写的LSM钩子函数,通过其数据
结构struct security_operations注册到系统中去,这样,我们的LSM检测就开
始起作用了。
更多信息可参考《Linux就该这么学》