aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDavide Libenzi <davidel@xmailserver.org>2007-05-11 01:23:11 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-11 11:29:36 -0400
commit5dc8bf8132d59c03fe2562bce165c2f03f021687 (patch)
tree308e2acb2264c21c93d57b3fb9fb4869e162aa85 /fs
parent325aa33da784e5997c756a151bc46e9cc9b79db2 (diff)
signal/timer/event fds: anonymous inode source
This patch add an anonymous inode source, to be used for files that need and inode only in order to create a file*. We do not care of having an inode for each file, and we do not even care of having different names in the associated dentries (dentry names will be same for classes of file*). This allow code reuse, and will be used by epoll, signalfd and timerfd (and whatever else there'll be). Signed-off-by: Davide Libenzi <davidel@xmailserver.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/Makefile1
-rw-r--r--fs/anon_inodes.c200
2 files changed, 201 insertions, 0 deletions
diff --git a/fs/Makefile b/fs/Makefile
index 9edf4112bee0..b5cd46a88cb0 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -22,6 +22,7 @@ endif
22obj-$(CONFIG_INOTIFY) += inotify.o 22obj-$(CONFIG_INOTIFY) += inotify.o
23obj-$(CONFIG_INOTIFY_USER) += inotify_user.o 23obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
24obj-$(CONFIG_EPOLL) += eventpoll.o 24obj-$(CONFIG_EPOLL) += eventpoll.o
25obj-$(CONFIG_ANON_INODES) += anon_inodes.o
25obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o 26obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
26 27
27nfsd-$(CONFIG_NFSD) := nfsctl.o 28nfsd-$(CONFIG_NFSD) := nfsctl.o
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
new file mode 100644
index 000000000000..40fe3a3222e4
--- /dev/null
+++ b/fs/anon_inodes.c
@@ -0,0 +1,200 @@
1/*
2 * fs/anon_inodes.c
3 *
4 * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
5 *
6 * Thanks to Arnd Bergmann for code review and suggestions.
7 * More changes for Thomas Gleixner suggestions.
8 *
9 */
10
11#include <linux/file.h>
12#include <linux/poll.h>
13#include <linux/slab.h>
14#include <linux/init.h>
15#include <linux/fs.h>
16#include <linux/mount.h>
17#include <linux/module.h>
18#include <linux/kernel.h>
19#include <linux/magic.h>
20#include <linux/anon_inodes.h>
21
22#include <asm/uaccess.h>
23
24static struct vfsmount *anon_inode_mnt __read_mostly;
25static struct inode *anon_inode_inode;
26static const struct file_operations anon_inode_fops;
27
28static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags,
29 const char *dev_name, void *data,
30 struct vfsmount *mnt)
31{
32 return get_sb_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC,
33 mnt);
34}
35
36static int anon_inodefs_delete_dentry(struct dentry *dentry)
37{
38 /*
39 * We faked vfs to believe the dentry was hashed when we created it.
40 * Now we restore the flag so that dput() will work correctly.
41 */
42 dentry->d_flags |= DCACHE_UNHASHED;
43 return 1;
44}
45
46static struct file_system_type anon_inode_fs_type = {
47 .name = "anon_inodefs",
48 .get_sb = anon_inodefs_get_sb,
49 .kill_sb = kill_anon_super,
50};
51static struct dentry_operations anon_inodefs_dentry_operations = {
52 .d_delete = anon_inodefs_delete_dentry,
53};
54
55/**
56 * anon_inode_getfd - creates a new file instance by hooking it up to and
57 * anonymous inode, and a dentry that describe the "class"
58 * of the file
59 *
60 * @pfd: [out] pointer to the file descriptor
61 * @dpinode: [out] pointer to the inode
62 * @pfile: [out] pointer to the file struct
63 * @name: [in] name of the "class" of the new file
64 * @fops [in] file operations for the new file
65 * @priv [in] private data for the new file (will be file's private_data)
66 *
67 * Creates a new file by hooking it on a single inode. This is useful for files
68 * that do not need to have a full-fledged inode in order to operate correctly.
69 * All the files created with anon_inode_getfd() will share a single inode, by
70 * hence saving memory and avoiding code duplication for the file/inode/dentry
71 * setup.
72 */
73int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
74 const char *name, const struct file_operations *fops,
75 void *priv)
76{
77 struct qstr this;
78 struct dentry *dentry;
79 struct inode *inode;
80 struct file *file;
81 int error, fd;
82
83 if (IS_ERR(anon_inode_inode))
84 return -ENODEV;
85 file = get_empty_filp();
86 if (!file)
87 return -ENFILE;
88
89 inode = igrab(anon_inode_inode);
90 if (IS_ERR(inode)) {
91 error = PTR_ERR(inode);
92 goto err_put_filp;
93 }
94
95 error = get_unused_fd();
96 if (error < 0)
97 goto err_iput;
98 fd = error;
99
100 /*
101 * Link the inode to a directory entry by creating a unique name
102 * using the inode sequence number.
103 */
104 error = -ENOMEM;
105 this.name = name;
106 this.len = strlen(name);
107 this.hash = 0;
108 dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
109 if (!dentry)
110 goto err_put_unused_fd;
111 dentry->d_op = &anon_inodefs_dentry_operations;
112 /* Do not publish this dentry inside the global dentry hash table */
113 dentry->d_flags &= ~DCACHE_UNHASHED;
114 d_instantiate(dentry, inode);
115
116 file->f_path.mnt = mntget(anon_inode_mnt);
117 file->f_path.dentry = dentry;
118 file->f_mapping = inode->i_mapping;
119
120 file->f_pos = 0;
121 file->f_flags = O_RDWR;
122 file->f_op = fops;
123 file->f_mode = FMODE_READ | FMODE_WRITE;
124 file->f_version = 0;
125 file->private_data = priv;
126
127 fd_install(fd, file);
128
129 *pfd = fd;
130 *pinode = inode;
131 *pfile = file;
132 return 0;
133
134err_put_unused_fd:
135 put_unused_fd(fd);
136err_iput:
137 iput(inode);
138err_put_filp:
139 put_filp(file);
140 return error;
141}
142
143/*
144 * A single inode exist for all anon_inode files. Contrary to pipes,
145 * anon_inode inodes has no per-instance data associated, so we can avoid
146 * the allocation of multiple of them.
147 */
148static struct inode *anon_inode_mkinode(void)
149{
150 struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
151
152 if (!inode)
153 return ERR_PTR(-ENOMEM);
154
155 inode->i_fop = &anon_inode_fops;
156
157 /*
158 * Mark the inode dirty from the very beginning,
159 * that way it will never be moved to the dirty
160 * list because mark_inode_dirty() will think
161 * that it already _is_ on the dirty list.
162 */
163 inode->i_state = I_DIRTY;
164 inode->i_mode = S_IRUSR | S_IWUSR;
165 inode->i_uid = current->fsuid;
166 inode->i_gid = current->fsgid;
167 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
168 return inode;
169}
170
171static int __init anon_inode_init(void)
172{
173 int error;
174
175 error = register_filesystem(&anon_inode_fs_type);
176 if (error)
177 goto err_exit;
178 anon_inode_mnt = kern_mount(&anon_inode_fs_type);
179 if (IS_ERR(anon_inode_mnt)) {
180 error = PTR_ERR(anon_inode_mnt);
181 goto err_unregister_filesystem;
182 }
183 anon_inode_inode = anon_inode_mkinode();
184 if (IS_ERR(anon_inode_inode)) {
185 error = PTR_ERR(anon_inode_inode);
186 goto err_mntput;
187 }
188
189 return 0;
190
191err_mntput:
192 mntput(anon_inode_mnt);
193err_unregister_filesystem:
194 unregister_filesystem(&anon_inode_fs_type);
195err_exit:
196 panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
197}
198
199fs_initcall(anon_inode_init);
200