1 /** 2 * libf2fs.c 3 * 4 * Copyright (c) 2013 Samsung Electronics Co., Ltd. 5 * http://www.samsung.com/ 6 * 7 * Dual licensed under the GPL or LGPL version 2 licenses. 8 */ 9 #define _LARGEFILE64_SOURCE 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <errno.h> 15 #include <unistd.h> 16 #include <fcntl.h> 17 #ifdef HAVE_MNTENT_H 18 #include <mntent.h> 19 #endif 20 #include <time.h> 21 #ifndef ANDROID_WINDOWS_HOST 22 #include <sys/stat.h> 23 #include <sys/mount.h> 24 #include <sys/ioctl.h> 25 #endif 26 #ifdef HAVE_LINUX_HDREG_H 27 #include <linux/hdreg.h> 28 #endif 29 30 #include <f2fs_fs.h> 31 32 struct f2fs_configuration c; 33 34 #ifdef WITH_ANDROID 35 #include <sparse/sparse.h> 36 struct sparse_file *f2fs_sparse_file; 37 static char **blocks; 38 u_int64_t blocks_count; 39 #endif 40 41 static int __get_device_fd(__u64 *offset) 42 { 43 __u64 blk_addr = *offset >> F2FS_BLKSIZE_BITS; 44 int i; 45 46 for (i = 0; i < c.ndevs; i++) { 47 if (c.devices[i].start_blkaddr <= blk_addr && 48 c.devices[i].end_blkaddr >= blk_addr) { 49 *offset -= 50 c.devices[i].start_blkaddr << F2FS_BLKSIZE_BITS; 51 return c.devices[i].fd; 52 } 53 } 54 return -1; 55 } 56 57 #ifndef HAVE_LSEEK64 58 typedef off_t off64_t; 59 60 static inline off64_t lseek64(int fd, __u64 offset, int set) 61 { 62 return lseek(fd, offset, set); 63 } 64 #endif 65 66 /* 67 * IO interfaces 68 */ 69 int dev_read_version(void *buf, __u64 offset, size_t len) 70 { 71 if (c.sparse_mode) 72 return 0; 73 if (lseek64(c.kd, (off64_t)offset, SEEK_SET) < 0) 74 return -1; 75 if (read(c.kd, buf, len) < 0) 76 return -1; 77 return 0; 78 } 79 80 #ifdef WITH_ANDROID 81 static int sparse_read_blk(__u64 block, int count, void *buf) 82 { 83 int i; 84 char *out = buf; 85 __u64 cur_block; 86 87 for (i = 0; i < count; ++i) { 88 cur_block = block + i; 89 if (blocks[cur_block]) 90 memcpy(out + (i * F2FS_BLKSIZE), 91 blocks[cur_block], F2FS_BLKSIZE); 92 else if (blocks) 93 memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE); 94 } 95 return 0; 96 } 97 98 static int sparse_write_blk(__u64 block, int count, const void *buf) 99 { 100 int i; 101 __u64 cur_block; 102 const char *in = buf; 103 104 for (i = 0; i < count; ++i) { 105 cur_block = block + i; 106 if (!blocks[cur_block]) { 107 blocks[cur_block] = calloc(1, F2FS_BLKSIZE); 108 if (!blocks[cur_block]) 109 return -ENOMEM; 110 } 111 memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE), 112 F2FS_BLKSIZE); 113 } 114 return 0; 115 } 116 117 static int sparse_import_segment(void *UNUSED(priv), const void *data, int len, 118 unsigned int block, unsigned int nr_blocks) 119 { 120 /* Ignore chunk headers, only write the data */ 121 if (!nr_blocks || len % F2FS_BLKSIZE) 122 return 0; 123 124 return sparse_write_blk(block, nr_blocks, data); 125 } 126 127 static int sparse_merge_blocks(uint64_t start, uint64_t num) 128 { 129 char *buf; 130 uint64_t i; 131 132 buf = calloc(num, F2FS_BLKSIZE); 133 if (!buf) { 134 fprintf(stderr, "failed to alloc %llu\n", 135 (unsigned long long)num * F2FS_BLKSIZE); 136 return -ENOMEM; 137 } 138 139 for (i = 0; i < num; i++) { 140 memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE); 141 free(blocks[start + i]); 142 blocks[start + i] = NULL; 143 } 144 145 /* free_sparse_blocks will release this buf. */ 146 blocks[start] = buf; 147 148 return sparse_file_add_data(f2fs_sparse_file, blocks[start], 149 F2FS_BLKSIZE * num, start); 150 } 151 #else 152 static int sparse_read_blk(__u64 block, int count, void *buf) { return 0; } 153 static int sparse_write_blk(__u64 block, int count, const void *buf) { return 0; } 154 #endif 155 156 int dev_read(void *buf, __u64 offset, size_t len) 157 { 158 int fd; 159 160 if (c.sparse_mode) 161 return sparse_read_blk(offset / F2FS_BLKSIZE, 162 len / F2FS_BLKSIZE, buf); 163 164 fd = __get_device_fd(&offset); 165 if (fd < 0) 166 return fd; 167 168 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0) 169 return -1; 170 if (read(fd, buf, len) < 0) 171 return -1; 172 return 0; 173 } 174 175 #ifdef POSIX_FADV_WILLNEED 176 int dev_readahead(__u64 offset, size_t len) 177 #else 178 int dev_readahead(__u64 offset, size_t UNUSED(len)) 179 #endif 180 { 181 int fd = __get_device_fd(&offset); 182 183 if (fd < 0) 184 return fd; 185 #ifdef POSIX_FADV_WILLNEED 186 return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED); 187 #else 188 return 0; 189 #endif 190 } 191 192 int dev_write(void *buf, __u64 offset, size_t len) 193 { 194 int fd; 195 196 if (c.dry_run) 197 return 0; 198 199 if (c.sparse_mode) 200 return sparse_write_blk(offset / F2FS_BLKSIZE, 201 len / F2FS_BLKSIZE, buf); 202 203 fd = __get_device_fd(&offset); 204 if (fd < 0) 205 return fd; 206 207 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0) 208 return -1; 209 if (write(fd, buf, len) < 0) 210 return -1; 211 return 0; 212 } 213 214 int dev_write_block(void *buf, __u64 blk_addr) 215 { 216 return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE); 217 } 218 219 int dev_write_dump(void *buf, __u64 offset, size_t len) 220 { 221 if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0) 222 return -1; 223 if (write(c.dump_fd, buf, len) < 0) 224 return -1; 225 return 0; 226 } 227 228 int dev_fill(void *buf, __u64 offset, size_t len) 229 { 230 int fd; 231 232 if (c.sparse_mode) 233 return 0; 234 235 fd = __get_device_fd(&offset); 236 if (fd < 0) 237 return fd; 238 239 /* Only allow fill to zero */ 240 if (*((__u8*)buf)) 241 return -1; 242 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0) 243 return -1; 244 if (write(fd, buf, len) < 0) 245 return -1; 246 return 0; 247 } 248 249 int dev_fill_block(void *buf, __u64 blk_addr) 250 { 251 return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE); 252 } 253 254 int dev_read_block(void *buf, __u64 blk_addr) 255 { 256 return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE); 257 } 258 259 int dev_reada_block(__u64 blk_addr) 260 { 261 return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE); 262 } 263 264 int f2fs_fsync_device(void) 265 { 266 #ifndef ANDROID_WINDOWS_HOST 267 int i; 268 269 for (i = 0; i < c.ndevs; i++) { 270 if (fsync(c.devices[i].fd) < 0) { 271 MSG(0, "\tError: Could not conduct fsync!!!\n"); 272 return -1; 273 } 274 } 275 #endif 276 return 0; 277 } 278 279 int f2fs_init_sparse_file(void) 280 { 281 #ifdef WITH_ANDROID 282 if (c.func == MKFS) { 283 f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size); 284 } else { 285 f2fs_sparse_file = sparse_file_import(c.devices[0].fd, 286 true, false); 287 if (!f2fs_sparse_file) 288 return -1; 289 290 c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0); 291 c.device_size &= (~((u_int64_t)(F2FS_BLKSIZE - 1))); 292 } 293 294 if (sparse_file_block_size(f2fs_sparse_file) != F2FS_BLKSIZE) { 295 MSG(0, "\tError: Corrupted sparse file\n"); 296 return -1; 297 } 298 blocks_count = c.device_size / F2FS_BLKSIZE; 299 blocks = calloc(blocks_count, sizeof(char *)); 300 301 return sparse_file_foreach_chunk(f2fs_sparse_file, true, false, 302 sparse_import_segment, NULL); 303 #else 304 MSG(0, "\tError: Sparse mode is only supported for android\n"); 305 return -1; 306 #endif 307 } 308 309 int f2fs_finalize_device(void) 310 { 311 int i; 312 int ret = 0; 313 314 #ifdef WITH_ANDROID 315 if (c.sparse_mode) { 316 int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0; 317 uint64_t j; 318 319 if (c.func != MKFS) { 320 sparse_file_destroy(f2fs_sparse_file); 321 ret = ftruncate(c.devices[0].fd, 0); 322 ASSERT(!ret); 323 lseek(c.devices[0].fd, 0, SEEK_SET); 324 f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, 325 c.device_size); 326 } 327 328 for (j = 0; j < blocks_count; ++j) { 329 if (!blocks[j] && chunk_start != -1) { 330 ret = sparse_merge_blocks(chunk_start, 331 j - chunk_start); 332 chunk_start = -1; 333 } else if (blocks[j] && chunk_start == -1) { 334 chunk_start = j; 335 } 336 ASSERT(!ret); 337 } 338 if (chunk_start != -1) { 339 ret = sparse_merge_blocks(chunk_start, 340 blocks_count - chunk_start); 341 ASSERT(!ret); 342 } 343 344 sparse_file_write(f2fs_sparse_file, c.devices[0].fd, 345 /*gzip*/0, /*sparse*/1, /*crc*/0); 346 347 sparse_file_destroy(f2fs_sparse_file); 348 for (j = 0; j < blocks_count; j++) 349 free(blocks[j]); 350 free(blocks); 351 blocks = NULL; 352 f2fs_sparse_file = NULL; 353 } 354 #endif 355 /* 356 * We should call fsync() to flush out all the dirty pages 357 * in the block device page cache. 358 */ 359 for (i = 0; i < c.ndevs; i++) { 360 #ifndef ANDROID_WINDOWS_HOST 361 ret = fsync(c.devices[i].fd); 362 if (ret < 0) { 363 MSG(0, "\tError: Could not conduct fsync!!!\n"); 364 break; 365 } 366 #endif 367 ret = close(c.devices[i].fd); 368 if (ret < 0) { 369 MSG(0, "\tError: Failed to close device file!!!\n"); 370 break; 371 } 372 } 373 close(c.kd); 374 375 return ret; 376 } 377