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