anon_inodes.c 4.56 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2 3 4 5 6 7 8 9 10 11
/*
 *  fs/anon_inodes.c
 *
 *  Copyright (C) 2007  Davide Libenzi <davidel@xmailserver.org>
 *
 *  Thanks to Arnd Bergmann for code review and suggestions.
 *  More changes for Thomas Gleixner suggestions.
 *
 */

12
#include <linux/cred.h>
13 14
#include <linux/file.h>
#include <linux/poll.h>
15
#include <linux/sched.h>
16 17 18 19 20 21 22
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/magic.h>
#include <linux/anon_inodes.h>
23
#include <linux/pseudo_fs.h>
24

25
#include <linux/uaccess.h>
26 27 28 29

static struct vfsmount *anon_inode_mnt __read_mostly;
static struct inode *anon_inode_inode;

Nick Piggin's avatar
Nick Piggin committed
30 31 32 33 34 35 36 37 38
/*
 * anon_inodefs_dname() is called from d_path().
 */
static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen)
{
	return dynamic_dname(dentry, buffer, buflen, "anon_inode:%s",
				dentry->d_name.name);
}

39 40 41 42
static const struct dentry_operations anon_inodefs_dentry_operations = {
	.d_dname	= anon_inodefs_dname,
};

43
static int anon_inodefs_init_fs_context(struct fs_context *fc)
44
{
45 46 47 48 49
	struct pseudo_fs_context *ctx = init_pseudo(fc, ANON_INODE_FS_MAGIC);
	if (!ctx)
		return -ENOMEM;
	ctx->dops = &anon_inodefs_dentry_operations;
	return 0;
50 51 52 53
}

static struct file_system_type anon_inode_fs_type = {
	.name		= "anon_inodefs",
54
	.init_fs_context = anon_inodefs_init_fs_context,
55 56 57
	.kill_sb	= kill_anon_super,
};

58
/**
59 60 61
 * anon_inode_getfile - creates a new file instance by hooking it up to an
 *                      anonymous inode, and a dentry that describe the "class"
 *                      of the file
62 63
 *
 * @name:    [in]    name of the "class" of the new file
64 65 66
 * @fops:    [in]    file operations for the new file
 * @priv:    [in]    private data for the new file (will be file's private_data)
 * @flags:   [in]    flags
67 68 69
 *
 * Creates a new file by hooking it on a single inode. This is useful for files
 * that do not need to have a full-fledged inode in order to operate correctly.
70
 * All the files created with anon_inode_getfile() will share a single inode,
71
 * hence saving memory and avoiding code duplication for the file/inode/dentry
72
 * setup.  Returns the newly created file* or an error pointer.
73
 */
74 75 76
struct file *anon_inode_getfile(const char *name,
				const struct file_operations *fops,
				void *priv, int flags)
77 78 79 80
{
	struct file *file;

	if (IS_ERR(anon_inode_inode))
81
		return ERR_PTR(-ENODEV);
82

83
	if (fops->owner && !try_module_get(fops->owner))
84
		return ERR_PTR(-ENOENT);
85

86 87
	/*
	 * We know the anon_inode inode count is always greater than zero,
Al Viro's avatar
Al Viro committed
88
	 * so ihold() is safe.
89
	 */
Al Viro's avatar
Al Viro committed
90
	ihold(anon_inode_inode);
91 92
	file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name,
				 flags & (O_ACCMODE | O_NONBLOCK), fops);
93
	if (IS_ERR(file))
94 95
		goto err;

96
	file->f_mapping = anon_inode_inode->i_mapping;
97 98 99

	file->private_data = priv;

100 101
	return file;

102 103
err:
	iput(anon_inode_inode);
104
	module_put(fops->owner);
105
	return file;
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
}
EXPORT_SYMBOL_GPL(anon_inode_getfile);

/**
 * anon_inode_getfd - creates a new file instance by hooking it up to an
 *                    anonymous inode, and a dentry that describe the "class"
 *                    of the file
 *
 * @name:    [in]    name of the "class" of the new file
 * @fops:    [in]    file operations for the new file
 * @priv:    [in]    private data for the new file (will be file's private_data)
 * @flags:   [in]    flags
 *
 * Creates a new file by hooking it on a single inode. This is useful for files
 * that do not need to have a full-fledged inode in order to operate correctly.
 * All the files created with anon_inode_getfd() will share a single inode,
 * hence saving memory and avoiding code duplication for the file/inode/dentry
 * setup.  Returns new descriptor or an error code.
 */
int anon_inode_getfd(const char *name, const struct file_operations *fops,
		     void *priv, int flags)
{
	int error, fd;
	struct file *file;

	error = get_unused_fd_flags(flags);
	if (error < 0)
		return error;
	fd = error;

	file = anon_inode_getfile(name, fops, priv, flags);
	if (IS_ERR(file)) {
		error = PTR_ERR(file);
		goto err_put_unused_fd;
	}
141 142
	fd_install(fd, file);

Al Viro's avatar
Al Viro committed
143
	return fd;
144 145 146 147 148

err_put_unused_fd:
	put_unused_fd(fd);
	return error;
}
149
EXPORT_SYMBOL_GPL(anon_inode_getfd);
150 151 152 153

static int __init anon_inode_init(void)
{
	anon_inode_mnt = kern_mount(&anon_inode_fs_type);
154 155
	if (IS_ERR(anon_inode_mnt))
		panic("anon_inode_init() kernel mount failed (%ld)\n", PTR_ERR(anon_inode_mnt));
156

157 158 159 160 161
	anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
	if (IS_ERR(anon_inode_inode))
		panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode));

	return 0;
162 163 164 165
}

fs_initcall(anon_inode_init);