1235537Sgber/*- 2235537Sgber * Copyright (c) 2010-2012 Semihalf. 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235537Sgber * SUCH DAMAGE. 25235537Sgber */ 26235537Sgber 27235537Sgber#include <sys/cdefs.h> 28235537Sgber__FBSDID("$FreeBSD: releng/10.2/sbin/newfs_nandfs/newfs_nandfs.c 285453 2015-07-13 13:02:04Z brueffer $"); 29235537Sgber 30235537Sgber#include <sys/param.h> 31235537Sgber#include <sys/fdcio.h> 32235537Sgber#include <sys/disk.h> 33235537Sgber#include <sys/disklabel.h> 34235537Sgber#include <sys/mount.h> 35235537Sgber#include <sys/stat.h> 36235537Sgber#include <sys/time.h> 37235537Sgber#include <sys/endian.h> 38235537Sgber#include <sys/stddef.h> 39235537Sgber#include <sys/uuid.h> 40235537Sgber#include <sys/dirent.h> 41235537Sgber#include <sys/stat.h> 42235537Sgber 43235537Sgber#include <ctype.h> 44235537Sgber#include <err.h> 45235537Sgber#include <errno.h> 46235537Sgber#include <fcntl.h> 47235537Sgber#include <inttypes.h> 48235537Sgber#include <libgeom.h> 49235537Sgber#include <paths.h> 50235537Sgber#include <stdio.h> 51235537Sgber#include <stdlib.h> 52235537Sgber#include <string.h> 53235537Sgber#include <time.h> 54235537Sgber#include <unistd.h> 55235537Sgber 56235537Sgber#include <fs/nandfs/nandfs_fs.h> 57235537Sgber#include <dev/nand/nand_dev.h> 58235537Sgber 59235537Sgber#define DEBUG 60235537Sgber#undef DEBUG 61235537Sgber#ifdef DEBUG 62235537Sgber#define debug(fmt, args...) do { \ 63235537Sgber printf("nandfs:" fmt "\n", ##args); } while (0) 64235537Sgber#else 65235537Sgber#define debug(fmt, args...) 66235537Sgber#endif 67235537Sgber 68235537Sgber#define NANDFS_FIRST_BLOCK nandfs_first_block() 69235537Sgber#define NANDFS_FIRST_CNO 1 70235537Sgber#define NANDFS_BLOCK_BAD 1 71235537Sgber#define NANDFS_BLOCK_GOOD 0 72235537Sgber 73235537Sgberstruct file_info { 74235537Sgber uint64_t ino; 75235537Sgber const char *name; 76235537Sgber uint32_t mode; 77235537Sgber uint64_t size; 78235537Sgber uint8_t nblocks; 79235537Sgber uint32_t *blocks; 80235537Sgber struct nandfs_inode *inode; 81235537Sgber}; 82235537Sgber 83249743Sedstatic struct file_info user_files[] = { 84249743Sed { NANDFS_ROOT_INO, NULL, S_IFDIR | 0755, 0, 1, NULL, NULL }, 85235537Sgber}; 86235537Sgber 87249743Sedstatic struct file_info ifile = 88249743Sed { NANDFS_IFILE_INO, NULL, 0, 0, -1, NULL, NULL }; 89249743Sedstatic struct file_info sufile = 90249743Sed { NANDFS_SUFILE_INO, NULL, 0, 0, -1, NULL, NULL }; 91249743Sedstatic struct file_info cpfile = 92249743Sed { NANDFS_CPFILE_INO, NULL, 0, 0, -1, NULL, NULL }; 93249743Sedstatic struct file_info datfile = 94249743Sed { NANDFS_DAT_INO, NULL, 0, 0, -1, NULL, NULL }; 95235537Sgber 96235537Sgberstruct nandfs_block { 97235537Sgber LIST_ENTRY(nandfs_block) block_link; 98235537Sgber uint32_t number; 99235537Sgber uint64_t offset; 100235537Sgber void *data; 101235537Sgber}; 102235537Sgber 103249743Sedstatic LIST_HEAD(, nandfs_block) block_head = 104249743Sed LIST_HEAD_INITIALIZER(&block_head); 105235537Sgber 106235537Sgber/* Storage geometry */ 107235537Sgberstatic off_t mediasize; 108235537Sgberstatic ssize_t sectorsize; 109235537Sgberstatic uint64_t nsegments; 110235537Sgberstatic uint64_t erasesize; 111235537Sgberstatic uint64_t segsize; 112235537Sgber 113249743Sedstatic struct nandfs_fsdata fsdata; 114249743Sedstatic struct nandfs_super_block super_block; 115235537Sgber 116235537Sgberstatic int is_nand; 117235537Sgber 118235537Sgber/* Nandfs parameters */ 119235537Sgberstatic size_t blocksize = NANDFS_DEF_BLOCKSIZE; 120235537Sgberstatic long blocks_per_segment; 121235537Sgberstatic long rsv_segment_percent = 5; 122235537Sgberstatic time_t nandfs_time; 123235537Sgberstatic uint32_t bad_segments_count = 0; 124235537Sgberstatic uint32_t *bad_segments = NULL; 125235537Sgberstatic uint8_t fsdata_blocks_state[NANDFS_NFSAREAS]; 126235537Sgber 127249743Sedstatic u_char *volumelabel = NULL; 128235537Sgber 129249743Sedstatic struct nandfs_super_root *sr; 130235537Sgber 131249743Sedstatic uint32_t nuserfiles; 132249743Sedstatic uint32_t seg_nblocks; 133249743Sedstatic uint32_t seg_endblock; 134235537Sgber 135235537Sgber#define SIZE_TO_BLOCK(size) (((size) + (blocksize - 1)) / blocksize) 136235537Sgber 137235537Sgberstatic uint32_t 138235537Sgbernandfs_first_block(void) 139235537Sgber{ 140235537Sgber uint32_t i, first_free, start_bad_segments = 0; 141235537Sgber 142235537Sgber for (i = 0; i < bad_segments_count; i++) { 143235537Sgber if (i == bad_segments[i]) 144235537Sgber start_bad_segments++; 145235537Sgber else 146235537Sgber break; 147235537Sgber } 148235537Sgber 149235537Sgber first_free = SIZE_TO_BLOCK(NANDFS_DATA_OFFSET_BYTES(erasesize) + 150235537Sgber (start_bad_segments * segsize)); 151235537Sgber 152235537Sgber if (first_free < (uint32_t)blocks_per_segment) 153235537Sgber return (blocks_per_segment); 154235537Sgber else 155235537Sgber return (first_free); 156235537Sgber} 157235537Sgber 158235537Sgberstatic void 159235537Sgberusage(void) 160235537Sgber{ 161235537Sgber 162235537Sgber fprintf(stderr, 163235537Sgber "usage: newfs_nandfs [ -options ] device\n" 164235537Sgber "where the options are:\n" 165235537Sgber "\t-b block-size\n" 166235537Sgber "\t-B blocks-per-segment\n" 167235537Sgber "\t-L volume label\n" 168235537Sgber "\t-m reserved-segments-percentage\n"); 169235537Sgber exit(1); 170235537Sgber} 171235537Sgber 172235537Sgberstatic int 173235537Sgbernandfs_log2(unsigned n) 174235537Sgber{ 175235537Sgber unsigned count; 176235537Sgber 177235537Sgber /* 178235537Sgber * N.B. this function will return 0 if supplied 0. 179235537Sgber */ 180235537Sgber for (count = 0; n/2; count++) 181235537Sgber n /= 2; 182235537Sgber return count; 183235537Sgber} 184235537Sgber 185235537Sgber/* from NetBSD's src/sys/net/if_ethersubr.c */ 186235537Sgberstatic uint32_t 187235537Sgbercrc32_le(uint32_t crc, const uint8_t *buf, size_t len) 188235537Sgber{ 189235537Sgber static const uint32_t crctab[] = { 190235537Sgber 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 191235537Sgber 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 192235537Sgber 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 193235537Sgber 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 194235537Sgber }; 195235537Sgber size_t i; 196235537Sgber 197235537Sgber crc = crc ^ ~0U; 198235537Sgber 199235537Sgber for (i = 0; i < len; i++) { 200235537Sgber crc ^= buf[i]; 201235537Sgber crc = (crc >> 4) ^ crctab[crc & 0xf]; 202235537Sgber crc = (crc >> 4) ^ crctab[crc & 0xf]; 203235537Sgber } 204235537Sgber 205235537Sgber return (crc ^ ~0U); 206235537Sgber} 207235537Sgber 208235537Sgberstatic void * 209235537Sgberget_block(uint32_t block_nr, uint64_t offset) 210235537Sgber{ 211235537Sgber struct nandfs_block *block, *new_block; 212235537Sgber 213235537Sgber LIST_FOREACH(block, &block_head, block_link) { 214235537Sgber if (block->number == block_nr) 215235537Sgber return block->data; 216235537Sgber } 217235537Sgber 218235537Sgber debug("allocating block %x\n", block_nr); 219235537Sgber 220235537Sgber new_block = malloc(sizeof(*block)); 221235537Sgber if (!new_block) 222235537Sgber err(1, "cannot allocate block"); 223235537Sgber 224235537Sgber new_block->number = block_nr; 225235537Sgber new_block->offset = offset; 226235537Sgber new_block->data = malloc(blocksize); 227235537Sgber if (!new_block->data) 228235537Sgber err(1, "cannot allocate block data"); 229235537Sgber 230235537Sgber memset(new_block->data, 0, blocksize); 231235537Sgber 232235537Sgber LIST_INSERT_HEAD(&block_head, new_block, block_link); 233235537Sgber 234235537Sgber return (new_block->data); 235235537Sgber} 236235537Sgber 237235537Sgberstatic int 238235537Sgbernandfs_seg_usage_blk_offset(uint64_t seg, uint64_t *blk, uint64_t *offset) 239235537Sgber{ 240235537Sgber uint64_t off; 241235537Sgber uint16_t seg_size; 242235537Sgber 243235537Sgber seg_size = sizeof(struct nandfs_segment_usage); 244235537Sgber 245235537Sgber off = roundup(sizeof(struct nandfs_sufile_header), seg_size); 246235537Sgber off += (seg * seg_size); 247235537Sgber 248235537Sgber *blk = off / blocksize; 249235537Sgber *offset = (off % blocksize) / seg_size; 250235537Sgber return (0); 251235537Sgber} 252235537Sgber 253235537Sgberstatic uint32_t 254235537Sgbersegment_size(void) 255235537Sgber{ 256235537Sgber u_int size; 257235537Sgber 258235537Sgber size = sizeof(struct nandfs_segment_summary ); 259235537Sgber size += seg_nblocks * sizeof(struct nandfs_binfo_v); 260235537Sgber 261235537Sgber if (size > blocksize) 262235537Sgber err(1, "segsum info bigger that blocksize"); 263235537Sgber 264235537Sgber return (size); 265235537Sgber} 266235537Sgber 267235537Sgber 268235537Sgberstatic void 269235537Sgberprepare_blockgrouped_file(uint32_t block) 270235537Sgber{ 271235537Sgber struct nandfs_block_group_desc *desc; 272235537Sgber uint32_t i, entries; 273235537Sgber 274235537Sgber desc = (struct nandfs_block_group_desc *)get_block(block, 0); 275235537Sgber entries = blocksize / sizeof(struct nandfs_block_group_desc); 276235537Sgber for (i = 0; i < entries; i++) 277235537Sgber desc[i].bg_nfrees = blocksize * 8; 278235537Sgber} 279235537Sgber 280235537Sgberstatic void 281235537Sgberalloc_blockgrouped_file(uint32_t block, uint32_t entry) 282235537Sgber{ 283235537Sgber struct nandfs_block_group_desc *desc; 284235537Sgber uint32_t desc_nr; 285235537Sgber uint32_t *bitmap; 286235537Sgber 287235537Sgber desc = (struct nandfs_block_group_desc *)get_block(block, 0); 288235537Sgber bitmap = (uint32_t *)get_block(block + 1, 1); 289235537Sgber 290235537Sgber bitmap += (entry >> 5); 291235537Sgber if (*bitmap & (1 << (entry % 32))) { 292235537Sgber printf("nandfs: blockgrouped entry %d already allocated\n", 293235537Sgber entry); 294235537Sgber } 295235537Sgber *bitmap |= (1 << (entry % 32)); 296235537Sgber 297235537Sgber desc_nr = entry / (blocksize * 8); 298235537Sgber desc[desc_nr].bg_nfrees--; 299235537Sgber} 300235537Sgber 301235537Sgber 302235537Sgberstatic uint64_t 303235537Sgbercount_su_blocks(void) 304235537Sgber{ 305235537Sgber uint64_t maxblk, blk, offset, i; 306235537Sgber 307235537Sgber maxblk = blk = 0; 308235537Sgber 309235537Sgber for (i = 0; i < bad_segments_count; i++) { 310235537Sgber nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &offset); 311235537Sgber debug("bad segment at block:%jx off: %jx", blk, offset); 312235537Sgber if (blk > maxblk) 313235537Sgber maxblk = blk; 314235537Sgber } 315235537Sgber 316235537Sgber debug("bad segment needs %#jx", blk); 317235537Sgber if (blk >= NDADDR) { 318235537Sgber printf("nandfs: file too big (%jd > %d)\n", blk, NDADDR); 319235537Sgber exit(2); 320235537Sgber } 321235537Sgber 322235537Sgber sufile.size = (blk + 1) * blocksize; 323235537Sgber return (blk + 1); 324235537Sgber} 325235537Sgber 326235537Sgberstatic void 327235537Sgbercount_seg_blocks(void) 328235537Sgber{ 329235537Sgber uint32_t i; 330235537Sgber 331235537Sgber for (i = 0; i < nuserfiles; i++) 332235537Sgber if (user_files[i].nblocks) { 333235537Sgber seg_nblocks += user_files[i].nblocks; 334235537Sgber user_files[i].blocks = malloc(user_files[i].nblocks * sizeof(uint32_t)); 335235537Sgber } 336235537Sgber 337235537Sgber ifile.nblocks = 2 + 338235537Sgber SIZE_TO_BLOCK(sizeof(struct nandfs_inode) * (NANDFS_USER_INO + 1)); 339235537Sgber ifile.blocks = malloc(ifile.nblocks * sizeof(uint32_t)); 340235537Sgber seg_nblocks += ifile.nblocks; 341235537Sgber 342235537Sgber cpfile.nblocks = 343235537Sgber SIZE_TO_BLOCK((NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1) * 344235537Sgber sizeof(struct nandfs_checkpoint)); 345235537Sgber cpfile.blocks = malloc(cpfile.nblocks * sizeof(uint32_t)); 346235537Sgber seg_nblocks += cpfile.nblocks; 347235537Sgber 348235537Sgber if (!bad_segments) { 349235537Sgber sufile.nblocks = 350235537Sgber SIZE_TO_BLOCK((NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET + 1) * 351235537Sgber sizeof(struct nandfs_segment_usage)); 352235537Sgber } else { 353235537Sgber debug("bad blocks found: extra space for sufile"); 354235537Sgber sufile.nblocks = count_su_blocks(); 355235537Sgber } 356235537Sgber 357235537Sgber sufile.blocks = malloc(sufile.nblocks * sizeof(uint32_t)); 358235537Sgber seg_nblocks += sufile.nblocks; 359235537Sgber 360235537Sgber datfile.nblocks = 2 + 361235537Sgber SIZE_TO_BLOCK((seg_nblocks) * sizeof(struct nandfs_dat_entry)); 362235537Sgber datfile.blocks = malloc(datfile.nblocks * sizeof(uint32_t)); 363235537Sgber seg_nblocks += datfile.nblocks; 364235537Sgber} 365235537Sgber 366235537Sgberstatic void 367235537Sgberassign_file_blocks(uint64_t start_block) 368235537Sgber{ 369235537Sgber uint32_t i, j; 370235537Sgber 371235537Sgber for (i = 0; i < nuserfiles; i++) 372235537Sgber for (j = 0; j < user_files[i].nblocks; j++) { 373235537Sgber debug("user file %d at block %d at %#jx", 374235537Sgber i, j, (uintmax_t)start_block); 375235537Sgber user_files[i].blocks[j] = start_block++; 376235537Sgber } 377235537Sgber 378235537Sgber for (j = 0; j < ifile.nblocks; j++) { 379235537Sgber debug("ifile block %d at %#jx", j, (uintmax_t)start_block); 380235537Sgber ifile.blocks[j] = start_block++; 381235537Sgber } 382235537Sgber 383235537Sgber for (j = 0; j < cpfile.nblocks; j++) { 384235537Sgber debug("cpfile block %d at %#jx", j, (uintmax_t)start_block); 385235537Sgber cpfile.blocks[j] = start_block++; 386235537Sgber } 387235537Sgber 388235537Sgber for (j = 0; j < sufile.nblocks; j++) { 389235537Sgber debug("sufile block %d at %#jx", j, (uintmax_t)start_block); 390235537Sgber sufile.blocks[j] = start_block++; 391235537Sgber } 392235537Sgber 393235537Sgber for (j = 0; j < datfile.nblocks; j++) { 394235537Sgber debug("datfile block %d at %#jx", j, (uintmax_t)start_block); 395235537Sgber datfile.blocks[j] = start_block++; 396235537Sgber } 397235537Sgber 398235537Sgber /* add one for superroot */ 399235537Sgber debug("sr at block %#jx", (uintmax_t)start_block); 400235537Sgber sr = (struct nandfs_super_root *)get_block(start_block++, 0); 401235537Sgber seg_endblock = start_block; 402235537Sgber} 403235537Sgber 404235537Sgberstatic void 405235537Sgbersave_datfile(void) 406235537Sgber{ 407235537Sgber 408235537Sgber prepare_blockgrouped_file(datfile.blocks[0]); 409235537Sgber} 410235537Sgber 411235537Sgberstatic uint64_t 412235537Sgberupdate_datfile(uint64_t block) 413235537Sgber{ 414235537Sgber struct nandfs_dat_entry *dat; 415235537Sgber static uint64_t vblock = 0; 416235537Sgber uint64_t allocated, i, off; 417235537Sgber 418235537Sgber if (vblock == 0) { 419235537Sgber alloc_blockgrouped_file(datfile.blocks[0], vblock); 420235537Sgber vblock++; 421235537Sgber } 422235537Sgber allocated = vblock; 423235537Sgber i = vblock / (blocksize / sizeof(*dat)); 424235537Sgber off = vblock % (blocksize / sizeof(*dat)); 425235537Sgber vblock++; 426235537Sgber 427235537Sgber dat = (struct nandfs_dat_entry *)get_block(datfile.blocks[2 + i], 2 + i); 428235537Sgber 429235537Sgber alloc_blockgrouped_file(datfile.blocks[0], allocated); 430235537Sgber dat[off].de_blocknr = block; 431235537Sgber dat[off].de_start = NANDFS_FIRST_CNO; 432235537Sgber dat[off].de_end = UINTMAX_MAX; 433235537Sgber 434235537Sgber return (allocated); 435235537Sgber} 436235537Sgber 437235537Sgberstatic union nandfs_binfo * 438235537Sgberupdate_block_info(union nandfs_binfo *binfo, struct file_info *file) 439235537Sgber{ 440235537Sgber nandfs_daddr_t vblock; 441235537Sgber uint32_t i; 442235537Sgber 443235537Sgber for (i = 0; i < file->nblocks; i++) { 444235537Sgber debug("%s: blk %x", __func__, i); 445235537Sgber if (file->ino != NANDFS_DAT_INO) { 446235537Sgber vblock = update_datfile(file->blocks[i]); 447235537Sgber binfo->bi_v.bi_vblocknr = vblock; 448235537Sgber binfo->bi_v.bi_blkoff = i; 449235537Sgber binfo->bi_v.bi_ino = file->ino; 450235537Sgber file->inode->i_db[i] = vblock; 451235537Sgber } else { 452235537Sgber binfo->bi_dat.bi_blkoff = i; 453235537Sgber binfo->bi_dat.bi_ino = file->ino; 454235537Sgber file->inode->i_db[i] = datfile.blocks[i]; 455235537Sgber } 456235537Sgber binfo++; 457235537Sgber } 458235537Sgber 459235537Sgber return (binfo); 460235537Sgber} 461235537Sgber 462235537Sgberstatic void 463235537Sgbersave_segsum(struct nandfs_segment_summary *ss) 464235537Sgber{ 465235537Sgber union nandfs_binfo *binfo; 466235537Sgber struct nandfs_block *block; 467235537Sgber uint32_t sum_bytes, i; 468235537Sgber uint8_t crc_data, crc_skip; 469235537Sgber 470235537Sgber sum_bytes = segment_size(); 471235537Sgber ss->ss_magic = NANDFS_SEGSUM_MAGIC; 472235537Sgber ss->ss_bytes = sizeof(struct nandfs_segment_summary); 473235537Sgber ss->ss_flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND | NANDFS_SS_SR; 474235537Sgber ss->ss_seq = 1; 475235537Sgber ss->ss_create = nandfs_time; 476235537Sgber 477235537Sgber ss->ss_next = nandfs_first_block() + blocks_per_segment; 478235537Sgber /* nblocks = segment blocks + segsum block + superroot */ 479235537Sgber ss->ss_nblocks = seg_nblocks + 2; 480235537Sgber ss->ss_nbinfos = seg_nblocks; 481235537Sgber ss->ss_sumbytes = sum_bytes; 482235537Sgber 483235537Sgber crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum); 484235537Sgber ss->ss_sumsum = crc32_le(0, (uint8_t *)ss + crc_skip, 485235537Sgber sum_bytes - crc_skip); 486235537Sgber crc_data = 0; 487235537Sgber 488235537Sgber binfo = (union nandfs_binfo *)(ss + 1); 489235537Sgber for (i = 0; i < nuserfiles; i++) { 490235537Sgber if (user_files[i].nblocks) 491235537Sgber binfo = update_block_info(binfo, &user_files[i]); 492235537Sgber } 493235537Sgber 494235537Sgber binfo = update_block_info(binfo, &ifile); 495235537Sgber binfo = update_block_info(binfo, &cpfile); 496235537Sgber binfo = update_block_info(binfo, &sufile); 497235537Sgber update_block_info(binfo, &datfile); 498235537Sgber 499235537Sgber /* save superroot crc */ 500235537Sgber crc_skip = sizeof(sr->sr_sum); 501235537Sgber sr->sr_sum = crc32_le(0, (uint8_t *)sr + crc_skip, 502235537Sgber NANDFS_SR_BYTES - crc_skip); 503235537Sgber 504235537Sgber /* segment checksup */ 505235537Sgber crc_skip = sizeof(ss->ss_datasum); 506235537Sgber LIST_FOREACH(block, &block_head, block_link) { 507235537Sgber if (block->number < NANDFS_FIRST_BLOCK) 508235537Sgber continue; 509235537Sgber if (block->number == NANDFS_FIRST_BLOCK) 510235537Sgber crc_data = crc32_le(0, 511235537Sgber (uint8_t *)block->data + crc_skip, 512235537Sgber blocksize - crc_skip); 513235537Sgber else 514235537Sgber crc_data = crc32_le(crc_data, (uint8_t *)block->data, 515235537Sgber blocksize); 516235537Sgber } 517235537Sgber ss->ss_datasum = crc_data; 518235537Sgber} 519235537Sgber 520235537Sgberstatic void 521235537Sgbercreate_fsdata(void) 522235537Sgber{ 523235537Sgber 524235537Sgber memset(&fsdata, 0, sizeof(struct nandfs_fsdata)); 525235537Sgber 526235537Sgber fsdata.f_magic = NANDFS_FSDATA_MAGIC; 527235537Sgber fsdata.f_nsegments = nsegments; 528235537Sgber fsdata.f_erasesize = erasesize; 529235537Sgber fsdata.f_first_data_block = NANDFS_FIRST_BLOCK; 530235537Sgber fsdata.f_blocks_per_segment = blocks_per_segment; 531235537Sgber fsdata.f_r_segments_percentage = rsv_segment_percent; 532235537Sgber fsdata.f_rev_level = NANDFS_CURRENT_REV; 533235537Sgber fsdata.f_sbbytes = NANDFS_SB_BYTES; 534235537Sgber fsdata.f_bytes = NANDFS_FSDATA_CRC_BYTES; 535235537Sgber fsdata.f_ctime = nandfs_time; 536235537Sgber fsdata.f_log_block_size = nandfs_log2(blocksize) - 10; 537235537Sgber fsdata.f_errors = 1; 538235537Sgber fsdata.f_inode_size = sizeof(struct nandfs_inode); 539235537Sgber fsdata.f_dat_entry_size = sizeof(struct nandfs_dat_entry); 540235537Sgber fsdata.f_checkpoint_size = sizeof(struct nandfs_checkpoint); 541235537Sgber fsdata.f_segment_usage_size = sizeof(struct nandfs_segment_usage); 542235537Sgber 543235537Sgber uuidgen(&fsdata.f_uuid, 1); 544235537Sgber 545235537Sgber if (volumelabel) 546235537Sgber memcpy(fsdata.f_volume_name, volumelabel, 16); 547235537Sgber 548235537Sgber fsdata.f_sum = crc32_le(0, (const uint8_t *)&fsdata, 549235537Sgber NANDFS_FSDATA_CRC_BYTES); 550235537Sgber} 551235537Sgber 552235537Sgberstatic void 553235537Sgbersave_fsdata(void *data) 554235537Sgber{ 555235537Sgber 556235537Sgber memcpy(data, &fsdata, sizeof(fsdata)); 557235537Sgber} 558235537Sgber 559235537Sgberstatic void 560235537Sgbercreate_super_block(void) 561235537Sgber{ 562235537Sgber 563235537Sgber memset(&super_block, 0, sizeof(struct nandfs_super_block)); 564235537Sgber 565235537Sgber super_block.s_magic = NANDFS_SUPER_MAGIC; 566235537Sgber super_block.s_last_cno = NANDFS_FIRST_CNO; 567235537Sgber super_block.s_last_pseg = NANDFS_FIRST_BLOCK; 568235537Sgber super_block.s_last_seq = 1; 569235537Sgber super_block.s_free_blocks_count = 570235537Sgber (nsegments - bad_segments_count) * blocks_per_segment; 571235537Sgber super_block.s_mtime = 0; 572235537Sgber super_block.s_wtime = nandfs_time; 573235537Sgber super_block.s_state = NANDFS_VALID_FS; 574235537Sgber 575235537Sgber super_block.s_sum = crc32_le(0, (const uint8_t *)&super_block, 576235537Sgber NANDFS_SB_BYTES); 577235537Sgber} 578235537Sgber 579235537Sgberstatic void 580235537Sgbersave_super_block(void *data) 581235537Sgber{ 582235537Sgber 583235537Sgber memcpy(data, &super_block, sizeof(super_block)); 584235537Sgber} 585235537Sgber 586235537Sgberstatic void 587235537Sgbersave_super_root(void) 588235537Sgber{ 589235537Sgber 590235537Sgber sr->sr_bytes = NANDFS_SR_BYTES; 591235537Sgber sr->sr_flags = 0; 592235537Sgber sr->sr_nongc_ctime = nandfs_time; 593235537Sgber datfile.inode = &sr->sr_dat; 594235537Sgber cpfile.inode = &sr->sr_cpfile; 595235537Sgber sufile.inode = &sr->sr_sufile; 596235537Sgber} 597235537Sgber 598235537Sgberstatic struct nandfs_dir_entry * 599235537Sgberadd_de(void *block, struct nandfs_dir_entry *de, uint64_t ino, 600235537Sgber const char *name, uint8_t type) 601235537Sgber{ 602235537Sgber uint16_t reclen; 603235537Sgber 604235537Sgber /* modify last de */ 605235537Sgber de->rec_len = NANDFS_DIR_REC_LEN(de->name_len); 606235537Sgber de = (void *)((uint8_t *)de + de->rec_len); 607235537Sgber 608235537Sgber reclen = blocksize - ((uintptr_t)de - (uintptr_t)block); 609235537Sgber if (reclen < NANDFS_DIR_REC_LEN(strlen(name))) { 610235537Sgber printf("nandfs: too many dir entries for one block\n"); 611235537Sgber return (NULL); 612235537Sgber } 613235537Sgber 614235537Sgber de->inode = ino; 615235537Sgber de->rec_len = reclen; 616235537Sgber de->name_len = strlen(name); 617235537Sgber de->file_type = type; 618235537Sgber memset(de->name, 0, 619235537Sgber (strlen(name) + NANDFS_DIR_PAD - 1) & ~NANDFS_DIR_ROUND); 620235537Sgber memcpy(de->name, name, strlen(name)); 621235537Sgber 622235537Sgber return (de); 623235537Sgber} 624235537Sgber 625235537Sgberstatic struct nandfs_dir_entry * 626235537Sgbermake_dir(void *block, uint64_t ino, uint64_t parent_ino) 627235537Sgber{ 628235537Sgber struct nandfs_dir_entry *de = (struct nandfs_dir_entry *)block; 629235537Sgber 630235537Sgber /* create '..' entry */ 631235537Sgber de->inode = parent_ino; 632235537Sgber de->rec_len = NANDFS_DIR_REC_LEN(2); 633235537Sgber de->name_len = 2; 634235537Sgber de->file_type = DT_DIR; 635235537Sgber memset(de->name, 0, NANDFS_DIR_NAME_LEN(2)); 636235537Sgber memcpy(de->name, "..", 2); 637235537Sgber 638235537Sgber /* create '.' entry */ 639235537Sgber de = (void *)((uint8_t *)block + NANDFS_DIR_REC_LEN(2)); 640235537Sgber de->inode = ino; 641235537Sgber de->rec_len = blocksize - NANDFS_DIR_REC_LEN(2); 642235537Sgber de->name_len = 1; 643235537Sgber de->file_type = DT_DIR; 644235537Sgber memset(de->name, 0, NANDFS_DIR_NAME_LEN(1)); 645235537Sgber memcpy(de->name, ".", 1); 646235537Sgber 647235537Sgber return (de); 648235537Sgber} 649235537Sgber 650235537Sgberstatic void 651235537Sgbersave_root_dir(void) 652235537Sgber{ 653235537Sgber struct file_info *root = &user_files[0]; 654235537Sgber struct nandfs_dir_entry *de; 655235537Sgber uint32_t i; 656235537Sgber void *block; 657235537Sgber 658235537Sgber block = get_block(root->blocks[0], 0); 659235537Sgber 660235537Sgber de = make_dir(block, root->ino, root->ino); 661235537Sgber for (i = 1; i < nuserfiles; i++) 662235537Sgber de = add_de(block, de, user_files[i].ino, user_files[i].name, 663235537Sgber IFTODT(user_files[i].mode)); 664235537Sgber 665235537Sgber root->size = ((uintptr_t)de - (uintptr_t)block) + 666235537Sgber NANDFS_DIR_REC_LEN(de->name_len); 667235537Sgber} 668235537Sgber 669235537Sgberstatic void 670235537Sgbersave_sufile(void) 671235537Sgber{ 672235537Sgber struct nandfs_sufile_header *header; 673235537Sgber struct nandfs_segment_usage *su; 674235537Sgber uint64_t blk, i, off; 675235537Sgber void *block; 676235537Sgber int start; 677235537Sgber 678235537Sgber /* 679235537Sgber * At the beginning just zero-out everything 680235537Sgber */ 681235537Sgber for (i = 0; i < sufile.nblocks; i++) 682235537Sgber get_block(sufile.blocks[i], 0); 683235537Sgber 684235537Sgber start = 0; 685235537Sgber 686235537Sgber block = get_block(sufile.blocks[start], 0); 687235537Sgber header = (struct nandfs_sufile_header *)block; 688235537Sgber header->sh_ncleansegs = nsegments - bad_segments_count - 1; 689235537Sgber header->sh_ndirtysegs = 1; 690235537Sgber header->sh_last_alloc = 1; 691235537Sgber 692235537Sgber su = (struct nandfs_segment_usage *)header; 693235537Sgber off = NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET; 694235537Sgber /* Allocate data segment */ 695235537Sgber su[off].su_lastmod = nandfs_time; 696235537Sgber /* nblocks = segment blocks + segsum block + superroot */ 697235537Sgber su[off].su_nblocks = seg_nblocks + 2; 698235537Sgber su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; 699235537Sgber off++; 700235537Sgber /* Allocate next segment */ 701235537Sgber su[off].su_lastmod = nandfs_time; 702235537Sgber su[off].su_nblocks = 0; 703235537Sgber su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; 704235537Sgber for (i = 0; i < bad_segments_count; i++) { 705235537Sgber nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &off); 706235537Sgber debug("storing bad_segments[%jd]=%x at %jx off %jx\n", i, 707235537Sgber bad_segments[i], blk, off); 708235537Sgber block = get_block(sufile.blocks[blk], 709235537Sgber off * sizeof(struct nandfs_segment_usage *)); 710235537Sgber su = (struct nandfs_segment_usage *)block; 711235537Sgber su[off].su_lastmod = nandfs_time; 712235537Sgber su[off].su_nblocks = 0; 713235537Sgber su[off].su_flags = NANDFS_SEGMENT_USAGE_ERROR; 714235537Sgber } 715235537Sgber} 716235537Sgber 717235537Sgberstatic void 718235537Sgbersave_cpfile(void) 719235537Sgber{ 720235537Sgber struct nandfs_cpfile_header *header; 721235537Sgber struct nandfs_checkpoint *cp, *initial_cp; 722235537Sgber int i, entries = blocksize / sizeof(struct nandfs_checkpoint); 723235537Sgber uint64_t cno; 724235537Sgber 725235537Sgber header = (struct nandfs_cpfile_header *)get_block(cpfile.blocks[0], 0); 726235537Sgber header->ch_ncheckpoints = 1; 727235537Sgber header->ch_nsnapshots = 0; 728235537Sgber 729235537Sgber cp = (struct nandfs_checkpoint *)header; 730235537Sgber 731235537Sgber /* fill first checkpoint data*/ 732235537Sgber initial_cp = &cp[NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET]; 733235537Sgber initial_cp->cp_flags = 0; 734235537Sgber initial_cp->cp_checkpoints_count = 0; 735235537Sgber initial_cp->cp_cno = NANDFS_FIRST_CNO; 736235537Sgber initial_cp->cp_create = nandfs_time; 737235537Sgber initial_cp->cp_nblk_inc = seg_endblock - 1; 738235537Sgber initial_cp->cp_blocks_count = seg_nblocks; 739235537Sgber memset(&initial_cp->cp_snapshot_list, 0, 740235537Sgber sizeof(struct nandfs_snapshot_list)); 741235537Sgber 742235537Sgber ifile.inode = &initial_cp->cp_ifile_inode; 743235537Sgber 744235537Sgber /* mark rest of cp as invalid */ 745235537Sgber cno = NANDFS_FIRST_CNO + 1; 746235537Sgber i = NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1; 747235537Sgber for (; i < entries; i++) { 748235537Sgber cp[i].cp_cno = cno++; 749235537Sgber cp[i].cp_flags = NANDFS_CHECKPOINT_INVALID; 750235537Sgber } 751235537Sgber} 752235537Sgber 753235537Sgberstatic void 754235537Sgberinit_inode(struct nandfs_inode *inode, struct file_info *file) 755235537Sgber{ 756235537Sgber 757235537Sgber inode->i_blocks = file->nblocks; 758235537Sgber inode->i_ctime = nandfs_time; 759235537Sgber inode->i_mtime = nandfs_time; 760235537Sgber inode->i_mode = file->mode & 0xffff; 761235537Sgber inode->i_links_count = 1; 762235537Sgber 763235537Sgber if (file->size > 0) 764235537Sgber inode->i_size = file->size; 765235537Sgber else 766235537Sgber inode->i_size = 0; 767235537Sgber 768235537Sgber if (file->ino == NANDFS_USER_INO) 769235537Sgber inode->i_flags = SF_NOUNLINK|UF_NOUNLINK; 770235537Sgber else 771235537Sgber inode->i_flags = 0; 772235537Sgber} 773235537Sgber 774235537Sgberstatic void 775235537Sgbersave_ifile(void) 776235537Sgber{ 777235537Sgber struct nandfs_inode *inode; 778235537Sgber struct file_info *file; 779235537Sgber uint64_t ino, blk, off; 780235537Sgber uint32_t i; 781235537Sgber 782235537Sgber prepare_blockgrouped_file(ifile.blocks[0]); 783235537Sgber for (i = 0; i <= NANDFS_USER_INO; i++) 784235537Sgber alloc_blockgrouped_file(ifile.blocks[0], i); 785235537Sgber 786235537Sgber for (i = 0; i < nuserfiles; i++) { 787235537Sgber file = &user_files[i]; 788235537Sgber ino = file->ino; 789235537Sgber blk = ino / (blocksize / sizeof(*inode)); 790235537Sgber off = ino % (blocksize / sizeof(*inode)); 791235537Sgber inode = 792235537Sgber (struct nandfs_inode *)get_block(ifile.blocks[2 + blk], 2 + blk); 793235537Sgber file->inode = &inode[off]; 794235537Sgber init_inode(file->inode, file); 795235537Sgber } 796235537Sgber 797235537Sgber init_inode(ifile.inode, &ifile); 798235537Sgber init_inode(cpfile.inode, &cpfile); 799235537Sgber init_inode(sufile.inode, &sufile); 800235537Sgber init_inode(datfile.inode, &datfile); 801235537Sgber} 802235537Sgber 803235537Sgberstatic int 804235537Sgbercreate_fs(void) 805235537Sgber{ 806235537Sgber uint64_t start_block; 807235537Sgber uint32_t segsum_size; 808235537Sgber char *data; 809235537Sgber int i; 810235537Sgber 811235537Sgber nuserfiles = (sizeof(user_files) / sizeof(user_files[0])); 812235537Sgber 813235537Sgber /* Count and assign blocks */ 814235537Sgber count_seg_blocks(); 815235537Sgber segsum_size = segment_size(); 816235537Sgber start_block = NANDFS_FIRST_BLOCK + SIZE_TO_BLOCK(segsum_size); 817235537Sgber assign_file_blocks(start_block); 818235537Sgber 819235537Sgber /* Create super root structure */ 820235537Sgber save_super_root(); 821235537Sgber 822235537Sgber /* Create root directory */ 823235537Sgber save_root_dir(); 824235537Sgber 825235537Sgber /* Fill in file contents */ 826235537Sgber save_sufile(); 827235537Sgber save_cpfile(); 828235537Sgber save_ifile(); 829235537Sgber save_datfile(); 830235537Sgber 831235537Sgber /* Save fsdata and superblocks */ 832235537Sgber create_fsdata(); 833235537Sgber create_super_block(); 834235537Sgber 835235537Sgber for (i = 0; i < NANDFS_NFSAREAS; i++) { 836235537Sgber if (fsdata_blocks_state[i] != NANDFS_BLOCK_GOOD) 837235537Sgber continue; 838235537Sgber 839235537Sgber data = get_block((i * erasesize)/blocksize, 0); 840235537Sgber save_fsdata(data); 841235537Sgber 842235537Sgber data = get_block((i * erasesize + NANDFS_SBLOCK_OFFSET_BYTES) / 843235537Sgber blocksize, 0); 844235537Sgber if (blocksize > NANDFS_SBLOCK_OFFSET_BYTES) 845235537Sgber data += NANDFS_SBLOCK_OFFSET_BYTES; 846235537Sgber save_super_block(data); 847235537Sgber memset(data + sizeof(struct nandfs_super_block), 0xff, 848235537Sgber (blocksize - sizeof(struct nandfs_super_block) - 849235537Sgber NANDFS_SBLOCK_OFFSET_BYTES)); 850235537Sgber } 851235537Sgber 852235537Sgber /* Save segment summary and CRCs */ 853235537Sgber save_segsum(get_block(NANDFS_FIRST_BLOCK, 0)); 854235537Sgber 855235537Sgber return (0); 856235537Sgber} 857235537Sgber 858235537Sgberstatic void 859235537Sgberwrite_fs(int fda) 860235537Sgber{ 861235537Sgber struct nandfs_block *block; 862235537Sgber char *data; 863235537Sgber u_int ret; 864235537Sgber 865235537Sgber /* Overwrite next block with ff if not nand device */ 866235537Sgber if (!is_nand) { 867235537Sgber data = get_block(seg_endblock, 0); 868235537Sgber memset(data, 0xff, blocksize); 869235537Sgber } 870235537Sgber 871235537Sgber LIST_FOREACH(block, &block_head, block_link) { 872235537Sgber lseek(fda, block->number * blocksize, SEEK_SET); 873235537Sgber ret = write(fda, block->data, blocksize); 874235537Sgber if (ret != blocksize) 875235537Sgber err(1, "cannot write filesystem data"); 876235537Sgber } 877235537Sgber} 878235537Sgber 879235537Sgberstatic void 880235537Sgbercheck_parameters(void) 881235537Sgber{ 882235537Sgber int i; 883235537Sgber 884235537Sgber /* check blocksize */ 885235537Sgber if ((blocksize < NANDFS_MIN_BLOCKSIZE) || (blocksize > MAXBSIZE) || 886235537Sgber ((blocksize - 1) & blocksize)) { 887235537Sgber errx(1, "Bad blocksize (%zu). Must be in range [%u-%u] " 888235537Sgber "and a power of two.", blocksize, NANDFS_MIN_BLOCKSIZE, 889235537Sgber MAXBSIZE); 890235537Sgber } 891235537Sgber 892235537Sgber /* check blocks per segments */ 893235537Sgber if ((blocks_per_segment < NANDFS_SEG_MIN_BLOCKS) || 894235537Sgber ((blocksize - 1) & blocksize)) 895235537Sgber errx(1, "Bad blocks per segment (%lu). Must be greater than " 896235537Sgber "%u and a power of two.", blocks_per_segment, 897235537Sgber NANDFS_SEG_MIN_BLOCKS); 898235537Sgber 899235537Sgber /* check reserved segment percentage */ 900285453Sbrueffer if ((rsv_segment_percent < 1) || (rsv_segment_percent > 99)) 901235537Sgber errx(1, "Bad reserved segment percentage. " 902235537Sgber "Must in range 1..99."); 903235537Sgber 904235537Sgber /* check volume label */ 905235537Sgber i = 0; 906235537Sgber if (volumelabel) { 907235537Sgber while (isalnum(volumelabel[++i])) 908235537Sgber ; 909235537Sgber 910235537Sgber if (volumelabel[i] != '\0') { 911235537Sgber errx(1, "bad volume label. " 912235537Sgber "Valid characters are alphanumerics."); 913235537Sgber } 914235537Sgber 915235537Sgber if (strlen(volumelabel) >= 16) 916235537Sgber errx(1, "Bad volume label. Length is longer than %d.", 917235537Sgber 16); 918235537Sgber } 919235537Sgber 920235537Sgber nandfs_time = time(NULL); 921235537Sgber} 922235537Sgber 923235537Sgberstatic void 924235537Sgberprint_parameters(void) 925235537Sgber{ 926235537Sgber 927235537Sgber printf("filesystem parameters:\n"); 928235537Sgber printf("blocksize: %#zx sectorsize: %#zx\n", blocksize, sectorsize); 929235537Sgber printf("erasesize: %#jx mediasize: %#jx\n", erasesize, mediasize); 930235537Sgber printf("segment size: %#jx blocks per segment: %#x\n", segsize, 931235537Sgber (uint32_t)blocks_per_segment); 932235537Sgber} 933235537Sgber 934235537Sgber/* 935235537Sgber * Exit with error if file system is mounted. 936235537Sgber */ 937235537Sgberstatic void 938235537Sgbercheck_mounted(const char *fname, mode_t mode) 939235537Sgber{ 940235537Sgber struct statfs *mp; 941235537Sgber const char *s1, *s2; 942235537Sgber size_t len; 943235537Sgber int n, r; 944235537Sgber 945235537Sgber if (!(n = getmntinfo(&mp, MNT_NOWAIT))) 946235537Sgber err(1, "getmntinfo"); 947235537Sgber 948235537Sgber len = strlen(_PATH_DEV); 949235537Sgber s1 = fname; 950235537Sgber if (!strncmp(s1, _PATH_DEV, len)) 951235537Sgber s1 += len; 952235537Sgber 953235537Sgber r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; 954235537Sgber 955235537Sgber for (; n--; mp++) { 956235537Sgber s2 = mp->f_mntfromname; 957235537Sgber 958235537Sgber if (!strncmp(s2, _PATH_DEV, len)) 959235537Sgber s2 += len; 960235537Sgber if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || 961235537Sgber !strcmp(s1, s2)) 962235537Sgber errx(1, "%s is mounted on %s", fname, mp->f_mntonname); 963235537Sgber } 964235537Sgber} 965235537Sgber 966235537Sgberstatic void 967235537Sgbercalculate_geometry(int fd) 968235537Sgber{ 969235537Sgber struct chip_param_io chip_params; 970235537Sgber char ident[DISK_IDENT_SIZE]; 971235537Sgber char medianame[MAXPATHLEN]; 972235537Sgber 973235537Sgber /* Check storage type */ 974235537Sgber g_get_ident(fd, ident, DISK_IDENT_SIZE); 975235537Sgber g_get_name(ident, medianame, MAXPATHLEN); 976235537Sgber debug("device name: %s", medianame); 977235537Sgber 978235537Sgber is_nand = (strstr(medianame, "gnand") != NULL); 979235537Sgber debug("is_nand = %d", is_nand); 980235537Sgber 981235537Sgber sectorsize = g_sectorsize(fd); 982235537Sgber debug("sectorsize: %#zx", sectorsize); 983235537Sgber 984235537Sgber /* Get storage size */ 985235537Sgber mediasize = g_mediasize(fd); 986235537Sgber debug("mediasize: %#jx", mediasize); 987235537Sgber 988235537Sgber /* Get storage erase unit size */ 989235537Sgber if (!is_nand) 990235537Sgber erasesize = NANDFS_DEF_ERASESIZE; 991266274Sian else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) != -1) 992266274Sian erasesize = chip_params.page_size * chip_params.pages_per_block; 993266274Sian else 994235537Sgber errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); 995235537Sgber 996235537Sgber debug("erasesize: %#jx", (uintmax_t)erasesize); 997235537Sgber 998235537Sgber if (blocks_per_segment == 0) { 999235537Sgber if (erasesize >= NANDFS_MIN_SEGSIZE) 1000235537Sgber blocks_per_segment = erasesize / blocksize; 1001235537Sgber else 1002235537Sgber blocks_per_segment = NANDFS_MIN_SEGSIZE / blocksize; 1003235537Sgber } 1004235537Sgber 1005235537Sgber /* Calculate number of segments */ 1006235537Sgber segsize = blocksize * blocks_per_segment; 1007235537Sgber nsegments = ((mediasize - NANDFS_NFSAREAS * erasesize) / segsize) - 2; 1008235537Sgber debug("segsize: %#jx", segsize); 1009235537Sgber debug("nsegments: %#jx", nsegments); 1010235537Sgber} 1011235537Sgber 1012235537Sgberstatic void 1013235537Sgbererase_device(int fd) 1014235537Sgber{ 1015235537Sgber int rest, failed; 1016235537Sgber uint64_t i, nblocks; 1017235537Sgber off_t offset; 1018235537Sgber 1019235537Sgber failed = 0; 1020235537Sgber for (i = 0; i < NANDFS_NFSAREAS; i++) { 1021235537Sgber debug("Deleting %jx\n", i * erasesize); 1022235537Sgber if (g_delete(fd, i * erasesize, erasesize)) { 1023235537Sgber printf("cannot delete %jx\n", i * erasesize); 1024235537Sgber fsdata_blocks_state[i] = NANDFS_BLOCK_BAD; 1025235537Sgber failed++; 1026235537Sgber } else 1027235537Sgber fsdata_blocks_state[i] = NANDFS_BLOCK_GOOD; 1028235537Sgber } 1029235537Sgber 1030235537Sgber if (failed == NANDFS_NFSAREAS) { 1031235537Sgber printf("%d first blocks not usable. Unable to create " 1032235537Sgber "filesystem.\n", failed); 1033235537Sgber exit(1); 1034235537Sgber } 1035235537Sgber 1036235537Sgber for (i = 0; i < nsegments; i++) { 1037235537Sgber offset = NANDFS_NFSAREAS * erasesize + i * segsize; 1038235537Sgber if (g_delete(fd, offset, segsize)) { 1039235537Sgber printf("cannot delete segment %jx (offset %jd)\n", 1040235537Sgber i, offset); 1041235537Sgber bad_segments_count++; 1042235537Sgber bad_segments = realloc(bad_segments, 1043235537Sgber bad_segments_count * sizeof(uint32_t)); 1044235537Sgber bad_segments[bad_segments_count - 1] = i; 1045235537Sgber } 1046235537Sgber } 1047235537Sgber 1048235537Sgber if (bad_segments_count == nsegments) { 1049235537Sgber printf("no valid segments\n"); 1050235537Sgber exit(1); 1051235537Sgber } 1052235537Sgber 1053235537Sgber /* Delete remaining blocks at the end of device */ 1054235537Sgber rest = mediasize % segsize; 1055235537Sgber nblocks = rest / erasesize; 1056235537Sgber for (i = 0; i < nblocks; i++) { 1057235537Sgber offset = (segsize * nsegments) + (i * erasesize); 1058235537Sgber if (g_delete(fd, offset, erasesize)) { 1059235537Sgber printf("cannot delete space after last segment " 1060235537Sgber "- probably a bad block\n"); 1061235537Sgber } 1062235537Sgber } 1063235537Sgber} 1064235537Sgber 1065235537Sgberstatic void 1066235537Sgbererase_initial(int fd) 1067235537Sgber{ 1068235537Sgber char buf[512]; 1069235537Sgber u_int i; 1070235537Sgber 1071235537Sgber memset(buf, 0xff, sizeof(buf)); 1072235537Sgber 1073235537Sgber lseek(fd, 0, SEEK_SET); 1074235537Sgber for (i = 0; i < NANDFS_NFSAREAS * erasesize; i += sizeof(buf)) 1075235537Sgber write(fd, buf, sizeof(buf)); 1076235537Sgber} 1077235537Sgber 1078235537Sgberstatic void 1079235537Sgbercreate_nandfs(int fd) 1080235537Sgber{ 1081235537Sgber 1082235537Sgber create_fs(); 1083235537Sgber 1084235537Sgber write_fs(fd); 1085235537Sgber} 1086235537Sgber 1087235537Sgberstatic void 1088235537Sgberprint_summary(void) 1089235537Sgber{ 1090235537Sgber 1091235537Sgber printf("filesystem created succesfully\n"); 1092235537Sgber printf("total segments: %#jx valid segments: %#jx\n", nsegments, 1093235537Sgber nsegments - bad_segments_count); 1094235537Sgber printf("total space: %ju MB free: %ju MB\n", 1095235537Sgber (nsegments * 1096235537Sgber blocks_per_segment * blocksize) / (1024 * 1024), 1097235537Sgber ((nsegments - bad_segments_count) * 1098235537Sgber blocks_per_segment * blocksize) / (1024 * 1024)); 1099235537Sgber} 1100235537Sgber 1101235537Sgberint 1102235537Sgbermain(int argc, char *argv[]) 1103235537Sgber{ 1104235537Sgber struct stat sb; 1105235537Sgber char buf[MAXPATHLEN]; 1106235537Sgber const char opts[] = "b:B:L:m:"; 1107235537Sgber const char *fname; 1108235537Sgber int ch, fd; 1109235537Sgber 1110235537Sgber while ((ch = getopt(argc, argv, opts)) != -1) { 1111235537Sgber switch (ch) { 1112235537Sgber case 'b': 1113235537Sgber blocksize = strtol(optarg, (char **)NULL, 10); 1114235537Sgber if (blocksize == 0) 1115235537Sgber usage(); 1116235537Sgber break; 1117235537Sgber case 'B': 1118235537Sgber blocks_per_segment = strtol(optarg, (char **)NULL, 10); 1119235537Sgber if (blocks_per_segment == 0) 1120235537Sgber usage(); 1121235537Sgber break; 1122235537Sgber case 'L': 1123235537Sgber volumelabel = optarg; 1124235537Sgber break; 1125235537Sgber case 'm': 1126235537Sgber rsv_segment_percent = strtol(optarg, (char **)NULL, 10); 1127235537Sgber if (rsv_segment_percent == 0) 1128235537Sgber usage(); 1129235537Sgber break; 1130235537Sgber default: 1131235537Sgber usage(); 1132235537Sgber } 1133235537Sgber } 1134235537Sgber 1135235537Sgber argc -= optind; 1136235537Sgber argv += optind; 1137235537Sgber if (argc < 1 || argc > 2) 1138235537Sgber usage(); 1139235537Sgber 1140235537Sgber /* construct proper device path */ 1141235537Sgber fname = *argv++; 1142235537Sgber if (!strchr(fname, '/')) { 1143235537Sgber snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 1144235537Sgber if (!(fname = strdup(buf))) 1145235537Sgber err(1, NULL); 1146235537Sgber } 1147235537Sgber 1148235537Sgber fd = g_open(fname, 1); 1149235537Sgber if (fd == -1) 1150235537Sgber err(1, "Cannot open %s", fname); 1151235537Sgber 1152235537Sgber if (fstat(fd, &sb) == -1) 1153235537Sgber err(1, "Cannot stat %s", fname); 1154235537Sgber if (!S_ISCHR(sb.st_mode)) 1155235537Sgber warnx("%s is not a character device", fname); 1156235537Sgber 1157235537Sgber check_mounted(fname, sb.st_mode); 1158235537Sgber 1159235537Sgber calculate_geometry(fd); 1160235537Sgber 1161235537Sgber check_parameters(); 1162235537Sgber 1163235537Sgber print_parameters(); 1164235537Sgber 1165235537Sgber if (is_nand) 1166235537Sgber erase_device(fd); 1167235537Sgber else 1168235537Sgber erase_initial(fd); 1169235537Sgber 1170235537Sgber create_nandfs(fd); 1171235537Sgber 1172235537Sgber print_summary(); 1173235537Sgber 1174235537Sgber g_close(fd); 1175235537Sgber 1176235537Sgber return (0); 1177235537Sgber} 1178235537Sgber 1179235537Sgber 1180