root/fs/super.c

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

DEFINITIONS

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

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