感谢支持
我们一直在努力

Linux内核部件分析

在linux内核中,有一种通用的双向循环链表,构成了各种队列的基础。链表的结构定义和相关函数均在include/linux/list.h中,下面就来全面的介绍这一链表的各种API。


  1. struct list_head {  
  2.     struct list_head *next, *prev;  
  3. };  

这是链表的元素结构。因为是循环链表,表头和表中节点都是这一结构。有prev和next两个指针,分别指向链表中前一节点和后一节点。


  1. #define LIST_HEAD_INIT(name) { &(name), &(name) }   
  2.   
  3. #define LIST_HEAD(name) \   
  4.     struct list_head name = LIST_HEAD_INIT(name)  
  5.   
  6. static inline void INIT_LIST_HEAD(struct list_head *list)  
  7. {  
  8.     list->next = list;  
  9.     list->prev = list;  
  10. }  

在初始化的时候,链表头的prev和next都是指向自身的。


  1. static inline void __list_add(struct list_head *new,  
  2.                   struct list_head *prev,  
  3.                   struct list_head *next)  
  4. {  
  5.     next->prev = new;  
  6.     new->next = next;  
  7.     new->prev = prev;  
  8.     prev->next = new;  
  9. }  
  10.   
  11. static inline void list_add(struct list_head *newstruct list_head *head)  
  12. {  
  13.     __list_add(new, head, head->next);  
  14. }  
  15.   
  16. static inline void list_add_tail(struct list_head *newstruct list_head *head)  
  17. {  
  18.     __list_add(new, head->prev, head);  
  19. }  

双向循环链表的实现,很少有例外情况,基本都可以用公共的方式来处理。这里无论是加第一个节点,还是其它的节点,使用的方法都一样。


另外,链表API实现时大致都是分为两层:一层外部的,如list_add、list_add_tail,用来消除一些例外情况,调用内部实现;一层是内部的,函数名前会加双下划线,如__list_add,往往是几个操作公共的部分,或者排除例外后的实现。


  1. static inline void __list_del(struct list_head * prev, struct list_head * next)  
  2. {  
  3.     next->prev = prev;  
  4.     prev->next = next;  
  5. }  
  6.   
  7. static inline void list_del(struct list_head *entry)  
  8. {  
  9.     __list_del(entry->prev, entry->next);  
  10.     entry->next = LIST_POISON1;  
  11.     entry->prev = LIST_POISON2;  
  12. }  
  13.   
  14. static inline void list_del_init(struct list_head *entry)  
  15. {  
  16.     __list_del(entry->prev, entry->next);  
  17.     INIT_LIST_HEAD(entry);  
  18. }  

list_del是链表中节点的删除。之所以在调用__list_del后又把被删除元素的next、prev指向特殊的LIST_POSITION1和LIST_POSITION2,是为了调试未定义的指针。


list_del_init则是删除节点后,随即把节点中指针再次初始化,这种删除方式更为实用。


  1. static inline void list_replace(struct list_head *old,  
  2.                 struct list_head *new)  
  3. {  
  4.     new->next = old->next;  
  5.     new->next->prev = new;  
  6.     new->prev = old->prev;  
  7.     new->prev->next = new;  
  8. }  
  9.   
  10. static inline void list_replace_init(struct list_head *old,  
  11.                     struct list_head *new)  
  12. {  
  13.     list_replace(old, new);  
  14.     INIT_LIST_HEAD(old);  
  15. }  

list_replace是将链表中一个节点old,替换为另一个节点new。从实现来看,即使old所在地链表只有old一个节点,new也可以成功替换,这就是双向循环链表可怕的通用之处。


list_replace_init将被替换的old随即又初始化。


  1. static inline void list_move(struct list_head *list, struct list_head *head)  
  2. {  
  3.     __list_del(list->prev, list->next);  
  4.     list_add(list, head);  
  5. }  
  6.   
  7. static inline void list_move_tail(struct list_head *list,  
  8.                   struct list_head *head)  
  9. {  
  10.     __list_del(list->prev, list->next);  
  11.     list_add_tail(list, head);  
  12. }  

list_move的作用是把list节点从原链表中去除,并加入新的链表head中。


list_move_tail只在加入新链表时与list_move有所不同,list_move是加到head之后的链表头部,而list_move_tail是加到head之前的链表尾部。


  1. static inline int list_is_last(const struct list_head *list,  
  2.                 const struct list_head *head)  
  3. {  
  4.     return list->next == head;  
  5. }  

list_is_last 判断list是否处于head链表的尾部。


  1. static inline int list_empty(const struct list_head *head)  
  2. {  
  3.     return head->next == head;  
  4. }  
  5.   
  6. static inline int list_empty_careful(const struct list_head *head)  
  7. {  
  8.     struct list_head *next = head->next;  
  9.     return (next == head) && (next == head->prev);  
  10. }  

list_empty 判断head链表是否为空,为空的意思就是只有一个链表头head。


list_empty_careful 同样是判断head链表是否为空,只是检查更为严格。


  1. static inline int list_is_singular(const struct list_head *head)  
  2. {  
  3.     return !list_empty(head) && (head->next == head->prev);  
  4. }  

list_is_singular 判断head中是否只有一个节点,即除链表头head外只有一个节点。


  1. static inline void __list_cut_position(struct list_head *list,  
  2.         struct list_head *head, struct list_head *entry)  
  3. {  
  4.     struct list_head *new_first = entry->next;  
  5.     list->next = head->next;  
  6.     list->next->prev = list;  
  7.     list->prev = entry;  
  8.     entry->next = list;  
  9.     head->next = new_first;  
  10.     new_first->prev = head;  
  11. }  
  12.   
  13. static inline void list_cut_position(struct list_head *list,  
  14.         struct list_head *head, struct list_head *entry)  
  15. {  
  16.     if (list_empty(head))  
  17.         return;  
  18.     if (list_is_singular(head) &&  
  19.         (head->next != entry && head != entry))  
  20.         return;  
  21.     if (entry == head)  
  22.         INIT_LIST_HEAD(list);  
  23.     else  
  24.         __list_cut_position(list, head, entry);  
  25. }  

list_cut_position 用于把head链表分为两个部分。从head->next一直到entry被从head链表中删除,加入新的链表list。新链表list应该是空的,或者原来的节点都可以被忽略掉。可以看到,list_cut_position中排除了一些意外情况,保证调用__list_cut_position时至少有一个元素会被加入新链表。


  1. static inline void __list_splice(const struct list_head *list,  
  2.                  struct list_head *prev,  
  3.                  struct list_head *next)  
  4. {  
  5.     struct list_head *first = list->next;  
  6.     struct list_head *last = list->prev;  
  7.   
  8.     first->prev = prev;  
  9.     prev->next = first;  
  10.   
  11.     last->next = next;  
  12.     next->prev = last;  
  13. }  
  14.   
  15. static inline void list_splice(const struct list_head *list,  
  16.                 struct list_head *head)  
  17. {  
  18.     if (!list_empty(list))  
  19.         __list_splice(list, head, head->next);  
  20. }  
  21.   
  22. static inline void list_splice_tail(struct list_head *list,  
  23.                 struct list_head *head)  
  24. {  
  25.     if (!list_empty(list))  
  26.         __list_splice(list, head->prev, head);  
  27. }  

list_splice的功能和list_cut_position正相反,它合并两个链表。list_splice把list链表中的节点加入head链表中。在实际操作之前,要先判断list链表是否为空。它保证调用__list_splice时list链表中至少有一个节点可以被合并到head链表中。


list_splice_tail只是在合并链表时插入的位置不同。list_splice是把原来list链表中的节点全加到head链表的头部,而list_splice_tail则是把原来list链表中的节点全加到head链表的尾部。


  1. static inline void list_splice_init(struct list_head *list,  
  2.                     struct list_head *head)  
  3. {  
  4.     if (!list_empty(list)) {  
  5.         __list_splice(list, head, head->next);  
  6.         INIT_LIST_HEAD(list);  
  7.     }  
  8. }  
  9.   
  10. static inline void list_splice_tail_init(struct list_head *list,  
  11.                      struct list_head *head)  
  12. {  
  13.     if (!list_empty(list)) {  
  14.         __list_splice(list, head->prev, head);  
  15.         INIT_LIST_HEAD(list);  
  16.     }  
  17. }  

list_splice_init 除了完成list_splice的功能,还把变空了的list链表头重新初始化。


list_splice_tail_init 除了完成list_splice_tail的功能,还吧变空了得list链表头重新初始化。

list操作的API大致如以上所列,包括链表节点添加与删除、节点从一个链表转移到另一个链表、链表中一个节点被替换为另一个节点、链表的合并与拆分、查看链表当前是否为空或者只有一个节点。接下来,是操作链表遍历时的一些宏,我们也简单介绍一下。


  1. #define list_entry(ptr, type, member) \   
  2.     container_of(ptr, type, member)  

list_entry主要用于从list节点查找其内嵌在的结构。比如定义一个结构struct A{ struct list_head list; }; 如果知道结构中链表的地址ptrList,就可以从ptrList进而获取整个结构的地址(即整个结构的指针) struct A *ptrA = list_entry(ptrList, struct A, list);


这种地址翻译的技巧是linux的拿手好戏,container_of随处可见,只是链表节点多被封装在更复杂的结构中,使用专门的list_entry定义也是为了使用方便。


  1. #define list_first_entry(ptr, type, member) \   
  2.     list_entry((ptr)->next, type, member)  

list_first_entry是将ptr看完一个链表的链表头,取出其中第一个节点对应的结构地址。使用list_first_entry是应保证链表中至少有一个节点。


  1. #define list_for_each(pos, head) \   
  2.     for (pos = (head)->next; prefetch(pos->next), pos != (head); \  
  3.             pos = pos->next)  

list_for_each循环遍历链表中的每个节点,从链表头部的第一个节点,一直到链表尾部。中间的prefetch是为了利用平台特性加速链表遍历,在某些平台下定义为空,可以忽略。


  1. #define __list_for_each(pos, head) \   
  2.     for (pos = (head)->next; pos != (head); pos = pos->next)  

__list_for_each与list_for_each没什么不同,只是少了prefetch的内容,实现上更为简单易懂。


  1. #define list_for_each_prev(pos, head) \   
  2.     for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \  
  3.             pos = pos->prev)  

list_for_each_prev与list_for_each的遍历顺序相反,从链表尾逆向遍历到链表头。


  1. #define list_for_each_safe(pos, n, head) \   
  2.     for (pos = (head)->next, n = pos->next; pos != (head); \  
  3.         pos = n, n = pos->next)  

list_for_each_safe 也是链表顺序遍历,只是更加安全。即使在遍历过程中,当前节点从链表中删除,也不会影响链表的遍历。参数上需要加一个暂存的链表节点指针n。


  1. #define list_for_each_prev_safe(pos, n, head) \   
  2.     for (pos = (head)->prev, n = pos->prev; \  
  3.          prefetch(pos->prev), pos != (head); \  
  4.          pos = n, n = pos->prev)  

list_for_each_prev_safe 与list_for_each_prev同样是链表逆序遍历,只是加了链表节点删除保护。


  1. #define list_for_each_entry(pos, head, member)              \   
  2.     for (pos = list_entry((head)->next, typeof(*pos), member);   \  
  3.          prefetch(pos->member.next), &pos->member != (head);  \  
  4.          pos = list_entry(pos->member.next, typeof(*pos), member))  

list_for_each_entry不是遍历链表节点,而是遍历链表节点所嵌套进的结构。这个实现上较为复杂,但可以等价于list_for_each加上list_entry的组合。


  1. #define list_for_each_entry_reverse(pos, head, member)          \   
  2.     for (pos = list_entry((head)->prev, typeof(*pos), member);   \  
  3.          prefetch(pos->member.prev), &pos->member != (head);  \  
  4.          pos = list_entry(pos->member.prev, typeof(*pos), member))  

list_for_each_entry_reverse 是逆序遍历链表节点所嵌套进的结构,等价于list_for_each_prev加上list_etnry的组合。


  1. #define list_for_each_entry_continue(pos, head, member)         \   
  2.     for (pos = list_entry(pos->member.next, typeof(*pos), member);   \  
  3.          prefetch(pos->member.next), &pos->member != (head);  \  
  4.          pos = list_entry(pos->member.next, typeof(*pos), member))  

list_for_each_entry_continue也是遍历链表上的节点嵌套的结构。只是并非从链表头开始,而是从结构指针的下一个结构开始,一直到链表尾部。


  1. #define list_for_each_entry_continue_reverse(pos, head, member)     \   
  2.     for (pos = list_entry(pos->member.prev, typeof(*pos), member);   \  
  3.          prefetch(pos->member.prev), &pos->member != (head);  \  
  4.          pos = list_entry(pos->member.prev, typeof(*pos), member))  

list_for_each_entry_continue_reverse 是逆序遍历链表上的节点嵌套的结构。只是并非从链表尾开始,而是从结构指针的前一个结构开始,一直到链表头部。


  1. #define list_for_each_entry_from(pos, head, member)             \   
  2.     for (; prefetch(pos->member.next), &pos->member != (head);    \  
  3.          pos = list_entry(pos->member.next, typeof(*pos), member))  

list_for_each_entry_from 是从当前结构指针pos开始,顺序遍历链表上的结构指针。


  1. #define list_for_each_entry_safe(pos, n, head, member)          \   
  2.     for (pos = list_entry((head)->next, typeof(*pos), member),   \  
  3.         n = list_entry(pos->member.next, typeof(*pos), member);  \  
  4.          &pos->member != (head);                     \  
  5.          pos = n, n = list_entry(n->member.next, typeof(*n), member))  

list_for_each_entry_safe 也是顺序遍历链表上节点嵌套的结构。只是加了删除节点的保护。


  1. #define list_for_each_entry_safe_continue(pos, n, head, member)         \   
  2.     for (pos = list_entry(pos->member.next, typeof(*pos), member),       \  
  3.         n = list_entry(pos->member.next, typeof(*pos), member);      \  
  4.          &pos->member != (head);                     \  
  5.          pos = n, n = list_entry(n->member.next, typeof(*n), member))  

list_for_each_entry_safe_continue 是从pos的下一个结构指针开始,顺序遍历链表上的结构指针,同时加了节点删除保护。


  1. #define list_for_each_entry_safe_from(pos, n, head, member)             \   
  2.     for (n = list_entry(pos->member.next, typeof(*pos), member);     \  
  3.          &pos->member != (head);                     \  
  4.          pos = n, n = list_entry(n->member.next, typeof(*n), member))  

list_for_each_entry_safe_from 是从pos开始,顺序遍历链表上的结构指针,同时加了节点删除保护。 


  1. #define list_for_each_entry_safe_reverse(pos, n, head, member)      \   
  2.     for (pos = list_entry((head)->prev, typeof(*pos), member),   \  
  3.         n = list_entry(pos->member.prev, typeof(*pos), member);  \  
  4.          &pos->member != (head);                     \  
  5.          pos = n, n = list_entry(n->member.prev, typeof(*n), member))  

list_for_each_entry_safe_reverse 是从pos的前一个结构指针开始,逆序遍历链表上的结构指针,同时加了节点删除保护。


至此为止,我们介绍了linux中双向循环链表的结构、所有的操作函数和遍历宏定义。相信以后在linux代码中遇到链表的使用,不会再陌生。

在任何处理器平台下,都会有一些原子性操作,供操作系统使用,我们这里只讲x86下面的。在单处理器情况下,每条指令的执行都是原子性的,但在多处理器情况下,只有那些单独的读操作或写操作才是原子性的。为了弥补这一缺点,x86提供了附加的lock前缀,使带lock前缀的读修改写指令也能原子性执行。带lock前缀的指令在操作时会锁住总线,使自身的执行即使在多处理器间也是原子性执行的。xchg指令不带lock前缀也是原子性执行,也就是说xchg执行时默认会锁内存总线。原子性操作是线程间同步的基础,linux专门定义了一种只进行原子操作的类型atomic_t,并提供相关的原子读写调用API。本节就来分析这些原子操作在x86下的实现。


  1. typedef struct {  

  2.     volatile int counter;  

  3. } atomic_t;  

原子类型其实是int类型,只是禁止寄存器对其暂存。


  1. #define ATOMIC_INIT(i)  { (i) }  

原子类型的初始化。32位x86平台下atomic API在arch/x86/include/asm/atomic_32.h中实现。


  1. static inline int atomic_read(const atomic_t *v)  

  2. {  

  3.     return v->counter;  

  4. }  

  5.   

  6. static inline void atomic_set(atomic_t *v, int i)  

  7. {  

  8.     v->counter = i;  

  9. }  

单独的读操作或者写操作,在x86下都是原子性的。


  1. static inline void atomic_add(int i, atomic_t *v)  

  2. {  

  3.     asm volatile(LOCK_PREFIX “addl %1,%0”  

  4.              : “+m” (v->counter)  

  5.              : “ir” (i));  

  6. }  

  7.   

  8. static inline void atomic_sub(int i, atomic_t *v)  

  9. {  

  10.     asm volatile(LOCK_PREFIX “subl %1,%0”  

  11.              : “+m” (v->counter)  

  12.              : “ir” (i));  

  13. }  

atomic_add和atomic_sub属于读修改写操作,实现时需要加lock前缀。


  1. static inline int atomic_sub_and_test(int i, atomic_t *v)  

  2. {  

  3.     unsigned char c;  

  4.   

  5.     asm volatile(LOCK_PREFIX “subl %2,%0; sete %1”  

  6.              : “+m” (v->counter), “=qm” (c)  

  7.              : “ir” (i) : “memory”);  

  8.     return c;  

  9. }  

atomic_sub_and_test执行完减操作后检查结果是否为0。


  1. static inline void atomic_inc(atomic_t *v)  

  2. {  

  3.     asm volatile(LOCK_PREFIX “incl %0”  

  4.              : “+m” (v->counter));  

  5. }  

  6.   

  7. static inline void atomic_dec(atomic_t *v)  

  8. {  

  9.     asm volatile(LOCK_PREFIX “decl %0”  

  10.              : “+m” (v->counter));  

  11. }  

atomic_inc和atomic_dec是递增递减操作。


  1. static inline int atomic_dec_and_test(atomic_t *v)  

  2. {  

  3.     unsigned char c;  

  4.   

  5.     asm volatile(LOCK_PREFIX “decl %0; sete %1”  

  6.              : “+m” (v->counter), “=qm” (c)  

  7.              : : “memory”);  

  8.     return c != 0;  

  9. }  

atomic_dec_and_test在递减后检查结果是否为0。


  1. static inline int atomic_inc_and_test(atomic_t *v)  

  2. {  

  3.     unsigned char c;  

  4.   

  5.     asm volatile(LOCK_PREFIX “incl %0; sete %1”  

  6.              : “+m” (v->counter), “=qm” (c)  

  7.              : : “memory”);  

  8.     return c != 0;  

  9. }  

atomic_inc_and_test在递增后检查结果是否为0。


  1. static inline int atomic_add_negative(int i, atomic_t *v)  

  2. {  

  3.     unsigned char c;  

  4.   

  5.     asm volatile(LOCK_PREFIX “addl %2,%0; sets %1”  

  6.              : “+m” (v->counter), “=qm” (c)  

  7.              : “ir” (i) : “memory”);  

  8.     return c;  

  9. }  

atomic_add_negative在加操作后检查结果是否为负数。


  1. static inline int atomic_add_return(int i, atomic_t *v)  

  2. {  

  3.     int __i;  

  4. #ifdef CONFIG_M386   

  5.     unsigned long flags;  

  6.     if (unlikely(boot_cpu_data.x86 <= 3))  

  7.         goto no_xadd;  

  8. #endif   

  9.     /* Modern 486+ processor */  

  10.     __i = i;  

  11.     asm volatile(LOCK_PREFIX “xaddl %0, %1”  

  12.              : “+r” (i), “+m” (v->counter)  

  13.              : : “memory”);  

  14.     return i + __i;  

  15.   

  16. #ifdef CONFIG_M386   

  17. no_xadd: /* Legacy 386 processor */  

  18.     local_irq_save(flags);  

  19.     __i = atomic_read(v);  

  20.     atomic_set(v, i + __i);  

  21.     local_irq_restore(flags);  

  22.     return i + __i;  

  23. #endif   

  24. }  

atomic_add_return 不仅执行加操作,而且把相加的结果返回。它是通过xadd这一指令实现的。


  1. static inline int atomic_sub_return(int i, atomic_t *v)  

  2. {  

  3.     return atomic_add_return(-i, v);  

  4. }  

atomic_sub_return 不仅执行减操作,而且把相减的结果返回。它是通过atomic_add_return实现的。


  1. static inline int atomic_cmpxchg(atomic_t *v, int old, int new)  

  2. {  

  3.     return cmpxchg(&v->counter, old, new);  

  4. }  

  5.   

  6. #define cmpxchg(ptr, o, n)                      \   

  7.     ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),   \  

  8.                        (unsigned long)(n),      \  

  9.                        sizeof(*(ptr))))  

  10.   

  11. static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,  

  12.                       unsigned long newint size)  

  13. {  

  14.     unsigned long prev;  

  15.     switch (size) {  

  16.     case 1:  

  17.         asm volatile(LOCK_PREFIX “cmpxchgb %b1,%2”  

  18.                  : “=a”(prev)  

  19.                  : “q”(new), “m”(*__xg(ptr)), “0”(old)  

  20.                  : “memory”);  

  21.         return prev;  

  22.     case 2:  

  23.         asm volatile(LOCK_PREFIX “cmpxchgw %w1,%2”  

  24.                  : “=a”(prev)  

  25.                  : “r”(new), “m”(*__xg(ptr)), “0”(old)  

  26.                  : “memory”);  

  27.         return prev;  

  28.     case 4:  

  29.         asm volatile(LOCK_PREFIX “cmpxchgl %k1,%2”  

  30.                  : “=a”(prev)  

  31.                  : “r”(new), “m”(*__xg(ptr)), “0”(old)  

  32.                  : “memory”);  

  33.         return prev;  

  34.     case 8:  

  35.         asm volatile(LOCK_PREFIX “cmpxchgq %1,%2”  

  36.                  : “=a”(prev)  

  37.                  : “r”(new), “m”(*__xg(ptr)), “0”(old)  

  38.                  : “memory”);  

  39.         return prev;  

  40.     }  

  41.     return old;  

  42. }  

atomic_cmpxchg是由cmpxchg指令完成的。它把旧值同atomic_t类型的值相比较,如果相同,就把新值存入atomic_t类型的值中,返回atomic_t类型变量中原有的值。


  1. static inline int atomic_xchg(atomic_t *v, int new)  

  2. {  

  3.     return xchg(&v->counter, new);  

  4. }  

  5.   

  6. #define xchg(ptr, v)                            \   

  7.     ((__typeof__(*(ptr)))__xchg((unsigned long)(v), (ptr), sizeof(*(ptr))))  

  8.   

  9. static inline unsigned long __xchg(unsigned long x, volatile void *ptr,  

  10.                    int size)  

  11. {  

  12.     switch (size) {  

  13.     case 1:  

  14.         asm volatile(“xchgb %b0,%1”  

  15.                  : “=q” (x)  

  16.                  : “m” (*__xg(ptr)), “0” (x)  

  17.                  : “memory”);  

  18.         break;  

  19.     case 2:  

  20.         asm volatile(“xchgw %w0,%1”  

  21.                  : “=r” (x)  

  22.                  : “m” (*__xg(ptr)), “0” (x)  

  23.                  : “memory”);  

  24.         break;  

  25.     case 4:  

  26.         asm volatile(“xchgl %k0,%1”  

  27.                  : “=r” (x)  

  28.                  : “m” (*__xg(ptr)), “0” (x)  

  29.                  : “memory”);  

  30.         break;  

  31.     case 8:  

  32.         asm volatile(“xchgq %0,%1”  

  33.                  : “=r” (x)  

  34.                  : “m” (*__xg(ptr)), “0” (x)  

  35.                  : “memory”);  

  36.         break;  

  37.     }  

  38.     return x;  

  39. }  

atomic_xchg则是将新值存入atomic_t类型的变量,并将变量的旧值返回。它使用xchg指令实现。


  1. /** 

  2.  * atomic_add_unless – add unless the number is already a given value 

  3.  * @v: pointer of type atomic_t 

  4.  * @a: the amount to add to v… 

  5.  * @u: …unless v is equal to u. 

  6.  * 

  7.  * Atomically adds @a to @v, so long as @v was not already @u. 

  8.  * Returns non-zero if @v was not @u, and zero otherwise. 

  9.  */  

  10. static inline int atomic_add_unless(atomic_t *v, int a, int u)  

  11. {  

  12.     int c, old;  

  13.     c = atomic_read(v);  

  14.     for (;;) {  

  15.         if (unlikely(c == (u)))  

  16.             break;  

  17.         old = atomic_cmpxchg((v), c, c + (a));  

  18.         if (likely(old == c))  

  19.             break;  

  20.         c = old;  

  21.     }  

  22.     return c != (u);  

  23. }  

atomic_add_unless的功能比较特殊。它检查v是否等于u,如果不是则把v的值加上a,返回值表示相加前v是否等于u。因为在atomic_read和atomic_cmpxchg中间可能有其它的写操作,所以要循环检查自己的值是否被写进去。


  1. #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)   

  2.   

  3. #define atomic_inc_return(v)  (atomic_add_return(1, v))   

  4. #define atomic_dec_return(v)  (atomic_sub_return(1, v))  

atomic_inc_not_zero在v值不是0时加1。


atomic_inc_return对v值加1,并返回相加结果。


atomic_dec_return对v值减1,并返回相减结果。


  1. #define atomic_clear_mask(mask, addr)               \   

  2.     asm volatile(LOCK_PREFIX “andl %0,%1”           \  

  3.              : : “r” (~(mask)), “m” (*(addr)) : “memory”)  

atomic_clear_mask清除变量某些位。


  1. #define atomic_set_mask(mask, addr)             \   

  2.     asm volatile(LOCK_PREFIX “orl %0,%1”                \  

  3.              : : “r” (mask), “m” (*(addr)) : “memory”)  

atomic_set_mask将变量的某些位置位。


  1. /* Atomic operations are already serializing on x86 */  

  2. #define smp_mb__before_atomic_dec() barrier()   

  3. #define smp_mb__after_atomic_dec()  barrier()   

  4. #define smp_mb__before_atomic_inc() barrier()   

  5. #define smp_mb__after_atomic_inc()  barrier()  

因为x86的atomic操作大多使用原子指令或者带lock前缀的指令。带lock前缀的指令执行前会完成之前的读写操作,对于原子操作来说不会受之前对同一位置的读写操作,所以这里只是用空操作barrier()代替。barrier()的作用相当于告诉编译器这里有一个内存屏障,放弃在寄存器中的暂存值,重新从内存中读入。


本节的atomic_t类型操作是最基础的,为了介绍下面的内容,必须先介绍它。如果可以使用atomic_t类型代替临界区操作,也可以加快不少速度。

kref是一个引用计数器,它被嵌套进其它的结构中,记录所嵌套结构的引用计数,并在计数清零时调用相应的清理函数。kref的原理和实现都非常简单,但要想用好却不容易,或者说kref被创建就是为了跟踪复杂情况下地结构引用销毁情况。所以这里先介绍kref的实现,再介绍其使用规则。

kref的头文件在include/linux/kref.h,实现在lib/kref.c。闲话少说,上代码。


  1. struct kref {  

  2.     atomic_t refcount;  

  3. };  
      可以看到,kref的结构中就包含一个atomic_t类型的计数值。atomic_t是原子类型,对其操作都要求是原子执行的,有专门的原子操作API执行,即使在多处理器间也保持原子性。使用atomic_t类型充当计数值,就省去了加锁去锁的过程。


  1. void kref_set(struct kref *kref, int num)  

  2. {  

  3.     atomic_set(&kref->refcount, num);  

  4.     smp_mb();  

  5. }  
kref_set 设置kref的初始计数值。具体计数值设置由原子操作atomic_set完成。之后还有一个smp_mb()是为了增加内存屏障,保证这一写操作会在之后的读写操作完成之前完成。


  1. void kref_init(struct kref *kref)  

  2. {  

  3.     kref_set(kref, 1);  

  4. }  

kref_init 初始化kref的计数值为1。


  1. void kref_get(struct kref *kref)  

  2. {  

  3.     WARN_ON(!atomic_read(&kref->refcount));  

  4.     atomic_inc(&kref->refcount);  

  5.     smp_mb__after_atomic_inc();  

  6. }  

kref_get递增kref的计数值。


  1. int kref_put(struct kref *kref, void (*release)(struct kref *kref))  

  2. {  

  3.     WARN_ON(release == NULL);  

  4.     WARN_ON(release == (void (*)(struct kref *))kfree);  

  5.   

  6.     if (atomic_dec_and_test(&kref->refcount)) {  

  7.         release(kref);  

  8.         return 1;  

  9.     }  

  10.     return 0;  

  11. }  

