日志标签 ‘内核编程’

Linux内核中通过文件描述符获取绝对路径

2014年3月19日

背景

在Linux内核中,已知一个进程的pid和其打开文件的文件描述符fd,如何获取该文件的绝对路径?基本思路是先获取该文件在内核中的file结构体,再通过d_path()获取到整个文件的绝对路径。

方法一

如果理解了进程和文件系统数据结构之间的关系,那么这种方法可以采用。基本的方法如下:

1.通过进程pid获取进程描述符task_struct;

2.通过task_struct获取该进程打开文件结构files_struct,从而获取文件描述符表;

3.以fd为索引在文件描述符表中获取对应文件的结构体file;

4.通过file获取对应path结构,该结构封装当前文件对应的dentry和挂载点;

5.通过内核函数d_path()获取该文件的绝对路径;

通过进程pid获取进程描述符demo:

struct task_struct *get_proc(pid_t pid)
{
	struct pid *pid_struct = NULL;
	struct task_struct *mytask = NULL;

	pid_struct = find_get_pid(pid);
	if (!pid_struct)
		return NULL;
	mytask = pid_task(pid_struct, PIDTYPE_PID);
	return mytask;
}

通过fd以及d_path()获取绝对路径demo:

int get_path(struct task_struct *mytask, int fd)
{
        struct file *myfile = NULL;
        struct files_struct *files = NULL;
        char path[100] = {'\0'};
        char *ppath = path;

        files = mytask->files;
        if (!files) {
                printk("files is null..\n");
                return -1;
        }
        myfile = files->fdt->fd[fd];
        if (!myfile) {
                printk("myfile is null..\n");
                return -1;
        }
        ppath = d_path(&(myfile->f_path), ppath, 100);

        printk("path:%s\n", ppath);
        return 0;
}

从上面的代码可以看出,从fd到file结构的获取均通过各个数据结构之间的指向关系获取。

方法二

与方法一的思路相同,但是可以直接使用内核提供的函数fget()进行fd到file的获取。这种方法使用比较简单,程序更加安全,不过就是少了对数据结构关系的思考过程。其实也可以将fget()函数的实现过程作为参考,欣赏内核中代码实现的严谨性。

 

inotify机制在内核态下的使用方法

2011年10月5日

inotify是一种使用简单而功能强大的文件系统事件监控机制。在用户态下通过一组简单的系统调用即可使用inotify机制监控文件的变化,而在内核态中也可以通过一组API来inotify机制。

1.创建并初始化inotify实例

为了在内核中使用inotify机制,必须首先创建并初始化一个inotify实例,每个inotify实例其实对应的是一个数据结构inotify_handle。

struct inotify_handle {
	struct idr		idr;		/* idr mapping wd -> watch */
	struct mutex		mutex;		/* protects this bad boy */
	struct list_head	watches;	/* list of watches */
	atomic_t		count;		/* reference count */
	u32			last_wd;	/* the last wd allocated */
	const struct inotify_operations *in_ops; /* inotify caller operations */
};

创建并初始化一个inotify实例的过程其实就是分配并初始化一个inotify_handle结构,这个过程通过inotify_init()完成。此外,每个inotify实例都与一个inotify_operations结构相关联,该结构中有两个钩子函数,分别定义了事件处理和销毁watch两个函数的接口,这两个钩子函数应该根据具体的应用场景来实现。

struct inotify_operations {
	void (*handle_event)(struct inotify_watch *, u32, u32, u32,
			     const char *, struct inode *);
	void (*destroy_watch)(struct inotify_watch *);
};

一个inotify_init()通用的使用方法如下:

struct inotify_operations *ops;
ops->handle_event = my_handle_event;
ops->destroy_watch = my_destroy_watch;
struct inotify_handle *ih = inotify_init(ops);

也就是说,通过向inotify_init()中传入一个inotify_operations结构的变量来实现钩子函数和inotify实例之间的关联。

2.添加watch

从inotify实例所对应的数据结构inotify_handle中可以看出,每个inotify实例都拥有一个由watch组成的链表。该双链表上的每个watch即代表该inotify实例所监控的对象,这个对象可能是文件,也可能是目录。每个watch在内核中的表示如下:

struct inotify_watch {
	struct list_head	h_list;	/* entry in inotify_handle's list */
	struct list_head	i_list;	/* entry in inode's list */
	atomic_t		count;	/* reference count */
	struct inotify_handle	*ih;	/* associated inotify handle */
	struct inode		*inode;	/* associated inode */
	__s32			wd;	/* watch descriptor */
	__u32			mask;	/* event mask for this watch */
};

该结构中每个字段的含义如下:

h_list:一个inotify实例中所有watch组成一个双链表,h_list表示当前watch在该双链表中所处的结点。该双链表的表头即为inotify_handle结构中的watches字段。

i_list:一个文件可能被多个inotify实例监控,而被监控一次就产生一个watch,该文件对应的所有watch组成一个双链表,i_list表示当前watch在该双链表中所处的结点。该双链表的表头即为inode结构中的inotify_watches字段。

count:表示该watch被引用的次数。

