ubd_user.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 622 行
C
622 行
/* * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) * Licensed under the GPL */#include <stddef.h>#include <unistd.h>#include <errno.h>#include <sched.h>#include <signal.h>#include <string.h>#include <netinet/in.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/fcntl.h>#include <sys/socket.h>#include <string.h>#include <sys/mman.h>#include <sys/param.h>#include "asm/types.h"#include "user_util.h"#include "kern_util.h"#include "user.h"#include "ubd_user.h"#include "os.h"#include <endian.h>#include <byteswap.h>#if __BYTE_ORDER == __BIG_ENDIAN# define ntohll(x) (x)# define htonll(x) (x)#elif __BYTE_ORDER == __LITTLE_ENDIAN# define ntohll(x) bswap_64(x)# define htonll(x) bswap_64(x)#else#error "__BYTE_ORDER not defined"#endif#define PATH_LEN_V1 256struct cow_header_v1 { int magic; int version; char backing_file[PATH_LEN_V1]; time_t mtime; __u64 size; int sectorsize;};#define PATH_LEN_V2 MAXPATHLENstruct cow_header_v2 { unsigned long magic; unsigned long version; char backing_file[PATH_LEN_V2]; time_t mtime; __u64 size; int sectorsize;};union cow_header { struct cow_header_v1 v1; struct cow_header_v2 v2;};#define COW_MAGIC 0x4f4f4f4d /* MOOO */#define COW_VERSION 2static void sizes(__u64 size, int sectorsize, int bitmap_offset, unsigned long *bitmap_len_out, int *data_offset_out){ *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); *data_offset_out = bitmap_offset + *bitmap_len_out; *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; *data_offset_out *= sectorsize;}static int read_cow_header(int fd, int *magic_out, char **backing_file_out, time_t *mtime_out, __u64 *size_out, int *sectorsize_out, int *bitmap_offset_out){ union cow_header *header; char *file; int err, n; unsigned long version, magic; header = um_kmalloc(sizeof(*header)); if(header == NULL){ printk("read_cow_header - Failed to allocate header\n"); return(-ENOMEM); } err = -EINVAL; n = read(fd, header, sizeof(*header)); if(n < offsetof(typeof(header->v1), backing_file)){ printk("read_cow_header - short header\n"); goto out; } magic = header->v1.magic; if(magic == COW_MAGIC) { version = header->v1.version; } else if(magic == ntohl(COW_MAGIC)){ version = ntohl(header->v1.version); } else goto out; *magic_out = COW_MAGIC; if(version == 1){ if(n < sizeof(header->v1)){ printk("read_cow_header - failed to read V1 header\n"); goto out; } *mtime_out = header->v1.mtime; *size_out = header->v1.size; *sectorsize_out = header->v1.sectorsize; *bitmap_offset_out = sizeof(header->v1); file = header->v1.backing_file; } else if(version == 2){ if(n < sizeof(header->v2)){ printk("read_cow_header - failed to read V2 header\n"); goto out; } *mtime_out = ntohl(header->v2.mtime); *size_out = ntohll(header->v2.size); *sectorsize_out = ntohl(header->v2.sectorsize); *bitmap_offset_out = sizeof(header->v2); file = header->v2.backing_file; } else { printk("read_cow_header - invalid COW version\n"); goto out; } err = -ENOMEM; *backing_file_out = uml_strdup(file); if(*backing_file_out == NULL){ printk("read_cow_header - failed to allocate backing file\n"); goto out; } err = 0; out: kfree(header); return(err);}static int same_backing_files(char *from_cmdline, char *from_cow, char *cow){ struct stat buf1, buf2; if(from_cmdline == NULL) return(1); if(!strcmp(from_cmdline, from_cow)) return(1); if(stat(from_cmdline, &buf1) < 0){ printk("Couldn't stat '%s', errno = %d\n", from_cmdline, errno); return(1); } if(stat(from_cow, &buf2) < 0){ printk("Couldn't stat '%s', errno = %d\n", from_cow, errno); return(1); } if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino)) return(1); printk("Backing file mismatch - \"%s\" requested,\n" "\"%s\" specified in COW header of \"%s\"\n", from_cmdline, from_cow, cow); return(0);}static int backing_file_mismatch(char *file, __u64 size, time_t mtime){ struct stat64 buf; long long actual; int err; if(stat64(file, &buf) < 0){ printk("Failed to stat backing file \"%s\", errno = %d\n", file, errno); return(-errno); } err = os_file_size(file, &actual); if(err){ printk("Failed to get size of backing file \"%s\", " "errno = %d\n", file, -err); return(err); } if(actual != size){ printk("Size mismatch (%ld vs %ld) of COW header vs backing " "file\n", size, actual); return(-EINVAL); } if(buf.st_mtime != mtime){ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " "file\n", mtime, buf.st_mtime); return(-EINVAL); } return(0);}int read_cow_bitmap(int fd, void *buf, int offset, int len){ int err; err = os_seek_file(fd, offset); if(err != 0) return(-errno); err = read(fd, buf, len); if(err < 0) return(-errno); return(0);}static int absolutize(char *to, int size, char *from){ char save_cwd[256], *slash; int remaining; if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { printk("absolutize : unable to get cwd - errno = %d\n", errno); return(-1); } slash = strrchr(from, '/'); if(slash != NULL){ *slash = '\0'; if(chdir(from)){ *slash = '/'; printk("absolutize : Can't cd to '%s' - errno = %d\n", from, errno); return(-1); } *slash = '/'; if(getcwd(to, size) == NULL){ printk("absolutize : unable to get cwd of '%s' - " "errno = %d\n", from, errno); return(-1); } remaining = size - strlen(to); if(strlen(slash) + 1 > remaining){ printk("absolutize : unable to fit '%s' into %d " "chars\n", from, size); return(-1); } strcat(to, slash); } else { if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ printk("absolutize : unable to fit '%s' into %d " "chars\n", from, size); return(-1); } strcpy(to, save_cwd); strcat(to, "/"); strcat(to, from); } chdir(save_cwd); return(0);}static int write_cow_header(char *cow_file, int fd, char *backing_file, int sectorsize, long long *size){ struct cow_header_v2 *header; struct stat64 buf; int err; err = os_seek_file(fd, 0); if(err != 0){ printk("write_cow_header - lseek failed, errno = %d\n", errno); return(-errno); } err = -ENOMEM; header = um_kmalloc(sizeof(*header)); if(header == NULL){ printk("Failed to allocate COW V2 header\n"); goto out; } header->magic = htonl(COW_MAGIC); header->version = htonl(COW_VERSION); err = -EINVAL; if(strlen(backing_file) > sizeof(header->backing_file) - 1){ printk("Backing file name \"%s\" is too long - names are " "limited to %d characters\n", backing_file, sizeof(header->backing_file) - 1); goto out_free; } if(absolutize(header->backing_file, sizeof(header->backing_file), backing_file)) goto out_free; err = stat64(header->backing_file, &buf); if(err < 0){ printk("Stat of backing file '%s' failed, errno = %d\n", header->backing_file, errno); err = -errno; goto out_free; } err = os_file_size(header->backing_file, size); if(err){ printk("Couldn't get size of backing file '%s', errno = %d\n", header->backing_file, -*size); goto out_free; } header->mtime = htonl(buf.st_mtime); header->size = htonll(*size); header->sectorsize = htonl(sectorsize); err = write(fd, header, sizeof(*header)); if(err != sizeof(*header)){ printk("Write of header to new COW file '%s' failed, " "errno = %d\n", cow_file, errno); goto out_free; } err = 0; out_free: kfree(header); out: return(err);}int open_ubd_file(char *file, struct openflags *openflags, char **backing_file_out, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out, int *create_cow_out){ time_t mtime; __u64 size; char *backing_file; int fd, err, sectorsize, magic, same, mode = 0644; if((fd = os_open_file(file, *openflags, mode)) < 0){ if((fd == -ENOENT) && (create_cow_out != NULL)) *create_cow_out = 1; if(!openflags->w || ((errno != EROFS) && (errno != EACCES))) return(-errno); openflags->w = 0; if((fd = os_open_file(file, *openflags, mode)) < 0) return(fd); } if(backing_file_out == NULL) return(fd); err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, §orsize, bitmap_offset_out); if(err && (*backing_file_out != NULL)){ printk("Failed to read COW header from COW file \"%s\", " "errno = %d\n", file, err); goto error; } if(err) return(fd); if(backing_file_out == NULL) return(fd); same = same_backing_files(*backing_file_out, backing_file, file); if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ printk("Switching backing file to '%s'\n", *backing_file_out); err = write_cow_header(file, fd, *backing_file_out, sectorsize, &size); if(err){ printk("Switch failed, errno = %d\n", err); return(err); } } else { *backing_file_out = backing_file; err = backing_file_mismatch(*backing_file_out, size, mtime); if(err) goto error; } sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, data_offset_out); return(fd); error: close(fd); return(err);}int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, int sectorsize, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out){ __u64 blocks; long zero; int err, fd, i; long long size; flags.c = 1; fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); if(fd < 0){ err = fd; printk("Open of COW file '%s' failed, errno = %d\n", cow_file, -err); goto out; } err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size); if(err) goto out_close; blocks = (size + sectorsize - 1) / sectorsize; blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8); zero = 0; for(i = 0; i < blocks; i++){ err = write(fd, &zero, sizeof(zero)); if(err != sizeof(zero)){ printk("Write of bitmap to new COW file '%s' failed, " "errno = %d\n", cow_file, errno); goto out_close; } } sizes(size, sectorsize, sizeof(struct cow_header_v2), bitmap_len_out, data_offset_out); *bitmap_offset_out = sizeof(struct cow_header_v2); return(fd); out_close: close(fd); out: return(err);}int read_ubd_fs(int fd, void *buffer, int len){ int n; n = read(fd, buffer, len); if(n < 0) return(-errno); else return(n);}int write_ubd_fs(int fd, char *buffer, int len){ int n; n = write(fd, buffer, len); if(n < 0) return(-errno); else return(n);}int ubd_is_dir(char *file){ struct stat64 buf; if(stat64(file, &buf) < 0) return(0); return(S_ISDIR(buf.st_mode));}void do_io(struct io_thread_req *req){ char *buf; unsigned long len; int n, nsectors, start, end, bit; __u64 off; nsectors = req->length / req->sectorsize; start = 0; do { bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask); end = start; while((end < nsectors) && (ubd_test_bit(end, (unsigned char *) &req->sector_mask) == bit)) end++; if(end != nsectors) printk("end != nsectors\n"); off = req->offset + req->offsets[bit] + start * req->sectorsize; len = (end - start) * req->sectorsize; buf = &req->buffer[start * req->sectorsize]; if(os_seek_file(req->fds[bit], off) != 0){ printk("do_io - lseek failed : errno = %d\n", errno); req->error = 1; return; } if(req->op == UBD_READ){ n = 0; do { buf = &buf[n]; len -= n; n = read(req->fds[bit], buf, len); if (n < 0) { printk("do_io - read returned %d : " "errno = %d fd = %d\n", n, errno, req->fds[bit]); req->error = 1; return; } } while((n < len) && (n != 0)); if (n < len) memset(&buf[n], 0, len - n); } else { n = write(req->fds[bit], buf, len); if(n != len){ printk("do_io - write returned %d : " "errno = %d fd = %d\n", n, errno, req->fds[bit]); req->error = 1; return; } } start = end; } while(start < nsectors); if(req->cow_offset != -1){ if(os_seek_file(req->fds[1], req->cow_offset) != 0){ printk("do_io - bitmap lseek failed : errno = %d\n", errno); req->error = 1; return; } n = write(req->fds[1], &req->bitmap_words, sizeof(req->bitmap_words)); if(n != sizeof(req->bitmap_words)){ printk("do_io - bitmap update returned %d : " "errno = %d fd = %d\n", n, errno, req->fds[1]); req->error = 1; return; } } req->error = 0; return;}/* Changed in start_io_thread, which is serialized by being called only * from ubd_init, which is an initcall. */int kernel_fd = -1;/* Only changed by the io thread */int io_count = 0;int io_thread(void *arg){ struct io_thread_req req; int n; signal(SIGWINCH, SIG_IGN); while(1){ n = read(kernel_fd, &req, sizeof(req)); if(n < 0) printk("io_thread - read returned %d, errno = %d\n", n, errno); else if(n < sizeof(req)){ printk("io_thread - short read : length = %d\n", n); continue; } io_count++; do_io(&req); n = write(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)) printk("io_thread - write failed, errno = %d\n", errno); }}int start_io_thread(unsigned long sp, int *fd_out){ int pid, fds[2], err; err = os_pipe(fds, 1, 1); if(err){ printk("start_io_thread - os_pipe failed, errno = %d\n", -err); return(-1); } kernel_fd = fds[0]; *fd_out = fds[1]; pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(pid < 0){ printk("start_io_thread - clone failed : errno = %d\n", errno); return(-errno); } return(pid);}#ifdef notdefint start_io_thread(unsigned long sp, int *fd_out){ int pid; if((kernel_fd = get_pty()) < 0) return(-1); raw(kernel_fd, 0); if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){ printk("Couldn't open tty for IO\n"); return(-1); } pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(pid < 0){ printk("start_io_thread - clone failed : errno = %d\n", errno); return(-errno); } return(pid);}#endif/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?