Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/ext2/super.c 3 * 4 * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved. 5 * Distributed under the terms of the Fiwix License. 6 */ 7 8 #include <fiwix/kernel.h> 9 #include <fiwix/types.h> 10 #include <fiwix/errno.h> 11 #include <fiwix/fs.h> 12 #include <fiwix/filesystems.h> 13 #include <fiwix/fs_ext2.h> 14 #include <fiwix/buffer.h> 15 #include <fiwix/sched.h> 16 #include <fiwix/stdio.h> 17 #include <fiwix/string.h> 18 19 struct fs_operations ext2_fsop = { 20 FSOP_REQUIRES_DEV, 21 NULL, 22 23 NULL, /* open */ 24 NULL, /* close */ 25 NULL, /* read */ 26 NULL, /* write */ 27 NULL, /* ioctl */ 28 NULL, /* lseek */ 29 NULL, /* readdir */ 30 NULL, /* mmap */ 31 NULL, /* select */ 32 33 NULL, /* readlink */ 34 NULL, /* followlink */ 35 NULL, /* bmap */ 36 NULL, /* lookup */ 37 NULL, /* rmdir */ 38 NULL, /* link */ 39 NULL, /* unlink */ 40 NULL, /* symlink */ 41 NULL, /* mkdir */ 42 NULL, /* mknod */ 43 NULL, /* truncate */ 44 NULL, /* create */ 45 NULL, /* rename */ 46 47 NULL, /* read_block */ 48 NULL, /* write_block */ 49 50 ext2_read_inode, 51 ext2_write_inode, 52 ext2_ialloc, 53 ext2_ifree, 54 ext2_statfs, 55 ext2_read_superblock, 56 ext2_remount_fs, 57 ext2_write_superblock, 58 ext2_release_superblock 59 }; 60 61 static void check_superblock(struct ext2_super_block *sb) 62 { 63 if(!(sb->s_state & EXT2_VALID_FS)) { 64 printk("WARNING: filesystem unchecked, fsck recommended.\n"); 65 } else if((sb->s_state & EXT2_ERROR_FS)) { 66 printk("WARNING: filesystem contains errors, fsck recommended.\n"); 67 } else if(sb->s_max_mnt_count >= 0 && sb->s_mnt_count >= (unsigned short int)sb->s_max_mnt_count) { 68 printk("WARNING: maximal mount count reached, fsck recommended.\n"); 69 } else if(sb->s_checkinterval && (sb->s_lastcheck + sb->s_checkinterval <= CURRENT_TIME)) { 70 printk("WARNING: checktime reached, fsck recommended.\n"); 71 } 72 } 73 74 void ext2_statfs(struct superblock *sb, struct statfs *statfsbuf) 75 { 76 statfsbuf->f_type = EXT2_SUPER_MAGIC; 77 statfsbuf->f_bsize = sb->s_blocksize; 78 statfsbuf->f_blocks = sb->u.ext2.sb.s_blocks_count; 79 statfsbuf->f_bfree = sb->u.ext2.sb.s_free_blocks_count; 80 if(statfsbuf->f_bfree >= sb->u.ext2.sb.s_r_blocks_count) { 81 statfsbuf->f_bavail = statfsbuf->f_bfree - sb->u.ext2.sb.s_r_blocks_count; 82 } else { 83 statfsbuf->f_bavail = 0; 84 } 85 statfsbuf->f_files = sb->u.ext2.sb.s_inodes_count; 86 statfsbuf->f_ffree = sb->u.ext2.sb.s_free_inodes_count; 87 /* statfsbuf->f_fsid = ? */ 88 statfsbuf->f_namelen = EXT2_NAME_LEN; 89 } 90 91 int ext2_read_superblock(__dev_t dev, struct superblock *sb) 92 { 93 struct buffer *buf; 94 struct ext2_super_block *ext2sb; 95 96 superblock_lock(sb); 97 if(!(buf = bread(dev, SUPERBLOCK, BLKSIZE_1K))) { 98 printk("WARNING: %s(): I/O error on device %d,%d.\n", __FUNCTION__, MAJOR(dev), MINOR(dev)); 99 superblock_unlock(sb); 100 return -EIO; 101 } 102 103 ext2sb = (struct ext2_super_block *)buf->data; 104 if(ext2sb->s_magic != EXT2_SUPER_MAGIC) { 105 printk("WARNING: %s(): invalid filesystem type or bad superblock on device %d,%d.\n", __FUNCTION__, MAJOR(dev), MINOR(dev)); 106 superblock_unlock(sb); 107 brelse(buf); 108 return -EINVAL; 109 } 110 111 if(ext2sb->s_minor_rev_level || ext2sb->s_rev_level) { 112 printk("WARNING: %s(): unsupported ext2 filesystem revision.\n", __FUNCTION__); 113 printk("Only revision 0 (original without features) is supported.\n"); 114 superblock_unlock(sb); 115 brelse(buf); 116 return -EINVAL; 117 } 118 119 sb->dev = dev; 120 sb->fsop = &ext2_fsop; 121 sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << ext2sb->s_log_block_size; 122 memcpy_b(&sb->u.ext2.sb, ext2sb, sizeof(struct ext2_super_block)); 123 EXT2_DESC_PER_BLOCK(sb) = sb->s_blocksize / sizeof(struct ext2_group_desc); 124 sb->u.ext2.block_groups = 1 + (ext2sb->s_blocks_count - 1) / ext2sb->s_blocks_per_group; 125 126 if(!(sb->root = iget(sb, EXT2_ROOT_INO))) { 127 printk("WARNING: %s(): unable to get root inode.\n", __FUNCTION__); 128 superblock_unlock(sb); 129 brelse(buf); 130 return -EINVAL; 131 } 132 133 check_superblock(ext2sb); 134 if(!(sb->flags & MS_RDONLY)) { 135 sb->u.ext2.sb.s_state &= ~EXT2_VALID_FS; 136 sb->u.ext2.sb.s_mnt_count++; 137 sb->u.ext2.sb.s_mtime = CURRENT_TIME; 138 memcpy_b(buf->data, &sb->u.ext2.sb, sizeof(struct ext2_super_block)); 139 bwrite(buf); 140 } else { 141 brelse(buf); 142 } 143 superblock_unlock(sb); 144 return 0; 145 } 146 147 int ext2_remount_fs(struct superblock *sb, int flags) 148 { 149 struct buffer *buf; 150 struct ext2_super_block *ext2sb; 151 152 if((flags & MS_RDONLY) == (sb->flags & MS_RDONLY)) { 153 return 0; 154 } 155 156 superblock_lock(sb); 157 if(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) { 158 superblock_unlock(sb); 159 return -EIO; 160 } 161 ext2sb = (struct ext2_super_block *)buf->data; 162 163 if(flags & MS_RDONLY) { 164 /* switching from RW to RO */ 165 sb->u.ext2.sb.s_state |= EXT2_VALID_FS; 166 ext2sb->s_state |= EXT2_VALID_FS; 167 } else { 168 /* switching from RO to RW */ 169 check_superblock(ext2sb); 170 memcpy_b(&sb->u.ext2.sb, ext2sb, sizeof(struct ext2_super_block)); 171 sb->u.ext2.sb.s_state &= ~EXT2_VALID_FS; 172 sb->u.ext2.sb.s_mnt_count++; 173 sb->u.ext2.sb.s_mtime = CURRENT_TIME; 174 ext2sb->s_state &= ~EXT2_VALID_FS; 175 } 176 177 sb->dirty = 1; 178 superblock_unlock(sb); 179 bwrite(buf); 180 return 0; 181 } 182 183 int ext2_write_superblock(struct superblock *sb) 184 { 185 struct buffer *buf; 186 187 superblock_lock(sb); 188 if(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) { 189 superblock_unlock(sb); 190 return -EIO; 191 } 192 193 memcpy_b(buf->data, &sb->u.ext2.sb, sizeof(struct ext2_super_block)); 194 sb->dirty = 0; 195 superblock_unlock(sb); 196 bwrite(buf); 197 return 0; 198 } 199 200 void ext2_release_superblock(struct superblock *sb) 201 { 202 if(sb->flags & MS_RDONLY) { 203 return; 204 } 205 206 superblock_lock(sb); 207 208 sb->u.ext2.sb.s_state |= EXT2_VALID_FS; 209 sb->dirty = 1; 210 211 superblock_unlock(sb); 212 } 213 214 int ext2_init(void) 215 { 216 return register_filesystem("ext2", &ext2_fsop); 217 }