/proc/version 的生成過程


/proc/version 的生成過程

通常我們cat /proc/version時,會顯示kernel相關的版本、編譯等信息

那么問題來了,這些信息是怎么生成的呢?

/proc/version文件是在kernel fs/proc/version.c 中生成

#include <linux/fs.h>                                               
#include <linux/init.h>                                             
#include <linux/kernel.h>                                           
#include <linux/proc_fs.h>                                          
#include <linux/seq_file.h>                                         
#include <linux/utsname.h>                                          
                                                                    
static int version_proc_show(struct seq_file *m, void *v)           
{                                                                   
    seq_printf(m, linux_proc_banner,    //linux_proc_banner()在init/version.c中定義
        utsname()->sysname,          //utsname()在include/linux/utsname.h中定義
        utsname()->release,                                         
        utsname()->version);                                        
    return 0;                                                       
}                                                                   
                                                                    
static int version_proc_open(struct inode *inode, struct file *file)
{                                                                   
    return single_open(file, version_proc_show, NULL);              
}                                                                   
                                                                    
static const struct file_operations version_proc_fops = {           
    .open       = version_proc_open,                                
    .read       = seq_read,                                         
    .llseek     = seq_lseek,                                        
    .release    = single_release,                                   
};                                                                  
                                                                    
static int __init proc_version_init(void)                           
{                                                                   
    proc_create("version", 0, NULL, &version_proc_fops);            
    return 0;                                                       
}                                                                   
module_init(proc_version_init);                                     

utsname()定義:

//include/linux/utsname.h
static inline struct new_utsname *utsname(void)
{
    return &current->nsproxy->uts_ns->name;
}

//current 是一個宏,表示當前進程的指針
//arch/arm/include/asm/current.h
#ifndef _ASMARM_CURRENT_H
#define _ASMARM_CURRENT_H

#include <linux/thread_info.h>

static inline struct task_struct *get_current(void) __attribute_const__;

static inline struct task_struct *get_current(void)
{
    return current_thread_info()->task;
}

#define current (get_current())

#endif /* _ASMARM_CURRENT_H */

//nsproxy, 是指kernel的namespace機制,關於機制,這里不展開。
//nsproxy 的初始化的定義在./kernel/nsproxy.c文件中
struct nsproxy init_nsproxy = {
    .count  = ATOMIC_INIT(1),
    .uts_ns = &init_uts_ns,
#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
    .ipc_ns = &init_ipc_ns,
#endif
    .mnt_ns = NULL,
    .pid_ns = &init_pid_ns,
#ifdef CONFIG_NET
    .net_ns = &init_net,
#endif
};

//該結構在task初始化的時候會被初始化,在include/linux/init_task.h文件中
#define INIT_TASK(tsk)  \
...
.nsproxy    = &init_nsproxy,                \
...

//init_nsprosy定義在init/version.c中
struct uts_namespace init_uts_ns = {
    .kref = {
        .refcount   = ATOMIC_INIT(2),
    },
    .name = {
        .sysname    = UTS_SYSNAME,
        .nodename   = UTS_NODENAME,
        .release    = UTS_RELEASE,
        .version    = UTS_VERSION,
        .machine    = UTS_MACHINE,
        .domainname = UTS_DOMAINNAME,
    },
    .user_ns = &init_user_ns,
};
EXPORT_SYMBOL_GPL(init_uts_ns);
//到這里&current->nsproxy->uts_ns->name的路徑就全部聯系起來了。

linux_proc_banner定義:

#include <generated/compile.h>
#include <linux/module.h>
#include <linux/uts.h>
#include <linux/utsname.h>
#include <generated/utsrelease.h>
#include <linux/version.h>

#ifndef CONFIG_KALLSYMS
#define version(a) Version_ ## a
#define version_string(a) version(a)

extern int version_string(LINUX_VERSION_CODE);
int version_string(LINUX_VERSION_CODE);
#endif

struct uts_namespace init_uts_ns = {
    .kref = {
        .refcount   = ATOMIC_INIT(2),
    },
    .name = {
        .sysname    = UTS_SYSNAME,
        .nodename   = UTS_NODENAME,
        .release    = UTS_RELEASE,
        .version    = UTS_VERSION,
        .machine    = UTS_MACHINE,
        .domainname = UTS_DOMAINNAME,
    },
    .user_ns = &init_user_ns,
};
EXPORT_SYMBOL_GPL(init_uts_ns);

/* FIXED STRINGS! Don't touch! */
const char linux_banner[] =
    "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
    LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";

const char linux_proc_banner[] =
    "%s version %s"
    " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
    " (" LINUX_COMPILER ") %s\n";

//那么,linux_proc_banner相當於
//	"UTS_SYSNAME version UTS_RELEASE"
//	" (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")"
//	" (" LINUX_COMPILER ") UTS_VERSION\n";

/*
* UTS_SYSNAME
* UTS_NODENAME
* UTS_RELEASE
* UTS_VERSION
* UTS_MACHINE
* UTS_DOMAINNAME
* LINUX_COMPILE_BY
* LINUX_COMPILE_HOST
* LINUX_COMPILER
* 這些宏都是在編譯kernel 是自動生成的。都放在include/generated/compile.h文件中
*/

include/generated/compile.h

#define UTS_MACHINE "arm"
#define UTS_VERSION "#3 SMP PREEMPT Tue Jul 31 12:04:09 CST 2018"
#define LINUX_COMPILE_BY "frank"
#define LINUX_COMPILE_HOST "ubuntu"
#define LINUX_COMPILER "gcc version 4.8.3 (OpenWrt/Linaro GCC 4.8-2014.04 unknown) "

那么問題又來了,compile.h是有誰生成的呢?

在scripts/mkcompile_h腳本中。


免責聲明!

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



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