LVM

LVM commands # lvreduce, 用于减小 LVM 逻辑卷(Logical Volume)的大小 # -r, 同时调整(resize)文件系统的大小(调用 resize2fs xfs_growfs 等) # -L -40G 减小逻辑卷的大小 40GB(注意 - 表示减小) # /dev/ubuntu-vg/root 要调整的逻辑卷路径(通常是根分区) sudo lvreduce -r -L -40G /dev/ubuntu-vg/root LVM 的基本概念 通过 LVM 技术,可以屏蔽掉磁盘分区的底层差异,在逻辑上给文件系统提供了一个卷的概念,然后在这些卷上建立相应的文件系统。下面是 LVM 中主要涉及的一些概念。 PM 物理存储设备 (Physical Media): 指系统的存储设备文件,比如 某一块硬盘, /dev/sda、/dev/sdb 等。 或者 设备映射器(Device Mapper)管理的加密分区. /dev/mapper/nvme0n1p8_crypt PV (物理卷 Physical Volume): PV 可以看做是硬盘上的分区, 指硬盘分区或者从逻辑上看起来和硬盘分区类似的设备 (比如 RAID 设备)。 PE (Physical Extent):PV(物理卷)中可以分配的最小存储单元称为 PE,PE 的大小是可以指定的。 VG (卷组, Volume Group): 卷组: 物理卷的组合. 类似于非 LVM 系统中的物理硬盘,一个 LVM 卷组由一个或者多个 PV(物理卷) 组成。 卷组是 LVM 的中间层,VG 将多个物理卷(Physical Volumes, PV)组合在一起, 以便在其上创建逻辑卷(Logical Volumes, LV)。 ...

2015-10-12 · 3 min · 635 words · -

文本处理命令, text command

文本处理命令, text command sort command 排序规则受 LC_COLLATE 影响 LC_COLLATE=C 适用于 ASCII 编码, 按ASCII 排序 LC_COLLATE=C.UTF-8 适用于包含中文或者其它非 ascii 字符的情况, 对于英文或符号也是按ASCII排序 LC_COLLATE=en_US.UTF-8 这种情况 sort 在排序时会忽略大小写, 不是严格的按 ASCII 排序 LC_COLLATE=C 或 LC_COLLATE=C.UTF-8 的情况, 如果想忽略大小写, 可以加参数 -f, –ignore-case On Linux, when LC_COLLATE=“en_US.UTF-8” the LC_COLLATE definiton is non-standard. The default behavior of sort is to ignore-case and lowercase has precedence over uppercase. echo -e "c\nb\nB\na" | LC_COLLATE=C sort # 以 ',' 作为分隔符, 用第一列排序 sort -t ',' -k 1 foo.csv # 以 ',' 作为分隔符, 用第二列排序 sort -t ',' -k 2 foo.csv 命令说明: 将文本文件的内容按行排序。 sort将文件/文本的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按 ASCII 码值进行比较,最后将他们按升序输出 ...

2015-09-17 · 3 min · 502 words · -

NIO

NIO JavaNIO 非堵塞应用通常适于I/O 读写等方面, 我们知道, 系统运行的性能瓶颈通常在I/O读写,包括对网络和磁盘的操作上, 过去,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情, 那么改进做法就是开设线程, 让线程去等待, 但是这样做也是相当耗费资源的(线程调度) Java NIO 非堵塞技术实际是采取 Reactor 模式, 或者说是 Observer 模式为我们监察I/O端口,如果有内容进来, 会自动通知我们,这样,我们就不必开启多个线程死等, 从外界看, 实现了流畅的I/O读写,不堵塞了。 Java NIO 出现不只是一个技术性能的提高,你会发现网络上到处在介绍它,因为它具有里程碑意义,从JDK1.4开始,Java开始提高性能相关的功能,从而使得Java在底层或者并行分布式计算等操作上已经可以和C或Perl等语言并驾齐驱。 IO 模型主要分类 同步 synchronous IO 异步 asynchronous IO 阻塞 blocking 非阻塞 (non-blocking) NIO 同步阻塞, blocking-IO, BIO 同步非阻塞, non-blocking-IO, NIO 异步阻塞: 不存在的… 异步非阻塞, Asynchronous-non-blocking-IO, AIO 同步, 异步 同步和异步关注的是消息通信机制 ( synchronous communication/ asynchronous communication ) 同步: 发送一个请求,等待返回, 再发送下一个请求,同步可以避免出现死锁,脏读的发生。 异步: 发送一个请求,不等待返回, 随时可以再发送下一个请求,可以提高效率,保证并发。 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。 举个通俗的例子: 你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了 (可能是5秒,也可能是一天) 告诉你结果 (返回结果) 。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了 (不返回结果) 。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。 ...

2015-08-31 · 2 min · 294 words · -

who

Linux 查看用户, 当前登录用户, 登录日志 # 查看 ssh 上已经连接的用户、session # 查看登录用户正在使用的进程信息 w who who -a netstat -tnpa | grep ‘ESTABLISHED.*sshd’ ps auxwww | grep sshd: ps ax | grep sshd /etc/shadow 和 /etc/passwd 系统存在的所有用户名 more /var/log/secure who /var/log/wtmp 干了些什么? root账户下输入su - username 切换到username下输入 history 能看到这个用户历史命令,默认最近的1000条 http://blog.csdn.net/wudiyi815/article/details/8061459 作为系统管理员,你可能经常会 (在某个时候) 需要查看系统中有哪些用户正在活动。有些时候,你甚至需要知道他 (她) 们正在做什么。本文为我们总结了4种查看系统用户信息 (通过编号 (ID) ) 的方法。 w w命令用于显示已经登录系统的用户的名称,以及他们正在做的事。该命令所使用的信息来源于/var/run/utmp文件。w命令输出的信息包括: USER 用户名称 tty 用户的机器名称或tty号 FROM 远程主机地址 LOGIN@ 用户登录系统的时间 IDLE 空闲时间, 时间格式: 22:29m(22h29m), 46.00s, 27:47(27m47s) JCPU 附加到 tty (终端) 的进程所用的时间 PCPU 当前进程所用时间 WHAT 用户当前正在使用的命令 IDLE The idle time is supposed to tell how long it has been since the user typed any input on that terminal. For Xwindows sessions, it is broken since Xwindows never reads input from a terminal, but instead gathers input directly from your mouse and keyboard, so the terminal never gets its timestamp updated since it is never read from. ...

