Linux 文件系统与设备文件
来源:互联网 发布:unity3d播放视频卡帧 编辑:程序博客网 时间:2024/05/22 05:05
概述
字符设备和块设备都良好的体现了“一切都是文件”的设计思想,掌握Linux文件系统、设备文件系统的知识就显得相当重要了
Linux 文件操作
int creat(const char *pathname, mode_t mode);
创建文件int open( const char *pathname, int flags, mode_t mode);
打开文件ssize_t read(int fd, void *buf, size_t count);
读文件ssize_t write(int fd, const void *buf, size_t count);
写文件off_t lseek(int fildes, off_t offset, int whence);
定位文件int close(int fd);
关闭文件
C 文件操作
FILE *fopen(const char *path, const char *mode);
打开文件size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
读文件size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
写文件int fseek(FILE *stream, long offset, int whence);
定位文件int fclose(FILE *stream);
关闭文件
基础示例
【代码仓库】
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <string.h>#define LENGTH 100void linux_file_sample(void){ int fd, len; char str[LENGTH]; fd = op den("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if(fd) { write(fd, "Hello World fromlinux_file_sample\n",strlen("Hello World from linux_file_sample\n")); close(fd); } fd = open("hello.txt", O_RDWR); len = read(fd, str, LENGTH); str[len] = '\0'; printf("%s\n", str); close(fd); }void c_file_sample(void){ FILE *fd; char str[LENGTH]; fd = fopen("hello.txt", "w+"); if(fd) { fputs("Hello World form c_file_sample\n", fd); fclose(fd); } fd = fopen("hello.txt", "r"); fgets(str, LENGTH, fd); printf("%s\n", str); fclose(fd);}int main(void){ linux_file_sample(); c_file_sample(); return 0;}
Makefile
# 可执行文件 TARGET=file # C文件 SRCS = file.c # 目标文件 OBJS = $(SRCS:.c=.o) # 指令编译器和选项 CC=gcc CFLAGS=-Wall -std=gnu99 $(TARGET):$(OBJS) # @echo TARGET:$@ # @echo OBJECTS:$^ $(CC) -o $@ $^ clean: rm -rf $(TARGET) $(OBJS) %.o:%.c $(CC) $(CFLAGS) -o $@ -c $<
运行
$make$./fileHello World from linux_file_sampleHello World form c_file_sample
Linux文件系统与设备驱动
上图描述了Linux中虚拟文件系统、磁盘/Flash文件系统及一般的设备文件与设备驱动程序之间的关系。
应用程序和VFS之间的接口是系统调用,而VFS与文件系统以及设备文件之间的接口是file_operations结构体成员函数,这个结构体包含对文件进行打开、关闭、读写、控制的一些列成员函数.
file结构体
file 结构体代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核和驱动源代码中,struct file的指针通常被命名为file或filep。
// include/linux/fs.h:line 835struct file { union { struct llist_node fu_llist; struct rcu_head fu_rcuhead; } f_u; struct path f_path; struct inode *f_inode; /* cached value */ const struct file_operations *f_op; /* * Protects f_ep_links, f_flags. * Must not be taken from IRQ context. */ spinlock_t f_lock; atomic_long_t f_count; unsigned int f_flags; fmode_t f_mode; struct mutex f_pos_lock; loff_t f_pos; struct fown_struct f_owner; const struct cred *f_cred; struct file_ra_state f_ra; u64 f_version;#ifdef CONFIG_SECURITY void *f_security;#endif /* needed for tty driver, and maybe others */ void *private_data;#ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; struct list_head f_tfile_llink;#endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping;} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
inode结构体
VFS inode包含文件访问权限、属主、组、大小、生成时间、访问时间、最后修改时间等信息。它是Linux管理文件系统的最基本单位,也是文件系统连接任何子目录、文件的桥梁。
// include/linux/fs.h:line 554/* * Keep mostly read-only and often accessed (especially for * the RCU path lookup and 'stat' data) fields at the beginning * of the 'struct inode' */struct inode { umode_t i_mode; unsigned short i_opflags; kuid_t i_uid; kgid_t i_gid; unsigned int i_flags;#ifdef CONFIG_FS_POSIX_ACL struct posix_acl *i_acl; struct posix_acl *i_default_acl;#endif const struct inode_operations *i_op; struct super_block *i_sb; struct address_space *i_mapping;#ifdef CONFIG_SECURITY void *i_security;#endif /* Stat data, not accessed from path walking */ unsigned long i_ino; /* * Filesystems may only read i_nlink directly. They shall use the * following functions for modification: * * (set|clear|inc|drop)_nlink * inode_(inc|dec)_link_count */ union { const unsigned int i_nlink; unsigned int __i_nlink; }; dev_t i_rdev; loff_t i_size; struct timespec i_atime; struct timespec i_mtime; struct timespec i_ctime; spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes; unsigned int i_blkbits; blkcnt_t i_blocks;#ifdef __NEED_I_SIZE_ORDERED seqcount_t i_size_seqcount;#endif /* Misc */ unsigned long i_state; struct rw_semaphore i_rwsem; unsigned long dirtied_when; /* jiffies of first dirtying */ unsigned long dirtied_time_when; struct hlist_node i_hash; struct list_head i_io_list; /* backing dev IO list */#ifdef CONFIG_CGROUP_WRITEBACK struct bdi_writeback *i_wb; /* the associated cgroup wb */ /* foreign inode detection, see wbc_detach_inode() */ int i_wb_frn_winner; u16 i_wb_frn_avg_time; u16 i_wb_frn_history;#endif struct list_head i_lru; /* inode LRU list */ struct list_head i_sb_list; struct list_head i_wb_list; /* backing dev writeback list */ union { struct hlist_head i_dentry; struct rcu_head i_rcu; }; u64 i_version; atomic_t i_count; atomic_t i_dio_count; atomic_t i_writecount;#ifdef CONFIG_IMA atomic_t i_readcount; /* struct files open RO */#endif const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ struct file_lock_context *i_flctx; struct address_space i_data; struct list_head i_devices; union { struct pipe_inode_info *i_pipe; struct block_device *i_bdev; struct cdev *i_cdev; char *i_link; unsigned i_dir_seq; }; __u32 i_generation;#ifdef CONFIG_FSNOTIFY __u32 i_fsnotify_mask; /* all events this inode cares about */ struct fsnotify_mark_connector __rcu *i_fsnotify_marks;#endif#if IS_ENABLED(CONFIG_FS_ENCRYPTION) struct fscrypt_info *i_crypt_info;#endif void *i_private; /* fs or device private pointer */};
字符设备
字符设备是能够像字节流(类似文件)一样被访问的设备,有字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少要实现open、close、read、write系统调用。字符设备可以通过文件系统节点来访问,这些设备文件和普通文件之间的唯一差别在于对普通文件的访问可以前后移动访问位置,而大多数字符设备是一个只能顺序访问的数据通道。一个字符设备是一种字节流设备,对设备的存取只能按顺序按字节的存取而不能随机访问,字符设备没有请求缓冲区,所有的访问请求都是按顺序执行的。但事实上现在一些高级字符设备也可以从指定位置一次读取一块数据。
块设备
块设备也是通过设备节点来访问。块设备上能够容纳文件系统。在大多数unix系统中,进行I/O操作时块设备每次只能传输一个或多个完整的块,而每块包含512字节(或更2的更高次幂字节的数据)。linux可以让应用程序向字符设备一样读写块设备,允许一次传递任意多字节的数据。因而,块设备和字符设备的区别仅仅在于内核内部管理数据的方式,也就是内核及驱动程序之间的软件接口,而这些不同对用户来讲是透明的。在内核中,和字符驱动程序相比,块驱动程序具有完全不同的接口。存储设备一 般属于块设备,块设备有请求缓冲区,并且支持随机访问而不必按照顺序去存取数据,比如你可以 先存取后面的数据,然后在存取前面的数据,这对字符设备来说是不可能的。Linux下的磁盘设备都是块设备,尽管在Linux下有块设备节点,但应用程序一般是通过文件系统及其高速缓存来访问块设备的,而不是直接通过设备节点来读写块设备上的数据。
网络设备
网络设备不同于字符设备和块设备,它是面向报文的而不是面向流的,它不支持随机访问,也没有请求缓冲区。由于不是面向流的设备,因此将网络接口映射到文件系统中的节点比较困难。内核和网络设备驱动程序间的通讯,完全不同于内核和字符以及块驱动程序之间的通讯,内核调用一套和数据包传输相关的函数而不是read,write。网络接口没有像字符设备和块设备一样的设备号,只有一个唯一的名字,如eth0、eth1等,而这个名字也不需要与设备文件节点对应。
字符设备与块设备的区别
- 字符设备是面向流的,最小访问单位是字节;而块设备是面向块的,最小访问单位是512字节或2的更高次幂。
- 字符设备只能顺序按字节访问,而块设备可随机访问。
- 块设备上可容纳文件系统,访问形式上,字符设备通过设备节点访问,而块设备虽然也可通过设备节点访问,但一般是通过文件系统来访问数据的。
网络设备没有设备节点是因为网络设备是面向报文的,很难实现相关read、write等文件读写函数。所以驱动的实现也与字符设备和块设备不同。
学习资源
- 《Linux C API 参考手册》
- 《Linux 设备驱动开发详解》
- Linux 文件系统与设备文件
- Linux文件系统与设备文件系统
- linux驱动学习--第七天:第五章 Linux 文件系统与设备文件系统 之 linux文件操作
- linux文件系统与设备文件系统的关系?
- Linux 文件系统与设备文件系统(3)
- 《Linux4.0设备驱动开发详解》笔记--第五章:Linux文件系统与设备文件
- linux笔记5(设备文件、文件系统
- Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型
- Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型
- Sysfs文件系统与Linux设备模型
- Linux-2.6设备模型与sysfs文件系统
- linux设备文件系统剖析与使用
- linux设备模型与sys文件系统
- 第5章 Linux文件系统与设备文件系统
- 5——linux文件系统与设备文件系统
- Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统
- Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统
- Linux的文件系统与文件
- export 到处模块从另一模块中出错
- ViewCompat.animate的使用
- Yaf 学习记录(1)
- 关于JS中如何获取动态加载的对象小结
- 最大子段和
- Linux 文件系统与设备文件
- $.ajax_error参数
- jQuery树形控件zTree使用小结
- java(3)类变量 类方法
- grub2的exit命令
- Linux脚本编程/shell语法和shell进度条的编写
- python函数的定义必须在调用前面(函数调用函数例外)
- ubuntu14.04 faster-rcnn GPU环境配置(2)
- 教你使用Git 命令版