linux/init/do_mounts.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/sched.h>
   3#include <linux/ctype.h>
   4#include <linux/fd.h>
   5#include <linux/tty.h>
   6#include <linux/suspend.h>
   7#include <linux/root_dev.h>
   8#include <linux/security.h>
   9#include <linux/delay.h>
  10#include <linux/genhd.h>
  11#include <linux/mount.h>
  12#include <linux/device.h>
  13#include <linux/init.h>
  14#include <linux/fs.h>
  15#include <linux/initrd.h>
  16#include <linux/async.h>
  17#include <linux/fs_struct.h>
  18#include <linux/slab.h>
  19
  20#include <linux/nfs_fs.h>
  21#include <linux/nfs_fs_sb.h>
  22#include <linux/nfs_mount.h>
  23
  24#include "do_mounts.h"
  25
  26int __initdata rd_doload;       /* 1 = load RAM disk, 0 = don't load */
  27
  28int root_mountflags = MS_RDONLY | MS_SILENT;
  29static char * __initdata root_device_name;
  30static char __initdata saved_root_name[64];
  31static int root_wait;
  32
  33dev_t ROOT_DEV;
  34
  35static int __init load_ramdisk(char *str)
  36{
  37        rd_doload = simple_strtol(str,NULL,0) & 3;
  38        return 1;
  39}
  40__setup("load_ramdisk=", load_ramdisk);
  41
  42static int __init readonly(char *str)
  43{
  44        if (*str)
  45                return 0;
  46        root_mountflags |= MS_RDONLY;
  47        return 1;
  48}
  49
  50static int __init readwrite(char *str)
  51{
  52        if (*str)
  53                return 0;
  54        root_mountflags &= ~MS_RDONLY;
  55        return 1;
  56}
  57
  58__setup("ro", readonly);
  59__setup("rw", readwrite);
  60
  61#ifdef CONFIG_BLOCK
  62/**
  63 * match_dev_by_uuid - callback for finding a partition using its uuid
  64 * @dev:        device passed in by the caller
  65 * @data:       opaque pointer to a 36 byte char array with a UUID
  66 *
  67 * Returns 1 if the device matches, and 0 otherwise.
  68 */
  69static int match_dev_by_uuid(struct device *dev, void *data)
  70{
  71        u8 *uuid = data;
  72        struct hd_struct *part = dev_to_part(dev);
  73
  74        if (!part->info)
  75                goto no_match;
  76
  77        if (memcmp(uuid, part->info->uuid, sizeof(part->info->uuid)))
  78                        goto no_match;
  79
  80        return 1;
  81no_match:
  82        return 0;
  83}
  84
  85
  86/**
  87 * devt_from_partuuid - looks up the dev_t of a partition by its UUID
  88 * @uuid:       min 36 byte char array containing a hex ascii UUID
  89 *
  90 * The function will return the first partition which contains a matching
  91 * UUID value in its partition_meta_info struct.  This does not search
  92 * by filesystem UUIDs.
  93 *
  94 * If @uuid is followed by a "/PARTNROFF=%d", then the number will be
  95 * extracted and used as an offset from the partition identified by the UUID.
  96 *
  97 * Returns the matching dev_t on success or 0 on failure.
  98 */
  99static dev_t devt_from_partuuid(char *uuid_str)
 100{
 101        dev_t res = 0;
 102        struct device *dev = NULL;
 103        u8 uuid[16];
 104        struct gendisk *disk;
 105        struct hd_struct *part;
 106        int offset = 0;
 107
 108        if (strlen(uuid_str) < 36)
 109                goto done;
 110
 111        /* Check for optional partition number offset attributes. */
 112        if (uuid_str[36]) {
 113                char c = 0;
 114                /* Explicitly fail on poor PARTUUID syntax. */
 115                if (sscanf(&uuid_str[36],
 116                           "/PARTNROFF=%d%c", &offset, &c) != 1) {
 117                        printk(KERN_ERR "VFS: PARTUUID= is invalid.\n"
 118                         "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
 119                        if (root_wait)
 120                                printk(KERN_ERR
 121                                     "Disabling rootwait; root= is invalid.\n");
 122                        root_wait = 0;
 123                        goto done;
 124                }
 125        }
 126
 127        /* Pack the requested UUID in the expected format. */
 128        part_pack_uuid(uuid_str, uuid);
 129
 130        dev = class_find_device(&block_class, NULL, uuid, &match_dev_by_uuid);
 131        if (!dev)
 132                goto done;
 133
 134        res = dev->devt;
 135
 136        /* Attempt to find the partition by offset. */
 137        if (!offset)
 138                goto no_offset;
 139
 140        res = 0;
 141        disk = part_to_disk(dev_to_part(dev));
 142        part = disk_get_part(disk, dev_to_part(dev)->partno + offset);
 143        if (part) {
 144                res = part_devt(part);
 145                put_device(part_to_dev(part));
 146        }
 147
 148no_offset:
 149        put_device(dev);
 150done:
 151        return res;
 152}
 153#endif
 154
 155/*
 156 *      Convert a name into device number.  We accept the following variants:
 157 *
 158 *      1) device number in hexadecimal represents itself
 159 *      2) /dev/nfs represents Root_NFS (0xff)
 160 *      3) /dev/<disk_name> represents the device number of disk
 161 *      4) /dev/<disk_name><decimal> represents the device number
 162 *         of partition - device number of disk plus the partition number
 163 *      5) /dev/<disk_name>p<decimal> - same as the above, that form is
 164 *         used when disk name of partitioned disk ends on a digit.
 165 *      6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
 166 *         unique id of a partition if the partition table provides it.
 167 *      7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
 168 *         a partition with a known unique id.
 169 *
 170 *      If name doesn't have fall into the categories above, we return (0,0).
 171 *      block_class is used to check if something is a disk name. If the disk
 172 *      name contains slashes, the device name has them replaced with
 173 *      bangs.
 174 */
 175
 176dev_t name_to_dev_t(char *name)
 177{
 178        char s[32];
 179        char *p;
 180        dev_t res = 0;
 181        int part;
 182
 183#ifdef CONFIG_BLOCK
 184        if (strncmp(name, "PARTUUID=", 9) == 0) {
 185                name += 9;
 186                res = devt_from_partuuid(name);
 187                if (!res)
 188                        goto fail;
 189                goto done;
 190        }
 191#endif
 192
 193        if (strncmp(name, "/dev/", 5) != 0) {
 194                unsigned maj, min;
 195
 196                if (sscanf(name, "%u:%u", &maj, &min) == 2) {
 197                        res = MKDEV(maj, min);
 198                        if (maj != MAJOR(res) || min != MINOR(res))
 199                                goto fail;
 200                } else {
 201                        res = new_decode_dev(simple_strtoul(name, &p, 16));
 202                        if (*p)
 203                                goto fail;
 204                }
 205                goto done;
 206        }
 207
 208        name += 5;
 209        res = Root_NFS;
 210        if (strcmp(name, "nfs") == 0)
 211                goto done;
 212        res = Root_RAM0;
 213        if (strcmp(name, "ram") == 0)
 214                goto done;
 215
 216        if (strlen(name) > 31)
 217                goto fail;
 218        strcpy(s, name);
 219        for (p = s; *p; p++)
 220                if (*p == '/')
 221                        *p = '!';
 222        res = blk_lookup_devt(s, 0);
 223        if (res)
 224                goto done;
 225
 226        /*
 227         * try non-existent, but valid partition, which may only exist
 228         * after revalidating the disk, like partitioned md devices
 229         */
 230        while (p > s && isdigit(p[-1]))
 231                p--;
 232        if (p == s || !*p || *p == '0')
 233                goto fail;
 234
 235        /* try disk name without <part number> */
 236        part = simple_strtoul(p, NULL, 10);
 237        *p = '\0';
 238        res = blk_lookup_devt(s, part);
 239        if (res)
 240                goto done;
 241
 242        /* try disk name without p<part number> */
 243        if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
 244                goto fail;
 245        p[-1] = '\0';
 246        res = blk_lookup_devt(s, part);
 247        if (res)
 248                goto done;
 249
 250fail:
 251        return 0;
 252done:
 253        return res;
 254}
 255
 256static int __init root_dev_setup(char *line)
 257{
 258        strlcpy(saved_root_name, line, sizeof(saved_root_name));
 259        return 1;
 260}
 261
 262__setup("root=", root_dev_setup);
 263
 264static int __init rootwait_setup(char *str)
 265{
 266        if (*str)
 267                return 0;
 268        root_wait = 1;
 269        return 1;
 270}
 271
 272__setup("rootwait", rootwait_setup);
 273
 274static char * __initdata root_mount_data;
 275static int __init root_data_setup(char *str)
 276{
 277        root_mount_data = str;
 278        return 1;
 279}
 280
 281static char * __initdata root_fs_names;
 282static int __init fs_names_setup(char *str)
 283{
 284        root_fs_names = str;
 285        return 1;
 286}
 287
 288static unsigned int __initdata root_delay;
 289static int __init root_delay_setup(char *str)
 290{
 291        root_delay = simple_strtoul(str, NULL, 0);
 292        return 1;
 293}
 294
 295__setup("rootflags=", root_data_setup);
 296__setup("rootfstype=", fs_names_setup);
 297__setup("rootdelay=", root_delay_setup);
 298
 299static void __init get_fs_names(char *page)
 300{
 301        char *s = page;
 302
 303        if (root_fs_names) {
 304                strcpy(page, root_fs_names);
 305                while (*s++) {
 306                        if (s[-1] == ',')
 307                                s[-1] = '\0';
 308                }
 309        } else {
 310                int len = get_filesystem_list(page);
 311                char *p, *next;
 312
 313                page[len] = '\0';
 314                for (p = page-1; p; p = next) {
 315                        next = strchr(++p, '\n');
 316                        if (*p++ != '\t')
 317                                continue;
 318                        while ((*s++ = *p++) != '\n')
 319                                ;
 320                        s[-1] = '\0';
 321                }
 322        }
 323        *s = '\0';
 324}
 325
 326static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 327{
 328        int err = sys_mount(name, "/root", fs, flags, data);
 329        if (err)
 330                return err;
 331
 332        sys_chdir((const char __user __force *)"/root");
 333        ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
 334        printk(KERN_INFO
 335               "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
 336               current->fs->pwd.mnt->mnt_sb->s_type->name,
 337               current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?
 338               " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
 339        return 0;
 340}
 341
 342void __init mount_block_root(char *name, int flags)
 343{
 344        char *fs_names = __getname_gfp(GFP_KERNEL
 345                | __GFP_NOTRACK_FALSE_POSITIVE);
 346        char *p;
 347#ifdef CONFIG_BLOCK
 348        char b[BDEVNAME_SIZE];
 349#else
 350        const char *b = name;
 351#endif
 352
 353        get_fs_names(fs_names);
 354retry:
 355        for (p = fs_names; *p; p += strlen(p)+1) {
 356                int err = do_mount_root(name, p, flags, root_mount_data);
 357                switch (err) {
 358                        case 0:
 359                                goto out;
 360                        case -EACCES:
 361                                flags |= MS_RDONLY;
 362                                goto retry;
 363                        case -EINVAL:
 364                                continue;
 365                }
 366                /*
 367                 * Allow the user to distinguish between failed sys_open
 368                 * and bad superblock on root device.
 369                 * and give them a list of the available devices
 370                 */
 371#ifdef CONFIG_BLOCK
 372                __bdevname(ROOT_DEV, b);
 373#endif
 374                printk("VFS: Cannot open root device \"%s\" or %s\n",
 375                                root_device_name, b);
 376                printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 377
 378                printk_all_partitions();
 379#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
 380                printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "
 381                       "explicit textual name for \"root=\" boot option.\n");
 382#endif
 383                panic("VFS: Unable to mount root fs on %s", b);
 384        }
 385
 386        printk("List of all partitions:\n");
 387        printk_all_partitions();
 388        printk("No filesystem could mount root, tried: ");
 389        for (p = fs_names; *p; p += strlen(p)+1)
 390                printk(" %s", p);
 391        printk("\n");
 392#ifdef CONFIG_BLOCK
 393        __bdevname(ROOT_DEV, b);
 394#endif
 395        panic("VFS: Unable to mount root fs on %s", b);
 396out:
 397        putname(fs_names);
 398}
 399 
 400#ifdef CONFIG_ROOT_NFS
 401
 402#define NFSROOT_TIMEOUT_MIN     5
 403#define NFSROOT_TIMEOUT_MAX     30
 404#define NFSROOT_RETRY_MAX       5
 405
 406static int __init mount_nfs_root(void)
 407{
 408        char *root_dev, *root_data;
 409        unsigned int timeout;
 410        int try, err;
 411
 412        err = nfs_root_data(&root_dev, &root_data);
 413        if (err != 0)
 414                return 0;
 415
 416        /*
 417         * The server or network may not be ready, so try several
 418         * times.  Stop after a few tries in case the client wants
 419         * to fall back to other boot methods.
 420         */
 421        timeout = NFSROOT_TIMEOUT_MIN;
 422        for (try = 1; ; try++) {
 423                err = do_mount_root(root_dev, "nfs",
 424                                        root_mountflags, root_data);
 425                if (err == 0)
 426                        return 1;
 427                if (try > NFSROOT_RETRY_MAX)
 428                        break;
 429
 430                /* Wait, in case the server refused us immediately */
 431                ssleep(timeout);
 432                timeout <<= 1;
 433                if (timeout > NFSROOT_TIMEOUT_MAX)
 434                        timeout = NFSROOT_TIMEOUT_MAX;
 435        }
 436        return 0;
 437}
 438#endif
 439
 440#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD)
 441void __init change_floppy(char *fmt, ...)
 442{
 443        struct termios termios;
 444        char buf[80];
 445        char c;
 446        int fd;
 447        va_list args;
 448        va_start(args, fmt);
 449        vsprintf(buf, fmt, args);
 450        va_end(args);
 451        fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0);
 452        if (fd >= 0) {
 453                sys_ioctl(fd, FDEJECT, 0);
 454                sys_close(fd);
 455        }
 456        printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf);
 457        fd = sys_open("/dev/console", O_RDWR, 0);
 458        if (fd >= 0) {
 459                sys_ioctl(fd, TCGETS, (long)&termios);
 460                termios.c_lflag &= ~ICANON;
 461                sys_ioctl(fd, TCSETSF, (long)&termios);
 462                sys_read(fd, &c, 1);
 463                termios.c_lflag |= ICANON;
 464                sys_ioctl(fd, TCSETSF, (long)&termios);
 465                sys_close(fd);
 466        }
 467}
 468#endif
 469
 470void __init mount_root(void)
 471{
 472#ifdef CONFIG_ROOT_NFS
 473        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
 474                if (mount_nfs_root())
 475                        return;
 476
 477                printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
 478                ROOT_DEV = Root_FD0;
 479        }
 480#endif
 481#ifdef CONFIG_BLK_DEV_FD
 482        if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
 483                /* rd_doload is 2 for a dual initrd/ramload setup */
 484                if (rd_doload==2) {
 485                        if (rd_load_disk(1)) {
 486                                ROOT_DEV = Root_RAM1;
 487                                root_device_name = NULL;
 488                        }
 489                } else
 490                        change_floppy("root floppy");
 491        }
 492#endif
 493#ifdef CONFIG_BLOCK
 494        create_dev("/dev/root", ROOT_DEV);
 495        mount_block_root("/dev/root", root_mountflags);
 496#endif
 497}
 498
 499/*
 500 * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
 501 */
 502void __init prepare_namespace(void)
 503{
 504        int is_floppy;
 505
 506        if (root_delay) {
 507                printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
 508                       root_delay);
 509                ssleep(root_delay);
 510        }
 511
 512        /*
 513         * wait for the known devices to complete their probing
 514         *
 515         * Note: this is a potential source of long boot delays.
 516         * For example, it is not atypical to wait 5 seconds here
 517         * for the touchpad of a laptop to initialize.
 518         */
 519        wait_for_device_probe();
 520
 521        md_run_setup();
 522
 523        if (saved_root_name[0]) {
 524                root_device_name = saved_root_name;
 525                if (!strncmp(root_device_name, "mtd", 3) ||
 526                    !strncmp(root_device_name, "ubi", 3)) {
 527                        mount_block_root(root_device_name, root_mountflags);
 528                        goto out;
 529                }
 530                ROOT_DEV = name_to_dev_t(root_device_name);
 531                if (strncmp(root_device_name, "/dev/", 5) == 0)
 532                        root_device_name += 5;
 533        }
 534
 535        if (initrd_load())
 536                goto out;
 537
 538        /* wait for any asynchronous scanning to complete */
 539        if ((ROOT_DEV == 0) && root_wait) {
 540                printk(KERN_INFO "Waiting for root device %s...\n",
 541                        saved_root_name);
 542                while (driver_probe_done() != 0 ||
 543                        (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
 544                        msleep(100);
 545                async_synchronize_full();
 546        }
 547
 548        is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
 549
 550        if (is_floppy && rd_doload && rd_load_disk(0))
 551                ROOT_DEV = Root_RAM0;
 552
 553        mount_root();
 554out:
 555        devtmpfs_mount("dev");
 556        sys_mount(".", "/", NULL, MS_MOVE, NULL);
 557        sys_chroot((const char __user __force *)".");
 558}
 559
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.