Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.12 378 lines 9.9 kB view raw
1#include <stddef.h> 2#include <string.h> 3#include <errno.h> 4/* _XOPEN_SOURCE is needed for pread, but we define _GNU_SOURCE, which defines 5 * that. 6 */ 7#include <unistd.h> 8#include <byteswap.h> 9#include <sys/time.h> 10#include <sys/param.h> 11#include <sys/user.h> 12#include <netinet/in.h> 13 14#include "os.h" 15 16#include "cow.h" 17#include "cow_sys.h" 18 19#define PATH_LEN_V1 256 20 21struct cow_header_v1 { 22 int magic; 23 int version; 24 char backing_file[PATH_LEN_V1]; 25 time_t mtime; 26 __u64 size; 27 int sectorsize; 28}; 29 30#define PATH_LEN_V2 MAXPATHLEN 31 32struct cow_header_v2 { 33 __u32 magic; 34 __u32 version; 35 char backing_file[PATH_LEN_V2]; 36 time_t mtime; 37 __u64 size; 38 int sectorsize; 39}; 40 41/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in 42 * case other systems have different values for MAXPATHLEN 43 */ 44#define PATH_LEN_V3 4096 45 46/* Changes from V2 - 47 * PATH_LEN_V3 as described above 48 * Explicitly specify field bit lengths for systems with different 49 * lengths for the usual C types. Not sure whether char or 50 * time_t should be changed, this can be changed later without 51 * breaking compatibility 52 * Add alignment field so that different alignments can be used for the 53 * bitmap and data 54 * Add cow_format field to allow for the possibility of different ways 55 * of specifying the COW blocks. For now, the only value is 0, 56 * for the traditional COW bitmap. 57 * Move the backing_file field to the end of the header. This allows 58 * for the possibility of expanding it into the padding required 59 * by the bitmap alignment. 60 * The bitmap and data portions of the file will be aligned as specified 61 * by the alignment field. This is to allow COW files to be 62 * put on devices with restrictions on access alignments, such as 63 * /dev/raw, with a 512 byte alignment restriction. This also 64 * allows the data to be more aligned more strictly than on 65 * sector boundaries. This is needed for ubd-mmap, which needs 66 * the data to be page aligned. 67 * Fixed (finally!) the rounding bug 68 */ 69 70struct cow_header_v3 { 71 __u32 magic; 72 __u32 version; 73 __u32 mtime; 74 __u64 size; 75 __u32 sectorsize; 76 __u32 alignment; 77 __u32 cow_format; 78 char backing_file[PATH_LEN_V3]; 79}; 80 81/* COW format definitions - for now, we have only the usual COW bitmap */ 82#define COW_BITMAP 0 83 84union cow_header { 85 struct cow_header_v1 v1; 86 struct cow_header_v2 v2; 87 struct cow_header_v3 v3; 88}; 89 90#define COW_MAGIC 0x4f4f4f4d /* MOOO */ 91#define COW_VERSION 3 92 93#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) 94#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) 95 96void cow_sizes(int version, __u64 size, int sectorsize, int align, 97 int bitmap_offset, unsigned long *bitmap_len_out, 98 int *data_offset_out) 99{ 100 if(version < 3){ 101 *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); 102 103 *data_offset_out = bitmap_offset + *bitmap_len_out; 104 *data_offset_out = (*data_offset_out + sectorsize - 1) / 105 sectorsize; 106 *data_offset_out *= sectorsize; 107 } 108 else { 109 *bitmap_len_out = DIV_ROUND(size, sectorsize); 110 *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); 111 112 *data_offset_out = bitmap_offset + *bitmap_len_out; 113 *data_offset_out = ROUND_UP(*data_offset_out, align); 114 } 115} 116 117static int absolutize(char *to, int size, char *from) 118{ 119 char save_cwd[256], *slash; 120 int remaining; 121 122 if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { 123 cow_printf("absolutize : unable to get cwd - errno = %d\n", 124 errno); 125 return(-1); 126 } 127 slash = strrchr(from, '/'); 128 if(slash != NULL){ 129 *slash = '\0'; 130 if(chdir(from)){ 131 *slash = '/'; 132 cow_printf("absolutize : Can't cd to '%s' - " 133 "errno = %d\n", from, errno); 134 return(-1); 135 } 136 *slash = '/'; 137 if(getcwd(to, size) == NULL){ 138 cow_printf("absolutize : unable to get cwd of '%s' - " 139 "errno = %d\n", from, errno); 140 return(-1); 141 } 142 remaining = size - strlen(to); 143 if(strlen(slash) + 1 > remaining){ 144 cow_printf("absolutize : unable to fit '%s' into %d " 145 "chars\n", from, size); 146 return(-1); 147 } 148 strcat(to, slash); 149 } 150 else { 151 if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ 152 cow_printf("absolutize : unable to fit '%s' into %d " 153 "chars\n", from, size); 154 return(-1); 155 } 156 strcpy(to, save_cwd); 157 strcat(to, "/"); 158 strcat(to, from); 159 } 160 chdir(save_cwd); 161 return(0); 162} 163 164int write_cow_header(char *cow_file, int fd, char *backing_file, 165 int sectorsize, int alignment, unsigned long long *size) 166{ 167 struct cow_header_v3 *header; 168 unsigned long modtime; 169 int err; 170 171 err = cow_seek_file(fd, 0); 172 if(err < 0){ 173 cow_printf("write_cow_header - lseek failed, err = %d\n", -err); 174 goto out; 175 } 176 177 err = -ENOMEM; 178 header = cow_malloc(sizeof(*header)); 179 if(header == NULL){ 180 cow_printf("Failed to allocate COW V3 header\n"); 181 goto out; 182 } 183 header->magic = htonl(COW_MAGIC); 184 header->version = htonl(COW_VERSION); 185 186 err = -EINVAL; 187 if(strlen(backing_file) > sizeof(header->backing_file) - 1){ 188 cow_printf("Backing file name \"%s\" is too long - names are " 189 "limited to %d characters\n", backing_file, 190 sizeof(header->backing_file) - 1); 191 goto out_free; 192 } 193 194 if(absolutize(header->backing_file, sizeof(header->backing_file), 195 backing_file)) 196 goto out_free; 197 198 err = os_file_modtime(header->backing_file, &modtime); 199 if(err < 0){ 200 cow_printf("Backing file '%s' mtime request failed, " 201 "err = %d\n", header->backing_file, -err); 202 goto out_free; 203 } 204 205 err = cow_file_size(header->backing_file, size); 206 if(err < 0){ 207 cow_printf("Couldn't get size of backing file '%s', " 208 "err = %d\n", header->backing_file, -err); 209 goto out_free; 210 } 211 212 header->mtime = htonl(modtime); 213 header->size = htonll(*size); 214 header->sectorsize = htonl(sectorsize); 215 header->alignment = htonl(alignment); 216 header->cow_format = COW_BITMAP; 217 218 err = os_write_file(fd, header, sizeof(*header)); 219 if(err != sizeof(*header)){ 220 cow_printf("Write of header to new COW file '%s' failed, " 221 "err = %d\n", cow_file, -err); 222 goto out_free; 223 } 224 err = 0; 225 out_free: 226 cow_free(header); 227 out: 228 return(err); 229} 230 231int file_reader(__u64 offset, char *buf, int len, void *arg) 232{ 233 int fd = *((int *) arg); 234 235 return(pread(fd, buf, len, offset)); 236} 237 238/* XXX Need to sanity-check the values read from the header */ 239 240int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 241 __u32 *version_out, char **backing_file_out, 242 time_t *mtime_out, unsigned long long *size_out, 243 int *sectorsize_out, __u32 *align_out, 244 int *bitmap_offset_out) 245{ 246 union cow_header *header; 247 char *file; 248 int err, n; 249 unsigned long version, magic; 250 251 header = cow_malloc(sizeof(*header)); 252 if(header == NULL){ 253 cow_printf("read_cow_header - Failed to allocate header\n"); 254 return(-ENOMEM); 255 } 256 err = -EINVAL; 257 n = (*reader)(0, (char *) header, sizeof(*header), arg); 258 if(n < offsetof(typeof(header->v1), backing_file)){ 259 cow_printf("read_cow_header - short header\n"); 260 goto out; 261 } 262 263 magic = header->v1.magic; 264 if(magic == COW_MAGIC) { 265 version = header->v1.version; 266 } 267 else if(magic == ntohl(COW_MAGIC)){ 268 version = ntohl(header->v1.version); 269 } 270 /* No error printed because the non-COW case comes through here */ 271 else goto out; 272 273 *version_out = version; 274 275 if(version == 1){ 276 if(n < sizeof(header->v1)){ 277 cow_printf("read_cow_header - failed to read V1 " 278 "header\n"); 279 goto out; 280 } 281 *mtime_out = header->v1.mtime; 282 *size_out = header->v1.size; 283 *sectorsize_out = header->v1.sectorsize; 284 *bitmap_offset_out = sizeof(header->v1); 285 *align_out = *sectorsize_out; 286 file = header->v1.backing_file; 287 } 288 else if(version == 2){ 289 if(n < sizeof(header->v2)){ 290 cow_printf("read_cow_header - failed to read V2 " 291 "header\n"); 292 goto out; 293 } 294 *mtime_out = ntohl(header->v2.mtime); 295 *size_out = ntohll(header->v2.size); 296 *sectorsize_out = ntohl(header->v2.sectorsize); 297 *bitmap_offset_out = sizeof(header->v2); 298 *align_out = *sectorsize_out; 299 file = header->v2.backing_file; 300 } 301 else if(version == 3){ 302 if(n < sizeof(header->v3)){ 303 cow_printf("read_cow_header - failed to read V2 " 304 "header\n"); 305 goto out; 306 } 307 *mtime_out = ntohl(header->v3.mtime); 308 *size_out = ntohll(header->v3.size); 309 *sectorsize_out = ntohl(header->v3.sectorsize); 310 *align_out = ntohl(header->v3.alignment); 311 *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); 312 file = header->v3.backing_file; 313 } 314 else { 315 cow_printf("read_cow_header - invalid COW version\n"); 316 goto out; 317 } 318 err = -ENOMEM; 319 *backing_file_out = cow_strdup(file); 320 if(*backing_file_out == NULL){ 321 cow_printf("read_cow_header - failed to allocate backing " 322 "file\n"); 323 goto out; 324 } 325 err = 0; 326 out: 327 cow_free(header); 328 return(err); 329} 330 331int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, 332 int alignment, int *bitmap_offset_out, 333 unsigned long *bitmap_len_out, int *data_offset_out) 334{ 335 unsigned long long size, offset; 336 char zero = 0; 337 int err; 338 339 err = write_cow_header(cow_file, fd, backing_file, sectorsize, 340 alignment, &size); 341 if(err) 342 goto out; 343 344 *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); 345 cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, 346 bitmap_len_out, data_offset_out); 347 348 offset = *data_offset_out + size - sizeof(zero); 349 err = cow_seek_file(fd, offset); 350 if(err < 0){ 351 cow_printf("cow bitmap lseek failed : err = %d\n", -err); 352 goto out; 353 } 354 355 /* does not really matter how much we write it is just to set EOF 356 * this also sets the entire COW bitmap 357 * to zero without having to allocate it 358 */ 359 err = cow_write_file(fd, &zero, sizeof(zero)); 360 if(err != sizeof(zero)){ 361 cow_printf("Write of bitmap to new COW file '%s' failed, " 362 "err = %d\n", cow_file, -err); 363 err = -EINVAL; 364 goto out; 365 } 366 367 return(0); 368 369 out: 370 return(err); 371} 372 373/* 374 * --------------------------------------------------------------------------- 375 * Local variables: 376 * c-file-style: "linux" 377 * End: 378 */