1 /* $NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
38 #if defined _KERNEL_OPT
43 #include <sys/systm.h>
44 #include <sys/param.h> /* errno */
52 #include "v7fs_impl.h"
53 #include "v7fs_endian.h"
54 #include "v7fs_superblock.h"
55 #include "v7fs_inode.h"
56 #include "v7fs_datablock.h"
58 #ifdef V7FS_SUPERBLOCK_DEBUG
59 #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
60 #define DPRINTF_(fmt, args...) printf(fmt, ##args)
62 #define DPRINTF(fmt, args...) ((void)0)
63 #define DPRINTF_(fmt, args...) ((void)0)
66 static void v7fs_superblock_endian_convert(struct v7fs_self
*,
67 struct v7fs_superblock
*, struct v7fs_superblock
*);
68 static int v7fs_superblock_sanity(struct v7fs_self
*);
70 /* Load superblock from disk. */
72 v7fs_superblock_load(struct v7fs_self
*fs
)
74 struct v7fs_superblock
*disksb
;
78 if (!(buf
= scratch_read(fs
, V7FS_SUPERBLOCK_SECTOR
)))
80 disksb
= (struct v7fs_superblock
*)buf
;
81 v7fs_superblock_endian_convert(fs
, &fs
->superblock
, disksb
);
82 scratch_free(fs
, buf
);
84 if ((error
= v7fs_superblock_sanity(fs
)))
90 /* Writeback superblock to disk. */
92 v7fs_superblock_writeback(struct v7fs_self
*fs
)
94 struct v7fs_superblock
*memsb
= &fs
->superblock
;
95 struct v7fs_superblock
*disksb
;
102 if (!(buf
= scratch_read(fs
, V7FS_SUPERBLOCK_SECTOR
)))
104 disksb
= (struct v7fs_superblock
*)buf
;
105 v7fs_superblock_endian_convert(fs
, disksb
, memsb
);
106 if (!fs
->io
.write(fs
->io
.cookie
, buf
, V7FS_SUPERBLOCK_SECTOR
))
108 scratch_free(fs
, buf
);
111 DPRINTF("done. %d\n", error
);
116 /* Check endian mismatch. */
118 v7fs_superblock_sanity(struct v7fs_self
*fs
)
120 const struct v7fs_superblock
*sb
= &fs
->superblock
;
123 if ((sb
->volume_size
< 128) || /* smaller than 64KB. */
124 (sb
->datablock_start_sector
> sb
->volume_size
) ||
125 (sb
->nfreeinode
> V7FS_MAX_FREEINODE
) ||
126 (sb
->nfreeblock
> V7FS_MAX_FREEBLOCK
) ||
127 (sb
->update_time
< 0) ||
128 (sb
->total_freeblock
> sb
->volume_size
) ||
129 ((sb
->nfreeinode
== 0) && (sb
->nfreeblock
== 0) &&
130 (sb
->total_freeblock
== 0) && (sb
->total_freeinode
== 0)) ||
131 (!(buf
= scratch_read(fs
, sb
->volume_size
- 1)))) {
132 DPRINTF("invalid super block.\n");
136 scratch_free(fs
, buf
);
141 /* Fill free block to superblock cache. */
143 v7fs_freeblock_update(struct v7fs_self
*fs
, v7fs_daddr_t blk
)
145 /* Assume superblock is locked by caller. */
146 struct v7fs_superblock
*sb
= &fs
->superblock
;
147 struct v7fs_freeblock
*fb
;
151 /* Read next freeblock table from disk. */
152 if (!datablock_number_sanity(fs
, blk
) || !(buf
= scratch_read(fs
, blk
)))
155 /* Update in-core superblock freelist. */
156 fb
= (struct v7fs_freeblock
*)buf
;
157 if ((error
= v7fs_freeblock_endian_convert(fs
, fb
))) {
158 scratch_free(fs
, buf
);
161 DPRINTF("freeblock table#%d, nfree=%d\n", blk
, fb
->nfreeblock
);
163 memcpy(sb
->freeblock
, fb
->freeblock
, sizeof(blk
) * fb
->nfreeblock
);
164 sb
->nfreeblock
= fb
->nfreeblock
;
166 scratch_free(fs
, buf
);
172 v7fs_freeblock_endian_convert(struct v7fs_self
*fs __unused
,
173 struct v7fs_freeblock
*fb __unused
)
179 nfree
= V7FS_VAL16(fs
, fb
->nfreeblock
);
180 if (nfree
<= 0 || nfree
> V7FS_MAX_FREEBLOCK
) {
181 DPRINTF("invalid freeblock list. %d (max=%d)\n", nfree
,
185 fb
->nfreeblock
= nfree
;
187 for (i
= 0; i
< nfree
; i
++) {
188 fb
->freeblock
[i
] = V7FS_VAL32(fs
, fb
->freeblock
[i
]);
195 /* Fill free inode to superblock cache. */
197 v7fs_freeinode_update(struct v7fs_self
*fs
)
199 /* Assume superblock is locked by caller. */
200 struct v7fs_superblock
*sb
= &fs
->superblock
;
201 v7fs_ino_t
*freeinode
= sb
->freeinode
;
205 /* Loop over all inode list. */
206 for (i
= V7FS_ILIST_SECTOR
, ino
= 1/* inode start from 1*/, k
= 0;
207 i
< sb
->datablock_start_sector
; i
++) {
208 struct v7fs_inode_diskimage
*di
;
210 if (!(buf
= scratch_read(fs
, i
))) {
211 DPRINTF("block %zu I/O error.\n", i
);
212 ino
+= V7FS_INODE_PER_BLOCK
;
215 di
= (struct v7fs_inode_diskimage
*)buf
;
218 (j
< V7FS_INODE_PER_BLOCK
) && (k
< V7FS_MAX_FREEINODE
);
220 if (v7fs_inode_allocated(di
))
222 DPRINTF("free inode%d\n", ino
);
223 freeinode
[k
++] = ino
;
225 scratch_free(fs
, buf
);
233 v7fs_superblock_endian_convert(struct v7fs_self
*fs __unused
,
234 struct v7fs_superblock
*to
, struct v7fs_superblock
*from
)
237 #define conv16(m) (to->m = V7FS_VAL16(fs, from->m))
238 #define conv32(m) (to->m = V7FS_VAL32(fs, from->m))
241 conv16(datablock_start_sector
);
244 v7fs_daddr_t
*dfrom
= from
->freeblock
;
245 v7fs_daddr_t
*dto
= to
->freeblock
;
246 for (i
= 0; i
< V7FS_MAX_FREEBLOCK
; i
++, dfrom
++, dto
++)
247 *dto
= V7FS_VAL32(fs
, *dfrom
);
250 v7fs_ino_t
*ifrom
= from
->freeinode
;
251 v7fs_ino_t
*ito
= to
->freeinode
;
252 for (i
= 0; i
< V7FS_MAX_FREEINODE
; i
++, ifrom
++, ito
++)
253 *ito
= V7FS_VAL16(fs
, *ifrom
);
256 conv32(total_freeblock
);
257 conv16(total_freeinode
);
261 memcpy(to
, from
, sizeof(*to
));