分類: 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 plaincopy
off_t lseek(
intfd, off_t offset,
intwhence);
第乙個引數fd是要操作的檔案描述符。
第二個引數指定檔案操作指標的偏移量。注意,檔案的讀和寫使用的是同乙個檔案操作指標。
第三個引數指定移動檔案操作指標的參考點。這個引數通常取值為以下巨集:
seek_set:表示相對檔案起始位置。
seek_cur:表示相對檔案操作指標當前位置。
seek_end:表示相對檔案結束位置。
下面先來看乙個使用者空間測試程式llseek_test.c的實現,這個程式用來測試scull的定位功能,其**如下:
[cpp]view plaincopy
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 plaincopy
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 plaincopy
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...