kref_put递减kref的计数值,如果计数值减为0,说明kref所指向的结构生命周期结束,会执行release释放函数。


所以说kref的API很简单,kref_init和kref_set基本都是初始时才会用到,平时常用的就是kref_get和kref_put。一旦在kref_put时计数值清零,立即调用结束函数。


kref设计得如此简单,是为了能灵活地用在各种结构的生命周期管理中。要用好它可不简单,好在Documentation/kref.txt中为我们总结了一些使用规则,下面简单翻译一下。


对于那些用在多种场合,被到处传递的结构,如果没有引用计数,bug几乎总是肯定的事。所以我们需要kref。kref允许我们在已有的结构中方便地添加引用计数。


你可以以如下方式添加kref到你的数据结构中:


  1. struct my_data {  

  2.     …  

  3.     struct kref refcount;  

  4.     …  

  5. };  

kref可以出现在你结构中的任意位置。


在分配kref后你必须初始化它,可以调用kref_init,把kref计数值初始为1。


  1. struct my_data *data;  

  2.   

  3. data = kmalloc(sizeof(*data), GFP_KERNEL);  

  4. if(!data)  

  5.     return -ENOMEM;  

  6. kref_init(&data->refcount);  

初始化之后,kref的使用应该遵循以下三条规则:


1) 如果你制造了一个结构指针的非暂时性副本,特别是当这个副本指针会被传递到其它执行线程时,你必须在传递副本指针之前执行kref_get:


  1. kref_put(&data->refcount);  

2)当你使用完,不再需要结构的指针,必须执行kref_put。如果这是结构指针的最后一个引用,release函数会被调用。如果代码绝不会在没有拥有引用计数的请求下去调用kref_get,在kref_put时就不需要加锁。


  1. kref_put(&data->refcount, data_release);  

3)如果代码试图在还没拥有引用计数的情况下就调用kref_get,就必须串行化kref_put和kref_get的执行。因为很可能在kref_get执行之前或者执行中,kref_put就被调用并把整个结构释放掉了。 


例如,你分配了一些数据并把它传递到其它线程去处理:


  1. void data_release(struct kref *kref)  

  2. {  

  3.     struct my_data *data = container_of(kref, struct my_data, refcount);  

  4.     kree(data);  

  5. }  

  6.   

  7. void more_data_handling(void *cb_data)  

  8. {  

  9.     struct my_data *data = cb_data;  

  10.     .  

  11.     .  do stuff with data here  

  12.     .  

  13.     kref_put(&data->refcount, data_release);  

  14. }  

  15.   

  16. int my_data_handler(void)  

  17. {  

  18.     int rv = 0;  

  19.     struct my_data *data;  

  20.     struct task_struct *task;  

  21.     data = kmalloc(sizeof(*data), GFP_KERNEL);  

  22.      if (!data)  

  23.         return -ENOMEM;  

  24.     kref_init(&data->refcount);  

  25.     kref_get(&data->refcount);  

  26.     task = kthread_run(more_data_handling, data, “more_data_handling”);  

  27.     if (task == ERR_PTR(-ENOMEM)){  

  28.          rv = -ENOMEM;  

  29.          goto out;  

  30.     }  

  31.     .  

  32.     .  do stuff with data here  

  33.     .  

  34. out:  

  35.     kref_put(&data->refcount, data_release);  

  36.     return rv;  

  37. }  

这样做,无论两个线程的执行顺序是怎样的都无所谓,kref_put知道何时数据不再有引用计数,可以被销毁。kref_get()调用不需要加锁,因为在my_data_handler中调用kref_get时已经拥有一个引用。同样地原因,kref_put也不需要加锁。


要注意规则一中的要求,必须在传递指针之前调用kref_get。决不能写下面的代码:


  1. task = kthread_run(more_data_handling, data, “more_data_handling”);  

  2. if(task == ERR_PTR(-ENOMEM)) {  

  3.     rv = -ENOMEM;  

  4.     goto out;  

  5. }  

  6. else {  

  7.      /* BAD BAD BAD – get is after the handoff */  

  8.     kref_get(&data->refcount);  

不要认为自己在使用上面的代码时知道自己在做什么。首先,你可能并不知道你在做什么。其次,你可能知道你在做什么(在部分加锁情况下上面的代码也是正确的),但一些修改或者复制你代码的人并不知道你在做什么。这是一种坏的使用方式。


当然在部分情况下也可以优化对get和put的使用。例如,你已经完成了对这个数据的处理,并要把它传递给其它线程,就不需要再做多余的get和put了。


  1. /* Silly extra get and put */  

  2. kref_get(&obj->ref);  

  3. enqueue(obj);  

  4. kref_put(&obj->ref, obj_cleanup);  

只需要做enqueue操作即可,可以在其后加一条注释。


  1. enqueue(obj);  

  2. /* We are done with obj , so we pass our refcount off to the queue. DON’T TOUCH obj AFTER HERE! */  

第三条规则是处理起来最麻烦的。例如,你有一列数据,每条数据都有kref计数,你希望获取第一条数据。但你不能简单地把第一条数据从链表中取出并调用kref_get。这违背了第三条,在调用kref_get前你并没有一个引用。你需要增加一个mutex(或者其它锁)。


  1. static DEFINE_MUTEX(mutex);  

  2. static LIST_HEAD(q);  

  3. struct my_data  

  4. {  

  5.     struct kref refcount;  

  6.     struct list_head link;  

  7. };  

  8.   

  9. static struct my_data *get_entry()  

  10. {  

  11.     struct my_data *entry = NULL;  

  12.     mutex_lock(&mutex);  

  13.     if(!list_empty(&q)){  

  14.         entry = container_of(q.next, struct my_q_entry, link);  

  15.         kref_get(&entry->refcount);  

  16.     }  

  17.     mutex_unlock(&mutex);  

  18.     return entry;  

  19. }  

  20.           

  21. static void release_entry(struct kref *ref)  

  22. {  

  23.     struct my_data *entry = container_of(ref, struct my_data, refcount);  

  24.       

  25.     list_del(&entry->link);  

  26.     kfree(entry);  

  27. }  

  28.   

  29. static void put_entry(struct my_data *entry)  

  30. {  

  31.     mutex_lock(&mutex);  

  32.     kref_put(&entry->refcount, release_entry);  

  33.     mutex_unlock(&mutex);  

  34. }  

如果你不想在整个释放过程中都加锁,kref_put的返回值就有用了。例如你不想在加锁情况下调用kfree,你可以如下使用kref_put。


  1. static void release_entry(struct kref *ref)  

  2. {  

  3.       

  4. }  

  5.   

  6. static void put_entry(struct my_data *entry)  

  7. {  

  8.     mutex_lock(&mutex);  

  9.     if(kref_put(&entry->refcount, release_entry)){  

  10.         list_del(&entry->link);  

  11.         mutex_unlock(&mutex);  

  12.         kfree(entry);  

  13.     }  

  14.     else  

  15.         mutex_unlock(&mutex);  

  16. }  

如果你在撤销结构的过程中需要调用其它的需要较长时间的函数,或者函数也可能要获取同样地互斥锁,这样做就很有用了。但要注意在release函数中做完撤销工作会使代码看起来更整洁。

前面我们说到过list_head,这是linux中通用的链表形式,双向循环链表,功能强大,实现简单优雅。可如果您认为list_head就是链表的极致,应该在linux链表界一统天下,那可就错了。据我所知,linux内核代码中至少还有两种链表能占有一席之地。一种就是hlist,一种就是本节要介绍的klist。虽然三者不同,但hlist和klist都可以看成是从list_head中发展出来的,用于特殊的链表使用情景。hlist是用于哈希表中。众所周知,哈希表主要就是一个哈希数组,为了解决映射冲突的问题,常常把哈希数组的每一项做成一个链表,这样有多少重复的都可以链进去。但哈希数组的项很多,list_head的话每个链表头都需要两个指针的空间,在稀疏的哈希表中实在是一种浪费,于是就发明了hlist。hlist有两大特点,一是它的链表头只需要一个指针,二是它的每一项都可以找到自己的前一节点,也就是说它不再循环,但仍是双向。令人不解的是,hlist的实现太绕了,比如它明明可以直接指向前一节点,却偏偏指向指针地址,还是前一节点中指向后一节点的指针地址。即使这种设计在实现时占便宜,但它理解上带来的不便已经远远超过实现上带来的小小便利。

同hlist一样,klist也是为了适应某类特殊情形的要求。考虑一个被简化的情形,假设一些设备被链接在设备链表中,一个线程命令卸载某设备,即将其从设备链表中删除,但这时该设备正在使用中,这时就出现了冲突。当前可以设置临界区并加锁,但因为使用一个设备而锁住整个设备链表显然是不对的;又或者可以从设备本身做文章,让线程阻塞,这当然也可以。但我们上节了解了kref,就该知道linux对待这种情况的风格,给它一个引用计数kref,等计数为零就删除。klist就是这么干的,它把kref直接保存在了链表节点上。之前说到有线程要求删除设备,之前的使用仍存在,所以不能实际删除,但不应该有新的应用访问到该设备。klist就提供了一种让节点在链表上隐身的方法。下面还是来看实际代码吧。


klist的头文件是include/linux/klist.h,实现在lib/klist.c。


  1. struct klist_node;  
  2. struct klist {  
  3.     spinlock_t      k_lock;  
  4.     struct list_head    k_list;  
  5.     void            (*get)(struct klist_node *);  
  6.     void            (*put)(struct klist_node *);  
  7. } __attribute__ ((aligned (4)));  
  8.   
  9. #define KLIST_INIT(_name, _get, _put)                   \   
  10.     { .k_lock   = __SPIN_LOCK_UNLOCKED(_name.k_lock),       \  
  11.       .k_list   = LIST_HEAD_INIT(_name.k_list),         \  
  12.       .get      = _get,                     \  
  13.       .put      = _put, }  
  14.   
  15. #define DEFINE_KLIST(_name, _get, _put)                 \   
  16.     struct klist _name = KLIST_INIT(_name, _get, _put)  
  17.   
  18. extern void klist_init(struct klist *k, void (*get)(struct klist_node *),  
  19.                void (*put)(struct klist_node *));  
  20.   
  21. struct klist_node {  
  22.     void            *n_klist;   /* never access directly */  
  23.     struct list_head    n_node;  
  24.     struct kref     n_ref;  
  25. };  

可以看到,klist的链表头是struct klist结构,链表节点是struct klist_node结构。先看struct klist,除了包含链表需要的k_list,还有用于加锁的k_lock。剩余的get()和put()函数是用于struct klist_node嵌入在更大的结构中,这样在节点初始时调用get(),在节点删除时调用put(),以表示链表中存在对结构的引用。再看struct klist_node,除了链表需要的n_node,还有一个引用计数n_ref。还有一个比较特殊的指针n_klist,n_klist是指向链表头struct klist的,但它的第0位用来表示是否该节点已被请求删除,如果已被请求删除则在链表循环时是看不到这一节点的,循环函数将其略过。现在你明白为什么非要在struct klist的定义后加上__attribute__((aligned(4)))。不过说实话这样在x86下仍然不太保险,但linux选择了相信gcc,毕竟是多年的战友和兄弟了,相互知根知底。


看过这两个结构,想必大家已经较为清楚了,下面就来看看它们的实现。


  1. /* 
  2.  * Use the lowest bit of n_klist to mark deleted nodes and exclude 
  3.  * dead ones from iteration. 
  4.  */  
  5. #define KNODE_DEAD      1LU   
  6. #define KNODE_KLIST_MASK    ~KNODE_DEAD   
  7.   
  8. static struct klist *knode_klist(struct klist_node *knode)  
  9. {  
  10.     return (struct klist *)  
  11.         ((unsigned long)knode->n_klist & KNODE_KLIST_MASK);  
  12. }  
  13.   
  14. static bool knode_dead(struct klist_node *knode)  
  15. {  
  16.     return (unsigned long)knode->n_klist & KNODE_DEAD;  
  17. }  
  18.   
  19. static void knode_set_klist(struct klist_node *knode, struct klist *klist)  
  20. {  
  21.     knode->n_klist = klist;  
  22.     /* no knode deserves to start its life dead */  
  23.     WARN_ON(knode_dead(knode));  
  24. }  
  25.   
  26. static void knode_kill(struct klist_node *knode)  
  27. {  
  28.     /* and no knode should die twice ever either, see we’re very humane */  
  29.     WARN_ON(knode_dead(knode));  
  30.     *(unsigned long *)&knode->n_klist |= KNODE_DEAD;  
  31. }  

前面的四个函数都是内部静态函数,帮助API实现的。knode_klist()是从节点找到链表头。knode_dead()是检查该节点是否已被请求删除。


knode_set_klist设置节点的链表头。knode_kill将该节点请求删除。细心的话大家会发现这四个函数是对称的,而且都是操作节点的内部函数。


  1. void klist_init(struct klist *k, void (*get)(struct klist_node *),  
  2.         void (*put)(struct klist_node *))  
  3. {  
  4.     INIT_LIST_HEAD(&k->k_list);  
  5.     spin_lock_init(&k->k_lock);  
  6.     k->get = get;  
  7.     k->put = put;  
  8. }  

klist_init,初始化klist。


  1. static void add_head(struct klist *k, struct klist_node *n)  
  2. {  
  3.     spin_lock(&k->k_lock);  
  4.     list_add(&n->n_node, &k->k_list);  
  5.     spin_unlock(&k->k_lock);  
  6. }  
  7.   
  8. static void add_tail(struct klist *k, struct klist_node *n)  
  9. {  
  10.     spin_lock(&k->k_lock);  
  11.     list_add_tail(&n->n_node, &k->k_list);  
  12.     spin_unlock(&k->k_lock);  
  13. }  
  14.   
  15. static void klist_node_init(struct klist *k, struct klist_node *n)  
  16. {  
  17.     INIT_LIST_HEAD(&n->n_node);  
  18.     kref_init(&n->n_ref);  
  19.     knode_set_klist(n, k);  
  20.     if (k->get)  
  21.         k->get(n);  
  22. }  

又是三个内部函数,add_head()将节点加入链表头,add_tail()将节点加入链表尾,klist_node_init()是初始化节点。注意在节点的引用计数初始化时,因为引用计数变为1,所以也要调用相应的get()函数。


  1. void klist_add_head(struct klist_node *n, struct klist *k)  
  2. {  
  3.     klist_node_init(k, n);  
  4.     add_head(k, n);  
  5. }  
  6.   
  7. void klist_add_tail(struct klist_node *n, struct klist *k)  
  8. {  
  9.     klist_node_init(k, n);  
  10.     add_tail(k, n);  
  11. }  

klist_add_head()将节点初始化,并加入链表头。


klist_add_tail()将节点初始化,并加入链表尾。


它们正是用上面的三个内部函数实现的,可见linux内核中对函数复用有很强的执念,其实这里add_tail和add_head是不用的,纵观整个文件,也只有klist_add_head()和klist_add_tail()对它们进行了调用。


  1. void klist_add_after(struct klist_node *n, struct klist_node *pos)  
  2. {  
  3.     struct klist *k = knode_klist(pos);  
  4.   
  5.     klist_node_init(k, n);  
  6.     spin_lock(&k->k_lock);  
  7.     list_add(&n->n_node, &pos->n_node);  
  8.     spin_unlock(&k->k_lock);  
  9. }  
  10.   
  11. void klist_add_before(struct klist_node *n, struct klist_node *pos)  
  12. {  
  13.     struct klist *k = knode_klist(pos);  
  14.   
  15.     klist_node_init(k, n);  
  16.     spin_lock(&k->k_lock);  
  17.     list_add_tail(&n->n_node, &pos->n_node);  
  18.     spin_unlock(&k->k_lock);  
  19. }  

klist_add_after()将节点加到指定节点后面。


klist_add_before()将节点加到指定节点前面。


这两个函数都是对外提供的API。在list_head中都没有看到有这种API,所以说需求决定了接口。虽说只有一步之遥,klist也不愿让外界介入它的内部实现。


之前出现的API都太常见了,既没有使用引用计数,又没有跳过请求删除的节点。所以klist的亮点在下面,klist链表的遍历。


  1. struct klist_iter {  
  2.     struct klist    *i_klist;  
  3.     struct klist_node   *i_cur;  
  4. };  
  5.   
  6.   
  7. extern void klist_iter_init(struct klist *k, struct klist_iter *i);  
  8. extern void klist_iter_init_node(struct klist *k, struct klist_iter *i,  
  9.                  struct klist_node *n);  
  10. extern void klist_iter_exit(struct klist_iter *i);  
  11. extern struct klist_node *klist_next(struct klist_iter *i);  

以上就是链表遍历需要的辅助结构struct klist_iter,和遍历用到的四个函数。


  1. struct klist_waiter {  
  2.     struct list_head list;  
  3.     struct klist_node *node;  
  4.     struct task_struct *process;  
  5.     int woken;  
  6. };  
  7.   
  8. static DEFINE_SPINLOCK(klist_remove_lock);  
  9. static LIST_HEAD(klist_remove_waiters);  
  10.   
  11. static void klist_release(struct kref *kref)  
  12. {  
  13.     struct klist_waiter *waiter, *tmp;  
  14.     struct klist_node *n = container_of(kref, struct klist_node, n_ref);  
  15.   
  16.     WARN_ON(!knode_dead(n));  
  17.     list_del(&n->n_node);  
  18.     spin_lock(&klist_remove_lock);  
  19.     list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) {  
  20.         if (waiter->node != n)  
  21.             continue;  
  22.   
  23.         waiter->woken = 1;  
  24.         mb();  
  25.         wake_up_process(waiter->process);  
  26.         list_del(&waiter->list);  
  27.     }  
  28.     spin_unlock(&klist_remove_lock);  
  29.     knode_set_klist(n, NULL);  
  30. }  
  31.   
  32. static int klist_dec_and_del(struct klist_node *n)  
  33. {  
  34.     return kref_put(&n->n_ref, klist_release);  
  35. }  
  36.   
  37. static void klist_put(struct klist_node *n, bool kill)  
  38. {  
  39.     struct klist *k = knode_klist(n);  
  40.     void (*put)(struct klist_node *) = k->put;  
  41.   
  42.     spin_lock(&k->k_lock);  
  43.     if (kill)  
  44.         knode_kill(n);  
  45.     if (!klist_dec_and_del(n))  
  46.         put = NULL;  
  47.     spin_unlock(&k->k_lock);  
  48.     if (put)  
  49.         put(n);  
  50. }  
  51.   
  52. /** 
  53.  * klist_del – Decrement the reference count of node and try to remove. 
  54.  * @n: node we’re deleting. 
  55.  */  
  56. void klist_del(struct klist_node *n)  
  57. {  
  58.     klist_put(n, true);  
  59. }  


以上的内容乍一看很难理解,其实都是klist实现必须的。因为使用kref动态删除,自然需要一个计数降为零时调用的函数klist_release。


klist_dec_and_del()就是对kref_put()的包装,起到减少节点引用计数的功能。


至于为什么会出现一个新的结构struct klist_waiter,也很简单。之前说有线程申请删除某节点,但节点的引用计数仍在,所以只能把请求删除的线程阻塞,就是用struct klist_waiter阻塞在klist_remove_waiters上。所以在klist_release()调用时还要将阻塞的线程唤醒。knode_kill()将节点设为已请求删除。而且还会调用put()函数。


释放引用计数是调用klist_del(),它通过内部函数klist_put()完成所需操作:用knode_kill()设置节点为已请求删除,用klist_dec_and_del()释放引用,调用可能的put()函数。


  1. /** 
  2.  * klist_remove – Decrement the refcount of node and wait for it to go away. 
  3.  * @n: node we’re removing. 
  4.  */  
  5. void klist_remove(struct klist_node *n)  
  6. {  
  7.     struct klist_waiter waiter;  
  8.   
  9.     waiter.node = n;  
  10.     waiter.process = current;  
  11.     waiter.woken = 0;  
  12.     spin_lock(&klist_remove_lock);  
  13.     list_add(&waiter.list, &klist_remove_waiters);  
  14.     spin_unlock(&klist_remove_lock);  
  15.   
  16.     klist_del(n);  
  17.   
  18.     for (;;) {  
  19.         set_current_state(TASK_UNINTERRUPTIBLE);  
  20.         if (waiter.woken)  
  21.             break;  
  22.         schedule();  
  23.     }  
  24.     __set_current_state(TASK_RUNNING);  
  25. }  

klist_remove()不但会调用klist_del()减少引用计数,还会一直阻塞到节点被删除。这个函数才是请求删除节点的线程应该调用的。


  1. int klist_node_attached(struct klist_node *n)  
  2. {  
  3.     return (n->n_klist != NULL);  
  4. }  

klist_node_attached()检查节点是否被包含在某链表中。


以上是klist的链表初始化,节点加入,节点删除函数。下面是klist链表遍历函数。


  1. struct klist_iter {  
  2.     struct klist        *i_klist;  
  3.     struct klist_node   *i_cur;  
  4. };  
  5.   
  6.   
  7. extern void klist_iter_init(struct klist *k, struct klist_iter *i);  
  8. extern void klist_iter_init_node(struct klist *k, struct klist_iter *i,  
  9.                  struct klist_node *n);  
  10. extern void klist_iter_exit(struct klist_iter *i);  
  11. extern struct klist_node *klist_next(struct klist_iter *i);  

klist的遍历有些复杂,因为它考虑到了在遍历过程中节点删除的情况,而且还要忽略那些已被删除的节点。宏实现已经无法满足要求,迫不得已,只能用函数实现,并用struct klist_iter记录中间状态。


  1. void klist_iter_init_node(struct klist *k, struct klist_iter *i,  
  2.               struct klist_node *n)  
  3. {  
  4.     i->i_klist = k;  
  5.     i->i_cur = n;  
  6.     if (n)  
  7.         kref_get(&n->n_ref);  
  8. }  
  9.   
  10. void klist_iter_init(struct klist *k, struct klist_iter *i)  
  11. {  
  12.     klist_iter_init_node(k, i, NULL);  
  13. }  

klist_iter_init_node()是从klist中的某个节点开始遍历,而klist_iter_init()是从链表头开始遍历的。


但你又要注意,klist_iter_init()和klist_iter_init_node()的用法又不同。klist_iter_init_node()可以在其后直接对当前节点进行访问,也可以调用klist_next()访问下一节点。而klist_iter_init()只能调用klist_next()访问下一节点。或许klist_iter_init_node()的本意不是从当前节点开始,而是从当前节点的下一节点开始。


  1. static struct klist_node *to_klist_node(struct list_head *n)  
  2. {  
  3.     return container_of(n, struct klist_node, n_node);  
  4. }  

 


  1. struct klist_node *klist_next(struct klist_iter *i)  
  2. {  
  3.     void (*put)(struct klist_node *) = i->i_klist->put;  
  4.     struct klist_node *last = i->i_cur;  
  5.     struct klist_node *next;  
  6.   
  7.     spin_lock(&i->i_klist->k_lock);  
  8.   
  9.     if (last) {  
  10.         next = to_klist_node(last->n_node.next);  
  11.         if (!klist_dec_and_del(last))  
  12.             put = NULL;  
  13.     } else  
  14.         next = to_klist_node(i->i_klist->k_list.next);  
  15.   
  16.     i->i_cur = NULL;  
  17.     while (next != to_klist_node(&i->i_klist->k_list)) {  
  18.         if (likely(!knode_dead(next))) {  
  19.             kref_get(&next->n_ref);  
  20.             i->i_cur = next;  
  21.             break;  
  22.         }  
  23.         next = to_klist_node(next->n_node.next);  
  24.     }  
  25.   
  26.     spin_unlock(&i->i_klist->k_lock);  
  27.   
  28.     if (put && last)  
  29.         put(last);  
  30.     return i->i_cur;  
  31. }  

klist_next()是将循环进行到下一节点。实现中需要注意两点问题:1、加锁,根据经验,单纯对某个节点操作不需要加锁,但对影响整个链表的操作需要加自旋锁。比如之前klist_iter_init_node()中对节点增加引用计数,就不需要加锁,因为只有已经拥有节点引用计数的线程才会特别地从那个节点开始。而之后klist_next()中则需要加锁,因为当前线程很可能没有引用计数,所以需要加锁,让情况固定下来。这既是保护链表,也是保护节点有效。符合kref引用计数的使用原则。2、要注意,虽然在节点切换的过程中是加锁的,但切换完访问当前节点时是解锁的,中间可能有节点被删除(这个通过spin_lock就可以搞定),也可能有节点被请求删除,这就需要注意。首先要忽略链表中已被请求删除的节点,然后在减少前一个节点引用计数时,可能就把前一个节点删除了。这里之所以不调用klist_put(),是因为本身已处于加锁状态,但仍要有它的实现。这里的实现和klist_put()中类似,代码不介意在加锁状态下唤醒另一个线程,但却不希望在加锁状态下调用put()函数,那可能会涉及释放另一个更大的结构。


  1. void klist_iter_exit(struct klist_iter *i)  
  2. {  
  3.     if (i->i_cur) {  
  4.         klist_put(i->i_cur, false);  
  5.         i->i_cur = NULL;  
  6.     }  
  7. }  

klist_iter_exit(),遍历结束函数。在遍历完成时调不调无所谓,但如果想中途结束,就一定要调用klist_iter_exit()。

klist主要用于设备驱动模型中,为了适应那些动态变化的设备和驱动,而专门设计的链表。klist并不通用,但它真的很新奇。 我看到它时,震惊于链表竟然可以专门异化成这种样子。如果你是松耦合的结构,如果你手下净是些桀骜不驯的家伙,那么不要只考虑kref,你可能还需要klist。

之前我们分析了引用计数kref,总结了sysfs提供的API,并翻译了介绍kobject原理及用法的文档。应该说准备工作做得足够多,kobject的实现怎么都可以看懂了,甚至只需要总结下API就行了。可我还是决定把kobject的实现代码从头分析一遍。一是因为kobject的代码很重要,会在设备驱动模型代码中无数次被用到,如果不熟悉的话可以说是举步维艰。二是为了熟悉linux的编码风格,为以后分析更大规模的代码奠定基础。

    kobject的头文件在include/linux/kobject.h,实现在lib/kobject.c。闲话少说,上代码。


  1. struct kobject {  

  2.     const char      *name;  

  3.     struct list_head    entry;  

  4.     struct kobject      *parent;  

  5.     struct kset     *kset;  

  6.     struct kobj_type    *ktype;  

  7.     struct sysfs_dirent *sd;  

  8.     struct kref     kref;  

  9.     unsigned int state_initialized:1;  

  10.     unsigned int state_in_sysfs:1;  

  11.     unsigned int state_add_uevent_sent:1;  

  12.     unsigned int state_remove_uevent_sent:1;  

  13.     unsigned int uevent_suppress:1;  

  14. };  

在struct kobject中,name是名字,entry是用于kobject所属kset下的子kobject链表,parent指向kobject的父节点,kset指向kobject所属的kset,ktype定义了kobject所属的类型,sd指向kobject对应的sysfs目录,kref记录kobject的引用计数,之后是一系列标志。


  1. struct kobj_type {  

  2.     void (*release)(struct kobject *kobj);  

  3.     struct sysfs_ops *sysfs_ops;  

  4.     struct attribute **default_attrs;  

  5. };  

struct kobj_type就是定义了kobject的公共类型,其中既有操作的函数,也有公共的属性。其中release()是在kobject释放时调用的,sysfs_ops中定义了读写属性文件时调用的函数。default_attrs中定义了这类kobject公共的属性。


  1. struct kset {  

  2.     struct list_head list;  

  3.     spinlock_t list_lock;  

  4.     struct kobject kobj;  

  5.     struct kset_uevent_ops *uevent_ops;  

  6. };  

struct kset可以看成在kobject上的扩展,它包含一个kobject的链表,可以方便地表示sysfs中目录与子目录的关系。其中,list是所属kobject的链表头,list_lock用于在访问链表时加锁,kobj是kset的内部kobject,要表现为sysfs中的目录就必须拥有kobject的功能,最后的kset_uevent_ops定义了对发往用户空间的uevent的处理。我对uevent不了解,会尽量忽略。


  1. struct kobj_attribute {  

  2.     struct attribute attr;  

  3.     ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,  

  4.             char *buf);  

  5.     ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,  

  6.              const char *buf, size_t count);  

  7. };  

struct kobj_attribute是kobject在attribute上做出的扩展,添加了两个专门读写kobject属性的函数。无论是kobject,还是kset(说到底是kset内部的kobject),都提供了使用kobj_attribute的快速创建方法。


