LDD3原始碼分析之llseek分析

2021-06-07 01:44:08 字數 3711 閱讀 4575

分類: ldd3原始碼分析

2012-03-28 14:36

201人閱讀收藏 

舉報部落格:

編譯環境: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(

intfd, off_t offset, 

intwhence);  

第乙個引數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, 

intwhence)  

524  

544    if

(newpos 

return

-einval;  

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

intnonseekable_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分析

部落格 編譯環境 ubuntu 10.10 核心版本 2.6.32 38 generic pae ldd3原始碼路徑 examples scull main.c 本文分析ldd3第6章的llseek函式。一 使用者空間的lseek函式要理解驅動中llseek函式的實現,必須先清楚對應的使用者空間中l...

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

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