1 /* Created (MFS based): 2 * February 2010 (Evgeniy Ivanov) 3 */ 4 5 #include "fs.h" 6 #include "buf.h" 7 #include "inode.h" 8 #include "super.h" 9 #include <stdlib.h> 10 #include <minix/vfsif.h> 11 #include <minix/bdev.h> 12 13 14 /*===========================================================================* 15 * fs_mount * 16 *===========================================================================*/ 17 int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node, 18 unsigned int *res_flags) 19 { 20 /* This function reads the superblock of the partition, gets the root inode 21 * and sends back the details of them. 22 */ 23 struct inode *root_ip; 24 int r, readonly; 25 u32_t mask; 26 27 fs_dev = dev; 28 readonly = (flags & REQ_RDONLY) ? 1 : 0; 29 30 /* Open the device the file system lives on. */ 31 if (bdev_open(fs_dev, readonly ? BDEV_R_BIT : (BDEV_R_BIT|BDEV_W_BIT)) != 32 OK) { 33 return(EINVAL); 34 } 35 36 /* Fill in the super block. */ 37 if(!(superblock = malloc(sizeof(*superblock)))) 38 panic("Can't allocate memory for superblock."); 39 40 superblock->s_dev = fs_dev; /* read_super() needs to know which dev */ 41 r = read_super(superblock); 42 43 /* Is it recognized as a Minix filesystem? */ 44 if (r != OK) { 45 superblock->s_dev = NO_DEV; 46 bdev_close(fs_dev); 47 return(r); 48 } 49 50 if (superblock->s_rev_level != EXT2_GOOD_OLD_REV) { 51 struct super_block *sp = superblock; /* just shorter name */ 52 mask = ~SUPPORTED_INCOMPAT_FEATURES; 53 if (HAS_INCOMPAT_FEATURE(sp, mask)) { 54 if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_COMPRESSION & mask)) 55 printf("ext2: fs compression is not supported by server\n"); 56 if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_FILETYPE & mask)) 57 printf("ext2: fs in dir filetype is not supported by server\n"); 58 if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_RECOVER & mask)) 59 printf("ext2: fs recovery is not supported by server\n"); 60 if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_JOURNAL_DEV & mask)) 61 printf("ext2: fs journal dev is not supported by server\n"); 62 if (HAS_INCOMPAT_FEATURE(sp, INCOMPAT_META_BG & mask)) 63 printf("ext2: fs meta bg is not supported by server\n"); 64 return(EINVAL); 65 } 66 mask = ~SUPPORTED_RO_COMPAT_FEATURES; 67 if (HAS_RO_COMPAT_FEATURE(sp, mask)) { 68 if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_SPARSE_SUPER & mask)) { 69 printf("ext2: sparse super is not supported by server, \ 70 remount read-only\n"); 71 } 72 if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_LARGE_FILE & mask)) { 73 printf("ext2: large files are not supported by server, \ 74 remount read-only\n"); 75 } 76 if (HAS_RO_COMPAT_FEATURE(sp, RO_COMPAT_BTREE_DIR & mask)) { 77 printf("ext2: dir's btree is not supported by server, \ 78 remount read-only\n"); 79 } 80 return(EINVAL); 81 } 82 } 83 84 if (superblock->s_state == EXT2_ERROR_FS) { 85 printf("ext2: filesystem wasn't cleanly unmounted last time\n"); 86 superblock->s_dev = NO_DEV; 87 bdev_close(fs_dev); 88 return(EINVAL); 89 } 90 91 lmfs_set_blocksize(superblock->s_block_size); 92 lmfs_set_blockusage(superblock->s_blocks_count, 93 superblock->s_blocks_count - superblock->s_free_blocks_count); 94 95 /* Get the root inode of the mounted file system. */ 96 if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { 97 printf("ext2: couldn't get root inode\n"); 98 superblock->s_dev = NO_DEV; 99 bdev_close(fs_dev); 100 return(EINVAL); 101 } 102 103 if (root_ip != NULL && root_ip->i_mode == 0) { 104 printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); 105 put_inode(root_ip); 106 superblock->s_dev = NO_DEV; 107 bdev_close(fs_dev); 108 return(EINVAL); 109 } 110 111 if (root_ip != NULL && (root_ip->i_mode & I_TYPE) != I_DIRECTORY) { 112 printf("%s:%d root inode has wrong type, it's not a DIR\n", 113 __FILE__, __LINE__); 114 put_inode(root_ip); 115 superblock->s_dev = NO_DEV; 116 bdev_close(fs_dev); 117 return(EINVAL); 118 } 119 120 superblock->s_rd_only = readonly; 121 122 if (!readonly) { 123 superblock->s_state = EXT2_ERROR_FS; 124 superblock->s_mnt_count++; 125 superblock->s_mtime = clock_time(NULL); 126 write_super(superblock); /* Commit info, we just set above */ 127 } 128 129 /* Root inode properties */ 130 root_node->fn_ino_nr = root_ip->i_num; 131 root_node->fn_mode = root_ip->i_mode; 132 root_node->fn_size = root_ip->i_size; 133 root_node->fn_uid = root_ip->i_uid; 134 root_node->fn_gid = root_ip->i_gid; 135 root_node->fn_dev = NO_DEV; 136 137 *res_flags = RES_NOFLAGS; 138 139 return(r); 140 } 141 142 143 /*===========================================================================* 144 * fs_mountpt * 145 *===========================================================================*/ 146 int fs_mountpt(ino_t ino_nr) 147 { 148 /* This function looks up the mount point, it checks the condition whether 149 * the partition can be mounted on the inode or not. 150 */ 151 register struct inode *rip; 152 int r = OK; 153 mode_t bits; 154 155 /* Temporarily open the file. */ 156 if( (rip = get_inode(fs_dev, ino_nr)) == NULL) 157 return(EINVAL); 158 159 if(rip->i_mountpoint) r = EBUSY; 160 161 /* It may not be special. */ 162 bits = rip->i_mode & I_TYPE; 163 if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; 164 165 put_inode(rip); 166 167 if(r == OK) rip->i_mountpoint = TRUE; 168 169 return(r); 170 } 171 172 173 /*===========================================================================* 174 * fs_unmount * 175 *===========================================================================*/ 176 void fs_unmount(void) 177 { 178 /* Unmount a file system by device number. */ 179 int count; 180 struct inode *rip, *root_ip; 181 182 /* See if the mounted device is busy. Only 1 inode using it should be 183 * open --the root inode-- and that inode only 1 time. This is an integrity 184 * check only: VFS expects the unmount to succeed either way. 185 */ 186 count = 0; 187 for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) 188 if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count; 189 if (count != 1) 190 printf("ext2: file system has %d in-use inodes!\n", count); 191 192 if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL) 193 panic("ext2: couldn't find root inode"); 194 195 /* Sync fs data before checking count. In some cases VFS can force unmounting 196 * and it will damage unsynced FS. We don't sync before checking root_ip since 197 * if it is missing then something strange happened with FS, so it's better 198 * to not use possibly corrupted data for syncing. 199 */ 200 if (!superblock->s_rd_only) { 201 /* force any cached blocks out of memory */ 202 fs_sync(); 203 } 204 205 put_inode(root_ip); 206 207 if (!superblock->s_rd_only) { 208 superblock->s_wtime = clock_time(NULL); 209 superblock->s_state = EXT2_VALID_FS; 210 write_super(superblock); /* Commit info, we just set above */ 211 } 212 213 /* Close the device the file system lives on. */ 214 bdev_close(fs_dev); 215 216 /* Throw all blocks out of the VM cache, to prevent corruption later. */ 217 lmfs_invalidate(fs_dev); 218 219 /* Finish off the unmount. */ 220 superblock->s_dev = NO_DEV; 221 } 222