1*9f988b79SJean-Baptiste Boric /* $NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
2*9f988b79SJean-Baptiste Boric
3*9f988b79SJean-Baptiste Boric /*-
4*9f988b79SJean-Baptiste Boric * Copyright (c) 2011 The NetBSD Foundation, Inc.
5*9f988b79SJean-Baptiste Boric * All rights reserved.
6*9f988b79SJean-Baptiste Boric *
7*9f988b79SJean-Baptiste Boric * This code is derived from software contributed to The NetBSD Foundation
8*9f988b79SJean-Baptiste Boric * by UCHIYAMA Yasushi.
9*9f988b79SJean-Baptiste Boric *
10*9f988b79SJean-Baptiste Boric * Redistribution and use in source and binary forms, with or without
11*9f988b79SJean-Baptiste Boric * modification, are permitted provided that the following conditions
12*9f988b79SJean-Baptiste Boric * are met:
13*9f988b79SJean-Baptiste Boric * 1. Redistributions of source code must retain the above copyright
14*9f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer.
15*9f988b79SJean-Baptiste Boric * 2. Redistributions in binary form must reproduce the above copyright
16*9f988b79SJean-Baptiste Boric * notice, this list of conditions and the following disclaimer in the
17*9f988b79SJean-Baptiste Boric * documentation and/or other materials provided with the distribution.
18*9f988b79SJean-Baptiste Boric *
19*9f988b79SJean-Baptiste Boric * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*9f988b79SJean-Baptiste Boric * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*9f988b79SJean-Baptiste Boric * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*9f988b79SJean-Baptiste Boric * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*9f988b79SJean-Baptiste Boric * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*9f988b79SJean-Baptiste Boric * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*9f988b79SJean-Baptiste Boric * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*9f988b79SJean-Baptiste Boric * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*9f988b79SJean-Baptiste Boric * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*9f988b79SJean-Baptiste Boric * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*9f988b79SJean-Baptiste Boric * POSSIBILITY OF SUCH DAMAGE.
30*9f988b79SJean-Baptiste Boric */
31*9f988b79SJean-Baptiste Boric
32*9f988b79SJean-Baptiste Boric #if HAVE_NBTOOL_CONFIG_H
33*9f988b79SJean-Baptiste Boric #include "nbtool_config.h"
34*9f988b79SJean-Baptiste Boric #endif
35*9f988b79SJean-Baptiste Boric
36*9f988b79SJean-Baptiste Boric #include <sys/cdefs.h>
37*9f988b79SJean-Baptiste Boric __KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
38*9f988b79SJean-Baptiste Boric #if defined _KERNEL_OPT
39*9f988b79SJean-Baptiste Boric #include "opt_v7fs.h"
40*9f988b79SJean-Baptiste Boric #endif
41*9f988b79SJean-Baptiste Boric
42*9f988b79SJean-Baptiste Boric #ifdef _KERNEL
43*9f988b79SJean-Baptiste Boric #include <sys/systm.h>
44*9f988b79SJean-Baptiste Boric #include <sys/param.h> /* errno */
45*9f988b79SJean-Baptiste Boric #else
46*9f988b79SJean-Baptiste Boric #include <stdio.h>
47*9f988b79SJean-Baptiste Boric #include <string.h>
48*9f988b79SJean-Baptiste Boric #include <errno.h>
49*9f988b79SJean-Baptiste Boric #endif
50*9f988b79SJean-Baptiste Boric
51*9f988b79SJean-Baptiste Boric #include "v7fs.h"
52*9f988b79SJean-Baptiste Boric #include "v7fs_impl.h"
53*9f988b79SJean-Baptiste Boric #include "v7fs_endian.h"
54*9f988b79SJean-Baptiste Boric #include "v7fs_superblock.h"
55*9f988b79SJean-Baptiste Boric #include "v7fs_inode.h"
56*9f988b79SJean-Baptiste Boric #include "v7fs_datablock.h"
57*9f988b79SJean-Baptiste Boric
58*9f988b79SJean-Baptiste Boric #ifdef V7FS_SUPERBLOCK_DEBUG
59*9f988b79SJean-Baptiste Boric #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
60*9f988b79SJean-Baptiste Boric #define DPRINTF_(fmt, args...) printf(fmt, ##args)
61*9f988b79SJean-Baptiste Boric #else
62*9f988b79SJean-Baptiste Boric #define DPRINTF(fmt, args...) ((void)0)
63*9f988b79SJean-Baptiste Boric #define DPRINTF_(fmt, args...) ((void)0)
64*9f988b79SJean-Baptiste Boric #endif
65*9f988b79SJean-Baptiste Boric
66*9f988b79SJean-Baptiste Boric static void v7fs_superblock_endian_convert(struct v7fs_self *,
67*9f988b79SJean-Baptiste Boric struct v7fs_superblock *, struct v7fs_superblock *);
68*9f988b79SJean-Baptiste Boric static int v7fs_superblock_sanity(struct v7fs_self *);
69*9f988b79SJean-Baptiste Boric
70*9f988b79SJean-Baptiste Boric /* Load superblock from disk. */
71*9f988b79SJean-Baptiste Boric int
v7fs_superblock_load(struct v7fs_self * fs)72*9f988b79SJean-Baptiste Boric v7fs_superblock_load(struct v7fs_self *fs)
73*9f988b79SJean-Baptiste Boric {
74*9f988b79SJean-Baptiste Boric struct v7fs_superblock *disksb;
75*9f988b79SJean-Baptiste Boric void *buf;
76*9f988b79SJean-Baptiste Boric int error;
77*9f988b79SJean-Baptiste Boric
78*9f988b79SJean-Baptiste Boric if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR)))
79*9f988b79SJean-Baptiste Boric return EIO;
80*9f988b79SJean-Baptiste Boric disksb = (struct v7fs_superblock *)buf;
81*9f988b79SJean-Baptiste Boric v7fs_superblock_endian_convert(fs, &fs->superblock, disksb);
82*9f988b79SJean-Baptiste Boric scratch_free(fs, buf);
83*9f988b79SJean-Baptiste Boric
84*9f988b79SJean-Baptiste Boric if ((error = v7fs_superblock_sanity(fs)))
85*9f988b79SJean-Baptiste Boric return error;
86*9f988b79SJean-Baptiste Boric
87*9f988b79SJean-Baptiste Boric return 0;
88*9f988b79SJean-Baptiste Boric }
89*9f988b79SJean-Baptiste Boric
90*9f988b79SJean-Baptiste Boric /* Writeback superblock to disk. */
91*9f988b79SJean-Baptiste Boric int
v7fs_superblock_writeback(struct v7fs_self * fs)92*9f988b79SJean-Baptiste Boric v7fs_superblock_writeback(struct v7fs_self *fs)
93*9f988b79SJean-Baptiste Boric {
94*9f988b79SJean-Baptiste Boric struct v7fs_superblock *memsb = &fs->superblock;
95*9f988b79SJean-Baptiste Boric struct v7fs_superblock *disksb;
96*9f988b79SJean-Baptiste Boric void *buf;
97*9f988b79SJean-Baptiste Boric int error = 0;
98*9f988b79SJean-Baptiste Boric
99*9f988b79SJean-Baptiste Boric if (!memsb->modified)
100*9f988b79SJean-Baptiste Boric return 0;
101*9f988b79SJean-Baptiste Boric
102*9f988b79SJean-Baptiste Boric if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR)))
103*9f988b79SJean-Baptiste Boric return EIO;
104*9f988b79SJean-Baptiste Boric disksb = (struct v7fs_superblock *)buf;
105*9f988b79SJean-Baptiste Boric v7fs_superblock_endian_convert(fs, disksb, memsb);
106*9f988b79SJean-Baptiste Boric if (!fs->io.write(fs->io.cookie, buf, V7FS_SUPERBLOCK_SECTOR))
107*9f988b79SJean-Baptiste Boric error = EIO;
108*9f988b79SJean-Baptiste Boric scratch_free(fs, buf);
109*9f988b79SJean-Baptiste Boric
110*9f988b79SJean-Baptiste Boric memsb->modified = 0;
111*9f988b79SJean-Baptiste Boric DPRINTF("done. %d\n", error);
112*9f988b79SJean-Baptiste Boric
113*9f988b79SJean-Baptiste Boric return error;
114*9f988b79SJean-Baptiste Boric }
115*9f988b79SJean-Baptiste Boric
116*9f988b79SJean-Baptiste Boric /* Check endian mismatch. */
117*9f988b79SJean-Baptiste Boric static int
v7fs_superblock_sanity(struct v7fs_self * fs)118*9f988b79SJean-Baptiste Boric v7fs_superblock_sanity(struct v7fs_self *fs)
119*9f988b79SJean-Baptiste Boric {
120*9f988b79SJean-Baptiste Boric const struct v7fs_superblock *sb = &fs->superblock;
121*9f988b79SJean-Baptiste Boric void *buf = 0;
122*9f988b79SJean-Baptiste Boric
123*9f988b79SJean-Baptiste Boric if ((sb->volume_size < 128) || /* smaller than 64KB. */
124*9f988b79SJean-Baptiste Boric (sb->datablock_start_sector > sb->volume_size) ||
125*9f988b79SJean-Baptiste Boric (sb->nfreeinode > V7FS_MAX_FREEINODE) ||
126*9f988b79SJean-Baptiste Boric (sb->nfreeblock > V7FS_MAX_FREEBLOCK) ||
127*9f988b79SJean-Baptiste Boric (sb->update_time < 0) ||
128*9f988b79SJean-Baptiste Boric (sb->total_freeblock > sb->volume_size) ||
129*9f988b79SJean-Baptiste Boric ((sb->nfreeinode == 0) && (sb->nfreeblock == 0) &&
130*9f988b79SJean-Baptiste Boric (sb->total_freeblock == 0) && (sb->total_freeinode == 0)) ||
131*9f988b79SJean-Baptiste Boric (!(buf = scratch_read(fs, sb->volume_size - 1)))) {
132*9f988b79SJean-Baptiste Boric DPRINTF("invalid super block.\n");
133*9f988b79SJean-Baptiste Boric return EINVAL;
134*9f988b79SJean-Baptiste Boric }
135*9f988b79SJean-Baptiste Boric if (buf)
136*9f988b79SJean-Baptiste Boric scratch_free(fs, buf);
137*9f988b79SJean-Baptiste Boric
138*9f988b79SJean-Baptiste Boric return 0;
139*9f988b79SJean-Baptiste Boric }
140*9f988b79SJean-Baptiste Boric
141*9f988b79SJean-Baptiste Boric /* Fill free block to superblock cache. */
142*9f988b79SJean-Baptiste Boric int
v7fs_freeblock_update(struct v7fs_self * fs,v7fs_daddr_t blk)143*9f988b79SJean-Baptiste Boric v7fs_freeblock_update(struct v7fs_self *fs, v7fs_daddr_t blk)
144*9f988b79SJean-Baptiste Boric {
145*9f988b79SJean-Baptiste Boric /* Assume superblock is locked by caller. */
146*9f988b79SJean-Baptiste Boric struct v7fs_superblock *sb = &fs->superblock;
147*9f988b79SJean-Baptiste Boric struct v7fs_freeblock *fb;
148*9f988b79SJean-Baptiste Boric void *buf;
149*9f988b79SJean-Baptiste Boric int error;
150*9f988b79SJean-Baptiste Boric
151*9f988b79SJean-Baptiste Boric /* Read next freeblock table from disk. */
152*9f988b79SJean-Baptiste Boric if (!datablock_number_sanity(fs, blk) || !(buf = scratch_read(fs, blk)))
153*9f988b79SJean-Baptiste Boric return EIO;
154*9f988b79SJean-Baptiste Boric
155*9f988b79SJean-Baptiste Boric /* Update in-core superblock freelist. */
156*9f988b79SJean-Baptiste Boric fb = (struct v7fs_freeblock *)buf;
157*9f988b79SJean-Baptiste Boric if ((error = v7fs_freeblock_endian_convert(fs, fb))) {
158*9f988b79SJean-Baptiste Boric scratch_free(fs, buf);
159*9f988b79SJean-Baptiste Boric return error;
160*9f988b79SJean-Baptiste Boric }
161*9f988b79SJean-Baptiste Boric DPRINTF("freeblock table#%d, nfree=%d\n", blk, fb->nfreeblock);
162*9f988b79SJean-Baptiste Boric
163*9f988b79SJean-Baptiste Boric memcpy(sb->freeblock, fb->freeblock, sizeof(blk) * fb->nfreeblock);
164*9f988b79SJean-Baptiste Boric sb->nfreeblock = fb->nfreeblock;
165*9f988b79SJean-Baptiste Boric sb->modified = true;
166*9f988b79SJean-Baptiste Boric scratch_free(fs, buf);
167*9f988b79SJean-Baptiste Boric
168*9f988b79SJean-Baptiste Boric return 0;
169*9f988b79SJean-Baptiste Boric }
170*9f988b79SJean-Baptiste Boric
171*9f988b79SJean-Baptiste Boric int
v7fs_freeblock_endian_convert(struct v7fs_self * fs __unused,struct v7fs_freeblock * fb __unused)172*9f988b79SJean-Baptiste Boric v7fs_freeblock_endian_convert(struct v7fs_self *fs __unused,
173*9f988b79SJean-Baptiste Boric struct v7fs_freeblock *fb __unused)
174*9f988b79SJean-Baptiste Boric {
175*9f988b79SJean-Baptiste Boric #ifdef V7FS_EI
176*9f988b79SJean-Baptiste Boric int i;
177*9f988b79SJean-Baptiste Boric int16_t nfree;
178*9f988b79SJean-Baptiste Boric
179*9f988b79SJean-Baptiste Boric nfree = V7FS_VAL16(fs, fb->nfreeblock);
180*9f988b79SJean-Baptiste Boric if (nfree <= 0 || nfree > V7FS_MAX_FREEBLOCK) {
181*9f988b79SJean-Baptiste Boric DPRINTF("invalid freeblock list. %d (max=%d)\n", nfree,
182*9f988b79SJean-Baptiste Boric V7FS_MAX_FREEBLOCK);
183*9f988b79SJean-Baptiste Boric return ENOSPC;
184*9f988b79SJean-Baptiste Boric }
185*9f988b79SJean-Baptiste Boric fb->nfreeblock = nfree;
186*9f988b79SJean-Baptiste Boric
187*9f988b79SJean-Baptiste Boric for (i = 0; i < nfree; i++) {
188*9f988b79SJean-Baptiste Boric fb->freeblock[i] = V7FS_VAL32(fs, fb->freeblock[i]);
189*9f988b79SJean-Baptiste Boric }
190*9f988b79SJean-Baptiste Boric #endif /* V7FS_EI */
191*9f988b79SJean-Baptiste Boric
192*9f988b79SJean-Baptiste Boric return 0;
193*9f988b79SJean-Baptiste Boric }
194*9f988b79SJean-Baptiste Boric
195*9f988b79SJean-Baptiste Boric /* Fill free inode to superblock cache. */
196*9f988b79SJean-Baptiste Boric int
v7fs_freeinode_update(struct v7fs_self * fs)197*9f988b79SJean-Baptiste Boric v7fs_freeinode_update(struct v7fs_self *fs)
198*9f988b79SJean-Baptiste Boric {
199*9f988b79SJean-Baptiste Boric /* Assume superblock is locked by caller. */
200*9f988b79SJean-Baptiste Boric struct v7fs_superblock *sb = &fs->superblock;
201*9f988b79SJean-Baptiste Boric v7fs_ino_t *freeinode = sb->freeinode;
202*9f988b79SJean-Baptiste Boric size_t i, j, k;
203*9f988b79SJean-Baptiste Boric v7fs_ino_t ino;
204*9f988b79SJean-Baptiste Boric
205*9f988b79SJean-Baptiste Boric /* Loop over all inode list. */
206*9f988b79SJean-Baptiste Boric for (i = V7FS_ILIST_SECTOR, ino = 1/* inode start from 1*/, k = 0;
207*9f988b79SJean-Baptiste Boric i < sb->datablock_start_sector; i++) {
208*9f988b79SJean-Baptiste Boric struct v7fs_inode_diskimage *di;
209*9f988b79SJean-Baptiste Boric void *buf;
210*9f988b79SJean-Baptiste Boric if (!(buf = scratch_read(fs, i))) {
211*9f988b79SJean-Baptiste Boric DPRINTF("block %zu I/O error.\n", i);
212*9f988b79SJean-Baptiste Boric ino += V7FS_INODE_PER_BLOCK;
213*9f988b79SJean-Baptiste Boric continue;
214*9f988b79SJean-Baptiste Boric }
215*9f988b79SJean-Baptiste Boric di = (struct v7fs_inode_diskimage *)buf;
216*9f988b79SJean-Baptiste Boric
217*9f988b79SJean-Baptiste Boric for (j = 0;
218*9f988b79SJean-Baptiste Boric (j < V7FS_INODE_PER_BLOCK) && (k < V7FS_MAX_FREEINODE);
219*9f988b79SJean-Baptiste Boric j++, di++, ino++) {
220*9f988b79SJean-Baptiste Boric if (v7fs_inode_allocated(di))
221*9f988b79SJean-Baptiste Boric continue;
222*9f988b79SJean-Baptiste Boric DPRINTF("free inode%d\n", ino);
223*9f988b79SJean-Baptiste Boric freeinode[k++] = ino;
224*9f988b79SJean-Baptiste Boric }
225*9f988b79SJean-Baptiste Boric scratch_free(fs, buf);
226*9f988b79SJean-Baptiste Boric }
227*9f988b79SJean-Baptiste Boric sb->nfreeinode = k;
228*9f988b79SJean-Baptiste Boric
229*9f988b79SJean-Baptiste Boric return 0;
230*9f988b79SJean-Baptiste Boric }
231*9f988b79SJean-Baptiste Boric
232*9f988b79SJean-Baptiste Boric static void
v7fs_superblock_endian_convert(struct v7fs_self * fs __unused,struct v7fs_superblock * to,struct v7fs_superblock * from)233*9f988b79SJean-Baptiste Boric v7fs_superblock_endian_convert(struct v7fs_self *fs __unused,
234*9f988b79SJean-Baptiste Boric struct v7fs_superblock *to, struct v7fs_superblock *from)
235*9f988b79SJean-Baptiste Boric {
236*9f988b79SJean-Baptiste Boric #ifdef V7FS_EI
237*9f988b79SJean-Baptiste Boric #define conv16(m) (to->m = V7FS_VAL16(fs, from->m))
238*9f988b79SJean-Baptiste Boric #define conv32(m) (to->m = V7FS_VAL32(fs, from->m))
239*9f988b79SJean-Baptiste Boric int i;
240*9f988b79SJean-Baptiste Boric
241*9f988b79SJean-Baptiste Boric conv16(datablock_start_sector);
242*9f988b79SJean-Baptiste Boric conv32(volume_size);
243*9f988b79SJean-Baptiste Boric conv16(nfreeblock);
244*9f988b79SJean-Baptiste Boric v7fs_daddr_t *dfrom = from->freeblock;
245*9f988b79SJean-Baptiste Boric v7fs_daddr_t *dto = to->freeblock;
246*9f988b79SJean-Baptiste Boric for (i = 0; i < V7FS_MAX_FREEBLOCK; i++, dfrom++, dto++)
247*9f988b79SJean-Baptiste Boric *dto = V7FS_VAL32(fs, *dfrom);
248*9f988b79SJean-Baptiste Boric
249*9f988b79SJean-Baptiste Boric conv16(nfreeinode);
250*9f988b79SJean-Baptiste Boric v7fs_ino_t *ifrom = from->freeinode;
251*9f988b79SJean-Baptiste Boric v7fs_ino_t *ito = to->freeinode;
252*9f988b79SJean-Baptiste Boric for (i = 0; i < V7FS_MAX_FREEINODE; i++, ifrom++, ito++)
253*9f988b79SJean-Baptiste Boric *ito = V7FS_VAL16(fs, *ifrom);
254*9f988b79SJean-Baptiste Boric
255*9f988b79SJean-Baptiste Boric conv32(update_time);
256*9f988b79SJean-Baptiste Boric conv32(total_freeblock);
257*9f988b79SJean-Baptiste Boric conv16(total_freeinode);
258*9f988b79SJean-Baptiste Boric #undef conv16
259*9f988b79SJean-Baptiste Boric #undef conv32
260*9f988b79SJean-Baptiste Boric #else /* V7FS_EI */
261*9f988b79SJean-Baptiste Boric memcpy(to, from , sizeof(*to));
262*9f988b79SJean-Baptiste Boric #endif /* V7FS_EI */
263*9f988b79SJean-Baptiste Boric }
264