open
с O_TMPFILE
Это было бы хорошим определением анонимного inode: он создает индекс внутри данного каталога без имени, которое вообще не отображаетсяс ls
.
Затем при закрытии дескриптора файл удаляется.
Он был добавлен в Linux 3.11.
#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, Linux4.10, glibc 2.24, работает с:
gcc -o a.out -std=c99 -Wall -Wextra a.c
./a.out
anon_inode_getfd
Функция ядра Linux
Если вы имеете дело с модулями ядра, это вероятное определение.
Вы называете это как:
fd = anon_inode_getfd("random", &fops_anon, NULL, O_RDONLY | O_CLOEXEC);
и возвращаете пользователю fd
, например, из ioctl
.
Теперь у пользователя есть fd
со связаннымпроизвольно file_operations
и inode
, и когда это fd
закрыто, все освобождается.
Этот метод полезен, например, если вы хотите иметь несколько системных вызовов read
, но не хотите создавать несколько файлов устройств, что дополнительно загрязняет /dev
: вы просто создаете дополнительные ioctl
s.
Пример минимального запуска с 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)