结构差不多介绍完了,下面看看实现。我所知道的代码分析风格,喜欢自顶向下的方式,从一个函数开始,介绍出一个函数调用树。在代码量很大,涉及调用层次很深的时候,确实要采用这种打洞的方式来寻找突破口。但这种自顶向下的方式有两个问题:一是很容易迷失,二是代码分析的难度会逐渐增大而不是减小。在茫茫的代码中,你一头下去,周围都是你不认识的函数,一个函数里调用了三个陌生的函数,其中一个陌生的函数又调用了五个更陌生的函数…不久你就会产生很强的挫败感。这就像走在沙漠上,你不知道终点在哪,也许翻过一个沙丘就到了,也许还有无数个沙丘。而且在这种分析时,人是逐渐走向细节,容易被细节所困扰,忽略了整体的印象与代码的层次感。所以,我觉得在分析代码时,也可以采用自底向上的方式,从细小的、内部使用的函数,到比较宏观的、供外部调用的函数。而且按照这种顺序来看代码,基本就是文件从头读到尾的顺序,也比较符合写代码的流程。linux代码喜欢在文件开始处攒内部静态函数,攒到一定程度爆发,突然实现几个外部API,然后再攒,再实现。而且之前的内部静态函数会反复调用到。linux代码写得很有层次感,除了内外有别,还把意思相近的,或者功能刚好相反的,或者使用时顺序调用的函数放在一起,很便于阅读。闲话少说,等你看完kobject的实现自然就清楚了。


  1. static int populate_dir(struct kobject *kobj)  

  2. {  

  3.     struct kobj_type *t = get_ktype(kobj);  

  4.     struct attribute *attr;  

  5.     int error = 0;  

  6.     int i;  

  7.   

  8.     if (t && t->default_attrs) {  

  9.         for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {  

  10.             error = sysfs_create_file(kobj, attr);  

  11.             if (error)  

  12.                 break;  

  13.         }  

  14.     }  

  15.     return error;  

  16. }  

  17.   

  18. static int create_dir(struct kobject *kobj)  

  19. {  

  20.     int error = 0;  

  21.     if (kobject_name(kobj)) {  

  22.         error = sysfs_create_dir(kobj);  

  23.         if (!error) {  

  24.             error = populate_dir(kobj);  

  25.             if (error)  

  26.                 sysfs_remove_dir(kobj);  

  27.         }  

  28.     }  

  29.     return error;  

  30. }  

create_dir()在sysfs中创建kobj对应的目录,populate_dir()创建kobj中默认属性对应的文件。create_dir()正是调用populate_dir()实现的。


  1. static int get_kobj_path_length(struct kobject *kobj)  

  2. {  

  3.     int length = 1;  

  4.     struct kobject *parent = kobj;  

  5.   

  6.     /* walk up the ancestors until we hit the one pointing to the 

  7.      * root. 

  8.      * Add 1 to strlen for leading ‘/’ of each level. 

  9.      */  

  10.     do {  

  11.         if (kobject_name(parent) == NULL)  

  12.             return 0;  

  13.         length += strlen(kobject_name(parent)) + 1;  

  14.         parent = parent->parent;  

  15.     } while (parent);  

  16.     return length;  

  17. }  

  18.   

  19. static void fill_kobj_path(struct kobject *kobj, char *path, int length)  

  20. {  

  21.     struct kobject *parent;  

  22.   

  23.     –length;  

  24.     for (parent = kobj; parent; parent = parent->parent) {  

  25.         int cur = strlen(kobject_name(parent));  

  26.         /* back up enough to print this name with ‘/’ */  

  27.         length -= cur;  

  28.         strncpy(path + length, kobject_name(parent), cur);  

  29.         *(path + –length) = ‘/’;  

  30.     }  

  31.   

  32.     pr_debug(“kobject: ‘%s’ (%p): %s: path = ‘%s’\n”, kobject_name(kobj),  

  33.          kobj, __func__, path);  

  34. }  

  35.   

  36. /** 

  37.  * kobject_get_path – generate and return the path associated with a given kobj and kset pair. 

  38.  * 

  39.  * @kobj:   kobject in question, with which to build the path 

  40.  * @gfp_mask:   the allocation type used to allocate the path 

  41.  * 

  42.  * The result must be freed by the caller with kfree(). 

  43.  */  

  44. char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)  

  45. {  

  46.     char *path;  

  47.     int len;  

  48.   

  49.     len = get_kobj_path_length(kobj);  

  50.     if (len == 0)  

  51.         return NULL;  

  52.     path = kzalloc(len, gfp_mask);  

  53.     if (!path)  

  54.         return NULL;  

  55.     fill_kobj_path(kobj, path, len);  

  56.   

  57.     return path;  

  58. }  

前面两个是内部函数,get_kobj_path_length()获得kobj路径名的长度,fill_kobj_path()把kobj路径名填充到path缓冲区中。


kobject_get_path()靠两个函数获得kobj的路径名,从攒函数到爆发一气呵成。


  1. static void kobj_kset_join(struct kobject *kobj)  

  2. {  

  3.     if (!kobj->kset)  

  4.         return;  

  5.   

  6.     kset_get(kobj->kset);  

  7.     spin_lock(&kobj->kset->list_lock);  

  8.     list_add_tail(&kobj->entry, &kobj->kset->list);  

  9.     spin_unlock(&kobj->kset->list_lock);  

  10. }  

  11.   

  12. /* remove the kobject from its kset’s list */  

  13. static void kobj_kset_leave(struct kobject *kobj)  

  14. {  

  15.     if (!kobj->kset)  

  16.         return;  

  17.   

  18.     spin_lock(&kobj->kset->list_lock);  

  19.     list_del_init(&kobj->entry);  

  20.     spin_unlock(&kobj->kset->list_lock);  

  21.     kset_put(kobj->kset);  

  22. }  

kobj_kset_join()把kobj加入kobj->kset的链表中,kobj_kset_leave()把kobj从kobj->kset的链表中去除,两者功能相对。


  1. static void kobject_init_internal(struct kobject *kobj)  

  2. {  

  3.     if (!kobj)  

  4.         return;  

  5.     kref_init(&kobj->kref);  

  6.     INIT_LIST_HEAD(&kobj->entry);  

  7.     kobj->state_in_sysfs = 0;  

  8.     kobj->state_add_uevent_sent = 0;  

  9.     kobj->state_remove_uevent_sent = 0;  

  10.     kobj->state_initialized = 1;  

  11. }  

  12.   

  13.   

  14. static int kobject_add_internal(struct kobject *kobj)  

  15. {  

  16.     int error = 0;  

  17.     struct kobject *parent;  

  18.   

  19.     if (!kobj)  

  20.         return -ENOENT;  

  21.   

  22.     if (!kobj->name || !kobj->name[0]) {  

  23.         WARN(1, “kobject: (%p): attempted to be registered with empty “  

  24.              “name!\n”, kobj);  

  25.         return -EINVAL;  

  26.     }  

  27.   

  28.     parent = kobject_get(kobj->parent);  

  29.   

  30.     /* join kset if set, use it as parent if we do not already have one */  

  31.     if (kobj->kset) {  

  32.         if (!parent)  

  33.             parent = kobject_get(&kobj->kset->kobj);  

  34.         kobj_kset_join(kobj);  

  35.         kobj->parent = parent;  

  36.     }  

  37.   

  38.     pr_debug(“kobject: ‘%s’ (%p): %s: parent: ‘%s’, set: ‘%s’\n”,  

  39.          kobject_name(kobj), kobj, __func__,  

  40.          parent ? kobject_name(parent) : “<NULL>”,  

  41.          kobj->kset ? kobject_name(&kobj->kset->kobj) : “<NULL>”);  

  42.   

  43.     error = create_dir(kobj);  

  44.     if (error) {  

  45.         kobj_kset_leave(kobj);  

  46.         kobject_put(parent);  

  47.         kobj->parent = NULL;  

  48.   

  49.         /* be noisy on error issues */  

  50.         if (error == -EEXIST)  

  51.             printk(KERN_ERR “%s failed for %s with “  

  52.                    “-EEXIST, don’t try to register things with “  

  53.                    “the same name in the same directory.\n”,  

  54.                    __func__, kobject_name(kobj));  

  55.         else  

  56.             printk(KERN_ERR “%s failed for %s (%d)\n”,  

  57.                    __func__, kobject_name(kobj), error);  

  58.         dump_stack();  

  59.     } else  

  60.         kobj->state_in_sysfs = 1;  

  61.   

  62.     return error;  

  63. }  

kobject_init_internal()初始化kobj。


kobject_add_internal()把kobj加入已有的结构。


这两个函数看似无关,实际很有关系。在kobject中有好几个结构变量,但重要的只有两个,一个是kset,一个是parent。这两个都是表示当前kobject在整个体系中的位置,决不能自行决定,需要外部参与设置。那把kobject创建的过程分为init和add两个阶段也就很好理解了。kobject_init_internal()把一些能自动初始化的结构变量初始化掉,等外界设置了parent和kset,再调用kobject_add_internal()把kobject安在适当的位置,并创建相应的sysfs目录及文件。


  1. int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,  

  2.                   va_list vargs)  

  3. {  

  4.     const char *old_name = kobj->name;  

  5.     char *s;  

  6.   

  7.     if (kobj->name && !fmt)  

  8.         return 0;  

  9.   

  10.     kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);  

  11.     if (!kobj->name)  

  12.         return -ENOMEM;  

  13.   

  14.     /* ewww… some of these buggers have ‘/’ in the name … */  

  15.     while ((s = strchr(kobj->name, ‘/’)))  

  16.         s[0] = ‘!’;  

  17.   

  18.     kfree(old_name);  

  19.     return 0;  

  20. }  

  21.   

  22. /** 

  23.  * kobject_set_name – Set the name of a kobject 

  24.  * @kobj: struct kobject to set the name of 

  25.  * @fmt: format string used to build the name 

  26.  * 

  27.  * This sets the name of the kobject.  If you have already added the 

  28.  * kobject to the system, you must call kobject_rename() in order to 

  29.  * change the name of the kobject. 

  30.  */  

  31. int kobject_set_name(struct kobject *kobj, const char *fmt, …)  

  32. {  

  33.     va_list vargs;  

  34.     int retval;  

  35.   

  36.     va_start(vargs, fmt);  

  37.     retval = kobject_set_name_vargs(kobj, fmt, vargs);  

  38.     va_end(vargs);  

  39.   

  40.     return retval;  

  41. }  

kobject_set_name()是设置kobj名称的,它又调用kobject_set_name_vargs()实现。但要注意,这个kobject_set_name()仅限于kobject添加到体系之前,因为它只是修改了名字,并未通知用户空间。


  1. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)  

  2. {  

  3.     char *err_str;  

  4.   

  5.     if (!kobj) {  

  6.         err_str = “invalid kobject pointer!”;  

  7.         goto error;  

  8.     }  

  9.     if (!ktype) {  

  10.         err_str = “must have a ktype to be initialized properly!\n”;  

  11.         goto error;  

  12.     }  

  13.     if (kobj->state_initialized) {  

  14.         /* do not error out as sometimes we can recover */  

  15.         printk(KERN_ERR “kobject (%p): tried to init an initialized “  

  16.                “object, something is seriously wrong.\n”, kobj);  

  17.         dump_stack();  

  18.     }  

  19.   

  20.     kobject_init_internal(kobj);  

  21.     kobj->ktype = ktype;  

  22.     return;  

  23.   

  24. error:  

  25.     printk(KERN_ERR “kobject (%p): %s\n”, kobj, err_str);  

  26.     dump_stack();  

  27. }  

kobject_init()就是调用kobject_init_internal()自动初始化了一些结构变量,然后又设置了ktype。其实这个ktype主要是管理一些默认属性什么的,只要在kobject_add_internal()调用create_dir()之前设置就行,之所以会出现在kobject_init()中,完全是为了与后面的kobject_create()相对比。


  1. static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,  

  2.                 const char *fmt, va_list vargs)  

  3. {  

  4.     int retval;  

  5.   

  6.     retval = kobject_set_name_vargs(kobj, fmt, vargs);  

  7.     if (retval) {  

  8.         printk(KERN_ERR “kobject: can not set name properly!\n”);  

  9.         return retval;  

  10.     }  

  11.     kobj->parent = parent;  

  12.     return kobject_add_internal(kobj);  

  13. }  

  14.   

  15. /** 

  16.  * kobject_add – the main kobject add function 

  17.  * @kobj: the kobject to add 

  18.  * @parent: pointer to the parent of the kobject. 

  19.  * @fmt: format to name the kobject with. 

  20.  * 

  21.  * The kobject name is set and added to the kobject hierarchy in this 

  22.  * function. 

  23.  * 

  24.  * If @parent is set, then the parent of the @kobj will be set to it. 

  25.  * If @parent is NULL, then the parent of the @kobj will be set to the 

  26.  * kobject associted with the kset assigned to this kobject.  If no kset 

  27.  * is assigned to the kobject, then the kobject will be located in the 

  28.  * root of the sysfs tree. 

  29.  * 

  30.  * If this function returns an error, kobject_put() must be called to 

  31.  * properly clean up the memory associated with the object. 

  32.  * Under no instance should the kobject that is passed to this function 

  33.  * be directly freed with a call to kfree(), that can leak memory. 

  34.  * 

  35.  * Note, no “add” uevent will be created with this call, the caller should set 

  36.  * up all of the necessary sysfs files for the object and then call 

  37.  * kobject_uevent() with the UEVENT_ADD parameter to ensure that 

  38.  * userspace is properly notified of this kobject’s creation. 

  39.  */  

  40. int kobject_add(struct kobject *kobj, struct kobject *parent,  

  41.         const char *fmt, …)  

  42. {  

  43.     va_list args;  

  44.     int retval;  

  45.   

  46.     if (!kobj)  

  47.         return -EINVAL;  

  48.   

  49.     if (!kobj->state_initialized) {  

  50.         printk(KERN_ERR “kobject ‘%s’ (%p): tried to add an “  

  51.                “uninitialized object, something is seriously wrong.\n”,  

  52.                kobject_name(kobj), kobj);  

  53.         dump_stack();  

  54.         return -EINVAL;  

  55.     }  

  56.     va_start(args, fmt);  

  57.     retval = kobject_add_varg(kobj, parent, fmt, args);  

  58.     va_end(args);  

  59.   

  60.     return retval;  

  61. }  

kobject_add()把kobj添加到体系中。但它还有一个附加功能,设置kobj的名字。parent也是作为参数传进来的,至于为什么kset没有同样传进来,或许是历史遗留原因吧。


  1. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,  

  2.              struct kobject *parent, const char *fmt, …)  

  3. {  

  4.     va_list args;  

  5.     int retval;  

  6.   

  7.     kobject_init(kobj, ktype);  

  8.   

  9.     va_start(args, fmt);  

  10.     retval = kobject_add_varg(kobj, parent, fmt, args);  

  11.     va_end(args);  

  12.   

  13.     return retval;  

  14. }  

kobject_init_and_add()虽然是kobject_init()和kobject_add()的合并,但并不常用,因为其中根本没留下设置kset的空挡,这无疑不太合适。


  1. int kobject_rename(struct kobject *kobj, const char *new_name)  

  2. {  

  3.     int error = 0;  

  4.     const char *devpath = NULL;  

  5.     const char *dup_name = NULL, *name;  

  6.     char *devpath_string = NULL;  

  7.     char *envp[2];  

  8.   

  9.     kobj = kobject_get(kobj);  

  10.     if (!kobj)  

  11.         return -EINVAL;  

  12.     if (!kobj->parent)  

  13.         return -EINVAL;  

  14.   

  15.     devpath = kobject_get_path(kobj, GFP_KERNEL);  

  16.     if (!devpath) {  

  17.         error = -ENOMEM;  

  18.         goto out;  

  19.     }  

  20.     devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);  

  21.     if (!devpath_string) {  

  22.         error = -ENOMEM;  

  23.         goto out;  

  24.     }  

  25.     sprintf(devpath_string, “DEVPATH_OLD=%s”, devpath);  

  26.     envp[0] = devpath_string;  

  27.     envp[1] = NULL;  

  28.   

  29.     name = dup_name = kstrdup(new_name, GFP_KERNEL);  

  30.     if (!name) {  

  31.         error = -ENOMEM;  

  32.         goto out;  

  33.     }  

  34.   

  35.     error = sysfs_rename_dir(kobj, new_name);  

  36.     if (error)  

  37.         goto out;  

  38.   

  39.     /* Install the new kobject name */  

  40.     dup_name = kobj->name;  

  41.     kobj->name = name;  

  42.   

  43.     /* This function is mostly/only used for network interface. 

  44.      * Some hotplug package track interfaces by their name and 

  45.      * therefore want to know when the name is changed by the user. */  

  46.     kobject_uevent_env(kobj, KOBJ_MOVE, envp);  

  47.   

  48. out:  

  49.     kfree(dup_name);  

  50.     kfree(devpath_string);  

  51.     kfree(devpath);  

  52.     kobject_put(kobj);  

  53.   

  54.     return error;  

  55. }  

kobject_rename()就是在kobj已经添加到系统之后,要改名字时调用的函数。它除了完成kobject_set_name()的功能,还向用户空间通知这一消息。


  1. int kobject_move(struct kobject *kobj, struct kobject *new_parent)  

  2. {  

  3.     int error;  

  4.     struct kobject *old_parent;  

  5.     const char *devpath = NULL;  

  6.     char *devpath_string = NULL;  

  7.     char *envp[2];  

  8.   

  9.     kobj = kobject_get(kobj);  

  10.     if (!kobj)  

  11.         return -EINVAL;  

  12.     new_parent = kobject_get(new_parent);  

  13.     if (!new_parent) {  

  14.         if (kobj->kset)  

  15.             new_parent = kobject_get(&kobj->kset->kobj);  

  16.     }  

  17.     /* old object path */  

  18.     devpath = kobject_get_path(kobj, GFP_KERNEL);  

  19.     if (!devpath) {  

  20.         error = -ENOMEM;  

  21.         goto out;  

  22.     }  

  23.     devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL);  

  24.     if (!devpath_string) {  

  25.         error = -ENOMEM;  

  26.         goto out;  

  27.     }  

  28.     sprintf(devpath_string, “DEVPATH_OLD=%s”, devpath);  

  29.     envp[0] = devpath_string;  

  30.     envp[1] = NULL;  

  31.     error = sysfs_move_dir(kobj, new_parent);  

  32.     if (error)  

  33.         goto out;  

  34.     old_parent = kobj->parent;  

  35.     kobj->parent = new_parent;  

  36.     new_parent = NULL;  

  37.     kobject_put(old_parent);  

  38.     kobject_uevent_env(kobj, KOBJ_MOVE, envp);  

  39. out:  

  40.     kobject_put(new_parent);  

  41.     kobject_put(kobj);  

  42.     kfree(devpath_string);  

  43.     kfree(devpath);  

  44.     return error;  

  45. }  

kobject_move()则是在kobj添加到系统后,想移动到新的parent kobject下所调用的函数。在通知用户空间上,与kobject_rename()调用的是同一操作。


  1. void kobject_del(struct kobject *kobj)  

  2. {  

  3.     if (!kobj)  

  4.         return;  

  5.   

  6.     sysfs_remove_dir(kobj);  

  7.     kobj->state_in_sysfs = 0;  

  8.     kobj_kset_leave(kobj);  

  9.     kobject_put(kobj->parent);  

  10.     kobj->parent = NULL;  

  11. }  

kobject_del()仅仅是把kobj从系统中退出,相对于kobject_add()操作。


  1. /** 

  2.  * kobject_get – increment refcount for object. 

  3.  * @kobj: object. 

  4.  */  

  5. struct kobject *kobject_get(struct kobject *kobj)  

  6. {  

  7.     if (kobj)  

  8.         kref_get(&kobj->kref);  

  9.     return kobj;  

  10. }  

  11.   

  12. /* 

  13.  * kobject_cleanup – free kobject resources. 

  14.  * @kobj: object to cleanup 

  15.  */  

  16. static void kobject_cleanup(struct kobject *kobj)  

  17. {  

  18.     struct kobj_type *t = get_ktype(kobj);  

  19.     const char *name = kobj->name;  

  20.   

  21.     pr_debug(“kobject: ‘%s’ (%p): %s\n”,  

  22.          kobject_name(kobj), kobj, __func__);  

  23.   

  24.     if (t && !t->release)  

  25.         pr_debug(“kobject: ‘%s’ (%p): does not have a release() “  

  26.              “function, it is broken and must be fixed.\n”,  

  27.              kobject_name(kobj), kobj);  

  28.   

  29.     /* send “remove” if the caller did not do it but sent “add” */  

  30.     if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {  

  31.         pr_debug(“kobject: ‘%s’ (%p): auto cleanup ‘remove’ event\n”,  

  32.              kobject_name(kobj), kobj);  

  33.         kobject_uevent(kobj, KOBJ_REMOVE);  

  34.     }  

  35.   

  36.     /* remove from sysfs if the caller did not do it */  

  37.     if (kobj->state_in_sysfs) {  

  38.         pr_debug(“kobject: ‘%s’ (%p): auto cleanup kobject_del\n”,  

  39.              kobject_name(kobj), kobj);  

  40.         kobject_del(kobj);  

  41.     }  

  42.   

  43.     if (t && t->release) {  

  44.         pr_debug(“kobject: ‘%s’ (%p): calling ktype release\n”,  

  45.              kobject_name(kobj), kobj);  

  46.         t->release(kobj);  

  47.     }  

  48.   

  49.     /* free name if we allocated it */  

  50.     if (name) {  

  51.         pr_debug(“kobject: ‘%s’: free name\n”, name);  

  52.         kfree(name);  

  53.     }  

  54. }  

  55.   

  56. static void kobject_release(struct kref *kref)  

  57. {  

  58.     kobject_cleanup(container_of(kref, struct kobject, kref));  

  59. }  

  60.   

  61. /** 

  62.  * kobject_put – decrement refcount for object. 

  63.  * @kobj: object. 

  64.  * 

  65.  * Decrement the refcount, and if 0, call kobject_cleanup(). 

  66.  */  

  67. void kobject_put(struct kobject *kobj)  

  68. {  

  69.     if (kobj) {  

  70.         if (!kobj->state_initialized)  

  71.             WARN(1, KERN_WARNING “kobject: ‘%s’ (%p): is not “  

  72.                    “initialized, yet kobject_put() is being “  

  73.                    “called.\n”, kobject_name(kobj), kobj);  

  74.         kref_put(&kobj->kref, kobject_release);  

  75.     }  

  76. }  

kobject_get()和kobject_put()走的完全是引用计数的路线。kobject_put()会在引用计数降为零时撤销整个kobject的存在:向用户空间发生REMOVE消息,从sysfs中删除相应目录,调用kobj_type中定义的release函数,释放name所占的空间。


看看前面介绍的API。


  1. int kobject_set_name(struct kobject *kobj, const char *name, …)  

  2.                 __attribute__((format(printf, 2, 3)));  

  3. int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,  

  4.                   va_list vargs);  

  5. void kobject_init(struct kobject *kobj, struct kobj_type *ktype);  

  6. int __must_check kobject_add(struct kobject *kobj,  

  7.                     struct kobject *parent,  

  8.                     const char *fmt, …);  

  9. int __must_check kobject_init_and_add(struct kobject *kobj,  

  10.                          struct kobj_type *ktype,  

  11.                          struct kobject *parent,  

  12.                          const char *fmt, …);  

  13. void kobject_del(struct kobject *kobj);  

  14.   

  15. int __must_check kobject_rename(struct kobject *, const char *new_name);  

  16. int __must_check kobject_move(struct kobject *, struct kobject *);  

  17.   

  18. struct kobject *kobject_get(struct kobject *kobj);  

  19. void kobject_put(struct kobject *kobj);  

  20.   

  21. char *kobject_get_path(struct kobject *kobj, gfp_t flag);  

基本上概扩了kobject从创建到删除,包括中间改名字,改位置,以及引用计数的变动。


当然,kobject创建仍比较麻烦,因为ktype需要自己写。下面就是kobject提供的一种快速创建方法。


  1. static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,  

  2.                   char *buf)  

  3. {  

  4.     struct kobj_attribute *kattr;  

  5.     ssize_t ret = -EIO;  

  6.   

  7.     kattr = container_of(attr, struct kobj_attribute, attr);  

  8.     if (kattr->show)  

  9.         ret = kattr->show(kobj, kattr, buf);  

  10.     return ret;  

  11. }  

  12.   

  13. static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,  

  14.                    const char *buf, size_t count)  

  15. {  

  16.     struct kobj_attribute *kattr;  

  17.     ssize_t ret = -EIO;  

  18.   

  19.     kattr = container_of(attr, struct kobj_attribute, attr);  

  20.     if (kattr->store)  

  21.         ret = kattr->store(kobj, kattr, buf, count);  

  22.     return ret;  

  23. }  

  24.   

  25. struct sysfs_ops kobj_sysfs_ops = {  

  26.     .show   = kobj_attr_show,  

  27.     .store  = kobj_attr_store,  

  28. };  

  29.   

  30. static void dynamic_kobj_release(struct kobject *kobj)  

  31. {  

  32.     pr_debug(“kobject: (%p): %s\n”, kobj, __func__);  

  33.     kfree(kobj);  

  34. }  

  35.   

  36. static struct kobj_type dynamic_kobj_ktype = {  

  37.     .release    = dynamic_kobj_release,  

  38.     .sysfs_ops  = &kobj_sysfs_ops,  

  39. };  

这个就是kobject自身提供的一种kobj_type,叫做dynamic_kobj_ktype。它没有提供默认的属性,但提供了release函数及访问属性的方法。


  1. struct kobject *kobject_create(void)  

  2. {  

  3.     struct kobject *kobj;  

  4.   

  5.     kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);  

  6.     if (!kobj)  

  7.         return NULL;  

  8.   

  9.     kobject_init(kobj, &dynamic_kobj_ktype);  

  10.     return kobj;  

  11. }  

  12.   

  13. struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)  

  14. {  

  15.     struct kobject *kobj;  

  16.     int retval;  

  17.   

  18.     kobj = kobject_create();  

  19.     if (!kobj)  

  20.         return NULL;  

  21.   

  22.     retval = kobject_add(kobj, parent, “%s”, name);  

  23.     if (retval) {  

  24.         printk(KERN_WARNING “%s: kobject_add error: %d\n”,  

  25.                __func__, retval);  

  26.         kobject_put(kobj);  

  27.         kobj = NULL;  

  28.     }  

  29.     return kobj;  

  30. }  

在kobject_create()及kobject_create_add()中,使用了这种dynamic_kobj_ktype。这是一种很好的偷懒方法。因为release()函数会释放kobj,所以这里的kobj必须是kobject_create()动态创建的。这里的kobject_create()和kobject_init()相对,kobject_create_and_add()和kobject_init_and_add()相对。值得一提的是,这里用kobject_create()和kobject_create_and_add()创建的kobject无法嵌入其它结构,是独立的存在,所以用到的地方很少。


  1. void kset_init(struct kset *k)  

  2. {  

  3.     kobject_init_internal(&k->kobj);  

  4.     INIT_LIST_HEAD(&k->list);  

  5.     spin_lock_init(&k->list_lock);  

  6. }  

kset_init()对kset进行初始化。不过它的界限同kobject差不多。


  1. int kset_register(struct kset *k)  

  2. {  

  3.     int err;  

  4.   

  5.     if (!k)  

  6.         return -EINVAL;  

  7.   

  8.     kset_init(k);  

  9.     err = kobject_add_internal(&k->kobj);  

  10.     if (err)  

  11.         return err;  

  12.     kobject_uevent(&k->kobj, KOBJ_ADD);  

  13.     return 0;  

  14. }  

kset_register()最大的特点是简单,它只负责把kset中的kobject连入系统,并发布KOBJ_ADD消息。所以在调用它之前,你要先设置好k->kobj.name、k->kobj.parent、k->kobj.kset。


  1. void kset_unregister(struct kset *k)  

  2. {  

  3.     if (!k)  

  4.         return;  

  5.     kobject_put(&k->kobj);  

  6. }  

kset_unregister()只是简单地释放创建时获得的引用计数。使用引用计数就是这么简单。


  1. struct kobject *kset_find_obj(struct kset *kset, const char *name)  

  2. {  

  3.     struct kobject *k;  

  4.     struct kobject *ret = NULL;  

  5.   

  6.     spin_lock(&kset->list_lock);  

  7.     list_for_each_entry(k, &kset->list, entry) {  

  8.         if (kobject_name(k) && !strcmp(kobject_name(k), name)) {  

  9.             ret = kobject_get(k);  

  10.             break;  

  11.         }  

  12.     }  

  13.     spin_unlock(&kset->list_lock);  

  14.     return ret;  

  15. }  

kset_find_obj()从kset的链表中找到名为name的kobject。这纯粹是一个对外的API。


  1. static void kset_release(struct kobject *kobj)  

  2. {  

  3.     struct kset *kset = container_of(kobj, struct kset, kobj);  

  4.     pr_debug(“kobject: ‘%s’ (%p): %s\n”,  

  5.          kobject_name(kobj), kobj, __func__);  

  6.     kfree(kset);  

  7. }  

  8.   

  9. static struct kobj_type kset_ktype = {  

  10.     .sysfs_ops  = &kobj_sysfs_ops,  

  11.     .release = kset_release,  

  12. };  

