kobject和kset的一些學習心得


  #include <linux/module.h>

  #include <linux/kernel.h>

  #include <linux/kobject.h>

  #include <linux/sysfs.h>

  #include <linux/slab.h>

  static struct kobject * parent;

  static struct kobject *child;

  static struct kset *c_kset;

  static unsigned long flag= 1;

  static ssize_t att_show(struct kobject *kobj,struct attribute *attr,char *buf)

  {

  size_t count = 0;

  count += sprintf(&buf[count],"%lu\n",flag);

  return count;

  }

  static ssize_t att_store(struct kobject *kobj,struct attribute *attr,

  const char *buf,size_t count)

  {

  flag = buf[0]-'0';

  //通過kobject_uevent來將內核對象kobj的狀態變化通知用戶程序

  switch(flag){

  case 0:

  kobject_uevent(kobj,KOBJ_ADD);

  break;

  case 1:

  kobject_uevent(kobj,KOBJ_REMOVE);

  break;

  case 2:

  kobject_uevent(kobj,KOBJ_CHANGE);

  break;

  case 3:

  kobject_uevent(kobj,KOBJ_MOVE);

  break;

  case 4:

  kobject_uevent(kobj,KOBJ_ONLINE);

  break;

  case 5:

  kobject_uevent(kobj,KOBJ_OFFLINE);

  break;

  }

  return count;

  }

  static struct attribute cld_att = {

  .name = "cldatt",

  .mode = 0777,

  };

  static const struct sysfs_ops att_ops = {

  .show = att_show,

  .store = att_store,

  };

  static struct kobj_type cld_ktype = {

  .sysfs_ops = &att_ops,

  };

  static int kobj_demo_init(void)

  {

  int err;

  parent = kobject_create_and_add("pa_obj",NULL);

  child = kzalloc(sizeof(*child),GFP_KERNEL);

  if(!child)

  return PTR_ERR(child);

  //一個能夠通知用戶空間狀態變化的kobject必須隸屬於某一個kset,也就是所謂的

  //subsystem,所以此處給內核對象child創建一個kset對象c_kset

  c_kset = kset_create_and_add("c_kset",NULL,parent);

  if(!c_kset)

  return -1;

  child->kset = c_kset;

  err = kobject_init_and_add(child,&cld_ktype,NULL,"cld_obj");

  if(err)

  return err;

  err = sysfs_create_file(child,&cld_att);

  return err;

  }

  static void kobj_demo_exit(void)

  {

  sysfs_remove_file(child,&cld_att);

  kset_unregister(c_kset);

  kobject_del(child);

  kobject_del(parent);

  }

  module_init(kobj_demo_init);

  module_exit(kobj_demo_exit);

  MODULE_LICENSE("GPL");

  陳學松大蝦的這個例子十分好。贊一個。

  kobject_create_and_add這個函數首先會調用kobject_create來分配並初始化一個kobject對象,

  然后調用kobject_add函數在sysfs文件系統中為新生成的kobject對象建立一個新的目錄。那么這個目錄建立在

  sysfs文件系統中的哪個位置呢?kobject_add最后是通過sysfs_craete_dir函數來創建一個目錄的,看一下這個函數

  的關鍵代碼便能知道

  /*fs/sysfs/dir.c*/

  int sysfs_create_dir(struct kobject *kobj)

  {

  ...

  if(kobj->parent)

  parent_sd = kobj->parent->sd;

  else

  parent_sd = &sysfs_root;

  ...

  error =create_dir(kobj,parent_sd,type,ns,kobject_name(kobj),&sd);

  if(!error)

  kobj->sd = sd;

  return error;

  }

  可以看到,如果kobj->parent字段為空,那么該函數就會調用create_dir在sysfs文件樹的根目錄下為kobj創建

  一個新的目錄,否則就在parent的目錄下為該kobj創建一個新的目錄。

  kobject_add首先會將參數parent賦值給kobj的parent成員 kobj->parent =parent,然后調用kobject_add_internal(kobj)函數,

  在kobject_add_internal函數內部,如果調用kobject_add時parent是一個NULL指針,那么要看該kobj是否在一個

  kset對象中,如果是就把該kset中的kobject成員作為kobj的parent;否則kobj的parent值仍然為NULL,那么在接下來

  調用sysfs_create_dir的時候,該kobj就會在/sys目錄創建一個新的文件夾。

  /*struct kobject * kobject_create_and_add(const char * name,struct kobject *parent)*/

  例如上面的kobject_create_and_add("pa_obj",NULL);這個函數傳入的parent為空,那么他將會在/sys下創建一個目錄名為pa_obj的新目錄。

  /*struct kset *kset_create_and_add(const char *name,

  struct kset_uevent_ops *uevent_ops,

  struct kobject *parent_kobj)*/

  再看下面的kset_create_and_add("c_kset",NULL,parent);kset里面也有一個內嵌的kobject,所以傳入的第一個和第三個參數是

  給這個內嵌的kobject用的,第二個參數是給kset用的。

  看一下kset的結構體原形:

  struct kset {

  struct list_head list;

  spinlock_t list_lock;

  struct kobject kobj;

  struct kset_uevent_ops *uevent_ops;

  };

  多么簡單,其實kset在sysfs文件系統中沒有實體表現的,他不像kobject,一個kobject對應一個sysfs文件系統下的一個目錄,kset的存在無法就是為了

  方便管理kobject。

  kset_create_and_add最終也會調用kobject_create_and_add,傳入的參數肯定是""c_kset"和parent,那么將會在/sys/pa_obj的目錄下面創建

  一個目錄名為c_kset的新目錄.

  再來看下面的

  child->kset = c_kset;

  err = kobject_init_and_add(child,&cld_ktype,NULL,"cld_obj");

  kobject_init_and_add與kobject_create_and_add的其中一個區別便是前者可以使用自己定義的kobj_type,而后者內核會提供一個默認的kobj_type

  (讀者自己深入函數內部就會看到這個默認的kobj_type)。

  這個函數原型為:int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,

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

  上面的程序在調用這個函數的時候把parent設置為NULL,由於在調用這個函數之前有這么一行:child->kset = c_kset,如上所分析的那樣,

  由於設置了child所屬的kset,那么在kobject_init_and_add內部會把child->parent設置為c_kset->kobj,這意味着將會在/sys/pa_obj/c_kset目錄下

  創建一個目錄名為cld_obj的新目錄,如果你把這kobject_init_and_add參數中的NULL改為parent(parent = kobject_create_and_add("pa_obj",NULL);

  這個parent就是pa_obj的對象kobj),那么這么一改,cld_obj目錄就和c_kset目錄一樣都是在/sys/pa_obj目錄之下了。

  再下面的sysfs_create_file是在相應的目錄下面創建一個屬性文件(注意,現在是創建文件而不是目錄了)

  上面幾個函數是構建linux設備模型框架的最基本的函數。。如果說linux設備模型是一棟摩天大廈,那么這幾個函數就是把這個大廈建立起來的最

  底層的建築工人。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM