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, major(fs_dev)); 92 93 /* Get the root inode of the mounted file system. */ 94 if ( (root_ip = get_inode(fs_dev, ROOT_INODE)) == NULL) { 95 printf("ext2: couldn't get root inode\n"); 96 superblock->s_dev = NO_DEV; 97 bdev_close(fs_dev); 98 return(EINVAL); 99 } 100 101 if (root_ip != NULL && root_ip->i_mode == 0) { 102 printf("%s:%d zero mode for root inode?\n", __FILE__, __LINE__); 103 put_inode(root_ip); 104 superblock->s_dev = NO_DEV; 105 bdev_close(fs_dev); 106 return(EINVAL); 107 } 108 109 if (root_ip != NULL && (root_ip->i_mode & I_TYPE) != I_DIRECTORY) { 110 printf("%s:%d root inode has wrong type, it's not a DIR\n", 111 __FILE__, __LINE__); 112 put_inode(root_ip); 113 superblock->s_dev = NO_DEV; 114 bdev_close(fs_dev); 115 return(EINVAL); 116 } 117 118 superblock->s_rd_only = readonly; 119 120 if (!readonly) { 121 superblock->s_state = EXT2_ERROR_FS; 122 superblock->s_mnt_count++; 123 superblock->s_mtime = clock_time(NULL); 124 write_super(superblock); /* Commit info, we just set above */ 125 } 126 127 /* Root inode properties */ 128 root_node->fn_ino_nr = root_ip->i_num; 129 root_node->fn_mode = root_ip->i_mode; 130 root_node->fn_size = root_ip->i_size; 131 root_node->fn_uid = root_ip->i_uid; 132 root_node->fn_gid = root_ip->i_gid; 133 root_node->fn_dev = NO_DEV; 134 135 *res_flags = RES_NOFLAGS; 136 137 return(r); 138 } 139 140 141 /*===========================================================================* 142 * fs_mountpt * 143 *===========================================================================*/ 144 int fs_mountpt(ino_t ino_nr) 145 { 146 /* This function looks up the mount point, it checks the condition whether 147 * the partition can be mounted on the inode or not. 148 */ 149 register struct inode *rip; 150 int r = OK; 151 mode_t bits; 152 153 /* Temporarily open the file. */ 154 if( (rip = get_inode(fs_dev, ino_nr)) == NULL) 155 return(EINVAL); 156 157 if(rip->i_mountpoint) r = EBUSY; 158 159 /* It may not be special. */ 160 bits = rip->i_mode & I_TYPE; 161 if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; 162 163 put_inode(rip); 164 165 if(r == OK) rip->i_mountpoint = TRUE; 166 167 return(r); 168 } 169 170 171 /*===========================================================================* 172 * fs_unmount * 173 *===========================================================================*/ 174 void fs_unmount(void) 175 { 176 /* Unmount a file system by device number. */ 177 int count; 178 struct inode *rip, *root_ip; 179 180 /* See if the mounted device is busy. Only 1 inode using it should be 181 * open --the root inode-- and that inode only 1 time. This is an integrity 182 * check only: VFS expects the unmount to succeed either way. 183 */ 184 count = 0; 185 for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) 186 if (rip->i_count > 0 && rip->i_dev == fs_dev) count += rip->i_count; 187 if (count != 1) 188 printf("ext2: file system has %d in-use inodes!\n", count); 189 190 if ((root_ip = find_inode(fs_dev, ROOT_INODE)) == NULL) 191 panic("ext2: couldn't find root inode"); 192 193 /* Sync fs data before checking count. In some cases VFS can force unmounting 194 * and it will damage unsynced FS. We don't sync before checking root_ip since 195 * if it is missing then something strange happened with FS, so it's better 196 * to not use possibly corrupted data for syncing. 197 */ 198 if (!superblock->s_rd_only) { 199 /* force any cached blocks out of memory */ 200 fs_sync(); 201 } 202 203 put_inode(root_ip); 204 205 if (!superblock->s_rd_only) { 206 superblock->s_wtime = clock_time(NULL); 207 superblock->s_state = EXT2_VALID_FS; 208 write_super(superblock); /* Commit info, we just set above */ 209 } 210 211 /* Close the device the file system lives on. */ 212 bdev_close(fs_dev); 213 214 /* Throw all blocks out of the VM cache, to prevent corruption later. */ 215 lmfs_invalidate(fs_dev); 216 217 /* Finish off the unmount. */ 218 superblock->s_dev = NO_DEV; 219 } 220