与kobject相对的,kset也提供了一种kobj_type,叫做kset_ktype。


  1. static struct kset *kset_create(const char *name,  

  2.                 struct kset_uevent_ops *uevent_ops,  

  3.                 struct kobject *parent_kobj)  

  4. {  

  5.     struct kset *kset;  

  6.     int retval;  

  7.   

  8.     kset = kzalloc(sizeof(*kset), GFP_KERNEL);  

  9.     if (!kset)  

  10.         return NULL;  

  11.     retval = kobject_set_name(&kset->kobj, name);  

  12.     if (retval) {  

  13.         kfree(kset);  

  14.         return NULL;  

  15.     }  

  16.     kset->uevent_ops = uevent_ops;  

  17.     kset->kobj.parent = parent_kobj;  

  18.   

  19.     /* 

  20.      * The kobject of this kset will have a type of kset_ktype and belong to 

  21.      * no kset itself.  That way we can properly free it when it is 

  22.      * finished being used. 

  23.      */  

  24.     kset->kobj.ktype = &kset_ktype;  

  25.     kset->kobj.kset = NULL;  

  26.   

  27.     return kset;  

  28. }  

  29.   

  30. /** 

  31.  * kset_create_and_add – create a struct kset dynamically and add it to sysfs 

  32.  * 

  33.  * @name: the name for the kset 

  34.  * @uevent_ops: a struct kset_uevent_ops for the kset 

  35.  * @parent_kobj: the parent kobject of this kset, if any. 

  36.  * 

  37.  * This function creates a kset structure dynamically and registers it 

  38.  * with sysfs.  When you are finished with this structure, call 

  39.  * kset_unregister() and the structure will be dynamically freed when it 

  40.  * is no longer being used. 

  41.  * 

  42.  * If the kset was not able to be created, NULL will be returned. 

  43.  */  

  44. struct kset *kset_create_and_add(const char *name,  

  45.                  struct kset_uevent_ops *uevent_ops,  

  46.                  struct kobject *parent_kobj)  

  47. {  

  48.     struct kset *kset;  

  49.     int error;  

  50.   

  51.     kset = kset_create(name, uevent_ops, parent_kobj);  

  52.     if (!kset)  

  53.         return NULL;  

  54.     error = kset_register(kset);  

  55.     if (error) {  

  56.         kfree(kset);  

  57.         return NULL;  

  58.     }  

  59.     return kset;  

  60. }  

kset_create()和kset_create_and_add()就是使用kset_type的快速创建函数。


说实话,使用kobject_create_and_add()的比较少见,但使用 kset_create_and_add()的情形还是见过一些的。比如sysfs中那些顶层的目录,就是单纯的目录,不需要嵌入什么很复杂的结构,用简单的kset_create_and_add()创建就好了。


  1. static inline const char *kobject_name(const struct kobject *kobj)  

  2. {  

  3.     return kobj->name;  

  4. }  

  5.   

  6. static inline struct kset *to_kset(struct kobject *kobj)  

  7. {  

  8.     return kobj ? container_of(kobj, struct kset, kobj) : NULL;  

  9. }  

  10.   

  11. static inline struct kset *kset_get(struct kset *k)  

  12. {  

  13.     return k ? to_kset(kobject_get(&k->kobj)) : NULL;  

  14. }  

  15.   

  16. static inline void kset_put(struct kset *k)  

  17. {  

  18.     kobject_put(&k->kobj);  

  19. }  

  20.   

  21. static inline struct kobj_type *get_ktype(struct kobject *kobj)  

  22. {  

  23.     return kobj->ktype;  

  24. }  

这些是在kobject.h中的内联函数。这里内联函数更多的意思是方便,易于屏蔽内部实现。


以上就是kobject共800余行的代码实现,当然我们忽略了uevent的那部分。


事实证明,自底向上或者顺序的代码分析方法,还是很适合千行左右的代码分析。而且这样分析很全面,容易我们洞察整个模块的意图,从而在理解代码时从较高的抽象角度去看。

linux的设备驱动模型,是建立在sysfs和kobject之上的,由总线、设备、驱动、类所组成的关系结构。从本节开始,我们将对linux这一设备驱动模型进行深入分析。

     头文件是include/linux/device.h,实现在drivers/base目录中。本节要分析的,是其中的设备,主要在core.c中。


  1. struct device {  

  2.     struct device       *parent;  

  3.   

  4.     struct device_private   *p;  

  5.   

  6.     struct kobject kobj;  

  7.     const char      *init_name; /* initial name of the device */  

  8.     struct device_type  *type;  

  9.   

  10.     struct semaphore    sem;    /* semaphore to synchronize calls to 

  11.                      * its driver. 

  12.                      */  

  13.   

  14.     struct bus_type *bus;       /* type of bus device is on */  

  15.     struct device_driver *driver;   /* which driver has allocated this 

  16.                        device */  

  17.     void        *platform_data; /* Platform specific data, device 

  18.                        core doesn’t touch it */  

  19.     struct dev_pm_info  power;  

  20.   

  21. #ifdef CONFIG_NUMA   

  22.     int     numa_node;  /* NUMA node this device is close to */  

  23. #endif   

  24.     u64     *dma_mask;  /* dma mask (if dma’able device) */  

  25.     u64     coherent_dma_mask;/* Like dma_mask, but for 

  26.                          alloc_coherent mappings as 

  27.                          not all hardware supports 

  28.                          64 bit addresses for consistent 

  29.                          allocations such descriptors. */  

  30.   

  31.     struct device_dma_parameters *dma_parms;  

  32.   

  33.     struct list_head    dma_pools;  /* dma pools (if dma’ble) */  

  34.   

  35.     struct dma_coherent_mem *dma_mem; /* internal for coherent mem 

  36.                          override */  

  37.     /* arch specific additions */  

  38.     struct dev_archdata archdata;  

  39.   

  40.     dev_t           devt;   /* dev_t, creates the sysfs “dev” */  

  41.   

  42.     spinlock_t      devres_lock;  

  43.     struct list_head    devres_head;  

  44.   

  45.     struct klist_node   knode_class;  

  46.     struct class        *class;  

  47.     const struct attribute_group **groups;  /* optional groups */  

  48.   

  49.     void    (*release)(struct device *dev);  

  50. };  

先来分析下struct device的结构变量。首先是指向父节点的指针parent,kobj是内嵌在device中的kobject,用于把它联系到sysfs中。bus是对设备所在总线的指针,driver是对设备所用驱动的指针。还有DMA需要的数据,表示设备号的devt,表示设备资源的devres_head和保护它的devres_lock。指向类的指针class,knode_class是被连入class链表时所用的klist节点。group是设备的属性集合。release应该是设备释放时调用的函数。


  1. struct device_private {  

  2.     struct klist klist_children;  

  3.     struct klist_node knode_parent;  

  4.     struct klist_node knode_driver;  

  5.     struct klist_node knode_bus;  

  6.     void *driver_data;  

  7.     struct device *device;  

  8. };  

  9. #define to_device_private_parent(obj)   \   

  10.     container_of(obj, struct device_private, knode_parent)  

  11. #define to_device_private_driver(obj)   \   

  12.     container_of(obj, struct device_private, knode_driver)  

  13. #define to_device_private_bus(obj)  \   

  14.     container_of(obj, struct device_private, knode_bus)  

struct device中有一部分不愿意让外界看到,所以做出struct device_private结构,包括了设备驱动模型内部的链接。klist_children是子设备的链表,knode_parent是连入父设备的klist_children时所用的节点,knode_driver是连入驱动的设备链表所用的节点,knode_bus是连入总线的设备链表时所用的节点。driver_data用于在设备结构中存放相关的驱动信息,也许是驱动专门为设备建立的结构实例。device则是指向struct device_private所属的device。


下面还有一些宏,to_device_private_parent()是从父设备的klist_children上节点,获得相应的device_private。to_device_private_driver()是从驱动的设备链表上节点,获得对应的device_private。to_device_private_bus()是从总线的设备链表上节点,获得对应的device_private。


或许会奇怪,为什么knode_class没有被移入struct device_private,或许有外部模块需要用到它。


  1. /* 

  2.  * The type of device, “struct device” is embedded in. A class 

  3.  * or bus can contain devices of different types 

  4.  * like “partitions” and “disks”, “mouse” and “event”. 

  5.  * This identifies the device type and carries type-specific 

  6.  * information, equivalent to the kobj_type of a kobject. 

  7.  * If “name” is specified, the uevent will contain it in 

  8.  * the DEVTYPE variable. 

  9.  */  

  10. struct device_type {  

  11.     const char *name;  

  12.     const struct attribute_group **groups;  

  13.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  

  14.     char *(*devnode)(struct device *dev, mode_t *mode);  

  15.     void (*release)(struct device *dev);  

  16.   

  17.     const struct dev_pm_ops *pm;  

  18. };  

device竟然有device_type,类似于与kobject相对的kobj_type,之后我们再看它怎么用。


  1. /* interface for exporting device attributes */  

  2. struct device_attribute {  

  3.     struct attribute    attr;  

  4.     ssize_t (*show)(struct device *dev, struct device_attribute *attr,  

  5.             char *buf);  

  6.     ssize_t (*store)(struct device *dev, struct device_attribute *attr,  

  7.              const char *buf, size_t count);  

  8. };  

  9.   

  10. #define DEVICE_ATTR(_name, _mode, _show, _store) \   

  11. struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)  

这个device_attribute显然就是device对struct attribute的封装,新加的show()、store()函数都是以与设备相关的结构调用的。


至于device中其它的archdata、dma、devres,都是作为设备特有的,我们现在主要关心设备驱动模型的建立,这些会尽量忽略。 


下面就来看看device的实现,这主要在core.c中。


  1. int __init devices_init(void)  

  2. {  

  3.     devices_kset = kset_create_and_add(“devices”, &device_uevent_ops, NULL);  

  4.     if (!devices_kset)  

  5.         return -ENOMEM;  

  6.     dev_kobj = kobject_create_and_add(“dev”, NULL);  

  7.     if (!dev_kobj)  

  8.         goto dev_kobj_err;  

  9.     sysfs_dev_block_kobj = kobject_create_and_add(“block”, dev_kobj);  

  10.     if (!sysfs_dev_block_kobj)  

  11.         goto block_kobj_err;  

  12.     sysfs_dev_char_kobj = kobject_create_and_add(“char”, dev_kobj);  

  13.     if (!sysfs_dev_char_kobj)  

  14.         goto char_kobj_err;  

  15.   

  16.     return 0;  

  17.   

  18.  char_kobj_err:  

  19.     kobject_put(sysfs_dev_block_kobj);  

  20.  block_kobj_err:  

  21.     kobject_put(dev_kobj);  

  22.  dev_kobj_err:  

  23.     kset_unregister(devices_kset);  

  24.     return -ENOMEM;  

  25. }  

这是在设备驱动模型初始化时调用的device部分初始的函数devices_init()。它干的事情我们都很熟悉,就是建立sysfs中的devices目录,和dev目录。还在dev目录下又建立了block和char两个子目录。因为dev目录只打算存放辅助的设备号,所以没必要使用kset。


  1. static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,  

  2.                  char *buf)  

  3. {  

  4.     struct device_attribute *dev_attr = to_dev_attr(attr);  

  5.     struct device *dev = to_dev(kobj);  

  6.     ssize_t ret = -EIO;  

  7.   

  8.     if (dev_attr->show)  

  9.         ret = dev_attr->show(dev, dev_attr, buf);  

  10.     if (ret >= (ssize_t)PAGE_SIZE) {  

  11.         print_symbol(“dev_attr_show: %s returned bad count\n”,  

  12.                 (unsigned long)dev_attr->show);  

  13.     }  

  14.     return ret;  

  15. }  

  16.   

  17. static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,  

  18.                   const char *buf, size_t count)  

  19. {  

  20.     struct device_attribute *dev_attr = to_dev_attr(attr);  

  21.     struct device *dev = to_dev(kobj);  

  22.     ssize_t ret = -EIO;  

  23.   

  24.     if (dev_attr->store)  

  25.         ret = dev_attr->store(dev, dev_attr, buf, count);  

  26.     return ret;  

  27. }  

  28.   

  29. static struct sysfs_ops dev_sysfs_ops = {  

  30.     .show   = dev_attr_show,  

  31.     .store  = dev_attr_store,  

  32. };  

看到这里是不是很熟悉,dev_sysfs_ops就是device准备注册到sysfs中的操作函数。dev_attr_show()和dev_attr_store()都会再调用与属性相关的函数。


  1. static void device_release(struct kobject *kobj)  

  2. {  

  3.     struct device *dev = to_dev(kobj);  

  4.     struct device_private *p = dev->p;  

  5.   

  6.     if (dev->release)  

  7.         dev->release(dev);  

  8.     else if (dev->type && dev->type->release)  

  9.         dev->type->release(dev);  

  10.     else if (dev->class && dev->class->dev_release)  

  11.         dev->class->dev_release(dev);  

  12.     else  

  13.         WARN(1, KERN_ERR “Device ‘%s’ does not have a release() “  

  14.             “function, it is broken and must be fixed.\n”,  

  15.             dev_name(dev));  

  16.     kfree(p);  

  17. }  

  18.   

  19. static struct kobj_type device_ktype = {  

  20.     .release    = device_release,  

  21.     .sysfs_ops  = &dev_sysfs_ops,  

  22. };  

使用的release函数是device_release。在释放device时,会依次调用device结构中定义的release函数,device_type中定义的release函数,device所属的class中所定义的release函数,最后会吧device_private结构释放掉。


  1. static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)  

  2. {  

  3.     struct kobj_type *ktype = get_ktype(kobj);  

  4.   

  5.     if (ktype == &device_ktype) {  

  6.         struct device *dev = to_dev(kobj);  

  7.         if (dev->bus)  

  8.             return 1;  

  9.         if (dev->class)  

  10.             return 1;  

  11.     }  

  12.     return 0;  

  13. }  

  14.   

  15. static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)  

  16. {  

  17.     struct device *dev = to_dev(kobj);  

  18.   

  19.     if (dev->bus)  

  20.         return dev->bus->name;  

  21.     if (dev->class)  

  22.         return dev->class->name;  

  23.     return NULL;  

  24. }  

  25.   

  26. static int dev_uevent(struct kset *kset, struct kobject *kobj,  

  27.               struct kobj_uevent_env *env)  

  28. {  

  29.     struct device *dev = to_dev(kobj);  

  30.     int retval = 0;  

  31.   

  32.     /* add device node properties if present */  

  33.     if (MAJOR(dev->devt)) {  

  34.         const char *tmp;  

  35.         const char *name;  

  36.         mode_t mode = 0;  

  37.   

  38.         add_uevent_var(env, “MAJOR=%u”, MAJOR(dev->devt));  

  39.         add_uevent_var(env, “MINOR=%u”, MINOR(dev->devt));  

  40.         name = device_get_devnode(dev, &mode, &tmp);  

  41.         if (name) {  

  42.             add_uevent_var(env, “DEVNAME=%s”, name);  

  43.             kfree(tmp);  

  44.             if (mode)  

  45.                 add_uevent_var(env, “DEVMODE=%#o”, mode & 0777);  

  46.         }  

  47.     }  

  48.   

  49.     if (dev->type && dev->type->name)  

  50.         add_uevent_var(env, “DEVTYPE=%s”, dev->type->name);  

  51.   

  52.     if (dev->driver)  

  53.         add_uevent_var(env, “DRIVER=%s”, dev->driver->name);  

  54.   

  55. #ifdef CONFIG_SYSFS_DEPRECATED   

  56.     if (dev->class) {  

  57.         struct device *parent = dev->parent;  

  58.   

  59.         /* find first bus device in parent chain */  

  60.         while (parent && !parent->bus)  

  61.             parent = parent->parent;  

  62.         if (parent && parent->bus) {  

  63.             const char *path;  

  64.   

  65.             path = kobject_get_path(&parent->kobj, GFP_KERNEL);  

  66.             if (path) {  

  67.                 add_uevent_var(env, “PHYSDEVPATH=%s”, path);  

  68.                 kfree(path);  

  69.             }  

  70.   

  71.             add_uevent_var(env, “PHYSDEVBUS=%s”, parent->bus->name);  

  72.   

  73.             if (parent->driver)  

  74.                 add_uevent_var(env, “PHYSDEVDRIVER=%s”,  

  75.                            parent->driver->name);  

  76.         }  

  77.     } else if (dev->bus) {  

  78.         add_uevent_var(env, “PHYSDEVBUS=%s”, dev->bus->name);  

  79.   

  80.         if (dev->driver)  

  81.             add_uevent_var(env, “PHYSDEVDRIVER=%s”,  

  82.                        dev->driver->name);  

  83.     }  

  84. #endif   

  85.   

  86.     /* have the bus specific function add its stuff */  

  87.     if (dev->bus && dev->bus->uevent) {  

  88.         retval = dev->bus->uevent(dev, env);  

  89.         if (retval)  

  90.             pr_debug(“device: ‘%s’: %s: bus uevent() returned %d\n”,  

  91.                  dev_name(dev), __func__, retval);  

  92.     }  

  93.   

  94.     /* have the class specific function add its stuff */  

  95.     if (dev->class && dev->class->dev_uevent) {  

  96.         retval = dev->class->dev_uevent(dev, env);  

  97.         if (retval)  

  98.             pr_debug(“device: ‘%s’: %s: class uevent() “  

  99.                  “returned %d\n”, dev_name(dev),  

  100.                  __func__, retval);  

  101.     }  

  102.   

  103.     /* have the device type specific fuction add its stuff */  

  104.     if (dev->type && dev->type->uevent) {  

  105.         retval = dev->type->uevent(dev, env);  

  106.         if (retval)  

  107.             pr_debug(“device: ‘%s’: %s: dev_type uevent() “  

  108.                  “returned %d\n”, dev_name(dev),  

  109.                  __func__, retval);  

  110.     }  

  111.   

  112.     return retval;  

  113. }  

  114.   

  115. static struct kset_uevent_ops device_uevent_ops = {  

  116.     .filter =   dev_uevent_filter,  

  117.     .name =     dev_uevent_name,  

  118.     .uevent =   dev_uevent,  

  119. };  

前面在讲到kset时,我们并未关注其中的kset_event_ops结构变量。但这里device既然用到了,我们就对其中的三个函数做简单介绍。kset_uevent_ops中的函数是用于管理kset内部kobject的uevent操作。其中filter函数用于阻止一个kobject向用户空间发送uevent,返回值为0表示阻止。这里dev_uevent_filter()检查device所属的bus或者class是否存在,如果都不存在,也就没有发送uevent的必要了。name函数是用于覆盖kset发送给用户空间的名称。这里dev_uevent_name()选择使用bus或者class的名称。uevent()函数是在uevent将被发送到用户空间之前调用的,用于向uevent中增加新的环境变量。dev_uevent()的实现很热闹,向uevent中添加了各种环境变量。


  1. static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,  

  2.                char *buf)  

  3. {  

  4.     struct kobject *top_kobj;  

  5.     struct kset *kset;  

  6.     struct kobj_uevent_env *env = NULL;  

  7.     int i;  

  8.     size_t count = 0;  

  9.     int retval;  

  10.   

  11.     /* search the kset, the device belongs to */  

  12.     top_kobj = &dev->kobj;  

  13.     while (!top_kobj->kset && top_kobj->parent)  

  14.         top_kobj = top_kobj->parent;  

  15.     if (!top_kobj->kset)  

  16.         goto out;  

  17.   

  18.     kset = top_kobj->kset;  

  19.     if (!kset->uevent_ops || !kset->uevent_ops->uevent)  

  20.         goto out;  

  21.   

  22.     /* respect filter */  

  23.     if (kset->uevent_ops && kset->uevent_ops->filter)  

  24.         if (!kset->uevent_ops->filter(kset, &dev->kobj))  

  25.             goto out;  

  26.   

  27.     env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);  

  28.     if (!env)  

  29.         return -ENOMEM;  

  30.   

  31.     /* let the kset specific function add its keys */  

  32.     retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);  

  33.     if (retval)  

  34.         goto out;  

  35.   

  36.     /* copy keys to file */  

  37.     for (i = 0; i < env->envp_idx; i++)  

  38.         count += sprintf(&buf[count], “%s\n”, env->envp[i]);  

  39. out:  

  40.     kfree(env);  

  41.     return count;  

  42. }  

  43.   

  44. static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,  

  45.                 const char *buf, size_t count)  

  46. {  

  47.     enum kobject_action action;  

  48.   

  49.     if (kobject_action_type(buf, count, &action) == 0) {  

  50.         kobject_uevent(&dev->kobj, action);  

  51.         goto out;  

  52.     }  

  53.   

  54.     dev_err(dev, “uevent: unsupported action-string; this will “  

  55.              “be ignored in a future kernel version\n”);  

  56.     kobject_uevent(&dev->kobj, KOBJ_ADD);  

  57. out:  

  58.     return count;  

  59. }  

  60.   

  61. static struct device_attribute uevent_attr =  

  62.     __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);  

device不仅在kset中添加了对uevent的管理,而且还把uevent信息做成设备的一个属性uevent。其中show_event()是显示uevent中环境变量的,store_uevent()是发送uevent的。


  1. static int device_add_attributes(struct device *dev,  

  2.                  struct device_attribute *attrs)  

  3. {  

  4.     int error = 0;  

  5.     int i;  

  6.   

  7.     if (attrs) {  

  8.         for (i = 0; attr_name(attrs[i]); i++) {  

  9.             error = device_create_file(dev, &attrs[i]);  

  10.             if (error)  

  11.                 break;  

  12.         }  

  13.         if (error)  

  14.             while (–i >= 0)  

  15.                 device_remove_file(dev, &attrs[i]);  

  16.     }  

  17.     return error;  

  18. }  

  19.   

  20. static void device_remove_attributes(struct device *dev,  

  21.                      struct device_attribute *attrs)  

  22. {  

  23.     int i;  

  24.   

  25.     if (attrs)  

  26.         for (i = 0; attr_name(attrs[i]); i++)  

  27.             device_remove_file(dev, &attrs[i]);  

  28. }  

  29.   

  30. static int device_add_groups(struct device *dev,  

  31.                  const struct attribute_group **groups)  

  32. {  

  33.     int error = 0;  

  34.     int i;  

  35.   

  36.     if (groups) {  

  37.         for (i = 0; groups[i]; i++) {  

  38.             error = sysfs_create_group(&dev->kobj, groups[i]);  

  39.             if (error) {  

  40.                 while (–i >= 0)  

  41.                     sysfs_remove_group(&dev->kobj,  

  42.                                groups[i]);  

  43.                 break;  

  44.             }  

  45.         }  

  46.     }  

  47.     return error;  

  48. }  

  49.   

  50. static void device_remove_groups(struct device *dev,  

  51.                  const struct attribute_group **groups)  

  52. {  

  53.     int i;  

  54.   

  55.     if (groups)  

  56.         for (i = 0; groups[i]; i++)  

  57.             sysfs_remove_group(&dev->kobj, groups[i]);  

  58. }  

以上四个内部函数是用来向device中添加或删除属性与属性集合的。


device_add_attributes、device_remove_attributes、device_add_groups、device_remove_groups,都是直接通过sysfs提供的API实现。


  1. static int device_add_attrs(struct device *dev)  

  2. {  

  3.     struct class *class = dev->class;  

  4.     struct device_type *type = dev->type;  

  5.     int error;  

  6.   

  7.     if (class) {  

  8.         error = device_add_attributes(dev, class->dev_attrs);  

  9.         if (error)  

  10.             return error;  

  11.     }  

  12.   

  13.     if (type) {  

  14.         error = device_add_groups(dev, type->groups);  

  15.         if (error)  

  16.             goto err_remove_class_attrs;  

  17.     }  

  18.   

  19.     error = device_add_groups(dev, dev->groups);  

  20.     if (error)  

  21.         goto err_remove_type_groups;  

  22.   

  23.     return 0;  

  24.   

  25.  err_remove_type_groups:  

  26.     if (type)  

  27.         device_remove_groups(dev, type->groups);  

  28.  err_remove_class_attrs:  

  29.     if (class)  

  30.         device_remove_attributes(dev, class->dev_attrs);  

  31.   

  32.     return error;  

  33. }  

  34.   

  35. static void device_remove_attrs(struct device *dev)  

  36. {  

  37.     struct class *class = dev->class;  

  38.     struct device_type *type = dev->type;  

  39.   

  40.     device_remove_groups(dev, dev->groups);  

  41.   

  42.     if (type)  

  43.         device_remove_groups(dev, type->groups);  

  44.   

  45.     if (class)  

  46.         device_remove_attributes(dev, class->dev_attrs);  

  47. }  

device_add_attrs()实际负责device中的属性添加。也是几个部分的集合,包括class中的dev_attrs,device_type中的groups,还有device本身的groups。


device_remove_attrs()则负责对应的device属性删除工作。


  1. #define print_dev_t(buffer, dev)                    \   

  2.     sprintf((buffer), “%u:%u\n”, MAJOR(dev), MINOR(dev))  

  3.   

  4. static ssize_t show_dev(struct device *dev, struct device_attribute *attr,  

  5.             char *buf)  

  6. {  

  7.     return print_dev_t(buf, dev->devt);  

  8. }  

  9.   

  10. static struct device_attribute devt_attr =  

  11.     __ATTR(dev, S_IRUGO, show_dev, NULL);  

这里又定义了一个名为dev的属性,就是显示设备的设备号。


  1. /** 

  2.  * device_create_file – create sysfs attribute file for device. 

  3.  * @dev: device. 

  4.  * @attr: device attribute descriptor. 

  5.  */  

  6. int device_create_file(struct device *dev, struct device_attribute *attr)  

  7. {  

  8.     int error = 0;  

  9.     if (dev)  

  10.         error = sysfs_create_file(&dev->kobj, &attr->attr);  

  11.     return error;  

  12. }  

  13.   

  14. /** 

  15.  * device_remove_file – remove sysfs attribute file. 

  16.  * @dev: device. 

  17.  * @attr: device attribute descriptor. 

  18.  */  

  19. void device_remove_file(struct device *dev, struct device_attribute *attr)  

  20. {  

  21.     if (dev)  

  22.         sysfs_remove_file(&dev->kobj, &attr->attr);  

  23. }  

  24.   

  25. /** 

  26.  * device_create_bin_file – create sysfs binary attribute file for device. 

  27.  * @dev: device. 

  28.  * @attr: device binary attribute descriptor. 

  29.  */  

  30. int device_create_bin_file(struct device *dev, struct bin_attribute *attr)  

  31. {  

  32.     int error = -EINVAL;  

  33.     if (dev)  

  34.         error = sysfs_create_bin_file(&dev->kobj, attr);  

  35.     return error;  

  36. }  

  37.   

  38. /** 

  39.  * device_remove_bin_file – remove sysfs binary attribute file 

  40.  * @dev: device. 

  41.  * @attr: device binary attribute descriptor. 

  42.  */  

  43. void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)  

  44. {  

  45.     if (dev)  

  46.         sysfs_remove_bin_file(&dev->kobj, attr);  

  47. }  

  48.   

  49. int device_schedule_callback_owner(struct device *dev,  

  50.         void (*func)(struct device *), struct module *owner)  

  51. {  

  52.     return sysfs_schedule_callback(&dev->kobj,  

  53.             (void (*)(void *)) func, dev, owner);  

  54. }  

这里的五个函数,也是对sysfs提供的API的简单封装。


device_create_file()和device_remove_file()提供直接的属性文件管理方法。


 device_create_bin_file()和device_remove_bin_file()则是提供设备管理二进制文件的方法。


device_schedule_callback_owner()也是简单地将func加入工作队列。


  1. static void klist_children_get(struct klist_node *n)  

  2. {  

  3.     struct device_private *p = to_device_private_parent(n);  

  4.     struct device *dev = p->device;  

  5.   

  6.     get_device(dev);  

  7. }  

  8.   

  9. static void klist_children_put(struct klist_node *n)  

  10. {  

  11.     struct device_private *p = to_device_private_parent(n);  

  12.     struct device *dev = p->device;  

  13.   

  14.     put_device(dev);  

  15. }  

如果之前认真看过klist的实现,应该知道,klist_children_get()和klist_children_put()就是在设备挂入和删除父设备的klist_children链表时调用的函数。在父设备klist_children链表上的指针,相当于对device的一个引用计数。


  1. struct device *get_device(struct device *dev)  

  2. {  

  3.     return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;  

  4. }  

  5.   

  6. /** 

  7.  * put_device – decrement reference count. 

  8.  * @dev: device in question. 

  9.  */  

  10. void put_device(struct device *dev)  

  11. {  

  12.     /* might_sleep(); */  

  13.     if (dev)  

  14.         kobject_put(&dev->kobj);  

  15. }  

