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: stable/10/sbin/newfs_nandfs/newfs_nandfs.c 316772 2017-04-13 17:11:50Z dim $"); 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{ 523316772Sdim struct uuid tmp; 524235537Sgber 525235537Sgber memset(&fsdata, 0, sizeof(struct nandfs_fsdata)); 526235537Sgber 527235537Sgber fsdata.f_magic = NANDFS_FSDATA_MAGIC; 528235537Sgber fsdata.f_nsegments = nsegments; 529235537Sgber fsdata.f_erasesize = erasesize; 530235537Sgber fsdata.f_first_data_block = NANDFS_FIRST_BLOCK; 531235537Sgber fsdata.f_blocks_per_segment = blocks_per_segment; 532235537Sgber fsdata.f_r_segments_percentage = rsv_segment_percent; 533235537Sgber fsdata.f_rev_level = NANDFS_CURRENT_REV; 534235537Sgber fsdata.f_sbbytes = NANDFS_SB_BYTES; 535235537Sgber fsdata.f_bytes = NANDFS_FSDATA_CRC_BYTES; 536235537Sgber fsdata.f_ctime = nandfs_time; 537235537Sgber fsdata.f_log_block_size = nandfs_log2(blocksize) - 10; 538235537Sgber fsdata.f_errors = 1; 539235537Sgber fsdata.f_inode_size = sizeof(struct nandfs_inode); 540235537Sgber fsdata.f_dat_entry_size = sizeof(struct nandfs_dat_entry); 541235537Sgber fsdata.f_checkpoint_size = sizeof(struct nandfs_checkpoint); 542235537Sgber fsdata.f_segment_usage_size = sizeof(struct nandfs_segment_usage); 543235537Sgber 544316772Sdim uuidgen(&tmp, 1); 545316772Sdim fsdata.f_uuid = tmp; 546235537Sgber 547235537Sgber if (volumelabel) 548235537Sgber memcpy(fsdata.f_volume_name, volumelabel, 16); 549235537Sgber 550235537Sgber fsdata.f_sum = crc32_le(0, (const uint8_t *)&fsdata, 551235537Sgber NANDFS_FSDATA_CRC_BYTES); 552235537Sgber} 553235537Sgber 554235537Sgberstatic void 555235537Sgbersave_fsdata(void *data) 556235537Sgber{ 557235537Sgber 558235537Sgber memcpy(data, &fsdata, sizeof(fsdata)); 559235537Sgber} 560235537Sgber 561235537Sgberstatic void 562235537Sgbercreate_super_block(void) 563235537Sgber{ 564235537Sgber 565235537Sgber memset(&super_block, 0, sizeof(struct nandfs_super_block)); 566235537Sgber 567235537Sgber super_block.s_magic = NANDFS_SUPER_MAGIC; 568235537Sgber super_block.s_last_cno = NANDFS_FIRST_CNO; 569235537Sgber super_block.s_last_pseg = NANDFS_FIRST_BLOCK; 570235537Sgber super_block.s_last_seq = 1; 571235537Sgber super_block.s_free_blocks_count = 572235537Sgber (nsegments - bad_segments_count) * blocks_per_segment; 573235537Sgber super_block.s_mtime = 0; 574235537Sgber super_block.s_wtime = nandfs_time; 575235537Sgber super_block.s_state = NANDFS_VALID_FS; 576235537Sgber 577235537Sgber super_block.s_sum = crc32_le(0, (const uint8_t *)&super_block, 578235537Sgber NANDFS_SB_BYTES); 579235537Sgber} 580235537Sgber 581235537Sgberstatic void 582235537Sgbersave_super_block(void *data) 583235537Sgber{ 584235537Sgber 585235537Sgber memcpy(data, &super_block, sizeof(super_block)); 586235537Sgber} 587235537Sgber 588235537Sgberstatic void 589235537Sgbersave_super_root(void) 590235537Sgber{ 591235537Sgber 592235537Sgber sr->sr_bytes = NANDFS_SR_BYTES; 593235537Sgber sr->sr_flags = 0; 594235537Sgber sr->sr_nongc_ctime = nandfs_time; 595235537Sgber datfile.inode = &sr->sr_dat; 596235537Sgber cpfile.inode = &sr->sr_cpfile; 597235537Sgber sufile.inode = &sr->sr_sufile; 598235537Sgber} 599235537Sgber 600235537Sgberstatic struct nandfs_dir_entry * 601235537Sgberadd_de(void *block, struct nandfs_dir_entry *de, uint64_t ino, 602235537Sgber const char *name, uint8_t type) 603235537Sgber{ 604235537Sgber uint16_t reclen; 605235537Sgber 606235537Sgber /* modify last de */ 607235537Sgber de->rec_len = NANDFS_DIR_REC_LEN(de->name_len); 608235537Sgber de = (void *)((uint8_t *)de + de->rec_len); 609235537Sgber 610235537Sgber reclen = blocksize - ((uintptr_t)de - (uintptr_t)block); 611235537Sgber if (reclen < NANDFS_DIR_REC_LEN(strlen(name))) { 612235537Sgber printf("nandfs: too many dir entries for one block\n"); 613235537Sgber return (NULL); 614235537Sgber } 615235537Sgber 616235537Sgber de->inode = ino; 617235537Sgber de->rec_len = reclen; 618235537Sgber de->name_len = strlen(name); 619235537Sgber de->file_type = type; 620235537Sgber memset(de->name, 0, 621235537Sgber (strlen(name) + NANDFS_DIR_PAD - 1) & ~NANDFS_DIR_ROUND); 622235537Sgber memcpy(de->name, name, strlen(name)); 623235537Sgber 624235537Sgber return (de); 625235537Sgber} 626235537Sgber 627235537Sgberstatic struct nandfs_dir_entry * 628235537Sgbermake_dir(void *block, uint64_t ino, uint64_t parent_ino) 629235537Sgber{ 630235537Sgber struct nandfs_dir_entry *de = (struct nandfs_dir_entry *)block; 631235537Sgber 632235537Sgber /* create '..' entry */ 633235537Sgber de->inode = parent_ino; 634235537Sgber de->rec_len = NANDFS_DIR_REC_LEN(2); 635235537Sgber de->name_len = 2; 636235537Sgber de->file_type = DT_DIR; 637235537Sgber memset(de->name, 0, NANDFS_DIR_NAME_LEN(2)); 638235537Sgber memcpy(de->name, "..", 2); 639235537Sgber 640235537Sgber /* create '.' entry */ 641235537Sgber de = (void *)((uint8_t *)block + NANDFS_DIR_REC_LEN(2)); 642235537Sgber de->inode = ino; 643235537Sgber de->rec_len = blocksize - NANDFS_DIR_REC_LEN(2); 644235537Sgber de->name_len = 1; 645235537Sgber de->file_type = DT_DIR; 646235537Sgber memset(de->name, 0, NANDFS_DIR_NAME_LEN(1)); 647235537Sgber memcpy(de->name, ".", 1); 648235537Sgber 649235537Sgber return (de); 650235537Sgber} 651235537Sgber 652235537Sgberstatic void 653235537Sgbersave_root_dir(void) 654235537Sgber{ 655235537Sgber struct file_info *root = &user_files[0]; 656235537Sgber struct nandfs_dir_entry *de; 657235537Sgber uint32_t i; 658235537Sgber void *block; 659235537Sgber 660235537Sgber block = get_block(root->blocks[0], 0); 661235537Sgber 662235537Sgber de = make_dir(block, root->ino, root->ino); 663235537Sgber for (i = 1; i < nuserfiles; i++) 664235537Sgber de = add_de(block, de, user_files[i].ino, user_files[i].name, 665235537Sgber IFTODT(user_files[i].mode)); 666235537Sgber 667235537Sgber root->size = ((uintptr_t)de - (uintptr_t)block) + 668235537Sgber NANDFS_DIR_REC_LEN(de->name_len); 669235537Sgber} 670235537Sgber 671235537Sgberstatic void 672235537Sgbersave_sufile(void) 673235537Sgber{ 674235537Sgber struct nandfs_sufile_header *header; 675235537Sgber struct nandfs_segment_usage *su; 676235537Sgber uint64_t blk, i, off; 677235537Sgber void *block; 678235537Sgber int start; 679235537Sgber 680235537Sgber /* 681235537Sgber * At the beginning just zero-out everything 682235537Sgber */ 683235537Sgber for (i = 0; i < sufile.nblocks; i++) 684235537Sgber get_block(sufile.blocks[i], 0); 685235537Sgber 686235537Sgber start = 0; 687235537Sgber 688235537Sgber block = get_block(sufile.blocks[start], 0); 689235537Sgber header = (struct nandfs_sufile_header *)block; 690235537Sgber header->sh_ncleansegs = nsegments - bad_segments_count - 1; 691235537Sgber header->sh_ndirtysegs = 1; 692235537Sgber header->sh_last_alloc = 1; 693235537Sgber 694235537Sgber su = (struct nandfs_segment_usage *)header; 695235537Sgber off = NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET; 696235537Sgber /* Allocate data segment */ 697235537Sgber su[off].su_lastmod = nandfs_time; 698235537Sgber /* nblocks = segment blocks + segsum block + superroot */ 699235537Sgber su[off].su_nblocks = seg_nblocks + 2; 700235537Sgber su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; 701235537Sgber off++; 702235537Sgber /* Allocate next segment */ 703235537Sgber su[off].su_lastmod = nandfs_time; 704235537Sgber su[off].su_nblocks = 0; 705235537Sgber su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY; 706235537Sgber for (i = 0; i < bad_segments_count; i++) { 707235537Sgber nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &off); 708235537Sgber debug("storing bad_segments[%jd]=%x at %jx off %jx\n", i, 709235537Sgber bad_segments[i], blk, off); 710235537Sgber block = get_block(sufile.blocks[blk], 711235537Sgber off * sizeof(struct nandfs_segment_usage *)); 712235537Sgber su = (struct nandfs_segment_usage *)block; 713235537Sgber su[off].su_lastmod = nandfs_time; 714235537Sgber su[off].su_nblocks = 0; 715235537Sgber su[off].su_flags = NANDFS_SEGMENT_USAGE_ERROR; 716235537Sgber } 717235537Sgber} 718235537Sgber 719235537Sgberstatic void 720235537Sgbersave_cpfile(void) 721235537Sgber{ 722235537Sgber struct nandfs_cpfile_header *header; 723235537Sgber struct nandfs_checkpoint *cp, *initial_cp; 724235537Sgber int i, entries = blocksize / sizeof(struct nandfs_checkpoint); 725235537Sgber uint64_t cno; 726235537Sgber 727235537Sgber header = (struct nandfs_cpfile_header *)get_block(cpfile.blocks[0], 0); 728235537Sgber header->ch_ncheckpoints = 1; 729235537Sgber header->ch_nsnapshots = 0; 730235537Sgber 731235537Sgber cp = (struct nandfs_checkpoint *)header; 732235537Sgber 733235537Sgber /* fill first checkpoint data*/ 734235537Sgber initial_cp = &cp[NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET]; 735235537Sgber initial_cp->cp_flags = 0; 736235537Sgber initial_cp->cp_checkpoints_count = 0; 737235537Sgber initial_cp->cp_cno = NANDFS_FIRST_CNO; 738235537Sgber initial_cp->cp_create = nandfs_time; 739235537Sgber initial_cp->cp_nblk_inc = seg_endblock - 1; 740235537Sgber initial_cp->cp_blocks_count = seg_nblocks; 741235537Sgber memset(&initial_cp->cp_snapshot_list, 0, 742235537Sgber sizeof(struct nandfs_snapshot_list)); 743235537Sgber 744235537Sgber ifile.inode = &initial_cp->cp_ifile_inode; 745235537Sgber 746235537Sgber /* mark rest of cp as invalid */ 747235537Sgber cno = NANDFS_FIRST_CNO + 1; 748235537Sgber i = NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1; 749235537Sgber for (; i < entries; i++) { 750235537Sgber cp[i].cp_cno = cno++; 751235537Sgber cp[i].cp_flags = NANDFS_CHECKPOINT_INVALID; 752235537Sgber } 753235537Sgber} 754235537Sgber 755235537Sgberstatic void 756235537Sgberinit_inode(struct nandfs_inode *inode, struct file_info *file) 757235537Sgber{ 758235537Sgber 759235537Sgber inode->i_blocks = file->nblocks; 760235537Sgber inode->i_ctime = nandfs_time; 761235537Sgber inode->i_mtime = nandfs_time; 762235537Sgber inode->i_mode = file->mode & 0xffff; 763235537Sgber inode->i_links_count = 1; 764235537Sgber 765235537Sgber if (file->size > 0) 766235537Sgber inode->i_size = file->size; 767235537Sgber else 768235537Sgber inode->i_size = 0; 769235537Sgber 770235537Sgber if (file->ino == NANDFS_USER_INO) 771235537Sgber inode->i_flags = SF_NOUNLINK|UF_NOUNLINK; 772235537Sgber else 773235537Sgber inode->i_flags = 0; 774235537Sgber} 775235537Sgber 776235537Sgberstatic void 777235537Sgbersave_ifile(void) 778235537Sgber{ 779235537Sgber struct nandfs_inode *inode; 780235537Sgber struct file_info *file; 781235537Sgber uint64_t ino, blk, off; 782235537Sgber uint32_t i; 783235537Sgber 784235537Sgber prepare_blockgrouped_file(ifile.blocks[0]); 785235537Sgber for (i = 0; i <= NANDFS_USER_INO; i++) 786235537Sgber alloc_blockgrouped_file(ifile.blocks[0], i); 787235537Sgber 788235537Sgber for (i = 0; i < nuserfiles; i++) { 789235537Sgber file = &user_files[i]; 790235537Sgber ino = file->ino; 791235537Sgber blk = ino / (blocksize / sizeof(*inode)); 792235537Sgber off = ino % (blocksize / sizeof(*inode)); 793235537Sgber inode = 794235537Sgber (struct nandfs_inode *)get_block(ifile.blocks[2 + blk], 2 + blk); 795235537Sgber file->inode = &inode[off]; 796235537Sgber init_inode(file->inode, file); 797235537Sgber } 798235537Sgber 799235537Sgber init_inode(ifile.inode, &ifile); 800235537Sgber init_inode(cpfile.inode, &cpfile); 801235537Sgber init_inode(sufile.inode, &sufile); 802235537Sgber init_inode(datfile.inode, &datfile); 803235537Sgber} 804235537Sgber 805235537Sgberstatic int 806235537Sgbercreate_fs(void) 807235537Sgber{ 808235537Sgber uint64_t start_block; 809235537Sgber uint32_t segsum_size; 810235537Sgber char *data; 811235537Sgber int i; 812235537Sgber 813235537Sgber nuserfiles = (sizeof(user_files) / sizeof(user_files[0])); 814235537Sgber 815235537Sgber /* Count and assign blocks */ 816235537Sgber count_seg_blocks(); 817235537Sgber segsum_size = segment_size(); 818235537Sgber start_block = NANDFS_FIRST_BLOCK + SIZE_TO_BLOCK(segsum_size); 819235537Sgber assign_file_blocks(start_block); 820235537Sgber 821235537Sgber /* Create super root structure */ 822235537Sgber save_super_root(); 823235537Sgber 824235537Sgber /* Create root directory */ 825235537Sgber save_root_dir(); 826235537Sgber 827235537Sgber /* Fill in file contents */ 828235537Sgber save_sufile(); 829235537Sgber save_cpfile(); 830235537Sgber save_ifile(); 831235537Sgber save_datfile(); 832235537Sgber 833235537Sgber /* Save fsdata and superblocks */ 834235537Sgber create_fsdata(); 835235537Sgber create_super_block(); 836235537Sgber 837235537Sgber for (i = 0; i < NANDFS_NFSAREAS; i++) { 838235537Sgber if (fsdata_blocks_state[i] != NANDFS_BLOCK_GOOD) 839235537Sgber continue; 840235537Sgber 841235537Sgber data = get_block((i * erasesize)/blocksize, 0); 842235537Sgber save_fsdata(data); 843235537Sgber 844235537Sgber data = get_block((i * erasesize + NANDFS_SBLOCK_OFFSET_BYTES) / 845235537Sgber blocksize, 0); 846235537Sgber if (blocksize > NANDFS_SBLOCK_OFFSET_BYTES) 847235537Sgber data += NANDFS_SBLOCK_OFFSET_BYTES; 848235537Sgber save_super_block(data); 849235537Sgber memset(data + sizeof(struct nandfs_super_block), 0xff, 850235537Sgber (blocksize - sizeof(struct nandfs_super_block) - 851235537Sgber NANDFS_SBLOCK_OFFSET_BYTES)); 852235537Sgber } 853235537Sgber 854235537Sgber /* Save segment summary and CRCs */ 855235537Sgber save_segsum(get_block(NANDFS_FIRST_BLOCK, 0)); 856235537Sgber 857235537Sgber return (0); 858235537Sgber} 859235537Sgber 860235537Sgberstatic void 861235537Sgberwrite_fs(int fda) 862235537Sgber{ 863235537Sgber struct nandfs_block *block; 864235537Sgber char *data; 865235537Sgber u_int ret; 866235537Sgber 867235537Sgber /* Overwrite next block with ff if not nand device */ 868235537Sgber if (!is_nand) { 869235537Sgber data = get_block(seg_endblock, 0); 870235537Sgber memset(data, 0xff, blocksize); 871235537Sgber } 872235537Sgber 873235537Sgber LIST_FOREACH(block, &block_head, block_link) { 874235537Sgber lseek(fda, block->number * blocksize, SEEK_SET); 875235537Sgber ret = write(fda, block->data, blocksize); 876235537Sgber if (ret != blocksize) 877235537Sgber err(1, "cannot write filesystem data"); 878235537Sgber } 879235537Sgber} 880235537Sgber 881235537Sgberstatic void 882235537Sgbercheck_parameters(void) 883235537Sgber{ 884235537Sgber int i; 885235537Sgber 886235537Sgber /* check blocksize */ 887235537Sgber if ((blocksize < NANDFS_MIN_BLOCKSIZE) || (blocksize > MAXBSIZE) || 888235537Sgber ((blocksize - 1) & blocksize)) { 889235537Sgber errx(1, "Bad blocksize (%zu). Must be in range [%u-%u] " 890235537Sgber "and a power of two.", blocksize, NANDFS_MIN_BLOCKSIZE, 891235537Sgber MAXBSIZE); 892235537Sgber } 893235537Sgber 894235537Sgber /* check blocks per segments */ 895235537Sgber if ((blocks_per_segment < NANDFS_SEG_MIN_BLOCKS) || 896235537Sgber ((blocksize - 1) & blocksize)) 897235537Sgber errx(1, "Bad blocks per segment (%lu). Must be greater than " 898235537Sgber "%u and a power of two.", blocks_per_segment, 899235537Sgber NANDFS_SEG_MIN_BLOCKS); 900235537Sgber 901235537Sgber /* check reserved segment percentage */ 902285453Sbrueffer if ((rsv_segment_percent < 1) || (rsv_segment_percent > 99)) 903235537Sgber errx(1, "Bad reserved segment percentage. " 904235537Sgber "Must in range 1..99."); 905235537Sgber 906235537Sgber /* check volume label */ 907235537Sgber i = 0; 908235537Sgber if (volumelabel) { 909235537Sgber while (isalnum(volumelabel[++i])) 910235537Sgber ; 911235537Sgber 912235537Sgber if (volumelabel[i] != '\0') { 913235537Sgber errx(1, "bad volume label. " 914235537Sgber "Valid characters are alphanumerics."); 915235537Sgber } 916235537Sgber 917235537Sgber if (strlen(volumelabel) >= 16) 918235537Sgber errx(1, "Bad volume label. Length is longer than %d.", 919235537Sgber 16); 920235537Sgber } 921235537Sgber 922235537Sgber nandfs_time = time(NULL); 923235537Sgber} 924235537Sgber 925235537Sgberstatic void 926235537Sgberprint_parameters(void) 927235537Sgber{ 928235537Sgber 929235537Sgber printf("filesystem parameters:\n"); 930235537Sgber printf("blocksize: %#zx sectorsize: %#zx\n", blocksize, sectorsize); 931235537Sgber printf("erasesize: %#jx mediasize: %#jx\n", erasesize, mediasize); 932235537Sgber printf("segment size: %#jx blocks per segment: %#x\n", segsize, 933235537Sgber (uint32_t)blocks_per_segment); 934235537Sgber} 935235537Sgber 936235537Sgber/* 937235537Sgber * Exit with error if file system is mounted. 938235537Sgber */ 939235537Sgberstatic void 940235537Sgbercheck_mounted(const char *fname, mode_t mode) 941235537Sgber{ 942235537Sgber struct statfs *mp; 943235537Sgber const char *s1, *s2; 944235537Sgber size_t len; 945235537Sgber int n, r; 946235537Sgber 947235537Sgber if (!(n = getmntinfo(&mp, MNT_NOWAIT))) 948235537Sgber err(1, "getmntinfo"); 949235537Sgber 950235537Sgber len = strlen(_PATH_DEV); 951235537Sgber s1 = fname; 952235537Sgber if (!strncmp(s1, _PATH_DEV, len)) 953235537Sgber s1 += len; 954235537Sgber 955235537Sgber r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; 956235537Sgber 957235537Sgber for (; n--; mp++) { 958235537Sgber s2 = mp->f_mntfromname; 959235537Sgber 960235537Sgber if (!strncmp(s2, _PATH_DEV, len)) 961235537Sgber s2 += len; 962235537Sgber if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || 963235537Sgber !strcmp(s1, s2)) 964235537Sgber errx(1, "%s is mounted on %s", fname, mp->f_mntonname); 965235537Sgber } 966235537Sgber} 967235537Sgber 968235537Sgberstatic void 969235537Sgbercalculate_geometry(int fd) 970235537Sgber{ 971235537Sgber struct chip_param_io chip_params; 972235537Sgber char ident[DISK_IDENT_SIZE]; 973235537Sgber char medianame[MAXPATHLEN]; 974235537Sgber 975235537Sgber /* Check storage type */ 976235537Sgber g_get_ident(fd, ident, DISK_IDENT_SIZE); 977235537Sgber g_get_name(ident, medianame, MAXPATHLEN); 978235537Sgber debug("device name: %s", medianame); 979235537Sgber 980235537Sgber is_nand = (strstr(medianame, "gnand") != NULL); 981235537Sgber debug("is_nand = %d", is_nand); 982235537Sgber 983235537Sgber sectorsize = g_sectorsize(fd); 984235537Sgber debug("sectorsize: %#zx", sectorsize); 985235537Sgber 986235537Sgber /* Get storage size */ 987235537Sgber mediasize = g_mediasize(fd); 988235537Sgber debug("mediasize: %#jx", mediasize); 989235537Sgber 990235537Sgber /* Get storage erase unit size */ 991235537Sgber if (!is_nand) 992235537Sgber erasesize = NANDFS_DEF_ERASESIZE; 993266274Sian else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) != -1) 994266274Sian erasesize = chip_params.page_size * chip_params.pages_per_block; 995266274Sian else 996235537Sgber errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)"); 997235537Sgber 998235537Sgber debug("erasesize: %#jx", (uintmax_t)erasesize); 999235537Sgber 1000235537Sgber if (blocks_per_segment == 0) { 1001235537Sgber if (erasesize >= NANDFS_MIN_SEGSIZE) 1002235537Sgber blocks_per_segment = erasesize / blocksize; 1003235537Sgber else 1004235537Sgber blocks_per_segment = NANDFS_MIN_SEGSIZE / blocksize; 1005235537Sgber } 1006235537Sgber 1007235537Sgber /* Calculate number of segments */ 1008235537Sgber segsize = blocksize * blocks_per_segment; 1009235537Sgber nsegments = ((mediasize - NANDFS_NFSAREAS * erasesize) / segsize) - 2; 1010235537Sgber debug("segsize: %#jx", segsize); 1011235537Sgber debug("nsegments: %#jx", nsegments); 1012235537Sgber} 1013235537Sgber 1014235537Sgberstatic void 1015235537Sgbererase_device(int fd) 1016235537Sgber{ 1017235537Sgber int rest, failed; 1018235537Sgber uint64_t i, nblocks; 1019235537Sgber off_t offset; 1020235537Sgber 1021235537Sgber failed = 0; 1022235537Sgber for (i = 0; i < NANDFS_NFSAREAS; i++) { 1023235537Sgber debug("Deleting %jx\n", i * erasesize); 1024235537Sgber if (g_delete(fd, i * erasesize, erasesize)) { 1025235537Sgber printf("cannot delete %jx\n", i * erasesize); 1026235537Sgber fsdata_blocks_state[i] = NANDFS_BLOCK_BAD; 1027235537Sgber failed++; 1028235537Sgber } else 1029235537Sgber fsdata_blocks_state[i] = NANDFS_BLOCK_GOOD; 1030235537Sgber } 1031235537Sgber 1032235537Sgber if (failed == NANDFS_NFSAREAS) { 1033235537Sgber printf("%d first blocks not usable. Unable to create " 1034235537Sgber "filesystem.\n", failed); 1035235537Sgber exit(1); 1036235537Sgber } 1037235537Sgber 1038235537Sgber for (i = 0; i < nsegments; i++) { 1039235537Sgber offset = NANDFS_NFSAREAS * erasesize + i * segsize; 1040235537Sgber if (g_delete(fd, offset, segsize)) { 1041235537Sgber printf("cannot delete segment %jx (offset %jd)\n", 1042235537Sgber i, offset); 1043235537Sgber bad_segments_count++; 1044235537Sgber bad_segments = realloc(bad_segments, 1045235537Sgber bad_segments_count * sizeof(uint32_t)); 1046235537Sgber bad_segments[bad_segments_count - 1] = i; 1047235537Sgber } 1048235537Sgber } 1049235537Sgber 1050235537Sgber if (bad_segments_count == nsegments) { 1051235537Sgber printf("no valid segments\n"); 1052235537Sgber exit(1); 1053235537Sgber } 1054235537Sgber 1055235537Sgber /* Delete remaining blocks at the end of device */ 1056235537Sgber rest = mediasize % segsize; 1057235537Sgber nblocks = rest / erasesize; 1058235537Sgber for (i = 0; i < nblocks; i++) { 1059235537Sgber offset = (segsize * nsegments) + (i * erasesize); 1060235537Sgber if (g_delete(fd, offset, erasesize)) { 1061235537Sgber printf("cannot delete space after last segment " 1062235537Sgber "- probably a bad block\n"); 1063235537Sgber } 1064235537Sgber } 1065235537Sgber} 1066235537Sgber 1067235537Sgberstatic void 1068235537Sgbererase_initial(int fd) 1069235537Sgber{ 1070235537Sgber char buf[512]; 1071235537Sgber u_int i; 1072235537Sgber 1073235537Sgber memset(buf, 0xff, sizeof(buf)); 1074235537Sgber 1075235537Sgber lseek(fd, 0, SEEK_SET); 1076235537Sgber for (i = 0; i < NANDFS_NFSAREAS * erasesize; i += sizeof(buf)) 1077235537Sgber write(fd, buf, sizeof(buf)); 1078235537Sgber} 1079235537Sgber 1080235537Sgberstatic void 1081235537Sgbercreate_nandfs(int fd) 1082235537Sgber{ 1083235537Sgber 1084235537Sgber create_fs(); 1085235537Sgber 1086235537Sgber write_fs(fd); 1087235537Sgber} 1088235537Sgber 1089235537Sgberstatic void 1090235537Sgberprint_summary(void) 1091235537Sgber{ 1092235537Sgber 1093293290Sbdrewery printf("filesystem was created successfully\n"); 1094235537Sgber printf("total segments: %#jx valid segments: %#jx\n", nsegments, 1095235537Sgber nsegments - bad_segments_count); 1096235537Sgber printf("total space: %ju MB free: %ju MB\n", 1097235537Sgber (nsegments * 1098235537Sgber blocks_per_segment * blocksize) / (1024 * 1024), 1099235537Sgber ((nsegments - bad_segments_count) * 1100235537Sgber blocks_per_segment * blocksize) / (1024 * 1024)); 1101235537Sgber} 1102235537Sgber 1103235537Sgberint 1104235537Sgbermain(int argc, char *argv[]) 1105235537Sgber{ 1106235537Sgber struct stat sb; 1107235537Sgber char buf[MAXPATHLEN]; 1108235537Sgber const char opts[] = "b:B:L:m:"; 1109235537Sgber const char *fname; 1110235537Sgber int ch, fd; 1111235537Sgber 1112235537Sgber while ((ch = getopt(argc, argv, opts)) != -1) { 1113235537Sgber switch (ch) { 1114235537Sgber case 'b': 1115235537Sgber blocksize = strtol(optarg, (char **)NULL, 10); 1116235537Sgber if (blocksize == 0) 1117235537Sgber usage(); 1118235537Sgber break; 1119235537Sgber case 'B': 1120235537Sgber blocks_per_segment = strtol(optarg, (char **)NULL, 10); 1121235537Sgber if (blocks_per_segment == 0) 1122235537Sgber usage(); 1123235537Sgber break; 1124235537Sgber case 'L': 1125235537Sgber volumelabel = optarg; 1126235537Sgber break; 1127235537Sgber case 'm': 1128235537Sgber rsv_segment_percent = strtol(optarg, (char **)NULL, 10); 1129235537Sgber if (rsv_segment_percent == 0) 1130235537Sgber usage(); 1131235537Sgber break; 1132235537Sgber default: 1133235537Sgber usage(); 1134235537Sgber } 1135235537Sgber } 1136235537Sgber 1137235537Sgber argc -= optind; 1138235537Sgber argv += optind; 1139235537Sgber if (argc < 1 || argc > 2) 1140235537Sgber usage(); 1141235537Sgber 1142235537Sgber /* construct proper device path */ 1143235537Sgber fname = *argv++; 1144235537Sgber if (!strchr(fname, '/')) { 1145235537Sgber snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 1146235537Sgber if (!(fname = strdup(buf))) 1147235537Sgber err(1, NULL); 1148235537Sgber } 1149235537Sgber 1150235537Sgber fd = g_open(fname, 1); 1151235537Sgber if (fd == -1) 1152235537Sgber err(1, "Cannot open %s", fname); 1153235537Sgber 1154235537Sgber if (fstat(fd, &sb) == -1) 1155235537Sgber err(1, "Cannot stat %s", fname); 1156235537Sgber if (!S_ISCHR(sb.st_mode)) 1157235537Sgber warnx("%s is not a character device", fname); 1158235537Sgber 1159235537Sgber check_mounted(fname, sb.st_mode); 1160235537Sgber 1161235537Sgber calculate_geometry(fd); 1162235537Sgber 1163235537Sgber check_parameters(); 1164235537Sgber 1165235537Sgber print_parameters(); 1166235537Sgber 1167235537Sgber if (is_nand) 1168235537Sgber erase_device(fd); 1169235537Sgber else 1170235537Sgber erase_initial(fd); 1171235537Sgber 1172235537Sgber create_nandfs(fd); 1173235537Sgber 1174235537Sgber print_summary(); 1175235537Sgber 1176235537Sgber g_close(fd); 1177235537Sgber 1178235537Sgber return (0); 1179235537Sgber} 1180235537Sgber 1181235537Sgber 1182