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