device中的引用计数,完全交给内嵌的kobject来做。如果引用计数降为零,自然是调用之前说到的包含甚广的device_release函数。


  1. void device_initialize(struct device *dev)  

  2. {  

  3.     dev->kobj.kset = devices_kset;  

  4.     kobject_init(&dev->kobj, &device_ktype);  

  5.     INIT_LIST_HEAD(&dev->dma_pools);  

  6.     init_MUTEX(&dev->sem);  

  7.     spin_lock_init(&dev->devres_lock);  

  8.     INIT_LIST_HEAD(&dev->devres_head);  

  9.     device_init_wakeup(dev, 0);  

  10.     device_pm_init(dev);  

  11.     set_dev_node(dev, -1);  

  12. }  

device_initialize()就是device结构的初始化函数,它把device中能初始化的部分全初始化。它的界限在其中kobj的位置与device在设备驱动模型中的位置,这些必须由外部设置。可以看到,调用kobject_init()时,object的kobj_type选择了device_ktype,其中主要是sysops的两个函数,还有device_release函数。


  1. static struct kobject *virtual_device_parent(struct device *dev)  

  2. {  

  3.     static struct kobject *virtual_dir = NULL;  

  4.   

  5.     if (!virtual_dir)  

  6.         virtual_dir = kobject_create_and_add(“virtual”,  

  7.                              &devices_kset->kobj);  

  8.   

  9.     return virtual_dir;  

  10. }  

  11.   

  12. static struct kobject *get_device_parent(struct device *dev,  

  13.                      struct device *parent)  

  14. {  

  15.     int retval;  

  16.   

  17.     if (dev->class) {  

  18.         struct kobject *kobj = NULL;  

  19.         struct kobject *parent_kobj;  

  20.         struct kobject *k;  

  21.   

  22.         /* 

  23.          * If we have no parent, we live in “virtual”. 

  24.          * Class-devices with a non class-device as parent, live 

  25.          * in a “glue” directory to prevent namespace collisions. 

  26.          */  

  27.         if (parent == NULL)  

  28.             parent_kobj = virtual_device_parent(dev);  

  29.         else if (parent->class)  

  30.             return &parent->kobj;  

  31.         else  

  32.             parent_kobj = &parent->kobj;  

  33.   

  34.         /* find our class-directory at the parent and reference it */  

  35.         spin_lock(&dev->class->p->class_dirs.list_lock);  

  36.         list_for_each_entry(k, &dev->class->p->class_dirs.list, entry)  

  37.             if (k->parent == parent_kobj) {  

  38.                 kobj = kobject_get(k);  

  39.                 break;  

  40.             }  

  41.         spin_unlock(&dev->class->p->class_dirs.list_lock);  

  42.         if (kobj)  

  43.             return kobj;  

  44.   

  45.         /* or create a new class-directory at the parent device */  

  46.         k = kobject_create();  

  47.         if (!k)  

  48.             return NULL;  

  49.         k->kset = &dev->class->p->class_dirs;  

  50.         retval = kobject_add(k, parent_kobj, “%s”, dev->class->name);  

  51.         if (retval < 0) {  

  52.             kobject_put(k);  

  53.             return NULL;  

  54.         }  

  55.         /* do not emit an uevent for this simple “glue” directory */  

  56.         return k;  

  57.     }  

  58.   

  59.     if (parent)  

  60.         return &parent->kobj;  

  61.     return NULL;  

  62. }  

这里的get_device_parent()就是获取父节点的kobject,但也并非就如此简单。get_device_parent()的返回值直接决定了device将被挂在哪个目录下。到底该挂在哪,是由dev->class、dev->parent、dev->parent->class等因素综合决定的。我们看get_device_parent()中是如何判断的。如果dev->class为空,表示一切随父设备,有parent则返回parent->kobj,没有则返回NULL。如果有dev->class呢,情况就比较复杂了,也许device有着与parent不同的class,也许device还没有一个parent,等等。我们看具体的情况。如果parent不为空,而且存在parent->class,则还放在parent目录下。不然,要么parent不存在,要么parent没有class,很难直接将有class的device放在parent下面。目前的解决方法很简单,在parent与device之间,再加一层表示class的目录。如果parent都没有,那就把/sys/devices/virtual当做parent。class->p->class_dirs就是专门存放这种中间kobject的kset。思路理清后,再结合实际的sysfs,代码就很容易看懂了。


  1. static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)  

  2. {  

  3.     /* see if we live in a “glue” directory */  

  4.     if (!glue_dir || !dev->class ||  

  5.         glue_dir->kset != &dev->class->p->class_dirs)  

  6.         return;  

  7.   

  8.     kobject_put(glue_dir);  

  9. }  

  10.   

  11. static void cleanup_device_parent(struct device *dev)  

  12. {  

  13.     cleanup_glue_dir(dev, dev->kobj.parent);  

  14. }  

cleanup_device_parent()是取消对parent引用时调用的函数,看起来只针对这种glue形式的目录起作用。


  1. static void setup_parent(struct device *dev, struct device *parent)  

  2. {  

  3.     struct kobject *kobj;  

  4.     kobj = get_device_parent(dev, parent);  

  5.     if (kobj)  

  6.         dev->kobj.parent = kobj;  

  7. }  

setup_parent()就是调用get_device_parent()获得应该存放的父目录kobj,并把dev->kobj.parent设为它。


  1. static int device_add_class_symlinks(struct device *dev)  

  2. {  

  3.     int error;  

  4.   

  5.     if (!dev->class)  

  6.         return 0;  

  7.   

  8.     error = sysfs_create_link(&dev->kobj,  

  9.                   &dev->class->p->class_subsys.kobj,  

  10.                   “subsystem”);  

  11.     if (error)  

  12.         goto out;  

  13.     /* link in the class directory pointing to the device */  

  14.     error = sysfs_create_link(&dev->class->p->class_subsys.kobj,  

  15.                   &dev->kobj, dev_name(dev));  

  16.     if (error)  

  17.         goto out_subsys;  

  18.   

  19.     if (dev->parent && device_is_not_partition(dev)) {  

  20.         error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,  

  21.                       “device”);  

  22.         if (error)  

  23.             goto out_busid;  

  24.     }  

  25.     return 0;  

  26.   

  27. out_busid:  

  28.     sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));  

  29. out_subsys:  

  30.     sysfs_remove_link(&dev->kobj, “subsystem”);  

  31. out:  

  32.     return error;  

  33. }  

device_add_class_symlinks()在device和class直接添加一些软链接。在device目录下创建指向class的subsystem文件,在class目录下创建指向device的同名文件。如果device有父设备,而且device不是块设备分区,则在device目录下建立一个指向父设备的device链接文件。这一点在usb设备和usb接口间很常见。


  1. static void device_remove_class_symlinks(struct device *dev)  

  2. {  

  3.     if (!dev->class)  

  4.         return;  

  5.   

  6. #ifdef CONFIG_SYSFS_DEPRECATED   

  7.     if (dev->parent && device_is_not_partition(dev)) {  

  8.         char *class_name;  

  9.   

  10.         class_name = make_class_name(dev->class->name, &dev->kobj);  

  11.         if (class_name) {  

  12.             sysfs_remove_link(&dev->parent->kobj, class_name);  

  13.             kfree(class_name);  

  14.         }  

  15.         sysfs_remove_link(&dev->kobj, “device”);  

  16.     }  

  17.   

  18.     if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&  

  19.         device_is_not_partition(dev))  

  20.         sysfs_remove_link(&dev->class->p->class_subsys.kobj,  

  21.                   dev_name(dev));  

  22. #else   

  23.     if (dev->parent && device_is_not_partition(dev))  

  24.         sysfs_remove_link(&dev->kobj, “device”);  

  25.   

  26.     sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));  

  27. #endif   

  28.   

  29.     sysfs_remove_link(&dev->kobj, “subsystem”);  

  30. }  

device_remove_class_symlinks()删除device和class之间的软链接。


  1. static inline const char *dev_name(const struct device *dev)  

  2. {  

  3.     return kobject_name(&dev->kobj);  

  4. }  

  5.   

  6. int dev_set_name(struct device *dev, const char *fmt, …)  

  7. {  

  8.     va_list vargs;  

  9.     int err;  

  10.   

  11.     va_start(vargs, fmt);  

  12.     err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);  

  13.     va_end(vargs);  

  14.     return err;  

  15. }  

dev_name()获得设备名称,dev_set_name()设置设备名称。但这里的dev_set_name()只能在设备未注册前使用。device的名称其实是完全靠dev->kobj管理的。


  1. static struct kobject *device_to_dev_kobj(struct device *dev)  

  2. {  

  3.     struct kobject *kobj;  

  4.   

  5.     if (dev->class)  

  6.         kobj = dev->class->dev_kobj;  

  7.     else  

  8.         kobj = sysfs_dev_char_kobj;  

  9.   

  10.     return kobj;  

  11. }  

device_to_dev_kobj()为dev选择合适的/sys/dev下的kobject,或者是块设备,或者是字符设备,或者没有。


  1. #define format_dev_t(buffer, dev)                   \   

  2.     ({                              \  

  3.         sprintf(buffer, “%u:%u”, MAJOR(dev), MINOR(dev));   \  

  4.         buffer;                         \  

  5.     })  

  6.   

  7. static int device_create_sys_dev_entry(struct device *dev)  

  8. {  

  9.     struct kobject *kobj = device_to_dev_kobj(dev);  

  10.     int error = 0;  

  11.     char devt_str[15];  

  12.   

  13.     if (kobj) {  

  14.         format_dev_t(devt_str, dev->devt);  

  15.         error = sysfs_create_link(kobj, &dev->kobj, devt_str);  

  16.     }  

  17.   

  18.     return error;  

  19. }  

  20.   

  21. static void device_remove_sys_dev_entry(struct device *dev)  

  22. {  

  23.     struct kobject *kobj = device_to_dev_kobj(dev);  

  24.     char devt_str[15];  

  25.   

  26.     if (kobj) {  

  27.         format_dev_t(devt_str, dev->devt);  

  28.         sysfs_remove_link(kobj, devt_str);  

  29.     }  

  30. }  

device_create_sys_dev_entry()是在/sys/dev相应的目录下建立对设备的软链接。先是通过device_to_dev_kobj()获得父节点的kobj,然后调用sysfs_create_link()建立软链接。


device_remove_sys_dev_entry()与其操作正相反,删除在/sys/dev下建立的软链接。


  1. int device_private_init(struct device *dev)  

  2. {  

  3.     dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);  

  4.     if (!dev->p)  

  5.         return -ENOMEM;  

  6.     dev->p->device = dev;  

  7.     klist_init(&dev->p->klist_children, klist_children_get,  

  8.            klist_children_put);  

  9.     return 0;  

  10. }  

device_private_init()分配并初始化dev->p。至于空间的释放,是等到释放设备时调用的device_release()中。


之前的函数比较散乱,或许找不出一个整体的印象。但下面马上就要看到重要的部分了,因为代码终于攒到了爆发的程度!


  1. /** 

  2.  * device_register – register a device with the system. 

  3.  * @dev: pointer to the device structure 

  4.  * 

  5.  * This happens in two clean steps – initialize the device 

  6.  * and add it to the system. The two steps can be called 

  7.  * separately, but this is the easiest and most common. 

  8.  * I.e. you should only call the two helpers separately if 

  9.  * have a clearly defined need to use and refcount the device 

  10.  * before it is added to the hierarchy. 

  11.  * 

  12.  * NOTE: _Never_ directly free @dev after calling this function, even 

  13.  * if it returned an error! Always use put_device() to give up the 

  14.  * reference initialized in this function instead. 

  15.  */  

  16. int device_register(struct device *dev)  

  17. {  

  18.     device_initialize(dev);  

  19.     return device_add(dev);  

  20. }  

device_register()是提供给外界注册设备的接口。它先是调用device_initialize()初始化dev结构,然后调用device_add()将其加入系统中。但要注意,在调用device_register()注册dev之前,有一些dev结构变量是需要自行设置的。这其中有指明设备位置的struct device *parent,struct bus_type *bus, struct class *class,有指明设备属性的 const char *init_name, struct device_type *type, const struct attribute_group **groups, void (*release)(struct device *dev), dev_t devt,等等。不同设备的使用方法不同,我们留待之后再具体分析。device_initialize()我们已经看过,下面重点看看device_add()是如何实现的。


  1. int device_add(struct device *dev)  

  2. {  

  3.     struct device *parent = NULL;  

  4.     struct class_interface *class_intf;  

  5.     int error = -EINVAL;  

  6.   

  7.     dev = get_device(dev);  

  8.     if (!dev)  

  9.         goto done;  

  10.   

  11.     if (!dev->p) {  

  12.         error = device_private_init(dev);  

  13.         if (error)  

  14.             goto done;  

  15.     }  

  16.   

  17.     /* 

  18.      * for statically allocated devices, which should all be converted 

  19.      * some day, we need to initialize the name. We prevent reading back 

  20.      * the name, and force the use of dev_name() 

  21.      */  

  22.     if (dev->init_name) {  

  23.         dev_set_name(dev, “%s”, dev->init_name);  

  24.         dev->init_name = NULL;  

  25.     }  

  26.   

  27.     if (!dev_name(dev))  

  28.         goto name_error;  

  29.   

  30.     pr_debug(“device: ‘%s’: %s\n”, dev_name(dev), __func__);  

  31.   

  32.     parent = get_device(dev->parent);  

  33.     setup_parent(dev, parent);  

  34.   

  35.     /* use parent numa_node */  

  36.     if (parent)  

  37.         set_dev_node(dev, dev_to_node(parent));  

  38.   

  39.     /* first, register with generic layer. */  

  40.     /* we require the name to be set before, and pass NULL */  

  41.     error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);  

  42.     if (error)  

  43.         goto Error;  

  44.   

  45.     /* notify platform of device entry */  

  46.     if (platform_notify)  

  47.         platform_notify(dev);  

  48.   

  49.     error = device_create_file(dev, &uevent_attr);  

  50.     if (error)  

  51.         goto attrError;  

  52.   

  53.     if (MAJOR(dev->devt)) {  

  54.         error = device_create_file(dev, &devt_attr);  

  55.         if (error)  

  56.             goto ueventattrError;  

  57.   

  58.         error = device_create_sys_dev_entry(dev);  

  59.         if (error)  

  60.             goto devtattrError;  

  61.   

  62.         devtmpfs_create_node(dev);  

  63.     }  

  64.   

  65.     error = device_add_class_symlinks(dev);  

  66.     if (error)  

  67.         goto SymlinkError;  

  68.     error = device_add_attrs(dev);  

  69.     if (error)  

  70.         goto AttrsError;  

  71.     error = bus_add_device(dev);  

  72.     if (error)  

  73.         goto BusError;  

  74.     error = dpm_sysfs_add(dev);  

  75.     if (error)  

  76.         goto DPMError;  

  77.     device_pm_add(dev);  

  78.   

  79.     /* Notify clients of device addition.  This call must come 

  80.      * after dpm_sysf_add() and before kobject_uevent(). 

  81.      */  

  82.     if (dev->bus)  

  83.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  

  84.                          BUS_NOTIFY_ADD_DEVICE, dev);  

  85.   

  86.     kobject_uevent(&dev->kobj, KOBJ_ADD);  

  87.     bus_probe_device(dev);  

  88.     if (parent)  

  89.         klist_add_tail(&dev->p->knode_parent,  

  90.                    &parent->p->klist_children);  

  91.   

  92.     if (dev->class) {  

  93.         mutex_lock(&dev->class->p->class_mutex);  

  94.         /* tie the class to the device */  

  95.         klist_add_tail(&dev->knode_class,  

  96.                    &dev->class->p->class_devices);  

  97.   

  98.         /* notify any interfaces that the device is here */  

  99.         list_for_each_entry(class_intf,  

  100.                     &dev->class->p->class_interfaces, node)  

  101.             if (class_intf->add_dev)  

  102.                 class_intf->add_dev(dev, class_intf);  

  103.         mutex_unlock(&dev->class->p->class_mutex);  

  104.     }  

  105. done:  

  106.     put_device(dev);  

  107.     return error;  

  108.  DPMError:  

  109.     bus_remove_device(dev);  

  110.  BusError:  

  111.     device_remove_attrs(dev);  

  112.  AttrsError:  

  113.     device_remove_class_symlinks(dev);  

  114.  SymlinkError:  

  115.     if (MAJOR(dev->devt))  

  116.         device_remove_sys_dev_entry(dev);  

  117.  devtattrError:  

  118.     if (MAJOR(dev->devt))  

  119.         device_remove_file(dev, &devt_attr);  

  120.  ueventattrError:  

  121.     device_remove_file(dev, &uevent_attr);  

  122.  attrError:  

  123.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);  

  124.     kobject_del(&dev->kobj);  

  125.  Error:  

  126.     cleanup_device_parent(dev);  

  127.     if (parent)  

  128.         put_device(parent);  

  129. name_error:  

  130.     kfree(dev->p);  

  131.     dev->p = NULL;  

  132.     goto done;  

  133. }  

device_add()将dev加入设备驱动模型。它先是调用get_device(dev)增加dev的引用计数,然后调用device_private_init()分配和初始化dev->p,调用dev_set_name()设置dev名字。然后是准备将dev加入sysfs,先是用get_device(parent)增加对parent的引用计数(无论是直接挂在parent下还是通过一个类层挂在parent下都要增加parent的引用计数),然后调用setup_parent()找到实际要加入的父kobject,通过kobject_add()加入其下。然后是添加属性和属性集合的操作,调用device_create_file()添加uevent属性,调用device_add_attrs()添加device/type/class预定义的属性与属性集合。如果dev有被分配设备号,再用device_create_file()添加dev属性,并用device_create_sys_dev_entry()在/sys/dev下添加相应的软链接,最后调用devtmpfs_create_node()在/dev下创建相应的设备文件。然后调用device_add_class_symlinks()添加dev与class间的软链接,调用bus_add_device()添加dev与bus间的软链接,并将dev挂入bus的设备链表。调用dpm_sysfs_add()增加dev下的power属性集合,调用device_pm_add()将dev加入dpm_list链表。


调用kobject_uevent()发布KOBJ_ADD消息,调用bus_probe_device()为dev寻找合适的驱动。如果有parent节点,把dev->p->knode_parent挂入parent->p->klist_children链表。如果dev有所属的class,将dev->knode_class挂在class->p->class_devices上,并调用可能的类设备接口的add_dev()方法。可能对于直接在bus上的设备来说,自然可以调用bus_probe_device()查找驱动,而不与总线直接接触的设备,则要靠class来发现驱动,这里的class_interface中的add_dev()方法,就是一个绝好的机会。最后会调用put_device(dev)释放在函数开头增加的引用计数。


device_add()要做的事很多,但想想每件事都在情理之中。device是设备驱动模型的基本元素,在class、bus、dev、devices中都有它的身影。device_add()要适应各种类型的设备注册,自然会越来越复杂。可以说文件开头定义的内部函数,差不多都是为了这里服务的。


  1. void device_unregister(struct device *dev)  

  2. {  

  3.     pr_debug(“device: ‘%s’: %s\n”, dev_name(dev), __func__);  

  4.     device_del(dev);  

  5.     put_device(dev);  

  6. }  

有注册自然又注销。device_unregister()就是用于将dev从系统中注销,并释放创建时产生的引用计数。


  1. void device_del(struct device *dev)  

  2. {  

  3.     struct device *parent = dev->parent;  

  4.     struct class_interface *class_intf;  

  5.   

  6.     /* Notify clients of device removal.  This call must come 

  7.      * before dpm_sysfs_remove(). 

  8.      */  

  9.     if (dev->bus)  

  10.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  

  11.                          BUS_NOTIFY_DEL_DEVICE, dev);  

  12.     device_pm_remove(dev);  

  13.     dpm_sysfs_remove(dev);  

  14.     if (parent)  

  15.         klist_del(&dev->p->knode_parent);  

  16.     if (MAJOR(dev->devt)) {  

  17.         devtmpfs_delete_node(dev);  

  18.         device_remove_sys_dev_entry(dev);  

  19.         device_remove_file(dev, &devt_attr);  

  20.     }  

  21.     if (dev->class) {  

  22.         device_remove_class_symlinks(dev);  

  23.   

  24.         mutex_lock(&dev->class->p->class_mutex);  

  25.         /* notify any interfaces that the device is now gone */  

  26.         list_for_each_entry(class_intf,  

  27.                     &dev->class->p->class_interfaces, node)  

  28.             if (class_intf->remove_dev)  

  29.                 class_intf->remove_dev(dev, class_intf);  

  30.         /* remove the device from the class list */  

  31.         klist_del(&dev->knode_class);  

  32.         mutex_unlock(&dev->class->p->class_mutex);  

  33.     }  

  34.     device_remove_file(dev, &uevent_attr);  

  35.     device_remove_attrs(dev);  

  36.     bus_remove_device(dev);  

  37.   

  38.     /* 

  39.      * Some platform devices are driven without driver attached 

  40.      * and managed resources may have been acquired.  Make sure 

  41.      * all resources are released. 

  42.      */  

  43.     devres_release_all(dev);  

  44.   

  45.     /* Notify the platform of the removal, in case they 

  46.      * need to do anything… 

  47.      */  

  48.     if (platform_notify_remove)  

  49.         platform_notify_remove(dev);  

  50.     kobject_uevent(&dev->kobj, KOBJ_REMOVE);  

  51.     cleanup_device_parent(dev);  

  52.     kobject_del(&dev->kobj);  

  53.     put_device(parent);  

  54. }  

device_del()是与device_add()相对的函数,进行实际的将dev从系统中脱离的工作。这其中既有将dev从设备驱动模型各种链表中脱离的工作,又有将dev从sysfs的各个角落删除的工作。大致流程与dev_add()相对,就不一一介绍。


爆发结束,下面来看一些比较轻松的函数。


  1. /** 

  2.  * device_get_devnode – path of device node file 

  3.  * @dev: device 

  4.  * @mode: returned file access mode 

  5.  * @tmp: possibly allocated string 

  6.  * 

  7.  * Return the relative path of a possible device node. 

  8.  * Non-default names may need to allocate a memory to compose 

  9.  * a name. This memory is returned in tmp and needs to be 

  10.  * freed by the caller. 

  11.  */  

  12. const char *device_get_devnode(struct device *dev,  

  13.                    mode_t *mode, const char **tmp)  

  14. {  

  15.     char *s;  

  16.   

  17.     *tmp = NULL;  

  18.   

  19.     /* the device type may provide a specific name */  

  20.     if (dev->type && dev->type->devnode)  

  21.         *tmp = dev->type->devnode(dev, mode);  

  22.     if (*tmp)  

  23.         return *tmp;  

  24.   

  25.     /* the class may provide a specific name */  

  26.     if (dev->class && dev->class->devnode)  

  27.         *tmp = dev->class->devnode(dev, mode);  

  28.     if (*tmp)  

  29.         return *tmp;  

  30.   

  31.     /* return name without allocation, tmp == NULL */  

  32.     if (strchr(dev_name(dev), ‘!’) == NULL)  

  33.         return dev_name(dev);  

  34.   

  35.     /* replace ‘!’ in the name with ‘/’ */  

  36.     *tmp = kstrdup(dev_name(dev), GFP_KERNEL);  

  37.     if (!*tmp)  

  38.         return NULL;  

  39.     while ((s = strchr(*tmp, ‘!’)))  

  40.         s[0] = ‘/’;  

  41.     return *tmp;  

  42. }  

device_get_devnode()返回设备的路径名。不过似乎可以由device_type或者class定义一些独特的返回名称。


  1. static struct device *next_device(struct klist_iter *i)  

  2. {  

  3.     struct klist_node *n = klist_next(i);  

  4.     struct device *dev = NULL;  

  5.     struct device_private *p;  

  6.   

  7.     if (n) {  

  8.         p = to_device_private_parent(n);  

  9.         dev = p->device;  

  10.     }  

  11.     return dev;  

  12. }  

  13.   

  14. int device_for_each_child(struct device *parent, void *data,  

  15.               int (*fn)(struct device *dev, void *data))  

  16. {  

  17.     struct klist_iter i;  

  18.     struct device *child;  

  19.     int error = 0;  

  20.   

  21.     if (!parent->p)  

  22.         return 0;  

  23.   

  24.     klist_iter_init(&parent->p->klist_children, &i);  

  25.     while ((child = next_device(&i)) && !error)  

  26.         error = fn(child, data);  

  27.     klist_iter_exit(&i);  

  28.     return error;  

  29. }  

  30.   

  31. struct device *device_find_child(struct device *parent, void *data,  

  32.                  int (*match)(struct device *dev, void *data))  

  33. {  

  34.     struct klist_iter i;  

  35.     struct device *child;  

  36.   

  37.     if (!parent)  

  38.         return NULL;  

  39.   

  40.     klist_iter_init(&parent->p->klist_children, &i);  

  41.     while ((child = next_device(&i)))  

  42.         if (match(child, data) && get_device(child))  

  43.             break;  

  44.     klist_iter_exit(&i);  

  45.     return child;  

  46. }  

device_for_each_child()对dev下的每个子device,都调用一遍特定的处理函数。


device_find_child()则是查找dev下特点的子device,查找使用特定的match函数。


这两个遍历过程都使用了klist特有的遍历函数,支持遍历过程中的节点删除等功能。next_device()则是为了遍历方便封装的一个内部函数。


下面本该是root_device注册相关的代码。但经过检查,linux内核中使用到的root_device很少见,而且在sysfs中也未能找到一个实际的例子。所以root_device即使还未被弃用,也并非主流,我们将其跳过。


与kobject和kset类似,device也为我们提供了快速device创建方法,下面就看看吧。


  1. static void device_create_release(struct device *dev)  

  2. {  

  3.     pr_debug(“device: ‘%s’: %s\n”, dev_name(dev), __func__);  

  4.     kfree(dev);  

  5. }  

  6.   

  7. struct device *device_create_vargs(struct class *classstruct device *parent,  

  8.                    dev_t devt, void *drvdata, const char *fmt,  

  9.                    va_list args)  

  10. {  

  11.     struct device *dev = NULL;  

  12.     int retval = -ENODEV;  

  13.   

  14.     if (class == NULL || IS_ERR(class))  

  15.         goto error;  

  16.   

  17.     dev = kzalloc(sizeof(*dev), GFP_KERNEL);  

  18.     if (!dev) {  

  19.         retval = -ENOMEM;  

  20.         goto error;  

  21.     }  

  22.   

  23.     dev->devt = devt;  

  24.     dev->class = class;  

  25.     dev->parent = parent;  

  26.     dev->release = device_create_release;  

  27.     dev_set_drvdata(dev, drvdata);  

  28.   

  29.     retval = kobject_set_name_vargs(&dev->kobj, fmt, args);  

  30.     if (retval)  

  31.         goto error;  

  32.   

  33.     retval = device_register(dev);  

  34.     if (retval)  

  35.         goto error;  

  36.   

  37.     return dev;  

  38.   

  39. error:  

  40.     put_device(dev);  

  41.     return ERR_PTR(retval);  

  42. }  

  43.   

  44. struct device *device_create(struct class *classstruct device *parent,  

  45.                  dev_t devt, void *drvdata, const char *fmt, …)  

  46. {  

  47.     va_list vargs;  

  48.     struct device *dev;  

  49.   

  50.     va_start(vargs, fmt);  

  51.     dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);  

  52.     va_end(vargs);  

  53.     return dev;  

  54. }  

这里的device_create()提供了一个快速的dev创建注册方法。只是中间没有提供设置device_type的方法,或许是这样的device已经够特立独行了,不需要搞出一类来。


  1. static int __match_devt(struct device *dev, void *data)  

  2. {  

  3.     dev_t *devt = data;  

  4.   

  5.     return dev->devt == *devt;  

  6. }  

  7.   

  8. void device_destroy(struct class *class, dev_t devt)  

  9. {  

  10.     struct device *dev;  

  11.   

  12.     dev = class_find_device(class, NULL, &devt, __match_devt);  

  13.     if (dev) {  

  14.         put_device(dev);  

  15.         device_unregister(dev);  

  16.     }  

  17. }  

device_destroy()就是与device_create()相对的注销函数。至于这里为什么会多一个put_device(dev),也很简单,因为在class_find_device()找到dev时,调用了get_device()。


  1. struct device *class_find_device(struct class *classstruct device *start,  

  2.                  void *data,  

  3.                  int (*match)(struct device *, void *))  

  4. {  

  5.     struct class_dev_iter iter;  

  6.     struct device *dev;  

  7.   

  8.     if (!class)  

  9.         return NULL;  

  10.     if (!class->p) {  

  11.         WARN(1, “%s called for class ‘%s’ before it was initialized”,  

  12.              __func__, class->name);  

  13.         return NULL;  

  14.     }  

  15.   

  16.     class_dev_iter_init(&iter, class, start, NULL);  

  17.     while ((dev = class_dev_iter_next(&iter))) {  

  18.         if (match(dev, data)) {  

  19.             get_device(dev);  

  20.             break;  

  21.         }  

  22.     }  

  23.     class_dev_iter_exit(&iter);  

  24.   

  25.     return dev;  

  26. }  

