文件可以看做相对磁盘等存储设备的地址空间。内存设备抽象作做进程地址空间。

文件可以看做线性字节数组,每字节可以读取写入。(当然是被掩盖了的)

目录记录文件的位置,目录包括文件或者其他子目录,目录本身也是文件。

文件系统的重要任务就是分配和索引数据块。

虚拟文件系统就是为了将各种文件系统统一 然后抽象成一个通用的层 。


内核线程和后台守护进程被广泛用在分层内存的一些创新策略上,那么这些创建的一般流程是怎样的?

内核线程

内核线程其实是运行在内核地址空间中的进程,没有独立的地址空间,共享内核的地址空间。Linux内核其实没有专门的线程,线程都当作普通的进程。task_struct->mm == NULL

Linux内核有多个函数接口创建内核线程,kthread_create()新创建的不能运行,还需要手动调用wake_up_process唤醒进程加入就绪队列。kthread_run()创建的马上就能直接运行。

下面这个模块,每个CPU一个内核线程,输出当前CPU状态,以及当前进程的优先级等信息。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/delay.h>

static struct task_struct *tsk[NR_CPUS];

static void show_reg(void)
{
	unsigned int spsr, sp, el;
	
	asm("mrs %0, spsr_el1" : "=r" (spsr) : : "cc");
	asm("mov %0, sp" : "=r" (sp) : : "cc");
	asm("mrs %0, CurrentEL" : "=r" (el) : : "cc");

	printk("spsr:0x%x, sp:0x%x, el=%d\n", spsr, sp, el >> 2);
}

static void show_prio(void)
{
	struct task_struct *task = current;

	printk("%s pid:%d, nice:%d prio:%d static_prio:%d normal_prio:%d\n",
			task->comm, task->pid,
			PRIO_TO_NICE(task->static_prio),
			task->prio, task->static_prio,
			task->normal_prio);
}

static void print_cpu(char *s)
{
	preempt_disable();
	pr_info("%s cpu=%d.\n", s, smp_processor_id());
	preempt_enable();
}

static int thread_fun(void *t)
{
	do {
		print_cpu("SLEEP in Thread Function ");
		msleep_interruptible(2000);
		print_cpu("msleep over in Thread Function");
		print_cpu("running");
		show_reg();
		show_prio();
	} while (!kthread_should_stop());
	return 0;
}

//入口
static int __init my_init(void)
{
	int i;
	print_cpu("Loading module");
	for_each_online_cpu(i) {
		tsk[i] = kthread_create(thread_fun, NULL, "kdemo/%d", i);
		if (!tsk[i]) {
			pr_info("Failed to generate a kernel thread\n");
			return -1;
		}
		kthread_bind(tsk[i], i);
		pr_info("About to wake up and run the thread for cpu=%d\n", i);
		wake_up_process(tsk[i]);
		pr_info("Staring thread for cpu %d", i);
		print_cpu("on");
	}
	return 0;
}

static void __exit my_exit(void)
{
	int i;
	for_each_online_cpu(i) {
		pr_info(" Kill Thread %d", i);
		kthread_stop(tsk[i]);
		print_cpu("Kill was done on ");
	}
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("Ben ShuShu");
MODULE_LICENSE("GPL v2");

BASEINCLUDE ?= /lib/modules/`uname -r`/build

kthread_test-objs := kthread.o

obj-m	:=   kthread_test.o
all :
	$(MAKE) -C $(BASEINCLUDE) M=$(PWD) modules;

clean:
	$(MAKE) -C $(BASEINCLUDE) M=$(PWD) clean;
	rm -f *.ko;


后台守护进程

创建一个守护进程,每隔5s查看当前内核的日志中是否有Oops错误。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/klog.h>

#define FALLBACK_KLOG_BUF_SHIFT 17  /* CONFIG_LOG_BUF_SHIFT in kernel */
#define FALLBACK_KLOG_BUF_LEN   (1 << FALLBACK_KLOG_BUF_SHIFT)

#define KLOG_CLOSE         0
#define KLOG_OPEN          1
#define KLOG_READ          2
#define KLOG_READ_ALL      3
#define KLOG_READ_CLEAR    4
#define KLOG_CLEAR         5
#define KLOG_CONSOLE_OFF   6
#define KLOG_CONSOLE_ON    7
#define KLOG_CONSOLE_LEVEL 8
#define KLOG_SIZE_UNREAD   9
#define KLOG_SIZE_BUFFER   10

/* we use 'Linux version' string instead of Oops in this lab */
//#define OOPS_LOG  "Oops" 
#define OOPS_LOG  "Linux version" 

int save_kernel_log(char *buffer)
{
	char path[128];
	time_t t;
	struct tm *tm;
	int fd;

	t = time(0);
	tm = localtime(&t);

	snprintf(path, 128, "/mnt/%d.%d.%d.%d.%d.%d.log", tm->tm_year+1900,
			tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
			tm->tm_min, tm->tm_sec);
	printf("%s\n", path);
	
        fd = open(path, O_WRONLY|O_CREAT, 0644);
	if(fd == -1) {
		printf("open error\n");
		return -1;
	}
        write(fd, buffer, strlen(buffer));
        close(fd);

	return 0;
}

int check_kernel_log()
{
	char *buffer;
	char *p;
	ssize_t klog_size;
	int ret = -1;
	int size;

	printf("start kernel log\n");

	klog_size = klogctl(KLOG_SIZE_BUFFER, 0, 0);
	if (klog_size <= 0) {
		klog_size = FALLBACK_KLOG_BUF_LEN;
	}

	printf("kernel log size: %d\n", klog_size);

	buffer = malloc(klog_size + 1);
	if (!buffer)
		return -1;

	size = klogctl(KLOG_READ_ALL, buffer, klog_size);
	if (size < 0) {
		printf("klogctl read error\n");
		goto done;
	}

	buffer[size] = '\0';

	/* check if oops in klog */
	p = strstr(buffer,OOPS_LOG);
	if (p) {
		printf("we found '%s' on kernel log\n", OOPS_LOG);
		save_kernel_log(buffer);
		ret = 0;
	} 
done:
	free(buffer);
	return ret;
}

int main(void)
{
	if(daemon(0,0) == -1) {
		printf("daemon error");
		return 0;
	}
	
	while(1) {
		check_kernel_log();
		
		sleep(5);
	}
	
	return 0;
}

文章作者: 易百分
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 易百分 !
  目录