aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/fdso.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/fdso.c')
-rw-r--r--litmus/fdso.c283
1 files changed, 283 insertions, 0 deletions
diff --git a/litmus/fdso.c b/litmus/fdso.c
new file mode 100644
index 000000000000..323efac17a47
--- /dev/null
+++ b/litmus/fdso.c
@@ -0,0 +1,283 @@
1/* fdso.c - file descriptor attached shared objects
2 *
3 * (c) 2007 B. Brandenburg, LITMUS^RT project
4 *
5 * Notes:
6 * - objects descriptor (OD) tables are not cloned during a fork.
7 * - objects are created on-demand, and freed after the last reference
8 * is dropped.
9 * - for now, object types are hard coded.
10 * - As long as we have live objects, we keep a reference to the inode.
11 */
12
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/mutex.h>
16#include <linux/file.h>
17#include <asm/uaccess.h>
18
19#include <litmus/fdso.h>
20
21
22static struct fdso_ops dummy_ops = {
23 .create = NULL
24};
25
26static const struct fdso_ops* fdso_ops[] = {
27 &dummy_ops,
28 &dummy_ops,
29};
30
31static void* fdso_create(obj_type_t type)
32{
33 if (fdso_ops[type]->create)
34 return fdso_ops[type]->create();
35 else
36 return NULL;
37}
38
39static void fdso_destroy(obj_type_t type, void* obj)
40{
41 fdso_ops[type]->destroy(obj);
42}
43
44static int fdso_open(struct od_table_entry* entry, void* __user config)
45{
46 if (fdso_ops[entry->obj->type]->open)
47 return fdso_ops[entry->obj->type]->open(entry, config);
48 else
49 return 0;
50}
51
52static int fdso_close(struct od_table_entry* entry)
53{
54 if (fdso_ops[entry->obj->type]->close)
55 return fdso_ops[entry->obj->type]->close(entry);
56 else
57 return 0;
58}
59
60/* inode must be locked already */
61static struct inode_obj_id* alloc_inode_obj(struct inode* inode,
62 obj_type_t type,
63 unsigned int id)
64{
65 struct inode_obj_id* obj;
66 void* raw_obj;
67
68 raw_obj = fdso_create(type);
69 if (!raw_obj)
70 return NULL;
71
72 obj = kmalloc(sizeof(*obj), GFP_KERNEL);
73 if (!obj)
74 return NULL;
75 INIT_LIST_HEAD(&obj->list);
76 atomic_set(&obj->count, 1);
77 obj->type = type;
78 obj->id = id;
79 obj->obj = raw_obj;
80 obj->inode = inode;
81
82 list_add(&obj->list, &inode->i_obj_list);
83 atomic_inc(&inode->i_count);
84
85 printk(KERN_DEBUG "alloc_inode_obj(%p, %d, %d): object created\n", inode, type, id);
86 return obj;
87}
88
89/* inode must be locked already */
90static struct inode_obj_id* get_inode_obj(struct inode* inode,
91 obj_type_t type,
92 unsigned int id)
93{
94 struct list_head* pos;
95 struct inode_obj_id* obj = NULL;
96
97 list_for_each(pos, &inode->i_obj_list) {
98 obj = list_entry(pos, struct inode_obj_id, list);
99 if (obj->id == id && obj->type == type) {
100 atomic_inc(&obj->count);
101 return obj;
102 }
103 }
104 printk(KERN_DEBUG "get_inode_obj(%p, %d, %d): couldn't find object\n", inode, type, id);
105 return NULL;
106}
107
108
109static void put_inode_obj(struct inode_obj_id* obj)
110{
111 struct inode* inode;
112 int let_go = 0;
113
114 inode = obj->inode;
115 if (atomic_dec_and_test(&obj->count)) {
116
117 mutex_lock(&inode->i_obj_mutex);
118 /* no new references can be obtained */
119 if (!atomic_read(&obj->count)) {
120 list_del(&obj->list);
121 fdso_destroy(obj->type, obj->obj);
122 kfree(obj);
123 let_go = 1;
124 }
125 mutex_unlock(&inode->i_obj_mutex);
126 if (let_go)
127 iput(inode);
128 }
129}
130
131static struct od_table_entry* get_od_entry(struct task_struct* t)
132{
133 struct od_table_entry* table;
134 int i;
135
136
137 table = t->od_table;
138 if (!table) {
139 table = kzalloc(sizeof(*table) * MAX_OBJECT_DESCRIPTORS,
140 GFP_KERNEL);
141 t->od_table = table;
142 }
143
144 for (i = 0; table && i < MAX_OBJECT_DESCRIPTORS; i++)
145 if (!table[i].used) {
146 table[i].used = 1;
147 return table + i;
148 }
149 return NULL;
150}
151
152static int put_od_entry(struct od_table_entry* od)
153{
154 put_inode_obj(od->obj);
155 od->used = 0;
156 return 0;
157}
158
159void exit_od_table(struct task_struct* t)
160{
161 int i;
162
163 if (t->od_table) {
164 for (i = 0; i < MAX_OBJECT_DESCRIPTORS; i++)
165 if (t->od_table[i].used)
166 put_od_entry(t->od_table + i);
167 kfree(t->od_table);
168 t->od_table = NULL;
169 }
170}
171
172static int do_sys_od_open(struct file* file, obj_type_t type, int id,
173 void* __user config)
174{
175 int idx = 0, err;
176 struct inode* inode;
177 struct inode_obj_id* obj = NULL;
178 struct od_table_entry* entry;
179
180 inode = file->f_dentry->d_inode;
181
182 entry = get_od_entry(current);
183 if (!entry)
184 return -ENOMEM;
185
186 mutex_lock(&inode->i_obj_mutex);
187 obj = get_inode_obj(inode, type, id);
188 if (!obj)
189 obj = alloc_inode_obj(inode, type, id);
190 if (!obj) {
191 idx = -ENOMEM;
192 entry->used = 0;
193 } else {
194 entry->obj = obj;
195 entry->extra = NULL;
196 idx = entry - current->od_table;
197 }
198
199 mutex_unlock(&inode->i_obj_mutex);
200
201 err = fdso_open(entry, config);
202 if (err < 0) {
203 /* The class rejected the open call.
204 * We need to clean up and tell user space.
205 */
206 put_od_entry(entry);
207 idx = err;
208 }
209
210 return idx;
211}
212
213
214struct od_table_entry* __od_lookup(int od)
215{
216 struct task_struct *t = current;
217
218 if (!t->od_table)
219 return NULL;
220 if (od < 0 || od >= MAX_OBJECT_DESCRIPTORS)
221 return NULL;
222 if (!t->od_table[od].used)
223 return NULL;
224 return t->od_table + od;
225}
226
227
228asmlinkage int sys_od_open(int fd, int type, int obj_id, void* __user config)
229{
230 int ret = 0;
231 struct file* file;
232
233 /*
234 1) get file from fd, get inode from file
235 2) lock inode
236 3) try to lookup object
237 4) if not present create and enqueue object, inc inode refcnt
238 5) increment refcnt of object
239 6) alloc od_table_entry, setup ptrs
240 7) unlock inode
241 8) return offset in od_table as OD
242 */
243
244 if (type < MIN_OBJ_TYPE || type > MAX_OBJ_TYPE) {
245 ret = -EINVAL;
246 goto out;
247 }
248
249 file = fget(fd);
250 if (!file) {
251 ret = -EBADF;
252 goto out;
253 }
254
255 ret = do_sys_od_open(file, type, obj_id, config);
256
257 fput(file);
258
259out:
260 return ret;
261}
262
263
264asmlinkage int sys_od_close(int od)
265{
266 int ret = -EINVAL;
267 struct task_struct *t = current;
268
269 if (od < 0 || od >= MAX_OBJECT_DESCRIPTORS)
270 return ret;
271
272 if (!t->od_table || !t->od_table[od].used)
273 return ret;
274
275
276 /* give the class a chance to reject the close
277 */
278 ret = fdso_close(t->od_table + od);
279 if (ret == 0)
280 ret = put_od_entry(t->od_table + od);
281
282 return ret;
283}