1 /* This file performs the MOUNT and UMOUNT system calls.
3 * The entry points into this file are
4 * do_fsready: perform the FS_READY system call
5 * do_mount: perform the MOUNT system call
6 * do_umount: perform the UMOUNT system call
7 * unmount: unmount a file system
13 #include <minix/callnr.h>
14 #include <minix/com.h>
15 #include <minix/keymap.h>
16 #include <minix/const.h>
17 #include <minix/endpoint.h>
18 #include <minix/syslib.h>
19 #include <minix/bitmap.h>
23 #include <sys/mount.h>
29 #include <minix/vfsif.h>
35 /* Allow the root to be replaced before the first 'real' mount. */
36 static int have_root
= 0;
38 /* Bitmap of in-use "none" pseudo devices. */
39 static bitchunk_t nonedev
[BITMAP_CHUNKS(NR_NONEDEVS
)] = { 0 };
41 #define alloc_nonedev(dev) SET_BIT(nonedev, minor(dev) - 1)
42 #define free_nonedev(dev) UNSET_BIT(nonedev, minor(dev) - 1)
44 static dev_t
name_to_dev(int allow_mountpt
, char path
[PATH_MAX
]);
45 static dev_t
find_free_nonedev(void);
46 static void update_bspec(dev_t dev
, endpoint_t fs_e
, int send_drv_e
);
48 /*===========================================================================*
50 *===========================================================================*/
51 static void update_bspec(dev_t dev
, endpoint_t fs_e
, int send_drv_e
)
53 /* Update all block special files for a certain device, to use a new FS endpt
54 * to route raw block I/O requests through.
60 for (vp
= &vnode
[0]; vp
< &vnode
[NR_VNODES
]; ++vp
)
61 if (vp
->v_ref_count
> 0 && S_ISBLK(vp
->v_mode
) && vp
->v_sdev
== dev
) {
65 if (major
< 0 || major
>= NR_DEVICES
) {
66 /* Can't update for out-of-range major */
69 dp
= &dmap
[major(dev
)];
70 if (dp
->dmap_driver
== NONE
) {
71 /* Can't update for vanished driver */
72 printf("VFS: can't send new driver label\n");
76 if ((r
= req_newdriver(fs_e
, vp
->v_sdev
,
77 dp
->dmap_label
)) != OK
) {
78 printf("VFS: Failed to send new driver label"
79 " for moved block special file to %d\n",
86 /*===========================================================================*
88 *===========================================================================*/
95 /*===========================================================================*
97 *===========================================================================*/
100 /* Perform the mount(name, mfile, mount_flags) system call. */
102 int r
, slot
, rdonly
, nodev
;
103 char fullpath
[PATH_MAX
];
104 char mount_label
[LABEL_MAX
];
107 vir_bytes label
, vname1
, vname2
;
108 size_t vname1_length
, vname2_length
;
110 mflags
= job_m_in
.mount_flags
;
111 label
= (vir_bytes
) job_m_in
.fs_label
;
112 vname1
= (vir_bytes
) job_m_in
.name1
;
113 vname1_length
= (size_t) job_m_in
.name1_length
;
114 vname2
= (vir_bytes
) job_m_in
.name2
;
115 vname2_length
= (size_t) job_m_in
.name2_length
;
117 /* Only the super-user may do MOUNT. */
118 if (!super_user
) return(EPERM
);
121 /* FS process' endpoint number */
122 if (mflags
& MS_LABEL16
) {
123 /* Get the label from the caller, and ask DS for the endpoint. */
124 r
= sys_datacopy(who_e
, label
, SELF
, (vir_bytes
) mount_label
,
125 sizeof(mount_label
));
126 if (r
!= OK
) return(r
);
128 mount_label
[sizeof(mount_label
)-1] = 0;
130 r
= ds_retrieve_label_endpt(mount_label
, &fs_e
);
131 if (r
!= OK
) return(r
);
133 /* Legacy support: get the endpoint from the request itself. */
134 fs_e
= (endpoint_t
) label
;
138 /* Sanity check on process number. */
139 if (isokendpt(fs_e
, &slot
) != OK
) return(EINVAL
);
141 /* Should the file system be mounted read-only? */
142 rdonly
= (mflags
& MS_RDONLY
);
144 /* A null string for block special device means don't use a device at all. */
145 nodev
= (vname1_length
== 0);
147 /* If 'name' is not for a block special file, return error. */
148 if (fetch_name(vname1
, vname1_length
, fullpath
) != OK
)
150 if ((dev
= name_to_dev(FALSE
/*allow_mountpt*/, fullpath
)) == NO_DEV
)
153 /* Find a free pseudo-device as substitute for an actual device. */
154 if ((dev
= find_free_nonedev()) == NO_DEV
)
158 /* Fetch the name of the mountpoint */
159 if (fetch_name(vname2
, vname2_length
, fullpath
) != OK
) return(err_code
);
161 /* Do the actual job */
162 return mount_fs(dev
, fullpath
, fs_e
, rdonly
, mount_label
);
166 /*===========================================================================*
168 *===========================================================================*/
171 char mountpoint
[PATH_MAX
],
174 char mount_label
[LABEL_MAX
] )
176 int i
, r
= OK
, found
, isroot
, mount_root
, con_reqs
, slot
;
177 struct fproc
*tfp
, *rfp
;
179 struct vnode
*root_node
, *vp
= NULL
;
180 struct vmnt
*new_vmp
, *parent_vmp
;
182 struct node_details res
;
183 struct lookup resolve
;
185 /* Look up block device driver label when dev is not a pseudo-device */
187 if (!is_nonedev(dev
)) {
188 /* Get driver process' endpoint */
189 dp
= &dmap
[major(dev
)];
190 if (dp
->dmap_driver
== NONE
) {
191 printf("VFS: no driver for dev %d\n", dev
);
195 label
= dp
->dmap_label
;
196 assert(strlen(label
) > 0);
199 /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/
201 for (i
= 0; i
< NR_MNTS
; ++i
) {
202 if (vmnt
[i
].m_dev
== dev
) found
= TRUE
;
206 } else if ((new_vmp
= get_free_vmnt()) == NULL
) {
210 if ((r
= lock_vmnt(new_vmp
, VMNT_EXCL
)) != OK
) return(r
);
212 isroot
= (strcmp(mountpoint
, "/") == 0);
213 mount_root
= (isroot
&& have_root
< 2); /* Root can be mounted twice:
215 * 2: boot disk (e.g., harddisk)
219 /* Get vnode of mountpoint */
220 lookup_init(&resolve
, mountpoint
, PATH_NOFLAGS
, &parent_vmp
, &vp
);
221 resolve
.l_vmnt_lock
= VMNT_EXCL
;
222 resolve
.l_vnode_lock
= VNODE_WRITE
;
223 if ((vp
= eat_path(&resolve
, fp
)) == NULL
)
225 else if (vp
->v_ref_count
== 1) {
226 /*Tell FS on which vnode it is mounted (glue into mount tree)*/
227 r
= req_mountpoint(vp
->v_fs_e
, vp
->v_inode_nr
);
232 /* Quickly unlock to allow back calls (from e.g. FUSE) to
234 unlock_vmnt(parent_vmp
);
242 unlock_vmnt(new_vmp
);
247 /* We'll need a vnode for the root inode */
248 if ((root_node
= get_free_vnode()) == NULL
) {
253 unlock_vmnt(new_vmp
);
256 lock_vnode(root_node
, VNODE_OPCL
);
258 /* Record process as a system process */
259 if (isokendpt(fs_e
, &slot
) != OK
) {
264 unlock_vnode(root_node
);
265 unlock_vmnt(new_vmp
);
269 rfp
->fp_flags
|= FP_SYS_PROC
; /* Process is an FS */
271 /* Store some essential vmnt data first */
272 new_vmp
->m_fs_e
= fs_e
;
273 new_vmp
->m_dev
= dev
;
274 if (rdonly
) new_vmp
->m_flags
|= VMNT_READONLY
;
275 else new_vmp
->m_flags
&= ~VMNT_READONLY
;
277 /* Tell FS which device to mount */
278 new_vmp
->m_flags
|= VMNT_MOUNTING
;
279 r
= req_readsuper(fs_e
, label
, dev
, rdonly
, isroot
, &res
, &con_reqs
);
280 new_vmp
->m_flags
&= ~VMNT_MOUNTING
;
283 mark_vmnt_free(new_vmp
);
284 unlock_vnode(root_node
);
289 unlock_vmnt(new_vmp
);
295 /* Fill in root node's fields */
296 root_node
->v_fs_e
= res
.fs_e
;
297 root_node
->v_inode_nr
= res
.inode_nr
;
298 root_node
->v_mode
= res
.fmode
;
299 root_node
->v_uid
= res
.uid
;
300 root_node
->v_gid
= res
.gid
;
301 root_node
->v_size
= res
.fsize
;
302 root_node
->v_sdev
= NO_DEV
;
303 root_node
->v_fs_count
= 1;
304 root_node
->v_ref_count
= 1;
306 /* Root node is indeed on the partition */
307 root_node
->v_vmnt
= new_vmp
;
308 root_node
->v_dev
= new_vmp
->m_dev
;
310 new_vmp
->m_comm
.c_max_reqs
= 1; /* Default if FS doesn't tell us */
312 new_vmp
->m_comm
.c_max_reqs
= con_reqs
;
313 new_vmp
->m_comm
.c_cur_reqs
= 0;
316 /* Superblock and root node already read.
317 * Nothing else can go wrong. Perform the mount. */
318 new_vmp
->m_root_node
= root_node
;
319 new_vmp
->m_mounted_on
= NULL
;
320 strlcpy(new_vmp
->m_label
, mount_label
, LABEL_MAX
);
321 if (is_nonedev(dev
)) alloc_nonedev(dev
);
322 update_bspec(dev
, fs_e
, 0 /* Don't send new driver endpoint */);
327 /* Replace all root and working directories */
328 for (i
= 0, tfp
= fproc
; i
< NR_PROCS
; i
++, tfp
++) {
329 if (tfp
->fp_pid
== PID_FREE
)
332 #define MAKEROOT(what) { \
333 if (what) put_vnode(what); \
334 dup_vnode(root_node); \
338 MAKEROOT(tfp
->fp_rd
);
339 MAKEROOT(tfp
->fp_wd
);
342 unlock_vnode(root_node
);
343 unlock_vmnt(new_vmp
);
344 have_root
++; /* We have a (new) root */
349 /* File types may not conflict. */
350 if (!S_ISDIR(vp
->v_mode
) && S_ISDIR(root_node
->v_mode
)) r
= EISDIR
;
352 /* If error, return the super block and both inodes; release the vmnt. */
355 unlock_vnode(root_node
);
356 mark_vmnt_free(new_vmp
);
357 unlock_vmnt(new_vmp
);
359 put_vnode(root_node
);
364 /* Nothing else can go wrong. Perform the mount. */
365 new_vmp
->m_mounted_on
= vp
;
366 new_vmp
->m_root_node
= root_node
;
367 strlcpy(new_vmp
->m_label
, mount_label
, LABEL_MAX
);
369 /* Allocate the pseudo device that was found, if not using a real device. */
370 if (is_nonedev(dev
)) alloc_nonedev(dev
);
372 /* The new FS will handle block I/O requests for its device now. */
373 if (!(new_vmp
->m_flags
& VMNT_FORCEROOTBSF
))
374 update_bspec(dev
, fs_e
, 0 /* Don't send new driver endpoint */);
377 unlock_vnode(root_node
);
378 unlock_vmnt(new_vmp
);
385 /*===========================================================================*
387 *===========================================================================*/
390 /* Mount the Pipe File Server. It's not really mounted onto the file system,
391 but it's necessary it has a vmnt entry to make locking easier */
397 if ((dev
= find_free_nonedev()) == NO_DEV
)
398 panic("VFS: no nonedev to initialize PFS");
400 if ((vmp
= get_free_vmnt()) == NULL
)
401 panic("VFS: no vmnt to initialize PFS");
406 vmp
->m_fs_e
= PFS_PROC_NR
;
407 strlcpy(vmp
->m_label
, "pfs", LABEL_MAX
);
409 rfp
= &fproc
[_ENDPOINT_P(PFS_PROC_NR
)];
410 rfp
->fp_flags
|= FP_SYS_PROC
; /* PFS is a driver and an FS */
413 /*===========================================================================*
415 *===========================================================================*/
418 /* Perform the umount(name) system call.
419 * syscall might provide 'name' embedded in the message.
421 char label
[LABEL_MAX
];
424 char fullpath
[PATH_MAX
];
428 vname
= (vir_bytes
) job_m_in
.name
;
429 vname_length
= (size_t) job_m_in
.name_length
;
431 /* Only the super-user may do umount. */
432 if (!super_user
) return(EPERM
);
434 /* If 'name' is not for a block special file or mountpoint, return error. */
435 if (copy_name(vname_length
, fullpath
) != OK
) {
436 /* Direct copy failed, try fetching from user space */
437 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
440 if ((dev
= name_to_dev(TRUE
/*allow_mountpt*/, fullpath
)) == NO_DEV
)
443 if ((r
= unmount(dev
, label
)) != OK
) return(r
);
445 /* Return the label of the mounted file system, so that the caller
446 * can shut down the corresponding server process.
448 if (strlen(label
) >= M3_LONG_STRING
) /* should never evaluate to true */
449 label
[M3_LONG_STRING
-1] = 0;
450 strlcpy(m_out
.umount_label
, label
, M3_LONG_STRING
);
455 /*===========================================================================*
457 *===========================================================================*/
459 dev_t dev
, /* block-special device */
460 char label
[LABEL_MAX
] /* buffer to retrieve label, or NULL */
464 struct vmnt
*vmp_i
= NULL
, *vmp
= NULL
;
467 /* Find vmnt that is to be unmounted */
468 for (vmp_i
= &vmnt
[0]; vmp_i
< &vmnt
[NR_MNTS
]; ++vmp_i
) {
469 if (vmp_i
->m_dev
== dev
) {
470 if(vmp
) panic("device mounted more than once: %d", dev
);
475 /* Did we find the vmnt (i.e., was dev a mounted device)? */
476 if(!vmp
) return(EINVAL
);
478 if ((r
= lock_vmnt(vmp
, VMNT_EXCL
)) != OK
) return(r
);
480 /* See if the mounted device is busy. Only 1 vnode using it should be
481 * open -- the root vnode -- and that inode only 1 time. */
483 for (vp
= &vnode
[0]; vp
< &vnode
[NR_VNODES
]; vp
++)
484 if (vp
->v_ref_count
> 0 && vp
->v_dev
== dev
) {
485 count
+= vp
->v_ref_count
;
486 if (is_vnode_locked(vp
)) locks
++;
489 if (count
> 1 || locks
> 1 || tll_haspendinglock(&vmp
->m_lock
)) {
491 return(EBUSY
); /* can't umount a busy file system */
494 /* Tell FS to drop all inode references for root inode except 1. */
495 vnode_clean_refs(vmp
->m_root_node
);
497 if (vmp
->m_mounted_on
) {
498 put_vnode(vmp
->m_mounted_on
);
499 vmp
->m_mounted_on
= NULL
;
502 vmp
->m_comm
.c_max_reqs
= 1; /* Force max concurrent reqs to just one, so
503 * we won't send any messages after the
506 /* Tell FS to unmount */
507 if ((r
= req_unmount(vmp
->m_fs_e
)) != OK
) /* Not recoverable. */
508 printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n",
511 if (is_nonedev(vmp
->m_dev
)) free_nonedev(vmp
->m_dev
);
513 if (label
!= NULL
) strlcpy(label
, vmp
->m_label
, LABEL_MAX
);
515 if (vmp
->m_root_node
) { /* PFS lacks a root node */
516 vmp
->m_root_node
->v_ref_count
= 0;
517 vmp
->m_root_node
->v_fs_count
= 0;
518 vmp
->m_root_node
->v_sdev
= NO_DEV
;
519 vmp
->m_root_node
= NULL
;
525 /* The root FS will handle block I/O requests for this device now. */
527 update_bspec(dev
, ROOT_FS_E
, 1 /* send new driver endpoint */);
534 /*===========================================================================*
536 *===========================================================================*/
537 void unmount_all(void)
539 /* Unmount all filesystems. File systems are mounted on other file systems,
540 * so you have to pull off the loose bits repeatedly to get it all undone.
546 /* Now unmount the rest */
547 for (i
= 0; i
< NR_MNTS
; i
++) {
548 /* Unmount at least one. */
549 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
550 if (vmp
->m_dev
!= NO_DEV
)
551 unmount(vmp
->m_dev
, NULL
);
555 /* Verify nothing is locked anymore */
561 /* Verify we succesfully unmounted all file systems */
562 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
563 if (vmp
->m_dev
!= NO_DEV
) {
564 panic("vmp still mounted: %s %d %d\n", vmp
->m_label
,
565 vmp
->m_fs_e
, vmp
->m_dev
);
570 /*===========================================================================*
572 *===========================================================================*/
573 static dev_t
name_to_dev(int allow_mountpt
, char path
[PATH_MAX
])
575 /* Convert the block special file in 'user_fullpath' to a device number.
576 * If the given path is not a block special file, but 'allow_mountpt' is set
577 * and the path is the root node of a mounted file system, return that device
578 * number. In all other cases, return NO_DEV and an error code in 'err_code'.
583 struct lookup resolve
;
585 lookup_init(&resolve
, path
, PATH_NOFLAGS
, &vmp
, &vp
);
586 resolve
.l_vmnt_lock
= VMNT_READ
;
587 resolve
.l_vnode_lock
= VNODE_READ
;
590 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(NO_DEV
);
592 if (S_ISBLK(vp
->v_mode
)) {
594 } else if (allow_mountpt
&& vp
->v_vmnt
->m_root_node
== vp
) {
608 /*===========================================================================*
610 *===========================================================================*/
611 int is_nonedev(dev_t dev
)
613 /* Return whether the given device is a "none" pseudo device.
616 return (major(dev
) == NONE_MAJOR
&&
617 minor(dev
) > 0 && minor(dev
) <= NR_NONEDEVS
);
621 /*===========================================================================*
622 * find_free_nonedev *
623 *===========================================================================*/
624 static dev_t
find_free_nonedev(void)
626 /* Find a free "none" pseudo device. Do not allocate it yet.
630 for (i
= 0; i
< NR_NONEDEVS
; i
++)
631 if (!GET_BIT(nonedev
, i
))
632 return makedev(NONE_MAJOR
, i
+ 1);