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 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.1 2011/06/27 11:52:25 uch Exp $"); 34 #if defined _KERNEL_OPT 35 #include "opt_v7fs.h" 36 #endif 37 38 #ifdef _KERNEL 39 #include <sys/systm.h> 40 #include <sys/param.h> /* errno */ 41 #else 42 #include <stdio.h> 43 #include <string.h> 44 #include <errno.h> 45 #endif 46 47 #include "v7fs.h" 48 #include "v7fs_impl.h" 49 #include "v7fs_endian.h" 50 #include "v7fs_superblock.h" 51 #include "v7fs_inode.h" 52 #include "v7fs_datablock.h" 53 54 #ifdef V7FS_SUPERBLOCK_DEBUG 55 #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 56 #define DPRINTF_(fmt, args...) printf(fmt, ##args) 57 #else 58 #define DPRINTF(fmt, args...) ((void)0) 59 #define DPRINTF_(fmt, args...) ((void)0) 60 #endif 61 62 static void v7fs_superblock_endian_convert(struct v7fs_self *, 63 struct v7fs_superblock *, struct v7fs_superblock *); 64 static int v7fs_superblock_sanity(struct v7fs_self *); 65 66 /* Load superblock from disk. */ 67 int 68 v7fs_superblock_load(struct v7fs_self *fs) 69 { 70 struct v7fs_superblock *disksb; 71 void *buf; 72 int error; 73 74 if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) 75 return EIO; 76 disksb = (struct v7fs_superblock *)buf; 77 v7fs_superblock_endian_convert(fs, &fs->superblock, disksb); 78 scratch_free(fs, buf); 79 80 if ((error = v7fs_superblock_sanity(fs))) 81 return error; 82 83 return 0; 84 } 85 86 /* Writeback superblock to disk. */ 87 int 88 v7fs_superblock_writeback(struct v7fs_self *fs) 89 { 90 struct v7fs_superblock *memsb = &fs->superblock; 91 struct v7fs_superblock *disksb; 92 void *buf; 93 int error = 0; 94 95 if (!memsb->modified) 96 return 0; 97 98 if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR))) 99 return EIO; 100 disksb = (struct v7fs_superblock *)buf; 101 v7fs_superblock_endian_convert(fs, disksb, memsb); 102 if (!fs->io.write(fs->io.cookie, buf, V7FS_SUPERBLOCK_SECTOR)) 103 error = EIO; 104 scratch_free(fs, buf); 105 106 memsb->modified = 0; 107 DPRINTF("done. %d\n", error); 108 109 return error; 110 } 111 112 /* Check endian mismatch. */ 113 static int 114 v7fs_superblock_sanity(struct v7fs_self *fs) 115 { 116 const struct v7fs_superblock *sb = &fs->superblock; 117 void *buf = 0; 118 119 if ((sb->volume_size < 128) || /* smaller than 64KB. */ 120 (sb->datablock_start_sector > sb->volume_size) || 121 (sb->nfreeinode > V7FS_MAX_FREEINODE) || 122 (sb->nfreeblock > V7FS_MAX_FREEBLOCK) || 123 (sb->update_time < 0) || 124 (sb->total_freeblock > sb->volume_size) || 125 ((sb->nfreeinode == 0) && (sb->nfreeblock == 0) && 126 (sb->total_freeblock == 0) && (sb->total_freeinode == 0)) || 127 (!(buf = scratch_read(fs, sb->volume_size - 1)))) { 128 DPRINTF("invalid super block.\n"); 129 return EINVAL; 130 } 131 if (buf) 132 scratch_free(fs, buf); 133 134 return 0; 135 } 136 137 /* Fill free block to superblock cache. */ 138 int 139 v7fs_freeblock_update(struct v7fs_self *fs, v7fs_daddr_t blk) 140 { 141 /* Assume superblock is locked by caller. */ 142 struct v7fs_superblock *sb = &fs->superblock; 143 struct v7fs_freeblock *fb; 144 void *buf; 145 int error; 146 147 /* Read next freeblock table from disk. */ 148 if (!datablock_number_sanity(fs, blk) || !(buf = scratch_read(fs, blk))) 149 return EIO; 150 151 /* Update in-core superblock freelist. */ 152 fb = (struct v7fs_freeblock *)buf; 153 if ((error = v7fs_freeblock_endian_convert(fs, fb))) { 154 scratch_free(fs, buf); 155 return error; 156 } 157 DPRINTF("freeblock table#%d, nfree=%d\n", blk, fb->nfreeblock); 158 159 memcpy(sb->freeblock, fb->freeblock, sizeof(blk) * fb->nfreeblock); 160 sb->nfreeblock = fb->nfreeblock; 161 sb->modified = true; 162 scratch_free(fs, buf); 163 164 return 0; 165 } 166 167 int 168 v7fs_freeblock_endian_convert(struct v7fs_self *fs __unused, 169 struct v7fs_freeblock *fb __unused) 170 { 171 #ifdef V7FS_EI 172 int i; 173 int16_t nfree; 174 175 nfree = V7FS_VAL16(fs, fb->nfreeblock); 176 if (nfree <= 0 || nfree > V7FS_MAX_FREEBLOCK) { 177 DPRINTF("invalid freeblock list. %d (max=%d)\n", nfree, 178 V7FS_MAX_FREEBLOCK); 179 return ENOSPC; 180 } 181 fb->nfreeblock = nfree; 182 183 for (i = 0; i < nfree; i++) { 184 fb->freeblock[i] = V7FS_VAL32(fs, fb->freeblock[i]); 185 } 186 #endif /* V7FS_EI */ 187 188 return 0; 189 } 190 191 /* Fill free inode to superblock cache. */ 192 int 193 v7fs_freeinode_update(struct v7fs_self *fs) 194 { 195 /* Assume superblock is locked by caller. */ 196 struct v7fs_superblock *sb = &fs->superblock; 197 v7fs_ino_t *freeinode = sb->freeinode; 198 size_t i, j, k; 199 v7fs_ino_t ino; 200 201 /* Loop over all inode list. */ 202 for (i = V7FS_ILIST_SECTOR, ino = 1/* inode start from 1*/, k = 0; 203 i < sb->datablock_start_sector; i++) { 204 struct v7fs_inode_diskimage *di; 205 void *buf; 206 if (!(buf = scratch_read(fs, i))) { 207 DPRINTF("block %zu I/O error.\n", i); 208 ino += V7FS_INODE_PER_BLOCK; 209 continue; 210 } 211 di = (struct v7fs_inode_diskimage *)buf; 212 213 for (j = 0; 214 (j < V7FS_INODE_PER_BLOCK) && (k < V7FS_MAX_FREEINODE); 215 j++, di++, ino++) { 216 if (v7fs_inode_allocated(di)) 217 continue; 218 DPRINTF("free inode%d\n", ino); 219 freeinode[k++] = ino; 220 } 221 scratch_free(fs, buf); 222 } 223 sb->nfreeinode = k; 224 225 return 0; 226 } 227 228 static void 229 v7fs_superblock_endian_convert(struct v7fs_self *fs __unused, 230 struct v7fs_superblock *to, struct v7fs_superblock *from) 231 { 232 #ifdef V7FS_EI 233 #define conv16(m) (to->m = V7FS_VAL16(fs, from->m)) 234 #define conv32(m) (to->m = V7FS_VAL32(fs, from->m)) 235 int i; 236 237 conv16(datablock_start_sector); 238 conv32(volume_size); 239 conv16(nfreeblock); 240 v7fs_daddr_t *dfrom = from->freeblock; 241 v7fs_daddr_t *dto = to->freeblock; 242 for (i = 0; i < V7FS_MAX_FREEBLOCK; i++, dfrom++, dto++) 243 *dto = V7FS_VAL32(fs, *dfrom); 244 245 conv16(nfreeinode); 246 v7fs_ino_t *ifrom = from->freeinode; 247 v7fs_ino_t *ito = to->freeinode; 248 for (i = 0; i < V7FS_MAX_FREEINODE; i++, ifrom++, ito++) 249 *ito = V7FS_VAL16(fs, *ifrom); 250 251 conv32(update_time); 252 conv32(total_freeblock); 253 conv16(total_freeinode); 254 #undef conv16 255 #undef conv32 256 #else /* V7FS_EI */ 257 memcpy(to, from , sizeof(*to)); 258 #endif /* V7FS_EI */ 259 } 260