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