Fork me on GitHub

root/fs/ext2/inode.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_group_desc
  2. ext2_read_inode
  3. ext2_write_inode
  4. ext2_bmap
  5. ext2_truncate

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

/* [previous][next][first][last][top][bottom][index][help] */