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

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