xref: /minix/minix/fs/ext2/mount.c (revision 9f988b79)
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