400c2a08d19b874e592db520df9a35f79f313da8
[linux-flexiantxendom0-3.2.10.git] / arch / um / drivers / ubd_user.c
1 /* 
2  * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3  * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
4  * Licensed under the GPL
5  */
6
7 #include <stddef.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <sched.h>
11 #include <signal.h>
12 #include <string.h>
13 #include <netinet/in.h>
14 #include <sys/time.h>
15 #include <sys/socket.h>
16 #include <sys/mman.h>
17 #include <sys/param.h>
18 #include "asm/types.h"
19 #include "user_util.h"
20 #include "kern_util.h"
21 #include "user.h"
22 #include "ubd_user.h"
23 #include "os.h"
24 #include "cow.h"
25
26 #include <endian.h>
27 #include <byteswap.h>
28
29 static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
30 {
31         struct uml_stat buf1, buf2;
32         int err;
33
34         if(from_cmdline == NULL) return(1);
35         if(!strcmp(from_cmdline, from_cow)) return(1);
36
37         err = os_stat_file(from_cmdline, &buf1);
38         if(err < 0){
39                 printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
40                 return(1);
41         }
42         err = os_stat_file(from_cow, &buf2);
43         if(err < 0){
44                 printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
45                 return(1);
46         }
47         if((buf1.ust_major == buf2.ust_major) && 
48            (buf1.ust_minor == buf2.ust_minor) && 
49            (buf1.ust_ino == buf2.ust_ino))
50                 return(1);
51
52         printk("Backing file mismatch - \"%s\" requested,\n"
53                "\"%s\" specified in COW header of \"%s\"\n",
54                from_cmdline, from_cow, cow);
55         return(0);
56 }
57
58 static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
59 {
60         unsigned long modtime;
61         long long actual;
62         int err;
63
64         err = os_file_modtime(file, &modtime);
65         if(err < 0){
66                 printk("Failed to get modification time of backing file "
67                        "\"%s\", err = %d\n", file, -err);
68                 return(err);
69         }
70
71         err = os_file_size(file, &actual);
72         if(err < 0){
73                 printk("Failed to get size of backing file \"%s\", "
74                        "err = %d\n", file, -err);
75                 return(err);
76         }
77
78         if(actual != size){
79                 printk("Size mismatch (%ld vs %ld) of COW header vs backing "
80                        "file\n", size, actual);
81                 return(-EINVAL);
82         }
83         if(modtime != mtime){
84                 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
85                        "file\n", mtime, modtime);
86                 return(-EINVAL);
87         }
88         return(0);
89 }
90
91 int read_cow_bitmap(int fd, void *buf, int offset, int len)
92 {
93         int err;
94
95         err = os_seek_file(fd, offset);
96         if(err < 0) 
97                 return(err);
98
99         err = os_read_file(fd, buf, len);
100         if(err < 0) 
101                 return(err);
102
103         return(0);
104 }
105
106 int open_ubd_file(char *file, struct openflags *openflags, 
107                   char **backing_file_out, int *bitmap_offset_out, 
108                   unsigned long *bitmap_len_out, int *data_offset_out, 
109                   int *create_cow_out)
110 {
111         time_t mtime;
112         __u64 size;
113         __u32 version, align;
114         char *backing_file;
115         int fd, err, sectorsize, same, mode = 0644;
116
117         fd = os_open_file(file, *openflags, mode);
118         if(fd < 0){
119                 if((fd == -ENOENT) && (create_cow_out != NULL))
120                         *create_cow_out = 1;
121                 if(!openflags->w ||
122                    ((errno != EROFS) && (errno != EACCES))) return(-errno);
123                 openflags->w = 0;
124                 fd = os_open_file(file, *openflags, mode); 
125                 if(fd < 0) 
126                         return(fd);
127         }
128
129         err = os_lock_file(fd, openflags->w);
130         if(err < 0){
131                 printk("Failed to lock '%s', err = %d\n", file, -err);
132                 goto out_close;
133         }
134         
135         if(backing_file_out == NULL) return(fd);
136
137         err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
138                               &size, &sectorsize, &align, bitmap_offset_out);
139         if(err && (*backing_file_out != NULL)){
140                 printk("Failed to read COW header from COW file \"%s\", "
141                        "errno = %d\n", file, -err);
142                 goto out_close;
143         }
144         if(err) return(fd);
145
146         if(backing_file_out == NULL) return(fd);
147         
148         same = same_backing_files(*backing_file_out, backing_file, file);
149
150         if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
151                 printk("Switching backing file to '%s'\n", *backing_file_out);
152                 err = write_cow_header(file, fd, *backing_file_out,
153                                        sectorsize, align, &size);
154                 if(err){
155                         printk("Switch failed, errno = %d\n", -err);
156                         return(err);
157                 }
158         }
159         else {
160                 *backing_file_out = backing_file;
161                 err = backing_file_mismatch(*backing_file_out, size, mtime);
162                 if(err) goto out_close;
163         }
164
165         cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, 
166                   bitmap_len_out, data_offset_out);
167
168         return(fd);
169  out_close:
170         os_close_file(fd);
171         return(err);
172 }
173
174 int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
175                     int sectorsize, int alignment, int *bitmap_offset_out, 
176                     unsigned long *bitmap_len_out, int *data_offset_out)
177 {
178         int err, fd;
179
180         flags.c = 1;
181         fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
182         if(fd < 0){
183                 err = fd;
184                 printk("Open of COW file '%s' failed, errno = %d\n", cow_file,
185                        -err);
186                 goto out;
187         }
188
189         err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
190                             bitmap_offset_out, bitmap_len_out, 
191                             data_offset_out);
192         if(!err)
193                 return(fd);
194
195         os_close_file(fd);
196  out:
197         return(err);
198 }
199
200 /* XXX Just trivial wrappers around os_read_file and os_write_file */
201 int read_ubd_fs(int fd, void *buffer, int len)
202 {
203         return(os_read_file(fd, buffer, len));
204 }
205
206 int write_ubd_fs(int fd, char *buffer, int len)
207 {
208         return(os_write_file(fd, buffer, len));
209 }
210
211 static int update_bitmap(struct io_thread_req *req)
212 {
213         int n;
214
215         if(req->cow_offset == -1)
216                 return(0);
217
218         n = os_seek_file(req->fds[1], req->cow_offset);
219         if(n < 0){
220                 printk("do_io - bitmap lseek failed : err = %d\n", -n);
221                 return(1);
222         }
223
224         n = os_write_file(req->fds[1], &req->bitmap_words,
225                           sizeof(req->bitmap_words));
226         if(n != sizeof(req->bitmap_words)){
227                 printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
228                        req->fds[1]);
229                 return(1);
230         }
231
232         return(0);
233 }
234
235 void do_io(struct io_thread_req *req)
236 {
237         char *buf;
238         unsigned long len;
239         int n, nsectors, start, end, bit;
240         int err;
241         __u64 off;
242
243         if(req->op == UBD_MMAP){
244                 /* Touch the page to force the host to do any necessary IO to 
245                  * get it into memory 
246                  */
247                 n = *((volatile int *) req->buffer);
248                 req->error = update_bitmap(req);
249                 return;
250         }
251
252         nsectors = req->length / req->sectorsize;
253         start = 0;
254         do {
255                 bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);
256                 end = start;
257                 while((end < nsectors) && 
258                       (ubd_test_bit(end, (unsigned char *) 
259                                     &req->sector_mask) == bit))
260                         end++;
261
262                 off = req->offset + req->offsets[bit] + 
263                         start * req->sectorsize;
264                 len = (end - start) * req->sectorsize;
265                 buf = &req->buffer[start * req->sectorsize];
266
267                 err = os_seek_file(req->fds[bit], off);
268                 if(err < 0){
269                         printk("do_io - lseek failed : err = %d\n", -err);
270                         req->error = 1;
271                         return;
272                 }
273                 if(req->op == UBD_READ){
274                         n = 0;
275                         do {
276                                 buf = &buf[n];
277                                 len -= n;
278                                 n = os_read_file(req->fds[bit], buf, len);
279                                 if (n < 0) {
280                                         printk("do_io - read failed, err = %d "
281                                                "fd = %d\n", -n, req->fds[bit]);
282                                         req->error = 1;
283                                         return;
284                                 }
285                         } while((n < len) && (n != 0));
286                         if (n < len) memset(&buf[n], 0, len - n);
287                 }
288                 else {
289                         n = os_write_file(req->fds[bit], buf, len);
290                         if(n != len){
291                                 printk("do_io - write failed err = %d "
292                                        "fd = %d\n", -n, req->fds[bit]);
293                                 req->error = 1;
294                                 return;
295                         }
296                 }
297
298                 start = end;
299         } while(start < nsectors);
300
301         req->error = update_bitmap(req);
302 }
303
304 /* Changed in start_io_thread, which is serialized by being called only
305  * from ubd_init, which is an initcall.
306  */
307 int kernel_fd = -1;
308
309 /* Only changed by the io thread */
310 int io_count = 0;
311
312 int io_thread(void *arg)
313 {
314         struct io_thread_req req;
315         int n;
316
317         signal(SIGWINCH, SIG_IGN);
318         while(1){
319                 n = os_read_file(kernel_fd, &req, sizeof(req));
320                 if(n != sizeof(req)){
321                         if(n < 0)
322                                 printk("io_thread - read failed, fd = %d, "
323                                        "err = %d\n", kernel_fd, -n);
324                         else {
325                                 printk("io_thread - short read, fd = %d, "
326                                        "length = %d\n", kernel_fd, n);
327                         }
328                         continue;
329                 }
330                 io_count++;
331                 do_io(&req);
332                 n = os_write_file(kernel_fd, &req, sizeof(req));
333                 if(n != sizeof(req))
334                         printk("io_thread - write failed, fd = %d, err = %d\n",
335                                kernel_fd, -n);
336         }
337 }
338
339 int start_io_thread(unsigned long sp, int *fd_out)
340 {
341         int pid, fds[2], err;
342
343         err = os_pipe(fds, 1, 1);
344         if(err < 0){
345                 printk("start_io_thread - os_pipe failed, err = %d\n", -err);
346                 goto out;
347         }
348
349         kernel_fd = fds[0];
350         *fd_out = fds[1];
351
352         pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
353                     NULL);
354         if(pid < 0){
355                 printk("start_io_thread - clone failed : errno = %d\n", errno);
356                 goto out_close;
357         }
358
359         return(pid);
360
361  out_close:
362         os_close_file(fds[0]);
363         os_close_file(fds[1]);
364         kernel_fd = -1;
365         *fd_out = -1;
366  out:
367         return(err);
368 }
369
370 /*
371  * Overrides for Emacs so that we follow Linus's tabbing style.
372  * Emacs will notice this stuff at the end of the file and automatically
373  * adjust the settings for this buffer only.  This must remain at the end
374  * of the file.
375  * ---------------------------------------------------------------------------
376  * Local variables:
377  * c-file-style: "linux"
378  * End:
379  */