• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0
2 
3 #define _LARGEFILE64_SOURCE
4 
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <getopt.h>
8 #include <poll.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/prctl.h>
14 #include <unistd.h>
15 #include <iostream>
16 
17 #define SECTOR_SIZE ((__u64)512)
18 #define BUFFER_BYTES 4096
19 
20 #define MAX(a, b) ((a) > (b) ? (a) : (b))
21 
22 /* This should be replaced with linux/dm-user.h. */
23 #ifndef _LINUX_DM_USER_H
24 #define _LINUX_DM_USER_H
25 
26 #include <linux/types.h>
27 
28 #define DM_USER_REQ_MAP_READ 0
29 #define DM_USER_REQ_MAP_WRITE 1
30 #define DM_USER_REQ_MAP_FLUSH 2
31 #define DM_USER_REQ_MAP_DISCARD 3
32 #define DM_USER_REQ_MAP_SECURE_ERASE 4
33 #define DM_USER_REQ_MAP_WRITE_SAME 5
34 #define DM_USER_REQ_MAP_WRITE_ZEROES 6
35 #define DM_USER_REQ_MAP_ZONE_OPEN 7
36 #define DM_USER_REQ_MAP_ZONE_CLOSE 8
37 #define DM_USER_REQ_MAP_ZONE_FINISH 9
38 #define DM_USER_REQ_MAP_ZONE_APPEND 10
39 #define DM_USER_REQ_MAP_ZONE_RESET 11
40 #define DM_USER_REQ_MAP_ZONE_RESET_ALL 12
41 
42 #define DM_USER_REQ_MAP_FLAG_FAILFAST_DEV 0x00001
43 #define DM_USER_REQ_MAP_FLAG_FAILFAST_TRANSPORT 0x00002
44 #define DM_USER_REQ_MAP_FLAG_FAILFAST_DRIVER 0x00004
45 #define DM_USER_REQ_MAP_FLAG_SYNC 0x00008
46 #define DM_USER_REQ_MAP_FLAG_META 0x00010
47 #define DM_USER_REQ_MAP_FLAG_PRIO 0x00020
48 #define DM_USER_REQ_MAP_FLAG_NOMERGE 0x00040
49 #define DM_USER_REQ_MAP_FLAG_IDLE 0x00080
50 #define DM_USER_REQ_MAP_FLAG_INTEGRITY 0x00100
51 #define DM_USER_REQ_MAP_FLAG_FUA 0x00200
52 #define DM_USER_REQ_MAP_FLAG_PREFLUSH 0x00400
53 #define DM_USER_REQ_MAP_FLAG_RAHEAD 0x00800
54 #define DM_USER_REQ_MAP_FLAG_BACKGROUND 0x01000
55 #define DM_USER_REQ_MAP_FLAG_NOWAIT 0x02000
56 #define DM_USER_REQ_MAP_FLAG_CGROUP_PUNT 0x04000
57 #define DM_USER_REQ_MAP_FLAG_NOUNMAP 0x08000
58 #define DM_USER_REQ_MAP_FLAG_HIPRI 0x10000
59 #define DM_USER_REQ_MAP_FLAG_DRV 0x20000
60 #define DM_USER_REQ_MAP_FLAG_SWAP 0x40000
61 
62 #define DM_USER_RESP_SUCCESS 0
63 #define DM_USER_RESP_ERROR 1
64 #define DM_USER_RESP_UNSUPPORTED 2
65 
66 struct dm_user_message {
67     __u64 seq;
68     __u64 type;
69     __u64 flags;
70     __u64 sector;
71     __u64 len;
72     __u8 buf[];
73 };
74 
75 #endif
76 
77 static bool verbose = false;
78 
write_all(int fd,void * buf,size_t len)79 ssize_t write_all(int fd, void* buf, size_t len) {
80     char* buf_c = (char*)buf;
81     ssize_t total = 0;
82     ssize_t once;
83 
84     while (total < static_cast<ssize_t>(len)) {
85         once = write(fd, buf_c + total, len - total);
86         if (once < 0) return once;
87         if (once == 0) {
88             errno = ENOSPC;
89             return 0;
90         }
91         total += once;
92     }
93 
94     return total;
95 }
96 
read_all(int fd,void * buf,size_t len)97 ssize_t read_all(int fd, void* buf, size_t len) {
98     char* buf_c = (char*)buf;
99     ssize_t total = 0;
100     ssize_t once;
101 
102     while (total < static_cast<ssize_t>(len)) {
103         once = read(fd, buf_c + total, len - total);
104         if (once < 0) return once;
105         if (once == 0) {
106             errno = ENOSPC;
107             return 0;
108         }
109         total += once;
110     }
111 
112     return total;
113 }
114 
not_splice(int from,int to,__u64 count)115 int not_splice(int from, int to, __u64 count) {
116     while (count > 0) {
117         char buf[BUFFER_BYTES];
118         __u64 max = count > BUFFER_BYTES ? BUFFER_BYTES : count;
119 
120         if (read_all(from, buf, max) <= 0) {
121             perror("Unable to read");
122             return -EIO;
123         }
124 
125         if (write_all(to, buf, max) <= 0) {
126             perror("Unable to write");
127             return -EIO;
128         }
129 
130         count -= max;
131     }
132 
133     return 0;
134 }
135 
simple_daemon(char * control_path,char * backing_path)136 int simple_daemon(char* control_path, char* backing_path) {
137     int control_fd = open(control_path, O_RDWR);
138     if (control_fd < 0) {
139         fprintf(stderr, "Unable to open control device %s\n", control_path);
140         return -1;
141     }
142 
143     int backing_fd = open(backing_path, O_RDWR);
144     if (backing_fd < 0) {
145         fprintf(stderr, "Unable to open backing device %s\n", backing_path);
146         return -1;
147     }
148 
149     while (1) {
150         struct dm_user_message msg;
151         char* base;
152         __u64 type;
153 
154         if (verbose) std::cerr << "dmuserd: Waiting for message...\n";
155 
156         if (read_all(control_fd, &msg, sizeof(msg)) < 0) {
157             if (errno == ENOTBLK) return 0;
158 
159             perror("unable to read msg");
160             return -1;
161         }
162 
163         if (verbose) {
164             std::string type;
165             switch (msg.type) {
166                 case DM_USER_REQ_MAP_WRITE:
167                     type = "write";
168                     break;
169                 case DM_USER_REQ_MAP_READ:
170                     type = "read";
171                     break;
172                 case DM_USER_REQ_MAP_FLUSH:
173                     type = "flush";
174                     break;
175                 default:
176                     /*
177                      * FIXME: Can't I do "whatever"s here rather that
178                      * std::string("whatever")?
179                      */
180                     type = std::string("(unknown, id=") + std::to_string(msg.type) + ")";
181                     break;
182             }
183 
184             std::string flags;
185             if (msg.flags & DM_USER_REQ_MAP_FLAG_SYNC) {
186                 if (!flags.empty()) flags += "|";
187                 flags += "S";
188             }
189             if (msg.flags & DM_USER_REQ_MAP_FLAG_META) {
190                 if (!flags.empty()) flags += "|";
191                 flags += "M";
192             }
193             if (msg.flags & DM_USER_REQ_MAP_FLAG_FUA) {
194                 if (!flags.empty()) flags += "|";
195                 flags += "FUA";
196             }
197             if (msg.flags & DM_USER_REQ_MAP_FLAG_PREFLUSH) {
198                 if (!flags.empty()) flags += "|";
199                 flags += "F";
200             }
201 
202             std::cerr << "dmuserd: Got " << type << " request " << flags << " for sector "
203                       << std::to_string(msg.sector) << " with length " << std::to_string(msg.len)
204                       << "\n";
205         }
206 
207         type = msg.type;
208         switch (type) {
209             case DM_USER_REQ_MAP_READ:
210                 msg.type = DM_USER_RESP_SUCCESS;
211                 break;
212             case DM_USER_REQ_MAP_WRITE:
213                 if (msg.flags & DM_USER_REQ_MAP_FLAG_PREFLUSH ||
214                     msg.flags & DM_USER_REQ_MAP_FLAG_FUA) {
215                     if (fsync(backing_fd) < 0) {
216                         perror("Unable to fsync(), just sync()ing instead");
217                         sync();
218                     }
219                 }
220                 msg.type = DM_USER_RESP_SUCCESS;
221                 if (lseek64(backing_fd, msg.sector * SECTOR_SIZE, SEEK_SET) < 0) {
222                     perror("Unable to seek");
223                     return -1;
224                 }
225                 if (not_splice(control_fd, backing_fd, msg.len) < 0) {
226                     if (errno == ENOTBLK) return 0;
227                     std::cerr << "unable to handle write data\n";
228                     return -1;
229                 }
230                 if (msg.flags & DM_USER_REQ_MAP_FLAG_FUA) {
231                     if (fsync(backing_fd) < 0) {
232                         perror("Unable to fsync(), just sync()ing instead");
233                         sync();
234                     }
235                 }
236                 break;
237             case DM_USER_REQ_MAP_FLUSH:
238                 msg.type = DM_USER_RESP_SUCCESS;
239                 if (fsync(backing_fd) < 0) {
240                     perror("Unable to fsync(), just sync()ing instead");
241                     sync();
242                 }
243                 break;
244             default:
245                 std::cerr << "dmuserd: unsupported op " << std::to_string(msg.type) << "\n";
246                 msg.type = DM_USER_RESP_UNSUPPORTED;
247                 break;
248         }
249 
250         if (verbose) std::cerr << "dmuserd: Responding to message\n";
251 
252         if (write_all(control_fd, &msg, sizeof(msg)) < 0) {
253             if (errno == ENOTBLK) return 0;
254             perror("unable to write msg");
255             return -1;
256         }
257 
258         switch (type) {
259             case DM_USER_REQ_MAP_READ:
260                 if (verbose) std::cerr << "dmuserd: Sending read data\n";
261                 if (lseek64(backing_fd, msg.sector * SECTOR_SIZE, SEEK_SET) < 0) {
262                     perror("Unable to seek");
263                     return -1;
264                 }
265                 if (not_splice(backing_fd, control_fd, msg.len) < 0) {
266                     if (errno == ENOTBLK) return 0;
267                     std::cerr << "unable to handle read data\n";
268                     return -1;
269                 }
270                 break;
271         }
272     }
273 
274     /* The daemon doesn't actully terminate for this test. */
275     perror("Unable to read from control device");
276     return -1;
277 }
278 
usage(char * prog)279 void usage(char* prog) {
280     printf("Usage: %s\n", prog);
281     printf("	Handles block requests in userspace, backed by memory\n");
282     printf("  -h			Display this help message\n");
283     printf("  -c <control dev>		Control device to use for the test\n");
284     printf("  -b <store path>		The file to use as a backing store, otherwise memory\n");
285     printf("  -v                        Enable verbose mode\n");
286 }
287 
main(int argc,char * argv[])288 int main(int argc, char* argv[]) {
289     char* control_path = NULL;
290     char* backing_path = NULL;
291     char* store;
292     int c;
293 
294     prctl(PR_SET_IO_FLUSHER, 0, 0, 0, 0);
295 
296     while ((c = getopt(argc, argv, "h:c:s:b:v")) != -1) {
297         switch (c) {
298             case 'h':
299                 usage(basename(argv[0]));
300                 exit(0);
301             case 'c':
302                 control_path = strdup(optarg);
303                 break;
304             case 'b':
305                 backing_path = strdup(optarg);
306                 break;
307             case 'v':
308                 verbose = true;
309                 break;
310             default:
311                 usage(basename(argv[0]));
312                 exit(1);
313         }
314     }
315 
316     int r = simple_daemon(control_path, backing_path);
317     if (r) fprintf(stderr, "simple_daemon() errored out\n");
318     return r;
319 }
320