1 /* $NetBSD: main.c,v 1.1 2011/06/27 11:52:58 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: main.c,v 1.1 2011/06/27 11:52:58 uch Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <errno.h> 41 #include <time.h> 42 #include <err.h> 43 44 #include "v7fs.h" 45 #include "v7fs_impl.h" 46 #include "v7fs_endian.h" 47 #include "v7fs_superblock.h" 48 #include "v7fs_inode.h" 49 #include "v7fs_datablock.h" /*v7fs_datablock_expand/last */ 50 #include "newfs_v7fs.h" 51 #include "progress.h" /*../sbin/fsck */ 52 53 #define VPRINTF(fmt, args...) { if (verbose) printf(fmt, ##args); } 54 55 static v7fs_daddr_t 56 determine_ilist_size(v7fs_daddr_t volume_size, int32_t files) 57 { 58 v7fs_daddr_t ilist_size; 59 60 if (files) 61 ilist_size = roundup2(files, V7FS_INODE_PER_BLOCK) / 62 V7FS_INODE_PER_BLOCK; 63 else 64 ilist_size = volume_size / 25; /* 4% */ 65 if (ilist_size > (v7fs_daddr_t)V7FS_ILISTBLK_MAX) 66 ilist_size = V7FS_ILISTBLK_MAX; 67 68 return ilist_size; 69 } 70 71 static int 72 make_root(struct v7fs_self *fs) 73 { 74 struct v7fs_inode inode; 75 struct v7fs_dirent *dir; 76 int error; 77 78 /* INO 1 badblk (don't used) */ 79 memset(&inode, 0, sizeof(inode)); 80 inode.inode_number = 1; 81 inode.mode = V7FS_IFREG; /* V7 manner */ 82 v7fs_inode_writeback(fs, &inode); 83 84 /* INO 2 root */ 85 v7fs_ino_t ino; 86 if ((error = v7fs_inode_allocate(fs, &ino))) { 87 errno = error; 88 warn("Can't allocate / inode"); 89 return error; 90 } 91 92 memset(&inode, 0, sizeof(inode)); 93 inode.inode_number = ino; 94 inode.mode = 0777 | V7FS_IFDIR; 95 inode.uid = 0; 96 inode.gid = 0; 97 inode.nlink = 2; /* . + .. */ 98 inode.atime = inode.mtime = inode.ctime = time(0); 99 100 /* root dirent. */ 101 v7fs_datablock_expand(fs, &inode, sizeof(*dir) * 2); 102 v7fs_daddr_t blk = inode.addr[0]; 103 void *buf; 104 if (!(buf = scratch_read(fs, blk))) { 105 v7fs_inode_deallocate(fs, ino); 106 errno = error = EIO; 107 warn("Can't read / dirent."); 108 return error; 109 } 110 dir = (struct v7fs_dirent *)buf; /*disk endian */ 111 112 strcpy(dir[0].name, "."); 113 dir[0].inode_number = V7FS_VAL16(fs, ino); 114 strcpy(dir[1].name, ".."); 115 dir[1].inode_number = V7FS_VAL16(fs, ino); 116 if (!fs->io.write(fs->io.cookie, buf, blk)) {/*writeback */ 117 scratch_free(fs, buf); 118 errno = error = EIO; 119 warn("Can't write / dirent."); 120 return error; 121 } 122 scratch_free(fs, buf); 123 v7fs_inode_writeback(fs, &inode); 124 if ((error = v7fs_superblock_writeback(fs))) { 125 errno = error; 126 warn("Can't write superblock."); 127 } 128 129 return error; 130 } 131 132 static v7fs_daddr_t 133 make_freeblocklist(struct v7fs_self *fs, v7fs_daddr_t listblk, uint8_t *buf) 134 { 135 uint32_t (*val32)(uint32_t) = fs->val.conv32; 136 uint16_t (*val16)(uint16_t) = fs->val.conv16; 137 struct v7fs_freeblock *fb = (struct v7fs_freeblock *)buf; 138 int i, j, k; 139 140 memset(buf, 0, V7FS_BSIZE); 141 142 for (i = V7FS_MAX_FREEBLOCK - 1, j = listblk + 1, k = 0; i >= 0; 143 i--, j++, k++) { 144 progress(0); 145 if (j == (int32_t)fs->superblock.volume_size) 146 { 147 VPRINTF("\nlast freeblock #%d\n", 148 (*val32)(fb->freeblock[i + 1])); 149 fb->nfreeblock = (*val16)(k); 150 151 memmove(fb->freeblock + 1, fb->freeblock + i + 1, k * 152 sizeof(v7fs_daddr_t)); 153 fb->freeblock[0] = 0; /* Terminate link; */ 154 VPRINTF("last freeblock contains #%d\n", 155 (*val16)(fb->nfreeblock)); 156 fs->io.write(fs->io.cookie, buf, listblk); 157 return 0; 158 } 159 fb->freeblock[i] = (*val32)(j); 160 } 161 fb->nfreeblock = (*val16)(k); 162 163 if (!fs->io.write(fs->io.cookie, buf, listblk)) { 164 errno = EIO; 165 warn("blk=%ld", (long)listblk); 166 return 0; 167 } 168 169 /* Return next link block */ 170 return (*val32)(fb->freeblock[0]); 171 } 172 173 static int 174 make_filesystem(struct v7fs_self *fs, v7fs_daddr_t volume_size, 175 v7fs_daddr_t ilist_size) 176 { 177 struct v7fs_superblock *sb; 178 v7fs_daddr_t blk; 179 uint8_t buf[V7FS_BSIZE]; 180 int error = 0; 181 int32_t i, j; 182 183 /* Setup ilist. (ilist must be zero filled. becuase of they are free) */ 184 VPRINTF("Zero clear ilist.\n"); 185 progress(&(struct progress_arg){ .label = "zero ilist", .tick = 186 ilist_size / PROGRESS_BAR_GRANULE }); 187 memset(buf, 0, sizeof buf); 188 for (i = V7FS_ILIST_SECTOR; i < (int32_t)ilist_size; i++) { 189 fs->io.write(fs->io.cookie, buf, i); 190 progress(0); 191 } 192 progress_done(); 193 VPRINTF("\n"); 194 195 /* Construct superblock */ 196 sb = &fs->superblock; 197 sb->volume_size = volume_size; 198 sb->datablock_start_sector = ilist_size + V7FS_ILIST_SECTOR; 199 sb->update_time = time(NULL); 200 201 /* fill free inode cache. */ 202 VPRINTF("Setup inode cache.\n"); 203 sb->nfreeinode = V7FS_MAX_FREEINODE; 204 for (i = V7FS_MAX_FREEINODE - 1, j = V7FS_ROOT_INODE; i >= 0; i--, j++) 205 sb->freeinode[i] = j; 206 sb->total_freeinode = ilist_size * V7FS_INODE_PER_BLOCK - 1; 207 208 /* fill free block cache. */ 209 VPRINTF("Setup free block cache.\n"); 210 sb->nfreeblock = V7FS_MAX_FREEBLOCK; 211 for (i = V7FS_MAX_FREEBLOCK - 1, j = sb->datablock_start_sector; i >= 0; 212 i--, j++) 213 sb->freeblock[i] = j; 214 sb->total_freeblock = volume_size - sb->datablock_start_sector - 1; 215 216 /* Write superblock. */ 217 sb->modified = 1; 218 if ((error = v7fs_superblock_writeback(fs))) { 219 errno = error; 220 warn("Can't write back superblock."); 221 return error; 222 } 223 224 /* Construct freeblock list */ 225 VPRINTF("Setup whole freeblock list.\n"); 226 progress(&(struct progress_arg){ .label = "freeblock list", .tick = 227 (volume_size - sb->datablock_start_sector) / PROGRESS_BAR_GRANULE}); 228 blk = sb->freeblock[0]; 229 while ((blk = make_freeblocklist(fs, blk, buf))) 230 continue; 231 progress_done(); 232 233 VPRINTF("done.\n"); 234 235 return 0; 236 } 237 238 int 239 v7fs_newfs(const struct v7fs_mount_device *mount, int32_t maxfile) 240 { 241 struct v7fs_self *fs; 242 v7fs_daddr_t ilist_size; 243 int error; 244 v7fs_daddr_t volume_size = mount->sectors; 245 246 /* Check and determine ilistblock, datablock size. */ 247 if (volume_size > V7FS_DADDR_MAX + 1) 248 return ENOSPC; 249 250 ilist_size = determine_ilist_size(volume_size, maxfile); 251 252 VPRINTF("volume size=%d, ilist size=%d, endian=%d, NAME_MAX=%d\n", 253 volume_size, ilist_size, mount->endian, V7FS_NAME_MAX); 254 255 /* Setup I/O ops. */ 256 if ((error = v7fs_io_init(&fs, mount, V7FS_BSIZE))) { 257 errno = error; 258 warn("I/O setup failed."); 259 return error; 260 } 261 fs->endian = mount->endian; 262 v7fs_endian_init(fs); 263 264 /* Construct filesystem. */ 265 if ((error = make_filesystem(fs, volume_size, ilist_size))) { 266 return error; 267 } 268 269 /* Setup root. */ 270 if ((error = make_root(fs))) { 271 return error; 272 } 273 274 v7fs_io_fini(fs); 275 276 return 0; 277 } 278