1262617Sdelphij/* $NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 uch Exp $ */ 2262685Sdelphij 3262617Sdelphij/*- 4262617Sdelphij * Copyright (c) 2011 The NetBSD Foundation, Inc. 5262617Sdelphij * All rights reserved. 6262617Sdelphij * 7262617Sdelphij * This code is derived from software contributed to The NetBSD Foundation 8262617Sdelphij * by UCHIYAMA Yasushi. 9262617Sdelphij * 10262617Sdelphij * Redistribution and use in source and binary forms, with or without 11262617Sdelphij * modification, are permitted provided that the following conditions 12262617Sdelphij * are met: 13262617Sdelphij * 1. Redistributions of source code must retain the above copyright 14262617Sdelphij * notice, this list of conditions and the following disclaimer. 15262617Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 16262617Sdelphij * notice, this list of conditions and the following disclaimer in the 17262617Sdelphij * documentation and/or other materials provided with the distribution. 18262617Sdelphij * 19262617Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20262617Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21262617Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22262617Sdelphij * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23262617Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24262617Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25262617Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26262617Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27262617Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28262685Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29262617Sdelphij * POSSIBILITY OF SUCH DAMAGE. 30262617Sdelphij */ 31262617Sdelphij 32262617Sdelphij#if HAVE_NBTOOL_CONFIG_H 33262617Sdelphij#include "nbtool_config.h" 34262617Sdelphij#endif 35262617Sdelphij 36262617Sdelphij#include <sys/cdefs.h> 37262617Sdelphij__KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); 38262617Sdelphij#if defined _KERNEL_OPT 39262617Sdelphij#include "opt_v7fs.h" 40262617Sdelphij#endif 41262617Sdelphij 42262685Sdelphij#ifdef _KERNEL 43262617Sdelphij#include <sys/systm.h> 44262617Sdelphij#include <sys/param.h> /* errno */ 45262617Sdelphij#else 46262617Sdelphij#include <stdio.h> 47262617Sdelphij#include <string.h> 48262617Sdelphij#include <errno.h> 49262617Sdelphij#endif 50262685Sdelphij 51262617Sdelphij#include "v7fs.h" 52262617Sdelphij#include "v7fs_impl.h" 53262617Sdelphij#include "v7fs_endian.h" 54262617Sdelphij#include "v7fs_superblock.h" 55262617Sdelphij#include "v7fs_inode.h" 56262617Sdelphij#include "v7fs_datablock.h" 57262617Sdelphij 58262685Sdelphij#ifdef V7FS_SUPERBLOCK_DEBUG 59262685Sdelphij#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 60262685Sdelphij#define DPRINTF_(fmt, args...) printf(fmt, ##args) 61262617Sdelphij#else 62262617Sdelphij#define DPRINTF(fmt, args...) ((void)0) 63262617Sdelphij#define DPRINTF_(fmt, args...) ((void)0) 64262685Sdelphij#endif 65262617Sdelphij 66262617Sdelphijstatic void v7fs_superblock_endian_convert(struct v7fs_self *, 67262617Sdelphij struct v7fs_superblock *, struct v7fs_superblock *); 68262617Sdelphijstatic int v7fs_superblock_sanity(struct v7fs_self *); 69262617Sdelphij 70262617Sdelphij/* Load superblock from disk. */ 71262617Sdelphijint 72262617Sdelphijv7fs_superblock_load(struct v7fs_self *fs) 73262685Sdelphij{ 74262685Sdelphij struct v7fs_superblock *disksb; 75262617Sdelphij void *buf; 76262685Sdelphij int error; 77262685Sdelphij 78262685Sdelphij if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) 79262685Sdelphij return EIO; 80262617Sdelphij disksb = (struct v7fs_superblock *)buf; 81262685Sdelphij v7fs_superblock_endian_convert(fs, &fs->superblock, disksb); 82262685Sdelphij scratch_free(fs, buf); 83262617Sdelphij 84262617Sdelphij if ((error = v7fs_superblock_sanity(fs))) 85262617Sdelphij return error; 86262617Sdelphij 87262685Sdelphij return 0; 88262685Sdelphij} 89262685Sdelphij 90262617Sdelphij/* Writeback superblock to disk. */ 91262617Sdelphijint 92262685Sdelphijv7fs_superblock_writeback(struct v7fs_self *fs) 93262685Sdelphij{ 94262617Sdelphij struct v7fs_superblock *memsb = &fs->superblock; 95262617Sdelphij struct v7fs_superblock *disksb; 96262617Sdelphij void *buf; 97262617Sdelphij int error = 0; 98262685Sdelphij 99262617Sdelphij if (!memsb->modified) 100262617Sdelphij return 0; 101262617Sdelphij 102262685Sdelphij if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) 103262685Sdelphij return EIO; 104262685Sdelphij disksb = (struct v7fs_superblock *)buf; 105262685Sdelphij v7fs_superblock_endian_convert(fs, disksb, memsb); 106262685Sdelphij if (!fs->io.write(fs->io.cookie, buf, V7FS_SUPERBLOCK_SECTOR)) 107262617Sdelphij error = EIO; 108262685Sdelphij scratch_free(fs, buf); 109262617Sdelphij 110262685Sdelphij memsb->modified = 0; 111262617Sdelphij DPRINTF("done. %d\n", error); 112262685Sdelphij 113262685Sdelphij return error; 114262685Sdelphij} 115262685Sdelphij 116262685Sdelphij/* Check endian mismatch. */ 117262685Sdelphijstatic int 118262685Sdelphijv7fs_superblock_sanity(struct v7fs_self *fs) 119262685Sdelphij{ 120262685Sdelphij const struct v7fs_superblock *sb = &fs->superblock; 121262617Sdelphij void *buf = 0; 122262617Sdelphij 123262617Sdelphij if ((sb->volume_size < 128) || /* smaller than 64KB. */ 124262617Sdelphij (sb->datablock_start_sector > sb->volume_size) || 125262617Sdelphij (sb->nfreeinode > V7FS_MAX_FREEINODE) || 126262685Sdelphij (sb->nfreeblock > V7FS_MAX_FREEBLOCK) || 127262617Sdelphij (sb->update_time < 0) || 128262617Sdelphij (sb->total_freeblock > sb->volume_size) || 129262617Sdelphij ((sb->nfreeinode == 0) && (sb->nfreeblock == 0) && 130262617Sdelphij (sb->total_freeblock == 0) && (sb->total_freeinode == 0)) || 131262617Sdelphij (!(buf = scratch_read(fs, sb->volume_size - 1)))) { 132262617Sdelphij DPRINTF("invalid super block.\n"); 133262617Sdelphij return EINVAL; 134262617Sdelphij } 135262617Sdelphij if (buf) 136262617Sdelphij scratch_free(fs, buf); 137262685Sdelphij 138262685Sdelphij return 0; 139} 140 141/* Fill free block to superblock cache. */ 142int 143v7fs_freeblock_update(struct v7fs_self *fs, v7fs_daddr_t blk) 144{ 145 /* Assume superblock is locked by caller. */ 146 struct v7fs_superblock *sb = &fs->superblock; 147 struct v7fs_freeblock *fb; 148 void *buf; 149 int error; 150 151 /* Read next freeblock table from disk. */ 152 if (!datablock_number_sanity(fs, blk) || !(buf = scratch_read(fs, blk))) 153 return EIO; 154 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); 159 return error; 160 } 161 DPRINTF("freeblock table#%d, nfree=%d\n", blk, fb->nfreeblock); 162 163 memcpy(sb->freeblock, fb->freeblock, sizeof(blk) * fb->nfreeblock); 164 sb->nfreeblock = fb->nfreeblock; 165 sb->modified = true; 166 scratch_free(fs, buf); 167 168 return 0; 169} 170 171int 172v7fs_freeblock_endian_convert(struct v7fs_self *fs __unused, 173 struct v7fs_freeblock *fb __unused) 174{ 175#ifdef V7FS_EI 176 int i; 177 int16_t nfree; 178 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, 182 V7FS_MAX_FREEBLOCK); 183 return ENOSPC; 184 } 185 fb->nfreeblock = nfree; 186 187 for (i = 0; i < nfree; i++) { 188 fb->freeblock[i] = V7FS_VAL32(fs, fb->freeblock[i]); 189 } 190#endif /* V7FS_EI */ 191 192 return 0; 193} 194 195/* Fill free inode to superblock cache. */ 196int 197v7fs_freeinode_update(struct v7fs_self *fs) 198{ 199 /* Assume superblock is locked by caller. */ 200 struct v7fs_superblock *sb = &fs->superblock; 201 v7fs_ino_t *freeinode = sb->freeinode; 202 size_t i, j, k; 203 v7fs_ino_t ino; 204 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; 209 void *buf; 210 if (!(buf = scratch_read(fs, i))) { 211 DPRINTF("block %zu I/O error.\n", i); 212 ino += V7FS_INODE_PER_BLOCK; 213 continue; 214 } 215 di = (struct v7fs_inode_diskimage *)buf; 216 217 for (j = 0; 218 (j < V7FS_INODE_PER_BLOCK) && (k < V7FS_MAX_FREEINODE); 219 j++, di++, ino++) { 220 if (v7fs_inode_allocated(di)) 221 continue; 222 DPRINTF("free inode%d\n", ino); 223 freeinode[k++] = ino; 224 } 225 scratch_free(fs, buf); 226 } 227 sb->nfreeinode = k; 228 229 return 0; 230} 231 232static void 233v7fs_superblock_endian_convert(struct v7fs_self *fs __unused, 234 struct v7fs_superblock *to, struct v7fs_superblock *from) 235{ 236#ifdef V7FS_EI 237#define conv16(m) (to->m = V7FS_VAL16(fs, from->m)) 238#define conv32(m) (to->m = V7FS_VAL32(fs, from->m)) 239 int i; 240 241 conv16(datablock_start_sector); 242 conv32(volume_size); 243 conv16(nfreeblock); 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); 248 249 conv16(nfreeinode); 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); 254 255 conv32(update_time); 256 conv32(total_freeblock); 257 conv16(total_freeinode); 258#undef conv16 259#undef conv32 260#else /* V7FS_EI */ 261 memcpy(to, from , sizeof(*to)); 262#endif /* V7FS_EI */ 263} 264