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

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