ih:每个watch必然属于某个inotify实例,该字段指向当前watch所属的inotify_handle结构。

inode:该字段指向当前watch所关联的文件的inode。

wd:表示当前watch的文件描述符。

mask:表示当前监控对象所对应的事件掩码。

当初始化完一个inotify实例后,通过inotify_add_watch()即可向该实例中添加watch。不过在添加前还需通过inotify_init_watch()对每个watch进行初始化。

对watch初始化完成的主要工作即初始化两个链表结点、该watch的引用计数等。向inotify实例添加一个watch主要完成的工作即为向两个watch链表中添加当前的watch结点,并且更新watch的引用计数等。

3.删除一个watch

从指定的inotify实例中删除一个watch所完成的工作其实和添加watch的过程相反,通过inotify_rm_watch()即可完成。

4.对监控事件的处理

handle_event()通常并不对具体的监控对象做处理,而是作为所有监控事件的入口点;接着根据每个事件的掩码做出“分流”动作,即对具体的监控事件做以处理。

使用list_head建立双联表

2011年5月24日

内核中与链表有关的操作都集中在list.h文件中,该文件不仅定义了链表数据结构,而且包含大量对链表操作的函数。

下面通过一个内核模块简单说明内核双链表的用法。该内核模块的加载函数首先建立了一个具有N个节点的双链表,然后再遍历该链表;在该内核模块卸载函数中,依次将每个节点从双链表中删除,并释放每个节点所占用的内核空间的内存。

在具体说明该程序之前,有必要搞清楚两个概念:链表中的数据节点和链表节点。内核在list.h中定义的链表节点list_head称之为链表节点。该结构除了指向前后节点的指针外,并不包含任何数据变量。因此,在实际使用的过程中,我们必须将所需数据和链表节点封装在一个数据结构中,这个新的数据结构就是数据节点。比如,在示例程序中,我们的数据节点除了包含链表节点外,还包含一个数据成员num。

#define N 10
//链表节点
struct numlist {
	int num;//数据
	struct list_head list;//指向双联表前后节点的指针
};
struct numlist numhead;//头节点

在使用双联表的操作函数时也应该注意数据节点和链表节点之间的差异。所有与双联表有关的操作函数都是对链表节点的操作,也就是说我们应该对这些函数传入链表节点(或指针)而不是数据节点。

在加载函数中,我们通过INIT_LIST_HEAD宏初始化链表的头指针。通过查看该宏的定义可知,必须向其传入一个list_head结构的指针变量,因此我们将&numhead.list传入其中。

接着,通过循环分别创建N个数据节点,并在创建完每个节点后,将其加入整个双链表中。将节点加入双链表的过程是通过list_add_tail函数完成的,该函数将新节点加入到双链表的末尾。

static int __init doublelist_init(void)
{
	//初始化头节点
	struct numlist *listnode;//每次申请链表节点时所用的指针
	struct list_head *pos;
	struct numlist *p;
	int i;

	printk("doublelist is starting...\n");
	INIT_LIST_HEAD(&numhead.list);

	//建立N个节点,依次加入到链表当中
		for (i = 0; i < N; i++) {
		listnode = (struct numlist *)kmalloc(sizeof(struct numlist), GFP_KERNEL);
		listnode->num = i+1;
		list_add_tail(&listnode->list, &numhead.list);
		printk("Node %d has added to the doublelist...\n", i+1);
	}

加载函数创建完双链表后,紧接着又对该双链表进行了遍历操作。我们在上面说过双链表的操作函数是对链表节点list_head进行操作的,因此遍历宏list_for_each也是对链表节点的遍历。如果我们需要得到数据节点中每个成员的值,那么就必须获得当前数据节点的指针,也就是该节点的首地址。因此list_entry宏的作用就是通过当前正在遍历的链表节点的指针pos获得其所属数据节点的指针p。

这里特别说明一下list_entry宏的参数,pos所指向的list_head结构在numlist结构中的字段称为list。

	//遍历链表
	i = 1;
	list_for_each(pos, &numhead.list) {
		p = list_entry(pos, struct numlist, list);
		printk("Node %d's data:%d\n", i, p->num);
		i++;
	}

	return 0;
}

在卸载函数中将会依次删除链表中的节点。list_for_each_safe遍历宏是专门为删除链表结点而设计的,它在遍历当前节点对同时保存下一个节点的地址。因此在每次遍历的时候一方面使用list_del将当前链表节点从整个链表中删除,一方面使用kfree函数释放该数据节点所占的内存空间。

static void __exit doublelist_exit(void)
{
	struct list_head *pos, *n;
	struct numlist *p;
	int i;

	//依次删除N个节点
	i = 1;
	list_for_each_safe(pos, n, &numhead.list) {
		list_del(pos);//从双联表中删除当前节点
		p = list_entry(pos, struct numlist, list);//得到当前数据节点的首地址,即指针
		kfree(p);//释放该数据节点所占空间
		printk("Node %d has removed from the doublelist...\n", i++);
	}
	printk("doublelist is exiting..\n");
}

该实例程序的完整代码可在此下载。

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key