aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--linux-core/mmfs_drv.c113
-rw-r--r--linux-core/mmfs_drv.h7
-rw-r--r--shared-core/mmfs.h7
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/drmtest.c33
-rw-r--r--tests/drmtest.h1
-rw-r--r--tests/mmfs_basic.c24
-rw-r--r--tests/mmfs_readwrite.c125
9 files changed, 280 insertions, 34 deletions
diff --git a/.gitignore b/.gitignore
index fe64a289..5a4bcb13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,6 +59,7 @@ tests/getstats
59tests/getversion 59tests/getversion
60tests/lock 60tests/lock
61tests/mmfs_basic 61tests/mmfs_basic
62tests/mmfs_readwrite
62tests/openclose 63tests/openclose
63tests/setversion 64tests/setversion
64tests/updatedraw 65tests/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. */
113static struct mmfs_object *
114mmfs_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 */
169static int 192static int
170mmfs_unreference_ioctl(struct inode *inode, struct file *filp, 193mmfs_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 */
213static int
214mmfs_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 */
252static int
253mmfs_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
185static int 286static int
186mmfs_ioctl(struct inode *inode, struct file *filp, 287mmfs_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 {
54struct mmfs_file { 54struct 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
64void mmfs_object_reference(struct mmfs_object *obj); 61void 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
28EXTRA_PROGRAMS = $(TESTS) 29EXTRA_PROGRAMS = $(TESTS)
29CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) 30CLEANFILES = $(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 */
32int drm_open_any(void) 34int drm_open_any(void)
@@ -81,3 +83,34 @@ int drm_open_any_master(void)
81 abort(); 83 abort();
82} 84}
83 85
86static void
87create_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
104int
105open_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
36int drm_open_any(void); 36int drm_open_any(void);
37int drm_open_any_master(void); 37int drm_open_any_master(void);
38int 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
38static void 38static void
39create_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
56static void
57test_bad_unref(int fd) 39test_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
40int 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
58int 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
71int 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}