class_find_device()本来是class.c中的内容,其实现也于之前将的遍历dev->p->klist_children类似,无非是在klist提供的遍历方法上加以封装。但我们这里列出class_find_device()的实现与使用它的device_destroy(),却是为了更好地分析这个调用流程中dev是如何被保护的。它实际上是经历了三个保护手段:首先在class_dev_iter_next()->klist_next()中,是受到struct klist中 spinlock_t k_lock保护的。在找到下一点并解锁之前,就增加了struct klist_node中的struct kref n_ref引用计数。在当前的next()调用完,到下一个next()调用之前,都是受这个增加的引用计数保护的。再看class_find_device()中,使用get_device(dev)增加了dev本身的引用计数保护(当然也要追溯到kobj->kref中),这是第三种保护。知道device_destroy()中主动调用put_device(dev)才去除了这种保护。


本来对dev的保护,应该完全是由dev中的引用计数完成的。但实际上这种保护很多时候是间接完成的。例如这里的klist中的自旋锁,klist_node中的引用计数,都不过是为了保持class的设备链表中对dev的引用计数不消失,这是一种间接保护的手段,保证了这中间即使外界主动释放class设备链表对dev的引用计数,dev仍然不会被实际注销。这种曲折的联系,才真正发挥了引用计数的作用,构成设备驱动模型独特的魅力。


  1. int device_rename(struct device *dev, char *new_name)  

  2. {  

  3.     char *old_device_name = NULL;  

  4.     int error;  

  5.   

  6.     dev = get_device(dev);  

  7.     if (!dev)  

  8.         return -EINVAL;  

  9.   

  10.     pr_debug(“device: ‘%s’: %s: renaming to ‘%s’\n”, dev_name(dev),  

  11.          __func__, new_name);  

  12. old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);  

  13.     if (!old_device_name) {  

  14.         error = -ENOMEM;  

  15.         goto out;  

  16.     }  

  17.   

  18.     error = kobject_rename(&dev->kobj, new_name);  

  19.     if (error)  

  20.         goto out;  

  21. if (dev->class) {  

  22.         error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj,  

  23.                          &dev->kobj, dev_name(dev));  

  24.         if (error)  

  25.             goto out;  

  26.         sysfs_remove_link(&dev->class->p->class_subsys.kobj,  

  27.                   old_device_name);  

  28.     }  

  29. out:  

  30.     put_device(dev);  

  31.   

  32.     kfree(old_device_name);  

  33.   

  34.     return error;  

  35. }  

device_rename()是供设备注册后改变名称用的,除了改变/sys/devices下地名称,还改变了/sys/class下地软链接名称。前者很自然,但后者却很难想到。即使简单的地方,经过重重调试,我们也会惊讶于linux的心细如发。


  1. static int device_move_class_links(struct device *dev,  

  2.                    struct device *old_parent,  

  3.                    struct device *new_parent)  

  4. {  

  5.     int error = 0;  

  6.     if (old_parent)  

  7.         sysfs_remove_link(&dev->kobj, “device”);  

  8.     if (new_parent)  

  9.         error = sysfs_create_link(&dev->kobj, &new_parent->kobj,  

  10.                       “device”);  

  11.     return error;  

  12. #endif   

  13. }  

device_move_class_links()只是一个内部函数,后面还有操纵它的那只手。这里的device_move_class_links显得很名不副实,并没用操作class中软链接的举动。这很正常,因为在sysfs中软链接是针对kobject来说的,所以即使位置变掉了,软链接还是很很准确地定位。


  1. /** 

  2.  * device_move – moves a device to a new parent 

  3.  * @dev: the pointer to the struct device to be moved 

  4.  * @new_parent: the new parent of the device (can by NULL) 

  5.  * @dpm_order: how to reorder the dpm_list 

  6.  */  

  7. int device_move(struct device *dev, struct device *new_parent,  

  8.         enum dpm_order dpm_order)  

  9. {  

  10.     int error;  

  11.     struct device *old_parent;  

  12.     struct kobject *new_parent_kobj;  

  13.   

  14.     dev = get_device(dev);  

  15.     if (!dev)  

  16.         return -EINVAL;  

  17.   

  18.     device_pm_lock();  

  19.     new_parent = get_device(new_parent);  

  20.     new_parent_kobj = get_device_parent(dev, new_parent);  

  21.   

  22.     pr_debug(“device: ‘%s’: %s: moving to ‘%s’\n”, dev_name(dev),  

  23.          __func__, new_parent ? dev_name(new_parent) : “<NULL>”);  

  24.     error = kobject_move(&dev->kobj, new_parent_kobj);  

  25.     if (error) {  

  26.         cleanup_glue_dir(dev, new_parent_kobj);  

  27.         put_device(new_parent);  

  28.         goto out;  

  29.     }  

  30.     old_parent = dev->parent;  

  31.     dev->parent = new_parent;  

  32.     if (old_parent)  

  33.         klist_remove(&dev->p->knode_parent);  

  34.     if (new_parent) {  

  35.         klist_add_tail(&dev->p->knode_parent,  

  36.                    &new_parent->p->klist_children);  

  37.         set_dev_node(dev, dev_to_node(new_parent));  

  38.     }  

  39.   

  40.     if (!dev->class)  

  41.         goto out_put;  

  42.     error = device_move_class_links(dev, old_parent, new_parent);  

  43.     if (error) {  

  44.         /* We ignore errors on cleanup since we’re hosed anyway… */  

  45.         device_move_class_links(dev, new_parent, old_parent);  

  46.         if (!kobject_move(&dev->kobj, &old_parent->kobj)) {  

  47.             if (new_parent)  

  48.                 klist_remove(&dev->p->knode_parent);  

  49.             dev->parent = old_parent;  

  50.             if (old_parent) {  

  51.                 klist_add_tail(&dev->p->knode_parent,  

  52.                            &old_parent->p->klist_children);  

  53.                 set_dev_node(dev, dev_to_node(old_parent));  

  54.             }  

  55.         }  

  56.         cleanup_glue_dir(dev, new_parent_kobj);  

  57.         put_device(new_parent);  

  58.         goto out;  

  59.     }  

  60.     switch (dpm_order) {  

  61.     case DPM_ORDER_NONE:  

  62.         break;  

  63.     case DPM_ORDER_DEV_AFTER_PARENT:  

  64.         device_pm_move_after(dev, new_parent);  

  65.         break;  

  66.     case DPM_ORDER_PARENT_BEFORE_DEV:  

  67.         device_pm_move_before(new_parent, dev);  

  68.         break;  

  69.     case DPM_ORDER_DEV_LAST:  

  70.         device_pm_move_last(dev);  

  71.         break;  

  72.     }  

  73. out_put:  

  74.     put_device(old_parent);  

  75. out:  

  76.     device_pm_unlock();  

  77.     put_device(dev);  

  78.     return error;  

  79. }  

device_move()就是将dev移到一个新的parent下。但也有可能这个parent是空的。大部分操作围绕在引用计数上,get_device(),put_device()。而且换了新的parent,到底要加到sysfs中哪个目录下,还要再调用get_device_parent()研究一下。主要的操作就是kobject_move()和device_move_class_links()。因为在sysfs中软链接是针对kobject来说的,所以即使位置变掉了,软链接还是很很准确地定位,所以在/sys/dev、/sys/bus、/sys/class中的软链接都不用变,这实在是sysfs的一大优势。除此之外,device_move()还涉及到电源管理的问题,device移动影响到dev在dpm_list上的位置,我们对此不了解,先忽略之。


  1. void device_shutdown(void)  

  2. {  

  3.     struct device *dev, *devn;  

  4.   

  5.     list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,  

  6.                 kobj.entry) {  

  7.         if (dev->bus && dev->bus->shutdown) {  

  8.             dev_dbg(dev, “shutdown\n”);  

  9.             dev->bus->shutdown(dev);  

  10.         } else if (dev->driver && dev->driver->shutdown) {  

  11.             dev_dbg(dev, “shutdown\n”);  

  12.             dev->driver->shutdown(dev);  

  13.         }  

  14.     }  

  15.     kobject_put(sysfs_dev_char_kobj);  

  16.     kobject_put(sysfs_dev_block_kobj);  

  17.     kobject_put(dev_kobj);  

  18.     async_synchronize_full();  

  19. }  

这个device_shutdown()是在系统关闭时才调用的。它动用了很少使用的devices_kset,从而可以遍历到每个注册到sysfs上的设备,调用相应的总线或驱动定义的shutdown()函数。提起这个,还是在device_initialize()中将dev->kobj->kset统一设为devices_kset的。原来设备虽然有不同的parent,但kset还是一样的。这样我们就能理解/sys/devices下的顶层设备目录是怎么来的,因为没用parent,就在调用kobject_add()时将kset->kobj当成了parent,所以会直接挂在顶层目录下。这样的目录大致有pci0000:00、virtual等等。


看完了core.c,我有种明白机器人也是由零件组成的的感觉。linux设备驱动模型的大门已经打开了四分之一。���着分析的深入,我们大概也会越来越明白linux的良苦用心。

上节我们分析设备驱动模型中的device,主要是drivers/base/core.c,可以说是代码量最大的一个文件。本节要分析的驱动driver,就要相对简单很多。原因也很简单,对于driver,我们能定义的公共部分实在不多,能再sysfs中表达的也很少。本节的分析将围绕drivers/base/driver.c,但头文件仍然是include/linux/device.h和drivers/base/base.h。

先让我们来看看driver的结构。


  1. struct device_driver {  

  2.     const char      *name;  

  3.     struct bus_type     *bus;  

  4.   

  5.     struct module       *owner;  

  6.     const char      *mod_name;  /* used for built-in modules */  

  7.   

  8.     bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */  

  9.   

  10.     int (*probe) (struct device *dev);  

  11.     int (*remove) (struct device *dev);  

  12.     void (*shutdown) (struct device *dev);  

  13.     int (*suspend) (struct device *dev, pm_message_t state);  

  14.     int (*resume) (struct device *dev);  

  15.     const struct attribute_group **groups;  

  16.   

  17.     const struct dev_pm_ops *pm;  

  18.   

  19.     struct driver_private *p;  

  20. };  

struct device_driver就是模型定义的通用驱动结构。name是驱动名称,但这个name也只是在静态定义的初始名称,实际使用的名称还是由kobject中保管的。bus执行驱动所在的总线,owner是驱动所在的模块,还有一个所在模块名称mod_name,suppress_bind_attrs定义是否允许驱动通过sysfs决定挂载还是卸载设备。下面是一系列函数指针,probe是在驱动刚与设备挂接时调用的,remove是在设备卸载时调用的,shutdown是在设备关闭时调用的(说实话我现在还不知道remove和shutdown的区别),suspend是设备休眠时调用的,resume是设备恢复时调用的。group是属性集合,pm是电源管理的函数集合,p是指向driver_private的指针。


  1. struct driver_private {  

  2.     struct kobject kobj;  

  3.     struct klist klist_devices;  

  4.     struct klist_node knode_bus;  

  5.     struct module_kobject *mkobj;  

  6.     struct device_driver *driver;  

  7. };  

  8. #define to_driver(obj) container_of(obj, struct driver_private, kobj)  

与device类似,device_driver把与其它组件联系的大部分结构变量移到struct driver_private中来。首先是kobj,在sysfs中代表driver目录本身。klist_devices是驱动下的设备链表,knode_bus是要挂载在总线的驱动链表上的节点。mkobj是driver与相关module的联系,之前在device_driver结构中已经有指向module的指针,但这还不够,在/sys下你能发现一个module目录,所以驱动所属的模块在sysfs中也有显示,具体留到代码中再看。driver指针自然是从driver_private指回struct device_driver的。


  1. struct driver_attribute {  

  2.     struct attribute attr;  

  3.     ssize_t (*show)(struct device_driver *driver, char *buf);  

  4.     ssize_t (*store)(struct device_driver *driver, const char *buf,  

  5.              size_t count);  

  6. };  

  7.   

  8. #define DRIVER_ATTR(_name, _mode, _show, _store)    \   

  9. struct driver_attribute driver_attr_##_name =       \  

  10.     __ATTR(_name, _mode, _show, _store)  

除了以上两个结构,还有struct driver_attribute。driver_attribute是driver对struct attribute的封装,添加了两个特用于device_driver的读写函数。这种封装看似简单重复,工作量很小,但在使用时却会造成巨大的便利。 


好,结构介绍完毕,下面看driver.c中的实现。


  1. static struct device *next_device(struct klist_iter *i)  

  2. {  

  3.     struct klist_node *n = klist_next(i);  

  4.     struct device *dev = NULL;  

  5.     struct device_private *dev_prv;  

  6.   

  7.     if (n) {  

  8.         dev_prv = to_device_private_driver(n);  

  9.         dev = dev_prv->device;  

  10.     }  

  11.     return dev;  

  12. }  

  13.   

  14. int driver_for_each_device(struct device_driver *drv, struct device *start,  

  15.                void *data, int (*fn)(struct device *, void *))  

  16. {  

  17.     struct klist_iter i;  

  18.     struct device *dev;  

  19.     int error = 0;  

  20.   

  21.     if (!drv)  

  22.         return -EINVAL;  

  23.   

  24.     klist_iter_init_node(&drv->p->klist_devices, &i,  

  25.                  start ? &start->p->knode_driver : NULL);  

  26.     while ((dev = next_device(&i)) && !error)  

  27.         error = fn(dev, data);  

  28.     klist_iter_exit(&i);  

  29.     return error;  

  30. }  

  31. struct device *driver_find_device(struct device_driver *drv,  

  32.                   struct device *start, void *data,  

  33.                   int (*match)(struct device *dev, void *data))  

  34. {  

  35.     struct klist_iter i;  

  36.     struct device *dev;  

  37.   

  38.     if (!drv)  

  39.         return NULL;  

  40.   

  41.     klist_iter_init_node(&drv->p->klist_devices, &i,  

  42.                  (start ? &start->p->knode_driver : NULL));  

  43.     while ((dev = next_device(&i)))  

  44.         if (match(dev, data) && get_device(dev))  

  45.             break;  

  46.     klist_iter_exit(&i);  

  47.     return dev;  

  48. }  

driver_for_each_device()是对drv的设备链表中的每个设备调用一次指定函数。


driver_find_device()是在drv的设备链表中寻找一个设备,寻找使用指定的匹配函数。


这两个函数都不陌生,在之前分析device的core.c中已经见到与它们很类似的函数,只不过那里是遍历设备的子设备链表,这里是遍历驱动的设备链表。next_device()同样是辅助用的内部函数。


  1. int driver_create_file(struct device_driver *drv,  

  2.                struct driver_attribute *attr)  

  3. {  

  4.     int error;  

  5.     if (drv)  

  6.         error = sysfs_create_file(&drv->p->kobj, &attr->attr);  

  7.     else  

  8.         error = -EINVAL;  

  9.     return error;  

  10. }  

  11.   

  12. void driver_remove_file(struct device_driver *drv,  

  13.             struct driver_attribute *attr)  

  14. {  

  15.     if (drv)  

  16.         sysfs_remove_file(&drv->p->kobj, &attr->attr);  

  17. }  

driver_create_file()创建drv下的属性文件,调用sysfs_create_file()实现。


driver_remove_file()删除drv下的属性文件,调用sysfs_remove_file()实现。


  1. static int driver_add_groups(struct device_driver *drv,  

  2.                  const struct attribute_group **groups)  

  3. {  

  4.     int error = 0;  

  5.     int i;  

  6.   

  7.     if (groups) {  

  8.         for (i = 0; groups[i]; i++) {  

  9.             error = sysfs_create_group(&drv->p->kobj, groups[i]);  

  10.             if (error) {  

  11.                 while (–i >= 0)  

  12.                     sysfs_remove_group(&drv->p->kobj,  

  13.                                groups[i]);  

  14.                 break;  

  15.             }  

  16.         }  

  17.     }  

  18.     return error;  

  19. }  

  20.   

  21. static void driver_remove_groups(struct device_driver *drv,  

  22.                  const struct attribute_group **groups)  

  23. {  

  24.     int i;  

  25.   

  26.     if (groups)  

  27.         for (i = 0; groups[i]; i++)  

  28.             sysfs_remove_group(&drv->p->kobj, groups[i]);  

  29. }  

driver_add_groups()在drv目录下添加属性集合,调用sysfs_create_groups()实现。


driver_remove_groups()在drv目录下删除属性集合,调用sysfs_remove_groups()实现。


发现两点问题:第一,是不是觉得driver_add_groups()不太合适,最好改为driver_create_groups()才搭调。但不只是driver用driver_add_groups(),device也使用device_add_groups(),不知一处这样做。第二���有没有发现driver_create_file()是外部函数,driver_add_groups()就是内部函数,也就是说driver只对外提供添加属性的接口,却不提供添加属性集合的接口。理由吗?在struct device_driver()已经专门定义了一个groups变量来添加属性集合,后面就不易再重复提供接口,而且创建属性集合需要的操作远比创建属性费时。在device中也是这样做的。


另外,driver中只提供管理属性文件的方法,却不提供管理二进制属性文件的方法,这是因为驱动本身没有这种需求,只有部分设备才要求二进制文件表示。


  1. struct device_driver *get_driver(struct device_driver *drv)  

  2. {  

  3.     if (drv) {  

  4.         struct driver_private *priv;  

  5.         struct kobject *kobj;  

  6.   

  7.         kobj = kobject_get(&drv->p->kobj);  

  8.         priv = to_driver(kobj);  

  9.         return priv->driver;  

  10.     }  

  11.     return NULL;  

  12. }  

  13.   

  14. void put_driver(struct device_driver *drv)  

  15. {  

  16.     kobject_put(&drv->p->kobj);  

  17. }  

get_driver()增加drv的引用计数,put_driver()减少drv的引用计数。这都是通过drv->p->kobj来做的。


  1. struct device_driver *driver_find(const char *name, struct bus_type *bus)  

  2. {  

  3.     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  

  4.     struct driver_private *priv;  

  5.   

  6.     if (k) {  

  7.         priv = to_driver(k);  

  8.         return priv->driver;  

  9.     }  

  10.     return NULL;  

  11. }  

driver_find()从bus的驱动链表中寻找特定名称的driver。


  1. /** 

  2.  * driver_register – register driver with bus 

  3.  * @drv: driver to register 

  4.  * 

  5.  * We pass off most of the work to the bus_add_driver() call, 

  6.  * since most of the things we have to do deal with the bus 

  7.  * structures. 

  8.  */  

  9. int driver_register(struct device_driver *drv)  

  10. {  

  11.     int ret;  

  12.     struct device_driver *other;  

  13.   

  14.     BUG_ON(!drv->bus->p);  

  15.   

  16.     if ((drv->bus->probe && drv->probe) ||  

  17.         (drv->bus->remove && drv->remove) ||  

  18.         (drv->bus->shutdown && drv->shutdown))  

  19.         printk(KERN_WARNING “Driver ‘%s’ needs updating – please use “  

  20.             “bus_type methods\n”, drv->name);  

  21.   

  22.     other = driver_find(drv->name, drv->bus);  

  23.     if (other) {  

  24.         put_driver(other);  

  25.         printk(KERN_ERR “Error: Driver ‘%s’ is already registered, “  

  26.             “aborting…\n”, drv->name);  

  27.         return -EBUSY;  

  28.     }  

  29.   

  30.     ret = bus_add_driver(drv);  

  31.     if (ret)  

  32.         return ret;  

  33.     ret = driver_add_groups(drv, drv->groups);  

  34.     if (ret)  

  35.         bus_remove_driver(drv);  

  36.     return ret;  

  37. }  

driver_register()将drv注册到系统中。它真是做得难以预料地简单,所有的工作几乎完全是由bus_add_driver()代为完成的。但你要注意,在调用driver_register()前,drv->bus一定要预先设置。device可以不绑定bus,但driver一定要绑定到bus上。


  1. void driver_unregister(struct device_driver *drv)  

  2. {  

  3.     if (!drv || !drv->p) {  

  4.         WARN(1, “Unexpected driver unregister!\n”);  

  5.         return;  

  6.     }  

  7.     driver_remove_groups(drv, drv->groups);  

  8.     bus_remove_driver(drv);  

  9. }  

driver_unregister()将drv从系统中撤销。大部分工作是调用bus_remove_driver()完成的。可以看出bus_add_driver()与bus_remove_driver()相对。driver和bus的联系如此紧密,以至于driver的注册和撤销工作都可以由bus代劳了。我们需要更进一步的分析。 


经过调查,我们发现很有一部分driver的代码被移动到了bus.c中。我们本节是以driver为主,所以接下来会尽量在不惊动bus的情况下,分析存在于bus.c中的driver代码。 


  1. static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,  

  2.                  char *buf)  

  3. {  

  4.     struct driver_attribute *drv_attr = to_drv_attr(attr);  

  5.     struct driver_private *drv_priv = to_driver(kobj);  

  6.     ssize_t ret = -EIO;  

  7.   

  8.     if (drv_attr->show)  

  9.         ret = drv_attr->show(drv_priv->driver, buf);  

  10.     return ret;  

  11. }  

  12.   

  13. static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,  

  14.                   const char *buf, size_t count)  

  15. {  

  16.     struct driver_attribute *drv_attr = to_drv_attr(attr);  

  17.     struct driver_private *drv_priv = to_driver(kobj);  

  18.     ssize_t ret = -EIO;  

  19.   

  20.     if (drv_attr->store)  

  21.         ret = drv_attr->store(drv_priv->driver, buf, count);  

  22.     return ret;  

  23. }  

  24.   

  25. static struct sysfs_ops driver_sysfs_ops = {  

  26.     .show   = drv_attr_show,  

  27.     .store  = drv_attr_store,  

  28. };  

看到这里,你终于觉得driver开始正常了,它还要定义sysfs读写时操作的函数。


  1. static void driver_release(struct kobject *kobj)  

  2. {  

  3.     struct driver_private *drv_priv = to_driver(kobj);  

  4.   

  5.     pr_debug(“driver: ‘%s’: %s\n”, kobject_name(kobj), __func__);  

  6.     kfree(drv_priv);  

  7. }  

  8.   

  9. static struct kobj_type driver_ktype = {  

  10.     .sysfs_ops  = &driver_sysfs_ops,  

  11.     .release    = driver_release,  

  12. };  

与device的释放函数device_release不同,driver_release没有提供外界代码运行的机会,只是简单地释放drv_priv函数。


  1. /* Manually detach a device from its associated driver. */  

  2. static ssize_t driver_unbind(struct device_driver *drv,  

  3.                  const char *buf, size_t count)  

  4. {  

  5.     struct bus_type *bus = bus_get(drv->bus);  

  6.     struct device *dev;  

  7.     int err = -ENODEV;  

  8.   

  9.     dev = bus_find_device_by_name(bus, NULL, buf);  

  10.     if (dev && dev->driver == drv) {  

  11.         if (dev->parent) /* Needed for USB */  

  12.             down(&dev->parent->sem);  

  13.         device_release_driver(dev);  

  14.         if (dev->parent)  

  15.             up(&dev->parent->sem);  

  16.         err = count;  

  17.     }  

  18.     put_device(dev);  

  19.     bus_put(bus);  

  20.     return err;  

  21. }  

  22. static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);  

  23.   

  24. /* 

  25.  * Manually attach a device to a driver. 

  26.  * Note: the driver must want to bind to the device, 

  27.  * it is not possible to override the driver’s id table. 

  28.  */  

  29. static ssize_t driver_bind(struct device_driver *drv,  

  30.                const char *buf, size_t count)  

  31. {  

  32.     struct bus_type *bus = bus_get(drv->bus);  

  33.     struct device *dev;  

  34.     int err = -ENODEV;  

  35.   

  36.     dev = bus_find_device_by_name(bus, NULL, buf);  

  37.     if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {  

  38.         if (dev->parent) /* Needed for USB */  

  39.             down(&dev->parent->sem);  

  40.         down(&dev->sem);  

  41.         err = driver_probe_device(drv, dev);  

  42.         up(&dev->sem);  

  43.         if (dev->parent)  

  44.             up(&dev->parent->sem);  

  45.   

  46.         if (err > 0) {  

  47.             /* success */  

  48.             err = count;  

  49.         } else if (err == 0) {  

  50.             /* driver didn’t accept device */  

  51.             err = -ENODEV;  

  52.         }  

  53.     }  

  54.     put_device(dev);  

  55.     bus_put(bus);  

  56.     return err;  

  57. }  

  58. static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);  

上面描述了driver下两个只写的属性文件,unbind和bind。应该是提供用户空间命令是否将设备与驱动挂接的接口。


  1. static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)  

  2. {  

  3.     int error = 0;  

  4.     int i;  

  5.   

  6.     if (bus->drv_attrs) {  

  7.         for (i = 0; attr_name(bus->drv_attrs[i]); i++) {  

  8.             error = driver_create_file(drv, &bus->drv_attrs[i]);  

  9.             if (error)  

  10.                 goto err;  

  11.         }  

  12.     }  

  13. done:  

  14.     return error;  

  15. err:  

  16.     while (–i >= 0)  

  17.         driver_remove_file(drv, &bus->drv_attrs[i]);  

  18.     goto done;  

  19. }  

  20.   

  21. static void driver_remove_attrs(struct bus_type *bus,  

  22.                 struct device_driver *drv)  

  23. {  

  24.     int i;  

  25.   

  26.     if (bus->drv_attrs) {  

  27.         for (i = 0; attr_name(bus->drv_attrs[i]); i++)  

  28.             driver_remove_file(drv, &bus->drv_attrs[i]);  

  29.     }  

  30. }  

driver_add_attrs()向drv目录下添加属性,只是这些属性都是在bus中定义的drv_attrs[]。


driver_remove_attrs()从drv目录中删除相应的bus->drv_attrs[]。


  1. static int __must_check add_bind_files(struct device_driver *drv)  

  2. {  

  3.     int ret;  

  4.   

  5.     ret = driver_create_file(drv, &driver_attr_unbind);  

  6.     if (ret == 0) {  

  7.         ret = driver_create_file(drv, &driver_attr_bind);  

  8.         if (ret)  

  9.             driver_remove_file(drv, &driver_attr_unbind);  

  10.     }  

  11.     return ret;  

  12. }  

  13.   

  14. static void remove_bind_files(struct device_driver *drv)  

  15. {  

  16.     driver_remove_file(drv, &driver_attr_bind);  

  17.     driver_remove_file(drv, &driver_attr_unbind);  

  18. }  

add_bind_files()在drv目录下增加bind和unbind属性。


remove_bind_files()从drv目录下删除bind和unbind属性。


  1. static ssize_t driver_uevent_store(struct device_driver *drv,  

  2.                    const char *buf, size_t count)  

  3. {  

  4.     enum kobject_action action;  

  5.   

  6.     if (kobject_action_type(buf, count, &action) == 0)  

  7.         kobject_uevent(&drv->p->kobj, action);  

  8.     return count;  

  9. }  

  10. static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);  

这是drv目录下地uevent属性文件,提供了从drv发送uevent的方法。


  1. /** 

  2.  * bus_add_driver – Add a driver to the bus. 

  3.  * @drv: driver. 

  4.  */  

  5. int bus_add_driver(struct device_driver *drv)  

  6. {  

  7.     struct bus_type *bus;  

  8.     struct driver_private *priv;  

  9.     int error = 0;  

  10.   

  11.     bus = bus_get(drv->bus);  

  12.     if (!bus)  

  13.         return -EINVAL;  

  14.   

  15.     pr_debug(“bus: ‘%s’: add driver %s\n”, bus->name, drv->name);  

  16.   

  17.     priv = kzalloc(sizeof(*priv), GFP_KERNEL);  

  18.     if (!priv) {  

  19.         error = -ENOMEM;  

  20.         goto out_put_bus;  

  21.     }  

  22.     klist_init(&priv->klist_devices, NULL, NULL);  

  23.     priv->driver = drv;  

  24.     drv->p = priv;  

  25.     priv->kobj.kset = bus->p->drivers_kset;  

  26.     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,  

  27.                      “%s”, drv->name);  

  28.     if (error)  

  29.         goto out_unregister;  

  30.   

  31.     if (drv->bus->p->drivers_autoprobe) {  

  32.         error = driver_attach(drv);  

  33.         if (error)  

  34.             goto out_unregister;  

  35.     }  

  36.     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);  

  37.     module_add_driver(drv->owner, drv);  

  38.   

  39.     error = driver_create_file(drv, &driver_attr_uevent);  

  40.     if (error) {  

  41.         printk(KERN_ERR “%s: uevent attr (%s) failed\n”,  

  42.             __func__, drv->name);  

  43.     }  

  44.     error = driver_add_attrs(bus, drv);  

  45.     if (error) {  

  46.         /* How the hell do we get out of this pickle? Give up */  

  47.         printk(KERN_ERR “%s: driver_add_attrs(%s) failed\n”,  

  48.             __func__, drv->name);  

  49.     }  

  50.   

  51.     if (!drv->suppress_bind_attrs) {  

  52.         error = add_bind_files(drv);  

  53.         if (error) {  

  54.             /* Ditto */  

  55.             printk(KERN_ERR “%s: add_bind_files(%s) failed\n”,  

  56.                 __func__, drv->name);  

  57.         }  

  58.     }  

  59.   

  60.     kobject_uevent(&priv->kobj, KOBJ_ADD);  

  61.     return 0;  

  62.   

  63. out_unregister:  

  64.     kfree(drv->p);  

  65.     drv->p = NULL;  

  66.     kobject_put(&priv->kobj);  

  67. out_put_bus:  

  68.     bus_put(bus);  

  69.     return error;  

  70. }  

