1 /* This file performs the MOUNT and UMOUNT system calls.
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 * unmount: unmount a file system
12 #include <minix/callnr.h>
13 #include <minix/com.h>
14 #include <minix/const.h>
15 #include <minix/endpoint.h>
16 #include <minix/syslib.h>
17 #include <minix/bitmap.h>
21 #include <sys/mount.h>
22 #include <sys/dirent.h>
25 #include <minix/vfsif.h>
30 /* Allow the root to be replaced before the first 'real' mount. */
31 static int have_root
= 0;
33 /* Bitmap of in-use "none" pseudo devices. */
34 static bitchunk_t nonedev
[BITMAP_CHUNKS(NR_NONEDEVS
)] = { 0 };
36 #define alloc_nonedev(dev) SET_BIT(nonedev, minor(dev) - 1)
37 #define free_nonedev(dev) UNSET_BIT(nonedev, minor(dev) - 1)
39 static dev_t
name_to_dev(int allow_mountpt
, char path
[PATH_MAX
]);
40 static dev_t
find_free_nonedev(void);
41 static void update_bspec(dev_t dev
, endpoint_t fs_e
, int send_drv_e
);
43 /*===========================================================================*
45 *===========================================================================*/
46 static void update_bspec(dev_t dev
, endpoint_t fs_e
, int send_drv_e
)
48 /* Update all block special files for a certain device, to use a new FS endpt
49 * to route raw block I/O requests through.
56 for (vp
= &vnode
[0]; vp
< &vnode
[NR_VNODES
]; ++vp
)
57 if (vp
->v_ref_count
> 0 && S_ISBLK(vp
->v_mode
) && vp
->v_sdev
== dev
) {
61 if (major
< 0 || major
>= NR_DEVICES
) {
62 /* Can't update for out-of-range major */
65 dp
= &dmap
[major(dev
)];
66 if (dp
->dmap_driver
== NONE
) {
67 /* Can't update for vanished driver */
68 printf("VFS: can't send new driver label\n");
72 if ((r
= req_newdriver(fs_e
, vp
->v_sdev
,
73 dp
->dmap_label
)) != OK
) {
74 printf("VFS: Failed to send new driver label"
75 " for moved block special file to %d\n",
82 /*===========================================================================*
84 *===========================================================================*/
87 /* Perform the mount(name, mfile, mount_flags) system call. */
90 char mount_path
[PATH_MAX
], mount_dev
[PATH_MAX
];
91 char mount_label
[LABEL_MAX
], mount_type
[FSTYPE_MAX
];
94 vir_bytes label
, type
, vname1
, vname2
;
95 size_t vname1_length
, vname2_length
, label_len
, type_len
;
97 mflags
= job_m_in
.m_lc_vfs_mount
.flags
;
98 label
= job_m_in
.m_lc_vfs_mount
.label
;
99 label_len
= job_m_in
.m_lc_vfs_mount
.labellen
;
100 vname1
= job_m_in
.m_lc_vfs_mount
.dev
;
101 vname1_length
= job_m_in
.m_lc_vfs_mount
.devlen
;
102 vname2
= job_m_in
.m_lc_vfs_mount
.path
;
103 vname2_length
= job_m_in
.m_lc_vfs_mount
.pathlen
;
104 type
= job_m_in
.m_lc_vfs_mount
.type
;
105 type_len
= job_m_in
.m_lc_vfs_mount
.typelen
;
107 /* Only the super-user may do MOUNT. */
108 if (!super_user
) return(EPERM
);
110 /* Get the label from the caller, and ask DS for the endpoint of the FS. */
111 if (label_len
> sizeof(mount_label
))
113 r
= sys_datacopy_wrapper(who_e
, label
, SELF
, (vir_bytes
) mount_label
,
114 sizeof(mount_label
));
115 if (r
!= OK
) return(r
);
117 mount_label
[sizeof(mount_label
)-1] = 0;
119 r
= ds_retrieve_label_endpt(mount_label
, &fs_e
);
120 if (r
!= OK
) return(r
);
122 /* Sanity check on process number. */
123 if (isokendpt(fs_e
, &slot
) != OK
) return(EINVAL
);
125 /* A null string for block special device means don't use a device at all. */
126 nodev
= (vname1_length
== 0);
128 /* If 'name' is not for a block special file, return error. */
129 if (fetch_name(vname1
, vname1_length
, mount_dev
) != OK
)
131 if ((dev
= name_to_dev(FALSE
/*allow_mountpt*/, mount_dev
)) == NO_DEV
)
134 /* Find a free pseudo-device as substitute for an actual device. */
135 if ((dev
= find_free_nonedev()) == NO_DEV
)
137 strlcpy(mount_dev
, "none", sizeof(mount_dev
));
140 /* Fetch the name of the mountpoint */
141 if (fetch_name(vname2
, vname2_length
, mount_path
) != OK
) return(err_code
);
143 /* Fetch the type of the file system. */
144 if (type_len
> sizeof(mount_type
)) return(ENAMETOOLONG
);
145 if (fetch_name(type
, type_len
, mount_type
) != OK
) return(err_code
);
147 /* Do the actual job */
148 return mount_fs(dev
, mount_dev
, mount_path
, fs_e
, mflags
, mount_type
,
153 /*===========================================================================*
155 *===========================================================================*/
158 char mount_dev
[PATH_MAX
],
159 char mount_path
[PATH_MAX
],
162 char mount_type
[FSTYPE_MAX
],
163 char mount_label
[LABEL_MAX
] )
165 int i
, r
= OK
, found
, isroot
, mount_root
, slot
;
166 struct fproc
*tfp
, *rfp
;
168 struct vnode
*root_node
, *vp
= NULL
;
169 struct vmnt
*new_vmp
, *parent_vmp
;
171 struct node_details res
;
172 struct lookup resolve
;
173 struct statvfs statvfs_buf
;
174 unsigned int fs_flags
;
176 /* Look up block device driver label when dev is not a pseudo-device */
178 if (!is_nonedev(dev
)) {
179 /* Get driver process' endpoint */
180 dp
= &dmap
[major(dev
)];
181 if (dp
->dmap_driver
== NONE
) {
182 printf("VFS: no driver for dev %llx\n", dev
);
186 label
= dp
->dmap_label
;
187 assert(strlen(label
) > 0);
190 /* Scan vmnt table to see if dev already mounted. If not, find a free slot.*/
192 for (i
= 0; i
< NR_MNTS
; ++i
) {
193 if (vmnt
[i
].m_dev
== dev
) found
= TRUE
;
197 } else if ((new_vmp
= get_free_vmnt()) == NULL
) {
200 if ((r
= lock_vmnt(new_vmp
, VMNT_EXCL
)) != OK
) return(r
);
202 strlcpy(new_vmp
->m_mount_path
, mount_path
, PATH_MAX
);
203 strlcpy(new_vmp
->m_mount_dev
, mount_dev
, PATH_MAX
);
204 strlcpy(new_vmp
->m_fstype
, mount_type
, sizeof(new_vmp
->m_fstype
));
205 isroot
= (strcmp(mount_path
, "/") == 0);
206 mount_root
= (isroot
&& have_root
< 2); /* Root can be mounted twice:
208 * 2: boot disk (e.g., harddisk)
212 /* Get vnode of mountpoint */
213 lookup_init(&resolve
, mount_path
, PATH_NOFLAGS
, &parent_vmp
, &vp
);
214 resolve
.l_vmnt_lock
= VMNT_EXCL
;
215 resolve
.l_vnode_lock
= VNODE_WRITE
;
216 if ((vp
= eat_path(&resolve
, fp
)) == NULL
)
218 else if (vp
->v_ref_count
== 1) {
219 /*Tell FS on which vnode it is mounted (glue into mount tree)*/
220 r
= req_mountpoint(vp
->v_fs_e
, vp
->v_inode_nr
);
225 /* Quickly unlock to allow back calls (from e.g. FUSE) to
227 unlock_vmnt(parent_vmp
);
235 unlock_vmnt(new_vmp
);
240 /* We'll need a vnode for the root inode */
241 if ((root_node
= get_free_vnode()) == NULL
) {
246 unlock_vmnt(new_vmp
);
249 lock_vnode(root_node
, VNODE_OPCL
);
251 /* Record process as a system process */
252 if (isokendpt(fs_e
, &slot
) != OK
) {
257 unlock_vnode(root_node
);
258 unlock_vmnt(new_vmp
);
262 rfp
->fp_flags
|= FP_SRV_PROC
; /* File Servers are also services */
264 /* Store some essential vmnt data first */
265 new_vmp
->m_fs_e
= fs_e
;
266 new_vmp
->m_dev
= dev
;
267 if (flags
& MNT_RDONLY
) new_vmp
->m_flags
|= VMNT_READONLY
;
268 else new_vmp
->m_flags
&= ~VMNT_READONLY
;
270 /* Tell FS which device to mount */
271 new_vmp
->m_flags
|= VMNT_MOUNTING
;
272 r
= req_readsuper(new_vmp
, label
, dev
, !!(flags
& MNT_RDONLY
), isroot
, &res
,
274 new_vmp
->m_flags
&= ~VMNT_MOUNTING
;
276 new_vmp
->m_fs_flags
= fs_flags
;
278 /* Fill the statvfs cache with initial values. */
280 r
= update_statvfs(new_vmp
, &statvfs_buf
);
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
;
309 if (!(new_vmp
->m_fs_flags
& RES_THREADED
))
310 new_vmp
->m_comm
.c_max_reqs
= 1;
312 new_vmp
->m_comm
.c_max_reqs
= NR_WTHREADS
;
313 new_vmp
->m_comm
.c_cur_reqs
= 0;
315 /* No more blocking operations, so we can now report on this file system. */
316 new_vmp
->m_flags
|= VMNT_CANSTAT
;
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
;
410 strlcpy(vmp
->m_label
, "pfs", LABEL_MAX
);
411 strlcpy(vmp
->m_mount_path
, "pipe", PATH_MAX
);
412 strlcpy(vmp
->m_mount_dev
, "none", PATH_MAX
);
415 /*===========================================================================*
417 *===========================================================================*/
420 /* Perform the umount(name) system call. Return the label of the FS service.
422 char label
[LABEL_MAX
];
425 char fullpath
[PATH_MAX
];
426 vir_bytes vname
, label_addr
;
427 size_t vname_length
, label_len
;
429 vname
= job_m_in
.m_lc_vfs_umount
.name
;
430 vname_length
= job_m_in
.m_lc_vfs_umount
.namelen
;
431 label_addr
= job_m_in
.m_lc_vfs_umount
.label
;
432 label_len
= job_m_in
.m_lc_vfs_umount
.labellen
;
434 /* Only the super-user may do umount. */
435 if (!super_user
) return(EPERM
);
437 /* If 'name' is not for a block special file or mountpoint, return error. */
438 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
) >= label_len
)
449 label
[label_len
-1] = 0;
450 return sys_datacopy_wrapper(SELF
, (vir_bytes
) label
, who_e
, label_addr
,
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: %llx", 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 /* This FS will now disappear, so stop listing it in statistics. */
495 vmp
->m_flags
&= ~VMNT_CANSTAT
;
497 /* Tell FS to drop all inode references for root inode except 1. */
498 vnode_clean_refs(vmp
->m_root_node
);
500 if (vmp
->m_mounted_on
) {
501 put_vnode(vmp
->m_mounted_on
);
502 vmp
->m_mounted_on
= NULL
;
505 vmp
->m_comm
.c_max_reqs
= 1; /* Force max concurrent reqs to just one, so
506 * we won't send any messages after the
509 /* Tell FS to unmount */
510 if ((r
= req_unmount(vmp
->m_fs_e
)) != OK
) /* Not recoverable. */
511 printf("VFS: ignoring failed umount attempt FS endpoint: %d (%d)\n",
514 if (is_nonedev(vmp
->m_dev
)) free_nonedev(vmp
->m_dev
);
516 if (label
!= NULL
) strlcpy(label
, vmp
->m_label
, LABEL_MAX
);
518 if (vmp
->m_root_node
) { /* PFS lacks a root node */
519 vmp
->m_root_node
->v_ref_count
= 0;
520 vmp
->m_root_node
->v_fs_count
= 0;
521 vmp
->m_root_node
->v_sdev
= NO_DEV
;
522 vmp
->m_root_node
= NULL
;
528 /* The root FS will handle block I/O requests for this device now. */
530 update_bspec(dev
, ROOT_FS_E
, 1 /* send new driver endpoint */);
537 /*===========================================================================*
539 *===========================================================================*/
540 void unmount_all(int force
)
542 /* Unmount all filesystems. File systems are mounted on other file systems,
543 * so you have to pull off the loose bits repeatedly to get it all undone.
549 /* Now unmount the rest */
550 for (i
= 0; i
< NR_MNTS
; i
++) {
551 /* Unmount at least one. */
552 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
553 if (vmp
->m_dev
!= NO_DEV
)
554 unmount(vmp
->m_dev
, NULL
);
560 /* Verify nothing is locked anymore */
566 /* Verify we succesfully unmounted all file systems */
567 for (vmp
= &vmnt
[0]; vmp
< &vmnt
[NR_MNTS
]; vmp
++) {
568 if (vmp
->m_dev
!= NO_DEV
) {
569 panic("vmp still mounted: %s %d %llx\n", vmp
->m_label
,
570 vmp
->m_fs_e
, vmp
->m_dev
);
575 /*===========================================================================*
577 *===========================================================================*/
578 static dev_t
name_to_dev(int allow_mountpt
, char path
[PATH_MAX
])
580 /* Convert the block special file in 'user_fullpath' to a device number.
581 * If the given path is not a block special file, but 'allow_mountpt' is set
582 * and the path is the root node of a mounted file system, return that device
583 * number. In all other cases, return NO_DEV and an error code in 'err_code'.
588 struct lookup resolve
;
590 lookup_init(&resolve
, path
, PATH_NOFLAGS
, &vmp
, &vp
);
591 resolve
.l_vmnt_lock
= VMNT_READ
;
592 resolve
.l_vnode_lock
= VNODE_READ
;
595 if ((vp
= eat_path(&resolve
, fp
)) == NULL
) return(NO_DEV
);
597 if (S_ISBLK(vp
->v_mode
)) {
599 } else if (allow_mountpt
&& vp
->v_vmnt
->m_root_node
== vp
) {
613 /*===========================================================================*
615 *===========================================================================*/
616 int is_nonedev(dev_t dev
)
618 /* Return whether the given device is a "none" pseudo device.
621 return (major(dev
) == NONE_MAJOR
&&
622 minor(dev
) > 0 && minor(dev
) <= NR_NONEDEVS
);
626 /*===========================================================================*
627 * find_free_nonedev *
628 *===========================================================================*/
629 static dev_t
find_free_nonedev(void)
631 /* Find a free "none" pseudo device. Do not allocate it yet.
635 for (i
= 0; i
< NR_NONEDEVS
; i
++)
636 if (!GET_BIT(nonedev
, i
))
637 return makedev(NONE_MAJOR
, i
+ 1);