+ E6 Q. U3 z: kIf you make a non-temporary copy of a pointer, especially if it can be passed to another thread of execution, you must increment the refcount with kref_get() before passing it off; ; K, M. h; k. f, E/ t, D4 A" m
规则二: 0 ]( V, B4 f0 L5 n4 Q6 `& s O: D/ `; k2 p# B3 ?2 g. |8 V3 I' ]
When you are done with a pointer, you must call kref_put();# [! } c( c% I7 c9 K, A( ^; b2 u
B4 U* e" S S& p, v4 s- A) }规则三: $ |: N& j' z% S : b* u/ p$ X! {$ }2 V0 D3 X0 j6 ?- A8 TIf the code attempts to gain a reference to a kref-ed structure without already holding a valid pointer, it must serialize access where a kref_put() cannot occur during the kref_get(), and the structure must remain valid during the kref_get().2 f* k/ @" e5 x5 b8 d m" S
. y% v+ K0 K; R( O 6 F, E0 s& x& K& U" S( G. D
8 t2 ^# G5 ]1 J* C5 h3 J* P* o# S对于规则一,其实主要是针对多条执行路径(比如另起一个线程)的情况。如果是在单一的执行路径里,比如把指针传递给一个函数,是不需要使用kref_get的。看下面这个例子:7 z* p" H A) U6 D9 N4 M
% ^7 R$ \9 U* C: T: ?+ y# ? D
kref_init(&obj->ref);
// do something here
// ...
kref_get(&obj->ref);
call_something(obj);
kref_put(&obj->ref);
// do something here
// ...
kref_put(&obj->ref);* d, M H! c |- p$ h- P1 ?( D' n
4 \* e7 @* N o2 q# l, ?4 q/ @7 k. |' o) M' C+ c! V4 r7 }9 S; c3 b
您是不是觉得call_something前后的一对kref_get和kref_put很多余呢?obj并没有逃出我们的掌控,所以它们确实是没有必要的。. y( ?/ C/ e* x" h$ f9 V
3 A- N: @3 N& R0 S * I8 a' p, G6 {3 N* a. z1 M 这个例子里已经用mutex来进行保护了,假如我们把mutex拿掉,会出现什么情况?记住,我们遇到的很可能是多线程操作。如果线程A在用container_of取得entry指针之后、调用kref_get之前,被线程B抢先执行,而线程B碰巧又做的是kref_put的操作,当线程A恢复执行时一定会出现内存访问的错误,所以,遇到这种情况一定要串行化处理。0 y$ B% x1 D) d& n