diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /init | |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'init')
| -rw-r--r-- | init/Kconfig | 463 | ||||
| -rw-r--r-- | init/Makefile | 28 | ||||
| -rw-r--r-- | init/calibrate.c | 79 | ||||
| -rw-r--r-- | init/do_mounts.c | 430 | ||||
| -rw-r--r-- | init/do_mounts.h | 92 | ||||
| -rw-r--r-- | init/do_mounts_devfs.c | 137 | ||||
| -rw-r--r-- | init/do_mounts_initrd.c | 121 | ||||
| -rw-r--r-- | init/do_mounts_md.c | 290 | ||||
| -rw-r--r-- | init/do_mounts_rd.c | 429 | ||||
| -rw-r--r-- | init/initramfs.c | 500 | ||||
| -rw-r--r-- | init/main.c | 713 | ||||
| -rw-r--r-- | init/version.c | 33 |
12 files changed, 3315 insertions, 0 deletions
diff --git a/init/Kconfig b/init/Kconfig new file mode 100644 index 000000000000..abe2682a6ca6 --- /dev/null +++ b/init/Kconfig | |||
| @@ -0,0 +1,463 @@ | |||
| 1 | menu "Code maturity level options" | ||
| 2 | |||
| 3 | config EXPERIMENTAL | ||
| 4 | bool "Prompt for development and/or incomplete code/drivers" | ||
| 5 | ---help--- | ||
| 6 | Some of the various things that Linux supports (such as network | ||
| 7 | drivers, file systems, network protocols, etc.) can be in a state | ||
| 8 | of development where the functionality, stability, or the level of | ||
| 9 | testing is not yet high enough for general use. This is usually | ||
| 10 | known as the "alpha-test" phase among developers. If a feature is | ||
| 11 | currently in alpha-test, then the developers usually discourage | ||
| 12 | uninformed widespread use of this feature by the general public to | ||
| 13 | avoid "Why doesn't this work?" type mail messages. However, active | ||
| 14 | testing and use of these systems is welcomed. Just be aware that it | ||
| 15 | may not meet the normal level of reliability or it may fail to work | ||
| 16 | in some special cases. Detailed bug reports from people familiar | ||
| 17 | with the kernel internals are usually welcomed by the developers | ||
| 18 | (before submitting bug reports, please read the documents | ||
| 19 | <file:README>, <file:MAINTAINERS>, <file:REPORTING-BUGS>, | ||
| 20 | <file:Documentation/BUG-HUNTING>, and | ||
| 21 | <file:Documentation/oops-tracing.txt> in the kernel source). | ||
| 22 | |||
| 23 | This option will also make obsoleted drivers available. These are | ||
| 24 | drivers that have been replaced by something else, and/or are | ||
| 25 | scheduled to be removed in a future kernel release. | ||
| 26 | |||
| 27 | Unless you intend to help test and develop a feature or driver that | ||
| 28 | falls into this category, or you have a situation that requires | ||
| 29 | using these features, you should probably say N here, which will | ||
| 30 | cause the configurator to present you with fewer choices. If | ||
| 31 | you say Y here, you will be offered the choice of using features or | ||
| 32 | drivers that are currently considered to be in the alpha-test phase. | ||
| 33 | |||
| 34 | config CLEAN_COMPILE | ||
| 35 | bool "Select only drivers expected to compile cleanly" if EXPERIMENTAL | ||
| 36 | default y | ||
| 37 | help | ||
| 38 | Select this option if you don't even want to see the option | ||
| 39 | to configure known-broken drivers. | ||
| 40 | |||
| 41 | If unsure, say Y | ||
| 42 | |||
| 43 | config BROKEN | ||
| 44 | bool | ||
| 45 | depends on !CLEAN_COMPILE | ||
| 46 | default y | ||
| 47 | |||
| 48 | config BROKEN_ON_SMP | ||
| 49 | bool | ||
| 50 | depends on BROKEN || !SMP | ||
| 51 | default y | ||
| 52 | |||
| 53 | config LOCK_KERNEL | ||
| 54 | bool | ||
| 55 | depends on SMP || PREEMPT | ||
| 56 | default y | ||
| 57 | |||
| 58 | config INIT_ENV_ARG_LIMIT | ||
| 59 | int | ||
| 60 | default 32 if !USERMODE | ||
| 61 | default 128 if USERMODE | ||
| 62 | help | ||
| 63 | This is the value of the two limits on the number of argument and of | ||
| 64 | env.var passed to init from the kernel command line. | ||
| 65 | |||
| 66 | endmenu | ||
| 67 | |||
| 68 | menu "General setup" | ||
| 69 | |||
| 70 | config LOCALVERSION | ||
| 71 | string "Local version - append to kernel release" | ||
| 72 | help | ||
| 73 | Append an extra string to the end of your kernel version. | ||
| 74 | This will show up when you type uname, for example. | ||
| 75 | The string you set here will be appended after the contents of | ||
| 76 | any files with a filename matching localversion* in your | ||
| 77 | object and source tree, in that order. Your total string can | ||
| 78 | be a maximum of 64 characters. | ||
| 79 | |||
| 80 | config SWAP | ||
| 81 | bool "Support for paging of anonymous memory (swap)" | ||
| 82 | depends on MMU | ||
| 83 | default y | ||
| 84 | help | ||
| 85 | This option allows you to choose whether you want to have support | ||
| 86 | for socalled swap devices or swap files in your kernel that are | ||
| 87 | used to provide more virtual memory than the actual RAM present | ||
| 88 | in your computer. If unsure say Y. | ||
| 89 | |||
| 90 | config SYSVIPC | ||
| 91 | bool "System V IPC" | ||
| 92 | depends on MMU | ||
| 93 | ---help--- | ||
| 94 | Inter Process Communication is a suite of library functions and | ||
| 95 | system calls which let processes (running programs) synchronize and | ||
| 96 | exchange information. It is generally considered to be a good thing, | ||
| 97 | and some programs won't run unless you say Y here. In particular, if | ||
| 98 | you want to run the DOS emulator dosemu under Linux (read the | ||
| 99 | DOSEMU-HOWTO, available from <http://www.tldp.org/docs.html#howto>), | ||
| 100 | you'll need to say Y here. | ||
| 101 | |||
| 102 | You can find documentation about IPC with "info ipc" and also in | ||
| 103 | section 6.4 of the Linux Programmer's Guide, available from | ||
| 104 | <http://www.tldp.org/guides.html>. | ||
| 105 | |||
| 106 | config POSIX_MQUEUE | ||
| 107 | bool "POSIX Message Queues" | ||
| 108 | depends on NET && EXPERIMENTAL | ||
| 109 | ---help--- | ||
| 110 | POSIX variant of message queues is a part of IPC. In POSIX message | ||
| 111 | queues every message has a priority which decides about succession | ||
| 112 | of receiving it by a process. If you want to compile and run | ||
| 113 | programs written e.g. for Solaris with use of its POSIX message | ||
| 114 | queues (functions mq_*) say Y here. To use this feature you will | ||
| 115 | also need mqueue library, available from | ||
| 116 | <http://www.mat.uni.torun.pl/~wrona/posix_ipc/> | ||
| 117 | |||
| 118 | POSIX message queues are visible as a filesystem called 'mqueue' | ||
| 119 | and can be mounted somewhere if you want to do filesystem | ||
| 120 | operations on message queues. | ||
| 121 | |||
| 122 | If unsure, say Y. | ||
| 123 | |||
| 124 | config BSD_PROCESS_ACCT | ||
| 125 | bool "BSD Process Accounting" | ||
| 126 | help | ||
| 127 | If you say Y here, a user level program will be able to instruct the | ||
| 128 | kernel (via a special system call) to write process accounting | ||
| 129 | information to a file: whenever a process exits, information about | ||
| 130 | that process will be appended to the file by the kernel. The | ||
| 131 | information includes things such as creation time, owning user, | ||
| 132 | command name, memory usage, controlling terminal etc. (the complete | ||
| 133 | list is in the struct acct in <file:include/linux/acct.h>). It is | ||
| 134 | up to the user level program to do useful things with this | ||
| 135 | information. This is generally a good idea, so say Y. | ||
| 136 | |||
| 137 | config BSD_PROCESS_ACCT_V3 | ||
| 138 | bool "BSD Process Accounting version 3 file format" | ||
| 139 | depends on BSD_PROCESS_ACCT | ||
| 140 | default n | ||
| 141 | help | ||
| 142 | If you say Y here, the process accounting information is written | ||
| 143 | in a new file format that also logs the process IDs of each | ||
| 144 | process and it's parent. Note that this file format is incompatible | ||
| 145 | with previous v0/v1/v2 file formats, so you will need updated tools | ||
| 146 | for processing it. A preliminary version of these tools is available | ||
| 147 | at <http://www.physik3.uni-rostock.de/tim/kernel/utils/acct/>. | ||
| 148 | |||
| 149 | config SYSCTL | ||
| 150 | bool "Sysctl support" | ||
| 151 | ---help--- | ||
| 152 | The sysctl interface provides a means of dynamically changing | ||
| 153 | certain kernel parameters and variables on the fly without requiring | ||
| 154 | a recompile of the kernel or reboot of the system. The primary | ||
| 155 | interface consists of a system call, but if you say Y to "/proc | ||
| 156 | file system support", a tree of modifiable sysctl entries will be | ||
| 157 | generated beneath the /proc/sys directory. They are explained in the | ||
| 158 | files in <file:Documentation/sysctl/>. Note that enabling this | ||
| 159 | option will enlarge the kernel by at least 8 KB. | ||
| 160 | |||
| 161 | As it is generally a good thing, you should say Y here unless | ||
| 162 | building a kernel for install/rescue disks or your system is very | ||
| 163 | limited in memory. | ||
| 164 | |||
| 165 | config AUDIT | ||
| 166 | bool "Auditing support" | ||
| 167 | default y if SECURITY_SELINUX | ||
| 168 | help | ||
| 169 | Enable auditing infrastructure that can be used with another | ||
| 170 | kernel subsystem, such as SELinux (which requires this for | ||
| 171 | logging of avc messages output). Does not do system-call | ||
| 172 | auditing without CONFIG_AUDITSYSCALL. | ||
| 173 | |||
| 174 | config AUDITSYSCALL | ||
| 175 | bool "Enable system-call auditing support" | ||
| 176 | depends on AUDIT && (X86 || PPC64 || ARCH_S390 || IA64) | ||
| 177 | default y if SECURITY_SELINUX | ||
| 178 | help | ||
| 179 | Enable low-overhead system-call auditing infrastructure that | ||
| 180 | can be used independently or with another kernel subsystem, | ||
| 181 | such as SELinux. | ||
| 182 | |||
| 183 | config HOTPLUG | ||
| 184 | bool "Support for hot-pluggable devices" if !ARCH_S390 | ||
| 185 | default ARCH_S390 | ||
| 186 | help | ||
| 187 | This option is provided for the case where no in-kernel-tree | ||
| 188 | modules require HOTPLUG functionality, but a module built | ||
| 189 | outside the kernel tree does. Such modules require Y here. | ||
| 190 | |||
| 191 | config KOBJECT_UEVENT | ||
| 192 | bool "Kernel Userspace Events" | ||
| 193 | depends on NET | ||
| 194 | default y | ||
| 195 | help | ||
| 196 | This option enables the kernel userspace event layer, which is a | ||
| 197 | simple mechanism for kernel-to-user communication over a netlink | ||
| 198 | socket. | ||
| 199 | The goal of the kernel userspace events layer is to provide a simple | ||
| 200 | and efficient events system, that notifies userspace about kobject | ||
| 201 | state changes. This will enable applications to just listen for | ||
| 202 | events instead of polling system devices and files. | ||
| 203 | Hotplug events (kobject addition and removal) are also available on | ||
| 204 | the netlink socket in addition to the execution of /sbin/hotplug if | ||
| 205 | CONFIG_HOTPLUG is enabled. | ||
| 206 | |||
| 207 | Say Y, unless you are building a system requiring minimal memory | ||
| 208 | consumption. | ||
| 209 | |||
| 210 | config IKCONFIG | ||
| 211 | bool "Kernel .config support" | ||
| 212 | ---help--- | ||
| 213 | This option enables the complete Linux kernel ".config" file | ||
| 214 | contents to be saved in the kernel. It provides documentation | ||
| 215 | of which kernel options are used in a running kernel or in an | ||
| 216 | on-disk kernel. This information can be extracted from the kernel | ||
| 217 | image file with the script scripts/extract-ikconfig and used as | ||
| 218 | input to rebuild the current kernel or to build another kernel. | ||
| 219 | It can also be extracted from a running kernel by reading | ||
| 220 | /proc/config.gz if enabled (below). | ||
| 221 | |||
| 222 | config IKCONFIG_PROC | ||
| 223 | bool "Enable access to .config through /proc/config.gz" | ||
| 224 | depends on IKCONFIG && PROC_FS | ||
| 225 | ---help--- | ||
| 226 | This option enables access to the kernel configuration file | ||
| 227 | through /proc/config.gz. | ||
| 228 | |||
| 229 | config CPUSETS | ||
| 230 | bool "Cpuset support" | ||
| 231 | depends on SMP | ||
| 232 | help | ||
| 233 | This options will let you create and manage CPUSET's which | ||
| 234 | allow dynamically partitioning a system into sets of CPUs and | ||
| 235 | Memory Nodes and assigning tasks to run only within those sets. | ||
| 236 | This is primarily useful on large SMP or NUMA systems. | ||
| 237 | |||
| 238 | Say N if unsure. | ||
| 239 | |||
| 240 | menuconfig EMBEDDED | ||
| 241 | bool "Configure standard kernel features (for small systems)" | ||
| 242 | help | ||
| 243 | This option allows certain base kernel options and settings | ||
| 244 | to be disabled or tweaked. This is for specialized | ||
| 245 | environments which can tolerate a "non-standard" kernel. | ||
| 246 | Only use this if you really know what you are doing. | ||
| 247 | |||
| 248 | config KALLSYMS | ||
| 249 | bool "Load all symbols for debugging/kksymoops" if EMBEDDED | ||
| 250 | default y | ||
| 251 | help | ||
| 252 | Say Y here to let the kernel print out symbolic crash information and | ||
| 253 | symbolic stack backtraces. This increases the size of the kernel | ||
| 254 | somewhat, as all symbols have to be loaded into the kernel image. | ||
| 255 | |||
| 256 | config KALLSYMS_ALL | ||
| 257 | bool "Include all symbols in kallsyms" | ||
| 258 | depends on DEBUG_KERNEL && KALLSYMS | ||
| 259 | help | ||
| 260 | Normally kallsyms only contains the symbols of functions, for nicer | ||
| 261 | OOPS messages. Some debuggers can use kallsyms for other | ||
| 262 | symbols too: say Y here to include all symbols, and you | ||
| 263 | don't care about adding 300k to the size of your kernel. | ||
| 264 | |||
| 265 | Say N. | ||
| 266 | |||
| 267 | config KALLSYMS_EXTRA_PASS | ||
| 268 | bool "Do an extra kallsyms pass" | ||
| 269 | depends on KALLSYMS | ||
| 270 | help | ||
| 271 | If kallsyms is not working correctly, the build will fail with | ||
| 272 | inconsistent kallsyms data. If that occurs, log a bug report and | ||
| 273 | turn on KALLSYMS_EXTRA_PASS which should result in a stable build. | ||
| 274 | Always say N here unless you find a bug in kallsyms, which must be | ||
| 275 | reported. KALLSYMS_EXTRA_PASS is only a temporary workaround while | ||
| 276 | you wait for kallsyms to be fixed. | ||
| 277 | |||
| 278 | config BASE_FULL | ||
| 279 | default y | ||
| 280 | bool "Enable full-sized data structures for core" if EMBEDDED | ||
| 281 | help | ||
| 282 | Disabling this option reduces the size of miscellaneous core | ||
| 283 | kernel data structures. This saves memory on small machines, | ||
| 284 | but may reduce performance. | ||
| 285 | |||
| 286 | config FUTEX | ||
| 287 | bool "Enable futex support" if EMBEDDED | ||
| 288 | default y | ||
| 289 | help | ||
| 290 | Disabling this option will cause the kernel to be built without | ||
| 291 | support for "fast userspace mutexes". The resulting kernel may not | ||
| 292 | run glibc-based applications correctly. | ||
| 293 | |||
| 294 | config EPOLL | ||
| 295 | bool "Enable eventpoll support" if EMBEDDED | ||
| 296 | default y | ||
| 297 | help | ||
| 298 | Disabling this option will cause the kernel to be built without | ||
| 299 | support for epoll family of system calls. | ||
| 300 | |||
| 301 | config CC_OPTIMIZE_FOR_SIZE | ||
| 302 | bool "Optimize for size" if EMBEDDED | ||
| 303 | default y if ARM || H8300 | ||
| 304 | help | ||
| 305 | Enabling this option will pass "-Os" instead of "-O2" to gcc | ||
| 306 | resulting in a smaller kernel. | ||
| 307 | |||
| 308 | WARNING: some versions of gcc may generate incorrect code with this | ||
| 309 | option. If problems are observed, a gcc upgrade may be needed. | ||
| 310 | |||
| 311 | If unsure, say N. | ||
| 312 | |||
| 313 | config SHMEM | ||
| 314 | bool "Use full shmem filesystem" if EMBEDDED | ||
| 315 | default y | ||
| 316 | depends on MMU | ||
| 317 | help | ||
| 318 | The shmem is an internal filesystem used to manage shared memory. | ||
| 319 | It is backed by swap and manages resource limits. It is also exported | ||
| 320 | to userspace as tmpfs if TMPFS is enabled. Disabling this | ||
| 321 | option replaces shmem and tmpfs with the much simpler ramfs code, | ||
| 322 | which may be appropriate on small systems without swap. | ||
| 323 | |||
| 324 | config CC_ALIGN_FUNCTIONS | ||
| 325 | int "Function alignment" if EMBEDDED | ||
| 326 | default 0 | ||
| 327 | help | ||
| 328 | Align the start of functions to the next power-of-two greater than n, | ||
| 329 | skipping up to n bytes. For instance, 32 aligns functions | ||
| 330 | to the next 32-byte boundary, but 24 would align to the next | ||
| 331 | 32-byte boundary only if this can be done by skipping 23 bytes or less. | ||
| 332 | Zero means use compiler's default. | ||
| 333 | |||
| 334 | config CC_ALIGN_LABELS | ||
| 335 | int "Label alignment" if EMBEDDED | ||
| 336 | default 0 | ||
| 337 | help | ||
| 338 | Align all branch targets to a power-of-two boundary, skipping | ||
| 339 | up to n bytes like ALIGN_FUNCTIONS. This option can easily | ||
| 340 | make code slower, because it must insert dummy operations for | ||
| 341 | when the branch target is reached in the usual flow of the code. | ||
| 342 | Zero means use compiler's default. | ||
| 343 | |||
| 344 | config CC_ALIGN_LOOPS | ||
| 345 | int "Loop alignment" if EMBEDDED | ||
| 346 | default 0 | ||
| 347 | help | ||
| 348 | Align loops to a power-of-two boundary, skipping up to n bytes. | ||
| 349 | Zero means use compiler's default. | ||
| 350 | |||
| 351 | config CC_ALIGN_JUMPS | ||
| 352 | int "Jump alignment" if EMBEDDED | ||
| 353 | default 0 | ||
| 354 | help | ||
| 355 | Align branch targets to a power-of-two boundary, for branch | ||
| 356 | targets where the targets can only be reached by jumping, | ||
| 357 | skipping up to n bytes like ALIGN_FUNCTIONS. In this case, | ||
| 358 | no dummy operations need be executed. | ||
| 359 | Zero means use compiler's default. | ||
| 360 | |||
| 361 | endmenu # General setup | ||
| 362 | |||
| 363 | config TINY_SHMEM | ||
| 364 | default !SHMEM | ||
| 365 | bool | ||
| 366 | |||
| 367 | config BASE_SMALL | ||
| 368 | int | ||
| 369 | default 0 if BASE_FULL | ||
| 370 | default 1 if !BASE_FULL | ||
| 371 | |||
| 372 | menu "Loadable module support" | ||
| 373 | |||
| 374 | config MODULES | ||
| 375 | bool "Enable loadable module support" | ||
| 376 | help | ||
| 377 | Kernel modules are small pieces of compiled code which can | ||
| 378 | be inserted in the running kernel, rather than being | ||
| 379 | permanently built into the kernel. You use the "modprobe" | ||
| 380 | tool to add (and sometimes remove) them. If you say Y here, | ||
| 381 | many parts of the kernel can be built as modules (by | ||
| 382 | answering M instead of Y where indicated): this is most | ||
| 383 | useful for infrequently used options which are not required | ||
| 384 | for booting. For more information, see the man pages for | ||
| 385 | modprobe, lsmod, modinfo, insmod and rmmod. | ||
| 386 | |||
| 387 | If you say Y here, you will need to run "make | ||
| 388 | modules_install" to put the modules under /lib/modules/ | ||
| 389 | where modprobe can find them (you may need to be root to do | ||
| 390 | this). | ||
| 391 | |||
| 392 | If unsure, say Y. | ||
| 393 | |||
| 394 | config MODULE_UNLOAD | ||
| 395 | bool "Module unloading" | ||
| 396 | depends on MODULES | ||
| 397 | help | ||
| 398 | Without this option you will not be able to unload any | ||
| 399 | modules (note that some modules may not be unloadable | ||
| 400 | anyway), which makes your kernel slightly smaller and | ||
| 401 | simpler. If unsure, say Y. | ||
| 402 | |||
| 403 | config MODULE_FORCE_UNLOAD | ||
| 404 | bool "Forced module unloading" | ||
| 405 | depends on MODULE_UNLOAD && EXPERIMENTAL | ||
| 406 | help | ||
| 407 | This option allows you to force a module to unload, even if the | ||
| 408 | kernel believes it is unsafe: the kernel will remove the module | ||
| 409 | without waiting for anyone to stop using it (using the -f option to | ||
| 410 | rmmod). This is mainly for kernel developers and desperate users. | ||
| 411 | If unsure, say N. | ||
| 412 | |||
| 413 | config OBSOLETE_MODPARM | ||
| 414 | bool | ||
| 415 | default y | ||
| 416 | depends on MODULES | ||
| 417 | help | ||
| 418 | You need this option to use module parameters on modules which | ||
| 419 | have not been converted to the new module parameter system yet. | ||
| 420 | If unsure, say Y. | ||
| 421 | |||
| 422 | config MODVERSIONS | ||
| 423 | bool "Module versioning support (EXPERIMENTAL)" | ||
| 424 | depends on MODULES && EXPERIMENTAL && !UML | ||
| 425 | help | ||
| 426 | Usually, you have to use modules compiled with your kernel. | ||
| 427 | Saying Y here makes it sometimes possible to use modules | ||
| 428 | compiled for different kernels, by adding enough information | ||
| 429 | to the modules to (hopefully) spot any changes which would | ||
| 430 | make them incompatible with the kernel you are running. If | ||
| 431 | unsure, say N. | ||
| 432 | |||
| 433 | config MODULE_SRCVERSION_ALL | ||
| 434 | bool "Source checksum for all modules" | ||
| 435 | depends on MODULES | ||
| 436 | help | ||
| 437 | Modules which contain a MODULE_VERSION get an extra "srcversion" | ||
| 438 | field inserted into their modinfo section, which contains a | ||
| 439 | sum of the source files which made it. This helps maintainers | ||
| 440 | see exactly which source was used to build a module (since | ||
| 441 | others sometimes change the module source without updating | ||
| 442 | the version). With this option, such a "srcversion" field | ||
| 443 | will be created for all modules. If unsure, say N. | ||
| 444 | |||
| 445 | config KMOD | ||
| 446 | bool "Automatic kernel module loading" | ||
| 447 | depends on MODULES | ||
| 448 | help | ||
| 449 | Normally when you have selected some parts of the kernel to | ||
| 450 | be created as kernel modules, you must load them (using the | ||
| 451 | "modprobe" command) before you can use them. If you say Y | ||
| 452 | here, some parts of the kernel will be able to load modules | ||
| 453 | automatically: when a part of the kernel needs a module, it | ||
| 454 | runs modprobe with the appropriate arguments, thereby | ||
| 455 | loading the module if it is available. If unsure, say Y. | ||
| 456 | |||
| 457 | config STOP_MACHINE | ||
| 458 | bool | ||
| 459 | default y | ||
| 460 | depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU | ||
| 461 | help | ||
| 462 | Need stop_machine() primitive. | ||
| 463 | endmenu | ||
diff --git a/init/Makefile b/init/Makefile new file mode 100644 index 000000000000..93a53fbdbe79 --- /dev/null +++ b/init/Makefile | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the linux kernel. | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-y := main.o version.o mounts.o initramfs.o | ||
| 6 | obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o | ||
| 7 | |||
| 8 | mounts-y := do_mounts.o | ||
| 9 | mounts-$(CONFIG_DEVFS_FS) += do_mounts_devfs.o | ||
| 10 | mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o | ||
| 11 | mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o | ||
| 12 | mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o | ||
| 13 | |||
| 14 | # files to be removed upon make clean | ||
| 15 | clean-files := ../include/linux/compile.h | ||
| 16 | |||
| 17 | # dependencies on generated files need to be listed explicitly | ||
| 18 | |||
| 19 | $(obj)/version.o: include/linux/compile.h | ||
| 20 | |||
| 21 | # compile.h changes depending on hostname, generation number, etc, | ||
| 22 | # so we regenerate it always. | ||
| 23 | # mkcompile_h will make sure to only update the | ||
| 24 | # actual file if its content has changed. | ||
| 25 | |||
| 26 | include/linux/compile.h: FORCE | ||
| 27 | @echo ' CHK $@' | ||
| 28 | @$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)" | ||
diff --git a/init/calibrate.c b/init/calibrate.c new file mode 100644 index 000000000000..c698e04a3dbe --- /dev/null +++ b/init/calibrate.c | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* calibrate.c: default delay calibration | ||
| 2 | * | ||
| 3 | * Excised from init/main.c | ||
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/sched.h> | ||
| 8 | #include <linux/delay.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | |||
| 11 | static unsigned long preset_lpj; | ||
| 12 | static int __init lpj_setup(char *str) | ||
| 13 | { | ||
| 14 | preset_lpj = simple_strtoul(str,NULL,0); | ||
| 15 | return 1; | ||
| 16 | } | ||
| 17 | |||
| 18 | __setup("lpj=", lpj_setup); | ||
| 19 | |||
| 20 | /* | ||
| 21 | * This is the number of bits of precision for the loops_per_jiffy. Each | ||
| 22 | * bit takes on average 1.5/HZ seconds. This (like the original) is a little | ||
| 23 | * better than 1% | ||
| 24 | */ | ||
| 25 | #define LPS_PREC 8 | ||
| 26 | |||
| 27 | void __devinit calibrate_delay(void) | ||
| 28 | { | ||
| 29 | unsigned long ticks, loopbit; | ||
| 30 | int lps_precision = LPS_PREC; | ||
| 31 | |||
| 32 | if (preset_lpj) { | ||
| 33 | loops_per_jiffy = preset_lpj; | ||
| 34 | printk("Calibrating delay loop (skipped)... " | ||
| 35 | "%lu.%02lu BogoMIPS preset\n", | ||
| 36 | loops_per_jiffy/(500000/HZ), | ||
| 37 | (loops_per_jiffy/(5000/HZ)) % 100); | ||
| 38 | } else { | ||
| 39 | loops_per_jiffy = (1<<12); | ||
| 40 | |||
| 41 | printk(KERN_DEBUG "Calibrating delay loop... "); | ||
| 42 | while ((loops_per_jiffy <<= 1) != 0) { | ||
| 43 | /* wait for "start of" clock tick */ | ||
| 44 | ticks = jiffies; | ||
| 45 | while (ticks == jiffies) | ||
| 46 | /* nothing */; | ||
| 47 | /* Go .. */ | ||
| 48 | ticks = jiffies; | ||
| 49 | __delay(loops_per_jiffy); | ||
| 50 | ticks = jiffies - ticks; | ||
| 51 | if (ticks) | ||
| 52 | break; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Do a binary approximation to get loops_per_jiffy set to | ||
| 57 | * equal one clock (up to lps_precision bits) | ||
| 58 | */ | ||
| 59 | loops_per_jiffy >>= 1; | ||
| 60 | loopbit = loops_per_jiffy; | ||
| 61 | while (lps_precision-- && (loopbit >>= 1)) { | ||
| 62 | loops_per_jiffy |= loopbit; | ||
| 63 | ticks = jiffies; | ||
| 64 | while (ticks == jiffies) | ||
| 65 | /* nothing */; | ||
| 66 | ticks = jiffies; | ||
| 67 | __delay(loops_per_jiffy); | ||
| 68 | if (jiffies != ticks) /* longer than 1 tick */ | ||
| 69 | loops_per_jiffy &= ~loopbit; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* Round the value and print it */ | ||
| 73 | printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", | ||
| 74 | loops_per_jiffy/(500000/HZ), | ||
| 75 | (loops_per_jiffy/(5000/HZ)) % 100, | ||
| 76 | loops_per_jiffy); | ||
| 77 | } | ||
| 78 | |||
| 79 | } | ||
diff --git a/init/do_mounts.c b/init/do_mounts.c new file mode 100644 index 000000000000..b7570c074d0f --- /dev/null +++ b/init/do_mounts.c | |||
| @@ -0,0 +1,430 @@ | |||
| 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 | |||
| 11 | #include <linux/nfs_fs.h> | ||
| 12 | #include <linux/nfs_fs_sb.h> | ||
| 13 | #include <linux/nfs_mount.h> | ||
| 14 | |||
| 15 | #include "do_mounts.h" | ||
| 16 | |||
| 17 | extern int get_filesystem_list(char * buf); | ||
| 18 | |||
| 19 | int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ | ||
| 20 | |||
| 21 | int root_mountflags = MS_RDONLY | MS_VERBOSE; | ||
| 22 | char * __initdata root_device_name; | ||
| 23 | static char __initdata saved_root_name[64]; | ||
| 24 | |||
| 25 | /* this is initialized in init/main.c */ | ||
| 26 | dev_t ROOT_DEV; | ||
| 27 | |||
| 28 | EXPORT_SYMBOL(ROOT_DEV); | ||
| 29 | |||
| 30 | static int __init load_ramdisk(char *str) | ||
| 31 | { | ||
| 32 | rd_doload = simple_strtol(str,NULL,0) & 3; | ||
| 33 | return 1; | ||
| 34 | } | ||
| 35 | __setup("load_ramdisk=", load_ramdisk); | ||
| 36 | |||
| 37 | static int __init readonly(char *str) | ||
| 38 | { | ||
| 39 | if (*str) | ||
| 40 | return 0; | ||
| 41 | root_mountflags |= MS_RDONLY; | ||
| 42 | return 1; | ||
| 43 | } | ||
| 44 | |||
| 45 | static int __init readwrite(char *str) | ||
| 46 | { | ||
| 47 | if (*str) | ||
| 48 | return 0; | ||
| 49 | root_mountflags &= ~MS_RDONLY; | ||
| 50 | return 1; | ||
| 51 | } | ||
| 52 | |||
| 53 | __setup("ro", readonly); | ||
| 54 | __setup("rw", readwrite); | ||
| 55 | |||
| 56 | static dev_t try_name(char *name, int part) | ||
| 57 | { | ||
| 58 | char path[64]; | ||
| 59 | char buf[32]; | ||
| 60 | int range; | ||
| 61 | dev_t res; | ||
| 62 | char *s; | ||
| 63 | int len; | ||
| 64 | int fd; | ||
| 65 | unsigned int maj, min; | ||
| 66 | |||
| 67 | /* read device number from .../dev */ | ||
| 68 | |||
| 69 | sprintf(path, "/sys/block/%s/dev", name); | ||
| 70 | fd = sys_open(path, 0, 0); | ||
| 71 | if (fd < 0) | ||
| 72 | goto fail; | ||
| 73 | len = sys_read(fd, buf, 32); | ||
| 74 | sys_close(fd); | ||
| 75 | if (len <= 0 || len == 32 || buf[len - 1] != '\n') | ||
| 76 | goto fail; | ||
| 77 | buf[len - 1] = '\0'; | ||
| 78 | if (sscanf(buf, "%u:%u", &maj, &min) == 2) { | ||
| 79 | /* | ||
| 80 | * Try the %u:%u format -- see print_dev_t() | ||
| 81 | */ | ||
| 82 | res = MKDEV(maj, min); | ||
| 83 | if (maj != MAJOR(res) || min != MINOR(res)) | ||
| 84 | goto fail; | ||
| 85 | } else { | ||
| 86 | /* | ||
| 87 | * Nope. Try old-style "0321" | ||
| 88 | */ | ||
| 89 | res = new_decode_dev(simple_strtoul(buf, &s, 16)); | ||
| 90 | if (*s) | ||
| 91 | goto fail; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* if it's there and we are not looking for a partition - that's it */ | ||
| 95 | if (!part) | ||
| 96 | return res; | ||
| 97 | |||
| 98 | /* otherwise read range from .../range */ | ||
| 99 | sprintf(path, "/sys/block/%s/range", name); | ||
| 100 | fd = sys_open(path, 0, 0); | ||
| 101 | if (fd < 0) | ||
| 102 | goto fail; | ||
| 103 | len = sys_read(fd, buf, 32); | ||
| 104 | sys_close(fd); | ||
| 105 | if (len <= 0 || len == 32 || buf[len - 1] != '\n') | ||
| 106 | goto fail; | ||
| 107 | buf[len - 1] = '\0'; | ||
| 108 | range = simple_strtoul(buf, &s, 10); | ||
| 109 | if (*s) | ||
| 110 | goto fail; | ||
| 111 | |||
| 112 | /* if partition is within range - we got it */ | ||
| 113 | if (part < range) | ||
| 114 | return res + part; | ||
| 115 | fail: | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Convert a name into device number. We accept the following variants: | ||
| 121 | * | ||
| 122 | * 1) device number in hexadecimal represents itself | ||
| 123 | * 2) /dev/nfs represents Root_NFS (0xff) | ||
| 124 | * 3) /dev/<disk_name> represents the device number of disk | ||
| 125 | * 4) /dev/<disk_name><decimal> represents the device number | ||
| 126 | * of partition - device number of disk plus the partition number | ||
| 127 | * 5) /dev/<disk_name>p<decimal> - same as the above, that form is | ||
| 128 | * used when disk name of partitioned disk ends on a digit. | ||
| 129 | * | ||
| 130 | * If name doesn't have fall into the categories above, we return 0. | ||
| 131 | * Driverfs is used to check if something is a disk name - it has | ||
| 132 | * all known disks under bus/block/devices. If the disk name | ||
| 133 | * contains slashes, name of driverfs node has them replaced with | ||
| 134 | * bangs. try_name() does the actual checks, assuming that driverfs | ||
| 135 | * is mounted on rootfs /sys. | ||
| 136 | */ | ||
| 137 | |||
| 138 | dev_t name_to_dev_t(char *name) | ||
| 139 | { | ||
| 140 | char s[32]; | ||
| 141 | char *p; | ||
| 142 | dev_t res = 0; | ||
| 143 | int part; | ||
| 144 | |||
| 145 | #ifdef CONFIG_SYSFS | ||
| 146 | int mkdir_err = sys_mkdir("/sys", 0700); | ||
| 147 | if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0) | ||
| 148 | goto out; | ||
| 149 | #endif | ||
| 150 | |||
| 151 | if (strncmp(name, "/dev/", 5) != 0) { | ||
| 152 | unsigned maj, min; | ||
| 153 | |||
| 154 | if (sscanf(name, "%u:%u", &maj, &min) == 2) { | ||
| 155 | res = MKDEV(maj, min); | ||
| 156 | if (maj != MAJOR(res) || min != MINOR(res)) | ||
| 157 | goto fail; | ||
| 158 | } else { | ||
| 159 | res = new_decode_dev(simple_strtoul(name, &p, 16)); | ||
| 160 | if (*p) | ||
| 161 | goto fail; | ||
| 162 | } | ||
| 163 | goto done; | ||
| 164 | } | ||
| 165 | name += 5; | ||
| 166 | res = Root_NFS; | ||
| 167 | if (strcmp(name, "nfs") == 0) | ||
| 168 | goto done; | ||
| 169 | res = Root_RAM0; | ||
| 170 | if (strcmp(name, "ram") == 0) | ||
| 171 | goto done; | ||
| 172 | |||
| 173 | if (strlen(name) > 31) | ||
| 174 | goto fail; | ||
| 175 | strcpy(s, name); | ||
| 176 | for (p = s; *p; p++) | ||
| 177 | if (*p == '/') | ||
| 178 | *p = '!'; | ||
| 179 | res = try_name(s, 0); | ||
| 180 | if (res) | ||
| 181 | goto done; | ||
| 182 | |||
| 183 | while (p > s && isdigit(p[-1])) | ||
| 184 | p--; | ||
| 185 | if (p == s || !*p || *p == '0') | ||
| 186 | goto fail; | ||
| 187 | part = simple_strtoul(p, NULL, 10); | ||
| 188 | *p = '\0'; | ||
| 189 | res = try_name(s, part); | ||
| 190 | if (res) | ||
| 191 | goto done; | ||
| 192 | |||
| 193 | if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') | ||
| 194 | goto fail; | ||
| 195 | p[-1] = '\0'; | ||
| 196 | res = try_name(s, part); | ||
| 197 | done: | ||
| 198 | #ifdef CONFIG_SYSFS | ||
| 199 | sys_umount("/sys", 0); | ||
| 200 | out: | ||
| 201 | if (!mkdir_err) | ||
| 202 | sys_rmdir("/sys"); | ||
| 203 | #endif | ||
| 204 | return res; | ||
| 205 | fail: | ||
| 206 | res = 0; | ||
| 207 | goto done; | ||
| 208 | } | ||
| 209 | |||
| 210 | static int __init root_dev_setup(char *line) | ||
| 211 | { | ||
| 212 | strlcpy(saved_root_name, line, sizeof(saved_root_name)); | ||
| 213 | return 1; | ||
| 214 | } | ||
| 215 | |||
| 216 | __setup("root=", root_dev_setup); | ||
| 217 | |||
| 218 | static char * __initdata root_mount_data; | ||
| 219 | static int __init root_data_setup(char *str) | ||
| 220 | { | ||
| 221 | root_mount_data = str; | ||
| 222 | return 1; | ||
| 223 | } | ||
| 224 | |||
| 225 | static char * __initdata root_fs_names; | ||
| 226 | static int __init fs_names_setup(char *str) | ||
| 227 | { | ||
| 228 | root_fs_names = str; | ||
| 229 | return 1; | ||
| 230 | } | ||
| 231 | |||
| 232 | static unsigned int __initdata root_delay; | ||
| 233 | static int __init root_delay_setup(char *str) | ||
| 234 | { | ||
| 235 | root_delay = simple_strtoul(str, NULL, 0); | ||
| 236 | return 1; | ||
| 237 | } | ||
| 238 | |||
| 239 | __setup("rootflags=", root_data_setup); | ||
| 240 | __setup("rootfstype=", fs_names_setup); | ||
| 241 | __setup("rootdelay=", root_delay_setup); | ||
| 242 | |||
| 243 | static void __init get_fs_names(char *page) | ||
| 244 | { | ||
| 245 | char *s = page; | ||
| 246 | |||
| 247 | if (root_fs_names) { | ||
| 248 | strcpy(page, root_fs_names); | ||
| 249 | while (*s++) { | ||
| 250 | if (s[-1] == ',') | ||
| 251 | s[-1] = '\0'; | ||
| 252 | } | ||
| 253 | } else { | ||
| 254 | int len = get_filesystem_list(page); | ||
| 255 | char *p, *next; | ||
| 256 | |||
| 257 | page[len] = '\0'; | ||
| 258 | for (p = page-1; p; p = next) { | ||
| 259 | next = strchr(++p, '\n'); | ||
| 260 | if (*p++ != '\t') | ||
| 261 | continue; | ||
| 262 | while ((*s++ = *p++) != '\n') | ||
| 263 | ; | ||
| 264 | s[-1] = '\0'; | ||
| 265 | } | ||
| 266 | } | ||
| 267 | *s = '\0'; | ||
| 268 | } | ||
| 269 | |||
| 270 | static int __init do_mount_root(char *name, char *fs, int flags, void *data) | ||
| 271 | { | ||
| 272 | int err = sys_mount(name, "/root", fs, flags, data); | ||
| 273 | if (err) | ||
| 274 | return err; | ||
| 275 | |||
| 276 | sys_chdir("/root"); | ||
| 277 | ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; | ||
| 278 | printk("VFS: Mounted root (%s filesystem)%s.\n", | ||
| 279 | current->fs->pwdmnt->mnt_sb->s_type->name, | ||
| 280 | current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ? | ||
| 281 | " readonly" : ""); | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | void __init mount_block_root(char *name, int flags) | ||
| 286 | { | ||
| 287 | char *fs_names = __getname(); | ||
| 288 | char *p; | ||
| 289 | char b[BDEVNAME_SIZE]; | ||
| 290 | |||
| 291 | get_fs_names(fs_names); | ||
| 292 | retry: | ||
| 293 | for (p = fs_names; *p; p += strlen(p)+1) { | ||
| 294 | int err = do_mount_root(name, p, flags, root_mount_data); | ||
| 295 | switch (err) { | ||
| 296 | case 0: | ||
| 297 | goto out; | ||
| 298 | case -EACCES: | ||
| 299 | flags |= MS_RDONLY; | ||
| 300 | goto retry; | ||
| 301 | case -EINVAL: | ||
| 302 | continue; | ||
| 303 | } | ||
| 304 | /* | ||
| 305 | * Allow the user to distinguish between failed sys_open | ||
| 306 | * and bad superblock on root device. | ||
| 307 | */ | ||
| 308 | __bdevname(ROOT_DEV, b); | ||
| 309 | printk("VFS: Cannot open root device \"%s\" or %s\n", | ||
| 310 | root_device_name, b); | ||
| 311 | printk("Please append a correct \"root=\" boot option\n"); | ||
| 312 | |||
| 313 | panic("VFS: Unable to mount root fs on %s", b); | ||
| 314 | } | ||
| 315 | panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b)); | ||
| 316 | out: | ||
| 317 | putname(fs_names); | ||
| 318 | } | ||
| 319 | |||
| 320 | #ifdef CONFIG_ROOT_NFS | ||
| 321 | static int __init mount_nfs_root(void) | ||
| 322 | { | ||
| 323 | void *data = nfs_root_data(); | ||
| 324 | |||
| 325 | create_dev("/dev/root", ROOT_DEV, NULL); | ||
| 326 | if (data && | ||
| 327 | do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0) | ||
| 328 | return 1; | ||
| 329 | return 0; | ||
| 330 | } | ||
| 331 | #endif | ||
| 332 | |||
| 333 | #if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD) | ||
| 334 | void __init change_floppy(char *fmt, ...) | ||
| 335 | { | ||
| 336 | struct termios termios; | ||
| 337 | char buf[80]; | ||
| 338 | char c; | ||
| 339 | int fd; | ||
| 340 | va_list args; | ||
| 341 | va_start(args, fmt); | ||
| 342 | vsprintf(buf, fmt, args); | ||
| 343 | va_end(args); | ||
| 344 | fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); | ||
| 345 | if (fd >= 0) { | ||
| 346 | sys_ioctl(fd, FDEJECT, 0); | ||
| 347 | sys_close(fd); | ||
| 348 | } | ||
| 349 | printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); | ||
| 350 | fd = sys_open("/dev/console", O_RDWR, 0); | ||
| 351 | if (fd >= 0) { | ||
| 352 | sys_ioctl(fd, TCGETS, (long)&termios); | ||
| 353 | termios.c_lflag &= ~ICANON; | ||
| 354 | sys_ioctl(fd, TCSETSF, (long)&termios); | ||
| 355 | sys_read(fd, &c, 1); | ||
| 356 | termios.c_lflag |= ICANON; | ||
| 357 | sys_ioctl(fd, TCSETSF, (long)&termios); | ||
| 358 | sys_close(fd); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | #endif | ||
| 362 | |||
| 363 | void __init mount_root(void) | ||
| 364 | { | ||
| 365 | #ifdef CONFIG_ROOT_NFS | ||
| 366 | if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) { | ||
| 367 | if (mount_nfs_root()) | ||
| 368 | return; | ||
| 369 | |||
| 370 | printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); | ||
| 371 | ROOT_DEV = Root_FD0; | ||
| 372 | } | ||
| 373 | #endif | ||
| 374 | #ifdef CONFIG_BLK_DEV_FD | ||
| 375 | if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { | ||
| 376 | /* rd_doload is 2 for a dual initrd/ramload setup */ | ||
| 377 | if (rd_doload==2) { | ||
| 378 | if (rd_load_disk(1)) { | ||
| 379 | ROOT_DEV = Root_RAM1; | ||
| 380 | root_device_name = NULL; | ||
| 381 | } | ||
| 382 | } else | ||
| 383 | change_floppy("root floppy"); | ||
| 384 | } | ||
| 385 | #endif | ||
| 386 | create_dev("/dev/root", ROOT_DEV, root_device_name); | ||
| 387 | mount_block_root("/dev/root", root_mountflags); | ||
| 388 | } | ||
| 389 | |||
| 390 | /* | ||
| 391 | * Prepare the namespace - decide what/where to mount, load ramdisks, etc. | ||
| 392 | */ | ||
| 393 | void __init prepare_namespace(void) | ||
| 394 | { | ||
| 395 | int is_floppy; | ||
| 396 | |||
| 397 | mount_devfs(); | ||
| 398 | |||
| 399 | if (root_delay) { | ||
| 400 | printk(KERN_INFO "Waiting %dsec before mounting root device...\n", | ||
| 401 | root_delay); | ||
| 402 | ssleep(root_delay); | ||
| 403 | } | ||
| 404 | |||
| 405 | md_run_setup(); | ||
| 406 | |||
| 407 | if (saved_root_name[0]) { | ||
| 408 | root_device_name = saved_root_name; | ||
| 409 | ROOT_DEV = name_to_dev_t(root_device_name); | ||
| 410 | if (strncmp(root_device_name, "/dev/", 5) == 0) | ||
| 411 | root_device_name += 5; | ||
| 412 | } | ||
| 413 | |||
| 414 | is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; | ||
| 415 | |||
| 416 | if (initrd_load()) | ||
| 417 | goto out; | ||
| 418 | |||
| 419 | if (is_floppy && rd_doload && rd_load_disk(0)) | ||
| 420 | ROOT_DEV = Root_RAM0; | ||
| 421 | |||
| 422 | mount_root(); | ||
| 423 | out: | ||
| 424 | umount_devfs("/dev"); | ||
| 425 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||
| 426 | sys_chroot("."); | ||
| 427 | security_sb_post_mountroot(); | ||
| 428 | mount_devfs_fs (); | ||
| 429 | } | ||
| 430 | |||
diff --git a/init/do_mounts.h b/init/do_mounts.h new file mode 100644 index 000000000000..de92bee4f35e --- /dev/null +++ b/init/do_mounts.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | #include <linux/config.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/devfs_fs_kernel.h> | ||
| 4 | #include <linux/init.h> | ||
| 5 | #include <linux/syscalls.h> | ||
| 6 | #include <linux/unistd.h> | ||
| 7 | #include <linux/slab.h> | ||
| 8 | #include <linux/mount.h> | ||
| 9 | #include <linux/major.h> | ||
| 10 | #include <linux/root_dev.h> | ||
| 11 | |||
| 12 | dev_t name_to_dev_t(char *name); | ||
| 13 | void change_floppy(char *fmt, ...); | ||
| 14 | void mount_block_root(char *name, int flags); | ||
| 15 | void mount_root(void); | ||
| 16 | extern int root_mountflags; | ||
| 17 | extern char *root_device_name; | ||
| 18 | |||
| 19 | #ifdef CONFIG_DEVFS_FS | ||
| 20 | |||
| 21 | void mount_devfs(void); | ||
| 22 | void umount_devfs(char *path); | ||
| 23 | int create_dev(char *name, dev_t dev, char *devfs_name); | ||
| 24 | |||
| 25 | #else | ||
| 26 | |||
| 27 | static inline void mount_devfs(void) {} | ||
| 28 | static inline void umount_devfs(const char *path) {} | ||
| 29 | |||
| 30 | static inline int create_dev(char *name, dev_t dev, char *devfs_name) | ||
| 31 | { | ||
| 32 | sys_unlink(name); | ||
| 33 | return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev)); | ||
| 34 | } | ||
| 35 | |||
| 36 | #endif | ||
| 37 | |||
| 38 | #if BITS_PER_LONG == 32 | ||
| 39 | static inline u32 bstat(char *name) | ||
| 40 | { | ||
| 41 | struct stat64 stat; | ||
| 42 | if (sys_stat64(name, &stat) != 0) | ||
| 43 | return 0; | ||
| 44 | if (!S_ISBLK(stat.st_mode)) | ||
| 45 | return 0; | ||
| 46 | if (stat.st_rdev != (u32)stat.st_rdev) | ||
| 47 | return 0; | ||
| 48 | return stat.st_rdev; | ||
| 49 | } | ||
| 50 | #else | ||
| 51 | static inline u32 bstat(char *name) | ||
| 52 | { | ||
| 53 | struct stat stat; | ||
| 54 | if (sys_newstat(name, &stat) != 0) | ||
| 55 | return 0; | ||
| 56 | if (!S_ISBLK(stat.st_mode)) | ||
| 57 | return 0; | ||
| 58 | return stat.st_rdev; | ||
| 59 | } | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #ifdef CONFIG_BLK_DEV_RAM | ||
| 63 | |||
| 64 | int __init rd_load_disk(int n); | ||
| 65 | int __init rd_load_image(char *from); | ||
| 66 | |||
| 67 | #else | ||
| 68 | |||
| 69 | static inline int rd_load_disk(int n) { return 0; } | ||
| 70 | static inline int rd_load_image(char *from) { return 0; } | ||
| 71 | |||
| 72 | #endif | ||
| 73 | |||
| 74 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 75 | |||
| 76 | int __init initrd_load(void); | ||
| 77 | |||
| 78 | #else | ||
| 79 | |||
| 80 | static inline int initrd_load(void) { return 0; } | ||
| 81 | |||
| 82 | #endif | ||
| 83 | |||
| 84 | #ifdef CONFIG_BLK_DEV_MD | ||
| 85 | |||
| 86 | void md_run_setup(void); | ||
| 87 | |||
| 88 | #else | ||
| 89 | |||
| 90 | static inline void md_run_setup(void) {} | ||
| 91 | |||
| 92 | #endif | ||
diff --git a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c new file mode 100644 index 000000000000..cc526474690a --- /dev/null +++ b/init/do_mounts_devfs.c | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | |||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/dirent.h> | ||
| 4 | #include <linux/string.h> | ||
| 5 | |||
| 6 | #include "do_mounts.h" | ||
| 7 | |||
| 8 | void __init mount_devfs(void) | ||
| 9 | { | ||
| 10 | sys_mount("devfs", "/dev", "devfs", 0, NULL); | ||
| 11 | } | ||
| 12 | |||
| 13 | void __init umount_devfs(char *path) | ||
| 14 | { | ||
| 15 | sys_umount(path, 0); | ||
| 16 | } | ||
| 17 | |||
| 18 | /* | ||
| 19 | * If the dir will fit in *buf, return its length. If it won't fit, return | ||
| 20 | * zero. Return -ve on error. | ||
| 21 | */ | ||
| 22 | static int __init do_read_dir(int fd, void *buf, int len) | ||
| 23 | { | ||
| 24 | long bytes, n; | ||
| 25 | char *p = buf; | ||
| 26 | sys_lseek(fd, 0, 0); | ||
| 27 | |||
| 28 | for (bytes = 0; bytes < len; bytes += n) { | ||
| 29 | n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes), | ||
| 30 | len - bytes); | ||
| 31 | if (n < 0) | ||
| 32 | return n; | ||
| 33 | if (n == 0) | ||
| 34 | return bytes; | ||
| 35 | } | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Try to read all of a directory. Returns the contents at *p, which | ||
| 41 | * is kmalloced memory. Returns the number of bytes read at *len. Returns | ||
| 42 | * NULL on error. | ||
| 43 | */ | ||
| 44 | static void * __init read_dir(char *path, int *len) | ||
| 45 | { | ||
| 46 | int size; | ||
| 47 | int fd = sys_open(path, 0, 0); | ||
| 48 | |||
| 49 | *len = 0; | ||
| 50 | if (fd < 0) | ||
| 51 | return NULL; | ||
| 52 | |||
| 53 | for (size = 1 << 9; size <= (PAGE_SIZE << MAX_ORDER); size <<= 1) { | ||
| 54 | void *p = kmalloc(size, GFP_KERNEL); | ||
| 55 | int n; | ||
| 56 | if (!p) | ||
| 57 | break; | ||
| 58 | n = do_read_dir(fd, p, size); | ||
| 59 | if (n > 0) { | ||
| 60 | sys_close(fd); | ||
| 61 | *len = n; | ||
| 62 | return p; | ||
| 63 | } | ||
| 64 | kfree(p); | ||
| 65 | if (n == -EINVAL) | ||
| 66 | continue; /* Try a larger buffer */ | ||
| 67 | if (n < 0) | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | sys_close(fd); | ||
| 71 | return NULL; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* | ||
| 75 | * recursively scan <path>, looking for a device node of type <dev> | ||
| 76 | */ | ||
| 77 | static int __init find_in_devfs(char *path, unsigned dev) | ||
| 78 | { | ||
| 79 | char *end = path + strlen(path); | ||
| 80 | int rest = path + 64 - end; | ||
| 81 | int size; | ||
| 82 | char *p = read_dir(path, &size); | ||
| 83 | char *s; | ||
| 84 | |||
| 85 | if (!p) | ||
| 86 | return -1; | ||
| 87 | for (s = p; s < p + size; s += ((struct linux_dirent64 *)s)->d_reclen) { | ||
| 88 | struct linux_dirent64 *d = (struct linux_dirent64 *)s; | ||
| 89 | if (strlen(d->d_name) + 2 > rest) | ||
| 90 | continue; | ||
| 91 | switch (d->d_type) { | ||
| 92 | case DT_BLK: | ||
| 93 | sprintf(end, "/%s", d->d_name); | ||
| 94 | if (bstat(path) != dev) | ||
| 95 | break; | ||
| 96 | kfree(p); | ||
| 97 | return 0; | ||
| 98 | case DT_DIR: | ||
| 99 | if (strcmp(d->d_name, ".") == 0) | ||
| 100 | break; | ||
| 101 | if (strcmp(d->d_name, "..") == 0) | ||
| 102 | break; | ||
| 103 | sprintf(end, "/%s", d->d_name); | ||
| 104 | if (find_in_devfs(path, dev) < 0) | ||
| 105 | break; | ||
| 106 | kfree(p); | ||
| 107 | return 0; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | kfree(p); | ||
| 111 | return -1; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | ||
| 115 | * create a device node called <name> which points to | ||
| 116 | * <devfs_name> if possible, otherwise find a device node | ||
| 117 | * which matches <dev> and make <name> a symlink pointing to it. | ||
| 118 | */ | ||
| 119 | int __init create_dev(char *name, dev_t dev, char *devfs_name) | ||
| 120 | { | ||
| 121 | char path[64]; | ||
| 122 | |||
| 123 | sys_unlink(name); | ||
| 124 | if (devfs_name && devfs_name[0]) { | ||
| 125 | if (strncmp(devfs_name, "/dev/", 5) == 0) | ||
| 126 | devfs_name += 5; | ||
| 127 | sprintf(path, "/dev/%s", devfs_name); | ||
| 128 | if (sys_access(path, 0) == 0) | ||
| 129 | return sys_symlink(devfs_name, name); | ||
| 130 | } | ||
| 131 | if (!dev) | ||
| 132 | return -1; | ||
| 133 | strcpy(path, "/dev"); | ||
| 134 | if (find_in_devfs(path, new_encode_dev(dev)) < 0) | ||
| 135 | return -1; | ||
| 136 | return sys_symlink(path + 5, name); | ||
| 137 | } | ||
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c new file mode 100644 index 000000000000..07e7d31f2d0b --- /dev/null +++ b/init/do_mounts_initrd.c | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | #define __KERNEL_SYSCALLS__ | ||
| 2 | #include <linux/unistd.h> | ||
| 3 | #include <linux/kernel.h> | ||
| 4 | #include <linux/fs.h> | ||
| 5 | #include <linux/minix_fs.h> | ||
| 6 | #include <linux/ext2_fs.h> | ||
| 7 | #include <linux/romfs_fs.h> | ||
| 8 | #include <linux/initrd.h> | ||
| 9 | #include <linux/sched.h> | ||
| 10 | |||
| 11 | #include "do_mounts.h" | ||
| 12 | |||
| 13 | unsigned long initrd_start, initrd_end; | ||
| 14 | int initrd_below_start_ok; | ||
| 15 | unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ | ||
| 16 | static int __initdata old_fd, root_fd; | ||
| 17 | static int __initdata mount_initrd = 1; | ||
| 18 | |||
| 19 | static int __init no_initrd(char *str) | ||
| 20 | { | ||
| 21 | mount_initrd = 0; | ||
| 22 | return 1; | ||
| 23 | } | ||
| 24 | |||
| 25 | __setup("noinitrd", no_initrd); | ||
| 26 | |||
| 27 | static int __init do_linuxrc(void * shell) | ||
| 28 | { | ||
| 29 | static char *argv[] = { "linuxrc", NULL, }; | ||
| 30 | extern char * envp_init[]; | ||
| 31 | |||
| 32 | sys_close(old_fd);sys_close(root_fd); | ||
| 33 | sys_close(0);sys_close(1);sys_close(2); | ||
| 34 | sys_setsid(); | ||
| 35 | (void) sys_open("/dev/console",O_RDWR,0); | ||
| 36 | (void) sys_dup(0); | ||
| 37 | (void) sys_dup(0); | ||
| 38 | return execve(shell, argv, envp_init); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void __init handle_initrd(void) | ||
| 42 | { | ||
| 43 | int error; | ||
| 44 | int i, pid; | ||
| 45 | |||
| 46 | real_root_dev = new_encode_dev(ROOT_DEV); | ||
| 47 | create_dev("/dev/root.old", Root_RAM0, NULL); | ||
| 48 | /* mount initrd on rootfs' /root */ | ||
| 49 | mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); | ||
| 50 | sys_mkdir("/old", 0700); | ||
| 51 | root_fd = sys_open("/", 0, 0); | ||
| 52 | old_fd = sys_open("/old", 0, 0); | ||
| 53 | /* move initrd over / and chdir/chroot in initrd root */ | ||
| 54 | sys_chdir("/root"); | ||
| 55 | sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||
| 56 | sys_chroot("."); | ||
| 57 | mount_devfs_fs (); | ||
| 58 | |||
| 59 | pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); | ||
| 60 | if (pid > 0) { | ||
| 61 | while (pid != sys_wait4(-1, &i, 0, NULL)) | ||
| 62 | yield(); | ||
| 63 | } | ||
| 64 | |||
| 65 | /* move initrd to rootfs' /old */ | ||
| 66 | sys_fchdir(old_fd); | ||
| 67 | sys_mount("/", ".", NULL, MS_MOVE, NULL); | ||
| 68 | /* switch root and cwd back to / of rootfs */ | ||
| 69 | sys_fchdir(root_fd); | ||
| 70 | sys_chroot("."); | ||
| 71 | sys_close(old_fd); | ||
| 72 | sys_close(root_fd); | ||
| 73 | umount_devfs("/old/dev"); | ||
| 74 | |||
| 75 | if (new_decode_dev(real_root_dev) == Root_RAM0) { | ||
| 76 | sys_chdir("/old"); | ||
| 77 | return; | ||
| 78 | } | ||
| 79 | |||
| 80 | ROOT_DEV = new_decode_dev(real_root_dev); | ||
| 81 | mount_root(); | ||
| 82 | |||
| 83 | printk(KERN_NOTICE "Trying to move old root to /initrd ... "); | ||
| 84 | error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); | ||
| 85 | if (!error) | ||
| 86 | printk("okay\n"); | ||
| 87 | else { | ||
| 88 | int fd = sys_open("/dev/root.old", O_RDWR, 0); | ||
| 89 | printk("failed\n"); | ||
| 90 | printk(KERN_NOTICE "Unmounting old root\n"); | ||
| 91 | sys_umount("/old", MNT_DETACH); | ||
| 92 | printk(KERN_NOTICE "Trying to free ramdisk memory ... "); | ||
| 93 | if (fd < 0) { | ||
| 94 | error = fd; | ||
| 95 | } else { | ||
| 96 | error = sys_ioctl(fd, BLKFLSBUF, 0); | ||
| 97 | sys_close(fd); | ||
| 98 | } | ||
| 99 | printk(!error ? "okay\n" : "failed\n"); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | int __init initrd_load(void) | ||
| 104 | { | ||
| 105 | if (mount_initrd) { | ||
| 106 | create_dev("/dev/ram", Root_RAM0, NULL); | ||
| 107 | /* | ||
| 108 | * Load the initrd data into /dev/ram0. Execute it as initrd | ||
| 109 | * unless /dev/ram0 is supposed to be our actual root device, | ||
| 110 | * in that case the ram disk is just set up here, and gets | ||
| 111 | * mounted in the normal path. | ||
| 112 | */ | ||
| 113 | if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { | ||
| 114 | sys_unlink("/initrd.image"); | ||
| 115 | handle_initrd(); | ||
| 116 | return 1; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | sys_unlink("/initrd.image"); | ||
| 120 | return 0; | ||
| 121 | } | ||
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c new file mode 100644 index 000000000000..3fbc3555ce96 --- /dev/null +++ b/init/do_mounts_md.c | |||
| @@ -0,0 +1,290 @@ | |||
| 1 | |||
| 2 | #include <linux/raid/md.h> | ||
| 3 | |||
| 4 | #include "do_mounts.h" | ||
| 5 | |||
| 6 | /* | ||
| 7 | * When md (and any require personalities) are compiled into the kernel | ||
| 8 | * (not a module), arrays can be assembles are boot time using with AUTODETECT | ||
| 9 | * where specially marked partitions are registered with md_autodetect_dev(), | ||
| 10 | * and with MD_BOOT where devices to be collected are given on the boot line | ||
| 11 | * with md=..... | ||
| 12 | * The code for that is here. | ||
| 13 | */ | ||
| 14 | |||
| 15 | static int __initdata raid_noautodetect, raid_autopart; | ||
| 16 | |||
| 17 | static struct { | ||
| 18 | int minor; | ||
| 19 | int partitioned; | ||
| 20 | int pers; | ||
| 21 | int chunk; | ||
| 22 | char *device_names; | ||
| 23 | } md_setup_args[MAX_MD_DEVS] __initdata; | ||
| 24 | |||
| 25 | static int md_setup_ents __initdata; | ||
| 26 | |||
| 27 | extern int mdp_major; | ||
| 28 | /* | ||
| 29 | * Parse the command-line parameters given our kernel, but do not | ||
| 30 | * actually try to invoke the MD device now; that is handled by | ||
| 31 | * md_setup_drive after the low-level disk drivers have initialised. | ||
| 32 | * | ||
| 33 | * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which | ||
| 34 | * assigns the task of parsing integer arguments to the | ||
| 35 | * invoked program now). Added ability to initialise all | ||
| 36 | * the MD devices (by specifying multiple "md=" lines) | ||
| 37 | * instead of just one. -- KTK | ||
| 38 | * 18May2000: Added support for persistent-superblock arrays: | ||
| 39 | * md=n,0,factor,fault,device-list uses RAID0 for device n | ||
| 40 | * md=n,-1,factor,fault,device-list uses LINEAR for device n | ||
| 41 | * md=n,device-list reads a RAID superblock from the devices | ||
| 42 | * elements in device-list are read by name_to_kdev_t so can be | ||
| 43 | * a hex number or something like /dev/hda1 /dev/sdb | ||
| 44 | * 2001-06-03: Dave Cinege <dcinege@psychosis.com> | ||
| 45 | * Shifted name_to_kdev_t() and related operations to md_set_drive() | ||
| 46 | * for later execution. Rewrote section to make devfs compatible. | ||
| 47 | */ | ||
| 48 | static int __init md_setup(char *str) | ||
| 49 | { | ||
| 50 | int minor, level, factor, fault, pers, partitioned = 0; | ||
| 51 | char *pername = ""; | ||
| 52 | char *str1; | ||
| 53 | int ent; | ||
| 54 | |||
| 55 | if (*str == 'd') { | ||
| 56 | partitioned = 1; | ||
| 57 | str++; | ||
| 58 | } | ||
| 59 | if (get_option(&str, &minor) != 2) { /* MD Number */ | ||
| 60 | printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | str1 = str; | ||
| 64 | if (minor >= MAX_MD_DEVS) { | ||
| 65 | printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | for (ent=0 ; ent< md_setup_ents ; ent++) | ||
| 69 | if (md_setup_args[ent].minor == minor && | ||
| 70 | md_setup_args[ent].partitioned == partitioned) { | ||
| 71 | printk(KERN_WARNING "md: md=%s%d, Specified more than once. " | ||
| 72 | "Replacing previous definition.\n", partitioned?"d":"", minor); | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | if (ent >= MAX_MD_DEVS) { | ||
| 76 | printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | if (ent >= md_setup_ents) | ||
| 80 | md_setup_ents++; | ||
| 81 | switch (get_option(&str, &level)) { /* RAID Personality */ | ||
| 82 | case 2: /* could be 0 or -1.. */ | ||
| 83 | if (level == 0 || level == LEVEL_LINEAR) { | ||
| 84 | if (get_option(&str, &factor) != 2 || /* Chunk Size */ | ||
| 85 | get_option(&str, &fault) != 2) { | ||
| 86 | printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | md_setup_args[ent].pers = level; | ||
| 90 | md_setup_args[ent].chunk = 1 << (factor+12); | ||
| 91 | if (level == LEVEL_LINEAR) { | ||
| 92 | pers = LINEAR; | ||
| 93 | pername = "linear"; | ||
| 94 | } else { | ||
| 95 | pers = RAID0; | ||
| 96 | pername = "raid0"; | ||
| 97 | } | ||
| 98 | md_setup_args[ent].pers = pers; | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | /* FALL THROUGH */ | ||
| 102 | case 1: /* the first device is numeric */ | ||
| 103 | str = str1; | ||
| 104 | /* FALL THROUGH */ | ||
| 105 | case 0: | ||
| 106 | md_setup_args[ent].pers = 0; | ||
| 107 | pername="super-block"; | ||
| 108 | } | ||
| 109 | |||
| 110 | printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n", | ||
| 111 | minor, pername, str); | ||
| 112 | md_setup_args[ent].device_names = str; | ||
| 113 | md_setup_args[ent].partitioned = partitioned; | ||
| 114 | md_setup_args[ent].minor = minor; | ||
| 115 | |||
| 116 | return 1; | ||
| 117 | } | ||
| 118 | |||
| 119 | #define MdpMinorShift 6 | ||
| 120 | |||
| 121 | static void __init md_setup_drive(void) | ||
| 122 | { | ||
| 123 | int minor, i, ent, partitioned; | ||
| 124 | dev_t dev; | ||
| 125 | dev_t devices[MD_SB_DISKS+1]; | ||
| 126 | |||
| 127 | for (ent = 0; ent < md_setup_ents ; ent++) { | ||
| 128 | int fd; | ||
| 129 | int err = 0; | ||
| 130 | char *devname; | ||
| 131 | mdu_disk_info_t dinfo; | ||
| 132 | char name[16], devfs_name[16]; | ||
| 133 | |||
| 134 | minor = md_setup_args[ent].minor; | ||
| 135 | partitioned = md_setup_args[ent].partitioned; | ||
| 136 | devname = md_setup_args[ent].device_names; | ||
| 137 | |||
| 138 | sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor); | ||
| 139 | sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor); | ||
| 140 | if (partitioned) | ||
| 141 | dev = MKDEV(mdp_major, minor << MdpMinorShift); | ||
| 142 | else | ||
| 143 | dev = MKDEV(MD_MAJOR, minor); | ||
| 144 | create_dev(name, dev, devfs_name); | ||
| 145 | for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { | ||
| 146 | char *p; | ||
| 147 | char comp_name[64]; | ||
| 148 | u32 rdev; | ||
| 149 | |||
| 150 | p = strchr(devname, ','); | ||
| 151 | if (p) | ||
| 152 | *p++ = 0; | ||
| 153 | |||
| 154 | dev = name_to_dev_t(devname); | ||
| 155 | if (strncmp(devname, "/dev/", 5) == 0) | ||
| 156 | devname += 5; | ||
| 157 | snprintf(comp_name, 63, "/dev/%s", devname); | ||
| 158 | rdev = bstat(comp_name); | ||
| 159 | if (rdev) | ||
| 160 | dev = new_decode_dev(rdev); | ||
| 161 | if (!dev) { | ||
| 162 | printk(KERN_WARNING "md: Unknown device name: %s\n", devname); | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | |||
| 166 | devices[i] = dev; | ||
| 167 | |||
| 168 | devname = p; | ||
| 169 | } | ||
| 170 | devices[i] = 0; | ||
| 171 | |||
| 172 | if (!i) | ||
| 173 | continue; | ||
| 174 | |||
| 175 | printk(KERN_INFO "md: Loading md%s%d: %s\n", | ||
| 176 | partitioned ? "_d" : "", minor, | ||
| 177 | md_setup_args[ent].device_names); | ||
| 178 | |||
| 179 | fd = sys_open(name, 0, 0); | ||
| 180 | if (fd < 0) { | ||
| 181 | printk(KERN_ERR "md: open failed - cannot start " | ||
| 182 | "array %s\n", name); | ||
| 183 | continue; | ||
| 184 | } | ||
| 185 | if (sys_ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) { | ||
| 186 | printk(KERN_WARNING | ||
| 187 | "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", | ||
| 188 | minor); | ||
| 189 | sys_close(fd); | ||
| 190 | continue; | ||
| 191 | } | ||
| 192 | |||
| 193 | if (md_setup_args[ent].pers) { | ||
| 194 | /* non-persistent */ | ||
| 195 | mdu_array_info_t ainfo; | ||
| 196 | ainfo.level = pers_to_level(md_setup_args[ent].pers); | ||
| 197 | ainfo.size = 0; | ||
| 198 | ainfo.nr_disks =0; | ||
| 199 | ainfo.raid_disks =0; | ||
| 200 | while (devices[ainfo.raid_disks]) | ||
| 201 | ainfo.raid_disks++; | ||
| 202 | ainfo.md_minor =minor; | ||
| 203 | ainfo.not_persistent = 1; | ||
| 204 | |||
| 205 | ainfo.state = (1 << MD_SB_CLEAN); | ||
| 206 | ainfo.layout = 0; | ||
| 207 | ainfo.chunk_size = md_setup_args[ent].chunk; | ||
| 208 | err = sys_ioctl(fd, SET_ARRAY_INFO, (long)&ainfo); | ||
| 209 | for (i = 0; !err && i <= MD_SB_DISKS; i++) { | ||
| 210 | dev = devices[i]; | ||
| 211 | if (!dev) | ||
| 212 | break; | ||
| 213 | dinfo.number = i; | ||
| 214 | dinfo.raid_disk = i; | ||
| 215 | dinfo.state = (1<<MD_DISK_ACTIVE)|(1<<MD_DISK_SYNC); | ||
| 216 | dinfo.major = MAJOR(dev); | ||
| 217 | dinfo.minor = MINOR(dev); | ||
| 218 | err = sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo); | ||
| 219 | } | ||
| 220 | } else { | ||
| 221 | /* persistent */ | ||
| 222 | for (i = 0; i <= MD_SB_DISKS; i++) { | ||
| 223 | dev = devices[i]; | ||
| 224 | if (!dev) | ||
| 225 | break; | ||
| 226 | dinfo.major = MAJOR(dev); | ||
| 227 | dinfo.minor = MINOR(dev); | ||
| 228 | sys_ioctl(fd, ADD_NEW_DISK, (long)&dinfo); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | if (!err) | ||
| 232 | err = sys_ioctl(fd, RUN_ARRAY, 0); | ||
| 233 | if (err) | ||
| 234 | printk(KERN_WARNING "md: starting md%d failed\n", minor); | ||
| 235 | else { | ||
| 236 | /* reread the partition table. | ||
| 237 | * I (neilb) and not sure why this is needed, but I cannot | ||
| 238 | * boot a kernel with devfs compiled in from partitioned md | ||
| 239 | * array without it | ||
| 240 | */ | ||
| 241 | sys_close(fd); | ||
| 242 | fd = sys_open(name, 0, 0); | ||
| 243 | sys_ioctl(fd, BLKRRPART, 0); | ||
| 244 | } | ||
| 245 | sys_close(fd); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | static int __init raid_setup(char *str) | ||
| 250 | { | ||
| 251 | int len, pos; | ||
| 252 | |||
| 253 | len = strlen(str) + 1; | ||
| 254 | pos = 0; | ||
| 255 | |||
| 256 | while (pos < len) { | ||
| 257 | char *comma = strchr(str+pos, ','); | ||
| 258 | int wlen; | ||
| 259 | if (comma) | ||
| 260 | wlen = (comma-str)-pos; | ||
| 261 | else wlen = (len-1)-pos; | ||
| 262 | |||
| 263 | if (!strncmp(str, "noautodetect", wlen)) | ||
| 264 | raid_noautodetect = 1; | ||
| 265 | if (strncmp(str, "partitionable", wlen)==0) | ||
| 266 | raid_autopart = 1; | ||
| 267 | if (strncmp(str, "part", wlen)==0) | ||
| 268 | raid_autopart = 1; | ||
| 269 | pos += wlen+1; | ||
| 270 | } | ||
| 271 | return 1; | ||
| 272 | } | ||
| 273 | |||
| 274 | __setup("raid=", raid_setup); | ||
| 275 | __setup("md=", md_setup); | ||
| 276 | |||
| 277 | void __init md_run_setup(void) | ||
| 278 | { | ||
| 279 | create_dev("/dev/md0", MKDEV(MD_MAJOR, 0), "md/0"); | ||
| 280 | if (raid_noautodetect) | ||
| 281 | printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); | ||
| 282 | else { | ||
| 283 | int fd = sys_open("/dev/md0", 0, 0); | ||
| 284 | if (fd >= 0) { | ||
| 285 | sys_ioctl(fd, RAID_AUTORUN, raid_autopart); | ||
| 286 | sys_close(fd); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | md_setup_drive(); | ||
| 290 | } | ||
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c new file mode 100644 index 000000000000..c10b08a80982 --- /dev/null +++ b/init/do_mounts_rd.c | |||
| @@ -0,0 +1,429 @@ | |||
| 1 | |||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/fs.h> | ||
| 4 | #include <linux/minix_fs.h> | ||
| 5 | #include <linux/ext2_fs.h> | ||
| 6 | #include <linux/romfs_fs.h> | ||
| 7 | #include <linux/cramfs_fs.h> | ||
| 8 | #include <linux/initrd.h> | ||
| 9 | #include <linux/string.h> | ||
| 10 | |||
| 11 | #include "do_mounts.h" | ||
| 12 | |||
| 13 | #define BUILD_CRAMDISK | ||
| 14 | |||
| 15 | int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */ | ||
| 16 | |||
| 17 | static int __init prompt_ramdisk(char *str) | ||
| 18 | { | ||
| 19 | rd_prompt = simple_strtol(str,NULL,0) & 1; | ||
| 20 | return 1; | ||
| 21 | } | ||
| 22 | __setup("prompt_ramdisk=", prompt_ramdisk); | ||
| 23 | |||
| 24 | int __initdata rd_image_start; /* starting block # of image */ | ||
| 25 | |||
| 26 | static int __init ramdisk_start_setup(char *str) | ||
| 27 | { | ||
| 28 | rd_image_start = simple_strtol(str,NULL,0); | ||
| 29 | return 1; | ||
| 30 | } | ||
| 31 | __setup("ramdisk_start=", ramdisk_start_setup); | ||
| 32 | |||
| 33 | static int __init crd_load(int in_fd, int out_fd); | ||
| 34 | |||
| 35 | /* | ||
| 36 | * This routine tries to find a RAM disk image to load, and returns the | ||
| 37 | * number of blocks to read for a non-compressed image, 0 if the image | ||
| 38 | * is a compressed image, and -1 if an image with the right magic | ||
| 39 | * numbers could not be found. | ||
| 40 | * | ||
| 41 | * We currently check for the following magic numbers: | ||
| 42 | * minix | ||
| 43 | * ext2 | ||
| 44 | * romfs | ||
| 45 | * cramfs | ||
| 46 | * gzip | ||
| 47 | */ | ||
| 48 | static int __init | ||
| 49 | identify_ramdisk_image(int fd, int start_block) | ||
| 50 | { | ||
| 51 | const int size = 512; | ||
| 52 | struct minix_super_block *minixsb; | ||
| 53 | struct ext2_super_block *ext2sb; | ||
| 54 | struct romfs_super_block *romfsb; | ||
| 55 | struct cramfs_super *cramfsb; | ||
| 56 | int nblocks = -1; | ||
| 57 | unsigned char *buf; | ||
| 58 | |||
| 59 | buf = kmalloc(size, GFP_KERNEL); | ||
| 60 | if (buf == 0) | ||
| 61 | return -1; | ||
| 62 | |||
| 63 | minixsb = (struct minix_super_block *) buf; | ||
| 64 | ext2sb = (struct ext2_super_block *) buf; | ||
| 65 | romfsb = (struct romfs_super_block *) buf; | ||
| 66 | cramfsb = (struct cramfs_super *) buf; | ||
| 67 | memset(buf, 0xe5, size); | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Read block 0 to test for gzipped kernel | ||
| 71 | */ | ||
| 72 | sys_lseek(fd, start_block * BLOCK_SIZE, 0); | ||
| 73 | sys_read(fd, buf, size); | ||
| 74 | |||
| 75 | /* | ||
| 76 | * If it matches the gzip magic numbers, return -1 | ||
| 77 | */ | ||
| 78 | if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { | ||
| 79 | printk(KERN_NOTICE | ||
| 80 | "RAMDISK: Compressed image found at block %d\n", | ||
| 81 | start_block); | ||
| 82 | nblocks = 0; | ||
| 83 | goto done; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* romfs is at block zero too */ | ||
| 87 | if (romfsb->word0 == ROMSB_WORD0 && | ||
| 88 | romfsb->word1 == ROMSB_WORD1) { | ||
| 89 | printk(KERN_NOTICE | ||
| 90 | "RAMDISK: romfs filesystem found at block %d\n", | ||
| 91 | start_block); | ||
| 92 | nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; | ||
| 93 | goto done; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (cramfsb->magic == CRAMFS_MAGIC) { | ||
| 97 | printk(KERN_NOTICE | ||
| 98 | "RAMDISK: cramfs filesystem found at block %d\n", | ||
| 99 | start_block); | ||
| 100 | nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; | ||
| 101 | goto done; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Read block 1 to test for minix and ext2 superblock | ||
| 106 | */ | ||
| 107 | sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0); | ||
| 108 | sys_read(fd, buf, size); | ||
| 109 | |||
| 110 | /* Try minix */ | ||
| 111 | if (minixsb->s_magic == MINIX_SUPER_MAGIC || | ||
| 112 | minixsb->s_magic == MINIX_SUPER_MAGIC2) { | ||
| 113 | printk(KERN_NOTICE | ||
| 114 | "RAMDISK: Minix filesystem found at block %d\n", | ||
| 115 | start_block); | ||
| 116 | nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; | ||
| 117 | goto done; | ||
| 118 | } | ||
| 119 | |||
| 120 | /* Try ext2 */ | ||
| 121 | if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { | ||
| 122 | printk(KERN_NOTICE | ||
| 123 | "RAMDISK: ext2 filesystem found at block %d\n", | ||
| 124 | start_block); | ||
| 125 | nblocks = le32_to_cpu(ext2sb->s_blocks_count) << | ||
| 126 | le32_to_cpu(ext2sb->s_log_block_size); | ||
| 127 | goto done; | ||
| 128 | } | ||
| 129 | |||
| 130 | printk(KERN_NOTICE | ||
| 131 | "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", | ||
| 132 | start_block); | ||
| 133 | |||
| 134 | done: | ||
| 135 | sys_lseek(fd, start_block * BLOCK_SIZE, 0); | ||
| 136 | kfree(buf); | ||
| 137 | return nblocks; | ||
| 138 | } | ||
| 139 | |||
| 140 | int __init rd_load_image(char *from) | ||
| 141 | { | ||
| 142 | int res = 0; | ||
| 143 | int in_fd, out_fd; | ||
| 144 | unsigned long rd_blocks, devblocks; | ||
| 145 | int nblocks, i, disk; | ||
| 146 | char *buf = NULL; | ||
| 147 | unsigned short rotate = 0; | ||
| 148 | #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) | ||
| 149 | char rotator[4] = { '|' , '/' , '-' , '\\' }; | ||
| 150 | #endif | ||
| 151 | |||
| 152 | out_fd = sys_open("/dev/ram", O_RDWR, 0); | ||
| 153 | if (out_fd < 0) | ||
| 154 | goto out; | ||
| 155 | |||
| 156 | in_fd = sys_open(from, O_RDONLY, 0); | ||
| 157 | if (in_fd < 0) | ||
| 158 | goto noclose_input; | ||
| 159 | |||
| 160 | nblocks = identify_ramdisk_image(in_fd, rd_image_start); | ||
| 161 | if (nblocks < 0) | ||
| 162 | goto done; | ||
| 163 | |||
| 164 | if (nblocks == 0) { | ||
| 165 | #ifdef BUILD_CRAMDISK | ||
| 166 | if (crd_load(in_fd, out_fd) == 0) | ||
| 167 | goto successful_load; | ||
| 168 | #else | ||
| 169 | printk(KERN_NOTICE | ||
| 170 | "RAMDISK: Kernel does not support compressed " | ||
| 171 | "RAM disk images\n"); | ||
| 172 | #endif | ||
| 173 | goto done; | ||
| 174 | } | ||
| 175 | |||
| 176 | /* | ||
| 177 | * NOTE NOTE: nblocks is not actually blocks but | ||
| 178 | * the number of kibibytes of data to load into a ramdisk. | ||
| 179 | * So any ramdisk block size that is a multiple of 1KiB should | ||
| 180 | * work when the appropriate ramdisk_blocksize is specified | ||
| 181 | * on the command line. | ||
| 182 | * | ||
| 183 | * The default ramdisk_blocksize is 1KiB and it is generally | ||
| 184 | * silly to use anything else, so make sure to use 1KiB | ||
| 185 | * blocksize while generating ext2fs ramdisk-images. | ||
| 186 | */ | ||
| 187 | if (sys_ioctl(out_fd, BLKGETSIZE, (unsigned long)&rd_blocks) < 0) | ||
| 188 | rd_blocks = 0; | ||
| 189 | else | ||
| 190 | rd_blocks >>= 1; | ||
| 191 | |||
| 192 | if (nblocks > rd_blocks) { | ||
| 193 | printk("RAMDISK: image too big! (%dKiB/%ldKiB)\n", | ||
| 194 | nblocks, rd_blocks); | ||
| 195 | goto done; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* | ||
| 199 | * OK, time to copy in the data | ||
| 200 | */ | ||
| 201 | if (sys_ioctl(in_fd, BLKGETSIZE, (unsigned long)&devblocks) < 0) | ||
| 202 | devblocks = 0; | ||
| 203 | else | ||
| 204 | devblocks >>= 1; | ||
| 205 | |||
| 206 | if (strcmp(from, "/initrd.image") == 0) | ||
| 207 | devblocks = nblocks; | ||
| 208 | |||
| 209 | if (devblocks == 0) { | ||
| 210 | printk(KERN_ERR "RAMDISK: could not determine device size\n"); | ||
| 211 | goto done; | ||
| 212 | } | ||
| 213 | |||
| 214 | buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); | ||
| 215 | if (buf == 0) { | ||
| 216 | printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); | ||
| 217 | goto done; | ||
| 218 | } | ||
| 219 | |||
| 220 | printk(KERN_NOTICE "RAMDISK: Loading %dKiB [%ld disk%s] into ram disk... ", | ||
| 221 | nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); | ||
| 222 | for (i = 0, disk = 1; i < nblocks; i++) { | ||
| 223 | if (i && (i % devblocks == 0)) { | ||
| 224 | printk("done disk #%d.\n", disk++); | ||
| 225 | rotate = 0; | ||
| 226 | if (sys_close(in_fd)) { | ||
| 227 | printk("Error closing the disk.\n"); | ||
| 228 | goto noclose_input; | ||
| 229 | } | ||
| 230 | change_floppy("disk #%d", disk); | ||
| 231 | in_fd = sys_open(from, O_RDONLY, 0); | ||
| 232 | if (in_fd < 0) { | ||
| 233 | printk("Error opening disk.\n"); | ||
| 234 | goto noclose_input; | ||
| 235 | } | ||
| 236 | printk("Loading disk #%d... ", disk); | ||
| 237 | } | ||
| 238 | sys_read(in_fd, buf, BLOCK_SIZE); | ||
| 239 | sys_write(out_fd, buf, BLOCK_SIZE); | ||
| 240 | #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) | ||
| 241 | if (!(i % 16)) { | ||
| 242 | printk("%c\b", rotator[rotate & 0x3]); | ||
| 243 | rotate++; | ||
| 244 | } | ||
| 245 | #endif | ||
| 246 | } | ||
| 247 | printk("done.\n"); | ||
| 248 | |||
| 249 | successful_load: | ||
| 250 | res = 1; | ||
| 251 | done: | ||
| 252 | sys_close(in_fd); | ||
| 253 | noclose_input: | ||
| 254 | sys_close(out_fd); | ||
| 255 | out: | ||
| 256 | kfree(buf); | ||
| 257 | sys_unlink("/dev/ram"); | ||
| 258 | return res; | ||
| 259 | } | ||
| 260 | |||
| 261 | int __init rd_load_disk(int n) | ||
| 262 | { | ||
| 263 | if (rd_prompt) | ||
| 264 | change_floppy("root floppy disk to be loaded into RAM disk"); | ||
| 265 | create_dev("/dev/root", ROOT_DEV, root_device_name); | ||
| 266 | create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL); | ||
| 267 | return rd_load_image("/dev/root"); | ||
| 268 | } | ||
| 269 | |||
| 270 | #ifdef BUILD_CRAMDISK | ||
| 271 | |||
| 272 | /* | ||
| 273 | * gzip declarations | ||
| 274 | */ | ||
| 275 | |||
| 276 | #define OF(args) args | ||
| 277 | |||
| 278 | #ifndef memzero | ||
| 279 | #define memzero(s, n) memset ((s), 0, (n)) | ||
| 280 | #endif | ||
| 281 | |||
| 282 | typedef unsigned char uch; | ||
| 283 | typedef unsigned short ush; | ||
| 284 | typedef unsigned long ulg; | ||
| 285 | |||
| 286 | #define INBUFSIZ 4096 | ||
| 287 | #define WSIZE 0x8000 /* window size--must be a power of two, and */ | ||
| 288 | /* at least 32K for zip's deflate method */ | ||
| 289 | |||
| 290 | static uch *inbuf; | ||
| 291 | static uch *window; | ||
| 292 | |||
| 293 | static unsigned insize; /* valid bytes in inbuf */ | ||
| 294 | static unsigned inptr; /* index of next byte to be processed in inbuf */ | ||
| 295 | static unsigned outcnt; /* bytes in output buffer */ | ||
| 296 | static int exit_code; | ||
| 297 | static int unzip_error; | ||
| 298 | static long bytes_out; | ||
| 299 | static int crd_infd, crd_outfd; | ||
| 300 | |||
| 301 | #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) | ||
| 302 | |||
| 303 | /* Diagnostic functions (stubbed out) */ | ||
| 304 | #define Assert(cond,msg) | ||
| 305 | #define Trace(x) | ||
| 306 | #define Tracev(x) | ||
| 307 | #define Tracevv(x) | ||
| 308 | #define Tracec(c,x) | ||
| 309 | #define Tracecv(c,x) | ||
| 310 | |||
| 311 | #define STATIC static | ||
| 312 | #define INIT __init | ||
| 313 | |||
| 314 | static int __init fill_inbuf(void); | ||
| 315 | static void __init flush_window(void); | ||
| 316 | static void __init *malloc(size_t size); | ||
| 317 | static void __init free(void *where); | ||
| 318 | static void __init error(char *m); | ||
| 319 | static void __init gzip_mark(void **); | ||
| 320 | static void __init gzip_release(void **); | ||
| 321 | |||
| 322 | #include "../lib/inflate.c" | ||
| 323 | |||
| 324 | static void __init *malloc(size_t size) | ||
| 325 | { | ||
| 326 | return kmalloc(size, GFP_KERNEL); | ||
| 327 | } | ||
| 328 | |||
| 329 | static void __init free(void *where) | ||
| 330 | { | ||
| 331 | kfree(where); | ||
| 332 | } | ||
| 333 | |||
| 334 | static void __init gzip_mark(void **ptr) | ||
| 335 | { | ||
| 336 | } | ||
| 337 | |||
| 338 | static void __init gzip_release(void **ptr) | ||
| 339 | { | ||
| 340 | } | ||
| 341 | |||
| 342 | |||
| 343 | /* =========================================================================== | ||
| 344 | * Fill the input buffer. This is called only when the buffer is empty | ||
| 345 | * and at least one byte is really needed. | ||
| 346 | * Returning -1 does not guarantee that gunzip() will ever return. | ||
| 347 | */ | ||
| 348 | static int __init fill_inbuf(void) | ||
| 349 | { | ||
| 350 | if (exit_code) return -1; | ||
| 351 | |||
| 352 | insize = sys_read(crd_infd, inbuf, INBUFSIZ); | ||
| 353 | if (insize == 0) { | ||
| 354 | error("RAMDISK: ran out of compressed data"); | ||
| 355 | return -1; | ||
| 356 | } | ||
| 357 | |||
| 358 | inptr = 1; | ||
| 359 | |||
| 360 | return inbuf[0]; | ||
| 361 | } | ||
| 362 | |||
| 363 | /* =========================================================================== | ||
| 364 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
| 365 | * (Used for the decompressed data only.) | ||
| 366 | */ | ||
| 367 | static void __init flush_window(void) | ||
| 368 | { | ||
| 369 | ulg c = crc; /* temporary variable */ | ||
| 370 | unsigned n, written; | ||
| 371 | uch *in, ch; | ||
| 372 | |||
| 373 | written = sys_write(crd_outfd, window, outcnt); | ||
| 374 | if (written != outcnt && unzip_error == 0) { | ||
| 375 | printk(KERN_ERR "RAMDISK: incomplete write (%d != %d) %ld\n", | ||
| 376 | written, outcnt, bytes_out); | ||
| 377 | unzip_error = 1; | ||
| 378 | } | ||
| 379 | in = window; | ||
| 380 | for (n = 0; n < outcnt; n++) { | ||
| 381 | ch = *in++; | ||
| 382 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
| 383 | } | ||
| 384 | crc = c; | ||
| 385 | bytes_out += (ulg)outcnt; | ||
| 386 | outcnt = 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | static void __init error(char *x) | ||
| 390 | { | ||
| 391 | printk(KERN_ERR "%s\n", x); | ||
| 392 | exit_code = 1; | ||
| 393 | unzip_error = 1; | ||
| 394 | } | ||
| 395 | |||
| 396 | static int __init crd_load(int in_fd, int out_fd) | ||
| 397 | { | ||
| 398 | int result; | ||
| 399 | |||
| 400 | insize = 0; /* valid bytes in inbuf */ | ||
| 401 | inptr = 0; /* index of next byte to be processed in inbuf */ | ||
| 402 | outcnt = 0; /* bytes in output buffer */ | ||
| 403 | exit_code = 0; | ||
| 404 | bytes_out = 0; | ||
| 405 | crc = (ulg)0xffffffffL; /* shift register contents */ | ||
| 406 | |||
| 407 | crd_infd = in_fd; | ||
| 408 | crd_outfd = out_fd; | ||
| 409 | inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); | ||
| 410 | if (inbuf == 0) { | ||
| 411 | printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n"); | ||
| 412 | return -1; | ||
| 413 | } | ||
| 414 | window = kmalloc(WSIZE, GFP_KERNEL); | ||
| 415 | if (window == 0) { | ||
| 416 | printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n"); | ||
| 417 | kfree(inbuf); | ||
| 418 | return -1; | ||
| 419 | } | ||
| 420 | makecrc(); | ||
| 421 | result = gunzip(); | ||
| 422 | if (unzip_error) | ||
| 423 | result = 1; | ||
| 424 | kfree(inbuf); | ||
| 425 | kfree(window); | ||
| 426 | return result; | ||
| 427 | } | ||
| 428 | |||
| 429 | #endif /* BUILD_CRAMDISK */ | ||
diff --git a/init/initramfs.c b/init/initramfs.c new file mode 100644 index 000000000000..02c5ce64990d --- /dev/null +++ b/init/initramfs.c | |||
| @@ -0,0 +1,500 @@ | |||
| 1 | #include <linux/init.h> | ||
| 2 | #include <linux/fs.h> | ||
| 3 | #include <linux/slab.h> | ||
| 4 | #include <linux/types.h> | ||
| 5 | #include <linux/fcntl.h> | ||
| 6 | #include <linux/delay.h> | ||
| 7 | #include <linux/string.h> | ||
| 8 | #include <linux/syscalls.h> | ||
| 9 | |||
| 10 | static __initdata char *message; | ||
| 11 | static void __init error(char *x) | ||
| 12 | { | ||
| 13 | if (!message) | ||
| 14 | message = x; | ||
| 15 | } | ||
| 16 | |||
| 17 | static void __init *malloc(size_t size) | ||
| 18 | { | ||
| 19 | return kmalloc(size, GFP_KERNEL); | ||
| 20 | } | ||
| 21 | |||
| 22 | static void __init free(void *where) | ||
| 23 | { | ||
| 24 | kfree(where); | ||
| 25 | } | ||
| 26 | |||
| 27 | /* link hash */ | ||
| 28 | |||
| 29 | static __initdata struct hash { | ||
| 30 | int ino, minor, major; | ||
| 31 | struct hash *next; | ||
| 32 | char *name; | ||
| 33 | } *head[32]; | ||
| 34 | |||
| 35 | static inline int hash(int major, int minor, int ino) | ||
| 36 | { | ||
| 37 | unsigned long tmp = ino + minor + (major << 3); | ||
| 38 | tmp += tmp >> 5; | ||
| 39 | return tmp & 31; | ||
| 40 | } | ||
| 41 | |||
| 42 | static char __init *find_link(int major, int minor, int ino, char *name) | ||
| 43 | { | ||
| 44 | struct hash **p, *q; | ||
| 45 | for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { | ||
| 46 | if ((*p)->ino != ino) | ||
| 47 | continue; | ||
| 48 | if ((*p)->minor != minor) | ||
| 49 | continue; | ||
| 50 | if ((*p)->major != major) | ||
| 51 | continue; | ||
| 52 | return (*p)->name; | ||
| 53 | } | ||
| 54 | q = (struct hash *)malloc(sizeof(struct hash)); | ||
| 55 | if (!q) | ||
| 56 | panic("can't allocate link hash entry"); | ||
| 57 | q->ino = ino; | ||
| 58 | q->minor = minor; | ||
| 59 | q->major = major; | ||
| 60 | q->name = name; | ||
| 61 | q->next = NULL; | ||
| 62 | *p = q; | ||
| 63 | return NULL; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void __init free_hash(void) | ||
| 67 | { | ||
| 68 | struct hash **p, *q; | ||
| 69 | for (p = head; p < head + 32; p++) { | ||
| 70 | while (*p) { | ||
| 71 | q = *p; | ||
| 72 | *p = q->next; | ||
| 73 | free(q); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | /* cpio header parsing */ | ||
| 79 | |||
| 80 | static __initdata unsigned long ino, major, minor, nlink; | ||
| 81 | static __initdata mode_t mode; | ||
| 82 | static __initdata unsigned long body_len, name_len; | ||
| 83 | static __initdata uid_t uid; | ||
| 84 | static __initdata gid_t gid; | ||
| 85 | static __initdata unsigned rdev; | ||
| 86 | |||
| 87 | static void __init parse_header(char *s) | ||
| 88 | { | ||
| 89 | unsigned long parsed[12]; | ||
| 90 | char buf[9]; | ||
| 91 | int i; | ||
| 92 | |||
| 93 | buf[8] = '\0'; | ||
| 94 | for (i = 0, s += 6; i < 12; i++, s += 8) { | ||
| 95 | memcpy(buf, s, 8); | ||
| 96 | parsed[i] = simple_strtoul(buf, NULL, 16); | ||
| 97 | } | ||
| 98 | ino = parsed[0]; | ||
| 99 | mode = parsed[1]; | ||
| 100 | uid = parsed[2]; | ||
| 101 | gid = parsed[3]; | ||
| 102 | nlink = parsed[4]; | ||
| 103 | body_len = parsed[6]; | ||
| 104 | major = parsed[7]; | ||
| 105 | minor = parsed[8]; | ||
| 106 | rdev = new_encode_dev(MKDEV(parsed[9], parsed[10])); | ||
| 107 | name_len = parsed[11]; | ||
| 108 | } | ||
| 109 | |||
| 110 | /* FSM */ | ||
| 111 | |||
| 112 | static __initdata enum state { | ||
| 113 | Start, | ||
| 114 | Collect, | ||
| 115 | GotHeader, | ||
| 116 | SkipIt, | ||
| 117 | GotName, | ||
| 118 | CopyFile, | ||
| 119 | GotSymlink, | ||
| 120 | Reset | ||
| 121 | } state, next_state; | ||
| 122 | |||
| 123 | static __initdata char *victim; | ||
| 124 | static __initdata unsigned count; | ||
| 125 | static __initdata loff_t this_header, next_header; | ||
| 126 | |||
| 127 | static __initdata int dry_run; | ||
| 128 | |||
| 129 | static inline void eat(unsigned n) | ||
| 130 | { | ||
| 131 | victim += n; | ||
| 132 | this_header += n; | ||
| 133 | count -= n; | ||
| 134 | } | ||
| 135 | |||
| 136 | #define N_ALIGN(len) ((((len) + 1) & ~3) + 2) | ||
| 137 | |||
| 138 | static __initdata char *collected; | ||
| 139 | static __initdata int remains; | ||
| 140 | static __initdata char *collect; | ||
| 141 | |||
| 142 | static void __init read_into(char *buf, unsigned size, enum state next) | ||
| 143 | { | ||
| 144 | if (count >= size) { | ||
| 145 | collected = victim; | ||
| 146 | eat(size); | ||
| 147 | state = next; | ||
| 148 | } else { | ||
| 149 | collect = collected = buf; | ||
| 150 | remains = size; | ||
| 151 | next_state = next; | ||
| 152 | state = Collect; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | static __initdata char *header_buf, *symlink_buf, *name_buf; | ||
| 157 | |||
| 158 | static int __init do_start(void) | ||
| 159 | { | ||
| 160 | read_into(header_buf, 110, GotHeader); | ||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | static int __init do_collect(void) | ||
| 165 | { | ||
| 166 | unsigned n = remains; | ||
| 167 | if (count < n) | ||
| 168 | n = count; | ||
| 169 | memcpy(collect, victim, n); | ||
| 170 | eat(n); | ||
| 171 | collect += n; | ||
| 172 | if ((remains -= n) != 0) | ||
| 173 | return 1; | ||
| 174 | state = next_state; | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | static int __init do_header(void) | ||
| 179 | { | ||
| 180 | if (memcmp(collected, "070701", 6)) { | ||
| 181 | error("no cpio magic"); | ||
| 182 | return 1; | ||
| 183 | } | ||
| 184 | parse_header(collected); | ||
| 185 | next_header = this_header + N_ALIGN(name_len) + body_len; | ||
| 186 | next_header = (next_header + 3) & ~3; | ||
| 187 | if (dry_run) { | ||
| 188 | read_into(name_buf, N_ALIGN(name_len), GotName); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | state = SkipIt; | ||
| 192 | if (name_len <= 0 || name_len > PATH_MAX) | ||
| 193 | return 0; | ||
| 194 | if (S_ISLNK(mode)) { | ||
| 195 | if (body_len > PATH_MAX) | ||
| 196 | return 0; | ||
| 197 | collect = collected = symlink_buf; | ||
| 198 | remains = N_ALIGN(name_len) + body_len; | ||
| 199 | next_state = GotSymlink; | ||
| 200 | state = Collect; | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | if (S_ISREG(mode) || !body_len) | ||
| 204 | read_into(name_buf, N_ALIGN(name_len), GotName); | ||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static int __init do_skip(void) | ||
| 209 | { | ||
| 210 | if (this_header + count < next_header) { | ||
| 211 | eat(count); | ||
| 212 | return 1; | ||
| 213 | } else { | ||
| 214 | eat(next_header - this_header); | ||
| 215 | state = next_state; | ||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | static int __init do_reset(void) | ||
| 221 | { | ||
| 222 | while(count && *victim == '\0') | ||
| 223 | eat(1); | ||
| 224 | if (count && (this_header & 3)) | ||
| 225 | error("broken padding"); | ||
| 226 | return 1; | ||
| 227 | } | ||
| 228 | |||
| 229 | static int __init maybe_link(void) | ||
| 230 | { | ||
| 231 | if (nlink >= 2) { | ||
| 232 | char *old = find_link(major, minor, ino, collected); | ||
| 233 | if (old) | ||
| 234 | return (sys_link(old, collected) < 0) ? -1 : 1; | ||
| 235 | } | ||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | static __initdata int wfd; | ||
| 240 | |||
| 241 | static int __init do_name(void) | ||
| 242 | { | ||
| 243 | state = SkipIt; | ||
| 244 | next_state = Reset; | ||
| 245 | if (strcmp(collected, "TRAILER!!!") == 0) { | ||
| 246 | free_hash(); | ||
| 247 | return 0; | ||
| 248 | } | ||
| 249 | if (dry_run) | ||
| 250 | return 0; | ||
| 251 | if (S_ISREG(mode)) { | ||
| 252 | if (maybe_link() >= 0) { | ||
| 253 | wfd = sys_open(collected, O_WRONLY|O_CREAT, mode); | ||
| 254 | if (wfd >= 0) { | ||
| 255 | sys_fchown(wfd, uid, gid); | ||
| 256 | sys_fchmod(wfd, mode); | ||
| 257 | state = CopyFile; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | } else if (S_ISDIR(mode)) { | ||
| 261 | sys_mkdir(collected, mode); | ||
| 262 | sys_chown(collected, uid, gid); | ||
| 263 | sys_chmod(collected, mode); | ||
| 264 | } else if (S_ISBLK(mode) || S_ISCHR(mode) || | ||
| 265 | S_ISFIFO(mode) || S_ISSOCK(mode)) { | ||
| 266 | if (maybe_link() == 0) { | ||
| 267 | sys_mknod(collected, mode, rdev); | ||
| 268 | sys_chown(collected, uid, gid); | ||
| 269 | sys_chmod(collected, mode); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int __init do_copy(void) | ||
| 276 | { | ||
| 277 | if (count >= body_len) { | ||
| 278 | sys_write(wfd, victim, body_len); | ||
| 279 | sys_close(wfd); | ||
| 280 | eat(body_len); | ||
| 281 | state = SkipIt; | ||
| 282 | return 0; | ||
| 283 | } else { | ||
| 284 | sys_write(wfd, victim, count); | ||
| 285 | body_len -= count; | ||
| 286 | eat(count); | ||
| 287 | return 1; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | |||
| 291 | static int __init do_symlink(void) | ||
| 292 | { | ||
| 293 | collected[N_ALIGN(name_len) + body_len] = '\0'; | ||
| 294 | sys_symlink(collected + N_ALIGN(name_len), collected); | ||
| 295 | sys_lchown(collected, uid, gid); | ||
| 296 | state = SkipIt; | ||
| 297 | next_state = Reset; | ||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | static __initdata int (*actions[])(void) = { | ||
| 302 | [Start] = do_start, | ||
| 303 | [Collect] = do_collect, | ||
| 304 | [GotHeader] = do_header, | ||
| 305 | [SkipIt] = do_skip, | ||
| 306 | [GotName] = do_name, | ||
| 307 | [CopyFile] = do_copy, | ||
| 308 | [GotSymlink] = do_symlink, | ||
| 309 | [Reset] = do_reset, | ||
| 310 | }; | ||
| 311 | |||
| 312 | static int __init write_buffer(char *buf, unsigned len) | ||
| 313 | { | ||
| 314 | count = len; | ||
| 315 | victim = buf; | ||
| 316 | |||
| 317 | while (!actions[state]()) | ||
| 318 | ; | ||
| 319 | return len - count; | ||
| 320 | } | ||
| 321 | |||
| 322 | static void __init flush_buffer(char *buf, unsigned len) | ||
| 323 | { | ||
| 324 | int written; | ||
| 325 | if (message) | ||
| 326 | return; | ||
| 327 | while ((written = write_buffer(buf, len)) < len && !message) { | ||
| 328 | char c = buf[written]; | ||
| 329 | if (c == '0') { | ||
| 330 | buf += written; | ||
| 331 | len -= written; | ||
| 332 | state = Start; | ||
| 333 | } else if (c == 0) { | ||
| 334 | buf += written; | ||
| 335 | len -= written; | ||
| 336 | state = Reset; | ||
| 337 | } else | ||
| 338 | error("junk in compressed archive"); | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | /* | ||
| 343 | * gzip declarations | ||
| 344 | */ | ||
| 345 | |||
| 346 | #define OF(args) args | ||
| 347 | |||
| 348 | #ifndef memzero | ||
| 349 | #define memzero(s, n) memset ((s), 0, (n)) | ||
| 350 | #endif | ||
| 351 | |||
| 352 | typedef unsigned char uch; | ||
| 353 | typedef unsigned short ush; | ||
| 354 | typedef unsigned long ulg; | ||
| 355 | |||
| 356 | #define WSIZE 0x8000 /* window size--must be a power of two, and */ | ||
| 357 | /* at least 32K for zip's deflate method */ | ||
| 358 | |||
| 359 | static uch *inbuf; | ||
| 360 | static uch *window; | ||
| 361 | |||
| 362 | static unsigned insize; /* valid bytes in inbuf */ | ||
| 363 | static unsigned inptr; /* index of next byte to be processed in inbuf */ | ||
| 364 | static unsigned outcnt; /* bytes in output buffer */ | ||
| 365 | static long bytes_out; | ||
| 366 | |||
| 367 | #define get_byte() (inptr < insize ? inbuf[inptr++] : -1) | ||
| 368 | |||
| 369 | /* Diagnostic functions (stubbed out) */ | ||
| 370 | #define Assert(cond,msg) | ||
| 371 | #define Trace(x) | ||
| 372 | #define Tracev(x) | ||
| 373 | #define Tracevv(x) | ||
| 374 | #define Tracec(c,x) | ||
| 375 | #define Tracecv(c,x) | ||
| 376 | |||
| 377 | #define STATIC static | ||
| 378 | #define INIT __init | ||
| 379 | |||
| 380 | static void __init flush_window(void); | ||
| 381 | static void __init error(char *m); | ||
| 382 | static void __init gzip_mark(void **); | ||
| 383 | static void __init gzip_release(void **); | ||
| 384 | |||
| 385 | #include "../lib/inflate.c" | ||
| 386 | |||
| 387 | static void __init gzip_mark(void **ptr) | ||
| 388 | { | ||
| 389 | } | ||
| 390 | |||
| 391 | static void __init gzip_release(void **ptr) | ||
| 392 | { | ||
| 393 | } | ||
| 394 | |||
| 395 | /* =========================================================================== | ||
| 396 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
| 397 | * (Used for the decompressed data only.) | ||
| 398 | */ | ||
| 399 | static void __init flush_window(void) | ||
| 400 | { | ||
| 401 | ulg c = crc; /* temporary variable */ | ||
| 402 | unsigned n; | ||
| 403 | uch *in, ch; | ||
| 404 | |||
| 405 | flush_buffer(window, outcnt); | ||
| 406 | in = window; | ||
| 407 | for (n = 0; n < outcnt; n++) { | ||
| 408 | ch = *in++; | ||
| 409 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
| 410 | } | ||
| 411 | crc = c; | ||
| 412 | bytes_out += (ulg)outcnt; | ||
| 413 | outcnt = 0; | ||
| 414 | } | ||
| 415 | |||
| 416 | static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) | ||
| 417 | { | ||
| 418 | int written; | ||
| 419 | dry_run = check_only; | ||
| 420 | header_buf = malloc(110); | ||
| 421 | symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1); | ||
| 422 | name_buf = malloc(N_ALIGN(PATH_MAX)); | ||
| 423 | window = malloc(WSIZE); | ||
| 424 | if (!window || !header_buf || !symlink_buf || !name_buf) | ||
| 425 | panic("can't allocate buffers"); | ||
| 426 | state = Start; | ||
| 427 | this_header = 0; | ||
| 428 | message = NULL; | ||
| 429 | while (!message && len) { | ||
| 430 | loff_t saved_offset = this_header; | ||
| 431 | if (*buf == '0' && !(this_header & 3)) { | ||
| 432 | state = Start; | ||
| 433 | written = write_buffer(buf, len); | ||
| 434 | buf += written; | ||
| 435 | len -= written; | ||
| 436 | continue; | ||
| 437 | } | ||
| 438 | if (!*buf) { | ||
| 439 | buf++; | ||
| 440 | len--; | ||
| 441 | this_header++; | ||
| 442 | continue; | ||
| 443 | } | ||
| 444 | this_header = 0; | ||
| 445 | insize = len; | ||
| 446 | inbuf = buf; | ||
| 447 | inptr = 0; | ||
| 448 | outcnt = 0; /* bytes in output buffer */ | ||
| 449 | bytes_out = 0; | ||
| 450 | crc = (ulg)0xffffffffL; /* shift register contents */ | ||
| 451 | makecrc(); | ||
| 452 | gunzip(); | ||
| 453 | if (state != Reset) | ||
| 454 | error("junk in gzipped archive"); | ||
| 455 | this_header = saved_offset + inptr; | ||
| 456 | buf += inptr; | ||
| 457 | len -= inptr; | ||
| 458 | } | ||
| 459 | free(window); | ||
| 460 | free(name_buf); | ||
| 461 | free(symlink_buf); | ||
| 462 | free(header_buf); | ||
| 463 | return message; | ||
| 464 | } | ||
| 465 | |||
| 466 | extern char __initramfs_start[], __initramfs_end[]; | ||
| 467 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 468 | #include <linux/initrd.h> | ||
| 469 | #endif | ||
| 470 | |||
| 471 | void __init populate_rootfs(void) | ||
| 472 | { | ||
| 473 | char *err = unpack_to_rootfs(__initramfs_start, | ||
| 474 | __initramfs_end - __initramfs_start, 0); | ||
| 475 | if (err) | ||
| 476 | panic(err); | ||
| 477 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 478 | if (initrd_start) { | ||
| 479 | int fd; | ||
| 480 | printk(KERN_INFO "checking if image is initramfs..."); | ||
| 481 | err = unpack_to_rootfs((char *)initrd_start, | ||
| 482 | initrd_end - initrd_start, 1); | ||
| 483 | if (!err) { | ||
| 484 | printk(" it is\n"); | ||
| 485 | unpack_to_rootfs((char *)initrd_start, | ||
| 486 | initrd_end - initrd_start, 0); | ||
| 487 | free_initrd_mem(initrd_start, initrd_end); | ||
| 488 | return; | ||
| 489 | } | ||
| 490 | printk("it isn't (%s); looks like an initrd\n", err); | ||
| 491 | fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 700); | ||
| 492 | if (fd >= 0) { | ||
| 493 | sys_write(fd, (char *)initrd_start, | ||
| 494 | initrd_end - initrd_start); | ||
| 495 | sys_close(fd); | ||
| 496 | free_initrd_mem(initrd_start, initrd_end); | ||
| 497 | } | ||
| 498 | } | ||
| 499 | #endif | ||
| 500 | } | ||
diff --git a/init/main.c b/init/main.c new file mode 100644 index 000000000000..40bf367ffdf1 --- /dev/null +++ b/init/main.c | |||
| @@ -0,0 +1,713 @@ | |||
| 1 | /* | ||
| 2 | * linux/init/main.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
| 5 | * | ||
| 6 | * GK 2/5/95 - Changed to support mounting root fs via NFS | ||
| 7 | * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 | ||
| 8 | * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 | ||
| 9 | * Simplified starting of init: Michael A. Griffith <grif@acm.org> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #define __KERNEL_SYSCALLS__ | ||
| 13 | |||
| 14 | #include <linux/config.h> | ||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/proc_fs.h> | ||
| 18 | #include <linux/devfs_fs_kernel.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/syscalls.h> | ||
| 21 | #include <linux/string.h> | ||
| 22 | #include <linux/ctype.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/utsname.h> | ||
| 25 | #include <linux/ioport.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/smp_lock.h> | ||
| 28 | #include <linux/initrd.h> | ||
| 29 | #include <linux/hdreg.h> | ||
| 30 | #include <linux/bootmem.h> | ||
| 31 | #include <linux/tty.h> | ||
| 32 | #include <linux/gfp.h> | ||
| 33 | #include <linux/percpu.h> | ||
| 34 | #include <linux/kmod.h> | ||
| 35 | #include <linux/kernel_stat.h> | ||
| 36 | #include <linux/security.h> | ||
| 37 | #include <linux/workqueue.h> | ||
| 38 | #include <linux/profile.h> | ||
| 39 | #include <linux/rcupdate.h> | ||
| 40 | #include <linux/moduleparam.h> | ||
| 41 | #include <linux/kallsyms.h> | ||
| 42 | #include <linux/writeback.h> | ||
| 43 | #include <linux/cpu.h> | ||
| 44 | #include <linux/cpuset.h> | ||
| 45 | #include <linux/efi.h> | ||
| 46 | #include <linux/unistd.h> | ||
| 47 | #include <linux/rmap.h> | ||
| 48 | #include <linux/mempolicy.h> | ||
| 49 | #include <linux/key.h> | ||
| 50 | |||
| 51 | #include <asm/io.h> | ||
| 52 | #include <asm/bugs.h> | ||
| 53 | #include <asm/setup.h> | ||
| 54 | |||
| 55 | /* | ||
| 56 | * This is one of the first .c files built. Error out early | ||
| 57 | * if we have compiler trouble.. | ||
| 58 | */ | ||
| 59 | #if __GNUC__ == 2 && __GNUC_MINOR__ == 96 | ||
| 60 | #ifdef CONFIG_FRAME_POINTER | ||
| 61 | #error This compiler cannot compile correctly with frame pointers enabled | ||
| 62 | #endif | ||
| 63 | #endif | ||
| 64 | |||
| 65 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 66 | #include <asm/smp.h> | ||
| 67 | #endif | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Versions of gcc older than that listed below may actually compile | ||
| 71 | * and link okay, but the end product can have subtle run time bugs. | ||
| 72 | * To avoid associated bogus bug reports, we flatly refuse to compile | ||
| 73 | * with a gcc that is known to be too old from the very beginning. | ||
| 74 | */ | ||
| 75 | #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) | ||
| 76 | #error Sorry, your GCC is too old. It builds incorrect kernels. | ||
| 77 | #endif | ||
| 78 | |||
| 79 | static int init(void *); | ||
| 80 | |||
| 81 | extern void init_IRQ(void); | ||
| 82 | extern void sock_init(void); | ||
| 83 | extern void fork_init(unsigned long); | ||
| 84 | extern void mca_init(void); | ||
| 85 | extern void sbus_init(void); | ||
| 86 | extern void sysctl_init(void); | ||
| 87 | extern void signals_init(void); | ||
| 88 | extern void buffer_init(void); | ||
| 89 | extern void pidhash_init(void); | ||
| 90 | extern void pidmap_init(void); | ||
| 91 | extern void prio_tree_init(void); | ||
| 92 | extern void radix_tree_init(void); | ||
| 93 | extern void free_initmem(void); | ||
| 94 | extern void populate_rootfs(void); | ||
| 95 | extern void driver_init(void); | ||
| 96 | extern void prepare_namespace(void); | ||
| 97 | #ifdef CONFIG_ACPI | ||
| 98 | extern void acpi_early_init(void); | ||
| 99 | #else | ||
| 100 | static inline void acpi_early_init(void) { } | ||
| 101 | #endif | ||
| 102 | |||
| 103 | #ifdef CONFIG_TC | ||
| 104 | extern void tc_init(void); | ||
| 105 | #endif | ||
| 106 | |||
| 107 | enum system_states system_state; | ||
| 108 | EXPORT_SYMBOL(system_state); | ||
| 109 | |||
| 110 | /* | ||
| 111 | * Boot command-line arguments | ||
| 112 | */ | ||
| 113 | #define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT | ||
| 114 | #define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT | ||
| 115 | |||
| 116 | extern void time_init(void); | ||
| 117 | /* Default late time init is NULL. archs can override this later. */ | ||
| 118 | void (*late_time_init)(void); | ||
| 119 | extern void softirq_init(void); | ||
| 120 | |||
| 121 | /* Untouched command line (eg. for /proc) saved by arch-specific code. */ | ||
| 122 | char saved_command_line[COMMAND_LINE_SIZE]; | ||
| 123 | |||
| 124 | static char *execute_command; | ||
| 125 | |||
| 126 | /* Setup configured maximum number of CPUs to activate */ | ||
| 127 | static unsigned int max_cpus = NR_CPUS; | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Setup routine for controlling SMP activation | ||
| 131 | * | ||
| 132 | * Command-line option of "nosmp" or "maxcpus=0" will disable SMP | ||
| 133 | * activation entirely (the MPS table probe still happens, though). | ||
| 134 | * | ||
| 135 | * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer | ||
| 136 | * greater than 0, limits the maximum number of CPUs activated in | ||
| 137 | * SMP mode to <NUM>. | ||
| 138 | */ | ||
| 139 | static int __init nosmp(char *str) | ||
| 140 | { | ||
| 141 | max_cpus = 0; | ||
| 142 | return 1; | ||
| 143 | } | ||
| 144 | |||
| 145 | __setup("nosmp", nosmp); | ||
| 146 | |||
| 147 | static int __init maxcpus(char *str) | ||
| 148 | { | ||
| 149 | get_option(&str, &max_cpus); | ||
| 150 | return 1; | ||
| 151 | } | ||
| 152 | |||
| 153 | __setup("maxcpus=", maxcpus); | ||
| 154 | |||
| 155 | static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; | ||
| 156 | char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; | ||
| 157 | static const char *panic_later, *panic_param; | ||
| 158 | |||
| 159 | extern struct obs_kernel_param __setup_start[], __setup_end[]; | ||
| 160 | |||
| 161 | static int __init obsolete_checksetup(char *line) | ||
| 162 | { | ||
| 163 | struct obs_kernel_param *p; | ||
| 164 | |||
| 165 | p = __setup_start; | ||
| 166 | do { | ||
| 167 | int n = strlen(p->str); | ||
| 168 | if (!strncmp(line, p->str, n)) { | ||
| 169 | if (p->early) { | ||
| 170 | /* Already done in parse_early_param? (Needs | ||
| 171 | * exact match on param part) */ | ||
| 172 | if (line[n] == '\0' || line[n] == '=') | ||
| 173 | return 1; | ||
| 174 | } else if (!p->setup_func) { | ||
| 175 | printk(KERN_WARNING "Parameter %s is obsolete," | ||
| 176 | " ignored\n", p->str); | ||
| 177 | return 1; | ||
| 178 | } else if (p->setup_func(line + n)) | ||
| 179 | return 1; | ||
| 180 | } | ||
| 181 | p++; | ||
| 182 | } while (p < __setup_end); | ||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | /* | ||
| 187 | * This should be approx 2 Bo*oMips to start (note initial shift), and will | ||
| 188 | * still work even if initially too large, it will just take slightly longer | ||
| 189 | */ | ||
| 190 | unsigned long loops_per_jiffy = (1<<12); | ||
| 191 | |||
| 192 | EXPORT_SYMBOL(loops_per_jiffy); | ||
| 193 | |||
| 194 | static int __init debug_kernel(char *str) | ||
| 195 | { | ||
| 196 | if (*str) | ||
| 197 | return 0; | ||
| 198 | console_loglevel = 10; | ||
| 199 | return 1; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int __init quiet_kernel(char *str) | ||
| 203 | { | ||
| 204 | if (*str) | ||
| 205 | return 0; | ||
| 206 | console_loglevel = 4; | ||
| 207 | return 1; | ||
| 208 | } | ||
| 209 | |||
| 210 | __setup("debug", debug_kernel); | ||
| 211 | __setup("quiet", quiet_kernel); | ||
| 212 | |||
| 213 | static int __init loglevel(char *str) | ||
| 214 | { | ||
| 215 | get_option(&str, &console_loglevel); | ||
| 216 | return 1; | ||
| 217 | } | ||
| 218 | |||
| 219 | __setup("loglevel=", loglevel); | ||
| 220 | |||
| 221 | /* | ||
| 222 | * Unknown boot options get handed to init, unless they look like | ||
| 223 | * failed parameters | ||
| 224 | */ | ||
| 225 | static int __init unknown_bootoption(char *param, char *val) | ||
| 226 | { | ||
| 227 | /* Change NUL term back to "=", to make "param" the whole string. */ | ||
| 228 | if (val) { | ||
| 229 | /* param=val or param="val"? */ | ||
| 230 | if (val == param+strlen(param)+1) | ||
| 231 | val[-1] = '='; | ||
| 232 | else if (val == param+strlen(param)+2) { | ||
| 233 | val[-2] = '='; | ||
| 234 | memmove(val-1, val, strlen(val)+1); | ||
| 235 | val--; | ||
| 236 | } else | ||
| 237 | BUG(); | ||
| 238 | } | ||
| 239 | |||
| 240 | /* Handle obsolete-style parameters */ | ||
| 241 | if (obsolete_checksetup(param)) | ||
| 242 | return 0; | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Preemptive maintenance for "why didn't my mispelled command | ||
| 246 | * line work?" | ||
| 247 | */ | ||
| 248 | if (strchr(param, '.') && (!val || strchr(param, '.') < val)) { | ||
| 249 | printk(KERN_ERR "Unknown boot option `%s': ignoring\n", param); | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | if (panic_later) | ||
| 254 | return 0; | ||
| 255 | |||
| 256 | if (val) { | ||
| 257 | /* Environment option */ | ||
| 258 | unsigned int i; | ||
| 259 | for (i = 0; envp_init[i]; i++) { | ||
| 260 | if (i == MAX_INIT_ENVS) { | ||
| 261 | panic_later = "Too many boot env vars at `%s'"; | ||
| 262 | panic_param = param; | ||
| 263 | } | ||
| 264 | if (!strncmp(param, envp_init[i], val - param)) | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | envp_init[i] = param; | ||
| 268 | } else { | ||
| 269 | /* Command line option */ | ||
| 270 | unsigned int i; | ||
| 271 | for (i = 0; argv_init[i]; i++) { | ||
| 272 | if (i == MAX_INIT_ARGS) { | ||
| 273 | panic_later = "Too many boot init vars at `%s'"; | ||
| 274 | panic_param = param; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | argv_init[i] = param; | ||
| 278 | } | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | static int __init init_setup(char *str) | ||
| 283 | { | ||
| 284 | unsigned int i; | ||
| 285 | |||
| 286 | execute_command = str; | ||
| 287 | /* | ||
| 288 | * In case LILO is going to boot us with default command line, | ||
| 289 | * it prepends "auto" before the whole cmdline which makes | ||
| 290 | * the shell think it should execute a script with such name. | ||
| 291 | * So we ignore all arguments entered _before_ init=... [MJ] | ||
| 292 | */ | ||
| 293 | for (i = 1; i < MAX_INIT_ARGS; i++) | ||
| 294 | argv_init[i] = NULL; | ||
| 295 | return 1; | ||
| 296 | } | ||
| 297 | __setup("init=", init_setup); | ||
| 298 | |||
| 299 | extern void setup_arch(char **); | ||
| 300 | |||
| 301 | #ifndef CONFIG_SMP | ||
| 302 | |||
| 303 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 304 | static void __init smp_init(void) | ||
| 305 | { | ||
| 306 | APIC_init_uniprocessor(); | ||
| 307 | } | ||
| 308 | #else | ||
| 309 | #define smp_init() do { } while (0) | ||
| 310 | #endif | ||
| 311 | |||
| 312 | static inline void setup_per_cpu_areas(void) { } | ||
| 313 | static inline void smp_prepare_cpus(unsigned int maxcpus) { } | ||
| 314 | |||
| 315 | #else | ||
| 316 | |||
| 317 | #ifdef __GENERIC_PER_CPU | ||
| 318 | unsigned long __per_cpu_offset[NR_CPUS]; | ||
| 319 | |||
| 320 | EXPORT_SYMBOL(__per_cpu_offset); | ||
| 321 | |||
| 322 | static void __init setup_per_cpu_areas(void) | ||
| 323 | { | ||
| 324 | unsigned long size, i; | ||
| 325 | char *ptr; | ||
| 326 | /* Created by linker magic */ | ||
| 327 | extern char __per_cpu_start[], __per_cpu_end[]; | ||
| 328 | |||
| 329 | /* Copy section for each CPU (we discard the original) */ | ||
| 330 | size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); | ||
| 331 | #ifdef CONFIG_MODULES | ||
| 332 | if (size < PERCPU_ENOUGH_ROOM) | ||
| 333 | size = PERCPU_ENOUGH_ROOM; | ||
| 334 | #endif | ||
| 335 | |||
| 336 | ptr = alloc_bootmem(size * NR_CPUS); | ||
| 337 | |||
| 338 | for (i = 0; i < NR_CPUS; i++, ptr += size) { | ||
| 339 | __per_cpu_offset[i] = ptr - __per_cpu_start; | ||
| 340 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | #endif /* !__GENERIC_PER_CPU */ | ||
| 344 | |||
| 345 | /* Called by boot processor to activate the rest. */ | ||
| 346 | static void __init smp_init(void) | ||
| 347 | { | ||
| 348 | unsigned int i; | ||
| 349 | |||
| 350 | /* FIXME: This should be done in userspace --RR */ | ||
| 351 | for_each_present_cpu(i) { | ||
| 352 | if (num_online_cpus() >= max_cpus) | ||
| 353 | break; | ||
| 354 | if (!cpu_online(i)) | ||
| 355 | cpu_up(i); | ||
| 356 | } | ||
| 357 | |||
| 358 | /* Any cleanup work */ | ||
| 359 | printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus()); | ||
| 360 | smp_cpus_done(max_cpus); | ||
| 361 | #if 0 | ||
| 362 | /* Get other processors into their bootup holding patterns. */ | ||
| 363 | |||
| 364 | smp_commence(); | ||
| 365 | #endif | ||
| 366 | } | ||
| 367 | |||
| 368 | #endif | ||
| 369 | |||
| 370 | /* | ||
| 371 | * We need to finalize in a non-__init function or else race conditions | ||
| 372 | * between the root thread and the init thread may cause start_kernel to | ||
| 373 | * be reaped by free_initmem before the root thread has proceeded to | ||
| 374 | * cpu_idle. | ||
| 375 | * | ||
| 376 | * gcc-3.4 accidentally inlines this function, so use noinline. | ||
| 377 | */ | ||
| 378 | |||
| 379 | static void noinline rest_init(void) | ||
| 380 | __releases(kernel_lock) | ||
| 381 | { | ||
| 382 | kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND); | ||
| 383 | numa_default_policy(); | ||
| 384 | unlock_kernel(); | ||
| 385 | preempt_enable_no_resched(); | ||
| 386 | cpu_idle(); | ||
| 387 | } | ||
| 388 | |||
| 389 | /* Check for early params. */ | ||
| 390 | static int __init do_early_param(char *param, char *val) | ||
| 391 | { | ||
| 392 | struct obs_kernel_param *p; | ||
| 393 | |||
| 394 | for (p = __setup_start; p < __setup_end; p++) { | ||
| 395 | if (p->early && strcmp(param, p->str) == 0) { | ||
| 396 | if (p->setup_func(val) != 0) | ||
| 397 | printk(KERN_WARNING | ||
| 398 | "Malformed early option '%s'\n", param); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | /* We accept everything at this stage. */ | ||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | /* Arch code calls this early on, or if not, just before other parsing. */ | ||
| 406 | void __init parse_early_param(void) | ||
| 407 | { | ||
| 408 | static __initdata int done = 0; | ||
| 409 | static __initdata char tmp_cmdline[COMMAND_LINE_SIZE]; | ||
| 410 | |||
| 411 | if (done) | ||
| 412 | return; | ||
| 413 | |||
| 414 | /* All fall through to do_early_param. */ | ||
| 415 | strlcpy(tmp_cmdline, saved_command_line, COMMAND_LINE_SIZE); | ||
| 416 | parse_args("early options", tmp_cmdline, NULL, 0, do_early_param); | ||
| 417 | done = 1; | ||
| 418 | } | ||
| 419 | |||
| 420 | /* | ||
| 421 | * Activate the first processor. | ||
| 422 | */ | ||
| 423 | |||
| 424 | asmlinkage void __init start_kernel(void) | ||
| 425 | { | ||
| 426 | char * command_line; | ||
| 427 | extern struct kernel_param __start___param[], __stop___param[]; | ||
| 428 | /* | ||
| 429 | * Interrupts are still disabled. Do necessary setups, then | ||
| 430 | * enable them | ||
| 431 | */ | ||
| 432 | lock_kernel(); | ||
| 433 | page_address_init(); | ||
| 434 | printk(KERN_NOTICE); | ||
| 435 | printk(linux_banner); | ||
| 436 | setup_arch(&command_line); | ||
| 437 | setup_per_cpu_areas(); | ||
| 438 | |||
| 439 | /* | ||
| 440 | * Mark the boot cpu "online" so that it can call console drivers in | ||
| 441 | * printk() and can access its per-cpu storage. | ||
| 442 | */ | ||
| 443 | smp_prepare_boot_cpu(); | ||
| 444 | |||
| 445 | /* | ||
| 446 | * Set up the scheduler prior starting any interrupts (such as the | ||
| 447 | * timer interrupt). Full topology setup happens at smp_init() | ||
| 448 | * time - but meanwhile we still have a functioning scheduler. | ||
| 449 | */ | ||
| 450 | sched_init(); | ||
| 451 | /* | ||
| 452 | * Disable preemption - early bootup scheduling is extremely | ||
| 453 | * fragile until we cpu_idle() for the first time. | ||
| 454 | */ | ||
| 455 | preempt_disable(); | ||
| 456 | build_all_zonelists(); | ||
| 457 | page_alloc_init(); | ||
| 458 | printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line); | ||
| 459 | parse_early_param(); | ||
| 460 | parse_args("Booting kernel", command_line, __start___param, | ||
| 461 | __stop___param - __start___param, | ||
| 462 | &unknown_bootoption); | ||
| 463 | sort_main_extable(); | ||
| 464 | trap_init(); | ||
| 465 | rcu_init(); | ||
| 466 | init_IRQ(); | ||
| 467 | pidhash_init(); | ||
| 468 | init_timers(); | ||
| 469 | softirq_init(); | ||
| 470 | time_init(); | ||
| 471 | |||
| 472 | /* | ||
| 473 | * HACK ALERT! This is early. We're enabling the console before | ||
| 474 | * we've done PCI setups etc, and console_init() must be aware of | ||
| 475 | * this. But we do want output early, in case something goes wrong. | ||
| 476 | */ | ||
| 477 | console_init(); | ||
| 478 | if (panic_later) | ||
| 479 | panic(panic_later, panic_param); | ||
| 480 | profile_init(); | ||
| 481 | local_irq_enable(); | ||
| 482 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 483 | if (initrd_start && !initrd_below_start_ok && | ||
| 484 | initrd_start < min_low_pfn << PAGE_SHIFT) { | ||
| 485 | printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " | ||
| 486 | "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT); | ||
| 487 | initrd_start = 0; | ||
| 488 | } | ||
| 489 | #endif | ||
| 490 | vfs_caches_init_early(); | ||
| 491 | mem_init(); | ||
| 492 | kmem_cache_init(); | ||
| 493 | numa_policy_init(); | ||
| 494 | if (late_time_init) | ||
| 495 | late_time_init(); | ||
| 496 | calibrate_delay(); | ||
| 497 | pidmap_init(); | ||
| 498 | pgtable_cache_init(); | ||
| 499 | prio_tree_init(); | ||
| 500 | anon_vma_init(); | ||
| 501 | #ifdef CONFIG_X86 | ||
| 502 | if (efi_enabled) | ||
| 503 | efi_enter_virtual_mode(); | ||
| 504 | #endif | ||
| 505 | fork_init(num_physpages); | ||
| 506 | proc_caches_init(); | ||
| 507 | buffer_init(); | ||
| 508 | unnamed_dev_init(); | ||
| 509 | key_init(); | ||
| 510 | security_init(); | ||
| 511 | vfs_caches_init(num_physpages); | ||
| 512 | radix_tree_init(); | ||
| 513 | signals_init(); | ||
| 514 | /* rootfs populating might need page-writeback */ | ||
| 515 | page_writeback_init(); | ||
| 516 | #ifdef CONFIG_PROC_FS | ||
| 517 | proc_root_init(); | ||
| 518 | #endif | ||
| 519 | cpuset_init(); | ||
| 520 | |||
| 521 | check_bugs(); | ||
| 522 | |||
| 523 | acpi_early_init(); /* before LAPIC and SMP init */ | ||
| 524 | |||
| 525 | /* Do the rest non-__init'ed, we're now alive */ | ||
| 526 | rest_init(); | ||
| 527 | } | ||
| 528 | |||
| 529 | static int __initdata initcall_debug; | ||
| 530 | |||
| 531 | static int __init initcall_debug_setup(char *str) | ||
| 532 | { | ||
| 533 | initcall_debug = 1; | ||
| 534 | return 1; | ||
| 535 | } | ||
| 536 | __setup("initcall_debug", initcall_debug_setup); | ||
| 537 | |||
| 538 | struct task_struct *child_reaper = &init_task; | ||
| 539 | |||
| 540 | extern initcall_t __initcall_start[], __initcall_end[]; | ||
| 541 | |||
| 542 | static void __init do_initcalls(void) | ||
| 543 | { | ||
| 544 | initcall_t *call; | ||
| 545 | int count = preempt_count(); | ||
| 546 | |||
| 547 | for (call = __initcall_start; call < __initcall_end; call++) { | ||
| 548 | char *msg; | ||
| 549 | |||
| 550 | if (initcall_debug) { | ||
| 551 | printk(KERN_DEBUG "Calling initcall 0x%p", *call); | ||
| 552 | print_fn_descriptor_symbol(": %s()", (unsigned long) *call); | ||
| 553 | printk("\n"); | ||
| 554 | } | ||
| 555 | |||
| 556 | (*call)(); | ||
| 557 | |||
| 558 | msg = NULL; | ||
| 559 | if (preempt_count() != count) { | ||
| 560 | msg = "preemption imbalance"; | ||
| 561 | preempt_count() = count; | ||
| 562 | } | ||
| 563 | if (irqs_disabled()) { | ||
| 564 | msg = "disabled interrupts"; | ||
| 565 | local_irq_enable(); | ||
| 566 | } | ||
| 567 | if (msg) { | ||
| 568 | printk(KERN_WARNING "error in initcall at 0x%p: " | ||
| 569 | "returned with %s\n", *call, msg); | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | /* Make sure there is no pending stuff from the initcall sequence */ | ||
| 574 | flush_scheduled_work(); | ||
| 575 | } | ||
| 576 | |||
| 577 | /* | ||
| 578 | * Ok, the machine is now initialized. None of the devices | ||
| 579 | * have been touched yet, but the CPU subsystem is up and | ||
| 580 | * running, and memory and process management works. | ||
| 581 | * | ||
| 582 | * Now we can finally start doing some real work.. | ||
| 583 | */ | ||
| 584 | static void __init do_basic_setup(void) | ||
| 585 | { | ||
| 586 | /* drivers will send hotplug events */ | ||
| 587 | init_workqueues(); | ||
| 588 | usermodehelper_init(); | ||
| 589 | driver_init(); | ||
| 590 | |||
| 591 | #ifdef CONFIG_SYSCTL | ||
| 592 | sysctl_init(); | ||
| 593 | #endif | ||
| 594 | |||
| 595 | /* Networking initialization needs a process context */ | ||
| 596 | sock_init(); | ||
| 597 | |||
| 598 | do_initcalls(); | ||
| 599 | } | ||
| 600 | |||
| 601 | static void do_pre_smp_initcalls(void) | ||
| 602 | { | ||
| 603 | extern int spawn_ksoftirqd(void); | ||
| 604 | #ifdef CONFIG_SMP | ||
| 605 | extern int migration_init(void); | ||
| 606 | |||
| 607 | migration_init(); | ||
| 608 | #endif | ||
| 609 | spawn_ksoftirqd(); | ||
| 610 | } | ||
| 611 | |||
| 612 | static void run_init_process(char *init_filename) | ||
| 613 | { | ||
| 614 | argv_init[0] = init_filename; | ||
| 615 | execve(init_filename, argv_init, envp_init); | ||
| 616 | } | ||
| 617 | |||
| 618 | static inline void fixup_cpu_present_map(void) | ||
| 619 | { | ||
| 620 | #ifdef CONFIG_SMP | ||
| 621 | int i; | ||
| 622 | |||
| 623 | /* | ||
| 624 | * If arch is not hotplug ready and did not populate | ||
| 625 | * cpu_present_map, just make cpu_present_map same as cpu_possible_map | ||
| 626 | * for other cpu bringup code to function as normal. e.g smp_init() etc. | ||
| 627 | */ | ||
| 628 | if (cpus_empty(cpu_present_map)) { | ||
| 629 | for_each_cpu(i) { | ||
| 630 | cpu_set(i, cpu_present_map); | ||
| 631 | } | ||
| 632 | } | ||
| 633 | #endif | ||
| 634 | } | ||
| 635 | |||
| 636 | static int init(void * unused) | ||
| 637 | { | ||
| 638 | lock_kernel(); | ||
| 639 | /* | ||
| 640 | * init can run on any cpu. | ||
| 641 | */ | ||
| 642 | set_cpus_allowed(current, CPU_MASK_ALL); | ||
| 643 | /* | ||
| 644 | * Tell the world that we're going to be the grim | ||
| 645 | * reaper of innocent orphaned children. | ||
| 646 | * | ||
| 647 | * We don't want people to have to make incorrect | ||
| 648 | * assumptions about where in the task array this | ||
| 649 | * can be found. | ||
| 650 | */ | ||
| 651 | child_reaper = current; | ||
| 652 | |||
| 653 | /* Sets up cpus_possible() */ | ||
| 654 | smp_prepare_cpus(max_cpus); | ||
| 655 | |||
| 656 | do_pre_smp_initcalls(); | ||
| 657 | |||
| 658 | fixup_cpu_present_map(); | ||
| 659 | smp_init(); | ||
| 660 | sched_init_smp(); | ||
| 661 | |||
| 662 | cpuset_init_smp(); | ||
| 663 | |||
| 664 | /* | ||
| 665 | * Do this before initcalls, because some drivers want to access | ||
| 666 | * firmware files. | ||
| 667 | */ | ||
| 668 | populate_rootfs(); | ||
| 669 | |||
| 670 | do_basic_setup(); | ||
| 671 | |||
| 672 | /* | ||
| 673 | * check if there is an early userspace init. If yes, let it do all | ||
| 674 | * the work | ||
| 675 | */ | ||
| 676 | if (sys_access((const char __user *) "/init", 0) == 0) | ||
| 677 | execute_command = "/init"; | ||
| 678 | else | ||
| 679 | prepare_namespace(); | ||
| 680 | |||
| 681 | /* | ||
| 682 | * Ok, we have completed the initial bootup, and | ||
| 683 | * we're essentially up and running. Get rid of the | ||
| 684 | * initmem segments and start the user-mode stuff.. | ||
| 685 | */ | ||
| 686 | free_initmem(); | ||
| 687 | unlock_kernel(); | ||
| 688 | system_state = SYSTEM_RUNNING; | ||
| 689 | numa_default_policy(); | ||
| 690 | |||
| 691 | if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) | ||
| 692 | printk(KERN_WARNING "Warning: unable to open an initial console.\n"); | ||
| 693 | |||
| 694 | (void) sys_dup(0); | ||
| 695 | (void) sys_dup(0); | ||
| 696 | |||
| 697 | /* | ||
| 698 | * We try each of these until one succeeds. | ||
| 699 | * | ||
| 700 | * The Bourne shell can be used instead of init if we are | ||
| 701 | * trying to recover a really broken machine. | ||
| 702 | */ | ||
| 703 | |||
| 704 | if (execute_command) | ||
| 705 | run_init_process(execute_command); | ||
| 706 | |||
| 707 | run_init_process("/sbin/init"); | ||
| 708 | run_init_process("/etc/init"); | ||
| 709 | run_init_process("/bin/init"); | ||
| 710 | run_init_process("/bin/sh"); | ||
| 711 | |||
| 712 | panic("No init found. Try passing init= option to kernel."); | ||
| 713 | } | ||
diff --git a/init/version.c b/init/version.c new file mode 100644 index 000000000000..3ddc3ceec2fe --- /dev/null +++ b/init/version.c | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* | ||
| 2 | * linux/init/version.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1992 Theodore Ts'o | ||
| 5 | * | ||
| 6 | * May be freely distributed as part of Linux. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/compile.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/uts.h> | ||
| 12 | #include <linux/utsname.h> | ||
| 13 | #include <linux/version.h> | ||
| 14 | |||
| 15 | #define version(a) Version_ ## a | ||
| 16 | #define version_string(a) version(a) | ||
| 17 | |||
| 18 | int version_string(LINUX_VERSION_CODE); | ||
| 19 | |||
| 20 | struct new_utsname system_utsname = { | ||
| 21 | .sysname = UTS_SYSNAME, | ||
| 22 | .nodename = UTS_NODENAME, | ||
| 23 | .release = UTS_RELEASE, | ||
| 24 | .version = UTS_VERSION, | ||
| 25 | .machine = UTS_MACHINE, | ||
| 26 | .domainname = UTS_DOMAINNAME, | ||
| 27 | }; | ||
| 28 | |||
| 29 | EXPORT_SYMBOL(system_utsname); | ||
| 30 | |||
| 31 | const char linux_banner[] = | ||
| 32 | "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" | ||
| 33 | LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; | ||