2015-08-27 · 2 min · 281 words · -

unix domain socket, UDS

unix domain socket, UDS ss -nxp ss -nxlp http://blog.csdn.net/bingqingsuimeng/article/details/8470029 http://blog.chinaunix.net/uid-20511624-id-1659107.html 什么是Socket Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程式员能够用他们来研发TCP/IP网络上的应用程式。要学Internet上的TCP/IP网络编程,必须理解Socket接口。 Socket接口设计者最先是将接口放在Unix操作系统里面的。假如了解 Unix 系统的输入和输出的话,就很容易了解 Socket 了。网络的 Socket数据传输是一种特别的I/O,Socket也是一种文档描述符。Socket也具备一个类似于打开文档的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种: 流式Socket (SOCK_STREAM) 和数据报式Socket (SOCK_DGRAM) 。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 Socket 建立 为了建立Socket,程式能够调用Socket函数,该函数返回一个类似于文档描述符的句柄。socket函数原型为: int socket(int domain, int type, int protocol); domain指明所使用的协议族,通常为PF_INET,表示互连网协议族 (TCP/IP协议族) ;type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket (SOCK_RAW) ,允许程式使用低层协议;protocol通常赋值"0"。 Socket()调用返回一个整型socket描述符,您能够在后面的调用使用他。 Socket描述符是个指向内部数据结构的指针,他指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上"建立一个Socket"意味着为一个Socket数据结构分配存储空间。Socket执行体为您管理描述符表。 两个网络程式之间的一个网络连接包括五种信息: 通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。 Socket配置 通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端连同面向连接socket的服务端通过调用 bind函数来配置本地信息。 Bind函数将socket和本机上的一个端口相关联,随后您就能够在该端口监听服务请求。Bind函数原型为: int bind(int sockfd,struct sockaddr *my_addr, int addrlen); Sockfd是调用socket函数返回的socket描述符,my_addr是个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被配置为sizeof(struct sockaddr)。 struct sockaddr结构类型是用来保存socket信息的: struct sockaddr { unsigned short sa_family; /地址族, AF_xxx/ char sa_data[14]; /14 字节的协议地址/ ...

2015-08-26 · 6 min · 1223 words · -

archlinux hibernate

archlinux hibernate edit config file /etc/mkinitcpio.conf add resume field sudo vim /etc/mkinitcpio.conf HOOKS=(base udev resume autodetect modconf block filesystems keyboard fsck) Configure the initramfs When an initramfs with the base hook is used, which is the default, the resume hook is required in /etc/mkinitcpio.conf. Whether by label or by UUID, the swap partition is referred to with a udev device node, so the resume hook must go after the udev hook. This example was made starting from the default hook configuration: ...

2015-08-08 · 1 min · 155 words · -

archlinux install

archlinux install download iso https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/ curl -O https://mirrors.tuna.tsinghua.edu.cn/archlinux/iso/2025.10.01/archlinux-2025.10.01-x86_64.iso Ventoy, usb-stick yay -S ventoy-bin copy to ventoy usb partition 用 ventoy U 盘引导系统 启动 sshd 设置 root 密码 进入 root@archiso 之后先设置 root 密码 passwd 连无线网 # 20250501, archlinux 的 iso 里默认已经安装 wpa_supplicant # start systemd-networkd and systemd-resolved service systemctl start systemd-networkd systemctl start systemd-resolved.service # wifi network 有默认配置 /etc/systemd/network/wifi.network # 设置 wifi 密码, 注意后面的 wlp3s0 替换成无线网卡的名字, 用 `ip a` 看一下 # psk 里写明文的密码 cat /etc/wpa_supplicant/wpa_supplicant-wlp3s0.conf network={ ssid="w1100n" psk="wifi_password_0" } sudo systemctl start wpa_supplicant@wlp3s0 systemctl start sshd 在 virtual box 里安装得设置一下端口映射 ...

2015-06-25 · 4 min · 655 words · -

systemd, systemctl basic, command

