aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjoern B. Brandenburg <bbb@cs.unc.edu>2009-12-08 11:31:07 -0500
committerBjoern B. Brandenburg <bbb@cs.unc.edu>2009-12-08 12:47:26 -0500
commita280dbb21fa396679874631da70fb9a91e823f9e (patch)
treeb4f948231f6bd0815900d9ce9dc12055542bd8af
parent5b4aa5ab69fa1971e04eff5eaa797a7ef19eff3e (diff)
add FDSO support.
-rw-r--r--fs/exec.c3
-rw-r--r--fs/inode.c2
-rw-r--r--include/linux/fs.h5
-rw-r--r--include/linux/sched.h5
-rw-r--r--include/litmus/fdso.h69
-rw-r--r--kernel/exit.c4
-rw-r--r--litmus/Makefile1
-rw-r--r--litmus/fdso.c283
8 files changed, 372 insertions, 0 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 282240afe99e..6f47786702a9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -56,6 +56,8 @@
56#include <asm/mmu_context.h> 56#include <asm/mmu_context.h>
57#include <asm/tlb.h> 57#include <asm/tlb.h>
58 58
59#include <litmus/litmus.h>
60
59#ifdef CONFIG_KMOD 61#ifdef CONFIG_KMOD
60#include <linux/kmod.h> 62#include <linux/kmod.h>
61#endif 63#endif
@@ -1309,6 +1311,7 @@ int do_execve(char * filename,
1309 goto out_kfree; 1311 goto out_kfree;
1310 1312
1311 sched_exec(); 1313 sched_exec();
1314 litmus_exec();
1312 1315
1313 bprm->file = file; 1316 bprm->file = file;
1314 bprm->filename = filename; 1317 bprm->filename = filename;
diff --git a/fs/inode.c b/fs/inode.c
index ed35383d0b6c..ef71ea06c65d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -220,6 +220,8 @@ void inode_init_once(struct inode *inode)
220 INIT_LIST_HEAD(&inode->inotify_watches); 220 INIT_LIST_HEAD(&inode->inotify_watches);
221 mutex_init(&inode->inotify_mutex); 221 mutex_init(&inode->inotify_mutex);
222#endif 222#endif
223 INIT_LIST_HEAD(&inode->i_obj_list);
224 mutex_init(&inode->i_obj_mutex);
223} 225}
224 226
225EXPORT_SYMBOL(inode_init_once); 227EXPORT_SYMBOL(inode_init_once);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b3ec4a496d64..22f856c14e76 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -588,6 +588,8 @@ static inline int mapping_writably_mapped(struct address_space *mapping)
588#define i_size_ordered_init(inode) do { } while (0) 588#define i_size_ordered_init(inode) do { } while (0)
589#endif 589#endif
590 590
591struct inode_obj_id_table;
592
591struct inode { 593struct inode {
592 struct hlist_node i_hash; 594 struct hlist_node i_hash;
593 struct list_head i_list; 595 struct list_head i_list;
@@ -653,6 +655,9 @@ struct inode {
653 void *i_security; 655 void *i_security;
654#endif 656#endif
655 void *i_private; /* fs or device private pointer */ 657 void *i_private; /* fs or device private pointer */
658
659 struct list_head i_obj_list;
660 struct mutex i_obj_mutex;
656}; 661};
657 662
658/* 663/*
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 3bf424c433ce..76e28f19e9a0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -917,6 +917,8 @@ struct sched_entity {
917#endif 917#endif
918}; 918};
919 919
920struct od_table_entry;
921
920struct task_struct { 922struct task_struct {
921 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ 923 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
922 void *stack; 924 void *stack;
@@ -1184,6 +1186,9 @@ struct task_struct {
1184 1186
1185 /* litmus parameters and state */ 1187 /* litmus parameters and state */
1186 struct rt_param rt_param; 1188 struct rt_param rt_param;
1189
1190 /* references to PI semaphores, etc. */
1191 struct od_table_entry* od_table;
1187}; 1192};
1188 1193
1189/* 1194/*
diff --git a/include/litmus/fdso.h b/include/litmus/fdso.h
new file mode 100644
index 000000000000..286e10f86de0
--- /dev/null
+++ b/include/litmus/fdso.h
@@ -0,0 +1,69 @@
1/* fdso.h - file descriptor attached shared objects
2 *
3 * (c) 2007 B. Brandenburg, LITMUS^RT project
4 */
5
6#ifndef _LINUX_FDSO_H_
7#define _LINUX_FDSO_H_
8
9#include <linux/list.h>
10#include <asm/atomic.h>
11
12#include <linux/fs.h>
13
14#define MAX_OBJECT_DESCRIPTORS 32
15
16typedef enum {
17 MIN_OBJ_TYPE = 0,
18
19 FMLP_SEM = 0,
20 SRP_SEM = 1,
21
22 MAX_OBJ_TYPE = 1
23} obj_type_t;
24
25struct inode_obj_id {
26 struct list_head list;
27 atomic_t count;
28 struct inode* inode;
29
30 obj_type_t type;
31 void* obj;
32 unsigned int id;
33};
34
35
36struct od_table_entry {
37 unsigned int used;
38
39 struct inode_obj_id* obj;
40 void* extra;
41};
42
43struct fdso_ops {
44 void* (*create) (void);
45 void (*destroy)(void*);
46 int (*open) (struct od_table_entry*, void* __user);
47 int (*close) (struct od_table_entry*);
48};
49
50/* translate a userspace supplied od into the raw table entry
51 * returns NULL if od is invalid
52 */
53struct od_table_entry* __od_lookup(int od);
54
55/* translate a userspace supplied od into the associated object
56 * returns NULL if od is invalid
57 */
58static inline void* od_lookup(int od, obj_type_t type)
59{
60 struct od_table_entry* e = __od_lookup(od);
61 return e && e->obj->type == type ? e->obj->obj : NULL;
62}
63
64#define lookup_fmlp_sem(od)((struct pi_semaphore*) od_lookup(od, FMLP_SEM))
65#define lookup_srp_sem(od) ((struct srp_semaphore*) od_lookup(od, SRP_SEM))
66#define lookup_ics(od) ((struct ics*) od_lookup(od, ICS_ID))
67
68
69#endif
diff --git a/kernel/exit.c b/kernel/exit.c
index 549c0558ba68..bc313b74a15c 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -52,6 +52,8 @@
52 52
53extern void sem_exit (void); 53extern void sem_exit (void);
54 54
55extern void exit_od_table(struct task_struct* t);
56
55static void exit_mm(struct task_struct * tsk); 57static void exit_mm(struct task_struct * tsk);
56 58
57static void __unhash_process(struct task_struct *p) 59static void __unhash_process(struct task_struct *p)
@@ -987,6 +989,8 @@ fastcall NORET_TYPE void do_exit(long code)
987 if (unlikely(tsk->audit_context)) 989 if (unlikely(tsk->audit_context))
988 audit_free(tsk); 990 audit_free(tsk);
989 991
992 exit_od_table(tsk);
993
990 tsk->exit_code = code; 994 tsk->exit_code = code;
991 taskstats_exit(tsk, group_dead); 995 taskstats_exit(tsk, group_dead);
992 996
diff --git a/litmus/Makefile b/litmus/Makefile
index 59f61cbc7f10..3d18cff62cee 100644
--- a/litmus/Makefile
+++ b/litmus/Makefile
@@ -7,6 +7,7 @@ obj-y = sched_plugin.o litmus.o \
7 sync.o \ 7 sync.o \
8 rt_domain.o \ 8 rt_domain.o \
9 edf_common.o \ 9 edf_common.o \
10 fdso.o \
10 heap.o 11 heap.o
11 12
12obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o 13obj-$(CONFIG_FEATHER_TRACE) += ft_event.o ftdev.o
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}