Linux 文件系統與驅動

之前做應用程序的開發,就知道Linux系統的一大特點就是一切皆文件,一直以來對所有設備的操作都是使用系統函數open read write close來實現的,就沒關心過系統裏面是怎麼實現對各種設備的區分和控制櫃,直到開始看Linux設備驅動方面的知識以後,感覺像發現了新大陸一樣的神奇,故把相關知識記錄下來,方便以後自己查找。

文件系統調用

文件的打開

int open(const char *pathname, int flags);
int open(const char *pathname, int falgs, mode_t mode);

open函數有兩個形式,其中第一個參數是需要打開的文件路徑及文件名(默認是當前路徑),flags是一下值的一個或者幾個的組合:

標誌(flag) 含義
O_RDONLY 只讀方式
O_WRONLY 只寫方式
O_RDWR 可讀可寫
O_APPEND 追加的方式
O_CREAT 創建一個文件
O_EXEC 如果使用了O_CREAT而且文件已經存在,就會發生一個錯誤
O_NOBLOCK 以非阻塞的方式
O_TRUNC 如果文件已經存在就刪除文件內容

O_RDONLY ,O_WRONLY ,O_RDWR這三個標誌位只能使用其中的一個
如果使用了O_CREAT標誌,那麼調用的函數需要指定第三個參數mode標誌,以表示文件的訪問權限:

標誌(flag) 含義
S_IRUSR 用戶可以讀
S_IWUSR 用戶可以寫
S_IXUSR 用戶可以執行
S_IRWXU 用戶可讀,可寫,可執行
S_IRGRP 組可讀
S_IWGRP 組可寫
S_IXGRP 組可執行
S_IRWXG 組可讀,可寫,可執行
S_IROTH 其他人可以讀
S_IWOTH 其他人可寫
S_IXOTH 其他人可執行
S_IRWXO 其他人可讀,可寫,可執行
S_ISUID 設置用戶執行ID
S_ISGID 設置組ID

除了通過以上宏第一或運算產生標誌位以外,可以自己用數字生產標誌位規則如下:

byte位 含義 備註
第一位 (byte 4) 設置用戶ID
第二位 (byte 3) 設置組ID
第三位 (byte 2) 用戶自己的權限 可取 1(可執行),2 (可寫),4(可讀),0(無)或者這些值的和
第四位 (byte 1) 組的權限
第五位 (byte 0) 其他人權限
open("test", O_CREAT, 10705);
open("test", O_CREAT, S_IRWXU | S_IROTH | S_IXOTH | S_ISUID);

上面兩個函數等價:當前路徑下創建一個用戶可讀可寫可執行,組沒有權限,其他人可讀可執行並設置用戶ID名爲test的文件

文件的讀寫

int read(int fd, const void *buf, size_t length);
int write(int fd, const void *buf, size_t length);

參數 fd 爲open函數返回的文件描述符,buf爲指向緩衝區的指針,length爲緩衝區大小;
read()從fd所指的文件裏面讀取length個字節到buf緩衝區,返回實際讀取到的字節數;
write()把length個字節從緩衝區buf中寫到fd指向的文件去,返回實際寫進去的字節數;

文件定位

int lseek(int fd, offset_t offset, int whence);

將文件指針相對whence移動offset個字節,操作成功時返回文件指針相對於文件頭的位置,whence可以取:

  • SEEK_SET:文件頭
  • SEEK_CUR:當前位置
  • SEEK_END:文件末尾

lseek(fd, 0, SEEK_END);返回的就是文件的長度
lseek(fd, -5 , SEEK_CUR);將文件指針相對當前位置向前移動5字節

文件關閉

int close(int fd);

文件系統與設備驅動

Linux應用程序和設置之間的關係如下圖所示:
在這裏插入圖片描述
應用程序通過系統調用,操作系統通過虛擬文件系統中的file_operations結構體去調用相應的設備驅動,file_operations結構體定義了一系列函數指針,相應的設備驅動實現這些函數,並把函數賦值給file_operations的函數指針,然後把驅動註冊到內核。file_operations結構體定義如下(include/linux/fs.h):

struct file_operations {
	struct module *owner;
	loff_t (*llseek) (struct file *, loff_t, int);
	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
	ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
	ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
	int (*iopoll)(struct kiocb *kiocb, bool spin);
	int (*iterate) (struct file *, struct dir_context *);
	int (*iterate_shared) (struct file *, struct dir_context *);
	__poll_t (*poll) (struct file *, struct poll_table_struct *);
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	int (*mmap) (struct file *, struct vm_area_struct *);
	unsigned long mmap_supported_flags;
	int (*open) (struct inode *, struct file *);
	int (*flush) (struct file *, fl_owner_t id);
	int (*release) (struct inode *, struct file *);
	int (*fsync) (struct file *, loff_t, loff_t, int datasync);
	int (*fasync) (int, struct file *, int);
	int (*lock) (struct file *, int, struct file_lock *);
	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
	int (*check_flags)(int);
	int (*flock) (struct file *, int, struct file_lock *);
	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
	int (*setlease)(struct file *, long, struct file_lock **, void **);
	long (*fallocate)(struct file *file, int mode, loff_t offset,
			  loff_t len);
	void (*show_fdinfo)(struct seq_file *m, struct file *f);
#ifndef CONFIG_MMU
	unsigned (*mmap_capabilities)(struct file *);
#endif
	ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
			loff_t, size_t, unsigned int);
	loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
				   struct file *file_out, loff_t pos_out,
				   loff_t len, unsigned int remap_flags);
	int (*fadvise)(struct file *, loff_t, loff_t, int);
} __randomize_layout;
file_operations內核函數 用戶空間函數 備註
llseek() lseek() 用來修改一個文件的當前讀寫位置,並將新位置返回,出錯時返回一個負數
read() read() fread() 從設備中讀取數據,成功返回讀取的字節數,失敗返回負數,0暗示end-of-file
write() write() fwrite() 向設備發送數據,成功返回發送的字節數,失敗返回負數,如果此函數未被實現,用戶調研write()以後講收到-EINVAL返回值
unlocked_ioctrl() ioctrl() fcntl() 提供設備相關控制命令調用,成功返回非負值,失敗返回負數
mmap() mmap() 幀緩衝被映射到用戶空間,應用程序可以直接訪問,不需要再內核空間和用戶空間進行內存複製,如果此函數未被實現,用戶調研mmap()以後講收到-EINVAL返回值
poll() select() poll() 用於查詢設備是否可被非阻塞的進行讀寫,當查詢的調節未觸發時,用戶空間進行select() 和 poll()查詢系統調用時將引起進程的阻塞
aio_read() aio_write 對設備進行異步讀寫操作,當該函數實現以後,用戶空間可以對設備執行SYS_io_setup、SYS_io_submit、SYS_io_getevents、SYS_io_destory等系統調用進行讀寫
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章