systemd, systemctl basic, command Systemd 是 Linux 系统中最新的初始化系统 (init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度 –now # enable and start service0 systemctl --now enable service0 Systemd 特性 系统引导时实现服务并行启动 按需启动守护进程 自动化的服务依赖关系管理 同时采用socket式与D-Bus总线式激活服务 系统状态快照 # 查看配置文件位置 systemctl status service0 # 修改配置之后重新加载配置文件 systemctl daemon-reload 配置文件主要放在 /usr/lib/systemd/system 目录, 也可能在/etc/systemd/system 目录 /lib/systemd/system:系统默认的单元文件 /etc/systemd/system:用户安装的软件的单元文件 /usr/lib/systemd/system:用户自己定义的单元文件 systemd-analyze 查看启动耗时 systemd-analyze # 查看每个服务的启动耗时 systemd-analyze blame # 显示瀑布状的启动过程流 # 打印严重消耗时间的服务树状表,按照启动消耗的时间进行排序,时间消耗越多,越排到前面。 @之后是服务激活或者启动的时间, +号之后是服务启动消耗的时间。 个人理解 @ 是从系统引导到服务启动起来的时间,是一个相对时间消耗,+是服务启动消耗的时间,是一个绝对时间消耗。 systemd-analyze critical-chain # 显示指定服务的启动流 比如 docker.service systemd-analyze critical-chain docker.service systemd 版本/version systemctl --version # 生成一张启动详细信息矢量图, .svg可以用chrome打开 sudo systemd-analyze plot > /home/wiloon/tmp/boot3.svg timedatectl # 查看当前时区设置 $ timedatectl # 显示所有可用的时区 $ timedatectl list-timezones # 设置当前时区 $ sudo timedatectl set-timezone America/New_York $ sudo timedatectl set-time YYYY-MM-DD $ sudo timedatectl set-time HH:MM:SS ## timedatectl ntp timedatectl set-ntp true loginctl # 列出当前session loginctl list-sessions # 列出当前登录用户 loginctl list-users # 列出显示指定用户的信息 loginctl show-user wiloon ## 查看 session 类型, 是 X server 还是 wayland, x or wayland loginctl show-session <SESSION_ID> -p Type cat systemctl cat bluetooth|grep Condition mask systemctl mask service0 systemctl unmask service0 check the boot performance systemd-analyze blame systemctl list-timers --all # 查看是否启用 systemctl is-enabled service0 # to see which units have failed. systemctl --failed # 退出系统并关闭电源 systemctl poweroff systemctl reboot # CPU 停止工作 $ sudo systemctl halt # 待机 systemctl suspend systemctl hibernate # 混合休眠模式 (同时休眠到硬盘并待机) : systemctl hybrid-sleep # list all service systemctl systemctl list-unit-files | grep enabled # 查看所有单元 $ systemctl list-unit-files # 查看所有 Service 单元 $ systemctl list-unit-files --type service # 查看所有 Timer 单元 $ systemctl list-unit-files --type timer 显示所有已启动的服务 systemctl list-units --type=service systemctl is-active httpd.service (仅显示是否 Active) # check service enabled systemctl list-unit-files |grep enabled # 查看服务是否开机启动 systemctl is-enabled foo.service # 禁止 foo.service 开机启动 systemctl disable foo.service # 禁止 foo.service 开机启动, 同时停掉服务 systemctl --now disable foo.service journalctl -f systemd-analyze blame systemctl --type=service systemctl status xxx systemctl status Loaded行: 配置文件的位置,是否设为开机启动 Active行: 表示正在运行 Main PID行: 主进程ID Status行: 由应用本身 (这里是 httpd ) 提供的软件当前状态 CGroup块: 应用的所有子进程 日志块: 应用的日志 # 打印完整的控制台日志, 不加 -l 的话, 默认会截断. systemctl status service0 -l http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html ...

2015-05-04 · 4 min · 665 words · -

文件存储和删除的过程

查找文件 通过文件名打开文件时,通过文件名先找到对应的inode,然后通过inode找到文件内容所在的block来读取数据。 文件存储和删除的过程 https://blog.csdn.net/MyySophia/article/details/107696414 创建文件 /tmp/a.txt 首先从 inode table 中找一个空闲的 inode 号分配给 a.txt,例如 2222。再将 inode map(imap) 中 2222 这个 inode 标记为已使用。 在 /tmp 的 data block 中添加一条 a.txt 文件的记录。该记录中包括一个指向 inode 的指针,例如 “0x2222”。 然后从 block map (bmap) 中找出空闲的 data block,并开始将 a.txt 中的数据写入到 data block 中。每写一段空间 ( ext4 每次分配一段空间 ) 就从 bmap 中找一次空闲的 data block, 直到存完所有数据。 设置 inode table 中关于 2222 这条记录的 data block 指针, 通过该指针可以找到 a.txt 使用了哪些 data block。 删除文件的过程 /tmp/a.txt 在 inode table 中删除指向 a.txt 的 data block 指针。这里只要一删除,外界就找不到 a.txt 的数据了。但是这个文件还存在,只是它是被"损坏"的文件,因为没有任何指针指向数据块。 在 imap 中将 2222 的 inode 标记为未使用。于是这个 inode 就被释放,可以被后续的文件重用。 删除父目录 /tmp 的 data block 中关于 a.txt 的记录。 这里只要一删除,外界就看不到也找不到这个文件了。 在 bmap 中将 a.txt 占用的 block 标记为未使用。这里被标记为未使用后,这些 data block 就可以被后续文件覆盖重用。 考虑一种情况,当一个文件被删除时,但此时还有进程在使用这个文件,这时是怎样的情况呢?外界是看不到也找不到这个文件的,所以删除的过程已经进行到了第 3 步。但进程还在使用这个文件的数据,也能找到这个文件的数据,是因为进程在加载这个文件的时候就已经获取到了该文件占用哪些 data block,虽然删除了文件,但 bmap 中这些 data block 还没有标记为未使用。 ...

2015-04-23 · 1 min · 120 words · -

Linux 下删除正在进行读写操作的文件

Linux 下删除正在进行读写操作的文件 多进程环境下, 打开同一个文件, 进行读写操作过程中, 如果其中一个进程删除这个文件, 那么, 另外正在读写这个文件会发生什么呢? 因为文件被删除了, 正在读写的进程发生异常? 正在读写的进程仍然正常读写, 好像没有发现发生了什么? 删除文件,其实是删除 inode 和文件的对应关系,而 linux 文件系统只有当连接文件的 inode 数量为0,并且没有程序在使用这个文件时,才会标记文件内容所在的数据块删除。 每个文件都有 2 个 link 计数器 - i_count 和 i_nlink。i_count 的意义是当前使用者的数量,i_nlink 的意义是介质连接的数量;或者可以理解为 i_count 是内存引用计数器,i_nlink 是硬盘引用计数器。再换句话说,当文件被某个进程引用时,i_count 就会增加;当创建文件的硬连接的时候,i_nlink 就会增加。 对于 rm 而言,就是减少 i_nlink。这里就出现一个问题,如果一个文件正在被某个进程调用,而用户却执行 rm 操作把文件删除了,会出现什么结果呢? 当用户执行 rm 操作后,ls 或者其他文件管理命令不再能够找到这个文件,但是进程却依然在继续正常执行,依然能够从文件中正确的读取内容。这是因为,rm 操作只是将 i_nlink 置为 0 了;由于文件被进程引用的缘故,i_count 不为 0,所以系统没有真正删除这个文件。i_nlink 是文件删除的充分条件,而 i_count 才是文件删除的必要条件。 基于以上只是,大家猜一下,如果在一个进程在打开文件写日志的时候,手动或者另外一个进程将这个日志删除,会发生什么情况? 是的,数据库并没有停掉。虽然日志文件被删除了,但是有一个进程已经打开了那个文件,所以向那个文件中的写操作仍然会成功,数据仍然会提交。 下面,告诉大家如何恢复那个删除的文件。 例如,你删除了 tcpdump.log, 执行 lsof | grep tcpdump.log,你应该能看到这样的输出: tcpdump 2864 tcpdump 4w REG 253,0 0 671457 /root/tcpdump.log (deleted) ...

2015-04-22 · 1 min · 167 words · -

free command

free command free命令可以查看系统内存的使用情况,-m 参数表示按照兆字节展示。最后两列分别表示用于IO缓存的内存数, 和用于文件系统页缓存的内存数。需要注意的是, 第二行-/+ buffers/cache,看上去缓存占用了大量内存空间。 这是Linux系统的内存使用策略,尽可能的利用内存,如果应用程序需要内存,这部分内存会立即被回收并分配给应用程序。因此,这部分内存一般也被当成是可用内存。 如果可用内存非常少,系统可能会动用交换区 (如果配置了的话) ,这样会增加IO开销 (可以在iostat命令中提现) ,降低系统性能。 free -h free -m total used free shared buff/cache available Mem: 8.7Gi 4.6Gi 437Mi 1.0Mi 3.8Gi 3.9Gi Swap: 0B 0B 0B Mem:表示物理内存统计。 total:表示物理内存总量( total = used + free + buff/cache )。 used:total - free - buff/cache, 表示总计分配给缓存 (包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用。 free:未被分配的内存。 shared:共享内存。Memory used (mostly) by tmpfs (Shmem in /proc/meminfo) buffers:kernel buffers, 系统分配但未被使用的buffers数量。 cached:page cache and slabs, 系统分配但未被使用的cache数量。 available: 启动新的应用程序时可以使用的内存, buffers/cache:表示物理内存的缓存统计。 used2:也就是第一行中的used – buffers - cached也是实际使用的内存总量。 // used2为第二行 free2 = buffers1 + cached1 + free1 // free2为第二行,buffers1等为第一行 free2:未被使用的buffers与cache和未被分配的内存之和,这就是系统当前实际可用内存。 Swap:表示硬盘上交换分区的使用情况。

2015-02-10 · 1 min · 91 words · -

协程, Coroutine

协程, Coroutine 协程别名: 微线程,纤程。英文:Coroutine, Green threads, fibers 传统编程语言中子程序或者函数是层级调用的,函数可以调用其它函数, 调用者需要等待被调用者结束之后继续执行, 函数调用是通过栈实现的. 一个线程就是按顺序执行一个或几个子函数, 函数调用只有一个入口和一个出口. 协程看上去也是函数,但是执行过程中在子程序内部可以中断,然后执行别的函数, 然后再被调度回来执行. 协程比线程有更高的执行效率, 协程没有线程切换的开销 协程在用户空间调度, 不涉及系统调用或任何阻塞调用, 不需要用来守卫关键区块的同步性原语(primitive)比如互斥锁、信号量等,并且不需要来自操作系统的支持 协程不需要多线程的锁机制, 为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。 协程是协作式多任务的, 线程典型是抢占式多任务的 因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。 使用抢占式调度的线程实现协程,但是会失去某些利益(特别是对硬性实时操作的适合性和相对廉价的相互之间切换)。 协程是语言层级的构造,可看作一种形式的控制流,而线程是系统层级的构造 生成器 生成器,也叫作“半协程”[8],是协程的子集。 https://www.liaoxuefeng.com/wiki/1016959663602400/1017968846697824 https://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B 有栈协程 有栈协程的好处,由于栈帧可以直接完全保存运行期上下文(主要是寄存器值),因此可以在任何时刻暂停协程的运行,这就很方便地支持了抢占式的调度器。 无栈协程 有栈协程的好处,由于栈帧可以直接完全保存运行期上下文(主要是寄存器值),因此可以在任何时刻暂停协程的运行,这就很方便地支持了抢占式的调度器。而无栈协程的上下文是一般通过类似结构体的方式保存在内存中,它依赖使用者显式地切换协程,否则协程不会主动让出执行权。 另外,有栈协程更方便将同步代码改造为异步代码,就像我们的例子一样,只需改动一行,加上go关键字就可以了。而无栈协程,同步改造为异步则更为复杂,甚至会导致牵一发动全身(async关键字扩散问题)。 Rust无栈协程 既然已经有了有栈协程,那么无栈协程是否还有优势呢。答案肯定的! 通常,无栈协程在内存空间和协程上下文切换的效率更高。值得说明的是,无栈协程并不是说不需要运行时的栈空间,而是和协程的创建者共用同一块运行时的栈空间。 如果一定要用一句话概括无栈协程,那就是:无栈协程可以看做是有状态的函数(generator),每次执行时会根据当前的状态和输入参数,得到(generate)输出,但不一定为最终结果。

2015-02-04 · 1 min · 39 words · -

bash

bash # -n 选项代表只检查语法,不执行脚本。 bash -n foo.sh # -n 或 --noexec 选项告诉 Bash:只读取并检查脚本的语法是否正确,但不会实际执行脚本中的任何命令。 bash -c 用法: bash -c "cmd string" 通常使用shell去运行脚本,两种方法 bash xxx.sh,另外一种就是bash -c “cmd string” 对于bash xxx.sh, 首先bash 会在当前目录去寻找xxx.sh,如果找到,就直接运行,找不到则按照环境变量$PATH的指定路径,按顺序去找,如果找到,则执行,找不到则报错。 shell 脚本的参数 $0 就是要执行的 shell 脚本 xxx.sh, $1 就是后面紧跟 xxx.sh 的参数,$2 $3依次类推 而对于bash -c “cmd string” 首先我们看看官方的说明解释 -c If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, they are assigned to the positional parameters, starting with $0. ...

2015-01-06 · 1 min · 174 words · -

WinSCP 的四种协议:SFTP(SSH)、FTP、SCP、WebDAV

WinSCP的四种协议:SFTP(SSH)、FTP、SCP、WebDAV 1、FTP FTP(File Transfer Protocol,文件传输协议),通过端口进行文件传输: 端口21,控制链路,用于发送指令给服务器并等待服务器响应; 端口20,数据链路,用来建立数据传输通道。 使用FTP协议可能会存在一些安全隐患,例如FTP服务器软件的漏洞、明文口令、通过FTP服务器进行端口扫描、数据劫持等。 参考:https://baike.baidu.com/item/FTP协议/7651119?fr=aladdin 2.SFTP(SSH) SSH (SSH File Transfer Protocol) 又称 SFTP(Secret File Transfer Protocol),安全文件传送协议,为传输文件提供一种安全的加密方法。 SFTP是SSH内含的协议,只要SSHD服务器启动了就可用,不需要FTP服务器启动才能用。 对网络安全性要求高时,建议使用SFTP。由于SFTP采用加密传输认证信息和数据,所以SFTP十分安全,但是传输效率就比FTP要低的多。 参考:https://baike.baidu.com/item/SSH文件传输协议?fromtitle=sftp&fromid=1184182 3、SCP SCP(secure copy),用来进行远程文件拷贝,使用和SSH相同的认证方式,提供相同的安全保障。 参考:https://www.cnblogs.com/mxh1099/p/5554823.html 4、WebDAV WebDAV一种基于HTTP1.1的扩展协议, 在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法, 使应用程序对Web Server直接读写,并支持写文件锁定及解锁,还可以支持文件的版本控制。 参考:https://baike.baidu.com/item/WebDAV https://www.cnblogs.com/bors/p/WinSCP.html run winscp from cmd winscp.exe /ini="C:\Users\martin\Documents\myconfig.ini"

2014-12-23 · 1 min · 40 words · -

netdata

netdata pacman -S netdata systemctl start netdata systemctl enable netdata vim /etc/netdata/netdata.conf [web] bind to = 0.0.0.0 [::]

2014-12-23 · 1 min · 18 words · -

Linux中的各种锁, 自旋锁/spin lock, 排队自旋锁、MCS锁、CLH锁,

Linux中的各种锁, 自旋锁/spin lock, 排队自旋锁、MCS锁、CLH锁 Linux中的各种锁 互斥锁 文件锁 读写锁 Linux作为典型的多用户、多任务、抢占式内核调度的操作系统,为了提高并行处理能力,无论在内核层面还是在用户层面都需要特殊的机制来确保任务的正确性和系统的稳定运行,就如同一个国家需要各种法律条款来约束每个公民的行为,才能有条不紊地运转。 在内核层面涉及到各种软硬件中断、进线程睡眠、抢占式内核调度、多处理器SMP架构等,因此内核在完成自己工作的时候一直在处理这些资源抢占的冲突问题。 在用户层面的进程,虽然Linux作为虚地址模式操作系统,为每个进程开辟了独立的虚拟地址空间,伪独占式拥有资源,但是仍然存在很多场景不得不产生多个进程共享资源的问题,来完成进程间的通信,但是在Go语言中进程间的通信使用消息来完成,处理地更优雅一些。 在线程层面,线程作为进程的一部分,进程内的多个线程只拥有自己的独立堆栈等少量结构,大部分的资源还是过线程共享,因此多线程的资源占用冲突比进程更加明显,所以多线程编程的线程安全问题是个重难点。综上可知,无论在kernel还是user space都必须有一些机制来确保对于资源共享问题的解决,然后这个机制就是接下来要说的: 同步和互斥。 同步和互斥机制 基本概念 同步和互斥的概念有时候很容易混淆,可以简单地认为同步是更加宏观角度的一种说法,互斥是冲突解决的细节方法。所谓同步就是调度者让任务按照约定的合理的顺序进行,但是当任务之间出现资源竞争,也就是竞态冲突时,使用互斥的规则强制约束允许数量的任务占用资源,从而解决各个竞争状态,实现任务的合理运行。 同步和互斥密不可分,有资料说互斥是一种特殊的同步,对此我不太理解,不过实际中想明白细节就行,文字游戏没有意义。 简单来说: 同步与互斥机制是用于控制多个任务对某些特定资源的访问策略 同步是控制多个任务按照一定的规则或顺序访问某些共享资源 互斥是控制某些共享资源在任意时刻只能允许规定数量的任务访问 角色分类 整个协调流程涉及的角色本质上只有三类: 不可独占的共享资源 多个使用者 调度者 调度者需要为多个运行任务制定访问使用规则来实现稳定运行,这个调度者可以是内核、可以是应用程序,具体场景具体分析。 重要术语 要很好地理解同步和互斥,就必须得搞清楚几个重要术语: 竞争冒险(race hazard)或竞态条件(race condition) 最早听说这个术语是在模电数电的课程上,门电路出现竞态条件造成错误的结果,在计算机里面就是多个使用者同时操作共享的变量造成结果的不确定。 临界区 临界区域critical section是指多使用者可能同时共同操作的那部分代码,比如自加自减操作,多个线程处理时就需要对自加自减进行保护,这段代码就是临界区域。 Linux中常用的锁 在说锁之前还需要知道几个东西:信号量和条件变量。这两个东西和锁有一定的联系和区别,在不同的场合单独使用或者配合实现来说实现安全的并发,至于网上很多说互斥锁是一种信号量的特例,对于这种特例理解不了也罢。信号量和互斥锁的场景不一样,信号量主要是资源数量的管理(池化),实际用的频率远不如互斥锁,文字游戏着实无趣,实用主义至上,掌握高频工具的特点正确使用即可,大可不必过于学术派。在使用锁时需要明确几个问题: 锁的所有权问题 谁加锁 谁解锁 解铃还须系铃人 锁的作用就是对临界区资源的读写操作的安全限制 锁是否可以被多个使用者占用(互不影响的使用者对资源的占用) 占用资源的加锁者的释放问题 (锁持有的超时问题) 等待资源的待加锁者的等待问题(如何通知到其他等着资源的使用者) 多个临界区资源锁的循环问题(死锁场景) 带着问题明确想要达到的目的,我们同样可以根据自己的需求设计锁,Linux现有的锁如果从上面几个问题的角度去理解,就非常容易了。 自旋锁 spinlock 自旋锁的主要特征是使用者在想要获得临界区执行权限时,如果临界区已经被加锁,那么自旋锁并不会阻塞睡眠,等待系统来主动唤醒,而是原地忙轮询资源是否被释放加锁,自旋就是自我旋转,这个名字还是很形象的。自旋锁有它的优点就是避免了系统的唤醒,自己来执行轮询,如果在临界区的资源代码非常短且是原子的,那么使用起来是非常方便的,避免了各种上下文切换,开销非常小,因此在内核的一些数据结构中自旋锁被广泛的使用。 互斥锁 mutex 使用者使用互斥锁时在访问共享资源之前对进行加锁操作,在访问完成之后进行解锁操作,谁加锁谁释放,其他使用者没有释放权限。 加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前进程解锁。 区别于自旋锁,互斥锁无法获取锁时将阻塞睡眠,需要系统来唤醒,可以看出来自旋锁自己原地旋转来确定锁被释放了,互斥锁由系统来唤醒,但是现实并不是那么美好的,因为很多业务逻辑系统是不知道的,仍然需要业务线程执行while来轮询是否可以重新加锁。考虑这种情况: 解锁时有多个线程阻塞,那么所有该锁上的线程都被变成就绪状态, 第一个变为就绪状态的线程又执行加锁操作,那么其他的线程又会进入等待,对其他线程而言就是虚假唤醒。 在这种方式下,只有一个线程能够访问被互斥锁保护的资源。 读写锁, 共享互斥锁, rwlock 读写锁也叫共享互斥锁: 读模式共享和写模式互斥,本质上这种非常合理,因为在数据没有被写的前提下,多个使用者读取时完全不需要加锁的。读写锁有读加锁状态、写加锁状态和不加锁状态三种状态,当读写锁在写加锁模式下,任何试图对这个锁进行加锁的线程都会被阻塞,直到写进程对其解锁。 读优先的读写锁: 读写锁 rwlock 默认的也是读优先,也就是:当读写锁在读加锁模式先,任何线程都可以对其进行读加锁操作,但是所有试图进行写加锁操作的线程都会被阻塞,直到所有的读线程都解锁,因此读写锁很适合读次数远远大于写的情况。这种情况需要考虑写饥饿问题,也就是大量的读一直轮不到写,因此需要设置公平的读写策略。在一次面试中曾经问到实现一个写优先级的读写锁,感兴趣的可以想想如何实现。 ...

2014-12-05 · 2 min · 326 words · -

DMA

DMA DMA的基本定义 DMA,全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。 DMA的主要特征 ·每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发,这些功能通过软件来配置。 ·在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)。 ·独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。 ·支持循环的缓冲器管理。 ·每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。 ·存储器和存储器间的传输、外设和存储器、存储器和外设之间的传输。 ·闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。 ·可编程的数据传输数目:最大为65535(0xFFFF)。 STM32F411x系列芯片DMA控制器 DMA的工作框图如下图所示。DMA控制器和Cortex™-M4核心共享系统数据总线,执行直接存储器数据传输。当CPU和DMA同时访问相同的目标(RAM或外设)时,DMA请求会暂停CPU访问系统总线达若干个周期,总线仲裁器执行循环调度,以保证CPU至少可以得到一半的系统总线(存储器或外设)带宽。 DMA控制器传输作为AHB主设备操作直接存储器,它可以控制AHB总线的控制矩阵以启动AHB传送。它可以执行以下信息交换: •外设到内存 •内存到外设 •内存到内存 DMA控制器提供两个AHB主端口:AHB内存端口(用于连接到内存)和AHB外设端口(用于连接到外设)。 但是,为了允许内存到内存的传输,AHB外设端口也必须可以访问内存。AHB从端口用于对DMA控制器的编程控制(仅支持32位访问)。 DMA处理 对于两个DMA控制器的系统实现如下图所示。DMA1控制器AHB外设端口没有像DMA2控制器那样连接到总线矩阵,所以只有DMA2能够执行内存到内存的数据传输。 DMA事务由给定数量的数据传输序列组成,可以传输的数据项的数量及其宽度(8位,16位或32位)可以通过软件编程实现。每个DMA传输都包含三个操作步骤: ·从外设数据寄存器或者从当前外设/存储器地址寄存器指示的存储器地址取数据,第一次传输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元; ·存数据到外设数据寄存器或者当前外设/存储器地址寄存器指示的存储器地址,第一次传输时的开始地址是DMA_CPARx或DMA_CMARx寄存器指定的外设基地址或存储器单元; ·执行一次DMA_CNDTRx寄存器的递减操作,该寄存器包含未完成的操作数目。 通道选择 事件发生后,外设向DMA控制器发送请求信号,DMA控制器根据通道优先级来处理请求。当DMA控制器访问外围设备时,确认信号即由DMA控制器发送到外围设备,一旦外围设备从DMA控制器收到确认信号,它就会释放其请求,当外设取消了该请求后,DMA控制器将释放确认信号。 如果外设还有更多请求,它可以启动下一轮请求操作。 每个数据流流都与一个DMA请求相关,该DMA请求可以从8个可能的通道请求中选择,由DMA_SxCR寄存器中的CHSEL [2:0]位控制。 来自外设(TIM,ADC,SPI,I2C等)的8个请求独立连接到每个通道如下图所示: 仲裁器 仲裁器根据通道请求的优先级来启动外设/存储器的访问。优先权管理分2个阶段: ·软件:每个通道的优先权可以在DMA_CCRx寄存器中设置,有4个等级:最高优先级、高优先级、中等优先级、低优先级; ·硬件:如果2个请求有相同的软件优先级,则较低编号的通道比较高编号的通道有较高的优先权。比如:如果软件优先级相同,通道2优先于通道4。 注意: 在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级。 DMA通道数据量 每个通道都可以在有固定地址的外设寄存器和存储器地址之间执行DMA传输。DMA传输的数据量是可编程的,最大达到65535(0xFFFF)。包含要传输的数据项数量的寄存器,在每次传输后递减。外设和存储器的传输数据量可以通过DMA_CCRx寄存器中的PSIZE和MSIZE位编程得到。 DMA传输模式 数据传输源和目的地都可以寻址整个4 GB区域中的外围设备和存储器,其地址介于0x0000 0000和0xFFFF FFFF之间。传输方向使用DMA_SxCR寄存器中的DIR [1:0]位进行配置,并提供三种可能性:存储器到外围设备,外围设备到存储器或存储器到存储器的传输。 外设到存储器模式 使能此模式时(通过将DMA_SxCR寄存器中的EN位置1),每次发生外设请求时,数据流都会启动传输从数据源来填充到FIFO。当达到FIFO的阈值水平时,FIFO的内容被清空并存储到目标地址。 当外设请求结束传输时(对于外设流控制器),或当DMA_SxNDTR寄存器达到零时或将DMA_SxNDTR寄存器中的EN位清零,则传输停止。 当赢得了相应流的仲裁时,该数据流通道才可以访问AHB源或目标端口,使用DMA_SxCR寄存器中的PL [1:0]位,为每个数据流通道的优先级进行仲裁。 存储器到外设模式 使能该模式时(通过将DMA_SxCR寄存器中的EN位置1),该数据流通道立即启动传输,以完全填充FIFO。每次发生外设请求时,FIFO的内容都会被清空并存储到目的地。当FIFO未满时,会从内存中重新加载数据。 当外设请求结束传输时(对于外设流控制器),或者当DMA_SxNDTR寄存器达到零时或将DMA_SxNDTR寄存器中的EN位清零,则传输停止。 当赢得了相应流的仲裁时,该数据流通道才可以访问AHB源或目标端口,使用DMA_SxCR寄存器中的PL [1:0]位,为每个数据流通道的优先级进行仲裁。 存储器到存储器模式 配置同上。存储器到存储器模式不能与循环模式同时使用。 循环模式 循环模式可用于处理循环缓冲区和连续数据流(例如ADC扫描模式)。 可以使用DMA_SxCR寄存器中的CIRC位来启用此功能。使能循环模式后,将在数据流通道配置阶段使用初始值自动装载要传输的数据,并且DMA请求将继续。 中断 每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断。 对于每个DMA数据流通道,可以在以下事件上产生中断: •达到半转移 •转移完成 •传输错误 ...

2014-11-17 · 1 min · 171 words · -

semaphore/信号量, mutex/互斥锁

信号量 Semaphore 信号量是 Edsger Dijkstra 发明的数据结构,在解决多种同步问题时很有用。其本质是一个整数,并关联两个操作: 申请 acquire(也称为 wait、decrement 或 P 操作) 释放 release(也称 signal、increment 或 V 操作) acquire操作将信号量减 1,如果结果值为负则线程阻塞,且直到其他线程进行了信号量累加为正数才能恢复。如结果为正数,线程则继续执行。 release操作将信号量加 1,如存在被阻塞的线程,此时他们中的一个线程将解除阻塞。 Go 运行时提供的 runtime_SemacquireMutex 和runtime_Semrelease 函数可用来实现sync.RWMutex互斥锁。 semaphore/信号量, mutex/互斥锁 Mutex 是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。一般的用法是用于串行化对 critical section 代码的访问,保证这段代码不会被并行的运行。 Semaphore/信号量 是一件可以容纳 N 人的房间,如果人不满就可以进去,如果人满了, 就要等待有人出来. 对于N=1的情况,称为binary semaphore。一般的用法是,用于限制对于某一资源的同时访问。 Binary semaphore 与 Mutex 的差异 在 有的系统中 Binary semaphore 与 Mutex 是没有差异的。在有的系统上,主要的差异是mutex一定要由获得锁的进程来释放。而semaphore可以由其它进程释放 (这时的semaphore实际就是个原子的变量,大家可以加或减) ,因此semaphore可以用于进程间同步。Semaphore的同步功能是所有系统都支持的,而Mutex能否由其他进程释放则未定,因此建议mutex只用于保护critical section。而semaphore则用于保护某变量,或者同步。 关于semaphore和mutex的区别,网上有著名的厕所理论 (http://koti.mbnet.fi/niclasw/MutexSemaphore.html) : Mutex Mutex 的发音是 /mjuteks/ ,其含义为互斥(体),这个词是Mutual Exclude的缩写。 Is a key to a toilet. One person can have the key - occupy the toilet - at the time. When finished, the person gives (frees) the key to the next person in the queue. Officially: “Mutexes are typically used to serialise access to a section of re-entrant code that cannot be executed concurrently by more than one thread. A mutex object only allows one thread into a controlled section, forcing other threads which attempt to gain access to that section to wait until the first thread has exited from that section.” Ref: Symbian Developer Library(A mutex is really a semaphore with value 1.) ...

2014-10-31 · 5 min · 869 words · -

缓冲IO, 缓冲I/O, buffered I/O

缓冲IO, 缓冲I/O, buffered I/O 在系统调用的函数中有 STDIN_FILENO 和 STDOUT_FILENO, STDERR_FILENO, 分别对应标准输入(一般使键盘),标准输出 (一般使显示器),标准错误,(他们都是非负整数,属于文件描述符)。一般在老程序中也将他们分别用 0,1,2 代替,但建议还是使用他们的别名。 在标准IO函数中还有stdin,stdout,stderr等是 FILE * 类型,是属于文件指针,属于标准I/O,高级的输入输出函数。在<stdio.h>中。 而STDIN_FILENO等是文件描述符,是非负整数,一般定义为0, 1, 2,属于没有buffer的I/O,直接调用系统调用, 在<unistd.h>zh 。 stdin是文件指针,是FILE *类型 STDIN_FILENO是文件描述符,是int类型的 stdout和STDOUT_FILENO同样。 所以使用fread(,,stdin),而read(STDOUT_FILENO),因为函数的参数类型是不一样的 二. 下面使网上的一篇文章,讲解缓冲IO和不带缓冲IO 首先,先稍微了解系统调用的概念: 系统调用,英文名system call,每个操作系统都在内核里有一些内建的函数库,这些函数可以用来完成一些系统系统调用把应用程序的请求传给内核,调用相应的的内核函数完成所需的处理,将处理结果返回给应用程序,如果没有系统调用和内核函数,用户将不能编写大型应用程序,及别的功能,这些函数集合起来就叫做程序接口或应用编程接口(Application Programming Interface,API),我们要在这个系统上编写各种应用程序,就是通过这个API接口来调用系统内核里面的函数。如果没有系统调用,那么应用程序就失去内核的支持。 现在,再聊不带缓存的I/O操作: linix对IO文件的操作分为不带缓存的IO操作和标准IO操作 (即带缓存),刚开始,要明确以下几点: 1:不带缓存,不是直接对磁盘文件进行读取操作,像read()和write()函数,它们都属于系统调用,只不过在用户层没有缓存,所以叫做无缓存IO,但对于内核来说,还是进行了缓存,只是用户层看不到罢了。如果这一点看不懂,请看第二点; 2:带不带缓存是相对来说的,如果你要写入数据到文件上时 (就是写入磁盘上),内核先将数据写入到内核中所设的缓冲储存器,假如这个缓冲储存器的长度是100个字节,你调用系统函数: ssize_t write (int fd,const void * buf,size_t count); 写操作时,设每次写入长度count=10个字节,那么你几要调用10次这个函数才能把这个缓冲区写满,此时数据还是在缓冲区,并没有写入到磁盘,缓冲区满时才进行实际上的IO操作,把数据写入到磁盘上,所以上面说的“不带缓存不是就没有缓存直写进磁盘”就是这个意思。 那么,既然不带缓存的操作实际在内核是有缓存器的,那带缓存的IO操作又是怎么回事呢? 带缓存IO也叫标准IO,符合ANSI C 的标准IO处理,不依赖系统内核,所以移植性强,我们使用标准IO操作很多时候是为了减少对read()和write()的系统调用次数,带缓存IO其实就是在用户层再建立一个缓存区,这个缓存区的分配和优化长度等细节都是标准IO库代你处理好了,不用去操心,还是用上面那个例子说明这个操作过程: 上面说要写数据到文件上,内核缓存 (注意这个不是用户层缓存区)区长度是100字节,我们调用不带缓存的IO函数write()就要调用10次,这样系统效率低,现在我们在用户层建立另一个缓存区 (用户层缓存区或者叫流缓存),假设流缓存的长度是50字节,我们用标准C库函数的fwrite()将数据写入到这个流缓存区里面,流缓存区满50字节后在进入内核缓存区,此时再调用系统函数write()将数据写入到文件 (实质是磁盘)上,看到这里,你用该明白一点,标准IO操作fwrite()最后还是要掉用无缓存IO操作write,这里进行了两次调用fwrite()写100字节也就是进行两次系统调用write()。 如果看到这里还没有一点眉目的话,那就比较麻烦了,希望下面两条总结能够帮上忙: 无缓存IO操作数据流向路径:数据——内核缓存区——磁盘 标准IO操作数据流向路径:数据——流缓存区——内核缓存区——磁盘 三. 下面是一个网友的见解,以供参考: 不带缓存的I/O对是文件描述符操作,下面带缓存的I/O是针对流的。 标准I/O库就是带缓存的I/O,它由ANSI C标准说明。当然,标准I/O最终都会调用上面的I/O例程。标准I/O库代替用户处理很多细节,比如缓存分配、以优化长度执行I/O等。 标准I/O提供缓存的目的就是减少调用read和write的次数,它对每个I/O流自动进行缓存管理 (标准I/O函数通常调用malloc来分配缓存)。它提供了三种类型的缓存: 1) 全缓存。当填满标准I/O缓存后才执行I/O操作。磁盘上的文件通常是全缓存的。 2) 行缓存。当输入输出遇到新行符或缓存满时,才由标准I/O库执行实际I/O操作。stdin、stdout通常是行缓存的。 3) 无缓存。相当于read、write了。stderr通常是无缓存的,因为它必须尽快输出。 ...

