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