From e9c8862f19958846dd0c7b39d0f6216aad6c7bee Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 00:20:47 -0400 Subject: Input: remove accept method from input_dev This method used to enforce exclusive access to iforce devices, but presenlty there are no known users of this method. Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/input.h b/include/linux/input.h index 56f1e0e1e598..6e3afad26fa9 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -893,7 +893,6 @@ struct input_dev { int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); - int (*accept)(struct input_dev *dev, struct file *file); int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); @@ -1030,7 +1029,6 @@ void input_release_device(struct input_handle *); int input_open_device(struct input_handle *); void input_close_device(struct input_handle *); -int input_accept_process(struct input_handle *handle, struct file *file); int input_flush_device(struct input_handle* handle, struct file* file); void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); -- cgit v1.2.3 From c7e8dc6ee6d59bf72f5478fa6355a27750e6c7d2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 00:21:03 -0400 Subject: Input: add start() method to input handlers The new start() method is called immediately after connect() and also when "grabbed" device is released by its owner. This will allow input handlers to re-synchronize state of once-grabbed device with the rest of devices. Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 39 ++++++++++++++++++++------------------- drivers/input/input.c | 12 ++++++++++-- include/linux/input.h | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 056ebe84b81d..38de44b87506 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -988,7 +988,7 @@ static inline unsigned char getleds(void) * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. * This allows for easy and efficient race-condition prevention - * for kbd_refresh_leds => input_event(dev, EV_LED, ...) => ... + * for kbd_start => input_event(dev, EV_LED, ...) => ... */ static void kbd_bh(unsigned long dummy) @@ -1011,23 +1011,6 @@ static void kbd_bh(unsigned long dummy) DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); -/* - * This allows a newly plugged keyboard to pick the LED state. - */ -static void kbd_refresh_leds(struct input_handle *handle) -{ - unsigned char leds = ledstate; - - tasklet_disable(&keyboard_tasklet); - if (leds != 0xff) { - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); - } - tasklet_enable(&keyboard_tasklet); -} - #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ @@ -1307,7 +1290,6 @@ static struct input_handle *kbd_connect(struct input_handler *handler, handle->name = "kbd"; input_open_device(handle); - kbd_refresh_leds(handle); return handle; } @@ -1318,6 +1300,24 @@ static void kbd_disconnect(struct input_handle *handle) kfree(handle); } +/* + * Start keyboard handler on the new keyboard by refreshing LED state to + * match the rest of the system. + */ +static void kbd_start(struct input_handle *handle) +{ + unsigned char leds = ledstate; + + tasklet_disable(&keyboard_tasklet); + if (leds != 0xff) { + input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); + input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_sync(handle->dev); + } + tasklet_enable(&keyboard_tasklet); +} + static struct input_device_id kbd_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, @@ -1338,6 +1338,7 @@ static struct input_handler kbd_handler = { .event = kbd_event, .connect = kbd_connect, .disconnect = kbd_disconnect, + .start = kbd_start, .name = "kbd", .id_table = kbd_ids, }; diff --git a/drivers/input/input.c b/drivers/input/input.c index c2e4d9bdcabf..7aeebb9071c2 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -209,8 +209,13 @@ EXPORT_SYMBOL(input_grab_device); void input_release_device(struct input_handle *handle) { - if (handle->dev->grab == handle) + if (handle->dev->grab == handle) { handle->dev->grab = NULL; + + list_for_each_entry(handle, &handle->dev->h_list, d_node) + if (handle->handler->start) + handle->handler->start(handle); + } } EXPORT_SYMBOL(input_release_device); @@ -954,8 +959,11 @@ int input_register_device(struct input_dev *dev) list_for_each_entry(handler, &input_handler_list, node) if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) if ((id = input_match_device(handler->id_table, dev))) - if ((handle = handler->connect(handler, dev, id))) + if ((handle = handler->connect(handler, dev, id))) { input_link_handle(handle); + if (handler->start) + handler->start(handle); + } input_wakeup_procfs_readers(); diff --git a/include/linux/input.h b/include/linux/input.h index 6e3afad26fa9..55e628e8805b 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -960,6 +960,26 @@ struct input_dev { struct input_handle; +/** + * struct input_handler - implements one of interfaces for input devices + * @private: driver-specific data + * @event: event handler + * @connect: called when attaching a handler to an input device + * @disconnect: disconnects a handler from input device + * @start: starts handler for given handle. This function is called by + * input core right after connect() method and also when a process + * that "grabbed" a device releases it + * @fops: file operations this driver implements + * @minor: beginning of range of 32 minors for devices this driver + * can provide + * @name: name of the handler, to be shown in /proc/bus/input/handlers + * @id_table: pointer to a table of input_device_ids this driver can + * handle + * @blacklist: prointer to a table of input_device_ids this driver should + * ignore even if they match @id_table + * @h_list: list of input handles associated with the handler + * @node: for placing the driver onto input_handler_list + */ struct input_handler { void *private; @@ -967,6 +987,7 @@ struct input_handler { void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); void (*disconnect)(struct input_handle *handle); + void (*start)(struct input_handle *handle); const struct file_operations *fops; int minor; -- cgit v1.2.3 From 0e739d28762e78c746cad8edd33223550a1c6a3f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Jul 2006 00:22:43 -0400 Subject: Input: introduce input_inject_event() function Create input_inject_event() function which is to be used by input handlers as opposed to input_event() which is reserved for drivers implementing input devices. The difference is that if device is "grabbed" by some process input_inject_event() will ignore events unless sent from the handle that is currently owns the device. Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 36 ++++++++++++++++++------------------ drivers/input/evdev.c | 6 +++--- drivers/input/input.c | 27 +++++++++++++++++++++++++++ include/linux/input.h | 1 + 4 files changed, 49 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 38de44b87506..1e946f585673 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -223,13 +223,13 @@ static void kd_nosound(unsigned long ignored) { struct list_head *node; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) - input_event(handle->dev, EV_SND, SND_TONE, 0); + input_inject_event(handle, EV_SND, SND_TONE, 0); if (test_bit(SND_BELL, handle->dev->sndbit)) - input_event(handle->dev, EV_SND, SND_BELL, 0); + input_inject_event(handle, EV_SND, SND_BELL, 0); } } } @@ -247,11 +247,11 @@ void kd_mksound(unsigned int hz, unsigned int ticks) struct input_handle *handle = to_handle_h(node); if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) { - input_event(handle->dev, EV_SND, SND_TONE, hz); + input_inject_event(handle, EV_SND, SND_TONE, hz); break; } if (test_bit(SND_BELL, handle->dev->sndbit)) { - input_event(handle->dev, EV_SND, SND_BELL, 1); + input_inject_event(handle, EV_SND, SND_BELL, 1); break; } } @@ -272,15 +272,15 @@ int kbd_rate(struct kbd_repeat *rep) unsigned int d = 0; unsigned int p = 0; - list_for_each(node,&kbd_handler.h_list) { + list_for_each(node, &kbd_handler.h_list) { struct input_handle *handle = to_handle_h(node); struct input_dev *dev = handle->dev; if (test_bit(EV_REP, dev->evbit)) { if (rep->delay > 0) - input_event(dev, EV_REP, REP_DELAY, rep->delay); + input_inject_event(handle, EV_REP, REP_DELAY, rep->delay); if (rep->period > 0) - input_event(dev, EV_REP, REP_PERIOD, rep->period); + input_inject_event(handle, EV_REP, REP_PERIOD, rep->period); d = dev->rep[REP_DELAY]; p = dev->rep[REP_PERIOD]; } @@ -988,7 +988,7 @@ static inline unsigned char getleds(void) * interrupt routines for this thing allows us to easily mask * this when we don't want any of the above to happen. * This allows for easy and efficient race-condition prevention - * for kbd_start => input_event(dev, EV_LED, ...) => ... + * for kbd_start => input_inject_event(dev, EV_LED, ...) => ... */ static void kbd_bh(unsigned long dummy) @@ -998,11 +998,11 @@ static void kbd_bh(unsigned long dummy) if (leds != ledstate) { list_for_each(node, &kbd_handler.h_list) { - struct input_handle * handle = to_handle_h(node); - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); + struct input_handle *handle = to_handle_h(node); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } } @@ -1310,10 +1310,10 @@ static void kbd_start(struct input_handle *handle) tasklet_disable(&keyboard_tasklet); if (leds != 0xff) { - input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); - input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_sync(handle->dev); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } tasklet_enable(&keyboard_tasklet); } diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2426a5d8537d..4bf48188cc91 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -256,7 +256,7 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_ if (evdev_event_from_user(buffer + retval, &event)) return -EFAULT; - input_event(list->evdev->handle.dev, event.type, event.code, event.value); + input_inject_event(&list->evdev->handle, event.type, event.code, event.value); retval += evdev_event_size(); } @@ -424,8 +424,8 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, if (get_user(v, ip + 1)) return -EFAULT; - input_event(dev, EV_REP, REP_DELAY, u); - input_event(dev, EV_REP, REP_PERIOD, v); + input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); + input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); return 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index 7aeebb9071c2..e20913942927 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -35,6 +35,16 @@ static LIST_HEAD(input_handler_list); static struct input_handler *input_table[8]; +/** + * input_event() - report new input event + * @handle: device that generated the event + * @type: type of the event + * @code: event code + * @value: value of the event + * + * This function should be used by drivers implementing various input devices + * See also input_inject_event() + */ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_handle *handle; @@ -183,6 +193,23 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in } EXPORT_SYMBOL(input_event); +/** + * input_inject_event() - send input event from input handler + * @handle: input handle to send event through + * @type: type of the event + * @code: event code + * @value: value of the event + * + * Similar to input_event() but will ignore event if device is "grabbed" and handle + * injecting event is not the one that owns the device. + */ +void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) +{ + if (!handle->dev->grab || handle->dev->grab == handle) + input_event(handle->dev, type, code, value); +} +EXPORT_SYMBOL(input_inject_event); + static void input_repeat_key(unsigned long data) { struct input_dev *dev = (void *) data; diff --git a/include/linux/input.h b/include/linux/input.h index 55e628e8805b..b3253ab72ff7 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1053,6 +1053,7 @@ void input_close_device(struct input_handle *); int input_flush_device(struct input_handle* handle, struct file* file); void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); +void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value); static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) { -- cgit v1.2.3 From 13abf50df209008b5d44075bafeeab42ace56aa6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 10 Jul 2006 23:18:46 +0900 Subject: [PATCH] libata: improve EH action and EHI flag handling Update ata_eh_about_to_do() and ata_eh_done() to improve EH action and EHI flag handling. * There are two types of EHI flags - one which expires on successful EH and the other which expires on a successful reset. Make this distinction clear. * Unlike other EH actions, reset actions are represented by two EH action masks and a EHI modifier. Implement correct about_to_do/done semantics for resets. That is, prior to reset, related EH info is sucked in from ehi and cleared, and after reset is complete, related EH info in ehc is cleared. These changes improve consistency and remove unnecessary EH actions caused by stale EH action masks and EHI flags. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/scsi/libata-eh.c | 33 ++++++++++++++++++++++++++++----- include/linux/libata.h | 4 +++- 2 files changed, 31 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1dcb2c13ffa9..29f59345305d 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -764,12 +764,27 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, unsigned int action) { unsigned long flags; + struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_context *ehc = &ap->eh_context; spin_lock_irqsave(ap->lock, flags); - ata_eh_clear_action(dev, &ap->eh_info, action); + /* Reset is represented by combination of actions and EHI + * flags. Suck in all related bits before clearing eh_info to + * avoid losing requested action. + */ + if (action & ATA_EH_RESET_MASK) { + ehc->i.action |= ehi->action & ATA_EH_RESET_MASK; + ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; + + /* make sure all reset actions are cleared & clear EHI flags */ + action |= ATA_EH_RESET_MASK; + ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + } + + ata_eh_clear_action(dev, ehi, action); - if (!(ap->eh_context.i.flags & ATA_EHI_QUIET)) + if (!(ehc->i.flags & ATA_EHI_QUIET)) ap->pflags |= ATA_PFLAG_RECOVERED; spin_unlock_irqrestore(ap->lock, flags); @@ -790,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, unsigned int action) { + /* if reset is complete, clear all reset actions & reset modifier */ + if (action & ATA_EH_RESET_MASK) { + action |= ATA_EH_RESET_MASK; + ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + } + ata_eh_clear_action(dev, &ap->eh_context.i, action); } @@ -1478,6 +1499,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_reset_fn_t reset; int i, did_followup_srst, rc; + /* about to reset */ + ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. */ @@ -1526,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_port_printk(ap, KERN_INFO, "%s resetting port\n", reset == softreset ? "soft" : "hard"); - /* reset */ - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); + /* mark that this EH session started with reset */ ehc->i.flags |= ATA_EHI_DID_RESET; rc = ata_do_reset(ap, reset, classes); @@ -1590,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, postreset(ap, classes); /* reset successful, schedule revalidation */ - ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); + ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 6cc497a2b6da..66c3100c2b94 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -265,12 +265,14 @@ enum { /* ata_eh_info->flags */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ - ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */ + ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ ATA_EHI_QUIET = (1 << 3), /* be quiet */ ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + /* max repeat if error condition is still set after ->error_handler */ ATA_EH_MAX_REPEAT = 5, -- cgit v1.2.3 From 361934849e9c0418950bedf667732f36337d88b9 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 28 Jul 2006 08:54:59 +0200 Subject: [PATCH] ide: option to disable cache flushes for buggy drives Some drives claim they support cache flushing, but get seriously confused if you try. Add this option to be able to boot with barriers enabled by default. Signed-off-by: Jens Axboe --- drivers/ide/ide-disk.c | 2 +- drivers/ide/ide.c | 5 ++++- include/linux/ide.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index f712e4cfd9dc..7cf3eb023521 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive) * not available so we don't need to recheck that. */ capacity = idedisk_capacity(drive); - barrier = ide_id_has_flush_cache(id) && + barrier = ide_id_has_flush_cache(id) && !drive->noflush && (drive->addressing == 0 || capacity <= (1ULL << 28) || ide_id_has_flush_cache_ext(id)); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 05fbd9298db7..defd4b4bd374 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1539,7 +1539,7 @@ static int __init ide_setup(char *s) const char *hd_words[] = { "none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", "minus8", "swapdata", "bswap", - "minus11", "remap", "remap63", "scsi", NULL }; + "noflush", "remap", "remap63", "scsi", NULL }; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; @@ -1578,6 +1578,9 @@ static int __init ide_setup(char *s) case -10: /* "bswap" */ drive->bswap = 1; goto done; + case -11: /* noflush */ + drive->noflush = 1; + goto done; case -12: /* "remap" */ drive->remap_0_to_1 = 1; goto done; diff --git a/include/linux/ide.h b/include/linux/ide.h index dc7abef10965..99620451d958 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -571,6 +571,7 @@ typedef struct ide_drive_s { u8 waiting_for_dma; /* dma currently in progress */ u8 unmask; /* okay to unmask other irqs */ u8 bswap; /* byte swap data */ + u8 noflush; /* don't attempt flushes */ u8 dsc_overlap; /* DSC overlap */ u8 nice1; /* give potential excess bandwidth */ -- cgit v1.2.3 From e3f2ddeac718c768fdac4b7fe69d465172f788a8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sat, 29 Jul 2006 05:17:57 +0200 Subject: [PATCH] pi-futex: robust-futex exit Fix robust PI-futexes to be properly unlocked on unexpected exit. For this to work the kernel has to know whether a futex is a PI or a non-PI one, because the semantics are different. Since the space in relevant glibc data structures is extremely scarce, the best solution is to encode the 'PI' information in bit 0 of the robust list pointer. Existing (non-PI) glibc robust futexes have this bit always zero, so the ABI is kept. New glibc with PI-robust-futexes will set this bit. Further fixes from Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Ulrich Drepper Signed-off-by: Thomas Gleixner Signed-off-by: Linus Torvalds --- include/linux/futex.h | 3 +- kernel/futex.c | 91 +++++++++++++++++++++++++++++++++++---------------- kernel/futex_compat.c | 34 ++++++++++++++----- 3 files changed, 89 insertions(+), 39 deletions(-) (limited to 'include/linux') diff --git a/include/linux/futex.h b/include/linux/futex.h index 34c3a215f2cd..d097b5b72bc6 100644 --- a/include/linux/futex.h +++ b/include/linux/futex.h @@ -96,7 +96,8 @@ struct robust_list_head { long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout, u32 __user *uaddr2, u32 val2, u32 val3); -extern int handle_futex_death(u32 __user *uaddr, struct task_struct *curr); +extern int +handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi); #ifdef CONFIG_FUTEX extern void exit_robust_list(struct task_struct *curr); diff --git a/kernel/futex.c b/kernel/futex.c index f59003b1d8f9..dda2049692a2 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -495,10 +495,13 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me) } /* - * We are the first waiter - try to look up the real owner and - * attach the new pi_state to it: + * We are the first waiter - try to look up the real owner and attach + * the new pi_state to it, but bail out when the owner died bit is set + * and TID = 0: */ pid = uval & FUTEX_TID_MASK; + if (!pid && (uval & FUTEX_OWNER_DIED)) + return -ESRCH; p = futex_find_get_task(pid); if (!p) return -ESRCH; @@ -579,16 +582,17 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) * kept enabled while there is PI state around. We must also * preserve the owner died bit.) */ - newval = (uval & FUTEX_OWNER_DIED) | FUTEX_WAITERS | new_owner->pid; - - inc_preempt_count(); - curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); - dec_preempt_count(); + if (!(uval & FUTEX_OWNER_DIED)) { + newval = FUTEX_WAITERS | new_owner->pid; - if (curval == -EFAULT) - return -EFAULT; - if (curval != uval) - return -EINVAL; + inc_preempt_count(); + curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval); + dec_preempt_count(); + if (curval == -EFAULT) + return -EFAULT; + if (curval != uval) + return -EINVAL; + } spin_lock_irq(&pi_state->owner->pi_lock); WARN_ON(list_empty(&pi_state->list)); @@ -1443,9 +1447,11 @@ retry_locked: * again. If it succeeds then we can return without waking * anyone else up: */ - inc_preempt_count(); - uval = futex_atomic_cmpxchg_inatomic(uaddr, current->pid, 0); - dec_preempt_count(); + if (!(uval & FUTEX_OWNER_DIED)) { + inc_preempt_count(); + uval = futex_atomic_cmpxchg_inatomic(uaddr, current->pid, 0); + dec_preempt_count(); + } if (unlikely(uval == -EFAULT)) goto pi_faulted; @@ -1478,9 +1484,11 @@ retry_locked: /* * No waiters - kernel unlocks the futex: */ - ret = unlock_futex_pi(uaddr, uval); - if (ret == -EFAULT) - goto pi_faulted; + if (!(uval & FUTEX_OWNER_DIED)) { + ret = unlock_futex_pi(uaddr, uval); + if (ret == -EFAULT) + goto pi_faulted; + } out_unlock: spin_unlock(&hb->lock); @@ -1699,9 +1707,9 @@ err_unlock: * Process a futex-list entry, check whether it's owned by the * dying task, and do notification if so: */ -int handle_futex_death(u32 __user *uaddr, struct task_struct *curr) +int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi) { - u32 uval, nval; + u32 uval, nval, mval; retry: if (get_user(uval, uaddr)) @@ -1718,20 +1726,44 @@ retry: * thread-death.) The rest of the cleanup is done in * userspace. */ - nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, - uval | FUTEX_OWNER_DIED); + mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED; + nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval); + if (nval == -EFAULT) return -1; if (nval != uval) goto retry; - if (uval & FUTEX_WAITERS) - futex_wake(uaddr, 1); + /* + * Wake robust non-PI futexes here. The wakeup of + * PI futexes happens in exit_pi_state(): + */ + if (!pi) { + if (uval & FUTEX_WAITERS) + futex_wake(uaddr, 1); + } } return 0; } +/* + * Fetch a robust-list pointer. Bit 0 signals PI futexes: + */ +static inline int fetch_robust_entry(struct robust_list __user **entry, + struct robust_list __user **head, int *pi) +{ + unsigned long uentry; + + if (get_user(uentry, (unsigned long *)head)) + return -EFAULT; + + *entry = (void *)(uentry & ~1UL); + *pi = uentry & 1; + + return 0; +} + /* * Walk curr->robust_list (very carefully, it's a userspace list!) * and mark any locks found there dead, and notify any waiters. @@ -1742,14 +1774,14 @@ void exit_robust_list(struct task_struct *curr) { struct robust_list_head __user *head = curr->robust_list; struct robust_list __user *entry, *pending; - unsigned int limit = ROBUST_LIST_LIMIT; + unsigned int limit = ROBUST_LIST_LIMIT, pi, pip; unsigned long futex_offset; /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): */ - if (get_user(entry, &head->list.next)) + if (fetch_robust_entry(&entry, &head->list.next, &pi)) return; /* * Fetch the relative futex offset: @@ -1760,10 +1792,11 @@ void exit_robust_list(struct task_struct *curr) * Fetch any possibly pending lock-add first, and handle it * if it exists: */ - if (get_user(pending, &head->list_op_pending)) + if (fetch_robust_entry(&pending, &head->list_op_pending, &pip)) return; + if (pending) - handle_futex_death((void *)pending + futex_offset, curr); + handle_futex_death((void *)pending + futex_offset, curr, pip); while (entry != &head->list) { /* @@ -1772,12 +1805,12 @@ void exit_robust_list(struct task_struct *curr) */ if (entry != pending) if (handle_futex_death((void *)entry + futex_offset, - curr)) + curr, pi)) return; /* * Fetch the next entry in the list: */ - if (get_user(entry, &entry->next)) + if (fetch_robust_entry(&entry, &entry->next, &pi)) return; /* * Avoid excessively long or circular lists: diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index d1d92b441fb7..d1aab1a452cc 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -12,6 +12,23 @@ #include + +/* + * Fetch a robust-list pointer. Bit 0 signals PI futexes: + */ +static inline int +fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry, + compat_uptr_t *head, int *pi) +{ + if (get_user(*uentry, head)) + return -EFAULT; + + *entry = compat_ptr((*uentry) & ~1); + *pi = (unsigned int)(*uentry) & 1; + + return 0; +} + /* * Walk curr->robust_list (very carefully, it's a userspace list!) * and mark any locks found there dead, and notify any waiters. @@ -22,17 +39,16 @@ void compat_exit_robust_list(struct task_struct *curr) { struct compat_robust_list_head __user *head = curr->compat_robust_list; struct robust_list __user *entry, *pending; + unsigned int limit = ROBUST_LIST_LIMIT, pi; compat_uptr_t uentry, upending; - unsigned int limit = ROBUST_LIST_LIMIT; compat_long_t futex_offset; /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): */ - if (get_user(uentry, &head->list.next)) + if (fetch_robust_entry(&uentry, &entry, &head->list.next, &pi)) return; - entry = compat_ptr(uentry); /* * Fetch the relative futex offset: */ @@ -42,11 +58,11 @@ void compat_exit_robust_list(struct task_struct *curr) * Fetch any possibly pending lock-add first, and handle it * if it exists: */ - if (get_user(upending, &head->list_op_pending)) + if (fetch_robust_entry(&upending, &pending, + &head->list_op_pending, &pi)) return; - pending = compat_ptr(upending); if (upending) - handle_futex_death((void *)pending + futex_offset, curr); + handle_futex_death((void *)pending + futex_offset, curr, pi); while (compat_ptr(uentry) != &head->list) { /* @@ -55,15 +71,15 @@ void compat_exit_robust_list(struct task_struct *curr) */ if (entry != pending) if (handle_futex_death((void *)entry + futex_offset, - curr)) + curr, pi)) return; /* * Fetch the next entry in the list: */ - if (get_user(uentry, (compat_uptr_t *)&entry->next)) + if (fetch_robust_entry(&uentry, &entry, + (compat_uptr_t *)&entry->next, &pi)) return; - entry = compat_ptr(uentry); /* * Avoid excessively long or circular lists: */ -- cgit v1.2.3 From f251d23eaee673524171b24a71a8794acf82783e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 22 Jul 2006 08:20:07 -0300 Subject: V4L/DVB (4342): Fix ext_controls align on 64 bit architectures u64 is aligned as 128bits on x86_64 architetures, requiring an special handling to ioctls that depends on v4l2_ext_control. Let's fix this before ext controls go to kernel mainstream to avoid one more compat32 stuff. Signed-off-by: Mauro Carvalho Chehab --- include/linux/videodev2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index a62673dad76e..b7146956a929 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -716,7 +716,7 @@ struct v4l2_ext_control __s64 value64; void *reserved; }; -}; +} __attribute__ ((packed)); struct v4l2_ext_controls { -- cgit v1.2.3 From 985bc96e27c729b8b686126ed26bba9fbaaf562d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 23 Jul 2006 06:31:19 -0300 Subject: V4L/DVB (4343): Fix for compilation without V4L1 or V4L1_COMPAT Removed usage of HAVE_V4L1 Including videodev.h will just include videodev2.h if V4L1 is not supported V4L1 code at core drivers will honor CONFIG_V4L1_COMPAT stuff Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++-- drivers/media/video/msp3400-driver.c | 10 +++++++++- drivers/media/video/saa7134/saa7134-video.c | 2 +- drivers/media/video/tuner-core.c | 23 ++++++++++++----------- drivers/media/video/v4l2-common.c | 24 ++++++++++++++---------- drivers/media/video/videodev.c | 8 ++++++-- drivers/media/video/vivi.c | 4 ++-- include/linux/videodev.h | 7 +++++-- 8 files changed, 51 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 2225d4b94140..ff4e7ed76b08 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1226,7 +1226,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return cx8800_try_fmt(dev,fh,f); } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { @@ -1585,7 +1585,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, *id = 0; return 0; } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT case VIDIOCSTUNER: { struct video_tuner *v = arg; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index dbb75a7db199..56246b8578f3 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -362,7 +362,7 @@ int msp_sleep(struct msp_state *state, int timeout) } /* ------------------------------------------------------------------------ */ - +#ifdef CONFIG_VIDEO_V4L1 static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode) { if (rxsubchans == V4L2_TUNER_SUB_MONO) @@ -384,6 +384,7 @@ static int msp_mode_v4l1_to_v4l2(int mode) return V4L2_TUNER_MODE_LANG1; return V4L2_TUNER_MODE_MONO; } +#endif static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { @@ -509,6 +510,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ +#ifdef CONFIG_VIDEO_V4L1 case VIDIOCGAUDIO: { struct video_audio *va = arg; @@ -577,6 +579,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOCSFREQ: + { + /* new channel -- kick audio carrier scan */ + msp_wake_thread(client); + break; + } +#endif case VIDIOC_S_FREQUENCY: { /* new channel -- kick audio carrier scan */ diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 82779585a97f..8656f2400e18 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -2087,7 +2087,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_format *f = arg; return saa7134_try_fmt(dev,fh,f); } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 277d35106bde..40590bae5ff7 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -590,6 +590,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (t->standby) t->standby (client); break; +#ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) return 0; @@ -599,17 +600,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) /* Should be implemented, since bttv calls it */ tuner_dbg("VIDIOCSAUDIO not implemented.\n"); break; - case TDA9887_SET_CONFIG: - if (t->type == TUNER_TDA9887) { - int *i = arg; - - t->tda9887_config = *i; - set_freq(client, t->tv_freq); - } - break; - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ case VIDIOCSCHAN: { static const v4l2_std_id map[] = { @@ -693,7 +683,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; return 0; } +#endif + case TDA9887_SET_CONFIG: + if (t->type == TUNER_TDA9887) { + int *i = arg; + t->tda9887_config = *i; + set_freq(client, t->tv_freq); + } + break; + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ case VIDIOC_S_STD: { v4l2_std_id *id = arg; diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index f06dc19e504a..2ecbeffb559e 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -202,7 +202,7 @@ static char *v4l2_memory_names[] = { /* ------------------------------------------------------------------ */ /* debug help functions */ -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT static const char *v4l1_ioctls[] = { [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", @@ -301,7 +301,7 @@ static const char *v4l2_ioctls[] = { #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) static const char *v4l2_int_ioctls[] = { -#ifdef HAVE_VIDEO_DECODER +#ifdef CONFIG_V4L1_COMPAT [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", @@ -367,7 +367,7 @@ void v4l_printk_ioctl(unsigned int cmd) (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); break; -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT case 'v': printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", (_IOC_NR(cmd) < V4L1_IOCTLS) ? @@ -414,6 +414,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) printk ("%s: tuner type=%d\n", s, *p); break; } +#ifdef CONFIG_VIDEO_V4L1_COMPAT case DECODER_SET_VBI_BYPASS: case DECODER_ENABLE_OUTPUT: case DECODER_GET_STATUS: @@ -424,6 +425,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) case VIDIOCCAPTURE: case VIDIOCSYNC: case VIDIOCSWRITEMODE: +#endif case TUNER_SET_TYPE_ADDR: case TUNER_SET_STANDBY: case TDA9887_SET_CONFIG: @@ -755,6 +757,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) p->afc); break; } +#ifdef CONFIG_VIDEO_V4L1_COMPAT case VIDIOCGVBIFMT: case VIDIOCSVBIFMT: { @@ -924,6 +927,14 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) p->clipcount); break; } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + { + unsigned long *p=arg; + printk ("%s: value=%lu\n", s, *p); + break; + } +#endif case VIDIOC_INT_AUDIO_CLOCK_FREQ: case VIDIOC_INT_I2S_CLOCK_FREQ: case VIDIOC_INT_S_STANDBY: @@ -933,13 +944,6 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) printk ("%s: value=%d\n", s, *p); break; } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - { - unsigned long *p=arg; - printk ("%s: value=%lu\n", s, *p); - break; - } case VIDIOC_G_STD: case VIDIOC_S_STD: case VIDIOC_QUERYSTD: diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 4c3f92605a82..5c5281981231 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -760,7 +760,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_overlay(file, fh, *i); break; } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { @@ -1578,7 +1578,11 @@ int video_register_device(struct video_device *vfd, int type, int nr) __FUNCTION__); return ret; } - video_device_create_file(vfd, &class_device_attr_name); + ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name); + if (ret < 0) { + printk(KERN_WARNING "%s error: %d\n", __FUNCTION__, ret); + return ret; + } #if 1 /* needed until all drivers are fixed */ diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 41d23c8acbd8..38bd0c1018c2 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -986,7 +986,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) file->f_flags & O_NONBLOCK)); } -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { struct vivi_fh *fh=priv; @@ -1328,7 +1328,7 @@ static struct video_device vivi = { .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, -#ifdef HAVE_V4L1 +#ifdef CONFIG_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif .tvnorms = tvnorms, diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 41bc7e9603cd..518c7a32175e 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -12,10 +12,11 @@ #ifndef __LINUX_VIDEODEV_H #define __LINUX_VIDEODEV_H -#define HAVE_V4L1 1 - #include +#ifdef CONFIG_VIDEO_V4L1_COMPAT +#define HAVE_V4L1 1 + struct video_capability { char name[32]; @@ -336,6 +337,8 @@ struct video_code #define VID_HARDWARE_SN9C102 38 #define VID_HARDWARE_ARV 39 +#endif /* CONFIG_VIDEO_V4L1_COMPAT */ + #endif /* __LINUX_VIDEODEV_H */ /* -- cgit v1.2.3 From 2ccb48ebb4de139eef4fcefd5f2bb823cb0d81b9 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Sun, 30 Jul 2006 03:03:01 -0700 Subject: [PATCH] ext3: avoid triggering ext3_error on bad NFS file handle The inode number out of an NFS file handle gets passed eventually to ext3_get_inode_block() without any checking. If ext3_get_inode_block() allows it to trigger an error, then bad filehandles can have unpleasant effect - ext3_error() will usually cause a forced read-only remount, or a panic if `errors=panic' was used. So remove the call to ext3_error there and put a matching check in ext3/namei.c where inode numbers are read off storage. [akpm@osdl.org: fix off-by-one error] Signed-off-by: Neil Brown Signed-off-by: Jan Kara Cc: Marcel Holtmann Cc: Cc: "Stephen C. Tweedie" Cc: Eric Sandeen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext3/inode.c | 13 +++++++------ fs/ext3/namei.c | 15 +++++++++++++-- include/linux/ext3_fs.h | 9 +++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index f804d5e9d60c..ab034d3053ea 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -2402,14 +2402,15 @@ static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, struct buffer_head *bh; struct ext3_group_desc * gdp; - - if ((ino != EXT3_ROOT_INO && ino != EXT3_JOURNAL_INO && - ino != EXT3_RESIZE_INO && ino < EXT3_FIRST_INO(sb)) || - ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) { - ext3_error(sb, "ext3_get_inode_block", - "bad inode number: %lu", ino); + if (!ext3_valid_inum(sb, ino)) { + /* + * This error is already checked for in namei.c unless we are + * looking at an NFS filehandle, in which case no error + * report is needed + */ return 0; } + block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); if (block_group >= EXT3_SB(sb)->s_groups_count) { ext3_error(sb,"ext3_get_inode_block","group >= groups count"); diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index d9176dba3698..2aa7101b27cd 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1000,7 +1000,12 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str if (bh) { unsigned long ino = le32_to_cpu(de->inode); brelse (bh); - inode = iget(dir->i_sb, ino); + if (!ext3_valid_inum(dir->i_sb, ino)) { + ext3_error(dir->i_sb, "ext3_lookup", + "bad inode number: %lu", ino); + inode = NULL; + } else + inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); @@ -1028,7 +1033,13 @@ struct dentry *ext3_get_parent(struct dentry *child) return ERR_PTR(-ENOENT); ino = le32_to_cpu(de->inode); brelse(bh); - inode = iget(child->d_inode->i_sb, ino); + + if (!ext3_valid_inum(child->d_inode->i_sb, ino)) { + ext3_error(child->d_inode->i_sb, "ext3_get_parent", + "bad inode number: %lu", ino); + inode = NULL; + } else + inode = iget(child->d_inode->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 5607e6457a65..9f9cce7bd86d 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -492,6 +492,15 @@ static inline struct ext3_inode_info *EXT3_I(struct inode *inode) { return container_of(inode, struct ext3_inode_info, vfs_inode); } + +static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino) +{ + return ino == EXT3_ROOT_INO || + ino == EXT3_JOURNAL_INO || + ino == EXT3_RESIZE_INO || + (ino >= EXT3_FIRST_INO(sb) && + ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)); +} #else /* Assume that user mode programs are passing in an ext3fs superblock, not * a kernel struct super_block. This will allow us to call the feature-test -- cgit v1.2.3 From 822cfbff2ef49a08d1b9618d50f81b475d4f936c Mon Sep 17 00:00:00 2001 From: Chandra Seetharaman Date: Sun, 30 Jul 2006 03:03:04 -0700 Subject: [PATCH] Process Events: Fix biarch compatibility issue. use __u64 timestamp Events sent by Process Events Connector from a 64-bit kernel are not binary compatible with a 32-bit userspace program because the "timestamp" field (struct timespec) is not arch independent. This affects the fields that follow "timestamp" as they will be be off by 8 bytes. This is a problem for 32-bit userspace programs running with 64-bit kernels on ppc64, s390, x86-64.. any "biarch" system. Matt had submitted a different solution to lkml as an RFC earlier. We have since switched to a solution recommended by Evgeniy Polyakov. This patch fixes the problem by changing the timestamp to be a __u64, which stores the number of nanoseconds. Tested on a x86_64 system with both 32 bit application and 64 bit application and on a i386 system. Signed-off-by: Chandra Seetharaman Signed-off-by: Matt Helsley Cc: Evgeniy Polyakov Cc: Guillaume Thouvenin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/connector/cn_proc.c | 20 +++++++++++++++----- include/linux/cn_proc.h | 3 ++- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 498aa37bca22..3ece69231343 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -51,6 +51,7 @@ void proc_fork_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -58,7 +59,8 @@ void proc_fork_connector(struct task_struct *task) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); /* get high res monotonic timestamp */ + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_FORK; ev->event_data.fork.parent_pid = task->real_parent->pid; ev->event_data.fork.parent_tgid = task->real_parent->tgid; @@ -76,6 +78,7 @@ void proc_exec_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; + struct timespec ts; __u8 buffer[CN_PROC_MSG_SIZE]; if (atomic_read(&proc_event_num_listeners) < 1) @@ -84,7 +87,8 @@ void proc_exec_connector(struct task_struct *task) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_EXEC; ev->event_data.exec.process_pid = task->pid; ev->event_data.exec.process_tgid = task->tgid; @@ -100,6 +104,7 @@ void proc_id_connector(struct task_struct *task, int which_id) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -118,7 +123,8 @@ void proc_id_connector(struct task_struct *task, int which_id) } else return; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ @@ -131,6 +137,7 @@ void proc_exit_connector(struct task_struct *task) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -138,7 +145,8 @@ void proc_exit_connector(struct task_struct *task) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; get_seq(&msg->seq, &ev->cpu); - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->what = PROC_EVENT_EXIT; ev->event_data.exit.process_pid = task->pid; ev->event_data.exit.process_tgid = task->tgid; @@ -164,6 +172,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) struct cn_msg *msg; struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; + struct timespec ts; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -171,7 +180,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) msg = (struct cn_msg*)buffer; ev = (struct proc_event*)msg->data; msg->seq = rcvd_seq; - ktime_get_ts(&ev->timestamp); + ktime_get_ts(&ts); /* get high res monotonic timestamp */ + ev->timestamp_ns = timespec_to_ns(&ts); ev->cpu = -1; ev->what = PROC_EVENT_NONE; ev->event_data.ack.err = err; diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h index dbb7769009be..1c86d65bc4b9 100644 --- a/include/linux/cn_proc.h +++ b/include/linux/cn_proc.h @@ -57,7 +57,8 @@ struct proc_event { PROC_EVENT_EXIT = 0x80000000 } what; __u32 cpu; - struct timespec timestamp; + __u64 __attribute__((aligned(8))) timestamp_ns; + /* Number of nano seconds since system boot */ union { /* must be last field of proc_event struct */ struct { __u32 err; -- cgit v1.2.3 From 15a647eba94c3da27ccc666bea72e7cca06b2d19 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 30 Jul 2006 03:03:08 -0700 Subject: [PATCH] genirq: {en,dis}able_irq_wake() need refcounting too IRQs need refcounting and a state flag to track whether the the IRQ should be enabled or disabled as a "normal IRQ" source after a series of calls to {en,dis}able_irq(). For shared IRQs, the IRQ must be enabled so long as at least one driver needs it active. Likewise, IRQs need the same support to track whether the IRQ should be enabled or disabled as a "wakeup event" source after a series of calls to {en,dis}able_irq_wake(). For shared IRQs, the IRQ must be enabled as a wakeup source during sleep so long as at least one driver needs it. But right now they _don't have_ that refcounting ... which means sharing a wakeup-capable IRQ can't work correctly in some configurations. This patch adds the refcount and flag mechanisms to set_irq_wake() -- which is what {en,dis}able_irq_wake() call -- and minimal documentation of what the irq wake mechanism does. Drivers relying on the older (broken) "toggle" semantics will trigger a warning; that'll be a handful of drivers on ARM systems. Signed-off-by: David Brownell Acked-by: Ingo Molnar Acked-by: Thomas Gleixner Cc: Russell King Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 3 +++ kernel/irq/manage.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index b48eae32dc61..6e59ac05ef2a 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -58,6 +58,7 @@ #define IRQ_NOREQUEST 0x04000000 /* IRQ cannot be requested */ #define IRQ_NOAUTOEN 0x08000000 /* IRQ will not be enabled on request irq */ #define IRQ_DELAYED_DISABLE 0x10000000 /* IRQ disable (masking) happens delayed. */ +#define IRQ_WAKEUP 0x20000000 /* IRQ triggers system wakeup */ struct proc_dir_entry; @@ -124,6 +125,7 @@ struct irq_chip { * @action: the irq action chain * @status: status information * @depth: disable-depth, for nested irq_disable() calls + * @wake_depth: enable depth, for multiple set_irq_wake() callers * @irq_count: stats field to detect stalled irqs * @irqs_unhandled: stats field for spurious unhandled interrupts * @lock: locking for SMP @@ -147,6 +149,7 @@ struct irq_desc { unsigned int status; /* IRQ status */ unsigned int depth; /* nested irq disables */ + unsigned int wake_depth; /* nested wake enables */ unsigned int irq_count; /* For detecting broken IRQs */ unsigned int irqs_unhandled; spinlock_t lock; diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 4e461438e48b..92be519eff26 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -137,16 +137,40 @@ EXPORT_SYMBOL(enable_irq); * @irq: interrupt to control * @on: enable/disable power management wakeup * - * Enable/disable power management wakeup mode + * Enable/disable power management wakeup mode, which is + * disabled by default. Enables and disables must match, + * just as they match for non-wakeup mode support. + * + * Wakeup mode lets this IRQ wake the system from sleep + * states like "suspend to RAM". */ int set_irq_wake(unsigned int irq, unsigned int on) { struct irq_desc *desc = irq_desc + irq; unsigned long flags; int ret = -ENXIO; + int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake; + /* wakeup-capable irqs can be shared between drivers that + * don't need to have the same sleep mode behaviors. + */ spin_lock_irqsave(&desc->lock, flags); - if (desc->chip->set_wake) + if (on) { + if (desc->wake_depth++ == 0) + desc->status |= IRQ_WAKEUP; + else + set_wake = NULL; + } else { + if (desc->wake_depth == 0) { + printk(KERN_WARNING "Unbalanced IRQ %d " + "wake disable\n", irq); + WARN_ON(1); + } else if (--desc->wake_depth == 0) + desc->status &= ~IRQ_WAKEUP; + else + set_wake = NULL; + } + if (set_wake) ret = desc->chip->set_wake(irq, on); spin_unlock_irqrestore(&desc->lock, flags); return ret; -- cgit v1.2.3 From 7d94dddd438bcba97db44f120da39bb001b5249f Mon Sep 17 00:00:00 2001 From: Shailabh Nagar Date: Sun, 30 Jul 2006 03:03:10 -0700 Subject: [PATCH] make taskstats sending completely independent of delay accounting on/off status Complete the separation of delay accounting and taskstats by ignoring the return value of delay accounting functions that fill in parts of taskstats before it is sent out (either in response to a command or as part of a task exit). Also make delayacct_add_tsk return silently when delay accounting is turned off rather than treat it as an error. Signed-off-by: Shailabh Nagar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/delayacct.h | 4 +--- kernel/taskstats.c | 8 +++----- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 7e8b6011b8f3..8a284cc6fd5f 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -80,9 +80,7 @@ static inline void delayacct_blkio_end(void) static inline int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) { - if (likely(!delayacct_on)) - return -EINVAL; - if (!tsk->delays) + if (likely(!delayacct_on) || !tsk->delays) return 0; return __delayacct_add_tsk(d, tsk); } diff --git a/kernel/taskstats.c b/kernel/taskstats.c index f45179ce028e..b4c737a11408 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -177,7 +177,7 @@ static int send_cpu_listeners(struct sk_buff *skb, unsigned int cpu) static int fill_pid(pid_t pid, struct task_struct *pidtsk, struct taskstats *stats) { - int rc; + int rc = 0; struct task_struct *tsk = pidtsk; if (!pidtsk) { @@ -196,12 +196,10 @@ static int fill_pid(pid_t pid, struct task_struct *pidtsk, * Each accounting subsystem adds calls to its functions to * fill in relevant parts of struct taskstsats as follows * - * rc = per-task-foo(stats, tsk); - * if (rc) - * goto err; + * per-task-foo(stats, tsk); */ - rc = delayacct_add_tsk(stats, tsk); + delayacct_add_tsk(stats, tsk); stats->version = TASKSTATS_VERSION; /* Define err: label here if needed */ -- cgit v1.2.3 From 163ecdff060f2fa9e8f5238882fd0137493556a6 Mon Sep 17 00:00:00 2001 From: Shailabh Nagar Date: Sun, 30 Jul 2006 03:03:11 -0700 Subject: [PATCH] delay accounting: temporarily enable by default Enable delay accounting by default so that feature gets coverage testing without requiring special measures. Earlier, it was off by default and had to be enabled via a boot time param. This patch reverses the default behaviour to improve coverage testing. It can be removed late in the kernel development cycle if its believed users shouldn't have to incur any cost if they don't want delay accounting. Or it can be retained forever if the utility of the stats is deemed common enough to warrant keeping the feature on. Signed-off-by: Shailabh Nagar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/accounting/delay-accounting.txt | 10 ++++++---- Documentation/kernel-parameters.txt | 4 ++-- include/linux/delayacct.h | 4 ++-- kernel/delayacct.c | 8 ++++---- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/Documentation/accounting/delay-accounting.txt b/Documentation/accounting/delay-accounting.txt index be215e58423b..1443cd71d263 100644 --- a/Documentation/accounting/delay-accounting.txt +++ b/Documentation/accounting/delay-accounting.txt @@ -64,11 +64,13 @@ Compile the kernel with CONFIG_TASK_DELAY_ACCT=y CONFIG_TASKSTATS=y -Enable the accounting at boot time by adding -the following to the kernel boot options - delayacct +Delay accounting is enabled by default at boot up. +To disable, add + nodelayacct +to the kernel boot options. The rest of the instructions +below assume this has not been done. -and after the system has booted up, use a utility +After the system has booted up, use a utility similar to getdelays.c to access the delays seen by a given task or a task group (tgid). The utility also allows a given command to be diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e11f7728ec6f..b50595a0550f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -448,8 +448,6 @@ running once the system is up. Format: [,] See also Documentation/networking/decnet.txt. - delayacct [KNL] Enable per-task delay accounting - dhash_entries= [KNL] Set number of hash buckets for dentry cache. @@ -1031,6 +1029,8 @@ running once the system is up. nocache [ARM] + nodelayacct [KNL] Disable per-task delay accounting + nodisconnect [HW,SCSI,M68K] Disables SCSI disconnects. noexec [IA-64] diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 8a284cc6fd5f..11487b6e7127 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -55,7 +55,7 @@ static inline void delayacct_tsk_init(struct task_struct *tsk) { /* reinitialize in case parent's non-null pointer was dup'ed*/ tsk->delays = NULL; - if (unlikely(delayacct_on)) + if (delayacct_on) __delayacct_tsk_init(tsk); } @@ -80,7 +80,7 @@ static inline void delayacct_blkio_end(void) static inline int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) { - if (likely(!delayacct_on) || !tsk->delays) + if (!delayacct_on || !tsk->delays) return 0; return __delayacct_add_tsk(d, tsk); } diff --git a/kernel/delayacct.c b/kernel/delayacct.c index f05392d64267..57ca3730205d 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -19,15 +19,15 @@ #include #include -int delayacct_on __read_mostly; /* Delay accounting turned on/off */ +int delayacct_on __read_mostly = 1; /* Delay accounting turned on/off */ kmem_cache_t *delayacct_cache; -static int __init delayacct_setup_enable(char *str) +static int __init delayacct_setup_disable(char *str) { - delayacct_on = 1; + delayacct_on = 0; return 1; } -__setup("delayacct", delayacct_setup_enable); +__setup("nodelayacct", delayacct_setup_disable); void delayacct_init(void) { -- cgit v1.2.3 From b8bdb460b7ecf08a4fed6e8b5b6b3fe874587aaa Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Sun, 30 Jul 2006 03:03:33 -0700 Subject: [PATCH] always define IRQ_PER_CPU Reduce the likelihood of someone accidentally introducing namespace collisions. Signed-off-by: Yoichi Yuasa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/irq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/irq.h b/include/linux/irq.h index 6e59ac05ef2a..fbf6d901e9c2 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -47,8 +47,8 @@ #define IRQ_WAITING 0x00200000 /* IRQ not yet seen - for autodetection */ #define IRQ_LEVEL 0x00400000 /* IRQ level triggered */ #define IRQ_MASKED 0x00800000 /* IRQ masked - shouldn't be seen again */ +#define IRQ_PER_CPU 0x01000000 /* IRQ is per CPU */ #ifdef CONFIG_IRQ_PER_CPU -# define IRQ_PER_CPU 0x01000000 /* IRQ is per CPU */ # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) #else # define CHECK_IRQ_PER_CPU(var) 0 -- cgit v1.2.3 From 0d94df56963251d896e87c6197f6df132593232b Mon Sep 17 00:00:00 2001 From: Uwe Zeisberger Date: Sun, 30 Jul 2006 03:04:02 -0700 Subject: [PATCH] Add parentheses around arguments in the SH_DIV macro. There is currently no affected user in the tree, but usage is less surprising that way. Signed-off-by: Uwe Zeisberger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/jiffies.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 043376920f51..329ebcffa106 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -47,8 +47,8 @@ * - (NOM / DEN) fits in (32 - LSH) bits. * - (NOM % DEN) fits in (32 - LSH) bits. */ -#define SH_DIV(NOM,DEN,LSH) ( ((NOM / DEN) << LSH) \ - + (((NOM % DEN) << LSH) + DEN / 2) / DEN) +#define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \ + + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN)) /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) -- cgit v1.2.3 From 256154fbc31c25a8df4d398232acfa9d4892224c Mon Sep 17 00:00:00 2001 From: "Antonino A. Daplas" Date: Sun, 30 Jul 2006 03:04:17 -0700 Subject: [PATCH] fbdev: statically link the framebuffer notification functions The backlight and lcd subsystems can be notified by the framebuffer layer of blanking events. However, these subsystems, as a whole, can function independently from the framebuffer layer. But in order to enable to the lcd and backlight subsystems, the framebuffer has to be compiled also, effectively sucking in a huge amount of unneeded code. To prevent dependency problems, separate out the framebuffer notification mechanism from the framebuffer layer and permanently link it to the kernel. Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/Kconfig | 2 +- drivers/video/Makefile | 1 + drivers/video/backlight/Kconfig | 4 +-- drivers/video/fb_notify.c | 46 +++++++++++++++++++++++++++++++++++ drivers/video/fbmem.c | 54 +++++++++-------------------------------- include/linux/fb.h | 2 +- 6 files changed, 62 insertions(+), 47 deletions(-) create mode 100644 drivers/video/fb_notify.c (limited to 'include/linux') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 82288a7218d4..728cb5677725 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1620,7 +1620,7 @@ if FB || SGI_NEWPORT_CONSOLE source "drivers/video/logo/Kconfig" endif -if FB && SYSFS +if SYSFS source "drivers/video/backlight/Kconfig" endif diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 95563c9c6b9c..481c6c9695f8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-y += fb_notify.o obj-$(CONFIG_FB) += fb.o fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ modedb.o fbcvt.o diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 022f9d3473f5..02f15297a021 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -10,7 +10,7 @@ menuconfig BACKLIGHT_LCD_SUPPORT config BACKLIGHT_CLASS_DEVICE tristate "Lowlevel Backlight controls" - depends on BACKLIGHT_LCD_SUPPORT && FB + depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of the LCD @@ -26,7 +26,7 @@ config BACKLIGHT_DEVICE config LCD_CLASS_DEVICE tristate "Lowlevel LCD controls" - depends on BACKLIGHT_LCD_SUPPORT && FB + depends on BACKLIGHT_LCD_SUPPORT default m help This framework adds support for low-level control of LCD. diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c new file mode 100644 index 000000000000..8c020389e4fa --- /dev/null +++ b/drivers/video/fb_notify.c @@ -0,0 +1,46 @@ +/* + * linux/drivers/video/fb_notify.c + * + * Copyright (C) 2006 Antonino Daplas + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#include +#include + +static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); + +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&fb_notifier_list, nb); +} +EXPORT_SYMBOL(fb_register_client); + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&fb_notifier_list, nb); +} +EXPORT_SYMBOL(fb_unregister_client); + +/** + * fb_notifier_call_chain - notify clients of fb_events + * + */ +int fb_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&fb_notifier_list, val, v); +} +EXPORT_SYMBOL_GPL(fb_notifier_call_chain); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 4fc9df426c1a..17961e3ecaa0 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -52,7 +52,6 @@ #define FBPIXMAPSIZE (1024 * 8) -static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); struct fb_info *registered_fb[FB_MAX]; int num_registered_fb; @@ -791,8 +790,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) event.info = info; event.data = &mode1; - ret = blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_MODE_DELETE, &event); + ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); } if (!ret) @@ -837,8 +835,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) info->flags &= ~FBINFO_MISC_USEREVENT; event.info = info; - blocking_notifier_call_chain(&fb_notifier_list, - evnt, &event); + fb_notifier_call_chain(evnt, &event); } } } @@ -861,8 +858,7 @@ fb_blank(struct fb_info *info, int blank) event.info = info; event.data = ␣ - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_BLANK, &event); + fb_notifier_call_chain(FB_EVENT_BLANK, &event); } return ret; @@ -933,8 +929,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, con2fb.framebuffer = -1; event.info = info; event.data = &con2fb; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_GET_CONSOLE_MAP, &event); + fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); return copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; case FBIOPUT_CON2FBMAP: @@ -952,9 +947,8 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EINVAL; event.info = info; event.data = &con2fb; - return blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_SET_CONSOLE_MAP, - &event); + return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, + &event); case FBIOBLANK: acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; @@ -1330,8 +1324,7 @@ register_framebuffer(struct fb_info *fb_info) registered_fb[i] = fb_info; event.info = fb_info; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_FB_REGISTERED, &event); + fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); return 0; } @@ -1365,29 +1358,10 @@ unregister_framebuffer(struct fb_info *fb_info) fb_cleanup_class_device(fb_info); class_device_destroy(fb_class, MKDEV(FB_MAJOR, i)); event.info = fb_info; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_FB_UNREGISTERED, &event); + fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); return 0; } -/** - * fb_register_client - register a client notifier - * @nb: notifier block to callback on events - */ -int fb_register_client(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&fb_notifier_list, nb); -} - -/** - * fb_unregister_client - unregister a client notifier - * @nb: notifier block to callback on events - */ -int fb_unregister_client(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&fb_notifier_list, nb); -} - /** * fb_set_suspend - low level driver signals suspend * @info: framebuffer affected @@ -1403,13 +1377,11 @@ void fb_set_suspend(struct fb_info *info, int state) event.info = info; if (state) { - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_SUSPEND, &event); + fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); info->state = FBINFO_STATE_SUSPENDED; } else { info->state = FBINFO_STATE_RUNNING; - blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_RESUME, &event); + fb_notifier_call_chain(FB_EVENT_RESUME, &event); } } @@ -1480,9 +1452,7 @@ int fb_new_modelist(struct fb_info *info) if (!list_empty(&info->modelist)) { event.info = info; - err = blocking_notifier_call_chain(&fb_notifier_list, - FB_EVENT_NEW_MODELIST, - &event); + err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); } return err; @@ -1594,8 +1564,6 @@ EXPORT_SYMBOL(fb_blank); EXPORT_SYMBOL(fb_pan_display); EXPORT_SYMBOL(fb_get_buffer_offset); EXPORT_SYMBOL(fb_set_suspend); -EXPORT_SYMBOL(fb_register_client); -EXPORT_SYMBOL(fb_unregister_client); EXPORT_SYMBOL(fb_get_options); MODULE_LICENSE("GPL"); diff --git a/include/linux/fb.h b/include/linux/fb.h index 405f44e44e5d..4ad0673b1995 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -524,7 +524,7 @@ struct fb_event { extern int fb_register_client(struct notifier_block *nb); extern int fb_unregister_client(struct notifier_block *nb); - +extern int fb_notifier_call_chain(unsigned long val, void *v); /* * Pixmap structure definition * -- cgit v1.2.3 From 4b755999d6e0c1d988fb448289abb6c226cd8c36 Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sun, 30 Jul 2006 03:04:19 -0700 Subject: [PATCH] powermac: More powermac backlight fixes This patch fixes several problems: - The legacy backlight value might be set at interrupt time. Introduced a worker to prevent it from directly calling the backlight code. - via-pmu allows the backlight to be grabbed, in which case we need to prevent other kernel code from changing the brightness. - Don't send PMU requests in via-pmu-backlight when the machine is about to sleep or waking up. - More Kconfig fixes. Signed-off-by: Michael Hanselmann Cc: Benjamin Herrenschmidt Cc: "Antonino A. Daplas" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/powermac/backlight.c | 58 ++++++++++++++++++++++-- drivers/macintosh/Kconfig | 2 - drivers/macintosh/adbhid.c | 14 ++---- drivers/macintosh/via-pmu-backlight.c | 68 +++++++++++++++++++++++------ drivers/macintosh/via-pmu.c | 39 ++++++----------- drivers/video/Kconfig | 28 +++++------- drivers/video/aty/aty128fb.c | 3 ++ drivers/video/aty/atyfb_base.c | 4 +- include/asm-powerpc/backlight.h | 4 ++ include/linux/pmu.h | 3 +- 10 files changed, 147 insertions(+), 76 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c index 74eed6b74cd6..d66415491055 100644 --- a/arch/powerpc/platforms/powermac/backlight.c +++ b/arch/powerpc/platforms/powermac/backlight.c @@ -10,19 +10,32 @@ #include #include #include +#include +#include +#include #include #include #define OLD_BACKLIGHT_MAX 15 static void pmac_backlight_key_worker(void *data); +static void pmac_backlight_set_legacy_worker(void *data); + static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker, NULL); +static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker, NULL); -/* Although this variable is used in interrupt context, it makes no sense to - * protect it. No user is able to produce enough key events per second and +/* Although these variables are used in interrupt context, it makes no sense to + * protect them. No user is able to produce enough key events per second and * notice the errors that might happen. */ static int pmac_backlight_key_queued; +static int pmac_backlight_set_legacy_queued; + +/* The via-pmu code allows the backlight to be grabbed, in which case the + * in-kernel control of the brightness needs to be disabled. This should + * only be used by really old PowerBooks. + */ +static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0); /* Protect the pmac_backlight variable */ DEFINE_MUTEX(pmac_backlight_mutex); @@ -82,6 +95,9 @@ int pmac_backlight_curve_lookup(struct fb_info *info, int value) static void pmac_backlight_key_worker(void *data) { + if (atomic_read(&kernel_backlight_disabled)) + return; + mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { struct backlight_properties *props; @@ -107,8 +123,12 @@ static void pmac_backlight_key_worker(void *data) mutex_unlock(&pmac_backlight_mutex); } +/* This function is called in interrupt context */ void pmac_backlight_key(int direction) { + if (atomic_read(&kernel_backlight_disabled)) + return; + /* we can receive multiple interrupts here, but the scheduled work * will run only once, with the last value */ @@ -116,7 +136,7 @@ void pmac_backlight_key(int direction) schedule_work(&pmac_backlight_key_work); } -int pmac_backlight_set_legacy_brightness(int brightness) +static int __pmac_backlight_set_legacy_brightness(int brightness) { int error = -ENXIO; @@ -145,6 +165,28 @@ int pmac_backlight_set_legacy_brightness(int brightness) return error; } +static void pmac_backlight_set_legacy_worker(void *data) +{ + if (atomic_read(&kernel_backlight_disabled)) + return; + + __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued); +} + +/* This function is called in interrupt context */ +void pmac_backlight_set_legacy_brightness_pmu(int brightness) { + if (atomic_read(&kernel_backlight_disabled)) + return; + + pmac_backlight_set_legacy_queued = brightness; + schedule_work(&pmac_backlight_set_legacy_work); +} + +int pmac_backlight_set_legacy_brightness(int brightness) +{ + return __pmac_backlight_set_legacy_brightness(brightness); +} + int pmac_backlight_get_legacy_brightness() { int result = -ENXIO; @@ -167,6 +209,16 @@ int pmac_backlight_get_legacy_brightness() return result; } +void pmac_backlight_disable() +{ + atomic_inc(&kernel_backlight_disabled); +} + +void pmac_backlight_enable() +{ + atomic_dec(&kernel_backlight_disabled); +} + EXPORT_SYMBOL_GPL(pmac_backlight); EXPORT_SYMBOL_GPL(pmac_backlight_mutex); EXPORT_SYMBOL_GPL(pmac_has_backlight_type); diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index f5fe7fb4b3ad..d162307e309f 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -115,8 +115,6 @@ config PMAC_BACKLIGHT bool "Backlight control for LCD screens" depends on ADB_PMU && FB = y && (BROKEN || !PPC64) select FB_BACKLIGHT - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT help Say Y here to enable Macintosh specific extensions of the generic backlight code. With this enabled, the brightness keys on older diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 545be1ed6927..c69d23bb255e 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -45,14 +45,11 @@ #include #include +#include #ifdef CONFIG_PPC_PMAC #include #endif -#ifdef CONFIG_PMAC_BACKLIGHT -#include -#endif - MODULE_AUTHOR("Franz Sirl "); #define KEYB_KEYREG 0 /* register # for key up/down data */ @@ -237,11 +234,6 @@ static struct adb_ids keyboard_ids; static struct adb_ids mouse_ids; static struct adb_ids buttons_ids; -#ifdef CONFIG_PMAC_BACKLIGHT -/* Exported to via-pmu.c */ -int disable_kernel_backlight = 0; -#endif /* CONFIG_PMAC_BACKLIGHT */ - /* Kind of keyboard, see Apple technote 1152 */ #define ADB_KEYBOARD_UNKNOWN 0 #define ADB_KEYBOARD_ANSI 0x0100 @@ -527,7 +519,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0xa: /* brightness decrease */ #ifdef CONFIG_PMAC_BACKLIGHT - if (!disable_kernel_backlight && down) + if (down) pmac_backlight_key_down(); #endif input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down); @@ -535,7 +527,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto case 0x9: /* brightness increase */ #ifdef CONFIG_PMAC_BACKLIGHT - if (!disable_kernel_backlight && down) + if (down) pmac_backlight_key_up(); #endif input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down); diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index b42d05f2aaff..d3f8d75bcbb4 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -15,8 +15,9 @@ #define MAX_PMU_LEVEL 0xFF -static struct device_node *vias; static struct backlight_properties pmu_backlight_data; +static spinlock_t pmu_backlight_lock; +static int sleeping; static int pmu_backlight_get_level_brightness(struct fb_info *info, int level) @@ -40,23 +41,36 @@ static int pmu_backlight_update_status(struct backlight_device *bd) { struct fb_info *info = class_get_devdata(&bd->class_dev); struct adb_request req; - int pmulevel, level = bd->props->brightness; + unsigned long flags; + int level = bd->props->brightness; - if (vias == NULL) - return -ENODEV; + spin_lock_irqsave(&pmu_backlight_lock, flags); + + /* Don't update brightness when sleeping */ + if (sleeping) + goto out; if (bd->props->power != FB_BLANK_UNBLANK || bd->props->fb_blank != FB_BLANK_UNBLANK) level = 0; - pmulevel = pmu_backlight_get_level_brightness(info, level); + if (level > 0) { + int pmulevel = pmu_backlight_get_level_brightness(info, level); - pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); - pmu_wait_complete(&req); + pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel); + pmu_wait_complete(&req); - pmu_request(&req, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (level > 0 ? PMU_POW_ON : PMU_POW_OFF)); - pmu_wait_complete(&req); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | PMU_POW_ON); + pmu_wait_complete(&req); + } else { + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_BACKLIGHT | PMU_POW_OFF); + pmu_wait_complete(&req); + } + +out: + spin_unlock_irqrestore(&pmu_backlight_lock, flags); return 0; } @@ -73,15 +87,39 @@ static struct backlight_properties pmu_backlight_data = { .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; -void __init pmu_backlight_init(struct device_node *in_vias) +#ifdef CONFIG_PM +static int pmu_backlight_sleep_call(struct pmu_sleep_notifier *self, int when) +{ + unsigned long flags; + + spin_lock_irqsave(&pmu_backlight_lock, flags); + + switch (when) { + case PBOOK_SLEEP_REQUEST: + sleeping = 1; + break; + case PBOOK_WAKE: + sleeping = 0; + break; + } + + spin_unlock_irqrestore(&pmu_backlight_lock, flags); + + return PBOOK_SLEEP_OK; +} + +static struct pmu_sleep_notifier pmu_backlight_sleep_notif = { + .notifier_call = pmu_backlight_sleep_call, +}; +#endif + +void __init pmu_backlight_init() { struct backlight_device *bd; struct fb_info *info; char name[10]; int level, autosave; - vias = in_vias; - /* Special case for the old PowerBook since I can't test on it */ autosave = machine_is_compatible("AAPL,3400/2400") || @@ -141,6 +179,10 @@ void __init pmu_backlight_init(struct device_node *in_vias) pmac_backlight = bd; mutex_unlock(&pmac_backlight_mutex); +#ifdef CONFIG_PM + pmu_register_sleep_notifier(&pmu_backlight_sleep_notif); +#endif + printk("pmubl: Backlight initialized (%s)\n", name); return; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 06ca80bfd6b9..ea386801e215 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -16,7 +16,6 @@ * a sleep or a freq. switch * - Move sleep code out of here to pmac_pm, merge into new * common PM infrastructure - * - Move backlight code out as well * - Save/Restore PCI space properly * */ @@ -60,9 +59,7 @@ #include #include #include -#ifdef CONFIG_PMAC_BACKLIGHT #include -#endif #include "via-pmu-event.h" @@ -177,10 +174,6 @@ static int query_batt_timer = BATTERY_POLLING_COUNT; static struct adb_request batt_req; static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES]; -#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) -extern int disable_kernel_backlight; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ - int __fake_sleep; int asleep; BLOCKING_NOTIFIER_HEAD(sleep_notifier_list); @@ -466,7 +459,7 @@ static int __init via_pmu_dev_init(void) #ifdef CONFIG_PMAC_BACKLIGHT /* Initialize backlight */ - pmu_backlight_init(vias); + pmu_backlight_init(); #endif #ifdef CONFIG_PPC32 @@ -1403,11 +1396,8 @@ next: else if ((1 << pirq) & PMU_INT_SNDBRT) { #ifdef CONFIG_PMAC_BACKLIGHT if (len == 3) -#ifdef CONFIG_INPUT_ADBHID - if (!disable_kernel_backlight) -#endif /* CONFIG_INPUT_ADBHID */ - pmac_backlight_set_legacy_brightness(data[1] >> 4); -#endif /* CONFIG_PMAC_BACKLIGHT */ + pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4); +#endif } /* Tick interrupt */ else if ((1 << pirq) & PMU_INT_TICK) { @@ -2414,7 +2404,7 @@ struct pmu_private { spinlock_t lock; #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) int backlight_locker; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ +#endif }; static LIST_HEAD(all_pmu_pvt); @@ -2464,7 +2454,7 @@ pmu_open(struct inode *inode, struct file *file) spin_lock_irqsave(&all_pvt_lock, flags); #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) pp->backlight_locker = 0; -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ +#endif list_add(&pp->list, &all_pmu_pvt); spin_unlock_irqrestore(&all_pvt_lock, flags); file->private_data = pp; @@ -2559,13 +2549,12 @@ pmu_release(struct inode *inode, struct file *file) spin_lock_irqsave(&all_pvt_lock, flags); list_del(&pp->list); spin_unlock_irqrestore(&all_pvt_lock, flags); + #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) - if (pp->backlight_locker) { - spin_lock_irqsave(&pmu_lock, flags); - disable_kernel_backlight--; - spin_unlock_irqrestore(&pmu_lock, flags); - } -#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */ + if (pp->backlight_locker) + pmac_backlight_enable(); +#endif + kfree(pp); } unlock_kernel(); @@ -2642,18 +2631,18 @@ pmu_ioctl(struct inode * inode, struct file *filp, #ifdef CONFIG_INPUT_ADBHID case PMU_IOC_GRAB_BACKLIGHT: { struct pmu_private *pp = filp->private_data; - unsigned long flags; if (pp->backlight_locker) return 0; + pp->backlight_locker = 1; - spin_lock_irqsave(&pmu_lock, flags); - disable_kernel_backlight++; - spin_unlock_irqrestore(&pmu_lock, flags); + pmac_backlight_disable(); + return 0; } #endif /* CONFIG_INPUT_ADBHID */ #endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */ + case PMU_IOC_GET_MODEL: return put_user(pmu_kind, argp); case PMU_IOC_HAS_ADB: diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 728cb5677725..c40b9b8b1e7e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -86,9 +86,11 @@ config FB_MACMODES default n config FB_BACKLIGHT - bool - depends on FB - default n + bool + depends on FB + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + default n config FB_MODE_HELPERS bool "Enable Video Mode Handling Helpers" @@ -721,10 +723,8 @@ config FB_NVIDIA_I2C config FB_NVIDIA_BACKLIGHT bool "Support for backlight control" - depends on FB_NVIDIA && PPC_PMAC + depends on FB_NVIDIA && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -769,10 +769,8 @@ config FB_RIVA_DEBUG config FB_RIVA_BACKLIGHT bool "Support for backlight control" - depends on FB_RIVA && PPC_PMAC + depends on FB_RIVA && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -1025,10 +1023,8 @@ config FB_RADEON_I2C config FB_RADEON_BACKLIGHT bool "Support for backlight control" - depends on FB_RADEON && PPC_PMAC + depends on FB_RADEON && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -1059,10 +1055,8 @@ config FB_ATY128 config FB_ATY128_BACKLIGHT bool "Support for backlight control" - depends on FB_ATY128 && PPC_PMAC + depends on FB_ATY128 && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. @@ -1111,10 +1105,8 @@ config FB_ATY_GX config FB_ATY_BACKLIGHT bool "Support for backlight control" - depends on FB_ATY && PPC_PMAC + depends on FB_ATY && PMAC_BACKLIGHT select FB_BACKLIGHT - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE default y help Say Y here if you want to control the backlight of your display. diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index c64a717e2d4b..8b08121b390b 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -455,7 +455,10 @@ static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_idle(struct aty128fb_par *par); static u32 depth_to_dst(u32 depth); + +#ifdef CONFIG_FB_ATY128_BACKLIGHT static void aty128_bl_set_power(struct fb_info *info, int power); +#endif #define BIOS_IN8(v) (readb(bios + (v))) #define BIOS_IN16(v) (readb(bios + (v)) | \ diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 1507d19f481f..053ff63365b7 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2812,7 +2812,7 @@ static int atyfb_blank(int blank, struct fb_info *info) if (par->lock_blank || par->asleep) return 0; -#ifdef CONFIG_PMAC_BACKLIGHT +#ifdef CONFIG_FB_ATY_BACKLIGHT if (machine_is(powermac) && blank > FB_BLANK_NORMAL) aty_bl_set_power(info, FB_BLANK_POWERDOWN); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) @@ -2844,7 +2844,7 @@ static int atyfb_blank(int blank, struct fb_info *info) } aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); -#ifdef CONFIG_PMAC_BACKLIGHT +#ifdef CONFIG_FB_ATY_BACKLIGHT if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) aty_bl_set_power(info, FB_BLANK_UNBLANK); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) diff --git a/include/asm-powerpc/backlight.h b/include/asm-powerpc/backlight.h index 58d4b6f8d827..8cf5c37c3817 100644 --- a/include/asm-powerpc/backlight.h +++ b/include/asm-powerpc/backlight.h @@ -30,8 +30,12 @@ static inline void pmac_backlight_key_down(void) pmac_backlight_key(1); } +extern void pmac_backlight_set_legacy_brightness_pmu(int brightness); extern int pmac_backlight_set_legacy_brightness(int brightness); extern int pmac_backlight_get_legacy_brightness(void); +extern void pmac_backlight_enable(void); +extern void pmac_backlight_disable(void); + #endif /* __KERNEL__ */ #endif diff --git a/include/linux/pmu.h b/include/linux/pmu.h index 2ed807ddc08c..783177387ac6 100644 --- a/include/linux/pmu.h +++ b/include/linux/pmu.h @@ -231,7 +231,6 @@ extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES]; extern unsigned int pmu_power_flags; /* Backlight */ -extern int disable_kernel_backlight; -extern void pmu_backlight_init(struct device_node*); +extern void pmu_backlight_init(void); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 9cd3ecd674cf3194e07435b5b9559c4d432026d5 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 30 Jul 2006 20:20:07 -0700 Subject: [NETFILTER]: include/linux/netfilter_bridge.h: header cleanup Header doesn't use anything from atomic.h. It fixes headers_check warning: include/linux/netfilter_bridge.h requires asm/atomic.h, which does not exist Compile tested on alpha arm i386-up sparc sparc64-up x86_64 alpha-up i386 sparc64 sparc-up x86_64-up Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- include/linux/netfilter_bridge.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 31f02ba036ce..10c13dc4665b 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h @@ -6,7 +6,6 @@ #include #if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER) -#include #include #endif -- cgit v1.2.3 From 8af2745645243b5e5b031504a643bf2158571dc7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 31 Jul 2006 22:35:23 -0700 Subject: [NET]: Add netdev_alloc_skb(). Add a dev_alloc_skb variant that takes a struct net_device * paramater. For now that paramater is unused, but I'll use it to allocate the skb from node-local memory in a follow-up patch. Also there have been some other plans mentioned on the list that can use it. Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- include/linux/skbuff.h | 22 ++++++++++++++++++++++ net/core/skbuff.c | 24 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 4307e764ef0a..b91fbfb7d54c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1104,6 +1104,28 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length) return __dev_alloc_skb(length, GFP_ATOMIC); } +extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, + unsigned int length, gfp_t gfp_mask); + +/** + * netdev_alloc_skb - allocate an skbuff for rx on a specific device + * @dev: network device to receive on + * @length: length to allocate + * + * Allocate a new &sk_buff and assign it a usage count of one. The + * buffer has unspecified headroom built in. Users should allocate + * the headroom they think they need without accounting for the + * built in space. The built in space is used for optimisations. + * + * %NULL is returned if there is no free memory. Although this function + * allocates memory it can be called from an interrupt. + */ +static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, + unsigned int length) +{ + return __netdev_alloc_skb(dev, length, GFP_ATOMIC); +} + /** * skb_cow - copy header of skb when it is required * @skb: buffer to cow diff --git a/net/core/skbuff.c b/net/core/skbuff.c index d236f02c6467..71487b915d67 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -256,6 +256,29 @@ nodata: goto out; } +/** + * __netdev_alloc_skb - allocate an skbuff for rx on a specific device + * @dev: network device to receive on + * @length: length to allocate + * @gfp_mask: get_free_pages mask, passed to alloc_skb + * + * Allocate a new &sk_buff and assign it a usage count of one. The + * buffer has unspecified headroom built in. Users should allocate + * the headroom they think they need without accounting for the + * built in space. The built in space is used for optimisations. + * + * %NULL is returned if there is no free memory. + */ +struct sk_buff *__netdev_alloc_skb(struct net_device *dev, + unsigned int length, gfp_t gfp_mask) +{ + struct sk_buff *skb; + + skb = alloc_skb(length + NET_SKB_PAD, gfp_mask); + if (likely(skb)) + skb_reserve(skb, NET_SKB_PAD); + return skb; +} static void skb_drop_list(struct sk_buff **listp) { @@ -2048,6 +2071,7 @@ EXPORT_SYMBOL(__kfree_skb); EXPORT_SYMBOL(kfree_skb); EXPORT_SYMBOL(__pskb_pull_tail); EXPORT_SYMBOL(__alloc_skb); +EXPORT_SYMBOL(__netdev_alloc_skb); EXPORT_SYMBOL(pskb_copy); EXPORT_SYMBOL(pskb_expand_head); EXPORT_SYMBOL(skb_checksum); -- cgit v1.2.3 From 76f10ad0e67cbc6ded2ee143e5188e0b7ff9fb15 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 2 Aug 2006 14:06:55 -0700 Subject: [NET]: Remove lockdep_set_class() call from skb_queue_head_init(). The skb_queue_head_init() function is used both in drivers for private use and in the core networking code. The usage models are vastly set of functions that is only softirq safe; while the driver usage tends to be more limited to a few hardirq safe accessor functions. Rather than annotating all 133+ driver usages, for now just split this lock into a per queue class. This change is obviously safe and probably should make 2.6.18. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/skbuff.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b91fbfb7d54c..b22d4a6083bd 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -606,10 +606,17 @@ static inline __u32 skb_queue_len(const struct sk_buff_head *list_) extern struct lock_class_key skb_queue_lock_key; +/* + * This function creates a split out lock class for each invocation; + * this is needed for now since a whole lot of users of the skb-queue + * infrastructure in drivers have different locking usage (in hardirq) + * than the networking core (in softirq only). In the long run either the + * network layer or drivers should need annotation to consolidate the + * main types of usage into 3 classes. + */ static inline void skb_queue_head_init(struct sk_buff_head *list) { spin_lock_init(&list->lock); - lockdep_set_class(&list->lock, &skb_queue_lock_key); list->prev = list->next = (struct sk_buff *)list; list->qlen = 0; } -- cgit v1.2.3 From 2b7e24b66d31d677d76b49918e711eb360c978b6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 2 Aug 2006 14:07:58 -0700 Subject: [NET]: skb_queue_lock_key() is no longer used. Signed-off-by: Adrian Bunk Acked-by: Arjan van de Ven Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 -- net/core/skbuff.c | 7 ------- 2 files changed, 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b22d4a6083bd..19c96d498e20 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -604,8 +604,6 @@ static inline __u32 skb_queue_len(const struct sk_buff_head *list_) return list_->qlen; } -extern struct lock_class_key skb_queue_lock_key; - /* * This function creates a split out lock class for each invocation; * this is needed for now since a whole lot of users of the skb-queue diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 71487b915d67..022d8894c11d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -70,13 +70,6 @@ static kmem_cache_t *skbuff_head_cache __read_mostly; static kmem_cache_t *skbuff_fclone_cache __read_mostly; -/* - * lockdep: lock class key used by skb_queue_head_init(): - */ -struct lock_class_key skb_queue_lock_key; - -EXPORT_SYMBOL(skb_queue_lock_key); - /* * Keep out-of-line to prevent kernel bloat. * __builtin_return_address is not used because it is not always -- cgit v1.2.3 From dc49c1f94e3469d94b952e8f5160dd4ccd791d79 Mon Sep 17 00:00:00 2001 From: Catherine Zhang Date: Wed, 2 Aug 2006 14:12:06 -0700 Subject: [AF_UNIX]: Kernel memory leak fix for af_unix datagram getpeersec patch From: Catherine Zhang This patch implements a cleaner fix for the memory leak problem of the original unix datagram getpeersec patch. Instead of creating a security context each time a unix datagram is sent, we only create the security context when the receiver requests it. This new design requires modification of the current unix_getsecpeer_dgram LSM hook and addition of two new hooks, namely, secid_to_secctx and release_secctx. The former retrieves the security context and the latter releases it. A hook is required for releasing the security context because it is up to the security module to decide how that's done. In the case of Selinux, it's a simple kfree operation. Acked-by: Stephen Smalley Signed-off-by: David S. Miller --- include/linux/security.h | 41 +++++++++++++++++++++++++++++++++++------ include/net/af_unix.h | 6 ++---- include/net/scm.h | 29 +++++++++++++++++++++++++---- net/ipv4/ip_sockglue.c | 9 +++++++-- net/unix/af_unix.c | 17 +++++------------ security/dummy.c | 14 ++++++++++++-- security/selinux/hooks.c | 38 ++++++++++++++++++++++++-------------- 7 files changed, 110 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index f75303831d09..aa5b8043dc38 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1109,6 +1109,16 @@ struct swap_info_struct; * @name contains the name of the security module being unstacked. * @ops contains a pointer to the struct security_operations of the module to unstack. * + * @secid_to_secctx: + * Convert secid to security context. + * @secid contains the security ID. + * @secdata contains the pointer that stores the converted security context. + * + * @release_secctx: + * Release the security context. + * @secdata contains the security context. + * @seclen contains the length of the security context. + * * This is the main security structure. */ struct security_operations { @@ -1289,6 +1299,8 @@ struct security_operations { int (*getprocattr)(struct task_struct *p, char *name, void *value, size_t size); int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size); + int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen); + void (*release_secctx)(char *secdata, u32 seclen); #ifdef CONFIG_SECURITY_NETWORK int (*unix_stream_connect) (struct socket * sock, @@ -1317,7 +1329,7 @@ struct security_operations { int (*socket_shutdown) (struct socket * sock, int how); int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb); int (*socket_getpeersec_stream) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len); - int (*socket_getpeersec_dgram) (struct sk_buff *skb, char **secdata, u32 *seclen); + int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid); int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority); void (*sk_free_security) (struct sock *sk); unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir); @@ -2059,6 +2071,16 @@ static inline int security_netlink_recv(struct sk_buff * skb, int cap) return security_ops->netlink_recv(skb, cap); } +static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return security_ops->secid_to_secctx(secid, secdata, seclen); +} + +static inline void security_release_secctx(char *secdata, u32 seclen) +{ + return security_ops->release_secctx(secdata, seclen); +} + /* prototypes */ extern int security_init (void); extern int register_security (struct security_operations *ops); @@ -2725,6 +2747,15 @@ static inline void securityfs_remove(struct dentry *dentry) { } +static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return -EOPNOTSUPP; +} + +static inline void security_release_secctx(char *secdata, u32 seclen) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_SECURITY */ #ifdef CONFIG_SECURITY_NETWORK @@ -2840,10 +2871,9 @@ static inline int security_socket_getpeersec_stream(struct socket *sock, char __ return security_ops->socket_getpeersec_stream(sock, optval, optlen, len); } -static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, - u32 *seclen) +static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { - return security_ops->socket_getpeersec_dgram(skb, secdata, seclen); + return security_ops->socket_getpeersec_dgram(sock, skb, secid); } static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority) @@ -2968,8 +2998,7 @@ static inline int security_socket_getpeersec_stream(struct socket *sock, char __ return -ENOPROTOOPT; } -static inline int security_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, - u32 *seclen) +static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { return -ENOPROTOOPT; } diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 2fec827c8801..c0398f5a8cb9 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -54,15 +54,13 @@ struct unix_skb_parms { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ #ifdef CONFIG_SECURITY_NETWORK - char *secdata; /* Security context */ - u32 seclen; /* Security length */ + u32 secid; /* Security ID */ #endif }; #define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb)) #define UNIXCREDS(skb) (&UNIXCB((skb)).creds) -#define UNIXSECDATA(skb) (&UNIXCB((skb)).secdata) -#define UNIXSECLEN(skb) (&UNIXCB((skb)).seclen) +#define UNIXSID(skb) (&UNIXCB((skb)).secid) #define unix_state_rlock(s) spin_lock(&unix_sk(s)->lock) #define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock) diff --git a/include/net/scm.h b/include/net/scm.h index 02daa097cdcd..5637d5e22d5f 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -3,6 +3,7 @@ #include #include +#include /* Well, we should have at least one descriptor open * to accept passed FDs 8) @@ -20,8 +21,7 @@ struct scm_cookie struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ #ifdef CONFIG_SECURITY_NETWORK - char *secdata; /* Security context */ - u32 seclen; /* Security length */ + u32 secid; /* Passed security ID */ #endif unsigned long seq; /* Connection seqno */ }; @@ -32,6 +32,16 @@ extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie extern void __scm_destroy(struct scm_cookie *scm); extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl); +#ifdef CONFIG_SECURITY_NETWORK +static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) +{ + security_socket_getpeersec_dgram(sock, NULL, &scm->secid); +} +#else +static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + static __inline__ void scm_destroy(struct scm_cookie *scm) { if (scm && scm->fp) @@ -47,6 +57,7 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, scm->creds.pid = p->tgid; scm->fp = NULL; scm->seq = 0; + unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) return 0; return __scm_send(sock, msg, scm); @@ -55,8 +66,18 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, #ifdef CONFIG_SECURITY_NETWORK static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) { - if (test_bit(SOCK_PASSSEC, &sock->flags) && scm->secdata != NULL) - put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scm->seclen, scm->secdata); + char *secdata; + u32 seclen; + int err; + + if (test_bit(SOCK_PASSSEC, &sock->flags)) { + err = security_secid_to_secctx(scm->secid, &secdata, &seclen); + + if (!err) { + put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata); + security_release_secctx(secdata, seclen); + } + } } #else static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 84f43a3c9098..2d05c4133d3e 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -112,14 +112,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) { char *secdata; - u32 seclen; + u32 seclen, secid; int err; - err = security_socket_getpeersec_dgram(skb, &secdata, &seclen); + err = security_socket_getpeersec_dgram(NULL, skb, &secid); + if (err) + return; + + err = security_secid_to_secctx(secid, &secdata, &seclen); if (err) return; put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata); + security_release_secctx(secdata, seclen); } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 6f2909279268..de6ec519272e 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -128,23 +128,17 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0); #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE) #ifdef CONFIG_SECURITY_NETWORK -static void unix_get_peersec_dgram(struct sk_buff *skb) +static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { - int err; - - err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb), - UNIXSECLEN(skb)); - if (err) - *(UNIXSECDATA(skb)) = NULL; + memcpy(UNIXSID(skb), &scm->secid, sizeof(u32)); } static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) { - scm->secdata = *UNIXSECDATA(skb); - scm->seclen = *UNIXSECLEN(skb); + scm->secid = *UNIXSID(skb); } #else -static inline void unix_get_peersec_dgram(struct sk_buff *skb) +static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) { } static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) @@ -1322,8 +1316,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); if (siocb->scm->fp) unix_attach_fds(siocb->scm, skb); - - unix_get_peersec_dgram(skb); + unix_get_secdata(siocb->scm, skb); skb->h.raw = skb->data; err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); diff --git a/security/dummy.c b/security/dummy.c index bbbfda70e131..58c6d399c844 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -791,8 +791,7 @@ static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optv return -ENOPROTOOPT; } -static int dummy_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, - u32 *seclen) +static int dummy_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { return -ENOPROTOOPT; } @@ -876,6 +875,15 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz return -EINVAL; } +static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return -EOPNOTSUPP; +} + +static void dummy_release_secctx(char *secdata, u32 seclen) +{ +} + #ifdef CONFIG_KEYS static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx, unsigned long flags) @@ -1028,6 +1036,8 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, d_instantiate); set_to_dummy_if_null(ops, getprocattr); set_to_dummy_if_null(ops, setprocattr); + set_to_dummy_if_null(ops, secid_to_secctx); + set_to_dummy_if_null(ops, release_secctx); #ifdef CONFIG_SECURITY_NETWORK set_to_dummy_if_null(ops, unix_stream_connect); set_to_dummy_if_null(ops, unix_may_send); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a91c961ba38b..5d1b8c733199 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3524,25 +3524,21 @@ out: return err; } -static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) +static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { + u32 peer_secid = SECSID_NULL; int err = 0; - u32 peer_sid; - if (skb->sk->sk_family == PF_UNIX) - selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket), - &peer_sid); - else - peer_sid = selinux_socket_getpeer_dgram(skb); - - if (peer_sid == SECSID_NULL) - return -EINVAL; + if (sock && (sock->sk->sk_family == PF_UNIX)) + selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); + else if (skb) + peer_secid = selinux_socket_getpeer_dgram(skb); - err = security_sid_to_context(peer_sid, secdata, seclen); - if (err) - return err; + if (peer_secid == SECSID_NULL) + err = -EINVAL; + *secid = peer_secid; - return 0; + return err; } static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) @@ -4407,6 +4403,17 @@ static int selinux_setprocattr(struct task_struct *p, return size; } +static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + return security_sid_to_context(secid, secdata, seclen); +} + +static void selinux_release_secctx(char *secdata, u32 seclen) +{ + if (secdata) + kfree(secdata); +} + #ifdef CONFIG_KEYS static int selinux_key_alloc(struct key *k, struct task_struct *tsk, @@ -4587,6 +4594,9 @@ static struct security_operations selinux_ops = { .getprocattr = selinux_getprocattr, .setprocattr = selinux_setprocattr, + .secid_to_secctx = selinux_secid_to_secctx, + .release_secctx = selinux_release_secctx, + .unix_stream_connect = selinux_socket_unix_stream_connect, .unix_may_send = selinux_socket_unix_may_send, -- cgit v1.2.3 From 95ce568812822931991a24147987c5c75c0ac5b0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 2 Aug 2006 14:37:06 -0700 Subject: [SECURITY]: Fix build with CONFIG_SECURITY disabled. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit include/linux/security.h: In function ‘security_release_secctx’: include/linux/security.h:2757: warning: ‘return’ with a value, in function returning void Signed-off-by: David S. Miller --- include/linux/security.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/security.h b/include/linux/security.h index aa5b8043dc38..6bc2aad494ff 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -2754,7 +2754,6 @@ static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *secle static inline void security_release_secctx(char *secdata, u32 seclen) { - return -EOPNOTSUPP; } #endif /* CONFIG_SECURITY */ -- cgit v1.2.3 From 3c332422f78159a0f5e4bc5f0ed8bbcbf51d9462 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 26 Jul 2006 13:59:23 +0100 Subject: usb-storage: Add US_FL_IGNORE_DEVICE flag; ignore ZyXEL G220F This patch adds a new unusual_devs flag for when usb-storage needs to ignore a device that it would otherwise claim. We need to ignore the ZyXEL G220F as it is a virtual CDROM drive which includes the windows driver for this USB-WLAN adapter. After the windows driver is installed on a windows system, it converts it into a WLAN adapter (by ejecting the virtual disc). The virtual CDROM is of no interest to Linux users. The zd1211rw driver will automatically perform the eject operation, we just need to ensure that usb-storage does not claim the device. Signed-off-by: Daniel Drake Signed-off-by: Matthew Dharm Signed-off-by: Phil Dibowitz Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 10 +++++++++- drivers/usb/storage/usb.c | 13 +++++++++++-- include/linux/usb_usual.h | 4 +++- 3 files changed, 23 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index a5ca449f6e64..ca6c56fba282 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1106,7 +1106,15 @@ UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff, "Optio S/S4", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), - + +/* This is a virtual windows driver CD, which the zd1211rw driver automatically + * converts into a WLAN device. */ +UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101, + "ZyXEL", + "G-220F USB-WLAN Install", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE ), + #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5ee19be52f65..8d7bdcb5924d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -483,7 +483,7 @@ static struct us_unusual_dev *find_unusual(const struct usb_device_id *id) } /* Get the unusual_devs entries and the string descriptors */ -static void get_device_info(struct us_data *us, const struct usb_device_id *id) +static int get_device_info(struct us_data *us, const struct usb_device_id *id) { struct usb_device *dev = us->pusb_dev; struct usb_interface_descriptor *idesc = @@ -500,6 +500,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) unusual_dev->useTransport; us->flags = USB_US_ORIG_FLAGS(id->driver_info); + if (us->flags & US_FL_IGNORE_DEVICE) { + printk(KERN_INFO USB_STORAGE "device ignored\n"); + return -ENODEV; + } + /* * This flag is only needed when we're in high-speed, so let's * disable it if we're in full-speed @@ -541,6 +546,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id) msgs[msg], UTS_RELEASE); } + + return 0; } /* Get the transport settings */ @@ -969,7 +976,9 @@ static int storage_probe(struct usb_interface *intf, * of the match from the usb_device_id table, so we can find the * corresponding entry in the private table. */ - get_device_info(us, id); + result = get_device_info(us, id); + if (result) + goto BadDevice; /* Get the transport, protocol, and pipe settings */ result = get_transport(us); diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index f38f43f20fae..e7fc5fed5b98 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -44,7 +44,9 @@ US_FLAG(NO_WP_DETECT, 0x00000200) \ /* Don't check for write-protect */ \ US_FLAG(MAX_SECTORS_64, 0x00000400) \ - /* Sets max_sectors to 64 */ + /* Sets max_sectors to 64 */ \ + US_FLAG(IGNORE_DEVICE, 0x00000800) \ + /* Don't claim device */ #define US_FLAG(name, value) US_FL_##name = value , enum { US_DO_ALL_FLAGS }; -- cgit v1.2.3 From 27fb4f0a7f00fda4044de44dcbe4d65b8359cc38 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Aug 2006 16:49:37 -0700 Subject: Revert "[PATCH] USB: convert usb class devices to real devices" This reverts bd00949647ddcea47ce4ea8bb2cfcfc98ebf9f2a commit because it required a newer version of udev to work properly than what is currently documented in Documentation/Changes. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/file.c | 13 +++++++------ include/linux/usb.h | 5 ++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index abee0f5b6a66..8de4f8c99d61 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -194,13 +194,14 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->usb_dev = device_create(usb_class->class, &intf->dev, - MKDEV(USB_MAJOR, minor), "%s", temp); - if (IS_ERR(intf->usb_dev)) { + intf->class_dev = class_device_create(usb_class->class, NULL, + MKDEV(USB_MAJOR, minor), + &intf->dev, "%s", temp); + if (IS_ERR(intf->class_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - retval = PTR_ERR(intf->usb_dev); + retval = PTR_ERR(intf->class_dev); } exit: return retval; @@ -241,8 +242,8 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); - intf->usb_dev = NULL; + class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); + intf->class_dev = NULL; intf->minor = -1; destroy_usb_class(); } diff --git a/include/linux/usb.h b/include/linux/usb.h index c944e8f06a4a..398c52f37679 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -103,8 +103,7 @@ enum usb_interface_condition { * @condition: binding state of the interface: not bound, binding * (in probe()), bound to a driver, or unbinding (in disconnect()) * @dev: driver model's view of this device - * @usb_dev: if an interface is bound to the USB major, this will point - * to the sysfs representation for that device. + * @class_dev: driver model's class view of this device. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -144,7 +143,7 @@ struct usb_interface { * bound to */ enum usb_interface_condition condition; /* state of binding */ struct device dev; /* interface specific device info */ - struct device *usb_dev; /* pointer to the usb class's device, if any */ + struct class_device *class_dev; }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ -- cgit v1.2.3 From cae74b30dd98c10baa5b47b4698bf67e5eb15687 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 2 Aug 2006 16:52:10 -0700 Subject: Revert "[PATCH] USB: move usb_device_class class devices to be real devices" This reverts c182274ffe1277f4e7c564719a696a37cacf74ea commit because it required a newer version of udev to work properly than what is currently documented in Documentation/Changes. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 20 ++++++++++---------- include/linux/usb.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index f7bdd94b3aa8..218621b9958e 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -517,19 +517,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig static struct usb_device *usbdev_lookup_minor(int minor) { - struct device *device; - struct usb_device *udev = NULL; + struct class_device *class_dev; + struct usb_device *dev = NULL; down(&usb_device_class->sem); - list_for_each_entry(device, &usb_device_class->devices, node) { - if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - udev = device->platform_data; + list_for_each_entry(class_dev, &usb_device_class->children, node) { + if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + dev = class_dev->class_data; break; } } up(&usb_device_class->sem); - return udev; + return dev; }; /* @@ -1580,16 +1580,16 @@ static void usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->usbfs_dev = device_create(usb_device_class, &dev->dev, - MKDEV(USB_DEVICE_MAJOR, minor), + dev->class_dev = class_device_create(usb_device_class, NULL, + MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); - dev->usbfs_dev->platform_data = dev; + dev->class_dev->class_data = dev; } static void usbdev_remove(struct usb_device *dev) { - device_unregister(dev->usbfs_dev); + class_device_unregister(dev->class_dev); } static int usbdev_notify(struct notifier_block *self, unsigned long action, diff --git a/include/linux/usb.h b/include/linux/usb.h index 398c52f37679..d2bd0c8e0154 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -360,7 +360,7 @@ struct usb_device { char *serial; /* iSerialNumber string, if present */ struct list_head filelist; - struct device *usbfs_dev; + struct class_device *class_dev; struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ /* -- cgit v1.2.3 From 3e2efce067cec0099f99ae59f28feda99b02b498 Mon Sep 17 00:00:00 2001 From: Amy Griffis Date: Thu, 13 Jul 2006 13:16:02 -0400 Subject: [PATCH] fix faulty inode data collection for open() with O_CREAT When the specified path is an existing file or when it is a symlink, audit collects the wrong inode number, which causes it to miss the open() event. Adding a second hook to the open() path fixes this. Also add audit_copy_inode() to consolidate some code. Signed-off-by: Amy Griffis Signed-off-by: Al Viro --- fs/namei.c | 2 ++ include/linux/audit.h | 7 ++++++ kernel/auditsc.c | 63 +++++++++++++++++++++++++++++++++------------------ 3 files changed, 50 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/fs/namei.c b/fs/namei.c index e01070d7bf58..47a7bad92d2a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1659,6 +1659,7 @@ do_last: * It already exists. */ mutex_unlock(&dir->d_inode->i_mutex); + audit_inode_update(path.dentry->d_inode); error = -EEXIST; if (flag & O_EXCL) @@ -1669,6 +1670,7 @@ do_last: if (flag & O_NOFOLLOW) goto exit_dput; } + error = -ENOENT; if (!path.dentry->d_inode) goto exit_dput; diff --git a/include/linux/audit.h b/include/linux/audit.h index b27d7debc5a1..e7e5e5348987 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -328,6 +328,7 @@ extern void audit_putname(const char *name); extern void __audit_inode(const char *name, const struct inode *inode); extern void __audit_inode_child(const char *dname, const struct inode *inode, unsigned long pino); +extern void __audit_inode_update(const struct inode *inode); static inline void audit_getname(const char *name) { if (unlikely(current->audit_context)) @@ -343,6 +344,10 @@ static inline void audit_inode_child(const char *dname, if (unlikely(current->audit_context)) __audit_inode_child(dname, inode, pino); } +static inline void audit_inode_update(const struct inode *inode) { + if (unlikely(current->audit_context)) + __audit_inode_update(inode); +} /* Private API (for audit.c only) */ extern unsigned int audit_serial(void); @@ -414,8 +419,10 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) #define audit_putname(n) do { ; } while (0) #define __audit_inode(n,i) do { ; } while (0) #define __audit_inode_child(d,i,p) do { ; } while (0) +#define __audit_inode_update(i) do { ; } while (0) #define audit_inode(n,i) do { ; } while (0) #define audit_inode_child(d,i,p) do { ; } while (0) +#define audit_inode_update(i) do { ; } while (0) #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) #define audit_get_loginuid(c) ({ -1; }) #define audit_ipc_obj(i) ({ 0; }) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index ae40ac8c39e7..b939ed2da3ee 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1199,14 +1199,18 @@ void audit_putname(const char *name) #endif } -static void audit_inode_context(int idx, const struct inode *inode) +/* Copy inode data into an audit_names. */ +static void audit_copy_inode(struct audit_names *name, const struct inode *inode) { - struct audit_context *context = current->audit_context; - - selinux_get_inode_sid(inode, &context->names[idx].osid); + name->ino = inode->i_ino; + name->dev = inode->i_sb->s_dev; + name->mode = inode->i_mode; + name->uid = inode->i_uid; + name->gid = inode->i_gid; + name->rdev = inode->i_rdev; + selinux_get_inode_sid(inode, &name->osid); } - /** * audit_inode - store the inode and device from a lookup * @name: name being audited @@ -1240,13 +1244,7 @@ void __audit_inode(const char *name, const struct inode *inode) ++context->ino_count; #endif } - context->names[idx].ino = inode->i_ino; - context->names[idx].dev = inode->i_sb->s_dev; - context->names[idx].mode = inode->i_mode; - context->names[idx].uid = inode->i_uid; - context->names[idx].gid = inode->i_gid; - context->names[idx].rdev = inode->i_rdev; - audit_inode_context(idx, inode); + audit_copy_inode(&context->names[idx], inode); } /** @@ -1302,16 +1300,37 @@ update_context: context->names[idx].name_len = AUDIT_NAME_FULL; context->names[idx].name_put = 0; /* don't call __putname() */ - if (inode) { - context->names[idx].ino = inode->i_ino; - context->names[idx].dev = inode->i_sb->s_dev; - context->names[idx].mode = inode->i_mode; - context->names[idx].uid = inode->i_uid; - context->names[idx].gid = inode->i_gid; - context->names[idx].rdev = inode->i_rdev; - audit_inode_context(idx, inode); - } else - context->names[idx].ino = (unsigned long)-1; + if (!inode) + context->names[idx].ino = (unsigned long)-1; + else + audit_copy_inode(&context->names[idx], inode); +} + +/** + * audit_inode_update - update inode info for last collected name + * @inode: inode being audited + * + * When open() is called on an existing object with the O_CREAT flag, the inode + * data audit initially collects is incorrect. This additional hook ensures + * audit has the inode data for the actual object to be opened. + */ +void __audit_inode_update(const struct inode *inode) +{ + struct audit_context *context = current->audit_context; + int idx; + + if (!context->in_syscall || !inode) + return; + + if (context->name_count == 0) { + context->name_count++; +#if AUDIT_DEBUG + context->ino_count++; +#endif + } + idx = context->name_count - 1; + + audit_copy_inode(&context->names[idx], inode); } /** -- cgit v1.2.3 From 73d3ec5abad3f1730ac8530899d2c14d92f3ad63 Mon Sep 17 00:00:00 2001 From: Amy Griffis Date: Thu, 13 Jul 2006 13:16:39 -0400 Subject: [PATCH] fix missed create event for directory audit When an object is created via a symlink into an audited directory, audit misses the event due to not having collected the inode data for the directory. Modify __audit_inode_child() to copy the parent inode data if a parent wasn't found in audit_names[]. Signed-off-by: Amy Griffis Signed-off-by: Al Viro --- fs/namei.c | 2 +- include/linux/audit.h | 8 ++++---- include/linux/fsnotify.h | 6 +++--- kernel/auditsc.c | 16 +++++++++++++--- 4 files changed, 21 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/namei.c b/fs/namei.c index 47a7bad92d2a..0ab26cbdacc0 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1357,7 +1357,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) return -ENOENT; BUG_ON(victim->d_parent->d_inode != dir); - audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino); + audit_inode_child(victim->d_name.name, victim->d_inode, dir); error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); if (error) diff --git a/include/linux/audit.h b/include/linux/audit.h index e7e5e5348987..bf196c05826c 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -327,7 +327,7 @@ extern void __audit_getname(const char *name); extern void audit_putname(const char *name); extern void __audit_inode(const char *name, const struct inode *inode); extern void __audit_inode_child(const char *dname, const struct inode *inode, - unsigned long pino); + const struct inode *parent); extern void __audit_inode_update(const struct inode *inode); static inline void audit_getname(const char *name) { @@ -339,10 +339,10 @@ static inline void audit_inode(const char *name, const struct inode *inode) { __audit_inode(name, inode); } static inline void audit_inode_child(const char *dname, - const struct inode *inode, - unsigned long pino) { + const struct inode *inode, + const struct inode *parent) { if (unlikely(current->audit_context)) - __audit_inode_child(dname, inode, pino); + __audit_inode_child(dname, inode, parent); } static inline void audit_inode_update(const struct inode *inode) { if (unlikely(current->audit_context)) diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index cc5dec70c32c..d4f219ffaa5d 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -67,7 +67,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, if (source) { inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); } - audit_inode_child(new_name, source, new_dir->i_ino); + audit_inode_child(new_name, source, new_dir); } /* @@ -98,7 +98,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) inode_dir_notify(inode, DN_CREATE); inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name, dentry->d_inode); - audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino); + audit_inode_child(dentry->d_name.name, dentry->d_inode, inode); } /* @@ -109,7 +109,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) inode_dir_notify(inode, DN_CREATE); inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, dentry->d_name.name, dentry->d_inode); - audit_inode_child(dentry->d_name.name, dentry->d_inode, inode->i_ino); + audit_inode_child(dentry->d_name.name, dentry->d_inode, inode); } /* diff --git a/kernel/auditsc.c b/kernel/auditsc.c index b939ed2da3ee..b1356fc63b26 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1251,7 +1251,7 @@ void __audit_inode(const char *name, const struct inode *inode) * audit_inode_child - collect inode info for created/removed objects * @dname: inode's dentry name * @inode: inode being audited - * @pino: inode number of dentry parent + * @parent: inode of dentry parent * * For syscalls that create or remove filesystem objects, audit_inode * can only collect information for the filesystem object's parent. @@ -1262,7 +1262,7 @@ void __audit_inode(const char *name, const struct inode *inode) * unsuccessful attempts. */ void __audit_inode_child(const char *dname, const struct inode *inode, - unsigned long pino) + const struct inode *parent) { int idx; struct audit_context *context = current->audit_context; @@ -1276,7 +1276,7 @@ void __audit_inode_child(const char *dname, const struct inode *inode, if (!dname) goto update_context; for (idx = 0; idx < context->name_count; idx++) - if (context->names[idx].ino == pino) { + if (context->names[idx].ino == parent->i_ino) { const char *name = context->names[idx].name; if (!name) @@ -1304,6 +1304,16 @@ update_context: context->names[idx].ino = (unsigned long)-1; else audit_copy_inode(&context->names[idx], inode); + + /* A parent was not found in audit_names, so copy the inode data for the + * provided parent. */ + if (!found_name) { + idx = context->name_count++; +#if AUDIT_DEBUG + context->ino_count++; +#endif + audit_copy_inode(&context->names[idx], parent); + } } /** -- cgit v1.2.3 From 471a5c7c839114cc8b55876203aeb2817c33e3c5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 10 Jul 2006 08:29:24 -0400 Subject: [PATCH] introduce audit rules counter Signed-off-by: Al Viro --- include/linux/audit.h | 2 ++ kernel/auditfilter.c | 24 ++++++++++++++++++++++++ kernel/auditsc.c | 3 +++ 3 files changed, 29 insertions(+) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index bf196c05826c..f1bfcff497bf 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -410,6 +410,7 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) return __audit_mq_getsetattr(mqdes, mqstat); return 0; } +extern int audit_n_rules; #else #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) @@ -437,6 +438,7 @@ static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) #define audit_mq_timedreceive(d,l,p,t) ({ 0; }) #define audit_mq_notify(d,n) ({ 0; }) #define audit_mq_getsetattr(d,s) ({ 0; }) +#define audit_n_rules 0 #endif #ifdef CONFIG_AUDIT diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 32420f914028..6a9a5c5a4e7d 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1136,6 +1136,14 @@ static inline int audit_add_rule(struct audit_entry *entry, struct audit_watch *watch = entry->rule.watch; struct nameidata *ndp, *ndw; int h, err, putnd_needed = 0; +#ifdef CONFIG_AUDITSYSCALL + int dont_count = 0; + + /* If either of these, don't count towards total */ + if (entry->rule.listnr == AUDIT_FILTER_USER || + entry->rule.listnr == AUDIT_FILTER_TYPE) + dont_count = 1; +#endif if (inode_f) { h = audit_hash_ino(inode_f->val); @@ -1176,6 +1184,10 @@ static inline int audit_add_rule(struct audit_entry *entry, } else { list_add_tail_rcu(&entry->list, list); } +#ifdef CONFIG_AUDITSYSCALL + if (!dont_count) + audit_n_rules++; +#endif mutex_unlock(&audit_filter_mutex); if (putnd_needed) @@ -1200,6 +1212,14 @@ static inline int audit_del_rule(struct audit_entry *entry, struct audit_watch *watch, *tmp_watch = entry->rule.watch; LIST_HEAD(inotify_list); int h, ret = 0; +#ifdef CONFIG_AUDITSYSCALL + int dont_count = 0; + + /* If either of these, don't count towards total */ + if (entry->rule.listnr == AUDIT_FILTER_USER || + entry->rule.listnr == AUDIT_FILTER_TYPE) + dont_count = 1; +#endif if (inode_f) { h = audit_hash_ino(inode_f->val); @@ -1237,6 +1257,10 @@ static inline int audit_del_rule(struct audit_entry *entry, list_del_rcu(&e->list); call_rcu(&e->rcu, audit_free_rule_rcu); +#ifdef CONFIG_AUDITSYSCALL + if (!dont_count) + audit_n_rules--; +#endif mutex_unlock(&audit_filter_mutex); if (!list_empty(&inotify_list)) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index b1356fc63b26..3ea836d3d941 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -85,6 +85,9 @@ extern int audit_enabled; /* Indicates that audit should log the full pathname. */ #define AUDIT_NAME_FULL -1 +/* number of audit rules */ +int audit_n_rules; + /* When fs/namei.c:getname() is called, we store the pointer in name and * we don't let putname() free it (instead we free all of the saved * pointers at syscall exit time). -- cgit v1.2.3 From d51374adf5f2f88155a072d3d801104e3c0c3d7f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 3 Aug 2006 10:59:26 -0400 Subject: [PATCH] mark context of syscall entered with no rules as dummy Signed-off-by: Al Viro --- include/linux/audit.h | 6 ++++++ kernel/auditsc.c | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/audit.h b/include/linux/audit.h index f1bfcff497bf..3f736d658218 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -329,6 +329,11 @@ extern void __audit_inode(const char *name, const struct inode *inode); extern void __audit_inode_child(const char *dname, const struct inode *inode, const struct inode *parent); extern void __audit_inode_update(const struct inode *inode); +static inline int audit_dummy_context(void) +{ + void *p = current->audit_context; + return !p || *(int *)p; +} static inline void audit_getname(const char *name) { if (unlikely(current->audit_context)) @@ -416,6 +421,7 @@ extern int audit_n_rules; #define audit_free(t) do { ; } while (0) #define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0) #define audit_syscall_exit(f,r) do { ; } while (0) +#define audit_dummy_context() 1 #define audit_getname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0) #define __audit_inode(n,i) do { ; } while (0) diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 3ea836d3d941..9618d1507251 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -177,6 +177,7 @@ struct audit_aux_data_path { /* The per-task audit context. */ struct audit_context { + int dummy; /* must be the first element */ int in_syscall; /* 1 if task is in a syscall */ enum audit_state state; unsigned int serial; /* serial number for record */ @@ -517,7 +518,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, context->return_valid = return_valid; context->return_code = return_code; - if (context->in_syscall && !context->auditable) { + if (context->in_syscall && !context->dummy && !context->auditable) { enum audit_state state; state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); @@ -1069,7 +1070,8 @@ void audit_syscall_entry(int arch, int major, context->argv[3] = a4; state = context->state; - if (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT) + context->dummy = !audit_n_rules; + if (!context->dummy && (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)) state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); if (likely(state == AUDIT_DISABLED)) return; -- cgit v1.2.3 From 5ac3a9c26c1cc4861d9cdd8b293fecbfcdc81afe Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Jul 2006 06:38:45 -0400 Subject: [PATCH] don't bother with aux entires for dummy context Signed-off-by: Al Viro --- fs/namei.c | 4 ++-- include/linux/audit.h | 22 +++++++++++----------- kernel/auditsc.c | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/fs/namei.c b/fs/namei.c index 0ab26cbdacc0..55a131230f94 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -159,7 +159,7 @@ char * getname(const char __user * filename) #ifdef CONFIG_AUDITSYSCALL void putname(const char *name) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) audit_putname(name); else __putname(name); @@ -1125,7 +1125,7 @@ static int fastcall do_path_lookup(int dfd, const char *name, retval = link_path_walk(name, nd); out: if (likely(retval == 0)) { - if (unlikely(current->audit_context && nd && nd->dentry && + if (unlikely(!audit_dummy_context() && nd && nd->dentry && nd->dentry->d_inode)) audit_inode(name, nd->dentry->d_inode); } diff --git a/include/linux/audit.h b/include/linux/audit.h index 3f736d658218..64f9f9e56ac5 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -336,21 +336,21 @@ static inline int audit_dummy_context(void) } static inline void audit_getname(const char *name) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) __audit_getname(name); } static inline void audit_inode(const char *name, const struct inode *inode) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) __audit_inode(name, inode); } static inline void audit_inode_child(const char *dname, const struct inode *inode, const struct inode *parent) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) __audit_inode_child(dname, inode, parent); } static inline void audit_inode_update(const struct inode *inode) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) __audit_inode_update(inode); } @@ -375,43 +375,43 @@ extern int __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); static inline int audit_ipc_obj(struct kern_ipc_perm *ipcp) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_ipc_obj(ipcp); return 0; } static inline int audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_ipc_set_perm(qbytes, uid, gid, mode); return 0; } static inline int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_mq_open(oflag, mode, u_attr); return 0; } static inline int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout); return 0; } static inline int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout); return 0; } static inline int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_mq_notify(mqdes, u_notification); return 0; } static inline int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) { - if (unlikely(current->audit_context)) + if (unlikely(!audit_dummy_context())) return __audit_mq_getsetattr(mqdes, mqstat); return 0; } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 9618d1507251..f571c7e925e6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1676,7 +1676,7 @@ int audit_bprm(struct linux_binprm *bprm) unsigned long p, next; void *to; - if (likely(!audit_enabled || !context)) + if (likely(!audit_enabled || !context || context->dummy)) return 0; ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p, @@ -1714,7 +1714,7 @@ int audit_socketcall(int nargs, unsigned long *args) struct audit_aux_data_socketcall *ax; struct audit_context *context = current->audit_context; - if (likely(!context)) + if (likely(!context || context->dummy)) return 0; ax = kmalloc(sizeof(*ax) + nargs * sizeof(unsigned long), GFP_KERNEL); @@ -1742,7 +1742,7 @@ int audit_sockaddr(int len, void *a) struct audit_aux_data_sockaddr *ax; struct audit_context *context = current->audit_context; - if (likely(!context)) + if (likely(!context || context->dummy)) return 0; ax = kmalloc(sizeof(*ax) + len, GFP_KERNEL); -- cgit v1.2.3 From 321311af25cbb65d3cc177e3777fedd526814ecc Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 31 Jul 2006 08:53:15 +0200 Subject: PCI: Unhide the SMBus on Asus PU-DLS Unhide the SMBus controller on the Asus PU-DLS board. This fixes bug #6763. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 7 +++++++ include/linux/pci_ids.h | 1 + 2 files changed, 8 insertions(+) (limited to 'include/linux') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e3c78c39b7e4..fb08bc951ac0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -990,6 +990,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x8070: /* P4G8X Deluxe */ asus_hides_smbus = 1; } + if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH) + switch (dev->subsystem_device) { + case 0x80c9: /* PU-DLS */ + asus_hides_smbus = 1; + } if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ @@ -1058,6 +1063,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asu DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge ); @@ -1081,6 +1087,7 @@ static void __init asus_hides_smbus_lpc(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c09396d2c77b..4eae06b08cf2 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2142,6 +2142,7 @@ #define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501 #define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 #define PCI_DEVICE_ID_INTEL_82860_HB 0x2531 +#define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c #define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 #define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 #define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 -- cgit v1.2.3 From 5669021e40964303994a20633548732c6bb26636 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 1 Aug 2006 14:59:19 -0700 Subject: PCI: docking station: remove dock uevents Remove uevent dock notifications. There are no consumers of these events at present, and uevents are likely not the correct way to send this type of event anyway. Until I get some kind of idea if anyone in userspace cares about dock events, I will just not send any. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/dock.c | 13 ++++++------- include/linux/kobject.h | 2 -- lib/kobject_uevent.c | 4 ---- 3 files changed, 6 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 1c0a39d8b04e..578b99b71d9c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -58,8 +58,8 @@ struct dock_dependent_device { }; #define DOCK_DOCKING 0x00000001 -#define DOCK_EVENT KOBJ_DOCK -#define UNDOCK_EVENT KOBJ_UNDOCK +#define DOCK_EVENT 3 +#define UNDOCK_EVENT 2 static struct dock_station *dock_station; @@ -322,11 +322,10 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) static void dock_event(struct dock_station *ds, u32 event, int num) { - struct acpi_device *device; - - device = dock_create_acpi_device(ds->handle); - if (device) - kobject_uevent(&device->kobj, num); + /* + * we don't do events until someone tells me that + * they would like to have them. + */ } /** diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 0503b2ed8bae..2d229327959e 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -46,8 +46,6 @@ enum kobject_action { KOBJ_UMOUNT = (__force kobject_action_t) 0x05, /* umount event for block devices (broken) */ KOBJ_OFFLINE = (__force kobject_action_t) 0x06, /* device offline */ KOBJ_ONLINE = (__force kobject_action_t) 0x07, /* device online */ - KOBJ_UNDOCK = (__force kobject_action_t) 0x08, /* undocking */ - KOBJ_DOCK = (__force kobject_action_t) 0x09, /* dock */ }; struct kobject { diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 2b1530fc573b..7f20e7b857cb 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -50,10 +50,6 @@ static char *action_to_string(enum kobject_action action) return "offline"; case KOBJ_ONLINE: return "online"; - case KOBJ_DOCK: - return "dock"; - case KOBJ_UNDOCK: - return "undock"; default: return NULL; } -- cgit v1.2.3 From e4e20512cfe0bacec0764b4925889d1fa94644f9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 3 Aug 2006 15:07:47 -0400 Subject: NFS: make 2 functions static nfs_writedata_free() and nfs_readdata_free() can now become static. Signed-off-by: Adrian Bunk Cc: Trond Myklebust Signed-off-by: Andrew Morton Signed-off-by: Trond Myklebust (cherry picked from 5e1ce40f0c3c8f67591aff17756930d7a18ceb1a commit) --- fs/nfs/read.c | 2 +- fs/nfs/write.c | 2 +- include/linux/nfs_fs.h | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 52bf634260a1..65c0c5b32351 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -63,7 +63,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) return p; } -void nfs_readdata_free(struct nfs_read_data *p) +static void nfs_readdata_free(struct nfs_read_data *p) { if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 86bac6a5008e..50774991f8d5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -137,7 +137,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) return p; } -void nfs_writedata_free(struct nfs_write_data *p) +static void nfs_writedata_free(struct nfs_write_data *p) { if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 55ea853d57bc..247434553ae8 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -476,10 +476,9 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page) } /* - * Allocate and free nfs_write_data structures + * Allocate nfs_write_data structures */ extern struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount); -extern void nfs_writedata_free(struct nfs_write_data *p); /* * linux/fs/nfs/read.c @@ -491,10 +490,9 @@ extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); extern void nfs_readdata_release(void *data); /* - * Allocate and free nfs_read_data structures + * Allocate nfs_read_data structures */ extern struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount); -extern void nfs_readdata_free(struct nfs_read_data *p); /* * linux/fs/nfs3proc.c -- cgit v1.2.3 From f3d43c769d14b7065da7f62ec468b1fcb8cd6e06 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 3 Aug 2006 15:07:47 -0400 Subject: NLM/lockd: remove b_done We never actually set the b_done field any more; it's always zero. Signed-off-by: J. Bruce Fields Signed-off-by: Trond Myklebust (cherry picked from af8412d4283ef91356e65e0ed9b025b376aebded commit) --- fs/lockd/svclock.c | 12 +++--------- include/linux/lockd/lockd.h | 1 - 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index baf5ae513481..c9d419703cf3 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -638,9 +638,6 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data) if (task->tk_status < 0) { /* RPC error: Re-insert for retransmission */ timeout = 10 * HZ; - } else if (block->b_done) { - /* Block already removed, kill it for real */ - timeout = 0; } else { /* Call was successful, now wait for client callback */ timeout = 60 * HZ; @@ -709,13 +706,10 @@ nlmsvc_retry_blocked(void) break; if (time_after(block->b_when,jiffies)) break; - dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", - block, block->b_when, block->b_done); + dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", + block, block->b_when); kref_get(&block->b_count); - if (block->b_done) - nlmsvc_unlink_block(block); - else - nlmsvc_grant_blocked(block); + nlmsvc_grant_blocked(block); nlmsvc_release_block(block); } diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index aa4fe905bb4d..0d92c468d55a 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h @@ -123,7 +123,6 @@ struct nlm_block { unsigned int b_id; /* block id */ unsigned char b_queued; /* re-queued */ unsigned char b_granted; /* VFS granted lock */ - unsigned char b_done; /* callback complete */ struct nlm_file * b_file; /* file in question */ }; -- cgit v1.2.3 From e0ab53deaa91293a7958d63d5a2cf4c5645ad6f0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Jul 2006 17:22:50 -0400 Subject: RPC: Ensure that we disconnect TCP socket when client requests error out If we're part way through transmitting a TCP request, and the client errors, then we need to disconnect and reconnect the TCP socket in order to avoid confusing the server. Signed-off-by: Trond Myklebust (cherry picked from 031a50c8b9ea82616abd4a4e18021a25848941ce commit) --- include/linux/sunrpc/xprt.h | 2 +- net/sunrpc/clnt.c | 52 +++++++++++++++++++++++++-------------------- net/sunrpc/xprt.c | 21 +++--------------- net/sunrpc/xprtsock.c | 29 ++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 43 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index e8bbe8118de8..840e47a4ccc5 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -229,7 +229,7 @@ int xprt_reserve_xprt(struct rpc_task *task); int xprt_reserve_xprt_cong(struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); -void xprt_abort_transmit(struct rpc_task *task); +void xprt_end_transmit(struct rpc_task *task); int xprt_adjust_timeout(struct rpc_rqst *req); void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4ba271f892c8..d6409e757219 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -921,26 +921,43 @@ call_transmit(struct rpc_task *task) task->tk_status = xprt_prepare_transmit(task); if (task->tk_status != 0) return; + task->tk_action = call_transmit_status; /* Encode here so that rpcsec_gss can use correct sequence number. */ if (rpc_task_need_encode(task)) { - task->tk_rqstp->rq_bytes_sent = 0; + BUG_ON(task->tk_rqstp->rq_bytes_sent != 0); call_encode(task); /* Did the encode result in an error condition? */ if (task->tk_status != 0) - goto out_nosend; + return; } - task->tk_action = call_transmit_status; xprt_transmit(task); if (task->tk_status < 0) return; - if (!task->tk_msg.rpc_proc->p_decode) { - task->tk_action = rpc_exit_task; - rpc_wake_up_task(task); - } - return; -out_nosend: - /* release socket write lock before attempting to handle error */ - xprt_abort_transmit(task); + /* + * On success, ensure that we call xprt_end_transmit() before sleeping + * in order to allow access to the socket to other RPC requests. + */ + call_transmit_status(task); + if (task->tk_msg.rpc_proc->p_decode != NULL) + return; + task->tk_action = rpc_exit_task; + rpc_wake_up_task(task); +} + +/* + * 5a. Handle cleanup after a transmission + */ +static void +call_transmit_status(struct rpc_task *task) +{ + task->tk_action = call_status; + /* + * Special case: if we've been waiting on the socket's write_space() + * callback, then don't call xprt_end_transmit(). + */ + if (task->tk_status == -EAGAIN) + return; + xprt_end_transmit(task); rpc_task_force_reencode(task); } @@ -992,18 +1009,7 @@ call_status(struct rpc_task *task) } /* - * 6a. Handle transmission errors. - */ -static void -call_transmit_status(struct rpc_task *task) -{ - if (task->tk_status != -EAGAIN) - rpc_task_force_reencode(task); - call_status(task); -} - -/* - * 6b. Handle RPC timeout + * 6a. Handle RPC timeout * We do not release the request slot, so we keep using the * same XID for all retransmits. */ diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 313b68d892c6..e8c2bc4977f3 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -707,12 +707,9 @@ out_unlock: return err; } -void -xprt_abort_transmit(struct rpc_task *task) +void xprt_end_transmit(struct rpc_task *task) { - struct rpc_xprt *xprt = task->tk_xprt; - - xprt_release_write(xprt, task); + xprt_release_write(task->tk_xprt, task); } /** @@ -761,8 +758,6 @@ void xprt_transmit(struct rpc_task *task) task->tk_status = -ENOTCONN; else if (!req->rq_received) rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); - - xprt->ops->release_xprt(xprt, task); spin_unlock_bh(&xprt->transport_lock); return; } @@ -772,18 +767,8 @@ void xprt_transmit(struct rpc_task *task) * schedq, and being picked up by a parallel run of rpciod(). */ task->tk_status = status; - - switch (status) { - case -ECONNREFUSED: + if (status == -ECONNREFUSED) rpc_sleep_on(&xprt->sending, task, NULL, NULL); - case -EAGAIN: - case -ENOTCONN: - return; - default: - break; - } - xprt_release_write(xprt, task); - return; } static inline void do_xprt_reserve(struct rpc_task *task) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index ee678ed13b6f..441bd53f5eca 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -413,6 +413,33 @@ static int xs_tcp_send_request(struct rpc_task *task) return status; } +/** + * xs_tcp_release_xprt - clean up after a tcp transmission + * @xprt: transport + * @task: rpc task + * + * This cleans up if an error causes us to abort the transmission of a request. + * In this case, the socket may need to be reset in order to avoid confusing + * the server. + */ +static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) +{ + struct rpc_rqst *req; + + if (task != xprt->snd_task) + return; + if (task == NULL) + goto out_release; + req = task->tk_rqstp; + if (req->rq_bytes_sent == 0) + goto out_release; + if (req->rq_bytes_sent == req->rq_snd_buf.len) + goto out_release; + set_bit(XPRT_CLOSE_WAIT, &task->tk_xprt->state); +out_release: + xprt_release_xprt(xprt, task); +} + /** * xs_close - close a socket * @xprt: transport @@ -1250,7 +1277,7 @@ static struct rpc_xprt_ops xs_udp_ops = { static struct rpc_xprt_ops xs_tcp_ops = { .reserve_xprt = xprt_reserve_xprt, - .release_xprt = xprt_release_xprt, + .release_xprt = xs_tcp_release_xprt, .set_port = xs_set_port, .connect = xs_connect, .buf_alloc = rpc_malloc, -- cgit v1.2.3 From a7ef7878ea7c8bca9b624db3f61223cdadda2a0a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 5 Aug 2006 12:13:42 -0700 Subject: [PATCH] Make suspend possible with a traced process at a breakpoint It should be possible to suspend, either to RAM or to disk, if there's a traced process that has just reached a breakpoint. However, this is a special case, because its parent process might have been frozen already and then we are unable to deliver the "freeze" signal to the traced process. If this happens, it's better to cancel the freezing of the traced process. Ref. http://bugzilla.kernel.org/show_bug.cgi?id=6787 Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 8 ++++++++ kernel/power/process.c | 26 ++++++++++++++++++-------- 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6afa72e080cb..6674fc1e51bf 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1557,6 +1557,14 @@ static inline void freeze(struct task_struct *p) p->flags |= PF_FREEZE; } +/* + * Sometimes we may need to cancel the previous 'freeze' request + */ +static inline void do_not_freeze(struct task_struct *p) +{ + p->flags &= ~PF_FREEZE; +} + /* * Wake up a frozen process */ diff --git a/kernel/power/process.c b/kernel/power/process.c index b2a5f671d6cd..72e72d2c61e6 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -66,13 +66,25 @@ static inline void freeze_process(struct task_struct *p) } } +static void cancel_freezing(struct task_struct *p) +{ + unsigned long flags; + + if (freezing(p)) { + pr_debug(" clean up: %s\n", p->comm); + do_not_freeze(p); + spin_lock_irqsave(&p->sighand->siglock, flags); + recalc_sigpending_tsk(p); + spin_unlock_irqrestore(&p->sighand->siglock, flags); + } +} + /* 0 = success, else # of processes that we failed to stop */ int freeze_processes(void) { int todo, nr_user, user_frozen; unsigned long start_time; struct task_struct *g, *p; - unsigned long flags; printk( "Stopping tasks: " ); start_time = jiffies; @@ -85,6 +97,10 @@ int freeze_processes(void) continue; if (frozen(p)) continue; + if (p->state == TASK_TRACED && frozen(p->parent)) { + cancel_freezing(p); + continue; + } if (p->mm && !(p->flags & PF_BORROWED_MM)) { /* The task is a user-space one. * Freeze it unless there's a vfork completion @@ -126,13 +142,7 @@ int freeze_processes(void) do_each_thread(g, p) { if (freezeable(p) && !frozen(p)) printk(KERN_ERR " %s\n", p->comm); - if (freezing(p)) { - pr_debug(" clean up: %s\n", p->comm); - p->flags &= ~PF_FREEZE; - spin_lock_irqsave(&p->sighand->siglock, flags); - recalc_sigpending_tsk(p); - spin_unlock_irqrestore(&p->sighand->siglock, flags); - } + cancel_freezing(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); return todo; -- cgit v1.2.3 From 38cbcdc0a7be69a15462dc49512d43353f34b43b Mon Sep 17 00:00:00 2001 From: Jan Blunck Date: Sat, 5 Aug 2006 12:14:14 -0700 Subject: [PATCH] fix vmstat per cpu usage The per cpu variables are used incorrectly in vmstat.h. Signed-off-by: Jan Blunck Cc: Christoph Lameter Acked-by: Steve Fox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmstat.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index 1ab806c47514..2d9b1b60798a 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -41,23 +41,23 @@ DECLARE_PER_CPU(struct vm_event_state, vm_event_states); static inline void __count_vm_event(enum vm_event_item item) { - __get_cpu_var(vm_event_states.event[item])++; + __get_cpu_var(vm_event_states).event[item]++; } static inline void count_vm_event(enum vm_event_item item) { - get_cpu_var(vm_event_states.event[item])++; + get_cpu_var(vm_event_states).event[item]++; put_cpu(); } static inline void __count_vm_events(enum vm_event_item item, long delta) { - __get_cpu_var(vm_event_states.event[item]) += delta; + __get_cpu_var(vm_event_states).event[item] += delta; } static inline void count_vm_events(enum vm_event_item item, long delta) { - get_cpu_var(vm_event_states.event[item]) += delta; + get_cpu_var(vm_event_states).event[item] += delta; put_cpu(); } -- cgit v1.2.3 From 9b7f750d446a717d4c8346fbb165b62661019b92 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 5 Aug 2006 12:14:27 -0700 Subject: [PATCH] debug_locks.h: add "struct task_struct;" Removes many, many "declared inside parameter list" warnings on parisc. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/debug_locks.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 6a7047851e48..88dafa246d87 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h @@ -1,6 +1,8 @@ #ifndef __LINUX_DEBUG_LOCKING_H #define __LINUX_DEBUG_LOCKING_H +struct task_struct; + extern int debug_locks; extern int debug_locks_silent; -- cgit v1.2.3