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