1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)lfs.c 5.1 (Berkeley) 09/19/91"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/disklabel.h> 14 #include <ufs/dinode.h> 15 #include <unistd.h> 16 #include <errno.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include "lfs.h" /* XXX move to <sys/lfs.h> */ 20 #include "config.h" 21 #include "extern.h" 22 23 static LFS_SUPER lfs_default = { 24 /* lfs_magic */ LFS_MAGIC, 25 /* lfs_version */ LFS_VERSION, 26 /* lfs_size */ 0, 27 /* lfs_ssize */ 0, 28 /* lfs_dsize */ 0, 29 /* lfs_bsize */ DFL_LFSBLOCK, 30 /* lfs_fsize */ 0, 31 /* lfs_frag */ 0, 32 /* lfs_free */ LFS_FIRST_INUM, 33 /* lfs_idaddr */ 0, 34 /* lfs_ifile */ LFS_IFILE_INUM, 35 /* lfs_lastseg */ 0, 36 /* lfs_tstamp */ 0, 37 /* lfs_minfree */ MINFREE, 38 /* lfs_inopb */ DFL_LFSBLOCK/sizeof(struct dinode), 39 /* lfs_ifpb */ DFL_LFSBLOCK/sizeof(IFILE), 40 /* lfs_nindir */ DFL_LFSBLOCK/sizeof(daddr_t), 41 /* lfs_nseg */ 0, 42 /* lfs_nspf */ 0, 43 /* lfs_segtabsz */ 0, 44 /* lfs_segmask */ DFL_LFSSEG_MASK, 45 /* lfs_segshift */ DFL_LFSSEG_SHIFT, 46 /* lfs_bmask */ DFL_LFSBLOCK_MASK, 47 /* lfs_bshift */ DFL_LFSBLOCK_SHIFT, 48 /* lfs_ffmask */ 0, 49 /* lfs_ffshift */ 0, 50 /* lfs_fbmask */ 0, 51 /* lfs_fbshift */ 0, 52 /* lfs_fsbtodb */ 0, 53 /* lfs_sboffs */ { 0 }, 54 /* lfs_fmod */ 0, 55 /* lfs_clean */ 0, 56 /* lfs_ronly */ 0, 57 /* lfs_flags */ 0, 58 /* lfs_fsmnt */ { 0 }, 59 /* lfs_cksum */ 0 60 }; 61 62 static void put __P((int, off_t, void *, size_t)); 63 64 int 65 make_lfs(fd, lp, partp, minfree, block_size, seg_size) 66 int fd; 67 struct disklabel *lp; 68 struct partition *partp; 69 int minfree; 70 int block_size; 71 int seg_size; 72 { 73 struct dinode *dip; /* Pointer to a disk inode */ 74 FINFO file_info; /* File info structure in summary blocks */ 75 IFILE *ifile; /* Pointer to array of ifile structures */ 76 IFILE *ip; /* Pointer to array of ifile structures */ 77 LFS_SUPER *lfsp; /* Superblock */ 78 SEGUSAGE *segp; /* Segment usage table */ 79 SEGUSAGE *segtable; /* Segment usage table */ 80 SEGSUM summary; /* Segment summary structure */ 81 SEGSUM *sp; /* Segment summary pointer */ 82 daddr_t last_sb_addr; /* Address of superblocks */ 83 daddr_t sb_addr; /* Address of superblocks */ 84 void *pagep; /* Pointer to the page we use to write stuff */ 85 void *sump; /* Used to copy stuff into segment buffer */ 86 u_long *block_array; /* Array of logical block nos to put in sum */ 87 int block_array_size; /* How many entries in block array */ 88 int bsize; /* Block size */ 89 int db_per_fb; /* Disk blocks per file block */ 90 int i; 91 int sb_to_sum; /* offset between superblock and summary */ 92 int sb_interval; /* number of segs between super blocks */ 93 int seg_seek; /* Seek offset for a segment */ 94 int ssize; /* Segment size */ 95 int sum_size; /* Size of the summary block */ 96 int wbytes; /* Number of bytes returned by write */ 97 98 lfsp = &lfs_default; 99 100 if (!(bsize = block_size)) 101 bsize = DFL_LFSBLOCK; 102 if (!(ssize = seg_size)) 103 ssize = DFL_LFSSEG; 104 105 /* Modify parts of superblock overridden by command line arguments */ 106 if (bsize != DFL_LFSBLOCK) { 107 lfsp->lfs_bshift = log2(bsize); 108 if (1 << lfsp->lfs_bshift != bsize) 109 fatal("%d: block size not a power of 2", bsize); 110 lfsp->lfs_bsize = bsize; 111 lfsp->lfs_bmask = bsize - 1; 112 lfsp->lfs_inopb = bsize / sizeof(struct dinode); 113 /* MIS -- should I round to power of 2 */ 114 lfsp->lfs_ifpb = bsize / sizeof(IFILE); 115 lfsp->lfs_nindir = bsize / sizeof(daddr_t); 116 } 117 118 if (ssize != DFL_LFSSEG) { 119 lfsp->lfs_segshift = log2(ssize); 120 if (1 << lfsp->lfs_segshift != ssize) 121 fatal("%d: segment size not power of 2", ssize); 122 lfsp->lfs_ssize = ssize; 123 lfsp->lfs_segmask = ssize - 1; 124 } 125 lfsp->lfs_ssize = ssize >> lfsp->lfs_bshift; 126 127 if (minfree) 128 lfsp->lfs_minfree = minfree; 129 130 /* 131 * Fill in parts of superblock that can be computed from file system 132 * size, disk geometry and current time. 133 */ 134 db_per_fb = bsize/lp->d_secsize; 135 lfsp->lfs_fsbtodb = log2(db_per_fb); 136 lfsp->lfs_size = partp->p_size >> lfsp->lfs_fsbtodb; 137 lfsp->lfs_dsize = lfsp->lfs_size - (LFS_LABELPAD >> lfsp->lfs_bshift); 138 lfsp->lfs_nseg = lfsp->lfs_dsize / lfsp->lfs_ssize; 139 lfsp->lfs_segtabsz = SEGTABSIZE_SU(lfsp); 140 if ((lfsp->lfs_tstamp = time(NULL)) == -1) 141 fatal("time: %s", strerror(errno)); 142 if ((sb_interval = lfsp->lfs_nseg / LFS_MAXNUMSB) < LFS_MIN_SBINTERVAL) 143 sb_interval = LFS_MIN_SBINTERVAL; 144 145 /* 146 * Now, lay out the file system. We need to figure out where 147 * the superblocks go, initialize the checkpoint information 148 * for the first two superblocks, initialize the segment usage 149 * information, put the segusage information in the ifile, create 150 * the first block of IFILE structures, and link all the IFILE 151 * structures into a free list. 152 */ 153 154 /* Figure out where the superblocks are going to live */ 155 lfsp->lfs_sboffs[0] = LFS_LABELPAD/lp->d_secsize; 156 for (i = 1; i < LFS_MAXNUMSB; i++) { 157 sb_addr = ((i * sb_interval) << 158 (lfsp->lfs_segshift - lfsp->lfs_bshift + lfsp->lfs_fsbtodb)) 159 + lfsp->lfs_sboffs[0]; 160 if (sb_addr > partp->p_size) 161 break; 162 lfsp->lfs_sboffs[i] = sb_addr; 163 } 164 last_sb_addr = lfsp->lfs_sboffs[i - 1]; 165 lfsp->lfs_lastseg = lfsp->lfs_sboffs[0]; 166 167 /* 168 * Initialize the segment usage table. The first segment will 169 * contain the superblock, the segusage table (segtabsz), 1 170 * block's worth of IFILE entries, and one block's worth of inodes 171 * (containing the ifile inode). 172 */ 173 if (!(segtable = malloc(lfsp->lfs_segtabsz << lfsp->lfs_bshift))) 174 fatal("%s", strerror(errno)); 175 segp = segtable; 176 segp->su_nbytes = 177 LFS_SBPAD + (lfsp->lfs_segtabsz + 2 << lfsp->lfs_bshift); 178 segp->su_lastmod = lfsp->lfs_tstamp; 179 segp->su_flags = SEGUSAGE_DIRTY; 180 181 /* Now use su_nbytes to figure out the daddr of the ifile inode */ 182 lfsp->lfs_idaddr = (((segp->su_nbytes >> lfsp->lfs_bshift) - 1) << 183 lfsp->lfs_fsbtodb) + lfsp->lfs_sboffs[0]; 184 185 for (segp = segtable + 1, i = 1; i < lfsp->lfs_nseg; i++, segp++) { 186 if ((i % sb_interval) == (sb_interval - 1)) 187 segp->su_nbytes = LFS_SBPAD; 188 else 189 segp->su_nbytes = 0; 190 segp->su_lastmod = 0; 191 segp->su_flags = 0; 192 } 193 194 /* 195 * Ready to start writing segments. The first segment is different 196 * because it contains the segment usage table and the ifile inode 197 * as well as a superblock. We don't have to write any segments which 198 * don't contain superblocks since they are marked as clean and do not 199 * containing any live bytes, so the only other segments we need to 200 * write are those containing superblock info. For all these segments, 201 * set the time stamp to be 0 so that the first superblock looks like 202 * the most recent. 203 */ 204 lfsp->lfs_cksum = 205 cksum(lfsp, sizeof(LFS_SUPER) - sizeof(lfsp->lfs_cksum)); 206 put(fd, LFS_LABELPAD, lfsp, sizeof(LFS_SUPER)); 207 put(fd, LFS_LABELPAD + LFS_SBPAD, segtable, 208 lfsp->lfs_segtabsz << lfsp->lfs_bshift); 209 (void)free(segtable); 210 211 /* Create the first block of the ifile. */ 212 if (!(pagep = malloc(lfsp->lfs_bsize))) 213 fatal("%s", strerror(errno)); 214 ifile = (IFILE *)pagep; 215 for (ip = &ifile[2], i = 2; i < lfsp->lfs_ifpb; ++ip) { 216 ip->if_version = 1; 217 ip->if_daddr = LFS_UNUSED_DADDR; 218 ip->if_nextfree = ++i; 219 } 220 ifile[lfsp->lfs_ifpb - 1].if_nextfree = LFS_UNUSED_INUM; 221 ip = &ifile[LFS_IFILE_INUM]; 222 ip->if_version = 1; 223 ip->if_daddr = lfsp->lfs_idaddr; 224 ip->if_st_atime = lfsp->lfs_tstamp; 225 226 if ((wbytes = write(fd, ifile, lfsp->lfs_bsize)) < 0) 227 fatal("%s: %s", special, strerror(errno)); 228 if (wbytes != lfsp->lfs_bsize) 229 fatal("%s: short write (%d, not %d)", 230 special, wbytes, lfsp->lfs_bsize); 231 232 /* Now create a block of disk inodes */ 233 dip = (struct dinode *)pagep; 234 bzero(dip, sizeof(struct dinode)); 235 dip->di_mode = IFREG; 236 dip->di_nlink = 1; 237 dip->di_blocks = lfsp->lfs_segtabsz + 1; 238 /* If we ever need something longer than 32 bits, this changes */ 239 dip->di_size = (dip->di_blocks << lfsp->lfs_bshift); 240 dip->di_atime = dip->di_mtime = dip->di_ctime = lfsp->lfs_tstamp; 241 dip->di_inum = LFS_IFILE_INUM; 242 #define SEGERR \ 243 "Segusage table requires too many blocks; increase block or segment size." 244 if (NDADDR < lfsp->lfs_segtabsz) 245 fatal("%s", SEGERR); 246 sb_addr = (LFS_LABELPAD + LFS_SBPAD) / lp->d_secsize; 247 248 /* Assign the block addresses for the ifile */ 249 for (i = 0; i < dip->di_blocks; i++, sb_addr += db_per_fb) 250 dip->di_db[i] = sb_addr; 251 252 /* Make all the other dinodes invalid */ 253 for (i = 1, dip++; i < lfsp->lfs_inopb; i++, dip++) 254 dip->di_inum = LFS_UNUSED_INUM; 255 256 /* Finally, write out the inode block */ 257 if ((wbytes = write(fd, pagep, lfsp->lfs_bsize)) < 0) 258 fatal("%s: %s", special, strerror(errno)); 259 if (wbytes != lfsp->lfs_bsize) 260 fatal("%s: short write (%d, not %d)", 261 special, wbytes, lfsp->lfs_bsize); 262 263 /* MIS -- probably want to replace with "write block code" */ 264 /* Now it's time to write the summary for the first segment. */ 265 summary.ss_next = 266 lfsp->lfs_sboffs[1] ? lfsp->lfs_sboffs[1] : lfsp->lfs_sboffs[0]; 267 summary.ss_prev = last_sb_addr; 268 summary.ss_nextsum = -1; 269 summary.ss_create = lfsp->lfs_tstamp; 270 summary.ss_nfinfo = 2; 271 summary.ss_ninos = 1; 272 273 /* Superblock and disk label */ 274 file_info.fi_nblocks = LFS_SBPAD >> lfsp->lfs_bshift; 275 file_info.fi_version = 1; 276 file_info.fi_ino = LFS_UNUSED_INUM; 277 278 /* Make sure that we don't overflow a summary block. */ 279 sum_size = 2*sizeof(FINFO) + sizeof(SEGSUM) + 280 file_info.fi_nblocks * sizeof(u_long) + 281 (lfsp->lfs_segtabsz + 1) * sizeof(u_long); 282 #define SUMERR \ 283 "Multiple summary blocks in segment 1 not yet implemented\nsummary is %d bytes." 284 if (sum_size > LFS_SUMMARY_SIZE) 285 fatal(SUMERR, sum_size); 286 287 block_array_size = file_info.fi_nblocks; 288 if ((lfsp->lfs_segtabsz + 1) > block_array_size) 289 block_array_size = lfsp->lfs_segtabsz + 1; 290 291 if (!(block_array = malloc(block_array_size *sizeof(int)))) 292 fatal("%s: %s", special, strerror(errno)); 293 294 /* fill in the array */ 295 for (i = 0; i < file_info.fi_nblocks; i++) 296 block_array[i] = i; 297 298 /* copy into segment */ 299 sump = pagep; 300 bcopy(&summary, sump, sizeof(SEGSUM)); 301 sump += sizeof(SEGSUM); 302 bcopy(&file_info, sump, sizeof(FINFO) - sizeof(u_long)); 303 sump += sizeof(FINFO) - sizeof(u_long); 304 bcopy(block_array, sump, sizeof(u_long) * file_info.fi_nblocks); 305 sump += sizeof(u_long) * file_info.fi_nblocks; 306 307 /* Now, add the ifile */ 308 file_info.fi_nblocks = lfsp->lfs_segtabsz + 1; 309 file_info.fi_version = 1; 310 file_info.fi_ino = LFS_IFILE_INUM; 311 312 for (i = 0; i < file_info.fi_nblocks; i++) 313 block_array[i] = i; 314 315 bcopy(&file_info, sump, sizeof(FINFO) - sizeof(u_long)); 316 sump += sizeof(FINFO) - sizeof(u_long); 317 bcopy(block_array, sump, sizeof(u_long) * file_info.fi_nblocks); 318 319 sb_to_sum = (lfsp->lfs_ssize << lfsp->lfs_bshift) - LFS_SUMMARY_SIZE; 320 ((SEGSUM *)pagep)->ss_cksum = cksum(pagep+sizeof(summary.ss_cksum), 321 LFS_SUMMARY_SIZE - sizeof(summary.ss_cksum)); 322 put(fd, LFS_LABELPAD + sb_to_sum, pagep, LFS_SUMMARY_SIZE); 323 324 summary.ss_nextsum = -1; 325 summary.ss_create = 0; 326 summary.ss_nfinfo = 1; 327 summary.ss_ninos = 0; 328 329 /* Superblock */ 330 file_info.fi_nblocks = LFS_SBPAD >> lfsp->lfs_bshift; 331 file_info.fi_version = 1; 332 file_info.fi_ino = LFS_UNUSED_INUM; 333 334 for (i = 0; i < file_info.fi_nblocks; i++) 335 block_array[i] = i; 336 337 sump = pagep; 338 bcopy (&summary, sump, sizeof(SEGSUM)); 339 sump += sizeof(SEGSUM); 340 bcopy(&file_info, sump, sizeof(FINFO) - sizeof(u_long)); 341 sump += sizeof(FINFO) - sizeof(u_long); 342 bcopy(block_array, sump, sizeof(u_long) * file_info.fi_nblocks); 343 344 /* Now, write rest of segments containing superblocks */ 345 lfsp->lfs_tstamp = 0; 346 for (sp = (SEGSUM *)pagep, i = 1; i < LFS_MAXNUMSB; i++) { 347 if (!lfsp->lfs_sboffs[i]) 348 break; 349 sp->ss_prev = lfsp->lfs_sboffs[i - 1]; 350 if (i < (LFS_MAXNUMSB - 1)) 351 sp->ss_next = lfsp->lfs_sboffs[i + 1]; 352 else 353 sp->ss_next = lfsp->lfs_sboffs[0]; 354 355 /* Superblock */ 356 seg_seek = lfsp->lfs_sboffs[i] * lp->d_secsize; 357 lfsp->lfs_cksum = 358 cksum(lfsp, sizeof(LFS_SUPER) - sizeof(lfsp->lfs_cksum)); 359 put(fd, seg_seek, lfsp, sizeof(LFS_SUPER)); 360 361 /* Summary */ 362 sp->ss_cksum = cksum(&sp->ss_cksum, 363 LFS_SUMMARY_SIZE - sizeof(sp->ss_cksum)); 364 put(fd, sb_to_sum + seg_seek, pagep, LFS_SUMMARY_SIZE); 365 } 366 (void)free(pagep); 367 (void)close(fd); 368 return (0); 369 } 370 371 static void 372 put(fd, off, p, len) 373 int fd; 374 off_t off; 375 void *p; 376 size_t len; 377 { 378 int wbytes; 379 380 if (lseek(fd, off, SEEK_SET) < 0) 381 fatal("%s: %s", special, strerror(errno)); 382 if ((wbytes = write(fd, p, len)) < 0) 383 fatal("%s: %s", special, strerror(errno)); 384 if (wbytes != len) 385 fatal("%s: short write (%d, not %d)", special, wbytes, len); 386 } 387