通常我们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


/* This file is auto generated, version 22 */
/* SMP PREEMPT */
#define UTS_MACHINE "arm"
#define UTS_VERSION "#22 SMP PREEMPT Thu Nov 15 19:00:10 CST 2018"
#define LINUX_COMPILE_BY "ljs"
#define LINUX_COMPILE_HOST "ea-server"
#define LINUX_COMPILER "gcc version 4.9 20150123 (prerelease) (GCC) "

那么问题又来了,compile.h是有谁生成的呢?
在scripts/mkcompile_h脚本中。

参考自

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