mount.c

Go to the documentation of this file.
00001 /* This file performs the MOUNT and UMOUNT system calls.
00002  *
00003  * The entry points into this file are
00004  *   do_mount:  perform the MOUNT system call
00005  *   do_umount: perform the UMOUNT system call
00006  */
00007 
00008 #include "fs.h"
00009 #include <fcntl.h>
00010 #include <string.h>
00011 #include <minix/com.h>
00012 #include <sys/stat.h>
00013 #include "buf.h"
00014 #include "file.h"
00015 #include "fproc.h"
00016 #include "inode.h"
00017 #include "param.h"
00018 #include "super.h"
00019 
00020 /* Allow the root to be replaced before the first 'real' mount. */
00021 PRIVATE int allow_newroot= 1;
00022 
00023 FORWARD _PROTOTYPE( dev_t name_to_dev, (char *path)                     );
00024 
00025 /*===========================================================================*
00026  *                              do_mount                                     *
00027  *===========================================================================*/
00028 PUBLIC int do_mount()
00029 {
00030 /* Perform the mount(name, mfile, rd_only) system call. */
00031 
00032   register struct inode *rip, *root_ip;
00033   struct super_block *xp, *sp;
00034   dev_t dev;
00035   mode_t bits;
00036   int rdir, mdir;               /* TRUE iff {root|mount} file is dir */
00037   int i, r, found;
00038   struct fproc *tfp;
00039 
00040   /* Only the super-user may do MOUNT. */
00041   if (!super_user) return(EPERM);
00042 
00043   /* If 'name' is not for a block special file, return error. */
00044   if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
00045   if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
00046 
00047   /* Scan super block table to see if dev already mounted & find a free slot.*/
00048   sp = NIL_SUPER;
00049   found = FALSE;
00050   for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) {
00051         if (xp->s_dev == dev)
00052         {
00053                 /* is it mounted already? */
00054                 found = TRUE;
00055                 sp= xp;
00056                 break;
00057         }
00058         if (xp->s_dev == NO_DEV) sp = xp;       /* record free slot */
00059   }
00060   if (found)
00061   {
00062         printf(
00063 "do_mount: s_imount = 0x%x (%x, %d), s_isup = 0x%x (%x, %d), fp_rootdir = 0x%x\n",
00064                 xp->s_imount, xp->s_imount->i_dev, xp->s_imount->i_num,
00065                 xp->s_isup, xp->s_isup->i_dev, xp->s_isup->i_num,
00066                 fproc[FS_PROC_NR].fp_rootdir);
00067         /* It is possible that we have an old root lying around that 
00068          * needs to be remounted.
00069          */
00070         if (xp->s_imount != xp->s_isup ||
00071                 xp->s_isup == fproc[FS_PROC_NR].fp_rootdir)
00072         {
00073                 /* Normally, s_imount refers to the mount point. For a root
00074                  * filesystem, s_imount is equal to the root inode. We assume
00075                  * that the root of FS is always the real root. If the two
00076                  * inodes are different or if the root of FS is equal two the
00077                  * root of the filesystem we found, we found a filesystem that
00078                  * is in use.
00079                  */
00080                 return(EBUSY);  /* already mounted */
00081         }
00082 
00083         if (root_dev == xp->s_dev)
00084         {
00085                 panic("fs", "inconsistency remounting old root",
00086                         NO_NUM);
00087         }
00088 
00089         /* Now get the inode of the file to be mounted on. */
00090         if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
00091                 return(err_code);
00092         }
00093 
00094         if ( (rip = eat_path(user_path)) == NIL_INODE) {
00095                 return(err_code);
00096         }
00097 
00098         r = OK;
00099 
00100         /* It may not be special. */
00101         bits = rip->i_mode & I_TYPE;
00102         if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL)
00103                 r = ENOTDIR;
00104 
00105         /* Get the root inode of the mounted file system. */
00106         root_ip= sp->s_isup;
00107 
00108         /* File types of 'rip' and 'root_ip' may not conflict. */
00109         if (r == OK) {
00110                 mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY); 
00111                                                 /* TRUE iff dir */
00112                 rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
00113                 if (!mdir && rdir) r = EISDIR;
00114         }
00115 
00116         /* If error, return the mount point. */
00117         if (r != OK) {
00118                 put_inode(rip);
00119                 return(r);
00120         }
00121 
00122         /* Nothing else can go wrong.  Perform the mount. */
00123         rip->i_mount = I_MOUNT; /* this bit says the inode is
00124                                  * mounted on
00125                                  */
00126         put_inode(sp->s_imount);
00127         sp->s_imount = rip;
00128         sp->s_rd_only = m_in.rd_only;
00129         allow_newroot= 0;               /* The root is now fixed */
00130         return(OK);
00131   }
00132   if (sp == NIL_SUPER) return(ENFILE);  /* no super block available */
00133 
00134   /* Open the device the file system lives on. */
00135   if (dev_open(dev, who_e, m_in.rd_only ? R_BIT : (R_BIT|W_BIT)) != OK) 
00136         return(EINVAL);
00137 
00138   /* Make the cache forget about blocks it has open on the filesystem */
00139   (void) do_sync();
00140   invalidate(dev);
00141 
00142   /* Fill in the super block. */
00143   sp->s_dev = dev;              /* read_super() needs to know which dev */
00144   r = read_super(sp);
00145 
00146   /* Is it recognized as a Minix filesystem? */
00147   if (r != OK) {
00148         dev_close(dev);
00149         sp->s_dev = NO_DEV;
00150         return(r);
00151   }
00152 
00153   /* Now get the inode of the file to be mounted on. */
00154   if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
00155         dev_close(dev);
00156         sp->s_dev = NO_DEV;
00157         return(err_code);
00158   }
00159 
00160   if (strcmp(user_path, "/") == 0 && allow_newroot)
00161   {
00162         printf("Replacing root\n");
00163 
00164         /* Get the root inode of the mounted file system. */
00165         if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
00166         if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
00167                 r = EINVAL;
00168         }
00169 
00170         /* If error, return the super block and both inodes; release the
00171          * maps.
00172          */
00173         if (r != OK) {
00174                 put_inode(root_ip);
00175                 (void) do_sync();
00176                 invalidate(dev);
00177                 dev_close(dev);
00178                 sp->s_dev = NO_DEV;
00179                 return(r);
00180         }
00181 
00182         /* Nothing else can go wrong.  Perform the mount. */
00183         sp->s_imount = root_ip;
00184         dup_inode(root_ip);
00185         sp->s_isup = root_ip;
00186         sp->s_rd_only = m_in.rd_only;
00187         root_dev= dev;
00188 
00189         /* Replace all root and working directories */
00190         for (i= 0, tfp= fproc; i<NR_PROCS; i++, tfp++)
00191         {
00192                 if (tfp->fp_pid == PID_FREE)
00193                         continue;
00194                 if (tfp->fp_rootdir == NULL)
00195                         panic("fs", "do_mount: null rootdir", i);
00196                 put_inode(tfp->fp_rootdir);
00197                 dup_inode(root_ip);
00198                 tfp->fp_rootdir= root_ip;
00199 
00200                 if (tfp->fp_workdir == NULL)
00201                         panic("fs", "do_mount: null workdir", i);
00202                 put_inode(tfp->fp_workdir);
00203                 dup_inode(root_ip);
00204                 tfp->fp_workdir= root_ip;
00205         }
00206 
00207         /* Leave the old filesystem lying around. */
00208         return(OK);
00209   }
00210 
00211   if ( (rip = eat_path(user_path)) == NIL_INODE) {
00212         dev_close(dev);
00213         sp->s_dev = NO_DEV;
00214         return(err_code);
00215   }
00216 
00217   /* It may not be busy. */
00218   r = OK;
00219   if (rip->i_count > 1) r = EBUSY;
00220 
00221   /* It may not be special. */
00222   bits = rip->i_mode & I_TYPE;
00223   if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR;
00224 
00225   /* Get the root inode of the mounted file system. */
00226   root_ip = NIL_INODE;          /* if 'r' not OK, make sure this is defined */
00227   if (r == OK) {
00228         if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
00229   }
00230   if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
00231         r = EINVAL;
00232   }
00233 
00234   /* File types of 'rip' and 'root_ip' may not conflict. */
00235   if (r == OK) {
00236         mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE iff dir */
00237         rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
00238         if (!mdir && rdir) r = EISDIR;
00239   }
00240 
00241   /* If error, return the super block and both inodes; release the maps. */
00242   if (r != OK) {
00243         put_inode(rip);
00244         put_inode(root_ip);
00245         (void) do_sync();
00246         invalidate(dev);
00247         dev_close(dev);
00248         sp->s_dev = NO_DEV;
00249         return(r);
00250   }
00251 
00252   /* Nothing else can go wrong.  Perform the mount. */
00253   rip->i_mount = I_MOUNT;       /* this bit says the inode is mounted on */
00254   sp->s_imount = rip;
00255   sp->s_isup = root_ip;
00256   sp->s_rd_only = m_in.rd_only;
00257   allow_newroot= 0;             /* The root is now fixed */
00258   return(OK);
00259 }
00260 
00261 /*===========================================================================*
00262  *                              do_umount                                    *
00263  *===========================================================================*/
00264 PUBLIC int do_umount()
00265 {
00266 /* Perform the umount(name) system call. */
00267   dev_t dev;
00268 
00269   /* Only the super-user may do UMOUNT. */
00270   if (!super_user) return(EPERM);
00271 
00272   /* If 'name' is not for a block special file, return error. */
00273   if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
00274   if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
00275 
00276   return(unmount(dev));
00277 }
00278 
00279 /*===========================================================================*
00280  *                              unmount                                      *
00281  *===========================================================================*/
00282 PUBLIC int unmount(dev)
00283 Dev_t dev;
00284 {
00285 /* Unmount a file system by device number. */
00286   register struct inode *rip;
00287   struct super_block *sp, *sp1;
00288   int count;
00289 
00290   /* See if the mounted device is busy.  Only 1 inode using it should be
00291    * open -- the root inode -- and that inode only 1 time.
00292    */
00293   count = 0;
00294   for (rip = &inode[0]; rip< &inode[NR_INODES]; rip++)
00295         if (rip->i_count > 0 && rip->i_dev == dev) count += rip->i_count;
00296   if (count > 1) return(EBUSY); /* can't umount a busy file system */
00297 
00298   /* Find the super block. */
00299   sp = NIL_SUPER;
00300   for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) {
00301         if (sp1->s_dev == dev) {
00302                 sp = sp1;
00303                 break;
00304         }
00305   }
00306 
00307   /* Sync the disk, and invalidate cache. */
00308   (void) do_sync();             /* force any cached blocks out of memory */
00309   invalidate(dev);              /* invalidate cache entries for this dev */
00310   if (sp == NIL_SUPER) {
00311         return(EINVAL);
00312   }
00313 
00314   /* Close the device the file system lives on. */
00315   dev_close(dev);
00316 
00317   /* Finish off the unmount. */
00318   sp->s_imount->i_mount = NO_MOUNT;     /* inode returns to normal */
00319   put_inode(sp->s_imount);      /* release the inode mounted on */
00320   put_inode(sp->s_isup);        /* release the root inode of the mounted fs */
00321   sp->s_imount = NIL_INODE;
00322   sp->s_dev = NO_DEV;
00323   return(OK);
00324 }
00325 
00326 /*===========================================================================*
00327  *                              name_to_dev                                  *
00328  *===========================================================================*/
00329 PRIVATE dev_t name_to_dev(path)
00330 char *path;                     /* pointer to path name */
00331 {
00332 /* Convert the block special file 'path' to a device number.  If 'path'
00333  * is not a block special file, return error code in 'err_code'.
00334  */
00335 
00336   register struct inode *rip;
00337   register dev_t dev;
00338 
00339   /* If 'path' can't be opened, give up immediately. */
00340   if ( (rip = eat_path(path)) == NIL_INODE) return(NO_DEV);
00341 
00342   /* If 'path' is not a block special file, return error. */
00343   if ( (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) {
00344         err_code = ENOTBLK;
00345         put_inode(rip);
00346         return(NO_DEV);
00347   }
00348 
00349   /* Extract the device number. */
00350   dev = (dev_t) rip->i_zone[0];
00351   put_inode(rip);
00352   return(dev);
00353 }

Generated on Fri Apr 14 22:57:09 2006 for minix by  doxygen 1.4.6