Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/minix/v2_inode.c 3 * 4 * Copyright 2018, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/fs.h> 10 #include <fiwix/filesystems.h> 11 #include <fiwix/fs_minix.h> 12 #include <fiwix/fs_pipe.h> 13 #include <fiwix/statfs.h> 14 #include <fiwix/sleep.h> 15 #include <fiwix/stat.h> 16 #include <fiwix/sched.h> 17 #include <fiwix/buffer.h> 18 #include <fiwix/process.h> 19 #include <fiwix/errno.h> 20 #include <fiwix/stdio.h> 21 #include <fiwix/string.h> 22 23 #define BLOCKS_PER_IND_BLOCK(sb) (sb->s_blocksize / sizeof(__u32)) 24 #define MINIX2_INODES_PER_BLOCK(sb) (sb->s_blocksize / sizeof(struct minix2_inode)) 25 26 #define MINIX_NDIR_BLOCKS 7 27 #define MINIX_IND_BLOCK MINIX_NDIR_BLOCKS 28 #define MINIX_DIND_BLOCK (MINIX_NDIR_BLOCKS + 1) 29 #define MINIX_TIND_BLOCK (MINIX_NDIR_BLOCKS + 2) 30 31 static void free_zone(struct inode *i, int block, int offset) 32 { 33 int n; 34 struct buffer *buf; 35 __u32 *zone; 36 37 if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) { 38 printk("WARNING: %s(): error reading block %d.\n", __FUNCTION__, block); 39 return; 40 } 41 zone = (__u32 *)buf->data; 42 for(n = offset; n < BLOCKS_PER_IND_BLOCK(i->sb); n++) { 43 if(zone[n]) { 44 minix_bfree(i->sb, zone[n]); 45 zone[n] = 0; 46 } 47 } 48 bwrite(buf); 49 } 50 51 int v2_minix_read_inode(struct inode *i) 52 { 53 __ino_t block; 54 short int offset; 55 struct minix2_inode *ii; 56 struct buffer *buf; 57 int errno; 58 59 block = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX2_INODES_PER_BLOCK(i->sb); 60 61 if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) { 62 return -EIO; 63 } 64 offset = (i->inode - 1) % MINIX2_INODES_PER_BLOCK(i->sb); 65 ii = ((struct minix2_inode *)buf->data) + offset; 66 67 i->i_mode = ii->i_mode; 68 i->i_nlink = ii->i_nlink; 69 i->i_uid = ii->i_uid; 70 i->i_gid = ii->i_gid; 71 i->i_size = ii->i_size; 72 i->i_atime = ii->i_atime; 73 i->i_mtime = ii->i_mtime; 74 i->i_ctime = ii->i_ctime; 75 memcpy_b(i->u.minix.u.i2_zone, ii->i_zone, sizeof(ii->i_zone)); 76 i->count = 1; 77 78 errno = 0; 79 switch(i->i_mode & S_IFMT) { 80 case S_IFCHR: 81 i->fsop = &def_chr_fsop; 82 i->rdev = ii->i_zone[0]; 83 break; 84 case S_IFBLK: 85 i->fsop = &def_blk_fsop; 86 i->rdev = ii->i_zone[0]; 87 break; 88 case S_IFIFO: 89 i->fsop = &pipefs_fsop; 90 /* it's a union so we need to clear pipefs_i */ 91 memset_b(&i->u.pipefs, NULL, sizeof(struct pipefs_inode)); 92 break; 93 case S_IFDIR: 94 i->fsop = &minix_dir_fsop; 95 break; 96 case S_IFREG: 97 i->fsop = &minix_file_fsop; 98 break; 99 case S_IFLNK: 100 i->fsop = &minix_symlink_fsop; 101 break; 102 case S_IFSOCK: 103 i->fsop = NULL; 104 break; 105 default: 106 printk("WARNING: %s(): invalid inode (%d) mode %o.\n", __FUNCTION__, i->inode, i->i_mode); 107 errno = -ENOENT; 108 break; 109 } 110 111 brelse(buf); 112 return errno; 113 } 114 115 int v2_minix_write_inode(struct inode *i) 116 { 117 __ino_t block; 118 short int offset; 119 struct minix2_inode *ii; 120 struct buffer *buf; 121 122 block = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX2_INODES_PER_BLOCK(i->sb); 123 124 if(!(buf = bread(i->dev, block, i->sb->s_blocksize))) { 125 return -EIO; 126 } 127 offset = (i->inode - 1) % MINIX2_INODES_PER_BLOCK(i->sb); 128 ii = ((struct minix2_inode *)buf->data) + offset; 129 130 ii->i_mode = i->i_mode; 131 ii->i_nlink = i->i_nlink; 132 ii->i_uid = i->i_uid; 133 ii->i_gid = i->i_gid; 134 ii->i_size = i->i_size; 135 ii->i_atime = i->i_atime; 136 ii->i_mtime = i->i_mtime; 137 ii->i_ctime = i->i_ctime; 138 if(S_ISCHR(i->i_mode) || S_ISBLK(i->i_mode)) { 139 ii->i_zone[0] = i->rdev; 140 } else { 141 memcpy_b(ii->i_zone, i->u.minix.u.i2_zone, sizeof(i->u.minix.u.i2_zone)); 142 } 143 i->dirty = 0; 144 bwrite(buf); 145 return 0; 146 } 147 148 int v2_minix_ialloc(struct inode *i, int mode) 149 { 150 __blk_t offset; 151 int inode, errno; 152 struct superblock *sb; 153 154 sb = i->sb; 155 superblock_lock(sb); 156 157 offset = 1 + SUPERBLOCK; 158 159 if(!(inode = minix_find_first_zero(sb, offset, sb->u.minix.sb.s_ninodes, offset + sb->u.minix.sb.s_imap_blocks))) { 160 superblock_unlock(sb); 161 return -ENOSPC; 162 } 163 164 errno = minix_change_bit(SET_BIT, sb, offset, inode); 165 166 if(errno) { 167 if(errno < 0) { 168 printk("WARNING: %s(): unable to set inode %d.\n", __FUNCTION__, inode); 169 superblock_unlock(sb); 170 return errno; 171 } else { 172 printk("WARNING: %s(): inode %d is already marked as used!\n", __FUNCTION__, inode); 173 } 174 } 175 176 i->inode = inode; 177 i->i_atime = CURRENT_TIME; 178 i->i_mtime = CURRENT_TIME; 179 i->i_ctime = CURRENT_TIME; 180 superblock_unlock(sb); 181 return 0; 182 } 183 184 void v2_minix_ifree(struct inode *i) 185 { 186 int errno; 187 struct superblock *sb; 188 189 minix_truncate(i, 0); 190 191 sb = i->sb; 192 superblock_lock(sb); 193 194 errno = minix_change_bit(CLEAR_BIT, i->sb, 1 + SUPERBLOCK, i->inode); 195 196 if(errno) { 197 if(errno < 0) { 198 printk("WARNING: %s(): unable to clear inode %d.\n", __FUNCTION__, i->inode); 199 } else { 200 printk("WARNING: %s(): inode %d is already marked as free!\n", __FUNCTION__, i->inode); 201 } 202 } 203 204 i->i_size = 0; 205 i->i_mtime = CURRENT_TIME; 206 i->i_ctime = CURRENT_TIME; 207 i->dirty = 1; 208 superblock_unlock(sb); 209 } 210 211 int v2_minix_bmap(struct inode *i, __off_t offset, int mode) 212 { 213 unsigned char level; 214 __u32 *indblock, *dindblock, *tindblock; 215 __blk_t block, iblock, dblock, tblock, newblock; 216 int blksize; 217 struct buffer *buf, *buf2, *buf3, *buf4; 218 219 blksize = i->sb->s_blocksize; 220 block = offset / blksize; 221 level = 0; 222 buf3 = NULL; /* makes GCC happy */ 223 224 if(block < MINIX_NDIR_BLOCKS) { 225 level = MINIX_NDIR_BLOCKS - 1; 226 } else { 227 if(block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) { 228 level = MINIX_IND_BLOCK; 229 } else if(block < ((BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)) + BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) { 230 level = MINIX_DIND_BLOCK; 231 } else { 232 level = MINIX_TIND_BLOCK; 233 } 234 block -= MINIX_NDIR_BLOCKS; 235 } 236 237 if(level < MINIX_NDIR_BLOCKS) { 238 if(!i->u.minix.u.i2_zone[block] && mode == FOR_WRITING) { 239 if((newblock = minix_balloc(i->sb)) < 0) { 240 return -ENOSPC; 241 } 242 /* initialize the new block */ 243 if(!(buf = bread(i->dev, newblock, blksize))) { 244 minix_bfree(i->sb, newblock); 245 return -EIO; 246 } 247 memset_b(buf->data, 0, blksize); 248 bwrite(buf); 249 i->u.minix.u.i2_zone[block] = newblock; 250 } 251 return i->u.minix.u.i2_zone[block]; 252 } 253 254 if(!i->u.minix.u.i2_zone[level]) { 255 if(mode == FOR_WRITING) { 256 if((newblock = minix_balloc(i->sb)) < 0) { 257 return -ENOSPC; 258 } 259 /* initialize the new block */ 260 if(!(buf = bread(i->dev, newblock, blksize))) { 261 minix_bfree(i->sb, newblock); 262 return -EIO; 263 } 264 memset_b(buf->data, 0, blksize); 265 bwrite(buf); 266 i->u.minix.u.i2_zone[level] = newblock; 267 } else { 268 return 0; 269 } 270 } 271 if(!(buf = bread(i->dev, i->u.minix.u.i2_zone[level], blksize))) { 272 return -EIO; 273 } 274 indblock = (__u32 *)buf->data; 275 dblock = block - BLOCKS_PER_IND_BLOCK(i->sb); 276 tblock = block - (BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)) - BLOCKS_PER_IND_BLOCK(i->sb); 277 278 if(level == MINIX_DIND_BLOCK) { 279 block = dblock / BLOCKS_PER_IND_BLOCK(i->sb); 280 } 281 if(level == MINIX_TIND_BLOCK) { 282 block = tblock / (BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)); 283 } 284 285 if(!indblock[block]) { 286 if(mode == FOR_WRITING) { 287 if((newblock = minix_balloc(i->sb)) < 0) { 288 brelse(buf); 289 return -ENOSPC; 290 } 291 /* initialize the new block */ 292 if(!(buf2 = bread(i->dev, newblock, blksize))) { 293 minix_bfree(i->sb, newblock); 294 brelse(buf); 295 return -EIO; 296 } 297 memset_b(buf2->data, 0, blksize); 298 bwrite(buf2); 299 indblock[block] = newblock; 300 if(level == MINIX_IND_BLOCK) { 301 bwrite(buf); 302 return newblock; 303 } 304 buf->flags |= (BUFFER_DIRTY | BUFFER_VALID); 305 } else { 306 brelse(buf); 307 return 0; 308 } 309 } 310 if(level == MINIX_IND_BLOCK) { 311 newblock = indblock[block]; 312 brelse(buf); 313 return newblock; 314 } 315 316 if(level == MINIX_TIND_BLOCK) { 317 if(!(buf3 = bread(i->dev, indblock[block], blksize))) { 318 printk("%s(): returning -EIO\n", __FUNCTION__); 319 brelse(buf); 320 return -EIO; 321 } 322 tindblock = (__u32 *)buf3->data; 323 block = tindblock[tblock / BLOCKS_PER_IND_BLOCK(i->sb)]; 324 if(!block) { 325 if(mode == FOR_WRITING) { 326 if((newblock = minix_balloc(i->sb)) < 0) { 327 brelse(buf); 328 brelse(buf3); 329 return -ENOSPC; 330 } 331 /* initialize the new block */ 332 if(!(buf4 = bread(i->dev, newblock, blksize))) { 333 minix_bfree(i->sb, newblock); 334 brelse(buf); 335 brelse(buf3); 336 return -EIO; 337 } 338 memset_b(buf4->data, 0, blksize); 339 bwrite(buf4); 340 tindblock[tblock / BLOCKS_PER_IND_BLOCK(i->sb)] = newblock; 341 buf3->flags |= (BUFFER_DIRTY | BUFFER_VALID); 342 block = newblock; 343 } else { 344 brelse(buf); 345 brelse(buf3); 346 return 0; 347 } 348 } 349 dblock = tblock; 350 iblock = tblock / BLOCKS_PER_IND_BLOCK(i->sb); 351 if(!(buf2 = bread(i->dev, block, blksize))) { 352 printk("%s(): returning -EIO\n", __FUNCTION__); 353 brelse(buf); 354 brelse(buf3); 355 return -EIO; 356 } 357 } else { 358 iblock = block; 359 if(!(buf2 = bread(i->dev, indblock[iblock], blksize))) { 360 printk("%s(): returning -EIO\n", __FUNCTION__); 361 brelse(buf); 362 return -EIO; 363 } 364 } 365 366 dindblock = (__u32 *)buf2->data; 367 block = dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))]; 368 if(!block && mode == FOR_WRITING) { 369 if((newblock = minix_balloc(i->sb)) < 0) { 370 brelse(buf); 371 if(level == MINIX_TIND_BLOCK) { 372 brelse(buf3); 373 } 374 brelse(buf2); 375 return -ENOSPC; 376 } 377 /* initialize the new block */ 378 if(!(buf4 = bread(i->dev, newblock, blksize))) { 379 minix_bfree(i->sb, newblock); 380 brelse(buf); 381 if(level == MINIX_TIND_BLOCK) { 382 brelse(buf3); 383 } 384 brelse(buf2); 385 return -EIO; 386 } 387 memset_b(buf4->data, 0, blksize); 388 bwrite(buf4); 389 dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))] = newblock; 390 buf2->flags |= (BUFFER_DIRTY | BUFFER_VALID); 391 block = newblock; 392 } 393 brelse(buf); 394 if(level == MINIX_TIND_BLOCK) { 395 brelse(buf3); 396 } 397 brelse(buf2); 398 return block; 399 } 400 401 int v2_minix_truncate(struct inode *i, __off_t length) 402 { 403 int n; 404 __blk_t block, dblock; 405 __u32 *zone; 406 struct buffer *buf; 407 408 block = length / i->sb->s_blocksize; 409 410 if(!S_ISDIR(i->i_mode) && !S_ISREG(i->i_mode) && !S_ISLNK(i->i_mode)) { 411 return -EINVAL; 412 } 413 414 if(block < MINIX_NDIR_BLOCKS) { 415 for(n = block; n < MINIX_NDIR_BLOCKS; n++) { 416 if(i->u.minix.u.i2_zone[n]) { 417 minix_bfree(i->sb, i->u.minix.u.i2_zone[n]); 418 i->u.minix.u.i2_zone[n] = 0; 419 } 420 } 421 block = 0; 422 } 423 424 if(!block || block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) { 425 if(block) { 426 block -= MINIX_NDIR_BLOCKS; 427 } 428 if(i->u.minix.u.i2_zone[MINIX_IND_BLOCK]) { 429 free_zone(i, i->u.minix.u.i2_zone[MINIX_IND_BLOCK], block); 430 if(!block) { 431 minix_bfree(i->sb, i->u.minix.u.i2_zone[MINIX_IND_BLOCK]); 432 i->u.minix.u.i2_zone[MINIX_IND_BLOCK] = 0; 433 } 434 } 435 block = 0; 436 } 437 438 if(block) { 439 block -= MINIX_NDIR_BLOCKS; 440 block -= BLOCKS_PER_IND_BLOCK(i->sb); 441 } 442 if(i->u.minix.u.i2_zone[MINIX_DIND_BLOCK]) { 443 if(!(buf = bread(i->dev, i->u.minix.u.i2_zone[MINIX_DIND_BLOCK], i->sb->s_blocksize))) { 444 printk("%s(): error reading block %d.\n", __FUNCTION__, i->u.minix.u.i2_zone[MINIX_DIND_BLOCK]); 445 } 446 zone = (__u32 *)buf->data; 447 dblock = block % BLOCKS_PER_IND_BLOCK(i->sb); 448 for(n = block / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) { 449 if(zone[n]) { 450 free_zone(i, zone[n], dblock); 451 if(!dblock) { 452 minix_bfree(i->sb, zone[n]); 453 } 454 } 455 dblock = 0; 456 } 457 bwrite(buf); 458 if(!block) { 459 minix_bfree(i->sb, i->u.minix.u.i2_zone[MINIX_DIND_BLOCK]); 460 i->u.minix.u.i2_zone[MINIX_DIND_BLOCK] = 0; 461 } 462 } 463 464 i->i_mtime = CURRENT_TIME; 465 i->i_ctime = CURRENT_TIME; 466 i->i_size = length; 467 i->dirty = 1; 468 469 return 0; 470 }