2010-12-22 12 views
14

Ich habe eine Google-Suche über "anonymous inode" gemacht und es scheint, dass es mit epoll verwandt ist ... aber was ist es eigentlich?Was ist ein anonymer Inode in Linux?

+1

Siehe akzeptierte Antwort: http://stackoverflow.com/questions/1401359/understanding- linux-proc-id-maps – Anders

Antwort

13

Zumindest in einigen Kontexten ist ein anonymer Inode ein Inode ohne angehängten Verzeichniseintrag. Der einfachste Weg, eine solche Inode zu schaffen, ist als solche:

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. 
+0

Kurz gesagt, ein anonymer Inode ist ein Inode, der aber keine Datei darstellt ein Speicherblock? – mrkschan

+5

Nein, es sind Daten auf der Festplatte, aber diese Daten haben keinen Eintrag mehr im Dateisystem, aus dem sie geöffnet werden können - Sie können die Daten nur verwenden, bis der letzte geöffnete Dateideskriptor geschlossen wird. Eine Situation, in der Sie dies wünschen, ist, wenn Sie eine temporäre Datei benötigen, die niemand öffnen darf; Viele der Verwendungen des Aufrufs mktemp() in UNIX sind eigentlich Fälle, in denen andere Prozesse die Datei nicht öffnen können, Sie brauchen nur eine temporäre Datei aus irgendeinem Grund. –

+0

Für dieses Beispiel wollen Sie fast sicher 'O_EXCL' hinzufügen und den Modus' 0600' anstelle von '0666' machen ... Da gibt es mindestens zwei große potentielle Schwachstellen (symlink vuln und race condition window wo ein anderer Benutzer könnte Öffnen Sie die Datei, wenn Ihre Umask nicht einschränkend genug ist. –

3

open mit O_TMPFILE

Dies wäre eine gute Definition von anonymen Inode sein: es eine Inode in einem bestimmten Verzeichnis erstellt, ohne Namen, was mit ls überhaupt nicht erscheint.

Dann, wenn Sie den Deskriptor schließen, wird die Datei gelöscht.

Es wurde in Linux 3.11 hinzugefügt.

#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; 
} 

Getestet in Ubuntu 17.04, Linux 4.10, glibc 2.24, laufen mit:

gcc -o a.out -std=c99 -Wall -Wextra a.c 
./a.out 

anon_inode_getfd Linux-Kernel-Funktion

Wenn Sie mit Kernel-Module handelt, ist dies ein wahrscheinliches Definition.

Sie nennen es wie:

fd = anon_inode_getfd("random", &fops_anon, NULL, O_RDONLY | O_CLOEXEC); 

und fd an Benutzer zurückgeben, z.B. von einem ioctl.

Nun hat der Benutzer ein fd mit zugehörigen beliebigen file_operations und inode, und wenn die fd geschlossen ist, wird alles befreit.

Diese Methode ist z.B. Wenn Sie mehrere read syscalls haben möchten, aber nicht mehrere Gerätedateien erstellen möchten, die /dev weiter verschmutzen: Sie erstellen stattdessen nur ioctl s.

Minimal runnable Beispiel mit QEMU Buildroot:

#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)