Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
1 /* 2 * fiwix/fs/minix/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_minix.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 minix_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 minix_read_inode, 51 minix_write_inode, 52 minix_ialloc, 53 minix_ifree, 54 minix_statfs, 55 minix_read_superblock, 56 minix_remount_fs, 57 minix_write_superblock, 58 minix_release_superblock 59 }; 60 61 static void check_superblock(struct minix_super_block *sb) 62 { 63 if(!(sb->s_state & MINIX_VALID_FS)) { 64 printk("WARNING: filesystem not checked, fsck recommended.\n"); 65 } 66 if(sb->s_state & MINIX_ERROR_FS) { 67 printk("WARNING: filesystem contains errors, fsck recommended.\n"); 68 } 69 } 70 71 void minix_statfs(struct superblock *sb, struct statfs *statfsbuf) 72 { 73 statfsbuf->f_type = sb->u.minix.sb.s_magic; 74 statfsbuf->f_bsize = sb->s_blocksize; 75 statfsbuf->f_blocks = sb->u.minix.nzones << sb->u.minix.sb.s_log_zone_size; 76 statfsbuf->f_bfree = sb->u.minix.nzones - minix_count_free_blocks(sb); 77 statfsbuf->f_bavail = statfsbuf->f_bfree; 78 79 statfsbuf->f_files = sb->u.minix.sb.s_ninodes; 80 statfsbuf->f_ffree = sb->u.minix.sb.s_ninodes - minix_count_free_inodes(sb); 81 /* statfsbuf->f_fsid = ? */ 82 statfsbuf->f_namelen = sb->u.minix.namelen; 83 } 84 85 int minix_read_superblock(__dev_t dev, struct superblock *sb) 86 { 87 struct buffer *buf; 88 int maps; 89 90 superblock_lock(sb); 91 if(!(buf = bread(dev, SUPERBLOCK, BLKSIZE_1K))) { 92 printk("WARNING: %s(): I/O error on device %d,%d.\n", __FUNCTION__, MAJOR(dev), MINOR(dev)); 93 superblock_unlock(sb); 94 return -EIO; 95 } 96 memcpy_b(&sb->u.minix.sb, buf->data, sizeof(struct minix_super_block)); 97 98 switch(sb->u.minix.sb.s_magic) { 99 case MINIX_SUPER_MAGIC: 100 sb->u.minix.namelen = 14; 101 sb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen; 102 sb->u.minix.version = 1; 103 sb->u.minix.nzones = sb->u.minix.sb.s_nzones; 104 printk("minix v1 (14 char names) filesystem detected on device %d,%d.\n", MAJOR(dev), MINOR(dev)); 105 break; 106 case MINIX_SUPER_MAGIC2: 107 sb->u.minix.namelen = 30; 108 sb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen; 109 sb->u.minix.version = 1; 110 sb->u.minix.nzones = sb->u.minix.sb.s_nzones; 111 printk("minix v1 (30 char names) filesystem detected on device %d,%d.\n", MAJOR(dev), MINOR(dev)); 112 break; 113 case MINIX2_SUPER_MAGIC: 114 sb->u.minix.namelen = 14; 115 sb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen; 116 sb->u.minix.version = 2; 117 sb->u.minix.nzones = sb->u.minix.sb.s_zones; 118 printk("minix v2 (14 char names) filesystem detected on device %d,%d.\n", MAJOR(dev), MINOR(dev)); 119 break; 120 case MINIX2_SUPER_MAGIC2: 121 sb->u.minix.namelen = 30; 122 sb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen; 123 sb->u.minix.version = 2; 124 sb->u.minix.nzones = sb->u.minix.sb.s_zones; 125 printk("minix v2 (30 char names) filesystem detected on device %d,%d.\n", MAJOR(dev), MINOR(dev)); 126 break; 127 default: 128 printk("ERROR: %s(): invalid filesystem type or bad superblock on device %d,%d.\n", __FUNCTION__, MAJOR(dev), MINOR(dev)); 129 superblock_unlock(sb); 130 brelse(buf); 131 return -EINVAL; 132 } 133 134 sb->dev = dev; 135 sb->fsop = &minix_fsop; 136 sb->s_blocksize = BLKSIZE_1K << sb->u.minix.sb.s_log_zone_size; 137 138 if(sb->s_blocksize != BLKSIZE_1K) { 139 printk("ERROR: %s(): block sizes > %d not supported in this filesystem.\n", __FUNCTION__, BLKSIZE_1K); 140 superblock_unlock(sb); 141 brelse(buf); 142 return -EINVAL; 143 } 144 145 /* 146 printk("s_ninodes = %d\n", sb->u.minix.sb.s_ninodes); 147 printk("s_nzones = %d (nzones = %d)\n", sb->u.minix.sb.s_nzones, sb->u.minix.nzones); 148 printk("s_imap_blocks = %d\n", sb->u.minix.sb.s_imap_blocks); 149 printk("s_zmap_blocks = %d\n", sb->u.minix.sb.s_zmap_blocks); 150 printk("s_firstdatazone = %d\n", sb->u.minix.sb.s_firstdatazone); 151 printk("s_log_zone_size = %d\n", sb->u.minix.sb.s_log_zone_size); 152 printk("s_max_size = %d\n", sb->u.minix.sb.s_max_size); 153 printk("s_magic = %x\n", sb->u.minix.sb.s_magic); 154 printk("s_state = %d\n", sb->u.minix.sb.s_state); 155 printk("s_zones = %d\n", sb->u.minix.sb.s_zones); 156 */ 157 158 /* Minix fs size is limited to: # of bitmaps * 8192 * 1024 */ 159 if(sb->u.minix.version == 1) { 160 maps = V1_MAX_BITMAP_BLOCKS; /* 64MB limit */ 161 } 162 if(sb->u.minix.version == 2) { 163 maps = V2_MAX_BITMAP_BLOCKS; /* 1GB limit */ 164 } 165 166 if(sb->u.minix.sb.s_imap_blocks > maps) { 167 printk("ERROR: %s(): number of imap blocks (%d) is greater than %d!\n", __FUNCTION__, sb->u.minix.sb.s_imap_blocks, maps); 168 superblock_unlock(sb); 169 brelse(buf); 170 return -EINVAL; 171 } 172 if(sb->u.minix.sb.s_zmap_blocks > maps) { 173 printk("ERROR: %s(): number of zmap blocks (%d) is greater than %d!\n", __FUNCTION__, sb->u.minix.sb.s_zmap_blocks, maps); 174 superblock_unlock(sb); 175 brelse(buf); 176 return -EINVAL; 177 } 178 179 superblock_unlock(sb); 180 181 if(!(sb->root = iget(sb, MINIX_ROOT_INO))) { 182 printk("ERROR: %s(): unable to get root inode.\n", __FUNCTION__); 183 brelse(buf); 184 return -EINVAL; 185 } 186 187 check_superblock(&sb->u.minix.sb); 188 189 if(!(sb->flags & MS_RDONLY)) { 190 sb->u.minix.sb.s_state &= ~MINIX_VALID_FS; 191 memcpy_b(buf->data, &sb->u.minix.sb, sizeof(struct minix_super_block)); 192 bwrite(buf); 193 } else { 194 brelse(buf); 195 } 196 197 return 0; 198 } 199 200 int minix_remount_fs(struct superblock *sb, int flags) 201 { 202 struct buffer *buf; 203 struct minix_super_block *minixsb; 204 205 if((flags & MS_RDONLY) == (sb->flags & MS_RDONLY)) { 206 return 0; 207 } 208 209 superblock_lock(sb); 210 if(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) { 211 superblock_unlock(sb); 212 return -EIO; 213 } 214 minixsb = (struct minix_super_block *)buf->data; 215 216 if(flags & MS_RDONLY) { 217 /* switching from RW to RO */ 218 sb->u.minix.sb.s_state |= MINIX_VALID_FS; 219 minixsb->s_state |= MINIX_VALID_FS; 220 } else { 221 /* switching from RO to RW */ 222 check_superblock(minixsb); 223 memcpy_b(&sb->u.minix.sb, minixsb, sizeof(struct minix_super_block)); 224 sb->u.minix.sb.s_state &= ~MINIX_VALID_FS; 225 minixsb->s_state &= ~MINIX_VALID_FS; 226 } 227 228 sb->dirty = 1; 229 superblock_unlock(sb); 230 bwrite(buf); 231 return 0; 232 } 233 234 int minix_write_superblock(struct superblock *sb) 235 { 236 struct buffer *buf; 237 238 superblock_lock(sb); 239 if(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) { 240 superblock_unlock(sb); 241 return -EIO; 242 } 243 244 memcpy_b(buf->data, &sb->u.minix.sb, sizeof(struct minix_super_block)); 245 sb->dirty = 0; 246 superblock_unlock(sb); 247 bwrite(buf); 248 return 0; 249 } 250 251 void minix_release_superblock(struct superblock *sb) 252 { 253 if(sb->flags & MS_RDONLY) { 254 return; 255 } 256 257 superblock_lock(sb); 258 259 sb->u.minix.sb.s_state |= MINIX_VALID_FS; 260 sb->dirty = 1; 261 262 superblock_unlock(sb); 263 } 264 265 int minix_init(void) 266 { 267 return register_filesystem("minix", &minix_fsop); 268 }