/*===========================================================================* * do_umount * *===========================================================================*/ PUBLIC int do_umount(void) { /* Perform the umount(name) system call. */ char label[LABEL_MAX]; dev_t dev; int r; char fullpath[PATH_MAX]; /* Only the super-user may do umount. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file or mountpoint, return error. */ if (fetch_name(m_in.name, m_in.name_length, M3, fullpath) != OK) return(err_code); if ((dev = name_to_dev(TRUE /*allow_mountpt*/, fullpath)) == NO_DEV) return(err_code); if ((r = unmount(dev, label)) != OK) return(r); /* Return the label of the mounted file system, so that the caller * can shut down the corresponding server process. */ if (strlen(label) >= M3_LONG_STRING) /* should never evaluate to true */ label[M3_LONG_STRING-1] = 0; strcpy(m_out.umount_label, label); return(OK); }
/*===========================================================================* * do_mount * *===========================================================================*/ PUBLIC int do_mount() { /* Perform the mount(name, mfile, mount_flags) system call. */ endpoint_t fs_e; int r, slot, rdonly, nodev; char fullpath[PATH_MAX]; char mount_label[LABEL_MAX]; dev_t dev; /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); /* FS process' endpoint number */ if (m_in.mount_flags & MS_LABEL16) { /* Get the label from the caller, and ask DS for the endpoint. */ r = sys_datacopy(who_e, (vir_bytes) m_in.fs_label, SELF, (vir_bytes) mount_label, (phys_bytes) sizeof(mount_label)); if (r != OK) return(r); mount_label[sizeof(mount_label)-1] = 0; r = ds_retrieve_label_endpt(mount_label, &fs_e); if (r != OK) return(r); } else { /* Legacy support: get the endpoint from the request itself. */ fs_e = (endpoint_t) m_in.fs_label; mount_label[0] = 0; } /* Sanity check on process number. */ if (isokendpt(fs_e, &slot) != OK) return(EINVAL); /* Should the file system be mounted read-only? */ rdonly = (m_in.mount_flags & MS_RDONLY); /* A null string for block special device means don't use a device at all. */ nodev = (m_in.name1_length == 0); if (!nodev) { /* If 'name' is not for a block special file, return error. */ if (fetch_name(m_in.name1, m_in.name1_length, M1, fullpath) != OK) return(err_code); if ((dev = name_to_dev(FALSE /*allow_mountpt*/, fullpath)) == NO_DEV) return(err_code); } else { /* Find a free pseudo-device as substitute for an actual device. */ if ((dev = find_free_nonedev()) == NO_DEV) return(err_code); } /* Fetch the name of the mountpoint */ if (fetch_name(m_in.name2, m_in.name2_length, M1, fullpath) != OK) return(err_code); /* Do the actual job */ return mount_fs(dev, fullpath, fs_e, rdonly, mount_label); }
/*===========================================================================* * do_umount * *===========================================================================*/ PUBLIC int do_umount() { /* Perform the umount(name) system call. */ dev_t dev; /* Only the super-user may do UMOUNT. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file, return error. */ if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code); return(unmount(dev)); }
/*===========================================================================* * do_umount * *===========================================================================*/ int do_umount(void) { /* Perform the umount(name) system call. * syscall might provide 'name' embedded in the message. */ char label[LABEL_MAX]; dev_t dev; int r; char fullpath[PATH_MAX]; vir_bytes vname; size_t vname_length; vname = (vir_bytes) job_m_in.name; vname_length = (size_t) job_m_in.name_length; /* Only the super-user may do umount. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file or mountpoint, return error. */ if (copy_name(vname_length, fullpath) != OK) { /* Direct copy failed, try fetching from user space */ if (fetch_name(vname, vname_length, fullpath) != OK) return(err_code); } if ((dev = name_to_dev(TRUE /*allow_mountpt*/, fullpath)) == NO_DEV) return(err_code); if ((r = unmount(dev, label)) != OK) return(r); /* Return the label of the mounted file system, so that the caller * can shut down the corresponding server process. */ if (strlen(label) >= M3_LONG_STRING) /* should never evaluate to true */ label[M3_LONG_STRING-1] = 0; strlcpy(m_out.umount_label, label, M3_LONG_STRING); return(OK); }
/*===========================================================================* * do_mount * *===========================================================================*/ PUBLIC int do_mount() { /* Perform the mount(name, mfile, rd_only) system call. */ register struct inode *rip, *root_ip; struct super_block *xp, *sp; dev_t dev; mode_t bits; int rdir, mdir; /* TRUE iff {root|mount} file is dir */ int i, r, found; struct fproc *tfp; /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); /* If 'name' is not for a block special file, return error. */ if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code); /* Scan super block table to see if dev already mounted & find a free slot.*/ sp = NIL_SUPER; found = FALSE; for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) { if (xp->s_dev == dev) { /* is it mounted already? */ found = TRUE; sp= xp; break; } if (xp->s_dev == NO_DEV) sp = xp; /* record free slot */ } if (found) { printf( "do_mount: s_imount = 0x%x (%x, %d), s_isup = 0x%x (%x, %d), fp_rootdir = 0x%x\n", xp->s_imount, xp->s_imount->i_dev, xp->s_imount->i_num, xp->s_isup, xp->s_isup->i_dev, xp->s_isup->i_num, fproc[FS_PROC_NR].fp_rootdir); /* It is possible that we have an old root lying around that * needs to be remounted. */ if (xp->s_imount != xp->s_isup || xp->s_isup == fproc[FS_PROC_NR].fp_rootdir) { /* Normally, s_imount refers to the mount point. For a root * filesystem, s_imount is equal to the root inode. We assume * that the root of FS is always the real root. If the two * inodes are different or if the root of FS is equal two the * root of the filesystem we found, we found a filesystem that * is in use. */ return(EBUSY); /* already mounted */ } if (root_dev == xp->s_dev) { panic("fs", "inconsistency remounting old root", NO_NUM); } /* Now get the inode of the file to be mounted on. */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { return(err_code); } if ( (rip = eat_path(user_path)) == NIL_INODE) { return(err_code); } r = OK; /* It may not be special. */ bits = rip->i_mode & I_TYPE; if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; /* Get the root inode of the mounted file system. */ root_ip= sp->s_isup; /* File types of 'rip' and 'root_ip' may not conflict. */ if (r == OK) { mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */ rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY); if (!mdir && rdir) r = EISDIR; } /* If error, return the mount point. */ if (r != OK) { put_inode(rip); return(r); } /* Nothing else can go wrong. Perform the mount. */ rip->i_mount = I_MOUNT; /* this bit says the inode is * mounted on */ put_inode(sp->s_imount); sp->s_imount = rip; sp->s_rd_only = m_in.rd_only; allow_newroot= 0; /* The root is now fixed */ return(OK); } if (sp == NIL_SUPER) return(ENFILE); /* no super block available */ /* Open the device the file system lives on. */ if (dev_open(dev, who_e, m_in.rd_only ? R_BIT : (R_BIT|W_BIT)) != OK) return(EINVAL); /* Make the cache forget about blocks it has open on the filesystem */ (void) do_sync(); invalidate(dev); /* Fill in the super block. */ sp->s_dev = dev; /* read_super() needs to know which dev */ r = read_super(sp); /* Is it recognized as a Minix filesystem? */ if (r != OK) { dev_close(dev); sp->s_dev = NO_DEV; return(r); } /* Now get the inode of the file to be mounted on. */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { dev_close(dev); sp->s_dev = NO_DEV; return(err_code); } if (strcmp(user_path, "/") == 0 && allow_newroot) { printf("Replacing root\n"); /* Get the root inode of the mounted file system. */ if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code; if (root_ip != NIL_INODE && root_ip->i_mode == 0) { r = EINVAL; } /* If error, return the super block and both inodes; release the * maps. */ if (r != OK) { put_inode(root_ip); (void) do_sync(); invalidate(dev); dev_close(dev); sp->s_dev = NO_DEV; return(r); } /* Nothing else can go wrong. Perform the mount. */ sp->s_imount = root_ip; dup_inode(root_ip); sp->s_isup = root_ip; sp->s_rd_only = m_in.rd_only; root_dev= dev; /* Replace all root and working directories */ for (i= 0, tfp= fproc; i<NR_PROCS; i++, tfp++) { if (tfp->fp_pid == PID_FREE) continue; if (tfp->fp_rootdir == NULL) panic("fs", "do_mount: null rootdir", i); put_inode(tfp->fp_rootdir); dup_inode(root_ip); tfp->fp_rootdir= root_ip; if (tfp->fp_workdir == NULL) panic("fs", "do_mount: null workdir", i); put_inode(tfp->fp_workdir); dup_inode(root_ip); tfp->fp_workdir= root_ip; } /* Leave the old filesystem lying around. */ return(OK); } if ( (rip = eat_path(user_path)) == NIL_INODE) { dev_close(dev); sp->s_dev = NO_DEV; return(err_code); } /* It may not be busy. */ r = OK; if (rip->i_count > 1) r = EBUSY; /* It may not be special. */ bits = rip->i_mode & I_TYPE; if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR; /* Get the root inode of the mounted file system. */ root_ip = NIL_INODE; /* if 'r' not OK, make sure this is defined */ if (r == OK) { if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code; } if (root_ip != NIL_INODE && root_ip->i_mode == 0) { r = EINVAL; } /* File types of 'rip' and 'root_ip' may not conflict. */ if (r == OK) { mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */ rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY); if (!mdir && rdir) r = EISDIR; } /* If error, return the super block and both inodes; release the maps. */ if (r != OK) { put_inode(rip); put_inode(root_ip); (void) do_sync(); invalidate(dev); dev_close(dev); sp->s_dev = NO_DEV; return(r); } /* Nothing else can go wrong. Perform the mount. */ rip->i_mount = I_MOUNT; /* this bit says the inode is mounted on */ sp->s_imount = rip; sp->s_isup = root_ip; sp->s_rd_only = m_in.rd_only; allow_newroot= 0; /* The root is now fixed */ return(OK); }
/*===========================================================================* * mount * *===========================================================================*/ PRIVATE int mount_fs(endpoint_t fs_e) { /* Perform the mount(name, mfile, rd_only) system call. */ int rdir, mdir; /* TRUE iff {root|mount} file is dir */ int i, r, found, isroot, replace_root; struct fproc *tfp; struct dmap *dp; dev_t dev; message m; struct vnode *root_node, *mounted_on = NULL, *bspec; struct vmnt *vmp; char *label; struct node_details res; SANITYCHECK; /* Only the super-user may do MOUNT. */ if (!super_user) return(EPERM); /* If FS not yet logged in, save message and suspend mount */ if (last_login_fs_e != fs_e) { mount_m_in = m_in; return SUSPEND; } /* Mount request got after FS login or * FS login arrived after a suspended mount */ last_login_fs_e = NONE; /* Clear endpoint field */ mount_m_in.m1_p3 = (char *) NONE; /* If 'name' is not for a block special file, return error. */ if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); /* Convert name to device number */ if ((dev = name_to_dev()) == NO_DEV) return(err_code); /* Check whether there is a block special file open which uses the * same device (partition) */ for (bspec = &vnode[0]; bspec < &vnode[NR_VNODES]; ++bspec) { if (bspec->v_ref_count > 0 && bspec->v_sdev == dev) { /* Found, sync the buffer cache */ req_sync(bspec->v_fs_e); break; /* Note: there are probably some blocks in the FS process' buffer * cache which contain data on this minor, although they will be * purged since the handling moves to the new FS process (if * everything goes well with the mount...) */ } } /* Didn't find? */ if (bspec == &vnode[NR_VNODES] && bspec->v_sdev != dev) bspec = NULL; /* Scan vmnt table to see if dev already mounted, if not, * find a free slot.*/ found = FALSE; vmp = NIL_VMNT; for (i = 0; i < NR_MNTS; ++i) { if (vmnt[i].m_dev == dev) { vmp = &vmnt[i]; found = TRUE; break; } else if (!vmp && vmnt[i].m_dev == NO_DEV) { vmp = &vmnt[i]; } } /* Partition was/is already mounted */ if (found) { /* It is possible that we have an old root lying around that * needs to be remounted. */ if (vmp->m_mounted_on || vmp->m_mounted_on == fproc[FS_PROC_NR].fp_rd) { /* Normally, m_mounted_on refers to the mount point. For a * root filesystem, m_mounted_on is equal to the root vnode. * We assume that the root of FS is always the real root. If * the two vnodes are different or if the root of FS is equal * to the root of the filesystem we found, we found a * filesystem that is in use. */ return EBUSY; /* already mounted */ } if(vmp->m_mounted_on) panic("vfs", "root unexpectedly mounted somewhere", NO_NUM); if (root_dev == vmp->m_dev) panic("fs", "inconsistency remounting old root", NO_NUM); /* Now get the inode of the file to be mounted on. */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { return(err_code); } /* Request lookup */ r = lookup_vp(0 /*flags*/, 0 /*!use_realuid*/, &mounted_on); if (r != OK) return r; if (mounted_on->v_ref_count != 1) { put_vnode(mounted_on); printf("vfs:mount_fs: mount point is busy\n"); return EBUSY; } /* Issue mountpoint request */ r = req_mountpoint(mounted_on->v_fs_e, mounted_on->v_inode_nr); if (r != OK) { put_vnode(mounted_on); printf("vfs:mount_fs: req_mountpoint_s failed with %d\n", r); return r; } /* Get the root inode of the mounted file system. */ root_node = vmp->m_root_node; /* File types may not conflict. */ if (r == OK) { mdir = ((mounted_on->v_mode & I_TYPE) == I_DIRECTORY); /* TRUE iff dir */ rdir = ((root_node->v_mode & I_TYPE) == I_DIRECTORY); if (!mdir && rdir) r = EISDIR; } /* If error, return the mount point. */ if (r != OK) { put_vnode(mounted_on); return(r); } /* Nothing else can go wrong. Perform the mount. */ vmp->m_mounted_on = mounted_on; vmp->m_flags = m_in.rd_only; allow_newroot = 0; /* The root is now fixed */ return(OK); } /* Fetch the name of the mountpoint */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) { return(err_code); } isroot= (strcmp(user_fullpath, "/") == 0); replace_root= (isroot && allow_newroot); if (!replace_root) { /* Get mount point and inform the FS it is on. */ #if 0 printf("vfs:mount_fs: mount point at '%s'\n", user_fullpath); #endif r = lookup_vp(0 /*flags*/, 0 /*!use_realuid*/, &mounted_on); if (r != OK) return r; /* Issue mountpoint request */ r = req_mountpoint(mounted_on->v_fs_e, mounted_on->v_inode_nr); if (r != OK) { put_vnode(mounted_on); printf("vfs:mount_fs: req_mountpoint_s failed with %d\n", r); return r; } } /* We'll need a vnode for the root inode, check whether there is one */ if ((root_node = get_free_vnode(__FILE__, __LINE__)) == NIL_VNODE) { printf("VFSmount: no free vnode available\n"); return ENFILE; } /* Get driver process' endpoint */ dp = &dmap[(dev >> MAJOR) & BYTE]; if (dp->dmap_driver == NONE) { printf("VFSmount: no driver for dev %x\n", dev); return(EINVAL); } label= dp->dmap_label; if (strlen(label) == 0) { panic(__FILE__, "vfs:mount_fs: no label for major", dev >> MAJOR); }