LDD3原始碼分析之llseek分析

2021-08-01 12:32:18 字數 3443 閱讀 1834

部落格:

編譯環境:ubuntu 10.10

核心版本:2.6.32-38-generic-pae

ldd3原始碼路徑:examples/scull/main.c

本文分析ldd3第6章的llseek函式。
一、使用者空間的lseek函式
要理解驅動中llseek函式的實現,必須先清楚對應的使用者空間中lseek函式的用法,lseek函式函式原型如下:
[cpp]view plain

copy

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

第乙個引數fd是要操作的檔案描述符。

第二個引數指定檔案操作指標的偏移量。注意,檔案的讀和寫使用的是同乙個檔案操作指標。
第三個引數指定移動檔案操作指標的參考點。這個引數通常取值為以下巨集:
seek_set:表示相對檔案起始位置。
seek_cur:表示相對檔案操作指標當前位置。
seek_end:表示相對檔案結束位置。
下面先來看乙個使用者空間測試程式llseek_test.c的實現,這個程式用來測試scull的定位功能,其**如下:
[cpp]view plain

copy

1#include 

2#include 

3#include 

4#include 

5#include 

6#include 

7  8#define buf_size 50  

9#define device_file "/dev/scull"

10  

11int main(int argc, char *argv)  

12  

23  

24    memset(buf, 0, buf_size);  

25    num = read(fd, buf, buf_size);  

26    buf[num] = 0;  

27    printf("%s\n", buf);  

28  

29    lseek(fd, 2, seek_set);  

30    write(fd, "aa", 2);  

31    num = read(fd, buf, buf_size);  

32    buf[num] = 0;  

33    printf("%s\n", buf);  

34  

35    lseek(fd, 2, seek_set);  

36    num = read(fd, buf, buf_size);  

37    buf[num] = 0;  

38    printf("%s\n", buf);  

39  

40    lseek(fd, 0, seek_set);  

41    lseek(fd, 2, seek_cur);  

42    num = read(fd, buf, buf_size);  

43    buf[num] = 0;  

44    printf("%s\n", buf);  

45  

46    lseek(fd, 0, seek_set);  

47    lseek(fd, 0, seek_end);  

48    memset(buf, 0, buf_size);  

49    printf("read return value is %d.\n", read(fd, buf, buf_size));  

50  

51    return 0;  

52}  

這個程式很簡單,主要關注一下lseek函式是怎樣移動檔案操作指標的。

第29行,使用seek_set巨集,將檔案操作指標移動到檔案起始位置加上2個位元組處。
第30行,寫入兩個字元』a』。
第41行,使用seek_cur巨集,將檔案操作指標移動到檔案操作指標當前位置加上2個位元組處。
第47行,使用seek_end巨集,將檔案操作指標移動到檔案結束處。
第49行,列印read的返回值,當檔案操作指標在檔案結束處時,read返回0。
下圖是使用llseek_test測試scull裝置的定位功能的過程:

這裡需要說明的一點是,從上面的輸出資訊可以看出,對檔案的read和write操作使用的是同乙個檔案操作指標。
二、驅動程式中llseek函式的實現
使用者空間的lseek函式的定位功能在驅動程式中是由llseek函式實現的。注意,要完成對檔案的定位操作,還需要read、write函式的配合,讀寫完成後必須更新檔案操作指標位置。
即使驅動程式中沒有實現llseek函式,有某些情況下,裝置也是可以完成定位操作的,核心通過修改filp->f_pos來執行定位,filp->f_pos是檔案的當前讀寫位置。但是,如果定位操作需要涉及裝置的物理操作,就必須實現llseek函式了。scull裝置的llseek函式**如下:
[cpp]view plain

copy

523loff_t scull_llseek(struct file *filp, loff_t off, int whence)  

524  

544    if (newpos 

545    filp->f_pos = newpos;  

546    return newpos;  

547}  

這裡唯一與裝置相關的操作就是第538行,取得裝置檔案的大小。同時,我們在前面的文章中分析過,scull的read和write函式讀寫檔案後,總是更新檔案操作指標的位置,定位功能需要llseek與read、write的配合。

對於某些裝置檔案來說,定位功能是沒有意義的,例如鍵盤。對於這些裝置,我們不能簡單地不實現llseek函式,因為預設方法是允許通過filp->f_pos定位的。我們應該在我們的open函式中呼叫nonseekable_open,通知核心裝置不支援llseek。該函式的函式原型如下:
[cpp]view plain

copy

int nonseekable_open(struct inode *inode; struct file *filp);  

另外,為完整起見,我們還應該將file_operations結構中的llseek方法設定為特殊的輔助函式no_llseek

LDD3原始碼分析之vmalloc

部落格 編譯環境 ubuntu 10.10 核心版本 2.6.32 38 generic pae ldd3原始碼路徑 examples scullv 一 scullv編譯本文分析ldd3第8章中與vmalloc函式相關 對應原始碼是examples scullv目錄下的相關檔案。這裡首先說明一下,s...

LDD3原始碼分析之llseek分析

分類 ldd3原始碼分析 2012 03 28 14 36 201人閱讀收藏 舉報部落格 編譯環境 ubuntu 10.10 核心版本 2.6.32 38 generic pae ldd3原始碼路徑 examples scull main.c 本文分析ldd3第6章的llseek函式。一 使用者空間...

LDD3原始碼學習筆記之scull pipe轉

pipe.c 驅動功能分析 本驅動使用環形緩衝作為scull裝置的的具體實現,類似於pipe.其中實現了阻塞的i o讀寫和非同步通知.主函式流程分析 1.定義scull pipe裝置機構體 2.初始化模組module init scull p init 3.退出並登出模組module exit sc...