Linux中的匿名inode是什么?

Linux中的匿名inode是什么?,linux,epoll,inode,Linux,Epoll,Inode,我在谷歌上搜索了“匿名inode”,它似乎和epoll有关。。。但实际上是什么呢?至少在某些上下文中,匿名inode是没有附加目录项的inode。创建这样一个inode的最简单方法如下: int fd = open( "/tmp/file", O_CREAT | O_RDWR, 0666 ); unlink( "/tmp/file" ); // Note that the descriptor fd now points to an inode that has no filesystem en

我在谷歌上搜索了“匿名inode”,它似乎和epoll有关。。。但实际上是什么呢?

至少在某些上下文中,匿名inode是没有附加目录项的inode。创建这样一个inode的最简单方法如下:

int fd = open( "/tmp/file", O_CREAT | O_RDWR, 0666 );
unlink( "/tmp/file" );
// Note that the descriptor fd now points to an inode that has no filesystem entry; you
// can still write to it, fstat() it, etc. but you can't find it in the filesystem.

O\u TMPFILE打开

这将是匿名inode的一个很好的定义:它在给定目录中创建一个没有任何名称的inode,它在
ls
中根本不会出现

然后,当您关闭描述符时,文件将被删除

它是在Linux3.11中添加的

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
    char buf[]  = { 'a', 'b', 'c', 'd' };
    char buf2[]  = { 'e', 'f', 'g', 'h' };
    int f, ret;
    size_t off;

    /* write */
    f = open(".", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
    ret = write(f, buf, sizeof(buf));

    /* Interactivelly check if anything changed on directory. It hasn't. */
    /*puts("hit enter to continue");*/
    /*getchar();*/

    /* read */
    lseek(f, 0, SEEK_SET);
    off = 0;
    while ((ret = read(f, buf2 + off, sizeof(buf) - off))) {
        off += ret;
    }
    close(f);
    assert(!memcmp(buf, buf2, sizeof(buf)));

    return EXIT_SUCCESS;
}
因此,这本质上是实现临时文件的最佳方式:因为它可以:

  • 始终立即找到一个免费名称,而无需我们循环文件名(不需要名称!)
  • 并自动删除
将其与目录的更手动的方法进行比较,如所示:

在Ubuntu 17.04、Linux 4.10和glibc 2.24中测试

/proc/PID/fd

我们可以通过以下方法快速检查:

#define _GNU_SOURCE
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
    int f = open(".", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
    struct stat s;
    fstat(f, &s);
    printf("pid %jd\n", (intmax_t)getpid());
    printf("inode %jd\n", (intmax_t)s.st_ino);
    getchar();
}
我们:

ls -l /proc/15952/fd
其中包括:

3 -> '/home/ciro/test/#44698689 (deleted)'
这向我们展示了如何查找给定进程的临时文件,并查看它们的
inode
和inode父目录

anon\u inode\u getfd
Linux内核函数

如果您处理的是内核模块,这可能是一个定义

你这样称呼它:

fd = anon_inode_getfd("random", &fops_anon, NULL, O_RDONLY | O_CLOEXEC);
并将
fd
返回给用户,例如从
ioctl
返回

现在用户有一个与任意
file\u操作相关联的
fd
inode
,当该
fd
关闭时,所有内容都被释放

此方法非常有用,例如,如果您希望有多个
read
系统调用,但不希望创建多个设备文件,这会进一步污染
/dev
:您只需创建额外的
ioctl
即可

QEMU Buildroot的最小可运行示例:


#include

请参阅接受的答案:不,它是磁盘上的数据,但该数据在文件系统中不再有可打开的条目——您只能在最后一个打开的文件描述符关闭之前使用该数据。一种情况下,您可能希望这样做,即当您需要一个临时文件时,您不希望任何人能够打开该文件;在UNIX中,mktemp()调用的许多用途实际上都是在不希望其他进程能够打开该文件的情况下,出于某种原因,您只需要一个临时文件。在本例中,您几乎肯定希望添加
O_EXCL
,并使模式为
0600
,而不是
0666
。。。目前至少存在两个主要的潜在漏洞(symlink vuln和race condition window,如果您的
umask
限制不够,其他用户可以在其中打开文件)。有没有办法重新链接目录项?没有,这样的文件无法重新链接。类似
timerfd
的东西也使用匿名索引节点。
3 -> '/home/ciro/test/#44698689 (deleted)'
fd = anon_inode_getfd("random", &fops_anon, NULL, O_RDONLY | O_CLOEXEC);
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> /* min */
#include <linux/module.h>
#include <linux/printk.h> /* printk */

#include "anonymous_inode.h"

MODULE_LICENSE("GPL");

static struct dentry *dir;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    char kbuf[1024];
    size_t ret;

    ret = snprintf(kbuf, sizeof(kbuf), "%llu", (unsigned long long)jiffies);
    if (copy_to_user(buf, kbuf, ret)) {
        ret = -EFAULT;
    }
    return ret;
}

static const struct file_operations fops_anon = {
    .read = read,
};

static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long argp)
{
    int fd;

    switch (cmd) {
        case LKMC_ANONYMOUS_INODE_GET_FD:
            fd = anon_inode_getfd(
                "random",
                &fops_anon,
                NULL,
                O_RDONLY | O_CLOEXEC
            );
            if (copy_to_user((void __user *)argp, &fd, sizeof(fd))) {
                return -EFAULT;
            }
        break;
        default:
            return -EINVAL;
        break;
    }
    return 0;
}

static const struct file_operations fops_ioctl = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = unlocked_ioctl
};

static int myinit(void)
{
    dir = debugfs_create_dir("lkmc_anonymous_inode", 0);
    debugfs_create_file("f", 0, dir, NULL, &fops_ioctl);
    return 0;
}

static void myexit(void)
{
    debugfs_remove_recursive(dir);
}

module_init(myinit)
module_exit(myexit)