remove close with negative file descriptor
[archipelago] / xseg / drivers / xseg_xsegdev.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/ioctl.h>
8 #include <sys/mman.h>
9 #include <sys/syscall.h>
10 #include <fcntl.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <signal.h>
14 #include <xseg/xseg.h>
15 #include <sys/util.h>
16 #include <xsegdev.h>
17
18 #define ERRSIZE 512
19 static char errbuf[ERRSIZE];
20
21 #define XSEG_DEVICE "/dev/xsegdev"
22 static int fdev = -1;
23
24 static int opendev(void)
25 {
26         if (fdev >= 0)
27                 return fdev;
28
29         fdev = open(XSEG_DEVICE, O_RDWR);
30         if (fdev < 0) {
31                 LOGMSG("Cannot open %s: %s\n", XSEG_DEVICE,
32                         strerror_r(errno, errbuf, ERRSIZE));
33                 fdev = -1;
34         }
35         return fdev;
36 }
37
38 static int closedev(void)
39 {
40         int r;
41         if (fdev < 0)
42                 return 0;
43
44         r = close(fdev);
45         if (r < 0) {
46                 LOGMSG("Cannot close %s: %s\n", XSEG_DEVICE,
47                         strerror_r(errno, errbuf, ERRSIZE));
48                 return -1;
49         } else
50                 fdev = -1;
51
52         return 0;
53 }
54
55 static long xsegdev_allocate(const char *name, uint64_t size)
56 {
57         int fd;
58         long oldsize;
59
60         fd = opendev();
61         if (fd < 0)
62                 return fd;
63
64         oldsize = ioctl(fd, XSEGDEV_IOC_SEGSIZE, 0);
65         if (oldsize >= 0) {
66                 LOGMSG("Destroying old segment\n");
67                 if (ioctl(fd, XSEGDEV_IOC_DESTROYSEG, 0)) {
68                         LOGMSG("Failed to destroy old segment");
69                         closedev();
70                         return -2;
71                 }
72         }
73
74         if (ioctl(fd, XSEGDEV_IOC_CREATESEG, size)) {
75                 LOGMSG("Failed to create segment");
76                 closedev();
77                 return -3;
78         }
79
80         return 0;
81 }
82
83 static long xsegdev_deallocate(const char *name)
84 {
85         int fd;
86         fd = open(XSEG_DEVICE, O_RDWR);
87         if (fd < 0) {
88                 LOGMSG("Cannot open %s: %s\n", XSEG_DEVICE,
89                         strerror_r(errno, errbuf, ERRSIZE));
90                 return -1;
91         }
92
93         if (ioctl(fd, XSEGDEV_IOC_DESTROYSEG, 0)) {
94                 LOGMSG("Failed to destroy old segment");
95                 return -2;
96         }
97
98         closedev();
99         return 0;
100 }
101
102 static void *xsegdev_map(const char *name, uint64_t size)
103 {
104         struct xseg *xseg;
105         int fd;
106         fd = opendev();
107         if (fd < 0)
108                 return NULL;
109
110         xseg = mmap (   XSEG_BASE_AS_PTR,
111                         size,
112                         PROT_READ | PROT_WRITE,
113                         MAP_SHARED | MAP_FIXED /* | MAP_LOCKED */,
114                         fd, 0   );
115
116         if (xseg == MAP_FAILED) {
117                 LOGMSG("Could not map segment: %s\n",
118                         strerror_r(errno, errbuf, ERRSIZE));
119                 closedev();
120                 return NULL;
121         }
122
123         return xseg;
124 }
125
126 static void xsegdev_unmap(void *ptr, uint64_t size)
127 {
128         struct xseg *xseg = ptr;
129         (void)munmap(xseg, xseg->segment_size);
130 }
131
132
133 static struct xseg_type xseg_xsegdev = {
134         /* xseg_operations */
135         {
136                 .malloc         = malloc,
137                 .mfree          = free,
138                 .allocate       = xsegdev_allocate,
139                 .deallocate     = xsegdev_deallocate,
140                 .map            = xsegdev_map,
141                 .unmap          = xsegdev_unmap
142         },
143         /* name */
144         "xsegdev"
145 };
146
147 static int xsegdev_signal_init(void)
148 {
149         return 0;
150 }
151
152 static void xsegdev_signal_quit(void) { }
153
154 static int xsegdev_prepare_wait(struct xseg_port *port)
155 {
156         return -1;
157 }
158
159 static int xsegdev_cancel_wait(struct xseg_port *port)
160 {
161         return -1;
162 }
163
164 static int xsegdev_wait_signal(struct xseg_port *port, uint32_t timeout)
165 {
166         return -1;
167 }
168
169 static int xsegdev_signal(struct xseg_port *port)
170 {
171         return write(opendev(), NULL, 0);
172 }
173
174 static void *xsegdev_malloc(uint64_t size)
175 {
176         return NULL;
177 }
178
179 static void *xsegdev_realloc(void *mem, uint64_t size)
180 {
181         return NULL;
182 }
183
184 static void xsegdev_mfree(void *mem) { }
185
186 static struct xseg_peer xseg_peer_xsegdev = {
187         /* xseg signal operations */
188         {
189                 .signal_init = xsegdev_signal_init,
190                 .signal_quit = xsegdev_signal_quit,
191                 .prepare_wait = xsegdev_prepare_wait,
192                 .cancel_wait = xsegdev_cancel_wait,
193                 .wait_signal = xsegdev_wait_signal,
194                 .signal = xsegdev_signal,
195                 .malloc = xsegdev_malloc,
196                 .realloc = xsegdev_realloc,
197                 .mfree = xsegdev_mfree
198         },
199         /* name */
200         "xsegdev"
201 };
202
203 void xseg_xsegdev_init(void)
204 {
205         xseg_register_type(&xseg_xsegdev);
206         xseg_register_peer(&xseg_peer_xsegdev);
207 }
208