diff options
426 files changed, 10191 insertions, 6521 deletions
diff --git a/Documentation/input/ff.txt b/Documentation/input/ff.txt index c7e10eaff203..c53b1c11aa40 100644 --- a/Documentation/input/ff.txt +++ b/Documentation/input/ff.txt | |||
| @@ -1,67 +1,37 @@ | |||
| 1 | Force feedback for Linux. | 1 | Force feedback for Linux. |
| 2 | By Johann Deneux <deneux@ifrance.com> on 2001/04/22. | 2 | By Johann Deneux <deneux@ifrance.com> on 2001/04/22. |
| 3 | Updated by Anssi Hannula <anssi.hannula@gmail.com> on 2006/04/09. | ||
| 3 | You may redistribute this file. Please remember to include shape.fig and | 4 | You may redistribute this file. Please remember to include shape.fig and |
| 4 | interactive.fig as well. | 5 | interactive.fig as well. |
| 5 | ---------------------------------------------------------------------------- | 6 | ---------------------------------------------------------------------------- |
| 6 | 7 | ||
| 7 | 0. Introduction | 8 | 1. Introduction |
| 8 | ~~~~~~~~~~~~~~~ | 9 | ~~~~~~~~~~~~~~~ |
| 9 | This document describes how to use force feedback devices under Linux. The | 10 | This document describes how to use force feedback devices under Linux. The |
| 10 | goal is not to support these devices as if they were simple input-only devices | 11 | goal is not to support these devices as if they were simple input-only devices |
| 11 | (as it is already the case), but to really enable the rendering of force | 12 | (as it is already the case), but to really enable the rendering of force |
| 12 | effects. | 13 | effects. |
| 13 | At the moment, only I-Force devices are supported, and not officially. That | 14 | This document only describes the force feedback part of the Linux input |
| 14 | means I had to find out how the protocol works on my own. Of course, the | 15 | interface. Please read joystick.txt and input.txt before reading further this |
| 15 | information I managed to grasp is far from being complete, and I can not | 16 | document. |
| 16 | guarranty that this driver will work for you. | ||
| 17 | This document only describes the force feedback part of the driver for I-Force | ||
| 18 | devices. Please read joystick.txt before reading further this document. | ||
| 19 | 17 | ||
| 20 | 2. Instructions to the user | 18 | 2. Instructions to the user |
| 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 19 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 22 | Here are instructions on how to compile and use the driver. In fact, this | 20 | To enable force feedback, you have to: |
| 23 | driver is the normal iforce, input and evdev drivers written by Vojtech | 21 | |
| 24 | Pavlik, plus additions to support force feedback. | 22 | 1. have your kernel configured with evdev and a driver that supports your |
| 23 | device. | ||
| 24 | 2. make sure evdev module is loaded and /dev/input/event* device files are | ||
| 25 | created. | ||
| 25 | 26 | ||
| 26 | Before you start, let me WARN you that some devices shake violently during the | 27 | Before you start, let me WARN you that some devices shake violently during the |
| 27 | initialisation phase. This happens for example with my "AVB Top Shot Pegasus". | 28 | initialisation phase. This happens for example with my "AVB Top Shot Pegasus". |
| 28 | To stop this annoying behaviour, move you joystick to its limits. Anyway, you | 29 | To stop this annoying behaviour, move you joystick to its limits. Anyway, you |
| 29 | should keep a hand on your device, in order to avoid it to brake down if | 30 | should keep a hand on your device, in order to avoid it to break down if |
| 30 | something goes wrong. | 31 | something goes wrong. |
| 31 | 32 | ||
| 32 | At the kernel's compilation: | 33 | If you have a serial iforce device, you need to start inputattach. See |
| 33 | - Enable IForce/Serial | 34 | joystick.txt for details. |
| 34 | - Enable Event interface | ||
| 35 | |||
| 36 | Compile the modules, install them. | ||
| 37 | |||
| 38 | You also need inputattach. | ||
| 39 | |||
| 40 | You then need to insert the modules into the following order: | ||
| 41 | % modprobe joydev | ||
| 42 | % modprobe serport # Only for serial | ||
| 43 | % modprobe iforce | ||
| 44 | % modprobe evdev | ||
| 45 | % ./inputattach -ifor $2 & # Only for serial | ||
| 46 | If you are using USB, you don't need the inputattach step. | ||
| 47 | |||
| 48 | Please check that you have all the /dev/input entries needed: | ||
| 49 | cd /dev | ||
| 50 | rm js* | ||
| 51 | mkdir input | ||
| 52 | mknod input/js0 c 13 0 | ||
| 53 | mknod input/js1 c 13 1 | ||
| 54 | mknod input/js2 c 13 2 | ||
| 55 | mknod input/js3 c 13 3 | ||
| 56 | ln -s input/js0 js0 | ||
| 57 | ln -s input/js1 js1 | ||
| 58 | ln -s input/js2 js2 | ||
| 59 | ln -s input/js3 js3 | ||
| 60 | |||
| 61 | mknod input/event0 c 13 64 | ||
| 62 | mknod input/event1 c 13 65 | ||
| 63 | mknod input/event2 c 13 66 | ||
| 64 | mknod input/event3 c 13 67 | ||
| 65 | 35 | ||
| 66 | 2.1 Does it work ? | 36 | 2.1 Does it work ? |
| 67 | ~~~~~~~~~~~~~~~~~~ | 37 | ~~~~~~~~~~~~~~~~~~ |
| @@ -70,9 +40,9 @@ There is an utility called fftest that will allow you to test the driver. | |||
| 70 | 40 | ||
| 71 | 3. Instructions to the developper | 41 | 3. Instructions to the developper |
| 72 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 73 | All interactions are done using the event API. That is, you can use ioctl() | 43 | All interactions are done using the event API. That is, you can use ioctl() |
| 74 | and write() on /dev/input/eventXX. | 44 | and write() on /dev/input/eventXX. |
| 75 | This information is subject to change. | 45 | This information is subject to change. |
| 76 | 46 | ||
| 77 | 3.1 Querying device capabilities | 47 | 3.1 Querying device capabilities |
| 78 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 48 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int request, unsigned long *features); | |||
| 86 | 56 | ||
| 87 | Returns the features supported by the device. features is a bitfield with the | 57 | Returns the features supported by the device. features is a bitfield with the |
| 88 | following bits: | 58 | following bits: |
| 89 | - FF_X has an X axis (usually joysticks) | ||
| 90 | - FF_Y has an Y axis (usually joysticks) | ||
| 91 | - FF_WHEEL has a wheel (usually sterring wheels) | ||
| 92 | - FF_CONSTANT can render constant force effects | 59 | - FF_CONSTANT can render constant force effects |
| 93 | - FF_PERIODIC can render periodic effects (sine, triangle, square...) | 60 | - FF_PERIODIC can render periodic effects with the following waveforms: |
| 61 | - FF_SQUARE square waveform | ||
| 62 | - FF_TRIANGLE triangle waveform | ||
| 63 | - FF_SINE sine waveform | ||
| 64 | - FF_SAW_UP sawtooth up waveform | ||
| 65 | - FF_SAW_DOWN sawtooth down waveform | ||
| 66 | - FF_CUSTOM custom waveform | ||
| 94 | - FF_RAMP can render ramp effects | 67 | - FF_RAMP can render ramp effects |
| 95 | - FF_SPRING can simulate the presence of a spring | 68 | - FF_SPRING can simulate the presence of a spring |
| 96 | - FF_FRICTION can simulate friction | 69 | - FF_FRICTION can simulate friction |
| 97 | - FF_DAMPER can simulate damper effects | 70 | - FF_DAMPER can simulate damper effects |
| 98 | - FF_RUMBLE rumble effects (normally the only effect supported by rumble | 71 | - FF_RUMBLE rumble effects |
| 99 | pads) | ||
| 100 | - FF_INERTIA can simulate inertia | 72 | - FF_INERTIA can simulate inertia |
| 73 | - FF_GAIN gain is adjustable | ||
| 74 | - FF_AUTOCENTER autocenter is adjustable | ||
| 75 | |||
| 76 | Note: In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All | ||
| 77 | devices that support FF_RUMBLE support FF_PERIODIC (square, triangle, | ||
| 78 | sine) and the other way around. | ||
| 79 | |||
| 80 | Note: The exact syntax FF_CUSTOM is undefined for the time being as no driver | ||
| 81 | supports it yet. | ||
| 101 | 82 | ||
| 102 | 83 | ||
| 103 | int ioctl(int fd, EVIOCGEFFECTS, int *n); | 84 | int ioctl(int fd, EVIOCGEFFECTS, int *n); |
| @@ -108,7 +89,7 @@ Returns the number of effects the device can keep in its memory. | |||
| 108 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 89 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 109 | #include <linux/input.h> | 90 | #include <linux/input.h> |
| 110 | #include <sys/ioctl.h> | 91 | #include <sys/ioctl.h> |
| 111 | 92 | ||
| 112 | int ioctl(int file_descriptor, int request, struct ff_effect *effect); | 93 | int ioctl(int file_descriptor, int request, struct ff_effect *effect); |
| 113 | 94 | ||
| 114 | "request" must be EVIOCSFF. | 95 | "request" must be EVIOCSFF. |
| @@ -120,6 +101,9 @@ to the unique id assigned by the driver. This data is required for performing | |||
| 120 | some operations (removing an effect, controlling the playback). | 101 | some operations (removing an effect, controlling the playback). |
| 121 | This if field must be set to -1 by the user in order to tell the driver to | 102 | This if field must be set to -1 by the user in order to tell the driver to |
| 122 | allocate a new effect. | 103 | allocate a new effect. |
| 104 | |||
| 105 | Effects are file descriptor specific. | ||
| 106 | |||
| 123 | See <linux/input.h> for a description of the ff_effect struct. You should also | 107 | See <linux/input.h> for a description of the ff_effect struct. You should also |
| 124 | find help in a few sketches, contained in files shape.fig and interactive.fig. | 108 | find help in a few sketches, contained in files shape.fig and interactive.fig. |
| 125 | You need xfig to visualize these files. | 109 | You need xfig to visualize these files. |
| @@ -128,8 +112,8 @@ You need xfig to visualize these files. | |||
| 128 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 112 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 129 | int ioctl(int fd, EVIOCRMFF, effect.id); | 113 | int ioctl(int fd, EVIOCRMFF, effect.id); |
| 130 | 114 | ||
| 131 | This makes room for new effects in the device's memory. Please note this won't | 115 | This makes room for new effects in the device's memory. Note that this also |
| 132 | stop the effect if it was playing. | 116 | stops the effect if it was playing. |
| 133 | 117 | ||
| 134 | 3.4 Controlling the playback of effects | 118 | 3.4 Controlling the playback of effects |
| 135 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 119 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -149,22 +133,21 @@ Control of playing is done with write(). Below is an example: | |||
| 149 | play.type = EV_FF; | 133 | play.type = EV_FF; |
| 150 | play.code = effect.id; | 134 | play.code = effect.id; |
| 151 | play.value = 3; | 135 | play.value = 3; |
| 152 | 136 | ||
| 153 | write(fd, (const void*) &play, sizeof(play)); | 137 | write(fd, (const void*) &play, sizeof(play)); |
| 154 | ... | 138 | ... |
| 155 | /* Stop an effect */ | 139 | /* Stop an effect */ |
| 156 | stop.type = EV_FF; | 140 | stop.type = EV_FF; |
| 157 | stop.code = effect.id; | 141 | stop.code = effect.id; |
| 158 | stop.value = 0; | 142 | stop.value = 0; |
| 159 | 143 | ||
| 160 | write(fd, (const void*) &play, sizeof(stop)); | 144 | write(fd, (const void*) &play, sizeof(stop)); |
| 161 | 145 | ||
| 162 | 3.5 Setting the gain | 146 | 3.5 Setting the gain |
| 163 | ~~~~~~~~~~~~~~~~~~~~ | 147 | ~~~~~~~~~~~~~~~~~~~~ |
| 164 | Not all devices have the same strength. Therefore, users should set a gain | 148 | Not all devices have the same strength. Therefore, users should set a gain |
| 165 | factor depending on how strong they want effects to be. This setting is | 149 | factor depending on how strong they want effects to be. This setting is |
| 166 | persistent across access to the driver, so you should not care about it if | 150 | persistent across access to the driver. |
| 167 | you are writing games, as another utility probably already set this for you. | ||
| 168 | 151 | ||
| 169 | /* Set the gain of the device | 152 | /* Set the gain of the device |
| 170 | int gain; /* between 0 and 100 */ | 153 | int gain; /* between 0 and 100 */ |
| @@ -204,11 +187,14 @@ type of device, not all parameters can be dynamically updated. For example, | |||
| 204 | the direction of an effect cannot be updated with iforce devices. In this | 187 | the direction of an effect cannot be updated with iforce devices. In this |
| 205 | case, the driver stops the effect, up-load it, and restart it. | 188 | case, the driver stops the effect, up-load it, and restart it. |
| 206 | 189 | ||
| 190 | Therefore it is recommended to dynamically change direction while the effect | ||
| 191 | is playing only when it is ok to restart the effect with a replay count of 1. | ||
| 207 | 192 | ||
| 208 | 3.8 Information about the status of effects | 193 | 3.8 Information about the status of effects |
| 209 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 194 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 210 | Every time the status of an effect is changed, an event is sent. The values | 195 | Every time the status of an effect is changed, an event is sent. The values |
| 211 | and meanings of the fields of the event are as follows: | 196 | and meanings of the fields of the event are as follows: |
| 197 | |||
| 212 | struct input_event { | 198 | struct input_event { |
| 213 | /* When the status of the effect changed */ | 199 | /* When the status of the effect changed */ |
| 214 | struct timeval time; | 200 | struct timeval time; |
| @@ -225,3 +211,9 @@ struct input_event { | |||
| 225 | 211 | ||
| 226 | FF_STATUS_STOPPED The effect stopped playing | 212 | FF_STATUS_STOPPED The effect stopped playing |
| 227 | FF_STATUS_PLAYING The effect started to play | 213 | FF_STATUS_PLAYING The effect started to play |
| 214 | |||
| 215 | NOTE: Status feedback is only supported by iforce driver. If you have | ||
| 216 | a really good reason to use this, please contact | ||
| 217 | linux-joystick@atrey.karlin.mff.cuni.cz or anssi.hannula@gmail.com | ||
| 218 | so that support for it can be added to the rest of the drivers. | ||
| 219 | |||
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 2c3b1eae4280..ba26201d5023 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt | |||
| @@ -151,9 +151,9 @@ So that you can load and unload Kprobes-based instrumentation modules, | |||
| 151 | make sure "Loadable module support" (CONFIG_MODULES) and "Module | 151 | make sure "Loadable module support" (CONFIG_MODULES) and "Module |
| 152 | unloading" (CONFIG_MODULE_UNLOAD) are set to "y". | 152 | unloading" (CONFIG_MODULE_UNLOAD) are set to "y". |
| 153 | 153 | ||
| 154 | You may also want to ensure that CONFIG_KALLSYMS and perhaps even | 154 | Also make sure that CONFIG_KALLSYMS and perhaps even CONFIG_KALLSYMS_ALL |
| 155 | CONFIG_KALLSYMS_ALL are set to "y", since kallsyms_lookup_name() | 155 | are set to "y", since kallsyms_lookup_name() is used by the in-kernel |
| 156 | is a handy, version-independent way to find a function's address. | 156 | kprobe address resolution code. |
| 157 | 157 | ||
| 158 | If you need to insert a probe in the middle of a function, you may find | 158 | If you need to insert a probe in the middle of a function, you may find |
| 159 | it useful to "Compile the kernel with debug info" (CONFIG_DEBUG_INFO), | 159 | it useful to "Compile the kernel with debug info" (CONFIG_DEBUG_INFO), |
| @@ -179,6 +179,27 @@ occurs during execution of kp->pre_handler or kp->post_handler, | |||
| 179 | or during single-stepping of the probed instruction, Kprobes calls | 179 | or during single-stepping of the probed instruction, Kprobes calls |
| 180 | kp->fault_handler. Any or all handlers can be NULL. | 180 | kp->fault_handler. Any or all handlers can be NULL. |
| 181 | 181 | ||
| 182 | NOTE: | ||
| 183 | 1. With the introduction of the "symbol_name" field to struct kprobe, | ||
| 184 | the probepoint address resolution will now be taken care of by the kernel. | ||
| 185 | The following will now work: | ||
| 186 | |||
| 187 | kp.symbol_name = "symbol_name"; | ||
| 188 | |||
| 189 | (64-bit powerpc intricacies such as function descriptors are handled | ||
| 190 | transparently) | ||
| 191 | |||
| 192 | 2. Use the "offset" field of struct kprobe if the offset into the symbol | ||
| 193 | to install a probepoint is known. This field is used to calculate the | ||
| 194 | probepoint. | ||
| 195 | |||
| 196 | 3. Specify either the kprobe "symbol_name" OR the "addr". If both are | ||
| 197 | specified, kprobe registration will fail with -EINVAL. | ||
| 198 | |||
| 199 | 4. With CISC architectures (such as i386 and x86_64), the kprobes code | ||
| 200 | does not validate if the kprobe.addr is at an instruction boundary. | ||
| 201 | Use "offset" with caution. | ||
| 202 | |||
| 182 | register_kprobe() returns 0 on success, or a negative errno otherwise. | 203 | register_kprobe() returns 0 on success, or a negative errno otherwise. |
| 183 | 204 | ||
| 184 | User's pre-handler (kp->pre_handler): | 205 | User's pre-handler (kp->pre_handler): |
| @@ -225,6 +246,12 @@ control to Kprobes.) If the probed function is declared asmlinkage, | |||
| 225 | fastcall, or anything else that affects how args are passed, the | 246 | fastcall, or anything else that affects how args are passed, the |
| 226 | handler's declaration must match. | 247 | handler's declaration must match. |
| 227 | 248 | ||
| 249 | NOTE: A macro JPROBE_ENTRY is provided to handle architecture-specific | ||
| 250 | aliasing of jp->entry. In the interest of portability, it is advised | ||
| 251 | to use: | ||
| 252 | |||
| 253 | jp->entry = JPROBE_ENTRY(handler); | ||
| 254 | |||
| 228 | register_jprobe() returns 0 on success, or a negative errno otherwise. | 255 | register_jprobe() returns 0 on success, or a negative errno otherwise. |
| 229 | 256 | ||
| 230 | 4.3 register_kretprobe | 257 | 4.3 register_kretprobe |
| @@ -251,6 +278,11 @@ of interest: | |||
| 251 | - ret_addr: the return address | 278 | - ret_addr: the return address |
| 252 | - rp: points to the corresponding kretprobe object | 279 | - rp: points to the corresponding kretprobe object |
| 253 | - task: points to the corresponding task struct | 280 | - task: points to the corresponding task struct |
| 281 | |||
| 282 | The regs_return_value(regs) macro provides a simple abstraction to | ||
| 283 | extract the return value from the appropriate register as defined by | ||
| 284 | the architecture's ABI. | ||
| 285 | |||
| 254 | The handler's return value is currently ignored. | 286 | The handler's return value is currently ignored. |
| 255 | 287 | ||
| 256 | 4.4 unregister_*probe | 288 | 4.4 unregister_*probe |
| @@ -369,7 +401,6 @@ stack trace and selected i386 registers when do_fork() is called. | |||
| 369 | #include <linux/kernel.h> | 401 | #include <linux/kernel.h> |
| 370 | #include <linux/module.h> | 402 | #include <linux/module.h> |
| 371 | #include <linux/kprobes.h> | 403 | #include <linux/kprobes.h> |
| 372 | #include <linux/kallsyms.h> | ||
| 373 | #include <linux/sched.h> | 404 | #include <linux/sched.h> |
| 374 | 405 | ||
| 375 | /*For each probe you need to allocate a kprobe structure*/ | 406 | /*For each probe you need to allocate a kprobe structure*/ |
| @@ -403,18 +434,14 @@ int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) | |||
| 403 | return 0; | 434 | return 0; |
| 404 | } | 435 | } |
| 405 | 436 | ||
| 406 | int init_module(void) | 437 | static int __init kprobe_init(void) |
| 407 | { | 438 | { |
| 408 | int ret; | 439 | int ret; |
| 409 | kp.pre_handler = handler_pre; | 440 | kp.pre_handler = handler_pre; |
| 410 | kp.post_handler = handler_post; | 441 | kp.post_handler = handler_post; |
| 411 | kp.fault_handler = handler_fault; | 442 | kp.fault_handler = handler_fault; |
| 412 | kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("do_fork"); | 443 | kp.symbol_name = "do_fork"; |
| 413 | /* register the kprobe now */ | 444 | |
| 414 | if (!kp.addr) { | ||
| 415 | printk("Couldn't find %s to plant kprobe\n", "do_fork"); | ||
| 416 | return -1; | ||
| 417 | } | ||
| 418 | if ((ret = register_kprobe(&kp) < 0)) { | 445 | if ((ret = register_kprobe(&kp) < 0)) { |
| 419 | printk("register_kprobe failed, returned %d\n", ret); | 446 | printk("register_kprobe failed, returned %d\n", ret); |
| 420 | return -1; | 447 | return -1; |
| @@ -423,12 +450,14 @@ int init_module(void) | |||
| 423 | return 0; | 450 | return 0; |
| 424 | } | 451 | } |
| 425 | 452 | ||
| 426 | void cleanup_module(void) | 453 | static void __exit kprobe_exit(void) |
| 427 | { | 454 | { |
| 428 | unregister_kprobe(&kp); | 455 | unregister_kprobe(&kp); |
| 429 | printk("kprobe unregistered\n"); | 456 | printk("kprobe unregistered\n"); |
| 430 | } | 457 | } |
| 431 | 458 | ||
| 459 | module_init(kprobe_init) | ||
| 460 | module_exit(kprobe_exit) | ||
| 432 | MODULE_LICENSE("GPL"); | 461 | MODULE_LICENSE("GPL"); |
| 433 | ----- cut here ----- | 462 | ----- cut here ----- |
| 434 | 463 | ||
| @@ -463,7 +492,6 @@ the arguments of do_fork(). | |||
| 463 | #include <linux/fs.h> | 492 | #include <linux/fs.h> |
| 464 | #include <linux/uio.h> | 493 | #include <linux/uio.h> |
| 465 | #include <linux/kprobes.h> | 494 | #include <linux/kprobes.h> |
| 466 | #include <linux/kallsyms.h> | ||
| 467 | 495 | ||
| 468 | /* | 496 | /* |
| 469 | * Jumper probe for do_fork. | 497 | * Jumper probe for do_fork. |
| @@ -485,17 +513,13 @@ long jdo_fork(unsigned long clone_flags, unsigned long stack_start, | |||
| 485 | } | 513 | } |
| 486 | 514 | ||
| 487 | static struct jprobe my_jprobe = { | 515 | static struct jprobe my_jprobe = { |
| 488 | .entry = (kprobe_opcode_t *) jdo_fork | 516 | .entry = JPROBE_ENTRY(jdo_fork) |
| 489 | }; | 517 | }; |
| 490 | 518 | ||
| 491 | int init_module(void) | 519 | static int __init jprobe_init(void) |
| 492 | { | 520 | { |
| 493 | int ret; | 521 | int ret; |
| 494 | my_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("do_fork"); | 522 | my_jprobe.kp.symbol_name = "do_fork"; |
| 495 | if (!my_jprobe.kp.addr) { | ||
| 496 | printk("Couldn't find %s to plant jprobe\n", "do_fork"); | ||
| 497 | return -1; | ||
| 498 | } | ||
| 499 | 523 | ||
| 500 | if ((ret = register_jprobe(&my_jprobe)) <0) { | 524 | if ((ret = register_jprobe(&my_jprobe)) <0) { |
| 501 | printk("register_jprobe failed, returned %d\n", ret); | 525 | printk("register_jprobe failed, returned %d\n", ret); |
| @@ -506,12 +530,14 @@ int init_module(void) | |||
| 506 | return 0; | 530 | return 0; |
| 507 | } | 531 | } |
| 508 | 532 | ||
| 509 | void cleanup_module(void) | 533 | static void __exit jprobe_exit(void) |
| 510 | { | 534 | { |
| 511 | unregister_jprobe(&my_jprobe); | 535 | unregister_jprobe(&my_jprobe); |
| 512 | printk("jprobe unregistered\n"); | 536 | printk("jprobe unregistered\n"); |
| 513 | } | 537 | } |
| 514 | 538 | ||
| 539 | module_init(jprobe_init) | ||
| 540 | module_exit(jprobe_exit) | ||
| 515 | MODULE_LICENSE("GPL"); | 541 | MODULE_LICENSE("GPL"); |
| 516 | ----- cut here ----- | 542 | ----- cut here ----- |
| 517 | 543 | ||
| @@ -530,16 +556,13 @@ report failed calls to sys_open(). | |||
| 530 | #include <linux/kernel.h> | 556 | #include <linux/kernel.h> |
| 531 | #include <linux/module.h> | 557 | #include <linux/module.h> |
| 532 | #include <linux/kprobes.h> | 558 | #include <linux/kprobes.h> |
| 533 | #include <linux/kallsyms.h> | ||
| 534 | 559 | ||
| 535 | static const char *probed_func = "sys_open"; | 560 | static const char *probed_func = "sys_open"; |
| 536 | 561 | ||
| 537 | /* Return-probe handler: If the probed function fails, log the return value. */ | 562 | /* Return-probe handler: If the probed function fails, log the return value. */ |
| 538 | static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) | 563 | static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) |
| 539 | { | 564 | { |
| 540 | // Substitute the appropriate register name for your architecture -- | 565 | int retval = regs_return_value(regs); |
| 541 | // e.g., regs->rax for x86_64, regs->gpr[3] for ppc64. | ||
| 542 | int retval = (int) regs->eax; | ||
| 543 | if (retval < 0) { | 566 | if (retval < 0) { |
| 544 | printk("%s returns %d\n", probed_func, retval); | 567 | printk("%s returns %d\n", probed_func, retval); |
| 545 | } | 568 | } |
| @@ -552,15 +575,11 @@ static struct kretprobe my_kretprobe = { | |||
| 552 | .maxactive = 20 | 575 | .maxactive = 20 |
| 553 | }; | 576 | }; |
| 554 | 577 | ||
| 555 | int init_module(void) | 578 | static int __init kretprobe_init(void) |
| 556 | { | 579 | { |
| 557 | int ret; | 580 | int ret; |
| 558 | my_kretprobe.kp.addr = | 581 | my_kretprobe.kp.symbol_name = (char *)probed_func; |
| 559 | (kprobe_opcode_t *) kallsyms_lookup_name(probed_func); | 582 | |
| 560 | if (!my_kretprobe.kp.addr) { | ||
| 561 | printk("Couldn't find %s to plant return probe\n", probed_func); | ||
| 562 | return -1; | ||
| 563 | } | ||
| 564 | if ((ret = register_kretprobe(&my_kretprobe)) < 0) { | 583 | if ((ret = register_kretprobe(&my_kretprobe)) < 0) { |
| 565 | printk("register_kretprobe failed, returned %d\n", ret); | 584 | printk("register_kretprobe failed, returned %d\n", ret); |
| 566 | return -1; | 585 | return -1; |
| @@ -569,7 +588,7 @@ int init_module(void) | |||
| 569 | return 0; | 588 | return 0; |
| 570 | } | 589 | } |
| 571 | 590 | ||
| 572 | void cleanup_module(void) | 591 | static void __exit kretprobe_exit(void) |
| 573 | { | 592 | { |
| 574 | unregister_kretprobe(&my_kretprobe); | 593 | unregister_kretprobe(&my_kretprobe); |
| 575 | printk("kretprobe unregistered\n"); | 594 | printk("kretprobe unregistered\n"); |
| @@ -578,6 +597,8 @@ void cleanup_module(void) | |||
| 578 | my_kretprobe.nmissed, probed_func); | 597 | my_kretprobe.nmissed, probed_func); |
| 579 | } | 598 | } |
| 580 | 599 | ||
| 600 | module_init(kretprobe_init) | ||
| 601 | module_exit(kretprobe_exit) | ||
| 581 | MODULE_LICENSE("GPL"); | 602 | MODULE_LICENSE("GPL"); |
| 582 | ----- cut here ----- | 603 | ----- cut here ----- |
| 583 | 604 | ||
| @@ -590,3 +611,5 @@ messages.) | |||
| 590 | For additional information on Kprobes, refer to the following URLs: | 611 | For additional information on Kprobes, refer to the following URLs: |
| 591 | http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe | 612 | http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe |
| 592 | http://www.redhat.com/magazine/005mar05/features/kprobes/ | 613 | http://www.redhat.com/magazine/005mar05/features/kprobes/ |
| 614 | http://www-users.cs.umn.edu/~boutcher/kprobes/ | ||
| 615 | http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115) | ||
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index f042cc42b00f..dbe327d32b6f 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c | |||
| @@ -36,7 +36,6 @@ | |||
| 36 | #include <asm/cacheflush.h> | 36 | #include <asm/cacheflush.h> |
| 37 | #include <asm/vga.h> | 37 | #include <asm/vga.h> |
| 38 | 38 | ||
| 39 | #define __KERNEL_SYSCALLS__ | ||
| 40 | #include <asm/unistd.h> | 39 | #include <asm/unistd.h> |
| 41 | 40 | ||
| 42 | extern struct hwrpb_struct *hwrpb; | 41 | extern struct hwrpb_struct *hwrpb; |
| @@ -116,7 +115,7 @@ EXPORT_SYMBOL(sys_dup); | |||
| 116 | EXPORT_SYMBOL(sys_exit); | 115 | EXPORT_SYMBOL(sys_exit); |
| 117 | EXPORT_SYMBOL(sys_write); | 116 | EXPORT_SYMBOL(sys_write); |
| 118 | EXPORT_SYMBOL(sys_lseek); | 117 | EXPORT_SYMBOL(sys_lseek); |
| 119 | EXPORT_SYMBOL(execve); | 118 | EXPORT_SYMBOL(kernel_execve); |
| 120 | EXPORT_SYMBOL(sys_setsid); | 119 | EXPORT_SYMBOL(sys_setsid); |
| 121 | EXPORT_SYMBOL(sys_wait4); | 120 | EXPORT_SYMBOL(sys_wait4); |
| 122 | 121 | ||
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 01ecd09d4a64..c95e95e1ab04 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S | |||
| @@ -655,12 +655,12 @@ kernel_thread: | |||
| 655 | .end kernel_thread | 655 | .end kernel_thread |
| 656 | 656 | ||
| 657 | /* | 657 | /* |
| 658 | * execve(path, argv, envp) | 658 | * kernel_execve(path, argv, envp) |
| 659 | */ | 659 | */ |
| 660 | .align 4 | 660 | .align 4 |
| 661 | .globl execve | 661 | .globl kernel_execve |
| 662 | .ent execve | 662 | .ent kernel_execve |
| 663 | execve: | 663 | kernel_execve: |
| 664 | /* We can be called from a module. */ | 664 | /* We can be called from a module. */ |
| 665 | ldgp $gp, 0($27) | 665 | ldgp $gp, 0($27) |
| 666 | lda $sp, -(32+SIZEOF_PT_REGS+8)($sp) | 666 | lda $sp, -(32+SIZEOF_PT_REGS+8)($sp) |
| @@ -704,7 +704,7 @@ execve: | |||
| 704 | 704 | ||
| 705 | 1: lda $sp, 32+SIZEOF_PT_REGS+8($sp) | 705 | 1: lda $sp, 32+SIZEOF_PT_REGS+8($sp) |
| 706 | ret | 706 | ret |
| 707 | .end execve | 707 | .end kernel_execve |
| 708 | 708 | ||
| 709 | 709 | ||
| 710 | /* | 710 | /* |
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 73c7622b5297..8a31fc1bfb15 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c | |||
| @@ -402,15 +402,15 @@ osf_utsname(char __user *name) | |||
| 402 | 402 | ||
| 403 | down_read(&uts_sem); | 403 | down_read(&uts_sem); |
| 404 | error = -EFAULT; | 404 | error = -EFAULT; |
| 405 | if (copy_to_user(name + 0, system_utsname.sysname, 32)) | 405 | if (copy_to_user(name + 0, utsname()->sysname, 32)) |
| 406 | goto out; | 406 | goto out; |
| 407 | if (copy_to_user(name + 32, system_utsname.nodename, 32)) | 407 | if (copy_to_user(name + 32, utsname()->nodename, 32)) |
| 408 | goto out; | 408 | goto out; |
| 409 | if (copy_to_user(name + 64, system_utsname.release, 32)) | 409 | if (copy_to_user(name + 64, utsname()->release, 32)) |
| 410 | goto out; | 410 | goto out; |
| 411 | if (copy_to_user(name + 96, system_utsname.version, 32)) | 411 | if (copy_to_user(name + 96, utsname()->version, 32)) |
| 412 | goto out; | 412 | goto out; |
| 413 | if (copy_to_user(name + 128, system_utsname.machine, 32)) | 413 | if (copy_to_user(name + 128, utsname()->machine, 32)) |
| 414 | goto out; | 414 | goto out; |
| 415 | 415 | ||
| 416 | error = 0; | 416 | error = 0; |
| @@ -449,8 +449,8 @@ osf_getdomainname(char __user *name, int namelen) | |||
| 449 | 449 | ||
| 450 | down_read(&uts_sem); | 450 | down_read(&uts_sem); |
| 451 | for (i = 0; i < len; ++i) { | 451 | for (i = 0; i < len; ++i) { |
| 452 | __put_user(system_utsname.domainname[i], name + i); | 452 | __put_user(utsname()->domainname[i], name + i); |
| 453 | if (system_utsname.domainname[i] == '\0') | 453 | if (utsname()->domainname[i] == '\0') |
| 454 | break; | 454 | break; |
| 455 | } | 455 | } |
| 456 | up_read(&uts_sem); | 456 | up_read(&uts_sem); |
| @@ -607,12 +607,12 @@ osf_sigstack(struct sigstack __user *uss, struct sigstack __user *uoss) | |||
| 607 | asmlinkage long | 607 | asmlinkage long |
| 608 | osf_sysinfo(int command, char __user *buf, long count) | 608 | osf_sysinfo(int command, char __user *buf, long count) |
| 609 | { | 609 | { |
| 610 | static char * sysinfo_table[] = { | 610 | char *sysinfo_table[] = { |
| 611 | system_utsname.sysname, | 611 | utsname()->sysname, |
| 612 | system_utsname.nodename, | 612 | utsname()->nodename, |
| 613 | system_utsname.release, | 613 | utsname()->release, |
| 614 | system_utsname.version, | 614 | utsname()->version, |
| 615 | system_utsname.machine, | 615 | utsname()->machine, |
| 616 | "alpha", /* instruction set architecture */ | 616 | "alpha", /* instruction set architecture */ |
| 617 | "dummy", /* hardware serial number */ | 617 | "dummy", /* hardware serial number */ |
| 618 | "dummy", /* hardware manufacturer */ | 618 | "dummy", /* hardware manufacturer */ |
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 9d7dff27f815..756923203860 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c | |||
| @@ -229,7 +229,7 @@ srmcons_close(struct tty_struct *tty, struct file *filp) | |||
| 229 | 229 | ||
| 230 | static struct tty_driver *srmcons_driver; | 230 | static struct tty_driver *srmcons_driver; |
| 231 | 231 | ||
| 232 | static struct tty_operations srmcons_ops = { | 232 | static const struct tty_operations srmcons_ops = { |
| 233 | .open = srmcons_open, | 233 | .open = srmcons_open, |
| 234 | .close = srmcons_close, | 234 | .close = srmcons_close, |
| 235 | .write = srmcons_write, | 235 | .write = srmcons_write, |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 0a722e77c143..6bbd93dd186a 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
| @@ -348,7 +348,7 @@ static void __init setup_processor(void) | |||
| 348 | cpu_name, processor_id, (int)processor_id & 15, | 348 | cpu_name, processor_id, (int)processor_id & 15, |
| 349 | proc_arch[cpu_architecture()], cr_alignment); | 349 | proc_arch[cpu_architecture()], cr_alignment); |
| 350 | 350 | ||
| 351 | sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); | 351 | sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS); |
| 352 | sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); | 352 | sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); |
| 353 | elf_hwcap = list->elf_hwcap; | 353 | elf_hwcap = list->elf_hwcap; |
| 354 | #ifndef CONFIG_ARM_THUMB | 354 | #ifndef CONFIG_ARM_THUMB |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 68e9634d260a..421329f5e18e 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
| @@ -36,7 +36,9 @@ | |||
| 36 | * The online bitmask indicates that the CPU is up and running. | 36 | * The online bitmask indicates that the CPU is up and running. |
| 37 | */ | 37 | */ |
| 38 | cpumask_t cpu_possible_map; | 38 | cpumask_t cpu_possible_map; |
| 39 | EXPORT_SYMBOL(cpu_possible_map); | ||
| 39 | cpumask_t cpu_online_map; | 40 | cpumask_t cpu_online_map; |
| 41 | EXPORT_SYMBOL(cpu_online_map); | ||
| 40 | 42 | ||
| 41 | /* | 43 | /* |
| 42 | * as from 2.5, kernels no longer have an init_tasks structure | 44 | * as from 2.5, kernels no longer have an init_tasks structure |
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 8170af471439..00c18d35913c 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c | |||
| @@ -279,7 +279,7 @@ out: | |||
| 279 | return error; | 279 | return error; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | long execve(const char *filename, char **argv, char **envp) | 282 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) |
| 283 | { | 283 | { |
| 284 | struct pt_regs regs; | 284 | struct pt_regs regs; |
| 285 | int ret; | 285 | int ret; |
| @@ -317,7 +317,7 @@ long execve(const char *filename, char **argv, char **envp) | |||
| 317 | out: | 317 | out: |
| 318 | return ret; | 318 | return ret; |
| 319 | } | 319 | } |
| 320 | EXPORT_SYMBOL(execve); | 320 | EXPORT_SYMBOL(kernel_execve); |
| 321 | 321 | ||
| 322 | /* | 322 | /* |
| 323 | * Since loff_t is a 64 bit type we avoid a lot of ABI hastle | 323 | * Since loff_t is a 64 bit type we avoid a lot of ABI hastle |
diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c index e7eb070f794f..466ddb54b44f 100644 --- a/arch/arm26/kernel/setup.c +++ b/arch/arm26/kernel/setup.c | |||
| @@ -143,7 +143,7 @@ static void __init setup_processor(void) | |||
| 143 | 143 | ||
| 144 | dump_cpu_info(); | 144 | dump_cpu_info(); |
| 145 | 145 | ||
| 146 | sprintf(system_utsname.machine, "%s", list->arch_name); | 146 | sprintf(init_utsname()->machine, "%s", list->arch_name); |
| 147 | sprintf(elf_platform, "%s", list->elf_name); | 147 | sprintf(elf_platform, "%s", list->elf_name); |
| 148 | elf_hwcap = list->elf_hwcap; | 148 | elf_hwcap = list->elf_hwcap; |
| 149 | 149 | ||
diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c index 85457897b8a9..dc05aba58baf 100644 --- a/arch/arm26/kernel/sys_arm.c +++ b/arch/arm26/kernel/sys_arm.c | |||
| @@ -283,7 +283,7 @@ out: | |||
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | /* FIXME - see if this is correct for arm26 */ | 285 | /* FIXME - see if this is correct for arm26 */ |
| 286 | long execve(const char *filename, char **argv, char **envp) | 286 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) |
| 287 | { | 287 | { |
| 288 | struct pt_regs regs; | 288 | struct pt_regs regs; |
| 289 | int ret; | 289 | int ret; |
| @@ -320,4 +320,4 @@ long execve(const char *filename, char **argv, char **envp) | |||
| 320 | return ret; | 320 | return ret; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | EXPORT_SYMBOL(execve); | 323 | EXPORT_SYMBOL(kernel_execve); |
diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c index 6ec5693da448..8deb6003ee62 100644 --- a/arch/avr32/kernel/sys_avr32.c +++ b/arch/avr32/kernel/sys_avr32.c | |||
| @@ -49,3 +49,17 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | |||
| 49 | fput(file); | 49 | fput(file); |
| 50 | return error; | 50 | return error; |
| 51 | } | 51 | } |
| 52 | |||
| 53 | int kernel_execve(const char *file, char **argv, char **envp) | ||
| 54 | { | ||
| 55 | register long scno asm("r8") = __NR_execve; | ||
| 56 | register long sc1 asm("r12") = (long)file; | ||
| 57 | register long sc2 asm("r11") = (long)argv; | ||
| 58 | register long sc3 asm("r10") = (long)envp; | ||
| 59 | |||
| 60 | asm volatile("scall" | ||
| 61 | : "=r"(sc1) | ||
| 62 | : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3) | ||
| 63 | : "cc", "memory"); | ||
| 64 | return sc1; | ||
| 65 | } | ||
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 464ecaec3bc0..2d0023f2d49b 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c | |||
| @@ -28,6 +28,7 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED}; | |||
| 28 | 28 | ||
| 29 | /* CPU masks */ | 29 | /* CPU masks */ |
| 30 | cpumask_t cpu_online_map = CPU_MASK_NONE; | 30 | cpumask_t cpu_online_map = CPU_MASK_NONE; |
| 31 | EXPORT_SYMBOL(cpu_online_map); | ||
| 31 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; | 32 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; |
| 32 | EXPORT_SYMBOL(phys_cpu_present_map); | 33 | EXPORT_SYMBOL(phys_cpu_present_map); |
| 33 | 34 | ||
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 7af3d5d43e43..ca8b45a0fe2e 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c | |||
| @@ -160,7 +160,7 @@ setup_arch(char **cmdline_p) | |||
| 160 | show_etrax_copyright(); | 160 | show_etrax_copyright(); |
| 161 | 161 | ||
| 162 | /* Setup utsname */ | 162 | /* Setup utsname */ |
| 163 | strcpy(system_utsname.machine, cris_machine_name); | 163 | strcpy(init_utsname()->machine, cris_machine_name); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | static void *c_start(struct seq_file *m, loff_t *pos) | 166 | static void *c_start(struct seq_file *m, loff_t *pos) |
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile index 32db3499c461..e8f73ed28b52 100644 --- a/arch/frv/kernel/Makefile +++ b/arch/frv/kernel/Makefile | |||
| @@ -8,7 +8,7 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o | |||
| 8 | extra-y:= head.o init_task.o vmlinux.lds | 8 | extra-y:= head.o init_task.o vmlinux.lds |
| 9 | 9 | ||
| 10 | obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ | 10 | obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \ |
| 11 | process.o traps.o ptrace.o signal.o dma.o \ | 11 | kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \ |
| 12 | sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \ | 12 | sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \ |
| 13 | debug-stub.o irq.o sleep.o uaccess.o | 13 | debug-stub.o irq.o sleep.o uaccess.o |
| 14 | 14 | ||
diff --git a/arch/frv/kernel/kernel_execve.S b/arch/frv/kernel/kernel_execve.S new file mode 100644 index 000000000000..9b074a16a052 --- /dev/null +++ b/arch/frv/kernel/kernel_execve.S | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* in-kernel program execution | ||
| 2 | * | ||
| 3 | * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/linkage.h> | ||
| 13 | #include <asm/unistd.h> | ||
| 14 | |||
| 15 | ############################################################################### | ||
| 16 | # | ||
| 17 | # Do a system call from kernel instead of calling sys_execve so we end up with | ||
| 18 | # proper pt_regs. | ||
| 19 | # | ||
| 20 | # int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 21 | # | ||
| 22 | # On entry: GR8/GR9/GR10: arguments to function | ||
| 23 | # On return: GR8: syscall return. | ||
| 24 | # | ||
| 25 | ############################################################################### | ||
| 26 | .globl kernel_execve | ||
| 27 | .type kernel_execve,@function | ||
| 28 | kernel_execve: | ||
| 29 | setlos __NR_execve,gr7 | ||
| 30 | tira gr0,#0 | ||
| 31 | bralr | ||
| 32 | |||
| 33 | .size kernel_execve,.-kernel_execve | ||
diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index 0f61b7ad69ab..302a2dfe634a 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <asm/cachectl.h> | 25 | #include <asm/cachectl.h> |
| 26 | #include <asm/traps.h> | 26 | #include <asm/traps.h> |
| 27 | #include <asm/ipc.h> | 27 | #include <asm/ipc.h> |
| 28 | #include <asm/unistd.h> | ||
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| 30 | * sys_pipe() is the normal C calling standard for creating | 31 | * sys_pipe() is the normal C calling standard for creating |
| @@ -280,3 +281,26 @@ asmlinkage void syscall_print(void *dummy,...) | |||
| 280 | ((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0); | 281 | ((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0); |
| 281 | } | 282 | } |
| 282 | #endif | 283 | #endif |
| 284 | |||
| 285 | /* | ||
| 286 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 287 | * end up with proper pt_regs. | ||
| 288 | */ | ||
| 289 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 290 | { | ||
| 291 | register long res __asm__("er0"); | ||
| 292 | register const char * _a __asm__("er1") = filename; | ||
| 293 | register void *_b __asm__("er2") = argv; | ||
| 294 | register void *_c __asm__("er3") = envp; | ||
| 295 | __asm__ __volatile__ ("mov.l %1,er0\n\t" | ||
| 296 | "trapa #0\n\t" | ||
| 297 | : "=r" (res) | ||
| 298 | : "g" (__NR_execve), | ||
| 299 | "g" (_a), | ||
| 300 | "g" (_b), | ||
| 301 | "g" (_c) | ||
| 302 | : "cc", "memory"); | ||
| 303 | return res; | ||
| 304 | } | ||
| 305 | |||
| 306 | |||
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 3fd2f256f2be..af219e51734f 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
| @@ -1142,7 +1142,7 @@ source "arch/i386/oprofile/Kconfig" | |||
| 1142 | 1142 | ||
| 1143 | config KPROBES | 1143 | config KPROBES |
| 1144 | bool "Kprobes (EXPERIMENTAL)" | 1144 | bool "Kprobes (EXPERIMENTAL)" |
| 1145 | depends on EXPERIMENTAL && MODULES | 1145 | depends on KALLSYMS && EXPERIMENTAL && MODULES |
| 1146 | help | 1146 | help |
| 1147 | Kprobes allows you to trap at almost any kernel address and | 1147 | Kprobes allows you to trap at almost any kernel address and |
| 1148 | execute a callback function. register_kprobe() establishes | 1148 | execute a callback function. register_kprobe() establishes |
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index afe6505ca0b3..d98e44b16fe2 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c | |||
| @@ -230,20 +230,20 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, | |||
| 230 | struct pt_regs *regs) | 230 | struct pt_regs *regs) |
| 231 | { | 231 | { |
| 232 | unsigned long *sara = (unsigned long *)®s->esp; | 232 | unsigned long *sara = (unsigned long *)®s->esp; |
| 233 | struct kretprobe_instance *ri; | ||
| 234 | 233 | ||
| 235 | if ((ri = get_free_rp_inst(rp)) != NULL) { | 234 | struct kretprobe_instance *ri; |
| 236 | ri->rp = rp; | 235 | |
| 237 | ri->task = current; | 236 | if ((ri = get_free_rp_inst(rp)) != NULL) { |
| 237 | ri->rp = rp; | ||
| 238 | ri->task = current; | ||
| 238 | ri->ret_addr = (kprobe_opcode_t *) *sara; | 239 | ri->ret_addr = (kprobe_opcode_t *) *sara; |
| 239 | 240 | ||
| 240 | /* Replace the return addr with trampoline addr */ | 241 | /* Replace the return addr with trampoline addr */ |
| 241 | *sara = (unsigned long) &kretprobe_trampoline; | 242 | *sara = (unsigned long) &kretprobe_trampoline; |
| 242 | 243 | add_rp_inst(ri); | |
| 243 | add_rp_inst(ri); | 244 | } else { |
| 244 | } else { | 245 | rp->nmissed++; |
| 245 | rp->nmissed++; | 246 | } |
| 246 | } | ||
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | /* | 249 | /* |
| @@ -359,7 +359,7 @@ no_kprobe: | |||
| 359 | void __kprobes kretprobe_trampoline_holder(void) | 359 | void __kprobes kretprobe_trampoline_holder(void) |
| 360 | { | 360 | { |
| 361 | asm volatile ( ".global kretprobe_trampoline\n" | 361 | asm volatile ( ".global kretprobe_trampoline\n" |
| 362 | "kretprobe_trampoline: \n" | 362 | "kretprobe_trampoline: \n" |
| 363 | " pushf\n" | 363 | " pushf\n" |
| 364 | /* skip cs, eip, orig_eax, es, ds */ | 364 | /* skip cs, eip, orig_eax, es, ds */ |
| 365 | " subl $20, %esp\n" | 365 | " subl $20, %esp\n" |
| @@ -395,14 +395,15 @@ no_kprobe: | |||
| 395 | */ | 395 | */ |
| 396 | fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) | 396 | fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) |
| 397 | { | 397 | { |
| 398 | struct kretprobe_instance *ri = NULL; | 398 | struct kretprobe_instance *ri = NULL; |
| 399 | struct hlist_head *head; | 399 | struct hlist_head *head, empty_rp; |
| 400 | struct hlist_node *node, *tmp; | 400 | struct hlist_node *node, *tmp; |
| 401 | unsigned long flags, orig_ret_address = 0; | 401 | unsigned long flags, orig_ret_address = 0; |
| 402 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | 402 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; |
| 403 | 403 | ||
| 404 | INIT_HLIST_HEAD(&empty_rp); | ||
| 404 | spin_lock_irqsave(&kretprobe_lock, flags); | 405 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 405 | head = kretprobe_inst_table_head(current); | 406 | head = kretprobe_inst_table_head(current); |
| 406 | 407 | ||
| 407 | /* | 408 | /* |
| 408 | * It is possible to have multiple instances associated with a given | 409 | * It is possible to have multiple instances associated with a given |
| @@ -413,14 +414,14 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) | |||
| 413 | * We can handle this because: | 414 | * We can handle this because: |
| 414 | * - instances are always inserted at the head of the list | 415 | * - instances are always inserted at the head of the list |
| 415 | * - when multiple return probes are registered for the same | 416 | * - when multiple return probes are registered for the same |
| 416 | * function, the first instance's ret_addr will point to the | 417 | * function, the first instance's ret_addr will point to the |
| 417 | * real return address, and all the rest will point to | 418 | * real return address, and all the rest will point to |
| 418 | * kretprobe_trampoline | 419 | * kretprobe_trampoline |
| 419 | */ | 420 | */ |
| 420 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | 421 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { |
| 421 | if (ri->task != current) | 422 | if (ri->task != current) |
| 422 | /* another task is sharing our hash bucket */ | 423 | /* another task is sharing our hash bucket */ |
| 423 | continue; | 424 | continue; |
| 424 | 425 | ||
| 425 | if (ri->rp && ri->rp->handler){ | 426 | if (ri->rp && ri->rp->handler){ |
| 426 | __get_cpu_var(current_kprobe) = &ri->rp->kp; | 427 | __get_cpu_var(current_kprobe) = &ri->rp->kp; |
| @@ -429,7 +430,7 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) | |||
| 429 | } | 430 | } |
| 430 | 431 | ||
| 431 | orig_ret_address = (unsigned long)ri->ret_addr; | 432 | orig_ret_address = (unsigned long)ri->ret_addr; |
| 432 | recycle_rp_inst(ri); | 433 | recycle_rp_inst(ri, &empty_rp); |
| 433 | 434 | ||
| 434 | if (orig_ret_address != trampoline_address) | 435 | if (orig_ret_address != trampoline_address) |
| 435 | /* | 436 | /* |
| @@ -444,6 +445,10 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs) | |||
| 444 | 445 | ||
| 445 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 446 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 446 | 447 | ||
| 448 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
| 449 | hlist_del(&ri->hlist); | ||
| 450 | kfree(ri); | ||
| 451 | } | ||
| 447 | return (void*)orig_ret_address; | 452 | return (void*)orig_ret_address; |
| 448 | } | 453 | } |
| 449 | 454 | ||
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 96cd0232e1e0..dad02a960e03 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c | |||
| @@ -297,9 +297,9 @@ void show_regs(struct pt_regs * regs) | |||
| 297 | if (user_mode_vm(regs)) | 297 | if (user_mode_vm(regs)) |
| 298 | printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); | 298 | printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); |
| 299 | printk(" EFLAGS: %08lx %s (%s %.*s)\n", | 299 | printk(" EFLAGS: %08lx %s (%s %.*s)\n", |
| 300 | regs->eflags, print_tainted(), system_utsname.release, | 300 | regs->eflags, print_tainted(), init_utsname()->release, |
| 301 | (int)strcspn(system_utsname.version, " "), | 301 | (int)strcspn(init_utsname()->version, " "), |
| 302 | system_utsname.version); | 302 | init_utsname()->version); |
| 303 | printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", | 303 | printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", |
| 304 | regs->eax,regs->ebx,regs->ecx,regs->edx); | 304 | regs->eax,regs->ebx,regs->ecx,regs->edx); |
| 305 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", | 305 | printk("ESI: %08lx EDI: %08lx EBP: %08lx", |
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 0831f709f777..9d93ecf6d999 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
| @@ -612,6 +612,7 @@ extern struct { | |||
| 612 | /* which logical CPUs are on which nodes */ | 612 | /* which logical CPUs are on which nodes */ |
| 613 | cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly = | 613 | cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly = |
| 614 | { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE }; | 614 | { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE }; |
| 615 | EXPORT_SYMBOL(node_2_cpu_mask); | ||
| 615 | /* which node each logical CPU is on */ | 616 | /* which node each logical CPU is on */ |
| 616 | int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 }; | 617 | int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 }; |
| 617 | EXPORT_SYMBOL(cpu_2_node); | 618 | EXPORT_SYMBOL(cpu_2_node); |
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c index 8fdb1fb17a5f..4048397f1740 100644 --- a/arch/i386/kernel/sys_i386.c +++ b/arch/i386/kernel/sys_i386.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/utsname.h> | 21 | #include <linux/utsname.h> |
| 22 | 22 | ||
| 23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
| 24 | #include <asm/unistd.h> | ||
| 24 | #include <asm/ipc.h> | 25 | #include <asm/ipc.h> |
| 25 | 26 | ||
| 26 | /* | 27 | /* |
| @@ -210,7 +211,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name) | |||
| 210 | if (!name) | 211 | if (!name) |
| 211 | return -EFAULT; | 212 | return -EFAULT; |
| 212 | down_read(&uts_sem); | 213 | down_read(&uts_sem); |
| 213 | err=copy_to_user(name, &system_utsname, sizeof (*name)); | 214 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 214 | up_read(&uts_sem); | 215 | up_read(&uts_sem); |
| 215 | return err?-EFAULT:0; | 216 | return err?-EFAULT:0; |
| 216 | } | 217 | } |
| @@ -226,16 +227,21 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) | |||
| 226 | 227 | ||
| 227 | down_read(&uts_sem); | 228 | down_read(&uts_sem); |
| 228 | 229 | ||
| 229 | error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); | 230 | error = __copy_to_user(&name->sysname, &utsname()->sysname, |
| 230 | error |= __put_user(0,name->sysname+__OLD_UTS_LEN); | 231 | __OLD_UTS_LEN); |
| 231 | error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); | 232 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); |
| 232 | error |= __put_user(0,name->nodename+__OLD_UTS_LEN); | 233 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, |
| 233 | error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); | 234 | __OLD_UTS_LEN); |
| 234 | error |= __put_user(0,name->release+__OLD_UTS_LEN); | 235 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); |
| 235 | error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); | 236 | error |= __copy_to_user(&name->release, &utsname()->release, |
| 236 | error |= __put_user(0,name->version+__OLD_UTS_LEN); | 237 | __OLD_UTS_LEN); |
| 237 | error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); | 238 | error |= __put_user(0, name->release + __OLD_UTS_LEN); |
| 238 | error |= __put_user(0,name->machine+__OLD_UTS_LEN); | 239 | error |= __copy_to_user(&name->version, &utsname()->version, |
| 240 | __OLD_UTS_LEN); | ||
| 241 | error |= __put_user(0, name->version + __OLD_UTS_LEN); | ||
| 242 | error |= __copy_to_user(&name->machine, &utsname()->machine, | ||
| 243 | __OLD_UTS_LEN); | ||
| 244 | error |= __put_user(0, name->machine + __OLD_UTS_LEN); | ||
| 239 | 245 | ||
| 240 | up_read(&uts_sem); | 246 | up_read(&uts_sem); |
| 241 | 247 | ||
| @@ -243,3 +249,17 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) | |||
| 243 | 249 | ||
| 244 | return error; | 250 | return error; |
| 245 | } | 251 | } |
| 252 | |||
| 253 | |||
| 254 | /* | ||
| 255 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 256 | * end up with proper pt_regs. | ||
| 257 | */ | ||
| 258 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 259 | { | ||
| 260 | long __res; | ||
| 261 | asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" | ||
| 262 | : "=a" (__res) | ||
| 263 | : "0" (__NR_execve),"ri" (filename),"c" (argv), "d" (envp) : "memory"); | ||
| 264 | return __res; | ||
| 265 | } | ||
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 6820b8d643c7..00489b706d27 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
| @@ -357,9 +357,9 @@ void show_registers(struct pt_regs *regs) | |||
| 357 | KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" | 357 | KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" |
| 358 | KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", | 358 | KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", |
| 359 | smp_processor_id(), 0xffff & regs->xcs, regs->eip, | 359 | smp_processor_id(), 0xffff & regs->xcs, regs->eip, |
| 360 | print_tainted(), regs->eflags, system_utsname.release, | 360 | print_tainted(), regs->eflags, init_utsname()->release, |
| 361 | (int)strcspn(system_utsname.version, " "), | 361 | (int)strcspn(init_utsname()->version, " "), |
| 362 | system_utsname.version); | 362 | init_utsname()->version); |
| 363 | print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); | 363 | print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); |
| 364 | printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", | 364 | printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", |
| 365 | regs->eax, regs->ebx, regs->ecx, regs->edx); | 365 | regs->eax, regs->ebx, regs->ecx, regs->edx); |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 0b7f701d5cf7..70f7eb9fed35 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
| @@ -516,7 +516,7 @@ source "arch/ia64/oprofile/Kconfig" | |||
| 516 | 516 | ||
| 517 | config KPROBES | 517 | config KPROBES |
| 518 | bool "Kprobes (EXPERIMENTAL)" | 518 | bool "Kprobes (EXPERIMENTAL)" |
| 519 | depends on EXPERIMENTAL && MODULES | 519 | depends on KALLSYMS && EXPERIMENTAL && MODULES |
| 520 | help | 520 | help |
| 521 | Kprobes allows you to trap at almost any kernel address and | 521 | Kprobes allows you to trap at almost any kernel address and |
| 522 | execute a callback function. register_kprobe() establishes | 522 | execute a callback function. register_kprobe() establishes |
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 0daacc20ed36..246eb3d3757a 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c | |||
| @@ -940,7 +940,7 @@ static inline void show_serial_version(void) | |||
| 940 | printk(KERN_INFO " no serial options enabled\n"); | 940 | printk(KERN_INFO " no serial options enabled\n"); |
| 941 | } | 941 | } |
| 942 | 942 | ||
| 943 | static struct tty_operations hp_ops = { | 943 | static const struct tty_operations hp_ops = { |
| 944 | .open = rs_open, | 944 | .open = rs_open, |
| 945 | .close = rs_close, | 945 | .close = rs_close, |
| 946 | .write = rs_write, | 946 | .write = rs_write, |
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 12701cf32d99..e5b1be51b197 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
| @@ -492,11 +492,11 @@ GLOBAL_ENTRY(prefetch_stack) | |||
| 492 | br.ret.sptk.many rp | 492 | br.ret.sptk.many rp |
| 493 | END(prefetch_stack) | 493 | END(prefetch_stack) |
| 494 | 494 | ||
| 495 | GLOBAL_ENTRY(execve) | 495 | GLOBAL_ENTRY(kernel_execve) |
| 496 | mov r15=__NR_execve // put syscall number in place | 496 | mov r15=__NR_execve // put syscall number in place |
| 497 | break __BREAK_SYSCALL | 497 | break __BREAK_SYSCALL |
| 498 | br.ret.sptk.many rp | 498 | br.ret.sptk.many rp |
| 499 | END(execve) | 499 | END(kernel_execve) |
| 500 | 500 | ||
| 501 | GLOBAL_ENTRY(clone) | 501 | GLOBAL_ENTRY(clone) |
| 502 | mov r15=__NR_clone // put syscall number in place | 502 | mov r15=__NR_clone // put syscall number in place |
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 169ec3a7156c..51217d63285e 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c | |||
| @@ -90,7 +90,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, | |||
| 90 | p->ainsn.target_br_reg = 0; | 90 | p->ainsn.target_br_reg = 0; |
| 91 | 91 | ||
| 92 | /* Check for Break instruction | 92 | /* Check for Break instruction |
| 93 | * Bits 37:40 Major opcode to be zero | 93 | * Bits 37:40 Major opcode to be zero |
| 94 | * Bits 27:32 X6 to be zero | 94 | * Bits 27:32 X6 to be zero |
| 95 | * Bits 32:35 X3 to be zero | 95 | * Bits 32:35 X3 to be zero |
| 96 | */ | 96 | */ |
| @@ -104,19 +104,19 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, | |||
| 104 | switch (major_opcode) { | 104 | switch (major_opcode) { |
| 105 | case INDIRECT_CALL_OPCODE: | 105 | case INDIRECT_CALL_OPCODE: |
| 106 | p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; | 106 | p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; |
| 107 | p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); | 107 | p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); |
| 108 | break; | 108 | break; |
| 109 | case IP_RELATIVE_PREDICT_OPCODE: | 109 | case IP_RELATIVE_PREDICT_OPCODE: |
| 110 | case IP_RELATIVE_BRANCH_OPCODE: | 110 | case IP_RELATIVE_BRANCH_OPCODE: |
| 111 | p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR; | 111 | p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR; |
| 112 | break; | 112 | break; |
| 113 | case IP_RELATIVE_CALL_OPCODE: | 113 | case IP_RELATIVE_CALL_OPCODE: |
| 114 | p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR; | 114 | p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR; |
| 115 | p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; | 115 | p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; |
| 116 | p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); | 116 | p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7); |
| 117 | break; | 117 | break; |
| 118 | } | 118 | } |
| 119 | } else if (bundle_encoding[template][slot] == X) { | 119 | } else if (bundle_encoding[template][slot] == X) { |
| 120 | switch (major_opcode) { | 120 | switch (major_opcode) { |
| 121 | case LONG_CALL_OPCODE: | 121 | case LONG_CALL_OPCODE: |
| 122 | p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; | 122 | p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG; |
| @@ -258,18 +258,18 @@ static void __kprobes get_kprobe_inst(bundle_t *bundle, uint slot, | |||
| 258 | 258 | ||
| 259 | switch (slot) { | 259 | switch (slot) { |
| 260 | case 0: | 260 | case 0: |
| 261 | *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT); | 261 | *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT); |
| 262 | *kprobe_inst = bundle->quad0.slot0; | 262 | *kprobe_inst = bundle->quad0.slot0; |
| 263 | break; | 263 | break; |
| 264 | case 1: | 264 | case 1: |
| 265 | *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT); | 265 | *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT); |
| 266 | kprobe_inst_p0 = bundle->quad0.slot1_p0; | 266 | kprobe_inst_p0 = bundle->quad0.slot1_p0; |
| 267 | kprobe_inst_p1 = bundle->quad1.slot1_p1; | 267 | kprobe_inst_p1 = bundle->quad1.slot1_p1; |
| 268 | *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46)); | 268 | *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46)); |
| 269 | break; | 269 | break; |
| 270 | case 2: | 270 | case 2: |
| 271 | *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT); | 271 | *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT); |
| 272 | *kprobe_inst = bundle->quad1.slot2; | 272 | *kprobe_inst = bundle->quad1.slot2; |
| 273 | break; | 273 | break; |
| 274 | } | 274 | } |
| 275 | } | 275 | } |
| @@ -290,11 +290,11 @@ static int __kprobes valid_kprobe_addr(int template, int slot, | |||
| 290 | return -EINVAL; | 290 | return -EINVAL; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | if (in_ivt_functions(addr)) { | 293 | if (in_ivt_functions(addr)) { |
| 294 | printk(KERN_WARNING "Kprobes can't be inserted inside " | 294 | printk(KERN_WARNING "Kprobes can't be inserted inside " |
| 295 | "IVT functions at 0x%lx\n", addr); | 295 | "IVT functions at 0x%lx\n", addr); |
| 296 | return -EINVAL; | 296 | return -EINVAL; |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | if (slot == 1 && bundle_encoding[template][1] != L) { | 299 | if (slot == 1 && bundle_encoding[template][1] != L) { |
| 300 | printk(KERN_WARNING "Inserting kprobes on slot #1 " | 300 | printk(KERN_WARNING "Inserting kprobes on slot #1 " |
| @@ -338,12 +338,13 @@ static void kretprobe_trampoline(void) | |||
| 338 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 338 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
| 339 | { | 339 | { |
| 340 | struct kretprobe_instance *ri = NULL; | 340 | struct kretprobe_instance *ri = NULL; |
| 341 | struct hlist_head *head; | 341 | struct hlist_head *head, empty_rp; |
| 342 | struct hlist_node *node, *tmp; | 342 | struct hlist_node *node, *tmp; |
| 343 | unsigned long flags, orig_ret_address = 0; | 343 | unsigned long flags, orig_ret_address = 0; |
| 344 | unsigned long trampoline_address = | 344 | unsigned long trampoline_address = |
| 345 | ((struct fnptr *)kretprobe_trampoline)->ip; | 345 | ((struct fnptr *)kretprobe_trampoline)->ip; |
| 346 | 346 | ||
| 347 | INIT_HLIST_HEAD(&empty_rp); | ||
| 347 | spin_lock_irqsave(&kretprobe_lock, flags); | 348 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 348 | head = kretprobe_inst_table_head(current); | 349 | head = kretprobe_inst_table_head(current); |
| 349 | 350 | ||
| @@ -369,7 +370,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 369 | ri->rp->handler(ri, regs); | 370 | ri->rp->handler(ri, regs); |
| 370 | 371 | ||
| 371 | orig_ret_address = (unsigned long)ri->ret_addr; | 372 | orig_ret_address = (unsigned long)ri->ret_addr; |
| 372 | recycle_rp_inst(ri); | 373 | recycle_rp_inst(ri, &empty_rp); |
| 373 | 374 | ||
| 374 | if (orig_ret_address != trampoline_address) | 375 | if (orig_ret_address != trampoline_address) |
| 375 | /* | 376 | /* |
| @@ -387,6 +388,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 387 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 388 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 388 | preempt_enable_no_resched(); | 389 | preempt_enable_no_resched(); |
| 389 | 390 | ||
| 391 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
| 392 | hlist_del(&ri->hlist); | ||
| 393 | kfree(ri); | ||
| 394 | } | ||
| 390 | /* | 395 | /* |
| 391 | * By returning a non-zero value, we are telling | 396 | * By returning a non-zero value, we are telling |
| 392 | * kprobe_handler() that we don't want the post_handler | 397 | * kprobe_handler() that we don't want the post_handler |
| @@ -424,14 +429,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
| 424 | bundle_t *bundle; | 429 | bundle_t *bundle; |
| 425 | 430 | ||
| 426 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; | 431 | bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle; |
| 427 | template = bundle->quad0.template; | 432 | template = bundle->quad0.template; |
| 428 | 433 | ||
| 429 | if(valid_kprobe_addr(template, slot, addr)) | 434 | if(valid_kprobe_addr(template, slot, addr)) |
| 430 | return -EINVAL; | 435 | return -EINVAL; |
| 431 | 436 | ||
| 432 | /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */ | 437 | /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */ |
| 433 | if (slot == 1 && bundle_encoding[template][1] == L) | 438 | if (slot == 1 && bundle_encoding[template][1] == L) |
| 434 | slot++; | 439 | slot++; |
| 435 | 440 | ||
| 436 | /* Get kprobe_inst and major_opcode from the bundle */ | 441 | /* Get kprobe_inst and major_opcode from the bundle */ |
| 437 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); | 442 | get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode); |
| @@ -489,21 +494,22 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) | |||
| 489 | */ | 494 | */ |
| 490 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | 495 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) |
| 491 | { | 496 | { |
| 492 | unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle); | 497 | unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle); |
| 493 | unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; | 498 | unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL; |
| 494 | unsigned long template; | 499 | unsigned long template; |
| 495 | int slot = ((unsigned long)p->addr & 0xf); | 500 | int slot = ((unsigned long)p->addr & 0xf); |
| 496 | 501 | ||
| 497 | template = p->ainsn.insn->bundle.quad0.template; | 502 | template = p->ainsn.insn->bundle.quad0.template; |
| 498 | 503 | ||
| 499 | if (slot == 1 && bundle_encoding[template][1] == L) | 504 | if (slot == 1 && bundle_encoding[template][1] == L) |
| 500 | slot = 2; | 505 | slot = 2; |
| 501 | 506 | ||
| 502 | if (p->ainsn.inst_flag) { | 507 | if (p->ainsn.inst_flag) { |
| 503 | 508 | ||
| 504 | if (p->ainsn.inst_flag & INST_FLAG_FIX_RELATIVE_IP_ADDR) { | 509 | if (p->ainsn.inst_flag & INST_FLAG_FIX_RELATIVE_IP_ADDR) { |
| 505 | /* Fix relative IP address */ | 510 | /* Fix relative IP address */ |
| 506 | regs->cr_iip = (regs->cr_iip - bundle_addr) + resume_addr; | 511 | regs->cr_iip = (regs->cr_iip - bundle_addr) + |
| 512 | resume_addr; | ||
| 507 | } | 513 | } |
| 508 | 514 | ||
| 509 | if (p->ainsn.inst_flag & INST_FLAG_FIX_BRANCH_REG) { | 515 | if (p->ainsn.inst_flag & INST_FLAG_FIX_BRANCH_REG) { |
| @@ -540,18 +546,18 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
| 540 | } | 546 | } |
| 541 | 547 | ||
| 542 | if (slot == 2) { | 548 | if (slot == 2) { |
| 543 | if (regs->cr_iip == bundle_addr + 0x10) { | 549 | if (regs->cr_iip == bundle_addr + 0x10) { |
| 544 | regs->cr_iip = resume_addr + 0x10; | 550 | regs->cr_iip = resume_addr + 0x10; |
| 545 | } | 551 | } |
| 546 | } else { | 552 | } else { |
| 547 | if (regs->cr_iip == bundle_addr) { | 553 | if (regs->cr_iip == bundle_addr) { |
| 548 | regs->cr_iip = resume_addr; | 554 | regs->cr_iip = resume_addr; |
| 549 | } | 555 | } |
| 550 | } | 556 | } |
| 551 | 557 | ||
| 552 | turn_ss_off: | 558 | turn_ss_off: |
| 553 | /* Turn off Single Step bit */ | 559 | /* Turn off Single Step bit */ |
| 554 | ia64_psr(regs)->ss = 0; | 560 | ia64_psr(regs)->ss = 0; |
| 555 | } | 561 | } |
| 556 | 562 | ||
| 557 | static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs) | 563 | static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs) |
| @@ -587,7 +593,7 @@ static int __kprobes is_ia64_break_inst(struct pt_regs *regs) | |||
| 587 | 593 | ||
| 588 | /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */ | 594 | /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */ |
| 589 | if (slot == 1 && bundle_encoding[template][1] == L) | 595 | if (slot == 1 && bundle_encoding[template][1] == L) |
| 590 | slot++; | 596 | slot++; |
| 591 | 597 | ||
| 592 | /* Get Kprobe probe instruction at given slot*/ | 598 | /* Get Kprobe probe instruction at given slot*/ |
| 593 | get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode); | 599 | get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode); |
| @@ -627,7 +633,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) | |||
| 627 | if (p) { | 633 | if (p) { |
| 628 | if ((kcb->kprobe_status == KPROBE_HIT_SS) && | 634 | if ((kcb->kprobe_status == KPROBE_HIT_SS) && |
| 629 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { | 635 | (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { |
| 630 | ia64_psr(regs)->ss = 0; | 636 | ia64_psr(regs)->ss = 0; |
| 631 | goto no_kprobe; | 637 | goto no_kprobe; |
| 632 | } | 638 | } |
| 633 | /* We have reentered the pre_kprobe_handler(), since | 639 | /* We have reentered the pre_kprobe_handler(), since |
| @@ -887,7 +893,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 887 | * fix the return address to our jprobe_inst_return() function | 893 | * fix the return address to our jprobe_inst_return() function |
| 888 | * in the jprobes.S file | 894 | * in the jprobes.S file |
| 889 | */ | 895 | */ |
| 890 | regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip; | 896 | regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip; |
| 891 | 897 | ||
| 892 | return 1; | 898 | return 1; |
| 893 | } | 899 | } |
diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c index 20340631179f..a78b45f5fe2f 100644 --- a/arch/ia64/kernel/numa.c +++ b/arch/ia64/kernel/numa.c | |||
| @@ -28,6 +28,7 @@ u16 cpu_to_node_map[NR_CPUS] __cacheline_aligned; | |||
| 28 | EXPORT_SYMBOL(cpu_to_node_map); | 28 | EXPORT_SYMBOL(cpu_to_node_map); |
| 29 | 29 | ||
| 30 | cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; | 30 | cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; |
| 31 | EXPORT_SYMBOL(node_to_cpu_mask); | ||
| 31 | 32 | ||
| 32 | void __cpuinit map_cpu_to_node(int cpu, int nid) | 33 | void __cpuinit map_cpu_to_node(int cpu, int nid) |
| 33 | { | 34 | { |
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index ea914cc6812a..51922b98086a 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c | |||
| @@ -8,8 +8,6 @@ | |||
| 8 | * 2005-10-07 Keith Owens <kaos@sgi.com> | 8 | * 2005-10-07 Keith Owens <kaos@sgi.com> |
| 9 | * Add notify_die() hooks. | 9 | * Add notify_die() hooks. |
| 10 | */ | 10 | */ |
| 11 | #define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */ | ||
| 12 | |||
| 13 | #include <linux/cpu.h> | 11 | #include <linux/cpu.h> |
| 14 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
| 15 | #include <linux/elf.h> | 13 | #include <linux/elf.h> |
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index b632b9c1e3b3..462ea178f49a 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c | |||
| @@ -423,7 +423,7 @@ static int sn_topology_show(struct seq_file *s, void *d) | |||
| 423 | "coherency_domain %d, " | 423 | "coherency_domain %d, " |
| 424 | "region_size %d\n", | 424 | "region_size %d\n", |
| 425 | 425 | ||
| 426 | partid, system_utsname.nodename, | 426 | partid, utsname()->nodename, |
| 427 | shubtype ? "shub2" : "shub1", | 427 | shubtype ? "shub2" : "shub1", |
| 428 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, | 428 | (u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift, |
| 429 | system_size, sharing_size, coher, region_size); | 429 | system_size, sharing_size, coher, region_size); |
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index a9cea32eb824..b567351f3c52 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c | |||
| @@ -25,6 +25,8 @@ | |||
| 25 | #include <asm/cachectl.h> | 25 | #include <asm/cachectl.h> |
| 26 | #include <asm/cacheflush.h> | 26 | #include <asm/cacheflush.h> |
| 27 | #include <asm/ipc.h> | 27 | #include <asm/ipc.h> |
| 28 | #include <asm/syscall.h> | ||
| 29 | #include <asm/unistd.h> | ||
| 28 | 30 | ||
| 29 | /* | 31 | /* |
| 30 | * sys_tas() - test-and-set | 32 | * sys_tas() - test-and-set |
| @@ -205,7 +207,7 @@ asmlinkage int sys_uname(struct old_utsname * name) | |||
| 205 | if (!name) | 207 | if (!name) |
| 206 | return -EFAULT; | 208 | return -EFAULT; |
| 207 | down_read(&uts_sem); | 209 | down_read(&uts_sem); |
| 208 | err=copy_to_user(name, &system_utsname, sizeof (*name)); | 210 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 209 | up_read(&uts_sem); | 211 | up_read(&uts_sem); |
| 210 | return err?-EFAULT:0; | 212 | return err?-EFAULT:0; |
| 211 | } | 213 | } |
| @@ -223,3 +225,21 @@ asmlinkage int sys_cachectl(char *addr, int nbytes, int op) | |||
| 223 | return -ENOSYS; | 225 | return -ENOSYS; |
| 224 | } | 226 | } |
| 225 | 227 | ||
| 228 | /* | ||
| 229 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 230 | * end up with proper pt_regs. | ||
| 231 | */ | ||
| 232 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 233 | { | ||
| 234 | register long __scno __asm__ ("r7") = __NR_execve; | ||
| 235 | register long __arg3 __asm__ ("r2") = (long)(envp); | ||
| 236 | register long __arg2 __asm__ ("r1") = (long)(argv); | ||
| 237 | register long __res __asm__ ("r0") = (long)(filename); | ||
| 238 | __asm__ __volatile__ ( | ||
| 239 | "trap #" SYSCALL_VECTOR "|| nop" | ||
| 240 | : "=r" (__res) | ||
| 241 | : "r" (__scno), "0" (__res), "r" (__arg2), | ||
| 242 | "r" (__arg3) | ||
| 243 | : "memory"); | ||
| 244 | return __res; | ||
| 245 | } | ||
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 143c552d38f3..90238a8c9e14 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <asm/traps.h> | 27 | #include <asm/traps.h> |
| 28 | #include <asm/ipc.h> | 28 | #include <asm/ipc.h> |
| 29 | #include <asm/page.h> | 29 | #include <asm/page.h> |
| 30 | #include <asm/unistd.h> | ||
| 30 | 31 | ||
| 31 | /* | 32 | /* |
| 32 | * sys_pipe() is the normal C calling standard for creating | 33 | * sys_pipe() is the normal C calling standard for creating |
| @@ -663,3 +664,18 @@ asmlinkage int sys_getpagesize(void) | |||
| 663 | { | 664 | { |
| 664 | return PAGE_SIZE; | 665 | return PAGE_SIZE; |
| 665 | } | 666 | } |
| 667 | |||
| 668 | /* | ||
| 669 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 670 | * end up with proper pt_regs. | ||
| 671 | */ | ||
| 672 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 673 | { | ||
| 674 | register long __res asm ("%d0") = __NR_execve; | ||
| 675 | register long __a asm ("%d1") = (long)(filename); | ||
| 676 | register long __b asm ("%d2") = (long)(argv); | ||
| 677 | register long __c asm ("%d3") = (long)(envp); | ||
| 678 | asm volatile ("trap #0" : "+d" (__res) | ||
| 679 | : "d" (__a), "d" (__b), "d" (__c)); | ||
| 680 | return __res; | ||
| 681 | } | ||
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c index d87e1e0a1336..c3494b8447d1 100644 --- a/arch/m68knommu/kernel/sys_m68k.c +++ b/arch/m68knommu/kernel/sys_m68k.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <asm/traps.h> | 26 | #include <asm/traps.h> |
| 27 | #include <asm/ipc.h> | 27 | #include <asm/ipc.h> |
| 28 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
| 29 | #include <asm/unistd.h> | ||
| 29 | 30 | ||
| 30 | /* | 31 | /* |
| 31 | * sys_pipe() is the normal C calling standard for creating | 32 | * sys_pipe() is the normal C calling standard for creating |
| @@ -206,3 +207,17 @@ asmlinkage int sys_getpagesize(void) | |||
| 206 | return PAGE_SIZE; | 207 | return PAGE_SIZE; |
| 207 | } | 208 | } |
| 208 | 209 | ||
| 210 | /* | ||
| 211 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 212 | * end up with proper pt_regs. | ||
| 213 | */ | ||
| 214 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 215 | { | ||
| 216 | register long __res asm ("%d0") = __NR_execve; | ||
| 217 | register long __a asm ("%d1") = (long)(filename); | ||
| 218 | register long __b asm ("%d2") = (long)(argv); | ||
| 219 | register long __c asm ("%d3") = (long)(envp); | ||
| 220 | asm volatile ("trap #0" : "+d" (__res) | ||
| 221 | : "d" (__a), "d" (__b), "d" (__c)); | ||
| 222 | return __res; | ||
| 223 | } | ||
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 30750c54bdf5..87cee341eb54 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
| @@ -537,6 +537,7 @@ config QEMU | |||
| 537 | select SYS_HAS_CPU_MIPS32_R1 | 537 | select SYS_HAS_CPU_MIPS32_R1 |
| 538 | select SYS_SUPPORTS_32BIT_KERNEL | 538 | select SYS_SUPPORTS_32BIT_KERNEL |
| 539 | select SYS_SUPPORTS_BIG_ENDIAN | 539 | select SYS_SUPPORTS_BIG_ENDIAN |
| 540 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
| 540 | select ARCH_SPARSEMEM_ENABLE | 541 | select ARCH_SPARSEMEM_ENABLE |
| 541 | help | 542 | help |
| 542 | Qemu is a software emulator which among other architectures also | 543 | Qemu is a software emulator which among other architectures also |
| @@ -1841,6 +1842,14 @@ config RWSEM_GENERIC_SPINLOCK | |||
| 1841 | bool | 1842 | bool |
| 1842 | default y | 1843 | default y |
| 1843 | 1844 | ||
| 1845 | config LOCKDEP_SUPPORT | ||
| 1846 | bool | ||
| 1847 | default y | ||
| 1848 | |||
| 1849 | config STACKTRACE_SUPPORT | ||
| 1850 | bool | ||
| 1851 | default y | ||
| 1852 | |||
| 1844 | source "init/Kconfig" | 1853 | source "init/Kconfig" |
| 1845 | 1854 | ||
| 1846 | menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)" | 1855 | menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)" |
diff --git a/arch/mips/basler/excite/excite_flashtest.c b/arch/mips/basler/excite/excite_flashtest.c deleted file mode 100644 index f0024a8e3294..000000000000 --- a/arch/mips/basler/excite/excite_flashtest.c +++ /dev/null | |||
| @@ -1,294 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2005 by Basler Vision Technologies AG | ||
| 3 | * Author: Thies Moeller <thies.moeller@baslerweb.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/string.h> | ||
| 25 | #include <linux/ioport.h> | ||
| 26 | #include <linux/device.h> | ||
| 27 | #include <linux/delay.h> | ||
| 28 | #include <linux/err.h> | ||
| 29 | #include <linux/kernel.h> | ||
| 30 | |||
| 31 | #include <excite.h> | ||
| 32 | |||
| 33 | #include <asm/io.h> | ||
| 34 | |||
| 35 | #include <linux/mtd/mtd.h> | ||
| 36 | #include <linux/mtd/nand.h> | ||
| 37 | #include <linux/mtd/nand_ecc.h> | ||
| 38 | #include <linux/mtd/partitions.h> | ||
| 39 | #include <asm/rm9k-ocd.h> // for ocd_write | ||
| 40 | #include <linux/workqueue.h> // for queue | ||
| 41 | |||
| 42 | #include "excite_nandflash.h" | ||
| 43 | #include "nandflash.h" | ||
| 44 | |||
| 45 | #define PFX "excite flashtest: " | ||
| 46 | typedef void __iomem *io_reg_t; | ||
| 47 | |||
| 48 | #define io_readb(__a__) __raw_readb((__a__)) | ||
| 49 | #define io_writeb(__v__, __a__) __raw_writeb((__v__), (__a__)) | ||
| 50 | |||
| 51 | |||
| 52 | |||
| 53 | static inline const struct resource *excite_nandflash_get_resource( | ||
| 54 | struct platform_device *d, unsigned long flags, const char *basename) | ||
| 55 | { | ||
| 56 | const char fmt[] = "%s_%u"; | ||
| 57 | char buf[80]; | ||
| 58 | |||
| 59 | if (unlikely(snprintf(buf, sizeof buf, fmt, basename, d->id) >= sizeof buf)) | ||
| 60 | return NULL; | ||
| 61 | |||
| 62 | return platform_get_resource_byname(d, flags, buf); | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline io_reg_t | ||
| 66 | excite_nandflash_map_regs(struct platform_device *d, const char *basename) | ||
| 67 | { | ||
| 68 | void *result = NULL; | ||
| 69 | const struct resource *const r = | ||
| 70 | excite_nandflash_get_resource(d, IORESOURCE_MEM, basename); | ||
| 71 | if (r) | ||
| 72 | result = ioremap_nocache(r->start, r->end + 1 - r->start); | ||
| 73 | return result; | ||
| 74 | } | ||
| 75 | |||
| 76 | /* controller and mtd information */ | ||
| 77 | |||
| 78 | struct excite_nandflash_drvdata { | ||
| 79 | struct mtd_info board_mtd; | ||
| 80 | struct nand_chip board_chip; | ||
| 81 | io_reg_t regs; | ||
| 82 | }; | ||
| 83 | |||
| 84 | |||
| 85 | /* command and control functions */ | ||
| 86 | static void excite_nandflash_hwcontrol(struct mtd_info *mtd, int cmd) | ||
| 87 | { | ||
| 88 | struct nand_chip *this = mtd->priv; | ||
| 89 | io_reg_t regs = container_of(mtd,struct excite_nandflash_drvdata,board_mtd)->regs; | ||
| 90 | |||
| 91 | switch (cmd) { | ||
| 92 | /* Select the command latch */ | ||
| 93 | case NAND_CTL_SETCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_CMD; | ||
| 94 | break; | ||
| 95 | /* Deselect the command latch */ | ||
| 96 | case NAND_CTL_CLRCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA; | ||
| 97 | break; | ||
| 98 | /* Select the address latch */ | ||
| 99 | case NAND_CTL_SETALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_ADDR; | ||
| 100 | break; | ||
| 101 | /* Deselect the address latch */ | ||
| 102 | case NAND_CTL_CLRALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA; | ||
| 103 | break; | ||
| 104 | /* Select the chip -- not used */ | ||
| 105 | case NAND_CTL_SETNCE: | ||
| 106 | break; | ||
| 107 | /* Deselect the chip -- not used */ | ||
| 108 | case NAND_CTL_CLRNCE: | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | |||
| 112 | this->IO_ADDR_R = this->IO_ADDR_W; | ||
| 113 | } | ||
| 114 | |||
| 115 | /* excite_nandflash_devready() | ||
| 116 | * | ||
| 117 | * returns 0 if the nand is busy, 1 if it is ready | ||
| 118 | */ | ||
| 119 | static int excite_nandflash_devready(struct mtd_info *mtd) | ||
| 120 | { | ||
| 121 | struct excite_nandflash_drvdata *drvdata = | ||
| 122 | container_of(mtd, struct excite_nandflash_drvdata, board_mtd); | ||
| 123 | |||
| 124 | return io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); | ||
| 125 | } | ||
| 126 | |||
| 127 | /* device management functions */ | ||
| 128 | |||
| 129 | /* excite_nandflash_remove | ||
| 130 | * | ||
| 131 | * called by device layer to remove the driver | ||
| 132 | * the binding to the mtd and all allocated | ||
| 133 | * resources are released | ||
| 134 | */ | ||
| 135 | static int excite_nandflash_remove(struct device *dev) | ||
| 136 | { | ||
| 137 | struct excite_nandflash_drvdata *this = dev_get_drvdata(dev); | ||
| 138 | |||
| 139 | pr_info(PFX "remove"); | ||
| 140 | |||
| 141 | dev_set_drvdata(dev, NULL); | ||
| 142 | |||
| 143 | if (this == NULL) { | ||
| 144 | pr_debug(PFX "call remove without private data!!"); | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | |||
| 149 | /* free the common resources */ | ||
| 150 | if (this->regs != NULL) { | ||
| 151 | iounmap(this->regs); | ||
| 152 | this->regs = NULL; | ||
| 153 | } | ||
| 154 | |||
| 155 | kfree(this); | ||
| 156 | |||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int elapsed; | ||
| 161 | |||
| 162 | void my_workqueue_handler(void *arg) | ||
| 163 | { | ||
| 164 | elapsed = 1; | ||
| 165 | } | ||
| 166 | |||
| 167 | DECLARE_WORK(sigElapsed, my_workqueue_handler, 0); | ||
| 168 | |||
| 169 | |||
| 170 | /* excite_nandflash_probe | ||
| 171 | * | ||
| 172 | * called by device layer when it finds a device matching | ||
| 173 | * one our driver can handled. This code checks to see if | ||
| 174 | * it can allocate all necessary resources then calls the | ||
| 175 | * nand layer to look for devices | ||
| 176 | */ | ||
| 177 | static int excite_nandflash_probe(struct device *dev) | ||
| 178 | { | ||
| 179 | struct platform_device *pdev = to_platform_device(dev); | ||
| 180 | |||
| 181 | struct excite_nandflash_drvdata *drvdata; /* private driver data */ | ||
| 182 | struct nand_chip *board_chip; /* private flash chip data */ | ||
| 183 | struct mtd_info *board_mtd; /* mtd info for this board */ | ||
| 184 | |||
| 185 | int err = 0; | ||
| 186 | int count = 0; | ||
| 187 | struct timeval tv,endtv; | ||
| 188 | unsigned int dt; | ||
| 189 | |||
| 190 | pr_info(PFX "probe dev: (%p)\n", dev); | ||
| 191 | |||
| 192 | pr_info(PFX "adjust LB timing\n"); | ||
| 193 | ocd_writel(0x00000330, LDP2); | ||
| 194 | |||
| 195 | drvdata = kmalloc(sizeof(*drvdata), GFP_KERNEL); | ||
| 196 | if (unlikely(!drvdata)) { | ||
| 197 | printk(KERN_ERR PFX "no memory for drvdata\n"); | ||
| 198 | err = -ENOMEM; | ||
| 199 | goto mem_error; | ||
| 200 | } | ||
| 201 | |||
| 202 | /* Initialize structures */ | ||
| 203 | memset(drvdata, 0, sizeof(*drvdata)); | ||
| 204 | |||
| 205 | /* bind private data into driver */ | ||
| 206 | dev_set_drvdata(dev, drvdata); | ||
| 207 | |||
| 208 | /* allocate and map the resource */ | ||
| 209 | drvdata->regs = | ||
| 210 | excite_nandflash_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS); | ||
| 211 | |||
| 212 | if (unlikely(!drvdata->regs)) { | ||
| 213 | printk(KERN_ERR PFX "cannot reserve register region\n"); | ||
| 214 | err = -ENXIO; | ||
| 215 | goto io_error; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* initialise our chip */ | ||
| 219 | board_chip = &drvdata->board_chip; | ||
| 220 | |||
| 221 | board_chip->IO_ADDR_R = drvdata->regs + EXCITE_NANDFLASH_DATA; | ||
| 222 | board_chip->IO_ADDR_W = drvdata->regs + EXCITE_NANDFLASH_DATA; | ||
| 223 | |||
| 224 | board_chip->hwcontrol = excite_nandflash_hwcontrol; | ||
| 225 | board_chip->dev_ready = excite_nandflash_devready; | ||
| 226 | |||
| 227 | board_chip->chip_delay = 25; | ||
| 228 | #if 0 | ||
| 229 | /* TODO: speedup the initial scan */ | ||
| 230 | board_chip->options = NAND_USE_FLASH_BBT; | ||
| 231 | #endif | ||
| 232 | board_chip->eccmode = NAND_ECC_SOFT; | ||
| 233 | |||
| 234 | /* link chip to mtd */ | ||
| 235 | board_mtd = &drvdata->board_mtd; | ||
| 236 | board_mtd->priv = board_chip; | ||
| 237 | |||
| 238 | |||
| 239 | pr_info(PFX "FlashTest\n"); | ||
| 240 | elapsed = 0; | ||
| 241 | /* schedule_delayed_work(&sigElapsed, 1*HZ); | ||
| 242 | while (!elapsed) { | ||
| 243 | io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); | ||
| 244 | count++; | ||
| 245 | } | ||
| 246 | pr_info(PFX "reads in 1 sec --> %d\n",count); | ||
| 247 | */ | ||
| 248 | do_gettimeofday(&tv); | ||
| 249 | for (count = 0 ; count < 1000000; count ++) { | ||
| 250 | io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS); | ||
| 251 | } | ||
| 252 | do_gettimeofday(&endtv); | ||
| 253 | dt = (endtv.tv_sec - tv.tv_sec) * 1000000 + endtv.tv_usec - tv.tv_usec; | ||
| 254 | pr_info(PFX "%8d us timeval\n",dt); | ||
| 255 | pr_info(PFX "EndFlashTest\n"); | ||
| 256 | |||
| 257 | /* return with error to unload everything | ||
| 258 | */ | ||
| 259 | io_error: | ||
| 260 | iounmap(drvdata->regs); | ||
| 261 | |||
| 262 | mem_error: | ||
| 263 | kfree(drvdata); | ||
| 264 | |||
| 265 | if (err == 0) | ||
| 266 | err = -EINVAL; | ||
| 267 | return err; | ||
| 268 | } | ||
| 269 | |||
| 270 | static struct device_driver excite_nandflash_driver = { | ||
| 271 | .name = "excite_nand", | ||
| 272 | .bus = &platform_bus_type, | ||
| 273 | .probe = excite_nandflash_probe, | ||
| 274 | .remove = excite_nandflash_remove, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static int __init excite_nandflash_init(void) | ||
| 278 | { | ||
| 279 | pr_info(PFX "register Driver (Rev: $Revision:$)\n"); | ||
| 280 | return driver_register(&excite_nandflash_driver); | ||
| 281 | } | ||
| 282 | |||
| 283 | static void __exit excite_nandflash_exit(void) | ||
| 284 | { | ||
| 285 | driver_unregister(&excite_nandflash_driver); | ||
| 286 | pr_info(PFX "Driver unregistered"); | ||
| 287 | } | ||
| 288 | |||
| 289 | module_init(excite_nandflash_init); | ||
| 290 | module_exit(excite_nandflash_exit); | ||
| 291 | |||
| 292 | MODULE_AUTHOR("Thies Moeller <thies.moeller@baslerweb.com>"); | ||
| 293 | MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver"); | ||
| 294 | MODULE_LICENSE("GPL"); | ||
diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig index d3705284de39..35931bedc3df 100644 --- a/arch/mips/configs/atlas_defconfig +++ b/arch/mips/configs/atlas_defconfig | |||
| @@ -161,6 +161,8 @@ CONFIG_HZ=100 | |||
| 161 | CONFIG_PREEMPT_NONE=y | 161 | CONFIG_PREEMPT_NONE=y |
| 162 | # CONFIG_PREEMPT_VOLUNTARY is not set | 162 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 163 | # CONFIG_PREEMPT is not set | 163 | # CONFIG_PREEMPT is not set |
| 164 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 165 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 164 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 166 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 165 | 167 | ||
| 166 | # | 168 | # |
| @@ -1304,6 +1306,7 @@ CONFIG_NLS_UTF8=m | |||
| 1304 | # | 1306 | # |
| 1305 | # Kernel hacking | 1307 | # Kernel hacking |
| 1306 | # | 1308 | # |
| 1309 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1307 | # CONFIG_PRINTK_TIME is not set | 1310 | # CONFIG_PRINTK_TIME is not set |
| 1308 | # CONFIG_MAGIC_SYSRQ is not set | 1311 | # CONFIG_MAGIC_SYSRQ is not set |
| 1309 | # CONFIG_UNUSED_SYMBOLS is not set | 1312 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index e12a475dcbf4..c6a015940b41 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig | |||
| @@ -167,6 +167,8 @@ CONFIG_PREEMPT_NONE=y | |||
| 167 | # CONFIG_PREEMPT_VOLUNTARY is not set | 167 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 168 | # CONFIG_PREEMPT is not set | 168 | # CONFIG_PREEMPT is not set |
| 169 | # CONFIG_PREEMPT_BKL is not set | 169 | # CONFIG_PREEMPT_BKL is not set |
| 170 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 171 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 170 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 172 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 171 | 173 | ||
| 172 | # | 174 | # |
| @@ -904,6 +906,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 904 | # | 906 | # |
| 905 | # Kernel hacking | 907 | # Kernel hacking |
| 906 | # | 908 | # |
| 909 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 907 | CONFIG_PRINTK_TIME=y | 910 | CONFIG_PRINTK_TIME=y |
| 908 | CONFIG_MAGIC_SYSRQ=y | 911 | CONFIG_MAGIC_SYSRQ=y |
| 909 | # CONFIG_UNUSED_SYMBOLS is not set | 912 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index bfade9abb767..e5358121d2da 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig | |||
| @@ -149,6 +149,8 @@ CONFIG_HZ=1000 | |||
| 149 | CONFIG_PREEMPT_NONE=y | 149 | CONFIG_PREEMPT_NONE=y |
| 150 | # CONFIG_PREEMPT_VOLUNTARY is not set | 150 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 151 | # CONFIG_PREEMPT is not set | 151 | # CONFIG_PREEMPT is not set |
| 152 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 153 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 153 | 155 | ||
| 154 | # | 156 | # |
| @@ -891,6 +893,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 891 | # | 893 | # |
| 892 | # Kernel hacking | 894 | # Kernel hacking |
| 893 | # | 895 | # |
| 896 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 894 | # CONFIG_PRINTK_TIME is not set | 897 | # CONFIG_PRINTK_TIME is not set |
| 895 | # CONFIG_MAGIC_SYSRQ is not set | 898 | # CONFIG_MAGIC_SYSRQ is not set |
| 896 | # CONFIG_UNUSED_SYMBOLS is not set | 899 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig index 4baf2ff1128a..adf1e8c98c65 100644 --- a/arch/mips/configs/cobalt_defconfig +++ b/arch/mips/configs/cobalt_defconfig | |||
| @@ -146,6 +146,8 @@ CONFIG_HZ=1000 | |||
| 146 | CONFIG_PREEMPT_NONE=y | 146 | CONFIG_PREEMPT_NONE=y |
| 147 | # CONFIG_PREEMPT_VOLUNTARY is not set | 147 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 148 | # CONFIG_PREEMPT is not set | 148 | # CONFIG_PREEMPT is not set |
| 149 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 150 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 149 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 150 | 152 | ||
| 151 | # | 153 | # |
| @@ -889,6 +891,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 889 | # | 891 | # |
| 890 | # Kernel hacking | 892 | # Kernel hacking |
| 891 | # | 893 | # |
| 894 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 892 | # CONFIG_PRINTK_TIME is not set | 895 | # CONFIG_PRINTK_TIME is not set |
| 893 | # CONFIG_MAGIC_SYSRQ is not set | 896 | # CONFIG_MAGIC_SYSRQ is not set |
| 894 | # CONFIG_UNUSED_SYMBOLS is not set | 897 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig index 93cca1585bc3..4fd29ffdfb8d 100644 --- a/arch/mips/configs/db1000_defconfig +++ b/arch/mips/configs/db1000_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
| @@ -1006,6 +1008,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1006 | # | 1008 | # |
| 1007 | # Kernel hacking | 1009 | # Kernel hacking |
| 1008 | # | 1010 | # |
| 1011 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1009 | # CONFIG_PRINTK_TIME is not set | 1012 | # CONFIG_PRINTK_TIME is not set |
| 1010 | # CONFIG_MAGIC_SYSRQ is not set | 1013 | # CONFIG_MAGIC_SYSRQ is not set |
| 1011 | # CONFIG_UNUSED_SYMBOLS is not set | 1014 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig index ffd99252a837..025b960ba990 100644 --- a/arch/mips/configs/db1100_defconfig +++ b/arch/mips/configs/db1100_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
| @@ -1006,6 +1008,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1006 | # | 1008 | # |
| 1007 | # Kernel hacking | 1009 | # Kernel hacking |
| 1008 | # | 1010 | # |
| 1011 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1009 | # CONFIG_PRINTK_TIME is not set | 1012 | # CONFIG_PRINTK_TIME is not set |
| 1010 | # CONFIG_MAGIC_SYSRQ is not set | 1013 | # CONFIG_MAGIC_SYSRQ is not set |
| 1011 | # CONFIG_UNUSED_SYMBOLS is not set | 1014 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig index 63eac5e89b9c..80c9dd98f897 100644 --- a/arch/mips/configs/db1200_defconfig +++ b/arch/mips/configs/db1200_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
| @@ -1087,6 +1089,7 @@ CONFIG_NLS_UTF8=m | |||
| 1087 | # | 1089 | # |
| 1088 | # Kernel hacking | 1090 | # Kernel hacking |
| 1089 | # | 1091 | # |
| 1092 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1090 | # CONFIG_PRINTK_TIME is not set | 1093 | # CONFIG_PRINTK_TIME is not set |
| 1091 | # CONFIG_MAGIC_SYSRQ is not set | 1094 | # CONFIG_MAGIC_SYSRQ is not set |
| 1092 | # CONFIG_UNUSED_SYMBOLS is not set | 1095 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig index 25a095f7dc4e..6caa90b0e176 100644 --- a/arch/mips/configs/db1500_defconfig +++ b/arch/mips/configs/db1500_defconfig | |||
| @@ -149,6 +149,8 @@ CONFIG_HZ=1000 | |||
| 149 | CONFIG_PREEMPT_NONE=y | 149 | CONFIG_PREEMPT_NONE=y |
| 150 | # CONFIG_PREEMPT_VOLUNTARY is not set | 150 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 151 | # CONFIG_PREEMPT is not set | 151 | # CONFIG_PREEMPT is not set |
| 152 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 153 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 153 | 155 | ||
| 154 | # | 156 | # |
| @@ -1290,6 +1292,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1290 | # | 1292 | # |
| 1291 | # Kernel hacking | 1293 | # Kernel hacking |
| 1292 | # | 1294 | # |
| 1295 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1293 | # CONFIG_PRINTK_TIME is not set | 1296 | # CONFIG_PRINTK_TIME is not set |
| 1294 | # CONFIG_MAGIC_SYSRQ is not set | 1297 | # CONFIG_MAGIC_SYSRQ is not set |
| 1295 | # CONFIG_UNUSED_SYMBOLS is not set | 1298 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig index dda469c842b3..c6cae86c6ab7 100644 --- a/arch/mips/configs/db1550_defconfig +++ b/arch/mips/configs/db1550_defconfig | |||
| @@ -148,6 +148,8 @@ CONFIG_HZ=1000 | |||
| 148 | CONFIG_PREEMPT_NONE=y | 148 | CONFIG_PREEMPT_NONE=y |
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | # CONFIG_PREEMPT is not set | 150 | # CONFIG_PREEMPT is not set |
| 151 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 152 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 152 | 154 | ||
| 153 | # | 155 | # |
| @@ -1111,6 +1113,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1111 | # | 1113 | # |
| 1112 | # Kernel hacking | 1114 | # Kernel hacking |
| 1113 | # | 1115 | # |
| 1116 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1114 | # CONFIG_PRINTK_TIME is not set | 1117 | # CONFIG_PRINTK_TIME is not set |
| 1115 | # CONFIG_MAGIC_SYSRQ is not set | 1118 | # CONFIG_MAGIC_SYSRQ is not set |
| 1116 | # CONFIG_UNUSED_SYMBOLS is not set | 1119 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig index fcd3dd19bc74..72f24001c99e 100644 --- a/arch/mips/configs/ddb5477_defconfig +++ b/arch/mips/configs/ddb5477_defconfig | |||
| @@ -146,6 +146,8 @@ CONFIG_HZ=1000 | |||
| 146 | CONFIG_PREEMPT_NONE=y | 146 | CONFIG_PREEMPT_NONE=y |
| 147 | # CONFIG_PREEMPT_VOLUNTARY is not set | 147 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 148 | # CONFIG_PREEMPT is not set | 148 | # CONFIG_PREEMPT is not set |
| 149 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 150 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 149 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 150 | 152 | ||
| 151 | # | 153 | # |
| @@ -852,6 +854,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 852 | # | 854 | # |
| 853 | # Kernel hacking | 855 | # Kernel hacking |
| 854 | # | 856 | # |
| 857 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 855 | # CONFIG_PRINTK_TIME is not set | 858 | # CONFIG_PRINTK_TIME is not set |
| 856 | # CONFIG_MAGIC_SYSRQ is not set | 859 | # CONFIG_MAGIC_SYSRQ is not set |
| 857 | # CONFIG_UNUSED_SYMBOLS is not set | 860 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig index 8683e0df12e0..be901df7fefa 100644 --- a/arch/mips/configs/decstation_defconfig +++ b/arch/mips/configs/decstation_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=128 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
| @@ -828,6 +830,7 @@ CONFIG_ULTRIX_PARTITION=y | |||
| 828 | # | 830 | # |
| 829 | # Kernel hacking | 831 | # Kernel hacking |
| 830 | # | 832 | # |
| 833 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 831 | # CONFIG_PRINTK_TIME is not set | 834 | # CONFIG_PRINTK_TIME is not set |
| 832 | CONFIG_MAGIC_SYSRQ=y | 835 | CONFIG_MAGIC_SYSRQ=y |
| 833 | # CONFIG_UNUSED_SYMBOLS is not set | 836 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index 4ace61c95778..6133c28beb8c 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig index 5847c916c130..a484b7d396fc 100644 --- a/arch/mips/configs/emma2rh_defconfig +++ b/arch/mips/configs/emma2rh_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | # CONFIG_PREEMPT_VOLUNTARY is not set | 147 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 148 | CONFIG_PREEMPT=y | 148 | CONFIG_PREEMPT=y |
| 149 | CONFIG_PREEMPT_BKL=y | 149 | CONFIG_PREEMPT_BKL=y |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
| @@ -1180,6 +1182,7 @@ CONFIG_NLS_UTF8=m | |||
| 1180 | # | 1182 | # |
| 1181 | # Kernel hacking | 1183 | # Kernel hacking |
| 1182 | # | 1184 | # |
| 1185 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1183 | # CONFIG_PRINTK_TIME is not set | 1186 | # CONFIG_PRINTK_TIME is not set |
| 1184 | # CONFIG_MAGIC_SYSRQ is not set | 1187 | # CONFIG_MAGIC_SYSRQ is not set |
| 1185 | # CONFIG_UNUSED_SYMBOLS is not set | 1188 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig index bc4c4f125c48..21bfcdebf8f5 100644 --- a/arch/mips/configs/ev64120_defconfig +++ b/arch/mips/configs/ev64120_defconfig | |||
| @@ -148,6 +148,8 @@ CONFIG_HZ=1000 | |||
| 148 | CONFIG_PREEMPT_NONE=y | 148 | CONFIG_PREEMPT_NONE=y |
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | # CONFIG_PREEMPT is not set | 150 | # CONFIG_PREEMPT is not set |
| 151 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 152 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 152 | 154 | ||
| 153 | # | 155 | # |
| @@ -842,6 +844,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 842 | # | 844 | # |
| 843 | # Kernel hacking | 845 | # Kernel hacking |
| 844 | # | 846 | # |
| 847 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 845 | # CONFIG_PRINTK_TIME is not set | 848 | # CONFIG_PRINTK_TIME is not set |
| 846 | # CONFIG_MAGIC_SYSRQ is not set | 849 | # CONFIG_MAGIC_SYSRQ is not set |
| 847 | # CONFIG_UNUSED_SYMBOLS is not set | 850 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig index eb87cbbfd037..1a5b06cfb4d6 100644 --- a/arch/mips/configs/excite_defconfig +++ b/arch/mips/configs/excite_defconfig | |||
| @@ -149,6 +149,8 @@ CONFIG_HZ=1000 | |||
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | CONFIG_PREEMPT=y | 150 | CONFIG_PREEMPT=y |
| 151 | CONFIG_PREEMPT_BKL=y | 151 | CONFIG_PREEMPT_BKL=y |
| 152 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 153 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 153 | 155 | ||
| 154 | # | 156 | # |
| @@ -1184,6 +1186,7 @@ CONFIG_NLS_ISO8859_1=m | |||
| 1184 | # | 1186 | # |
| 1185 | # Kernel hacking | 1187 | # Kernel hacking |
| 1186 | # | 1188 | # |
| 1189 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1187 | # CONFIG_PRINTK_TIME is not set | 1190 | # CONFIG_PRINTK_TIME is not set |
| 1188 | # CONFIG_MAGIC_SYSRQ is not set | 1191 | # CONFIG_MAGIC_SYSRQ is not set |
| 1189 | # CONFIG_UNUSED_SYMBOLS is not set | 1192 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index cc9b24eda9e8..21d53e0c9ee8 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | # CONFIG_PREEMPT_NONE is not set | 153 | # CONFIG_PREEMPT_NONE is not set |
| 154 | CONFIG_PREEMPT_VOLUNTARY=y | 154 | CONFIG_PREEMPT_VOLUNTARY=y |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -1147,6 +1149,7 @@ CONFIG_NLS_UTF8=m | |||
| 1147 | # | 1149 | # |
| 1148 | # Kernel hacking | 1150 | # Kernel hacking |
| 1149 | # | 1151 | # |
| 1152 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1150 | # CONFIG_PRINTK_TIME is not set | 1153 | # CONFIG_PRINTK_TIME is not set |
| 1151 | # CONFIG_MAGIC_SYSRQ is not set | 1154 | # CONFIG_MAGIC_SYSRQ is not set |
| 1152 | # CONFIG_UNUSED_SYMBOLS is not set | 1155 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 50092ba8aa71..e3e94c7e5ee1 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig | |||
| @@ -162,6 +162,8 @@ CONFIG_PREEMPT_NONE=y | |||
| 162 | # CONFIG_PREEMPT is not set | 162 | # CONFIG_PREEMPT is not set |
| 163 | CONFIG_PREEMPT_BKL=y | 163 | CONFIG_PREEMPT_BKL=y |
| 164 | # CONFIG_MIPS_INSANE_LARGE is not set | 164 | # CONFIG_MIPS_INSANE_LARGE is not set |
| 165 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 166 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 165 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 167 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 166 | 168 | ||
| 167 | # | 169 | # |
| @@ -980,6 +982,7 @@ CONFIG_SGI_PARTITION=y | |||
| 980 | # | 982 | # |
| 981 | # Kernel hacking | 983 | # Kernel hacking |
| 982 | # | 984 | # |
| 985 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 983 | # CONFIG_PRINTK_TIME is not set | 986 | # CONFIG_PRINTK_TIME is not set |
| 984 | # CONFIG_MAGIC_SYSRQ is not set | 987 | # CONFIG_MAGIC_SYSRQ is not set |
| 985 | # CONFIG_UNUSED_SYMBOLS is not set | 988 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig index dec2ba6ba03f..b4ab2bea9723 100644 --- a/arch/mips/configs/ip32_defconfig +++ b/arch/mips/configs/ip32_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | # CONFIG_PREEMPT_NONE is not set | 153 | # CONFIG_PREEMPT_NONE is not set |
| 154 | CONFIG_PREEMPT_VOLUNTARY=y | 154 | CONFIG_PREEMPT_VOLUNTARY=y |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -922,6 +924,7 @@ CONFIG_SGI_PARTITION=y | |||
| 922 | # | 924 | # |
| 923 | # Kernel hacking | 925 | # Kernel hacking |
| 924 | # | 926 | # |
| 927 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 925 | # CONFIG_PRINTK_TIME is not set | 928 | # CONFIG_PRINTK_TIME is not set |
| 926 | # CONFIG_MAGIC_SYSRQ is not set | 929 | # CONFIG_MAGIC_SYSRQ is not set |
| 927 | # CONFIG_UNUSED_SYMBOLS is not set | 930 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig index 37f9dd7187b1..18d20fb7d5f0 100644 --- a/arch/mips/configs/it8172_defconfig +++ b/arch/mips/configs/it8172_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
| @@ -900,6 +902,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 900 | # | 902 | # |
| 901 | # Kernel hacking | 903 | # Kernel hacking |
| 902 | # | 904 | # |
| 905 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 903 | # CONFIG_PRINTK_TIME is not set | 906 | # CONFIG_PRINTK_TIME is not set |
| 904 | # CONFIG_MAGIC_SYSRQ is not set | 907 | # CONFIG_MAGIC_SYSRQ is not set |
| 905 | # CONFIG_UNUSED_SYMBOLS is not set | 908 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig index 18874a4c24fe..99831d0bf76b 100644 --- a/arch/mips/configs/ivr_defconfig +++ b/arch/mips/configs/ivr_defconfig | |||
| @@ -144,6 +144,8 @@ CONFIG_HZ=1000 | |||
| 144 | CONFIG_PREEMPT_NONE=y | 144 | CONFIG_PREEMPT_NONE=y |
| 145 | # CONFIG_PREEMPT_VOLUNTARY is not set | 145 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 146 | # CONFIG_PREEMPT is not set | 146 | # CONFIG_PREEMPT is not set |
| 147 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 148 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 147 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 149 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 148 | 150 | ||
| 149 | # | 151 | # |
| @@ -856,6 +858,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 856 | # | 858 | # |
| 857 | # Kernel hacking | 859 | # Kernel hacking |
| 858 | # | 860 | # |
| 861 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 859 | # CONFIG_PRINTK_TIME is not set | 862 | # CONFIG_PRINTK_TIME is not set |
| 860 | # CONFIG_MAGIC_SYSRQ is not set | 863 | # CONFIG_MAGIC_SYSRQ is not set |
| 861 | # CONFIG_UNUSED_SYMBOLS is not set | 864 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig index 9f1e3048d623..9d4d17ace123 100644 --- a/arch/mips/configs/jaguar-atx_defconfig +++ b/arch/mips/configs/jaguar-atx_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | CONFIG_PREEMPT_NONE=y | 153 | CONFIG_PREEMPT_NONE=y |
| 154 | # CONFIG_PREEMPT_VOLUNTARY is not set | 154 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -775,6 +777,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 775 | # | 777 | # |
| 776 | # Kernel hacking | 778 | # Kernel hacking |
| 777 | # | 779 | # |
| 780 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 778 | # CONFIG_PRINTK_TIME is not set | 781 | # CONFIG_PRINTK_TIME is not set |
| 779 | # CONFIG_MAGIC_SYSRQ is not set | 782 | # CONFIG_MAGIC_SYSRQ is not set |
| 780 | # CONFIG_UNUSED_SYMBOLS is not set | 783 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig index fded3f73815f..d03746667a96 100644 --- a/arch/mips/configs/jmr3927_defconfig +++ b/arch/mips/configs/jmr3927_defconfig | |||
| @@ -143,6 +143,8 @@ CONFIG_PREEMPT_NONE=y | |||
| 143 | # CONFIG_PREEMPT_VOLUNTARY is not set | 143 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 144 | # CONFIG_PREEMPT is not set | 144 | # CONFIG_PREEMPT is not set |
| 145 | CONFIG_RTC_DS1742=y | 145 | CONFIG_RTC_DS1742=y |
| 146 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 147 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 146 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 148 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 147 | 149 | ||
| 148 | # | 150 | # |
| @@ -872,6 +874,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 872 | # | 874 | # |
| 873 | # Kernel hacking | 875 | # Kernel hacking |
| 874 | # | 876 | # |
| 877 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 875 | # CONFIG_PRINTK_TIME is not set | 878 | # CONFIG_PRINTK_TIME is not set |
| 876 | # CONFIG_MAGIC_SYSRQ is not set | 879 | # CONFIG_MAGIC_SYSRQ is not set |
| 877 | # CONFIG_UNUSED_SYMBOLS is not set | 880 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig index 320b8cdd6e58..1db8249b4c0f 100644 --- a/arch/mips/configs/lasat200_defconfig +++ b/arch/mips/configs/lasat200_defconfig | |||
| @@ -151,6 +151,8 @@ CONFIG_HZ=1000 | |||
| 151 | CONFIG_PREEMPT_NONE=y | 151 | CONFIG_PREEMPT_NONE=y |
| 152 | # CONFIG_PREEMPT_VOLUNTARY is not set | 152 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 153 | # CONFIG_PREEMPT is not set | 153 | # CONFIG_PREEMPT is not set |
| 154 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 155 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 155 | 157 | ||
| 156 | # | 158 | # |
| @@ -970,6 +972,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 970 | # | 972 | # |
| 971 | # Kernel hacking | 973 | # Kernel hacking |
| 972 | # | 974 | # |
| 975 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 973 | # CONFIG_PRINTK_TIME is not set | 976 | # CONFIG_PRINTK_TIME is not set |
| 974 | # CONFIG_MAGIC_SYSRQ is not set | 977 | # CONFIG_MAGIC_SYSRQ is not set |
| 975 | # CONFIG_UNUSED_SYMBOLS is not set | 978 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 0ba1ef5048fb..aeefe2873e38 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig | |||
| @@ -170,6 +170,8 @@ CONFIG_HZ=100 | |||
| 170 | CONFIG_PREEMPT_NONE=y | 170 | CONFIG_PREEMPT_NONE=y |
| 171 | # CONFIG_PREEMPT_VOLUNTARY is not set | 171 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 172 | # CONFIG_PREEMPT is not set | 172 | # CONFIG_PREEMPT is not set |
| 173 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 174 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 173 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 175 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 174 | 176 | ||
| 175 | # | 177 | # |
| @@ -1341,6 +1343,7 @@ CONFIG_NLS_UTF8=m | |||
| 1341 | # | 1343 | # |
| 1342 | # Kernel hacking | 1344 | # Kernel hacking |
| 1343 | # | 1345 | # |
| 1346 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1344 | # CONFIG_PRINTK_TIME is not set | 1347 | # CONFIG_PRINTK_TIME is not set |
| 1345 | # CONFIG_MAGIC_SYSRQ is not set | 1348 | # CONFIG_MAGIC_SYSRQ is not set |
| 1346 | # CONFIG_UNUSED_SYMBOLS is not set | 1349 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig index adbeeadddb8f..a3cbd23bf217 100644 --- a/arch/mips/configs/mipssim_defconfig +++ b/arch/mips/configs/mipssim_defconfig | |||
| @@ -148,6 +148,8 @@ CONFIG_HZ=1000 | |||
| 148 | CONFIG_PREEMPT_NONE=y | 148 | CONFIG_PREEMPT_NONE=y |
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | # CONFIG_PREEMPT is not set | 150 | # CONFIG_PREEMPT is not set |
| 151 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 152 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 152 | 154 | ||
| 153 | # | 155 | # |
| @@ -799,6 +801,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 799 | # | 801 | # |
| 800 | # Kernel hacking | 802 | # Kernel hacking |
| 801 | # | 803 | # |
| 804 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 802 | # CONFIG_PRINTK_TIME is not set | 805 | # CONFIG_PRINTK_TIME is not set |
| 803 | # CONFIG_MAGIC_SYSRQ is not set | 806 | # CONFIG_MAGIC_SYSRQ is not set |
| 804 | # CONFIG_UNUSED_SYMBOLS is not set | 807 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index 79fd544fcb2a..6570b47426ce 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig | |||
| @@ -148,6 +148,8 @@ CONFIG_HZ=1000 | |||
| 148 | CONFIG_PREEMPT_NONE=y | 148 | CONFIG_PREEMPT_NONE=y |
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | # CONFIG_PREEMPT is not set | 150 | # CONFIG_PREEMPT is not set |
| 151 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 152 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 152 | 154 | ||
| 153 | # | 155 | # |
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig index 4d87da2b99fd..440d65f93a94 100644 --- a/arch/mips/configs/ocelot_3_defconfig +++ b/arch/mips/configs/ocelot_3_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | CONFIG_PREEMPT_NONE=y | 153 | CONFIG_PREEMPT_NONE=y |
| 154 | # CONFIG_PREEMPT_VOLUNTARY is not set | 154 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -1091,6 +1093,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1091 | # | 1093 | # |
| 1092 | # Kernel hacking | 1094 | # Kernel hacking |
| 1093 | # | 1095 | # |
| 1096 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1094 | # CONFIG_PRINTK_TIME is not set | 1097 | # CONFIG_PRINTK_TIME is not set |
| 1095 | # CONFIG_MAGIC_SYSRQ is not set | 1098 | # CONFIG_MAGIC_SYSRQ is not set |
| 1096 | # CONFIG_UNUSED_SYMBOLS is not set | 1099 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig index a7ac2b0a8273..c2c7ae77da3e 100644 --- a/arch/mips/configs/ocelot_c_defconfig +++ b/arch/mips/configs/ocelot_c_defconfig | |||
| @@ -150,6 +150,8 @@ CONFIG_HZ=1000 | |||
| 150 | CONFIG_PREEMPT_NONE=y | 150 | CONFIG_PREEMPT_NONE=y |
| 151 | # CONFIG_PREEMPT_VOLUNTARY is not set | 151 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 152 | # CONFIG_PREEMPT is not set | 152 | # CONFIG_PREEMPT is not set |
| 153 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 154 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 155 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 154 | 156 | ||
| 155 | # | 157 | # |
| @@ -839,6 +841,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 839 | # | 841 | # |
| 840 | # Kernel hacking | 842 | # Kernel hacking |
| 841 | # | 843 | # |
| 844 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 842 | # CONFIG_PRINTK_TIME is not set | 845 | # CONFIG_PRINTK_TIME is not set |
| 843 | # CONFIG_MAGIC_SYSRQ is not set | 846 | # CONFIG_MAGIC_SYSRQ is not set |
| 844 | # CONFIG_UNUSED_SYMBOLS is not set | 847 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig index 853e7bba5122..67efe270e0cc 100644 --- a/arch/mips/configs/ocelot_defconfig +++ b/arch/mips/configs/ocelot_defconfig | |||
| @@ -154,6 +154,8 @@ CONFIG_HZ=1000 | |||
| 154 | CONFIG_PREEMPT_NONE=y | 154 | CONFIG_PREEMPT_NONE=y |
| 155 | # CONFIG_PREEMPT_VOLUNTARY is not set | 155 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 156 | # CONFIG_PREEMPT is not set | 156 | # CONFIG_PREEMPT is not set |
| 157 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 158 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 157 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 159 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 158 | 160 | ||
| 159 | # | 161 | # |
| @@ -788,6 +790,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 788 | # | 790 | # |
| 789 | # Kernel hacking | 791 | # Kernel hacking |
| 790 | # | 792 | # |
| 793 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 791 | # CONFIG_PRINTK_TIME is not set | 794 | # CONFIG_PRINTK_TIME is not set |
| 792 | # CONFIG_MAGIC_SYSRQ is not set | 795 | # CONFIG_MAGIC_SYSRQ is not set |
| 793 | # CONFIG_UNUSED_SYMBOLS is not set | 796 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig index 8524efa23a49..a10f34de5f7e 100644 --- a/arch/mips/configs/ocelot_g_defconfig +++ b/arch/mips/configs/ocelot_g_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | CONFIG_PREEMPT_NONE=y | 153 | CONFIG_PREEMPT_NONE=y |
| 154 | # CONFIG_PREEMPT_VOLUNTARY is not set | 154 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -842,6 +844,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 842 | # | 844 | # |
| 843 | # Kernel hacking | 845 | # Kernel hacking |
| 844 | # | 846 | # |
| 847 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 845 | # CONFIG_PRINTK_TIME is not set | 848 | # CONFIG_PRINTK_TIME is not set |
| 846 | # CONFIG_MAGIC_SYSRQ is not set | 849 | # CONFIG_MAGIC_SYSRQ is not set |
| 847 | # CONFIG_UNUSED_SYMBOLS is not set | 850 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig index 1a16e92900cb..741f8258075c 100644 --- a/arch/mips/configs/pb1100_defconfig +++ b/arch/mips/configs/pb1100_defconfig | |||
| @@ -149,6 +149,8 @@ CONFIG_HZ=1000 | |||
| 149 | CONFIG_PREEMPT_NONE=y | 149 | CONFIG_PREEMPT_NONE=y |
| 150 | # CONFIG_PREEMPT_VOLUNTARY is not set | 150 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 151 | # CONFIG_PREEMPT is not set | 151 | # CONFIG_PREEMPT is not set |
| 152 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 153 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 153 | 155 | ||
| 154 | # | 156 | # |
| @@ -1000,6 +1002,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1000 | # | 1002 | # |
| 1001 | # Kernel hacking | 1003 | # Kernel hacking |
| 1002 | # | 1004 | # |
| 1005 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1003 | # CONFIG_PRINTK_TIME is not set | 1006 | # CONFIG_PRINTK_TIME is not set |
| 1004 | # CONFIG_MAGIC_SYSRQ is not set | 1007 | # CONFIG_MAGIC_SYSRQ is not set |
| 1005 | # CONFIG_UNUSED_SYMBOLS is not set | 1008 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig index 9ea8edea6f29..8576340714da 100644 --- a/arch/mips/configs/pb1500_defconfig +++ b/arch/mips/configs/pb1500_defconfig | |||
| @@ -148,6 +148,8 @@ CONFIG_HZ=1000 | |||
| 148 | CONFIG_PREEMPT_NONE=y | 148 | CONFIG_PREEMPT_NONE=y |
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | # CONFIG_PREEMPT is not set | 150 | # CONFIG_PREEMPT is not set |
| 151 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 152 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 152 | 154 | ||
| 153 | # | 155 | # |
| @@ -1106,6 +1108,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1106 | # | 1108 | # |
| 1107 | # Kernel hacking | 1109 | # Kernel hacking |
| 1108 | # | 1110 | # |
| 1111 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1109 | # CONFIG_PRINTK_TIME is not set | 1112 | # CONFIG_PRINTK_TIME is not set |
| 1110 | # CONFIG_MAGIC_SYSRQ is not set | 1113 | # CONFIG_MAGIC_SYSRQ is not set |
| 1111 | # CONFIG_UNUSED_SYMBOLS is not set | 1114 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig index c4a158976f8f..3db7427d1b55 100644 --- a/arch/mips/configs/pb1550_defconfig +++ b/arch/mips/configs/pb1550_defconfig | |||
| @@ -148,6 +148,8 @@ CONFIG_HZ=1000 | |||
| 148 | CONFIG_PREEMPT_NONE=y | 148 | CONFIG_PREEMPT_NONE=y |
| 149 | # CONFIG_PREEMPT_VOLUNTARY is not set | 149 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 150 | # CONFIG_PREEMPT is not set | 150 | # CONFIG_PREEMPT is not set |
| 151 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 152 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 151 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 153 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 152 | 154 | ||
| 153 | # | 155 | # |
| @@ -1098,6 +1100,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1098 | # | 1100 | # |
| 1099 | # Kernel hacking | 1101 | # Kernel hacking |
| 1100 | # | 1102 | # |
| 1103 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1101 | # CONFIG_PRINTK_TIME is not set | 1104 | # CONFIG_PRINTK_TIME is not set |
| 1102 | # CONFIG_MAGIC_SYSRQ is not set | 1105 | # CONFIG_MAGIC_SYSRQ is not set |
| 1103 | # CONFIG_UNUSED_SYMBOLS is not set | 1106 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 1cbf270c301c..26b0b9883496 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | CONFIG_PREEMPT_NONE=y | 153 | CONFIG_PREEMPT_NONE=y |
| 154 | # CONFIG_PREEMPT_VOLUNTARY is not set | 154 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -876,6 +878,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 876 | # | 878 | # |
| 877 | # Kernel hacking | 879 | # Kernel hacking |
| 878 | # | 880 | # |
| 881 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 879 | # CONFIG_PRINTK_TIME is not set | 882 | # CONFIG_PRINTK_TIME is not set |
| 880 | CONFIG_MAGIC_SYSRQ=y | 883 | CONFIG_MAGIC_SYSRQ=y |
| 881 | # CONFIG_UNUSED_SYMBOLS is not set | 884 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index bec30b15b9bd..e93266b37dd9 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | CONFIG_PREEMPT_NONE=y | 153 | CONFIG_PREEMPT_NONE=y |
| 154 | # CONFIG_PREEMPT_VOLUNTARY is not set | 154 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -1057,6 +1059,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1057 | # | 1059 | # |
| 1058 | # Kernel hacking | 1060 | # Kernel hacking |
| 1059 | # | 1061 | # |
| 1062 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1060 | # CONFIG_PRINTK_TIME is not set | 1063 | # CONFIG_PRINTK_TIME is not set |
| 1061 | # CONFIG_MAGIC_SYSRQ is not set | 1064 | # CONFIG_MAGIC_SYSRQ is not set |
| 1062 | # CONFIG_UNUSED_SYMBOLS is not set | 1065 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig index f5f799e93707..9b0dab822bd0 100644 --- a/arch/mips/configs/qemu_defconfig +++ b/arch/mips/configs/qemu_defconfig | |||
| @@ -145,6 +145,8 @@ CONFIG_HZ=100 | |||
| 145 | CONFIG_PREEMPT_NONE=y | 145 | CONFIG_PREEMPT_NONE=y |
| 146 | # CONFIG_PREEMPT_VOLUNTARY is not set | 146 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 147 | # CONFIG_PREEMPT is not set | 147 | # CONFIG_PREEMPT is not set |
| 148 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 149 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 148 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 149 | 151 | ||
| 150 | # | 152 | # |
| @@ -733,6 +735,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 733 | # | 735 | # |
| 734 | # Kernel hacking | 736 | # Kernel hacking |
| 735 | # | 737 | # |
| 738 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 736 | # CONFIG_PRINTK_TIME is not set | 739 | # CONFIG_PRINTK_TIME is not set |
| 737 | # CONFIG_MAGIC_SYSRQ is not set | 740 | # CONFIG_MAGIC_SYSRQ is not set |
| 738 | # CONFIG_UNUSED_SYMBOLS is not set | 741 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig index 2f5650227ba3..dd0296036026 100644 --- a/arch/mips/configs/rbhma4500_defconfig +++ b/arch/mips/configs/rbhma4500_defconfig | |||
| @@ -155,6 +155,8 @@ CONFIG_HZ=1000 | |||
| 155 | CONFIG_PREEMPT_NONE=y | 155 | CONFIG_PREEMPT_NONE=y |
| 156 | # CONFIG_PREEMPT_VOLUNTARY is not set | 156 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 157 | # CONFIG_PREEMPT is not set | 157 | # CONFIG_PREEMPT is not set |
| 158 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 159 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 160 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 159 | 161 | ||
| 160 | # | 162 | # |
| @@ -1335,6 +1337,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" | |||
| 1335 | # | 1337 | # |
| 1336 | # Kernel hacking | 1338 | # Kernel hacking |
| 1337 | # | 1339 | # |
| 1340 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1338 | # CONFIG_PRINTK_TIME is not set | 1341 | # CONFIG_PRINTK_TIME is not set |
| 1339 | # CONFIG_MAGIC_SYSRQ is not set | 1342 | # CONFIG_MAGIC_SYSRQ is not set |
| 1340 | # CONFIG_UNUSED_SYMBOLS is not set | 1343 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index 4fee90b2b100..d8a498d64d62 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig | |||
| @@ -158,6 +158,8 @@ CONFIG_HZ=1000 | |||
| 158 | # CONFIG_PREEMPT_NONE is not set | 158 | # CONFIG_PREEMPT_NONE is not set |
| 159 | CONFIG_PREEMPT_VOLUNTARY=y | 159 | CONFIG_PREEMPT_VOLUNTARY=y |
| 160 | # CONFIG_PREEMPT is not set | 160 | # CONFIG_PREEMPT is not set |
| 161 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 162 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 161 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 163 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 162 | 164 | ||
| 163 | # | 165 | # |
| @@ -1584,6 +1586,7 @@ CONFIG_NLS_UTF8=m | |||
| 1584 | # | 1586 | # |
| 1585 | # Kernel hacking | 1587 | # Kernel hacking |
| 1586 | # | 1588 | # |
| 1589 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1587 | # CONFIG_PRINTK_TIME is not set | 1590 | # CONFIG_PRINTK_TIME is not set |
| 1588 | # CONFIG_MAGIC_SYSRQ is not set | 1591 | # CONFIG_MAGIC_SYSRQ is not set |
| 1589 | # CONFIG_UNUSED_SYMBOLS is not set | 1592 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig index 9041f095f96f..805a4fe450f5 100644 --- a/arch/mips/configs/sb1250-swarm_defconfig +++ b/arch/mips/configs/sb1250-swarm_defconfig | |||
| @@ -171,6 +171,8 @@ CONFIG_PREEMPT_NONE=y | |||
| 171 | # CONFIG_PREEMPT_VOLUNTARY is not set | 171 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 172 | # CONFIG_PREEMPT is not set | 172 | # CONFIG_PREEMPT is not set |
| 173 | CONFIG_PREEMPT_BKL=y | 173 | CONFIG_PREEMPT_BKL=y |
| 174 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 175 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 174 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 176 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 175 | 177 | ||
| 176 | # | 178 | # |
| @@ -873,6 +875,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 873 | # | 875 | # |
| 874 | # Kernel hacking | 876 | # Kernel hacking |
| 875 | # | 877 | # |
| 878 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 876 | # CONFIG_PRINTK_TIME is not set | 879 | # CONFIG_PRINTK_TIME is not set |
| 877 | # CONFIG_MAGIC_SYSRQ is not set | 880 | # CONFIG_MAGIC_SYSRQ is not set |
| 878 | # CONFIG_UNUSED_SYMBOLS is not set | 881 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig index 02abb2f1bfaf..6fcb656d8d87 100644 --- a/arch/mips/configs/sead_defconfig +++ b/arch/mips/configs/sead_defconfig | |||
| @@ -151,6 +151,8 @@ CONFIG_HZ=1000 | |||
| 151 | CONFIG_PREEMPT_NONE=y | 151 | CONFIG_PREEMPT_NONE=y |
| 152 | # CONFIG_PREEMPT_VOLUNTARY is not set | 152 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 153 | # CONFIG_PREEMPT is not set | 153 | # CONFIG_PREEMPT is not set |
| 154 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 155 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 155 | 157 | ||
| 156 | # | 158 | # |
| @@ -581,6 +583,7 @@ CONFIG_PARTITION_ADVANCED=y | |||
| 581 | # | 583 | # |
| 582 | # Kernel hacking | 584 | # Kernel hacking |
| 583 | # | 585 | # |
| 586 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 584 | # CONFIG_PRINTK_TIME is not set | 587 | # CONFIG_PRINTK_TIME is not set |
| 585 | # CONFIG_MAGIC_SYSRQ is not set | 588 | # CONFIG_MAGIC_SYSRQ is not set |
| 586 | # CONFIG_UNUSED_SYMBOLS is not set | 589 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig index ca3d0c4ba15b..dc312f19ada7 100644 --- a/arch/mips/configs/tb0226_defconfig +++ b/arch/mips/configs/tb0226_defconfig | |||
| @@ -151,6 +151,8 @@ CONFIG_HZ=1000 | |||
| 151 | CONFIG_PREEMPT_NONE=y | 151 | CONFIG_PREEMPT_NONE=y |
| 152 | # CONFIG_PREEMPT_VOLUNTARY is not set | 152 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 153 | # CONFIG_PREEMPT is not set | 153 | # CONFIG_PREEMPT is not set |
| 154 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 155 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 155 | 157 | ||
| 156 | # | 158 | # |
| @@ -1059,6 +1061,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 1059 | # | 1061 | # |
| 1060 | # Kernel hacking | 1062 | # Kernel hacking |
| 1061 | # | 1063 | # |
| 1064 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1062 | # CONFIG_PRINTK_TIME is not set | 1065 | # CONFIG_PRINTK_TIME is not set |
| 1063 | # CONFIG_MAGIC_SYSRQ is not set | 1066 | # CONFIG_MAGIC_SYSRQ is not set |
| 1064 | # CONFIG_UNUSED_SYMBOLS is not set | 1067 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig index 4e2009ace278..85615d99b01a 100644 --- a/arch/mips/configs/tb0229_defconfig +++ b/arch/mips/configs/tb0229_defconfig | |||
| @@ -151,6 +151,8 @@ CONFIG_HZ=1000 | |||
| 151 | CONFIG_PREEMPT_NONE=y | 151 | CONFIG_PREEMPT_NONE=y |
| 152 | # CONFIG_PREEMPT_VOLUNTARY is not set | 152 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 153 | # CONFIG_PREEMPT is not set | 153 | # CONFIG_PREEMPT is not set |
| 154 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 155 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 155 | 157 | ||
| 156 | # | 158 | # |
| @@ -968,6 +970,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 968 | # | 970 | # |
| 969 | # Kernel hacking | 971 | # Kernel hacking |
| 970 | # | 972 | # |
| 973 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 971 | # CONFIG_PRINTK_TIME is not set | 974 | # CONFIG_PRINTK_TIME is not set |
| 972 | # CONFIG_MAGIC_SYSRQ is not set | 975 | # CONFIG_MAGIC_SYSRQ is not set |
| 973 | # CONFIG_UNUSED_SYMBOLS is not set | 976 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig index 535a813d01a9..ad7271b3f266 100644 --- a/arch/mips/configs/tb0287_defconfig +++ b/arch/mips/configs/tb0287_defconfig | |||
| @@ -151,6 +151,8 @@ CONFIG_HZ=1000 | |||
| 151 | CONFIG_PREEMPT_NONE=y | 151 | CONFIG_PREEMPT_NONE=y |
| 152 | # CONFIG_PREEMPT_VOLUNTARY is not set | 152 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 153 | # CONFIG_PREEMPT is not set | 153 | # CONFIG_PREEMPT is not set |
| 154 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 155 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 154 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 155 | 157 | ||
| 156 | # | 158 | # |
| @@ -1146,6 +1148,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 1146 | # | 1148 | # |
| 1147 | # Kernel hacking | 1149 | # Kernel hacking |
| 1148 | # | 1150 | # |
| 1151 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1149 | # CONFIG_PRINTK_TIME is not set | 1152 | # CONFIG_PRINTK_TIME is not set |
| 1150 | # CONFIG_MAGIC_SYSRQ is not set | 1153 | # CONFIG_MAGIC_SYSRQ is not set |
| 1151 | # CONFIG_UNUSED_SYMBOLS is not set | 1154 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig index 3a3ef20b21cc..863f6a7cadfd 100644 --- a/arch/mips/configs/workpad_defconfig +++ b/arch/mips/configs/workpad_defconfig | |||
| @@ -147,6 +147,8 @@ CONFIG_HZ=1000 | |||
| 147 | CONFIG_PREEMPT_NONE=y | 147 | CONFIG_PREEMPT_NONE=y |
| 148 | # CONFIG_PREEMPT_VOLUNTARY is not set | 148 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 149 | # CONFIG_PREEMPT is not set | 149 | # CONFIG_PREEMPT is not set |
| 150 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 151 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 150 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 152 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 151 | 153 | ||
| 152 | # | 154 | # |
diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig index e6b1dea55842..c10267d61cc9 100644 --- a/arch/mips/configs/wrppmc_defconfig +++ b/arch/mips/configs/wrppmc_defconfig | |||
| @@ -155,6 +155,8 @@ CONFIG_HZ=1000 | |||
| 155 | CONFIG_PREEMPT_NONE=y | 155 | CONFIG_PREEMPT_NONE=y |
| 156 | # CONFIG_PREEMPT_VOLUNTARY is not set | 156 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 157 | # CONFIG_PREEMPT is not set | 157 | # CONFIG_PREEMPT is not set |
| 158 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 159 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 160 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 159 | 161 | ||
| 160 | # | 162 | # |
| @@ -829,6 +831,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 829 | # | 831 | # |
| 830 | # Kernel hacking | 832 | # Kernel hacking |
| 831 | # | 833 | # |
| 834 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 832 | # CONFIG_PRINTK_TIME is not set | 835 | # CONFIG_PRINTK_TIME is not set |
| 833 | # CONFIG_MAGIC_SYSRQ is not set | 836 | # CONFIG_MAGIC_SYSRQ is not set |
| 834 | # CONFIG_UNUSED_SYMBOLS is not set | 837 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig index 06a072b77b1c..4d3c1329f3cf 100644 --- a/arch/mips/configs/yosemite_defconfig +++ b/arch/mips/configs/yosemite_defconfig | |||
| @@ -152,6 +152,8 @@ CONFIG_PREEMPT_NONE=y | |||
| 152 | # CONFIG_PREEMPT_VOLUNTARY is not set | 152 | # CONFIG_PREEMPT_VOLUNTARY is not set |
| 153 | # CONFIG_PREEMPT is not set | 153 | # CONFIG_PREEMPT is not set |
| 154 | CONFIG_PREEMPT_BKL=y | 154 | CONFIG_PREEMPT_BKL=y |
| 155 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 156 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 155 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 157 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 156 | 158 | ||
| 157 | # | 159 | # |
| @@ -760,6 +762,7 @@ CONFIG_MSDOS_PARTITION=y | |||
| 760 | # | 762 | # |
| 761 | # Kernel hacking | 763 | # Kernel hacking |
| 762 | # | 764 | # |
| 765 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 763 | # CONFIG_PRINTK_TIME is not set | 766 | # CONFIG_PRINTK_TIME is not set |
| 764 | # CONFIG_MAGIC_SYSRQ is not set | 767 | # CONFIG_MAGIC_SYSRQ is not set |
| 765 | # CONFIG_UNUSED_SYMBOLS is not set | 768 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/defconfig b/arch/mips/defconfig index cc9b24eda9e8..21d53e0c9ee8 100644 --- a/arch/mips/defconfig +++ b/arch/mips/defconfig | |||
| @@ -153,6 +153,8 @@ CONFIG_HZ=1000 | |||
| 153 | # CONFIG_PREEMPT_NONE is not set | 153 | # CONFIG_PREEMPT_NONE is not set |
| 154 | CONFIG_PREEMPT_VOLUNTARY=y | 154 | CONFIG_PREEMPT_VOLUNTARY=y |
| 155 | # CONFIG_PREEMPT is not set | 155 | # CONFIG_PREEMPT is not set |
| 156 | CONFIG_LOCKDEP_SUPPORT=y | ||
| 157 | CONFIG_STACKTRACE_SUPPORT=y | ||
| 156 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 158 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
| 157 | 159 | ||
| 158 | # | 160 | # |
| @@ -1147,6 +1149,7 @@ CONFIG_NLS_UTF8=m | |||
| 1147 | # | 1149 | # |
| 1148 | # Kernel hacking | 1150 | # Kernel hacking |
| 1149 | # | 1151 | # |
| 1152 | CONFIG_TRACE_IRQFLAGS_SUPPORT=y | ||
| 1150 | # CONFIG_PRINTK_TIME is not set | 1153 | # CONFIG_PRINTK_TIME is not set |
| 1151 | # CONFIG_MAGIC_SYSRQ is not set | 1154 | # CONFIG_MAGIC_SYSRQ is not set |
| 1152 | # CONFIG_UNUSED_SYMBOLS is not set | 1155 | # CONFIG_UNUSED_SYMBOLS is not set |
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 881c467c6982..cd9cec9e39e9 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
| @@ -11,6 +11,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ | |||
| 11 | binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ | 11 | binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ |
| 12 | irix5sys.o sysirix.o | 12 | irix5sys.o sysirix.o |
| 13 | 13 | ||
| 14 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | ||
| 14 | obj-$(CONFIG_MODULES) += mips_ksyms.o module.o | 15 | obj-$(CONFIG_MODULES) += mips_ksyms.o module.o |
| 15 | 16 | ||
| 16 | obj-$(CONFIG_APM) += apm.o | 17 | obj-$(CONFIG_APM) += apm.o |
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 37fda3dcdfc5..af6ef2fd8300 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S | |||
| @@ -220,8 +220,8 @@ NESTED(except_vec_vi_handler, 0, sp) | |||
| 220 | CLI | 220 | CLI |
| 221 | TRACE_IRQS_OFF | 221 | TRACE_IRQS_OFF |
| 222 | move a0, sp | 222 | move a0, sp |
| 223 | jalr v0 | 223 | PTR_LA ra, ret_from_irq |
| 224 | j ret_from_irq | 224 | jr v0 |
| 225 | END(except_vec_vi_handler) | 225 | END(except_vec_vi_handler) |
| 226 | 226 | ||
| 227 | /* | 227 | /* |
| @@ -349,8 +349,8 @@ NESTED(nmi_handler, PT_SIZE, sp) | |||
| 349 | .set at | 349 | .set at |
| 350 | __BUILD_\verbose \exception | 350 | __BUILD_\verbose \exception |
| 351 | move a0, sp | 351 | move a0, sp |
| 352 | jal do_\handler | 352 | PTR_LA ra, ret_from_exception |
| 353 | j ret_from_exception | 353 | j do_\handler |
| 354 | END(handle_\exception) | 354 | END(handle_\exception) |
| 355 | .endm | 355 | .endm |
| 356 | 356 | ||
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index ea36c8e8852c..48e3418c217b 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c | |||
| @@ -302,11 +302,11 @@ static struct irqaction irq2 = { | |||
| 302 | }; | 302 | }; |
| 303 | 303 | ||
| 304 | static struct resource pic1_io_resource = { | 304 | static struct resource pic1_io_resource = { |
| 305 | .name = "pic1", .start = 0x20, .end = 0x3f, .flags = IORESOURCE_BUSY | 305 | .name = "pic1", .start = 0x20, .end = 0x21, .flags = IORESOURCE_BUSY |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | static struct resource pic2_io_resource = { | 308 | static struct resource pic2_io_resource = { |
| 309 | .name = "pic2", .start = 0xa0, .end = 0xbf, .flags = IORESOURCE_BUSY | 309 | .name = "pic2", .start = 0xa0, .end = 0xa1, .flags = IORESOURCE_BUSY |
| 310 | }; | 310 | }; |
| 311 | 311 | ||
| 312 | /* | 312 | /* |
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 43b1162d714f..52cada45b353 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
| @@ -1039,7 +1039,7 @@ asmlinkage long sys32_newuname(struct new_utsname __user * name) | |||
| 1039 | int ret = 0; | 1039 | int ret = 0; |
| 1040 | 1040 | ||
| 1041 | down_read(&uts_sem); | 1041 | down_read(&uts_sem); |
| 1042 | if (copy_to_user(name,&system_utsname,sizeof *name)) | 1042 | if (copy_to_user(name, utsname(), sizeof *name)) |
| 1043 | ret = -EFAULT; | 1043 | ret = -EFAULT; |
| 1044 | up_read(&uts_sem); | 1044 | up_read(&uts_sem); |
| 1045 | 1045 | ||
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 2613a0dd4b82..045d987bc683 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include <asm/elf.h> | 40 | #include <asm/elf.h> |
| 41 | #include <asm/isadep.h> | 41 | #include <asm/isadep.h> |
| 42 | #include <asm/inst.h> | 42 | #include <asm/inst.h> |
| 43 | #include <asm/stacktrace.h> | ||
| 43 | #ifdef CONFIG_MIPS_MT_SMTC | 44 | #ifdef CONFIG_MIPS_MT_SMTC |
| 44 | #include <asm/mipsmtregs.h> | 45 | #include <asm/mipsmtregs.h> |
| 45 | extern void smtc_idle_loop_hook(void); | 46 | extern void smtc_idle_loop_hook(void); |
| @@ -398,7 +399,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
| 398 | #ifdef CONFIG_KALLSYMS | 399 | #ifdef CONFIG_KALLSYMS |
| 399 | /* used by show_backtrace() */ | 400 | /* used by show_backtrace() */ |
| 400 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | 401 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, |
| 401 | unsigned long pc, unsigned long ra) | 402 | unsigned long pc, unsigned long *ra) |
| 402 | { | 403 | { |
| 403 | unsigned long stack_page; | 404 | unsigned long stack_page; |
| 404 | struct mips_frame_info info; | 405 | struct mips_frame_info info; |
| @@ -406,18 +407,42 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | |||
| 406 | char namebuf[KSYM_NAME_LEN + 1]; | 407 | char namebuf[KSYM_NAME_LEN + 1]; |
| 407 | unsigned long size, ofs; | 408 | unsigned long size, ofs; |
| 408 | int leaf; | 409 | int leaf; |
| 410 | extern void ret_from_irq(void); | ||
| 411 | extern void ret_from_exception(void); | ||
| 409 | 412 | ||
| 410 | stack_page = (unsigned long)task_stack_page(task); | 413 | stack_page = (unsigned long)task_stack_page(task); |
| 411 | if (!stack_page) | 414 | if (!stack_page) |
| 412 | return 0; | 415 | return 0; |
| 413 | 416 | ||
| 417 | /* | ||
| 418 | * If we reached the bottom of interrupt context, | ||
| 419 | * return saved pc in pt_regs. | ||
| 420 | */ | ||
| 421 | if (pc == (unsigned long)ret_from_irq || | ||
| 422 | pc == (unsigned long)ret_from_exception) { | ||
| 423 | struct pt_regs *regs; | ||
| 424 | if (*sp >= stack_page && | ||
| 425 | *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) { | ||
| 426 | regs = (struct pt_regs *)*sp; | ||
| 427 | pc = regs->cp0_epc; | ||
| 428 | if (__kernel_text_address(pc)) { | ||
| 429 | *sp = regs->regs[29]; | ||
| 430 | *ra = regs->regs[31]; | ||
| 431 | return pc; | ||
| 432 | } | ||
| 433 | } | ||
| 434 | return 0; | ||
| 435 | } | ||
| 414 | if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) | 436 | if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) |
| 415 | return 0; | 437 | return 0; |
| 416 | /* | 438 | /* |
| 417 | * Return ra if an exception occured at the first instruction | 439 | * Return ra if an exception occured at the first instruction |
| 418 | */ | 440 | */ |
| 419 | if (unlikely(ofs == 0)) | 441 | if (unlikely(ofs == 0)) { |
| 420 | return ra; | 442 | pc = *ra; |
| 443 | *ra = 0; | ||
| 444 | return pc; | ||
| 445 | } | ||
| 421 | 446 | ||
| 422 | info.func = (void *)(pc - ofs); | 447 | info.func = (void *)(pc - ofs); |
| 423 | info.func_size = ofs; /* analyze from start to ofs */ | 448 | info.func_size = ofs; /* analyze from start to ofs */ |
| @@ -436,11 +461,12 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | |||
| 436 | * one. In that cases avoid to return always the | 461 | * one. In that cases avoid to return always the |
| 437 | * same value. | 462 | * same value. |
| 438 | */ | 463 | */ |
| 439 | pc = pc != ra ? ra : 0; | 464 | pc = pc != *ra ? *ra : 0; |
| 440 | else | 465 | else |
| 441 | pc = ((unsigned long *)(*sp))[info.pc_offset]; | 466 | pc = ((unsigned long *)(*sp))[info.pc_offset]; |
| 442 | 467 | ||
| 443 | *sp += info.frame_size; | 468 | *sp += info.frame_size; |
| 469 | *ra = 0; | ||
| 444 | return __kernel_text_address(pc) ? pc : 0; | 470 | return __kernel_text_address(pc) ? pc : 0; |
| 445 | } | 471 | } |
| 446 | #endif | 472 | #endif |
| @@ -453,6 +479,7 @@ unsigned long get_wchan(struct task_struct *task) | |||
| 453 | unsigned long pc = 0; | 479 | unsigned long pc = 0; |
| 454 | #ifdef CONFIG_KALLSYMS | 480 | #ifdef CONFIG_KALLSYMS |
| 455 | unsigned long sp; | 481 | unsigned long sp; |
| 482 | unsigned long ra = 0; | ||
| 456 | #endif | 483 | #endif |
| 457 | 484 | ||
| 458 | if (!task || task == current || task->state == TASK_RUNNING) | 485 | if (!task || task == current || task->state == TASK_RUNNING) |
| @@ -466,7 +493,7 @@ unsigned long get_wchan(struct task_struct *task) | |||
| 466 | sp = task->thread.reg29 + schedule_mfi.frame_size; | 493 | sp = task->thread.reg29 + schedule_mfi.frame_size; |
| 467 | 494 | ||
| 468 | while (in_sched_functions(pc)) | 495 | while (in_sched_functions(pc)) |
| 469 | pc = unwind_stack(task, &sp, pc, 0); | 496 | pc = unwind_stack(task, &sp, pc, &ra); |
| 470 | #endif | 497 | #endif |
| 471 | 498 | ||
| 472 | out: | 499 | out: |
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index e71785102206..61362e6fa9ec 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S | |||
| @@ -28,18 +28,7 @@ | |||
| 28 | NESTED(handle_sys, PT_SIZE, sp) | 28 | NESTED(handle_sys, PT_SIZE, sp) |
| 29 | .set noat | 29 | .set noat |
| 30 | SAVE_SOME | 30 | SAVE_SOME |
| 31 | #ifdef CONFIG_TRACE_IRQFLAGS | 31 | TRACE_IRQS_ON_RELOAD |
| 32 | TRACE_IRQS_ON | ||
| 33 | #ifdef CONFIG_64BIT | ||
| 34 | LONG_L $8, PT_R8(sp) | ||
| 35 | LONG_L $9, PT_R9(sp) | ||
| 36 | #endif | ||
| 37 | LONG_L $7, PT_R7(sp) | ||
| 38 | LONG_L $6, PT_R6(sp) | ||
| 39 | LONG_L $5, PT_R5(sp) | ||
| 40 | LONG_L $4, PT_R4(sp) | ||
| 41 | LONG_L $2, PT_R2(sp) | ||
| 42 | #endif | ||
| 43 | STI | 32 | STI |
| 44 | .set at | 33 | .set at |
| 45 | 34 | ||
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 4c22d0b4825d..6c7b5ed0ea6e 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S | |||
| @@ -34,7 +34,7 @@ NESTED(handle_sys64, PT_SIZE, sp) | |||
| 34 | */ | 34 | */ |
| 35 | .set noat | 35 | .set noat |
| 36 | SAVE_SOME | 36 | SAVE_SOME |
| 37 | TRACE_IRQS_ON | 37 | TRACE_IRQS_ON_RELOAD |
| 38 | STI | 38 | STI |
| 39 | .set at | 39 | .set at |
| 40 | #endif | 40 | #endif |
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index f25c2a2f1038..6d9f18727ac5 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
| @@ -33,7 +33,7 @@ NESTED(handle_sysn32, PT_SIZE, sp) | |||
| 33 | #ifndef CONFIG_MIPS32_O32 | 33 | #ifndef CONFIG_MIPS32_O32 |
| 34 | .set noat | 34 | .set noat |
| 35 | SAVE_SOME | 35 | SAVE_SOME |
| 36 | TRACE_IRQS_ON | 36 | TRACE_IRQS_ON_RELOAD |
| 37 | STI | 37 | STI |
| 38 | .set at | 38 | .set at |
| 39 | #endif | 39 | #endif |
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 288ee4ac4dbb..2e6d0673163e 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | NESTED(handle_sys, PT_SIZE, sp) | 28 | NESTED(handle_sys, PT_SIZE, sp) |
| 29 | .set noat | 29 | .set noat |
| 30 | SAVE_SOME | 30 | SAVE_SOME |
| 31 | TRACE_IRQS_ON | 31 | TRACE_IRQS_ON_RELOAD |
| 32 | STI | 32 | STI |
| 33 | .set at | 33 | .set at |
| 34 | ld t1, PT_EPC(sp) # skip syscall on return | 34 | ld t1, PT_EPC(sp) # skip syscall on return |
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 50c17eaa7f25..477c5334ec1b 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c | |||
| @@ -42,8 +42,6 @@ | |||
| 42 | 42 | ||
| 43 | #include "signal-common.h" | 43 | #include "signal-common.h" |
| 44 | 44 | ||
| 45 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
| 46 | |||
| 47 | /* | 45 | /* |
| 48 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... | 46 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... |
| 49 | */ | 47 | */ |
| @@ -83,6 +81,8 @@ struct rt_sigframe_n32 { | |||
| 83 | #endif | 81 | #endif |
| 84 | }; | 82 | }; |
| 85 | 83 | ||
| 84 | extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat); | ||
| 85 | |||
| 86 | save_static_function(sysn32_rt_sigsuspend); | 86 | save_static_function(sysn32_rt_sigsuspend); |
| 87 | __attribute_used__ noinline static int | 87 | __attribute_used__ noinline static int |
| 88 | _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | 88 | _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) |
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c new file mode 100644 index 000000000000..4aabe526a68e --- /dev/null +++ b/arch/mips/kernel/stacktrace.c | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | * arch/mips/kernel/stacktrace.c | ||
| 3 | * | ||
| 4 | * Stack trace management functions | ||
| 5 | * | ||
| 6 | * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
| 7 | */ | ||
| 8 | #include <linux/sched.h> | ||
| 9 | #include <linux/stacktrace.h> | ||
| 10 | #include <asm/stacktrace.h> | ||
| 11 | |||
| 12 | /* | ||
| 13 | * Save stack-backtrace addresses into a stack_trace buffer: | ||
| 14 | */ | ||
| 15 | static void save_raw_context_stack(struct stack_trace *trace, | ||
| 16 | unsigned long reg29) | ||
| 17 | { | ||
| 18 | unsigned long *sp = (unsigned long *)reg29; | ||
| 19 | unsigned long addr; | ||
| 20 | |||
| 21 | while (!kstack_end(sp)) { | ||
| 22 | addr = *sp++; | ||
| 23 | if (__kernel_text_address(addr)) { | ||
| 24 | if (trace->skip > 0) | ||
| 25 | trace->skip--; | ||
| 26 | else | ||
| 27 | trace->entries[trace->nr_entries++] = addr; | ||
| 28 | if (trace->nr_entries >= trace->max_entries) | ||
| 29 | break; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | static void save_context_stack(struct stack_trace *trace, | ||
| 35 | struct task_struct *task, struct pt_regs *regs) | ||
| 36 | { | ||
| 37 | unsigned long sp = regs->regs[29]; | ||
| 38 | #ifdef CONFIG_KALLSYMS | ||
| 39 | unsigned long ra = regs->regs[31]; | ||
| 40 | unsigned long pc = regs->cp0_epc; | ||
| 41 | |||
| 42 | if (raw_show_trace || !__kernel_text_address(pc)) { | ||
| 43 | unsigned long stack_page = | ||
| 44 | (unsigned long)task_stack_page(task); | ||
| 45 | if (stack_page && sp >= stack_page && | ||
| 46 | sp <= stack_page + THREAD_SIZE - 32) | ||
| 47 | save_raw_context_stack(trace, sp); | ||
| 48 | return; | ||
| 49 | } | ||
| 50 | do { | ||
| 51 | if (trace->skip > 0) | ||
| 52 | trace->skip--; | ||
| 53 | else | ||
| 54 | trace->entries[trace->nr_entries++] = pc; | ||
| 55 | if (trace->nr_entries >= trace->max_entries) | ||
| 56 | break; | ||
| 57 | pc = unwind_stack(task, &sp, pc, &ra); | ||
| 58 | } while (pc); | ||
| 59 | #else | ||
| 60 | save_raw_context_stack(sp); | ||
| 61 | #endif | ||
| 62 | } | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Save stack-backtrace addresses into a stack_trace buffer. | ||
| 66 | */ | ||
| 67 | void save_stack_trace(struct stack_trace *trace, struct task_struct *task) | ||
| 68 | { | ||
| 69 | struct pt_regs dummyregs; | ||
| 70 | struct pt_regs *regs = &dummyregs; | ||
| 71 | |||
| 72 | WARN_ON(trace->nr_entries || !trace->max_entries); | ||
| 73 | |||
| 74 | if (task && task != current) { | ||
| 75 | regs->regs[29] = task->thread.reg29; | ||
| 76 | regs->regs[31] = 0; | ||
| 77 | regs->cp0_epc = task->thread.reg31; | ||
| 78 | } else { | ||
| 79 | if (!task) | ||
| 80 | task = current; | ||
| 81 | prepare_frametrace(regs); | ||
| 82 | } | ||
| 83 | |||
| 84 | save_context_stack(trace, task, regs); | ||
| 85 | } | ||
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 9951240cc3fd..26e1a7e78d13 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
| @@ -231,7 +231,7 @@ out: | |||
| 231 | */ | 231 | */ |
| 232 | asmlinkage int sys_uname(struct old_utsname __user * name) | 232 | asmlinkage int sys_uname(struct old_utsname __user * name) |
| 233 | { | 233 | { |
| 234 | if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) | 234 | if (name && !copy_to_user(name, utsname(), sizeof (*name))) |
| 235 | return 0; | 235 | return 0; |
| 236 | return -EFAULT; | 236 | return -EFAULT; |
| 237 | } | 237 | } |
| @@ -248,16 +248,21 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name) | |||
| 248 | if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) | 248 | if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) |
| 249 | return -EFAULT; | 249 | return -EFAULT; |
| 250 | 250 | ||
| 251 | error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); | 251 | error = __copy_to_user(&name->sysname, &utsname()->sysname, |
| 252 | error -= __put_user(0,name->sysname+__OLD_UTS_LEN); | 252 | __OLD_UTS_LEN); |
| 253 | error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); | 253 | error -= __put_user(0, name->sysname + __OLD_UTS_LEN); |
| 254 | error -= __put_user(0,name->nodename+__OLD_UTS_LEN); | 254 | error -= __copy_to_user(&name->nodename, &utsname()->nodename, |
| 255 | error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); | 255 | __OLD_UTS_LEN); |
| 256 | error -= __put_user(0,name->release+__OLD_UTS_LEN); | 256 | error -= __put_user(0, name->nodename + __OLD_UTS_LEN); |
| 257 | error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); | 257 | error -= __copy_to_user(&name->release, &utsname()->release, |
| 258 | error -= __put_user(0,name->version+__OLD_UTS_LEN); | 258 | __OLD_UTS_LEN); |
| 259 | error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); | 259 | error -= __put_user(0, name->release + __OLD_UTS_LEN); |
| 260 | error = __put_user(0,name->machine+__OLD_UTS_LEN); | 260 | error -= __copy_to_user(&name->version, &utsname()->version, |
| 261 | __OLD_UTS_LEN); | ||
| 262 | error -= __put_user(0, name->version + __OLD_UTS_LEN); | ||
| 263 | error -= __copy_to_user(&name->machine, &utsname()->machine, | ||
| 264 | __OLD_UTS_LEN); | ||
| 265 | error = __put_user(0, name->machine + __OLD_UTS_LEN); | ||
| 261 | error = error ? -EFAULT : 0; | 266 | error = error ? -EFAULT : 0; |
| 262 | 267 | ||
| 263 | return error; | 268 | return error; |
| @@ -401,3 +406,32 @@ asmlinkage void bad_stack(void) | |||
| 401 | { | 406 | { |
| 402 | do_exit(SIGSEGV); | 407 | do_exit(SIGSEGV); |
| 403 | } | 408 | } |
| 409 | |||
| 410 | /* | ||
| 411 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 412 | * end up with proper pt_regs. | ||
| 413 | */ | ||
| 414 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 415 | { | ||
| 416 | register unsigned long __a0 asm("$4") = (unsigned long) filename; | ||
| 417 | register unsigned long __a1 asm("$5") = (unsigned long) argv; | ||
| 418 | register unsigned long __a2 asm("$6") = (unsigned long) envp; | ||
| 419 | register unsigned long __a3 asm("$7"); | ||
| 420 | unsigned long __v0; | ||
| 421 | |||
| 422 | __asm__ volatile (" \n" | ||
| 423 | " .set noreorder \n" | ||
| 424 | " li $2, %5 # __NR_execve \n" | ||
| 425 | " syscall \n" | ||
| 426 | " move %0, $2 \n" | ||
| 427 | " .set reorder \n" | ||
| 428 | : "=&r" (__v0), "=r" (__a3) | ||
| 429 | : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve) | ||
| 430 | : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", | ||
| 431 | "memory"); | ||
| 432 | |||
| 433 | if (__a3 == 0) | ||
| 434 | return __v0; | ||
| 435 | |||
| 436 | return -__v0; | ||
| 437 | } | ||
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 1137dd6ea7aa..11bb97174972 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c | |||
| @@ -884,7 +884,7 @@ asmlinkage int irix_getdomainname(char __user *name, int len) | |||
| 884 | down_read(&uts_sem); | 884 | down_read(&uts_sem); |
| 885 | if (len > __NEW_UTS_LEN) | 885 | if (len > __NEW_UTS_LEN) |
| 886 | len = __NEW_UTS_LEN; | 886 | len = __NEW_UTS_LEN; |
| 887 | err = copy_to_user(name, system_utsname.domainname, len) ? -EFAULT : 0; | 887 | err = copy_to_user(name, utsname()->domainname, len) ? -EFAULT : 0; |
| 888 | up_read(&uts_sem); | 888 | up_read(&uts_sem); |
| 889 | 889 | ||
| 890 | return err; | 890 | return err; |
| @@ -1127,11 +1127,11 @@ struct iuname { | |||
| 1127 | asmlinkage int irix_uname(struct iuname __user *buf) | 1127 | asmlinkage int irix_uname(struct iuname __user *buf) |
| 1128 | { | 1128 | { |
| 1129 | down_read(&uts_sem); | 1129 | down_read(&uts_sem); |
| 1130 | if (copy_from_user(system_utsname.sysname, buf->sysname, 65) | 1130 | if (copy_from_user(utsname()->sysname, buf->sysname, 65) |
| 1131 | || copy_from_user(system_utsname.nodename, buf->nodename, 65) | 1131 | || copy_from_user(utsname()->nodename, buf->nodename, 65) |
| 1132 | || copy_from_user(system_utsname.release, buf->release, 65) | 1132 | || copy_from_user(utsname()->release, buf->release, 65) |
| 1133 | || copy_from_user(system_utsname.version, buf->version, 65) | 1133 | || copy_from_user(utsname()->version, buf->version, 65) |
| 1134 | || copy_from_user(system_utsname.machine, buf->machine, 65)) { | 1134 | || copy_from_user(utsname()->machine, buf->machine, 65)) { |
| 1135 | return -EFAULT; | 1135 | return -EFAULT; |
| 1136 | } | 1136 | } |
| 1137 | up_read(&uts_sem); | 1137 | up_read(&uts_sem); |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e51d8fd9a152..b7292a56d4cd 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <asm/mmu_context.h> | 41 | #include <asm/mmu_context.h> |
| 42 | #include <asm/watch.h> | 42 | #include <asm/watch.h> |
| 43 | #include <asm/types.h> | 43 | #include <asm/types.h> |
| 44 | #include <asm/stacktrace.h> | ||
| 44 | 45 | ||
| 45 | extern asmlinkage void handle_int(void); | 46 | extern asmlinkage void handle_int(void); |
| 46 | extern asmlinkage void handle_tlbm(void); | 47 | extern asmlinkage void handle_tlbm(void); |
| @@ -92,16 +93,14 @@ static void show_raw_backtrace(unsigned long reg29) | |||
| 92 | } | 93 | } |
| 93 | 94 | ||
| 94 | #ifdef CONFIG_KALLSYMS | 95 | #ifdef CONFIG_KALLSYMS |
| 95 | static int raw_show_trace; | 96 | int raw_show_trace; |
| 96 | static int __init set_raw_show_trace(char *str) | 97 | static int __init set_raw_show_trace(char *str) |
| 97 | { | 98 | { |
| 98 | raw_show_trace = 1; | 99 | raw_show_trace = 1; |
| 99 | return 1; | 100 | return 1; |
| 100 | } | 101 | } |
| 101 | __setup("raw_show_trace", set_raw_show_trace); | 102 | __setup("raw_show_trace", set_raw_show_trace); |
| 102 | 103 | #endif | |
| 103 | extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | ||
| 104 | unsigned long pc, unsigned long ra); | ||
| 105 | 104 | ||
| 106 | static void show_backtrace(struct task_struct *task, struct pt_regs *regs) | 105 | static void show_backtrace(struct task_struct *task, struct pt_regs *regs) |
| 107 | { | 106 | { |
| @@ -116,14 +115,10 @@ static void show_backtrace(struct task_struct *task, struct pt_regs *regs) | |||
| 116 | printk("Call Trace:\n"); | 115 | printk("Call Trace:\n"); |
| 117 | do { | 116 | do { |
| 118 | print_ip_sym(pc); | 117 | print_ip_sym(pc); |
| 119 | pc = unwind_stack(task, &sp, pc, ra); | 118 | pc = unwind_stack(task, &sp, pc, &ra); |
| 120 | ra = 0; | ||
| 121 | } while (pc); | 119 | } while (pc); |
| 122 | printk("\n"); | 120 | printk("\n"); |
| 123 | } | 121 | } |
| 124 | #else | ||
| 125 | #define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]); | ||
| 126 | #endif | ||
| 127 | 122 | ||
| 128 | /* | 123 | /* |
| 129 | * This routine abuses get_user()/put_user() to reference pointers | 124 | * This routine abuses get_user()/put_user() to reference pointers |
| @@ -158,28 +153,6 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) | |||
| 158 | show_backtrace(task, regs); | 153 | show_backtrace(task, regs); |
| 159 | } | 154 | } |
| 160 | 155 | ||
| 161 | static __always_inline void prepare_frametrace(struct pt_regs *regs) | ||
| 162 | { | ||
| 163 | __asm__ __volatile__( | ||
| 164 | ".set push\n\t" | ||
| 165 | ".set noat\n\t" | ||
| 166 | #ifdef CONFIG_64BIT | ||
| 167 | "1: dla $1, 1b\n\t" | ||
| 168 | "sd $1, %0\n\t" | ||
| 169 | "sd $29, %1\n\t" | ||
| 170 | "sd $31, %2\n\t" | ||
| 171 | #else | ||
| 172 | "1: la $1, 1b\n\t" | ||
| 173 | "sw $1, %0\n\t" | ||
| 174 | "sw $29, %1\n\t" | ||
| 175 | "sw $31, %2\n\t" | ||
| 176 | #endif | ||
| 177 | ".set pop\n\t" | ||
| 178 | : "=m" (regs->cp0_epc), | ||
| 179 | "=m" (regs->regs[29]), "=m" (regs->regs[31]) | ||
| 180 | : : "memory"); | ||
| 181 | } | ||
| 182 | |||
| 183 | void show_stack(struct task_struct *task, unsigned long *sp) | 156 | void show_stack(struct task_struct *task, unsigned long *sp) |
| 184 | { | 157 | { |
| 185 | struct pt_regs regs; | 158 | struct pt_regs regs; |
| @@ -206,11 +179,6 @@ void dump_stack(void) | |||
| 206 | { | 179 | { |
| 207 | struct pt_regs regs; | 180 | struct pt_regs regs; |
| 208 | 181 | ||
| 209 | /* | ||
| 210 | * Remove any garbage that may be in regs (specially func | ||
| 211 | * addresses) to avoid show_raw_backtrace() to report them | ||
| 212 | */ | ||
| 213 | memset(®s, 0, sizeof(regs)); | ||
| 214 | prepare_frametrace(®s); | 182 | prepare_frametrace(®s); |
| 215 | show_backtrace(current, ®s); | 183 | show_backtrace(current, ®s); |
| 216 | } | 184 | } |
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index e1f35ef81145..d1af42c2a52e 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c | |||
| @@ -268,26 +268,6 @@ static void r3k_flush_data_cache_page(unsigned long addr) | |||
| 268 | { | 268 | { |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page) | ||
| 272 | { | ||
| 273 | struct mm_struct *mm = vma->vm_mm; | ||
| 274 | unsigned long physpage; | ||
| 275 | |||
| 276 | if (cpu_context(smp_processor_id(), mm) == 0) | ||
| 277 | return; | ||
| 278 | |||
| 279 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 280 | return; | ||
| 281 | |||
| 282 | #ifdef DEBUG_CACHE | ||
| 283 | printk("cpage[%d,%08lx]", cpu_context(smp_processor_id(), mm), page); | ||
| 284 | #endif | ||
| 285 | |||
| 286 | physpage = (unsigned long) page_address(page); | ||
| 287 | if (physpage) | ||
| 288 | r3k_flush_icache_range(physpage, physpage + PAGE_SIZE); | ||
| 289 | } | ||
| 290 | |||
| 291 | static void r3k_flush_cache_sigtramp(unsigned long addr) | 271 | static void r3k_flush_cache_sigtramp(unsigned long addr) |
| 292 | { | 272 | { |
| 293 | unsigned long flags; | 273 | unsigned long flags; |
| @@ -335,7 +315,6 @@ void __init r3k_cache_init(void) | |||
| 335 | flush_cache_mm = r3k_flush_cache_mm; | 315 | flush_cache_mm = r3k_flush_cache_mm; |
| 336 | flush_cache_range = r3k_flush_cache_range; | 316 | flush_cache_range = r3k_flush_cache_range; |
| 337 | flush_cache_page = r3k_flush_cache_page; | 317 | flush_cache_page = r3k_flush_cache_page; |
| 338 | __flush_icache_page = r3k_flush_icache_page; | ||
| 339 | flush_icache_range = r3k_flush_icache_range; | 318 | flush_icache_range = r3k_flush_icache_range; |
| 340 | 319 | ||
| 341 | flush_cache_sigtramp = r3k_flush_cache_sigtramp; | 320 | flush_cache_sigtramp = r3k_flush_cache_sigtramp; |
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 0b2da53750bd..cc895dad71d2 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c | |||
| @@ -551,82 +551,6 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end) | |||
| 551 | instruction_hazard(); | 551 | instruction_hazard(); |
| 552 | } | 552 | } |
| 553 | 553 | ||
| 554 | /* | ||
| 555 | * Ok, this seriously sucks. We use them to flush a user page but don't | ||
| 556 | * know the virtual address, so we have to blast away the whole icache | ||
| 557 | * which is significantly more expensive than the real thing. Otoh we at | ||
| 558 | * least know the kernel address of the page so we can flush it | ||
| 559 | * selectivly. | ||
| 560 | */ | ||
| 561 | |||
| 562 | struct flush_icache_page_args { | ||
| 563 | struct vm_area_struct *vma; | ||
| 564 | struct page *page; | ||
| 565 | }; | ||
| 566 | |||
| 567 | static inline void local_r4k_flush_icache_page(void *args) | ||
| 568 | { | ||
| 569 | struct flush_icache_page_args *fip_args = args; | ||
| 570 | struct vm_area_struct *vma = fip_args->vma; | ||
| 571 | struct page *page = fip_args->page; | ||
| 572 | |||
| 573 | /* | ||
| 574 | * Tricky ... Because we don't know the virtual address we've got the | ||
| 575 | * choice of either invalidating the entire primary and secondary | ||
| 576 | * caches or invalidating the secondary caches also. With the subset | ||
| 577 | * enforcment on R4000SC, R4400SC, R10000 and R12000 invalidating the | ||
| 578 | * secondary cache will result in any entries in the primary caches | ||
| 579 | * also getting invalidated which hopefully is a bit more economical. | ||
| 580 | */ | ||
| 581 | if (cpu_has_inclusive_pcaches) { | ||
| 582 | unsigned long addr = (unsigned long) page_address(page); | ||
| 583 | |||
| 584 | r4k_blast_scache_page(addr); | ||
| 585 | ClearPageDcacheDirty(page); | ||
| 586 | |||
| 587 | return; | ||
| 588 | } | ||
| 589 | |||
| 590 | if (!cpu_has_ic_fills_f_dc) { | ||
| 591 | unsigned long addr = (unsigned long) page_address(page); | ||
| 592 | r4k_blast_dcache_page(addr); | ||
| 593 | if (!cpu_icache_snoops_remote_store) | ||
| 594 | r4k_blast_scache_page(addr); | ||
| 595 | ClearPageDcacheDirty(page); | ||
| 596 | } | ||
| 597 | |||
| 598 | /* | ||
| 599 | * We're not sure of the virtual address(es) involved here, so | ||
| 600 | * we have to flush the entire I-cache. | ||
| 601 | */ | ||
| 602 | if (cpu_has_vtag_icache && vma->vm_mm == current->active_mm) { | ||
| 603 | int cpu = smp_processor_id(); | ||
| 604 | |||
| 605 | if (cpu_context(cpu, vma->vm_mm) != 0) | ||
| 606 | drop_mmu_context(vma->vm_mm, cpu); | ||
| 607 | } else | ||
| 608 | r4k_blast_icache(); | ||
| 609 | } | ||
| 610 | |||
| 611 | static void r4k_flush_icache_page(struct vm_area_struct *vma, | ||
| 612 | struct page *page) | ||
| 613 | { | ||
| 614 | struct flush_icache_page_args args; | ||
| 615 | |||
| 616 | /* | ||
| 617 | * If there's no context yet, or the page isn't executable, no I-cache | ||
| 618 | * flush is needed. | ||
| 619 | */ | ||
| 620 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 621 | return; | ||
| 622 | |||
| 623 | args.vma = vma; | ||
| 624 | args.page = page; | ||
| 625 | |||
| 626 | r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1); | ||
| 627 | } | ||
| 628 | |||
| 629 | |||
| 630 | #ifdef CONFIG_DMA_NONCOHERENT | 554 | #ifdef CONFIG_DMA_NONCOHERENT |
| 631 | 555 | ||
| 632 | static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) | 556 | static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) |
| @@ -1291,7 +1215,6 @@ void __init r4k_cache_init(void) | |||
| 1291 | __flush_cache_all = r4k___flush_cache_all; | 1215 | __flush_cache_all = r4k___flush_cache_all; |
| 1292 | flush_cache_mm = r4k_flush_cache_mm; | 1216 | flush_cache_mm = r4k_flush_cache_mm; |
| 1293 | flush_cache_page = r4k_flush_cache_page; | 1217 | flush_cache_page = r4k_flush_cache_page; |
| 1294 | __flush_icache_page = r4k_flush_icache_page; | ||
| 1295 | flush_cache_range = r4k_flush_cache_range; | 1218 | flush_cache_range = r4k_flush_cache_range; |
| 1296 | 1219 | ||
| 1297 | flush_cache_sigtramp = r4k_flush_cache_sigtramp; | 1220 | flush_cache_sigtramp = r4k_flush_cache_sigtramp; |
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 16bad7c0a63f..5537558f19f7 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c | |||
| @@ -307,66 +307,6 @@ void sb1_flush_icache_range(unsigned long start, unsigned long end) | |||
| 307 | #endif | 307 | #endif |
| 308 | 308 | ||
| 309 | /* | 309 | /* |
| 310 | * Flush the icache for a given physical page. Need to writeback the | ||
| 311 | * dcache first, then invalidate the icache. If the page isn't | ||
| 312 | * executable, nothing is required. | ||
| 313 | */ | ||
| 314 | static void local_sb1_flush_icache_page(struct vm_area_struct *vma, | ||
| 315 | struct page *page) | ||
| 316 | { | ||
| 317 | unsigned long start; | ||
| 318 | int cpu = smp_processor_id(); | ||
| 319 | |||
| 320 | #ifndef CONFIG_SMP | ||
| 321 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 322 | return; | ||
| 323 | #endif | ||
| 324 | |||
| 325 | /* Need to writeback any dirty data for that page, we have the PA */ | ||
| 326 | start = (unsigned long)(page-mem_map) << PAGE_SHIFT; | ||
| 327 | __sb1_writeback_inv_dcache_phys_range(start, start + PAGE_SIZE); | ||
| 328 | /* | ||
| 329 | * If there's a context, bump the ASID (cheaper than a flush, | ||
| 330 | * since we don't know VAs!) | ||
| 331 | */ | ||
| 332 | if (vma->vm_mm == current->active_mm) { | ||
| 333 | if (cpu_context(cpu, vma->vm_mm) != 0) | ||
| 334 | drop_mmu_context(vma->vm_mm, cpu); | ||
| 335 | } else | ||
| 336 | __sb1_flush_icache_range(start, start + PAGE_SIZE); | ||
| 337 | |||
| 338 | } | ||
| 339 | |||
| 340 | #ifdef CONFIG_SMP | ||
| 341 | struct flush_icache_page_args { | ||
| 342 | struct vm_area_struct *vma; | ||
| 343 | struct page *page; | ||
| 344 | }; | ||
| 345 | |||
| 346 | static void sb1_flush_icache_page_ipi(void *info) | ||
| 347 | { | ||
| 348 | struct flush_icache_page_args *args = info; | ||
| 349 | local_sb1_flush_icache_page(args->vma, args->page); | ||
| 350 | } | ||
| 351 | |||
| 352 | /* Dirty dcache could be on another CPU, so do the IPIs */ | ||
| 353 | static void sb1_flush_icache_page(struct vm_area_struct *vma, | ||
| 354 | struct page *page) | ||
| 355 | { | ||
| 356 | struct flush_icache_page_args args; | ||
| 357 | |||
| 358 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 359 | return; | ||
| 360 | args.vma = vma; | ||
| 361 | args.page = page; | ||
| 362 | on_each_cpu(sb1_flush_icache_page_ipi, (void *) &args, 1, 1); | ||
| 363 | } | ||
| 364 | #else | ||
| 365 | void sb1_flush_icache_page(struct vm_area_struct *vma, struct page *page) | ||
| 366 | __attribute__((alias("local_sb1_flush_icache_page"))); | ||
| 367 | #endif | ||
| 368 | |||
| 369 | /* | ||
| 370 | * A signal trampoline must fit into a single cacheline. | 310 | * A signal trampoline must fit into a single cacheline. |
| 371 | */ | 311 | */ |
| 372 | static void local_sb1_flush_cache_sigtramp(unsigned long addr) | 312 | static void local_sb1_flush_cache_sigtramp(unsigned long addr) |
| @@ -526,7 +466,6 @@ void sb1_cache_init(void) | |||
| 526 | 466 | ||
| 527 | /* These routines are for Icache coherence with the Dcache */ | 467 | /* These routines are for Icache coherence with the Dcache */ |
| 528 | flush_icache_range = sb1_flush_icache_range; | 468 | flush_icache_range = sb1_flush_icache_range; |
| 529 | __flush_icache_page = sb1_flush_icache_page; | ||
| 530 | flush_icache_all = __sb1_flush_icache_all; /* local only */ | 469 | flush_icache_all = __sb1_flush_icache_all; /* local only */ |
| 531 | 470 | ||
| 532 | /* This implies an Icache flush too, so can't be nop'ed */ | 471 | /* This implies an Icache flush too, so can't be nop'ed */ |
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index 932a09d7ef84..f32ebde30ccf 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c | |||
| @@ -248,33 +248,6 @@ static void tx39_flush_icache_range(unsigned long start, unsigned long end) | |||
| 248 | } | 248 | } |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | /* | ||
| 252 | * Ok, this seriously sucks. We use them to flush a user page but don't | ||
| 253 | * know the virtual address, so we have to blast away the whole icache | ||
| 254 | * which is significantly more expensive than the real thing. Otoh we at | ||
| 255 | * least know the kernel address of the page so we can flush it | ||
| 256 | * selectivly. | ||
| 257 | */ | ||
| 258 | static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page) | ||
| 259 | { | ||
| 260 | unsigned long addr; | ||
| 261 | /* | ||
| 262 | * If there's no context yet, or the page isn't executable, no icache | ||
| 263 | * flush is needed. | ||
| 264 | */ | ||
| 265 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 266 | return; | ||
| 267 | |||
| 268 | addr = (unsigned long) page_address(page); | ||
| 269 | tx39_blast_dcache_page(addr); | ||
| 270 | |||
| 271 | /* | ||
| 272 | * We're not sure of the virtual address(es) involved here, so | ||
| 273 | * we have to flush the entire I-cache. | ||
| 274 | */ | ||
| 275 | tx39_blast_icache(); | ||
| 276 | } | ||
| 277 | |||
| 278 | static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) | 251 | static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size) |
| 279 | { | 252 | { |
| 280 | unsigned long end; | 253 | unsigned long end; |
| @@ -382,7 +355,6 @@ void __init tx39_cache_init(void) | |||
| 382 | flush_cache_mm = (void *) tx39h_flush_icache_all; | 355 | flush_cache_mm = (void *) tx39h_flush_icache_all; |
| 383 | flush_cache_range = (void *) tx39h_flush_icache_all; | 356 | flush_cache_range = (void *) tx39h_flush_icache_all; |
| 384 | flush_cache_page = (void *) tx39h_flush_icache_all; | 357 | flush_cache_page = (void *) tx39h_flush_icache_all; |
| 385 | __flush_icache_page = (void *) tx39h_flush_icache_all; | ||
| 386 | flush_icache_range = (void *) tx39h_flush_icache_all; | 358 | flush_icache_range = (void *) tx39h_flush_icache_all; |
| 387 | 359 | ||
| 388 | flush_cache_sigtramp = (void *) tx39h_flush_icache_all; | 360 | flush_cache_sigtramp = (void *) tx39h_flush_icache_all; |
| @@ -408,7 +380,6 @@ void __init tx39_cache_init(void) | |||
| 408 | flush_cache_mm = tx39_flush_cache_mm; | 380 | flush_cache_mm = tx39_flush_cache_mm; |
| 409 | flush_cache_range = tx39_flush_cache_range; | 381 | flush_cache_range = tx39_flush_cache_range; |
| 410 | flush_cache_page = tx39_flush_cache_page; | 382 | flush_cache_page = tx39_flush_cache_page; |
| 411 | __flush_icache_page = tx39_flush_icache_page; | ||
| 412 | flush_icache_range = tx39_flush_icache_range; | 383 | flush_icache_range = tx39_flush_icache_range; |
| 413 | 384 | ||
| 414 | flush_cache_sigtramp = tx39_flush_cache_sigtramp; | 385 | flush_cache_sigtramp = tx39_flush_cache_sigtramp; |
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 40c8b0235183..caf807ded514 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c | |||
| @@ -25,7 +25,6 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start, | |||
| 25 | void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, | 25 | void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, |
| 26 | unsigned long pfn); | 26 | unsigned long pfn); |
| 27 | void (*flush_icache_range)(unsigned long start, unsigned long end); | 27 | void (*flush_icache_range)(unsigned long start, unsigned long end); |
| 28 | void (*__flush_icache_page)(struct vm_area_struct *vma, struct page *page); | ||
| 29 | 28 | ||
| 30 | /* MIPS specific cache operations */ | 29 | /* MIPS specific cache operations */ |
| 31 | void (*flush_cache_sigtramp)(unsigned long addr); | 30 | void (*flush_cache_sigtramp)(unsigned long addr); |
diff --git a/arch/mips/mm/tlbex-fault.S b/arch/mips/mm/tlbex-fault.S index 9e7f4175b493..e99eaa1fbedc 100644 --- a/arch/mips/mm/tlbex-fault.S +++ b/arch/mips/mm/tlbex-fault.S | |||
| @@ -19,8 +19,8 @@ | |||
| 19 | move a0, sp | 19 | move a0, sp |
| 20 | REG_S a2, PT_BVADDR(sp) | 20 | REG_S a2, PT_BVADDR(sp) |
| 21 | li a1, \write | 21 | li a1, \write |
| 22 | jal do_page_fault | 22 | PTR_LA ra, ret_from_exception |
| 23 | j ret_from_exception | 23 | j do_page_fault |
| 24 | END(tlb_do_page_fault_\write) | 24 | END(tlb_do_page_fault_\write) |
| 25 | .endm | 25 | .endm |
| 26 | 26 | ||
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c index 8134220ed600..7a941ecff3bb 100644 --- a/arch/mips/sgi-ip22/ip22-reset.c +++ b/arch/mips/sgi-ip22/ip22-reset.c | |||
| @@ -123,7 +123,8 @@ static inline void power_button(void) | |||
| 123 | if (machine_state & MACHINE_PANICED) | 123 | if (machine_state & MACHINE_PANICED) |
| 124 | return; | 124 | return; |
| 125 | 125 | ||
| 126 | if ((machine_state & MACHINE_SHUTTING_DOWN) || kill_proc(1,SIGINT,1)) { | 126 | if ((machine_state & MACHINE_SHUTTING_DOWN) || |
| 127 | kill_cad_pid(SIGINT, 1)) { | ||
| 127 | /* No init process or button pressed twice. */ | 128 | /* No init process or button pressed twice. */ |
| 128 | sgi_machine_power_off(); | 129 | sgi_machine_power_off(); |
| 129 | } | 130 | } |
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 79ddb4605659..fd0932b2d521 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c | |||
| @@ -120,7 +120,7 @@ static inline void ip32_power_button(void) | |||
| 120 | if (has_panicked) | 120 | if (has_panicked) |
| 121 | return; | 121 | return; |
| 122 | 122 | ||
| 123 | if (shuting_down || kill_proc(1, SIGINT, 1)) { | 123 | if (shuting_down || kill_cad_pid(SIGINT, 1)) { |
| 124 | /* No init process or button pressed twice. */ | 124 | /* No init process or button pressed twice. */ |
| 125 | ip32_machine_power_off(); | 125 | ip32_machine_power_off(); |
| 126 | } | 126 | } |
diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c index cb69727027ae..2e2dc4f2c853 100644 --- a/arch/parisc/hpux/sys_hpux.c +++ b/arch/parisc/hpux/sys_hpux.c | |||
| @@ -266,16 +266,21 @@ static int hpux_uname(struct hpux_utsname *name) | |||
| 266 | 266 | ||
| 267 | down_read(&uts_sem); | 267 | down_read(&uts_sem); |
| 268 | 268 | ||
| 269 | error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1); | 269 | error = __copy_to_user(&name->sysname, &utsname()->sysname, |
| 270 | error |= __put_user(0,name->sysname+HPUX_UTSLEN-1); | 270 | HPUX_UTSLEN - 1); |
| 271 | error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1); | 271 | error |= __put_user(0, name->sysname + HPUX_UTSLEN - 1); |
| 272 | error |= __put_user(0,name->nodename+HPUX_UTSLEN-1); | 272 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, |
| 273 | error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1); | 273 | HPUX_UTSLEN - 1); |
| 274 | error |= __put_user(0,name->release+HPUX_UTSLEN-1); | 274 | error |= __put_user(0, name->nodename + HPUX_UTSLEN - 1); |
| 275 | error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1); | 275 | error |= __copy_to_user(&name->release, &utsname()->release, |
| 276 | error |= __put_user(0,name->version+HPUX_UTSLEN-1); | 276 | HPUX_UTSLEN - 1); |
| 277 | error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1); | 277 | error |= __put_user(0, name->release + HPUX_UTSLEN - 1); |
| 278 | error |= __put_user(0,name->machine+HPUX_UTSLEN-1); | 278 | error |= __copy_to_user(&name->version, &utsname()->version, |
| 279 | HPUX_UTSLEN - 1); | ||
| 280 | error |= __put_user(0, name->version + HPUX_UTSLEN - 1); | ||
| 281 | error |= __copy_to_user(&name->machine, &utsname()->machine, | ||
| 282 | HPUX_UTSLEN - 1); | ||
| 283 | error |= __put_user(0, name->machine + HPUX_UTSLEN - 1); | ||
| 279 | 284 | ||
| 280 | up_read(&uts_sem); | 285 | up_read(&uts_sem); |
| 281 | 286 | ||
| @@ -373,8 +378,8 @@ int hpux_utssys(char *ubuf, int n, int type) | |||
| 373 | /* TODO: print a warning about using this? */ | 378 | /* TODO: print a warning about using this? */ |
| 374 | down_write(&uts_sem); | 379 | down_write(&uts_sem); |
| 375 | error = -EFAULT; | 380 | error = -EFAULT; |
| 376 | if (!copy_from_user(system_utsname.sysname, ubuf, len)) { | 381 | if (!copy_from_user(utsname()->sysname, ubuf, len)) { |
| 377 | system_utsname.sysname[len] = 0; | 382 | utsname()->sysname[len] = 0; |
| 378 | error = 0; | 383 | error = 0; |
| 379 | } | 384 | } |
| 380 | up_write(&uts_sem); | 385 | up_write(&uts_sem); |
| @@ -400,8 +405,8 @@ int hpux_utssys(char *ubuf, int n, int type) | |||
| 400 | /* TODO: print a warning about this? */ | 405 | /* TODO: print a warning about this? */ |
| 401 | down_write(&uts_sem); | 406 | down_write(&uts_sem); |
| 402 | error = -EFAULT; | 407 | error = -EFAULT; |
| 403 | if (!copy_from_user(system_utsname.release, ubuf, len)) { | 408 | if (!copy_from_user(utsname()->release, ubuf, len)) { |
| 404 | system_utsname.release[len] = 0; | 409 | utsname()->release[len] = 0; |
| 405 | error = 0; | 410 | error = 0; |
| 406 | } | 411 | } |
| 407 | up_write(&uts_sem); | 412 | up_write(&uts_sem); |
| @@ -422,13 +427,13 @@ int hpux_getdomainname(char *name, int len) | |||
| 422 | 427 | ||
| 423 | down_read(&uts_sem); | 428 | down_read(&uts_sem); |
| 424 | 429 | ||
| 425 | nlen = strlen(system_utsname.domainname) + 1; | 430 | nlen = strlen(utsname()->domainname) + 1; |
| 426 | 431 | ||
| 427 | if (nlen < len) | 432 | if (nlen < len) |
| 428 | len = nlen; | 433 | len = nlen; |
| 429 | if(len > __NEW_UTS_LEN) | 434 | if(len > __NEW_UTS_LEN) |
| 430 | goto done; | 435 | goto done; |
| 431 | if(copy_to_user(name, system_utsname.domainname, len)) | 436 | if(copy_to_user(name, utsname()->domainname, len)) |
| 432 | goto done; | 437 | goto done; |
| 433 | err = 0; | 438 | err = 0; |
| 434 | done: | 439 | done: |
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 0b485ef4be89..2f9f9dfa66f7 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c | |||
| @@ -368,7 +368,14 @@ out: | |||
| 368 | return error; | 368 | return error; |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | unsigned long | 371 | extern int __execve(const char *filename, char *const argv[], |
| 372 | char *const envp[], struct task_struct *task); | ||
| 373 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 374 | { | ||
| 375 | return __execve(filename, argv, envp, current); | ||
| 376 | } | ||
| 377 | |||
| 378 | unsigned long | ||
| 372 | get_wchan(struct task_struct *p) | 379 | get_wchan(struct task_struct *p) |
| 373 | { | 380 | { |
| 374 | struct unwind_frame_info info; | 381 | struct unwind_frame_info info; |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a0dd1b0ee483..032e6ab5d3c4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
| @@ -1069,7 +1069,7 @@ source "arch/powerpc/oprofile/Kconfig" | |||
| 1069 | 1069 | ||
| 1070 | config KPROBES | 1070 | config KPROBES |
| 1071 | bool "Kprobes (EXPERIMENTAL)" | 1071 | bool "Kprobes (EXPERIMENTAL)" |
| 1072 | depends on PPC64 && EXPERIMENTAL && MODULES | 1072 | depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES |
| 1073 | help | 1073 | help |
| 1074 | Kprobes allows you to trap at almost any kernel address and | 1074 | Kprobes allows you to trap at almost any kernel address and |
| 1075 | execute a callback function. register_kprobe() establishes | 1075 | execute a callback function. register_kprobe() establishes |
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index cd65c367b8b6..7b8d12b9026c 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c | |||
| @@ -259,14 +259,15 @@ void kretprobe_trampoline_holder(void) | |||
| 259 | */ | 259 | */ |
| 260 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 260 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
| 261 | { | 261 | { |
| 262 | struct kretprobe_instance *ri = NULL; | 262 | struct kretprobe_instance *ri = NULL; |
| 263 | struct hlist_head *head; | 263 | struct hlist_head *head, empty_rp; |
| 264 | struct hlist_node *node, *tmp; | 264 | struct hlist_node *node, *tmp; |
| 265 | unsigned long flags, orig_ret_address = 0; | 265 | unsigned long flags, orig_ret_address = 0; |
| 266 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | 266 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; |
| 267 | 267 | ||
| 268 | INIT_HLIST_HEAD(&empty_rp); | ||
| 268 | spin_lock_irqsave(&kretprobe_lock, flags); | 269 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 269 | head = kretprobe_inst_table_head(current); | 270 | head = kretprobe_inst_table_head(current); |
| 270 | 271 | ||
| 271 | /* | 272 | /* |
| 272 | * It is possible to have multiple instances associated with a given | 273 | * It is possible to have multiple instances associated with a given |
| @@ -277,20 +278,20 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 277 | * We can handle this because: | 278 | * We can handle this because: |
| 278 | * - instances are always inserted at the head of the list | 279 | * - instances are always inserted at the head of the list |
| 279 | * - when multiple return probes are registered for the same | 280 | * - when multiple return probes are registered for the same |
| 280 | * function, the first instance's ret_addr will point to the | 281 | * function, the first instance's ret_addr will point to the |
| 281 | * real return address, and all the rest will point to | 282 | * real return address, and all the rest will point to |
| 282 | * kretprobe_trampoline | 283 | * kretprobe_trampoline |
| 283 | */ | 284 | */ |
| 284 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | 285 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { |
| 285 | if (ri->task != current) | 286 | if (ri->task != current) |
| 286 | /* another task is sharing our hash bucket */ | 287 | /* another task is sharing our hash bucket */ |
| 287 | continue; | 288 | continue; |
| 288 | 289 | ||
| 289 | if (ri->rp && ri->rp->handler) | 290 | if (ri->rp && ri->rp->handler) |
| 290 | ri->rp->handler(ri, regs); | 291 | ri->rp->handler(ri, regs); |
| 291 | 292 | ||
| 292 | orig_ret_address = (unsigned long)ri->ret_addr; | 293 | orig_ret_address = (unsigned long)ri->ret_addr; |
| 293 | recycle_rp_inst(ri); | 294 | recycle_rp_inst(ri, &empty_rp); |
| 294 | 295 | ||
| 295 | if (orig_ret_address != trampoline_address) | 296 | if (orig_ret_address != trampoline_address) |
| 296 | /* | 297 | /* |
| @@ -308,12 +309,16 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 308 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 309 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 309 | preempt_enable_no_resched(); | 310 | preempt_enable_no_resched(); |
| 310 | 311 | ||
| 311 | /* | 312 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { |
| 312 | * By returning a non-zero value, we are telling | 313 | hlist_del(&ri->hlist); |
| 313 | * kprobe_handler() that we don't want the post_handler | 314 | kfree(ri); |
| 314 | * to run (and have re-enabled preemption) | 315 | } |
| 315 | */ | 316 | /* |
| 316 | return 1; | 317 | * By returning a non-zero value, we are telling |
| 318 | * kprobe_handler() that we don't want the post_handler | ||
| 319 | * to run (and have re-enabled preemption) | ||
| 320 | */ | ||
| 321 | return 1; | ||
| 317 | } | 322 | } |
| 318 | 323 | ||
| 319 | /* | 324 | /* |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 58758d883361..88fd73fdf048 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
| @@ -843,7 +843,7 @@ _GLOBAL(kernel_thread) | |||
| 843 | addi r1,r1,16 | 843 | addi r1,r1,16 |
| 844 | blr | 844 | blr |
| 845 | 845 | ||
| 846 | _GLOBAL(execve) | 846 | _GLOBAL(kernel_execve) |
| 847 | li r0,__NR_execve | 847 | li r0,__NR_execve |
| 848 | sc | 848 | sc |
| 849 | bnslr | 849 | bnslr |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index e3ed21cd3d94..9c54eccad993 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
| @@ -556,7 +556,7 @@ _GLOBAL(giveup_altivec) | |||
| 556 | 556 | ||
| 557 | #endif /* CONFIG_ALTIVEC */ | 557 | #endif /* CONFIG_ALTIVEC */ |
| 558 | 558 | ||
| 559 | _GLOBAL(execve) | 559 | _GLOBAL(kernel_execve) |
| 560 | li r0,__NR_execve | 560 | li r0,__NR_execve |
| 561 | sc | 561 | sc |
| 562 | bnslr | 562 | bnslr |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index a127a1e3c097..7b2f6452ba72 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
| @@ -424,7 +424,7 @@ void show_regs(struct pt_regs * regs) | |||
| 424 | printk("NIP: "REG" LR: "REG" CTR: "REG"\n", | 424 | printk("NIP: "REG" LR: "REG" CTR: "REG"\n", |
| 425 | regs->nip, regs->link, regs->ctr); | 425 | regs->nip, regs->link, regs->ctr); |
| 426 | printk("REGS: %p TRAP: %04lx %s (%s)\n", | 426 | printk("REGS: %p TRAP: %04lx %s (%s)\n", |
| 427 | regs, regs->trap, print_tainted(), system_utsname.release); | 427 | regs, regs->trap, print_tainted(), init_utsname()->release); |
| 428 | printk("MSR: "REG" ", regs->msr); | 428 | printk("MSR: "REG" ", regs->msr); |
| 429 | printbits(regs->msr, msr_bits); | 429 | printbits(regs->msr, msr_bits); |
| 430 | printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer); | 430 | printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer); |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 962ad5ebc767..cda2dbe70a76 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
| @@ -414,7 +414,7 @@ void __init setup_system(void) | |||
| 414 | smp_release_cpus(); | 414 | smp_release_cpus(); |
| 415 | #endif | 415 | #endif |
| 416 | 416 | ||
| 417 | printk("Starting Linux PPC64 %s\n", system_utsname.version); | 417 | printk("Starting Linux PPC64 %s\n", init_utsname()->version); |
| 418 | 418 | ||
| 419 | printk("-----------------------------------------------------\n"); | 419 | printk("-----------------------------------------------------\n"); |
| 420 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | 420 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); |
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 9b69d99a9103..d358866b880f 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c | |||
| @@ -260,7 +260,7 @@ long ppc_newuname(struct new_utsname __user * name) | |||
| 260 | int err = 0; | 260 | int err = 0; |
| 261 | 261 | ||
| 262 | down_read(&uts_sem); | 262 | down_read(&uts_sem); |
| 263 | if (copy_to_user(name, &system_utsname, sizeof(*name))) | 263 | if (copy_to_user(name, utsname(), sizeof(*name))) |
| 264 | err = -EFAULT; | 264 | err = -EFAULT; |
| 265 | up_read(&uts_sem); | 265 | up_read(&uts_sem); |
| 266 | if (!err) | 266 | if (!err) |
| @@ -273,7 +273,7 @@ int sys_uname(struct old_utsname __user *name) | |||
| 273 | int err = 0; | 273 | int err = 0; |
| 274 | 274 | ||
| 275 | down_read(&uts_sem); | 275 | down_read(&uts_sem); |
| 276 | if (copy_to_user(name, &system_utsname, sizeof(*name))) | 276 | if (copy_to_user(name, utsname(), sizeof(*name))) |
| 277 | err = -EFAULT; | 277 | err = -EFAULT; |
| 278 | up_read(&uts_sem); | 278 | up_read(&uts_sem); |
| 279 | if (!err) | 279 | if (!err) |
| @@ -289,19 +289,19 @@ int sys_olduname(struct oldold_utsname __user *name) | |||
| 289 | return -EFAULT; | 289 | return -EFAULT; |
| 290 | 290 | ||
| 291 | down_read(&uts_sem); | 291 | down_read(&uts_sem); |
| 292 | error = __copy_to_user(&name->sysname, &system_utsname.sysname, | 292 | error = __copy_to_user(&name->sysname, &utsname()->sysname, |
| 293 | __OLD_UTS_LEN); | 293 | __OLD_UTS_LEN); |
| 294 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); | 294 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); |
| 295 | error |= __copy_to_user(&name->nodename, &system_utsname.nodename, | 295 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, |
| 296 | __OLD_UTS_LEN); | 296 | __OLD_UTS_LEN); |
| 297 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); | 297 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); |
| 298 | error |= __copy_to_user(&name->release, &system_utsname.release, | 298 | error |= __copy_to_user(&name->release, &utsname()->release, |
| 299 | __OLD_UTS_LEN); | 299 | __OLD_UTS_LEN); |
| 300 | error |= __put_user(0, name->release + __OLD_UTS_LEN); | 300 | error |= __put_user(0, name->release + __OLD_UTS_LEN); |
| 301 | error |= __copy_to_user(&name->version, &system_utsname.version, | 301 | error |= __copy_to_user(&name->version, &utsname()->version, |
| 302 | __OLD_UTS_LEN); | 302 | __OLD_UTS_LEN); |
| 303 | error |= __put_user(0, name->version + __OLD_UTS_LEN); | 303 | error |= __put_user(0, name->version + __OLD_UTS_LEN); |
| 304 | error |= __copy_to_user(&name->machine, &system_utsname.machine, | 304 | error |= __copy_to_user(&name->machine, &utsname()->machine, |
| 305 | __OLD_UTS_LEN); | 305 | __OLD_UTS_LEN); |
| 306 | error |= override_machine(name->machine); | 306 | error |= override_machine(name->machine); |
| 307 | up_read(&uts_sem); | 307 | up_read(&uts_sem); |
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 1a2c2a50f922..1983b640bac1 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c | |||
| @@ -357,7 +357,7 @@ static int dma_and_signal_ce_msg(char *ce_msg, | |||
| 357 | */ | 357 | */ |
| 358 | static int shutdown(void) | 358 | static int shutdown(void) |
| 359 | { | 359 | { |
| 360 | int rc = kill_proc(1, SIGINT, 1); | 360 | int rc = kill_cad_pid(SIGINT, 1); |
| 361 | 361 | ||
| 362 | if (rc) { | 362 | if (rc) { |
| 363 | printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " | 363 | printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 8ed362140452..98189d8efaca 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
| @@ -342,7 +342,7 @@ static int __init pSeries_init_panel(void) | |||
| 342 | { | 342 | { |
| 343 | /* Manually leave the kernel version on the panel. */ | 343 | /* Manually leave the kernel version on the panel. */ |
| 344 | ppc_md.progress("Linux ppc64\n", 0); | 344 | ppc_md.progress("Linux ppc64\n", 0); |
| 345 | ppc_md.progress(system_utsname.release, 0); | 345 | ppc_md.progress(init_utsname()->version, 0); |
| 346 | 346 | ||
| 347 | return 0; | 347 | return 0; |
| 348 | } | 348 | } |
diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c index b81a367dc278..87fe9a89dba7 100644 --- a/arch/ppc/4xx_io/serial_sicc.c +++ b/arch/ppc/4xx_io/serial_sicc.c | |||
| @@ -1720,7 +1720,7 @@ static int siccuart_open(struct tty_struct *tty, struct file *filp) | |||
| 1720 | return 0; | 1720 | return 0; |
| 1721 | } | 1721 | } |
| 1722 | 1722 | ||
| 1723 | static struct tty_operations sicc_ops = { | 1723 | static const struct tty_operations sicc_ops = { |
| 1724 | .open = siccuart_open, | 1724 | .open = siccuart_open, |
| 1725 | .close = siccuart_close, | 1725 | .close = siccuart_close, |
| 1726 | .write = siccuart_write, | 1726 | .write = siccuart_write, |
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 50b4bbd06804..5f6684012ded 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S | |||
| @@ -942,20 +942,16 @@ _GLOBAL(kernel_thread) | |||
| 942 | addi r1,r1,16 | 942 | addi r1,r1,16 |
| 943 | blr | 943 | blr |
| 944 | 944 | ||
| 945 | _GLOBAL(kernel_execve) | ||
| 946 | li r0,__NR_execve | ||
| 947 | sc | ||
| 948 | bnslr | ||
| 949 | neg r3,r3 | ||
| 950 | blr | ||
| 951 | |||
| 945 | /* | 952 | /* |
| 946 | * This routine is just here to keep GCC happy - sigh... | 953 | * This routine is just here to keep GCC happy - sigh... |
| 947 | */ | 954 | */ |
| 948 | _GLOBAL(__main) | 955 | _GLOBAL(__main) |
| 949 | blr | 956 | blr |
| 950 | 957 | ||
| 951 | #define SYSCALL(name) \ | ||
| 952 | _GLOBAL(name) \ | ||
| 953 | li r0,__NR_##name; \ | ||
| 954 | sc; \ | ||
| 955 | bnslr; \ | ||
| 956 | lis r4,errno@ha; \ | ||
| 957 | stw r3,errno@l(r4); \ | ||
| 958 | li r3,-1; \ | ||
| 959 | blr | ||
| 960 | |||
| 961 | SYSCALL(execve) | ||
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index ca28fb0b3790..4d9ff5ce4cbd 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
| @@ -369,11 +369,12 @@ void __kprobes kretprobe_trampoline_holder(void) | |||
| 369 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 369 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
| 370 | { | 370 | { |
| 371 | struct kretprobe_instance *ri = NULL; | 371 | struct kretprobe_instance *ri = NULL; |
| 372 | struct hlist_head *head; | 372 | struct hlist_head *head, empty_rp; |
| 373 | struct hlist_node *node, *tmp; | 373 | struct hlist_node *node, *tmp; |
| 374 | unsigned long flags, orig_ret_address = 0; | 374 | unsigned long flags, orig_ret_address = 0; |
| 375 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; | 375 | unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; |
| 376 | 376 | ||
| 377 | INIT_HLIST_HEAD(&empty_rp); | ||
| 377 | spin_lock_irqsave(&kretprobe_lock, flags); | 378 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 378 | head = kretprobe_inst_table_head(current); | 379 | head = kretprobe_inst_table_head(current); |
| 379 | 380 | ||
| @@ -399,7 +400,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 399 | ri->rp->handler(ri, regs); | 400 | ri->rp->handler(ri, regs); |
| 400 | 401 | ||
| 401 | orig_ret_address = (unsigned long)ri->ret_addr; | 402 | orig_ret_address = (unsigned long)ri->ret_addr; |
| 402 | recycle_rp_inst(ri); | 403 | recycle_rp_inst(ri, &empty_rp); |
| 403 | 404 | ||
| 404 | if (orig_ret_address != trampoline_address) { | 405 | if (orig_ret_address != trampoline_address) { |
| 405 | /* | 406 | /* |
| @@ -417,6 +418,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 417 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 418 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 418 | preempt_enable_no_resched(); | 419 | preempt_enable_no_resched(); |
| 419 | 420 | ||
| 421 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
| 422 | hlist_del(&ri->hlist); | ||
| 423 | kfree(ri); | ||
| 424 | } | ||
| 420 | /* | 425 | /* |
| 421 | * By returning a non-zero value, we are telling | 426 | * By returning a non-zero value, we are telling |
| 422 | * kprobe_handler() that we don't want the post_handler | 427 | * kprobe_handler() that we don't want the post_handler |
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index e351780bb660..584ed95f3380 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/file.h> | 27 | #include <linux/file.h> |
| 28 | #include <linux/utsname.h> | 28 | #include <linux/utsname.h> |
| 29 | #include <linux/personality.h> | 29 | #include <linux/personality.h> |
| 30 | #include <linux/unistd.h> | ||
| 30 | 31 | ||
| 31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 32 | #include <asm/ipc.h> | 33 | #include <asm/ipc.h> |
| @@ -266,3 +267,22 @@ s390_fadvise64_64(struct fadvise64_64_args __user *args) | |||
| 266 | return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice); | 267 | return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice); |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 270 | /* | ||
| 271 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 272 | * end up with proper pt_regs. | ||
| 273 | */ | ||
| 274 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 275 | { | ||
| 276 | register const char *__arg1 asm("2") = filename; | ||
| 277 | register char *const*__arg2 asm("3") = argv; | ||
| 278 | register char *const*__arg3 asm("4") = envp; | ||
| 279 | register long __svcres asm("2"); | ||
| 280 | asm volatile( | ||
| 281 | "svc %b1" | ||
| 282 | : "=d" (__svcres) | ||
| 283 | : "i" (__NR_execve), | ||
| 284 | "0" (__arg1), | ||
| 285 | "d" (__arg2), | ||
| 286 | "d" (__arg3) : "memory"); | ||
| 287 | return __svcres; | ||
| 288 | } | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 5f587332234a..77491cf9b259 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
| @@ -459,7 +459,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 459 | seq_printf(m, "machine\t\t: %s\n", get_system_type()); | 459 | seq_printf(m, "machine\t\t: %s\n", get_system_type()); |
| 460 | 460 | ||
| 461 | seq_printf(m, "processor\t: %d\n", cpu); | 461 | seq_printf(m, "processor\t: %d\n", cpu); |
| 462 | seq_printf(m, "cpu family\t: %s\n", system_utsname.machine); | 462 | seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine); |
| 463 | seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype()); | 463 | seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype()); |
| 464 | 464 | ||
| 465 | show_cpuflags(m); | 465 | show_cpuflags(m); |
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 6c0fb7c4af11..dbebaddcfe39 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c | |||
| @@ -42,6 +42,7 @@ cpumask_t cpu_possible_map; | |||
| 42 | EXPORT_SYMBOL(cpu_possible_map); | 42 | EXPORT_SYMBOL(cpu_possible_map); |
| 43 | 43 | ||
| 44 | cpumask_t cpu_online_map; | 44 | cpumask_t cpu_online_map; |
| 45 | EXPORT_SYMBOL(cpu_online_map); | ||
| 45 | static atomic_t cpus_booted = ATOMIC_INIT(0); | 46 | static atomic_t cpus_booted = ATOMIC_INIT(0); |
| 46 | 47 | ||
| 47 | /* These are defined by the board-specific code. */ | 48 | /* These are defined by the board-specific code. */ |
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index b68ff705f067..8fde95001c34 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
| 26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
| 27 | #include <asm/ipc.h> | 27 | #include <asm/ipc.h> |
| 28 | #include <asm/unistd.h> | ||
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| 30 | * sys_pipe() is the normal C calling standard for creating | 31 | * sys_pipe() is the normal C calling standard for creating |
| @@ -281,7 +282,7 @@ asmlinkage int sys_uname(struct old_utsname * name) | |||
| 281 | if (!name) | 282 | if (!name) |
| 282 | return -EFAULT; | 283 | return -EFAULT; |
| 283 | down_read(&uts_sem); | 284 | down_read(&uts_sem); |
| 284 | err=copy_to_user(name, &system_utsname, sizeof (*name)); | 285 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 285 | up_read(&uts_sem); | 286 | up_read(&uts_sem); |
| 286 | return err?-EFAULT:0; | 287 | return err?-EFAULT:0; |
| 287 | } | 288 | } |
| @@ -309,3 +310,19 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, | |||
| 309 | (u64)len0 << 32 | len1, advice); | 310 | (u64)len0 << 32 | len1, advice); |
| 310 | #endif | 311 | #endif |
| 311 | } | 312 | } |
| 313 | |||
| 314 | /* | ||
| 315 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 316 | * end up with proper pt_regs. | ||
| 317 | */ | ||
| 318 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 319 | { | ||
| 320 | register long __sc0 __asm__ ("r3") = __NR_execve; | ||
| 321 | register long __sc4 __asm__ ("r4") = (long) filename; | ||
| 322 | register long __sc5 __asm__ ("r5") = (long) argv; | ||
| 323 | register long __sc6 __asm__ ("r6") = (long) envp; | ||
| 324 | __asm__ __volatile__ ("trapa #0x13" : "=z" (__sc0) | ||
| 325 | : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) | ||
| 326 | : "memory"); | ||
| 327 | return __sc0; | ||
| 328 | } | ||
diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c index db475b7833fb..525d0ec19b78 100644 --- a/arch/sh64/kernel/process.c +++ b/arch/sh64/kernel/process.c | |||
| @@ -20,261 +20,16 @@ | |||
| 20 | /* | 20 | /* |
| 21 | * This file handles the architecture-dependent parts of process handling.. | 21 | * This file handles the architecture-dependent parts of process handling.. |
| 22 | */ | 22 | */ |
| 23 | |||
| 24 | /* Temporary flags/tests. All to be removed/undefined. BEGIN */ | ||
| 25 | #define IDLE_TRACE | ||
| 26 | #define VM_SHOW_TABLES | ||
| 27 | #define VM_TEST_FAULT | ||
| 28 | #define VM_TEST_RTLBMISS | ||
| 29 | #define VM_TEST_WTLBMISS | ||
| 30 | |||
| 31 | #undef VM_SHOW_TABLES | ||
| 32 | #undef IDLE_TRACE | ||
| 33 | /* Temporary flags/tests. All to be removed/undefined. END */ | ||
| 34 | |||
| 35 | #define __KERNEL_SYSCALLS__ | ||
| 36 | #include <stdarg.h> | ||
| 37 | |||
| 38 | #include <linux/kernel.h> | ||
| 39 | #include <linux/rwsem.h> | ||
| 40 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
| 41 | #include <linux/smp.h> | ||
| 42 | #include <linux/smp_lock.h> | ||
| 43 | #include <linux/ptrace.h> | 24 | #include <linux/ptrace.h> |
| 44 | #include <linux/slab.h> | ||
| 45 | #include <linux/vmalloc.h> | ||
| 46 | #include <linux/user.h> | ||
| 47 | #include <linux/a.out.h> | ||
| 48 | #include <linux/interrupt.h> | ||
| 49 | #include <linux/unistd.h> | ||
| 50 | #include <linux/delay.h> | ||
| 51 | #include <linux/reboot.h> | 25 | #include <linux/reboot.h> |
| 52 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 53 | 27 | #include <linux/module.h> | |
| 54 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
| 55 | #include <asm/pgtable.h> | 29 | #include <asm/pgtable.h> |
| 56 | #include <asm/system.h> | ||
| 57 | #include <asm/io.h> | ||
| 58 | #include <asm/processor.h> /* includes also <asm/registers.h> */ | ||
| 59 | #include <asm/mmu_context.h> | ||
| 60 | #include <asm/elf.h> | ||
| 61 | #include <asm/page.h> | ||
| 62 | |||
| 63 | #include <linux/irq.h> | ||
| 64 | 30 | ||
| 65 | struct task_struct *last_task_used_math = NULL; | 31 | struct task_struct *last_task_used_math = NULL; |
| 66 | 32 | ||
| 67 | #ifdef IDLE_TRACE | ||
| 68 | #ifdef VM_SHOW_TABLES | ||
| 69 | /* For testing */ | ||
| 70 | static void print_PTE(long base) | ||
| 71 | { | ||
| 72 | int i, skip=0; | ||
| 73 | long long x, y, *p = (long long *) base; | ||
| 74 | |||
| 75 | for (i=0; i< 512; i++, p++){ | ||
| 76 | if (*p == 0) { | ||
| 77 | if (!skip) { | ||
| 78 | skip++; | ||
| 79 | printk("(0s) "); | ||
| 80 | } | ||
| 81 | } else { | ||
| 82 | skip=0; | ||
| 83 | x = (*p) >> 32; | ||
| 84 | y = (*p) & 0xffffffff; | ||
| 85 | printk("%08Lx%08Lx ", x, y); | ||
| 86 | if (!((i+1)&0x3)) printk("\n"); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | /* For testing */ | ||
| 92 | static void print_DIR(long base) | ||
| 93 | { | ||
| 94 | int i, skip=0; | ||
| 95 | long *p = (long *) base; | ||
| 96 | |||
| 97 | for (i=0; i< 512; i++, p++){ | ||
| 98 | if (*p == 0) { | ||
| 99 | if (!skip) { | ||
| 100 | skip++; | ||
| 101 | printk("(0s) "); | ||
| 102 | } | ||
| 103 | } else { | ||
| 104 | skip=0; | ||
| 105 | printk("%08lx ", *p); | ||
| 106 | if (!((i+1)&0x7)) printk("\n"); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | /* For testing */ | ||
| 112 | static void print_vmalloc_first_tables(void) | ||
| 113 | { | ||
| 114 | |||
| 115 | #define PRESENT 0x800 /* Bit 11 */ | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Do it really dirty by looking at raw addresses, | ||
| 119 | * raw offsets, no types. If we used pgtable/pgalloc | ||
| 120 | * macros/definitions we could hide potential bugs. | ||
| 121 | * | ||
| 122 | * Note that pointers are 32-bit for CDC. | ||
| 123 | */ | ||
| 124 | long pgdt, pmdt, ptet; | ||
| 125 | |||
| 126 | pgdt = (long) &swapper_pg_dir; | ||
| 127 | printk("-->PGD (0x%08lx):\n", pgdt); | ||
| 128 | print_DIR(pgdt); | ||
| 129 | printk("\n"); | ||
| 130 | |||
| 131 | /* VMALLOC pool is mapped at 0xc0000000, second (pointer) entry in PGD */ | ||
| 132 | pgdt += 4; | ||
| 133 | pmdt = (long) (* (long *) pgdt); | ||
| 134 | if (!(pmdt & PRESENT)) { | ||
| 135 | printk("No PMD\n"); | ||
| 136 | return; | ||
| 137 | } else pmdt &= 0xfffff000; | ||
| 138 | |||
| 139 | printk("-->PMD (0x%08lx):\n", pmdt); | ||
| 140 | print_DIR(pmdt); | ||
| 141 | printk("\n"); | ||
| 142 | |||
| 143 | /* Get the pmdt displacement for 0xc0000000 */ | ||
| 144 | pmdt += 2048; | ||
| 145 | |||
| 146 | /* just look at first two address ranges ... */ | ||
| 147 | /* ... 0xc0000000 ... */ | ||
| 148 | ptet = (long) (* (long *) pmdt); | ||
| 149 | if (!(ptet & PRESENT)) { | ||
| 150 | printk("No PTE0\n"); | ||
| 151 | return; | ||
| 152 | } else ptet &= 0xfffff000; | ||
| 153 | |||
| 154 | printk("-->PTE0 (0x%08lx):\n", ptet); | ||
| 155 | print_PTE(ptet); | ||
| 156 | printk("\n"); | ||
| 157 | |||
| 158 | /* ... 0xc0001000 ... */ | ||
| 159 | ptet += 4; | ||
| 160 | if (!(ptet & PRESENT)) { | ||
| 161 | printk("No PTE1\n"); | ||
| 162 | return; | ||
| 163 | } else ptet &= 0xfffff000; | ||
| 164 | printk("-->PTE1 (0x%08lx):\n", ptet); | ||
| 165 | print_PTE(ptet); | ||
| 166 | printk("\n"); | ||
| 167 | } | ||
| 168 | #else | ||
| 169 | #define print_vmalloc_first_tables() | ||
| 170 | #endif /* VM_SHOW_TABLES */ | ||
| 171 | |||
| 172 | static void test_VM(void) | ||
| 173 | { | ||
| 174 | void *a, *b, *c; | ||
| 175 | |||
| 176 | #ifdef VM_SHOW_TABLES | ||
| 177 | printk("Initial PGD/PMD/PTE\n"); | ||
| 178 | #endif | ||
| 179 | print_vmalloc_first_tables(); | ||
| 180 | |||
| 181 | printk("Allocating 2 bytes\n"); | ||
| 182 | a = vmalloc(2); | ||
| 183 | print_vmalloc_first_tables(); | ||
| 184 | |||
| 185 | printk("Allocating 4100 bytes\n"); | ||
| 186 | b = vmalloc(4100); | ||
| 187 | print_vmalloc_first_tables(); | ||
| 188 | |||
| 189 | printk("Allocating 20234 bytes\n"); | ||
| 190 | c = vmalloc(20234); | ||
| 191 | print_vmalloc_first_tables(); | ||
| 192 | |||
| 193 | #ifdef VM_TEST_FAULT | ||
| 194 | /* Here you may want to fault ! */ | ||
| 195 | |||
| 196 | #ifdef VM_TEST_RTLBMISS | ||
| 197 | printk("Ready to fault upon read.\n"); | ||
| 198 | if (* (char *) a) { | ||
| 199 | printk("RTLBMISSed on area a !\n"); | ||
| 200 | } | ||
| 201 | printk("RTLBMISSed on area a !\n"); | ||
| 202 | #endif | ||
| 203 | |||
| 204 | #ifdef VM_TEST_WTLBMISS | ||
| 205 | printk("Ready to fault upon write.\n"); | ||
| 206 | *((char *) b) = 'L'; | ||
| 207 | printk("WTLBMISSed on area b !\n"); | ||
| 208 | #endif | ||
| 209 | |||
| 210 | #endif /* VM_TEST_FAULT */ | ||
| 211 | |||
| 212 | printk("Deallocating the 4100 byte chunk\n"); | ||
| 213 | vfree(b); | ||
| 214 | print_vmalloc_first_tables(); | ||
| 215 | |||
| 216 | printk("Deallocating the 2 byte chunk\n"); | ||
| 217 | vfree(a); | ||
| 218 | print_vmalloc_first_tables(); | ||
| 219 | |||
| 220 | printk("Deallocating the last chunk\n"); | ||
| 221 | vfree(c); | ||
| 222 | print_vmalloc_first_tables(); | ||
| 223 | } | ||
| 224 | |||
| 225 | extern unsigned long volatile jiffies; | ||
| 226 | int once = 0; | ||
| 227 | unsigned long old_jiffies; | ||
| 228 | int pid = -1, pgid = -1; | ||
| 229 | |||
| 230 | void idle_trace(void) | ||
| 231 | { | ||
| 232 | |||
| 233 | _syscall0(int, getpid) | ||
| 234 | _syscall1(int, getpgid, int, pid) | ||
| 235 | |||
| 236 | if (!once) { | ||
| 237 | /* VM allocation/deallocation simple test */ | ||
| 238 | test_VM(); | ||
| 239 | pid = getpid(); | ||
| 240 | |||
| 241 | printk("Got all through to Idle !!\n"); | ||
| 242 | printk("I'm now going to loop forever ...\n"); | ||
| 243 | printk("Any ! below is a timer tick.\n"); | ||
| 244 | printk("Any . below is a getpgid system call from pid = %d.\n", pid); | ||
| 245 | |||
| 246 | |||
| 247 | old_jiffies = jiffies; | ||
| 248 | once++; | ||
| 249 | } | ||
| 250 | |||
| 251 | if (old_jiffies != jiffies) { | ||
| 252 | old_jiffies = jiffies - old_jiffies; | ||
| 253 | switch (old_jiffies) { | ||
| 254 | case 1: | ||
| 255 | printk("!"); | ||
| 256 | break; | ||
| 257 | case 2: | ||
| 258 | printk("!!"); | ||
| 259 | break; | ||
| 260 | case 3: | ||
| 261 | printk("!!!"); | ||
| 262 | break; | ||
| 263 | case 4: | ||
| 264 | printk("!!!!"); | ||
| 265 | break; | ||
| 266 | default: | ||
| 267 | printk("(%d!)", (int) old_jiffies); | ||
| 268 | } | ||
| 269 | old_jiffies = jiffies; | ||
| 270 | } | ||
| 271 | pgid = getpgid(pid); | ||
| 272 | printk("."); | ||
| 273 | } | ||
| 274 | #else | ||
| 275 | #define idle_trace() do { } while (0) | ||
| 276 | #endif /* IDLE_TRACE */ | ||
| 277 | |||
| 278 | static int hlt_counter = 1; | 33 | static int hlt_counter = 1; |
| 279 | 34 | ||
| 280 | #define HARD_IDLE_TIMEOUT (HZ / 3) | 35 | #define HARD_IDLE_TIMEOUT (HZ / 3) |
| @@ -323,7 +78,6 @@ void cpu_idle(void) | |||
| 323 | local_irq_disable(); | 78 | local_irq_disable(); |
| 324 | while (!need_resched()) { | 79 | while (!need_resched()) { |
| 325 | local_irq_enable(); | 80 | local_irq_enable(); |
| 326 | idle_trace(); | ||
| 327 | hlt(); | 81 | hlt(); |
| 328 | local_irq_disable(); | 82 | local_irq_disable(); |
| 329 | } | 83 | } |
| @@ -622,6 +376,10 @@ void free_task_struct(struct task_struct *p) | |||
| 622 | /* | 376 | /* |
| 623 | * Create a kernel thread | 377 | * Create a kernel thread |
| 624 | */ | 378 | */ |
| 379 | ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *)) | ||
| 380 | { | ||
| 381 | do_exit(fn(arg)); | ||
| 382 | } | ||
| 625 | 383 | ||
| 626 | /* | 384 | /* |
| 627 | * This is the mechanism for creating a new kernel thread. | 385 | * This is the mechanism for creating a new kernel thread. |
| @@ -633,19 +391,17 @@ void free_task_struct(struct task_struct *p) | |||
| 633 | */ | 391 | */ |
| 634 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | 392 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) |
| 635 | { | 393 | { |
| 636 | /* A bit less processor dependent than older sh ... */ | 394 | struct pt_regs regs; |
| 637 | unsigned int reply; | ||
| 638 | 395 | ||
| 639 | static __inline__ _syscall2(int,clone,unsigned long,flags,unsigned long,newsp) | 396 | memset(®s, 0, sizeof(regs)); |
| 640 | static __inline__ _syscall1(int,exit,int,ret) | 397 | regs.regs[2] = (unsigned long)arg; |
| 398 | regs.regs[3] = (unsigned long)fn; | ||
| 641 | 399 | ||
| 642 | reply = clone(flags | CLONE_VM, 0); | 400 | regs.pc = (unsigned long)kernel_thread_helper; |
| 643 | if (!reply) { | 401 | regs.sr = (1 << 30); |
| 644 | /* Child */ | ||
| 645 | reply = exit(fn(arg)); | ||
| 646 | } | ||
| 647 | 402 | ||
| 648 | return reply; | 403 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, |
| 404 | ®s, 0, NULL, NULL); | ||
| 649 | } | 405 | } |
| 650 | 406 | ||
| 651 | /* | 407 | /* |
diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c index 58ff7d522d81..ad0fa4e003e7 100644 --- a/arch/sh64/kernel/sys_sh64.c +++ b/arch/sh64/kernel/sys_sh64.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 33 | #include <asm/ipc.h> | 33 | #include <asm/ipc.h> |
| 34 | #include <asm/ptrace.h> | 34 | #include <asm/ptrace.h> |
| 35 | #include <asm/unistd.h> | ||
| 35 | 36 | ||
| 36 | #define REG_3 3 | 37 | #define REG_3 3 |
| 37 | 38 | ||
| @@ -279,7 +280,25 @@ asmlinkage int sys_uname(struct old_utsname * name) | |||
| 279 | if (!name) | 280 | if (!name) |
| 280 | return -EFAULT; | 281 | return -EFAULT; |
| 281 | down_read(&uts_sem); | 282 | down_read(&uts_sem); |
| 282 | err=copy_to_user(name, &system_utsname, sizeof (*name)); | 283 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 283 | up_read(&uts_sem); | 284 | up_read(&uts_sem); |
| 284 | return err?-EFAULT:0; | 285 | return err?-EFAULT:0; |
| 285 | } | 286 | } |
| 287 | |||
| 288 | /* | ||
| 289 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 290 | * end up with proper pt_regs. | ||
| 291 | */ | ||
| 292 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 293 | { | ||
| 294 | register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve); | ||
| 295 | register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename; | ||
| 296 | register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv; | ||
| 297 | register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp; | ||
| 298 | __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)" | ||
| 299 | : "=r" (__sc0) | ||
| 300 | : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) ); | ||
| 301 | __asm__ __volatile__ ("!dummy %0 %1 %2 %3" | ||
| 302 | : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory"); | ||
| 303 | return __sc0; | ||
| 304 | } | ||
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 896863fb208a..a954a0c00000 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
| 26 | #include <asm/ipc.h> | 26 | #include <asm/ipc.h> |
| 27 | #include <asm/unistd.h> | ||
| 27 | 28 | ||
| 28 | /* #define DEBUG_UNIMP_SYSCALL */ | 29 | /* #define DEBUG_UNIMP_SYSCALL */ |
| 29 | 30 | ||
| @@ -475,16 +476,38 @@ asmlinkage int sys_getdomainname(char __user *name, int len) | |||
| 475 | 476 | ||
| 476 | down_read(&uts_sem); | 477 | down_read(&uts_sem); |
| 477 | 478 | ||
| 478 | nlen = strlen(system_utsname.domainname) + 1; | 479 | nlen = strlen(utsname()->domainname) + 1; |
| 479 | err = -EINVAL; | 480 | err = -EINVAL; |
| 480 | if (nlen > len) | 481 | if (nlen > len) |
| 481 | goto out; | 482 | goto out; |
| 482 | 483 | ||
| 483 | err = -EFAULT; | 484 | err = -EFAULT; |
| 484 | if (!copy_to_user(name, system_utsname.domainname, nlen)) | 485 | if (!copy_to_user(name, utsname()->domainname, nlen)) |
| 485 | err = 0; | 486 | err = 0; |
| 486 | 487 | ||
| 487 | out: | 488 | out: |
| 488 | up_read(&uts_sem); | 489 | up_read(&uts_sem); |
| 489 | return err; | 490 | return err; |
| 490 | } | 491 | } |
| 492 | |||
| 493 | /* | ||
| 494 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 495 | * end up with proper pt_regs. | ||
| 496 | */ | ||
| 497 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 498 | { | ||
| 499 | long __res; | ||
| 500 | register long __g1 __asm__ ("g1") = __NR_execve; | ||
| 501 | register long __o0 __asm__ ("o0") = (long)(filename); | ||
| 502 | register long __o1 __asm__ ("o1") = (long)(argv); | ||
| 503 | register long __o2 __asm__ ("o2") = (long)(envp); | ||
| 504 | asm volatile ("t 0x10\n\t" | ||
| 505 | "bcc 1f\n\t" | ||
| 506 | "mov %%o0, %0\n\t" | ||
| 507 | "sub %%g0, %%o0, %0\n\t" | ||
| 508 | "1:\n\t" | ||
| 509 | : "=r" (__res), "=&r" (__o0) | ||
| 510 | : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) | ||
| 511 | : "cc"); | ||
| 512 | return __res; | ||
| 513 | } | ||
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index aa0fb2efb615..9d2cd97d1c3a 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c | |||
| @@ -483,13 +483,18 @@ asmlinkage int sunos_uname(struct sunos_utsname __user *name) | |||
| 483 | { | 483 | { |
| 484 | int ret; | 484 | int ret; |
| 485 | down_read(&uts_sem); | 485 | down_read(&uts_sem); |
| 486 | ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); | 486 | ret = copy_to_user(&name->sname[0], &utsname()->sysname[0], |
| 487 | sizeof(name->sname) - 1); | ||
| 487 | if (!ret) { | 488 | if (!ret) { |
| 488 | ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); | 489 | ret |= __copy_to_user(&name->nname[0], &utsname()->nodename[0], |
| 490 | sizeof(name->nname) - 1); | ||
| 489 | ret |= __put_user('\0', &name->nname[8]); | 491 | ret |= __put_user('\0', &name->nname[8]); |
| 490 | ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); | 492 | ret |= __copy_to_user(&name->rel[0], &utsname()->release[0], |
| 491 | ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); | 493 | sizeof(name->rel) - 1); |
| 492 | ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); | 494 | ret |= __copy_to_user(&name->ver[0], &utsname()->version[0], |
| 495 | sizeof(name->ver) - 1); | ||
| 496 | ret |= __copy_to_user(&name->mach[0], &utsname()->machine[0], | ||
| 497 | sizeof(name->mach) - 1); | ||
| 493 | } | 498 | } |
| 494 | up_read(&uts_sem); | 499 | up_read(&uts_sem); |
| 495 | return ret ? -EFAULT : 0; | 500 | return ret ? -EFAULT : 0; |
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 8d8ca716f7a7..b627f8dbcaad 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig | |||
| @@ -420,7 +420,7 @@ source "arch/sparc64/oprofile/Kconfig" | |||
| 420 | 420 | ||
| 421 | config KPROBES | 421 | config KPROBES |
| 422 | bool "Kprobes (EXPERIMENTAL)" | 422 | bool "Kprobes (EXPERIMENTAL)" |
| 423 | depends on EXPERIMENTAL && MODULES | 423 | depends on KALLSYMS && EXPERIMENTAL && MODULES |
| 424 | help | 424 | help |
| 425 | Kprobes allows you to trap at almost any kernel address and | 425 | Kprobes allows you to trap at almost any kernel address and |
| 426 | execute a callback function. register_kprobe() establishes | 426 | execute a callback function. register_kprobe() establishes |
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index e55466c77b61..0b9c70627ce4 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c | |||
| @@ -4,8 +4,6 @@ | |||
| 4 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) | 4 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #define __KERNEL_SYSCALLS__ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| 10 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 11 | #include <linux/init.h> | 9 | #include <linux/init.h> |
| @@ -14,6 +12,7 @@ | |||
| 14 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
| 15 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 16 | #include <linux/pm.h> | 14 | #include <linux/pm.h> |
| 15 | #include <linux/syscalls.h> | ||
| 17 | 16 | ||
| 18 | #include <asm/system.h> | 17 | #include <asm/system.h> |
| 19 | #include <asm/auxio.h> | 18 | #include <asm/auxio.h> |
| @@ -98,7 +97,7 @@ again: | |||
| 98 | 97 | ||
| 99 | /* Ok, down we go... */ | 98 | /* Ok, down we go... */ |
| 100 | button_pressed = 0; | 99 | button_pressed = 0; |
| 101 | if (execve("/sbin/shutdown", argv, envp) < 0) { | 100 | if (kernel_execve("/sbin/shutdown", argv, envp) < 0) { |
| 102 | printk("powerd: shutdown execution failed\n"); | 101 | printk("powerd: shutdown execution failed\n"); |
| 103 | add_wait_queue(&powerd_wait, &wait); | 102 | add_wait_queue(&powerd_wait, &wait); |
| 104 | goto again; | 103 | goto again; |
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index c608c947e6c3..a53d4abb4b49 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <asm/utrap.h> | 31 | #include <asm/utrap.h> |
| 32 | #include <asm/perfctr.h> | 32 | #include <asm/perfctr.h> |
| 33 | #include <asm/a.out.h> | 33 | #include <asm/a.out.h> |
| 34 | #include <asm/unistd.h> | ||
| 34 | 35 | ||
| 35 | /* #define DEBUG_UNIMP_SYSCALL */ | 36 | /* #define DEBUG_UNIMP_SYSCALL */ |
| 36 | 37 | ||
| @@ -712,13 +713,13 @@ asmlinkage long sys_getdomainname(char __user *name, int len) | |||
| 712 | 713 | ||
| 713 | down_read(&uts_sem); | 714 | down_read(&uts_sem); |
| 714 | 715 | ||
| 715 | nlen = strlen(system_utsname.domainname) + 1; | 716 | nlen = strlen(utsname()->domainname) + 1; |
| 716 | err = -EINVAL; | 717 | err = -EINVAL; |
| 717 | if (nlen > len) | 718 | if (nlen > len) |
| 718 | goto out; | 719 | goto out; |
| 719 | 720 | ||
| 720 | err = -EFAULT; | 721 | err = -EFAULT; |
| 721 | if (!copy_to_user(name, system_utsname.domainname, nlen)) | 722 | if (!copy_to_user(name, utsname()->domainname, nlen)) |
| 722 | err = 0; | 723 | err = 0; |
| 723 | 724 | ||
| 724 | out: | 725 | out: |
| @@ -963,3 +964,23 @@ asmlinkage long sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, | |||
| 963 | }; | 964 | }; |
| 964 | return err; | 965 | return err; |
| 965 | } | 966 | } |
| 967 | |||
| 968 | /* | ||
| 969 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 970 | * end up with proper pt_regs. | ||
| 971 | */ | ||
| 972 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 973 | { | ||
| 974 | long __res; | ||
| 975 | register long __g1 __asm__ ("g1") = __NR_execve; | ||
| 976 | register long __o0 __asm__ ("o0") = (long)(filename); | ||
| 977 | register long __o1 __asm__ ("o1") = (long)(argv); | ||
| 978 | register long __o2 __asm__ ("o2") = (long)(envp); | ||
| 979 | asm volatile ("t 0x6d\n\t" | ||
| 980 | "sub %%g0, %%o0, %0\n\t" | ||
| 981 | "movcc %%xcc, %%o0, %0\n\t" | ||
| 982 | : "=r" (__res), "=&r" (__o0) | ||
| 983 | : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) | ||
| 984 | : "cc"); | ||
| 985 | return __res; | ||
| 986 | } | ||
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 87ebdf858a3a..953296b73f3f 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c | |||
| @@ -439,16 +439,16 @@ asmlinkage int sunos_uname(struct sunos_utsname __user *name) | |||
| 439 | int ret; | 439 | int ret; |
| 440 | 440 | ||
| 441 | down_read(&uts_sem); | 441 | down_read(&uts_sem); |
| 442 | ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], | 442 | ret = copy_to_user(&name->sname[0], &utsname()->sysname[0], |
| 443 | sizeof(name->sname) - 1); | 443 | sizeof(name->sname) - 1); |
| 444 | ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], | 444 | ret |= copy_to_user(&name->nname[0], &utsname()->nodename[0], |
| 445 | sizeof(name->nname) - 1); | 445 | sizeof(name->nname) - 1); |
| 446 | ret |= put_user('\0', &name->nname[8]); | 446 | ret |= put_user('\0', &name->nname[8]); |
| 447 | ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], | 447 | ret |= copy_to_user(&name->rel[0], &utsname()->release[0], |
| 448 | sizeof(name->rel) - 1); | 448 | sizeof(name->rel) - 1); |
| 449 | ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], | 449 | ret |= copy_to_user(&name->ver[0], &utsname()->version[0], |
| 450 | sizeof(name->ver) - 1); | 450 | sizeof(name->ver) - 1); |
| 451 | ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], | 451 | ret |= copy_to_user(&name->mach[0], &utsname()->machine[0], |
| 452 | sizeof(name->mach) - 1); | 452 | sizeof(name->mach) - 1); |
| 453 | up_read(&uts_sem); | 453 | up_read(&uts_sem); |
| 454 | return (ret ? -EFAULT : 0); | 454 | return (ret ? -EFAULT : 0); |
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 9c581328e76a..9ed997982f8d 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c | |||
| @@ -249,7 +249,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) | |||
| 249 | /* Let's cheat */ | 249 | /* Let's cheat */ |
| 250 | err = set_utsfield(v->sysname, "SunOS", 1, 0); | 250 | err = set_utsfield(v->sysname, "SunOS", 1, 0); |
| 251 | down_read(&uts_sem); | 251 | down_read(&uts_sem); |
| 252 | err |= set_utsfield(v->nodename, system_utsname.nodename, | 252 | err |= set_utsfield(v->nodename, utsname()->nodename, |
| 253 | 1, 1); | 253 | 1, 1); |
| 254 | up_read(&uts_sem); | 254 | up_read(&uts_sem); |
| 255 | err |= set_utsfield(v->release, "2.6", 0, 0); | 255 | err |= set_utsfield(v->release, "2.6", 0, 0); |
| @@ -273,7 +273,7 @@ asmlinkage int solaris_utsname(u32 buf) | |||
| 273 | /* Why should we not lie a bit? */ | 273 | /* Why should we not lie a bit? */ |
| 274 | down_read(&uts_sem); | 274 | down_read(&uts_sem); |
| 275 | err = set_utsfield(v->sysname, "SunOS", 0, 0); | 275 | err = set_utsfield(v->sysname, "SunOS", 0, 0); |
| 276 | err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1); | 276 | err |= set_utsfield(v->nodename, utsname()->nodename, 1, 1); |
| 277 | err |= set_utsfield(v->release, "5.6", 0, 0); | 277 | err |= set_utsfield(v->release, "5.6", 0, 0); |
| 278 | err |= set_utsfield(v->version, "Generic", 0, 0); | 278 | err |= set_utsfield(v->version, "Generic", 0, 0); |
| 279 | err |= set_utsfield(v->machine, machine(), 0, 0); | 279 | err |= set_utsfield(v->machine, machine(), 0, 0); |
| @@ -305,7 +305,7 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count) | |||
| 305 | case SI_HOSTNAME: | 305 | case SI_HOSTNAME: |
| 306 | r = buffer + 256; | 306 | r = buffer + 256; |
| 307 | down_read(&uts_sem); | 307 | down_read(&uts_sem); |
| 308 | for (p = system_utsname.nodename, q = buffer; | 308 | for (p = utsname()->nodename, q = buffer; |
| 309 | q < r && *p && *p != '.'; *q++ = *p++); | 309 | q < r && *p && *p != '.'; *q++ = *p++); |
| 310 | up_read(&uts_sem); | 310 | up_read(&uts_sem); |
| 311 | *q = 0; | 311 | *q = 0; |
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 563ce7690a1e..24747a413785 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
| @@ -642,9 +642,9 @@ int line_remove(struct line *lines, unsigned int num, int n) | |||
| 642 | } | 642 | } |
| 643 | 643 | ||
| 644 | struct tty_driver *line_register_devfs(struct lines *set, | 644 | struct tty_driver *line_register_devfs(struct lines *set, |
| 645 | struct line_driver *line_driver, | 645 | struct line_driver *line_driver, |
| 646 | struct tty_operations *ops, struct line *lines, | 646 | const struct tty_operations *ops, |
| 647 | int nlines) | 647 | struct line *lines, int nlines) |
| 648 | { | 648 | { |
| 649 | int i; | 649 | int i; |
| 650 | struct tty_driver *driver = alloc_tty_driver(nlines); | 650 | struct tty_driver *driver = alloc_tty_driver(nlines); |
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 773a134e7fdb..a67dcbd78de4 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
| @@ -106,9 +106,9 @@ void mconsole_version(struct mc_request *req) | |||
| 106 | { | 106 | { |
| 107 | char version[256]; | 107 | char version[256]; |
| 108 | 108 | ||
| 109 | sprintf(version, "%s %s %s %s %s", system_utsname.sysname, | 109 | sprintf(version, "%s %s %s %s %s", utsname()->sysname, |
| 110 | system_utsname.nodename, system_utsname.release, | 110 | utsname()->nodename, utsname()->release, |
| 111 | system_utsname.version, system_utsname.machine); | 111 | utsname()->version, utsname()->machine); |
| 112 | mconsole_reply(req, version, 0, 0); | 112 | mconsole_reply(req, version, 0, 0); |
| 113 | } | 113 | } |
| 114 | 114 | ||
diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 642c9a0320f9..7be24811bb30 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h | |||
| @@ -91,10 +91,9 @@ extern int line_setup_irq(int fd, int input, int output, struct line *line, | |||
| 91 | void *data); | 91 | void *data); |
| 92 | extern void line_close_chan(struct line *line); | 92 | extern void line_close_chan(struct line *line); |
| 93 | extern struct tty_driver * line_register_devfs(struct lines *set, | 93 | extern struct tty_driver * line_register_devfs(struct lines *set, |
| 94 | struct line_driver *line_driver, | 94 | struct line_driver *line_driver, |
| 95 | struct tty_operations *driver, | 95 | const struct tty_operations *driver, |
| 96 | struct line *lines, | 96 | struct line *lines, int nlines); |
| 97 | int nlines); | ||
| 98 | extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); | 97 | extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); |
| 99 | extern void close_lines(struct line *lines, int nlines); | 98 | extern void close_lines(struct line *lines, int nlines); |
| 100 | 99 | ||
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index 48cf88dd02d4..f5ed8624648b 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c | |||
| @@ -110,7 +110,7 @@ long sys_uname(struct old_utsname __user * name) | |||
| 110 | if (!name) | 110 | if (!name) |
| 111 | return -EFAULT; | 111 | return -EFAULT; |
| 112 | down_read(&uts_sem); | 112 | down_read(&uts_sem); |
| 113 | err = copy_to_user(name, &system_utsname, sizeof (*name)); | 113 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 114 | up_read(&uts_sem); | 114 | up_read(&uts_sem); |
| 115 | return err?-EFAULT:0; | 115 | return err?-EFAULT:0; |
| 116 | } | 116 | } |
| @@ -126,21 +126,21 @@ long sys_olduname(struct oldold_utsname __user * name) | |||
| 126 | 126 | ||
| 127 | down_read(&uts_sem); | 127 | down_read(&uts_sem); |
| 128 | 128 | ||
| 129 | error = __copy_to_user(&name->sysname,&system_utsname.sysname, | 129 | error = __copy_to_user(&name->sysname, &utsname()->sysname, |
| 130 | __OLD_UTS_LEN); | 130 | __OLD_UTS_LEN); |
| 131 | error |= __put_user(0,name->sysname+__OLD_UTS_LEN); | 131 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); |
| 132 | error |= __copy_to_user(&name->nodename,&system_utsname.nodename, | 132 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, |
| 133 | __OLD_UTS_LEN); | 133 | __OLD_UTS_LEN); |
| 134 | error |= __put_user(0,name->nodename+__OLD_UTS_LEN); | 134 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); |
| 135 | error |= __copy_to_user(&name->release,&system_utsname.release, | 135 | error |= __copy_to_user(&name->release, &utsname()->release, |
| 136 | __OLD_UTS_LEN); | 136 | __OLD_UTS_LEN); |
| 137 | error |= __put_user(0,name->release+__OLD_UTS_LEN); | 137 | error |= __put_user(0, name->release + __OLD_UTS_LEN); |
| 138 | error |= __copy_to_user(&name->version,&system_utsname.version, | 138 | error |= __copy_to_user(&name->version, &utsname()->version, |
| 139 | __OLD_UTS_LEN); | 139 | __OLD_UTS_LEN); |
| 140 | error |= __put_user(0,name->version+__OLD_UTS_LEN); | 140 | error |= __put_user(0, name->version + __OLD_UTS_LEN); |
| 141 | error |= __copy_to_user(&name->machine,&system_utsname.machine, | 141 | error |= __copy_to_user(&name->machine, &utsname()->machine, |
| 142 | __OLD_UTS_LEN); | 142 | __OLD_UTS_LEN); |
| 143 | error |= __put_user(0,name->machine+__OLD_UTS_LEN); | 143 | error |= __put_user(0, name->machine + __OLD_UTS_LEN); |
| 144 | 144 | ||
| 145 | up_read(&uts_sem); | 145 | up_read(&uts_sem); |
| 146 | 146 | ||
| @@ -164,3 +164,16 @@ int next_syscall_index(int limit) | |||
| 164 | spin_unlock(&syscall_lock); | 164 | spin_unlock(&syscall_lock); |
| 165 | return(ret); | 165 | return(ret); |
| 166 | } | 166 | } |
| 167 | |||
| 168 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 169 | { | ||
| 170 | mm_segment_t fs; | ||
| 171 | int ret; | ||
| 172 | |||
| 173 | fs = get_fs(); | ||
| 174 | set_fs(KERNEL_DS); | ||
| 175 | ret = um_execve(filename, argv, envp); | ||
| 176 | set_fs(fs); | ||
| 177 | |||
| 178 | return ret; | ||
| 179 | } | ||
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 55005710dcbb..97d88e7902f7 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c | |||
| @@ -167,7 +167,7 @@ static char *usage_string = | |||
| 167 | 167 | ||
| 168 | static int __init uml_version_setup(char *line, int *add) | 168 | static int __init uml_version_setup(char *line, int *add) |
| 169 | { | 169 | { |
| 170 | printf("%s\n", system_utsname.release); | 170 | printf("%s\n", init_utsname()->release); |
| 171 | exit(0); | 171 | exit(0); |
| 172 | 172 | ||
| 173 | return 0; | 173 | return 0; |
| @@ -278,7 +278,7 @@ static int __init Usage(char *line, int *add) | |||
| 278 | { | 278 | { |
| 279 | const char **p; | 279 | const char **p; |
| 280 | 280 | ||
| 281 | printf(usage_string, system_utsname.release); | 281 | printf(usage_string, init_utsname()->release); |
| 282 | p = &__uml_help_start; | 282 | p = &__uml_help_start; |
| 283 | while (p < &__uml_help_end) { | 283 | while (p < &__uml_help_end) { |
| 284 | printf("%s", *p); | 284 | printf("%s", *p); |
| @@ -403,7 +403,7 @@ int linux_main(int argc, char **argv) | |||
| 403 | /* Reserve up to 4M after the current brk */ | 403 | /* Reserve up to 4M after the current brk */ |
| 404 | uml_reserved = ROUND_4M(brk_start) + (1 << 22); | 404 | uml_reserved = ROUND_4M(brk_start) + (1 << 22); |
| 405 | 405 | ||
| 406 | setup_machinename(system_utsname.machine); | 406 | setup_machinename(init_utsname()->machine); |
| 407 | 407 | ||
| 408 | #ifdef CONFIG_CMDLINE_ON_HOST | 408 | #ifdef CONFIG_CMDLINE_ON_HOST |
| 409 | argv1_begin = argv[1]; | 409 | argv1_begin = argv[1]; |
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index ff203625a4bd..51f0893640a6 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <sys/mman.h> | 11 | #include <sys/mman.h> |
| 12 | #include <sys/wait.h> | 12 | #include <sys/wait.h> |
| 13 | #include <sys/mman.h> | 13 | #include <sys/mman.h> |
| 14 | #include <sys/syscall.h> | ||
| 14 | #include "ptrace_user.h" | 15 | #include "ptrace_user.h" |
| 15 | #include "os.h" | 16 | #include "os.h" |
| 16 | #include "user.h" | 17 | #include "user.h" |
| @@ -140,11 +141,9 @@ void os_usr1_process(int pid) | |||
| 140 | * syscalls, and also breaks with clone(), which does not unshare the TLS. | 141 | * syscalls, and also breaks with clone(), which does not unshare the TLS. |
| 141 | */ | 142 | */ |
| 142 | 143 | ||
| 143 | inline _syscall0(pid_t, getpid) | ||
| 144 | |||
| 145 | int os_getpid(void) | 144 | int os_getpid(void) |
| 146 | { | 145 | { |
| 147 | return(getpid()); | 146 | return(syscall(__NR_getpid)); |
| 148 | } | 147 | } |
| 149 | 148 | ||
| 150 | int os_getpgrp(void) | 149 | int os_getpgrp(void) |
diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c index 120abbe4e3ce..6e945ab45843 100644 --- a/arch/um/os-Linux/sys-i386/tls.c +++ b/arch/um/os-Linux/sys-i386/tls.c | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | #include <errno.h> | 1 | #include <errno.h> |
| 2 | #include <linux/unistd.h> | 2 | #include <linux/unistd.h> |
| 3 | #include <sys/syscall.h> | ||
| 3 | #include "sysdep/tls.h" | 4 | #include "sysdep/tls.h" |
| 4 | #include "user_util.h" | 5 | #include "user_util.h" |
| 5 | 6 | ||
| 6 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); | ||
| 7 | |||
| 8 | /* Checks whether host supports TLS, and sets *tls_min according to the value | 7 | /* Checks whether host supports TLS, and sets *tls_min according to the value |
| 9 | * valid on the host. | 8 | * valid on the host. |
| 10 | * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ | 9 | * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ |
| @@ -17,7 +16,7 @@ void check_host_supports_tls(int *supports_tls, int *tls_min) { | |||
| 17 | user_desc_t info; | 16 | user_desc_t info; |
| 18 | info.entry_number = val[i]; | 17 | info.entry_number = val[i]; |
| 19 | 18 | ||
| 20 | if (get_thread_area(&info) == 0) { | 19 | if (syscall(__NR_get_thread_area, &info) == 0) { |
| 21 | *tls_min = val[i]; | 20 | *tls_min = val[i]; |
| 22 | *supports_tls = 1; | 21 | *supports_tls = 1; |
| 23 | return; | 22 | return; |
diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c index 9cb09a45546b..a2de2580b8af 100644 --- a/arch/um/os-Linux/tls.c +++ b/arch/um/os-Linux/tls.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | #include <errno.h> | 1 | #include <errno.h> |
| 2 | #include <sys/ptrace.h> | 2 | #include <sys/ptrace.h> |
| 3 | #include <sys/syscall.h> | ||
| 3 | #include <asm/ldt.h> | 4 | #include <asm/ldt.h> |
| 4 | #include "sysdep/tls.h" | 5 | #include "sysdep/tls.h" |
| 5 | #include "uml-config.h" | 6 | #include "uml-config.h" |
| @@ -48,14 +49,11 @@ int os_get_thread_area(user_desc_t *info, int pid) | |||
| 48 | #ifdef UML_CONFIG_MODE_TT | 49 | #ifdef UML_CONFIG_MODE_TT |
| 49 | #include "linux/unistd.h" | 50 | #include "linux/unistd.h" |
| 50 | 51 | ||
| 51 | static _syscall1(int, get_thread_area, user_desc_t *, u_info); | ||
| 52 | static _syscall1(int, set_thread_area, user_desc_t *, u_info); | ||
| 53 | |||
| 54 | int do_set_thread_area_tt(user_desc_t *info) | 52 | int do_set_thread_area_tt(user_desc_t *info) |
| 55 | { | 53 | { |
| 56 | int ret; | 54 | int ret; |
| 57 | 55 | ||
| 58 | ret = set_thread_area(info); | 56 | ret = syscall(__NR_set_thread_area,info); |
| 59 | if (ret < 0) { | 57 | if (ret < 0) { |
| 60 | ret = -errno; | 58 | ret = -errno; |
| 61 | } | 59 | } |
| @@ -66,7 +64,7 @@ int do_get_thread_area_tt(user_desc_t *info) | |||
| 66 | { | 64 | { |
| 67 | int ret; | 65 | int ret; |
| 68 | 66 | ||
| 69 | ret = get_thread_area(info); | 67 | ret = syscall(__NR_get_thread_area,info); |
| 70 | if (ret < 0) { | 68 | if (ret < 0) { |
| 71 | ret = -errno; | 69 | ret = -errno; |
| 72 | } | 70 | } |
diff --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c index 1b0ad0e4adcd..8e55cd5d3d07 100644 --- a/arch/um/sys-i386/unmap.c +++ b/arch/um/sys-i386/unmap.c | |||
| @@ -5,20 +5,17 @@ | |||
| 5 | 5 | ||
| 6 | #include <linux/mman.h> | 6 | #include <linux/mman.h> |
| 7 | #include <asm/unistd.h> | 7 | #include <asm/unistd.h> |
| 8 | #include <sys/syscall.h> | ||
| 8 | 9 | ||
| 9 | static int errno; | ||
| 10 | |||
| 11 | static inline _syscall2(int,munmap,void *,start,size_t,len) | ||
| 12 | static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) | ||
| 13 | int switcheroo(int fd, int prot, void *from, void *to, int size) | 10 | int switcheroo(int fd, int prot, void *from, void *to, int size) |
| 14 | { | 11 | { |
| 15 | if(munmap(to, size) < 0){ | 12 | if (syscall(__NR_munmap, to, size) < 0){ |
| 16 | return(-1); | 13 | return(-1); |
| 17 | } | 14 | } |
| 18 | if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){ | 15 | if (syscall(__NR_mmap2, to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){ |
| 19 | return(-1); | 16 | return(-1); |
| 20 | } | 17 | } |
| 21 | if(munmap(from, size) < 0){ | 18 | if (syscall(__NR_munmap, from, size) < 0){ |
| 22 | return(-1); | 19 | return(-1); |
| 23 | } | 20 | } |
| 24 | return(0); | 21 | return(0); |
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 6fce9f45dfdc..73ce4463f70c 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c | |||
| @@ -21,7 +21,7 @@ asmlinkage long sys_uname64(struct new_utsname __user * name) | |||
| 21 | { | 21 | { |
| 22 | int err; | 22 | int err; |
| 23 | down_read(&uts_sem); | 23 | down_read(&uts_sem); |
| 24 | err = copy_to_user(name, &system_utsname, sizeof (*name)); | 24 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 25 | up_read(&uts_sem); | 25 | up_read(&uts_sem); |
| 26 | if (personality(current->personality) == PER_LINUX32) | 26 | if (personality(current->personality) == PER_LINUX32) |
| 27 | err |= copy_to_user(&name->machine, "i686", 5); | 27 | err |= copy_to_user(&name->machine, "i686", 5); |
diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c index d0a25af19a5b..ce3e07fcf283 100644 --- a/arch/um/sys-x86_64/sysrq.c +++ b/arch/um/sys-x86_64/sysrq.c | |||
| @@ -16,7 +16,7 @@ void __show_regs(struct pt_regs * regs) | |||
| 16 | printk("\n"); | 16 | printk("\n"); |
| 17 | print_modules(); | 17 | print_modules(); |
| 18 | printk("Pid: %d, comm: %.20s %s %s\n", | 18 | printk("Pid: %d, comm: %.20s %s %s\n", |
| 19 | current->pid, current->comm, print_tainted(), system_utsname.release); | 19 | current->pid, current->comm, print_tainted(), init_utsname()->release); |
| 20 | printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff, | 20 | printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff, |
| 21 | PT_REGS_RIP(regs)); | 21 | PT_REGS_RIP(regs)); |
| 22 | printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), | 22 | printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), |
diff --git a/arch/um/sys-x86_64/unmap.c b/arch/um/sys-x86_64/unmap.c index f4a4bffd8a18..57c9286a701b 100644 --- a/arch/um/sys-x86_64/unmap.c +++ b/arch/um/sys-x86_64/unmap.c | |||
| @@ -5,20 +5,17 @@ | |||
| 5 | 5 | ||
| 6 | #include <linux/mman.h> | 6 | #include <linux/mman.h> |
| 7 | #include <asm/unistd.h> | 7 | #include <asm/unistd.h> |
| 8 | #include <sys/syscall.h> | ||
| 8 | 9 | ||
| 9 | static int errno; | ||
| 10 | |||
| 11 | static inline _syscall2(int,munmap,void *,start,size_t,len) | ||
| 12 | static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset) | ||
| 13 | int switcheroo(int fd, int prot, void *from, void *to, int size) | 10 | int switcheroo(int fd, int prot, void *from, void *to, int size) |
| 14 | { | 11 | { |
| 15 | if(munmap(to, size) < 0){ | 12 | if (syscall(__NR_munmap, to, size) < 0){ |
| 16 | return(-1); | 13 | return(-1); |
| 17 | } | 14 | } |
| 18 | if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){ | 15 | if (syscall(__NR_mmap, to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){ |
| 19 | return(-1); | 16 | return(-1); |
| 20 | } | 17 | } |
| 21 | if(munmap(from, size) < 0){ | 18 | if (syscall(__NR_munmap, from, size) < 0){ |
| 22 | return(-1); | 19 | return(-1); |
| 23 | } | 20 | } |
| 24 | return(0); | 21 | return(0); |
diff --git a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c index 815f8a43926f..92f514fdcc79 100644 --- a/arch/v850/kernel/memcons.c +++ b/arch/v850/kernel/memcons.c | |||
| @@ -104,7 +104,7 @@ int memcons_tty_chars_in_buffer (struct tty_struct *tty) | |||
| 104 | return 0; | 104 | return 0; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static struct tty_operations ops = { | 107 | static const struct tty_operations ops = { |
| 108 | .open = memcons_tty_open, | 108 | .open = memcons_tty_open, |
| 109 | .write = memcons_tty_write, | 109 | .write = memcons_tty_write, |
| 110 | .write_room = memcons_tty_write_room, | 110 | .write_room = memcons_tty_write_room, |
diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c index 3975aa02cef8..9973596ae304 100644 --- a/arch/v850/kernel/simcons.c +++ b/arch/v850/kernel/simcons.c | |||
| @@ -77,7 +77,7 @@ int simcons_tty_chars_in_buffer (struct tty_struct *tty) | |||
| 77 | return 0; | 77 | return 0; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static struct tty_operations ops = { | 80 | static const struct tty_operations ops = { |
| 81 | .open = simcons_tty_open, | 81 | .open = simcons_tty_open, |
| 82 | .write = simcons_tty_write, | 82 | .write = simcons_tty_write, |
| 83 | .write_room = simcons_tty_write_room, | 83 | .write_room = simcons_tty_write_room, |
diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c index 2ec0700fc46b..d2b1fb19d243 100644 --- a/arch/v850/kernel/syscalls.c +++ b/arch/v850/kernel/syscalls.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
| 34 | #include <asm/ipc.h> | 34 | #include <asm/ipc.h> |
| 35 | #include <asm/semaphore.h> | 35 | #include <asm/semaphore.h> |
| 36 | #include <asm/unistd.h> | ||
| 36 | 37 | ||
| 37 | /* | 38 | /* |
| 38 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | 39 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. |
| @@ -194,3 +195,22 @@ unsigned long sys_mmap (unsigned long addr, size_t len, | |||
| 194 | out: | 195 | out: |
| 195 | return err; | 196 | return err; |
| 196 | } | 197 | } |
| 198 | |||
| 199 | /* | ||
| 200 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 201 | * end up with proper pt_regs. | ||
| 202 | */ | ||
| 203 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 204 | { | ||
| 205 | register char *__a __asm__ ("r6") = filename; | ||
| 206 | register void *__b __asm__ ("r7") = argv; | ||
| 207 | register void *__c __asm__ ("r8") = envp; | ||
| 208 | register unsigned long __syscall __asm__ ("r12") = __NR_execve; | ||
| 209 | register unsigned long __ret __asm__ ("r10"); | ||
| 210 | __asm__ __volatile__ ("trap 0" | ||
| 211 | : "=r" (__ret), "=r" (__syscall) | ||
| 212 | : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) | ||
| 213 | : "r1", "r5", "r11", "r13", "r14", | ||
| 214 | "r15", "r16", "r17", "r18", "r19"); | ||
| 215 | return __ret; | ||
| 216 | } | ||
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index b87a19f0d584..0a5d8e659aa4 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
| @@ -690,7 +690,7 @@ source "arch/x86_64/oprofile/Kconfig" | |||
| 690 | 690 | ||
| 691 | config KPROBES | 691 | config KPROBES |
| 692 | bool "Kprobes (EXPERIMENTAL)" | 692 | bool "Kprobes (EXPERIMENTAL)" |
| 693 | depends on EXPERIMENTAL && MODULES | 693 | depends on KALLSYMS && EXPERIMENTAL && MODULES |
| 694 | help | 694 | help |
| 695 | Kprobes allows you to trap at almost any kernel address and | 695 | Kprobes allows you to trap at almost any kernel address and |
| 696 | execute a callback function. register_kprobe() establishes | 696 | execute a callback function. register_kprobe() establishes |
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c index f280d3665f4b..26a01717cc1a 100644 --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c | |||
| @@ -784,36 +784,36 @@ asmlinkage long sys32_olduname(struct oldold_utsname __user * name) | |||
| 784 | 784 | ||
| 785 | if (!name) | 785 | if (!name) |
| 786 | return -EFAULT; | 786 | return -EFAULT; |
| 787 | if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) | 787 | if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) |
| 788 | return -EFAULT; | 788 | return -EFAULT; |
| 789 | 789 | ||
| 790 | down_read(&uts_sem); | 790 | down_read(&uts_sem); |
| 791 | 791 | ||
| 792 | err = __copy_to_user(&name->sysname,&system_utsname.sysname, | 792 | err = __copy_to_user(&name->sysname,&utsname()->sysname, |
| 793 | __OLD_UTS_LEN); | 793 | __OLD_UTS_LEN); |
| 794 | err |= __put_user(0,name->sysname+__OLD_UTS_LEN); | 794 | err |= __put_user(0,name->sysname+__OLD_UTS_LEN); |
| 795 | err |= __copy_to_user(&name->nodename,&system_utsname.nodename, | 795 | err |= __copy_to_user(&name->nodename,&utsname()->nodename, |
| 796 | __OLD_UTS_LEN); | 796 | __OLD_UTS_LEN); |
| 797 | err |= __put_user(0,name->nodename+__OLD_UTS_LEN); | 797 | err |= __put_user(0,name->nodename+__OLD_UTS_LEN); |
| 798 | err |= __copy_to_user(&name->release,&system_utsname.release, | 798 | err |= __copy_to_user(&name->release,&utsname()->release, |
| 799 | __OLD_UTS_LEN); | 799 | __OLD_UTS_LEN); |
| 800 | err |= __put_user(0,name->release+__OLD_UTS_LEN); | 800 | err |= __put_user(0,name->release+__OLD_UTS_LEN); |
| 801 | err |= __copy_to_user(&name->version,&system_utsname.version, | 801 | err |= __copy_to_user(&name->version,&utsname()->version, |
| 802 | __OLD_UTS_LEN); | 802 | __OLD_UTS_LEN); |
| 803 | err |= __put_user(0,name->version+__OLD_UTS_LEN); | 803 | err |= __put_user(0,name->version+__OLD_UTS_LEN); |
| 804 | { | 804 | { |
| 805 | char *arch = "x86_64"; | 805 | char *arch = "x86_64"; |
| 806 | if (personality(current->personality) == PER_LINUX32) | 806 | if (personality(current->personality) == PER_LINUX32) |
| 807 | arch = "i686"; | 807 | arch = "i686"; |
| 808 | 808 | ||
| 809 | err |= __copy_to_user(&name->machine,arch,strlen(arch)+1); | 809 | err |= __copy_to_user(&name->machine, arch, strlen(arch)+1); |
| 810 | } | 810 | } |
| 811 | 811 | ||
| 812 | up_read(&uts_sem); | 812 | up_read(&uts_sem); |
| 813 | 813 | ||
| 814 | err = err ? -EFAULT : 0; | 814 | err = err ? -EFAULT : 0; |
| 815 | 815 | ||
| 816 | return err; | 816 | return err; |
| 817 | } | 817 | } |
| 818 | 818 | ||
| 819 | long sys32_uname(struct old_utsname __user * name) | 819 | long sys32_uname(struct old_utsname __user * name) |
| @@ -822,7 +822,7 @@ long sys32_uname(struct old_utsname __user * name) | |||
| 822 | if (!name) | 822 | if (!name) |
| 823 | return -EFAULT; | 823 | return -EFAULT; |
| 824 | down_read(&uts_sem); | 824 | down_read(&uts_sem); |
| 825 | err=copy_to_user(name, &system_utsname, sizeof (*name)); | 825 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 826 | up_read(&uts_sem); | 826 | up_read(&uts_sem); |
| 827 | if (personality(current->personality) == PER_LINUX32) | 827 | if (personality(current->personality) == PER_LINUX32) |
| 828 | err |= copy_to_user(&name->machine, "i686", 5); | 828 | err |= copy_to_user(&name->machine, "i686", 5); |
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 2802524104f3..b8285cf1a9c3 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S | |||
| @@ -1023,7 +1023,7 @@ ENDPROC(child_rip) | |||
| 1023 | * do_sys_execve asm fallback arguments: | 1023 | * do_sys_execve asm fallback arguments: |
| 1024 | * rdi: name, rsi: argv, rdx: envp, fake frame on the stack | 1024 | * rdi: name, rsi: argv, rdx: envp, fake frame on the stack |
| 1025 | */ | 1025 | */ |
| 1026 | ENTRY(execve) | 1026 | ENTRY(kernel_execve) |
| 1027 | CFI_STARTPROC | 1027 | CFI_STARTPROC |
| 1028 | FAKE_STACK_FRAME $0 | 1028 | FAKE_STACK_FRAME $0 |
| 1029 | SAVE_ALL | 1029 | SAVE_ALL |
| @@ -1036,7 +1036,7 @@ ENTRY(execve) | |||
| 1036 | UNFAKE_STACK_FRAME | 1036 | UNFAKE_STACK_FRAME |
| 1037 | ret | 1037 | ret |
| 1038 | CFI_ENDPROC | 1038 | CFI_ENDPROC |
| 1039 | ENDPROC(execve) | 1039 | ENDPROC(kernel_execve) |
| 1040 | 1040 | ||
| 1041 | KPROBE_ENTRY(page_fault) | 1041 | KPROBE_ENTRY(page_fault) |
| 1042 | errorentry do_page_fault | 1042 | errorentry do_page_fault |
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index ffc73ac72485..ac241567e682 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c | |||
| @@ -270,20 +270,19 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, | |||
| 270 | struct pt_regs *regs) | 270 | struct pt_regs *regs) |
| 271 | { | 271 | { |
| 272 | unsigned long *sara = (unsigned long *)regs->rsp; | 272 | unsigned long *sara = (unsigned long *)regs->rsp; |
| 273 | struct kretprobe_instance *ri; | 273 | struct kretprobe_instance *ri; |
| 274 | 274 | ||
| 275 | if ((ri = get_free_rp_inst(rp)) != NULL) { | 275 | if ((ri = get_free_rp_inst(rp)) != NULL) { |
| 276 | ri->rp = rp; | 276 | ri->rp = rp; |
| 277 | ri->task = current; | 277 | ri->task = current; |
| 278 | ri->ret_addr = (kprobe_opcode_t *) *sara; | 278 | ri->ret_addr = (kprobe_opcode_t *) *sara; |
| 279 | 279 | ||
| 280 | /* Replace the return addr with trampoline addr */ | 280 | /* Replace the return addr with trampoline addr */ |
| 281 | *sara = (unsigned long) &kretprobe_trampoline; | 281 | *sara = (unsigned long) &kretprobe_trampoline; |
| 282 | 282 | add_rp_inst(ri); | |
| 283 | add_rp_inst(ri); | 283 | } else { |
| 284 | } else { | 284 | rp->nmissed++; |
| 285 | rp->nmissed++; | 285 | } |
| 286 | } | ||
| 287 | } | 286 | } |
| 288 | 287 | ||
| 289 | int __kprobes kprobe_handler(struct pt_regs *regs) | 288 | int __kprobes kprobe_handler(struct pt_regs *regs) |
| @@ -405,14 +404,15 @@ no_kprobe: | |||
| 405 | */ | 404 | */ |
| 406 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 405 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
| 407 | { | 406 | { |
| 408 | struct kretprobe_instance *ri = NULL; | 407 | struct kretprobe_instance *ri = NULL; |
| 409 | struct hlist_head *head; | 408 | struct hlist_head *head, empty_rp; |
| 410 | struct hlist_node *node, *tmp; | 409 | struct hlist_node *node, *tmp; |
| 411 | unsigned long flags, orig_ret_address = 0; | 410 | unsigned long flags, orig_ret_address = 0; |
| 412 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | 411 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; |
| 413 | 412 | ||
| 413 | INIT_HLIST_HEAD(&empty_rp); | ||
| 414 | spin_lock_irqsave(&kretprobe_lock, flags); | 414 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 415 | head = kretprobe_inst_table_head(current); | 415 | head = kretprobe_inst_table_head(current); |
| 416 | 416 | ||
| 417 | /* | 417 | /* |
| 418 | * It is possible to have multiple instances associated with a given | 418 | * It is possible to have multiple instances associated with a given |
| @@ -423,20 +423,20 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 423 | * We can handle this because: | 423 | * We can handle this because: |
| 424 | * - instances are always inserted at the head of the list | 424 | * - instances are always inserted at the head of the list |
| 425 | * - when multiple return probes are registered for the same | 425 | * - when multiple return probes are registered for the same |
| 426 | * function, the first instance's ret_addr will point to the | 426 | * function, the first instance's ret_addr will point to the |
| 427 | * real return address, and all the rest will point to | 427 | * real return address, and all the rest will point to |
| 428 | * kretprobe_trampoline | 428 | * kretprobe_trampoline |
| 429 | */ | 429 | */ |
| 430 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | 430 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { |
| 431 | if (ri->task != current) | 431 | if (ri->task != current) |
| 432 | /* another task is sharing our hash bucket */ | 432 | /* another task is sharing our hash bucket */ |
| 433 | continue; | 433 | continue; |
| 434 | 434 | ||
| 435 | if (ri->rp && ri->rp->handler) | 435 | if (ri->rp && ri->rp->handler) |
| 436 | ri->rp->handler(ri, regs); | 436 | ri->rp->handler(ri, regs); |
| 437 | 437 | ||
| 438 | orig_ret_address = (unsigned long)ri->ret_addr; | 438 | orig_ret_address = (unsigned long)ri->ret_addr; |
| 439 | recycle_rp_inst(ri); | 439 | recycle_rp_inst(ri, &empty_rp); |
| 440 | 440 | ||
| 441 | if (orig_ret_address != trampoline_address) | 441 | if (orig_ret_address != trampoline_address) |
| 442 | /* | 442 | /* |
| @@ -454,12 +454,16 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 454 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 454 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 455 | preempt_enable_no_resched(); | 455 | preempt_enable_no_resched(); |
| 456 | 456 | ||
| 457 | /* | 457 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { |
| 458 | * By returning a non-zero value, we are telling | 458 | hlist_del(&ri->hlist); |
| 459 | * kprobe_handler() that we don't want the post_handler | 459 | kfree(ri); |
| 460 | } | ||
| 461 | /* | ||
| 462 | * By returning a non-zero value, we are telling | ||
| 463 | * kprobe_handler() that we don't want the post_handler | ||
| 460 | * to run (and have re-enabled preemption) | 464 | * to run (and have re-enabled preemption) |
| 461 | */ | 465 | */ |
| 462 | return 1; | 466 | return 1; |
| 463 | } | 467 | } |
| 464 | 468 | ||
| 465 | /* | 469 | /* |
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 458006ae19f3..de10cb8a2c97 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c | |||
| @@ -294,9 +294,9 @@ void __show_regs(struct pt_regs * regs) | |||
| 294 | print_modules(); | 294 | print_modules(); |
| 295 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", | 295 | printk("Pid: %d, comm: %.20s %s %s %.*s\n", |
| 296 | current->pid, current->comm, print_tainted(), | 296 | current->pid, current->comm, print_tainted(), |
| 297 | system_utsname.release, | 297 | init_utsname()->release, |
| 298 | (int)strcspn(system_utsname.version, " "), | 298 | (int)strcspn(init_utsname()->version, " "), |
| 299 | system_utsname.version); | 299 | init_utsname()->version); |
| 300 | printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); | 300 | printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); |
| 301 | printk_address(regs->rip); | 301 | printk_address(regs->rip); |
| 302 | printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, | 302 | printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, |
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c index 6449ea8fe756..76bf7c241fe4 100644 --- a/arch/x86_64/kernel/sys_x86_64.c +++ b/arch/x86_64/kernel/sys_x86_64.c | |||
| @@ -148,7 +148,7 @@ asmlinkage long sys_uname(struct new_utsname __user * name) | |||
| 148 | { | 148 | { |
| 149 | int err; | 149 | int err; |
| 150 | down_read(&uts_sem); | 150 | down_read(&uts_sem); |
| 151 | err = copy_to_user(name, &system_utsname, sizeof (*name)); | 151 | err = copy_to_user(name, utsname(), sizeof (*name)); |
| 152 | up_read(&uts_sem); | 152 | up_read(&uts_sem); |
| 153 | if (personality(current->personality) == PER_LINUX32) | 153 | if (personality(current->personality) == PER_LINUX32) |
| 154 | err |= copy_to_user(&name->machine, "i686", 5); | 154 | err |= copy_to_user(&name->machine, "i686", 5); |
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c index 4688ba2db84d..d9285d4d5565 100644 --- a/arch/xtensa/kernel/syscalls.c +++ b/arch/xtensa/kernel/syscalls.c | |||
| @@ -128,7 +128,7 @@ out: | |||
| 128 | 128 | ||
| 129 | int sys_uname(struct old_utsname * name) | 129 | int sys_uname(struct old_utsname * name) |
| 130 | { | 130 | { |
| 131 | if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) | 131 | if (name && !copy_to_user(name, utsname(), sizeof (*name))) |
| 132 | return 0; | 132 | return 0; |
| 133 | return -EFAULT; | 133 | return -EFAULT; |
| 134 | } | 134 | } |
| @@ -266,3 +266,23 @@ void system_call (struct pt_regs *regs) | |||
| 266 | regs->areg[2] = res; | 266 | regs->areg[2] = res; |
| 267 | do_syscall_trace(); | 267 | do_syscall_trace(); |
| 268 | } | 268 | } |
| 269 | |||
| 270 | /* | ||
| 271 | * Do a system call from kernel instead of calling sys_execve so we | ||
| 272 | * end up with proper pt_regs. | ||
| 273 | */ | ||
| 274 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
| 275 | { | ||
| 276 | long __res; | ||
| 277 | asm volatile ( | ||
| 278 | " mov a5, %2 \n" | ||
| 279 | " mov a4, %4 \n" | ||
| 280 | " mov a3, %3 \n" | ||
| 281 | " movi a2, %1 \n" | ||
| 282 | " syscall \n" | ||
| 283 | " mov %0, a2 \n" | ||
| 284 | : "=a" (__res) | ||
| 285 | : "i" (__NR_execve), "a" (filename), "a" (argv), "a" (envp) | ||
| 286 | : "a2", "a3", "a4", "a5"); | ||
| 287 | return __res; | ||
| 288 | } | ||
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c index 22d3c571a7bc..5c947cae7520 100644 --- a/arch/xtensa/platform-iss/console.c +++ b/arch/xtensa/platform-iss/console.c | |||
| @@ -191,7 +191,7 @@ static int rs_read_proc(char *page, char **start, off_t off, int count, | |||
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | 193 | ||
| 194 | static struct tty_operations serial_ops = { | 194 | static const struct tty_operations serial_ops = { |
| 195 | .open = rs_open, | 195 | .open = rs_open, |
| 196 | .close = rs_close, | 196 | .close = rs_close, |
| 197 | .write = rs_write, | 197 | .write = rs_write, |
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 9d6713a93ed7..d0e92ed0a367 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c | |||
| @@ -1958,7 +1958,7 @@ static void show_serial_version(void) | |||
| 1958 | } | 1958 | } |
| 1959 | 1959 | ||
| 1960 | 1960 | ||
| 1961 | static struct tty_operations serial_ops = { | 1961 | static const struct tty_operations serial_ops = { |
| 1962 | .open = rs_open, | 1962 | .open = rs_open, |
| 1963 | .close = rs_close, | 1963 | .close = rs_close, |
| 1964 | .write = rs_write, | 1964 | .write = rs_write, |
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c1c67281750d..f85b4eb16618 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
| @@ -5205,7 +5205,7 @@ done: | |||
| 5205 | extra ports are ignored. | 5205 | extra ports are ignored. |
| 5206 | */ | 5206 | */ |
| 5207 | 5207 | ||
| 5208 | static struct tty_operations cy_ops = { | 5208 | static const struct tty_operations cy_ops = { |
| 5209 | .open = cy_open, | 5209 | .open = cy_open, |
| 5210 | .close = cy_close, | 5210 | .close = cy_close, |
| 5211 | .write = cy_write, | 5211 | .write = cy_write, |
diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 86d290e9f307..3baa2ab8cbd4 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c | |||
| @@ -1125,7 +1125,7 @@ static void __exit epca_module_exit(void) | |||
| 1125 | 1125 | ||
| 1126 | module_exit(epca_module_exit); | 1126 | module_exit(epca_module_exit); |
| 1127 | 1127 | ||
| 1128 | static struct tty_operations pc_ops = { | 1128 | static const struct tty_operations pc_ops = { |
| 1129 | .open = pc_open, | 1129 | .open = pc_open, |
| 1130 | .close = pc_close, | 1130 | .close = pc_close, |
| 1131 | .write = pc_write, | 1131 | .write = pc_write, |
diff --git a/drivers/char/esp.c b/drivers/char/esp.c index afcd83d9984b..05788c75d7fc 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c | |||
| @@ -2376,7 +2376,7 @@ static inline int autoconfig(struct esp_struct * info) | |||
| 2376 | return (port_detected); | 2376 | return (port_detected); |
| 2377 | } | 2377 | } |
| 2378 | 2378 | ||
| 2379 | static struct tty_operations esp_ops = { | 2379 | static const struct tty_operations esp_ops = { |
| 2380 | .open = esp_open, | 2380 | .open = esp_open, |
| 2381 | .close = rs_close, | 2381 | .close = rs_close, |
| 2382 | .write = rs_write, | 2382 | .write = rs_write, |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index a76d2c40dd5e..4053d1cd393f 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
| @@ -696,7 +696,7 @@ int khvcd(void *unused) | |||
| 696 | return 0; | 696 | return 0; |
| 697 | } | 697 | } |
| 698 | 698 | ||
| 699 | static struct tty_operations hvc_ops = { | 699 | static const struct tty_operations hvc_ops = { |
| 700 | .open = hvc_open, | 700 | .open = hvc_open, |
| 701 | .close = hvc_close, | 701 | .close = hvc_close, |
| 702 | .write = hvc_write, | 702 | .write = hvc_write, |
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 4589ff302b07..0b89bcde8c52 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c | |||
| @@ -1306,7 +1306,7 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) | |||
| 1306 | return hvcsd->chars_in_buffer; | 1306 | return hvcsd->chars_in_buffer; |
| 1307 | } | 1307 | } |
| 1308 | 1308 | ||
| 1309 | static struct tty_operations hvcs_ops = { | 1309 | static const struct tty_operations hvcs_ops = { |
| 1310 | .open = hvcs_open, | 1310 | .open = hvcs_open, |
| 1311 | .close = hvcs_close, | 1311 | .close = hvcs_close, |
| 1312 | .hangup = hvcs_hangup, | 1312 | .hangup = hvcs_hangup, |
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index a89a95fb5e40..c07dc58d5c1d 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c | |||
| @@ -1130,7 +1130,7 @@ static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, | |||
| 1130 | } | 1130 | } |
| 1131 | 1131 | ||
| 1132 | 1132 | ||
| 1133 | static struct tty_operations hvsi_ops = { | 1133 | static const struct tty_operations hvsi_ops = { |
| 1134 | .open = hvsi_open, | 1134 | .open = hvsi_open, |
| 1135 | .close = hvsi_close, | 1135 | .close = hvsi_close, |
| 1136 | .write = hvsi_write, | 1136 | .write = hvsi_write, |
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 331f447e6228..4828bc914ce3 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c | |||
| @@ -458,7 +458,7 @@ cleanup_module(void) | |||
| 458 | } | 458 | } |
| 459 | #endif /* MODULE */ | 459 | #endif /* MODULE */ |
| 460 | 460 | ||
| 461 | static struct tty_operations ip2_ops = { | 461 | static const struct tty_operations ip2_ops = { |
| 462 | .open = ip2_open, | 462 | .open = ip2_open, |
| 463 | .close = ip2_close, | 463 | .close = ip2_close, |
| 464 | .write = ip2_write, | 464 | .write = ip2_write, |
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 2e1da632aee1..ea2bbf80ad33 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c | |||
| @@ -1550,7 +1550,7 @@ static void isicom_unregister_ioregion(struct pci_dev *pdev) | |||
| 1550 | board->base = 0; | 1550 | board->base = 0; |
| 1551 | } | 1551 | } |
| 1552 | 1552 | ||
| 1553 | static struct tty_operations isicom_ops = { | 1553 | static const struct tty_operations isicom_ops = { |
| 1554 | .open = isicom_open, | 1554 | .open = isicom_open, |
| 1555 | .close = isicom_close, | 1555 | .close = isicom_close, |
| 1556 | .write = isicom_write, | 1556 | .write = isicom_write, |
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 6b4d82a4565f..d6e031542c6b 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c | |||
| @@ -4636,7 +4636,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un | |||
| 4636 | return rc; | 4636 | return rc; |
| 4637 | } | 4637 | } |
| 4638 | 4638 | ||
| 4639 | static struct tty_operations stli_ops = { | 4639 | static const struct tty_operations stli_ops = { |
| 4640 | .open = stli_open, | 4640 | .open = stli_open, |
| 4641 | .close = stli_close, | 4641 | .close = stli_close, |
| 4642 | .write = stli_write, | 4642 | .write = stli_write, |
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 3e90aac37510..e2011669c7bb 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c | |||
| @@ -108,7 +108,11 @@ const int NR_TYPES = ARRAY_SIZE(max_vals); | |||
| 108 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | 108 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; |
| 109 | static struct kbd_struct *kbd = kbd_table; | 109 | static struct kbd_struct *kbd = kbd_table; |
| 110 | 110 | ||
| 111 | int spawnpid, spawnsig; | 111 | struct vt_spawn_console vt_spawn_con = { |
| 112 | .lock = SPIN_LOCK_UNLOCKED, | ||
| 113 | .pid = NULL, | ||
| 114 | .sig = 0, | ||
| 115 | }; | ||
| 112 | 116 | ||
| 113 | /* | 117 | /* |
| 114 | * Variables exported for vt.c | 118 | * Variables exported for vt.c |
| @@ -578,9 +582,13 @@ static void fn_compose(struct vc_data *vc, struct pt_regs *regs) | |||
| 578 | 582 | ||
| 579 | static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) | 583 | static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs) |
| 580 | { | 584 | { |
| 581 | if (spawnpid) | 585 | spin_lock(&vt_spawn_con.lock); |
| 582 | if (kill_proc(spawnpid, spawnsig, 1)) | 586 | if (vt_spawn_con.pid) |
| 583 | spawnpid = 0; | 587 | if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { |
| 588 | put_pid(vt_spawn_con.pid); | ||
| 589 | vt_spawn_con.pid = NULL; | ||
| 590 | } | ||
| 591 | spin_unlock(&vt_spawn_con.lock); | ||
| 584 | } | 592 | } |
| 585 | 593 | ||
| 586 | static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) | 594 | static void fn_SAK(struct vc_data *vc, struct pt_regs *regs) |
| @@ -1285,7 +1293,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, | |||
| 1285 | */ | 1293 | */ |
| 1286 | static struct input_handle *kbd_connect(struct input_handler *handler, | 1294 | static struct input_handle *kbd_connect(struct input_handler *handler, |
| 1287 | struct input_dev *dev, | 1295 | struct input_dev *dev, |
| 1288 | struct input_device_id *id) | 1296 | const struct input_device_id *id) |
| 1289 | { | 1297 | { |
| 1290 | struct input_handle *handle; | 1298 | struct input_handle *handle; |
| 1291 | int i; | 1299 | int i; |
| @@ -1334,7 +1342,7 @@ static void kbd_start(struct input_handle *handle) | |||
| 1334 | tasklet_enable(&keyboard_tasklet); | 1342 | tasklet_enable(&keyboard_tasklet); |
| 1335 | } | 1343 | } |
| 1336 | 1344 | ||
| 1337 | static struct input_device_id kbd_ids[] = { | 1345 | static const struct input_device_id kbd_ids[] = { |
| 1338 | { | 1346 | { |
| 1339 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | 1347 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
| 1340 | .evbit = { BIT(EV_KEY) }, | 1348 | .evbit = { BIT(EV_KEY) }, |
| @@ -1362,6 +1370,7 @@ static struct input_handler kbd_handler = { | |||
| 1362 | int __init kbd_init(void) | 1370 | int __init kbd_init(void) |
| 1363 | { | 1371 | { |
| 1364 | int i; | 1372 | int i; |
| 1373 | int error; | ||
| 1365 | 1374 | ||
| 1366 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 1375 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
| 1367 | kbd_table[i].ledflagstate = KBD_DEFLEDS; | 1376 | kbd_table[i].ledflagstate = KBD_DEFLEDS; |
| @@ -1373,7 +1382,9 @@ int __init kbd_init(void) | |||
| 1373 | kbd_table[i].kbdmode = VC_XLATE; | 1382 | kbd_table[i].kbdmode = VC_XLATE; |
| 1374 | } | 1383 | } |
| 1375 | 1384 | ||
| 1376 | input_register_handler(&kbd_handler); | 1385 | error = input_register_handler(&kbd_handler); |
| 1386 | if (error) | ||
| 1387 | return error; | ||
| 1377 | 1388 | ||
| 1378 | tasklet_enable(&keyboard_tasklet); | 1389 | tasklet_enable(&keyboard_tasklet); |
| 1379 | tasklet_schedule(&keyboard_tasklet); | 1390 | tasklet_schedule(&keyboard_tasklet); |
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index c1a6d3c48da1..b401383808c2 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
| @@ -281,7 +281,7 @@ static int moxa_get_serial_info(struct moxa_str *, struct serial_struct __user * | |||
| 281 | static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *); | 281 | static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *); |
| 282 | static void MoxaSetFifo(int port, int enable); | 282 | static void MoxaSetFifo(int port, int enable); |
| 283 | 283 | ||
| 284 | static struct tty_operations moxa_ops = { | 284 | static const struct tty_operations moxa_ops = { |
| 285 | .open = moxa_open, | 285 | .open = moxa_open, |
| 286 | .close = moxa_close, | 286 | .close = moxa_close, |
| 287 | .write = moxa_write, | 287 | .write = moxa_write, |
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 27a653772049..8253fca8efd5 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c | |||
| @@ -453,7 +453,7 @@ static int CheckIsMoxaMust(int io) | |||
| 453 | 453 | ||
| 454 | /* above is modified by Victor Yu. 08-15-2002 */ | 454 | /* above is modified by Victor Yu. 08-15-2002 */ |
| 455 | 455 | ||
| 456 | static struct tty_operations mxser_ops = { | 456 | static const struct tty_operations mxser_ops = { |
| 457 | .open = mxser_open, | 457 | .open = mxser_open, |
| 458 | .close = mxser_close, | 458 | .close = mxser_close, |
| 459 | .write = mxser_write, | 459 | .write = mxser_write, |
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 7c57ebfa8640..ea1aa7764f8e 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c | |||
| @@ -127,9 +127,8 @@ static void button_consume_callbacks (int bpcount) | |||
| 127 | static void button_sequence_finished (unsigned long parameters) | 127 | static void button_sequence_finished (unsigned long parameters) |
| 128 | { | 128 | { |
| 129 | #ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ | 129 | #ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ |
| 130 | if (button_press_count == reboot_count) { | 130 | if (button_press_count == reboot_count) |
| 131 | kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ | 131 | kill_cad_pid(SIGINT, 1); /* Ask init to reboot us */ |
| 132 | } | ||
| 133 | #endif /* CONFIG_NWBUTTON_REBOOT */ | 132 | #endif /* CONFIG_NWBUTTON_REBOOT */ |
| 134 | button_consume_callbacks (button_press_count); | 133 | button_consume_callbacks (button_press_count); |
| 135 | bcount = sprintf (button_output_buffer, "%d\n", button_press_count); | 134 | bcount = sprintf (button_output_buffer, "%d\n", button_press_count); |
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 00f574cbb0d4..dd845cbefe94 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
| @@ -3010,7 +3010,7 @@ static struct pcmcia_driver mgslpc_driver = { | |||
| 3010 | .resume = mgslpc_resume, | 3010 | .resume = mgslpc_resume, |
| 3011 | }; | 3011 | }; |
| 3012 | 3012 | ||
| 3013 | static struct tty_operations mgslpc_ops = { | 3013 | static const struct tty_operations mgslpc_ops = { |
| 3014 | .open = mgslpc_open, | 3014 | .open = mgslpc_open, |
| 3015 | .close = mgslpc_close, | 3015 | .close = mgslpc_close, |
| 3016 | .write = mgslpc_write, | 3016 | .write = mgslpc_write, |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 34dd4c38110e..80d3eedd7f96 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
| @@ -224,7 +224,7 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) | |||
| 224 | tty->termios->c_cflag |= (CS8 | CREAD); | 224 | tty->termios->c_cflag |= (CS8 | CREAD); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static struct tty_operations pty_ops = { | 227 | static const struct tty_operations pty_ops = { |
| 228 | .open = pty_open, | 228 | .open = pty_open, |
| 229 | .close = pty_close, | 229 | .close = pty_close, |
| 230 | .write = pty_write, | 230 | .write = pty_write, |
diff --git a/drivers/char/random.c b/drivers/char/random.c index b430a12eb819..07f47a0208a7 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
| @@ -889,8 +889,8 @@ static void init_std_data(struct entropy_store *r) | |||
| 889 | 889 | ||
| 890 | do_gettimeofday(&tv); | 890 | do_gettimeofday(&tv); |
| 891 | add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4); | 891 | add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4); |
| 892 | add_entropy_words(r, (__u32 *)&system_utsname, | 892 | add_entropy_words(r, (__u32 *)utsname(), |
| 893 | sizeof(system_utsname)/4); | 893 | sizeof(*(utsname()))/4); |
| 894 | } | 894 | } |
| 895 | 895 | ||
| 896 | static int __init rand_initialize(void) | 896 | static int __init rand_initialize(void) |
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 3fa80aaf4527..202a3b0945b7 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c | |||
| @@ -727,7 +727,7 @@ static struct vpd_prom *get_VPD_PROM(struct Host *hp) | |||
| 727 | return &vpdp; | 727 | return &vpdp; |
| 728 | } | 728 | } |
| 729 | 729 | ||
| 730 | static struct tty_operations rio_ops = { | 730 | static const struct tty_operations rio_ops = { |
| 731 | .open = riotopen, | 731 | .open = riotopen, |
| 732 | .close = gs_close, | 732 | .close = gs_close, |
| 733 | .write = gs_write, | 733 | .write = gs_write, |
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 06b9f78a95d9..214d850112fd 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c | |||
| @@ -1583,7 +1583,7 @@ static void do_softint(void *private_) | |||
| 1583 | } | 1583 | } |
| 1584 | } | 1584 | } |
| 1585 | 1585 | ||
| 1586 | static struct tty_operations riscom_ops = { | 1586 | static const struct tty_operations riscom_ops = { |
| 1587 | .open = rc_open, | 1587 | .open = rc_open, |
| 1588 | .close = rc_close, | 1588 | .close = rc_close, |
| 1589 | .write = rc_write, | 1589 | .write = rc_write, |
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0ac131881322..bac80056f7e0 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c | |||
| @@ -2334,7 +2334,7 @@ static int __init init_ISA(int i) | |||
| 2334 | return (1); | 2334 | return (1); |
| 2335 | } | 2335 | } |
| 2336 | 2336 | ||
| 2337 | static struct tty_operations rocket_ops = { | 2337 | static const struct tty_operations rocket_ops = { |
| 2338 | .open = rp_open, | 2338 | .open = rp_open, |
| 2339 | .close = rp_close, | 2339 | .close = rp_close, |
| 2340 | .write = rp_write, | 2340 | .write = rp_write, |
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 510bd3e0e88b..65c751d0d643 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c | |||
| @@ -661,7 +661,7 @@ static void a2232_init_portstructs(void) | |||
| 661 | } | 661 | } |
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | static struct tty_operations a2232_ops = { | 664 | static const struct tty_operations a2232_ops = { |
| 665 | .open = a2232_open, | 665 | .open = a2232_open, |
| 666 | .close = gs_close, | 666 | .close = gs_close, |
| 667 | .write = gs_write, | 667 | .write = gs_write, |
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 21a710cb4bba..b4ea1266b663 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c | |||
| @@ -2158,7 +2158,7 @@ mvme167_serial_console_setup(int cflag) | |||
| 2158 | rcor >> 5, rbpr); | 2158 | rcor >> 5, rbpr); |
| 2159 | } /* serial_console_init */ | 2159 | } /* serial_console_init */ |
| 2160 | 2160 | ||
| 2161 | static struct tty_operations cy_ops = { | 2161 | static const struct tty_operations cy_ops = { |
| 2162 | .open = cy_open, | 2162 | .open = cy_open, |
| 2163 | .close = cy_close, | 2163 | .close = cy_close, |
| 2164 | .write = cy_write, | 2164 | .write = cy_write, |
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index d12d4f629cec..864854c58866 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c | |||
| @@ -220,7 +220,7 @@ scdrv_dispatch_event(char *event, int len) | |||
| 220 | " Sending SIGPWR to init...\n"); | 220 | " Sending SIGPWR to init...\n"); |
| 221 | 221 | ||
| 222 | /* give a SIGPWR signal to init proc */ | 222 | /* give a SIGPWR signal to init proc */ |
| 223 | kill_proc(1, SIGPWR, 0); | 223 | kill_cad_pid(SIGPWR, 0); |
| 224 | } else { | 224 | } else { |
| 225 | /* print to system log */ | 225 | /* print to system log */ |
| 226 | printk("%s|$(0x%x)%s\n", severity, esp_code, desc); | 226 | printk("%s|$(0x%x)%s\n", severity, esp_code, desc); |
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index f52c7c31badf..902c48dca3bc 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c | |||
| @@ -2363,7 +2363,7 @@ static void do_softint(void *private_) | |||
| 2363 | func_exit(); | 2363 | func_exit(); |
| 2364 | } | 2364 | } |
| 2365 | 2365 | ||
| 2366 | static struct tty_operations sx_ops = { | 2366 | static const struct tty_operations sx_ops = { |
| 2367 | .open = sx_open, | 2367 | .open = sx_open, |
| 2368 | .close = sx_close, | 2368 | .close = sx_close, |
| 2369 | .write = sx_write, | 2369 | .write = sx_write, |
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 3beb2203d24b..bd711537ec4e 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c | |||
| @@ -2993,7 +2993,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns | |||
| 2993 | return(rc); | 2993 | return(rc); |
| 2994 | } | 2994 | } |
| 2995 | 2995 | ||
| 2996 | static struct tty_operations stl_ops = { | 2996 | static const struct tty_operations stl_ops = { |
| 2997 | .open = stl_open, | 2997 | .open = stl_open, |
| 2998 | .close = stl_close, | 2998 | .close = stl_close, |
| 2999 | .write = stl_write, | 2999 | .write = stl_write, |
diff --git a/drivers/char/sx.c b/drivers/char/sx.c index e1cd2bc4b1e4..57e31e5eaedb 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c | |||
| @@ -2226,7 +2226,7 @@ static int probe_si (struct sx_board *board) | |||
| 2226 | return 1; | 2226 | return 1; |
| 2227 | } | 2227 | } |
| 2228 | 2228 | ||
| 2229 | static struct tty_operations sx_ops = { | 2229 | static const struct tty_operations sx_ops = { |
| 2230 | .break_ctl = sx_break, | 2230 | .break_ctl = sx_break, |
| 2231 | .open = sx_open, | 2231 | .open = sx_open, |
| 2232 | .close = gs_close, | 2232 | .close = gs_close, |
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 78b1b1a2732b..244dc308c770 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c | |||
| @@ -4360,7 +4360,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) | |||
| 4360 | 4360 | ||
| 4361 | } /* end of mgsl_allocate_device()*/ | 4361 | } /* end of mgsl_allocate_device()*/ |
| 4362 | 4362 | ||
| 4363 | static struct tty_operations mgsl_ops = { | 4363 | static const struct tty_operations mgsl_ops = { |
| 4364 | .open = mgsl_open, | 4364 | .open = mgsl_open, |
| 4365 | .close = mgsl_close, | 4365 | .close = mgsl_close, |
| 4366 | .write = mgsl_write, | 4366 | .write = mgsl_write, |
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 78bc85180c82..bdc7cb248b8f 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
| @@ -3441,7 +3441,7 @@ static void __devexit remove_one(struct pci_dev *dev) | |||
| 3441 | { | 3441 | { |
| 3442 | } | 3442 | } |
| 3443 | 3443 | ||
| 3444 | static struct tty_operations ops = { | 3444 | static const struct tty_operations ops = { |
| 3445 | .open = open, | 3445 | .open = open, |
| 3446 | .close = close, | 3446 | .close = close, |
| 3447 | .write = write, | 3447 | .write = write, |
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 66f3754fbbdf..6eb75dcd7961 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c | |||
| @@ -3929,7 +3929,7 @@ void device_init(int adapter_num, struct pci_dev *pdev) | |||
| 3929 | } | 3929 | } |
| 3930 | } | 3930 | } |
| 3931 | 3931 | ||
| 3932 | static struct tty_operations ops = { | 3932 | static const struct tty_operations ops = { |
| 3933 | .open = open, | 3933 | .open = open, |
| 3934 | .close = close, | 3934 | .close = close, |
| 3935 | .write = write, | 3935 | .write = write, |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 333741770f1e..e90ea39c7c4b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -3680,7 +3680,8 @@ void put_tty_driver(struct tty_driver *driver) | |||
| 3680 | kfree(driver); | 3680 | kfree(driver); |
| 3681 | } | 3681 | } |
| 3682 | 3682 | ||
| 3683 | void tty_set_operations(struct tty_driver *driver, struct tty_operations *op) | 3683 | void tty_set_operations(struct tty_driver *driver, |
| 3684 | const struct tty_operations *op) | ||
| 3684 | { | 3685 | { |
| 3685 | driver->open = op->open; | 3686 | driver->open = op->open; |
| 3686 | driver->close = op->close; | 3687 | driver->close = op->close; |
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index f3efeaf2826e..a362ee9c92dd 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c | |||
| @@ -1047,7 +1047,7 @@ static int send_open(HvLpIndex remoteLp, void *sem) | |||
| 1047 | 0, 0, 0, 0); | 1047 | 0, 0, 0, 0); |
| 1048 | } | 1048 | } |
| 1049 | 1049 | ||
| 1050 | static struct tty_operations serial_ops = { | 1050 | static const struct tty_operations serial_ops = { |
| 1051 | .open = viotty_open, | 1051 | .open = viotty_open, |
| 1052 | .close = viotty_close, | 1052 | .close = viotty_close, |
| 1053 | .write = viotty_write, | 1053 | .write = viotty_write, |
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index bfe5ea948f6a..c2ca31eb850b 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c | |||
| @@ -113,7 +113,7 @@ static struct real_driver scc_real_driver = { | |||
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | 115 | ||
| 116 | static struct tty_operations scc_ops = { | 116 | static const struct tty_operations scc_ops = { |
| 117 | .open = scc_open, | 117 | .open = scc_open, |
| 118 | .close = gs_close, | 118 | .close = gs_close, |
| 119 | .write = gs_write, | 119 | .write = gs_write, |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index fb75da940b59..ec0c070bf15f 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
| @@ -903,6 +903,7 @@ void vc_deallocate(unsigned int currcons) | |||
| 903 | if (vc_cons_allocated(currcons)) { | 903 | if (vc_cons_allocated(currcons)) { |
| 904 | struct vc_data *vc = vc_cons[currcons].d; | 904 | struct vc_data *vc = vc_cons[currcons].d; |
| 905 | vc->vc_sw->con_deinit(vc); | 905 | vc->vc_sw->con_deinit(vc); |
| 906 | put_pid(vc->vt_pid); | ||
| 906 | module_put(vc->vc_sw->owner); | 907 | module_put(vc->vc_sw->owner); |
| 907 | if (vc->vc_kmalloced) | 908 | if (vc->vc_kmalloced) |
| 908 | kfree(vc->vc_screenbuf); | 909 | kfree(vc->vc_screenbuf); |
| @@ -2674,7 +2675,7 @@ static int __init con_init(void) | |||
| 2674 | } | 2675 | } |
| 2675 | console_initcall(con_init); | 2676 | console_initcall(con_init); |
| 2676 | 2677 | ||
| 2677 | static struct tty_operations con_ops = { | 2678 | static const struct tty_operations con_ops = { |
| 2678 | .open = con_open, | 2679 | .open = con_open, |
| 2679 | .close = con_close, | 2680 | .close = con_close, |
| 2680 | .write = con_write, | 2681 | .write = con_write, |
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index a53e382cc107..ac5d60edbafa 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c | |||
| @@ -645,13 +645,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
| 645 | */ | 645 | */ |
| 646 | case KDSIGACCEPT: | 646 | case KDSIGACCEPT: |
| 647 | { | 647 | { |
| 648 | extern int spawnpid, spawnsig; | ||
| 649 | if (!perm || !capable(CAP_KILL)) | 648 | if (!perm || !capable(CAP_KILL)) |
| 650 | return -EPERM; | 649 | return -EPERM; |
| 651 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) | 650 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) |
| 652 | return -EINVAL; | 651 | return -EINVAL; |
| 653 | spawnpid = current->pid; | 652 | |
| 654 | spawnsig = arg; | 653 | spin_lock_irq(&vt_spawn_con.lock); |
| 654 | put_pid(vt_spawn_con.pid); | ||
| 655 | vt_spawn_con.pid = get_pid(task_pid(current)); | ||
| 656 | vt_spawn_con.sig = arg; | ||
| 657 | spin_unlock_irq(&vt_spawn_con.lock); | ||
| 655 | return 0; | 658 | return 0; |
| 656 | } | 659 | } |
| 657 | 660 | ||
| @@ -669,7 +672,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
| 669 | vc->vt_mode = tmp; | 672 | vc->vt_mode = tmp; |
| 670 | /* the frsig is ignored, so we set it to 0 */ | 673 | /* the frsig is ignored, so we set it to 0 */ |
| 671 | vc->vt_mode.frsig = 0; | 674 | vc->vt_mode.frsig = 0; |
| 672 | vc->vt_pid = current->pid; | 675 | put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current)))); |
| 673 | /* no switch is required -- saw@shade.msu.ru */ | 676 | /* no switch is required -- saw@shade.msu.ru */ |
| 674 | vc->vt_newvt = -1; | 677 | vc->vt_newvt = -1; |
| 675 | release_console_sem(); | 678 | release_console_sem(); |
| @@ -1060,7 +1063,7 @@ void reset_vc(struct vc_data *vc) | |||
| 1060 | vc->vt_mode.relsig = 0; | 1063 | vc->vt_mode.relsig = 0; |
| 1061 | vc->vt_mode.acqsig = 0; | 1064 | vc->vt_mode.acqsig = 0; |
| 1062 | vc->vt_mode.frsig = 0; | 1065 | vc->vt_mode.frsig = 0; |
| 1063 | vc->vt_pid = -1; | 1066 | put_pid(xchg(&vc->vt_pid, NULL)); |
| 1064 | vc->vt_newvt = -1; | 1067 | vc->vt_newvt = -1; |
| 1065 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ | 1068 | if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ |
| 1066 | reset_palette(vc); | 1069 | reset_palette(vc); |
| @@ -1111,7 +1114,7 @@ static void complete_change_console(struct vc_data *vc) | |||
| 1111 | * tell us if the process has gone or something else | 1114 | * tell us if the process has gone or something else |
| 1112 | * is awry | 1115 | * is awry |
| 1113 | */ | 1116 | */ |
| 1114 | if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { | 1117 | if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) { |
| 1115 | /* | 1118 | /* |
| 1116 | * The controlling process has died, so we revert back to | 1119 | * The controlling process has died, so we revert back to |
| 1117 | * normal operation. In this case, we'll also change back | 1120 | * normal operation. In this case, we'll also change back |
| @@ -1171,7 +1174,7 @@ void change_console(struct vc_data *new_vc) | |||
| 1171 | * tell us if the process has gone or something else | 1174 | * tell us if the process has gone or something else |
| 1172 | * is awry | 1175 | * is awry |
| 1173 | */ | 1176 | */ |
| 1174 | if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { | 1177 | if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) { |
| 1175 | /* | 1178 | /* |
| 1176 | * It worked. Mark the vt to switch to and | 1179 | * It worked. Mark the vt to switch to and |
| 1177 | * return. The process needs to send us a | 1180 | * return. The process needs to send us a |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 42eaed88c281..a5456108dbad 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
| @@ -1601,7 +1601,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd) | |||
| 1601 | dev->mmap = ipath_mmap; | 1601 | dev->mmap = ipath_mmap; |
| 1602 | 1602 | ||
| 1603 | snprintf(dev->node_desc, sizeof(dev->node_desc), | 1603 | snprintf(dev->node_desc, sizeof(dev->node_desc), |
| 1604 | IPATH_IDSTR " %s", system_utsname.nodename); | 1604 | IPATH_IDSTR " %s", init_utsname()->nodename); |
| 1605 | 1605 | ||
| 1606 | ret = ib_register_device(dev); | 1606 | ret = ib_register_device(dev); |
| 1607 | if (ret) | 1607 | if (ret) |
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 58223b5d842a..96232313b1b9 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig | |||
| @@ -24,6 +24,20 @@ config INPUT | |||
| 24 | 24 | ||
| 25 | if INPUT | 25 | if INPUT |
| 26 | 26 | ||
| 27 | config INPUT_FF_MEMLESS | ||
| 28 | tristate "Support for memoryless force-feedback devices" | ||
| 29 | default n | ||
| 30 | ---help--- | ||
| 31 | Say Y here if you have memoryless force-feedback input device | ||
| 32 | such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual | ||
| 33 | Power 2, or similar. You will also need to enable hardware-specific | ||
| 34 | driver. | ||
| 35 | |||
| 36 | If unsure, say N. | ||
| 37 | |||
| 38 | To compile this driver as a module, choose M here: the | ||
| 39 | module will be called ff-memless. | ||
| 40 | |||
| 27 | comment "Userland interfaces" | 41 | comment "Userland interfaces" |
| 28 | 42 | ||
| 29 | config INPUT_MOUSEDEV | 43 | config INPUT_MOUSEDEV |
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 1a6ff4982f30..a005b1df5f1a 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile | |||
| @@ -4,7 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | # Each configuration option enables a list of files. | 5 | # Each configuration option enables a list of files. |
| 6 | 6 | ||
| 7 | obj-$(CONFIG_INPUT) += input.o | 7 | obj-$(CONFIG_INPUT) += input-core.o |
| 8 | input-core-objs := input.o ff-core.o | ||
| 9 | |||
| 10 | obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o | ||
| 11 | |||
| 8 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o | 12 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o |
| 9 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o | 13 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o |
| 10 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o | 14 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o |
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 07358fb51b82..5a9653c3128a 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c | |||
| @@ -42,10 +42,12 @@ static char evbug_name[] = "evbug"; | |||
| 42 | 42 | ||
| 43 | static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 43 | static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) |
| 44 | { | 44 | { |
| 45 | printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); | 45 | printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", |
| 46 | handle->dev->phys, type, code, value); | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 49 | static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, |
| 50 | const struct input_device_id *id) | ||
| 49 | { | 51 | { |
| 50 | struct input_handle *handle; | 52 | struct input_handle *handle; |
| 51 | 53 | ||
| @@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle) | |||
| 72 | kfree(handle); | 74 | kfree(handle); |
| 73 | } | 75 | } |
| 74 | 76 | ||
| 75 | static struct input_device_id evbug_ids[] = { | 77 | static const struct input_device_id evbug_ids[] = { |
| 76 | { .driver_info = 1 }, /* Matches all devices */ | 78 | { .driver_info = 1 }, /* Matches all devices */ |
| 77 | { }, /* Terminating zero entry */ | 79 | { }, /* Terminating zero entry */ |
| 78 | }; | 80 | }; |
| @@ -89,8 +91,7 @@ static struct input_handler evbug_handler = { | |||
| 89 | 91 | ||
| 90 | static int __init evbug_init(void) | 92 | static int __init evbug_init(void) |
| 91 | { | 93 | { |
| 92 | input_register_handler(&evbug_handler); | 94 | return input_register_handler(&evbug_handler); |
| 93 | return 0; | ||
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | static void __exit evbug_exit(void) | 97 | static void __exit evbug_exit(void) |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 4bf48188cc91..6439f378f6cc 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
| 391 | struct evdev *evdev = list->evdev; | 391 | struct evdev *evdev = list->evdev; |
| 392 | struct input_dev *dev = evdev->handle.dev; | 392 | struct input_dev *dev = evdev->handle.dev; |
| 393 | struct input_absinfo abs; | 393 | struct input_absinfo abs; |
| 394 | struct ff_effect effect; | ||
| 394 | int __user *ip = (int __user *)p; | 395 | int __user *ip = (int __user *)p; |
| 395 | int i, t, u, v; | 396 | int i, t, u, v; |
| 397 | int error; | ||
| 396 | 398 | ||
| 397 | if (!evdev->exist) | 399 | if (!evdev->exist) |
| 398 | return -ENODEV; | 400 | return -ENODEV; |
| @@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
| 460 | return 0; | 462 | return 0; |
| 461 | 463 | ||
| 462 | case EVIOCSFF: | 464 | case EVIOCSFF: |
| 463 | if (dev->upload_effect) { | 465 | if (copy_from_user(&effect, p, sizeof(effect))) |
| 464 | struct ff_effect effect; | 466 | return -EFAULT; |
| 465 | int err; | ||
| 466 | |||
| 467 | if (copy_from_user(&effect, p, sizeof(effect))) | ||
| 468 | return -EFAULT; | ||
| 469 | err = dev->upload_effect(dev, &effect); | ||
| 470 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | ||
| 471 | return -EFAULT; | ||
| 472 | return err; | ||
| 473 | } else | ||
| 474 | return -ENOSYS; | ||
| 475 | 467 | ||
| 476 | case EVIOCRMFF: | 468 | error = input_ff_upload(dev, &effect, file); |
| 477 | if (!dev->erase_effect) | ||
| 478 | return -ENOSYS; | ||
| 479 | 469 | ||
| 480 | return dev->erase_effect(dev, (int)(unsigned long) p); | 470 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) |
| 471 | return -EFAULT; | ||
| 472 | |||
| 473 | return error; | ||
| 474 | |||
| 475 | case EVIOCRMFF: | ||
| 476 | return input_ff_erase(dev, (int)(unsigned long) p, file); | ||
| 481 | 477 | ||
| 482 | case EVIOCGEFFECTS: | 478 | case EVIOCGEFFECTS: |
| 483 | if (put_user(dev->ff_effects_max, ip)) | 479 | i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0; |
| 480 | if (put_user(i, ip)) | ||
| 484 | return -EFAULT; | 481 | return -EFAULT; |
| 485 | return 0; | 482 | return 0; |
| 486 | 483 | ||
| @@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon | |||
| 604 | } | 601 | } |
| 605 | #endif | 602 | #endif |
| 606 | 603 | ||
| 607 | static struct file_operations evdev_fops = { | 604 | static const struct file_operations evdev_fops = { |
| 608 | .owner = THIS_MODULE, | 605 | .owner = THIS_MODULE, |
| 609 | .read = evdev_read, | 606 | .read = evdev_read, |
| 610 | .write = evdev_write, | 607 | .write = evdev_write, |
| @@ -619,7 +616,8 @@ static struct file_operations evdev_fops = { | |||
| 619 | .flush = evdev_flush | 616 | .flush = evdev_flush |
| 620 | }; | 617 | }; |
| 621 | 618 | ||
| 622 | static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 619 | static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, |
| 620 | const struct input_device_id *id) | ||
| 623 | { | 621 | { |
| 624 | struct evdev *evdev; | 622 | struct evdev *evdev; |
| 625 | struct class_device *cdev; | 623 | struct class_device *cdev; |
| @@ -669,6 +667,7 @@ static void evdev_disconnect(struct input_handle *handle) | |||
| 669 | evdev->exist = 0; | 667 | evdev->exist = 0; |
| 670 | 668 | ||
| 671 | if (evdev->open) { | 669 | if (evdev->open) { |
| 670 | input_flush_device(handle, NULL); | ||
| 672 | input_close_device(handle); | 671 | input_close_device(handle); |
| 673 | wake_up_interruptible(&evdev->wait); | 672 | wake_up_interruptible(&evdev->wait); |
| 674 | list_for_each_entry(list, &evdev->list, node) | 673 | list_for_each_entry(list, &evdev->list, node) |
| @@ -677,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle) | |||
| 677 | evdev_free(evdev); | 676 | evdev_free(evdev); |
| 678 | } | 677 | } |
| 679 | 678 | ||
| 680 | static struct input_device_id evdev_ids[] = { | 679 | static const struct input_device_id evdev_ids[] = { |
| 681 | { .driver_info = 1 }, /* Matches all devices */ | 680 | { .driver_info = 1 }, /* Matches all devices */ |
| 682 | { }, /* Terminating zero entry */ | 681 | { }, /* Terminating zero entry */ |
| 683 | }; | 682 | }; |
| @@ -696,8 +695,7 @@ static struct input_handler evdev_handler = { | |||
| 696 | 695 | ||
| 697 | static int __init evdev_init(void) | 696 | static int __init evdev_init(void) |
| 698 | { | 697 | { |
| 699 | input_register_handler(&evdev_handler); | 698 | return input_register_handler(&evdev_handler); |
| 700 | return 0; | ||
| 701 | } | 699 | } |
| 702 | 700 | ||
| 703 | static void __exit evdev_exit(void) | 701 | static void __exit evdev_exit(void) |
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c new file mode 100644 index 000000000000..35656cadc914 --- /dev/null +++ b/drivers/input/ff-core.c | |||
| @@ -0,0 +1,367 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for Linux input subsystem | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru> | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* #define DEBUG */ | ||
| 25 | |||
| 26 | #define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg) | ||
| 27 | |||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/mutex.h> | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Check that the effect_id is a valid effect and whether the user | ||
| 34 | * is the owner | ||
| 35 | */ | ||
| 36 | static int check_effect_access(struct ff_device *ff, int effect_id, | ||
| 37 | struct file *file) | ||
| 38 | { | ||
| 39 | if (effect_id < 0 || effect_id >= ff->max_effects || | ||
| 40 | !ff->effect_owners[effect_id]) | ||
| 41 | return -EINVAL; | ||
| 42 | |||
| 43 | if (file && ff->effect_owners[effect_id] != file) | ||
| 44 | return -EACCES; | ||
| 45 | |||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Checks whether 2 effects can be combined together | ||
| 51 | */ | ||
| 52 | static inline int check_effects_compatible(struct ff_effect *e1, | ||
| 53 | struct ff_effect *e2) | ||
| 54 | { | ||
| 55 | return e1->type == e2->type && | ||
| 56 | (e1->type != FF_PERIODIC || | ||
| 57 | e1->u.periodic.waveform == e2->u.periodic.waveform); | ||
| 58 | } | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Convert an effect into compatible one | ||
| 62 | */ | ||
| 63 | static int compat_effect(struct ff_device *ff, struct ff_effect *effect) | ||
| 64 | { | ||
| 65 | int magnitude; | ||
| 66 | |||
| 67 | switch (effect->type) { | ||
| 68 | case FF_RUMBLE: | ||
| 69 | if (!test_bit(FF_PERIODIC, ff->ffbit)) | ||
| 70 | return -EINVAL; | ||
| 71 | |||
| 72 | /* | ||
| 73 | * calculate manginude of sine wave as average of rumble's | ||
| 74 | * 2/3 of strong magnitude and 1/3 of weak magnitude | ||
| 75 | */ | ||
| 76 | magnitude = effect->u.rumble.strong_magnitude / 3 + | ||
| 77 | effect->u.rumble.weak_magnitude / 6; | ||
| 78 | |||
| 79 | effect->type = FF_PERIODIC; | ||
| 80 | effect->u.periodic.waveform = FF_SINE; | ||
| 81 | effect->u.periodic.period = 50; | ||
| 82 | effect->u.periodic.magnitude = max(magnitude, 0x7fff); | ||
| 83 | effect->u.periodic.offset = 0; | ||
| 84 | effect->u.periodic.phase = 0; | ||
| 85 | effect->u.periodic.envelope.attack_length = 0; | ||
| 86 | effect->u.periodic.envelope.attack_level = 0; | ||
| 87 | effect->u.periodic.envelope.fade_length = 0; | ||
| 88 | effect->u.periodic.envelope.fade_level = 0; | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | |||
| 92 | default: | ||
| 93 | /* Let driver handle conversion */ | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * input_ff_upload() - upload effect into force-feedback device | ||
| 100 | * @dev: input device | ||
| 101 | * @effect: effect to be uploaded | ||
| 102 | * @file: owner of the effect | ||
| 103 | */ | ||
| 104 | int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, | ||
| 105 | struct file *file) | ||
| 106 | { | ||
| 107 | struct ff_device *ff = dev->ff; | ||
| 108 | struct ff_effect *old; | ||
| 109 | int ret = 0; | ||
| 110 | int id; | ||
| 111 | |||
| 112 | if (!test_bit(EV_FF, dev->evbit)) | ||
| 113 | return -ENOSYS; | ||
| 114 | |||
| 115 | if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || | ||
| 116 | !test_bit(effect->type, dev->ffbit)) { | ||
| 117 | debug("invalid or not supported effect type in upload"); | ||
| 118 | return -EINVAL; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (effect->type == FF_PERIODIC && | ||
| 122 | (effect->u.periodic.waveform < FF_WAVEFORM_MIN || | ||
| 123 | effect->u.periodic.waveform > FF_WAVEFORM_MAX || | ||
| 124 | !test_bit(effect->u.periodic.waveform, dev->ffbit))) { | ||
| 125 | debug("invalid or not supported wave form in upload"); | ||
| 126 | return -EINVAL; | ||
| 127 | } | ||
| 128 | |||
| 129 | if (!test_bit(effect->type, ff->ffbit)) { | ||
| 130 | ret = compat_effect(ff, effect); | ||
| 131 | if (ret) | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 135 | mutex_lock(&ff->mutex); | ||
| 136 | |||
| 137 | if (effect->id == -1) { | ||
| 138 | for (id = 0; id < ff->max_effects; id++) | ||
| 139 | if (!ff->effect_owners[id]) | ||
| 140 | break; | ||
| 141 | |||
| 142 | if (id >= ff->max_effects) { | ||
| 143 | ret = -ENOSPC; | ||
| 144 | goto out; | ||
| 145 | } | ||
| 146 | |||
| 147 | effect->id = id; | ||
| 148 | old = NULL; | ||
| 149 | |||
| 150 | } else { | ||
| 151 | id = effect->id; | ||
| 152 | |||
| 153 | ret = check_effect_access(ff, id, file); | ||
| 154 | if (ret) | ||
| 155 | goto out; | ||
| 156 | |||
| 157 | old = &ff->effects[id]; | ||
| 158 | |||
| 159 | if (!check_effects_compatible(effect, old)) { | ||
| 160 | ret = -EINVAL; | ||
| 161 | goto out; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | ret = ff->upload(dev, effect, old); | ||
| 166 | if (ret) | ||
| 167 | goto out; | ||
| 168 | |||
| 169 | ff->effects[id] = *effect; | ||
| 170 | ff->effect_owners[id] = file; | ||
| 171 | |||
| 172 | out: | ||
| 173 | mutex_unlock(&ff->mutex); | ||
| 174 | return ret; | ||
| 175 | } | ||
| 176 | EXPORT_SYMBOL_GPL(input_ff_upload); | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Erases the effect if the requester is also the effect owner. The mutex | ||
| 180 | * should already be locked before calling this function. | ||
| 181 | */ | ||
| 182 | static int erase_effect(struct input_dev *dev, int effect_id, | ||
| 183 | struct file *file) | ||
| 184 | { | ||
| 185 | struct ff_device *ff = dev->ff; | ||
| 186 | int error; | ||
| 187 | |||
| 188 | error = check_effect_access(ff, effect_id, file); | ||
| 189 | if (error) | ||
| 190 | return error; | ||
| 191 | |||
| 192 | ff->playback(dev, effect_id, 0); | ||
| 193 | |||
| 194 | if (ff->erase) { | ||
| 195 | error = ff->erase(dev, effect_id); | ||
| 196 | if (error) | ||
| 197 | return error; | ||
| 198 | } | ||
| 199 | |||
| 200 | ff->effect_owners[effect_id] = NULL; | ||
| 201 | |||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * input_ff_erase - erase an effect from device | ||
| 207 | * @dev: input device to erase effect from | ||
| 208 | * @effect_id: id of the ffect to be erased | ||
| 209 | * @file: purported owner of the request | ||
| 210 | * | ||
| 211 | * This function erases a force-feedback effect from specified device. | ||
| 212 | * The effect will only be erased if it was uploaded through the same | ||
| 213 | * file handle that is requesting erase. | ||
| 214 | */ | ||
| 215 | int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) | ||
| 216 | { | ||
| 217 | struct ff_device *ff = dev->ff; | ||
| 218 | int ret; | ||
| 219 | |||
| 220 | if (!test_bit(EV_FF, dev->evbit)) | ||
| 221 | return -ENOSYS; | ||
| 222 | |||
| 223 | mutex_lock(&ff->mutex); | ||
| 224 | ret = erase_effect(dev, effect_id, file); | ||
| 225 | mutex_unlock(&ff->mutex); | ||
| 226 | |||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | EXPORT_SYMBOL_GPL(input_ff_erase); | ||
| 230 | |||
| 231 | /* | ||
| 232 | * flush_effects - erase all effects owned by a file handle | ||
| 233 | */ | ||
| 234 | static int flush_effects(struct input_dev *dev, struct file *file) | ||
| 235 | { | ||
| 236 | struct ff_device *ff = dev->ff; | ||
| 237 | int i; | ||
| 238 | |||
| 239 | debug("flushing now"); | ||
| 240 | |||
| 241 | mutex_lock(&ff->mutex); | ||
| 242 | |||
| 243 | for (i = 0; i < ff->max_effects; i++) | ||
| 244 | erase_effect(dev, i, file); | ||
| 245 | |||
| 246 | mutex_unlock(&ff->mutex); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * input_ff_event() - generic handler for force-feedback events | ||
| 253 | * @dev: input device to send the effect to | ||
| 254 | * @type: event type (anything but EV_FF is ignored) | ||
| 255 | * @code: event code | ||
| 256 | * @value: event value | ||
| 257 | */ | ||
| 258 | int input_ff_event(struct input_dev *dev, unsigned int type, | ||
| 259 | unsigned int code, int value) | ||
| 260 | { | ||
| 261 | struct ff_device *ff = dev->ff; | ||
| 262 | |||
| 263 | if (type != EV_FF) | ||
| 264 | return 0; | ||
| 265 | |||
| 266 | mutex_lock(&ff->mutex); | ||
| 267 | |||
| 268 | switch (code) { | ||
| 269 | case FF_GAIN: | ||
| 270 | if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff) | ||
| 271 | break; | ||
| 272 | |||
| 273 | ff->set_gain(dev, value); | ||
| 274 | break; | ||
| 275 | |||
| 276 | case FF_AUTOCENTER: | ||
| 277 | if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff) | ||
| 278 | break; | ||
| 279 | |||
| 280 | ff->set_autocenter(dev, value); | ||
| 281 | break; | ||
| 282 | |||
| 283 | default: | ||
| 284 | ff->playback(dev, code, value); | ||
| 285 | break; | ||
| 286 | } | ||
| 287 | |||
| 288 | mutex_unlock(&ff->mutex); | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | EXPORT_SYMBOL_GPL(input_ff_event); | ||
| 292 | |||
| 293 | /** | ||
| 294 | * input_ff_create() - create force-feedback device | ||
| 295 | * @dev: input device supporting force-feedback | ||
| 296 | * @max_effects: maximum number of effects supported by the device | ||
| 297 | * | ||
| 298 | * This function allocates all necessary memory for a force feedback | ||
| 299 | * portion of an input device and installs all default handlers. | ||
| 300 | * @dev->ffbit should be already set up before calling this function. | ||
| 301 | * Once ff device is created you need to setup its upload, erase, | ||
| 302 | * playback and other handlers before registering input device | ||
| 303 | */ | ||
| 304 | int input_ff_create(struct input_dev *dev, int max_effects) | ||
| 305 | { | ||
| 306 | struct ff_device *ff; | ||
| 307 | int i; | ||
| 308 | |||
| 309 | if (!max_effects) { | ||
| 310 | printk(KERN_ERR | ||
| 311 | "ff-core: cannot allocate device without any effects\n"); | ||
| 312 | return -EINVAL; | ||
| 313 | } | ||
| 314 | |||
| 315 | ff = kzalloc(sizeof(struct ff_device) + | ||
| 316 | max_effects * sizeof(struct file *), GFP_KERNEL); | ||
| 317 | if (!ff) | ||
| 318 | return -ENOMEM; | ||
| 319 | |||
| 320 | ff->effects = kcalloc(max_effects, sizeof(struct ff_effect), | ||
| 321 | GFP_KERNEL); | ||
| 322 | if (!ff->effects) { | ||
| 323 | kfree(ff); | ||
| 324 | return -ENOMEM; | ||
| 325 | } | ||
| 326 | |||
| 327 | ff->max_effects = max_effects; | ||
| 328 | mutex_init(&ff->mutex); | ||
| 329 | |||
| 330 | dev->ff = ff; | ||
| 331 | dev->flush = flush_effects; | ||
| 332 | dev->event = input_ff_event; | ||
| 333 | set_bit(EV_FF, dev->evbit); | ||
| 334 | |||
| 335 | /* Copy "true" bits into ff device bitmap */ | ||
| 336 | for (i = 0; i <= FF_MAX; i++) | ||
| 337 | if (test_bit(i, dev->ffbit)) | ||
| 338 | set_bit(i, ff->ffbit); | ||
| 339 | |||
| 340 | /* we can emulate RUMBLE with periodic effects */ | ||
| 341 | if (test_bit(FF_PERIODIC, ff->ffbit)) | ||
| 342 | set_bit(FF_RUMBLE, dev->ffbit); | ||
| 343 | |||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | EXPORT_SYMBOL_GPL(input_ff_create); | ||
| 347 | |||
| 348 | /** | ||
| 349 | * input_ff_free() - frees force feedback portion of input device | ||
| 350 | * @dev: input device supporintg force feedback | ||
| 351 | * | ||
| 352 | * This function is only needed in error path as input core will | ||
| 353 | * automatically free force feedback structures when device is | ||
| 354 | * destroyed. | ||
| 355 | */ | ||
| 356 | void input_ff_destroy(struct input_dev *dev) | ||
| 357 | { | ||
| 358 | clear_bit(EV_FF, dev->evbit); | ||
| 359 | if (dev->ff) { | ||
| 360 | if (dev->ff->destroy) | ||
| 361 | dev->ff->destroy(dev->ff); | ||
| 362 | kfree(dev->ff->private); | ||
| 363 | kfree(dev->ff); | ||
| 364 | dev->ff = NULL; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | EXPORT_SYMBOL_GPL(input_ff_destroy); | ||
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c new file mode 100644 index 000000000000..cd8b7297e6df --- /dev/null +++ b/drivers/input/ff-memless.c | |||
| @@ -0,0 +1,515 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for memoryless devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru> | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* #define DEBUG */ | ||
| 25 | |||
| 26 | #define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg) | ||
| 27 | |||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/module.h> | ||
| 30 | #include <linux/mutex.h> | ||
| 31 | #include <linux/spinlock.h> | ||
| 32 | #include <linux/sched.h> | ||
| 33 | |||
| 34 | #include "fixp-arith.h" | ||
| 35 | |||
| 36 | MODULE_LICENSE("GPL"); | ||
| 37 | MODULE_AUTHOR("Anssi Hannula <anssi.hannula@gmail.com>"); | ||
| 38 | MODULE_DESCRIPTION("Force feedback support for memoryless devices"); | ||
| 39 | |||
| 40 | /* Number of effects handled with memoryless devices */ | ||
| 41 | #define FF_MEMLESS_EFFECTS 16 | ||
| 42 | |||
| 43 | /* Envelope update interval in ms */ | ||
| 44 | #define FF_ENVELOPE_INTERVAL 50 | ||
| 45 | |||
| 46 | #define FF_EFFECT_STARTED 0 | ||
| 47 | #define FF_EFFECT_PLAYING 1 | ||
| 48 | #define FF_EFFECT_ABORTING 2 | ||
| 49 | |||
| 50 | struct ml_effect_state { | ||
| 51 | struct ff_effect *effect; | ||
| 52 | unsigned long flags; /* effect state (STARTED, PLAYING, etc) */ | ||
| 53 | int count; /* loop count of the effect */ | ||
| 54 | unsigned long play_at; /* start time */ | ||
| 55 | unsigned long stop_at; /* stop time */ | ||
| 56 | unsigned long adj_at; /* last time the effect was sent */ | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct ml_device { | ||
| 60 | void *private; | ||
| 61 | struct ml_effect_state states[FF_MEMLESS_EFFECTS]; | ||
| 62 | int gain; | ||
| 63 | struct timer_list timer; | ||
| 64 | spinlock_t timer_lock; | ||
| 65 | struct input_dev *dev; | ||
| 66 | |||
| 67 | int (*play_effect)(struct input_dev *dev, void *data, | ||
| 68 | struct ff_effect *effect); | ||
| 69 | }; | ||
| 70 | |||
| 71 | static const struct ff_envelope *get_envelope(const struct ff_effect *effect) | ||
| 72 | { | ||
| 73 | static const struct ff_envelope empty_envelope; | ||
| 74 | |||
| 75 | switch (effect->type) { | ||
| 76 | case FF_PERIODIC: | ||
| 77 | return &effect->u.periodic.envelope; | ||
| 78 | case FF_CONSTANT: | ||
| 79 | return &effect->u.constant.envelope; | ||
| 80 | default: | ||
| 81 | return &empty_envelope; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Check for the next time envelope requires an update on memoryless devices | ||
| 87 | */ | ||
| 88 | static unsigned long calculate_next_time(struct ml_effect_state *state) | ||
| 89 | { | ||
| 90 | const struct ff_envelope *envelope = get_envelope(state->effect); | ||
| 91 | unsigned long attack_stop, fade_start, next_fade; | ||
| 92 | |||
| 93 | if (envelope->attack_length) { | ||
| 94 | attack_stop = state->play_at + | ||
| 95 | msecs_to_jiffies(envelope->attack_length); | ||
| 96 | if (time_before(state->adj_at, attack_stop)) | ||
| 97 | return state->adj_at + | ||
| 98 | msecs_to_jiffies(FF_ENVELOPE_INTERVAL); | ||
| 99 | } | ||
| 100 | |||
| 101 | if (state->effect->replay.length) { | ||
| 102 | if (envelope->fade_length) { | ||
| 103 | /* check when fading should start */ | ||
| 104 | fade_start = state->stop_at - | ||
| 105 | msecs_to_jiffies(envelope->fade_length); | ||
| 106 | |||
| 107 | if (time_before(state->adj_at, fade_start)) | ||
| 108 | return fade_start; | ||
| 109 | |||
| 110 | /* already fading, advance to next checkpoint */ | ||
| 111 | next_fade = state->adj_at + | ||
| 112 | msecs_to_jiffies(FF_ENVELOPE_INTERVAL); | ||
| 113 | if (time_before(next_fade, state->stop_at)) | ||
| 114 | return next_fade; | ||
| 115 | } | ||
| 116 | |||
| 117 | return state->stop_at; | ||
| 118 | } | ||
| 119 | |||
| 120 | return state->play_at; | ||
| 121 | } | ||
| 122 | |||
| 123 | static void ml_schedule_timer(struct ml_device *ml) | ||
| 124 | { | ||
| 125 | struct ml_effect_state *state; | ||
| 126 | unsigned long now = jiffies; | ||
| 127 | unsigned long earliest = 0; | ||
| 128 | unsigned long next_at; | ||
| 129 | int events = 0; | ||
| 130 | int i; | ||
| 131 | |||
| 132 | debug("calculating next timer"); | ||
| 133 | |||
| 134 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { | ||
| 135 | |||
| 136 | state = &ml->states[i]; | ||
| 137 | |||
| 138 | if (!test_bit(FF_EFFECT_STARTED, &state->flags)) | ||
| 139 | continue; | ||
| 140 | |||
| 141 | if (test_bit(FF_EFFECT_PLAYING, &state->flags)) | ||
| 142 | next_at = calculate_next_time(state); | ||
| 143 | else | ||
| 144 | next_at = state->play_at; | ||
| 145 | |||
| 146 | if (time_before_eq(now, next_at) && | ||
| 147 | (++events == 1 || time_before(next_at, earliest))) | ||
| 148 | earliest = next_at; | ||
| 149 | } | ||
| 150 | |||
| 151 | if (!events) { | ||
| 152 | debug("no actions"); | ||
| 153 | del_timer(&ml->timer); | ||
| 154 | } else { | ||
| 155 | debug("timer set"); | ||
| 156 | mod_timer(&ml->timer, earliest); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | /* | ||
| 161 | * Apply an envelope to a value | ||
| 162 | */ | ||
| 163 | static int apply_envelope(struct ml_effect_state *state, int value, | ||
| 164 | struct ff_envelope *envelope) | ||
| 165 | { | ||
| 166 | struct ff_effect *effect = state->effect; | ||
| 167 | unsigned long now = jiffies; | ||
| 168 | int time_from_level; | ||
| 169 | int time_of_envelope; | ||
| 170 | int envelope_level; | ||
| 171 | int difference; | ||
| 172 | |||
| 173 | if (envelope->attack_length && | ||
| 174 | time_before(now, | ||
| 175 | state->play_at + msecs_to_jiffies(envelope->attack_length))) { | ||
| 176 | debug("value = 0x%x, attack_level = 0x%x", value, | ||
| 177 | envelope->attack_level); | ||
| 178 | time_from_level = jiffies_to_msecs(now - state->play_at); | ||
| 179 | time_of_envelope = envelope->attack_length; | ||
| 180 | envelope_level = min_t(__s16, envelope->attack_level, 0x7fff); | ||
| 181 | |||
| 182 | } else if (envelope->fade_length && effect->replay.length && | ||
| 183 | time_after(now, | ||
| 184 | state->stop_at - msecs_to_jiffies(envelope->fade_length)) && | ||
| 185 | time_before(now, state->stop_at)) { | ||
| 186 | time_from_level = jiffies_to_msecs(state->stop_at - now); | ||
| 187 | time_of_envelope = envelope->fade_length; | ||
| 188 | envelope_level = min_t(__s16, envelope->fade_level, 0x7fff); | ||
| 189 | } else | ||
| 190 | return value; | ||
| 191 | |||
| 192 | difference = abs(value) - envelope_level; | ||
| 193 | |||
| 194 | debug("difference = %d", difference); | ||
| 195 | debug("time_from_level = 0x%x", time_from_level); | ||
| 196 | debug("time_of_envelope = 0x%x", time_of_envelope); | ||
| 197 | |||
| 198 | difference = difference * time_from_level / time_of_envelope; | ||
| 199 | |||
| 200 | debug("difference = %d", difference); | ||
| 201 | |||
| 202 | return value < 0 ? | ||
| 203 | -(difference + envelope_level) : (difference + envelope_level); | ||
| 204 | } | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Return the type the effect has to be converted into (memless devices) | ||
| 208 | */ | ||
| 209 | static int get_compatible_type(struct ff_device *ff, int effect_type) | ||
| 210 | { | ||
| 211 | |||
| 212 | if (test_bit(effect_type, ff->ffbit)) | ||
| 213 | return effect_type; | ||
| 214 | |||
| 215 | if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) | ||
| 216 | return FF_RUMBLE; | ||
| 217 | |||
| 218 | printk(KERN_ERR | ||
| 219 | "ff-memless: invalid type in get_compatible_type()\n"); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Combine two effects and apply gain. | ||
| 226 | */ | ||
| 227 | static void ml_combine_effects(struct ff_effect *effect, | ||
| 228 | struct ml_effect_state *state, | ||
| 229 | int gain) | ||
| 230 | { | ||
| 231 | struct ff_effect *new = state->effect; | ||
| 232 | unsigned int strong, weak, i; | ||
| 233 | int x, y; | ||
| 234 | fixp_t level; | ||
| 235 | |||
| 236 | switch (new->type) { | ||
| 237 | case FF_CONSTANT: | ||
| 238 | i = new->direction * 360 / 0xffff; | ||
| 239 | level = fixp_new16(apply_envelope(state, | ||
| 240 | new->u.constant.level, | ||
| 241 | &new->u.constant.envelope)); | ||
| 242 | x = fixp_mult(fixp_sin(i), level) * gain / 0xffff; | ||
| 243 | y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff; | ||
| 244 | /* | ||
| 245 | * here we abuse ff_ramp to hold x and y of constant force | ||
| 246 | * If in future any driver wants something else than x and y | ||
| 247 | * in s8, this should be changed to something more generic | ||
| 248 | */ | ||
| 249 | effect->u.ramp.start_level = | ||
| 250 | max(min(effect->u.ramp.start_level + x, 0x7f), -0x80); | ||
| 251 | effect->u.ramp.end_level = | ||
| 252 | max(min(effect->u.ramp.end_level + y, 0x7f), -0x80); | ||
| 253 | break; | ||
| 254 | |||
| 255 | case FF_RUMBLE: | ||
| 256 | strong = new->u.rumble.strong_magnitude * gain / 0xffff; | ||
| 257 | weak = new->u.rumble.weak_magnitude * gain / 0xffff; | ||
| 258 | effect->u.rumble.strong_magnitude = | ||
| 259 | min(strong + effect->u.rumble.strong_magnitude, | ||
| 260 | 0xffffU); | ||
| 261 | effect->u.rumble.weak_magnitude = | ||
| 262 | min(weak + effect->u.rumble.weak_magnitude, 0xffffU); | ||
| 263 | break; | ||
| 264 | |||
| 265 | case FF_PERIODIC: | ||
| 266 | i = apply_envelope(state, abs(new->u.periodic.magnitude), | ||
| 267 | &new->u.periodic.envelope); | ||
| 268 | |||
| 269 | /* here we also scale it 0x7fff => 0xffff */ | ||
| 270 | i = i * gain / 0x7fff; | ||
| 271 | |||
| 272 | effect->u.rumble.strong_magnitude = | ||
| 273 | min(i + effect->u.rumble.strong_magnitude, 0xffffU); | ||
| 274 | effect->u.rumble.weak_magnitude = | ||
| 275 | min(i + effect->u.rumble.weak_magnitude, 0xffffU); | ||
| 276 | break; | ||
| 277 | |||
| 278 | default: | ||
| 279 | printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n"); | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | |||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | /* | ||
| 287 | * Because memoryless devices have only one effect per effect type active | ||
| 288 | * at one time we have to combine multiple effects into one | ||
| 289 | */ | ||
| 290 | static int ml_get_combo_effect(struct ml_device *ml, | ||
| 291 | unsigned long *effect_handled, | ||
| 292 | struct ff_effect *combo_effect) | ||
| 293 | { | ||
| 294 | struct ff_effect *effect; | ||
| 295 | struct ml_effect_state *state; | ||
| 296 | int effect_type; | ||
| 297 | int i; | ||
| 298 | |||
| 299 | memset(combo_effect, 0, sizeof(struct ff_effect)); | ||
| 300 | |||
| 301 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { | ||
| 302 | if (__test_and_set_bit(i, effect_handled)) | ||
| 303 | continue; | ||
| 304 | |||
| 305 | state = &ml->states[i]; | ||
| 306 | effect = state->effect; | ||
| 307 | |||
| 308 | if (!test_bit(FF_EFFECT_STARTED, &state->flags)) | ||
| 309 | continue; | ||
| 310 | |||
| 311 | if (time_before(jiffies, state->play_at)) | ||
| 312 | continue; | ||
| 313 | |||
| 314 | /* | ||
| 315 | * here we have started effects that are either | ||
| 316 | * currently playing (and may need be aborted) | ||
| 317 | * or need to start playing. | ||
| 318 | */ | ||
| 319 | effect_type = get_compatible_type(ml->dev->ff, effect->type); | ||
| 320 | if (combo_effect->type != effect_type) { | ||
| 321 | if (combo_effect->type != 0) { | ||
| 322 | __clear_bit(i, effect_handled); | ||
| 323 | continue; | ||
| 324 | } | ||
| 325 | combo_effect->type = effect_type; | ||
| 326 | } | ||
| 327 | |||
| 328 | if (__test_and_clear_bit(FF_EFFECT_ABORTING, &state->flags)) { | ||
| 329 | __clear_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 330 | __clear_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 331 | } else if (effect->replay.length && | ||
| 332 | time_after_eq(jiffies, state->stop_at)) { | ||
| 333 | |||
| 334 | __clear_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 335 | |||
| 336 | if (--state->count <= 0) { | ||
| 337 | __clear_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 338 | } else { | ||
| 339 | state->play_at = jiffies + | ||
| 340 | msecs_to_jiffies(effect->replay.delay); | ||
| 341 | state->stop_at = state->play_at + | ||
| 342 | msecs_to_jiffies(effect->replay.length); | ||
| 343 | } | ||
| 344 | } else { | ||
| 345 | __set_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 346 | state->adj_at = jiffies; | ||
| 347 | ml_combine_effects(combo_effect, state, ml->gain); | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | return combo_effect->type != 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static void ml_play_effects(struct ml_device *ml) | ||
| 355 | { | ||
| 356 | struct ff_effect effect; | ||
| 357 | DECLARE_BITMAP(handled_bm, FF_MEMLESS_EFFECTS); | ||
| 358 | |||
| 359 | memset(handled_bm, 0, sizeof(handled_bm)); | ||
| 360 | |||
| 361 | while (ml_get_combo_effect(ml, handled_bm, &effect)) | ||
| 362 | ml->play_effect(ml->dev, ml->private, &effect); | ||
| 363 | |||
| 364 | ml_schedule_timer(ml); | ||
| 365 | } | ||
| 366 | |||
| 367 | static void ml_effect_timer(unsigned long timer_data) | ||
| 368 | { | ||
| 369 | struct input_dev *dev = (struct input_dev *)timer_data; | ||
| 370 | struct ml_device *ml = dev->ff->private; | ||
| 371 | |||
| 372 | debug("timer: updating effects"); | ||
| 373 | |||
| 374 | spin_lock(&ml->timer_lock); | ||
| 375 | ml_play_effects(ml); | ||
| 376 | spin_unlock(&ml->timer_lock); | ||
| 377 | } | ||
| 378 | |||
| 379 | static void ml_ff_set_gain(struct input_dev *dev, u16 gain) | ||
| 380 | { | ||
| 381 | struct ml_device *ml = dev->ff->private; | ||
| 382 | int i; | ||
| 383 | |||
| 384 | spin_lock_bh(&ml->timer_lock); | ||
| 385 | |||
| 386 | ml->gain = gain; | ||
| 387 | |||
| 388 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) | ||
| 389 | __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags); | ||
| 390 | |||
| 391 | ml_play_effects(ml); | ||
| 392 | |||
| 393 | spin_unlock_bh(&ml->timer_lock); | ||
| 394 | } | ||
| 395 | |||
| 396 | static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) | ||
| 397 | { | ||
| 398 | struct ml_device *ml = dev->ff->private; | ||
| 399 | struct ml_effect_state *state = &ml->states[effect_id]; | ||
| 400 | |||
| 401 | spin_lock_bh(&ml->timer_lock); | ||
| 402 | |||
| 403 | if (value > 0) { | ||
| 404 | debug("initiated play"); | ||
| 405 | |||
| 406 | __set_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 407 | state->count = value; | ||
| 408 | state->play_at = jiffies + | ||
| 409 | msecs_to_jiffies(state->effect->replay.delay); | ||
| 410 | state->stop_at = state->play_at + | ||
| 411 | msecs_to_jiffies(state->effect->replay.length); | ||
| 412 | state->adj_at = state->play_at; | ||
| 413 | |||
| 414 | ml_schedule_timer(ml); | ||
| 415 | |||
| 416 | } else { | ||
| 417 | debug("initiated stop"); | ||
| 418 | |||
| 419 | if (test_bit(FF_EFFECT_PLAYING, &state->flags)) | ||
| 420 | __set_bit(FF_EFFECT_ABORTING, &state->flags); | ||
| 421 | else | ||
| 422 | __clear_bit(FF_EFFECT_STARTED, &state->flags); | ||
| 423 | |||
| 424 | ml_play_effects(ml); | ||
| 425 | } | ||
| 426 | |||
| 427 | spin_unlock_bh(&ml->timer_lock); | ||
| 428 | |||
| 429 | return 0; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int ml_ff_upload(struct input_dev *dev, | ||
| 433 | struct ff_effect *effect, struct ff_effect *old) | ||
| 434 | { | ||
| 435 | struct ml_device *ml = dev->ff->private; | ||
| 436 | struct ml_effect_state *state = &ml->states[effect->id]; | ||
| 437 | |||
| 438 | spin_lock_bh(&ml->timer_lock); | ||
| 439 | |||
| 440 | if (test_bit(FF_EFFECT_STARTED, &state->flags)) { | ||
| 441 | __clear_bit(FF_EFFECT_PLAYING, &state->flags); | ||
| 442 | state->play_at = jiffies + | ||
| 443 | msecs_to_jiffies(state->effect->replay.delay); | ||
| 444 | state->stop_at = state->play_at + | ||
| 445 | msecs_to_jiffies(state->effect->replay.length); | ||
| 446 | state->adj_at = state->play_at; | ||
| 447 | ml_schedule_timer(ml); | ||
| 448 | } | ||
| 449 | |||
| 450 | spin_unlock_bh(&ml->timer_lock); | ||
| 451 | |||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 455 | static void ml_ff_destroy(struct ff_device *ff) | ||
| 456 | { | ||
| 457 | struct ml_device *ml = ff->private; | ||
| 458 | |||
| 459 | kfree(ml->private); | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 463 | * input_ff_create_memless() - create memoryless FF device | ||
| 464 | * @dev: input device supporting force-feedback | ||
| 465 | * @data: driver-specific data to be passed into @play_effect | ||
| 466 | * @play_effect: driver-specific method for playing FF effect | ||
| 467 | */ | ||
| 468 | int input_ff_create_memless(struct input_dev *dev, void *data, | ||
| 469 | int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) | ||
| 470 | { | ||
| 471 | struct ml_device *ml; | ||
| 472 | struct ff_device *ff; | ||
| 473 | int error; | ||
| 474 | int i; | ||
| 475 | |||
| 476 | ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL); | ||
| 477 | if (!ml) | ||
| 478 | return -ENOMEM; | ||
| 479 | |||
| 480 | ml->dev = dev; | ||
| 481 | ml->private = data; | ||
| 482 | ml->play_effect = play_effect; | ||
| 483 | ml->gain = 0xffff; | ||
| 484 | spin_lock_init(&ml->timer_lock); | ||
| 485 | setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev); | ||
| 486 | |||
| 487 | set_bit(FF_GAIN, dev->ffbit); | ||
| 488 | |||
| 489 | error = input_ff_create(dev, FF_MEMLESS_EFFECTS); | ||
| 490 | if (error) { | ||
| 491 | kfree(ml); | ||
| 492 | return error; | ||
| 493 | } | ||
| 494 | |||
| 495 | ff = dev->ff; | ||
| 496 | ff->private = ml; | ||
| 497 | ff->upload = ml_ff_upload; | ||
| 498 | ff->playback = ml_ff_playback; | ||
| 499 | ff->set_gain = ml_ff_set_gain; | ||
| 500 | ff->destroy = ml_ff_destroy; | ||
| 501 | |||
| 502 | /* we can emulate periodic effects with RUMBLE */ | ||
| 503 | if (test_bit(FF_RUMBLE, ff->ffbit)) { | ||
| 504 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 505 | set_bit(FF_SINE, dev->ffbit); | ||
| 506 | set_bit(FF_TRIANGLE, dev->ffbit); | ||
| 507 | set_bit(FF_SQUARE, dev->ffbit); | ||
| 508 | } | ||
| 509 | |||
| 510 | for (i = 0; i < FF_MEMLESS_EFFECTS; i++) | ||
| 511 | ml->states[i].effect = &ff->effects[i]; | ||
| 512 | |||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | EXPORT_SYMBOL_GPL(input_ff_create_memless); | ||
diff --git a/drivers/usb/input/fixp-arith.h b/drivers/input/fixp-arith.h index ed3d2da0c485..ed3d2da0c485 100644 --- a/drivers/usb/input/fixp-arith.h +++ b/drivers/input/fixp-arith.h | |||
diff --git a/drivers/input/input.c b/drivers/input/input.c index 9cb4b9a54f01..1c8c8a5bc4a9 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
| @@ -176,6 +176,10 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in | |||
| 176 | break; | 176 | break; |
| 177 | 177 | ||
| 178 | case EV_FF: | 178 | case EV_FF: |
| 179 | |||
| 180 | if (value < 0) | ||
| 181 | return; | ||
| 182 | |||
| 179 | if (dev->event) | 183 | if (dev->event) |
| 180 | dev->event(dev, type, code, value); | 184 | dev->event(dev, type, code, value); |
| 181 | break; | 185 | break; |
| @@ -309,7 +313,8 @@ static void input_link_handle(struct input_handle *handle) | |||
| 309 | if (i != NBITS(max)) \ | 313 | if (i != NBITS(max)) \ |
| 310 | continue; | 314 | continue; |
| 311 | 315 | ||
| 312 | static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) | 316 | static const struct input_device_id *input_match_device(const struct input_device_id *id, |
| 317 | struct input_dev *dev) | ||
| 313 | { | 318 | { |
| 314 | int i; | 319 | int i; |
| 315 | 320 | ||
| @@ -762,7 +767,9 @@ static void input_dev_release(struct class_device *class_dev) | |||
| 762 | { | 767 | { |
| 763 | struct input_dev *dev = to_input_dev(class_dev); | 768 | struct input_dev *dev = to_input_dev(class_dev); |
| 764 | 769 | ||
| 770 | input_ff_destroy(dev); | ||
| 765 | kfree(dev); | 771 | kfree(dev); |
| 772 | |||
| 766 | module_put(THIS_MODULE); | 773 | module_put(THIS_MODULE); |
| 767 | } | 774 | } |
| 768 | 775 | ||
| @@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(void) | |||
| 899 | 906 | ||
| 900 | dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); | 907 | dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); |
| 901 | if (dev) { | 908 | if (dev) { |
| 902 | dev->dynalloc = 1; | ||
| 903 | dev->cdev.class = &input_class; | 909 | dev->cdev.class = &input_class; |
| 904 | class_device_initialize(&dev->cdev); | 910 | class_device_initialize(&dev->cdev); |
| 905 | mutex_init(&dev->mutex); | 911 | mutex_init(&dev->mutex); |
| 906 | INIT_LIST_HEAD(&dev->h_list); | 912 | INIT_LIST_HEAD(&dev->h_list); |
| 907 | INIT_LIST_HEAD(&dev->node); | 913 | INIT_LIST_HEAD(&dev->node); |
| 914 | |||
| 915 | __module_get(THIS_MODULE); | ||
| 908 | } | 916 | } |
| 909 | 917 | ||
| 910 | return dev; | 918 | return dev; |
| @@ -929,17 +937,10 @@ int input_register_device(struct input_dev *dev) | |||
| 929 | static atomic_t input_no = ATOMIC_INIT(0); | 937 | static atomic_t input_no = ATOMIC_INIT(0); |
| 930 | struct input_handle *handle; | 938 | struct input_handle *handle; |
| 931 | struct input_handler *handler; | 939 | struct input_handler *handler; |
| 932 | struct input_device_id *id; | 940 | const struct input_device_id *id; |
| 933 | const char *path; | 941 | const char *path; |
| 934 | int error; | 942 | int error; |
| 935 | 943 | ||
| 936 | if (!dev->dynalloc) { | ||
| 937 | printk(KERN_WARNING "input: device %s is statically allocated, will not register\n" | ||
| 938 | "Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n", | ||
| 939 | dev->name ? dev->name : "<Unknown>"); | ||
| 940 | return -EINVAL; | ||
| 941 | } | ||
| 942 | |||
| 943 | set_bit(EV_SYN, dev->evbit); | 944 | set_bit(EV_SYN, dev->evbit); |
| 944 | 945 | ||
| 945 | /* | 946 | /* |
| @@ -955,10 +956,8 @@ int input_register_device(struct input_dev *dev) | |||
| 955 | dev->rep[REP_PERIOD] = 33; | 956 | dev->rep[REP_PERIOD] = 33; |
| 956 | } | 957 | } |
| 957 | 958 | ||
| 958 | INIT_LIST_HEAD(&dev->h_list); | ||
| 959 | list_add_tail(&dev->node, &input_dev_list); | 959 | list_add_tail(&dev->node, &input_dev_list); |
| 960 | 960 | ||
| 961 | dev->cdev.class = &input_class; | ||
| 962 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), | 961 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), |
| 963 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); | 962 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); |
| 964 | 963 | ||
| @@ -978,8 +977,6 @@ int input_register_device(struct input_dev *dev) | |||
| 978 | if (error) | 977 | if (error) |
| 979 | goto fail3; | 978 | goto fail3; |
| 980 | 979 | ||
| 981 | __module_get(THIS_MODULE); | ||
| 982 | |||
| 983 | path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); | 980 | path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); |
| 984 | printk(KERN_INFO "input: %s as %s\n", | 981 | printk(KERN_INFO "input: %s as %s\n", |
| 985 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); | 982 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); |
| @@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device); | |||
| 1008 | void input_unregister_device(struct input_dev *dev) | 1005 | void input_unregister_device(struct input_dev *dev) |
| 1009 | { | 1006 | { |
| 1010 | struct list_head *node, *next; | 1007 | struct list_head *node, *next; |
| 1008 | int code; | ||
| 1011 | 1009 | ||
| 1012 | if (!dev) | 1010 | for (code = 0; code <= KEY_MAX; code++) |
| 1013 | return; | 1011 | if (test_bit(code, dev->key)) |
| 1012 | input_report_key(dev, code, 0); | ||
| 1013 | input_sync(dev); | ||
| 1014 | 1014 | ||
| 1015 | del_timer_sync(&dev->timer); | 1015 | del_timer_sync(&dev->timer); |
| 1016 | 1016 | ||
| @@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev) | |||
| 1037 | } | 1037 | } |
| 1038 | EXPORT_SYMBOL(input_unregister_device); | 1038 | EXPORT_SYMBOL(input_unregister_device); |
| 1039 | 1039 | ||
| 1040 | void input_register_handler(struct input_handler *handler) | 1040 | int input_register_handler(struct input_handler *handler) |
| 1041 | { | 1041 | { |
| 1042 | struct input_dev *dev; | 1042 | struct input_dev *dev; |
| 1043 | struct input_handle *handle; | 1043 | struct input_handle *handle; |
| 1044 | struct input_device_id *id; | 1044 | const struct input_device_id *id; |
| 1045 | |||
| 1046 | if (!handler) | ||
| 1047 | return; | ||
| 1048 | 1045 | ||
| 1049 | INIT_LIST_HEAD(&handler->h_list); | 1046 | INIT_LIST_HEAD(&handler->h_list); |
| 1050 | 1047 | ||
| 1051 | if (handler->fops != NULL) | 1048 | if (handler->fops != NULL) { |
| 1049 | if (input_table[handler->minor >> 5]) | ||
| 1050 | return -EBUSY; | ||
| 1051 | |||
| 1052 | input_table[handler->minor >> 5] = handler; | 1052 | input_table[handler->minor >> 5] = handler; |
| 1053 | } | ||
| 1053 | 1054 | ||
| 1054 | list_add_tail(&handler->node, &input_handler_list); | 1055 | list_add_tail(&handler->node, &input_handler_list); |
| 1055 | 1056 | ||
| @@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler) | |||
| 1063 | } | 1064 | } |
| 1064 | 1065 | ||
| 1065 | input_wakeup_procfs_readers(); | 1066 | input_wakeup_procfs_readers(); |
| 1067 | return 0; | ||
| 1066 | } | 1068 | } |
| 1067 | EXPORT_SYMBOL(input_register_handler); | 1069 | EXPORT_SYMBOL(input_register_handler); |
| 1068 | 1070 | ||
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index d67157513bf7..9f3529ad3fda 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
| @@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
| 451 | } | 451 | } |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | static struct file_operations joydev_fops = { | 454 | static const struct file_operations joydev_fops = { |
| 455 | .owner = THIS_MODULE, | 455 | .owner = THIS_MODULE, |
| 456 | .read = joydev_read, | 456 | .read = joydev_read, |
| 457 | .write = joydev_write, | 457 | .write = joydev_write, |
| @@ -465,7 +465,8 @@ static struct file_operations joydev_fops = { | |||
| 465 | .fasync = joydev_fasync, | 465 | .fasync = joydev_fasync, |
| 466 | }; | 466 | }; |
| 467 | 467 | ||
| 468 | static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 468 | static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, |
| 469 | const struct input_device_id *id) | ||
| 469 | { | 470 | { |
| 470 | struct joydev *joydev; | 471 | struct joydev *joydev; |
| 471 | struct class_device *cdev; | 472 | struct class_device *cdev; |
| @@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle) | |||
| 562 | joydev_free(joydev); | 563 | joydev_free(joydev); |
| 563 | } | 564 | } |
| 564 | 565 | ||
| 565 | static struct input_device_id joydev_blacklist[] = { | 566 | static const struct input_device_id joydev_blacklist[] = { |
| 566 | { | 567 | { |
| 567 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 568 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, |
| 568 | .evbit = { BIT(EV_KEY) }, | 569 | .evbit = { BIT(EV_KEY) }, |
| @@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = { | |||
| 571 | { } /* Terminating entry */ | 572 | { } /* Terminating entry */ |
| 572 | }; | 573 | }; |
| 573 | 574 | ||
| 574 | static struct input_device_id joydev_ids[] = { | 575 | static const struct input_device_id joydev_ids[] = { |
| 575 | { | 576 | { |
| 576 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 577 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, |
| 577 | .evbit = { BIT(EV_ABS) }, | 578 | .evbit = { BIT(EV_ABS) }, |
| @@ -605,8 +606,7 @@ static struct input_handler joydev_handler = { | |||
| 605 | 606 | ||
| 606 | static int __init joydev_init(void) | 607 | static int __init joydev_init(void) |
| 607 | { | 608 | { |
| 608 | input_register_handler(&joydev_handler); | 609 | return input_register_handler(&joydev_handler); |
| 609 | return 0; | ||
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | static void __exit joydev_exit(void) | 612 | static void __exit joydev_exit(void) |
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 50c90765aee1..8fb0c19cc60e 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c | |||
| @@ -165,19 +165,19 @@ static int make_condition_modifier(struct iforce* iforce, | |||
| 165 | data[0] = LO(mod_chunk->start); | 165 | data[0] = LO(mod_chunk->start); |
| 166 | data[1] = HI(mod_chunk->start); | 166 | data[1] = HI(mod_chunk->start); |
| 167 | 167 | ||
| 168 | data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ | 168 | data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ |
| 169 | data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ | 169 | data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */ |
| 170 | 170 | ||
| 171 | center = (500*center)>>15; | 171 | center = (500 * center) >> 15; |
| 172 | data[4] = LO(center); | 172 | data[4] = LO(center); |
| 173 | data[5] = HI(center); | 173 | data[5] = HI(center); |
| 174 | 174 | ||
| 175 | db = (1000*db)>>16; | 175 | db = (1000 * db) >> 16; |
| 176 | data[6] = LO(db); | 176 | data[6] = LO(db); |
| 177 | data[7] = HI(db); | 177 | data[7] = HI(db); |
| 178 | 178 | ||
| 179 | data[8] = (100*rsat)>>16; | 179 | data[8] = (100 * rsat) >> 16; |
| 180 | data[9] = (100*lsat)>>16; | 180 | data[9] = (100 * lsat) >> 16; |
| 181 | 181 | ||
| 182 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); | 182 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); |
| 183 | iforce_dump_packet("condition", FF_CMD_CONDITION, data); | 183 | iforce_dump_packet("condition", FF_CMD_CONDITION, data); |
| @@ -188,6 +188,7 @@ static int make_condition_modifier(struct iforce* iforce, | |||
| 188 | static unsigned char find_button(struct iforce *iforce, signed short button) | 188 | static unsigned char find_button(struct iforce *iforce, signed short button) |
| 189 | { | 189 | { |
| 190 | int i; | 190 | int i; |
| 191 | |||
| 191 | for (i = 1; iforce->type->btn[i] >= 0; i++) | 192 | for (i = 1; iforce->type->btn[i] >= 0; i++) |
| 192 | if (iforce->type->btn[i] == button) | 193 | if (iforce->type->btn[i] == button) |
| 193 | return i + 1; | 194 | return i + 1; |
| @@ -198,19 +199,17 @@ static unsigned char find_button(struct iforce *iforce, signed short button) | |||
| 198 | * Analyse the changes in an effect, and tell if we need to send an condition | 199 | * Analyse the changes in an effect, and tell if we need to send an condition |
| 199 | * parameter packet | 200 | * parameter packet |
| 200 | */ | 201 | */ |
| 201 | static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | 202 | static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new) |
| 202 | { | 203 | { |
| 203 | int id = new->id; | 204 | int ret = 0; |
| 204 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 205 | int ret=0; | ||
| 206 | int i; | 205 | int i; |
| 207 | 206 | ||
| 208 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { | 207 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { |
| 209 | printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); | 208 | printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); |
| 210 | return FALSE; | 209 | return 0; |
| 211 | } | 210 | } |
| 212 | 211 | ||
| 213 | for(i=0; i<2; i++) { | 212 | for (i = 0; i < 2; i++) { |
| 214 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation | 213 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation |
| 215 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation | 214 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation |
| 216 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff | 215 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff |
| @@ -225,35 +224,29 @@ static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | |||
| 225 | * Analyse the changes in an effect, and tell if we need to send a magnitude | 224 | * Analyse the changes in an effect, and tell if we need to send a magnitude |
| 226 | * parameter packet | 225 | * parameter packet |
| 227 | */ | 226 | */ |
| 228 | static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) | 227 | static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect) |
| 229 | { | 228 | { |
| 230 | int id = effect->id; | ||
| 231 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 232 | |||
| 233 | if (effect->type != FF_CONSTANT) { | 229 | if (effect->type != FF_CONSTANT) { |
| 234 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | 230 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); |
| 235 | return FALSE; | 231 | return 0; |
| 236 | } | 232 | } |
| 237 | 233 | ||
| 238 | return (old->u.constant.level != effect->u.constant.level); | 234 | return old->u.constant.level != effect->u.constant.level; |
| 239 | } | 235 | } |
| 240 | 236 | ||
| 241 | /* | 237 | /* |
| 242 | * Analyse the changes in an effect, and tell if we need to send an envelope | 238 | * Analyse the changes in an effect, and tell if we need to send an envelope |
| 243 | * parameter packet | 239 | * parameter packet |
| 244 | */ | 240 | */ |
| 245 | static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect) | 241 | static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effect) |
| 246 | { | 242 | { |
| 247 | int id = effect->id; | ||
| 248 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 249 | |||
| 250 | switch (effect->type) { | 243 | switch (effect->type) { |
| 251 | case FF_CONSTANT: | 244 | case FF_CONSTANT: |
| 252 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length | 245 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length |
| 253 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level | 246 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level |
| 254 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length | 247 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length |
| 255 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) | 248 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) |
| 256 | return TRUE; | 249 | return 1; |
| 257 | break; | 250 | break; |
| 258 | 251 | ||
| 259 | case FF_PERIODIC: | 252 | case FF_PERIODIC: |
| @@ -261,30 +254,26 @@ static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effec | |||
| 261 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level | 254 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level |
| 262 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length | 255 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length |
| 263 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) | 256 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) |
| 264 | return TRUE; | 257 | return 1; |
| 265 | break; | 258 | break; |
| 266 | 259 | ||
| 267 | default: | 260 | default: |
| 268 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | 261 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); |
| 269 | } | 262 | } |
| 270 | 263 | ||
| 271 | return FALSE; | 264 | return 0; |
| 272 | } | 265 | } |
| 273 | 266 | ||
| 274 | /* | 267 | /* |
| 275 | * Analyse the changes in an effect, and tell if we need to send a periodic | 268 | * Analyse the changes in an effect, and tell if we need to send a periodic |
| 276 | * parameter effect | 269 | * parameter effect |
| 277 | */ | 270 | */ |
| 278 | static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | 271 | static int need_period_modifier(struct ff_effect *old, struct ff_effect *new) |
| 279 | { | 272 | { |
| 280 | int id = new->id; | ||
| 281 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 282 | |||
| 283 | if (new->type != FF_PERIODIC) { | 273 | if (new->type != FF_PERIODIC) { |
| 284 | printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); | 274 | printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n"); |
| 285 | return FALSE; | 275 | return 0; |
| 286 | } | 276 | } |
| 287 | |||
| 288 | return (old->u.periodic.period != new->u.periodic.period | 277 | return (old->u.periodic.period != new->u.periodic.period |
| 289 | || old->u.periodic.magnitude != new->u.periodic.magnitude | 278 | || old->u.periodic.magnitude != new->u.periodic.magnitude |
| 290 | || old->u.periodic.offset != new->u.periodic.offset | 279 | || old->u.periodic.offset != new->u.periodic.offset |
| @@ -295,19 +284,16 @@ static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | |||
| 295 | * Analyse the changes in an effect, and tell if we need to send an effect | 284 | * Analyse the changes in an effect, and tell if we need to send an effect |
| 296 | * packet | 285 | * packet |
| 297 | */ | 286 | */ |
| 298 | static int need_core(struct iforce* iforce, struct ff_effect* new) | 287 | static int need_core(struct ff_effect *old, struct ff_effect *new) |
| 299 | { | 288 | { |
| 300 | int id = new->id; | ||
| 301 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
| 302 | |||
| 303 | if (old->direction != new->direction | 289 | if (old->direction != new->direction |
| 304 | || old->trigger.button != new->trigger.button | 290 | || old->trigger.button != new->trigger.button |
| 305 | || old->trigger.interval != new->trigger.interval | 291 | || old->trigger.interval != new->trigger.interval |
| 306 | || old->replay.length != new->replay.length | 292 | || old->replay.length != new->replay.length |
| 307 | || old->replay.delay != new->replay.delay) | 293 | || old->replay.delay != new->replay.delay) |
| 308 | return TRUE; | 294 | return 1; |
| 309 | 295 | ||
| 310 | return FALSE; | 296 | return 0; |
| 311 | } | 297 | } |
| 312 | /* | 298 | /* |
| 313 | * Send the part common to all effects to the device | 299 | * Send the part common to all effects to the device |
| @@ -360,7 +346,7 @@ static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | |||
| 360 | * Upload a periodic effect to the device | 346 | * Upload a periodic effect to the device |
| 361 | * See also iforce_upload_constant. | 347 | * See also iforce_upload_constant. |
| 362 | */ | 348 | */ |
| 363 | int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) | 349 | int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
| 364 | { | 350 | { |
| 365 | u8 wave_code; | 351 | u8 wave_code; |
| 366 | int core_id = effect->id; | 352 | int core_id = effect->id; |
| @@ -371,23 +357,25 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int | |||
| 371 | int param2_err = 1; | 357 | int param2_err = 1; |
| 372 | int core_err = 0; | 358 | int core_err = 0; |
| 373 | 359 | ||
| 374 | if (!is_update || need_period_modifier(iforce, effect)) { | 360 | if (!old || need_period_modifier(old, effect)) { |
| 375 | param1_err = make_period_modifier(iforce, mod1_chunk, | 361 | param1_err = make_period_modifier(iforce, mod1_chunk, |
| 376 | is_update, | 362 | old != NULL, |
| 377 | effect->u.periodic.magnitude, effect->u.periodic.offset, | 363 | effect->u.periodic.magnitude, effect->u.periodic.offset, |
| 378 | effect->u.periodic.period, effect->u.periodic.phase); | 364 | effect->u.periodic.period, effect->u.periodic.phase); |
| 379 | if (param1_err) return param1_err; | 365 | if (param1_err) |
| 366 | return param1_err; | ||
| 380 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | 367 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
| 381 | } | 368 | } |
| 382 | 369 | ||
| 383 | if (!is_update || need_envelope_modifier(iforce, effect)) { | 370 | if (!old || need_envelope_modifier(old, effect)) { |
| 384 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | 371 | param2_err = make_envelope_modifier(iforce, mod2_chunk, |
| 385 | is_update, | 372 | old !=NULL, |
| 386 | effect->u.periodic.envelope.attack_length, | 373 | effect->u.periodic.envelope.attack_length, |
| 387 | effect->u.periodic.envelope.attack_level, | 374 | effect->u.periodic.envelope.attack_level, |
| 388 | effect->u.periodic.envelope.fade_length, | 375 | effect->u.periodic.envelope.fade_length, |
| 389 | effect->u.periodic.envelope.fade_level); | 376 | effect->u.periodic.envelope.fade_level); |
| 390 | if (param2_err) return param2_err; | 377 | if (param2_err) |
| 378 | return param2_err; | ||
| 391 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | 379 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
| 392 | } | 380 | } |
| 393 | 381 | ||
| @@ -400,7 +388,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int | |||
| 400 | default: wave_code = 0x20; break; | 388 | default: wave_code = 0x20; break; |
| 401 | } | 389 | } |
| 402 | 390 | ||
| 403 | if (!is_update || need_core(iforce, effect)) { | 391 | if (!old || need_core(old, effect)) { |
| 404 | core_err = make_core(iforce, effect->id, | 392 | core_err = make_core(iforce, effect->id, |
| 405 | mod1_chunk->start, | 393 | mod1_chunk->start, |
| 406 | mod2_chunk->start, | 394 | mod2_chunk->start, |
| @@ -429,7 +417,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int | |||
| 429 | * 0 Ok, effect created or updated | 417 | * 0 Ok, effect created or updated |
| 430 | * 1 effect did not change since last upload, and no packet was therefore sent | 418 | * 1 effect did not change since last upload, and no packet was therefore sent |
| 431 | */ | 419 | */ |
| 432 | int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) | 420 | int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
| 433 | { | 421 | { |
| 434 | int core_id = effect->id; | 422 | int core_id = effect->id; |
| 435 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | 423 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; |
| @@ -439,26 +427,28 @@ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int | |||
| 439 | int param2_err = 1; | 427 | int param2_err = 1; |
| 440 | int core_err = 0; | 428 | int core_err = 0; |
| 441 | 429 | ||
| 442 | if (!is_update || need_magnitude_modifier(iforce, effect)) { | 430 | if (!old || need_magnitude_modifier(old, effect)) { |
| 443 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, | 431 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, |
| 444 | is_update, | 432 | old != NULL, |
| 445 | effect->u.constant.level); | 433 | effect->u.constant.level); |
| 446 | if (param1_err) return param1_err; | 434 | if (param1_err) |
| 435 | return param1_err; | ||
| 447 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | 436 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
| 448 | } | 437 | } |
| 449 | 438 | ||
| 450 | if (!is_update || need_envelope_modifier(iforce, effect)) { | 439 | if (!old || need_envelope_modifier(old, effect)) { |
| 451 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | 440 | param2_err = make_envelope_modifier(iforce, mod2_chunk, |
| 452 | is_update, | 441 | old != NULL, |
| 453 | effect->u.constant.envelope.attack_length, | 442 | effect->u.constant.envelope.attack_length, |
| 454 | effect->u.constant.envelope.attack_level, | 443 | effect->u.constant.envelope.attack_level, |
| 455 | effect->u.constant.envelope.fade_length, | 444 | effect->u.constant.envelope.fade_length, |
| 456 | effect->u.constant.envelope.fade_level); | 445 | effect->u.constant.envelope.fade_level); |
| 457 | if (param2_err) return param2_err; | 446 | if (param2_err) |
| 447 | return param2_err; | ||
| 458 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | 448 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
| 459 | } | 449 | } |
| 460 | 450 | ||
| 461 | if (!is_update || need_core(iforce, effect)) { | 451 | if (!old || need_core(old, effect)) { |
| 462 | core_err = make_core(iforce, effect->id, | 452 | core_err = make_core(iforce, effect->id, |
| 463 | mod1_chunk->start, | 453 | mod1_chunk->start, |
| 464 | mod2_chunk->start, | 454 | mod2_chunk->start, |
| @@ -483,7 +473,7 @@ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int | |||
| 483 | /* | 473 | /* |
| 484 | * Upload an condition effect. Those are for example friction, inertia, springs... | 474 | * Upload an condition effect. Those are for example friction, inertia, springs... |
| 485 | */ | 475 | */ |
| 486 | int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update) | 476 | int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old) |
| 487 | { | 477 | { |
| 488 | int core_id = effect->id; | 478 | int core_id = effect->id; |
| 489 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | 479 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; |
| @@ -494,37 +484,39 @@ int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int | |||
| 494 | int core_err = 0; | 484 | int core_err = 0; |
| 495 | 485 | ||
| 496 | switch (effect->type) { | 486 | switch (effect->type) { |
| 497 | case FF_SPRING: type = 0x40; break; | 487 | case FF_SPRING: type = 0x40; break; |
| 498 | case FF_DAMPER: type = 0x41; break; | 488 | case FF_DAMPER: type = 0x41; break; |
| 499 | default: return -1; | 489 | default: return -1; |
| 500 | } | 490 | } |
| 501 | 491 | ||
| 502 | if (!is_update || need_condition_modifier(iforce, effect)) { | 492 | if (!old || need_condition_modifier(old, effect)) { |
| 503 | param_err = make_condition_modifier(iforce, mod1_chunk, | 493 | param_err = make_condition_modifier(iforce, mod1_chunk, |
| 504 | is_update, | 494 | old != NULL, |
| 505 | effect->u.condition[0].right_saturation, | 495 | effect->u.condition[0].right_saturation, |
| 506 | effect->u.condition[0].left_saturation, | 496 | effect->u.condition[0].left_saturation, |
| 507 | effect->u.condition[0].right_coeff, | 497 | effect->u.condition[0].right_coeff, |
| 508 | effect->u.condition[0].left_coeff, | 498 | effect->u.condition[0].left_coeff, |
| 509 | effect->u.condition[0].deadband, | 499 | effect->u.condition[0].deadband, |
| 510 | effect->u.condition[0].center); | 500 | effect->u.condition[0].center); |
| 511 | if (param_err) return param_err; | 501 | if (param_err) |
| 502 | return param_err; | ||
| 512 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | 503 | set_bit(FF_MOD1_IS_USED, core_effect->flags); |
| 513 | 504 | ||
| 514 | param_err = make_condition_modifier(iforce, mod2_chunk, | 505 | param_err = make_condition_modifier(iforce, mod2_chunk, |
| 515 | is_update, | 506 | old != NULL, |
| 516 | effect->u.condition[1].right_saturation, | 507 | effect->u.condition[1].right_saturation, |
| 517 | effect->u.condition[1].left_saturation, | 508 | effect->u.condition[1].left_saturation, |
| 518 | effect->u.condition[1].right_coeff, | 509 | effect->u.condition[1].right_coeff, |
| 519 | effect->u.condition[1].left_coeff, | 510 | effect->u.condition[1].left_coeff, |
| 520 | effect->u.condition[1].deadband, | 511 | effect->u.condition[1].deadband, |
| 521 | effect->u.condition[1].center); | 512 | effect->u.condition[1].center); |
| 522 | if (param_err) return param_err; | 513 | if (param_err) |
| 514 | return param_err; | ||
| 523 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | 515 | set_bit(FF_MOD2_IS_USED, core_effect->flags); |
| 524 | 516 | ||
| 525 | } | 517 | } |
| 526 | 518 | ||
| 527 | if (!is_update || need_core(iforce, effect)) { | 519 | if (!old || need_core(old, effect)) { |
| 528 | core_err = make_core(iforce, effect->id, | 520 | core_err = make_core(iforce, effect->id, |
| 529 | mod1_chunk->start, mod2_chunk->start, | 521 | mod1_chunk->start, mod2_chunk->start, |
| 530 | type, 0xc0, | 522 | type, 0xc0, |
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index b4914e7231f8..24c684bc6337 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c | |||
| @@ -83,103 +83,57 @@ static struct iforce_device iforce_device[] = { | |||
| 83 | { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } | 83 | { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | 86 | static int iforce_playback(struct input_dev *dev, int effect_id, int value) | |
| 87 | |||
| 88 | static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
| 89 | { | 87 | { |
| 90 | struct iforce* iforce = dev->private; | 88 | struct iforce* iforce = dev->private; |
| 91 | unsigned char data[3]; | 89 | struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; |
| 92 | |||
| 93 | if (type != EV_FF) | ||
| 94 | return -1; | ||
| 95 | |||
| 96 | switch (code) { | ||
| 97 | |||
| 98 | case FF_GAIN: | ||
| 99 | |||
| 100 | data[0] = value >> 9; | ||
| 101 | iforce_send_packet(iforce, FF_CMD_GAIN, data); | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | |||
| 105 | case FF_AUTOCENTER: | ||
| 106 | 90 | ||
| 107 | data[0] = 0x03; | 91 | if (value > 0) |
| 108 | data[1] = value >> 9; | 92 | set_bit(FF_CORE_SHOULD_PLAY, core_effect->flags); |
| 109 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | 93 | else |
| 94 | clear_bit(FF_CORE_SHOULD_PLAY, core_effect->flags); | ||
| 110 | 95 | ||
| 111 | data[0] = 0x04; | 96 | iforce_control_playback(iforce, effect_id, value); |
| 112 | data[1] = 0x01; | 97 | return 0; |
| 113 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | 98 | } |
| 114 | 99 | ||
| 115 | return 0; | 100 | static void iforce_set_gain(struct input_dev *dev, u16 gain) |
| 101 | { | ||
| 102 | struct iforce* iforce = dev->private; | ||
| 103 | unsigned char data[3]; | ||
| 116 | 104 | ||
| 117 | default: /* Play or stop an effect */ | 105 | data[0] = gain >> 9; |
| 106 | iforce_send_packet(iforce, FF_CMD_GAIN, data); | ||
| 107 | } | ||
| 118 | 108 | ||
| 119 | if (!CHECK_OWNERSHIP(code, iforce)) { | 109 | static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude) |
| 120 | return -1; | 110 | { |
| 121 | } | 111 | struct iforce* iforce = dev->private; |
| 122 | if (value > 0) { | 112 | unsigned char data[3]; |
| 123 | set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
| 124 | } | ||
| 125 | else { | ||
| 126 | clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
| 127 | } | ||
| 128 | 113 | ||
| 129 | iforce_control_playback(iforce, code, value); | 114 | data[0] = 0x03; |
| 130 | return 0; | 115 | data[1] = magnitude >> 9; |
| 131 | } | 116 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); |
| 132 | 117 | ||
| 133 | return -1; | 118 | data[0] = 0x04; |
| 119 | data[1] = 0x01; | ||
| 120 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | ||
| 134 | } | 121 | } |
| 135 | 122 | ||
| 136 | /* | 123 | /* |
| 137 | * Function called when an ioctl is performed on the event dev entry. | 124 | * Function called when an ioctl is performed on the event dev entry. |
| 138 | * It uploads an effect to the device | 125 | * It uploads an effect to the device |
| 139 | */ | 126 | */ |
| 140 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 127 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) |
| 141 | { | 128 | { |
| 142 | struct iforce* iforce = dev->private; | 129 | struct iforce* iforce = dev->private; |
| 143 | int id; | 130 | struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id]; |
| 144 | int ret; | 131 | int ret; |
| 145 | int is_update; | ||
| 146 | |||
| 147 | /* Check this effect type is supported by this device */ | ||
| 148 | if (!test_bit(effect->type, iforce->dev->ffbit)) | ||
| 149 | return -EINVAL; | ||
| 150 | |||
| 151 | /* | ||
| 152 | * If we want to create a new effect, get a free id | ||
| 153 | */ | ||
| 154 | if (effect->id == -1) { | ||
| 155 | |||
| 156 | for (id = 0; id < FF_EFFECTS_MAX; ++id) | ||
| 157 | if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) | ||
| 158 | break; | ||
| 159 | |||
| 160 | if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max) | ||
| 161 | return -ENOMEM; | ||
| 162 | |||
| 163 | effect->id = id; | ||
| 164 | iforce->core_effects[id].owner = current->pid; | ||
| 165 | iforce->core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */ | ||
| 166 | |||
| 167 | is_update = FALSE; | ||
| 168 | } | ||
| 169 | else { | ||
| 170 | /* We want to update an effect */ | ||
| 171 | if (!CHECK_OWNERSHIP(effect->id, iforce)) | ||
| 172 | return -EACCES; | ||
| 173 | |||
| 174 | /* Parameter type cannot be updated */ | ||
| 175 | if (effect->type != iforce->core_effects[effect->id].effect.type) | ||
| 176 | return -EINVAL; | ||
| 177 | 132 | ||
| 133 | if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) { | ||
| 178 | /* Check the effect is not already being updated */ | 134 | /* Check the effect is not already being updated */ |
| 179 | if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) | 135 | if (test_bit(FF_CORE_UPDATE, core_effect->flags)) |
| 180 | return -EAGAIN; | 136 | return -EAGAIN; |
| 181 | |||
| 182 | is_update = TRUE; | ||
| 183 | } | 137 | } |
| 184 | 138 | ||
| 185 | /* | 139 | /* |
| @@ -188,28 +142,28 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |||
| 188 | switch (effect->type) { | 142 | switch (effect->type) { |
| 189 | 143 | ||
| 190 | case FF_PERIODIC: | 144 | case FF_PERIODIC: |
| 191 | ret = iforce_upload_periodic(iforce, effect, is_update); | 145 | ret = iforce_upload_periodic(iforce, effect, old); |
| 192 | break; | 146 | break; |
| 193 | 147 | ||
| 194 | case FF_CONSTANT: | 148 | case FF_CONSTANT: |
| 195 | ret = iforce_upload_constant(iforce, effect, is_update); | 149 | ret = iforce_upload_constant(iforce, effect, old); |
| 196 | break; | 150 | break; |
| 197 | 151 | ||
| 198 | case FF_SPRING: | 152 | case FF_SPRING: |
| 199 | case FF_DAMPER: | 153 | case FF_DAMPER: |
| 200 | ret = iforce_upload_condition(iforce, effect, is_update); | 154 | ret = iforce_upload_condition(iforce, effect, old); |
| 201 | break; | 155 | break; |
| 202 | 156 | ||
| 203 | default: | 157 | default: |
| 204 | return -EINVAL; | 158 | return -EINVAL; |
| 205 | } | 159 | } |
| 160 | |||
| 206 | if (ret == 0) { | 161 | if (ret == 0) { |
| 207 | /* A packet was sent, forbid new updates until we are notified | 162 | /* A packet was sent, forbid new updates until we are notified |
| 208 | * that the packet was updated | 163 | * that the packet was updated |
| 209 | */ | 164 | */ |
| 210 | set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); | 165 | set_bit(FF_CORE_UPDATE, core_effect->flags); |
| 211 | } | 166 | } |
| 212 | iforce->core_effects[effect->id].effect = *effect; | ||
| 213 | return ret; | 167 | return ret; |
| 214 | } | 168 | } |
| 215 | 169 | ||
| @@ -219,20 +173,9 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |||
| 219 | */ | 173 | */ |
| 220 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) | 174 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) |
| 221 | { | 175 | { |
| 222 | struct iforce* iforce = dev->private; | 176 | struct iforce *iforce = dev->private; |
| 177 | struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id]; | ||
| 223 | int err = 0; | 178 | int err = 0; |
| 224 | struct iforce_core_effect* core_effect; | ||
| 225 | |||
| 226 | if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) | ||
| 227 | return -EINVAL; | ||
| 228 | |||
| 229 | core_effect = &iforce->core_effects[effect_id]; | ||
| 230 | |||
| 231 | /* Check who is trying to erase this effect */ | ||
| 232 | if (core_effect->owner != current->pid) { | ||
| 233 | printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner); | ||
| 234 | return -EACCES; | ||
| 235 | } | ||
| 236 | 179 | ||
| 237 | if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) | 180 | if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) |
| 238 | err = release_resource(&core_effect->mod1_chunk); | 181 | err = release_resource(&core_effect->mod1_chunk); |
| @@ -240,7 +183,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id) | |||
| 240 | if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) | 183 | if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) |
| 241 | err = release_resource(&core_effect->mod2_chunk); | 184 | err = release_resource(&core_effect->mod2_chunk); |
| 242 | 185 | ||
| 243 | /*TODO: remember to change that if more FF_MOD* bits are added */ | 186 | /* TODO: remember to change that if more FF_MOD* bits are added */ |
| 244 | core_effect->flags[0] = 0; | 187 | core_effect->flags[0] = 0; |
| 245 | 188 | ||
| 246 | return err; | 189 | return err; |
| @@ -260,52 +203,31 @@ static int iforce_open(struct input_dev *dev) | |||
| 260 | #endif | 203 | #endif |
| 261 | } | 204 | } |
| 262 | 205 | ||
| 263 | /* Enable force feedback */ | 206 | if (test_bit(EV_FF, dev->evbit)) { |
| 264 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | 207 | /* Enable force feedback */ |
| 208 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | ||
| 209 | } | ||
| 265 | 210 | ||
| 266 | return 0; | 211 | return 0; |
| 267 | } | 212 | } |
| 268 | 213 | ||
| 269 | static int iforce_flush(struct input_dev *dev, struct file *file) | 214 | static void iforce_release(struct input_dev *dev) |
| 270 | { | 215 | { |
| 271 | struct iforce *iforce = dev->private; | 216 | struct iforce *iforce = dev->private; |
| 272 | int i; | 217 | int i; |
| 273 | 218 | ||
| 274 | /* Erase all effects this process owns */ | 219 | if (test_bit(EV_FF, dev->evbit)) { |
| 275 | for (i=0; i<dev->ff_effects_max; ++i) { | 220 | /* Check: no effects should be present in memory */ |
| 276 | 221 | for (i = 0; i < dev->ff->max_effects; i++) { | |
| 277 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | 222 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) { |
| 278 | current->pid == iforce->core_effects[i].owner) { | 223 | printk(KERN_WARNING "iforce_release: Device still owns effects\n"); |
| 279 | 224 | break; | |
| 280 | /* Stop effect */ | ||
| 281 | input_report_ff(dev, i, 0); | ||
| 282 | |||
| 283 | /* Free ressources assigned to effect */ | ||
| 284 | if (iforce_erase_effect(dev, i)) { | ||
| 285 | printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i); | ||
| 286 | } | 225 | } |
| 287 | } | 226 | } |
| 288 | 227 | ||
| 228 | /* Disable force feedback playback */ | ||
| 229 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | ||
| 289 | } | 230 | } |
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void iforce_release(struct input_dev *dev) | ||
| 294 | { | ||
| 295 | struct iforce *iforce = dev->private; | ||
| 296 | int i; | ||
| 297 | |||
| 298 | /* Check: no effect should be present in memory */ | ||
| 299 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
| 300 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | if (i<dev->ff_effects_max) { | ||
| 304 | printk(KERN_WARNING "iforce_release: Device still owns effects\n"); | ||
| 305 | } | ||
| 306 | |||
| 307 | /* Disable force feedback playback */ | ||
| 308 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | ||
| 309 | 231 | ||
| 310 | switch (iforce->bus) { | 232 | switch (iforce->bus) { |
| 311 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | 233 | #ifdef CONFIG_JOYSTICK_IFORCE_USB |
| @@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce *iforce) | |||
| 342 | int iforce_init_device(struct iforce *iforce) | 264 | int iforce_init_device(struct iforce *iforce) |
| 343 | { | 265 | { |
| 344 | struct input_dev *input_dev; | 266 | struct input_dev *input_dev; |
| 267 | struct ff_device *ff; | ||
| 345 | unsigned char c[] = "CEOV"; | 268 | unsigned char c[] = "CEOV"; |
| 346 | int i; | 269 | int i, error; |
| 270 | int ff_effects = 0; | ||
| 347 | 271 | ||
| 348 | input_dev = input_allocate_device(); | 272 | input_dev = input_allocate_device(); |
| 349 | if (!input_dev) | 273 | if (!input_dev) |
| @@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *iforce) | |||
| 378 | input_dev->name = "Unknown I-Force device"; | 302 | input_dev->name = "Unknown I-Force device"; |
| 379 | input_dev->open = iforce_open; | 303 | input_dev->open = iforce_open; |
| 380 | input_dev->close = iforce_release; | 304 | input_dev->close = iforce_release; |
| 381 | input_dev->flush = iforce_flush; | ||
| 382 | input_dev->event = iforce_input_event; | ||
| 383 | input_dev->upload_effect = iforce_upload_effect; | ||
| 384 | input_dev->erase_effect = iforce_erase_effect; | ||
| 385 | input_dev->ff_effects_max = 10; | ||
| 386 | 305 | ||
| 387 | /* | 306 | /* |
| 388 | * On-device memory allocation. | 307 | * On-device memory allocation. |
| @@ -430,15 +349,15 @@ int iforce_init_device(struct iforce *iforce) | |||
| 430 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); | 349 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); |
| 431 | 350 | ||
| 432 | if (!iforce_get_id_packet(iforce, "N")) | 351 | if (!iforce_get_id_packet(iforce, "N")) |
| 433 | iforce->dev->ff_effects_max = iforce->edata[1]; | 352 | ff_effects = iforce->edata[1]; |
| 434 | else | 353 | else |
| 435 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); | 354 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); |
| 436 | 355 | ||
| 437 | /* Check if the device can store more effects than the driver can really handle */ | 356 | /* Check if the device can store more effects than the driver can really handle */ |
| 438 | if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) { | 357 | if (ff_effects > IFORCE_EFFECTS_MAX) { |
| 439 | printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", | 358 | printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n", |
| 440 | iforce->dev->ff_effects_max, FF_EFFECTS_MAX); | 359 | IFORCE_EFFECTS_MAX, ff_effects); |
| 441 | iforce->dev->ff_effects_max = FF_EFFECTS_MAX; | 360 | ff_effects = IFORCE_EFFECTS_MAX; |
| 442 | } | 361 | } |
| 443 | 362 | ||
| 444 | /* | 363 | /* |
| @@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *iforce) | |||
| 472 | * Set input device bitfields and ranges. | 391 | * Set input device bitfields and ranges. |
| 473 | */ | 392 | */ |
| 474 | 393 | ||
| 475 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); | 394 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF_STATUS); |
| 476 | 395 | ||
| 477 | for (i = 0; iforce->type->btn[i] >= 0; i++) { | 396 | for (i = 0; iforce->type->btn[i] >= 0; i++) |
| 478 | signed short t = iforce->type->btn[i]; | 397 | set_bit(iforce->type->btn[i], input_dev->keybit); |
| 479 | set_bit(t, input_dev->keybit); | ||
| 480 | } | ||
| 481 | set_bit(BTN_DEAD, input_dev->keybit); | 398 | set_bit(BTN_DEAD, input_dev->keybit); |
| 482 | 399 | ||
| 483 | for (i = 0; iforce->type->abs[i] >= 0; i++) { | 400 | for (i = 0; iforce->type->abs[i] >= 0; i++) { |
| @@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *iforce) | |||
| 516 | } | 433 | } |
| 517 | } | 434 | } |
| 518 | 435 | ||
| 519 | for (i = 0; iforce->type->ff[i] >= 0; i++) | 436 | if (ff_effects) { |
| 520 | set_bit(iforce->type->ff[i], input_dev->ffbit); | ||
| 521 | 437 | ||
| 438 | for (i = 0; iforce->type->ff[i] >= 0; i++) | ||
| 439 | set_bit(iforce->type->ff[i], input_dev->ffbit); | ||
| 440 | |||
| 441 | error = input_ff_create(input_dev, ff_effects); | ||
| 442 | if (error) { | ||
| 443 | input_free_device(input_dev); | ||
| 444 | return error; | ||
| 445 | } | ||
| 446 | |||
| 447 | ff = input_dev->ff; | ||
| 448 | ff->upload = iforce_upload_effect; | ||
| 449 | ff->erase = iforce_erase_effect; | ||
| 450 | ff->set_gain = iforce_set_gain; | ||
| 451 | ff->set_autocenter = iforce_set_autocenter; | ||
| 452 | ff->playback = iforce_playback; | ||
| 453 | } | ||
| 522 | /* | 454 | /* |
| 523 | * Register input device. | 455 | * Register input device. |
| 524 | */ | 456 | */ |
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 76cb1f88f4e8..8632d47a7fbe 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c | |||
| @@ -140,7 +140,10 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) | |||
| 140 | { | 140 | { |
| 141 | int i; | 141 | int i; |
| 142 | 142 | ||
| 143 | for (i = 0; i < iforce->dev->ff_effects_max; ++i) { | 143 | if (!iforce->dev->ff) |
| 144 | return 0; | ||
| 145 | |||
| 146 | for (i = 0; i < iforce->dev->ff->max_effects; ++i) { | ||
| 144 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | 147 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && |
| 145 | (iforce->core_effects[i].mod1_chunk.start == addr || | 148 | (iforce->core_effects[i].mod1_chunk.start == addr || |
| 146 | iforce->core_effects[i].mod2_chunk.start == addr)) { | 149 | iforce->core_effects[i].mod2_chunk.start == addr)) { |
| @@ -229,19 +232,17 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, | |||
| 229 | i = data[1] & 0x7f; | 232 | i = data[1] & 0x7f; |
| 230 | if (data[1] & 0x80) { | 233 | if (data[1] & 0x80) { |
| 231 | if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | 234 | if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { |
| 232 | /* Report play event */ | 235 | /* Report play event */ |
| 233 | input_report_ff_status(dev, i, FF_STATUS_PLAYING); | 236 | input_report_ff_status(dev, i, FF_STATUS_PLAYING); |
| 234 | } | 237 | } |
| 235 | } | 238 | } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { |
| 236 | else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | ||
| 237 | /* Report stop event */ | 239 | /* Report stop event */ |
| 238 | input_report_ff_status(dev, i, FF_STATUS_STOPPED); | 240 | input_report_ff_status(dev, i, FF_STATUS_STOPPED); |
| 239 | } | 241 | } |
| 240 | if (LO(cmd) > 3) { | 242 | if (LO(cmd) > 3) { |
| 241 | int j; | 243 | int j; |
| 242 | for (j=3; j<LO(cmd); j+=2) { | 244 | for (j = 3; j < LO(cmd); j += 2) |
| 243 | mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); | 245 | mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); |
| 244 | } | ||
| 245 | } | 246 | } |
| 246 | break; | 247 | break; |
| 247 | } | 248 | } |
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index e9924d6f01b3..947df2739843 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h | |||
| @@ -51,10 +51,7 @@ | |||
| 51 | #define IFORCE_232 1 | 51 | #define IFORCE_232 1 |
| 52 | #define IFORCE_USB 2 | 52 | #define IFORCE_USB 2 |
| 53 | 53 | ||
| 54 | #define FALSE 0 | 54 | #define IFORCE_EFFECTS_MAX 32 |
| 55 | #define TRUE 1 | ||
| 56 | |||
| 57 | #define FF_EFFECTS_MAX 32 | ||
| 58 | 55 | ||
| 59 | /* Each force feedback effect is made of one core effect, which can be | 56 | /* Each force feedback effect is made of one core effect, which can be |
| 60 | * associated to at most to effect modifiers | 57 | * associated to at most to effect modifiers |
| @@ -67,24 +64,11 @@ | |||
| 67 | #define FF_CORE_UPDATE 5 /* Effect is being updated */ | 64 | #define FF_CORE_UPDATE 5 /* Effect is being updated */ |
| 68 | #define FF_MODCORE_MAX 5 | 65 | #define FF_MODCORE_MAX 5 |
| 69 | 66 | ||
| 70 | #define CHECK_OWNERSHIP(i, iforce) \ | ||
| 71 | ((i) < FF_EFFECTS_MAX && i >= 0 && \ | ||
| 72 | test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ | ||
| 73 | (current->pid == 0 || \ | ||
| 74 | (iforce)->core_effects[(i)].owner == current->pid)) | ||
| 75 | |||
| 76 | struct iforce_core_effect { | 67 | struct iforce_core_effect { |
| 77 | /* Information about where modifiers are stored in the device's memory */ | 68 | /* Information about where modifiers are stored in the device's memory */ |
| 78 | struct resource mod1_chunk; | 69 | struct resource mod1_chunk; |
| 79 | struct resource mod2_chunk; | 70 | struct resource mod2_chunk; |
| 80 | unsigned long flags[NBITS(FF_MODCORE_MAX)]; | 71 | unsigned long flags[NBITS(FF_MODCORE_MAX)]; |
| 81 | pid_t owner; | ||
| 82 | /* Used to keep track of parameters of an effect. They are needed | ||
| 83 | * to know what parts of an effect changed in an update operation. | ||
| 84 | * We try to send only parameter packets if possible, as sending | ||
| 85 | * effect parameter requires the effect to be stoped and restarted | ||
| 86 | */ | ||
| 87 | struct ff_effect effect; | ||
| 88 | }; | 72 | }; |
| 89 | 73 | ||
| 90 | #define FF_CMD_EFFECT 0x010e | 74 | #define FF_CMD_EFFECT 0x010e |
| @@ -145,7 +129,7 @@ struct iforce { | |||
| 145 | /* Force Feedback */ | 129 | /* Force Feedback */ |
| 146 | wait_queue_head_t wait; | 130 | wait_queue_head_t wait; |
| 147 | struct resource device_memory; | 131 | struct resource device_memory; |
| 148 | struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; | 132 | struct iforce_core_effect core_effects[IFORCE_EFFECTS_MAX]; |
| 149 | struct mutex mem_mutex; | 133 | struct mutex mem_mutex; |
| 150 | }; | 134 | }; |
| 151 | 135 | ||
| @@ -182,9 +166,9 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; | |||
| 182 | int iforce_get_id_packet(struct iforce *iforce, char *packet); | 166 | int iforce_get_id_packet(struct iforce *iforce, char *packet); |
| 183 | 167 | ||
| 184 | /* iforce-ff.c */ | 168 | /* iforce-ff.c */ |
| 185 | int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); | 169 | int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *); |
| 186 | int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); | 170 | int iforce_upload_constant(struct iforce *, struct ff_effect *, struct ff_effect *); |
| 187 | int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); | 171 | int iforce_upload_condition(struct iforce *, struct ff_effect *, struct ff_effect *); |
| 188 | 172 | ||
| 189 | /* Public variables */ | 173 | /* Public variables */ |
| 190 | extern struct serio_driver iforce_serio_drv; | 174 | extern struct serio_driver iforce_serio_drv; |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 83eac3a66bc8..c62e00c79dec 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -121,6 +121,17 @@ config KEYBOARD_NEWTON | |||
| 121 | To compile this driver as a module, choose M here: the | 121 | To compile this driver as a module, choose M here: the |
| 122 | module will be called newtonkbd. | 122 | module will be called newtonkbd. |
| 123 | 123 | ||
| 124 | config KEYBOARD_STOWAWAY | ||
| 125 | tristate "Stowaway keyboard" | ||
| 126 | select SERIO | ||
| 127 | help | ||
| 128 | Say Y here if you have a Stowaway keyboard on a serial port. | ||
| 129 | Stowaway compatible keyboards like Dicota Input-PDA keyboard | ||
| 130 | are also supported by this driver. | ||
| 131 | |||
| 132 | To compile this driver as a module, choose M here: the | ||
| 133 | module will be called stowaway. | ||
| 134 | |||
| 124 | config KEYBOARD_CORGI | 135 | config KEYBOARD_CORGI |
| 125 | tristate "Corgi keyboard" | 136 | tristate "Corgi keyboard" |
| 126 | depends on PXA_SHARPSL | 137 | depends on PXA_SHARPSL |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b265391f1f10..4c79e7bc9d06 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | |||
| 11 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | 11 | obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o |
| 12 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o | 12 | obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o |
| 13 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | 13 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o |
| 14 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | ||
| 14 | obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o | 15 | obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o |
| 15 | obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o | 16 | obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o |
| 16 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o | 17 | obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o |
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index a86afd0a5ef1..40244d4ce0f1 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c | |||
| @@ -652,9 +652,7 @@ static int atkbd_probe(struct atkbd *atkbd) | |||
| 652 | return 0; | 652 | return 0; |
| 653 | } | 653 | } |
| 654 | 654 | ||
| 655 | if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ | 655 | if (!ps2_is_keyboard_id(param[0])) |
| 656 | param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */ | ||
| 657 | param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */ | ||
| 658 | return -1; | 656 | return -1; |
| 659 | 657 | ||
| 660 | atkbd->id = (param[0] << 8) | param[1]; | 658 | atkbd->id = (param[0] << 8) | param[1]; |
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c new file mode 100644 index 000000000000..04c54c57f25c --- /dev/null +++ b/drivers/input/keyboard/stowaway.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Stowaway keyboard driver for Linux | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Copyright (c) 2006 Marek Vasut | ||
| 7 | * | ||
| 8 | * Based on Newton keyboard driver for Linux | ||
| 9 | * by Justin Cormack | ||
| 10 | */ | ||
| 11 | |||
| 12 | /* | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation; either version 2 of the License, or | ||
| 16 | * (at your option) any later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | * You should have received a copy of the GNU General Public License | ||
| 24 | * along with this program; if not, write to the Free Software | ||
| 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 26 | * | ||
| 27 | * Should you need to contact me, the author, you can do so either by | ||
| 28 | * e-mail - mail your message to <marek.vasut@gmail.com>, or by paper mail: | ||
| 29 | * Marek Vasut, Liskovecka 559, Frydek-Mistek, 738 01 Czech Republic | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | #include <linux/input.h> | ||
| 35 | #include <linux/init.h> | ||
| 36 | #include <linux/serio.h> | ||
| 37 | |||
| 38 | #define DRIVER_DESC "Stowaway keyboard driver" | ||
| 39 | |||
| 40 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
| 41 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 42 | MODULE_LICENSE("GPL"); | ||
| 43 | |||
| 44 | #define SKBD_KEY_MASK 0x7f | ||
| 45 | #define SKBD_RELEASE 0x80 | ||
| 46 | |||
| 47 | static unsigned char skbd_keycode[128] = { | ||
| 48 | KEY_1, KEY_2, KEY_3, KEY_Z, KEY_4, KEY_5, KEY_6, KEY_7, | ||
| 49 | 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_GRAVE, | ||
| 50 | KEY_X, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_SPACE, | ||
| 51 | KEY_CAPSLOCK, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, | ||
| 52 | 0, 0, 0, KEY_LEFTALT, 0, 0, 0, 0, | ||
| 53 | 0, 0, 0, 0, KEY_C, KEY_V, KEY_B, KEY_N, | ||
| 54 | KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_HOME, KEY_8, KEY_9, KEY_0, KEY_ESC, | ||
| 55 | KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_END, KEY_U, KEY_I, KEY_O, KEY_P, | ||
| 56 | KEY_APOSTROPHE, KEY_ENTER, KEY_PAGEUP,0, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, | ||
| 57 | KEY_SLASH, KEY_UP, KEY_PAGEDOWN, 0,KEY_M, KEY_COMMA, KEY_DOT, KEY_INSERT, | ||
| 58 | KEY_DELETE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, | ||
| 59 | KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, | ||
| 60 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 61 | 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 62 | 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, | ||
| 63 | KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0 | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct skbd { | ||
| 67 | unsigned char keycode[128]; | ||
| 68 | struct input_dev *dev; | ||
| 69 | struct serio *serio; | ||
| 70 | char phys[32]; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data, | ||
| 74 | unsigned int flags, struct pt_regs *regs) | ||
| 75 | { | ||
| 76 | struct skbd *skbd = serio_get_drvdata(serio); | ||
| 77 | struct input_dev *dev = skbd->dev; | ||
| 78 | |||
| 79 | if (skbd->keycode[data & SKBD_KEY_MASK]) { | ||
| 80 | input_regs(dev, regs); | ||
| 81 | input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK], | ||
| 82 | !(data & SKBD_RELEASE)); | ||
| 83 | input_sync(dev); | ||
| 84 | } | ||
| 85 | |||
| 86 | return IRQ_HANDLED; | ||
| 87 | } | ||
| 88 | |||
| 89 | static int skbd_connect(struct serio *serio, struct serio_driver *drv) | ||
| 90 | { | ||
| 91 | struct skbd *skbd; | ||
| 92 | struct input_dev *input_dev; | ||
| 93 | int err = -ENOMEM; | ||
| 94 | int i; | ||
| 95 | |||
| 96 | skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL); | ||
| 97 | input_dev = input_allocate_device(); | ||
| 98 | if (!skbd || !input_dev) | ||
| 99 | goto fail1; | ||
| 100 | |||
| 101 | skbd->serio = serio; | ||
| 102 | skbd->dev = input_dev; | ||
| 103 | snprintf(skbd->phys, sizeof(skbd->phys), "%s/input0", serio->phys); | ||
| 104 | memcpy(skbd->keycode, skbd_keycode, sizeof(skbd->keycode)); | ||
| 105 | |||
| 106 | input_dev->name = "Stowaway Keyboard"; | ||
| 107 | input_dev->phys = skbd->phys; | ||
| 108 | input_dev->id.bustype = BUS_RS232; | ||
| 109 | input_dev->id.vendor = SERIO_STOWAWAY; | ||
| 110 | input_dev->id.product = 0x0001; | ||
| 111 | input_dev->id.version = 0x0100; | ||
| 112 | input_dev->cdev.dev = &serio->dev; | ||
| 113 | input_dev->private = skbd; | ||
| 114 | |||
| 115 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
| 116 | input_dev->keycode = skbd->keycode; | ||
| 117 | input_dev->keycodesize = sizeof(unsigned char); | ||
| 118 | input_dev->keycodemax = ARRAY_SIZE(skbd_keycode); | ||
| 119 | for (i = 0; i < ARRAY_SIZE(skbd_keycode); i++) | ||
| 120 | set_bit(skbd_keycode[i], input_dev->keybit); | ||
| 121 | clear_bit(0, input_dev->keybit); | ||
| 122 | |||
| 123 | serio_set_drvdata(serio, skbd); | ||
| 124 | |||
| 125 | err = serio_open(serio, drv); | ||
| 126 | if (err) | ||
| 127 | goto fail2; | ||
| 128 | |||
| 129 | err = input_register_device(skbd->dev); | ||
| 130 | if (err) | ||
| 131 | goto fail3; | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | |||
| 135 | fail3: serio_close(serio); | ||
| 136 | fail2: serio_set_drvdata(serio, NULL); | ||
| 137 | fail1: input_free_device(input_dev); | ||
| 138 | kfree(skbd); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void skbd_disconnect(struct serio *serio) | ||
| 143 | { | ||
| 144 | struct skbd *skbd = serio_get_drvdata(serio); | ||
| 145 | |||
| 146 | serio_close(serio); | ||
| 147 | serio_set_drvdata(serio, NULL); | ||
| 148 | input_unregister_device(skbd->dev); | ||
| 149 | kfree(skbd); | ||
| 150 | } | ||
| 151 | |||
| 152 | static struct serio_device_id skbd_serio_ids[] = { | ||
| 153 | { | ||
| 154 | .type = SERIO_RS232, | ||
| 155 | .proto = SERIO_STOWAWAY, | ||
| 156 | .id = SERIO_ANY, | ||
| 157 | .extra = SERIO_ANY, | ||
| 158 | }, | ||
| 159 | { 0 } | ||
| 160 | }; | ||
| 161 | |||
| 162 | MODULE_DEVICE_TABLE(serio, skbd_serio_ids); | ||
| 163 | |||
| 164 | static struct serio_driver skbd_drv = { | ||
| 165 | .driver = { | ||
| 166 | .name = "stowaway", | ||
| 167 | }, | ||
| 168 | .description = DRIVER_DESC, | ||
| 169 | .id_table = skbd_serio_ids, | ||
| 170 | .interrupt = skbd_interrupt, | ||
| 171 | .connect = skbd_connect, | ||
| 172 | .disconnect = skbd_disconnect, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static int __init skbd_init(void) | ||
| 176 | { | ||
| 177 | serio_register_driver(&skbd_drv); | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static void __exit skbd_exit(void) | ||
| 182 | { | ||
| 183 | serio_unregister_driver(&skbd_drv); | ||
| 184 | } | ||
| 185 | |||
| 186 | module_init(skbd_init); | ||
| 187 | module_exit(skbd_exit); | ||
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index d723e9ad7c41..9516439b7c78 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
| @@ -20,6 +20,9 @@ | |||
| 20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> | 20 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> |
| 21 | * | 21 | * |
| 22 | * Changes/Revisions: | 22 | * Changes/Revisions: |
| 23 | * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>) | ||
| 24 | * - updated ff support for the changes in kernel interface | ||
| 25 | * - added MODULE_VERSION | ||
| 23 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) | 26 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) |
| 24 | * - added force feedback support | 27 | * - added force feedback support |
| 25 | * - added UI_SET_PHYS | 28 | * - added UI_SET_PHYS |
| @@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r | |||
| 107 | return request->retval; | 110 | return request->retval; |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) | 113 | static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) |
| 114 | { | ||
| 115 | uinput_dev_event(dev, EV_FF, FF_GAIN, gain); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) | ||
| 119 | { | ||
| 120 | uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); | ||
| 121 | } | ||
| 122 | |||
| 123 | static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) | ||
| 124 | { | ||
| 125 | return uinput_dev_event(dev, EV_FF, effect_id, value); | ||
| 126 | } | ||
| 127 | |||
| 128 | static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) | ||
| 111 | { | 129 | { |
| 112 | struct uinput_request request; | 130 | struct uinput_request request; |
| 113 | int retval; | 131 | int retval; |
| 114 | 132 | ||
| 115 | if (!test_bit(EV_FF, dev->evbit)) | ||
| 116 | return -ENOSYS; | ||
| 117 | |||
| 118 | request.id = -1; | 133 | request.id = -1; |
| 119 | init_completion(&request.done); | 134 | init_completion(&request.done); |
| 120 | request.code = UI_FF_UPLOAD; | 135 | request.code = UI_FF_UPLOAD; |
| 121 | request.u.effect = effect; | 136 | request.u.upload.effect = effect; |
| 137 | request.u.upload.old = old; | ||
| 122 | 138 | ||
| 123 | retval = uinput_request_reserve_slot(dev->private, &request); | 139 | retval = uinput_request_reserve_slot(dev->private, &request); |
| 124 | if (!retval) | 140 | if (!retval) |
| @@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev) | |||
| 168 | 184 | ||
| 169 | static int uinput_create_device(struct uinput_device *udev) | 185 | static int uinput_create_device(struct uinput_device *udev) |
| 170 | { | 186 | { |
| 187 | struct input_dev *dev = udev->dev; | ||
| 171 | int error; | 188 | int error; |
| 172 | 189 | ||
| 173 | if (udev->state != UIST_SETUP_COMPLETE) { | 190 | if (udev->state != UIST_SETUP_COMPLETE) { |
| @@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev) | |||
| 175 | return -EINVAL; | 192 | return -EINVAL; |
| 176 | } | 193 | } |
| 177 | 194 | ||
| 178 | error = input_register_device(udev->dev); | 195 | if (udev->ff_effects_max) { |
| 179 | if (error) { | 196 | error = input_ff_create(dev, udev->ff_effects_max); |
| 180 | uinput_destroy_device(udev); | 197 | if (error) |
| 181 | return error; | 198 | goto fail1; |
| 199 | |||
| 200 | dev->ff->upload = uinput_dev_upload_effect; | ||
| 201 | dev->ff->erase = uinput_dev_erase_effect; | ||
| 202 | dev->ff->playback = uinput_dev_playback; | ||
| 203 | dev->ff->set_gain = uinput_dev_set_gain; | ||
| 204 | dev->ff->set_autocenter = uinput_dev_set_autocenter; | ||
| 182 | } | 205 | } |
| 183 | 206 | ||
| 207 | error = input_register_device(udev->dev); | ||
| 208 | if (error) | ||
| 209 | goto fail2; | ||
| 210 | |||
| 184 | udev->state = UIST_CREATED; | 211 | udev->state = UIST_CREATED; |
| 185 | 212 | ||
| 186 | return 0; | 213 | return 0; |
| 214 | |||
| 215 | fail2: input_ff_destroy(dev); | ||
| 216 | fail1: uinput_destroy_device(udev); | ||
| 217 | return error; | ||
| 187 | } | 218 | } |
| 188 | 219 | ||
| 189 | static int uinput_open(struct inode *inode, struct file *file) | 220 | static int uinput_open(struct inode *inode, struct file *file) |
| @@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev) | |||
| 243 | return -ENOMEM; | 274 | return -ENOMEM; |
| 244 | 275 | ||
| 245 | udev->dev->event = uinput_dev_event; | 276 | udev->dev->event = uinput_dev_event; |
| 246 | udev->dev->upload_effect = uinput_dev_upload_effect; | ||
| 247 | udev->dev->erase_effect = uinput_dev_erase_effect; | ||
| 248 | udev->dev->private = udev; | 277 | udev->dev->private = udev; |
| 249 | 278 | ||
| 250 | return 0; | 279 | return 0; |
| @@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu | |||
| 278 | goto exit; | 307 | goto exit; |
| 279 | } | 308 | } |
| 280 | 309 | ||
| 310 | udev->ff_effects_max = user_dev->ff_effects_max; | ||
| 311 | |||
| 281 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; | 312 | size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; |
| 282 | if (!size) { | 313 | if (!size) { |
| 283 | retval = -EINVAL; | 314 | retval = -EINVAL; |
| @@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu | |||
| 296 | dev->id.vendor = user_dev->id.vendor; | 327 | dev->id.vendor = user_dev->id.vendor; |
| 297 | dev->id.product = user_dev->id.product; | 328 | dev->id.product = user_dev->id.product; |
| 298 | dev->id.version = user_dev->id.version; | 329 | dev->id.version = user_dev->id.version; |
| 299 | dev->ff_effects_max = user_dev->ff_effects_max; | ||
| 300 | 330 | ||
| 301 | size = sizeof(int) * (ABS_MAX + 1); | 331 | size = sizeof(int) * (ABS_MAX + 1); |
| 302 | memcpy(dev->absmax, user_dev->absmax, size); | 332 | memcpy(dev->absmax, user_dev->absmax, size); |
| @@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 525 | break; | 555 | break; |
| 526 | } | 556 | } |
| 527 | req = uinput_request_find(udev, ff_up.request_id); | 557 | req = uinput_request_find(udev, ff_up.request_id); |
| 528 | if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { | 558 | if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { |
| 529 | retval = -EINVAL; | 559 | retval = -EINVAL; |
| 530 | break; | 560 | break; |
| 531 | } | 561 | } |
| 532 | ff_up.retval = 0; | 562 | ff_up.retval = 0; |
| 533 | memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect)); | 563 | memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); |
| 564 | if (req->u.upload.old) | ||
| 565 | memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); | ||
| 566 | else | ||
| 567 | memset(&ff_up.old, 0, sizeof(struct ff_effect)); | ||
| 568 | |||
| 534 | if (copy_to_user(p, &ff_up, sizeof(ff_up))) { | 569 | if (copy_to_user(p, &ff_up, sizeof(ff_up))) { |
| 535 | retval = -EFAULT; | 570 | retval = -EFAULT; |
| 536 | break; | 571 | break; |
| @@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 561 | break; | 596 | break; |
| 562 | } | 597 | } |
| 563 | req = uinput_request_find(udev, ff_up.request_id); | 598 | req = uinput_request_find(udev, ff_up.request_id); |
| 564 | if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { | 599 | if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { |
| 565 | retval = -EINVAL; | 600 | retval = -EINVAL; |
| 566 | break; | 601 | break; |
| 567 | } | 602 | } |
| 568 | req->retval = ff_up.retval; | 603 | req->retval = ff_up.retval; |
| 569 | memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); | ||
| 570 | uinput_request_done(udev, req); | 604 | uinput_request_done(udev, req); |
| 571 | break; | 605 | break; |
| 572 | 606 | ||
| @@ -622,6 +656,7 @@ static void __exit uinput_exit(void) | |||
| 622 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); | 656 | MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); |
| 623 | MODULE_DESCRIPTION("User level driver support for input subsystem"); | 657 | MODULE_DESCRIPTION("User level driver support for input subsystem"); |
| 624 | MODULE_LICENSE("GPL"); | 658 | MODULE_LICENSE("GPL"); |
| 659 | MODULE_VERSION("0.3"); | ||
| 625 | 660 | ||
| 626 | module_init(uinput_init); | 661 | module_init(uinput_init); |
| 627 | module_exit(uinput_exit); | 662 | module_exit(uinput_exit); |
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index de0f46dd9692..4639537336fc 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c | |||
| @@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi_system_id *dmi) | |||
| 248 | 248 | ||
| 249 | keymap = dmi->driver_data; | 249 | keymap = dmi->driver_data; |
| 250 | for (key = keymap; key->type != KE_END; key++) { | 250 | for (key = keymap; key->type != KE_END; key++) { |
| 251 | if (key->type == KE_WIFI) { | 251 | if (key->type == KE_WIFI) |
| 252 | have_wifi = 1; | 252 | have_wifi = 1; |
| 253 | break; | 253 | else if (key->type == KE_BLUETOOTH) |
| 254 | } else if (key->type == KE_BLUETOOTH) { | ||
| 255 | have_bluetooth = 1; | 254 | have_bluetooth = 1; |
| 256 | break; | ||
| 257 | } | ||
| 258 | } | 255 | } |
| 259 | return 1; | 256 | return 1; |
| 260 | } | 257 | } |
| @@ -389,7 +386,16 @@ static struct dmi_system_id dmi_ids[] __initdata = { | |||
| 389 | }, | 386 | }, |
| 390 | .driver_data = keymap_acer_travelmate_240 | 387 | .driver_data = keymap_acer_travelmate_240 |
| 391 | }, | 388 | }, |
| 392 | { | 389 | { |
| 390 | .callback = dmi_matched, | ||
| 391 | .ident = "Acer TravelMate 2424NWXCi", | ||
| 392 | .matches = { | ||
| 393 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
| 394 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"), | ||
| 395 | }, | ||
| 396 | .driver_data = keymap_acer_travelmate_240 | ||
| 397 | }, | ||
| 398 | { | ||
| 393 | .callback = dmi_matched, | 399 | .callback = dmi_matched, |
| 394 | .ident = "AOpen 1559AS", | 400 | .ident = "AOpen 1559AS", |
| 395 | .matches = { | 401 | .matches = { |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 070d75330afd..450b68a619fd 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
| @@ -36,7 +36,7 @@ | |||
| 36 | #define ALPS_PASS 0x20 | 36 | #define ALPS_PASS 0x20 |
| 37 | #define ALPS_FW_BK_2 0x40 | 37 | #define ALPS_FW_BK_2 0x40 |
| 38 | 38 | ||
| 39 | static struct alps_model_info alps_model_data[] = { | 39 | static const struct alps_model_info alps_model_data[] = { |
| 40 | { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ | 40 | { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ |
| 41 | { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, | 41 | { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, |
| 42 | { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, | 42 | { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, |
| @@ -209,10 +209,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs * | |||
| 209 | return PSMOUSE_GOOD_DATA; | 209 | return PSMOUSE_GOOD_DATA; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) | 212 | static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) |
| 213 | { | 213 | { |
| 214 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 214 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
| 215 | unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; | 215 | static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; |
| 216 | unsigned char param[4]; | 216 | unsigned char param[4]; |
| 217 | int i; | 217 | int i; |
| 218 | 218 | ||
| @@ -504,7 +504,7 @@ init_fail: | |||
| 504 | int alps_detect(struct psmouse *psmouse, int set_properties) | 504 | int alps_detect(struct psmouse *psmouse, int set_properties) |
| 505 | { | 505 | { |
| 506 | int version; | 506 | int version; |
| 507 | struct alps_model_info *model; | 507 | const struct alps_model_info *model; |
| 508 | 508 | ||
| 509 | if (!(model = alps_get_model(psmouse, &version))) | 509 | if (!(model = alps_get_model(psmouse, &version))) |
| 510 | return -1; | 510 | return -1; |
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index e428f8d5d12e..69db7325a494 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h | |||
| @@ -25,7 +25,7 @@ struct alps_data { | |||
| 25 | struct input_dev *dev2; /* Relative device */ | 25 | struct input_dev *dev2; /* Relative device */ |
| 26 | char name[32]; /* Name */ | 26 | char name[32]; /* Name */ |
| 27 | char phys[32]; /* Phys */ | 27 | char phys[32]; /* Phys */ |
| 28 | struct alps_model_info *i; /* Info */ | 28 | const struct alps_model_info *i;/* Info */ |
| 29 | int prev_fin; /* Finger bit from previous packet */ | 29 | int prev_fin; /* Finger bit from previous packet */ |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index c14395ba7980..5e9d25067513 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
| @@ -115,13 +115,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) | |||
| 115 | 115 | ||
| 116 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 116 | static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
| 117 | { | 117 | { |
| 118 | unsigned char params[] = { 0, 1, 2, 2, 3 }; | 118 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
| 119 | unsigned char p; | ||
| 119 | 120 | ||
| 120 | if (resolution == 0 || resolution > 400) | 121 | if (resolution == 0 || resolution > 400) |
| 121 | resolution = 400; | 122 | resolution = 400; |
| 122 | 123 | ||
| 123 | ps2_command(&psmouse->ps2dev, ¶ms[resolution / 100], PSMOUSE_CMD_SETRES); | 124 | p = params[resolution / 100]; |
| 124 | psmouse->resolution = 50 << params[resolution / 100]; | 125 | ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); |
| 126 | psmouse->resolution = 50 << p; | ||
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | static void lifebook_disconnect(struct psmouse *psmouse) | 129 | static void lifebook_disconnect(struct psmouse *psmouse) |
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 54b696cfe1e3..7972eecbcfe4 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c | |||
| @@ -30,9 +30,9 @@ | |||
| 30 | #define PS2PP_NAV_BTN 0x20 | 30 | #define PS2PP_NAV_BTN 0x20 |
| 31 | 31 | ||
| 32 | struct ps2pp_info { | 32 | struct ps2pp_info { |
| 33 | const int model; | 33 | u8 model; |
| 34 | unsigned const int kind; | 34 | u8 kind; |
| 35 | unsigned const int features; | 35 | u16 features; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | /* | 38 | /* |
| @@ -199,9 +199,9 @@ static void ps2pp_disconnect(struct psmouse *psmouse) | |||
| 199 | device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); | 199 | device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | static struct ps2pp_info *get_model_info(unsigned char model) | 202 | static const struct ps2pp_info *get_model_info(unsigned char model) |
| 203 | { | 203 | { |
| 204 | static struct ps2pp_info ps2pp_list[] = { | 204 | static const struct ps2pp_info ps2pp_list[] = { |
| 205 | { 12, 0, PS2PP_SIDE_BTN}, | 205 | { 12, 0, PS2PP_SIDE_BTN}, |
| 206 | { 13, 0, 0 }, | 206 | { 13, 0, 0 }, |
| 207 | { 15, PS2PP_KIND_MX, /* MX1000 */ | 207 | { 15, PS2PP_KIND_MX, /* MX1000 */ |
| @@ -215,6 +215,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) | |||
| 215 | { 51, 0, 0 }, | 215 | { 51, 0, 0 }, |
| 216 | { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, | 216 | { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, |
| 217 | { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, | 217 | { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, |
| 218 | { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */ | ||
| 218 | { 61, PS2PP_KIND_MX, /* MX700 */ | 219 | { 61, PS2PP_KIND_MX, /* MX700 */ |
| 219 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | | 220 | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | |
| 220 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | 221 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, |
| @@ -244,12 +245,11 @@ static struct ps2pp_info *get_model_info(unsigned char model) | |||
| 244 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, | 245 | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, |
| 245 | { 114, PS2PP_KIND_MX, /* MX310 */ | 246 | { 114, PS2PP_KIND_MX, /* MX310 */ |
| 246 | PS2PP_WHEEL | PS2PP_SIDE_BTN | | 247 | PS2PP_WHEEL | PS2PP_SIDE_BTN | |
| 247 | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, | 248 | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN } |
| 248 | { } | ||
| 249 | }; | 249 | }; |
| 250 | int i; | 250 | int i; |
| 251 | 251 | ||
| 252 | for (i = 0; ps2pp_list[i].model; i++) | 252 | for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++) |
| 253 | if (model == ps2pp_list[i].model) | 253 | if (model == ps2pp_list[i].model) |
| 254 | return &ps2pp_list[i]; | 254 | return &ps2pp_list[i]; |
| 255 | 255 | ||
| @@ -261,7 +261,8 @@ static struct ps2pp_info *get_model_info(unsigned char model) | |||
| 261 | * Set up input device's properties based on the detected mouse model. | 261 | * Set up input device's properties based on the detected mouse model. |
| 262 | */ | 262 | */ |
| 263 | 263 | ||
| 264 | static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info, | 264 | static void ps2pp_set_model_properties(struct psmouse *psmouse, |
| 265 | const struct ps2pp_info *model_info, | ||
| 265 | int using_ps2pp) | 266 | int using_ps2pp) |
| 266 | { | 267 | { |
| 267 | struct input_dev *input_dev = psmouse->dev; | 268 | struct input_dev *input_dev = psmouse->dev; |
| @@ -327,7 +328,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) | |||
| 327 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 328 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
| 328 | unsigned char param[4]; | 329 | unsigned char param[4]; |
| 329 | unsigned char model, buttons; | 330 | unsigned char model, buttons; |
| 330 | struct ps2pp_info *model_info; | 331 | const struct ps2pp_info *model_info; |
| 331 | int use_ps2pp = 0; | 332 | int use_ps2pp = 0; |
| 332 | 333 | ||
| 333 | param[0] = 0; | 334 | param[0] = 0; |
| @@ -349,7 +350,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) | |||
| 349 | /* | 350 | /* |
| 350 | * Do Logitech PS2++ / PS2T++ magic init. | 351 | * Do Logitech PS2++ / PS2T++ magic init. |
| 351 | */ | 352 | */ |
| 352 | if (model == 97) { /* Touch Pad 3 */ | 353 | if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */ |
| 353 | 354 | ||
| 354 | /* Unprotect RAM */ | 355 | /* Unprotect RAM */ |
| 355 | param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; | 356 | param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 343afa38f4c2..9fb7eb6b0f71 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
| @@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmoused_wq; | |||
| 112 | 112 | ||
| 113 | struct psmouse_protocol { | 113 | struct psmouse_protocol { |
| 114 | enum psmouse_type type; | 114 | enum psmouse_type type; |
| 115 | char *name; | 115 | const char *name; |
| 116 | char *alias; | 116 | const char *alias; |
| 117 | int maxproto; | 117 | int maxproto; |
| 118 | int (*detect)(struct psmouse *, int); | 118 | int (*detect)(struct psmouse *, int); |
| 119 | int (*init)(struct psmouse *); | 119 | int (*init)(struct psmouse *); |
| @@ -507,15 +507,17 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) | |||
| 507 | { | 507 | { |
| 508 | struct ps2dev *ps2dev = &psmouse->ps2dev; | 508 | struct ps2dev *ps2dev = &psmouse->ps2dev; |
| 509 | unsigned char param[2]; | 509 | unsigned char param[2]; |
| 510 | unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 }; | 510 | static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; |
| 511 | int i; | 511 | int i; |
| 512 | 512 | ||
| 513 | param[0] = 10; | 513 | param[0] = 10; |
| 514 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | 514 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); |
| 515 | param[0] = 0; | 515 | param[0] = 0; |
| 516 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); | 516 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); |
| 517 | for (i = 0; seq[i]; i++) | 517 | for (i = 0; i < ARRAY_SIZE(seq); i++) { |
| 518 | ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE); | 518 | param[0] = seq[i]; |
| 519 | ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); | ||
| 520 | } | ||
| 519 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); | 521 | ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); |
| 520 | 522 | ||
| 521 | if (param[0] != 2) | 523 | if (param[0] != 2) |
| @@ -652,7 +654,7 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
| 652 | return PSMOUSE_PS2; | 654 | return PSMOUSE_PS2; |
| 653 | } | 655 | } |
| 654 | 656 | ||
| 655 | static struct psmouse_protocol psmouse_protocols[] = { | 657 | static const struct psmouse_protocol psmouse_protocols[] = { |
| 656 | { | 658 | { |
| 657 | .type = PSMOUSE_PS2, | 659 | .type = PSMOUSE_PS2, |
| 658 | .name = "PS/2", | 660 | .name = "PS/2", |
| @@ -726,7 +728,7 @@ static struct psmouse_protocol psmouse_protocols[] = { | |||
| 726 | }, | 728 | }, |
| 727 | }; | 729 | }; |
| 728 | 730 | ||
| 729 | static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) | 731 | static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) |
| 730 | { | 732 | { |
| 731 | int i; | 733 | int i; |
| 732 | 734 | ||
| @@ -738,9 +740,9 @@ static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) | |||
| 738 | return &psmouse_protocols[0]; | 740 | return &psmouse_protocols[0]; |
| 739 | } | 741 | } |
| 740 | 742 | ||
| 741 | static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) | 743 | static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) |
| 742 | { | 744 | { |
| 743 | struct psmouse_protocol *p; | 745 | const struct psmouse_protocol *p; |
| 744 | int i; | 746 | int i; |
| 745 | 747 | ||
| 746 | for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { | 748 | for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { |
| @@ -795,13 +797,15 @@ static int psmouse_probe(struct psmouse *psmouse) | |||
| 795 | 797 | ||
| 796 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) | 798 | void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) |
| 797 | { | 799 | { |
| 798 | unsigned char params[] = { 0, 1, 2, 2, 3 }; | 800 | static const unsigned char params[] = { 0, 1, 2, 2, 3 }; |
| 801 | unsigned char p; | ||
| 799 | 802 | ||
| 800 | if (resolution == 0 || resolution > 200) | 803 | if (resolution == 0 || resolution > 200) |
| 801 | resolution = 200; | 804 | resolution = 200; |
| 802 | 805 | ||
| 803 | ps2_command(&psmouse->ps2dev, ¶ms[resolution / 50], PSMOUSE_CMD_SETRES); | 806 | p = params[resolution / 50]; |
| 804 | psmouse->resolution = 25 << params[resolution / 50]; | 807 | ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); |
| 808 | psmouse->resolution = 25 << p; | ||
| 805 | } | 809 | } |
| 806 | 810 | ||
| 807 | /* | 811 | /* |
| @@ -810,12 +814,14 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) | |||
| 810 | 814 | ||
| 811 | static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) | 815 | static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) |
| 812 | { | 816 | { |
| 813 | unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; | 817 | static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; |
| 818 | unsigned char r; | ||
| 814 | int i = 0; | 819 | int i = 0; |
| 815 | 820 | ||
| 816 | while (rates[i] > rate) i++; | 821 | while (rates[i] > rate) i++; |
| 817 | ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE); | 822 | r = rates[i]; |
| 818 | psmouse->rate = rates[i]; | 823 | ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE); |
| 824 | psmouse->rate = r; | ||
| 819 | } | 825 | } |
| 820 | 826 | ||
| 821 | /* | 827 | /* |
| @@ -1031,7 +1037,7 @@ static void psmouse_disconnect(struct serio *serio) | |||
| 1031 | mutex_unlock(&psmouse_mutex); | 1037 | mutex_unlock(&psmouse_mutex); |
| 1032 | } | 1038 | } |
| 1033 | 1039 | ||
| 1034 | static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) | 1040 | static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto) |
| 1035 | { | 1041 | { |
| 1036 | struct input_dev *input_dev = psmouse->dev; | 1042 | struct input_dev *input_dev = psmouse->dev; |
| 1037 | 1043 | ||
| @@ -1362,7 +1368,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co | |||
| 1362 | struct serio *serio = psmouse->ps2dev.serio; | 1368 | struct serio *serio = psmouse->ps2dev.serio; |
| 1363 | struct psmouse *parent = NULL; | 1369 | struct psmouse *parent = NULL; |
| 1364 | struct input_dev *new_dev; | 1370 | struct input_dev *new_dev; |
| 1365 | struct psmouse_protocol *proto; | 1371 | const struct psmouse_protocol *proto; |
| 1366 | int retry = 0; | 1372 | int retry = 0; |
| 1367 | 1373 | ||
| 1368 | if (!(proto = psmouse_protocol_by_name(buf, count))) | 1374 | if (!(proto = psmouse_protocol_by_name(buf, count))) |
| @@ -1459,7 +1465,7 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, | |||
| 1459 | 1465 | ||
| 1460 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) | 1466 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) |
| 1461 | { | 1467 | { |
| 1462 | struct psmouse_protocol *proto; | 1468 | const struct psmouse_protocol *proto; |
| 1463 | 1469 | ||
| 1464 | if (!val) | 1470 | if (!val) |
| 1465 | return -EINVAL; | 1471 | return -EINVAL; |
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 0023501a5b63..680b32353884 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c | |||
| @@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
| 42 | MODULE_DESCRIPTION(DRIVER_DESC); | 42 | MODULE_DESCRIPTION(DRIVER_DESC); |
| 43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
| 44 | 44 | ||
| 45 | static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", | 45 | static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", |
| 46 | "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", | 46 | "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", |
| 47 | "Logitech MZ++ Mouse"}; | 47 | "Logitech MZ++ Mouse"}; |
| 48 | 48 | ||
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index ad5d0a85e960..392108c436ba 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
| @@ -430,11 +430,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) | |||
| 430 | 430 | ||
| 431 | static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) | 431 | static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) |
| 432 | { | 432 | { |
| 433 | static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; | 433 | static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; |
| 434 | static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; | 434 | static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; |
| 435 | static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; | 435 | static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; |
| 436 | static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; | 436 | static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; |
| 437 | static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; | 437 | static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; |
| 438 | 438 | ||
| 439 | if (idx < 0 || idx > 4) | 439 | if (idx < 0 || idx > 4) |
| 440 | return 0; | 440 | return 0; |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 1f851acab30d..a22a74a2a3dc 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
| @@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait) | |||
| 614 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); | 614 | (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); |
| 615 | } | 615 | } |
| 616 | 616 | ||
| 617 | static struct file_operations mousedev_fops = { | 617 | static const struct file_operations mousedev_fops = { |
| 618 | .owner = THIS_MODULE, | 618 | .owner = THIS_MODULE, |
| 619 | .read = mousedev_read, | 619 | .read = mousedev_read, |
| 620 | .write = mousedev_write, | 620 | .write = mousedev_write, |
| @@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = { | |||
| 624 | .fasync = mousedev_fasync, | 624 | .fasync = mousedev_fasync, |
| 625 | }; | 625 | }; |
| 626 | 626 | ||
| 627 | static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | 627 | static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, |
| 628 | const struct input_device_id *id) | ||
| 628 | { | 629 | { |
| 629 | struct mousedev *mousedev; | 630 | struct mousedev *mousedev; |
| 630 | struct class_device *cdev; | 631 | struct class_device *cdev; |
| @@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle) | |||
| 688 | } | 689 | } |
| 689 | } | 690 | } |
| 690 | 691 | ||
| 691 | static struct input_device_id mousedev_ids[] = { | 692 | static const struct input_device_id mousedev_ids[] = { |
| 692 | { | 693 | { |
| 693 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 694 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, |
| 694 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 695 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
| @@ -737,7 +738,12 @@ static int psaux_registered; | |||
| 737 | 738 | ||
| 738 | static int __init mousedev_init(void) | 739 | static int __init mousedev_init(void) |
| 739 | { | 740 | { |
| 740 | input_register_handler(&mousedev_handler); | 741 | struct class_device *cdev; |
| 742 | int error; | ||
| 743 | |||
| 744 | error = input_register_handler(&mousedev_handler); | ||
| 745 | if (error) | ||
| 746 | return error; | ||
| 741 | 747 | ||
| 742 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); | 748 | memset(&mousedev_mix, 0, sizeof(struct mousedev)); |
| 743 | INIT_LIST_HEAD(&mousedev_mix.list); | 749 | INIT_LIST_HEAD(&mousedev_mix.list); |
| @@ -746,12 +752,20 @@ static int __init mousedev_init(void) | |||
| 746 | mousedev_mix.exist = 1; | 752 | mousedev_mix.exist = 1; |
| 747 | mousedev_mix.minor = MOUSEDEV_MIX; | 753 | mousedev_mix.minor = MOUSEDEV_MIX; |
| 748 | 754 | ||
| 749 | class_device_create(&input_class, NULL, | 755 | cdev = class_device_create(&input_class, NULL, |
| 750 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); | 756 | MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); |
| 757 | if (IS_ERR(cdev)) { | ||
| 758 | input_unregister_handler(&mousedev_handler); | ||
| 759 | return PTR_ERR(cdev); | ||
| 760 | } | ||
| 751 | 761 | ||
| 752 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 762 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
| 753 | if (!(psaux_registered = !misc_register(&psaux_mouse))) | 763 | error = misc_register(&psaux_mouse); |
| 754 | printk(KERN_WARNING "mice: could not misc_register the device\n"); | 764 | if (error) |
| 765 | printk(KERN_WARNING "mice: could not register psaux device, " | ||
| 766 | "error: %d\n", error); | ||
| 767 | else | ||
| 768 | psaux_registered = 1; | ||
| 755 | #endif | 769 | #endif |
| 756 | 770 | ||
| 757 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); | 771 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); |
diff --git a/drivers/input/power.c b/drivers/input/power.c index 51a519e24b6d..ee82464a2fa7 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c | |||
| @@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type, | |||
| 98 | 98 | ||
| 99 | static struct input_handle *power_connect(struct input_handler *handler, | 99 | static struct input_handle *power_connect(struct input_handler *handler, |
| 100 | struct input_dev *dev, | 100 | struct input_dev *dev, |
| 101 | struct input_device_id *id) | 101 | const struct input_device_id *id) |
| 102 | { | 102 | { |
| 103 | struct input_handle *handle; | 103 | struct input_handle *handle; |
| 104 | 104 | ||
| @@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle) | |||
| 120 | kfree(handle); | 120 | kfree(handle); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | static struct input_device_id power_ids[] = { | 123 | static const struct input_device_id power_ids[] = { |
| 124 | { | 124 | { |
| 125 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 125 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, |
| 126 | .evbit = { BIT(EV_KEY) }, | 126 | .evbit = { BIT(EV_KEY) }, |
| @@ -150,8 +150,7 @@ static struct input_handler power_handler = { | |||
| 150 | 150 | ||
| 151 | static int __init power_init(void) | 151 | static int __init power_init(void) |
| 152 | { | 152 | { |
| 153 | input_register_handler(&power_handler); | 153 | return input_register_handler(&power_handler); |
| 154 | return 0; | ||
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | static void __exit power_exit(void) | 156 | static void __exit power_exit(void) |
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index f606e96bc2f4..8738edda6610 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
| @@ -160,6 +160,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | |||
| 160 | }, | 160 | }, |
| 161 | }, | 161 | }, |
| 162 | { | 162 | { |
| 163 | .ident = "Toshiba Equium A110", | ||
| 164 | .matches = { | ||
| 165 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
| 166 | DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"), | ||
| 167 | }, | ||
| 168 | }, | ||
| 169 | { | ||
| 163 | .ident = "Alienware Sentia", | 170 | .ident = "Alienware Sentia", |
| 164 | .matches = { | 171 | .matches = { |
| 165 | DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), | 172 | DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"), |
| @@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { | |||
| 180 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), | 187 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), |
| 181 | }, | 188 | }, |
| 182 | }, | 189 | }, |
| 190 | { | ||
| 191 | .ident = "Amoi M636/A737", | ||
| 192 | .matches = { | ||
| 193 | DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."), | ||
| 194 | DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"), | ||
| 195 | }, | ||
| 196 | }, | ||
| 183 | { } | 197 | { } |
| 184 | }; | 198 | }; |
| 185 | 199 | ||
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 06a3f25657dd..1bb0c76a9259 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
| @@ -90,46 +90,24 @@ static DEFINE_SPINLOCK(i8042_lock); | |||
| 90 | struct i8042_port { | 90 | struct i8042_port { |
| 91 | struct serio *serio; | 91 | struct serio *serio; |
| 92 | int irq; | 92 | int irq; |
| 93 | unsigned char disable; | ||
| 94 | unsigned char irqen; | ||
| 95 | unsigned char exists; | 93 | unsigned char exists; |
| 96 | signed char mux; | 94 | signed char mux; |
| 97 | char name[8]; | ||
| 98 | }; | 95 | }; |
| 99 | 96 | ||
| 100 | #define I8042_KBD_PORT_NO 0 | 97 | #define I8042_KBD_PORT_NO 0 |
| 101 | #define I8042_AUX_PORT_NO 1 | 98 | #define I8042_AUX_PORT_NO 1 |
| 102 | #define I8042_MUX_PORT_NO 2 | 99 | #define I8042_MUX_PORT_NO 2 |
| 103 | #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) | 100 | #define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2) |
| 104 | static struct i8042_port i8042_ports[I8042_NUM_PORTS] = { | 101 | |
| 105 | { | 102 | static struct i8042_port i8042_ports[I8042_NUM_PORTS]; |
| 106 | .disable = I8042_CTR_KBDDIS, | ||
| 107 | .irqen = I8042_CTR_KBDINT, | ||
| 108 | .mux = -1, | ||
| 109 | .name = "KBD", | ||
| 110 | }, | ||
| 111 | { | ||
| 112 | .disable = I8042_CTR_AUXDIS, | ||
| 113 | .irqen = I8042_CTR_AUXINT, | ||
| 114 | .mux = -1, | ||
| 115 | .name = "AUX", | ||
| 116 | } | ||
| 117 | }; | ||
| 118 | 103 | ||
| 119 | static unsigned char i8042_initial_ctr; | 104 | static unsigned char i8042_initial_ctr; |
| 120 | static unsigned char i8042_ctr; | 105 | static unsigned char i8042_ctr; |
| 121 | static unsigned char i8042_mux_open; | ||
| 122 | static unsigned char i8042_mux_present; | 106 | static unsigned char i8042_mux_present; |
| 123 | static struct timer_list i8042_timer; | 107 | static unsigned char i8042_kbd_irq_registered; |
| 108 | static unsigned char i8042_aux_irq_registered; | ||
| 124 | static struct platform_device *i8042_platform_device; | 109 | static struct platform_device *i8042_platform_device; |
| 125 | 110 | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Shared IRQ's require a device pointer, but this driver doesn't support | ||
| 129 | * multiple devices | ||
| 130 | */ | ||
| 131 | #define i8042_request_irq_cookie (&i8042_timer) | ||
| 132 | |||
| 133 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); | 111 | static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); |
| 134 | 112 | ||
| 135 | /* | 113 | /* |
| @@ -141,6 +119,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); | |||
| 141 | static int i8042_wait_read(void) | 119 | static int i8042_wait_read(void) |
| 142 | { | 120 | { |
| 143 | int i = 0; | 121 | int i = 0; |
| 122 | |||
| 144 | while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { | 123 | while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) { |
| 145 | udelay(50); | 124 | udelay(50); |
| 146 | i++; | 125 | i++; |
| @@ -151,6 +130,7 @@ static int i8042_wait_read(void) | |||
| 151 | static int i8042_wait_write(void) | 130 | static int i8042_wait_write(void) |
| 152 | { | 131 | { |
| 153 | int i = 0; | 132 | int i = 0; |
| 133 | |||
| 154 | while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { | 134 | while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) { |
| 155 | udelay(50); | 135 | udelay(50); |
| 156 | i++; | 136 | i++; |
| @@ -192,48 +172,57 @@ static int i8042_flush(void) | |||
| 192 | * encoded in bits 8-11 of the command number. | 172 | * encoded in bits 8-11 of the command number. |
| 193 | */ | 173 | */ |
| 194 | 174 | ||
| 195 | static int i8042_command(unsigned char *param, int command) | 175 | static int __i8042_command(unsigned char *param, int command) |
| 196 | { | 176 | { |
| 197 | unsigned long flags; | 177 | int i, error; |
| 198 | int i, retval, auxerr = 0; | ||
| 199 | 178 | ||
| 200 | if (i8042_noloop && command == I8042_CMD_AUX_LOOP) | 179 | if (i8042_noloop && command == I8042_CMD_AUX_LOOP) |
| 201 | return -1; | 180 | return -1; |
| 202 | 181 | ||
| 203 | spin_lock_irqsave(&i8042_lock, flags); | 182 | error = i8042_wait_write(); |
| 204 | 183 | if (error) | |
| 205 | if ((retval = i8042_wait_write())) | 184 | return error; |
| 206 | goto out; | ||
| 207 | 185 | ||
| 208 | dbg("%02x -> i8042 (command)", command & 0xff); | 186 | dbg("%02x -> i8042 (command)", command & 0xff); |
| 209 | i8042_write_command(command & 0xff); | 187 | i8042_write_command(command & 0xff); |
| 210 | 188 | ||
| 211 | for (i = 0; i < ((command >> 12) & 0xf); i++) { | 189 | for (i = 0; i < ((command >> 12) & 0xf); i++) { |
| 212 | if ((retval = i8042_wait_write())) | 190 | error = i8042_wait_write(); |
| 213 | goto out; | 191 | if (error) |
| 192 | return error; | ||
| 214 | dbg("%02x -> i8042 (parameter)", param[i]); | 193 | dbg("%02x -> i8042 (parameter)", param[i]); |
| 215 | i8042_write_data(param[i]); | 194 | i8042_write_data(param[i]); |
| 216 | } | 195 | } |
| 217 | 196 | ||
| 218 | for (i = 0; i < ((command >> 8) & 0xf); i++) { | 197 | for (i = 0; i < ((command >> 8) & 0xf); i++) { |
| 219 | if ((retval = i8042_wait_read())) | 198 | error = i8042_wait_read(); |
| 220 | goto out; | 199 | if (error) { |
| 200 | dbg(" -- i8042 (timeout)"); | ||
| 201 | return error; | ||
| 202 | } | ||
| 221 | 203 | ||
| 222 | if (command == I8042_CMD_AUX_LOOP && | 204 | if (command == I8042_CMD_AUX_LOOP && |
| 223 | !(i8042_read_status() & I8042_STR_AUXDATA)) { | 205 | !(i8042_read_status() & I8042_STR_AUXDATA)) { |
| 224 | retval = auxerr = -1; | 206 | dbg(" -- i8042 (auxerr)"); |
| 225 | goto out; | 207 | return -1; |
| 226 | } | 208 | } |
| 227 | 209 | ||
| 228 | param[i] = i8042_read_data(); | 210 | param[i] = i8042_read_data(); |
| 229 | dbg("%02x <- i8042 (return)", param[i]); | 211 | dbg("%02x <- i8042 (return)", param[i]); |
| 230 | } | 212 | } |
| 231 | 213 | ||
| 232 | if (retval) | 214 | return 0; |
| 233 | dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout"); | 215 | } |
| 234 | 216 | ||
| 235 | out: | 217 | static int i8042_command(unsigned char *param, int command) |
| 218 | { | ||
| 219 | unsigned long flags; | ||
| 220 | int retval; | ||
| 221 | |||
| 222 | spin_lock_irqsave(&i8042_lock, flags); | ||
| 223 | retval = __i8042_command(param, command); | ||
| 236 | spin_unlock_irqrestore(&i8042_lock, flags); | 224 | spin_unlock_irqrestore(&i8042_lock, flags); |
| 225 | |||
| 237 | return retval; | 226 | return retval; |
| 238 | } | 227 | } |
| 239 | 228 | ||
| @@ -248,7 +237,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) | |||
| 248 | 237 | ||
| 249 | spin_lock_irqsave(&i8042_lock, flags); | 238 | spin_lock_irqsave(&i8042_lock, flags); |
| 250 | 239 | ||
| 251 | if(!(retval = i8042_wait_write())) { | 240 | if (!(retval = i8042_wait_write())) { |
| 252 | dbg("%02x -> i8042 (kbd-data)", c); | 241 | dbg("%02x -> i8042 (kbd-data)", c); |
| 253 | i8042_write_data(c); | 242 | i8042_write_data(c); |
| 254 | } | 243 | } |
| @@ -287,100 +276,6 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) | |||
| 287 | } | 276 | } |
| 288 | 277 | ||
| 289 | /* | 278 | /* |
| 290 | * i8042_activate_port() enables port on a chip. | ||
| 291 | */ | ||
| 292 | |||
| 293 | static int i8042_activate_port(struct i8042_port *port) | ||
| 294 | { | ||
| 295 | if (!port->serio) | ||
| 296 | return -1; | ||
| 297 | |||
| 298 | i8042_flush(); | ||
| 299 | |||
| 300 | /* | ||
| 301 | * Enable port again here because it is disabled if we are | ||
| 302 | * resuming (normally it is enabled already). | ||
| 303 | */ | ||
| 304 | i8042_ctr &= ~port->disable; | ||
| 305 | |||
| 306 | i8042_ctr |= port->irqen; | ||
| 307 | |||
| 308 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 309 | i8042_ctr &= ~port->irqen; | ||
| 310 | return -1; | ||
| 311 | } | ||
| 312 | |||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | |||
| 317 | /* | ||
| 318 | * i8042_open() is called when a port is open by the higher layer. | ||
| 319 | * It allocates the interrupt and calls i8042_enable_port. | ||
| 320 | */ | ||
| 321 | |||
| 322 | static int i8042_open(struct serio *serio) | ||
| 323 | { | ||
| 324 | struct i8042_port *port = serio->port_data; | ||
| 325 | |||
| 326 | if (port->mux != -1) | ||
| 327 | if (i8042_mux_open++) | ||
| 328 | return 0; | ||
| 329 | |||
| 330 | if (request_irq(port->irq, i8042_interrupt, | ||
| 331 | IRQF_SHARED, "i8042", i8042_request_irq_cookie)) { | ||
| 332 | printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name); | ||
| 333 | goto irq_fail; | ||
| 334 | } | ||
| 335 | |||
| 336 | if (i8042_activate_port(port)) { | ||
| 337 | printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name); | ||
| 338 | goto activate_fail; | ||
| 339 | } | ||
| 340 | |||
| 341 | i8042_interrupt(0, NULL, NULL); | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | |||
| 345 | activate_fail: | ||
| 346 | free_irq(port->irq, i8042_request_irq_cookie); | ||
| 347 | |||
| 348 | irq_fail: | ||
| 349 | serio_unregister_port_delayed(serio); | ||
| 350 | |||
| 351 | return -1; | ||
| 352 | } | ||
| 353 | |||
| 354 | /* | ||
| 355 | * i8042_close() frees the interrupt, so that it can possibly be used | ||
| 356 | * by another driver. We never know - if the user doesn't have a mouse, | ||
| 357 | * the BIOS could have used the AUX interrupt for PCI. | ||
| 358 | */ | ||
| 359 | |||
| 360 | static void i8042_close(struct serio *serio) | ||
| 361 | { | ||
| 362 | struct i8042_port *port = serio->port_data; | ||
| 363 | |||
| 364 | if (port->mux != -1) | ||
| 365 | if (--i8042_mux_open) | ||
| 366 | return; | ||
| 367 | |||
| 368 | i8042_ctr &= ~port->irqen; | ||
| 369 | |||
| 370 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 371 | printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name); | ||
| 372 | /* | ||
| 373 | * We still want to continue and free IRQ so if more data keeps coming in | ||
| 374 | * kernel will just ignore the irq. | ||
| 375 | */ | ||
| 376 | } | ||
| 377 | |||
| 378 | free_irq(port->irq, i8042_request_irq_cookie); | ||
| 379 | |||
| 380 | i8042_flush(); | ||
| 381 | } | ||
| 382 | |||
| 383 | /* | ||
| 384 | * i8042_start() is called by serio core when port is about to finish | 279 | * i8042_start() is called by serio core when port is about to finish |
| 385 | * registering. It will mark port as existing so i8042_interrupt can | 280 | * registering. It will mark port as existing so i8042_interrupt can |
| 386 | * start sending data through it. | 281 | * start sending data through it. |
| @@ -423,8 +318,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 423 | unsigned int port_no; | 318 | unsigned int port_no; |
| 424 | int ret; | 319 | int ret; |
| 425 | 320 | ||
| 426 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | ||
| 427 | |||
| 428 | spin_lock_irqsave(&i8042_lock, flags); | 321 | spin_lock_irqsave(&i8042_lock, flags); |
| 429 | str = i8042_read_status(); | 322 | str = i8042_read_status(); |
| 430 | if (unlikely(~str & I8042_STR_OBF)) { | 323 | if (unlikely(~str & I8042_STR_OBF)) { |
| @@ -480,8 +373,8 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 480 | 373 | ||
| 481 | port = &i8042_ports[port_no]; | 374 | port = &i8042_ports[port_no]; |
| 482 | 375 | ||
| 483 | dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", | 376 | dbg("%02x <- i8042 (interrupt, %d, %d%s%s)", |
| 484 | data, port->name, irq, | 377 | data, port_no, irq, |
| 485 | dfl & SERIO_PARITY ? ", bad parity" : "", | 378 | dfl & SERIO_PARITY ? ", bad parity" : "", |
| 486 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); | 379 | dfl & SERIO_TIMEOUT ? ", timeout" : ""); |
| 487 | 380 | ||
| @@ -494,6 +387,58 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 494 | } | 387 | } |
| 495 | 388 | ||
| 496 | /* | 389 | /* |
| 390 | * i8042_enable_kbd_port enables keybaord port on chip | ||
| 391 | */ | ||
| 392 | |||
| 393 | static int i8042_enable_kbd_port(void) | ||
| 394 | { | ||
| 395 | i8042_ctr &= ~I8042_CTR_KBDDIS; | ||
| 396 | i8042_ctr |= I8042_CTR_KBDINT; | ||
| 397 | |||
| 398 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 399 | printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); | ||
| 400 | return -EIO; | ||
| 401 | } | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | /* | ||
| 407 | * i8042_enable_aux_port enables AUX (mouse) port on chip | ||
| 408 | */ | ||
| 409 | |||
| 410 | static int i8042_enable_aux_port(void) | ||
| 411 | { | ||
| 412 | i8042_ctr &= ~I8042_CTR_AUXDIS; | ||
| 413 | i8042_ctr |= I8042_CTR_AUXINT; | ||
| 414 | |||
| 415 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 416 | printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); | ||
| 417 | return -EIO; | ||
| 418 | } | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | /* | ||
| 424 | * i8042_enable_mux_ports enables 4 individual AUX ports after | ||
| 425 | * the controller has been switched into Multiplexed mode | ||
| 426 | */ | ||
| 427 | |||
| 428 | static int i8042_enable_mux_ports(void) | ||
| 429 | { | ||
| 430 | unsigned char param; | ||
| 431 | int i; | ||
| 432 | |||
| 433 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { | ||
| 434 | i8042_command(¶m, I8042_CMD_MUX_PFX + i); | ||
| 435 | i8042_command(¶m, I8042_CMD_AUX_ENABLE); | ||
| 436 | } | ||
| 437 | |||
| 438 | return i8042_enable_aux_port(); | ||
| 439 | } | ||
| 440 | |||
| 441 | /* | ||
| 497 | * i8042_set_mux_mode checks whether the controller has an active | 442 | * i8042_set_mux_mode checks whether the controller has an active |
| 498 | * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. | 443 | * multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode. |
| 499 | */ | 444 | */ |
| @@ -510,8 +455,7 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) | |||
| 510 | 455 | ||
| 511 | /* | 456 | /* |
| 512 | * Internal loopback test - send three bytes, they should come back from the | 457 | * Internal loopback test - send three bytes, they should come back from the |
| 513 | * mouse interface, the last should be version. Note that we negate mouseport | 458 | * mouse interface, the last should be version. |
| 514 | * command responses for the i8042_check_aux() routine. | ||
| 515 | */ | 459 | */ |
| 516 | 460 | ||
| 517 | param = 0xf0; | 461 | param = 0xf0; |
| @@ -530,67 +474,67 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version) | |||
| 530 | return 0; | 474 | return 0; |
| 531 | } | 475 | } |
| 532 | 476 | ||
| 533 | |||
| 534 | /* | 477 | /* |
| 535 | * i8042_enable_mux_ports enables 4 individual AUX ports after | 478 | * i8042_check_mux() checks whether the controller supports the PS/2 Active |
| 536 | * the controller has been switched into Multiplexed mode | 479 | * Multiplexing specification by Synaptics, Phoenix, Insyde and |
| 480 | * LCS/Telegraphics. | ||
| 537 | */ | 481 | */ |
| 538 | 482 | ||
| 539 | static int i8042_enable_mux_ports(void) | 483 | static int __devinit i8042_check_mux(void) |
| 540 | { | 484 | { |
| 541 | unsigned char param; | 485 | unsigned char mux_version; |
| 542 | int i; | 486 | |
| 487 | if (i8042_set_mux_mode(1, &mux_version)) | ||
| 488 | return -1; | ||
| 489 | |||
| 543 | /* | 490 | /* |
| 544 | * Disable all muxed ports by disabling AUX. | 491 | * Workaround for interference with USB Legacy emulation |
| 492 | * that causes a v10.12 MUX to be found. | ||
| 545 | */ | 493 | */ |
| 494 | if (mux_version == 0xAC) | ||
| 495 | return -1; | ||
| 496 | |||
| 497 | printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", | ||
| 498 | (mux_version >> 4) & 0xf, mux_version & 0xf); | ||
| 546 | 499 | ||
| 500 | /* | ||
| 501 | * Disable all muxed ports by disabling AUX. | ||
| 502 | */ | ||
| 547 | i8042_ctr |= I8042_CTR_AUXDIS; | 503 | i8042_ctr |= I8042_CTR_AUXDIS; |
| 548 | i8042_ctr &= ~I8042_CTR_AUXINT; | 504 | i8042_ctr &= ~I8042_CTR_AUXINT; |
| 549 | 505 | ||
| 550 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 506 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { |
| 551 | printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); | 507 | printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n"); |
| 552 | return -1; | 508 | return -EIO; |
| 553 | } | 509 | } |
| 554 | 510 | ||
| 555 | /* | 511 | i8042_mux_present = 1; |
| 556 | * Enable all muxed ports. | ||
| 557 | */ | ||
| 558 | |||
| 559 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { | ||
| 560 | i8042_command(¶m, I8042_CMD_MUX_PFX + i); | ||
| 561 | i8042_command(¶m, I8042_CMD_AUX_ENABLE); | ||
| 562 | } | ||
| 563 | 512 | ||
| 564 | return 0; | 513 | return 0; |
| 565 | } | 514 | } |
| 566 | 515 | ||
| 567 | |||
| 568 | /* | 516 | /* |
| 569 | * i8042_check_mux() checks whether the controller supports the PS/2 Active | 517 | * The following is used to test AUX IRQ delivery. |
| 570 | * Multiplexing specification by Synaptics, Phoenix, Insyde and | ||
| 571 | * LCS/Telegraphics. | ||
| 572 | */ | 518 | */ |
| 519 | static struct completion i8042_aux_irq_delivered __devinitdata; | ||
| 520 | static int i8042_irq_being_tested __devinitdata; | ||
| 573 | 521 | ||
| 574 | static int __devinit i8042_check_mux(void) | 522 | static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id, struct pt_regs *regs) |
| 575 | { | 523 | { |
| 576 | unsigned char mux_version; | 524 | unsigned long flags; |
| 577 | 525 | unsigned char str, data; | |
| 578 | if (i8042_set_mux_mode(1, &mux_version)) | ||
| 579 | return -1; | ||
| 580 | |||
| 581 | /* Workaround for interference with USB Legacy emulation */ | ||
| 582 | /* that causes a v10.12 MUX to be found. */ | ||
| 583 | if (mux_version == 0xAC) | ||
| 584 | return -1; | ||
| 585 | |||
| 586 | printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n", | ||
| 587 | (mux_version >> 4) & 0xf, mux_version & 0xf); | ||
| 588 | 526 | ||
| 589 | if (i8042_enable_mux_ports()) | 527 | spin_lock_irqsave(&i8042_lock, flags); |
| 590 | return -1; | 528 | str = i8042_read_status(); |
| 529 | if (str & I8042_STR_OBF) { | ||
| 530 | data = i8042_read_data(); | ||
| 531 | if (i8042_irq_being_tested && | ||
| 532 | data == 0xa5 && (str & I8042_STR_AUXDATA)) | ||
| 533 | complete(&i8042_aux_irq_delivered); | ||
| 534 | } | ||
| 535 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
| 591 | 536 | ||
| 592 | i8042_mux_present = 1; | 537 | return IRQ_HANDLED; |
| 593 | return 0; | ||
| 594 | } | 538 | } |
| 595 | 539 | ||
| 596 | 540 | ||
| @@ -601,18 +545,10 @@ static int __devinit i8042_check_mux(void) | |||
| 601 | 545 | ||
| 602 | static int __devinit i8042_check_aux(void) | 546 | static int __devinit i8042_check_aux(void) |
| 603 | { | 547 | { |
| 548 | int retval = -1; | ||
| 549 | int irq_registered = 0; | ||
| 550 | unsigned long flags; | ||
| 604 | unsigned char param; | 551 | unsigned char param; |
| 605 | static int i8042_check_aux_cookie; | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Check if AUX irq is available. If it isn't, then there is no point | ||
| 609 | * in trying to detect AUX presence. | ||
| 610 | */ | ||
| 611 | |||
| 612 | if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt, | ||
| 613 | IRQF_SHARED, "i8042", &i8042_check_aux_cookie)) | ||
| 614 | return -1; | ||
| 615 | free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie); | ||
| 616 | 552 | ||
| 617 | /* | 553 | /* |
| 618 | * Get rid of bytes in the queue. | 554 | * Get rid of bytes in the queue. |
| @@ -637,9 +573,9 @@ static int __devinit i8042_check_aux(void) | |||
| 637 | * AUX ports, we test for this only when the LOOP command failed. | 573 | * AUX ports, we test for this only when the LOOP command failed. |
| 638 | */ | 574 | */ |
| 639 | 575 | ||
| 640 | if (i8042_command(¶m, I8042_CMD_AUX_TEST) | 576 | if (i8042_command(¶m, I8042_CMD_AUX_TEST) || |
| 641 | || (param && param != 0xfa && param != 0xff)) | 577 | (param && param != 0xfa && param != 0xff)) |
| 642 | return -1; | 578 | return -1; |
| 643 | } | 579 | } |
| 644 | 580 | ||
| 645 | /* | 581 | /* |
| @@ -659,54 +595,80 @@ static int __devinit i8042_check_aux(void) | |||
| 659 | return -1; | 595 | return -1; |
| 660 | 596 | ||
| 661 | /* | 597 | /* |
| 662 | * Disable the interface. | 598 | * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and |
| 599 | * used it for a PCI card or somethig else. | ||
| 663 | */ | 600 | */ |
| 664 | 601 | ||
| 665 | i8042_ctr |= I8042_CTR_AUXDIS; | 602 | if (i8042_noloop) { |
| 666 | i8042_ctr &= ~I8042_CTR_AUXINT; | 603 | /* |
| 604 | * Without LOOP command we can't test AUX IRQ delivery. Assume the port | ||
| 605 | * is working and hope we are right. | ||
| 606 | */ | ||
| 607 | retval = 0; | ||
| 608 | goto out; | ||
| 609 | } | ||
| 667 | 610 | ||
| 668 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | 611 | if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED, |
| 669 | return -1; | 612 | "i8042", i8042_platform_device)) |
| 613 | goto out; | ||
| 670 | 614 | ||
| 671 | return 0; | 615 | irq_registered = 1; |
| 672 | } | 616 | |
| 617 | if (i8042_enable_aux_port()) | ||
| 618 | goto out; | ||
| 619 | |||
| 620 | spin_lock_irqsave(&i8042_lock, flags); | ||
| 673 | 621 | ||
| 622 | init_completion(&i8042_aux_irq_delivered); | ||
| 623 | i8042_irq_being_tested = 1; | ||
| 624 | |||
| 625 | param = 0xa5; | ||
| 626 | retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); | ||
| 627 | |||
| 628 | spin_unlock_irqrestore(&i8042_lock, flags); | ||
| 629 | |||
| 630 | if (retval) | ||
| 631 | goto out; | ||
| 674 | 632 | ||
| 633 | if (wait_for_completion_timeout(&i8042_aux_irq_delivered, | ||
| 634 | msecs_to_jiffies(250)) == 0) { | ||
| 675 | /* | 635 | /* |
| 676 | * i8042_port_register() marks the device as existing, | 636 | * AUX IRQ was never delivered so we need to flush the controller to |
| 677 | * registers it, and reports to the user. | 637 | * get rid of the byte we put there; otherwise keyboard may not work. |
| 678 | */ | 638 | */ |
| 639 | i8042_flush(); | ||
| 640 | retval = -1; | ||
| 641 | } | ||
| 679 | 642 | ||
| 680 | static int __devinit i8042_port_register(struct i8042_port *port) | 643 | out: |
| 681 | { | ||
| 682 | i8042_ctr &= ~port->disable; | ||
| 683 | 644 | ||
| 684 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 645 | /* |
| 685 | printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n"); | 646 | * Disable the interface. |
| 686 | kfree(port->serio); | 647 | */ |
| 687 | port->serio = NULL; | ||
| 688 | i8042_ctr |= port->disable; | ||
| 689 | return -EIO; | ||
| 690 | } | ||
| 691 | 648 | ||
| 692 | printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n", | 649 | i8042_ctr |= I8042_CTR_AUXDIS; |
| 693 | port->name, | 650 | i8042_ctr &= ~I8042_CTR_AUXINT; |
| 694 | (unsigned long) I8042_DATA_REG, | ||
| 695 | (unsigned long) I8042_COMMAND_REG, | ||
| 696 | port->irq); | ||
| 697 | 651 | ||
| 698 | serio_register_port(port->serio); | 652 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) |
| 653 | retval = -1; | ||
| 699 | 654 | ||
| 700 | return 0; | 655 | if (irq_registered) |
| 701 | } | 656 | free_irq(I8042_AUX_IRQ, i8042_platform_device); |
| 702 | 657 | ||
| 658 | return retval; | ||
| 659 | } | ||
| 703 | 660 | ||
| 704 | static void i8042_timer_func(unsigned long data) | 661 | static int i8042_controller_check(void) |
| 705 | { | 662 | { |
| 706 | i8042_interrupt(0, NULL, NULL); | 663 | if (i8042_flush() == I8042_BUFFER_SIZE) { |
| 664 | printk(KERN_ERR "i8042.c: No controller found.\n"); | ||
| 665 | return -ENODEV; | ||
| 666 | } | ||
| 667 | |||
| 668 | return 0; | ||
| 707 | } | 669 | } |
| 708 | 670 | ||
| 709 | static int i8042_ctl_test(void) | 671 | static int i8042_controller_selftest(void) |
| 710 | { | 672 | { |
| 711 | unsigned char param; | 673 | unsigned char param; |
| 712 | 674 | ||
| @@ -715,13 +677,13 @@ static int i8042_ctl_test(void) | |||
| 715 | 677 | ||
| 716 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { | 678 | if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { |
| 717 | printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); | 679 | printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); |
| 718 | return -1; | 680 | return -ENODEV; |
| 719 | } | 681 | } |
| 720 | 682 | ||
| 721 | if (param != I8042_RET_CTL_TEST) { | 683 | if (param != I8042_RET_CTL_TEST) { |
| 722 | printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", | 684 | printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", |
| 723 | param, I8042_RET_CTL_TEST); | 685 | param, I8042_RET_CTL_TEST); |
| 724 | return -1; | 686 | return -EIO; |
| 725 | } | 687 | } |
| 726 | 688 | ||
| 727 | return 0; | 689 | return 0; |
| @@ -738,25 +700,12 @@ static int i8042_controller_init(void) | |||
| 738 | unsigned long flags; | 700 | unsigned long flags; |
| 739 | 701 | ||
| 740 | /* | 702 | /* |
| 741 | * Test the i8042. We need to know if it thinks it's working correctly | ||
| 742 | * before doing anything else. | ||
| 743 | */ | ||
| 744 | |||
| 745 | if (i8042_flush() == I8042_BUFFER_SIZE) { | ||
| 746 | printk(KERN_ERR "i8042.c: No controller found.\n"); | ||
| 747 | return -1; | ||
| 748 | } | ||
| 749 | |||
| 750 | if (i8042_ctl_test()) | ||
| 751 | return -1; | ||
| 752 | |||
| 753 | /* | ||
| 754 | * Save the CTR for restoral on unload / reboot. | 703 | * Save the CTR for restoral on unload / reboot. |
| 755 | */ | 704 | */ |
| 756 | 705 | ||
| 757 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { | 706 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { |
| 758 | printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); | 707 | printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); |
| 759 | return -1; | 708 | return -EIO; |
| 760 | } | 709 | } |
| 761 | 710 | ||
| 762 | i8042_initial_ctr = i8042_ctr; | 711 | i8042_initial_ctr = i8042_ctr; |
| @@ -805,7 +754,7 @@ static int i8042_controller_init(void) | |||
| 805 | 754 | ||
| 806 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 755 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { |
| 807 | printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); | 756 | printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n"); |
| 808 | return -1; | 757 | return -EIO; |
| 809 | } | 758 | } |
| 810 | 759 | ||
| 811 | return 0; | 760 | return 0; |
| @@ -813,15 +762,12 @@ static int i8042_controller_init(void) | |||
| 813 | 762 | ||
| 814 | 763 | ||
| 815 | /* | 764 | /* |
| 816 | * Reset the controller. | 765 | * Reset the controller and reset CRT to the original value set by BIOS. |
| 817 | */ | 766 | */ |
| 767 | |||
| 818 | static void i8042_controller_reset(void) | 768 | static void i8042_controller_reset(void) |
| 819 | { | 769 | { |
| 820 | /* | 770 | i8042_flush(); |
| 821 | * Reset the controller if requested. | ||
| 822 | */ | ||
| 823 | |||
| 824 | i8042_ctl_test(); | ||
| 825 | 771 | ||
| 826 | /* | 772 | /* |
| 827 | * Disable MUX mode if present. | 773 | * Disable MUX mode if present. |
| @@ -831,12 +777,16 @@ static void i8042_controller_reset(void) | |||
| 831 | i8042_set_mux_mode(0, NULL); | 777 | i8042_set_mux_mode(0, NULL); |
| 832 | 778 | ||
| 833 | /* | 779 | /* |
| 834 | * Restore the original control register setting. | 780 | * Reset the controller if requested. |
| 835 | */ | 781 | */ |
| 836 | 782 | ||
| 837 | i8042_ctr = i8042_initial_ctr; | 783 | i8042_controller_selftest(); |
| 838 | 784 | ||
| 839 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) | 785 | /* |
| 786 | * Restore the original control register setting. | ||
| 787 | */ | ||
| 788 | |||
| 789 | if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR)) | ||
| 840 | printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); | 790 | printk(KERN_WARNING "i8042.c: Can't restore CTR.\n"); |
| 841 | } | 791 | } |
| 842 | 792 | ||
| @@ -850,14 +800,12 @@ static void i8042_controller_cleanup(void) | |||
| 850 | { | 800 | { |
| 851 | int i; | 801 | int i; |
| 852 | 802 | ||
| 853 | i8042_flush(); | ||
| 854 | |||
| 855 | /* | 803 | /* |
| 856 | * Reset anything that is connected to the ports. | 804 | * Reset anything that is connected to the ports. |
| 857 | */ | 805 | */ |
| 858 | 806 | ||
| 859 | for (i = 0; i < I8042_NUM_PORTS; i++) | 807 | for (i = 0; i < I8042_NUM_PORTS; i++) |
| 860 | if (i8042_ports[i].exists) | 808 | if (i8042_ports[i].serio) |
| 861 | serio_cleanup(i8042_ports[i].serio); | 809 | serio_cleanup(i8042_ports[i].serio); |
| 862 | 810 | ||
| 863 | i8042_controller_reset(); | 811 | i8042_controller_reset(); |
| @@ -913,8 +861,7 @@ static long i8042_panic_blink(long count) | |||
| 913 | 861 | ||
| 914 | static int i8042_suspend(struct platform_device *dev, pm_message_t state) | 862 | static int i8042_suspend(struct platform_device *dev, pm_message_t state) |
| 915 | { | 863 | { |
| 916 | del_timer_sync(&i8042_timer); | 864 | i8042_controller_cleanup(); |
| 917 | i8042_controller_reset(); | ||
| 918 | 865 | ||
| 919 | return 0; | 866 | return 0; |
| 920 | } | 867 | } |
| @@ -926,33 +873,39 @@ static int i8042_suspend(struct platform_device *dev, pm_message_t state) | |||
| 926 | 873 | ||
| 927 | static int i8042_resume(struct platform_device *dev) | 874 | static int i8042_resume(struct platform_device *dev) |
| 928 | { | 875 | { |
| 929 | int i; | 876 | int error; |
| 930 | 877 | ||
| 931 | if (i8042_ctl_test()) | 878 | error = i8042_controller_check(); |
| 932 | return -1; | 879 | if (error) |
| 880 | return error; | ||
| 933 | 881 | ||
| 934 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 882 | error = i8042_controller_selftest(); |
| 935 | printk(KERN_ERR "i8042: Can't write CTR\n"); | 883 | if (error) |
| 936 | return -1; | 884 | return error; |
| 937 | } | ||
| 938 | |||
| 939 | if (i8042_mux_present) | ||
| 940 | if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) | ||
| 941 | printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n"); | ||
| 942 | 885 | ||
| 943 | /* | 886 | /* |
| 944 | * Activate all ports. | 887 | * Restore pre-resume CTR value and disable all ports |
| 945 | */ | 888 | */ |
| 946 | 889 | ||
| 947 | for (i = 0; i < I8042_NUM_PORTS; i++) | 890 | i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS; |
| 948 | i8042_activate_port(&i8042_ports[i]); | 891 | i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT); |
| 892 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | ||
| 893 | printk(KERN_ERR "i8042: Can't write CTR to resume\n"); | ||
| 894 | return -EIO; | ||
| 895 | } | ||
| 949 | 896 | ||
| 950 | /* | 897 | if (i8042_mux_present) { |
| 951 | * Restart timer (for polling "stuck" data) | 898 | if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports()) |
| 952 | */ | 899 | printk(KERN_WARNING |
| 953 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | 900 | "i8042: failed to resume active multiplexor, " |
| 901 | "mouse won't work.\n"); | ||
| 902 | } else if (i8042_ports[I8042_AUX_PORT_NO].serio) | ||
| 903 | i8042_enable_aux_port(); | ||
| 954 | 904 | ||
| 955 | panic_blink = i8042_panic_blink; | 905 | if (i8042_ports[I8042_KBD_PORT_NO].serio) |
| 906 | i8042_enable_kbd_port(); | ||
| 907 | |||
| 908 | i8042_interrupt(0, NULL, NULL); | ||
| 956 | 909 | ||
| 957 | return 0; | 910 | return 0; |
| 958 | } | 911 | } |
| @@ -978,24 +931,24 @@ static int __devinit i8042_create_kbd_port(void) | |||
| 978 | 931 | ||
| 979 | serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; | 932 | serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL; |
| 980 | serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; | 933 | serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write; |
| 981 | serio->open = i8042_open; | ||
| 982 | serio->close = i8042_close; | ||
| 983 | serio->start = i8042_start; | 934 | serio->start = i8042_start; |
| 984 | serio->stop = i8042_stop; | 935 | serio->stop = i8042_stop; |
| 985 | serio->port_data = port; | 936 | serio->port_data = port; |
| 986 | serio->dev.parent = &i8042_platform_device->dev; | 937 | serio->dev.parent = &i8042_platform_device->dev; |
| 987 | strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); | 938 | strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); |
| 988 | strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); | 939 | strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); |
| 989 | 940 | ||
| 990 | port->serio = serio; | 941 | port->serio = serio; |
| 942 | port->irq = I8042_KBD_IRQ; | ||
| 991 | 943 | ||
| 992 | return i8042_port_register(port); | 944 | return 0; |
| 993 | } | 945 | } |
| 994 | 946 | ||
| 995 | static int __devinit i8042_create_aux_port(void) | 947 | static int __devinit i8042_create_aux_port(int idx) |
| 996 | { | 948 | { |
| 997 | struct serio *serio; | 949 | struct serio *serio; |
| 998 | struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO]; | 950 | int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; |
| 951 | struct i8042_port *port = &i8042_ports[port_no]; | ||
| 999 | 952 | ||
| 1000 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | 953 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); |
| 1001 | if (!serio) | 954 | if (!serio) |
| @@ -1003,111 +956,191 @@ static int __devinit i8042_create_aux_port(void) | |||
| 1003 | 956 | ||
| 1004 | serio->id.type = SERIO_8042; | 957 | serio->id.type = SERIO_8042; |
| 1005 | serio->write = i8042_aux_write; | 958 | serio->write = i8042_aux_write; |
| 1006 | serio->open = i8042_open; | ||
| 1007 | serio->close = i8042_close; | ||
| 1008 | serio->start = i8042_start; | 959 | serio->start = i8042_start; |
| 1009 | serio->stop = i8042_stop; | 960 | serio->stop = i8042_stop; |
| 1010 | serio->port_data = port; | 961 | serio->port_data = port; |
| 1011 | serio->dev.parent = &i8042_platform_device->dev; | 962 | serio->dev.parent = &i8042_platform_device->dev; |
| 1012 | strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); | 963 | if (idx < 0) { |
| 1013 | strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); | 964 | strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name)); |
| 965 | strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); | ||
| 966 | } else { | ||
| 967 | snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx); | ||
| 968 | snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1); | ||
| 969 | } | ||
| 1014 | 970 | ||
| 1015 | port->serio = serio; | 971 | port->serio = serio; |
| 972 | port->mux = idx; | ||
| 973 | port->irq = I8042_AUX_IRQ; | ||
| 1016 | 974 | ||
| 1017 | return i8042_port_register(port); | 975 | return 0; |
| 1018 | } | 976 | } |
| 1019 | 977 | ||
| 1020 | static int __devinit i8042_create_mux_port(int index) | 978 | static void __devinit i8042_free_kbd_port(void) |
| 1021 | { | 979 | { |
| 1022 | struct serio *serio; | 980 | kfree(i8042_ports[I8042_KBD_PORT_NO].serio); |
| 1023 | struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index]; | 981 | i8042_ports[I8042_KBD_PORT_NO].serio = NULL; |
| 982 | } | ||
| 1024 | 983 | ||
| 1025 | serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | 984 | static void __devinit i8042_free_aux_ports(void) |
| 1026 | if (!serio) | 985 | { |
| 1027 | return -ENOMEM; | 986 | int i; |
| 1028 | 987 | ||
| 1029 | serio->id.type = SERIO_8042; | 988 | for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) { |
| 1030 | serio->write = i8042_aux_write; | 989 | kfree(i8042_ports[i].serio); |
| 1031 | serio->open = i8042_open; | 990 | i8042_ports[i].serio = NULL; |
| 1032 | serio->close = i8042_close; | 991 | } |
| 1033 | serio->start = i8042_start; | 992 | } |
| 1034 | serio->stop = i8042_stop; | ||
| 1035 | serio->port_data = port; | ||
| 1036 | serio->dev.parent = &i8042_platform_device->dev; | ||
| 1037 | snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); | ||
| 1038 | snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); | ||
| 1039 | 993 | ||
| 1040 | *port = i8042_ports[I8042_AUX_PORT_NO]; | 994 | static void __devinit i8042_register_ports(void) |
| 1041 | port->exists = 0; | 995 | { |
| 1042 | snprintf(port->name, sizeof(port->name), "AUX%d", index); | 996 | int i; |
| 1043 | port->mux = index; | ||
| 1044 | port->serio = serio; | ||
| 1045 | 997 | ||
| 1046 | return i8042_port_register(port); | 998 | for (i = 0; i < I8042_NUM_PORTS; i++) { |
| 999 | if (i8042_ports[i].serio) { | ||
| 1000 | printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n", | ||
| 1001 | i8042_ports[i].serio->name, | ||
| 1002 | (unsigned long) I8042_DATA_REG, | ||
| 1003 | (unsigned long) I8042_COMMAND_REG, | ||
| 1004 | i8042_ports[i].irq); | ||
| 1005 | serio_register_port(i8042_ports[i].serio); | ||
| 1006 | } | ||
| 1007 | } | ||
| 1047 | } | 1008 | } |
| 1048 | 1009 | ||
| 1049 | static int __devinit i8042_probe(struct platform_device *dev) | 1010 | static void __devinit i8042_unregister_ports(void) |
| 1050 | { | 1011 | { |
| 1051 | int i, have_ports = 0; | 1012 | int i; |
| 1052 | int err; | ||
| 1053 | 1013 | ||
| 1054 | init_timer(&i8042_timer); | 1014 | for (i = 0; i < I8042_NUM_PORTS; i++) { |
| 1055 | i8042_timer.function = i8042_timer_func; | 1015 | if (i8042_ports[i].serio) { |
| 1016 | serio_unregister_port(i8042_ports[i].serio); | ||
| 1017 | i8042_ports[i].serio = NULL; | ||
| 1018 | } | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | static void i8042_free_irqs(void) | ||
| 1023 | { | ||
| 1024 | if (i8042_aux_irq_registered) | ||
| 1025 | free_irq(I8042_AUX_IRQ, i8042_platform_device); | ||
| 1026 | if (i8042_kbd_irq_registered) | ||
| 1027 | free_irq(I8042_KBD_IRQ, i8042_platform_device); | ||
| 1028 | |||
| 1029 | i8042_aux_irq_registered = i8042_kbd_irq_registered = 0; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | static int __devinit i8042_setup_aux(void) | ||
| 1033 | { | ||
| 1034 | int (*aux_enable)(void); | ||
| 1035 | int error; | ||
| 1036 | int i; | ||
| 1056 | 1037 | ||
| 1057 | if (i8042_controller_init()) | 1038 | if (i8042_check_aux()) |
| 1058 | return -ENODEV; | 1039 | return -ENODEV; |
| 1059 | 1040 | ||
| 1060 | if (!i8042_noaux && !i8042_check_aux()) { | 1041 | if (i8042_nomux || i8042_check_mux()) { |
| 1061 | if (!i8042_nomux && !i8042_check_mux()) { | 1042 | error = i8042_create_aux_port(-1); |
| 1062 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { | 1043 | if (error) |
| 1063 | err = i8042_create_mux_port(i); | 1044 | goto err_free_ports; |
| 1064 | if (err) | 1045 | aux_enable = i8042_enable_aux_port; |
| 1065 | goto err_unregister_ports; | 1046 | } else { |
| 1066 | } | 1047 | for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { |
| 1067 | } else { | 1048 | error = i8042_create_aux_port(i); |
| 1068 | err = i8042_create_aux_port(); | 1049 | if (error) |
| 1069 | if (err) | 1050 | goto err_free_ports; |
| 1070 | goto err_unregister_ports; | ||
| 1071 | } | 1051 | } |
| 1072 | have_ports = 1; | 1052 | aux_enable = i8042_enable_mux_ports; |
| 1073 | } | 1053 | } |
| 1074 | 1054 | ||
| 1075 | if (!i8042_nokbd) { | 1055 | error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, |
| 1076 | err = i8042_create_kbd_port(); | 1056 | "i8042", i8042_platform_device); |
| 1077 | if (err) | 1057 | if (error) |
| 1078 | goto err_unregister_ports; | 1058 | goto err_free_ports; |
| 1079 | have_ports = 1; | ||
| 1080 | } | ||
| 1081 | 1059 | ||
| 1082 | if (!have_ports) { | 1060 | if (aux_enable()) |
| 1083 | err = -ENODEV; | 1061 | goto err_free_irq; |
| 1084 | goto err_controller_cleanup; | ||
| 1085 | } | ||
| 1086 | 1062 | ||
| 1087 | mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); | 1063 | i8042_aux_irq_registered = 1; |
| 1088 | return 0; | 1064 | return 0; |
| 1089 | 1065 | ||
| 1090 | err_unregister_ports: | 1066 | err_free_irq: |
| 1091 | for (i = 0; i < I8042_NUM_PORTS; i++) | 1067 | free_irq(I8042_AUX_IRQ, i8042_platform_device); |
| 1092 | if (i8042_ports[i].serio) | 1068 | err_free_ports: |
| 1093 | serio_unregister_port(i8042_ports[i].serio); | 1069 | i8042_free_aux_ports(); |
| 1094 | err_controller_cleanup: | 1070 | return error; |
| 1095 | i8042_controller_cleanup(); | 1071 | } |
| 1096 | 1072 | ||
| 1097 | return err; | 1073 | static int __devinit i8042_setup_kbd(void) |
| 1074 | { | ||
| 1075 | int error; | ||
| 1076 | |||
| 1077 | error = i8042_create_kbd_port(); | ||
| 1078 | if (error) | ||
| 1079 | return error; | ||
| 1080 | |||
| 1081 | error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, | ||
| 1082 | "i8042", i8042_platform_device); | ||
| 1083 | if (error) | ||
| 1084 | goto err_free_port; | ||
| 1085 | |||
| 1086 | error = i8042_enable_kbd_port(); | ||
| 1087 | if (error) | ||
| 1088 | goto err_free_irq; | ||
| 1089 | |||
| 1090 | i8042_kbd_irq_registered = 1; | ||
| 1091 | return 0; | ||
| 1092 | |||
| 1093 | err_free_irq: | ||
| 1094 | free_irq(I8042_KBD_IRQ, i8042_platform_device); | ||
| 1095 | err_free_port: | ||
| 1096 | i8042_free_kbd_port(); | ||
| 1097 | return error; | ||
| 1098 | } | 1098 | } |
| 1099 | 1099 | ||
| 1100 | static int __devexit i8042_remove(struct platform_device *dev) | 1100 | static int __devinit i8042_probe(struct platform_device *dev) |
| 1101 | { | 1101 | { |
| 1102 | int i; | 1102 | int error; |
| 1103 | 1103 | ||
| 1104 | i8042_controller_cleanup(); | 1104 | error = i8042_controller_selftest(); |
| 1105 | if (error) | ||
| 1106 | return error; | ||
| 1105 | 1107 | ||
| 1106 | for (i = 0; i < I8042_NUM_PORTS; i++) | 1108 | error = i8042_controller_init(); |
| 1107 | if (i8042_ports[i].exists) | 1109 | if (error) |
| 1108 | serio_unregister_port(i8042_ports[i].serio); | 1110 | return error; |
| 1111 | |||
| 1112 | if (!i8042_noaux) { | ||
| 1113 | error = i8042_setup_aux(); | ||
| 1114 | if (error && error != -ENODEV && error != -EBUSY) | ||
| 1115 | goto out_fail; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | if (!i8042_nokbd) { | ||
| 1119 | error = i8042_setup_kbd(); | ||
| 1120 | if (error) | ||
| 1121 | goto out_fail; | ||
| 1122 | } | ||
| 1109 | 1123 | ||
| 1110 | del_timer_sync(&i8042_timer); | 1124 | /* |
| 1125 | * Ok, everything is ready, let's register all serio ports | ||
| 1126 | */ | ||
| 1127 | i8042_register_ports(); | ||
| 1128 | |||
| 1129 | return 0; | ||
| 1130 | |||
| 1131 | out_fail: | ||
| 1132 | i8042_free_aux_ports(); /* in case KBD failed but AUX not */ | ||
| 1133 | i8042_free_irqs(); | ||
| 1134 | i8042_controller_reset(); | ||
| 1135 | |||
| 1136 | return error; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static int __devexit i8042_remove(struct platform_device *dev) | ||
| 1140 | { | ||
| 1141 | i8042_unregister_ports(); | ||
| 1142 | i8042_free_irqs(); | ||
| 1143 | i8042_controller_reset(); | ||
| 1111 | 1144 | ||
| 1112 | return 0; | 1145 | return 0; |
| 1113 | } | 1146 | } |
| @@ -1134,8 +1167,9 @@ static int __init i8042_init(void) | |||
| 1134 | if (err) | 1167 | if (err) |
| 1135 | return err; | 1168 | return err; |
| 1136 | 1169 | ||
| 1137 | i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ; | 1170 | err = i8042_controller_check(); |
| 1138 | i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ; | 1171 | if (err) |
| 1172 | goto err_platform_exit; | ||
| 1139 | 1173 | ||
| 1140 | err = platform_driver_register(&i8042_driver); | 1174 | err = platform_driver_register(&i8042_driver); |
| 1141 | if (err) | 1175 | if (err) |
| @@ -1151,6 +1185,8 @@ static int __init i8042_init(void) | |||
| 1151 | if (err) | 1185 | if (err) |
| 1152 | goto err_free_device; | 1186 | goto err_free_device; |
| 1153 | 1187 | ||
| 1188 | panic_blink = i8042_panic_blink; | ||
| 1189 | |||
| 1154 | return 0; | 1190 | return 0; |
| 1155 | 1191 | ||
| 1156 | err_free_device: | 1192 | err_free_device: |
| @@ -1167,7 +1203,6 @@ static void __exit i8042_exit(void) | |||
| 1167 | { | 1203 | { |
| 1168 | platform_device_unregister(i8042_platform_device); | 1204 | platform_device_unregister(i8042_platform_device); |
| 1169 | platform_driver_unregister(&i8042_driver); | 1205 | platform_driver_unregister(&i8042_driver); |
| 1170 | |||
| 1171 | i8042_platform_exit(); | 1206 | i8042_platform_exit(); |
| 1172 | 1207 | ||
| 1173 | panic_blink = NULL; | 1208 | panic_blink = NULL; |
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index af526ab9ec04..b3eb7a72d961 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h | |||
| @@ -37,15 +37,6 @@ | |||
| 37 | #define I8042_CTL_TIMEOUT 10000 | 37 | #define I8042_CTL_TIMEOUT 10000 |
| 38 | 38 | ||
| 39 | /* | 39 | /* |
| 40 | * When the device isn't opened and it's interrupts aren't used, we poll it at | ||
| 41 | * regular intervals to see if any characters arrived. If yes, we can start | ||
| 42 | * probing for any mouse / keyboard connected. This is the period of the | ||
| 43 | * polling. | ||
| 44 | */ | ||
| 45 | |||
| 46 | #define I8042_POLL_PERIOD HZ/20 | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Status register bits. | 40 | * Status register bits. |
| 50 | */ | 41 | */ |
| 51 | 42 | ||
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index ed202f2f251a..dcb16b5cbec0 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c | |||
| @@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); | |||
| 27 | MODULE_DESCRIPTION("PS/2 driver library"); | 27 | MODULE_DESCRIPTION("PS/2 driver library"); |
| 28 | MODULE_LICENSE("GPL"); | 28 | MODULE_LICENSE("GPL"); |
| 29 | 29 | ||
| 30 | EXPORT_SYMBOL(ps2_init); | ||
| 31 | EXPORT_SYMBOL(ps2_sendbyte); | ||
| 32 | EXPORT_SYMBOL(ps2_drain); | ||
| 33 | EXPORT_SYMBOL(ps2_command); | ||
| 34 | EXPORT_SYMBOL(ps2_schedule_command); | ||
| 35 | EXPORT_SYMBOL(ps2_handle_ack); | ||
| 36 | EXPORT_SYMBOL(ps2_handle_response); | ||
| 37 | EXPORT_SYMBOL(ps2_cmd_aborted); | ||
| 38 | |||
| 39 | /* Work structure to schedule execution of a command */ | 30 | /* Work structure to schedule execution of a command */ |
| 40 | struct ps2work { | 31 | struct ps2work { |
| 41 | struct work_struct work; | 32 | struct work_struct work; |
| @@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) | |||
| 71 | 62 | ||
| 72 | return -ps2dev->nak; | 63 | return -ps2dev->nak; |
| 73 | } | 64 | } |
| 65 | EXPORT_SYMBOL(ps2_sendbyte); | ||
| 74 | 66 | ||
| 75 | /* | 67 | /* |
| 76 | * ps2_drain() waits for device to transmit requested number of bytes | 68 | * ps2_drain() waits for device to transmit requested number of bytes |
| @@ -96,15 +88,16 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) | |||
| 96 | msecs_to_jiffies(timeout)); | 88 | msecs_to_jiffies(timeout)); |
| 97 | mutex_unlock(&ps2dev->cmd_mutex); | 89 | mutex_unlock(&ps2dev->cmd_mutex); |
| 98 | } | 90 | } |
| 91 | EXPORT_SYMBOL(ps2_drain); | ||
| 99 | 92 | ||
| 100 | /* | 93 | /* |
| 101 | * ps2_is_keyboard_id() checks received ID byte against the list of | 94 | * ps2_is_keyboard_id() checks received ID byte against the list of |
| 102 | * known keyboard IDs. | 95 | * known keyboard IDs. |
| 103 | */ | 96 | */ |
| 104 | 97 | ||
| 105 | static inline int ps2_is_keyboard_id(char id_byte) | 98 | int ps2_is_keyboard_id(char id_byte) |
| 106 | { | 99 | { |
| 107 | static char keyboard_ids[] = { | 100 | const static char keyboard_ids[] = { |
| 108 | 0xab, /* Regular keyboards */ | 101 | 0xab, /* Regular keyboards */ |
| 109 | 0xac, /* NCD Sun keyboard */ | 102 | 0xac, /* NCD Sun keyboard */ |
| 110 | 0x2b, /* Trust keyboard, translated */ | 103 | 0x2b, /* Trust keyboard, translated */ |
| @@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(char id_byte) | |||
| 115 | 108 | ||
| 116 | return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; | 109 | return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; |
| 117 | } | 110 | } |
| 111 | EXPORT_SYMBOL(ps2_is_keyboard_id); | ||
| 118 | 112 | ||
| 119 | /* | 113 | /* |
| 120 | * ps2_adjust_timeout() is called after receiving 1st byte of command | 114 | * ps2_adjust_timeout() is called after receiving 1st byte of command |
| @@ -139,6 +133,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) | |||
| 139 | 133 | ||
| 140 | case PS2_CMD_GETID: | 134 | case PS2_CMD_GETID: |
| 141 | /* | 135 | /* |
| 136 | * Microsoft Natural Elite keyboard responds to | ||
| 137 | * the GET ID command as it were a mouse, with | ||
| 138 | * a single byte. Fail the command so atkbd will | ||
| 139 | * use alternative probe to detect it. | ||
| 140 | */ | ||
| 141 | if (ps2dev->cmdbuf[1] == 0xaa) { | ||
| 142 | serio_pause_rx(ps2dev->serio); | ||
| 143 | ps2dev->flags = 0; | ||
| 144 | serio_continue_rx(ps2dev->serio); | ||
| 145 | timeout = 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 142 | * If device behind the port is not a keyboard there | 149 | * If device behind the port is not a keyboard there |
| 143 | * won't be 2nd byte of ID response. | 150 | * won't be 2nd byte of ID response. |
| 144 | */ | 151 | */ |
| @@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) | |||
| 237 | mutex_unlock(&ps2dev->cmd_mutex); | 244 | mutex_unlock(&ps2dev->cmd_mutex); |
| 238 | return rc; | 245 | return rc; |
| 239 | } | 246 | } |
| 247 | EXPORT_SYMBOL(ps2_command); | ||
| 240 | 248 | ||
| 241 | /* | 249 | /* |
| 242 | * ps2_execute_scheduled_command() sends a command, previously scheduled by | 250 | * ps2_execute_scheduled_command() sends a command, previously scheduled by |
| @@ -279,6 +287,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman | |||
| 279 | 287 | ||
| 280 | return 0; | 288 | return 0; |
| 281 | } | 289 | } |
| 290 | EXPORT_SYMBOL(ps2_schedule_command); | ||
| 282 | 291 | ||
| 283 | /* | 292 | /* |
| 284 | * ps2_init() initializes ps2dev structure | 293 | * ps2_init() initializes ps2dev structure |
| @@ -290,6 +299,7 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio) | |||
| 290 | init_waitqueue_head(&ps2dev->wait); | 299 | init_waitqueue_head(&ps2dev->wait); |
| 291 | ps2dev->serio = serio; | 300 | ps2dev->serio = serio; |
| 292 | } | 301 | } |
| 302 | EXPORT_SYMBOL(ps2_init); | ||
| 293 | 303 | ||
| 294 | /* | 304 | /* |
| 295 | * ps2_handle_ack() is supposed to be used in interrupt handler | 305 | * ps2_handle_ack() is supposed to be used in interrupt handler |
| @@ -335,6 +345,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) | |||
| 335 | 345 | ||
| 336 | return 1; | 346 | return 1; |
| 337 | } | 347 | } |
| 348 | EXPORT_SYMBOL(ps2_handle_ack); | ||
| 338 | 349 | ||
| 339 | /* | 350 | /* |
| 340 | * ps2_handle_response() is supposed to be used in interrupt handler | 351 | * ps2_handle_response() is supposed to be used in interrupt handler |
| @@ -360,6 +371,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) | |||
| 360 | 371 | ||
| 361 | return 1; | 372 | return 1; |
| 362 | } | 373 | } |
| 374 | EXPORT_SYMBOL(ps2_handle_response); | ||
| 363 | 375 | ||
| 364 | void ps2_cmd_aborted(struct ps2dev *ps2dev) | 376 | void ps2_cmd_aborted(struct ps2dev *ps2dev) |
| 365 | { | 377 | { |
| @@ -371,4 +383,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev) | |||
| 371 | 383 | ||
| 372 | ps2dev->flags = 0; | 384 | ps2dev->flags = 0; |
| 373 | } | 385 | } |
| 374 | 386 | EXPORT_SYMBOL(ps2_cmd_aborted); | |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b1b14f8d4dd6..9418bbe47072 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
| @@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600 | |||
| 108 | To compile this driver as a module, choose M here: the | 108 | To compile this driver as a module, choose M here: the |
| 109 | module will be called hp680_ts_input. | 109 | module will be called hp680_ts_input. |
| 110 | 110 | ||
| 111 | config TOUCHSCREEN_PENMOUNT | ||
| 112 | tristate "Penmount serial touchscreen" | ||
| 113 | select SERIO | ||
| 114 | help | ||
| 115 | Say Y here if you have a Penmount serial touchscreen connected to | ||
| 116 | your system. | ||
| 117 | |||
| 118 | If unsure, say N. | ||
| 119 | |||
| 120 | To compile this driver as a module, choose M here: the | ||
| 121 | module will be called penmount. | ||
| 122 | |||
| 123 | config TOUCHSCREEN_TOUCHRIGHT | ||
| 124 | tristate "Touchright serial touchscreen" | ||
| 125 | select SERIO | ||
| 126 | help | ||
| 127 | Say Y here if you have a Touchright serial touchscreen connected to | ||
| 128 | your system. | ||
| 129 | |||
| 130 | If unsure, say N. | ||
| 131 | |||
| 132 | To compile this driver as a module, choose M here: the | ||
| 133 | module will be called touchright. | ||
| 134 | |||
| 135 | config TOUCHSCREEN_TOUCHWIN | ||
| 136 | tristate "Touchwin serial touchscreen" | ||
| 137 | select SERIO | ||
| 138 | help | ||
| 139 | Say Y here if you have a Touchwin serial touchscreen connected to | ||
| 140 | your system. | ||
| 141 | |||
| 142 | If unsure, say N. | ||
| 143 | |||
| 144 | To compile this driver as a module, choose M here: the | ||
| 145 | module will be called touchwin. | ||
| 146 | |||
| 111 | endif | 147 | endif |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5e5557c43121..1abb8f10d608 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
| @@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | |||
| 12 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o | 12 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o |
| 13 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o | 13 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o |
| 14 | obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o | 14 | obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o |
| 15 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o | ||
| 16 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | ||
| 17 | obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o | ||
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index c86a2eb310fd..ab565335ee44 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/input.h> | 23 | #include <linux/input.h> |
| 24 | #include <linux/serio.h> | 24 | #include <linux/serio.h> |
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/ctype.h> | ||
| 26 | 27 | ||
| 27 | #define DRIVER_DESC "Elo serial touchscreen driver" | 28 | #define DRIVER_DESC "Elo serial touchscreen driver" |
| 28 | 29 | ||
| @@ -34,7 +35,19 @@ MODULE_LICENSE("GPL"); | |||
| 34 | * Definitions & global arrays. | 35 | * Definitions & global arrays. |
| 35 | */ | 36 | */ |
| 36 | 37 | ||
| 37 | #define ELO_MAX_LENGTH 10 | 38 | #define ELO_MAX_LENGTH 10 |
| 39 | |||
| 40 | #define ELO10_PACKET_LEN 8 | ||
| 41 | #define ELO10_TOUCH 0x03 | ||
| 42 | #define ELO10_PRESSURE 0x80 | ||
| 43 | |||
| 44 | #define ELO10_LEAD_BYTE 'U' | ||
| 45 | |||
| 46 | #define ELO10_ID_CMD 'i' | ||
| 47 | |||
| 48 | #define ELO10_TOUCH_PACKET 'T' | ||
| 49 | #define ELO10_ACK_PACKET 'A' | ||
| 50 | #define ELI10_ID_PACKET 'I' | ||
| 38 | 51 | ||
| 39 | /* | 52 | /* |
| 40 | * Per-touchscreen data. | 53 | * Per-touchscreen data. |
| @@ -43,51 +56,67 @@ MODULE_LICENSE("GPL"); | |||
| 43 | struct elo { | 56 | struct elo { |
| 44 | struct input_dev *dev; | 57 | struct input_dev *dev; |
| 45 | struct serio *serio; | 58 | struct serio *serio; |
| 59 | struct mutex cmd_mutex; | ||
| 60 | struct completion cmd_done; | ||
| 46 | int id; | 61 | int id; |
| 47 | int idx; | 62 | int idx; |
| 63 | unsigned char expected_packet; | ||
| 48 | unsigned char csum; | 64 | unsigned char csum; |
| 49 | unsigned char data[ELO_MAX_LENGTH]; | 65 | unsigned char data[ELO_MAX_LENGTH]; |
| 66 | unsigned char response[ELO10_PACKET_LEN]; | ||
| 50 | char phys[32]; | 67 | char phys[32]; |
| 51 | }; | 68 | }; |
| 52 | 69 | ||
| 53 | static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) | 70 | static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_regs *regs) |
| 54 | { | 71 | { |
| 55 | struct input_dev *dev = elo->dev; | 72 | struct input_dev *dev = elo->dev; |
| 56 | 73 | ||
| 57 | elo->csum += elo->data[elo->idx] = data; | 74 | elo->data[elo->idx] = data; |
| 58 | |||
| 59 | switch (elo->idx++) { | 75 | switch (elo->idx++) { |
| 60 | |||
| 61 | case 0: | 76 | case 0: |
| 62 | if (data != 'U') { | 77 | elo->csum = 0xaa; |
| 78 | if (data != ELO10_LEAD_BYTE) { | ||
| 79 | pr_debug("elo: unsynchronized data: 0x%02x\n", data); | ||
| 63 | elo->idx = 0; | 80 | elo->idx = 0; |
| 64 | elo->csum = 0; | ||
| 65 | } | ||
| 66 | break; | ||
| 67 | |||
| 68 | case 1: | ||
| 69 | if (data != 'T') { | ||
| 70 | elo->idx = 0; | ||
| 71 | elo->csum = 0; | ||
| 72 | } | 81 | } |
| 73 | break; | 82 | break; |
| 74 | 83 | ||
| 75 | case 9: | 84 | case 9: |
| 76 | if (elo->csum) { | 85 | elo->idx = 0; |
| 86 | if (data != elo->csum) { | ||
| 87 | pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n", | ||
| 88 | data, elo->csum); | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | if (elo->data[1] != elo->expected_packet) { | ||
| 92 | if (elo->data[1] != ELO10_TOUCH_PACKET) | ||
| 93 | pr_debug("elo: unexpected packet: 0x%02x\n", | ||
| 94 | elo->data[1]); | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) { | ||
| 77 | input_regs(dev, regs); | 98 | input_regs(dev, regs); |
| 78 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); | 99 | input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); |
| 79 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); | 100 | input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); |
| 80 | input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); | 101 | if (elo->data[2] & ELO10_PRESSURE) |
| 81 | input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); | 102 | input_report_abs(dev, ABS_PRESSURE, |
| 103 | (elo->data[8] << 8) | elo->data[7]); | ||
| 104 | input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH); | ||
| 82 | input_sync(dev); | 105 | input_sync(dev); |
| 106 | } else if (elo->data[1] == ELO10_ACK_PACKET) { | ||
| 107 | if (elo->data[2] == '0') | ||
| 108 | elo->expected_packet = ELO10_TOUCH_PACKET; | ||
| 109 | complete(&elo->cmd_done); | ||
| 110 | } else { | ||
| 111 | memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN); | ||
| 112 | elo->expected_packet = ELO10_ACK_PACKET; | ||
| 83 | } | 113 | } |
| 84 | elo->idx = 0; | ||
| 85 | elo->csum = 0; | ||
| 86 | break; | 114 | break; |
| 87 | } | 115 | } |
| 116 | elo->csum += data; | ||
| 88 | } | 117 | } |
| 89 | 118 | ||
| 90 | static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) | 119 | static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_regs *regs) |
| 91 | { | 120 | { |
| 92 | struct input_dev *dev = elo->dev; | 121 | struct input_dev *dev = elo->dev; |
| 93 | 122 | ||
| @@ -135,7 +164,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re | |||
| 135 | } | 164 | } |
| 136 | } | 165 | } |
| 137 | 166 | ||
| 138 | static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) | 167 | static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_regs *regs) |
| 139 | { | 168 | { |
| 140 | struct input_dev *dev = elo->dev; | 169 | struct input_dev *dev = elo->dev; |
| 141 | 170 | ||
| @@ -161,7 +190,7 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re | |||
| 161 | static irqreturn_t elo_interrupt(struct serio *serio, | 190 | static irqreturn_t elo_interrupt(struct serio *serio, |
| 162 | unsigned char data, unsigned int flags, struct pt_regs *regs) | 191 | unsigned char data, unsigned int flags, struct pt_regs *regs) |
| 163 | { | 192 | { |
| 164 | struct elo* elo = serio_get_drvdata(serio); | 193 | struct elo *elo = serio_get_drvdata(serio); |
| 165 | 194 | ||
| 166 | switch(elo->id) { | 195 | switch(elo->id) { |
| 167 | case 0: | 196 | case 0: |
| @@ -181,17 +210,81 @@ static irqreturn_t elo_interrupt(struct serio *serio, | |||
| 181 | return IRQ_HANDLED; | 210 | return IRQ_HANDLED; |
| 182 | } | 211 | } |
| 183 | 212 | ||
| 213 | static int elo_command_10(struct elo *elo, unsigned char *packet) | ||
| 214 | { | ||
| 215 | int rc = -1; | ||
| 216 | int i; | ||
| 217 | unsigned char csum = 0xaa + ELO10_LEAD_BYTE; | ||
| 218 | |||
| 219 | mutex_lock(&elo->cmd_mutex); | ||
| 220 | |||
| 221 | serio_pause_rx(elo->serio); | ||
| 222 | elo->expected_packet = toupper(packet[0]); | ||
| 223 | init_completion(&elo->cmd_done); | ||
| 224 | serio_continue_rx(elo->serio); | ||
| 225 | |||
| 226 | if (serio_write(elo->serio, ELO10_LEAD_BYTE)) | ||
| 227 | goto out; | ||
| 228 | |||
| 229 | for (i = 0; i < ELO10_PACKET_LEN; i++) { | ||
| 230 | csum += packet[i]; | ||
| 231 | if (serio_write(elo->serio, packet[i])) | ||
| 232 | goto out; | ||
| 233 | } | ||
| 234 | |||
| 235 | if (serio_write(elo->serio, csum)) | ||
| 236 | goto out; | ||
| 237 | |||
| 238 | wait_for_completion_timeout(&elo->cmd_done, HZ); | ||
| 239 | |||
| 240 | if (elo->expected_packet == ELO10_TOUCH_PACKET) { | ||
| 241 | /* We are back in reporting mode, the command was ACKed */ | ||
| 242 | memcpy(packet, elo->response, ELO10_PACKET_LEN); | ||
| 243 | rc = 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | out: | ||
| 247 | mutex_unlock(&elo->cmd_mutex); | ||
| 248 | return rc; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int elo_setup_10(struct elo *elo) | ||
| 252 | { | ||
| 253 | static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" }; | ||
| 254 | struct input_dev *dev = elo->dev; | ||
| 255 | unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD }; | ||
| 256 | |||
| 257 | if (elo_command_10(elo, packet)) | ||
| 258 | return -1; | ||
| 259 | |||
| 260 | dev->id.version = (packet[5] << 8) | packet[4]; | ||
| 261 | |||
| 262 | input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0); | ||
| 263 | input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0); | ||
| 264 | if (packet[3] & ELO10_PRESSURE) | ||
| 265 | input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); | ||
| 266 | |||
| 267 | printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, " | ||
| 268 | "features: %x02x, controller: 0x%02x\n", | ||
| 269 | elo_types[(packet[1] -'0') & 0x03], | ||
| 270 | packet[5], packet[4], packet[3], packet[7]); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 184 | /* | 275 | /* |
| 185 | * elo_disconnect() is the opposite of elo_connect() | 276 | * elo_disconnect() is the opposite of elo_connect() |
| 186 | */ | 277 | */ |
| 187 | 278 | ||
| 188 | static void elo_disconnect(struct serio *serio) | 279 | static void elo_disconnect(struct serio *serio) |
| 189 | { | 280 | { |
| 190 | struct elo* elo = serio_get_drvdata(serio); | 281 | struct elo *elo = serio_get_drvdata(serio); |
| 191 | 282 | ||
| 283 | input_get_device(elo->dev); | ||
| 192 | input_unregister_device(elo->dev); | 284 | input_unregister_device(elo->dev); |
| 193 | serio_close(serio); | 285 | serio_close(serio); |
| 194 | serio_set_drvdata(serio, NULL); | 286 | serio_set_drvdata(serio, NULL); |
| 287 | input_put_device(elo->dev); | ||
| 195 | kfree(elo); | 288 | kfree(elo); |
| 196 | } | 289 | } |
| 197 | 290 | ||
| @@ -211,12 +304,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
| 211 | input_dev = input_allocate_device(); | 304 | input_dev = input_allocate_device(); |
| 212 | if (!elo || !input_dev) { | 305 | if (!elo || !input_dev) { |
| 213 | err = -ENOMEM; | 306 | err = -ENOMEM; |
| 214 | goto fail; | 307 | goto fail1; |
| 215 | } | 308 | } |
| 216 | 309 | ||
| 217 | elo->serio = serio; | 310 | elo->serio = serio; |
| 218 | elo->id = serio->id.id; | 311 | elo->id = serio->id.id; |
| 219 | elo->dev = input_dev; | 312 | elo->dev = input_dev; |
| 313 | elo->expected_packet = ELO10_TOUCH_PACKET; | ||
| 314 | mutex_init(&elo->cmd_mutex); | ||
| 315 | init_completion(&elo->cmd_done); | ||
| 220 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); | 316 | snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); |
| 221 | 317 | ||
| 222 | input_dev->private = elo; | 318 | input_dev->private = elo; |
| @@ -231,12 +327,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
| 231 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | 327 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); |
| 232 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | 328 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); |
| 233 | 329 | ||
| 330 | serio_set_drvdata(serio, elo); | ||
| 331 | err = serio_open(serio, drv); | ||
| 332 | if (err) | ||
| 333 | goto fail2; | ||
| 334 | |||
| 234 | switch (elo->id) { | 335 | switch (elo->id) { |
| 235 | 336 | ||
| 236 | case 0: /* 10-byte protocol */ | 337 | case 0: /* 10-byte protocol */ |
| 237 | input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); | 338 | if (elo_setup_10(elo)) |
| 238 | input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); | 339 | goto fail3; |
| 239 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0); | 340 | |
| 240 | break; | 341 | break; |
| 241 | 342 | ||
| 242 | case 1: /* 6-byte protocol */ | 343 | case 1: /* 6-byte protocol */ |
| @@ -253,17 +354,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) | |||
| 253 | break; | 354 | break; |
| 254 | } | 355 | } |
| 255 | 356 | ||
| 256 | serio_set_drvdata(serio, elo); | 357 | err = input_register_device(elo->dev); |
| 257 | |||
| 258 | err = serio_open(serio, drv); | ||
| 259 | if (err) | 358 | if (err) |
| 260 | goto fail; | 359 | goto fail3; |
| 261 | 360 | ||
| 262 | input_register_device(elo->dev); | ||
| 263 | return 0; | 361 | return 0; |
| 264 | 362 | ||
| 265 | fail: serio_set_drvdata(serio, NULL); | 363 | fail3: serio_close(serio); |
| 266 | input_free_device(input_dev); | 364 | fail2: serio_set_drvdata(serio, NULL); |
| 365 | fail1: input_free_device(input_dev); | ||
| 267 | kfree(elo); | 366 | kfree(elo); |
| 268 | return err; | 367 | return err; |
| 269 | } | 368 | } |
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c new file mode 100644 index 000000000000..f7370109d43e --- /dev/null +++ b/drivers/input/touchscreen/penmount.c | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | /* | ||
| 2 | * Penmount serial touchscreen driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> | ||
| 5 | * | ||
| 6 | * Based on ELO driver (drivers/input/touchscreen/elo.c) | ||
| 7 | * Copyright (c) 2004 Vojtech Pavlik | ||
| 8 | */ | ||
| 9 | |||
| 10 | /* | ||
| 11 | * This program is free software; you can redistribute it and/or modify it | ||
| 12 | * under the terms of the GNU General Public License version 2 as published | ||
| 13 | * by the Free Software Foundation. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/errno.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/input.h> | ||
| 21 | #include <linux/serio.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | |||
| 24 | #define DRIVER_DESC "Penmount serial touchscreen driver" | ||
| 25 | |||
| 26 | MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); | ||
| 27 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 28 | MODULE_LICENSE("GPL"); | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Definitions & global arrays. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #define PM_MAX_LENGTH 5 | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Per-touchscreen data. | ||
| 38 | */ | ||
| 39 | |||
| 40 | struct pm { | ||
| 41 | struct input_dev *dev; | ||
| 42 | struct serio *serio; | ||
| 43 | int idx; | ||
| 44 | unsigned char data[PM_MAX_LENGTH]; | ||
| 45 | char phys[32]; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static irqreturn_t pm_interrupt(struct serio *serio, | ||
| 49 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
| 50 | { | ||
| 51 | struct pm *pm = serio_get_drvdata(serio); | ||
| 52 | struct input_dev *dev = pm->dev; | ||
| 53 | |||
| 54 | pm->data[pm->idx] = data; | ||
| 55 | |||
| 56 | if (pm->data[0] & 0x80) { | ||
| 57 | if (PM_MAX_LENGTH == ++pm->idx) { | ||
| 58 | input_regs(dev, regs); | ||
| 59 | input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]); | ||
| 60 | input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]); | ||
| 61 | input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); | ||
| 62 | input_sync(dev); | ||
| 63 | pm->idx = 0; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | return IRQ_HANDLED; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * pm_disconnect() is the opposite of pm_connect() | ||
| 72 | */ | ||
| 73 | |||
| 74 | static void pm_disconnect(struct serio *serio) | ||
| 75 | { | ||
| 76 | struct pm *pm = serio_get_drvdata(serio); | ||
| 77 | |||
| 78 | input_get_device(pm->dev); | ||
| 79 | input_unregister_device(pm->dev); | ||
| 80 | serio_close(serio); | ||
| 81 | serio_set_drvdata(serio, NULL); | ||
| 82 | input_put_device(pm->dev); | ||
| 83 | kfree(pm); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * pm_connect() is the routine that is called when someone adds a | ||
| 88 | * new serio device that supports Gunze protocol and registers it as | ||
| 89 | * an input device. | ||
| 90 | */ | ||
| 91 | |||
| 92 | static int pm_connect(struct serio *serio, struct serio_driver *drv) | ||
| 93 | { | ||
| 94 | struct pm *pm; | ||
| 95 | struct input_dev *input_dev; | ||
| 96 | int err; | ||
| 97 | |||
| 98 | pm = kzalloc(sizeof(struct pm), GFP_KERNEL); | ||
| 99 | input_dev = input_allocate_device(); | ||
| 100 | if (!pm || !input_dev) { | ||
| 101 | err = -ENOMEM; | ||
| 102 | goto fail1; | ||
| 103 | } | ||
| 104 | |||
| 105 | pm->serio = serio; | ||
| 106 | pm->dev = input_dev; | ||
| 107 | snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); | ||
| 108 | |||
| 109 | input_dev->private = pm; | ||
| 110 | input_dev->name = "Penmount Serial TouchScreen"; | ||
| 111 | input_dev->phys = pm->phys; | ||
| 112 | input_dev->id.bustype = BUS_RS232; | ||
| 113 | input_dev->id.vendor = SERIO_PENMOUNT; | ||
| 114 | input_dev->id.product = 0; | ||
| 115 | input_dev->id.version = 0x0100; | ||
| 116 | input_dev->cdev.dev = &serio->dev; | ||
| 117 | |||
| 118 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 119 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 120 | input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); | ||
| 121 | input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); | ||
| 122 | |||
| 123 | serio_set_drvdata(serio, pm); | ||
| 124 | |||
| 125 | err = serio_open(serio, drv); | ||
| 126 | if (err) | ||
| 127 | goto fail2; | ||
| 128 | |||
| 129 | err = input_register_device(pm->dev); | ||
| 130 | if (err) | ||
| 131 | goto fail3; | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | |||
| 135 | fail3: serio_close(serio); | ||
| 136 | fail2: serio_set_drvdata(serio, NULL); | ||
| 137 | fail1: input_free_device(input_dev); | ||
| 138 | kfree(pm); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* | ||
| 143 | * The serio driver structure. | ||
| 144 | */ | ||
| 145 | |||
| 146 | static struct serio_device_id pm_serio_ids[] = { | ||
| 147 | { | ||
| 148 | .type = SERIO_RS232, | ||
| 149 | .proto = SERIO_PENMOUNT, | ||
| 150 | .id = SERIO_ANY, | ||
| 151 | .extra = SERIO_ANY, | ||
| 152 | }, | ||
| 153 | { 0 } | ||
| 154 | }; | ||
| 155 | |||
| 156 | MODULE_DEVICE_TABLE(serio, pm_serio_ids); | ||
| 157 | |||
| 158 | static struct serio_driver pm_drv = { | ||
| 159 | .driver = { | ||
| 160 | .name = "penmountlpc", | ||
| 161 | }, | ||
| 162 | .description = DRIVER_DESC, | ||
| 163 | .id_table = pm_serio_ids, | ||
| 164 | .interrupt = pm_interrupt, | ||
| 165 | .connect = pm_connect, | ||
| 166 | .disconnect = pm_disconnect, | ||
| 167 | }; | ||
| 168 | |||
| 169 | /* | ||
| 170 | * The functions for inserting/removing us as a module. | ||
| 171 | */ | ||
| 172 | |||
| 173 | static int __init pm_init(void) | ||
| 174 | { | ||
| 175 | serio_register_driver(&pm_drv); | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static void __exit pm_exit(void) | ||
| 180 | { | ||
| 181 | serio_unregister_driver(&pm_drv); | ||
| 182 | } | ||
| 183 | |||
| 184 | module_init(pm_init); | ||
| 185 | module_exit(pm_exit); | ||
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c new file mode 100644 index 000000000000..1c89fa538651 --- /dev/null +++ b/drivers/input/touchscreen/touchright.c | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | /* | ||
| 2 | * Touchright serial touchscreen driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> | ||
| 5 | * | ||
| 6 | * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) | ||
| 7 | * Copyright (c) 2004 Vojtech Pavlik | ||
| 8 | * and Dan Streetman <ddstreet@ieee.org> | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify it | ||
| 13 | * under the terms of the GNU General Public License version 2 as published | ||
| 14 | * by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/errno.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/input.h> | ||
| 22 | #include <linux/serio.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | |||
| 25 | #define DRIVER_DESC "Touchright serial touchscreen driver" | ||
| 26 | |||
| 27 | MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); | ||
| 28 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 29 | MODULE_LICENSE("GPL"); | ||
| 30 | |||
| 31 | /* | ||
| 32 | * Definitions & global arrays. | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define TR_FORMAT_TOUCH_BIT 0x01 | ||
| 36 | #define TR_FORMAT_STATUS_BYTE 0x40 | ||
| 37 | #define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT | ||
| 38 | |||
| 39 | #define TR_LENGTH 5 | ||
| 40 | |||
| 41 | #define TR_MIN_XC 0 | ||
| 42 | #define TR_MAX_XC 0x1ff | ||
| 43 | #define TR_MIN_YC 0 | ||
| 44 | #define TR_MAX_YC 0x1ff | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Per-touchscreen data. | ||
| 48 | */ | ||
| 49 | |||
| 50 | struct tr { | ||
| 51 | struct input_dev *dev; | ||
| 52 | struct serio *serio; | ||
| 53 | int idx; | ||
| 54 | unsigned char data[TR_LENGTH]; | ||
| 55 | char phys[32]; | ||
| 56 | }; | ||
| 57 | |||
| 58 | static irqreturn_t tr_interrupt(struct serio *serio, | ||
| 59 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
| 60 | { | ||
| 61 | struct tr *tr = serio_get_drvdata(serio); | ||
| 62 | struct input_dev *dev = tr->dev; | ||
| 63 | |||
| 64 | tr->data[tr->idx] = data; | ||
| 65 | |||
| 66 | if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) { | ||
| 67 | if (++tr->idx == TR_LENGTH) { | ||
| 68 | input_regs(dev, regs); | ||
| 69 | input_report_abs(dev, ABS_X, | ||
| 70 | (tr->data[1] << 5) | (tr->data[2] >> 1)); | ||
| 71 | input_report_abs(dev, ABS_Y, | ||
| 72 | (tr->data[3] << 5) | (tr->data[4] >> 1)); | ||
| 73 | input_report_key(dev, BTN_TOUCH, | ||
| 74 | tr->data[0] & TR_FORMAT_TOUCH_BIT); | ||
| 75 | input_sync(dev); | ||
| 76 | tr->idx = 0; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | return IRQ_HANDLED; | ||
| 81 | } | ||
| 82 | |||
| 83 | /* | ||
| 84 | * tr_disconnect() is the opposite of tr_connect() | ||
| 85 | */ | ||
| 86 | |||
| 87 | static void tr_disconnect(struct serio *serio) | ||
| 88 | { | ||
| 89 | struct tr *tr = serio_get_drvdata(serio); | ||
| 90 | |||
| 91 | input_get_device(tr->dev); | ||
| 92 | input_unregister_device(tr->dev); | ||
| 93 | serio_close(serio); | ||
| 94 | serio_set_drvdata(serio, NULL); | ||
| 95 | input_put_device(tr->dev); | ||
| 96 | kfree(tr); | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * tr_connect() is the routine that is called when someone adds a | ||
| 101 | * new serio device that supports the Touchright protocol and registers it as | ||
| 102 | * an input device. | ||
| 103 | */ | ||
| 104 | |||
| 105 | static int tr_connect(struct serio *serio, struct serio_driver *drv) | ||
| 106 | { | ||
| 107 | struct tr *tr; | ||
| 108 | struct input_dev *input_dev; | ||
| 109 | int err; | ||
| 110 | |||
| 111 | tr = kzalloc(sizeof(struct tr), GFP_KERNEL); | ||
| 112 | input_dev = input_allocate_device(); | ||
| 113 | if (!tr || !input_dev) { | ||
| 114 | err = -ENOMEM; | ||
| 115 | goto fail1; | ||
| 116 | } | ||
| 117 | |||
| 118 | tr->serio = serio; | ||
| 119 | tr->dev = input_dev; | ||
| 120 | snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); | ||
| 121 | |||
| 122 | input_dev->private = tr; | ||
| 123 | input_dev->name = "Touchright Serial TouchScreen"; | ||
| 124 | input_dev->phys = tr->phys; | ||
| 125 | input_dev->id.bustype = BUS_RS232; | ||
| 126 | input_dev->id.vendor = SERIO_TOUCHRIGHT; | ||
| 127 | input_dev->id.product = 0; | ||
| 128 | input_dev->id.version = 0x0100; | ||
| 129 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 130 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 131 | input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0); | ||
| 132 | input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0); | ||
| 133 | |||
| 134 | serio_set_drvdata(serio, tr); | ||
| 135 | |||
| 136 | err = serio_open(serio, drv); | ||
| 137 | if (err) | ||
| 138 | goto fail2; | ||
| 139 | |||
| 140 | err = input_register_device(tr->dev); | ||
| 141 | if (err) | ||
| 142 | goto fail3; | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | |||
| 146 | fail3: serio_close(serio); | ||
| 147 | fail2: serio_set_drvdata(serio, NULL); | ||
| 148 | fail1: input_free_device(input_dev); | ||
| 149 | kfree(tr); | ||
| 150 | return err; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * The serio driver structure. | ||
| 155 | */ | ||
| 156 | |||
| 157 | static struct serio_device_id tr_serio_ids[] = { | ||
| 158 | { | ||
| 159 | .type = SERIO_RS232, | ||
| 160 | .proto = SERIO_TOUCHRIGHT, | ||
| 161 | .id = SERIO_ANY, | ||
| 162 | .extra = SERIO_ANY, | ||
| 163 | }, | ||
| 164 | { 0 } | ||
| 165 | }; | ||
| 166 | |||
| 167 | MODULE_DEVICE_TABLE(serio, tr_serio_ids); | ||
| 168 | |||
| 169 | static struct serio_driver tr_drv = { | ||
| 170 | .driver = { | ||
| 171 | .name = "touchright", | ||
| 172 | }, | ||
| 173 | .description = DRIVER_DESC, | ||
| 174 | .id_table = tr_serio_ids, | ||
| 175 | .interrupt = tr_interrupt, | ||
| 176 | .connect = tr_connect, | ||
| 177 | .disconnect = tr_disconnect, | ||
| 178 | }; | ||
| 179 | |||
| 180 | /* | ||
| 181 | * The functions for inserting/removing us as a module. | ||
| 182 | */ | ||
| 183 | |||
| 184 | static int __init tr_init(void) | ||
| 185 | { | ||
| 186 | serio_register_driver(&tr_drv); | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void __exit tr_exit(void) | ||
| 191 | { | ||
| 192 | serio_unregister_driver(&tr_drv); | ||
| 193 | } | ||
| 194 | |||
| 195 | module_init(tr_init); | ||
| 196 | module_exit(tr_exit); | ||
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c new file mode 100644 index 000000000000..a7b4c755958e --- /dev/null +++ b/drivers/input/touchscreen/touchwin.c | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | /* | ||
| 2 | * Touchwindow serial touchscreen driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com> | ||
| 5 | * | ||
| 6 | * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) | ||
| 7 | * Copyright (c) 2004 Vojtech Pavlik | ||
| 8 | * and Dan Streetman <ddstreet@ieee.org> | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * This program is free software; you can redistribute it and/or modify it | ||
| 13 | * under the terms of the GNU General Public License version 2 as published | ||
| 14 | * by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * 2005/02/19 Rick Koch: | ||
| 19 | * The Touchwindow I used is made by Edmark Corp. and | ||
| 20 | * constantly outputs a stream of 0's unless it is touched. | ||
| 21 | * It then outputs 3 bytes: X, Y, and a copy of Y. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/serio.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | |||
| 32 | #define DRIVER_DESC "Touchwindow serial touchscreen driver" | ||
| 33 | |||
| 34 | MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>"); | ||
| 35 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 36 | MODULE_LICENSE("GPL"); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Definitions & global arrays. | ||
| 40 | */ | ||
| 41 | |||
| 42 | #define TW_LENGTH 3 | ||
| 43 | |||
| 44 | #define TW_MIN_XC 0 | ||
| 45 | #define TW_MAX_XC 0xff | ||
| 46 | #define TW_MIN_YC 0 | ||
| 47 | #define TW_MAX_YC 0xff | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Per-touchscreen data. | ||
| 51 | */ | ||
| 52 | |||
| 53 | struct tw { | ||
| 54 | struct input_dev *dev; | ||
| 55 | struct serio *serio; | ||
| 56 | int idx; | ||
| 57 | int touched; | ||
| 58 | unsigned char data[TW_LENGTH]; | ||
| 59 | char phys[32]; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static irqreturn_t tw_interrupt(struct serio *serio, | ||
| 63 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
| 64 | { | ||
| 65 | struct tw *tw = serio_get_drvdata(serio); | ||
| 66 | struct input_dev *dev = tw->dev; | ||
| 67 | |||
| 68 | if (data) { /* touch */ | ||
| 69 | tw->touched = 1; | ||
| 70 | tw->data[tw->idx++] = data; | ||
| 71 | /* verify length and that the two Y's are the same */ | ||
| 72 | if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { | ||
| 73 | input_regs(dev, regs); | ||
| 74 | input_report_abs(dev, ABS_X, tw->data[0]); | ||
| 75 | input_report_abs(dev, ABS_Y, tw->data[1]); | ||
| 76 | input_report_key(dev, BTN_TOUCH, 1); | ||
| 77 | input_sync(dev); | ||
| 78 | tw->idx = 0; | ||
| 79 | } | ||
| 80 | } else if (tw->touched) { /* untouch */ | ||
| 81 | input_report_key(dev, BTN_TOUCH, 0); | ||
| 82 | input_sync(dev); | ||
| 83 | tw->idx = 0; | ||
| 84 | tw->touched = 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | return IRQ_HANDLED; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * tw_disconnect() is the opposite of tw_connect() | ||
| 92 | */ | ||
| 93 | |||
| 94 | static void tw_disconnect(struct serio *serio) | ||
| 95 | { | ||
| 96 | struct tw *tw = serio_get_drvdata(serio); | ||
| 97 | |||
| 98 | input_get_device(tw->dev); | ||
| 99 | input_unregister_device(tw->dev); | ||
| 100 | serio_close(serio); | ||
| 101 | serio_set_drvdata(serio, NULL); | ||
| 102 | input_put_device(tw->dev); | ||
| 103 | kfree(tw); | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * tw_connect() is the routine that is called when someone adds a | ||
| 108 | * new serio device that supports the Touchwin protocol and registers it as | ||
| 109 | * an input device. | ||
| 110 | */ | ||
| 111 | |||
| 112 | static int tw_connect(struct serio *serio, struct serio_driver *drv) | ||
| 113 | { | ||
| 114 | struct tw *tw; | ||
| 115 | struct input_dev *input_dev; | ||
| 116 | int err; | ||
| 117 | |||
| 118 | tw = kzalloc(sizeof(struct tw), GFP_KERNEL); | ||
| 119 | input_dev = input_allocate_device(); | ||
| 120 | if (!tw || !input_dev) { | ||
| 121 | err = -ENOMEM; | ||
| 122 | goto fail1; | ||
| 123 | } | ||
| 124 | |||
| 125 | tw->serio = serio; | ||
| 126 | tw->dev = input_dev; | ||
| 127 | snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); | ||
| 128 | |||
| 129 | input_dev->private = tw; | ||
| 130 | input_dev->name = "Touchwindow Serial TouchScreen"; | ||
| 131 | input_dev->phys = tw->phys; | ||
| 132 | input_dev->id.bustype = BUS_RS232; | ||
| 133 | input_dev->id.vendor = SERIO_TOUCHWIN; | ||
| 134 | input_dev->id.product = 0; | ||
| 135 | input_dev->id.version = 0x0100; | ||
| 136 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 137 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 138 | input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0); | ||
| 139 | input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0); | ||
| 140 | |||
| 141 | serio_set_drvdata(serio, tw); | ||
| 142 | |||
| 143 | err = serio_open(serio, drv); | ||
| 144 | if (err) | ||
| 145 | goto fail2; | ||
| 146 | |||
| 147 | err = input_register_device(tw->dev); | ||
| 148 | if (err) | ||
| 149 | goto fail3; | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | |||
| 153 | fail3: serio_close(serio); | ||
| 154 | fail2: serio_set_drvdata(serio, NULL); | ||
| 155 | fail1: input_free_device(input_dev); | ||
| 156 | kfree(tw); | ||
| 157 | return err; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* | ||
| 161 | * The serio driver structure. | ||
| 162 | */ | ||
| 163 | |||
| 164 | static struct serio_device_id tw_serio_ids[] = { | ||
| 165 | { | ||
| 166 | .type = SERIO_RS232, | ||
| 167 | .proto = SERIO_TOUCHWIN, | ||
| 168 | .id = SERIO_ANY, | ||
| 169 | .extra = SERIO_ANY, | ||
| 170 | }, | ||
| 171 | { 0 } | ||
| 172 | }; | ||
| 173 | |||
| 174 | MODULE_DEVICE_TABLE(serio, tw_serio_ids); | ||
| 175 | |||
| 176 | static struct serio_driver tw_drv = { | ||
| 177 | .driver = { | ||
| 178 | .name = "touchwin", | ||
| 179 | }, | ||
| 180 | .description = DRIVER_DESC, | ||
| 181 | .id_table = tw_serio_ids, | ||
| 182 | .interrupt = tw_interrupt, | ||
| 183 | .connect = tw_connect, | ||
| 184 | .disconnect = tw_disconnect, | ||
| 185 | }; | ||
| 186 | |||
| 187 | /* | ||
| 188 | * The functions for inserting/removing us as a module. | ||
| 189 | */ | ||
| 190 | |||
| 191 | static int __init tw_init(void) | ||
| 192 | { | ||
| 193 | serio_register_driver(&tw_drv); | ||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static void __exit tw_exit(void) | ||
| 198 | { | ||
| 199 | serio_unregister_driver(&tw_drv); | ||
| 200 | } | ||
| 201 | |||
| 202 | module_init(tw_init); | ||
| 203 | module_exit(tw_exit); | ||
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 00e3929c6288..a730c461227f 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c | |||
| @@ -135,8 +135,6 @@ struct tsdev_list { | |||
| 135 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) | 135 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) |
| 136 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) | 136 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) |
| 137 | 137 | ||
| 138 | static struct input_handler tsdev_handler; | ||
| 139 | |||
| 140 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; | 138 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; |
| 141 | 139 | ||
| 142 | static int tsdev_fasync(int fd, struct file *file, int on) | 140 | static int tsdev_fasync(int fd, struct file *file, int on) |
| @@ -263,7 +261,7 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, | |||
| 263 | return retval; | 261 | return retval; |
| 264 | } | 262 | } |
| 265 | 263 | ||
| 266 | static struct file_operations tsdev_fops = { | 264 | static const struct file_operations tsdev_fops = { |
| 267 | .owner = THIS_MODULE, | 265 | .owner = THIS_MODULE, |
| 268 | .open = tsdev_open, | 266 | .open = tsdev_open, |
| 269 | .release = tsdev_release, | 267 | .release = tsdev_release, |
| @@ -370,7 +368,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, | |||
| 370 | 368 | ||
| 371 | static struct input_handle *tsdev_connect(struct input_handler *handler, | 369 | static struct input_handle *tsdev_connect(struct input_handler *handler, |
| 372 | struct input_dev *dev, | 370 | struct input_dev *dev, |
| 373 | struct input_device_id *id) | 371 | const struct input_device_id *id) |
| 374 | { | 372 | { |
| 375 | struct tsdev *tsdev; | 373 | struct tsdev *tsdev; |
| 376 | struct class_device *cdev; | 374 | struct class_device *cdev; |
| @@ -443,7 +441,7 @@ static void tsdev_disconnect(struct input_handle *handle) | |||
| 443 | tsdev_free(tsdev); | 441 | tsdev_free(tsdev); |
| 444 | } | 442 | } |
| 445 | 443 | ||
| 446 | static struct input_device_id tsdev_ids[] = { | 444 | static const struct input_device_id tsdev_ids[] = { |
| 447 | { | 445 | { |
| 448 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 446 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, |
| 449 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 447 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
| @@ -481,9 +479,7 @@ static struct input_handler tsdev_handler = { | |||
| 481 | 479 | ||
| 482 | static int __init tsdev_init(void) | 480 | static int __init tsdev_init(void) |
| 483 | { | 481 | { |
| 484 | input_register_handler(&tsdev_handler); | 482 | return input_register_handler(&tsdev_handler); |
| 485 | printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); | ||
| 486 | return 0; | ||
| 487 | } | 483 | } |
| 488 | 484 | ||
| 489 | static void __exit tsdev_exit(void) | 485 | static void __exit tsdev_exit(void) |
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 669f76393b5a..11844bbfe933 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c | |||
| @@ -1298,7 +1298,7 @@ static int capinc_tty_read_proc(char *page, char **start, off_t off, | |||
| 1298 | 1298 | ||
| 1299 | static struct tty_driver *capinc_tty_driver; | 1299 | static struct tty_driver *capinc_tty_driver; |
| 1300 | 1300 | ||
| 1301 | static struct tty_operations capinc_ops = { | 1301 | static const struct tty_operations capinc_ops = { |
| 1302 | .open = capinc_tty_open, | 1302 | .open = capinc_tty_open, |
| 1303 | .close = capinc_tty_close, | 1303 | .close = capinc_tty_close, |
| 1304 | .write = capinc_tty_write, | 1304 | .write = capinc_tty_write, |
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index bd2e4267528e..596f3aebe2f7 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c | |||
| @@ -134,7 +134,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, | |||
| 134 | static int if_write(struct tty_struct *tty, | 134 | static int if_write(struct tty_struct *tty, |
| 135 | const unsigned char *buf, int count); | 135 | const unsigned char *buf, int count); |
| 136 | 136 | ||
| 137 | static struct tty_operations if_ops = { | 137 | static const struct tty_operations if_ops = { |
| 138 | .open = if_open, | 138 | .open = if_open, |
| 139 | .close = if_close, | 139 | .close = if_close, |
| 140 | .ioctl = if_ioctl, | 140 | .ioctl = if_ioctl, |
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index 9ae3a7f3e7b3..9ad840e95dbe 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c | |||
| @@ -83,5 +83,6 @@ void gigaset_init_dev_sysfs(struct cardstate *cs) | |||
| 83 | return; | 83 | return; |
| 84 | 84 | ||
| 85 | gig_dbg(DEBUG_INIT, "setting up sysfs"); | 85 | gig_dbg(DEBUG_INIT, "setting up sysfs"); |
| 86 | class_device_create_file(cs->class, &class_device_attr_cidmode); | 86 | if (class_device_create_file(cs->class, &class_device_attr_cidmode)) |
| 87 | dev_err(cs->dev, "could not create sysfs attribute\n"); | ||
| 87 | } | 88 | } |
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 75920aa0a3c5..2f9d5118ceaf 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h | |||
| @@ -1316,7 +1316,18 @@ void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); | |||
| 1316 | void iecpy(u_char * dest, u_char * iestart, int ieoffset); | 1316 | void iecpy(u_char * dest, u_char * iestart, int ieoffset); |
| 1317 | #endif /* __KERNEL__ */ | 1317 | #endif /* __KERNEL__ */ |
| 1318 | 1318 | ||
| 1319 | #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} | 1319 | /* |
| 1320 | * Busywait delay for `jiffs' jiffies | ||
| 1321 | */ | ||
| 1322 | #define HZDELAY(jiffs) do { \ | ||
| 1323 | int tout = jiffs; \ | ||
| 1324 | \ | ||
| 1325 | while (tout--) { \ | ||
| 1326 | int loops = USEC_PER_SEC / HZ; \ | ||
| 1327 | while (loops--) \ | ||
| 1328 | udelay(1); \ | ||
| 1329 | } \ | ||
| 1330 | } while (0) | ||
| 1320 | 1331 | ||
| 1321 | int ll_run(struct IsdnCardState *cs, int addfeatures); | 1332 | int ll_run(struct IsdnCardState *cs, int addfeatures); |
| 1322 | int CallcNew(void); | 1333 | int CallcNew(void); |
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 9ab66e8960d5..2b91bb07fc7f 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c | |||
| @@ -1860,7 +1860,7 @@ modem_write_profile(atemu * m) | |||
| 1860 | send_sig(SIGIO, dev->profd, 1); | 1860 | send_sig(SIGIO, dev->profd, 1); |
| 1861 | } | 1861 | } |
| 1862 | 1862 | ||
| 1863 | static struct tty_operations modem_ops = { | 1863 | static const struct tty_operations modem_ops = { |
| 1864 | .open = isdn_tty_open, | 1864 | .open = isdn_tty_open, |
| 1865 | .close = isdn_tty_close, | 1865 | .close = isdn_tty_close, |
| 1866 | .write = isdn_tty_write, | 1866 | .write = isdn_tty_write, |
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index c972fe014c58..9878183ba3f0 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | #define __KERNEL_SYSCALLS__ | ||
| 30 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
| 31 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| 32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 19c2b85249c3..c1bf1fb04c5c 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -3,5 +3,6 @@ | |||
| 3 | # | 3 | # |
| 4 | obj- := misc.o # Dummy rule to force built-in.o to be made | 4 | obj- := misc.o # Dummy rule to force built-in.o to be made |
| 5 | 5 | ||
| 6 | obj-$(CONFIG_IBM_ASM) += ibmasm/ | 6 | obj-$(CONFIG_IBM_ASM) += ibmasm/ |
| 7 | obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ | 7 | obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ |
| 8 | obj-$(CONFIG_LKDTM) += lkdtm.o | ||
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c new file mode 100644 index 000000000000..e689ee94ac3d --- /dev/null +++ b/drivers/misc/lkdtm.c | |||
| @@ -0,0 +1,342 @@ | |||
| 1 | /* | ||
| 2 | * Kprobe module for testing crash dumps | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | * | ||
| 18 | * Copyright (C) IBM Corporation, 2006 | ||
| 19 | * | ||
| 20 | * Author: Ankita Garg <ankita@in.ibm.com> | ||
| 21 | * | ||
| 22 | * This module induces system failures at predefined crashpoints to | ||
| 23 | * evaluate the reliability of crash dumps obtained using different dumping | ||
| 24 | * solutions. | ||
| 25 | * | ||
| 26 | * It is adapted from the Linux Kernel Dump Test Tool by | ||
| 27 | * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net> | ||
| 28 | * | ||
| 29 | * Usage : insmod lkdtm.ko [recur_count={>0}] cpoint_name=<> cpoint_type=<> | ||
| 30 | * [cpoint_count={>0}] | ||
| 31 | * | ||
| 32 | * recur_count : Recursion level for the stack overflow test. Default is 10. | ||
| 33 | * | ||
| 34 | * cpoint_name : Crash point where the kernel is to be crashed. It can be | ||
| 35 | * one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY, | ||
| 36 | * FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD, | ||
| 37 | * IDE_CORE_CP | ||
| 38 | * | ||
| 39 | * cpoint_type : Indicates the action to be taken on hitting the crash point. | ||
| 40 | * It can be one of PANIC, BUG, EXCEPTION, LOOP, OVERFLOW | ||
| 41 | * | ||
| 42 | * cpoint_count : Indicates the number of times the crash point is to be hit | ||
| 43 | * to trigger an action. The default is 10. | ||
| 44 | */ | ||
| 45 | |||
| 46 | #include <linux/kernel.h> | ||
| 47 | #include <linux/module.h> | ||
| 48 | #include <linux/kprobes.h> | ||
| 49 | #include <linux/kallsyms.h> | ||
| 50 | #include <linux/init.h> | ||
| 51 | #include <linux/irq.h> | ||
| 52 | #include <linux/interrupt.h> | ||
| 53 | #include <scsi/scsi_cmnd.h> | ||
| 54 | |||
| 55 | #ifdef CONFIG_IDE | ||
| 56 | #include <linux/ide.h> | ||
| 57 | #endif | ||
| 58 | |||
| 59 | #define NUM_CPOINTS 8 | ||
| 60 | #define NUM_CPOINT_TYPES 5 | ||
| 61 | #define DEFAULT_COUNT 10 | ||
| 62 | #define REC_NUM_DEFAULT 10 | ||
| 63 | |||
| 64 | enum cname { | ||
| 65 | INVALID, | ||
| 66 | INT_HARDWARE_ENTRY, | ||
| 67 | INT_HW_IRQ_EN, | ||
| 68 | INT_TASKLET_ENTRY, | ||
| 69 | FS_DEVRW, | ||
| 70 | MEM_SWAPOUT, | ||
| 71 | TIMERADD, | ||
| 72 | SCSI_DISPATCH_CMD, | ||
| 73 | IDE_CORE_CP | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum ctype { | ||
| 77 | NONE, | ||
| 78 | PANIC, | ||
| 79 | BUG, | ||
| 80 | EXCEPTION, | ||
| 81 | LOOP, | ||
| 82 | OVERFLOW | ||
| 83 | }; | ||
| 84 | |||
| 85 | static char* cp_name[] = { | ||
| 86 | "INT_HARDWARE_ENTRY", | ||
| 87 | "INT_HW_IRQ_EN", | ||
| 88 | "INT_TASKLET_ENTRY", | ||
| 89 | "FS_DEVRW", | ||
| 90 | "MEM_SWAPOUT", | ||
| 91 | "TIMERADD", | ||
| 92 | "SCSI_DISPATCH_CMD", | ||
| 93 | "IDE_CORE_CP" | ||
| 94 | }; | ||
| 95 | |||
| 96 | static char* cp_type[] = { | ||
| 97 | "PANIC", | ||
| 98 | "BUG", | ||
| 99 | "EXCEPTION", | ||
| 100 | "LOOP", | ||
| 101 | "OVERFLOW" | ||
| 102 | }; | ||
| 103 | |||
| 104 | static struct jprobe lkdtm; | ||
| 105 | |||
| 106 | static int lkdtm_parse_commandline(void); | ||
| 107 | static void lkdtm_handler(void); | ||
| 108 | |||
| 109 | static char* cpoint_name = INVALID; | ||
| 110 | static char* cpoint_type = NONE; | ||
| 111 | static int cpoint_count = DEFAULT_COUNT; | ||
| 112 | static int recur_count = REC_NUM_DEFAULT; | ||
| 113 | |||
| 114 | static enum cname cpoint = INVALID; | ||
| 115 | static enum ctype cptype = NONE; | ||
| 116 | static int count = DEFAULT_COUNT; | ||
| 117 | |||
| 118 | module_param(recur_count, int, 0644); | ||
| 119 | MODULE_PARM_DESC(recur_count, "Recurcion level for the stack overflow test,\ | ||
| 120 | default is 10"); | ||
| 121 | module_param(cpoint_name, charp, 0644); | ||
| 122 | MODULE_PARM_DESC(cpoint_name, "Crash Point, where kernel is to be crashed"); | ||
| 123 | module_param(cpoint_type, charp, 06444); | ||
| 124 | MODULE_PARM_DESC(cpoint_type, "Crash Point Type, action to be taken on\ | ||
| 125 | hitting the crash point"); | ||
| 126 | module_param(cpoint_count, int, 06444); | ||
| 127 | MODULE_PARM_DESC(cpoint_count, "Crash Point Count, number of times the \ | ||
| 128 | crash point is to be hit to trigger action"); | ||
| 129 | |||
| 130 | unsigned int jp_do_irq(unsigned int irq, struct pt_regs *regs) | ||
| 131 | { | ||
| 132 | lkdtm_handler(); | ||
| 133 | jprobe_return(); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | irqreturn_t jp_handle_irq_event(unsigned int irq, struct pt_regs *regs, | ||
| 138 | struct irqaction *action) | ||
| 139 | { | ||
| 140 | lkdtm_handler(); | ||
| 141 | jprobe_return(); | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | void jp_tasklet_action(struct softirq_action *a) | ||
| 146 | { | ||
| 147 | lkdtm_handler(); | ||
| 148 | jprobe_return(); | ||
| 149 | } | ||
| 150 | |||
| 151 | void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) | ||
| 152 | { | ||
| 153 | lkdtm_handler(); | ||
| 154 | jprobe_return(); | ||
| 155 | } | ||
| 156 | |||
| 157 | struct scan_control; | ||
| 158 | |||
| 159 | unsigned long jp_shrink_page_list(struct list_head *page_list, | ||
| 160 | struct scan_control *sc) | ||
| 161 | { | ||
| 162 | lkdtm_handler(); | ||
| 163 | jprobe_return(); | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, | ||
| 168 | const enum hrtimer_mode mode) | ||
| 169 | { | ||
| 170 | lkdtm_handler(); | ||
| 171 | jprobe_return(); | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) | ||
| 176 | { | ||
| 177 | lkdtm_handler(); | ||
| 178 | jprobe_return(); | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | #ifdef CONFIG_IDE | ||
| 183 | int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, | ||
| 184 | struct block_device *bdev, unsigned int cmd, | ||
| 185 | unsigned long arg) | ||
| 186 | { | ||
| 187 | lkdtm_handler(); | ||
| 188 | jprobe_return(); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | #endif | ||
| 192 | |||
| 193 | static int lkdtm_parse_commandline(void) | ||
| 194 | { | ||
| 195 | int i; | ||
| 196 | |||
| 197 | if (cpoint_name == INVALID || cpoint_type == NONE || | ||
| 198 | cpoint_count < 1 || recur_count < 1) | ||
| 199 | return -EINVAL; | ||
| 200 | |||
| 201 | for (i = 0; i < NUM_CPOINTS; ++i) { | ||
| 202 | if (!strcmp(cpoint_name, cp_name[i])) { | ||
| 203 | cpoint = i + 1; | ||
| 204 | break; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | for (i = 0; i < NUM_CPOINT_TYPES; ++i) { | ||
| 209 | if (!strcmp(cpoint_type, cp_type[i])) { | ||
| 210 | cptype = i + 1; | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | if (cpoint == INVALID || cptype == NONE) | ||
| 216 | return -EINVAL; | ||
| 217 | |||
| 218 | count = cpoint_count; | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int recursive_loop(int a) | ||
| 224 | { | ||
| 225 | char buf[1024]; | ||
| 226 | |||
| 227 | memset(buf,0xFF,1024); | ||
| 228 | recur_count--; | ||
| 229 | if (!recur_count) | ||
| 230 | return 0; | ||
| 231 | else | ||
| 232 | return recursive_loop(a); | ||
| 233 | } | ||
| 234 | |||
| 235 | void lkdtm_handler(void) | ||
| 236 | { | ||
| 237 | printk(KERN_INFO "lkdtm : Crash point %s of type %s hit\n", | ||
| 238 | cpoint_name, cpoint_type); | ||
| 239 | --count; | ||
| 240 | |||
| 241 | if (count == 0) { | ||
| 242 | switch (cptype) { | ||
| 243 | case NONE: | ||
| 244 | break; | ||
| 245 | case PANIC: | ||
| 246 | printk(KERN_INFO "lkdtm : PANIC\n"); | ||
| 247 | panic("dumptest"); | ||
| 248 | break; | ||
| 249 | case BUG: | ||
| 250 | printk(KERN_INFO "lkdtm : BUG\n"); | ||
| 251 | BUG(); | ||
| 252 | break; | ||
| 253 | case EXCEPTION: | ||
| 254 | printk(KERN_INFO "lkdtm : EXCEPTION\n"); | ||
| 255 | *((int *) 0) = 0; | ||
| 256 | break; | ||
| 257 | case LOOP: | ||
| 258 | printk(KERN_INFO "lkdtm : LOOP\n"); | ||
| 259 | for (;;); | ||
| 260 | break; | ||
| 261 | case OVERFLOW: | ||
| 262 | printk(KERN_INFO "lkdtm : OVERFLOW\n"); | ||
| 263 | (void) recursive_loop(0); | ||
| 264 | break; | ||
| 265 | default: | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | count = cpoint_count; | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | int lkdtm_module_init(void) | ||
| 273 | { | ||
| 274 | int ret; | ||
| 275 | |||
| 276 | if (lkdtm_parse_commandline() == -EINVAL) { | ||
| 277 | printk(KERN_INFO "lkdtm : Invalid command\n"); | ||
| 278 | return -EINVAL; | ||
| 279 | } | ||
| 280 | |||
| 281 | switch (cpoint) { | ||
| 282 | case INT_HARDWARE_ENTRY: | ||
| 283 | lkdtm.kp.symbol_name = "__do_IRQ"; | ||
| 284 | lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; | ||
| 285 | break; | ||
| 286 | case INT_HW_IRQ_EN: | ||
| 287 | lkdtm.kp.symbol_name = "handle_IRQ_event"; | ||
| 288 | lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; | ||
| 289 | break; | ||
| 290 | case INT_TASKLET_ENTRY: | ||
| 291 | lkdtm.kp.symbol_name = "tasklet_action"; | ||
| 292 | lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; | ||
| 293 | break; | ||
| 294 | case FS_DEVRW: | ||
| 295 | lkdtm.kp.symbol_name = "ll_rw_block"; | ||
| 296 | lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; | ||
| 297 | break; | ||
| 298 | case MEM_SWAPOUT: | ||
| 299 | lkdtm.kp.symbol_name = "shrink_page_list"; | ||
| 300 | lkdtm.entry = (kprobe_opcode_t*) jp_shrink_page_list; | ||
| 301 | break; | ||
| 302 | case TIMERADD: | ||
| 303 | lkdtm.kp.symbol_name = "hrtimer_start"; | ||
| 304 | lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; | ||
| 305 | break; | ||
| 306 | case SCSI_DISPATCH_CMD: | ||
| 307 | lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; | ||
| 308 | lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; | ||
| 309 | break; | ||
| 310 | case IDE_CORE_CP: | ||
| 311 | #ifdef CONFIG_IDE | ||
| 312 | lkdtm.kp.symbol_name = "generic_ide_ioctl"; | ||
| 313 | lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; | ||
| 314 | #else | ||
| 315 | printk(KERN_INFO "lkdtm : Crash point not available\n"); | ||
| 316 | #endif | ||
| 317 | break; | ||
| 318 | default: | ||
| 319 | printk(KERN_INFO "lkdtm : Invalid Crash Point\n"); | ||
| 320 | break; | ||
| 321 | } | ||
| 322 | |||
| 323 | if ((ret = register_jprobe(&lkdtm)) < 0) { | ||
| 324 | printk(KERN_INFO "lkdtm : Couldn't register jprobe\n"); | ||
| 325 | return ret; | ||
| 326 | } | ||
| 327 | |||
| 328 | printk(KERN_INFO "lkdtm : Crash point %s of type %s registered\n", | ||
| 329 | cpoint_name, cpoint_type); | ||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | void lkdtm_module_exit(void) | ||
| 334 | { | ||
| 335 | unregister_jprobe(&lkdtm); | ||
| 336 | printk(KERN_INFO "lkdtm : Crash point unregistered\n"); | ||
| 337 | } | ||
| 338 | |||
| 339 | module_init(lkdtm_module_init); | ||
| 340 | module_exit(lkdtm_module_exit); | ||
| 341 | |||
| 342 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index bc0face01d25..151a2e10e4f3 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -697,7 +697,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on) | |||
| 697 | return ret; | 697 | return ret; |
| 698 | 698 | ||
| 699 | if (on) { | 699 | if (on) { |
| 700 | ret = f_setown(file, current->pid, 0); | 700 | ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0); |
| 701 | if (ret) | 701 | if (ret) |
| 702 | return ret; | 702 | return ret; |
| 703 | tun->flags |= TUN_FASYNC; | 703 | tun->flags |= TUN_FASYNC; |
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 97937809de09..eddfa8786e83 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c | |||
| @@ -150,7 +150,6 @@ that only one external action is invoked at a time. | |||
| 150 | #include <linux/skbuff.h> | 150 | #include <linux/skbuff.h> |
| 151 | #include <asm/uaccess.h> | 151 | #include <asm/uaccess.h> |
| 152 | #include <asm/io.h> | 152 | #include <asm/io.h> |
| 153 | #define __KERNEL_SYSCALLS__ | ||
| 154 | #include <linux/fs.h> | 153 | #include <linux/fs.h> |
| 155 | #include <linux/mm.h> | 154 | #include <linux/mm.h> |
| 156 | #include <linux/slab.h> | 155 | #include <linux/slab.h> |
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index bf00fa2537bb..8dac2ba82bb9 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c | |||
| @@ -684,7 +684,7 @@ int __init led_init(void) | |||
| 684 | int ret; | 684 | int ret; |
| 685 | 685 | ||
| 686 | snprintf(lcd_text_default, sizeof(lcd_text_default), | 686 | snprintf(lcd_text_default, sizeof(lcd_text_default), |
| 687 | "Linux %s", system_utsname.release); | 687 | "Linux %s", init_utsname()->release); |
| 688 | 688 | ||
| 689 | /* Work around the buggy PDC of KittyHawk-machines */ | 689 | /* Work around the buggy PDC of KittyHawk-machines */ |
| 690 | switch (CPU_HVERSION) { | 690 | switch (CPU_HVERSION) { |
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index fad5a33bf0fa..4a9f025a6b58 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c | |||
| @@ -84,8 +84,7 @@ | |||
| 84 | 84 | ||
| 85 | static void deferred_poweroff(void *dummy) | 85 | static void deferred_poweroff(void *dummy) |
| 86 | { | 86 | { |
| 87 | extern int cad_pid; /* from kernel/sys.c */ | 87 | if (kill_cad_pid(SIGINT, 1)) { |
| 88 | if (kill_proc(cad_pid, SIGINT, 1)) { | ||
| 89 | /* just in case killing init process failed */ | 88 | /* just in case killing init process failed */ |
| 90 | machine_power_off(); | 89 | machine_power_off(); |
| 91 | } | 90 | } |
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index c5d7476da471..933cd864a5c9 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c | |||
| @@ -298,7 +298,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz | |||
| 298 | { | 298 | { |
| 299 | struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); | 299 | struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); |
| 300 | cisdump_t *cis; | 300 | cisdump_t *cis; |
| 301 | ssize_t ret = count; | 301 | int error; |
| 302 | 302 | ||
| 303 | if (off) | 303 | if (off) |
| 304 | return -EINVAL; | 304 | return -EINVAL; |
| @@ -316,25 +316,22 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz | |||
| 316 | cis->Length = count + 1; | 316 | cis->Length = count + 1; |
| 317 | memcpy(cis->Data, buf, count); | 317 | memcpy(cis->Data, buf, count); |
| 318 | 318 | ||
| 319 | if (pcmcia_replace_cis(s, cis)) | 319 | error = pcmcia_replace_cis(s, cis); |
| 320 | ret = -EIO; | ||
| 321 | |||
| 322 | kfree(cis); | 320 | kfree(cis); |
| 321 | if (error) | ||
| 322 | return -EIO; | ||
| 323 | 323 | ||
| 324 | if (!ret) { | 324 | mutex_lock(&s->skt_mutex); |
| 325 | mutex_lock(&s->skt_mutex); | 325 | if ((s->callback) && (s->state & SOCKET_PRESENT) && |
| 326 | if ((s->callback) && (s->state & SOCKET_PRESENT) && | 326 | !(s->state & SOCKET_CARDBUS)) { |
| 327 | !(s->state & SOCKET_CARDBUS)) { | 327 | if (try_module_get(s->callback->owner)) { |
| 328 | if (try_module_get(s->callback->owner)) { | 328 | s->callback->requery(s); |
| 329 | s->callback->requery(s); | 329 | module_put(s->callback->owner); |
| 330 | module_put(s->callback->owner); | ||
| 331 | } | ||
| 332 | } | 330 | } |
| 333 | mutex_unlock(&s->skt_mutex); | ||
| 334 | } | 331 | } |
| 332 | mutex_unlock(&s->skt_mutex); | ||
| 335 | 333 | ||
| 336 | 334 | return count; | |
| 337 | return (ret); | ||
| 338 | } | 335 | } |
| 339 | 336 | ||
| 340 | 337 | ||
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 6f8370e88a76..625637b84d33 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c | |||
| @@ -116,7 +116,7 @@ static void __exit rtc_sysfs_exit(void) | |||
| 116 | class_interface_unregister(&rtc_sysfs_interface); | 116 | class_interface_unregister(&rtc_sysfs_interface); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | subsys_init(rtc_sysfs_init); | 119 | subsys_initcall(rtc_sysfs_init); |
| 120 | module_exit(rtc_sysfs_exit); | 120 | module_exit(rtc_sysfs_exit); |
| 121 | 121 | ||
| 122 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | 122 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 2fa566fa6da4..d7de175d53f0 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
| @@ -1103,7 +1103,7 @@ tty3215_start(struct tty_struct *tty) | |||
| 1103 | } | 1103 | } |
| 1104 | } | 1104 | } |
| 1105 | 1105 | ||
| 1106 | static struct tty_operations tty3215_ops = { | 1106 | static const struct tty_operations tty3215_ops = { |
| 1107 | .open = tty3215_open, | 1107 | .open = tty3215_open, |
| 1108 | .close = tty3215_close, | 1108 | .close = tty3215_close, |
| 1109 | .write = tty3215_write, | 1109 | .write = tty3215_write, |
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index b4557fa30858..78f8bda81dae 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c | |||
| @@ -27,7 +27,7 @@ struct raw3270_fn fs3270_fn; | |||
| 27 | 27 | ||
| 28 | struct fs3270 { | 28 | struct fs3270 { |
| 29 | struct raw3270_view view; | 29 | struct raw3270_view view; |
| 30 | pid_t fs_pid; /* Pid of controlling program. */ | 30 | struct pid *fs_pid; /* Pid of controlling program. */ |
| 31 | int read_command; /* ccw command to use for reads. */ | 31 | int read_command; /* ccw command to use for reads. */ |
| 32 | int write_command; /* ccw command to use for writes. */ | 32 | int write_command; /* ccw command to use for writes. */ |
| 33 | int attention; /* Got attention. */ | 33 | int attention; /* Got attention. */ |
| @@ -102,7 +102,7 @@ fs3270_restore_callback(struct raw3270_request *rq, void *data) | |||
| 102 | fp = (struct fs3270 *) rq->view; | 102 | fp = (struct fs3270 *) rq->view; |
| 103 | if (rq->rc != 0 || rq->rescnt != 0) { | 103 | if (rq->rc != 0 || rq->rescnt != 0) { |
| 104 | if (fp->fs_pid) | 104 | if (fp->fs_pid) |
| 105 | kill_proc(fp->fs_pid, SIGHUP, 1); | 105 | kill_pid(fp->fs_pid, SIGHUP, 1); |
| 106 | } | 106 | } |
| 107 | fp->rdbuf_size = 0; | 107 | fp->rdbuf_size = 0; |
| 108 | raw3270_request_reset(rq); | 108 | raw3270_request_reset(rq); |
| @@ -173,7 +173,7 @@ fs3270_save_callback(struct raw3270_request *rq, void *data) | |||
| 173 | */ | 173 | */ |
| 174 | if (rq->rc != 0 || rq->rescnt == 0) { | 174 | if (rq->rc != 0 || rq->rescnt == 0) { |
| 175 | if (fp->fs_pid) | 175 | if (fp->fs_pid) |
| 176 | kill_proc(fp->fs_pid, SIGHUP, 1); | 176 | kill_pid(fp->fs_pid, SIGHUP, 1); |
| 177 | fp->rdbuf_size = 0; | 177 | fp->rdbuf_size = 0; |
| 178 | } else | 178 | } else |
| 179 | fp->rdbuf_size = fp->rdbuf->size - rq->rescnt; | 179 | fp->rdbuf_size = fp->rdbuf->size - rq->rescnt; |
| @@ -442,7 +442,7 @@ fs3270_open(struct inode *inode, struct file *filp) | |||
| 442 | return PTR_ERR(fp); | 442 | return PTR_ERR(fp); |
| 443 | 443 | ||
| 444 | init_waitqueue_head(&fp->wait); | 444 | init_waitqueue_head(&fp->wait); |
| 445 | fp->fs_pid = current->pid; | 445 | fp->fs_pid = get_pid(task_pid(current)); |
| 446 | rc = raw3270_add_view(&fp->view, &fs3270_fn, minor); | 446 | rc = raw3270_add_view(&fp->view, &fs3270_fn, minor); |
| 447 | if (rc) { | 447 | if (rc) { |
| 448 | fs3270_free_view(&fp->view); | 448 | fs3270_free_view(&fp->view); |
| @@ -480,7 +480,8 @@ fs3270_close(struct inode *inode, struct file *filp) | |||
| 480 | fp = filp->private_data; | 480 | fp = filp->private_data; |
| 481 | filp->private_data = NULL; | 481 | filp->private_data = NULL; |
| 482 | if (fp) { | 482 | if (fp) { |
| 483 | fp->fs_pid = 0; | 483 | put_pid(fp->fs_pid); |
| 484 | fp->fs_pid = NULL; | ||
| 484 | raw3270_reset(&fp->view); | 485 | raw3270_reset(&fp->view); |
| 485 | raw3270_put_view(&fp->view); | 486 | raw3270_put_view(&fp->view); |
| 486 | raw3270_del_view(&fp->view); | 487 | raw3270_del_view(&fp->view); |
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index f6cf9023039e..6f43e04dbefd 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
| @@ -711,7 +711,7 @@ static struct sclp_register sclp_input_event = | |||
| 711 | .receiver_fn = sclp_tty_receiver | 711 | .receiver_fn = sclp_tty_receiver |
| 712 | }; | 712 | }; |
| 713 | 713 | ||
| 714 | static struct tty_operations sclp_ops = { | 714 | static const struct tty_operations sclp_ops = { |
| 715 | .open = sclp_tty_open, | 715 | .open = sclp_tty_open, |
| 716 | .close = sclp_tty_close, | 716 | .close = sclp_tty_close, |
| 717 | .write = sclp_tty_write, | 717 | .write = sclp_tty_write, |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 54fba6f17188..723bf4191bfe 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
| @@ -655,7 +655,7 @@ __sclp_vt220_init(int early) | |||
| 655 | return 0; | 655 | return 0; |
| 656 | } | 656 | } |
| 657 | 657 | ||
| 658 | static struct tty_operations sclp_vt220_ops = { | 658 | static const struct tty_operations sclp_vt220_ops = { |
| 659 | .open = sclp_vt220_open, | 659 | .open = sclp_vt220_open, |
| 660 | .close = sclp_vt220_close, | 660 | .close = sclp_vt220_close, |
| 661 | .write = sclp_vt220_write, | 661 | .write = sclp_vt220_write, |
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 06e2eeec8473..4717c3611601 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c | |||
| @@ -1737,7 +1737,7 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file, | |||
| 1737 | return kbd_ioctl(tp->kbd, file, cmd, arg); | 1737 | return kbd_ioctl(tp->kbd, file, cmd, arg); |
| 1738 | } | 1738 | } |
| 1739 | 1739 | ||
| 1740 | static struct tty_operations tty3270_ops = { | 1740 | static const struct tty_operations tty3270_ops = { |
| 1741 | .open = tty3270_open, | 1741 | .open = tty3270_open, |
| 1742 | .close = tty3270_close, | 1742 | .close = tty3270_close, |
| 1743 | .write = tty3270_write, | 1743 | .write = tty3270_write, |
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 479364d0332a..e088b5e28711 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c | |||
| @@ -208,7 +208,7 @@ s390_handle_mcck(void) | |||
| 208 | */ | 208 | */ |
| 209 | __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ | 209 | __ctl_clear_bit(14, 24); /* Disable WARNING MCH */ |
| 210 | if (xchg(&mchchk_wng_posted, 1) == 0) | 210 | if (xchg(&mchchk_wng_posted, 1) == 0) |
| 211 | kill_proc(1, SIGPWR, 1); | 211 | kill_cad_pid(SIGPWR, 1); |
| 212 | } | 212 | } |
| 213 | #endif | 213 | #endif |
| 214 | 214 | ||
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c index 4fdb2c932210..a305d4091547 100644 --- a/drivers/sbus/char/aurora.c +++ b/drivers/sbus/char/aurora.c | |||
| @@ -2187,7 +2187,7 @@ static void do_softint(void *private_) | |||
| 2187 | #endif | 2187 | #endif |
| 2188 | } | 2188 | } |
| 2189 | 2189 | ||
| 2190 | static struct tty_operations aurora_ops = { | 2190 | static const struct tty_operations aurora_ops = { |
| 2191 | .open = aurora_open, | 2191 | .open = aurora_open, |
| 2192 | .close = aurora_close, | 2192 | .close = aurora_close, |
| 2193 | .write = aurora_write, | 2193 | .write = aurora_write, |
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c index 1cc706e11119..d27e4f6d7045 100644 --- a/drivers/sbus/char/bbc_envctrl.c +++ b/drivers/sbus/char/bbc_envctrl.c | |||
| @@ -4,9 +4,6 @@ | |||
| 4 | * Copyright (C) 2001 David S. Miller (davem@redhat.com) | 4 | * Copyright (C) 2001 David S. Miller (davem@redhat.com) |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #define __KERNEL_SYSCALLS__ | ||
| 8 | static int errno; | ||
| 9 | |||
| 10 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| 11 | #include <linux/kthread.h> | 8 | #include <linux/kthread.h> |
| 12 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
| @@ -200,7 +197,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp) | |||
| 200 | printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); | 197 | printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n"); |
| 201 | 198 | ||
| 202 | shutting_down = 1; | 199 | shutting_down = 1; |
| 203 | if (execve("/sbin/shutdown", argv, envp) < 0) | 200 | if (kernel_execve("/sbin/shutdown", argv, envp) < 0) |
| 204 | printk(KERN_CRIT "envctrl: shutdown execution failed\n"); | 201 | printk(KERN_CRIT "envctrl: shutdown execution failed\n"); |
| 205 | } | 202 | } |
| 206 | 203 | ||
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 063e676a3ac0..728a133d0fc5 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c | |||
| @@ -19,9 +19,6 @@ | |||
| 19 | * Daniele Bellucci <bellucda@tiscali.it> | 19 | * Daniele Bellucci <bellucda@tiscali.it> |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #define __KERNEL_SYSCALLS__ | ||
| 23 | static int errno; | ||
| 24 | |||
| 25 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 26 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
| 27 | #include <linux/kthread.h> | 24 | #include <linux/kthread.h> |
| @@ -976,13 +973,15 @@ static void envctrl_do_shutdown(void) | |||
| 976 | "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; | 973 | "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; |
| 977 | char *argv[] = { | 974 | char *argv[] = { |
| 978 | "/sbin/shutdown", "-h", "now", NULL }; | 975 | "/sbin/shutdown", "-h", "now", NULL }; |
| 976 | int ret; | ||
| 979 | 977 | ||
| 980 | if (inprog != 0) | 978 | if (inprog != 0) |
| 981 | return; | 979 | return; |
| 982 | 980 | ||
| 983 | inprog = 1; | 981 | inprog = 1; |
| 984 | printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); | 982 | printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n"); |
| 985 | if (0 > execve("/sbin/shutdown", argv, envp)) { | 983 | ret = kernel_execve("/sbin/shutdown", argv, envp); |
| 984 | if (ret < 0) { | ||
| 986 | printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); | 985 | printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); |
| 987 | inprog = 0; /* unlikely to succeed, but we could try again */ | 986 | inprog = 0; /* unlikely to succeed, but we could try again */ |
| 988 | } | 987 | } |
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index ae4106458991..1b53afb1cb57 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
| @@ -933,8 +933,8 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) | |||
| 933 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | 933 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); |
| 934 | ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION); | 934 | ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION); |
| 935 | sprintf(ae->un.OsNameVersion, "%s %s %s", | 935 | sprintf(ae->un.OsNameVersion, "%s %s %s", |
| 936 | system_utsname.sysname, system_utsname.release, | 936 | init_utsname()->sysname, init_utsname()->release, |
| 937 | system_utsname.version); | 937 | init_utsname()->version); |
| 938 | len = strlen(ae->un.OsNameVersion); | 938 | len = strlen(ae->un.OsNameVersion); |
| 939 | len += (len & 3) ? (4 - (len & 3)) : 4; | 939 | len += (len & 3) ? (4 - (len & 3)) : 4; |
| 940 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | 940 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); |
| @@ -1052,7 +1052,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) | |||
| 1052 | size); | 1052 | size); |
| 1053 | ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME); | 1053 | ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME); |
| 1054 | sprintf(ae->un.HostName, "%s", | 1054 | sprintf(ae->un.HostName, "%s", |
| 1055 | system_utsname.nodename); | 1055 | init_utsname()->nodename); |
| 1056 | len = strlen(ae->un.HostName); | 1056 | len = strlen(ae->un.HostName); |
| 1057 | len += (len & 3) ? (4 - (len & 3)) : 4; | 1057 | len += (len & 3) ? (4 - (len & 3)) : 4; |
| 1058 | ae->ad.bits.AttrLen = | 1058 | ae->ad.bits.AttrLen = |
| @@ -1140,7 +1140,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba) | |||
| 1140 | 1140 | ||
| 1141 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID); | 1141 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID); |
| 1142 | if (ndlp) { | 1142 | if (ndlp) { |
| 1143 | if (system_utsname.nodename[0] != '\0') { | 1143 | if (init_utsname()->nodename[0] != '\0') { |
| 1144 | lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA); | 1144 | lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA); |
| 1145 | } else { | 1145 | } else { |
| 1146 | mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); | 1146 | mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); |
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 993a702422ec..bac853c5abb5 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c | |||
| @@ -1378,7 +1378,7 @@ void startup_console(void) | |||
| 1378 | #endif /* CONFIG_PM_LEGACY */ | 1378 | #endif /* CONFIG_PM_LEGACY */ |
| 1379 | 1379 | ||
| 1380 | 1380 | ||
| 1381 | static struct tty_operations rs_ops = { | 1381 | static const struct tty_operations rs_ops = { |
| 1382 | .open = rs_open, | 1382 | .open = rs_open, |
| 1383 | .close = rs_close, | 1383 | .close = rs_close, |
| 1384 | .write = rs_write, | 1384 | .write = rs_write, |
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index e80e70e9b126..1b299e8c57cd 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c | |||
| @@ -2424,7 +2424,7 @@ long console_360_init(long kmem_start, long kmem_end) | |||
| 2424 | */ | 2424 | */ |
| 2425 | static int baud_idx; | 2425 | static int baud_idx; |
| 2426 | 2426 | ||
| 2427 | static struct tty_operations rs_360_ops = { | 2427 | static const struct tty_operations rs_360_ops = { |
| 2428 | .owner = THIS_MODULE, | 2428 | .owner = THIS_MODULE, |
| 2429 | .open = rs_360_open, | 2429 | .open = rs_360_open, |
| 2430 | .close = rs_360_close, | 2430 | .close = rs_360_close, |
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index cabd048c8636..9851d9eff022 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c | |||
| @@ -4825,7 +4825,7 @@ show_serial_version(void) | |||
| 4825 | 4825 | ||
| 4826 | /* rs_init inits the driver at boot (using the module_init chain) */ | 4826 | /* rs_init inits the driver at boot (using the module_init chain) */ |
| 4827 | 4827 | ||
| 4828 | static struct tty_operations rs_ops = { | 4828 | static const struct tty_operations rs_ops = { |
| 4829 | .open = rs_open, | 4829 | .open = rs_open, |
| 4830 | .close = rs_close, | 4830 | .close = rs_close, |
| 4831 | .write = rs_write, | 4831 | .write = rs_write, |
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 832abd3c4706..00d7859c167e 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c | |||
| @@ -1666,7 +1666,7 @@ static void show_serial_version(void) | |||
| 1666 | printk(mcfrs_drivername); | 1666 | printk(mcfrs_drivername); |
| 1667 | } | 1667 | } |
| 1668 | 1668 | ||
| 1669 | static struct tty_operations mcfrs_ops = { | 1669 | static const struct tty_operations mcfrs_ops = { |
| 1670 | .open = mcfrs_open, | 1670 | .open = mcfrs_open, |
| 1671 | .close = mcfrs_close, | 1671 | .close = mcfrs_close, |
| 1672 | .write = mcfrs_write, | 1672 | .write = mcfrs_write, |
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 5f7ba1adb309..de5e8930a6fd 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
| @@ -2111,7 +2111,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, | |||
| 2111 | } | 2111 | } |
| 2112 | } | 2112 | } |
| 2113 | 2113 | ||
| 2114 | static struct tty_operations uart_ops = { | 2114 | static const struct tty_operations uart_ops = { |
| 2115 | .open = uart_open, | 2115 | .open = uart_open, |
| 2116 | .close = uart_close, | 2116 | .close = uart_close, |
| 2117 | .write = uart_write, | 2117 | .write = uart_write, |
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 5e8a27620f6f..622881f26761 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c | |||
| @@ -1701,7 +1701,7 @@ static void __init probe_sccs(void) | |||
| 1701 | spin_unlock_irqrestore(&zs_lock, flags); | 1701 | spin_unlock_irqrestore(&zs_lock, flags); |
| 1702 | } | 1702 | } |
| 1703 | 1703 | ||
| 1704 | static struct tty_operations serial_ops = { | 1704 | static const struct tty_operations serial_ops = { |
| 1705 | .open = rs_open, | 1705 | .open = rs_open, |
| 1706 | .close = rs_close, | 1706 | .close = rs_close, |
| 1707 | .write = rs_write, | 1707 | .write = rs_write, |
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ca90326f2f5c..71288295df2f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -1120,7 +1120,7 @@ static struct usb_driver acm_driver = { | |||
| 1120 | * TTY driver structures. | 1120 | * TTY driver structures. |
| 1121 | */ | 1121 | */ |
| 1122 | 1122 | ||
| 1123 | static struct tty_operations acm_ops = { | 1123 | static const struct tty_operations acm_ops = { |
| 1124 | .open = acm_tty_open, | 1124 | .open = acm_tty_open, |
| 1125 | .close = acm_tty_close, | 1125 | .close = acm_tty_close, |
| 1126 | .write = acm_tty_write, | 1126 | .write = acm_tty_write, |
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index a94c63bef632..3f509beb88e4 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
| @@ -65,7 +65,7 @@ DEFINE_MUTEX(usbfs_mutex); | |||
| 65 | struct async { | 65 | struct async { |
| 66 | struct list_head asynclist; | 66 | struct list_head asynclist; |
| 67 | struct dev_state *ps; | 67 | struct dev_state *ps; |
| 68 | pid_t pid; | 68 | struct pid *pid; |
| 69 | uid_t uid, euid; | 69 | uid_t uid, euid; |
| 70 | unsigned int signr; | 70 | unsigned int signr; |
| 71 | unsigned int ifnum; | 71 | unsigned int ifnum; |
| @@ -225,6 +225,7 @@ static struct async *alloc_async(unsigned int numisoframes) | |||
| 225 | 225 | ||
| 226 | static void free_async(struct async *as) | 226 | static void free_async(struct async *as) |
| 227 | { | 227 | { |
| 228 | put_pid(as->pid); | ||
| 228 | kfree(as->urb->transfer_buffer); | 229 | kfree(as->urb->transfer_buffer); |
| 229 | kfree(as->urb->setup_packet); | 230 | kfree(as->urb->setup_packet); |
| 230 | usb_free_urb(as->urb); | 231 | usb_free_urb(as->urb); |
| @@ -317,7 +318,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) | |||
| 317 | sinfo.si_errno = as->urb->status; | 318 | sinfo.si_errno = as->urb->status; |
| 318 | sinfo.si_code = SI_ASYNCIO; | 319 | sinfo.si_code = SI_ASYNCIO; |
| 319 | sinfo.si_addr = as->userurb; | 320 | sinfo.si_addr = as->userurb; |
| 320 | kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, | 321 | kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, |
| 321 | as->euid, as->secid); | 322 | as->euid, as->secid); |
| 322 | } | 323 | } |
| 323 | snoop(&urb->dev->dev, "urb complete\n"); | 324 | snoop(&urb->dev->dev, "urb complete\n"); |
| @@ -573,7 +574,7 @@ static int usbdev_open(struct inode *inode, struct file *file) | |||
| 573 | INIT_LIST_HEAD(&ps->async_completed); | 574 | INIT_LIST_HEAD(&ps->async_completed); |
| 574 | init_waitqueue_head(&ps->wait); | 575 | init_waitqueue_head(&ps->wait); |
| 575 | ps->discsignr = 0; | 576 | ps->discsignr = 0; |
| 576 | ps->disc_pid = current->pid; | 577 | ps->disc_pid = get_pid(task_pid(current)); |
| 577 | ps->disc_uid = current->uid; | 578 | ps->disc_uid = current->uid; |
| 578 | ps->disc_euid = current->euid; | 579 | ps->disc_euid = current->euid; |
| 579 | ps->disccontext = NULL; | 580 | ps->disccontext = NULL; |
| @@ -611,6 +612,7 @@ static int usbdev_release(struct inode *inode, struct file *file) | |||
| 611 | usb_autosuspend_device(dev, 1); | 612 | usb_autosuspend_device(dev, 1); |
| 612 | usb_unlock_device(dev); | 613 | usb_unlock_device(dev); |
| 613 | usb_put_dev(dev); | 614 | usb_put_dev(dev); |
| 615 | put_pid(ps->disc_pid); | ||
| 614 | kfree(ps); | 616 | kfree(ps); |
| 615 | return 0; | 617 | return 0; |
| 616 | } | 618 | } |
| @@ -1063,7 +1065,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 1063 | as->userbuffer = NULL; | 1065 | as->userbuffer = NULL; |
| 1064 | as->signr = uurb->signr; | 1066 | as->signr = uurb->signr; |
| 1065 | as->ifnum = ifnum; | 1067 | as->ifnum = ifnum; |
| 1066 | as->pid = current->pid; | 1068 | as->pid = get_pid(task_pid(current)); |
| 1067 | as->uid = current->uid; | 1069 | as->uid = current->uid; |
| 1068 | as->euid = current->euid; | 1070 | as->euid = current->euid; |
| 1069 | security_task_getsecid(current, &as->secid); | 1071 | security_task_getsecid(current, &as->secid); |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 37f9f5e7425d..e658089f7b50 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
| @@ -318,8 +318,8 @@ static int rh_string ( | |||
| 318 | 318 | ||
| 319 | // id 3 == vendor description | 319 | // id 3 == vendor description |
| 320 | } else if (id == 3) { | 320 | } else if (id == 3) { |
| 321 | snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname, | 321 | snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, |
| 322 | system_utsname.release, hcd->driver->description); | 322 | init_utsname()->release, hcd->driver->description); |
| 323 | 323 | ||
| 324 | // unsupported IDs --> "protocol stall" | 324 | // unsupported IDs --> "protocol stall" |
| 325 | } else | 325 | } else |
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 7c77c2d8d300..b5d6a79af0be 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c | |||
| @@ -699,7 +699,7 @@ static void usbfs_remove_device(struct usb_device *dev) | |||
| 699 | sinfo.si_errno = EPIPE; | 699 | sinfo.si_errno = EPIPE; |
| 700 | sinfo.si_code = SI_ASYNCIO; | 700 | sinfo.si_code = SI_ASYNCIO; |
| 701 | sinfo.si_addr = ds->disccontext; | 701 | sinfo.si_addr = ds->disccontext; |
| 702 | kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); | 702 | kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); |
| 703 | } | 703 | } |
| 704 | } | 704 | } |
| 705 | } | 705 | } |
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index f69df137ec0e..13322e33f912 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
| @@ -139,7 +139,7 @@ struct dev_state { | |||
| 139 | struct list_head async_completed; | 139 | struct list_head async_completed; |
| 140 | wait_queue_head_t wait; /* wake up if a request completed */ | 140 | wait_queue_head_t wait; /* wake up if a request completed */ |
| 141 | unsigned int discsignr; | 141 | unsigned int discsignr; |
| 142 | pid_t disc_pid; | 142 | struct pid *disc_pid; |
| 143 | uid_t disc_uid, disc_euid; | 143 | uid_t disc_uid, disc_euid; |
| 144 | void __user *disccontext; | 144 | void __user *disccontext; |
| 145 | unsigned long ifclaimed; | 145 | unsigned long ifclaimed; |
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 366dc0a9e52c..1c17d26d03b8 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c | |||
| @@ -2260,7 +2260,7 @@ eth_bind (struct usb_gadget *gadget) | |||
| 2260 | return -ENODEV; | 2260 | return -ENODEV; |
| 2261 | } | 2261 | } |
| 2262 | snprintf (manufacturer, sizeof manufacturer, "%s %s/%s", | 2262 | snprintf (manufacturer, sizeof manufacturer, "%s %s/%s", |
| 2263 | system_utsname.sysname, system_utsname.release, | 2263 | init_utsname()->sysname, init_utsname()->release, |
| 2264 | gadget->name); | 2264 | gadget->name); |
| 2265 | 2265 | ||
| 2266 | /* If there's an RNDIS configuration, that's what Windows wants to | 2266 | /* If there's an RNDIS configuration, that's what Windows wants to |
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index c83d3b6c68f2..8b975d15538d 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
| @@ -4001,7 +4001,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
| 4001 | usb_gadget_set_selfpowered(gadget); | 4001 | usb_gadget_set_selfpowered(gadget); |
| 4002 | 4002 | ||
| 4003 | snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", | 4003 | snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", |
| 4004 | system_utsname.sysname, system_utsname.release, | 4004 | init_utsname()->sysname, init_utsname()->release, |
| 4005 | gadget->name); | 4005 | gadget->name); |
| 4006 | 4006 | ||
| 4007 | /* On a real device, serial[] would be loaded from permanent | 4007 | /* On a real device, serial[] would be loaded from permanent |
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index b68cecd57411..83601d4009e3 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c | |||
| @@ -1189,7 +1189,7 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget) | |||
| 1189 | strlcpy(manufacturer, iManufacturer, sizeof(manufacturer)); | 1189 | strlcpy(manufacturer, iManufacturer, sizeof(manufacturer)); |
| 1190 | } else { | 1190 | } else { |
| 1191 | snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", | 1191 | snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", |
| 1192 | system_utsname.sysname, system_utsname.release, | 1192 | init_utsname()->sysname, init_utsname()->release, |
| 1193 | gadget->name); | 1193 | gadget->name); |
| 1194 | } | 1194 | } |
| 1195 | if (iProduct) { | 1195 | if (iProduct) { |
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index b893e3118e1b..208e55a667ac 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c | |||
| @@ -271,7 +271,7 @@ static unsigned int use_acm = GS_DEFAULT_USE_ACM; | |||
| 271 | 271 | ||
| 272 | 272 | ||
| 273 | /* tty driver struct */ | 273 | /* tty driver struct */ |
| 274 | static struct tty_operations gs_tty_ops = { | 274 | static const struct tty_operations gs_tty_ops = { |
| 275 | .open = gs_open, | 275 | .open = gs_open, |
| 276 | .close = gs_close, | 276 | .close = gs_close, |
| 277 | .write = gs_write, | 277 | .write = gs_write, |
| @@ -1434,7 +1434,7 @@ static int __init gs_bind(struct usb_gadget *gadget) | |||
| 1434 | return -ENOMEM; | 1434 | return -ENOMEM; |
| 1435 | 1435 | ||
| 1436 | snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", | 1436 | snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", |
| 1437 | system_utsname.sysname, system_utsname.release, | 1437 | init_utsname()->sysname, init_utsname()->release, |
| 1438 | gadget->name); | 1438 | gadget->name); |
| 1439 | 1439 | ||
| 1440 | memset(dev, 0, sizeof(struct gs_dev)); | 1440 | memset(dev, 0, sizeof(struct gs_dev)); |
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index b7018ee487ea..0f809dd68492 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c | |||
| @@ -1242,7 +1242,7 @@ autoconf_fail: | |||
| 1242 | EP_OUT_NAME, EP_IN_NAME); | 1242 | EP_OUT_NAME, EP_IN_NAME); |
| 1243 | 1243 | ||
| 1244 | snprintf (manufacturer, sizeof manufacturer, "%s %s with %s", | 1244 | snprintf (manufacturer, sizeof manufacturer, "%s %s with %s", |
| 1245 | system_utsname.sysname, system_utsname.release, | 1245 | init_utsname()->sysname, init_utsname()->release, |
| 1246 | gadget->name); | 1246 | gadget->name); |
| 1247 | 1247 | ||
| 1248 | return 0; | 1248 | return 0; |
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index a102a58fe361..21cd22640080 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig | |||
| @@ -60,16 +60,17 @@ config HID_FF | |||
| 60 | If unsure, say N. | 60 | If unsure, say N. |
| 61 | 61 | ||
| 62 | config HID_PID | 62 | config HID_PID |
| 63 | bool "PID Devices (Microsoft Sidewinder Force Feedback 2)" | 63 | bool "PID device support" |
| 64 | depends on HID_FF | 64 | depends on HID_FF |
| 65 | help | 65 | help |
| 66 | Say Y here if you have a PID-compliant joystick and wish to enable force | 66 | Say Y here if you have a PID-compliant device and wish to enable force |
| 67 | feedback for it. The Microsoft Sidewinder Force Feedback 2 is one such | 67 | feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such |
| 68 | device. | 68 | devices. |
| 69 | 69 | ||
| 70 | config LOGITECH_FF | 70 | config LOGITECH_FF |
| 71 | bool "Logitech WingMan *3D support" | 71 | bool "Logitech WingMan *3D support" |
| 72 | depends on HID_FF | 72 | depends on HID_FF |
| 73 | select INPUT_FF_MEMLESS if USB_HID | ||
| 73 | help | 74 | help |
| 74 | Say Y here if you have one of these devices: | 75 | Say Y here if you have one of these devices: |
| 75 | - Logitech WingMan Cordless RumblePad | 76 | - Logitech WingMan Cordless RumblePad |
| @@ -81,12 +82,21 @@ config LOGITECH_FF | |||
| 81 | config THRUSTMASTER_FF | 82 | config THRUSTMASTER_FF |
| 82 | bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" | 83 | bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" |
| 83 | depends on HID_FF && EXPERIMENTAL | 84 | depends on HID_FF && EXPERIMENTAL |
| 85 | select INPUT_FF_MEMLESS if USB_HID | ||
| 84 | help | 86 | help |
| 85 | Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, | 87 | Say Y here if you have a THRUSTMASTER FireStore Dual Power 2, |
| 86 | and want to enable force feedback support for it. | 88 | and want to enable force feedback support for it. |
| 87 | Note: if you say N here, this device will still be supported, but without | 89 | Note: if you say N here, this device will still be supported, but without |
| 88 | force feedback. | 90 | force feedback. |
| 89 | 91 | ||
| 92 | config ZEROPLUS_FF | ||
| 93 | bool "Zeroplus based game controller support" | ||
| 94 | depends on HID_FF | ||
| 95 | select INPUT_FF_MEMLESS if USB_HID | ||
| 96 | help | ||
| 97 | Say Y here if you have a Zeroplus based game controller and want to | ||
| 98 | enable force feedback for it. | ||
| 99 | |||
| 90 | config USB_HIDDEV | 100 | config USB_HIDDEV |
| 91 | bool "/dev/hiddev raw HID device support" | 101 | bool "/dev/hiddev raw HID device support" |
| 92 | depends on USB_HID | 102 | depends on USB_HID |
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 48551be324ac..295f459d1079 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile | |||
| @@ -15,7 +15,7 @@ ifeq ($(CONFIG_USB_HIDINPUT),y) | |||
| 15 | usbhid-objs += hid-input.o | 15 | usbhid-objs += hid-input.o |
| 16 | endif | 16 | endif |
| 17 | ifeq ($(CONFIG_HID_PID),y) | 17 | ifeq ($(CONFIG_HID_PID),y) |
| 18 | usbhid-objs += pid.o | 18 | usbhid-objs += hid-pidff.o |
| 19 | endif | 19 | endif |
| 20 | ifeq ($(CONFIG_LOGITECH_FF),y) | 20 | ifeq ($(CONFIG_LOGITECH_FF),y) |
| 21 | usbhid-objs += hid-lgff.o | 21 | usbhid-objs += hid-lgff.o |
| @@ -23,6 +23,9 @@ endif | |||
| 23 | ifeq ($(CONFIG_THRUSTMASTER_FF),y) | 23 | ifeq ($(CONFIG_THRUSTMASTER_FF),y) |
| 24 | usbhid-objs += hid-tmff.o | 24 | usbhid-objs += hid-tmff.o |
| 25 | endif | 25 | endif |
| 26 | ifeq ($(CONFIG_ZEROPLUS_FF),y) | ||
| 27 | usbhid-objs += hid-zpff.o | ||
| 28 | endif | ||
| 26 | ifeq ($(CONFIG_HID_FF),y) | 29 | ifeq ($(CONFIG_HID_FF),y) |
| 27 | usbhid-objs += hid-ff.o | 30 | usbhid-objs += hid-ff.o |
| 28 | endif | 31 | endif |
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 81b1ea01a172..e0fd11605b43 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
| @@ -543,8 +543,6 @@ static void hid_free_device(struct hid_device *device) | |||
| 543 | { | 543 | { |
| 544 | unsigned i,j; | 544 | unsigned i,j; |
| 545 | 545 | ||
| 546 | hid_ff_exit(device); | ||
| 547 | |||
| 548 | for (i = 0; i < HID_REPORT_TYPES; i++) { | 546 | for (i = 0; i < HID_REPORT_TYPES; i++) { |
| 549 | struct hid_report_enum *report_enum = device->report_enum + i; | 547 | struct hid_report_enum *report_enum = device->report_enum + i; |
| 550 | 548 | ||
| @@ -1109,7 +1107,7 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) | |||
| 1109 | /* | 1107 | /* |
| 1110 | * Find a report field with a specified HID usage. | 1108 | * Find a report field with a specified HID usage. |
| 1111 | */ | 1109 | */ |
| 1112 | 1110 | #if 0 | |
| 1113 | struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type) | 1111 | struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type) |
| 1114 | { | 1112 | { |
| 1115 | struct hid_report *report; | 1113 | struct hid_report *report; |
| @@ -1121,6 +1119,7 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u | |||
| 1121 | return report->field[i]; | 1119 | return report->field[i]; |
| 1122 | return NULL; | 1120 | return NULL; |
| 1123 | } | 1121 | } |
| 1122 | #endif /* 0 */ | ||
| 1124 | 1123 | ||
| 1125 | static int hid_submit_out(struct hid_device *hid) | 1124 | static int hid_submit_out(struct hid_device *hid) |
| 1126 | { | 1125 | { |
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index d5c91ee67991..a8fc46c721c5 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c | |||
| @@ -44,45 +44,38 @@ struct hid_ff_initializer { | |||
| 44 | int (*init)(struct hid_device*); | 44 | int (*init)(struct hid_device*); |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | /* | ||
| 48 | * We try pidff when no other driver is found because PID is the | ||
| 49 | * standards compliant way of implementing force feedback in HID. | ||
| 50 | * pidff_init() will quickly abort if the device doesn't appear to | ||
| 51 | * be a PID device | ||
| 52 | */ | ||
| 47 | static struct hid_ff_initializer inits[] = { | 53 | static struct hid_ff_initializer inits[] = { |
| 48 | #ifdef CONFIG_LOGITECH_FF | 54 | #ifdef CONFIG_LOGITECH_FF |
| 49 | {0x46d, 0xc211, hid_lgff_init}, // Logitech Cordless rumble pad | 55 | { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */ |
| 50 | {0x46d, 0xc283, hid_lgff_init}, // Logitech Wingman Force 3d | 56 | { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */ |
| 51 | {0x46d, 0xc295, hid_lgff_init}, // Logitech MOMO force wheel | 57 | { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ |
| 52 | {0x46d, 0xc219, hid_lgff_init}, // Logitech Cordless rumble pad 2 | 58 | { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ |
| 53 | #endif | ||
| 54 | #ifdef CONFIG_HID_PID | ||
| 55 | {0x45e, 0x001b, hid_pid_init}, | ||
| 56 | #endif | 59 | #endif |
| 57 | #ifdef CONFIG_THRUSTMASTER_FF | 60 | #ifdef CONFIG_THRUSTMASTER_FF |
| 58 | {0x44f, 0xb304, hid_tmff_init}, | 61 | { 0x44f, 0xb304, hid_tmff_init }, |
| 59 | #endif | 62 | #endif |
| 60 | {0, 0, NULL} /* Terminating entry */ | 63 | #ifdef CONFIG_ZEROPLUS_FF |
| 64 | { 0xc12, 0x0005, hid_zpff_init }, | ||
| 65 | { 0xc12, 0x0030, hid_zpff_init }, | ||
| 66 | #endif | ||
| 67 | { 0, 0, hid_pidff_init} /* Matches anything */ | ||
| 61 | }; | 68 | }; |
| 62 | 69 | ||
| 63 | static struct hid_ff_initializer *hid_get_ff_init(__u16 idVendor, | ||
| 64 | __u16 idProduct) | ||
| 65 | { | ||
| 66 | struct hid_ff_initializer *init; | ||
| 67 | for (init = inits; | ||
| 68 | init->idVendor | ||
| 69 | && !(init->idVendor == idVendor | ||
| 70 | && init->idProduct == idProduct); | ||
| 71 | init++); | ||
| 72 | |||
| 73 | return init->idVendor? init : NULL; | ||
| 74 | } | ||
| 75 | |||
| 76 | int hid_ff_init(struct hid_device* hid) | 70 | int hid_ff_init(struct hid_device* hid) |
| 77 | { | 71 | { |
| 78 | struct hid_ff_initializer *init; | 72 | struct hid_ff_initializer *init; |
| 73 | int vendor = le16_to_cpu(hid->dev->descriptor.idVendor); | ||
| 74 | int product = le16_to_cpu(hid->dev->descriptor.idProduct); | ||
| 79 | 75 | ||
| 80 | init = hid_get_ff_init(le16_to_cpu(hid->dev->descriptor.idVendor), | 76 | for (init = inits; init->idVendor; init++) |
| 81 | le16_to_cpu(hid->dev->descriptor.idProduct)); | 77 | if (init->idVendor == vendor && init->idProduct == product) |
| 78 | break; | ||
| 82 | 79 | ||
| 83 | if (!init) { | ||
| 84 | dbg("hid_ff_init could not find initializer"); | ||
| 85 | return -ENOSYS; | ||
| 86 | } | ||
| 87 | return init->init(hid); | 80 | return init->init(hid); |
| 88 | } | 81 | } |
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 7208839f2dbf..4c62afbeb430 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c | |||
| @@ -65,11 +65,9 @@ static const struct { | |||
| 65 | #define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0) | 65 | #define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0) |
| 66 | #define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0) | 66 | #define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0) |
| 67 | #define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) | 67 | #define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) |
| 68 | #define map_ff(c) do { usage->code = c; usage->type = EV_FF; bit = input->ffbit; max = FF_MAX; } while (0) | ||
| 69 | 68 | ||
| 70 | #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) | 69 | #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) |
| 71 | #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) | 70 | #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) |
| 72 | #define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0) | ||
| 73 | 71 | ||
| 74 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK | 72 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK |
| 75 | 73 | ||
| @@ -525,23 +523,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 525 | 523 | ||
| 526 | case HID_UP_PID: | 524 | case HID_UP_PID: |
| 527 | 525 | ||
| 528 | set_bit(EV_FF, input->evbit); | ||
| 529 | switch(usage->hid & HID_USAGE) { | 526 | switch(usage->hid & HID_USAGE) { |
| 530 | case 0x26: map_ff_effect(FF_CONSTANT); goto ignore; | ||
| 531 | case 0x27: map_ff_effect(FF_RAMP); goto ignore; | ||
| 532 | case 0x28: map_ff_effect(FF_CUSTOM); goto ignore; | ||
| 533 | case 0x30: map_ff_effect(FF_SQUARE); map_ff_effect(FF_PERIODIC); goto ignore; | ||
| 534 | case 0x31: map_ff_effect(FF_SINE); map_ff_effect(FF_PERIODIC); goto ignore; | ||
| 535 | case 0x32: map_ff_effect(FF_TRIANGLE); map_ff_effect(FF_PERIODIC); goto ignore; | ||
| 536 | case 0x33: map_ff_effect(FF_SAW_UP); map_ff_effect(FF_PERIODIC); goto ignore; | ||
| 537 | case 0x34: map_ff_effect(FF_SAW_DOWN); map_ff_effect(FF_PERIODIC); goto ignore; | ||
| 538 | case 0x40: map_ff_effect(FF_SPRING); goto ignore; | ||
| 539 | case 0x41: map_ff_effect(FF_DAMPER); goto ignore; | ||
| 540 | case 0x42: map_ff_effect(FF_INERTIA); goto ignore; | ||
| 541 | case 0x43: map_ff_effect(FF_FRICTION); goto ignore; | ||
| 542 | case 0x7e: map_ff(FF_GAIN); break; | ||
| 543 | case 0x83: input->ff_effects_max = field->value[0]; goto ignore; | ||
| 544 | case 0x98: map_ff(FF_AUTOCENTER); break; | ||
| 545 | case 0xa4: map_key_clear(BTN_DEAD); break; | 527 | case 0xa4: map_key_clear(BTN_DEAD); break; |
| 546 | default: goto ignore; | 528 | default: goto ignore; |
| 547 | } | 529 | } |
| @@ -698,8 +680,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
| 698 | } | 680 | } |
| 699 | 681 | ||
| 700 | if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ | 682 | if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ |
| 701 | input->ff_effects_max = value; | 683 | dbg("Maximum Effects - %d",value); |
| 702 | dbg("Maximum Effects - %d",input->ff_effects_max); | ||
| 703 | return; | 684 | return; |
| 704 | } | 685 | } |
| 705 | 686 | ||
| @@ -748,7 +729,7 @@ static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsign | |||
| 748 | int offset; | 729 | int offset; |
| 749 | 730 | ||
| 750 | if (type == EV_FF) | 731 | if (type == EV_FF) |
| 751 | return hid_ff_event(hid, dev, type, code, value); | 732 | return input_ff_event(dev, type, code, value); |
| 752 | 733 | ||
| 753 | if (type != EV_LED) | 734 | if (type != EV_LED) |
| 754 | return -1; | 735 | return -1; |
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index f07d44357ff1..93da222b6da8 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c | |||
| @@ -1,12 +1,11 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * $$ | ||
| 3 | * | ||
| 4 | * Force feedback support for hid-compliant for some of the devices from | 2 | * Force feedback support for hid-compliant for some of the devices from |
| 5 | * Logitech, namely: | 3 | * Logitech, namely: |
| 6 | * - WingMan Cordless RumblePad | 4 | * - WingMan Cordless RumblePad |
| 7 | * - WingMan Force 3D | 5 | * - WingMan Force 3D |
| 8 | * | 6 | * |
| 9 | * Copyright (c) 2002-2004 Johann Deneux | 7 | * Copyright (c) 2002-2004 Johann Deneux |
| 8 | * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 10 | */ | 9 | */ |
| 11 | 10 | ||
| 12 | /* | 11 | /* |
| @@ -29,495 +28,117 @@ | |||
| 29 | */ | 28 | */ |
| 30 | 29 | ||
| 31 | #include <linux/input.h> | 30 | #include <linux/input.h> |
| 32 | #include <linux/sched.h> | ||
| 33 | |||
| 34 | //#define DEBUG | ||
| 35 | #include <linux/usb.h> | 31 | #include <linux/usb.h> |
| 36 | |||
| 37 | #include <linux/circ_buf.h> | ||
| 38 | |||
| 39 | #include "hid.h" | 32 | #include "hid.h" |
| 40 | #include "fixp-arith.h" | ||
| 41 | |||
| 42 | |||
| 43 | /* Periodicity of the update */ | ||
| 44 | #define PERIOD (HZ/10) | ||
| 45 | |||
| 46 | #define RUN_AT(t) (jiffies + (t)) | ||
| 47 | |||
| 48 | /* Effect status */ | ||
| 49 | #define EFFECT_STARTED 0 /* Effect is going to play after some time | ||
| 50 | (ff_replay.delay) */ | ||
| 51 | #define EFFECT_PLAYING 1 /* Effect is being played */ | ||
| 52 | #define EFFECT_USED 2 | ||
| 53 | |||
| 54 | // For lgff_device::flags | ||
| 55 | #define DEVICE_CLOSING 0 /* The driver is being unitialised */ | ||
| 56 | |||
| 57 | /* Check that the current process can access an effect */ | ||
| 58 | #define CHECK_OWNERSHIP(effect) (current->pid == 0 \ | ||
| 59 | || effect.owner == current->pid) | ||
| 60 | |||
| 61 | #define LGFF_CHECK_OWNERSHIP(i, l) \ | ||
| 62 | (i>=0 && i<LGFF_EFFECTS \ | ||
| 63 | && test_bit(EFFECT_USED, l->effects[i].flags) \ | ||
| 64 | && CHECK_OWNERSHIP(l->effects[i])) | ||
| 65 | |||
| 66 | #define LGFF_EFFECTS 8 | ||
| 67 | 33 | ||
| 68 | struct device_type { | 34 | struct device_type { |
| 69 | u16 idVendor; | 35 | u16 idVendor; |
| 70 | u16 idProduct; | 36 | u16 idProduct; |
| 71 | signed short *ff; | 37 | const signed short *ff; |
| 72 | }; | ||
| 73 | |||
| 74 | struct lgff_effect { | ||
| 75 | pid_t owner; | ||
| 76 | |||
| 77 | struct ff_effect effect; | ||
| 78 | |||
| 79 | unsigned long flags[1]; | ||
| 80 | unsigned int count; /* Number of times left to play */ | ||
| 81 | unsigned long started_at; /* When the effect started to play */ | ||
| 82 | }; | ||
| 83 | |||
| 84 | struct lgff_device { | ||
| 85 | struct hid_device* hid; | ||
| 86 | |||
| 87 | struct hid_report* constant; | ||
| 88 | struct hid_report* rumble; | ||
| 89 | struct hid_report* condition; | ||
| 90 | |||
| 91 | struct lgff_effect effects[LGFF_EFFECTS]; | ||
| 92 | spinlock_t lock; /* device-level lock. Having locks on | ||
| 93 | a per-effect basis could be nice, but | ||
| 94 | isn't really necessary */ | ||
| 95 | |||
| 96 | unsigned long flags[1]; /* Contains various information about the | ||
| 97 | state of the driver for this device */ | ||
| 98 | |||
| 99 | struct timer_list timer; | ||
| 100 | }; | 38 | }; |
| 101 | 39 | ||
| 102 | /* Callbacks */ | 40 | static const signed short ff_rumble[] = { |
| 103 | static void hid_lgff_exit(struct hid_device* hid); | ||
| 104 | static int hid_lgff_event(struct hid_device *hid, struct input_dev *input, | ||
| 105 | unsigned int type, unsigned int code, int value); | ||
| 106 | static int hid_lgff_flush(struct input_dev *input, struct file *file); | ||
| 107 | static int hid_lgff_upload_effect(struct input_dev *input, | ||
| 108 | struct ff_effect *effect); | ||
| 109 | static int hid_lgff_erase(struct input_dev *input, int id); | ||
| 110 | |||
| 111 | /* Local functions */ | ||
| 112 | static void hid_lgff_input_init(struct hid_device* hid); | ||
| 113 | static void hid_lgff_timer(unsigned long timer_data); | ||
| 114 | static struct hid_report* hid_lgff_duplicate_report(struct hid_report*); | ||
| 115 | static void hid_lgff_delete_report(struct hid_report*); | ||
| 116 | |||
| 117 | static signed short ff_rumble[] = { | ||
| 118 | FF_RUMBLE, | 41 | FF_RUMBLE, |
| 119 | -1 | 42 | -1 |
| 120 | }; | 43 | }; |
| 121 | 44 | ||
| 122 | static signed short ff_joystick[] = { | 45 | static const signed short ff_joystick[] = { |
| 123 | FF_CONSTANT, | 46 | FF_CONSTANT, |
| 124 | -1 | 47 | -1 |
| 125 | }; | 48 | }; |
| 126 | 49 | ||
| 127 | static struct device_type devices[] = { | 50 | static const struct device_type devices[] = { |
| 128 | {0x046d, 0xc211, ff_rumble}, | 51 | { 0x046d, 0xc211, ff_rumble }, |
| 129 | {0x046d, 0xc219, ff_rumble}, | 52 | { 0x046d, 0xc219, ff_rumble }, |
| 130 | {0x046d, 0xc283, ff_joystick}, | 53 | { 0x046d, 0xc283, ff_joystick }, |
| 131 | {0x0000, 0x0000, ff_joystick} | 54 | { 0x0000, 0x0000, ff_joystick } |
| 132 | }; | 55 | }; |
| 133 | 56 | ||
| 57 | static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | ||
| 58 | { | ||
| 59 | struct hid_device *hid = dev->private; | ||
| 60 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 61 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | ||
| 62 | int x, y; | ||
| 63 | unsigned int left, right; | ||
| 64 | |||
| 65 | #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff | ||
| 66 | |||
| 67 | switch (effect->type) { | ||
| 68 | case FF_CONSTANT: | ||
| 69 | x = effect->u.ramp.start_level + 0x7f; /* 0x7f is center */ | ||
| 70 | y = effect->u.ramp.end_level + 0x7f; | ||
| 71 | CLAMP(x); | ||
| 72 | CLAMP(y); | ||
| 73 | report->field[0]->value[0] = 0x51; | ||
| 74 | report->field[0]->value[1] = 0x08; | ||
| 75 | report->field[0]->value[2] = x; | ||
| 76 | report->field[0]->value[3] = y; | ||
| 77 | dbg("(x, y)=(%04x, %04x)", x, y); | ||
| 78 | hid_submit_report(hid, report, USB_DIR_OUT); | ||
| 79 | break; | ||
| 80 | |||
| 81 | case FF_RUMBLE: | ||
| 82 | right = effect->u.rumble.strong_magnitude; | ||
| 83 | left = effect->u.rumble.weak_magnitude; | ||
| 84 | right = right * 0xff / 0xffff; | ||
| 85 | left = left * 0xff / 0xffff; | ||
| 86 | CLAMP(left); | ||
| 87 | CLAMP(right); | ||
| 88 | report->field[0]->value[0] = 0x42; | ||
| 89 | report->field[0]->value[1] = 0x00; | ||
| 90 | report->field[0]->value[2] = left; | ||
| 91 | report->field[0]->value[3] = right; | ||
| 92 | dbg("(left, right)=(%04x, %04x)", left, right); | ||
| 93 | hid_submit_report(hid, report, USB_DIR_OUT); | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 134 | int hid_lgff_init(struct hid_device* hid) | 99 | int hid_lgff_init(struct hid_device* hid) |
| 135 | { | 100 | { |
| 136 | struct lgff_device *private; | 101 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); |
| 137 | struct hid_report* report; | 102 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
| 138 | struct hid_field* field; | 103 | struct input_dev *dev = hidinput->input; |
| 104 | struct hid_report *report; | ||
| 105 | struct hid_field *field; | ||
| 106 | int error; | ||
| 107 | int i, j; | ||
| 139 | 108 | ||
| 140 | /* Find the report to use */ | 109 | /* Find the report to use */ |
| 141 | if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) { | 110 | if (list_empty(report_list)) { |
| 142 | err("No output report found"); | 111 | err("No output report found"); |
| 143 | return -1; | 112 | return -1; |
| 144 | } | 113 | } |
| 114 | |||
| 145 | /* Check that the report looks ok */ | 115 | /* Check that the report looks ok */ |
| 146 | report = (struct hid_report*)hid->report_enum[HID_OUTPUT_REPORT].report_list.next; | 116 | report = list_entry(report_list->next, struct hid_report, list); |
| 147 | if (!report) { | 117 | if (!report) { |
| 148 | err("NULL output report"); | 118 | err("NULL output report"); |
| 149 | return -1; | 119 | return -1; |
| 150 | } | 120 | } |
| 121 | |||
| 151 | field = report->field[0]; | 122 | field = report->field[0]; |
| 152 | if (!field) { | 123 | if (!field) { |
| 153 | err("NULL field"); | 124 | err("NULL field"); |
| 154 | return -1; | 125 | return -1; |
| 155 | } | 126 | } |
| 156 | 127 | ||
| 157 | private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL); | 128 | for (i = 0; i < ARRAY_SIZE(devices); i++) { |
| 158 | if (!private) | 129 | if (dev->id.vendor == devices[i].idVendor && |
| 159 | return -1; | 130 | dev->id.product == devices[i].idProduct) { |
| 160 | hid->ff_private = private; | 131 | for (j = 0; devices[i].ff[j] >= 0; j++) |
| 161 | 132 | set_bit(devices[i].ff[j], dev->ffbit); | |
| 162 | /* Input init */ | 133 | break; |
| 163 | hid_lgff_input_init(hid); | ||
| 164 | |||
| 165 | |||
| 166 | private->constant = hid_lgff_duplicate_report(report); | ||
| 167 | if (!private->constant) { | ||
| 168 | kfree(private); | ||
| 169 | return -1; | ||
| 170 | } | ||
| 171 | private->constant->field[0]->value[0] = 0x51; | ||
| 172 | private->constant->field[0]->value[1] = 0x08; | ||
| 173 | private->constant->field[0]->value[2] = 0x7f; | ||
| 174 | private->constant->field[0]->value[3] = 0x7f; | ||
| 175 | |||
| 176 | private->rumble = hid_lgff_duplicate_report(report); | ||
| 177 | if (!private->rumble) { | ||
| 178 | hid_lgff_delete_report(private->constant); | ||
| 179 | kfree(private); | ||
| 180 | return -1; | ||
| 181 | } | ||
| 182 | private->rumble->field[0]->value[0] = 0x42; | ||
| 183 | |||
| 184 | |||
| 185 | private->condition = hid_lgff_duplicate_report(report); | ||
| 186 | if (!private->condition) { | ||
| 187 | hid_lgff_delete_report(private->rumble); | ||
| 188 | hid_lgff_delete_report(private->constant); | ||
| 189 | kfree(private); | ||
| 190 | return -1; | ||
| 191 | } | ||
| 192 | |||
| 193 | private->hid = hid; | ||
| 194 | |||
| 195 | spin_lock_init(&private->lock); | ||
| 196 | init_timer(&private->timer); | ||
| 197 | private->timer.data = (unsigned long)private; | ||
| 198 | private->timer.function = hid_lgff_timer; | ||
| 199 | |||
| 200 | /* Event and exit callbacks */ | ||
| 201 | hid->ff_exit = hid_lgff_exit; | ||
| 202 | hid->ff_event = hid_lgff_event; | ||
| 203 | |||
| 204 | /* Start the update task */ | ||
| 205 | private->timer.expires = RUN_AT(PERIOD); | ||
| 206 | add_timer(&private->timer); /*TODO: only run the timer when at least | ||
| 207 | one effect is playing */ | ||
| 208 | |||
| 209 | printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n"); | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 214 | static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report) | ||
| 215 | { | ||
| 216 | struct hid_report* ret; | ||
| 217 | |||
| 218 | ret = kmalloc(sizeof(struct lgff_device), GFP_KERNEL); | ||
| 219 | if (!ret) | ||
| 220 | return NULL; | ||
| 221 | *ret = *report; | ||
| 222 | |||
| 223 | ret->field[0] = kmalloc(sizeof(struct hid_field), GFP_KERNEL); | ||
| 224 | if (!ret->field[0]) { | ||
| 225 | kfree(ret); | ||
| 226 | return NULL; | ||
| 227 | } | ||
| 228 | *ret->field[0] = *report->field[0]; | ||
| 229 | |||
| 230 | ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL); | ||
| 231 | if (!ret->field[0]->value) { | ||
| 232 | kfree(ret->field[0]); | ||
| 233 | kfree(ret); | ||
| 234 | return NULL; | ||
| 235 | } | ||
| 236 | |||
| 237 | return ret; | ||
| 238 | } | ||
| 239 | |||
| 240 | static void hid_lgff_delete_report(struct hid_report* report) | ||
| 241 | { | ||
| 242 | if (report) { | ||
| 243 | kfree(report->field[0]->value); | ||
| 244 | kfree(report->field[0]); | ||
| 245 | kfree(report); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | static void hid_lgff_input_init(struct hid_device* hid) | ||
| 250 | { | ||
| 251 | struct device_type* dev = devices; | ||
| 252 | signed short* ff; | ||
| 253 | u16 idVendor = le16_to_cpu(hid->dev->descriptor.idVendor); | ||
| 254 | u16 idProduct = le16_to_cpu(hid->dev->descriptor.idProduct); | ||
| 255 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
| 256 | struct input_dev *input_dev = hidinput->input; | ||
| 257 | |||
| 258 | while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct)) | ||
| 259 | dev++; | ||
| 260 | |||
| 261 | for (ff = dev->ff; *ff >= 0; ff++) | ||
| 262 | set_bit(*ff, input_dev->ffbit); | ||
| 263 | |||
| 264 | input_dev->upload_effect = hid_lgff_upload_effect; | ||
| 265 | input_dev->flush = hid_lgff_flush; | ||
| 266 | |||
| 267 | set_bit(EV_FF, input_dev->evbit); | ||
| 268 | input_dev->ff_effects_max = LGFF_EFFECTS; | ||
| 269 | } | ||
| 270 | |||
| 271 | static void hid_lgff_exit(struct hid_device* hid) | ||
| 272 | { | ||
| 273 | struct lgff_device *lgff = hid->ff_private; | ||
| 274 | |||
| 275 | set_bit(DEVICE_CLOSING, lgff->flags); | ||
| 276 | del_timer_sync(&lgff->timer); | ||
| 277 | |||
| 278 | hid_lgff_delete_report(lgff->condition); | ||
| 279 | hid_lgff_delete_report(lgff->rumble); | ||
| 280 | hid_lgff_delete_report(lgff->constant); | ||
| 281 | |||
| 282 | kfree(lgff); | ||
| 283 | } | ||
| 284 | |||
| 285 | static int hid_lgff_event(struct hid_device *hid, struct input_dev* input, | ||
| 286 | unsigned int type, unsigned int code, int value) | ||
| 287 | { | ||
| 288 | struct lgff_device *lgff = hid->ff_private; | ||
| 289 | struct lgff_effect *effect = lgff->effects + code; | ||
| 290 | unsigned long flags; | ||
| 291 | |||
| 292 | if (type != EV_FF) return -EINVAL; | ||
| 293 | if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES; | ||
| 294 | if (value < 0) return -EINVAL; | ||
| 295 | |||
| 296 | spin_lock_irqsave(&lgff->lock, flags); | ||
| 297 | |||
| 298 | if (value > 0) { | ||
| 299 | if (test_bit(EFFECT_STARTED, effect->flags)) { | ||
| 300 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 301 | return -EBUSY; | ||
| 302 | } | ||
| 303 | if (test_bit(EFFECT_PLAYING, effect->flags)) { | ||
| 304 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 305 | return -EBUSY; | ||
| 306 | } | ||
| 307 | |||
| 308 | effect->count = value; | ||
| 309 | |||
| 310 | if (effect->effect.replay.delay) { | ||
| 311 | set_bit(EFFECT_STARTED, effect->flags); | ||
| 312 | } else { | ||
| 313 | set_bit(EFFECT_PLAYING, effect->flags); | ||
| 314 | } | ||
| 315 | effect->started_at = jiffies; | ||
| 316 | } | ||
| 317 | else { /* value == 0 */ | ||
| 318 | clear_bit(EFFECT_STARTED, effect->flags); | ||
| 319 | clear_bit(EFFECT_PLAYING, effect->flags); | ||
| 320 | } | ||
| 321 | |||
| 322 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 323 | |||
| 324 | return 0; | ||
| 325 | |||
| 326 | } | ||
| 327 | |||
| 328 | /* Erase all effects this process owns */ | ||
| 329 | static int hid_lgff_flush(struct input_dev *dev, struct file *file) | ||
| 330 | { | ||
| 331 | struct hid_device *hid = dev->private; | ||
| 332 | struct lgff_device *lgff = hid->ff_private; | ||
| 333 | int i; | ||
| 334 | |||
| 335 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
| 336 | |||
| 337 | /*NOTE: no need to lock here. The only times EFFECT_USED is | ||
| 338 | modified is when effects are uploaded or when an effect is | ||
| 339 | erased. But a process cannot close its dev/input/eventX fd | ||
| 340 | and perform ioctls on the same fd all at the same time */ | ||
| 341 | if ( current->pid == lgff->effects[i].owner | ||
| 342 | && test_bit(EFFECT_USED, lgff->effects[i].flags)) { | ||
| 343 | |||
| 344 | if (hid_lgff_erase(dev, i)) | ||
| 345 | warn("erase effect %d failed", i); | ||
| 346 | } | ||
| 347 | |||
| 348 | } | ||
| 349 | |||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int hid_lgff_erase(struct input_dev *dev, int id) | ||
| 354 | { | ||
| 355 | struct hid_device *hid = dev->private; | ||
| 356 | struct lgff_device *lgff = hid->ff_private; | ||
| 357 | unsigned long flags; | ||
| 358 | |||
| 359 | if (!LGFF_CHECK_OWNERSHIP(id, lgff)) return -EACCES; | ||
| 360 | |||
| 361 | spin_lock_irqsave(&lgff->lock, flags); | ||
| 362 | lgff->effects[id].flags[0] = 0; | ||
| 363 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | static int hid_lgff_upload_effect(struct input_dev* input, | ||
| 369 | struct ff_effect* effect) | ||
| 370 | { | ||
| 371 | struct hid_device *hid = input->private; | ||
| 372 | struct lgff_device *lgff = hid->ff_private; | ||
| 373 | struct lgff_effect new; | ||
| 374 | int id; | ||
| 375 | unsigned long flags; | ||
| 376 | |||
| 377 | dbg("ioctl rumble"); | ||
| 378 | |||
| 379 | if (!test_bit(effect->type, input->ffbit)) return -EINVAL; | ||
| 380 | |||
| 381 | spin_lock_irqsave(&lgff->lock, flags); | ||
| 382 | |||
| 383 | if (effect->id == -1) { | ||
| 384 | int i; | ||
| 385 | |||
| 386 | for (i=0; i<LGFF_EFFECTS && test_bit(EFFECT_USED, lgff->effects[i].flags); ++i); | ||
| 387 | if (i >= LGFF_EFFECTS) { | ||
| 388 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 389 | return -ENOSPC; | ||
| 390 | } | 134 | } |
| 391 | |||
| 392 | effect->id = i; | ||
| 393 | lgff->effects[i].owner = current->pid; | ||
| 394 | lgff->effects[i].flags[0] = 0; | ||
| 395 | set_bit(EFFECT_USED, lgff->effects[i].flags); | ||
| 396 | } | 135 | } |
| 397 | else if (!LGFF_CHECK_OWNERSHIP(effect->id, lgff)) { | ||
| 398 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 399 | return -EACCES; | ||
| 400 | } | ||
| 401 | |||
| 402 | id = effect->id; | ||
| 403 | new = lgff->effects[id]; | ||
| 404 | |||
| 405 | new.effect = *effect; | ||
| 406 | |||
| 407 | if (test_bit(EFFECT_STARTED, lgff->effects[id].flags) | ||
| 408 | || test_bit(EFFECT_STARTED, lgff->effects[id].flags)) { | ||
| 409 | |||
| 410 | /* Changing replay parameters is not allowed (for the time | ||
| 411 | being) */ | ||
| 412 | if (new.effect.replay.delay != lgff->effects[id].effect.replay.delay | ||
| 413 | || new.effect.replay.length != lgff->effects[id].effect.replay.length) { | ||
| 414 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 415 | return -ENOSYS; | ||
| 416 | } | ||
| 417 | 136 | ||
| 418 | lgff->effects[id] = new; | 137 | error = input_ff_create_memless(dev, NULL, hid_lgff_play); |
| 138 | if (error) | ||
| 139 | return error; | ||
| 419 | 140 | ||
| 420 | } else { | 141 | printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n"); |
| 421 | lgff->effects[id] = new; | ||
| 422 | } | ||
| 423 | 142 | ||
| 424 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 425 | return 0; | 143 | return 0; |
| 426 | } | 144 | } |
| 427 | |||
| 428 | static void hid_lgff_timer(unsigned long timer_data) | ||
| 429 | { | ||
| 430 | struct lgff_device *lgff = (struct lgff_device*)timer_data; | ||
| 431 | struct hid_device *hid = lgff->hid; | ||
| 432 | unsigned long flags; | ||
| 433 | int x = 0x7f, y = 0x7f; // Coordinates of constant effects | ||
| 434 | unsigned int left = 0, right = 0; // Rumbling | ||
| 435 | int i; | ||
| 436 | |||
| 437 | spin_lock_irqsave(&lgff->lock, flags); | ||
| 438 | |||
| 439 | for (i=0; i<LGFF_EFFECTS; ++i) { | ||
| 440 | struct lgff_effect* effect = lgff->effects +i; | ||
| 441 | |||
| 442 | if (test_bit(EFFECT_PLAYING, effect->flags)) { | ||
| 443 | |||
| 444 | switch (effect->effect.type) { | ||
| 445 | case FF_CONSTANT: { | ||
| 446 | //TODO: handle envelopes | ||
| 447 | int degrees = effect->effect.direction * 360 >> 16; | ||
| 448 | x += fixp_mult(fixp_sin(degrees), | ||
| 449 | fixp_new16(effect->effect.u.constant.level)); | ||
| 450 | y += fixp_mult(-fixp_cos(degrees), | ||
| 451 | fixp_new16(effect->effect.u.constant.level)); | ||
| 452 | } break; | ||
| 453 | case FF_RUMBLE: | ||
| 454 | right += effect->effect.u.rumble.strong_magnitude; | ||
| 455 | left += effect->effect.u.rumble.weak_magnitude; | ||
| 456 | break; | ||
| 457 | }; | ||
| 458 | |||
| 459 | /* One run of the effect is finished playing */ | ||
| 460 | if (time_after(jiffies, | ||
| 461 | effect->started_at | ||
| 462 | + effect->effect.replay.delay*HZ/1000 | ||
| 463 | + effect->effect.replay.length*HZ/1000)) { | ||
| 464 | dbg("Finished playing once %d", i); | ||
| 465 | if (--effect->count <= 0) { | ||
| 466 | dbg("Stopped %d", i); | ||
| 467 | clear_bit(EFFECT_PLAYING, effect->flags); | ||
| 468 | } | ||
| 469 | else { | ||
| 470 | dbg("Start again %d", i); | ||
| 471 | if (effect->effect.replay.length != 0) { | ||
| 472 | clear_bit(EFFECT_PLAYING, effect->flags); | ||
| 473 | set_bit(EFFECT_STARTED, effect->flags); | ||
| 474 | } | ||
| 475 | effect->started_at = jiffies; | ||
| 476 | } | ||
| 477 | } | ||
| 478 | |||
| 479 | } else if (test_bit(EFFECT_STARTED, lgff->effects[i].flags)) { | ||
| 480 | /* Check if we should start playing the effect */ | ||
| 481 | if (time_after(jiffies, | ||
| 482 | lgff->effects[i].started_at | ||
| 483 | + lgff->effects[i].effect.replay.delay*HZ/1000)) { | ||
| 484 | dbg("Now playing %d", i); | ||
| 485 | clear_bit(EFFECT_STARTED, lgff->effects[i].flags); | ||
| 486 | set_bit(EFFECT_PLAYING, lgff->effects[i].flags); | ||
| 487 | } | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | #define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff | ||
| 492 | |||
| 493 | // Clamp values | ||
| 494 | CLAMP(x); | ||
| 495 | CLAMP(y); | ||
| 496 | CLAMP(left); | ||
| 497 | CLAMP(right); | ||
| 498 | |||
| 499 | #undef CLAMP | ||
| 500 | |||
| 501 | if (x != lgff->constant->field[0]->value[2] | ||
| 502 | || y != lgff->constant->field[0]->value[3]) { | ||
| 503 | lgff->constant->field[0]->value[2] = x; | ||
| 504 | lgff->constant->field[0]->value[3] = y; | ||
| 505 | dbg("(x,y)=(%04x, %04x)", x, y); | ||
| 506 | hid_submit_report(hid, lgff->constant, USB_DIR_OUT); | ||
| 507 | } | ||
| 508 | |||
| 509 | if (left != lgff->rumble->field[0]->value[2] | ||
| 510 | || right != lgff->rumble->field[0]->value[3]) { | ||
| 511 | lgff->rumble->field[0]->value[2] = left; | ||
| 512 | lgff->rumble->field[0]->value[3] = right; | ||
| 513 | dbg("(left,right)=(%04x, %04x)", left, right); | ||
| 514 | hid_submit_report(hid, lgff->rumble, USB_DIR_OUT); | ||
| 515 | } | ||
| 516 | |||
| 517 | if (!test_bit(DEVICE_CLOSING, lgff->flags)) { | ||
| 518 | lgff->timer.expires = RUN_AT(PERIOD); | ||
| 519 | add_timer(&lgff->timer); | ||
| 520 | } | ||
| 521 | |||
| 522 | spin_unlock_irqrestore(&lgff->lock, flags); | ||
| 523 | } | ||
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c new file mode 100644 index 000000000000..5420c13eb8eb --- /dev/null +++ b/drivers/usb/input/hid-pidff.c | |||
| @@ -0,0 +1,1330 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback driver for USB HID PID compliant devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* #define DEBUG */ | ||
| 24 | |||
| 25 | #define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg) | ||
| 26 | |||
| 27 | #include <linux/sched.h> | ||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/usb.h> | ||
| 30 | |||
| 31 | #include "hid.h" | ||
| 32 | |||
| 33 | #define PID_EFFECTS_MAX 64 | ||
| 34 | |||
| 35 | /* Report usage table used to put reports into an array */ | ||
| 36 | |||
| 37 | #define PID_SET_EFFECT 0 | ||
| 38 | #define PID_EFFECT_OPERATION 1 | ||
| 39 | #define PID_DEVICE_GAIN 2 | ||
| 40 | #define PID_POOL 3 | ||
| 41 | #define PID_BLOCK_LOAD 4 | ||
| 42 | #define PID_BLOCK_FREE 5 | ||
| 43 | #define PID_DEVICE_CONTROL 6 | ||
| 44 | #define PID_CREATE_NEW_EFFECT 7 | ||
| 45 | |||
| 46 | #define PID_REQUIRED_REPORTS 7 | ||
| 47 | |||
| 48 | #define PID_SET_ENVELOPE 8 | ||
| 49 | #define PID_SET_CONDITION 9 | ||
| 50 | #define PID_SET_PERIODIC 10 | ||
| 51 | #define PID_SET_CONSTANT 11 | ||
| 52 | #define PID_SET_RAMP 12 | ||
| 53 | static const u8 pidff_reports[] = { | ||
| 54 | 0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab, | ||
| 55 | 0x5a, 0x5f, 0x6e, 0x73, 0x74 | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* device_control is really 0x95, but 0x96 specified as it is the usage of | ||
| 59 | the only field in that report */ | ||
| 60 | |||
| 61 | /* Value usage tables used to put fields and values into arrays */ | ||
| 62 | |||
| 63 | #define PID_EFFECT_BLOCK_INDEX 0 | ||
| 64 | |||
| 65 | #define PID_DURATION 1 | ||
| 66 | #define PID_GAIN 2 | ||
| 67 | #define PID_TRIGGER_BUTTON 3 | ||
| 68 | #define PID_TRIGGER_REPEAT_INT 4 | ||
| 69 | #define PID_DIRECTION_ENABLE 5 | ||
| 70 | #define PID_START_DELAY 6 | ||
| 71 | static const u8 pidff_set_effect[] = { | ||
| 72 | 0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7 | ||
| 73 | }; | ||
| 74 | |||
| 75 | #define PID_ATTACK_LEVEL 1 | ||
| 76 | #define PID_ATTACK_TIME 2 | ||
| 77 | #define PID_FADE_LEVEL 3 | ||
| 78 | #define PID_FADE_TIME 4 | ||
| 79 | static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e }; | ||
| 80 | |||
| 81 | #define PID_PARAM_BLOCK_OFFSET 1 | ||
| 82 | #define PID_CP_OFFSET 2 | ||
| 83 | #define PID_POS_COEFFICIENT 3 | ||
| 84 | #define PID_NEG_COEFFICIENT 4 | ||
| 85 | #define PID_POS_SATURATION 5 | ||
| 86 | #define PID_NEG_SATURATION 6 | ||
| 87 | #define PID_DEAD_BAND 7 | ||
| 88 | static const u8 pidff_set_condition[] = { | ||
| 89 | 0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65 | ||
| 90 | }; | ||
| 91 | |||
| 92 | #define PID_MAGNITUDE 1 | ||
| 93 | #define PID_OFFSET 2 | ||
| 94 | #define PID_PHASE 3 | ||
| 95 | #define PID_PERIOD 4 | ||
| 96 | static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 }; | ||
| 97 | static const u8 pidff_set_constant[] = { 0x22, 0x70 }; | ||
| 98 | |||
| 99 | #define PID_RAMP_START 1 | ||
| 100 | #define PID_RAMP_END 2 | ||
| 101 | static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 }; | ||
| 102 | |||
| 103 | #define PID_RAM_POOL_AVAILABLE 1 | ||
| 104 | static const u8 pidff_block_load[] = { 0x22, 0xac }; | ||
| 105 | |||
| 106 | #define PID_LOOP_COUNT 1 | ||
| 107 | static const u8 pidff_effect_operation[] = { 0x22, 0x7c }; | ||
| 108 | |||
| 109 | static const u8 pidff_block_free[] = { 0x22 }; | ||
| 110 | |||
| 111 | #define PID_DEVICE_GAIN_FIELD 0 | ||
| 112 | static const u8 pidff_device_gain[] = { 0x7e }; | ||
| 113 | |||
| 114 | #define PID_RAM_POOL_SIZE 0 | ||
| 115 | #define PID_SIMULTANEOUS_MAX 1 | ||
| 116 | #define PID_DEVICE_MANAGED_POOL 2 | ||
| 117 | static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 }; | ||
| 118 | |||
| 119 | /* Special field key tables used to put special field keys into arrays */ | ||
| 120 | |||
| 121 | #define PID_ENABLE_ACTUATORS 0 | ||
| 122 | #define PID_RESET 1 | ||
| 123 | static const u8 pidff_device_control[] = { 0x97, 0x9a }; | ||
| 124 | |||
| 125 | #define PID_CONSTANT 0 | ||
| 126 | #define PID_RAMP 1 | ||
| 127 | #define PID_SQUARE 2 | ||
| 128 | #define PID_SINE 3 | ||
| 129 | #define PID_TRIANGLE 4 | ||
| 130 | #define PID_SAW_UP 5 | ||
| 131 | #define PID_SAW_DOWN 6 | ||
| 132 | #define PID_SPRING 7 | ||
| 133 | #define PID_DAMPER 8 | ||
| 134 | #define PID_INERTIA 9 | ||
| 135 | #define PID_FRICTION 10 | ||
| 136 | static const u8 pidff_effect_types[] = { | ||
| 137 | 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, | ||
| 138 | 0x40, 0x41, 0x42, 0x43 | ||
| 139 | }; | ||
| 140 | |||
| 141 | #define PID_BLOCK_LOAD_SUCCESS 0 | ||
| 142 | #define PID_BLOCK_LOAD_FULL 1 | ||
| 143 | static const u8 pidff_block_load_status[] = { 0x8c, 0x8d }; | ||
| 144 | |||
| 145 | #define PID_EFFECT_START 0 | ||
| 146 | #define PID_EFFECT_STOP 1 | ||
| 147 | static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b }; | ||
| 148 | |||
| 149 | struct pidff_usage { | ||
| 150 | struct hid_field *field; | ||
| 151 | s32 *value; | ||
| 152 | }; | ||
| 153 | |||
| 154 | struct pidff_device { | ||
| 155 | struct hid_device *hid; | ||
| 156 | |||
| 157 | struct hid_report *reports[sizeof(pidff_reports)]; | ||
| 158 | |||
| 159 | struct pidff_usage set_effect[sizeof(pidff_set_effect)]; | ||
| 160 | struct pidff_usage set_envelope[sizeof(pidff_set_envelope)]; | ||
| 161 | struct pidff_usage set_condition[sizeof(pidff_set_condition)]; | ||
| 162 | struct pidff_usage set_periodic[sizeof(pidff_set_periodic)]; | ||
| 163 | struct pidff_usage set_constant[sizeof(pidff_set_constant)]; | ||
| 164 | struct pidff_usage set_ramp[sizeof(pidff_set_ramp)]; | ||
| 165 | |||
| 166 | struct pidff_usage device_gain[sizeof(pidff_device_gain)]; | ||
| 167 | struct pidff_usage block_load[sizeof(pidff_block_load)]; | ||
| 168 | struct pidff_usage pool[sizeof(pidff_pool)]; | ||
| 169 | struct pidff_usage effect_operation[sizeof(pidff_effect_operation)]; | ||
| 170 | struct pidff_usage block_free[sizeof(pidff_block_free)]; | ||
| 171 | |||
| 172 | /* Special field is a field that is not composed of | ||
| 173 | usage<->value pairs that pidff_usage values are */ | ||
| 174 | |||
| 175 | /* Special field in create_new_effect */ | ||
| 176 | struct hid_field *create_new_effect_type; | ||
| 177 | |||
| 178 | /* Special fields in set_effect */ | ||
| 179 | struct hid_field *set_effect_type; | ||
| 180 | struct hid_field *effect_direction; | ||
| 181 | |||
| 182 | /* Special field in device_control */ | ||
| 183 | struct hid_field *device_control; | ||
| 184 | |||
| 185 | /* Special field in block_load */ | ||
| 186 | struct hid_field *block_load_status; | ||
| 187 | |||
| 188 | /* Special field in effect_operation */ | ||
| 189 | struct hid_field *effect_operation_status; | ||
| 190 | |||
| 191 | int control_id[sizeof(pidff_device_control)]; | ||
| 192 | int type_id[sizeof(pidff_effect_types)]; | ||
| 193 | int status_id[sizeof(pidff_block_load_status)]; | ||
| 194 | int operation_id[sizeof(pidff_effect_operation_status)]; | ||
| 195 | |||
| 196 | int pid_id[PID_EFFECTS_MAX]; | ||
| 197 | }; | ||
| 198 | |||
| 199 | /* | ||
| 200 | * Scale an unsigned value with range 0..max for the given field | ||
| 201 | */ | ||
| 202 | static int pidff_rescale(int i, int max, struct hid_field *field) | ||
| 203 | { | ||
| 204 | return i * (field->logical_maximum - field->logical_minimum) / max + | ||
| 205 | field->logical_minimum; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Scale a signed value in range -0x8000..0x7fff for the given field | ||
| 210 | */ | ||
| 211 | static int pidff_rescale_signed(int i, struct hid_field *field) | ||
| 212 | { | ||
| 213 | return i == 0 ? 0 : i > | ||
| 214 | 0 ? i * field->logical_maximum / 0x7fff : i * | ||
| 215 | field->logical_minimum / -0x8000; | ||
| 216 | } | ||
| 217 | |||
| 218 | static void pidff_set(struct pidff_usage *usage, u16 value) | ||
| 219 | { | ||
| 220 | usage->value[0] = pidff_rescale(value, 0xffff, usage->field); | ||
| 221 | debug("calculated from %d to %d", value, usage->value[0]); | ||
| 222 | } | ||
| 223 | |||
| 224 | static void pidff_set_signed(struct pidff_usage *usage, s16 value) | ||
| 225 | { | ||
| 226 | if (usage->field->logical_minimum < 0) | ||
| 227 | usage->value[0] = pidff_rescale_signed(value, usage->field); | ||
| 228 | else { | ||
| 229 | if (value < 0) | ||
| 230 | usage->value[0] = | ||
| 231 | pidff_rescale(-value, 0x8000, usage->field); | ||
| 232 | else | ||
| 233 | usage->value[0] = | ||
| 234 | pidff_rescale(value, 0x7fff, usage->field); | ||
| 235 | } | ||
| 236 | debug("calculated from %d to %d", value, usage->value[0]); | ||
| 237 | } | ||
| 238 | |||
| 239 | /* | ||
| 240 | * Send envelope report to the device | ||
| 241 | */ | ||
| 242 | static void pidff_set_envelope_report(struct pidff_device *pidff, | ||
| 243 | struct ff_envelope *envelope) | ||
| 244 | { | ||
| 245 | pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 246 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 247 | |||
| 248 | pidff->set_envelope[PID_ATTACK_LEVEL].value[0] = | ||
| 249 | pidff_rescale(envelope->attack_level > | ||
| 250 | 0x7fff ? 0x7fff : envelope->attack_level, 0x7fff, | ||
| 251 | pidff->set_envelope[PID_ATTACK_LEVEL].field); | ||
| 252 | pidff->set_envelope[PID_FADE_LEVEL].value[0] = | ||
| 253 | pidff_rescale(envelope->fade_level > | ||
| 254 | 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff, | ||
| 255 | pidff->set_envelope[PID_FADE_LEVEL].field); | ||
| 256 | |||
| 257 | pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length; | ||
| 258 | pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length; | ||
| 259 | |||
| 260 | debug("attack %u => %d", envelope->attack_level, | ||
| 261 | pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); | ||
| 262 | |||
| 263 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], | ||
| 264 | USB_DIR_OUT); | ||
| 265 | } | ||
| 266 | |||
| 267 | /* | ||
| 268 | * Test if the new envelope differs from old one | ||
| 269 | */ | ||
| 270 | static int pidff_needs_set_envelope(struct ff_envelope *envelope, | ||
| 271 | struct ff_envelope *old) | ||
| 272 | { | ||
| 273 | return envelope->attack_level != old->attack_level || | ||
| 274 | envelope->fade_level != old->fade_level || | ||
| 275 | envelope->attack_length != old->attack_length || | ||
| 276 | envelope->fade_length != old->fade_length; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* | ||
| 280 | * Send constant force report to the device | ||
| 281 | */ | ||
| 282 | static void pidff_set_constant_force_report(struct pidff_device *pidff, | ||
| 283 | struct ff_effect *effect) | ||
| 284 | { | ||
| 285 | pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 286 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 287 | pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE], | ||
| 288 | effect->u.constant.level); | ||
| 289 | |||
| 290 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], | ||
| 291 | USB_DIR_OUT); | ||
| 292 | } | ||
| 293 | |||
| 294 | /* | ||
| 295 | * Test if the constant parameters have changed between effects | ||
| 296 | */ | ||
| 297 | static int pidff_needs_set_constant(struct ff_effect *effect, | ||
| 298 | struct ff_effect *old) | ||
| 299 | { | ||
| 300 | return effect->u.constant.level != old->u.constant.level; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* | ||
| 304 | * Send set effect report to the device | ||
| 305 | */ | ||
| 306 | static void pidff_set_effect_report(struct pidff_device *pidff, | ||
| 307 | struct ff_effect *effect) | ||
| 308 | { | ||
| 309 | pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 310 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 311 | pidff->set_effect_type->value[0] = | ||
| 312 | pidff->create_new_effect_type->value[0]; | ||
| 313 | pidff->set_effect[PID_DURATION].value[0] = effect->replay.length; | ||
| 314 | pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button; | ||
| 315 | pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = | ||
| 316 | effect->trigger.interval; | ||
| 317 | pidff->set_effect[PID_GAIN].value[0] = | ||
| 318 | pidff->set_effect[PID_GAIN].field->logical_maximum; | ||
| 319 | pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; | ||
| 320 | pidff->effect_direction->value[0] = | ||
| 321 | pidff_rescale(effect->direction, 0xffff, | ||
| 322 | pidff->effect_direction); | ||
| 323 | pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; | ||
| 324 | |||
| 325 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], | ||
| 326 | USB_DIR_OUT); | ||
| 327 | } | ||
| 328 | |||
| 329 | /* | ||
| 330 | * Test if the values used in set_effect have changed | ||
| 331 | */ | ||
| 332 | static int pidff_needs_set_effect(struct ff_effect *effect, | ||
| 333 | struct ff_effect *old) | ||
| 334 | { | ||
| 335 | return effect->replay.length != old->replay.length || | ||
| 336 | effect->trigger.interval != old->trigger.interval || | ||
| 337 | effect->trigger.button != old->trigger.button || | ||
| 338 | effect->direction != old->direction || | ||
| 339 | effect->replay.delay != old->replay.delay; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* | ||
| 343 | * Send periodic effect report to the device | ||
| 344 | */ | ||
| 345 | static void pidff_set_periodic_report(struct pidff_device *pidff, | ||
| 346 | struct ff_effect *effect) | ||
| 347 | { | ||
| 348 | pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 349 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 350 | pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE], | ||
| 351 | effect->u.periodic.magnitude); | ||
| 352 | pidff_set_signed(&pidff->set_periodic[PID_OFFSET], | ||
| 353 | effect->u.periodic.offset); | ||
| 354 | pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); | ||
| 355 | pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; | ||
| 356 | |||
| 357 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], | ||
| 358 | USB_DIR_OUT); | ||
| 359 | |||
| 360 | } | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Test if periodic effect parameters have changed | ||
| 364 | */ | ||
| 365 | static int pidff_needs_set_periodic(struct ff_effect *effect, | ||
| 366 | struct ff_effect *old) | ||
| 367 | { | ||
| 368 | return effect->u.periodic.magnitude != old->u.periodic.magnitude || | ||
| 369 | effect->u.periodic.offset != old->u.periodic.offset || | ||
| 370 | effect->u.periodic.phase != old->u.periodic.phase || | ||
| 371 | effect->u.periodic.period != old->u.periodic.period; | ||
| 372 | } | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Send condition effect reports to the device | ||
| 376 | */ | ||
| 377 | static void pidff_set_condition_report(struct pidff_device *pidff, | ||
| 378 | struct ff_effect *effect) | ||
| 379 | { | ||
| 380 | int i; | ||
| 381 | |||
| 382 | pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 383 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 384 | |||
| 385 | for (i = 0; i < 2; i++) { | ||
| 386 | pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i; | ||
| 387 | pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET], | ||
| 388 | effect->u.condition[i].center); | ||
| 389 | pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT], | ||
| 390 | effect->u.condition[i].right_coeff); | ||
| 391 | pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT], | ||
| 392 | effect->u.condition[i].left_coeff); | ||
| 393 | pidff_set(&pidff->set_condition[PID_POS_SATURATION], | ||
| 394 | effect->u.condition[i].right_saturation); | ||
| 395 | pidff_set(&pidff->set_condition[PID_NEG_SATURATION], | ||
| 396 | effect->u.condition[i].left_saturation); | ||
| 397 | pidff_set(&pidff->set_condition[PID_DEAD_BAND], | ||
| 398 | effect->u.condition[i].deadband); | ||
| 399 | hid_wait_io(pidff->hid); | ||
| 400 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], | ||
| 401 | USB_DIR_OUT); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | /* | ||
| 406 | * Test if condition effect parameters have changed | ||
| 407 | */ | ||
| 408 | static int pidff_needs_set_condition(struct ff_effect *effect, | ||
| 409 | struct ff_effect *old) | ||
| 410 | { | ||
| 411 | int i; | ||
| 412 | int ret = 0; | ||
| 413 | |||
| 414 | for (i = 0; i < 2; i++) { | ||
| 415 | struct ff_condition_effect *cond = &effect->u.condition[i]; | ||
| 416 | struct ff_condition_effect *old_cond = &old->u.condition[i]; | ||
| 417 | |||
| 418 | ret |= cond->center != old_cond->center || | ||
| 419 | cond->right_coeff != old_cond->right_coeff || | ||
| 420 | cond->left_coeff != old_cond->left_coeff || | ||
| 421 | cond->right_saturation != old_cond->right_saturation || | ||
| 422 | cond->left_saturation != old_cond->left_saturation || | ||
| 423 | cond->deadband != old_cond->deadband; | ||
| 424 | } | ||
| 425 | |||
| 426 | return ret; | ||
| 427 | } | ||
| 428 | |||
| 429 | /* | ||
| 430 | * Send ramp force report to the device | ||
| 431 | */ | ||
| 432 | static void pidff_set_ramp_force_report(struct pidff_device *pidff, | ||
| 433 | struct ff_effect *effect) | ||
| 434 | { | ||
| 435 | pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 436 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 437 | pidff_set_signed(&pidff->set_ramp[PID_RAMP_START], | ||
| 438 | effect->u.ramp.start_level); | ||
| 439 | pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], | ||
| 440 | effect->u.ramp.end_level); | ||
| 441 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], | ||
| 442 | USB_DIR_OUT); | ||
| 443 | } | ||
| 444 | |||
| 445 | /* | ||
| 446 | * Test if ramp force parameters have changed | ||
| 447 | */ | ||
| 448 | static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old) | ||
| 449 | { | ||
| 450 | return effect->u.ramp.start_level != old->u.ramp.start_level || | ||
| 451 | effect->u.ramp.end_level != old->u.ramp.end_level; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* | ||
| 455 | * Send a request for effect upload to the device | ||
| 456 | * | ||
| 457 | * Returns 0 if device reported success, -ENOSPC if the device reported memory | ||
| 458 | * is full. Upon unknown response the function will retry for 60 times, if | ||
| 459 | * still unsuccessful -EIO is returned. | ||
| 460 | */ | ||
| 461 | static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) | ||
| 462 | { | ||
| 463 | int j; | ||
| 464 | |||
| 465 | pidff->create_new_effect_type->value[0] = efnum; | ||
| 466 | hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], | ||
| 467 | USB_DIR_OUT); | ||
| 468 | debug("create_new_effect sent, type: %d", efnum); | ||
| 469 | |||
| 470 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; | ||
| 471 | pidff->block_load_status->value[0] = 0; | ||
| 472 | hid_wait_io(pidff->hid); | ||
| 473 | |||
| 474 | for (j = 0; j < 60; j++) { | ||
| 475 | debug("pid_block_load requested"); | ||
| 476 | hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], | ||
| 477 | USB_DIR_IN); | ||
| 478 | hid_wait_io(pidff->hid); | ||
| 479 | if (pidff->block_load_status->value[0] == | ||
| 480 | pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { | ||
| 481 | debug("device reported free memory: %d bytes", | ||
| 482 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? | ||
| 483 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); | ||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | if (pidff->block_load_status->value[0] == | ||
| 487 | pidff->status_id[PID_BLOCK_LOAD_FULL]) { | ||
| 488 | debug("not enough memory free: %d bytes", | ||
| 489 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value ? | ||
| 490 | pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1); | ||
| 491 | return -ENOSPC; | ||
| 492 | } | ||
| 493 | } | ||
| 494 | printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n"); | ||
| 495 | return -EIO; | ||
| 496 | } | ||
| 497 | |||
| 498 | /* | ||
| 499 | * Play the effect with PID id n times | ||
| 500 | */ | ||
| 501 | static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) | ||
| 502 | { | ||
| 503 | pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; | ||
| 504 | |||
| 505 | if (n == 0) { | ||
| 506 | pidff->effect_operation_status->value[0] = | ||
| 507 | pidff->operation_id[PID_EFFECT_STOP]; | ||
| 508 | } else { | ||
| 509 | pidff->effect_operation_status->value[0] = | ||
| 510 | pidff->operation_id[PID_EFFECT_START]; | ||
| 511 | pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; | ||
| 512 | } | ||
| 513 | |||
| 514 | hid_wait_io(pidff->hid); | ||
| 515 | hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], | ||
| 516 | USB_DIR_OUT); | ||
| 517 | } | ||
| 518 | |||
| 519 | /** | ||
| 520 | * Play the effect with effect id @effect_id for @value times | ||
| 521 | */ | ||
| 522 | static int pidff_playback(struct input_dev *dev, int effect_id, int value) | ||
| 523 | { | ||
| 524 | struct pidff_device *pidff = dev->ff->private; | ||
| 525 | |||
| 526 | pidff_playback_pid(pidff, pidff->pid_id[effect_id], value); | ||
| 527 | |||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | |||
| 531 | /* | ||
| 532 | * Erase effect with PID id | ||
| 533 | */ | ||
| 534 | static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) | ||
| 535 | { | ||
| 536 | pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; | ||
| 537 | hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], | ||
| 538 | USB_DIR_OUT); | ||
| 539 | } | ||
| 540 | |||
| 541 | /* | ||
| 542 | * Stop and erase effect with effect_id | ||
| 543 | */ | ||
| 544 | static int pidff_erase_effect(struct input_dev *dev, int effect_id) | ||
| 545 | { | ||
| 546 | struct pidff_device *pidff = dev->ff->private; | ||
| 547 | int pid_id = pidff->pid_id[effect_id]; | ||
| 548 | |||
| 549 | debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]); | ||
| 550 | pidff_playback_pid(pidff, pid_id, 0); | ||
| 551 | pidff_erase_pid(pidff, pid_id); | ||
| 552 | |||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | |||
| 556 | /* | ||
| 557 | * Effect upload handler | ||
| 558 | */ | ||
| 559 | static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect, | ||
| 560 | struct ff_effect *old) | ||
| 561 | { | ||
| 562 | struct pidff_device *pidff = dev->ff->private; | ||
| 563 | int type_id; | ||
| 564 | int error; | ||
| 565 | |||
| 566 | switch (effect->type) { | ||
| 567 | case FF_CONSTANT: | ||
| 568 | if (!old) { | ||
| 569 | error = pidff_request_effect_upload(pidff, | ||
| 570 | pidff->type_id[PID_CONSTANT]); | ||
| 571 | if (error) | ||
| 572 | return error; | ||
| 573 | } | ||
| 574 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 575 | pidff_set_effect_report(pidff, effect); | ||
| 576 | if (!old || pidff_needs_set_constant(effect, old)) | ||
| 577 | pidff_set_constant_force_report(pidff, effect); | ||
| 578 | if (!old || | ||
| 579 | pidff_needs_set_envelope(&effect->u.constant.envelope, | ||
| 580 | &old->u.constant.envelope)) | ||
| 581 | pidff_set_envelope_report(pidff, | ||
| 582 | &effect->u.constant.envelope); | ||
| 583 | break; | ||
| 584 | |||
| 585 | case FF_PERIODIC: | ||
| 586 | if (!old) { | ||
| 587 | switch (effect->u.periodic.waveform) { | ||
| 588 | case FF_SQUARE: | ||
| 589 | type_id = PID_SQUARE; | ||
| 590 | break; | ||
| 591 | case FF_TRIANGLE: | ||
| 592 | type_id = PID_TRIANGLE; | ||
| 593 | break; | ||
| 594 | case FF_SINE: | ||
| 595 | type_id = PID_SINE; | ||
| 596 | break; | ||
| 597 | case FF_SAW_UP: | ||
| 598 | type_id = PID_SAW_UP; | ||
| 599 | break; | ||
| 600 | case FF_SAW_DOWN: | ||
| 601 | type_id = PID_SAW_DOWN; | ||
| 602 | break; | ||
| 603 | default: | ||
| 604 | printk(KERN_ERR | ||
| 605 | "hid-pidff: invalid waveform\n"); | ||
| 606 | return -EINVAL; | ||
| 607 | } | ||
| 608 | |||
| 609 | error = pidff_request_effect_upload(pidff, | ||
| 610 | pidff->type_id[type_id]); | ||
| 611 | if (error) | ||
| 612 | return error; | ||
| 613 | } | ||
| 614 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 615 | pidff_set_effect_report(pidff, effect); | ||
| 616 | if (!old || pidff_needs_set_periodic(effect, old)) | ||
| 617 | pidff_set_periodic_report(pidff, effect); | ||
| 618 | if (!old || | ||
| 619 | pidff_needs_set_envelope(&effect->u.periodic.envelope, | ||
| 620 | &old->u.periodic.envelope)) | ||
| 621 | pidff_set_envelope_report(pidff, | ||
| 622 | &effect->u.periodic.envelope); | ||
| 623 | break; | ||
| 624 | |||
| 625 | case FF_RAMP: | ||
| 626 | if (!old) { | ||
| 627 | error = pidff_request_effect_upload(pidff, | ||
| 628 | pidff->type_id[PID_RAMP]); | ||
| 629 | if (error) | ||
| 630 | return error; | ||
| 631 | } | ||
| 632 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 633 | pidff_set_effect_report(pidff, effect); | ||
| 634 | if (!old || pidff_needs_set_ramp(effect, old)) | ||
| 635 | pidff_set_ramp_force_report(pidff, effect); | ||
| 636 | if (!old || | ||
| 637 | pidff_needs_set_envelope(&effect->u.ramp.envelope, | ||
| 638 | &old->u.ramp.envelope)) | ||
| 639 | pidff_set_envelope_report(pidff, | ||
| 640 | &effect->u.ramp.envelope); | ||
| 641 | break; | ||
| 642 | |||
| 643 | case FF_SPRING: | ||
| 644 | if (!old) { | ||
| 645 | error = pidff_request_effect_upload(pidff, | ||
| 646 | pidff->type_id[PID_SPRING]); | ||
| 647 | if (error) | ||
| 648 | return error; | ||
| 649 | } | ||
| 650 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 651 | pidff_set_effect_report(pidff, effect); | ||
| 652 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 653 | pidff_set_condition_report(pidff, effect); | ||
| 654 | break; | ||
| 655 | |||
| 656 | case FF_FRICTION: | ||
| 657 | if (!old) { | ||
| 658 | error = pidff_request_effect_upload(pidff, | ||
| 659 | pidff->type_id[PID_FRICTION]); | ||
| 660 | if (error) | ||
| 661 | return error; | ||
| 662 | } | ||
| 663 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 664 | pidff_set_effect_report(pidff, effect); | ||
| 665 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 666 | pidff_set_condition_report(pidff, effect); | ||
| 667 | break; | ||
| 668 | |||
| 669 | case FF_DAMPER: | ||
| 670 | if (!old) { | ||
| 671 | error = pidff_request_effect_upload(pidff, | ||
| 672 | pidff->type_id[PID_DAMPER]); | ||
| 673 | if (error) | ||
| 674 | return error; | ||
| 675 | } | ||
| 676 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 677 | pidff_set_effect_report(pidff, effect); | ||
| 678 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 679 | pidff_set_condition_report(pidff, effect); | ||
| 680 | break; | ||
| 681 | |||
| 682 | case FF_INERTIA: | ||
| 683 | if (!old) { | ||
| 684 | error = pidff_request_effect_upload(pidff, | ||
| 685 | pidff->type_id[PID_INERTIA]); | ||
| 686 | if (error) | ||
| 687 | return error; | ||
| 688 | } | ||
| 689 | if (!old || pidff_needs_set_effect(effect, old)) | ||
| 690 | pidff_set_effect_report(pidff, effect); | ||
| 691 | if (!old || pidff_needs_set_condition(effect, old)) | ||
| 692 | pidff_set_condition_report(pidff, effect); | ||
| 693 | break; | ||
| 694 | |||
| 695 | default: | ||
| 696 | printk(KERN_ERR "hid-pidff: invalid type\n"); | ||
| 697 | return -EINVAL; | ||
| 698 | } | ||
| 699 | |||
| 700 | if (!old) | ||
| 701 | pidff->pid_id[effect->id] = | ||
| 702 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]; | ||
| 703 | |||
| 704 | debug("uploaded"); | ||
| 705 | |||
| 706 | return 0; | ||
| 707 | } | ||
| 708 | |||
| 709 | /* | ||
| 710 | * set_gain() handler | ||
| 711 | */ | ||
| 712 | static void pidff_set_gain(struct input_dev *dev, u16 gain) | ||
| 713 | { | ||
| 714 | struct pidff_device *pidff = dev->ff->private; | ||
| 715 | |||
| 716 | pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); | ||
| 717 | hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], | ||
| 718 | USB_DIR_OUT); | ||
| 719 | } | ||
| 720 | |||
| 721 | static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) | ||
| 722 | { | ||
| 723 | struct hid_field *field = | ||
| 724 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field; | ||
| 725 | |||
| 726 | if (!magnitude) { | ||
| 727 | pidff_playback_pid(pidff, field->logical_minimum, 0); | ||
| 728 | return; | ||
| 729 | } | ||
| 730 | |||
| 731 | pidff_playback_pid(pidff, field->logical_minimum, 1); | ||
| 732 | |||
| 733 | pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] = | ||
| 734 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum; | ||
| 735 | pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING]; | ||
| 736 | pidff->set_effect[PID_DURATION].value[0] = 0; | ||
| 737 | pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0; | ||
| 738 | pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; | ||
| 739 | pidff_set(&pidff->set_effect[PID_GAIN], magnitude); | ||
| 740 | pidff->set_effect[PID_START_DELAY].value[0] = 0; | ||
| 741 | |||
| 742 | hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], | ||
| 743 | USB_DIR_OUT); | ||
| 744 | } | ||
| 745 | |||
| 746 | /* | ||
| 747 | * pidff_set_autocenter() handler | ||
| 748 | */ | ||
| 749 | static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude) | ||
| 750 | { | ||
| 751 | struct pidff_device *pidff = dev->ff->private; | ||
| 752 | |||
| 753 | pidff_autocenter(pidff, magnitude); | ||
| 754 | } | ||
| 755 | |||
| 756 | /* | ||
| 757 | * Find fields from a report and fill a pidff_usage | ||
| 758 | */ | ||
| 759 | static int pidff_find_fields(struct pidff_usage *usage, const u8 *table, | ||
| 760 | struct hid_report *report, int count, int strict) | ||
| 761 | { | ||
| 762 | int i, j, k, found; | ||
| 763 | |||
| 764 | for (k = 0; k < count; k++) { | ||
| 765 | found = 0; | ||
| 766 | for (i = 0; i < report->maxfield; i++) { | ||
| 767 | if (report->field[i]->maxusage != | ||
| 768 | report->field[i]->report_count) { | ||
| 769 | debug("maxusage and report_count do not match, " | ||
| 770 | "skipping"); | ||
| 771 | continue; | ||
| 772 | } | ||
| 773 | for (j = 0; j < report->field[i]->maxusage; j++) { | ||
| 774 | if (report->field[i]->usage[j].hid == | ||
| 775 | (HID_UP_PID | table[k])) { | ||
| 776 | debug("found %d at %d->%d", k, i, j); | ||
| 777 | usage[k].field = report->field[i]; | ||
| 778 | usage[k].value = | ||
| 779 | &report->field[i]->value[j]; | ||
| 780 | found = 1; | ||
| 781 | break; | ||
| 782 | } | ||
| 783 | } | ||
| 784 | if (found) | ||
| 785 | break; | ||
| 786 | } | ||
| 787 | if (!found && strict) { | ||
| 788 | debug("failed to locate %d", k); | ||
| 789 | return -1; | ||
| 790 | } | ||
| 791 | } | ||
| 792 | return 0; | ||
| 793 | } | ||
| 794 | |||
| 795 | /* | ||
| 796 | * Return index into pidff_reports for the given usage | ||
| 797 | */ | ||
| 798 | static int pidff_check_usage(int usage) | ||
| 799 | { | ||
| 800 | int i; | ||
| 801 | |||
| 802 | for (i = 0; i < sizeof(pidff_reports); i++) | ||
| 803 | if (usage == (HID_UP_PID | pidff_reports[i])) | ||
| 804 | return i; | ||
| 805 | |||
| 806 | return -1; | ||
| 807 | } | ||
| 808 | |||
| 809 | /* | ||
| 810 | * Find the reports and fill pidff->reports[] | ||
| 811 | * report_type specifies either OUTPUT or FEATURE reports | ||
| 812 | */ | ||
| 813 | static void pidff_find_reports(struct hid_device *hid, int report_type, | ||
| 814 | struct pidff_device *pidff) | ||
| 815 | { | ||
| 816 | struct hid_report *report; | ||
| 817 | int i, ret; | ||
| 818 | |||
| 819 | list_for_each_entry(report, | ||
| 820 | &hid->report_enum[report_type].report_list, list) { | ||
| 821 | if (report->maxfield < 1) | ||
| 822 | continue; | ||
| 823 | ret = pidff_check_usage(report->field[0]->logical); | ||
| 824 | if (ret != -1) { | ||
| 825 | debug("found usage 0x%02x from field->logical", | ||
| 826 | pidff_reports[ret]); | ||
| 827 | pidff->reports[ret] = report; | ||
| 828 | continue; | ||
| 829 | } | ||
| 830 | |||
| 831 | /* | ||
| 832 | * Sometimes logical collections are stacked to indicate | ||
| 833 | * different usages for the report and the field, in which | ||
| 834 | * case we want the usage of the parent. However, Linux HID | ||
| 835 | * implementation hides this fact, so we have to dig it up | ||
| 836 | * ourselves | ||
| 837 | */ | ||
| 838 | i = report->field[0]->usage[0].collection_index; | ||
| 839 | if (i <= 0 || | ||
| 840 | hid->collection[i - 1].type != HID_COLLECTION_LOGICAL) | ||
| 841 | continue; | ||
| 842 | ret = pidff_check_usage(hid->collection[i - 1].usage); | ||
| 843 | if (ret != -1 && !pidff->reports[ret]) { | ||
| 844 | debug("found usage 0x%02x from collection array", | ||
| 845 | pidff_reports[ret]); | ||
| 846 | pidff->reports[ret] = report; | ||
| 847 | } | ||
| 848 | } | ||
| 849 | } | ||
| 850 | |||
| 851 | /* | ||
| 852 | * Test if the required reports have been found | ||
| 853 | */ | ||
| 854 | static int pidff_reports_ok(struct pidff_device *pidff) | ||
| 855 | { | ||
| 856 | int i; | ||
| 857 | |||
| 858 | for (i = 0; i <= PID_REQUIRED_REPORTS; i++) { | ||
| 859 | if (!pidff->reports[i]) { | ||
| 860 | debug("%d missing", i); | ||
| 861 | return 0; | ||
| 862 | } | ||
| 863 | } | ||
| 864 | |||
| 865 | return 1; | ||
| 866 | } | ||
| 867 | |||
| 868 | /* | ||
| 869 | * Find a field with a specific usage within a report | ||
| 870 | */ | ||
| 871 | static struct hid_field *pidff_find_special_field(struct hid_report *report, | ||
| 872 | int usage, int enforce_min) | ||
| 873 | { | ||
| 874 | int i; | ||
| 875 | |||
| 876 | for (i = 0; i < report->maxfield; i++) { | ||
| 877 | if (report->field[i]->logical == (HID_UP_PID | usage) && | ||
| 878 | report->field[i]->report_count > 0) { | ||
| 879 | if (!enforce_min || | ||
| 880 | report->field[i]->logical_minimum == 1) | ||
| 881 | return report->field[i]; | ||
| 882 | else { | ||
| 883 | printk(KERN_ERR "hid-pidff: logical_minimum " | ||
| 884 | "is not 1 as it should be\n"); | ||
| 885 | return NULL; | ||
| 886 | } | ||
| 887 | } | ||
| 888 | } | ||
| 889 | return NULL; | ||
| 890 | } | ||
| 891 | |||
| 892 | /* | ||
| 893 | * Fill a pidff->*_id struct table | ||
| 894 | */ | ||
| 895 | static int pidff_find_special_keys(int *keys, struct hid_field *fld, | ||
| 896 | const u8 *usagetable, int count) | ||
| 897 | { | ||
| 898 | |||
| 899 | int i, j; | ||
| 900 | int found = 0; | ||
| 901 | |||
| 902 | for (i = 0; i < count; i++) { | ||
| 903 | for (j = 0; j < fld->maxusage; j++) { | ||
| 904 | if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) { | ||
| 905 | keys[i] = j + 1; | ||
| 906 | found++; | ||
| 907 | break; | ||
| 908 | } | ||
| 909 | } | ||
| 910 | } | ||
| 911 | return found; | ||
| 912 | } | ||
| 913 | |||
| 914 | #define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \ | ||
| 915 | pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \ | ||
| 916 | sizeof(pidff_ ## name)) | ||
| 917 | |||
| 918 | /* | ||
| 919 | * Find and check the special fields | ||
| 920 | */ | ||
| 921 | static int pidff_find_special_fields(struct pidff_device *pidff) | ||
| 922 | { | ||
| 923 | debug("finding special fields"); | ||
| 924 | |||
| 925 | pidff->create_new_effect_type = | ||
| 926 | pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT], | ||
| 927 | 0x25, 1); | ||
| 928 | pidff->set_effect_type = | ||
| 929 | pidff_find_special_field(pidff->reports[PID_SET_EFFECT], | ||
| 930 | 0x25, 1); | ||
| 931 | pidff->effect_direction = | ||
| 932 | pidff_find_special_field(pidff->reports[PID_SET_EFFECT], | ||
| 933 | 0x57, 0); | ||
| 934 | pidff->device_control = | ||
| 935 | pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL], | ||
| 936 | 0x96, 1); | ||
| 937 | pidff->block_load_status = | ||
| 938 | pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD], | ||
| 939 | 0x8b, 1); | ||
| 940 | pidff->effect_operation_status = | ||
| 941 | pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION], | ||
| 942 | 0x78, 1); | ||
| 943 | |||
| 944 | debug("search done"); | ||
| 945 | |||
| 946 | if (!pidff->create_new_effect_type || !pidff->set_effect_type) { | ||
| 947 | printk(KERN_ERR "hid-pidff: effect lists not found\n"); | ||
| 948 | return -1; | ||
| 949 | } | ||
| 950 | |||
| 951 | if (!pidff->effect_direction) { | ||
| 952 | printk(KERN_ERR "hid-pidff: direction field not found\n"); | ||
| 953 | return -1; | ||
| 954 | } | ||
| 955 | |||
| 956 | if (!pidff->device_control) { | ||
| 957 | printk(KERN_ERR "hid-pidff: device control field not found\n"); | ||
| 958 | return -1; | ||
| 959 | } | ||
| 960 | |||
| 961 | if (!pidff->block_load_status) { | ||
| 962 | printk(KERN_ERR | ||
| 963 | "hid-pidff: block load status field not found\n"); | ||
| 964 | return -1; | ||
| 965 | } | ||
| 966 | |||
| 967 | if (!pidff->effect_operation_status) { | ||
| 968 | printk(KERN_ERR | ||
| 969 | "hid-pidff: effect operation field not found\n"); | ||
| 970 | return -1; | ||
| 971 | } | ||
| 972 | |||
| 973 | pidff_find_special_keys(pidff->control_id, pidff->device_control, | ||
| 974 | pidff_device_control, | ||
| 975 | sizeof(pidff_device_control)); | ||
| 976 | |||
| 977 | PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control); | ||
| 978 | |||
| 979 | if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type, | ||
| 980 | effect_types)) { | ||
| 981 | printk(KERN_ERR "hid-pidff: no effect types found\n"); | ||
| 982 | return -1; | ||
| 983 | } | ||
| 984 | |||
| 985 | if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status, | ||
| 986 | block_load_status) != | ||
| 987 | sizeof(pidff_block_load_status)) { | ||
| 988 | printk(KERN_ERR | ||
| 989 | "hidpidff: block load status identifiers not found\n"); | ||
| 990 | return -1; | ||
| 991 | } | ||
| 992 | |||
| 993 | if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status, | ||
| 994 | effect_operation_status) != | ||
| 995 | sizeof(pidff_effect_operation_status)) { | ||
| 996 | printk(KERN_ERR | ||
| 997 | "hidpidff: effect operation identifiers not found\n"); | ||
| 998 | return -1; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | /** | ||
| 1005 | * Find the implemented effect types | ||
| 1006 | */ | ||
| 1007 | static int pidff_find_effects(struct pidff_device *pidff, | ||
| 1008 | struct input_dev *dev) | ||
| 1009 | { | ||
| 1010 | int i; | ||
| 1011 | |||
| 1012 | for (i = 0; i < sizeof(pidff_effect_types); i++) { | ||
| 1013 | int pidff_type = pidff->type_id[i]; | ||
| 1014 | if (pidff->set_effect_type->usage[pidff_type].hid != | ||
| 1015 | pidff->create_new_effect_type->usage[pidff_type].hid) { | ||
| 1016 | printk(KERN_ERR "hid-pidff: " | ||
| 1017 | "effect type number %d is invalid\n", i); | ||
| 1018 | return -1; | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | if (pidff->type_id[PID_CONSTANT]) | ||
| 1023 | set_bit(FF_CONSTANT, dev->ffbit); | ||
| 1024 | if (pidff->type_id[PID_RAMP]) | ||
| 1025 | set_bit(FF_RAMP, dev->ffbit); | ||
| 1026 | if (pidff->type_id[PID_SQUARE]) { | ||
| 1027 | set_bit(FF_SQUARE, dev->ffbit); | ||
| 1028 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1029 | } | ||
| 1030 | if (pidff->type_id[PID_SINE]) { | ||
| 1031 | set_bit(FF_SINE, dev->ffbit); | ||
| 1032 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1033 | } | ||
| 1034 | if (pidff->type_id[PID_TRIANGLE]) { | ||
| 1035 | set_bit(FF_TRIANGLE, dev->ffbit); | ||
| 1036 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1037 | } | ||
| 1038 | if (pidff->type_id[PID_SAW_UP]) { | ||
| 1039 | set_bit(FF_SAW_UP, dev->ffbit); | ||
| 1040 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1041 | } | ||
| 1042 | if (pidff->type_id[PID_SAW_DOWN]) { | ||
| 1043 | set_bit(FF_SAW_DOWN, dev->ffbit); | ||
| 1044 | set_bit(FF_PERIODIC, dev->ffbit); | ||
| 1045 | } | ||
| 1046 | if (pidff->type_id[PID_SPRING]) | ||
| 1047 | set_bit(FF_SPRING, dev->ffbit); | ||
| 1048 | if (pidff->type_id[PID_DAMPER]) | ||
| 1049 | set_bit(FF_DAMPER, dev->ffbit); | ||
| 1050 | if (pidff->type_id[PID_INERTIA]) | ||
| 1051 | set_bit(FF_INERTIA, dev->ffbit); | ||
| 1052 | if (pidff->type_id[PID_FRICTION]) | ||
| 1053 | set_bit(FF_FRICTION, dev->ffbit); | ||
| 1054 | |||
| 1055 | return 0; | ||
| 1056 | |||
| 1057 | } | ||
| 1058 | |||
| 1059 | #define PIDFF_FIND_FIELDS(name, report, strict) \ | ||
| 1060 | pidff_find_fields(pidff->name, pidff_ ## name, \ | ||
| 1061 | pidff->reports[report], \ | ||
| 1062 | sizeof(pidff_ ## name), strict) | ||
| 1063 | |||
| 1064 | /* | ||
| 1065 | * Fill and check the pidff_usages | ||
| 1066 | */ | ||
| 1067 | static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev) | ||
| 1068 | { | ||
| 1069 | int envelope_ok = 0; | ||
| 1070 | |||
| 1071 | if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) { | ||
| 1072 | printk(KERN_ERR | ||
| 1073 | "hid-pidff: unknown set_effect report layout\n"); | ||
| 1074 | return -ENODEV; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0); | ||
| 1078 | if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) { | ||
| 1079 | printk(KERN_ERR | ||
| 1080 | "hid-pidff: unknown pid_block_load report layout\n"); | ||
| 1081 | return -ENODEV; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) { | ||
| 1085 | printk(KERN_ERR | ||
| 1086 | "hid-pidff: unknown effect_operation report layout\n"); | ||
| 1087 | return -ENODEV; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) { | ||
| 1091 | printk(KERN_ERR | ||
| 1092 | "hid-pidff: unknown pid_block_free report layout\n"); | ||
| 1093 | return -ENODEV; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1)) | ||
| 1097 | envelope_ok = 1; | ||
| 1098 | |||
| 1099 | if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev)) | ||
| 1100 | return -ENODEV; | ||
| 1101 | |||
| 1102 | if (!envelope_ok) { | ||
| 1103 | if (test_and_clear_bit(FF_CONSTANT, dev->ffbit)) | ||
| 1104 | printk(KERN_WARNING "hid-pidff: " | ||
| 1105 | "has constant effect but no envelope\n"); | ||
| 1106 | if (test_and_clear_bit(FF_RAMP, dev->ffbit)) | ||
| 1107 | printk(KERN_WARNING "hid-pidff: " | ||
| 1108 | "has ramp effect but no envelope\n"); | ||
| 1109 | |||
| 1110 | if (test_and_clear_bit(FF_PERIODIC, dev->ffbit)) | ||
| 1111 | printk(KERN_WARNING "hid-pidff: " | ||
| 1112 | "has periodic effect but no envelope\n"); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | if (test_bit(FF_CONSTANT, dev->ffbit) && | ||
| 1116 | PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) { | ||
| 1117 | printk(KERN_WARNING | ||
| 1118 | "hid-pidff: unknown constant effect layout\n"); | ||
| 1119 | clear_bit(FF_CONSTANT, dev->ffbit); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | if (test_bit(FF_RAMP, dev->ffbit) && | ||
| 1123 | PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) { | ||
| 1124 | printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n"); | ||
| 1125 | clear_bit(FF_RAMP, dev->ffbit); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | if ((test_bit(FF_SPRING, dev->ffbit) || | ||
| 1129 | test_bit(FF_DAMPER, dev->ffbit) || | ||
| 1130 | test_bit(FF_FRICTION, dev->ffbit) || | ||
| 1131 | test_bit(FF_INERTIA, dev->ffbit)) && | ||
| 1132 | PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) { | ||
| 1133 | printk(KERN_WARNING | ||
| 1134 | "hid-pidff: unknown condition effect layout\n"); | ||
| 1135 | clear_bit(FF_SPRING, dev->ffbit); | ||
| 1136 | clear_bit(FF_DAMPER, dev->ffbit); | ||
| 1137 | clear_bit(FF_FRICTION, dev->ffbit); | ||
| 1138 | clear_bit(FF_INERTIA, dev->ffbit); | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | if (test_bit(FF_PERIODIC, dev->ffbit) && | ||
| 1142 | PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) { | ||
| 1143 | printk(KERN_WARNING | ||
| 1144 | "hid-pidff: unknown periodic effect layout\n"); | ||
| 1145 | clear_bit(FF_PERIODIC, dev->ffbit); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | PIDFF_FIND_FIELDS(pool, PID_POOL, 0); | ||
| 1149 | |||
| 1150 | if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1)) | ||
| 1151 | set_bit(FF_GAIN, dev->ffbit); | ||
| 1152 | |||
| 1153 | return 0; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | /* | ||
| 1157 | * Reset the device | ||
| 1158 | */ | ||
| 1159 | static void pidff_reset(struct pidff_device *pidff) | ||
| 1160 | { | ||
| 1161 | struct hid_device *hid = pidff->hid; | ||
| 1162 | int i = 0; | ||
| 1163 | |||
| 1164 | pidff->device_control->value[0] = pidff->control_id[PID_RESET]; | ||
| 1165 | /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ | ||
| 1166 | hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); | ||
| 1167 | hid_wait_io(hid); | ||
| 1168 | hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); | ||
| 1169 | hid_wait_io(hid); | ||
| 1170 | |||
| 1171 | pidff->device_control->value[0] = | ||
| 1172 | pidff->control_id[PID_ENABLE_ACTUATORS]; | ||
| 1173 | hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); | ||
| 1174 | hid_wait_io(hid); | ||
| 1175 | |||
| 1176 | /* pool report is sometimes messed up, refetch it */ | ||
| 1177 | hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); | ||
| 1178 | hid_wait_io(hid); | ||
| 1179 | |||
| 1180 | if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { | ||
| 1181 | int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0]; | ||
| 1182 | while (sim_effects < 2) { | ||
| 1183 | if (i++ > 20) { | ||
| 1184 | printk(KERN_WARNING "hid-pidff: device reports " | ||
| 1185 | "%d simultaneous effects\n", | ||
| 1186 | sim_effects); | ||
| 1187 | break; | ||
| 1188 | } | ||
| 1189 | debug("pid_pool requested again"); | ||
| 1190 | hid_submit_report(hid, pidff->reports[PID_POOL], | ||
| 1191 | USB_DIR_IN); | ||
| 1192 | hid_wait_io(hid); | ||
| 1193 | } | ||
| 1194 | } | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | /* | ||
| 1198 | * Test if autocenter modification is using the supported method | ||
| 1199 | */ | ||
| 1200 | static int pidff_check_autocenter(struct pidff_device *pidff, | ||
| 1201 | struct input_dev *dev) | ||
| 1202 | { | ||
| 1203 | int error; | ||
| 1204 | |||
| 1205 | /* | ||
| 1206 | * Let's find out if autocenter modification is supported | ||
| 1207 | * Specification doesn't specify anything, so we request an | ||
| 1208 | * effect upload and cancel it immediately. If the approved | ||
| 1209 | * effect id was one above the minimum, then we assume the first | ||
| 1210 | * effect id is a built-in spring type effect used for autocenter | ||
| 1211 | */ | ||
| 1212 | |||
| 1213 | error = pidff_request_effect_upload(pidff, 1); | ||
| 1214 | if (error) { | ||
| 1215 | printk(KERN_ERR "hid-pidff: upload request failed\n"); | ||
| 1216 | return error; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] == | ||
| 1220 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) { | ||
| 1221 | pidff_autocenter(pidff, 0xffff); | ||
| 1222 | set_bit(FF_AUTOCENTER, dev->ffbit); | ||
| 1223 | } else { | ||
| 1224 | printk(KERN_NOTICE "hid-pidff: " | ||
| 1225 | "device has unknown autocenter control method\n"); | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | pidff_erase_pid(pidff, | ||
| 1229 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]); | ||
| 1230 | |||
| 1231 | return 0; | ||
| 1232 | |||
| 1233 | } | ||
| 1234 | |||
| 1235 | /* | ||
| 1236 | * Check if the device is PID and initialize it | ||
| 1237 | */ | ||
| 1238 | int hid_pidff_init(struct hid_device *hid) | ||
| 1239 | { | ||
| 1240 | struct pidff_device *pidff; | ||
| 1241 | struct hid_input *hidinput = list_entry(hid->inputs.next, | ||
| 1242 | struct hid_input, list); | ||
| 1243 | struct input_dev *dev = hidinput->input; | ||
| 1244 | struct ff_device *ff; | ||
| 1245 | int max_effects; | ||
| 1246 | int error; | ||
| 1247 | |||
| 1248 | debug("starting pid init"); | ||
| 1249 | |||
| 1250 | if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) { | ||
| 1251 | debug("not a PID device, no output report"); | ||
| 1252 | return -ENODEV; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | pidff = kzalloc(sizeof(*pidff), GFP_KERNEL); | ||
| 1256 | if (!pidff) | ||
| 1257 | return -ENOMEM; | ||
| 1258 | |||
| 1259 | pidff->hid = hid; | ||
| 1260 | |||
| 1261 | pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff); | ||
| 1262 | pidff_find_reports(hid, HID_FEATURE_REPORT, pidff); | ||
| 1263 | |||
| 1264 | if (!pidff_reports_ok(pidff)) { | ||
| 1265 | debug("reports not ok, aborting"); | ||
| 1266 | error = -ENODEV; | ||
| 1267 | goto fail; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | error = pidff_init_fields(pidff, dev); | ||
| 1271 | if (error) | ||
| 1272 | goto fail; | ||
| 1273 | |||
| 1274 | pidff_reset(pidff); | ||
| 1275 | |||
| 1276 | if (test_bit(FF_GAIN, dev->ffbit)) { | ||
| 1277 | pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); | ||
| 1278 | hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], | ||
| 1279 | USB_DIR_OUT); | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | error = pidff_check_autocenter(pidff, dev); | ||
| 1283 | if (error) | ||
| 1284 | goto fail; | ||
| 1285 | |||
| 1286 | max_effects = | ||
| 1287 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum - | ||
| 1288 | pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + | ||
| 1289 | 1; | ||
| 1290 | debug("max effects is %d", max_effects); | ||
| 1291 | |||
| 1292 | if (max_effects > PID_EFFECTS_MAX) | ||
| 1293 | max_effects = PID_EFFECTS_MAX; | ||
| 1294 | |||
| 1295 | if (pidff->pool[PID_SIMULTANEOUS_MAX].value) | ||
| 1296 | debug("max simultaneous effects is %d", | ||
| 1297 | pidff->pool[PID_SIMULTANEOUS_MAX].value[0]); | ||
| 1298 | |||
| 1299 | if (pidff->pool[PID_RAM_POOL_SIZE].value) | ||
| 1300 | debug("device memory size is %d bytes", | ||
| 1301 | pidff->pool[PID_RAM_POOL_SIZE].value[0]); | ||
| 1302 | |||
| 1303 | if (pidff->pool[PID_DEVICE_MANAGED_POOL].value && | ||
| 1304 | pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) { | ||
| 1305 | printk(KERN_NOTICE "hid-pidff: " | ||
| 1306 | "device does not support device managed pool\n"); | ||
| 1307 | goto fail; | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | error = input_ff_create(dev, max_effects); | ||
| 1311 | if (error) | ||
| 1312 | goto fail; | ||
| 1313 | |||
| 1314 | ff = dev->ff; | ||
| 1315 | ff->private = pidff; | ||
| 1316 | ff->upload = pidff_upload_effect; | ||
| 1317 | ff->erase = pidff_erase_effect; | ||
| 1318 | ff->set_gain = pidff_set_gain; | ||
| 1319 | ff->set_autocenter = pidff_set_autocenter; | ||
| 1320 | ff->playback = pidff_playback; | ||
| 1321 | |||
| 1322 | printk(KERN_INFO "Force feedback for USB HID PID devices by " | ||
| 1323 | "Anssi Hannula <anssi.hannula@gmail.com>\n"); | ||
| 1324 | |||
| 1325 | return 0; | ||
| 1326 | |||
| 1327 | fail: | ||
| 1328 | kfree(pidff); | ||
| 1329 | return error; | ||
| 1330 | } | ||
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 534425c69c0a..2d5be4c318ac 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c | |||
| @@ -28,97 +28,65 @@ | |||
| 28 | */ | 28 | */ |
| 29 | 29 | ||
| 30 | #include <linux/input.h> | 30 | #include <linux/input.h> |
| 31 | #include <linux/sched.h> | ||
| 32 | 31 | ||
| 33 | #undef DEBUG | 32 | #undef DEBUG |
| 34 | #include <linux/usb.h> | 33 | #include <linux/usb.h> |
| 35 | 34 | ||
| 36 | #include <linux/circ_buf.h> | ||
| 37 | |||
| 38 | #include "hid.h" | 35 | #include "hid.h" |
| 39 | #include "fixp-arith.h" | ||
| 40 | 36 | ||
| 41 | /* Usages for thrustmaster devices I know about */ | 37 | /* Usages for thrustmaster devices I know about */ |
| 42 | #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) | 38 | #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) |
| 43 | #define DELAY_CALC(t,delay) ((t) + (delay)*HZ/1000) | ||
| 44 | |||
| 45 | /* Effect status */ | ||
| 46 | #define EFFECT_STARTED 0 /* Effect is going to play after some time */ | ||
| 47 | #define EFFECT_PLAYING 1 /* Effect is playing */ | ||
| 48 | #define EFFECT_USED 2 | ||
| 49 | |||
| 50 | /* For tmff_device::flags */ | ||
| 51 | #define DEVICE_CLOSING 0 /* The driver is being unitialised */ | ||
| 52 | |||
| 53 | /* Check that the current process can access an effect */ | ||
| 54 | #define CHECK_OWNERSHIP(effect) (current->pid == 0 \ | ||
| 55 | || effect.owner == current->pid) | ||
| 56 | |||
| 57 | #define TMFF_CHECK_ID(id) ((id) >= 0 && (id) < TMFF_EFFECTS) | ||
| 58 | 39 | ||
| 59 | #define TMFF_CHECK_OWNERSHIP(i, l) \ | ||
| 60 | (test_bit(EFFECT_USED, l->effects[i].flags) \ | ||
| 61 | && CHECK_OWNERSHIP(l->effects[i])) | ||
| 62 | |||
| 63 | #define TMFF_EFFECTS 8 | ||
| 64 | |||
| 65 | struct tmff_effect { | ||
| 66 | pid_t owner; | ||
| 67 | |||
| 68 | struct ff_effect effect; | ||
| 69 | |||
| 70 | unsigned long flags[1]; | ||
| 71 | unsigned int count; /* Number of times left to play */ | ||
| 72 | |||
| 73 | unsigned long play_at; /* When the effect starts to play */ | ||
| 74 | unsigned long stop_at; /* When the effect ends */ | ||
| 75 | }; | ||
| 76 | 40 | ||
| 77 | struct tmff_device { | 41 | struct tmff_device { |
| 78 | struct hid_device *hid; | ||
| 79 | |||
| 80 | struct hid_report *report; | 42 | struct hid_report *report; |
| 81 | |||
| 82 | struct hid_field *rumble; | 43 | struct hid_field *rumble; |
| 44 | }; | ||
| 83 | 45 | ||
| 84 | unsigned int effects_playing; | 46 | /* Changes values from 0 to 0xffff into values from minimum to maximum */ |
| 85 | struct tmff_effect effects[TMFF_EFFECTS]; | 47 | static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) |
| 86 | spinlock_t lock; /* device-level lock. Having locks on | 48 | { |
| 87 | a per-effect basis could be nice, but | 49 | int ret; |
| 88 | isn't really necessary */ | ||
| 89 | 50 | ||
| 90 | unsigned long flags[1]; /* Contains various information about the | 51 | ret = (in * (maximum - minimum) / 0xffff) + minimum; |
| 91 | state of the driver for this device */ | 52 | if (ret < minimum) |
| 53 | return minimum; | ||
| 54 | if (ret > maximum) | ||
| 55 | return maximum; | ||
| 56 | return ret; | ||
| 57 | } | ||
| 92 | 58 | ||
| 93 | struct timer_list timer; | 59 | static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) |
| 94 | }; | 60 | { |
| 61 | struct hid_device *hid = dev->private; | ||
| 62 | struct tmff_device *tmff = data; | ||
| 63 | int left, right; /* Rumbling */ | ||
| 95 | 64 | ||
| 96 | /* Callbacks */ | 65 | left = hid_tmff_scale(effect->u.rumble.weak_magnitude, |
| 97 | static void hid_tmff_exit(struct hid_device *hid); | 66 | tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); |
| 98 | static int hid_tmff_event(struct hid_device *hid, struct input_dev *input, | 67 | right = hid_tmff_scale(effect->u.rumble.strong_magnitude, |
| 99 | unsigned int type, unsigned int code, int value); | 68 | tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); |
| 100 | static int hid_tmff_flush(struct input_dev *input, struct file *file); | ||
| 101 | static int hid_tmff_upload_effect(struct input_dev *input, | ||
| 102 | struct ff_effect *effect); | ||
| 103 | static int hid_tmff_erase(struct input_dev *input, int id); | ||
| 104 | 69 | ||
| 105 | /* Local functions */ | 70 | tmff->rumble->value[0] = left; |
| 106 | static void hid_tmff_recalculate_timer(struct tmff_device *tmff); | 71 | tmff->rumble->value[1] = right; |
| 107 | static void hid_tmff_timer(unsigned long timer_data); | 72 | dbg("(left,right)=(%08x, %08x)", left, right); |
| 73 | hid_submit_report(hid, tmff->report, USB_DIR_OUT); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 108 | 77 | ||
| 109 | int hid_tmff_init(struct hid_device *hid) | 78 | int hid_tmff_init(struct hid_device *hid) |
| 110 | { | 79 | { |
| 111 | struct tmff_device *private; | 80 | struct tmff_device *tmff; |
| 112 | struct list_head *pos; | 81 | struct list_head *pos; |
| 113 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | 82 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); |
| 114 | struct input_dev *input_dev = hidinput->input; | 83 | struct input_dev *input_dev = hidinput->input; |
| 84 | int error; | ||
| 115 | 85 | ||
| 116 | private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); | 86 | tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL); |
| 117 | if (!private) | 87 | if (!tmff) |
| 118 | return -ENOMEM; | 88 | return -ENOMEM; |
| 119 | 89 | ||
| 120 | hid->ff_private = private; | ||
| 121 | |||
| 122 | /* Find the report to use */ | 90 | /* Find the report to use */ |
| 123 | __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { | 91 | __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { |
| 124 | struct hid_report *report = (struct hid_report *)pos; | 92 | struct hid_report *report = (struct hid_report *)pos; |
| @@ -142,18 +110,18 @@ int hid_tmff_init(struct hid_device *hid) | |||
| 142 | continue; | 110 | continue; |
| 143 | } | 111 | } |
| 144 | 112 | ||
| 145 | if (private->report && private->report != report) { | 113 | if (tmff->report && tmff->report != report) { |
| 146 | warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report"); | 114 | warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report"); |
| 147 | continue; | 115 | continue; |
| 148 | } | 116 | } |
| 149 | 117 | ||
| 150 | if (private->rumble && private->rumble != field) { | 118 | if (tmff->rumble && tmff->rumble != field) { |
| 151 | warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR"); | 119 | warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR"); |
| 152 | continue; | 120 | continue; |
| 153 | } | 121 | } |
| 154 | 122 | ||
| 155 | private->report = report; | 123 | tmff->report = report; |
| 156 | private->rumble = field; | 124 | tmff->rumble = field; |
| 157 | 125 | ||
| 158 | set_bit(FF_RUMBLE, input_dev->ffbit); | 126 | set_bit(FF_RUMBLE, input_dev->ffbit); |
| 159 | break; | 127 | break; |
| @@ -162,302 +130,17 @@ int hid_tmff_init(struct hid_device *hid) | |||
| 162 | warn("ignoring unknown output usage %08x", field->usage[0].hid); | 130 | warn("ignoring unknown output usage %08x", field->usage[0].hid); |
| 163 | continue; | 131 | continue; |
| 164 | } | 132 | } |
| 165 | |||
| 166 | /* Fallthrough to here only when a valid usage is found */ | ||
| 167 | input_dev->upload_effect = hid_tmff_upload_effect; | ||
| 168 | input_dev->flush = hid_tmff_flush; | ||
| 169 | |||
| 170 | set_bit(EV_FF, input_dev->evbit); | ||
| 171 | input_dev->ff_effects_max = TMFF_EFFECTS; | ||
| 172 | } | 133 | } |
| 173 | } | 134 | } |
| 174 | 135 | ||
| 175 | private->hid = hid; | 136 | error = input_ff_create_memless(input_dev, tmff, hid_tmff_play); |
| 176 | 137 | if (error) { | |
| 177 | spin_lock_init(&private->lock); | 138 | kfree(tmff); |
| 178 | init_timer(&private->timer); | 139 | return error; |
| 179 | private->timer.data = (unsigned long)private; | ||
| 180 | private->timer.function = hid_tmff_timer; | ||
| 181 | |||
| 182 | /* Event and exit callbacks */ | ||
| 183 | hid->ff_exit = hid_tmff_exit; | ||
| 184 | hid->ff_event = hid_tmff_event; | ||
| 185 | |||
| 186 | info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>"); | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static void hid_tmff_exit(struct hid_device *hid) | ||
| 192 | { | ||
| 193 | struct tmff_device *tmff = hid->ff_private; | ||
| 194 | unsigned long flags; | ||
| 195 | |||
| 196 | spin_lock_irqsave(&tmff->lock, flags); | ||
| 197 | |||
| 198 | set_bit(DEVICE_CLOSING, tmff->flags); | ||
| 199 | del_timer_sync(&tmff->timer); | ||
| 200 | |||
| 201 | spin_unlock_irqrestore(&tmff->lock, flags); | ||
| 202 | |||
| 203 | kfree(tmff); | ||
| 204 | } | ||
| 205 | |||
| 206 | static int hid_tmff_event(struct hid_device *hid, struct input_dev *input, | ||
| 207 | unsigned int type, unsigned int code, int value) | ||
| 208 | { | ||
| 209 | struct tmff_device *tmff = hid->ff_private; | ||
| 210 | struct tmff_effect *effect = &tmff->effects[code]; | ||
| 211 | unsigned long flags; | ||
| 212 | |||
| 213 | if (type != EV_FF) | ||
| 214 | return -EINVAL; | ||
| 215 | if (!TMFF_CHECK_ID(code)) | ||
| 216 | return -EINVAL; | ||
| 217 | if (!TMFF_CHECK_OWNERSHIP(code, tmff)) | ||
| 218 | return -EACCES; | ||
| 219 | if (value < 0) | ||
| 220 | return -EINVAL; | ||
| 221 | |||
| 222 | spin_lock_irqsave(&tmff->lock, flags); | ||
| 223 | |||
| 224 | if (value > 0) { | ||
| 225 | set_bit(EFFECT_STARTED, effect->flags); | ||
| 226 | clear_bit(EFFECT_PLAYING, effect->flags); | ||
| 227 | effect->count = value; | ||
| 228 | effect->play_at = DELAY_CALC(jiffies, effect->effect.replay.delay); | ||
| 229 | } else { | ||
| 230 | clear_bit(EFFECT_STARTED, effect->flags); | ||
| 231 | clear_bit(EFFECT_PLAYING, effect->flags); | ||
| 232 | } | ||
| 233 | |||
| 234 | hid_tmff_recalculate_timer(tmff); | ||
| 235 | |||
| 236 | spin_unlock_irqrestore(&tmff->lock, flags); | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | |||
| 240 | } | ||
| 241 | |||
| 242 | /* Erase all effects this process owns */ | ||
| 243 | |||
| 244 | static int hid_tmff_flush(struct input_dev *dev, struct file *file) | ||
| 245 | { | ||
| 246 | struct hid_device *hid = dev->private; | ||
| 247 | struct tmff_device *tmff = hid->ff_private; | ||
| 248 | int i; | ||
| 249 | |||
| 250 | for (i=0; i<dev->ff_effects_max; ++i) | ||
| 251 | |||
| 252 | /* NOTE: no need to lock here. The only times EFFECT_USED is | ||
| 253 | modified is when effects are uploaded or when an effect is | ||
| 254 | erased. But a process cannot close its dev/input/eventX fd | ||
| 255 | and perform ioctls on the same fd all at the same time */ | ||
| 256 | |||
| 257 | if (current->pid == tmff->effects[i].owner | ||
| 258 | && test_bit(EFFECT_USED, tmff->effects[i].flags)) | ||
| 259 | if (hid_tmff_erase(dev, i)) | ||
| 260 | warn("erase effect %d failed", i); | ||
| 261 | |||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int hid_tmff_erase(struct input_dev *dev, int id) | ||
| 267 | { | ||
| 268 | struct hid_device *hid = dev->private; | ||
| 269 | struct tmff_device *tmff = hid->ff_private; | ||
| 270 | unsigned long flags; | ||
| 271 | |||
| 272 | if (!TMFF_CHECK_ID(id)) | ||
| 273 | return -EINVAL; | ||
| 274 | if (!TMFF_CHECK_OWNERSHIP(id, tmff)) | ||
| 275 | return -EACCES; | ||
| 276 | |||
| 277 | spin_lock_irqsave(&tmff->lock, flags); | ||
| 278 | |||
| 279 | tmff->effects[id].flags[0] = 0; | ||
| 280 | hid_tmff_recalculate_timer(tmff); | ||
| 281 | |||
| 282 | spin_unlock_irqrestore(&tmff->lock, flags); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static int hid_tmff_upload_effect(struct input_dev *input, | ||
| 288 | struct ff_effect *effect) | ||
| 289 | { | ||
| 290 | struct hid_device *hid = input->private; | ||
| 291 | struct tmff_device *tmff = hid->ff_private; | ||
| 292 | int id; | ||
| 293 | unsigned long flags; | ||
| 294 | |||
| 295 | if (!test_bit(effect->type, input->ffbit)) | ||
| 296 | return -EINVAL; | ||
| 297 | if (effect->id != -1 && !TMFF_CHECK_ID(effect->id)) | ||
| 298 | return -EINVAL; | ||
| 299 | |||
| 300 | spin_lock_irqsave(&tmff->lock, flags); | ||
| 301 | |||
| 302 | if (effect->id == -1) { | ||
| 303 | /* Find a free effect */ | ||
| 304 | for (id = 0; id < TMFF_EFFECTS && test_bit(EFFECT_USED, tmff->effects[id].flags); ++id); | ||
| 305 | |||
| 306 | if (id >= TMFF_EFFECTS) { | ||
| 307 | spin_unlock_irqrestore(&tmff->lock, flags); | ||
| 308 | return -ENOSPC; | ||
| 309 | } | ||
| 310 | |||
| 311 | effect->id = id; | ||
| 312 | tmff->effects[id].owner = current->pid; | ||
| 313 | tmff->effects[id].flags[0] = 0; | ||
| 314 | set_bit(EFFECT_USED, tmff->effects[id].flags); | ||
| 315 | |||
| 316 | } else { | ||
| 317 | /* Re-uploading an owned effect, to change parameters */ | ||
| 318 | id = effect->id; | ||
| 319 | clear_bit(EFFECT_PLAYING, tmff->effects[id].flags); | ||
| 320 | } | 140 | } |
| 321 | 141 | ||
| 322 | tmff->effects[id].effect = *effect; | 142 | info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>"); |
| 323 | |||
| 324 | hid_tmff_recalculate_timer(tmff); | ||
| 325 | 143 | ||
| 326 | spin_unlock_irqrestore(&tmff->lock, flags); | ||
| 327 | return 0; | 144 | return 0; |
| 328 | } | 145 | } |
| 329 | 146 | ||
| 330 | /* Start the timer for the next start/stop/delay */ | ||
| 331 | /* Always call this while tmff->lock is locked */ | ||
| 332 | |||
| 333 | static void hid_tmff_recalculate_timer(struct tmff_device *tmff) | ||
| 334 | { | ||
| 335 | int i; | ||
| 336 | int events = 0; | ||
| 337 | unsigned long next_time; | ||
| 338 | |||
| 339 | next_time = 0; /* Shut up compiler's incorrect warning */ | ||
| 340 | |||
| 341 | /* Find the next change in an effect's status */ | ||
| 342 | for (i = 0; i < TMFF_EFFECTS; ++i) { | ||
| 343 | struct tmff_effect *effect = &tmff->effects[i]; | ||
| 344 | unsigned long play_time; | ||
| 345 | |||
| 346 | if (!test_bit(EFFECT_STARTED, effect->flags)) | ||
| 347 | continue; | ||
| 348 | |||
| 349 | effect->stop_at = DELAY_CALC(effect->play_at, effect->effect.replay.length); | ||
| 350 | |||
| 351 | if (!test_bit(EFFECT_PLAYING, effect->flags)) | ||
| 352 | play_time = effect->play_at; | ||
| 353 | else | ||
| 354 | play_time = effect->stop_at; | ||
| 355 | |||
| 356 | events++; | ||
| 357 | |||
| 358 | if (time_after(jiffies, play_time)) | ||
| 359 | play_time = jiffies; | ||
| 360 | |||
| 361 | if (events == 1) | ||
| 362 | next_time = play_time; | ||
| 363 | else { | ||
| 364 | if (time_after(next_time, play_time)) | ||
| 365 | next_time = play_time; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | if (!events && tmff->effects_playing) { | ||
| 370 | /* Treat all effects turning off as an event */ | ||
| 371 | events = 1; | ||
| 372 | next_time = jiffies; | ||
| 373 | } | ||
| 374 | |||
| 375 | if (!events) { | ||
| 376 | /* No events, no time, no need for a timer. */ | ||
| 377 | del_timer_sync(&tmff->timer); | ||
| 378 | return; | ||
| 379 | } | ||
| 380 | |||
| 381 | mod_timer(&tmff->timer, next_time); | ||
| 382 | } | ||
| 383 | |||
| 384 | /* Changes values from 0 to 0xffff into values from minimum to maximum */ | ||
| 385 | static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) | ||
| 386 | { | ||
| 387 | int ret; | ||
| 388 | |||
| 389 | ret = (in * (maximum - minimum) / 0xffff) + minimum; | ||
| 390 | if (ret < minimum) | ||
| 391 | return minimum; | ||
| 392 | if (ret > maximum) | ||
| 393 | return maximum; | ||
| 394 | return ret; | ||
| 395 | } | ||
| 396 | |||
| 397 | static void hid_tmff_timer(unsigned long timer_data) | ||
| 398 | { | ||
| 399 | struct tmff_device *tmff = (struct tmff_device *) timer_data; | ||
| 400 | struct hid_device *hid = tmff->hid; | ||
| 401 | unsigned long flags; | ||
| 402 | int left = 0, right = 0; /* Rumbling */ | ||
| 403 | int i; | ||
| 404 | |||
| 405 | spin_lock_irqsave(&tmff->lock, flags); | ||
| 406 | |||
| 407 | tmff->effects_playing = 0; | ||
| 408 | |||
| 409 | for (i = 0; i < TMFF_EFFECTS; ++i) { | ||
| 410 | struct tmff_effect *effect = &tmff->effects[i]; | ||
| 411 | |||
| 412 | if (!test_bit(EFFECT_STARTED, effect->flags)) | ||
| 413 | continue; | ||
| 414 | |||
| 415 | if (!time_after(jiffies, effect->play_at)) | ||
| 416 | continue; | ||
| 417 | |||
| 418 | if (time_after(jiffies, effect->stop_at)) { | ||
| 419 | |||
| 420 | dbg("Finished playing once %d", i); | ||
| 421 | clear_bit(EFFECT_PLAYING, effect->flags); | ||
| 422 | |||
| 423 | if (--effect->count <= 0) { | ||
| 424 | dbg("Stopped %d", i); | ||
| 425 | clear_bit(EFFECT_STARTED, effect->flags); | ||
| 426 | continue; | ||
| 427 | } else { | ||
| 428 | dbg("Start again %d", i); | ||
| 429 | effect->play_at = DELAY_CALC(jiffies, effect->effect.replay.delay); | ||
| 430 | continue; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | ++tmff->effects_playing; | ||
| 435 | |||
| 436 | set_bit(EFFECT_PLAYING, effect->flags); | ||
| 437 | |||
| 438 | switch (effect->effect.type) { | ||
| 439 | case FF_RUMBLE: | ||
| 440 | right += effect->effect.u.rumble.strong_magnitude; | ||
| 441 | left += effect->effect.u.rumble.weak_magnitude; | ||
| 442 | break; | ||
| 443 | default: | ||
| 444 | BUG(); | ||
| 445 | break; | ||
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 | left = hid_tmff_scale(left, tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); | ||
| 450 | right = hid_tmff_scale(right, tmff->rumble->logical_minimum, tmff->rumble->logical_maximum); | ||
| 451 | |||
| 452 | if (left != tmff->rumble->value[0] || right != tmff->rumble->value[1]) { | ||
| 453 | tmff->rumble->value[0] = left; | ||
| 454 | tmff->rumble->value[1] = right; | ||
| 455 | dbg("(left,right)=(%08x, %08x)", left, right); | ||
| 456 | hid_submit_report(hid, tmff->report, USB_DIR_OUT); | ||
| 457 | } | ||
| 458 | |||
| 459 | if (!test_bit(DEVICE_CLOSING, tmff->flags)) | ||
| 460 | hid_tmff_recalculate_timer(tmff); | ||
| 461 | |||
| 462 | spin_unlock_irqrestore(&tmff->lock, flags); | ||
| 463 | } | ||
diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c new file mode 100644 index 000000000000..d2ce3214572c --- /dev/null +++ b/drivers/usb/input/hid-zpff.c | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* | ||
| 2 | * Force feedback support for Zeroplus based devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | |||
| 24 | /* #define DEBUG */ | ||
| 25 | |||
| 26 | #define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg) | ||
| 27 | |||
| 28 | #include <linux/input.h> | ||
| 29 | #include <linux/usb.h> | ||
| 30 | #include "hid.h" | ||
| 31 | |||
| 32 | struct zpff_device { | ||
| 33 | struct hid_report *report; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static int hid_zpff_play(struct input_dev *dev, void *data, | ||
| 37 | struct ff_effect *effect) | ||
| 38 | { | ||
| 39 | struct hid_device *hid = dev->private; | ||
| 40 | struct zpff_device *zpff = data; | ||
| 41 | int left, right; | ||
| 42 | |||
| 43 | /* | ||
| 44 | * The following is specified the other way around in the Zeroplus | ||
| 45 | * datasheet but the order below is correct for the XFX Executioner; | ||
| 46 | * however it is possible that the XFX Executioner is an exception | ||
| 47 | */ | ||
| 48 | |||
| 49 | left = effect->u.rumble.strong_magnitude; | ||
| 50 | right = effect->u.rumble.weak_magnitude; | ||
| 51 | debug("called with 0x%04x 0x%04x", left, right); | ||
| 52 | |||
| 53 | left = left * 0x7f / 0xffff; | ||
| 54 | right = right * 0x7f / 0xffff; | ||
| 55 | |||
| 56 | zpff->report->field[2]->value[0] = left; | ||
| 57 | zpff->report->field[3]->value[0] = right; | ||
| 58 | debug("running with 0x%02x 0x%02x", left, right); | ||
| 59 | hid_submit_report(hid, zpff->report, USB_DIR_OUT); | ||
| 60 | |||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | int hid_zpff_init(struct hid_device *hid) | ||
| 65 | { | ||
| 66 | struct zpff_device *zpff; | ||
| 67 | struct hid_report *report; | ||
| 68 | struct hid_input *hidinput = list_entry(hid->inputs.next, | ||
| 69 | struct hid_input, list); | ||
| 70 | struct list_head *report_list = | ||
| 71 | &hid->report_enum[HID_OUTPUT_REPORT].report_list; | ||
| 72 | struct input_dev *dev = hidinput->input; | ||
| 73 | int error; | ||
| 74 | |||
| 75 | if (list_empty(report_list)) { | ||
| 76 | printk(KERN_ERR "hid-zpff: no output report found\n"); | ||
| 77 | return -ENODEV; | ||
| 78 | } | ||
| 79 | |||
| 80 | report = list_entry(report_list->next, struct hid_report, list); | ||
| 81 | |||
| 82 | if (report->maxfield < 4) { | ||
| 83 | printk(KERN_ERR "hid-zpff: not enough fields in report\n"); | ||
| 84 | return -ENODEV; | ||
| 85 | } | ||
| 86 | |||
| 87 | zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); | ||
| 88 | if (!zpff) | ||
| 89 | return -ENOMEM; | ||
| 90 | |||
| 91 | set_bit(FF_RUMBLE, dev->ffbit); | ||
| 92 | |||
| 93 | error = input_ff_create_memless(dev, zpff, hid_zpff_play); | ||
| 94 | if (error) { | ||
| 95 | kfree(zpff); | ||
| 96 | return error; | ||
| 97 | } | ||
| 98 | |||
| 99 | zpff->report = report; | ||
| 100 | zpff->report->field[0]->value[0] = 0x00; | ||
| 101 | zpff->report->field[1]->value[0] = 0x02; | ||
| 102 | zpff->report->field[2]->value[0] = 0x00; | ||
| 103 | zpff->report->field[3]->value[0] = 0x00; | ||
| 104 | hid_submit_report(hid, zpff->report, USB_DIR_OUT); | ||
| 105 | |||
| 106 | printk(KERN_INFO "Force feedback for Zeroplus based devices by " | ||
| 107 | "Anssi Hannula <anssi.hannula@gmail.com>\n"); | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 778e575de352..b03fd9b075df 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h | |||
| @@ -449,11 +449,6 @@ struct hid_device { /* device report descriptor */ | |||
| 449 | char phys[64]; /* Device physical location */ | 449 | char phys[64]; /* Device physical location */ |
| 450 | char uniq[64]; /* Device unique identifier (serial #) */ | 450 | char uniq[64]; /* Device unique identifier (serial #) */ |
| 451 | 451 | ||
| 452 | void *ff_private; /* Private data for the force-feedback driver */ | ||
| 453 | void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */ | ||
| 454 | int (*ff_event)(struct hid_device *hid, struct input_dev *input, | ||
| 455 | unsigned int type, unsigned int code, int value); | ||
| 456 | |||
| 457 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK | 452 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK |
| 458 | unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; | 453 | unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; |
| 459 | unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; | 454 | unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; |
| @@ -521,29 +516,22 @@ void hid_close(struct hid_device *); | |||
| 521 | int hid_set_field(struct hid_field *, unsigned, __s32); | 516 | int hid_set_field(struct hid_field *, unsigned, __s32); |
| 522 | void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); | 517 | void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); |
| 523 | void hid_init_reports(struct hid_device *hid); | 518 | void hid_init_reports(struct hid_device *hid); |
| 524 | struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type); | ||
| 525 | int hid_wait_io(struct hid_device* hid); | 519 | int hid_wait_io(struct hid_device* hid); |
| 526 | 520 | ||
| 527 | 521 | ||
| 528 | #ifdef CONFIG_HID_FF | 522 | #ifdef CONFIG_HID_FF |
| 529 | int hid_ff_init(struct hid_device *hid); | 523 | int hid_ff_init(struct hid_device *hid); |
| 524 | |||
| 525 | int hid_lgff_init(struct hid_device *hid); | ||
| 526 | int hid_tmff_init(struct hid_device *hid); | ||
| 527 | int hid_zpff_init(struct hid_device *hid); | ||
| 528 | #ifdef CONFIG_HID_PID | ||
| 529 | int hid_pidff_init(struct hid_device *hid); | ||
| 530 | #else | ||
| 531 | static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } | ||
| 532 | #endif | ||
| 533 | |||
| 530 | #else | 534 | #else |
| 531 | static inline int hid_ff_init(struct hid_device *hid) { return -1; } | 535 | static inline int hid_ff_init(struct hid_device *hid) { return -1; } |
| 532 | #endif | 536 | #endif |
| 533 | static inline void hid_ff_exit(struct hid_device *hid) | ||
| 534 | { | ||
| 535 | if (hid->ff_exit) | ||
| 536 | hid->ff_exit(hid); | ||
| 537 | } | ||
| 538 | static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input, | ||
| 539 | unsigned int type, unsigned int code, int value) | ||
| 540 | { | ||
| 541 | if (hid->ff_event) | ||
| 542 | return hid->ff_event(hid, input, type, code, value); | ||
| 543 | return -ENOSYS; | ||
| 544 | } | ||
| 545 | |||
| 546 | int hid_lgff_init(struct hid_device* hid); | ||
| 547 | int hid_tmff_init(struct hid_device* hid); | ||
| 548 | int hid_pid_init(struct hid_device* hid); | ||
| 549 | 537 | ||
diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c deleted file mode 100644 index d9d9f656b8c9..000000000000 --- a/drivers/usb/input/pid.c +++ /dev/null | |||
| @@ -1,295 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * PID Force feedback support for hid devices. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2002 Rodrigo Damazio. | ||
| 5 | * Portions by Johann Deneux and Bjorn Augustson | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | * Should you need to contact me, the author, you can do so by | ||
| 24 | * e-mail - mail your message to <rdamazio@lsi.usp.br> | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <linux/config.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/kernel.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/mm.h> | ||
| 33 | #include <linux/smp_lock.h> | ||
| 34 | #include <linux/spinlock.h> | ||
| 35 | #include <linux/input.h> | ||
| 36 | #include <linux/usb.h> | ||
| 37 | #include "hid.h" | ||
| 38 | #include "pid.h" | ||
| 39 | |||
| 40 | #define CHECK_OWNERSHIP(i, hid_pid) \ | ||
| 41 | ((i) < FF_EFFECTS_MAX && i >= 0 && \ | ||
| 42 | test_bit(FF_PID_FLAGS_USED, &hid_pid->effects[(i)].flags) && \ | ||
| 43 | (current->pid == 0 || \ | ||
| 44 | (hid_pid)->effects[(i)].owner == current->pid)) | ||
| 45 | |||
| 46 | /* Called when a transfer is completed */ | ||
| 47 | static void hid_pid_ctrl_out(struct urb *u, struct pt_regs *regs) | ||
| 48 | { | ||
| 49 | dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n"); | ||
| 50 | } | ||
| 51 | |||
| 52 | static void hid_pid_exit(struct hid_device *hid) | ||
| 53 | { | ||
| 54 | struct hid_ff_pid *private = hid->ff_private; | ||
| 55 | |||
| 56 | if (private->urbffout) { | ||
| 57 | usb_kill_urb(private->urbffout); | ||
| 58 | usb_free_urb(private->urbffout); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) | ||
| 63 | { | ||
| 64 | dev_info(&pid->hid->dev->dev, "requested periodic force upload\n"); | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) | ||
| 69 | { | ||
| 70 | dev_info(&pid->hid->dev->dev, "requested constant force upload\n"); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) | ||
| 75 | { | ||
| 76 | dev_info(&pid->hid->dev->dev, "requested Condition force upload\n"); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update) | ||
| 81 | { | ||
| 82 | dev_info(&pid->hid->dev->dev, "request ramp force upload\n"); | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static int hid_pid_event(struct hid_device *hid, struct input_dev *input, | ||
| 87 | unsigned int type, unsigned int code, int value) | ||
| 88 | { | ||
| 89 | dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value); | ||
| 90 | |||
| 91 | if (type != EV_FF) | ||
| 92 | return -1; | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | /* Lock must be held by caller */ | ||
| 98 | static void hid_pid_ctrl_playback(struct hid_device *hid, struct hid_pid_effect *effect, int play) | ||
| 99 | { | ||
| 100 | if (play) | ||
| 101 | set_bit(FF_PID_FLAGS_PLAYING, &effect->flags); | ||
| 102 | else | ||
| 103 | clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags); | ||
| 104 | } | ||
| 105 | |||
| 106 | static int hid_pid_erase(struct input_dev *dev, int id) | ||
| 107 | { | ||
| 108 | struct hid_device *hid = dev->private; | ||
| 109 | struct hid_ff_pid *pid = hid->ff_private; | ||
| 110 | struct hid_field *field; | ||
| 111 | unsigned long flags; | ||
| 112 | int ret; | ||
| 113 | |||
| 114 | if (!CHECK_OWNERSHIP(id, pid)) | ||
| 115 | return -EACCES; | ||
| 116 | |||
| 117 | /* Find report */ | ||
| 118 | field = hid_find_field_by_usage(hid, HID_UP_PID | FF_PID_USAGE_BLOCK_FREE, | ||
| 119 | HID_OUTPUT_REPORT); | ||
| 120 | if (!field) { | ||
| 121 | dev_err(&hid->dev->dev, "couldn't find report\n"); | ||
| 122 | return -EIO; | ||
| 123 | } | ||
| 124 | |||
| 125 | ret = hid_set_field(field, 0, pid->effects[id].device_id); | ||
| 126 | if (ret) { | ||
| 127 | dev_err(&hid->dev->dev, "couldn't set field\n"); | ||
| 128 | return ret; | ||
| 129 | } | ||
| 130 | |||
| 131 | hid_submit_report(hid, field->report, USB_DIR_OUT); | ||
| 132 | |||
| 133 | spin_lock_irqsave(&pid->lock, flags); | ||
| 134 | hid_pid_ctrl_playback(hid, pid->effects + id, 0); | ||
| 135 | pid->effects[id].flags = 0; | ||
| 136 | spin_unlock_irqrestore(&pid->lock, flags); | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Erase all effects this process owns */ | ||
| 142 | static int hid_pid_flush(struct input_dev *dev, struct file *file) | ||
| 143 | { | ||
| 144 | struct hid_device *hid = dev->private; | ||
| 145 | struct hid_ff_pid *pid = hid->ff_private; | ||
| 146 | int i; | ||
| 147 | |||
| 148 | /*NOTE: no need to lock here. The only times EFFECT_USED is | ||
| 149 | modified is when effects are uploaded or when an effect is | ||
| 150 | erased. But a process cannot close its dev/input/eventX fd | ||
| 151 | and perform ioctls on the same fd all at the same time */ | ||
| 152 | /*FIXME: multiple threads, anyone? */ | ||
| 153 | for (i = 0; i < dev->ff_effects_max; ++i) | ||
| 154 | if (current->pid == pid->effects[i].owner | ||
| 155 | && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags)) | ||
| 156 | if (hid_pid_erase(dev, i)) | ||
| 157 | dev_warn(&hid->dev->dev, "erase effect %d failed", i); | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | static int hid_pid_upload_effect(struct input_dev *dev, | ||
| 163 | struct ff_effect *effect) | ||
| 164 | { | ||
| 165 | struct hid_ff_pid *pid_private = (struct hid_ff_pid *)(dev->private); | ||
| 166 | int ret; | ||
| 167 | int is_update; | ||
| 168 | unsigned long flags; | ||
| 169 | |||
| 170 | dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n", effect->type); | ||
| 171 | /* Check this effect type is supported by this device */ | ||
| 172 | if (!test_bit(effect->type, dev->ffbit)) { | ||
| 173 | dev_dbg(&pid_private->hid->dev->dev, | ||
| 174 | "invalid kind of effect requested.\n"); | ||
| 175 | return -EINVAL; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* | ||
| 179 | * If we want to create a new effect, get a free id | ||
| 180 | */ | ||
| 181 | if (effect->id == -1) { | ||
| 182 | int id = 0; | ||
| 183 | |||
| 184 | // Spinlock so we don`t get a race condition when choosing IDs | ||
| 185 | spin_lock_irqsave(&pid_private->lock, flags); | ||
| 186 | |||
| 187 | while (id < FF_EFFECTS_MAX) | ||
| 188 | if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags)) | ||
| 189 | break; | ||
| 190 | |||
| 191 | if (id == FF_EFFECTS_MAX) { | ||
| 192 | spin_unlock_irqrestore(&pid_private->lock, flags); | ||
| 193 | // TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) { | ||
| 194 | dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n"); | ||
| 195 | return -ENOMEM; | ||
| 196 | } | ||
| 197 | |||
| 198 | effect->id = id; | ||
| 199 | dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d.\n", id); | ||
| 200 | pid_private->effects[id].owner = current->pid; | ||
| 201 | pid_private->effects[id].flags = (1 << FF_PID_FLAGS_USED); | ||
| 202 | spin_unlock_irqrestore(&pid_private->lock, flags); | ||
| 203 | |||
| 204 | is_update = FF_PID_FALSE; | ||
| 205 | } else { | ||
| 206 | /* We want to update an effect */ | ||
| 207 | if (!CHECK_OWNERSHIP(effect->id, pid_private)) | ||
| 208 | return -EACCES; | ||
| 209 | |||
| 210 | /* Parameter type cannot be updated */ | ||
| 211 | if (effect->type != pid_private->effects[effect->id].effect.type) | ||
| 212 | return -EINVAL; | ||
| 213 | |||
| 214 | /* Check the effect is not already being updated */ | ||
| 215 | if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags)) | ||
| 216 | return -EAGAIN; | ||
| 217 | |||
| 218 | is_update = FF_PID_TRUE; | ||
| 219 | } | ||
| 220 | |||
| 221 | /* | ||
| 222 | * Upload the effect | ||
| 223 | */ | ||
| 224 | switch (effect->type) { | ||
| 225 | case FF_PERIODIC: | ||
| 226 | ret = pid_upload_periodic(pid_private, effect, is_update); | ||
| 227 | break; | ||
| 228 | |||
| 229 | case FF_CONSTANT: | ||
| 230 | ret = pid_upload_constant(pid_private, effect, is_update); | ||
| 231 | break; | ||
| 232 | |||
| 233 | case FF_SPRING: | ||
| 234 | case FF_FRICTION: | ||
| 235 | case FF_DAMPER: | ||
| 236 | case FF_INERTIA: | ||
| 237 | ret = pid_upload_condition(pid_private, effect, is_update); | ||
| 238 | break; | ||
| 239 | |||
| 240 | case FF_RAMP: | ||
| 241 | ret = pid_upload_ramp(pid_private, effect, is_update); | ||
| 242 | break; | ||
| 243 | |||
| 244 | default: | ||
| 245 | dev_dbg(&pid_private->hid->dev->dev, | ||
| 246 | "invalid type of effect requested - %x.\n", | ||
| 247 | effect->type); | ||
| 248 | return -EINVAL; | ||
| 249 | } | ||
| 250 | /* If a packet was sent, forbid new updates until we are notified | ||
| 251 | * that the packet was updated | ||
| 252 | */ | ||
| 253 | if (ret == 0) | ||
| 254 | set_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags); | ||
| 255 | pid_private->effects[effect->id].effect = *effect; | ||
| 256 | return ret; | ||
| 257 | } | ||
| 258 | |||
| 259 | int hid_pid_init(struct hid_device *hid) | ||
| 260 | { | ||
| 261 | struct hid_ff_pid *private; | ||
| 262 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
| 263 | struct input_dev *input_dev = hidinput->input; | ||
| 264 | |||
| 265 | private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL); | ||
| 266 | if (!private) | ||
| 267 | return -ENOMEM; | ||
| 268 | |||
| 269 | private->hid = hid; | ||
| 270 | |||
| 271 | hid->ff_exit = hid_pid_exit; | ||
| 272 | hid->ff_event = hid_pid_event; | ||
| 273 | |||
| 274 | /* Open output URB */ | ||
| 275 | if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) { | ||
| 276 | kfree(private); | ||
| 277 | return -1; | ||
| 278 | } | ||
| 279 | |||
| 280 | usb_fill_control_urb(private->urbffout, hid->dev, 0, | ||
| 281 | (void *)&private->ffcr, private->ctrl_buffer, 8, | ||
| 282 | hid_pid_ctrl_out, hid); | ||
| 283 | |||
| 284 | input_dev->upload_effect = hid_pid_upload_effect; | ||
| 285 | input_dev->flush = hid_pid_flush; | ||
| 286 | input_dev->ff_effects_max = 8; // A random default | ||
| 287 | set_bit(EV_FF, input_dev->evbit); | ||
| 288 | set_bit(EV_FF_STATUS, input_dev->evbit); | ||
| 289 | |||
| 290 | spin_lock_init(&private->lock); | ||
| 291 | |||
| 292 | printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n"); | ||
| 293 | |||
| 294 | return 0; | ||
| 295 | } | ||
diff --git a/drivers/usb/input/pid.h b/drivers/usb/input/pid.h deleted file mode 100644 index a2cb9627ed0e..000000000000 --- a/drivers/usb/input/pid.h +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * PID Force feedback support for hid devices. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2002 Rodrigo Damazio. | ||
| 5 | */ | ||
| 6 | |||
| 7 | /* | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | * Should you need to contact me, the author, you can do so by | ||
| 23 | * e-mail - mail your message to <rdamazio@lsi.usp.br> | ||
| 24 | */ | ||
| 25 | |||
| 26 | #define FF_EFFECTS_MAX 64 | ||
| 27 | |||
| 28 | #define FF_PID_FLAGS_USED 1 /* If the effect exists */ | ||
| 29 | #define FF_PID_FLAGS_UPDATING 2 /* If the effect is being updated */ | ||
| 30 | #define FF_PID_FLAGS_PLAYING 3 /* If the effect is currently being played */ | ||
| 31 | |||
| 32 | #define FF_PID_FALSE 0 | ||
| 33 | #define FF_PID_TRUE 1 | ||
| 34 | |||
| 35 | struct hid_pid_effect { | ||
| 36 | unsigned long flags; | ||
| 37 | pid_t owner; | ||
| 38 | unsigned int device_id; /* The device-assigned ID */ | ||
| 39 | struct ff_effect effect; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct hid_ff_pid { | ||
| 43 | struct hid_device *hid; | ||
| 44 | unsigned long gain; | ||
| 45 | |||
| 46 | struct urb *urbffout; | ||
| 47 | struct usb_ctrlrequest ffcr; | ||
| 48 | spinlock_t lock; | ||
| 49 | |||
| 50 | unsigned char ctrl_buffer[8]; | ||
| 51 | |||
| 52 | struct hid_pid_effect effects[FF_EFFECTS_MAX]; | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Constants from the PID usage table (still far from complete) | ||
| 57 | */ | ||
| 58 | |||
| 59 | #define FF_PID_USAGE_BLOCK_LOAD 0x89UL | ||
| 60 | #define FF_PID_USAGE_BLOCK_FREE 0x90UL | ||
| 61 | #define FF_PID_USAGE_NEW_EFFECT 0xABUL | ||
| 62 | #define FF_PID_USAGE_POOL_REPORT 0x7FUL | ||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 0222d92842b8..8006e51c34bb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
| @@ -1015,7 +1015,7 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
| 1015 | dev_info(dev, "device disconnected\n"); | 1015 | dev_info(dev, "device disconnected\n"); |
| 1016 | } | 1016 | } |
| 1017 | 1017 | ||
| 1018 | static struct tty_operations serial_ops = { | 1018 | static const struct tty_operations serial_ops = { |
| 1019 | .open = serial_open, | 1019 | .open = serial_open, |
| 1020 | .close = serial_close, | 1020 | .close = serial_close, |
| 1021 | .write = serial_write, | 1021 | .write = serial_write, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0e9ba0b9d71e..c78762051da4 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -772,12 +772,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 772 | separator[1] = 0; | 772 | separator[1] = 0; |
| 773 | 773 | ||
| 774 | memset(vol->source_rfc1001_name,0x20,15); | 774 | memset(vol->source_rfc1001_name,0x20,15); |
| 775 | for(i=0;i < strnlen(system_utsname.nodename,15);i++) { | 775 | for(i=0;i < strnlen(utsname()->nodename,15);i++) { |
| 776 | /* does not have to be a perfect mapping since the field is | 776 | /* does not have to be a perfect mapping since the field is |
| 777 | informational, only used for servers that do not support | 777 | informational, only used for servers that do not support |
| 778 | port 445 and it can be overridden at mount time */ | 778 | port 445 and it can be overridden at mount time */ |
| 779 | vol->source_rfc1001_name[i] = | 779 | vol->source_rfc1001_name[i] = |
| 780 | toupper(system_utsname.nodename[i]); | 780 | toupper(utsname()->nodename[i]); |
| 781 | } | 781 | } |
| 782 | vol->source_rfc1001_name[15] = 0; | 782 | vol->source_rfc1001_name[15] = 0; |
| 783 | /* null target name indicates to use *SMBSERVR default called name | 783 | /* null target name indicates to use *SMBSERVR default called name |
| @@ -2153,7 +2153,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2153 | 32, nls_codepage); | 2153 | 32, nls_codepage); |
| 2154 | bcc_ptr += 2 * bytes_returned; | 2154 | bcc_ptr += 2 * bytes_returned; |
| 2155 | bytes_returned = | 2155 | bytes_returned = |
| 2156 | cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, | 2156 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, |
| 2157 | 32, nls_codepage); | 2157 | 32, nls_codepage); |
| 2158 | bcc_ptr += 2 * bytes_returned; | 2158 | bcc_ptr += 2 * bytes_returned; |
| 2159 | bcc_ptr += 2; | 2159 | bcc_ptr += 2; |
| @@ -2180,8 +2180,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2180 | } | 2180 | } |
| 2181 | strcpy(bcc_ptr, "Linux version "); | 2181 | strcpy(bcc_ptr, "Linux version "); |
| 2182 | bcc_ptr += strlen("Linux version "); | 2182 | bcc_ptr += strlen("Linux version "); |
| 2183 | strcpy(bcc_ptr, system_utsname.release); | 2183 | strcpy(bcc_ptr, utsname()->release); |
| 2184 | bcc_ptr += strlen(system_utsname.release) + 1; | 2184 | bcc_ptr += strlen(utsname()->release) + 1; |
| 2185 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | 2185 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); |
| 2186 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | 2186 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; |
| 2187 | } | 2187 | } |
| @@ -2445,7 +2445,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2445 | 32, nls_codepage); | 2445 | 32, nls_codepage); |
| 2446 | bcc_ptr += 2 * bytes_returned; | 2446 | bcc_ptr += 2 * bytes_returned; |
| 2447 | bytes_returned = | 2447 | bytes_returned = |
| 2448 | cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, | 2448 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, |
| 2449 | nls_codepage); | 2449 | nls_codepage); |
| 2450 | bcc_ptr += 2 * bytes_returned; | 2450 | bcc_ptr += 2 * bytes_returned; |
| 2451 | bcc_ptr += 2; /* null terminate Linux version */ | 2451 | bcc_ptr += 2; /* null terminate Linux version */ |
| @@ -2462,8 +2462,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2462 | } else { /* ASCII */ | 2462 | } else { /* ASCII */ |
| 2463 | strcpy(bcc_ptr, "Linux version "); | 2463 | strcpy(bcc_ptr, "Linux version "); |
| 2464 | bcc_ptr += strlen("Linux version "); | 2464 | bcc_ptr += strlen("Linux version "); |
| 2465 | strcpy(bcc_ptr, system_utsname.release); | 2465 | strcpy(bcc_ptr, utsname()->release); |
| 2466 | bcc_ptr += strlen(system_utsname.release) + 1; | 2466 | bcc_ptr += strlen(utsname()->release) + 1; |
| 2467 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | 2467 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); |
| 2468 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | 2468 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; |
| 2469 | bcc_ptr++; /* empty domain field */ | 2469 | bcc_ptr++; /* empty domain field */ |
| @@ -2836,7 +2836,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2836 | 32, nls_codepage); | 2836 | 32, nls_codepage); |
| 2837 | bcc_ptr += 2 * bytes_returned; | 2837 | bcc_ptr += 2 * bytes_returned; |
| 2838 | bytes_returned = | 2838 | bytes_returned = |
| 2839 | cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, | 2839 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, |
| 2840 | nls_codepage); | 2840 | nls_codepage); |
| 2841 | bcc_ptr += 2 * bytes_returned; | 2841 | bcc_ptr += 2 * bytes_returned; |
| 2842 | bcc_ptr += 2; /* null term version string */ | 2842 | bcc_ptr += 2; /* null term version string */ |
| @@ -2888,8 +2888,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2888 | 2888 | ||
| 2889 | strcpy(bcc_ptr, "Linux version "); | 2889 | strcpy(bcc_ptr, "Linux version "); |
| 2890 | bcc_ptr += strlen("Linux version "); | 2890 | bcc_ptr += strlen("Linux version "); |
| 2891 | strcpy(bcc_ptr, system_utsname.release); | 2891 | strcpy(bcc_ptr, utsname()->release); |
| 2892 | bcc_ptr += strlen(system_utsname.release) + 1; | 2892 | bcc_ptr += strlen(utsname()->release) + 1; |
| 2893 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | 2893 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); |
| 2894 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | 2894 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; |
| 2895 | bcc_ptr++; /* null domain */ | 2895 | bcc_ptr++; /* null domain */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d1705ab8136e..22b4c35dcfe3 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -111,7 +111,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | |||
| 111 | bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, | 111 | bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, |
| 112 | nls_cp); | 112 | nls_cp); |
| 113 | bcc_ptr += 2 * bytes_ret; | 113 | bcc_ptr += 2 * bytes_ret; |
| 114 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, | 114 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, |
| 115 | 32, nls_cp); | 115 | 32, nls_cp); |
| 116 | bcc_ptr += 2 * bytes_ret; | 116 | bcc_ptr += 2 * bytes_ret; |
| 117 | bcc_ptr += 2; /* trailing null */ | 117 | bcc_ptr += 2; /* trailing null */ |
| @@ -158,8 +158,8 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | |||
| 158 | 158 | ||
| 159 | strcpy(bcc_ptr, "Linux version "); | 159 | strcpy(bcc_ptr, "Linux version "); |
| 160 | bcc_ptr += strlen("Linux version "); | 160 | bcc_ptr += strlen("Linux version "); |
| 161 | strcpy(bcc_ptr, system_utsname.release); | 161 | strcpy(bcc_ptr, init_utsname()->release); |
| 162 | bcc_ptr += strlen(system_utsname.release) + 1; | 162 | bcc_ptr += strlen(init_utsname()->release) + 1; |
| 163 | 163 | ||
| 164 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | 164 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); |
| 165 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | 165 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; |
diff --git a/fs/compat.c b/fs/compat.c index 13fb08d096c4..d98c96f4a44d 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -56,8 +56,6 @@ | |||
| 56 | 56 | ||
| 57 | int compat_log = 1; | 57 | int compat_log = 1; |
| 58 | 58 | ||
| 59 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
| 60 | |||
| 61 | int compat_printk(const char *fmt, ...) | 59 | int compat_printk(const char *fmt, ...) |
| 62 | { | 60 | { |
| 63 | va_list ap; | 61 | va_list ap; |
diff --git a/fs/dnotify.c b/fs/dnotify.c index f932591df5a4..2b0442db67e0 100644 --- a/fs/dnotify.c +++ b/fs/dnotify.c | |||
| @@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 92 | prev = &odn->dn_next; | 92 | prev = &odn->dn_next; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | error = f_setown(filp, current->pid, 0); | 95 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
| 96 | if (error) | 96 | if (error) |
| 97 | goto out_free; | 97 | goto out_free; |
| 98 | 98 | ||
| @@ -1318,7 +1318,7 @@ static void format_corename(char *corename, const char *pattern, long signr) | |||
| 1318 | case 'h': | 1318 | case 'h': |
| 1319 | down_read(&uts_sem); | 1319 | down_read(&uts_sem); |
| 1320 | rc = snprintf(out_ptr, out_end - out_ptr, | 1320 | rc = snprintf(out_ptr, out_end - out_ptr, |
| 1321 | "%s", system_utsname.nodename); | 1321 | "%s", utsname()->nodename); |
| 1322 | up_read(&uts_sem); | 1322 | up_read(&uts_sem); |
| 1323 | if (rc > out_end - out_ptr) | 1323 | if (rc > out_end - out_ptr) |
| 1324 | goto out; | 1324 | goto out; |
diff --git a/fs/fcntl.c b/fs/fcntl.c index d35cbc6bc112..e4f26165f12a 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -250,19 +250,22 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
| 250 | return error; | 250 | return error; |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static void f_modown(struct file *filp, unsigned long pid, | 253 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, |
| 254 | uid_t uid, uid_t euid, int force) | 254 | uid_t uid, uid_t euid, int force) |
| 255 | { | 255 | { |
| 256 | write_lock_irq(&filp->f_owner.lock); | 256 | write_lock_irq(&filp->f_owner.lock); |
| 257 | if (force || !filp->f_owner.pid) { | 257 | if (force || !filp->f_owner.pid) { |
| 258 | filp->f_owner.pid = pid; | 258 | put_pid(filp->f_owner.pid); |
| 259 | filp->f_owner.pid = get_pid(pid); | ||
| 260 | filp->f_owner.pid_type = type; | ||
| 259 | filp->f_owner.uid = uid; | 261 | filp->f_owner.uid = uid; |
| 260 | filp->f_owner.euid = euid; | 262 | filp->f_owner.euid = euid; |
| 261 | } | 263 | } |
| 262 | write_unlock_irq(&filp->f_owner.lock); | 264 | write_unlock_irq(&filp->f_owner.lock); |
| 263 | } | 265 | } |
| 264 | 266 | ||
| 265 | int f_setown(struct file *filp, unsigned long arg, int force) | 267 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, |
| 268 | int force) | ||
| 266 | { | 269 | { |
| 267 | int err; | 270 | int err; |
| 268 | 271 | ||
| @@ -270,15 +273,44 @@ int f_setown(struct file *filp, unsigned long arg, int force) | |||
| 270 | if (err) | 273 | if (err) |
| 271 | return err; | 274 | return err; |
| 272 | 275 | ||
| 273 | f_modown(filp, arg, current->uid, current->euid, force); | 276 | f_modown(filp, pid, type, current->uid, current->euid, force); |
| 274 | return 0; | 277 | return 0; |
| 275 | } | 278 | } |
| 279 | EXPORT_SYMBOL(__f_setown); | ||
| 276 | 280 | ||
| 281 | int f_setown(struct file *filp, unsigned long arg, int force) | ||
| 282 | { | ||
| 283 | enum pid_type type; | ||
| 284 | struct pid *pid; | ||
| 285 | int who = arg; | ||
| 286 | int result; | ||
| 287 | type = PIDTYPE_PID; | ||
| 288 | if (who < 0) { | ||
| 289 | type = PIDTYPE_PGID; | ||
| 290 | who = -who; | ||
| 291 | } | ||
| 292 | rcu_read_lock(); | ||
| 293 | pid = find_pid(who); | ||
| 294 | result = __f_setown(filp, pid, type, force); | ||
| 295 | rcu_read_unlock(); | ||
| 296 | return result; | ||
| 297 | } | ||
| 277 | EXPORT_SYMBOL(f_setown); | 298 | EXPORT_SYMBOL(f_setown); |
| 278 | 299 | ||
| 279 | void f_delown(struct file *filp) | 300 | void f_delown(struct file *filp) |
| 280 | { | 301 | { |
| 281 | f_modown(filp, 0, 0, 0, 1); | 302 | f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1); |
| 303 | } | ||
| 304 | |||
| 305 | pid_t f_getown(struct file *filp) | ||
| 306 | { | ||
| 307 | pid_t pid; | ||
| 308 | read_lock(&filp->f_owner.lock); | ||
| 309 | pid = pid_nr(filp->f_owner.pid); | ||
| 310 | if (filp->f_owner.pid_type == PIDTYPE_PGID) | ||
| 311 | pid = -pid; | ||
| 312 | read_unlock(&filp->f_owner.lock); | ||
| 313 | return pid; | ||
| 282 | } | 314 | } |
| 283 | 315 | ||
| 284 | static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | 316 | static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, |
| @@ -319,7 +351,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
| 319 | * current syscall conventions, the only way | 351 | * current syscall conventions, the only way |
| 320 | * to fix this will be in libc. | 352 | * to fix this will be in libc. |
| 321 | */ | 353 | */ |
| 322 | err = filp->f_owner.pid; | 354 | err = f_getown(filp); |
| 323 | force_successful_syscall_return(); | 355 | force_successful_syscall_return(); |
| 324 | break; | 356 | break; |
| 325 | case F_SETOWN: | 357 | case F_SETOWN: |
| @@ -470,24 +502,19 @@ static void send_sigio_to_task(struct task_struct *p, | |||
| 470 | void send_sigio(struct fown_struct *fown, int fd, int band) | 502 | void send_sigio(struct fown_struct *fown, int fd, int band) |
| 471 | { | 503 | { |
| 472 | struct task_struct *p; | 504 | struct task_struct *p; |
| 473 | int pid; | 505 | enum pid_type type; |
| 506 | struct pid *pid; | ||
| 474 | 507 | ||
| 475 | read_lock(&fown->lock); | 508 | read_lock(&fown->lock); |
| 509 | type = fown->pid_type; | ||
| 476 | pid = fown->pid; | 510 | pid = fown->pid; |
| 477 | if (!pid) | 511 | if (!pid) |
| 478 | goto out_unlock_fown; | 512 | goto out_unlock_fown; |
| 479 | 513 | ||
| 480 | read_lock(&tasklist_lock); | 514 | read_lock(&tasklist_lock); |
| 481 | if (pid > 0) { | 515 | do_each_pid_task(pid, type, p) { |
| 482 | p = find_task_by_pid(pid); | 516 | send_sigio_to_task(p, fown, fd, band); |
| 483 | if (p) { | 517 | } while_each_pid_task(pid, type, p); |
| 484 | send_sigio_to_task(p, fown, fd, band); | ||
| 485 | } | ||
| 486 | } else { | ||
| 487 | do_each_task_pid(-pid, PIDTYPE_PGID, p) { | ||
| 488 | send_sigio_to_task(p, fown, fd, band); | ||
| 489 | } while_each_task_pid(-pid, PIDTYPE_PGID, p); | ||
| 490 | } | ||
| 491 | read_unlock(&tasklist_lock); | 518 | read_unlock(&tasklist_lock); |
| 492 | out_unlock_fown: | 519 | out_unlock_fown: |
| 493 | read_unlock(&fown->lock); | 520 | read_unlock(&fown->lock); |
| @@ -503,9 +530,12 @@ static void send_sigurg_to_task(struct task_struct *p, | |||
| 503 | int send_sigurg(struct fown_struct *fown) | 530 | int send_sigurg(struct fown_struct *fown) |
| 504 | { | 531 | { |
| 505 | struct task_struct *p; | 532 | struct task_struct *p; |
| 506 | int pid, ret = 0; | 533 | enum pid_type type; |
| 534 | struct pid *pid; | ||
| 535 | int ret = 0; | ||
| 507 | 536 | ||
| 508 | read_lock(&fown->lock); | 537 | read_lock(&fown->lock); |
| 538 | type = fown->pid_type; | ||
| 509 | pid = fown->pid; | 539 | pid = fown->pid; |
| 510 | if (!pid) | 540 | if (!pid) |
| 511 | goto out_unlock_fown; | 541 | goto out_unlock_fown; |
| @@ -513,16 +543,9 @@ int send_sigurg(struct fown_struct *fown) | |||
| 513 | ret = 1; | 543 | ret = 1; |
| 514 | 544 | ||
| 515 | read_lock(&tasklist_lock); | 545 | read_lock(&tasklist_lock); |
| 516 | if (pid > 0) { | 546 | do_each_pid_task(pid, type, p) { |
| 517 | p = find_task_by_pid(pid); | 547 | send_sigurg_to_task(p, fown); |
| 518 | if (p) { | 548 | } while_each_pid_task(pid, type, p); |
| 519 | send_sigurg_to_task(p, fown); | ||
| 520 | } | ||
| 521 | } else { | ||
| 522 | do_each_task_pid(-pid, PIDTYPE_PGID, p) { | ||
| 523 | send_sigurg_to_task(p, fown); | ||
| 524 | } while_each_task_pid(-pid, PIDTYPE_PGID, p); | ||
| 525 | } | ||
| 526 | read_unlock(&tasklist_lock); | 549 | read_unlock(&tasklist_lock); |
| 527 | out_unlock_fown: | 550 | out_unlock_fown: |
| 528 | read_unlock(&fown->lock); | 551 | read_unlock(&fown->lock); |
diff --git a/fs/file_table.c b/fs/file_table.c index bc35a40417d7..24f25a057d9c 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
| @@ -174,6 +174,7 @@ void fastcall __fput(struct file *file) | |||
| 174 | fops_put(file->f_op); | 174 | fops_put(file->f_op); |
| 175 | if (file->f_mode & FMODE_WRITE) | 175 | if (file->f_mode & FMODE_WRITE) |
| 176 | put_write_access(inode); | 176 | put_write_access(inode); |
| 177 | put_pid(file->f_owner.pid); | ||
| 177 | file_kill(file); | 178 | file_kill(file); |
| 178 | file->f_dentry = NULL; | 179 | file->f_dentry = NULL; |
| 179 | file->f_vfsmnt = NULL; | 180 | file->f_vfsmnt = NULL; |
diff --git a/fs/inode.c b/fs/inode.c index ada7643104e1..bf6bec4e54ff 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -657,7 +657,7 @@ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_he | |||
| 657 | return inode; | 657 | return inode; |
| 658 | } | 658 | } |
| 659 | 659 | ||
| 660 | static inline unsigned long hash(struct super_block *sb, unsigned long hashval) | 660 | static unsigned long hash(struct super_block *sb, unsigned long hashval) |
| 661 | { | 661 | { |
| 662 | unsigned long tmp; | 662 | unsigned long tmp; |
| 663 | 663 | ||
| @@ -1003,7 +1003,7 @@ void generic_delete_inode(struct inode *inode) | |||
| 1003 | 1003 | ||
| 1004 | list_del_init(&inode->i_list); | 1004 | list_del_init(&inode->i_list); |
| 1005 | list_del_init(&inode->i_sb_list); | 1005 | list_del_init(&inode->i_sb_list); |
| 1006 | inode->i_state|=I_FREEING; | 1006 | inode->i_state |= I_FREEING; |
| 1007 | inodes_stat.nr_inodes--; | 1007 | inodes_stat.nr_inodes--; |
| 1008 | spin_unlock(&inode_lock); | 1008 | spin_unlock(&inode_lock); |
| 1009 | 1009 | ||
| @@ -1210,13 +1210,15 @@ void file_update_time(struct file *file) | |||
| 1210 | return; | 1210 | return; |
| 1211 | 1211 | ||
| 1212 | now = current_fs_time(inode->i_sb); | 1212 | now = current_fs_time(inode->i_sb); |
| 1213 | if (!timespec_equal(&inode->i_mtime, &now)) | 1213 | if (!timespec_equal(&inode->i_mtime, &now)) { |
| 1214 | inode->i_mtime = now; | ||
| 1214 | sync_it = 1; | 1215 | sync_it = 1; |
| 1215 | inode->i_mtime = now; | 1216 | } |
| 1216 | 1217 | ||
| 1217 | if (!timespec_equal(&inode->i_ctime, &now)) | 1218 | if (!timespec_equal(&inode->i_ctime, &now)) { |
| 1219 | inode->i_ctime = now; | ||
| 1218 | sync_it = 1; | 1220 | sync_it = 1; |
| 1219 | inode->i_ctime = now; | 1221 | } |
| 1220 | 1222 | ||
| 1221 | if (sync_it) | 1223 | if (sync_it) |
| 1222 | mark_inode_dirty_sync(inode); | 1224 | mark_inode_dirty_sync(inode); |
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index f95cc3f3c42d..87e1d03e8267 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
| @@ -202,7 +202,7 @@ reclaimer(void *ptr) | |||
| 202 | /* This one ensures that our parent doesn't terminate while the | 202 | /* This one ensures that our parent doesn't terminate while the |
| 203 | * reclaim is in progress */ | 203 | * reclaim is in progress */ |
| 204 | lock_kernel(); | 204 | lock_kernel(); |
| 205 | lockd_up(); | 205 | lockd_up(0); /* note: this cannot fail as lockd is already running */ |
| 206 | 206 | ||
| 207 | nlmclnt_prepare_reclaim(host); | 207 | nlmclnt_prepare_reclaim(host); |
| 208 | /* First, reclaim all locks that have been marked. */ | 208 | /* First, reclaim all locks that have been marked. */ |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 271e2165fff6..0116729cec5f 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
| @@ -129,11 +129,11 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) | |||
| 129 | nlmclnt_next_cookie(&argp->cookie); | 129 | nlmclnt_next_cookie(&argp->cookie); |
| 130 | argp->state = nsm_local_state; | 130 | argp->state = nsm_local_state; |
| 131 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); | 131 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); |
| 132 | lock->caller = system_utsname.nodename; | 132 | lock->caller = utsname()->nodename; |
| 133 | lock->oh.data = req->a_owner; | 133 | lock->oh.data = req->a_owner; |
| 134 | lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", | 134 | lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", |
| 135 | (unsigned int)fl->fl_u.nfs_fl.owner->pid, | 135 | (unsigned int)fl->fl_u.nfs_fl.owner->pid, |
| 136 | system_utsname.nodename); | 136 | utsname()->nodename); |
| 137 | lock->svid = fl->fl_u.nfs_fl.owner->pid; | 137 | lock->svid = fl->fl_u.nfs_fl.owner->pid; |
| 138 | lock->fl.fl_start = fl->fl_start; | 138 | lock->fl.fl_start = fl->fl_start; |
| 139 | lock->fl.fl_end = fl->fl_end; | 139 | lock->fl.fl_end = fl->fl_end; |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 5954dcb497e4..a816b920d431 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
| @@ -145,7 +145,7 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp) | |||
| 145 | */ | 145 | */ |
| 146 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); | 146 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); |
| 147 | if (!(p = xdr_encode_string(p, buffer)) | 147 | if (!(p = xdr_encode_string(p, buffer)) |
| 148 | || !(p = xdr_encode_string(p, system_utsname.nodename))) | 148 | || !(p = xdr_encode_string(p, utsname()->nodename))) |
| 149 | return ERR_PTR(-EIO); | 149 | return ERR_PTR(-EIO); |
| 150 | *p++ = htonl(argp->prog); | 150 | *p++ = htonl(argp->prog); |
| 151 | *p++ = htonl(argp->vers); | 151 | *p++ = htonl(argp->vers); |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 9a991b52c647..3cc369e5693f 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/sunrpc/clnt.h> | 31 | #include <linux/sunrpc/clnt.h> |
| 32 | #include <linux/sunrpc/svc.h> | 32 | #include <linux/sunrpc/svc.h> |
| 33 | #include <linux/sunrpc/svcsock.h> | 33 | #include <linux/sunrpc/svcsock.h> |
| 34 | #include <net/ip.h> | ||
| 34 | #include <linux/lockd/lockd.h> | 35 | #include <linux/lockd/lockd.h> |
| 35 | #include <linux/nfs.h> | 36 | #include <linux/nfs.h> |
| 36 | 37 | ||
| @@ -46,6 +47,7 @@ EXPORT_SYMBOL(nlmsvc_ops); | |||
| 46 | static DEFINE_MUTEX(nlmsvc_mutex); | 47 | static DEFINE_MUTEX(nlmsvc_mutex); |
| 47 | static unsigned int nlmsvc_users; | 48 | static unsigned int nlmsvc_users; |
| 48 | static pid_t nlmsvc_pid; | 49 | static pid_t nlmsvc_pid; |
| 50 | static struct svc_serv *nlmsvc_serv; | ||
| 49 | int nlmsvc_grace_period; | 51 | int nlmsvc_grace_period; |
| 50 | unsigned long nlmsvc_timeout; | 52 | unsigned long nlmsvc_timeout; |
| 51 | 53 | ||
| @@ -96,7 +98,6 @@ static inline void clear_grace_period(void) | |||
| 96 | static void | 98 | static void |
| 97 | lockd(struct svc_rqst *rqstp) | 99 | lockd(struct svc_rqst *rqstp) |
| 98 | { | 100 | { |
| 99 | struct svc_serv *serv = rqstp->rq_server; | ||
| 100 | int err = 0; | 101 | int err = 0; |
| 101 | unsigned long grace_period_expire; | 102 | unsigned long grace_period_expire; |
| 102 | 103 | ||
| @@ -112,6 +113,7 @@ lockd(struct svc_rqst *rqstp) | |||
| 112 | * Let our maker know we're running. | 113 | * Let our maker know we're running. |
| 113 | */ | 114 | */ |
| 114 | nlmsvc_pid = current->pid; | 115 | nlmsvc_pid = current->pid; |
| 116 | nlmsvc_serv = rqstp->rq_server; | ||
| 115 | complete(&lockd_start_done); | 117 | complete(&lockd_start_done); |
| 116 | 118 | ||
| 117 | daemonize("lockd"); | 119 | daemonize("lockd"); |
| @@ -161,7 +163,7 @@ lockd(struct svc_rqst *rqstp) | |||
| 161 | * Find a socket with data available and call its | 163 | * Find a socket with data available and call its |
| 162 | * recvfrom routine. | 164 | * recvfrom routine. |
| 163 | */ | 165 | */ |
| 164 | err = svc_recv(serv, rqstp, timeout); | 166 | err = svc_recv(rqstp, timeout); |
| 165 | if (err == -EAGAIN || err == -EINTR) | 167 | if (err == -EAGAIN || err == -EINTR) |
| 166 | continue; | 168 | continue; |
| 167 | if (err < 0) { | 169 | if (err < 0) { |
| @@ -174,7 +176,7 @@ lockd(struct svc_rqst *rqstp) | |||
| 174 | dprintk("lockd: request from %08x\n", | 176 | dprintk("lockd: request from %08x\n", |
| 175 | (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); | 177 | (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); |
| 176 | 178 | ||
| 177 | svc_process(serv, rqstp); | 179 | svc_process(rqstp); |
| 178 | 180 | ||
| 179 | } | 181 | } |
| 180 | 182 | ||
| @@ -189,6 +191,7 @@ lockd(struct svc_rqst *rqstp) | |||
| 189 | nlmsvc_invalidate_all(); | 191 | nlmsvc_invalidate_all(); |
| 190 | nlm_shutdown_hosts(); | 192 | nlm_shutdown_hosts(); |
| 191 | nlmsvc_pid = 0; | 193 | nlmsvc_pid = 0; |
| 194 | nlmsvc_serv = NULL; | ||
| 192 | } else | 195 | } else |
| 193 | printk(KERN_DEBUG | 196 | printk(KERN_DEBUG |
| 194 | "lockd: new process, skipping host shutdown\n"); | 197 | "lockd: new process, skipping host shutdown\n"); |
| @@ -205,54 +208,77 @@ lockd(struct svc_rqst *rqstp) | |||
| 205 | module_put_and_exit(0); | 208 | module_put_and_exit(0); |
| 206 | } | 209 | } |
| 207 | 210 | ||
| 211 | |||
| 212 | static int find_socket(struct svc_serv *serv, int proto) | ||
| 213 | { | ||
| 214 | struct svc_sock *svsk; | ||
| 215 | int found = 0; | ||
| 216 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) | ||
| 217 | if (svsk->sk_sk->sk_protocol == proto) { | ||
| 218 | found = 1; | ||
| 219 | break; | ||
| 220 | } | ||
| 221 | return found; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int make_socks(struct svc_serv *serv, int proto) | ||
| 225 | { | ||
| 226 | /* Make any sockets that are needed but not present. | ||
| 227 | * If nlm_udpport or nlm_tcpport were set as module | ||
| 228 | * options, make those sockets unconditionally | ||
| 229 | */ | ||
| 230 | static int warned; | ||
| 231 | int err = 0; | ||
| 232 | if (proto == IPPROTO_UDP || nlm_udpport) | ||
| 233 | if (!find_socket(serv, IPPROTO_UDP)) | ||
| 234 | err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport); | ||
| 235 | if (err == 0 && (proto == IPPROTO_TCP || nlm_tcpport)) | ||
| 236 | if (!find_socket(serv, IPPROTO_TCP)) | ||
| 237 | err= svc_makesock(serv, IPPROTO_TCP, nlm_tcpport); | ||
| 238 | if (!err) | ||
| 239 | warned = 0; | ||
| 240 | else if (warned++ == 0) | ||
| 241 | printk(KERN_WARNING | ||
| 242 | "lockd_up: makesock failed, error=%d\n", err); | ||
| 243 | return err; | ||
| 244 | } | ||
| 245 | |||
| 208 | /* | 246 | /* |
| 209 | * Bring up the lockd process if it's not already up. | 247 | * Bring up the lockd process if it's not already up. |
| 210 | */ | 248 | */ |
| 211 | int | 249 | int |
| 212 | lockd_up(void) | 250 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ |
| 213 | { | 251 | { |
| 214 | static int warned; | ||
| 215 | struct svc_serv * serv; | 252 | struct svc_serv * serv; |
| 216 | int error = 0; | 253 | int error = 0; |
| 217 | 254 | ||
| 218 | mutex_lock(&nlmsvc_mutex); | 255 | mutex_lock(&nlmsvc_mutex); |
| 219 | /* | 256 | /* |
| 220 | * Unconditionally increment the user count ... this is | ||
| 221 | * the number of clients who _want_ a lockd process. | ||
| 222 | */ | ||
| 223 | nlmsvc_users++; | ||
| 224 | /* | ||
| 225 | * Check whether we're already up and running. | 257 | * Check whether we're already up and running. |
| 226 | */ | 258 | */ |
| 227 | if (nlmsvc_pid) | 259 | if (nlmsvc_pid) { |
| 260 | if (proto) | ||
| 261 | error = make_socks(nlmsvc_serv, proto); | ||
| 228 | goto out; | 262 | goto out; |
| 263 | } | ||
| 229 | 264 | ||
| 230 | /* | 265 | /* |
| 231 | * Sanity check: if there's no pid, | 266 | * Sanity check: if there's no pid, |
| 232 | * we should be the first user ... | 267 | * we should be the first user ... |
| 233 | */ | 268 | */ |
| 234 | if (nlmsvc_users > 1) | 269 | if (nlmsvc_users) |
| 235 | printk(KERN_WARNING | 270 | printk(KERN_WARNING |
| 236 | "lockd_up: no pid, %d users??\n", nlmsvc_users); | 271 | "lockd_up: no pid, %d users??\n", nlmsvc_users); |
| 237 | 272 | ||
| 238 | error = -ENOMEM; | 273 | error = -ENOMEM; |
| 239 | serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE); | 274 | serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL); |
| 240 | if (!serv) { | 275 | if (!serv) { |
| 241 | printk(KERN_WARNING "lockd_up: create service failed\n"); | 276 | printk(KERN_WARNING "lockd_up: create service failed\n"); |
| 242 | goto out; | 277 | goto out; |
| 243 | } | 278 | } |
| 244 | 279 | ||
| 245 | if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0 | 280 | if ((error = make_socks(serv, proto)) < 0) |
| 246 | #ifdef CONFIG_NFSD_TCP | ||
| 247 | || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0 | ||
| 248 | #endif | ||
| 249 | ) { | ||
| 250 | if (warned++ == 0) | ||
| 251 | printk(KERN_WARNING | ||
| 252 | "lockd_up: makesock failed, error=%d\n", error); | ||
| 253 | goto destroy_and_out; | 281 | goto destroy_and_out; |
| 254 | } | ||
| 255 | warned = 0; | ||
| 256 | 282 | ||
| 257 | /* | 283 | /* |
| 258 | * Create the kernel thread and wait for it to start. | 284 | * Create the kernel thread and wait for it to start. |
| @@ -272,6 +298,8 @@ lockd_up(void) | |||
| 272 | destroy_and_out: | 298 | destroy_and_out: |
| 273 | svc_destroy(serv); | 299 | svc_destroy(serv); |
| 274 | out: | 300 | out: |
| 301 | if (!error) | ||
| 302 | nlmsvc_users++; | ||
| 275 | mutex_unlock(&nlmsvc_mutex); | 303 | mutex_unlock(&nlmsvc_mutex); |
| 276 | return error; | 304 | return error; |
| 277 | } | 305 | } |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index c9d419703cf3..93c00ee7189d 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
| @@ -325,7 +325,7 @@ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) | |||
| 325 | { | 325 | { |
| 326 | locks_copy_lock(&call->a_args.lock.fl, &lock->fl); | 326 | locks_copy_lock(&call->a_args.lock.fl, &lock->fl); |
| 327 | memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); | 327 | memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); |
| 328 | call->a_args.lock.caller = system_utsname.nodename; | 328 | call->a_args.lock.caller = utsname()->nodename; |
| 329 | call->a_args.lock.oh.len = lock->oh.len; | 329 | call->a_args.lock.oh.len = lock->oh.len; |
| 330 | 330 | ||
| 331 | /* set default data area */ | 331 | /* set default data area */ |
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 033ea4ac2c30..61c46facf257 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c | |||
| @@ -515,7 +515,7 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) | |||
| 515 | */ | 515 | */ |
| 516 | #define NLM_void_sz 0 | 516 | #define NLM_void_sz 0 |
| 517 | #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) | 517 | #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) |
| 518 | #define NLM_caller_sz 1+XDR_QUADLEN(sizeof(system_utsname.nodename)) | 518 | #define NLM_caller_sz 1+XDR_QUADLEN(sizeof(utsname()->nodename)) |
| 519 | #define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ) | 519 | #define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ) |
| 520 | /* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */ | 520 | /* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */ |
| 521 | #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) | 521 | #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) |
diff --git a/fs/locks.c b/fs/locks.c index 21dfadfca2bc..e0b6a80649a0 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
| 1514 | goto out_unlock; | 1514 | goto out_unlock; |
| 1515 | } | 1515 | } |
| 1516 | 1516 | ||
| 1517 | error = f_setown(filp, current->pid, 0); | 1517 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
| 1518 | out_unlock: | 1518 | out_unlock: |
| 1519 | unlock_kernel(); | 1519 | unlock_kernel(); |
| 1520 | return error; | 1520 | return error; |
diff --git a/fs/namespace.c b/fs/namespace.c index 66d921e14fee..55442a6cf221 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -133,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | |||
| 133 | 133 | ||
| 134 | static inline int check_mnt(struct vfsmount *mnt) | 134 | static inline int check_mnt(struct vfsmount *mnt) |
| 135 | { | 135 | { |
| 136 | return mnt->mnt_namespace == current->namespace; | 136 | return mnt->mnt_namespace == current->nsproxy->namespace; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | static void touch_namespace(struct namespace *ns) | 139 | static void touch_namespace(struct namespace *ns) |
| @@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
| 830 | if (parent_nd) { | 830 | if (parent_nd) { |
| 831 | detach_mnt(source_mnt, parent_nd); | 831 | detach_mnt(source_mnt, parent_nd); |
| 832 | attach_mnt(source_mnt, nd); | 832 | attach_mnt(source_mnt, nd); |
| 833 | touch_namespace(current->namespace); | 833 | touch_namespace(current->nsproxy->namespace); |
| 834 | } else { | 834 | } else { |
| 835 | mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); | 835 | mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); |
| 836 | commit_tree(source_mnt); | 836 | commit_tree(source_mnt); |
| @@ -1441,7 +1441,7 @@ dput_out: | |||
| 1441 | */ | 1441 | */ |
| 1442 | struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) | 1442 | struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) |
| 1443 | { | 1443 | { |
| 1444 | struct namespace *namespace = tsk->namespace; | 1444 | struct namespace *namespace = tsk->nsproxy->namespace; |
| 1445 | struct namespace *new_ns; | 1445 | struct namespace *new_ns; |
| 1446 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; | 1446 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; |
| 1447 | struct vfsmount *p, *q; | 1447 | struct vfsmount *p, *q; |
| @@ -1508,7 +1508,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) | |||
| 1508 | 1508 | ||
| 1509 | int copy_namespace(int flags, struct task_struct *tsk) | 1509 | int copy_namespace(int flags, struct task_struct *tsk) |
| 1510 | { | 1510 | { |
| 1511 | struct namespace *namespace = tsk->namespace; | 1511 | struct namespace *namespace = tsk->nsproxy->namespace; |
| 1512 | struct namespace *new_ns; | 1512 | struct namespace *new_ns; |
| 1513 | int err = 0; | 1513 | int err = 0; |
| 1514 | 1514 | ||
| @@ -1531,7 +1531,7 @@ int copy_namespace(int flags, struct task_struct *tsk) | |||
| 1531 | goto out; | 1531 | goto out; |
| 1532 | } | 1532 | } |
| 1533 | 1533 | ||
| 1534 | tsk->namespace = new_ns; | 1534 | tsk->nsproxy->namespace = new_ns; |
| 1535 | 1535 | ||
| 1536 | out: | 1536 | out: |
| 1537 | put_namespace(namespace); | 1537 | put_namespace(namespace); |
| @@ -1754,7 +1754,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
| 1754 | detach_mnt(user_nd.mnt, &root_parent); | 1754 | detach_mnt(user_nd.mnt, &root_parent); |
| 1755 | attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ | 1755 | attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ |
| 1756 | attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ | 1756 | attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ |
| 1757 | touch_namespace(current->namespace); | 1757 | touch_namespace(current->nsproxy->namespace); |
| 1758 | spin_unlock(&vfsmount_lock); | 1758 | spin_unlock(&vfsmount_lock); |
| 1759 | chroot_fs_refs(&user_nd, &new_nd); | 1759 | chroot_fs_refs(&user_nd, &new_nd); |
| 1760 | security_sb_post_pivotroot(&user_nd, &new_nd); | 1760 | security_sb_post_pivotroot(&user_nd, &new_nd); |
| @@ -1780,7 +1780,6 @@ static void __init init_mount_tree(void) | |||
| 1780 | { | 1780 | { |
| 1781 | struct vfsmount *mnt; | 1781 | struct vfsmount *mnt; |
| 1782 | struct namespace *namespace; | 1782 | struct namespace *namespace; |
| 1783 | struct task_struct *g, *p; | ||
| 1784 | 1783 | ||
| 1785 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 1784 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); |
| 1786 | if (IS_ERR(mnt)) | 1785 | if (IS_ERR(mnt)) |
| @@ -1796,13 +1795,8 @@ static void __init init_mount_tree(void) | |||
| 1796 | namespace->root = mnt; | 1795 | namespace->root = mnt; |
| 1797 | mnt->mnt_namespace = namespace; | 1796 | mnt->mnt_namespace = namespace; |
| 1798 | 1797 | ||
| 1799 | init_task.namespace = namespace; | 1798 | init_task.nsproxy->namespace = namespace; |
| 1800 | read_lock(&tasklist_lock); | 1799 | get_namespace(namespace); |
| 1801 | do_each_thread(g, p) { | ||
| 1802 | get_namespace(namespace); | ||
| 1803 | p->namespace = namespace; | ||
| 1804 | } while_each_thread(g, p); | ||
| 1805 | read_unlock(&tasklist_lock); | ||
| 1806 | 1800 | ||
| 1807 | set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); | 1801 | set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root); |
| 1808 | set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); | 1802 | set_fs_root(current->fs, namespace->root, namespace->root->mnt_root); |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a3ee11364db0..7933e2e99dbc 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -58,7 +58,6 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
| 58 | */ | 58 | */ |
| 59 | static void nfs_callback_svc(struct svc_rqst *rqstp) | 59 | static void nfs_callback_svc(struct svc_rqst *rqstp) |
| 60 | { | 60 | { |
| 61 | struct svc_serv *serv = rqstp->rq_server; | ||
| 62 | int err; | 61 | int err; |
| 63 | 62 | ||
| 64 | __module_get(THIS_MODULE); | 63 | __module_get(THIS_MODULE); |
| @@ -80,7 +79,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
| 80 | /* | 79 | /* |
| 81 | * Listen for a request on the socket | 80 | * Listen for a request on the socket |
| 82 | */ | 81 | */ |
| 83 | err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT); | 82 | err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); |
| 84 | if (err == -EAGAIN || err == -EINTR) | 83 | if (err == -EAGAIN || err == -EINTR) |
| 85 | continue; | 84 | continue; |
| 86 | if (err < 0) { | 85 | if (err < 0) { |
| @@ -91,7 +90,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
| 91 | } | 90 | } |
| 92 | dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__, | 91 | dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__, |
| 93 | NIPQUAD(rqstp->rq_addr.sin_addr.s_addr)); | 92 | NIPQUAD(rqstp->rq_addr.sin_addr.s_addr)); |
| 94 | svc_process(serv, rqstp); | 93 | svc_process(rqstp); |
| 95 | } | 94 | } |
| 96 | 95 | ||
| 97 | svc_exit_thread(rqstp); | 96 | svc_exit_thread(rqstp); |
| @@ -116,7 +115,7 @@ int nfs_callback_up(void) | |||
| 116 | goto out; | 115 | goto out; |
| 117 | init_completion(&nfs_callback_info.started); | 116 | init_completion(&nfs_callback_info.started); |
| 118 | init_completion(&nfs_callback_info.stopped); | 117 | init_completion(&nfs_callback_info.stopped); |
| 119 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE); | 118 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); |
| 120 | ret = -ENOMEM; | 119 | ret = -ENOMEM; |
| 121 | if (!serv) | 120 | if (!serv) |
| 122 | goto out_err; | 121 | goto out_err; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index ec1938d4b814..8106f3b29e4a 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -460,7 +460,8 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
| 460 | goto out; | 460 | goto out; |
| 461 | if (server->flags & NFS_MOUNT_NONLM) | 461 | if (server->flags & NFS_MOUNT_NONLM) |
| 462 | goto out; | 462 | goto out; |
| 463 | error = lockd_up(); | 463 | error = lockd_up((server->flags & NFS_MOUNT_TCP) ? |
| 464 | IPPROTO_TCP : IPPROTO_UDP); | ||
| 464 | if (error < 0) | 465 | if (error < 0) |
| 465 | server->flags |= NFS_MOUNT_NONLM; | 466 | server->flags |= NFS_MOUNT_NONLM; |
| 466 | else | 467 | else |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index c0a754ecdee6..1d656a645199 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
| @@ -312,7 +312,7 @@ static int __init root_nfs_name(char *name) | |||
| 312 | /* Override them by options set on kernel command-line */ | 312 | /* Override them by options set on kernel command-line */ |
| 313 | root_nfs_parse(name, buf); | 313 | root_nfs_parse(name, buf); |
| 314 | 314 | ||
| 315 | cp = system_utsname.nodename; | 315 | cp = utsname()->nodename; |
| 316 | if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { | 316 | if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { |
| 317 | printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); | 317 | printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); |
| 318 | return -1; | 318 | return -1; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 01bc68c628ad..cfe141e5d759 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
| @@ -370,7 +370,7 @@ static int check_export(struct inode *inode, int flags) | |||
| 370 | */ | 370 | */ |
| 371 | if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && | 371 | if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && |
| 372 | !(flags & NFSEXP_FSID)) { | 372 | !(flags & NFSEXP_FSID)) { |
| 373 | dprintk("exp_export: export of non-dev fs without fsid"); | 373 | dprintk("exp_export: export of non-dev fs without fsid\n"); |
| 374 | return -EINVAL; | 374 | return -EINVAL; |
| 375 | } | 375 | } |
| 376 | if (!inode->i_sb->s_export_op) { | 376 | if (!inode->i_sb->s_export_op) { |
| @@ -1078,6 +1078,7 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |||
| 1078 | /* Iterator */ | 1078 | /* Iterator */ |
| 1079 | 1079 | ||
| 1080 | static void *e_start(struct seq_file *m, loff_t *pos) | 1080 | static void *e_start(struct seq_file *m, loff_t *pos) |
| 1081 | __acquires(svc_export_cache.hash_lock) | ||
| 1081 | { | 1082 | { |
| 1082 | loff_t n = *pos; | 1083 | loff_t n = *pos; |
| 1083 | unsigned hash, export; | 1084 | unsigned hash, export; |
| @@ -1086,7 +1087,7 @@ static void *e_start(struct seq_file *m, loff_t *pos) | |||
| 1086 | exp_readlock(); | 1087 | exp_readlock(); |
| 1087 | read_lock(&svc_export_cache.hash_lock); | 1088 | read_lock(&svc_export_cache.hash_lock); |
| 1088 | if (!n--) | 1089 | if (!n--) |
| 1089 | return (void *)1; | 1090 | return SEQ_START_TOKEN; |
| 1090 | hash = n >> 32; | 1091 | hash = n >> 32; |
| 1091 | export = n & ((1LL<<32) - 1); | 1092 | export = n & ((1LL<<32) - 1); |
| 1092 | 1093 | ||
| @@ -1110,7 +1111,7 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos) | |||
| 1110 | struct cache_head *ch = p; | 1111 | struct cache_head *ch = p; |
| 1111 | int hash = (*pos >> 32); | 1112 | int hash = (*pos >> 32); |
| 1112 | 1113 | ||
| 1113 | if (p == (void *)1) | 1114 | if (p == SEQ_START_TOKEN) |
| 1114 | hash = 0; | 1115 | hash = 0; |
| 1115 | else if (ch->next == NULL) { | 1116 | else if (ch->next == NULL) { |
| 1116 | hash++; | 1117 | hash++; |
| @@ -1131,6 +1132,7 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos) | |||
| 1131 | } | 1132 | } |
| 1132 | 1133 | ||
| 1133 | static void e_stop(struct seq_file *m, void *p) | 1134 | static void e_stop(struct seq_file *m, void *p) |
| 1135 | __releases(svc_export_cache.hash_lock) | ||
| 1134 | { | 1136 | { |
| 1135 | read_unlock(&svc_export_cache.hash_lock); | 1137 | read_unlock(&svc_export_cache.hash_lock); |
| 1136 | exp_readunlock(); | 1138 | exp_readunlock(); |
| @@ -1178,15 +1180,13 @@ static int e_show(struct seq_file *m, void *p) | |||
| 1178 | { | 1180 | { |
| 1179 | struct cache_head *cp = p; | 1181 | struct cache_head *cp = p; |
| 1180 | struct svc_export *exp = container_of(cp, struct svc_export, h); | 1182 | struct svc_export *exp = container_of(cp, struct svc_export, h); |
| 1181 | svc_client *clp; | ||
| 1182 | 1183 | ||
| 1183 | if (p == (void *)1) { | 1184 | if (p == SEQ_START_TOKEN) { |
| 1184 | seq_puts(m, "# Version 1.1\n"); | 1185 | seq_puts(m, "# Version 1.1\n"); |
| 1185 | seq_puts(m, "# Path Client(Flags) # IPs\n"); | 1186 | seq_puts(m, "# Path Client(Flags) # IPs\n"); |
| 1186 | return 0; | 1187 | return 0; |
| 1187 | } | 1188 | } |
| 1188 | 1189 | ||
| 1189 | clp = exp->ex_client; | ||
| 1190 | cache_get(&exp->h); | 1190 | cache_get(&exp->h); |
| 1191 | if (cache_check(&svc_export_cache, &exp->h, NULL)) | 1191 | if (cache_check(&svc_export_cache, &exp->h, NULL)) |
| 1192 | return 0; | 1192 | return 0; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 8583d99ee740..f6ca9fb3fc63 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -131,7 +131,7 @@ xdr_error: \ | |||
| 131 | #define READ_BUF(nbytes) do { \ | 131 | #define READ_BUF(nbytes) do { \ |
| 132 | p = xdr_inline_decode(xdr, nbytes); \ | 132 | p = xdr_inline_decode(xdr, nbytes); \ |
| 133 | if (!p) { \ | 133 | if (!p) { \ |
| 134 | dprintk("NFSD: %s: reply buffer overflowed in line %d.", \ | 134 | dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \ |
| 135 | __FUNCTION__, __LINE__); \ | 135 | __FUNCTION__, __LINE__); \ |
| 136 | return -EIO; \ | 136 | return -EIO; \ |
| 137 | } \ | 137 | } \ |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index ee4eff27aedc..15ded7a30a72 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -600,7 +600,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se | |||
| 600 | &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); | 600 | &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); |
| 601 | nfs4_unlock_state(); | 601 | nfs4_unlock_state(); |
| 602 | if (status) { | 602 | if (status) { |
| 603 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!"); | 603 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); |
| 604 | return status; | 604 | return status; |
| 605 | } | 605 | } |
| 606 | } | 606 | } |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7046ac9cf97f..5c6a477c20ec 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -23,10 +23,14 @@ | |||
| 23 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
| 24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
| 25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
| 26 | #include <linux/smp_lock.h> | ||
| 27 | #include <linux/ctype.h> | ||
| 26 | 28 | ||
| 27 | #include <linux/nfs.h> | 29 | #include <linux/nfs.h> |
| 28 | #include <linux/nfsd_idmap.h> | 30 | #include <linux/nfsd_idmap.h> |
| 31 | #include <linux/lockd/bind.h> | ||
| 29 | #include <linux/sunrpc/svc.h> | 32 | #include <linux/sunrpc/svc.h> |
| 33 | #include <linux/sunrpc/svcsock.h> | ||
| 30 | #include <linux/nfsd/nfsd.h> | 34 | #include <linux/nfsd/nfsd.h> |
| 31 | #include <linux/nfsd/cache.h> | 35 | #include <linux/nfsd/cache.h> |
| 32 | #include <linux/nfsd/xdr.h> | 36 | #include <linux/nfsd/xdr.h> |
| @@ -35,8 +39,6 @@ | |||
| 35 | 39 | ||
| 36 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
| 37 | 41 | ||
| 38 | unsigned int nfsd_versbits = ~0; | ||
| 39 | |||
| 40 | /* | 42 | /* |
| 41 | * We have a single directory with 9 nodes in it. | 43 | * We have a single directory with 9 nodes in it. |
| 42 | */ | 44 | */ |
| @@ -52,7 +54,9 @@ enum { | |||
| 52 | NFSD_List, | 54 | NFSD_List, |
| 53 | NFSD_Fh, | 55 | NFSD_Fh, |
| 54 | NFSD_Threads, | 56 | NFSD_Threads, |
| 57 | NFSD_Pool_Threads, | ||
| 55 | NFSD_Versions, | 58 | NFSD_Versions, |
| 59 | NFSD_Ports, | ||
| 56 | /* | 60 | /* |
| 57 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] | 61 | * The below MUST come last. Otherwise we leave a hole in nfsd_files[] |
| 58 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops | 62 | * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops |
| @@ -75,7 +79,9 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size); | |||
| 75 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); | 79 | static ssize_t write_getfs(struct file *file, char *buf, size_t size); |
| 76 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 80 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
| 77 | static ssize_t write_threads(struct file *file, char *buf, size_t size); | 81 | static ssize_t write_threads(struct file *file, char *buf, size_t size); |
| 82 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); | ||
| 78 | static ssize_t write_versions(struct file *file, char *buf, size_t size); | 83 | static ssize_t write_versions(struct file *file, char *buf, size_t size); |
| 84 | static ssize_t write_ports(struct file *file, char *buf, size_t size); | ||
| 79 | #ifdef CONFIG_NFSD_V4 | 85 | #ifdef CONFIG_NFSD_V4 |
| 80 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | 86 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); |
| 81 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 87 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
| @@ -91,7 +97,9 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
| 91 | [NFSD_Getfs] = write_getfs, | 97 | [NFSD_Getfs] = write_getfs, |
| 92 | [NFSD_Fh] = write_filehandle, | 98 | [NFSD_Fh] = write_filehandle, |
| 93 | [NFSD_Threads] = write_threads, | 99 | [NFSD_Threads] = write_threads, |
| 100 | [NFSD_Pool_Threads] = write_pool_threads, | ||
| 94 | [NFSD_Versions] = write_versions, | 101 | [NFSD_Versions] = write_versions, |
| 102 | [NFSD_Ports] = write_ports, | ||
| 95 | #ifdef CONFIG_NFSD_V4 | 103 | #ifdef CONFIG_NFSD_V4 |
| 96 | [NFSD_Leasetime] = write_leasetime, | 104 | [NFSD_Leasetime] = write_leasetime, |
| 97 | [NFSD_RecoveryDir] = write_recoverydir, | 105 | [NFSD_RecoveryDir] = write_recoverydir, |
| @@ -358,6 +366,72 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
| 358 | return strlen(buf); | 366 | return strlen(buf); |
| 359 | } | 367 | } |
| 360 | 368 | ||
| 369 | extern int nfsd_nrpools(void); | ||
| 370 | extern int nfsd_get_nrthreads(int n, int *); | ||
| 371 | extern int nfsd_set_nrthreads(int n, int *); | ||
| 372 | |||
| 373 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | ||
| 374 | { | ||
| 375 | /* if size > 0, look for an array of number of threads per node | ||
| 376 | * and apply them then write out number of threads per node as reply | ||
| 377 | */ | ||
| 378 | char *mesg = buf; | ||
| 379 | int i; | ||
| 380 | int rv; | ||
| 381 | int len; | ||
| 382 | int npools = nfsd_nrpools(); | ||
| 383 | int *nthreads; | ||
| 384 | |||
| 385 | if (npools == 0) { | ||
| 386 | /* | ||
| 387 | * NFS is shut down. The admin can start it by | ||
| 388 | * writing to the threads file but NOT the pool_threads | ||
| 389 | * file, sorry. Report zero threads. | ||
| 390 | */ | ||
| 391 | strcpy(buf, "0\n"); | ||
| 392 | return strlen(buf); | ||
| 393 | } | ||
| 394 | |||
| 395 | nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL); | ||
| 396 | if (nthreads == NULL) | ||
| 397 | return -ENOMEM; | ||
| 398 | |||
| 399 | if (size > 0) { | ||
| 400 | for (i = 0; i < npools; i++) { | ||
| 401 | rv = get_int(&mesg, &nthreads[i]); | ||
| 402 | if (rv == -ENOENT) | ||
| 403 | break; /* fewer numbers than pools */ | ||
| 404 | if (rv) | ||
| 405 | goto out_free; /* syntax error */ | ||
| 406 | rv = -EINVAL; | ||
| 407 | if (nthreads[i] < 0) | ||
| 408 | goto out_free; | ||
| 409 | } | ||
| 410 | rv = nfsd_set_nrthreads(i, nthreads); | ||
| 411 | if (rv) | ||
| 412 | goto out_free; | ||
| 413 | } | ||
| 414 | |||
| 415 | rv = nfsd_get_nrthreads(npools, nthreads); | ||
| 416 | if (rv) | ||
| 417 | goto out_free; | ||
| 418 | |||
| 419 | mesg = buf; | ||
| 420 | size = SIMPLE_TRANSACTION_LIMIT; | ||
| 421 | for (i = 0; i < npools && size > 0; i++) { | ||
| 422 | snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' ')); | ||
| 423 | len = strlen(mesg); | ||
| 424 | size -= len; | ||
| 425 | mesg += len; | ||
| 426 | } | ||
| 427 | |||
| 428 | return (mesg-buf); | ||
| 429 | |||
| 430 | out_free: | ||
| 431 | kfree(nthreads); | ||
| 432 | return rv; | ||
| 433 | } | ||
| 434 | |||
| 361 | static ssize_t write_versions(struct file *file, char *buf, size_t size) | 435 | static ssize_t write_versions(struct file *file, char *buf, size_t size) |
| 362 | { | 436 | { |
| 363 | /* | 437 | /* |
| @@ -372,6 +446,10 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
| 372 | 446 | ||
| 373 | if (size>0) { | 447 | if (size>0) { |
| 374 | if (nfsd_serv) | 448 | if (nfsd_serv) |
| 449 | /* Cannot change versions without updating | ||
| 450 | * nfsd_serv->sv_xdrsize, and reallocing | ||
| 451 | * rq_argp and rq_resp | ||
| 452 | */ | ||
| 375 | return -EBUSY; | 453 | return -EBUSY; |
| 376 | if (buf[size-1] != '\n') | 454 | if (buf[size-1] != '\n') |
| 377 | return -EINVAL; | 455 | return -EINVAL; |
| @@ -390,10 +468,7 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
| 390 | case 2: | 468 | case 2: |
| 391 | case 3: | 469 | case 3: |
| 392 | case 4: | 470 | case 4: |
| 393 | if (sign != '-') | 471 | nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); |
| 394 | NFSCTL_VERSET(nfsd_versbits, num); | ||
| 395 | else | ||
| 396 | NFSCTL_VERUNSET(nfsd_versbits, num); | ||
| 397 | break; | 472 | break; |
| 398 | default: | 473 | default: |
| 399 | return -EINVAL; | 474 | return -EINVAL; |
| @@ -404,16 +479,15 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
| 404 | /* If all get turned off, turn them back on, as | 479 | /* If all get turned off, turn them back on, as |
| 405 | * having no versions is BAD | 480 | * having no versions is BAD |
| 406 | */ | 481 | */ |
| 407 | if ((nfsd_versbits & NFSCTL_VERALL)==0) | 482 | nfsd_reset_versions(); |
| 408 | nfsd_versbits = NFSCTL_VERALL; | ||
| 409 | } | 483 | } |
| 410 | /* Now write current state into reply buffer */ | 484 | /* Now write current state into reply buffer */ |
| 411 | len = 0; | 485 | len = 0; |
| 412 | sep = ""; | 486 | sep = ""; |
| 413 | for (num=2 ; num <= 4 ; num++) | 487 | for (num=2 ; num <= 4 ; num++) |
| 414 | if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) { | 488 | if (nfsd_vers(num, NFSD_AVAIL)) { |
| 415 | len += sprintf(buf+len, "%s%c%d", sep, | 489 | len += sprintf(buf+len, "%s%c%d", sep, |
| 416 | NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-', | 490 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
| 417 | num); | 491 | num); |
| 418 | sep = " "; | 492 | sep = " "; |
| 419 | } | 493 | } |
| @@ -421,6 +495,62 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
| 421 | return len; | 495 | return len; |
| 422 | } | 496 | } |
| 423 | 497 | ||
| 498 | static ssize_t write_ports(struct file *file, char *buf, size_t size) | ||
| 499 | { | ||
| 500 | if (size == 0) { | ||
| 501 | int len = 0; | ||
| 502 | lock_kernel(); | ||
| 503 | if (nfsd_serv) | ||
| 504 | len = svc_sock_names(buf, nfsd_serv, NULL); | ||
| 505 | unlock_kernel(); | ||
| 506 | return len; | ||
| 507 | } | ||
| 508 | /* Either a single 'fd' number is written, in which | ||
| 509 | * case it must be for a socket of a supported family/protocol, | ||
| 510 | * and we use it as an nfsd socket, or | ||
| 511 | * A '-' followed by the 'name' of a socket in which case | ||
| 512 | * we close the socket. | ||
| 513 | */ | ||
| 514 | if (isdigit(buf[0])) { | ||
| 515 | char *mesg = buf; | ||
| 516 | int fd; | ||
| 517 | int err; | ||
| 518 | err = get_int(&mesg, &fd); | ||
| 519 | if (err) | ||
| 520 | return -EINVAL; | ||
| 521 | if (fd < 0) | ||
| 522 | return -EINVAL; | ||
| 523 | err = nfsd_create_serv(); | ||
| 524 | if (!err) { | ||
| 525 | int proto = 0; | ||
| 526 | err = lockd_up(proto); | ||
| 527 | if (!err) { | ||
| 528 | err = svc_addsock(nfsd_serv, fd, buf, &proto); | ||
| 529 | if (err) | ||
| 530 | lockd_down(); | ||
| 531 | } | ||
| 532 | /* Decrease the count, but don't shutdown the | ||
| 533 | * the service | ||
| 534 | */ | ||
| 535 | nfsd_serv->sv_nrthreads--; | ||
| 536 | } | ||
| 537 | return err; | ||
| 538 | } | ||
| 539 | if (buf[0] == '-') { | ||
| 540 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | ||
| 541 | int len = 0; | ||
| 542 | if (!toclose) | ||
| 543 | return -ENOMEM; | ||
| 544 | lock_kernel(); | ||
| 545 | if (nfsd_serv) | ||
| 546 | len = svc_sock_names(buf, nfsd_serv, toclose); | ||
| 547 | unlock_kernel(); | ||
| 548 | kfree(toclose); | ||
| 549 | return len; | ||
| 550 | } | ||
| 551 | return -EINVAL; | ||
| 552 | } | ||
| 553 | |||
| 424 | #ifdef CONFIG_NFSD_V4 | 554 | #ifdef CONFIG_NFSD_V4 |
| 425 | extern time_t nfs4_leasetime(void); | 555 | extern time_t nfs4_leasetime(void); |
| 426 | 556 | ||
| @@ -483,7 +613,9 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
| 483 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 613 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
| 484 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, | 614 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 485 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 615 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 616 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, | ||
| 486 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, | 617 | [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 618 | [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, | ||
| 487 | #ifdef CONFIG_NFSD_V4 | 619 | #ifdef CONFIG_NFSD_V4 |
| 488 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 620 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
| 489 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, | 621 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ec1decf29bab..19443056ec30 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -57,12 +57,6 @@ static atomic_t nfsd_busy; | |||
| 57 | static unsigned long nfsd_last_call; | 57 | static unsigned long nfsd_last_call; |
| 58 | static DEFINE_SPINLOCK(nfsd_call_lock); | 58 | static DEFINE_SPINLOCK(nfsd_call_lock); |
| 59 | 59 | ||
| 60 | struct nfsd_list { | ||
| 61 | struct list_head list; | ||
| 62 | struct task_struct *task; | ||
| 63 | }; | ||
| 64 | static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); | ||
| 65 | |||
| 66 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 60 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
| 67 | static struct svc_stat nfsd_acl_svcstats; | 61 | static struct svc_stat nfsd_acl_svcstats; |
| 68 | static struct svc_version * nfsd_acl_version[] = { | 62 | static struct svc_version * nfsd_acl_version[] = { |
| @@ -117,6 +111,32 @@ struct svc_program nfsd_program = { | |||
| 117 | 111 | ||
| 118 | }; | 112 | }; |
| 119 | 113 | ||
| 114 | int nfsd_vers(int vers, enum vers_op change) | ||
| 115 | { | ||
| 116 | if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) | ||
| 117 | return -1; | ||
| 118 | switch(change) { | ||
| 119 | case NFSD_SET: | ||
| 120 | nfsd_versions[vers] = nfsd_version[vers]; | ||
| 121 | break; | ||
| 122 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
| 123 | if (vers < NFSD_ACL_NRVERS) | ||
| 124 | nfsd_acl_version[vers] = nfsd_acl_version[vers]; | ||
| 125 | #endif | ||
| 126 | case NFSD_CLEAR: | ||
| 127 | nfsd_versions[vers] = NULL; | ||
| 128 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
| 129 | if (vers < NFSD_ACL_NRVERS) | ||
| 130 | nfsd_acl_version[vers] = NULL; | ||
| 131 | #endif | ||
| 132 | break; | ||
| 133 | case NFSD_TEST: | ||
| 134 | return nfsd_versions[vers] != NULL; | ||
| 135 | case NFSD_AVAIL: | ||
| 136 | return nfsd_version[vers] != NULL; | ||
| 137 | } | ||
| 138 | return 0; | ||
| 139 | } | ||
| 120 | /* | 140 | /* |
| 121 | * Maximum number of nfsd processes | 141 | * Maximum number of nfsd processes |
| 122 | */ | 142 | */ |
| @@ -130,16 +150,175 @@ int nfsd_nrthreads(void) | |||
| 130 | return nfsd_serv->sv_nrthreads; | 150 | return nfsd_serv->sv_nrthreads; |
| 131 | } | 151 | } |
| 132 | 152 | ||
| 153 | static int killsig; /* signal that was used to kill last nfsd */ | ||
| 154 | static void nfsd_last_thread(struct svc_serv *serv) | ||
| 155 | { | ||
| 156 | /* When last nfsd thread exits we need to do some clean-up */ | ||
| 157 | struct svc_sock *svsk; | ||
| 158 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) | ||
| 159 | lockd_down(); | ||
| 160 | nfsd_serv = NULL; | ||
| 161 | nfsd_racache_shutdown(); | ||
| 162 | nfs4_state_shutdown(); | ||
| 163 | |||
| 164 | printk(KERN_WARNING "nfsd: last server has exited\n"); | ||
| 165 | if (killsig != SIG_NOCLEAN) { | ||
| 166 | printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); | ||
| 167 | nfsd_export_flush(); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | void nfsd_reset_versions(void) | ||
| 172 | { | ||
| 173 | int found_one = 0; | ||
| 174 | int i; | ||
| 175 | |||
| 176 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { | ||
| 177 | if (nfsd_program.pg_vers[i]) | ||
| 178 | found_one = 1; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (!found_one) { | ||
| 182 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) | ||
| 183 | nfsd_program.pg_vers[i] = nfsd_version[i]; | ||
| 184 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||
| 185 | for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) | ||
| 186 | nfsd_acl_program.pg_vers[i] = | ||
| 187 | nfsd_acl_version[i]; | ||
| 188 | #endif | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | int nfsd_create_serv(void) | ||
| 193 | { | ||
| 194 | int err = 0; | ||
| 195 | lock_kernel(); | ||
| 196 | if (nfsd_serv) { | ||
| 197 | svc_get(nfsd_serv); | ||
| 198 | unlock_kernel(); | ||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | |||
| 202 | atomic_set(&nfsd_busy, 0); | ||
| 203 | nfsd_serv = svc_create_pooled(&nfsd_program, NFSD_BUFSIZE, | ||
| 204 | nfsd_last_thread, | ||
| 205 | nfsd, SIG_NOCLEAN, THIS_MODULE); | ||
| 206 | if (nfsd_serv == NULL) | ||
| 207 | err = -ENOMEM; | ||
| 208 | unlock_kernel(); | ||
| 209 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | ||
| 210 | return err; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int nfsd_init_socks(int port) | ||
| 214 | { | ||
| 215 | int error; | ||
| 216 | if (!list_empty(&nfsd_serv->sv_permsocks)) | ||
| 217 | return 0; | ||
| 218 | |||
| 219 | error = lockd_up(IPPROTO_UDP); | ||
| 220 | if (error >= 0) { | ||
| 221 | error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); | ||
| 222 | if (error < 0) | ||
| 223 | lockd_down(); | ||
| 224 | } | ||
| 225 | if (error < 0) | ||
| 226 | return error; | ||
| 227 | |||
| 228 | #ifdef CONFIG_NFSD_TCP | ||
| 229 | error = lockd_up(IPPROTO_TCP); | ||
| 230 | if (error >= 0) { | ||
| 231 | error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); | ||
| 232 | if (error < 0) | ||
| 233 | lockd_down(); | ||
| 234 | } | ||
| 235 | if (error < 0) | ||
| 236 | return error; | ||
| 237 | #endif | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | int nfsd_nrpools(void) | ||
| 242 | { | ||
| 243 | if (nfsd_serv == NULL) | ||
| 244 | return 0; | ||
| 245 | else | ||
| 246 | return nfsd_serv->sv_nrpools; | ||
| 247 | } | ||
| 248 | |||
| 249 | int nfsd_get_nrthreads(int n, int *nthreads) | ||
| 250 | { | ||
| 251 | int i = 0; | ||
| 252 | |||
| 253 | if (nfsd_serv != NULL) { | ||
| 254 | for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++) | ||
| 255 | nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads; | ||
| 256 | } | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | int nfsd_set_nrthreads(int n, int *nthreads) | ||
| 262 | { | ||
| 263 | int i = 0; | ||
| 264 | int tot = 0; | ||
| 265 | int err = 0; | ||
| 266 | |||
| 267 | if (nfsd_serv == NULL || n <= 0) | ||
| 268 | return 0; | ||
| 269 | |||
| 270 | if (n > nfsd_serv->sv_nrpools) | ||
| 271 | n = nfsd_serv->sv_nrpools; | ||
| 272 | |||
| 273 | /* enforce a global maximum number of threads */ | ||
| 274 | tot = 0; | ||
| 275 | for (i = 0; i < n; i++) { | ||
| 276 | if (nthreads[i] > NFSD_MAXSERVS) | ||
| 277 | nthreads[i] = NFSD_MAXSERVS; | ||
| 278 | tot += nthreads[i]; | ||
| 279 | } | ||
| 280 | if (tot > NFSD_MAXSERVS) { | ||
| 281 | /* total too large: scale down requested numbers */ | ||
| 282 | for (i = 0; i < n && tot > 0; i++) { | ||
| 283 | int new = nthreads[i] * NFSD_MAXSERVS / tot; | ||
| 284 | tot -= (nthreads[i] - new); | ||
| 285 | nthreads[i] = new; | ||
| 286 | } | ||
| 287 | for (i = 0; i < n && tot > 0; i++) { | ||
| 288 | nthreads[i]--; | ||
| 289 | tot--; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | /* | ||
| 294 | * There must always be a thread in pool 0; the admin | ||
| 295 | * can't shut down NFS completely using pool_threads. | ||
| 296 | */ | ||
| 297 | if (nthreads[0] == 0) | ||
| 298 | nthreads[0] = 1; | ||
| 299 | |||
| 300 | /* apply the new numbers */ | ||
| 301 | lock_kernel(); | ||
| 302 | svc_get(nfsd_serv); | ||
| 303 | for (i = 0; i < n; i++) { | ||
| 304 | err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i], | ||
| 305 | nthreads[i]); | ||
| 306 | if (err) | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | svc_destroy(nfsd_serv); | ||
| 310 | unlock_kernel(); | ||
| 311 | |||
| 312 | return err; | ||
| 313 | } | ||
| 314 | |||
| 133 | int | 315 | int |
| 134 | nfsd_svc(unsigned short port, int nrservs) | 316 | nfsd_svc(unsigned short port, int nrservs) |
| 135 | { | 317 | { |
| 136 | int error; | 318 | int error; |
| 137 | int none_left, found_one, i; | ||
| 138 | struct list_head *victim; | ||
| 139 | 319 | ||
| 140 | lock_kernel(); | 320 | lock_kernel(); |
| 141 | dprintk("nfsd: creating service: vers 0x%x\n", | 321 | dprintk("nfsd: creating service\n"); |
| 142 | nfsd_versbits); | ||
| 143 | error = -EINVAL; | 322 | error = -EINVAL; |
| 144 | if (nrservs <= 0) | 323 | if (nrservs <= 0) |
| 145 | nrservs = 0; | 324 | nrservs = 0; |
| @@ -153,91 +332,20 @@ nfsd_svc(unsigned short port, int nrservs) | |||
| 153 | error = nfs4_state_start(); | 332 | error = nfs4_state_start(); |
| 154 | if (error<0) | 333 | if (error<0) |
| 155 | goto out; | 334 | goto out; |
| 156 | if (!nfsd_serv) { | ||
| 157 | /* | ||
| 158 | * Use the nfsd_ctlbits to define which | ||
| 159 | * versions that will be advertised. | ||
| 160 | * If nfsd_ctlbits doesn't list any version, | ||
| 161 | * export them all. | ||
| 162 | */ | ||
| 163 | found_one = 0; | ||
| 164 | |||
| 165 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { | ||
| 166 | if (NFSCTL_VERISSET(nfsd_versbits, i)) { | ||
| 167 | nfsd_program.pg_vers[i] = nfsd_version[i]; | ||
| 168 | found_one = 1; | ||
| 169 | } else | ||
| 170 | nfsd_program.pg_vers[i] = NULL; | ||
| 171 | } | ||
| 172 | 335 | ||
| 173 | if (!found_one) { | 336 | nfsd_reset_versions(); |
| 174 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) | ||
| 175 | nfsd_program.pg_vers[i] = nfsd_version[i]; | ||
| 176 | } | ||
| 177 | 337 | ||
| 338 | error = nfsd_create_serv(); | ||
| 178 | 339 | ||
| 179 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 340 | if (error) |
| 180 | found_one = 0; | 341 | goto out; |
| 181 | 342 | error = nfsd_init_socks(port); | |
| 182 | for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) { | 343 | if (error) |
| 183 | if (NFSCTL_VERISSET(nfsd_versbits, i)) { | 344 | goto failure; |
| 184 | nfsd_acl_program.pg_vers[i] = | ||
| 185 | nfsd_acl_version[i]; | ||
| 186 | found_one = 1; | ||
| 187 | } else | ||
| 188 | nfsd_acl_program.pg_vers[i] = NULL; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (!found_one) { | ||
| 192 | for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) | ||
| 193 | nfsd_acl_program.pg_vers[i] = | ||
| 194 | nfsd_acl_version[i]; | ||
| 195 | } | ||
| 196 | #endif | ||
| 197 | |||
| 198 | atomic_set(&nfsd_busy, 0); | ||
| 199 | error = -ENOMEM; | ||
| 200 | nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); | ||
| 201 | if (nfsd_serv == NULL) | ||
| 202 | goto out; | ||
| 203 | error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); | ||
| 204 | if (error < 0) | ||
| 205 | goto failure; | ||
| 206 | 345 | ||
| 207 | #ifdef CONFIG_NFSD_TCP | 346 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
| 208 | error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); | ||
| 209 | if (error < 0) | ||
| 210 | goto failure; | ||
| 211 | #endif | ||
| 212 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | ||
| 213 | } else | ||
| 214 | nfsd_serv->sv_nrthreads++; | ||
| 215 | nrservs -= (nfsd_serv->sv_nrthreads-1); | ||
| 216 | while (nrservs > 0) { | ||
| 217 | nrservs--; | ||
| 218 | __module_get(THIS_MODULE); | ||
| 219 | error = svc_create_thread(nfsd, nfsd_serv); | ||
| 220 | if (error < 0) { | ||
| 221 | module_put(THIS_MODULE); | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | victim = nfsd_list.next; | ||
| 226 | while (nrservs < 0 && victim != &nfsd_list) { | ||
| 227 | struct nfsd_list *nl = | ||
| 228 | list_entry(victim,struct nfsd_list, list); | ||
| 229 | victim = victim->next; | ||
| 230 | send_sig(SIG_NOCLEAN, nl->task, 1); | ||
| 231 | nrservs++; | ||
| 232 | } | ||
| 233 | failure: | 347 | failure: |
| 234 | none_left = (nfsd_serv->sv_nrthreads == 1); | ||
| 235 | svc_destroy(nfsd_serv); /* Release server */ | 348 | svc_destroy(nfsd_serv); /* Release server */ |
| 236 | if (none_left) { | ||
| 237 | nfsd_serv = NULL; | ||
| 238 | nfsd_racache_shutdown(); | ||
| 239 | nfs4_state_shutdown(); | ||
| 240 | } | ||
| 241 | out: | 349 | out: |
| 242 | unlock_kernel(); | 350 | unlock_kernel(); |
| 243 | return error; | 351 | return error; |
| @@ -270,10 +378,8 @@ update_thread_usage(int busy_threads) | |||
| 270 | static void | 378 | static void |
| 271 | nfsd(struct svc_rqst *rqstp) | 379 | nfsd(struct svc_rqst *rqstp) |
| 272 | { | 380 | { |
| 273 | struct svc_serv *serv = rqstp->rq_server; | ||
| 274 | struct fs_struct *fsp; | 381 | struct fs_struct *fsp; |
| 275 | int err; | 382 | int err; |
| 276 | struct nfsd_list me; | ||
| 277 | sigset_t shutdown_mask, allowed_mask; | 383 | sigset_t shutdown_mask, allowed_mask; |
| 278 | 384 | ||
| 279 | /* Lock module and set up kernel thread */ | 385 | /* Lock module and set up kernel thread */ |
| @@ -297,10 +403,7 @@ nfsd(struct svc_rqst *rqstp) | |||
| 297 | 403 | ||
| 298 | nfsdstats.th_cnt++; | 404 | nfsdstats.th_cnt++; |
| 299 | 405 | ||
| 300 | lockd_up(); /* start lockd */ | 406 | rqstp->rq_task = current; |
| 301 | |||
| 302 | me.task = current; | ||
| 303 | list_add(&me.list, &nfsd_list); | ||
| 304 | 407 | ||
| 305 | unlock_kernel(); | 408 | unlock_kernel(); |
| 306 | 409 | ||
| @@ -322,8 +425,7 @@ nfsd(struct svc_rqst *rqstp) | |||
| 322 | * Find a socket with data available and call its | 425 | * Find a socket with data available and call its |
| 323 | * recvfrom routine. | 426 | * recvfrom routine. |
| 324 | */ | 427 | */ |
| 325 | while ((err = svc_recv(serv, rqstp, | 428 | while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) |
| 326 | 60*60*HZ)) == -EAGAIN) | ||
| 327 | ; | 429 | ; |
| 328 | if (err < 0) | 430 | if (err < 0) |
| 329 | break; | 431 | break; |
| @@ -336,7 +438,7 @@ nfsd(struct svc_rqst *rqstp) | |||
| 336 | /* Process request with signals blocked. */ | 438 | /* Process request with signals blocked. */ |
| 337 | sigprocmask(SIG_SETMASK, &allowed_mask, NULL); | 439 | sigprocmask(SIG_SETMASK, &allowed_mask, NULL); |
| 338 | 440 | ||
| 339 | svc_process(serv, rqstp); | 441 | svc_process(rqstp); |
| 340 | 442 | ||
| 341 | /* Unlock export hash tables */ | 443 | /* Unlock export hash tables */ |
| 342 | exp_readunlock(); | 444 | exp_readunlock(); |
| @@ -353,29 +455,13 @@ nfsd(struct svc_rqst *rqstp) | |||
| 353 | if (sigismember(¤t->pending.signal, signo) && | 455 | if (sigismember(¤t->pending.signal, signo) && |
| 354 | !sigismember(¤t->blocked, signo)) | 456 | !sigismember(¤t->blocked, signo)) |
| 355 | break; | 457 | break; |
| 356 | err = signo; | 458 | killsig = signo; |
| 357 | } | 459 | } |
| 358 | /* Clear signals before calling lockd_down() and svc_exit_thread() */ | 460 | /* Clear signals before calling svc_exit_thread() */ |
| 359 | flush_signals(current); | 461 | flush_signals(current); |
| 360 | 462 | ||
| 361 | lock_kernel(); | 463 | lock_kernel(); |
| 362 | 464 | ||
| 363 | /* Release lockd */ | ||
| 364 | lockd_down(); | ||
| 365 | |||
| 366 | /* Check if this is last thread */ | ||
| 367 | if (serv->sv_nrthreads==1) { | ||
| 368 | |||
| 369 | printk(KERN_WARNING "nfsd: last server has exited\n"); | ||
| 370 | if (err != SIG_NOCLEAN) { | ||
| 371 | printk(KERN_WARNING "nfsd: unexporting all filesystems\n"); | ||
| 372 | nfsd_export_flush(); | ||
| 373 | } | ||
| 374 | nfsd_serv = NULL; | ||
| 375 | nfsd_racache_shutdown(); /* release read-ahead cache */ | ||
| 376 | nfs4_state_shutdown(); | ||
| 377 | } | ||
| 378 | list_del(&me.list); | ||
| 379 | nfsdstats.th_cnt --; | 465 | nfsdstats.th_cnt --; |
| 380 | 466 | ||
| 381 | out: | 467 | out: |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c9e3b5a8fe07..443ebc52e382 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -1114,7 +1114,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1114 | */ | 1114 | */ |
| 1115 | if (!resfhp->fh_dentry) { | 1115 | if (!resfhp->fh_dentry) { |
| 1116 | /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ | 1116 | /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ |
| 1117 | fh_lock(fhp); | 1117 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
| 1118 | dchild = lookup_one_len(fname, dentry, flen); | 1118 | dchild = lookup_one_len(fname, dentry, flen); |
| 1119 | err = PTR_ERR(dchild); | 1119 | err = PTR_ERR(dchild); |
| 1120 | if (IS_ERR(dchild)) | 1120 | if (IS_ERR(dchild)) |
| @@ -1240,7 +1240,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1240 | err = nfserr_notdir; | 1240 | err = nfserr_notdir; |
| 1241 | if(!dirp->i_op || !dirp->i_op->lookup) | 1241 | if(!dirp->i_op || !dirp->i_op->lookup) |
| 1242 | goto out; | 1242 | goto out; |
| 1243 | fh_lock(fhp); | 1243 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
| 1244 | 1244 | ||
| 1245 | /* | 1245 | /* |
| 1246 | * Compose the response file handle. | 1246 | * Compose the response file handle. |
| @@ -1494,7 +1494,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
| 1494 | if (isdotent(name, len)) | 1494 | if (isdotent(name, len)) |
| 1495 | goto out; | 1495 | goto out; |
| 1496 | 1496 | ||
| 1497 | fh_lock(ffhp); | 1497 | fh_lock_nested(ffhp, I_MUTEX_PARENT); |
| 1498 | ddir = ffhp->fh_dentry; | 1498 | ddir = ffhp->fh_dentry; |
| 1499 | dirp = ddir->d_inode; | 1499 | dirp = ddir->d_inode; |
| 1500 | 1500 | ||
| @@ -1644,7 +1644,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 1644 | if (err) | 1644 | if (err) |
| 1645 | goto out; | 1645 | goto out; |
| 1646 | 1646 | ||
| 1647 | fh_lock(fhp); | 1647 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
| 1648 | dentry = fhp->fh_dentry; | 1648 | dentry = fhp->fh_dentry; |
| 1649 | dirp = dentry->d_inode; | 1649 | dirp = dentry->d_inode; |
| 1650 | 1650 | ||
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 9de6b495f112..b1317ad5ca18 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c | |||
| @@ -163,8 +163,6 @@ int register_nls(struct nls_table * nls) | |||
| 163 | { | 163 | { |
| 164 | struct nls_table ** tmp = &tables; | 164 | struct nls_table ** tmp = &tables; |
| 165 | 165 | ||
| 166 | if (!nls) | ||
| 167 | return -EINVAL; | ||
| 168 | if (nls->next) | 166 | if (nls->next) |
| 169 | return -EBUSY; | 167 | return -EBUSY; |
| 170 | 168 | ||
diff --git a/fs/proc/array.c b/fs/proc/array.c index c0e554971df0..25e917fb4739 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -162,7 +162,7 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
| 162 | int g; | 162 | int g; |
| 163 | struct fdtable *fdt = NULL; | 163 | struct fdtable *fdt = NULL; |
| 164 | 164 | ||
| 165 | read_lock(&tasklist_lock); | 165 | rcu_read_lock(); |
| 166 | buffer += sprintf(buffer, | 166 | buffer += sprintf(buffer, |
| 167 | "State:\t%s\n" | 167 | "State:\t%s\n" |
| 168 | "SleepAVG:\t%lu%%\n" | 168 | "SleepAVG:\t%lu%%\n" |
| @@ -174,14 +174,13 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
| 174 | "Gid:\t%d\t%d\t%d\t%d\n", | 174 | "Gid:\t%d\t%d\t%d\t%d\n", |
| 175 | get_task_state(p), | 175 | get_task_state(p), |
| 176 | (p->sleep_avg/1024)*100/(1020000000/1024), | 176 | (p->sleep_avg/1024)*100/(1020000000/1024), |
| 177 | p->tgid, | 177 | p->tgid, p->pid, |
| 178 | p->pid, pid_alive(p) ? p->group_leader->real_parent->tgid : 0, | 178 | pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0, |
| 179 | pid_alive(p) && p->ptrace ? p->parent->pid : 0, | 179 | pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0, |
| 180 | p->uid, p->euid, p->suid, p->fsuid, | 180 | p->uid, p->euid, p->suid, p->fsuid, |
| 181 | p->gid, p->egid, p->sgid, p->fsgid); | 181 | p->gid, p->egid, p->sgid, p->fsgid); |
| 182 | read_unlock(&tasklist_lock); | 182 | |
| 183 | task_lock(p); | 183 | task_lock(p); |
| 184 | rcu_read_lock(); | ||
| 185 | if (p->files) | 184 | if (p->files) |
| 186 | fdt = files_fdtable(p->files); | 185 | fdt = files_fdtable(p->files); |
| 187 | buffer += sprintf(buffer, | 186 | buffer += sprintf(buffer, |
| @@ -244,6 +243,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, | |||
| 244 | 243 | ||
| 245 | static inline char * task_sig(struct task_struct *p, char *buffer) | 244 | static inline char * task_sig(struct task_struct *p, char *buffer) |
| 246 | { | 245 | { |
| 246 | unsigned long flags; | ||
| 247 | sigset_t pending, shpending, blocked, ignored, caught; | 247 | sigset_t pending, shpending, blocked, ignored, caught; |
| 248 | int num_threads = 0; | 248 | int num_threads = 0; |
| 249 | unsigned long qsize = 0; | 249 | unsigned long qsize = 0; |
| @@ -255,10 +255,8 @@ static inline char * task_sig(struct task_struct *p, char *buffer) | |||
| 255 | sigemptyset(&ignored); | 255 | sigemptyset(&ignored); |
| 256 | sigemptyset(&caught); | 256 | sigemptyset(&caught); |
| 257 | 257 | ||
| 258 | /* Gather all the data with the appropriate locks held */ | 258 | rcu_read_lock(); |
| 259 | read_lock(&tasklist_lock); | 259 | if (lock_task_sighand(p, &flags)) { |
| 260 | if (p->sighand) { | ||
| 261 | spin_lock_irq(&p->sighand->siglock); | ||
| 262 | pending = p->pending.signal; | 260 | pending = p->pending.signal; |
| 263 | shpending = p->signal->shared_pending.signal; | 261 | shpending = p->signal->shared_pending.signal; |
| 264 | blocked = p->blocked; | 262 | blocked = p->blocked; |
| @@ -266,9 +264,9 @@ static inline char * task_sig(struct task_struct *p, char *buffer) | |||
| 266 | num_threads = atomic_read(&p->signal->count); | 264 | num_threads = atomic_read(&p->signal->count); |
| 267 | qsize = atomic_read(&p->user->sigpending); | 265 | qsize = atomic_read(&p->user->sigpending); |
| 268 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; | 266 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; |
| 269 | spin_unlock_irq(&p->sighand->siglock); | 267 | unlock_task_sighand(p, &flags); |
| 270 | } | 268 | } |
| 271 | read_unlock(&tasklist_lock); | 269 | rcu_read_unlock(); |
| 272 | 270 | ||
| 273 | buffer += sprintf(buffer, "Threads:\t%d\n", num_threads); | 271 | buffer += sprintf(buffer, "Threads:\t%d\n", num_threads); |
| 274 | buffer += sprintf(buffer, "SigQ:\t%lu/%lu\n", qsize, qlim); | 272 | buffer += sprintf(buffer, "SigQ:\t%lu/%lu\n", qsize, qlim); |
| @@ -322,7 +320,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
| 322 | sigset_t sigign, sigcatch; | 320 | sigset_t sigign, sigcatch; |
| 323 | char state; | 321 | char state; |
| 324 | int res; | 322 | int res; |
| 325 | pid_t ppid, pgid = -1, sid = -1; | 323 | pid_t ppid = 0, pgid = -1, sid = -1; |
| 326 | int num_threads = 0; | 324 | int num_threads = 0; |
| 327 | struct mm_struct *mm; | 325 | struct mm_struct *mm; |
| 328 | unsigned long long start_time; | 326 | unsigned long long start_time; |
| @@ -330,8 +328,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
| 330 | unsigned long min_flt = 0, maj_flt = 0; | 328 | unsigned long min_flt = 0, maj_flt = 0; |
| 331 | cputime_t cutime, cstime, utime, stime; | 329 | cputime_t cutime, cstime, utime, stime; |
| 332 | unsigned long rsslim = 0; | 330 | unsigned long rsslim = 0; |
| 333 | struct task_struct *t; | ||
| 334 | char tcomm[sizeof(task->comm)]; | 331 | char tcomm[sizeof(task->comm)]; |
| 332 | unsigned long flags; | ||
| 335 | 333 | ||
| 336 | state = *get_task_state(task); | 334 | state = *get_task_state(task); |
| 337 | vsize = eip = esp = 0; | 335 | vsize = eip = esp = 0; |
| @@ -349,15 +347,33 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
| 349 | cutime = cstime = utime = stime = cputime_zero; | 347 | cutime = cstime = utime = stime = cputime_zero; |
| 350 | 348 | ||
| 351 | mutex_lock(&tty_mutex); | 349 | mutex_lock(&tty_mutex); |
| 352 | read_lock(&tasklist_lock); | 350 | rcu_read_lock(); |
| 353 | if (task->sighand) { | 351 | if (lock_task_sighand(task, &flags)) { |
| 354 | spin_lock_irq(&task->sighand->siglock); | 352 | struct signal_struct *sig = task->signal; |
| 355 | num_threads = atomic_read(&task->signal->count); | 353 | struct tty_struct *tty = sig->tty; |
| 354 | |||
| 355 | if (tty) { | ||
| 356 | /* | ||
| 357 | * sig->tty is not stable, but tty_mutex | ||
| 358 | * protects us from release_dev(tty) | ||
| 359 | */ | ||
| 360 | barrier(); | ||
| 361 | tty_pgrp = tty->pgrp; | ||
| 362 | tty_nr = new_encode_dev(tty_devnum(tty)); | ||
| 363 | } | ||
| 364 | |||
| 365 | num_threads = atomic_read(&sig->count); | ||
| 356 | collect_sigign_sigcatch(task, &sigign, &sigcatch); | 366 | collect_sigign_sigcatch(task, &sigign, &sigcatch); |
| 357 | 367 | ||
| 368 | cmin_flt = sig->cmin_flt; | ||
| 369 | cmaj_flt = sig->cmaj_flt; | ||
| 370 | cutime = sig->cutime; | ||
| 371 | cstime = sig->cstime; | ||
| 372 | rsslim = sig->rlim[RLIMIT_RSS].rlim_cur; | ||
| 373 | |||
| 358 | /* add up live thread stats at the group level */ | 374 | /* add up live thread stats at the group level */ |
| 359 | if (whole) { | 375 | if (whole) { |
| 360 | t = task; | 376 | struct task_struct *t = task; |
| 361 | do { | 377 | do { |
| 362 | min_flt += t->min_flt; | 378 | min_flt += t->min_flt; |
| 363 | maj_flt += t->maj_flt; | 379 | maj_flt += t->maj_flt; |
| @@ -365,31 +381,20 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
| 365 | stime = cputime_add(stime, t->stime); | 381 | stime = cputime_add(stime, t->stime); |
| 366 | t = next_thread(t); | 382 | t = next_thread(t); |
| 367 | } while (t != task); | 383 | } while (t != task); |
| 368 | } | ||
| 369 | 384 | ||
| 370 | spin_unlock_irq(&task->sighand->siglock); | 385 | min_flt += sig->min_flt; |
| 371 | } | 386 | maj_flt += sig->maj_flt; |
| 372 | if (task->signal) { | 387 | utime = cputime_add(utime, sig->utime); |
| 373 | if (task->signal->tty) { | 388 | stime = cputime_add(stime, sig->stime); |
| 374 | tty_pgrp = task->signal->tty->pgrp; | ||
| 375 | tty_nr = new_encode_dev(tty_devnum(task->signal->tty)); | ||
| 376 | } | 389 | } |
| 390 | |||
| 391 | sid = sig->session; | ||
| 377 | pgid = process_group(task); | 392 | pgid = process_group(task); |
| 378 | sid = task->signal->session; | 393 | ppid = rcu_dereference(task->real_parent)->tgid; |
| 379 | cmin_flt = task->signal->cmin_flt; | 394 | |
| 380 | cmaj_flt = task->signal->cmaj_flt; | 395 | unlock_task_sighand(task, &flags); |
| 381 | cutime = task->signal->cutime; | ||
| 382 | cstime = task->signal->cstime; | ||
| 383 | rsslim = task->signal->rlim[RLIMIT_RSS].rlim_cur; | ||
| 384 | if (whole) { | ||
| 385 | min_flt += task->signal->min_flt; | ||
| 386 | maj_flt += task->signal->maj_flt; | ||
| 387 | utime = cputime_add(utime, task->signal->utime); | ||
| 388 | stime = cputime_add(stime, task->signal->stime); | ||
| 389 | } | ||
| 390 | } | 396 | } |
| 391 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; | 397 | rcu_read_unlock(); |
| 392 | read_unlock(&tasklist_lock); | ||
| 393 | mutex_unlock(&tty_mutex); | 398 | mutex_unlock(&tty_mutex); |
| 394 | 399 | ||
| 395 | if (!whole || num_threads<2) | 400 | if (!whole || num_threads<2) |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 89c20d9d50bf..82da55b5cffe 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -71,6 +71,7 @@ | |||
| 71 | #include <linux/cpuset.h> | 71 | #include <linux/cpuset.h> |
| 72 | #include <linux/audit.h> | 72 | #include <linux/audit.h> |
| 73 | #include <linux/poll.h> | 73 | #include <linux/poll.h> |
| 74 | #include <linux/nsproxy.h> | ||
| 74 | #include "internal.h" | 75 | #include "internal.h" |
| 75 | 76 | ||
| 76 | /* NOTE: | 77 | /* NOTE: |
| @@ -83,262 +84,44 @@ | |||
| 83 | * in /proc for a task before it execs a suid executable. | 84 | * in /proc for a task before it execs a suid executable. |
| 84 | */ | 85 | */ |
| 85 | 86 | ||
| 86 | /* | ||
| 87 | * For hysterical raisins we keep the same inumbers as in the old procfs. | ||
| 88 | * Feel free to change the macro below - just keep the range distinct from | ||
| 89 | * inumbers of the rest of procfs (currently those are in 0x0000--0xffff). | ||
| 90 | * As soon as we'll get a separate superblock we will be able to forget | ||
| 91 | * about magical ranges too. | ||
| 92 | */ | ||
| 93 | |||
| 94 | #define fake_ino(pid,ino) (((pid)<<16)|(ino)) | ||
| 95 | |||
| 96 | enum pid_directory_inos { | ||
| 97 | PROC_TGID_INO = 2, | ||
| 98 | PROC_TGID_TASK, | ||
| 99 | PROC_TGID_STATUS, | ||
| 100 | PROC_TGID_MEM, | ||
| 101 | #ifdef CONFIG_SECCOMP | ||
| 102 | PROC_TGID_SECCOMP, | ||
| 103 | #endif | ||
| 104 | PROC_TGID_CWD, | ||
| 105 | PROC_TGID_ROOT, | ||
| 106 | PROC_TGID_EXE, | ||
| 107 | PROC_TGID_FD, | ||
| 108 | PROC_TGID_ENVIRON, | ||
| 109 | PROC_TGID_AUXV, | ||
| 110 | PROC_TGID_CMDLINE, | ||
| 111 | PROC_TGID_STAT, | ||
| 112 | PROC_TGID_STATM, | ||
| 113 | PROC_TGID_MAPS, | ||
| 114 | PROC_TGID_NUMA_MAPS, | ||
| 115 | PROC_TGID_MOUNTS, | ||
| 116 | PROC_TGID_MOUNTSTATS, | ||
| 117 | PROC_TGID_WCHAN, | ||
| 118 | #ifdef CONFIG_MMU | ||
| 119 | PROC_TGID_SMAPS, | ||
| 120 | #endif | ||
| 121 | #ifdef CONFIG_SCHEDSTATS | ||
| 122 | PROC_TGID_SCHEDSTAT, | ||
| 123 | #endif | ||
| 124 | #ifdef CONFIG_CPUSETS | ||
| 125 | PROC_TGID_CPUSET, | ||
| 126 | #endif | ||
| 127 | #ifdef CONFIG_SECURITY | ||
| 128 | PROC_TGID_ATTR, | ||
| 129 | PROC_TGID_ATTR_CURRENT, | ||
| 130 | PROC_TGID_ATTR_PREV, | ||
| 131 | PROC_TGID_ATTR_EXEC, | ||
| 132 | PROC_TGID_ATTR_FSCREATE, | ||
| 133 | PROC_TGID_ATTR_KEYCREATE, | ||
| 134 | PROC_TGID_ATTR_SOCKCREATE, | ||
| 135 | #endif | ||
| 136 | #ifdef CONFIG_AUDITSYSCALL | ||
| 137 | PROC_TGID_LOGINUID, | ||
| 138 | #endif | ||
| 139 | PROC_TGID_OOM_SCORE, | ||
| 140 | PROC_TGID_OOM_ADJUST, | ||
| 141 | PROC_TID_INO, | ||
| 142 | PROC_TID_STATUS, | ||
| 143 | PROC_TID_MEM, | ||
| 144 | #ifdef CONFIG_SECCOMP | ||
| 145 | PROC_TID_SECCOMP, | ||
| 146 | #endif | ||
| 147 | PROC_TID_CWD, | ||
| 148 | PROC_TID_ROOT, | ||
| 149 | PROC_TID_EXE, | ||
| 150 | PROC_TID_FD, | ||
| 151 | PROC_TID_ENVIRON, | ||
| 152 | PROC_TID_AUXV, | ||
| 153 | PROC_TID_CMDLINE, | ||
| 154 | PROC_TID_STAT, | ||
| 155 | PROC_TID_STATM, | ||
| 156 | PROC_TID_MAPS, | ||
| 157 | PROC_TID_NUMA_MAPS, | ||
| 158 | PROC_TID_MOUNTS, | ||
| 159 | PROC_TID_MOUNTSTATS, | ||
| 160 | PROC_TID_WCHAN, | ||
| 161 | #ifdef CONFIG_MMU | ||
| 162 | PROC_TID_SMAPS, | ||
| 163 | #endif | ||
| 164 | #ifdef CONFIG_SCHEDSTATS | ||
| 165 | PROC_TID_SCHEDSTAT, | ||
| 166 | #endif | ||
| 167 | #ifdef CONFIG_CPUSETS | ||
| 168 | PROC_TID_CPUSET, | ||
| 169 | #endif | ||
| 170 | #ifdef CONFIG_SECURITY | ||
| 171 | PROC_TID_ATTR, | ||
| 172 | PROC_TID_ATTR_CURRENT, | ||
| 173 | PROC_TID_ATTR_PREV, | ||
| 174 | PROC_TID_ATTR_EXEC, | ||
| 175 | PROC_TID_ATTR_FSCREATE, | ||
| 176 | PROC_TID_ATTR_KEYCREATE, | ||
| 177 | PROC_TID_ATTR_SOCKCREATE, | ||
| 178 | #endif | ||
| 179 | #ifdef CONFIG_AUDITSYSCALL | ||
| 180 | PROC_TID_LOGINUID, | ||
| 181 | #endif | ||
| 182 | PROC_TID_OOM_SCORE, | ||
| 183 | PROC_TID_OOM_ADJUST, | ||
| 184 | |||
| 185 | /* Add new entries before this */ | ||
| 186 | PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */ | ||
| 187 | }; | ||
| 188 | 87 | ||
| 189 | /* Worst case buffer size needed for holding an integer. */ | 88 | /* Worst case buffer size needed for holding an integer. */ |
| 190 | #define PROC_NUMBUF 10 | 89 | #define PROC_NUMBUF 10 |
| 191 | 90 | ||
| 192 | struct pid_entry { | 91 | struct pid_entry { |
| 193 | int type; | ||
| 194 | int len; | 92 | int len; |
| 195 | char *name; | 93 | char *name; |
| 196 | mode_t mode; | 94 | mode_t mode; |
| 95 | struct inode_operations *iop; | ||
| 96 | struct file_operations *fop; | ||
| 97 | union proc_op op; | ||
| 197 | }; | 98 | }; |
| 198 | 99 | ||
| 199 | #define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)} | 100 | #define NOD(NAME, MODE, IOP, FOP, OP) { \ |
| 200 | 101 | .len = sizeof(NAME) - 1, \ | |
| 201 | static struct pid_entry tgid_base_stuff[] = { | 102 | .name = (NAME), \ |
| 202 | E(PROC_TGID_TASK, "task", S_IFDIR|S_IRUGO|S_IXUGO), | 103 | .mode = MODE, \ |
| 203 | E(PROC_TGID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR), | 104 | .iop = IOP, \ |
| 204 | E(PROC_TGID_ENVIRON, "environ", S_IFREG|S_IRUSR), | 105 | .fop = FOP, \ |
| 205 | E(PROC_TGID_AUXV, "auxv", S_IFREG|S_IRUSR), | 106 | .op = OP, \ |
| 206 | E(PROC_TGID_STATUS, "status", S_IFREG|S_IRUGO), | ||
| 207 | E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), | ||
| 208 | E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), | ||
| 209 | E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), | ||
| 210 | E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), | ||
| 211 | #ifdef CONFIG_NUMA | ||
| 212 | E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), | ||
| 213 | #endif | ||
| 214 | E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | ||
| 215 | #ifdef CONFIG_SECCOMP | ||
| 216 | E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), | ||
| 217 | #endif | ||
| 218 | E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO), | ||
| 219 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | ||
| 220 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), | ||
| 221 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | ||
| 222 | E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR), | ||
| 223 | #ifdef CONFIG_MMU | ||
| 224 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), | ||
| 225 | #endif | ||
| 226 | #ifdef CONFIG_SECURITY | ||
| 227 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | ||
| 228 | #endif | ||
| 229 | #ifdef CONFIG_KALLSYMS | ||
| 230 | E(PROC_TGID_WCHAN, "wchan", S_IFREG|S_IRUGO), | ||
| 231 | #endif | ||
| 232 | #ifdef CONFIG_SCHEDSTATS | ||
| 233 | E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO), | ||
| 234 | #endif | ||
| 235 | #ifdef CONFIG_CPUSETS | ||
| 236 | E(PROC_TGID_CPUSET, "cpuset", S_IFREG|S_IRUGO), | ||
| 237 | #endif | ||
| 238 | E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO), | ||
| 239 | E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR), | ||
| 240 | #ifdef CONFIG_AUDITSYSCALL | ||
| 241 | E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO), | ||
| 242 | #endif | ||
| 243 | {0,0,NULL,0} | ||
| 244 | }; | ||
| 245 | static struct pid_entry tid_base_stuff[] = { | ||
| 246 | E(PROC_TID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR), | ||
| 247 | E(PROC_TID_ENVIRON, "environ", S_IFREG|S_IRUSR), | ||
| 248 | E(PROC_TID_AUXV, "auxv", S_IFREG|S_IRUSR), | ||
| 249 | E(PROC_TID_STATUS, "status", S_IFREG|S_IRUGO), | ||
| 250 | E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO), | ||
| 251 | E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), | ||
| 252 | E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), | ||
| 253 | E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), | ||
| 254 | #ifdef CONFIG_NUMA | ||
| 255 | E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), | ||
| 256 | #endif | ||
| 257 | E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | ||
| 258 | #ifdef CONFIG_SECCOMP | ||
| 259 | E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), | ||
| 260 | #endif | ||
| 261 | E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO), | ||
| 262 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), | ||
| 263 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), | ||
| 264 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | ||
| 265 | #ifdef CONFIG_MMU | ||
| 266 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), | ||
| 267 | #endif | ||
| 268 | #ifdef CONFIG_SECURITY | ||
| 269 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | ||
| 270 | #endif | ||
| 271 | #ifdef CONFIG_KALLSYMS | ||
| 272 | E(PROC_TID_WCHAN, "wchan", S_IFREG|S_IRUGO), | ||
| 273 | #endif | ||
| 274 | #ifdef CONFIG_SCHEDSTATS | ||
| 275 | E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO), | ||
| 276 | #endif | ||
| 277 | #ifdef CONFIG_CPUSETS | ||
| 278 | E(PROC_TID_CPUSET, "cpuset", S_IFREG|S_IRUGO), | ||
| 279 | #endif | ||
| 280 | E(PROC_TID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO), | ||
| 281 | E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR), | ||
| 282 | #ifdef CONFIG_AUDITSYSCALL | ||
| 283 | E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO), | ||
| 284 | #endif | ||
| 285 | {0,0,NULL,0} | ||
| 286 | }; | ||
| 287 | |||
| 288 | #ifdef CONFIG_SECURITY | ||
| 289 | static struct pid_entry tgid_attr_stuff[] = { | ||
| 290 | E(PROC_TGID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 291 | E(PROC_TGID_ATTR_PREV, "prev", S_IFREG|S_IRUGO), | ||
| 292 | E(PROC_TGID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 293 | E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 294 | E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 295 | E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 296 | {0,0,NULL,0} | ||
| 297 | }; | ||
| 298 | static struct pid_entry tid_attr_stuff[] = { | ||
| 299 | E(PROC_TID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 300 | E(PROC_TID_ATTR_PREV, "prev", S_IFREG|S_IRUGO), | ||
| 301 | E(PROC_TID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 302 | E(PROC_TID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 303 | E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 304 | E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO), | ||
| 305 | {0,0,NULL,0} | ||
| 306 | }; | ||
| 307 | #endif | ||
| 308 | |||
| 309 | #undef E | ||
| 310 | |||
| 311 | static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | ||
| 312 | { | ||
| 313 | struct task_struct *task = get_proc_task(inode); | ||
| 314 | struct files_struct *files = NULL; | ||
| 315 | struct file *file; | ||
| 316 | int fd = proc_fd(inode); | ||
| 317 | |||
| 318 | if (task) { | ||
| 319 | files = get_files_struct(task); | ||
| 320 | put_task_struct(task); | ||
| 321 | } | ||
| 322 | if (files) { | ||
| 323 | /* | ||
| 324 | * We are not taking a ref to the file structure, so we must | ||
| 325 | * hold ->file_lock. | ||
| 326 | */ | ||
| 327 | spin_lock(&files->file_lock); | ||
| 328 | file = fcheck_files(files, fd); | ||
| 329 | if (file) { | ||
| 330 | *mnt = mntget(file->f_vfsmnt); | ||
| 331 | *dentry = dget(file->f_dentry); | ||
| 332 | spin_unlock(&files->file_lock); | ||
| 333 | put_files_struct(files); | ||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | spin_unlock(&files->file_lock); | ||
| 337 | put_files_struct(files); | ||
| 338 | } | ||
| 339 | return -ENOENT; | ||
| 340 | } | 107 | } |
| 341 | 108 | ||
| 109 | #define DIR(NAME, MODE, OTYPE) \ | ||
| 110 | NOD(NAME, (S_IFDIR|(MODE)), \ | ||
| 111 | &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations, \ | ||
| 112 | {} ) | ||
| 113 | #define LNK(NAME, OTYPE) \ | ||
| 114 | NOD(NAME, (S_IFLNK|S_IRWXUGO), \ | ||
| 115 | &proc_pid_link_inode_operations, NULL, \ | ||
| 116 | { .proc_get_link = &proc_##OTYPE##_link } ) | ||
| 117 | #define REG(NAME, MODE, OTYPE) \ | ||
| 118 | NOD(NAME, (S_IFREG|(MODE)), NULL, \ | ||
| 119 | &proc_##OTYPE##_operations, {}) | ||
| 120 | #define INF(NAME, MODE, OTYPE) \ | ||
| 121 | NOD(NAME, (S_IFREG|(MODE)), \ | ||
| 122 | NULL, &proc_info_file_operations, \ | ||
| 123 | { .proc_read = &proc_##OTYPE } ) | ||
| 124 | |||
| 342 | static struct fs_struct *get_fs_struct(struct task_struct *task) | 125 | static struct fs_struct *get_fs_struct(struct task_struct *task) |
| 343 | { | 126 | { |
| 344 | struct fs_struct *fs; | 127 | struct fs_struct *fs; |
| @@ -587,7 +370,7 @@ static int mounts_open(struct inode *inode, struct file *file) | |||
| 587 | 370 | ||
| 588 | if (task) { | 371 | if (task) { |
| 589 | task_lock(task); | 372 | task_lock(task); |
| 590 | namespace = task->namespace; | 373 | namespace = task->nsproxy->namespace; |
| 591 | if (namespace) | 374 | if (namespace) |
| 592 | get_namespace(namespace); | 375 | get_namespace(namespace); |
| 593 | task_unlock(task); | 376 | task_unlock(task); |
| @@ -658,7 +441,7 @@ static int mountstats_open(struct inode *inode, struct file *file) | |||
| 658 | 441 | ||
| 659 | if (task) { | 442 | if (task) { |
| 660 | task_lock(task); | 443 | task_lock(task); |
| 661 | namespace = task->namespace; | 444 | namespace = task->nsproxy->namespace; |
| 662 | if (namespace) | 445 | if (namespace) |
| 663 | get_namespace(namespace); | 446 | get_namespace(namespace); |
| 664 | task_unlock(task); | 447 | task_unlock(task); |
| @@ -1137,143 +920,6 @@ static struct inode_operations proc_pid_link_inode_operations = { | |||
| 1137 | .setattr = proc_setattr, | 920 | .setattr = proc_setattr, |
| 1138 | }; | 921 | }; |
| 1139 | 922 | ||
| 1140 | static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | ||
| 1141 | { | ||
| 1142 | struct dentry *dentry = filp->f_dentry; | ||
| 1143 | struct inode *inode = dentry->d_inode; | ||
| 1144 | struct task_struct *p = get_proc_task(inode); | ||
| 1145 | unsigned int fd, tid, ino; | ||
| 1146 | int retval; | ||
| 1147 | char buf[PROC_NUMBUF]; | ||
| 1148 | struct files_struct * files; | ||
| 1149 | struct fdtable *fdt; | ||
| 1150 | |||
| 1151 | retval = -ENOENT; | ||
| 1152 | if (!p) | ||
| 1153 | goto out_no_task; | ||
| 1154 | retval = 0; | ||
| 1155 | tid = p->pid; | ||
| 1156 | |||
| 1157 | fd = filp->f_pos; | ||
| 1158 | switch (fd) { | ||
| 1159 | case 0: | ||
| 1160 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) | ||
| 1161 | goto out; | ||
| 1162 | filp->f_pos++; | ||
| 1163 | case 1: | ||
| 1164 | ino = parent_ino(dentry); | ||
| 1165 | if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) | ||
| 1166 | goto out; | ||
| 1167 | filp->f_pos++; | ||
| 1168 | default: | ||
| 1169 | files = get_files_struct(p); | ||
| 1170 | if (!files) | ||
| 1171 | goto out; | ||
| 1172 | rcu_read_lock(); | ||
| 1173 | fdt = files_fdtable(files); | ||
| 1174 | for (fd = filp->f_pos-2; | ||
| 1175 | fd < fdt->max_fds; | ||
| 1176 | fd++, filp->f_pos++) { | ||
| 1177 | unsigned int i,j; | ||
| 1178 | |||
| 1179 | if (!fcheck_files(files, fd)) | ||
| 1180 | continue; | ||
| 1181 | rcu_read_unlock(); | ||
| 1182 | |||
| 1183 | j = PROC_NUMBUF; | ||
| 1184 | i = fd; | ||
| 1185 | do { | ||
| 1186 | j--; | ||
| 1187 | buf[j] = '0' + (i % 10); | ||
| 1188 | i /= 10; | ||
| 1189 | } while (i); | ||
| 1190 | |||
| 1191 | ino = fake_ino(tid, PROC_TID_FD_DIR + fd); | ||
| 1192 | if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) { | ||
| 1193 | rcu_read_lock(); | ||
| 1194 | break; | ||
| 1195 | } | ||
| 1196 | rcu_read_lock(); | ||
| 1197 | } | ||
| 1198 | rcu_read_unlock(); | ||
| 1199 | put_files_struct(files); | ||
| 1200 | } | ||
| 1201 | out: | ||
| 1202 | put_task_struct(p); | ||
| 1203 | out_no_task: | ||
| 1204 | return retval; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | static int proc_pident_readdir(struct file *filp, | ||
| 1208 | void *dirent, filldir_t filldir, | ||
| 1209 | struct pid_entry *ents, unsigned int nents) | ||
| 1210 | { | ||
| 1211 | int i; | ||
| 1212 | int pid; | ||
| 1213 | struct dentry *dentry = filp->f_dentry; | ||
| 1214 | struct inode *inode = dentry->d_inode; | ||
| 1215 | struct task_struct *task = get_proc_task(inode); | ||
| 1216 | struct pid_entry *p; | ||
| 1217 | ino_t ino; | ||
| 1218 | int ret; | ||
| 1219 | |||
| 1220 | ret = -ENOENT; | ||
| 1221 | if (!task) | ||
| 1222 | goto out; | ||
| 1223 | |||
| 1224 | ret = 0; | ||
| 1225 | pid = task->pid; | ||
| 1226 | put_task_struct(task); | ||
| 1227 | i = filp->f_pos; | ||
| 1228 | switch (i) { | ||
| 1229 | case 0: | ||
| 1230 | ino = inode->i_ino; | ||
| 1231 | if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) | ||
| 1232 | goto out; | ||
| 1233 | i++; | ||
| 1234 | filp->f_pos++; | ||
| 1235 | /* fall through */ | ||
| 1236 | case 1: | ||
| 1237 | ino = parent_ino(dentry); | ||
| 1238 | if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) | ||
| 1239 | goto out; | ||
| 1240 | i++; | ||
| 1241 | filp->f_pos++; | ||
| 1242 | /* fall through */ | ||
| 1243 | default: | ||
| 1244 | i -= 2; | ||
| 1245 | if (i >= nents) { | ||
| 1246 | ret = 1; | ||
| 1247 | goto out; | ||
| 1248 | } | ||
| 1249 | p = ents + i; | ||
| 1250 | while (p->name) { | ||
| 1251 | if (filldir(dirent, p->name, p->len, filp->f_pos, | ||
| 1252 | fake_ino(pid, p->type), p->mode >> 12) < 0) | ||
| 1253 | goto out; | ||
| 1254 | filp->f_pos++; | ||
| 1255 | p++; | ||
| 1256 | } | ||
| 1257 | } | ||
| 1258 | |||
| 1259 | ret = 1; | ||
| 1260 | out: | ||
| 1261 | return ret; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | static int proc_tgid_base_readdir(struct file * filp, | ||
| 1265 | void * dirent, filldir_t filldir) | ||
| 1266 | { | ||
| 1267 | return proc_pident_readdir(filp,dirent,filldir, | ||
| 1268 | tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff)); | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | static int proc_tid_base_readdir(struct file * filp, | ||
| 1272 | void * dirent, filldir_t filldir) | ||
| 1273 | { | ||
| 1274 | return proc_pident_readdir(filp,dirent,filldir, | ||
| 1275 | tid_base_stuff,ARRAY_SIZE(tid_base_stuff)); | ||
| 1276 | } | ||
| 1277 | 923 | ||
| 1278 | /* building an inode */ | 924 | /* building an inode */ |
| 1279 | 925 | ||
| @@ -1293,13 +939,13 @@ static int task_dumpable(struct task_struct *task) | |||
| 1293 | } | 939 | } |
| 1294 | 940 | ||
| 1295 | 941 | ||
| 1296 | static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino) | 942 | static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task) |
| 1297 | { | 943 | { |
| 1298 | struct inode * inode; | 944 | struct inode * inode; |
| 1299 | struct proc_inode *ei; | 945 | struct proc_inode *ei; |
| 1300 | 946 | ||
| 1301 | /* We need a new inode */ | 947 | /* We need a new inode */ |
| 1302 | 948 | ||
| 1303 | inode = new_inode(sb); | 949 | inode = new_inode(sb); |
| 1304 | if (!inode) | 950 | if (!inode) |
| 1305 | goto out; | 951 | goto out; |
| @@ -1307,13 +953,12 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st | |||
| 1307 | /* Common stuff */ | 953 | /* Common stuff */ |
| 1308 | ei = PROC_I(inode); | 954 | ei = PROC_I(inode); |
| 1309 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 955 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 1310 | inode->i_ino = fake_ino(task->pid, ino); | ||
| 1311 | inode->i_op = &proc_def_inode_operations; | 956 | inode->i_op = &proc_def_inode_operations; |
| 1312 | 957 | ||
| 1313 | /* | 958 | /* |
| 1314 | * grab the reference to task. | 959 | * grab the reference to task. |
| 1315 | */ | 960 | */ |
| 1316 | ei->pid = get_pid(task->pids[PIDTYPE_PID].pid); | 961 | ei->pid = get_task_pid(task, PIDTYPE_PID); |
| 1317 | if (!ei->pid) | 962 | if (!ei->pid) |
| 1318 | goto out_unlock; | 963 | goto out_unlock; |
| 1319 | 964 | ||
| @@ -1333,6 +978,27 @@ out_unlock: | |||
| 1333 | return NULL; | 978 | return NULL; |
| 1334 | } | 979 | } |
| 1335 | 980 | ||
| 981 | static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||
| 982 | { | ||
| 983 | struct inode *inode = dentry->d_inode; | ||
| 984 | struct task_struct *task; | ||
| 985 | generic_fillattr(inode, stat); | ||
| 986 | |||
| 987 | rcu_read_lock(); | ||
| 988 | stat->uid = 0; | ||
| 989 | stat->gid = 0; | ||
| 990 | task = pid_task(proc_pid(inode), PIDTYPE_PID); | ||
| 991 | if (task) { | ||
| 992 | if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || | ||
| 993 | task_dumpable(task)) { | ||
| 994 | stat->uid = task->euid; | ||
| 995 | stat->gid = task->egid; | ||
| 996 | } | ||
| 997 | } | ||
| 998 | rcu_read_unlock(); | ||
| 999 | return 0; | ||
| 1000 | } | ||
| 1001 | |||
| 1336 | /* dentry stuff */ | 1002 | /* dentry stuff */ |
| 1337 | 1003 | ||
| 1338 | /* | 1004 | /* |
| @@ -1372,25 +1038,130 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1372 | return 0; | 1038 | return 0; |
| 1373 | } | 1039 | } |
| 1374 | 1040 | ||
| 1375 | static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | 1041 | static int pid_delete_dentry(struct dentry * dentry) |
| 1376 | { | 1042 | { |
| 1377 | struct inode *inode = dentry->d_inode; | 1043 | /* Is the task we represent dead? |
| 1378 | struct task_struct *task; | 1044 | * If so, then don't put the dentry on the lru list, |
| 1379 | generic_fillattr(inode, stat); | 1045 | * kill it immediately. |
| 1046 | */ | ||
| 1047 | return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static struct dentry_operations pid_dentry_operations = | ||
| 1051 | { | ||
| 1052 | .d_revalidate = pid_revalidate, | ||
| 1053 | .d_delete = pid_delete_dentry, | ||
| 1054 | }; | ||
| 1055 | |||
| 1056 | /* Lookups */ | ||
| 1057 | |||
| 1058 | typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *); | ||
| 1059 | |||
| 1060 | /* | ||
| 1061 | * Fill a directory entry. | ||
| 1062 | * | ||
| 1063 | * If possible create the dcache entry and derive our inode number and | ||
| 1064 | * file type from dcache entry. | ||
| 1065 | * | ||
| 1066 | * Since all of the proc inode numbers are dynamically generated, the inode | ||
| 1067 | * numbers do not exist until the inode is cache. This means creating the | ||
| 1068 | * the dcache entry in readdir is necessary to keep the inode numbers | ||
| 1069 | * reported by readdir in sync with the inode numbers reported | ||
| 1070 | * by stat. | ||
| 1071 | */ | ||
| 1072 | static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | ||
| 1073 | char *name, int len, | ||
| 1074 | instantiate_t instantiate, struct task_struct *task, void *ptr) | ||
| 1075 | { | ||
| 1076 | struct dentry *child, *dir = filp->f_dentry; | ||
| 1077 | struct inode *inode; | ||
| 1078 | struct qstr qname; | ||
| 1079 | ino_t ino = 0; | ||
| 1080 | unsigned type = DT_UNKNOWN; | ||
| 1081 | |||
| 1082 | qname.name = name; | ||
| 1083 | qname.len = len; | ||
| 1084 | qname.hash = full_name_hash(name, len); | ||
| 1085 | |||
| 1086 | child = d_lookup(dir, &qname); | ||
| 1087 | if (!child) { | ||
| 1088 | struct dentry *new; | ||
| 1089 | new = d_alloc(dir, &qname); | ||
| 1090 | if (new) { | ||
| 1091 | child = instantiate(dir->d_inode, new, task, ptr); | ||
| 1092 | if (child) | ||
| 1093 | dput(new); | ||
| 1094 | else | ||
| 1095 | child = new; | ||
| 1096 | } | ||
| 1097 | } | ||
| 1098 | if (!child || IS_ERR(child) || !child->d_inode) | ||
| 1099 | goto end_instantiate; | ||
| 1100 | inode = child->d_inode; | ||
| 1101 | if (inode) { | ||
| 1102 | ino = inode->i_ino; | ||
| 1103 | type = inode->i_mode >> 12; | ||
| 1104 | } | ||
| 1105 | dput(child); | ||
| 1106 | end_instantiate: | ||
| 1107 | if (!ino) | ||
| 1108 | ino = find_inode_number(dir, &qname); | ||
| 1109 | if (!ino) | ||
| 1110 | ino = 1; | ||
| 1111 | return filldir(dirent, name, len, filp->f_pos, ino, type); | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | static unsigned name_to_int(struct dentry *dentry) | ||
| 1115 | { | ||
| 1116 | const char *name = dentry->d_name.name; | ||
| 1117 | int len = dentry->d_name.len; | ||
| 1118 | unsigned n = 0; | ||
| 1119 | |||
| 1120 | if (len > 1 && *name == '0') | ||
| 1121 | goto out; | ||
| 1122 | while (len-- > 0) { | ||
| 1123 | unsigned c = *name++ - '0'; | ||
| 1124 | if (c > 9) | ||
| 1125 | goto out; | ||
| 1126 | if (n >= (~0U-9)/10) | ||
| 1127 | goto out; | ||
| 1128 | n *= 10; | ||
| 1129 | n += c; | ||
| 1130 | } | ||
| 1131 | return n; | ||
| 1132 | out: | ||
| 1133 | return ~0U; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | ||
| 1137 | { | ||
| 1138 | struct task_struct *task = get_proc_task(inode); | ||
| 1139 | struct files_struct *files = NULL; | ||
| 1140 | struct file *file; | ||
| 1141 | int fd = proc_fd(inode); | ||
| 1380 | 1142 | ||
| 1381 | rcu_read_lock(); | ||
| 1382 | stat->uid = 0; | ||
| 1383 | stat->gid = 0; | ||
| 1384 | task = pid_task(proc_pid(inode), PIDTYPE_PID); | ||
| 1385 | if (task) { | 1143 | if (task) { |
| 1386 | if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || | 1144 | files = get_files_struct(task); |
| 1387 | task_dumpable(task)) { | 1145 | put_task_struct(task); |
| 1388 | stat->uid = task->euid; | 1146 | } |
| 1389 | stat->gid = task->egid; | 1147 | if (files) { |
| 1148 | /* | ||
| 1149 | * We are not taking a ref to the file structure, so we must | ||
| 1150 | * hold ->file_lock. | ||
| 1151 | */ | ||
| 1152 | spin_lock(&files->file_lock); | ||
| 1153 | file = fcheck_files(files, fd); | ||
| 1154 | if (file) { | ||
| 1155 | *mnt = mntget(file->f_vfsmnt); | ||
| 1156 | *dentry = dget(file->f_dentry); | ||
| 1157 | spin_unlock(&files->file_lock); | ||
| 1158 | put_files_struct(files); | ||
| 1159 | return 0; | ||
| 1390 | } | 1160 | } |
| 1161 | spin_unlock(&files->file_lock); | ||
| 1162 | put_files_struct(files); | ||
| 1391 | } | 1163 | } |
| 1392 | rcu_read_unlock(); | 1164 | return -ENOENT; |
| 1393 | return 0; | ||
| 1394 | } | 1165 | } |
| 1395 | 1166 | ||
| 1396 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | 1167 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) |
| @@ -1428,75 +1199,30 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1428 | return 0; | 1199 | return 0; |
| 1429 | } | 1200 | } |
| 1430 | 1201 | ||
| 1431 | static int pid_delete_dentry(struct dentry * dentry) | ||
| 1432 | { | ||
| 1433 | /* Is the task we represent dead? | ||
| 1434 | * If so, then don't put the dentry on the lru list, | ||
| 1435 | * kill it immediately. | ||
| 1436 | */ | ||
| 1437 | return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | static struct dentry_operations tid_fd_dentry_operations = | 1202 | static struct dentry_operations tid_fd_dentry_operations = |
| 1441 | { | 1203 | { |
| 1442 | .d_revalidate = tid_fd_revalidate, | 1204 | .d_revalidate = tid_fd_revalidate, |
| 1443 | .d_delete = pid_delete_dentry, | 1205 | .d_delete = pid_delete_dentry, |
| 1444 | }; | 1206 | }; |
| 1445 | 1207 | ||
| 1446 | static struct dentry_operations pid_dentry_operations = | 1208 | static struct dentry *proc_fd_instantiate(struct inode *dir, |
| 1447 | { | 1209 | struct dentry *dentry, struct task_struct *task, void *ptr) |
| 1448 | .d_revalidate = pid_revalidate, | ||
| 1449 | .d_delete = pid_delete_dentry, | ||
| 1450 | }; | ||
| 1451 | |||
| 1452 | /* Lookups */ | ||
| 1453 | |||
| 1454 | static unsigned name_to_int(struct dentry *dentry) | ||
| 1455 | { | ||
| 1456 | const char *name = dentry->d_name.name; | ||
| 1457 | int len = dentry->d_name.len; | ||
| 1458 | unsigned n = 0; | ||
| 1459 | |||
| 1460 | if (len > 1 && *name == '0') | ||
| 1461 | goto out; | ||
| 1462 | while (len-- > 0) { | ||
| 1463 | unsigned c = *name++ - '0'; | ||
| 1464 | if (c > 9) | ||
| 1465 | goto out; | ||
| 1466 | if (n >= (~0U-9)/10) | ||
| 1467 | goto out; | ||
| 1468 | n *= 10; | ||
| 1469 | n += c; | ||
| 1470 | } | ||
| 1471 | return n; | ||
| 1472 | out: | ||
| 1473 | return ~0U; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | /* SMP-safe */ | ||
| 1477 | static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) | ||
| 1478 | { | 1210 | { |
| 1479 | struct task_struct *task = get_proc_task(dir); | 1211 | unsigned fd = *(unsigned *)ptr; |
| 1480 | unsigned fd = name_to_int(dentry); | 1212 | struct file *file; |
| 1481 | struct dentry *result = ERR_PTR(-ENOENT); | 1213 | struct files_struct *files; |
| 1482 | struct file * file; | 1214 | struct inode *inode; |
| 1483 | struct files_struct * files; | 1215 | struct proc_inode *ei; |
| 1484 | struct inode *inode; | 1216 | struct dentry *error = ERR_PTR(-ENOENT); |
| 1485 | struct proc_inode *ei; | ||
| 1486 | |||
| 1487 | if (!task) | ||
| 1488 | goto out_no_task; | ||
| 1489 | if (fd == ~0U) | ||
| 1490 | goto out; | ||
| 1491 | 1217 | ||
| 1492 | inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd); | 1218 | inode = proc_pid_make_inode(dir->i_sb, task); |
| 1493 | if (!inode) | 1219 | if (!inode) |
| 1494 | goto out; | 1220 | goto out; |
| 1495 | ei = PROC_I(inode); | 1221 | ei = PROC_I(inode); |
| 1496 | ei->fd = fd; | 1222 | ei->fd = fd; |
| 1497 | files = get_files_struct(task); | 1223 | files = get_files_struct(task); |
| 1498 | if (!files) | 1224 | if (!files) |
| 1499 | goto out_unlock; | 1225 | goto out_iput; |
| 1500 | inode->i_mode = S_IFLNK; | 1226 | inode->i_mode = S_IFLNK; |
| 1501 | 1227 | ||
| 1502 | /* | 1228 | /* |
| @@ -1506,13 +1232,14 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
| 1506 | spin_lock(&files->file_lock); | 1232 | spin_lock(&files->file_lock); |
| 1507 | file = fcheck_files(files, fd); | 1233 | file = fcheck_files(files, fd); |
| 1508 | if (!file) | 1234 | if (!file) |
| 1509 | goto out_unlock2; | 1235 | goto out_unlock; |
| 1510 | if (file->f_mode & 1) | 1236 | if (file->f_mode & 1) |
| 1511 | inode->i_mode |= S_IRUSR | S_IXUSR; | 1237 | inode->i_mode |= S_IRUSR | S_IXUSR; |
| 1512 | if (file->f_mode & 2) | 1238 | if (file->f_mode & 2) |
| 1513 | inode->i_mode |= S_IWUSR | S_IXUSR; | 1239 | inode->i_mode |= S_IWUSR | S_IXUSR; |
| 1514 | spin_unlock(&files->file_lock); | 1240 | spin_unlock(&files->file_lock); |
| 1515 | put_files_struct(files); | 1241 | put_files_struct(files); |
| 1242 | |||
| 1516 | inode->i_op = &proc_pid_link_inode_operations; | 1243 | inode->i_op = &proc_pid_link_inode_operations; |
| 1517 | inode->i_size = 64; | 1244 | inode->i_size = 64; |
| 1518 | ei->op.proc_get_link = proc_fd_link; | 1245 | ei->op.proc_get_link = proc_fd_link; |
| @@ -1520,34 +1247,106 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
| 1520 | d_add(dentry, inode); | 1247 | d_add(dentry, inode); |
| 1521 | /* Close the race of the process dying before we return the dentry */ | 1248 | /* Close the race of the process dying before we return the dentry */ |
| 1522 | if (tid_fd_revalidate(dentry, NULL)) | 1249 | if (tid_fd_revalidate(dentry, NULL)) |
| 1523 | result = NULL; | 1250 | error = NULL; |
| 1524 | out: | ||
| 1525 | put_task_struct(task); | ||
| 1526 | out_no_task: | ||
| 1527 | return result; | ||
| 1528 | 1251 | ||
| 1529 | out_unlock2: | 1252 | out: |
| 1253 | return error; | ||
| 1254 | out_unlock: | ||
| 1530 | spin_unlock(&files->file_lock); | 1255 | spin_unlock(&files->file_lock); |
| 1531 | put_files_struct(files); | 1256 | put_files_struct(files); |
| 1532 | out_unlock: | 1257 | out_iput: |
| 1533 | iput(inode); | 1258 | iput(inode); |
| 1534 | goto out; | 1259 | goto out; |
| 1535 | } | 1260 | } |
| 1536 | 1261 | ||
| 1537 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir); | 1262 | static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) |
| 1538 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd); | 1263 | { |
| 1539 | static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | 1264 | struct task_struct *task = get_proc_task(dir); |
| 1265 | unsigned fd = name_to_int(dentry); | ||
| 1266 | struct dentry *result = ERR_PTR(-ENOENT); | ||
| 1267 | |||
| 1268 | if (!task) | ||
| 1269 | goto out_no_task; | ||
| 1270 | if (fd == ~0U) | ||
| 1271 | goto out; | ||
| 1272 | |||
| 1273 | result = proc_fd_instantiate(dir, dentry, task, &fd); | ||
| 1274 | out: | ||
| 1275 | put_task_struct(task); | ||
| 1276 | out_no_task: | ||
| 1277 | return result; | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | ||
| 1281 | struct task_struct *task, int fd) | ||
| 1282 | { | ||
| 1283 | char name[PROC_NUMBUF]; | ||
| 1284 | int len = snprintf(name, sizeof(name), "%d", fd); | ||
| 1285 | return proc_fill_cache(filp, dirent, filldir, name, len, | ||
| 1286 | proc_fd_instantiate, task, &fd); | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | ||
| 1290 | { | ||
| 1291 | struct dentry *dentry = filp->f_dentry; | ||
| 1292 | struct inode *inode = dentry->d_inode; | ||
| 1293 | struct task_struct *p = get_proc_task(inode); | ||
| 1294 | unsigned int fd, tid, ino; | ||
| 1295 | int retval; | ||
| 1296 | struct files_struct * files; | ||
| 1297 | struct fdtable *fdt; | ||
| 1298 | |||
| 1299 | retval = -ENOENT; | ||
| 1300 | if (!p) | ||
| 1301 | goto out_no_task; | ||
| 1302 | retval = 0; | ||
| 1303 | tid = p->pid; | ||
| 1304 | |||
| 1305 | fd = filp->f_pos; | ||
| 1306 | switch (fd) { | ||
| 1307 | case 0: | ||
| 1308 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) | ||
| 1309 | goto out; | ||
| 1310 | filp->f_pos++; | ||
| 1311 | case 1: | ||
| 1312 | ino = parent_ino(dentry); | ||
| 1313 | if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) | ||
| 1314 | goto out; | ||
| 1315 | filp->f_pos++; | ||
| 1316 | default: | ||
| 1317 | files = get_files_struct(p); | ||
| 1318 | if (!files) | ||
| 1319 | goto out; | ||
| 1320 | rcu_read_lock(); | ||
| 1321 | fdt = files_fdtable(files); | ||
| 1322 | for (fd = filp->f_pos-2; | ||
| 1323 | fd < fdt->max_fds; | ||
| 1324 | fd++, filp->f_pos++) { | ||
| 1325 | |||
| 1326 | if (!fcheck_files(files, fd)) | ||
| 1327 | continue; | ||
| 1328 | rcu_read_unlock(); | ||
| 1329 | |||
| 1330 | if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) { | ||
| 1331 | rcu_read_lock(); | ||
| 1332 | break; | ||
| 1333 | } | ||
| 1334 | rcu_read_lock(); | ||
| 1335 | } | ||
| 1336 | rcu_read_unlock(); | ||
| 1337 | put_files_struct(files); | ||
| 1338 | } | ||
| 1339 | out: | ||
| 1340 | put_task_struct(p); | ||
| 1341 | out_no_task: | ||
| 1342 | return retval; | ||
| 1343 | } | ||
| 1540 | 1344 | ||
| 1541 | static struct file_operations proc_fd_operations = { | 1345 | static struct file_operations proc_fd_operations = { |
| 1542 | .read = generic_read_dir, | 1346 | .read = generic_read_dir, |
| 1543 | .readdir = proc_readfd, | 1347 | .readdir = proc_readfd, |
| 1544 | }; | 1348 | }; |
| 1545 | 1349 | ||
| 1546 | static struct file_operations proc_task_operations = { | ||
| 1547 | .read = generic_read_dir, | ||
| 1548 | .readdir = proc_task_readdir, | ||
| 1549 | }; | ||
| 1550 | |||
| 1551 | /* | 1350 | /* |
| 1552 | * proc directories can do almost nothing.. | 1351 | * proc directories can do almost nothing.. |
| 1553 | */ | 1352 | */ |
| @@ -1556,11 +1355,137 @@ static struct inode_operations proc_fd_inode_operations = { | |||
| 1556 | .setattr = proc_setattr, | 1355 | .setattr = proc_setattr, |
| 1557 | }; | 1356 | }; |
| 1558 | 1357 | ||
| 1559 | static struct inode_operations proc_task_inode_operations = { | 1358 | static struct dentry *proc_pident_instantiate(struct inode *dir, |
| 1560 | .lookup = proc_task_lookup, | 1359 | struct dentry *dentry, struct task_struct *task, void *ptr) |
| 1561 | .getattr = proc_task_getattr, | 1360 | { |
| 1562 | .setattr = proc_setattr, | 1361 | struct pid_entry *p = ptr; |
| 1563 | }; | 1362 | struct inode *inode; |
| 1363 | struct proc_inode *ei; | ||
| 1364 | struct dentry *error = ERR_PTR(-EINVAL); | ||
| 1365 | |||
| 1366 | inode = proc_pid_make_inode(dir->i_sb, task); | ||
| 1367 | if (!inode) | ||
| 1368 | goto out; | ||
| 1369 | |||
| 1370 | ei = PROC_I(inode); | ||
| 1371 | inode->i_mode = p->mode; | ||
| 1372 | if (S_ISDIR(inode->i_mode)) | ||
| 1373 | inode->i_nlink = 2; /* Use getattr to fix if necessary */ | ||
| 1374 | if (p->iop) | ||
| 1375 | inode->i_op = p->iop; | ||
| 1376 | if (p->fop) | ||
| 1377 | inode->i_fop = p->fop; | ||
| 1378 | ei->op = p->op; | ||
| 1379 | dentry->d_op = &pid_dentry_operations; | ||
| 1380 | d_add(dentry, inode); | ||
| 1381 | /* Close the race of the process dying before we return the dentry */ | ||
| 1382 | if (pid_revalidate(dentry, NULL)) | ||
| 1383 | error = NULL; | ||
| 1384 | out: | ||
| 1385 | return error; | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | static struct dentry *proc_pident_lookup(struct inode *dir, | ||
| 1389 | struct dentry *dentry, | ||
| 1390 | struct pid_entry *ents, | ||
| 1391 | unsigned int nents) | ||
| 1392 | { | ||
| 1393 | struct inode *inode; | ||
| 1394 | struct dentry *error; | ||
| 1395 | struct task_struct *task = get_proc_task(dir); | ||
| 1396 | struct pid_entry *p, *last; | ||
| 1397 | |||
| 1398 | error = ERR_PTR(-ENOENT); | ||
| 1399 | inode = NULL; | ||
| 1400 | |||
| 1401 | if (!task) | ||
| 1402 | goto out_no_task; | ||
| 1403 | |||
| 1404 | /* | ||
| 1405 | * Yes, it does not scale. And it should not. Don't add | ||
| 1406 | * new entries into /proc/<tgid>/ without very good reasons. | ||
| 1407 | */ | ||
| 1408 | last = &ents[nents - 1]; | ||
| 1409 | for (p = ents; p <= last; p++) { | ||
| 1410 | if (p->len != dentry->d_name.len) | ||
| 1411 | continue; | ||
| 1412 | if (!memcmp(dentry->d_name.name, p->name, p->len)) | ||
| 1413 | break; | ||
| 1414 | } | ||
| 1415 | if (p > last) | ||
| 1416 | goto out; | ||
| 1417 | |||
| 1418 | error = proc_pident_instantiate(dir, dentry, task, p); | ||
| 1419 | out: | ||
| 1420 | put_task_struct(task); | ||
| 1421 | out_no_task: | ||
| 1422 | return error; | ||
| 1423 | } | ||
| 1424 | |||
| 1425 | static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | ||
| 1426 | struct task_struct *task, struct pid_entry *p) | ||
| 1427 | { | ||
| 1428 | return proc_fill_cache(filp, dirent, filldir, p->name, p->len, | ||
| 1429 | proc_pident_instantiate, task, p); | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | static int proc_pident_readdir(struct file *filp, | ||
| 1433 | void *dirent, filldir_t filldir, | ||
| 1434 | struct pid_entry *ents, unsigned int nents) | ||
| 1435 | { | ||
| 1436 | int i; | ||
| 1437 | int pid; | ||
| 1438 | struct dentry *dentry = filp->f_dentry; | ||
| 1439 | struct inode *inode = dentry->d_inode; | ||
| 1440 | struct task_struct *task = get_proc_task(inode); | ||
| 1441 | struct pid_entry *p, *last; | ||
| 1442 | ino_t ino; | ||
| 1443 | int ret; | ||
| 1444 | |||
| 1445 | ret = -ENOENT; | ||
| 1446 | if (!task) | ||
| 1447 | goto out_no_task; | ||
| 1448 | |||
| 1449 | ret = 0; | ||
| 1450 | pid = task->pid; | ||
| 1451 | i = filp->f_pos; | ||
| 1452 | switch (i) { | ||
| 1453 | case 0: | ||
| 1454 | ino = inode->i_ino; | ||
| 1455 | if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) | ||
| 1456 | goto out; | ||
| 1457 | i++; | ||
| 1458 | filp->f_pos++; | ||
| 1459 | /* fall through */ | ||
| 1460 | case 1: | ||
| 1461 | ino = parent_ino(dentry); | ||
| 1462 | if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) | ||
| 1463 | goto out; | ||
| 1464 | i++; | ||
| 1465 | filp->f_pos++; | ||
| 1466 | /* fall through */ | ||
| 1467 | default: | ||
| 1468 | i -= 2; | ||
| 1469 | if (i >= nents) { | ||
| 1470 | ret = 1; | ||
| 1471 | goto out; | ||
| 1472 | } | ||
| 1473 | p = ents + i; | ||
| 1474 | last = &ents[nents - 1]; | ||
| 1475 | while (p <= last) { | ||
| 1476 | if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0) | ||
| 1477 | goto out; | ||
| 1478 | filp->f_pos++; | ||
| 1479 | p++; | ||
| 1480 | } | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | ret = 1; | ||
| 1484 | out: | ||
| 1485 | put_task_struct(task); | ||
| 1486 | out_no_task: | ||
| 1487 | return ret; | ||
| 1488 | } | ||
| 1564 | 1489 | ||
| 1565 | #ifdef CONFIG_SECURITY | 1490 | #ifdef CONFIG_SECURITY |
| 1566 | static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, | 1491 | static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, |
| @@ -1581,8 +1506,8 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, | |||
| 1581 | if (!(page = __get_free_page(GFP_KERNEL))) | 1506 | if (!(page = __get_free_page(GFP_KERNEL))) |
| 1582 | goto out; | 1507 | goto out; |
| 1583 | 1508 | ||
| 1584 | length = security_getprocattr(task, | 1509 | length = security_getprocattr(task, |
| 1585 | (char*)file->f_dentry->d_name.name, | 1510 | (char*)file->f_dentry->d_name.name, |
| 1586 | (void*)page, count); | 1511 | (void*)page, count); |
| 1587 | if (length >= 0) | 1512 | if (length >= 0) |
| 1588 | length = simple_read_from_buffer(buf, count, ppos, (char *)page, length); | 1513 | length = simple_read_from_buffer(buf, count, ppos, (char *)page, length); |
| @@ -1595,17 +1520,17 @@ out_no_task: | |||
| 1595 | 1520 | ||
| 1596 | static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, | 1521 | static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, |
| 1597 | size_t count, loff_t *ppos) | 1522 | size_t count, loff_t *ppos) |
| 1598 | { | 1523 | { |
| 1599 | struct inode * inode = file->f_dentry->d_inode; | 1524 | struct inode * inode = file->f_dentry->d_inode; |
| 1600 | char *page; | 1525 | char *page; |
| 1601 | ssize_t length; | 1526 | ssize_t length; |
| 1602 | struct task_struct *task = get_proc_task(inode); | 1527 | struct task_struct *task = get_proc_task(inode); |
| 1603 | 1528 | ||
| 1604 | length = -ESRCH; | 1529 | length = -ESRCH; |
| 1605 | if (!task) | 1530 | if (!task) |
| 1606 | goto out_no_task; | 1531 | goto out_no_task; |
| 1607 | if (count > PAGE_SIZE) | 1532 | if (count > PAGE_SIZE) |
| 1608 | count = PAGE_SIZE; | 1533 | count = PAGE_SIZE; |
| 1609 | 1534 | ||
| 1610 | /* No partial writes. */ | 1535 | /* No partial writes. */ |
| 1611 | length = -EINVAL; | 1536 | length = -EINVAL; |
| @@ -1613,16 +1538,16 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, | |||
| 1613 | goto out; | 1538 | goto out; |
| 1614 | 1539 | ||
| 1615 | length = -ENOMEM; | 1540 | length = -ENOMEM; |
| 1616 | page = (char*)__get_free_page(GFP_USER); | 1541 | page = (char*)__get_free_page(GFP_USER); |
| 1617 | if (!page) | 1542 | if (!page) |
| 1618 | goto out; | 1543 | goto out; |
| 1619 | 1544 | ||
| 1620 | length = -EFAULT; | 1545 | length = -EFAULT; |
| 1621 | if (copy_from_user(page, buf, count)) | 1546 | if (copy_from_user(page, buf, count)) |
| 1622 | goto out_free; | 1547 | goto out_free; |
| 1623 | 1548 | ||
| 1624 | length = security_setprocattr(task, | 1549 | length = security_setprocattr(task, |
| 1625 | (char*)file->f_dentry->d_name.name, | 1550 | (char*)file->f_dentry->d_name.name, |
| 1626 | (void*)page, count); | 1551 | (void*)page, count); |
| 1627 | out_free: | 1552 | out_free: |
| 1628 | free_page((unsigned long) page); | 1553 | free_page((unsigned long) page); |
| @@ -1630,330 +1555,263 @@ out: | |||
| 1630 | put_task_struct(task); | 1555 | put_task_struct(task); |
| 1631 | out_no_task: | 1556 | out_no_task: |
| 1632 | return length; | 1557 | return length; |
| 1633 | } | 1558 | } |
| 1634 | 1559 | ||
| 1635 | static struct file_operations proc_pid_attr_operations = { | 1560 | static struct file_operations proc_pid_attr_operations = { |
| 1636 | .read = proc_pid_attr_read, | 1561 | .read = proc_pid_attr_read, |
| 1637 | .write = proc_pid_attr_write, | 1562 | .write = proc_pid_attr_write, |
| 1638 | }; | 1563 | }; |
| 1639 | 1564 | ||
| 1640 | static struct file_operations proc_tid_attr_operations; | 1565 | static struct pid_entry attr_dir_stuff[] = { |
| 1641 | static struct inode_operations proc_tid_attr_inode_operations; | 1566 | REG("current", S_IRUGO|S_IWUGO, pid_attr), |
| 1642 | static struct file_operations proc_tgid_attr_operations; | 1567 | REG("prev", S_IRUGO, pid_attr), |
| 1643 | static struct inode_operations proc_tgid_attr_inode_operations; | 1568 | REG("exec", S_IRUGO|S_IWUGO, pid_attr), |
| 1569 | REG("fscreate", S_IRUGO|S_IWUGO, pid_attr), | ||
| 1570 | REG("keycreate", S_IRUGO|S_IWUGO, pid_attr), | ||
| 1571 | REG("sockcreate", S_IRUGO|S_IWUGO, pid_attr), | ||
| 1572 | }; | ||
| 1573 | |||
| 1574 | static int proc_attr_dir_readdir(struct file * filp, | ||
| 1575 | void * dirent, filldir_t filldir) | ||
| 1576 | { | ||
| 1577 | return proc_pident_readdir(filp,dirent,filldir, | ||
| 1578 | attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff)); | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | static struct file_operations proc_attr_dir_operations = { | ||
| 1582 | .read = generic_read_dir, | ||
| 1583 | .readdir = proc_attr_dir_readdir, | ||
| 1584 | }; | ||
| 1585 | |||
| 1586 | static struct dentry *proc_attr_dir_lookup(struct inode *dir, | ||
| 1587 | struct dentry *dentry, struct nameidata *nd) | ||
| 1588 | { | ||
| 1589 | return proc_pident_lookup(dir, dentry, | ||
| 1590 | attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | static struct inode_operations proc_attr_dir_inode_operations = { | ||
| 1594 | .lookup = proc_attr_dir_lookup, | ||
| 1595 | .getattr = pid_getattr, | ||
| 1596 | .setattr = proc_setattr, | ||
| 1597 | }; | ||
| 1598 | |||
| 1644 | #endif | 1599 | #endif |
| 1645 | 1600 | ||
| 1646 | /* SMP-safe */ | 1601 | /* |
| 1647 | static struct dentry *proc_pident_lookup(struct inode *dir, | 1602 | * /proc/self: |
| 1648 | struct dentry *dentry, | 1603 | */ |
| 1649 | struct pid_entry *ents) | 1604 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, |
| 1605 | int buflen) | ||
| 1606 | { | ||
| 1607 | char tmp[PROC_NUMBUF]; | ||
| 1608 | sprintf(tmp, "%d", current->tgid); | ||
| 1609 | return vfs_readlink(dentry,buffer,buflen,tmp); | ||
| 1610 | } | ||
| 1611 | |||
| 1612 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
| 1650 | { | 1613 | { |
| 1614 | char tmp[PROC_NUMBUF]; | ||
| 1615 | sprintf(tmp, "%d", current->tgid); | ||
| 1616 | return ERR_PTR(vfs_follow_link(nd,tmp)); | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | static struct inode_operations proc_self_inode_operations = { | ||
| 1620 | .readlink = proc_self_readlink, | ||
| 1621 | .follow_link = proc_self_follow_link, | ||
| 1622 | }; | ||
| 1623 | |||
| 1624 | /* | ||
| 1625 | * proc base | ||
| 1626 | * | ||
| 1627 | * These are the directory entries in the root directory of /proc | ||
| 1628 | * that properly belong to the /proc filesystem, as they describe | ||
| 1629 | * describe something that is process related. | ||
| 1630 | */ | ||
| 1631 | static struct pid_entry proc_base_stuff[] = { | ||
| 1632 | NOD("self", S_IFLNK|S_IRWXUGO, | ||
| 1633 | &proc_self_inode_operations, NULL, {}), | ||
| 1634 | }; | ||
| 1635 | |||
| 1636 | /* | ||
| 1637 | * Exceptional case: normally we are not allowed to unhash a busy | ||
| 1638 | * directory. In this case, however, we can do it - no aliasing problems | ||
| 1639 | * due to the way we treat inodes. | ||
| 1640 | */ | ||
| 1641 | static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
| 1642 | { | ||
| 1643 | struct inode *inode = dentry->d_inode; | ||
| 1644 | struct task_struct *task = get_proc_task(inode); | ||
| 1645 | if (task) { | ||
| 1646 | put_task_struct(task); | ||
| 1647 | return 1; | ||
| 1648 | } | ||
| 1649 | d_drop(dentry); | ||
| 1650 | return 0; | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | static struct dentry_operations proc_base_dentry_operations = | ||
| 1654 | { | ||
| 1655 | .d_revalidate = proc_base_revalidate, | ||
| 1656 | .d_delete = pid_delete_dentry, | ||
| 1657 | }; | ||
| 1658 | |||
| 1659 | static struct dentry *proc_base_instantiate(struct inode *dir, | ||
| 1660 | struct dentry *dentry, struct task_struct *task, void *ptr) | ||
| 1661 | { | ||
| 1662 | struct pid_entry *p = ptr; | ||
| 1651 | struct inode *inode; | 1663 | struct inode *inode; |
| 1664 | struct proc_inode *ei; | ||
| 1665 | struct dentry *error = ERR_PTR(-EINVAL); | ||
| 1666 | |||
| 1667 | /* Allocate the inode */ | ||
| 1668 | error = ERR_PTR(-ENOMEM); | ||
| 1669 | inode = new_inode(dir->i_sb); | ||
| 1670 | if (!inode) | ||
| 1671 | goto out; | ||
| 1672 | |||
| 1673 | /* Initialize the inode */ | ||
| 1674 | ei = PROC_I(inode); | ||
| 1675 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
| 1676 | |||
| 1677 | /* | ||
| 1678 | * grab the reference to the task. | ||
| 1679 | */ | ||
| 1680 | ei->pid = get_task_pid(task, PIDTYPE_PID); | ||
| 1681 | if (!ei->pid) | ||
| 1682 | goto out_iput; | ||
| 1683 | |||
| 1684 | inode->i_uid = 0; | ||
| 1685 | inode->i_gid = 0; | ||
| 1686 | inode->i_mode = p->mode; | ||
| 1687 | if (S_ISDIR(inode->i_mode)) | ||
| 1688 | inode->i_nlink = 2; | ||
| 1689 | if (S_ISLNK(inode->i_mode)) | ||
| 1690 | inode->i_size = 64; | ||
| 1691 | if (p->iop) | ||
| 1692 | inode->i_op = p->iop; | ||
| 1693 | if (p->fop) | ||
| 1694 | inode->i_fop = p->fop; | ||
| 1695 | ei->op = p->op; | ||
| 1696 | dentry->d_op = &proc_base_dentry_operations; | ||
| 1697 | d_add(dentry, inode); | ||
| 1698 | error = NULL; | ||
| 1699 | out: | ||
| 1700 | return error; | ||
| 1701 | out_iput: | ||
| 1702 | iput(inode); | ||
| 1703 | goto out; | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) | ||
| 1707 | { | ||
| 1652 | struct dentry *error; | 1708 | struct dentry *error; |
| 1653 | struct task_struct *task = get_proc_task(dir); | 1709 | struct task_struct *task = get_proc_task(dir); |
| 1654 | struct pid_entry *p; | 1710 | struct pid_entry *p, *last; |
| 1655 | struct proc_inode *ei; | ||
| 1656 | 1711 | ||
| 1657 | error = ERR_PTR(-ENOENT); | 1712 | error = ERR_PTR(-ENOENT); |
| 1658 | inode = NULL; | ||
| 1659 | 1713 | ||
| 1660 | if (!task) | 1714 | if (!task) |
| 1661 | goto out_no_task; | 1715 | goto out_no_task; |
| 1662 | 1716 | ||
| 1663 | for (p = ents; p->name; p++) { | 1717 | /* Lookup the directory entry */ |
| 1718 | last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1]; | ||
| 1719 | for (p = proc_base_stuff; p <= last; p++) { | ||
| 1664 | if (p->len != dentry->d_name.len) | 1720 | if (p->len != dentry->d_name.len) |
| 1665 | continue; | 1721 | continue; |
| 1666 | if (!memcmp(dentry->d_name.name, p->name, p->len)) | 1722 | if (!memcmp(dentry->d_name.name, p->name, p->len)) |
| 1667 | break; | 1723 | break; |
| 1668 | } | 1724 | } |
| 1669 | if (!p->name) | 1725 | if (p > last) |
| 1670 | goto out; | 1726 | goto out; |
| 1671 | 1727 | ||
| 1672 | error = ERR_PTR(-EINVAL); | 1728 | error = proc_base_instantiate(dir, dentry, task, p); |
| 1673 | inode = proc_pid_make_inode(dir->i_sb, task, p->type); | ||
| 1674 | if (!inode) | ||
| 1675 | goto out; | ||
| 1676 | 1729 | ||
| 1677 | ei = PROC_I(inode); | 1730 | out: |
| 1678 | inode->i_mode = p->mode; | 1731 | put_task_struct(task); |
| 1679 | /* | 1732 | out_no_task: |
| 1680 | * Yes, it does not scale. And it should not. Don't add | 1733 | return error; |
| 1681 | * new entries into /proc/<tgid>/ without very good reasons. | 1734 | } |
| 1682 | */ | 1735 | |
| 1683 | switch(p->type) { | 1736 | static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
| 1684 | case PROC_TGID_TASK: | 1737 | struct task_struct *task, struct pid_entry *p) |
| 1685 | inode->i_nlink = 2; | 1738 | { |
| 1686 | inode->i_op = &proc_task_inode_operations; | 1739 | return proc_fill_cache(filp, dirent, filldir, p->name, p->len, |
| 1687 | inode->i_fop = &proc_task_operations; | 1740 | proc_base_instantiate, task, p); |
| 1688 | break; | 1741 | } |
| 1689 | case PROC_TID_FD: | 1742 | |
| 1690 | case PROC_TGID_FD: | 1743 | /* |
| 1691 | inode->i_nlink = 2; | 1744 | * Thread groups |
| 1692 | inode->i_op = &proc_fd_inode_operations; | 1745 | */ |
| 1693 | inode->i_fop = &proc_fd_operations; | 1746 | static struct file_operations proc_task_operations; |
| 1694 | break; | 1747 | static struct inode_operations proc_task_inode_operations; |
| 1695 | case PROC_TID_EXE: | 1748 | |
| 1696 | case PROC_TGID_EXE: | 1749 | static struct pid_entry tgid_base_stuff[] = { |
| 1697 | inode->i_op = &proc_pid_link_inode_operations; | 1750 | DIR("task", S_IRUGO|S_IXUGO, task), |
| 1698 | ei->op.proc_get_link = proc_exe_link; | 1751 | DIR("fd", S_IRUSR|S_IXUSR, fd), |
| 1699 | break; | 1752 | INF("environ", S_IRUSR, pid_environ), |
| 1700 | case PROC_TID_CWD: | 1753 | INF("auxv", S_IRUSR, pid_auxv), |
| 1701 | case PROC_TGID_CWD: | 1754 | INF("status", S_IRUGO, pid_status), |
| 1702 | inode->i_op = &proc_pid_link_inode_operations; | 1755 | INF("cmdline", S_IRUGO, pid_cmdline), |
| 1703 | ei->op.proc_get_link = proc_cwd_link; | 1756 | INF("stat", S_IRUGO, tgid_stat), |
| 1704 | break; | 1757 | INF("statm", S_IRUGO, pid_statm), |
| 1705 | case PROC_TID_ROOT: | 1758 | REG("maps", S_IRUGO, maps), |
| 1706 | case PROC_TGID_ROOT: | ||
| 1707 | inode->i_op = &proc_pid_link_inode_operations; | ||
| 1708 | ei->op.proc_get_link = proc_root_link; | ||
| 1709 | break; | ||
| 1710 | case PROC_TID_ENVIRON: | ||
| 1711 | case PROC_TGID_ENVIRON: | ||
| 1712 | inode->i_fop = &proc_info_file_operations; | ||
| 1713 | ei->op.proc_read = proc_pid_environ; | ||
| 1714 | break; | ||
| 1715 | case PROC_TID_AUXV: | ||
| 1716 | case PROC_TGID_AUXV: | ||
| 1717 | inode->i_fop = &proc_info_file_operations; | ||
| 1718 | ei->op.proc_read = proc_pid_auxv; | ||
| 1719 | break; | ||
| 1720 | case PROC_TID_STATUS: | ||
| 1721 | case PROC_TGID_STATUS: | ||
| 1722 | inode->i_fop = &proc_info_file_operations; | ||
| 1723 | ei->op.proc_read = proc_pid_status; | ||
| 1724 | break; | ||
| 1725 | case PROC_TID_STAT: | ||
| 1726 | inode->i_fop = &proc_info_file_operations; | ||
| 1727 | ei->op.proc_read = proc_tid_stat; | ||
| 1728 | break; | ||
| 1729 | case PROC_TGID_STAT: | ||
| 1730 | inode->i_fop = &proc_info_file_operations; | ||
| 1731 | ei->op.proc_read = proc_tgid_stat; | ||
| 1732 | break; | ||
| 1733 | case PROC_TID_CMDLINE: | ||
| 1734 | case PROC_TGID_CMDLINE: | ||
| 1735 | inode->i_fop = &proc_info_file_operations; | ||
| 1736 | ei->op.proc_read = proc_pid_cmdline; | ||
| 1737 | break; | ||
| 1738 | case PROC_TID_STATM: | ||
| 1739 | case PROC_TGID_STATM: | ||
| 1740 | inode->i_fop = &proc_info_file_operations; | ||
| 1741 | ei->op.proc_read = proc_pid_statm; | ||
| 1742 | break; | ||
| 1743 | case PROC_TID_MAPS: | ||
| 1744 | case PROC_TGID_MAPS: | ||
| 1745 | inode->i_fop = &proc_maps_operations; | ||
| 1746 | break; | ||
| 1747 | #ifdef CONFIG_NUMA | 1759 | #ifdef CONFIG_NUMA |
| 1748 | case PROC_TID_NUMA_MAPS: | 1760 | REG("numa_maps", S_IRUGO, numa_maps), |
| 1749 | case PROC_TGID_NUMA_MAPS: | ||
| 1750 | inode->i_fop = &proc_numa_maps_operations; | ||
| 1751 | break; | ||
| 1752 | #endif | 1761 | #endif |
| 1753 | case PROC_TID_MEM: | 1762 | REG("mem", S_IRUSR|S_IWUSR, mem), |
| 1754 | case PROC_TGID_MEM: | ||
| 1755 | inode->i_fop = &proc_mem_operations; | ||
| 1756 | break; | ||
| 1757 | #ifdef CONFIG_SECCOMP | 1763 | #ifdef CONFIG_SECCOMP |
| 1758 | case PROC_TID_SECCOMP: | 1764 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), |
| 1759 | case PROC_TGID_SECCOMP: | 1765 | #endif |
| 1760 | inode->i_fop = &proc_seccomp_operations; | 1766 | LNK("cwd", cwd), |
| 1761 | break; | 1767 | LNK("root", root), |
| 1762 | #endif /* CONFIG_SECCOMP */ | 1768 | LNK("exe", exe), |
| 1763 | case PROC_TID_MOUNTS: | 1769 | REG("mounts", S_IRUGO, mounts), |
| 1764 | case PROC_TGID_MOUNTS: | 1770 | REG("mountstats", S_IRUSR, mountstats), |
| 1765 | inode->i_fop = &proc_mounts_operations; | ||
| 1766 | break; | ||
| 1767 | #ifdef CONFIG_MMU | 1771 | #ifdef CONFIG_MMU |
| 1768 | case PROC_TID_SMAPS: | 1772 | REG("smaps", S_IRUGO, smaps), |
| 1769 | case PROC_TGID_SMAPS: | ||
| 1770 | inode->i_fop = &proc_smaps_operations; | ||
| 1771 | break; | ||
| 1772 | #endif | 1773 | #endif |
| 1773 | case PROC_TID_MOUNTSTATS: | ||
| 1774 | case PROC_TGID_MOUNTSTATS: | ||
| 1775 | inode->i_fop = &proc_mountstats_operations; | ||
| 1776 | break; | ||
| 1777 | #ifdef CONFIG_SECURITY | 1774 | #ifdef CONFIG_SECURITY |
| 1778 | case PROC_TID_ATTR: | 1775 | DIR("attr", S_IRUGO|S_IXUGO, attr_dir), |
| 1779 | inode->i_nlink = 2; | ||
| 1780 | inode->i_op = &proc_tid_attr_inode_operations; | ||
| 1781 | inode->i_fop = &proc_tid_attr_operations; | ||
| 1782 | break; | ||
| 1783 | case PROC_TGID_ATTR: | ||
| 1784 | inode->i_nlink = 2; | ||
| 1785 | inode->i_op = &proc_tgid_attr_inode_operations; | ||
| 1786 | inode->i_fop = &proc_tgid_attr_operations; | ||
| 1787 | break; | ||
| 1788 | case PROC_TID_ATTR_CURRENT: | ||
| 1789 | case PROC_TGID_ATTR_CURRENT: | ||
| 1790 | case PROC_TID_ATTR_PREV: | ||
| 1791 | case PROC_TGID_ATTR_PREV: | ||
| 1792 | case PROC_TID_ATTR_EXEC: | ||
| 1793 | case PROC_TGID_ATTR_EXEC: | ||
| 1794 | case PROC_TID_ATTR_FSCREATE: | ||
| 1795 | case PROC_TGID_ATTR_FSCREATE: | ||
| 1796 | case PROC_TID_ATTR_KEYCREATE: | ||
| 1797 | case PROC_TGID_ATTR_KEYCREATE: | ||
| 1798 | case PROC_TID_ATTR_SOCKCREATE: | ||
| 1799 | case PROC_TGID_ATTR_SOCKCREATE: | ||
| 1800 | inode->i_fop = &proc_pid_attr_operations; | ||
| 1801 | break; | ||
| 1802 | #endif | 1776 | #endif |
| 1803 | #ifdef CONFIG_KALLSYMS | 1777 | #ifdef CONFIG_KALLSYMS |
| 1804 | case PROC_TID_WCHAN: | 1778 | INF("wchan", S_IRUGO, pid_wchan), |
| 1805 | case PROC_TGID_WCHAN: | ||
| 1806 | inode->i_fop = &proc_info_file_operations; | ||
| 1807 | ei->op.proc_read = proc_pid_wchan; | ||
| 1808 | break; | ||
| 1809 | #endif | 1779 | #endif |
| 1810 | #ifdef CONFIG_SCHEDSTATS | 1780 | #ifdef CONFIG_SCHEDSTATS |
| 1811 | case PROC_TID_SCHEDSTAT: | 1781 | INF("schedstat", S_IRUGO, pid_schedstat), |
| 1812 | case PROC_TGID_SCHEDSTAT: | ||
| 1813 | inode->i_fop = &proc_info_file_operations; | ||
| 1814 | ei->op.proc_read = proc_pid_schedstat; | ||
| 1815 | break; | ||
| 1816 | #endif | 1782 | #endif |
| 1817 | #ifdef CONFIG_CPUSETS | 1783 | #ifdef CONFIG_CPUSETS |
| 1818 | case PROC_TID_CPUSET: | 1784 | REG("cpuset", S_IRUGO, cpuset), |
| 1819 | case PROC_TGID_CPUSET: | ||
| 1820 | inode->i_fop = &proc_cpuset_operations; | ||
| 1821 | break; | ||
| 1822 | #endif | 1785 | #endif |
| 1823 | case PROC_TID_OOM_SCORE: | 1786 | INF("oom_score", S_IRUGO, oom_score), |
| 1824 | case PROC_TGID_OOM_SCORE: | 1787 | REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), |
| 1825 | inode->i_fop = &proc_info_file_operations; | ||
| 1826 | ei->op.proc_read = proc_oom_score; | ||
| 1827 | break; | ||
| 1828 | case PROC_TID_OOM_ADJUST: | ||
| 1829 | case PROC_TGID_OOM_ADJUST: | ||
| 1830 | inode->i_fop = &proc_oom_adjust_operations; | ||
| 1831 | break; | ||
| 1832 | #ifdef CONFIG_AUDITSYSCALL | 1788 | #ifdef CONFIG_AUDITSYSCALL |
| 1833 | case PROC_TID_LOGINUID: | 1789 | REG("loginuid", S_IWUSR|S_IRUGO, loginuid), |
| 1834 | case PROC_TGID_LOGINUID: | ||
| 1835 | inode->i_fop = &proc_loginuid_operations; | ||
| 1836 | break; | ||
| 1837 | #endif | 1790 | #endif |
| 1838 | default: | ||
| 1839 | printk("procfs: impossible type (%d)",p->type); | ||
| 1840 | iput(inode); | ||
| 1841 | error = ERR_PTR(-EINVAL); | ||
| 1842 | goto out; | ||
| 1843 | } | ||
| 1844 | dentry->d_op = &pid_dentry_operations; | ||
| 1845 | d_add(dentry, inode); | ||
| 1846 | /* Close the race of the process dying before we return the dentry */ | ||
| 1847 | if (pid_revalidate(dentry, NULL)) | ||
| 1848 | error = NULL; | ||
| 1849 | out: | ||
| 1850 | put_task_struct(task); | ||
| 1851 | out_no_task: | ||
| 1852 | return error; | ||
| 1853 | } | ||
| 1854 | |||
| 1855 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ | ||
| 1856 | return proc_pident_lookup(dir, dentry, tgid_base_stuff); | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ | ||
| 1860 | return proc_pident_lookup(dir, dentry, tid_base_stuff); | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | static struct file_operations proc_tgid_base_operations = { | ||
| 1864 | .read = generic_read_dir, | ||
| 1865 | .readdir = proc_tgid_base_readdir, | ||
| 1866 | }; | 1791 | }; |
| 1867 | 1792 | ||
| 1868 | static struct file_operations proc_tid_base_operations = { | 1793 | static int proc_tgid_base_readdir(struct file * filp, |
| 1869 | .read = generic_read_dir, | ||
| 1870 | .readdir = proc_tid_base_readdir, | ||
| 1871 | }; | ||
| 1872 | |||
| 1873 | static struct inode_operations proc_tgid_base_inode_operations = { | ||
| 1874 | .lookup = proc_tgid_base_lookup, | ||
| 1875 | .getattr = pid_getattr, | ||
| 1876 | .setattr = proc_setattr, | ||
| 1877 | }; | ||
| 1878 | |||
| 1879 | static struct inode_operations proc_tid_base_inode_operations = { | ||
| 1880 | .lookup = proc_tid_base_lookup, | ||
| 1881 | .getattr = pid_getattr, | ||
| 1882 | .setattr = proc_setattr, | ||
| 1883 | }; | ||
| 1884 | |||
| 1885 | #ifdef CONFIG_SECURITY | ||
| 1886 | static int proc_tgid_attr_readdir(struct file * filp, | ||
| 1887 | void * dirent, filldir_t filldir) | ||
| 1888 | { | ||
| 1889 | return proc_pident_readdir(filp,dirent,filldir, | ||
| 1890 | tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff)); | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | static int proc_tid_attr_readdir(struct file * filp, | ||
| 1894 | void * dirent, filldir_t filldir) | 1794 | void * dirent, filldir_t filldir) |
| 1895 | { | 1795 | { |
| 1896 | return proc_pident_readdir(filp,dirent,filldir, | 1796 | return proc_pident_readdir(filp,dirent,filldir, |
| 1897 | tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff)); | 1797 | tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff)); |
| 1898 | } | 1798 | } |
| 1899 | 1799 | ||
| 1900 | static struct file_operations proc_tgid_attr_operations = { | 1800 | static struct file_operations proc_tgid_base_operations = { |
| 1901 | .read = generic_read_dir, | ||
| 1902 | .readdir = proc_tgid_attr_readdir, | ||
| 1903 | }; | ||
| 1904 | |||
| 1905 | static struct file_operations proc_tid_attr_operations = { | ||
| 1906 | .read = generic_read_dir, | 1801 | .read = generic_read_dir, |
| 1907 | .readdir = proc_tid_attr_readdir, | 1802 | .readdir = proc_tgid_base_readdir, |
| 1908 | }; | 1803 | }; |
| 1909 | 1804 | ||
| 1910 | static struct dentry *proc_tgid_attr_lookup(struct inode *dir, | 1805 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ |
| 1911 | struct dentry *dentry, struct nameidata *nd) | 1806 | return proc_pident_lookup(dir, dentry, |
| 1912 | { | 1807 | tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); |
| 1913 | return proc_pident_lookup(dir, dentry, tgid_attr_stuff); | ||
| 1914 | } | ||
| 1915 | |||
| 1916 | static struct dentry *proc_tid_attr_lookup(struct inode *dir, | ||
| 1917 | struct dentry *dentry, struct nameidata *nd) | ||
| 1918 | { | ||
| 1919 | return proc_pident_lookup(dir, dentry, tid_attr_stuff); | ||
| 1920 | } | 1808 | } |
| 1921 | 1809 | ||
| 1922 | static struct inode_operations proc_tgid_attr_inode_operations = { | 1810 | static struct inode_operations proc_tgid_base_inode_operations = { |
| 1923 | .lookup = proc_tgid_attr_lookup, | 1811 | .lookup = proc_tgid_base_lookup, |
| 1924 | .getattr = pid_getattr, | ||
| 1925 | .setattr = proc_setattr, | ||
| 1926 | }; | ||
| 1927 | |||
| 1928 | static struct inode_operations proc_tid_attr_inode_operations = { | ||
| 1929 | .lookup = proc_tid_attr_lookup, | ||
| 1930 | .getattr = pid_getattr, | 1812 | .getattr = pid_getattr, |
| 1931 | .setattr = proc_setattr, | 1813 | .setattr = proc_setattr, |
| 1932 | }; | 1814 | }; |
| 1933 | #endif | ||
| 1934 | |||
| 1935 | /* | ||
| 1936 | * /proc/self: | ||
| 1937 | */ | ||
| 1938 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | ||
| 1939 | int buflen) | ||
| 1940 | { | ||
| 1941 | char tmp[PROC_NUMBUF]; | ||
| 1942 | sprintf(tmp, "%d", current->tgid); | ||
| 1943 | return vfs_readlink(dentry,buffer,buflen,tmp); | ||
| 1944 | } | ||
| 1945 | |||
| 1946 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
| 1947 | { | ||
| 1948 | char tmp[PROC_NUMBUF]; | ||
| 1949 | sprintf(tmp, "%d", current->tgid); | ||
| 1950 | return ERR_PTR(vfs_follow_link(nd,tmp)); | ||
| 1951 | } | ||
| 1952 | |||
| 1953 | static struct inode_operations proc_self_inode_operations = { | ||
| 1954 | .readlink = proc_self_readlink, | ||
| 1955 | .follow_link = proc_self_follow_link, | ||
| 1956 | }; | ||
| 1957 | 1815 | ||
| 1958 | /** | 1816 | /** |
| 1959 | * proc_flush_task - Remove dcache entries for @task from the /proc dcache. | 1817 | * proc_flush_task - Remove dcache entries for @task from the /proc dcache. |
| @@ -2022,54 +1880,23 @@ out: | |||
| 2022 | return; | 1880 | return; |
| 2023 | } | 1881 | } |
| 2024 | 1882 | ||
| 2025 | /* SMP-safe */ | 1883 | struct dentry *proc_pid_instantiate(struct inode *dir, |
| 2026 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 1884 | struct dentry * dentry, struct task_struct *task, void *ptr) |
| 2027 | { | 1885 | { |
| 2028 | struct dentry *result = ERR_PTR(-ENOENT); | 1886 | struct dentry *error = ERR_PTR(-ENOENT); |
| 2029 | struct task_struct *task; | ||
| 2030 | struct inode *inode; | 1887 | struct inode *inode; |
| 2031 | struct proc_inode *ei; | ||
| 2032 | unsigned tgid; | ||
| 2033 | |||
| 2034 | if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) { | ||
| 2035 | inode = new_inode(dir->i_sb); | ||
| 2036 | if (!inode) | ||
| 2037 | return ERR_PTR(-ENOMEM); | ||
| 2038 | ei = PROC_I(inode); | ||
| 2039 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
| 2040 | inode->i_ino = fake_ino(0, PROC_TGID_INO); | ||
| 2041 | ei->pde = NULL; | ||
| 2042 | inode->i_mode = S_IFLNK|S_IRWXUGO; | ||
| 2043 | inode->i_uid = inode->i_gid = 0; | ||
| 2044 | inode->i_size = 64; | ||
| 2045 | inode->i_op = &proc_self_inode_operations; | ||
| 2046 | d_add(dentry, inode); | ||
| 2047 | return NULL; | ||
| 2048 | } | ||
| 2049 | tgid = name_to_int(dentry); | ||
| 2050 | if (tgid == ~0U) | ||
| 2051 | goto out; | ||
| 2052 | 1888 | ||
| 2053 | rcu_read_lock(); | 1889 | inode = proc_pid_make_inode(dir->i_sb, task); |
| 2054 | task = find_task_by_pid(tgid); | ||
| 2055 | if (task) | ||
| 2056 | get_task_struct(task); | ||
| 2057 | rcu_read_unlock(); | ||
| 2058 | if (!task) | ||
| 2059 | goto out; | ||
| 2060 | |||
| 2061 | inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); | ||
| 2062 | if (!inode) | 1890 | if (!inode) |
| 2063 | goto out_put_task; | 1891 | goto out; |
| 2064 | 1892 | ||
| 2065 | inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; | 1893 | inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; |
| 2066 | inode->i_op = &proc_tgid_base_inode_operations; | 1894 | inode->i_op = &proc_tgid_base_inode_operations; |
| 2067 | inode->i_fop = &proc_tgid_base_operations; | 1895 | inode->i_fop = &proc_tgid_base_operations; |
| 2068 | inode->i_flags|=S_IMMUTABLE; | 1896 | inode->i_flags|=S_IMMUTABLE; |
| 2069 | #ifdef CONFIG_SECURITY | ||
| 2070 | inode->i_nlink = 5; | ||
| 2071 | #else | ||
| 2072 | inode->i_nlink = 4; | 1897 | inode->i_nlink = 4; |
| 1898 | #ifdef CONFIG_SECURITY | ||
| 1899 | inode->i_nlink += 1; | ||
| 2073 | #endif | 1900 | #endif |
| 2074 | 1901 | ||
| 2075 | dentry->d_op = &pid_dentry_operations; | 1902 | dentry->d_op = &pid_dentry_operations; |
| @@ -2077,179 +1904,251 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct | |||
| 2077 | d_add(dentry, inode); | 1904 | d_add(dentry, inode); |
| 2078 | /* Close the race of the process dying before we return the dentry */ | 1905 | /* Close the race of the process dying before we return the dentry */ |
| 2079 | if (pid_revalidate(dentry, NULL)) | 1906 | if (pid_revalidate(dentry, NULL)) |
| 2080 | result = NULL; | 1907 | error = NULL; |
| 2081 | |||
| 2082 | out_put_task: | ||
| 2083 | put_task_struct(task); | ||
| 2084 | out: | 1908 | out: |
| 2085 | return result; | 1909 | return error; |
| 2086 | } | 1910 | } |
| 2087 | 1911 | ||
| 2088 | /* SMP-safe */ | 1912 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
| 2089 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | ||
| 2090 | { | 1913 | { |
| 2091 | struct dentry *result = ERR_PTR(-ENOENT); | 1914 | struct dentry *result = ERR_PTR(-ENOENT); |
| 2092 | struct task_struct *task; | 1915 | struct task_struct *task; |
| 2093 | struct task_struct *leader = get_proc_task(dir); | 1916 | unsigned tgid; |
| 2094 | struct inode *inode; | ||
| 2095 | unsigned tid; | ||
| 2096 | 1917 | ||
| 2097 | if (!leader) | 1918 | result = proc_base_lookup(dir, dentry); |
| 2098 | goto out_no_task; | 1919 | if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) |
| 1920 | goto out; | ||
| 2099 | 1921 | ||
| 2100 | tid = name_to_int(dentry); | 1922 | tgid = name_to_int(dentry); |
| 2101 | if (tid == ~0U) | 1923 | if (tgid == ~0U) |
| 2102 | goto out; | 1924 | goto out; |
| 2103 | 1925 | ||
| 2104 | rcu_read_lock(); | 1926 | rcu_read_lock(); |
| 2105 | task = find_task_by_pid(tid); | 1927 | task = find_task_by_pid(tgid); |
| 2106 | if (task) | 1928 | if (task) |
| 2107 | get_task_struct(task); | 1929 | get_task_struct(task); |
| 2108 | rcu_read_unlock(); | 1930 | rcu_read_unlock(); |
| 2109 | if (!task) | 1931 | if (!task) |
| 2110 | goto out; | 1932 | goto out; |
| 2111 | if (leader->tgid != task->tgid) | ||
| 2112 | goto out_drop_task; | ||
| 2113 | |||
| 2114 | inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); | ||
| 2115 | |||
| 2116 | |||
| 2117 | if (!inode) | ||
| 2118 | goto out_drop_task; | ||
| 2119 | inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; | ||
| 2120 | inode->i_op = &proc_tid_base_inode_operations; | ||
| 2121 | inode->i_fop = &proc_tid_base_operations; | ||
| 2122 | inode->i_flags|=S_IMMUTABLE; | ||
| 2123 | #ifdef CONFIG_SECURITY | ||
| 2124 | inode->i_nlink = 4; | ||
| 2125 | #else | ||
| 2126 | inode->i_nlink = 3; | ||
| 2127 | #endif | ||
| 2128 | |||
| 2129 | dentry->d_op = &pid_dentry_operations; | ||
| 2130 | |||
| 2131 | d_add(dentry, inode); | ||
| 2132 | /* Close the race of the process dying before we return the dentry */ | ||
| 2133 | if (pid_revalidate(dentry, NULL)) | ||
| 2134 | result = NULL; | ||
| 2135 | 1933 | ||
| 2136 | out_drop_task: | 1934 | result = proc_pid_instantiate(dir, dentry, task, NULL); |
| 2137 | put_task_struct(task); | 1935 | put_task_struct(task); |
| 2138 | out: | 1936 | out: |
| 2139 | put_task_struct(leader); | ||
| 2140 | out_no_task: | ||
| 2141 | return result; | 1937 | return result; |
| 2142 | } | 1938 | } |
| 2143 | 1939 | ||
| 2144 | /* | 1940 | /* |
| 2145 | * Find the first tgid to return to user space. | 1941 | * Find the first task with tgid >= tgid |
| 2146 | * | ||
| 2147 | * Usually this is just whatever follows &init_task, but if the users | ||
| 2148 | * buffer was too small to hold the full list or there was a seek into | ||
| 2149 | * the middle of the directory we have more work to do. | ||
| 2150 | * | ||
| 2151 | * In the case of a short read we start with find_task_by_pid. | ||
| 2152 | * | 1942 | * |
| 2153 | * In the case of a seek we start with &init_task and walk nr | ||
| 2154 | * threads past it. | ||
| 2155 | */ | 1943 | */ |
| 2156 | static struct task_struct *first_tgid(int tgid, unsigned int nr) | 1944 | static struct task_struct *next_tgid(unsigned int tgid) |
| 2157 | { | 1945 | { |
| 2158 | struct task_struct *pos; | 1946 | struct task_struct *task; |
| 2159 | rcu_read_lock(); | 1947 | struct pid *pid; |
| 2160 | if (tgid && nr) { | ||
| 2161 | pos = find_task_by_pid(tgid); | ||
| 2162 | if (pos && thread_group_leader(pos)) | ||
| 2163 | goto found; | ||
| 2164 | } | ||
| 2165 | /* If nr exceeds the number of processes get out quickly */ | ||
| 2166 | pos = NULL; | ||
| 2167 | if (nr && nr >= nr_processes()) | ||
| 2168 | goto done; | ||
| 2169 | 1948 | ||
| 2170 | /* If we haven't found our starting place yet start with | 1949 | rcu_read_lock(); |
| 2171 | * the init_task and walk nr tasks forward. | 1950 | retry: |
| 2172 | */ | 1951 | task = NULL; |
| 2173 | for (pos = next_task(&init_task); nr > 0; --nr) { | 1952 | pid = find_ge_pid(tgid); |
| 2174 | pos = next_task(pos); | 1953 | if (pid) { |
| 2175 | if (pos == &init_task) { | 1954 | tgid = pid->nr + 1; |
| 2176 | pos = NULL; | 1955 | task = pid_task(pid, PIDTYPE_PID); |
| 2177 | goto done; | 1956 | /* What we to know is if the pid we have find is the |
| 2178 | } | 1957 | * pid of a thread_group_leader. Testing for task |
| 1958 | * being a thread_group_leader is the obvious thing | ||
| 1959 | * todo but there is a window when it fails, due to | ||
| 1960 | * the pid transfer logic in de_thread. | ||
| 1961 | * | ||
| 1962 | * So we perform the straight forward test of seeing | ||
| 1963 | * if the pid we have found is the pid of a thread | ||
| 1964 | * group leader, and don't worry if the task we have | ||
| 1965 | * found doesn't happen to be a thread group leader. | ||
| 1966 | * As we don't care in the case of readdir. | ||
| 1967 | */ | ||
| 1968 | if (!task || !has_group_leader_pid(task)) | ||
| 1969 | goto retry; | ||
| 1970 | get_task_struct(task); | ||
| 2179 | } | 1971 | } |
| 2180 | found: | ||
| 2181 | get_task_struct(pos); | ||
| 2182 | done: | ||
| 2183 | rcu_read_unlock(); | 1972 | rcu_read_unlock(); |
| 2184 | return pos; | 1973 | return task; |
| 2185 | } | 1974 | } |
| 2186 | 1975 | ||
| 2187 | /* | 1976 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff)) |
| 2188 | * Find the next task in the task list. | 1977 | |
| 2189 | * Return NULL if we loop or there is any error. | 1978 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
| 2190 | * | 1979 | struct task_struct *task, int tgid) |
| 2191 | * The reference to the input task_struct is released. | ||
| 2192 | */ | ||
| 2193 | static struct task_struct *next_tgid(struct task_struct *start) | ||
| 2194 | { | 1980 | { |
| 2195 | struct task_struct *pos; | 1981 | char name[PROC_NUMBUF]; |
| 2196 | rcu_read_lock(); | 1982 | int len = snprintf(name, sizeof(name), "%d", tgid); |
| 2197 | pos = start; | 1983 | return proc_fill_cache(filp, dirent, filldir, name, len, |
| 2198 | if (pid_alive(start)) | 1984 | proc_pid_instantiate, task, NULL); |
| 2199 | pos = next_task(start); | ||
| 2200 | if (pid_alive(pos) && (pos != &init_task)) { | ||
| 2201 | get_task_struct(pos); | ||
| 2202 | goto done; | ||
| 2203 | } | ||
| 2204 | pos = NULL; | ||
| 2205 | done: | ||
| 2206 | rcu_read_unlock(); | ||
| 2207 | put_task_struct(start); | ||
| 2208 | return pos; | ||
| 2209 | } | 1985 | } |
| 2210 | 1986 | ||
| 2211 | /* for the /proc/ directory itself, after non-process stuff has been done */ | 1987 | /* for the /proc/ directory itself, after non-process stuff has been done */ |
| 2212 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | 1988 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) |
| 2213 | { | 1989 | { |
| 2214 | char buf[PROC_NUMBUF]; | ||
| 2215 | unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; | 1990 | unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; |
| 1991 | struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode); | ||
| 2216 | struct task_struct *task; | 1992 | struct task_struct *task; |
| 2217 | int tgid; | 1993 | int tgid; |
| 2218 | 1994 | ||
| 2219 | if (!nr) { | 1995 | if (!reaper) |
| 2220 | ino_t ino = fake_ino(0,PROC_TGID_INO); | 1996 | goto out_no_task; |
| 2221 | if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0) | 1997 | |
| 2222 | return 0; | 1998 | for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { |
| 2223 | filp->f_pos++; | 1999 | struct pid_entry *p = &proc_base_stuff[nr]; |
| 2224 | nr++; | 2000 | if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) |
| 2001 | goto out; | ||
| 2225 | } | 2002 | } |
| 2226 | nr -= 1; | ||
| 2227 | 2003 | ||
| 2228 | /* f_version caches the tgid value that the last readdir call couldn't | 2004 | tgid = filp->f_pos - TGID_OFFSET; |
| 2229 | * return. lseek aka telldir automagically resets f_version to 0. | 2005 | for (task = next_tgid(tgid); |
| 2230 | */ | ||
| 2231 | tgid = filp->f_version; | ||
| 2232 | filp->f_version = 0; | ||
| 2233 | for (task = first_tgid(tgid, nr); | ||
| 2234 | task; | 2006 | task; |
| 2235 | task = next_tgid(task), filp->f_pos++) { | 2007 | put_task_struct(task), task = next_tgid(tgid + 1)) { |
| 2236 | int len; | ||
| 2237 | ino_t ino; | ||
| 2238 | tgid = task->pid; | 2008 | tgid = task->pid; |
| 2239 | len = snprintf(buf, sizeof(buf), "%d", tgid); | 2009 | filp->f_pos = tgid + TGID_OFFSET; |
| 2240 | ino = fake_ino(tgid, PROC_TGID_INO); | 2010 | if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) { |
| 2241 | if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) { | ||
| 2242 | /* returning this tgid failed, save it as the first | ||
| 2243 | * pid for the next readir call */ | ||
| 2244 | filp->f_version = tgid; | ||
| 2245 | put_task_struct(task); | 2011 | put_task_struct(task); |
| 2246 | break; | 2012 | goto out; |
| 2247 | } | 2013 | } |
| 2248 | } | 2014 | } |
| 2015 | filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET; | ||
| 2016 | out: | ||
| 2017 | put_task_struct(reaper); | ||
| 2018 | out_no_task: | ||
| 2249 | return 0; | 2019 | return 0; |
| 2250 | } | 2020 | } |
| 2251 | 2021 | ||
| 2252 | /* | 2022 | /* |
| 2023 | * Tasks | ||
| 2024 | */ | ||
| 2025 | static struct pid_entry tid_base_stuff[] = { | ||
| 2026 | DIR("fd", S_IRUSR|S_IXUSR, fd), | ||
| 2027 | INF("environ", S_IRUSR, pid_environ), | ||
| 2028 | INF("auxv", S_IRUSR, pid_auxv), | ||
| 2029 | INF("status", S_IRUGO, pid_status), | ||
| 2030 | INF("cmdline", S_IRUGO, pid_cmdline), | ||
| 2031 | INF("stat", S_IRUGO, tid_stat), | ||
| 2032 | INF("statm", S_IRUGO, pid_statm), | ||
| 2033 | REG("maps", S_IRUGO, maps), | ||
| 2034 | #ifdef CONFIG_NUMA | ||
| 2035 | REG("numa_maps", S_IRUGO, numa_maps), | ||
| 2036 | #endif | ||
| 2037 | REG("mem", S_IRUSR|S_IWUSR, mem), | ||
| 2038 | #ifdef CONFIG_SECCOMP | ||
| 2039 | REG("seccomp", S_IRUSR|S_IWUSR, seccomp), | ||
| 2040 | #endif | ||
| 2041 | LNK("cwd", cwd), | ||
| 2042 | LNK("root", root), | ||
| 2043 | LNK("exe", exe), | ||
| 2044 | REG("mounts", S_IRUGO, mounts), | ||
| 2045 | #ifdef CONFIG_MMU | ||
| 2046 | REG("smaps", S_IRUGO, smaps), | ||
| 2047 | #endif | ||
| 2048 | #ifdef CONFIG_SECURITY | ||
| 2049 | DIR("attr", S_IRUGO|S_IXUGO, attr_dir), | ||
| 2050 | #endif | ||
| 2051 | #ifdef CONFIG_KALLSYMS | ||
| 2052 | INF("wchan", S_IRUGO, pid_wchan), | ||
| 2053 | #endif | ||
| 2054 | #ifdef CONFIG_SCHEDSTATS | ||
| 2055 | INF("schedstat", S_IRUGO, pid_schedstat), | ||
| 2056 | #endif | ||
| 2057 | #ifdef CONFIG_CPUSETS | ||
| 2058 | REG("cpuset", S_IRUGO, cpuset), | ||
| 2059 | #endif | ||
| 2060 | INF("oom_score", S_IRUGO, oom_score), | ||
| 2061 | REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), | ||
| 2062 | #ifdef CONFIG_AUDITSYSCALL | ||
| 2063 | REG("loginuid", S_IWUSR|S_IRUGO, loginuid), | ||
| 2064 | #endif | ||
| 2065 | }; | ||
| 2066 | |||
| 2067 | static int proc_tid_base_readdir(struct file * filp, | ||
| 2068 | void * dirent, filldir_t filldir) | ||
| 2069 | { | ||
| 2070 | return proc_pident_readdir(filp,dirent,filldir, | ||
| 2071 | tid_base_stuff,ARRAY_SIZE(tid_base_stuff)); | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ | ||
| 2075 | return proc_pident_lookup(dir, dentry, | ||
| 2076 | tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | static struct file_operations proc_tid_base_operations = { | ||
| 2080 | .read = generic_read_dir, | ||
| 2081 | .readdir = proc_tid_base_readdir, | ||
| 2082 | }; | ||
| 2083 | |||
| 2084 | static struct inode_operations proc_tid_base_inode_operations = { | ||
| 2085 | .lookup = proc_tid_base_lookup, | ||
| 2086 | .getattr = pid_getattr, | ||
| 2087 | .setattr = proc_setattr, | ||
| 2088 | }; | ||
| 2089 | |||
| 2090 | static struct dentry *proc_task_instantiate(struct inode *dir, | ||
| 2091 | struct dentry *dentry, struct task_struct *task, void *ptr) | ||
| 2092 | { | ||
| 2093 | struct dentry *error = ERR_PTR(-ENOENT); | ||
| 2094 | struct inode *inode; | ||
| 2095 | inode = proc_pid_make_inode(dir->i_sb, task); | ||
| 2096 | |||
| 2097 | if (!inode) | ||
| 2098 | goto out; | ||
| 2099 | inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; | ||
| 2100 | inode->i_op = &proc_tid_base_inode_operations; | ||
| 2101 | inode->i_fop = &proc_tid_base_operations; | ||
| 2102 | inode->i_flags|=S_IMMUTABLE; | ||
| 2103 | inode->i_nlink = 3; | ||
| 2104 | #ifdef CONFIG_SECURITY | ||
| 2105 | inode->i_nlink += 1; | ||
| 2106 | #endif | ||
| 2107 | |||
| 2108 | dentry->d_op = &pid_dentry_operations; | ||
| 2109 | |||
| 2110 | d_add(dentry, inode); | ||
| 2111 | /* Close the race of the process dying before we return the dentry */ | ||
| 2112 | if (pid_revalidate(dentry, NULL)) | ||
| 2113 | error = NULL; | ||
| 2114 | out: | ||
| 2115 | return error; | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | ||
| 2119 | { | ||
| 2120 | struct dentry *result = ERR_PTR(-ENOENT); | ||
| 2121 | struct task_struct *task; | ||
| 2122 | struct task_struct *leader = get_proc_task(dir); | ||
| 2123 | unsigned tid; | ||
| 2124 | |||
| 2125 | if (!leader) | ||
| 2126 | goto out_no_task; | ||
| 2127 | |||
| 2128 | tid = name_to_int(dentry); | ||
| 2129 | if (tid == ~0U) | ||
| 2130 | goto out; | ||
| 2131 | |||
| 2132 | rcu_read_lock(); | ||
| 2133 | task = find_task_by_pid(tid); | ||
| 2134 | if (task) | ||
| 2135 | get_task_struct(task); | ||
| 2136 | rcu_read_unlock(); | ||
| 2137 | if (!task) | ||
| 2138 | goto out; | ||
| 2139 | if (leader->tgid != task->tgid) | ||
| 2140 | goto out_drop_task; | ||
| 2141 | |||
| 2142 | result = proc_task_instantiate(dir, dentry, task, NULL); | ||
| 2143 | out_drop_task: | ||
| 2144 | put_task_struct(task); | ||
| 2145 | out: | ||
| 2146 | put_task_struct(leader); | ||
| 2147 | out_no_task: | ||
| 2148 | return result; | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | /* | ||
| 2253 | * Find the first tid of a thread group to return to user space. | 2152 | * Find the first tid of a thread group to return to user space. |
| 2254 | * | 2153 | * |
| 2255 | * Usually this is just the thread group leader, but if the users | 2154 | * Usually this is just the thread group leader, but if the users |
| @@ -2318,10 +2217,18 @@ static struct task_struct *next_tid(struct task_struct *start) | |||
| 2318 | return pos; | 2217 | return pos; |
| 2319 | } | 2218 | } |
| 2320 | 2219 | ||
| 2220 | static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | ||
| 2221 | struct task_struct *task, int tid) | ||
| 2222 | { | ||
| 2223 | char name[PROC_NUMBUF]; | ||
| 2224 | int len = snprintf(name, sizeof(name), "%d", tid); | ||
| 2225 | return proc_fill_cache(filp, dirent, filldir, name, len, | ||
| 2226 | proc_task_instantiate, task, NULL); | ||
| 2227 | } | ||
| 2228 | |||
| 2321 | /* for the /proc/TGID/task/ directories */ | 2229 | /* for the /proc/TGID/task/ directories */ |
| 2322 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir) | 2230 | static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir) |
| 2323 | { | 2231 | { |
| 2324 | char buf[PROC_NUMBUF]; | ||
| 2325 | struct dentry *dentry = filp->f_dentry; | 2232 | struct dentry *dentry = filp->f_dentry; |
| 2326 | struct inode *inode = dentry->d_inode; | 2233 | struct inode *inode = dentry->d_inode; |
| 2327 | struct task_struct *leader = get_proc_task(inode); | 2234 | struct task_struct *leader = get_proc_task(inode); |
| @@ -2358,11 +2265,8 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi | |||
| 2358 | for (task = first_tid(leader, tid, pos - 2); | 2265 | for (task = first_tid(leader, tid, pos - 2); |
| 2359 | task; | 2266 | task; |
| 2360 | task = next_tid(task), pos++) { | 2267 | task = next_tid(task), pos++) { |
| 2361 | int len; | ||
| 2362 | tid = task->pid; | 2268 | tid = task->pid; |
| 2363 | len = snprintf(buf, sizeof(buf), "%d", tid); | 2269 | if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) { |
| 2364 | ino = fake_ino(tid, PROC_TID_INO); | ||
| 2365 | if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) { | ||
| 2366 | /* returning this tgid failed, save it as the first | 2270 | /* returning this tgid failed, save it as the first |
| 2367 | * pid for the next readir call */ | 2271 | * pid for the next readir call */ |
| 2368 | filp->f_version = tid; | 2272 | filp->f_version = tid; |
| @@ -2392,3 +2296,14 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct | |||
| 2392 | 2296 | ||
| 2393 | return 0; | 2297 | return 0; |
| 2394 | } | 2298 | } |
| 2299 | |||
| 2300 | static struct inode_operations proc_task_inode_operations = { | ||
| 2301 | .lookup = proc_task_lookup, | ||
| 2302 | .getattr = proc_task_getattr, | ||
| 2303 | .setattr = proc_setattr, | ||
| 2304 | }; | ||
| 2305 | |||
| 2306 | static struct file_operations proc_task_operations = { | ||
| 2307 | .read = generic_read_dir, | ||
| 2308 | .readdir = proc_task_readdir, | ||
| 2309 | }; | ||
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 66bc425f2f3d..8d88e58ed5cc 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <linux/sysrq.h> | 45 | #include <linux/sysrq.h> |
| 46 | #include <linux/vmalloc.h> | 46 | #include <linux/vmalloc.h> |
| 47 | #include <linux/crash_dump.h> | 47 | #include <linux/crash_dump.h> |
| 48 | #include <linux/pspace.h> | ||
| 48 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
| 49 | #include <asm/pgtable.h> | 50 | #include <asm/pgtable.h> |
| 50 | #include <asm/io.h> | 51 | #include <asm/io.h> |
| @@ -91,7 +92,7 @@ static int loadavg_read_proc(char *page, char **start, off_t off, | |||
| 91 | LOAD_INT(a), LOAD_FRAC(a), | 92 | LOAD_INT(a), LOAD_FRAC(a), |
| 92 | LOAD_INT(b), LOAD_FRAC(b), | 93 | LOAD_INT(b), LOAD_FRAC(b), |
| 93 | LOAD_INT(c), LOAD_FRAC(c), | 94 | LOAD_INT(c), LOAD_FRAC(c), |
| 94 | nr_running(), nr_threads, last_pid); | 95 | nr_running(), nr_threads, init_pspace.last_pid); |
| 95 | return proc_calc_metrics(page, start, off, count, eof, len); | 96 | return proc_calc_metrics(page, start, off, count, eof, len); |
| 96 | } | 97 | } |
| 97 | 98 | ||
diff --git a/fs/proc/root.c b/fs/proc/root.c index 8901c65caca8..ffe66c38488b 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
| 18 | #include <linux/smp_lock.h> | 18 | #include <linux/smp_lock.h> |
| 19 | #include <linux/mount.h> | ||
| 19 | 20 | ||
| 20 | #include "internal.h" | 21 | #include "internal.h" |
| 21 | 22 | ||
| @@ -28,6 +29,17 @@ struct proc_dir_entry *proc_sys_root; | |||
| 28 | static int proc_get_sb(struct file_system_type *fs_type, | 29 | static int proc_get_sb(struct file_system_type *fs_type, |
| 29 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 30 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
| 30 | { | 31 | { |
| 32 | if (proc_mnt) { | ||
| 33 | /* Seed the root directory with a pid so it doesn't need | ||
| 34 | * to be special in base.c. I would do this earlier but | ||
| 35 | * the only task alive when /proc is mounted the first time | ||
| 36 | * is the init_task and it doesn't have any pids. | ||
| 37 | */ | ||
| 38 | struct proc_inode *ei; | ||
| 39 | ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode); | ||
| 40 | if (!ei->pid) | ||
| 41 | ei->pid = find_get_pid(1); | ||
| 42 | } | ||
| 31 | return get_sb_single(fs_type, flags, data, proc_fill_super, mnt); | 43 | return get_sb_single(fs_type, flags, data, proc_fill_super, mnt); |
| 32 | } | 44 | } |
| 33 | 45 | ||
diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h index bc6e6a9259dc..2cabbd465c0c 100644 --- a/include/asm-alpha/unistd.h +++ b/include/asm-alpha/unistd.h | |||
| @@ -580,75 +580,6 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, type6 arg6)\ | |||
| 580 | #define __ARCH_WANT_SYS_OLDUMOUNT | 580 | #define __ARCH_WANT_SYS_OLDUMOUNT |
| 581 | #define __ARCH_WANT_SYS_SIGPENDING | 581 | #define __ARCH_WANT_SYS_SIGPENDING |
| 582 | 582 | ||
| 583 | #ifdef __KERNEL_SYSCALLS__ | ||
| 584 | |||
| 585 | #include <linux/compiler.h> | ||
| 586 | #include <linux/types.h> | ||
| 587 | #include <linux/string.h> | ||
| 588 | #include <linux/signal.h> | ||
| 589 | #include <linux/syscalls.h> | ||
| 590 | #include <asm/ptrace.h> | ||
| 591 | |||
| 592 | static inline long open(const char * name, int mode, int flags) | ||
| 593 | { | ||
| 594 | return sys_open(name, mode, flags); | ||
| 595 | } | ||
| 596 | |||
| 597 | static inline long dup(int fd) | ||
| 598 | { | ||
| 599 | return sys_dup(fd); | ||
| 600 | } | ||
| 601 | |||
| 602 | static inline long close(int fd) | ||
| 603 | { | ||
| 604 | return sys_close(fd); | ||
| 605 | } | ||
| 606 | |||
| 607 | static inline off_t lseek(int fd, off_t off, int whence) | ||
| 608 | { | ||
| 609 | return sys_lseek(fd, off, whence); | ||
| 610 | } | ||
| 611 | |||
| 612 | static inline void _exit(int value) | ||
| 613 | { | ||
| 614 | sys_exit(value); | ||
| 615 | } | ||
| 616 | |||
| 617 | #define exit(x) _exit(x) | ||
| 618 | |||
| 619 | static inline long write(int fd, const char * buf, size_t nr) | ||
| 620 | { | ||
| 621 | return sys_write(fd, buf, nr); | ||
| 622 | } | ||
| 623 | |||
| 624 | static inline long read(int fd, char * buf, size_t nr) | ||
| 625 | { | ||
| 626 | return sys_read(fd, buf, nr); | ||
| 627 | } | ||
| 628 | |||
| 629 | extern int execve(char *, char **, char **); | ||
| 630 | |||
| 631 | static inline long setsid(void) | ||
| 632 | { | ||
| 633 | return sys_setsid(); | ||
| 634 | } | ||
| 635 | |||
| 636 | static inline pid_t waitpid(int pid, int * wait_stat, int flags) | ||
| 637 | { | ||
| 638 | return sys_wait4(pid, wait_stat, flags, NULL); | ||
| 639 | } | ||
| 640 | |||
| 641 | asmlinkage int sys_execve(char *ufilename, char **argv, char **envp, | ||
| 642 | unsigned long a3, unsigned long a4, unsigned long a5, | ||
| 643 | struct pt_regs regs); | ||
| 644 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 645 | const struct sigaction __user *act, | ||
| 646 | struct sigaction __user *oact, | ||
| 647 | size_t sigsetsize, | ||
| 648 | void *restorer); | ||
| 649 | |||
| 650 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 651 | |||
| 652 | /* "Conditional" syscalls. What we want is | 583 | /* "Conditional" syscalls. What we want is |
| 653 | 584 | ||
| 654 | __attribute__((weak,alias("sys_ni_syscall"))) | 585 | __attribute__((weak,alias("sys_ni_syscall"))) |
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h index 2ab4078334bf..14a87eec5a2d 100644 --- a/include/asm-arm/unistd.h +++ b/include/asm-arm/unistd.h | |||
| @@ -549,30 +549,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 | |||
| 549 | #define __ARCH_WANT_SYS_SOCKETCALL | 549 | #define __ARCH_WANT_SYS_SOCKETCALL |
| 550 | #endif | 550 | #endif |
| 551 | 551 | ||
| 552 | #ifdef __KERNEL_SYSCALLS__ | ||
| 553 | |||
| 554 | #include <linux/compiler.h> | ||
| 555 | #include <linux/types.h> | ||
| 556 | #include <linux/syscalls.h> | ||
| 557 | |||
| 558 | extern long execve(const char *file, char **argv, char **envp); | ||
| 559 | |||
| 560 | struct pt_regs; | ||
| 561 | asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, | ||
| 562 | struct pt_regs *regs); | ||
| 563 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 564 | struct pt_regs *regs); | ||
| 565 | asmlinkage int sys_fork(struct pt_regs *regs); | ||
| 566 | asmlinkage int sys_vfork(struct pt_regs *regs); | ||
| 567 | asmlinkage int sys_pipe(unsigned long *fildes); | ||
| 568 | struct sigaction; | ||
| 569 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 570 | const struct sigaction __user *act, | ||
| 571 | struct sigaction __user *oact, | ||
| 572 | size_t sigsetsize); | ||
| 573 | |||
| 574 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 575 | |||
| 576 | /* | 552 | /* |
| 577 | * "Conditional" syscalls | 553 | * "Conditional" syscalls |
| 578 | * | 554 | * |
diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h index c6d2436c9d34..25a5eead85be 100644 --- a/include/asm-arm26/unistd.h +++ b/include/asm-arm26/unistd.h | |||
| @@ -464,30 +464,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 | |||
| 464 | #define __ARCH_WANT_SYS_SIGPROCMASK | 464 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 465 | #define __ARCH_WANT_SYS_RT_SIGACTION | 465 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 466 | 466 | ||
| 467 | #ifdef __KERNEL_SYSCALLS__ | ||
| 468 | |||
| 469 | #include <linux/compiler.h> | ||
| 470 | #include <linux/types.h> | ||
| 471 | #include <linux/syscalls.h> | ||
| 472 | |||
| 473 | extern long execve(const char *file, char **argv, char **envp); | ||
| 474 | |||
| 475 | struct pt_regs; | ||
| 476 | asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, | ||
| 477 | struct pt_regs *regs); | ||
| 478 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 479 | struct pt_regs *regs); | ||
| 480 | asmlinkage int sys_fork(struct pt_regs *regs); | ||
| 481 | asmlinkage int sys_vfork(struct pt_regs *regs); | ||
| 482 | asmlinkage int sys_pipe(unsigned long *fildes); | ||
| 483 | struct sigaction; | ||
| 484 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 485 | const struct sigaction __user *act, | ||
| 486 | struct sigaction __user *oact, | ||
| 487 | size_t sigsetsize); | ||
| 488 | |||
| 489 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 490 | |||
| 491 | /* | 467 | /* |
| 492 | * "Conditional" syscalls | 468 | * "Conditional" syscalls |
| 493 | * | 469 | * |
diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h index 1f528f92690d..a50e5004550c 100644 --- a/include/asm-avr32/unistd.h +++ b/include/asm-avr32/unistd.h | |||
| @@ -281,30 +281,10 @@ | |||
| 281 | #define __NR_tee 263 | 281 | #define __NR_tee 263 |
| 282 | #define __NR_vmsplice 264 | 282 | #define __NR_vmsplice 264 |
| 283 | 283 | ||
| 284 | #ifdef __KERNEL__ | ||
| 284 | #define NR_syscalls 265 | 285 | #define NR_syscalls 265 |
| 285 | 286 | ||
| 286 | 287 | ||
| 287 | /* | ||
| 288 | * AVR32 calling convention for system calls: | ||
| 289 | * - System call number in r8 | ||
| 290 | * - Parameters in r12 and downwards to r9 as well as r6 and r5. | ||
| 291 | * - Return value in r12 | ||
| 292 | */ | ||
| 293 | |||
| 294 | /* | ||
| 295 | * user-visible error numbers are in the range -1 - -124: see | ||
| 296 | * <asm-generic/errno.h> | ||
| 297 | */ | ||
| 298 | |||
| 299 | #define __syscall_return(type, res) do { \ | ||
| 300 | if ((unsigned long)(res) >= (unsigned long)(-125)) { \ | ||
| 301 | errno = -(res); \ | ||
| 302 | res = -1; \ | ||
| 303 | } \ | ||
| 304 | return (type) (res); \ | ||
| 305 | } while (0) | ||
| 306 | |||
| 307 | #ifdef __KERNEL__ | ||
| 308 | #define __ARCH_WANT_IPC_PARSE_VERSION | 288 | #define __ARCH_WANT_IPC_PARSE_VERSION |
| 309 | #define __ARCH_WANT_STAT64 | 289 | #define __ARCH_WANT_STAT64 |
| 310 | #define __ARCH_WANT_SYS_ALARM | 290 | #define __ARCH_WANT_SYS_ALARM |
| @@ -319,62 +299,6 @@ | |||
| 319 | #define __ARCH_WANT_SYS_GETPGRP | 299 | #define __ARCH_WANT_SYS_GETPGRP |
| 320 | #define __ARCH_WANT_SYS_RT_SIGACTION | 300 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 321 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 301 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
| 322 | #endif | ||
| 323 | |||
| 324 | #if defined(__KERNEL_SYSCALLS__) || defined(__CHECKER__) | ||
| 325 | |||
| 326 | #include <linux/types.h> | ||
| 327 | #include <linux/linkage.h> | ||
| 328 | #include <asm/signal.h> | ||
| 329 | |||
| 330 | struct pt_regs; | ||
| 331 | |||
| 332 | /* | ||
| 333 | * we need this inline - forking from kernel space will result | ||
| 334 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 335 | * is no problem, but for the stack. This is handled by not letting | ||
| 336 | * main() use the stack at all after fork(). Thus, no function | ||
| 337 | * calls - which means inline code for fork too, as otherwise we | ||
| 338 | * would use the stack upon exit from 'fork()'. | ||
| 339 | * | ||
| 340 | * Actually only pause and fork are needed inline, so that there | ||
| 341 | * won't be any messing with the stack from main(), but we define | ||
| 342 | * some others too. | ||
| 343 | */ | ||
| 344 | static inline int execve(const char *file, char **argv, char **envp) | ||
| 345 | { | ||
| 346 | register long scno asm("r8") = __NR_execve; | ||
| 347 | register long sc1 asm("r12") = (long)file; | ||
| 348 | register long sc2 asm("r11") = (long)argv; | ||
| 349 | register long sc3 asm("r10") = (long)envp; | ||
| 350 | int res; | ||
| 351 | |||
| 352 | asm volatile("scall" | ||
| 353 | : "=r"(sc1) | ||
| 354 | : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3) | ||
| 355 | : "lr", "memory"); | ||
| 356 | res = sc1; | ||
| 357 | __syscall_return(int, res); | ||
| 358 | } | ||
| 359 | |||
| 360 | asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize); | ||
| 361 | asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
| 362 | struct pt_regs *regs); | ||
| 363 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs); | ||
| 364 | asmlinkage int sys_pipe(unsigned long __user *filedes); | ||
| 365 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
| 366 | unsigned long prot, unsigned long flags, | ||
| 367 | unsigned long fd, off_t offset); | ||
| 368 | asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len); | ||
| 369 | asmlinkage int sys_fork(struct pt_regs *regs); | ||
| 370 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 371 | unsigned long parent_tidptr, | ||
| 372 | unsigned long child_tidptr, struct pt_regs *regs); | ||
| 373 | asmlinkage int sys_vfork(struct pt_regs *regs); | ||
| 374 | asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv, | ||
| 375 | char __user *__user *uenvp, struct pt_regs *regs); | ||
| 376 | |||
| 377 | #endif | ||
| 378 | 302 | ||
| 379 | /* | 303 | /* |
| 380 | * "Conditional" syscalls | 304 | * "Conditional" syscalls |
| @@ -384,4 +308,6 @@ asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv, | |||
| 384 | */ | 308 | */ |
| 385 | #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); | 309 | #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); |
| 386 | 310 | ||
| 311 | #endif /* __KERNEL__ */ | ||
| 312 | |||
| 387 | #endif /* __ASM_AVR32_UNISTD_H */ | 313 | #endif /* __ASM_AVR32_UNISTD_H */ |
diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h index 7372efae0516..7c90fa970c38 100644 --- a/include/asm-cris/unistd.h +++ b/include/asm-cris/unistd.h | |||
| @@ -322,67 +322,6 @@ | |||
| 322 | #define __ARCH_WANT_SYS_SIGPROCMASK | 322 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 323 | #define __ARCH_WANT_SYS_RT_SIGACTION | 323 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 324 | 324 | ||
| 325 | #ifdef __KERNEL_SYSCALLS__ | ||
| 326 | |||
| 327 | #include <linux/compiler.h> | ||
| 328 | #include <linux/types.h> | ||
| 329 | #include <linux/linkage.h> | ||
| 330 | |||
| 331 | /* | ||
| 332 | * we need this inline - forking from kernel space will result | ||
| 333 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 334 | * is no problem, but for the stack. This is handled by not letting | ||
| 335 | * main() use the stack at all after fork(). Thus, no function | ||
| 336 | * calls - which means inline code for fork too, as otherwise we | ||
| 337 | * would use the stack upon exit from 'fork()'. | ||
| 338 | * | ||
| 339 | * Actually only pause and fork are needed inline, so that there | ||
| 340 | * won't be any messing with the stack from main(), but we define | ||
| 341 | * some others too. | ||
| 342 | */ | ||
| 343 | #define __NR__exit __NR_exit | ||
| 344 | static inline _syscall0(pid_t,setsid) | ||
| 345 | static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 346 | static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 347 | static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 348 | static inline _syscall1(int,dup,int,fd) | ||
| 349 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 350 | static inline _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 351 | static inline _syscall1(int,close,int,fd) | ||
| 352 | |||
| 353 | struct pt_regs; | ||
| 354 | asmlinkage long sys_mmap2( | ||
| 355 | unsigned long addr, unsigned long len, | ||
| 356 | unsigned long prot, unsigned long flags, | ||
| 357 | unsigned long fd, unsigned long pgoff); | ||
| 358 | asmlinkage int sys_execve(const char *fname, char **argv, char **envp, | ||
| 359 | long r13, long mof, long srp, struct pt_regs *regs); | ||
| 360 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, | ||
| 361 | int* parent_tid, int* child_tid, long mof, long srp, | ||
| 362 | struct pt_regs *regs); | ||
| 363 | asmlinkage int sys_fork(long r10, long r11, long r12, long r13, | ||
| 364 | long mof, long srp, struct pt_regs *regs); | ||
| 365 | asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, | ||
| 366 | long mof, long srp, struct pt_regs *regs); | ||
| 367 | asmlinkage int sys_pipe(unsigned long __user *fildes); | ||
| 368 | struct sigaction; | ||
| 369 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 370 | const struct sigaction __user *act, | ||
| 371 | struct sigaction __user *oact, | ||
| 372 | size_t sigsetsize); | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Since we define it "external", it collides with the built-in | ||
| 376 | * definition, which has the "noreturn" attribute and will cause | ||
| 377 | * complaints. We don't want to use -fno-builtin, so just use a | ||
| 378 | * different name when in the kernel. | ||
| 379 | */ | ||
| 380 | #define _exit kernel_syscall_exit | ||
| 381 | static inline _syscall1(int,_exit,int,exitcode) | ||
| 382 | static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 383 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 384 | |||
| 385 | |||
| 386 | /* | 325 | /* |
| 387 | * "Conditional" syscalls | 326 | * "Conditional" syscalls |
| 388 | * | 327 | * |
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index d104d1b91d39..725e854928cf 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h | |||
| @@ -440,31 +440,6 @@ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg | |||
| 440 | __syscall_return(type, __sc0); \ | 440 | __syscall_return(type, __sc0); \ |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | |||
| 444 | #ifdef __KERNEL_SYSCALLS__ | ||
| 445 | |||
| 446 | #include <linux/compiler.h> | ||
| 447 | #include <linux/types.h> | ||
| 448 | #include <linux/linkage.h> | ||
| 449 | #include <asm/ptrace.h> | ||
| 450 | |||
| 451 | /* | ||
| 452 | * we need this inline - forking from kernel space will result | ||
| 453 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 454 | * is no problem, but for the stack. This is handled by not letting | ||
| 455 | * main() use the stack at all after fork(). Thus, no function | ||
| 456 | * calls - which means inline code for fork too, as otherwise we | ||
| 457 | * would use the stack upon exit from 'fork()'. | ||
| 458 | * | ||
| 459 | * Actually only pause and fork are needed inline, so that there | ||
| 460 | * won't be any messing with the stack from main(), but we define | ||
| 461 | * some others too. | ||
| 462 | */ | ||
| 463 | #define __NR__exit __NR_exit | ||
| 464 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 465 | |||
| 466 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 467 | |||
| 468 | #define __ARCH_WANT_IPC_PARSE_VERSION | 443 | #define __ARCH_WANT_IPC_PARSE_VERSION |
| 469 | /* #define __ARCH_WANT_OLD_READDIR */ | 444 | /* #define __ARCH_WANT_OLD_READDIR */ |
| 470 | #define __ARCH_WANT_OLD_STAT | 445 | #define __ARCH_WANT_OLD_STAT |
diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h index a2dd90462d80..747788d629ae 100644 --- a/include/asm-h8300/unistd.h +++ b/include/asm-h8300/unistd.h | |||
| @@ -485,57 +485,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ | |||
| 485 | #define __ARCH_WANT_SYS_SIGPROCMASK | 485 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 486 | #define __ARCH_WANT_SYS_RT_SIGACTION | 486 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 487 | 487 | ||
| 488 | #ifdef __KERNEL_SYSCALLS__ | ||
| 489 | |||
| 490 | #include <linux/compiler.h> | ||
| 491 | #include <linux/types.h> | ||
| 492 | |||
| 493 | /* | ||
| 494 | * we need this inline - forking from kernel space will result | ||
| 495 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 496 | * is no problem, but for the stack. This is handled by not letting | ||
| 497 | * main() use the stack at all after fork(). Thus, no function | ||
| 498 | * calls - which means inline code for fork too, as otherwise we | ||
| 499 | * would use the stack upon exit from 'fork()'. | ||
| 500 | * | ||
| 501 | * Actually only pause and fork are needed inline, so that there | ||
| 502 | * won't be any messing with the stack from main(), but we define | ||
| 503 | * some others too. | ||
| 504 | */ | ||
| 505 | #define __NR__exit __NR_exit | ||
| 506 | static inline _syscall0(int,pause) | ||
| 507 | static inline _syscall0(int,sync) | ||
| 508 | static inline _syscall0(pid_t,setsid) | ||
| 509 | static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 510 | static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 511 | static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 512 | static inline _syscall1(int,dup,int,fd) | ||
| 513 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 514 | static inline _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 515 | static inline _syscall1(int,close,int,fd) | ||
| 516 | static inline _syscall1(int,_exit,int,exitcode) | ||
| 517 | static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 518 | static inline _syscall1(int,delete_module,const char *,name) | ||
| 519 | |||
| 520 | static inline pid_t wait(int * wait_stat) | ||
| 521 | { | ||
| 522 | return waitpid(-1,wait_stat,0); | ||
| 523 | } | ||
| 524 | |||
| 525 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
| 526 | unsigned long prot, unsigned long flags, | ||
| 527 | unsigned long fd, unsigned long pgoff); | ||
| 528 | asmlinkage int sys_execve(char *name, char **argv, char **envp, | ||
| 529 | int dummy, ...); | ||
| 530 | asmlinkage int sys_pipe(unsigned long *fildes); | ||
| 531 | struct sigaction; | ||
| 532 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 533 | const struct sigaction __user *act, | ||
| 534 | struct sigaction __user *oact, | ||
| 535 | size_t sigsetsize); | ||
| 536 | |||
| 537 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 538 | |||
| 539 | /* | 488 | /* |
| 540 | * "Conditional" syscalls | 489 | * "Conditional" syscalls |
| 541 | */ | 490 | */ |
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h index 2a9e4ee5904d..592ffeeda45e 100644 --- a/include/asm-i386/bugs.h +++ b/include/asm-i386/bugs.h | |||
| @@ -189,6 +189,6 @@ static void __init check_bugs(void) | |||
| 189 | check_fpu(); | 189 | check_fpu(); |
| 190 | check_hlt(); | 190 | check_hlt(); |
| 191 | check_popad(); | 191 | check_popad(); |
| 192 | system_utsname.machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86); | 192 | init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86); |
| 193 | alternative_instructions(); | 193 | alternative_instructions(); |
| 194 | } | 194 | } |
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index db4344d9f73f..3a05436f31c0 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h | |||
| @@ -112,7 +112,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t; | |||
| 112 | For the moment, we have only optimizations for the Intel generations, | 112 | For the moment, we have only optimizations for the Intel generations, |
| 113 | but that could change... */ | 113 | but that could change... */ |
| 114 | 114 | ||
| 115 | #define ELF_PLATFORM (system_utsname.machine) | 115 | #define ELF_PLATFORM (utsname()->machine) |
| 116 | 116 | ||
| 117 | #define SET_PERSONALITY(ex, ibcs2) do { } while (0) | 117 | #define SET_PERSONALITY(ex, ibcs2) do { } while (0) |
| 118 | 118 | ||
diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h index a4a0e5207db5..d505f501077a 100644 --- a/include/asm-i386/ptrace.h +++ b/include/asm-i386/ptrace.h | |||
| @@ -47,7 +47,10 @@ static inline int user_mode_vm(struct pt_regs *regs) | |||
| 47 | { | 47 | { |
| 48 | return ((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= USER_RPL; | 48 | return ((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= USER_RPL; |
| 49 | } | 49 | } |
| 50 | |||
| 50 | #define instruction_pointer(regs) ((regs)->eip) | 51 | #define instruction_pointer(regs) ((regs)->eip) |
| 52 | #define regs_return_value(regs) ((regs)->eax) | ||
| 53 | |||
| 51 | extern unsigned long profile_pc(struct pt_regs *regs); | 54 | extern unsigned long profile_pc(struct pt_regs *regs); |
| 52 | #endif /* __KERNEL__ */ | 55 | #endif /* __KERNEL__ */ |
| 53 | 56 | ||
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index bd9987087adc..3ca7ab963d7d 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h | |||
| @@ -451,45 +451,6 @@ __syscall_return(type,__res); \ | |||
| 451 | #define __ARCH_WANT_SYS_RT_SIGACTION | 451 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 452 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 452 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
| 453 | 453 | ||
| 454 | #ifdef __KERNEL_SYSCALLS__ | ||
| 455 | |||
| 456 | #include <linux/compiler.h> | ||
| 457 | #include <linux/types.h> | ||
| 458 | #include <linux/linkage.h> | ||
| 459 | #include <asm/ptrace.h> | ||
| 460 | |||
| 461 | /* | ||
| 462 | * we need this inline - forking from kernel space will result | ||
| 463 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 464 | * is no problem, but for the stack. This is handled by not letting | ||
| 465 | * main() use the stack at all after fork(). Thus, no function | ||
| 466 | * calls - which means inline code for fork too, as otherwise we | ||
| 467 | * would use the stack upon exit from 'fork()'. | ||
| 468 | * | ||
| 469 | * Actually only pause and fork are needed inline, so that there | ||
| 470 | * won't be any messing with the stack from main(), but we define | ||
| 471 | * some others too. | ||
| 472 | */ | ||
| 473 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 474 | |||
| 475 | asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount); | ||
| 476 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
| 477 | unsigned long prot, unsigned long flags, | ||
| 478 | unsigned long fd, unsigned long pgoff); | ||
| 479 | asmlinkage int sys_execve(struct pt_regs regs); | ||
| 480 | asmlinkage int sys_clone(struct pt_regs regs); | ||
| 481 | asmlinkage int sys_fork(struct pt_regs regs); | ||
| 482 | asmlinkage int sys_vfork(struct pt_regs regs); | ||
| 483 | asmlinkage int sys_pipe(unsigned long __user *fildes); | ||
| 484 | asmlinkage long sys_iopl(unsigned long unused); | ||
| 485 | struct sigaction; | ||
| 486 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 487 | const struct sigaction __user *act, | ||
| 488 | struct sigaction __user *oact, | ||
| 489 | size_t sigsetsize); | ||
| 490 | |||
| 491 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 492 | |||
| 493 | /* | 454 | /* |
| 494 | * "Conditional" syscalls | 455 | * "Conditional" syscalls |
| 495 | * | 456 | * |
diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index 1414316efd40..f4ef87a36236 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h | |||
| @@ -241,6 +241,9 @@ struct switch_stack { | |||
| 241 | * the canonical representation by adding to instruction pointer. | 241 | * the canonical representation by adding to instruction pointer. |
| 242 | */ | 242 | */ |
| 243 | # define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri) | 243 | # define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri) |
| 244 | |||
| 245 | #define regs_return_value(regs) ((regs)->r8) | ||
| 246 | |||
| 244 | /* Conserve space in histogram by encoding slot bits in address | 247 | /* Conserve space in histogram by encoding slot bits in address |
| 245 | * bits 2 and 3 rather than bits 0 and 1. | 248 | * bits 2 and 3 rather than bits 0 and 1. |
| 246 | */ | 249 | */ |
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index bb0eb727dcd0..53c5c0ee122c 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h | |||
| @@ -319,78 +319,6 @@ | |||
| 319 | 319 | ||
| 320 | extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr); | 320 | extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr); |
| 321 | 321 | ||
| 322 | #ifdef __KERNEL_SYSCALLS__ | ||
| 323 | |||
| 324 | #include <linux/compiler.h> | ||
| 325 | #include <linux/string.h> | ||
| 326 | #include <linux/signal.h> | ||
| 327 | #include <asm/ptrace.h> | ||
| 328 | #include <linux/stringify.h> | ||
| 329 | #include <linux/syscalls.h> | ||
| 330 | |||
| 331 | static inline long | ||
| 332 | open (const char * name, int mode, int flags) | ||
| 333 | { | ||
| 334 | return sys_open(name, mode, flags); | ||
| 335 | } | ||
| 336 | |||
| 337 | static inline long | ||
| 338 | dup (int fd) | ||
| 339 | { | ||
| 340 | return sys_dup(fd); | ||
| 341 | } | ||
| 342 | |||
| 343 | static inline long | ||
| 344 | close (int fd) | ||
| 345 | { | ||
| 346 | return sys_close(fd); | ||
| 347 | } | ||
| 348 | |||
| 349 | static inline off_t | ||
| 350 | lseek (int fd, off_t off, int whence) | ||
| 351 | { | ||
| 352 | return sys_lseek(fd, off, whence); | ||
| 353 | } | ||
| 354 | |||
| 355 | static inline void | ||
| 356 | _exit (int value) | ||
| 357 | { | ||
| 358 | sys_exit(value); | ||
| 359 | } | ||
| 360 | |||
| 361 | #define exit(x) _exit(x) | ||
| 362 | |||
| 363 | static inline long | ||
| 364 | write (int fd, const char * buf, size_t nr) | ||
| 365 | { | ||
| 366 | return sys_write(fd, buf, nr); | ||
| 367 | } | ||
| 368 | |||
| 369 | static inline long | ||
| 370 | read (int fd, char * buf, size_t nr) | ||
| 371 | { | ||
| 372 | return sys_read(fd, buf, nr); | ||
| 373 | } | ||
| 374 | |||
| 375 | |||
| 376 | static inline long | ||
| 377 | setsid (void) | ||
| 378 | { | ||
| 379 | return sys_setsid(); | ||
| 380 | } | ||
| 381 | |||
| 382 | static inline pid_t | ||
| 383 | waitpid (int pid, int * wait_stat, int flags) | ||
| 384 | { | ||
| 385 | return sys_wait4(pid, wait_stat, flags, NULL); | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | extern int execve (const char *filename, char *const av[], char *const ep[]); | ||
| 390 | extern pid_t clone (unsigned long flags, void *sp); | ||
| 391 | |||
| 392 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 393 | |||
| 394 | asmlinkage unsigned long sys_mmap( | 322 | asmlinkage unsigned long sys_mmap( |
| 395 | unsigned long addr, unsigned long len, | 323 | unsigned long addr, unsigned long len, |
| 396 | int prot, int flags, | 324 | int prot, int flags, |
diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h index 5c6a9ac6cf1a..95aa34298d82 100644 --- a/include/asm-m32r/unistd.h +++ b/include/asm-m32r/unistd.h | |||
| @@ -424,43 +424,6 @@ __syscall_return(type,__res); \ | |||
| 424 | #define __ARCH_WANT_SYS_OLDUMOUNT | 424 | #define __ARCH_WANT_SYS_OLDUMOUNT |
| 425 | #define __ARCH_WANT_SYS_RT_SIGACTION | 425 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 426 | 426 | ||
| 427 | #ifdef __KERNEL_SYSCALLS__ | ||
| 428 | |||
| 429 | #include <linux/compiler.h> | ||
| 430 | #include <linux/types.h> | ||
| 431 | #include <linux/linkage.h> | ||
| 432 | #include <asm/ptrace.h> | ||
| 433 | |||
| 434 | /* | ||
| 435 | * we need this inline - forking from kernel space will result | ||
| 436 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 437 | * is no problem, but for the stack. This is handled by not letting | ||
| 438 | * main() use the stack at all after fork(). Thus, no function | ||
| 439 | * calls - which means inline code for fork too, as otherwise we | ||
| 440 | * would use the stack upon exit from 'fork()'. | ||
| 441 | * | ||
| 442 | * Actually only pause and fork are needed inline, so that there | ||
| 443 | * won't be any messing with the stack from main(), but we define | ||
| 444 | * some others too. | ||
| 445 | */ | ||
| 446 | static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 447 | |||
| 448 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
| 449 | unsigned long prot, unsigned long flags, | ||
| 450 | unsigned long fd, unsigned long pgoff); | ||
| 451 | asmlinkage int sys_execve(struct pt_regs regs); | ||
| 452 | asmlinkage int sys_clone(struct pt_regs regs); | ||
| 453 | asmlinkage int sys_fork(struct pt_regs regs); | ||
| 454 | asmlinkage int sys_vfork(struct pt_regs regs); | ||
| 455 | asmlinkage int sys_pipe(unsigned long __user *fildes); | ||
| 456 | struct sigaction; | ||
| 457 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 458 | const struct sigaction __user *act, | ||
| 459 | struct sigaction __user *oact, | ||
| 460 | size_t sigsetsize); | ||
| 461 | |||
| 462 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 463 | |||
| 464 | /* | 427 | /* |
| 465 | * "Conditional" syscalls | 428 | * "Conditional" syscalls |
| 466 | * | 429 | * |
diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h index 751632b904db..3ab716f0fc18 100644 --- a/include/asm-m68k/unistd.h +++ b/include/asm-m68k/unistd.h | |||
| @@ -409,12 +409,6 @@ __syscall_return(type,__res); \ | |||
| 409 | #define __ARCH_WANT_SYS_SIGPROCMASK | 409 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 410 | #define __ARCH_WANT_SYS_RT_SIGACTION | 410 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 411 | 411 | ||
| 412 | #ifdef __KERNEL_SYSCALLS__ | ||
| 413 | |||
| 414 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 415 | |||
| 416 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 417 | |||
| 418 | /* | 412 | /* |
| 419 | * "Conditional" syscalls | 413 | * "Conditional" syscalls |
| 420 | * | 414 | * |
diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h index 21fdc37c5c2c..daafb5d43ef1 100644 --- a/include/asm-m68knommu/unistd.h +++ b/include/asm-m68knommu/unistd.h | |||
| @@ -463,61 +463,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \ | |||
| 463 | #define __ARCH_WANT_SYS_SIGPROCMASK | 463 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 464 | #define __ARCH_WANT_SYS_RT_SIGACTION | 464 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 465 | 465 | ||
| 466 | #ifdef __KERNEL_SYSCALLS__ | ||
| 467 | |||
| 468 | #include <linux/compiler.h> | ||
| 469 | #include <linux/interrupt.h> | ||
| 470 | #include <linux/types.h> | ||
| 471 | |||
| 472 | /* | ||
| 473 | * we need this inline - forking from kernel space will result | ||
| 474 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 475 | * is no problem, but for the stack. This is handled by not letting | ||
| 476 | * main() use the stack at all after fork(). Thus, no function | ||
| 477 | * calls - which means inline code for fork too, as otherwise we | ||
| 478 | * would use the stack upon exit from 'fork()'. | ||
| 479 | * | ||
| 480 | * Actually only pause and fork are needed inline, so that there | ||
| 481 | * won't be any messing with the stack from main(), but we define | ||
| 482 | * some others too. | ||
| 483 | */ | ||
| 484 | #define __NR__exit __NR_exit | ||
| 485 | static inline _syscall0(int,pause) | ||
| 486 | static inline _syscall0(int,sync) | ||
| 487 | static inline _syscall0(pid_t,setsid) | ||
| 488 | static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 489 | static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 490 | static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 491 | static inline _syscall1(int,dup,int,fd) | ||
| 492 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 493 | static inline _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 494 | static inline _syscall1(int,close,int,fd) | ||
| 495 | static inline _syscall1(int,_exit,int,exitcode) | ||
| 496 | static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 497 | static inline _syscall1(int,delete_module,const char *,name) | ||
| 498 | |||
| 499 | static inline pid_t wait(int * wait_stat) | ||
| 500 | { | ||
| 501 | return waitpid(-1,wait_stat,0); | ||
| 502 | } | ||
| 503 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
| 504 | unsigned long prot, unsigned long flags, | ||
| 505 | unsigned long fd, unsigned long pgoff); | ||
| 506 | asmlinkage int sys_execve(char *name, char **argv, char **envp); | ||
| 507 | asmlinkage int sys_pipe(unsigned long *fildes); | ||
| 508 | struct pt_regs; | ||
| 509 | int sys_request_irq(unsigned int, | ||
| 510 | irqreturn_t (*)(int, void *, struct pt_regs *), | ||
| 511 | unsigned long, const char *, void *); | ||
| 512 | void sys_free_irq(unsigned int, void *); | ||
| 513 | struct sigaction; | ||
| 514 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 515 | const struct sigaction __user *act, | ||
| 516 | struct sigaction __user *oact, | ||
| 517 | size_t sigsetsize); | ||
| 518 | |||
| 519 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 520 | |||
| 521 | /* | 466 | /* |
| 522 | * "Conditional" syscalls | 467 | * "Conditional" syscalls |
| 523 | * | 468 | * |
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h index 36416fdfcf68..9ab59e2bb233 100644 --- a/include/asm-mips/cacheflush.h +++ b/include/asm-mips/cacheflush.h | |||
| @@ -46,8 +46,6 @@ static inline void flush_dcache_page(struct page *page) | |||
| 46 | #define flush_dcache_mmap_lock(mapping) do { } while (0) | 46 | #define flush_dcache_mmap_lock(mapping) do { } while (0) |
| 47 | #define flush_dcache_mmap_unlock(mapping) do { } while (0) | 47 | #define flush_dcache_mmap_unlock(mapping) do { } while (0) |
| 48 | 48 | ||
| 49 | extern void (*__flush_icache_page)(struct vm_area_struct *vma, | ||
| 50 | struct page *page); | ||
| 51 | static inline void flush_icache_page(struct vm_area_struct *vma, | 49 | static inline void flush_icache_page(struct vm_area_struct *vma, |
| 52 | struct page *page) | 50 | struct page *page) |
| 53 | { | 51 | { |
diff --git a/include/asm-mips/galileo-boards/ev96100.h b/include/asm-mips/galileo-boards/ev96100.h deleted file mode 100644 index 070dfd84a8e8..000000000000 --- a/include/asm-mips/galileo-boards/ev96100.h +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | */ | ||
| 4 | #ifndef _MIPS_EV96100_H | ||
| 5 | #define _MIPS_EV96100_H | ||
| 6 | |||
| 7 | #include <asm/addrspace.h> | ||
| 8 | |||
| 9 | /* | ||
| 10 | * GT64120 config space base address | ||
| 11 | */ | ||
| 12 | #define GT64120_BASE (KSEG1ADDR(0x14000000)) | ||
| 13 | #define MIPS_GT_BASE GT64120_BASE | ||
| 14 | |||
| 15 | /* | ||
| 16 | * PCI Bus allocation | ||
| 17 | */ | ||
| 18 | #define GT_PCI_MEM_BASE 0x12000000UL | ||
| 19 | #define GT_PCI_MEM_SIZE 0x02000000UL | ||
| 20 | #define GT_PCI_IO_BASE 0x10000000UL | ||
| 21 | #define GT_PCI_IO_SIZE 0x02000000UL | ||
| 22 | #define GT_ISA_IO_BASE PCI_IO_BASE | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Duart I/O ports. | ||
| 26 | */ | ||
| 27 | #define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20) | ||
| 28 | #define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00) | ||
| 29 | |||
| 30 | |||
| 31 | /* | ||
| 32 | * EV96100 interrupt controller register base. | ||
| 33 | */ | ||
| 34 | #define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000)) | ||
| 35 | |||
| 36 | /* | ||
| 37 | * EV96100 UART register base. | ||
| 38 | */ | ||
| 39 | #define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR | ||
| 40 | #define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR | ||
| 41 | #define EV96100_BASE_BAUD ( 3686400 / 16 ) | ||
| 42 | |||
| 43 | |||
| 44 | /* | ||
| 45 | * Because of an error/peculiarity in the Galileo chip, we need to swap the | ||
| 46 | * bytes when running bigendian. | ||
| 47 | */ | ||
| 48 | #define __GT_READ(ofs) \ | ||
| 49 | (*(volatile u32 *)(GT64120_BASE+(ofs))) | ||
| 50 | #define __GT_WRITE(ofs, data) \ | ||
| 51 | do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0) | ||
| 52 | #define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs)) | ||
| 53 | #define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data)) | ||
| 54 | |||
| 55 | #endif /* !(_MIPS_EV96100_H) */ | ||
diff --git a/include/asm-mips/galileo-boards/ev96100int.h b/include/asm-mips/galileo-boards/ev96100int.h deleted file mode 100644 index c58b16d06d6e..000000000000 --- a/include/asm-mips/galileo-boards/ev96100int.h +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | */ | ||
| 4 | #ifndef _MIPS_EV96100INT_H | ||
| 5 | #define _MIPS_EV96100INT_H | ||
| 6 | |||
| 7 | #define EV96100INT_UART_0 6 /* IP 6 */ | ||
| 8 | #define EV96100INT_TIMER 7 /* IP 7 */ | ||
| 9 | |||
| 10 | extern void ev96100int_init(void); | ||
| 11 | |||
| 12 | #endif /* !(_MIPS_EV96100_H) */ | ||
diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h index 43ca09a3a3d0..46bf5de5ac72 100644 --- a/include/asm-mips/irqflags.h +++ b/include/asm-mips/irqflags.h | |||
| @@ -213,12 +213,37 @@ static inline int raw_irqs_disabled_flags(unsigned long flags) | |||
| 213 | * Do the CPU's IRQ-state tracing from assembly code. | 213 | * Do the CPU's IRQ-state tracing from assembly code. |
| 214 | */ | 214 | */ |
| 215 | #ifdef CONFIG_TRACE_IRQFLAGS | 215 | #ifdef CONFIG_TRACE_IRQFLAGS |
| 216 | /* Reload some registers clobbered by trace_hardirqs_on */ | ||
| 217 | #ifdef CONFIG_64BIT | ||
| 218 | # define TRACE_IRQS_RELOAD_REGS \ | ||
| 219 | LONG_L $11, PT_R11(sp); \ | ||
| 220 | LONG_L $10, PT_R10(sp); \ | ||
| 221 | LONG_L $9, PT_R9(sp); \ | ||
| 222 | LONG_L $8, PT_R8(sp); \ | ||
| 223 | LONG_L $7, PT_R7(sp); \ | ||
| 224 | LONG_L $6, PT_R6(sp); \ | ||
| 225 | LONG_L $5, PT_R5(sp); \ | ||
| 226 | LONG_L $4, PT_R4(sp); \ | ||
| 227 | LONG_L $2, PT_R2(sp) | ||
| 228 | #else | ||
| 229 | # define TRACE_IRQS_RELOAD_REGS \ | ||
| 230 | LONG_L $7, PT_R7(sp); \ | ||
| 231 | LONG_L $6, PT_R6(sp); \ | ||
| 232 | LONG_L $5, PT_R5(sp); \ | ||
| 233 | LONG_L $4, PT_R4(sp); \ | ||
| 234 | LONG_L $2, PT_R2(sp) | ||
| 235 | #endif | ||
| 216 | # define TRACE_IRQS_ON \ | 236 | # define TRACE_IRQS_ON \ |
| 237 | CLI; /* make sure trace_hardirqs_on() is called in kernel level */ \ | ||
| 217 | jal trace_hardirqs_on | 238 | jal trace_hardirqs_on |
| 239 | # define TRACE_IRQS_ON_RELOAD \ | ||
| 240 | TRACE_IRQS_ON; \ | ||
| 241 | TRACE_IRQS_RELOAD_REGS | ||
| 218 | # define TRACE_IRQS_OFF \ | 242 | # define TRACE_IRQS_OFF \ |
| 219 | jal trace_hardirqs_off | 243 | jal trace_hardirqs_off |
| 220 | #else | 244 | #else |
| 221 | # define TRACE_IRQS_ON | 245 | # define TRACE_IRQS_ON |
| 246 | # define TRACE_IRQS_ON_RELOAD | ||
| 222 | # define TRACE_IRQS_OFF | 247 | # define TRACE_IRQS_OFF |
| 223 | #endif | 248 | #endif |
| 224 | 249 | ||
diff --git a/include/asm-mips/mach-ev64120/mach-gt64120.h b/include/asm-mips/mach-ev64120/mach-gt64120.h index 13b1443a7a65..7e272ce57ea3 100644 --- a/include/asm-mips/mach-ev64120/mach-gt64120.h +++ b/include/asm-mips/mach-ev64120/mach-gt64120.h | |||
| @@ -42,6 +42,7 @@ extern unsigned long gt64120_base; | |||
| 42 | #define EV64120_UART0_REGS_BASE (KSEG1ADDR(EV64120_COM1_BASE_ADDR)) | 42 | #define EV64120_UART0_REGS_BASE (KSEG1ADDR(EV64120_COM1_BASE_ADDR)) |
| 43 | #define EV64120_UART1_REGS_BASE (KSEG1ADDR(EV64120_COM2_BASE_ADDR)) | 43 | #define EV64120_UART1_REGS_BASE (KSEG1ADDR(EV64120_COM2_BASE_ADDR)) |
| 44 | #define EV64120_BASE_BAUD ( 3686400 / 16 ) | 44 | #define EV64120_BASE_BAUD ( 3686400 / 16 ) |
| 45 | #define EV64120_UART_IRQ 6 | ||
| 45 | 46 | ||
| 46 | /* | 47 | /* |
| 47 | * PCI interrupts will come in on either the INTA or INTD interrups lines, | 48 | * PCI interrupts will come in on either the INTA or INTD interrups lines, |
diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h index 035637c67e7c..c882e04e1497 100644 --- a/include/asm-mips/serial.h +++ b/include/asm-mips/serial.h | |||
| @@ -55,19 +55,18 @@ | |||
| 55 | * Galileo EV64120 evaluation board | 55 | * Galileo EV64120 evaluation board |
| 56 | */ | 56 | */ |
| 57 | #ifdef CONFIG_MIPS_EV64120 | 57 | #ifdef CONFIG_MIPS_EV64120 |
| 58 | #include <asm/galileo-boards/ev96100.h> | 58 | #include <mach-gt64120.h> |
| 59 | #include <asm/galileo-boards/ev96100int.h> | 59 | #define EV64120_SERIAL_PORT_DEFNS \ |
| 60 | #define EV96100_SERIAL_PORT_DEFNS \ | 60 | { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \ |
| 61 | { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \ | ||
| 62 | .flags = STD_COM_FLAGS, \ | 61 | .flags = STD_COM_FLAGS, \ |
| 63 | .iomem_base = EV96100_UART0_REGS_BASE, .iomem_reg_shift = 2, \ | 62 | .iomem_base = EV64120_UART0_REGS_BASE, .iomem_reg_shift = 2, \ |
| 64 | .io_type = SERIAL_IO_MEM }, \ | 63 | .io_type = SERIAL_IO_MEM }, \ |
| 65 | { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \ | 64 | { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \ |
| 66 | .flags = STD_COM_FLAGS, \ | 65 | .flags = STD_COM_FLAGS, \ |
| 67 | .iomem_base = EV96100_UART1_REGS_BASE, .iomem_reg_shift = 2, \ | 66 | .iomem_base = EV64120_UART1_REGS_BASE, .iomem_reg_shift = 2, \ |
| 68 | .io_type = SERIAL_IO_MEM }, | 67 | .io_type = SERIAL_IO_MEM }, |
| 69 | #else | 68 | #else |
| 70 | #define EV96100_SERIAL_PORT_DEFNS | 69 | #define EV64120_SERIAL_PORT_DEFNS |
| 71 | #endif | 70 | #endif |
| 72 | 71 | ||
| 73 | #ifdef CONFIG_MIPS_ITE8172 | 72 | #ifdef CONFIG_MIPS_ITE8172 |
| @@ -239,7 +238,7 @@ | |||
| 239 | 238 | ||
| 240 | #define SERIAL_PORT_DFNS \ | 239 | #define SERIAL_PORT_DFNS \ |
| 241 | DDB5477_SERIAL_PORT_DEFNS \ | 240 | DDB5477_SERIAL_PORT_DEFNS \ |
| 242 | EV96100_SERIAL_PORT_DEFNS \ | 241 | EV64120_SERIAL_PORT_DEFNS \ |
| 243 | IP32_SERIAL_PORT_DEFNS \ | 242 | IP32_SERIAL_PORT_DEFNS \ |
| 244 | ITE_SERIAL_PORT_DEFNS \ | 243 | ITE_SERIAL_PORT_DEFNS \ |
| 245 | IVR_SERIAL_PORT_DEFNS \ | 244 | IVR_SERIAL_PORT_DEFNS \ |
diff --git a/include/asm-mips/stacktrace.h b/include/asm-mips/stacktrace.h new file mode 100644 index 000000000000..07f873351a86 --- /dev/null +++ b/include/asm-mips/stacktrace.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | #ifndef _ASM_STACKTRACE_H | ||
| 2 | #define _ASM_STACKTRACE_H | ||
| 3 | |||
| 4 | #include <asm/ptrace.h> | ||
| 5 | |||
| 6 | #ifdef CONFIG_KALLSYMS | ||
| 7 | extern int raw_show_trace; | ||
| 8 | extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | ||
| 9 | unsigned long pc, unsigned long *ra); | ||
| 10 | #else | ||
| 11 | #define raw_show_trace 1 | ||
| 12 | #define unwind_stack(task, sp, pc, ra) 0 | ||
| 13 | #endif | ||
| 14 | |||
| 15 | static __always_inline void prepare_frametrace(struct pt_regs *regs) | ||
| 16 | { | ||
| 17 | #ifndef CONFIG_KALLSYMS | ||
| 18 | /* | ||
| 19 | * Remove any garbage that may be in regs (specially func | ||
| 20 | * addresses) to avoid show_raw_backtrace() to report them | ||
| 21 | */ | ||
| 22 | memset(regs, 0, sizeof(*regs)); | ||
| 23 | #endif | ||
| 24 | __asm__ __volatile__( | ||
| 25 | ".set push\n\t" | ||
| 26 | ".set noat\n\t" | ||
| 27 | #ifdef CONFIG_64BIT | ||
| 28 | "1: dla $1, 1b\n\t" | ||
| 29 | "sd $1, %0\n\t" | ||
| 30 | "sd $29, %1\n\t" | ||
| 31 | "sd $31, %2\n\t" | ||
| 32 | #else | ||
| 33 | "1: la $1, 1b\n\t" | ||
| 34 | "sw $1, %0\n\t" | ||
| 35 | "sw $29, %1\n\t" | ||
| 36 | "sw $31, %2\n\t" | ||
| 37 | #endif | ||
| 38 | ".set pop\n\t" | ||
| 39 | : "=m" (regs->cp0_epc), | ||
| 40 | "=m" (regs->regs[29]), "=m" (regs->regs[31]) | ||
| 41 | : : "memory"); | ||
| 42 | } | ||
| 43 | |||
| 44 | #endif /* _ASM_STACKTRACE_H */ | ||
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h index c39142920fe6..685c91467e63 100644 --- a/include/asm-mips/unistd.h +++ b/include/asm-mips/unistd.h | |||
| @@ -1212,45 +1212,6 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \ | |||
| 1212 | # define __ARCH_WANT_COMPAT_SYS_TIME | 1212 | # define __ARCH_WANT_COMPAT_SYS_TIME |
| 1213 | # endif | 1213 | # endif |
| 1214 | 1214 | ||
| 1215 | #ifdef __KERNEL_SYSCALLS__ | ||
| 1216 | |||
| 1217 | #include <linux/compiler.h> | ||
| 1218 | #include <linux/types.h> | ||
| 1219 | #include <linux/linkage.h> | ||
| 1220 | #include <asm/ptrace.h> | ||
| 1221 | #include <asm/sim.h> | ||
| 1222 | |||
| 1223 | /* | ||
| 1224 | * we need this inline - forking from kernel space will result | ||
| 1225 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 1226 | * is no problem, but for the stack. This is handled by not letting | ||
| 1227 | * main() use the stack at all after fork(). Thus, no function | ||
| 1228 | * calls - which means inline code for fork too, as otherwise we | ||
| 1229 | * would use the stack upon exit from 'fork()'. | ||
| 1230 | * | ||
| 1231 | * Actually only pause and fork are needed inline, so that there | ||
| 1232 | * won't be any messing with the stack from main(), but we define | ||
| 1233 | * some others too. | ||
| 1234 | */ | ||
| 1235 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 1236 | |||
| 1237 | asmlinkage unsigned long sys_mmap( | ||
| 1238 | unsigned long addr, size_t len, | ||
| 1239 | int prot, int flags, | ||
| 1240 | int fd, off_t offset); | ||
| 1241 | asmlinkage long sys_mmap2( | ||
| 1242 | unsigned long addr, unsigned long len, | ||
| 1243 | unsigned long prot, unsigned long flags, | ||
| 1244 | unsigned long fd, unsigned long pgoff); | ||
| 1245 | asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs); | ||
| 1246 | asmlinkage int sys_pipe(nabi_no_regargs struct pt_regs regs); | ||
| 1247 | struct sigaction; | ||
| 1248 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 1249 | const struct sigaction __user *act, | ||
| 1250 | struct sigaction __user *oact, | ||
| 1251 | size_t sigsetsize); | ||
| 1252 | |||
| 1253 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 1254 | #endif /* !__ASSEMBLY__ */ | 1215 | #endif /* !__ASSEMBLY__ */ |
| 1255 | 1216 | ||
| 1256 | /* | 1217 | /* |
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h index 27bcfad1c3e3..53b0f5d290e4 100644 --- a/include/asm-parisc/unistd.h +++ b/include/asm-parisc/unistd.h | |||
| @@ -952,92 +952,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ | |||
| 952 | #define __ARCH_WANT_SYS_SIGPROCMASK | 952 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 953 | #define __ARCH_WANT_SYS_RT_SIGACTION | 953 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 954 | 954 | ||
| 955 | /* mmap & mmap2 take 6 arguments */ | ||
| 956 | #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ | ||
| 957 | type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \ | ||
| 958 | { \ | ||
| 959 | return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6); \ | ||
| 960 | } | ||
| 961 | |||
| 962 | #ifdef __KERNEL_SYSCALLS__ | ||
| 963 | |||
| 964 | #include <asm/current.h> | ||
| 965 | #include <linux/compiler.h> | ||
| 966 | #include <linux/types.h> | ||
| 967 | #include <linux/syscalls.h> | ||
| 968 | |||
| 969 | static inline pid_t setsid(void) | ||
| 970 | { | ||
| 971 | return sys_setsid(); | ||
| 972 | } | ||
| 973 | |||
| 974 | static inline int write(int fd, const char *buf, off_t count) | ||
| 975 | { | ||
| 976 | return sys_write(fd, buf, count); | ||
| 977 | } | ||
| 978 | |||
| 979 | static inline int read(int fd, char *buf, off_t count) | ||
| 980 | { | ||
| 981 | return sys_read(fd, buf, count); | ||
| 982 | } | ||
| 983 | |||
| 984 | static inline off_t lseek(int fd, off_t offset, int count) | ||
| 985 | { | ||
| 986 | return sys_lseek(fd, offset, count); | ||
| 987 | } | ||
| 988 | |||
| 989 | static inline int dup(int fd) | ||
| 990 | { | ||
| 991 | return sys_dup(fd); | ||
| 992 | } | ||
| 993 | |||
| 994 | static inline int execve(char *filename, char * argv [], | ||
| 995 | char * envp[]) | ||
| 996 | { | ||
| 997 | extern int __execve(char *, char **, char **, struct task_struct *); | ||
| 998 | return __execve(filename, argv, envp, current); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | static inline int open(const char *file, int flag, int mode) | ||
| 1002 | { | ||
| 1003 | return sys_open(file, flag, mode); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | static inline int close(int fd) | ||
| 1007 | { | ||
| 1008 | return sys_close(fd); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | static inline void _exit(int exitcode) | ||
| 1012 | { | ||
| 1013 | sys_exit(exitcode); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | static inline pid_t waitpid(pid_t pid, int *wait_stat, int options) | ||
| 1017 | { | ||
| 1018 | return sys_wait4(pid, wait_stat, options, NULL); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, | ||
| 1022 | unsigned long prot, unsigned long flags, | ||
| 1023 | unsigned long fd, unsigned long offset); | ||
| 1024 | asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, | ||
| 1025 | unsigned long prot, unsigned long flags, | ||
| 1026 | unsigned long fd, unsigned long pgoff); | ||
| 1027 | struct pt_regs; | ||
| 1028 | asmlinkage int sys_execve(struct pt_regs *regs); | ||
| 1029 | int sys_clone(unsigned long clone_flags, unsigned long usp, | ||
| 1030 | struct pt_regs *regs); | ||
| 1031 | int sys_vfork(struct pt_regs *regs); | ||
| 1032 | int sys_pipe(int *fildes); | ||
| 1033 | struct sigaction; | ||
| 1034 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 1035 | const struct sigaction __user *act, | ||
| 1036 | struct sigaction __user *oact, | ||
| 1037 | size_t sigsetsize); | ||
| 1038 | |||
| 1039 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 1040 | |||
| 1041 | #endif /* __ASSEMBLY__ */ | 955 | #endif /* __ASSEMBLY__ */ |
| 1042 | 956 | ||
| 1043 | #undef STR | 957 | #undef STR |
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index 34e1f89a5fa0..2dafa376a63f 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h | |||
| @@ -44,6 +44,28 @@ typedef unsigned int kprobe_opcode_t; | |||
| 44 | #define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) | 44 | #define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000) |
| 45 | #define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) | 45 | #define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000) |
| 46 | 46 | ||
| 47 | /* | ||
| 48 | * 64bit powerpc uses function descriptors. | ||
| 49 | * Handle cases where: | ||
| 50 | * - User passes a <.symbol> or <module:.symbol> | ||
| 51 | * - User passes a <symbol> or <module:symbol> | ||
| 52 | * - User passes a non-existant symbol, kallsyms_lookup_name | ||
| 53 | * returns 0. Don't deref the NULL pointer in that case | ||
| 54 | */ | ||
| 55 | #define kprobe_lookup_name(name, addr) \ | ||
| 56 | { \ | ||
| 57 | addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \ | ||
| 58 | if (addr) { \ | ||
| 59 | char *colon; \ | ||
| 60 | if ((colon = strchr(name, ':')) != NULL) { \ | ||
| 61 | colon++; \ | ||
| 62 | if (*colon != '\0' && *colon != '.') \ | ||
| 63 | addr = *(kprobe_opcode_t **)addr; \ | ||
| 64 | } else if (name[0] != '.') \ | ||
| 65 | addr = *(kprobe_opcode_t **)addr; \ | ||
| 66 | } \ | ||
| 67 | } | ||
| 68 | |||
| 47 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) | 69 | #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry) |
| 48 | 70 | ||
| 49 | #define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ | 71 | #define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \ |
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h index 4435efe85d0e..4ad77a13f865 100644 --- a/include/asm-powerpc/ptrace.h +++ b/include/asm-powerpc/ptrace.h | |||
| @@ -73,6 +73,8 @@ struct pt_regs { | |||
| 73 | #ifndef __ASSEMBLY__ | 73 | #ifndef __ASSEMBLY__ |
| 74 | 74 | ||
| 75 | #define instruction_pointer(regs) ((regs)->nip) | 75 | #define instruction_pointer(regs) ((regs)->nip) |
| 76 | #define regs_return_value(regs) ((regs)->gpr[3]) | ||
| 77 | |||
| 76 | #ifdef CONFIG_SMP | 78 | #ifdef CONFIG_SMP |
| 77 | extern unsigned long profile_pc(struct pt_regs *regs); | 79 | extern unsigned long profile_pc(struct pt_regs *regs); |
| 78 | #else | 80 | #else |
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index eb66eae6616f..464a48cce7f5 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h | |||
| @@ -479,13 +479,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 | |||
| 479 | #endif | 479 | #endif |
| 480 | 480 | ||
| 481 | /* | 481 | /* |
| 482 | * System call prototypes. | ||
| 483 | */ | ||
| 484 | #ifdef __KERNEL_SYSCALLS__ | ||
| 485 | extern int execve(const char *file, char **argv, char **envp); | ||
| 486 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 487 | |||
| 488 | /* | ||
| 489 | * "Conditional" syscalls | 482 | * "Conditional" syscalls |
| 490 | * | 483 | * |
| 491 | * What we want is __attribute__((weak,alias("sys_ni_syscall"))), | 484 | * What we want is __attribute__((weak,alias("sys_ni_syscall"))), |
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 8d2bf65b0b64..7b768c5c68a8 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h | |||
| @@ -472,6 +472,7 @@ struct user_regs_struct | |||
| 472 | 472 | ||
| 473 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) | 473 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) |
| 474 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) | 474 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) |
| 475 | #define regs_return_value(regs)((regs)->gprs[2]) | ||
| 475 | #define profile_pc(regs) instruction_pointer(regs) | 476 | #define profile_pc(regs) instruction_pointer(regs) |
| 476 | extern void show_regs(struct pt_regs * regs); | 477 | extern void show_regs(struct pt_regs * regs); |
| 477 | #endif | 478 | #endif |
diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 0361ac5dcde3..0cccfd83c457 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h | |||
| @@ -523,57 +523,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ | |||
| 523 | # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | 523 | # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND |
| 524 | # endif | 524 | # endif |
| 525 | 525 | ||
| 526 | #ifdef __KERNEL_SYSCALLS__ | ||
| 527 | |||
| 528 | #include <linux/compiler.h> | ||
| 529 | #include <linux/types.h> | ||
| 530 | #include <asm/ptrace.h> | ||
| 531 | #include <asm/stat.h> | ||
| 532 | #include <linux/syscalls.h> | ||
| 533 | |||
| 534 | /* | ||
| 535 | * we need this inline - forking from kernel space will result | ||
| 536 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 537 | * is no problem, but for the stack. This is handled by not letting | ||
| 538 | * main() use the stack at all after fork(). Thus, no function | ||
| 539 | * calls - which means inline code for fork too, as otherwise we | ||
| 540 | * would use the stack upon exit from 'fork()'. | ||
| 541 | * | ||
| 542 | * Actually only pause and fork are needed inline, so that there | ||
| 543 | * won't be any messing with the stack from main(), but we define | ||
| 544 | * some others too. | ||
| 545 | */ | ||
| 546 | #define __NR__exit __NR_exit | ||
| 547 | static inline _syscall0(pid_t,setsid) | ||
| 548 | static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 549 | static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 550 | static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 551 | static inline _syscall1(int,dup,int,fd) | ||
| 552 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 553 | static inline _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 554 | static inline _syscall1(int,close,int,fd) | ||
| 555 | static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf) | ||
| 556 | |||
| 557 | static inline pid_t waitpid(int pid, int *wait_stat, int flags) | ||
| 558 | { | ||
| 559 | return sys_wait4(pid, wait_stat, flags, NULL); | ||
| 560 | } | ||
| 561 | struct mmap_arg_struct; | ||
| 562 | asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg); | ||
| 563 | |||
| 564 | asmlinkage long sys_execve(struct pt_regs regs); | ||
| 565 | asmlinkage long sys_clone(struct pt_regs regs); | ||
| 566 | asmlinkage long sys_fork(struct pt_regs regs); | ||
| 567 | asmlinkage long sys_vfork(struct pt_regs regs); | ||
| 568 | asmlinkage long sys_pipe(unsigned long __user *fildes); | ||
| 569 | struct sigaction; | ||
| 570 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 571 | const struct sigaction __user *act, | ||
| 572 | struct sigaction __user *oact, | ||
| 573 | size_t sigsetsize); | ||
| 574 | |||
| 575 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 576 | |||
| 577 | /* | 526 | /* |
| 578 | * "Conditional" syscalls | 527 | * "Conditional" syscalls |
| 579 | * | 528 | * |
diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h index b4000c8bf31b..beeea40f549e 100644 --- a/include/asm-sh/bugs.h +++ b/include/asm-sh/bugs.h | |||
| @@ -18,7 +18,7 @@ static void __init check_bugs(void) | |||
| 18 | { | 18 | { |
| 19 | extern char *get_cpu_subtype(void); | 19 | extern char *get_cpu_subtype(void); |
| 20 | extern unsigned long loops_per_jiffy; | 20 | extern unsigned long loops_per_jiffy; |
| 21 | char *p= &system_utsname.machine[2]; /* "sh" */ | 21 | char *p= &init_utsname()->machine[2]; /* "sh" */ |
| 22 | 22 | ||
| 23 | cpu_data->loops_per_jiffy = loops_per_jiffy; | 23 | cpu_data->loops_per_jiffy = loops_per_jiffy; |
| 24 | 24 | ||
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 5d5e9f94def5..f1a0cbc966be 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h | |||
| @@ -472,76 +472,6 @@ __syscall_return(type,__sc0); \ | |||
| 472 | #define __ARCH_WANT_SYS_RT_SIGACTION | 472 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 473 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 473 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
| 474 | 474 | ||
| 475 | #ifdef __KERNEL_SYSCALLS__ | ||
| 476 | |||
| 477 | #include <linux/compiler.h> | ||
| 478 | #include <linux/types.h> | ||
| 479 | #include <linux/linkage.h> | ||
| 480 | #include <asm/ptrace.h> | ||
| 481 | |||
| 482 | /* | ||
| 483 | * we need this inline - forking from kernel space will result | ||
| 484 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 485 | * is no problem, but for the stack. This is handled by not letting | ||
| 486 | * main() use the stack at all after fork(). Thus, no function | ||
| 487 | * calls - which means inline code for fork too, as otherwise we | ||
| 488 | * would use the stack upon exit from 'fork()'. | ||
| 489 | * | ||
| 490 | * Actually only pause and fork are needed inline, so that there | ||
| 491 | * won't be any messing with the stack from main(), but we define | ||
| 492 | * some others too. | ||
| 493 | */ | ||
| 494 | #define __NR__exit __NR_exit | ||
| 495 | static __inline__ _syscall0(int,pause) | ||
| 496 | static __inline__ _syscall0(int,sync) | ||
| 497 | static __inline__ _syscall0(pid_t,setsid) | ||
| 498 | static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 499 | static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 500 | static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 501 | static __inline__ _syscall1(int,dup,int,fd) | ||
| 502 | static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 503 | static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 504 | static __inline__ _syscall1(int,close,int,fd) | ||
| 505 | static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 506 | static __inline__ _syscall1(int,delete_module,const char *,name) | ||
| 507 | |||
| 508 | static __inline__ pid_t wait(int * wait_stat) | ||
| 509 | { | ||
| 510 | return waitpid(-1,wait_stat,0); | ||
| 511 | } | ||
| 512 | |||
| 513 | asmlinkage long sys_mmap2( | ||
| 514 | unsigned long addr, unsigned long len, | ||
| 515 | unsigned long prot, unsigned long flags, | ||
| 516 | unsigned long fd, unsigned long pgoff); | ||
| 517 | asmlinkage int sys_execve(char *ufilename, char **uargv, | ||
| 518 | char **uenvp, unsigned long r7, | ||
| 519 | struct pt_regs regs); | ||
| 520 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 521 | unsigned long parent_tidptr, | ||
| 522 | unsigned long child_tidptr, | ||
| 523 | struct pt_regs regs); | ||
| 524 | asmlinkage int sys_fork(unsigned long r4, unsigned long r5, | ||
| 525 | unsigned long r6, unsigned long r7, | ||
| 526 | struct pt_regs regs); | ||
| 527 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | ||
| 528 | unsigned long r6, unsigned long r7, | ||
| 529 | struct pt_regs regs); | ||
| 530 | asmlinkage int sys_pipe(unsigned long r4, unsigned long r5, | ||
| 531 | unsigned long r6, unsigned long r7, | ||
| 532 | struct pt_regs regs); | ||
| 533 | asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char *buf, | ||
| 534 | size_t count, long dummy, loff_t pos); | ||
| 535 | asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char *buf, | ||
| 536 | size_t count, long dummy, loff_t pos); | ||
| 537 | struct sigaction; | ||
| 538 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 539 | const struct sigaction __user *act, | ||
| 540 | struct sigaction __user *oact, | ||
| 541 | size_t sigsetsize); | ||
| 542 | |||
| 543 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 544 | |||
| 545 | /* | 475 | /* |
| 546 | * "Conditional" syscalls | 476 | * "Conditional" syscalls |
| 547 | * | 477 | * |
diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h index c113566bef33..ee7828b27ad1 100644 --- a/include/asm-sh64/unistd.h +++ b/include/asm-sh64/unistd.h | |||
| @@ -513,47 +513,6 @@ __syscall_return(type,__sc0); \ | |||
| 513 | #define __ARCH_WANT_SYS_SIGPROCMASK | 513 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 514 | #define __ARCH_WANT_SYS_RT_SIGACTION | 514 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 515 | 515 | ||
| 516 | #ifdef __KERNEL_SYSCALLS__ | ||
| 517 | |||
| 518 | /* Copy from sh */ | ||
| 519 | #include <linux/compiler.h> | ||
| 520 | #include <linux/types.h> | ||
| 521 | #include <asm/ptrace.h> | ||
| 522 | |||
| 523 | /* | ||
| 524 | * we need this inline - forking from kernel space will result | ||
| 525 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 526 | * is no problem, but for the stack. This is handled by not letting | ||
| 527 | * main() use the stack at all after fork(). Thus, no function | ||
| 528 | * calls - which means inline code for fork too, as otherwise we | ||
| 529 | * would use the stack upon exit from 'fork()'. | ||
| 530 | * | ||
| 531 | * Actually only pause and fork are needed inline, so that there | ||
| 532 | * won't be any messing with the stack from main(), but we define | ||
| 533 | * some others too. | ||
| 534 | */ | ||
| 535 | #define __NR__exit __NR_exit | ||
| 536 | static inline _syscall0(int,pause) | ||
| 537 | static inline _syscall1(int,setup,int,magic) | ||
| 538 | static inline _syscall0(int,sync) | ||
| 539 | static inline _syscall0(pid_t,setsid) | ||
| 540 | static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 541 | static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 542 | static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 543 | static inline _syscall1(int,dup,int,fd) | ||
| 544 | static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 545 | static inline _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 546 | static inline _syscall1(int,close,int,fd) | ||
| 547 | static inline _syscall1(int,_exit,int,exitcode) | ||
| 548 | static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 549 | static inline _syscall1(int,delete_module,const char *,name) | ||
| 550 | |||
| 551 | static inline pid_t wait(int * wait_stat) | ||
| 552 | { | ||
| 553 | return waitpid(-1,wait_stat,0); | ||
| 554 | } | ||
| 555 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 556 | |||
| 557 | /* | 516 | /* |
| 558 | * "Conditional" syscalls | 517 | * "Conditional" syscalls |
| 559 | * | 518 | * |
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 2553762465ca..c7a495afc82e 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h | |||
| @@ -478,53 +478,6 @@ return -1; \ | |||
| 478 | #define __ARCH_WANT_SYS_SIGPROCMASK | 478 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 479 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 479 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
| 480 | 480 | ||
| 481 | #ifdef __KERNEL_SYSCALLS__ | ||
| 482 | |||
| 483 | #include <linux/compiler.h> | ||
| 484 | #include <linux/types.h> | ||
| 485 | |||
| 486 | /* | ||
| 487 | * we need this inline - forking from kernel space will result | ||
| 488 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 489 | * is no problem, but for the stack. This is handled by not letting | ||
| 490 | * main() use the stack at all after fork(). Thus, no function | ||
| 491 | * calls - which means inline code for fork too, as otherwise we | ||
| 492 | * would use the stack upon exit from 'fork()'. | ||
| 493 | * | ||
| 494 | * Actually only pause and fork are needed inline, so that there | ||
| 495 | * won't be any messing with the stack from main(), but we define | ||
| 496 | * some others too. | ||
| 497 | */ | ||
| 498 | #define __NR__exit __NR_exit | ||
| 499 | static __inline__ _syscall0(pid_t,setsid) | ||
| 500 | static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count) | ||
| 501 | static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 502 | static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 503 | static __inline__ _syscall1(int,dup,int,fd) | ||
| 504 | static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp) | ||
| 505 | static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode) | ||
| 506 | static __inline__ _syscall1(int,close,int,fd) | ||
| 507 | static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 508 | |||
| 509 | #include <linux/linkage.h> | ||
| 510 | |||
| 511 | asmlinkage unsigned long sys_mmap( | ||
| 512 | unsigned long addr, unsigned long len, | ||
| 513 | unsigned long prot, unsigned long flags, | ||
| 514 | unsigned long fd, unsigned long off); | ||
| 515 | asmlinkage unsigned long sys_mmap2( | ||
| 516 | unsigned long addr, unsigned long len, | ||
| 517 | unsigned long prot, unsigned long flags, | ||
| 518 | unsigned long fd, unsigned long pgoff); | ||
| 519 | struct sigaction; | ||
| 520 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 521 | const struct sigaction __user *act, | ||
| 522 | struct sigaction __user *oact, | ||
| 523 | void __user *restorer, | ||
| 524 | size_t sigsetsize); | ||
| 525 | |||
| 526 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 527 | |||
| 528 | /* | 481 | /* |
| 529 | * "Conditional" syscalls | 482 | * "Conditional" syscalls |
| 530 | * | 483 | * |
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index badc73fdcb97..124cf076717f 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h | |||
| @@ -445,48 +445,6 @@ if (__res>=0) \ | |||
| 445 | errno = -__res; \ | 445 | errno = -__res; \ |
| 446 | return -1; \ | 446 | return -1; \ |
| 447 | } | 447 | } |
| 448 | #ifdef __KERNEL_SYSCALLS__ | ||
| 449 | |||
| 450 | #include <linux/compiler.h> | ||
| 451 | #include <linux/types.h> | ||
| 452 | |||
| 453 | /* | ||
| 454 | * we need this inline - forking from kernel space will result | ||
| 455 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 456 | * is no problem, but for the stack. This is handled by not letting | ||
| 457 | * main() use the stack at all after fork(). Thus, no function | ||
| 458 | * calls - which means inline code for fork too, as otherwise we | ||
| 459 | * would use the stack upon exit from 'fork()'. | ||
| 460 | * | ||
| 461 | * Actually only pause and fork are needed inline, so that there | ||
| 462 | * won't be any messing with the stack from main(), but we define | ||
| 463 | * some others too. | ||
| 464 | */ | ||
| 465 | #define __NR__exit __NR_exit | ||
| 466 | static __inline__ _syscall0(pid_t,setsid) | ||
| 467 | static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count) | ||
| 468 | static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 469 | static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 470 | static __inline__ _syscall1(int,dup,int,fd) | ||
| 471 | static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp) | ||
| 472 | static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode) | ||
| 473 | static __inline__ _syscall1(int,close,int,fd) | ||
| 474 | static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 475 | |||
| 476 | #include <linux/linkage.h> | ||
| 477 | |||
| 478 | asmlinkage unsigned long sys_mmap( | ||
| 479 | unsigned long addr, unsigned long len, | ||
| 480 | unsigned long prot, unsigned long flags, | ||
| 481 | unsigned long fd, unsigned long off); | ||
| 482 | struct sigaction; | ||
| 483 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 484 | const struct sigaction __user *act, | ||
| 485 | struct sigaction __user *oact, | ||
| 486 | void __user *restorer, | ||
| 487 | size_t sigsetsize); | ||
| 488 | |||
| 489 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 490 | 448 | ||
| 491 | /* sysconf options, for SunOS compatibility */ | 449 | /* sysconf options, for SunOS compatibility */ |
| 492 | #define _SC_ARG_MAX 1 | 450 | #define _SC_ARG_MAX 1 |
diff --git a/include/asm-um/unistd.h b/include/asm-um/unistd.h index afccfcaa9ea9..732c83f04c3d 100644 --- a/include/asm-um/unistd.h +++ b/include/asm-um/unistd.h | |||
| @@ -37,34 +37,6 @@ extern int um_execve(const char *file, char *const argv[], char *const env[]); | |||
| 37 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 37 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
| 38 | #endif | 38 | #endif |
| 39 | 39 | ||
| 40 | #ifdef __KERNEL_SYSCALLS__ | ||
| 41 | |||
| 42 | #include <linux/compiler.h> | ||
| 43 | #include <linux/types.h> | ||
| 44 | |||
| 45 | static inline int execve(const char *filename, char *const argv[], | ||
| 46 | char *const envp[]) | ||
| 47 | { | ||
| 48 | mm_segment_t fs; | ||
| 49 | int ret; | ||
| 50 | |||
| 51 | fs = get_fs(); | ||
| 52 | set_fs(KERNEL_DS); | ||
| 53 | ret = um_execve(filename, argv, envp); | ||
| 54 | set_fs(fs); | ||
| 55 | |||
| 56 | if (ret >= 0) | ||
| 57 | return ret; | ||
| 58 | |||
| 59 | errno = -(long)ret; | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | |||
| 63 | int sys_execve(char *file, char **argv, char **env); | ||
| 64 | |||
| 65 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 66 | |||
| 67 | #undef __KERNEL_SYSCALLS__ | ||
| 68 | #include "asm/arch/unistd.h" | 40 | #include "asm/arch/unistd.h" |
| 69 | 41 | ||
| 70 | #endif /* _UM_UNISTD_H_*/ | 42 | #endif /* _UM_UNISTD_H_*/ |
diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h index 552b7c873a57..737401e7d3ad 100644 --- a/include/asm-v850/unistd.h +++ b/include/asm-v850/unistd.h | |||
| @@ -387,57 +387,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ | |||
| 387 | #define __ARCH_WANT_SYS_SIGPROCMASK | 387 | #define __ARCH_WANT_SYS_SIGPROCMASK |
| 388 | #define __ARCH_WANT_SYS_RT_SIGACTION | 388 | #define __ARCH_WANT_SYS_RT_SIGACTION |
| 389 | 389 | ||
| 390 | #ifdef __KERNEL_SYSCALLS__ | ||
| 391 | |||
| 392 | #include <linux/compiler.h> | ||
| 393 | #include <linux/types.h> | ||
| 394 | |||
| 395 | /* | ||
| 396 | * we need this inline - forking from kernel space will result | ||
| 397 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 398 | * is no problem, but for the stack. This is handled by not letting | ||
| 399 | * main() use the stack at all after fork(). Thus, no function | ||
| 400 | * calls - which means inline code for fork too, as otherwise we | ||
| 401 | * would use the stack upon exit from 'fork()'. | ||
| 402 | * | ||
| 403 | * Actually only pause and fork are needed inline, so that there | ||
| 404 | * won't be any messing with the stack from main(), but we define | ||
| 405 | * some others too. | ||
| 406 | */ | ||
| 407 | #define __NR__exit __NR_exit | ||
| 408 | extern inline _syscall0(pid_t,setsid) | ||
| 409 | extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
| 410 | extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count) | ||
| 411 | extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) | ||
| 412 | extern inline _syscall1(int,dup,int,fd) | ||
| 413 | extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
| 414 | extern inline _syscall3(int,open,const char *,file,int,flag,int,mode) | ||
| 415 | extern inline _syscall1(int,close,int,fd) | ||
| 416 | extern inline _syscall1(int,_exit,int,exitcode) | ||
| 417 | extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
| 418 | |||
| 419 | extern inline pid_t wait(int * wait_stat) | ||
| 420 | { | ||
| 421 | return waitpid (-1, wait_stat, 0); | ||
| 422 | } | ||
| 423 | |||
| 424 | unsigned long sys_mmap(unsigned long addr, size_t len, | ||
| 425 | unsigned long prot, unsigned long flags, | ||
| 426 | unsigned long fd, off_t offset); | ||
| 427 | unsigned long sys_mmap2(unsigned long addr, size_t len, | ||
| 428 | unsigned long prot, unsigned long flags, | ||
| 429 | unsigned long fd, unsigned long pgoff); | ||
| 430 | struct pt_regs; | ||
| 431 | int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs); | ||
| 432 | int sys_pipe (int *fildes); | ||
| 433 | struct sigaction; | ||
| 434 | asmlinkage long sys_rt_sigaction(int sig, | ||
| 435 | const struct sigaction __user *act, | ||
| 436 | struct sigaction __user *oact, | ||
| 437 | size_t sigsetsize); | ||
| 438 | |||
| 439 | #endif /* __KERNEL_SYSCALLS__ */ | ||
| 440 | |||
| 441 | /* | 390 | /* |
| 442 | * "Conditional" syscalls | 391 | * "Conditional" syscalls |
| 443 | */ | 392 | */ |
diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h index ab827dc381d7..5ea84dbb1e9c 100644 --- a/include/asm-x86_64/ptrace.h +++ b/include/asm-x86_64/ptrace.h | |||
| @@ -39,6 +39,8 @@ struct pt_regs { | |||
| 39 | #define user_mode(regs) (!!((regs)->cs & 3)) | 39 | #define user_mode(regs) (!!((regs)->cs & 3)) |
| 40 | #define user_mode_vm(regs) user_mode(regs) | 40 | #define user_mode_vm(regs) user_mode(regs) |
| 41 | #define instruction_pointer(regs) ((regs)->rip) | 41 | #define instruction_pointer(regs) ((regs)->rip) |
| 42 | #define regs_return_value(regs) ((regs)->rax) | ||
| 43 | |||
| 42 | extern unsigned long profile_pc(struct pt_regs *regs); | 44 | extern unsigned long profile_pc(struct pt_regs *regs); |
| 43 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); | 45 | void signal_fault(struct pt_regs *regs, void __user *frame, char *where); |
| 44 | 46 | ||
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 6137146516d3..777288eb7e75 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h | |||
| @@ -620,10 +620,11 @@ __SYSCALL(__NR_vmsplice, sys_vmsplice) | |||
| 620 | #define __NR_move_pages 279 | 620 | #define __NR_move_pages 279 |
| 621 | __SYSCALL(__NR_move_pages, sys_move_pages) | 621 | __SYSCALL(__NR_move_pages, sys_move_pages) |
| 622 | 622 | ||
| 623 | #ifdef __KERNEL__ | ||
| 624 | |||
| 625 | #define __NR_syscall_max __NR_move_pages | 623 | #define __NR_syscall_max __NR_move_pages |
| 624 | |||
| 625 | #ifdef __KERNEL__ | ||
| 626 | #include <linux/err.h> | 626 | #include <linux/err.h> |
| 627 | #endif | ||
| 627 | 628 | ||
| 628 | #ifndef __NO_STUBS | 629 | #ifndef __NO_STUBS |
| 629 | 630 | ||
| @@ -663,8 +664,6 @@ do { \ | |||
| 663 | #define __ARCH_WANT_SYS_TIME | 664 | #define __ARCH_WANT_SYS_TIME |
| 664 | #define __ARCH_WANT_COMPAT_SYS_TIME | 665 | #define __ARCH_WANT_COMPAT_SYS_TIME |
| 665 | 666 | ||
| 666 | #ifndef __KERNEL_SYSCALLS__ | ||
| 667 | |||
| 668 | #define __syscall "syscall" | 667 | #define __syscall "syscall" |
| 669 | 668 | ||
| 670 | #define _syscall0(type,name) \ | 669 | #define _syscall0(type,name) \ |
| @@ -746,83 +745,7 @@ __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9 ; " __syscall \ | |||
| 746 | __syscall_return(type,__res); \ | 745 | __syscall_return(type,__res); \ |
| 747 | } | 746 | } |
| 748 | 747 | ||
| 749 | #else /* __KERNEL_SYSCALLS__ */ | 748 | #ifdef __KERNEL__ |
| 750 | |||
| 751 | #include <linux/syscalls.h> | ||
| 752 | #include <asm/ptrace.h> | ||
| 753 | |||
| 754 | /* | ||
| 755 | * we need this inline - forking from kernel space will result | ||
| 756 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
| 757 | * is no problem, but for the stack. This is handled by not letting | ||
| 758 | * main() use the stack at all after fork(). Thus, no function | ||
| 759 | * calls - which means inline code for fork too, as otherwise we | ||
| 760 | * would use the stack upon exit from 'fork()'. | ||
| 761 | * | ||
| 762 | * Actually only pause and fork are needed inline, so that there | ||
| 763 | * won't be any messing with the stack from main(), but we define | ||
| 764 | * some others too. | ||
| 765 | */ | ||
| 766 | #define __NR__exit __NR_exit | ||
| 767 | |||
| 768 | static inline pid_t setsid(void) | ||
| 769 | { | ||
| 770 | return sys_setsid(); | ||
| 771 | } | ||
| 772 | |||
| 773 | static inline ssize_t write(unsigned int fd, char * buf, size_t count) | ||
| 774 | { | ||
| 775 | return sys_write(fd, buf, count); | ||
| 776 | } | ||
| 777 | |||
| 778 | static inline ssize_t read(unsigned int fd, char * buf, size_t count) | ||
| 779 | { | ||
| 780 | return sys_read(fd, buf, count); | ||
| 781 | } | ||
| 782 | |||
| 783 | static inline off_t lseek(unsigned int fd, off_t offset, unsigned int origin) | ||
| 784 | { | ||
| 785 | return sys_lseek(fd, offset, origin); | ||
| 786 | } | ||
| 787 | |||
| 788 | static inline long dup(unsigned int fd) | ||
| 789 | { | ||
| 790 | return sys_dup(fd); | ||
| 791 | } | ||
| 792 | |||
| 793 | /* implemented in asm in arch/x86_64/kernel/entry.S */ | ||
| 794 | extern int execve(const char *, char * const *, char * const *); | ||
| 795 | |||
| 796 | static inline long open(const char * filename, int flags, int mode) | ||
| 797 | { | ||
| 798 | return sys_open(filename, flags, mode); | ||
| 799 | } | ||
| 800 | |||
| 801 | static inline long close(unsigned int fd) | ||
| 802 | { | ||
| 803 | return sys_close(fd); | ||
| 804 | } | ||
| 805 | |||
| 806 | static inline pid_t waitpid(int pid, int * wait_stat, int flags) | ||
| 807 | { | ||
| 808 | return sys_wait4(pid, wait_stat, flags, NULL); | ||
| 809 | } | ||
| 810 | |||
| 811 | extern long sys_mmap(unsigned long addr, unsigned long len, | ||
| 812 | unsigned long prot, unsigned long flags, | ||
| 813 | unsigned long fd, unsigned long off); | ||
| 814 | |||
| 815 | extern int sys_modify_ldt(int func, void *ptr, unsigned long bytecount); | ||
| 816 | |||
| 817 | asmlinkage long sys_execve(char *name, char **argv, char **envp, | ||
| 818 | struct pt_regs regs); | ||
| 819 | asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 820 | void *parent_tid, void *child_tid, | ||
| 821 | struct pt_regs regs); | ||
| 822 | asmlinkage long sys_fork(struct pt_regs regs); | ||
| 823 | asmlinkage long sys_vfork(struct pt_regs regs); | ||
| 824 | asmlinkage long sys_pipe(int *fildes); | ||
| 825 | |||
| 826 | #ifndef __ASSEMBLY__ | 749 | #ifndef __ASSEMBLY__ |
| 827 | 750 | ||
| 828 | #include <linux/linkage.h> | 751 | #include <linux/linkage.h> |
| @@ -839,8 +762,8 @@ asmlinkage long sys_rt_sigaction(int sig, | |||
| 839 | size_t sigsetsize); | 762 | size_t sigsetsize); |
| 840 | 763 | ||
| 841 | #endif /* __ASSEMBLY__ */ | 764 | #endif /* __ASSEMBLY__ */ |
| 842 | 765 | #endif /* __KERNEL__ */ | |
| 843 | #endif /* __KERNEL_SYSCALLS__ */ | 766 | #endif /* __NO_STUBS */ |
| 844 | 767 | ||
| 845 | /* | 768 | /* |
| 846 | * "Conditional" syscalls | 769 | * "Conditional" syscalls |
| @@ -850,8 +773,4 @@ asmlinkage long sys_rt_sigaction(int sig, | |||
| 850 | */ | 773 | */ |
| 851 | #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") | 774 | #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall") |
| 852 | 775 | ||
| 853 | #endif /* __NO_STUBS */ | ||
| 854 | |||
| 855 | #endif /* __KERNEL__ */ | ||
| 856 | |||
| 857 | #endif /* _ASM_X86_64_UNISTD_H_ */ | 776 | #endif /* _ASM_X86_64_UNISTD_H_ */ |
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h index 5e1b99dc4ab3..411f810a55c6 100644 --- a/include/asm-xtensa/unistd.h +++ b/include/asm-xtensa/unistd.h | |||
| @@ -402,11 +402,6 @@ __asm__ __volatile__ ( \ | |||
| 402 | __syscall_return(type,__res); \ | 402 | __syscall_return(type,__res); \ |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | |||
| 406 | #ifdef __KERNEL_SYSCALLS__ | ||
| 407 | static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp) | ||
| 408 | #endif | ||
| 409 | |||
| 410 | /* | 405 | /* |
| 411 | * "Conditional" syscalls | 406 | * "Conditional" syscalls |
| 412 | * | 407 | * |
diff --git a/include/linux/compat.h b/include/linux/compat.h index 9760753e662b..6f110957cc97 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <asm/compat.h> | 14 | #include <asm/compat.h> |
| 15 | #include <asm/siginfo.h> | 15 | #include <asm/siginfo.h> |
| 16 | #include <asm/signal.h> | ||
| 16 | 17 | ||
| 17 | #define compat_jiffies_to_clock_t(x) \ | 18 | #define compat_jiffies_to_clock_t(x) \ |
| 18 | (((unsigned long)(x) * COMPAT_USER_HZ) / HZ) | 19 | (((unsigned long)(x) * COMPAT_USER_HZ) / HZ) |
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 25423f79bf9f..ed6c0fee1ac7 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h | |||
| @@ -54,7 +54,7 @@ struct vc_data { | |||
| 54 | struct tty_struct *vc_tty; /* TTY we are attached to */ | 54 | struct tty_struct *vc_tty; /* TTY we are attached to */ |
| 55 | /* data for manual vt switching */ | 55 | /* data for manual vt switching */ |
| 56 | struct vt_mode vt_mode; | 56 | struct vt_mode vt_mode; |
| 57 | int vt_pid; | 57 | struct pid *vt_pid; |
| 58 | int vt_newvt; | 58 | int vt_newvt; |
| 59 | wait_queue_head_t paste_wait; | 59 | wait_queue_head_t paste_wait; |
| 60 | /* mode flags */ | 60 | /* mode flags */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 2e29a2edaeec..91c0b2a32a90 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -684,7 +684,8 @@ extern struct block_device *I_BDEV(struct inode *inode); | |||
| 684 | 684 | ||
| 685 | struct fown_struct { | 685 | struct fown_struct { |
| 686 | rwlock_t lock; /* protects pid, uid, euid fields */ | 686 | rwlock_t lock; /* protects pid, uid, euid fields */ |
| 687 | int pid; /* pid or -pgrp where SIGIO should be sent */ | 687 | struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ |
| 688 | enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ | ||
| 688 | uid_t uid, euid; /* uid/euid of process setting the owner */ | 689 | uid_t uid, euid; /* uid/euid of process setting the owner */ |
| 689 | int signum; /* posix.1b rt signal to be delivered on IO */ | 690 | int signum; /* posix.1b rt signal to be delivered on IO */ |
| 690 | }; | 691 | }; |
| @@ -880,8 +881,10 @@ extern void kill_fasync(struct fasync_struct **, int, int); | |||
| 880 | /* only for net: no internal synchronization */ | 881 | /* only for net: no internal synchronization */ |
| 881 | extern void __kill_fasync(struct fasync_struct *, int, int); | 882 | extern void __kill_fasync(struct fasync_struct *, int, int); |
| 882 | 883 | ||
| 884 | extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force); | ||
| 883 | extern int f_setown(struct file *filp, unsigned long arg, int force); | 885 | extern int f_setown(struct file *filp, unsigned long arg, int force); |
| 884 | extern void f_delown(struct file *filp); | 886 | extern void f_delown(struct file *filp); |
| 887 | extern pid_t f_getown(struct file *filp); | ||
| 885 | extern int send_sigurg(struct fown_struct *fown); | 888 | extern int send_sigurg(struct fown_struct *fown); |
| 886 | 889 | ||
| 887 | /* | 890 | /* |
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 690c42803d2e..9869ef3674ac 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h | |||
| @@ -31,5 +31,6 @@ struct gen_pool_chunk { | |||
| 31 | 31 | ||
| 32 | extern struct gen_pool *gen_pool_create(int, int); | 32 | extern struct gen_pool *gen_pool_create(int, int); |
| 33 | extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int); | 33 | extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int); |
| 34 | extern void gen_pool_destroy(struct gen_pool *); | ||
| 34 | extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); | 35 | extern unsigned long gen_pool_alloc(struct gen_pool *, size_t); |
| 35 | extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); | 36 | extern void gen_pool_free(struct gen_pool *, unsigned long, size_t); |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 60aac2cea0cf..33c5daacc743 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
| @@ -4,7 +4,9 @@ | |||
| 4 | #include <linux/file.h> | 4 | #include <linux/file.h> |
| 5 | #include <linux/rcupdate.h> | 5 | #include <linux/rcupdate.h> |
| 6 | #include <linux/irqflags.h> | 6 | #include <linux/irqflags.h> |
| 7 | #include <linux/utsname.h> | ||
| 7 | #include <linux/lockdep.h> | 8 | #include <linux/lockdep.h> |
| 9 | #include <linux/ipc.h> | ||
| 8 | 10 | ||
| 9 | #define INIT_FDTABLE \ | 11 | #define INIT_FDTABLE \ |
| 10 | { \ | 12 | { \ |
| @@ -68,6 +70,15 @@ | |||
| 68 | .session = 1, \ | 70 | .session = 1, \ |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 73 | extern struct nsproxy init_nsproxy; | ||
| 74 | #define INIT_NSPROXY(nsproxy) { \ | ||
| 75 | .count = ATOMIC_INIT(1), \ | ||
| 76 | .nslock = SPIN_LOCK_UNLOCKED, \ | ||
| 77 | .uts_ns = &init_uts_ns, \ | ||
| 78 | .namespace = NULL, \ | ||
| 79 | INIT_IPC_NS(ipc_ns) \ | ||
| 80 | } | ||
| 81 | |||
| 71 | #define INIT_SIGHAND(sighand) { \ | 82 | #define INIT_SIGHAND(sighand) { \ |
| 72 | .count = ATOMIC_INIT(1), \ | 83 | .count = ATOMIC_INIT(1), \ |
| 73 | .action = { { { .sa_handler = NULL, } }, }, \ | 84 | .action = { { { .sa_handler = NULL, } }, }, \ |
| @@ -117,6 +128,7 @@ extern struct group_info init_groups; | |||
| 117 | .files = &init_files, \ | 128 | .files = &init_files, \ |
| 118 | .signal = &init_signals, \ | 129 | .signal = &init_signals, \ |
| 119 | .sighand = &init_sighand, \ | 130 | .sighand = &init_sighand, \ |
| 131 | .nsproxy = &init_nsproxy, \ | ||
| 120 | .pending = { \ | 132 | .pending = { \ |
| 121 | .list = LIST_HEAD_INIT(tsk.pending.list), \ | 133 | .list = LIST_HEAD_INIT(tsk.pending.list), \ |
| 122 | .signal = {{0}}}, \ | 134 | .signal = {{0}}}, \ |
diff --git a/include/linux/input.h b/include/linux/input.h index b3253ab72ff7..5770105471dd 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
| @@ -349,6 +349,9 @@ struct input_absinfo { | |||
| 349 | 349 | ||
| 350 | #define KEY_BATTERY 236 | 350 | #define KEY_BATTERY 236 |
| 351 | 351 | ||
| 352 | #define KEY_BLUETOOTH 237 | ||
| 353 | #define KEY_WLAN 238 | ||
| 354 | |||
| 352 | #define KEY_UNKNOWN 240 | 355 | #define KEY_UNKNOWN 240 |
| 353 | 356 | ||
| 354 | #define BTN_MISC 0x100 | 357 | #define BTN_MISC 0x100 |
| @@ -645,6 +648,7 @@ struct input_absinfo { | |||
| 645 | #define BUS_USB 0x03 | 648 | #define BUS_USB 0x03 |
| 646 | #define BUS_HIL 0x04 | 649 | #define BUS_HIL 0x04 |
| 647 | #define BUS_BLUETOOTH 0x05 | 650 | #define BUS_BLUETOOTH 0x05 |
| 651 | #define BUS_VIRTUAL 0x06 | ||
| 648 | 652 | ||
| 649 | #define BUS_ISA 0x10 | 653 | #define BUS_ISA 0x10 |
| 650 | #define BUS_I8042 0x11 | 654 | #define BUS_I8042 0x11 |
| @@ -667,98 +671,167 @@ struct input_absinfo { | |||
| 667 | 671 | ||
| 668 | /* | 672 | /* |
| 669 | * Structures used in ioctls to upload effects to a device | 673 | * Structures used in ioctls to upload effects to a device |
| 670 | * The first structures are not passed directly by using ioctls. | 674 | * They are pieces of a bigger structure (called ff_effect) |
| 671 | * They are sub-structures of the actually sent structure (called ff_effect) | 675 | */ |
| 676 | |||
| 677 | /* | ||
| 678 | * All duration values are expressed in ms. Values above 32767 ms (0x7fff) | ||
| 679 | * should not be used and have unspecified results. | ||
| 672 | */ | 680 | */ |
| 673 | 681 | ||
| 682 | /** | ||
| 683 | * struct ff_replay - defines scheduling of the effect | ||
| 684 | * @length: duration of the effect | ||
| 685 | * @delay: delay before effect should start playing | ||
| 686 | */ | ||
| 674 | struct ff_replay { | 687 | struct ff_replay { |
| 675 | __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */ | 688 | __u16 length; |
| 676 | __u16 delay; /* Time to wait before to start playing an effect */ | 689 | __u16 delay; |
| 677 | }; | 690 | }; |
| 678 | 691 | ||
| 692 | /** | ||
| 693 | * struct ff_trigger - defines what triggers the effect | ||
| 694 | * @button: number of the button triggering the effect | ||
| 695 | * @interval: controls how soon the effect can be re-triggered | ||
| 696 | */ | ||
| 679 | struct ff_trigger { | 697 | struct ff_trigger { |
| 680 | __u16 button; /* Number of button triggering an effect */ | 698 | __u16 button; |
| 681 | __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ | 699 | __u16 interval; |
| 682 | }; | 700 | }; |
| 683 | 701 | ||
| 702 | /** | ||
| 703 | * struct ff_envelope - generic effect envelope | ||
| 704 | * @attack_length: duration of the attack (ms) | ||
| 705 | * @attack_level: level at the beginning of the attack | ||
| 706 | * @fade_length: duration of fade (ms) | ||
| 707 | * @fade_level: level at the end of fade | ||
| 708 | * | ||
| 709 | * The @attack_level and @fade_level are absolute values; when applying | ||
| 710 | * envelope force-feedback core will convert to positive/negative | ||
| 711 | * value based on polarity of the default level of the effect. | ||
| 712 | * Valid range for the attack and fade levels is 0x0000 - 0x7fff | ||
| 713 | */ | ||
| 684 | struct ff_envelope { | 714 | struct ff_envelope { |
| 685 | __u16 attack_length; /* Duration of attack (ms) */ | 715 | __u16 attack_length; |
| 686 | __u16 attack_level; /* Level at beginning of attack */ | 716 | __u16 attack_level; |
| 687 | __u16 fade_length; /* Duration of fade (ms) */ | 717 | __u16 fade_length; |
| 688 | __u16 fade_level; /* Level at end of fade */ | 718 | __u16 fade_level; |
| 689 | }; | 719 | }; |
| 690 | 720 | ||
| 691 | /* FF_CONSTANT */ | 721 | /** |
| 722 | * struct ff_constant_effect - defines parameters of a constant effect | ||
| 723 | * @level: strength of the effect; may be negative | ||
| 724 | * @envelope: envelope data | ||
| 725 | */ | ||
| 692 | struct ff_constant_effect { | 726 | struct ff_constant_effect { |
| 693 | __s16 level; /* Strength of effect. Negative values are OK */ | 727 | __s16 level; |
| 694 | struct ff_envelope envelope; | 728 | struct ff_envelope envelope; |
| 695 | }; | 729 | }; |
| 696 | 730 | ||
| 697 | /* FF_RAMP */ | 731 | /** |
| 732 | * struct ff_ramp_effect - defines parameters of a ramp effect | ||
| 733 | * @start_level: beginning strength of the effect; may be negative | ||
| 734 | * @end_level: final strength of the effect; may be negative | ||
| 735 | * @envelope: envelope data | ||
| 736 | */ | ||
| 698 | struct ff_ramp_effect { | 737 | struct ff_ramp_effect { |
| 699 | __s16 start_level; | 738 | __s16 start_level; |
| 700 | __s16 end_level; | 739 | __s16 end_level; |
| 701 | struct ff_envelope envelope; | 740 | struct ff_envelope envelope; |
| 702 | }; | 741 | }; |
| 703 | 742 | ||
| 704 | /* FF_SPRING of FF_FRICTION */ | 743 | /** |
| 744 | * struct ff_condition_effect - defines a spring or friction effect | ||
| 745 | * @right_saturation: maximum level when joystick moved all way to the right | ||
| 746 | * @left_saturation: same for the left side | ||
| 747 | * @right_coeff: controls how fast the force grows when the joystick moves | ||
| 748 | * to the right | ||
| 749 | * @left_coeff: same for the left side | ||
| 750 | * @deadband: size of the dead zone, where no force is produced | ||
| 751 | * @center: position of the dead zone | ||
| 752 | */ | ||
| 705 | struct ff_condition_effect { | 753 | struct ff_condition_effect { |
| 706 | __u16 right_saturation; /* Max level when joystick is on the right */ | 754 | __u16 right_saturation; |
| 707 | __u16 left_saturation; /* Max level when joystick in on the left */ | 755 | __u16 left_saturation; |
| 708 | |||
| 709 | __s16 right_coeff; /* Indicates how fast the force grows when the | ||
| 710 | joystick moves to the right */ | ||
| 711 | __s16 left_coeff; /* Same for left side */ | ||
| 712 | 756 | ||
| 713 | __u16 deadband; /* Size of area where no force is produced */ | 757 | __s16 right_coeff; |
| 714 | __s16 center; /* Position of dead zone */ | 758 | __s16 left_coeff; |
| 715 | 759 | ||
| 760 | __u16 deadband; | ||
| 761 | __s16 center; | ||
| 716 | }; | 762 | }; |
| 717 | 763 | ||
| 718 | /* FF_PERIODIC */ | 764 | /** |
| 765 | * struct ff_periodic_effect - defines parameters of a periodic effect | ||
| 766 | * @waveform: kind of the effect (wave) | ||
| 767 | * @period: period of the wave (ms) | ||
| 768 | * @magnitude: peak value | ||
| 769 | * @offset: mean value of the wave (roughly) | ||
| 770 | * @phase: 'horizontal' shift | ||
| 771 | * @envelope: envelope data | ||
| 772 | * @custom_len: number of samples (FF_CUSTOM only) | ||
| 773 | * @custom_data: buffer of samples (FF_CUSTOM only) | ||
| 774 | * | ||
| 775 | * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, | ||
| 776 | * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined | ||
| 777 | * for the time being as no driver supports it yet. | ||
| 778 | * | ||
| 779 | * Note: the data pointed by custom_data is copied by the driver. | ||
| 780 | * You can therefore dispose of the memory after the upload/update. | ||
| 781 | */ | ||
| 719 | struct ff_periodic_effect { | 782 | struct ff_periodic_effect { |
| 720 | __u16 waveform; /* Kind of wave (sine, square...) */ | 783 | __u16 waveform; |
| 721 | __u16 period; /* in ms */ | 784 | __u16 period; |
| 722 | __s16 magnitude; /* Peak value */ | 785 | __s16 magnitude; |
| 723 | __s16 offset; /* Mean value of wave (roughly) */ | 786 | __s16 offset; |
| 724 | __u16 phase; /* 'Horizontal' shift */ | 787 | __u16 phase; |
| 725 | 788 | ||
| 726 | struct ff_envelope envelope; | 789 | struct ff_envelope envelope; |
| 727 | 790 | ||
| 728 | /* Only used if waveform == FF_CUSTOM */ | 791 | __u32 custom_len; |
| 729 | __u32 custom_len; /* Number of samples */ | 792 | __s16 *custom_data; |
| 730 | __s16 *custom_data; /* Buffer of samples */ | ||
| 731 | /* Note: the data pointed by custom_data is copied by the driver. You can | ||
| 732 | * therefore dispose of the memory after the upload/update */ | ||
| 733 | }; | 793 | }; |
| 734 | 794 | ||
| 735 | /* FF_RUMBLE */ | 795 | /** |
| 736 | /* Some rumble pads have two motors of different weight. | 796 | * struct ff_rumble_effect - defines parameters of a periodic effect |
| 737 | strong_magnitude represents the magnitude of the vibration generated | 797 | * @strong_magnitude: magnitude of the heavy motor |
| 738 | by the heavy motor. | 798 | * @weak_magnitude: magnitude of the light one |
| 739 | */ | 799 | * |
| 800 | * Some rumble pads have two motors of different weight. Strong_magnitude | ||
| 801 | * represents the magnitude of the vibration generated by the heavy one. | ||
| 802 | */ | ||
| 740 | struct ff_rumble_effect { | 803 | struct ff_rumble_effect { |
| 741 | __u16 strong_magnitude; /* Magnitude of the heavy motor */ | 804 | __u16 strong_magnitude; |
| 742 | __u16 weak_magnitude; /* Magnitude of the light one */ | 805 | __u16 weak_magnitude; |
| 743 | }; | 806 | }; |
| 744 | 807 | ||
| 745 | /* | 808 | /** |
| 746 | * Structure sent through ioctl from the application to the driver | 809 | * struct ff_effect - defines force feedback effect |
| 810 | * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, | ||
| 811 | * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) | ||
| 812 | * @id: an unique id assigned to an effect | ||
| 813 | * @direction: direction of the effect | ||
| 814 | * @trigger: trigger conditions (struct ff_trigger) | ||
| 815 | * @replay: scheduling of the effect (struct ff_replay) | ||
| 816 | * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, | ||
| 817 | * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further | ||
| 818 | * defining effect parameters | ||
| 819 | * | ||
| 820 | * This structure is sent through ioctl from the application to the driver. | ||
| 821 | * To create a new effect aplication should set its @id to -1; the kernel | ||
| 822 | * will return assigned @id which can later be used to update or delete | ||
| 823 | * this effect. | ||
| 824 | * | ||
| 825 | * Direction of the effect is encoded as follows: | ||
| 826 | * 0 deg -> 0x0000 (down) | ||
| 827 | * 90 deg -> 0x4000 (left) | ||
| 828 | * 180 deg -> 0x8000 (up) | ||
| 829 | * 270 deg -> 0xC000 (right) | ||
| 747 | */ | 830 | */ |
| 748 | struct ff_effect { | 831 | struct ff_effect { |
| 749 | __u16 type; | 832 | __u16 type; |
| 750 | /* Following field denotes the unique id assigned to an effect. | ||
| 751 | * If user sets if to -1, a new effect is created, and its id is returned in the same field | ||
| 752 | * Else, the user sets it to the effect id it wants to update. | ||
| 753 | */ | ||
| 754 | __s16 id; | 833 | __s16 id; |
| 755 | 834 | __u16 direction; | |
| 756 | __u16 direction; /* Direction. 0 deg -> 0x0000 (down) | ||
| 757 | 90 deg -> 0x4000 (left) | ||
| 758 | 180 deg -> 0x8000 (up) | ||
| 759 | 270 deg -> 0xC000 (right) | ||
| 760 | */ | ||
| 761 | |||
| 762 | struct ff_trigger trigger; | 835 | struct ff_trigger trigger; |
| 763 | struct ff_replay replay; | 836 | struct ff_replay replay; |
| 764 | 837 | ||
| @@ -784,6 +857,9 @@ struct ff_effect { | |||
| 784 | #define FF_INERTIA 0x56 | 857 | #define FF_INERTIA 0x56 |
| 785 | #define FF_RAMP 0x57 | 858 | #define FF_RAMP 0x57 |
| 786 | 859 | ||
| 860 | #define FF_EFFECT_MIN FF_RUMBLE | ||
| 861 | #define FF_EFFECT_MAX FF_RAMP | ||
| 862 | |||
| 787 | /* | 863 | /* |
| 788 | * Force feedback periodic effect types | 864 | * Force feedback periodic effect types |
| 789 | */ | 865 | */ |
| @@ -795,6 +871,9 @@ struct ff_effect { | |||
| 795 | #define FF_SAW_DOWN 0x5c | 871 | #define FF_SAW_DOWN 0x5c |
| 796 | #define FF_CUSTOM 0x5d | 872 | #define FF_CUSTOM 0x5d |
| 797 | 873 | ||
| 874 | #define FF_WAVEFORM_MIN FF_SQUARE | ||
| 875 | #define FF_WAVEFORM_MAX FF_CUSTOM | ||
| 876 | |||
| 798 | /* | 877 | /* |
| 799 | * Set ff device properties | 878 | * Set ff device properties |
| 800 | */ | 879 | */ |
| @@ -864,12 +943,13 @@ struct input_dev { | |||
| 864 | unsigned long sndbit[NBITS(SND_MAX)]; | 943 | unsigned long sndbit[NBITS(SND_MAX)]; |
| 865 | unsigned long ffbit[NBITS(FF_MAX)]; | 944 | unsigned long ffbit[NBITS(FF_MAX)]; |
| 866 | unsigned long swbit[NBITS(SW_MAX)]; | 945 | unsigned long swbit[NBITS(SW_MAX)]; |
| 867 | int ff_effects_max; | ||
| 868 | 946 | ||
| 869 | unsigned int keycodemax; | 947 | unsigned int keycodemax; |
| 870 | unsigned int keycodesize; | 948 | unsigned int keycodesize; |
| 871 | void *keycode; | 949 | void *keycode; |
| 872 | 950 | ||
| 951 | struct ff_device *ff; | ||
| 952 | |||
| 873 | unsigned int repeat_key; | 953 | unsigned int repeat_key; |
| 874 | struct timer_list timer; | 954 | struct timer_list timer; |
| 875 | 955 | ||
| @@ -895,8 +975,6 @@ struct input_dev { | |||
| 895 | void (*close)(struct input_dev *dev); | 975 | void (*close)(struct input_dev *dev); |
| 896 | int (*flush)(struct input_dev *dev, struct file *file); | 976 | int (*flush)(struct input_dev *dev, struct file *file); |
| 897 | int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); | 977 | int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); |
| 898 | int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); | ||
| 899 | int (*erase_effect)(struct input_dev *dev, int effect_id); | ||
| 900 | 978 | ||
| 901 | struct input_handle *grab; | 979 | struct input_handle *grab; |
| 902 | 980 | ||
| @@ -904,9 +982,6 @@ struct input_dev { | |||
| 904 | unsigned int users; | 982 | unsigned int users; |
| 905 | 983 | ||
| 906 | struct class_device cdev; | 984 | struct class_device cdev; |
| 907 | struct device *dev; /* will be removed soon */ | ||
| 908 | |||
| 909 | int dynalloc; /* temporarily */ | ||
| 910 | 985 | ||
| 911 | struct list_head h_list; | 986 | struct list_head h_list; |
| 912 | struct list_head node; | 987 | struct list_head node; |
| @@ -985,16 +1060,16 @@ struct input_handler { | |||
| 985 | void *private; | 1060 | void *private; |
| 986 | 1061 | ||
| 987 | void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); | 1062 | void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); |
| 988 | struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); | 1063 | struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); |
| 989 | void (*disconnect)(struct input_handle *handle); | 1064 | void (*disconnect)(struct input_handle *handle); |
| 990 | void (*start)(struct input_handle *handle); | 1065 | void (*start)(struct input_handle *handle); |
| 991 | 1066 | ||
| 992 | const struct file_operations *fops; | 1067 | const struct file_operations *fops; |
| 993 | int minor; | 1068 | int minor; |
| 994 | char *name; | 1069 | const char *name; |
| 995 | 1070 | ||
| 996 | struct input_device_id *id_table; | 1071 | const struct input_device_id *id_table; |
| 997 | struct input_device_id *blacklist; | 1072 | const struct input_device_id *blacklist; |
| 998 | 1073 | ||
| 999 | struct list_head h_list; | 1074 | struct list_head h_list; |
| 1000 | struct list_head node; | 1075 | struct list_head node; |
| @@ -1005,7 +1080,7 @@ struct input_handle { | |||
| 1005 | void *private; | 1080 | void *private; |
| 1006 | 1081 | ||
| 1007 | int open; | 1082 | int open; |
| 1008 | char *name; | 1083 | const char *name; |
| 1009 | 1084 | ||
| 1010 | struct input_dev *dev; | 1085 | struct input_dev *dev; |
| 1011 | struct input_handler *handler; | 1086 | struct input_handler *handler; |
| @@ -1019,12 +1094,6 @@ struct input_handle { | |||
| 1019 | #define to_handle(n) container_of(n,struct input_handle,d_node) | 1094 | #define to_handle(n) container_of(n,struct input_handle,d_node) |
| 1020 | #define to_handle_h(n) container_of(n,struct input_handle,h_node) | 1095 | #define to_handle_h(n) container_of(n,struct input_handle,h_node) |
| 1021 | 1096 | ||
| 1022 | static inline void init_input_dev(struct input_dev *dev) | ||
| 1023 | { | ||
| 1024 | INIT_LIST_HEAD(&dev->h_list); | ||
| 1025 | INIT_LIST_HEAD(&dev->node); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | struct input_dev *input_allocate_device(void); | 1097 | struct input_dev *input_allocate_device(void); |
| 1029 | void input_free_device(struct input_dev *dev); | 1098 | void input_free_device(struct input_dev *dev); |
| 1030 | 1099 | ||
| @@ -1041,7 +1110,7 @@ static inline void input_put_device(struct input_dev *dev) | |||
| 1041 | int input_register_device(struct input_dev *); | 1110 | int input_register_device(struct input_dev *); |
| 1042 | void input_unregister_device(struct input_dev *); | 1111 | void input_unregister_device(struct input_dev *); |
| 1043 | 1112 | ||
| 1044 | void input_register_handler(struct input_handler *); | 1113 | int input_register_handler(struct input_handler *); |
| 1045 | void input_unregister_handler(struct input_handler *); | 1114 | void input_unregister_handler(struct input_handler *); |
| 1046 | 1115 | ||
| 1047 | int input_grab_device(struct input_handle *); | 1116 | int input_grab_device(struct input_handle *); |
| @@ -1070,11 +1139,6 @@ static inline void input_report_abs(struct input_dev *dev, unsigned int code, in | |||
| 1070 | input_event(dev, EV_ABS, code, value); | 1139 | input_event(dev, EV_ABS, code, value); |
| 1071 | } | 1140 | } |
| 1072 | 1141 | ||
| 1073 | static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value) | ||
| 1074 | { | ||
| 1075 | input_event(dev, EV_FF, code, value); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) | 1142 | static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) |
| 1079 | { | 1143 | { |
| 1080 | input_event(dev, EV_FF_STATUS, code, value); | 1144 | input_event(dev, EV_FF_STATUS, code, value); |
| @@ -1108,5 +1172,61 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min | |||
| 1108 | 1172 | ||
| 1109 | extern struct class input_class; | 1173 | extern struct class input_class; |
| 1110 | 1174 | ||
| 1175 | /** | ||
| 1176 | * struct ff_device - force-feedback part of an input device | ||
| 1177 | * @upload: Called to upload an new effect into device | ||
| 1178 | * @erase: Called to erase an effect from device | ||
| 1179 | * @playback: Called to request device to start playing specified effect | ||
| 1180 | * @set_gain: Called to set specified gain | ||
| 1181 | * @set_autocenter: Called to auto-center device | ||
| 1182 | * @destroy: called by input core when parent input device is being | ||
| 1183 | * destroyed | ||
| 1184 | * @private: driver-specific data, will be freed automatically | ||
| 1185 | * @ffbit: bitmap of force feedback capabilities truly supported by | ||
| 1186 | * device (not emulated like ones in input_dev->ffbit) | ||
| 1187 | * @mutex: mutex for serializing access to the device | ||
| 1188 | * @max_effects: maximum number of effects supported by device | ||
| 1189 | * @effects: pointer to an array of effects currently loaded into device | ||
| 1190 | * @effect_owners: array of effect owners; when file handle owning | ||
| 1191 | * an effect gets closed the effcet is automatically erased | ||
| 1192 | * | ||
| 1193 | * Every force-feedback device must implement upload() and playback() | ||
| 1194 | * methods; erase() is optional. set_gain() and set_autocenter() need | ||
| 1195 | * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER | ||
| 1196 | * bits. | ||
| 1197 | */ | ||
| 1198 | struct ff_device { | ||
| 1199 | int (*upload)(struct input_dev *dev, struct ff_effect *effect, | ||
| 1200 | struct ff_effect *old); | ||
| 1201 | int (*erase)(struct input_dev *dev, int effect_id); | ||
| 1202 | |||
| 1203 | int (*playback)(struct input_dev *dev, int effect_id, int value); | ||
| 1204 | void (*set_gain)(struct input_dev *dev, u16 gain); | ||
| 1205 | void (*set_autocenter)(struct input_dev *dev, u16 magnitude); | ||
| 1206 | |||
| 1207 | void (*destroy)(struct ff_device *); | ||
| 1208 | |||
| 1209 | void *private; | ||
| 1210 | |||
| 1211 | unsigned long ffbit[NBITS(FF_MAX)]; | ||
| 1212 | |||
| 1213 | struct mutex mutex; | ||
| 1214 | |||
| 1215 | int max_effects; | ||
| 1216 | struct ff_effect *effects; | ||
| 1217 | struct file *effect_owners[]; | ||
| 1218 | }; | ||
| 1219 | |||
| 1220 | int input_ff_create(struct input_dev *dev, int max_effects); | ||
| 1221 | void input_ff_destroy(struct input_dev *dev); | ||
| 1222 | |||
| 1223 | int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); | ||
| 1224 | |||
| 1225 | int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file); | ||
| 1226 | int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); | ||
| 1227 | |||
| 1228 | int input_ff_create_memless(struct input_dev *dev, void *data, | ||
| 1229 | int (*play_effect)(struct input_dev *, void *, struct ff_effect *)); | ||
| 1230 | |||
| 1111 | #endif | 1231 | #endif |
| 1112 | #endif | 1232 | #endif |
diff --git a/include/linux/ipc.h b/include/linux/ipc.h index b291189737e7..d9e2b3f36c35 100644 --- a/include/linux/ipc.h +++ b/include/linux/ipc.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define _LINUX_IPC_H | 2 | #define _LINUX_IPC_H |
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | #include <linux/kref.h> | ||
| 5 | 6 | ||
| 6 | #define IPC_PRIVATE ((__kernel_key_t) 0) | 7 | #define IPC_PRIVATE ((__kernel_key_t) 0) |
| 7 | 8 | ||
| @@ -68,6 +69,59 @@ struct kern_ipc_perm | |||
| 68 | void *security; | 69 | void *security; |
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 72 | struct ipc_ids; | ||
| 73 | struct ipc_namespace { | ||
| 74 | struct kref kref; | ||
| 75 | struct ipc_ids *ids[3]; | ||
| 76 | |||
| 77 | int sem_ctls[4]; | ||
| 78 | int used_sems; | ||
| 79 | |||
| 80 | int msg_ctlmax; | ||
| 81 | int msg_ctlmnb; | ||
| 82 | int msg_ctlmni; | ||
| 83 | |||
| 84 | size_t shm_ctlmax; | ||
| 85 | size_t shm_ctlall; | ||
| 86 | int shm_ctlmni; | ||
| 87 | int shm_tot; | ||
| 88 | }; | ||
| 89 | |||
| 90 | extern struct ipc_namespace init_ipc_ns; | ||
| 91 | |||
| 92 | #ifdef CONFIG_SYSVIPC | ||
| 93 | #define INIT_IPC_NS(ns) .ns = &init_ipc_ns, | ||
| 94 | #else | ||
| 95 | #define INIT_IPC_NS(ns) | ||
| 96 | #endif | ||
| 97 | |||
| 98 | #ifdef CONFIG_IPC_NS | ||
| 99 | extern void free_ipc_ns(struct kref *kref); | ||
| 100 | extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); | ||
| 101 | extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); | ||
| 102 | #else | ||
| 103 | static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk) | ||
| 104 | { | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | #endif | ||
| 108 | |||
| 109 | static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) | ||
| 110 | { | ||
| 111 | #ifdef CONFIG_IPC_NS | ||
| 112 | if (ns) | ||
| 113 | kref_get(&ns->kref); | ||
| 114 | #endif | ||
| 115 | return ns; | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline void put_ipc_ns(struct ipc_namespace *ns) | ||
| 119 | { | ||
| 120 | #ifdef CONFIG_IPC_NS | ||
| 121 | kref_put(&ns->kref, free_ipc_ns); | ||
| 122 | #endif | ||
| 123 | } | ||
| 124 | |||
| 71 | #endif /* __KERNEL__ */ | 125 | #endif /* __KERNEL__ */ |
| 72 | 126 | ||
| 73 | #endif /* _LINUX_IPC_H */ | 127 | #endif /* _LINUX_IPC_H */ |
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 8bf6702da2a0..ac4c0559f751 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
| @@ -77,6 +77,12 @@ struct kprobe { | |||
| 77 | /* location of the probe point */ | 77 | /* location of the probe point */ |
| 78 | kprobe_opcode_t *addr; | 78 | kprobe_opcode_t *addr; |
| 79 | 79 | ||
| 80 | /* Allow user to indicate symbol name of the probe point */ | ||
| 81 | char *symbol_name; | ||
| 82 | |||
| 83 | /* Offset into the symbol */ | ||
| 84 | unsigned int offset; | ||
| 85 | |||
| 80 | /* Called before addr is executed. */ | 86 | /* Called before addr is executed. */ |
| 81 | kprobe_pre_handler_t pre_handler; | 87 | kprobe_pre_handler_t pre_handler; |
| 82 | 88 | ||
| @@ -196,7 +202,7 @@ void unregister_kretprobe(struct kretprobe *rp); | |||
| 196 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp); | 202 | struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp); |
| 197 | void add_rp_inst(struct kretprobe_instance *ri); | 203 | void add_rp_inst(struct kretprobe_instance *ri); |
| 198 | void kprobe_flush_task(struct task_struct *tk); | 204 | void kprobe_flush_task(struct task_struct *tk); |
| 199 | void recycle_rp_inst(struct kretprobe_instance *ri); | 205 | void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); |
| 200 | #else /* CONFIG_KPROBES */ | 206 | #else /* CONFIG_KPROBES */ |
| 201 | 207 | ||
| 202 | #define __kprobes /**/ | 208 | #define __kprobes /**/ |
diff --git a/include/linux/libps2.h b/include/linux/libps2.h index 08a450a9dbf7..f6f301e2b0f5 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h | |||
| @@ -47,5 +47,6 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman | |||
| 47 | int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); | 47 | int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); |
| 48 | int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); | 48 | int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); |
| 49 | void ps2_cmd_aborted(struct ps2dev *ps2dev); | 49 | void ps2_cmd_aborted(struct ps2dev *ps2dev); |
| 50 | int ps2_is_keyboard_id(char id); | ||
| 50 | 51 | ||
| 51 | #endif /* _LIBPS2_H */ | 52 | #endif /* _LIBPS2_H */ |
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h index b054debef2e0..81e3a185f951 100644 --- a/include/linux/lockd/bind.h +++ b/include/linux/lockd/bind.h | |||
| @@ -30,7 +30,7 @@ extern struct nlmsvc_binding * nlmsvc_ops; | |||
| 30 | * Functions exported by the lockd module | 30 | * Functions exported by the lockd module |
| 31 | */ | 31 | */ |
| 32 | extern int nlmclnt_proc(struct inode *, int, struct file_lock *); | 32 | extern int nlmclnt_proc(struct inode *, int, struct file_lock *); |
| 33 | extern int lockd_up(void); | 33 | extern int lockd_up(int proto); |
| 34 | extern void lockd_down(void); | 34 | extern void lockd_down(void); |
| 35 | 35 | ||
| 36 | #endif /* LINUX_LOCKD_BIND_H */ | 36 | #endif /* LINUX_LOCKD_BIND_H */ |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 0d92c468d55a..47b7dbd647a6 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
| @@ -80,7 +80,7 @@ struct nlm_wait; | |||
| 80 | /* | 80 | /* |
| 81 | * Memory chunk for NLM client RPC request. | 81 | * Memory chunk for NLM client RPC request. |
| 82 | */ | 82 | */ |
| 83 | #define NLMCLNT_OHSIZE (sizeof(system_utsname.nodename)+10) | 83 | #define NLMCLNT_OHSIZE (sizeof(utsname()->nodename)+10) |
| 84 | struct nlm_rqst { | 84 | struct nlm_rqst { |
| 85 | unsigned int a_flags; /* initial RPC task flags */ | 85 | unsigned int a_flags; /* initial RPC task flags */ |
| 86 | struct nlm_host * a_host; /* host handle */ | 86 | struct nlm_host * a_host; /* host handle */ |
diff --git a/include/linux/module.h b/include/linux/module.h index 2c599175c583..4b2d8091a410 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -320,6 +320,8 @@ struct module | |||
| 320 | /* Am I GPL-compatible */ | 320 | /* Am I GPL-compatible */ |
| 321 | int license_gplok; | 321 | int license_gplok; |
| 322 | 322 | ||
| 323 | unsigned int taints; /* same bits as kernel:tainted */ | ||
| 324 | |||
| 323 | #ifdef CONFIG_MODULE_UNLOAD | 325 | #ifdef CONFIG_MODULE_UNLOAD |
| 324 | /* Reference counts */ | 326 | /* Reference counts */ |
| 325 | struct module_ref ref[NR_CPUS]; | 327 | struct module_ref ref[NR_CPUS]; |
diff --git a/include/linux/namespace.h b/include/linux/namespace.h index 3abc8e3b4879..d137009f0b2b 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <linux/mount.h> | 5 | #include <linux/mount.h> |
| 6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
| 7 | #include <linux/nsproxy.h> | ||
| 7 | 8 | ||
| 8 | struct namespace { | 9 | struct namespace { |
| 9 | atomic_t count; | 10 | atomic_t count; |
| @@ -26,11 +27,8 @@ static inline void put_namespace(struct namespace *namespace) | |||
| 26 | 27 | ||
| 27 | static inline void exit_namespace(struct task_struct *p) | 28 | static inline void exit_namespace(struct task_struct *p) |
| 28 | { | 29 | { |
| 29 | struct namespace *namespace = p->namespace; | 30 | struct namespace *namespace = p->nsproxy->namespace; |
| 30 | if (namespace) { | 31 | if (namespace) { |
| 31 | task_lock(p); | ||
| 32 | p->namespace = NULL; | ||
| 33 | task_unlock(p); | ||
| 34 | put_namespace(namespace); | 32 | put_namespace(namespace); |
| 35 | } | 33 | } |
| 36 | } | 34 | } |
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 2dcad295fece..e1dbc86c270b 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h | |||
| @@ -140,6 +140,11 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int); | |||
| 140 | int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); | 140 | int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); |
| 141 | #endif | 141 | #endif |
| 142 | 142 | ||
| 143 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | ||
| 144 | int nfsd_vers(int vers, enum vers_op change); | ||
| 145 | void nfsd_reset_versions(void); | ||
| 146 | int nfsd_create_serv(void); | ||
| 147 | |||
| 143 | 148 | ||
| 144 | /* | 149 | /* |
| 145 | * NFSv4 State | 150 | * NFSv4 State |
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h index 31a3cb617ce0..069257ea99a0 100644 --- a/include/linux/nfsd/nfsfh.h +++ b/include/linux/nfsd/nfsfh.h | |||
| @@ -290,8 +290,9 @@ fill_post_wcc(struct svc_fh *fhp) | |||
| 290 | * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once | 290 | * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once |
| 291 | * so, any changes here should be reflected there. | 291 | * so, any changes here should be reflected there. |
| 292 | */ | 292 | */ |
| 293 | |||
| 293 | static inline void | 294 | static inline void |
| 294 | fh_lock(struct svc_fh *fhp) | 295 | fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) |
| 295 | { | 296 | { |
| 296 | struct dentry *dentry = fhp->fh_dentry; | 297 | struct dentry *dentry = fhp->fh_dentry; |
| 297 | struct inode *inode; | 298 | struct inode *inode; |
| @@ -310,11 +311,17 @@ fh_lock(struct svc_fh *fhp) | |||
| 310 | } | 311 | } |
| 311 | 312 | ||
| 312 | inode = dentry->d_inode; | 313 | inode = dentry->d_inode; |
| 313 | mutex_lock(&inode->i_mutex); | 314 | mutex_lock_nested(&inode->i_mutex, subclass); |
| 314 | fill_pre_wcc(fhp); | 315 | fill_pre_wcc(fhp); |
| 315 | fhp->fh_locked = 1; | 316 | fhp->fh_locked = 1; |
| 316 | } | 317 | } |
| 317 | 318 | ||
| 319 | static inline void | ||
| 320 | fh_lock(struct svc_fh *fhp) | ||
| 321 | { | ||
| 322 | fh_lock_nested(fhp, I_MUTEX_NORMAL); | ||
| 323 | } | ||
| 324 | |||
| 318 | /* | 325 | /* |
| 319 | * Unlock a file handle/inode | 326 | * Unlock a file handle/inode |
| 320 | */ | 327 | */ |
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h index dae0faea2807..8bcddccb6c42 100644 --- a/include/linux/nfsd/syscall.h +++ b/include/linux/nfsd/syscall.h | |||
| @@ -38,21 +38,6 @@ | |||
| 38 | #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ | 38 | #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ |
| 39 | #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ | 39 | #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ |
| 40 | 40 | ||
| 41 | /* | ||
| 42 | * Macros used to set version | ||
| 43 | */ | ||
| 44 | #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) | ||
| 45 | #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) | ||
| 46 | #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) | ||
| 47 | |||
| 48 | #if defined(CONFIG_NFSD_V4) | ||
| 49 | #define NFSCTL_VERALL (0x1c /* 0b011100 */) | ||
| 50 | #elif defined(CONFIG_NFSD_V3) | ||
| 51 | #define NFSCTL_VERALL (0x0c /* 0b001100 */) | ||
| 52 | #else | ||
| 53 | #define NFSCTL_VERALL (0x04 /* 0b000100 */) | ||
| 54 | #endif | ||
| 55 | |||
| 56 | /* SVC */ | 41 | /* SVC */ |
| 57 | struct nfsctl_svc { | 42 | struct nfsctl_svc { |
| 58 | unsigned short svc_port; | 43 | unsigned short svc_port; |
| @@ -134,8 +119,6 @@ extern int exp_delclient(struct nfsctl_client *ncp); | |||
| 134 | extern int exp_export(struct nfsctl_export *nxp); | 119 | extern int exp_export(struct nfsctl_export *nxp); |
| 135 | extern int exp_unexport(struct nfsctl_export *nxp); | 120 | extern int exp_unexport(struct nfsctl_export *nxp); |
| 136 | 121 | ||
| 137 | extern unsigned int nfsd_versbits; | ||
| 138 | |||
| 139 | #endif /* __KERNEL__ */ | 122 | #endif /* __KERNEL__ */ |
| 140 | 123 | ||
| 141 | #endif /* NFSD_SYSCALL_H */ | 124 | #endif /* NFSD_SYSCALL_H */ |
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h index 1a9ef3e627d1..5dce5c21822c 100644 --- a/include/linux/nodemask.h +++ b/include/linux/nodemask.h | |||
| @@ -352,6 +352,7 @@ extern nodemask_t node_possible_map; | |||
| 352 | #define node_possible(node) node_isset((node), node_possible_map) | 352 | #define node_possible(node) node_isset((node), node_possible_map) |
| 353 | #define first_online_node first_node(node_online_map) | 353 | #define first_online_node first_node(node_online_map) |
| 354 | #define next_online_node(nid) next_node((nid), node_online_map) | 354 | #define next_online_node(nid) next_node((nid), node_online_map) |
| 355 | int highest_possible_node_id(void); | ||
| 355 | #else | 356 | #else |
| 356 | #define num_online_nodes() 1 | 357 | #define num_online_nodes() 1 |
| 357 | #define num_possible_nodes() 1 | 358 | #define num_possible_nodes() 1 |
| @@ -359,6 +360,7 @@ extern nodemask_t node_possible_map; | |||
| 359 | #define node_possible(node) ((node) == 0) | 360 | #define node_possible(node) ((node) == 0) |
| 360 | #define first_online_node 0 | 361 | #define first_online_node 0 |
| 361 | #define next_online_node(nid) (MAX_NUMNODES) | 362 | #define next_online_node(nid) (MAX_NUMNODES) |
| 363 | #define highest_possible_node_id() 0 | ||
| 362 | #endif | 364 | #endif |
| 363 | 365 | ||
| 364 | #define any_online_node(mask) \ | 366 | #define any_online_node(mask) \ |
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h new file mode 100644 index 000000000000..f6baecdeecd6 --- /dev/null +++ b/include/linux/nsproxy.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | #ifndef _LINUX_NSPROXY_H | ||
| 2 | #define _LINUX_NSPROXY_H | ||
| 3 | |||
| 4 | #include <linux/spinlock.h> | ||
| 5 | #include <linux/sched.h> | ||
| 6 | |||
| 7 | struct namespace; | ||
| 8 | struct uts_namespace; | ||
| 9 | struct ipc_namespace; | ||
| 10 | |||
| 11 | /* | ||
| 12 | * A structure to contain pointers to all per-process | ||
| 13 | * namespaces - fs (mount), uts, network, sysvipc, etc. | ||
| 14 | * | ||
| 15 | * 'count' is the number of tasks holding a reference. | ||
| 16 | * The count for each namespace, then, will be the number | ||
| 17 | * of nsproxies pointing to it, not the number of tasks. | ||
| 18 | * | ||
| 19 | * The nsproxy is shared by tasks which share all namespaces. | ||
| 20 | * As soon as a single namespace is cloned or unshared, the | ||
| 21 | * nsproxy is copied. | ||
| 22 | */ | ||
| 23 | struct nsproxy { | ||
| 24 | atomic_t count; | ||
| 25 | spinlock_t nslock; | ||
| 26 | struct uts_namespace *uts_ns; | ||
| 27 | struct ipc_namespace *ipc_ns; | ||
| 28 | struct namespace *namespace; | ||
| 29 | }; | ||
| 30 | extern struct nsproxy init_nsproxy; | ||
| 31 | |||
| 32 | struct nsproxy *dup_namespaces(struct nsproxy *orig); | ||
| 33 | int copy_namespaces(int flags, struct task_struct *tsk); | ||
| 34 | void get_task_namespaces(struct task_struct *tsk); | ||
| 35 | void free_nsproxy(struct nsproxy *ns); | ||
| 36 | |||
| 37 | static inline void put_nsproxy(struct nsproxy *ns) | ||
| 38 | { | ||
| 39 | if (atomic_dec_and_test(&ns->count)) { | ||
| 40 | free_nsproxy(ns); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline void exit_task_namespaces(struct task_struct *p) | ||
| 45 | { | ||
| 46 | struct nsproxy *ns = p->nsproxy; | ||
| 47 | if (ns) { | ||
| 48 | put_nsproxy(ns); | ||
| 49 | p->nsproxy = NULL; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | #endif | ||
diff --git a/include/linux/pid.h b/include/linux/pid.h index 93da7e2d9f30..17b9e04d3586 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h | |||
| @@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_task(struct pid *pid, enum pid_type)); | |||
| 68 | extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid, | 68 | extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid, |
| 69 | enum pid_type)); | 69 | enum pid_type)); |
| 70 | 70 | ||
| 71 | extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); | ||
| 72 | |||
| 71 | /* | 73 | /* |
| 72 | * attach_pid() and detach_pid() must be called with the tasklist_lock | 74 | * attach_pid() and detach_pid() must be called with the tasklist_lock |
| 73 | * write-held. | 75 | * write-held. |
| @@ -89,33 +91,42 @@ extern struct pid *FASTCALL(find_pid(int nr)); | |||
| 89 | * Lookup a PID in the hash table, and return with it's count elevated. | 91 | * Lookup a PID in the hash table, and return with it's count elevated. |
| 90 | */ | 92 | */ |
| 91 | extern struct pid *find_get_pid(int nr); | 93 | extern struct pid *find_get_pid(int nr); |
| 94 | extern struct pid *find_ge_pid(int nr); | ||
| 92 | 95 | ||
| 93 | extern struct pid *alloc_pid(void); | 96 | extern struct pid *alloc_pid(void); |
| 94 | extern void FASTCALL(free_pid(struct pid *pid)); | 97 | extern void FASTCALL(free_pid(struct pid *pid)); |
| 95 | 98 | ||
| 96 | #define pid_next(task, type) \ | 99 | static inline pid_t pid_nr(struct pid *pid) |
| 97 | ((task)->pids[(type)].node.next) | 100 | { |
| 101 | pid_t nr = 0; | ||
| 102 | if (pid) | ||
| 103 | nr = pid->nr; | ||
| 104 | return nr; | ||
| 105 | } | ||
| 106 | |||
| 98 | 107 | ||
| 99 | #define pid_next_task(task, type) \ | 108 | #define do_each_task_pid(who, type, task) \ |
| 100 | hlist_entry(pid_next(task, type), struct task_struct, \ | 109 | do { \ |
| 101 | pids[(type)].node) | 110 | struct hlist_node *pos___; \ |
| 111 | struct pid *pid___ = find_pid(who); \ | ||
| 112 | if (pid___ != NULL) \ | ||
| 113 | hlist_for_each_entry_rcu((task), pos___, \ | ||
| 114 | &pid___->tasks[type], pids[type].node) { | ||
| 102 | 115 | ||
| 116 | #define while_each_task_pid(who, type, task) \ | ||
| 117 | } \ | ||
| 118 | } while (0) | ||
| 103 | 119 | ||
| 104 | /* We could use hlist_for_each_entry_rcu here but it takes more arguments | 120 | |
| 105 | * than the do_each_task_pid/while_each_task_pid. So we roll our own | 121 | #define do_each_pid_task(pid, type, task) \ |
| 106 | * to preserve the existing interface. | 122 | do { \ |
| 107 | */ | 123 | struct hlist_node *pos___; \ |
| 108 | #define do_each_task_pid(who, type, task) \ | 124 | if (pid != NULL) \ |
| 109 | if ((task = find_task_by_pid_type(type, who))) { \ | 125 | hlist_for_each_entry_rcu((task), pos___, \ |
| 110 | prefetch(pid_next(task, type)); \ | 126 | &pid->tasks[type], pids[type].node) { |
| 111 | do { | 127 | |
| 112 | 128 | #define while_each_pid_task(pid, type, task) \ | |
| 113 | #define while_each_task_pid(who, type, task) \ | 129 | } \ |
| 114 | } while (pid_next(task, type) && ({ \ | 130 | } while (0) |
| 115 | task = pid_next_task(task, type); \ | ||
| 116 | rcu_dereference(task); \ | ||
| 117 | prefetch(pid_next(task, type)); \ | ||
| 118 | 1; }) ); \ | ||
| 119 | } | ||
| 120 | 131 | ||
| 121 | #endif /* _LINUX_PID_H */ | 132 | #endif /* _LINUX_PID_H */ |
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 57f70bc8b24b..87dec8fe6de9 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h | |||
| @@ -244,13 +244,15 @@ static inline void kclist_add(struct kcore_list *new, void *addr, size_t size) | |||
| 244 | extern void kclist_add(struct kcore_list *, void *, size_t); | 244 | extern void kclist_add(struct kcore_list *, void *, size_t); |
| 245 | #endif | 245 | #endif |
| 246 | 246 | ||
| 247 | union proc_op { | ||
| 248 | int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); | ||
| 249 | int (*proc_read)(struct task_struct *task, char *page); | ||
| 250 | }; | ||
| 251 | |||
| 247 | struct proc_inode { | 252 | struct proc_inode { |
| 248 | struct pid *pid; | 253 | struct pid *pid; |
| 249 | int fd; | 254 | int fd; |
| 250 | union { | 255 | union proc_op op; |
| 251 | int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); | ||
| 252 | int (*proc_read)(struct task_struct *task, char *page); | ||
| 253 | } op; | ||
| 254 | struct proc_dir_entry *pde; | 256 | struct proc_dir_entry *pde; |
| 255 | struct inode vfs_inode; | 257 | struct inode vfs_inode; |
| 256 | }; | 258 | }; |
diff --git a/include/linux/pspace.h b/include/linux/pspace.h new file mode 100644 index 000000000000..91d48b8b2d99 --- /dev/null +++ b/include/linux/pspace.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | #ifndef _LINUX_PSPACE_H | ||
| 2 | #define _LINUX_PSPACE_H | ||
| 3 | |||
| 4 | #include <linux/sched.h> | ||
| 5 | #include <linux/mm.h> | ||
| 6 | #include <linux/threads.h> | ||
| 7 | #include <linux/pid.h> | ||
| 8 | |||
| 9 | struct pidmap { | ||
| 10 | atomic_t nr_free; | ||
| 11 | void *page; | ||
| 12 | }; | ||
| 13 | |||
| 14 | #define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) | ||
| 15 | |||
| 16 | struct pspace { | ||
| 17 | struct pidmap pidmap[PIDMAP_ENTRIES]; | ||
| 18 | int last_pid; | ||
| 19 | }; | ||
| 20 | |||
| 21 | extern struct pspace init_pspace; | ||
| 22 | |||
| 23 | #endif /* _LINUX_PSPACE_H */ | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 7ef899c47c29..38530232d92f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | #define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ | 24 | #define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ |
| 25 | #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ | 25 | #define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ |
| 26 | #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ | 26 | #define CLONE_STOPPED 0x02000000 /* Start in stopped state */ |
| 27 | #define CLONE_NEWUTS 0x04000000 /* New utsname group? */ | ||
| 28 | #define CLONE_NEWIPC 0x08000000 /* New ipcs */ | ||
| 27 | 29 | ||
| 28 | /* | 30 | /* |
| 29 | * Scheduling policies | 31 | * Scheduling policies |
| @@ -118,7 +120,6 @@ extern unsigned long avenrun[]; /* Load averages */ | |||
| 118 | 120 | ||
| 119 | extern unsigned long total_forks; | 121 | extern unsigned long total_forks; |
| 120 | extern int nr_threads; | 122 | extern int nr_threads; |
| 121 | extern int last_pid; | ||
| 122 | DECLARE_PER_CPU(unsigned long, process_counts); | 123 | DECLARE_PER_CPU(unsigned long, process_counts); |
| 123 | extern int nr_processes(void); | 124 | extern int nr_processes(void); |
| 124 | extern unsigned long nr_running(void); | 125 | extern unsigned long nr_running(void); |
| @@ -239,7 +240,7 @@ extern signed long schedule_timeout_interruptible(signed long timeout); | |||
| 239 | extern signed long schedule_timeout_uninterruptible(signed long timeout); | 240 | extern signed long schedule_timeout_uninterruptible(signed long timeout); |
| 240 | asmlinkage void schedule(void); | 241 | asmlinkage void schedule(void); |
| 241 | 242 | ||
| 242 | struct namespace; | 243 | struct nsproxy; |
| 243 | 244 | ||
| 244 | /* Maximum number of active map areas.. This is a random (large) number */ | 245 | /* Maximum number of active map areas.. This is a random (large) number */ |
| 245 | #define DEFAULT_MAX_MAP_COUNT 65536 | 246 | #define DEFAULT_MAX_MAP_COUNT 65536 |
| @@ -754,6 +755,7 @@ static inline void prefetch_stack(struct task_struct *t) { } | |||
| 754 | struct audit_context; /* See audit.c */ | 755 | struct audit_context; /* See audit.c */ |
| 755 | struct mempolicy; | 756 | struct mempolicy; |
| 756 | struct pipe_inode_info; | 757 | struct pipe_inode_info; |
| 758 | struct uts_namespace; | ||
| 757 | 759 | ||
| 758 | enum sleep_type { | 760 | enum sleep_type { |
| 759 | SLEEP_NORMAL, | 761 | SLEEP_NORMAL, |
| @@ -897,8 +899,8 @@ struct task_struct { | |||
| 897 | struct fs_struct *fs; | 899 | struct fs_struct *fs; |
| 898 | /* open file information */ | 900 | /* open file information */ |
| 899 | struct files_struct *files; | 901 | struct files_struct *files; |
| 900 | /* namespace */ | 902 | /* namespaces */ |
| 901 | struct namespace *namespace; | 903 | struct nsproxy *nsproxy; |
| 902 | /* signal handlers */ | 904 | /* signal handlers */ |
| 903 | struct signal_struct *signal; | 905 | struct signal_struct *signal; |
| 904 | struct sighand_struct *sighand; | 906 | struct sighand_struct *sighand; |
| @@ -1020,6 +1022,26 @@ static inline pid_t process_group(struct task_struct *tsk) | |||
| 1020 | return tsk->signal->pgrp; | 1022 | return tsk->signal->pgrp; |
| 1021 | } | 1023 | } |
| 1022 | 1024 | ||
| 1025 | static inline struct pid *task_pid(struct task_struct *task) | ||
| 1026 | { | ||
| 1027 | return task->pids[PIDTYPE_PID].pid; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | static inline struct pid *task_tgid(struct task_struct *task) | ||
| 1031 | { | ||
| 1032 | return task->group_leader->pids[PIDTYPE_PID].pid; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | static inline struct pid *task_pgrp(struct task_struct *task) | ||
| 1036 | { | ||
| 1037 | return task->group_leader->pids[PIDTYPE_PGID].pid; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static inline struct pid *task_session(struct task_struct *task) | ||
| 1041 | { | ||
| 1042 | return task->group_leader->pids[PIDTYPE_SID].pid; | ||
| 1043 | } | ||
| 1044 | |||
| 1023 | /** | 1045 | /** |
| 1024 | * pid_alive - check that a task structure is not stale | 1046 | * pid_alive - check that a task structure is not stale |
| 1025 | * @p: Task structure to be checked. | 1047 | * @p: Task structure to be checked. |
| @@ -1043,6 +1065,8 @@ static inline int is_init(struct task_struct *tsk) | |||
| 1043 | return tsk->pid == 1; | 1065 | return tsk->pid == 1; |
| 1044 | } | 1066 | } |
| 1045 | 1067 | ||
| 1068 | extern struct pid *cad_pid; | ||
| 1069 | |||
| 1046 | extern void free_task(struct task_struct *tsk); | 1070 | extern void free_task(struct task_struct *tsk); |
| 1047 | #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) | 1071 | #define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) |
| 1048 | 1072 | ||
| @@ -1247,10 +1271,15 @@ extern int send_sig_info(int, struct siginfo *, struct task_struct *); | |||
| 1247 | extern int send_group_sig_info(int, struct siginfo *, struct task_struct *); | 1271 | extern int send_group_sig_info(int, struct siginfo *, struct task_struct *); |
| 1248 | extern int force_sigsegv(int, struct task_struct *); | 1272 | extern int force_sigsegv(int, struct task_struct *); |
| 1249 | extern int force_sig_info(int, struct siginfo *, struct task_struct *); | 1273 | extern int force_sig_info(int, struct siginfo *, struct task_struct *); |
| 1274 | extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); | ||
| 1275 | extern int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); | ||
| 1276 | extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid); | ||
| 1277 | extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_t, u32); | ||
| 1278 | extern int kill_pgrp(struct pid *pid, int sig, int priv); | ||
| 1279 | extern int kill_pid(struct pid *pid, int sig, int priv); | ||
| 1250 | extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); | 1280 | extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); |
| 1251 | extern int kill_pg_info(int, struct siginfo *, pid_t); | 1281 | extern int kill_pg_info(int, struct siginfo *, pid_t); |
| 1252 | extern int kill_proc_info(int, struct siginfo *, pid_t); | 1282 | extern int kill_proc_info(int, struct siginfo *, pid_t); |
| 1253 | extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t, u32); | ||
| 1254 | extern void do_notify_parent(struct task_struct *, int); | 1283 | extern void do_notify_parent(struct task_struct *, int); |
| 1255 | extern void force_sig(int, struct task_struct *); | 1284 | extern void force_sig(int, struct task_struct *); |
| 1256 | extern void force_sig_specific(int, struct task_struct *); | 1285 | extern void force_sig_specific(int, struct task_struct *); |
| @@ -1265,6 +1294,11 @@ extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *); | |||
| 1265 | extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *); | 1294 | extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *); |
| 1266 | extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long); | 1295 | extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long); |
| 1267 | 1296 | ||
| 1297 | static inline int kill_cad_pid(int sig, int priv) | ||
| 1298 | { | ||
| 1299 | return kill_pid(cad_pid, sig, priv); | ||
| 1300 | } | ||
| 1301 | |||
| 1268 | /* These can be the second arg to send_sig_info/send_group_sig_info. */ | 1302 | /* These can be the second arg to send_sig_info/send_group_sig_info. */ |
| 1269 | #define SEND_SIG_NOINFO ((struct siginfo *) 0) | 1303 | #define SEND_SIG_NOINFO ((struct siginfo *) 0) |
| 1270 | #define SEND_SIG_PRIV ((struct siginfo *) 1) | 1304 | #define SEND_SIG_PRIV ((struct siginfo *) 1) |
| @@ -1358,6 +1392,17 @@ extern void wait_task_inactive(struct task_struct * p); | |||
| 1358 | /* de_thread depends on thread_group_leader not being a pid based check */ | 1392 | /* de_thread depends on thread_group_leader not being a pid based check */ |
| 1359 | #define thread_group_leader(p) (p == p->group_leader) | 1393 | #define thread_group_leader(p) (p == p->group_leader) |
| 1360 | 1394 | ||
| 1395 | /* Do to the insanities of de_thread it is possible for a process | ||
| 1396 | * to have the pid of the thread group leader without actually being | ||
| 1397 | * the thread group leader. For iteration through the pids in proc | ||
| 1398 | * all we care about is that we have a task with the appropriate | ||
| 1399 | * pid, we don't actually care if we have the right task. | ||
| 1400 | */ | ||
| 1401 | static inline int has_group_leader_pid(struct task_struct *p) | ||
| 1402 | { | ||
| 1403 | return p->pid == p->tgid; | ||
| 1404 | } | ||
| 1405 | |||
| 1361 | static inline struct task_struct *next_thread(const struct task_struct *p) | 1406 | static inline struct task_struct *next_thread(const struct task_struct *p) |
| 1362 | { | 1407 | { |
| 1363 | return list_entry(rcu_dereference(p->thread_group.next), | 1408 | return list_entry(rcu_dereference(p->thread_group.next), |
diff --git a/include/linux/serio.h b/include/linux/serio.h index 6348e8330897..c9069310b6ac 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h | |||
| @@ -217,5 +217,8 @@ static inline void serio_unpin_driver(struct serio *serio) | |||
| 217 | #define SERIO_LKKBD 0x28 | 217 | #define SERIO_LKKBD 0x28 |
| 218 | #define SERIO_ELO 0x29 | 218 | #define SERIO_ELO 0x29 |
| 219 | #define SERIO_MICROTOUCH 0x30 | 219 | #define SERIO_MICROTOUCH 0x30 |
| 220 | #define SERIO_PENMOUNT 0x31 | ||
| 221 | #define SERIO_TOUCHRIGHT 0x32 | ||
| 222 | #define SERIO_TOUCHWIN 0x33 | ||
| 220 | 223 | ||
| 221 | #endif | 224 | #endif |
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 73140ee5c638..4ebcdf91f3b3 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h | |||
| @@ -18,6 +18,30 @@ | |||
| 18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
| 19 | 19 | ||
| 20 | /* | 20 | /* |
| 21 | * This is the RPC server thread function prototype | ||
| 22 | */ | ||
| 23 | typedef void (*svc_thread_fn)(struct svc_rqst *); | ||
| 24 | |||
| 25 | /* | ||
| 26 | * | ||
| 27 | * RPC service thread pool. | ||
| 28 | * | ||
| 29 | * Pool of threads and temporary sockets. Generally there is only | ||
| 30 | * a single one of these per RPC service, but on NUMA machines those | ||
| 31 | * services that can benefit from it (i.e. nfs but not lockd) will | ||
| 32 | * have one pool per NUMA node. This optimisation reduces cross- | ||
| 33 | * node traffic on multi-node NUMA NFS servers. | ||
| 34 | */ | ||
| 35 | struct svc_pool { | ||
| 36 | unsigned int sp_id; /* pool id; also node id on NUMA */ | ||
| 37 | spinlock_t sp_lock; /* protects all fields */ | ||
| 38 | struct list_head sp_threads; /* idle server threads */ | ||
| 39 | struct list_head sp_sockets; /* pending sockets */ | ||
| 40 | unsigned int sp_nrthreads; /* # of threads in pool */ | ||
| 41 | struct list_head sp_all_threads; /* all server threads */ | ||
| 42 | } ____cacheline_aligned_in_smp; | ||
| 43 | |||
| 44 | /* | ||
| 21 | * RPC service. | 45 | * RPC service. |
| 22 | * | 46 | * |
| 23 | * An RPC service is a ``daemon,'' possibly multithreaded, which | 47 | * An RPC service is a ``daemon,'' possibly multithreaded, which |
| @@ -28,8 +52,6 @@ | |||
| 28 | * We currently do not support more than one RPC program per daemon. | 52 | * We currently do not support more than one RPC program per daemon. |
| 29 | */ | 53 | */ |
| 30 | struct svc_serv { | 54 | struct svc_serv { |
| 31 | struct list_head sv_threads; /* idle server threads */ | ||
| 32 | struct list_head sv_sockets; /* pending sockets */ | ||
| 33 | struct svc_program * sv_program; /* RPC program */ | 55 | struct svc_program * sv_program; /* RPC program */ |
| 34 | struct svc_stat * sv_stats; /* RPC statistics */ | 56 | struct svc_stat * sv_stats; /* RPC statistics */ |
| 35 | spinlock_t sv_lock; | 57 | spinlock_t sv_lock; |
| @@ -40,11 +62,36 @@ struct svc_serv { | |||
| 40 | struct list_head sv_permsocks; /* all permanent sockets */ | 62 | struct list_head sv_permsocks; /* all permanent sockets */ |
| 41 | struct list_head sv_tempsocks; /* all temporary sockets */ | 63 | struct list_head sv_tempsocks; /* all temporary sockets */ |
| 42 | int sv_tmpcnt; /* count of temporary sockets */ | 64 | int sv_tmpcnt; /* count of temporary sockets */ |
| 65 | struct timer_list sv_temptimer; /* timer for aging temporary sockets */ | ||
| 43 | 66 | ||
| 44 | char * sv_name; /* service name */ | 67 | char * sv_name; /* service name */ |
| 68 | |||
| 69 | unsigned int sv_nrpools; /* number of thread pools */ | ||
| 70 | struct svc_pool * sv_pools; /* array of thread pools */ | ||
| 71 | |||
| 72 | void (*sv_shutdown)(struct svc_serv *serv); | ||
| 73 | /* Callback to use when last thread | ||
| 74 | * exits. | ||
| 75 | */ | ||
| 76 | |||
| 77 | struct module * sv_module; /* optional module to count when | ||
| 78 | * adding threads */ | ||
| 79 | svc_thread_fn sv_function; /* main function for threads */ | ||
| 80 | int sv_kill_signal; /* signal to kill threads */ | ||
| 45 | }; | 81 | }; |
| 46 | 82 | ||
| 47 | /* | 83 | /* |
| 84 | * We use sv_nrthreads as a reference count. svc_destroy() drops | ||
| 85 | * this refcount, so we need to bump it up around operations that | ||
| 86 | * change the number of threads. Horrible, but there it is. | ||
| 87 | * Should be called with the BKL held. | ||
| 88 | */ | ||
| 89 | static inline void svc_get(struct svc_serv *serv) | ||
| 90 | { | ||
| 91 | serv->sv_nrthreads++; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* | ||
| 48 | * Maximum payload size supported by a kernel RPC server. | 95 | * Maximum payload size supported by a kernel RPC server. |
| 49 | * This is use to determine the max number of pages nfsd is | 96 | * This is use to determine the max number of pages nfsd is |
| 50 | * willing to return in a single READ operation. | 97 | * willing to return in a single READ operation. |
| @@ -127,11 +174,13 @@ static inline void svc_putu32(struct kvec *iov, __be32 val) | |||
| 127 | */ | 174 | */ |
| 128 | struct svc_rqst { | 175 | struct svc_rqst { |
| 129 | struct list_head rq_list; /* idle list */ | 176 | struct list_head rq_list; /* idle list */ |
| 177 | struct list_head rq_all; /* all threads list */ | ||
| 130 | struct svc_sock * rq_sock; /* socket */ | 178 | struct svc_sock * rq_sock; /* socket */ |
| 131 | struct sockaddr_in rq_addr; /* peer address */ | 179 | struct sockaddr_in rq_addr; /* peer address */ |
| 132 | int rq_addrlen; | 180 | int rq_addrlen; |
| 133 | 181 | ||
| 134 | struct svc_serv * rq_server; /* RPC service definition */ | 182 | struct svc_serv * rq_server; /* RPC service definition */ |
| 183 | struct svc_pool * rq_pool; /* thread pool */ | ||
| 135 | struct svc_procedure * rq_procinfo; /* procedure info */ | 184 | struct svc_procedure * rq_procinfo; /* procedure info */ |
| 136 | struct auth_ops * rq_authop; /* authentication flavour */ | 185 | struct auth_ops * rq_authop; /* authentication flavour */ |
| 137 | struct svc_cred rq_cred; /* auth info */ | 186 | struct svc_cred rq_cred; /* auth info */ |
| @@ -180,6 +229,7 @@ struct svc_rqst { | |||
| 180 | * to prevent encrypting page | 229 | * to prevent encrypting page |
| 181 | * cache pages */ | 230 | * cache pages */ |
| 182 | wait_queue_head_t rq_wait; /* synchronization */ | 231 | wait_queue_head_t rq_wait; /* synchronization */ |
| 232 | struct task_struct *rq_task; /* service thread */ | ||
| 183 | }; | 233 | }; |
| 184 | 234 | ||
| 185 | /* | 235 | /* |
| @@ -321,20 +371,21 @@ struct svc_procedure { | |||
| 321 | }; | 371 | }; |
| 322 | 372 | ||
| 323 | /* | 373 | /* |
| 324 | * This is the RPC server thread function prototype | ||
| 325 | */ | ||
| 326 | typedef void (*svc_thread_fn)(struct svc_rqst *); | ||
| 327 | |||
| 328 | /* | ||
| 329 | * Function prototypes. | 374 | * Function prototypes. |
| 330 | */ | 375 | */ |
| 331 | struct svc_serv * svc_create(struct svc_program *, unsigned int); | 376 | struct svc_serv * svc_create(struct svc_program *, unsigned int, |
| 377 | void (*shutdown)(struct svc_serv*)); | ||
| 332 | int svc_create_thread(svc_thread_fn, struct svc_serv *); | 378 | int svc_create_thread(svc_thread_fn, struct svc_serv *); |
| 333 | void svc_exit_thread(struct svc_rqst *); | 379 | void svc_exit_thread(struct svc_rqst *); |
| 380 | struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, | ||
| 381 | void (*shutdown)(struct svc_serv*), | ||
| 382 | svc_thread_fn, int sig, struct module *); | ||
| 383 | int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); | ||
| 334 | void svc_destroy(struct svc_serv *); | 384 | void svc_destroy(struct svc_serv *); |
| 335 | int svc_process(struct svc_serv *, struct svc_rqst *); | 385 | int svc_process(struct svc_rqst *); |
| 336 | int svc_register(struct svc_serv *, int, unsigned short); | 386 | int svc_register(struct svc_serv *, int, unsigned short); |
| 337 | void svc_wake_up(struct svc_serv *); | 387 | void svc_wake_up(struct svc_serv *); |
| 338 | void svc_reserve(struct svc_rqst *rqstp, int space); | 388 | void svc_reserve(struct svc_rqst *rqstp, int space); |
| 389 | struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); | ||
| 339 | 390 | ||
| 340 | #endif /* SUNRPC_SVC_H */ | 391 | #endif /* SUNRPC_SVC_H */ |
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index b4acb3d37c3f..4c296152cbfa 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
| @@ -20,8 +20,9 @@ struct svc_sock { | |||
| 20 | struct socket * sk_sock; /* berkeley socket layer */ | 20 | struct socket * sk_sock; /* berkeley socket layer */ |
| 21 | struct sock * sk_sk; /* INET layer */ | 21 | struct sock * sk_sk; /* INET layer */ |
| 22 | 22 | ||
| 23 | struct svc_pool * sk_pool; /* current pool iff queued */ | ||
| 23 | struct svc_serv * sk_server; /* service for this socket */ | 24 | struct svc_serv * sk_server; /* service for this socket */ |
| 24 | unsigned int sk_inuse; /* use count */ | 25 | atomic_t sk_inuse; /* use count */ |
| 25 | unsigned long sk_flags; | 26 | unsigned long sk_flags; |
| 26 | #define SK_BUSY 0 /* enqueued/receiving */ | 27 | #define SK_BUSY 0 /* enqueued/receiving */ |
| 27 | #define SK_CONN 1 /* conn pending */ | 28 | #define SK_CONN 1 /* conn pending */ |
| @@ -31,9 +32,12 @@ struct svc_sock { | |||
| 31 | #define SK_DEAD 6 /* socket closed */ | 32 | #define SK_DEAD 6 /* socket closed */ |
| 32 | #define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */ | 33 | #define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */ |
| 33 | #define SK_DEFERRED 8 /* request on sk_deferred */ | 34 | #define SK_DEFERRED 8 /* request on sk_deferred */ |
| 35 | #define SK_OLD 9 /* used for temp socket aging mark+sweep */ | ||
| 36 | #define SK_DETACHED 10 /* detached from tempsocks list */ | ||
| 34 | 37 | ||
| 35 | int sk_reserved; /* space on outq that is reserved */ | 38 | atomic_t sk_reserved; /* space on outq that is reserved */ |
| 36 | 39 | ||
| 40 | spinlock_t sk_defer_lock; /* protects sk_deferred */ | ||
| 37 | struct list_head sk_deferred; /* deferred requests that need to | 41 | struct list_head sk_deferred; /* deferred requests that need to |
| 38 | * be revisted */ | 42 | * be revisted */ |
| 39 | struct mutex sk_mutex; /* to serialize sending data */ | 43 | struct mutex sk_mutex; /* to serialize sending data */ |
| @@ -57,9 +61,14 @@ struct svc_sock { | |||
| 57 | */ | 61 | */ |
| 58 | int svc_makesock(struct svc_serv *, int, unsigned short); | 62 | int svc_makesock(struct svc_serv *, int, unsigned short); |
| 59 | void svc_delete_socket(struct svc_sock *); | 63 | void svc_delete_socket(struct svc_sock *); |
| 60 | int svc_recv(struct svc_serv *, struct svc_rqst *, long); | 64 | int svc_recv(struct svc_rqst *, long); |
| 61 | int svc_send(struct svc_rqst *); | 65 | int svc_send(struct svc_rqst *); |
| 62 | void svc_drop(struct svc_rqst *); | 66 | void svc_drop(struct svc_rqst *); |
| 63 | void svc_sock_update_bufs(struct svc_serv *serv); | 67 | void svc_sock_update_bufs(struct svc_serv *serv); |
| 68 | int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); | ||
| 69 | int svc_addsock(struct svc_serv *serv, | ||
| 70 | int fd, | ||
| 71 | char *name_return, | ||
| 72 | int *proto); | ||
| 64 | 73 | ||
| 65 | #endif /* SUNRPC_SVCSOCK_H */ | 74 | #endif /* SUNRPC_SVCSOCK_H */ |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 2d1c3d5c83ac..3efcfc7e9c6c 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
| @@ -599,4 +599,6 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, | |||
| 599 | size_t len); | 599 | size_t len); |
| 600 | asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); | 600 | asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); |
| 601 | 601 | ||
| 602 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]); | ||
| 603 | |||
| 602 | #endif | 604 | #endif |
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 58c961c9e170..5c8473bb6882 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h | |||
| @@ -219,7 +219,8 @@ extern struct list_head tty_drivers; | |||
| 219 | 219 | ||
| 220 | struct tty_driver *alloc_tty_driver(int lines); | 220 | struct tty_driver *alloc_tty_driver(int lines); |
| 221 | void put_tty_driver(struct tty_driver *driver); | 221 | void put_tty_driver(struct tty_driver *driver); |
| 222 | void tty_set_operations(struct tty_driver *driver, struct tty_operations *op); | 222 | void tty_set_operations(struct tty_driver *driver, |
| 223 | const struct tty_operations *op); | ||
| 223 | 224 | ||
| 224 | /* tty driver magic number */ | 225 | /* tty driver magic number */ |
| 225 | #define TTY_DRIVER_MAGIC 0x5402 | 226 | #define TTY_DRIVER_MAGIC 0x5402 |
diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 7168302f9844..1fd61eeed664 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h | |||
| @@ -22,12 +22,18 @@ | |||
| 22 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> | 22 | * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> |
| 23 | * | 23 | * |
| 24 | * Changes/Revisions: | 24 | * Changes/Revisions: |
| 25 | * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) | ||
| 26 | * - update ff support for the changes in kernel interface | ||
| 27 | * - add UINPUT_VERSION | ||
| 25 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) | 28 | * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) |
| 26 | * - added force feedback support | 29 | * - added force feedback support |
| 27 | * - added UI_SET_PHYS | 30 | * - added UI_SET_PHYS |
| 28 | * 0.1 20/06/2002 | 31 | * 0.1 20/06/2002 |
| 29 | * - first public version | 32 | * - first public version |
| 30 | */ | 33 | */ |
| 34 | |||
| 35 | #define UINPUT_VERSION 3 | ||
| 36 | |||
| 31 | #ifdef __KERNEL__ | 37 | #ifdef __KERNEL__ |
| 32 | #define UINPUT_MINOR 223 | 38 | #define UINPUT_MINOR 223 |
| 33 | #define UINPUT_NAME "uinput" | 39 | #define UINPUT_NAME "uinput" |
| @@ -45,7 +51,10 @@ struct uinput_request { | |||
| 45 | 51 | ||
| 46 | union { | 52 | union { |
| 47 | int effect_id; | 53 | int effect_id; |
| 48 | struct ff_effect* effect; | 54 | struct { |
| 55 | struct ff_effect *effect; | ||
| 56 | struct ff_effect *old; | ||
| 57 | } upload; | ||
| 49 | } u; | 58 | } u; |
| 50 | }; | 59 | }; |
| 51 | 60 | ||
| @@ -58,6 +67,7 @@ struct uinput_device { | |||
| 58 | unsigned char head; | 67 | unsigned char head; |
| 59 | unsigned char tail; | 68 | unsigned char tail; |
| 60 | struct input_event buff[UINPUT_BUFFER_SIZE]; | 69 | struct input_event buff[UINPUT_BUFFER_SIZE]; |
| 70 | int ff_effects_max; | ||
| 61 | 71 | ||
| 62 | struct uinput_request *requests[UINPUT_NUM_REQUESTS]; | 72 | struct uinput_request *requests[UINPUT_NUM_REQUESTS]; |
| 63 | wait_queue_head_t requests_waitq; | 73 | wait_queue_head_t requests_waitq; |
| @@ -69,6 +79,7 @@ struct uinput_ff_upload { | |||
| 69 | int request_id; | 79 | int request_id; |
| 70 | int retval; | 80 | int retval; |
| 71 | struct ff_effect effect; | 81 | struct ff_effect effect; |
| 82 | struct ff_effect old; | ||
| 72 | }; | 83 | }; |
| 73 | 84 | ||
| 74 | struct uinput_ff_erase { | 85 | struct uinput_ff_erase { |
| @@ -98,33 +109,33 @@ struct uinput_ff_erase { | |||
| 98 | #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) | 109 | #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) |
| 99 | #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) | 110 | #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) |
| 100 | 111 | ||
| 101 | /* To write a force-feedback-capable driver, the upload_effect | 112 | /* |
| 113 | * To write a force-feedback-capable driver, the upload_effect | ||
| 102 | * and erase_effect callbacks in input_dev must be implemented. | 114 | * and erase_effect callbacks in input_dev must be implemented. |
| 103 | * The uinput driver will generate a fake input event when one of | 115 | * The uinput driver will generate a fake input event when one of |
| 104 | * these callbacks are invoked. The userspace code then uses | 116 | * these callbacks are invoked. The userspace code then uses |
| 105 | * ioctls to retrieve additional parameters and send the return code. | 117 | * ioctls to retrieve additional parameters and send the return code. |
| 106 | * The callback blocks until this return code is sent. | 118 | * The callback blocks until this return code is sent. |
| 107 | * | 119 | * |
| 108 | * The described callback mechanism is only used if EV_FF is set. | 120 | * The described callback mechanism is only used if ff_effects_max |
| 109 | * Otherwise, default implementations of upload_effect and erase_effect | 121 | * is set. |
| 110 | * are used. | ||
| 111 | * | 122 | * |
| 112 | * To implement upload_effect(): | 123 | * To implement upload_effect(): |
| 113 | * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD. | 124 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. |
| 114 | * A request ID will be given in 'value'. | 125 | * A request ID will be given in 'value'. |
| 115 | * 2. Allocate a uinput_ff_upload struct, fill in request_id with | 126 | * 2. Allocate a uinput_ff_upload struct, fill in request_id with |
| 116 | * the 'value' from the EV_UINPUT event. | 127 | * the 'value' from the EV_UINPUT event. |
| 117 | * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the | 128 | * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the |
| 118 | * uinput_ff_upload struct. It will be filled in with the | 129 | * uinput_ff_upload struct. It will be filled in with the |
| 119 | * ff_effect passed to upload_effect(). | 130 | * ff_effects passed to upload_effect(). |
| 120 | * 4. Perform the effect upload, and place the modified ff_effect | 131 | * 4. Perform the effect upload, and place a return code back into |
| 121 | * and a return code back into the uinput_ff_upload struct. | 132 | the uinput_ff_upload struct. |
| 122 | * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the | 133 | * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the |
| 123 | * uinput_ff_upload_effect struct. This will complete execution | 134 | * uinput_ff_upload_effect struct. This will complete execution |
| 124 | * of our upload_effect() handler. | 135 | * of our upload_effect() handler. |
| 125 | * | 136 | * |
| 126 | * To implement erase_effect(): | 137 | * To implement erase_effect(): |
| 127 | * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE. | 138 | * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. |
| 128 | * A request ID will be given in 'value'. | 139 | * A request ID will be given in 'value'. |
| 129 | * 2. Allocate a uinput_ff_erase struct, fill in request_id with | 140 | * 2. Allocate a uinput_ff_erase struct, fill in request_id with |
| 130 | * the 'value' from the EV_UINPUT event. | 141 | * the 'value' from the EV_UINPUT event. |
| @@ -133,13 +144,13 @@ struct uinput_ff_erase { | |||
| 133 | * effect ID passed to erase_effect(). | 144 | * effect ID passed to erase_effect(). |
| 134 | * 4. Perform the effect erasure, and place a return code back | 145 | * 4. Perform the effect erasure, and place a return code back |
| 135 | * into the uinput_ff_erase struct. | 146 | * into the uinput_ff_erase struct. |
| 136 | * and a return code back into the uinput_ff_erase struct. | ||
| 137 | * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the | 147 | * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the |
| 138 | * uinput_ff_erase_effect struct. This will complete execution | 148 | * uinput_ff_erase_effect struct. This will complete execution |
| 139 | * of our erase_effect() handler. | 149 | * of our erase_effect() handler. |
| 140 | */ | 150 | */ |
| 141 | 151 | ||
| 142 | /* This is the new event type, used only by uinput. | 152 | /* |
| 153 | * This is the new event type, used only by uinput. | ||
| 143 | * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' | 154 | * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' |
| 144 | * is the unique request ID. This number was picked | 155 | * is the unique request ID. This number was picked |
| 145 | * arbitrarily, above EV_MAX (since the input system | 156 | * arbitrarily, above EV_MAX (since the input system |
diff --git a/include/linux/unistd.h b/include/linux/unistd.h index c18c60f3254e..aa8d5b5e2e3e 100644 --- a/include/linux/unistd.h +++ b/include/linux/unistd.h | |||
| @@ -1,12 +1,8 @@ | |||
| 1 | #ifndef _LINUX_UNISTD_H_ | 1 | #ifndef _LINUX_UNISTD_H_ |
| 2 | #define _LINUX_UNISTD_H_ | 2 | #define _LINUX_UNISTD_H_ |
| 3 | 3 | ||
| 4 | #ifdef __KERNEL__ | ||
| 5 | extern int errno; | ||
| 6 | #endif | ||
| 7 | |||
| 8 | /* | 4 | /* |
| 9 | * Include machine specific syscallX macros | 5 | * Include machine specific syscall numbers |
| 10 | */ | 6 | */ |
| 11 | #include <asm/unistd.h> | 7 | #include <asm/unistd.h> |
| 12 | 8 | ||
diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 13e1da0c538d..02e4b6972064 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h | |||
| @@ -1,6 +1,11 @@ | |||
| 1 | #ifndef _LINUX_UTSNAME_H | 1 | #ifndef _LINUX_UTSNAME_H |
| 2 | #define _LINUX_UTSNAME_H | 2 | #define _LINUX_UTSNAME_H |
| 3 | 3 | ||
| 4 | #include <linux/sched.h> | ||
| 5 | #include <linux/kref.h> | ||
| 6 | #include <linux/nsproxy.h> | ||
| 7 | #include <asm/atomic.h> | ||
| 8 | |||
| 4 | #define __OLD_UTS_LEN 8 | 9 | #define __OLD_UTS_LEN 8 |
| 5 | 10 | ||
| 6 | struct oldold_utsname { | 11 | struct oldold_utsname { |
| @@ -30,7 +35,55 @@ struct new_utsname { | |||
| 30 | char domainname[65]; | 35 | char domainname[65]; |
| 31 | }; | 36 | }; |
| 32 | 37 | ||
| 33 | extern struct new_utsname system_utsname; | 38 | struct uts_namespace { |
| 39 | struct kref kref; | ||
| 40 | struct new_utsname name; | ||
| 41 | }; | ||
| 42 | extern struct uts_namespace init_uts_ns; | ||
| 43 | |||
| 44 | static inline void get_uts_ns(struct uts_namespace *ns) | ||
| 45 | { | ||
| 46 | kref_get(&ns->kref); | ||
| 47 | } | ||
| 48 | |||
| 49 | #ifdef CONFIG_UTS_NS | ||
| 50 | extern int unshare_utsname(unsigned long unshare_flags, | ||
| 51 | struct uts_namespace **new_uts); | ||
| 52 | extern int copy_utsname(int flags, struct task_struct *tsk); | ||
| 53 | extern void free_uts_ns(struct kref *kref); | ||
| 54 | |||
| 55 | static inline void put_uts_ns(struct uts_namespace *ns) | ||
| 56 | { | ||
| 57 | kref_put(&ns->kref, free_uts_ns); | ||
| 58 | } | ||
| 59 | #else | ||
| 60 | static inline int unshare_utsname(unsigned long unshare_flags, | ||
| 61 | struct uts_namespace **new_uts) | ||
| 62 | { | ||
| 63 | if (unshare_flags & CLONE_NEWUTS) | ||
| 64 | return -EINVAL; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline int copy_utsname(int flags, struct task_struct *tsk) | ||
| 70 | { | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | static inline void put_uts_ns(struct uts_namespace *ns) | ||
| 74 | { | ||
| 75 | } | ||
| 76 | #endif | ||
| 77 | |||
| 78 | static inline struct new_utsname *utsname(void) | ||
| 79 | { | ||
| 80 | return ¤t->nsproxy->uts_ns->name; | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline struct new_utsname *init_utsname(void) | ||
| 84 | { | ||
| 85 | return &init_uts_ns.name; | ||
| 86 | } | ||
| 34 | 87 | ||
| 35 | extern struct rw_semaphore uts_sem; | 88 | extern struct rw_semaphore uts_sem; |
| 36 | #endif | 89 | #endif |
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 1009d3fe1fc2..37a1a41f5b65 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h | |||
| @@ -84,4 +84,11 @@ void reset_vc(struct vc_data *vc); | |||
| 84 | extern char con_buf[CON_BUF_SIZE]; | 84 | extern char con_buf[CON_BUF_SIZE]; |
| 85 | extern struct semaphore con_buf_sem; | 85 | extern struct semaphore con_buf_sem; |
| 86 | 86 | ||
| 87 | struct vt_spawn_console { | ||
| 88 | spinlock_t lock; | ||
| 89 | struct pid *pid; | ||
| 90 | int sig; | ||
| 91 | }; | ||
| 92 | extern struct vt_spawn_console vt_spawn_con; | ||
| 93 | |||
| 87 | #endif /* _VT_KERN_H */ | 94 | #endif /* _VT_KERN_H */ |
diff --git a/init/Kconfig b/init/Kconfig index f7a04d0daf07..10382931eead 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -115,6 +115,15 @@ config SYSVIPC | |||
| 115 | section 6.4 of the Linux Programmer's Guide, available from | 115 | section 6.4 of the Linux Programmer's Guide, available from |
| 116 | <http://www.tldp.org/guides.html>. | 116 | <http://www.tldp.org/guides.html>. |
| 117 | 117 | ||
| 118 | config IPC_NS | ||
| 119 | bool "IPC Namespaces" | ||
| 120 | depends on SYSVIPC | ||
| 121 | default n | ||
| 122 | help | ||
| 123 | Support ipc namespaces. This allows containers, i.e. virtual | ||
| 124 | environments, to use ipc namespaces to provide different ipc | ||
| 125 | objects for different servers. If unsure, say N. | ||
| 126 | |||
| 118 | config POSIX_MQUEUE | 127 | config POSIX_MQUEUE |
| 119 | bool "POSIX Message Queues" | 128 | bool "POSIX Message Queues" |
| 120 | depends on NET && EXPERIMENTAL | 129 | depends on NET && EXPERIMENTAL |
| @@ -182,6 +191,14 @@ config TASK_DELAY_ACCT | |||
| 182 | 191 | ||
| 183 | Say N if unsure. | 192 | Say N if unsure. |
| 184 | 193 | ||
| 194 | config UTS_NS | ||
| 195 | bool "UTS Namespaces" | ||
| 196 | default n | ||
| 197 | help | ||
| 198 | Support uts namespaces. This allows containers, i.e. | ||
| 199 | vservers, to use uts namespaces to provide different | ||
| 200 | uts info for different servers. If unsure, say N. | ||
| 201 | |||
| 185 | config AUDIT | 202 | config AUDIT |
| 186 | bool "Auditing support" | 203 | bool "Auditing support" |
| 187 | depends on NET | 204 | depends on NET |
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index a06f037fa000..919a80cb322e 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | #define __KERNEL_SYSCALLS__ | ||
| 2 | #include <linux/unistd.h> | 1 | #include <linux/unistd.h> |
| 3 | #include <linux/kernel.h> | 2 | #include <linux/kernel.h> |
| 4 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
| @@ -35,7 +34,7 @@ static int __init do_linuxrc(void * shell) | |||
| 35 | (void) sys_open("/dev/console",O_RDWR,0); | 34 | (void) sys_open("/dev/console",O_RDWR,0); |
| 36 | (void) sys_dup(0); | 35 | (void) sys_dup(0); |
| 37 | (void) sys_dup(0); | 36 | (void) sys_dup(0); |
| 38 | return execve(shell, argv, envp_init); | 37 | return kernel_execve(shell, argv, envp_init); |
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | static void __init handle_initrd(void) | 40 | static void __init handle_initrd(void) |
diff --git a/init/main.c b/init/main.c index 0766e69712b2..ee123243fb53 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -9,8 +9,6 @@ | |||
| 9 | * Simplified starting of init: Michael A. Griffith <grif@acm.org> | 9 | * Simplified starting of init: Michael A. Griffith <grif@acm.org> |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #define __KERNEL_SYSCALLS__ | ||
| 13 | |||
| 14 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 15 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 16 | #include <linux/proc_fs.h> | 14 | #include <linux/proc_fs.h> |
| @@ -703,7 +701,7 @@ static void do_pre_smp_initcalls(void) | |||
| 703 | static void run_init_process(char *init_filename) | 701 | static void run_init_process(char *init_filename) |
| 704 | { | 702 | { |
| 705 | argv_init[0] = init_filename; | 703 | argv_init[0] = init_filename; |
| 706 | execve(init_filename, argv_init, envp_init); | 704 | kernel_execve(init_filename, argv_init, envp_init); |
| 707 | } | 705 | } |
| 708 | 706 | ||
| 709 | static int init(void * unused) | 707 | static int init(void * unused) |
| @@ -723,6 +721,8 @@ static int init(void * unused) | |||
| 723 | */ | 721 | */ |
| 724 | child_reaper = current; | 722 | child_reaper = current; |
| 725 | 723 | ||
| 724 | cad_pid = task_pid(current); | ||
| 725 | |||
| 726 | smp_prepare_cpus(max_cpus); | 726 | smp_prepare_cpus(max_cpus); |
| 727 | 727 | ||
| 728 | do_pre_smp_initcalls(); | 728 | do_pre_smp_initcalls(); |
diff --git a/init/version.c b/init/version.c index e290802c6bd2..8f28344d9c70 100644 --- a/init/version.c +++ b/init/version.c | |||
| @@ -12,22 +12,27 @@ | |||
| 12 | #include <linux/utsname.h> | 12 | #include <linux/utsname.h> |
| 13 | #include <linux/utsrelease.h> | 13 | #include <linux/utsrelease.h> |
| 14 | #include <linux/version.h> | 14 | #include <linux/version.h> |
| 15 | #include <linux/sched.h> | ||
| 15 | 16 | ||
| 16 | #define version(a) Version_ ## a | 17 | #define version(a) Version_ ## a |
| 17 | #define version_string(a) version(a) | 18 | #define version_string(a) version(a) |
| 18 | 19 | ||
| 19 | int version_string(LINUX_VERSION_CODE); | 20 | int version_string(LINUX_VERSION_CODE); |
| 20 | 21 | ||
| 21 | struct new_utsname system_utsname = { | 22 | struct uts_namespace init_uts_ns = { |
| 22 | .sysname = UTS_SYSNAME, | 23 | .kref = { |
| 23 | .nodename = UTS_NODENAME, | 24 | .refcount = ATOMIC_INIT(2), |
| 24 | .release = UTS_RELEASE, | 25 | }, |
| 25 | .version = UTS_VERSION, | 26 | .name = { |
| 26 | .machine = UTS_MACHINE, | 27 | .sysname = UTS_SYSNAME, |
| 27 | .domainname = UTS_DOMAINNAME, | 28 | .nodename = UTS_NODENAME, |
| 29 | .release = UTS_RELEASE, | ||
| 30 | .version = UTS_VERSION, | ||
| 31 | .machine = UTS_MACHINE, | ||
| 32 | .domainname = UTS_DOMAINNAME, | ||
| 33 | }, | ||
| 28 | }; | 34 | }; |
| 29 | 35 | EXPORT_SYMBOL_GPL(init_uts_ns); | |
| 30 | EXPORT_SYMBOL(system_utsname); | ||
| 31 | 36 | ||
| 32 | const char linux_banner[] = | 37 | const char linux_banner[] = |
| 33 | "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" | 38 | "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index d75d0ba83360..c45ae86cec31 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
| @@ -73,7 +73,7 @@ struct mqueue_inode_info { | |||
| 73 | struct mq_attr attr; | 73 | struct mq_attr attr; |
| 74 | 74 | ||
| 75 | struct sigevent notify; | 75 | struct sigevent notify; |
| 76 | pid_t notify_owner; | 76 | struct pid* notify_owner; |
| 77 | struct user_struct *user; /* user who created, for accounting */ | 77 | struct user_struct *user; /* user who created, for accounting */ |
| 78 | struct sock *notify_sock; | 78 | struct sock *notify_sock; |
| 79 | struct sk_buff *notify_cookie; | 79 | struct sk_buff *notify_cookie; |
| @@ -134,7 +134,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, | |||
| 134 | INIT_LIST_HEAD(&info->e_wait_q[0].list); | 134 | INIT_LIST_HEAD(&info->e_wait_q[0].list); |
| 135 | INIT_LIST_HEAD(&info->e_wait_q[1].list); | 135 | INIT_LIST_HEAD(&info->e_wait_q[1].list); |
| 136 | info->messages = NULL; | 136 | info->messages = NULL; |
| 137 | info->notify_owner = 0; | 137 | info->notify_owner = NULL; |
| 138 | info->qsize = 0; | 138 | info->qsize = 0; |
| 139 | info->user = NULL; /* set when all is ok */ | 139 | info->user = NULL; /* set when all is ok */ |
| 140 | memset(&info->attr, 0, sizeof(info->attr)); | 140 | memset(&info->attr, 0, sizeof(info->attr)); |
| @@ -338,7 +338,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, | |||
| 338 | (info->notify_owner && | 338 | (info->notify_owner && |
| 339 | info->notify.sigev_notify == SIGEV_SIGNAL) ? | 339 | info->notify.sigev_notify == SIGEV_SIGNAL) ? |
| 340 | info->notify.sigev_signo : 0, | 340 | info->notify.sigev_signo : 0, |
| 341 | info->notify_owner); | 341 | pid_nr(info->notify_owner)); |
| 342 | spin_unlock(&info->lock); | 342 | spin_unlock(&info->lock); |
| 343 | buffer[sizeof(buffer)-1] = '\0'; | 343 | buffer[sizeof(buffer)-1] = '\0'; |
| 344 | slen = strlen(buffer)+1; | 344 | slen = strlen(buffer)+1; |
| @@ -363,7 +363,7 @@ static int mqueue_flush_file(struct file *filp, fl_owner_t id) | |||
| 363 | struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); | 363 | struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode); |
| 364 | 364 | ||
| 365 | spin_lock(&info->lock); | 365 | spin_lock(&info->lock); |
| 366 | if (current->tgid == info->notify_owner) | 366 | if (task_tgid(current) == info->notify_owner) |
| 367 | remove_notification(info); | 367 | remove_notification(info); |
| 368 | 368 | ||
| 369 | spin_unlock(&info->lock); | 369 | spin_unlock(&info->lock); |
| @@ -518,8 +518,8 @@ static void __do_notify(struct mqueue_inode_info *info) | |||
| 518 | sig_i.si_pid = current->tgid; | 518 | sig_i.si_pid = current->tgid; |
| 519 | sig_i.si_uid = current->uid; | 519 | sig_i.si_uid = current->uid; |
| 520 | 520 | ||
| 521 | kill_proc_info(info->notify.sigev_signo, | 521 | kill_pid_info(info->notify.sigev_signo, |
| 522 | &sig_i, info->notify_owner); | 522 | &sig_i, info->notify_owner); |
| 523 | break; | 523 | break; |
| 524 | case SIGEV_THREAD: | 524 | case SIGEV_THREAD: |
| 525 | set_cookie(info->notify_cookie, NOTIFY_WOKENUP); | 525 | set_cookie(info->notify_cookie, NOTIFY_WOKENUP); |
| @@ -528,7 +528,8 @@ static void __do_notify(struct mqueue_inode_info *info) | |||
| 528 | break; | 528 | break; |
| 529 | } | 529 | } |
| 530 | /* after notification unregisters process */ | 530 | /* after notification unregisters process */ |
| 531 | info->notify_owner = 0; | 531 | put_pid(info->notify_owner); |
| 532 | info->notify_owner = NULL; | ||
| 532 | } | 533 | } |
| 533 | wake_up(&info->wait_q); | 534 | wake_up(&info->wait_q); |
| 534 | } | 535 | } |
| @@ -566,12 +567,13 @@ static long prepare_timeout(const struct timespec __user *u_arg) | |||
| 566 | 567 | ||
| 567 | static void remove_notification(struct mqueue_inode_info *info) | 568 | static void remove_notification(struct mqueue_inode_info *info) |
| 568 | { | 569 | { |
| 569 | if (info->notify_owner != 0 && | 570 | if (info->notify_owner != NULL && |
| 570 | info->notify.sigev_notify == SIGEV_THREAD) { | 571 | info->notify.sigev_notify == SIGEV_THREAD) { |
| 571 | set_cookie(info->notify_cookie, NOTIFY_REMOVED); | 572 | set_cookie(info->notify_cookie, NOTIFY_REMOVED); |
| 572 | netlink_sendskb(info->notify_sock, info->notify_cookie, 0); | 573 | netlink_sendskb(info->notify_sock, info->notify_cookie, 0); |
| 573 | } | 574 | } |
| 574 | info->notify_owner = 0; | 575 | put_pid(info->notify_owner); |
| 576 | info->notify_owner = NULL; | ||
| 575 | } | 577 | } |
| 576 | 578 | ||
| 577 | static int mq_attr_ok(struct mq_attr *attr) | 579 | static int mq_attr_ok(struct mq_attr *attr) |
| @@ -1062,11 +1064,11 @@ retry: | |||
| 1062 | ret = 0; | 1064 | ret = 0; |
| 1063 | spin_lock(&info->lock); | 1065 | spin_lock(&info->lock); |
| 1064 | if (u_notification == NULL) { | 1066 | if (u_notification == NULL) { |
| 1065 | if (info->notify_owner == current->tgid) { | 1067 | if (info->notify_owner == task_tgid(current)) { |
| 1066 | remove_notification(info); | 1068 | remove_notification(info); |
| 1067 | inode->i_atime = inode->i_ctime = CURRENT_TIME; | 1069 | inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 1068 | } | 1070 | } |
| 1069 | } else if (info->notify_owner != 0) { | 1071 | } else if (info->notify_owner != NULL) { |
| 1070 | ret = -EBUSY; | 1072 | ret = -EBUSY; |
| 1071 | } else { | 1073 | } else { |
| 1072 | switch (notification.sigev_notify) { | 1074 | switch (notification.sigev_notify) { |
| @@ -1086,7 +1088,8 @@ retry: | |||
| 1086 | info->notify.sigev_notify = SIGEV_SIGNAL; | 1088 | info->notify.sigev_notify = SIGEV_SIGNAL; |
| 1087 | break; | 1089 | break; |
| 1088 | } | 1090 | } |
| 1089 | info->notify_owner = current->tgid; | 1091 | |
| 1092 | info->notify_owner = get_pid(task_tgid(current)); | ||
| 1090 | inode->i_atime = inode->i_ctime = CURRENT_TIME; | 1093 | inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 1091 | } | 1094 | } |
| 1092 | spin_unlock(&info->lock); | 1095 | spin_unlock(&info->lock); |
| @@ -16,6 +16,10 @@ | |||
| 16 | * | 16 | * |
| 17 | * support for audit of ipc object properties and permission changes | 17 | * support for audit of ipc object properties and permission changes |
| 18 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> | 18 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
| 19 | * | ||
| 20 | * namespaces support | ||
| 21 | * OpenVZ, SWsoft Inc. | ||
| 22 | * Pavel Emelianov <xemul@openvz.org> | ||
| 19 | */ | 23 | */ |
| 20 | 24 | ||
| 21 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
| @@ -31,16 +35,12 @@ | |||
| 31 | #include <linux/audit.h> | 35 | #include <linux/audit.h> |
| 32 | #include <linux/seq_file.h> | 36 | #include <linux/seq_file.h> |
| 33 | #include <linux/mutex.h> | 37 | #include <linux/mutex.h> |
| 38 | #include <linux/nsproxy.h> | ||
| 34 | 39 | ||
| 35 | #include <asm/current.h> | 40 | #include <asm/current.h> |
| 36 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
| 37 | #include "util.h" | 42 | #include "util.h" |
| 38 | 43 | ||
| 39 | /* sysctl: */ | ||
| 40 | int msg_ctlmax = MSGMAX; | ||
| 41 | int msg_ctlmnb = MSGMNB; | ||
| 42 | int msg_ctlmni = MSGMNI; | ||
| 43 | |||
| 44 | /* | 44 | /* |
| 45 | * one msg_receiver structure for each sleeping receiver: | 45 | * one msg_receiver structure for each sleeping receiver: |
| 46 | */ | 46 | */ |
| @@ -69,30 +69,75 @@ struct msg_sender { | |||
| 69 | static atomic_t msg_bytes = ATOMIC_INIT(0); | 69 | static atomic_t msg_bytes = ATOMIC_INIT(0); |
| 70 | static atomic_t msg_hdrs = ATOMIC_INIT(0); | 70 | static atomic_t msg_hdrs = ATOMIC_INIT(0); |
| 71 | 71 | ||
| 72 | static struct ipc_ids msg_ids; | 72 | static struct ipc_ids init_msg_ids; |
| 73 | 73 | ||
| 74 | #define msg_lock(id) ((struct msg_queue *)ipc_lock(&msg_ids, id)) | 74 | #define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS])) |
| 75 | #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) | ||
| 76 | #define msg_rmid(id) ((struct msg_queue *)ipc_rmid(&msg_ids, id)) | ||
| 77 | #define msg_checkid(msq, msgid) ipc_checkid(&msg_ids, &msq->q_perm, msgid) | ||
| 78 | #define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq) | ||
| 79 | 75 | ||
| 80 | static void freeque(struct msg_queue *msq, int id); | 76 | #define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id)) |
| 81 | static int newque(key_t key, int msgflg); | 77 | #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) |
| 78 | #define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id)) | ||
| 79 | #define msg_checkid(ns, msq, msgid) \ | ||
| 80 | ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid) | ||
| 81 | #define msg_buildid(ns, id, seq) \ | ||
| 82 | ipc_buildid(&msg_ids(ns), id, seq) | ||
| 83 | |||
| 84 | static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id); | ||
| 85 | static int newque (struct ipc_namespace *ns, key_t key, int msgflg); | ||
| 82 | #ifdef CONFIG_PROC_FS | 86 | #ifdef CONFIG_PROC_FS |
| 83 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it); | 87 | static int sysvipc_msg_proc_show(struct seq_file *s, void *it); |
| 84 | #endif | 88 | #endif |
| 85 | 89 | ||
| 90 | static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) | ||
| 91 | { | ||
| 92 | ns->ids[IPC_MSG_IDS] = ids; | ||
| 93 | ns->msg_ctlmax = MSGMAX; | ||
| 94 | ns->msg_ctlmnb = MSGMNB; | ||
| 95 | ns->msg_ctlmni = MSGMNI; | ||
| 96 | ipc_init_ids(ids, ns->msg_ctlmni); | ||
| 97 | } | ||
| 98 | |||
| 99 | #ifdef CONFIG_IPC_NS | ||
| 100 | int msg_init_ns(struct ipc_namespace *ns) | ||
| 101 | { | ||
| 102 | struct ipc_ids *ids; | ||
| 103 | |||
| 104 | ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); | ||
| 105 | if (ids == NULL) | ||
| 106 | return -ENOMEM; | ||
| 107 | |||
| 108 | __msg_init_ns(ns, ids); | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | void msg_exit_ns(struct ipc_namespace *ns) | ||
| 113 | { | ||
| 114 | int i; | ||
| 115 | struct msg_queue *msq; | ||
| 116 | |||
| 117 | mutex_lock(&msg_ids(ns).mutex); | ||
| 118 | for (i = 0; i <= msg_ids(ns).max_id; i++) { | ||
| 119 | msq = msg_lock(ns, i); | ||
| 120 | if (msq == NULL) | ||
| 121 | continue; | ||
| 122 | |||
| 123 | freeque(ns, msq, i); | ||
| 124 | } | ||
| 125 | mutex_unlock(&msg_ids(ns).mutex); | ||
| 126 | |||
| 127 | kfree(ns->ids[IPC_MSG_IDS]); | ||
| 128 | ns->ids[IPC_MSG_IDS] = NULL; | ||
| 129 | } | ||
| 130 | #endif | ||
| 131 | |||
| 86 | void __init msg_init(void) | 132 | void __init msg_init(void) |
| 87 | { | 133 | { |
| 88 | ipc_init_ids(&msg_ids, msg_ctlmni); | 134 | __msg_init_ns(&init_ipc_ns, &init_msg_ids); |
| 89 | ipc_init_proc_interface("sysvipc/msg", | 135 | ipc_init_proc_interface("sysvipc/msg", |
| 90 | " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", | 136 | " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", |
| 91 | &msg_ids, | 137 | IPC_MSG_IDS, sysvipc_msg_proc_show); |
| 92 | sysvipc_msg_proc_show); | ||
| 93 | } | 138 | } |
| 94 | 139 | ||
| 95 | static int newque(key_t key, int msgflg) | 140 | static int newque (struct ipc_namespace *ns, key_t key, int msgflg) |
| 96 | { | 141 | { |
| 97 | struct msg_queue *msq; | 142 | struct msg_queue *msq; |
| 98 | int id, retval; | 143 | int id, retval; |
| @@ -111,18 +156,18 @@ static int newque(key_t key, int msgflg) | |||
| 111 | return retval; | 156 | return retval; |
| 112 | } | 157 | } |
| 113 | 158 | ||
| 114 | id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); | 159 | id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni); |
| 115 | if (id == -1) { | 160 | if (id == -1) { |
| 116 | security_msg_queue_free(msq); | 161 | security_msg_queue_free(msq); |
| 117 | ipc_rcu_putref(msq); | 162 | ipc_rcu_putref(msq); |
| 118 | return -ENOSPC; | 163 | return -ENOSPC; |
| 119 | } | 164 | } |
| 120 | 165 | ||
| 121 | msq->q_id = msg_buildid(id, msq->q_perm.seq); | 166 | msq->q_id = msg_buildid(ns, id, msq->q_perm.seq); |
| 122 | msq->q_stime = msq->q_rtime = 0; | 167 | msq->q_stime = msq->q_rtime = 0; |
| 123 | msq->q_ctime = get_seconds(); | 168 | msq->q_ctime = get_seconds(); |
| 124 | msq->q_cbytes = msq->q_qnum = 0; | 169 | msq->q_cbytes = msq->q_qnum = 0; |
| 125 | msq->q_qbytes = msg_ctlmnb; | 170 | msq->q_qbytes = ns->msg_ctlmnb; |
| 126 | msq->q_lspid = msq->q_lrpid = 0; | 171 | msq->q_lspid = msq->q_lrpid = 0; |
| 127 | INIT_LIST_HEAD(&msq->q_messages); | 172 | INIT_LIST_HEAD(&msq->q_messages); |
| 128 | INIT_LIST_HEAD(&msq->q_receivers); | 173 | INIT_LIST_HEAD(&msq->q_receivers); |
| @@ -186,13 +231,13 @@ static void expunge_all(struct msg_queue *msq, int res) | |||
| 186 | * msg_ids.mutex and the spinlock for this message queue is hold | 231 | * msg_ids.mutex and the spinlock for this message queue is hold |
| 187 | * before freeque() is called. msg_ids.mutex remains locked on exit. | 232 | * before freeque() is called. msg_ids.mutex remains locked on exit. |
| 188 | */ | 233 | */ |
| 189 | static void freeque(struct msg_queue *msq, int id) | 234 | static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id) |
| 190 | { | 235 | { |
| 191 | struct list_head *tmp; | 236 | struct list_head *tmp; |
| 192 | 237 | ||
| 193 | expunge_all(msq, -EIDRM); | 238 | expunge_all(msq, -EIDRM); |
| 194 | ss_wakeup(&msq->q_senders, 1); | 239 | ss_wakeup(&msq->q_senders, 1); |
| 195 | msq = msg_rmid(id); | 240 | msq = msg_rmid(ns, id); |
| 196 | msg_unlock(msq); | 241 | msg_unlock(msq); |
| 197 | 242 | ||
| 198 | tmp = msq->q_messages.next; | 243 | tmp = msq->q_messages.next; |
| @@ -212,24 +257,27 @@ asmlinkage long sys_msgget(key_t key, int msgflg) | |||
| 212 | { | 257 | { |
| 213 | struct msg_queue *msq; | 258 | struct msg_queue *msq; |
| 214 | int id, ret = -EPERM; | 259 | int id, ret = -EPERM; |
| 260 | struct ipc_namespace *ns; | ||
| 261 | |||
| 262 | ns = current->nsproxy->ipc_ns; | ||
| 215 | 263 | ||
| 216 | mutex_lock(&msg_ids.mutex); | 264 | mutex_lock(&msg_ids(ns).mutex); |
| 217 | if (key == IPC_PRIVATE) | 265 | if (key == IPC_PRIVATE) |
| 218 | ret = newque(key, msgflg); | 266 | ret = newque(ns, key, msgflg); |
| 219 | else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */ | 267 | else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */ |
| 220 | if (!(msgflg & IPC_CREAT)) | 268 | if (!(msgflg & IPC_CREAT)) |
| 221 | ret = -ENOENT; | 269 | ret = -ENOENT; |
| 222 | else | 270 | else |
| 223 | ret = newque(key, msgflg); | 271 | ret = newque(ns, key, msgflg); |
| 224 | } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { | 272 | } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { |
| 225 | ret = -EEXIST; | 273 | ret = -EEXIST; |
| 226 | } else { | 274 | } else { |
| 227 | msq = msg_lock(id); | 275 | msq = msg_lock(ns, id); |
| 228 | BUG_ON(msq == NULL); | 276 | BUG_ON(msq == NULL); |
| 229 | if (ipcperms(&msq->q_perm, msgflg)) | 277 | if (ipcperms(&msq->q_perm, msgflg)) |
| 230 | ret = -EACCES; | 278 | ret = -EACCES; |
| 231 | else { | 279 | else { |
| 232 | int qid = msg_buildid(id, msq->q_perm.seq); | 280 | int qid = msg_buildid(ns, id, msq->q_perm.seq); |
| 233 | 281 | ||
| 234 | ret = security_msg_queue_associate(msq, msgflg); | 282 | ret = security_msg_queue_associate(msq, msgflg); |
| 235 | if (!ret) | 283 | if (!ret) |
| @@ -237,7 +285,7 @@ asmlinkage long sys_msgget(key_t key, int msgflg) | |||
| 237 | } | 285 | } |
| 238 | msg_unlock(msq); | 286 | msg_unlock(msq); |
| 239 | } | 287 | } |
| 240 | mutex_unlock(&msg_ids.mutex); | 288 | mutex_unlock(&msg_ids(ns).mutex); |
| 241 | 289 | ||
| 242 | return ret; | 290 | return ret; |
| 243 | } | 291 | } |
| @@ -341,11 +389,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 341 | struct msq_setbuf setbuf; | 389 | struct msq_setbuf setbuf; |
| 342 | struct msg_queue *msq; | 390 | struct msg_queue *msq; |
| 343 | int err, version; | 391 | int err, version; |
| 392 | struct ipc_namespace *ns; | ||
| 344 | 393 | ||
| 345 | if (msqid < 0 || cmd < 0) | 394 | if (msqid < 0 || cmd < 0) |
| 346 | return -EINVAL; | 395 | return -EINVAL; |
| 347 | 396 | ||
| 348 | version = ipc_parse_version(&cmd); | 397 | version = ipc_parse_version(&cmd); |
| 398 | ns = current->nsproxy->ipc_ns; | ||
| 349 | 399 | ||
| 350 | switch (cmd) { | 400 | switch (cmd) { |
| 351 | case IPC_INFO: | 401 | case IPC_INFO: |
| @@ -366,14 +416,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 366 | return err; | 416 | return err; |
| 367 | 417 | ||
| 368 | memset(&msginfo, 0, sizeof(msginfo)); | 418 | memset(&msginfo, 0, sizeof(msginfo)); |
| 369 | msginfo.msgmni = msg_ctlmni; | 419 | msginfo.msgmni = ns->msg_ctlmni; |
| 370 | msginfo.msgmax = msg_ctlmax; | 420 | msginfo.msgmax = ns->msg_ctlmax; |
| 371 | msginfo.msgmnb = msg_ctlmnb; | 421 | msginfo.msgmnb = ns->msg_ctlmnb; |
| 372 | msginfo.msgssz = MSGSSZ; | 422 | msginfo.msgssz = MSGSSZ; |
| 373 | msginfo.msgseg = MSGSEG; | 423 | msginfo.msgseg = MSGSEG; |
| 374 | mutex_lock(&msg_ids.mutex); | 424 | mutex_lock(&msg_ids(ns).mutex); |
| 375 | if (cmd == MSG_INFO) { | 425 | if (cmd == MSG_INFO) { |
| 376 | msginfo.msgpool = msg_ids.in_use; | 426 | msginfo.msgpool = msg_ids(ns).in_use; |
| 377 | msginfo.msgmap = atomic_read(&msg_hdrs); | 427 | msginfo.msgmap = atomic_read(&msg_hdrs); |
| 378 | msginfo.msgtql = atomic_read(&msg_bytes); | 428 | msginfo.msgtql = atomic_read(&msg_bytes); |
| 379 | } else { | 429 | } else { |
| @@ -381,8 +431,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 381 | msginfo.msgpool = MSGPOOL; | 431 | msginfo.msgpool = MSGPOOL; |
| 382 | msginfo.msgtql = MSGTQL; | 432 | msginfo.msgtql = MSGTQL; |
| 383 | } | 433 | } |
| 384 | max_id = msg_ids.max_id; | 434 | max_id = msg_ids(ns).max_id; |
| 385 | mutex_unlock(&msg_ids.mutex); | 435 | mutex_unlock(&msg_ids(ns).mutex); |
| 386 | if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) | 436 | if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) |
| 387 | return -EFAULT; | 437 | return -EFAULT; |
| 388 | return (max_id < 0) ? 0 : max_id; | 438 | return (max_id < 0) ? 0 : max_id; |
| @@ -395,20 +445,20 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 395 | 445 | ||
| 396 | if (!buf) | 446 | if (!buf) |
| 397 | return -EFAULT; | 447 | return -EFAULT; |
| 398 | if (cmd == MSG_STAT && msqid >= msg_ids.entries->size) | 448 | if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size) |
| 399 | return -EINVAL; | 449 | return -EINVAL; |
| 400 | 450 | ||
| 401 | memset(&tbuf, 0, sizeof(tbuf)); | 451 | memset(&tbuf, 0, sizeof(tbuf)); |
| 402 | 452 | ||
| 403 | msq = msg_lock(msqid); | 453 | msq = msg_lock(ns, msqid); |
| 404 | if (msq == NULL) | 454 | if (msq == NULL) |
| 405 | return -EINVAL; | 455 | return -EINVAL; |
| 406 | 456 | ||
| 407 | if (cmd == MSG_STAT) { | 457 | if (cmd == MSG_STAT) { |
| 408 | success_return = msg_buildid(msqid, msq->q_perm.seq); | 458 | success_return = msg_buildid(ns, msqid, msq->q_perm.seq); |
| 409 | } else { | 459 | } else { |
| 410 | err = -EIDRM; | 460 | err = -EIDRM; |
| 411 | if (msg_checkid(msq, msqid)) | 461 | if (msg_checkid(ns, msq, msqid)) |
| 412 | goto out_unlock; | 462 | goto out_unlock; |
| 413 | success_return = 0; | 463 | success_return = 0; |
| 414 | } | 464 | } |
| @@ -446,14 +496,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 446 | return -EINVAL; | 496 | return -EINVAL; |
| 447 | } | 497 | } |
| 448 | 498 | ||
| 449 | mutex_lock(&msg_ids.mutex); | 499 | mutex_lock(&msg_ids(ns).mutex); |
| 450 | msq = msg_lock(msqid); | 500 | msq = msg_lock(ns, msqid); |
| 451 | err = -EINVAL; | 501 | err = -EINVAL; |
| 452 | if (msq == NULL) | 502 | if (msq == NULL) |
| 453 | goto out_up; | 503 | goto out_up; |
| 454 | 504 | ||
| 455 | err = -EIDRM; | 505 | err = -EIDRM; |
| 456 | if (msg_checkid(msq, msqid)) | 506 | if (msg_checkid(ns, msq, msqid)) |
| 457 | goto out_unlock_up; | 507 | goto out_unlock_up; |
| 458 | ipcp = &msq->q_perm; | 508 | ipcp = &msq->q_perm; |
| 459 | 509 | ||
| @@ -481,7 +531,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 481 | case IPC_SET: | 531 | case IPC_SET: |
| 482 | { | 532 | { |
| 483 | err = -EPERM; | 533 | err = -EPERM; |
| 484 | if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) | 534 | if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE)) |
| 485 | goto out_unlock_up; | 535 | goto out_unlock_up; |
| 486 | 536 | ||
| 487 | msq->q_qbytes = setbuf.qbytes; | 537 | msq->q_qbytes = setbuf.qbytes; |
| @@ -503,12 +553,12 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) | |||
| 503 | break; | 553 | break; |
| 504 | } | 554 | } |
| 505 | case IPC_RMID: | 555 | case IPC_RMID: |
| 506 | freeque(msq, msqid); | 556 | freeque(ns, msq, msqid); |
| 507 | break; | 557 | break; |
| 508 | } | 558 | } |
| 509 | err = 0; | 559 | err = 0; |
| 510 | out_up: | 560 | out_up: |
| 511 | mutex_unlock(&msg_ids.mutex); | 561 | mutex_unlock(&msg_ids(ns).mutex); |
| 512 | return err; | 562 | return err; |
| 513 | out_unlock_up: | 563 | out_unlock_up: |
| 514 | msg_unlock(msq); | 564 | msg_unlock(msq); |
| @@ -582,8 +632,11 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) | |||
| 582 | struct msg_msg *msg; | 632 | struct msg_msg *msg; |
| 583 | long mtype; | 633 | long mtype; |
| 584 | int err; | 634 | int err; |
| 635 | struct ipc_namespace *ns; | ||
| 636 | |||
| 637 | ns = current->nsproxy->ipc_ns; | ||
| 585 | 638 | ||
| 586 | if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0) | 639 | if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0) |
| 587 | return -EINVAL; | 640 | return -EINVAL; |
| 588 | if (get_user(mtype, &msgp->mtype)) | 641 | if (get_user(mtype, &msgp->mtype)) |
| 589 | return -EFAULT; | 642 | return -EFAULT; |
| @@ -597,13 +650,13 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg) | |||
| 597 | msg->m_type = mtype; | 650 | msg->m_type = mtype; |
| 598 | msg->m_ts = msgsz; | 651 | msg->m_ts = msgsz; |
| 599 | 652 | ||
| 600 | msq = msg_lock(msqid); | 653 | msq = msg_lock(ns, msqid); |
| 601 | err = -EINVAL; | 654 | err = -EINVAL; |
| 602 | if (msq == NULL) | 655 | if (msq == NULL) |
| 603 | goto out_free; | 656 | goto out_free; |
| 604 | 657 | ||
| 605 | err= -EIDRM; | 658 | err= -EIDRM; |
| 606 | if (msg_checkid(msq, msqid)) | 659 | if (msg_checkid(ns, msq, msqid)) |
| 607 | goto out_unlock_free; | 660 | goto out_unlock_free; |
| 608 | 661 | ||
| 609 | for (;;) { | 662 | for (;;) { |
| @@ -694,17 +747,19 @@ asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz, | |||
| 694 | struct msg_queue *msq; | 747 | struct msg_queue *msq; |
| 695 | struct msg_msg *msg; | 748 | struct msg_msg *msg; |
| 696 | int mode; | 749 | int mode; |
| 750 | struct ipc_namespace *ns; | ||
| 697 | 751 | ||
| 698 | if (msqid < 0 || (long) msgsz < 0) | 752 | if (msqid < 0 || (long) msgsz < 0) |
| 699 | return -EINVAL; | 753 | return -EINVAL; |
| 700 | mode = convert_mode(&msgtyp, msgflg); | 754 | mode = convert_mode(&msgtyp, msgflg); |
| 755 | ns = current->nsproxy->ipc_ns; | ||
| 701 | 756 | ||
| 702 | msq = msg_lock(msqid); | 757 | msq = msg_lock(ns, msqid); |
| 703 | if (msq == NULL) | 758 | if (msq == NULL) |
| 704 | return -EINVAL; | 759 | return -EINVAL; |
| 705 | 760 | ||
| 706 | msg = ERR_PTR(-EIDRM); | 761 | msg = ERR_PTR(-EIDRM); |
| 707 | if (msg_checkid(msq, msqid)) | 762 | if (msg_checkid(ns, msq, msqid)) |
| 708 | goto out_unlock; | 763 | goto out_unlock; |
| 709 | 764 | ||
| 710 | for (;;) { | 765 | for (;;) { |
| @@ -64,6 +64,10 @@ | |||
| 64 | * | 64 | * |
| 65 | * support for audit of ipc object properties and permission changes | 65 | * support for audit of ipc object properties and permission changes |
| 66 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> | 66 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
| 67 | * | ||
| 68 | * namespaces support | ||
| 69 | * OpenVZ, SWsoft Inc. | ||
| 70 | * Pavel Emelianov <xemul@openvz.org> | ||
| 67 | */ | 71 | */ |
| 68 | 72 | ||
| 69 | #include <linux/slab.h> | 73 | #include <linux/slab.h> |
| @@ -78,22 +82,25 @@ | |||
| 78 | #include <linux/capability.h> | 82 | #include <linux/capability.h> |
| 79 | #include <linux/seq_file.h> | 83 | #include <linux/seq_file.h> |
| 80 | #include <linux/mutex.h> | 84 | #include <linux/mutex.h> |
| 85 | #include <linux/nsproxy.h> | ||
| 81 | 86 | ||
| 82 | #include <asm/uaccess.h> | 87 | #include <asm/uaccess.h> |
| 83 | #include "util.h" | 88 | #include "util.h" |
| 84 | 89 | ||
| 90 | #define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) | ||
| 91 | |||
| 92 | #define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id)) | ||
| 93 | #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) | ||
| 94 | #define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id)) | ||
| 95 | #define sem_checkid(ns, sma, semid) \ | ||
| 96 | ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid) | ||
| 97 | #define sem_buildid(ns, id, seq) \ | ||
| 98 | ipc_buildid(&sem_ids(ns), id, seq) | ||
| 85 | 99 | ||
| 86 | #define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id)) | 100 | static struct ipc_ids init_sem_ids; |
| 87 | #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) | ||
| 88 | #define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id)) | ||
| 89 | #define sem_checkid(sma, semid) \ | ||
| 90 | ipc_checkid(&sem_ids,&sma->sem_perm,semid) | ||
| 91 | #define sem_buildid(id, seq) \ | ||
| 92 | ipc_buildid(&sem_ids, id, seq) | ||
| 93 | static struct ipc_ids sem_ids; | ||
| 94 | 101 | ||
| 95 | static int newary (key_t, int, int); | 102 | static int newary(struct ipc_namespace *, key_t, int, int); |
| 96 | static void freeary (struct sem_array *sma, int id); | 103 | static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id); |
| 97 | #ifdef CONFIG_PROC_FS | 104 | #ifdef CONFIG_PROC_FS |
| 98 | static int sysvipc_sem_proc_show(struct seq_file *s, void *it); | 105 | static int sysvipc_sem_proc_show(struct seq_file *s, void *it); |
| 99 | #endif | 106 | #endif |
| @@ -110,22 +117,61 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it); | |||
| 110 | * | 117 | * |
| 111 | */ | 118 | */ |
| 112 | 119 | ||
| 113 | int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI}; | 120 | #define sc_semmsl sem_ctls[0] |
| 114 | #define sc_semmsl (sem_ctls[0]) | 121 | #define sc_semmns sem_ctls[1] |
| 115 | #define sc_semmns (sem_ctls[1]) | 122 | #define sc_semopm sem_ctls[2] |
| 116 | #define sc_semopm (sem_ctls[2]) | 123 | #define sc_semmni sem_ctls[3] |
| 117 | #define sc_semmni (sem_ctls[3]) | ||
| 118 | 124 | ||
| 119 | static int used_sems; | 125 | static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) |
| 126 | { | ||
| 127 | ns->ids[IPC_SEM_IDS] = ids; | ||
| 128 | ns->sc_semmsl = SEMMSL; | ||
| 129 | ns->sc_semmns = SEMMNS; | ||
| 130 | ns->sc_semopm = SEMOPM; | ||
| 131 | ns->sc_semmni = SEMMNI; | ||
| 132 | ns->used_sems = 0; | ||
| 133 | ipc_init_ids(ids, ns->sc_semmni); | ||
| 134 | } | ||
| 135 | |||
| 136 | #ifdef CONFIG_IPC_NS | ||
| 137 | int sem_init_ns(struct ipc_namespace *ns) | ||
| 138 | { | ||
| 139 | struct ipc_ids *ids; | ||
| 140 | |||
| 141 | ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); | ||
| 142 | if (ids == NULL) | ||
| 143 | return -ENOMEM; | ||
| 144 | |||
| 145 | __sem_init_ns(ns, ids); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | void sem_exit_ns(struct ipc_namespace *ns) | ||
| 150 | { | ||
| 151 | int i; | ||
| 152 | struct sem_array *sma; | ||
| 153 | |||
| 154 | mutex_lock(&sem_ids(ns).mutex); | ||
| 155 | for (i = 0; i <= sem_ids(ns).max_id; i++) { | ||
| 156 | sma = sem_lock(ns, i); | ||
| 157 | if (sma == NULL) | ||
| 158 | continue; | ||
| 159 | |||
| 160 | freeary(ns, sma, i); | ||
| 161 | } | ||
| 162 | mutex_unlock(&sem_ids(ns).mutex); | ||
| 163 | |||
| 164 | kfree(ns->ids[IPC_SEM_IDS]); | ||
| 165 | ns->ids[IPC_SEM_IDS] = NULL; | ||
| 166 | } | ||
| 167 | #endif | ||
| 120 | 168 | ||
| 121 | void __init sem_init (void) | 169 | void __init sem_init (void) |
| 122 | { | 170 | { |
| 123 | used_sems = 0; | 171 | __sem_init_ns(&init_ipc_ns, &init_sem_ids); |
| 124 | ipc_init_ids(&sem_ids,sc_semmni); | ||
| 125 | ipc_init_proc_interface("sysvipc/sem", | 172 | ipc_init_proc_interface("sysvipc/sem", |
| 126 | " key semid perms nsems uid gid cuid cgid otime ctime\n", | 173 | " key semid perms nsems uid gid cuid cgid otime ctime\n", |
| 127 | &sem_ids, | 174 | IPC_SEM_IDS, sysvipc_sem_proc_show); |
| 128 | sysvipc_sem_proc_show); | ||
| 129 | } | 175 | } |
| 130 | 176 | ||
| 131 | /* | 177 | /* |
| @@ -162,7 +208,7 @@ void __init sem_init (void) | |||
| 162 | */ | 208 | */ |
| 163 | #define IN_WAKEUP 1 | 209 | #define IN_WAKEUP 1 |
| 164 | 210 | ||
| 165 | static int newary (key_t key, int nsems, int semflg) | 211 | static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg) |
| 166 | { | 212 | { |
| 167 | int id; | 213 | int id; |
| 168 | int retval; | 214 | int retval; |
| @@ -171,7 +217,7 @@ static int newary (key_t key, int nsems, int semflg) | |||
| 171 | 217 | ||
| 172 | if (!nsems) | 218 | if (!nsems) |
| 173 | return -EINVAL; | 219 | return -EINVAL; |
| 174 | if (used_sems + nsems > sc_semmns) | 220 | if (ns->used_sems + nsems > ns->sc_semmns) |
| 175 | return -ENOSPC; | 221 | return -ENOSPC; |
| 176 | 222 | ||
| 177 | size = sizeof (*sma) + nsems * sizeof (struct sem); | 223 | size = sizeof (*sma) + nsems * sizeof (struct sem); |
| @@ -191,15 +237,15 @@ static int newary (key_t key, int nsems, int semflg) | |||
| 191 | return retval; | 237 | return retval; |
| 192 | } | 238 | } |
| 193 | 239 | ||
| 194 | id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); | 240 | id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); |
| 195 | if(id == -1) { | 241 | if(id == -1) { |
| 196 | security_sem_free(sma); | 242 | security_sem_free(sma); |
| 197 | ipc_rcu_putref(sma); | 243 | ipc_rcu_putref(sma); |
| 198 | return -ENOSPC; | 244 | return -ENOSPC; |
| 199 | } | 245 | } |
| 200 | used_sems += nsems; | 246 | ns->used_sems += nsems; |
| 201 | 247 | ||
| 202 | sma->sem_id = sem_buildid(id, sma->sem_perm.seq); | 248 | sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq); |
| 203 | sma->sem_base = (struct sem *) &sma[1]; | 249 | sma->sem_base = (struct sem *) &sma[1]; |
| 204 | /* sma->sem_pending = NULL; */ | 250 | /* sma->sem_pending = NULL; */ |
| 205 | sma->sem_pending_last = &sma->sem_pending; | 251 | sma->sem_pending_last = &sma->sem_pending; |
| @@ -215,29 +261,32 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) | |||
| 215 | { | 261 | { |
| 216 | int id, err = -EINVAL; | 262 | int id, err = -EINVAL; |
| 217 | struct sem_array *sma; | 263 | struct sem_array *sma; |
| 264 | struct ipc_namespace *ns; | ||
| 218 | 265 | ||
| 219 | if (nsems < 0 || nsems > sc_semmsl) | 266 | ns = current->nsproxy->ipc_ns; |
| 267 | |||
| 268 | if (nsems < 0 || nsems > ns->sc_semmsl) | ||
| 220 | return -EINVAL; | 269 | return -EINVAL; |
| 221 | mutex_lock(&sem_ids.mutex); | 270 | mutex_lock(&sem_ids(ns).mutex); |
| 222 | 271 | ||
| 223 | if (key == IPC_PRIVATE) { | 272 | if (key == IPC_PRIVATE) { |
| 224 | err = newary(key, nsems, semflg); | 273 | err = newary(ns, key, nsems, semflg); |
| 225 | } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */ | 274 | } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */ |
| 226 | if (!(semflg & IPC_CREAT)) | 275 | if (!(semflg & IPC_CREAT)) |
| 227 | err = -ENOENT; | 276 | err = -ENOENT; |
| 228 | else | 277 | else |
| 229 | err = newary(key, nsems, semflg); | 278 | err = newary(ns, key, nsems, semflg); |
| 230 | } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { | 279 | } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { |
| 231 | err = -EEXIST; | 280 | err = -EEXIST; |
| 232 | } else { | 281 | } else { |
| 233 | sma = sem_lock(id); | 282 | sma = sem_lock(ns, id); |
| 234 | BUG_ON(sma==NULL); | 283 | BUG_ON(sma==NULL); |
| 235 | if (nsems > sma->sem_nsems) | 284 | if (nsems > sma->sem_nsems) |
| 236 | err = -EINVAL; | 285 | err = -EINVAL; |
| 237 | else if (ipcperms(&sma->sem_perm, semflg)) | 286 | else if (ipcperms(&sma->sem_perm, semflg)) |
| 238 | err = -EACCES; | 287 | err = -EACCES; |
| 239 | else { | 288 | else { |
| 240 | int semid = sem_buildid(id, sma->sem_perm.seq); | 289 | int semid = sem_buildid(ns, id, sma->sem_perm.seq); |
| 241 | err = security_sem_associate(sma, semflg); | 290 | err = security_sem_associate(sma, semflg); |
| 242 | if (!err) | 291 | if (!err) |
| 243 | err = semid; | 292 | err = semid; |
| @@ -245,7 +294,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) | |||
| 245 | sem_unlock(sma); | 294 | sem_unlock(sma); |
| 246 | } | 295 | } |
| 247 | 296 | ||
| 248 | mutex_unlock(&sem_ids.mutex); | 297 | mutex_unlock(&sem_ids(ns).mutex); |
| 249 | return err; | 298 | return err; |
| 250 | } | 299 | } |
| 251 | 300 | ||
| @@ -444,7 +493,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum) | |||
| 444 | * the spinlock for this semaphore set hold. sem_ids.mutex remains locked | 493 | * the spinlock for this semaphore set hold. sem_ids.mutex remains locked |
| 445 | * on exit. | 494 | * on exit. |
| 446 | */ | 495 | */ |
| 447 | static void freeary (struct sem_array *sma, int id) | 496 | static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id) |
| 448 | { | 497 | { |
| 449 | struct sem_undo *un; | 498 | struct sem_undo *un; |
| 450 | struct sem_queue *q; | 499 | struct sem_queue *q; |
| @@ -472,10 +521,10 @@ static void freeary (struct sem_array *sma, int id) | |||
| 472 | } | 521 | } |
| 473 | 522 | ||
| 474 | /* Remove the semaphore set from the ID array*/ | 523 | /* Remove the semaphore set from the ID array*/ |
| 475 | sma = sem_rmid(id); | 524 | sma = sem_rmid(ns, id); |
| 476 | sem_unlock(sma); | 525 | sem_unlock(sma); |
| 477 | 526 | ||
| 478 | used_sems -= sma->sem_nsems; | 527 | ns->used_sems -= sma->sem_nsems; |
| 479 | size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); | 528 | size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); |
| 480 | security_sem_free(sma); | 529 | security_sem_free(sma); |
| 481 | ipc_rcu_putref(sma); | 530 | ipc_rcu_putref(sma); |
| @@ -503,7 +552,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, | |||
| 503 | } | 552 | } |
| 504 | } | 553 | } |
| 505 | 554 | ||
| 506 | static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg) | 555 | static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, |
| 556 | int cmd, int version, union semun arg) | ||
| 507 | { | 557 | { |
| 508 | int err = -EINVAL; | 558 | int err = -EINVAL; |
| 509 | struct sem_array *sma; | 559 | struct sem_array *sma; |
| @@ -520,24 +570,24 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu | |||
| 520 | return err; | 570 | return err; |
| 521 | 571 | ||
| 522 | memset(&seminfo,0,sizeof(seminfo)); | 572 | memset(&seminfo,0,sizeof(seminfo)); |
| 523 | seminfo.semmni = sc_semmni; | 573 | seminfo.semmni = ns->sc_semmni; |
| 524 | seminfo.semmns = sc_semmns; | 574 | seminfo.semmns = ns->sc_semmns; |
| 525 | seminfo.semmsl = sc_semmsl; | 575 | seminfo.semmsl = ns->sc_semmsl; |
| 526 | seminfo.semopm = sc_semopm; | 576 | seminfo.semopm = ns->sc_semopm; |
| 527 | seminfo.semvmx = SEMVMX; | 577 | seminfo.semvmx = SEMVMX; |
| 528 | seminfo.semmnu = SEMMNU; | 578 | seminfo.semmnu = SEMMNU; |
| 529 | seminfo.semmap = SEMMAP; | 579 | seminfo.semmap = SEMMAP; |
| 530 | seminfo.semume = SEMUME; | 580 | seminfo.semume = SEMUME; |
| 531 | mutex_lock(&sem_ids.mutex); | 581 | mutex_lock(&sem_ids(ns).mutex); |
| 532 | if (cmd == SEM_INFO) { | 582 | if (cmd == SEM_INFO) { |
| 533 | seminfo.semusz = sem_ids.in_use; | 583 | seminfo.semusz = sem_ids(ns).in_use; |
| 534 | seminfo.semaem = used_sems; | 584 | seminfo.semaem = ns->used_sems; |
| 535 | } else { | 585 | } else { |
| 536 | seminfo.semusz = SEMUSZ; | 586 | seminfo.semusz = SEMUSZ; |
| 537 | seminfo.semaem = SEMAEM; | 587 | seminfo.semaem = SEMAEM; |
| 538 | } | 588 | } |
| 539 | max_id = sem_ids.max_id; | 589 | max_id = sem_ids(ns).max_id; |
| 540 | mutex_unlock(&sem_ids.mutex); | 590 | mutex_unlock(&sem_ids(ns).mutex); |
| 541 | if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) | 591 | if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) |
| 542 | return -EFAULT; | 592 | return -EFAULT; |
| 543 | return (max_id < 0) ? 0: max_id; | 593 | return (max_id < 0) ? 0: max_id; |
| @@ -547,12 +597,12 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu | |||
| 547 | struct semid64_ds tbuf; | 597 | struct semid64_ds tbuf; |
| 548 | int id; | 598 | int id; |
| 549 | 599 | ||
| 550 | if(semid >= sem_ids.entries->size) | 600 | if(semid >= sem_ids(ns).entries->size) |
| 551 | return -EINVAL; | 601 | return -EINVAL; |
| 552 | 602 | ||
| 553 | memset(&tbuf,0,sizeof(tbuf)); | 603 | memset(&tbuf,0,sizeof(tbuf)); |
| 554 | 604 | ||
| 555 | sma = sem_lock(semid); | 605 | sma = sem_lock(ns, semid); |
| 556 | if(sma == NULL) | 606 | if(sma == NULL) |
| 557 | return -EINVAL; | 607 | return -EINVAL; |
| 558 | 608 | ||
| @@ -564,7 +614,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu | |||
| 564 | if (err) | 614 | if (err) |
| 565 | goto out_unlock; | 615 | goto out_unlock; |
| 566 | 616 | ||
| 567 | id = sem_buildid(semid, sma->sem_perm.seq); | 617 | id = sem_buildid(ns, semid, sma->sem_perm.seq); |
| 568 | 618 | ||
| 569 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); | 619 | kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); |
| 570 | tbuf.sem_otime = sma->sem_otime; | 620 | tbuf.sem_otime = sma->sem_otime; |
| @@ -584,7 +634,8 @@ out_unlock: | |||
| 584 | return err; | 634 | return err; |
| 585 | } | 635 | } |
| 586 | 636 | ||
| 587 | static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg) | 637 | static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, |
| 638 | int cmd, int version, union semun arg) | ||
| 588 | { | 639 | { |
| 589 | struct sem_array *sma; | 640 | struct sem_array *sma; |
| 590 | struct sem* curr; | 641 | struct sem* curr; |
| @@ -593,14 +644,14 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun | |||
| 593 | ushort* sem_io = fast_sem_io; | 644 | ushort* sem_io = fast_sem_io; |
| 594 | int nsems; | 645 | int nsems; |
| 595 | 646 | ||
| 596 | sma = sem_lock(semid); | 647 | sma = sem_lock(ns, semid); |
| 597 | if(sma==NULL) | 648 | if(sma==NULL) |
| 598 | return -EINVAL; | 649 | return -EINVAL; |
| 599 | 650 | ||
| 600 | nsems = sma->sem_nsems; | 651 | nsems = sma->sem_nsems; |
| 601 | 652 | ||
| 602 | err=-EIDRM; | 653 | err=-EIDRM; |
| 603 | if (sem_checkid(sma,semid)) | 654 | if (sem_checkid(ns,sma,semid)) |
| 604 | goto out_unlock; | 655 | goto out_unlock; |
| 605 | 656 | ||
| 606 | err = -EACCES; | 657 | err = -EACCES; |
| @@ -802,7 +853,8 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __ | |||
| 802 | } | 853 | } |
| 803 | } | 854 | } |
| 804 | 855 | ||
| 805 | static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg) | 856 | static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, |
| 857 | int cmd, int version, union semun arg) | ||
| 806 | { | 858 | { |
| 807 | struct sem_array *sma; | 859 | struct sem_array *sma; |
| 808 | int err; | 860 | int err; |
| @@ -813,11 +865,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
| 813 | if(copy_semid_from_user (&setbuf, arg.buf, version)) | 865 | if(copy_semid_from_user (&setbuf, arg.buf, version)) |
| 814 | return -EFAULT; | 866 | return -EFAULT; |
| 815 | } | 867 | } |
| 816 | sma = sem_lock(semid); | 868 | sma = sem_lock(ns, semid); |
| 817 | if(sma==NULL) | 869 | if(sma==NULL) |
| 818 | return -EINVAL; | 870 | return -EINVAL; |
| 819 | 871 | ||
| 820 | if (sem_checkid(sma,semid)) { | 872 | if (sem_checkid(ns,sma,semid)) { |
| 821 | err=-EIDRM; | 873 | err=-EIDRM; |
| 822 | goto out_unlock; | 874 | goto out_unlock; |
| 823 | } | 875 | } |
| @@ -844,7 +896,7 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun | |||
| 844 | 896 | ||
| 845 | switch(cmd){ | 897 | switch(cmd){ |
| 846 | case IPC_RMID: | 898 | case IPC_RMID: |
| 847 | freeary(sma, semid); | 899 | freeary(ns, sma, semid); |
| 848 | err = 0; | 900 | err = 0; |
| 849 | break; | 901 | break; |
| 850 | case IPC_SET: | 902 | case IPC_SET: |
| @@ -872,17 +924,19 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) | |||
| 872 | { | 924 | { |
| 873 | int err = -EINVAL; | 925 | int err = -EINVAL; |
| 874 | int version; | 926 | int version; |
| 927 | struct ipc_namespace *ns; | ||
| 875 | 928 | ||
| 876 | if (semid < 0) | 929 | if (semid < 0) |
| 877 | return -EINVAL; | 930 | return -EINVAL; |
| 878 | 931 | ||
| 879 | version = ipc_parse_version(&cmd); | 932 | version = ipc_parse_version(&cmd); |
| 933 | ns = current->nsproxy->ipc_ns; | ||
| 880 | 934 | ||
| 881 | switch(cmd) { | 935 | switch(cmd) { |
| 882 | case IPC_INFO: | 936 | case IPC_INFO: |
| 883 | case SEM_INFO: | 937 | case SEM_INFO: |
| 884 | case SEM_STAT: | 938 | case SEM_STAT: |
| 885 | err = semctl_nolock(semid,semnum,cmd,version,arg); | 939 | err = semctl_nolock(ns,semid,semnum,cmd,version,arg); |
| 886 | return err; | 940 | return err; |
| 887 | case GETALL: | 941 | case GETALL: |
| 888 | case GETVAL: | 942 | case GETVAL: |
| @@ -892,13 +946,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) | |||
| 892 | case IPC_STAT: | 946 | case IPC_STAT: |
| 893 | case SETVAL: | 947 | case SETVAL: |
| 894 | case SETALL: | 948 | case SETALL: |
| 895 | err = semctl_main(semid,semnum,cmd,version,arg); | 949 | err = semctl_main(ns,semid,semnum,cmd,version,arg); |
| 896 | return err; | 950 | return err; |
| 897 | case IPC_RMID: | 951 | case IPC_RMID: |
| 898 | case IPC_SET: | 952 | case IPC_SET: |
| 899 | mutex_lock(&sem_ids.mutex); | 953 | mutex_lock(&sem_ids(ns).mutex); |
| 900 | err = semctl_down(semid,semnum,cmd,version,arg); | 954 | err = semctl_down(ns,semid,semnum,cmd,version,arg); |
| 901 | mutex_unlock(&sem_ids.mutex); | 955 | mutex_unlock(&sem_ids(ns).mutex); |
| 902 | return err; | 956 | return err; |
| 903 | default: | 957 | default: |
| 904 | return -EINVAL; | 958 | return -EINVAL; |
| @@ -949,15 +1003,12 @@ static inline void unlock_semundo(void) | |||
| 949 | static inline int get_undo_list(struct sem_undo_list **undo_listp) | 1003 | static inline int get_undo_list(struct sem_undo_list **undo_listp) |
| 950 | { | 1004 | { |
| 951 | struct sem_undo_list *undo_list; | 1005 | struct sem_undo_list *undo_list; |
| 952 | int size; | ||
| 953 | 1006 | ||
| 954 | undo_list = current->sysvsem.undo_list; | 1007 | undo_list = current->sysvsem.undo_list; |
| 955 | if (!undo_list) { | 1008 | if (!undo_list) { |
| 956 | size = sizeof(struct sem_undo_list); | 1009 | undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL); |
| 957 | undo_list = (struct sem_undo_list *) kmalloc(size, GFP_KERNEL); | ||
| 958 | if (undo_list == NULL) | 1010 | if (undo_list == NULL) |
| 959 | return -ENOMEM; | 1011 | return -ENOMEM; |
| 960 | memset(undo_list, 0, size); | ||
| 961 | spin_lock_init(&undo_list->lock); | 1012 | spin_lock_init(&undo_list->lock); |
| 962 | atomic_set(&undo_list->refcnt, 1); | 1013 | atomic_set(&undo_list->refcnt, 1); |
| 963 | current->sysvsem.undo_list = undo_list; | 1014 | current->sysvsem.undo_list = undo_list; |
| @@ -986,7 +1037,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid) | |||
| 986 | return un; | 1037 | return un; |
| 987 | } | 1038 | } |
| 988 | 1039 | ||
| 989 | static struct sem_undo *find_undo(int semid) | 1040 | static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid) |
| 990 | { | 1041 | { |
| 991 | struct sem_array *sma; | 1042 | struct sem_array *sma; |
| 992 | struct sem_undo_list *ulp; | 1043 | struct sem_undo_list *ulp; |
| @@ -1005,12 +1056,12 @@ static struct sem_undo *find_undo(int semid) | |||
| 1005 | goto out; | 1056 | goto out; |
| 1006 | 1057 | ||
| 1007 | /* no undo structure around - allocate one. */ | 1058 | /* no undo structure around - allocate one. */ |
| 1008 | sma = sem_lock(semid); | 1059 | sma = sem_lock(ns, semid); |
| 1009 | un = ERR_PTR(-EINVAL); | 1060 | un = ERR_PTR(-EINVAL); |
| 1010 | if(sma==NULL) | 1061 | if(sma==NULL) |
| 1011 | goto out; | 1062 | goto out; |
| 1012 | un = ERR_PTR(-EIDRM); | 1063 | un = ERR_PTR(-EIDRM); |
| 1013 | if (sem_checkid(sma,semid)) { | 1064 | if (sem_checkid(ns,sma,semid)) { |
| 1014 | sem_unlock(sma); | 1065 | sem_unlock(sma); |
| 1015 | goto out; | 1066 | goto out; |
| 1016 | } | 1067 | } |
| @@ -1070,10 +1121,13 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, | |||
| 1070 | int undos = 0, alter = 0, max; | 1121 | int undos = 0, alter = 0, max; |
| 1071 | struct sem_queue queue; | 1122 | struct sem_queue queue; |
| 1072 | unsigned long jiffies_left = 0; | 1123 | unsigned long jiffies_left = 0; |
| 1124 | struct ipc_namespace *ns; | ||
| 1125 | |||
| 1126 | ns = current->nsproxy->ipc_ns; | ||
| 1073 | 1127 | ||
| 1074 | if (nsops < 1 || semid < 0) | 1128 | if (nsops < 1 || semid < 0) |
| 1075 | return -EINVAL; | 1129 | return -EINVAL; |
| 1076 | if (nsops > sc_semopm) | 1130 | if (nsops > ns->sc_semopm) |
| 1077 | return -E2BIG; | 1131 | return -E2BIG; |
| 1078 | if(nsops > SEMOPM_FAST) { | 1132 | if(nsops > SEMOPM_FAST) { |
| 1079 | sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); | 1133 | sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); |
| @@ -1109,7 +1163,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, | |||
| 1109 | 1163 | ||
| 1110 | retry_undos: | 1164 | retry_undos: |
| 1111 | if (undos) { | 1165 | if (undos) { |
| 1112 | un = find_undo(semid); | 1166 | un = find_undo(ns, semid); |
| 1113 | if (IS_ERR(un)) { | 1167 | if (IS_ERR(un)) { |
| 1114 | error = PTR_ERR(un); | 1168 | error = PTR_ERR(un); |
| 1115 | goto out_free; | 1169 | goto out_free; |
| @@ -1117,12 +1171,12 @@ retry_undos: | |||
| 1117 | } else | 1171 | } else |
| 1118 | un = NULL; | 1172 | un = NULL; |
| 1119 | 1173 | ||
| 1120 | sma = sem_lock(semid); | 1174 | sma = sem_lock(ns, semid); |
| 1121 | error=-EINVAL; | 1175 | error=-EINVAL; |
| 1122 | if(sma==NULL) | 1176 | if(sma==NULL) |
| 1123 | goto out_free; | 1177 | goto out_free; |
| 1124 | error = -EIDRM; | 1178 | error = -EIDRM; |
| 1125 | if (sem_checkid(sma,semid)) | 1179 | if (sem_checkid(ns,sma,semid)) |
| 1126 | goto out_unlock_free; | 1180 | goto out_unlock_free; |
| 1127 | /* | 1181 | /* |
| 1128 | * semid identifies are not unique - find_undo may have | 1182 | * semid identifies are not unique - find_undo may have |
| @@ -1190,7 +1244,7 @@ retry_undos: | |||
| 1190 | goto out_free; | 1244 | goto out_free; |
| 1191 | } | 1245 | } |
| 1192 | 1246 | ||
| 1193 | sma = sem_lock(semid); | 1247 | sma = sem_lock(ns, semid); |
| 1194 | if(sma==NULL) { | 1248 | if(sma==NULL) { |
| 1195 | BUG_ON(queue.prev != NULL); | 1249 | BUG_ON(queue.prev != NULL); |
| 1196 | error = -EIDRM; | 1250 | error = -EIDRM; |
| @@ -1267,6 +1321,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 1267 | { | 1321 | { |
| 1268 | struct sem_undo_list *undo_list; | 1322 | struct sem_undo_list *undo_list; |
| 1269 | struct sem_undo *u, **up; | 1323 | struct sem_undo *u, **up; |
| 1324 | struct ipc_namespace *ns; | ||
| 1270 | 1325 | ||
| 1271 | undo_list = tsk->sysvsem.undo_list; | 1326 | undo_list = tsk->sysvsem.undo_list; |
| 1272 | if (!undo_list) | 1327 | if (!undo_list) |
| @@ -1275,6 +1330,7 @@ void exit_sem(struct task_struct *tsk) | |||
| 1275 | if (!atomic_dec_and_test(&undo_list->refcnt)) | 1330 | if (!atomic_dec_and_test(&undo_list->refcnt)) |
| 1276 | return; | 1331 | return; |
| 1277 | 1332 | ||
| 1333 | ns = tsk->nsproxy->ipc_ns; | ||
| 1278 | /* There's no need to hold the semundo list lock, as current | 1334 | /* There's no need to hold the semundo list lock, as current |
| 1279 | * is the last task exiting for this undo list. | 1335 | * is the last task exiting for this undo list. |
| 1280 | */ | 1336 | */ |
| @@ -1288,14 +1344,14 @@ void exit_sem(struct task_struct *tsk) | |||
| 1288 | 1344 | ||
| 1289 | if(semid == -1) | 1345 | if(semid == -1) |
| 1290 | continue; | 1346 | continue; |
| 1291 | sma = sem_lock(semid); | 1347 | sma = sem_lock(ns, semid); |
| 1292 | if (sma == NULL) | 1348 | if (sma == NULL) |
| 1293 | continue; | 1349 | continue; |
| 1294 | 1350 | ||
| 1295 | if (u->semid == -1) | 1351 | if (u->semid == -1) |
| 1296 | goto next_entry; | 1352 | goto next_entry; |
| 1297 | 1353 | ||
| 1298 | BUG_ON(sem_checkid(sma,u->semid)); | 1354 | BUG_ON(sem_checkid(ns,sma,u->semid)); |
| 1299 | 1355 | ||
| 1300 | /* remove u from the sma->undo list */ | 1356 | /* remove u from the sma->undo list */ |
| 1301 | for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { | 1357 | for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { |
| @@ -15,6 +15,10 @@ | |||
| 15 | * | 15 | * |
| 16 | * support for audit of ipc object properties and permission changes | 16 | * support for audit of ipc object properties and permission changes |
| 17 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> | 17 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
| 18 | * | ||
| 19 | * namespaces support | ||
| 20 | * OpenVZ, SWsoft Inc. | ||
| 21 | * Pavel Emelianov <xemul@openvz.org> | ||
| 18 | */ | 22 | */ |
| 19 | 23 | ||
| 20 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| @@ -32,6 +36,7 @@ | |||
| 32 | #include <linux/ptrace.h> | 36 | #include <linux/ptrace.h> |
| 33 | #include <linux/seq_file.h> | 37 | #include <linux/seq_file.h> |
| 34 | #include <linux/mutex.h> | 38 | #include <linux/mutex.h> |
| 39 | #include <linux/nsproxy.h> | ||
| 35 | 40 | ||
| 36 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
| 37 | 42 | ||
| @@ -40,59 +45,115 @@ | |||
| 40 | static struct file_operations shm_file_operations; | 45 | static struct file_operations shm_file_operations; |
| 41 | static struct vm_operations_struct shm_vm_ops; | 46 | static struct vm_operations_struct shm_vm_ops; |
| 42 | 47 | ||
| 43 | static struct ipc_ids shm_ids; | 48 | static struct ipc_ids init_shm_ids; |
| 49 | |||
| 50 | #define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) | ||
| 44 | 51 | ||
| 45 | #define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id)) | 52 | #define shm_lock(ns, id) \ |
| 46 | #define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm) | 53 | ((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id)) |
| 47 | #define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id)) | 54 | #define shm_unlock(shp) \ |
| 48 | #define shm_buildid(id, seq) \ | 55 | ipc_unlock(&(shp)->shm_perm) |
| 49 | ipc_buildid(&shm_ids, id, seq) | 56 | #define shm_get(ns, id) \ |
| 57 | ((struct shmid_kernel*)ipc_get(&shm_ids(ns),id)) | ||
| 58 | #define shm_buildid(ns, id, seq) \ | ||
| 59 | ipc_buildid(&shm_ids(ns), id, seq) | ||
| 50 | 60 | ||
| 51 | static int newseg (key_t key, int shmflg, size_t size); | 61 | static int newseg (struct ipc_namespace *ns, key_t key, |
| 62 | int shmflg, size_t size); | ||
| 52 | static void shm_open (struct vm_area_struct *shmd); | 63 | static void shm_open (struct vm_area_struct *shmd); |
| 53 | static void shm_close (struct vm_area_struct *shmd); | 64 | static void shm_close (struct vm_area_struct *shmd); |
| 65 | static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); | ||
| 54 | #ifdef CONFIG_PROC_FS | 66 | #ifdef CONFIG_PROC_FS |
| 55 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); | 67 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it); |
| 56 | #endif | 68 | #endif |
| 57 | 69 | ||
| 58 | size_t shm_ctlmax = SHMMAX; | 70 | static void __ipc_init __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) |
| 59 | size_t shm_ctlall = SHMALL; | 71 | { |
| 60 | int shm_ctlmni = SHMMNI; | 72 | ns->ids[IPC_SHM_IDS] = ids; |
| 73 | ns->shm_ctlmax = SHMMAX; | ||
| 74 | ns->shm_ctlall = SHMALL; | ||
| 75 | ns->shm_ctlmni = SHMMNI; | ||
| 76 | ns->shm_tot = 0; | ||
| 77 | ipc_init_ids(ids, 1); | ||
| 78 | } | ||
| 79 | |||
| 80 | static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp) | ||
| 81 | { | ||
| 82 | if (shp->shm_nattch){ | ||
| 83 | shp->shm_perm.mode |= SHM_DEST; | ||
| 84 | /* Do not find it any more */ | ||
| 85 | shp->shm_perm.key = IPC_PRIVATE; | ||
| 86 | shm_unlock(shp); | ||
| 87 | } else | ||
| 88 | shm_destroy(ns, shp); | ||
| 89 | } | ||
| 90 | |||
| 91 | #ifdef CONFIG_IPC_NS | ||
| 92 | int shm_init_ns(struct ipc_namespace *ns) | ||
| 93 | { | ||
| 94 | struct ipc_ids *ids; | ||
| 95 | |||
| 96 | ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); | ||
| 97 | if (ids == NULL) | ||
| 98 | return -ENOMEM; | ||
| 61 | 99 | ||
| 62 | static int shm_tot; /* total number of shared memory pages */ | 100 | __shm_init_ns(ns, ids); |
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | void shm_exit_ns(struct ipc_namespace *ns) | ||
| 105 | { | ||
| 106 | int i; | ||
| 107 | struct shmid_kernel *shp; | ||
| 108 | |||
| 109 | mutex_lock(&shm_ids(ns).mutex); | ||
| 110 | for (i = 0; i <= shm_ids(ns).max_id; i++) { | ||
| 111 | shp = shm_lock(ns, i); | ||
| 112 | if (shp == NULL) | ||
| 113 | continue; | ||
| 114 | |||
| 115 | do_shm_rmid(ns, shp); | ||
| 116 | } | ||
| 117 | mutex_unlock(&shm_ids(ns).mutex); | ||
| 118 | |||
| 119 | kfree(ns->ids[IPC_SHM_IDS]); | ||
| 120 | ns->ids[IPC_SHM_IDS] = NULL; | ||
| 121 | } | ||
| 122 | #endif | ||
| 63 | 123 | ||
| 64 | void __init shm_init (void) | 124 | void __init shm_init (void) |
| 65 | { | 125 | { |
| 66 | ipc_init_ids(&shm_ids, 1); | 126 | __shm_init_ns(&init_ipc_ns, &init_shm_ids); |
| 67 | ipc_init_proc_interface("sysvipc/shm", | 127 | ipc_init_proc_interface("sysvipc/shm", |
| 68 | " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", | 128 | " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", |
| 69 | &shm_ids, | 129 | IPC_SHM_IDS, sysvipc_shm_proc_show); |
| 70 | sysvipc_shm_proc_show); | ||
| 71 | } | 130 | } |
| 72 | 131 | ||
| 73 | static inline int shm_checkid(struct shmid_kernel *s, int id) | 132 | static inline int shm_checkid(struct ipc_namespace *ns, |
| 133 | struct shmid_kernel *s, int id) | ||
| 74 | { | 134 | { |
| 75 | if (ipc_checkid(&shm_ids,&s->shm_perm,id)) | 135 | if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id)) |
| 76 | return -EIDRM; | 136 | return -EIDRM; |
| 77 | return 0; | 137 | return 0; |
| 78 | } | 138 | } |
| 79 | 139 | ||
| 80 | static inline struct shmid_kernel *shm_rmid(int id) | 140 | static inline struct shmid_kernel *shm_rmid(struct ipc_namespace *ns, int id) |
| 81 | { | 141 | { |
| 82 | return (struct shmid_kernel *)ipc_rmid(&shm_ids,id); | 142 | return (struct shmid_kernel *)ipc_rmid(&shm_ids(ns), id); |
| 83 | } | 143 | } |
| 84 | 144 | ||
| 85 | static inline int shm_addid(struct shmid_kernel *shp) | 145 | static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp) |
| 86 | { | 146 | { |
| 87 | return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni); | 147 | return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); |
| 88 | } | 148 | } |
| 89 | 149 | ||
| 90 | 150 | ||
| 91 | 151 | ||
| 92 | static inline void shm_inc (int id) { | 152 | static inline void shm_inc(struct ipc_namespace *ns, int id) |
| 153 | { | ||
| 93 | struct shmid_kernel *shp; | 154 | struct shmid_kernel *shp; |
| 94 | 155 | ||
| 95 | shp = shm_lock(id); | 156 | shp = shm_lock(ns, id); |
| 96 | BUG_ON(!shp); | 157 | BUG_ON(!shp); |
| 97 | shp->shm_atim = get_seconds(); | 158 | shp->shm_atim = get_seconds(); |
| 98 | shp->shm_lprid = current->tgid; | 159 | shp->shm_lprid = current->tgid; |
| @@ -100,10 +161,13 @@ static inline void shm_inc (int id) { | |||
| 100 | shm_unlock(shp); | 161 | shm_unlock(shp); |
| 101 | } | 162 | } |
| 102 | 163 | ||
| 164 | #define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data)) | ||
| 165 | |||
| 103 | /* This is called by fork, once for every shm attach. */ | 166 | /* This is called by fork, once for every shm attach. */ |
| 104 | static void shm_open (struct vm_area_struct *shmd) | 167 | static void shm_open(struct vm_area_struct *shmd) |
| 105 | { | 168 | { |
| 106 | shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino); | 169 | shm_inc(shm_file_ns(shmd->vm_file), |
| 170 | shmd->vm_file->f_dentry->d_inode->i_ino); | ||
| 107 | } | 171 | } |
| 108 | 172 | ||
| 109 | /* | 173 | /* |
| @@ -114,10 +178,10 @@ static void shm_open (struct vm_area_struct *shmd) | |||
| 114 | * It has to be called with shp and shm_ids.mutex locked, | 178 | * It has to be called with shp and shm_ids.mutex locked, |
| 115 | * but returns with shp unlocked and freed. | 179 | * but returns with shp unlocked and freed. |
| 116 | */ | 180 | */ |
| 117 | static void shm_destroy (struct shmid_kernel *shp) | 181 | static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) |
| 118 | { | 182 | { |
| 119 | shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; | 183 | ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 120 | shm_rmid (shp->id); | 184 | shm_rmid(ns, shp->id); |
| 121 | shm_unlock(shp); | 185 | shm_unlock(shp); |
| 122 | if (!is_file_hugepages(shp->shm_file)) | 186 | if (!is_file_hugepages(shp->shm_file)) |
| 123 | shmem_lock(shp->shm_file, 0, shp->mlock_user); | 187 | shmem_lock(shp->shm_file, 0, shp->mlock_user); |
| @@ -140,20 +204,23 @@ static void shm_close (struct vm_area_struct *shmd) | |||
| 140 | struct file * file = shmd->vm_file; | 204 | struct file * file = shmd->vm_file; |
| 141 | int id = file->f_dentry->d_inode->i_ino; | 205 | int id = file->f_dentry->d_inode->i_ino; |
| 142 | struct shmid_kernel *shp; | 206 | struct shmid_kernel *shp; |
| 207 | struct ipc_namespace *ns; | ||
| 143 | 208 | ||
| 144 | mutex_lock(&shm_ids.mutex); | 209 | ns = shm_file_ns(file); |
| 210 | |||
| 211 | mutex_lock(&shm_ids(ns).mutex); | ||
| 145 | /* remove from the list of attaches of the shm segment */ | 212 | /* remove from the list of attaches of the shm segment */ |
| 146 | shp = shm_lock(id); | 213 | shp = shm_lock(ns, id); |
| 147 | BUG_ON(!shp); | 214 | BUG_ON(!shp); |
| 148 | shp->shm_lprid = current->tgid; | 215 | shp->shm_lprid = current->tgid; |
| 149 | shp->shm_dtim = get_seconds(); | 216 | shp->shm_dtim = get_seconds(); |
| 150 | shp->shm_nattch--; | 217 | shp->shm_nattch--; |
| 151 | if(shp->shm_nattch == 0 && | 218 | if(shp->shm_nattch == 0 && |
| 152 | shp->shm_perm.mode & SHM_DEST) | 219 | shp->shm_perm.mode & SHM_DEST) |
| 153 | shm_destroy (shp); | 220 | shm_destroy(ns, shp); |
| 154 | else | 221 | else |
| 155 | shm_unlock(shp); | 222 | shm_unlock(shp); |
| 156 | mutex_unlock(&shm_ids.mutex); | 223 | mutex_unlock(&shm_ids(ns).mutex); |
| 157 | } | 224 | } |
| 158 | 225 | ||
| 159 | static int shm_mmap(struct file * file, struct vm_area_struct * vma) | 226 | static int shm_mmap(struct file * file, struct vm_area_struct * vma) |
| @@ -165,14 +232,25 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma) | |||
| 165 | vma->vm_ops = &shm_vm_ops; | 232 | vma->vm_ops = &shm_vm_ops; |
| 166 | if (!(vma->vm_flags & VM_WRITE)) | 233 | if (!(vma->vm_flags & VM_WRITE)) |
| 167 | vma->vm_flags &= ~VM_MAYWRITE; | 234 | vma->vm_flags &= ~VM_MAYWRITE; |
| 168 | shm_inc(file->f_dentry->d_inode->i_ino); | 235 | shm_inc(shm_file_ns(file), file->f_dentry->d_inode->i_ino); |
| 169 | } | 236 | } |
| 170 | 237 | ||
| 171 | return ret; | 238 | return ret; |
| 172 | } | 239 | } |
| 173 | 240 | ||
| 241 | static int shm_release(struct inode *ino, struct file *file) | ||
| 242 | { | ||
| 243 | struct ipc_namespace *ns; | ||
| 244 | |||
| 245 | ns = shm_file_ns(file); | ||
| 246 | put_ipc_ns(ns); | ||
| 247 | shm_file_ns(file) = NULL; | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 174 | static struct file_operations shm_file_operations = { | 251 | static struct file_operations shm_file_operations = { |
| 175 | .mmap = shm_mmap, | 252 | .mmap = shm_mmap, |
| 253 | .release = shm_release, | ||
| 176 | #ifndef CONFIG_MMU | 254 | #ifndef CONFIG_MMU |
| 177 | .get_unmapped_area = shmem_get_unmapped_area, | 255 | .get_unmapped_area = shmem_get_unmapped_area, |
| 178 | #endif | 256 | #endif |
| @@ -188,7 +266,7 @@ static struct vm_operations_struct shm_vm_ops = { | |||
| 188 | #endif | 266 | #endif |
| 189 | }; | 267 | }; |
| 190 | 268 | ||
| 191 | static int newseg (key_t key, int shmflg, size_t size) | 269 | static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size) |
| 192 | { | 270 | { |
| 193 | int error; | 271 | int error; |
| 194 | struct shmid_kernel *shp; | 272 | struct shmid_kernel *shp; |
| @@ -197,10 +275,10 @@ static int newseg (key_t key, int shmflg, size_t size) | |||
| 197 | char name[13]; | 275 | char name[13]; |
| 198 | int id; | 276 | int id; |
| 199 | 277 | ||
| 200 | if (size < SHMMIN || size > shm_ctlmax) | 278 | if (size < SHMMIN || size > ns->shm_ctlmax) |
| 201 | return -EINVAL; | 279 | return -EINVAL; |
| 202 | 280 | ||
| 203 | if (shm_tot + numpages >= shm_ctlall) | 281 | if (ns->shm_tot + numpages >= ns->shm_ctlall) |
| 204 | return -ENOSPC; | 282 | return -ENOSPC; |
| 205 | 283 | ||
| 206 | shp = ipc_rcu_alloc(sizeof(*shp)); | 284 | shp = ipc_rcu_alloc(sizeof(*shp)); |
| @@ -239,7 +317,7 @@ static int newseg (key_t key, int shmflg, size_t size) | |||
| 239 | goto no_file; | 317 | goto no_file; |
| 240 | 318 | ||
| 241 | error = -ENOSPC; | 319 | error = -ENOSPC; |
| 242 | id = shm_addid(shp); | 320 | id = shm_addid(ns, shp); |
| 243 | if(id == -1) | 321 | if(id == -1) |
| 244 | goto no_id; | 322 | goto no_id; |
| 245 | 323 | ||
| @@ -249,15 +327,17 @@ static int newseg (key_t key, int shmflg, size_t size) | |||
| 249 | shp->shm_ctim = get_seconds(); | 327 | shp->shm_ctim = get_seconds(); |
| 250 | shp->shm_segsz = size; | 328 | shp->shm_segsz = size; |
| 251 | shp->shm_nattch = 0; | 329 | shp->shm_nattch = 0; |
| 252 | shp->id = shm_buildid(id,shp->shm_perm.seq); | 330 | shp->id = shm_buildid(ns, id, shp->shm_perm.seq); |
| 253 | shp->shm_file = file; | 331 | shp->shm_file = file; |
| 254 | file->f_dentry->d_inode->i_ino = shp->id; | 332 | file->f_dentry->d_inode->i_ino = shp->id; |
| 255 | 333 | ||
| 334 | shm_file_ns(file) = get_ipc_ns(ns); | ||
| 335 | |||
| 256 | /* Hugetlb ops would have already been assigned. */ | 336 | /* Hugetlb ops would have already been assigned. */ |
| 257 | if (!(shmflg & SHM_HUGETLB)) | 337 | if (!(shmflg & SHM_HUGETLB)) |
| 258 | file->f_op = &shm_file_operations; | 338 | file->f_op = &shm_file_operations; |
| 259 | 339 | ||
| 260 | shm_tot += numpages; | 340 | ns->shm_tot += numpages; |
| 261 | shm_unlock(shp); | 341 | shm_unlock(shp); |
| 262 | return shp->id; | 342 | return shp->id; |
| 263 | 343 | ||
| @@ -273,33 +353,36 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) | |||
| 273 | { | 353 | { |
| 274 | struct shmid_kernel *shp; | 354 | struct shmid_kernel *shp; |
| 275 | int err, id = 0; | 355 | int err, id = 0; |
| 356 | struct ipc_namespace *ns; | ||
| 357 | |||
| 358 | ns = current->nsproxy->ipc_ns; | ||
| 276 | 359 | ||
| 277 | mutex_lock(&shm_ids.mutex); | 360 | mutex_lock(&shm_ids(ns).mutex); |
| 278 | if (key == IPC_PRIVATE) { | 361 | if (key == IPC_PRIVATE) { |
| 279 | err = newseg(key, shmflg, size); | 362 | err = newseg(ns, key, shmflg, size); |
| 280 | } else if ((id = ipc_findkey(&shm_ids, key)) == -1) { | 363 | } else if ((id = ipc_findkey(&shm_ids(ns), key)) == -1) { |
| 281 | if (!(shmflg & IPC_CREAT)) | 364 | if (!(shmflg & IPC_CREAT)) |
| 282 | err = -ENOENT; | 365 | err = -ENOENT; |
| 283 | else | 366 | else |
| 284 | err = newseg(key, shmflg, size); | 367 | err = newseg(ns, key, shmflg, size); |
| 285 | } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) { | 368 | } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) { |
| 286 | err = -EEXIST; | 369 | err = -EEXIST; |
| 287 | } else { | 370 | } else { |
| 288 | shp = shm_lock(id); | 371 | shp = shm_lock(ns, id); |
| 289 | BUG_ON(shp==NULL); | 372 | BUG_ON(shp==NULL); |
| 290 | if (shp->shm_segsz < size) | 373 | if (shp->shm_segsz < size) |
| 291 | err = -EINVAL; | 374 | err = -EINVAL; |
| 292 | else if (ipcperms(&shp->shm_perm, shmflg)) | 375 | else if (ipcperms(&shp->shm_perm, shmflg)) |
| 293 | err = -EACCES; | 376 | err = -EACCES; |
| 294 | else { | 377 | else { |
| 295 | int shmid = shm_buildid(id, shp->shm_perm.seq); | 378 | int shmid = shm_buildid(ns, id, shp->shm_perm.seq); |
| 296 | err = security_shm_associate(shp, shmflg); | 379 | err = security_shm_associate(shp, shmflg); |
| 297 | if (!err) | 380 | if (!err) |
| 298 | err = shmid; | 381 | err = shmid; |
| 299 | } | 382 | } |
| 300 | shm_unlock(shp); | 383 | shm_unlock(shp); |
| 301 | } | 384 | } |
| 302 | mutex_unlock(&shm_ids.mutex); | 385 | mutex_unlock(&shm_ids(ns).mutex); |
| 303 | 386 | ||
| 304 | return err; | 387 | return err; |
| 305 | } | 388 | } |
| @@ -395,18 +478,19 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf | |||
| 395 | } | 478 | } |
| 396 | } | 479 | } |
| 397 | 480 | ||
| 398 | static void shm_get_stat(unsigned long *rss, unsigned long *swp) | 481 | static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, |
| 482 | unsigned long *swp) | ||
| 399 | { | 483 | { |
| 400 | int i; | 484 | int i; |
| 401 | 485 | ||
| 402 | *rss = 0; | 486 | *rss = 0; |
| 403 | *swp = 0; | 487 | *swp = 0; |
| 404 | 488 | ||
| 405 | for (i = 0; i <= shm_ids.max_id; i++) { | 489 | for (i = 0; i <= shm_ids(ns).max_id; i++) { |
| 406 | struct shmid_kernel *shp; | 490 | struct shmid_kernel *shp; |
| 407 | struct inode *inode; | 491 | struct inode *inode; |
| 408 | 492 | ||
| 409 | shp = shm_get(i); | 493 | shp = shm_get(ns, i); |
| 410 | if(!shp) | 494 | if(!shp) |
| 411 | continue; | 495 | continue; |
| 412 | 496 | ||
| @@ -430,6 +514,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 430 | struct shm_setbuf setbuf; | 514 | struct shm_setbuf setbuf; |
| 431 | struct shmid_kernel *shp; | 515 | struct shmid_kernel *shp; |
| 432 | int err, version; | 516 | int err, version; |
| 517 | struct ipc_namespace *ns; | ||
| 433 | 518 | ||
| 434 | if (cmd < 0 || shmid < 0) { | 519 | if (cmd < 0 || shmid < 0) { |
| 435 | err = -EINVAL; | 520 | err = -EINVAL; |
| @@ -437,6 +522,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 437 | } | 522 | } |
| 438 | 523 | ||
| 439 | version = ipc_parse_version(&cmd); | 524 | version = ipc_parse_version(&cmd); |
| 525 | ns = current->nsproxy->ipc_ns; | ||
| 440 | 526 | ||
| 441 | switch (cmd) { /* replace with proc interface ? */ | 527 | switch (cmd) { /* replace with proc interface ? */ |
| 442 | case IPC_INFO: | 528 | case IPC_INFO: |
| @@ -448,15 +534,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 448 | return err; | 534 | return err; |
| 449 | 535 | ||
| 450 | memset(&shminfo,0,sizeof(shminfo)); | 536 | memset(&shminfo,0,sizeof(shminfo)); |
| 451 | shminfo.shmmni = shminfo.shmseg = shm_ctlmni; | 537 | shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni; |
| 452 | shminfo.shmmax = shm_ctlmax; | 538 | shminfo.shmmax = ns->shm_ctlmax; |
| 453 | shminfo.shmall = shm_ctlall; | 539 | shminfo.shmall = ns->shm_ctlall; |
| 454 | 540 | ||
| 455 | shminfo.shmmin = SHMMIN; | 541 | shminfo.shmmin = SHMMIN; |
| 456 | if(copy_shminfo_to_user (buf, &shminfo, version)) | 542 | if(copy_shminfo_to_user (buf, &shminfo, version)) |
| 457 | return -EFAULT; | 543 | return -EFAULT; |
| 458 | /* reading a integer is always atomic */ | 544 | /* reading a integer is always atomic */ |
| 459 | err= shm_ids.max_id; | 545 | err= shm_ids(ns).max_id; |
| 460 | if(err<0) | 546 | if(err<0) |
| 461 | err = 0; | 547 | err = 0; |
| 462 | goto out; | 548 | goto out; |
| @@ -470,14 +556,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 470 | return err; | 556 | return err; |
| 471 | 557 | ||
| 472 | memset(&shm_info,0,sizeof(shm_info)); | 558 | memset(&shm_info,0,sizeof(shm_info)); |
| 473 | mutex_lock(&shm_ids.mutex); | 559 | mutex_lock(&shm_ids(ns).mutex); |
| 474 | shm_info.used_ids = shm_ids.in_use; | 560 | shm_info.used_ids = shm_ids(ns).in_use; |
| 475 | shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp); | 561 | shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); |
| 476 | shm_info.shm_tot = shm_tot; | 562 | shm_info.shm_tot = ns->shm_tot; |
| 477 | shm_info.swap_attempts = 0; | 563 | shm_info.swap_attempts = 0; |
| 478 | shm_info.swap_successes = 0; | 564 | shm_info.swap_successes = 0; |
| 479 | err = shm_ids.max_id; | 565 | err = shm_ids(ns).max_id; |
| 480 | mutex_unlock(&shm_ids.mutex); | 566 | mutex_unlock(&shm_ids(ns).mutex); |
| 481 | if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { | 567 | if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { |
| 482 | err = -EFAULT; | 568 | err = -EFAULT; |
| 483 | goto out; | 569 | goto out; |
| @@ -492,17 +578,17 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 492 | struct shmid64_ds tbuf; | 578 | struct shmid64_ds tbuf; |
| 493 | int result; | 579 | int result; |
| 494 | memset(&tbuf, 0, sizeof(tbuf)); | 580 | memset(&tbuf, 0, sizeof(tbuf)); |
| 495 | shp = shm_lock(shmid); | 581 | shp = shm_lock(ns, shmid); |
| 496 | if(shp==NULL) { | 582 | if(shp==NULL) { |
| 497 | err = -EINVAL; | 583 | err = -EINVAL; |
| 498 | goto out; | 584 | goto out; |
| 499 | } else if(cmd==SHM_STAT) { | 585 | } else if(cmd==SHM_STAT) { |
| 500 | err = -EINVAL; | 586 | err = -EINVAL; |
| 501 | if (shmid > shm_ids.max_id) | 587 | if (shmid > shm_ids(ns).max_id) |
| 502 | goto out_unlock; | 588 | goto out_unlock; |
| 503 | result = shm_buildid(shmid, shp->shm_perm.seq); | 589 | result = shm_buildid(ns, shmid, shp->shm_perm.seq); |
| 504 | } else { | 590 | } else { |
| 505 | err = shm_checkid(shp,shmid); | 591 | err = shm_checkid(ns, shp,shmid); |
| 506 | if(err) | 592 | if(err) |
| 507 | goto out_unlock; | 593 | goto out_unlock; |
| 508 | result = 0; | 594 | result = 0; |
| @@ -534,12 +620,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 534 | case SHM_LOCK: | 620 | case SHM_LOCK: |
| 535 | case SHM_UNLOCK: | 621 | case SHM_UNLOCK: |
| 536 | { | 622 | { |
| 537 | shp = shm_lock(shmid); | 623 | shp = shm_lock(ns, shmid); |
| 538 | if(shp==NULL) { | 624 | if(shp==NULL) { |
| 539 | err = -EINVAL; | 625 | err = -EINVAL; |
| 540 | goto out; | 626 | goto out; |
| 541 | } | 627 | } |
| 542 | err = shm_checkid(shp,shmid); | 628 | err = shm_checkid(ns, shp,shmid); |
| 543 | if(err) | 629 | if(err) |
| 544 | goto out_unlock; | 630 | goto out_unlock; |
| 545 | 631 | ||
| @@ -590,12 +676,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 590 | * Instead we set a destroyed flag, and then blow | 676 | * Instead we set a destroyed flag, and then blow |
| 591 | * the name away when the usage hits zero. | 677 | * the name away when the usage hits zero. |
| 592 | */ | 678 | */ |
| 593 | mutex_lock(&shm_ids.mutex); | 679 | mutex_lock(&shm_ids(ns).mutex); |
| 594 | shp = shm_lock(shmid); | 680 | shp = shm_lock(ns, shmid); |
| 595 | err = -EINVAL; | 681 | err = -EINVAL; |
| 596 | if (shp == NULL) | 682 | if (shp == NULL) |
| 597 | goto out_up; | 683 | goto out_up; |
| 598 | err = shm_checkid(shp, shmid); | 684 | err = shm_checkid(ns, shp, shmid); |
| 599 | if(err) | 685 | if(err) |
| 600 | goto out_unlock_up; | 686 | goto out_unlock_up; |
| 601 | 687 | ||
| @@ -614,14 +700,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 614 | if (err) | 700 | if (err) |
| 615 | goto out_unlock_up; | 701 | goto out_unlock_up; |
| 616 | 702 | ||
| 617 | if (shp->shm_nattch){ | 703 | do_shm_rmid(ns, shp); |
| 618 | shp->shm_perm.mode |= SHM_DEST; | 704 | mutex_unlock(&shm_ids(ns).mutex); |
| 619 | /* Do not find it any more */ | ||
| 620 | shp->shm_perm.key = IPC_PRIVATE; | ||
| 621 | shm_unlock(shp); | ||
| 622 | } else | ||
| 623 | shm_destroy (shp); | ||
| 624 | mutex_unlock(&shm_ids.mutex); | ||
| 625 | goto out; | 705 | goto out; |
| 626 | } | 706 | } |
| 627 | 707 | ||
| @@ -631,12 +711,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 631 | err = -EFAULT; | 711 | err = -EFAULT; |
| 632 | goto out; | 712 | goto out; |
| 633 | } | 713 | } |
| 634 | mutex_lock(&shm_ids.mutex); | 714 | mutex_lock(&shm_ids(ns).mutex); |
| 635 | shp = shm_lock(shmid); | 715 | shp = shm_lock(ns, shmid); |
| 636 | err=-EINVAL; | 716 | err=-EINVAL; |
| 637 | if(shp==NULL) | 717 | if(shp==NULL) |
| 638 | goto out_up; | 718 | goto out_up; |
| 639 | err = shm_checkid(shp,shmid); | 719 | err = shm_checkid(ns, shp,shmid); |
| 640 | if(err) | 720 | if(err) |
| 641 | goto out_unlock_up; | 721 | goto out_unlock_up; |
| 642 | err = audit_ipc_obj(&(shp->shm_perm)); | 722 | err = audit_ipc_obj(&(shp->shm_perm)); |
| @@ -673,7 +753,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) | |||
| 673 | out_unlock_up: | 753 | out_unlock_up: |
| 674 | shm_unlock(shp); | 754 | shm_unlock(shp); |
| 675 | out_up: | 755 | out_up: |
| 676 | mutex_unlock(&shm_ids.mutex); | 756 | mutex_unlock(&shm_ids(ns).mutex); |
| 677 | goto out; | 757 | goto out; |
| 678 | out_unlock: | 758 | out_unlock: |
| 679 | shm_unlock(shp); | 759 | shm_unlock(shp); |
| @@ -699,6 +779,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
| 699 | unsigned long prot; | 779 | unsigned long prot; |
| 700 | int acc_mode; | 780 | int acc_mode; |
| 701 | void *user_addr; | 781 | void *user_addr; |
| 782 | struct ipc_namespace *ns; | ||
| 702 | 783 | ||
| 703 | if (shmid < 0) { | 784 | if (shmid < 0) { |
| 704 | err = -EINVAL; | 785 | err = -EINVAL; |
| @@ -737,12 +818,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
| 737 | * We cannot rely on the fs check since SYSV IPC does have an | 818 | * We cannot rely on the fs check since SYSV IPC does have an |
| 738 | * additional creator id... | 819 | * additional creator id... |
| 739 | */ | 820 | */ |
| 740 | shp = shm_lock(shmid); | 821 | ns = current->nsproxy->ipc_ns; |
| 822 | shp = shm_lock(ns, shmid); | ||
| 741 | if(shp == NULL) { | 823 | if(shp == NULL) { |
| 742 | err = -EINVAL; | 824 | err = -EINVAL; |
| 743 | goto out; | 825 | goto out; |
| 744 | } | 826 | } |
| 745 | err = shm_checkid(shp,shmid); | 827 | err = shm_checkid(ns, shp,shmid); |
| 746 | if (err) { | 828 | if (err) { |
| 747 | shm_unlock(shp); | 829 | shm_unlock(shp); |
| 748 | goto out; | 830 | goto out; |
| @@ -783,16 +865,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) | |||
| 783 | invalid: | 865 | invalid: |
| 784 | up_write(¤t->mm->mmap_sem); | 866 | up_write(¤t->mm->mmap_sem); |
| 785 | 867 | ||
| 786 | mutex_lock(&shm_ids.mutex); | 868 | mutex_lock(&shm_ids(ns).mutex); |
| 787 | shp = shm_lock(shmid); | 869 | shp = shm_lock(ns, shmid); |
| 788 | BUG_ON(!shp); | 870 | BUG_ON(!shp); |
| 789 | shp->shm_nattch--; | 871 | shp->shm_nattch--; |
| 790 | if(shp->shm_nattch == 0 && | 872 | if(shp->shm_nattch == 0 && |
| 791 | shp->shm_perm.mode & SHM_DEST) | 873 | shp->shm_perm.mode & SHM_DEST) |
| 792 | shm_destroy (shp); | 874 | shm_destroy(ns, shp); |
| 793 | else | 875 | else |
| 794 | shm_unlock(shp); | 876 | shm_unlock(shp); |
| 795 | mutex_unlock(&shm_ids.mutex); | 877 | mutex_unlock(&shm_ids(ns).mutex); |
| 796 | 878 | ||
| 797 | *raddr = (unsigned long) user_addr; | 879 | *raddr = (unsigned long) user_addr; |
| 798 | err = 0; | 880 | err = 0; |
diff --git a/ipc/util.c b/ipc/util.c index 67b6d178db6e..42479e4eec59 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
| @@ -12,6 +12,9 @@ | |||
| 12 | * Mingming Cao <cmm@us.ibm.com> | 12 | * Mingming Cao <cmm@us.ibm.com> |
| 13 | * Mar 2006 - support for audit of ipc object properties | 13 | * Mar 2006 - support for audit of ipc object properties |
| 14 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> | 14 | * Dustin Kirkland <dustin.kirkland@us.ibm.com> |
| 15 | * Jun 2006 - namespaces ssupport | ||
| 16 | * OpenVZ, SWsoft Inc. | ||
| 17 | * Pavel Emelianov <xemul@openvz.org> | ||
| 15 | */ | 18 | */ |
| 16 | 19 | ||
| 17 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
| @@ -29,6 +32,7 @@ | |||
| 29 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
| 30 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
| 31 | #include <linux/audit.h> | 34 | #include <linux/audit.h> |
| 35 | #include <linux/nsproxy.h> | ||
| 32 | 36 | ||
| 33 | #include <asm/unistd.h> | 37 | #include <asm/unistd.h> |
| 34 | 38 | ||
| @@ -37,10 +41,111 @@ | |||
| 37 | struct ipc_proc_iface { | 41 | struct ipc_proc_iface { |
| 38 | const char *path; | 42 | const char *path; |
| 39 | const char *header; | 43 | const char *header; |
| 40 | struct ipc_ids *ids; | 44 | int ids; |
| 41 | int (*show)(struct seq_file *, void *); | 45 | int (*show)(struct seq_file *, void *); |
| 42 | }; | 46 | }; |
| 43 | 47 | ||
| 48 | struct ipc_namespace init_ipc_ns = { | ||
| 49 | .kref = { | ||
| 50 | .refcount = ATOMIC_INIT(2), | ||
| 51 | }, | ||
| 52 | }; | ||
| 53 | |||
| 54 | #ifdef CONFIG_IPC_NS | ||
| 55 | static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) | ||
| 56 | { | ||
| 57 | int err; | ||
| 58 | struct ipc_namespace *ns; | ||
| 59 | |||
| 60 | err = -ENOMEM; | ||
| 61 | ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); | ||
| 62 | if (ns == NULL) | ||
| 63 | goto err_mem; | ||
| 64 | |||
| 65 | err = sem_init_ns(ns); | ||
| 66 | if (err) | ||
| 67 | goto err_sem; | ||
| 68 | err = msg_init_ns(ns); | ||
| 69 | if (err) | ||
| 70 | goto err_msg; | ||
| 71 | err = shm_init_ns(ns); | ||
| 72 | if (err) | ||
| 73 | goto err_shm; | ||
| 74 | |||
| 75 | kref_init(&ns->kref); | ||
| 76 | return ns; | ||
| 77 | |||
| 78 | err_shm: | ||
| 79 | msg_exit_ns(ns); | ||
| 80 | err_msg: | ||
| 81 | sem_exit_ns(ns); | ||
| 82 | err_sem: | ||
| 83 | kfree(ns); | ||
| 84 | err_mem: | ||
| 85 | return ERR_PTR(err); | ||
| 86 | } | ||
| 87 | |||
| 88 | int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc) | ||
| 89 | { | ||
| 90 | struct ipc_namespace *new; | ||
| 91 | |||
| 92 | if (unshare_flags & CLONE_NEWIPC) { | ||
| 93 | if (!capable(CAP_SYS_ADMIN)) | ||
| 94 | return -EPERM; | ||
| 95 | |||
| 96 | new = clone_ipc_ns(current->nsproxy->ipc_ns); | ||
| 97 | if (IS_ERR(new)) | ||
| 98 | return PTR_ERR(new); | ||
| 99 | |||
| 100 | *new_ipc = new; | ||
| 101 | } | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | int copy_ipcs(unsigned long flags, struct task_struct *tsk) | ||
| 107 | { | ||
| 108 | struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns; | ||
| 109 | struct ipc_namespace *new_ns; | ||
| 110 | int err = 0; | ||
| 111 | |||
| 112 | if (!old_ns) | ||
| 113 | return 0; | ||
| 114 | |||
| 115 | get_ipc_ns(old_ns); | ||
| 116 | |||
| 117 | if (!(flags & CLONE_NEWIPC)) | ||
| 118 | return 0; | ||
| 119 | |||
| 120 | if (!capable(CAP_SYS_ADMIN)) { | ||
| 121 | err = -EPERM; | ||
| 122 | goto out; | ||
| 123 | } | ||
| 124 | |||
| 125 | new_ns = clone_ipc_ns(old_ns); | ||
| 126 | if (!new_ns) { | ||
| 127 | err = -ENOMEM; | ||
| 128 | goto out; | ||
| 129 | } | ||
| 130 | |||
| 131 | tsk->nsproxy->ipc_ns = new_ns; | ||
| 132 | out: | ||
| 133 | put_ipc_ns(old_ns); | ||
| 134 | return err; | ||
| 135 | } | ||
| 136 | |||
| 137 | void free_ipc_ns(struct kref *kref) | ||
| 138 | { | ||
| 139 | struct ipc_namespace *ns; | ||
| 140 | |||
| 141 | ns = container_of(kref, struct ipc_namespace, kref); | ||
| 142 | sem_exit_ns(ns); | ||
| 143 | msg_exit_ns(ns); | ||
| 144 | shm_exit_ns(ns); | ||
| 145 | kfree(ns); | ||
| 146 | } | ||
| 147 | #endif | ||
| 148 | |||
| 44 | /** | 149 | /** |
| 45 | * ipc_init - initialise IPC subsystem | 150 | * ipc_init - initialise IPC subsystem |
| 46 | * | 151 | * |
| @@ -67,7 +172,7 @@ __initcall(ipc_init); | |||
| 67 | * array itself. | 172 | * array itself. |
| 68 | */ | 173 | */ |
| 69 | 174 | ||
| 70 | void __init ipc_init_ids(struct ipc_ids* ids, int size) | 175 | void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size) |
| 71 | { | 176 | { |
| 72 | int i; | 177 | int i; |
| 73 | 178 | ||
| @@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops; | |||
| 110 | * @show: show routine. | 215 | * @show: show routine. |
| 111 | */ | 216 | */ |
| 112 | void __init ipc_init_proc_interface(const char *path, const char *header, | 217 | void __init ipc_init_proc_interface(const char *path, const char *header, |
| 113 | struct ipc_ids *ids, | 218 | int ids, int (*show)(struct seq_file *, void *)) |
| 114 | int (*show)(struct seq_file *, void *)) | ||
| 115 | { | 219 | { |
| 116 | struct proc_dir_entry *pde; | 220 | struct proc_dir_entry *pde; |
| 117 | struct ipc_proc_iface *iface; | 221 | struct ipc_proc_iface *iface; |
| @@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) | |||
| 635 | struct ipc_proc_iface *iface = s->private; | 739 | struct ipc_proc_iface *iface = s->private; |
| 636 | struct kern_ipc_perm *ipc = it; | 740 | struct kern_ipc_perm *ipc = it; |
| 637 | loff_t p; | 741 | loff_t p; |
| 742 | struct ipc_ids *ids; | ||
| 743 | |||
| 744 | ids = current->nsproxy->ipc_ns->ids[iface->ids]; | ||
| 638 | 745 | ||
| 639 | /* If we had an ipc id locked before, unlock it */ | 746 | /* If we had an ipc id locked before, unlock it */ |
| 640 | if (ipc && ipc != SEQ_START_TOKEN) | 747 | if (ipc && ipc != SEQ_START_TOKEN) |
| @@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) | |||
| 644 | * p = *pos - 1 (because id 0 starts at position 1) | 751 | * p = *pos - 1 (because id 0 starts at position 1) |
| 645 | * + 1 (because we increment the position by one) | 752 | * + 1 (because we increment the position by one) |
| 646 | */ | 753 | */ |
| 647 | for (p = *pos; p <= iface->ids->max_id; p++) { | 754 | for (p = *pos; p <= ids->max_id; p++) { |
| 648 | if ((ipc = ipc_lock(iface->ids, p)) != NULL) { | 755 | if ((ipc = ipc_lock(ids, p)) != NULL) { |
| 649 | *pos = p + 1; | 756 | *pos = p + 1; |
| 650 | return ipc; | 757 | return ipc; |
| 651 | } | 758 | } |
| @@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) | |||
| 664 | struct ipc_proc_iface *iface = s->private; | 771 | struct ipc_proc_iface *iface = s->private; |
| 665 | struct kern_ipc_perm *ipc; | 772 | struct kern_ipc_perm *ipc; |
| 666 | loff_t p; | 773 | loff_t p; |
| 774 | struct ipc_ids *ids; | ||
| 775 | |||
| 776 | ids = current->nsproxy->ipc_ns->ids[iface->ids]; | ||
| 667 | 777 | ||
| 668 | /* | 778 | /* |
| 669 | * Take the lock - this will be released by the corresponding | 779 | * Take the lock - this will be released by the corresponding |
| 670 | * call to stop(). | 780 | * call to stop(). |
| 671 | */ | 781 | */ |
| 672 | mutex_lock(&iface->ids->mutex); | 782 | mutex_lock(&ids->mutex); |
| 673 | 783 | ||
| 674 | /* pos < 0 is invalid */ | 784 | /* pos < 0 is invalid */ |
| 675 | if (*pos < 0) | 785 | if (*pos < 0) |
| @@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) | |||
| 680 | return SEQ_START_TOKEN; | 790 | return SEQ_START_TOKEN; |
| 681 | 791 | ||
| 682 | /* Find the (pos-1)th ipc */ | 792 | /* Find the (pos-1)th ipc */ |
| 683 | for (p = *pos - 1; p <= iface->ids->max_id; p++) { | 793 | for (p = *pos - 1; p <= ids->max_id; p++) { |
| 684 | if ((ipc = ipc_lock(iface->ids, p)) != NULL) { | 794 | if ((ipc = ipc_lock(ids, p)) != NULL) { |
| 685 | *pos = p + 1; | 795 | *pos = p + 1; |
| 686 | return ipc; | 796 | return ipc; |
| 687 | } | 797 | } |
| @@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it) | |||
| 693 | { | 803 | { |
| 694 | struct kern_ipc_perm *ipc = it; | 804 | struct kern_ipc_perm *ipc = it; |
| 695 | struct ipc_proc_iface *iface = s->private; | 805 | struct ipc_proc_iface *iface = s->private; |
| 806 | struct ipc_ids *ids; | ||
| 696 | 807 | ||
| 697 | /* If we had a locked segment, release it */ | 808 | /* If we had a locked segment, release it */ |
| 698 | if (ipc && ipc != SEQ_START_TOKEN) | 809 | if (ipc && ipc != SEQ_START_TOKEN) |
| 699 | ipc_unlock(ipc); | 810 | ipc_unlock(ipc); |
| 700 | 811 | ||
| 812 | ids = current->nsproxy->ipc_ns->ids[iface->ids]; | ||
| 701 | /* Release the lock we took in start() */ | 813 | /* Release the lock we took in start() */ |
| 702 | mutex_unlock(&iface->ids->mutex); | 814 | mutex_unlock(&ids->mutex); |
| 703 | } | 815 | } |
| 704 | 816 | ||
| 705 | static int sysvipc_proc_show(struct seq_file *s, void *it) | 817 | static int sysvipc_proc_show(struct seq_file *s, void *it) |
diff --git a/ipc/util.h b/ipc/util.h index 0181553d31d8..c8fd6b9d77b5 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
| @@ -3,6 +3,8 @@ | |||
| 3 | * Copyright (C) 1999 Christoph Rohland | 3 | * Copyright (C) 1999 Christoph Rohland |
| 4 | * | 4 | * |
| 5 | * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> | 5 | * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> |
| 6 | * namespaces support. 2006 OpenVZ, SWsoft Inc. | ||
| 7 | * Pavel Emelianov <xemul@openvz.org> | ||
| 6 | */ | 8 | */ |
| 7 | 9 | ||
| 8 | #ifndef _IPC_UTIL_H | 10 | #ifndef _IPC_UTIL_H |
| @@ -15,6 +17,14 @@ void sem_init (void); | |||
| 15 | void msg_init (void); | 17 | void msg_init (void); |
| 16 | void shm_init (void); | 18 | void shm_init (void); |
| 17 | 19 | ||
| 20 | int sem_init_ns(struct ipc_namespace *ns); | ||
| 21 | int msg_init_ns(struct ipc_namespace *ns); | ||
| 22 | int shm_init_ns(struct ipc_namespace *ns); | ||
| 23 | |||
| 24 | void sem_exit_ns(struct ipc_namespace *ns); | ||
| 25 | void msg_exit_ns(struct ipc_namespace *ns); | ||
| 26 | void shm_exit_ns(struct ipc_namespace *ns); | ||
| 27 | |||
| 18 | struct ipc_id_ary { | 28 | struct ipc_id_ary { |
| 19 | int size; | 29 | int size; |
| 20 | struct kern_ipc_perm *p[0]; | 30 | struct kern_ipc_perm *p[0]; |
| @@ -31,15 +41,23 @@ struct ipc_ids { | |||
| 31 | }; | 41 | }; |
| 32 | 42 | ||
| 33 | struct seq_file; | 43 | struct seq_file; |
| 34 | void __init ipc_init_ids(struct ipc_ids* ids, int size); | 44 | #ifdef CONFIG_IPC_NS |
| 45 | #define __ipc_init | ||
| 46 | #else | ||
| 47 | #define __ipc_init __init | ||
| 48 | #endif | ||
| 49 | void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size); | ||
| 35 | #ifdef CONFIG_PROC_FS | 50 | #ifdef CONFIG_PROC_FS |
| 36 | void __init ipc_init_proc_interface(const char *path, const char *header, | 51 | void __init ipc_init_proc_interface(const char *path, const char *header, |
| 37 | struct ipc_ids *ids, | 52 | int ids, int (*show)(struct seq_file *, void *)); |
| 38 | int (*show)(struct seq_file *, void *)); | ||
| 39 | #else | 53 | #else |
| 40 | #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) | 54 | #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) |
| 41 | #endif | 55 | #endif |
| 42 | 56 | ||
| 57 | #define IPC_SEM_IDS 0 | ||
| 58 | #define IPC_MSG_IDS 1 | ||
| 59 | #define IPC_SHM_IDS 2 | ||
| 60 | |||
| 43 | /* must be called with ids->mutex acquired.*/ | 61 | /* must be called with ids->mutex acquired.*/ |
| 44 | int ipc_findkey(struct ipc_ids* ids, key_t key); | 62 | int ipc_findkey(struct ipc_ids* ids, key_t key); |
| 45 | int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); | 63 | int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); |
diff --git a/kernel/Makefile b/kernel/Makefile index aacaafb28b9d..d948ca12acf0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ | |||
| 8 | signal.o sys.o kmod.o workqueue.o pid.o \ | 8 | signal.o sys.o kmod.o workqueue.o pid.o \ |
| 9 | rcupdate.o extable.o params.o posix-timers.o \ | 9 | rcupdate.o extable.o params.o posix-timers.o \ |
| 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ | 10 | kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ |
| 11 | hrtimer.o rwsem.o latency.o | 11 | hrtimer.o rwsem.o latency.o nsproxy.o |
| 12 | 12 | ||
| 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
| 14 | obj-y += time/ | 14 | obj-y += time/ |
| @@ -48,6 +48,7 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ | |||
| 48 | obj-$(CONFIG_SECCOMP) += seccomp.o | 48 | obj-$(CONFIG_SECCOMP) += seccomp.o |
| 49 | obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o | 49 | obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o |
| 50 | obj-$(CONFIG_RELAY) += relay.o | 50 | obj-$(CONFIG_RELAY) += relay.o |
| 51 | obj-$(CONFIG_UTS_NS) += utsname.o | ||
| 51 | obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o | 52 | obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o |
| 52 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o | 53 | obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o |
| 53 | 54 | ||
diff --git a/kernel/compat.c b/kernel/compat.c index b4fbd838cd77..75573e5d27b0 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
| @@ -26,8 +26,6 @@ | |||
| 26 | 26 | ||
| 27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
| 28 | 28 | ||
| 29 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
| 30 | |||
| 31 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) | 29 | int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts) |
| 32 | { | 30 | { |
| 33 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || | 31 | return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) || |
diff --git a/kernel/exit.c b/kernel/exit.c index 3b47f26985f2..f250a5e3e281 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/tsacct_kern.h> | 21 | #include <linux/tsacct_kern.h> |
| 22 | #include <linux/file.h> | 22 | #include <linux/file.h> |
| 23 | #include <linux/binfmts.h> | 23 | #include <linux/binfmts.h> |
| 24 | #include <linux/nsproxy.h> | ||
| 24 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 25 | #include <linux/profile.h> | 26 | #include <linux/profile.h> |
| 26 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
| @@ -397,9 +398,11 @@ void daemonize(const char *name, ...) | |||
| 397 | fs = init_task.fs; | 398 | fs = init_task.fs; |
| 398 | current->fs = fs; | 399 | current->fs = fs; |
| 399 | atomic_inc(&fs->count); | 400 | atomic_inc(&fs->count); |
| 400 | exit_namespace(current); | 401 | |
| 401 | current->namespace = init_task.namespace; | 402 | exit_task_namespaces(current); |
| 402 | get_namespace(current->namespace); | 403 | current->nsproxy = init_task.nsproxy; |
| 404 | get_task_namespaces(current); | ||
| 405 | |||
| 403 | exit_files(current); | 406 | exit_files(current); |
| 404 | current->files = init_task.files; | 407 | current->files = init_task.files; |
| 405 | atomic_inc(¤t->files->count); | 408 | atomic_inc(¤t->files->count); |
| @@ -917,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 917 | exit_sem(tsk); | 920 | exit_sem(tsk); |
| 918 | __exit_files(tsk); | 921 | __exit_files(tsk); |
| 919 | __exit_fs(tsk); | 922 | __exit_fs(tsk); |
| 920 | exit_namespace(tsk); | ||
| 921 | exit_thread(); | 923 | exit_thread(); |
| 922 | cpuset_exit(tsk); | 924 | cpuset_exit(tsk); |
| 923 | exit_keys(tsk); | 925 | exit_keys(tsk); |
| @@ -932,6 +934,7 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 932 | tsk->exit_code = code; | 934 | tsk->exit_code = code; |
| 933 | proc_exit_connector(tsk); | 935 | proc_exit_connector(tsk); |
| 934 | exit_notify(tsk); | 936 | exit_notify(tsk); |
| 937 | exit_task_namespaces(tsk); | ||
| 935 | #ifdef CONFIG_NUMA | 938 | #ifdef CONFIG_NUMA |
| 936 | mpol_free(tsk->mempolicy); | 939 | mpol_free(tsk->mempolicy); |
| 937 | tsk->mempolicy = NULL; | 940 | tsk->mempolicy = NULL; |
diff --git a/kernel/fork.c b/kernel/fork.c index 89f666491d1f..7dc6140baac6 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/binfmts.h> | 27 | #include <linux/binfmts.h> |
| 28 | #include <linux/mman.h> | 28 | #include <linux/mman.h> |
| 29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
| 30 | #include <linux/nsproxy.h> | ||
| 30 | #include <linux/capability.h> | 31 | #include <linux/capability.h> |
| 31 | #include <linux/cpu.h> | 32 | #include <linux/cpu.h> |
| 32 | #include <linux/cpuset.h> | 33 | #include <linux/cpuset.h> |
| @@ -1116,11 +1117,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1116 | goto bad_fork_cleanup_signal; | 1117 | goto bad_fork_cleanup_signal; |
| 1117 | if ((retval = copy_keys(clone_flags, p))) | 1118 | if ((retval = copy_keys(clone_flags, p))) |
| 1118 | goto bad_fork_cleanup_mm; | 1119 | goto bad_fork_cleanup_mm; |
| 1119 | if ((retval = copy_namespace(clone_flags, p))) | 1120 | if ((retval = copy_namespaces(clone_flags, p))) |
| 1120 | goto bad_fork_cleanup_keys; | 1121 | goto bad_fork_cleanup_keys; |
| 1121 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); | 1122 | retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); |
| 1122 | if (retval) | 1123 | if (retval) |
| 1123 | goto bad_fork_cleanup_namespace; | 1124 | goto bad_fork_cleanup_namespaces; |
| 1124 | 1125 | ||
| 1125 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; | 1126 | p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; |
| 1126 | /* | 1127 | /* |
| @@ -1212,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1212 | spin_unlock(¤t->sighand->siglock); | 1213 | spin_unlock(¤t->sighand->siglock); |
| 1213 | write_unlock_irq(&tasklist_lock); | 1214 | write_unlock_irq(&tasklist_lock); |
| 1214 | retval = -ERESTARTNOINTR; | 1215 | retval = -ERESTARTNOINTR; |
| 1215 | goto bad_fork_cleanup_namespace; | 1216 | goto bad_fork_cleanup_namespaces; |
| 1216 | } | 1217 | } |
| 1217 | 1218 | ||
| 1218 | if (clone_flags & CLONE_THREAD) { | 1219 | if (clone_flags & CLONE_THREAD) { |
| @@ -1260,8 +1261,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1260 | proc_fork_connector(p); | 1261 | proc_fork_connector(p); |
| 1261 | return p; | 1262 | return p; |
| 1262 | 1263 | ||
| 1263 | bad_fork_cleanup_namespace: | 1264 | bad_fork_cleanup_namespaces: |
| 1264 | exit_namespace(p); | 1265 | exit_task_namespaces(p); |
| 1265 | bad_fork_cleanup_keys: | 1266 | bad_fork_cleanup_keys: |
| 1266 | exit_keys(p); | 1267 | exit_keys(p); |
| 1267 | bad_fork_cleanup_mm: | 1268 | bad_fork_cleanup_mm: |
| @@ -1514,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) | |||
| 1514 | */ | 1515 | */ |
| 1515 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) | 1516 | static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) |
| 1516 | { | 1517 | { |
| 1517 | struct namespace *ns = current->namespace; | 1518 | struct namespace *ns = current->nsproxy->namespace; |
| 1518 | 1519 | ||
| 1519 | if ((unshare_flags & CLONE_NEWNS) && | 1520 | if ((unshare_flags & CLONE_NEWNS) && ns) { |
| 1520 | (ns && atomic_read(&ns->count) > 1)) { | ||
| 1521 | if (!capable(CAP_SYS_ADMIN)) | 1521 | if (!capable(CAP_SYS_ADMIN)) |
| 1522 | return -EPERM; | 1522 | return -EPERM; |
| 1523 | 1523 | ||
| @@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n | |||
| 1589 | return 0; | 1589 | return 0; |
| 1590 | } | 1590 | } |
| 1591 | 1591 | ||
| 1592 | #ifndef CONFIG_IPC_NS | ||
| 1593 | static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns) | ||
| 1594 | { | ||
| 1595 | if (flags & CLONE_NEWIPC) | ||
| 1596 | return -EINVAL; | ||
| 1597 | |||
| 1598 | return 0; | ||
| 1599 | } | ||
| 1600 | #endif | ||
| 1601 | |||
| 1592 | /* | 1602 | /* |
| 1593 | * unshare allows a process to 'unshare' part of the process | 1603 | * unshare allows a process to 'unshare' part of the process |
| 1594 | * context which was originally shared using clone. copy_* | 1604 | * context which was originally shared using clone. copy_* |
| @@ -1606,13 +1616,17 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1606 | struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; | 1616 | struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL; |
| 1607 | struct files_struct *fd, *new_fd = NULL; | 1617 | struct files_struct *fd, *new_fd = NULL; |
| 1608 | struct sem_undo_list *new_ulist = NULL; | 1618 | struct sem_undo_list *new_ulist = NULL; |
| 1619 | struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL; | ||
| 1620 | struct uts_namespace *uts, *new_uts = NULL; | ||
| 1621 | struct ipc_namespace *ipc, *new_ipc = NULL; | ||
| 1609 | 1622 | ||
| 1610 | check_unshare_flags(&unshare_flags); | 1623 | check_unshare_flags(&unshare_flags); |
| 1611 | 1624 | ||
| 1612 | /* Return -EINVAL for all unsupported flags */ | 1625 | /* Return -EINVAL for all unsupported flags */ |
| 1613 | err = -EINVAL; | 1626 | err = -EINVAL; |
| 1614 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| | 1627 | if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| |
| 1615 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM)) | 1628 | CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| |
| 1629 | CLONE_NEWUTS|CLONE_NEWIPC)) | ||
| 1616 | goto bad_unshare_out; | 1630 | goto bad_unshare_out; |
| 1617 | 1631 | ||
| 1618 | if ((err = unshare_thread(unshare_flags))) | 1632 | if ((err = unshare_thread(unshare_flags))) |
| @@ -1629,11 +1643,30 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1629 | goto bad_unshare_cleanup_vm; | 1643 | goto bad_unshare_cleanup_vm; |
| 1630 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) | 1644 | if ((err = unshare_semundo(unshare_flags, &new_ulist))) |
| 1631 | goto bad_unshare_cleanup_fd; | 1645 | goto bad_unshare_cleanup_fd; |
| 1646 | if ((err = unshare_utsname(unshare_flags, &new_uts))) | ||
| 1647 | goto bad_unshare_cleanup_semundo; | ||
| 1648 | if ((err = unshare_ipcs(unshare_flags, &new_ipc))) | ||
| 1649 | goto bad_unshare_cleanup_uts; | ||
| 1650 | |||
| 1651 | if (new_ns || new_uts || new_ipc) { | ||
| 1652 | old_nsproxy = current->nsproxy; | ||
| 1653 | new_nsproxy = dup_namespaces(old_nsproxy); | ||
| 1654 | if (!new_nsproxy) { | ||
| 1655 | err = -ENOMEM; | ||
| 1656 | goto bad_unshare_cleanup_ipc; | ||
| 1657 | } | ||
| 1658 | } | ||
| 1632 | 1659 | ||
| 1633 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) { | 1660 | if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist || |
| 1661 | new_uts || new_ipc) { | ||
| 1634 | 1662 | ||
| 1635 | task_lock(current); | 1663 | task_lock(current); |
| 1636 | 1664 | ||
| 1665 | if (new_nsproxy) { | ||
| 1666 | current->nsproxy = new_nsproxy; | ||
| 1667 | new_nsproxy = old_nsproxy; | ||
| 1668 | } | ||
| 1669 | |||
| 1637 | if (new_fs) { | 1670 | if (new_fs) { |
| 1638 | fs = current->fs; | 1671 | fs = current->fs; |
| 1639 | current->fs = new_fs; | 1672 | current->fs = new_fs; |
| @@ -1641,8 +1674,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1641 | } | 1674 | } |
| 1642 | 1675 | ||
| 1643 | if (new_ns) { | 1676 | if (new_ns) { |
| 1644 | ns = current->namespace; | 1677 | ns = current->nsproxy->namespace; |
| 1645 | current->namespace = new_ns; | 1678 | current->nsproxy->namespace = new_ns; |
| 1646 | new_ns = ns; | 1679 | new_ns = ns; |
| 1647 | } | 1680 | } |
| 1648 | 1681 | ||
| @@ -1667,9 +1700,33 @@ asmlinkage long sys_unshare(unsigned long unshare_flags) | |||
| 1667 | new_fd = fd; | 1700 | new_fd = fd; |
| 1668 | } | 1701 | } |
| 1669 | 1702 | ||
| 1703 | if (new_uts) { | ||
| 1704 | uts = current->nsproxy->uts_ns; | ||
| 1705 | current->nsproxy->uts_ns = new_uts; | ||
| 1706 | new_uts = uts; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | if (new_ipc) { | ||
| 1710 | ipc = current->nsproxy->ipc_ns; | ||
| 1711 | current->nsproxy->ipc_ns = new_ipc; | ||
| 1712 | new_ipc = ipc; | ||
| 1713 | } | ||
| 1714 | |||
| 1670 | task_unlock(current); | 1715 | task_unlock(current); |
| 1671 | } | 1716 | } |
| 1672 | 1717 | ||
| 1718 | if (new_nsproxy) | ||
| 1719 | put_nsproxy(new_nsproxy); | ||
| 1720 | |||
| 1721 | bad_unshare_cleanup_ipc: | ||
| 1722 | if (new_ipc) | ||
| 1723 | put_ipc_ns(new_ipc); | ||
| 1724 | |||
| 1725 | bad_unshare_cleanup_uts: | ||
| 1726 | if (new_uts) | ||
| 1727 | put_uts_ns(new_uts); | ||
| 1728 | |||
| 1729 | bad_unshare_cleanup_semundo: | ||
| 1673 | bad_unshare_cleanup_fd: | 1730 | bad_unshare_cleanup_fd: |
| 1674 | if (new_fd) | 1731 | if (new_fd) |
| 1675 | put_files_struct(new_fd); | 1732 | put_files_struct(new_fd); |
diff --git a/kernel/futex.c b/kernel/futex.c index 4b6770e9806d..4aaf91951a43 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
| @@ -1527,7 +1527,7 @@ static int futex_fd(u32 __user *uaddr, int signal) | |||
| 1527 | filp->f_mapping = filp->f_dentry->d_inode->i_mapping; | 1527 | filp->f_mapping = filp->f_dentry->d_inode->i_mapping; |
| 1528 | 1528 | ||
| 1529 | if (signal) { | 1529 | if (signal) { |
| 1530 | err = f_setown(filp, current->pid, 1); | 1530 | err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1); |
| 1531 | if (err < 0) { | 1531 | if (err < 0) { |
| 1532 | goto error; | 1532 | goto error; |
| 1533 | } | 1533 | } |
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index ab16a5a4cfe9..342bca62c496 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
| @@ -154,7 +154,6 @@ unsigned long kallsyms_lookup_name(const char *name) | |||
| 154 | } | 154 | } |
| 155 | return module_kallsyms_lookup_name(name); | 155 | return module_kallsyms_lookup_name(name); |
| 156 | } | 156 | } |
| 157 | EXPORT_SYMBOL_GPL(kallsyms_lookup_name); | ||
| 158 | 157 | ||
| 159 | /* | 158 | /* |
| 160 | * Lookup an address | 159 | * Lookup an address |
diff --git a/kernel/kmod.c b/kernel/kmod.c index f8121b95183f..bb4e29d924e4 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -18,8 +18,6 @@ | |||
| 18 | call_usermodehelper wait flag, and remove exec_usermodehelper. | 18 | call_usermodehelper wait flag, and remove exec_usermodehelper. |
| 19 | Rusty Russell <rusty@rustcorp.com.au> Jan 2003 | 19 | Rusty Russell <rusty@rustcorp.com.au> Jan 2003 |
| 20 | */ | 20 | */ |
| 21 | #define __KERNEL_SYSCALLS__ | ||
| 22 | |||
| 23 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 24 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 25 | #include <linux/syscalls.h> | 23 | #include <linux/syscalls.h> |
| @@ -169,7 +167,8 @@ static int ____call_usermodehelper(void *data) | |||
| 169 | 167 | ||
| 170 | retval = -EPERM; | 168 | retval = -EPERM; |
| 171 | if (current->fs->root) | 169 | if (current->fs->root) |
| 172 | retval = execve(sub_info->path, sub_info->argv, sub_info->envp); | 170 | retval = kernel_execve(sub_info->path, |
| 171 | sub_info->argv, sub_info->envp); | ||
| 173 | 172 | ||
| 174 | /* Exec failed? */ | 173 | /* Exec failed? */ |
| 175 | sub_info->retval = retval; | 174 | sub_info->retval = retval; |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 3f57dfdc8f92..610c837ad9e0 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
| 39 | #include <linux/moduleloader.h> | 39 | #include <linux/moduleloader.h> |
| 40 | #include <linux/kallsyms.h> | ||
| 40 | #include <asm-generic/sections.h> | 41 | #include <asm-generic/sections.h> |
| 41 | #include <asm/cacheflush.h> | 42 | #include <asm/cacheflush.h> |
| 42 | #include <asm/errno.h> | 43 | #include <asm/errno.h> |
| @@ -45,6 +46,16 @@ | |||
| 45 | #define KPROBE_HASH_BITS 6 | 46 | #define KPROBE_HASH_BITS 6 |
| 46 | #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) | 47 | #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) |
| 47 | 48 | ||
| 49 | |||
| 50 | /* | ||
| 51 | * Some oddball architectures like 64bit powerpc have function descriptors | ||
| 52 | * so this must be overridable. | ||
| 53 | */ | ||
| 54 | #ifndef kprobe_lookup_name | ||
| 55 | #define kprobe_lookup_name(name, addr) \ | ||
| 56 | addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) | ||
| 57 | #endif | ||
| 58 | |||
| 48 | static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; | 59 | static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; |
| 49 | static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; | 60 | static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; |
| 50 | static atomic_t kprobe_count; | 61 | static atomic_t kprobe_count; |
| @@ -308,7 +319,8 @@ void __kprobes add_rp_inst(struct kretprobe_instance *ri) | |||
| 308 | } | 319 | } |
| 309 | 320 | ||
| 310 | /* Called with kretprobe_lock held */ | 321 | /* Called with kretprobe_lock held */ |
| 311 | void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) | 322 | void __kprobes recycle_rp_inst(struct kretprobe_instance *ri, |
| 323 | struct hlist_head *head) | ||
| 312 | { | 324 | { |
| 313 | /* remove rp inst off the rprobe_inst_table */ | 325 | /* remove rp inst off the rprobe_inst_table */ |
| 314 | hlist_del(&ri->hlist); | 326 | hlist_del(&ri->hlist); |
| @@ -320,7 +332,7 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) | |||
| 320 | hlist_add_head(&ri->uflist, &ri->rp->free_instances); | 332 | hlist_add_head(&ri->uflist, &ri->rp->free_instances); |
| 321 | } else | 333 | } else |
| 322 | /* Unregistering */ | 334 | /* Unregistering */ |
| 323 | kfree(ri); | 335 | hlist_add_head(&ri->hlist, head); |
| 324 | } | 336 | } |
| 325 | 337 | ||
| 326 | struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) | 338 | struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) |
| @@ -336,18 +348,24 @@ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk) | |||
| 336 | */ | 348 | */ |
| 337 | void __kprobes kprobe_flush_task(struct task_struct *tk) | 349 | void __kprobes kprobe_flush_task(struct task_struct *tk) |
| 338 | { | 350 | { |
| 339 | struct kretprobe_instance *ri; | 351 | struct kretprobe_instance *ri; |
| 340 | struct hlist_head *head; | 352 | struct hlist_head *head, empty_rp; |
| 341 | struct hlist_node *node, *tmp; | 353 | struct hlist_node *node, *tmp; |
| 342 | unsigned long flags = 0; | 354 | unsigned long flags = 0; |
| 343 | 355 | ||
| 356 | INIT_HLIST_HEAD(&empty_rp); | ||
| 344 | spin_lock_irqsave(&kretprobe_lock, flags); | 357 | spin_lock_irqsave(&kretprobe_lock, flags); |
| 345 | head = kretprobe_inst_table_head(tk); | 358 | head = kretprobe_inst_table_head(tk); |
| 346 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | 359 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { |
| 347 | if (ri->task == tk) | 360 | if (ri->task == tk) |
| 348 | recycle_rp_inst(ri); | 361 | recycle_rp_inst(ri, &empty_rp); |
| 349 | } | 362 | } |
| 350 | spin_unlock_irqrestore(&kretprobe_lock, flags); | 363 | spin_unlock_irqrestore(&kretprobe_lock, flags); |
| 364 | |||
| 365 | hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { | ||
| 366 | hlist_del(&ri->hlist); | ||
| 367 | kfree(ri); | ||
| 368 | } | ||
| 351 | } | 369 | } |
| 352 | 370 | ||
| 353 | static inline void free_rp_inst(struct kretprobe *rp) | 371 | static inline void free_rp_inst(struct kretprobe *rp) |
| @@ -447,6 +465,21 @@ static int __kprobes __register_kprobe(struct kprobe *p, | |||
| 447 | struct kprobe *old_p; | 465 | struct kprobe *old_p; |
| 448 | struct module *probed_mod; | 466 | struct module *probed_mod; |
| 449 | 467 | ||
| 468 | /* | ||
| 469 | * If we have a symbol_name argument look it up, | ||
| 470 | * and add it to the address. That way the addr | ||
| 471 | * field can either be global or relative to a symbol. | ||
| 472 | */ | ||
| 473 | if (p->symbol_name) { | ||
| 474 | if (p->addr) | ||
| 475 | return -EINVAL; | ||
| 476 | kprobe_lookup_name(p->symbol_name, p->addr); | ||
| 477 | } | ||
| 478 | |||
| 479 | if (!p->addr) | ||
| 480 | return -EINVAL; | ||
| 481 | p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset); | ||
| 482 | |||
| 450 | if ((!kernel_text_address((unsigned long) p->addr)) || | 483 | if ((!kernel_text_address((unsigned long) p->addr)) || |
| 451 | in_kprobes_functions((unsigned long) p->addr)) | 484 | in_kprobes_functions((unsigned long) p->addr)) |
| 452 | return -EINVAL; | 485 | return -EINVAL; |
| @@ -488,7 +521,7 @@ static int __kprobes __register_kprobe(struct kprobe *p, | |||
| 488 | (ARCH_INACTIVE_KPROBE_COUNT + 1)) | 521 | (ARCH_INACTIVE_KPROBE_COUNT + 1)) |
| 489 | register_page_fault_notifier(&kprobe_page_fault_nb); | 522 | register_page_fault_notifier(&kprobe_page_fault_nb); |
| 490 | 523 | ||
| 491 | arch_arm_kprobe(p); | 524 | arch_arm_kprobe(p); |
| 492 | 525 | ||
| 493 | out: | 526 | out: |
| 494 | mutex_unlock(&kprobe_mutex); | 527 | mutex_unlock(&kprobe_mutex); |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index e596525669ed..4c0553461000 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
| @@ -518,9 +518,9 @@ print_circular_bug_entry(struct lock_list *target, unsigned int depth) | |||
| 518 | 518 | ||
| 519 | static void print_kernel_version(void) | 519 | static void print_kernel_version(void) |
| 520 | { | 520 | { |
| 521 | printk("%s %.*s\n", system_utsname.release, | 521 | printk("%s %.*s\n", init_utsname()->release, |
| 522 | (int)strcspn(system_utsname.version, " "), | 522 | (int)strcspn(init_utsname()->version, " "), |
| 523 | system_utsname.version); | 523 | init_utsname()->version); |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | /* | 526 | /* |
diff --git a/kernel/module.c b/kernel/module.c index 05625d5dc758..7c77a0a9275c 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -851,6 +851,7 @@ static int check_version(Elf_Shdr *sechdrs, | |||
| 851 | printk("%s: no version for \"%s\" found: kernel tainted.\n", | 851 | printk("%s: no version for \"%s\" found: kernel tainted.\n", |
| 852 | mod->name, symname); | 852 | mod->name, symname); |
| 853 | add_taint(TAINT_FORCED_MODULE); | 853 | add_taint(TAINT_FORCED_MODULE); |
| 854 | mod->taints |= TAINT_FORCED_MODULE; | ||
| 854 | } | 855 | } |
| 855 | return 1; | 856 | return 1; |
| 856 | } | 857 | } |
| @@ -1339,6 +1340,7 @@ static void set_license(struct module *mod, const char *license) | |||
| 1339 | printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", | 1340 | printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", |
| 1340 | mod->name, license); | 1341 | mod->name, license); |
| 1341 | add_taint(TAINT_PROPRIETARY_MODULE); | 1342 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1343 | mod->taints |= TAINT_PROPRIETARY_MODULE; | ||
| 1342 | } | 1344 | } |
| 1343 | } | 1345 | } |
| 1344 | 1346 | ||
| @@ -1618,6 +1620,7 @@ static struct module *load_module(void __user *umod, | |||
| 1618 | /* This is allowed: modprobe --force will invalidate it. */ | 1620 | /* This is allowed: modprobe --force will invalidate it. */ |
| 1619 | if (!modmagic) { | 1621 | if (!modmagic) { |
| 1620 | add_taint(TAINT_FORCED_MODULE); | 1622 | add_taint(TAINT_FORCED_MODULE); |
| 1623 | mod->taints |= TAINT_FORCED_MODULE; | ||
| 1621 | printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", | 1624 | printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", |
| 1622 | mod->name); | 1625 | mod->name); |
| 1623 | } else if (!same_magic(modmagic, vermagic)) { | 1626 | } else if (!same_magic(modmagic, vermagic)) { |
| @@ -1711,10 +1714,14 @@ static struct module *load_module(void __user *umod, | |||
| 1711 | /* Set up license info based on the info section */ | 1714 | /* Set up license info based on the info section */ |
| 1712 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 1715 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
| 1713 | 1716 | ||
| 1714 | if (strcmp(mod->name, "ndiswrapper") == 0) | 1717 | if (strcmp(mod->name, "ndiswrapper") == 0) { |
| 1715 | add_taint(TAINT_PROPRIETARY_MODULE); | 1718 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1716 | if (strcmp(mod->name, "driverloader") == 0) | 1719 | mod->taints |= TAINT_PROPRIETARY_MODULE; |
| 1720 | } | ||
| 1721 | if (strcmp(mod->name, "driverloader") == 0) { | ||
| 1717 | add_taint(TAINT_PROPRIETARY_MODULE); | 1722 | add_taint(TAINT_PROPRIETARY_MODULE); |
| 1723 | mod->taints |= TAINT_PROPRIETARY_MODULE; | ||
| 1724 | } | ||
| 1718 | 1725 | ||
| 1719 | /* Set up MODINFO_ATTR fields */ | 1726 | /* Set up MODINFO_ATTR fields */ |
| 1720 | setup_modinfo(mod, sechdrs, infoindex); | 1727 | setup_modinfo(mod, sechdrs, infoindex); |
| @@ -1760,6 +1767,7 @@ static struct module *load_module(void __user *umod, | |||
| 1760 | printk(KERN_WARNING "%s: No versions for exported symbols." | 1767 | printk(KERN_WARNING "%s: No versions for exported symbols." |
| 1761 | " Tainting kernel.\n", mod->name); | 1768 | " Tainting kernel.\n", mod->name); |
| 1762 | add_taint(TAINT_FORCED_MODULE); | 1769 | add_taint(TAINT_FORCED_MODULE); |
| 1770 | mod->taints |= TAINT_FORCED_MODULE; | ||
| 1763 | } | 1771 | } |
| 1764 | #endif | 1772 | #endif |
| 1765 | 1773 | ||
| @@ -2226,14 +2234,37 @@ struct module *module_text_address(unsigned long addr) | |||
| 2226 | return mod; | 2234 | return mod; |
| 2227 | } | 2235 | } |
| 2228 | 2236 | ||
| 2237 | static char *taint_flags(unsigned int taints, char *buf) | ||
| 2238 | { | ||
| 2239 | *buf = '\0'; | ||
| 2240 | if (taints) { | ||
| 2241 | int bx; | ||
| 2242 | |||
| 2243 | buf[0] = '('; | ||
| 2244 | bx = 1; | ||
| 2245 | if (taints & TAINT_PROPRIETARY_MODULE) | ||
| 2246 | buf[bx++] = 'P'; | ||
| 2247 | if (taints & TAINT_FORCED_MODULE) | ||
| 2248 | buf[bx++] = 'F'; | ||
| 2249 | /* | ||
| 2250 | * TAINT_FORCED_RMMOD: could be added. | ||
| 2251 | * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't | ||
| 2252 | * apply to modules. | ||
| 2253 | */ | ||
| 2254 | buf[bx] = ')'; | ||
| 2255 | } | ||
| 2256 | return buf; | ||
| 2257 | } | ||
| 2258 | |||
| 2229 | /* Don't grab lock, we're oopsing. */ | 2259 | /* Don't grab lock, we're oopsing. */ |
| 2230 | void print_modules(void) | 2260 | void print_modules(void) |
| 2231 | { | 2261 | { |
| 2232 | struct module *mod; | 2262 | struct module *mod; |
| 2263 | char buf[8]; | ||
| 2233 | 2264 | ||
| 2234 | printk("Modules linked in:"); | 2265 | printk("Modules linked in:"); |
| 2235 | list_for_each_entry(mod, &modules, list) | 2266 | list_for_each_entry(mod, &modules, list) |
| 2236 | printk(" %s", mod->name); | 2267 | printk(" %s%s", mod->name, taint_flags(mod->taints, buf)); |
| 2237 | printk("\n"); | 2268 | printk("\n"); |
| 2238 | } | 2269 | } |
| 2239 | 2270 | ||
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c new file mode 100644 index 000000000000..6ebdb82a0ce4 --- /dev/null +++ b/kernel/nsproxy.c | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Serge Hallyn <serue@us.ibm.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation, version 2 of the | ||
| 9 | * License. | ||
| 10 | * | ||
| 11 | * Jun 2006 - namespaces support | ||
| 12 | * OpenVZ, SWsoft Inc. | ||
| 13 | * Pavel Emelianov <xemul@openvz.org> | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/version.h> | ||
| 18 | #include <linux/nsproxy.h> | ||
| 19 | #include <linux/init_task.h> | ||
| 20 | #include <linux/namespace.h> | ||
| 21 | #include <linux/utsname.h> | ||
| 22 | |||
| 23 | struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy); | ||
| 24 | |||
| 25 | static inline void get_nsproxy(struct nsproxy *ns) | ||
| 26 | { | ||
| 27 | atomic_inc(&ns->count); | ||
| 28 | } | ||
| 29 | |||
| 30 | void get_task_namespaces(struct task_struct *tsk) | ||
| 31 | { | ||
| 32 | struct nsproxy *ns = tsk->nsproxy; | ||
| 33 | if (ns) { | ||
| 34 | get_nsproxy(ns); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | /* | ||
| 39 | * creates a copy of "orig" with refcount 1. | ||
| 40 | * This does not grab references to the contained namespaces, | ||
| 41 | * so that needs to be done by dup_namespaces. | ||
| 42 | */ | ||
| 43 | static inline struct nsproxy *clone_namespaces(struct nsproxy *orig) | ||
| 44 | { | ||
| 45 | struct nsproxy *ns; | ||
| 46 | |||
| 47 | ns = kmalloc(sizeof(struct nsproxy), GFP_KERNEL); | ||
| 48 | if (ns) { | ||
| 49 | memcpy(ns, orig, sizeof(struct nsproxy)); | ||
| 50 | atomic_set(&ns->count, 1); | ||
| 51 | } | ||
| 52 | return ns; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * copies the nsproxy, setting refcount to 1, and grabbing a | ||
| 57 | * reference to all contained namespaces. Called from | ||
| 58 | * sys_unshare() | ||
| 59 | */ | ||
| 60 | struct nsproxy *dup_namespaces(struct nsproxy *orig) | ||
| 61 | { | ||
| 62 | struct nsproxy *ns = clone_namespaces(orig); | ||
| 63 | |||
| 64 | if (ns) { | ||
| 65 | if (ns->namespace) | ||
| 66 | get_namespace(ns->namespace); | ||
| 67 | if (ns->uts_ns) | ||
| 68 | get_uts_ns(ns->uts_ns); | ||
| 69 | if (ns->ipc_ns) | ||
| 70 | get_ipc_ns(ns->ipc_ns); | ||
| 71 | } | ||
| 72 | |||
| 73 | return ns; | ||
| 74 | } | ||
| 75 | |||
| 76 | /* | ||
| 77 | * called from clone. This now handles copy for nsproxy and all | ||
| 78 | * namespaces therein. | ||
| 79 | */ | ||
| 80 | int copy_namespaces(int flags, struct task_struct *tsk) | ||
| 81 | { | ||
| 82 | struct nsproxy *old_ns = tsk->nsproxy; | ||
| 83 | struct nsproxy *new_ns; | ||
| 84 | int err = 0; | ||
| 85 | |||
| 86 | if (!old_ns) | ||
| 87 | return 0; | ||
| 88 | |||
| 89 | get_nsproxy(old_ns); | ||
| 90 | |||
| 91 | if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC))) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | new_ns = clone_namespaces(old_ns); | ||
| 95 | if (!new_ns) { | ||
| 96 | err = -ENOMEM; | ||
| 97 | goto out; | ||
| 98 | } | ||
| 99 | |||
| 100 | tsk->nsproxy = new_ns; | ||
| 101 | |||
| 102 | err = copy_namespace(flags, tsk); | ||
| 103 | if (err) | ||
| 104 | goto out_ns; | ||
| 105 | |||
| 106 | err = copy_utsname(flags, tsk); | ||
| 107 | if (err) | ||
| 108 | goto out_uts; | ||
| 109 | |||
| 110 | err = copy_ipcs(flags, tsk); | ||
| 111 | if (err) | ||
| 112 | goto out_ipc; | ||
| 113 | |||
| 114 | out: | ||
| 115 | put_nsproxy(old_ns); | ||
| 116 | return err; | ||
| 117 | |||
| 118 | out_ipc: | ||
| 119 | if (new_ns->uts_ns) | ||
| 120 | put_uts_ns(new_ns->uts_ns); | ||
| 121 | out_uts: | ||
| 122 | if (new_ns->namespace) | ||
| 123 | put_namespace(new_ns->namespace); | ||
| 124 | out_ns: | ||
| 125 | tsk->nsproxy = old_ns; | ||
| 126 | kfree(new_ns); | ||
| 127 | goto out; | ||
| 128 | } | ||
| 129 | |||
| 130 | void free_nsproxy(struct nsproxy *ns) | ||
| 131 | { | ||
| 132 | if (ns->namespace) | ||
| 133 | put_namespace(ns->namespace); | ||
| 134 | if (ns->uts_ns) | ||
| 135 | put_uts_ns(ns->uts_ns); | ||
| 136 | if (ns->ipc_ns) | ||
| 137 | put_ipc_ns(ns->ipc_ns); | ||
| 138 | kfree(ns); | ||
| 139 | } | ||
diff --git a/kernel/pid.c b/kernel/pid.c index 8387e8c68193..b914392085f9 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/bootmem.h> | 27 | #include <linux/bootmem.h> |
| 28 | #include <linux/hash.h> | 28 | #include <linux/hash.h> |
| 29 | #include <linux/pspace.h> | ||
| 29 | 30 | ||
| 30 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) | 31 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) |
| 31 | static struct hlist_head *pid_hash; | 32 | static struct hlist_head *pid_hash; |
| @@ -33,17 +34,20 @@ static int pidhash_shift; | |||
| 33 | static kmem_cache_t *pid_cachep; | 34 | static kmem_cache_t *pid_cachep; |
| 34 | 35 | ||
| 35 | int pid_max = PID_MAX_DEFAULT; | 36 | int pid_max = PID_MAX_DEFAULT; |
| 36 | int last_pid; | ||
| 37 | 37 | ||
| 38 | #define RESERVED_PIDS 300 | 38 | #define RESERVED_PIDS 300 |
| 39 | 39 | ||
| 40 | int pid_max_min = RESERVED_PIDS + 1; | 40 | int pid_max_min = RESERVED_PIDS + 1; |
| 41 | int pid_max_max = PID_MAX_LIMIT; | 41 | int pid_max_max = PID_MAX_LIMIT; |
| 42 | 42 | ||
| 43 | #define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8) | ||
| 44 | #define BITS_PER_PAGE (PAGE_SIZE*8) | 43 | #define BITS_PER_PAGE (PAGE_SIZE*8) |
| 45 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) | 44 | #define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) |
| 46 | #define mk_pid(map, off) (((map) - pidmap_array)*BITS_PER_PAGE + (off)) | 45 | |
| 46 | static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off) | ||
| 47 | { | ||
| 48 | return (map - pspace->pidmap)*BITS_PER_PAGE + off; | ||
| 49 | } | ||
| 50 | |||
| 47 | #define find_next_offset(map, off) \ | 51 | #define find_next_offset(map, off) \ |
| 48 | find_next_zero_bit((map)->page, BITS_PER_PAGE, off) | 52 | find_next_zero_bit((map)->page, BITS_PER_PAGE, off) |
| 49 | 53 | ||
| @@ -53,13 +57,12 @@ int pid_max_max = PID_MAX_LIMIT; | |||
| 53 | * value does not cause lots of bitmaps to be allocated, but | 57 | * value does not cause lots of bitmaps to be allocated, but |
| 54 | * the scheme scales to up to 4 million PIDs, runtime. | 58 | * the scheme scales to up to 4 million PIDs, runtime. |
| 55 | */ | 59 | */ |
| 56 | typedef struct pidmap { | 60 | struct pspace init_pspace = { |
| 57 | atomic_t nr_free; | 61 | .pidmap = { |
| 58 | void *page; | 62 | [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } |
| 59 | } pidmap_t; | 63 | }, |
| 60 | 64 | .last_pid = 0 | |
| 61 | static pidmap_t pidmap_array[PIDMAP_ENTRIES] = | 65 | }; |
| 62 | { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } }; | ||
| 63 | 66 | ||
| 64 | /* | 67 | /* |
| 65 | * Note: disable interrupts while the pidmap_lock is held as an | 68 | * Note: disable interrupts while the pidmap_lock is held as an |
| @@ -74,40 +77,41 @@ static pidmap_t pidmap_array[PIDMAP_ENTRIES] = | |||
| 74 | * irq handlers that take it we can leave the interrupts enabled. | 77 | * irq handlers that take it we can leave the interrupts enabled. |
| 75 | * For now it is easier to be safe than to prove it can't happen. | 78 | * For now it is easier to be safe than to prove it can't happen. |
| 76 | */ | 79 | */ |
| 80 | |||
| 77 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); | 81 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); |
| 78 | 82 | ||
| 79 | static fastcall void free_pidmap(int pid) | 83 | static fastcall void free_pidmap(struct pspace *pspace, int pid) |
| 80 | { | 84 | { |
| 81 | pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE; | 85 | struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE; |
| 82 | int offset = pid & BITS_PER_PAGE_MASK; | 86 | int offset = pid & BITS_PER_PAGE_MASK; |
| 83 | 87 | ||
| 84 | clear_bit(offset, map->page); | 88 | clear_bit(offset, map->page); |
| 85 | atomic_inc(&map->nr_free); | 89 | atomic_inc(&map->nr_free); |
| 86 | } | 90 | } |
| 87 | 91 | ||
| 88 | static int alloc_pidmap(void) | 92 | static int alloc_pidmap(struct pspace *pspace) |
| 89 | { | 93 | { |
| 90 | int i, offset, max_scan, pid, last = last_pid; | 94 | int i, offset, max_scan, pid, last = pspace->last_pid; |
| 91 | pidmap_t *map; | 95 | struct pidmap *map; |
| 92 | 96 | ||
| 93 | pid = last + 1; | 97 | pid = last + 1; |
| 94 | if (pid >= pid_max) | 98 | if (pid >= pid_max) |
| 95 | pid = RESERVED_PIDS; | 99 | pid = RESERVED_PIDS; |
| 96 | offset = pid & BITS_PER_PAGE_MASK; | 100 | offset = pid & BITS_PER_PAGE_MASK; |
| 97 | map = &pidmap_array[pid/BITS_PER_PAGE]; | 101 | map = &pspace->pidmap[pid/BITS_PER_PAGE]; |
| 98 | max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset; | 102 | max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset; |
| 99 | for (i = 0; i <= max_scan; ++i) { | 103 | for (i = 0; i <= max_scan; ++i) { |
| 100 | if (unlikely(!map->page)) { | 104 | if (unlikely(!map->page)) { |
| 101 | unsigned long page = get_zeroed_page(GFP_KERNEL); | 105 | void *page = kzalloc(PAGE_SIZE, GFP_KERNEL); |
| 102 | /* | 106 | /* |
| 103 | * Free the page if someone raced with us | 107 | * Free the page if someone raced with us |
| 104 | * installing it: | 108 | * installing it: |
| 105 | */ | 109 | */ |
| 106 | spin_lock_irq(&pidmap_lock); | 110 | spin_lock_irq(&pidmap_lock); |
| 107 | if (map->page) | 111 | if (map->page) |
| 108 | free_page(page); | 112 | kfree(page); |
| 109 | else | 113 | else |
| 110 | map->page = (void *)page; | 114 | map->page = page; |
| 111 | spin_unlock_irq(&pidmap_lock); | 115 | spin_unlock_irq(&pidmap_lock); |
| 112 | if (unlikely(!map->page)) | 116 | if (unlikely(!map->page)) |
| 113 | break; | 117 | break; |
| @@ -116,11 +120,11 @@ static int alloc_pidmap(void) | |||
| 116 | do { | 120 | do { |
| 117 | if (!test_and_set_bit(offset, map->page)) { | 121 | if (!test_and_set_bit(offset, map->page)) { |
| 118 | atomic_dec(&map->nr_free); | 122 | atomic_dec(&map->nr_free); |
| 119 | last_pid = pid; | 123 | pspace->last_pid = pid; |
| 120 | return pid; | 124 | return pid; |
| 121 | } | 125 | } |
| 122 | offset = find_next_offset(map, offset); | 126 | offset = find_next_offset(map, offset); |
| 123 | pid = mk_pid(map, offset); | 127 | pid = mk_pid(pspace, map, offset); |
| 124 | /* | 128 | /* |
| 125 | * find_next_offset() found a bit, the pid from it | 129 | * find_next_offset() found a bit, the pid from it |
| 126 | * is in-bounds, and if we fell back to the last | 130 | * is in-bounds, and if we fell back to the last |
| @@ -131,16 +135,34 @@ static int alloc_pidmap(void) | |||
| 131 | (i != max_scan || pid < last || | 135 | (i != max_scan || pid < last || |
| 132 | !((last+1) & BITS_PER_PAGE_MASK))); | 136 | !((last+1) & BITS_PER_PAGE_MASK))); |
| 133 | } | 137 | } |
| 134 | if (map < &pidmap_array[(pid_max-1)/BITS_PER_PAGE]) { | 138 | if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) { |
| 135 | ++map; | 139 | ++map; |
| 136 | offset = 0; | 140 | offset = 0; |
| 137 | } else { | 141 | } else { |
| 138 | map = &pidmap_array[0]; | 142 | map = &pspace->pidmap[0]; |
| 139 | offset = RESERVED_PIDS; | 143 | offset = RESERVED_PIDS; |
| 140 | if (unlikely(last == offset)) | 144 | if (unlikely(last == offset)) |
| 141 | break; | 145 | break; |
| 142 | } | 146 | } |
| 143 | pid = mk_pid(map, offset); | 147 | pid = mk_pid(pspace, map, offset); |
| 148 | } | ||
| 149 | return -1; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int next_pidmap(struct pspace *pspace, int last) | ||
| 153 | { | ||
| 154 | int offset; | ||
| 155 | struct pidmap *map, *end; | ||
| 156 | |||
| 157 | offset = (last + 1) & BITS_PER_PAGE_MASK; | ||
| 158 | map = &pspace->pidmap[(last + 1)/BITS_PER_PAGE]; | ||
| 159 | end = &pspace->pidmap[PIDMAP_ENTRIES]; | ||
| 160 | for (; map < end; map++, offset = 0) { | ||
| 161 | if (unlikely(!map->page)) | ||
| 162 | continue; | ||
| 163 | offset = find_next_bit((map)->page, BITS_PER_PAGE, offset); | ||
| 164 | if (offset < BITS_PER_PAGE) | ||
| 165 | return mk_pid(pspace, map, offset); | ||
| 144 | } | 166 | } |
| 145 | return -1; | 167 | return -1; |
| 146 | } | 168 | } |
| @@ -153,6 +175,7 @@ fastcall void put_pid(struct pid *pid) | |||
| 153 | atomic_dec_and_test(&pid->count)) | 175 | atomic_dec_and_test(&pid->count)) |
| 154 | kmem_cache_free(pid_cachep, pid); | 176 | kmem_cache_free(pid_cachep, pid); |
| 155 | } | 177 | } |
| 178 | EXPORT_SYMBOL_GPL(put_pid); | ||
| 156 | 179 | ||
| 157 | static void delayed_put_pid(struct rcu_head *rhp) | 180 | static void delayed_put_pid(struct rcu_head *rhp) |
| 158 | { | 181 | { |
| @@ -169,7 +192,7 @@ fastcall void free_pid(struct pid *pid) | |||
| 169 | hlist_del_rcu(&pid->pid_chain); | 192 | hlist_del_rcu(&pid->pid_chain); |
| 170 | spin_unlock_irqrestore(&pidmap_lock, flags); | 193 | spin_unlock_irqrestore(&pidmap_lock, flags); |
| 171 | 194 | ||
| 172 | free_pidmap(pid->nr); | 195 | free_pidmap(&init_pspace, pid->nr); |
| 173 | call_rcu(&pid->rcu, delayed_put_pid); | 196 | call_rcu(&pid->rcu, delayed_put_pid); |
| 174 | } | 197 | } |
| 175 | 198 | ||
| @@ -183,7 +206,7 @@ struct pid *alloc_pid(void) | |||
| 183 | if (!pid) | 206 | if (!pid) |
| 184 | goto out; | 207 | goto out; |
| 185 | 208 | ||
| 186 | nr = alloc_pidmap(); | 209 | nr = alloc_pidmap(&init_pspace); |
| 187 | if (nr < 0) | 210 | if (nr < 0) |
| 188 | goto out_free; | 211 | goto out_free; |
| 189 | 212 | ||
| @@ -217,6 +240,7 @@ struct pid * fastcall find_pid(int nr) | |||
| 217 | } | 240 | } |
| 218 | return NULL; | 241 | return NULL; |
| 219 | } | 242 | } |
| 243 | EXPORT_SYMBOL_GPL(find_pid); | ||
| 220 | 244 | ||
| 221 | int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr) | 245 | int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr) |
| 222 | { | 246 | { |
| @@ -280,6 +304,15 @@ struct task_struct *find_task_by_pid_type(int type, int nr) | |||
| 280 | 304 | ||
| 281 | EXPORT_SYMBOL(find_task_by_pid_type); | 305 | EXPORT_SYMBOL(find_task_by_pid_type); |
| 282 | 306 | ||
| 307 | struct pid *get_task_pid(struct task_struct *task, enum pid_type type) | ||
| 308 | { | ||
| 309 | struct pid *pid; | ||
| 310 | rcu_read_lock(); | ||
| 311 | pid = get_pid(task->pids[type].pid); | ||
| 312 | rcu_read_unlock(); | ||
| 313 | return pid; | ||
| 314 | } | ||
| 315 | |||
| 283 | struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) | 316 | struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type) |
| 284 | { | 317 | { |
| 285 | struct task_struct *result; | 318 | struct task_struct *result; |
| @@ -303,6 +336,26 @@ struct pid *find_get_pid(pid_t nr) | |||
| 303 | } | 336 | } |
| 304 | 337 | ||
| 305 | /* | 338 | /* |
| 339 | * Used by proc to find the first pid that is greater then or equal to nr. | ||
| 340 | * | ||
| 341 | * If there is a pid at nr this function is exactly the same as find_pid. | ||
| 342 | */ | ||
| 343 | struct pid *find_ge_pid(int nr) | ||
| 344 | { | ||
| 345 | struct pid *pid; | ||
| 346 | |||
| 347 | do { | ||
| 348 | pid = find_pid(nr); | ||
| 349 | if (pid) | ||
| 350 | break; | ||
| 351 | nr = next_pidmap(&init_pspace, nr); | ||
| 352 | } while (nr > 0); | ||
| 353 | |||
| 354 | return pid; | ||
| 355 | } | ||
| 356 | EXPORT_SYMBOL_GPL(find_get_pid); | ||
| 357 | |||
| 358 | /* | ||
| 306 | * The pid hash table is scaled according to the amount of memory in the | 359 | * The pid hash table is scaled according to the amount of memory in the |
| 307 | * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or | 360 | * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or |
| 308 | * more. | 361 | * more. |
| @@ -329,10 +382,10 @@ void __init pidhash_init(void) | |||
| 329 | 382 | ||
| 330 | void __init pidmap_init(void) | 383 | void __init pidmap_init(void) |
| 331 | { | 384 | { |
| 332 | pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL); | 385 | init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); |
| 333 | /* Reserve PID 0. We never call free_pidmap(0) */ | 386 | /* Reserve PID 0. We never call free_pidmap(0) */ |
| 334 | set_bit(0, pidmap_array->page); | 387 | set_bit(0, init_pspace.pidmap[0].page); |
| 335 | atomic_dec(&pidmap_array->nr_free); | 388 | atomic_dec(&init_pspace.pidmap[0].nr_free); |
| 336 | 389 | ||
| 337 | pid_cachep = kmem_cache_create("pid", sizeof(struct pid), | 390 | pid_cachep = kmem_cache_create("pid", sizeof(struct pid), |
| 338 | __alignof__(struct pid), | 391 | __alignof__(struct pid), |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 1b84313cbab5..99f9b7d177d6 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -906,7 +906,7 @@ static void init_header(struct swsusp_info *info) | |||
| 906 | memset(info, 0, sizeof(struct swsusp_info)); | 906 | memset(info, 0, sizeof(struct swsusp_info)); |
| 907 | info->version_code = LINUX_VERSION_CODE; | 907 | info->version_code = LINUX_VERSION_CODE; |
| 908 | info->num_physpages = num_physpages; | 908 | info->num_physpages = num_physpages; |
| 909 | memcpy(&info->uts, &system_utsname, sizeof(system_utsname)); | 909 | memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname)); |
| 910 | info->cpus = num_online_cpus(); | 910 | info->cpus = num_online_cpus(); |
| 911 | info->image_pages = nr_copy_pages; | 911 | info->image_pages = nr_copy_pages; |
| 912 | info->pages = nr_copy_pages + nr_meta_pages + 1; | 912 | info->pages = nr_copy_pages + nr_meta_pages + 1; |
| @@ -1050,13 +1050,13 @@ static inline int check_header(struct swsusp_info *info) | |||
| 1050 | reason = "kernel version"; | 1050 | reason = "kernel version"; |
| 1051 | if (info->num_physpages != num_physpages) | 1051 | if (info->num_physpages != num_physpages) |
| 1052 | reason = "memory size"; | 1052 | reason = "memory size"; |
| 1053 | if (strcmp(info->uts.sysname,system_utsname.sysname)) | 1053 | if (strcmp(info->uts.sysname,init_utsname()->sysname)) |
| 1054 | reason = "system type"; | 1054 | reason = "system type"; |
| 1055 | if (strcmp(info->uts.release,system_utsname.release)) | 1055 | if (strcmp(info->uts.release,init_utsname()->release)) |
| 1056 | reason = "kernel release"; | 1056 | reason = "kernel release"; |
| 1057 | if (strcmp(info->uts.version,system_utsname.version)) | 1057 | if (strcmp(info->uts.version,init_utsname()->version)) |
| 1058 | reason = "version"; | 1058 | reason = "version"; |
| 1059 | if (strcmp(info->uts.machine,system_utsname.machine)) | 1059 | if (strcmp(info->uts.machine,init_utsname()->machine)) |
| 1060 | reason = "machine"; | 1060 | reason = "machine"; |
| 1061 | if (reason) { | 1061 | if (reason) { |
| 1062 | printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason); | 1062 | printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason); |
diff --git a/kernel/sched.c b/kernel/sched.c index 2bbd948f0169..e4e54e86f4a2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -4384,7 +4384,10 @@ EXPORT_SYMBOL(cpu_present_map); | |||
| 4384 | 4384 | ||
| 4385 | #ifndef CONFIG_SMP | 4385 | #ifndef CONFIG_SMP |
| 4386 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL; | 4386 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL; |
| 4387 | EXPORT_SYMBOL(cpu_online_map); | ||
| 4388 | |||
| 4387 | cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL; | 4389 | cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL; |
| 4390 | EXPORT_SYMBOL(cpu_possible_map); | ||
| 4388 | #endif | 4391 | #endif |
| 4389 | 4392 | ||
| 4390 | long sched_getaffinity(pid_t pid, cpumask_t *mask) | 4393 | long sched_getaffinity(pid_t pid, cpumask_t *mask) |
diff --git a/kernel/signal.c b/kernel/signal.c index fb5da6d19f14..7ed8d5304bec 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -1055,28 +1055,44 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | |||
| 1055 | } | 1055 | } |
| 1056 | 1056 | ||
| 1057 | /* | 1057 | /* |
| 1058 | * kill_pg_info() sends a signal to a process group: this is what the tty | 1058 | * kill_pgrp_info() sends a signal to a process group: this is what the tty |
| 1059 | * control characters do (^C, ^Z etc) | 1059 | * control characters do (^C, ^Z etc) |
| 1060 | */ | 1060 | */ |
| 1061 | 1061 | ||
| 1062 | int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | 1062 | int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) |
| 1063 | { | 1063 | { |
| 1064 | struct task_struct *p = NULL; | 1064 | struct task_struct *p = NULL; |
| 1065 | int retval, success; | 1065 | int retval, success; |
| 1066 | 1066 | ||
| 1067 | if (pgrp <= 0) | ||
| 1068 | return -EINVAL; | ||
| 1069 | |||
| 1070 | success = 0; | 1067 | success = 0; |
| 1071 | retval = -ESRCH; | 1068 | retval = -ESRCH; |
| 1072 | do_each_task_pid(pgrp, PIDTYPE_PGID, p) { | 1069 | do_each_pid_task(pgrp, PIDTYPE_PGID, p) { |
| 1073 | int err = group_send_sig_info(sig, info, p); | 1070 | int err = group_send_sig_info(sig, info, p); |
| 1074 | success |= !err; | 1071 | success |= !err; |
| 1075 | retval = err; | 1072 | retval = err; |
| 1076 | } while_each_task_pid(pgrp, PIDTYPE_PGID, p); | 1073 | } while_each_pid_task(pgrp, PIDTYPE_PGID, p); |
| 1077 | return success ? 0 : retval; | 1074 | return success ? 0 : retval; |
| 1078 | } | 1075 | } |
| 1079 | 1076 | ||
| 1077 | int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) | ||
| 1078 | { | ||
| 1079 | int retval; | ||
| 1080 | |||
| 1081 | read_lock(&tasklist_lock); | ||
| 1082 | retval = __kill_pgrp_info(sig, info, pgrp); | ||
| 1083 | read_unlock(&tasklist_lock); | ||
| 1084 | |||
| 1085 | return retval; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | ||
| 1089 | { | ||
| 1090 | if (pgrp <= 0) | ||
| 1091 | return -EINVAL; | ||
| 1092 | |||
| 1093 | return __kill_pgrp_info(sig, info, find_pid(pgrp)); | ||
| 1094 | } | ||
| 1095 | |||
| 1080 | int | 1096 | int |
| 1081 | kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | 1097 | kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) |
| 1082 | { | 1098 | { |
| @@ -1089,8 +1105,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp) | |||
| 1089 | return retval; | 1105 | return retval; |
| 1090 | } | 1106 | } |
| 1091 | 1107 | ||
| 1092 | int | 1108 | int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) |
| 1093 | kill_proc_info(int sig, struct siginfo *info, pid_t pid) | ||
| 1094 | { | 1109 | { |
| 1095 | int error; | 1110 | int error; |
| 1096 | int acquired_tasklist_lock = 0; | 1111 | int acquired_tasklist_lock = 0; |
| @@ -1101,7 +1116,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
| 1101 | read_lock(&tasklist_lock); | 1116 | read_lock(&tasklist_lock); |
| 1102 | acquired_tasklist_lock = 1; | 1117 | acquired_tasklist_lock = 1; |
| 1103 | } | 1118 | } |
| 1104 | p = find_task_by_pid(pid); | 1119 | p = pid_task(pid, PIDTYPE_PID); |
| 1105 | error = -ESRCH; | 1120 | error = -ESRCH; |
| 1106 | if (p) | 1121 | if (p) |
| 1107 | error = group_send_sig_info(sig, info, p); | 1122 | error = group_send_sig_info(sig, info, p); |
| @@ -1111,8 +1126,18 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
| 1111 | return error; | 1126 | return error; |
| 1112 | } | 1127 | } |
| 1113 | 1128 | ||
| 1114 | /* like kill_proc_info(), but doesn't use uid/euid of "current" */ | 1129 | int |
| 1115 | int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | 1130 | kill_proc_info(int sig, struct siginfo *info, pid_t pid) |
| 1131 | { | ||
| 1132 | int error; | ||
| 1133 | rcu_read_lock(); | ||
| 1134 | error = kill_pid_info(sig, info, find_pid(pid)); | ||
| 1135 | rcu_read_unlock(); | ||
| 1136 | return error; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | /* like kill_pid_info(), but doesn't use uid/euid of "current" */ | ||
| 1140 | int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | ||
| 1116 | uid_t uid, uid_t euid, u32 secid) | 1141 | uid_t uid, uid_t euid, u32 secid) |
| 1117 | { | 1142 | { |
| 1118 | int ret = -EINVAL; | 1143 | int ret = -EINVAL; |
| @@ -1122,7 +1147,7 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | |||
| 1122 | return ret; | 1147 | return ret; |
| 1123 | 1148 | ||
| 1124 | read_lock(&tasklist_lock); | 1149 | read_lock(&tasklist_lock); |
| 1125 | p = find_task_by_pid(pid); | 1150 | p = pid_task(pid, PIDTYPE_PID); |
| 1126 | if (!p) { | 1151 | if (!p) { |
| 1127 | ret = -ESRCH; | 1152 | ret = -ESRCH; |
| 1128 | goto out_unlock; | 1153 | goto out_unlock; |
| @@ -1146,7 +1171,7 @@ out_unlock: | |||
| 1146 | read_unlock(&tasklist_lock); | 1171 | read_unlock(&tasklist_lock); |
| 1147 | return ret; | 1172 | return ret; |
| 1148 | } | 1173 | } |
| 1149 | EXPORT_SYMBOL_GPL(kill_proc_info_as_uid); | 1174 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); |
| 1150 | 1175 | ||
| 1151 | /* | 1176 | /* |
| 1152 | * kill_something_info() interprets pid in interesting ways just like kill(2). | 1177 | * kill_something_info() interprets pid in interesting ways just like kill(2). |
| @@ -1264,6 +1289,18 @@ force_sigsegv(int sig, struct task_struct *p) | |||
| 1264 | return 0; | 1289 | return 0; |
| 1265 | } | 1290 | } |
| 1266 | 1291 | ||
| 1292 | int kill_pgrp(struct pid *pid, int sig, int priv) | ||
| 1293 | { | ||
| 1294 | return kill_pgrp_info(sig, __si_special(priv), pid); | ||
| 1295 | } | ||
| 1296 | EXPORT_SYMBOL(kill_pgrp); | ||
| 1297 | |||
| 1298 | int kill_pid(struct pid *pid, int sig, int priv) | ||
| 1299 | { | ||
| 1300 | return kill_pid_info(sig, __si_special(priv), pid); | ||
| 1301 | } | ||
| 1302 | EXPORT_SYMBOL(kill_pid); | ||
| 1303 | |||
| 1267 | int | 1304 | int |
| 1268 | kill_pg(pid_t pgrp, int sig, int priv) | 1305 | kill_pg(pid_t pgrp, int sig, int priv) |
| 1269 | { | 1306 | { |
diff --git a/kernel/sys.c b/kernel/sys.c index 2460581c928c..2314867ae34f 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -92,7 +92,8 @@ EXPORT_SYMBOL(fs_overflowgid); | |||
| 92 | */ | 92 | */ |
| 93 | 93 | ||
| 94 | int C_A_D = 1; | 94 | int C_A_D = 1; |
| 95 | int cad_pid = 1; | 95 | struct pid *cad_pid; |
| 96 | EXPORT_SYMBOL(cad_pid); | ||
| 96 | 97 | ||
| 97 | /* | 98 | /* |
| 98 | * Notifier list for kernel code which wants to be called | 99 | * Notifier list for kernel code which wants to be called |
| @@ -221,7 +222,7 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | |||
| 221 | * of the last notifier function called. | 222 | * of the last notifier function called. |
| 222 | */ | 223 | */ |
| 223 | 224 | ||
| 224 | int atomic_notifier_call_chain(struct atomic_notifier_head *nh, | 225 | int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, |
| 225 | unsigned long val, void *v) | 226 | unsigned long val, void *v) |
| 226 | { | 227 | { |
| 227 | int ret; | 228 | int ret; |
| @@ -773,10 +774,9 @@ void ctrl_alt_del(void) | |||
| 773 | if (C_A_D) | 774 | if (C_A_D) |
| 774 | schedule_work(&cad_work); | 775 | schedule_work(&cad_work); |
| 775 | else | 776 | else |
| 776 | kill_proc(cad_pid, SIGINT, 1); | 777 | kill_cad_pid(SIGINT, 1); |
| 777 | } | 778 | } |
| 778 | 779 | ||
| 779 | |||
| 780 | /* | 780 | /* |
| 781 | * Unprivileged users may change the real gid to the effective gid | 781 | * Unprivileged users may change the real gid to the effective gid |
| 782 | * or vice versa. (BSD-style) | 782 | * or vice versa. (BSD-style) |
| @@ -1655,7 +1655,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name) | |||
| 1655 | int errno = 0; | 1655 | int errno = 0; |
| 1656 | 1656 | ||
| 1657 | down_read(&uts_sem); | 1657 | down_read(&uts_sem); |
| 1658 | if (copy_to_user(name,&system_utsname,sizeof *name)) | 1658 | if (copy_to_user(name, utsname(), sizeof *name)) |
| 1659 | errno = -EFAULT; | 1659 | errno = -EFAULT; |
| 1660 | up_read(&uts_sem); | 1660 | up_read(&uts_sem); |
| 1661 | return errno; | 1661 | return errno; |
| @@ -1673,8 +1673,8 @@ asmlinkage long sys_sethostname(char __user *name, int len) | |||
| 1673 | down_write(&uts_sem); | 1673 | down_write(&uts_sem); |
| 1674 | errno = -EFAULT; | 1674 | errno = -EFAULT; |
| 1675 | if (!copy_from_user(tmp, name, len)) { | 1675 | if (!copy_from_user(tmp, name, len)) { |
| 1676 | memcpy(system_utsname.nodename, tmp, len); | 1676 | memcpy(utsname()->nodename, tmp, len); |
| 1677 | system_utsname.nodename[len] = 0; | 1677 | utsname()->nodename[len] = 0; |
| 1678 | errno = 0; | 1678 | errno = 0; |
| 1679 | } | 1679 | } |
| 1680 | up_write(&uts_sem); | 1680 | up_write(&uts_sem); |
| @@ -1690,11 +1690,11 @@ asmlinkage long sys_gethostname(char __user *name, int len) | |||
| 1690 | if (len < 0) | 1690 | if (len < 0) |
| 1691 | return -EINVAL; | 1691 | return -EINVAL; |
| 1692 | down_read(&uts_sem); | 1692 | down_read(&uts_sem); |
| 1693 | i = 1 + strlen(system_utsname.nodename); | 1693 | i = 1 + strlen(utsname()->nodename); |
| 1694 | if (i > len) | 1694 | if (i > len) |
| 1695 | i = len; | 1695 | i = len; |
| 1696 | errno = 0; | 1696 | errno = 0; |
| 1697 | if (copy_to_user(name, system_utsname.nodename, i)) | 1697 | if (copy_to_user(name, utsname()->nodename, i)) |
| 1698 | errno = -EFAULT; | 1698 | errno = -EFAULT; |
| 1699 | up_read(&uts_sem); | 1699 | up_read(&uts_sem); |
| 1700 | return errno; | 1700 | return errno; |
| @@ -1719,8 +1719,8 @@ asmlinkage long sys_setdomainname(char __user *name, int len) | |||
| 1719 | down_write(&uts_sem); | 1719 | down_write(&uts_sem); |
| 1720 | errno = -EFAULT; | 1720 | errno = -EFAULT; |
| 1721 | if (!copy_from_user(tmp, name, len)) { | 1721 | if (!copy_from_user(tmp, name, len)) { |
| 1722 | memcpy(system_utsname.domainname, tmp, len); | 1722 | memcpy(utsname()->domainname, tmp, len); |
| 1723 | system_utsname.domainname[len] = 0; | 1723 | utsname()->domainname[len] = 0; |
| 1724 | errno = 0; | 1724 | errno = 0; |
| 1725 | } | 1725 | } |
| 1726 | up_write(&uts_sem); | 1726 | up_write(&uts_sem); |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ba42694f0453..8020fb273c4f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -68,7 +68,6 @@ extern int sysrq_enabled; | |||
| 68 | extern int core_uses_pid; | 68 | extern int core_uses_pid; |
| 69 | extern int suid_dumpable; | 69 | extern int suid_dumpable; |
| 70 | extern char core_pattern[]; | 70 | extern char core_pattern[]; |
| 71 | extern int cad_pid; | ||
| 72 | extern int pid_max; | 71 | extern int pid_max; |
| 73 | extern int min_free_kbytes; | 72 | extern int min_free_kbytes; |
| 74 | extern int printk_ratelimit_jiffies; | 73 | extern int printk_ratelimit_jiffies; |
| @@ -92,13 +91,8 @@ extern char modprobe_path[]; | |||
| 92 | extern int sg_big_buff; | 91 | extern int sg_big_buff; |
| 93 | #endif | 92 | #endif |
| 94 | #ifdef CONFIG_SYSVIPC | 93 | #ifdef CONFIG_SYSVIPC |
| 95 | extern size_t shm_ctlmax; | 94 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, |
| 96 | extern size_t shm_ctlall; | 95 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 97 | extern int shm_ctlmni; | ||
| 98 | extern int msg_ctlmax; | ||
| 99 | extern int msg_ctlmnb; | ||
| 100 | extern int msg_ctlmni; | ||
| 101 | extern int sem_ctls[]; | ||
| 102 | #endif | 96 | #endif |
| 103 | 97 | ||
| 104 | #ifdef __sparc__ | 98 | #ifdef __sparc__ |
| @@ -139,7 +133,10 @@ static int parse_table(int __user *, int, void __user *, size_t __user *, | |||
| 139 | void __user *, size_t, ctl_table *, void **); | 133 | void __user *, size_t, ctl_table *, void **); |
| 140 | #endif | 134 | #endif |
| 141 | 135 | ||
| 142 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | 136 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, |
| 137 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
| 138 | |||
| 139 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, | ||
| 143 | void __user *buffer, size_t *lenp, loff_t *ppos); | 140 | void __user *buffer, size_t *lenp, loff_t *ppos); |
| 144 | 141 | ||
| 145 | static ctl_table root_table[]; | 142 | static ctl_table root_table[]; |
| @@ -229,51 +226,100 @@ static ctl_table root_table[] = { | |||
| 229 | }; | 226 | }; |
| 230 | 227 | ||
| 231 | static ctl_table kern_table[] = { | 228 | static ctl_table kern_table[] = { |
| 229 | #ifndef CONFIG_UTS_NS | ||
| 230 | { | ||
| 231 | .ctl_name = KERN_OSTYPE, | ||
| 232 | .procname = "ostype", | ||
| 233 | .data = init_uts_ns.name.sysname, | ||
| 234 | .maxlen = sizeof(init_uts_ns.name.sysname), | ||
| 235 | .mode = 0444, | ||
| 236 | .proc_handler = &proc_do_uts_string, | ||
| 237 | .strategy = &sysctl_string, | ||
| 238 | }, | ||
| 239 | { | ||
| 240 | .ctl_name = KERN_OSRELEASE, | ||
| 241 | .procname = "osrelease", | ||
| 242 | .data = init_uts_ns.name.release, | ||
| 243 | .maxlen = sizeof(init_uts_ns.name.release), | ||
| 244 | .mode = 0444, | ||
| 245 | .proc_handler = &proc_do_uts_string, | ||
| 246 | .strategy = &sysctl_string, | ||
| 247 | }, | ||
| 248 | { | ||
| 249 | .ctl_name = KERN_VERSION, | ||
| 250 | .procname = "version", | ||
| 251 | .data = init_uts_ns.name.version, | ||
| 252 | .maxlen = sizeof(init_uts_ns.name.version), | ||
| 253 | .mode = 0444, | ||
| 254 | .proc_handler = &proc_do_uts_string, | ||
| 255 | .strategy = &sysctl_string, | ||
| 256 | }, | ||
| 257 | { | ||
| 258 | .ctl_name = KERN_NODENAME, | ||
| 259 | .procname = "hostname", | ||
| 260 | .data = init_uts_ns.name.nodename, | ||
| 261 | .maxlen = sizeof(init_uts_ns.name.nodename), | ||
| 262 | .mode = 0644, | ||
| 263 | .proc_handler = &proc_do_uts_string, | ||
| 264 | .strategy = &sysctl_string, | ||
| 265 | }, | ||
| 266 | { | ||
| 267 | .ctl_name = KERN_DOMAINNAME, | ||
| 268 | .procname = "domainname", | ||
| 269 | .data = init_uts_ns.name.domainname, | ||
| 270 | .maxlen = sizeof(init_uts_ns.name.domainname), | ||
| 271 | .mode = 0644, | ||
| 272 | .proc_handler = &proc_do_uts_string, | ||
| 273 | .strategy = &sysctl_string, | ||
| 274 | }, | ||
| 275 | #else /* !CONFIG_UTS_NS */ | ||
| 232 | { | 276 | { |
| 233 | .ctl_name = KERN_OSTYPE, | 277 | .ctl_name = KERN_OSTYPE, |
| 234 | .procname = "ostype", | 278 | .procname = "ostype", |
| 235 | .data = system_utsname.sysname, | 279 | .data = NULL, |
| 236 | .maxlen = sizeof(system_utsname.sysname), | 280 | /* could maybe use __NEW_UTS_LEN here? */ |
| 281 | .maxlen = FIELD_SIZEOF(struct new_utsname, sysname), | ||
| 237 | .mode = 0444, | 282 | .mode = 0444, |
| 238 | .proc_handler = &proc_doutsstring, | 283 | .proc_handler = &proc_do_uts_string, |
| 239 | .strategy = &sysctl_string, | 284 | .strategy = &sysctl_string, |
| 240 | }, | 285 | }, |
| 241 | { | 286 | { |
| 242 | .ctl_name = KERN_OSRELEASE, | 287 | .ctl_name = KERN_OSRELEASE, |
| 243 | .procname = "osrelease", | 288 | .procname = "osrelease", |
| 244 | .data = system_utsname.release, | 289 | .data = NULL, |
| 245 | .maxlen = sizeof(system_utsname.release), | 290 | .maxlen = FIELD_SIZEOF(struct new_utsname, release), |
| 246 | .mode = 0444, | 291 | .mode = 0444, |
| 247 | .proc_handler = &proc_doutsstring, | 292 | .proc_handler = &proc_do_uts_string, |
| 248 | .strategy = &sysctl_string, | 293 | .strategy = &sysctl_string, |
| 249 | }, | 294 | }, |
| 250 | { | 295 | { |
| 251 | .ctl_name = KERN_VERSION, | 296 | .ctl_name = KERN_VERSION, |
| 252 | .procname = "version", | 297 | .procname = "version", |
| 253 | .data = system_utsname.version, | 298 | .data = NULL, |
| 254 | .maxlen = sizeof(system_utsname.version), | 299 | .maxlen = FIELD_SIZEOF(struct new_utsname, version), |
| 255 | .mode = 0444, | 300 | .mode = 0444, |
| 256 | .proc_handler = &proc_doutsstring, | 301 | .proc_handler = &proc_do_uts_string, |
| 257 | .strategy = &sysctl_string, | 302 | .strategy = &sysctl_string, |
| 258 | }, | 303 | }, |
| 259 | { | 304 | { |
| 260 | .ctl_name = KERN_NODENAME, | 305 | .ctl_name = KERN_NODENAME, |
| 261 | .procname = "hostname", | 306 | .procname = "hostname", |
| 262 | .data = system_utsname.nodename, | 307 | .data = NULL, |
| 263 | .maxlen = sizeof(system_utsname.nodename), | 308 | .maxlen = FIELD_SIZEOF(struct new_utsname, nodename), |
| 264 | .mode = 0644, | 309 | .mode = 0644, |
| 265 | .proc_handler = &proc_doutsstring, | 310 | .proc_handler = &proc_do_uts_string, |
| 266 | .strategy = &sysctl_string, | 311 | .strategy = &sysctl_string, |
| 267 | }, | 312 | }, |
| 268 | { | 313 | { |
| 269 | .ctl_name = KERN_DOMAINNAME, | 314 | .ctl_name = KERN_DOMAINNAME, |
| 270 | .procname = "domainname", | 315 | .procname = "domainname", |
| 271 | .data = system_utsname.domainname, | 316 | .data = NULL, |
| 272 | .maxlen = sizeof(system_utsname.domainname), | 317 | .maxlen = FIELD_SIZEOF(struct new_utsname, domainname), |
| 273 | .mode = 0644, | 318 | .mode = 0644, |
| 274 | .proc_handler = &proc_doutsstring, | 319 | .proc_handler = &proc_do_uts_string, |
| 275 | .strategy = &sysctl_string, | 320 | .strategy = &sysctl_string, |
| 276 | }, | 321 | }, |
| 322 | #endif /* !CONFIG_UTS_NS */ | ||
| 277 | { | 323 | { |
| 278 | .ctl_name = KERN_PANIC, | 324 | .ctl_name = KERN_PANIC, |
| 279 | .procname = "panic", | 325 | .procname = "panic", |
| @@ -432,58 +478,58 @@ static ctl_table kern_table[] = { | |||
| 432 | { | 478 | { |
| 433 | .ctl_name = KERN_SHMMAX, | 479 | .ctl_name = KERN_SHMMAX, |
| 434 | .procname = "shmmax", | 480 | .procname = "shmmax", |
| 435 | .data = &shm_ctlmax, | 481 | .data = NULL, |
| 436 | .maxlen = sizeof (size_t), | 482 | .maxlen = sizeof (size_t), |
| 437 | .mode = 0644, | 483 | .mode = 0644, |
| 438 | .proc_handler = &proc_doulongvec_minmax, | 484 | .proc_handler = &proc_do_ipc_string, |
| 439 | }, | 485 | }, |
| 440 | { | 486 | { |
| 441 | .ctl_name = KERN_SHMALL, | 487 | .ctl_name = KERN_SHMALL, |
| 442 | .procname = "shmall", | 488 | .procname = "shmall", |
| 443 | .data = &shm_ctlall, | 489 | .data = NULL, |
| 444 | .maxlen = sizeof (size_t), | 490 | .maxlen = sizeof (size_t), |
| 445 | .mode = 0644, | 491 | .mode = 0644, |
| 446 | .proc_handler = &proc_doulongvec_minmax, | 492 | .proc_handler = &proc_do_ipc_string, |
| 447 | }, | 493 | }, |
| 448 | { | 494 | { |
| 449 | .ctl_name = KERN_SHMMNI, | 495 | .ctl_name = KERN_SHMMNI, |
| 450 | .procname = "shmmni", | 496 | .procname = "shmmni", |
| 451 | .data = &shm_ctlmni, | 497 | .data = NULL, |
| 452 | .maxlen = sizeof (int), | 498 | .maxlen = sizeof (int), |
| 453 | .mode = 0644, | 499 | .mode = 0644, |
| 454 | .proc_handler = &proc_dointvec, | 500 | .proc_handler = &proc_do_ipc_string, |
| 455 | }, | 501 | }, |
| 456 | { | 502 | { |
| 457 | .ctl_name = KERN_MSGMAX, | 503 | .ctl_name = KERN_MSGMAX, |
| 458 | .procname = "msgmax", | 504 | .procname = "msgmax", |
| 459 | .data = &msg_ctlmax, | 505 | .data = NULL, |
| 460 | .maxlen = sizeof (int), | 506 | .maxlen = sizeof (int), |
| 461 | .mode = 0644, | 507 | .mode = 0644, |
| 462 | .proc_handler = &proc_dointvec, | 508 | .proc_handler = &proc_do_ipc_string, |
| 463 | }, | 509 | }, |
| 464 | { | 510 | { |
| 465 | .ctl_name = KERN_MSGMNI, | 511 | .ctl_name = KERN_MSGMNI, |
| 466 | .procname = "msgmni", | 512 | .procname = "msgmni", |
| 467 | .data = &msg_ctlmni, | 513 | .data = NULL, |
| 468 | .maxlen = sizeof (int), | 514 | .maxlen = sizeof (int), |
| 469 | .mode = 0644, | 515 | .mode = 0644, |
| 470 | .proc_handler = &proc_dointvec, | 516 | .proc_handler = &proc_do_ipc_string, |
| 471 | }, | 517 | }, |
| 472 | { | 518 | { |
| 473 | .ctl_name = KERN_MSGMNB, | 519 | .ctl_name = KERN_MSGMNB, |
| 474 | .procname = "msgmnb", | 520 | .procname = "msgmnb", |
| 475 | .data = &msg_ctlmnb, | 521 | .data = NULL, |
| 476 | .maxlen = sizeof (int), | 522 | .maxlen = sizeof (int), |
| 477 | .mode = 0644, | 523 | .mode = 0644, |
| 478 | .proc_handler = &proc_dointvec, | 524 | .proc_handler = &proc_do_ipc_string, |
| 479 | }, | 525 | }, |
| 480 | { | 526 | { |
| 481 | .ctl_name = KERN_SEM, | 527 | .ctl_name = KERN_SEM, |
| 482 | .procname = "sem", | 528 | .procname = "sem", |
| 483 | .data = &sem_ctls, | 529 | .data = NULL, |
| 484 | .maxlen = 4*sizeof (int), | 530 | .maxlen = 4*sizeof (int), |
| 485 | .mode = 0644, | 531 | .mode = 0644, |
| 486 | .proc_handler = &proc_dointvec, | 532 | .proc_handler = &proc_do_ipc_string, |
| 487 | }, | 533 | }, |
| 488 | #endif | 534 | #endif |
| 489 | #ifdef CONFIG_MAGIC_SYSRQ | 535 | #ifdef CONFIG_MAGIC_SYSRQ |
| @@ -499,10 +545,10 @@ static ctl_table kern_table[] = { | |||
| 499 | { | 545 | { |
| 500 | .ctl_name = KERN_CADPID, | 546 | .ctl_name = KERN_CADPID, |
| 501 | .procname = "cad_pid", | 547 | .procname = "cad_pid", |
| 502 | .data = &cad_pid, | 548 | .data = NULL, |
| 503 | .maxlen = sizeof (int), | 549 | .maxlen = sizeof (int), |
| 504 | .mode = 0600, | 550 | .mode = 0600, |
| 505 | .proc_handler = &proc_dointvec, | 551 | .proc_handler = &proc_do_cad_pid, |
| 506 | }, | 552 | }, |
| 507 | { | 553 | { |
| 508 | .ctl_name = KERN_MAX_THREADS, | 554 | .ctl_name = KERN_MAX_THREADS, |
| @@ -1624,32 +1670,15 @@ static ssize_t proc_writesys(struct file * file, const char __user * buf, | |||
| 1624 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); | 1670 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); |
| 1625 | } | 1671 | } |
| 1626 | 1672 | ||
| 1627 | /** | 1673 | static int _proc_do_string(void* data, int maxlen, int write, |
| 1628 | * proc_dostring - read a string sysctl | 1674 | struct file *filp, void __user *buffer, |
| 1629 | * @table: the sysctl table | 1675 | size_t *lenp, loff_t *ppos) |
| 1630 | * @write: %TRUE if this is a write to the sysctl file | ||
| 1631 | * @filp: the file structure | ||
| 1632 | * @buffer: the user buffer | ||
| 1633 | * @lenp: the size of the user buffer | ||
| 1634 | * @ppos: file position | ||
| 1635 | * | ||
| 1636 | * Reads/writes a string from/to the user buffer. If the kernel | ||
| 1637 | * buffer provided is not large enough to hold the string, the | ||
| 1638 | * string is truncated. The copied string is %NULL-terminated. | ||
| 1639 | * If the string is being read by the user process, it is copied | ||
| 1640 | * and a newline '\n' is added. It is truncated if the buffer is | ||
| 1641 | * not large enough. | ||
| 1642 | * | ||
| 1643 | * Returns 0 on success. | ||
| 1644 | */ | ||
| 1645 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
| 1646 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 1647 | { | 1676 | { |
| 1648 | size_t len; | 1677 | size_t len; |
| 1649 | char __user *p; | 1678 | char __user *p; |
| 1650 | char c; | 1679 | char c; |
| 1651 | 1680 | ||
| 1652 | if (!table->data || !table->maxlen || !*lenp || | 1681 | if (!data || !maxlen || !*lenp || |
| 1653 | (*ppos && !write)) { | 1682 | (*ppos && !write)) { |
| 1654 | *lenp = 0; | 1683 | *lenp = 0; |
| 1655 | return 0; | 1684 | return 0; |
| @@ -1665,20 +1694,20 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
| 1665 | break; | 1694 | break; |
| 1666 | len++; | 1695 | len++; |
| 1667 | } | 1696 | } |
| 1668 | if (len >= table->maxlen) | 1697 | if (len >= maxlen) |
| 1669 | len = table->maxlen-1; | 1698 | len = maxlen-1; |
| 1670 | if(copy_from_user(table->data, buffer, len)) | 1699 | if(copy_from_user(data, buffer, len)) |
| 1671 | return -EFAULT; | 1700 | return -EFAULT; |
| 1672 | ((char *) table->data)[len] = 0; | 1701 | ((char *) data)[len] = 0; |
| 1673 | *ppos += *lenp; | 1702 | *ppos += *lenp; |
| 1674 | } else { | 1703 | } else { |
| 1675 | len = strlen(table->data); | 1704 | len = strlen(data); |
| 1676 | if (len > table->maxlen) | 1705 | if (len > maxlen) |
| 1677 | len = table->maxlen; | 1706 | len = maxlen; |
| 1678 | if (len > *lenp) | 1707 | if (len > *lenp) |
| 1679 | len = *lenp; | 1708 | len = *lenp; |
| 1680 | if (len) | 1709 | if (len) |
| 1681 | if(copy_to_user(buffer, table->data, len)) | 1710 | if(copy_to_user(buffer, data, len)) |
| 1682 | return -EFAULT; | 1711 | return -EFAULT; |
| 1683 | if (len < *lenp) { | 1712 | if (len < *lenp) { |
| 1684 | if(put_user('\n', ((char __user *) buffer) + len)) | 1713 | if(put_user('\n', ((char __user *) buffer) + len)) |
| @@ -1691,12 +1720,38 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
| 1691 | return 0; | 1720 | return 0; |
| 1692 | } | 1721 | } |
| 1693 | 1722 | ||
| 1723 | /** | ||
| 1724 | * proc_dostring - read a string sysctl | ||
| 1725 | * @table: the sysctl table | ||
| 1726 | * @write: %TRUE if this is a write to the sysctl file | ||
| 1727 | * @filp: the file structure | ||
| 1728 | * @buffer: the user buffer | ||
| 1729 | * @lenp: the size of the user buffer | ||
| 1730 | * @ppos: file position | ||
| 1731 | * | ||
| 1732 | * Reads/writes a string from/to the user buffer. If the kernel | ||
| 1733 | * buffer provided is not large enough to hold the string, the | ||
| 1734 | * string is truncated. The copied string is %NULL-terminated. | ||
| 1735 | * If the string is being read by the user process, it is copied | ||
| 1736 | * and a newline '\n' is added. It is truncated if the buffer is | ||
| 1737 | * not large enough. | ||
| 1738 | * | ||
| 1739 | * Returns 0 on success. | ||
| 1740 | */ | ||
| 1741 | int proc_dostring(ctl_table *table, int write, struct file *filp, | ||
| 1742 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 1743 | { | ||
| 1744 | return _proc_do_string(table->data, table->maxlen, write, filp, | ||
| 1745 | buffer, lenp, ppos); | ||
| 1746 | } | ||
| 1747 | |||
| 1694 | /* | 1748 | /* |
| 1695 | * Special case of dostring for the UTS structure. This has locks | 1749 | * Special case of dostring for the UTS structure. This has locks |
| 1696 | * to observe. Should this be in kernel/sys.c ???? | 1750 | * to observe. Should this be in kernel/sys.c ???? |
| 1697 | */ | 1751 | */ |
| 1698 | 1752 | ||
| 1699 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | 1753 | #ifndef CONFIG_UTS_NS |
| 1754 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
| 1700 | void __user *buffer, size_t *lenp, loff_t *ppos) | 1755 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 1701 | { | 1756 | { |
| 1702 | int r; | 1757 | int r; |
| @@ -1712,6 +1767,48 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | |||
| 1712 | } | 1767 | } |
| 1713 | return r; | 1768 | return r; |
| 1714 | } | 1769 | } |
| 1770 | #else /* !CONFIG_UTS_NS */ | ||
| 1771 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
| 1772 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 1773 | { | ||
| 1774 | int r; | ||
| 1775 | struct uts_namespace* uts_ns = current->nsproxy->uts_ns; | ||
| 1776 | char* which; | ||
| 1777 | |||
| 1778 | switch (table->ctl_name) { | ||
| 1779 | case KERN_OSTYPE: | ||
| 1780 | which = uts_ns->name.sysname; | ||
| 1781 | break; | ||
| 1782 | case KERN_NODENAME: | ||
| 1783 | which = uts_ns->name.nodename; | ||
| 1784 | break; | ||
| 1785 | case KERN_OSRELEASE: | ||
| 1786 | which = uts_ns->name.release; | ||
| 1787 | break; | ||
| 1788 | case KERN_VERSION: | ||
| 1789 | which = uts_ns->name.version; | ||
| 1790 | break; | ||
| 1791 | case KERN_DOMAINNAME: | ||
| 1792 | which = uts_ns->name.domainname; | ||
| 1793 | break; | ||
| 1794 | default: | ||
| 1795 | r = -EINVAL; | ||
| 1796 | goto out; | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | if (!write) { | ||
| 1800 | down_read(&uts_sem); | ||
| 1801 | r=_proc_do_string(which,table->maxlen,0,filp,buffer,lenp, ppos); | ||
| 1802 | up_read(&uts_sem); | ||
| 1803 | } else { | ||
| 1804 | down_write(&uts_sem); | ||
| 1805 | r=_proc_do_string(which,table->maxlen,1,filp,buffer,lenp, ppos); | ||
| 1806 | up_write(&uts_sem); | ||
| 1807 | } | ||
| 1808 | out: | ||
| 1809 | return r; | ||
| 1810 | } | ||
| 1811 | #endif /* !CONFIG_UTS_NS */ | ||
| 1715 | 1812 | ||
| 1716 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | 1813 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, |
| 1717 | int *valp, | 1814 | int *valp, |
| @@ -1732,8 +1829,9 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | |||
| 1732 | return 0; | 1829 | return 0; |
| 1733 | } | 1830 | } |
| 1734 | 1831 | ||
| 1735 | static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | 1832 | static int __do_proc_dointvec(void *tbl_data, ctl_table *table, |
| 1736 | void __user *buffer, size_t *lenp, loff_t *ppos, | 1833 | int write, struct file *filp, void __user *buffer, |
| 1834 | size_t *lenp, loff_t *ppos, | ||
| 1737 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | 1835 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, |
| 1738 | int write, void *data), | 1836 | int write, void *data), |
| 1739 | void *data) | 1837 | void *data) |
| @@ -1746,13 +1844,13 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | |||
| 1746 | char buf[TMPBUFLEN], *p; | 1844 | char buf[TMPBUFLEN], *p; |
| 1747 | char __user *s = buffer; | 1845 | char __user *s = buffer; |
| 1748 | 1846 | ||
| 1749 | if (!table->data || !table->maxlen || !*lenp || | 1847 | if (!tbl_data || !table->maxlen || !*lenp || |
| 1750 | (*ppos && !write)) { | 1848 | (*ppos && !write)) { |
| 1751 | *lenp = 0; | 1849 | *lenp = 0; |
| 1752 | return 0; | 1850 | return 0; |
| 1753 | } | 1851 | } |
| 1754 | 1852 | ||
| 1755 | i = (int *) table->data; | 1853 | i = (int *) tbl_data; |
| 1756 | vleft = table->maxlen / sizeof(*i); | 1854 | vleft = table->maxlen / sizeof(*i); |
| 1757 | left = *lenp; | 1855 | left = *lenp; |
| 1758 | 1856 | ||
| @@ -1841,6 +1939,16 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | |||
| 1841 | #undef TMPBUFLEN | 1939 | #undef TMPBUFLEN |
| 1842 | } | 1940 | } |
| 1843 | 1941 | ||
| 1942 | static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, | ||
| 1943 | void __user *buffer, size_t *lenp, loff_t *ppos, | ||
| 1944 | int (*conv)(int *negp, unsigned long *lvalp, int *valp, | ||
| 1945 | int write, void *data), | ||
| 1946 | void *data) | ||
| 1947 | { | ||
| 1948 | return __do_proc_dointvec(table->data, table, write, filp, | ||
| 1949 | buffer, lenp, ppos, conv, data); | ||
| 1950 | } | ||
| 1951 | |||
| 1844 | /** | 1952 | /** |
| 1845 | * proc_dointvec - read a vector of integers | 1953 | * proc_dointvec - read a vector of integers |
| 1846 | * @table: the sysctl table | 1954 | * @table: the sysctl table |
| @@ -1974,7 +2082,7 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, | |||
| 1974 | do_proc_dointvec_minmax_conv, ¶m); | 2082 | do_proc_dointvec_minmax_conv, ¶m); |
| 1975 | } | 2083 | } |
| 1976 | 2084 | ||
| 1977 | static int do_proc_doulongvec_minmax(ctl_table *table, int write, | 2085 | static int __do_proc_doulongvec_minmax(void *data, ctl_table *table, int write, |
| 1978 | struct file *filp, | 2086 | struct file *filp, |
| 1979 | void __user *buffer, | 2087 | void __user *buffer, |
| 1980 | size_t *lenp, loff_t *ppos, | 2088 | size_t *lenp, loff_t *ppos, |
| @@ -1988,13 +2096,13 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, | |||
| 1988 | char buf[TMPBUFLEN], *p; | 2096 | char buf[TMPBUFLEN], *p; |
| 1989 | char __user *s = buffer; | 2097 | char __user *s = buffer; |
| 1990 | 2098 | ||
| 1991 | if (!table->data || !table->maxlen || !*lenp || | 2099 | if (!data || !table->maxlen || !*lenp || |
| 1992 | (*ppos && !write)) { | 2100 | (*ppos && !write)) { |
| 1993 | *lenp = 0; | 2101 | *lenp = 0; |
| 1994 | return 0; | 2102 | return 0; |
| 1995 | } | 2103 | } |
| 1996 | 2104 | ||
| 1997 | i = (unsigned long *) table->data; | 2105 | i = (unsigned long *) data; |
| 1998 | min = (unsigned long *) table->extra1; | 2106 | min = (unsigned long *) table->extra1; |
| 1999 | max = (unsigned long *) table->extra2; | 2107 | max = (unsigned long *) table->extra2; |
| 2000 | vleft = table->maxlen / sizeof(unsigned long); | 2108 | vleft = table->maxlen / sizeof(unsigned long); |
| @@ -2079,6 +2187,17 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write, | |||
| 2079 | #undef TMPBUFLEN | 2187 | #undef TMPBUFLEN |
| 2080 | } | 2188 | } |
| 2081 | 2189 | ||
| 2190 | static int do_proc_doulongvec_minmax(ctl_table *table, int write, | ||
| 2191 | struct file *filp, | ||
| 2192 | void __user *buffer, | ||
| 2193 | size_t *lenp, loff_t *ppos, | ||
| 2194 | unsigned long convmul, | ||
| 2195 | unsigned long convdiv) | ||
| 2196 | { | ||
| 2197 | return __do_proc_doulongvec_minmax(table->data, table, write, | ||
| 2198 | filp, buffer, lenp, ppos, convmul, convdiv); | ||
| 2199 | } | ||
| 2200 | |||
| 2082 | /** | 2201 | /** |
| 2083 | * proc_doulongvec_minmax - read a vector of long integers with min/max values | 2202 | * proc_doulongvec_minmax - read a vector of long integers with min/max values |
| 2084 | * @table: the sysctl table | 2203 | * @table: the sysctl table |
| @@ -2267,6 +2386,71 @@ int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, | |||
| 2267 | do_proc_dointvec_ms_jiffies_conv, NULL); | 2386 | do_proc_dointvec_ms_jiffies_conv, NULL); |
| 2268 | } | 2387 | } |
| 2269 | 2388 | ||
| 2389 | #ifdef CONFIG_SYSVIPC | ||
| 2390 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, | ||
| 2391 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2392 | { | ||
| 2393 | void *data; | ||
| 2394 | struct ipc_namespace *ns; | ||
| 2395 | |||
| 2396 | ns = current->nsproxy->ipc_ns; | ||
| 2397 | |||
| 2398 | switch (table->ctl_name) { | ||
| 2399 | case KERN_SHMMAX: | ||
| 2400 | data = &ns->shm_ctlmax; | ||
| 2401 | goto proc_minmax; | ||
| 2402 | case KERN_SHMALL: | ||
| 2403 | data = &ns->shm_ctlall; | ||
| 2404 | goto proc_minmax; | ||
| 2405 | case KERN_SHMMNI: | ||
| 2406 | data = &ns->shm_ctlmni; | ||
| 2407 | break; | ||
| 2408 | case KERN_MSGMAX: | ||
| 2409 | data = &ns->msg_ctlmax; | ||
| 2410 | break; | ||
| 2411 | case KERN_MSGMNI: | ||
| 2412 | data = &ns->msg_ctlmni; | ||
| 2413 | break; | ||
| 2414 | case KERN_MSGMNB: | ||
| 2415 | data = &ns->msg_ctlmnb; | ||
| 2416 | break; | ||
| 2417 | case KERN_SEM: | ||
| 2418 | data = &ns->sem_ctls; | ||
| 2419 | break; | ||
| 2420 | default: | ||
| 2421 | return -EINVAL; | ||
| 2422 | } | ||
| 2423 | |||
| 2424 | return __do_proc_dointvec(data, table, write, filp, buffer, | ||
| 2425 | lenp, ppos, NULL, NULL); | ||
| 2426 | proc_minmax: | ||
| 2427 | return __do_proc_doulongvec_minmax(data, table, write, filp, buffer, | ||
| 2428 | lenp, ppos, 1l, 1l); | ||
| 2429 | } | ||
| 2430 | #endif | ||
| 2431 | |||
| 2432 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, | ||
| 2433 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2434 | { | ||
| 2435 | struct pid *new_pid; | ||
| 2436 | pid_t tmp; | ||
| 2437 | int r; | ||
| 2438 | |||
| 2439 | tmp = pid_nr(cad_pid); | ||
| 2440 | |||
| 2441 | r = __do_proc_dointvec(&tmp, table, write, filp, buffer, | ||
| 2442 | lenp, ppos, NULL, NULL); | ||
| 2443 | if (r || !write) | ||
| 2444 | return r; | ||
| 2445 | |||
| 2446 | new_pid = find_get_pid(tmp); | ||
| 2447 | if (!new_pid) | ||
| 2448 | return -ESRCH; | ||
| 2449 | |||
| 2450 | put_pid(xchg(&cad_pid, new_pid)); | ||
| 2451 | return 0; | ||
| 2452 | } | ||
| 2453 | |||
| 2270 | #else /* CONFIG_PROC_FS */ | 2454 | #else /* CONFIG_PROC_FS */ |
| 2271 | 2455 | ||
| 2272 | int proc_dostring(ctl_table *table, int write, struct file *filp, | 2456 | int proc_dostring(ctl_table *table, int write, struct file *filp, |
| @@ -2275,12 +2459,20 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
| 2275 | return -ENOSYS; | 2459 | return -ENOSYS; |
| 2276 | } | 2460 | } |
| 2277 | 2461 | ||
| 2278 | static int proc_doutsstring(ctl_table *table, int write, struct file *filp, | 2462 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, |
| 2279 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2463 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 2280 | { | 2464 | { |
| 2281 | return -ENOSYS; | 2465 | return -ENOSYS; |
| 2282 | } | 2466 | } |
| 2283 | 2467 | ||
| 2468 | #ifdef CONFIG_SYSVIPC | ||
| 2469 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, | ||
| 2470 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 2471 | { | ||
| 2472 | return -ENOSYS; | ||
| 2473 | } | ||
| 2474 | #endif | ||
| 2475 | |||
| 2284 | int proc_dointvec(ctl_table *table, int write, struct file *filp, | 2476 | int proc_dointvec(ctl_table *table, int write, struct file *filp, |
| 2285 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2477 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 2286 | { | 2478 | { |
diff --git a/kernel/utsname.c b/kernel/utsname.c new file mode 100644 index 000000000000..c859164a6993 --- /dev/null +++ b/kernel/utsname.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2004 IBM Corporation | ||
| 3 | * | ||
| 4 | * Author: Serge Hallyn <serue@us.ibm.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License as | ||
| 8 | * published by the Free Software Foundation, version 2 of the | ||
| 9 | * License. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/uts.h> | ||
| 14 | #include <linux/utsname.h> | ||
| 15 | #include <linux/version.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Clone a new ns copying an original utsname, setting refcount to 1 | ||
| 19 | * @old_ns: namespace to clone | ||
| 20 | * Return NULL on error (failure to kmalloc), new ns otherwise | ||
| 21 | */ | ||
| 22 | static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns) | ||
| 23 | { | ||
| 24 | struct uts_namespace *ns; | ||
| 25 | |||
| 26 | ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL); | ||
| 27 | if (ns) { | ||
| 28 | memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); | ||
| 29 | kref_init(&ns->kref); | ||
| 30 | } | ||
| 31 | return ns; | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * unshare the current process' utsname namespace. | ||
| 36 | * called only in sys_unshare() | ||
| 37 | */ | ||
| 38 | int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts) | ||
| 39 | { | ||
| 40 | if (unshare_flags & CLONE_NEWUTS) { | ||
| 41 | if (!capable(CAP_SYS_ADMIN)) | ||
| 42 | return -EPERM; | ||
| 43 | |||
| 44 | *new_uts = clone_uts_ns(current->nsproxy->uts_ns); | ||
| 45 | if (!*new_uts) | ||
| 46 | return -ENOMEM; | ||
| 47 | } | ||
| 48 | |||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | /* | ||
| 53 | * Copy task tsk's utsname namespace, or clone it if flags | ||
| 54 | * specifies CLONE_NEWUTS. In latter case, changes to the | ||
| 55 | * utsname of this process won't be seen by parent, and vice | ||
| 56 | * versa. | ||
| 57 | */ | ||
| 58 | int copy_utsname(int flags, struct task_struct *tsk) | ||
| 59 | { | ||
| 60 | struct uts_namespace *old_ns = tsk->nsproxy->uts_ns; | ||
| 61 | struct uts_namespace *new_ns; | ||
| 62 | int err = 0; | ||
| 63 | |||
| 64 | if (!old_ns) | ||
| 65 | return 0; | ||
| 66 | |||
| 67 | get_uts_ns(old_ns); | ||
| 68 | |||
| 69 | if (!(flags & CLONE_NEWUTS)) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (!capable(CAP_SYS_ADMIN)) { | ||
| 73 | err = -EPERM; | ||
| 74 | goto out; | ||
| 75 | } | ||
| 76 | |||
| 77 | new_ns = clone_uts_ns(old_ns); | ||
| 78 | if (!new_ns) { | ||
| 79 | err = -ENOMEM; | ||
| 80 | goto out; | ||
| 81 | } | ||
| 82 | tsk->nsproxy->uts_ns = new_ns; | ||
| 83 | |||
| 84 | out: | ||
| 85 | put_uts_ns(old_ns); | ||
| 86 | return err; | ||
| 87 | } | ||
| 88 | |||
| 89 | void free_uts_ns(struct kref *kref) | ||
| 90 | { | ||
| 91 | struct uts_namespace *ns; | ||
| 92 | |||
| 93 | ns = container_of(kref, struct uts_namespace, kref); | ||
| 94 | kfree(ns); | ||
| 95 | } | ||
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f9ae75cc0145..756a908c441d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -384,3 +384,17 @@ config RCU_TORTURE_TEST | |||
| 384 | at boot time (you probably don't). | 384 | at boot time (you probably don't). |
| 385 | Say M if you want the RCU torture tests to build as a module. | 385 | Say M if you want the RCU torture tests to build as a module. |
| 386 | Say N if you are unsure. | 386 | Say N if you are unsure. |
| 387 | |||
| 388 | config LKDTM | ||
| 389 | tristate "Linux Kernel Dump Test Tool Module" | ||
| 390 | depends on KPROBES | ||
| 391 | default n | ||
| 392 | help | ||
| 393 | This module enables testing of the different dumping mechanisms by | ||
| 394 | inducing system failures at predefined crash points. | ||
| 395 | If you don't need it: say N | ||
| 396 | Choose M here to compile this code as a module. The module will be | ||
| 397 | called lkdtm. | ||
| 398 | |||
| 399 | Documentation on how to use the module can be found in | ||
| 400 | drivers/misc/lkdtm.c | ||
diff --git a/lib/Makefile b/lib/Makefile index ddf3e676e1f4..b0361756e22e 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for some libs needed in the kernel. | 2 | # Makefile for some libs needed in the kernel. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ | 5 | lib-y := ctype.o string.o vsprintf.o cmdline.o \ |
| 6 | bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ | 6 | bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ |
| 7 | idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ | 7 | idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ |
| 8 | sha1.o | 8 | sha1.o |
diff --git a/lib/cpumask.c b/lib/cpumask.c index 3a67dc5ada7d..7a2a73f88d59 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c | |||
| @@ -43,3 +43,19 @@ int __any_online_cpu(const cpumask_t *mask) | |||
| 43 | return cpu; | 43 | return cpu; |
| 44 | } | 44 | } |
| 45 | EXPORT_SYMBOL(__any_online_cpu); | 45 | EXPORT_SYMBOL(__any_online_cpu); |
| 46 | |||
| 47 | #if MAX_NUMNODES > 1 | ||
| 48 | /* | ||
| 49 | * Find the highest possible node id. | ||
| 50 | */ | ||
| 51 | int highest_possible_node_id(void) | ||
| 52 | { | ||
| 53 | unsigned int node; | ||
| 54 | unsigned int highest = 0; | ||
| 55 | |||
| 56 | for_each_node_mask(node, node_possible_map) | ||
| 57 | highest = node; | ||
| 58 | return highest; | ||
| 59 | } | ||
| 60 | EXPORT_SYMBOL(highest_possible_node_id); | ||
| 61 | #endif | ||
diff --git a/lib/errno.c b/lib/errno.c deleted file mode 100644 index 41cb9d76c052..000000000000 --- a/lib/errno.c +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/lib/errno.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
| 5 | */ | ||
| 6 | |||
| 7 | int errno; | ||
diff --git a/lib/genalloc.c b/lib/genalloc.c index 71338b48e889..75ae68ce03e1 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c | |||
| @@ -14,11 +14,13 @@ | |||
| 14 | #include <linux/genalloc.h> | 14 | #include <linux/genalloc.h> |
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | /* | 17 | /** |
| 18 | * Create a new special memory pool. | 18 | * gen_pool_create - create a new special memory pool |
| 19 | * | ||
| 20 | * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents | 19 | * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents |
| 21 | * @nid: node id of the node the pool structure should be allocated on, or -1 | 20 | * @nid: node id of the node the pool structure should be allocated on, or -1 |
| 21 | * | ||
| 22 | * Create a new special memory pool that can be used to manage special purpose | ||
| 23 | * memory not managed by the regular kmalloc/kfree interface. | ||
| 22 | */ | 24 | */ |
| 23 | struct gen_pool *gen_pool_create(int min_alloc_order, int nid) | 25 | struct gen_pool *gen_pool_create(int min_alloc_order, int nid) |
| 24 | { | 26 | { |
| @@ -34,15 +36,15 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid) | |||
| 34 | } | 36 | } |
| 35 | EXPORT_SYMBOL(gen_pool_create); | 37 | EXPORT_SYMBOL(gen_pool_create); |
| 36 | 38 | ||
| 37 | 39 | /** | |
| 38 | /* | 40 | * gen_pool_add - add a new chunk of special memory to the pool |
| 39 | * Add a new chunk of memory to the specified pool. | ||
| 40 | * | ||
| 41 | * @pool: pool to add new memory chunk to | 41 | * @pool: pool to add new memory chunk to |
| 42 | * @addr: starting address of memory chunk to add to pool | 42 | * @addr: starting address of memory chunk to add to pool |
| 43 | * @size: size in bytes of the memory chunk to add to pool | 43 | * @size: size in bytes of the memory chunk to add to pool |
| 44 | * @nid: node id of the node the chunk structure and bitmap should be | 44 | * @nid: node id of the node the chunk structure and bitmap should be |
| 45 | * allocated on, or -1 | 45 | * allocated on, or -1 |
| 46 | * | ||
| 47 | * Add a new chunk of special memory to the specified pool. | ||
| 46 | */ | 48 | */ |
| 47 | int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, | 49 | int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, |
| 48 | int nid) | 50 | int nid) |
| @@ -69,13 +71,44 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size, | |||
| 69 | } | 71 | } |
| 70 | EXPORT_SYMBOL(gen_pool_add); | 72 | EXPORT_SYMBOL(gen_pool_add); |
| 71 | 73 | ||
| 72 | 74 | /** | |
| 73 | /* | 75 | * gen_pool_destroy - destroy a special memory pool |
| 74 | * Allocate the requested number of bytes from the specified pool. | 76 | * @pool: pool to destroy |
| 75 | * Uses a first-fit algorithm. | ||
| 76 | * | 77 | * |
| 78 | * Destroy the specified special memory pool. Verifies that there are no | ||
| 79 | * outstanding allocations. | ||
| 80 | */ | ||
| 81 | void gen_pool_destroy(struct gen_pool *pool) | ||
| 82 | { | ||
| 83 | struct list_head *_chunk, *_next_chunk; | ||
| 84 | struct gen_pool_chunk *chunk; | ||
| 85 | int order = pool->min_alloc_order; | ||
| 86 | int bit, end_bit; | ||
| 87 | |||
| 88 | |||
| 89 | write_lock(&pool->lock); | ||
| 90 | list_for_each_safe(_chunk, _next_chunk, &pool->chunks) { | ||
| 91 | chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk); | ||
| 92 | list_del(&chunk->next_chunk); | ||
| 93 | |||
| 94 | end_bit = (chunk->end_addr - chunk->start_addr) >> order; | ||
| 95 | bit = find_next_bit(chunk->bits, end_bit, 0); | ||
| 96 | BUG_ON(bit < end_bit); | ||
| 97 | |||
| 98 | kfree(chunk); | ||
| 99 | } | ||
| 100 | kfree(pool); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | EXPORT_SYMBOL(gen_pool_destroy); | ||
| 104 | |||
| 105 | /** | ||
| 106 | * gen_pool_alloc - allocate special memory from the pool | ||
| 77 | * @pool: pool to allocate from | 107 | * @pool: pool to allocate from |
| 78 | * @size: number of bytes to allocate from the pool | 108 | * @size: number of bytes to allocate from the pool |
| 109 | * | ||
| 110 | * Allocate the requested number of bytes from the specified pool. | ||
| 111 | * Uses a first-fit algorithm. | ||
| 79 | */ | 112 | */ |
| 80 | unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) | 113 | unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) |
| 81 | { | 114 | { |
| @@ -127,13 +160,13 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size) | |||
| 127 | } | 160 | } |
| 128 | EXPORT_SYMBOL(gen_pool_alloc); | 161 | EXPORT_SYMBOL(gen_pool_alloc); |
| 129 | 162 | ||
| 130 | 163 | /** | |
| 131 | /* | 164 | * gen_pool_free - free allocated special memory back to the pool |
| 132 | * Free the specified memory back to the specified pool. | ||
| 133 | * | ||
| 134 | * @pool: pool to free to | 165 | * @pool: pool to free to |
| 135 | * @addr: starting address of memory to free back to pool | 166 | * @addr: starting address of memory to free back to pool |
| 136 | * @size: size in bytes of memory to free | 167 | * @size: size in bytes of memory to free |
| 168 | * | ||
| 169 | * Free previously allocated special memory back to the specified pool. | ||
| 137 | */ | 170 | */ |
| 138 | void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size) | 171 | void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size) |
| 139 | { | 172 | { |
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 26f322737db0..1958ad1b8541 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c | |||
| @@ -1011,7 +1011,7 @@ static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsign | |||
| 1011 | 1011 | ||
| 1012 | /* ---- TTY structure ---- */ | 1012 | /* ---- TTY structure ---- */ |
| 1013 | 1013 | ||
| 1014 | static struct tty_operations rfcomm_ops = { | 1014 | static const struct tty_operations rfcomm_ops = { |
| 1015 | .open = rfcomm_tty_open, | 1015 | .open = rfcomm_tty_open, |
| 1016 | .close = rfcomm_tty_close, | 1016 | .close = rfcomm_tty_close, |
| 1017 | .write = rfcomm_tty_write, | 1017 | .write = rfcomm_tty_write, |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 1fbb38415b19..f8ce84759159 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
| @@ -366,7 +366,7 @@ static int __init ic_defaults(void) | |||
| 366 | */ | 366 | */ |
| 367 | 367 | ||
| 368 | if (!ic_host_name_set) | 368 | if (!ic_host_name_set) |
| 369 | sprintf(system_utsname.nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); | 369 | sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); |
| 370 | 370 | ||
| 371 | if (root_server_addr == INADDR_NONE) | 371 | if (root_server_addr == INADDR_NONE) |
| 372 | root_server_addr = ic_servaddr; | 372 | root_server_addr = ic_servaddr; |
| @@ -805,7 +805,7 @@ static void __init ic_do_bootp_ext(u8 *ext) | |||
| 805 | } | 805 | } |
| 806 | break; | 806 | break; |
| 807 | case 12: /* Host name */ | 807 | case 12: /* Host name */ |
| 808 | ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN); | 808 | ic_bootp_string(utsname()->nodename, ext+1, *ext, __NEW_UTS_LEN); |
| 809 | ic_host_name_set = 1; | 809 | ic_host_name_set = 1; |
| 810 | break; | 810 | break; |
| 811 | case 15: /* Domain name (DNS) */ | 811 | case 15: /* Domain name (DNS) */ |
| @@ -816,7 +816,7 @@ static void __init ic_do_bootp_ext(u8 *ext) | |||
| 816 | ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); | 816 | ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path)); |
| 817 | break; | 817 | break; |
| 818 | case 40: /* NIS Domain name (_not_ DNS) */ | 818 | case 40: /* NIS Domain name (_not_ DNS) */ |
| 819 | ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN); | 819 | ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN); |
| 820 | break; | 820 | break; |
| 821 | } | 821 | } |
| 822 | } | 822 | } |
| @@ -1368,7 +1368,7 @@ static int __init ip_auto_config(void) | |||
| 1368 | printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask)); | 1368 | printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask)); |
| 1369 | printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway)); | 1369 | printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway)); |
| 1370 | printk(",\n host=%s, domain=%s, nis-domain=%s", | 1370 | printk(",\n host=%s, domain=%s, nis-domain=%s", |
| 1371 | system_utsname.nodename, ic_domain, system_utsname.domainname); | 1371 | utsname()->nodename, ic_domain, utsname()->domainname); |
| 1372 | printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr)); | 1372 | printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr)); |
| 1373 | printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr)); | 1373 | printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr)); |
| 1374 | printk(", rootpath=%s", root_server_path); | 1374 | printk(", rootpath=%s", root_server_path); |
| @@ -1478,11 +1478,11 @@ static int __init ip_auto_config_setup(char *addrs) | |||
| 1478 | case 4: | 1478 | case 4: |
| 1479 | if ((dp = strchr(ip, '.'))) { | 1479 | if ((dp = strchr(ip, '.'))) { |
| 1480 | *dp++ = '\0'; | 1480 | *dp++ = '\0'; |
| 1481 | strlcpy(system_utsname.domainname, dp, | 1481 | strlcpy(utsname()->domainname, dp, |
| 1482 | sizeof(system_utsname.domainname)); | 1482 | sizeof(utsname()->domainname)); |
| 1483 | } | 1483 | } |
| 1484 | strlcpy(system_utsname.nodename, ip, | 1484 | strlcpy(utsname()->nodename, ip, |
| 1485 | sizeof(system_utsname.nodename)); | 1485 | sizeof(utsname()->nodename)); |
| 1486 | ic_host_name_set = 1; | 1486 | ic_host_name_set = 1; |
| 1487 | break; | 1487 | break; |
| 1488 | case 5: | 1488 | case 5: |
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index dab37d2f65fc..4be336f17883 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c | |||
| @@ -99,8 +99,10 @@ static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static struct jprobe tcp_send_probe = { | 101 | static struct jprobe tcp_send_probe = { |
| 102 | .kp = { .addr = (kprobe_opcode_t *) &tcp_sendmsg, }, | 102 | .kp = { |
| 103 | .entry = (kprobe_opcode_t *) &jtcp_sendmsg, | 103 | .symbol_name = "tcp_sendmsg", |
| 104 | }, | ||
| 105 | .entry = JPROBE_ENTRY(jtcp_sendmsg), | ||
| 104 | }; | 106 | }; |
| 105 | 107 | ||
| 106 | 108 | ||
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 3bcdb467efc5..d50a02030ad7 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c | |||
| @@ -79,7 +79,7 @@ static struct tty_driver *driver; | |||
| 79 | 79 | ||
| 80 | hashbin_t *ircomm_tty = NULL; | 80 | hashbin_t *ircomm_tty = NULL; |
| 81 | 81 | ||
| 82 | static struct tty_operations ops = { | 82 | static const struct tty_operations ops = { |
| 83 | .open = ircomm_tty_open, | 83 | .open = ircomm_tty_open, |
| 84 | .close = ircomm_tty_close, | 84 | .close = ircomm_tty_close, |
| 85 | .write = ircomm_tty_write, | 85 | .write = ircomm_tty_write, |
diff --git a/net/socket.c b/net/socket.c index 01918f7a301a..6c9b9b326d76 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -825,7 +825,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
| 825 | break; | 825 | break; |
| 826 | case FIOGETOWN: | 826 | case FIOGETOWN: |
| 827 | case SIOCGPGRP: | 827 | case SIOCGPGRP: |
| 828 | err = put_user(sock->file->f_owner.pid, | 828 | err = put_user(f_getown(sock->file), |
| 829 | (int __user *)argp); | 829 | (int __user *)argp); |
| 830 | break; | 830 | break; |
| 831 | case SIOCGIFBR: | 831 | case SIOCGIFBR: |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 124ff0ceb55b..78696f2dc7d6 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -161,10 +161,10 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /* save the nodename */ | 163 | /* save the nodename */ |
| 164 | clnt->cl_nodelen = strlen(system_utsname.nodename); | 164 | clnt->cl_nodelen = strlen(utsname()->nodename); |
| 165 | if (clnt->cl_nodelen > UNX_MAXNODENAME) | 165 | if (clnt->cl_nodelen > UNX_MAXNODENAME) |
| 166 | clnt->cl_nodelen = UNX_MAXNODENAME; | 166 | clnt->cl_nodelen = UNX_MAXNODENAME; |
| 167 | memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen); | 167 | memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen); |
| 168 | return clnt; | 168 | return clnt; |
| 169 | 169 | ||
| 170 | out_no_auth: | 170 | out_no_auth: |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 26c0531d7e25..192dff5dabcb 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
| @@ -70,6 +70,8 @@ EXPORT_SYMBOL(put_rpccred); | |||
| 70 | /* RPC server stuff */ | 70 | /* RPC server stuff */ |
| 71 | EXPORT_SYMBOL(svc_create); | 71 | EXPORT_SYMBOL(svc_create); |
| 72 | EXPORT_SYMBOL(svc_create_thread); | 72 | EXPORT_SYMBOL(svc_create_thread); |
| 73 | EXPORT_SYMBOL(svc_create_pooled); | ||
| 74 | EXPORT_SYMBOL(svc_set_num_threads); | ||
| 73 | EXPORT_SYMBOL(svc_exit_thread); | 75 | EXPORT_SYMBOL(svc_exit_thread); |
| 74 | EXPORT_SYMBOL(svc_destroy); | 76 | EXPORT_SYMBOL(svc_destroy); |
| 75 | EXPORT_SYMBOL(svc_drop); | 77 | EXPORT_SYMBOL(svc_drop); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 44b8d9d4c18a..a99e67b164c1 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
| @@ -4,6 +4,10 @@ | |||
| 4 | * High-level RPC service routines | 4 | * High-level RPC service routines |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> |
| 7 | * | ||
| 8 | * Multiple threads pools and NUMAisation | ||
| 9 | * Copyright (c) 2006 Silicon Graphics, Inc. | ||
| 10 | * by Greg Banks <gnb@melbourne.sgi.com> | ||
| 7 | */ | 11 | */ |
| 8 | 12 | ||
| 9 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
| @@ -12,6 +16,8 @@ | |||
| 12 | #include <linux/net.h> | 16 | #include <linux/net.h> |
| 13 | #include <linux/in.h> | 17 | #include <linux/in.h> |
| 14 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/module.h> | ||
| 15 | 21 | ||
| 16 | #include <linux/sunrpc/types.h> | 22 | #include <linux/sunrpc/types.h> |
| 17 | #include <linux/sunrpc/xdr.h> | 23 | #include <linux/sunrpc/xdr.h> |
| @@ -23,14 +29,252 @@ | |||
| 23 | #define RPC_PARANOIA 1 | 29 | #define RPC_PARANOIA 1 |
| 24 | 30 | ||
| 25 | /* | 31 | /* |
| 32 | * Mode for mapping cpus to pools. | ||
| 33 | */ | ||
| 34 | enum { | ||
| 35 | SVC_POOL_NONE = -1, /* uninitialised, choose one of the others */ | ||
| 36 | SVC_POOL_GLOBAL, /* no mapping, just a single global pool | ||
| 37 | * (legacy & UP mode) */ | ||
| 38 | SVC_POOL_PERCPU, /* one pool per cpu */ | ||
| 39 | SVC_POOL_PERNODE /* one pool per numa node */ | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * Structure for mapping cpus to pools and vice versa. | ||
| 44 | * Setup once during sunrpc initialisation. | ||
| 45 | */ | ||
| 46 | static struct svc_pool_map { | ||
| 47 | int mode; /* Note: int not enum to avoid | ||
| 48 | * warnings about "enumeration value | ||
| 49 | * not handled in switch" */ | ||
| 50 | unsigned int npools; | ||
| 51 | unsigned int *pool_to; /* maps pool id to cpu or node */ | ||
| 52 | unsigned int *to_pool; /* maps cpu or node to pool id */ | ||
| 53 | } svc_pool_map = { | ||
| 54 | .mode = SVC_POOL_NONE | ||
| 55 | }; | ||
| 56 | |||
| 57 | |||
| 58 | /* | ||
| 59 | * Detect best pool mapping mode heuristically, | ||
| 60 | * according to the machine's topology. | ||
| 61 | */ | ||
| 62 | static int | ||
| 63 | svc_pool_map_choose_mode(void) | ||
| 64 | { | ||
| 65 | unsigned int node; | ||
| 66 | |||
| 67 | if (num_online_nodes() > 1) { | ||
| 68 | /* | ||
| 69 | * Actually have multiple NUMA nodes, | ||
| 70 | * so split pools on NUMA node boundaries | ||
| 71 | */ | ||
| 72 | return SVC_POOL_PERNODE; | ||
| 73 | } | ||
| 74 | |||
| 75 | node = any_online_node(node_online_map); | ||
| 76 | if (nr_cpus_node(node) > 2) { | ||
| 77 | /* | ||
| 78 | * Non-trivial SMP, or CONFIG_NUMA on | ||
| 79 | * non-NUMA hardware, e.g. with a generic | ||
| 80 | * x86_64 kernel on Xeons. In this case we | ||
| 81 | * want to divide the pools on cpu boundaries. | ||
| 82 | */ | ||
| 83 | return SVC_POOL_PERCPU; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* default: one global pool */ | ||
| 87 | return SVC_POOL_GLOBAL; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Allocate the to_pool[] and pool_to[] arrays. | ||
| 92 | * Returns 0 on success or an errno. | ||
| 93 | */ | ||
| 94 | static int | ||
| 95 | svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) | ||
| 96 | { | ||
| 97 | m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); | ||
| 98 | if (!m->to_pool) | ||
| 99 | goto fail; | ||
| 100 | m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL); | ||
| 101 | if (!m->pool_to) | ||
| 102 | goto fail_free; | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | |||
| 106 | fail_free: | ||
| 107 | kfree(m->to_pool); | ||
| 108 | fail: | ||
| 109 | return -ENOMEM; | ||
| 110 | } | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Initialise the pool map for SVC_POOL_PERCPU mode. | ||
| 114 | * Returns number of pools or <0 on error. | ||
| 115 | */ | ||
| 116 | static int | ||
| 117 | svc_pool_map_init_percpu(struct svc_pool_map *m) | ||
| 118 | { | ||
| 119 | unsigned int maxpools = highest_possible_processor_id()+1; | ||
| 120 | unsigned int pidx = 0; | ||
| 121 | unsigned int cpu; | ||
| 122 | int err; | ||
| 123 | |||
| 124 | err = svc_pool_map_alloc_arrays(m, maxpools); | ||
| 125 | if (err) | ||
| 126 | return err; | ||
| 127 | |||
| 128 | for_each_online_cpu(cpu) { | ||
| 129 | BUG_ON(pidx > maxpools); | ||
| 130 | m->to_pool[cpu] = pidx; | ||
| 131 | m->pool_to[pidx] = cpu; | ||
| 132 | pidx++; | ||
| 133 | } | ||
| 134 | /* cpus brought online later all get mapped to pool0, sorry */ | ||
| 135 | |||
| 136 | return pidx; | ||
| 137 | }; | ||
| 138 | |||
| 139 | |||
| 140 | /* | ||
| 141 | * Initialise the pool map for SVC_POOL_PERNODE mode. | ||
| 142 | * Returns number of pools or <0 on error. | ||
| 143 | */ | ||
| 144 | static int | ||
| 145 | svc_pool_map_init_pernode(struct svc_pool_map *m) | ||
| 146 | { | ||
| 147 | unsigned int maxpools = highest_possible_node_id()+1; | ||
| 148 | unsigned int pidx = 0; | ||
| 149 | unsigned int node; | ||
| 150 | int err; | ||
| 151 | |||
| 152 | err = svc_pool_map_alloc_arrays(m, maxpools); | ||
| 153 | if (err) | ||
| 154 | return err; | ||
| 155 | |||
| 156 | for_each_node_with_cpus(node) { | ||
| 157 | /* some architectures (e.g. SN2) have cpuless nodes */ | ||
| 158 | BUG_ON(pidx > maxpools); | ||
| 159 | m->to_pool[node] = pidx; | ||
| 160 | m->pool_to[pidx] = node; | ||
| 161 | pidx++; | ||
| 162 | } | ||
| 163 | /* nodes brought online later all get mapped to pool0, sorry */ | ||
| 164 | |||
| 165 | return pidx; | ||
| 166 | } | ||
| 167 | |||
| 168 | |||
| 169 | /* | ||
| 170 | * Build the global map of cpus to pools and vice versa. | ||
| 171 | */ | ||
| 172 | static unsigned int | ||
| 173 | svc_pool_map_init(void) | ||
| 174 | { | ||
| 175 | struct svc_pool_map *m = &svc_pool_map; | ||
| 176 | int npools = -1; | ||
| 177 | |||
| 178 | if (m->mode != SVC_POOL_NONE) | ||
| 179 | return m->npools; | ||
| 180 | |||
| 181 | m->mode = svc_pool_map_choose_mode(); | ||
| 182 | |||
| 183 | switch (m->mode) { | ||
| 184 | case SVC_POOL_PERCPU: | ||
| 185 | npools = svc_pool_map_init_percpu(m); | ||
| 186 | break; | ||
| 187 | case SVC_POOL_PERNODE: | ||
| 188 | npools = svc_pool_map_init_pernode(m); | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | |||
| 192 | if (npools < 0) { | ||
| 193 | /* default, or memory allocation failure */ | ||
| 194 | npools = 1; | ||
| 195 | m->mode = SVC_POOL_GLOBAL; | ||
| 196 | } | ||
| 197 | m->npools = npools; | ||
| 198 | |||
| 199 | return m->npools; | ||
| 200 | } | ||
| 201 | |||
| 202 | /* | ||
| 203 | * Set the current thread's cpus_allowed mask so that it | ||
| 204 | * will only run on cpus in the given pool. | ||
| 205 | * | ||
| 206 | * Returns 1 and fills in oldmask iff a cpumask was applied. | ||
| 207 | */ | ||
| 208 | static inline int | ||
| 209 | svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask) | ||
| 210 | { | ||
| 211 | struct svc_pool_map *m = &svc_pool_map; | ||
| 212 | unsigned int node; /* or cpu */ | ||
| 213 | |||
| 214 | /* | ||
| 215 | * The caller checks for sv_nrpools > 1, which | ||
| 216 | * implies that we've been initialized and the | ||
| 217 | * map mode is not NONE. | ||
| 218 | */ | ||
| 219 | BUG_ON(m->mode == SVC_POOL_NONE); | ||
| 220 | |||
| 221 | switch (m->mode) | ||
| 222 | { | ||
| 223 | default: | ||
| 224 | return 0; | ||
| 225 | case SVC_POOL_PERCPU: | ||
| 226 | node = m->pool_to[pidx]; | ||
| 227 | *oldmask = current->cpus_allowed; | ||
| 228 | set_cpus_allowed(current, cpumask_of_cpu(node)); | ||
| 229 | return 1; | ||
| 230 | case SVC_POOL_PERNODE: | ||
| 231 | node = m->pool_to[pidx]; | ||
| 232 | *oldmask = current->cpus_allowed; | ||
| 233 | set_cpus_allowed(current, node_to_cpumask(node)); | ||
| 234 | return 1; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | /* | ||
| 239 | * Use the mapping mode to choose a pool for a given CPU. | ||
| 240 | * Used when enqueueing an incoming RPC. Always returns | ||
| 241 | * a non-NULL pool pointer. | ||
| 242 | */ | ||
| 243 | struct svc_pool * | ||
| 244 | svc_pool_for_cpu(struct svc_serv *serv, int cpu) | ||
| 245 | { | ||
| 246 | struct svc_pool_map *m = &svc_pool_map; | ||
| 247 | unsigned int pidx = 0; | ||
| 248 | |||
| 249 | /* | ||
| 250 | * SVC_POOL_NONE happens in a pure client when | ||
| 251 | * lockd is brought up, so silently treat it the | ||
| 252 | * same as SVC_POOL_GLOBAL. | ||
| 253 | */ | ||
| 254 | |||
| 255 | switch (m->mode) { | ||
| 256 | case SVC_POOL_PERCPU: | ||
| 257 | pidx = m->to_pool[cpu]; | ||
| 258 | break; | ||
| 259 | case SVC_POOL_PERNODE: | ||
| 260 | pidx = m->to_pool[cpu_to_node(cpu)]; | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | return &serv->sv_pools[pidx % serv->sv_nrpools]; | ||
| 264 | } | ||
| 265 | |||
| 266 | |||
| 267 | /* | ||
| 26 | * Create an RPC service | 268 | * Create an RPC service |
| 27 | */ | 269 | */ |
| 28 | struct svc_serv * | 270 | static struct svc_serv * |
| 29 | svc_create(struct svc_program *prog, unsigned int bufsize) | 271 | __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, |
| 272 | void (*shutdown)(struct svc_serv *serv)) | ||
| 30 | { | 273 | { |
| 31 | struct svc_serv *serv; | 274 | struct svc_serv *serv; |
| 32 | int vers; | 275 | int vers; |
| 33 | unsigned int xdrsize; | 276 | unsigned int xdrsize; |
| 277 | unsigned int i; | ||
| 34 | 278 | ||
| 35 | if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) | 279 | if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL))) |
| 36 | return NULL; | 280 | return NULL; |
| @@ -39,6 +283,7 @@ svc_create(struct svc_program *prog, unsigned int bufsize) | |||
| 39 | serv->sv_nrthreads = 1; | 283 | serv->sv_nrthreads = 1; |
| 40 | serv->sv_stats = prog->pg_stats; | 284 | serv->sv_stats = prog->pg_stats; |
| 41 | serv->sv_bufsz = bufsize? bufsize : 4096; | 285 | serv->sv_bufsz = bufsize? bufsize : 4096; |
| 286 | serv->sv_shutdown = shutdown; | ||
| 42 | xdrsize = 0; | 287 | xdrsize = 0; |
| 43 | while (prog) { | 288 | while (prog) { |
| 44 | prog->pg_lovers = prog->pg_nvers-1; | 289 | prog->pg_lovers = prog->pg_nvers-1; |
| @@ -53,20 +298,68 @@ svc_create(struct svc_program *prog, unsigned int bufsize) | |||
| 53 | prog = prog->pg_next; | 298 | prog = prog->pg_next; |
| 54 | } | 299 | } |
| 55 | serv->sv_xdrsize = xdrsize; | 300 | serv->sv_xdrsize = xdrsize; |
| 56 | INIT_LIST_HEAD(&serv->sv_threads); | ||
| 57 | INIT_LIST_HEAD(&serv->sv_sockets); | ||
| 58 | INIT_LIST_HEAD(&serv->sv_tempsocks); | 301 | INIT_LIST_HEAD(&serv->sv_tempsocks); |
| 59 | INIT_LIST_HEAD(&serv->sv_permsocks); | 302 | INIT_LIST_HEAD(&serv->sv_permsocks); |
| 303 | init_timer(&serv->sv_temptimer); | ||
| 60 | spin_lock_init(&serv->sv_lock); | 304 | spin_lock_init(&serv->sv_lock); |
| 61 | 305 | ||
| 306 | serv->sv_nrpools = npools; | ||
| 307 | serv->sv_pools = | ||
| 308 | kcalloc(sizeof(struct svc_pool), serv->sv_nrpools, | ||
| 309 | GFP_KERNEL); | ||
| 310 | if (!serv->sv_pools) { | ||
| 311 | kfree(serv); | ||
| 312 | return NULL; | ||
| 313 | } | ||
| 314 | |||
| 315 | for (i = 0; i < serv->sv_nrpools; i++) { | ||
| 316 | struct svc_pool *pool = &serv->sv_pools[i]; | ||
| 317 | |||
| 318 | dprintk("initialising pool %u for %s\n", | ||
| 319 | i, serv->sv_name); | ||
| 320 | |||
| 321 | pool->sp_id = i; | ||
| 322 | INIT_LIST_HEAD(&pool->sp_threads); | ||
| 323 | INIT_LIST_HEAD(&pool->sp_sockets); | ||
| 324 | INIT_LIST_HEAD(&pool->sp_all_threads); | ||
| 325 | spin_lock_init(&pool->sp_lock); | ||
| 326 | } | ||
| 327 | |||
| 328 | |||
| 62 | /* Remove any stale portmap registrations */ | 329 | /* Remove any stale portmap registrations */ |
| 63 | svc_register(serv, 0, 0); | 330 | svc_register(serv, 0, 0); |
| 64 | 331 | ||
| 65 | return serv; | 332 | return serv; |
| 66 | } | 333 | } |
| 67 | 334 | ||
| 335 | struct svc_serv * | ||
| 336 | svc_create(struct svc_program *prog, unsigned int bufsize, | ||
| 337 | void (*shutdown)(struct svc_serv *serv)) | ||
| 338 | { | ||
| 339 | return __svc_create(prog, bufsize, /*npools*/1, shutdown); | ||
| 340 | } | ||
| 341 | |||
| 342 | struct svc_serv * | ||
| 343 | svc_create_pooled(struct svc_program *prog, unsigned int bufsize, | ||
| 344 | void (*shutdown)(struct svc_serv *serv), | ||
| 345 | svc_thread_fn func, int sig, struct module *mod) | ||
| 346 | { | ||
| 347 | struct svc_serv *serv; | ||
| 348 | unsigned int npools = svc_pool_map_init(); | ||
| 349 | |||
| 350 | serv = __svc_create(prog, bufsize, npools, shutdown); | ||
| 351 | |||
| 352 | if (serv != NULL) { | ||
| 353 | serv->sv_function = func; | ||
| 354 | serv->sv_kill_signal = sig; | ||
| 355 | serv->sv_module = mod; | ||
| 356 | } | ||
| 357 | |||
| 358 | return serv; | ||
| 359 | } | ||
| 360 | |||
| 68 | /* | 361 | /* |
| 69 | * Destroy an RPC service | 362 | * Destroy an RPC service. Should be called with the BKL held |
| 70 | */ | 363 | */ |
| 71 | void | 364 | void |
| 72 | svc_destroy(struct svc_serv *serv) | 365 | svc_destroy(struct svc_serv *serv) |
| @@ -85,12 +378,17 @@ svc_destroy(struct svc_serv *serv) | |||
| 85 | } else | 378 | } else |
| 86 | printk("svc_destroy: no threads for serv=%p!\n", serv); | 379 | printk("svc_destroy: no threads for serv=%p!\n", serv); |
| 87 | 380 | ||
| 381 | del_timer_sync(&serv->sv_temptimer); | ||
| 382 | |||
| 88 | while (!list_empty(&serv->sv_tempsocks)) { | 383 | while (!list_empty(&serv->sv_tempsocks)) { |
| 89 | svsk = list_entry(serv->sv_tempsocks.next, | 384 | svsk = list_entry(serv->sv_tempsocks.next, |
| 90 | struct svc_sock, | 385 | struct svc_sock, |
| 91 | sk_list); | 386 | sk_list); |
| 92 | svc_delete_socket(svsk); | 387 | svc_delete_socket(svsk); |
| 93 | } | 388 | } |
| 389 | if (serv->sv_shutdown) | ||
| 390 | serv->sv_shutdown(serv); | ||
| 391 | |||
| 94 | while (!list_empty(&serv->sv_permsocks)) { | 392 | while (!list_empty(&serv->sv_permsocks)) { |
| 95 | svsk = list_entry(serv->sv_permsocks.next, | 393 | svsk = list_entry(serv->sv_permsocks.next, |
| 96 | struct svc_sock, | 394 | struct svc_sock, |
| @@ -102,6 +400,7 @@ svc_destroy(struct svc_serv *serv) | |||
| 102 | 400 | ||
| 103 | /* Unregister service with the portmapper */ | 401 | /* Unregister service with the portmapper */ |
| 104 | svc_register(serv, 0, 0); | 402 | svc_register(serv, 0, 0); |
| 403 | kfree(serv->sv_pools); | ||
| 105 | kfree(serv); | 404 | kfree(serv); |
| 106 | } | 405 | } |
| 107 | 406 | ||
| @@ -150,13 +449,18 @@ svc_release_buffer(struct svc_rqst *rqstp) | |||
| 150 | } | 449 | } |
| 151 | 450 | ||
| 152 | /* | 451 | /* |
| 153 | * Create a server thread | 452 | * Create a thread in the given pool. Caller must hold BKL. |
| 453 | * On a NUMA or SMP machine, with a multi-pool serv, the thread | ||
| 454 | * will be restricted to run on the cpus belonging to the pool. | ||
| 154 | */ | 455 | */ |
| 155 | int | 456 | static int |
| 156 | svc_create_thread(svc_thread_fn func, struct svc_serv *serv) | 457 | __svc_create_thread(svc_thread_fn func, struct svc_serv *serv, |
| 458 | struct svc_pool *pool) | ||
| 157 | { | 459 | { |
| 158 | struct svc_rqst *rqstp; | 460 | struct svc_rqst *rqstp; |
| 159 | int error = -ENOMEM; | 461 | int error = -ENOMEM; |
| 462 | int have_oldmask = 0; | ||
| 463 | cpumask_t oldmask; | ||
| 160 | 464 | ||
| 161 | rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); | 465 | rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL); |
| 162 | if (!rqstp) | 466 | if (!rqstp) |
| @@ -170,8 +474,21 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv) | |||
| 170 | goto out_thread; | 474 | goto out_thread; |
| 171 | 475 | ||
| 172 | serv->sv_nrthreads++; | 476 | serv->sv_nrthreads++; |
| 477 | spin_lock_bh(&pool->sp_lock); | ||
| 478 | pool->sp_nrthreads++; | ||
| 479 | list_add(&rqstp->rq_all, &pool->sp_all_threads); | ||
| 480 | spin_unlock_bh(&pool->sp_lock); | ||
| 173 | rqstp->rq_server = serv; | 481 | rqstp->rq_server = serv; |
| 482 | rqstp->rq_pool = pool; | ||
| 483 | |||
| 484 | if (serv->sv_nrpools > 1) | ||
| 485 | have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask); | ||
| 486 | |||
| 174 | error = kernel_thread((int (*)(void *)) func, rqstp, 0); | 487 | error = kernel_thread((int (*)(void *)) func, rqstp, 0); |
| 488 | |||
| 489 | if (have_oldmask) | ||
| 490 | set_cpus_allowed(current, oldmask); | ||
| 491 | |||
| 175 | if (error < 0) | 492 | if (error < 0) |
| 176 | goto out_thread; | 493 | goto out_thread; |
| 177 | svc_sock_update_bufs(serv); | 494 | svc_sock_update_bufs(serv); |
| @@ -185,17 +502,136 @@ out_thread: | |||
| 185 | } | 502 | } |
| 186 | 503 | ||
| 187 | /* | 504 | /* |
| 188 | * Destroy an RPC server thread | 505 | * Create a thread in the default pool. Caller must hold BKL. |
| 506 | */ | ||
| 507 | int | ||
| 508 | svc_create_thread(svc_thread_fn func, struct svc_serv *serv) | ||
| 509 | { | ||
| 510 | return __svc_create_thread(func, serv, &serv->sv_pools[0]); | ||
| 511 | } | ||
| 512 | |||
| 513 | /* | ||
| 514 | * Choose a pool in which to create a new thread, for svc_set_num_threads | ||
| 515 | */ | ||
| 516 | static inline struct svc_pool * | ||
| 517 | choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) | ||
| 518 | { | ||
| 519 | if (pool != NULL) | ||
| 520 | return pool; | ||
| 521 | |||
| 522 | return &serv->sv_pools[(*state)++ % serv->sv_nrpools]; | ||
| 523 | } | ||
| 524 | |||
| 525 | /* | ||
| 526 | * Choose a thread to kill, for svc_set_num_threads | ||
| 527 | */ | ||
| 528 | static inline struct task_struct * | ||
| 529 | choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state) | ||
| 530 | { | ||
| 531 | unsigned int i; | ||
| 532 | struct task_struct *task = NULL; | ||
| 533 | |||
| 534 | if (pool != NULL) { | ||
| 535 | spin_lock_bh(&pool->sp_lock); | ||
| 536 | } else { | ||
| 537 | /* choose a pool in round-robin fashion */ | ||
| 538 | for (i = 0; i < serv->sv_nrpools; i++) { | ||
| 539 | pool = &serv->sv_pools[--(*state) % serv->sv_nrpools]; | ||
| 540 | spin_lock_bh(&pool->sp_lock); | ||
| 541 | if (!list_empty(&pool->sp_all_threads)) | ||
| 542 | goto found_pool; | ||
| 543 | spin_unlock_bh(&pool->sp_lock); | ||
| 544 | } | ||
| 545 | return NULL; | ||
| 546 | } | ||
| 547 | |||
| 548 | found_pool: | ||
| 549 | if (!list_empty(&pool->sp_all_threads)) { | ||
| 550 | struct svc_rqst *rqstp; | ||
| 551 | |||
| 552 | /* | ||
| 553 | * Remove from the pool->sp_all_threads list | ||
| 554 | * so we don't try to kill it again. | ||
| 555 | */ | ||
| 556 | rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all); | ||
| 557 | list_del_init(&rqstp->rq_all); | ||
| 558 | task = rqstp->rq_task; | ||
| 559 | } | ||
| 560 | spin_unlock_bh(&pool->sp_lock); | ||
| 561 | |||
| 562 | return task; | ||
| 563 | } | ||
| 564 | |||
| 565 | /* | ||
| 566 | * Create or destroy enough new threads to make the number | ||
| 567 | * of threads the given number. If `pool' is non-NULL, applies | ||
| 568 | * only to threads in that pool, otherwise round-robins between | ||
| 569 | * all pools. Must be called with a svc_get() reference and | ||
| 570 | * the BKL held. | ||
| 571 | * | ||
| 572 | * Destroying threads relies on the service threads filling in | ||
| 573 | * rqstp->rq_task, which only the nfs ones do. Assumes the serv | ||
| 574 | * has been created using svc_create_pooled(). | ||
| 575 | * | ||
| 576 | * Based on code that used to be in nfsd_svc() but tweaked | ||
| 577 | * to be pool-aware. | ||
| 578 | */ | ||
| 579 | int | ||
| 580 | svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) | ||
| 581 | { | ||
| 582 | struct task_struct *victim; | ||
| 583 | int error = 0; | ||
| 584 | unsigned int state = serv->sv_nrthreads-1; | ||
| 585 | |||
| 586 | if (pool == NULL) { | ||
| 587 | /* The -1 assumes caller has done a svc_get() */ | ||
| 588 | nrservs -= (serv->sv_nrthreads-1); | ||
| 589 | } else { | ||
| 590 | spin_lock_bh(&pool->sp_lock); | ||
| 591 | nrservs -= pool->sp_nrthreads; | ||
| 592 | spin_unlock_bh(&pool->sp_lock); | ||
| 593 | } | ||
| 594 | |||
| 595 | /* create new threads */ | ||
| 596 | while (nrservs > 0) { | ||
| 597 | nrservs--; | ||
| 598 | __module_get(serv->sv_module); | ||
| 599 | error = __svc_create_thread(serv->sv_function, serv, | ||
| 600 | choose_pool(serv, pool, &state)); | ||
| 601 | if (error < 0) { | ||
| 602 | module_put(serv->sv_module); | ||
| 603 | break; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | /* destroy old threads */ | ||
| 607 | while (nrservs < 0 && | ||
| 608 | (victim = choose_victim(serv, pool, &state)) != NULL) { | ||
| 609 | send_sig(serv->sv_kill_signal, victim, 1); | ||
| 610 | nrservs++; | ||
| 611 | } | ||
| 612 | |||
| 613 | return error; | ||
| 614 | } | ||
| 615 | |||
| 616 | /* | ||
| 617 | * Called from a server thread as it's exiting. Caller must hold BKL. | ||
| 189 | */ | 618 | */ |
| 190 | void | 619 | void |
| 191 | svc_exit_thread(struct svc_rqst *rqstp) | 620 | svc_exit_thread(struct svc_rqst *rqstp) |
| 192 | { | 621 | { |
| 193 | struct svc_serv *serv = rqstp->rq_server; | 622 | struct svc_serv *serv = rqstp->rq_server; |
| 623 | struct svc_pool *pool = rqstp->rq_pool; | ||
| 194 | 624 | ||
| 195 | svc_release_buffer(rqstp); | 625 | svc_release_buffer(rqstp); |
| 196 | kfree(rqstp->rq_resp); | 626 | kfree(rqstp->rq_resp); |
| 197 | kfree(rqstp->rq_argp); | 627 | kfree(rqstp->rq_argp); |
| 198 | kfree(rqstp->rq_auth_data); | 628 | kfree(rqstp->rq_auth_data); |
| 629 | |||
| 630 | spin_lock_bh(&pool->sp_lock); | ||
| 631 | pool->sp_nrthreads--; | ||
| 632 | list_del(&rqstp->rq_all); | ||
| 633 | spin_unlock_bh(&pool->sp_lock); | ||
| 634 | |||
| 199 | kfree(rqstp); | 635 | kfree(rqstp); |
| 200 | 636 | ||
| 201 | /* Release the server */ | 637 | /* Release the server */ |
| @@ -248,13 +684,14 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port) | |||
| 248 | * Process the RPC request. | 684 | * Process the RPC request. |
| 249 | */ | 685 | */ |
| 250 | int | 686 | int |
| 251 | svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) | 687 | svc_process(struct svc_rqst *rqstp) |
| 252 | { | 688 | { |
| 253 | struct svc_program *progp; | 689 | struct svc_program *progp; |
| 254 | struct svc_version *versp = NULL; /* compiler food */ | 690 | struct svc_version *versp = NULL; /* compiler food */ |
| 255 | struct svc_procedure *procp = NULL; | 691 | struct svc_procedure *procp = NULL; |
| 256 | struct kvec * argv = &rqstp->rq_arg.head[0]; | 692 | struct kvec * argv = &rqstp->rq_arg.head[0]; |
| 257 | struct kvec * resv = &rqstp->rq_res.head[0]; | 693 | struct kvec * resv = &rqstp->rq_res.head[0]; |
| 694 | struct svc_serv *serv = rqstp->rq_server; | ||
| 258 | kxdrproc_t xdr; | 695 | kxdrproc_t xdr; |
| 259 | __be32 *statp; | 696 | __be32 *statp; |
| 260 | u32 dir, prog, vers, proc; | 697 | u32 dir, prog, vers, proc; |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 1020d54b01d0..40d41a2831d7 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
| @@ -348,12 +348,9 @@ int auth_unix_forget_old(struct auth_domain *dom) | |||
| 348 | 348 | ||
| 349 | struct auth_domain *auth_unix_lookup(struct in_addr addr) | 349 | struct auth_domain *auth_unix_lookup(struct in_addr addr) |
| 350 | { | 350 | { |
| 351 | struct ip_map key, *ipm; | 351 | struct ip_map *ipm; |
| 352 | struct auth_domain *rv; | 352 | struct auth_domain *rv; |
| 353 | 353 | ||
| 354 | strcpy(key.m_class, "nfsd"); | ||
| 355 | key.m_addr = addr; | ||
| 356 | |||
| 357 | ipm = ip_map_lookup("nfsd", addr); | 354 | ipm = ip_map_lookup("nfsd", addr); |
| 358 | 355 | ||
| 359 | if (!ipm) | 356 | if (!ipm) |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 5b0fe1b66a23..cba85d195222 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
| 33 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
| 34 | #include <linux/file.h> | ||
| 34 | #include <net/sock.h> | 35 | #include <net/sock.h> |
| 35 | #include <net/checksum.h> | 36 | #include <net/checksum.h> |
| 36 | #include <net/ip.h> | 37 | #include <net/ip.h> |
| @@ -45,13 +46,16 @@ | |||
| 45 | 46 | ||
| 46 | /* SMP locking strategy: | 47 | /* SMP locking strategy: |
| 47 | * | 48 | * |
| 48 | * svc_serv->sv_lock protects most stuff for that service. | 49 | * svc_pool->sp_lock protects most of the fields of that pool. |
| 50 | * svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt. | ||
| 51 | * when both need to be taken (rare), svc_serv->sv_lock is first. | ||
| 52 | * BKL protects svc_serv->sv_nrthread. | ||
| 53 | * svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list | ||
| 54 | * svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply. | ||
| 49 | * | 55 | * |
| 50 | * Some flags can be set to certain values at any time | 56 | * Some flags can be set to certain values at any time |
| 51 | * providing that certain rules are followed: | 57 | * providing that certain rules are followed: |
| 52 | * | 58 | * |
| 53 | * SK_BUSY can be set to 0 at any time. | ||
| 54 | * svc_sock_enqueue must be called afterwards | ||
| 55 | * SK_CONN, SK_DATA, can be set or cleared at any time. | 59 | * SK_CONN, SK_DATA, can be set or cleared at any time. |
| 56 | * after a set, svc_sock_enqueue must be called. | 60 | * after a set, svc_sock_enqueue must be called. |
| 57 | * after a clear, the socket must be read/accepted | 61 | * after a clear, the socket must be read/accepted |
| @@ -73,23 +77,30 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk); | |||
| 73 | static int svc_deferred_recv(struct svc_rqst *rqstp); | 77 | static int svc_deferred_recv(struct svc_rqst *rqstp); |
| 74 | static struct cache_deferred_req *svc_defer(struct cache_req *req); | 78 | static struct cache_deferred_req *svc_defer(struct cache_req *req); |
| 75 | 79 | ||
| 80 | /* apparently the "standard" is that clients close | ||
| 81 | * idle connections after 5 minutes, servers after | ||
| 82 | * 6 minutes | ||
| 83 | * http://www.connectathon.org/talks96/nfstcp.pdf | ||
| 84 | */ | ||
| 85 | static int svc_conn_age_period = 6*60; | ||
| 86 | |||
| 76 | /* | 87 | /* |
| 77 | * Queue up an idle server thread. Must have serv->sv_lock held. | 88 | * Queue up an idle server thread. Must have pool->sp_lock held. |
| 78 | * Note: this is really a stack rather than a queue, so that we only | 89 | * Note: this is really a stack rather than a queue, so that we only |
| 79 | * use as many different threads as we need, and the rest don't polute | 90 | * use as many different threads as we need, and the rest don't pollute |
| 80 | * the cache. | 91 | * the cache. |
| 81 | */ | 92 | */ |
| 82 | static inline void | 93 | static inline void |
| 83 | svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp) | 94 | svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp) |
| 84 | { | 95 | { |
| 85 | list_add(&rqstp->rq_list, &serv->sv_threads); | 96 | list_add(&rqstp->rq_list, &pool->sp_threads); |
| 86 | } | 97 | } |
| 87 | 98 | ||
| 88 | /* | 99 | /* |
| 89 | * Dequeue an nfsd thread. Must have serv->sv_lock held. | 100 | * Dequeue an nfsd thread. Must have pool->sp_lock held. |
| 90 | */ | 101 | */ |
| 91 | static inline void | 102 | static inline void |
| 92 | svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp) | 103 | svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp) |
| 93 | { | 104 | { |
| 94 | list_del(&rqstp->rq_list); | 105 | list_del(&rqstp->rq_list); |
| 95 | } | 106 | } |
| @@ -140,7 +151,9 @@ static void | |||
| 140 | svc_sock_enqueue(struct svc_sock *svsk) | 151 | svc_sock_enqueue(struct svc_sock *svsk) |
| 141 | { | 152 | { |
| 142 | struct svc_serv *serv = svsk->sk_server; | 153 | struct svc_serv *serv = svsk->sk_server; |
| 154 | struct svc_pool *pool; | ||
| 143 | struct svc_rqst *rqstp; | 155 | struct svc_rqst *rqstp; |
| 156 | int cpu; | ||
| 144 | 157 | ||
| 145 | if (!(svsk->sk_flags & | 158 | if (!(svsk->sk_flags & |
| 146 | ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) )) | 159 | ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) )) |
| @@ -148,10 +161,14 @@ svc_sock_enqueue(struct svc_sock *svsk) | |||
| 148 | if (test_bit(SK_DEAD, &svsk->sk_flags)) | 161 | if (test_bit(SK_DEAD, &svsk->sk_flags)) |
| 149 | return; | 162 | return; |
| 150 | 163 | ||
| 151 | spin_lock_bh(&serv->sv_lock); | 164 | cpu = get_cpu(); |
| 165 | pool = svc_pool_for_cpu(svsk->sk_server, cpu); | ||
| 166 | put_cpu(); | ||
| 152 | 167 | ||
| 153 | if (!list_empty(&serv->sv_threads) && | 168 | spin_lock_bh(&pool->sp_lock); |
| 154 | !list_empty(&serv->sv_sockets)) | 169 | |
| 170 | if (!list_empty(&pool->sp_threads) && | ||
| 171 | !list_empty(&pool->sp_sockets)) | ||
| 155 | printk(KERN_ERR | 172 | printk(KERN_ERR |
| 156 | "svc_sock_enqueue: threads and sockets both waiting??\n"); | 173 | "svc_sock_enqueue: threads and sockets both waiting??\n"); |
| 157 | 174 | ||
| @@ -161,73 +178,79 @@ svc_sock_enqueue(struct svc_sock *svsk) | |||
| 161 | goto out_unlock; | 178 | goto out_unlock; |
| 162 | } | 179 | } |
| 163 | 180 | ||
| 164 | if (test_bit(SK_BUSY, &svsk->sk_flags)) { | 181 | /* Mark socket as busy. It will remain in this state until the |
| 165 | /* Don't enqueue socket while daemon is receiving */ | 182 | * server has processed all pending data and put the socket back |
| 183 | * on the idle list. We update SK_BUSY atomically because | ||
| 184 | * it also guards against trying to enqueue the svc_sock twice. | ||
| 185 | */ | ||
| 186 | if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) { | ||
| 187 | /* Don't enqueue socket while already enqueued */ | ||
| 166 | dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk); | 188 | dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk); |
| 167 | goto out_unlock; | 189 | goto out_unlock; |
| 168 | } | 190 | } |
| 191 | BUG_ON(svsk->sk_pool != NULL); | ||
| 192 | svsk->sk_pool = pool; | ||
| 169 | 193 | ||
| 170 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | 194 | set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); |
| 171 | if (((svsk->sk_reserved + serv->sv_bufsz)*2 | 195 | if (((atomic_read(&svsk->sk_reserved) + serv->sv_bufsz)*2 |
| 172 | > svc_sock_wspace(svsk)) | 196 | > svc_sock_wspace(svsk)) |
| 173 | && !test_bit(SK_CLOSE, &svsk->sk_flags) | 197 | && !test_bit(SK_CLOSE, &svsk->sk_flags) |
| 174 | && !test_bit(SK_CONN, &svsk->sk_flags)) { | 198 | && !test_bit(SK_CONN, &svsk->sk_flags)) { |
| 175 | /* Don't enqueue while not enough space for reply */ | 199 | /* Don't enqueue while not enough space for reply */ |
| 176 | dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n", | 200 | dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n", |
| 177 | svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz, | 201 | svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_bufsz, |
| 178 | svc_sock_wspace(svsk)); | 202 | svc_sock_wspace(svsk)); |
| 203 | svsk->sk_pool = NULL; | ||
| 204 | clear_bit(SK_BUSY, &svsk->sk_flags); | ||
| 179 | goto out_unlock; | 205 | goto out_unlock; |
| 180 | } | 206 | } |
| 181 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); | 207 | clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags); |
| 182 | 208 | ||
| 183 | /* Mark socket as busy. It will remain in this state until the | ||
| 184 | * server has processed all pending data and put the socket back | ||
| 185 | * on the idle list. | ||
| 186 | */ | ||
| 187 | set_bit(SK_BUSY, &svsk->sk_flags); | ||
| 188 | 209 | ||
| 189 | if (!list_empty(&serv->sv_threads)) { | 210 | if (!list_empty(&pool->sp_threads)) { |
| 190 | rqstp = list_entry(serv->sv_threads.next, | 211 | rqstp = list_entry(pool->sp_threads.next, |
| 191 | struct svc_rqst, | 212 | struct svc_rqst, |
| 192 | rq_list); | 213 | rq_list); |
| 193 | dprintk("svc: socket %p served by daemon %p\n", | 214 | dprintk("svc: socket %p served by daemon %p\n", |
| 194 | svsk->sk_sk, rqstp); | 215 | svsk->sk_sk, rqstp); |
| 195 | svc_serv_dequeue(serv, rqstp); | 216 | svc_thread_dequeue(pool, rqstp); |
| 196 | if (rqstp->rq_sock) | 217 | if (rqstp->rq_sock) |
| 197 | printk(KERN_ERR | 218 | printk(KERN_ERR |
| 198 | "svc_sock_enqueue: server %p, rq_sock=%p!\n", | 219 | "svc_sock_enqueue: server %p, rq_sock=%p!\n", |
| 199 | rqstp, rqstp->rq_sock); | 220 | rqstp, rqstp->rq_sock); |
| 200 | rqstp->rq_sock = svsk; | 221 | rqstp->rq_sock = svsk; |
| 201 | svsk->sk_inuse++; | 222 | atomic_inc(&svsk->sk_inuse); |
| 202 | rqstp->rq_reserved = serv->sv_bufsz; | 223 | rqstp->rq_reserved = serv->sv_bufsz; |
| 203 | svsk->sk_reserved += rqstp->rq_reserved; | 224 | atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); |
| 225 | BUG_ON(svsk->sk_pool != pool); | ||
| 204 | wake_up(&rqstp->rq_wait); | 226 | wake_up(&rqstp->rq_wait); |
| 205 | } else { | 227 | } else { |
| 206 | dprintk("svc: socket %p put into queue\n", svsk->sk_sk); | 228 | dprintk("svc: socket %p put into queue\n", svsk->sk_sk); |
| 207 | list_add_tail(&svsk->sk_ready, &serv->sv_sockets); | 229 | list_add_tail(&svsk->sk_ready, &pool->sp_sockets); |
| 230 | BUG_ON(svsk->sk_pool != pool); | ||
| 208 | } | 231 | } |
| 209 | 232 | ||
| 210 | out_unlock: | 233 | out_unlock: |
| 211 | spin_unlock_bh(&serv->sv_lock); | 234 | spin_unlock_bh(&pool->sp_lock); |
| 212 | } | 235 | } |
| 213 | 236 | ||
| 214 | /* | 237 | /* |
| 215 | * Dequeue the first socket. Must be called with the serv->sv_lock held. | 238 | * Dequeue the first socket. Must be called with the pool->sp_lock held. |
| 216 | */ | 239 | */ |
| 217 | static inline struct svc_sock * | 240 | static inline struct svc_sock * |
| 218 | svc_sock_dequeue(struct svc_serv *serv) | 241 | svc_sock_dequeue(struct svc_pool *pool) |
| 219 | { | 242 | { |
| 220 | struct svc_sock *svsk; | 243 | struct svc_sock *svsk; |
| 221 | 244 | ||
| 222 | if (list_empty(&serv->sv_sockets)) | 245 | if (list_empty(&pool->sp_sockets)) |
| 223 | return NULL; | 246 | return NULL; |
| 224 | 247 | ||
| 225 | svsk = list_entry(serv->sv_sockets.next, | 248 | svsk = list_entry(pool->sp_sockets.next, |
| 226 | struct svc_sock, sk_ready); | 249 | struct svc_sock, sk_ready); |
| 227 | list_del_init(&svsk->sk_ready); | 250 | list_del_init(&svsk->sk_ready); |
| 228 | 251 | ||
| 229 | dprintk("svc: socket %p dequeued, inuse=%d\n", | 252 | dprintk("svc: socket %p dequeued, inuse=%d\n", |
| 230 | svsk->sk_sk, svsk->sk_inuse); | 253 | svsk->sk_sk, atomic_read(&svsk->sk_inuse)); |
| 231 | 254 | ||
| 232 | return svsk; | 255 | return svsk; |
| 233 | } | 256 | } |
| @@ -241,6 +264,7 @@ svc_sock_dequeue(struct svc_serv *serv) | |||
| 241 | static inline void | 264 | static inline void |
| 242 | svc_sock_received(struct svc_sock *svsk) | 265 | svc_sock_received(struct svc_sock *svsk) |
| 243 | { | 266 | { |
| 267 | svsk->sk_pool = NULL; | ||
| 244 | clear_bit(SK_BUSY, &svsk->sk_flags); | 268 | clear_bit(SK_BUSY, &svsk->sk_flags); |
| 245 | svc_sock_enqueue(svsk); | 269 | svc_sock_enqueue(svsk); |
| 246 | } | 270 | } |
| @@ -262,10 +286,8 @@ void svc_reserve(struct svc_rqst *rqstp, int space) | |||
| 262 | 286 | ||
| 263 | if (space < rqstp->rq_reserved) { | 287 | if (space < rqstp->rq_reserved) { |
| 264 | struct svc_sock *svsk = rqstp->rq_sock; | 288 | struct svc_sock *svsk = rqstp->rq_sock; |
| 265 | spin_lock_bh(&svsk->sk_server->sv_lock); | 289 | atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved); |
| 266 | svsk->sk_reserved -= (rqstp->rq_reserved - space); | ||
| 267 | rqstp->rq_reserved = space; | 290 | rqstp->rq_reserved = space; |
| 268 | spin_unlock_bh(&svsk->sk_server->sv_lock); | ||
| 269 | 291 | ||
| 270 | svc_sock_enqueue(svsk); | 292 | svc_sock_enqueue(svsk); |
| 271 | } | 293 | } |
| @@ -277,17 +299,11 @@ void svc_reserve(struct svc_rqst *rqstp, int space) | |||
| 277 | static inline void | 299 | static inline void |
| 278 | svc_sock_put(struct svc_sock *svsk) | 300 | svc_sock_put(struct svc_sock *svsk) |
| 279 | { | 301 | { |
| 280 | struct svc_serv *serv = svsk->sk_server; | 302 | if (atomic_dec_and_test(&svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) { |
| 281 | |||
| 282 | spin_lock_bh(&serv->sv_lock); | ||
| 283 | if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) { | ||
| 284 | spin_unlock_bh(&serv->sv_lock); | ||
| 285 | dprintk("svc: releasing dead socket\n"); | 303 | dprintk("svc: releasing dead socket\n"); |
| 286 | sock_release(svsk->sk_sock); | 304 | sock_release(svsk->sk_sock); |
| 287 | kfree(svsk); | 305 | kfree(svsk); |
| 288 | } | 306 | } |
| 289 | else | ||
| 290 | spin_unlock_bh(&serv->sv_lock); | ||
| 291 | } | 307 | } |
| 292 | 308 | ||
| 293 | static void | 309 | static void |
| @@ -321,25 +337,33 @@ svc_sock_release(struct svc_rqst *rqstp) | |||
| 321 | 337 | ||
| 322 | /* | 338 | /* |
| 323 | * External function to wake up a server waiting for data | 339 | * External function to wake up a server waiting for data |
| 340 | * This really only makes sense for services like lockd | ||
| 341 | * which have exactly one thread anyway. | ||
| 324 | */ | 342 | */ |
| 325 | void | 343 | void |
| 326 | svc_wake_up(struct svc_serv *serv) | 344 | svc_wake_up(struct svc_serv *serv) |
| 327 | { | 345 | { |
| 328 | struct svc_rqst *rqstp; | 346 | struct svc_rqst *rqstp; |
| 329 | 347 | unsigned int i; | |
| 330 | spin_lock_bh(&serv->sv_lock); | 348 | struct svc_pool *pool; |
| 331 | if (!list_empty(&serv->sv_threads)) { | 349 | |
| 332 | rqstp = list_entry(serv->sv_threads.next, | 350 | for (i = 0; i < serv->sv_nrpools; i++) { |
| 333 | struct svc_rqst, | 351 | pool = &serv->sv_pools[i]; |
| 334 | rq_list); | 352 | |
| 335 | dprintk("svc: daemon %p woken up.\n", rqstp); | 353 | spin_lock_bh(&pool->sp_lock); |
| 336 | /* | 354 | if (!list_empty(&pool->sp_threads)) { |
| 337 | svc_serv_dequeue(serv, rqstp); | 355 | rqstp = list_entry(pool->sp_threads.next, |
| 338 | rqstp->rq_sock = NULL; | 356 | struct svc_rqst, |
| 339 | */ | 357 | rq_list); |
| 340 | wake_up(&rqstp->rq_wait); | 358 | dprintk("svc: daemon %p woken up.\n", rqstp); |
| 359 | /* | ||
| 360 | svc_thread_dequeue(pool, rqstp); | ||
| 361 | rqstp->rq_sock = NULL; | ||
| 362 | */ | ||
| 363 | wake_up(&rqstp->rq_wait); | ||
| 364 | } | ||
| 365 | spin_unlock_bh(&pool->sp_lock); | ||
| 341 | } | 366 | } |
| 342 | spin_unlock_bh(&serv->sv_lock); | ||
| 343 | } | 367 | } |
| 344 | 368 | ||
| 345 | /* | 369 | /* |
| @@ -429,6 +453,51 @@ out: | |||
| 429 | } | 453 | } |
| 430 | 454 | ||
| 431 | /* | 455 | /* |
| 456 | * Report socket names for nfsdfs | ||
| 457 | */ | ||
| 458 | static int one_sock_name(char *buf, struct svc_sock *svsk) | ||
| 459 | { | ||
| 460 | int len; | ||
| 461 | |||
| 462 | switch(svsk->sk_sk->sk_family) { | ||
| 463 | case AF_INET: | ||
| 464 | len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n", | ||
| 465 | svsk->sk_sk->sk_protocol==IPPROTO_UDP? | ||
| 466 | "udp" : "tcp", | ||
| 467 | NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr), | ||
| 468 | inet_sk(svsk->sk_sk)->num); | ||
| 469 | break; | ||
| 470 | default: | ||
| 471 | len = sprintf(buf, "*unknown-%d*\n", | ||
| 472 | svsk->sk_sk->sk_family); | ||
| 473 | } | ||
| 474 | return len; | ||
| 475 | } | ||
| 476 | |||
| 477 | int | ||
| 478 | svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) | ||
| 479 | { | ||
| 480 | struct svc_sock *svsk, *closesk = NULL; | ||
| 481 | int len = 0; | ||
| 482 | |||
| 483 | if (!serv) | ||
| 484 | return 0; | ||
| 485 | spin_lock(&serv->sv_lock); | ||
| 486 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { | ||
| 487 | int onelen = one_sock_name(buf+len, svsk); | ||
| 488 | if (toclose && strcmp(toclose, buf+len) == 0) | ||
| 489 | closesk = svsk; | ||
| 490 | else | ||
| 491 | len += onelen; | ||
| 492 | } | ||
| 493 | spin_unlock(&serv->sv_lock); | ||
| 494 | if (closesk) | ||
| 495 | svc_delete_socket(closesk); | ||
| 496 | return len; | ||
| 497 | } | ||
| 498 | EXPORT_SYMBOL(svc_sock_names); | ||
| 499 | |||
| 500 | /* | ||
| 432 | * Check input queue length | 501 | * Check input queue length |
| 433 | */ | 502 | */ |
| 434 | static int | 503 | static int |
| @@ -557,7 +626,10 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
| 557 | /* udp sockets need large rcvbuf as all pending | 626 | /* udp sockets need large rcvbuf as all pending |
| 558 | * requests are still in that buffer. sndbuf must | 627 | * requests are still in that buffer. sndbuf must |
| 559 | * also be large enough that there is enough space | 628 | * also be large enough that there is enough space |
| 560 | * for one reply per thread. | 629 | * for one reply per thread. We count all threads |
| 630 | * rather than threads in a particular pool, which | ||
| 631 | * provides an upper bound on the number of threads | ||
| 632 | * which will access the socket. | ||
| 561 | */ | 633 | */ |
| 562 | svc_sock_setbufsize(svsk->sk_sock, | 634 | svc_sock_setbufsize(svsk->sk_sock, |
| 563 | (serv->sv_nrthreads+3) * serv->sv_bufsz, | 635 | (serv->sv_nrthreads+3) * serv->sv_bufsz, |
| @@ -844,7 +916,7 @@ svc_tcp_accept(struct svc_sock *svsk) | |||
| 844 | struct svc_sock, | 916 | struct svc_sock, |
| 845 | sk_list); | 917 | sk_list); |
| 846 | set_bit(SK_CLOSE, &svsk->sk_flags); | 918 | set_bit(SK_CLOSE, &svsk->sk_flags); |
| 847 | svsk->sk_inuse ++; | 919 | atomic_inc(&svsk->sk_inuse); |
| 848 | } | 920 | } |
| 849 | spin_unlock_bh(&serv->sv_lock); | 921 | spin_unlock_bh(&serv->sv_lock); |
| 850 | 922 | ||
| @@ -902,6 +974,11 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
| 902 | /* sndbuf needs to have room for one request | 974 | /* sndbuf needs to have room for one request |
| 903 | * per thread, otherwise we can stall even when the | 975 | * per thread, otherwise we can stall even when the |
| 904 | * network isn't a bottleneck. | 976 | * network isn't a bottleneck. |
| 977 | * | ||
| 978 | * We count all threads rather than threads in a | ||
| 979 | * particular pool, which provides an upper bound | ||
| 980 | * on the number of threads which will access the socket. | ||
| 981 | * | ||
| 905 | * rcvbuf just needs to be able to hold a few requests. | 982 | * rcvbuf just needs to be able to hold a few requests. |
| 906 | * Normally they will be removed from the queue | 983 | * Normally they will be removed from the queue |
| 907 | * as soon a a complete request arrives. | 984 | * as soon a a complete request arrives. |
| @@ -1117,12 +1194,16 @@ svc_sock_update_bufs(struct svc_serv *serv) | |||
| 1117 | } | 1194 | } |
| 1118 | 1195 | ||
| 1119 | /* | 1196 | /* |
| 1120 | * Receive the next request on any socket. | 1197 | * Receive the next request on any socket. This code is carefully |
| 1198 | * organised not to touch any cachelines in the shared svc_serv | ||
| 1199 | * structure, only cachelines in the local svc_pool. | ||
| 1121 | */ | 1200 | */ |
| 1122 | int | 1201 | int |
| 1123 | svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) | 1202 | svc_recv(struct svc_rqst *rqstp, long timeout) |
| 1124 | { | 1203 | { |
| 1125 | struct svc_sock *svsk =NULL; | 1204 | struct svc_sock *svsk =NULL; |
| 1205 | struct svc_serv *serv = rqstp->rq_server; | ||
| 1206 | struct svc_pool *pool = rqstp->rq_pool; | ||
| 1126 | int len; | 1207 | int len; |
| 1127 | int pages; | 1208 | int pages; |
| 1128 | struct xdr_buf *arg; | 1209 | struct xdr_buf *arg; |
| @@ -1172,32 +1253,15 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) | |||
| 1172 | if (signalled()) | 1253 | if (signalled()) |
| 1173 | return -EINTR; | 1254 | return -EINTR; |
| 1174 | 1255 | ||
| 1175 | spin_lock_bh(&serv->sv_lock); | 1256 | spin_lock_bh(&pool->sp_lock); |
| 1176 | if (!list_empty(&serv->sv_tempsocks)) { | 1257 | if ((svsk = svc_sock_dequeue(pool)) != NULL) { |
| 1177 | svsk = list_entry(serv->sv_tempsocks.next, | ||
| 1178 | struct svc_sock, sk_list); | ||
| 1179 | /* apparently the "standard" is that clients close | ||
| 1180 | * idle connections after 5 minutes, servers after | ||
| 1181 | * 6 minutes | ||
| 1182 | * http://www.connectathon.org/talks96/nfstcp.pdf | ||
| 1183 | */ | ||
| 1184 | if (get_seconds() - svsk->sk_lastrecv < 6*60 | ||
| 1185 | || test_bit(SK_BUSY, &svsk->sk_flags)) | ||
| 1186 | svsk = NULL; | ||
| 1187 | } | ||
| 1188 | if (svsk) { | ||
| 1189 | set_bit(SK_BUSY, &svsk->sk_flags); | ||
| 1190 | set_bit(SK_CLOSE, &svsk->sk_flags); | ||
| 1191 | rqstp->rq_sock = svsk; | ||
| 1192 | svsk->sk_inuse++; | ||
| 1193 | } else if ((svsk = svc_sock_dequeue(serv)) != NULL) { | ||
| 1194 | rqstp->rq_sock = svsk; | 1258 | rqstp->rq_sock = svsk; |
| 1195 | svsk->sk_inuse++; | 1259 | atomic_inc(&svsk->sk_inuse); |
| 1196 | rqstp->rq_reserved = serv->sv_bufsz; | 1260 | rqstp->rq_reserved = serv->sv_bufsz; |
| 1197 | svsk->sk_reserved += rqstp->rq_reserved; | 1261 | atomic_add(rqstp->rq_reserved, &svsk->sk_reserved); |
| 1198 | } else { | 1262 | } else { |
| 1199 | /* No data pending. Go to sleep */ | 1263 | /* No data pending. Go to sleep */ |
| 1200 | svc_serv_enqueue(serv, rqstp); | 1264 | svc_thread_enqueue(pool, rqstp); |
| 1201 | 1265 | ||
| 1202 | /* | 1266 | /* |
| 1203 | * We have to be able to interrupt this wait | 1267 | * We have to be able to interrupt this wait |
| @@ -1205,26 +1269,26 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) | |||
| 1205 | */ | 1269 | */ |
| 1206 | set_current_state(TASK_INTERRUPTIBLE); | 1270 | set_current_state(TASK_INTERRUPTIBLE); |
| 1207 | add_wait_queue(&rqstp->rq_wait, &wait); | 1271 | add_wait_queue(&rqstp->rq_wait, &wait); |
| 1208 | spin_unlock_bh(&serv->sv_lock); | 1272 | spin_unlock_bh(&pool->sp_lock); |
| 1209 | 1273 | ||
| 1210 | schedule_timeout(timeout); | 1274 | schedule_timeout(timeout); |
| 1211 | 1275 | ||
| 1212 | try_to_freeze(); | 1276 | try_to_freeze(); |
| 1213 | 1277 | ||
| 1214 | spin_lock_bh(&serv->sv_lock); | 1278 | spin_lock_bh(&pool->sp_lock); |
| 1215 | remove_wait_queue(&rqstp->rq_wait, &wait); | 1279 | remove_wait_queue(&rqstp->rq_wait, &wait); |
| 1216 | 1280 | ||
| 1217 | if (!(svsk = rqstp->rq_sock)) { | 1281 | if (!(svsk = rqstp->rq_sock)) { |
| 1218 | svc_serv_dequeue(serv, rqstp); | 1282 | svc_thread_dequeue(pool, rqstp); |
| 1219 | spin_unlock_bh(&serv->sv_lock); | 1283 | spin_unlock_bh(&pool->sp_lock); |
| 1220 | dprintk("svc: server %p, no data yet\n", rqstp); | 1284 | dprintk("svc: server %p, no data yet\n", rqstp); |
| 1221 | return signalled()? -EINTR : -EAGAIN; | 1285 | return signalled()? -EINTR : -EAGAIN; |
| 1222 | } | 1286 | } |
| 1223 | } | 1287 | } |
| 1224 | spin_unlock_bh(&serv->sv_lock); | 1288 | spin_unlock_bh(&pool->sp_lock); |
| 1225 | 1289 | ||
| 1226 | dprintk("svc: server %p, socket %p, inuse=%d\n", | 1290 | dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n", |
| 1227 | rqstp, svsk, svsk->sk_inuse); | 1291 | rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse)); |
| 1228 | len = svsk->sk_recvfrom(rqstp); | 1292 | len = svsk->sk_recvfrom(rqstp); |
| 1229 | dprintk("svc: got len=%d\n", len); | 1293 | dprintk("svc: got len=%d\n", len); |
| 1230 | 1294 | ||
| @@ -1235,13 +1299,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) | |||
| 1235 | return -EAGAIN; | 1299 | return -EAGAIN; |
| 1236 | } | 1300 | } |
| 1237 | svsk->sk_lastrecv = get_seconds(); | 1301 | svsk->sk_lastrecv = get_seconds(); |
| 1238 | if (test_bit(SK_TEMP, &svsk->sk_flags)) { | 1302 | clear_bit(SK_OLD, &svsk->sk_flags); |
| 1239 | /* push active sockets to end of list */ | ||
| 1240 | spin_lock_bh(&serv->sv_lock); | ||
| 1241 | if (!list_empty(&svsk->sk_list)) | ||
| 1242 | list_move_tail(&svsk->sk_list, &serv->sv_tempsocks); | ||
| 1243 | spin_unlock_bh(&serv->sv_lock); | ||
| 1244 | } | ||
| 1245 | 1303 | ||
| 1246 | rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; | 1304 | rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; |
| 1247 | rqstp->rq_chandle.defer = svc_defer; | 1305 | rqstp->rq_chandle.defer = svc_defer; |
| @@ -1301,6 +1359,58 @@ svc_send(struct svc_rqst *rqstp) | |||
| 1301 | } | 1359 | } |
| 1302 | 1360 | ||
| 1303 | /* | 1361 | /* |
| 1362 | * Timer function to close old temporary sockets, using | ||
| 1363 | * a mark-and-sweep algorithm. | ||
| 1364 | */ | ||
| 1365 | static void | ||
| 1366 | svc_age_temp_sockets(unsigned long closure) | ||
| 1367 | { | ||
| 1368 | struct svc_serv *serv = (struct svc_serv *)closure; | ||
| 1369 | struct svc_sock *svsk; | ||
| 1370 | struct list_head *le, *next; | ||
| 1371 | LIST_HEAD(to_be_aged); | ||
| 1372 | |||
| 1373 | dprintk("svc_age_temp_sockets\n"); | ||
| 1374 | |||
| 1375 | if (!spin_trylock_bh(&serv->sv_lock)) { | ||
| 1376 | /* busy, try again 1 sec later */ | ||
| 1377 | dprintk("svc_age_temp_sockets: busy\n"); | ||
| 1378 | mod_timer(&serv->sv_temptimer, jiffies + HZ); | ||
| 1379 | return; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | list_for_each_safe(le, next, &serv->sv_tempsocks) { | ||
| 1383 | svsk = list_entry(le, struct svc_sock, sk_list); | ||
| 1384 | |||
| 1385 | if (!test_and_set_bit(SK_OLD, &svsk->sk_flags)) | ||
| 1386 | continue; | ||
| 1387 | if (atomic_read(&svsk->sk_inuse) || test_bit(SK_BUSY, &svsk->sk_flags)) | ||
| 1388 | continue; | ||
| 1389 | atomic_inc(&svsk->sk_inuse); | ||
| 1390 | list_move(le, &to_be_aged); | ||
| 1391 | set_bit(SK_CLOSE, &svsk->sk_flags); | ||
| 1392 | set_bit(SK_DETACHED, &svsk->sk_flags); | ||
| 1393 | } | ||
| 1394 | spin_unlock_bh(&serv->sv_lock); | ||
| 1395 | |||
| 1396 | while (!list_empty(&to_be_aged)) { | ||
| 1397 | le = to_be_aged.next; | ||
| 1398 | /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */ | ||
| 1399 | list_del_init(le); | ||
| 1400 | svsk = list_entry(le, struct svc_sock, sk_list); | ||
| 1401 | |||
| 1402 | dprintk("queuing svsk %p for closing, %lu seconds old\n", | ||
| 1403 | svsk, get_seconds() - svsk->sk_lastrecv); | ||
| 1404 | |||
| 1405 | /* a thread will dequeue and close it soon */ | ||
| 1406 | svc_sock_enqueue(svsk); | ||
| 1407 | svc_sock_put(svsk); | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); | ||
| 1411 | } | ||
| 1412 | |||
| 1413 | /* | ||
| 1304 | * Initialize socket for RPC use and create svc_sock struct | 1414 | * Initialize socket for RPC use and create svc_sock struct |
| 1305 | * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF. | 1415 | * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF. |
| 1306 | */ | 1416 | */ |
| @@ -1337,7 +1447,9 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, | |||
| 1337 | svsk->sk_odata = inet->sk_data_ready; | 1447 | svsk->sk_odata = inet->sk_data_ready; |
| 1338 | svsk->sk_owspace = inet->sk_write_space; | 1448 | svsk->sk_owspace = inet->sk_write_space; |
| 1339 | svsk->sk_server = serv; | 1449 | svsk->sk_server = serv; |
| 1450 | atomic_set(&svsk->sk_inuse, 0); | ||
| 1340 | svsk->sk_lastrecv = get_seconds(); | 1451 | svsk->sk_lastrecv = get_seconds(); |
| 1452 | spin_lock_init(&svsk->sk_defer_lock); | ||
| 1341 | INIT_LIST_HEAD(&svsk->sk_deferred); | 1453 | INIT_LIST_HEAD(&svsk->sk_deferred); |
| 1342 | INIT_LIST_HEAD(&svsk->sk_ready); | 1454 | INIT_LIST_HEAD(&svsk->sk_ready); |
| 1343 | mutex_init(&svsk->sk_mutex); | 1455 | mutex_init(&svsk->sk_mutex); |
| @@ -1353,6 +1465,13 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, | |||
| 1353 | set_bit(SK_TEMP, &svsk->sk_flags); | 1465 | set_bit(SK_TEMP, &svsk->sk_flags); |
| 1354 | list_add(&svsk->sk_list, &serv->sv_tempsocks); | 1466 | list_add(&svsk->sk_list, &serv->sv_tempsocks); |
| 1355 | serv->sv_tmpcnt++; | 1467 | serv->sv_tmpcnt++; |
| 1468 | if (serv->sv_temptimer.function == NULL) { | ||
| 1469 | /* setup timer to age temp sockets */ | ||
| 1470 | setup_timer(&serv->sv_temptimer, svc_age_temp_sockets, | ||
| 1471 | (unsigned long)serv); | ||
| 1472 | mod_timer(&serv->sv_temptimer, | ||
| 1473 | jiffies + svc_conn_age_period * HZ); | ||
| 1474 | } | ||
| 1356 | } else { | 1475 | } else { |
| 1357 | clear_bit(SK_TEMP, &svsk->sk_flags); | 1476 | clear_bit(SK_TEMP, &svsk->sk_flags); |
| 1358 | list_add(&svsk->sk_list, &serv->sv_permsocks); | 1477 | list_add(&svsk->sk_list, &serv->sv_permsocks); |
| @@ -1367,6 +1486,38 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, | |||
| 1367 | return svsk; | 1486 | return svsk; |
| 1368 | } | 1487 | } |
| 1369 | 1488 | ||
| 1489 | int svc_addsock(struct svc_serv *serv, | ||
| 1490 | int fd, | ||
| 1491 | char *name_return, | ||
| 1492 | int *proto) | ||
| 1493 | { | ||
| 1494 | int err = 0; | ||
| 1495 | struct socket *so = sockfd_lookup(fd, &err); | ||
| 1496 | struct svc_sock *svsk = NULL; | ||
| 1497 | |||
| 1498 | if (!so) | ||
| 1499 | return err; | ||
| 1500 | if (so->sk->sk_family != AF_INET) | ||
| 1501 | err = -EAFNOSUPPORT; | ||
| 1502 | else if (so->sk->sk_protocol != IPPROTO_TCP && | ||
| 1503 | so->sk->sk_protocol != IPPROTO_UDP) | ||
| 1504 | err = -EPROTONOSUPPORT; | ||
| 1505 | else if (so->state > SS_UNCONNECTED) | ||
| 1506 | err = -EISCONN; | ||
| 1507 | else { | ||
| 1508 | svsk = svc_setup_socket(serv, so, &err, 1); | ||
| 1509 | if (svsk) | ||
| 1510 | err = 0; | ||
| 1511 | } | ||
| 1512 | if (err) { | ||
| 1513 | sockfd_put(so); | ||
| 1514 | return err; | ||
| 1515 | } | ||
| 1516 | if (proto) *proto = so->sk->sk_protocol; | ||
| 1517 | return one_sock_name(name_return, svsk); | ||
| 1518 | } | ||
| 1519 | EXPORT_SYMBOL_GPL(svc_addsock); | ||
| 1520 | |||
| 1370 | /* | 1521 | /* |
| 1371 | * Create socket for RPC service. | 1522 | * Create socket for RPC service. |
| 1372 | */ | 1523 | */ |
| @@ -1434,15 +1585,25 @@ svc_delete_socket(struct svc_sock *svsk) | |||
| 1434 | 1585 | ||
| 1435 | spin_lock_bh(&serv->sv_lock); | 1586 | spin_lock_bh(&serv->sv_lock); |
| 1436 | 1587 | ||
| 1437 | list_del_init(&svsk->sk_list); | 1588 | if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags)) |
| 1438 | list_del_init(&svsk->sk_ready); | 1589 | list_del_init(&svsk->sk_list); |
| 1590 | /* | ||
| 1591 | * We used to delete the svc_sock from whichever list | ||
| 1592 | * it's sk_ready node was on, but we don't actually | ||
| 1593 | * need to. This is because the only time we're called | ||
| 1594 | * while still attached to a queue, the queue itself | ||
| 1595 | * is about to be destroyed (in svc_destroy). | ||
| 1596 | */ | ||
| 1439 | if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) | 1597 | if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) |
| 1440 | if (test_bit(SK_TEMP, &svsk->sk_flags)) | 1598 | if (test_bit(SK_TEMP, &svsk->sk_flags)) |
| 1441 | serv->sv_tmpcnt--; | 1599 | serv->sv_tmpcnt--; |
| 1442 | 1600 | ||
| 1443 | if (!svsk->sk_inuse) { | 1601 | if (!atomic_read(&svsk->sk_inuse)) { |
| 1444 | spin_unlock_bh(&serv->sv_lock); | 1602 | spin_unlock_bh(&serv->sv_lock); |
| 1445 | sock_release(svsk->sk_sock); | 1603 | if (svsk->sk_sock->file) |
| 1604 | sockfd_put(svsk->sk_sock); | ||
| 1605 | else | ||
| 1606 | sock_release(svsk->sk_sock); | ||
| 1446 | kfree(svsk); | 1607 | kfree(svsk); |
| 1447 | } else { | 1608 | } else { |
| 1448 | spin_unlock_bh(&serv->sv_lock); | 1609 | spin_unlock_bh(&serv->sv_lock); |
| @@ -1473,7 +1634,6 @@ svc_makesock(struct svc_serv *serv, int protocol, unsigned short port) | |||
| 1473 | static void svc_revisit(struct cache_deferred_req *dreq, int too_many) | 1634 | static void svc_revisit(struct cache_deferred_req *dreq, int too_many) |
| 1474 | { | 1635 | { |
| 1475 | struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle); | 1636 | struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle); |
| 1476 | struct svc_serv *serv = dreq->owner; | ||
| 1477 | struct svc_sock *svsk; | 1637 | struct svc_sock *svsk; |
| 1478 | 1638 | ||
| 1479 | if (too_many) { | 1639 | if (too_many) { |
| @@ -1484,9 +1644,9 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many) | |||
| 1484 | dprintk("revisit queued\n"); | 1644 | dprintk("revisit queued\n"); |
| 1485 | svsk = dr->svsk; | 1645 | svsk = dr->svsk; |
| 1486 | dr->svsk = NULL; | 1646 | dr->svsk = NULL; |
| 1487 | spin_lock_bh(&serv->sv_lock); | 1647 | spin_lock_bh(&svsk->sk_defer_lock); |
| 1488 | list_add(&dr->handle.recent, &svsk->sk_deferred); | 1648 | list_add(&dr->handle.recent, &svsk->sk_deferred); |
| 1489 | spin_unlock_bh(&serv->sv_lock); | 1649 | spin_unlock_bh(&svsk->sk_defer_lock); |
| 1490 | set_bit(SK_DEFERRED, &svsk->sk_flags); | 1650 | set_bit(SK_DEFERRED, &svsk->sk_flags); |
| 1491 | svc_sock_enqueue(svsk); | 1651 | svc_sock_enqueue(svsk); |
| 1492 | svc_sock_put(svsk); | 1652 | svc_sock_put(svsk); |
| @@ -1518,10 +1678,8 @@ svc_defer(struct cache_req *req) | |||
| 1518 | dr->argslen = rqstp->rq_arg.len >> 2; | 1678 | dr->argslen = rqstp->rq_arg.len >> 2; |
| 1519 | memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2); | 1679 | memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2); |
| 1520 | } | 1680 | } |
| 1521 | spin_lock_bh(&rqstp->rq_server->sv_lock); | 1681 | atomic_inc(&rqstp->rq_sock->sk_inuse); |
| 1522 | rqstp->rq_sock->sk_inuse++; | ||
| 1523 | dr->svsk = rqstp->rq_sock; | 1682 | dr->svsk = rqstp->rq_sock; |
| 1524 | spin_unlock_bh(&rqstp->rq_server->sv_lock); | ||
| 1525 | 1683 | ||
| 1526 | dr->handle.revisit = svc_revisit; | 1684 | dr->handle.revisit = svc_revisit; |
| 1527 | return &dr->handle; | 1685 | return &dr->handle; |
| @@ -1548,11 +1706,10 @@ static int svc_deferred_recv(struct svc_rqst *rqstp) | |||
| 1548 | static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk) | 1706 | static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk) |
| 1549 | { | 1707 | { |
| 1550 | struct svc_deferred_req *dr = NULL; | 1708 | struct svc_deferred_req *dr = NULL; |
| 1551 | struct svc_serv *serv = svsk->sk_server; | ||
| 1552 | 1709 | ||
| 1553 | if (!test_bit(SK_DEFERRED, &svsk->sk_flags)) | 1710 | if (!test_bit(SK_DEFERRED, &svsk->sk_flags)) |
| 1554 | return NULL; | 1711 | return NULL; |
| 1555 | spin_lock_bh(&serv->sv_lock); | 1712 | spin_lock_bh(&svsk->sk_defer_lock); |
| 1556 | clear_bit(SK_DEFERRED, &svsk->sk_flags); | 1713 | clear_bit(SK_DEFERRED, &svsk->sk_flags); |
| 1557 | if (!list_empty(&svsk->sk_deferred)) { | 1714 | if (!list_empty(&svsk->sk_deferred)) { |
| 1558 | dr = list_entry(svsk->sk_deferred.next, | 1715 | dr = list_entry(svsk->sk_deferred.next, |
| @@ -1561,6 +1718,6 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk) | |||
| 1561 | list_del_init(&dr->handle.recent); | 1718 | list_del_init(&dr->handle.recent); |
| 1562 | set_bit(SK_DEFERRED, &svsk->sk_flags); | 1719 | set_bit(SK_DEFERRED, &svsk->sk_flags); |
| 1563 | } | 1720 | } |
| 1564 | spin_unlock_bh(&serv->sv_lock); | 1721 | spin_unlock_bh(&svsk->sk_defer_lock); |
| 1565 | return dr; | 1722 | return dr; |
| 1566 | } | 1723 | } |
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 3ebc34919c76..a444bfe2cf74 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c | |||
| @@ -96,11 +96,11 @@ static void snd_sndstat_proc_read(struct snd_info_entry *entry, | |||
| 96 | { | 96 | { |
| 97 | snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n"); | 97 | snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n"); |
| 98 | snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n", | 98 | snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n", |
| 99 | system_utsname.sysname, | 99 | init_utsname()->sysname, |
| 100 | system_utsname.nodename, | 100 | init_utsname()->nodename, |
| 101 | system_utsname.release, | 101 | init_utsname()->release, |
| 102 | system_utsname.version, | 102 | init_utsname()->version, |
| 103 | system_utsname.machine); | 103 | init_utsname()->machine); |
| 104 | snd_iprintf(buffer, "Config options: 0\n"); | 104 | snd_iprintf(buffer, "Config options: 0\n"); |
| 105 | snd_iprintf(buffer, "\nInstalled drivers: \n"); | 105 | snd_iprintf(buffer, "\nInstalled drivers: \n"); |
| 106 | snd_iprintf(buffer, "Type 10: ALSA emulation\n"); | 106 | snd_iprintf(buffer, "Type 10: ALSA emulation\n"); |
