1*f1ca1ce2Sapb /* $NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $ */
29255b46fSuch
39255b46fSuch /*-
49255b46fSuch * Copyright (c) 2011 The NetBSD Foundation, Inc.
59255b46fSuch * All rights reserved.
69255b46fSuch *
79255b46fSuch * This code is derived from software contributed to The NetBSD Foundation
89255b46fSuch * by UCHIYAMA Yasushi.
99255b46fSuch *
109255b46fSuch * Redistribution and use in source and binary forms, with or without
119255b46fSuch * modification, are permitted provided that the following conditions
129255b46fSuch * are met:
139255b46fSuch * 1. Redistributions of source code must retain the above copyright
149255b46fSuch * notice, this list of conditions and the following disclaimer.
159255b46fSuch * 2. Redistributions in binary form must reproduce the above copyright
169255b46fSuch * notice, this list of conditions and the following disclaimer in the
179255b46fSuch * documentation and/or other materials provided with the distribution.
189255b46fSuch *
199255b46fSuch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209255b46fSuch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219255b46fSuch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229255b46fSuch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239255b46fSuch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249255b46fSuch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259255b46fSuch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269255b46fSuch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279255b46fSuch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289255b46fSuch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299255b46fSuch * POSSIBILITY OF SUCH DAMAGE.
309255b46fSuch */
319255b46fSuch
32*f1ca1ce2Sapb #if HAVE_NBTOOL_CONFIG_H
33*f1ca1ce2Sapb #include "nbtool_config.h"
34*f1ca1ce2Sapb #endif
35*f1ca1ce2Sapb
369255b46fSuch #include <sys/cdefs.h>
37*f1ca1ce2Sapb __KERNEL_RCSID(0, "$NetBSD: v7fs_superblock.c,v 1.2 2011/07/18 21:51:49 apb Exp $");
389255b46fSuch #if defined _KERNEL_OPT
399255b46fSuch #include "opt_v7fs.h"
409255b46fSuch #endif
419255b46fSuch
429255b46fSuch #ifdef _KERNEL
439255b46fSuch #include <sys/systm.h>
449255b46fSuch #include <sys/param.h> /* errno */
459255b46fSuch #else
469255b46fSuch #include <stdio.h>
479255b46fSuch #include <string.h>
489255b46fSuch #include <errno.h>
499255b46fSuch #endif
509255b46fSuch
519255b46fSuch #include "v7fs.h"
529255b46fSuch #include "v7fs_impl.h"
539255b46fSuch #include "v7fs_endian.h"
549255b46fSuch #include "v7fs_superblock.h"
559255b46fSuch #include "v7fs_inode.h"
569255b46fSuch #include "v7fs_datablock.h"
579255b46fSuch
589255b46fSuch #ifdef V7FS_SUPERBLOCK_DEBUG
599255b46fSuch #define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args)
609255b46fSuch #define DPRINTF_(fmt, args...) printf(fmt, ##args)
619255b46fSuch #else
629255b46fSuch #define DPRINTF(fmt, args...) ((void)0)
639255b46fSuch #define DPRINTF_(fmt, args...) ((void)0)
649255b46fSuch #endif
659255b46fSuch
669255b46fSuch static void v7fs_superblock_endian_convert(struct v7fs_self *,
679255b46fSuch struct v7fs_superblock *, struct v7fs_superblock *);
689255b46fSuch static int v7fs_superblock_sanity(struct v7fs_self *);
699255b46fSuch
709255b46fSuch /* Load superblock from disk. */
719255b46fSuch int
v7fs_superblock_load(struct v7fs_self * fs)729255b46fSuch v7fs_superblock_load(struct v7fs_self *fs)
739255b46fSuch {
749255b46fSuch struct v7fs_superblock *disksb;
759255b46fSuch void *buf;
769255b46fSuch int error;
779255b46fSuch
789255b46fSuch if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR)))
799255b46fSuch return EIO;
809255b46fSuch disksb = (struct v7fs_superblock *)buf;
819255b46fSuch v7fs_superblock_endian_convert(fs, &fs->superblock, disksb);
829255b46fSuch scratch_free(fs, buf);
839255b46fSuch
849255b46fSuch if ((error = v7fs_superblock_sanity(fs)))
859255b46fSuch return error;
869255b46fSuch
879255b46fSuch return 0;
889255b46fSuch }
899255b46fSuch
909255b46fSuch /* Writeback superblock to disk. */
919255b46fSuch int
v7fs_superblock_writeback(struct v7fs_self * fs)929255b46fSuch v7fs_superblock_writeback(struct v7fs_self *fs)
939255b46fSuch {
949255b46fSuch struct v7fs_superblock *memsb = &fs->superblock;
959255b46fSuch struct v7fs_superblock *disksb;
969255b46fSuch void *buf;
979255b46fSuch int error = 0;
989255b46fSuch
999255b46fSuch if (!memsb->modified)
1009255b46fSuch return 0;
1019255b46fSuch
1029255b46fSuch if (!(buf = scratch_read(fs, V7FS_SUPERBLOCK_SECTOR)))
1039255b46fSuch return EIO;
1049255b46fSuch disksb = (struct v7fs_superblock *)buf;
1059255b46fSuch v7fs_superblock_endian_convert(fs, disksb, memsb);
1069255b46fSuch if (!fs->io.write(fs->io.cookie, buf, V7FS_SUPERBLOCK_SECTOR))
1079255b46fSuch error = EIO;
1089255b46fSuch scratch_free(fs, buf);
1099255b46fSuch
1109255b46fSuch memsb->modified = 0;
1119255b46fSuch DPRINTF("done. %d\n", error);
1129255b46fSuch
1139255b46fSuch return error;
1149255b46fSuch }
1159255b46fSuch
1169255b46fSuch /* Check endian mismatch. */
1179255b46fSuch static int
v7fs_superblock_sanity(struct v7fs_self * fs)1189255b46fSuch v7fs_superblock_sanity(struct v7fs_self *fs)
1199255b46fSuch {
1209255b46fSuch const struct v7fs_superblock *sb = &fs->superblock;
1219255b46fSuch void *buf = 0;
1229255b46fSuch
1239255b46fSuch if ((sb->volume_size < 128) || /* smaller than 64KB. */
1249255b46fSuch (sb->datablock_start_sector > sb->volume_size) ||
1259255b46fSuch (sb->nfreeinode > V7FS_MAX_FREEINODE) ||
1269255b46fSuch (sb->nfreeblock > V7FS_MAX_FREEBLOCK) ||
1279255b46fSuch (sb->update_time < 0) ||
1289255b46fSuch (sb->total_freeblock > sb->volume_size) ||
1299255b46fSuch ((sb->nfreeinode == 0) && (sb->nfreeblock == 0) &&
1309255b46fSuch (sb->total_freeblock == 0) && (sb->total_freeinode == 0)) ||
1319255b46fSuch (!(buf = scratch_read(fs, sb->volume_size - 1)))) {
1329255b46fSuch DPRINTF("invalid super block.\n");
1339255b46fSuch return EINVAL;
1349255b46fSuch }
1359255b46fSuch if (buf)
1369255b46fSuch scratch_free(fs, buf);
1379255b46fSuch
1389255b46fSuch return 0;
1399255b46fSuch }
1409255b46fSuch
1419255b46fSuch /* Fill free block to superblock cache. */
1429255b46fSuch int
v7fs_freeblock_update(struct v7fs_self * fs,v7fs_daddr_t blk)1439255b46fSuch v7fs_freeblock_update(struct v7fs_self *fs, v7fs_daddr_t blk)
1449255b46fSuch {
1459255b46fSuch /* Assume superblock is locked by caller. */
1469255b46fSuch struct v7fs_superblock *sb = &fs->superblock;
1479255b46fSuch struct v7fs_freeblock *fb;
1489255b46fSuch void *buf;
1499255b46fSuch int error;
1509255b46fSuch
1519255b46fSuch /* Read next freeblock table from disk. */
1529255b46fSuch if (!datablock_number_sanity(fs, blk) || !(buf = scratch_read(fs, blk)))
1539255b46fSuch return EIO;
1549255b46fSuch
1559255b46fSuch /* Update in-core superblock freelist. */
1569255b46fSuch fb = (struct v7fs_freeblock *)buf;
1579255b46fSuch if ((error = v7fs_freeblock_endian_convert(fs, fb))) {
1589255b46fSuch scratch_free(fs, buf);
1599255b46fSuch return error;
1609255b46fSuch }
1619255b46fSuch DPRINTF("freeblock table#%d, nfree=%d\n", blk, fb->nfreeblock);
1629255b46fSuch
1639255b46fSuch memcpy(sb->freeblock, fb->freeblock, sizeof(blk) * fb->nfreeblock);
1649255b46fSuch sb->nfreeblock = fb->nfreeblock;
1659255b46fSuch sb->modified = true;
1669255b46fSuch scratch_free(fs, buf);
1679255b46fSuch
1689255b46fSuch return 0;
1699255b46fSuch }
1709255b46fSuch
1719255b46fSuch int
v7fs_freeblock_endian_convert(struct v7fs_self * fs __unused,struct v7fs_freeblock * fb __unused)1729255b46fSuch v7fs_freeblock_endian_convert(struct v7fs_self *fs __unused,
1739255b46fSuch struct v7fs_freeblock *fb __unused)
1749255b46fSuch {
1759255b46fSuch #ifdef V7FS_EI
1769255b46fSuch int i;
1779255b46fSuch int16_t nfree;
1789255b46fSuch
1799255b46fSuch nfree = V7FS_VAL16(fs, fb->nfreeblock);
1809255b46fSuch if (nfree <= 0 || nfree > V7FS_MAX_FREEBLOCK) {
1819255b46fSuch DPRINTF("invalid freeblock list. %d (max=%d)\n", nfree,
1829255b46fSuch V7FS_MAX_FREEBLOCK);
1839255b46fSuch return ENOSPC;
1849255b46fSuch }
1859255b46fSuch fb->nfreeblock = nfree;
1869255b46fSuch
1879255b46fSuch for (i = 0; i < nfree; i++) {
1889255b46fSuch fb->freeblock[i] = V7FS_VAL32(fs, fb->freeblock[i]);
1899255b46fSuch }
1909255b46fSuch #endif /* V7FS_EI */
1919255b46fSuch
1929255b46fSuch return 0;
1939255b46fSuch }
1949255b46fSuch
1959255b46fSuch /* Fill free inode to superblock cache. */
1969255b46fSuch int
v7fs_freeinode_update(struct v7fs_self * fs)1979255b46fSuch v7fs_freeinode_update(struct v7fs_self *fs)
1989255b46fSuch {
1999255b46fSuch /* Assume superblock is locked by caller. */
2009255b46fSuch struct v7fs_superblock *sb = &fs->superblock;
2019255b46fSuch v7fs_ino_t *freeinode = sb->freeinode;
2029255b46fSuch size_t i, j, k;
2039255b46fSuch v7fs_ino_t ino;
2049255b46fSuch
2059255b46fSuch /* Loop over all inode list. */
2069255b46fSuch for (i = V7FS_ILIST_SECTOR, ino = 1/* inode start from 1*/, k = 0;
2079255b46fSuch i < sb->datablock_start_sector; i++) {
2089255b46fSuch struct v7fs_inode_diskimage *di;
2099255b46fSuch void *buf;
2109255b46fSuch if (!(buf = scratch_read(fs, i))) {
2119255b46fSuch DPRINTF("block %zu I/O error.\n", i);
2129255b46fSuch ino += V7FS_INODE_PER_BLOCK;
2139255b46fSuch continue;
2149255b46fSuch }
2159255b46fSuch di = (struct v7fs_inode_diskimage *)buf;
2169255b46fSuch
2179255b46fSuch for (j = 0;
2189255b46fSuch (j < V7FS_INODE_PER_BLOCK) && (k < V7FS_MAX_FREEINODE);
2199255b46fSuch j++, di++, ino++) {
2209255b46fSuch if (v7fs_inode_allocated(di))
2219255b46fSuch continue;
2229255b46fSuch DPRINTF("free inode%d\n", ino);
2239255b46fSuch freeinode[k++] = ino;
2249255b46fSuch }
2259255b46fSuch scratch_free(fs, buf);
2269255b46fSuch }
2279255b46fSuch sb->nfreeinode = k;
2289255b46fSuch
2299255b46fSuch return 0;
2309255b46fSuch }
2319255b46fSuch
2329255b46fSuch static void
v7fs_superblock_endian_convert(struct v7fs_self * fs __unused,struct v7fs_superblock * to,struct v7fs_superblock * from)2339255b46fSuch v7fs_superblock_endian_convert(struct v7fs_self *fs __unused,
2349255b46fSuch struct v7fs_superblock *to, struct v7fs_superblock *from)
2359255b46fSuch {
2369255b46fSuch #ifdef V7FS_EI
2379255b46fSuch #define conv16(m) (to->m = V7FS_VAL16(fs, from->m))
2389255b46fSuch #define conv32(m) (to->m = V7FS_VAL32(fs, from->m))
2399255b46fSuch int i;
2409255b46fSuch
2419255b46fSuch conv16(datablock_start_sector);
2429255b46fSuch conv32(volume_size);
2439255b46fSuch conv16(nfreeblock);
2449255b46fSuch v7fs_daddr_t *dfrom = from->freeblock;
2459255b46fSuch v7fs_daddr_t *dto = to->freeblock;
2469255b46fSuch for (i = 0; i < V7FS_MAX_FREEBLOCK; i++, dfrom++, dto++)
2479255b46fSuch *dto = V7FS_VAL32(fs, *dfrom);
2489255b46fSuch
2499255b46fSuch conv16(nfreeinode);
2509255b46fSuch v7fs_ino_t *ifrom = from->freeinode;
2519255b46fSuch v7fs_ino_t *ito = to->freeinode;
2529255b46fSuch for (i = 0; i < V7FS_MAX_FREEINODE; i++, ifrom++, ito++)
2539255b46fSuch *ito = V7FS_VAL16(fs, *ifrom);
2549255b46fSuch
2559255b46fSuch conv32(update_time);
2569255b46fSuch conv32(total_freeblock);
2579255b46fSuch conv16(total_freeinode);
2589255b46fSuch #undef conv16
2599255b46fSuch #undef conv32
2609255b46fSuch #else /* V7FS_EI */
2619255b46fSuch memcpy(to, from , sizeof(*to));
2629255b46fSuch #endif /* V7FS_EI */
2639255b46fSuch }
264