<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>dwt&#039;s life - kernel</title>
<link>https://dwt.life/tag/kernel/</link>
<atom:link href="https://dwt.life/feed/tag/kernel/" rel="self" type="application/rss+xml" />
<language>zh-CN</language>
<description></description>
<lastBuildDate>Tue, 06 Jul 2021 09:12:52 +0800</lastBuildDate>
<pubDate>Tue, 06 Jul 2021 09:12:52 +0800</pubDate>
<item>
<title>openat与open的区别及用法示例（dfd）</title>
<link>https://dwt.life/archives/29/</link>
<guid>https://dwt.life/archives/29/</guid>
<pubDate>Tue, 06 Jul 2021 09:12:52 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[从2.6.16版本开始，GNU/Linux引入opeant系统调用：#define _XOPEN_SOURCE 700 /* Or define _POSIX_C_SOURCE &gt;= 20...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>从2.6.16版本开始，GNU/Linux引入opeant系统调用：</p><pre><code>#define _XOPEN_SOURCE 700 /* Or define _POSIX_C_SOURCE &gt;= 200809 */
#include &lt;fcntl.h&gt;
int openat(int  dirfd , const char * pathname , int  flags , ... /* mode_t  mode */);</code></pre><p>Returns file descriptor on success, or –1 on error<br>同open相比，多了一个dirfd参数。关于它的用法，参考以下解释：</p><blockquote><p>If pathname specifies a relative pathname, then it is interpreted<br>relative to the directory referred to by the open file descriptor<br>dirfd, rather than relative to the process’s current working<br>directory.</p><p>If pathname specifies a relative pathname, and dirfd contains the<br>special value AT_FDCWD , then pathname is interpreted relative to the<br>process’s current working directory (i.e., the same behavior as<br>open(2)).</p><p>If pathname specifies an absolute pathname, then dirfd is ignored.</p></blockquote><p>总结起来，如果pathname是绝对路径，则dirfd参数没用。如果pathname是相对路径，并且dirfd的值不是AT_FDCWD，则pathname的参照物是相对于dirfd指向的目录，而不是进程的当前工作目录；反之，如果dirfd的值是AT_FDCWD，pathname则是相对于进程当前工作目录的相对路径，此时等同于open。参考kernel代码则一目了然：</p><p>引入openat（及其它at结尾的函数）有以下两个原因：</p><blockquote><p>First, openat() allows an application to avoid race conditions that<br>could occur when using open(2) to open files in directories other than<br>the current working directory. These race conditions result from the<br>fact that some component of the directory prefix given to open(2)<br>could be changed in parallel with the call to open(2). Such races can<br>be avoided by opening a file descriptor for the target directory, and<br>then specifying that file descriptor as the dirfd argument of<br>openat().</p><p>Second, openat() allows the implementation of a per-thread “current<br>working directory”, via file descriptor(s) maintained by the<br>application. (This functionality can also be obtained by tricks based<br>on the use of /proc/self/fd/dirfd, but less efficiently.)</p></blockquote><p>引入openat是方便一个进程内的各线程可拥有不同的当前目录，传统的chdir会影响整个进程，而使用openat只需要每个线程在初始化时打开一个目录(调用open)，然后就可以以openat在“当前目录”操作文件了，如：</p><pre><code>int dirfd = open(&quot;/tmp&quot;); // 相当于chdir到“/tmp”
int filefd = openat(dirfd, &quot;myfile&quot;); // 在/tmp目录下打开“myfile”文件 </code></pre><p>用法示例：</p><pre><code>#include &lt;stdio.h&gt;  
#include &lt;sys/stat.h&gt;  
#include &lt;fcntl.h&gt;  
#include &lt;stdlib.h&gt;  
#include &lt;unistd.h&gt;  
  
void creat_at(char *dir_path, char *relative_path)  
{  
    int dir_fd;  
    int fd;  
    int flags;  
    mode_t mode;  
  
    dir_fd = open(dir_path, O_RDONLY);  //fd参数是通过打开相对路径名所在的目录来获取。
    if (dir_fd &lt; 0)   
    {  
        perror(&quot;open&quot;);  
        exit(EXIT_FAILURE);  
    }  
  
    flags = O_CREAT | O_TRUNC | O_RDWR;  
    mode = 0640;  //-rw-r-----
    fd = openat(dir_fd, relative_path, flags, mode);  
    if (fd &lt; 0)   
    {  
        perror(&quot;openat&quot;);  
        exit(EXIT_FAILURE);  
    }  
  
    write(fd, &quot;HELLO&quot;, 5);  
  
    close(fd);  
    close(dir_fd);  
}  
  
int main()  
{  
    creat_at(&quot;../03.文件IO&quot;, &quot;log.txt&quot;);  
    return 0;  
}</code></pre><p>借用dirfd，将DIR*转换成int类型的文件描述符</p><pre><code>#include &lt;sys/types.h&gt;  
#include &lt;sys/stat.h&gt;  
#include &lt;fcntl.h&gt;  
#include &lt;dirent.h&gt;  
#include &lt;stdio.h&gt;  
#include &lt;unistd.h&gt;  
  
int main()  
{  
    DIR *dir;  
    int dirfd2;  
    int fd;  
    int n;  
  
    dir = opendir(&quot;../03.文件IO&quot;);  
    if(NULL == dir)  
    {  
        perror(&quot;open dir error&quot;);  
        return -1;  
    }  
    dirfd2 = dirfd(dir);  
    if(-1 == dirfd2)  
    {  
        perror(&quot;dirfd error&quot;);  
        return -1;  
    }  
  
    fd = openat(dirfd2,&quot;output.log&quot;,O_CREAT|O_RDWR|O_TRUNC, \
　　　　　　　　　　　　　　　　　　　　　　S_IRWXU|S_IRWXG|S_IRWXO);  
    if(-1 == fd)  
    {  
        perror(&quot;opeat error&quot;);  
        return -1;  
    }  
    n = write(fd,&quot;Hello world!\n&quot;,15);  
      
    close(fd);  
    closedir(dir);  
  
    return 0;  
  
}</code></pre>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://dwt.life/archives/29/#comments</comments>
<wfw:commentRss>https://dwt.life/feed/tag/kernel/</wfw:commentRss>
</item>
<item>
<title>郵件回復歸檔：關於Linux Kernel不同版本存在的模塊開發問題</title>
<link>https://dwt.life/archives/28/</link>
<guid>https://dwt.life/archives/28/</guid>
<pubDate>Mon, 05 Jul 2021 14:14:02 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[來自https://szlin.me/的博主的郵件解答，其中第一點有不小的作用。Hi Rick,一般而言, 遇到這種改版造成行為改變的議題, 我常用以下兩種方法.找出並定位改變的 kernel ...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>來自<a href="https://szlin.me/">https://szlin.me/</a>的博主的郵件解答，其中第一點有不小的作用。</p><blockquote><p>Hi Rick,</p><p>一般而言, 遇到這種改版造成行為改變的議題, 我常用以下兩種方法.</p><ol><li>找出並定位改變的 kernel 版本 - 使用 git blame + bisect 來找出 function argument or content 的差異, 並詳細閱讀 commit log, 大概就會有手感.</li></ol><p>如果找到並閱讀完 commit log 還是沒有頭緒, 可試試</p><ol start="2"><li>透過 grep 關鍵字, 找出其他也有使用該 function 的檔案, 了解它們在新版的使用方法. 並可搭配 git blame 來看如何這些檔案如何從舊版移植到新版</li></ol><p>以上行為也可以搭配 kernel documentation 來閱讀, 雖然有時候文件會跟不上 code 進版速度.</p><p>最後, 若公司允許, 建議把 driver 進行 upstream, 推入 Linux kernel mainline 中.<br>這樣一來就不會有因為 kernel 進版而導致錯誤, 因為 Linux kernel 本身進板時, maintainer 就會處理了.</p><p>以上, 希望對你有所幫助.</p><p>SZ</p></blockquote>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://dwt.life/archives/28/#comments</comments>
<wfw:commentRss>https://dwt.life/feed/tag/kernel/</wfw:commentRss>
</item>
<item>
<title>Centos对应内核版本</title>
<link>https://dwt.life/archives/25/</link>
<guid>https://dwt.life/archives/25/</guid>
<pubDate>Sun, 04 Jul 2021 01:12:11 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[https://en.wikipedia.org/wiki/CentOS#CentOS_version_7]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p><a href="https://en.wikipedia.org/wiki/CentOS#CentOS_version_7">https://en.wikipedia.org/wiki/CentOS#CentOS_version_7</a></p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://dwt.life/archives/25/#comments</comments>
<wfw:commentRss>https://dwt.life/feed/tag/kernel/</wfw:commentRss>
</item>
<item>
<title>linux4.17后重写sys_call_table函数参数无法获得的解决方法</title>
<link>https://dwt.life/archives/23/</link>
<guid>https://dwt.life/archives/23/</guid>
<pubDate>Sat, 03 Jul 2021 17:25:00 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[从社区中得到了一个解决方案：System call hooking example arguments are incorrect然后搜索这个得到了这篇文章其中，参数以const struct ...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>从社区中得到了一个解决方案：<a href="https://stackoverflow.com/questions/59851520/system-call-hooking-example-arguments-are-incorrect">System call hooking example arguments are incorrect</a></p><p>然后搜索这个得到了<a href="https://blog.csdn.net/weixin_42915431/article/details/105622584">这篇文章</a></p><p>其中，参数以const struct pt_regs *regs的形式存储，<br>第一个参数dfd在regs-&gt;di中<br>第二个参数filename在regs-&gt;si中<br>第三个参数flags在regs-&gt;dx中<br>第四个参数mode在regs-&gt;r10中<br>获取之后再对其进行类型转换即可。</p><p>主要是kernel4.17后对参数的获取做了修改，但是即使定义的函数没有hook上也不会影响正常使用的意思。</p><p>花了两天时间自己没解决，求助社区半天不到就解决了。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://dwt.life/archives/23/#comments</comments>
<wfw:commentRss>https://dwt.life/feed/tag/kernel/</wfw:commentRss>
</item>
<item>
<title>linux 内核函数 filp_open、filp_read、IS_ERR、ERR_PTR、PTR_ERR 简介</title>
<link>https://dwt.life/archives/22/</link>
<guid>https://dwt.life/archives/22/</guid>
<pubDate>Fri, 02 Jul 2021 11:41:00 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[内核态文件操作在用户态，我们操作文件可以用C库函数：open()、read()、write()等，但是在内核态没有库函数可用，这时就需要用内核的一些函数：filp_open、filp_close...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>内核态文件操作<br>在用户态，我们操作文件可以用C库函数：open()、read()、write()等，但是在内核态没有库函数可用，这时就需要用内核的一些函数：<code>filp_open</code>、<code>filp_close</code>、<code>vfs_read</code>、<code>vfs_write</code>、<code>set_fs</code>、<code>get_fs</code>等函数，</p><p>在下列文件中声明：</p><pre><code class="lang-c">/usr/lib/modules/3.10.0-514.el7.x86_64/build/include/linux/fs.h

/usr/lib/modules/3.10.0-514.el7.x86_64/build/include/asm-generic/uaccess.h

/usr/src/kernels/3.10.0-514.el7.x86_64/include/linux/err.h</code></pre><h2>filp_open</h2><p><code>extern struct file *filp_open(const char *, int, umode_t);</code></p><p>参数说明：</p><p>第一个参数表明要打开或创建文件的名称(包括路径部分)。</p><p>第二个参数文件的打开方式，其取值与标准库中的open相应参数类似，可以取O_CREAT,O_RDWR,O_RDONLY等。</p><p>第三个参数创建文件时使用，设置创建文件的读写权限，其它情况可以设为0</p><p>该函数返回strcut file*结构指针，供后继函数操作使用，该返回值用IS_ERR()来检验其有效性。</p><h2>filp_close</h2><p><code>extern int filp_close(struct file *, fl_owner_t id);</code></p><p>参数说明：</p><p>第一个参数是filp_open返回的file结构体指针</p><p>第二个参数基本上都是NULL</p><h2>vfs_read/write</h2><p><code>extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);</code><br><code>extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);</code></p><p>参数说明：</p><p>第一个参数是filp_open返回的file结构体指针</p><p>第二个参数是buf，注意，这个参数有用__user修饰，表明buf指向用户空间的地址，如果传入内核空间的地址，就会报错，并返回-EFAULT，</p><p>但在kernel中，要使这两个读写函数使用kernel空间的buf指针也能正确工作，需要使用set_fs()</p><h2>set_fs</h2><p><code>static inline void set_fs(mm_segment_t fs)</code></p><p>该函数的作用是改变kernel对内存地址检查的处理方式，</p><p>其实该函数的参数fs只有两个取值：USER_DS，KERNEL_DS，分别代表用户空间和内核空间，</p><p>默认情况下，kernel取值为USER_DS，即对用户空间地址检查并做变换。</p><p>那么要在这种对内存地址做检查变换的函数中使用内核空间地址，就需要使用set_fs(KERNEL_DS)进行设置，</p><p>它的作用是取得当前的设置，这两个函数的一般用法为：</p><pre><code class="lang-c">filp_open()
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
...... //与内存有关的操作
set_fs(old_fs);
filp_close</code></pre><p>第三个参数表明文件要读写的起始位置。</p><p>几点说明：（从网上查找的资料）</p><p>Linux Kernel组成员不赞成在kernel中独立的读写文件(这样做可能会影响到策略和安全问题)，对内核需要操作的文件内容，最好由应用层配合完成。</p><p>这些函数的正确运行需要依赖于进程环境，因此,有些函数不能在中断的handle或Kernel中不属于任何进程的代码中执行，否则可能出现崩溃，要避免这种情况发生，可以在kernel中创建内核线程，将这些函数放在线程环境下执行。</p><pre><code class="lang-c">
#ifndef _LINUX_ERR_H
#define _LINUX_ERR_H
#include &lt;linux/compiler.h&gt;
#include &lt;asm/errno.h&gt;
/*
 * Kernel pointers have redundant information, so we can use a
 * scheme where we can return either an error code or a dentry
 * pointer with the same return value.
 *
 * This should be a per-architecture thing, to allow different
 * error and pointer decisions.
 */
#define MAX_ERRNO       4095
 
#ifndef __ASSEMBLY__
 
#define IS_ERR_VALUE(x) unlikely((x) &gt;= (unsigned long)-MAX_ERRNO)
 
static inline void * __must_check ERR_PTR(long error)
{
        return (void *) error;
}

static inline long __must_check PTR_ERR(const void *ptr)
{
        return (long) ptr;
}
 
static inline long __must_check IS_ERR(const void *ptr)
{
        return IS_ERR_VALUE((unsigned long)ptr);
}
 
static inline long __must_check IS_ERR_OR_NULL(const void *ptr)
{
        return !ptr || IS_ERR_VALUE((unsigned long)ptr);
}</code></pre><p>内核中的函数常常返回指针，问题是如果出错，也希望能够通过返回的指针体现出来。</p><p>总体来说，如果内核返回一个指针，那么有三种情况：合法指针，NULL指针和非法指针。</p><p>在linux中有很多错误，内核错误可以参考include/asm-generic/errno-base.h。</p><p>MAX_ERRNO定义了最大的错误号4095，刚好是4k-1，所以内核地址保留了0xfffffffffffff000~0xffffffffffffffff（64位系统）用来记录错误号，也就是说这段地址和Linux的错误号是一一对应的，可以用上面的内联函数相互转化。</p><p>比如说我们上面的filp_open函数返回值，用IS_ERR函数去检查，如果地址落在0xfffffffffffff000~0xffffffffffffffff范围，</p><p>表示filp_open函数失败，IS_ERR为1，同时filp_open返回的错误地址对应一个linux的错误号，</p><p>如果想知道是哪个错误号，就用PTR_ERR函数来转化。</p><p>错误的返回地址和错误号是可以使用 ERR_PTR、PTR_ERR 相互转化的。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://dwt.life/archives/22/#comments</comments>
<wfw:commentRss>https://dwt.life/feed/tag/kernel/</wfw:commentRss>
</item>
<item>
<title>yum 安装对应内核版本的kernel-devel</title>
<link>https://dwt.life/archives/19/</link>
<guid>https://dwt.life/archives/19/</guid>
<pubDate>Thu, 01 Jul 2021 00:22:02 +0800</pubDate>
<dc:creator>Ricky</dc:creator>
<description><![CDATA[uname -r 查看内核版本查看已安装kernel-develuname -a ; rpm -qa kernel\* | sort下载对应版本sudo yum install &quot;ke...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<ol><li>uname -r 查看内核版本</li><li>查看已安装kernel-devel<br><code>uname -a ; rpm -qa kernel\* | sort</code></li><li>下载对应版本<br><code>sudo yum install &quot;kernel-devel-uname-r == $(uname -r)&quot;</code><br>完成后在/usr/src/kernels/下生成对应版本的源码</li></ol>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://dwt.life/archives/19/#comments</comments>
<wfw:commentRss>https://dwt.life/feed/tag/kernel/</wfw:commentRss>
</item>
</channel>
</rss>