Chinaunix首页 | 论坛 | 博客
  • 博客访问: 51794
  • 博文数量: 19
  • 博客积分: 930
  • 博客等级: 准尉
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-29 17:58
文章分类
文章存档

2009年(8)

2008年(11)

我的朋友
最近访客

分类: LINUX

2008-12-03 14:24:59

proc文件的管理 1 proc_dir_entry结构 首先我们看一下proc_dir_entry结构,这个结构在proc_fs.h中定义: struct proc_dir_entry { unsigned short low_ino; unsigned short namelen; const char *name; mode_t mode; nlink_t nlink; uid_t uid; gid_t gid; unsigned long size; struct inode_operations * proc_iops; struct file_operations * proc_fops; get_info_t *get_info; struct module *owner; struct proc_dir_entry *next, *parent, *subdir; void *data; read_proc_t *read_proc; write_proc_t *write_proc; atomic_t count; /* use count */ int deleted; /* delete flag */ kdev_t rdev; }; 在这个结构中,描述了一个proc文件的全部信息,每一个proc文件正是使用proc_dir_entry结构来表示的。下面我们看一下它最重要的几个域: low_ino:这是用来唯一标志proc_dir_entry结构的节点号,也就是proc文件系统内的索引节点的标号,除了根结点,其他的节点号都是在创建proc_dir_entry的时候,由make_inode_number()动态创建的。 name:即这个proc文件的名字。 mode:该proc文件的模式由两部分用位或运算组成,第一部分是文件的类型,可以参考include/linux/stat.h中的定义,比 如,S_IFREG表示普通文件,而S_IFDIR表示目录文件。第二部分是该文件的权限,同样可以参考include/linux/stat.h中的定 义,比如,S_IRUSR表示该文件能够被拥有者读,S_IROTH 表示该文件可以被其他人读取。但真正的权限检查,我们可以放到后面提到的inode_operations结构中。 size:即我们使用“ls”命令时,所显示出的文件大小。 proc_iops:这是一个inode_operations结构,其中设置了针对这个proc索引节点的操作函数,这样,我们就可以针对不同类型的 proc文件,提供不同的方法,以完成不同的工作。比如我们上面提到的对proc文件的权限检查,就可以放在这个结构中。 proc_fops:这是一个file_operations结构,其中放置了针对这个proc文件的操作函数,我们可以把对proc文件的读写操作,放在这个结构中,用以实现对/proc目录中的文件的读,写功能。 get_info:当用户向proc文件读取的数据小于一个页面大小时,可以使用这个函数向用户返回数据。 struct proc_dir_entry *next, *parent, *subdir:使用这些链表,在内存中,proc_dir_entry结构就以树的形式链接在一起。 read_proc_t *read_proc 和write_proc_t *write_proc:这两个函数提供了对proc文件进行操作的简单接口。我们知道,对于proc文件,我们可以从中读取核心数据,还可以向其中写入 数据,因此,对于一些功能比较简单的proc文件,我们只要实现这两个函数(或其中之一)即可,而不用设inode_operations结构,这样, 整个操作比较简单。实际上,我们会在后面的分析中看到,在注册proc文件的时候,会自动为proc_fops设置一个缺省的 file_operations结构,如果我们只实现了上面提到的两个读写操作,而没有设置自己file_operations结构,那么,会由缺省的 inode_operations结构中的读写函数检查调用这两个函数。 atomic_t count:该结构的使用计数。当一个proc_dir_entry结构的count减为零时,会释放该结构,这种结果就像把一个ext2文件系统的文件从磁盘上删除掉一样。 int deleted:这是一个删除标志,当我们调用remove_proc_entry函数要删除一个proc_dir_entry时,如果发现该结构还在使用,就会设置该标志并且推出。 2 建立proc文件 在了解了proc_dir_entry结构之后,我们来看一看proc文件系统是如何管理自己的文件结构的。 首先我们看一看它是如何创建proc文件的,参考文件fs/proc/generic.c,其中,有一个函数create_proc_entry,由它创建并注册proc文件,下面我们看一下它的源码: struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { struct proc_dir_entry *ent = NULL; const char *fn = name; int len; if (!parent && xlate_proc_name(name, &parent, &fn) != 0) goto out; len = strlen(fn); ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); if (!ent) goto out; memset(ent, 0, sizeof(struct proc_dir_entry)); memcpy(((char *) ent) + sizeof(*ent), fn, len + 1); ent->name = ((char *) ent) + sizeof(*ent); ent->namelen = len; if (S_ISDIR(mode)) { if ((mode & S_IALLUGO) == 0) mode |= S_IRUGO | S_IXUGO; ent->proc_fops = &proc_dir_operations; ent->proc_iops = &proc_dir_inode_operations; ent->nlink = 2; } else { if ((mode & S_IFMT) == 0) mode |= S_IFREG; if ((mode & S_IALLUGO) == 0) mode |= S_IRUGO; ent->nlink = 1; } ent->mode = mode; proc_register(parent, ent); /* link ent to parent */ out: return ent; } 我们看到,首先,该函数会做一些必要的检查,比如要确保它的父节点必须存在等等。其次会创建一个proc_dir_entry结构,并且为该文件 的名字也分配空间,并用->name指向它。再次,会根据该文件的类型,设置适当的模式和链接数。最后,会调用proc_register (parent, ent)函数,将这个结构链接到proc文件树中。 下面我们看一下它的实现代码: static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) { int i; i = make_inode_number(); if (i < 0) return -EAGAIN; dp->low_ino = i; dp->next = dir->subdir; dp->parent = dir; dir->subdir = dp; if (S_ISDIR(dp->mode)) { if (dp->proc_iops == NULL) { dp->proc_fops = &proc_dir_operations; dp->proc_iops = &proc_dir_inode_operations; } dir->nlink++; } else if (S_ISLNK(dp->mode)) { if (dp->proc_iops == NULL) dp->proc_iops = &proc_link_inode_operations; } else if (S_ISREG(dp->mode)) { if (dp->proc_fops == NULL) dp->proc_fops = &proc_file_operations; } return 0; } 这个函数主要完成三部分的工作,第一,使用make_inode_number()函数动态的到一个节点号,并且设置low_ino。第二步,将 这个proc_dir_entry结构链接到它的父节点上。第三步,根据文件类型的不同,设置不同的(索引节点和文件)缺省操作函数集。 这样,一个proc文件就注册成功了。 3 删除proc文件 在同一源文件中,提供了删除proc_dir_entry结构的函数,即remove_proc_entry,下面我们分析一下它的实现过程。 void remove_proc_entry(const char *name, struct proc_dir_entry *parent) { struct proc_dir_entry **p; struct proc_dir_entry *de; const char *fn = name; int len; if (!parent && xlate_proc_name(name, &parent, &fn) != 0) goto out; len = strlen(fn); for (p = &parent->subdir; *p; p=&(*p)->next ) { if (!proc_match(len, fn, *p)) continue; de = *p; *p = de->next; de->next = NULL; if (S_ISDIR(de->mode)) parent->nlink--; clear_bit(de->low_ino-PROC_DYNAMIC_FIRST, (void *) proc_alloc_map); proc_kill_inodes(de); de->nlink = 0; if (!atomic_read(&de->count)) free_proc_entry(de); else { de->deleted = 1; printk("remove_proc_entry: %s/%s busy, count=%d\n", parent->name, de->name, atomic_read(&de->count)); } break; } out: return; } 该函数在参数parent的所有孩子中查找指定的名字,如果找到匹配的节点,即proc_match(len, fn, *p),那么,就将该结构从树结构中去掉。然后,如果删除的proc_dir_entry是目录结构,那么,就减少其父节点的链接数。 然后,调用clear_bit(de->low_ino-PROC_DYNAMIC_FIRST, (void *) proc_alloc_map)函数,清除该节点号。 最后,将该结构的链接数置零,并调用atomic_read(&de->count)来检查它的引用计数,如果是零,那么就使用函数free_proc_entry释放该节点,否则,就将它的删除标记位置一,在以后适当地机会中,再将其释放。 4 其他管理函数 除此之外,我们看到还有一些函数,可以方便我们管理和使用proc文件系统,我们简单地介绍一下: struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent)函数,这个函数用来在proc文件系统中注册一个子目录,根据它的参数,我们就可以看出它的功能。在这个函数里,将动态分配一个 proc_dir_entry结构以及它的名字,然后,设置目录文件的缺省操作(proc_iops以及proc_fops)以及nlink值,最后,调 用proc_register函数将其注册。 struct proc_dir_entry *proc_mknod(const char *name, mode_t mode, struct proc_dir_entry *parent, kdev_t rdev)函数,用来在proc文件系统中建立一个设备文件,因此,在创建proc_dir_entry结构后,没有设置缺省操作,而是使用-> rdev = rdev指定了设备。最后,调用proc_register函数将其注册。 struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent, const char *dest)函数,该函数创建了一个链接文件,使用->mode = S_IFLNK|S_IRUGO|S_IWUGO|S_IXUGO来标志,它和其他文件的建立很相似,只是,它将链接的目标文件名放在了-> data域中。最后,它同样调用proc_register函数将该结构注册。
阅读(616) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~