diff options
author | Eric Anholt | 2008-04-22 18:08:23 -0500 |
---|---|---|
committer | Eric Anholt | 2008-04-23 12:42:06 -0500 |
commit | 47a2b7dc03e35d4eaf8148b87aeea8dd96723b4d (patch) | |
tree | 09df677e70bf9e9cce1fbd603f8134cacc4a5e58 | |
parent | c82894034f611696c54c5aaf2112be638aa2cb35 (diff) | |
download | external-libgbm-47a2b7dc03e35d4eaf8148b87aeea8dd96723b4d.tar.gz external-libgbm-47a2b7dc03e35d4eaf8148b87aeea8dd96723b4d.tar.xz external-libgbm-47a2b7dc03e35d4eaf8148b87aeea8dd96723b4d.zip |
Initial add of mmfs module.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | linux-core/Makefile | 3 | ||||
-rw-r--r-- | linux-core/Makefile.kernel | 3 | ||||
-rw-r--r-- | linux-core/mmfs.h | 176 | ||||
-rw-r--r-- | linux-core/mmfs_drv.c | 299 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/mmfs_basic.c | 68 |
7 files changed, 551 insertions, 3 deletions
@@ -58,6 +58,7 @@ tests/getclient | |||
58 | tests/getstats | 58 | tests/getstats |
59 | tests/getversion | 59 | tests/getversion |
60 | tests/lock | 60 | tests/lock |
61 | tests/mmfs_basic | ||
61 | tests/openclose | 62 | tests/openclose |
62 | tests/setversion | 63 | tests/setversion |
63 | tests/updatedraw | 64 | tests/updatedraw |
diff --git a/linux-core/Makefile b/linux-core/Makefile index 3af6f370..f2d44642 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile | |||
@@ -58,7 +58,7 @@ endif | |||
58 | 58 | ||
59 | # Modules for all architectures | 59 | # Modules for all architectures |
60 | MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \ | 60 | MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \ |
61 | mach64.o nv.o nouveau.o xgi.o | 61 | mach64.o nv.o nouveau.o xgi.o mmfs.o |
62 | 62 | ||
63 | # Modules only for ix86 architectures | 63 | # Modules only for ix86 architectures |
64 | ifneq (,$(findstring 86,$(MACHINE))) | 64 | ifneq (,$(findstring 86,$(MACHINE))) |
@@ -92,6 +92,7 @@ NVHEADERS = nv_drv.h $(DRMHEADERS) | |||
92 | FFBHEADERS = ffb_drv.h $(DRMHEADERS) | 92 | FFBHEADERS = ffb_drv.h $(DRMHEADERS) |
93 | NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS) | 93 | NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS) |
94 | XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS) | 94 | XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS) |
95 | MMFSHEADERS = mmfs.h mmfs_priv.h | ||
95 | 96 | ||
96 | PROGS = dristat drmstat | 97 | PROGS = dristat drmstat |
97 | 98 | ||
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index f012262d..093552bf 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel | |||
@@ -41,6 +41,7 @@ mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o | |||
41 | nv-objs := nv_drv.o | 41 | nv-objs := nv_drv.o |
42 | xgi-objs := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \ | 42 | xgi-objs := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \ |
43 | xgi_fence.o | 43 | xgi_fence.o |
44 | mmfs-objs := mmfs_drv.o | ||
44 | 45 | ||
45 | ifeq ($(CONFIG_COMPAT),y) | 46 | ifeq ($(CONFIG_COMPAT),y) |
46 | drm-objs += drm_ioc32.o | 47 | drm-objs += drm_ioc32.o |
@@ -52,7 +53,7 @@ nouveau-objs += nouveau_ioc32.o | |||
52 | xgi-objs += xgi_ioc32.o | 53 | xgi-objs += xgi_ioc32.o |
53 | endif | 54 | endif |
54 | 55 | ||
55 | obj-m += drm.o | 56 | obj-m += drm.o mmfs.o |
56 | obj-$(CONFIG_DRM_TDFX) += tdfx.o | 57 | obj-$(CONFIG_DRM_TDFX) += tdfx.o |
57 | obj-$(CONFIG_DRM_R128) += r128.o | 58 | obj-$(CONFIG_DRM_R128) += r128.o |
58 | obj-$(CONFIG_DRM_RADEON)+= radeon.o | 59 | obj-$(CONFIG_DRM_RADEON)+= radeon.o |
diff --git a/linux-core/mmfs.h b/linux-core/mmfs.h new file mode 100644 index 00000000..bdc148b9 --- /dev/null +++ b/linux-core/mmfs.h | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | /** @file mmfs.h | ||
29 | * This file provides ioctl and ioctl argument definitions for using the | ||
30 | * mmfs device. | ||
31 | */ | ||
32 | #ifdef __KERNEL__ | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/idr.h> | ||
35 | |||
36 | /** @file mmfs_priv.h | ||
37 | * This file provides internal structure definitions for mmfs.. | ||
38 | */ | ||
39 | |||
40 | /** | ||
41 | * This structure defines the mmfs memory object, which will be used by the | ||
42 | * DRM for its buffer objects. | ||
43 | */ | ||
44 | struct mmfs_object { | ||
45 | /** File representing the shmem storage */ | ||
46 | struct file *filp; | ||
47 | |||
48 | spinlock_t lock; | ||
49 | |||
50 | size_t size; | ||
51 | /** Reference count of this object, protected by object_lock */ | ||
52 | int refcount; | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * This structure defines the process (actually per-fd) mapping of object | ||
57 | * handles to mmfs objects. | ||
58 | */ | ||
59 | struct mmfs_file { | ||
60 | /** Mapping of object handles to object pointers. */ | ||
61 | struct idr object_idr; | ||
62 | /** | ||
63 | * Lock for synchronization of access to object->refcount and | ||
64 | * object_idr. See note in mmfs_unreference_ioctl. | ||
65 | */ | ||
66 | spinlock_t delete_lock; | ||
67 | }; | ||
68 | |||
69 | void mmfs_object_reference(struct mmfs_object *obj); | ||
70 | void mmfs_object_unreference(struct mmfs_object *obj); | ||
71 | |||
72 | #endif /* __KERNEL__ */ | ||
73 | |||
74 | #define MMFS_DEVICE_PATH "/dev/mmfs" | ||
75 | /* XXX: Choose non-experimental major */ | ||
76 | #define MMFS_DEVICE_MAJOR 246 | ||
77 | |||
78 | struct mmfs_alloc_args { | ||
79 | /** | ||
80 | * Requested size for the object. | ||
81 | * | ||
82 | * The (page-aligned) allocated size for the object will be returned. | ||
83 | */ | ||
84 | uint32_t size; | ||
85 | /** Returned handle for the object. */ | ||
86 | uint32_t handle; | ||
87 | }; | ||
88 | |||
89 | struct mmfs_unreference_args { | ||
90 | /** Handle of the object to be unreferenced. */ | ||
91 | uint32_t handle; | ||
92 | }; | ||
93 | |||
94 | struct mmfs_link_args { | ||
95 | /** Handle for the object being given a name. */ | ||
96 | uint32_t handle; | ||
97 | /** Requested file name to export the object under. */ | ||
98 | char *name; | ||
99 | /** Requested file mode to export the object under. */ | ||
100 | mode_t mode; | ||
101 | }; | ||
102 | |||
103 | struct mmfs_pread_args { | ||
104 | /** Handle for the object being read. */ | ||
105 | uint32_t handle; | ||
106 | /** Offset into the object to read from */ | ||
107 | off_t offset; | ||
108 | /** Length of data to read */ | ||
109 | size_t size; | ||
110 | /** Pointer to write the data into. */ | ||
111 | void *data; | ||
112 | }; | ||
113 | |||
114 | struct mmfs_pwrite_args { | ||
115 | /** Handle for the object being written to. */ | ||
116 | uint32_t handle; | ||
117 | /** Offset into the object to write to */ | ||
118 | off_t offset; | ||
119 | /** Length of data to write */ | ||
120 | size_t size; | ||
121 | /** Pointer to read the data from. */ | ||
122 | void *data; | ||
123 | }; | ||
124 | |||
125 | struct mmfs_mmap_args { | ||
126 | /** Handle for the object being mapped. */ | ||
127 | uint32_t handle; | ||
128 | /** Offset in the object to map. */ | ||
129 | off_t offset; | ||
130 | /** | ||
131 | * Length of data to map. | ||
132 | * | ||
133 | * The value will be page-aligned. | ||
134 | */ | ||
135 | size_t size; | ||
136 | /** Returned pointer the data was mapped at */ | ||
137 | void *addr; | ||
138 | }; | ||
139 | |||
140 | /** | ||
141 | * \name Ioctls Definitions | ||
142 | */ | ||
143 | /* @{ */ | ||
144 | |||
145 | #define MMFS_IOCTL_BASE 'm' | ||
146 | #define MMFS_IO(nr) _IO(MMFS_IOCTL_BASE, nr) | ||
147 | #define MMFS_IOR(nr,type) _IOR(MMFS_IOCTL_BASE, nr, type) | ||
148 | #define MMFS_IOW(nr,type) _IOW(MMFS_IOCTL_BASE, nr, type) | ||
149 | #define MMFS_IOWR(nr,type) _IOWR(MMFS_IOCTL_BASE, nr, type) | ||
150 | |||
151 | /** This ioctl allocates an object and returns a handle referencing it. */ | ||
152 | #define MMFS_IOCTL_ALLOC MMFS_IOWR(0x00, struct mmfs_alloc_args) | ||
153 | |||
154 | /** | ||
155 | * This ioctl releases the reference on the handle returned from | ||
156 | * MMFS_IOCTL_ALLOC. | ||
157 | */ | ||
158 | #define MMFS_IOCTL_UNREFERENCE MMFS_IOR(0x01, struct mmfs_unreference_args) | ||
159 | |||
160 | /** | ||
161 | * This ioctl creates a file in the mmfs filesystem representing an object. | ||
162 | * | ||
163 | * XXX: Need a way to get handle from fd or name. | ||
164 | */ | ||
165 | #define MMFS_IOCTL_LINK MMFS_IOWR(0x02, struct mmfs_link_args) | ||
166 | |||
167 | /** This ioctl copies data from an object into a user address. */ | ||
168 | #define MMFS_IOCTL_PREAD MMFS_IOWR(0x03, struct mmfs_pread_args) | ||
169 | |||
170 | /** This ioctl copies data from a user address into an object. */ | ||
171 | #define MMFS_IOCTL_PWRITE MMFS_IOWR(0x04, struct mmfs_pwrite_args) | ||
172 | |||
173 | /** This ioctl maps data from the object into the user address space. */ | ||
174 | #define MMFS_IOCTL_MMAP MMFS_IOWR(0x05, struct mmfs_mmap_args) | ||
175 | |||
176 | /* }@ */ | ||
diff --git a/linux-core/mmfs_drv.c b/linux-core/mmfs_drv.c new file mode 100644 index 00000000..f4b07117 --- /dev/null +++ b/linux-core/mmfs_drv.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/types.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/file.h> | ||
34 | #include <linux/module.h> | ||
35 | #include "mmfs.h" | ||
36 | |||
37 | /** @file mmfs.c | ||
38 | * | ||
39 | * This file provides the filesystem for memory manager objects used by the | ||
40 | * DRM. | ||
41 | * | ||
42 | * The goal is to have swap-backed object allocation managed through | ||
43 | * struct file. However, file descriptors as handles to a struct file have | ||
44 | * two major failings: | ||
45 | * - Process limits prevent more than 1024 or so being used at a time by | ||
46 | * default. | ||
47 | * - Inability to allocate high fds will aggravate the X Server's select() | ||
48 | * handling, and likely that of many GL client applications as well. | ||
49 | * | ||
50 | * This led to a plan of using our own integer IDs (called handles, following | ||
51 | * DRM terminology) to mimic fds, and implement the fd syscalls we need as | ||
52 | * ioctls. The objects themselves will still include the struct file so | ||
53 | * that we can transition to fds if the required kernel infrastructure shows | ||
54 | * up at a later data, and as our interface with shmfs for memory allocation. | ||
55 | */ | ||
56 | |||
57 | static struct mmfs_object * | ||
58 | mmfs_object_alloc(size_t size) | ||
59 | { | ||
60 | struct mmfs_object *obj; | ||
61 | |||
62 | BUG_ON((size & (PAGE_SIZE - 1)) != 0); | ||
63 | |||
64 | obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); | ||
65 | |||
66 | obj->filp = shmem_file_setup("mmfs object", size, 0); | ||
67 | if (IS_ERR(obj->filp)) { | ||
68 | kfree(obj); | ||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | obj->refcount = 1; | ||
73 | |||
74 | return obj; | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Removes the mapping from handle to filp for this object. | ||
79 | */ | ||
80 | static int | ||
81 | mmfs_handle_delete(struct mmfs_file *mmfs_filp, int handle) | ||
82 | { | ||
83 | struct mmfs_object *obj; | ||
84 | |||
85 | /* This is gross. The idr system doesn't let us try a delete and | ||
86 | * return an error code. It just spews if you fail at deleting. | ||
87 | * So, we have to grab a lock around finding the object and then | ||
88 | * doing the delete on it and dropping the refcount, or the user | ||
89 | * could race us to double-decrement the refcount and cause a | ||
90 | * use-after-free later. Given the frequency of our handle lookups, | ||
91 | * we may want to use ida for number allocation and a hash table | ||
92 | * for the pointers, anyway. | ||
93 | */ | ||
94 | spin_lock(&mmfs_filp->delete_lock); | ||
95 | |||
96 | /* Check if we currently have a reference on the object */ | ||
97 | obj = idr_find(&mmfs_filp->object_idr, handle); | ||
98 | if (obj == NULL) { | ||
99 | spin_unlock(&mmfs_filp->delete_lock); | ||
100 | return -EINVAL; | ||
101 | } | ||
102 | |||
103 | /* Release reference and decrement refcount. */ | ||
104 | idr_remove(&mmfs_filp->object_idr, handle); | ||
105 | mmfs_object_unreference(obj); | ||
106 | |||
107 | spin_unlock(&mmfs_filp->delete_lock); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * Allocates a new mmfs object and returns a handle to it. | ||
114 | */ | ||
115 | static int | ||
116 | mmfs_alloc_ioctl(struct inode *inode, struct file *filp, | ||
117 | unsigned int cmd, unsigned long arg) | ||
118 | { | ||
119 | struct mmfs_file *mmfs_filp = filp->private_data; | ||
120 | struct mmfs_alloc_args args; | ||
121 | struct mmfs_object *obj; | ||
122 | int handle, ret; | ||
123 | |||
124 | if (copy_from_user(&args, (void __user *)arg, sizeof(args))) | ||
125 | return -EFAULT; | ||
126 | |||
127 | /* Round requested size up to page size */ | ||
128 | args.size = (args.size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); | ||
129 | |||
130 | /* Allocate the new object */ | ||
131 | obj = mmfs_object_alloc(args.size); | ||
132 | if (obj == NULL) | ||
133 | return -ENOMEM; | ||
134 | |||
135 | /* Get the user-visible handle using idr. | ||
136 | * | ||
137 | * I'm not really sure why the idr api needs us to do this in two | ||
138 | * repeating steps. It handles internal locking of its data | ||
139 | * structure, yet insists that we keep its memory allocation step | ||
140 | * separate from its slot-finding step for locking purposes. | ||
141 | */ | ||
142 | do { | ||
143 | if (idr_pre_get(&mmfs_filp->object_idr, GFP_KERNEL) == 0) { | ||
144 | kfree(obj); | ||
145 | return -EFAULT; | ||
146 | } | ||
147 | |||
148 | ret = idr_get_new(&mmfs_filp->object_idr, obj, &handle); | ||
149 | } while (ret == -EAGAIN); | ||
150 | |||
151 | if (ret != 0) { | ||
152 | mmfs_object_unreference(obj); | ||
153 | return -EFAULT; | ||
154 | } | ||
155 | |||
156 | args.handle = handle; | ||
157 | |||
158 | if (copy_to_user((void __user *)arg, &args, sizeof(args))) { | ||
159 | mmfs_handle_delete(mmfs_filp, args.handle); | ||
160 | return -EFAULT; | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * Allocates a new mmfs object and returns a handle to it. | ||
168 | */ | ||
169 | static int | ||
170 | mmfs_unreference_ioctl(struct inode *inode, struct file *filp, | ||
171 | unsigned int cmd, unsigned long arg) | ||
172 | { | ||
173 | struct mmfs_file *mmfs_filp = filp->private_data; | ||
174 | struct mmfs_unreference_args args; | ||
175 | int ret; | ||
176 | |||
177 | if (copy_from_user(&args, (void __user *)arg, sizeof(args))) | ||
178 | return -EFAULT; | ||
179 | |||
180 | ret = mmfs_handle_delete(mmfs_filp, args.handle); | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | static int | ||
186 | mmfs_ioctl(struct inode *inode, struct file *filp, | ||
187 | unsigned int cmd, unsigned long arg) | ||
188 | { | ||
189 | |||
190 | switch (cmd) { | ||
191 | case MMFS_IOCTL_ALLOC: | ||
192 | return mmfs_alloc_ioctl(inode, filp, cmd, arg); | ||
193 | case MMFS_IOCTL_UNREFERENCE: | ||
194 | return mmfs_unreference_ioctl(inode, filp, cmd, arg); | ||
195 | default: | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * Sets up the file private for keeping track of our mappings of handles to | ||
202 | * mmfs objects. | ||
203 | */ | ||
204 | int | ||
205 | mmfs_open(struct inode *inode, struct file *filp) | ||
206 | { | ||
207 | struct mmfs_file *mmfs_filp; | ||
208 | |||
209 | if (filp->f_flags & O_EXCL) | ||
210 | return -EBUSY; /* No exclusive opens */ | ||
211 | |||
212 | mmfs_filp = kcalloc(1, sizeof(*mmfs_filp), GFP_KERNEL); | ||
213 | if (mmfs_filp == NULL) | ||
214 | return -ENOMEM; | ||
215 | filp->private_data = mmfs_filp; | ||
216 | |||
217 | idr_init(&mmfs_filp->object_idr); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /** Called at device close to release the file's references on objects. */ | ||
223 | static int | ||
224 | mmfs_object_release(int id, void *ptr, void *data) | ||
225 | { | ||
226 | struct mmfs_object *obj = ptr; | ||
227 | |||
228 | mmfs_object_unreference(obj); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * Called at close time when the filp is going away. | ||
235 | * | ||
236 | * Releases any remaining references on objects by this filp. | ||
237 | */ | ||
238 | int | ||
239 | mmfs_close(struct inode *inode, struct file *filp) | ||
240 | { | ||
241 | struct mmfs_file *mmfs_filp = filp->private_data; | ||
242 | |||
243 | idr_for_each(&mmfs_filp->object_idr, &mmfs_object_release, NULL); | ||
244 | |||
245 | idr_destroy(&mmfs_filp->object_idr); | ||
246 | |||
247 | kfree(mmfs_filp); | ||
248 | filp->private_data = NULL; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | void | ||
254 | mmfs_object_reference(struct mmfs_object *obj) | ||
255 | { | ||
256 | spin_lock(&obj->lock); | ||
257 | obj->refcount++; | ||
258 | spin_unlock(&obj->lock); | ||
259 | } | ||
260 | |||
261 | void | ||
262 | mmfs_object_unreference(struct mmfs_object *obj) | ||
263 | { | ||
264 | spin_lock(&obj->lock); | ||
265 | obj->refcount--; | ||
266 | spin_unlock(&obj->lock); | ||
267 | if (obj->refcount == 0) { | ||
268 | fput(obj->filp); | ||
269 | kfree(obj); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /** File operations structure */ | ||
274 | static const struct file_operations mmfs_dev_fops = { | ||
275 | .owner = THIS_MODULE, | ||
276 | .open = mmfs_open, | ||
277 | .release = mmfs_close, | ||
278 | .ioctl = mmfs_ioctl, | ||
279 | }; | ||
280 | |||
281 | static int __init mmfs_init(void) | ||
282 | { | ||
283 | int ret; | ||
284 | |||
285 | ret = register_chrdev(MMFS_DEVICE_MAJOR, "mmfs", &mmfs_dev_fops); | ||
286 | if (ret != 0) | ||
287 | return ret; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static void __exit mmfs_exit(void) | ||
293 | { | ||
294 | unregister_chrdev(MMFS_DEVICE_MAJOR, "mmfs"); | ||
295 | } | ||
296 | |||
297 | module_init(mmfs_init); | ||
298 | module_exit(mmfs_exit); | ||
299 | MODULE_LICENSE("GPL and additional rights"); | ||
diff --git a/tests/Makefile.am b/tests/Makefile.am index dce1754e..4a7b0119 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am | |||
@@ -1,4 +1,5 @@ | |||
1 | AM_CFLAGS = \ | 1 | AM_CFLAGS = \ |
2 | -I $(top_srcdir)/linux-core \ | ||
2 | -I $(top_srcdir)/shared-core \ | 3 | -I $(top_srcdir)/shared-core \ |
3 | -I $(top_srcdir)/libdrm | 4 | -I $(top_srcdir)/libdrm |
4 | 5 | ||
@@ -22,7 +23,8 @@ TESTS = auth \ | |||
22 | getstats \ | 23 | getstats \ |
23 | lock \ | 24 | lock \ |
24 | setversion \ | 25 | setversion \ |
25 | updatedraw | 26 | updatedraw \ |
27 | mmfs_basic | ||
26 | 28 | ||
27 | EXTRA_PROGRAMS = $(TESTS) | 29 | EXTRA_PROGRAMS = $(TESTS) |
28 | CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) | 30 | CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) |
diff --git a/tests/mmfs_basic.c b/tests/mmfs_basic.c new file mode 100644 index 00000000..907dc585 --- /dev/null +++ b/tests/mmfs_basic.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <stdlib.h> | ||
29 | #include <stdio.h> | ||
30 | #include <assert.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <inttypes.h> | ||
33 | #include <sys/stat.h> | ||
34 | #include "mmfs.h" | ||
35 | |||
36 | static void | ||
37 | create_mmfs_device() | ||
38 | { | ||
39 | struct stat sb; | ||
40 | int ret; | ||
41 | |||
42 | ret = stat(MMFS_DEVICE_PATH, &sb); | ||
43 | |||
44 | if (ret == 0) | ||
45 | return; | ||
46 | |||
47 | ret = mknod(MMFS_DEVICE_PATH, S_IFCHR | S_IRUSR | S_IWUSR, | ||
48 | makedev(MMFS_DEVICE_MAJOR, 0)); | ||
49 | |||
50 | if (ret != 0) | ||
51 | errx(1, "mknod()"); | ||
52 | } | ||
53 | |||
54 | |||
55 | int main(int argc, char **argv) | ||
56 | { | ||
57 | int fd; | ||
58 | |||
59 | create_mmfs_device(); | ||
60 | |||
61 | fd = open(MMFS_DEVICE_PATH, O_RDWR); | ||
62 | if (fd == -1) | ||
63 | errx(1, "open()"); | ||
64 | |||
65 | close(fd); | ||
66 | |||
67 | return 0; | ||
68 | } | ||