1 /* $NetBSD: v7fs_inode.c,v 1.3 2024/09/25 20:10:36 andvar 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.3 2024/09/25 20:10:36 andvar 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 64 static void v7fs_inode_setup_disk_image(const struct v7fs_self *, 65 struct v7fs_inode *, struct v7fs_inode_diskimage *); 66 static 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 69 static int v7fs_inode_block_sanity(const struct v7fs_superblock *, 70 v7fs_daddr_t); 71 72 static int 73 v7fs_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 86 int 87 v7fs_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 99 int 100 v7fs_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 corrupt\n"); 128 goto errexit; 129 } 130 *ino = inode_number; 131 132 errexit: 133 SUPERB_UNLOCK(fs); 134 135 return error; 136 } 137 138 void 139 v7fs_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 160 void 161 v7fs_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 194 static void 195 v7fs_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. */ 220 int 221 v7fs_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. */ 248 int 249 v7fs_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 279 static int 280 v7fs_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