2014-07-28 · 1 min · 133 words · -

虚拟文件系统

虚拟文件系统 为什么需要虚拟文件系统 虚拟文件系统 超级块,superblock inode 为什么需要虚拟文件系统 在 Linux 系统中一切皆文件,除了普通文件之外,目录、字符设备、块设备、套接字、进程、线程、管道等都是“文件”。 用户程序需要一个统一的操作接口屏蔽不同文件系统(ext2/3/4,xfs,vfat,socket)的差异和操作细节 在Linux中对文件的 操作可以跨文件系统而执行。如下图所示,我们可以使用 cp 命令从 fat 文件系统格式的硬盘拷贝数据到 ext2 文件系统格式的硬盘;而这样的操作涉及到两个不同的文件系统. 上层应用几乎不用关注底层的实现细节。我们只需要使用VFS暴露出来的标准的read、write等接口就可以了 通过VFS系统,Linux提供了通用的系统调用,可以跨越不同文件系统和介质之间执行,极大简化了用户访问不同文件系统的过程。 “一切皆是文件”是 Unix/Linux 的基本哲学之一。不仅普通的文件,目录、字符设备、块设备、 套接字等在 Unix/Linux 中都是以文件被对待;它们虽然类型不同,但是对其提供的却是同一套操作界面。 虚拟文件系统, Virtual File System,VFS VFS 是 Linux 内核中的一个软件层,是内核的子系统之一,为用户空间的程序提供文件和文件系统操作的统一接口,屏蔽不同文件系统的差异和操作细节 借助 VFS 可以直接使用open()、read()、write() 这样的系统调用操作文件,而无须考虑具体的文件系统和实际的存储介质。 通过 VFS,Linux 提供了通用的系统调用,可以跨越不同文件系统和介质之间执行,极大简化了用户访问不同文件系统的过程。另一方面,新的文件系统、新类型的存储介质,可以无须编译的情况下,动态加载到Linux中。 “一切皆文件"是Linux的基本哲学之一,不仅是普通的文件,包括目录、字符设备、块设备、套接字等,都可以以文件的方式被对待。实现这一行为的基础,正是Linux的虚拟文件系统机制。 VFS原理 VFS之所以能够衔接各种各样的文件系统,是因为它抽象了一个通用的文件系统模型,定义了通用文件系统都支持的、概念上的接口。新的文件系统只要支持并实现这些接口,并注册到Linux内核中,即可安装和使用。 虚拟文件系统组成部分 Linux为了实现这种VFS系统,采用面向对象的设计思路,主要抽象了四种对象类型: 超级块对象:代表一个已安装的文件系统。 索引节点对象:代表具体的文件。 目录项对象:代表一个目录项,是文件路径的一个组成部分。 文件对象:代表进程打开的文件。 每个对象都包含一组操作方法,用于操作相应的文件系统。 备注:Linux将目录当做文件对象来处理,是另一种形式的文件,它里面包含了一个或多个目录项。而目录项是单独抽象的对象,主要包括文件名和索引节点号。因为目录是可以层层嵌套,以形成文件路径,而路径中的每一部分,其实就是目录项。 接下来介绍一下各个对象的作用以及相关操作。 超级块, superblock 存储一个已安装的文件系统的控制信息(文件系统的状态、类型、大小、区块数、索引节点数等),代表一个已安装的文件系统;每次一个实际的文件系统被安装时, 内核会从磁盘的特定位置读取一些控制信息来填充内存中的超级块对象。一个安装实例和一个超级块对象一一对应。 超级块通过其结构中的一个域s_type记录它所属的文件系统类型。 superblock:记录此 filesystem 的整体信息,包括inode/block的总量、使用量、剩余量, 以及文件系统的格式与相关信息等; Superblock 是记录整个 filesystem 相关信息的地方, 没有 Superblock ,就没有这个 filesystem 了. ...

2014-04-14 · 5 min · 916 words · -