diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | linux-core/mmfs_drv.c | 113 | ||||
-rw-r--r-- | linux-core/mmfs_drv.h | 7 | ||||
-rw-r--r-- | shared-core/mmfs.h | 7 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/drmtest.c | 33 | ||||
-rw-r--r-- | tests/drmtest.h | 1 | ||||
-rw-r--r-- | tests/mmfs_basic.c | 24 | ||||
-rw-r--r-- | tests/mmfs_readwrite.c | 125 |
9 files changed, 280 insertions, 34 deletions
@@ -59,6 +59,7 @@ tests/getstats | |||
59 | tests/getversion | 59 | tests/getversion |
60 | tests/lock | 60 | tests/lock |
61 | tests/mmfs_basic | 61 | tests/mmfs_basic |
62 | tests/mmfs_readwrite | ||
62 | tests/openclose | 63 | tests/openclose |
63 | tests/setversion | 64 | tests/setversion |
64 | tests/updatedraw | 65 | tests/updatedraw |
diff --git a/linux-core/mmfs_drv.c b/linux-core/mmfs_drv.c index f4b07117..d973592d 100644 --- a/linux-core/mmfs_drv.c +++ b/linux-core/mmfs_drv.c | |||
@@ -91,12 +91,12 @@ mmfs_handle_delete(struct mmfs_file *mmfs_filp, int handle) | |||
91 | * we may want to use ida for number allocation and a hash table | 91 | * we may want to use ida for number allocation and a hash table |
92 | * for the pointers, anyway. | 92 | * for the pointers, anyway. |
93 | */ | 93 | */ |
94 | spin_lock(&mmfs_filp->delete_lock); | 94 | spin_lock(&mmfs_filp->table_lock); |
95 | 95 | ||
96 | /* Check if we currently have a reference on the object */ | 96 | /* Check if we currently have a reference on the object */ |
97 | obj = idr_find(&mmfs_filp->object_idr, handle); | 97 | obj = idr_find(&mmfs_filp->object_idr, handle); |
98 | if (obj == NULL) { | 98 | if (obj == NULL) { |
99 | spin_unlock(&mmfs_filp->delete_lock); | 99 | spin_unlock(&mmfs_filp->table_lock); |
100 | return -EINVAL; | 100 | return -EINVAL; |
101 | } | 101 | } |
102 | 102 | ||
@@ -104,11 +104,34 @@ mmfs_handle_delete(struct mmfs_file *mmfs_filp, int handle) | |||
104 | idr_remove(&mmfs_filp->object_idr, handle); | 104 | idr_remove(&mmfs_filp->object_idr, handle); |
105 | mmfs_object_unreference(obj); | 105 | mmfs_object_unreference(obj); |
106 | 106 | ||
107 | spin_unlock(&mmfs_filp->delete_lock); | 107 | spin_unlock(&mmfs_filp->table_lock); |
108 | 108 | ||
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | /** Returns a reference to the object named by the handle. */ | ||
113 | static struct mmfs_object * | ||
114 | mmfs_object_lookup(struct mmfs_file *mmfs_filp, int handle) | ||
115 | { | ||
116 | struct mmfs_object *obj; | ||
117 | |||
118 | spin_lock(&mmfs_filp->table_lock); | ||
119 | |||
120 | /* Check if we currently have a reference on the object */ | ||
121 | obj = idr_find(&mmfs_filp->object_idr, handle); | ||
122 | if (obj == NULL) { | ||
123 | spin_unlock(&mmfs_filp->table_lock); | ||
124 | return NULL; | ||
125 | } | ||
126 | |||
127 | mmfs_object_reference(obj); | ||
128 | |||
129 | spin_unlock(&mmfs_filp->table_lock); | ||
130 | |||
131 | return obj; | ||
132 | } | ||
133 | |||
134 | |||
112 | /** | 135 | /** |
113 | * Allocates a new mmfs object and returns a handle to it. | 136 | * Allocates a new mmfs object and returns a handle to it. |
114 | */ | 137 | */ |
@@ -164,7 +187,7 @@ mmfs_alloc_ioctl(struct inode *inode, struct file *filp, | |||
164 | } | 187 | } |
165 | 188 | ||
166 | /** | 189 | /** |
167 | * Allocates a new mmfs object and returns a handle to it. | 190 | * Releases the handle to an mmfs object. |
168 | */ | 191 | */ |
169 | static int | 192 | static int |
170 | mmfs_unreference_ioctl(struct inode *inode, struct file *filp, | 193 | mmfs_unreference_ioctl(struct inode *inode, struct file *filp, |
@@ -182,6 +205,84 @@ mmfs_unreference_ioctl(struct inode *inode, struct file *filp, | |||
182 | return ret; | 205 | return ret; |
183 | } | 206 | } |
184 | 207 | ||
208 | /** | ||
209 | * Reads data from the object referenced by handle. | ||
210 | * | ||
211 | * On error, the contents of *data are undefined. | ||
212 | */ | ||
213 | static int | ||
214 | mmfs_pread_ioctl(struct inode *inode, struct file *filp, | ||
215 | unsigned int cmd, unsigned long arg) | ||
216 | { | ||
217 | struct mmfs_file *mmfs_filp = filp->private_data; | ||
218 | struct mmfs_pread_args args; | ||
219 | struct mmfs_object *obj; | ||
220 | ssize_t read; | ||
221 | loff_t offset; | ||
222 | |||
223 | if (copy_from_user(&args, (void __user *)arg, sizeof(args))) | ||
224 | return -EFAULT; | ||
225 | |||
226 | obj = mmfs_object_lookup(mmfs_filp, args.handle); | ||
227 | if (obj == NULL) | ||
228 | return -EINVAL; | ||
229 | |||
230 | offset = args.offset; | ||
231 | |||
232 | read = obj->filp->f_op->read(obj->filp, (char __user *)args.data, | ||
233 | args.size, &offset); | ||
234 | if (read != args.size) { | ||
235 | mmfs_object_unreference(obj); | ||
236 | if (read < 0) | ||
237 | return read; | ||
238 | else | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | mmfs_object_unreference(obj); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * Writes data to the object referenced by handle. | ||
249 | * | ||
250 | * On error, the contents of the buffer that were to be modified are undefined. | ||
251 | */ | ||
252 | static int | ||
253 | mmfs_pwrite_ioctl(struct inode *inode, struct file *filp, | ||
254 | unsigned int cmd, unsigned long arg) | ||
255 | { | ||
256 | struct mmfs_file *mmfs_filp = filp->private_data; | ||
257 | struct mmfs_pwrite_args args; | ||
258 | struct mmfs_object *obj; | ||
259 | ssize_t written; | ||
260 | loff_t offset; | ||
261 | |||
262 | if (copy_from_user(&args, (void __user *)arg, sizeof(args))) | ||
263 | return -EFAULT; | ||
264 | |||
265 | obj = mmfs_object_lookup(mmfs_filp, args.handle); | ||
266 | if (obj == NULL) | ||
267 | return -EINVAL; | ||
268 | |||
269 | offset = args.offset; | ||
270 | |||
271 | written = obj->filp->f_op->write(obj->filp, (char __user *)args.data, | ||
272 | args.size, &offset); | ||
273 | if (written != args.size) { | ||
274 | mmfs_object_unreference(obj); | ||
275 | if (written < 0) | ||
276 | return written; | ||
277 | else | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | mmfs_object_unreference(obj); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
185 | static int | 286 | static int |
186 | mmfs_ioctl(struct inode *inode, struct file *filp, | 287 | mmfs_ioctl(struct inode *inode, struct file *filp, |
187 | unsigned int cmd, unsigned long arg) | 288 | unsigned int cmd, unsigned long arg) |
@@ -192,6 +293,10 @@ mmfs_ioctl(struct inode *inode, struct file *filp, | |||
192 | return mmfs_alloc_ioctl(inode, filp, cmd, arg); | 293 | return mmfs_alloc_ioctl(inode, filp, cmd, arg); |
193 | case MMFS_IOCTL_UNREFERENCE: | 294 | case MMFS_IOCTL_UNREFERENCE: |
194 | return mmfs_unreference_ioctl(inode, filp, cmd, arg); | 295 | return mmfs_unreference_ioctl(inode, filp, cmd, arg); |
296 | case MMFS_IOCTL_PREAD: | ||
297 | return mmfs_pread_ioctl(inode, filp, cmd, arg); | ||
298 | case MMFS_IOCTL_PWRITE: | ||
299 | return mmfs_pwrite_ioctl(inode, filp, cmd, arg); | ||
195 | default: | 300 | default: |
196 | return -EINVAL; | 301 | return -EINVAL; |
197 | } | 302 | } |
diff --git a/linux-core/mmfs_drv.h b/linux-core/mmfs_drv.h index 1944d2af..53d2f6cb 100644 --- a/linux-core/mmfs_drv.h +++ b/linux-core/mmfs_drv.h | |||
@@ -54,11 +54,8 @@ struct mmfs_object { | |||
54 | struct mmfs_file { | 54 | struct mmfs_file { |
55 | /** Mapping of object handles to object pointers. */ | 55 | /** Mapping of object handles to object pointers. */ |
56 | struct idr object_idr; | 56 | struct idr object_idr; |
57 | /** | 57 | /** Lock for synchronization of access to object_idr. */ |
58 | * Lock for synchronization of access to object->refcount and | 58 | spinlock_t table_lock; |
59 | * object_idr. See note in mmfs_unreference_ioctl. | ||
60 | */ | ||
61 | spinlock_t delete_lock; | ||
62 | }; | 59 | }; |
63 | 60 | ||
64 | void mmfs_object_reference(struct mmfs_object *obj); | 61 | void mmfs_object_reference(struct mmfs_object *obj); |
diff --git a/shared-core/mmfs.h b/shared-core/mmfs.h index bc7e991f..e0a4f25b 100644 --- a/shared-core/mmfs.h +++ b/shared-core/mmfs.h | |||
@@ -25,7 +25,12 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sys/ioctl.h> | 28 | #ifdef __linux__ |
29 | #include <asm/ioctl.h> | ||
30 | #else | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/ioccom.h> | ||
33 | #endif | ||
29 | 34 | ||
30 | /** @file mmfs.h | 35 | /** @file mmfs.h |
31 | * This file provides ioctl and ioctl argument definitions for using the | 36 | * This file provides ioctl and ioctl argument definitions for using the |
diff --git a/tests/Makefile.am b/tests/Makefile.am index 97752774..e2931013 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am | |||
@@ -23,7 +23,8 @@ TESTS = auth \ | |||
23 | lock \ | 23 | lock \ |
24 | setversion \ | 24 | setversion \ |
25 | updatedraw \ | 25 | updatedraw \ |
26 | mmfs_basic | 26 | mmfs_basic \ |
27 | mmfs_readwrite | ||
27 | 28 | ||
28 | EXTRA_PROGRAMS = $(TESTS) | 29 | EXTRA_PROGRAMS = $(TESTS) |
29 | CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) | 30 | CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) |
diff --git a/tests/drmtest.c b/tests/drmtest.c index cae99a0c..58f71a6a 100644 --- a/tests/drmtest.c +++ b/tests/drmtest.c | |||
@@ -26,7 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <fcntl.h> | 28 | #include <fcntl.h> |
29 | #include <sys/stat.h> | ||
29 | #include "drmtest.h" | 30 | #include "drmtest.h" |
31 | #include "mmfs.h" | ||
30 | 32 | ||
31 | /** Open the first DRM device we can find, searching up to 16 device nodes */ | 33 | /** Open the first DRM device we can find, searching up to 16 device nodes */ |
32 | int drm_open_any(void) | 34 | int drm_open_any(void) |
@@ -81,3 +83,34 @@ int drm_open_any_master(void) | |||
81 | abort(); | 83 | abort(); |
82 | } | 84 | } |
83 | 85 | ||
86 | static void | ||
87 | create_mmfs_device() | ||
88 | { | ||
89 | struct stat sb; | ||
90 | int ret; | ||
91 | |||
92 | ret = stat(MMFS_DEVICE_PATH, &sb); | ||
93 | |||
94 | if (ret == 0) | ||
95 | return; | ||
96 | |||
97 | ret = mknod(MMFS_DEVICE_PATH, S_IFCHR | S_IRUSR | S_IWUSR, | ||
98 | makedev(MMFS_DEVICE_MAJOR, 0)); | ||
99 | |||
100 | if (ret != 0) | ||
101 | errx(1, "mknod()"); | ||
102 | } | ||
103 | |||
104 | int | ||
105 | open_mmfs_device() | ||
106 | { | ||
107 | int fd; | ||
108 | |||
109 | create_mmfs_device(); | ||
110 | |||
111 | fd = open(MMFS_DEVICE_PATH, O_RDWR); | ||
112 | if (fd == -1) | ||
113 | errx(1, "open()"); | ||
114 | |||
115 | return fd; | ||
116 | } | ||
diff --git a/tests/drmtest.h b/tests/drmtest.h index afa0df4a..b84ada71 100644 --- a/tests/drmtest.h +++ b/tests/drmtest.h | |||
@@ -35,3 +35,4 @@ | |||
35 | 35 | ||
36 | int drm_open_any(void); | 36 | int drm_open_any(void); |
37 | int drm_open_any_master(void); | 37 | int drm_open_any_master(void); |
38 | int open_mmfs_device(); | ||
diff --git a/tests/mmfs_basic.c b/tests/mmfs_basic.c index b0ae8905..c6975b0b 100644 --- a/tests/mmfs_basic.c +++ b/tests/mmfs_basic.c | |||
@@ -36,24 +36,6 @@ | |||
36 | #include "mmfs.h" | 36 | #include "mmfs.h" |
37 | 37 | ||
38 | static void | 38 | static void |
39 | create_mmfs_device() | ||
40 | { | ||
41 | struct stat sb; | ||
42 | int ret; | ||
43 | |||
44 | ret = stat(MMFS_DEVICE_PATH, &sb); | ||
45 | |||
46 | if (ret == 0) | ||
47 | return; | ||
48 | |||
49 | ret = mknod(MMFS_DEVICE_PATH, S_IFCHR | S_IRUSR | S_IWUSR, | ||
50 | makedev(MMFS_DEVICE_MAJOR, 0)); | ||
51 | |||
52 | if (ret != 0) | ||
53 | errx(1, "mknod()"); | ||
54 | } | ||
55 | |||
56 | static void | ||
57 | test_bad_unref(int fd) | 39 | test_bad_unref(int fd) |
58 | { | 40 | { |
59 | struct mmfs_unreference_args unref; | 41 | struct mmfs_unreference_args unref; |
@@ -117,11 +99,7 @@ int main(int argc, char **argv) | |||
117 | { | 99 | { |
118 | int fd; | 100 | int fd; |
119 | 101 | ||
120 | create_mmfs_device(); | 102 | fd = open_mmfs_device(); |
121 | |||
122 | fd = open(MMFS_DEVICE_PATH, O_RDWR); | ||
123 | if (fd == -1) | ||
124 | errx(1, "open()"); | ||
125 | 103 | ||
126 | test_bad_ioctl(fd); | 104 | test_bad_ioctl(fd); |
127 | test_bad_unref(fd); | 105 | test_bad_unref(fd); |
diff --git a/tests/mmfs_readwrite.c b/tests/mmfs_readwrite.c new file mode 100644 index 00000000..09d1967d --- /dev/null +++ b/tests/mmfs_readwrite.c | |||
@@ -0,0 +1,125 @@ | |||
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 <string.h> | ||
31 | #include <assert.h> | ||
32 | #include <fcntl.h> | ||
33 | #include <inttypes.h> | ||
34 | #include <errno.h> | ||
35 | #include <sys/stat.h> | ||
36 | #include "mmfs.h" | ||
37 | |||
38 | #define MMFS_BUFFER_SIZE 16384 | ||
39 | |||
40 | int do_read(int fd, int handle, void *buf, int offset, int size) | ||
41 | { | ||
42 | struct mmfs_pread_args read; | ||
43 | |||
44 | /* Ensure that we don't have any convenient data in buf in case | ||
45 | * we fail. | ||
46 | */ | ||
47 | memset(buf, 0xd0, size); | ||
48 | |||
49 | memset(&read, 0, sizeof(read)); | ||
50 | read.handle = handle; | ||
51 | read.data = buf; | ||
52 | read.size = size; | ||
53 | read.offset = offset; | ||
54 | |||
55 | return ioctl(fd, MMFS_IOCTL_PREAD, &read); | ||
56 | } | ||
57 | |||
58 | int do_write(int fd, int handle, void *buf, int offset, int size) | ||
59 | { | ||
60 | struct mmfs_pwrite_args write; | ||
61 | |||
62 | memset(&write, 0, sizeof(write)); | ||
63 | write.handle = handle; | ||
64 | write.data = buf; | ||
65 | write.size = size; | ||
66 | write.offset = offset; | ||
67 | |||
68 | return ioctl(fd, MMFS_IOCTL_PWRITE, &write); | ||
69 | } | ||
70 | |||
71 | int main(int argc, char **argv) | ||
72 | { | ||
73 | int fd; | ||
74 | struct mmfs_alloc_args alloc; | ||
75 | uint8_t expected[MMFS_BUFFER_SIZE]; | ||
76 | uint8_t buf[MMFS_BUFFER_SIZE]; | ||
77 | int ret; | ||
78 | int handle; | ||
79 | |||
80 | fd = open_mmfs_device(); | ||
81 | |||
82 | memset(&alloc, 0, sizeof(alloc)); | ||
83 | alloc.size = MMFS_BUFFER_SIZE; | ||
84 | ret = ioctl(fd, MMFS_IOCTL_ALLOC, &alloc); | ||
85 | assert(ret == 0); | ||
86 | handle = alloc.handle; | ||
87 | |||
88 | printf("Testing contents of newly allocated object.\n"); | ||
89 | ret = do_read(fd, handle, buf, 0, MMFS_BUFFER_SIZE); | ||
90 | assert(ret == 0); | ||
91 | memset(&expected, 0, sizeof(expected)); | ||
92 | assert(memcmp(expected, buf, sizeof(expected)) == 0); | ||
93 | |||
94 | printf("Testing read beyond end of buffer.\n"); | ||
95 | ret = do_read(fd, handle, buf, MMFS_BUFFER_SIZE / 2, MMFS_BUFFER_SIZE); | ||
96 | assert(ret == -1 && errno == EINVAL); | ||
97 | |||
98 | printf("Testing full write of buffer\n"); | ||
99 | memset(buf, 0, sizeof(buf)); | ||
100 | memset(buf + 1024, 0x01, 1024); | ||
101 | memset(expected + 1024, 0x01, 1024); | ||
102 | ret = do_write(fd, handle, buf, 0, MMFS_BUFFER_SIZE); | ||
103 | assert(ret == 0); | ||
104 | ret = do_read(fd, handle, buf, 0, MMFS_BUFFER_SIZE); | ||
105 | assert(ret == 0); | ||
106 | assert(memcmp(buf, expected, sizeof(buf)) == 0); | ||
107 | |||
108 | printf("Testing partial write of buffer\n"); | ||
109 | memset(buf + 4096, 0x02, 1024); | ||
110 | memset(expected + 4096, 0x02, 1024); | ||
111 | ret = do_write(fd, handle, buf + 4096, 4096, 1024); | ||
112 | assert(ret == 0); | ||
113 | ret = do_read(fd, handle, buf, 0, MMFS_BUFFER_SIZE); | ||
114 | assert(ret == 0); | ||
115 | assert(memcmp(buf, expected, sizeof(buf)) == 0); | ||
116 | |||
117 | printf("Testing partial read of buffer\n"); | ||
118 | ret = do_read(fd, handle, buf, 512, 1024); | ||
119 | assert(ret == 0); | ||
120 | assert(memcmp(buf, expected + 512, 1024) == 0); | ||
121 | |||
122 | close(fd); | ||
123 | |||
124 | return 0; | ||
125 | } | ||