source: trunk/minix/servers/fs/mount.c@ 22

Last change on this file since 22 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 9.5 KB
Line 
1/* This file performs the MOUNT and UMOUNT system calls.
2 *
3 * The entry points into this file are
4 * do_mount: perform the MOUNT system call
5 * do_umount: perform the UMOUNT system call
6 */
7
8#include "fs.h"
9#include <fcntl.h>
10#include <string.h>
11#include <minix/com.h>
12#include <sys/stat.h>
13#include "buf.h"
14#include "file.h"
15#include "fproc.h"
16#include "inode.h"
17#include "param.h"
18#include "super.h"
19
20/* Allow the root to be replaced before the first 'real' mount. */
21PRIVATE int allow_newroot= 1;
22
23FORWARD _PROTOTYPE( dev_t name_to_dev, (char *path) );
24
25/*===========================================================================*
26 * do_mount *
27 *===========================================================================*/
28PUBLIC int do_mount()
29{
30/* Perform the mount(name, mfile, rd_only) system call. */
31
32 register struct inode *rip, *root_ip;
33 struct super_block *xp, *sp;
34 dev_t dev;
35 mode_t bits;
36 int rdir, mdir; /* TRUE iff {root|mount} file is dir */
37 int i, r, found;
38 struct fproc *tfp;
39
40 /* Only the super-user may do MOUNT. */
41 if (!super_user) return(EPERM);
42
43 /* If 'name' is not for a block special file, return error. */
44 if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
45 if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
46
47 /* Scan super block table to see if dev already mounted & find a free slot.*/
48 sp = NIL_SUPER;
49 found = FALSE;
50 for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) {
51 if (xp->s_dev == dev)
52 {
53 /* is it mounted already? */
54 found = TRUE;
55 sp= xp;
56 break;
57 }
58 if (xp->s_dev == NO_DEV) sp = xp; /* record free slot */
59 }
60 if (found)
61 {
62 printf(
63"do_mount: s_imount = 0x%x (%x, %d), s_isup = 0x%x (%x, %d), fp_rootdir = 0x%x\n",
64 xp->s_imount, xp->s_imount->i_dev, xp->s_imount->i_num,
65 xp->s_isup, xp->s_isup->i_dev, xp->s_isup->i_num,
66 fproc[FS_PROC_NR].fp_rootdir);
67 /* It is possible that we have an old root lying around that
68 * needs to be remounted.
69 */
70 if (xp->s_imount != xp->s_isup ||
71 xp->s_isup == fproc[FS_PROC_NR].fp_rootdir)
72 {
73 /* Normally, s_imount refers to the mount point. For a root
74 * filesystem, s_imount is equal to the root inode. We assume
75 * that the root of FS is always the real root. If the two
76 * inodes are different or if the root of FS is equal two the
77 * root of the filesystem we found, we found a filesystem that
78 * is in use.
79 */
80 return(EBUSY); /* already mounted */
81 }
82
83 if (root_dev == xp->s_dev)
84 {
85 panic("fs", "inconsistency remounting old root",
86 NO_NUM);
87 }
88
89 /* Now get the inode of the file to be mounted on. */
90 if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
91 return(err_code);
92 }
93
94 if ( (rip = eat_path(user_path)) == NIL_INODE) {
95 return(err_code);
96 }
97
98 r = OK;
99
100 /* It may not be special. */
101 bits = rip->i_mode & I_TYPE;
102 if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL)
103 r = ENOTDIR;
104
105 /* Get the root inode of the mounted file system. */
106 root_ip= sp->s_isup;
107
108 /* File types of 'rip' and 'root_ip' may not conflict. */
109 if (r == OK) {
110 mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY);
111 /* TRUE iff dir */
112 rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
113 if (!mdir && rdir) r = EISDIR;
114 }
115
116 /* If error, return the mount point. */
117 if (r != OK) {
118 put_inode(rip);
119 return(r);
120 }
121
122 /* Nothing else can go wrong. Perform the mount. */
123 rip->i_mount = I_MOUNT; /* this bit says the inode is
124 * mounted on
125 */
126 put_inode(sp->s_imount);
127 sp->s_imount = rip;
128 sp->s_rd_only = m_in.rd_only;
129 allow_newroot= 0; /* The root is now fixed */
130 return(OK);
131 }
132 if (sp == NIL_SUPER) return(ENFILE); /* no super block available */
133
134 /* Open the device the file system lives on. */
135 if (dev_open(dev, who_e, m_in.rd_only ? R_BIT : (R_BIT|W_BIT)) != OK)
136 return(EINVAL);
137
138 /* Make the cache forget about blocks it has open on the filesystem */
139 (void) do_sync();
140 invalidate(dev);
141
142 /* Fill in the super block. */
143 sp->s_dev = dev; /* read_super() needs to know which dev */
144 r = read_super(sp);
145
146 /* Is it recognized as a Minix filesystem? */
147 if (r != OK) {
148 dev_close(dev);
149 sp->s_dev = NO_DEV;
150 return(r);
151 }
152
153 /* Now get the inode of the file to be mounted on. */
154 if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
155 dev_close(dev);
156 sp->s_dev = NO_DEV;
157 return(err_code);
158 }
159
160 if (strcmp(user_path, "/") == 0 && allow_newroot)
161 {
162 printf("Replacing root\n");
163
164 /* Get the root inode of the mounted file system. */
165 if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
166 if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
167 r = EINVAL;
168 }
169
170 /* If error, return the super block and both inodes; release the
171 * maps.
172 */
173 if (r != OK) {
174 put_inode(root_ip);
175 (void) do_sync();
176 invalidate(dev);
177 dev_close(dev);
178 sp->s_dev = NO_DEV;
179 return(r);
180 }
181
182 /* Nothing else can go wrong. Perform the mount. */
183 sp->s_imount = root_ip;
184 dup_inode(root_ip);
185 sp->s_isup = root_ip;
186 sp->s_rd_only = m_in.rd_only;
187 root_dev= dev;
188
189 /* Replace all root and working directories */
190 for (i= 0, tfp= fproc; i<NR_PROCS; i++, tfp++)
191 {
192 if (tfp->fp_pid == PID_FREE)
193 continue;
194 if (tfp->fp_rootdir == NULL)
195 panic("fs", "do_mount: null rootdir", i);
196 put_inode(tfp->fp_rootdir);
197 dup_inode(root_ip);
198 tfp->fp_rootdir= root_ip;
199
200 if (tfp->fp_workdir == NULL)
201 panic("fs", "do_mount: null workdir", i);
202 put_inode(tfp->fp_workdir);
203 dup_inode(root_ip);
204 tfp->fp_workdir= root_ip;
205 }
206
207 /* Leave the old filesystem lying around. */
208 return(OK);
209 }
210
211 if ( (rip = eat_path(user_path)) == NIL_INODE) {
212 dev_close(dev);
213 sp->s_dev = NO_DEV;
214 return(err_code);
215 }
216
217 /* It may not be busy. */
218 r = OK;
219 if (rip->i_count > 1) r = EBUSY;
220
221 /* It may not be special. */
222 bits = rip->i_mode & I_TYPE;
223 if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR;
224
225 /* Get the root inode of the mounted file system. */
226 root_ip = NIL_INODE; /* if 'r' not OK, make sure this is defined */
227 if (r == OK) {
228 if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
229 }
230 if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
231 r = EINVAL;
232 }
233
234 /* File types of 'rip' and 'root_ip' may not conflict. */
235 if (r == OK) {
236 mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */
237 rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
238 if (!mdir && rdir) r = EISDIR;
239 }
240
241 /* If error, return the super block and both inodes; release the maps. */
242 if (r != OK) {
243 put_inode(rip);
244 put_inode(root_ip);
245 (void) do_sync();
246 invalidate(dev);
247 dev_close(dev);
248 sp->s_dev = NO_DEV;
249 return(r);
250 }
251
252 /* Nothing else can go wrong. Perform the mount. */
253 rip->i_mount = I_MOUNT; /* this bit says the inode is mounted on */
254 sp->s_imount = rip;
255 sp->s_isup = root_ip;
256 sp->s_rd_only = m_in.rd_only;
257 allow_newroot= 0; /* The root is now fixed */
258 return(OK);
259}
260
261/*===========================================================================*
262 * do_umount *
263 *===========================================================================*/
264PUBLIC int do_umount()
265{
266/* Perform the umount(name) system call. */
267 dev_t dev;
268
269 /* Only the super-user may do UMOUNT. */
270 if (!super_user) return(EPERM);
271
272 /* If 'name' is not for a block special file, return error. */
273 if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
274 if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
275
276 return(unmount(dev));
277}
278
279/*===========================================================================*
280 * unmount *
281 *===========================================================================*/
282PUBLIC int unmount(dev)
283Dev_t dev;
284{
285/* Unmount a file system by device number. */
286 register struct inode *rip;
287 struct super_block *sp, *sp1;
288 int count;
289
290 /* See if the mounted device is busy. Only 1 inode using it should be
291 * open -- the root inode -- and that inode only 1 time.
292 */
293 count = 0;
294 for (rip = &inode[0]; rip< &inode[NR_INODES]; rip++)
295 if (rip->i_count > 0 && rip->i_dev == dev) count += rip->i_count;
296 if (count > 1) return(EBUSY); /* can't umount a busy file system */
297
298 /* Find the super block. */
299 sp = NIL_SUPER;
300 for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) {
301 if (sp1->s_dev == dev) {
302 sp = sp1;
303 break;
304 }
305 }
306
307 /* Sync the disk, and invalidate cache. */
308 (void) do_sync(); /* force any cached blocks out of memory */
309 invalidate(dev); /* invalidate cache entries for this dev */
310 if (sp == NIL_SUPER) {
311 return(EINVAL);
312 }
313
314 /* Close the device the file system lives on. */
315 dev_close(dev);
316
317 /* Finish off the unmount. */
318 sp->s_imount->i_mount = NO_MOUNT; /* inode returns to normal */
319 put_inode(sp->s_imount); /* release the inode mounted on */
320 put_inode(sp->s_isup); /* release the root inode of the mounted fs */
321 sp->s_imount = NIL_INODE;
322 sp->s_dev = NO_DEV;
323 return(OK);
324}
325
326/*===========================================================================*
327 * name_to_dev *
328 *===========================================================================*/
329PRIVATE dev_t name_to_dev(path)
330char *path; /* pointer to path name */
331{
332/* Convert the block special file 'path' to a device number. If 'path'
333 * is not a block special file, return error code in 'err_code'.
334 */
335
336 register struct inode *rip;
337 register dev_t dev;
338
339 /* If 'path' can't be opened, give up immediately. */
340 if ( (rip = eat_path(path)) == NIL_INODE) return(NO_DEV);
341
342 /* If 'path' is not a block special file, return error. */
343 if ( (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) {
344 err_code = ENOTBLK;
345 put_inode(rip);
346 return(NO_DEV);
347 }
348
349 /* Extract the device number. */
350 dev = (dev_t) rip->i_zone[0];
351 put_inode(rip);
352 return(dev);
353}
Note: See TracBrowser for help on using the repository browser.