文件可以看做相对磁盘等存储设备的地址空间。内存设备抽象作做进程地址空间。
文件可以看做线性字节数组,每字节可以读取写入。(当然是被掩盖了的)
目录记录文件的位置,目录包括文件或者其他子目录,目录本身也是文件。
文件系统的重要任务就是分配和索引数据块。
虚拟文件系统就是为了将各种文件系统统一 然后抽象成一个通用的层 。
内核线程和后台守护进程被广泛用在分层内存的一些创新策略上,那么这些创建的一般流程是怎样的?
内核线程
内核线程其实是运行在内核地址空间中的进程,没有独立的地址空间,共享内核的地址空间。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;
}