bus_add_driver()看似是把drv与bus联系起来,其实是完成driver加入系统的大部分操作。


首先调用bus_get(drv->bus)增加对bus的引用。


分配并初始化drv->p,即driver_private结构。


调用kobject_init_and_add()将drv加入sysfs,之前只是设置了priv->obj.kset为bus->p->drivers_kset,所以drv目录会出现在bus目录的drivers子目录中。如果总线允许自动probe,就会调用driver_attach()将驱动和总线上的设备进行匹配,这个过程先略过。


然后调用klist_add_tail()将drv挂入总线的驱动链表。


调用module_add_driver()创建driver相关的模块在sysfs中的表示。后面专门描述。


调用driver_create_file()在drv目录下创建uevent属性文件。


调用driver_add_attrs()在drv目录下添加bus->driver_attrs[]中定义的属性。


如果drv->suppress_bind_attrs为零,即允许用户空间决定驱动何时链接和卸载设备,则调用add_bind_files()添加bind和unbind属性文件。


调用kobject_uevent()向用户空间发布KOBJ_ADD消息。 


从bus_add_driver()的处理过程来看,driver只在bus的drivers目录下出现,没什么软链接,需要的属性也不多。


  1. /** 

  2.  * bus_remove_driver – delete driver from bus’s knowledge. 

  3.  * @drv: driver. 

  4.  * 

  5.  * Detach the driver from the devices it controls, and remove 

  6.  * it from its bus’s list of drivers. Finally, we drop the reference 

  7.  * to the bus we took in bus_add_driver(). 

  8.  */  

  9. void bus_remove_driver(struct device_driver *drv)  

  10. {  

  11.     if (!drv->bus)  

  12.         return;  

  13.   

  14.     if (!drv->suppress_bind_attrs)  

  15.         remove_bind_files(drv);  

  16.     driver_remove_attrs(drv->bus, drv);  

  17.     driver_remove_file(drv, &driver_attr_uevent);  

  18.     klist_remove(&drv->p->knode_bus);  

  19.     pr_debug(“bus: ‘%s’: remove driver %s\n”, drv->bus->name, drv->name);  

  20.     driver_detach(drv);  

  21.     module_remove_driver(drv);  

  22.     kobject_put(&drv->p->kobj);  

  23.     bus_put(drv->bus);  

  24. }  

bus_remove_driver()将drv从系统中撤销,与bus_add_driver()相对应。


driver真正精彩的地方在于probe函数,对设备的操作,对用户空间提供的接口,可惜这些都是特定的。这里只能将driver与bus联系起来,并在以后与device联系起来。


不过不必失望,下面我们分析下drivers/base/module.c,它显示了与驱动有关的module,在sysfs中的表现情况。


首先介绍使用到的结构。应该说module.c的代码实现很简单,但使用到的结构不简单。


  1. struct module_attribute {  

  2.         struct attribute attr;  

  3.         ssize_t (*show)(struct module_attribute *, struct module *, char *);  

  4.         ssize_t (*store)(struct module_attribute *, struct module *,  

  5.              const char *, size_t count);  

  6.     void (*setup)(struct module *, const char *);  

  7.     int (*test)(struct module *);  

  8.     void (*free)(struct module *);  

  9. };  

  10.   

  11. struct param_attribute  

  12. {  

  13.     struct module_attribute mattr;  

  14.     struct kernel_param *param;  

  15. };  

  16.   

  17. struct module_param_attrs  

  18. {  

  19.     unsigned int num;  

  20.     struct attribute_group grp;  

  21.     struct param_attribute attrs[0];  

  22. };  

  23.   

  24. struct module_kobject  

  25. {  

  26.     struct kobject kobj;  

  27.     struct module *mod;  

  28.     struct kobject *drivers_dir;  

  29.     struct module_param_attrs *mp;  

  30. };  

可以看到module_attribute结构除了包含struct attribute,还多增加了好几条函数指针。而这只是最简单的,struct param_attribute除了包含module_attribute,还有一个指向kernel_param的指针param。这个kernel_param就太复杂了,是外界向module提供参数用的窗口,这里忽略。后面还有struct module_param_attrs和struct module_kobject。


  1. static char *make_driver_name(struct device_driver *drv)  

  2. {  

  3.     char *driver_name;  

  4.   

  5.     driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,  

  6.                   GFP_KERNEL);  

  7.     if (!driver_name)  

  8.         return NULL;  

  9.   

  10.     sprintf(driver_name, “%s:%s”, drv->bus->name, drv->name);  

  11.     return driver_name;  

  12. }  

make_driver_name()将drv的名字和drv->bus的名字合起来,不过这是一个内部函数,具体使用还要看后面。


  1. static void module_create_drivers_dir(struct module_kobject *mk)  

  2. {  

  3.     if (!mk || mk->drivers_dir)  

  4.         return;  

  5.   

  6.     mk->drivers_dir = kobject_create_and_add(“drivers”, &mk->kobj);  

  7. }  

module_create_drivers_dir()在mk所在的目录下创建一个drivers的目录。不过因为是使用kobject_create_and_add(),所以这个kobject使用默认的dynamic_kobj_ktype。


  1. void module_add_driver(struct module *mod, struct device_driver *drv)  

  2. {  

  3.     char *driver_name;  

  4.     int no_warn;  

  5.     struct module_kobject *mk = NULL;  

  6.   

  7.     if (!drv)  

  8.         return;  

  9.   

  10.     if (mod)  

  11.         mk = &mod->mkobj;  

  12.     else if (drv->mod_name) {  

  13.         struct kobject *mkobj;  

  14.   

  15.         /* Lookup built-in module entry in /sys/modules */  

  16.         mkobj = kset_find_obj(module_kset, drv->mod_name);  

  17.         if (mkobj) {  

  18.             mk = container_of(mkobj, struct module_kobject, kobj);  

  19.             /* remember our module structure */  

  20.             drv->p->mkobj = mk;  

  21.             /* kset_find_obj took a reference */  

  22.             kobject_put(mkobj);  

  23.         }  

  24.     }  

  25.   

  26.     if (!mk)  

  27.         return;  

  28.   

  29.     /* Don’t check return codes; these calls are idempotent */  

  30.     no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, “module”);  

  31.     driver_name = make_driver_name(drv);  

  32.     if (driver_name) {  

  33.         module_create_drivers_dir(mk);  

  34.         no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,  

  35.                         driver_name);  

  36.         kfree(driver_name);  

  37.     }  

  38. }  

module_add_drivers()在module下添加与driver的联系。


开始调用kset_find_obj()从module_kset下寻找drv所属的module对应的kobj。说明每个module在加载时都会在/sys/module中创建一个kobject目录。这里找到后只是将其赋给drv->p->kmobj,并调用kobject_put()释放找到时加上的引用计数。至于为什么driver不保留对module的引用计数,或许是不需要,或许是已经存在了。


接下来调用sysfs_create_link()在驱动目录中添加指向module目录的软链接,名称就是module。


调用module_create_drivers_dir()在module目录下建立drivers子目录。


调用sysfs_create_link()在drivers子目录下建立指向驱动目录的软链接,名称使用make_driver_name()的返回结果。


  1. void module_remove_driver(struct device_driver *drv)  

  2. {  

  3.     struct module_kobject *mk = NULL;  

  4.     char *driver_name;  

  5.   

  6.     if (!drv)  

  7.         return;  

  8.   

  9.     sysfs_remove_link(&drv->p->kobj, “module”);  

  10.   

  11.     if (drv->owner)  

  12.         mk = &drv->owner->mkobj;  

  13.     else if (drv->p->mkobj)  

  14.         mk = drv->p->mkobj;  

  15.     if (mk && mk->drivers_dir) {  

  16.         driver_name = make_driver_name(drv);  

  17.         if (driver_name) {  

  18.             sysfs_remove_link(mk->drivers_dir, driver_name);  

  19.             kfree(driver_name);  

  20.         }  

  21.     }  

  22. }  

module_remove_driver()消除driver与相应module之间的软链接关系。


对于module,应该是另一个议题了,这里只是简单涉及,下节我们将涉及到总线bus,并深入分析device和driver的关系。

前面我们分析了设备驱动模型中的device和driver,device和driver本来是不相关的东西,只因为bus的存在,才被联系到了一起。本节就来看看设备驱动模型中起枢纽作用的bus。本节的头文件在include/linux/device.h和drivers/base/base.h,实现代码主要在bus.c中。因为在bus中有很多代码时为了device找到driver或者driver找到device而定义的,本节先尽量忽略这部分,专注于bus的注册和注销,属性定义等内容。剩下的留到讨论device和driver关系时在分析。

先来看看bus的数据结构。


  1. struct bus_type {  

  2.     const char      *name;  

  3.     struct bus_attribute    *bus_attrs;  

  4.     struct device_attribute *dev_attrs;  

  5.     struct driver_attribute *drv_attrs;  

  6.   

  7.     int (*match)(struct device *dev, struct device_driver *drv);  

  8.     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  

  9.     int (*probe)(struct device *dev);  

  10.     int (*remove)(struct device *dev);  

  11.     void (*shutdown)(struct device *dev);  

  12.   

  13.     int (*suspend)(struct device *dev, pm_message_t state);  

  14.     int (*resume)(struct device *dev);  

  15.   

  16.     const struct dev_pm_ops *pm;  

  17.   

  18.     struct bus_type_private *p;  

  19. };  

struct bus_type是bus的通用数据结构。


name是bus的名称,注意到这里也是const char类型的,在sysfs中使用的还是kobj中动态创建的名称,这里的name只是初始名。


bus_attrs是bus为自己定义的一系列属性,dev_attrs是bus为旗下的device定义的一系列属性,drv_attrs是bus为旗下的driver定义的一系列属性。其中dev_attrs在bus_add_device()->device_add_attrs()中被加入dev目录下,drv_attrs在bus_add_driver()->driver_add_attrs()中被加入driver目录下。


match函数匹配总线中的dev和driver,返回值为1代表匹配成功,为0则失败。


uevent函数用于总线对uevent的环境变量添加,但在总线下设备的dev_uevent处理函数也有对它的调用。


probe函数是总线在匹配成功时调用的函数,bus->probe和drv->probe中只会有一个起效,同时存在时使用bus->probe。


remove函数在总线上设备或者驱动要删除时调用,bus->remove和drv->remove中同样只会有一个起效。


shutdown函数在所有设备都关闭时调用,即在core.c中的device_shutdown()函数中调用,bus->shutdown和drv->shutdown同样只会有一个起效。


suspend函数是在总线上设备休眠时调用。


resume函数是在总线上设备恢复时调用。


pm是struct dev_pm_ops类型,其中定义了一系列电源管理的函数。


p是指向bus_type_private的指针,其中定义了将bus同其它组件联系起来的变量。


  1. struct bus_type_private {  

  2.     struct kset subsys;  

  3.     struct kset *drivers_kset;  

  4.     struct kset *devices_kset;  

  5.     struct klist klist_devices;  

  6.     struct klist klist_drivers;  

  7.     struct blocking_notifier_head bus_notifier;  

  8.     unsigned int drivers_autoprobe:1;  

  9.     struct bus_type *bus;  

  10. };  

  11.   

  12. #define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj)  

struct bus_type_private是将bus同device、driver、sysfs联系起来的结构。


subsys是kset类型,代表bus在sysfs中的类型。


drivers_kset代表bus目录下的drivers子目录。
devices_kset代表bus目录下地devices子目录。


klist_devices是bus的设备链表,klist_drivers是bus的驱动链表。


bus_notifier用于在总线上内容发送变化时调用特定的函数,这里略过。


driver_autoprobe标志定义是否允许device和driver自动匹配,如果允许会在device或者driver注册时就进行匹配工作。


bus指针指向struct bus_type类型。


使用struct bus_type_private可以将struct bus_type中的部分细节屏蔽掉,利于外界使用bus_type。struct  driver_private和struct device_private都有类似的功能。


  1. struct bus_attribute {  

  2.     struct attribute    attr;  

  3.     ssize_t (*show)(struct bus_type *bus, char *buf);  

  4.     ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);  

  5. };  

  6.   

  7. #define BUS_ATTR(_name, _mode, _show, _store)   \   

  8. struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)  

  9.   

  10. #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)  

struct bus_attribute是bus对struct attribute类型的封装,更方便总线属性的定义。


  1. static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,  

  2.                  char *buf)  

  3. {  

  4.     struct bus_attribute *bus_attr = to_bus_attr(attr);  

  5.     struct bus_type_private *bus_priv = to_bus(kobj);  

  6.     ssize_t ret = 0;  

  7.   

  8.     if (bus_attr->show)  

  9.         ret = bus_attr->show(bus_priv->bus, buf);  

  10.     return ret;  

  11. }  

  12.   

  13. static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,  

  14.                   const char *buf, size_t count)  

  15. {  

  16.     struct bus_attribute *bus_attr = to_bus_attr(attr);  

  17.     struct bus_type_private *bus_priv = to_bus(kobj);  

  18.     ssize_t ret = 0;  

  19.   

  20.     if (bus_attr->store)  

  21.         ret = bus_attr->store(bus_priv->bus, buf, count);  

  22.     return ret;  

  23. }  

  24.   

  25. static struct sysfs_ops bus_sysfs_ops = {  

  26.     .show   = bus_attr_show,  

  27.     .store  = bus_attr_store,  

  28. };  

  29.   

  30. static struct kobj_type bus_ktype = {  

  31.     .sysfs_ops  = &bus_sysfs_ops,  

  32. };  

以上应该是我们最熟悉的部分,bus_ktype中定义了bus对应的kset应该使用的kobj_type实例。与此类似,driver使用的是自定义的driver_ktype,device使用的是自定义的device_ktype。只是这里仅仅定义了sysfs_ops,并未定义release函数,不知bus_type_private打算何时释放。


  1. int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)  

  2. {  

  3.     int error;  

  4.     if (bus_get(bus)) {  

  5.         error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);  

  6.         bus_put(bus);  

  7.     } else  

  8.         error = -EINVAL;  

  9.     return error;  

  10. }  

  11.   

  12. void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)  

  13. {  

  14.     if (bus_get(bus)) {  

  15.         sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);  

  16.         bus_put(bus);  

  17.     }  

  18. }  

bus_create_file()在bus目录下创建属性文件,bus_remove_file()在bus目录下删除属性文件。类似的函数在driver和device中都有见到。


  1. static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)  

  2. {  

  3.     struct kobj_type *ktype = get_ktype(kobj);  

  4.   

  5.     if (ktype == &bus_ktype)  

  6.         return 1;  

  7.     return 0;  

  8. }  

  9.   

  10. static struct kset_uevent_ops bus_uevent_ops = {  

  11.     .filter = bus_uevent_filter,  

  12. };  

  13.   

  14. static struct kset *bus_kset;  

可以看到这里定义了一个bus_uevent_ops变量,这是kset对uevent事件处理所用的结构,它会用在bus_kset中。


  1. int __init buses_init(void)  

  2. {  

  3.     bus_kset = kset_create_and_add(“bus”, &bus_uevent_ops, NULL);  

  4.     if (!bus_kset)  

  5.         return -ENOMEM;  

  6.     return 0;  

  7. }  

在buses_init()中创建了/sys/bus目录,这是一个kset类型,使用了bus_uevent_ops的uevent操作类型。


其实这里的操作不难想象,在devices中我们有一个类似的devices_kset,可以回顾一下。


  1. static struct kset_uevent_ops device_uevent_ops = {  

  2.     .filter =   dev_uevent_filter,  

  3.     .name =     dev_uevent_name,  

  4.     .uevent =   dev_uevent,  

  5. };  

  6.   

  7. /* kset to create /sys/devices/  */  

  8. struct kset *devices_kset;  

  9.   

  10. int __init devices_init(void)  

  11. {  

  12.     devices_kset = kset_create_and_add(“devices”, &device_uevent_ops, NULL);  

  13.                 …  

  14. }  

  15.   

  16. void device_initialize(struct device *dev)  

  17. {  

  18.     dev->kobj.kset = devices_kset;  

  19.                 …  

  20. }  

devices_kset在devices_init()中被创建,使用相应的device_uevent_ops进行uevent处理。而devices_kset又被设为每个device初始化时使用的kset。这就不难想象每个device都是以devices_kset为所属kset的,并使用device_uevent_ops中的处理函数。


只是这里还不知bus_kset会在哪里用到,或许是每个bus所属的kset吧,下面会有答案。


  1. static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)  

  2. {  

  3.     return sprintf(buf, “%d\n”, bus->p->drivers_autoprobe);  

  4. }  

  5.   

  6. static ssize_t store_drivers_autoprobe(struct bus_type *bus,  

  7.                        const char *buf, size_t count)  

  8. {  

  9.     if (buf[0] == ‘0’)  

  10.         bus->p->drivers_autoprobe = 0;  

  11.     else  

  12.         bus->p->drivers_autoprobe = 1;  

  13.     return count;  

  14. }  

  15.   

  16. static ssize_t store_drivers_probe(struct bus_type *bus,  

  17.                    const char *buf, size_t count)  

  18. {  

  19.     struct device *dev;  

  20.   

  21.     dev = bus_find_device_by_name(bus, NULL, buf);  

  22.     if (!dev)  

  23.         return -ENODEV;  

  24.     if (bus_rescan_devices_helper(dev, NULL) != 0)  

  25.         return -EINVAL;  

  26.     return count;  

  27. }  

  28.   

  29. static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);  

  30. static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,  

  31.         show_drivers_autoprobe, store_drivers_autoprobe);  

这里定义了总线下的两个属性,只写得drivers_probe,和可读写的drivers_autoprobe。至于其怎么实现的,我们现在还不关心。


  1. static int add_probe_files(struct bus_type *bus)  

  2. {  

  3.     int retval;  

  4.   

  5.     retval = bus_create_file(bus, &bus_attr_drivers_probe);  

  6.     if (retval)  

  7.         goto out;  

  8.   

  9.     retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);  

  10.     if (retval)  

  11.         bus_remove_file(bus, &bus_attr_drivers_probe);  

  12. out:  

  13.     return retval;  

  14. }  

  15.   

  16. static void remove_probe_files(struct bus_type *bus)  

  17. {  

  18.     bus_remove_file(bus, &bus_attr_drivers_autoprobe);  

  19.     bus_remove_file(bus, &bus_attr_drivers_probe);  

  20. }  

add_probe_files()在bus目录下添加drivers_probe和drivers_autoprobe文件。


remove_probe_files()在bus目录下删除drivers_probe和drivers_autoprobe文件。


这两个函数对bus的probe类型属性进行管理,就像add_bind_files/remove_bind_files对driver的bind类型属性进行管理一样。


  1. static ssize_t bus_uevent_store(struct bus_type *bus,  

  2.                 const char *buf, size_t count)  

  3. {  

  4.     enum kobject_action action;  

  5.   

  6.     if (kobject_action_type(buf, count, &action) == 0)  

  7.         kobject_uevent(&bus->p->subsys.kobj, action);  

  8.     return count;  

  9. }  

  10. static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);  

上面定义了bus的一个属性uevent,用于bus所在的kset节点主动发起uevent消息。


同样地uevent文件在driver目录中也有见到。device目录中也有,不过除了store_uevent之外,还增加了show_uevent的功能。


  1. static struct device *next_device(struct klist_iter *i)  

  2. {  

  3.     struct klist_node *n = klist_next(i);  

  4.     struct device *dev = NULL;  

  5.     struct device_private *dev_prv;  

  6.   

  7.     if (n) {  

  8.         dev_prv = to_device_private_bus(n);  

  9.         dev = dev_prv->device;  

  10.     }  

  11.     return dev;  

  12. }  

  13.   

  14. int bus_for_each_dev(struct bus_type *bus, struct device *start,  

  15.              void *data, int (*fn)(struct device *, void *))  

  16. {  

  17.     struct klist_iter i;  

  18.     struct device *dev;  

  19.     int error = 0;  

  20.   

  21.     if (!bus)  

  22.         return -EINVAL;  

  23.   

  24.     klist_iter_init_node(&bus->p->klist_devices, &i,  

  25.                  (start ? &start->p->knode_bus : NULL));  

  26.     while ((dev = next_device(&i)) && !error)  

  27.         error = fn(dev, data);  

  28.     klist_iter_exit(&i);  

  29.     return error;  

  30. }  

  31.   

  32. struct device *bus_find_device(struct bus_type *bus,  

  33.                    struct device *start, void *data,  

  34.                    int (*match)(struct device *dev, void *data))  

  35. {  

  36.     struct klist_iter i;  

  37.     struct device *dev;  

  38.   

  39.     if (!bus)  

  40.         return NULL;  

  41.   

  42.     klist_iter_init_node(&bus->p->klist_devices, &i,  

  43.                  (start ? &start->p->knode_bus : NULL));  

  44.     while ((dev = next_device(&i)))  

  45.         if (match(dev, data) && get_device(dev))  

  46.             break;  

  47.     klist_iter_exit(&i);  

  48.     return dev;  

  49. }  

bus_for_each_dev()是以bus的设备链表中每个设备为参数,调用指定的处理函数。


bus_find_device()是寻找bus设备链表中的某个设备,使用指定的匹配函数。


这两个函数提供遍历bus的设备链表的方法,类似于drivers_for_each_device/drivers_find_device对driver的设备链表的遍历,device_for_each_child/device_find_child对device的子设备链表的遍历。


  1. static int match_name(struct device *dev, void *data)  

  2. {  

  3.     const char *name = data;  

  4.   

  5.     return sysfs_streq(name, dev_name(dev));  

  6. }  

  7.   

  8. struct device *bus_find_device_by_name(struct bus_type *bus,  

  9.                        struct device *start, const char *name)  

  10. {  

  11.     return bus_find_device(bus, start, (void *)name, match_name);  

  12. }  

bus_find_device_by_name()给出了如何使用遍历函数的例子,寻找bus设备链表中指定名称的设备。


  1. static struct device_driver *next_driver(struct klist_iter *i)  

  2. {  

  3.     struct klist_node *n = klist_next(i);  

  4.     struct driver_private *drv_priv;  

  5.   

  6.     if (n) {  

  7.         drv_priv = container_of(n, struct driver_private, knode_bus);  

  8.         return drv_priv->driver;  

  9.     }  

  10.     return NULL;  

  11. }  

  12.   

  13. int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,  

  14.              void *data, int (*fn)(struct device_driver *, void *))  

  15. {  

  16.     struct klist_iter i;  

  17.     struct device_driver *drv;  

  18.     int error = 0;  

  19.   

  20.     if (!bus)  

  21.         return -EINVAL;  

  22.   

  23.     klist_iter_init_node(&bus->p->klist_drivers, &i,  

  24.                  start ? &start->p->knode_bus : NULL);  

  25.     while ((drv = next_driver(&i)) && !error)  

  26.         error = fn(drv, data);  

  27.     klist_iter_exit(&i);  

  28.     return error;  

  29. }  

bus_for_each_drv()对bus的驱动链表中的每个驱动调用指定的函数。


这和前面的bus_for_each_dev/bus_find_dev什么都是类似的,只是你可能怀疑为什么会没有bus_find_drv。是没有它的用武之地吗?


请看driver.c中的driver_find()函数。


  1. struct device_driver *driver_find(const char *name, struct bus_type *bus)  

  2. {  

  3.     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  

  4.     struct driver_private *priv;  

  5.   

  6.     if (k) {  

  7.         priv = to_driver(k);  

  8.         return priv->driver;  

  9.     }  

  10.     return NULL;  

  11. }  

driver_find()函数是在bus的驱动链表中寻找指定名称的驱动,它的存在证明bus_find_drv()完全是用得上的。可linux却偏偏没有实现bus_find_drv。driver_find()的实现也因此一直走内层路线,它直接用kset_find_obj()进行kobect的名称匹配,调用to_driver()等内容将kobj转化为drv。首先这完全不同于bus_for_each_drv()等一系列遍历函数,它们走的都是在klist中寻找的路线,这里确实走的sysfs中kset内部链表。其次,这里其实也是获得了drv的一个引用计数,在kset_find_obj()中会增加匹配的kobj的引用计数,driver_find()并没有释放,就相当于获取了drv的一个引用计数。这样虽然也可以,但代码写得很不优雅。可见人无完人,linux代码还有许多可改进之处。当然,也可能在最新的linux版本中已经改正了。


  1. static int bus_add_attrs(struct bus_type *bus)  

  2. {  

  3.     int error = 0;  

  4.     int i;  

  5.   

  6.     if (bus->bus_attrs) {  

  7.         for (i = 0; attr_name(bus->bus_attrs[i]); i++) {  

  8.             error = bus_create_file(bus, &bus->bus_attrs[i]);  

  9.             if (error)  

  10.                 goto err;  

  11.         }  

  12.     }  

  13. done:  

  14.     return error;  

  15. err:  

  16.     while (–i >= 0)  

  17.         bus_remove_file(bus, &bus->bus_attrs[i]);  

  18.     goto done;  

  19. }  

  20.   

  21. static void bus_remove_attrs(struct bus_type *bus)  

  22. {  

  23.     int i;  

  24.   

  25.     if (bus->bus_attrs) {  

  26.         for (i = 0; attr_name(bus->bus_attrs[i]); i++)  

  27.             bus_remove_file(bus, &bus->bus_attrs[i]);  

  28.     }  

  29. }  

bus_add_attrs()将bus->bus_attrs中定义的属性加入bus目录。


bus_remove_attrs()将bus->bus_attrs中定义的属性删除。


开始看struct bus_type时我们说到结构中的bus_attrs、dev_attrs、drv_attrs三种属性,后两者分别在device_add_attrs()和driver_add_attrs()中添加,最后的bus_attrs也终于在bus_add_attrs()中得到添加。只是它们虽然都定义在bus_type中,确实添加在完全不同的三个地方。


  1. static void klist_devices_get(struct klist_node *n)  

  2. {  

  3.     struct device_private *dev_prv = to_device_private_bus(n);  

  4.     struct device *dev = dev_prv->device;  

  5.   

  6.     get_device(dev);  

  7. }  

  8.   

  9. static void klist_devices_put(struct klist_node *n)  

  10. {  

  11.     struct device_private *dev_prv = to_device_private_bus(n);  

  12.     struct device *dev = dev_prv->device;  

  13.   

  14.     put_device(dev);  

  15. }  

klist_devices_get()用于bus设备链表上添加节点时增加对相应设备的引用。


klist_devices_put()用于bus设备链表上删除节点时减少对相应设备的引用。


相似的函数是device中的klist_children_get/klist_children_put,这是device的子设备链表。除此之外,bus的驱动链表和driver的设备链表,都没有这种引用计数的保护。原因还未知,也许是linux觉得驱动不太靠谱,万一突然当掉,也不至于影响device的正常管理。


  1. /** 

  2.  * bus_register – register a bus with the system. 

  3.  * @bus: bus. 

  4.  * 

  5.  * Once we have that, we registered the bus with the kobject 

  6.  * infrastructure, then register the children subsystems it has: 

  7.  * the devices and drivers that belong to the bus. 

  8.  */  

  9. int bus_register(struct bus_type *bus)  

  10. {  

  11.     int retval;  

  12.     struct bus_type_private *priv;  

  13.   

  14.     priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);  

  15.     if (!priv)  

  16.         return -ENOMEM;  

  17.   

  18.     priv->bus = bus;  

  19.     bus->p = priv;  

  20.   

  21.     BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);  

  22.   

  23.     retval = kobject_set_name(&priv->subsys.kobj, “%s”, bus->name);  

  24.     if (retval)  

  25.         goto out;  

  26.   

  27.     priv->subsys.kobj.kset = bus_kset;  

  28.     priv->subsys.kobj.ktype = &bus_ktype;  

  29.     priv->drivers_autoprobe = 1;  

  30.   

  31.     retval = kset_register(&priv->subsys);  

  32.     if (retval)  

  33.         goto out;  

  34.   

  35.     retval = bus_create_file(bus, &bus_attr_uevent);  

  36.     if (retval)  

  37.         goto bus_uevent_fail;  

  38.   

  39.     priv->devices_kset = kset_create_and_add(“devices”, NULL,  

  40.                          &priv->subsys.kobj);  

  41.     if (!priv->devices_kset) {  

  42.         retval = -ENOMEM;  

  43.         goto bus_devices_fail;  

  44.     }  

  45.   

  46.     priv->drivers_kset = kset_create_and_add(“drivers”, NULL,  

  47.                          &priv->subsys.kobj);  

  48.     if (!priv->drivers_kset) {  

  49.         retval = -ENOMEM;  

  50.         goto bus_drivers_fail;  

  51.     }  

  52.   

  53.     klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  

  54.     klist_init(&priv->klist_drivers, NULL, NULL);  

  55.   

  56.     retval = add_probe_files(bus);  

  57.     if (retval)  

  58.         goto bus_probe_files_fail;  

  59.   

  60.     retval = bus_add_attrs(bus);  

  61.     if (retval)  

  62.         goto bus_attrs_fail;  

  63.   

  64.     pr_debug(“bus: ‘%s’: registered\n”, bus->name);  

  65.     return 0;  

  66.   

  67. bus_attrs_fail:  

  68.     remove_probe_files(bus);  

  69. bus_probe_files_fail:  

  70.     kset_unregister(bus->p->drivers_kset);  

  71. bus_drivers_fail:  

  72.     kset_unregister(bus->p->devices_kset);  

  73. bus_devices_fail:  

  74.     bus_remove_file(bus, &bus_attr_uevent);  

  75. bus_uevent_fail:  

  76.     kset_unregister(&bus->p->subsys);  

  77.     kfree(bus->p);  

  78. out:  

  79.     bus->p = NULL;  

  80.     return retval;  

  81. }  

