From 954032d2527f2fce7355ba70709b5e143d6b686f Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 24 Mar 2011 22:51:14 -0400 Subject: nfsd: fix auth_domain reference leak on nlm operations This was noticed by users who performed more than 2^32 lock operations and hence made this counter overflow (eventually leading to use-after-free's). Setting rq_client to NULL here means that it won't later get auth_domain_put() when it should be. Appears to have been introduced in 2.5.42 by "[PATCH] kNFSd: Move auth domain lookup into svcauth" which moved most of the rq_client handling to common svcauth code, but left behind this one line. Cc: Neil Brown Cc: stable@kernel.org Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 0c6d816..7c831a2 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -38,7 +38,6 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) exp_readlock(); nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); fh_put(&fh); - rqstp->rq_client = NULL; exp_readunlock(); /* We return nlm error codes as nlm doesn't know * about nfsd, but nfsd does know about nlm.. -- cgit v0.10.2 From 361ae8cb57ec35ace2fa5f9695dba14eca9893e0 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Wed, 30 Mar 2011 21:14:26 +0200 Subject: xen: events: fix error checks in bind_*_to_irqhandler() Checking 'irq < 0' doesn't work when 'irq' is unsigned. The assigned bind_evtchn_to_irq() and bind_virq_to_irq() return int, so using int appears appropriate. Signed-off-by: Nicolas Kaiser Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 036343b..589f0a5 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -912,8 +912,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn, unsigned long irqflags, const char *devname, void *dev_id) { - unsigned int irq; - int retval; + int irq, retval; irq = bind_evtchn_to_irq(evtchn); if (irq < 0) @@ -955,8 +954,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) { - unsigned int irq; - int retval; + int irq, retval; irq = bind_virq_to_irq(virq, cpu); if (irq < 0) -- cgit v0.10.2 From 272df502bcd1fbb1b95facc92bd861d604be8871 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 31 Mar 2011 07:18:46 +0900 Subject: gpio/pca953x: fix error handling path in probe() call If the device fails to respond, then the error path tries to remove an interrupt that never got registered, which causes an backtrace from the interrupt handling code. Fix this by ensuring that the cleanup path has two labels and use the correct path as needed. fixes the following error: WARNING: at kernel/irq/manage.c:908 __free_irq+0x80/0x160() Trying to free already-free IRQ 0 Signed-off-by: Ben Dooks Signed-off-by: Mark Brown Signed-off-by: Grant Likely diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 583e925..7630ab7 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -558,7 +558,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, ret = gpiochip_add(&chip->gpio_chip); if (ret) - goto out_failed; + goto out_failed_irq; if (pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -570,8 +570,9 @@ static int __devinit pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; -out_failed: +out_failed_irq: pca953x_irq_teardown(chip); +out_failed: kfree(chip->dyn_pdata); kfree(chip); return ret; -- cgit v0.10.2 From 89b3600ccfb01aed6873bc499442fc0bed00bbdd Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 29 Mar 2011 07:09:20 +0000 Subject: xfs: fix unreferenced var error in xfs_buf.c Signed-off-by: Dave Chinner Signed-off-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 596bb2c..d917146 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -657,8 +657,6 @@ xfs_buf_readahead( xfs_off_t ioff, size_t isize) { - struct backing_dev_info *bdi; - if (bdi_read_congested(target->bt_bdi)) return; -- cgit v0.10.2 From ba43861277f1858472de4adfc0b28a047484da83 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Thu, 24 Mar 2011 18:17:14 -0500 Subject: gpio/ml_ioh_gpio: Fix output value of ioh_gpio_direction_output() The ioh_gpio_direction_output() function was missing a write to set the desired output value. The function would properly set the GPIO direction, but not the output value. The value would have to manually be set with a follow up call to ioh_gpio_set(). Add the missing write so that ioh_gpio_direction_output() sets both the GPIO direction and value. Signed-off-by: Peter Tyser Tested-by: Tomoya MORINAGA Signed-off-by: Grant Likely diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c index 7f6f01a..0a775f7 100644 --- a/drivers/gpio/ml_ioh_gpio.c +++ b/drivers/gpio/ml_ioh_gpio.c @@ -116,6 +116,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, reg_val |= (1 << nr); else reg_val &= ~(1 << nr); + iowrite32(reg_val, &chip->reg->regs[chip->ch].po); mutex_unlock(&chip->lock); -- cgit v0.10.2 From 88aab9341a315d81118be6b41c45e4fe32b94bc1 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Fri, 25 Mar 2011 10:04:00 -0500 Subject: gpio/pch_gpio: Fix output value of pch_gpio_direction_output() The pch_gpio_direction_output() function was missing a write to set the desired output value. The function would properly set the GPIO direction, but not the output value. The value would have to manually be set with a follow up call to pch_gpio_set(). Add the missing write so that pch_gpio_direction_output() sets both the GPIO direction and value. Signed-off-by: Peter Tyser Tested-by: Tomoya MORINAGA Signed-off-by: Grant Likely diff --git a/drivers/gpio/pch_gpio.c b/drivers/gpio/pch_gpio.c index 2c6af87..f970a5f 100644 --- a/drivers/gpio/pch_gpio.c +++ b/drivers/gpio/pch_gpio.c @@ -105,6 +105,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, reg_val |= (1 << nr); else reg_val &= ~(1 << nr); + iowrite32(reg_val, &chip->reg->po); mutex_unlock(&chip->lock); -- cgit v0.10.2 From bda1a730ab303609897a91c554542d28496d3684 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 30 Mar 2011 16:32:31 +0200 Subject: asus-laptop: remove removed features from feature-removal-schedule.txt commit 3b81cf9d558c57406b4ed9b0d2639113d1d428b6 removed those features. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 274b32d..492e81d 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -387,26 +387,6 @@ Who: Tejun Heo ---------------------------- -What: Support for lcd_switch and display_get in asus-laptop driver -When: March 2010 -Why: These two features use non-standard interfaces. There are the - only features that really need multiple path to guess what's - the right method name on a specific laptop. - - Removing them will allow to remove a lot of code an significantly - clean the drivers. - - This will affect the backlight code which won't be able to know - if the backlight is on or off. The platform display file will also be - write only (like the one in eeepc-laptop). - - This should'nt affect a lot of user because they usually know - when their display is on or off. - -Who: Corentin Chary - ----------------------------- - What: sysfs-class-rfkill state file When: Feb 2014 Files: net/rfkill/core.c -- cgit v0.10.2 From 58a9f397ac9288403d600b22b8472c0d164ee8cb Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 30 Mar 2011 16:32:32 +0200 Subject: asus-wmi: swap input name and phys Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index efc776c..832a3fd7 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -201,8 +201,8 @@ static int asus_wmi_input_init(struct asus_wmi *asus) if (!asus->inputdev) return -ENOMEM; - asus->inputdev->name = asus->driver->input_phys; - asus->inputdev->phys = asus->driver->input_name; + asus->inputdev->name = asus->driver->input_name; + asus->inputdev->phys = asus->driver->input_phys; asus->inputdev->id.bustype = BUS_HOST; asus->inputdev->dev.parent = &asus->platform_device->dev; -- cgit v0.10.2 From 9481472559b3ecd366390786628c2fb211d1477b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 30 Mar 2011 16:32:33 +0200 Subject: eeepc-wmi: add keys found on EeePC 1215T Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0ddc434..649dcad 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -67,9 +67,11 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x82, { KEY_CAMERA } }, { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, { KE_KEY, 0x88, { KEY_WLAN } }, + { KE_KEY, 0xbd, { KEY_CAMERA } }, { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ + { KE_KEY, 0xe8, { KEY_SCREENLOCK } }, { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, { KE_KEY, 0xec, { KEY_CAMERA_UP } }, -- cgit v0.10.2 From a0bcaee99df69b6d4d4dfd30bd40ac24b5ad3e22 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 30 Mar 2011 15:20:22 -0700 Subject: msi-laptop: fix config-dependent build error The msi-laptop driver uses input_*() and sparse_keymap_*() interfaces. It should depend on the INPUT subsystem being present and select INPUT_SPARSEKMAP so that those interfaces are present. ERROR: "input_free_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "input_register_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "sparse_keymap_setup" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "input_allocate_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "sparse_keymap_report_event" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "input_unregister_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "sparse_keymap_free" [drivers/platform/x86/msi-laptop.ko] undefined! Signed-off-by: Randy Dunlap Cc: Matthew Garrett Cc: "Lee, Chun-Yi" Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2ee442c..0485e39 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -187,7 +187,8 @@ config MSI_LAPTOP depends on ACPI depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL - depends on SERIO_I8042 + depends on INPUT && SERIO_I8042 + select INPUT_SPARSEKMAP ---help--- This is a driver for laptops built by MSI (MICRO-STAR INTERNATIONAL): -- cgit v0.10.2 From 512d06b5b64fb422d90f199b1be188082729edf9 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 4 Apr 2011 15:18:45 +0200 Subject: netfilter: ipset: list:set timeout variant fixes - the timeout value was actually not set - the garbage collector was broken The variant is fixed, the tests to the ipset testsuite are added. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index a47c329..f4a46c0 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -43,14 +43,19 @@ struct list_set { static inline struct set_elem * list_set_elem(const struct list_set *map, u32 id) { - return (struct set_elem *)((char *)map->members + id * map->dsize); + return (struct set_elem *)((void *)map->members + id * map->dsize); +} + +static inline struct set_telem * +list_set_telem(const struct list_set *map, u32 id) +{ + return (struct set_telem *)((void *)map->members + id * map->dsize); } static inline bool list_set_timeout(const struct list_set *map, u32 id) { - const struct set_telem *elem = - (const struct set_telem *) list_set_elem(map, id); + const struct set_telem *elem = list_set_telem(map, id); return ip_set_timeout_test(elem->timeout); } @@ -58,19 +63,11 @@ list_set_timeout(const struct list_set *map, u32 id) static inline bool list_set_expired(const struct list_set *map, u32 id) { - const struct set_telem *elem = - (const struct set_telem *) list_set_elem(map, id); + const struct set_telem *elem = list_set_telem(map, id); return ip_set_timeout_expired(elem->timeout); } -static inline int -list_set_exist(const struct set_telem *elem) -{ - return elem->id != IPSET_INVALID_ID && - !ip_set_timeout_expired(elem->timeout); -} - /* Set list without and with timeout */ static int @@ -146,11 +143,11 @@ list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id, struct set_telem *e; for (; i < map->size; i++) { - e = (struct set_telem *)list_set_elem(map, i); + e = list_set_telem(map, i); swap(e->id, id); + swap(e->timeout, timeout); if (e->id == IPSET_INVALID_ID) break; - swap(e->timeout, timeout); } } @@ -164,7 +161,7 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id, /* Last element replaced: e.g. add new,before,last */ ip_set_put_byindex(e->id); if (with_timeout(map->timeout)) - list_elem_tadd(map, i, id, timeout); + list_elem_tadd(map, i, id, ip_set_timeout_set(timeout)); else list_elem_add(map, i, id); @@ -172,11 +169,11 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id, } static int -list_set_del(struct list_set *map, ip_set_id_t id, u32 i) +list_set_del(struct list_set *map, u32 i) { struct set_elem *a = list_set_elem(map, i), *b; - ip_set_put_byindex(id); + ip_set_put_byindex(a->id); for (; i < map->size - 1; i++) { b = list_set_elem(map, i + 1); @@ -308,11 +305,11 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], (before == 0 || (before > 0 && next_id_eq(map, i, refid)))) - ret = list_set_del(map, id, i); + ret = list_set_del(map, i); else if (before < 0 && elem->id == refid && next_id_eq(map, i, id)) - ret = list_set_del(map, id, i + 1); + ret = list_set_del(map, i + 1); } break; default: @@ -460,17 +457,15 @@ list_set_gc(unsigned long ul_set) struct list_set *map = set->data; struct set_telem *e; u32 i; - - /* We run parallel with other readers (test element) - * but adding/deleting new entries is locked out */ - read_lock_bh(&set->lock); - for (i = map->size - 1; i >= 0; i--) { - e = (struct set_telem *) list_set_elem(map, i); - if (e->id != IPSET_INVALID_ID && - list_set_expired(map, i)) - list_set_del(map, e->id, i); + + /* nfnl_lock should be called */ + write_lock_bh(&set->lock); + for (i = 0; i < map->size; i++) { + e = list_set_telem(map, i); + if (e->id != IPSET_INVALID_ID && list_set_expired(map, i)) + list_set_del(map, i); } - read_unlock_bh(&set->lock); + write_unlock_bh(&set->lock); map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; add_timer(&map->gc); -- cgit v0.10.2 From 2f9f28b212a2bd4948c8ceaaec33ce0123632129 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 4 Apr 2011 15:19:25 +0200 Subject: netfilter: ipset: references are protected by rwlock instead of mutex The timeout variant of the list:set type must reference the member sets. However, its garbage collector runs at timer interrupt so the mutex protection of the references is a no go. Therefore the reference protection is converted to rwlock. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index ec333d8..5a262e3 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -293,7 +293,7 @@ struct ip_set { /* Lock protecting the set data */ rwlock_t lock; /* References to the set */ - atomic_t ref; + u32 ref; /* The core set type */ struct ip_set_type *type; /* The type variant doing the real job */ diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h index ec9d9be..a0196ac 100644 --- a/include/linux/netfilter/ipset/ip_set_ahash.h +++ b/include/linux/netfilter/ipset/ip_set_ahash.h @@ -515,8 +515,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb) if (h->netmask != HOST_MASK) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask); #endif - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)); if (with_timeout(h->timeout)) NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout)); diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index bca9699..a113ff0 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c @@ -338,8 +338,7 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb) NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); if (map->netmask != 32) NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->memsize)); if (with_timeout(map->timeout)) diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 5e79017..00a3324 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -434,8 +434,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb) goto nla_put_failure; NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + (map->last_ip - map->first_ip + 1) * map->dsize)); diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 165f09b..6b38eb8 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c @@ -320,8 +320,7 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb) goto nla_put_failure; NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port)); NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->memsize)); if (with_timeout(map->timeout)) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index d6b4823..e88ac3c 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -26,6 +26,7 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */ static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ +static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ static struct ip_set **ip_set_list; /* all individual sets */ static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ @@ -301,13 +302,18 @@ EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); static inline void __ip_set_get(ip_set_id_t index) { - atomic_inc(&ip_set_list[index]->ref); + write_lock_bh(&ip_set_ref_lock); + ip_set_list[index]->ref++; + write_unlock_bh(&ip_set_ref_lock); } static inline void __ip_set_put(ip_set_id_t index) { - atomic_dec(&ip_set_list[index]->ref); + write_lock_bh(&ip_set_ref_lock); + BUG_ON(ip_set_list[index]->ref == 0); + ip_set_list[index]->ref--; + write_unlock_bh(&ip_set_ref_lock); } /* @@ -324,7 +330,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, struct ip_set *set = ip_set_list[index]; int ret = 0; - BUG_ON(set == NULL || atomic_read(&set->ref) == 0); + BUG_ON(set == NULL); pr_debug("set %s, index %u\n", set->name, index); if (dim < set->type->dimension || @@ -356,7 +362,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, struct ip_set *set = ip_set_list[index]; int ret; - BUG_ON(set == NULL || atomic_read(&set->ref) == 0); + BUG_ON(set == NULL); pr_debug("set %s, index %u\n", set->name, index); if (dim < set->type->dimension || @@ -378,7 +384,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, struct ip_set *set = ip_set_list[index]; int ret = 0; - BUG_ON(set == NULL || atomic_read(&set->ref) == 0); + BUG_ON(set == NULL); pr_debug("set %s, index %u\n", set->name, index); if (dim < set->type->dimension || @@ -397,7 +403,6 @@ EXPORT_SYMBOL_GPL(ip_set_del); * Find set by name, reference it once. The reference makes sure the * thing pointed to, does not go away under our feet. * - * The nfnl mutex must already be activated. */ ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set) @@ -423,15 +428,12 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname); * reference count by 1. The caller shall not assume the index * to be valid, after calling this function. * - * The nfnl mutex must already be activated. */ void ip_set_put_byindex(ip_set_id_t index) { - if (ip_set_list[index] != NULL) { - BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0); + if (ip_set_list[index] != NULL) __ip_set_put(index); - } } EXPORT_SYMBOL_GPL(ip_set_put_byindex); @@ -441,7 +443,6 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex); * can't be destroyed. The set cannot be renamed due to * the referencing either. * - * The nfnl mutex must already be activated. */ const char * ip_set_name_byindex(ip_set_id_t index) @@ -449,7 +450,7 @@ ip_set_name_byindex(ip_set_id_t index) const struct ip_set *set = ip_set_list[index]; BUG_ON(set == NULL); - BUG_ON(atomic_read(&set->ref) == 0); + BUG_ON(set->ref == 0); /* Referenced, so it's safe */ return set->name; @@ -515,10 +516,7 @@ void ip_set_nfnl_put(ip_set_id_t index) { nfnl_lock(); - if (ip_set_list[index] != NULL) { - BUG_ON(atomic_read(&ip_set_list[index]->ref) == 0); - __ip_set_put(index); - } + ip_set_put_byindex(index); nfnl_unlock(); } EXPORT_SYMBOL_GPL(ip_set_nfnl_put); @@ -526,7 +524,7 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put); /* * Communication protocol with userspace over netlink. * - * We already locked by nfnl_lock. + * The commands are serialized by the nfnl mutex. */ static inline bool @@ -657,7 +655,6 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, return -ENOMEM; rwlock_init(&set->lock); strlcpy(set->name, name, IPSET_MAXNAMELEN); - atomic_set(&set->ref, 0); set->family = family; /* @@ -690,8 +687,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, /* * Here, we have a valid, constructed set and we are protected - * by nfnl_lock. Find the first free index in ip_set_list and - * check clashing. + * by the nfnl mutex. Find the first free index in ip_set_list + * and check clashing. */ if ((ret = find_free_id(set->name, &index, &clash)) != 0) { /* If this is the same set and requested, ignore error */ @@ -751,31 +748,51 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, const struct nlattr * const attr[]) { ip_set_id_t i; + int ret = 0; if (unlikely(protocol_failed(attr))) return -IPSET_ERR_PROTOCOL; - /* References are protected by the nfnl mutex */ + /* Commands are serialized and references are + * protected by the ip_set_ref_lock. + * External systems (i.e. xt_set) must call + * ip_set_put|get_nfnl_* functions, that way we + * can safely check references here. + * + * list:set timer can only decrement the reference + * counter, so if it's already zero, we can proceed + * without holding the lock. + */ + read_lock_bh(&ip_set_ref_lock); if (!attr[IPSET_ATTR_SETNAME]) { for (i = 0; i < ip_set_max; i++) { - if (ip_set_list[i] != NULL && - (atomic_read(&ip_set_list[i]->ref))) - return -IPSET_ERR_BUSY; + if (ip_set_list[i] != NULL && ip_set_list[i]->ref) { + ret = IPSET_ERR_BUSY; + goto out; + } } + read_unlock_bh(&ip_set_ref_lock); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL) ip_set_destroy_set(i); } } else { i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); - if (i == IPSET_INVALID_ID) - return -ENOENT; - else if (atomic_read(&ip_set_list[i]->ref)) - return -IPSET_ERR_BUSY; + if (i == IPSET_INVALID_ID) { + ret = -ENOENT; + goto out; + } else if (ip_set_list[i]->ref) { + ret = -IPSET_ERR_BUSY; + goto out; + } + read_unlock_bh(&ip_set_ref_lock); ip_set_destroy_set(i); } return 0; +out: + read_unlock_bh(&ip_set_ref_lock); + return ret; } /* Flush sets */ @@ -834,6 +851,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set; const char *name2; ip_set_id_t i; + int ret = 0; if (unlikely(protocol_failed(attr) || attr[IPSET_ATTR_SETNAME] == NULL || @@ -843,25 +861,33 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); if (set == NULL) return -ENOENT; - if (atomic_read(&set->ref) != 0) - return -IPSET_ERR_REFERENCED; + + read_lock_bh(&ip_set_ref_lock); + if (set->ref != 0) { + ret = -IPSET_ERR_REFERENCED; + goto out; + } name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); for (i = 0; i < ip_set_max; i++) { if (ip_set_list[i] != NULL && - STREQ(ip_set_list[i]->name, name2)) - return -IPSET_ERR_EXIST_SETNAME2; + STREQ(ip_set_list[i]->name, name2)) { + ret = -IPSET_ERR_EXIST_SETNAME2; + goto out; + } } strncpy(set->name, name2, IPSET_MAXNAMELEN); - return 0; +out: + read_unlock_bh(&ip_set_ref_lock); + return ret; } /* Swap two sets so that name/index points to the other. * References and set names are also swapped. * - * We are protected by the nfnl mutex and references are - * manipulated only by holding the mutex. The kernel interfaces + * The commands are serialized by the nfnl mutex and references are + * protected by the ip_set_ref_lock. The kernel interfaces * do not hold the mutex but the pointer settings are atomic * so the ip_set_list always contains valid pointers to the sets. */ @@ -874,7 +900,6 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, struct ip_set *from, *to; ip_set_id_t from_id, to_id; char from_name[IPSET_MAXNAMELEN]; - u32 from_ref; if (unlikely(protocol_failed(attr) || attr[IPSET_ATTR_SETNAME] == NULL || @@ -899,17 +924,15 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, from->type->family == to->type->family)) return -IPSET_ERR_TYPE_MISMATCH; - /* No magic here: ref munging protected by the nfnl_lock */ strncpy(from_name, from->name, IPSET_MAXNAMELEN); - from_ref = atomic_read(&from->ref); - strncpy(from->name, to->name, IPSET_MAXNAMELEN); - atomic_set(&from->ref, atomic_read(&to->ref)); strncpy(to->name, from_name, IPSET_MAXNAMELEN); - atomic_set(&to->ref, from_ref); + write_lock_bh(&ip_set_ref_lock); + swap(from->ref, to->ref); ip_set_list[from_id] = to; ip_set_list[to_id] = from; + write_unlock_bh(&ip_set_ref_lock); return 0; } @@ -926,7 +949,7 @@ ip_set_dump_done(struct netlink_callback *cb) { if (cb->args[2]) { pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name); - __ip_set_put((ip_set_id_t) cb->args[1]); + ip_set_put_byindex((ip_set_id_t) cb->args[1]); } return 0; } @@ -1068,7 +1091,7 @@ release_refcount: /* If there was an error or set is done, release set */ if (ret || !cb->args[2]) { pr_debug("release set %s\n", ip_set_list[index]->name); - __ip_set_put(index); + ip_set_put_byindex(index); } /* If we dump all sets, continue with dumping last ones */ diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index f4a46c0..e9159e9 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c @@ -366,8 +366,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb) NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size)); if (with_timeout(map->timeout)) NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); + NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->size * map->dsize)); ipset_nest_end(skb, nested); @@ -457,8 +456,7 @@ list_set_gc(unsigned long ul_set) struct list_set *map = set->data; struct set_telem *e; u32 i; - - /* nfnl_lock should be called */ + write_lock_bh(&set->lock); for (i = 0; i < map->size; i++) { e = list_set_telem(map, i); -- cgit v0.10.2 From b4232a22776aa5d063f890d21ca69870dbbe431b Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 4 Apr 2011 15:21:02 +0200 Subject: netfilter: h323: bug in parsing of ASN1 SEQOF field Static analyzer of clang found a dead store which appears to be a bug in reading count of items in SEQOF field, only the lower byte of word is stored. This may lead to corrupted read and communication shutdown. The bug has been in the module since it's first inclusion into linux kernel. [Patrick: the bug is real, but without practical consequence since the largest amount of sequence-of members we parse is 30.] Signed-off-by: David Sterba Signed-off-by: Patrick McHardy diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c index 8678823..bcd5ed6 100644 --- a/net/netfilter/nf_conntrack_h323_asn1.c +++ b/net/netfilter/nf_conntrack_h323_asn1.c @@ -631,7 +631,7 @@ static int decode_seqof(bitstr_t *bs, const struct field_t *f, CHECK_BOUND(bs, 2); count = *bs->cur++; count <<= 8; - count = *bs->cur++; + count += *bs->cur++; break; case SEMI: BYTE_ALIGN(bs); -- cgit v0.10.2 From a09d19779f3ffac6e16821accc2c1cc4df1b643a Mon Sep 17 00:00:00 2001 From: Hans Schillstrom Date: Mon, 4 Apr 2011 15:25:18 +0200 Subject: IPVS: fix NULL ptr dereference in ip_vs_ctl.c ip_vs_genl_dump_daemons() ipvsadm -ln --daemon will trigger a Null pointer exception because ip_vs_genl_dump_daemons() uses skb_net() instead of skb_sknet(). To prevent others from NULL ptr a check is made in ip_vs.h skb_net(). Signed-off-by: Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Patrick McHardy diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 30b49ed..4d1b71a 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -52,7 +52,7 @@ static inline struct net *skb_net(const struct sk_buff *skb) */ if (likely(skb->dev && skb->dev->nd_net)) return dev_net(skb->dev); - if (skb_dst(skb)->dev) + if (skb_dst(skb) && skb_dst(skb)->dev) return dev_net(skb_dst(skb)->dev); WARN(skb->sk, "Maybe skb_sknet should be used in %s() at line:%d\n", __func__, __LINE__); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 33733c8..ae47090 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3120,7 +3120,7 @@ nla_put_failure: static int ip_vs_genl_dump_daemons(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb_net(skb); + struct net *net = skb_sknet(skb); struct netns_ipvs *ipvs = net_ipvs(net); mutex_lock(&__ip_vs_mutex); -- cgit v0.10.2 From 31ad3dd64e689bc79dd819f8f134b9b025240eb8 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 4 Apr 2011 16:56:29 +0200 Subject: netfilter: af_info: add network namespace parameter to route hook This is required to eventually replace the rt6_lookup call in xt_addrtype.c with nf_afinfo->route(). Signed-off-by: Florian Westphal Acked-by: David S. Miller Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index eeec00a..20ed452 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -270,7 +270,8 @@ struct nf_afinfo { unsigned int dataoff, unsigned int len, u_int8_t protocol); - int (*route)(struct dst_entry **dst, struct flowi *fl); + int (*route)(struct net *net, struct dst_entry **dst, + struct flowi *fl); void (*saveroute)(const struct sk_buff *skb, struct nf_queue_entry *entry); int (*reroute)(struct sk_buff *skb, diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index f3c0b54..f1035f0 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -221,9 +221,10 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, return csum; } -static int nf_ip_route(struct dst_entry **dst, struct flowi *fl) +static int nf_ip_route(struct net *net, struct dst_entry **dst, + struct flowi *fl) { - struct rtable *rt = ip_route_output_key(&init_net, &fl->u.ip4); + struct rtable *rt = ip_route_output_key(net, &fl->u.ip4); if (IS_ERR(rt)) return PTR_ERR(rt); *dst = &rt->dst; diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 39aaca2..e008b9b 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -90,9 +90,10 @@ static int nf_ip6_reroute(struct sk_buff *skb, return 0; } -static int nf_ip6_route(struct dst_entry **dst, struct flowi *fl) +static int nf_ip6_route(struct net *net, struct dst_entry **dst, + struct flowi *fl) { - *dst = ip6_route_output(&init_net, NULL, &fl->u.ip6); + *dst = ip6_route_output(net, NULL, &fl->u.ip6); return (*dst)->error; } diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 533a183..39a4538 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -731,9 +731,9 @@ static int callforward_do_filter(const union nf_inet_addr *src, memset(&fl2, 0, sizeof(fl2)); fl2.daddr = dst->ip; - if (!afinfo->route((struct dst_entry **)&rt1, + if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, flowi4_to_flowi(&fl1))) { - if (!afinfo->route((struct dst_entry **)&rt2, + if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, flowi4_to_flowi(&fl2))) { if (rt1->rt_gateway == rt2->rt_gateway && rt1->dst.dev == rt2->dst.dev) @@ -755,9 +755,9 @@ static int callforward_do_filter(const union nf_inet_addr *src, memset(&fl2, 0, sizeof(fl2)); ipv6_addr_copy(&fl2.daddr, &dst->in6); - if (!afinfo->route((struct dst_entry **)&rt1, + if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, flowi6_to_flowi(&fl1))) { - if (!afinfo->route((struct dst_entry **)&rt2, + if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, flowi6_to_flowi(&fl2))) { if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway, sizeof(rt1->rt6i_gateway)) && diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 6e6b46c..8690125 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -166,7 +166,7 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb, rcu_read_lock(); ai = nf_get_afinfo(family); if (ai != NULL) - ai->route((struct dst_entry **)&rt, &fl); + ai->route(&init_net, (struct dst_entry **)&rt, &fl); rcu_read_unlock(); if (rt != NULL) { -- cgit v0.10.2 From 0fae2e7740aca7e384c5f337f458897e7e337d58 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 4 Apr 2011 17:00:54 +0200 Subject: netfilter: af_info: add 'strict' parameter to limit lookup to .oif ipv6 fib lookup can set RT6_LOOKUP_F_IFACE flag to restrict search to an interface, but this flag cannot be set via struct flowi. Also, it cannot be set via ip6_route_output: this function uses the passed sock struct to determine if this flag is required (by testing for nonzero sk_bound_dev_if). Work around this by passing in an artificial struct sk in case 'strict' argument is true. This is required to replace the rt6_lookup call in xt_addrtype.c with nf_afinfo->route(). Signed-off-by: Florian Westphal Acked-by: David S. Miller Signed-off-by: Patrick McHardy diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 20ed452..7fa95df 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -271,7 +271,7 @@ struct nf_afinfo { unsigned int len, u_int8_t protocol); int (*route)(struct net *net, struct dst_entry **dst, - struct flowi *fl); + struct flowi *fl, bool strict); void (*saveroute)(const struct sk_buff *skb, struct nf_queue_entry *entry); int (*reroute)(struct sk_buff *skb, diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index f1035f0..4614bab 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -222,7 +222,7 @@ static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, } static int nf_ip_route(struct net *net, struct dst_entry **dst, - struct flowi *fl) + struct flowi *fl, bool strict __always_unused) { struct rtable *rt = ip_route_output_key(net, &fl->u.ip4); if (IS_ERR(rt)) diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index e008b9b..28bc1f6 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -91,9 +91,17 @@ static int nf_ip6_reroute(struct sk_buff *skb, } static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl) + struct flowi *fl, bool strict) { - *dst = ip6_route_output(net, NULL, &fl->u.ip6); + static const struct ipv6_pinfo fake_pinfo; + static const struct inet_sock fake_sk = { + /* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */ + .sk.sk_bound_dev_if = 1, + .pinet6 = (struct ipv6_pinfo *) &fake_pinfo, + }; + const void *sk = strict ? &fake_sk : NULL; + + *dst = ip6_route_output(net, sk, &fl->u.ip6); return (*dst)->error; } diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 39a4538..18b2ce5 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -732,9 +732,9 @@ static int callforward_do_filter(const union nf_inet_addr *src, memset(&fl2, 0, sizeof(fl2)); fl2.daddr = dst->ip; if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, - flowi4_to_flowi(&fl1))) { + flowi4_to_flowi(&fl1), false)) { if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, - flowi4_to_flowi(&fl2))) { + flowi4_to_flowi(&fl2), false)) { if (rt1->rt_gateway == rt2->rt_gateway && rt1->dst.dev == rt2->dst.dev) ret = 1; @@ -756,9 +756,9 @@ static int callforward_do_filter(const union nf_inet_addr *src, memset(&fl2, 0, sizeof(fl2)); ipv6_addr_copy(&fl2.daddr, &dst->in6); if (!afinfo->route(&init_net, (struct dst_entry **)&rt1, - flowi6_to_flowi(&fl1))) { + flowi6_to_flowi(&fl1), false)) { if (!afinfo->route(&init_net, (struct dst_entry **)&rt2, - flowi6_to_flowi(&fl2))) { + flowi6_to_flowi(&fl2), false)) { if (!memcmp(&rt1->rt6i_gateway, &rt2->rt6i_gateway, sizeof(rt1->rt6i_gateway)) && rt1->dst.dev == rt2->dst.dev) diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 8690125..9e63b43 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -166,7 +166,7 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb, rcu_read_lock(); ai = nf_get_afinfo(family); if (ai != NULL) - ai->route(&init_net, (struct dst_entry **)&rt, &fl); + ai->route(&init_net, (struct dst_entry **)&rt, &fl, false); rcu_read_unlock(); if (rt != NULL) { -- cgit v0.10.2 From b7225041e93f81e7e38fcdf27fc82044e7695efd Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 4 Apr 2011 17:01:43 +0200 Subject: netfilter: xt_addrtype: replace rt6_lookup with nf_afinfo->route This avoids pulling in the ipv6 module when using (ipv4-only) iptables -m addrtype. Signed-off-by: Florian Westphal Acked-by: David S. Miller Signed-off-by: Patrick McHardy diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index c3f988a..32bff6d 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -652,7 +652,6 @@ comment "Xtables matches" config NETFILTER_XT_MATCH_ADDRTYPE tristate '"addrtype" address type match support' depends on NETFILTER_ADVANCED - depends on (IPV6 || IPV6=n) ---help--- This option allows you to match what routing thinks of an address, eg. UNICAST, LOCAL, BROADCAST, ... diff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c index 2220b85..b77d383 100644 --- a/net/netfilter/xt_addrtype.c +++ b/net/netfilter/xt_addrtype.c @@ -32,11 +32,32 @@ MODULE_ALIAS("ipt_addrtype"); MODULE_ALIAS("ip6t_addrtype"); #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) -static u32 xt_addrtype_rt6_to_type(const struct rt6_info *rt) +static u32 match_lookup_rt6(struct net *net, const struct net_device *dev, + const struct in6_addr *addr) { + const struct nf_afinfo *afinfo; + struct flowi6 flow; + struct rt6_info *rt; u32 ret; + int route_err; - if (!rt) + memset(&flow, 0, sizeof(flow)); + ipv6_addr_copy(&flow.daddr, addr); + if (dev) + flow.flowi6_oif = dev->ifindex; + + rcu_read_lock(); + + afinfo = nf_get_afinfo(NFPROTO_IPV6); + if (afinfo != NULL) + route_err = afinfo->route(net, (struct dst_entry **)&rt, + flowi6_to_flowi(&flow), !!dev); + else + route_err = 1; + + rcu_read_unlock(); + + if (route_err) return XT_ADDRTYPE_UNREACHABLE; if (rt->rt6i_flags & RTF_REJECT) @@ -48,6 +69,9 @@ static u32 xt_addrtype_rt6_to_type(const struct rt6_info *rt) ret |= XT_ADDRTYPE_LOCAL; if (rt->rt6i_flags & RTF_ANYCAST) ret |= XT_ADDRTYPE_ANYCAST; + + + dst_release(&rt->dst); return ret; } @@ -65,18 +89,8 @@ static bool match_type6(struct net *net, const struct net_device *dev, return false; if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST | - XT_ADDRTYPE_UNREACHABLE) & mask) { - struct rt6_info *rt; - u32 type; - int ifindex = dev ? dev->ifindex : 0; - - rt = rt6_lookup(net, addr, NULL, ifindex, !!dev); - - type = xt_addrtype_rt6_to_type(rt); - - dst_release(&rt->dst); - return !!(mask & type); - } + XT_ADDRTYPE_UNREACHABLE) & mask) + return !!(mask & match_lookup_rt6(net, dev, addr)); return true; } -- cgit v0.10.2 From 96120d86fe302c006259baee9061eea9e1b9e486 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 4 Apr 2011 17:06:21 +0200 Subject: netfilter: xt_conntrack: fix inverted conntrack direction test --ctdir ORIGINAL matches REPLY packets, and vv: userspace sets "invert_flags &= ~XT_CONNTRACK_DIRECTION" in ORIGINAL case. Thus: (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^ !!(info->invert_flags & XT_CONNTRACK_DIRECTION)) yields "1 ^ 0", which is true -> returns false. Reproducer: iptables -I OUTPUT 1 -p tcp --syn -m conntrack --ctdir ORIGINAL Signed-off-by: Florian Westphal Signed-off-by: Patrick McHardy diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 2c0086a..481a86f 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -195,7 +195,7 @@ conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par, return info->match_flags & XT_CONNTRACK_STATE; if ((info->match_flags & XT_CONNTRACK_DIRECTION) && (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^ - !!(info->invert_flags & XT_CONNTRACK_DIRECTION)) + !(info->invert_flags & XT_CONNTRACK_DIRECTION)) return false; if (info->match_flags & XT_CONNTRACK_ORIGSRC) -- cgit v0.10.2 From fef34861381eefe266c822fc28bdedc897a8265f Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 2 Apr 2011 19:00:44 +0900 Subject: sony-laptop: fix early NULL pointer dereference The SNC acpi driver could get early notifications before it fully initializes and that could lead to dereferencing the sony_nc_handles structure pointer that is still NULL at that stage. Make sure we return early from the handle lookup function in these cases. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index e642f5f..33c3b8c 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -808,6 +808,11 @@ static int sony_nc_handles_cleanup(struct platform_device *pd) static int sony_find_snc_handle(int handle) { int i; + + /* not initialized yet, return early */ + if (!handles) + return -1; + for (i = 0; i < 0x10; i++) { if (handles->cap[i] == handle) { dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", -- cgit v0.10.2 From 65d7ac038e34702feedad91d0bf597b1f0a4174a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 2 Apr 2011 21:23:36 +0200 Subject: platform-drivers: x86: pmic: Restore the dropped buslock/unlock When I added the buslock/unlock mechanism to the pmic code in order to get rid of the horrible work queue stuff, stupid me missed to add the new callbacks to the irq_chip. In consequence Andrew removed the unused functions, but I missed that. Add them back and hook them up proper. Signed-off-by: Thomas Gleixner Cc: Matthew Garrett Cc: Andrew Morton Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index d653104..7bbb538 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -74,6 +74,19 @@ struct pmic_gpio { u32 trigger_type; }; +static void pmic_program_irqtype(int gpio, int type) +{ + if (type & IRQ_TYPE_EDGE_RISING) + intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); + else + intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); + + if (type & IRQ_TYPE_EDGE_FALLING) + intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); + else + intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); +}; + static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { if (offset > 8) { @@ -166,16 +179,38 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return pg->irq_base + offset; } +static void pmic_bus_lock(struct irq_data *data) +{ + struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); + + mutex_lock(&pg->buslock); +} + +static void pmic_bus_sync_unlock(struct irq_data *data) +{ + struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); + + if (pg->update_type) { + unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE; + + pmic_program_irqtype(gpio, pg->trigger_type); + pg->update_type = 0; + } + mutex_unlock(&pg->buslock); +} + /* the gpiointr register is read-clear, so just do nothing. */ static void pmic_irq_unmask(struct irq_data *data) { } static void pmic_irq_mask(struct irq_data *data) { } static struct irq_chip pmic_irqchip = { - .name = "PMIC-GPIO", - .irq_mask = pmic_irq_mask, - .irq_unmask = pmic_irq_unmask, - .irq_set_type = pmic_irq_type, + .name = "PMIC-GPIO", + .irq_mask = pmic_irq_mask, + .irq_unmask = pmic_irq_unmask, + .irq_set_type = pmic_irq_type, + .irq_bus_lock = pmic_irq_buslock, + .irq_bus_sync_unlock = pmic_bus_sync_unlock, }; static irqreturn_t pmic_irq_handler(int irq, void *data) -- cgit v0.10.2 From 50f689af019b19f9b9a39be782c21b6f52b1615a Mon Sep 17 00:00:00 2001 From: Zhu Yanhai Date: Mon, 4 Apr 2011 12:58:12 -0400 Subject: jbd2: move bdget out of critical section bdget() should not be called when we hold spinlocks since it might sleep. Reviewed-by: Jan Kara Signed-off-by: Zhu Yanhai Signed-off-by: "Theodore Ts'o" diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 90407b8..33dd3ef 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -2413,10 +2413,12 @@ const char *jbd2_dev_to_name(dev_t device) new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL); if (!new_dev) return "NODEV-ALLOCFAILURE"; /* Something non-NULL */ + bd = bdget(device); spin_lock(&devname_cache_lock); if (devcache[i]) { if (devcache[i]->device == device) { kfree(new_dev); + bdput(bd); ret = devcache[i]->devname; spin_unlock(&devname_cache_lock); return ret; @@ -2425,7 +2427,6 @@ const char *jbd2_dev_to_name(dev_t device) } devcache[i] = new_dev; devcache[i]->device = device; - bd = bdget(device); if (bd) { bdevname(bd, devcache[i]->devname); bdput(bd); -- cgit v0.10.2 From d88885d0923ae27b01dfcec644f94829b1e46bea Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 4 Apr 2011 14:48:20 -0400 Subject: xen/debug: Don't be so verbose with WARN on 1-1 mapping errors. There are valid situations in which this error is not a warning. Mainly when QEMU maps a guest memory and uses the VM_IO flag to set the MFNs. For right now make the WARN be WARN_ONCE. In the future we will: 1). Remove the VM_IO code handling.. 2). .. which will also remove this debug facility. Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index c82df6c..a991b57 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -565,13 +565,13 @@ pte_t xen_make_pte_debug(pteval_t pte) if (io_page && (xen_initial_domain() || addr >= ISA_END_ADDRESS)) { other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT; - WARN(addr != other_addr, + WARN_ONCE(addr != other_addr, "0x%lx is using VM_IO, but it is 0x%lx!\n", (unsigned long)addr, (unsigned long)other_addr); } else { pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP; other_addr = (_pte.pte & PTE_PFN_MASK); - WARN((addr == other_addr) && (!io_page) && (!iomap_set), + WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set), "0x%lx is missing VM_IO (and wasn't fixed)!\n", (unsigned long)addr); } -- cgit v0.10.2 From c85ce65ecac078ab1a1835c87c4a6319cf74660a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 30 Mar 2011 14:02:46 -0400 Subject: b43: allocate receive buffers big enough for max frame len + offset Otherwise, skb_put inside of dma_rx can fail... https://bugzilla.kernel.org/show_bug.cgi?id=32042 Signed-off-by: John W. Linville Acked-by: Larry Finger Cc: stable@kernel.org diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 3d5566e..ff0f5ba 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1536,7 +1536,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) dmaaddr = meta->dmaaddr; goto drop_recycle_buffer; } - if (unlikely(len > ring->rx_buffersize)) { + if (unlikely(len + ring->frameoffset > ring->rx_buffersize)) { /* The data did not fit into one descriptor buffer * and is split over multiple buffers. * This should never happen, as we try to allocate buffers diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index a01c210..e8a80a1 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -163,7 +163,7 @@ struct b43_dmadesc_generic { /* DMA engine tuning knobs */ #define B43_TXRING_SLOTS 256 #define B43_RXRING_SLOTS 64 -#define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN +#define B43_DMA0_RX_BUFFERSIZE (B43_DMA0_RX_FRAMEOFFSET + IEEE80211_MAX_FRAME_LEN) /* Pointer poison */ #define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM)) -- cgit v0.10.2 From 5245e3a9f77a8dd4ea92d7bdab2e96629f1feda4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 30 Mar 2011 21:31:39 +0300 Subject: wl12xx: fix module author's email address in the spi and sdio modules The MODULE_AUTHOR() macro in the main module (wl12xx) has been updated to reflect one of the author's new email address, but the wl12xx_spi and wl12xx_sdio modules haven't been updated. This patches updates them. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 5b9dbea..b1c7d03 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -340,7 +340,7 @@ module_init(wl1271_init); module_exit(wl1271_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL1271_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 18cf017..ffc745b 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -487,7 +487,7 @@ module_init(wl1271_init); module_exit(wl1271_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL1271_AP_FW_NAME); -- cgit v0.10.2 From 8f06ca2c83689f4d352a34ef1c484f40c25b41ed Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 1 Apr 2011 17:16:33 +0530 Subject: ath9k: Fix phy info print message with AR9485 chipset. The phy information print during driver init time doesn't show the numeric part of the chip name properly for AR9485. This patch addresses this issue by adding the string to the respective array. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 338b075..1ec9bcd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2546,6 +2546,7 @@ static struct { { AR_SREV_VERSION_9287, "9287" }, { AR_SREV_VERSION_9271, "9271" }, { AR_SREV_VERSION_9300, "9300" }, + { AR_SREV_VERSION_9485, "9485" }, }; /* For devices with external radios */ -- cgit v0.10.2 From 5312c3f60ba49073081b2dc421f9f3c22dd43d99 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Apr 2011 13:52:34 +0200 Subject: mac80211: fix comment regarding aggregation buf_size The description for buf_size was misleading and just said you couldn't TX larger aggregates, but of course you can't TX aggregates in a way that would exceed the window either, which is possible even if the aggregates are shorter than that. Expand the description, thanks to Emmanuel for explaining this to me. Cc: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index cefe1b3..965f1b1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1753,8 +1753,19 @@ enum ieee80211_ampdu_mlme_action { * that TX/RX_STOP can pass NULL for this parameter. * The @buf_size parameter is only valid when the action is set to * %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder - * buffer size (number of subframes) for this session -- aggregates - * containing more subframes than this may not be transmitted to the peer. + * buffer size (number of subframes) for this session -- the driver + * may neither send aggregates containing more subframes than this + * nor send aggregates in a way that lost frames would exceed the + * buffer size. If just limiting the aggregate size, this would be + * possible with a buf_size of 8: + * - TX: 1.....7 + * - RX: 2....7 (lost frame #1) + * - TX: 8..1... + * which is invalid since #1 was now re-transmitted well past the + * buffer size of 8. Correct ways to retransmit #1 would be: + * - TX: 1 or 18 or 81 + * Even "189" would be wrong since 1 could be lost again. + * * Returns a negative error code on failure. * The callback can sleep. * -- cgit v0.10.2 From fcf8bd3ba5362682f945a3f838070ac5e10ff871 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Fri, 1 Apr 2011 15:46:05 +0200 Subject: mac80211: Fix duplicate frames on cooked monitor Cleaning the ieee80211_rx_data.flags field here is wrong, instead the flags should be valid accross processing the frame on different interfaces. Fix this by removing the incorrect flags=0 assignment. Introduced in commit 554891e63a29af35cc6bb403ef34e319518114d0 (mac80211: move packet flags into packet). Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index aa5cc37..2afeac9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2541,7 +2541,6 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx) * same TID from the same station */ rx->skb = skb; - rx->flags = 0; CALL_RXH(ieee80211_rx_h_decrypt) CALL_RXH(ieee80211_rx_h_check_more_data) @@ -2612,6 +2611,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) .sdata = sta->sdata, .local = sta->local, .queue = tid, + .flags = 0, }; struct tid_ampdu_rx *tid_agg_rx; -- cgit v0.10.2 From 2fc713b20469b2779fa89f582d2a9696b10031e7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 1 Apr 2011 19:34:08 +0300 Subject: zd1211rw: remove URB_SHORT_NOT_OK flag in zd_usb_iowrite16v_async() Patch removes the bogus flag introduced by upstream commit eefdbec1ea8b7093d2c09d1825f68438701723cf. Old code had buffer length check that new code tried to handle with URB_SHORT_NOT_OK flag. With USB debugging enabled bogus flag caused usb_submit_urb fail. Remove URB_SHORT_NOT_OK flag and add buffer length check to urb completion handler. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=32092 Reported-by: Jonathan Callen Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 58236e6..9b1a26a 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1671,6 +1671,10 @@ static void iowrite16v_urb_complete(struct urb *urb) if (urb->status && !usb->cmd_error) usb->cmd_error = urb->status; + + if (!usb->cmd_error && + urb->actual_length != urb->transfer_buffer_length) + usb->cmd_error = -EIO; } static int zd_submit_waiting_urb(struct zd_usb *usb, bool last) @@ -1805,7 +1809,7 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), req, req_len, iowrite16v_urb_complete, usb, ep->desc.bInterval); - urb->transfer_flags |= URB_FREE_BUFFER | URB_SHORT_NOT_OK; + urb->transfer_flags |= URB_FREE_BUFFER; /* Submit previous URB */ r = zd_submit_waiting_urb(usb, false); -- cgit v0.10.2 From 023535732f4db01af4921f20f058bc4561d9add7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 1 Apr 2011 19:34:16 +0300 Subject: zd1211rw: reset rx idle timer from tasklet 2.6.38 added WARN_ON(in_irq) in del_timer_sync that triggers on zd1211rw when reseting rx idle timer in urb completion handler. Move timer reseting to tasklet. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 9b1a26a..ab607bb 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -643,7 +643,7 @@ static void rx_urb_complete(struct urb *urb) usb = urb->context; rx = &usb->rx; - zd_usb_reset_rx_idle_timer(usb); + tasklet_schedule(&rx->reset_timer_tasklet); if (length%rx->usb_packet_size > rx->usb_packet_size-4) { /* If there is an old first fragment, we don't care. */ @@ -812,6 +812,7 @@ void zd_usb_disable_rx(struct zd_usb *usb) __zd_usb_disable_rx(usb); mutex_unlock(&rx->setup_mutex); + tasklet_kill(&rx->reset_timer_tasklet); cancel_delayed_work_sync(&rx->idle_work); } @@ -1106,6 +1107,13 @@ static void zd_rx_idle_timer_handler(struct work_struct *work) zd_usb_reset_rx(usb); } +static void zd_usb_reset_rx_idle_timer_tasklet(unsigned long param) +{ + struct zd_usb *usb = (struct zd_usb *)param; + + zd_usb_reset_rx_idle_timer(usb); +} + void zd_usb_reset_rx_idle_timer(struct zd_usb *usb) { struct zd_usb_rx *rx = &usb->rx; @@ -1127,6 +1135,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb) static inline void init_usb_rx(struct zd_usb *usb) { struct zd_usb_rx *rx = &usb->rx; + spin_lock_init(&rx->lock); mutex_init(&rx->setup_mutex); if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) { @@ -1136,11 +1145,14 @@ static inline void init_usb_rx(struct zd_usb *usb) } ZD_ASSERT(rx->fragment_length == 0); INIT_DELAYED_WORK(&rx->idle_work, zd_rx_idle_timer_handler); + rx->reset_timer_tasklet.func = zd_usb_reset_rx_idle_timer_tasklet; + rx->reset_timer_tasklet.data = (unsigned long)usb; } static inline void init_usb_tx(struct zd_usb *usb) { struct zd_usb_tx *tx = &usb->tx; + spin_lock_init(&tx->lock); atomic_set(&tx->enabled, 0); tx->stopped = 0; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index b3df2c8..325d0f9 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -183,6 +183,7 @@ struct zd_usb_rx { spinlock_t lock; struct mutex setup_mutex; struct delayed_work idle_work; + struct tasklet_struct reset_timer_tasklet; u8 fragment[2 * USB_MAX_RX_SIZE]; unsigned int fragment_length; unsigned int usb_packet_size; -- cgit v0.10.2 From 09b661b33268698d3b453dceb78cda129ad899b4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 1 Apr 2011 19:42:02 +0300 Subject: wl12xx: fix potential buffer overflow in testmode nvs push We were allocating the size of the NVS file struct and not checking whether the length of the buffer passed was correct before copying it into the allocated memory. This is a security hole because buffer overflows can occur if the userspace passes a bigger file than what is expected. With this patch, we check if the size of the data passed from userspace matches the size required. This bug was introduced in 2.6.36. Cc: stable@kernel.org Reported-by: Ido Yariv Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index e64403b..6ec06a4 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -204,7 +204,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) kfree(wl->nvs); - wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); + if (len != sizeof(struct wl1271_nvs_file)) + return -EINVAL; + + wl->nvs = kzalloc(len, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); ret = -ENOMEM; -- cgit v0.10.2 From 220107610c7c2c9703e09eb363e8ab31025b9315 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 2 Apr 2011 11:31:29 +0200 Subject: p54usb: IDs for two new devices Cc: Reported-by: Mark Davis [via p54/devices wiki] Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 9b344a9..e183587 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -56,6 +56,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */ {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ @@ -68,6 +69,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */ + {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */ {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */ {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ -- cgit v0.10.2 From 2e3e66e3bbcd5f999dc66d843a3efc2314e40e7b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 2 Apr 2011 18:10:22 -0500 Subject: rtlwifi: Fix some warnings/bugs Some compiler/architecture combinations generate some warnings that are not seen on my main system. Two of the "warnings" about unitialized variables are really bugs. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index f74a870..590f14f 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -685,7 +685,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; - u8 hworden; + u8 hworden = 0; u8 tmpdata[8]; if (data == NULL) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 5ef9137..28a6ce3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -303,7 +303,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, u16 box_reg, box_extreg; u8 u1b_tmp; bool isfw_read = false; - u8 buf_index; + u8 buf_index = 0; bool bwrite_sucess = false; u8 wait_h2c_limmit = 100; u8 wait_writeh2c_limmit = 100; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a4b2613..f5d8573 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -246,7 +246,7 @@ static void _rtl_usb_io_handler_init(struct device *dev, static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) { - struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_priv __maybe_unused *rtlpriv = rtl_priv(hw); mutex_destroy(&rtlpriv->io.bb_mutex); } -- cgit v0.10.2 From 37f4ee0b6b39640828dac5937a482c20e8ac794f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 4 Apr 2011 13:50:32 +0200 Subject: rt2x00: fix cancelling uninitialized work {rx,tx}done_work's are only initialized for usb devices. Signed-off-by: Stanislaw Gruszka Cc: stable@kernel.org Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9de9dbe..84eb6ad 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1062,8 +1062,10 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); - cancel_work_sync(&rt2x00dev->rxdone_work); - cancel_work_sync(&rt2x00dev->txdone_work); + if (rt2x00_is_usb(rt2x00dev)) { + cancel_work_sync(&rt2x00dev->rxdone_work); + cancel_work_sync(&rt2x00dev->txdone_work); + } destroy_workqueue(rt2x00dev->workqueue); /* -- cgit v0.10.2 From 3d7dc7e8c1566acb0fc55df228b2ed91f5638e9d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 4 Apr 2011 13:18:44 -0400 Subject: iwlwifi: accept EEPROM version 0x423 for iwl6000 A number of these devices have appeared "in the wild", and apparently the Windows driver is perfectly happy to support this EEPROM version. Signed-off-by: John W. Linville Cc: stable@kernel.org Acked-by: Wey-Yi Guy diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 98aa8af..20b6646 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -241,7 +241,7 @@ struct iwl_eeprom_enhanced_txpwr { /* 6x00 Specific */ #define EEPROM_6000_TX_POWER_VERSION (4) -#define EEPROM_6000_EEPROM_VERSION (0x434) +#define EEPROM_6000_EEPROM_VERSION (0x423) /* 6x50 Specific */ #define EEPROM_6050_TX_POWER_VERSION (4) -- cgit v0.10.2 From 21f976975cbecbdaf23ceeacc1cab2b1c05a028e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 4 Apr 2011 15:33:39 -0400 Subject: ext4: remove unnecessary [cm]time update of quota file It is not necessary to update [cm]time of quota file on each quota file write and it wastes journal space and IO throughput with inode writes. So just remove the updating from ext4_quota_write() and only update times when quotas are being turned off. Userspace cannot get anything reliable from quota files while they are used by the kernel anyway. Signed-off-by: Jan Kara Signed-off-by: "Theodore Ts'o" diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index e25e99b..d0f5353 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h @@ -86,8 +86,8 @@ #ifdef CONFIG_QUOTA /* Amount of blocks needed for quota update - we know that the structure was - * allocated so we need to update only inode+data */ -#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) + * allocated so we need to update only data block */ +#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 1 : 0) /* Amount of blocks needed for quota insert/delete - we do some block writes * but inode, sb and group updates are done only once */ #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 22546ad..35ff9fe 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4614,11 +4614,24 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, static int ext4_quota_off(struct super_block *sb, int type) { + struct inode *inode = sb_dqopt(sb)->files[type]; + handle_t *handle; + /* Force all delayed allocation blocks to be allocated. * Caller already holds s_umount sem */ if (test_opt(sb, DELALLOC)) sync_filesystem(sb); + /* Update modification times of quota files when userspace can + * start looking at them */ + handle = ext4_journal_start(inode, 1); + if (IS_ERR(handle)) + goto out; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + ext4_mark_inode_dirty(handle, inode); + ext4_journal_stop(handle); + +out: return dquot_quota_off(sb, type); } @@ -4714,9 +4727,8 @@ out: if (inode->i_size < off + len) { i_size_write(inode, off + len); EXT4_I(inode)->i_disksize = inode->i_size; + ext4_mark_inode_dirty(handle, inode); } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - ext4_mark_inode_dirty(handle, inode); mutex_unlock(&inode->i_mutex); return len; } -- cgit v0.10.2 From 5b41395fcc0265fc9f193aef9df39ce49d64677c Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Mon, 4 Apr 2011 15:40:24 -0400 Subject: ext4: fix credits computing for indirect mapped files When writing a contiguous set of blocks, two indirect blocks could be needed depending on how the blocks are aligned, so we need to increase the number of credits needed by one. [ Also fixed a another bug which could further underestimate the number of journal credits needed by 1; the code was using integer division instead of DIV_ROUND_UP() -- tytso] Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Cc: stable@kernel.org diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1a86282..7d11e02 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5398,13 +5398,12 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks, /* if nrblocks are contiguous */ if (chunk) { /* - * With N contiguous data blocks, it need at most - * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) indirect blocks - * 2 dindirect blocks - * 1 tindirect block + * With N contiguous data blocks, we need at most + * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks, + * 2 dindirect blocks, and 1 tindirect block */ - indirects = nrblocks / EXT4_ADDR_PER_BLOCK(inode->i_sb); - return indirects + 3; + return DIV_ROUND_UP(nrblocks, + EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; } /* * if nrblocks are not contiguous, worse case, each block touch -- cgit v0.10.2 From 46e4690bbd9a4f8d9e7c4f34e34b48f703ad47e0 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Mon, 4 Apr 2011 16:00:49 -0400 Subject: ext4: fix a double free in ext4_register_li_request In ext4_register_li_request, we malloc a ext4_li_request and inserts it into ext4_li_info->li_request_list. In case of any error later, we free it in the end. But if we have some error in ext4_run_lazyinit_thread, the whole li_request_list will be dropped and freed in it. So we will double free this ext4_li_request. This patch just sets elr to NULL after it is inserted to the list so that the latter kfree won't double free it. Signed-off-by: Tao Ma Reviewed-by: Lukas Czerner Signed-off-by: "Theodore Ts'o" Cc: stable@kernel.org diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 35ff9fe..35bd020 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2975,6 +2975,12 @@ static int ext4_register_li_request(struct super_block *sb, mutex_unlock(&ext4_li_info->li_list_mtx); sbi->s_li_request = elr; + /* + * set elr to NULL here since it has been inserted to + * the request_list and the removal and free of it is + * handled by ext4_clear_request_list from now on. + */ + elr = NULL; if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) { ret = ext4_run_lazyinit_thread(); -- cgit v0.10.2 From ac5c15fa585a89bcebca92dfdbb862dd507534fc Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Wed, 9 Feb 2011 14:56:42 +0100 Subject: drm/nouveau: correct memtiming table parsing for nv4x In line with envytools, verified on 4 or 5 BIOS'es. Signed-off-by: Ben Skeggs Signed-off-by: Roy Spliet diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 2683377..78f467f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -552,6 +552,7 @@ nouveau_mem_timing_init(struct drm_device *dev) u8 tRC; /* Byte 9 */ u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; + u8 magic_number = 0; /* Yeah... sorry*/ u8 *mem = NULL, *entry; int i, recordlen, entries; @@ -596,6 +597,12 @@ nouveau_mem_timing_init(struct drm_device *dev) if (!memtimings->timing) return; + /* Get "some number" from the timing reg for NV_40 + * Used in calculations later */ + if(dev_priv->card_type == NV_40) { + magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24; + } + entry = mem + mem[1]; for (i = 0; i < entries; i++, entry += recordlen) { struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; @@ -635,36 +642,51 @@ nouveau_mem_timing_init(struct drm_device *dev) /* XXX: I don't trust the -1's and +1's... they must come * from somewhere! */ - timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 | + timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | tUNK_18 << 16 | - (tUNK_1 + tUNK_19 + 1) << 8 | - (tUNK_2 - 1)); + (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; + if(dev_priv->chipset == 0xa8) { + timing->reg_100224 |= (tUNK_2 - 1); + } else { + timing->reg_100224 |= (tUNK_2 + 2 - magic_number); + } timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); - if(recordlen > 19) { - timing->reg_100228 += (tUNK_19 - 1) << 24; - }/* I cannot back-up this else-statement right now - else { - timing->reg_100228 += tUNK_12 << 24; - }*/ - - /* XXX: reg_10022c */ - timing->reg_10022c = tUNK_2 - 1; - - timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | - tUNK_13 << 8 | tUNK_13); - - /* XXX: +6? */ - timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC); - timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; - - /* XXX; reg_100238, reg_10023c - * reg: 0x00?????? - * reg_10023c: - * 0 for pre-NV50 cards - * 0x????0202 for NV50+ cards (empirical evidence) */ - if(dev_priv->card_type >= NV_50) { + if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) { + timing->reg_100228 |= (tUNK_19 - 1) << 24; + } + + if(dev_priv->card_type == NV_40) { + /* NV40: don't know what the rest of the regs are.. + * And don't need to know either */ + timing->reg_100228 |= 0x20200000 | magic_number << 24; + } else if(dev_priv->card_type >= NV_50) { + /* XXX: reg_10022c */ + timing->reg_10022c = tUNK_2 - 1; + + timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | + tUNK_13 << 8 | tUNK_13); + + timing->reg_100234 = (tRAS << 24 | tRC); + timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; + + if(dev_priv->chipset < 0xa3) { + timing->reg_100234 |= (tUNK_2 + 2) << 8; + } else { + /* XXX: +6? */ + timing->reg_100234 |= (tUNK_19 + 6) << 8; + } + + /* XXX; reg_100238, reg_10023c + * reg_100238: 0x00?????? + * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */ timing->reg_10023c = 0x202; + if(dev_priv->chipset < 0xa3) { + timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; + } else { + /* currently unknown + * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ + } } NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, @@ -675,7 +697,7 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100238, timing->reg_10023c); } - memtimings->nr_timing = entries; + memtimings->nr_timing = entries; memtimings->supported = true; } -- cgit v0.10.2 From b251d1a488b8a742b621f4cd28f7e57a7bacc434 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 18 Mar 2011 20:19:53 +0000 Subject: nv30: Fix parsing of perf table Perf tables v 1.2 and 1.3 (seen on Geforce FX/ 5) are not long enough to store the voltage label/id v2 - Remove comment from the code Signed-off-by: Emil Velikov Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index ac62a1b..670e3cb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c @@ -134,7 +134,7 @@ nouveau_perf_init(struct drm_device *dev) case 0x13: case 0x15: perflvl->fanspeed = entry[55]; - perflvl->voltage = entry[56]; + perflvl->voltage = (recordlen > 56) ? entry[56] : 0; perflvl->core = ROM32(entry[1]) * 10; perflvl->memory = ROM32(entry[5]) * 20; break; -- cgit v0.10.2 From fb522ee1aa57f2bb57ebd1111524601076d9ad0a Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Thu, 10 Mar 2011 22:43:25 +0100 Subject: drm/nouveau: fix oops on unload with disabled LVDS panel Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=35135 BUG: unable to handle kernel NULL pointer dereference at 000002d8 IP: [] nv04_dfp_restore+0x7f/0xd0 [nouveau] (...) Call Trace: [] nv04_display_destroy+0xa8/0x140 [nouveau] [] nouveau_unload+0x2a/0x160 [nouveau] [] drm_put_dev+0xbb/0x1b0 [drm] [] nouveau_pci_remove+0x15/0x20 [nouveau] [] pci_device_remove+0x44/0xf0 [] __device_release_driver+0x51/0xb0 [] driver_detach+0x8f/0xa0 [] bus_remove_driver+0x63/0xa0 [] driver_unregister+0x49/0x80 [] ? sysfs_remove_file+0x14/0x20 [] pci_unregister_driver+0x32/0x90 [] ? __stop_machine+0x5a/0x70 [] drm_exit+0x83/0x90 [drm] [] nouveau_exit+0x1b/0x8be [nouveau] [] sys_delete_module+0x13b/0x1f0 [] ? do_munmap+0x1fe/0x280 [] ? arch_unmap_area_topdown+0x0/0x20 [] syscall_call+0x7/0xb Reported-by: Francesco Marella Tested-by: Francesco Marella Signed-off-by: Marcin Slusarz [ currojerez@riseup.net: No need to spam the logs in that case, an unbound LVDS encoder is not an error. ] Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index c82db37..12098bf 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -581,12 +581,13 @@ static void nv04_dfp_restore(struct drm_encoder *encoder) int head = nv_encoder->restore.head; if (nv_encoder->dcb->type == OUTPUT_LVDS) { - struct drm_display_mode *native_mode = nouveau_encoder_connector_get(nv_encoder)->native_mode; - if (native_mode) - call_lvds_script(dev, nv_encoder->dcb, head, LVDS_PANEL_ON, - native_mode->clock); - else - NV_ERROR(dev, "Not restoring LVDS without native mode\n"); + struct nouveau_connector *connector = + nouveau_encoder_connector_get(nv_encoder); + + if (connector && connector->native_mode) + call_lvds_script(dev, nv_encoder->dcb, head, + LVDS_PANEL_ON, + connector->native_mode->clock); } else if (nv_encoder->dcb->type == OUTPUT_TMDS) { int clock = nouveau_hw_pllvals_to_clk -- cgit v0.10.2 From ec64a40868469d308ad1e040c6ead2373af334dd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 21 Mar 2011 21:31:21 +1000 Subject: drm/nouveau: implement init table opcode 0x5c Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8314a49..eca191a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -269,7 +269,7 @@ struct init_tbl_entry { int (*handler)(struct nvbios *, uint16_t, struct init_exec *); }; -static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *); +static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *); #define MACRO_INDEX_SIZE 2 #define MACRO_SIZE 8 @@ -2011,6 +2011,27 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) } static int +init_jump(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +{ + /* + * INIT_JUMP opcode: 0x5C ('\') + * + * offset (8 bit): opcode + * offset + 1 (16 bit): offset (in bios) + * + * Continue execution of init table from 'offset' + */ + + uint16_t jmp_offset = ROM16(bios->data[offset + 1]); + + if (!iexec->execute) + return 3; + + BIOSLOG(bios, "0x%04X: Jump to 0x%04X\n", offset, jmp_offset); + return jmp_offset - offset; +} + +static int init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { /* @@ -3659,6 +3680,7 @@ static struct init_tbl_entry itbl_entry[] = { { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, + { "INIT_JUMP" , 0x5C, init_jump }, { "INIT_I2C_IF" , 0x5E, init_i2c_if }, { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, @@ -3700,8 +3722,7 @@ static struct init_tbl_entry itbl_entry[] = { #define MAX_TABLE_OPS 1000 static int -parse_init_table(struct nvbios *bios, unsigned int offset, - struct init_exec *iexec) +parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { /* * Parses all commands in an init table. -- cgit v0.10.2 From 59197c026257ab730c7fc8819a0e2b26e125a534 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Mon, 21 Mar 2011 21:41:47 +1000 Subject: drm/nv50-nvc0: work around an evo channel hang that some people see Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index a2cfaa6..c8e83c1 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -186,6 +186,7 @@ nv50_evo_channel_init(struct nouveau_channel *evo) nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id); evo->dma.max = (4096/4) - 2; + evo->dma.max &= ~7; evo->dma.put = 0; evo->dma.cur = evo->dma.put; evo->dma.free = evo->dma.max - evo->dma.cur; -- cgit v0.10.2 From c0929b499f834210561fe5e8c48bcad4f2130d25 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 21 Mar 2011 11:42:51 +1000 Subject: drm/nouveau: quirk for XFX GT-240X-YA Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index eca191a..90aef64 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6354,6 +6354,32 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) } } + /* XFX GT-240X-YA + * + * So many things wrong here, replace the entire encoder table.. + */ + if (nv_match_device(dev, 0x0ca3, 0x1682, 0x3003)) { + if (idx == 0) { + *conn = 0x02001300; /* VGA, connector 1 */ + *conf = 0x00000028; + } else + if (idx == 1) { + *conn = 0x01010312; /* DVI, connector 0 */ + *conf = 0x00020030; + } else + if (idx == 2) { + *conn = 0x01010310; /* VGA, connector 0 */ + *conf = 0x00000028; + } else + if (idx == 3) { + *conn = 0x02022362; /* HDMI, connector 2 */ + *conf = 0x00020010; + } else { + *conn = 0x0000000e; /* EOL */ + *conf = 0x00000000; + } + } + return true; } -- cgit v0.10.2 From 2b4cebe4e165b0ef30a138e4cf602538dea15583 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 29 Mar 2011 09:56:14 +1000 Subject: drm/nv50: use "nv86" tlb flush method on everything except 0x50/0xac It has been reported that this greatly improves (and possibly fixes completely) the stability of NVA3+ chipsets. In traces of my NVA8, NVIDIA now appear to be doing this too. The most recent traces of 0x50 and 0xac I could find don't show NVIDIA checking PGRAPH status on these flushes, so for now, we won't either. Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index fff180a..59ed5be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1190,7 +1190,7 @@ extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_unload_context(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); extern void nv50_graph_tlb_flush(struct drm_device *dev); -extern void nv86_graph_tlb_flush(struct drm_device *dev); +extern void nv84_graph_tlb_flush(struct drm_device *dev); extern struct nouveau_enum nv50_data_error_names[]; /* nvc0_graph.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 4fcbd09..1e7e006 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -376,15 +376,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv50_graph_destroy_context; engine->graph.load_context = nv50_graph_load_context; engine->graph.unload_context = nv50_graph_unload_context; - if (dev_priv->chipset != 0x86) + if (dev_priv->chipset == 0x50 || + dev_priv->chipset == 0xac) engine->graph.tlb_flush = nv50_graph_tlb_flush; - else { - /* from what i can see nvidia do this on every - * pre-NVA3 board except NVAC, but, we've only - * ever seen problems on NV86 - */ - engine->graph.tlb_flush = nv86_graph_tlb_flush; - } + else + engine->graph.tlb_flush = nv84_graph_tlb_flush; engine->fifo.channels = 128; engine->fifo.init = nv50_fifo_init; engine->fifo.takedown = nv50_fifo_takedown; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 8675b00..b02a5b1 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -503,7 +503,7 @@ nv50_graph_tlb_flush(struct drm_device *dev) } void -nv86_graph_tlb_flush(struct drm_device *dev) +nv84_graph_tlb_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; -- cgit v0.10.2 From e61e51f134a3299c2c37051f69638cc9e9fd88c1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 30 Mar 2011 11:56:16 +1000 Subject: drm/nv50-nvc0: remove some code that doesn't belong here Not sure how this snuck in... Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 2b99840..a19ccaa 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -469,9 +469,6 @@ nv50_crtc_wait_complete(struct drm_crtc *crtc) start = ptimer->read(dev); do { - nv_wr32(dev, 0x61002c, 0x370); - nv_wr32(dev, 0x000140, 1); - if (nv_ro32(disp->ntfy, 0x000)) return 0; } while (ptimer->read(dev) - start < 2000000000ULL); -- cgit v0.10.2 From a719726f4ceaf14842c80fd7e58dec40cb7022a2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 30 Mar 2011 13:57:44 +1000 Subject: drm/nvc0: improve vm flush function Signed-off-by: Ben Skeggs diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c index 69af0ba..a0a2a02 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -104,20 +104,26 @@ nvc0_vm_flush(struct nouveau_vm *vm) struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; struct drm_device *dev = vm->dev; struct nouveau_vm_pgd *vpgd; - u32 r100c80, engine; + u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5; pinstmem->flush(vm->dev); - if (vm == dev_priv->chan_vm) - engine = 1; - else - engine = 5; - + spin_lock(&dev_priv->ramin_lock); list_for_each_entry(vpgd, &vm->pgd_list, head) { - r100c80 = nv_rd32(dev, 0x100c80); + /* looks like maybe a "free flush slots" counter, the + * faster you write to 0x100cbc to more it decreases + */ + if (!nv_wait_ne(dev, 0x100c80, 0x00ff0000, 0x00000000)) { + NV_ERROR(dev, "vm timeout 0: 0x%08x %d\n", + nv_rd32(dev, 0x100c80), engine); + } nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8); nv_wr32(dev, 0x100cbc, 0x80000000 | engine); - if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80)) - NV_ERROR(dev, "vm flush timeout eng %d\n", engine); + /* wait for flush to be queued? */ + if (!nv_wait(dev, 0x100c80, 0x00008000, 0x00008000)) { + NV_ERROR(dev, "vm timeout 1: 0x%08x %d\n", + nv_rd32(dev, 0x100c80), engine); + } } + spin_unlock(&dev_priv->ramin_lock); } -- cgit v0.10.2 From 6cba611e600ded15f642552ce6b5f7ee243bacf0 Mon Sep 17 00:00:00 2001 From: Zhang Huan Date: Tue, 5 Apr 2011 19:16:20 -0400 Subject: jbd2: fix potential memory leak on transaction commit There is potential memory leak of journal head in function jbd2_journal_commit_transaction. The problem is that JBD2 will not reclaim the journal head of commit record if error occurs or journal is abotred. I use the following script to reproduce this issue, on a RHEL6 system. I found it very easy to reproduce with async commit enabled. mount /dev/sdb /mnt -o journal_checksum,journal_async_commit touch /mnt/xxx echo offline > /sys/block/sdb/device/state sync umount /mnt rmmod ext4 rmmod jbd2 Removal of the jbd2 module will make slab complaining that "cache `jbd2_journal_head': can't free all objects". Signed-off-by: Zhang Huan Signed-off-by: "Theodore Ts'o" diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index fa36d76..b98e4c1 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -105,6 +105,8 @@ static int journal_submit_commit_record(journal_t *journal, int ret; struct timespec now = current_kernel_time(); + *cbh = NULL; + if (is_journal_aborted(journal)) return 0; @@ -806,7 +808,7 @@ wait_for_iobuf: if (err) __jbd2_journal_abort_hard(journal); } - if (!err && !is_journal_aborted(journal)) + if (cbh) err = journal_wait_on_commit_record(journal, cbh); if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT) && -- cgit v0.10.2 From 0449641130f5652b344ef6fa39fa019d7e94660a Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Tue, 5 Apr 2011 19:55:28 -0400 Subject: ext4: init timer earlier to avoid a kernel panic in __save_error_info During mount, when we fail to open journal inode or root inode, the __save_error_info will mod_timer. But actually s_err_report isn't initialized yet and the kernel oops. The detailed information can be found https://bugzilla.kernel.org/show_bug.cgi?id=32082. The best way is to check whether the timer s_err_report is initialized or not. But it seems that in include/linux/timer.h, we can't find a good function to check the status of this timer, so this patch just move the initializtion of s_err_report earlier so that we can avoid the kernel panic. The corresponding del_timer is also added in the error path. Reported-by: Sami Liedes Signed-off-by: Tao Ma Signed-off-by: "Theodore Ts'o" diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 35bd020..551cb8e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3391,6 +3391,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); + init_timer(&sbi->s_err_report); + sbi->s_err_report.function = print_daily_error_info; + sbi->s_err_report.data = (unsigned long) sb; + err = percpu_counter_init(&sbi->s_freeblocks_counter, ext4_count_free_blocks(sb)); if (!err) { @@ -3652,9 +3656,6 @@ no_journal: "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, *sbi->s_es->s_mount_opts ? "; " : "", orig_data); - init_timer(&sbi->s_err_report); - sbi->s_err_report.function = print_daily_error_info; - sbi->s_err_report.data = (unsigned long) sb; if (es->s_error_count) mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */ @@ -3678,6 +3679,7 @@ failed_mount_wq: sbi->s_journal = NULL; } failed_mount3: + del_timer(&sbi->s_err_report); if (sbi->s_flex_groups) { if (is_vmalloc_addr(sbi->s_flex_groups)) vfree(sbi->s_flex_groups); -- cgit v0.10.2 From 61f4237d5b005767a76f4f3694e68e6f78f392d9 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Sat, 18 Sep 2010 22:25:30 -0700 Subject: xen: just completely disable XSAVE Some (old) versions of Xen just kill the domain if it tries to set any unknown bits in CR4, so we can't reliably probe for OSXSAVE in CR4. Since Xen doesn't support XSAVE for guests at the moment, and no such support is being worked on, there's no downside in just unconditionally masking XSAVE support. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 49dbd78..66272a2 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -250,23 +250,7 @@ static __init void xen_init_cpuid_mask(void) ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ (1 << X86_FEATURE_ACPI)); /* disable ACPI */ - ax = 1; - cx = 0; - xen_cpuid(&ax, &bx, &cx, &dx); - - /* cpuid claims we support xsave; try enabling it to see what happens */ - if (cx & (1 << (X86_FEATURE_XSAVE % 32))) { - unsigned long cr4; - - set_in_cr4(X86_CR4_OSXSAVE); - - cr4 = read_cr4(); - - if ((cr4 & X86_CR4_OSXSAVE) == 0) - cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32)); - - clear_in_cr4(X86_CR4_OSXSAVE); - } + cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32)); /* disable XSAVE */ } static void xen_set_debugreg(int reg, unsigned long val) -- cgit v0.10.2 From 947ccf9c3c30307b774af3666ee74fcd9f47f646 Mon Sep 17 00:00:00 2001 From: Shan Haitao Date: Tue, 9 Nov 2010 11:43:36 -0800 Subject: xen: Allow PV-OPS kernel to detect whether XSAVE is supported Xen fails to mask XSAVE from the cpuid feature, despite not historically supporting guest use of XSAVE. However, now that XSAVE support has been added to Xen, we need to reliably detect its presence. The most reliable way to do this is to look at the OSXSAVE feature in cpuid which is set iff the OS (Xen, in this case), has set CR4.OSXSAVE. [ Cleaned up conditional a bit. - Jeremy ] Signed-off-by: Shan Haitao Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 66272a2..e3c6a06 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -238,6 +238,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, static __init void xen_init_cpuid_mask(void) { unsigned int ax, bx, cx, dx; + unsigned int xsave_mask; cpuid_leaf1_edx_mask = ~((1 << X86_FEATURE_MCE) | /* disable MCE */ @@ -249,8 +250,16 @@ static __init void xen_init_cpuid_mask(void) cpuid_leaf1_edx_mask &= ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ (1 << X86_FEATURE_ACPI)); /* disable ACPI */ + ax = 1; + xen_cpuid(&ax, &bx, &cx, &dx); - cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32)); /* disable XSAVE */ + xsave_mask = + (1 << (X86_FEATURE_XSAVE % 32)) | + (1 << (X86_FEATURE_OSXSAVE % 32)); + + /* Xen will set CR4.OSXSAVE if supported and not disabled by force */ + if ((cx & xsave_mask) != xsave_mask) + cpuid_leaf1_ecx_mask &= ~xsave_mask; /* disable XSAVE & OSXSAVE */ } static void xen_set_debugreg(int reg, unsigned long val) -- cgit v0.10.2 From 35a67edf3570e9b44c34965dd52a6b7f845fb40f Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 5 Apr 2011 06:52:49 +0000 Subject: smsc911x: fix mac_lock acquision before calling smsc911x_mac_read When SMSC911X_SAVE_MAC_ADDRESS flag is enabled the driver calls smsc911x_mac_read and smsc911x_mac_read function without acquiring mac_lock spinlock This patch fixes following warning smsc911x: Driver version 2008-10-21. ------------[ cut here ]------------ WARNING: at drivers/net/smsc911x.c:261 smsc911x_mac_read+0x24/0x220() Modules linked in: [] (unwind_backtrace+0x0/0xe0) from [] (warn_slowpath_common+0x4c/0x64) [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_null+0x18/0x1c) [] (warn_slowpath_null+0x18/0x1c) from [] (smsc911x_mac_read+0x24/0x220) [] (smsc911x_mac_read+0x24/0x220) from [] (smsc911x_read_mac_address+0x18/0x6c) [] (smsc911x_read_mac_address+0x18/0x6c) from [] (smsc911x_drv_probe+0x498/0x1788) [] (smsc911x_drv_probe+0x498/0x1788) from [] (platform_drv_probe+0x14/0x18) [] (platform_drv_probe+0x14/0x18) from [] (driver_probe_device+0xc8/0x184) [] (driver_probe_device+0xc8/0x184) from [] (__driver_attach+0x68/0x8c) [] (__driver_attach+0x68/0x8c) from [] (bus_for_each_dev+0x48/0x74) [] (bus_for_each_dev+0x48/0x74) from [] (bus_add_driver+0x9c/0x228) [] (bus_add_driver+0x9c/0x228) from [] (driver_register+0xa0/0x124) [] (driver_register+0xa0/0x124) from [] (do_one_initcall+0x94/0x168) [] (do_one_initcall+0x94/0x168) from [] (kernel_init+0xa0/0x154) [] (kernel_init+0xa0/0x154) from [] (kernel_thread_exit+0x0/0x8) ---[ end trace 2c931a35b7885770 ]--- Signed-off-by: Enric Balletbo i Serra Signed-off-by: David S. Miller diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 1566259..4747846 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1818,6 +1818,7 @@ static int __devinit smsc911x_init(struct net_device *dev) SMSC_TRACE(PROBE, "PHY will be autodetected."); spin_lock_init(&pdata->dev_lock); + spin_lock_init(&pdata->mac_lock); if (pdata->ioaddr == 0) { SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); @@ -1895,8 +1896,11 @@ static int __devinit smsc911x_init(struct net_device *dev) /* workaround for platforms without an eeprom, where the mac address * is stored elsewhere and set by the bootloader. This saves the * mac address before resetting the device */ - if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) + if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) { + spin_lock_irq(&pdata->mac_lock); smsc911x_read_mac_address(dev); + spin_unlock_irq(&pdata->mac_lock); + } /* Reset the LAN911x */ if (smsc911x_soft_reset(pdata)) @@ -2059,8 +2063,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); } - spin_lock_init(&pdata->mac_lock); - retval = smsc911x_mii_init(pdev, dev); if (retval) { SMSC_WARNING(PROBE, -- cgit v0.10.2 From 34206f267120c839a479d0237db907fa062e7b0f Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 5 Apr 2011 07:08:41 +0000 Subject: can: mcp251x: Allow pass IRQ flags through platform data. When an interrupt occurs, the INT pin is driven low by the MCP251x controller (falling edge) but in some cases the INT pin can be connected to the MPU through a transistor or level translator which inverts this signal. In this case interrupt should be configured in rising edge. This patch adds support to pass the IRQ flags via mcp251x_platform_data. Signed-off-by: Enric Balletbo i Serra Acked-by: Wolfgang Grandegger Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 7513c45..330140e 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -931,7 +931,8 @@ static int mcp251x_open(struct net_device *net) priv->tx_len = 0; ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist, - IRQF_TRIGGER_FALLING, DEVICE_NAME, priv); + pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING, + DEVICE_NAME, priv); if (ret) { dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); if (pdata->transceiver_enable) diff --git a/include/linux/can/platform/mcp251x.h b/include/linux/can/platform/mcp251x.h index 8e20540..089fe43 100644 --- a/include/linux/can/platform/mcp251x.h +++ b/include/linux/can/platform/mcp251x.h @@ -12,6 +12,7 @@ /** * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data * @oscillator_frequency: - oscillator frequency in Hz + * @irq_flags: - IRQF configuration flags * @board_specific_setup: - called before probing the chip (power,reset) * @transceiver_enable: - called to power on/off the transceiver * @power_enable: - called to power on/off the mcp *and* the @@ -24,6 +25,7 @@ struct mcp251x_platform_data { unsigned long oscillator_frequency; + unsigned long irq_flags; int (*board_specific_setup)(struct spi_device *spi); int (*transceiver_enable)(int enable); int (*power_enable) (int enable); -- cgit v0.10.2 From 1e58148670908e9fd180761c0eed3839b6778f01 Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Mon, 4 Apr 2011 08:29:59 +0000 Subject: bna: Fix for handling firmware heartbeat failure This patch contains a fix for gracefully handling firmware heartbeat failure instead of forcing panic. Signed-off-by: Debashis Dutt Signed-off-by: Rasesh Mody Signed-off-by: David S. Miller diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index 34933cb..e3de0b8 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -2219,13 +2219,9 @@ bfa_nw_ioc_get_mac(struct bfa_ioc *ioc) static void bfa_ioc_recover(struct bfa_ioc *ioc) { - u16 bdf; - - bdf = (ioc->pcidev.pci_slot << 8 | ioc->pcidev.pci_func << 3 | - ioc->pcidev.device_id); - - pr_crit("Firmware heartbeat failure at %d", bdf); - BUG_ON(1); + pr_crit("Heart Beat of IOC has failed\n"); + bfa_ioc_stats(ioc, ioc_hbfails); + bfa_fsm_send_event(ioc, IOC_E_HBFAIL); } static void -- cgit v0.10.2 From 2d5d4154650459b61a8e7097d186a89d89dab8ed Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 05:53:13 +0000 Subject: be2net: Fix a potential crash during shutdown. adapter could remain uninitialized if probe fails for some reason. A null pointer access could cause a crash if be_shutdown is called after that. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a71163f..6e8e211 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -3141,12 +3141,14 @@ static int be_resume(struct pci_dev *pdev) static void be_shutdown(struct pci_dev *pdev) { struct be_adapter *adapter = pci_get_drvdata(pdev); - struct net_device *netdev = adapter->netdev; - if (netif_running(netdev)) + if (!adapter) + return; + + if (netif_running(adapter->netdev)) cancel_delayed_work_sync(&adapter->work); - netif_device_detach(netdev); + netif_device_detach(adapter->netdev); be_cmd_reset_function(adapter); -- cgit v0.10.2 From 47482f132a689af168fae3055ff1899dfd032d3a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 6 Apr 2011 13:07:09 -0700 Subject: ipv6: Enable RFS sk_rxhash tracking for ipv6 sockets (v2) properly record sk_rxhash in ipv6 sockets (v2) Noticed while working on another project that flows to sockets which I had open on a test systems weren't getting steered properly when I had RFS enabled. Looking more closely I found that: 1) The affected sockets were all ipv6 2) They weren't getting steered because sk->sk_rxhash was never set from the incomming skbs on that socket. This was occuring because there are several points in the IPv4 tcp and udp code which save the rxhash value when a new connection is established. Those calls to sock_rps_save_rxhash were never added to the corresponding ipv6 code paths. This patch adds those calls. Tested by myself to properly enable RFS functionalty on ipv6. Change notes: v2: Filtered UDP to only arm RFS on bound sockets (Eric Dumazet) Signed-off-by: Neil Horman Signed-off-by: David S. Miller diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 56fa125..4f49e5d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1622,6 +1622,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) opt_skb = skb_clone(skb, GFP_ATOMIC); if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ + sock_rps_save_rxhash(sk, skb->rxhash); if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) goto reset; if (opt_skb) @@ -1649,7 +1650,8 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) __kfree_skb(opt_skb); return 0; } - } + } else + sock_rps_save_rxhash(sk, skb->rxhash); if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) goto reset; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d7037c0..15c3774 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -505,6 +505,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) int rc; int is_udplite = IS_UDPLITE(sk); + if (!ipv6_addr_any(&inet6_sk(sk)->daddr)) + sock_rps_save_rxhash(sk, skb->rxhash); + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) goto drop; -- cgit v0.10.2 From ec80bfcb68a0c46443991991d459a0cde773cdea Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Tue, 5 Apr 2011 03:03:56 +0000 Subject: dsa/mv88e6131: add support for mv88e6085 switch The mv88e6085 is identical to the mv88e6095, except that all ports are 10/100 Mb/s, so use the existing setup code except for the cpu/dsa speed selection in _setup_port(). Signed-off-by: Peter Korsgaard Acked-by: Lennert Buytenhek Signed-off-by: David S. Miller diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c index bb2b41b..a8e4f8c 100644 --- a/net/dsa/mv88e6131.c +++ b/net/dsa/mv88e6131.c @@ -14,6 +14,13 @@ #include "dsa_priv.h" #include "mv88e6xxx.h" +/* + * Switch product IDs + */ +#define ID_6085 0x04a0 +#define ID_6095 0x0950 +#define ID_6131 0x1060 + static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr) { int ret; @@ -21,9 +28,11 @@ static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr) ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03); if (ret >= 0) { ret &= 0xfff0; - if (ret == 0x0950) + if (ret == ID_6085) + return "Marvell 88E6085"; + if (ret == ID_6095) return "Marvell 88E6095/88E6095F"; - if (ret == 0x1060) + if (ret == ID_6131) return "Marvell 88E6131"; } @@ -164,6 +173,7 @@ static int mv88e6131_setup_global(struct dsa_switch *ds) static int mv88e6131_setup_port(struct dsa_switch *ds, int p) { + struct mv88e6xxx_priv_state *ps = (void *)(ds + 1); int addr = REG_PORT(p); u16 val; @@ -171,10 +181,13 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p) * MAC Forcing register: don't force link, speed, duplex * or flow control state to any particular values on physical * ports, but force the CPU port and all DSA ports to 1000 Mb/s - * full duplex. + * (100 Mb/s on 6085) full duplex. */ if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p)) - REG_WRITE(addr, 0x01, 0x003e); + if (ps->id == ID_6085) + REG_WRITE(addr, 0x01, 0x003d); /* 100 Mb/s */ + else + REG_WRITE(addr, 0x01, 0x003e); /* 1000 Mb/s */ else REG_WRITE(addr, 0x01, 0x0003); @@ -286,6 +299,8 @@ static int mv88e6131_setup(struct dsa_switch *ds) mv88e6xxx_ppu_state_init(ds); mutex_init(&ps->stats_mutex); + ps->id = REG_READ(REG_PORT(0), 0x03) & 0xfff0; + ret = mv88e6131_switch_reset(ds); if (ret < 0) return ret; diff --git a/net/dsa/mv88e6xxx.h b/net/dsa/mv88e6xxx.h index eb0e0aa..61156ca2 100644 --- a/net/dsa/mv88e6xxx.h +++ b/net/dsa/mv88e6xxx.h @@ -39,6 +39,8 @@ struct mv88e6xxx_priv_state { * Hold this mutex over snapshot + dump sequences. */ struct mutex stats_mutex; + + int id; /* switch product id */ }; struct mv88e6xxx_hw_stat { -- cgit v0.10.2 From ae07b0b221b6ab2edf9e3abd518aec6cd3f1ba66 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Wed, 6 Apr 2011 14:04:49 -0700 Subject: pppoe: drop PPPOX_ZOMBIEs in pppoe_flush_dev otherwise we loop forever if a PPPoE socket was set to PPPOX_ZOMBIE state by a PADT message when the ethernet device is going down afterwards. Signed-off-by: Ulrich Weber Signed-off-by: David S. Miller diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 78c0e3c..71b1d8f 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -317,7 +317,7 @@ static void pppoe_flush_dev(struct net_device *dev) lock_sock(sk); if (po->pppoe_dev == dev && - sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { pppox_unbind_sock(sk); sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); -- cgit v0.10.2 From ecd6210765f93bd2c578d370d45bb49c710f3e89 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Sun, 3 Apr 2011 01:54:11 +0000 Subject: be2net: Rename some struct members for clarity Renamed msix_vec_idx to eq_idx in be_eq_obj struct. Renamed msix_vec_next_idx to eq_next_idx in be_adapter structure. These members are used in INTX mode also. Signed-off-by: Sarveswara Rao Mygapula Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index f803c58..66823ed 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -154,7 +154,7 @@ struct be_eq_obj { u16 min_eqd; /* in usecs */ u16 max_eqd; /* in usecs */ u16 cur_eqd; /* in usecs */ - u8 msix_vec_idx; + u8 eq_idx; struct napi_struct napi; }; @@ -291,7 +291,7 @@ struct be_adapter { u32 num_rx_qs; u32 big_page_size; /* Compounded page size shared by rx wrbs */ - u8 msix_vec_next_idx; + u8 eq_next_idx; struct be_drv_stats drv_stats; struct vlan_group *vlan_grp; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6e8e211..1a4808c 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1497,7 +1497,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) goto tx_eq_free; - adapter->tx_eq.msix_vec_idx = adapter->msix_vec_next_idx++; + adapter->tx_eq.eq_idx = adapter->eq_next_idx++; /* Alloc TX eth compl queue */ @@ -1590,7 +1590,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) if (rc) goto err; - rxo->rx_eq.msix_vec_idx = adapter->msix_vec_next_idx++; + rxo->rx_eq.eq_idx = adapter->eq_next_idx++; /* CQ */ cq = &rxo->cq; @@ -1666,11 +1666,11 @@ static irqreturn_t be_intx(int irq, void *dev) if (!isr) return IRQ_NONE; - if ((1 << adapter->tx_eq.msix_vec_idx & isr)) + if ((1 << adapter->tx_eq.eq_idx & isr)) event_handle(adapter, &adapter->tx_eq); for_all_rx_queues(adapter, rxo, i) { - if ((1 << rxo->rx_eq.msix_vec_idx & isr)) + if ((1 << rxo->rx_eq.eq_idx & isr)) event_handle(adapter, &rxo->rx_eq); } } @@ -1951,7 +1951,7 @@ static void be_sriov_disable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, struct be_eq_obj *eq_obj) { - return adapter->msix_entries[eq_obj->msix_vec_idx].vector; + return adapter->msix_entries[eq_obj->eq_idx].vector; } static int be_request_irq(struct be_adapter *adapter, -- cgit v0.10.2 From 1f5db833758a9650ad002058e40760aaa11d732e Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Sun, 3 Apr 2011 01:54:39 +0000 Subject: be2net: Fix suspend/resume operation eq_next_idx is not getting reset to zero during suspend. This causes resume to fail. Added the fix. Signed-off-by: Sarveswara Rao Mygapula Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 1a4808c..88d4c80 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2345,6 +2345,7 @@ static int be_clear(struct be_adapter *adapter) be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); + adapter->eq_next_idx = 0; if (be_physfn(adapter) && adapter->sriov_enabled) for (vf = 0; vf < num_vfs; vf++) -- cgit v0.10.2 From 9b57e1a79e2142df8412ab223c90ba6f47c6b3a3 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Sun, 3 Apr 2011 23:12:23 +0000 Subject: MAINTAINERS: add entry for Xen network backend Signed-off-by: Ian Campbell Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 6b4b9cd..649600c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6916,6 +6916,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86. S: Maintained F: drivers/platform/x86 +XEN NETWORK BACKEND DRIVER +M: Ian Campbell +L: xen-devel@lists.xensource.com (moderated for non-subscribers) +L: netdev@vger.kernel.org +S: Supported +F: drivers/net/xen-netback/* + XEN PCI SUBSYSTEM M: Konrad Rzeszutek Wilk L: xen-devel@lists.xensource.com (moderated for non-subscribers) -- cgit v0.10.2 From 850a28ecd8044ef36b2c7699d2e3736a410b4d0a Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 6 Apr 2011 17:49:15 +0300 Subject: spi: Fix race condition in stop_queue() There's a race condition in stop_queue() in some drivers - if drv_data->queue is empty, but drv_data->busy is still set (or opposite situation) stop_queue will return -EBUSY. So fix loop condition to check that both drv_data->queue is empty and drv_data->busy is not set. This patch affects following drivers: pxa2xx_spi spi_bfin5xx amba-pl022 dw_spi Signed-off-by: Vasily Khoruzhick Acked-by: Eric Miao Acked-by: Mike Frysinger Signed-off-by: Grant Likely diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 5a4e0af..4b8357b 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -1555,7 +1555,7 @@ static int stop_queue(struct pl022 *pl022) * A wait_queue on the pl022->busy could be used, but then the common * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead */ - while (!list_empty(&pl022->queue) && pl022->busy && limit--) { + while ((!list_empty(&pl022->queue) || pl022->busy) && limit--) { spin_unlock_irqrestore(&pl022->queue_lock, flags); msleep(10); spin_lock_irqsave(&pl022->queue_lock, flags); diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 9a61964..d040deb 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -821,7 +821,7 @@ static int stop_queue(struct dw_spi *dws) spin_lock_irqsave(&dws->lock, flags); dws->run = QUEUE_STOPPED; - while (!list_empty(&dws->queue) && dws->busy && limit--) { + while ((!list_empty(&dws->queue) || dws->busy) && limit--) { spin_unlock_irqrestore(&dws->lock, flags); msleep(10); spin_lock_irqsave(&dws->lock, flags); diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index a429b01..3aa7820 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1493,7 +1493,7 @@ static int stop_queue(struct driver_data *drv_data) * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead */ drv_data->run = QUEUE_STOPPED; - while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { spin_unlock_irqrestore(&drv_data->lock, flags); msleep(10); spin_lock_irqsave(&drv_data->lock, flags); diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index a284624..f3a1c52 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1284,7 +1284,7 @@ static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data) * friends on every SPI message. Do this instead */ drv_data->running = false; - while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { spin_unlock_irqrestore(&drv_data->lock, flags); msleep(10); spin_lock_irqsave(&drv_data->lock, flags); -- cgit v0.10.2 From 1b86a58f9d7ce4fe2377687f378fbfb53bdc9b6c Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 7 Apr 2011 14:04:08 -0700 Subject: ipv4: Fix "Set rt->rt_iif more sanely on output routes." Commit 1018b5c01636c7c6bda31a719bda34fc631db29a ("Set rt->rt_iif more sanely on output routes.") breaks rt_is_{output,input}_route. This became the cause to return "IP_PKTINFO's ->ipi_ifindex == 0". To fix it, this does: 1) Add "int rt_route_iif;" to struct rtable 2) For input routes, always set rt_route_iif to same value as rt_iif 3) For output routes, always set rt_route_iif to zero. Set rt_iif as it is done currently. 4) Change rt_is_{output,input}_route() to test rt_route_iif Signed-off-by: OGAWA Hirofumi Signed-off-by: David S. Miller diff --git a/include/net/route.h b/include/net/route.h index f88429c..8fce062 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -64,6 +64,7 @@ struct rtable { __be32 rt_dst; /* Path destination */ __be32 rt_src; /* Path source */ + int rt_route_iif; int rt_iif; int rt_oif; __u32 rt_mark; @@ -80,12 +81,12 @@ struct rtable { static inline bool rt_is_input_route(struct rtable *rt) { - return rt->rt_iif != 0; + return rt->rt_route_iif != 0; } static inline bool rt_is_output_route(struct rtable *rt) { - return rt->rt_iif == 0; + return rt->rt_route_iif == 0; } struct ip_rt_acct { diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4b0c811..1628be5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1891,6 +1891,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, #ifdef CONFIG_IP_ROUTE_CLASSID rth->dst.tclassid = itag; #endif + rth->rt_route_iif = dev->ifindex; rth->rt_iif = dev->ifindex; rth->dst.dev = init_net.loopback_dev; dev_hold(rth->dst.dev); @@ -2026,6 +2027,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_key_src = saddr; rth->rt_src = saddr; rth->rt_gateway = daddr; + rth->rt_route_iif = in_dev->dev->ifindex; rth->rt_iif = in_dev->dev->ifindex; rth->dst.dev = (out_dev)->dev; dev_hold(rth->dst.dev); @@ -2202,6 +2204,7 @@ local_input: #ifdef CONFIG_IP_ROUTE_CLASSID rth->dst.tclassid = itag; #endif + rth->rt_route_iif = dev->ifindex; rth->rt_iif = dev->ifindex; rth->dst.dev = net->loopback_dev; dev_hold(rth->dst.dev); @@ -2401,7 +2404,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res, rth->rt_mark = oldflp4->flowi4_mark; rth->rt_dst = fl4->daddr; rth->rt_src = fl4->saddr; - rth->rt_iif = 0; + rth->rt_route_iif = 0; + rth->rt_iif = oldflp4->flowi4_oif ? : dev_out->ifindex; /* get references to the devices that are to be hold by the routing cache entry */ rth->dst.dev = dev_out; @@ -2716,6 +2720,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or rt->rt_key_dst = ort->rt_key_dst; rt->rt_key_src = ort->rt_key_src; rt->rt_tos = ort->rt_tos; + rt->rt_route_iif = ort->rt_route_iif; rt->rt_iif = ort->rt_iif; rt->rt_oif = ort->rt_oif; rt->rt_mark = ort->rt_mark; @@ -2725,7 +2730,6 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or rt->rt_type = ort->rt_type; rt->rt_dst = ort->rt_dst; rt->rt_src = ort->rt_src; - rt->rt_iif = ort->rt_iif; rt->rt_gateway = ort->rt_gateway; rt->rt_spec_dst = ort->rt_spec_dst; rt->peer = ort->peer; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 13e0e7f..d20a05e 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -74,6 +74,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, rt->rt_key_dst = fl4->daddr; rt->rt_key_src = fl4->saddr; rt->rt_tos = fl4->flowi4_tos; + rt->rt_route_iif = fl4->flowi4_iif; rt->rt_iif = fl4->flowi4_iif; rt->rt_oif = fl4->flowi4_oif; rt->rt_mark = fl4->flowi4_mark; -- cgit v0.10.2 From e828776a8abe6b9bae7ed9638710bff7642c568a Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: fix extent format buffer allocation size When formatting an inode item, we have to allocate a separate buffer to hold extents when there are delayed allocation extents on the inode and it is in extent format. The allocation size is derived from the in-core data fork representation, which accounts for delayed allocation extents, while the on-disk representation does not contain any delalloc extents. As a result of this mismatch, the allocated buffer can be far larger than needed to hold the real extent list which, due to the fact the inode is in extent format, is limited to the size of the literal area of the inode. However, we can have thousands of delalloc extents, resulting in an allocation size orders of magnitude larger than is needed to hold all the real extents. Fix this by limiting the size of the buffer being allocated to the size of the literal area of the inodes in the filesystem (i.e. the maximum size an inode fork can grow to). Signed-off-by: Dave Chinner Reviewed-by: Alex Elder diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 46cc401..576fdfe 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -198,6 +198,41 @@ xfs_inode_item_size( } /* + * xfs_inode_item_format_extents - convert in-core extents to on-disk form + * + * For either the data or attr fork in extent format, we need to endian convert + * the in-core extent as we place them into the on-disk inode. In this case, we + * need to do this conversion before we write the extents into the log. Because + * we don't have the disk inode to write into here, we allocate a buffer and + * format the extents into it via xfs_iextents_copy(). We free the buffer in + * the unlock routine after the copy for the log has been made. + * + * In the case of the data fork, the in-core and on-disk fork sizes can be + * different due to delayed allocation extents. We only log on-disk extents + * here, so always use the physical fork size to determine the size of the + * buffer we need to allocate. + */ +STATIC void +xfs_inode_item_format_extents( + struct xfs_inode *ip, + struct xfs_log_iovec *vecp, + int whichfork, + int type) +{ + xfs_bmbt_rec_t *ext_buffer; + + ext_buffer = kmem_alloc(XFS_IFORK_SIZE(ip, whichfork), KM_SLEEP); + if (whichfork == XFS_DATA_FORK) + ip->i_itemp->ili_extents_buf = ext_buffer; + else + ip->i_itemp->ili_aextents_buf = ext_buffer; + + vecp->i_addr = ext_buffer; + vecp->i_len = xfs_iextents_copy(ip, ext_buffer, whichfork); + vecp->i_type = type; +} + +/* * This is called to fill in the vector of log iovecs for the * given inode log item. It fills the first item with an inode * log format structure, the second with the on-disk inode structure, @@ -213,7 +248,6 @@ xfs_inode_item_format( struct xfs_inode *ip = iip->ili_inode; uint nvecs; size_t data_bytes; - xfs_bmbt_rec_t *ext_buffer; xfs_mount_t *mp; vecp->i_addr = &iip->ili_format; @@ -320,22 +354,8 @@ xfs_inode_item_format( } else #endif { - /* - * There are delayed allocation extents - * in the inode, or we need to convert - * the extents to on disk format. - * Use xfs_iextents_copy() - * to copy only the real extents into - * a separate buffer. We'll free the - * buffer in the unlock routine. - */ - ext_buffer = kmem_alloc(ip->i_df.if_bytes, - KM_SLEEP); - iip->ili_extents_buf = ext_buffer; - vecp->i_addr = ext_buffer; - vecp->i_len = xfs_iextents_copy(ip, ext_buffer, - XFS_DATA_FORK); - vecp->i_type = XLOG_REG_TYPE_IEXT; + xfs_inode_item_format_extents(ip, vecp, + XFS_DATA_FORK, XLOG_REG_TYPE_IEXT); } ASSERT(vecp->i_len <= ip->i_df.if_bytes); iip->ili_format.ilf_dsize = vecp->i_len; @@ -445,19 +465,12 @@ xfs_inode_item_format( */ vecp->i_addr = ip->i_afp->if_u1.if_extents; vecp->i_len = ip->i_afp->if_bytes; + vecp->i_type = XLOG_REG_TYPE_IATTR_EXT; #else ASSERT(iip->ili_aextents_buf == NULL); - /* - * Need to endian flip before logging - */ - ext_buffer = kmem_alloc(ip->i_afp->if_bytes, - KM_SLEEP); - iip->ili_aextents_buf = ext_buffer; - vecp->i_addr = ext_buffer; - vecp->i_len = xfs_iextents_copy(ip, ext_buffer, - XFS_ATTR_FORK); + xfs_inode_item_format_extents(ip, vecp, + XFS_ATTR_FORK, XLOG_REG_TYPE_IATTR_EXT); #endif - vecp->i_type = XLOG_REG_TYPE_IATTR_EXT; iip->ili_format.ilf_asize = vecp->i_len; vecp++; nvecs++; -- cgit v0.10.2 From c6d09b666de11eb272326a6eb6cd3246da571014 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: introduce a xfssyncd workqueue All of the work xfssyncd does is background functionality. There is no need for a thread per filesystem to do this work - it can al be managed by a global workqueue now they manage concurrency effectively. Introduce a new gglobal xfssyncd workqueue, and convert the periodic work to use this new functionality. To do this, use a delayed work construct to schedule the next running of the periodic sync work for the filesystem. When the sync work is complete, queue a new delayed work for the next running of the sync work. For laptop mode, we wait on completion for the sync works, so ensure that the sync work queuing interface can flush and wait for work to complete to enable the work queue infrastructure to replace the current sequence number and wakeup that is used. Because the sync work does non-trivial amounts of work, mark the new work queue as CPU intensive. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 1ba5c45..c71b6ed 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1191,22 +1191,12 @@ xfs_fs_sync_fs( return -error; if (laptop_mode) { - int prev_sync_seq = mp->m_sync_seq; - /* * The disk must be active because we're syncing. * We schedule xfssyncd now (now that the disk is * active) instead of later (when it might not be). */ - wake_up_process(mp->m_sync_task); - /* - * We have to wait for the sync iteration to complete. - * If we don't, the disk activity caused by the sync - * will come after the sync is completed, and that - * triggers another sync from laptop mode. - */ - wait_event(mp->m_wait_single_sync_task, - mp->m_sync_seq != prev_sync_seq); + flush_delayed_work_sync(&mp->m_sync_work); } return 0; @@ -1492,7 +1482,6 @@ xfs_fs_fill_super( atomic_set(&mp->m_active_trans, 0); INIT_LIST_HEAD(&mp->m_sync_list); spin_lock_init(&mp->m_sync_lock); - init_waitqueue_head(&mp->m_wait_single_sync_task); mp->m_super = sb; sb->s_fs_info = mp; @@ -1833,13 +1822,27 @@ init_xfs_fs(void) if (error) goto out_cleanup_procfs; + /* + * max_active is set to 8 to give enough concurency to allow + * multiple work operations on each CPU to run. This allows multiple + * filesystems to be running sync work concurrently, and scales with + * the number of CPUs in the system. + */ + xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8); + if (!xfs_syncd_wq) { + error = -ENOMEM; + goto out_sysctl_unregister; + } + vfs_initquota(); error = register_filesystem(&xfs_fs_type); if (error) - goto out_sysctl_unregister; + goto out_destroy_xfs_syncd; return 0; + out_destroy_xfs_syncd: + destroy_workqueue(xfs_syncd_wq); out_sysctl_unregister: xfs_sysctl_unregister(); out_cleanup_procfs: @@ -1861,6 +1864,7 @@ exit_xfs_fs(void) { vfs_exitquota(); unregister_filesystem(&xfs_fs_type); + destroy_workqueue(xfs_syncd_wq); xfs_sysctl_unregister(); xfs_cleanup_procfs(); xfs_buf_terminate(); diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 594cd82..4a582d8 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -39,6 +39,8 @@ #include #include +struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */ + /* * The inode lookup is done in batches to keep the amount of lock traffic and * radix tree lookups to a minimum. The batch size is a trade off between @@ -489,32 +491,6 @@ xfs_flush_inodes( xfs_log_force(ip->i_mount, XFS_LOG_SYNC); } -/* - * Every sync period we need to unpin all items, reclaim inodes and sync - * disk quotas. We might need to cover the log to indicate that the - * filesystem is idle and not frozen. - */ -STATIC void -xfs_sync_worker( - struct xfs_mount *mp, - void *unused) -{ - int error; - - if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { - /* dgc: errors ignored here */ - if (mp->m_super->s_frozen == SB_UNFROZEN && - xfs_log_need_covered(mp)) - error = xfs_fs_log_dummy(mp); - else - xfs_log_force(mp, 0); - xfs_reclaim_inodes(mp, 0); - error = xfs_qm_sync(mp, SYNC_TRYLOCK); - } - mp->m_sync_seq++; - wake_up(&mp->m_wait_single_sync_task); -} - STATIC int xfssyncd( void *arg) @@ -528,34 +504,19 @@ xfssyncd( timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); for (;;) { if (list_empty(&mp->m_sync_list)) - timeleft = schedule_timeout_interruptible(timeleft); + schedule_timeout_interruptible(timeleft); /* swsusp */ try_to_freeze(); if (kthread_should_stop() && list_empty(&mp->m_sync_list)) break; spin_lock(&mp->m_sync_lock); - /* - * We can get woken by laptop mode, to do a sync - - * that's the (only!) case where the list would be - * empty with time remaining. - */ - if (!timeleft || list_empty(&mp->m_sync_list)) { - if (!timeleft) - timeleft = xfs_syncd_centisecs * - msecs_to_jiffies(10); - INIT_LIST_HEAD(&mp->m_sync_work.w_list); - list_add_tail(&mp->m_sync_work.w_list, - &mp->m_sync_list); - } list_splice_init(&mp->m_sync_list, &tmp); spin_unlock(&mp->m_sync_lock); list_for_each_entry_safe(work, n, &tmp, w_list) { (*work->w_syncer)(mp, work->w_data); list_del(&work->w_list); - if (work == &mp->m_sync_work) - continue; if (work->w_completion) complete(work->w_completion); kmem_free(work); @@ -565,13 +526,49 @@ xfssyncd( return 0; } +static void +xfs_syncd_queue_sync( + struct xfs_mount *mp) +{ + queue_delayed_work(xfs_syncd_wq, &mp->m_sync_work, + msecs_to_jiffies(xfs_syncd_centisecs * 10)); +} + +/* + * Every sync period we need to unpin all items, reclaim inodes and sync + * disk quotas. We might need to cover the log to indicate that the + * filesystem is idle and not frozen. + */ +STATIC void +xfs_sync_worker( + struct work_struct *work) +{ + struct xfs_mount *mp = container_of(to_delayed_work(work), + struct xfs_mount, m_sync_work); + int error; + + if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { + /* dgc: errors ignored here */ + if (mp->m_super->s_frozen == SB_UNFROZEN && + xfs_log_need_covered(mp)) + error = xfs_fs_log_dummy(mp); + else + xfs_log_force(mp, 0); + xfs_reclaim_inodes(mp, 0); + error = xfs_qm_sync(mp, SYNC_TRYLOCK); + } + + /* queue us up again */ + xfs_syncd_queue_sync(mp); +} + int xfs_syncd_init( struct xfs_mount *mp) { - mp->m_sync_work.w_syncer = xfs_sync_worker; - mp->m_sync_work.w_mount = mp; - mp->m_sync_work.w_completion = NULL; + INIT_DELAYED_WORK(&mp->m_sync_work, xfs_sync_worker); + xfs_syncd_queue_sync(mp); + mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd/%s", mp->m_fsname); if (IS_ERR(mp->m_sync_task)) return -PTR_ERR(mp->m_sync_task); @@ -582,6 +579,7 @@ void xfs_syncd_stop( struct xfs_mount *mp) { + cancel_delayed_work_sync(&mp->m_sync_work); kthread_stop(mp->m_sync_task); } diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 32ba662..e3a6ad2 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h @@ -32,6 +32,8 @@ typedef struct xfs_sync_work { #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ #define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */ +extern struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */ + int xfs_syncd_init(struct xfs_mount *mp); void xfs_syncd_stop(struct xfs_mount *mp); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index a62e897..2c11e62 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -203,12 +203,10 @@ typedef struct xfs_mount { struct mutex m_icsb_mutex; /* balancer sync lock */ #endif struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ + struct delayed_work m_sync_work; /* background sync work */ struct task_struct *m_sync_task; /* generalised sync thread */ - xfs_sync_work_t m_sync_work; /* work item for VFS_SYNC */ struct list_head m_sync_list; /* sync thread work item list */ spinlock_t m_sync_lock; /* work item list lock */ - int m_sync_seq; /* sync thread generation no. */ - wait_queue_head_t m_wait_single_sync_task; __int64_t m_update_flags; /* sb flags we need to update on the next remount,rw */ struct shrinker m_inode_shrink; /* inode reclaim shrinker */ -- cgit v0.10.2 From 89e4cb550a492cfca038a555fcc1bdac58822ec3 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: convert ENOSPC inode flushing to use new syncd workqueue On of the problems with the current inode flush at ENOSPC is that we queue a flush per ENOSPC event, regardless of how many are already queued. Thi can result in hundreds of queued flushes, most of which simply burn CPU scanned and do no real work. This simply slows down allocation at ENOSPC. We really only need one active flush at a time, and we can easily implement that via the new xfs_syncd_wq. All we need to do is queue a flush if one is not already active, then block waiting for the currently active flush to complete. The result is that we only ever have a single ENOSPC inode flush active at a time and this greatly reduces the overhead of ENOSPC processing. On my 2p test machine, this results in tests exercising ENOSPC conditions running significantly faster - 042 halves execution time, 083 drops from 60s to 5s, etc - while not introducing test regressions. This allows us to remove the old xfssyncd threads and infrastructure as they are no longer used. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index c71b6ed..ee0e981 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1480,8 +1480,6 @@ xfs_fs_fill_super( spin_lock_init(&mp->m_sb_lock); mutex_init(&mp->m_growlock); atomic_set(&mp->m_active_trans, 0); - INIT_LIST_HEAD(&mp->m_sync_list); - spin_lock_init(&mp->m_sync_lock); mp->m_super = sb; sb->s_fs_info = mp; diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 4a582d8..af32759 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -433,99 +433,6 @@ xfs_quiesce_attr( xfs_unmountfs_writesb(mp); } -/* - * Enqueue a work item to be picked up by the vfs xfssyncd thread. - * Doing this has two advantages: - * - It saves on stack space, which is tight in certain situations - * - It can be used (with care) as a mechanism to avoid deadlocks. - * Flushing while allocating in a full filesystem requires both. - */ -STATIC void -xfs_syncd_queue_work( - struct xfs_mount *mp, - void *data, - void (*syncer)(struct xfs_mount *, void *), - struct completion *completion) -{ - struct xfs_sync_work *work; - - work = kmem_alloc(sizeof(struct xfs_sync_work), KM_SLEEP); - INIT_LIST_HEAD(&work->w_list); - work->w_syncer = syncer; - work->w_data = data; - work->w_mount = mp; - work->w_completion = completion; - spin_lock(&mp->m_sync_lock); - list_add_tail(&work->w_list, &mp->m_sync_list); - spin_unlock(&mp->m_sync_lock); - wake_up_process(mp->m_sync_task); -} - -/* - * Flush delayed allocate data, attempting to free up reserved space - * from existing allocations. At this point a new allocation attempt - * has failed with ENOSPC and we are in the process of scratching our - * heads, looking about for more room... - */ -STATIC void -xfs_flush_inodes_work( - struct xfs_mount *mp, - void *arg) -{ - struct inode *inode = arg; - xfs_sync_data(mp, SYNC_TRYLOCK); - xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT); - iput(inode); -} - -void -xfs_flush_inodes( - xfs_inode_t *ip) -{ - struct inode *inode = VFS_I(ip); - DECLARE_COMPLETION_ONSTACK(completion); - - igrab(inode); - xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work, &completion); - wait_for_completion(&completion); - xfs_log_force(ip->i_mount, XFS_LOG_SYNC); -} - -STATIC int -xfssyncd( - void *arg) -{ - struct xfs_mount *mp = arg; - long timeleft; - xfs_sync_work_t *work, *n; - LIST_HEAD (tmp); - - set_freezable(); - timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); - for (;;) { - if (list_empty(&mp->m_sync_list)) - schedule_timeout_interruptible(timeleft); - /* swsusp */ - try_to_freeze(); - if (kthread_should_stop() && list_empty(&mp->m_sync_list)) - break; - - spin_lock(&mp->m_sync_lock); - list_splice_init(&mp->m_sync_list, &tmp); - spin_unlock(&mp->m_sync_lock); - - list_for_each_entry_safe(work, n, &tmp, w_list) { - (*work->w_syncer)(mp, work->w_data); - list_del(&work->w_list); - if (work->w_completion) - complete(work->w_completion); - kmem_free(work); - } - } - - return 0; -} - static void xfs_syncd_queue_sync( struct xfs_mount *mp) @@ -562,16 +469,47 @@ xfs_sync_worker( xfs_syncd_queue_sync(mp); } +/* + * Flush delayed allocate data, attempting to free up reserved space + * from existing allocations. At this point a new allocation attempt + * has failed with ENOSPC and we are in the process of scratching our + * heads, looking about for more room. + * + * Queue a new data flush if there isn't one already in progress and + * wait for completion of the flush. This means that we only ever have one + * inode flush in progress no matter how many ENOSPC events are occurring and + * so will prevent the system from bogging down due to every concurrent + * ENOSPC event scanning all the active inodes in the system for writeback. + */ +void +xfs_flush_inodes( + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + + queue_work(xfs_syncd_wq, &mp->m_flush_work); + flush_work_sync(&mp->m_flush_work); +} + +STATIC void +xfs_flush_worker( + struct work_struct *work) +{ + struct xfs_mount *mp = container_of(work, + struct xfs_mount, m_flush_work); + + xfs_sync_data(mp, SYNC_TRYLOCK); + xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT); +} + int xfs_syncd_init( struct xfs_mount *mp) { + INIT_WORK(&mp->m_flush_work, xfs_flush_worker); INIT_DELAYED_WORK(&mp->m_sync_work, xfs_sync_worker); xfs_syncd_queue_sync(mp); - mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd/%s", mp->m_fsname); - if (IS_ERR(mp->m_sync_task)) - return -PTR_ERR(mp->m_sync_task); return 0; } @@ -580,7 +518,7 @@ xfs_syncd_stop( struct xfs_mount *mp) { cancel_delayed_work_sync(&mp->m_sync_work); - kthread_stop(mp->m_sync_task); + cancel_work_sync(&mp->m_flush_work); } void diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 2c11e62..a0ad90e 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -204,9 +204,7 @@ typedef struct xfs_mount { #endif struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ struct delayed_work m_sync_work; /* background sync work */ - struct task_struct *m_sync_task; /* generalised sync thread */ - struct list_head m_sync_list; /* sync thread work item list */ - spinlock_t m_sync_lock; /* work item list lock */ + struct work_struct m_flush_work; /* background inode flush */ __int64_t m_update_flags; /* sb flags we need to update on the next remount,rw */ struct shrinker m_inode_shrink; /* inode reclaim shrinker */ -- cgit v0.10.2 From a7b339f1b8698667eada006e717cdb4523be2ed5 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: introduce background inode reclaim work Background inode reclaim needs to run more frequently that the XFS syncd work is run as 30s is too long between optimal reclaim runs. Add a new periodic work item to the xfs syncd workqueue to run a fast, non-blocking inode reclaim scan. Background inode reclaim is kicked by the act of marking inodes for reclaim. When an AG is first marked as having reclaimable inodes, the background reclaim work is kicked. It will continue to run periodically untill it detects that there are no more reclaimable inodes. It will be kicked again when the first inode is queued for reclaim. To ensure shrinker based inode reclaim throttles to the inode cleaning and reclaim rate but still reclaim inodes efficiently, make it kick the background inode reclaim so that when we are low on memory we are trying to reclaim inodes as efficiently as possible. This kick shoul d not be necessary, but it will protect against failures to kick the background reclaim when inodes are first dirtied. To provide the rate throttling, make the shrinker pass do synchronous inode reclaim so that it blocks on inodes under IO. This means that the shrinker will reclaim inodes rather than just skipping over them, but it does not adversely affect the rate of reclaim because most dirty inodes are already under IO due to the background reclaim work the shrinker kicked. These two modifications solve one of the two OOM killer invocations Chris Mason reported recently when running a stress testing script. The particular workload trigger for the OOM killer invocation is where there are more threads than CPUs all unlinking files in an extremely memory constrained environment. Unlike other solutions, this one does not have a performance impact on performance when memory is not constrained or the number of concurrent threads operating is <= to the number of CPUs. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index af32759..debe282 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -461,7 +461,6 @@ xfs_sync_worker( error = xfs_fs_log_dummy(mp); else xfs_log_force(mp, 0); - xfs_reclaim_inodes(mp, 0); error = xfs_qm_sync(mp, SYNC_TRYLOCK); } @@ -470,6 +469,52 @@ xfs_sync_worker( } /* + * Queue a new inode reclaim pass if there are reclaimable inodes and there + * isn't a reclaim pass already in progress. By default it runs every 5s based + * on the xfs syncd work default of 30s. Perhaps this should have it's own + * tunable, but that can be done if this method proves to be ineffective or too + * aggressive. + */ +static void +xfs_syncd_queue_reclaim( + struct xfs_mount *mp) +{ + + /* + * We can have inodes enter reclaim after we've shut down the syncd + * workqueue during unmount, so don't allow reclaim work to be queued + * during unmount. + */ + if (!(mp->m_super->s_flags & MS_ACTIVE)) + return; + + rcu_read_lock(); + if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) { + queue_delayed_work(xfs_syncd_wq, &mp->m_reclaim_work, + msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10)); + } + rcu_read_unlock(); +} + +/* + * This is a fast pass over the inode cache to try to get reclaim moving on as + * many inodes as possible in a short period of time. It kicks itself every few + * seconds, as well as being kicked by the inode cache shrinker when memory + * goes low. It scans as quickly as possible avoiding locked inodes or those + * already being flushed, and once done schedules a future pass. + */ +STATIC void +xfs_reclaim_worker( + struct work_struct *work) +{ + struct xfs_mount *mp = container_of(to_delayed_work(work), + struct xfs_mount, m_reclaim_work); + + xfs_reclaim_inodes(mp, SYNC_TRYLOCK); + xfs_syncd_queue_reclaim(mp); +} + +/* * Flush delayed allocate data, attempting to free up reserved space * from existing allocations. At this point a new allocation attempt * has failed with ENOSPC and we are in the process of scratching our @@ -508,7 +553,10 @@ xfs_syncd_init( { INIT_WORK(&mp->m_flush_work, xfs_flush_worker); INIT_DELAYED_WORK(&mp->m_sync_work, xfs_sync_worker); + INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker); + xfs_syncd_queue_sync(mp); + xfs_syncd_queue_reclaim(mp); return 0; } @@ -518,6 +566,7 @@ xfs_syncd_stop( struct xfs_mount *mp) { cancel_delayed_work_sync(&mp->m_sync_work); + cancel_delayed_work_sync(&mp->m_reclaim_work); cancel_work_sync(&mp->m_flush_work); } @@ -537,6 +586,10 @@ __xfs_inode_set_reclaim_tag( XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), XFS_ICI_RECLAIM_TAG); spin_unlock(&ip->i_mount->m_perag_lock); + + /* schedule periodic background inode reclaim */ + xfs_syncd_queue_reclaim(ip->i_mount); + trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno, -1, _RET_IP_); } @@ -953,7 +1006,13 @@ xfs_reclaim_inodes( } /* - * Shrinker infrastructure. + * Inode cache shrinker. + * + * When called we make sure that there is a background (fast) inode reclaim in + * progress, while we will throttle the speed of reclaim via doiing synchronous + * reclaim of inodes. That means if we come across dirty inodes, we wait for + * them to be cleaned, which we hope will not be very long due to the + * background walker having already kicked the IO off on those dirty inodes. */ static int xfs_reclaim_inode_shrink( @@ -968,10 +1027,14 @@ xfs_reclaim_inode_shrink( mp = container_of(shrink, struct xfs_mount, m_inode_shrink); if (nr_to_scan) { + /* kick background reclaimer */ + xfs_syncd_queue_reclaim(mp); + if (!(gfp_mask & __GFP_FS)) return -1; - xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK, &nr_to_scan); + xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, + &nr_to_scan); /* terminate if we don't exhaust the scan */ if (nr_to_scan > 0) return -1; diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index a0ad90e..19af0ab 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -204,6 +204,7 @@ typedef struct xfs_mount { #endif struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ struct delayed_work m_sync_work; /* background sync work */ + struct delayed_work m_reclaim_work; /* background inode reclaim */ struct work_struct m_flush_work; /* background inode flush */ __int64_t m_update_flags; /* sb flags we need to update on the next remount,rw */ -- cgit v0.10.2 From 0bf6a5bd4b55b466964ead6fa566d8f346a828ee Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: convert the xfsaild threads to a workqueue Similar to the xfssyncd, the per-filesystem xfsaild threads can be converted to a global workqueue and run periodically by delayed works. This makes sense for the AIL pushing because it uses variable timeouts depending on the work that needs to be done. By removing the xfsaild, we simplify the AIL pushing code and remove the need to spread the code to implement the threading and pushing across multiple files. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index ee0e981..67d5b2c 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -816,75 +816,6 @@ xfs_setup_devices( return 0; } -/* - * XFS AIL push thread support - */ -void -xfsaild_wakeup( - struct xfs_ail *ailp, - xfs_lsn_t threshold_lsn) -{ - /* only ever move the target forwards */ - if (XFS_LSN_CMP(threshold_lsn, ailp->xa_target) > 0) { - ailp->xa_target = threshold_lsn; - wake_up_process(ailp->xa_task); - } -} - -STATIC int -xfsaild( - void *data) -{ - struct xfs_ail *ailp = data; - xfs_lsn_t last_pushed_lsn = 0; - long tout = 0; /* milliseconds */ - - while (!kthread_should_stop()) { - /* - * for short sleeps indicating congestion, don't allow us to - * get woken early. Otherwise all we do is bang on the AIL lock - * without making progress. - */ - if (tout && tout <= 20) - __set_current_state(TASK_KILLABLE); - else - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(tout ? - msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT); - - /* swsusp */ - try_to_freeze(); - - ASSERT(ailp->xa_mount->m_log); - if (XFS_FORCED_SHUTDOWN(ailp->xa_mount)) - continue; - - tout = xfsaild_push(ailp, &last_pushed_lsn); - } - - return 0; -} /* xfsaild */ - -int -xfsaild_start( - struct xfs_ail *ailp) -{ - ailp->xa_target = 0; - ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s", - ailp->xa_mount->m_fsname); - if (IS_ERR(ailp->xa_task)) - return -PTR_ERR(ailp->xa_task); - return 0; -} - -void -xfsaild_stop( - struct xfs_ail *ailp) -{ - kthread_stop(ailp->xa_task); -} - - /* Catch misguided souls that try to use this interface on XFS */ STATIC struct inode * xfs_fs_alloc_inode( @@ -1786,6 +1717,38 @@ xfs_destroy_zones(void) } STATIC int __init +xfs_init_workqueues(void) +{ + /* + * max_active is set to 8 to give enough concurency to allow + * multiple work operations on each CPU to run. This allows multiple + * filesystems to be running sync work concurrently, and scales with + * the number of CPUs in the system. + */ + xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8); + if (!xfs_syncd_wq) + goto out; + + xfs_ail_wq = alloc_workqueue("xfsail", WQ_CPU_INTENSIVE, 8); + if (!xfs_ail_wq) + goto out_destroy_syncd; + + return 0; + +out_destroy_syncd: + destroy_workqueue(xfs_syncd_wq); +out: + return -ENOMEM; +} + +STATIC void __exit +xfs_destroy_workqueues(void) +{ + destroy_workqueue(xfs_ail_wq); + destroy_workqueue(xfs_syncd_wq); +} + +STATIC int __init init_xfs_fs(void) { int error; @@ -1800,10 +1763,14 @@ init_xfs_fs(void) if (error) goto out; - error = xfs_mru_cache_init(); + error = xfs_init_workqueues(); if (error) goto out_destroy_zones; + error = xfs_mru_cache_init(); + if (error) + goto out_destroy_wq; + error = xfs_filestream_init(); if (error) goto out_mru_cache_uninit; @@ -1820,27 +1787,17 @@ init_xfs_fs(void) if (error) goto out_cleanup_procfs; - /* - * max_active is set to 8 to give enough concurency to allow - * multiple work operations on each CPU to run. This allows multiple - * filesystems to be running sync work concurrently, and scales with - * the number of CPUs in the system. - */ - xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8); - if (!xfs_syncd_wq) { - error = -ENOMEM; + error = xfs_init_workqueues(); + if (error) goto out_sysctl_unregister; - } vfs_initquota(); error = register_filesystem(&xfs_fs_type); if (error) - goto out_destroy_xfs_syncd; + goto out_sysctl_unregister; return 0; - out_destroy_xfs_syncd: - destroy_workqueue(xfs_syncd_wq); out_sysctl_unregister: xfs_sysctl_unregister(); out_cleanup_procfs: @@ -1851,6 +1808,8 @@ init_xfs_fs(void) xfs_filestream_uninit(); out_mru_cache_uninit: xfs_mru_cache_uninit(); + out_destroy_wq: + xfs_destroy_workqueues(); out_destroy_zones: xfs_destroy_zones(); out: @@ -1862,12 +1821,12 @@ exit_xfs_fs(void) { vfs_exitquota(); unregister_filesystem(&xfs_fs_type); - destroy_workqueue(xfs_syncd_wq); xfs_sysctl_unregister(); xfs_cleanup_procfs(); xfs_buf_terminate(); xfs_filestream_uninit(); xfs_mru_cache_uninit(); + xfs_destroy_workqueues(); xfs_destroy_zones(); } diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 12aff95..cb3aeac 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -28,6 +28,8 @@ #include "xfs_trans_priv.h" #include "xfs_error.h" +struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */ + STATIC void xfs_ail_splice(struct xfs_ail *, struct list_head *, xfs_lsn_t); STATIC void xfs_ail_delete(struct xfs_ail *, xfs_log_item_t *); STATIC xfs_log_item_t * xfs_ail_min(struct xfs_ail *); @@ -69,36 +71,6 @@ xfs_trans_ail_tail( } /* - * xfs_trans_push_ail - * - * This routine is called to move the tail of the AIL forward. It does this by - * trying to flush items in the AIL whose lsns are below the given - * threshold_lsn. - * - * the push is run asynchronously in a separate thread, so we return the tail - * of the log right now instead of the tail after the push. This means we will - * either continue right away, or we will sleep waiting on the async thread to - * do its work. - * - * We do this unlocked - we only need to know whether there is anything in the - * AIL at the time we are called. We don't need to access the contents of - * any of the objects, so the lock is not needed. - */ -void -xfs_trans_ail_push( - struct xfs_ail *ailp, - xfs_lsn_t threshold_lsn) -{ - xfs_log_item_t *lip; - - lip = xfs_ail_min(ailp); - if (lip && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) { - if (XFS_LSN_CMP(threshold_lsn, ailp->xa_target) > 0) - xfsaild_wakeup(ailp, threshold_lsn); - } -} - -/* * AIL traversal cursor initialisation. * * The cursor keeps track of where our current traversal is up @@ -236,16 +208,16 @@ out: } /* - * xfsaild_push does the work of pushing on the AIL. Returning a timeout of - * zero indicates that the caller should sleep until woken. + * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself + * to run at a later time if there is more work to do to complete the push. */ -long -xfsaild_push( - struct xfs_ail *ailp, - xfs_lsn_t *last_lsn) +STATIC void +xfs_ail_worker( + struct work_struct *work) { - long tout = 0; - xfs_lsn_t last_pushed_lsn = *last_lsn; + struct xfs_ail *ailp = container_of(to_delayed_work(work), + struct xfs_ail, xa_work); + long tout; xfs_lsn_t target = ailp->xa_target; xfs_lsn_t lsn; xfs_log_item_t *lip; @@ -256,15 +228,15 @@ xfsaild_push( spin_lock(&ailp->xa_lock); xfs_trans_ail_cursor_init(ailp, cur); - lip = xfs_trans_ail_cursor_first(ailp, cur, *last_lsn); + lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn); if (!lip || XFS_FORCED_SHUTDOWN(mp)) { /* * AIL is empty or our push has reached the end. */ xfs_trans_ail_cursor_done(ailp, cur); spin_unlock(&ailp->xa_lock); - *last_lsn = 0; - return tout; + ailp->xa_last_pushed_lsn = 0; + return; } XFS_STATS_INC(xs_push_ail); @@ -301,13 +273,13 @@ xfsaild_push( case XFS_ITEM_SUCCESS: XFS_STATS_INC(xs_push_ail_success); IOP_PUSH(lip); - last_pushed_lsn = lsn; + ailp->xa_last_pushed_lsn = lsn; break; case XFS_ITEM_PUSHBUF: XFS_STATS_INC(xs_push_ail_pushbuf); IOP_PUSHBUF(lip); - last_pushed_lsn = lsn; + ailp->xa_last_pushed_lsn = lsn; push_xfsbufd = 1; break; @@ -319,7 +291,7 @@ xfsaild_push( case XFS_ITEM_LOCKED: XFS_STATS_INC(xs_push_ail_locked); - last_pushed_lsn = lsn; + ailp->xa_last_pushed_lsn = lsn; stuck++; break; @@ -374,9 +346,23 @@ xfsaild_push( wake_up_process(mp->m_ddev_targp->bt_task); } + /* assume we have more work to do in a short while */ + tout = 10; if (!count) { /* We're past our target or empty, so idle */ - last_pushed_lsn = 0; + ailp->xa_last_pushed_lsn = 0; + + /* + * Check for an updated push target before clearing the + * XFS_AIL_PUSHING_BIT. If the target changed, we've got more + * work to do. Wait a bit longer before starting that work. + */ + smp_rmb(); + if (ailp->xa_target == target) { + clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); + return; + } + tout = 50; } else if (XFS_LSN_CMP(lsn, target) >= 0) { /* * We reached the target so wait a bit longer for I/O to @@ -384,7 +370,7 @@ xfsaild_push( * start the next scan from the start of the AIL. */ tout = 50; - last_pushed_lsn = 0; + ailp->xa_last_pushed_lsn = 0; } else if ((stuck * 100) / count > 90) { /* * Either there is a lot of contention on the AIL or we @@ -396,14 +382,48 @@ xfsaild_push( * continuing from where we were. */ tout = 20; - } else { - /* more to do, but wait a short while before continuing */ - tout = 10; } - *last_lsn = last_pushed_lsn; - return tout; + + /* There is more to do, requeue us. */ + queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, + msecs_to_jiffies(tout)); } +/* + * This routine is called to move the tail of the AIL forward. It does this by + * trying to flush items in the AIL whose lsns are below the given + * threshold_lsn. + * + * The push is run asynchronously in a workqueue, which means the caller needs + * to handle waiting on the async flush for space to become available. + * We don't want to interrupt any push that is in progress, hence we only queue + * work if we set the pushing bit approriately. + * + * We do this unlocked - we only need to know whether there is anything in the + * AIL at the time we are called. We don't need to access the contents of + * any of the objects, so the lock is not needed. + */ +void +xfs_trans_ail_push( + struct xfs_ail *ailp, + xfs_lsn_t threshold_lsn) +{ + xfs_log_item_t *lip; + + lip = xfs_ail_min(ailp); + if (!lip || XFS_FORCED_SHUTDOWN(ailp->xa_mount) || + XFS_LSN_CMP(threshold_lsn, ailp->xa_target) <= 0) + return; + + /* + * Ensure that the new target is noticed in push code before it clears + * the XFS_AIL_PUSHING_BIT. + */ + smp_wmb(); + ailp->xa_target = threshold_lsn; + if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) + queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); +} /* * This is to be called when an item is unlocked that may have @@ -615,7 +635,6 @@ xfs_trans_ail_init( xfs_mount_t *mp) { struct xfs_ail *ailp; - int error; ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL); if (!ailp) @@ -624,15 +643,9 @@ xfs_trans_ail_init( ailp->xa_mount = mp; INIT_LIST_HEAD(&ailp->xa_ail); spin_lock_init(&ailp->xa_lock); - error = xfsaild_start(ailp); - if (error) - goto out_free_ailp; + INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker); mp->m_ail = ailp; return 0; - -out_free_ailp: - kmem_free(ailp); - return error; } void @@ -641,7 +654,7 @@ xfs_trans_ail_destroy( { struct xfs_ail *ailp = mp->m_ail; - xfsaild_stop(ailp); + cancel_delayed_work_sync(&ailp->xa_work); kmem_free(ailp); } diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 35162c2..6ebd322 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h @@ -65,16 +65,22 @@ struct xfs_ail_cursor { struct xfs_ail { struct xfs_mount *xa_mount; struct list_head xa_ail; - uint xa_gen; - struct task_struct *xa_task; xfs_lsn_t xa_target; struct xfs_ail_cursor xa_cursors; spinlock_t xa_lock; + struct delayed_work xa_work; + xfs_lsn_t xa_last_pushed_lsn; + unsigned long xa_flags; }; +#define XFS_AIL_PUSHING_BIT 0 + /* * From xfs_trans_ail.c */ + +extern struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */ + void xfs_trans_ail_update_bulk(struct xfs_ail *ailp, struct xfs_log_item **log_items, int nr_items, xfs_lsn_t lsn) __releases(ailp->xa_lock); @@ -112,11 +118,6 @@ struct xfs_log_item *xfs_trans_ail_cursor_next(struct xfs_ail *ailp, void xfs_trans_ail_cursor_done(struct xfs_ail *ailp, struct xfs_ail_cursor *cur); -long xfsaild_push(struct xfs_ail *, xfs_lsn_t *); -void xfsaild_wakeup(struct xfs_ail *, xfs_lsn_t); -int xfsaild_start(struct xfs_ail *); -void xfsaild_stop(struct xfs_ail *); - #if BITS_PER_LONG != 64 static inline void xfs_trans_ail_copy_lsn( -- cgit v0.10.2 From cd4a3c503c185f5f0a20f04f90da0a6966dd03bd Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: clean up code layout in xfs_trans_ail.c This patch rearranges the location of functions in xfs_trans_ail.c to remove the need for forward declarations of those functions in preparation for adding new functions without the need for forward declarations. Signed-off-by: Dave Chinner Reviewed-by: Alex Elder diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index cb3aeac..8012bfb 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -30,41 +30,100 @@ struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */ -STATIC void xfs_ail_splice(struct xfs_ail *, struct list_head *, xfs_lsn_t); -STATIC void xfs_ail_delete(struct xfs_ail *, xfs_log_item_t *); -STATIC xfs_log_item_t * xfs_ail_min(struct xfs_ail *); -STATIC xfs_log_item_t * xfs_ail_next(struct xfs_ail *, xfs_log_item_t *); - #ifdef DEBUG -STATIC void xfs_ail_check(struct xfs_ail *, xfs_log_item_t *); -#else +/* + * Check that the list is sorted as it should be. + */ +STATIC void +xfs_ail_check( + struct xfs_ail *ailp, + xfs_log_item_t *lip) +{ + xfs_log_item_t *prev_lip; + + if (list_empty(&ailp->xa_ail)) + return; + + /* + * Check the next and previous entries are valid. + */ + ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); + prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail); + if (&prev_lip->li_ail != &ailp->xa_ail) + ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); + + prev_lip = list_entry(lip->li_ail.next, xfs_log_item_t, li_ail); + if (&prev_lip->li_ail != &ailp->xa_ail) + ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0); + + +#ifdef XFS_TRANS_DEBUG + /* + * Walk the list checking lsn ordering, and that every entry has the + * XFS_LI_IN_AIL flag set. This is really expensive, so only do it + * when specifically debugging the transaction subsystem. + */ + prev_lip = list_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); + list_for_each_entry(lip, &ailp->xa_ail, li_ail) { + if (&prev_lip->li_ail != &ailp->xa_ail) + ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); + ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); + prev_lip = lip; + } +#endif /* XFS_TRANS_DEBUG */ +} +#else /* !DEBUG */ #define xfs_ail_check(a,l) #endif /* DEBUG */ +/* + * Return a pointer to the first item in the AIL. If the AIL is empty, then + * return NULL. + */ +static xfs_log_item_t * +xfs_ail_min( + struct xfs_ail *ailp) +{ + if (list_empty(&ailp->xa_ail)) + return NULL; + + return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); +} + +/* + * Return a pointer to the item which follows the given item in the AIL. If + * the given item is the last item in the list, then return NULL. + */ +static xfs_log_item_t * +xfs_ail_next( + struct xfs_ail *ailp, + xfs_log_item_t *lip) +{ + if (lip->li_ail.next == &ailp->xa_ail) + return NULL; + + return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail); +} /* - * This is called by the log manager code to determine the LSN - * of the tail of the log. This is exactly the LSN of the first - * item in the AIL. If the AIL is empty, then this function - * returns 0. + * This is called by the log manager code to determine the LSN of the tail of + * the log. This is exactly the LSN of the first item in the AIL. If the AIL + * is empty, then this function returns 0. * - * We need the AIL lock in order to get a coherent read of the - * lsn of the last item in the AIL. + * We need the AIL lock in order to get a coherent read of the lsn of the last + * item in the AIL. */ xfs_lsn_t xfs_trans_ail_tail( struct xfs_ail *ailp) { - xfs_lsn_t lsn; + xfs_lsn_t lsn = 0; xfs_log_item_t *lip; spin_lock(&ailp->xa_lock); lip = xfs_ail_min(ailp); - if (lip == NULL) { - lsn = (xfs_lsn_t)0; - } else { + if (lip) lsn = lip->li_lsn; - } spin_unlock(&ailp->xa_lock); return lsn; @@ -208,6 +267,47 @@ out: } /* + * splice the log item list into the AIL at the given LSN. + */ +static void +xfs_ail_splice( + struct xfs_ail *ailp, + struct list_head *list, + xfs_lsn_t lsn) +{ + xfs_log_item_t *next_lip; + + /* If the list is empty, just insert the item. */ + if (list_empty(&ailp->xa_ail)) { + list_splice(list, &ailp->xa_ail); + return; + } + + list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) { + if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0) + break; + } + + ASSERT(&next_lip->li_ail == &ailp->xa_ail || + XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0); + + list_splice_init(list, &next_lip->li_ail); +} + +/* + * Delete the given item from the AIL. Return a pointer to the item. + */ +static void +xfs_ail_delete( + struct xfs_ail *ailp, + xfs_log_item_t *lip) +{ + xfs_ail_check(ailp, lip); + list_del(&lip->li_ail); + xfs_trans_ail_cursor_clear(ailp, lip); +} + +/* * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself * to run at a later time if there is more work to do to complete the push. */ @@ -657,121 +757,3 @@ xfs_trans_ail_destroy( cancel_delayed_work_sync(&ailp->xa_work); kmem_free(ailp); } - -/* - * splice the log item list into the AIL at the given LSN. - */ -STATIC void -xfs_ail_splice( - struct xfs_ail *ailp, - struct list_head *list, - xfs_lsn_t lsn) -{ - xfs_log_item_t *next_lip; - - /* - * If the list is empty, just insert the item. - */ - if (list_empty(&ailp->xa_ail)) { - list_splice(list, &ailp->xa_ail); - return; - } - - list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) { - if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0) - break; - } - - ASSERT((&next_lip->li_ail == &ailp->xa_ail) || - (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0)); - - list_splice_init(list, &next_lip->li_ail); - return; -} - -/* - * Delete the given item from the AIL. Return a pointer to the item. - */ -STATIC void -xfs_ail_delete( - struct xfs_ail *ailp, - xfs_log_item_t *lip) -{ - xfs_ail_check(ailp, lip); - list_del(&lip->li_ail); - xfs_trans_ail_cursor_clear(ailp, lip); -} - -/* - * Return a pointer to the first item in the AIL. - * If the AIL is empty, then return NULL. - */ -STATIC xfs_log_item_t * -xfs_ail_min( - struct xfs_ail *ailp) -{ - if (list_empty(&ailp->xa_ail)) - return NULL; - - return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); -} - -/* - * Return a pointer to the item which follows - * the given item in the AIL. If the given item - * is the last item in the list, then return NULL. - */ -STATIC xfs_log_item_t * -xfs_ail_next( - struct xfs_ail *ailp, - xfs_log_item_t *lip) -{ - if (lip->li_ail.next == &ailp->xa_ail) - return NULL; - - return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail); -} - -#ifdef DEBUG -/* - * Check that the list is sorted as it should be. - */ -STATIC void -xfs_ail_check( - struct xfs_ail *ailp, - xfs_log_item_t *lip) -{ - xfs_log_item_t *prev_lip; - - if (list_empty(&ailp->xa_ail)) - return; - - /* - * Check the next and previous entries are valid. - */ - ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); - prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail); - if (&prev_lip->li_ail != &ailp->xa_ail) - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); - - prev_lip = list_entry(lip->li_ail.next, xfs_log_item_t, li_ail); - if (&prev_lip->li_ail != &ailp->xa_ail) - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0); - - -#ifdef XFS_TRANS_DEBUG - /* - * Walk the list checking lsn ordering, and that every entry has the - * XFS_LI_IN_AIL flag set. This is really expensive, so only do it - * when specifically debugging the transaction subsystem. - */ - prev_lip = list_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); - list_for_each_entry(lip, &ailp->xa_ail, li_ail) { - if (&prev_lip->li_ail != &ailp->xa_ail) - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); - ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); - prev_lip = lip; - } -#endif /* XFS_TRANS_DEBUG */ -} -#endif /* DEBUG */ -- cgit v0.10.2 From fd074841cfe01b006465fb9388091012585e8dfb Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: push the AIL from memory reclaim and periodic sync When we are short on memory, we want to expedite the cleaning of dirty objects. Hence when we run short on memory, we need to kick the AIL flushing into action to clean as many dirty objects as quickly as possible. To implement this, sample the lsn of the log item at the head of the AIL and use that as the push target for the AIL flush. Further, we keep items in the AIL that are dirty that are not tracked any other way, so we can get objects sitting in the AIL that don't get written back until the AIL is pushed. Hence to get the filesystem to the idle state, we might need to push the AIL to flush out any remaining dirty objects sitting in the AIL. This requires the same push mechanism as the reclaim push. This patch also renames xfs_trans_ail_tail() to xfs_ail_min_lsn() to match the new xfs_ail_max_lsn() function introduced in this patch. Similarly for xfs_trans_ail_push -> xfs_ail_push. Signed-off-by: Dave Chinner Reviewed-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index debe282..9ad9560 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -22,6 +22,7 @@ #include "xfs_log.h" #include "xfs_inum.h" #include "xfs_trans.h" +#include "xfs_trans_priv.h" #include "xfs_sb.h" #include "xfs_ag.h" #include "xfs_mount.h" @@ -462,6 +463,9 @@ xfs_sync_worker( else xfs_log_force(mp, 0); error = xfs_qm_sync(mp, SYNC_TRYLOCK); + + /* start pushing all the metadata that is currently dirty */ + xfs_ail_push_all(mp->m_ail); } /* queue us up again */ @@ -1027,8 +1031,9 @@ xfs_reclaim_inode_shrink( mp = container_of(shrink, struct xfs_mount, m_inode_shrink); if (nr_to_scan) { - /* kick background reclaimer */ + /* kick background reclaimer and push the AIL */ xfs_syncd_queue_reclaim(mp); + xfs_ail_push_all(mp->m_ail); if (!(gfp_mask & __GFP_FS)) return -1; diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 25efa9b..2464316 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -761,7 +761,7 @@ xfs_log_need_covered(xfs_mount_t *mp) break; case XLOG_STATE_COVER_NEED: case XLOG_STATE_COVER_NEED2: - if (!xfs_trans_ail_tail(log->l_ailp) && + if (!xfs_ail_min_lsn(log->l_ailp) && xlog_iclogs_empty(log)) { if (log->l_covered_state == XLOG_STATE_COVER_NEED) log->l_covered_state = XLOG_STATE_COVER_DONE; @@ -801,7 +801,7 @@ xlog_assign_tail_lsn( xfs_lsn_t tail_lsn; struct log *log = mp->m_log; - tail_lsn = xfs_trans_ail_tail(mp->m_ail); + tail_lsn = xfs_ail_min_lsn(mp->m_ail); if (!tail_lsn) tail_lsn = atomic64_read(&log->l_last_sync_lsn); @@ -1239,7 +1239,7 @@ xlog_grant_push_ail( * the filesystem is shutting down. */ if (!XLOG_FORCED_SHUTDOWN(log)) - xfs_trans_ail_push(log->l_ailp, threshold_lsn); + xfs_ail_push(log->l_ailp, threshold_lsn); } /* diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 8012bfb..acdb92f 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -90,6 +90,20 @@ xfs_ail_min( return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); } + /* + * Return a pointer to the last item in the AIL. If the AIL is empty, then + * return NULL. + */ +static xfs_log_item_t * +xfs_ail_max( + struct xfs_ail *ailp) +{ + if (list_empty(&ailp->xa_ail)) + return NULL; + + return list_entry(ailp->xa_ail.prev, xfs_log_item_t, li_ail); +} + /* * Return a pointer to the item which follows the given item in the AIL. If * the given item is the last item in the list, then return NULL. @@ -114,7 +128,7 @@ xfs_ail_next( * item in the AIL. */ xfs_lsn_t -xfs_trans_ail_tail( +xfs_ail_min_lsn( struct xfs_ail *ailp) { xfs_lsn_t lsn = 0; @@ -130,6 +144,25 @@ xfs_trans_ail_tail( } /* + * Return the maximum lsn held in the AIL, or zero if the AIL is empty. + */ +static xfs_lsn_t +xfs_ail_max_lsn( + struct xfs_ail *ailp) +{ + xfs_lsn_t lsn = 0; + xfs_log_item_t *lip; + + spin_lock(&ailp->xa_lock); + lip = xfs_ail_max(ailp); + if (lip) + lsn = lip->li_lsn; + spin_unlock(&ailp->xa_lock); + + return lsn; +} + +/* * AIL traversal cursor initialisation. * * The cursor keeps track of where our current traversal is up @@ -504,7 +537,7 @@ xfs_ail_worker( * any of the objects, so the lock is not needed. */ void -xfs_trans_ail_push( +xfs_ail_push( struct xfs_ail *ailp, xfs_lsn_t threshold_lsn) { @@ -526,6 +559,19 @@ xfs_trans_ail_push( } /* + * Push out all items in the AIL immediately + */ +void +xfs_ail_push_all( + struct xfs_ail *ailp) +{ + xfs_lsn_t threshold_lsn = xfs_ail_max_lsn(ailp); + + if (threshold_lsn) + xfs_ail_push(ailp, threshold_lsn); +} + +/* * This is to be called when an item is unlocked that may have * been in the AIL. It will wake up the first member of the AIL * wait list if this item's unlocking might allow it to progress. diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 6ebd322..6b164e9 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h @@ -104,12 +104,13 @@ xfs_trans_ail_delete( xfs_trans_ail_delete_bulk(ailp, &lip, 1); } -void xfs_trans_ail_push(struct xfs_ail *, xfs_lsn_t); +void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); +void xfs_ail_push_all(struct xfs_ail *); +xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp); + void xfs_trans_unlocked_item(struct xfs_ail *, xfs_log_item_t *); -xfs_lsn_t xfs_trans_ail_tail(struct xfs_ail *ailp); - struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp, struct xfs_ail_cursor *cur, xfs_lsn_t lsn); -- cgit v0.10.2 From be65b18a10e62321c5ba09a1dc0f70babeb0eba1 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: catch bad block numbers freeing extents. A fuzzed filesystem crashed a kernel when freeing an extent with a block number beyond the end of the filesystem. Convert all the debug asserts in xfs_free_extent() to active checks so that we catch bad extents and return that the filesytsem is corrupted rather than crashing. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4bc3c64..27d64d7 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -2395,17 +2395,33 @@ xfs_free_extent( memset(&args, 0, sizeof(xfs_alloc_arg_t)); args.tp = tp; args.mp = tp->t_mountp; + + /* + * validate that the block number is legal - the enables us to detect + * and handle a silent filesystem corruption rather than crashing. + */ args.agno = XFS_FSB_TO_AGNO(args.mp, bno); - ASSERT(args.agno < args.mp->m_sb.sb_agcount); + if (args.agno >= args.mp->m_sb.sb_agcount) + return EFSCORRUPTED; + args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); + if (args.agbno >= args.mp->m_sb.sb_agblocks) + return EFSCORRUPTED; + args.pag = xfs_perag_get(args.mp, args.agno); - if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) + ASSERT(args.pag); + + error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); + if (error) goto error0; -#ifdef DEBUG - ASSERT(args.agbp != NULL); - ASSERT((args.agbno + len) <= - be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)); -#endif + + /* validate the extent size is legal now we have the agf locked */ + if (args.agbno + len > + be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) { + error = EFSCORRUPTED; + goto error0; + } + error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); error0: xfs_perag_put(args.pag); -- cgit v0.10.2 From da8a1a4a4dfc1ead12c343b992fc8300a22d33d0 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Fri, 8 Apr 2011 12:45:07 +1000 Subject: xfs: convert log tail checking to a warning On the Power platform, the log tail debug checks fire excessively causing the system to panic early in testing. The debug checks are known to be racy, though on x86_64 there is no evidence that they trigger at all. We want to keep the checks active on debug systems to alert us to problems with log space accounting, but we need to reduce the impact of a racy check on testing on the Power platform. As a result, convert the ASSERT conditions to warnings, and allow them to fire only once per filesystem mount. This will prevent false positives from interfering with testing, whilst still providing us with the indication that they may be a problem with log space accounting should that occur. Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Reviewed-by: Alex Elder diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 2464316..b612ce4 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -3407,6 +3407,17 @@ xlog_verify_dest_ptr( xfs_emerg(log->l_mp, "%s: invalid ptr", __func__); } +/* + * Check to make sure the grant write head didn't just over lap the tail. If + * the cycles are the same, we can't be overlapping. Otherwise, make sure that + * the cycles differ by exactly one and check the byte count. + * + * This check is run unlocked, so can give false positives. Rather than assert + * on failures, use a warn-once flag and a panic tag to allow the admin to + * determine if they want to panic the machine when such an error occurs. For + * debug kernels this will have the same effect as using an assert but, unlinke + * an assert, it can be turned off at runtime. + */ STATIC void xlog_verify_grant_tail( struct log *log) @@ -3414,17 +3425,22 @@ xlog_verify_grant_tail( int tail_cycle, tail_blocks; int cycle, space; - /* - * Check to make sure the grant write head didn't just over lap the - * tail. If the cycles are the same, we can't be overlapping. - * Otherwise, make sure that the cycles differ by exactly one and - * check the byte count. - */ xlog_crack_grant_head(&log->l_grant_write_head, &cycle, &space); xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks); if (tail_cycle != cycle) { - ASSERT(cycle - 1 == tail_cycle); - ASSERT(space <= BBTOB(tail_blocks)); + if (cycle - 1 != tail_cycle && + !(log->l_flags & XLOG_TAIL_WARN)) { + xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, + "%s: cycle - 1 != tail_cycle", __func__); + log->l_flags |= XLOG_TAIL_WARN; + } + + if (space > BBTOB(tail_blocks) && + !(log->l_flags & XLOG_TAIL_WARN)) { + xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, + "%s: space > BBTOB(tail_blocks)", __func__); + log->l_flags |= XLOG_TAIL_WARN; + } } } diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 15dbf1f..bc988d4 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -144,6 +144,7 @@ static inline uint xlog_get_client_id(__be32 i) #define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ #define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being shutdown */ +#define XLOG_TAIL_WARN 0x10 /* log tail verify warning issued */ #ifdef __KERNEL__ /* -- cgit v0.10.2 From ab6dc30da55d262c54ae12e47e4a2e4372e39fbf Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 6 Apr 2011 23:24:42 +0000 Subject: mlx4: Sensing link type at device initialization When bringing the port up, performing a SENSE_PORT command To try and check to which physical link type (IB or Ethernet) the physical port is connected. In case there is no valid link partner, the port will come up as its supported default. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 62fa7ee..3814fc9 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -944,6 +944,10 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) } for (port = 1; port <= dev->caps.num_ports; port++) { + enum mlx4_port_type port_type = 0; + mlx4_SENSE_PORT(dev, port, &port_type); + if (port_type) + dev->caps.port_type[port] = port_type; ib_port_default_caps = 0; err = mlx4_get_port_ib_caps(dev, port, &ib_port_default_caps); if (err) @@ -958,6 +962,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) goto err_mcg_table_free; } } + mlx4_set_port_mask(dev); return 0; diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index c1e0e5f..dd7d745 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -431,6 +431,8 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); void mlx4_handle_catas_err(struct mlx4_dev *dev); +int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, + enum mlx4_port_type *type); void mlx4_do_sense_ports(struct mlx4_dev *dev, enum mlx4_port_type *stype, enum mlx4_port_type *defaults); diff --git a/drivers/net/mlx4/sense.c b/drivers/net/mlx4/sense.c index 015fbe7..e2337a7 100644 --- a/drivers/net/mlx4/sense.c +++ b/drivers/net/mlx4/sense.c @@ -38,8 +38,8 @@ #include "mlx4.h" -static int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, - enum mlx4_port_type *type) +int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, + enum mlx4_port_type *type) { u64 out_param; int err = 0; -- cgit v0.10.2 From 60b1809f7e2ea2620aa548e1c866066756bdd1d2 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 6 Apr 2011 23:25:45 +0000 Subject: mlx4_en: Restoring RX buffer pointer in case of failure If not done, second attempt to open the RX ring would cause memory corruption. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 05998ee..98d4ce0 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -345,6 +345,8 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) err = mlx4_en_init_allocator(priv, ring); if (err) { en_err(priv, "Failed initializing ring allocator\n"); + if (ring->stride <= TXBB_SIZE) + ring->buf -= TXBB_SIZE; ring_ind--; goto err_allocator; } @@ -369,6 +371,8 @@ err_buffers: ring_ind = priv->rx_ring_num - 1; err_allocator: while (ring_ind >= 0) { + if (priv->rx_ring[ring_ind].stride <= TXBB_SIZE) + priv->rx_ring[ring_ind].buf -= TXBB_SIZE; mlx4_en_destroy_allocator(priv, &priv->rx_ring[ring_ind]); ring_ind--; } -- cgit v0.10.2 From ecb697c16c1718ae97bb73ce41a5d5ac2aed29ec Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Apr 2011 12:55:44 +0000 Subject: xfs: fix variable set but not used warnings GCC 4.6 now warnings about variables set but not used. Fix the trivially fixable warnings of this sort. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index d917146..2eef165 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -293,7 +293,6 @@ xfs_buf_allocate_memory( size_t nbytes, offset; gfp_t gfp_mask = xb_to_gfp(flags); unsigned short page_count, i; - pgoff_t first; xfs_off_t end; int error; @@ -333,7 +332,6 @@ use_alloc_page: return error; offset = bp->b_offset; - first = bp->b_file_offset >> PAGE_SHIFT; bp->b_flags |= _XBF_PAGES; for (i = 0; i < bp->b_page_count; i++) { diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 254ee06..69228aa 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -461,12 +461,10 @@ xfs_qm_dqflush_all( struct xfs_quotainfo *q = mp->m_quotainfo; int recl; struct xfs_dquot *dqp; - int niters; int error; if (!q) return 0; - niters = 0; again: mutex_lock(&q->qi_dqlist_lock); list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) { @@ -1314,14 +1312,9 @@ xfs_qm_dqiter_bufs( { xfs_buf_t *bp; int error; - int notcommitted; - int incr; int type; ASSERT(blkcnt > 0); - notcommitted = 0; - incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? - XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER : (flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP); error = 0; diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index c9446f1..567b29b 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h @@ -65,11 +65,6 @@ extern kmem_zone_t *qm_dqtrxzone; * block in the dquot/xqm code. */ #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 -/* - * When doing a quotacheck, we log dquot clusters of this many FSBs at most - * in a single transaction. We don't want to ask for too huge a log reservation. - */ -#define XFS_QM_MAX_DQCLUSTER_LOGSZ 3 typedef xfs_dqhash_t xfs_dqlist_t; diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index c82f067..c79859e 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -313,14 +313,12 @@ xfs_qm_scall_quotaon( { int error; uint qf; - uint accflags; __int64_t sbflags; flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); /* * Switching on quota accounting must be done at mount time. */ - accflags = flags & XFS_ALL_QUOTA_ACCT; flags &= ~(XFS_ALL_QUOTA_ACCT); sbflags = 0; diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index dc1882a..751e94f 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -204,7 +204,6 @@ xfs_bulkstat( xfs_agi_t *agi; /* agi header data */ xfs_agino_t agino; /* inode # in allocation group */ xfs_agnumber_t agno; /* allocation group number */ - xfs_daddr_t bno; /* inode cluster start daddr */ int chunkidx; /* current index into inode chunk */ int clustidx; /* current index into inode cluster */ xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ @@ -463,7 +462,6 @@ xfs_bulkstat( mp->m_sb.sb_inopblog); } ino = XFS_AGINO_TO_INO(mp, agno, agino); - bno = XFS_AGB_TO_DADDR(mp, agno, agbno); /* * Skip if this inode is free. */ -- cgit v0.10.2 From 957935dcd8e11d6f789b4ed769b376040e15565b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 2 Apr 2011 18:13:40 +0000 Subject: xfs: fix xfs_debug warnings For a CONFIG_XFS_DEBUG=n build gcc complains about statements with no effect in xfs_debug: fs/xfs/quota/xfs_qm_syscalls.c: In function 'xfs_qm_scall_trunc_qfiles': fs/xfs/quota/xfs_qm_syscalls.c:291:3: warning: statement with no effect The reason for that is that the various new xfs message functions have a return value which is never used, and in case of the non-debug build xfs_debug the macro evaluates to a plain 0 which produces the above warnings. This can be fixed by turning xfs_debug into an inline function instead of a macro, but in addition to that I've also changed all the message helpers to return void as we never use their return values. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_message.c b/fs/xfs/linux-2.6/xfs_message.c index 508e06f..3ca7956 100644 --- a/fs/xfs/linux-2.6/xfs_message.c +++ b/fs/xfs/linux-2.6/xfs_message.c @@ -28,53 +28,47 @@ /* * XFS logging functions */ -static int +static void __xfs_printk( const char *level, const struct xfs_mount *mp, struct va_format *vaf) { if (mp && mp->m_fsname) - return printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); - return printk("%sXFS: %pV\n", level, vaf); + printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); + printk("%sXFS: %pV\n", level, vaf); } -int xfs_printk( +void xfs_printk( const char *level, const struct xfs_mount *mp, const char *fmt, ...) { struct va_format vaf; va_list args; - int r; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - r = __xfs_printk(level, mp, &vaf); + __xfs_printk(level, mp, &vaf); va_end(args); - - return r; } #define define_xfs_printk_level(func, kern_level) \ -int func(const struct xfs_mount *mp, const char *fmt, ...) \ +void func(const struct xfs_mount *mp, const char *fmt, ...) \ { \ struct va_format vaf; \ va_list args; \ - int r; \ \ va_start(args, fmt); \ \ vaf.fmt = fmt; \ vaf.va = &args; \ \ - r = __xfs_printk(kern_level, mp, &vaf); \ + __xfs_printk(kern_level, mp, &vaf); \ va_end(args); \ - \ - return r; \ } \ define_xfs_printk_level(xfs_emerg, KERN_EMERG); @@ -88,7 +82,7 @@ define_xfs_printk_level(xfs_info, KERN_INFO); define_xfs_printk_level(xfs_debug, KERN_DEBUG); #endif -int +void xfs_alert_tag( const struct xfs_mount *mp, int panic_tag, @@ -97,7 +91,6 @@ xfs_alert_tag( struct va_format vaf; va_list args; int do_panic = 0; - int r; if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { xfs_printk(KERN_ALERT, mp, @@ -110,12 +103,10 @@ xfs_alert_tag( vaf.fmt = fmt; vaf.va = &args; - r = __xfs_printk(KERN_ALERT, mp, &vaf); + __xfs_printk(KERN_ALERT, mp, &vaf); va_end(args); BUG_ON(do_panic); - - return r; } void diff --git a/fs/xfs/linux-2.6/xfs_message.h b/fs/xfs/linux-2.6/xfs_message.h index e77ffa1..f1b3fc1 100644 --- a/fs/xfs/linux-2.6/xfs_message.h +++ b/fs/xfs/linux-2.6/xfs_message.h @@ -3,32 +3,34 @@ struct xfs_mount; -extern int xfs_printk(const char *level, const struct xfs_mount *mp, +extern void xfs_printk(const char *level, const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); -extern int xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -extern int xfs_alert(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_alert(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -extern int xfs_alert_tag(const struct xfs_mount *mp, int tag, +extern void xfs_alert_tag(const struct xfs_mount *mp, int tag, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); -extern int xfs_crit(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_crit(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -extern int xfs_err(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_err(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -extern int xfs_warn(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_warn(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -extern int xfs_notice(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_notice(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -extern int xfs_info(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_info(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); #ifdef DEBUG -extern int xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) +extern void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); #else -#define xfs_debug(mp, fmt, ...) (0) +static inline void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) +{ +} #endif extern void assfail(char *expr, char *f, int l); -- cgit v0.10.2 From a1b7ea5d58c53c13f082110e535d98bc4e8e5cfe Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 30 Mar 2011 11:05:09 +0000 Subject: xfs: use proper interfaces for on-stack plugging Add proper blk_start_plug/blk_finish_plug pairs for the two places where we issue buffer I/O, and remove the blk_flush_plug in xfs_buf_lock and xfs_buf_iowait, given that context switches already flush the per-process plugging lists. Signed-off-by: Christoph Hellwig Signed-off-by: Alex Elder diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 2eef165..478ca15 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -915,8 +915,6 @@ xfs_buf_lock( if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE)) xfs_log_force(bp->b_target->bt_mount, 0); - if (atomic_read(&bp->b_io_remaining)) - blk_flush_plug(current); down(&bp->b_sema); XB_SET_OWNER(bp); @@ -1305,8 +1303,6 @@ xfs_buf_iowait( { trace_xfs_buf_iowait(bp, _RET_IP_); - if (atomic_read(&bp->b_io_remaining)) - blk_flush_plug(current); wait_for_completion(&bp->b_iowait); trace_xfs_buf_iowait_done(bp, _RET_IP_); @@ -1743,8 +1739,8 @@ xfsbufd( do { long age = xfs_buf_age_centisecs * msecs_to_jiffies(10); long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10); - int count = 0; struct list_head tmp; + struct blk_plug plug; if (unlikely(freezing(current))) { set_bit(XBT_FORCE_SLEEP, &target->bt_flags); @@ -1760,16 +1756,15 @@ xfsbufd( xfs_buf_delwri_split(target, &tmp, age); list_sort(NULL, &tmp, xfs_buf_cmp); + + blk_start_plug(&plug); while (!list_empty(&tmp)) { struct xfs_buf *bp; bp = list_first_entry(&tmp, struct xfs_buf, b_list); list_del_init(&bp->b_list); xfs_bdstrat_cb(bp); - count++; } - if (count) - blk_flush_plug(current); - + blk_finish_plug(&plug); } while (!kthread_should_stop()); return 0; @@ -1789,6 +1784,7 @@ xfs_flush_buftarg( int pincount = 0; LIST_HEAD(tmp_list); LIST_HEAD(wait_list); + struct blk_plug plug; xfs_buf_runall_queues(xfsconvertd_workqueue); xfs_buf_runall_queues(xfsdatad_workqueue); @@ -1803,6 +1799,8 @@ xfs_flush_buftarg( * we do that after issuing all the IO. */ list_sort(NULL, &tmp_list, xfs_buf_cmp); + + blk_start_plug(&plug); while (!list_empty(&tmp_list)) { bp = list_first_entry(&tmp_list, struct xfs_buf, b_list); ASSERT(target == bp->b_target); @@ -1813,10 +1811,10 @@ xfs_flush_buftarg( } xfs_bdstrat_cb(bp); } + blk_finish_plug(&plug); if (wait) { - /* Expedite and wait for IO to complete. */ - blk_flush_plug(current); + /* Wait for IO to complete. */ while (!list_empty(&wait_list)) { bp = list_first_entry(&wait_list, struct xfs_buf, b_list); -- cgit v0.10.2 From 0a0883c8433c743dad0a4d9ebe2717558f2c209e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Apr 2011 17:57:23 +1000 Subject: i915: restore only the mode of this driver on lastclose This has always used a big hammer, but that hammer is probably too big, I'm also not sure its necessary but at least this should be safe. Should fix: https://bugzilla.kernel.org/show_bug.cgi?id=23592 Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7273037..12876f2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_fb_helper_restore(); + intel_fb_restore_mode(dev); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f5b0d83..1d20712 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,4 +338,5 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); +extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 5127827..96a45c4 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,3 +264,19 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } + +void intel_fb_restore_mode(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, i; + + if (!dev_priv->fbdev) + return; + + for (i = 0; i < dev_priv->fbdev->helper.crtc_count; i++) { + struct drm_mode_set *mode_set = &dev_priv->fbdev->helper.crtc_info[i].mode_set; + ret = drm_crtc_helper_set_config(mode_set); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); + } +} -- cgit v0.10.2 From dc66b325f161bb651493c7d96ad44876b629cf6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 7 Apr 2011 16:17:47 +0200 Subject: radeon: Fix KMS CP writeback on big endian machines. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is necessary even with PCI(e) GART, and it makes writeback work even with AGP on my PowerBook. Might still be unreliable with older revisions of UniNorth and other AGP bridges though. Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 9e59868..bbcd1dd 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -79,7 +79,7 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev) scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; else scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; - seq = rdev->wb.wb[scratch_index/4]; + seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]); } else seq = RREG32(rdev->fence_drv.scratch_reg); if (seq != rdev->fence_drv.last_seq) { diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index bbc9cd8..c6776e4 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -248,7 +248,7 @@ void radeon_ib_pool_fini(struct radeon_device *rdev) void radeon_ring_free_size(struct radeon_device *rdev) { if (rdev->wb.enabled) - rdev->cp.rptr = rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4]; + rdev->cp.rptr = le32_to_cpu(rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4]); else { if (rdev->family >= CHIP_R600) rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); -- cgit v0.10.2 From 88a2b75cceba1fdbc1fdb70c7c8cd2b40da3d95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 7 Apr 2011 16:20:49 +0200 Subject: drm/radeon: Fix KMS legacy backlight support if CONFIG_BACKLIGHT_CLASS_DEVICE=m. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 5b54268..2f46e0c 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -269,7 +269,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { .disable = radeon_legacy_encoder_disable, }; -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) #define MAX_RADEON_LEVEL 0xFF -- cgit v0.10.2 From 9bb09fa1b5b07459279301ac6220d575f307597b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 7 Apr 2011 10:31:25 -0400 Subject: drm/radeon/kms: pll tweaks for rv6xx Prefer minm over maxp. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=35994 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index b41ec59..9d516a8 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -531,6 +531,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + if ((rdev->family == CHIP_R600) || + (rdev->family == CHIP_RV610) || + (rdev->family == CHIP_RV630) || + (rdev->family == CHIP_RV670)) + pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; } else { pll->flags |= RADEON_PLL_LEGACY; -- cgit v0.10.2 From d4864d604a8d29a0d6a13a8d882be6e21c498c22 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 6 Apr 2011 13:44:10 -0400 Subject: drm/radeon/kms: make radeon i2c put/get bytes less noisy Switch some errors to debug output. These are generally harmless and tend to confuse users. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index ded2a45..ccbabf7 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1062,7 +1062,7 @@ void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus, *val = in_buf[0]; DRM_DEBUG("val = 0x%02x\n", *val); } else { - DRM_ERROR("i2c 0x%02x 0x%02x read failed\n", + DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n", addr, *val); } } @@ -1084,7 +1084,7 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus, out_buf[1] = val; if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1) - DRM_ERROR("i2c 0x%02x 0x%02x write failed\n", + DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n", addr, val); } -- cgit v0.10.2 From 23fcf2ec93fb8573a653408316af599939ff9a8e Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 28 Mar 2011 15:15:09 +0800 Subject: nfsd4: fix oops on lock failure Lock stateid's can have access_bmap 0 if they were only partially initialized (due to a failed lock request); handle that case in free_generic_stateid. ------------[ cut here ]------------ kernel BUG at fs/nfsd/nfs4state.c:380! invalid opcode: 0000 [#1] SMP last sysfs file: /sys/kernel/mm/ksm/run Modules linked in: nfs fscache md4 nls_utf8 cifs ip6table_filter ip6_tables ebtable_nat ebtables ipt_MASQUERADE iptable_nat nf_nat bridge stp llc nfsd lockd nfs_acl auth_rpcgss sunrpc ipv6 ppdev parport_pc parport pcnet32 mii pcspkr microcode i2c_piix4 BusLogic floppy [last unloaded: mperf] Pid: 1468, comm: nfsd Not tainted 2.6.38+ #120 VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform EIP: 0060:[] EFLAGS: 00010297 CPU: 0 EIP is at nfs4_access_to_omode+0x1c/0x29 [nfsd] EAX: ffffffff EBX: dd758120 ECX: 00000000 EDX: 00000004 ESI: dd758120 EDI: ddfe657c EBP: dd54dde0 ESP: dd54dde0 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process nfsd (pid: 1468, ti=dd54c000 task=ddc92580 task.ti=dd54c000) Stack: dd54ddf0 e24f19ca 00000000 ddfe6560 dd54de08 e24f1a5d dd758130 deee3a20 ddfe6560 31270000 dd54df1c e24f52fd 0000000f dd758090 e2505dd0 0be304cf dbb51d68 0000000e ddfe657c ddcd8020 dd758130 dd758128 dd7580d8 dd54de68 Call Trace: [] free_generic_stateid+0x1c/0x3e [nfsd] [] release_lockowner+0x71/0x8a [nfsd] [] nfsd4_lock+0x617/0x66c [nfsd] [] ? nfsd_setuser+0x199/0x1bb [nfsd] [] ? nfsd_setuser_and_check_port+0x65/0x81 [nfsd] [] ? _cond_resched+0x8/0x1c [] ? slab_pre_alloc_hook.clone.33+0x23/0x27 [] ? kmem_cache_alloc+0x1a/0xd2 [] ? __call_rcu+0xd7/0xdd [] ? fh_verify+0x401/0x452 [nfsd] [] ? nfsd4_encode_operation+0x52/0x117 [nfsd] [] ? nfsd4_putfh+0x33/0x3b [nfsd] [] ? nfsd4_delegreturn+0xd4/0xd4 [nfsd] [] nfsd4_proc_compound+0x1ea/0x33e [nfsd] [] nfsd_dispatch+0xd1/0x1a5 [nfsd] [] svc_process_common+0x282/0x46f [sunrpc] [] svc_process+0xdc/0xfa [sunrpc] [] nfsd+0xd6/0x115 [nfsd] [] ? nfsd_shutdown+0x24/0x24 [nfsd] [] kthread+0x62/0x67 [] ? kthread_worker_fn+0x114/0x114 [] kernel_thread_helper+0x6/0x10 Code: eb 05 b8 00 00 27 4f 8d 65 f4 5b 5e 5f 5d c3 83 e0 03 55 83 f8 02 89 e5 74 17 83 f8 03 74 05 48 75 09 eb 09 b8 02 00 00 00 eb 0b <0f> 0b 31 c0 eb 05 b8 01 00 00 00 5d c3 55 89 e5 57 56 89 d6 8d EIP: [] nfs4_access_to_omode+0x1c/0x29 [nfsd] SS:ESP 0068:dd54dde0 ---[ end trace 2b0bf6c6557cb284 ]--- The trace route is: -> nfsd4_lock() -> if (lock->lk_is_new) { -> alloc_init_lock_stateid() 3739: stp->st_access_bmap = 0; ->if (status && lock->lk_is_new && lock_sop) -> release_lockowner() -> free_generic_stateid() -> nfs4_access_bmap_to_omode() -> nfs4_access_to_omode() 380: BUG(); ***** This problem was introduced by 0997b173609b9229ece28941c118a2a9b278796e. Reported-by: Mi Jinlong Tested-by: Mi Jinlong Signed-off-by: J. Bruce Fields diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index fbde6f7..8e3c407 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -397,10 +397,13 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp) static void free_generic_stateid(struct nfs4_stateid *stp) { - int oflag = nfs4_access_bmap_to_omode(stp); + int oflag; - nfs4_file_put_access(stp->st_file, oflag); - put_nfs4_file(stp->st_file); + if (stp->st_access_bmap) { + oflag = nfs4_access_bmap_to_omode(stp); + nfs4_file_put_access(stp->st_file, oflag); + put_nfs4_file(stp->st_file); + } kmem_cache_free(stateid_slab, stp); } -- cgit v0.10.2 From 88edaa415966af965bb7eb7056d8b58145462c8e Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Sun, 10 Apr 2011 18:59:27 -0700 Subject: net: Add support for SMSC LAN9530, LAN9730 and LAN89530 This patch adds support for SMSC's LAN9530, LAN9730 and LAN89530 USB ethernet controllers to the existing smsc95xx driver by adding their new USB VID/PID pairs. Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 727874d..47a6c87 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1313,6 +1313,21 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0424, 0x9909), .driver_info = (unsigned long) &smsc95xx_info, }, + { + /* SMSC LAN9530 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9530), + .driver_info = (unsigned long) &smsc95xx_info, + }, + { + /* SMSC LAN9730 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9730), + .driver_info = (unsigned long) &smsc95xx_info, + }, + { + /* SMSC LAN89530 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9E08), + .driver_info = (unsigned long) &smsc95xx_info, + }, { }, /* END */ }; MODULE_DEVICE_TABLE(usb, products); -- cgit v0.10.2 From 0893ed458b4b1d7c7667ca7ffb8b11febe7e7e6c Mon Sep 17 00:00:00 2001 From: Curt Wohlgemuth Date: Sun, 10 Apr 2011 22:05:31 -0400 Subject: ext4: sync the directory inode in ext4_sync_parent() ext4 has taken the stance that, in the absence of a journal, when an fsync/fdatasync of an inode is done, the parent directory should be sync'ed if this inode entry is new. ext4_sync_parent(), which implements this, does indeed sync the dirent pages for parent directories, but it does not sync the directory *inode*. This patch fixes this. Also now return error status from ext4_sync_parent(). I tested this using a power fail test, which panics a machine running a file server getting requests from a client. Without this patch, on about every other test run, the server is missing many, many files that had been synced. With this patch, on > 6 runs, I see zero files being lost. Google-Bug-Id: 4179519 Signed-off-by: Curt Wohlgemuth Signed-off-by: "Theodore Ts'o" diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 7f74019..b1f9b5f 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c @@ -125,9 +125,11 @@ extern int ext4_flush_completed_IO(struct inode *inode) * the parent directory's parent as well, and so on recursively, if * they are also freshly created. */ -static void ext4_sync_parent(struct inode *inode) +static int ext4_sync_parent(struct inode *inode) { + struct writeback_control wbc; struct dentry *dentry = NULL; + int ret = 0; while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); @@ -136,8 +138,17 @@ static void ext4_sync_parent(struct inode *inode) if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) break; inode = dentry->d_parent->d_inode; - sync_mapping_buffers(inode->i_mapping); + ret = sync_mapping_buffers(inode->i_mapping); + if (ret) + break; + memset(&wbc, 0, sizeof(wbc)); + wbc.sync_mode = WB_SYNC_ALL; + wbc.nr_to_write = 0; /* only write out the inode */ + ret = sync_inode(inode, &wbc); + if (ret) + break; } + return ret; } /* @@ -176,7 +187,7 @@ int ext4_sync_file(struct file *file, int datasync) if (!journal) { ret = generic_file_fsync(file, datasync); if (!ret && !list_empty(&inode->i_dentry)) - ext4_sync_parent(inode); + ret = ext4_sync_parent(inode); goto out; } -- cgit v0.10.2 From be4f27d324e8ddd57cc0d4d604fe85ee0425cba9 Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Sun, 10 Apr 2011 22:06:07 -0400 Subject: ext4: allow an active handle to be started when freezing ext4_journal_start_sb() should not prevent an active handle from being started due to s_frozen. Otherwise, deadlock is easy to happen, below is a situation. ================================================ freeze | truncate ================================================ | ext4_ext_truncate() freeze_super() | starts a handle sets s_frozen | | ext4_ext_truncate() | holds i_data_sem ext4_freeze() | waits for updates | | ext4_free_blocks() | calls dquot_free_block() | | dquot_free_blocks() | calls ext4_dirty_inode() | | ext4_dirty_inode() | trys to start an active | handle | | block due to s_frozen ================================================ Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Reported-by: Amir Goldstein Reviewed-by: Jan Kara Reviewed-by: Andreas Dilger diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 551cb8e..7b636ce 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -242,27 +242,44 @@ static void ext4_put_nojournal(handle_t *handle) * journal_end calls result in the superblock being marked dirty, so * that sync() will call the filesystem's write_super callback if * appropriate. + * + * To avoid j_barrier hold in userspace when a user calls freeze(), + * ext4 prevents a new handle from being started by s_frozen, which + * is in an upper layer. */ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) { journal_t *journal; + handle_t *handle; if (sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS); - vfs_check_frozen(sb, SB_FREEZE_TRANS); - /* Special case here: if the journal has aborted behind our - * backs (eg. EIO in the commit thread), then we still need to - * take the FS itself readonly cleanly. */ journal = EXT4_SB(sb)->s_journal; - if (journal) { - if (is_journal_aborted(journal)) { - ext4_abort(sb, "Detected aborted journal"); - return ERR_PTR(-EROFS); - } - return jbd2_journal_start(journal, nblocks); + handle = ext4_journal_current_handle(); + + /* + * If a handle has been started, it should be allowed to + * finish, otherwise deadlock could happen between freeze + * and others(e.g. truncate) due to the restart of the + * journal handle if the filesystem is forzen and active + * handles are not stopped. + */ + if (!handle) + vfs_check_frozen(sb, SB_FREEZE_TRANS); + + if (!journal) + return ext4_get_nojournal(); + /* + * Special case here: if the journal has aborted behind our + * backs (eg. EIO in the commit thread), then we still need to + * take the FS itself readonly cleanly. + */ + if (is_journal_aborted(journal)) { + ext4_abort(sb, "Detected aborted journal"); + return ERR_PTR(-EROFS); } - return ext4_get_nojournal(); + return jbd2_journal_start(journal, nblocks); } /* @@ -4146,6 +4163,11 @@ static int ext4_sync_fs(struct super_block *sb, int wait) /* * LVM calls this function before a (read-only) snapshot is created. This * gives us a chance to flush the journal completely and mark the fs clean. + * + * Note that only this function cannot bring a filesystem to be in a clean + * state independently, because ext4 prevents a new handle from being started + * by @sb->s_frozen, which stays in an upper layer. It thus needs help from + * the upper layer. */ static int ext4_freeze(struct super_block *sb) { -- cgit v0.10.2 From f80da1e70f1ffec3825aa0a1d0801f4896e002b6 Mon Sep 17 00:00:00 2001 From: Kazuya Mio Date: Sun, 10 Apr 2011 22:06:36 -0400 Subject: ext4: Allow indirect-block file to grow the file size to max file size We can create 4402345721856 byte file with indirect block mapping. However, if we grow an indirect-block file to the size with ftruncate(), we can see an ext4 warning. The following patch fixes this problem. How to reproduce: # dd if=/dev/zero of=/mnt/mp1/hoge bs=1 count=0 seek=4402345721856 0+0 records in 0+0 records out 0 bytes (0 B) copied, 0.000221428 s, 0.0 kB/s # tail -n 1 /var/log/messages Nov 25 15:10:27 test kernel: EXT4-fs warning (device sda8): ext4_block_to_path:345: block 1074791436 > max in inode 12 Signed-off-by: Kazuya Mio Signed-off-by: "Theodore Ts'o" diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 7d11e02..5560f78 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4429,8 +4429,8 @@ void ext4_truncate(struct inode *inode) Indirect chain[4]; Indirect *partial; __le32 nr = 0; - int n; - ext4_lblk_t last_block; + int n = 0; + ext4_lblk_t last_block, max_block; unsigned blocksize = inode->i_sb->s_blocksize; trace_ext4_truncate_enter(inode); @@ -4455,14 +4455,18 @@ void ext4_truncate(struct inode *inode) last_block = (inode->i_size + blocksize-1) >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); + max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) + >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); if (inode->i_size & (blocksize - 1)) if (ext4_block_truncate_page(handle, mapping, inode->i_size)) goto out_stop; - n = ext4_block_to_path(inode, last_block, offsets, NULL); - if (n == 0) - goto out_stop; /* error */ + if (last_block != max_block) { + n = ext4_block_to_path(inode, last_block, offsets, NULL); + if (n == 0) + goto out_stop; /* error */ + } /* * OK. This truncate is going to happen. We add the inode to the @@ -4493,7 +4497,13 @@ void ext4_truncate(struct inode *inode) */ ei->i_disksize = inode->i_size; - if (n == 1) { /* direct blocks */ + if (last_block == max_block) { + /* + * It is unnecessary to free any data blocks if last_block is + * equal to the indirect block limit. + */ + goto out_unlock; + } else if (n == 1) { /* direct blocks */ ext4_free_data(handle, inode, NULL, i_data+offsets[0], i_data + EXT4_NDIR_BLOCKS); goto do_indirects; @@ -4553,6 +4563,7 @@ do_indirects: ; } +out_unlock: up_write(&ei->i_data_sem); inode->i_mtime = inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); -- cgit v0.10.2 From c8205636029fc869278c55b7336053b3e7ae3ef4 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 10 Apr 2011 22:30:07 -0400 Subject: ext4: fix data corruption regression by reverting commit 6de9843dab3f Revert commit 6de9843dab3f2a1d4d66d80aa9e5782f80977d20, since it caused a data corruption regression with BitTorrent downloads. Thanks to Damien for discovering and bisecting to find the problem commit. https://bugzilla.kernel.org/show_bug.cgi?id=32972 Reported-by: Damien Grassart Signed-off-by: "Theodore Ts'o" diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 5560f78..9c8cf81 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2502,6 +2502,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, * for partial write. */ set_buffer_new(bh); + set_buffer_mapped(bh); } return 0; } -- cgit v0.10.2 From 8faa7cf828bca1745a4ed599876567f5afc47544 Mon Sep 17 00:00:00 2001 From: "Ira W. Snyder" Date: Thu, 7 Apr 2011 10:33:03 -0700 Subject: dt/fsldma: fix build warning caused by of_platform_device changes Commit 000061245a6797d542854106463b6b20fbdcb12e, "dt/powerpc: Eliminate users of of_platform_{,un}register_driver" forgot to convert the type of structure passed into platform_device_register() when it was converted from of_platform_device_register. Fix it. Signed-off-by: Ira W. Snyder Signed-off-by: Grant Likely diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 6b39675..8a78154 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1448,7 +1448,7 @@ static const struct of_device_id fsldma_of_ids[] = { {} }; -static struct of_platform_driver fsldma_of_driver = { +static struct platform_driver fsldma_of_driver = { .driver = { .name = "fsl-elo-dma", .owner = THIS_MODULE, -- cgit v0.10.2 From b42282e5a05018ecdc0d63a4ad530b0999785912 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 11 Apr 2011 10:53:11 -0700 Subject: pci: fix PCI bus allocation alignment handling In commit 13583b16592a ("PCI: refactor io size calculation code") Ram had a thinko in the refactorization of the code: the end result used the variable 'align' for the bus alignment, but the original code used 'min_align'. Since then, another use of that 'align' variable got introduced by commit c8adf9a3e873 ("PCI: pre-allocate additional resources to devices only after successful allocation of essential resources.") Fix both of those uses to use 'min_align' as they should. Daniel Hellstrom Acked-by: Ram Pai Acked-by: Jesse Barnes Signed-off-by: Linus Torvalds diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 89d0a6a..ebf51ad 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -676,10 +676,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = align1 >> 1; align += aligns[order]; } - size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), align); + size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); size1 = !add_size ? size : calculate_memsize(size, min_size+add_size, 0, - resource_size(b_res), align); + resource_size(b_res), min_align); if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " -- cgit v0.10.2 From 1f112cee07b314e244ee9e71d9c1e6950dc13327 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Apr 2011 22:54:42 +0200 Subject: PM / Hibernate: Introduce CONFIG_HIBERNATE_CALLBACKS Xen save/restore is going to use hibernate device callbacks for quiescing devices and putting them back to normal operations and it would need to select CONFIG_HIBERNATION for this purpose. However, that also would cause the hibernate interfaces for user space to be enabled, which might confuse user space, because the Xen kernels don't support hibernation. Moreover, it would be wasteful, as it would make the Xen kernels include a substantial amount of code that they would never use. To address this issue introduce new power management Kconfig option CONFIG_HIBERNATE_CALLBACKS, such that it will only select the code that is necessary for the hibernate device callbacks to work and make CONFIG_HIBERNATION select it. Then, Xen save/restore will be able to select CONFIG_HIBERNATE_CALLBACKS without dragging the entire hibernate code along with it. Signed-off-by: Rafael J. Wysocki Tested-by: Shriram Rajagopalan diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index c00d4ca..28581f1 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c @@ -527,7 +527,7 @@ static int ibmebus_bus_pm_resume_noirq(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int ibmebus_bus_pm_freeze(struct device *dev) { @@ -665,7 +665,7 @@ static int ibmebus_bus_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define ibmebus_bus_pm_freeze NULL #define ibmebus_bus_pm_thaw NULL @@ -676,7 +676,7 @@ static int ibmebus_bus_pm_restore_noirq(struct device *dev) #define ibmebus_bus_pm_poweroff_noirq NULL #define ibmebus_bus_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ static struct dev_pm_ops ibmebus_bus_dev_pm_ops = { .prepare = ibmebus_bus_pm_prepare, diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 8210405..7025593 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -214,7 +214,7 @@ static int amba_pm_resume_noirq(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int amba_pm_freeze(struct device *dev) { @@ -352,7 +352,7 @@ static int amba_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define amba_pm_freeze NULL #define amba_pm_thaw NULL @@ -363,7 +363,7 @@ static int amba_pm_restore_noirq(struct device *dev) #define amba_pm_poweroff_noirq NULL #define amba_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f051cff..9279231 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -771,7 +771,7 @@ int __weak platform_pm_resume_noirq(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int platform_pm_freeze(struct device *dev) { @@ -909,7 +909,7 @@ static int platform_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define platform_pm_freeze NULL #define platform_pm_thaw NULL @@ -920,7 +920,7 @@ static int platform_pm_restore_noirq(struct device *dev) #define platform_pm_poweroff_noirq NULL #define platform_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 052dc53..fbc5b6e 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -233,7 +233,7 @@ static int pm_op(struct device *dev, } break; #endif /* CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS case PM_EVENT_FREEZE: case PM_EVENT_QUIESCE: if (ops->freeze) { @@ -260,7 +260,7 @@ static int pm_op(struct device *dev, suspend_report_result(ops->restore, error); } break; -#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ default: error = -EINVAL; } @@ -308,7 +308,7 @@ static int pm_noirq_op(struct device *dev, } break; #endif /* CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS case PM_EVENT_FREEZE: case PM_EVENT_QUIESCE: if (ops->freeze_noirq) { @@ -335,7 +335,7 @@ static int pm_noirq_op(struct device *dev, suspend_report_result(ops->restore_noirq, error); } break; -#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ default: error = -EINVAL; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d86ea8b..135df16 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -781,7 +781,7 @@ static int pci_pm_resume(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int pci_pm_freeze(struct device *dev) { @@ -970,7 +970,7 @@ static int pci_pm_restore(struct device *dev) return error; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define pci_pm_freeze NULL #define pci_pm_freeze_noirq NULL @@ -981,7 +981,7 @@ static int pci_pm_restore(struct device *dev) #define pci_pm_restore NULL #define pci_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 95143dd..1ac9412 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -61,7 +61,7 @@ static void xen_post_suspend(int cancelled) xen_mm_unpin_all(); } -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int xen_suspend(void *data) { struct suspend_info *si = data; @@ -173,7 +173,7 @@ out: #endif shutting_down = SHUTDOWN_INVALID; } -#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ struct shutdown_handler { const char *command; @@ -202,7 +202,7 @@ static void shutdown_handler(struct xenbus_watch *watch, { "poweroff", do_poweroff }, { "halt", do_poweroff }, { "reboot", do_reboot }, -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS { "suspend", do_suspend }, #endif {NULL, NULL}, diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 5a89e36..083ffea 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -249,6 +249,8 @@ extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); extern int hibernate(void); extern bool system_entering_hibernation(void); #else /* CONFIG_HIBERNATION */ +static inline void register_nosave_region(unsigned long b, unsigned long e) {} +static inline void register_nosave_region_late(unsigned long b, unsigned long e) {} static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } static inline void swsusp_set_page_free(struct page *p) {} static inline void swsusp_unset_page_free(struct page *p) {} @@ -297,14 +299,7 @@ static inline bool pm_wakeup_pending(void) { return false; } extern struct mutex pm_mutex; -#ifndef CONFIG_HIBERNATION -static inline void register_nosave_region(unsigned long b, unsigned long e) -{ -} -static inline void register_nosave_region_late(unsigned long b, unsigned long e) -{ -} - +#ifndef CONFIG_HIBERNATE_CALLBACKS static inline void lock_system_sleep(void) {} static inline void unlock_system_sleep(void) {} diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 4603f08..0497914 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -18,9 +18,13 @@ config SUSPEND_FREEZER Turning OFF this setting is NOT recommended! If in doubt, say Y. +config HIBERNATE_CALLBACKS + bool + config HIBERNATION bool "Hibernation (aka 'suspend to disk')" depends on SWAP && ARCH_HIBERNATION_POSSIBLE + select HIBERNATE_CALLBACKS select LZO_COMPRESS select LZO_DECOMPRESS ---help--- @@ -85,7 +89,7 @@ config PM_STD_PARTITION config PM_SLEEP def_bool y - depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE + depends on SUSPEND || HIBERNATE_CALLBACKS || XEN_SAVE_RESTORE config PM_SLEEP_SMP def_bool y -- cgit v0.10.2 From d419e4c0f7584ffc5c72d9aeeaac485cc756ebcf Mon Sep 17 00:00:00 2001 From: Shriram Rajagopalan Date: Mon, 11 Apr 2011 22:54:48 +0200 Subject: fix XEN_SAVE_RESTORE Kconfig dependencies Make XEN_SAVE_RESTORE select HIBERNATE_CALLBACKS. Remove XEN_SAVE_RESTORE dependency from PM_SLEEP. Signed-off-by: Shriram Rajagopalan Acked-by: Ian Campbell Signed-off-by: Rafael J. Wysocki diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index 1c7121b..5cc821c 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig @@ -39,6 +39,7 @@ config XEN_MAX_DOMAIN_MEMORY config XEN_SAVE_RESTORE bool depends on XEN + select HIBERNATE_CALLBACKS default y config XEN_DEBUG_FS diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 0497914..6de9a8f 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -89,7 +89,7 @@ config PM_STD_PARTITION config PM_SLEEP def_bool y - depends on SUSPEND || HIBERNATE_CALLBACKS || XEN_SAVE_RESTORE + depends on SUSPEND || HIBERNATE_CALLBACKS config PM_SLEEP_SMP def_bool y -- cgit v0.10.2 From 39411f81eec7dc01677b14dda97684c0ce23ac1b Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Mon, 11 Apr 2011 12:06:12 -0700 Subject: xfs_destroy_workqueues() should not be tagged with__exit ia64 throws away .exit sections for the built-in CONFIG case, so routines that are used in other circumstances should not be tagged as __exit. Signed-off-by: Tony Luck Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder Signed-off-by: Linus Torvalds diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 67d5b2c..b38e58d 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -1741,7 +1741,7 @@ out: return -ENOMEM; } -STATIC void __exit +STATIC void xfs_destroy_workqueues(void) { destroy_workqueue(xfs_ail_wq); -- cgit v0.10.2 From a6360dd37e1a144ed11e6548371bade559a1e4df Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 11 Apr 2011 17:21:51 -0700 Subject: Linux 2.6.39-rc3 diff --git a/Makefile b/Makefile index 8392b64..322e733 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 39 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* -- cgit v0.10.2 From 7797069305d13252fd66cf722aa8f2cbeb3c95cd Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 5 Apr 2011 16:23:47 -0700 Subject: cifs: check for private_data before trying to put it cifs_close doesn't check that the filp->private_data is non-NULL before trying to put it. That can cause an oops in certain error conditions that can occur on open or lookup before the private_data is set. Reported-by: Ben Greear CC: Stable Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c27d236..5ae061c 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -575,8 +575,10 @@ reopen_error_exit: int cifs_close(struct inode *inode, struct file *file) { - cifsFileInfo_put(file->private_data); - file->private_data = NULL; + if (file->private_data != NULL) { + cifsFileInfo_put(file->private_data); + file->private_data = NULL; + } /* return code from the ->release op is always ignored */ return 0; -- cgit v0.10.2 From bdf1b03e093bdbc571f404e751c7b0e2dca412ea Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 22 Feb 2011 20:17:19 -0500 Subject: cifs: replace /proc/fs/cifs/Experimental with a module parm This flag currently only affects whether we allow "zero-copy" writes with signing enabled. Typically we map pages in the pagecache directly into the write request. If signing is enabled however and the contents of the page change after the signature is calculated but before the write is sent then the signature will be wrong. Servers typically respond to this by closing down the socket. Still, this can provide a performance benefit so the "Experimental" flag was overloaded to allow this. That's really not a good place for this option however since it's not clear what that flag does. Move that flag instead to a new module parameter that better describes its purpose. That's also better since it can be set at module insertion time by configuring modprobe.d. Reviewed-by: Suresh Jayaraman Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/README b/fs/cifs/README index fe16835..74ab165f 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -685,22 +685,6 @@ LinuxExtensionsEnabled If set to one then the client will attempt to support and want to map the uid and gid fields to values supplied at mount (rather than the actual values, then set this to zero. (default 1) -Experimental When set to 1 used to enable certain experimental - features (currently enables multipage writes - when signing is enabled, the multipage write - performance enhancement was disabled when - signing turned on in case buffer was modified - just before it was sent, also this flag will - be used to use the new experimental directory change - notification code). When set to 2 enables - an additional experimental feature, "raw ntlmssp" - session establishment support (which allows - specifying "sec=ntlmssp" on mount). The Linux cifs - module will use ntlmv2 authentication encapsulated - in "raw ntlmssp" (not using SPNEGO) when - "sec=ntlmssp" is specified on mount. - This support also requires building cifs with - the CONFIG_CIFS_EXPERIMENTAL configuration flag. These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs (after the cifs module has been installed or built into the diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 65829d3..30d01bc 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -423,7 +423,6 @@ static const struct file_operations cifs_lookup_cache_proc_fops; static const struct file_operations traceSMB_proc_fops; static const struct file_operations cifs_multiuser_mount_proc_fops; static const struct file_operations cifs_security_flags_proc_fops; -static const struct file_operations cifs_experimental_proc_fops; static const struct file_operations cifs_linux_ext_proc_fops; void @@ -441,8 +440,6 @@ cifs_proc_init(void) proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); - proc_create("Experimental", 0, proc_fs_cifs, - &cifs_experimental_proc_fops); proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, &cifs_linux_ext_proc_fops); proc_create("MultiuserMount", 0, proc_fs_cifs, @@ -469,7 +466,6 @@ cifs_proc_clean(void) remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("SecurityFlags", proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); - remove_proc_entry("Experimental", proc_fs_cifs); remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); remove_proc_entry("fs/cifs", NULL); } @@ -550,45 +546,6 @@ static const struct file_operations cifs_oplock_proc_fops = { .write = cifs_oplock_proc_write, }; -static int cifs_experimental_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%d\n", experimEnabled); - return 0; -} - -static int cifs_experimental_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, cifs_experimental_proc_show, NULL); -} - -static ssize_t cifs_experimental_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *ppos) -{ - char c; - int rc; - - rc = get_user(c, buffer); - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - experimEnabled = 0; - else if (c == '1' || c == 'y' || c == 'Y') - experimEnabled = 1; - else if (c == '2') - experimEnabled = 2; - - return count; -} - -static const struct file_operations cifs_experimental_proc_fops = { - .owner = THIS_MODULE, - .open = cifs_experimental_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = cifs_experimental_proc_write, -}; - static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) { seq_printf(m, "%d\n", linuxExtEnabled); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f297013..41c78e8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -53,7 +53,6 @@ int cifsFYI = 0; int cifsERROR = 1; int traceSMB = 0; unsigned int oplockEnabled = 1; -unsigned int experimEnabled = 0; unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; @@ -82,6 +81,10 @@ module_param(echo_retries, ushort, 0644); MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " "reconnecting server. Default: 5. 0 means " "never reconnect."); +bool sign_zero_copy; /* globals init to false automatically */ +module_param(sign_zero_copy, bool, 0644); +MODULE_PARM_DESC(sign_zero_copy, "Don't copy pages on write with signing " + "enabled. Default: N"); extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 17afb0f..10e4afe 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -817,7 +817,6 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions have the uid/password or Kerberos credential or equivalent for current user */ GLOBAL_EXTERN unsigned int oplockEnabled; -GLOBAL_EXTERN unsigned int experimEnabled; GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ @@ -827,6 +826,7 @@ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ +GLOBAL_EXTERN bool sign_zero_copy; /* don't copy written pages with signing */ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5ae061c..e2d7b6b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -981,7 +981,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, if (rc != 0) break; } - if (experimEnabled || (pTcon->ses->server && + if (sign_zero_copy || (pTcon->ses->server && ((pTcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0))) { @@ -1242,7 +1242,7 @@ static int cifs_writepages(struct address_space *mapping, } tcon = tlink_tcon(open_file->tlink); - if (!experimEnabled && tcon->ses->server->secMode & + if (!sign_zero_copy && tcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { cifsFileInfo_put(open_file); kfree(iov); -- cgit v0.10.2 From 8727c8a85f3951ef0eef36a665f5dceebb4c495d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 25 Feb 2011 01:11:56 -0600 Subject: Allow user names longer than 32 bytes We artificially limited the user name to 32 bytes, but modern servers handle larger. Set the maximum length to a reasonable 256, and make the user name string dynamically allocated rather than a fixed size in session structure. Also clean up old checkpatch warning. Signed-off-by: Steve French diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 4dfba82..33d2213 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -113,7 +113,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) MAX_MECH_STR_LEN + UID_KEY_LEN + (sizeof(uid_t) * 2) + CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + - USER_KEY_LEN + strlen(sesInfo->userName) + + USER_KEY_LEN + strlen(sesInfo->user_name) + PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; spnego_key = ERR_PTR(-ENOMEM); @@ -153,7 +153,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); dp = description + strlen(description); - sprintf(dp, ";user=%s", sesInfo->userName); + sprintf(dp, ";user=%s", sesInfo->user_name); dp = description + strlen(description); sprintf(dp, ";pid=0x%x", current->pid); diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index a51585f..e307a28 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -469,15 +469,15 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash, return rc; } - /* convert ses->userName to unicode and uppercase */ - len = strlen(ses->userName); + /* convert ses->user_name to unicode and uppercase */ + len = strlen(ses->user_name); user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) { cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); rc = -ENOMEM; goto calc_exit_2; } - len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp); UniStrupr(user); crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 41c78e8..0e0cc60 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -412,8 +412,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) seq_printf(s, ",multiuser"); - else if (tcon->ses->userName) - seq_printf(s, ",username=%s", tcon->ses->userName); + else if (tcon->ses->user_name) + seq_printf(s, ",username=%s", tcon->ses->user_name); if (tcon->ses->domainName) seq_printf(s, ",domain=%s", tcon->ses->domainName); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 10e4afe..94cd874 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -38,9 +38,8 @@ #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) #define MAX_SERVER_SIZE 15 #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ -#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null - termination then *2 for unicode versions */ -#define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ +#define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ +#define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ #define CIFS_MIN_RCV_POOL 4 @@ -274,7 +273,7 @@ struct cifsSesInfo { int capabilities; char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for TCP names - will ipv6 and sctp addresses fit? */ - char userName[MAX_USERNAME_SIZE + 1]; + char *user_name; char *domainName; char *password; struct session_key auth_key; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 6e2b2ad..54436a3 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -881,7 +881,8 @@ cifs_parse_mount_options(char *options, const char *devname, /* null user, ie anonymous, authentication */ vol->nullauth = 1; } - if (strnlen(value, 200) < 200) { + if (strnlen(value, MAX_USERNAME_SIZE) < + MAX_USERNAME_SIZE) { vol->username = value; } else { printk(KERN_WARNING "CIFS: username too long\n"); @@ -1808,7 +1809,9 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) break; default: /* anything else takes username/password */ - if (strncmp(ses->userName, vol->username, + if (ses->user_name == NULL) + continue; + if (strncmp(ses->user_name, vol->username, MAX_USERNAME_SIZE)) continue; if (strlen(vol->username) != 0 && @@ -1906,9 +1909,11 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) else sprintf(ses->serverName, "%pI4", &addr->sin_addr); - if (volume_info->username) - strncpy(ses->userName, volume_info->username, - MAX_USERNAME_SIZE); + if (volume_info->username) { + ses->user_name = kstrdup(volume_info->username, GFP_KERNEL); + if (!ses->user_name) + goto get_ses_fail; + } /* volume_info->password freed at unmount */ if (volume_info->password) { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 2a930a7..7228179 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -100,6 +100,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) memset(buf_to_free->password, 0, strlen(buf_to_free->password)); kfree(buf_to_free->password); } + kfree(buf_to_free->user_name); kfree(buf_to_free->domainName); kfree(buf_to_free); } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1676570..006485f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -219,12 +219,12 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, bcc_ptr++; } */ /* copy user */ - if (ses->userName == NULL) { + if (ses->user_name == NULL) { /* null user mount */ *bcc_ptr = 0; *(bcc_ptr+1) = 0; } else { - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->user_name, MAX_USERNAME_SIZE, nls_cp); } bcc_ptr += 2 * bytes_ret; @@ -244,12 +244,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, /* copy user */ /* BB what about null user mounts - check that we do this BB */ /* copy user */ - if (ses->userName == NULL) { - /* BB what about null user mounts - check that we do this BB */ - } else { - strncpy(bcc_ptr, ses->userName, MAX_USERNAME_SIZE); - } - bcc_ptr += strnlen(ses->userName, MAX_USERNAME_SIZE); + if (ses->user_name != NULL) + strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE); + /* else null user mount */ + + bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); *bcc_ptr = 0; bcc_ptr++; /* account for null termination */ @@ -523,14 +522,14 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, tmp += len; } - if (ses->userName == NULL) { + if (ses->user_name == NULL) { sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.Length = 0; sec_blob->UserName.MaximumLength = 0; tmp += 2; } else { int len; - len = cifs_strtoUCS((__le16 *)tmp, ses->userName, + len = cifs_strtoUCS((__le16 *)tmp, ses->user_name, MAX_USERNAME_SIZE, nls_cp); len *= 2; /* unicode is 2 bytes each */ sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); -- cgit v0.10.2 From 2e325d5973b99bb7421e689351ca74f349eee5ea Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 8 Mar 2011 05:51:19 +0000 Subject: Max share size is too small Max share name was set to 64, and (at least for Windows) can be 80. Signed-off-by: Steve French diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 94cd874..1cff9aa 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -37,7 +37,7 @@ #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) #define MAX_SERVER_SIZE 15 -#define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ +#define MAX_SHARE_SIZE 80 #define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ -- cgit v0.10.2 From 6da9791061ca3b7b3c7eb7350eb452443f40a0e5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 13 Mar 2011 18:55:55 +0000 Subject: Elminate sparse __CHECK_ENDIAN__ warnings on port conversion Ports are __be16 not unsigned short int Eliminates the remaining fixable endian warnings: ~/cifs-2.6$ make modules C=1 M=fs/cifs CF=-D__CHECK_ENDIAN__ CHECK fs/cifs/connect.c fs/cifs/connect.c:2408:23: warning: incorrect type in assignment (different base types) fs/cifs/connect.c:2408:23: expected unsigned short *sport fs/cifs/connect.c:2408:23: got restricted __be16 * fs/cifs/connect.c:2410:23: warning: incorrect type in assignment (different base types) fs/cifs/connect.c:2410:23: expected unsigned short *sport fs/cifs/connect.c:2410:23: got restricted __be16 * fs/cifs/connect.c:2416:24: warning: incorrect type in assignment (different base types) fs/cifs/connect.c:2416:24: expected unsigned short [unsigned] [short] fs/cifs/connect.c:2416:24: got restricted __be16 [usertype] fs/cifs/connect.c:2423:24: warning: incorrect type in assignment (different base types) fs/cifs/connect.c:2423:24: expected unsigned short [unsigned] [short] fs/cifs/connect.c:2423:24: got restricted __be16 [usertype] fs/cifs/connect.c:2326:23: warning: incorrect type in assignment (different base types) fs/cifs/connect.c:2326:23: expected unsigned short [unsigned] sport fs/cifs/connect.c:2326:23: got restricted __be16 [usertype] sin6_port fs/cifs/connect.c:2330:23: warning: incorrect type in assignment (different base types) fs/cifs/connect.c:2330:23: expected unsigned short [unsigned] sport fs/cifs/connect.c:2330:23: got restricted __be16 [usertype] sin_port fs/cifs/connect.c:2394:22: warning: restricted __be16 degrades to integer Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 54436a3..94a05a6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1473,7 +1473,7 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) static bool match_port(struct TCP_Server_Info *server, struct sockaddr *addr) { - unsigned short int port, *sport; + __be16 port, *sport; switch (addr->sa_family) { case AF_INET: @@ -2281,7 +2281,7 @@ static int generic_ip_connect(struct TCP_Server_Info *server) { int rc = 0; - unsigned short int sport; + __be16 sport; int slen, sfamily; struct socket *socket = server->ssocket; struct sockaddr *saddr; @@ -2366,7 +2366,7 @@ generic_ip_connect(struct TCP_Server_Info *server) static int ip_connect(struct TCP_Server_Info *server) { - unsigned short int *sport; + __be16 *sport; struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; -- cgit v0.10.2 From 5443d130aa4990424a8e64984e64b50ec70661bb Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 13 Mar 2011 05:08:25 +0000 Subject: various endian fixes to cifs make modules C=2 M=fs/cifs CF=-D__CHECK_ENDIAN__ Found for example: CHECK fs/cifs/cifssmb.c fs/cifs/cifssmb.c:728:22: warning: incorrect type in assignment (different base types) fs/cifs/cifssmb.c:728:22: expected unsigned short [unsigned] [usertype] Tid fs/cifs/cifssmb.c:728:22: got restricted __le16 [usertype] fs/cifs/cifssmb.c:1883:45: warning: incorrect type in assignment (different base types) fs/cifs/cifssmb.c:1883:45: expected long long [signed] [usertype] fl_start fs/cifs/cifssmb.c:1883:45: got restricted __le64 [usertype] start fs/cifs/cifssmb.c:1884:54: warning: restricted __le64 degrades to integer fs/cifs/cifssmb.c:1885:58: warning: restricted __le64 degrades to integer fs/cifs/cifssmb.c:1886:43: warning: incorrect type in assignment (different base types) fs/cifs/cifssmb.c:1886:43: expected unsigned int [unsigned] fl_pid fs/cifs/cifssmb.c:1886:43: got restricted __le32 [usertype] pid In checking new smb2 code for missing endian conversions, I noticed some endian errors had crept in over the last few releases into the cifs code (symlink, ntlmssp, posix lock, and also a less problematic warning in fscache). A followon patch will address a few smb2 endian problems. Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index e654dfd..53d57a3 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -50,7 +50,7 @@ void cifs_fscache_unregister(void) */ struct cifs_server_key { uint16_t family; /* address family */ - uint16_t port; /* IP port */ + __be16 port; /* IP port */ union { struct in_addr ipv4_addr; struct in6_addr ipv6_addr; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2644a5d..3919ec8 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -729,7 +729,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) return rc; /* set up echo request */ - smb->hdr.Tid = cpu_to_le16(0xffff); + smb->hdr.Tid = 0xffff; smb->hdr.WordCount = 1; put_unaligned_le16(1, &smb->EchoCount); put_bcc_le(1, &smb->hdr); @@ -1884,10 +1884,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, __constant_cpu_to_le16(CIFS_WRLCK)) pLockData->fl_type = F_WRLCK; - pLockData->fl_start = parm_data->start; - pLockData->fl_end = parm_data->start + - parm_data->length - 1; - pLockData->fl_pid = parm_data->pid; + pLockData->fl_start = le64_to_cpu(parm_data->start); + pLockData->fl_end = pLockData->fl_start + + le64_to_cpu(parm_data->length) - 1; + pLockData->fl_pid = le32_to_cpu(parm_data->pid); } } diff --git a/fs/cifs/link.c b/fs/cifs/link.c index e8804d3..ce417a9 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -239,7 +239,7 @@ CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon, if (rc != 0) return rc; - if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { + if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { CIFSSMBClose(xid, tcon, netfid); /* it's not a symlink */ return -EINVAL; @@ -316,7 +316,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, if (rc != 0) goto out; - if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { + if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { CIFSSMBClose(xid, pTcon, netfid); /* it's not a symlink */ goto out; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 006485f..f6728eb 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -404,8 +404,8 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, /* BB spec says that if AvId field of MsvAvTimestamp is populated then we must set the MIC field of the AUTHENTICATE_MESSAGE */ ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); - tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); - tilen = cpu_to_le16(pblob->TargetInfoArray.Length); + tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset); + tilen = le16_to_cpu(pblob->TargetInfoArray.Length); if (tilen) { ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); if (!ses->auth_key.response) { -- cgit v0.10.2 From 70945643722ffeac779d2529a348f99567fa5c33 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 14 Mar 2011 13:48:08 -0400 Subject: cifs: always do is_path_accessible check in cifs_mount Currently, we skip doing the is_path_accessible check in cifs_mount if there is no prefixpath. I have a report of at least one server however that allows a TREE_CONNECT to a share that has a DFS referral at its root. The reporter in this case was using a UNC that had no prefixpath, so the is_path_accessible check was not triggered and the box later hit a BUG() because we were chasing a DFS referral on the root dentry for the mount. This patch fixes this by removing the check for a zero-length prefixpath. That should make the is_path_accessible check be done in this situation and should allow the client to chase the DFS referral at mount time instead. Cc: stable@kernel.org Reported-and-Tested-by: Yogesh Sharma Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 94a05a6..5eacb89 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2831,7 +2831,7 @@ try_mount_again: remote_path_check: /* check if a whole path (including prepath) is not remote */ - if (!rc && cifs_sb->prepathlen && tcon) { + if (!rc && tcon) { /* build_path_to_root works only when we have a valid tcon */ full_path = cifs_build_path_to_root(cifs_sb, tcon); if (full_path == NULL) { -- cgit v0.10.2 From 8679b0dba7cb98842cbe37f61ef05ef64106334c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 16 Mar 2011 15:15:30 -0400 Subject: cifs: fix broken BCC check in is_valid_oplock_break The BCC is still __le16 at this point, and in any case we need to use the get_bcc_le macro to make sure we don't hit alignment problems. Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 7228179..0c684ae 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -521,7 +521,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) (struct smb_com_transaction_change_notify_rsp *)buf; struct file_notify_information *pnotify; __u32 data_offset = 0; - if (pSMBr->ByteCount > sizeof(struct file_notify_information)) { + if (get_bcc_le(buf) > sizeof(struct file_notify_information)) { data_offset = le32_to_cpu(pSMBr->DataOffset); pnotify = (struct file_notify_information *) -- cgit v0.10.2 From 2b6c26a0a62cc0bab0ad487533d5581d7c293fef Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 25 Mar 2011 16:25:57 -0400 Subject: cifs: set ra_pages in backing_dev_info Commit 522440ed made cifs set backing_dev_info on the mapping attached to new inodes. This change caused a fairly significant read performance regression, as cifs started doing page-sized reads exclusively. By virtue of the fact that they're allocated as part of cifs_sb_info by kzalloc, the ra_pages on cifs BDIs get set to 0, which prevents any readahead. This forces the normal read codepaths to use readpage instead of readpages causing a four-fold increase in the number of read calls with the default rsize. Fix it by setting ra_pages in the BDI to the same value as that in the default_backing_dev_info. Fixes https://bugzilla.kernel.org/show_bug.cgi?id=31662 Cc: stable@kernel.org Reported-and-Tested-by: Till Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0e0cc60..e3352a1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -130,6 +130,7 @@ cifs_read_super(struct super_block *sb, void *data, kfree(cifs_sb); return rc; } + cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; #ifdef CONFIG_CIFS_DFS_UPCALL /* copy mount params to sb for use in submounts */ -- cgit v0.10.2 From c0c7b905e911a1f1faf515a24e849d4ffcdd0a8a Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 31 Mar 2011 17:32:54 -0400 Subject: cifs: clean up length checks in check2ndT2 Thus spake David Howells: The code that follows this: remaining = total_data_size - data_in_this_rsp; if (remaining == 0) return 0; else if (remaining < 0) { generates better code if you drop the 'remaining' variable and compare the values directly. Clean it up per his recommendation... Reported-and-acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5eacb89..709fd9d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -248,24 +248,24 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); - remaining = total_data_size - data_in_this_rsp; - - if (remaining == 0) + if (total_data_size == data_in_this_rsp) return 0; - else if (remaining < 0) { + else if (total_data_size < data_in_this_rsp) { cFYI(1, "total data %d smaller than data in frame %d", total_data_size, data_in_this_rsp); return -EINVAL; - } else { - cFYI(1, "missing %d bytes from transact2, check next response", - remaining); - if (total_data_size > maxBufSize) { - cERROR(1, "TotalDataSize %d is over maximum buffer %d", - total_data_size, maxBufSize); - return -EINVAL; - } - return remaining; } + + remaining = total_data_size - data_in_this_rsp; + + cFYI(1, "missing %d bytes from transact2, check next response", + remaining); + if (total_data_size > maxBufSize) { + cERROR(1, "TotalDataSize %d is over maximum buffer %d", + total_data_size, maxBufSize); + return -EINVAL; + } + return remaining; } static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) -- cgit v0.10.2 From 581ade4d1c025eb10421eda0d0c0a2f04447d7c5 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 5 Apr 2011 15:02:37 -0400 Subject: cifs: clean up various nits in unicode routines (try #2) Minor revision to the original patch. Don't abuse the __le16 variable on the stack by casting it to wchar_t and handing it off to char2uni. Declare an actual wchar_t on the stack instead. This fixes a valid sparse warning. Fix the spelling of UNI_ASTERISK. Eliminate the unneeded len_remaining variable in cifsConvertToUCS. Also, as David Howells points out. We were better off making cifsConvertToUCS *not* use put_unaligned_le16 since it means that we can't optimize the mapped characters at compile time. Switch them instead to use cpu_to_le16, and simply use put_unaligned to set them in the string. Reported-and-acked-by: David Howells Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index fc0fd4f..23d43cd 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -90,7 +90,7 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, case UNI_COLON: *target = ':'; break; - case UNI_ASTERIK: + case UNI_ASTERISK: *target = '*'; break; case UNI_QUESTION: @@ -264,40 +264,40 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, * names are little endian 16 bit Unicode on the wire */ int -cifsConvertToUCS(__le16 *target, const char *source, int maxlen, +cifsConvertToUCS(__le16 *target, const char *source, int srclen, const struct nls_table *cp, int mapChars) { int i, j, charlen; - int len_remaining = maxlen; char src_char; - __u16 temp; + __le16 dst_char; + wchar_t tmp; if (!mapChars) return cifs_strtoUCS(target, source, PATH_MAX, cp); - for (i = 0, j = 0; i < maxlen; j++) { + for (i = 0, j = 0; i < srclen; j++) { src_char = source[i]; switch (src_char) { case 0: - put_unaligned_le16(0, &target[j]); + put_unaligned(0, &target[j]); goto ctoUCS_out; case ':': - temp = UNI_COLON; + dst_char = cpu_to_le16(UNI_COLON); break; case '*': - temp = UNI_ASTERIK; + dst_char = cpu_to_le16(UNI_ASTERISK); break; case '?': - temp = UNI_QUESTION; + dst_char = cpu_to_le16(UNI_QUESTION); break; case '<': - temp = UNI_LESSTHAN; + dst_char = cpu_to_le16(UNI_LESSTHAN); break; case '>': - temp = UNI_GRTRTHAN; + dst_char = cpu_to_le16(UNI_GRTRTHAN); break; case '|': - temp = UNI_PIPE; + dst_char = cpu_to_le16(UNI_PIPE); break; /* * FIXME: We can not handle remapping backslash (UNI_SLASH) @@ -305,17 +305,17 @@ cifsConvertToUCS(__le16 *target, const char *source, int maxlen, * as they use backslash as separator. */ default: - charlen = cp->char2uni(source+i, len_remaining, - &temp); + charlen = cp->char2uni(source + i, srclen - i, &tmp); + dst_char = cpu_to_le16(tmp); + /* * if no match, use question mark, which at least in * some cases serves as wild card */ if (charlen < 1) { - temp = 0x003f; + dst_char = cpu_to_le16(0x003f); charlen = 1; } - len_remaining -= charlen; /* * character may take more than one byte in the source * string, but will take exactly two bytes in the @@ -324,9 +324,8 @@ cifsConvertToUCS(__le16 *target, const char *source, int maxlen, i += charlen; continue; } - put_unaligned_le16(temp, &target[j]); + put_unaligned(dst_char, &target[j]); i++; /* move to next char in source string */ - len_remaining--; } ctoUCS_out: diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 7fe6b52..644dd882 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -44,7 +44,7 @@ * reserved symbols (along with \ and /), otherwise illegal to store * in filenames in NTFS */ -#define UNI_ASTERIK (__u16) ('*' + 0xF000) +#define UNI_ASTERISK (__u16) ('*' + 0xF000) #define UNI_QUESTION (__u16) ('?' + 0xF000) #define UNI_COLON (__u16) (':' + 0xF000) #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) -- cgit v0.10.2 From 157c249114508aa71daa308a426e15d81a4eed00 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Sat, 2 Apr 2011 07:34:30 -0400 Subject: cifs: wrap received signature check in srv_mutex While testing my patchset to fix asynchronous writes, I hit a bunch of signature problems when testing with signing on. The problem seems to be that signature checks on receive can be running at the same time as a process that is sending, or even that multiple receives can be checking signatures at the same time, clobbering the same data structures. While we're at it, clean up the comments over cifs_calculate_signature and add a note that the srv_mutex should be held when calling this function. This patch seems to fix the problems for me, but I'm not clear on whether it's the best approach. If it is, then this should probably go to stable too. Cc: stable@kernel.org Cc: Shirish Pargaonkar Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e307a28..d1a016b 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -30,12 +30,13 @@ #include #include -/* Calculate and return the CIFS signature based on the mac key and SMB PDU */ -/* the 16 byte signature must be allocated by the caller */ -/* Note we only use the 1st eight bytes */ -/* Note that the smb header signature field on input contains the - sequence number before this function is called */ - +/* + * Calculate and return the CIFS signature based on the mac key and SMB PDU. + * The 16 byte signature must be allocated by the caller. Note we only use the + * 1st eight bytes and that the smb header signature field on input contains + * the sequence number before this function is called. Also, this function + * should be called with the server->srv_mutex held. + */ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, char *signature) { @@ -209,8 +210,10 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.Reserved = 0; + mutex_lock(&server->srv_mutex); rc = cifs_calculate_signature(cifs_pdu, server, what_we_think_sig_should_be); + mutex_unlock(&server->srv_mutex); if (rc) return rc; -- cgit v0.10.2 From fd88ce9313e9f9d3b56eada7fc76a301828baefd Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 12 Apr 2011 01:01:14 +0000 Subject: [CIFS] cifs: clarify the meaning of tcpStatus == CifsGood When the TCP_Server_Info is first allocated and connected, tcpStatus == CifsGood means that the NEGOTIATE_PROTOCOL request has completed and the socket is ready for other calls. cifs_reconnect however sets tcpStatus to CifsGood as soon as the socket is reconnected and the optional RFC1001 session setup is done. We have no clear way to tell the difference between these two states, and we need to know this in order to know whether we can send an echo or not. Resolve this by adding a new statusEnum value -- CifsNeedNegotiate. When the socket has been connected but has not yet had a NEGOTIATE_PROTOCOL request done, set it to this value. Once the NEGOTIATE is done, cifs_negotiate_protocol will set tcpStatus to CifsGood. This also fixes and cleans the logic in cifs_reconnect and cifs_reconnect_tcon. The old code checked for specific states when what it really wants to know is whether the state has actually changed from CifsNeedReconnect. Reported-and-Tested-by: JG Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1cff9aa..ddb3599 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -91,7 +91,8 @@ enum statusEnum { CifsNew = 0, CifsGood, CifsExiting, - CifsNeedReconnect + CifsNeedReconnect, + CifsNeedNegotiate }; enum securityEnum { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 3919ec8..df959ba 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -142,9 +142,9 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) */ while (server->tcpStatus == CifsNeedReconnect) { wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus == CifsGood), 10 * HZ); + (server->tcpStatus != CifsNeedReconnect), 10 * HZ); - /* is TCP session is reestablished now ?*/ + /* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect) break; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 709fd9d..8cf4a63 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -199,8 +199,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } spin_unlock(&GlobalMid_Lock); - while ((server->tcpStatus != CifsExiting) && - (server->tcpStatus != CifsGood)) { + while (server->tcpStatus == CifsNeedReconnect) { try_to_freeze(); /* we should try only the port we connected to before */ @@ -212,7 +211,7 @@ cifs_reconnect(struct TCP_Server_Info *server) atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); if (server->tcpStatus != CifsExiting) - server->tcpStatus = CifsGood; + server->tcpStatus = CifsNeedNegotiate; spin_unlock(&GlobalMid_Lock); } } @@ -421,7 +420,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) pdu_length = 4; /* enough to get RFC1001 header */ incomplete_rcv: - if (echo_retries > 0 && + if (echo_retries > 0 && server->tcpStatus == CifsGood && time_after(jiffies, server->lstrp + (echo_retries * SMB_ECHO_INTERVAL))) { cERROR(1, "Server %s has not responded in %d seconds. " @@ -1766,6 +1765,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) module_put(THIS_MODULE); goto out_err_crypto_release; } + tcp_ses->tcpStatus = CifsNeedNegotiate; /* thread spawned, put it on the list */ spin_lock(&cifs_tcp_ses_lock); -- cgit v0.10.2 From d9b942013730c38ac83564d6669c6d0ecf6d754d Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 12 Apr 2011 01:24:57 +0000 Subject: [CIFS] Warn on requesting default security (ntlm) on mount Warn once if default security (ntlm) requested. We will update the default to the stronger security mechanism (ntlmv2) in 2.6.41. Kerberos is also stronger than ntlm, but more servers support ntlmv2 and ntlmv2 does not require an upcall, so ntlmv2 is a better default. Reviewed-by: Jeff Layton CC: Suresh Jayaraman Reviewed-by: Shirish Pargaonkar Signed-off-by: Steve French diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8cf4a63..db9d55b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1854,6 +1854,8 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) cifs_put_tcp_session(server); } +static bool warned_on_ntlm; /* globals init to false automatically */ + static struct cifsSesInfo * cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) { @@ -1928,6 +1930,15 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) } ses->cred_uid = volume_info->cred_uid; ses->linux_uid = volume_info->linux_uid; + + /* ntlmv2 is much stronger than ntlm security, and has been broadly + supported for many years, time to update default security mechanism */ + if ((volume_info->secFlg == 0) && warned_on_ntlm == false) { + warned_on_ntlm = true; + cERROR(1, "default security mechanism requested. The default " + "security mechanism will be upgraded from ntlm to " + "ntlmv2 in kernel release 2.6.41"); + } ses->overrideSecFlg = volume_info->secFlg; mutex_lock(&ses->session_mutex); -- cgit v0.10.2 From e710d7d5a9cab1041b7a3cf9e655b75d92786857 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 8 Apr 2011 00:43:01 +0200 Subject: mfd: Fetch cell pointer from platform_device->mfd_cell In order for MFD drivers to fetch their cell pointer but also their platform data one, an mfd cell pointer is added to the platform_device structure. That allows all MFD sub devices drivers to be MFD agnostic, unless they really need to access their MFD cell data. Most of them don't, especially the ones for IPs used by both MFD and non MFD SoCs. Cc: Grant Likely Acked-by: Greg KH Signed-off-by: Samuel Ortiz diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f051cff..6c3a2bd 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -149,6 +149,7 @@ static void platform_device_release(struct device *dev) of_device_node_put(&pa->pdev.dev); kfree(pa->pdev.dev.platform_data); + kfree(pa->pdev.mfd_cell); kfree(pa->pdev.resource); kfree(pa); } diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index d01574d..f4c8c84 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -55,6 +55,19 @@ int mfd_cell_disable(struct platform_device *pdev) } EXPORT_SYMBOL(mfd_cell_disable); +static int mfd_platform_add_cell(struct platform_device *pdev, + const struct mfd_cell *cell) +{ + if (!cell) + return 0; + + pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL); + if (!pdev->mfd_cell) + return -ENOMEM; + + return 0; +} + static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, struct resource *mem_base, @@ -75,7 +88,7 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; - ret = platform_device_add_data(pdev, cell, sizeof(*cell)); + ret = mfd_platform_add_cell(pdev, cell); if (ret) goto fail_res; @@ -123,7 +136,6 @@ static int mfd_add_device(struct device *parent, int id, return 0; -/* platform_device_del(pdev); */ fail_res: kfree(res); fail_device: diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index ad1b19a..aef23309 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -86,16 +86,25 @@ extern int mfd_clone_cell(const char *cell, const char **clones, */ static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev) { - return pdev->dev.platform_data; + return pdev->mfd_cell; } /* * Given a platform device that's been created by mfd_add_devices(), fetch * the .mfd_data entry from the mfd_cell that created it. + * Otherwise just return the platform_data pointer. + * This maintains compatibility with platform drivers whose devices aren't + * created by the mfd layer, and expect platform_data to contain what would've + * otherwise been in mfd_data. */ static inline void *mfd_get_data(struct platform_device *pdev) { - return mfd_get_cell(pdev)->mfd_data; + const struct mfd_cell *cell = mfd_get_cell(pdev); + + if (cell) + return cell->mfd_data; + else + return pdev->dev.platform_data; } extern int mfd_add_devices(struct device *parent, int id, diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index d96db98..744942c 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -14,6 +14,8 @@ #include #include +struct mfd_cell; + struct platform_device { const char * name; int id; @@ -23,6 +25,9 @@ struct platform_device { const struct platform_device_id *id_entry; + /* MFD cell pointer */ + struct mfd_cell *mfd_cell; + /* arch specific additions */ struct pdev_archdata archdata; }; -- cgit v0.10.2 From ca83ce3d5b9ad321ee24f5870a77f0b21ac5a5de Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 12 Apr 2011 09:13:44 -0400 Subject: cifs: don't allow mmap'ed pages to be dirtied while under writeback (try #3) This is more or less the same patch as before, but with some merge conflicts fixed up. If a process has a dirty page mapped into its page tables, then it has the ability to change it while the client is trying to write the data out to the server. If that happens after the signature has been calculated then that signature will then be wrong, and the server will likely reset the TCP connection. This patch adds a page_mkwrite handler for CIFS that simply takes the page lock. Because the page lock is held over the life of writepage and writepages, this prevents the page from becoming writeable until the write call has completed. With this, we can also remove the "sign_zero_copy" module option and always inline the pages when writing. Signed-off-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e3352a1..5c412b3 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -81,10 +81,6 @@ module_param(echo_retries, ushort, 0644); MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " "reconnecting server. Default: 5. 0 means " "never reconnect."); -bool sign_zero_copy; /* globals init to false automatically */ -module_param(sign_zero_copy, bool, 0644); -MODULE_PARM_DESC(sign_zero_copy, "Don't copy pages on write with signing " - "enabled. Default: N"); extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ddb3599..a5d1106 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -826,7 +826,6 @@ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ -GLOBAL_EXTERN bool sign_zero_copy; /* don't copy written pages with signing */ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e2d7b6b..faf5952 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -972,6 +972,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, total_written += bytes_written) { rc = -EAGAIN; while (rc == -EAGAIN) { + struct kvec iov[2]; + unsigned int len; + if (open_file->invalidHandle) { /* we could deadlock if we called filemap_fdatawait from here so tell @@ -981,31 +984,14 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, if (rc != 0) break; } - if (sign_zero_copy || (pTcon->ses->server && - ((pTcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - == 0))) { - struct kvec iov[2]; - unsigned int len; - - len = min((size_t)cifs_sb->wsize, - write_size - total_written); - /* iov[0] is reserved for smb header */ - iov[1].iov_base = (char *)write_data + - total_written; - iov[1].iov_len = len; - rc = CIFSSMBWrite2(xid, pTcon, - open_file->netfid, len, - *poffset, &bytes_written, - iov, 1, 0); - } else - rc = CIFSSMBWrite(xid, pTcon, - open_file->netfid, - min_t(const int, cifs_sb->wsize, - write_size - total_written), - *poffset, &bytes_written, - write_data + total_written, - NULL, 0); + + len = min((size_t)cifs_sb->wsize, + write_size - total_written); + /* iov[0] is reserved for smb header */ + iov[1].iov_base = (char *)write_data + total_written; + iov[1].iov_len = len; + rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid, len, + *poffset, &bytes_written, iov, 1, 0); } if (rc || (bytes_written == 0)) { if (total_written) @@ -1242,12 +1228,6 @@ static int cifs_writepages(struct address_space *mapping, } tcon = tlink_tcon(open_file->tlink); - if (!sign_zero_copy && tcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { - cifsFileInfo_put(open_file); - kfree(iov); - return generic_writepages(mapping, wbc); - } cifsFileInfo_put(open_file); xid = GetXid(); @@ -1982,6 +1962,24 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, return total_read; } +/* + * If the page is mmap'ed into a process' page tables, then we need to make + * sure that it doesn't change while being written back. + */ +static int +cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct page *page = vmf->page; + + lock_page(page); + return VM_FAULT_LOCKED; +} + +static struct vm_operations_struct cifs_file_vm_ops = { + .fault = filemap_fault, + .page_mkwrite = cifs_page_mkwrite, +}; + int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) { int rc, xid; @@ -1993,6 +1991,8 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) cifs_invalidate_mapping(inode); rc = generic_file_mmap(file, vma); + if (rc == 0) + vma->vm_ops = &cifs_file_vm_ops; FreeXid(xid); return rc; } @@ -2009,6 +2009,8 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) return rc; } rc = generic_file_mmap(file, vma); + if (rc == 0) + vma->vm_ops = &cifs_file_vm_ops; FreeXid(xid); return rc; } -- cgit v0.10.2 From 101650726e4a5c0eca3e2716aefeb3296bb177b9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 8 Apr 2011 17:02:04 +0200 Subject: samsung-laptop: add support for N230 model Signed-off-by: Greg Kroah-Hartman [mmarek: cherry-picked from staging commit 0789b003] Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index de434c6..11a3fe2 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -591,12 +591,12 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { .callback = dmi_check_cb, }, { - .ident = "N150/N210/N220", + .ident = "N150/N210/N220/N230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), }, .callback = dmi_check_cb, }, -- cgit v0.10.2 From 3d536ed415a8f5d3f683597521df071af9f2866c Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Fri, 8 Apr 2011 17:02:03 +0200 Subject: samsung-laptop: Samsung R410P backlight driver Here's a trivial patch which adds support to the backlight device found in Samsung R410 Plus laptops. Signed-off-by: Alberto Mardegan Signed-off-by: Greg Kroah-Hartman [mmarek: cherry-picked from staging commit d542f180] Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 11a3fe2..39f30ff 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -571,6 +571,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { .callback = dmi_check_cb, }, { + .ident = "R410 Plus", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), + DMI_MATCH(DMI_BOARD_NAME, "R460"), + }, + .callback = dmi_check_cb, + }, + { .ident = "R518", .matches = { DMI_MATCH(DMI_SYS_VENDOR, -- cgit v0.10.2 From 993819c563695efc2782d312f55bec634c2d2da5 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 8 Apr 2011 17:02:06 +0200 Subject: staging: samsung-laptop has moved to platform/x86 Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 18b43fc..9d5a033 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -133,8 +133,6 @@ source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" -source "drivers/staging/samsung-laptop/Kconfig" - source "drivers/staging/sm7xx/Kconfig" source "drivers/staging/dt3155v4l/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index cfd13cd..adebf8e 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,7 +49,6 @@ obj-$(CONFIG_XVMALLOC) += zram/ obj-$(CONFIG_ZCACHE) += zcache/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ -obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/ obj-$(CONFIG_FB_SM7XX) += sm7xx/ obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ diff --git a/drivers/staging/samsung-laptop/Kconfig b/drivers/staging/samsung-laptop/Kconfig deleted file mode 100644 index f27c608..0000000 --- a/drivers/staging/samsung-laptop/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config SAMSUNG_LAPTOP - tristate "Samsung Laptop driver" - default n - depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 - help - This module implements a driver for the N128 Samsung Laptop - providing control over the Wireless LED and the LCD backlight - - To compile this driver as a module, choose - M here: the module will be called samsung-laptop. diff --git a/drivers/staging/samsung-laptop/Makefile b/drivers/staging/samsung-laptop/Makefile deleted file mode 100644 index 3c6f420..0000000 --- a/drivers/staging/samsung-laptop/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o diff --git a/drivers/staging/samsung-laptop/TODO b/drivers/staging/samsung-laptop/TODO deleted file mode 100644 index f7a6d58..0000000 --- a/drivers/staging/samsung-laptop/TODO +++ /dev/null @@ -1,5 +0,0 @@ -TODO: - - review from other developers - - figure out ACPI video issues - -Please send patches to Greg Kroah-Hartman diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c deleted file mode 100644 index 2529446..0000000 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Samsung Laptop driver - * - * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) - * Copyright (C) 2009,2011 Novell Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This driver is needed because a number of Samsung laptops do not hook - * their control settings through ACPI. So we have to poke around in the - * BIOS to do things like brightness values, and "special" key controls. - */ - -/* - * We have 0 - 8 as valid brightness levels. The specs say that level 0 should - * be reserved by the BIOS (which really doesn't make much sense), we tell - * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 - */ -#define MAX_BRIGHT 0x07 - - -#define SABI_IFACE_MAIN 0x00 -#define SABI_IFACE_SUB 0x02 -#define SABI_IFACE_COMPLETE 0x04 -#define SABI_IFACE_DATA 0x05 - -/* Structure to get data back to the calling function */ -struct sabi_retval { - u8 retval[20]; -}; - -struct sabi_header_offsets { - u8 port; - u8 re_mem; - u8 iface_func; - u8 en_mem; - u8 data_offset; - u8 data_segment; -}; - -struct sabi_commands { - /* - * Brightness is 0 - 8, as described above. - * Value 0 is for the BIOS to use - */ - u8 get_brightness; - u8 set_brightness; - - /* - * first byte: - * 0x00 - wireless is off - * 0x01 - wireless is on - * second byte: - * 0x02 - 3G is off - * 0x03 - 3G is on - * TODO, verify 3G is correct, that doesn't seem right... - */ - u8 get_wireless_button; - u8 set_wireless_button; - - /* 0 is off, 1 is on */ - u8 get_backlight; - u8 set_backlight; - - /* - * 0x80 or 0x00 - no action - * 0x81 - recovery key pressed - */ - u8 get_recovery_mode; - u8 set_recovery_mode; - - /* - * on seclinux: 0 is low, 1 is high, - * on swsmi: 0 is normal, 1 is silent, 2 is turbo - */ - u8 get_performance_level; - u8 set_performance_level; - - /* - * Tell the BIOS that Linux is running on this machine. - * 81 is on, 80 is off - */ - u8 set_linux; -}; - -struct sabi_performance_level { - const char *name; - u8 value; -}; - -struct sabi_config { - const char *test_string; - u16 main_function; - const struct sabi_header_offsets header_offsets; - const struct sabi_commands commands; - const struct sabi_performance_level performance_levels[4]; - u8 min_brightness; - u8 max_brightness; -}; - -static const struct sabi_config sabi_configs[] = { - { - .test_string = "SECLINUX", - - .main_function = 0x4c49, - - .header_offsets = { - .port = 0x00, - .re_mem = 0x02, - .iface_func = 0x03, - .en_mem = 0x04, - .data_offset = 0x05, - .data_segment = 0x07, - }, - - .commands = { - .get_brightness = 0x00, - .set_brightness = 0x01, - - .get_wireless_button = 0x02, - .set_wireless_button = 0x03, - - .get_backlight = 0x04, - .set_backlight = 0x05, - - .get_recovery_mode = 0x06, - .set_recovery_mode = 0x07, - - .get_performance_level = 0x08, - .set_performance_level = 0x09, - - .set_linux = 0x0a, - }, - - .performance_levels = { - { - .name = "silent", - .value = 0, - }, - { - .name = "normal", - .value = 1, - }, - { }, - }, - .min_brightness = 1, - .max_brightness = 8, - }, - { - .test_string = "SwSmi@", - - .main_function = 0x5843, - - .header_offsets = { - .port = 0x00, - .re_mem = 0x04, - .iface_func = 0x02, - .en_mem = 0x03, - .data_offset = 0x05, - .data_segment = 0x07, - }, - - .commands = { - .get_brightness = 0x10, - .set_brightness = 0x11, - - .get_wireless_button = 0x12, - .set_wireless_button = 0x13, - - .get_backlight = 0x2d, - .set_backlight = 0x2e, - - .get_recovery_mode = 0xff, - .set_recovery_mode = 0xff, - - .get_performance_level = 0x31, - .set_performance_level = 0x32, - - .set_linux = 0xff, - }, - - .performance_levels = { - { - .name = "normal", - .value = 0, - }, - { - .name = "silent", - .value = 1, - }, - { - .name = "overclock", - .value = 2, - }, - { }, - }, - .min_brightness = 0, - .max_brightness = 8, - }, - { }, -}; - -static const struct sabi_config *sabi_config; - -static void __iomem *sabi; -static void __iomem *sabi_iface; -static void __iomem *f0000_segment; -static struct backlight_device *backlight_device; -static struct mutex sabi_mutex; -static struct platform_device *sdev; -static struct rfkill *rfk; - -static int force; -module_param(force, bool, 0); -MODULE_PARM_DESC(force, - "Disable the DMI check and forces the driver to be loaded"); - -static int debug; -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -static int sabi_get_command(u8 command, struct sabi_retval *sretval) -{ - int retval = 0; - u16 port = readw(sabi + sabi_config->header_offsets.port); - u8 complete, iface_data; - - mutex_lock(&sabi_mutex); - - /* enable memory to be able to write to it */ - outb(readb(sabi + sabi_config->header_offsets.en_mem), port); - - /* write out the command */ - writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); - writew(command, sabi_iface + SABI_IFACE_SUB); - writeb(0, sabi_iface + SABI_IFACE_COMPLETE); - outb(readb(sabi + sabi_config->header_offsets.iface_func), port); - - /* write protect memory to make it safe */ - outb(readb(sabi + sabi_config->header_offsets.re_mem), port); - - /* see if the command actually succeeded */ - complete = readb(sabi_iface + SABI_IFACE_COMPLETE); - iface_data = readb(sabi_iface + SABI_IFACE_DATA); - if (complete != 0xaa || iface_data == 0xff) { - pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", - command, complete, iface_data); - retval = -EINVAL; - goto exit; - } - /* - * Save off the data into a structure so the caller use it. - * Right now we only want the first 4 bytes, - * There are commands that need more, but not for the ones we - * currently care about. - */ - sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); - sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); - sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); - sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); - -exit: - mutex_unlock(&sabi_mutex); - return retval; - -} - -static int sabi_set_command(u8 command, u8 data) -{ - int retval = 0; - u16 port = readw(sabi + sabi_config->header_offsets.port); - u8 complete, iface_data; - - mutex_lock(&sabi_mutex); - - /* enable memory to be able to write to it */ - outb(readb(sabi + sabi_config->header_offsets.en_mem), port); - - /* write out the command */ - writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); - writew(command, sabi_iface + SABI_IFACE_SUB); - writeb(0, sabi_iface + SABI_IFACE_COMPLETE); - writeb(data, sabi_iface + SABI_IFACE_DATA); - outb(readb(sabi + sabi_config->header_offsets.iface_func), port); - - /* write protect memory to make it safe */ - outb(readb(sabi + sabi_config->header_offsets.re_mem), port); - - /* see if the command actually succeeded */ - complete = readb(sabi_iface + SABI_IFACE_COMPLETE); - iface_data = readb(sabi_iface + SABI_IFACE_DATA); - if (complete != 0xaa || iface_data == 0xff) { - pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", - command, complete, iface_data); - retval = -EINVAL; - } - - mutex_unlock(&sabi_mutex); - return retval; -} - -static void test_backlight(void) -{ - struct sabi_retval sretval; - - sabi_get_command(sabi_config->commands.get_backlight, &sretval); - printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); - - sabi_set_command(sabi_config->commands.set_backlight, 0); - printk(KERN_DEBUG "backlight should be off\n"); - - sabi_get_command(sabi_config->commands.get_backlight, &sretval); - printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); - - msleep(1000); - - sabi_set_command(sabi_config->commands.set_backlight, 1); - printk(KERN_DEBUG "backlight should be on\n"); - - sabi_get_command(sabi_config->commands.get_backlight, &sretval); - printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); -} - -static void test_wireless(void) -{ - struct sabi_retval sretval; - - sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); - printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); - - sabi_set_command(sabi_config->commands.set_wireless_button, 0); - printk(KERN_DEBUG "wireless led should be off\n"); - - sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); - printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); - - msleep(1000); - - sabi_set_command(sabi_config->commands.set_wireless_button, 1); - printk(KERN_DEBUG "wireless led should be on\n"); - - sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); - printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); -} - -static u8 read_brightness(void) -{ - struct sabi_retval sretval; - int user_brightness = 0; - int retval; - - retval = sabi_get_command(sabi_config->commands.get_brightness, - &sretval); - if (!retval) { - user_brightness = sretval.retval[0]; - if (user_brightness != 0) - user_brightness -= sabi_config->min_brightness; - } - return user_brightness; -} - -static void set_brightness(u8 user_brightness) -{ - u8 user_level = user_brightness - sabi_config->min_brightness; - - sabi_set_command(sabi_config->commands.set_brightness, user_level); -} - -static int get_brightness(struct backlight_device *bd) -{ - return (int)read_brightness(); -} - -static int update_status(struct backlight_device *bd) -{ - set_brightness(bd->props.brightness); - - if (bd->props.power == FB_BLANK_UNBLANK) - sabi_set_command(sabi_config->commands.set_backlight, 1); - else - sabi_set_command(sabi_config->commands.set_backlight, 0); - return 0; -} - -static const struct backlight_ops backlight_ops = { - .get_brightness = get_brightness, - .update_status = update_status, -}; - -static int rfkill_set(void *data, bool blocked) -{ - /* Do something with blocked...*/ - /* - * blocked == false is on - * blocked == true is off - */ - if (blocked) - sabi_set_command(sabi_config->commands.set_wireless_button, 0); - else - sabi_set_command(sabi_config->commands.set_wireless_button, 1); - - return 0; -} - -static struct rfkill_ops rfkill_ops = { - .set_block = rfkill_set, -}; - -static int init_wireless(struct platform_device *sdev) -{ - int retval; - - rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, - &rfkill_ops, NULL); - if (!rfk) - return -ENOMEM; - - retval = rfkill_register(rfk); - if (retval) { - rfkill_destroy(rfk); - return -ENODEV; - } - - return 0; -} - -static void destroy_wireless(void) -{ - rfkill_unregister(rfk); - rfkill_destroy(rfk); -} - -static ssize_t get_performance_level(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sabi_retval sretval; - int retval; - int i; - - /* Read the state */ - retval = sabi_get_command(sabi_config->commands.get_performance_level, - &sretval); - if (retval) - return retval; - - /* The logic is backwards, yeah, lots of fun... */ - for (i = 0; sabi_config->performance_levels[i].name; ++i) { - if (sretval.retval[0] == sabi_config->performance_levels[i].value) - return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); - } - return sprintf(buf, "%s\n", "unknown"); -} - -static ssize_t set_performance_level(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - if (count >= 1) { - int i; - for (i = 0; sabi_config->performance_levels[i].name; ++i) { - const struct sabi_performance_level *level = - &sabi_config->performance_levels[i]; - if (!strncasecmp(level->name, buf, strlen(level->name))) { - sabi_set_command(sabi_config->commands.set_performance_level, - level->value); - break; - } - } - if (!sabi_config->performance_levels[i].name) - return -EINVAL; - } - return count; -} -static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, - get_performance_level, set_performance_level); - - -static int __init dmi_check_cb(const struct dmi_system_id *id) -{ - pr_info("found laptop model '%s'\n", - id->ident); - return 0; -} - -static struct dmi_system_id __initdata samsung_dmi_table[] = { - { - .ident = "N128", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N128"), - DMI_MATCH(DMI_BOARD_NAME, "N128"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N130", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N130"), - DMI_MATCH(DMI_BOARD_NAME, "N130"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X125", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X125"), - DMI_MATCH(DMI_BOARD_NAME, "X125"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X120/X170", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), - DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NC10", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), - DMI_MATCH(DMI_BOARD_NAME, "NC10"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NP-Q45", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), - DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X360"), - DMI_MATCH(DMI_BOARD_NAME, "X360"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R410 Plus", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), - DMI_MATCH(DMI_BOARD_NAME, "R460"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R518", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R518"), - DMI_MATCH(DMI_BOARD_NAME, "R518"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R519/R719", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), - DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N150/N210/N220/N230", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N150P/N210P/N220P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), - DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R530/R730", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), - DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NF110/NF210/NF310", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), - DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N145P/N250P/N260P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), - DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R70/R71", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), - DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "P460", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "P460"), - DMI_MATCH(DMI_BOARD_NAME, "P460"), - }, - .callback = dmi_check_cb, - }, - { }, -}; -MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); - -static int find_signature(void __iomem *memcheck, const char *testStr) -{ - int i = 0; - int loca; - - for (loca = 0; loca < 0xffff; loca++) { - char temp = readb(memcheck + loca); - - if (temp == testStr[i]) { - if (i == strlen(testStr)-1) - break; - ++i; - } else { - i = 0; - } - } - return loca; -} - -static int __init samsung_init(void) -{ - struct backlight_properties props; - struct sabi_retval sretval; - unsigned int ifaceP; - int i; - int loca; - int retval; - - mutex_init(&sabi_mutex); - - if (!force && !dmi_check_system(samsung_dmi_table)) - return -ENODEV; - - f0000_segment = ioremap_nocache(0xf0000, 0xffff); - if (!f0000_segment) { - pr_err("Can't map the segment at 0xf0000\n"); - return -EINVAL; - } - - /* Try to find one of the signatures in memory to find the header */ - for (i = 0; sabi_configs[i].test_string != 0; ++i) { - sabi_config = &sabi_configs[i]; - loca = find_signature(f0000_segment, sabi_config->test_string); - if (loca != 0xffff) - break; - } - - if (loca == 0xffff) { - pr_err("This computer does not support SABI\n"); - goto error_no_signature; - } - - /* point to the SMI port Number */ - loca += 1; - sabi = (f0000_segment + loca); - - if (debug) { - printk(KERN_DEBUG "This computer supports SABI==%x\n", - loca + 0xf0000 - 6); - printk(KERN_DEBUG "SABI header:\n"); - printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", - readw(sabi + sabi_config->header_offsets.port)); - printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", - readb(sabi + sabi_config->header_offsets.iface_func)); - printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", - readb(sabi + sabi_config->header_offsets.en_mem)); - printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", - readb(sabi + sabi_config->header_offsets.re_mem)); - printk(KERN_DEBUG " SABI data offset = 0x%04x\n", - readw(sabi + sabi_config->header_offsets.data_offset)); - printk(KERN_DEBUG " SABI data segment = 0x%04x\n", - readw(sabi + sabi_config->header_offsets.data_segment)); - } - - /* Get a pointer to the SABI Interface */ - ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; - ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; - sabi_iface = ioremap_nocache(ifaceP, 16); - if (!sabi_iface) { - pr_err("Can't remap %x\n", ifaceP); - goto exit; - } - if (debug) { - printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); - printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); - - test_backlight(); - test_wireless(); - - retval = sabi_get_command(sabi_config->commands.get_brightness, - &sretval); - printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); - } - - /* Turn on "Linux" mode in the BIOS */ - if (sabi_config->commands.set_linux != 0xff) { - retval = sabi_set_command(sabi_config->commands.set_linux, - 0x81); - if (retval) { - pr_warn("Linux mode was not set!\n"); - goto error_no_platform; - } - } - - /* knock up a platform device to hang stuff off of */ - sdev = platform_device_register_simple("samsung", -1, NULL, 0); - if (IS_ERR(sdev)) - goto error_no_platform; - - /* create a backlight device to talk to this one */ - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = sabi_config->max_brightness; - backlight_device = backlight_device_register("samsung", &sdev->dev, - NULL, &backlight_ops, - &props); - if (IS_ERR(backlight_device)) - goto error_no_backlight; - - backlight_device->props.brightness = read_brightness(); - backlight_device->props.power = FB_BLANK_UNBLANK; - backlight_update_status(backlight_device); - - retval = init_wireless(sdev); - if (retval) - goto error_no_rfk; - - retval = device_create_file(&sdev->dev, &dev_attr_performance_level); - if (retval) - goto error_file_create; - -exit: - return 0; - -error_file_create: - destroy_wireless(); - -error_no_rfk: - backlight_device_unregister(backlight_device); - -error_no_backlight: - platform_device_unregister(sdev); - -error_no_platform: - iounmap(sabi_iface); - -error_no_signature: - iounmap(f0000_segment); - return -EINVAL; -} - -static void __exit samsung_exit(void) -{ - /* Turn off "Linux" mode in the BIOS */ - if (sabi_config->commands.set_linux != 0xff) - sabi_set_command(sabi_config->commands.set_linux, 0x80); - - device_remove_file(&sdev->dev, &dev_attr_performance_level); - backlight_device_unregister(backlight_device); - destroy_wireless(); - iounmap(sabi_iface); - iounmap(f0000_segment); - platform_device_unregister(sdev); -} - -module_init(samsung_init); -module_exit(samsung_exit); - -MODULE_AUTHOR("Greg Kroah-Hartman "); -MODULE_DESCRIPTION("Samsung Backlight driver"); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 8713b04ab8da256493410bd4f25170d2e0836534 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 8 Apr 2011 17:02:05 +0200 Subject: samsung-laptop: set backlight type Cherry-picked from drivers/staging/samsung-laptop/samsung-laptop.c Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 39f30ff..d347116 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -781,6 +781,7 @@ static int __init samsung_init(void) /* create a backlight device to talk to this one */ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = sabi_config->max_brightness; backlight_device = backlight_device_register("samsung", &sdev->dev, NULL, &backlight_ops, -- cgit v0.10.2 From 855b8bc9953fdf40095fdec9d91d49736ca7b17c Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Tue, 5 Apr 2011 23:38:35 +0900 Subject: sony-laptop: only show the handles sysfs file in debug mode It makes no sense to expose this type of information to userspace unless the driver was explicitly loaded with the debug option. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 33c3b8c..33d9555 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -771,11 +771,6 @@ static int sony_nc_handles_setup(struct platform_device *pd) if (!handles) return -ENOMEM; - sysfs_attr_init(&handles->devattr.attr); - handles->devattr.attr.name = "handles"; - handles->devattr.attr.mode = S_IRUGO; - handles->devattr.show = sony_nc_handles_show; - for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { if (!acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i + 0x20, &result)) { @@ -785,11 +780,18 @@ static int sony_nc_handles_setup(struct platform_device *pd) } } - /* allow reading capabilities via sysfs */ - if (device_create_file(&pd->dev, &handles->devattr)) { - kfree(handles); - handles = NULL; - return -1; + if (debug) { + sysfs_attr_init(&handles->devattr.attr); + handles->devattr.attr.name = "handles"; + handles->devattr.attr.mode = S_IRUGO; + handles->devattr.show = sony_nc_handles_show; + + /* allow reading capabilities via sysfs */ + if (device_create_file(&pd->dev, &handles->devattr)) { + kfree(handles); + handles = NULL; + return -1; + } } return 0; @@ -798,7 +800,8 @@ static int sony_nc_handles_setup(struct platform_device *pd) static int sony_nc_handles_cleanup(struct platform_device *pd) { if (handles) { - device_remove_file(&pd->dev, &handles->devattr); + if (debug) + device_remove_file(&pd->dev, &handles->devattr); kfree(handles); handles = NULL; } -- cgit v0.10.2 From df410d522410e676602a14eb5957c4b3e1fa3902 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Tue, 5 Apr 2011 23:38:34 +0900 Subject: sony-laptop: keyboard backlight fixes Restore the original state on module removal, set the latest values on resume. When setting the keyboard backlight mode try to turn on/off backlight immediately. [malattia@linux.it: patch taken from a largely modified sony-laptop.c, ported and slightly modified to use defines already available.] Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 33d9555..8f709ae 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -138,6 +138,8 @@ MODULE_PARM_DESC(kbd_backlight_timeout, "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " "(default: 0)"); +static void sony_nc_kbd_backlight_resume(void); + enum sony_nc_rfkill { SONY_WIFI, SONY_BLUETOOTH, @@ -1176,6 +1178,9 @@ static int sony_nc_resume(struct acpi_device *device) /* re-read rfkill state */ sony_nc_rfkill_update(); + /* restore kbd backlight states */ + sony_nc_kbd_backlight_resume(); + return 0; } @@ -1363,6 +1368,7 @@ out_no_enum: #define KBDBL_HANDLER 0x137 #define KBDBL_PRESENT 0xB00 #define SET_MODE 0xC00 +#define SET_STATE 0xD00 #define SET_TIMEOUT 0xE00 struct kbd_backlight { @@ -1385,6 +1391,10 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) (value << 0x10) | SET_MODE, &result)) return -EIO; + /* Try to turn the light on/off immediately */ + sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, + &result); + kbdbl_handle->mode = value; return 0; @@ -1466,7 +1476,7 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd) { int result; - if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) + if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) return 0; if (!(result & 0x02)) return 0; @@ -1509,13 +1519,36 @@ outkzalloc: static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) { if (kbdbl_handle) { + int result; + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); + + /* restore the default hw behaviour */ + sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); + sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); + kfree(kbdbl_handle); } return 0; } +static void sony_nc_kbd_backlight_resume(void) +{ + int ignore = 0; + + if (!kbdbl_handle) + return; + + if (kbdbl_handle->mode == 0) + sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); + + if (kbdbl_handle->timeout != 0) + sony_call_snc_handle(KBDBL_HANDLER, + (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT, + &ignore); +} + static void sony_nc_backlight_setup(void) { acpi_handle unused; -- cgit v0.10.2 From 08a0799d5736f1494ef35d386570d177447acbfb Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Wed, 6 Apr 2011 17:40:06 +0800 Subject: acer-wmi: Fix capitalisation of GUID in module alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3 needs to be wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3 in module alias for acer-wmi is automatically loaded. Cc: Pali Rohár Cc: Carlos Corbacho Cc: Matthew Garrett Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 5ea6c34..ac4e7f83 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -89,7 +89,7 @@ MODULE_LICENSE("GPL"); #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); -MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); +MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"); MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); enum acer_wmi_event_ids { -- cgit v0.10.2 From b569ab3911aca64841bd819720d2b241aa09d713 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 31 Mar 2011 15:22:33 -0700 Subject: thinkpad-acpi fails to load with newer Thinkpad X201s BIOS The new BIOS has a slightly different EC version string. From a1541710300b083a1a9acff2890d721d15ede62b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 13 Mar 2011 23:46:22 -0700 Subject: [PATCH] thinkpad-acpi: Some BIOS versions don't end in WW, remove check My X201s BIOS version string is 6QET46V1 (1.16 ). The EC version string is 6QHT28WW-1.09. The driver was requiring that both of these have 'WW' in positions 6 and 7. I don't know what the significance of having 'V1' there instead is, but removing the test makes the driver load on my machine. Signed-off-by: Keith Packard Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a08561f..efb3b6b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -8618,8 +8618,7 @@ static bool __pure __init tpacpi_is_valid_fw_id(const char* const s, tpacpi_is_fw_digit(s[1]) && s[2] == t && s[3] == 'T' && tpacpi_is_fw_digit(s[4]) && - tpacpi_is_fw_digit(s[5]) && - s[6] == 'W' && s[7] == 'W'; + tpacpi_is_fw_digit(s[5]); } /* returns 0 - probe ok, or < 0 - probe error. -- cgit v0.10.2 From be85bccaa5aa5a11dcaf85f9e945ffefd253f631 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 12 Apr 2011 13:35:56 -0700 Subject: Revert "vfs: Export file system uuid via /proc//mountinfo" This reverts commit 93f1c20bc8cdb757be50566eff88d65c3b26881f. It turns out that libmount misparses it because it adds a '-' character in the uuid string, which libmount then incorrectly confuses with the separator string (" - ") at the end of all the optional arguments. Upstream libmount (in the util-linux tree) has been fixed, but until that fix actually percolates up to users, we'd better not expose this change in the kernel. Let's revisit this later (possibly by exposing the UUID without any '-' characters in it, avoiding the user-space bug). Reported-by: Dave Jones Cc: Aneesh Kumar K.V Cc: Al Viro Cc: Karel Zak Cc: Ram Pai Cc: Miklos Szeredi Cc: Eric Sandeen Signed-off-by: Linus Torvalds diff --git a/fs/namespace.c b/fs/namespace.c index 7dba2ed..d99bcf5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1030,18 +1030,6 @@ const struct seq_operations mounts_op = { .show = show_vfsmnt }; -static int uuid_is_nil(u8 *uuid) -{ - int i; - u8 *cp = (u8 *)uuid; - - for (i = 0; i < 16; i++) { - if (*cp++) - return 0; - } - return 1; -} - static int show_mountinfo(struct seq_file *m, void *v) { struct proc_mounts *p = m->private; @@ -1085,10 +1073,6 @@ static int show_mountinfo(struct seq_file *m, void *v) if (IS_MNT_UNBINDABLE(mnt)) seq_puts(m, " unbindable"); - if (!uuid_is_nil(mnt->mnt_sb->s_uuid)) - /* print the uuid */ - seq_printf(m, " uuid:%pU", mnt->mnt_sb->s_uuid); - /* Filesystem specific data */ seq_puts(m, " - "); show_type(m, sb); diff --git a/include/linux/fs.h b/include/linux/fs.h index dbd860a..5b14843 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1403,7 +1403,6 @@ struct super_block { wait_queue_head_t s_wait_unfrozen; char s_id[32]; /* Informational name */ - u8 s_uuid[16]; /* UUID */ void *s_fs_info; /* Filesystem private info */ fmode_t s_mode; -- cgit v0.10.2 From 95042f9eb78a8d9a17455e2ef263f2f310ecef15 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 12 Apr 2011 14:15:51 -0700 Subject: vm: fix mlock() on stack guard page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 53a7706d5ed8 ("mlock: do not hold mmap_sem for extended periods of time") changed mlock() to care about the exact number of pages that __get_user_pages() had brought it. Before, it would only care about errors. And that doesn't work, because we also handled one page specially in __mlock_vma_pages_range(), namely the stack guard page. So when that case was handled, the number of pages that the function returned was off by one. In particular, it could be zero, and then the caller would end up not making any progress at all. Rather than try to fix up that off-by-one error for the mlock case specially, this just moves the logic to handle the stack guard page into__get_user_pages() itself, thus making all the counts come out right automatically. Reported-by: Robert Święcki Cc: Hugh Dickins Cc: Oleg Nesterov Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/mm/memory.c b/mm/memory.c index 9da8cab..b623a24 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1410,6 +1410,13 @@ no_page_table: return page; } +static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) +{ + return (vma->vm_flags & VM_GROWSDOWN) && + (vma->vm_start == addr) && + !vma_stack_continue(vma->vm_prev, addr); +} + /** * __get_user_pages() - pin user pages in memory * @tsk: task_struct of target task @@ -1488,7 +1495,6 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, vma = find_extend_vma(mm, start); if (!vma && in_gate_area(mm, start)) { unsigned long pg = start & PAGE_MASK; - struct vm_area_struct *gate_vma = get_gate_vma(mm); pgd_t *pgd; pud_t *pud; pmd_t *pmd; @@ -1513,10 +1519,11 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, pte_unmap(pte); return i ? : -EFAULT; } + vma = get_gate_vma(mm); if (pages) { struct page *page; - page = vm_normal_page(gate_vma, start, *pte); + page = vm_normal_page(vma, start, *pte); if (!page) { if (!(gup_flags & FOLL_DUMP) && is_zero_pfn(pte_pfn(*pte))) @@ -1530,12 +1537,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, get_page(page); } pte_unmap(pte); - if (vmas) - vmas[i] = gate_vma; - i++; - start += PAGE_SIZE; - nr_pages--; - continue; + goto next_page; } if (!vma || @@ -1549,6 +1551,13 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, continue; } + /* + * If we don't actually want the page itself, + * and it's the stack guard page, just skip it. + */ + if (!pages && stack_guard_page(vma, start)) + goto next_page; + do { struct page *page; unsigned int foll_flags = gup_flags; @@ -1631,6 +1640,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, flush_anon_page(vma, page, start); flush_dcache_page(page); } +next_page: if (vmas) vmas[i] = vma; i++; diff --git a/mm/mlock.c b/mm/mlock.c index 2689a08c..6b55e3e 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -135,13 +135,6 @@ void munlock_vma_page(struct page *page) } } -static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSDOWN) && - (vma->vm_start == addr) && - !vma_stack_continue(vma->vm_prev, addr); -} - /** * __mlock_vma_pages_range() - mlock a range of pages in the vma. * @vma: target vma @@ -188,12 +181,6 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, if (vma->vm_flags & VM_LOCKED) gup_flags |= FOLL_MLOCK; - /* We don't try to access the guard page of a stack vma */ - if (stack_guard_page(vma, start)) { - addr += PAGE_SIZE; - nr_pages--; - } - return __get_user_pages(current, mm, addr, nr_pages, gup_flags, NULL, NULL, nonblocking); } -- cgit v0.10.2 From 0d88f6e804c824454b5ed0d3034ed3dcf7467a87 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 12 Apr 2011 19:18:08 +1000 Subject: nfs: don't call __mark_inode_dirty while holding i_lock nfs_scan_commit() is called with the inode->i_lock held, but it then calls __mark_inode_dirty() while still holding the lock. This causes a deadlock. Push the inode->i_lock into nfs_scan_commit() so it can protect only the parts of the code it needs to and can be dropped before the call to __mark_inode_dirty() to avoid the deadlock. Signed-off-by: Dave Chinner Tested-by: Will Simoneau Signed-off-by: Linus Torvalds diff --git a/fs/nfs/write.c b/fs/nfs/write.c index af0c627..e4cbc11 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -542,11 +542,15 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, u if (!nfs_need_commit(nfsi)) return 0; + spin_lock(&inode->i_lock); ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); if (ret > 0) nfsi->ncommit -= ret; + spin_unlock(&inode->i_lock); + if (nfs_need_commit(NFS_I(inode))) __mark_inode_dirty(inode, I_DIRTY_DATASYNC); + return ret; } #else @@ -1483,9 +1487,7 @@ int nfs_commit_inode(struct inode *inode, int how) res = nfs_commit_set_lock(NFS_I(inode), may_wait); if (res <= 0) goto out_mark_dirty; - spin_lock(&inode->i_lock); res = nfs_scan_commit(inode, &head, 0, 0); - spin_unlock(&inode->i_lock); if (res) { int error; -- cgit v0.10.2 From 0bba01695b74fdd2f9286243bb39f88544d81401 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 12 Apr 2011 15:21:04 -0700 Subject: vfs: Re-introduce s_uuid in the superblock Gaah. When commit be85bccaa5aa reverted the export of file system uuid via /proc//mountinfo, it also unintentionally removed the s_uuid field in struct super_block. I didn't mean to do that, since filesystems have been taught to fill it in (and we want to keep it for future re-introduction in the mountinfo file). Stupid of me. This adds it back in. Signed-off-by: Linus Torvalds diff --git a/include/linux/fs.h b/include/linux/fs.h index 5b14843..dbd860a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1403,6 +1403,7 @@ struct super_block { wait_queue_head_t s_wait_unfrozen; char s_id[32]; /* Informational name */ + u8 s_uuid[16]; /* UUID */ void *s_fs_info; /* Filesystem private info */ fmode_t s_mode; -- cgit v0.10.2 From 92656d707e961c88b6f931038c7dc41790a52e1e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 13:32:13 -0400 Subject: drm/radeon/kms: clean up gart dummy page handling As per Konrad's original patch, the dummy page used by the gart code and allocated in radeon_gart_init() was not freed properly in radeon_gart_fini(). At the same time r6xx and newer allocated and freed the dummy page on their own. So to do Konrad's patch one better, just remove the allocation and freeing of the dummy page in the r6xx, 7xx, evergreen, and ni code and allocate and free in the gart_init/fini() functions for all asics. Cc: Jerome Glisse Signed-off-by: Alex Deucher Acked-by: Konrad Rzeszutek Wilk Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0b0cc74..cff7144 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3036,9 +3036,6 @@ int evergreen_init(struct radeon_device *rdev) { int r; - r = radeon_dummy_page_init(rdev); - if (r) - return r; /* This don't do much */ r = radeon_gem_init(rdev); if (r) @@ -3150,7 +3147,6 @@ void evergreen_fini(struct radeon_device *rdev) radeon_atombios_fini(rdev); kfree(rdev->bios); rdev->bios = NULL; - radeon_dummy_page_fini(rdev); } static void evergreen_pcie_gen2_enable(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index be271c4..304fc76 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2509,9 +2509,6 @@ int r600_init(struct radeon_device *rdev) { int r; - r = radeon_dummy_page_init(rdev); - if (r) - return r; if (r600_debugfs_mc_info_init(rdev)) { DRM_ERROR("Failed to register debugfs file for mc !\n"); } @@ -2625,7 +2622,6 @@ void r600_fini(struct radeon_device *rdev) radeon_atombios_fini(rdev); kfree(rdev->bios); rdev->bios = NULL; - radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index f0534ef..8a955bb 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -285,4 +285,6 @@ void radeon_gart_fini(struct radeon_device *rdev) rdev->gart.pages = NULL; rdev->gart.pages_addr = NULL; rdev->gart.ttm_alloced = NULL; + + radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index b974ac7..4faa2e5 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1255,9 +1255,6 @@ int rv770_init(struct radeon_device *rdev) { int r; - r = radeon_dummy_page_init(rdev); - if (r) - return r; /* This don't do much */ r = radeon_gem_init(rdev); if (r) @@ -1372,7 +1369,6 @@ void rv770_fini(struct radeon_device *rdev) radeon_atombios_fini(rdev); kfree(rdev->bios); rdev->bios = NULL; - radeon_dummy_page_fini(rdev); } static void rv770_pcie_gen2_enable(struct radeon_device *rdev) -- cgit v0.10.2 From 71e16bfbd2b1c63d4d97cc5059694c9346aee340 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 13:33:27 -0400 Subject: drm/radeon/kms: fix suspend on rv530 asics Apparently only rv515 asics need the workaround added in f24d86f1a49505cdea56728b853a5d0a3f8e3d11 (drm/radeon/kms: fix resume regression for some r5xx laptops). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=34709 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 258fa5e..d71d375 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -32,6 +32,7 @@ #include "atom.h" #include "atom-names.h" #include "atom-bits.h" +#include "radeon.h" #define ATOM_COND_ABOVE 0 #define ATOM_COND_ABOVEOREQUAL 1 @@ -101,7 +102,9 @@ static void debug_print_spaces(int n) static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data) { + struct radeon_device *rdev = ctx->card->dev->dev_private; uint32_t temp = 0xCDCDCDCD; + while (1) switch (CU8(base)) { case ATOM_IIO_NOP: @@ -112,7 +115,8 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, base += 3; break; case ATOM_IIO_WRITE: - (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); + if (rdev->family == CHIP_RV515) + (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); base += 3; break; -- cgit v0.10.2 From b4df8be1048eb6c8c5a8bd1646f5989fd34b549e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 13:40:18 -0400 Subject: drm/radeon/kms: fix pcie_p callbacks on btc and cayman btc and cayman asics use the same callback for pcie port registers. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index eb888ee..ca57619 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -94,7 +94,7 @@ static void radeon_register_accessor_init(struct radeon_device *rdev) rdev->mc_rreg = &rs600_mc_rreg; rdev->mc_wreg = &rs600_mc_wreg; } - if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_HEMLOCK)) { + if (rdev->family >= CHIP_R600) { rdev->pciep_rreg = &r600_pciep_rreg; rdev->pciep_wreg = &r600_pciep_wreg; } -- cgit v0.10.2 From 8a83ec5ee824a6bd431b49bdb2428c8bf88f03eb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 14:49:23 -0400 Subject: drm/radeon/kms: add voltage type to atom set voltage function This is needed for setting voltages other than vddc. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index cff7144..f244817 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -122,7 +122,7 @@ void evergreen_pm_misc(struct radeon_device *rdev) if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { - radeon_atom_set_voltage(rdev, voltage->voltage); + radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 304fc76..15d5829 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -587,7 +587,7 @@ void r600_pm_misc(struct radeon_device *rdev) if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { - radeon_atom_set_voltage(rdev, voltage->voltage); + radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG_DRIVER("Setting: v: %d\n", voltage->voltage); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 93f5365..9955740 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -177,7 +177,7 @@ void radeon_pm_suspend(struct radeon_device *rdev); void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); -void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type); void rs690_pm_info(struct radeon_device *rdev); extern int rv6xx_get_temp(struct radeon_device *rdev); extern int rv770_get_temp(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 99768d9..330a5b5 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2577,25 +2577,25 @@ union set_voltage { struct _SET_VOLTAGE_PARAMETERS_V2 v2; }; -void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level) +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type) { union set_voltage args; int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); - u8 frev, crev, volt_index = level; + u8 frev, crev, volt_index = voltage_level; if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; switch (crev) { case 1: - args.v1.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v1.ucVoltageType = voltage_type; args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE; args.v1.ucVoltageIndex = volt_index; break; case 2: - args.v2.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v2.ucVoltageType = voltage_type; args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE; - args.v2.usVoltageLevel = cpu_to_le16(level); + args.v2.usVoltageLevel = cpu_to_le16(voltage_level); break; default: DRM_ERROR("Unknown table version %d, %d\n", frev, crev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 08de669..4010571 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -23,6 +23,7 @@ #include "drmP.h" #include "radeon.h" #include "avivod.h" +#include "atom.h" #ifdef CONFIG_ACPI #include #endif @@ -535,7 +536,8 @@ void radeon_pm_resume(struct radeon_device *rdev) /* set up the default clocks if the MC ucode is loaded */ if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { if (rdev->pm.default_vddc) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddc); + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, + SET_VOLTAGE_TYPE_ASIC_VDDC); if (rdev->pm.default_sclk) radeon_set_engine_clock(rdev, rdev->pm.default_sclk); if (rdev->pm.default_mclk) @@ -585,7 +587,8 @@ int radeon_pm_init(struct radeon_device *rdev) /* set up the default clocks if the MC ucode is loaded */ if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { if (rdev->pm.default_vddc) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddc); + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, + SET_VOLTAGE_TYPE_ASIC_VDDC); if (rdev->pm.default_sclk) radeon_set_engine_clock(rdev, rdev->pm.default_sclk); if (rdev->pm.default_mclk) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 876cebc..6e3b11e 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -114,7 +114,7 @@ void rs600_pm_misc(struct radeon_device *rdev) udelay(voltage->delay); } } else if (voltage->type == VOLTAGE_VDDC) - radeon_atom_set_voltage(rdev, voltage->vddc_id); + radeon_atom_set_voltage(rdev, voltage->vddc_id, SET_VOLTAGE_TYPE_ASIC_VDDC); dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4faa2e5..ef8a5bab 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -106,7 +106,7 @@ void rv770_pm_misc(struct radeon_device *rdev) if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { - radeon_atom_set_voltage(rdev, voltage->voltage); + radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } -- cgit v0.10.2 From 2feea49ae34a2fcea1035136b85f5eaca56f5cd0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 14:49:24 -0400 Subject: drm/radeon/kms: properly program vddci on evergreen+ Change vddci as well as vddc when changing power modes on evergreen/ni. Also, properly set vddci on boot up for ni cards. The vbios only sets the limited clocks and voltages on boot until the mc ucode is loaded. This should fix stability problems on some btc cards. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f244817..3453910 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -120,11 +120,16 @@ void evergreen_pm_misc(struct radeon_device *rdev) struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx]; struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; - if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { - if (voltage->voltage != rdev->pm.current_vddc) { + if (voltage->type == VOLTAGE_SW) { + if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) { radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; - DRM_DEBUG("Setting: v: %d\n", voltage->voltage); + DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage); + } + if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) { + radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI); + rdev->pm.current_vddci = voltage->vddci; + DRM_DEBUG("Setting: vddci: %d\n", voltage->vddci); } } } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 9955740..ba643b5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -767,7 +767,9 @@ struct radeon_voltage { u8 vddci_id; /* index into vddci voltage table */ bool vddci_enabled; /* r6xx+ sw */ - u32 voltage; + u16 voltage; + /* evergreen+ vddci */ + u16 vddci; }; /* clock mode flags */ @@ -835,10 +837,12 @@ struct radeon_pm { int default_power_state_index; u32 current_sclk; u32 current_mclk; - u32 current_vddc; + u16 current_vddc; + u16 current_vddci; u32 default_sclk; u32 default_mclk; - u32 default_vddc; + u16 default_vddc; + u16 default_vddci; struct radeon_i2c_chan *i2c_bus; /* selected pm method */ enum radeon_pm_method pm_method; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 330a5b5..f5d12fb 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2176,24 +2176,27 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r } } -static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) +static void radeon_atombios_get_default_voltages(struct radeon_device *rdev, + u16 *vddc, u16 *vddci) { struct radeon_mode_info *mode_info = &rdev->mode_info; int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); u8 frev, crev; u16 data_offset; union firmware_info *firmware_info; - u16 vddc = 0; + + *vddc = 0; + *vddci = 0; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); - vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); + *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); + if ((frev == 2) && (crev >= 2)) + *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage); } - - return vddc; } static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, @@ -2203,7 +2206,9 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde int j; u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); u32 misc2 = le16_to_cpu(non_clock_info->usClassification); - u16 vddc = radeon_atombios_get_default_vddc(rdev); + u16 vddc, vddci; + + radeon_atombios_get_default_voltages(rdev, &vddc, &vddci); rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; @@ -2244,6 +2249,7 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage; + rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci; } else { /* patch the table values with the default slck/mclk from firmware info */ for (j = 0; j < mode_index; j++) { @@ -2286,6 +2292,8 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = le16_to_cpu(clock_info->evergreen.usVDDC); + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci = + le16_to_cpu(clock_info->evergreen.usVDDCI); } else { sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); sclk |= clock_info->r600.ucEngineClockHigh << 16; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 4010571..86eda1e 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -538,6 +538,9 @@ void radeon_pm_resume(struct radeon_device *rdev) if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, SET_VOLTAGE_TYPE_ASIC_VDDC); + if (rdev->pm.default_vddci) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, + SET_VOLTAGE_TYPE_ASIC_VDDCI); if (rdev->pm.default_sclk) radeon_set_engine_clock(rdev, rdev->pm.default_sclk); if (rdev->pm.default_mclk) @@ -550,6 +553,7 @@ void radeon_pm_resume(struct radeon_device *rdev) rdev->pm.current_sclk = rdev->pm.default_sclk; rdev->pm.current_mclk = rdev->pm.default_mclk; rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; -- cgit v0.10.2 From cbf15bdbbdaec3b2e3b4f476803a6149707d1a1f Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 12 Apr 2011 14:27:47 +0400 Subject: i915: select VIDEO_OUTPUT_CONTROL for ACPI_VIDEO fix Kconfig warning: (DRM_I915 && STUB_POULSBO) selects ACPI_VIDEO which has unmet direct dependencies (ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT) Signed-off-by: Konstantin Khlebnikov Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index a6feb78c..c58f691 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -96,6 +96,7 @@ config DRM_I915 # i915 depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick select BACKLIGHT_CLASS_DEVICE if ACPI + select VIDEO_OUTPUT_CONTROL if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI select ACPI_BUTTON if ACPI diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig index 70e60a4..4199179 100644 --- a/drivers/gpu/stub/Kconfig +++ b/drivers/gpu/stub/Kconfig @@ -5,6 +5,7 @@ config STUB_POULSBO # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick select BACKLIGHT_CLASS_DEVICE if ACPI + select VIDEO_OUTPUT_CONTROL if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI select THERMAL if ACPI -- cgit v0.10.2 From d87dfdbfc91c5e37288e7e8f7afdd992ba61a60d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Apr 2011 09:15:09 +1000 Subject: Revert "ttm: Utilize the DMA API for pages that have TTM_PAGE_FLAG_DMA32 set." This reverts commit 69a07f0b117a40fcc1a479358d8e1f41793617f2. We've tracked a number of problems back to this, and Thomas thinks we should redesign this for .40/41 anyways so I'm happy to revert it. Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 737a2a2e..9d9d929 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -683,22 +683,14 @@ int ttm_get_pages(struct list_head *pages, int flags, gfp_flags |= GFP_HIGHUSER; for (r = 0; r < count; ++r) { - if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) { - void *addr; - addr = dma_alloc_coherent(NULL, PAGE_SIZE, - &dma_address[r], - gfp_flags); - if (addr == NULL) - return -ENOMEM; - p = virt_to_page(addr); - } else - p = alloc_page(gfp_flags); + p = alloc_page(gfp_flags); if (!p) { printk(KERN_ERR TTM_PFX "Unable to allocate page."); return -ENOMEM; } + list_add(&p->lru, pages); } return 0; @@ -746,24 +738,12 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags, unsigned long irq_flags; struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); struct page *p, *tmp; - unsigned r; if (pool == NULL) { /* No pool for this memory type so free the pages */ - r = page_count-1; list_for_each_entry_safe(p, tmp, pages, lru) { - if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) { - void *addr = page_address(p); - WARN_ON(!addr || !dma_address[r]); - if (addr) - dma_free_coherent(NULL, PAGE_SIZE, - addr, - dma_address[r]); - dma_address[r] = 0; - } else - __free_page(p); - r--; + __free_page(p); } /* Make the pages list empty */ INIT_LIST_HEAD(pages); -- cgit v0.10.2 From 2582b6efceb43dce63b4a1090d289934067a972d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Apr 2011 09:20:24 +1000 Subject: Revert "i915: restore only the mode of this driver on lastclose" This reverts commit 0a0883c8433c743dad0a4d9ebe2717558f2c209e. this was in my tree by accident, I meant to rebase it out and didn't realise in time. Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 12876f2..7273037 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - intel_fb_restore_mode(dev); + drm_fb_helper_restore(); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1d20712..f5b0d83 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,5 +338,4 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); -extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 96a45c4..5127827 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,19 +264,3 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } - -void intel_fb_restore_mode(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret, i; - - if (!dev_priv->fbdev) - return; - - for (i = 0; i < dev_priv->fbdev->helper.crtc_count; i++) { - struct drm_mode_set *mode_set = &dev_priv->fbdev->helper.crtc_info[i].mode_set; - ret = drm_crtc_helper_set_config(mode_set); - if (ret) - DRM_DEBUG("failed to restore crtc mode\n"); - } -} -- cgit v0.10.2 From 60d48c1e67dc8de0676453de18adba1768fb6fab Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Apr 2011 22:24:45 +0200 Subject: m68k,m68knommu: Wire up name_to_handle_at, open_by_handle_at, clock_adjtime, syncfs Signed-off-by: Geert Uytterhoeven Acked-by: Greg Ungerer Signed-off-by: Linus Torvalds diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 26d851d..29e1790 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -343,10 +343,14 @@ #define __NR_fanotify_init 337 #define __NR_fanotify_mark 338 #define __NR_prlimit64 339 +#define __NR_name_to_handle_at 340 +#define __NR_open_by_handle_at 341 +#define __NR_clock_adjtime 342 +#define __NR_syncfs 343 #ifdef __KERNEL__ -#define NR_syscalls 340 +#define NR_syscalls 344 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S index 1559dea..1359ee6 100644 --- a/arch/m68k/kernel/entry_mm.S +++ b/arch/m68k/kernel/entry_mm.S @@ -750,4 +750,8 @@ sys_call_table: .long sys_fanotify_init .long sys_fanotify_mark .long sys_prlimit64 + .long sys_name_to_handle_at /* 340 */ + .long sys_open_by_handle_at + .long sys_clock_adjtime + .long sys_syncfs diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 79b1ed1..9b8393d 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -358,6 +358,10 @@ ENTRY(sys_call_table) .long sys_fanotify_init .long sys_fanotify_mark .long sys_prlimit64 + .long sys_name_to_handle_at /* 340 */ + .long sys_open_by_handle_at + .long sys_clock_adjtime + .long sys_syncfs .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall -- cgit v0.10.2 From 8faf9e3838c31c426e6203cb7dc6fc0f0bdb8b7e Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Sun, 10 Apr 2011 14:14:43 +0800 Subject: fix the wrong argument of the functions definition The functions of eic_chip's memebers use the wrong argument . Signed-off-by: Wanlong Gao Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index 47ba4b9..755ac59 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -61,34 +61,34 @@ struct eic { static struct eic *nmi_eic; static bool nmi_enabled; -static void eic_ack_irq(struct irq_chip *d) +static void eic_ack_irq(struct irq_data *d) { - struct eic *eic = irq_data_get_irq_chip_data(data); + struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq)); } -static void eic_mask_irq(struct irq_chip *d) +static void eic_mask_irq(struct irq_data *d) { - struct eic *eic = irq_data_get_irq_chip_data(data); + struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq)); } -static void eic_mask_ack_irq(struct irq_chip *d) +static void eic_mask_ack_irq(struct irq_data *d) { - struct eic *eic = irq_data_get_irq_chip_data(data); + struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq)); eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq)); } -static void eic_unmask_irq(struct irq_chip *d) +static void eic_unmask_irq(struct irq_data *d) { - struct eic *eic = irq_data_get_irq_chip_data(data); + struct eic *eic = irq_data_get_irq_chip_data(d); eic_writel(eic, IER, 1 << (d->irq - eic->first_irq)); } -static int eic_set_irq_type(struct irq_chip *d, unsigned int flow_type) +static int eic_set_irq_type(struct irq_data *d, unsigned int flow_type) { - struct eic *eic = irq_data_get_irq_chip_data(data); + struct eic *eic = irq_data_get_irq_chip_data(d); unsigned int irq = d->irq; unsigned int i = irq - eic->first_irq; u32 mode, edge, level; -- cgit v0.10.2 From 024b3f2936c9a9393d2cf37b7c537b29fb894b62 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 10 Apr 2011 06:17:20 +0200 Subject: avr32: At32ap: pio fix typo "))" on gpio_irq_unmask prototype introduce in commit d75f1bfdbccb Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Thomas Gleixner Cc: Hans-Christian Egtvedt Cc: Nicolas Ferre Cc: Patrice Vilchez Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index f308e1d..2e0aa85 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -257,7 +257,7 @@ static void gpio_irq_mask(struct irq_data *d) pio_writel(pio, IDR, 1 << (gpio & 0x1f)); } -static void gpio_irq_unmask(struct irq_data *d)) +static void gpio_irq_unmask(struct irq_data *d) { unsigned gpio = irq_to_gpio(d->irq); struct pio_device *pio = &pio_dev[gpio >> 5]; -- cgit v0.10.2 From 51ef85d8f9ae24475a0cb1bd772258eafec91c69 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 9 Mar 2011 00:32:36 +0000 Subject: avr32: Fix .size directive for cpu_enter_idle gas used to accept (and ignore?) .size directives which referred to undefined symbols, as this does. In binutils 2.21 these are treated as errors. Signed-off-by: Ben Hutchings Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S index 17503b0..f868f4c 100644 --- a/arch/avr32/mach-at32ap/pm-at32ap700x.S +++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S @@ -53,7 +53,7 @@ cpu_enter_idle: st.w r8[TI_flags], r9 unmask_interrupts sleep CPU_SLEEP_IDLE - .size cpu_idle_sleep, . - cpu_idle_sleep + .size cpu_enter_idle, . - cpu_enter_idle /* * Common return path for PM functions that don't run from -- cgit v0.10.2 From 6e2ad51190cdb11b364377882134513f60dec6b9 Mon Sep 17 00:00:00 2001 From: Ole Henrik Jahren Date: Sun, 6 Mar 2011 20:42:39 +0100 Subject: avr32: fix deadlock when reading clock list in debugfs When writing out /sys/kernel/debug/at32ap_clk, clock list lock is being held while clk_get() is called. clk_get() attempts to take the same lock, which results in deadlock. Introduce and call lock free version, __clk_get(), instead. Signed-off-by: Ole Henrik Jahren Cc: Hans-Christian Egtvedt Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 442f08c..86925fd6 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -35,22 +35,30 @@ void at32_clk_register(struct clk *clk) spin_unlock(&clk_list_lock); } -struct clk *clk_get(struct device *dev, const char *id) +static struct clk *__clk_get(struct device *dev, const char *id) { struct clk *clk; - spin_lock(&clk_list_lock); - list_for_each_entry(clk, &at32_clock_list, list) { if (clk->dev == dev && strcmp(id, clk->name) == 0) { - spin_unlock(&clk_list_lock); return clk; } } - spin_unlock(&clk_list_lock); return ERR_PTR(-ENOENT); } + +struct clk *clk_get(struct device *dev, const char *id) +{ + struct clk *clk; + + spin_lock(&clk_list_lock); + clk = __clk_get(dev, id); + spin_unlock(&clk_list_lock); + + return clk; +} + EXPORT_SYMBOL(clk_get); void clk_put(struct clk *clk) @@ -257,15 +265,15 @@ static int clk_show(struct seq_file *s, void *unused) spin_lock(&clk_list_lock); /* show clock tree as derived from the three oscillators */ - clk = clk_get(NULL, "osc32k"); + clk = __clk_get(NULL, "osc32k"); dump_clock(clk, &r); clk_put(clk); - clk = clk_get(NULL, "osc0"); + clk = __clk_get(NULL, "osc0"); dump_clock(clk, &r); clk_put(clk); - clk = clk_get(NULL, "osc1"); + clk = __clk_get(NULL, "osc1"); dump_clock(clk, &r); clk_put(clk); -- cgit v0.10.2 From 9f0d15aac9987adaff18b85585fb7eaba266e112 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 4 Apr 2011 15:58:04 +0100 Subject: avr32: init cannot ignore signals sent by force_sig_info() We can delete the code that checks to see if we're sending an ignored signal to init because force_sig_info() already handles this case. force_sig_info() will kill init even if the signal handler is SIG_DFL and the scenario described in the comment where init might "generate the same exception over and over again" cannot occur (force_sig_info() clears SIGNAL_UNKILLABLE to ensure that init will die). Also, the use of is_global_init() is not correct in the multhreaded case, as Oleg Nesterov explains, "is_global_init() is not right in theory, /sbin/init can be multithreaded. And, this doesn't cover the sub-namespace inits... I'd suggest to check SIGNAL_UNKILLABLE, but looking closer I think you can simply remove this code." It seems this code was copied from arch/powerpc in March 2007 in commit 623b0355d5b1 "[AVR32] Clean up exception handling code" but the code was deleted from arch/powerpc in November 2009 in commit a0592d42fe3e "powerpc: kill the obsolete code under is_global_init()" So catch up with powerpc and delete the bogus code. Signed-off-by: Matt Fleming Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c index b91b204..7aa2575 100644 --- a/arch/avr32/kernel/traps.c +++ b/arch/avr32/kernel/traps.c @@ -95,28 +95,6 @@ void _exception(long signr, struct pt_regs *regs, int code, info.si_code = code; info.si_addr = (void __user *)addr; force_sig_info(signr, &info, current); - - /* - * Init gets no signals that it doesn't have a handler for. - * That's all very well, but if it has caused a synchronous - * exception and we ignore the resulting signal, it will just - * generate the same exception over and over again and we get - * nowhere. Better to kill it and let the kernel panic. - */ - if (is_global_init(current)) { - __sighandler_t handler; - - spin_lock_irq(¤t->sighand->siglock); - handler = current->sighand->action[signr-1].sa.sa_handler; - spin_unlock_irq(¤t->sighand->siglock); - if (handler == SIG_DFL) { - /* init has generated a synchronous exception - and it doesn't have a handler for the signal */ - printk(KERN_CRIT "init has generated signal %ld " - "but has no handler for it\n", signr); - do_exit(signr); - } - } } asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs) -- cgit v0.10.2 From c7d876321f4cf252bc70c1995bbc077a65b3af2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 9 Feb 2011 11:28:04 +0100 Subject: don't check platform_get_irq's return value against zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_get_irq returns -ENXIO on failure, so !int_irq was probably always true. Better use (int)int_irq <= 0. Note that a return value of zero is still handled as error even though this could mean irq0. This is a followup to 305b3228f9ff4d59f49e6d34a7034d44ee8ce2f0 that changed the return value of platform_get_irq from 0 to -ENXIO on error. Acked-by: Hans-Christian Egtvedt Signed-off-by: Uwe Kleine-König Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index 755ac59..fbc2aea 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -191,7 +191,7 @@ static int __init eic_probe(struct platform_device *pdev) regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); int_irq = platform_get_irq(pdev, 0); - if (!regs || !int_irq) { + if (!regs || (int)int_irq <= 0) { dev_dbg(&pdev->dev, "missing regs and/or irq resource\n"); return -ENXIO; } -- cgit v0.10.2 From 24a1a47562b0fbb97321191dcc3a67b337b20f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bie=C3=9Fmann?= Date: Wed, 13 Apr 2011 10:07:35 +0200 Subject: avr32: add ATAG_BOARDINFO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ATAG_BOARDINFO is intended to hand over the information bd->bi_board_number from u-boot to the kernel. This piece of information can be used to implement some kind of board identification while booting the kernel. Therefore it is placed in .initdata section and can be accessed via the new symbol board_number only while initializing the kernel. Signed-off-by: Andreas Bießmann Signed-off-by: Hans-Christian Egtvedt diff --git a/arch/avr32/include/asm/setup.h b/arch/avr32/include/asm/setup.h index ff5b7cf..160543d 100644 --- a/arch/avr32/include/asm/setup.h +++ b/arch/avr32/include/asm/setup.h @@ -94,6 +94,13 @@ struct tag_ethernet { #define ETH_INVALID_PHY 0xff +/* board information */ +#define ATAG_BOARDINFO 0x54410008 + +struct tag_boardinfo { + u32 board_number; +}; + struct tag { struct tag_header hdr; union { @@ -102,6 +109,7 @@ struct tag { struct tag_cmdline cmdline; struct tag_clock clock; struct tag_ethernet ethernet; + struct tag_boardinfo boardinfo; } u; }; @@ -128,6 +136,7 @@ extern struct tag *bootloader_tags; extern resource_size_t fbmem_start; extern resource_size_t fbmem_size; +extern u32 board_number; void setup_processor(void); diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index 5c70839..bb0974c 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -391,6 +391,21 @@ static int __init parse_tag_clock(struct tag *tag) __tagtable(ATAG_CLOCK, parse_tag_clock); /* + * The board_number correspond to the bd->bi_board_number in U-Boot. This + * parameter is only available during initialisation and can be used in some + * kind of board identification. + */ +u32 __initdata board_number; + +static int __init parse_tag_boardinfo(struct tag *tag) +{ + board_number = tag->u.boardinfo.board_number; + + return 0; +} +__tagtable(ATAG_BOARDINFO, parse_tag_boardinfo); + +/* * Scan the tag table for this tag, and call its parse function. The * tag table is built by the linker from all the __tagtable * declarations. -- cgit v0.10.2 From a626ca6a656450e9f4df91d0dda238fff23285f4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 13 Apr 2011 08:07:28 -0700 Subject: vm: fix vm_pgoff wrap in stack expansion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 982134ba6261 ("mm: avoid wrapping vm_pgoff in mremap()") fixed the case of a expanding mapping causing vm_pgoff wrapping when you used mremap. But there was another case where we expand mappings hiding in plain sight: the automatic stack expansion. This fixes that case too. This one also found by Robert Święcki, using his nasty system call fuzzer tool. Good job. Reported-and-tested-by: Robert Święcki Cc: stable@kernel.org Signed-off-by: Linus Torvalds diff --git a/mm/mmap.c b/mm/mmap.c index 2ec8eb5..8c05e5b 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1814,11 +1814,14 @@ static int expand_downwards(struct vm_area_struct *vma, size = vma->vm_end - address; grow = (vma->vm_start - address) >> PAGE_SHIFT; - error = acct_stack_growth(vma, size, grow); - if (!error) { - vma->vm_start = address; - vma->vm_pgoff -= grow; - perf_event_mmap(vma); + error = -ENOMEM; + if (grow <= vma->vm_pgoff) { + error = acct_stack_growth(vma, size, grow); + if (!error) { + vma->vm_start = address; + vma->vm_pgoff -= grow; + perf_event_mmap(vma); + } } } vma_unlock_anon_vma(vma); -- cgit v0.10.2 From 6631e635c65dc33cb798cc2f51d0ddd69ada6319 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 13 Apr 2011 08:08:20 -0700 Subject: block: don't flush plugged IO on forced preemtion scheduling We really only want to unplug the pending IO when the process actually goes to sleep. So move the test for flushing the plug up to the place where we actually deactivate the task - where we have properly checked for preemption and for the process really sleeping. Acked-by: Jens Axboe Acked-by: Peter Zijlstra Signed-off-by: Linus Torvalds diff --git a/kernel/sched.c b/kernel/sched.c index 4801363..a187c3f 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4111,20 +4111,20 @@ need_resched: try_to_wake_up_local(to_wakeup); } deactivate_task(rq, prev, DEQUEUE_SLEEP); + + /* + * If we are going to sleep and we have plugged IO queued, make + * sure to submit it to avoid deadlocks. + */ + if (blk_needs_flush_plug(prev)) { + raw_spin_unlock(&rq->lock); + blk_flush_plug(prev); + raw_spin_lock(&rq->lock); + } } switch_count = &prev->nvcsw; } - /* - * If we are going to sleep and we have plugged IO queued, make - * sure to submit it to avoid deadlocks. - */ - if (prev->state != TASK_RUNNING && blk_needs_flush_plug(prev)) { - raw_spin_unlock(&rq->lock); - blk_flush_plug(prev); - raw_spin_lock(&rq->lock); - } - pre_schedule(rq, prev); if (unlikely(!rq->nr_running)) -- cgit v0.10.2 From 21a8d026e0721f90ae03084e96a215632c80fc13 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 13 Apr 2011 11:52:16 -0400 Subject: x86 platform drivers: Build fix for intel_pmic_gpio Fix an incorrect function name so the driver builds. Signed-off-by: Matthew Garrett diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 7bbb538..464bb3f 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -209,7 +209,7 @@ static struct irq_chip pmic_irqchip = { .irq_mask = pmic_irq_mask, .irq_unmask = pmic_irq_unmask, .irq_set_type = pmic_irq_type, - .irq_bus_lock = pmic_irq_buslock, + .irq_bus_lock = pmic_bus_lock, .irq_bus_sync_unlock = pmic_bus_sync_unlock, }; -- cgit v0.10.2