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

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