initial commit with v2.6.9
[linux-2.6.9-moxart.git] / arch / um / drivers / ubd_user.c
blob882d2f7c1ee72a175d26c5d182ec80efb7d89f0c
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 */
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"
26 #include <endian.h>
27 #include <byteswap.h>
29 static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
31 struct uml_stat buf1, buf2;
32 int err;
34 if(from_cmdline == NULL) return(1);
35 if(!strcmp(from_cmdline, from_cow)) return(1);
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);
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);
47 if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
48 return(1);
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);
56 static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
58 unsigned long modtime;
59 long long actual;
60 int err;
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);
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);
76 if(actual != size){
77 printk("Size mismatch (%ld vs %ld) of COW header vs backing "
78 "file\n", size, actual);
79 return(-EINVAL);
81 if(modtime != mtime){
82 printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
83 "file\n", mtime, modtime);
84 return(-EINVAL);
86 return(0);
89 int read_cow_bitmap(int fd, void *buf, int offset, int len)
91 int err;
93 err = os_seek_file(fd, offset);
94 if(err < 0)
95 return(err);
97 err = os_read_file(fd, buf, len);
98 if(err < 0)
99 return(err);
101 return(0);
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)
109 time_t mtime;
110 __u64 size;
111 __u32 version, align;
112 char *backing_file;
113 int fd, err, sectorsize, same, mode = 0644;
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);
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;
133 if(backing_file_out == NULL) return(fd);
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;
142 if(err) return(fd);
144 if(backing_file_out == NULL) return(fd);
146 same = same_backing_files(*backing_file_out, backing_file, file);
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);
157 else {
158 *backing_file_out = backing_file;
159 err = backing_file_mismatch(*backing_file_out, size, mtime);
160 if(err) goto out_close;
163 cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
164 bitmap_len_out, data_offset_out);
166 return(fd);
167 out_close:
168 os_close_file(fd);
169 return(err);
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)
176 int err, fd;
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;
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);
197 /* XXX Just trivial wrappers around os_read_file and os_write_file */
198 int read_ubd_fs(int fd, void *buffer, int len)
200 return(os_read_file(fd, buffer, len));
203 int write_ubd_fs(int fd, char *buffer, int len)
205 return(os_write_file(fd, buffer, len));
208 static int update_bitmap(struct io_thread_req *req)
210 int n;
212 if(req->cow_offset == -1)
213 return(0);
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);
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);
229 return(0);
232 void do_io(struct io_thread_req *req)
234 char *buf;
235 unsigned long len;
236 int n, nsectors, start, end, bit;
237 int err;
238 __u64 off;
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
244 n = *((volatile int *) req->buffer);
245 req->error = update_bitmap(req);
246 return;
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++;
259 off = req->offset + req->offsets[bit] +
260 start * req->sectorsize;
261 len = (end - start) * req->sectorsize;
262 buf = &req->buffer[start * req->sectorsize];
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;
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;
282 } while((n < len) && (n != 0));
283 if (n < len) memset(&buf[n], 0, len - n);
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;
295 start = end;
296 } while(start < nsectors);
298 req->error = update_bitmap(req);
301 /* Changed in start_io_thread, which is serialized by being called only
302 * from ubd_init, which is an initcall.
304 int kernel_fd = -1;
306 /* Only changed by the io thread */
307 int io_count = 0;
309 int io_thread(void *arg)
311 struct io_thread_req req;
312 int n;
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);
325 continue;
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);
336 int start_io_thread(unsigned long sp, int *fd_out)
338 int pid, fds[2], err;
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;
346 kernel_fd = fds[0];
347 *fd_out = fds[1];
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;
357 return(pid);
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);
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: