root/fs/super.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_fs_type
  2. lock_super
  3. free_super
  4. wait_on_super
  5. get_super
  6. put_super
  7. read_super
  8. do_umount
  9. sys_umount
  10. do_mount
  11. sys_mount
  12. mount_root

   1 /*
   2  *  linux/fs/super.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  * super.c contains code to handle the super-block tables.
   9  */
  10 #include <linux/config.h>
  11 #include <linux/sched.h>
  12 #include <linux/minix_fs.h>
  13 #include <linux/proc_fs.h>
  14 #include <linux/ext_fs.h>
  15 #include <linux/msdos_fs.h>
  16 #include <linux/kernel.h>
  17 #include <linux/stat.h>
  18 #include <linux/errno.h>
  19 
  20 #include <asm/system.h>
  21 #include <asm/segment.h>
  22 
  23 int sync_dev(int dev);
  24 void wait_for_keypress(void);
  25 void fcntl_init_locks(void);
  26 
  27 /* set_bit uses setb, as gas doesn't recognize setc */
  28 #define set_bit(bitnr,addr) ({ \
  29 register int __res __asm__("ax"); \
  30 __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
  31 __res; })
  32 
  33 struct super_block super_block[NR_SUPER];
  34 /* this is initialized in init/main.c */
  35 int ROOT_DEV = 0;
  36 
  37 /* Move into include file later */
  38 
  39 static struct file_system_type file_systems[] = {
  40         {minix_read_super,"minix"},
  41         {ext_read_super,"ext"},
  42         {msdos_read_super,"msdos"},
  43         {proc_read_super,"proc"},
  44         {NULL,NULL}
  45 };
  46 
  47 /* end of include file */
  48 
  49 struct file_system_type *get_fs_type(char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51         int a;
  52         
  53         for(a = 0 ; file_systems[a].read_super ; a++)
  54                 if (!strcmp(name,file_systems[a].name))
  55                         return(&file_systems[a]);
  56         return(NULL);
  57 }
  58 
  59 void lock_super(struct super_block * sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         cli();
  62         while (sb->s_lock)
  63                 sleep_on(&(sb->s_wait));
  64         sb->s_lock = 1;
  65         sti();
  66 }
  67 
  68 void free_super(struct super_block * sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70         sb->s_lock = 0;
  71         wake_up(&(sb->s_wait));
  72 }
  73 
  74 void wait_on_super(struct super_block * sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         cli();
  77         while (sb->s_lock)
  78                 sleep_on(&(sb->s_wait));
  79         sti();
  80 }
  81 
  82 struct super_block * get_super(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  83 {
  84         struct super_block * s;
  85 
  86         if (!dev)
  87                 return NULL;
  88         s = 0+super_block;
  89         while (s < NR_SUPER+super_block)
  90                 if (s->s_dev == dev) {
  91                         wait_on_super(s);
  92                         if (s->s_dev == dev)
  93                                 return s;
  94                         s = 0+super_block;
  95                 } else
  96                         s++;
  97         return NULL;
  98 }
  99 
 100 void put_super(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102         struct super_block * sb;
 103 
 104         if (dev == ROOT_DEV) {
 105                 printk("root diskette changed: prepare for armageddon\n\r");
 106                 return;
 107         }
 108         if (!(sb = get_super(dev)))
 109                 return;
 110         if (sb->s_covered) {
 111                 printk("Mounted disk changed - tssk, tssk\n\r");
 112                 return;
 113         }
 114         if (sb->s_op && sb->s_op->put_super)
 115                 sb->s_op->put_super(sb);
 116 }
 117 
 118 static struct super_block * read_super(int dev,char *name,int flags,void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120         struct super_block * s;
 121         struct file_system_type *type;
 122 
 123         if (!dev)
 124                 return NULL;
 125         check_disk_change(dev);
 126         if (s = get_super(dev))
 127                 return s;
 128         if (!(type = get_fs_type(name))) {
 129                 printk("get fs type failed %s\n",name);
 130                 return NULL;
 131         }
 132         for (s = 0+super_block ;; s++) {
 133                 if (s >= NR_SUPER+super_block)
 134                         return NULL;
 135                 if (!s->s_dev)
 136                         break;
 137         }
 138         s->s_dev = dev;
 139         s->s_flags = flags;
 140         if (!type->read_super(s,data)) {
 141                 s->s_dev = 0;
 142                 return NULL;
 143         }
 144         s->s_dev = dev;
 145         s->s_covered = NULL;
 146         s->s_rd_only = 0;
 147         s->s_dirt = 0;
 148         return s;
 149 }
 150 
 151 static int do_umount(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 152 {
 153         struct super_block * sb;
 154         struct inode * inode;
 155 
 156         if (dev==ROOT_DEV)
 157                 return -EBUSY;
 158         if (!(sb=get_super(dev)) || !(sb->s_covered))
 159                 return -ENOENT;
 160         if (!sb->s_covered->i_mount)
 161                 printk("Mounted inode has i_mount=0\n");
 162         for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
 163                 if (inode->i_dev==dev && inode->i_count)
 164                         if (inode == sb->s_mounted && inode->i_count == 1)
 165                                 continue;
 166                         else
 167                                 return -EBUSY;
 168         sb->s_covered->i_mount=0;
 169         iput(sb->s_covered);
 170         sb->s_covered = NULL;
 171         iput(sb->s_mounted);
 172         sb->s_mounted = NULL;
 173         if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
 174                 sb->s_op->write_super (sb);
 175         put_super(dev);
 176         return 0;
 177 }
 178 
 179 int sys_umount(char * dev_name)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181         struct inode * inode;
 182         int dev,retval;
 183 
 184         if (!suser())
 185                 return -EPERM;
 186         retval = namei(dev_name,&inode);
 187         if (retval)
 188                 return retval;
 189         dev = inode->i_rdev;
 190         if (!S_ISBLK(inode->i_mode)) {
 191                 iput(inode);
 192                 return -ENOTBLK;
 193         }
 194         retval = do_umount(dev);
 195         if (!retval && MAJOR(dev) < MAX_BLKDEV &&
 196             blkdev_fops[MAJOR(dev)]->release)
 197                 blkdev_fops[MAJOR(dev)]->release(inode,NULL);
 198         iput(inode);
 199         if (retval) return retval;
 200         sync_dev(dev);
 201         return 0;
 202 }
 203 
 204 /*
 205  * do_mount() does the actual mounting after sys_mount has done the ugly
 206  * parameter parsing. When enough time has gone by, and everything uses the
 207  * new mount() parameters, sys_mount() can then be cleaned up.
 208  *
 209  * We cannot mount a filesystem if it has active, used, or dirty inodes.
 210  * We also have to flush all inode-data for this device, as the new mount
 211  * might need new info.
 212  */
 213 static int do_mount(int dev, const char * dir, char * type, int flags, void * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         struct inode * inode, * dir_i;
 216         struct super_block * sb;
 217         int error;
 218 
 219         error = namei(dir,&dir_i);
 220         if (error)
 221                 return error;
 222         if (dir_i->i_count != 1 || dir_i->i_mount) {
 223                 iput(dir_i);
 224                 return -EBUSY;
 225         }
 226         if (!S_ISDIR(dir_i->i_mode)) {
 227                 iput(dir_i);
 228                 return -EPERM;
 229         }
 230         for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
 231                 if (inode->i_dev != dev)
 232                         continue;
 233                 if (inode->i_count || inode->i_dirt || inode->i_lock) {
 234                         iput(dir_i);
 235                         return -EBUSY;
 236                 }
 237                 inode->i_dev = 0;
 238         }
 239         sb = read_super(dev,type,flags,data);
 240         if (!sb || sb->s_covered) {
 241                 iput(dir_i);
 242                 return -EBUSY;
 243         }
 244         sb->s_flags = flags;
 245         sb->s_covered = dir_i;
 246         dir_i->i_mount = 1;
 247         return 0;               /* we don't iput(dir_i) - see umount */
 248 }
 249 
 250 /*
 251  * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
 252  * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
 253  *
 254  * data is a (void *) that can point to any structure up to 4095 bytes, which
 255  * can contain arbitrary fs-dependent information (or be NULL).
 256  *
 257  * NOTE! As old versions of mount() didn't use this setup, the flags has to have
 258  * a special 16-bit magic number in the hight word: 0xC0ED. If this magic word
 259  * isn't present, the flags and data info isn't used, as the syscall assumes we
 260  * are talking to an older version that didn't understand them.
 261  */
 262 int sys_mount(char * dev_name, char * dir_name, char * type,
     /* [previous][next][first][last][top][bottom][index][help] */
 263         unsigned long new_flags, void *data)
 264 {
 265         struct inode * inode;
 266         int dev;
 267         int retval;
 268         char tmp[100],*t;
 269         int i;
 270         unsigned long flags = 0;
 271         unsigned long page = 0;
 272 
 273         if (!suser())
 274                 return -EPERM;
 275         retval = namei(dev_name,&inode);
 276         if (retval)
 277                 return retval;
 278         dev = inode->i_rdev;
 279         if (!S_ISBLK(inode->i_mode))
 280                 retval = -EPERM;
 281         else if (IS_NODEV(inode))
 282                 retval = -EACCES;
 283         if (!retval && blkdev_fops[MAJOR(dev)]->open)
 284                 retval = blkdev_fops[MAJOR(dev)]->open(inode,NULL);
 285         if (retval) {
 286                 iput(inode);
 287                 return retval;
 288         }
 289         if ((new_flags & 0xffff0000) == 0xC0ED0000) {
 290                 flags = new_flags & 0xffff;
 291                 if (data && (unsigned long) data < TASK_SIZE)
 292                         page = get_free_page(GFP_KERNEL);
 293         }
 294         if (page) {
 295                 i = TASK_SIZE - (unsigned long) data;
 296                 if (i < 0 || i > 4095)
 297                         i = 4095;
 298                 memcpy_fromfs((void *) page,data,i);
 299         }
 300         if (type) {
 301                 for (i = 0 ; i < 100 ; i++)
 302                         if (!(tmp[i] = get_fs_byte(type++)))
 303                                 break;
 304                 t = tmp;
 305         } else
 306                 t = "minix";
 307         retval = do_mount(dev,dir_name,t,flags,(void *) page);
 308         free_page(page);
 309         if (retval && blkdev_fops[MAJOR(dev)]->release)
 310                 blkdev_fops[MAJOR(dev)]->release(inode,NULL);
 311         iput(inode);
 312         return retval;
 313 }
 314 
 315 void mount_root(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317         int i;
 318         struct file_system_type * fs_type = file_systems;
 319         struct super_block * p;
 320         struct inode * mi;
 321 
 322         if (32 != sizeof (struct minix_inode))
 323                 panic("bad i-node size");
 324         for(i=0;i<NR_FILE;i++)
 325                 file_table[i].f_count=0;
 326         fcntl_init_locks();
 327         if (MAJOR(ROOT_DEV) == 2) {
 328                 printk("Insert root floppy and press ENTER");
 329                 wait_for_keypress();
 330         }
 331         for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
 332                 p->s_dev = 0;
 333                 p->s_blocksize = 0;
 334                 p->s_lock = 0;
 335                 p->s_wait = NULL;
 336                 p->s_mounted = p->s_covered = NULL;
 337         }
 338         while (fs_type->read_super && fs_type->name) {
 339                 p = read_super(ROOT_DEV,fs_type->name,0,NULL);
 340                 if (p) {
 341                         mi = p->s_mounted;
 342                         mi->i_count += 3 ;      /* NOTE! it is logically used 4 times, not 1 */
 343                         p->s_covered = mi;
 344                         p->s_flags = 0;
 345                         current->pwd = mi;
 346                         current->root = mi;
 347                         return;
 348                 }
 349                 fs_type++;
 350         }
 351         panic("Unable to mount root");
 352 }

/* [previous][next][first][last][top][bottom][index][help] */