bus_register()将bus注册到系统中。


先分配并初始化bus->p,名称使用bus->name,所属的kset使用bus_kset(果然不出所料),类型使用bus_ktype。bus_ktype的使用同driver中的driver_ktype,和device中的device_ktype一样,都是自定义的kobj_type,要知道kobj_type的使用关系到release函数,和自定义属性类型能否正常发挥。


调用kset_register()将bus加入sysfs,因为只是设置了kset,所以会被加入/sys/bus目录下。与driver直接加入相关总线的drivers目录类似,却是与device复杂的寻找父节点过程相去甚远。


在bus目录下添加uevent属性。


在bus目录下创建devices子目录。它是一个kset类型的,目的是展示bus下的设备链表。


在bus目录下创建drivers子目录。它也是一个kset类型的,目的是展示bus下的驱动链表。


或许在最开始有设备驱动模型时,还需要kset来表达这种链表关系,但随着klist等结构的加入,kset的作用也越来越少,现在更多的作用是用来处理uevent消息。


之后初始化bus的设备链表和驱动链表,其中设备链表会占用设备的引用计数。


调用add_probe_files()在bus目录下添加probe相关的两个属性文件。


调用bus_add_attrs添加bus结构中添加的属性。 


bus_register()中的操作出乎意料的简单。bus既不需要在哪里添加软链接,也不需要主动向谁报道,从来都是device和driver到bus这里报道的。所以bus_register()中只需要初始一下结构,添加到sysfs中,添加相关的子目录和属性文件,就行了。


  1. void bus_unregister(struct bus_type *bus)  

  2. {  

  3.     pr_debug(“bus: ‘%s’: unregistering\n”, bus->name);  

  4.     bus_remove_attrs(bus);  

  5.     remove_probe_files(bus);  

  6.     kset_unregister(bus->p->drivers_kset);  

  7.     kset_unregister(bus->p->devices_kset);  

  8.     bus_remove_file(bus, &bus_attr_uevent);  

  9.     kset_unregister(&bus->p->subsys);  

  10.     kfree(bus->p);  

  11.     bus->p = NULL;  

  12. }  

bus_unregister()与bus_register()相对,将bus从系统中注销。不过要把bus注销也不是那么简单的,bus中的driver和device都对bus保有一份引用计数。或许正是如此,bus把释放bus->p的动作放在了bus_unregister()中,这至少能保证较早地释放不需要的内存空间。而且在bus引用计数用完时,也不会有任何操作,bus的容错性还是很高的。


  1. static struct bus_type *bus_get(struct bus_type *bus)  

  2. {  

  3.     if (bus) {  

  4.         kset_get(&bus->p->subsys);  

  5.         return bus;  

  6.     }  

  7.     return NULL;  

  8. }  

  9.   

  10. static void bus_put(struct bus_type *bus)  

  11. {  

  12.     if (bus)  

  13.         kset_put(&bus->p->subsys);  

  14. }  

bus_get()增加对bus的引用计数,bus_put()减少对bus的引用计数。实际上这里bus的引用计数降为零时,只是将sysfs中bus对应的目录删除。


无论是bus,还是device,还是driver,都是将主要的注销工作放在相关的unregister中。至于在引用计数降为零时的操作,大概只在device_release()中可见。这主要是因为引用计数,虽然是广泛用在设备驱动模型中,但实际支持的,绝大部分是设备的热插拔,而不是总线或者驱动的热插拔。当然,桥设备的热插拔也可能附带总线的热插拔。


  1. /* 

  2.  * Yes, this forcably breaks the klist abstraction temporarily.  It 

  3.  * just wants to sort the klist, not change reference counts and 

  4.  * take/drop locks rapidly in the process.  It does all this while 

  5.  * holding the lock for the list, so objects can’t otherwise be 

  6.  * added/removed while we’re swizzling. 

  7.  */  

  8. static void device_insertion_sort_klist(struct device *a, struct list_head *list,  

  9.                     int (*compare)(const struct device *a,  

  10.                             const struct device *b))  

  11. {  

  12.     struct list_head *pos;  

  13.     struct klist_node *n;  

  14.     struct device_private *dev_prv;  

  15.     struct device *b;  

  16.   

  17.     list_for_each(pos, list) {  

  18.         n = container_of(pos, struct klist_node, n_node);  

  19.         dev_prv = to_device_private_bus(n);  

  20.         b = dev_prv->device;  

  21.         if (compare(a, b) <= 0) {  

  22.             list_move_tail(&a->p->knode_bus.n_node,  

  23.                        &b->p->knode_bus.n_node);  

  24.             return;  

  25.         }  

  26.     }  

  27.     list_move_tail(&a->p->knode_bus.n_node, list);  

  28. }  

  29.   

  30. void bus_sort_breadthfirst(struct bus_type *bus,  

  31.                int (*compare)(const struct device *a,  

  32.                       const struct device *b))  

  33. {  

  34.     LIST_HEAD(sorted_devices);  

  35.     struct list_head *pos, *tmp;  

  36.     struct klist_node *n;  

  37.     struct device_private *dev_prv;  

  38.     struct device *dev;  

  39.     struct klist *device_klist;  

  40.   

  41.     device_klist = bus_get_device_klist(bus);  

  42.   

  43.     spin_lock(&device_klist->k_lock);  

  44.     list_for_each_safe(pos, tmp, &device_klist->k_list) {  

  45.         n = container_of(pos, struct klist_node, n_node);  

  46.         dev_prv = to_device_private_bus(n);  

  47.         dev = dev_prv->device;  

  48.         device_insertion_sort_klist(dev, &sorted_devices, compare);  

  49.     }  

  50.     list_splice(&sorted_devices, &device_klist->k_list);  

  51.     spin_unlock(&device_klist->k_lock);  

  52. }  

bus_sort_breadthfirst()是将bus的设备链表进行排序,使用指定的比较函数,排成降序。


本节主要分析了bus的注册注销过程,下节我们将深入分析device和driver的绑定过程,了解bus在这其中到底起了什么作用。随着我们了解的逐渐深入,未知的东西也在逐渐增多。但饭要一口一口吃,我们的分析也要一点一点来,急不得。

前面我们分析了device、driver、bus三种类型,主要是三者的注册与注销,在sysfs中的目录与属性文件创建等内容。本节就来详细分析下,在设备注册到总线上时,总线是如何为其寻找对应的驱动的;在驱动注册到总线上时,总线又是如何为其寻找对应的设备的。

本节的实现代码集中在drivers/base/bus.c和drivers/base/dd.c中。


先来回忆下,在device_register()->device_add()中,先是调用bus_add_device()添加device与bus间的联系,并添加bus为device定义的属性,然后会调用bus_probe_device()。bus_probe_device()会试图为已挂在总线上的该设备寻找对应的驱动。我们的故事就从这里开始。


  1. /** 

  2.  * bus_probe_device – probe drivers for a new device 

  3.  * @dev: device to probe 

  4.  * 

  5.  * – Automatically probe for a driver if the bus allows it. 

  6.  */  

  7. void bus_probe_device(struct device *dev)  

  8. {  

  9.     struct bus_type *bus = dev->bus;  

  10.     int ret;  

  11.   

  12.     if (bus && bus->p->drivers_autoprobe) {  

  13.         ret = device_attach(dev);  

  14.         WARN_ON(ret < 0);  

  15.     }  

  16. }  
bus_probe_device()为总线上的设备寻找驱动。它先是检查bus->p->drivers_autoprobe,看是否允许自动探测。允许了才会调用device_attach()进行实际的寻找工作。


说到bus->p->drivers_autoprobe这个变量,它是在bus_type_private中的,在调用bus_register()前都初始化不了,在bus_register()中自动定为1。所以,除非是用户空间通过drivers_autoprobe属性文件主动禁止,bus总是允许自动探测的,所有的bus都是如此。


  1. /** 

  2.  * device_attach – try to attach device to a driver. 

  3.  * @dev: device. 

  4.  * 

  5.  * Walk the list of drivers that the bus has and call 

  6.  * driver_probe_device() for each pair. If a compatible 

  7.  * pair is found, break out and return. 

  8.  * 

  9.  * Returns 1 if the device was bound to a driver; 

  10.  * 0 if no matching driver was found; 

  11.  * -ENODEV if the device is not registered. 

  12.  * 

  13.  * When called for a USB interface, @dev->parent->sem must be held. 

  14.  */  

  15. int device_attach(struct device *dev)  

  16. {  

  17.     int ret = 0;  

  18.   

  19.     down(&dev->sem);  

  20.     if (dev->driver) {  

  21.         ret = device_bind_driver(dev);  

  22.         if (ret == 0)  

  23.             ret = 1;  

  24.         else {  

  25.             dev->driver = NULL;  

  26.             ret = 0;  

  27.         }  

  28.     } else {  

  29.         pm_runtime_get_noresume(dev);  

  30.         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);  

  31.         pm_runtime_put_sync(dev);  

  32.     }  

  33.     up(&dev->sem);  

  34.     return ret;  

  35. }  


device_attach()在实际绑定之前,会用dev->sem进行加锁。不错,dev->sem几乎就是为了在设备与驱动绑定或者解除绑定时加锁用的。还没有看到它在其它地方被调用。


如果在调用device_attach()前就已经有了dev->driver(),就调用device_bind_driver()进行绑定,不然还要调用bus_for_each_drv()进行依次匹配。至于pm_runtime_get_noresume之类的函数,属于电源管理部分,我们现在先忽略。


  1. static void driver_bound(struct device *dev)  

  2. {  

  3.     if (klist_node_attached(&dev->p->knode_driver)) {  

  4.         printk(KERN_WARNING “%s: device %s already bound\n”,  

  5.             __func__, kobject_name(&dev->kobj));  

  6.         return;  

  7.     }  

  8.   

  9.     pr_debug(“driver: ‘%s’: %s: bound to device ‘%s’\n”, dev_name(dev),  

  10.          __func__, dev->driver->name);  

  11.   

  12.     if (dev->bus)  

  13.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  

  14.                          BUS_NOTIFY_BOUND_DRIVER, dev);  

  15.   

  16.     klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);  

  17. }  

  18.   

  19. static int driver_sysfs_add(struct device *dev)  

  20. {  

  21.     int ret;  

  22.   

  23.     ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,  

  24.               kobject_name(&dev->kobj));  

  25.     if (ret == 0) {  

  26.         ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,  

  27.                     “driver”);  

  28.         if (ret)  

  29.             sysfs_remove_link(&dev->driver->p->kobj,  

  30.                     kobject_name(&dev->kobj));  

  31.     }  

  32.     return ret;  

  33. }  

  34.   

  35. static void driver_sysfs_remove(struct device *dev)  

  36. {  

  37.     struct device_driver *drv = dev->driver;  

  38.   

  39.     if (drv) {  

  40.         sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));  

  41.         sysfs_remove_link(&dev->kobj, “driver”);  

  42.     }  

  43. }  

  44.   

  45. /** 

  46.  * device_bind_driver – bind a driver to one device. 

  47.  * @dev: device. 

  48.  * 

  49.  * Allow manual attachment of a driver to a device. 

  50.  * Caller must have already set @dev->driver. 

  51.  * 

  52.  * Note that this does not modify the bus reference count 

  53.  * nor take the bus’s rwsem. Please verify those are accounted 

  54.  * for before calling this. (It is ok to call with no other effort 

  55.  * from a driver’s probe() method.) 

  56.  * 

  57.  * This function must be called with @dev->sem held. 

  58.  */  

  59. int device_bind_driver(struct device *dev)  

  60. {  

  61.     int ret;  

  62.   

  63.     ret = driver_sysfs_add(dev);  

  64.     if (!ret)  

  65.         driver_bound(dev);  

  66.     return ret;  

  67. }  
device_bind_driver()将device与driver绑定。它调用了两个内部函数。


其中drivers_sysfs_add()负责创建sysfs中driver和device指向对方的软链接。还有一个与它相对的函数drivers_sysfs_remove()。


driver_bound()则实际将device加入驱动的设备链表。


因为在调用device_bind_driver()之前就已经设置过dev->driver了,所以这样就将device和driver绑定了。


只是这样好像还缺少了什么,不错,之前看到driver时曾定义了drv->probe函数,bus->probe也有类似的功能,这里只是绑定,却没有调用probe函数。


让我们回过头来,继续看如果device_attach()中没有定义dev->driver会怎么样,是用bus_for_each_drv()对bus的驱动链表进行遍历,遍历函数使用__device_attach。


  1. static int __device_attach(struct device_driver *drv, void *data)  

  2. {  

  3.     struct device *dev = data;  

  4.   

  5.     if (!driver_match_device(drv, dev))  

  6.         return 0;  

  7.   

  8.     return driver_probe_device(drv, dev);  

  9. }  
不要小看了__device_attach(),就是在__device_attach()中既完成了匹配工作,又完成了绑定工作。bus_for_each_drv()在遍历中,如果遍历函数返回值不为0,则遍历结束。所以在__device_attach()找到并绑定了适合的驱动,就会返回1停止遍历,否则继续遍历剩余的驱动。


先来看匹配工作,这是在driver_match_device()中完成的。


  1. static inline int driver_match_device(struct device_driver *drv,  

  2.                       struct device *dev)  

  3. {  

  4.     return drv->bus->match ? drv->bus->match(dev, drv) : 1;  

  5. }  
原来driver_match_device()实际是调用drv->bus->match()来完成设备和驱动的匹配的。其实这也是理所当然。因为总线不同,总线规范设备、厂商、类设备等定义的规格都不同,也只有bus亲自主持匹配工作。再具体的就只能等分析具体总线的时候了。


  1. int driver_probe_device(struct device_driver *drv, struct device *dev)  

  2. {  

  3.     int ret = 0;  

  4.   

  5.     if (!device_is_registered(dev))  

  6.         return -ENODEV;  

  7.   

  8.     pr_debug(“bus: ‘%s’: %s: matched device %s with driver %s\n”,  

  9.          drv->bus->name, __func__, dev_name(dev), drv->name);  

  10.   

  11.     pm_runtime_get_noresume(dev);  

  12.     pm_runtime_barrier(dev);  

  13.     ret = really_probe(dev, drv);  

  14.     pm_runtime_put_sync(dev);  

  15.   

  16.     return ret;  

  17. }  
如果driver_match_device()匹配成功了,__device_attach()就会继续调用driver_probe_devices()完成绑定。但driver_probe_devices()又是调用really_probe()完成的。


  1. static atomic_t probe_count = ATOMIC_INIT(0);  

  2. static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);  

  3.   

  4. static int really_probe(struct device *dev, struct device_driver *drv)  

  5. {  

  6.     int ret = 0;  

  7.   

  8.     atomic_inc(&probe_count);  

  9.     pr_debug(“bus: ‘%s’: %s: probing driver %s with device %s\n”,  

  10.          drv->bus->name, __func__, drv->name, dev_name(dev));  

  11.     WARN_ON(!list_empty(&dev->devres_head));  

  12.   

  13.     dev->driver = drv;  

  14.     if (driver_sysfs_add(dev)) {  

  15.         printk(KERN_ERR “%s: driver_sysfs_add(%s) failed\n”,  

  16.             __func__, dev_name(dev));  

  17.         goto probe_failed;  

  18.     }  

  19.   

  20.     if (dev->bus->probe) {  

  21.         ret = dev->bus->probe(dev);  

  22.         if (ret)  

  23.             goto probe_failed;  

  24.     } else if (drv->probe) {  

  25.         ret = drv->probe(dev);  

  26.         if (ret)  

  27.             goto probe_failed;  

  28.     }  

  29.   

  30.     driver_bound(dev);  

  31.     ret = 1;  

  32.     pr_debug(“bus: ‘%s’: %s: bound device %s to driver %s\n”,  

  33.          drv->bus->name, __func__, dev_name(dev), drv->name);  

  34.     goto done;  

  35.   

  36. probe_failed:  

  37.     devres_release_all(dev);  

  38.     driver_sysfs_remove(dev);  

  39.     dev->driver = NULL;  

  40.   

  41.     if (ret != -ENODEV && ret != -ENXIO) {  

  42.         /* driver matched but the probe failed */  

  43.         printk(KERN_WARNING  

  44.                “%s: probe of %s failed with error %d\n”,  

  45.                drv->name, dev_name(dev), ret);  

  46.     }  

  47.     /* 

  48.      * Ignore errors returned by ->probe so that the next driver can try 

  49.      * its luck. 

  50.      */  

  51.     ret = 0;  

  52. done:  

  53.     atomic_dec(&probe_count);  

  54.     wake_up(&probe_waitqueue);  

  55.     return ret;  

  56. }  
really_probe()完成的绑定工作和device_bind_driver()差不多,只是它还会调用bus->probe或者drv->probe中定义的probe函数。


至于在really_probe()中使用probe_count保护,最后调用wake_up(&probe_waitqueue),都是为了进行同步。


  1. /** 

  2.  * driver_probe_done 

  3.  * Determine if the probe sequence is finished or not. 

  4.  * 

  5.  * Should somehow figure out how to use a semaphore, not an atomic variable… 

  6.  */  

  7. int driver_probe_done(void)  

  8. {  

  9.     pr_debug(“%s: probe_count = %d\n”, __func__,  

  10.          atomic_read(&probe_count));  

  11.     if (atomic_read(&probe_count))  

  12.         return -EBUSY;  

  13.     return 0;  

  14. }  

  15.   

  16. /** 

  17.  * wait_for_device_probe 

  18.  * Wait for device probing to be completed. 

  19.  */  

  20. void wait_for_device_probe(void)  

  21. {  

  22.     /* wait for the known devices to complete their probing */  

  23.     wait_event(probe_waitqueue, atomic_read(&probe_count) == 0);  

  24.     async_synchronize_full();  

  25. }  
driver_probe_done()检查当前是否有设备正在绑定驱动。


wait_for_device_probe()会阻塞到所有的设备绑定完驱动。




关于bus_probe_device()的过程就分析到这里,下面来看下bus_add_driver()又是怎样做的。


之前我们已经知道driver_register()把绝大部分操作都移到了bus_add_driver()中来。其中只有一点和设备与驱动的绑定相关,就是对driver_attach()的调用。


  1. int driver_attach(struct device_driver *drv)  

  2. {  

  3.     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  

  4. }  
driver_attach()一如device_attach,只是这里是对总线的设备链表进行遍历,使用的遍历函数是__driver_attach()。


  1. static int __driver_attach(struct device *dev, void *data)  

  2. {  

  3.     struct device_driver *drv = data;  

  4.   

  5.     /* 

  6.      * Lock device and try to bind to it. We drop the error 

  7.      * here and always return 0, because we need to keep trying 

  8.      * to bind to devices and some drivers will return an error 

  9.      * simply if it didn’t support the device. 

  10.      * 

  11.      * driver_probe_device() will spit a warning if there 

  12.      * is an error. 

  13.      */  

  14.   

  15.     if (!driver_match_device(drv, dev))  

  16.         return 0;  

  17.   

  18.     if (dev->parent) /* Needed for USB */  

  19.         down(&dev->parent->sem);  

  20.     down(&dev->sem);  

  21.     if (!dev->driver)  

  22.         driver_probe_device(drv, dev);  

  23.     up(&dev->sem);  

  24.     if (dev->parent)  

  25.         up(&dev->parent->sem);  

  26.   

  27.     return 0;  

  28. }  
在__driver_attach()中,driver_match_device()就不说了,它是调到bus->match去的。


然后依然是加锁,调用driver_probe_device()函数。这就与__device_attach()的路径一致了。




不要以为就这样结束了,现在我们只是看到了把device和driver绑定到一起的方法,却没有看到解除绑定的方法。


既然绑定的方法是在设备和驱动注册的时候调用的,那解除绑定自然是在设备或驱动注销的时候。


还是先来看设备的,device_unregister()->device_del()会调用bus_remove_device()将设备从总线上删除。


bus_remove_device()是与bus_add_device()相对的,但也不仅如此,它还调用了device_release_driver()来解除与driver的绑定。


  1. /** 

  2.  * device_release_driver – manually detach device from driver. 

  3.  * @dev: device. 

  4.  * 

  5.  * Manually detach device from driver. 

  6.  * When called for a USB interface, @dev->parent->sem must be held. 

  7.  */  

  8. void device_release_driver(struct device *dev)  

  9. {  

  10.     /* 

  11.      * If anyone calls device_release_driver() recursively from 

  12.      * within their ->remove callback for the same device, they 

  13.      * will deadlock right here. 

  14.      */  

  15.     down(&dev->sem);  

  16.     __device_release_driver(dev);  

  17.     up(&dev->sem);  

  18. }  

  19.   

  20. /* 

  21.  * __device_release_driver() must be called with @dev->sem held. 

  22.  * When called for a USB interface, @dev->parent->sem must be held as well. 

  23.  */  

  24. static void __device_release_driver(struct device *dev)  

  25. {  

  26.     struct device_driver *drv;  

  27.   

  28.     drv = dev->driver;  

  29.     if (drv) {  

  30.         pm_runtime_get_noresume(dev);  

  31.         pm_runtime_barrier(dev);  

  32.   

  33.         driver_sysfs_remove(dev);  

  34.   

  35.         if (dev->bus)  

  36.             blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  

  37.                              BUS_NOTIFY_UNBIND_DRIVER,  

  38.                              dev);  

  39.   

  40.         if (dev->bus && dev->bus->remove)  

  41.             dev->bus->remove(dev);  

  42.         else if (drv->remove)  

  43.             drv->remove(dev);  

  44.         devres_release_all(dev);  

  45.         dev->driver = NULL;  

  46.         klist_remove(&dev->p->knode_driver);  

  47.         if (dev->bus)  

  48.             blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  

  49.                              BUS_NOTIFY_UNBOUND_DRIVER,  

  50.                              dev);  

  51.   

  52.         pm_runtime_put_sync(dev);  

  53.     }  

  54. }  
device_release_driver()还是负责加加锁,实际的工作由__device_release_driver()来完成。


除了sysfs和结构中解除绑定的操作,还调用了bus->remove或者driver->remove。




虽然device注销时与driver解除绑定很简单,但driver注销要与device解除绑定就要复杂一些,因为它要与设备链表上所有的设备解除绑定。


在driver_unregister()->bus_remove_driver()中,调用了driver_detach()函数。


  1. /** 

  2.  * driver_detach – detach driver from all devices it controls. 

  3.  * @drv: driver. 

  4.  */  

  5. void driver_detach(struct device_driver *drv)  

  6. {  

  7.     struct device_private *dev_prv;  

  8.     struct device *dev;  

  9.   

  10.     for (;;) {  

  11.         spin_lock(&drv->p->klist_devices.k_lock);  

  12.         if (list_empty(&drv->p->klist_devices.k_list)) {  

  13.             spin_unlock(&drv->p->klist_devices.k_lock);  

  14.             break;  

  15.         }  

  16.         dev_prv = list_entry(drv->p->klist_devices.k_list.prev,  

  17.                      struct device_private,  

  18.                      knode_driver.n_node);  

  19.         dev = dev_prv->device;  

  20.         get_device(dev);  

  21.         spin_unlock(&drv->p->klist_devices.k_lock);  

  22.   

  23.         if (dev->parent) /* Needed for USB */  

  24.             down(&dev->parent->sem);  

  25.         down(&dev->sem);  

  26.         if (dev->driver == drv)  

  27.             __device_release_driver(dev);  

  28.         up(&dev->sem);  

  29.         if (dev->parent)  

  30.             up(&dev->parent->sem);  

  31.         put_device(dev);  

  32.     }  

  33. }  
可以看到,driver_detach()基本操作就是与设备链表上的设备解除绑定。等了这么久,终于有个有点意思的地方。一看这个drv的设备链表遍历,首先明明是klist,却没使用标准的循环函数,奇怪,然后发现竟然没有将设备卸下链表的地方,更奇怪。其实再一想就明白了。你看到list_entry()中,是从设备链表末尾取设备解除绑定的,这是驱动生怕前面的设备解除绑定了,后面的就不工作了。也正是因为klist遍历是逆向的,所以无法使用标准函数。至于将设备卸下链表的地方,是在__device_release_driver()中。


或许会奇怪这里为什么会有get_device()和put_device()的操作。这是为了防止设备一取下链表,就会释放最后一个引用计数,导致直接注销。那时候的情况,一定是在占用了dev->sem的同时去等待dev->sem,通俗来说就是死锁。


通过driver_attach()和driver_detach()的训练,我们已经习惯在为设备加锁时,顺便为其父设备加锁。虽然在device_attach()和device_release_driver()中只是对设备本身加锁。或许是害怕在驱动与设备解除绑定的过程中,父设备突然也要解除绑定,导致不一致状态。为至于为什么设备方主动要求时不需要对父设备加锁,或许是设备的主动申请更靠谱,不会在子设备绑定或释放的同时,父设备也申请释放。总之,在linux看来,设备恐怕比驱动还要靠谱一些,从driver和bus的引用计数,从这里的加锁情况,都可以看出一二。


  1. void *dev_get_drvdata(const struct device *dev)  

  2. {  

  3.     if (dev && dev->p)  

  4.         return dev->p->driver_data;  

  5.     return NULL;  

  6. }  

  7.   

  8. void dev_set_drvdata(struct device *dev, void *data)  

  9. {  

  10.     int error;  

  11.   

  12.     if (!dev)  

  13.         return;  

  14.     if (!dev->p) {  

  15.         error = device_private_init(dev);  

  16.         if (error)  

  17.             return;  

  18.     }  

  19.     dev->p->driver_data = data;  

  20. }  
最后的dev_set_drvdata()是在dev->p->driver_data中存放驱动定义的数据。dev_get_drvdata()是获取这个数据。


不要 小看这个device_private结构中小小的driver_data,在驱动编写中总能派上大用场。当然也不是说没有driver_data就过不下去,毕竟驱动可以定义一个自己的device结构,并把通用的struct device内嵌其中,然后想放多少数据都行。可那样太麻烦,许多驱动都要专门设置这样一个变量,索性加到通用的数据结构中。而且是直接加到device_private中,眼不见为净,方便省事。


  1. /** 

  2.  * device_reprobe – remove driver for a device and probe for a new driver 

  3.  * @dev: the device to reprobe 

  4.  * 

  5.  * This function detaches the attached driver (if any) for the given 

  6.  * device and restarts the driver probing process.  It is intended 

  7.  * to use if probing criteria changed during a devices lifetime and 

  8.  * driver attachment should change accordingly. 

  9.  */  

  10. int device_reprobe(struct device *dev)  

  11. {  

  12.     if (dev->driver) {  

  13.         if (dev->parent)        /* Needed for USB */  

  14.             down(&dev->parent->sem);  

  15.         device_release_driver(dev);  

  16.         if (dev->parent)  

  17.             up(&dev->parent->sem);  

  18.     }  

  19.     return bus_rescan_devices_helper(dev, NULL);  

  20. }  
device_reprobe()显然是dev对之前的驱动不满意,要新绑定一个。


  1. static int __must_check bus_rescan_devices_helper(struct device *dev,  

  2.                           void *data)  

  3. {  

  4.     int ret = 0;  

  5.   

  6.     if (!dev->driver) {  

  7.         if (dev->parent) /* Needed for USB */  

  8.             down(&dev->parent->sem);  

  9.         ret = device_attach(dev);  

  10.         if (dev->parent)  

  11.             up(&dev->parent->sem);  

  12.     }  

  13.     return ret < 0 ? ret : 0;  

  14. }  
bus_rescan_devices_helper()就是用来绑定新驱动的内部函数。


我们终于成功完成了对dd.c的分析,并将bus.c剩余的部分结了尾。想必大家已经充分领略了device、driver和bus的铁三角结构,下节我们将进入设备驱动模型的另一方天地。

赞(0) 打赏
转载请注明出处:服务器评测 » Linux内核部件分析
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