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 mount_path
[PATH_MAX
], mount_dev
[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
, mount_dev
) != OK
)
150 if ((dev
= name_to_dev(FALSE
/*allow_mountpt*/, mount_dev
)) == NO_DEV
)
153 /* Find a free pseudo-device as substitute for an actual device. */
154 if ((dev
= find_free_nonedev()) == NO_DEV
)
156 strlcpy(mount_dev
, "none", sizeof(mount_dev
));
159 /* Fetch the name of the mountpoint */
160 if (fetch_name(vname2
, vname2_length
, mount_path
) != OK
) return(err_code
);
162 /* Do the actual job */
163 return mount_fs(dev
, mount_dev
, mount_path
, fs_e
, rdonly
, mount_label
);
167 /*===========================================================================*
169 *===========================================================================*/
172 char mount_dev
[PATH_MAX
],
173 char mount_path
[PATH_MAX
],
176 char mount_label
[LABEL_MAX
] )
178 int i
, r
= OK
, found
, isroot
, mount_root
, con_reqs
, slot
;
179 struct fproc
*tfp
, *rfp
;
181 struct vnode
*root_node
, *vp
= NULL
;
182 struct vmnt
*new_vmp
, *parent_vmp
;
184 struct node_details res
;
185 struct lookup resolve
;
187 /* Look up block device driver label when dev is not a pseudo-device */
189 if (!is_nonedev(dev
)) {
190 /* Get driver process' endpoint */
191 dp
= &dmap
[major(dev
)];
192 if (dp
->dmap_driver
== NONE
) {
193 printf("VFS: no driver for dev %d\n", dev
);
197 label
= dp
->dmap_label
;
198 assert(strlen(label
) > 0);
201 /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/
203 for (i
= 0; i
< NR_MNTS
; ++i
) {
204 if (vmnt
[i
].m_dev
== dev
) found
= TRUE
;
208 } else if ((new_vmp
= get_free_vmnt()) == NULL
) {
211 if ((r
= lock_vmnt(new_vmp
, VMNT_EXCL
)) != OK
) return(r
);
213 strlcpy(new_vmp
->m_mount_path
, mount_path
, PATH_MAX
);
214 strlcpy(new_vmp
->m_mount_dev
, mount_dev
, PATH_MAX
);
215 isroot
= (strcmp(mount_path
, "/") == 0);
216 mount_root
= (isroot
&& have_root
< 2); /* Root can be mounted twice:
218 * 2: boot disk (e.g., harddisk)
222 /* Get vnode of mountpoint */
223 lookup_init(&resolve
, mount_path
, PATH_NOFLAGS
, &parent_vmp
, &vp
);
224 resolve
.l_vmnt_lock
= VMNT_EXCL
;
225 resolve
.l_vnode_lock
= VNODE_WRITE
;
226 if ((vp
= eat_path(&resolve
, fp
)) == NULL
)
228 else if (vp
->v_ref_count
== 1) {
229 /*Tell FS on which vnode it is mounted (glue into mount tree)*/
230 r
= req_mountpoint(vp
->v_fs_e
, vp
->v_inode_nr
);
235 /* Quickly unlock to allow back calls (from e.g. FUSE) to
237 unlock_vmnt(parent_vmp
);
245 unlock_vmnt(new_vmp
);
250 /* We'll need a vnode for the root inode */
251 if ((root_node
= get_free_vnode()) == NULL
) {
256 unlock_vmnt(new_vmp
);
259 lock_vnode(root_node
, VNODE_OPCL
);
261 /* Record process as a system process */
262 if (isokendpt(fs_e
, &slot
) != OK
) {
267 unlock_vnode(root_node
);
268 unlock_vmnt(new_vmp
);
272 rfp
->fp_flags
|= FP_SRV_PROC
; /* File Servers are also services */
274 /* Store some essential vmnt data first */
275 new_vmp
->m_fs_e
= fs_e
;
276 new_vmp
->m_dev
= dev
;
277 if (rdonly
) new_vmp
->m_flags
|= VMNT_READONLY
;
278 else new_vmp
->m_flags
&= ~VMNT_READONLY
;
280 /* Tell FS which device to mount */
281 new_vmp
->m_flags
|= VMNT_MOUNTING
;
282 r
= req_readsuper(fs_e
, label
, dev
, rdonly
, isroot
, &res
, &con_reqs
);
283 new_vmp
->m_flags
&= ~VMNT_MOUNTING
;
286 mark_vmnt_free(new_vmp
);
287 unlock_vnode(root_node
);
292 unlock_vmnt(new_vmp
);
298 /* Fill in root node's fields */
299 root_node
->v_fs_e
= res
.fs_e
;
300 root_node
->v_inode_nr
= res
.inode_nr
;
301 root_node
->v_mode
= res
.fmode
;
302 root_node
->v_uid
= res
.uid
;
303 root_node
->v_gid
= res
.gid
;
304 root_node
->v_size
= res
.fsize
;
305 root_node
->v_sdev
= NO_DEV
;
306 root_node
->v_fs_count
= 1;
307 root_node
->v_ref_count
= 1;
309 /* Root node is indeed on the partition */
310 root_node
->v_vmnt
= new_vmp
;
311 root_node
->v_dev
= new_vmp
->m_dev
;
313 new_vmp
->m_comm
.c_max_reqs
= 1; /* Default if FS doesn't tell us */
315 new_vmp
->m_comm
.c_max_reqs
= con_reqs
;
316 new_vmp
->m_comm
.c_cur_reqs
= 0;
319 /* Superblock and root node already read.
320 * Nothing else can go wrong. Perform the mount. */
321 new_vmp
->m_root_node
= root_node
;
322 new_vmp
->m_mounted_on
= NULL
;
323 strlcpy(new_vmp
->m_label
, mount_label
, LABEL_MAX
);
324 if (is_nonedev(dev
)) alloc_nonedev(dev
);
325 update_bspec(dev
, fs_e
, 0 /* Don't send new driver endpoint */);
330 /* Replace all root and working directories */
331 for (i
= 0, tfp
= fproc
; i
< NR_PROCS
; i
++, tfp
++) {
332 if (tfp
->fp_pid
== PID_FREE
)
335 #define MAKEROOT(what) { \
336 if (what) put_vnode(what); \
337 dup_vnode(root_node); \
341 MAKEROOT(tfp
->fp_rd
);
342 MAKEROOT(tfp
->fp_wd
);
345 unlock_vnode(root_node
);
346 unlock_vmnt(new_vmp
);
347 have_root
++; /* We have a (new) root */
352 /* File types may not conflict. */
353 if (!S_ISDIR(vp
->v_mode
) && S_ISDIR(root_node
->v_mode
)) r
= EISDIR
;
355 /* If error, return the super block and both inodes; release the vmnt. */
358 unlock_vnode(root_node
);
359 mark_vmnt_free(new_vmp
);
360 unlock_vmnt(new_vmp
);
362 put_vnode(root_node
);
367 /* Nothing else can go wrong. Perform the mount. */
368 new_vmp
->m_mounted_on
= vp
;
369 new_vmp
->m_root_node
= root_node
;
370 strlcpy(new_vmp
->m_label
, mount_label
, LABEL_MAX
);
372 /* Allocate the pseudo device that was found, if not using a real device. */
373 if (is_nonedev(dev
)) alloc_nonedev(dev
);
375 /* The new FS will handle block I/O requests for its device now. */
376 if (!(new_vmp
->m_flags
& VMNT_FORCEROOTBSF
))
377 update_bspec(dev
, fs_e
, 0 /* Don't send new driver endpoint */);
380 unlock_vnode(root_node
);
381 unlock_vmnt(new_vmp
);
388 /*===========================================================================*
390 *===========================================================================*/
393 /* Mount the Pipe File Server. It's not really mounted onto the file system,
394 but it's necessary it has a vmnt entry to make locking easier */
399 if ((dev
= find_free_nonedev()) == NO_DEV
)
400 panic("VFS: no nonedev to initialize PFS");
402 if ((vmp
= get_free_vmnt()) == NULL
)
403 panic("VFS: no vmnt to initialize PFS");
408 vmp
->m_fs_e
= PFS_PROC_NR
;
409 strlcpy(vmp
->m_label
, "pfs", LABEL_MAX
);
410 strlcpy(vmp
->m_mount_path
, "pipe", PATH_MAX
);
411 strlcpy(vmp
->m_mount_dev
, "none", PATH_MAX
);
414 /*===========================================================================*
416 *===========================================================================*/
419 /* Perform the umount(name) system call.
420 * syscall might provide 'name' embedded in the message.
422 char label
[LABEL_MAX
];
425 char fullpath
[PATH_MAX
];
429 vname
= (vir_bytes
) job_m_in
.name
;
430 vname_length
= (size_t) job_m_in
.name_length
;
432 /* Only the super-user may do umount. */
433 if (!super_user
) return(EPERM
);
435 /* If 'name' is not for a block special file or mountpoint, return error. */
436 if (copy_name(vname_length
, fullpath
) != OK
) {
437 /* Direct copy failed, try fetching from user space */
438 if (fetch_name(vname
, vname_length
, fullpath
) != OK
)
441 if ((dev
= name_to_dev(TRUE
/*allow_mountpt*/, fullpath
)) == NO_DEV
)
444 if ((r
= unmount(dev
, label
)) != OK
) return(r
);
446 /* Return the label of the mounted file system, so that the caller
447 * can shut down the corresponding server process.
449 if (strlen(label
) >= M3_LONG_STRING
) /* should never evaluate to true */
450 label
[M3_LONG_STRING
-1] = 0;
451 strlcpy(m_out
.umount_label
, label
, M3_LONG_STRING
);
456 /*===========================================================================*
458 *===========================================================================*/
460 dev_t dev
, /* block-special device */
461 char label
[LABEL_MAX
] /* buffer to retrieve label, or NULL */
465 struct vmnt
*vmp_i
= NULL
, *vmp
= NULL
;
468 /* Find vmnt that is to be unmounted */
469 for (vmp_i
= &vmnt
[0]; vmp_i
< &vmnt
[NR_MNTS
]; ++vmp_i
) {
470 if (vmp_i
->m_dev
== dev
) {
471 if(vmp
) panic("device mounted more than once: %d", dev
);
476 /* Did we find the vmnt (i.e., was dev a mounted device)? */
477 if(!vmp
) return(EINVAL
);
479 if ((r
= lock_vmnt(vmp
, VMNT_EXCL
)) != OK
) return(r
);
481 /* See if the mounted device is busy. Only 1 vnode using it should be
482 * open -- the root vnode -- and that inode only 1 time. */
484 for (vp
= &vnode
[0]; vp
< &vnode
[NR_VNODES
]; vp
++)
485 if (vp
->v_ref_count
> 0 && vp
->v_dev
== dev
) {
486 count
+= vp
->v_ref_count
;
487 if (is_vnode_locked(vp
)) locks
++;
490 if (count
> 1 || locks
> 1 || tll_haspendinglock(&vmp
->m_lock
)) {
492 return(EBUSY
); /* can't umount a busy file system */
495 /* Tell FS to drop all inode references for root inode except 1. */
496 vnode_clean_refs(vmp
->m_root_node
);
498 if (vmp
->m_mounted_on
) {
499 put_vnode(vmp
->m_mounted_on
);
500 vmp
->m_mounted_on
= NULL
;
503 vmp
->m_comm
.c_max_reqs
= 1; /* Force max concurrent reqs to just one, so
504 * we won't send any messages after the
507 /* Tell FS to unmount */
508 if ((r
= req_unmount(vmp
->m_fs_e
)) != OK
) /* Not recoverable. */
509 printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n",
512 if (is_nonedev(vmp
->m_dev
)) free_nonedev(vmp
->m_dev
);
514 if (label
!= NULL
) strlcpy(label
, vmp
->m_label
, LABEL_MAX
);
516 if (vmp
->m_root_node
) { /* PFS lacks a root node */
517 vmp
->m_root_node
->v_ref_count
= 0;
518 vmp
->m_root_node
->v_fs_count
= 0;
519 vmp
->m_root_node
->v_sdev
= NO_DEV
;
520 vmp
->m_root_node
= NULL
;
526 /* The root FS will handle block I/O requests for this device now. */
528 update_bspec(dev
, ROOT_FS_E
, 1 /* send new driver endpoint */);
535 /*===========================================================================*
537 *===========================================================================*/
538 void unmount_all(int force
)
540 /* Unmount all filesystems. File systems are mounted on other file systems,
541 * so you have to pull off the loose bits repeatedly to get it all undone.
547 /* Now unmount the rest */
548 for (i
= 0; i
< NR_MNTS
; i
++) {
549 /* Unmount at least one. */
550 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
551 if (vmp
->m_dev
!= NO_DEV
)
552 unmount(vmp
->m_dev
, NULL
);
558 /* Verify nothing is locked anymore */
564 /* Verify we succesfully unmounted all file systems */
565 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
566 if (vmp
->m_dev
!= NO_DEV
) {
567 panic("vmp still mounted: %s %d %d\n", vmp
->m_label
,
568 vmp
->m_fs_e
, vmp
->m_dev
);
573 /*===========================================================================*
575 *===========================================================================*/
576 static dev_t
name_to_dev(int allow_mountpt
, char path
[PATH_MAX
])
578 /* Convert the block special file in 'user_fullpath' to a device number.
579 * If the given path is not a block special file, but 'allow_mountpt' is set
580 * and the path is the root node of a mounted file system, return that device
581 * number. In all other cases, return NO_DEV and an error code in 'err_code'.
586 struct lookup resolve
;
588 lookup_init(&resolve
, path
, PATH_NOFLAGS
, &vmp
, &vp
);
589 resolve
.l_vmnt_lock
= VMNT_READ
;
590 resolve
.l_vnode_lock
= VNODE_READ
;
593 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(NO_DEV
);
595 if (S_ISBLK(vp
->v_mode
)) {
597 } else if (allow_mountpt
&& vp
->v_vmnt
->m_root_node
== vp
) {
611 /*===========================================================================*
613 *===========================================================================*/
614 int is_nonedev(dev_t dev
)
616 /* Return whether the given device is a "none" pseudo device.
619 return (major(dev
) == NONE_MAJOR
&&
620 minor(dev
) > 0 && minor(dev
) <= NR_NONEDEVS
);
624 /*===========================================================================*
625 * find_free_nonedev *
626 *===========================================================================*/
627 static dev_t
find_free_nonedev(void)
629 /* Find a free "none" pseudo device. Do not allocate it yet.
633 for (i
= 0; i
< NR_NONEDEVS
; i
++)
634 if (!GET_BIT(nonedev
, i
))
635 return makedev(NONE_MAJOR
, i
+ 1);