1/* $NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 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#if HAVE_NBTOOL_CONFIG_H 33#include "nbtool_config.h" 34#endif 35 36#include <sys/cdefs.h> 37__KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); 38#if defined _KERNEL_OPT 39#include "opt_v7fs.h" 40#endif 41 42#ifdef _KERNEL 43#include <sys/systm.h> 44#include <sys/param.h> /* errno */ 45#else 46#include <stdio.h> 47#include <string.h> 48#include <errno.h> 49#endif 50 51#include "v7fs.h" 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" 57 58#ifdef V7FS_SUPERBLOCK_DEBUG 59#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 60#define DPRINTF_(fmt, args...) printf(fmt, ##args) 61#else 62#define DPRINTF(fmt, args...) ((void)0) 63#define DPRINTF_(fmt, args...) ((void)0) 64#endif 65 66static void v7fs_superblock_endian_convert(struct v7fs_self *, 67 struct v7fs_superblock *, struct v7fs_superblock *); 68static int v7fs_superblock_sanity(struct v7fs_self *); 69 70/* Load superblock from disk. */ 71int 72v7fs_superblock_load(struct v7fs_self *fs) 73{ 74 struct v7fs_superblock *disksb; 75 void *buf; 76 int error; 77 78 if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) 79 return EIO; 80 disksb = (struct v7fs_superblock *)buf; 81 v7fs_superblock_endian_convert(fs, &fs->superblock, disksb); 82 scratch_free(fs, buf); 83 84 if ((error = v7fs_superblock_sanity(fs))) 85 return error; 86 87 return 0; 88} 89 90/* Writeback superblock to disk. */ 91int 92v7fs_superblock_writeback(struct v7fs_self *fs) 93{ 94 struct v7fs_superblock *memsb = &fs->superblock; 95 struct v7fs_superblock *disksb; 96 void *buf; 97 int error = 0; 98 99 if (!memsb->modified) 100 return 0; 101 102 if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) 103 return EIO; 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)) 107 error = EIO; 108 scratch_free(fs, buf); 109 110 memsb->modified = 0; 111 DPRINTF("done. %d\n", error); 112 113 return error; 114} 115 116/* Check endian mismatch. */ 117static int 118v7fs_superblock_sanity(struct v7fs_self *fs) 119{ 120 const struct v7fs_superblock *sb = &fs->superblock; 121 void *buf = 0; 122 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"); 133 return EINVAL; 134 } 135 if (buf) 136 scratch_free(fs, buf); 137 138 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