root/fs/super.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_fs_type
  2. __wait_on_super
  3. sync_supers
  4. get_super
  5. put_super
  6. read_super
  7. get_unnamed_dev
  8. put_unnamed_dev
  9. do_umount
  10. sys_umount
  11. do_mount
  12. do_remount
  13. sys_mount
  14. 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/kernel.h>
  13 #include <linux/stat.h>
  14 #include <linux/errno.h>
  15 #include <linux/string.h>
  16 #include <linux/locks.h>
  17 
  18 #include <asm/system.h>
  19 #include <asm/segment.h>
  20 
  21  
  22 /*
  23  * The definition of file_systems that used to be here is now in
  24  * filesystems.c.  Now super.c contains no fs specific code.  -- jrs
  25  */
  26 
  27 extern struct file_system_type file_systems[];
  28 extern struct file_operations * blkdev_fops[];
  29 
  30 extern void wait_for_keypress(void);
  31 extern void fcntl_init_locks(void);
  32 
  33 extern int root_mountflags;
  34 
  35 struct super_block super_block[NR_SUPER];
  36 
  37 /* this is initialized in init/main.c */
  38 dev_t ROOT_DEV = 0;
  39 
  40 struct file_system_type *get_fs_type(char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42         int a;
  43         
  44         if (!name)
  45                 return &file_systems[0];
  46         for(a = 0 ; file_systems[a].read_super ; a++)
  47                 if (!strcmp(name,file_systems[a].name))
  48                         return(&file_systems[a]);
  49         return NULL;
  50 }
  51 
  52 void __wait_on_super(struct super_block * sb)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54         struct wait_queue wait = { current, NULL };
  55 
  56         add_wait_queue(&sb->s_wait, &wait);
  57 repeat:
  58         current->state = TASK_UNINTERRUPTIBLE;
  59         if (sb->s_lock) {
  60                 schedule();
  61                 goto repeat;
  62         }
  63         remove_wait_queue(&sb->s_wait, &wait);
  64         current->state = TASK_RUNNING;
  65 }
  66 
  67 void sync_supers(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69         struct super_block * sb;
  70 
  71         for (sb = super_block + 0 ; sb < super_block + NR_SUPER ; sb++) {
  72                 if (!sb->s_dev)
  73                         continue;
  74                 if (dev && sb->s_dev != dev)
  75                         continue;
  76                 wait_on_super(sb);
  77                 if (!sb->s_dev || !sb->s_dirt)
  78                         continue;
  79                 if (dev && (dev != sb->s_dev))
  80                         continue;
  81                 if (sb->s_op && sb->s_op->write_super)
  82                         sb->s_op->write_super(sb);
  83         }
  84 }
  85 
  86 static struct super_block * get_super(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         struct super_block * s;
  89 
  90         if (!dev)
  91                 return NULL;
  92         s = 0+super_block;
  93         while (s < NR_SUPER+super_block)
  94                 if (s->s_dev == dev) {
  95                         wait_on_super(s);
  96                         if (s->s_dev == dev)
  97                                 return s;
  98                         s = 0+super_block;
  99                 } else
 100                         s++;
 101         return NULL;
 102 }
 103 
 104 void put_super(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106         struct super_block * sb;
 107 
 108         if (dev == ROOT_DEV) {
 109                 printk("VFS: Root device %d/%d: prepare for armageddon\n",
 110                                                         MAJOR(dev), MINOR(dev));
 111                 return;
 112         }
 113         if (!(sb = get_super(dev)))
 114                 return;
 115         if (sb->s_covered) {
 116                 printk("VFS: Mounted device %d/%d - tssk, tssk\n",
 117                                                 MAJOR(dev), MINOR(dev));
 118                 return;
 119         }
 120         if (sb->s_op && sb->s_op->put_super)
 121                 sb->s_op->put_super(sb);
 122 }
 123 
 124 static struct super_block * read_super(dev_t dev,char *name,int flags,
     /* [previous][next][first][last][top][bottom][index][help] */
 125                                        void *data, int silent)
 126 {
 127         struct super_block * s;
 128         struct file_system_type *type;
 129 
 130         if (!dev)
 131                 return NULL;
 132         check_disk_change(dev);
 133         s = get_super(dev);
 134         if (s)
 135                 return s;
 136         if (!(type = get_fs_type(name))) {
 137                 printk("VFS: on device %d/%d: get_fs_type(%s) failed\n",
 138                                                 MAJOR(dev), MINOR(dev), name);
 139                 return NULL;
 140         }
 141         for (s = 0+super_block ;; s++) {
 142                 if (s >= NR_SUPER+super_block)
 143                         return NULL;
 144                 if (!s->s_dev)
 145                         break;
 146         }
 147         s->s_dev = dev;
 148         s->s_flags = flags;
 149         if (!type->read_super(s,data, silent)) {
 150                 s->s_dev = 0;
 151                 return NULL;
 152         }
 153         s->s_dev = dev;
 154         s->s_covered = NULL;
 155         s->s_rd_only = 0;
 156         s->s_dirt = 0;
 157         return s;
 158 }
 159 
 160 /*
 161  * Unnamed block devices are dummy devices used by virtual
 162  * filesystems which don't use real block-devices.  -- jrs
 163  */
 164 
 165 static char unnamed_dev_in_use[256];
 166 
 167 static dev_t get_unnamed_dev(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169         static int first_use = 0;
 170         int i;
 171 
 172         if (first_use == 0) {
 173                 first_use = 1;
 174                 memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use));
 175                 unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */
 176         }
 177         for (i = 0; i < 256; i++) {
 178                 if (!unnamed_dev_in_use[i]) {
 179                         unnamed_dev_in_use[i] = 1;
 180                         return (UNNAMED_MAJOR << 8) | i;
 181                 }
 182         }
 183         return 0;
 184 }
 185 
 186 static void put_unnamed_dev(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188         if (!dev)
 189                 return;
 190         if (!unnamed_dev_in_use[dev]) {
 191                 printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",
 192                                                         MAJOR(dev), MINOR(dev));
 193                 return;
 194         }
 195         unnamed_dev_in_use[dev] = 0;
 196 }
 197 
 198 static int do_umount(dev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200         struct super_block * sb;
 201 
 202         if (dev==ROOT_DEV)
 203                 return -EBUSY;
 204         if (!(sb=get_super(dev)) || !(sb->s_covered))
 205                 return -ENOENT;
 206         if (!sb->s_covered->i_mount)
 207                 printk("VFS: umount(%d/%d): mounted inode has i_mount=0\n",
 208                                                         MAJOR(dev), MINOR(dev));
 209         if (!fs_may_umount(dev, sb->s_mounted))
 210                 return -EBUSY;
 211         sb->s_covered->i_mount=0;
 212         iput(sb->s_covered);
 213         sb->s_covered = NULL;
 214         iput(sb->s_mounted);
 215         sb->s_mounted = NULL;
 216         if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
 217                 sb->s_op->write_super(sb);
 218         put_super(dev);
 219         return 0;
 220 }
 221 
 222 /*
 223  * Now umount can handle mount points as well as block devices.
 224  * This is important for filesystems which use unnamed block devices.
 225  *
 226  * There is a little kludge here with the dummy_inode.  The current
 227  * vfs release functions only use the r_dev field in the inode so
 228  * we give them the info they need without using a real inode.
 229  * If any other fields are ever needed by any block device release
 230  * functions, they should be faked here.  -- jrs
 231  */
 232 
 233 int sys_umount(char * name)
     /* [previous][next][first][last][top][bottom][index][help] */
 234 {
 235         struct inode * inode;
 236         dev_t dev;
 237         int retval;
 238         struct inode dummy_inode;
 239         struct file_operations * fops;
 240 
 241         if (!suser())
 242                 return -EPERM;
 243         retval = namei(name,&inode);
 244         if (retval)
 245                 return retval;
 246         if (S_ISBLK(inode->i_mode)) {
 247                 dev = inode->i_rdev;
 248                 if (IS_NODEV(inode)) {
 249                         iput(inode);
 250                         return -EACCES;
 251                 }
 252         } else if (S_ISDIR(inode->i_mode)) {
 253                 if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted) {
 254                         iput(inode);
 255                         return -EINVAL;
 256                 }
 257                 dev = inode->i_sb->s_dev;
 258                 iput(inode);
 259                 memset(&dummy_inode, 0, sizeof(dummy_inode));
 260                 dummy_inode.i_rdev = dev;
 261                 inode = &dummy_inode;
 262         } else {
 263                 iput(inode);
 264                 return -EINVAL;
 265         }
 266         if (MAJOR(dev) >= MAX_BLKDEV) {
 267                 iput(inode);
 268                 return -ENXIO;
 269         }
 270         if (!(retval = do_umount(dev))) {
 271                 fops = blkdev_fops[MAJOR(dev)];
 272                 if (fops && fops->release)
 273                         fops->release(inode,NULL);
 274                 if (MAJOR(dev) == UNNAMED_MAJOR)
 275                         put_unnamed_dev(dev);
 276         }
 277         if (inode != &dummy_inode)
 278                 iput(inode);
 279         if (retval)
 280                 return retval;
 281         sync_dev(dev);
 282         return 0;
 283 }
 284 
 285 /*
 286  * do_mount() does the actual mounting after sys_mount has done the ugly
 287  * parameter parsing. When enough time has gone by, and everything uses the
 288  * new mount() parameters, sys_mount() can then be cleaned up.
 289  *
 290  * We cannot mount a filesystem if it has active, used, or dirty inodes.
 291  * We also have to flush all inode-data for this device, as the new mount
 292  * might need new info.
 293  */
 294 static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296         struct inode * dir_i;
 297         struct super_block * sb;
 298         int error;
 299 
 300         error = namei(dir,&dir_i);
 301         if (error)
 302                 return error;
 303         if (dir_i->i_count != 1 || dir_i->i_mount) {
 304                 iput(dir_i);
 305                 return -EBUSY;
 306         }
 307         if (!S_ISDIR(dir_i->i_mode)) {
 308                 iput(dir_i);
 309                 return -EPERM;
 310         }
 311         if (!fs_may_mount(dev)) {
 312                 iput(dir_i);
 313                 return -EBUSY;
 314         }
 315         sb = read_super(dev,type,flags,data,0);
 316         if (!sb || sb->s_covered) {
 317                 iput(dir_i);
 318                 return -EBUSY;
 319         }
 320         sb->s_covered = dir_i;
 321         dir_i->i_mount = 1;
 322         return 0;               /* we don't iput(dir_i) - see umount */
 323 }
 324 
 325 
 326 /*
 327  * Alters the mount flags of a mounted file system. Only the mount point
 328  * is used as a reference - file system type and the device are ignored.
 329  * FS-specific mount options can't be altered by remounting.
 330  */
 331 
 332 static int do_remount(const char *dir,int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334         struct inode *dir_i;
 335         int retval;
 336 
 337         retval = namei(dir,&dir_i);
 338         if (retval)
 339                 return retval;
 340         if (dir_i != dir_i->i_sb->s_mounted) {
 341                 iput(dir_i);
 342                 return -EINVAL;
 343         }
 344         dir_i->i_sb->s_flags = (dir_i->i_sb->s_flags & ~MS_RMT_MASK) |
 345                 (flags & MS_RMT_MASK);
 346         iput(dir_i);
 347         return 0;
 348 }
 349 
 350 
 351 /*
 352  * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
 353  * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
 354  *
 355  * data is a (void *) that can point to any structure up to 4095 bytes, which
 356  * can contain arbitrary fs-dependent information (or be NULL).
 357  *
 358  * NOTE! As old versions of mount() didn't use this setup, the flags has to have
 359  * a special 16-bit magic number in the hight word: 0xC0ED. If this magic word
 360  * isn't present, the flags and data info isn't used, as the syscall assumes we
 361  * are talking to an older version that didn't understand them.
 362  */
 363 int sys_mount(char * dev_name, char * dir_name, char * type,
     /* [previous][next][first][last][top][bottom][index][help] */
 364         unsigned long new_flags, void * data)
 365 {
 366         struct file_system_type * fstype;
 367         struct inode * inode;
 368         struct file_operations * fops;
 369         dev_t dev;
 370         int retval;
 371         char tmp[100], * t;
 372         int i;
 373         unsigned long flags = 0;
 374         unsigned long page = 0;
 375 
 376         if (!suser())
 377                 return -EPERM;
 378         if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
 379                 return do_remount(dir_name,new_flags & ~MS_MGC_MSK & ~MS_REMOUNT);
 380         }
 381         if (type) {
 382                 for (i = 0 ; i < 100 ; i++) {
 383                         if (TASK_SIZE <= (unsigned long) type)
 384                                 return -EFAULT;
 385                         if (!(tmp[i] = get_fs_byte(type++)))
 386                                 break;
 387                 }
 388                 t = tmp;
 389         } else
 390                 t = NULL;
 391         if (!(fstype = get_fs_type(t)))
 392                 return -ENODEV;
 393         t = fstype->name;
 394         if (fstype->requires_dev) {
 395                 retval = namei(dev_name,&inode);
 396                 if (retval)
 397                         return retval;
 398                 if (!S_ISBLK(inode->i_mode)) {
 399                         iput(inode);
 400                         return -ENOTBLK;
 401                 }
 402                 if (IS_NODEV(inode)) {
 403                         iput(inode);
 404                         return -EACCES;
 405                 }
 406                 dev = inode->i_rdev;
 407                 if (MAJOR(dev) >= MAX_BLKDEV) {
 408                         iput(inode);
 409                         return -ENXIO;
 410                 }
 411         } else {
 412                 if (!(dev = get_unnamed_dev()))
 413                         return -EMFILE;
 414                 inode = NULL;
 415         }
 416         fops = blkdev_fops[MAJOR(dev)];
 417         if (fops && fops->open) {
 418                 retval = fops->open(inode,NULL);
 419                 if (retval) {
 420                         iput(inode);
 421                         return retval;
 422                 }
 423         }
 424         if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
 425                 flags = new_flags & ~MS_MGC_MSK;
 426                 if (data) {
 427                         if ((unsigned long) data >= TASK_SIZE) {
 428                                 iput(inode);
 429                                 return -EFAULT;
 430                         }
 431                         page = get_free_page(GFP_KERNEL);
 432                         i = TASK_SIZE - (unsigned long) data;
 433                         if (i < 0 || i > 4095)
 434                                 i = 4095;
 435                         memcpy_fromfs((void *) page,data,i);
 436                 }
 437         }
 438         retval = do_mount(dev,dir_name,t,flags,(void *) page);
 439         free_page(page);
 440         if (retval && fops && fops->release)
 441                 fops->release(inode,NULL);
 442         iput(inode);
 443         return retval;
 444 }
 445 
 446 void mount_root(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 447 {
 448         struct file_system_type * fs_type;
 449         struct super_block * sb;
 450         struct inode * inode;
 451 
 452         memset(super_block, 0, sizeof(super_block));
 453         fcntl_init_locks();
 454         if (MAJOR(ROOT_DEV) == 2) {
 455                 printk("VFS: Insert root floppy and press ENTER");
 456                 wait_for_keypress();
 457         }
 458         for (fs_type = file_systems; fs_type->read_super; fs_type++) {
 459                 if (!fs_type->requires_dev)
 460                         continue;
 461                 sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
 462                 if (sb) {
 463                         inode = sb->s_mounted;
 464                         inode->i_count += 3 ;   /* NOTE! it is logically used 4 times, not 1 */
 465                         sb->s_covered = inode;
 466                         sb->s_flags = root_mountflags;
 467                         current->pwd = inode;
 468                         current->root = inode;
 469                         printk ("VFS: Mounted root (%s filesystem)%s.\n",
 470                                 fs_type->name,
 471                                 (sb->s_flags & MS_RDONLY) ? " readonly" : "");
 472                         return;
 473                 }
 474         }
 475         panic("VFS: Unable to mount root");
 476 }

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