if ( ( rp != wp ) && ( count > 0 ) )
! s( J! x8 G% Q; I
1 ^9 F% c: V, W: V* m goto repeate_reading;, z' B6 Y' w: N" S
7 }0 w" L( b' ?" \5 e4 v flag = 0;
( ?- x7 N. N5 B/ E; R3 W9 e
* Q1 W. S6 U Y0 [# c wake_up_interruptible( &write_wq );
3 ^# [$ o/ _5 w, R4 @1 Y , @7 x: ?8 C2 @9 [- v
return nRead;2 z! l' C( |5 u7 K
0 g# ^" ]" Q7 i$ I/ u% B! k }
g6 x* X2 m' o2 l* W% E# O & m H% N+ B1 E# ]2 ?
在前头我有提到,buf 的地址是属于 user space 的。在 kernel space 中,你不能像普通写到 buffer 里一样直接将资料写到 buf 里,或直接从 buf 里读资料。Linux 里使用 FS 这个 register 来当作 kernel space 和 user space 的切换。所以,如果你想手动的话,可以这样做:
% t& Z, S) V) I# d# T5 x/ Z
- r. j) v* [ v! `' l. g: R mm_segment_t fs;4 T* t% f; e, Y) Y6 y8 _' O
+ q1 }# Q0 z0 ?0 {, ? fs = get_fs();
8 o/ r: g9 ~% ^+ `
9 q7 D& ~) I$ r5 f7 b! q4 A1 j set_fs( USER_DS );
3 Y9 n4 j3 _% ^( ~7 v ( e0 ]5 g* e, {+ ?/ K$ R2 _
write_data_to_buf( buf );
- y4 s5 ^ _1 O$ ]7 {
3 i( { J' G: H# H; c set_fs( fs );0 P) P5 w1 Q& R* V
$ a! Q, p2 b- |
也就是先切换到 user space,再写资料到 buf 里。之后记得要切换回来 kernel space.这种自己动手的方法比较麻烦,所以 Linux 提供了几个 function,可以让我们直接在不同的 space 之间做资料的搬移。诚如各位所见,copy_to_user() 就是其中一个。# D' i& m' I/ w
) U/ ^! z. _, s3 c7 |. v3 S3 { copy_to_user( to,from,n );
0 u' `2 F ^5 l [ 6 B+ u3 H! Z' s7 D% }: k+ a
copy_from_user( to,from,n );- ~# I' f6 t2 m7 S3 B* J
( r4 b+ ~3 @3 T2 @
顾名思义,copy_to_user() 就是将资料 copy 到 user space 的 buffer 里,也就是从 to 写到 from,n 为要 copy 的 byte 数。相同的,copy_from_user() 就是将资料从 user space 的 from copy 到位于 kernel 的 to 里,长度是 n bytes.在以前的 kernel 里,这两个 function 的前身是 memcpy_tofs() 和 memcpy_fromfs(),不知道为什么到了 kernel 2.2.1之后,名字就被改掉了。至于它们的程序代码有没有更改就不太清楚了。至于到那一版才改的。我没有仔细去查,只知道在 2.0.36 时还没改,到了 2.2.1 就改了。这两个 function 是 macro,都定义在 里。要使用前记得先 include 进来。
/ n F; L* f% W/ |7 _. k Y" d6 W* b
( [( s# w3 B1 [. G 相信 buf_read() 的程序代码应当不难了解才对。不知道各位有没有看到,在buf_read() 的后面有一行的程序,就是6 y, N, J" n( W8 ]/ T" Z/ O& M* Y
! N6 j. p: o; I, I
wake_up_interruptible( &write_wq );
9 t8 |. l9 ^7 `* | v# H
2 C, i2 i+ ~4 R/ z( I' q& X8 s write_wq 是我们用来放那些想要写资料到 buffer,但 buffer 已满的 process.这一行的程序会将挂在此 queue 上的 process 叫醒。当 queue 是空的时,也就是当 write_wq 为 NULL 时,wake_up_interruptible() 并不会造成任何的错误。接下来,我们来看看更改后的 buf_write()。
9 H2 x1 d$ g* l: P$ @) D& U : D) V% m' R- Z( ~& F7 Y9 A( Q
static ssize_t buf_write( struct file *filp,const char *buf,size_t count,loff_t *ppos )
3 F& z$ b( p2 I" B& v2 f
V6 n. S# V/ {' P& x3 D; T8 J {' X9 F. a8 O- _
/ B! s! B9 Y9 A. c2 i
int num,nWrite;
, P; ^6 q! }0 o ( Y% K: u" o' p, O4 i
nWrite = 0;. ?8 ^, @3 [$ {& E t+ m
c, r7 \1 p1 a. R: a( ]% h+ Z6 }. t while ( ( wp == rp ) && flag ) {
3 }! s9 W3 ?8 ~4 | ; F5 }* Y, B G
interruptible_sleep_on( &write_wq );2 c4 e9 |$ e" H- M8 `
8 C! Q+ G8 Y* n* Q
}- H: V, {8 w2 Q
- ~$ P8 v/ d2 W repeate_writing:& s* H5 {+ F) O& ]
7 e, L5 N; o" L! h( J% U if ( rp > wp ) {5 {& B6 [2 K1 F# Y4 q
& E/ l2 ]( H# F0 [8 \. ~& H
num = min( count,( int ) ( rp - wp ) );
! ^$ P2 e0 D E, {* N & ?0 C I) m) g. k6 k' f
}: H5 F' a5 X/ i/ J0 O% u
. i8 ?$ w8 ~) t8 b6 M% H else {
- a) j( W; V5 n& `, Q * u8 r* z, h, e( c F0 S
num = min( count,( int ) ( buffer + BUF_LEN - wp ) );
* f' L+ O$ e2 B7 [7 T
; H& s% K' Q: E4 j e6 R' i3 Y }
( m# T7 d+ a& [" b M7 |. [% ?: N . S& T) J; y. q
copy_from_user( wp,buf,num );
# O" N% C% T' j, }! q3 Q6 g & z% c2 g4 {1 |& A
wp += num;
* @1 n, y5 ]% o4 m5 C4 j# \% w
& |/ t/ [/ J- }' Y9 n: n count -= num;, U! V- x) }7 S' p* V
) E& x8 _; i) s6 x+ h2 S3 F. u; K nWrite += num;
' ?$ F8 A2 l, I5 k& x: O
. ^$ k6 k" M" D, Y! r3 ?) Q( x if ( wp == ( buffer + BUF_LEN ) ) {
3 ]3 U d* ~* D, J j$ p# } c- W7 w6 d: M& O% G5 K
wp = buffer; |