xref: /netbsd-src/sbin/newfs_v7fs/main.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
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