1/* $NetBSD: v7fs_inode.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_inode.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> 45#else 46#include <stdio.h> 47#include <string.h> 48#include <errno.h> 49#include <time.h> 50#endif 51 52#include "v7fs.h" 53#include "v7fs_impl.h" 54#include "v7fs_endian.h" 55#include "v7fs_inode.h" 56#include "v7fs_superblock.h" 57 58#ifdef V7FS_INODE_DEBUG 59#define DPRINTF(fmt, args...) printf("%s: " fmt, __func__, ##args) 60#else 61#define DPRINTF(fmt, args...) ((void)0) 62#endif 63 64static void v7fs_inode_setup_disk_image(const struct v7fs_self *, 65 struct v7fs_inode *, struct v7fs_inode_diskimage *); 66static int v7fs_inode_inquire_disk_location(const struct v7fs_self *, 67 v7fs_ino_t, v7fs_daddr_t *, v7fs_daddr_t *); 68#ifdef V7FS_INODE_DEBUG 69static int v7fs_inode_block_sanity(const struct v7fs_superblock *, 70 v7fs_daddr_t); 71 72static int 73v7fs_inode_block_sanity(const struct v7fs_superblock *sb, v7fs_daddr_t blk) 74{ 75 76 if ((blk < V7FS_ILIST_SECTOR) || (blk >= sb->datablock_start_sector)) { 77 DPRINTF("invalid inode block#%d (%d-%d)\n", blk, 78 V7FS_ILIST_SECTOR, sb->datablock_start_sector); 79 return ENOSPC; 80 } 81 82 return 0; 83} 84#endif /* V7FS_INODE_DEBUG */ 85 86int 87v7fs_inode_number_sanity(const struct v7fs_superblock *sb, v7fs_ino_t ino) 88{ 89 90 if (ino < V7FS_ROOT_INODE || ((size_t)ino >= V7FS_MAX_INODE(sb))) { 91 DPRINTF("invalid inode#%d (%d-%zu)\n", ino, 92 V7FS_ROOT_INODE, V7FS_MAX_INODE(sb)); 93 return ENOSPC; 94 } 95 96 return 0; 97} 98 99int 100v7fs_inode_allocate(struct v7fs_self *fs, v7fs_ino_t *ino) 101{ 102 struct v7fs_superblock *sb = &fs->superblock; 103 v7fs_ino_t inode_number; 104 int error = ENOSPC; 105 *ino = 0; 106 107 SUPERB_LOCK(fs); 108 if (sb->total_freeinode == 0) { 109 DPRINTF("inode exhausted!(1)\n"); 110 goto errexit; 111 } 112 113 /* If there is no free inode cache, update it. */ 114 if (sb->nfreeinode <= 0 && (error = v7fs_freeinode_update(fs))) { 115 DPRINTF("inode exhausted!(2)\n"); 116 goto errexit; 117 } 118 /* Get inode from superblock cache. */ 119 KDASSERT(sb->nfreeinode <= V7FS_MAX_FREEINODE); 120 inode_number = sb->freeinode[--sb->nfreeinode]; 121 sb->total_freeinode--; 122 sb->modified = 1; 123 124 if ((error = v7fs_inode_number_sanity(sb, inode_number))) { 125 DPRINTF("new inode#%d %d %d\n", inode_number, sb->nfreeinode, 126 sb->total_freeinode); 127 DPRINTF("free inode list corupt\n"); 128 goto errexit; 129 } 130 *ino = inode_number; 131 132errexit: 133 SUPERB_UNLOCK(fs); 134 135 return error; 136} 137 138void 139v7fs_inode_deallocate(struct v7fs_self *fs, v7fs_ino_t ino) 140{ 141 struct v7fs_superblock *sb = &fs->superblock; 142 struct v7fs_inode inode; 143 144 memset(&inode, 0, sizeof(inode)); 145 inode.inode_number = ino; 146 v7fs_inode_writeback(fs, &inode); 147 148 SUPERB_LOCK(fs); 149 if (sb->nfreeinode < V7FS_MAX_FREEINODE) { 150 /* link to freeinode list. */ 151 sb->freeinode[sb->nfreeinode++] = ino; 152 } 153 /* If superblock inode cache is full, this inode charged by 154 v7fs_freeinode_update() later. */ 155 sb->total_freeinode++; 156 sb->modified = true; 157 SUPERB_UNLOCK(fs); 158} 159 160void 161v7fs_inode_setup_memory_image(const struct v7fs_self *fs __unused, 162 struct v7fs_inode *mem, struct v7fs_inode_diskimage *disk) 163{ 164#define conv16(m) (mem->m = V7FS_VAL16(fs, (disk->m))) 165#define conv32(m) (mem->m = V7FS_VAL32(fs, (disk->m))) 166 uint32_t addr; 167 int i; 168 169 memset(mem, 0, sizeof(*mem)); 170 conv16(mode); 171 conv16(nlink); 172 conv16(uid); 173 conv16(gid); 174 conv32(filesize); 175 conv32(atime); 176 conv32(mtime); 177 conv32(ctime); 178 179 for (i = 0; i < V7FS_NADDR; i++) { 180 int j = i * 3; /* 3 byte each. (v7fs_daddr is 24bit) */ 181 /* expand to 4byte with endian conversion. */ 182 addr = V7FS_VAL24_READ(fs, &disk->addr[j]); 183 mem->addr[i] = addr; 184 } 185 mem->device = 0; 186 if (v7fs_inode_iscdev(mem) || v7fs_inode_isbdev(mem)) { 187 mem->device = mem->addr[0]; 188 } 189 190#undef conv16 191#undef conv32 192} 193 194static void 195v7fs_inode_setup_disk_image(const struct v7fs_self *fs __unused, 196 struct v7fs_inode *mem, struct v7fs_inode_diskimage *disk) 197{ 198#define conv16(m) (disk->m = V7FS_VAL16(fs, (mem->m))) 199#define conv32(m) (disk->m = V7FS_VAL32(fs, (mem->m))) 200 201 conv16(mode); 202 conv16(nlink); 203 conv16(uid); 204 conv16(gid); 205 conv32(filesize); 206 conv32(atime); 207 conv32(mtime); 208 conv32(ctime); 209 210 int i; 211 for (i = 0; i < V7FS_NADDR; i++) { 212 int j = i * 3; /* 3 byte each. */ 213 V7FS_VAL24_WRITE(fs, mem->addr[i], disk->addr + j); 214 } 215#undef conv16 216#undef conv32 217} 218 219/* Load inode from disk. */ 220int 221v7fs_inode_load(struct v7fs_self *fs, struct v7fs_inode *p, v7fs_ino_t n) 222{ 223 v7fs_daddr_t blk, ofs; 224 struct v7fs_inode_diskimage *di; 225 void *buf; 226 227 if (v7fs_inode_inquire_disk_location(fs, n, &blk, &ofs) != 0) 228 return ENOENT; 229 230 ILIST_LOCK(fs); 231 if (!(buf = scratch_read(fs, blk))) { 232 ILIST_UNLOCK(fs); 233 return EIO; 234 } 235 ILIST_UNLOCK(fs); 236 di = (struct v7fs_inode_diskimage *)buf; 237 238 /* Decode disk address, convert endian. */ 239 v7fs_inode_setup_memory_image(fs, p, di + ofs); 240 p->inode_number = n; 241 242 scratch_free(fs, buf); 243 244 return 0; 245} 246 247/* Write back inode to disk. */ 248int 249v7fs_inode_writeback(struct v7fs_self *fs, struct v7fs_inode *mem) 250{ 251 struct v7fs_inode_diskimage disk; 252 v7fs_ino_t ino = mem->inode_number; 253 v7fs_daddr_t blk; 254 v7fs_daddr_t ofs; 255 void *buf; 256 int error = 0; 257 258 if (v7fs_inode_inquire_disk_location(fs, ino, &blk, &ofs) != 0) 259 return ENOENT; 260 261 v7fs_inode_setup_disk_image(fs, mem, &disk); 262 263 ILIST_LOCK(fs); 264 if (!(buf = scratch_read(fs, blk))) { 265 ILIST_UNLOCK(fs); 266 return EIO; 267 } 268 struct v7fs_inode_diskimage *di = (struct v7fs_inode_diskimage *)buf; 269 di[ofs] = disk; /* structure copy; */ 270 if (!fs->io.write(fs->io.cookie, buf, blk)) 271 error = EIO; 272 ILIST_UNLOCK(fs); 273 274 scratch_free(fs, buf); 275 276 return error; 277} 278 279static int 280v7fs_inode_inquire_disk_location(const struct v7fs_self *fs 281 __unused, v7fs_ino_t n, v7fs_daddr_t *block, 282 v7fs_daddr_t *offset) 283{ 284 v7fs_daddr_t ofs, blk; 285#ifdef V7FS_INODE_DEBUG 286 v7fs_inode_number_sanity(&fs->superblock, n); 287#endif 288 ofs = (n - 1/*inode start from 1*/) * 289 sizeof(struct v7fs_inode_diskimage); 290 blk = ofs >> V7FS_BSHIFT; 291 292 *block = blk + V7FS_ILIST_SECTOR; 293 *offset = (ofs - blk * V7FS_BSIZE) / 294 sizeof(struct v7fs_inode_diskimage); 295#ifdef V7FS_INODE_DEBUG 296 return v7fs_inode_block_sanity(&fs->superblock, *block); 297#else 298 return 0; 299#endif 300} 301 302