diff options
75 files changed, 971 insertions, 1705 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 274b32d12532..492e81df2968 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -387,26 +387,6 @@ Who: Tejun Heo <tj@kernel.org> | |||
387 | 387 | ||
388 | ---------------------------- | 388 | ---------------------------- |
389 | 389 | ||
390 | What: Support for lcd_switch and display_get in asus-laptop driver | ||
391 | When: March 2010 | ||
392 | Why: These two features use non-standard interfaces. There are the | ||
393 | only features that really need multiple path to guess what's | ||
394 | the right method name on a specific laptop. | ||
395 | |||
396 | Removing them will allow to remove a lot of code an significantly | ||
397 | clean the drivers. | ||
398 | |||
399 | This will affect the backlight code which won't be able to know | ||
400 | if the backlight is on or off. The platform display file will also be | ||
401 | write only (like the one in eeepc-laptop). | ||
402 | |||
403 | This should'nt affect a lot of user because they usually know | ||
404 | when their display is on or off. | ||
405 | |||
406 | Who: Corentin Chary <corentin.chary@gmail.com> | ||
407 | |||
408 | ---------------------------- | ||
409 | |||
410 | What: sysfs-class-rfkill state file | 390 | What: sysfs-class-rfkill state file |
411 | When: Feb 2014 | 391 | When: Feb 2014 |
412 | Files: net/rfkill/core.c | 392 | Files: net/rfkill/core.c |
@@ -1,7 +1,7 @@ | |||
1 | VERSION = 2 | 1 | VERSION = 2 |
2 | PATCHLEVEL = 6 | 2 | PATCHLEVEL = 6 |
3 | SUBLEVEL = 39 | 3 | SUBLEVEL = 39 |
4 | EXTRAVERSION = -rc2 | 4 | EXTRAVERSION = -rc3 |
5 | NAME = Flesh-Eating Bats with Fangs | 5 | NAME = Flesh-Eating Bats with Fangs |
6 | 6 | ||
7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 49dbd78ec3cb..e3c6a06cf725 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, | |||
238 | static __init void xen_init_cpuid_mask(void) | 238 | static __init void xen_init_cpuid_mask(void) |
239 | { | 239 | { |
240 | unsigned int ax, bx, cx, dx; | 240 | unsigned int ax, bx, cx, dx; |
241 | unsigned int xsave_mask; | ||
241 | 242 | ||
242 | cpuid_leaf1_edx_mask = | 243 | cpuid_leaf1_edx_mask = |
243 | ~((1 << X86_FEATURE_MCE) | /* disable MCE */ | 244 | ~((1 << X86_FEATURE_MCE) | /* disable MCE */ |
@@ -249,24 +250,16 @@ static __init void xen_init_cpuid_mask(void) | |||
249 | cpuid_leaf1_edx_mask &= | 250 | cpuid_leaf1_edx_mask &= |
250 | ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ | 251 | ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ |
251 | (1 << X86_FEATURE_ACPI)); /* disable ACPI */ | 252 | (1 << X86_FEATURE_ACPI)); /* disable ACPI */ |
252 | |||
253 | ax = 1; | 253 | ax = 1; |
254 | cx = 0; | ||
255 | xen_cpuid(&ax, &bx, &cx, &dx); | 254 | xen_cpuid(&ax, &bx, &cx, &dx); |
256 | 255 | ||
257 | /* cpuid claims we support xsave; try enabling it to see what happens */ | 256 | xsave_mask = |
258 | if (cx & (1 << (X86_FEATURE_XSAVE % 32))) { | 257 | (1 << (X86_FEATURE_XSAVE % 32)) | |
259 | unsigned long cr4; | 258 | (1 << (X86_FEATURE_OSXSAVE % 32)); |
260 | |||
261 | set_in_cr4(X86_CR4_OSXSAVE); | ||
262 | |||
263 | cr4 = read_cr4(); | ||
264 | 259 | ||
265 | if ((cr4 & X86_CR4_OSXSAVE) == 0) | 260 | /* Xen will set CR4.OSXSAVE if supported and not disabled by force */ |
266 | cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32)); | 261 | if ((cx & xsave_mask) != xsave_mask) |
267 | 262 | cpuid_leaf1_ecx_mask &= ~xsave_mask; /* disable XSAVE & OSXSAVE */ | |
268 | clear_in_cr4(X86_CR4_OSXSAVE); | ||
269 | } | ||
270 | } | 263 | } |
271 | 264 | ||
272 | static void xen_set_debugreg(int reg, unsigned long val) | 265 | static void xen_set_debugreg(int reg, unsigned long val) |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index c82df6c9c0f0..a991b57f91fe 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) | |||
565 | if (io_page && | 565 | if (io_page && |
566 | (xen_initial_domain() || addr >= ISA_END_ADDRESS)) { | 566 | (xen_initial_domain() || addr >= ISA_END_ADDRESS)) { |
567 | other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT; | 567 | other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT; |
568 | WARN(addr != other_addr, | 568 | WARN_ONCE(addr != other_addr, |
569 | "0x%lx is using VM_IO, but it is 0x%lx!\n", | 569 | "0x%lx is using VM_IO, but it is 0x%lx!\n", |
570 | (unsigned long)addr, (unsigned long)other_addr); | 570 | (unsigned long)addr, (unsigned long)other_addr); |
571 | } else { | 571 | } else { |
572 | pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP; | 572 | pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP; |
573 | other_addr = (_pte.pte & PTE_PFN_MASK); | 573 | other_addr = (_pte.pte & PTE_PFN_MASK); |
574 | WARN((addr == other_addr) && (!io_page) && (!iomap_set), | 574 | WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set), |
575 | "0x%lx is missing VM_IO (and wasn't fixed)!\n", | 575 | "0x%lx is missing VM_IO (and wasn't fixed)!\n", |
576 | (unsigned long)addr); | 576 | (unsigned long)addr); |
577 | } | 577 | } |
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 92792313d24a..9e0e4fc24c46 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -149,6 +149,7 @@ static void platform_device_release(struct device *dev) | |||
149 | 149 | ||
150 | of_device_node_put(&pa->pdev.dev); | 150 | of_device_node_put(&pa->pdev.dev); |
151 | kfree(pa->pdev.dev.platform_data); | 151 | kfree(pa->pdev.dev.platform_data); |
152 | kfree(pa->pdev.mfd_cell); | ||
152 | kfree(pa->pdev.resource); | 153 | kfree(pa->pdev.resource); |
153 | kfree(pa); | 154 | kfree(pa); |
154 | } | 155 | } |
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 6b396759e7f5..8a781540590c 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c | |||
@@ -1448,7 +1448,7 @@ static const struct of_device_id fsldma_of_ids[] = { | |||
1448 | {} | 1448 | {} |
1449 | }; | 1449 | }; |
1450 | 1450 | ||
1451 | static struct of_platform_driver fsldma_of_driver = { | 1451 | static struct platform_driver fsldma_of_driver = { |
1452 | .driver = { | 1452 | .driver = { |
1453 | .name = "fsl-elo-dma", | 1453 | .name = "fsl-elo-dma", |
1454 | .owner = THIS_MODULE, | 1454 | .owner = THIS_MODULE, |
diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c index 7f6f01a4b145..0a775f7987c2 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, | |||
116 | reg_val |= (1 << nr); | 116 | reg_val |= (1 << nr); |
117 | else | 117 | else |
118 | reg_val &= ~(1 << nr); | 118 | reg_val &= ~(1 << nr); |
119 | iowrite32(reg_val, &chip->reg->regs[chip->ch].po); | ||
119 | 120 | ||
120 | mutex_unlock(&chip->lock); | 121 | mutex_unlock(&chip->lock); |
121 | 122 | ||
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 583e92592073..7630ab7b9bec 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c | |||
@@ -558,7 +558,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, | |||
558 | 558 | ||
559 | ret = gpiochip_add(&chip->gpio_chip); | 559 | ret = gpiochip_add(&chip->gpio_chip); |
560 | if (ret) | 560 | if (ret) |
561 | goto out_failed; | 561 | goto out_failed_irq; |
562 | 562 | ||
563 | if (pdata->setup) { | 563 | if (pdata->setup) { |
564 | ret = pdata->setup(client, chip->gpio_chip.base, | 564 | ret = pdata->setup(client, chip->gpio_chip.base, |
@@ -570,8 +570,9 @@ static int __devinit pca953x_probe(struct i2c_client *client, | |||
570 | i2c_set_clientdata(client, chip); | 570 | i2c_set_clientdata(client, chip); |
571 | return 0; | 571 | return 0; |
572 | 572 | ||
573 | out_failed: | 573 | out_failed_irq: |
574 | pca953x_irq_teardown(chip); | 574 | pca953x_irq_teardown(chip); |
575 | out_failed: | ||
575 | kfree(chip->dyn_pdata); | 576 | kfree(chip->dyn_pdata); |
576 | kfree(chip); | 577 | kfree(chip); |
577 | return ret; | 578 | return ret; |
diff --git a/drivers/gpio/pch_gpio.c b/drivers/gpio/pch_gpio.c index 2c6af8705103..f970a5f3585e 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, | |||
105 | reg_val |= (1 << nr); | 105 | reg_val |= (1 << nr); |
106 | else | 106 | else |
107 | reg_val &= ~(1 << nr); | 107 | reg_val &= ~(1 << nr); |
108 | iowrite32(reg_val, &chip->reg->po); | ||
108 | 109 | ||
109 | mutex_unlock(&chip->lock); | 110 | mutex_unlock(&chip->lock); |
110 | 111 | ||
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index d01574d98870..f4c8c844b913 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) | |||
55 | } | 55 | } |
56 | EXPORT_SYMBOL(mfd_cell_disable); | 56 | EXPORT_SYMBOL(mfd_cell_disable); |
57 | 57 | ||
58 | static int mfd_platform_add_cell(struct platform_device *pdev, | ||
59 | const struct mfd_cell *cell) | ||
60 | { | ||
61 | if (!cell) | ||
62 | return 0; | ||
63 | |||
64 | pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL); | ||
65 | if (!pdev->mfd_cell) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
58 | static int mfd_add_device(struct device *parent, int id, | 71 | static int mfd_add_device(struct device *parent, int id, |
59 | const struct mfd_cell *cell, | 72 | const struct mfd_cell *cell, |
60 | struct resource *mem_base, | 73 | struct resource *mem_base, |
@@ -75,7 +88,7 @@ static int mfd_add_device(struct device *parent, int id, | |||
75 | 88 | ||
76 | pdev->dev.parent = parent; | 89 | pdev->dev.parent = parent; |
77 | 90 | ||
78 | ret = platform_device_add_data(pdev, cell, sizeof(*cell)); | 91 | ret = mfd_platform_add_cell(pdev, cell); |
79 | if (ret) | 92 | if (ret) |
80 | goto fail_res; | 93 | goto fail_res; |
81 | 94 | ||
@@ -123,7 +136,6 @@ static int mfd_add_device(struct device *parent, int id, | |||
123 | 136 | ||
124 | return 0; | 137 | return 0; |
125 | 138 | ||
126 | /* platform_device_del(pdev); */ | ||
127 | fail_res: | 139 | fail_res: |
128 | kfree(res); | 140 | kfree(res); |
129 | fail_device: | 141 | fail_device: |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2ee442c2a5db..0485e394712a 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -187,7 +187,8 @@ config MSI_LAPTOP | |||
187 | depends on ACPI | 187 | depends on ACPI |
188 | depends on BACKLIGHT_CLASS_DEVICE | 188 | depends on BACKLIGHT_CLASS_DEVICE |
189 | depends on RFKILL | 189 | depends on RFKILL |
190 | depends on SERIO_I8042 | 190 | depends on INPUT && SERIO_I8042 |
191 | select INPUT_SPARSEKMAP | ||
191 | ---help--- | 192 | ---help--- |
192 | This is a driver for laptops built by MSI (MICRO-STAR | 193 | This is a driver for laptops built by MSI (MICRO-STAR |
193 | INTERNATIONAL): | 194 | INTERNATIONAL): |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 5ea6c3477d17..ac4e7f83ce6c 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL"); | |||
89 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" | 89 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" |
90 | 90 | ||
91 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); | 91 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); |
92 | MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); | 92 | MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"); |
93 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); | 93 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); |
94 | 94 | ||
95 | enum acer_wmi_event_ids { | 95 | enum acer_wmi_event_ids { |
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index efc776cb0c66..832a3fd7c1c8 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) | |||
201 | if (!asus->inputdev) | 201 | if (!asus->inputdev) |
202 | return -ENOMEM; | 202 | return -ENOMEM; |
203 | 203 | ||
204 | asus->inputdev->name = asus->driver->input_phys; | 204 | asus->inputdev->name = asus->driver->input_name; |
205 | asus->inputdev->phys = asus->driver->input_name; | 205 | asus->inputdev->phys = asus->driver->input_phys; |
206 | asus->inputdev->id.bustype = BUS_HOST; | 206 | asus->inputdev->id.bustype = BUS_HOST; |
207 | asus->inputdev->dev.parent = &asus->platform_device->dev; | 207 | asus->inputdev->dev.parent = &asus->platform_device->dev; |
208 | 208 | ||
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0ddc434fb93b..649dcadd8ea3 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[] = { | |||
67 | { KE_KEY, 0x82, { KEY_CAMERA } }, | 67 | { KE_KEY, 0x82, { KEY_CAMERA } }, |
68 | { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, | 68 | { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, |
69 | { KE_KEY, 0x88, { KEY_WLAN } }, | 69 | { KE_KEY, 0x88, { KEY_WLAN } }, |
70 | { KE_KEY, 0xbd, { KEY_CAMERA } }, | ||
70 | { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, | 71 | { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, |
71 | { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ | 72 | { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ |
72 | { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ | 73 | { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ |
74 | { KE_KEY, 0xe8, { KEY_SCREENLOCK } }, | ||
73 | { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, | 75 | { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, |
74 | { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, | 76 | { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, |
75 | { KE_KEY, 0xec, { KEY_CAMERA_UP } }, | 77 | { KE_KEY, 0xec, { KEY_CAMERA_UP } }, |
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index d653104b59cb..7bbb5388e564 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c | |||
@@ -74,6 +74,19 @@ struct pmic_gpio { | |||
74 | u32 trigger_type; | 74 | u32 trigger_type; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static void pmic_program_irqtype(int gpio, int type) | ||
78 | { | ||
79 | if (type & IRQ_TYPE_EDGE_RISING) | ||
80 | intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); | ||
81 | else | ||
82 | intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); | ||
83 | |||
84 | if (type & IRQ_TYPE_EDGE_FALLING) | ||
85 | intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); | ||
86 | else | ||
87 | intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); | ||
88 | }; | ||
89 | |||
77 | static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | 90 | static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) |
78 | { | 91 | { |
79 | if (offset > 8) { | 92 | if (offset > 8) { |
@@ -166,16 +179,38 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | |||
166 | return pg->irq_base + offset; | 179 | return pg->irq_base + offset; |
167 | } | 180 | } |
168 | 181 | ||
182 | static void pmic_bus_lock(struct irq_data *data) | ||
183 | { | ||
184 | struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); | ||
185 | |||
186 | mutex_lock(&pg->buslock); | ||
187 | } | ||
188 | |||
189 | static void pmic_bus_sync_unlock(struct irq_data *data) | ||
190 | { | ||
191 | struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); | ||
192 | |||
193 | if (pg->update_type) { | ||
194 | unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE; | ||
195 | |||
196 | pmic_program_irqtype(gpio, pg->trigger_type); | ||
197 | pg->update_type = 0; | ||
198 | } | ||
199 | mutex_unlock(&pg->buslock); | ||
200 | } | ||
201 | |||
169 | /* the gpiointr register is read-clear, so just do nothing. */ | 202 | /* the gpiointr register is read-clear, so just do nothing. */ |
170 | static void pmic_irq_unmask(struct irq_data *data) { } | 203 | static void pmic_irq_unmask(struct irq_data *data) { } |
171 | 204 | ||
172 | static void pmic_irq_mask(struct irq_data *data) { } | 205 | static void pmic_irq_mask(struct irq_data *data) { } |
173 | 206 | ||
174 | static struct irq_chip pmic_irqchip = { | 207 | static struct irq_chip pmic_irqchip = { |
175 | .name = "PMIC-GPIO", | 208 | .name = "PMIC-GPIO", |
176 | .irq_mask = pmic_irq_mask, | 209 | .irq_mask = pmic_irq_mask, |
177 | .irq_unmask = pmic_irq_unmask, | 210 | .irq_unmask = pmic_irq_unmask, |
178 | .irq_set_type = pmic_irq_type, | 211 | .irq_set_type = pmic_irq_type, |
212 | .irq_bus_lock = pmic_irq_buslock, | ||
213 | .irq_bus_sync_unlock = pmic_bus_sync_unlock, | ||
179 | }; | 214 | }; |
180 | 215 | ||
181 | static irqreturn_t pmic_irq_handler(int irq, void *data) | 216 | static irqreturn_t pmic_irq_handler(int irq, void *data) |
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index de434c6dc2d6..d347116d150e 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[] = { | |||
571 | .callback = dmi_check_cb, | 571 | .callback = dmi_check_cb, |
572 | }, | 572 | }, |
573 | { | 573 | { |
574 | .ident = "R410 Plus", | ||
575 | .matches = { | ||
576 | DMI_MATCH(DMI_SYS_VENDOR, | ||
577 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
578 | DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), | ||
579 | DMI_MATCH(DMI_BOARD_NAME, "R460"), | ||
580 | }, | ||
581 | .callback = dmi_check_cb, | ||
582 | }, | ||
583 | { | ||
574 | .ident = "R518", | 584 | .ident = "R518", |
575 | .matches = { | 585 | .matches = { |
576 | DMI_MATCH(DMI_SYS_VENDOR, | 586 | DMI_MATCH(DMI_SYS_VENDOR, |
@@ -591,12 +601,12 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { | |||
591 | .callback = dmi_check_cb, | 601 | .callback = dmi_check_cb, |
592 | }, | 602 | }, |
593 | { | 603 | { |
594 | .ident = "N150/N210/N220", | 604 | .ident = "N150/N210/N220/N230", |
595 | .matches = { | 605 | .matches = { |
596 | DMI_MATCH(DMI_SYS_VENDOR, | 606 | DMI_MATCH(DMI_SYS_VENDOR, |
597 | "SAMSUNG ELECTRONICS CO., LTD."), | 607 | "SAMSUNG ELECTRONICS CO., LTD."), |
598 | DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), | 608 | DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), |
599 | DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), | 609 | DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), |
600 | }, | 610 | }, |
601 | .callback = dmi_check_cb, | 611 | .callback = dmi_check_cb, |
602 | }, | 612 | }, |
@@ -771,6 +781,7 @@ static int __init samsung_init(void) | |||
771 | 781 | ||
772 | /* create a backlight device to talk to this one */ | 782 | /* create a backlight device to talk to this one */ |
773 | memset(&props, 0, sizeof(struct backlight_properties)); | 783 | memset(&props, 0, sizeof(struct backlight_properties)); |
784 | props.type = BACKLIGHT_PLATFORM; | ||
774 | props.max_brightness = sabi_config->max_brightness; | 785 | props.max_brightness = sabi_config->max_brightness; |
775 | backlight_device = backlight_device_register("samsung", &sdev->dev, | 786 | backlight_device = backlight_device_register("samsung", &sdev->dev, |
776 | NULL, &backlight_ops, | 787 | NULL, &backlight_ops, |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index e642f5f29504..8f709aec4da0 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, | |||
138 | "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " | 138 | "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " |
139 | "(default: 0)"); | 139 | "(default: 0)"); |
140 | 140 | ||
141 | static void sony_nc_kbd_backlight_resume(void); | ||
142 | |||
141 | enum sony_nc_rfkill { | 143 | enum sony_nc_rfkill { |
142 | SONY_WIFI, | 144 | SONY_WIFI, |
143 | SONY_BLUETOOTH, | 145 | SONY_BLUETOOTH, |
@@ -771,11 +773,6 @@ static int sony_nc_handles_setup(struct platform_device *pd) | |||
771 | if (!handles) | 773 | if (!handles) |
772 | return -ENOMEM; | 774 | return -ENOMEM; |
773 | 775 | ||
774 | sysfs_attr_init(&handles->devattr.attr); | ||
775 | handles->devattr.attr.name = "handles"; | ||
776 | handles->devattr.attr.mode = S_IRUGO; | ||
777 | handles->devattr.show = sony_nc_handles_show; | ||
778 | |||
779 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { | 776 | for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { |
780 | if (!acpi_callsetfunc(sony_nc_acpi_handle, | 777 | if (!acpi_callsetfunc(sony_nc_acpi_handle, |
781 | "SN00", i + 0x20, &result)) { | 778 | "SN00", i + 0x20, &result)) { |
@@ -785,11 +782,18 @@ static int sony_nc_handles_setup(struct platform_device *pd) | |||
785 | } | 782 | } |
786 | } | 783 | } |
787 | 784 | ||
788 | /* allow reading capabilities via sysfs */ | 785 | if (debug) { |
789 | if (device_create_file(&pd->dev, &handles->devattr)) { | 786 | sysfs_attr_init(&handles->devattr.attr); |
790 | kfree(handles); | 787 | handles->devattr.attr.name = "handles"; |
791 | handles = NULL; | 788 | handles->devattr.attr.mode = S_IRUGO; |
792 | return -1; | 789 | handles->devattr.show = sony_nc_handles_show; |
790 | |||
791 | /* allow reading capabilities via sysfs */ | ||
792 | if (device_create_file(&pd->dev, &handles->devattr)) { | ||
793 | kfree(handles); | ||
794 | handles = NULL; | ||
795 | return -1; | ||
796 | } | ||
793 | } | 797 | } |
794 | 798 | ||
795 | return 0; | 799 | return 0; |
@@ -798,7 +802,8 @@ static int sony_nc_handles_setup(struct platform_device *pd) | |||
798 | static int sony_nc_handles_cleanup(struct platform_device *pd) | 802 | static int sony_nc_handles_cleanup(struct platform_device *pd) |
799 | { | 803 | { |
800 | if (handles) { | 804 | if (handles) { |
801 | device_remove_file(&pd->dev, &handles->devattr); | 805 | if (debug) |
806 | device_remove_file(&pd->dev, &handles->devattr); | ||
802 | kfree(handles); | 807 | kfree(handles); |
803 | handles = NULL; | 808 | handles = NULL; |
804 | } | 809 | } |
@@ -808,6 +813,11 @@ static int sony_nc_handles_cleanup(struct platform_device *pd) | |||
808 | static int sony_find_snc_handle(int handle) | 813 | static int sony_find_snc_handle(int handle) |
809 | { | 814 | { |
810 | int i; | 815 | int i; |
816 | |||
817 | /* not initialized yet, return early */ | ||
818 | if (!handles) | ||
819 | return -1; | ||
820 | |||
811 | for (i = 0; i < 0x10; i++) { | 821 | for (i = 0; i < 0x10; i++) { |
812 | if (handles->cap[i] == handle) { | 822 | if (handles->cap[i] == handle) { |
813 | dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", | 823 | dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", |
@@ -1168,6 +1178,9 @@ static int sony_nc_resume(struct acpi_device *device) | |||
1168 | /* re-read rfkill state */ | 1178 | /* re-read rfkill state */ |
1169 | sony_nc_rfkill_update(); | 1179 | sony_nc_rfkill_update(); |
1170 | 1180 | ||
1181 | /* restore kbd backlight states */ | ||
1182 | sony_nc_kbd_backlight_resume(); | ||
1183 | |||
1171 | return 0; | 1184 | return 0; |
1172 | } | 1185 | } |
1173 | 1186 | ||
@@ -1355,6 +1368,7 @@ out_no_enum: | |||
1355 | #define KBDBL_HANDLER 0x137 | 1368 | #define KBDBL_HANDLER 0x137 |
1356 | #define KBDBL_PRESENT 0xB00 | 1369 | #define KBDBL_PRESENT 0xB00 |
1357 | #define SET_MODE 0xC00 | 1370 | #define SET_MODE 0xC00 |
1371 | #define SET_STATE 0xD00 | ||
1358 | #define SET_TIMEOUT 0xE00 | 1372 | #define SET_TIMEOUT 0xE00 |
1359 | 1373 | ||
1360 | struct kbd_backlight { | 1374 | struct kbd_backlight { |
@@ -1377,6 +1391,10 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) | |||
1377 | (value << 0x10) | SET_MODE, &result)) | 1391 | (value << 0x10) | SET_MODE, &result)) |
1378 | return -EIO; | 1392 | return -EIO; |
1379 | 1393 | ||
1394 | /* Try to turn the light on/off immediately */ | ||
1395 | sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, | ||
1396 | &result); | ||
1397 | |||
1380 | kbdbl_handle->mode = value; | 1398 | kbdbl_handle->mode = value; |
1381 | 1399 | ||
1382 | return 0; | 1400 | return 0; |
@@ -1458,7 +1476,7 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd) | |||
1458 | { | 1476 | { |
1459 | int result; | 1477 | int result; |
1460 | 1478 | ||
1461 | if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) | 1479 | if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) |
1462 | return 0; | 1480 | return 0; |
1463 | if (!(result & 0x02)) | 1481 | if (!(result & 0x02)) |
1464 | return 0; | 1482 | return 0; |
@@ -1501,13 +1519,36 @@ outkzalloc: | |||
1501 | static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | 1519 | static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) |
1502 | { | 1520 | { |
1503 | if (kbdbl_handle) { | 1521 | if (kbdbl_handle) { |
1522 | int result; | ||
1523 | |||
1504 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | 1524 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); |
1505 | device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); | 1525 | device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); |
1526 | |||
1527 | /* restore the default hw behaviour */ | ||
1528 | sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); | ||
1529 | sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); | ||
1530 | |||
1506 | kfree(kbdbl_handle); | 1531 | kfree(kbdbl_handle); |
1507 | } | 1532 | } |
1508 | return 0; | 1533 | return 0; |
1509 | } | 1534 | } |
1510 | 1535 | ||
1536 | static void sony_nc_kbd_backlight_resume(void) | ||
1537 | { | ||
1538 | int ignore = 0; | ||
1539 | |||
1540 | if (!kbdbl_handle) | ||
1541 | return; | ||
1542 | |||
1543 | if (kbdbl_handle->mode == 0) | ||
1544 | sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); | ||
1545 | |||
1546 | if (kbdbl_handle->timeout != 0) | ||
1547 | sony_call_snc_handle(KBDBL_HANDLER, | ||
1548 | (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT, | ||
1549 | &ignore); | ||
1550 | } | ||
1551 | |||
1511 | static void sony_nc_backlight_setup(void) | 1552 | static void sony_nc_backlight_setup(void) |
1512 | { | 1553 | { |
1513 | acpi_handle unused; | 1554 | acpi_handle unused; |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a08561f5349e..efb3b6b9bcdb 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, | |||
8618 | tpacpi_is_fw_digit(s[1]) && | 8618 | tpacpi_is_fw_digit(s[1]) && |
8619 | s[2] == t && s[3] == 'T' && | 8619 | s[2] == t && s[3] == 'T' && |
8620 | tpacpi_is_fw_digit(s[4]) && | 8620 | tpacpi_is_fw_digit(s[4]) && |
8621 | tpacpi_is_fw_digit(s[5]) && | 8621 | tpacpi_is_fw_digit(s[5]); |
8622 | s[6] == 'W' && s[7] == 'W'; | ||
8623 | } | 8622 | } |
8624 | 8623 | ||
8625 | /* returns 0 - probe ok, or < 0 - probe error. | 8624 | /* returns 0 - probe ok, or < 0 - probe error. |
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 5825370bad25..08de58e7f59f 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c | |||
@@ -1555,7 +1555,7 @@ static int stop_queue(struct pl022 *pl022) | |||
1555 | * A wait_queue on the pl022->busy could be used, but then the common | 1555 | * A wait_queue on the pl022->busy could be used, but then the common |
1556 | * execution path (pump_messages) would be required to call wake_up or | 1556 | * execution path (pump_messages) would be required to call wake_up or |
1557 | * friends on every SPI message. Do this instead */ | 1557 | * friends on every SPI message. Do this instead */ |
1558 | while (!list_empty(&pl022->queue) && pl022->busy && limit--) { | 1558 | while ((!list_empty(&pl022->queue) || pl022->busy) && limit--) { |
1559 | spin_unlock_irqrestore(&pl022->queue_lock, flags); | 1559 | spin_unlock_irqrestore(&pl022->queue_lock, flags); |
1560 | msleep(10); | 1560 | msleep(10); |
1561 | spin_lock_irqsave(&pl022->queue_lock, flags); | 1561 | spin_lock_irqsave(&pl022->queue_lock, flags); |
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index b1a4b9f503ae..871e337c917f 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) | |||
821 | 821 | ||
822 | spin_lock_irqsave(&dws->lock, flags); | 822 | spin_lock_irqsave(&dws->lock, flags); |
823 | dws->run = QUEUE_STOPPED; | 823 | dws->run = QUEUE_STOPPED; |
824 | while (!list_empty(&dws->queue) && dws->busy && limit--) { | 824 | while ((!list_empty(&dws->queue) || dws->busy) && limit--) { |
825 | spin_unlock_irqrestore(&dws->lock, flags); | 825 | spin_unlock_irqrestore(&dws->lock, flags); |
826 | msleep(10); | 826 | msleep(10); |
827 | spin_lock_irqsave(&dws->lock, flags); | 827 | spin_lock_irqsave(&dws->lock, flags); |
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 9c74aad6be93..dc25bee8d33f 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) | |||
1493 | * execution path (pump_messages) would be required to call wake_up or | 1493 | * execution path (pump_messages) would be required to call wake_up or |
1494 | * friends on every SPI message. Do this instead */ | 1494 | * friends on every SPI message. Do this instead */ |
1495 | drv_data->run = QUEUE_STOPPED; | 1495 | drv_data->run = QUEUE_STOPPED; |
1496 | while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { | 1496 | while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { |
1497 | spin_unlock_irqrestore(&drv_data->lock, flags); | 1497 | spin_unlock_irqrestore(&drv_data->lock, flags); |
1498 | msleep(10); | 1498 | msleep(10); |
1499 | spin_lock_irqsave(&drv_data->lock, flags); | 1499 | spin_lock_irqsave(&drv_data->lock, flags); |
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index bdb7289a1d22..f706dba165cf 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) | |||
1284 | * friends on every SPI message. Do this instead | 1284 | * friends on every SPI message. Do this instead |
1285 | */ | 1285 | */ |
1286 | drv_data->running = false; | 1286 | drv_data->running = false; |
1287 | while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { | 1287 | while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { |
1288 | spin_unlock_irqrestore(&drv_data->lock, flags); | 1288 | spin_unlock_irqrestore(&drv_data->lock, flags); |
1289 | msleep(10); | 1289 | msleep(10); |
1290 | spin_lock_irqsave(&drv_data->lock, flags); | 1290 | spin_lock_irqsave(&drv_data->lock, flags); |
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index dca4a0bb6ca9..e3786f161bc3 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
@@ -131,8 +131,6 @@ source "drivers/staging/wlags49_h2/Kconfig" | |||
131 | 131 | ||
132 | source "drivers/staging/wlags49_h25/Kconfig" | 132 | source "drivers/staging/wlags49_h25/Kconfig" |
133 | 133 | ||
134 | source "drivers/staging/samsung-laptop/Kconfig" | ||
135 | |||
136 | source "drivers/staging/sm7xx/Kconfig" | 134 | source "drivers/staging/sm7xx/Kconfig" |
137 | 135 | ||
138 | source "drivers/staging/dt3155v4l/Kconfig" | 136 | source "drivers/staging/dt3155v4l/Kconfig" |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index eb93012b6f59..f0d5c5315612 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
@@ -48,7 +48,6 @@ obj-$(CONFIG_XVMALLOC) += zram/ | |||
48 | obj-$(CONFIG_ZCACHE) += zcache/ | 48 | obj-$(CONFIG_ZCACHE) += zcache/ |
49 | obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ | 49 | obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ |
50 | obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ | 50 | obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ |
51 | obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/ | ||
52 | obj-$(CONFIG_FB_SM7XX) += sm7xx/ | 51 | obj-$(CONFIG_FB_SM7XX) += sm7xx/ |
53 | obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ | 52 | obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ |
54 | obj-$(CONFIG_CRYSTALHD) += crystalhd/ | 53 | obj-$(CONFIG_CRYSTALHD) += crystalhd/ |
diff --git a/drivers/staging/samsung-laptop/Kconfig b/drivers/staging/samsung-laptop/Kconfig deleted file mode 100644 index f27c60864c26..000000000000 --- a/drivers/staging/samsung-laptop/Kconfig +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | config SAMSUNG_LAPTOP | ||
2 | tristate "Samsung Laptop driver" | ||
3 | default n | ||
4 | depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 | ||
5 | help | ||
6 | This module implements a driver for the N128 Samsung Laptop | ||
7 | providing control over the Wireless LED and the LCD backlight | ||
8 | |||
9 | To compile this driver as a module, choose | ||
10 | 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 3c6f42045211..000000000000 --- a/drivers/staging/samsung-laptop/Makefile +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | 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 f7a6d589916e..000000000000 --- a/drivers/staging/samsung-laptop/TODO +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | TODO: | ||
2 | - review from other developers | ||
3 | - figure out ACPI video issues | ||
4 | |||
5 | Please send patches to Greg Kroah-Hartman <gregkh@suse.de> | ||
diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c deleted file mode 100644 index 25294462b8b6..000000000000 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ /dev/null | |||
@@ -1,843 +0,0 @@ | |||
1 | /* | ||
2 | * Samsung Laptop driver | ||
3 | * | ||
4 | * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) | ||
5 | * Copyright (C) 2009,2011 Novell Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/backlight.h> | ||
20 | #include <linux/fb.h> | ||
21 | #include <linux/dmi.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/rfkill.h> | ||
24 | |||
25 | /* | ||
26 | * This driver is needed because a number of Samsung laptops do not hook | ||
27 | * their control settings through ACPI. So we have to poke around in the | ||
28 | * BIOS to do things like brightness values, and "special" key controls. | ||
29 | */ | ||
30 | |||
31 | /* | ||
32 | * We have 0 - 8 as valid brightness levels. The specs say that level 0 should | ||
33 | * be reserved by the BIOS (which really doesn't make much sense), we tell | ||
34 | * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 | ||
35 | */ | ||
36 | #define MAX_BRIGHT 0x07 | ||
37 | |||
38 | |||
39 | #define SABI_IFACE_MAIN 0x00 | ||
40 | #define SABI_IFACE_SUB 0x02 | ||
41 | #define SABI_IFACE_COMPLETE 0x04 | ||
42 | #define SABI_IFACE_DATA 0x05 | ||
43 | |||
44 | /* Structure to get data back to the calling function */ | ||
45 | struct sabi_retval { | ||
46 | u8 retval[20]; | ||
47 | }; | ||
48 | |||
49 | struct sabi_header_offsets { | ||
50 | u8 port; | ||
51 | u8 re_mem; | ||
52 | u8 iface_func; | ||
53 | u8 en_mem; | ||
54 | u8 data_offset; | ||
55 | u8 data_segment; | ||
56 | }; | ||
57 | |||
58 | struct sabi_commands { | ||
59 | /* | ||
60 | * Brightness is 0 - 8, as described above. | ||
61 | * Value 0 is for the BIOS to use | ||
62 | */ | ||
63 | u8 get_brightness; | ||
64 | u8 set_brightness; | ||
65 | |||
66 | /* | ||
67 | * first byte: | ||
68 | * 0x00 - wireless is off | ||
69 | * 0x01 - wireless is on | ||
70 | * second byte: | ||
71 | * 0x02 - 3G is off | ||
72 | * 0x03 - 3G is on | ||
73 | * TODO, verify 3G is correct, that doesn't seem right... | ||
74 | */ | ||
75 | u8 get_wireless_button; | ||
76 | u8 set_wireless_button; | ||
77 | |||
78 | /* 0 is off, 1 is on */ | ||
79 | u8 get_backlight; | ||
80 | u8 set_backlight; | ||
81 | |||
82 | /* | ||
83 | * 0x80 or 0x00 - no action | ||
84 | * 0x81 - recovery key pressed | ||
85 | */ | ||
86 | u8 get_recovery_mode; | ||
87 | u8 set_recovery_mode; | ||
88 | |||
89 | /* | ||
90 | * on seclinux: 0 is low, 1 is high, | ||
91 | * on swsmi: 0 is normal, 1 is silent, 2 is turbo | ||
92 | */ | ||
93 | u8 get_performance_level; | ||
94 | u8 set_performance_level; | ||
95 | |||
96 | /* | ||
97 | * Tell the BIOS that Linux is running on this machine. | ||
98 | * 81 is on, 80 is off | ||
99 | */ | ||
100 | u8 set_linux; | ||
101 | }; | ||
102 | |||
103 | struct sabi_performance_level { | ||
104 | const char *name; | ||
105 | u8 value; | ||
106 | }; | ||
107 | |||
108 | struct sabi_config { | ||
109 | const char *test_string; | ||
110 | u16 main_function; | ||
111 | const struct sabi_header_offsets header_offsets; | ||
112 | const struct sabi_commands commands; | ||
113 | const struct sabi_performance_level performance_levels[4]; | ||
114 | u8 min_brightness; | ||
115 | u8 max_brightness; | ||
116 | }; | ||
117 | |||
118 | static const struct sabi_config sabi_configs[] = { | ||
119 | { | ||
120 | .test_string = "SECLINUX", | ||
121 | |||
122 | .main_function = 0x4c49, | ||
123 | |||
124 | .header_offsets = { | ||
125 | .port = 0x00, | ||
126 | .re_mem = 0x02, | ||
127 | .iface_func = 0x03, | ||
128 | .en_mem = 0x04, | ||
129 | .data_offset = 0x05, | ||
130 | .data_segment = 0x07, | ||
131 | }, | ||
132 | |||
133 | .commands = { | ||
134 | .get_brightness = 0x00, | ||
135 | .set_brightness = 0x01, | ||
136 | |||
137 | .get_wireless_button = 0x02, | ||
138 | .set_wireless_button = 0x03, | ||
139 | |||
140 | .get_backlight = 0x04, | ||
141 | .set_backlight = 0x05, | ||
142 | |||
143 | .get_recovery_mode = 0x06, | ||
144 | .set_recovery_mode = 0x07, | ||
145 | |||
146 | .get_performance_level = 0x08, | ||
147 | .set_performance_level = 0x09, | ||
148 | |||
149 | .set_linux = 0x0a, | ||
150 | }, | ||
151 | |||
152 | .performance_levels = { | ||
153 | { | ||
154 | .name = "silent", | ||
155 | .value = 0, | ||
156 | }, | ||
157 | { | ||
158 | .name = "normal", | ||
159 | .value = 1, | ||
160 | }, | ||
161 | { }, | ||
162 | }, | ||
163 | .min_brightness = 1, | ||
164 | .max_brightness = 8, | ||
165 | }, | ||
166 | { | ||
167 | .test_string = "SwSmi@", | ||
168 | |||
169 | .main_function = 0x5843, | ||
170 | |||
171 | .header_offsets = { | ||
172 | .port = 0x00, | ||
173 | .re_mem = 0x04, | ||
174 | .iface_func = 0x02, | ||
175 | .en_mem = 0x03, | ||
176 | .data_offset = 0x05, | ||
177 | .data_segment = 0x07, | ||
178 | }, | ||
179 | |||
180 | .commands = { | ||
181 | .get_brightness = 0x10, | ||
182 | .set_brightness = 0x11, | ||
183 | |||
184 | .get_wireless_button = 0x12, | ||
185 | .set_wireless_button = 0x13, | ||
186 | |||
187 | .get_backlight = 0x2d, | ||
188 | .set_backlight = 0x2e, | ||
189 | |||
190 | .get_recovery_mode = 0xff, | ||
191 | .set_recovery_mode = 0xff, | ||
192 | |||
193 | .get_performance_level = 0x31, | ||
194 | .set_performance_level = 0x32, | ||
195 | |||
196 | .set_linux = 0xff, | ||
197 | }, | ||
198 | |||
199 | .performance_levels = { | ||
200 | { | ||
201 | .name = "normal", | ||
202 | .value = 0, | ||
203 | }, | ||
204 | { | ||
205 | .name = "silent", | ||
206 | .value = 1, | ||
207 | }, | ||
208 | { | ||
209 | .name = "overclock", | ||
210 | .value = 2, | ||
211 | }, | ||
212 | { }, | ||
213 | }, | ||
214 | .min_brightness = 0, | ||
215 | .max_brightness = 8, | ||
216 | }, | ||
217 | { }, | ||
218 | }; | ||
219 | |||
220 | static const struct sabi_config *sabi_config; | ||
221 | |||
222 | static void __iomem *sabi; | ||
223 | static void __iomem *sabi_iface; | ||
224 | static void __iomem *f0000_segment; | ||
225 | static struct backlight_device *backlight_device; | ||
226 | static struct mutex sabi_mutex; | ||
227 | static struct platform_device *sdev; | ||
228 | static struct rfkill *rfk; | ||
229 | |||
230 | static int force; | ||
231 | module_param(force, bool, 0); | ||
232 | MODULE_PARM_DESC(force, | ||
233 | "Disable the DMI check and forces the driver to be loaded"); | ||
234 | |||
235 | static int debug; | ||
236 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
237 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||
238 | |||
239 | static int sabi_get_command(u8 command, struct sabi_retval *sretval) | ||
240 | { | ||
241 | int retval = 0; | ||
242 | u16 port = readw(sabi + sabi_config->header_offsets.port); | ||
243 | u8 complete, iface_data; | ||
244 | |||
245 | mutex_lock(&sabi_mutex); | ||
246 | |||
247 | /* enable memory to be able to write to it */ | ||
248 | outb(readb(sabi + sabi_config->header_offsets.en_mem), port); | ||
249 | |||
250 | /* write out the command */ | ||
251 | writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); | ||
252 | writew(command, sabi_iface + SABI_IFACE_SUB); | ||
253 | writeb(0, sabi_iface + SABI_IFACE_COMPLETE); | ||
254 | outb(readb(sabi + sabi_config->header_offsets.iface_func), port); | ||
255 | |||
256 | /* write protect memory to make it safe */ | ||
257 | outb(readb(sabi + sabi_config->header_offsets.re_mem), port); | ||
258 | |||
259 | /* see if the command actually succeeded */ | ||
260 | complete = readb(sabi_iface + SABI_IFACE_COMPLETE); | ||
261 | iface_data = readb(sabi_iface + SABI_IFACE_DATA); | ||
262 | if (complete != 0xaa || iface_data == 0xff) { | ||
263 | pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", | ||
264 | command, complete, iface_data); | ||
265 | retval = -EINVAL; | ||
266 | goto exit; | ||
267 | } | ||
268 | /* | ||
269 | * Save off the data into a structure so the caller use it. | ||
270 | * Right now we only want the first 4 bytes, | ||
271 | * There are commands that need more, but not for the ones we | ||
272 | * currently care about. | ||
273 | */ | ||
274 | sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); | ||
275 | sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); | ||
276 | sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); | ||
277 | sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); | ||
278 | |||
279 | exit: | ||
280 | mutex_unlock(&sabi_mutex); | ||
281 | return retval; | ||
282 | |||
283 | } | ||
284 | |||
285 | static int sabi_set_command(u8 command, u8 data) | ||
286 | { | ||
287 | int retval = 0; | ||
288 | u16 port = readw(sabi + sabi_config->header_offsets.port); | ||
289 | u8 complete, iface_data; | ||
290 | |||
291 | mutex_lock(&sabi_mutex); | ||
292 | |||
293 | /* enable memory to be able to write to it */ | ||
294 | outb(readb(sabi + sabi_config->header_offsets.en_mem), port); | ||
295 | |||
296 | /* write out the command */ | ||
297 | writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); | ||
298 | writew(command, sabi_iface + SABI_IFACE_SUB); | ||
299 | writeb(0, sabi_iface + SABI_IFACE_COMPLETE); | ||
300 | writeb(data, sabi_iface + SABI_IFACE_DATA); | ||
301 | outb(readb(sabi + sabi_config->header_offsets.iface_func), port); | ||
302 | |||
303 | /* write protect memory to make it safe */ | ||
304 | outb(readb(sabi + sabi_config->header_offsets.re_mem), port); | ||
305 | |||
306 | /* see if the command actually succeeded */ | ||
307 | complete = readb(sabi_iface + SABI_IFACE_COMPLETE); | ||
308 | iface_data = readb(sabi_iface + SABI_IFACE_DATA); | ||
309 | if (complete != 0xaa || iface_data == 0xff) { | ||
310 | pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", | ||
311 | command, complete, iface_data); | ||
312 | retval = -EINVAL; | ||
313 | } | ||
314 | |||
315 | mutex_unlock(&sabi_mutex); | ||
316 | return retval; | ||
317 | } | ||
318 | |||
319 | static void test_backlight(void) | ||
320 | { | ||
321 | struct sabi_retval sretval; | ||
322 | |||
323 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
324 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
325 | |||
326 | sabi_set_command(sabi_config->commands.set_backlight, 0); | ||
327 | printk(KERN_DEBUG "backlight should be off\n"); | ||
328 | |||
329 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
330 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
331 | |||
332 | msleep(1000); | ||
333 | |||
334 | sabi_set_command(sabi_config->commands.set_backlight, 1); | ||
335 | printk(KERN_DEBUG "backlight should be on\n"); | ||
336 | |||
337 | sabi_get_command(sabi_config->commands.get_backlight, &sretval); | ||
338 | printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); | ||
339 | } | ||
340 | |||
341 | static void test_wireless(void) | ||
342 | { | ||
343 | struct sabi_retval sretval; | ||
344 | |||
345 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
346 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
347 | |||
348 | sabi_set_command(sabi_config->commands.set_wireless_button, 0); | ||
349 | printk(KERN_DEBUG "wireless led should be off\n"); | ||
350 | |||
351 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
352 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
353 | |||
354 | msleep(1000); | ||
355 | |||
356 | sabi_set_command(sabi_config->commands.set_wireless_button, 1); | ||
357 | printk(KERN_DEBUG "wireless led should be on\n"); | ||
358 | |||
359 | sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); | ||
360 | printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); | ||
361 | } | ||
362 | |||
363 | static u8 read_brightness(void) | ||
364 | { | ||
365 | struct sabi_retval sretval; | ||
366 | int user_brightness = 0; | ||
367 | int retval; | ||
368 | |||
369 | retval = sabi_get_command(sabi_config->commands.get_brightness, | ||
370 | &sretval); | ||
371 | if (!retval) { | ||
372 | user_brightness = sretval.retval[0]; | ||
373 | if (user_brightness != 0) | ||
374 | user_brightness -= sabi_config->min_brightness; | ||
375 | } | ||
376 | return user_brightness; | ||
377 | } | ||
378 | |||
379 | static void set_brightness(u8 user_brightness) | ||
380 | { | ||
381 | u8 user_level = user_brightness - sabi_config->min_brightness; | ||
382 | |||
383 | sabi_set_command(sabi_config->commands.set_brightness, user_level); | ||
384 | } | ||
385 | |||
386 | static int get_brightness(struct backlight_device *bd) | ||
387 | { | ||
388 | return (int)read_brightness(); | ||
389 | } | ||
390 | |||
391 | static int update_status(struct backlight_device *bd) | ||
392 | { | ||
393 | set_brightness(bd->props.brightness); | ||
394 | |||
395 | if (bd->props.power == FB_BLANK_UNBLANK) | ||
396 | sabi_set_command(sabi_config->commands.set_backlight, 1); | ||
397 | else | ||
398 | sabi_set_command(sabi_config->commands.set_backlight, 0); | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static const struct backlight_ops backlight_ops = { | ||
403 | .get_brightness = get_brightness, | ||
404 | .update_status = update_status, | ||
405 | }; | ||
406 | |||
407 | static int rfkill_set(void *data, bool blocked) | ||
408 | { | ||
409 | /* Do something with blocked...*/ | ||
410 | /* | ||
411 | * blocked == false is on | ||
412 | * blocked == true is off | ||
413 | */ | ||
414 | if (blocked) | ||
415 | sabi_set_command(sabi_config->commands.set_wireless_button, 0); | ||
416 | else | ||
417 | sabi_set_command(sabi_config->commands.set_wireless_button, 1); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static struct rfkill_ops rfkill_ops = { | ||
423 | .set_block = rfkill_set, | ||
424 | }; | ||
425 | |||
426 | static int init_wireless(struct platform_device *sdev) | ||
427 | { | ||
428 | int retval; | ||
429 | |||
430 | rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, | ||
431 | &rfkill_ops, NULL); | ||
432 | if (!rfk) | ||
433 | return -ENOMEM; | ||
434 | |||
435 | retval = rfkill_register(rfk); | ||
436 | if (retval) { | ||
437 | rfkill_destroy(rfk); | ||
438 | return -ENODEV; | ||
439 | } | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static void destroy_wireless(void) | ||
445 | { | ||
446 | rfkill_unregister(rfk); | ||
447 | rfkill_destroy(rfk); | ||
448 | } | ||
449 | |||
450 | static ssize_t get_performance_level(struct device *dev, | ||
451 | struct device_attribute *attr, char *buf) | ||
452 | { | ||
453 | struct sabi_retval sretval; | ||
454 | int retval; | ||
455 | int i; | ||
456 | |||
457 | /* Read the state */ | ||
458 | retval = sabi_get_command(sabi_config->commands.get_performance_level, | ||
459 | &sretval); | ||
460 | if (retval) | ||
461 | return retval; | ||
462 | |||
463 | /* The logic is backwards, yeah, lots of fun... */ | ||
464 | for (i = 0; sabi_config->performance_levels[i].name; ++i) { | ||
465 | if (sretval.retval[0] == sabi_config->performance_levels[i].value) | ||
466 | return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); | ||
467 | } | ||
468 | return sprintf(buf, "%s\n", "unknown"); | ||
469 | } | ||
470 | |||
471 | static ssize_t set_performance_level(struct device *dev, | ||
472 | struct device_attribute *attr, const char *buf, | ||
473 | size_t count) | ||
474 | { | ||
475 | if (count >= 1) { | ||
476 | int i; | ||
477 | for (i = 0; sabi_config->performance_levels[i].name; ++i) { | ||
478 | const struct sabi_performance_level *level = | ||
479 | &sabi_config->performance_levels[i]; | ||
480 | if (!strncasecmp(level->name, buf, strlen(level->name))) { | ||
481 | sabi_set_command(sabi_config->commands.set_performance_level, | ||
482 | level->value); | ||
483 | break; | ||
484 | } | ||
485 | } | ||
486 | if (!sabi_config->performance_levels[i].name) | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | return count; | ||
490 | } | ||
491 | static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, | ||
492 | get_performance_level, set_performance_level); | ||
493 | |||
494 | |||
495 | static int __init dmi_check_cb(const struct dmi_system_id *id) | ||
496 | { | ||
497 | pr_info("found laptop model '%s'\n", | ||
498 | id->ident); | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static struct dmi_system_id __initdata samsung_dmi_table[] = { | ||
503 | { | ||
504 | .ident = "N128", | ||
505 | .matches = { | ||
506 | DMI_MATCH(DMI_SYS_VENDOR, | ||
507 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
508 | DMI_MATCH(DMI_PRODUCT_NAME, "N128"), | ||
509 | DMI_MATCH(DMI_BOARD_NAME, "N128"), | ||
510 | }, | ||
511 | .callback = dmi_check_cb, | ||
512 | }, | ||
513 | { | ||
514 | .ident = "N130", | ||
515 | .matches = { | ||
516 | DMI_MATCH(DMI_SYS_VENDOR, | ||
517 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
518 | DMI_MATCH(DMI_PRODUCT_NAME, "N130"), | ||
519 | DMI_MATCH(DMI_BOARD_NAME, "N130"), | ||
520 | }, | ||
521 | .callback = dmi_check_cb, | ||
522 | }, | ||
523 | { | ||
524 | .ident = "X125", | ||
525 | .matches = { | ||
526 | DMI_MATCH(DMI_SYS_VENDOR, | ||
527 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
528 | DMI_MATCH(DMI_PRODUCT_NAME, "X125"), | ||
529 | DMI_MATCH(DMI_BOARD_NAME, "X125"), | ||
530 | }, | ||
531 | .callback = dmi_check_cb, | ||
532 | }, | ||
533 | { | ||
534 | .ident = "X120/X170", | ||
535 | .matches = { | ||
536 | DMI_MATCH(DMI_SYS_VENDOR, | ||
537 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
538 | DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), | ||
539 | DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), | ||
540 | }, | ||
541 | .callback = dmi_check_cb, | ||
542 | }, | ||
543 | { | ||
544 | .ident = "NC10", | ||
545 | .matches = { | ||
546 | DMI_MATCH(DMI_SYS_VENDOR, | ||
547 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
548 | DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), | ||
549 | DMI_MATCH(DMI_BOARD_NAME, "NC10"), | ||
550 | }, | ||
551 | .callback = dmi_check_cb, | ||
552 | }, | ||
553 | { | ||
554 | .ident = "NP-Q45", | ||
555 | .matches = { | ||
556 | DMI_MATCH(DMI_SYS_VENDOR, | ||
557 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
558 | DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), | ||
559 | DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), | ||
560 | }, | ||
561 | .callback = dmi_check_cb, | ||
562 | }, | ||
563 | { | ||
564 | .ident = "X360", | ||
565 | .matches = { | ||
566 | DMI_MATCH(DMI_SYS_VENDOR, | ||
567 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
568 | DMI_MATCH(DMI_PRODUCT_NAME, "X360"), | ||
569 | DMI_MATCH(DMI_BOARD_NAME, "X360"), | ||
570 | }, | ||
571 | .callback = dmi_check_cb, | ||
572 | }, | ||
573 | { | ||
574 | .ident = "R410 Plus", | ||
575 | .matches = { | ||
576 | DMI_MATCH(DMI_SYS_VENDOR, | ||
577 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
578 | DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), | ||
579 | DMI_MATCH(DMI_BOARD_NAME, "R460"), | ||
580 | }, | ||
581 | .callback = dmi_check_cb, | ||
582 | }, | ||
583 | { | ||
584 | .ident = "R518", | ||
585 | .matches = { | ||
586 | DMI_MATCH(DMI_SYS_VENDOR, | ||
587 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
588 | DMI_MATCH(DMI_PRODUCT_NAME, "R518"), | ||
589 | DMI_MATCH(DMI_BOARD_NAME, "R518"), | ||
590 | }, | ||
591 | .callback = dmi_check_cb, | ||
592 | }, | ||
593 | { | ||
594 | .ident = "R519/R719", | ||
595 | .matches = { | ||
596 | DMI_MATCH(DMI_SYS_VENDOR, | ||
597 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
598 | DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), | ||
599 | DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), | ||
600 | }, | ||
601 | .callback = dmi_check_cb, | ||
602 | }, | ||
603 | { | ||
604 | .ident = "N150/N210/N220/N230", | ||
605 | .matches = { | ||
606 | DMI_MATCH(DMI_SYS_VENDOR, | ||
607 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
608 | DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), | ||
609 | DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), | ||
610 | }, | ||
611 | .callback = dmi_check_cb, | ||
612 | }, | ||
613 | { | ||
614 | .ident = "N150P/N210P/N220P", | ||
615 | .matches = { | ||
616 | DMI_MATCH(DMI_SYS_VENDOR, | ||
617 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
618 | DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), | ||
619 | DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), | ||
620 | }, | ||
621 | .callback = dmi_check_cb, | ||
622 | }, | ||
623 | { | ||
624 | .ident = "R530/R730", | ||
625 | .matches = { | ||
626 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
627 | DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), | ||
628 | DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), | ||
629 | }, | ||
630 | .callback = dmi_check_cb, | ||
631 | }, | ||
632 | { | ||
633 | .ident = "NF110/NF210/NF310", | ||
634 | .matches = { | ||
635 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
636 | DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), | ||
637 | DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), | ||
638 | }, | ||
639 | .callback = dmi_check_cb, | ||
640 | }, | ||
641 | { | ||
642 | .ident = "N145P/N250P/N260P", | ||
643 | .matches = { | ||
644 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
645 | DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), | ||
646 | DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), | ||
647 | }, | ||
648 | .callback = dmi_check_cb, | ||
649 | }, | ||
650 | { | ||
651 | .ident = "R70/R71", | ||
652 | .matches = { | ||
653 | DMI_MATCH(DMI_SYS_VENDOR, | ||
654 | "SAMSUNG ELECTRONICS CO., LTD."), | ||
655 | DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), | ||
656 | DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), | ||
657 | }, | ||
658 | .callback = dmi_check_cb, | ||
659 | }, | ||
660 | { | ||
661 | .ident = "P460", | ||
662 | .matches = { | ||
663 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), | ||
664 | DMI_MATCH(DMI_PRODUCT_NAME, "P460"), | ||
665 | DMI_MATCH(DMI_BOARD_NAME, "P460"), | ||
666 | }, | ||
667 | .callback = dmi_check_cb, | ||
668 | }, | ||
669 | { }, | ||
670 | }; | ||
671 | MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); | ||
672 | |||
673 | static int find_signature(void __iomem *memcheck, const char *testStr) | ||
674 | { | ||
675 | int i = 0; | ||
676 | int loca; | ||
677 | |||
678 | for (loca = 0; loca < 0xffff; loca++) { | ||
679 | char temp = readb(memcheck + loca); | ||
680 | |||
681 | if (temp == testStr[i]) { | ||
682 | if (i == strlen(testStr)-1) | ||
683 | break; | ||
684 | ++i; | ||
685 | } else { | ||
686 | i = 0; | ||
687 | } | ||
688 | } | ||
689 | return loca; | ||
690 | } | ||
691 | |||
692 | static int __init samsung_init(void) | ||
693 | { | ||
694 | struct backlight_properties props; | ||
695 | struct sabi_retval sretval; | ||
696 | unsigned int ifaceP; | ||
697 | int i; | ||
698 | int loca; | ||
699 | int retval; | ||
700 | |||
701 | mutex_init(&sabi_mutex); | ||
702 | |||
703 | if (!force && !dmi_check_system(samsung_dmi_table)) | ||
704 | return -ENODEV; | ||
705 | |||
706 | f0000_segment = ioremap_nocache(0xf0000, 0xffff); | ||
707 | if (!f0000_segment) { | ||
708 | pr_err("Can't map the segment at 0xf0000\n"); | ||
709 | return -EINVAL; | ||
710 | } | ||
711 | |||
712 | /* Try to find one of the signatures in memory to find the header */ | ||
713 | for (i = 0; sabi_configs[i].test_string != 0; ++i) { | ||
714 | sabi_config = &sabi_configs[i]; | ||
715 | loca = find_signature(f0000_segment, sabi_config->test_string); | ||
716 | if (loca != 0xffff) | ||
717 | break; | ||
718 | } | ||
719 | |||
720 | if (loca == 0xffff) { | ||
721 | pr_err("This computer does not support SABI\n"); | ||
722 | goto error_no_signature; | ||
723 | } | ||
724 | |||
725 | /* point to the SMI port Number */ | ||
726 | loca += 1; | ||
727 | sabi = (f0000_segment + loca); | ||
728 | |||
729 | if (debug) { | ||
730 | printk(KERN_DEBUG "This computer supports SABI==%x\n", | ||
731 | loca + 0xf0000 - 6); | ||
732 | printk(KERN_DEBUG "SABI header:\n"); | ||
733 | printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", | ||
734 | readw(sabi + sabi_config->header_offsets.port)); | ||
735 | printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", | ||
736 | readb(sabi + sabi_config->header_offsets.iface_func)); | ||
737 | printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", | ||
738 | readb(sabi + sabi_config->header_offsets.en_mem)); | ||
739 | printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", | ||
740 | readb(sabi + sabi_config->header_offsets.re_mem)); | ||
741 | printk(KERN_DEBUG " SABI data offset = 0x%04x\n", | ||
742 | readw(sabi + sabi_config->header_offsets.data_offset)); | ||
743 | printk(KERN_DEBUG " SABI data segment = 0x%04x\n", | ||
744 | readw(sabi + sabi_config->header_offsets.data_segment)); | ||
745 | } | ||
746 | |||
747 | /* Get a pointer to the SABI Interface */ | ||
748 | ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; | ||
749 | ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; | ||
750 | sabi_iface = ioremap_nocache(ifaceP, 16); | ||
751 | if (!sabi_iface) { | ||
752 | pr_err("Can't remap %x\n", ifaceP); | ||
753 | goto exit; | ||
754 | } | ||
755 | if (debug) { | ||
756 | printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); | ||
757 | printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); | ||
758 | |||
759 | test_backlight(); | ||
760 | test_wireless(); | ||
761 | |||
762 | retval = sabi_get_command(sabi_config->commands.get_brightness, | ||
763 | &sretval); | ||
764 | printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); | ||
765 | } | ||
766 | |||
767 | /* Turn on "Linux" mode in the BIOS */ | ||
768 | if (sabi_config->commands.set_linux != 0xff) { | ||
769 | retval = sabi_set_command(sabi_config->commands.set_linux, | ||
770 | 0x81); | ||
771 | if (retval) { | ||
772 | pr_warn("Linux mode was not set!\n"); | ||
773 | goto error_no_platform; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | /* knock up a platform device to hang stuff off of */ | ||
778 | sdev = platform_device_register_simple("samsung", -1, NULL, 0); | ||
779 | if (IS_ERR(sdev)) | ||
780 | goto error_no_platform; | ||
781 | |||
782 | /* create a backlight device to talk to this one */ | ||
783 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
784 | props.type = BACKLIGHT_PLATFORM; | ||
785 | props.max_brightness = sabi_config->max_brightness; | ||
786 | backlight_device = backlight_device_register("samsung", &sdev->dev, | ||
787 | NULL, &backlight_ops, | ||
788 | &props); | ||
789 | if (IS_ERR(backlight_device)) | ||
790 | goto error_no_backlight; | ||
791 | |||
792 | backlight_device->props.brightness = read_brightness(); | ||
793 | backlight_device->props.power = FB_BLANK_UNBLANK; | ||
794 | backlight_update_status(backlight_device); | ||
795 | |||
796 | retval = init_wireless(sdev); | ||
797 | if (retval) | ||
798 | goto error_no_rfk; | ||
799 | |||
800 | retval = device_create_file(&sdev->dev, &dev_attr_performance_level); | ||
801 | if (retval) | ||
802 | goto error_file_create; | ||
803 | |||
804 | exit: | ||
805 | return 0; | ||
806 | |||
807 | error_file_create: | ||
808 | destroy_wireless(); | ||
809 | |||
810 | error_no_rfk: | ||
811 | backlight_device_unregister(backlight_device); | ||
812 | |||
813 | error_no_backlight: | ||
814 | platform_device_unregister(sdev); | ||
815 | |||
816 | error_no_platform: | ||
817 | iounmap(sabi_iface); | ||
818 | |||
819 | error_no_signature: | ||
820 | iounmap(f0000_segment); | ||
821 | return -EINVAL; | ||
822 | } | ||
823 | |||
824 | static void __exit samsung_exit(void) | ||
825 | { | ||
826 | /* Turn off "Linux" mode in the BIOS */ | ||
827 | if (sabi_config->commands.set_linux != 0xff) | ||
828 | sabi_set_command(sabi_config->commands.set_linux, 0x80); | ||
829 | |||
830 | device_remove_file(&sdev->dev, &dev_attr_performance_level); | ||
831 | backlight_device_unregister(backlight_device); | ||
832 | destroy_wireless(); | ||
833 | iounmap(sabi_iface); | ||
834 | iounmap(f0000_segment); | ||
835 | platform_device_unregister(sdev); | ||
836 | } | ||
837 | |||
838 | module_init(samsung_init); | ||
839 | module_exit(samsung_exit); | ||
840 | |||
841 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); | ||
842 | MODULE_DESCRIPTION("Samsung Backlight driver"); | ||
843 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 42d6c930cc87..33167b43ac7e 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -912,8 +912,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn, | |||
912 | unsigned long irqflags, | 912 | unsigned long irqflags, |
913 | const char *devname, void *dev_id) | 913 | const char *devname, void *dev_id) |
914 | { | 914 | { |
915 | unsigned int irq; | 915 | int irq, retval; |
916 | int retval; | ||
917 | 916 | ||
918 | irq = bind_evtchn_to_irq(evtchn); | 917 | irq = bind_evtchn_to_irq(evtchn); |
919 | if (irq < 0) | 918 | if (irq < 0) |
@@ -955,8 +954,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu, | |||
955 | irq_handler_t handler, | 954 | irq_handler_t handler, |
956 | unsigned long irqflags, const char *devname, void *dev_id) | 955 | unsigned long irqflags, const char *devname, void *dev_id) |
957 | { | 956 | { |
958 | unsigned int irq; | 957 | int irq, retval; |
959 | int retval; | ||
960 | 958 | ||
961 | irq = bind_virq_to_irq(virq, cpu); | 959 | irq = bind_virq_to_irq(virq, cpu); |
962 | if (irq < 0) | 960 | if (irq < 0) |
diff --git a/fs/cifs/README b/fs/cifs/README index fe1683590828..74ab165fc646 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -685,22 +685,6 @@ LinuxExtensionsEnabled If set to one then the client will attempt to | |||
685 | support and want to map the uid and gid fields | 685 | support and want to map the uid and gid fields |
686 | to values supplied at mount (rather than the | 686 | to values supplied at mount (rather than the |
687 | actual values, then set this to zero. (default 1) | 687 | actual values, then set this to zero. (default 1) |
688 | Experimental When set to 1 used to enable certain experimental | ||
689 | features (currently enables multipage writes | ||
690 | when signing is enabled, the multipage write | ||
691 | performance enhancement was disabled when | ||
692 | signing turned on in case buffer was modified | ||
693 | just before it was sent, also this flag will | ||
694 | be used to use the new experimental directory change | ||
695 | notification code). When set to 2 enables | ||
696 | an additional experimental feature, "raw ntlmssp" | ||
697 | session establishment support (which allows | ||
698 | specifying "sec=ntlmssp" on mount). The Linux cifs | ||
699 | module will use ntlmv2 authentication encapsulated | ||
700 | in "raw ntlmssp" (not using SPNEGO) when | ||
701 | "sec=ntlmssp" is specified on mount. | ||
702 | This support also requires building cifs with | ||
703 | the CONFIG_CIFS_EXPERIMENTAL configuration flag. | ||
704 | 688 | ||
705 | These experimental features and tracing can be enabled by changing flags in | 689 | These experimental features and tracing can be enabled by changing flags in |
706 | /proc/fs/cifs (after the cifs module has been installed or built into the | 690 | /proc/fs/cifs (after the cifs module has been installed or built into the |
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index e654dfd092c3..53d57a3fe427 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c | |||
@@ -50,7 +50,7 @@ void cifs_fscache_unregister(void) | |||
50 | */ | 50 | */ |
51 | struct cifs_server_key { | 51 | struct cifs_server_key { |
52 | uint16_t family; /* address family */ | 52 | uint16_t family; /* address family */ |
53 | uint16_t port; /* IP port */ | 53 | __be16 port; /* IP port */ |
54 | union { | 54 | union { |
55 | struct in_addr ipv4_addr; | 55 | struct in_addr ipv4_addr; |
56 | struct in6_addr ipv6_addr; | 56 | struct in6_addr ipv6_addr; |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 65829d32128c..30d01bc90855 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; | |||
423 | static const struct file_operations traceSMB_proc_fops; | 423 | static const struct file_operations traceSMB_proc_fops; |
424 | static const struct file_operations cifs_multiuser_mount_proc_fops; | 424 | static const struct file_operations cifs_multiuser_mount_proc_fops; |
425 | static const struct file_operations cifs_security_flags_proc_fops; | 425 | static const struct file_operations cifs_security_flags_proc_fops; |
426 | static const struct file_operations cifs_experimental_proc_fops; | ||
427 | static const struct file_operations cifs_linux_ext_proc_fops; | 426 | static const struct file_operations cifs_linux_ext_proc_fops; |
428 | 427 | ||
429 | void | 428 | void |
@@ -441,8 +440,6 @@ cifs_proc_init(void) | |||
441 | proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); | 440 | proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); |
442 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); | 441 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); |
443 | proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); | 442 | proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); |
444 | proc_create("Experimental", 0, proc_fs_cifs, | ||
445 | &cifs_experimental_proc_fops); | ||
446 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, | 443 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, |
447 | &cifs_linux_ext_proc_fops); | 444 | &cifs_linux_ext_proc_fops); |
448 | proc_create("MultiuserMount", 0, proc_fs_cifs, | 445 | proc_create("MultiuserMount", 0, proc_fs_cifs, |
@@ -469,7 +466,6 @@ cifs_proc_clean(void) | |||
469 | remove_proc_entry("OplockEnabled", proc_fs_cifs); | 466 | remove_proc_entry("OplockEnabled", proc_fs_cifs); |
470 | remove_proc_entry("SecurityFlags", proc_fs_cifs); | 467 | remove_proc_entry("SecurityFlags", proc_fs_cifs); |
471 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); | 468 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); |
472 | remove_proc_entry("Experimental", proc_fs_cifs); | ||
473 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); | 469 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); |
474 | remove_proc_entry("fs/cifs", NULL); | 470 | remove_proc_entry("fs/cifs", NULL); |
475 | } | 471 | } |
@@ -550,45 +546,6 @@ static const struct file_operations cifs_oplock_proc_fops = { | |||
550 | .write = cifs_oplock_proc_write, | 546 | .write = cifs_oplock_proc_write, |
551 | }; | 547 | }; |
552 | 548 | ||
553 | static int cifs_experimental_proc_show(struct seq_file *m, void *v) | ||
554 | { | ||
555 | seq_printf(m, "%d\n", experimEnabled); | ||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int cifs_experimental_proc_open(struct inode *inode, struct file *file) | ||
560 | { | ||
561 | return single_open(file, cifs_experimental_proc_show, NULL); | ||
562 | } | ||
563 | |||
564 | static ssize_t cifs_experimental_proc_write(struct file *file, | ||
565 | const char __user *buffer, size_t count, loff_t *ppos) | ||
566 | { | ||
567 | char c; | ||
568 | int rc; | ||
569 | |||
570 | rc = get_user(c, buffer); | ||
571 | if (rc) | ||
572 | return rc; | ||
573 | if (c == '0' || c == 'n' || c == 'N') | ||
574 | experimEnabled = 0; | ||
575 | else if (c == '1' || c == 'y' || c == 'Y') | ||
576 | experimEnabled = 1; | ||
577 | else if (c == '2') | ||
578 | experimEnabled = 2; | ||
579 | |||
580 | return count; | ||
581 | } | ||
582 | |||
583 | static const struct file_operations cifs_experimental_proc_fops = { | ||
584 | .owner = THIS_MODULE, | ||
585 | .open = cifs_experimental_proc_open, | ||
586 | .read = seq_read, | ||
587 | .llseek = seq_lseek, | ||
588 | .release = single_release, | ||
589 | .write = cifs_experimental_proc_write, | ||
590 | }; | ||
591 | |||
592 | static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) | 549 | static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) |
593 | { | 550 | { |
594 | seq_printf(m, "%d\n", linuxExtEnabled); | 551 | seq_printf(m, "%d\n", linuxExtEnabled); |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 4dfba8283165..33d221394aca 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -113,7 +113,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
113 | MAX_MECH_STR_LEN + | 113 | MAX_MECH_STR_LEN + |
114 | UID_KEY_LEN + (sizeof(uid_t) * 2) + | 114 | UID_KEY_LEN + (sizeof(uid_t) * 2) + |
115 | CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + | 115 | CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + |
116 | USER_KEY_LEN + strlen(sesInfo->userName) + | 116 | USER_KEY_LEN + strlen(sesInfo->user_name) + |
117 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; | 117 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; |
118 | 118 | ||
119 | spnego_key = ERR_PTR(-ENOMEM); | 119 | spnego_key = ERR_PTR(-ENOMEM); |
@@ -153,7 +153,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
153 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); | 153 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); |
154 | 154 | ||
155 | dp = description + strlen(description); | 155 | dp = description + strlen(description); |
156 | sprintf(dp, ";user=%s", sesInfo->userName); | 156 | sprintf(dp, ";user=%s", sesInfo->user_name); |
157 | 157 | ||
158 | dp = description + strlen(description); | 158 | dp = description + strlen(description); |
159 | sprintf(dp, ";pid=0x%x", current->pid); | 159 | sprintf(dp, ";pid=0x%x", current->pid); |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index fc0fd4fde306..23d43cde4306 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, | |||
90 | case UNI_COLON: | 90 | case UNI_COLON: |
91 | *target = ':'; | 91 | *target = ':'; |
92 | break; | 92 | break; |
93 | case UNI_ASTERIK: | 93 | case UNI_ASTERISK: |
94 | *target = '*'; | 94 | *target = '*'; |
95 | break; | 95 | break; |
96 | case UNI_QUESTION: | 96 | case UNI_QUESTION: |
@@ -264,40 +264,40 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, | |||
264 | * names are little endian 16 bit Unicode on the wire | 264 | * names are little endian 16 bit Unicode on the wire |
265 | */ | 265 | */ |
266 | int | 266 | int |
267 | cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | 267 | cifsConvertToUCS(__le16 *target, const char *source, int srclen, |
268 | const struct nls_table *cp, int mapChars) | 268 | const struct nls_table *cp, int mapChars) |
269 | { | 269 | { |
270 | int i, j, charlen; | 270 | int i, j, charlen; |
271 | int len_remaining = maxlen; | ||
272 | char src_char; | 271 | char src_char; |
273 | __u16 temp; | 272 | __le16 dst_char; |
273 | wchar_t tmp; | ||
274 | 274 | ||
275 | if (!mapChars) | 275 | if (!mapChars) |
276 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | 276 | return cifs_strtoUCS(target, source, PATH_MAX, cp); |
277 | 277 | ||
278 | for (i = 0, j = 0; i < maxlen; j++) { | 278 | for (i = 0, j = 0; i < srclen; j++) { |
279 | src_char = source[i]; | 279 | src_char = source[i]; |
280 | switch (src_char) { | 280 | switch (src_char) { |
281 | case 0: | 281 | case 0: |
282 | put_unaligned_le16(0, &target[j]); | 282 | put_unaligned(0, &target[j]); |
283 | goto ctoUCS_out; | 283 | goto ctoUCS_out; |
284 | case ':': | 284 | case ':': |
285 | temp = UNI_COLON; | 285 | dst_char = cpu_to_le16(UNI_COLON); |
286 | break; | 286 | break; |
287 | case '*': | 287 | case '*': |
288 | temp = UNI_ASTERIK; | 288 | dst_char = cpu_to_le16(UNI_ASTERISK); |
289 | break; | 289 | break; |
290 | case '?': | 290 | case '?': |
291 | temp = UNI_QUESTION; | 291 | dst_char = cpu_to_le16(UNI_QUESTION); |
292 | break; | 292 | break; |
293 | case '<': | 293 | case '<': |
294 | temp = UNI_LESSTHAN; | 294 | dst_char = cpu_to_le16(UNI_LESSTHAN); |
295 | break; | 295 | break; |
296 | case '>': | 296 | case '>': |
297 | temp = UNI_GRTRTHAN; | 297 | dst_char = cpu_to_le16(UNI_GRTRTHAN); |
298 | break; | 298 | break; |
299 | case '|': | 299 | case '|': |
300 | temp = UNI_PIPE; | 300 | dst_char = cpu_to_le16(UNI_PIPE); |
301 | break; | 301 | break; |
302 | /* | 302 | /* |
303 | * FIXME: We can not handle remapping backslash (UNI_SLASH) | 303 | * FIXME: We can not handle remapping backslash (UNI_SLASH) |
@@ -305,17 +305,17 @@ cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | |||
305 | * as they use backslash as separator. | 305 | * as they use backslash as separator. |
306 | */ | 306 | */ |
307 | default: | 307 | default: |
308 | charlen = cp->char2uni(source+i, len_remaining, | 308 | charlen = cp->char2uni(source + i, srclen - i, &tmp); |
309 | &temp); | 309 | dst_char = cpu_to_le16(tmp); |
310 | |||
310 | /* | 311 | /* |
311 | * if no match, use question mark, which at least in | 312 | * if no match, use question mark, which at least in |
312 | * some cases serves as wild card | 313 | * some cases serves as wild card |
313 | */ | 314 | */ |
314 | if (charlen < 1) { | 315 | if (charlen < 1) { |
315 | temp = 0x003f; | 316 | dst_char = cpu_to_le16(0x003f); |
316 | charlen = 1; | 317 | charlen = 1; |
317 | } | 318 | } |
318 | len_remaining -= charlen; | ||
319 | /* | 319 | /* |
320 | * character may take more than one byte in the source | 320 | * character may take more than one byte in the source |
321 | * string, but will take exactly two bytes in the | 321 | * string, but will take exactly two bytes in the |
@@ -324,9 +324,8 @@ cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | |||
324 | i += charlen; | 324 | i += charlen; |
325 | continue; | 325 | continue; |
326 | } | 326 | } |
327 | put_unaligned_le16(temp, &target[j]); | 327 | put_unaligned(dst_char, &target[j]); |
328 | i++; /* move to next char in source string */ | 328 | i++; /* move to next char in source string */ |
329 | len_remaining--; | ||
330 | } | 329 | } |
331 | 330 | ||
332 | ctoUCS_out: | 331 | ctoUCS_out: |
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 7fe6b52df507..644dd882a560 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
@@ -44,7 +44,7 @@ | |||
44 | * reserved symbols (along with \ and /), otherwise illegal to store | 44 | * reserved symbols (along with \ and /), otherwise illegal to store |
45 | * in filenames in NTFS | 45 | * in filenames in NTFS |
46 | */ | 46 | */ |
47 | #define UNI_ASTERIK (__u16) ('*' + 0xF000) | 47 | #define UNI_ASTERISK (__u16) ('*' + 0xF000) |
48 | #define UNI_QUESTION (__u16) ('?' + 0xF000) | 48 | #define UNI_QUESTION (__u16) ('?' + 0xF000) |
49 | #define UNI_COLON (__u16) (':' + 0xF000) | 49 | #define UNI_COLON (__u16) (':' + 0xF000) |
50 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | 50 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index a51585f9852b..d1a016be73ba 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -30,12 +30,13 @@ | |||
30 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
31 | #include <linux/random.h> | 31 | #include <linux/random.h> |
32 | 32 | ||
33 | /* Calculate and return the CIFS signature based on the mac key and SMB PDU */ | 33 | /* |
34 | /* the 16 byte signature must be allocated by the caller */ | 34 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. |
35 | /* Note we only use the 1st eight bytes */ | 35 | * The 16 byte signature must be allocated by the caller. Note we only use the |
36 | /* Note that the smb header signature field on input contains the | 36 | * 1st eight bytes and that the smb header signature field on input contains |
37 | sequence number before this function is called */ | 37 | * the sequence number before this function is called. Also, this function |
38 | 38 | * should be called with the server->srv_mutex held. | |
39 | */ | ||
39 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | 40 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
40 | struct TCP_Server_Info *server, char *signature) | 41 | struct TCP_Server_Info *server, char *signature) |
41 | { | 42 | { |
@@ -209,8 +210,10 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
209 | cpu_to_le32(expected_sequence_number); | 210 | cpu_to_le32(expected_sequence_number); |
210 | cifs_pdu->Signature.Sequence.Reserved = 0; | 211 | cifs_pdu->Signature.Sequence.Reserved = 0; |
211 | 212 | ||
213 | mutex_lock(&server->srv_mutex); | ||
212 | rc = cifs_calculate_signature(cifs_pdu, server, | 214 | rc = cifs_calculate_signature(cifs_pdu, server, |
213 | what_we_think_sig_should_be); | 215 | what_we_think_sig_should_be); |
216 | mutex_unlock(&server->srv_mutex); | ||
214 | 217 | ||
215 | if (rc) | 218 | if (rc) |
216 | return rc; | 219 | return rc; |
@@ -469,15 +472,15 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash, | |||
469 | return rc; | 472 | return rc; |
470 | } | 473 | } |
471 | 474 | ||
472 | /* convert ses->userName to unicode and uppercase */ | 475 | /* convert ses->user_name to unicode and uppercase */ |
473 | len = strlen(ses->userName); | 476 | len = strlen(ses->user_name); |
474 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 477 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
475 | if (user == NULL) { | 478 | if (user == NULL) { |
476 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | 479 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); |
477 | rc = -ENOMEM; | 480 | rc = -ENOMEM; |
478 | goto calc_exit_2; | 481 | goto calc_exit_2; |
479 | } | 482 | } |
480 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 483 | len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp); |
481 | UniStrupr(user); | 484 | UniStrupr(user); |
482 | 485 | ||
483 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | 486 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f2970136d17d..5c412b33cd7c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -53,7 +53,6 @@ int cifsFYI = 0; | |||
53 | int cifsERROR = 1; | 53 | int cifsERROR = 1; |
54 | int traceSMB = 0; | 54 | int traceSMB = 0; |
55 | unsigned int oplockEnabled = 1; | 55 | unsigned int oplockEnabled = 1; |
56 | unsigned int experimEnabled = 0; | ||
57 | unsigned int linuxExtEnabled = 1; | 56 | unsigned int linuxExtEnabled = 1; |
58 | unsigned int lookupCacheEnabled = 1; | 57 | unsigned int lookupCacheEnabled = 1; |
59 | unsigned int multiuser_mount = 0; | 58 | unsigned int multiuser_mount = 0; |
@@ -127,6 +126,7 @@ cifs_read_super(struct super_block *sb, void *data, | |||
127 | kfree(cifs_sb); | 126 | kfree(cifs_sb); |
128 | return rc; | 127 | return rc; |
129 | } | 128 | } |
129 | cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; | ||
130 | 130 | ||
131 | #ifdef CONFIG_CIFS_DFS_UPCALL | 131 | #ifdef CONFIG_CIFS_DFS_UPCALL |
132 | /* copy mount params to sb for use in submounts */ | 132 | /* copy mount params to sb for use in submounts */ |
@@ -409,8 +409,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
409 | 409 | ||
410 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) | 410 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) |
411 | seq_printf(s, ",multiuser"); | 411 | seq_printf(s, ",multiuser"); |
412 | else if (tcon->ses->userName) | 412 | else if (tcon->ses->user_name) |
413 | seq_printf(s, ",username=%s", tcon->ses->userName); | 413 | seq_printf(s, ",username=%s", tcon->ses->user_name); |
414 | 414 | ||
415 | if (tcon->ses->domainName) | 415 | if (tcon->ses->domainName) |
416 | seq_printf(s, ",domain=%s", tcon->ses->domainName); | 416 | seq_printf(s, ",domain=%s", tcon->ses->domainName); |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 17afb0fbcaed..a5d1106fcbde 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -37,10 +37,9 @@ | |||
37 | 37 | ||
38 | #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) | 38 | #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) |
39 | #define MAX_SERVER_SIZE 15 | 39 | #define MAX_SERVER_SIZE 15 |
40 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ | 40 | #define MAX_SHARE_SIZE 80 |
41 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | 41 | #define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ |
42 | termination then *2 for unicode versions */ | 42 | #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ |
43 | #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ | ||
44 | 43 | ||
45 | #define CIFS_MIN_RCV_POOL 4 | 44 | #define CIFS_MIN_RCV_POOL 4 |
46 | 45 | ||
@@ -92,7 +91,8 @@ enum statusEnum { | |||
92 | CifsNew = 0, | 91 | CifsNew = 0, |
93 | CifsGood, | 92 | CifsGood, |
94 | CifsExiting, | 93 | CifsExiting, |
95 | CifsNeedReconnect | 94 | CifsNeedReconnect, |
95 | CifsNeedNegotiate | ||
96 | }; | 96 | }; |
97 | 97 | ||
98 | enum securityEnum { | 98 | enum securityEnum { |
@@ -274,7 +274,7 @@ struct cifsSesInfo { | |||
274 | int capabilities; | 274 | int capabilities; |
275 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 275 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for |
276 | TCP names - will ipv6 and sctp addresses fit? */ | 276 | TCP names - will ipv6 and sctp addresses fit? */ |
277 | char userName[MAX_USERNAME_SIZE + 1]; | 277 | char *user_name; |
278 | char *domainName; | 278 | char *domainName; |
279 | char *password; | 279 | char *password; |
280 | struct session_key auth_key; | 280 | struct session_key auth_key; |
@@ -817,7 +817,6 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions | |||
817 | have the uid/password or Kerberos credential | 817 | have the uid/password or Kerberos credential |
818 | or equivalent for current user */ | 818 | or equivalent for current user */ |
819 | GLOBAL_EXTERN unsigned int oplockEnabled; | 819 | GLOBAL_EXTERN unsigned int oplockEnabled; |
820 | GLOBAL_EXTERN unsigned int experimEnabled; | ||
821 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; | 820 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; |
822 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent | 821 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent |
823 | with more secure ntlmssp2 challenge/resp */ | 822 | with more secure ntlmssp2 challenge/resp */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2644a5d6cc67..df959bae6728 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -142,9 +142,9 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | |||
142 | */ | 142 | */ |
143 | while (server->tcpStatus == CifsNeedReconnect) { | 143 | while (server->tcpStatus == CifsNeedReconnect) { |
144 | wait_event_interruptible_timeout(server->response_q, | 144 | wait_event_interruptible_timeout(server->response_q, |
145 | (server->tcpStatus == CifsGood), 10 * HZ); | 145 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); |
146 | 146 | ||
147 | /* is TCP session is reestablished now ?*/ | 147 | /* are we still trying to reconnect? */ |
148 | if (server->tcpStatus != CifsNeedReconnect) | 148 | if (server->tcpStatus != CifsNeedReconnect) |
149 | break; | 149 | break; |
150 | 150 | ||
@@ -729,7 +729,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) | |||
729 | return rc; | 729 | return rc; |
730 | 730 | ||
731 | /* set up echo request */ | 731 | /* set up echo request */ |
732 | smb->hdr.Tid = cpu_to_le16(0xffff); | 732 | smb->hdr.Tid = 0xffff; |
733 | smb->hdr.WordCount = 1; | 733 | smb->hdr.WordCount = 1; |
734 | put_unaligned_le16(1, &smb->EchoCount); | 734 | put_unaligned_le16(1, &smb->EchoCount); |
735 | put_bcc_le(1, &smb->hdr); | 735 | put_bcc_le(1, &smb->hdr); |
@@ -1884,10 +1884,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1884 | __constant_cpu_to_le16(CIFS_WRLCK)) | 1884 | __constant_cpu_to_le16(CIFS_WRLCK)) |
1885 | pLockData->fl_type = F_WRLCK; | 1885 | pLockData->fl_type = F_WRLCK; |
1886 | 1886 | ||
1887 | pLockData->fl_start = parm_data->start; | 1887 | pLockData->fl_start = le64_to_cpu(parm_data->start); |
1888 | pLockData->fl_end = parm_data->start + | 1888 | pLockData->fl_end = pLockData->fl_start + |
1889 | parm_data->length - 1; | 1889 | le64_to_cpu(parm_data->length) - 1; |
1890 | pLockData->fl_pid = parm_data->pid; | 1890 | pLockData->fl_pid = le32_to_cpu(parm_data->pid); |
1891 | } | 1891 | } |
1892 | } | 1892 | } |
1893 | 1893 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 6e2b2addfc78..db9d55b507d0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -199,8 +199,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
199 | } | 199 | } |
200 | spin_unlock(&GlobalMid_Lock); | 200 | spin_unlock(&GlobalMid_Lock); |
201 | 201 | ||
202 | while ((server->tcpStatus != CifsExiting) && | 202 | while (server->tcpStatus == CifsNeedReconnect) { |
203 | (server->tcpStatus != CifsGood)) { | ||
204 | try_to_freeze(); | 203 | try_to_freeze(); |
205 | 204 | ||
206 | /* we should try only the port we connected to before */ | 205 | /* we should try only the port we connected to before */ |
@@ -212,7 +211,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
212 | atomic_inc(&tcpSesReconnectCount); | 211 | atomic_inc(&tcpSesReconnectCount); |
213 | spin_lock(&GlobalMid_Lock); | 212 | spin_lock(&GlobalMid_Lock); |
214 | if (server->tcpStatus != CifsExiting) | 213 | if (server->tcpStatus != CifsExiting) |
215 | server->tcpStatus = CifsGood; | 214 | server->tcpStatus = CifsNeedNegotiate; |
216 | spin_unlock(&GlobalMid_Lock); | 215 | spin_unlock(&GlobalMid_Lock); |
217 | } | 216 | } |
218 | } | 217 | } |
@@ -248,24 +247,24 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | |||
248 | total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); | 247 | total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); |
249 | data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); | 248 | data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); |
250 | 249 | ||
251 | remaining = total_data_size - data_in_this_rsp; | 250 | if (total_data_size == data_in_this_rsp) |
252 | |||
253 | if (remaining == 0) | ||
254 | return 0; | 251 | return 0; |
255 | else if (remaining < 0) { | 252 | else if (total_data_size < data_in_this_rsp) { |
256 | cFYI(1, "total data %d smaller than data in frame %d", | 253 | cFYI(1, "total data %d smaller than data in frame %d", |
257 | total_data_size, data_in_this_rsp); | 254 | total_data_size, data_in_this_rsp); |
258 | return -EINVAL; | 255 | return -EINVAL; |
259 | } else { | ||
260 | cFYI(1, "missing %d bytes from transact2, check next response", | ||
261 | remaining); | ||
262 | if (total_data_size > maxBufSize) { | ||
263 | cERROR(1, "TotalDataSize %d is over maximum buffer %d", | ||
264 | total_data_size, maxBufSize); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | return remaining; | ||
268 | } | 256 | } |
257 | |||
258 | remaining = total_data_size - data_in_this_rsp; | ||
259 | |||
260 | cFYI(1, "missing %d bytes from transact2, check next response", | ||
261 | remaining); | ||
262 | if (total_data_size > maxBufSize) { | ||
263 | cERROR(1, "TotalDataSize %d is over maximum buffer %d", | ||
264 | total_data_size, maxBufSize); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | return remaining; | ||
269 | } | 268 | } |
270 | 269 | ||
271 | static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) | 270 | static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) |
@@ -421,7 +420,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
421 | pdu_length = 4; /* enough to get RFC1001 header */ | 420 | pdu_length = 4; /* enough to get RFC1001 header */ |
422 | 421 | ||
423 | incomplete_rcv: | 422 | incomplete_rcv: |
424 | if (echo_retries > 0 && | 423 | if (echo_retries > 0 && server->tcpStatus == CifsGood && |
425 | time_after(jiffies, server->lstrp + | 424 | time_after(jiffies, server->lstrp + |
426 | (echo_retries * SMB_ECHO_INTERVAL))) { | 425 | (echo_retries * SMB_ECHO_INTERVAL))) { |
427 | cERROR(1, "Server %s has not responded in %d seconds. " | 426 | cERROR(1, "Server %s has not responded in %d seconds. " |
@@ -881,7 +880,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
881 | /* null user, ie anonymous, authentication */ | 880 | /* null user, ie anonymous, authentication */ |
882 | vol->nullauth = 1; | 881 | vol->nullauth = 1; |
883 | } | 882 | } |
884 | if (strnlen(value, 200) < 200) { | 883 | if (strnlen(value, MAX_USERNAME_SIZE) < |
884 | MAX_USERNAME_SIZE) { | ||
885 | vol->username = value; | 885 | vol->username = value; |
886 | } else { | 886 | } else { |
887 | printk(KERN_WARNING "CIFS: username too long\n"); | 887 | printk(KERN_WARNING "CIFS: username too long\n"); |
@@ -1472,7 +1472,7 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) | |||
1472 | static bool | 1472 | static bool |
1473 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) | 1473 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) |
1474 | { | 1474 | { |
1475 | unsigned short int port, *sport; | 1475 | __be16 port, *sport; |
1476 | 1476 | ||
1477 | switch (addr->sa_family) { | 1477 | switch (addr->sa_family) { |
1478 | case AF_INET: | 1478 | case AF_INET: |
@@ -1765,6 +1765,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1765 | module_put(THIS_MODULE); | 1765 | module_put(THIS_MODULE); |
1766 | goto out_err_crypto_release; | 1766 | goto out_err_crypto_release; |
1767 | } | 1767 | } |
1768 | tcp_ses->tcpStatus = CifsNeedNegotiate; | ||
1768 | 1769 | ||
1769 | /* thread spawned, put it on the list */ | 1770 | /* thread spawned, put it on the list */ |
1770 | spin_lock(&cifs_tcp_ses_lock); | 1771 | spin_lock(&cifs_tcp_ses_lock); |
@@ -1808,7 +1809,9 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
1808 | break; | 1809 | break; |
1809 | default: | 1810 | default: |
1810 | /* anything else takes username/password */ | 1811 | /* anything else takes username/password */ |
1811 | if (strncmp(ses->userName, vol->username, | 1812 | if (ses->user_name == NULL) |
1813 | continue; | ||
1814 | if (strncmp(ses->user_name, vol->username, | ||
1812 | MAX_USERNAME_SIZE)) | 1815 | MAX_USERNAME_SIZE)) |
1813 | continue; | 1816 | continue; |
1814 | if (strlen(vol->username) != 0 && | 1817 | if (strlen(vol->username) != 0 && |
@@ -1851,6 +1854,8 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) | |||
1851 | cifs_put_tcp_session(server); | 1854 | cifs_put_tcp_session(server); |
1852 | } | 1855 | } |
1853 | 1856 | ||
1857 | static bool warned_on_ntlm; /* globals init to false automatically */ | ||
1858 | |||
1854 | static struct cifsSesInfo * | 1859 | static struct cifsSesInfo * |
1855 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | 1860 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) |
1856 | { | 1861 | { |
@@ -1906,9 +1911,11 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1906 | else | 1911 | else |
1907 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); | 1912 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); |
1908 | 1913 | ||
1909 | if (volume_info->username) | 1914 | if (volume_info->username) { |
1910 | strncpy(ses->userName, volume_info->username, | 1915 | ses->user_name = kstrdup(volume_info->username, GFP_KERNEL); |
1911 | MAX_USERNAME_SIZE); | 1916 | if (!ses->user_name) |
1917 | goto get_ses_fail; | ||
1918 | } | ||
1912 | 1919 | ||
1913 | /* volume_info->password freed at unmount */ | 1920 | /* volume_info->password freed at unmount */ |
1914 | if (volume_info->password) { | 1921 | if (volume_info->password) { |
@@ -1923,6 +1930,15 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1923 | } | 1930 | } |
1924 | ses->cred_uid = volume_info->cred_uid; | 1931 | ses->cred_uid = volume_info->cred_uid; |
1925 | ses->linux_uid = volume_info->linux_uid; | 1932 | ses->linux_uid = volume_info->linux_uid; |
1933 | |||
1934 | /* ntlmv2 is much stronger than ntlm security, and has been broadly | ||
1935 | supported for many years, time to update default security mechanism */ | ||
1936 | if ((volume_info->secFlg == 0) && warned_on_ntlm == false) { | ||
1937 | warned_on_ntlm = true; | ||
1938 | cERROR(1, "default security mechanism requested. The default " | ||
1939 | "security mechanism will be upgraded from ntlm to " | ||
1940 | "ntlmv2 in kernel release 2.6.41"); | ||
1941 | } | ||
1926 | ses->overrideSecFlg = volume_info->secFlg; | 1942 | ses->overrideSecFlg = volume_info->secFlg; |
1927 | 1943 | ||
1928 | mutex_lock(&ses->session_mutex); | 1944 | mutex_lock(&ses->session_mutex); |
@@ -2276,7 +2292,7 @@ static int | |||
2276 | generic_ip_connect(struct TCP_Server_Info *server) | 2292 | generic_ip_connect(struct TCP_Server_Info *server) |
2277 | { | 2293 | { |
2278 | int rc = 0; | 2294 | int rc = 0; |
2279 | unsigned short int sport; | 2295 | __be16 sport; |
2280 | int slen, sfamily; | 2296 | int slen, sfamily; |
2281 | struct socket *socket = server->ssocket; | 2297 | struct socket *socket = server->ssocket; |
2282 | struct sockaddr *saddr; | 2298 | struct sockaddr *saddr; |
@@ -2361,7 +2377,7 @@ generic_ip_connect(struct TCP_Server_Info *server) | |||
2361 | static int | 2377 | static int |
2362 | ip_connect(struct TCP_Server_Info *server) | 2378 | ip_connect(struct TCP_Server_Info *server) |
2363 | { | 2379 | { |
2364 | unsigned short int *sport; | 2380 | __be16 *sport; |
2365 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | 2381 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
2366 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | 2382 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
2367 | 2383 | ||
@@ -2826,7 +2842,7 @@ try_mount_again: | |||
2826 | 2842 | ||
2827 | remote_path_check: | 2843 | remote_path_check: |
2828 | /* check if a whole path (including prepath) is not remote */ | 2844 | /* check if a whole path (including prepath) is not remote */ |
2829 | if (!rc && cifs_sb->prepathlen && tcon) { | 2845 | if (!rc && tcon) { |
2830 | /* build_path_to_root works only when we have a valid tcon */ | 2846 | /* build_path_to_root works only when we have a valid tcon */ |
2831 | full_path = cifs_build_path_to_root(cifs_sb, tcon); | 2847 | full_path = cifs_build_path_to_root(cifs_sb, tcon); |
2832 | if (full_path == NULL) { | 2848 | if (full_path == NULL) { |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c27d236738fc..faf59529e847 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -575,8 +575,10 @@ reopen_error_exit: | |||
575 | 575 | ||
576 | int cifs_close(struct inode *inode, struct file *file) | 576 | int cifs_close(struct inode *inode, struct file *file) |
577 | { | 577 | { |
578 | cifsFileInfo_put(file->private_data); | 578 | if (file->private_data != NULL) { |
579 | file->private_data = NULL; | 579 | cifsFileInfo_put(file->private_data); |
580 | file->private_data = NULL; | ||
581 | } | ||
580 | 582 | ||
581 | /* return code from the ->release op is always ignored */ | 583 | /* return code from the ->release op is always ignored */ |
582 | return 0; | 584 | return 0; |
@@ -970,6 +972,9 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
970 | total_written += bytes_written) { | 972 | total_written += bytes_written) { |
971 | rc = -EAGAIN; | 973 | rc = -EAGAIN; |
972 | while (rc == -EAGAIN) { | 974 | while (rc == -EAGAIN) { |
975 | struct kvec iov[2]; | ||
976 | unsigned int len; | ||
977 | |||
973 | if (open_file->invalidHandle) { | 978 | if (open_file->invalidHandle) { |
974 | /* we could deadlock if we called | 979 | /* we could deadlock if we called |
975 | filemap_fdatawait from here so tell | 980 | filemap_fdatawait from here so tell |
@@ -979,31 +984,14 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
979 | if (rc != 0) | 984 | if (rc != 0) |
980 | break; | 985 | break; |
981 | } | 986 | } |
982 | if (experimEnabled || (pTcon->ses->server && | 987 | |
983 | ((pTcon->ses->server->secMode & | 988 | len = min((size_t)cifs_sb->wsize, |
984 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 989 | write_size - total_written); |
985 | == 0))) { | 990 | /* iov[0] is reserved for smb header */ |
986 | struct kvec iov[2]; | 991 | iov[1].iov_base = (char *)write_data + total_written; |
987 | unsigned int len; | 992 | iov[1].iov_len = len; |
988 | 993 | rc = CIFSSMBWrite2(xid, pTcon, open_file->netfid, len, | |
989 | len = min((size_t)cifs_sb->wsize, | 994 | *poffset, &bytes_written, iov, 1, 0); |
990 | write_size - total_written); | ||
991 | /* iov[0] is reserved for smb header */ | ||
992 | iov[1].iov_base = (char *)write_data + | ||
993 | total_written; | ||
994 | iov[1].iov_len = len; | ||
995 | rc = CIFSSMBWrite2(xid, pTcon, | ||
996 | open_file->netfid, len, | ||
997 | *poffset, &bytes_written, | ||
998 | iov, 1, 0); | ||
999 | } else | ||
1000 | rc = CIFSSMBWrite(xid, pTcon, | ||
1001 | open_file->netfid, | ||
1002 | min_t(const int, cifs_sb->wsize, | ||
1003 | write_size - total_written), | ||
1004 | *poffset, &bytes_written, | ||
1005 | write_data + total_written, | ||
1006 | NULL, 0); | ||
1007 | } | 995 | } |
1008 | if (rc || (bytes_written == 0)) { | 996 | if (rc || (bytes_written == 0)) { |
1009 | if (total_written) | 997 | if (total_written) |
@@ -1240,12 +1228,6 @@ static int cifs_writepages(struct address_space *mapping, | |||
1240 | } | 1228 | } |
1241 | 1229 | ||
1242 | tcon = tlink_tcon(open_file->tlink); | 1230 | tcon = tlink_tcon(open_file->tlink); |
1243 | if (!experimEnabled && tcon->ses->server->secMode & | ||
1244 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | ||
1245 | cifsFileInfo_put(open_file); | ||
1246 | kfree(iov); | ||
1247 | return generic_writepages(mapping, wbc); | ||
1248 | } | ||
1249 | cifsFileInfo_put(open_file); | 1231 | cifsFileInfo_put(open_file); |
1250 | 1232 | ||
1251 | xid = GetXid(); | 1233 | xid = GetXid(); |
@@ -1980,6 +1962,24 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1980 | return total_read; | 1962 | return total_read; |
1981 | } | 1963 | } |
1982 | 1964 | ||
1965 | /* | ||
1966 | * If the page is mmap'ed into a process' page tables, then we need to make | ||
1967 | * sure that it doesn't change while being written back. | ||
1968 | */ | ||
1969 | static int | ||
1970 | cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
1971 | { | ||
1972 | struct page *page = vmf->page; | ||
1973 | |||
1974 | lock_page(page); | ||
1975 | return VM_FAULT_LOCKED; | ||
1976 | } | ||
1977 | |||
1978 | static struct vm_operations_struct cifs_file_vm_ops = { | ||
1979 | .fault = filemap_fault, | ||
1980 | .page_mkwrite = cifs_page_mkwrite, | ||
1981 | }; | ||
1982 | |||
1983 | int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) | 1983 | int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) |
1984 | { | 1984 | { |
1985 | int rc, xid; | 1985 | int rc, xid; |
@@ -1991,6 +1991,8 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) | |||
1991 | cifs_invalidate_mapping(inode); | 1991 | cifs_invalidate_mapping(inode); |
1992 | 1992 | ||
1993 | rc = generic_file_mmap(file, vma); | 1993 | rc = generic_file_mmap(file, vma); |
1994 | if (rc == 0) | ||
1995 | vma->vm_ops = &cifs_file_vm_ops; | ||
1994 | FreeXid(xid); | 1996 | FreeXid(xid); |
1995 | return rc; | 1997 | return rc; |
1996 | } | 1998 | } |
@@ -2007,6 +2009,8 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
2007 | return rc; | 2009 | return rc; |
2008 | } | 2010 | } |
2009 | rc = generic_file_mmap(file, vma); | 2011 | rc = generic_file_mmap(file, vma); |
2012 | if (rc == 0) | ||
2013 | vma->vm_ops = &cifs_file_vm_ops; | ||
2010 | FreeXid(xid); | 2014 | FreeXid(xid); |
2011 | return rc; | 2015 | return rc; |
2012 | } | 2016 | } |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index e8804d373404..ce417a9764a3 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -239,7 +239,7 @@ CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon, | |||
239 | if (rc != 0) | 239 | if (rc != 0) |
240 | return rc; | 240 | return rc; |
241 | 241 | ||
242 | if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { | 242 | if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { |
243 | CIFSSMBClose(xid, tcon, netfid); | 243 | CIFSSMBClose(xid, tcon, netfid); |
244 | /* it's not a symlink */ | 244 | /* it's not a symlink */ |
245 | return -EINVAL; | 245 | return -EINVAL; |
@@ -316,7 +316,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, | |||
316 | if (rc != 0) | 316 | if (rc != 0) |
317 | goto out; | 317 | goto out; |
318 | 318 | ||
319 | if (file_info.EndOfFile != CIFS_MF_SYMLINK_FILE_SIZE) { | 319 | if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { |
320 | CIFSSMBClose(xid, pTcon, netfid); | 320 | CIFSSMBClose(xid, pTcon, netfid); |
321 | /* it's not a symlink */ | 321 | /* it's not a symlink */ |
322 | goto out; | 322 | goto out; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 2a930a752a78..0c684ae4c071 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -100,6 +100,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) | |||
100 | memset(buf_to_free->password, 0, strlen(buf_to_free->password)); | 100 | memset(buf_to_free->password, 0, strlen(buf_to_free->password)); |
101 | kfree(buf_to_free->password); | 101 | kfree(buf_to_free->password); |
102 | } | 102 | } |
103 | kfree(buf_to_free->user_name); | ||
103 | kfree(buf_to_free->domainName); | 104 | kfree(buf_to_free->domainName); |
104 | kfree(buf_to_free); | 105 | kfree(buf_to_free); |
105 | } | 106 | } |
@@ -520,7 +521,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
520 | (struct smb_com_transaction_change_notify_rsp *)buf; | 521 | (struct smb_com_transaction_change_notify_rsp *)buf; |
521 | struct file_notify_information *pnotify; | 522 | struct file_notify_information *pnotify; |
522 | __u32 data_offset = 0; | 523 | __u32 data_offset = 0; |
523 | if (pSMBr->ByteCount > sizeof(struct file_notify_information)) { | 524 | if (get_bcc_le(buf) > sizeof(struct file_notify_information)) { |
524 | data_offset = le32_to_cpu(pSMBr->DataOffset); | 525 | data_offset = le32_to_cpu(pSMBr->DataOffset); |
525 | 526 | ||
526 | pnotify = (struct file_notify_information *) | 527 | pnotify = (struct file_notify_information *) |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 16765703131b..f6728eb6f4b9 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, | |||
219 | bcc_ptr++; | 219 | bcc_ptr++; |
220 | } */ | 220 | } */ |
221 | /* copy user */ | 221 | /* copy user */ |
222 | if (ses->userName == NULL) { | 222 | if (ses->user_name == NULL) { |
223 | /* null user mount */ | 223 | /* null user mount */ |
224 | *bcc_ptr = 0; | 224 | *bcc_ptr = 0; |
225 | *(bcc_ptr+1) = 0; | 225 | *(bcc_ptr+1) = 0; |
226 | } else { | 226 | } else { |
227 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, | 227 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->user_name, |
228 | MAX_USERNAME_SIZE, nls_cp); | 228 | MAX_USERNAME_SIZE, nls_cp); |
229 | } | 229 | } |
230 | bcc_ptr += 2 * bytes_ret; | 230 | bcc_ptr += 2 * bytes_ret; |
@@ -244,12 +244,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
244 | /* copy user */ | 244 | /* copy user */ |
245 | /* BB what about null user mounts - check that we do this BB */ | 245 | /* BB what about null user mounts - check that we do this BB */ |
246 | /* copy user */ | 246 | /* copy user */ |
247 | if (ses->userName == NULL) { | 247 | if (ses->user_name != NULL) |
248 | /* BB what about null user mounts - check that we do this BB */ | 248 | strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE); |
249 | } else { | 249 | /* else null user mount */ |
250 | strncpy(bcc_ptr, ses->userName, MAX_USERNAME_SIZE); | 250 | |
251 | } | 251 | bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); |
252 | bcc_ptr += strnlen(ses->userName, MAX_USERNAME_SIZE); | ||
253 | *bcc_ptr = 0; | 252 | *bcc_ptr = 0; |
254 | bcc_ptr++; /* account for null termination */ | 253 | bcc_ptr++; /* account for null termination */ |
255 | 254 | ||
@@ -405,8 +404,8 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
405 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | 404 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then |
406 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | 405 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ |
407 | ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); | 406 | ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); |
408 | tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset); | 407 | tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset); |
409 | tilen = cpu_to_le16(pblob->TargetInfoArray.Length); | 408 | tilen = le16_to_cpu(pblob->TargetInfoArray.Length); |
410 | if (tilen) { | 409 | if (tilen) { |
411 | ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); | 410 | ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); |
412 | if (!ses->auth_key.response) { | 411 | if (!ses->auth_key.response) { |
@@ -523,14 +522,14 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
523 | tmp += len; | 522 | tmp += len; |
524 | } | 523 | } |
525 | 524 | ||
526 | if (ses->userName == NULL) { | 525 | if (ses->user_name == NULL) { |
527 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 526 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
528 | sec_blob->UserName.Length = 0; | 527 | sec_blob->UserName.Length = 0; |
529 | sec_blob->UserName.MaximumLength = 0; | 528 | sec_blob->UserName.MaximumLength = 0; |
530 | tmp += 2; | 529 | tmp += 2; |
531 | } else { | 530 | } else { |
532 | int len; | 531 | int len; |
533 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | 532 | len = cifs_strtoUCS((__le16 *)tmp, ses->user_name, |
534 | MAX_USERNAME_SIZE, nls_cp); | 533 | MAX_USERNAME_SIZE, nls_cp); |
535 | len *= 2; /* unicode is 2 bytes each */ | 534 | len *= 2; /* unicode is 2 bytes each */ |
536 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 535 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index e25e99bf7ee1..d0f53538a57f 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -86,8 +86,8 @@ | |||
86 | 86 | ||
87 | #ifdef CONFIG_QUOTA | 87 | #ifdef CONFIG_QUOTA |
88 | /* Amount of blocks needed for quota update - we know that the structure was | 88 | /* Amount of blocks needed for quota update - we know that the structure was |
89 | * allocated so we need to update only inode+data */ | 89 | * allocated so we need to update only data block */ |
90 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) | 90 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 1 : 0) |
91 | /* Amount of blocks needed for quota insert/delete - we do some block writes | 91 | /* Amount of blocks needed for quota insert/delete - we do some block writes |
92 | * but inode, sb and group updates are done only once */ | 92 | * but inode, sb and group updates are done only once */ |
93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ | 93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 4673bc05274f..e9473cbe80df 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -125,9 +125,11 @@ extern int ext4_flush_completed_IO(struct inode *inode) | |||
125 | * the parent directory's parent as well, and so on recursively, if | 125 | * the parent directory's parent as well, and so on recursively, if |
126 | * they are also freshly created. | 126 | * they are also freshly created. |
127 | */ | 127 | */ |
128 | static void ext4_sync_parent(struct inode *inode) | 128 | static int ext4_sync_parent(struct inode *inode) |
129 | { | 129 | { |
130 | struct writeback_control wbc; | ||
130 | struct dentry *dentry = NULL; | 131 | struct dentry *dentry = NULL; |
132 | int ret = 0; | ||
131 | 133 | ||
132 | while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { | 134 | while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { |
133 | ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); | 135 | ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); |
@@ -136,8 +138,17 @@ static void ext4_sync_parent(struct inode *inode) | |||
136 | if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) | 138 | if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) |
137 | break; | 139 | break; |
138 | inode = dentry->d_parent->d_inode; | 140 | inode = dentry->d_parent->d_inode; |
139 | sync_mapping_buffers(inode->i_mapping); | 141 | ret = sync_mapping_buffers(inode->i_mapping); |
142 | if (ret) | ||
143 | break; | ||
144 | memset(&wbc, 0, sizeof(wbc)); | ||
145 | wbc.sync_mode = WB_SYNC_ALL; | ||
146 | wbc.nr_to_write = 0; /* only write out the inode */ | ||
147 | ret = sync_inode(inode, &wbc); | ||
148 | if (ret) | ||
149 | break; | ||
140 | } | 150 | } |
151 | return ret; | ||
141 | } | 152 | } |
142 | 153 | ||
143 | /* | 154 | /* |
@@ -176,7 +187,7 @@ int ext4_sync_file(struct file *file, int datasync) | |||
176 | if (!journal) { | 187 | if (!journal) { |
177 | ret = generic_file_fsync(file, datasync); | 188 | ret = generic_file_fsync(file, datasync); |
178 | if (!ret && !list_empty(&inode->i_dentry)) | 189 | if (!ret && !list_empty(&inode->i_dentry)) |
179 | ext4_sync_parent(inode); | 190 | ret = ext4_sync_parent(inode); |
180 | goto out; | 191 | goto out; |
181 | } | 192 | } |
182 | 193 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ad8e303c0d29..f2fa5e8a582c 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, | |||
2502 | * for partial write. | 2502 | * for partial write. |
2503 | */ | 2503 | */ |
2504 | set_buffer_new(bh); | 2504 | set_buffer_new(bh); |
2505 | set_buffer_mapped(bh); | ||
2505 | } | 2506 | } |
2506 | return 0; | 2507 | return 0; |
2507 | } | 2508 | } |
@@ -4429,8 +4430,8 @@ void ext4_truncate(struct inode *inode) | |||
4429 | Indirect chain[4]; | 4430 | Indirect chain[4]; |
4430 | Indirect *partial; | 4431 | Indirect *partial; |
4431 | __le32 nr = 0; | 4432 | __le32 nr = 0; |
4432 | int n; | 4433 | int n = 0; |
4433 | ext4_lblk_t last_block; | 4434 | ext4_lblk_t last_block, max_block; |
4434 | unsigned blocksize = inode->i_sb->s_blocksize; | 4435 | unsigned blocksize = inode->i_sb->s_blocksize; |
4435 | 4436 | ||
4436 | trace_ext4_truncate_enter(inode); | 4437 | trace_ext4_truncate_enter(inode); |
@@ -4455,14 +4456,18 @@ void ext4_truncate(struct inode *inode) | |||
4455 | 4456 | ||
4456 | last_block = (inode->i_size + blocksize-1) | 4457 | last_block = (inode->i_size + blocksize-1) |
4457 | >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); | 4458 | >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); |
4459 | max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) | ||
4460 | >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); | ||
4458 | 4461 | ||
4459 | if (inode->i_size & (blocksize - 1)) | 4462 | if (inode->i_size & (blocksize - 1)) |
4460 | if (ext4_block_truncate_page(handle, mapping, inode->i_size)) | 4463 | if (ext4_block_truncate_page(handle, mapping, inode->i_size)) |
4461 | goto out_stop; | 4464 | goto out_stop; |
4462 | 4465 | ||
4463 | n = ext4_block_to_path(inode, last_block, offsets, NULL); | 4466 | if (last_block != max_block) { |
4464 | if (n == 0) | 4467 | n = ext4_block_to_path(inode, last_block, offsets, NULL); |
4465 | goto out_stop; /* error */ | 4468 | if (n == 0) |
4469 | goto out_stop; /* error */ | ||
4470 | } | ||
4466 | 4471 | ||
4467 | /* | 4472 | /* |
4468 | * OK. This truncate is going to happen. We add the inode to the | 4473 | * OK. This truncate is going to happen. We add the inode to the |
@@ -4493,7 +4498,13 @@ void ext4_truncate(struct inode *inode) | |||
4493 | */ | 4498 | */ |
4494 | ei->i_disksize = inode->i_size; | 4499 | ei->i_disksize = inode->i_size; |
4495 | 4500 | ||
4496 | if (n == 1) { /* direct blocks */ | 4501 | if (last_block == max_block) { |
4502 | /* | ||
4503 | * It is unnecessary to free any data blocks if last_block is | ||
4504 | * equal to the indirect block limit. | ||
4505 | */ | ||
4506 | goto out_unlock; | ||
4507 | } else if (n == 1) { /* direct blocks */ | ||
4497 | ext4_free_data(handle, inode, NULL, i_data+offsets[0], | 4508 | ext4_free_data(handle, inode, NULL, i_data+offsets[0], |
4498 | i_data + EXT4_NDIR_BLOCKS); | 4509 | i_data + EXT4_NDIR_BLOCKS); |
4499 | goto do_indirects; | 4510 | goto do_indirects; |
@@ -4553,6 +4564,7 @@ do_indirects: | |||
4553 | ; | 4564 | ; |
4554 | } | 4565 | } |
4555 | 4566 | ||
4567 | out_unlock: | ||
4556 | up_write(&ei->i_data_sem); | 4568 | up_write(&ei->i_data_sem); |
4557 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | 4569 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); |
4558 | ext4_mark_inode_dirty(handle, inode); | 4570 | ext4_mark_inode_dirty(handle, inode); |
@@ -5398,13 +5410,12 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks, | |||
5398 | /* if nrblocks are contiguous */ | 5410 | /* if nrblocks are contiguous */ |
5399 | if (chunk) { | 5411 | if (chunk) { |
5400 | /* | 5412 | /* |
5401 | * With N contiguous data blocks, it need at most | 5413 | * With N contiguous data blocks, we need at most |
5402 | * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) indirect blocks | 5414 | * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks, |
5403 | * 2 dindirect blocks | 5415 | * 2 dindirect blocks, and 1 tindirect block |
5404 | * 1 tindirect block | ||
5405 | */ | 5416 | */ |
5406 | indirects = nrblocks / EXT4_ADDR_PER_BLOCK(inode->i_sb); | 5417 | return DIV_ROUND_UP(nrblocks, |
5407 | return indirects + 3; | 5418 | EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; |
5408 | } | 5419 | } |
5409 | /* | 5420 | /* |
5410 | * if nrblocks are not contiguous, worse case, each block touch | 5421 | * if nrblocks are not contiguous, worse case, each block touch |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 056474b7b8e0..8553dfb310af 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -242,27 +242,44 @@ static void ext4_put_nojournal(handle_t *handle) | |||
242 | * journal_end calls result in the superblock being marked dirty, so | 242 | * journal_end calls result in the superblock being marked dirty, so |
243 | * that sync() will call the filesystem's write_super callback if | 243 | * that sync() will call the filesystem's write_super callback if |
244 | * appropriate. | 244 | * appropriate. |
245 | * | ||
246 | * To avoid j_barrier hold in userspace when a user calls freeze(), | ||
247 | * ext4 prevents a new handle from being started by s_frozen, which | ||
248 | * is in an upper layer. | ||
245 | */ | 249 | */ |
246 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) | 250 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) |
247 | { | 251 | { |
248 | journal_t *journal; | 252 | journal_t *journal; |
253 | handle_t *handle; | ||
249 | 254 | ||
250 | if (sb->s_flags & MS_RDONLY) | 255 | if (sb->s_flags & MS_RDONLY) |
251 | return ERR_PTR(-EROFS); | 256 | return ERR_PTR(-EROFS); |
252 | 257 | ||
253 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
254 | /* Special case here: if the journal has aborted behind our | ||
255 | * backs (eg. EIO in the commit thread), then we still need to | ||
256 | * take the FS itself readonly cleanly. */ | ||
257 | journal = EXT4_SB(sb)->s_journal; | 258 | journal = EXT4_SB(sb)->s_journal; |
258 | if (journal) { | 259 | handle = ext4_journal_current_handle(); |
259 | if (is_journal_aborted(journal)) { | 260 | |
260 | ext4_abort(sb, "Detected aborted journal"); | 261 | /* |
261 | return ERR_PTR(-EROFS); | 262 | * If a handle has been started, it should be allowed to |
262 | } | 263 | * finish, otherwise deadlock could happen between freeze |
263 | return jbd2_journal_start(journal, nblocks); | 264 | * and others(e.g. truncate) due to the restart of the |
265 | * journal handle if the filesystem is forzen and active | ||
266 | * handles are not stopped. | ||
267 | */ | ||
268 | if (!handle) | ||
269 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
270 | |||
271 | if (!journal) | ||
272 | return ext4_get_nojournal(); | ||
273 | /* | ||
274 | * Special case here: if the journal has aborted behind our | ||
275 | * backs (eg. EIO in the commit thread), then we still need to | ||
276 | * take the FS itself readonly cleanly. | ||
277 | */ | ||
278 | if (is_journal_aborted(journal)) { | ||
279 | ext4_abort(sb, "Detected aborted journal"); | ||
280 | return ERR_PTR(-EROFS); | ||
264 | } | 281 | } |
265 | return ext4_get_nojournal(); | 282 | return jbd2_journal_start(journal, nblocks); |
266 | } | 283 | } |
267 | 284 | ||
268 | /* | 285 | /* |
@@ -2975,6 +2992,12 @@ static int ext4_register_li_request(struct super_block *sb, | |||
2975 | mutex_unlock(&ext4_li_info->li_list_mtx); | 2992 | mutex_unlock(&ext4_li_info->li_list_mtx); |
2976 | 2993 | ||
2977 | sbi->s_li_request = elr; | 2994 | sbi->s_li_request = elr; |
2995 | /* | ||
2996 | * set elr to NULL here since it has been inserted to | ||
2997 | * the request_list and the removal and free of it is | ||
2998 | * handled by ext4_clear_request_list from now on. | ||
2999 | */ | ||
3000 | elr = NULL; | ||
2978 | 3001 | ||
2979 | if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) { | 3002 | if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) { |
2980 | ret = ext4_run_lazyinit_thread(); | 3003 | ret = ext4_run_lazyinit_thread(); |
@@ -3385,6 +3408,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3385 | get_random_bytes(&sbi->s_next_generation, sizeof(u32)); | 3408 | get_random_bytes(&sbi->s_next_generation, sizeof(u32)); |
3386 | spin_lock_init(&sbi->s_next_gen_lock); | 3409 | spin_lock_init(&sbi->s_next_gen_lock); |
3387 | 3410 | ||
3411 | init_timer(&sbi->s_err_report); | ||
3412 | sbi->s_err_report.function = print_daily_error_info; | ||
3413 | sbi->s_err_report.data = (unsigned long) sb; | ||
3414 | |||
3388 | err = percpu_counter_init(&sbi->s_freeblocks_counter, | 3415 | err = percpu_counter_init(&sbi->s_freeblocks_counter, |
3389 | ext4_count_free_blocks(sb)); | 3416 | ext4_count_free_blocks(sb)); |
3390 | if (!err) { | 3417 | if (!err) { |
@@ -3646,9 +3673,6 @@ no_journal: | |||
3646 | "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, | 3673 | "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, |
3647 | *sbi->s_es->s_mount_opts ? "; " : "", orig_data); | 3674 | *sbi->s_es->s_mount_opts ? "; " : "", orig_data); |
3648 | 3675 | ||
3649 | init_timer(&sbi->s_err_report); | ||
3650 | sbi->s_err_report.function = print_daily_error_info; | ||
3651 | sbi->s_err_report.data = (unsigned long) sb; | ||
3652 | if (es->s_error_count) | 3676 | if (es->s_error_count) |
3653 | mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */ | 3677 | mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */ |
3654 | 3678 | ||
@@ -3672,6 +3696,7 @@ failed_mount_wq: | |||
3672 | sbi->s_journal = NULL; | 3696 | sbi->s_journal = NULL; |
3673 | } | 3697 | } |
3674 | failed_mount3: | 3698 | failed_mount3: |
3699 | del_timer(&sbi->s_err_report); | ||
3675 | if (sbi->s_flex_groups) { | 3700 | if (sbi->s_flex_groups) { |
3676 | if (is_vmalloc_addr(sbi->s_flex_groups)) | 3701 | if (is_vmalloc_addr(sbi->s_flex_groups)) |
3677 | vfree(sbi->s_flex_groups); | 3702 | vfree(sbi->s_flex_groups); |
@@ -4138,6 +4163,11 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
4138 | /* | 4163 | /* |
4139 | * LVM calls this function before a (read-only) snapshot is created. This | 4164 | * LVM calls this function before a (read-only) snapshot is created. This |
4140 | * gives us a chance to flush the journal completely and mark the fs clean. | 4165 | * gives us a chance to flush the journal completely and mark the fs clean. |
4166 | * | ||
4167 | * Note that only this function cannot bring a filesystem to be in a clean | ||
4168 | * state independently, because ext4 prevents a new handle from being started | ||
4169 | * by @sb->s_frozen, which stays in an upper layer. It thus needs help from | ||
4170 | * the upper layer. | ||
4141 | */ | 4171 | */ |
4142 | static int ext4_freeze(struct super_block *sb) | 4172 | static int ext4_freeze(struct super_block *sb) |
4143 | { | 4173 | { |
@@ -4614,11 +4644,24 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
4614 | 4644 | ||
4615 | static int ext4_quota_off(struct super_block *sb, int type) | 4645 | static int ext4_quota_off(struct super_block *sb, int type) |
4616 | { | 4646 | { |
4647 | struct inode *inode = sb_dqopt(sb)->files[type]; | ||
4648 | handle_t *handle; | ||
4649 | |||
4617 | /* Force all delayed allocation blocks to be allocated. | 4650 | /* Force all delayed allocation blocks to be allocated. |
4618 | * Caller already holds s_umount sem */ | 4651 | * Caller already holds s_umount sem */ |
4619 | if (test_opt(sb, DELALLOC)) | 4652 | if (test_opt(sb, DELALLOC)) |
4620 | sync_filesystem(sb); | 4653 | sync_filesystem(sb); |
4621 | 4654 | ||
4655 | /* Update modification times of quota files when userspace can | ||
4656 | * start looking at them */ | ||
4657 | handle = ext4_journal_start(inode, 1); | ||
4658 | if (IS_ERR(handle)) | ||
4659 | goto out; | ||
4660 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
4661 | ext4_mark_inode_dirty(handle, inode); | ||
4662 | ext4_journal_stop(handle); | ||
4663 | |||
4664 | out: | ||
4622 | return dquot_quota_off(sb, type); | 4665 | return dquot_quota_off(sb, type); |
4623 | } | 4666 | } |
4624 | 4667 | ||
@@ -4714,9 +4757,8 @@ out: | |||
4714 | if (inode->i_size < off + len) { | 4757 | if (inode->i_size < off + len) { |
4715 | i_size_write(inode, off + len); | 4758 | i_size_write(inode, off + len); |
4716 | EXT4_I(inode)->i_disksize = inode->i_size; | 4759 | EXT4_I(inode)->i_disksize = inode->i_size; |
4760 | ext4_mark_inode_dirty(handle, inode); | ||
4717 | } | 4761 | } |
4718 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
4719 | ext4_mark_inode_dirty(handle, inode); | ||
4720 | mutex_unlock(&inode->i_mutex); | 4762 | mutex_unlock(&inode->i_mutex); |
4721 | return len; | 4763 | return len; |
4722 | } | 4764 | } |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 20af62f4304b..6e28000a4b21 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -105,6 +105,8 @@ static int journal_submit_commit_record(journal_t *journal, | |||
105 | int ret; | 105 | int ret; |
106 | struct timespec now = current_kernel_time(); | 106 | struct timespec now = current_kernel_time(); |
107 | 107 | ||
108 | *cbh = NULL; | ||
109 | |||
108 | if (is_journal_aborted(journal)) | 110 | if (is_journal_aborted(journal)) |
109 | return 0; | 111 | return 0; |
110 | 112 | ||
@@ -806,7 +808,7 @@ wait_for_iobuf: | |||
806 | if (err) | 808 | if (err) |
807 | __jbd2_journal_abort_hard(journal); | 809 | __jbd2_journal_abort_hard(journal); |
808 | } | 810 | } |
809 | if (!err && !is_journal_aborted(journal)) | 811 | if (cbh) |
810 | err = journal_wait_on_commit_record(journal, cbh); | 812 | err = journal_wait_on_commit_record(journal, cbh); |
811 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | 813 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, |
812 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT) && | 814 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT) && |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index aba8ebaec25c..e0ec3db1c395 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -2413,10 +2413,12 @@ const char *jbd2_dev_to_name(dev_t device) | |||
2413 | new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL); | 2413 | new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL); |
2414 | if (!new_dev) | 2414 | if (!new_dev) |
2415 | return "NODEV-ALLOCFAILURE"; /* Something non-NULL */ | 2415 | return "NODEV-ALLOCFAILURE"; /* Something non-NULL */ |
2416 | bd = bdget(device); | ||
2416 | spin_lock(&devname_cache_lock); | 2417 | spin_lock(&devname_cache_lock); |
2417 | if (devcache[i]) { | 2418 | if (devcache[i]) { |
2418 | if (devcache[i]->device == device) { | 2419 | if (devcache[i]->device == device) { |
2419 | kfree(new_dev); | 2420 | kfree(new_dev); |
2421 | bdput(bd); | ||
2420 | ret = devcache[i]->devname; | 2422 | ret = devcache[i]->devname; |
2421 | spin_unlock(&devname_cache_lock); | 2423 | spin_unlock(&devname_cache_lock); |
2422 | return ret; | 2424 | return ret; |
@@ -2425,7 +2427,6 @@ const char *jbd2_dev_to_name(dev_t device) | |||
2425 | } | 2427 | } |
2426 | devcache[i] = new_dev; | 2428 | devcache[i] = new_dev; |
2427 | devcache[i]->device = device; | 2429 | devcache[i]->device = device; |
2428 | bd = bdget(device); | ||
2429 | if (bd) { | 2430 | if (bd) { |
2430 | bdevname(bd, devcache[i]->devname); | 2431 | bdevname(bd, devcache[i]->devname); |
2431 | bdput(bd); | 2432 | bdput(bd); |
diff --git a/fs/namespace.c b/fs/namespace.c index 7dba2ed03429..d99bcf59e4c2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1030,18 +1030,6 @@ const struct seq_operations mounts_op = { | |||
1030 | .show = show_vfsmnt | 1030 | .show = show_vfsmnt |
1031 | }; | 1031 | }; |
1032 | 1032 | ||
1033 | static int uuid_is_nil(u8 *uuid) | ||
1034 | { | ||
1035 | int i; | ||
1036 | u8 *cp = (u8 *)uuid; | ||
1037 | |||
1038 | for (i = 0; i < 16; i++) { | ||
1039 | if (*cp++) | ||
1040 | return 0; | ||
1041 | } | ||
1042 | return 1; | ||
1043 | } | ||
1044 | |||
1045 | static int show_mountinfo(struct seq_file *m, void *v) | 1033 | static int show_mountinfo(struct seq_file *m, void *v) |
1046 | { | 1034 | { |
1047 | struct proc_mounts *p = m->private; | 1035 | struct proc_mounts *p = m->private; |
@@ -1085,10 +1073,6 @@ static int show_mountinfo(struct seq_file *m, void *v) | |||
1085 | if (IS_MNT_UNBINDABLE(mnt)) | 1073 | if (IS_MNT_UNBINDABLE(mnt)) |
1086 | seq_puts(m, " unbindable"); | 1074 | seq_puts(m, " unbindable"); |
1087 | 1075 | ||
1088 | if (!uuid_is_nil(mnt->mnt_sb->s_uuid)) | ||
1089 | /* print the uuid */ | ||
1090 | seq_printf(m, " uuid:%pU", mnt->mnt_sb->s_uuid); | ||
1091 | |||
1092 | /* Filesystem specific data */ | 1076 | /* Filesystem specific data */ |
1093 | seq_puts(m, " - "); | 1077 | seq_puts(m, " - "); |
1094 | show_type(m, sb); | 1078 | show_type(m, sb); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index af0c6279a4a7..e4cbc11a74ab 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 | |||
542 | if (!nfs_need_commit(nfsi)) | 542 | if (!nfs_need_commit(nfsi)) |
543 | return 0; | 543 | return 0; |
544 | 544 | ||
545 | spin_lock(&inode->i_lock); | ||
545 | ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); | 546 | ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); |
546 | if (ret > 0) | 547 | if (ret > 0) |
547 | nfsi->ncommit -= ret; | 548 | nfsi->ncommit -= ret; |
549 | spin_unlock(&inode->i_lock); | ||
550 | |||
548 | if (nfs_need_commit(NFS_I(inode))) | 551 | if (nfs_need_commit(NFS_I(inode))) |
549 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 552 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
553 | |||
550 | return ret; | 554 | return ret; |
551 | } | 555 | } |
552 | #else | 556 | #else |
@@ -1483,9 +1487,7 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1483 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); | 1487 | res = nfs_commit_set_lock(NFS_I(inode), may_wait); |
1484 | if (res <= 0) | 1488 | if (res <= 0) |
1485 | goto out_mark_dirty; | 1489 | goto out_mark_dirty; |
1486 | spin_lock(&inode->i_lock); | ||
1487 | res = nfs_scan_commit(inode, &head, 0, 0); | 1490 | res = nfs_scan_commit(inode, &head, 0, 0); |
1488 | spin_unlock(&inode->i_lock); | ||
1489 | if (res) { | 1491 | if (res) { |
1490 | int error; | 1492 | int error; |
1491 | 1493 | ||
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 0c6d81670137..7c831a2731fa 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) | |||
38 | exp_readlock(); | 38 | exp_readlock(); |
39 | nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); | 39 | nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); |
40 | fh_put(&fh); | 40 | fh_put(&fh); |
41 | rqstp->rq_client = NULL; | ||
42 | exp_readunlock(); | 41 | exp_readunlock(); |
43 | /* We return nlm error codes as nlm doesn't know | 42 | /* We return nlm error codes as nlm doesn't know |
44 | * about nfsd, but nfsd does know about nlm.. | 43 | * about nfsd, but nfsd does know about nlm.. |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4b36ec3eb8ea..aa309aa93fe8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -397,10 +397,13 @@ static void unhash_generic_stateid(struct nfs4_stateid *stp) | |||
397 | 397 | ||
398 | static void free_generic_stateid(struct nfs4_stateid *stp) | 398 | static void free_generic_stateid(struct nfs4_stateid *stp) |
399 | { | 399 | { |
400 | int oflag = nfs4_access_bmap_to_omode(stp); | 400 | int oflag; |
401 | 401 | ||
402 | nfs4_file_put_access(stp->st_file, oflag); | 402 | if (stp->st_access_bmap) { |
403 | put_nfs4_file(stp->st_file); | 403 | oflag = nfs4_access_bmap_to_omode(stp); |
404 | nfs4_file_put_access(stp->st_file, oflag); | ||
405 | put_nfs4_file(stp->st_file); | ||
406 | } | ||
404 | kmem_cache_free(stateid_slab, stp); | 407 | kmem_cache_free(stateid_slab, stp); |
405 | } | 408 | } |
406 | 409 | ||
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 5ea402023ebd..9ef9ed2cfe2e 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( | |||
293 | size_t nbytes, offset; | 293 | size_t nbytes, offset; |
294 | gfp_t gfp_mask = xb_to_gfp(flags); | 294 | gfp_t gfp_mask = xb_to_gfp(flags); |
295 | unsigned short page_count, i; | 295 | unsigned short page_count, i; |
296 | pgoff_t first; | ||
297 | xfs_off_t end; | 296 | xfs_off_t end; |
298 | int error; | 297 | int error; |
299 | 298 | ||
@@ -333,7 +332,6 @@ use_alloc_page: | |||
333 | return error; | 332 | return error; |
334 | 333 | ||
335 | offset = bp->b_offset; | 334 | offset = bp->b_offset; |
336 | first = bp->b_file_offset >> PAGE_SHIFT; | ||
337 | bp->b_flags |= _XBF_PAGES; | 335 | bp->b_flags |= _XBF_PAGES; |
338 | 336 | ||
339 | for (i = 0; i < bp->b_page_count; i++) { | 337 | for (i = 0; i < bp->b_page_count; i++) { |
@@ -657,8 +655,6 @@ xfs_buf_readahead( | |||
657 | xfs_off_t ioff, | 655 | xfs_off_t ioff, |
658 | size_t isize) | 656 | size_t isize) |
659 | { | 657 | { |
660 | struct backing_dev_info *bdi; | ||
661 | |||
662 | if (bdi_read_congested(target->bt_bdi)) | 658 | if (bdi_read_congested(target->bt_bdi)) |
663 | return; | 659 | return; |
664 | 660 | ||
@@ -919,8 +915,6 @@ xfs_buf_lock( | |||
919 | 915 | ||
920 | if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE)) | 916 | if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE)) |
921 | xfs_log_force(bp->b_target->bt_mount, 0); | 917 | xfs_log_force(bp->b_target->bt_mount, 0); |
922 | if (atomic_read(&bp->b_io_remaining)) | ||
923 | blk_flush_plug(current); | ||
924 | down(&bp->b_sema); | 918 | down(&bp->b_sema); |
925 | XB_SET_OWNER(bp); | 919 | XB_SET_OWNER(bp); |
926 | 920 | ||
@@ -1309,8 +1303,6 @@ xfs_buf_iowait( | |||
1309 | { | 1303 | { |
1310 | trace_xfs_buf_iowait(bp, _RET_IP_); | 1304 | trace_xfs_buf_iowait(bp, _RET_IP_); |
1311 | 1305 | ||
1312 | if (atomic_read(&bp->b_io_remaining)) | ||
1313 | blk_flush_plug(current); | ||
1314 | wait_for_completion(&bp->b_iowait); | 1306 | wait_for_completion(&bp->b_iowait); |
1315 | 1307 | ||
1316 | trace_xfs_buf_iowait_done(bp, _RET_IP_); | 1308 | trace_xfs_buf_iowait_done(bp, _RET_IP_); |
@@ -1747,8 +1739,8 @@ xfsbufd( | |||
1747 | do { | 1739 | do { |
1748 | long age = xfs_buf_age_centisecs * msecs_to_jiffies(10); | 1740 | long age = xfs_buf_age_centisecs * msecs_to_jiffies(10); |
1749 | long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10); | 1741 | long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10); |
1750 | int count = 0; | ||
1751 | struct list_head tmp; | 1742 | struct list_head tmp; |
1743 | struct blk_plug plug; | ||
1752 | 1744 | ||
1753 | if (unlikely(freezing(current))) { | 1745 | if (unlikely(freezing(current))) { |
1754 | set_bit(XBT_FORCE_SLEEP, &target->bt_flags); | 1746 | set_bit(XBT_FORCE_SLEEP, &target->bt_flags); |
@@ -1764,16 +1756,15 @@ xfsbufd( | |||
1764 | 1756 | ||
1765 | xfs_buf_delwri_split(target, &tmp, age); | 1757 | xfs_buf_delwri_split(target, &tmp, age); |
1766 | list_sort(NULL, &tmp, xfs_buf_cmp); | 1758 | list_sort(NULL, &tmp, xfs_buf_cmp); |
1759 | |||
1760 | blk_start_plug(&plug); | ||
1767 | while (!list_empty(&tmp)) { | 1761 | while (!list_empty(&tmp)) { |
1768 | struct xfs_buf *bp; | 1762 | struct xfs_buf *bp; |
1769 | bp = list_first_entry(&tmp, struct xfs_buf, b_list); | 1763 | bp = list_first_entry(&tmp, struct xfs_buf, b_list); |
1770 | list_del_init(&bp->b_list); | 1764 | list_del_init(&bp->b_list); |
1771 | xfs_bdstrat_cb(bp); | 1765 | xfs_bdstrat_cb(bp); |
1772 | count++; | ||
1773 | } | 1766 | } |
1774 | if (count) | 1767 | blk_finish_plug(&plug); |
1775 | blk_flush_plug(current); | ||
1776 | |||
1777 | } while (!kthread_should_stop()); | 1768 | } while (!kthread_should_stop()); |
1778 | 1769 | ||
1779 | return 0; | 1770 | return 0; |
@@ -1793,6 +1784,7 @@ xfs_flush_buftarg( | |||
1793 | int pincount = 0; | 1784 | int pincount = 0; |
1794 | LIST_HEAD(tmp_list); | 1785 | LIST_HEAD(tmp_list); |
1795 | LIST_HEAD(wait_list); | 1786 | LIST_HEAD(wait_list); |
1787 | struct blk_plug plug; | ||
1796 | 1788 | ||
1797 | xfs_buf_runall_queues(xfsconvertd_workqueue); | 1789 | xfs_buf_runall_queues(xfsconvertd_workqueue); |
1798 | xfs_buf_runall_queues(xfsdatad_workqueue); | 1790 | xfs_buf_runall_queues(xfsdatad_workqueue); |
@@ -1807,6 +1799,8 @@ xfs_flush_buftarg( | |||
1807 | * we do that after issuing all the IO. | 1799 | * we do that after issuing all the IO. |
1808 | */ | 1800 | */ |
1809 | list_sort(NULL, &tmp_list, xfs_buf_cmp); | 1801 | list_sort(NULL, &tmp_list, xfs_buf_cmp); |
1802 | |||
1803 | blk_start_plug(&plug); | ||
1810 | while (!list_empty(&tmp_list)) { | 1804 | while (!list_empty(&tmp_list)) { |
1811 | bp = list_first_entry(&tmp_list, struct xfs_buf, b_list); | 1805 | bp = list_first_entry(&tmp_list, struct xfs_buf, b_list); |
1812 | ASSERT(target == bp->b_target); | 1806 | ASSERT(target == bp->b_target); |
@@ -1817,10 +1811,10 @@ xfs_flush_buftarg( | |||
1817 | } | 1811 | } |
1818 | xfs_bdstrat_cb(bp); | 1812 | xfs_bdstrat_cb(bp); |
1819 | } | 1813 | } |
1814 | blk_finish_plug(&plug); | ||
1820 | 1815 | ||
1821 | if (wait) { | 1816 | if (wait) { |
1822 | /* Expedite and wait for IO to complete. */ | 1817 | /* Wait for IO to complete. */ |
1823 | blk_flush_plug(current); | ||
1824 | while (!list_empty(&wait_list)) { | 1818 | while (!list_empty(&wait_list)) { |
1825 | bp = list_first_entry(&wait_list, struct xfs_buf, b_list); | 1819 | bp = list_first_entry(&wait_list, struct xfs_buf, b_list); |
1826 | 1820 | ||
diff --git a/fs/xfs/linux-2.6/xfs_message.c b/fs/xfs/linux-2.6/xfs_message.c index 508e06fd7d1e..3ca795609113 100644 --- a/fs/xfs/linux-2.6/xfs_message.c +++ b/fs/xfs/linux-2.6/xfs_message.c | |||
@@ -28,53 +28,47 @@ | |||
28 | /* | 28 | /* |
29 | * XFS logging functions | 29 | * XFS logging functions |
30 | */ | 30 | */ |
31 | static int | 31 | static void |
32 | __xfs_printk( | 32 | __xfs_printk( |
33 | const char *level, | 33 | const char *level, |
34 | const struct xfs_mount *mp, | 34 | const struct xfs_mount *mp, |
35 | struct va_format *vaf) | 35 | struct va_format *vaf) |
36 | { | 36 | { |
37 | if (mp && mp->m_fsname) | 37 | if (mp && mp->m_fsname) |
38 | return printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); | 38 | printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); |
39 | return printk("%sXFS: %pV\n", level, vaf); | 39 | printk("%sXFS: %pV\n", level, vaf); |
40 | } | 40 | } |
41 | 41 | ||
42 | int xfs_printk( | 42 | void xfs_printk( |
43 | const char *level, | 43 | const char *level, |
44 | const struct xfs_mount *mp, | 44 | const struct xfs_mount *mp, |
45 | const char *fmt, ...) | 45 | const char *fmt, ...) |
46 | { | 46 | { |
47 | struct va_format vaf; | 47 | struct va_format vaf; |
48 | va_list args; | 48 | va_list args; |
49 | int r; | ||
50 | 49 | ||
51 | va_start(args, fmt); | 50 | va_start(args, fmt); |
52 | 51 | ||
53 | vaf.fmt = fmt; | 52 | vaf.fmt = fmt; |
54 | vaf.va = &args; | 53 | vaf.va = &args; |
55 | 54 | ||
56 | r = __xfs_printk(level, mp, &vaf); | 55 | __xfs_printk(level, mp, &vaf); |
57 | va_end(args); | 56 | va_end(args); |
58 | |||
59 | return r; | ||
60 | } | 57 | } |
61 | 58 | ||
62 | #define define_xfs_printk_level(func, kern_level) \ | 59 | #define define_xfs_printk_level(func, kern_level) \ |
63 | int func(const struct xfs_mount *mp, const char *fmt, ...) \ | 60 | void func(const struct xfs_mount *mp, const char *fmt, ...) \ |
64 | { \ | 61 | { \ |
65 | struct va_format vaf; \ | 62 | struct va_format vaf; \ |
66 | va_list args; \ | 63 | va_list args; \ |
67 | int r; \ | ||
68 | \ | 64 | \ |
69 | va_start(args, fmt); \ | 65 | va_start(args, fmt); \ |
70 | \ | 66 | \ |
71 | vaf.fmt = fmt; \ | 67 | vaf.fmt = fmt; \ |
72 | vaf.va = &args; \ | 68 | vaf.va = &args; \ |
73 | \ | 69 | \ |
74 | r = __xfs_printk(kern_level, mp, &vaf); \ | 70 | __xfs_printk(kern_level, mp, &vaf); \ |
75 | va_end(args); \ | 71 | va_end(args); \ |
76 | \ | ||
77 | return r; \ | ||
78 | } \ | 72 | } \ |
79 | 73 | ||
80 | define_xfs_printk_level(xfs_emerg, KERN_EMERG); | 74 | define_xfs_printk_level(xfs_emerg, KERN_EMERG); |
@@ -88,7 +82,7 @@ define_xfs_printk_level(xfs_info, KERN_INFO); | |||
88 | define_xfs_printk_level(xfs_debug, KERN_DEBUG); | 82 | define_xfs_printk_level(xfs_debug, KERN_DEBUG); |
89 | #endif | 83 | #endif |
90 | 84 | ||
91 | int | 85 | void |
92 | xfs_alert_tag( | 86 | xfs_alert_tag( |
93 | const struct xfs_mount *mp, | 87 | const struct xfs_mount *mp, |
94 | int panic_tag, | 88 | int panic_tag, |
@@ -97,7 +91,6 @@ xfs_alert_tag( | |||
97 | struct va_format vaf; | 91 | struct va_format vaf; |
98 | va_list args; | 92 | va_list args; |
99 | int do_panic = 0; | 93 | int do_panic = 0; |
100 | int r; | ||
101 | 94 | ||
102 | if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { | 95 | if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { |
103 | xfs_printk(KERN_ALERT, mp, | 96 | xfs_printk(KERN_ALERT, mp, |
@@ -110,12 +103,10 @@ xfs_alert_tag( | |||
110 | vaf.fmt = fmt; | 103 | vaf.fmt = fmt; |
111 | vaf.va = &args; | 104 | vaf.va = &args; |
112 | 105 | ||
113 | r = __xfs_printk(KERN_ALERT, mp, &vaf); | 106 | __xfs_printk(KERN_ALERT, mp, &vaf); |
114 | va_end(args); | 107 | va_end(args); |
115 | 108 | ||
116 | BUG_ON(do_panic); | 109 | BUG_ON(do_panic); |
117 | |||
118 | return r; | ||
119 | } | 110 | } |
120 | 111 | ||
121 | void | 112 | void |
diff --git a/fs/xfs/linux-2.6/xfs_message.h b/fs/xfs/linux-2.6/xfs_message.h index e77ffa16745b..f1b3fc1b6c4e 100644 --- a/fs/xfs/linux-2.6/xfs_message.h +++ b/fs/xfs/linux-2.6/xfs_message.h | |||
@@ -3,32 +3,34 @@ | |||
3 | 3 | ||
4 | struct xfs_mount; | 4 | struct xfs_mount; |
5 | 5 | ||
6 | extern int xfs_printk(const char *level, const struct xfs_mount *mp, | 6 | extern void xfs_printk(const char *level, const struct xfs_mount *mp, |
7 | const char *fmt, ...) | 7 | const char *fmt, ...) |
8 | __attribute__ ((format (printf, 3, 4))); | 8 | __attribute__ ((format (printf, 3, 4))); |
9 | extern int xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...) | 9 | extern void xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...) |
10 | __attribute__ ((format (printf, 2, 3))); | 10 | __attribute__ ((format (printf, 2, 3))); |
11 | extern int xfs_alert(const struct xfs_mount *mp, const char *fmt, ...) | 11 | extern void xfs_alert(const struct xfs_mount *mp, const char *fmt, ...) |
12 | __attribute__ ((format (printf, 2, 3))); | 12 | __attribute__ ((format (printf, 2, 3))); |
13 | extern int xfs_alert_tag(const struct xfs_mount *mp, int tag, | 13 | extern void xfs_alert_tag(const struct xfs_mount *mp, int tag, |
14 | const char *fmt, ...) | 14 | const char *fmt, ...) |
15 | __attribute__ ((format (printf, 3, 4))); | 15 | __attribute__ ((format (printf, 3, 4))); |
16 | extern int xfs_crit(const struct xfs_mount *mp, const char *fmt, ...) | 16 | extern void xfs_crit(const struct xfs_mount *mp, const char *fmt, ...) |
17 | __attribute__ ((format (printf, 2, 3))); | 17 | __attribute__ ((format (printf, 2, 3))); |
18 | extern int xfs_err(const struct xfs_mount *mp, const char *fmt, ...) | 18 | extern void xfs_err(const struct xfs_mount *mp, const char *fmt, ...) |
19 | __attribute__ ((format (printf, 2, 3))); | 19 | __attribute__ ((format (printf, 2, 3))); |
20 | extern int xfs_warn(const struct xfs_mount *mp, const char *fmt, ...) | 20 | extern void xfs_warn(const struct xfs_mount *mp, const char *fmt, ...) |
21 | __attribute__ ((format (printf, 2, 3))); | 21 | __attribute__ ((format (printf, 2, 3))); |
22 | extern int xfs_notice(const struct xfs_mount *mp, const char *fmt, ...) | 22 | extern void xfs_notice(const struct xfs_mount *mp, const char *fmt, ...) |
23 | __attribute__ ((format (printf, 2, 3))); | 23 | __attribute__ ((format (printf, 2, 3))); |
24 | extern int xfs_info(const struct xfs_mount *mp, const char *fmt, ...) | 24 | extern void xfs_info(const struct xfs_mount *mp, const char *fmt, ...) |
25 | __attribute__ ((format (printf, 2, 3))); | 25 | __attribute__ ((format (printf, 2, 3))); |
26 | 26 | ||
27 | #ifdef DEBUG | 27 | #ifdef DEBUG |
28 | extern int xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) | 28 | extern void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) |
29 | __attribute__ ((format (printf, 2, 3))); | 29 | __attribute__ ((format (printf, 2, 3))); |
30 | #else | 30 | #else |
31 | #define xfs_debug(mp, fmt, ...) (0) | 31 | static inline void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) |
32 | { | ||
33 | } | ||
32 | #endif | 34 | #endif |
33 | 35 | ||
34 | extern void assfail(char *expr, char *f, int l); | 36 | extern void assfail(char *expr, char *f, int l); |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 1ba5c451da36..b38e58d02299 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( | |||
816 | return 0; | 816 | return 0; |
817 | } | 817 | } |
818 | 818 | ||
819 | /* | ||
820 | * XFS AIL push thread support | ||
821 | */ | ||
822 | void | ||
823 | xfsaild_wakeup( | ||
824 | struct xfs_ail *ailp, | ||
825 | xfs_lsn_t threshold_lsn) | ||
826 | { | ||
827 | /* only ever move the target forwards */ | ||
828 | if (XFS_LSN_CMP(threshold_lsn, ailp->xa_target) > 0) { | ||
829 | ailp->xa_target = threshold_lsn; | ||
830 | wake_up_process(ailp->xa_task); | ||
831 | } | ||
832 | } | ||
833 | |||
834 | STATIC int | ||
835 | xfsaild( | ||
836 | void *data) | ||
837 | { | ||
838 | struct xfs_ail *ailp = data; | ||
839 | xfs_lsn_t last_pushed_lsn = 0; | ||
840 | long tout = 0; /* milliseconds */ | ||
841 | |||
842 | while (!kthread_should_stop()) { | ||
843 | /* | ||
844 | * for short sleeps indicating congestion, don't allow us to | ||
845 | * get woken early. Otherwise all we do is bang on the AIL lock | ||
846 | * without making progress. | ||
847 | */ | ||
848 | if (tout && tout <= 20) | ||
849 | __set_current_state(TASK_KILLABLE); | ||
850 | else | ||
851 | __set_current_state(TASK_INTERRUPTIBLE); | ||
852 | schedule_timeout(tout ? | ||
853 | msecs_to_jiffies(tout) : MAX_SCHEDULE_TIMEOUT); | ||
854 | |||
855 | /* swsusp */ | ||
856 | try_to_freeze(); | ||
857 | |||
858 | ASSERT(ailp->xa_mount->m_log); | ||
859 | if (XFS_FORCED_SHUTDOWN(ailp->xa_mount)) | ||
860 | continue; | ||
861 | |||
862 | tout = xfsaild_push(ailp, &last_pushed_lsn); | ||
863 | } | ||
864 | |||
865 | return 0; | ||
866 | } /* xfsaild */ | ||
867 | |||
868 | int | ||
869 | xfsaild_start( | ||
870 | struct xfs_ail *ailp) | ||
871 | { | ||
872 | ailp->xa_target = 0; | ||
873 | ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s", | ||
874 | ailp->xa_mount->m_fsname); | ||
875 | if (IS_ERR(ailp->xa_task)) | ||
876 | return -PTR_ERR(ailp->xa_task); | ||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | void | ||
881 | xfsaild_stop( | ||
882 | struct xfs_ail *ailp) | ||
883 | { | ||
884 | kthread_stop(ailp->xa_task); | ||
885 | } | ||
886 | |||
887 | |||
888 | /* Catch misguided souls that try to use this interface on XFS */ | 819 | /* Catch misguided souls that try to use this interface on XFS */ |
889 | STATIC struct inode * | 820 | STATIC struct inode * |
890 | xfs_fs_alloc_inode( | 821 | xfs_fs_alloc_inode( |
@@ -1191,22 +1122,12 @@ xfs_fs_sync_fs( | |||
1191 | return -error; | 1122 | return -error; |
1192 | 1123 | ||
1193 | if (laptop_mode) { | 1124 | if (laptop_mode) { |
1194 | int prev_sync_seq = mp->m_sync_seq; | ||
1195 | |||
1196 | /* | 1125 | /* |
1197 | * The disk must be active because we're syncing. | 1126 | * The disk must be active because we're syncing. |
1198 | * We schedule xfssyncd now (now that the disk is | 1127 | * We schedule xfssyncd now (now that the disk is |
1199 | * active) instead of later (when it might not be). | 1128 | * active) instead of later (when it might not be). |
1200 | */ | 1129 | */ |
1201 | wake_up_process(mp->m_sync_task); | 1130 | flush_delayed_work_sync(&mp->m_sync_work); |
1202 | /* | ||
1203 | * We have to wait for the sync iteration to complete. | ||
1204 | * If we don't, the disk activity caused by the sync | ||
1205 | * will come after the sync is completed, and that | ||
1206 | * triggers another sync from laptop mode. | ||
1207 | */ | ||
1208 | wait_event(mp->m_wait_single_sync_task, | ||
1209 | mp->m_sync_seq != prev_sync_seq); | ||
1210 | } | 1131 | } |
1211 | 1132 | ||
1212 | return 0; | 1133 | return 0; |
@@ -1490,9 +1411,6 @@ xfs_fs_fill_super( | |||
1490 | spin_lock_init(&mp->m_sb_lock); | 1411 | spin_lock_init(&mp->m_sb_lock); |
1491 | mutex_init(&mp->m_growlock); | 1412 | mutex_init(&mp->m_growlock); |
1492 | atomic_set(&mp->m_active_trans, 0); | 1413 | atomic_set(&mp->m_active_trans, 0); |
1493 | INIT_LIST_HEAD(&mp->m_sync_list); | ||
1494 | spin_lock_init(&mp->m_sync_lock); | ||
1495 | init_waitqueue_head(&mp->m_wait_single_sync_task); | ||
1496 | 1414 | ||
1497 | mp->m_super = sb; | 1415 | mp->m_super = sb; |
1498 | sb->s_fs_info = mp; | 1416 | sb->s_fs_info = mp; |
@@ -1799,6 +1717,38 @@ xfs_destroy_zones(void) | |||
1799 | } | 1717 | } |
1800 | 1718 | ||
1801 | STATIC int __init | 1719 | STATIC int __init |
1720 | xfs_init_workqueues(void) | ||
1721 | { | ||
1722 | /* | ||
1723 | * max_active is set to 8 to give enough concurency to allow | ||
1724 | * multiple work operations on each CPU to run. This allows multiple | ||
1725 | * filesystems to be running sync work concurrently, and scales with | ||
1726 | * the number of CPUs in the system. | ||
1727 | */ | ||
1728 | xfs_syncd_wq = alloc_workqueue("xfssyncd", WQ_CPU_INTENSIVE, 8); | ||
1729 | if (!xfs_syncd_wq) | ||
1730 | goto out; | ||
1731 | |||
1732 | xfs_ail_wq = alloc_workqueue("xfsail", WQ_CPU_INTENSIVE, 8); | ||
1733 | if (!xfs_ail_wq) | ||
1734 | goto out_destroy_syncd; | ||
1735 | |||
1736 | return 0; | ||
1737 | |||
1738 | out_destroy_syncd: | ||
1739 | destroy_workqueue(xfs_syncd_wq); | ||
1740 | out: | ||
1741 | return -ENOMEM; | ||
1742 | } | ||
1743 | |||
1744 | STATIC void | ||
1745 | xfs_destroy_workqueues(void) | ||
1746 | { | ||
1747 | destroy_workqueue(xfs_ail_wq); | ||
1748 | destroy_workqueue(xfs_syncd_wq); | ||
1749 | } | ||
1750 | |||
1751 | STATIC int __init | ||
1802 | init_xfs_fs(void) | 1752 | init_xfs_fs(void) |
1803 | { | 1753 | { |
1804 | int error; | 1754 | int error; |
@@ -1813,10 +1763,14 @@ init_xfs_fs(void) | |||
1813 | if (error) | 1763 | if (error) |
1814 | goto out; | 1764 | goto out; |
1815 | 1765 | ||
1816 | error = xfs_mru_cache_init(); | 1766 | error = xfs_init_workqueues(); |
1817 | if (error) | 1767 | if (error) |
1818 | goto out_destroy_zones; | 1768 | goto out_destroy_zones; |
1819 | 1769 | ||
1770 | error = xfs_mru_cache_init(); | ||
1771 | if (error) | ||
1772 | goto out_destroy_wq; | ||
1773 | |||
1820 | error = xfs_filestream_init(); | 1774 | error = xfs_filestream_init(); |
1821 | if (error) | 1775 | if (error) |
1822 | goto out_mru_cache_uninit; | 1776 | goto out_mru_cache_uninit; |
@@ -1833,6 +1787,10 @@ init_xfs_fs(void) | |||
1833 | if (error) | 1787 | if (error) |
1834 | goto out_cleanup_procfs; | 1788 | goto out_cleanup_procfs; |
1835 | 1789 | ||
1790 | error = xfs_init_workqueues(); | ||
1791 | if (error) | ||
1792 | goto out_sysctl_unregister; | ||
1793 | |||
1836 | vfs_initquota(); | 1794 | vfs_initquota(); |
1837 | 1795 | ||
1838 | error = register_filesystem(&xfs_fs_type); | 1796 | error = register_filesystem(&xfs_fs_type); |
@@ -1850,6 +1808,8 @@ init_xfs_fs(void) | |||
1850 | xfs_filestream_uninit(); | 1808 | xfs_filestream_uninit(); |
1851 | out_mru_cache_uninit: | 1809 | out_mru_cache_uninit: |
1852 | xfs_mru_cache_uninit(); | 1810 | xfs_mru_cache_uninit(); |
1811 | out_destroy_wq: | ||
1812 | xfs_destroy_workqueues(); | ||
1853 | out_destroy_zones: | 1813 | out_destroy_zones: |
1854 | xfs_destroy_zones(); | 1814 | xfs_destroy_zones(); |
1855 | out: | 1815 | out: |
@@ -1866,6 +1826,7 @@ exit_xfs_fs(void) | |||
1866 | xfs_buf_terminate(); | 1826 | xfs_buf_terminate(); |
1867 | xfs_filestream_uninit(); | 1827 | xfs_filestream_uninit(); |
1868 | xfs_mru_cache_uninit(); | 1828 | xfs_mru_cache_uninit(); |
1829 | xfs_destroy_workqueues(); | ||
1869 | xfs_destroy_zones(); | 1830 | xfs_destroy_zones(); |
1870 | } | 1831 | } |
1871 | 1832 | ||
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 9cf35a688f53..e4f9c1b0836c 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "xfs_log.h" | 22 | #include "xfs_log.h" |
23 | #include "xfs_inum.h" | 23 | #include "xfs_inum.h" |
24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
25 | #include "xfs_trans_priv.h" | ||
25 | #include "xfs_sb.h" | 26 | #include "xfs_sb.h" |
26 | #include "xfs_ag.h" | 27 | #include "xfs_ag.h" |
27 | #include "xfs_mount.h" | 28 | #include "xfs_mount.h" |
@@ -39,6 +40,8 @@ | |||
39 | #include <linux/kthread.h> | 40 | #include <linux/kthread.h> |
40 | #include <linux/freezer.h> | 41 | #include <linux/freezer.h> |
41 | 42 | ||
43 | struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */ | ||
44 | |||
42 | /* | 45 | /* |
43 | * The inode lookup is done in batches to keep the amount of lock traffic and | 46 | * The inode lookup is done in batches to keep the amount of lock traffic and |
44 | * radix tree lookups to a minimum. The batch size is a trade off between | 47 | * radix tree lookups to a minimum. The batch size is a trade off between |
@@ -431,62 +434,12 @@ xfs_quiesce_attr( | |||
431 | xfs_unmountfs_writesb(mp); | 434 | xfs_unmountfs_writesb(mp); |
432 | } | 435 | } |
433 | 436 | ||
434 | /* | 437 | static void |
435 | * Enqueue a work item to be picked up by the vfs xfssyncd thread. | 438 | xfs_syncd_queue_sync( |
436 | * Doing this has two advantages: | 439 | struct xfs_mount *mp) |
437 | * - It saves on stack space, which is tight in certain situations | ||
438 | * - It can be used (with care) as a mechanism to avoid deadlocks. | ||
439 | * Flushing while allocating in a full filesystem requires both. | ||
440 | */ | ||
441 | STATIC void | ||
442 | xfs_syncd_queue_work( | ||
443 | struct xfs_mount *mp, | ||
444 | void *data, | ||
445 | void (*syncer)(struct xfs_mount *, void *), | ||
446 | struct completion *completion) | ||
447 | { | ||
448 | struct xfs_sync_work *work; | ||
449 | |||
450 | work = kmem_alloc(sizeof(struct xfs_sync_work), KM_SLEEP); | ||
451 | INIT_LIST_HEAD(&work->w_list); | ||
452 | work->w_syncer = syncer; | ||
453 | work->w_data = data; | ||
454 | work->w_mount = mp; | ||
455 | work->w_completion = completion; | ||
456 | spin_lock(&mp->m_sync_lock); | ||
457 | list_add_tail(&work->w_list, &mp->m_sync_list); | ||
458 | spin_unlock(&mp->m_sync_lock); | ||
459 | wake_up_process(mp->m_sync_task); | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Flush delayed allocate data, attempting to free up reserved space | ||
464 | * from existing allocations. At this point a new allocation attempt | ||
465 | * has failed with ENOSPC and we are in the process of scratching our | ||
466 | * heads, looking about for more room... | ||
467 | */ | ||
468 | STATIC void | ||
469 | xfs_flush_inodes_work( | ||
470 | struct xfs_mount *mp, | ||
471 | void *arg) | ||
472 | { | ||
473 | struct inode *inode = arg; | ||
474 | xfs_sync_data(mp, SYNC_TRYLOCK); | ||
475 | xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT); | ||
476 | iput(inode); | ||
477 | } | ||
478 | |||
479 | void | ||
480 | xfs_flush_inodes( | ||
481 | xfs_inode_t *ip) | ||
482 | { | 440 | { |
483 | struct inode *inode = VFS_I(ip); | 441 | queue_delayed_work(xfs_syncd_wq, &mp->m_sync_work, |
484 | DECLARE_COMPLETION_ONSTACK(completion); | 442 | msecs_to_jiffies(xfs_syncd_centisecs * 10)); |
485 | |||
486 | igrab(inode); | ||
487 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inodes_work, &completion); | ||
488 | wait_for_completion(&completion); | ||
489 | xfs_log_force(ip->i_mount, XFS_LOG_SYNC); | ||
490 | } | 443 | } |
491 | 444 | ||
492 | /* | 445 | /* |
@@ -496,9 +449,10 @@ xfs_flush_inodes( | |||
496 | */ | 449 | */ |
497 | STATIC void | 450 | STATIC void |
498 | xfs_sync_worker( | 451 | xfs_sync_worker( |
499 | struct xfs_mount *mp, | 452 | struct work_struct *work) |
500 | void *unused) | ||
501 | { | 453 | { |
454 | struct xfs_mount *mp = container_of(to_delayed_work(work), | ||
455 | struct xfs_mount, m_sync_work); | ||
502 | int error; | 456 | int error; |
503 | 457 | ||
504 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { | 458 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { |
@@ -508,73 +462,106 @@ xfs_sync_worker( | |||
508 | error = xfs_fs_log_dummy(mp); | 462 | error = xfs_fs_log_dummy(mp); |
509 | else | 463 | else |
510 | xfs_log_force(mp, 0); | 464 | xfs_log_force(mp, 0); |
511 | xfs_reclaim_inodes(mp, 0); | ||
512 | error = xfs_qm_sync(mp, SYNC_TRYLOCK); | 465 | error = xfs_qm_sync(mp, SYNC_TRYLOCK); |
466 | |||
467 | /* start pushing all the metadata that is currently dirty */ | ||
468 | xfs_ail_push_all(mp->m_ail); | ||
513 | } | 469 | } |
514 | mp->m_sync_seq++; | 470 | |
515 | wake_up(&mp->m_wait_single_sync_task); | 471 | /* queue us up again */ |
472 | xfs_syncd_queue_sync(mp); | ||
516 | } | 473 | } |
517 | 474 | ||
518 | STATIC int | 475 | /* |
519 | xfssyncd( | 476 | * Queue a new inode reclaim pass if there are reclaimable inodes and there |
520 | void *arg) | 477 | * isn't a reclaim pass already in progress. By default it runs every 5s based |
478 | * on the xfs syncd work default of 30s. Perhaps this should have it's own | ||
479 | * tunable, but that can be done if this method proves to be ineffective or too | ||
480 | * aggressive. | ||
481 | */ | ||
482 | static void | ||
483 | xfs_syncd_queue_reclaim( | ||
484 | struct xfs_mount *mp) | ||
521 | { | 485 | { |
522 | struct xfs_mount *mp = arg; | ||
523 | long timeleft; | ||
524 | xfs_sync_work_t *work, *n; | ||
525 | LIST_HEAD (tmp); | ||
526 | |||
527 | set_freezable(); | ||
528 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); | ||
529 | for (;;) { | ||
530 | if (list_empty(&mp->m_sync_list)) | ||
531 | timeleft = schedule_timeout_interruptible(timeleft); | ||
532 | /* swsusp */ | ||
533 | try_to_freeze(); | ||
534 | if (kthread_should_stop() && list_empty(&mp->m_sync_list)) | ||
535 | break; | ||
536 | 486 | ||
537 | spin_lock(&mp->m_sync_lock); | 487 | /* |
538 | /* | 488 | * We can have inodes enter reclaim after we've shut down the syncd |
539 | * We can get woken by laptop mode, to do a sync - | 489 | * workqueue during unmount, so don't allow reclaim work to be queued |
540 | * that's the (only!) case where the list would be | 490 | * during unmount. |
541 | * empty with time remaining. | 491 | */ |
542 | */ | 492 | if (!(mp->m_super->s_flags & MS_ACTIVE)) |
543 | if (!timeleft || list_empty(&mp->m_sync_list)) { | 493 | return; |
544 | if (!timeleft) | ||
545 | timeleft = xfs_syncd_centisecs * | ||
546 | msecs_to_jiffies(10); | ||
547 | INIT_LIST_HEAD(&mp->m_sync_work.w_list); | ||
548 | list_add_tail(&mp->m_sync_work.w_list, | ||
549 | &mp->m_sync_list); | ||
550 | } | ||
551 | list_splice_init(&mp->m_sync_list, &tmp); | ||
552 | spin_unlock(&mp->m_sync_lock); | ||
553 | 494 | ||
554 | list_for_each_entry_safe(work, n, &tmp, w_list) { | 495 | rcu_read_lock(); |
555 | (*work->w_syncer)(mp, work->w_data); | 496 | if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) { |
556 | list_del(&work->w_list); | 497 | queue_delayed_work(xfs_syncd_wq, &mp->m_reclaim_work, |
557 | if (work == &mp->m_sync_work) | 498 | msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10)); |
558 | continue; | ||
559 | if (work->w_completion) | ||
560 | complete(work->w_completion); | ||
561 | kmem_free(work); | ||
562 | } | ||
563 | } | 499 | } |
500 | rcu_read_unlock(); | ||
501 | } | ||
564 | 502 | ||
565 | return 0; | 503 | /* |
504 | * This is a fast pass over the inode cache to try to get reclaim moving on as | ||
505 | * many inodes as possible in a short period of time. It kicks itself every few | ||
506 | * seconds, as well as being kicked by the inode cache shrinker when memory | ||
507 | * goes low. It scans as quickly as possible avoiding locked inodes or those | ||
508 | * already being flushed, and once done schedules a future pass. | ||
509 | */ | ||
510 | STATIC void | ||
511 | xfs_reclaim_worker( | ||
512 | struct work_struct *work) | ||
513 | { | ||
514 | struct xfs_mount *mp = container_of(to_delayed_work(work), | ||
515 | struct xfs_mount, m_reclaim_work); | ||
516 | |||
517 | xfs_reclaim_inodes(mp, SYNC_TRYLOCK); | ||
518 | xfs_syncd_queue_reclaim(mp); | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * Flush delayed allocate data, attempting to free up reserved space | ||
523 | * from existing allocations. At this point a new allocation attempt | ||
524 | * has failed with ENOSPC and we are in the process of scratching our | ||
525 | * heads, looking about for more room. | ||
526 | * | ||
527 | * Queue a new data flush if there isn't one already in progress and | ||
528 | * wait for completion of the flush. This means that we only ever have one | ||
529 | * inode flush in progress no matter how many ENOSPC events are occurring and | ||
530 | * so will prevent the system from bogging down due to every concurrent | ||
531 | * ENOSPC event scanning all the active inodes in the system for writeback. | ||
532 | */ | ||
533 | void | ||
534 | xfs_flush_inodes( | ||
535 | struct xfs_inode *ip) | ||
536 | { | ||
537 | struct xfs_mount *mp = ip->i_mount; | ||
538 | |||
539 | queue_work(xfs_syncd_wq, &mp->m_flush_work); | ||
540 | flush_work_sync(&mp->m_flush_work); | ||
541 | } | ||
542 | |||
543 | STATIC void | ||
544 | xfs_flush_worker( | ||
545 | struct work_struct *work) | ||
546 | { | ||
547 | struct xfs_mount *mp = container_of(work, | ||
548 | struct xfs_mount, m_flush_work); | ||
549 | |||
550 | xfs_sync_data(mp, SYNC_TRYLOCK); | ||
551 | xfs_sync_data(mp, SYNC_TRYLOCK | SYNC_WAIT); | ||
566 | } | 552 | } |
567 | 553 | ||
568 | int | 554 | int |
569 | xfs_syncd_init( | 555 | xfs_syncd_init( |
570 | struct xfs_mount *mp) | 556 | struct xfs_mount *mp) |
571 | { | 557 | { |
572 | mp->m_sync_work.w_syncer = xfs_sync_worker; | 558 | INIT_WORK(&mp->m_flush_work, xfs_flush_worker); |
573 | mp->m_sync_work.w_mount = mp; | 559 | INIT_DELAYED_WORK(&mp->m_sync_work, xfs_sync_worker); |
574 | mp->m_sync_work.w_completion = NULL; | 560 | INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker); |
575 | mp->m_sync_task = kthread_run(xfssyncd, mp, "xfssyncd/%s", mp->m_fsname); | 561 | |
576 | if (IS_ERR(mp->m_sync_task)) | 562 | xfs_syncd_queue_sync(mp); |
577 | return -PTR_ERR(mp->m_sync_task); | 563 | xfs_syncd_queue_reclaim(mp); |
564 | |||
578 | return 0; | 565 | return 0; |
579 | } | 566 | } |
580 | 567 | ||
@@ -582,7 +569,9 @@ void | |||
582 | xfs_syncd_stop( | 569 | xfs_syncd_stop( |
583 | struct xfs_mount *mp) | 570 | struct xfs_mount *mp) |
584 | { | 571 | { |
585 | kthread_stop(mp->m_sync_task); | 572 | cancel_delayed_work_sync(&mp->m_sync_work); |
573 | cancel_delayed_work_sync(&mp->m_reclaim_work); | ||
574 | cancel_work_sync(&mp->m_flush_work); | ||
586 | } | 575 | } |
587 | 576 | ||
588 | void | 577 | void |
@@ -601,6 +590,10 @@ __xfs_inode_set_reclaim_tag( | |||
601 | XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), | 590 | XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), |
602 | XFS_ICI_RECLAIM_TAG); | 591 | XFS_ICI_RECLAIM_TAG); |
603 | spin_unlock(&ip->i_mount->m_perag_lock); | 592 | spin_unlock(&ip->i_mount->m_perag_lock); |
593 | |||
594 | /* schedule periodic background inode reclaim */ | ||
595 | xfs_syncd_queue_reclaim(ip->i_mount); | ||
596 | |||
604 | trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno, | 597 | trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno, |
605 | -1, _RET_IP_); | 598 | -1, _RET_IP_); |
606 | } | 599 | } |
@@ -1017,7 +1010,13 @@ xfs_reclaim_inodes( | |||
1017 | } | 1010 | } |
1018 | 1011 | ||
1019 | /* | 1012 | /* |
1020 | * Shrinker infrastructure. | 1013 | * Inode cache shrinker. |
1014 | * | ||
1015 | * When called we make sure that there is a background (fast) inode reclaim in | ||
1016 | * progress, while we will throttle the speed of reclaim via doiing synchronous | ||
1017 | * reclaim of inodes. That means if we come across dirty inodes, we wait for | ||
1018 | * them to be cleaned, which we hope will not be very long due to the | ||
1019 | * background walker having already kicked the IO off on those dirty inodes. | ||
1021 | */ | 1020 | */ |
1022 | static int | 1021 | static int |
1023 | xfs_reclaim_inode_shrink( | 1022 | xfs_reclaim_inode_shrink( |
@@ -1032,10 +1031,15 @@ xfs_reclaim_inode_shrink( | |||
1032 | 1031 | ||
1033 | mp = container_of(shrink, struct xfs_mount, m_inode_shrink); | 1032 | mp = container_of(shrink, struct xfs_mount, m_inode_shrink); |
1034 | if (nr_to_scan) { | 1033 | if (nr_to_scan) { |
1034 | /* kick background reclaimer and push the AIL */ | ||
1035 | xfs_syncd_queue_reclaim(mp); | ||
1036 | xfs_ail_push_all(mp->m_ail); | ||
1037 | |||
1035 | if (!(gfp_mask & __GFP_FS)) | 1038 | if (!(gfp_mask & __GFP_FS)) |
1036 | return -1; | 1039 | return -1; |
1037 | 1040 | ||
1038 | xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK, &nr_to_scan); | 1041 | xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, |
1042 | &nr_to_scan); | ||
1039 | /* terminate if we don't exhaust the scan */ | 1043 | /* terminate if we don't exhaust the scan */ |
1040 | if (nr_to_scan > 0) | 1044 | if (nr_to_scan > 0) |
1041 | return -1; | 1045 | return -1; |
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 32ba6628290c..e3a6ad27415f 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 { | |||
32 | #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ | 32 | #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ |
33 | #define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */ | 33 | #define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */ |
34 | 34 | ||
35 | extern struct workqueue_struct *xfs_syncd_wq; /* sync workqueue */ | ||
36 | |||
35 | int xfs_syncd_init(struct xfs_mount *mp); | 37 | int xfs_syncd_init(struct xfs_mount *mp); |
36 | void xfs_syncd_stop(struct xfs_mount *mp); | 38 | void xfs_syncd_stop(struct xfs_mount *mp); |
37 | 39 | ||
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 254ee062bd7d..69228aa8605a 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
@@ -461,12 +461,10 @@ xfs_qm_dqflush_all( | |||
461 | struct xfs_quotainfo *q = mp->m_quotainfo; | 461 | struct xfs_quotainfo *q = mp->m_quotainfo; |
462 | int recl; | 462 | int recl; |
463 | struct xfs_dquot *dqp; | 463 | struct xfs_dquot *dqp; |
464 | int niters; | ||
465 | int error; | 464 | int error; |
466 | 465 | ||
467 | if (!q) | 466 | if (!q) |
468 | return 0; | 467 | return 0; |
469 | niters = 0; | ||
470 | again: | 468 | again: |
471 | mutex_lock(&q->qi_dqlist_lock); | 469 | mutex_lock(&q->qi_dqlist_lock); |
472 | list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) { | 470 | list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) { |
@@ -1314,14 +1312,9 @@ xfs_qm_dqiter_bufs( | |||
1314 | { | 1312 | { |
1315 | xfs_buf_t *bp; | 1313 | xfs_buf_t *bp; |
1316 | int error; | 1314 | int error; |
1317 | int notcommitted; | ||
1318 | int incr; | ||
1319 | int type; | 1315 | int type; |
1320 | 1316 | ||
1321 | ASSERT(blkcnt > 0); | 1317 | ASSERT(blkcnt > 0); |
1322 | notcommitted = 0; | ||
1323 | incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? | ||
1324 | XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; | ||
1325 | type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER : | 1318 | type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER : |
1326 | (flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP); | 1319 | (flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP); |
1327 | error = 0; | 1320 | error = 0; |
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index c9446f1c726d..567b29b9f1b3 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; | |||
65 | * block in the dquot/xqm code. | 65 | * block in the dquot/xqm code. |
66 | */ | 66 | */ |
67 | #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 | 67 | #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 |
68 | /* | ||
69 | * When doing a quotacheck, we log dquot clusters of this many FSBs at most | ||
70 | * in a single transaction. We don't want to ask for too huge a log reservation. | ||
71 | */ | ||
72 | #define XFS_QM_MAX_DQCLUSTER_LOGSZ 3 | ||
73 | 68 | ||
74 | typedef xfs_dqhash_t xfs_dqlist_t; | 69 | typedef xfs_dqhash_t xfs_dqlist_t; |
75 | 70 | ||
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 0d62a07b7fd8..2dadb15d5ca9 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( | |||
313 | { | 313 | { |
314 | int error; | 314 | int error; |
315 | uint qf; | 315 | uint qf; |
316 | uint accflags; | ||
317 | __int64_t sbflags; | 316 | __int64_t sbflags; |
318 | 317 | ||
319 | flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); | 318 | flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); |
320 | /* | 319 | /* |
321 | * Switching on quota accounting must be done at mount time. | 320 | * Switching on quota accounting must be done at mount time. |
322 | */ | 321 | */ |
323 | accflags = flags & XFS_ALL_QUOTA_ACCT; | ||
324 | flags &= ~(XFS_ALL_QUOTA_ACCT); | 322 | flags &= ~(XFS_ALL_QUOTA_ACCT); |
325 | 323 | ||
326 | sbflags = 0; | 324 | sbflags = 0; |
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4bc3c649aee4..27d64d752eab 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
@@ -2395,17 +2395,33 @@ xfs_free_extent( | |||
2395 | memset(&args, 0, sizeof(xfs_alloc_arg_t)); | 2395 | memset(&args, 0, sizeof(xfs_alloc_arg_t)); |
2396 | args.tp = tp; | 2396 | args.tp = tp; |
2397 | args.mp = tp->t_mountp; | 2397 | args.mp = tp->t_mountp; |
2398 | |||
2399 | /* | ||
2400 | * validate that the block number is legal - the enables us to detect | ||
2401 | * and handle a silent filesystem corruption rather than crashing. | ||
2402 | */ | ||
2398 | args.agno = XFS_FSB_TO_AGNO(args.mp, bno); | 2403 | args.agno = XFS_FSB_TO_AGNO(args.mp, bno); |
2399 | ASSERT(args.agno < args.mp->m_sb.sb_agcount); | 2404 | if (args.agno >= args.mp->m_sb.sb_agcount) |
2405 | return EFSCORRUPTED; | ||
2406 | |||
2400 | args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); | 2407 | args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); |
2408 | if (args.agbno >= args.mp->m_sb.sb_agblocks) | ||
2409 | return EFSCORRUPTED; | ||
2410 | |||
2401 | args.pag = xfs_perag_get(args.mp, args.agno); | 2411 | args.pag = xfs_perag_get(args.mp, args.agno); |
2402 | if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) | 2412 | ASSERT(args.pag); |
2413 | |||
2414 | error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); | ||
2415 | if (error) | ||
2403 | goto error0; | 2416 | goto error0; |
2404 | #ifdef DEBUG | 2417 | |
2405 | ASSERT(args.agbp != NULL); | 2418 | /* validate the extent size is legal now we have the agf locked */ |
2406 | ASSERT((args.agbno + len) <= | 2419 | if (args.agbno + len > |
2407 | be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)); | 2420 | be32_to_cpu(XFS_BUF_TO_AGF(args.agbp)->agf_length)) { |
2408 | #endif | 2421 | error = EFSCORRUPTED; |
2422 | goto error0; | ||
2423 | } | ||
2424 | |||
2409 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); | 2425 | error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0); |
2410 | error0: | 2426 | error0: |
2411 | xfs_perag_put(args.pag); | 2427 | xfs_perag_put(args.pag); |
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 46cc40131d4a..576fdfe81d60 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
@@ -198,6 +198,41 @@ xfs_inode_item_size( | |||
198 | } | 198 | } |
199 | 199 | ||
200 | /* | 200 | /* |
201 | * xfs_inode_item_format_extents - convert in-core extents to on-disk form | ||
202 | * | ||
203 | * For either the data or attr fork in extent format, we need to endian convert | ||
204 | * the in-core extent as we place them into the on-disk inode. In this case, we | ||
205 | * need to do this conversion before we write the extents into the log. Because | ||
206 | * we don't have the disk inode to write into here, we allocate a buffer and | ||
207 | * format the extents into it via xfs_iextents_copy(). We free the buffer in | ||
208 | * the unlock routine after the copy for the log has been made. | ||
209 | * | ||
210 | * In the case of the data fork, the in-core and on-disk fork sizes can be | ||
211 | * different due to delayed allocation extents. We only log on-disk extents | ||
212 | * here, so always use the physical fork size to determine the size of the | ||
213 | * buffer we need to allocate. | ||
214 | */ | ||
215 | STATIC void | ||
216 | xfs_inode_item_format_extents( | ||
217 | struct xfs_inode *ip, | ||
218 | struct xfs_log_iovec *vecp, | ||
219 | int whichfork, | ||
220 | int type) | ||
221 | { | ||
222 | xfs_bmbt_rec_t *ext_buffer; | ||
223 | |||
224 | ext_buffer = kmem_alloc(XFS_IFORK_SIZE(ip, whichfork), KM_SLEEP); | ||
225 | if (whichfork == XFS_DATA_FORK) | ||
226 | ip->i_itemp->ili_extents_buf = ext_buffer; | ||
227 | else | ||
228 | ip->i_itemp->ili_aextents_buf = ext_buffer; | ||
229 | |||
230 | vecp->i_addr = ext_buffer; | ||
231 | vecp->i_len = xfs_iextents_copy(ip, ext_buffer, whichfork); | ||
232 | vecp->i_type = type; | ||
233 | } | ||
234 | |||
235 | /* | ||
201 | * This is called to fill in the vector of log iovecs for the | 236 | * This is called to fill in the vector of log iovecs for the |
202 | * given inode log item. It fills the first item with an inode | 237 | * given inode log item. It fills the first item with an inode |
203 | * log format structure, the second with the on-disk inode structure, | 238 | * log format structure, the second with the on-disk inode structure, |
@@ -213,7 +248,6 @@ xfs_inode_item_format( | |||
213 | struct xfs_inode *ip = iip->ili_inode; | 248 | struct xfs_inode *ip = iip->ili_inode; |
214 | uint nvecs; | 249 | uint nvecs; |
215 | size_t data_bytes; | 250 | size_t data_bytes; |
216 | xfs_bmbt_rec_t *ext_buffer; | ||
217 | xfs_mount_t *mp; | 251 | xfs_mount_t *mp; |
218 | 252 | ||
219 | vecp->i_addr = &iip->ili_format; | 253 | vecp->i_addr = &iip->ili_format; |
@@ -320,22 +354,8 @@ xfs_inode_item_format( | |||
320 | } else | 354 | } else |
321 | #endif | 355 | #endif |
322 | { | 356 | { |
323 | /* | 357 | xfs_inode_item_format_extents(ip, vecp, |
324 | * There are delayed allocation extents | 358 | XFS_DATA_FORK, XLOG_REG_TYPE_IEXT); |
325 | * in the inode, or we need to convert | ||
326 | * the extents to on disk format. | ||
327 | * Use xfs_iextents_copy() | ||
328 | * to copy only the real extents into | ||
329 | * a separate buffer. We'll free the | ||
330 | * buffer in the unlock routine. | ||
331 | */ | ||
332 | ext_buffer = kmem_alloc(ip->i_df.if_bytes, | ||
333 | KM_SLEEP); | ||
334 | iip->ili_extents_buf = ext_buffer; | ||
335 | vecp->i_addr = ext_buffer; | ||
336 | vecp->i_len = xfs_iextents_copy(ip, ext_buffer, | ||
337 | XFS_DATA_FORK); | ||
338 | vecp->i_type = XLOG_REG_TYPE_IEXT; | ||
339 | } | 359 | } |
340 | ASSERT(vecp->i_len <= ip->i_df.if_bytes); | 360 | ASSERT(vecp->i_len <= ip->i_df.if_bytes); |
341 | iip->ili_format.ilf_dsize = vecp->i_len; | 361 | iip->ili_format.ilf_dsize = vecp->i_len; |
@@ -445,19 +465,12 @@ xfs_inode_item_format( | |||
445 | */ | 465 | */ |
446 | vecp->i_addr = ip->i_afp->if_u1.if_extents; | 466 | vecp->i_addr = ip->i_afp->if_u1.if_extents; |
447 | vecp->i_len = ip->i_afp->if_bytes; | 467 | vecp->i_len = ip->i_afp->if_bytes; |
468 | vecp->i_type = XLOG_REG_TYPE_IATTR_EXT; | ||
448 | #else | 469 | #else |
449 | ASSERT(iip->ili_aextents_buf == NULL); | 470 | ASSERT(iip->ili_aextents_buf == NULL); |
450 | /* | 471 | xfs_inode_item_format_extents(ip, vecp, |
451 | * Need to endian flip before logging | 472 | XFS_ATTR_FORK, XLOG_REG_TYPE_IATTR_EXT); |
452 | */ | ||
453 | ext_buffer = kmem_alloc(ip->i_afp->if_bytes, | ||
454 | KM_SLEEP); | ||
455 | iip->ili_aextents_buf = ext_buffer; | ||
456 | vecp->i_addr = ext_buffer; | ||
457 | vecp->i_len = xfs_iextents_copy(ip, ext_buffer, | ||
458 | XFS_ATTR_FORK); | ||
459 | #endif | 473 | #endif |
460 | vecp->i_type = XLOG_REG_TYPE_IATTR_EXT; | ||
461 | iip->ili_format.ilf_asize = vecp->i_len; | 474 | iip->ili_format.ilf_asize = vecp->i_len; |
462 | vecp++; | 475 | vecp++; |
463 | nvecs++; | 476 | nvecs++; |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index dc1882adaf54..751e94fe1f77 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -204,7 +204,6 @@ xfs_bulkstat( | |||
204 | xfs_agi_t *agi; /* agi header data */ | 204 | xfs_agi_t *agi; /* agi header data */ |
205 | xfs_agino_t agino; /* inode # in allocation group */ | 205 | xfs_agino_t agino; /* inode # in allocation group */ |
206 | xfs_agnumber_t agno; /* allocation group number */ | 206 | xfs_agnumber_t agno; /* allocation group number */ |
207 | xfs_daddr_t bno; /* inode cluster start daddr */ | ||
208 | int chunkidx; /* current index into inode chunk */ | 207 | int chunkidx; /* current index into inode chunk */ |
209 | int clustidx; /* current index into inode cluster */ | 208 | int clustidx; /* current index into inode cluster */ |
210 | xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ | 209 | xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ |
@@ -463,7 +462,6 @@ xfs_bulkstat( | |||
463 | mp->m_sb.sb_inopblog); | 462 | mp->m_sb.sb_inopblog); |
464 | } | 463 | } |
465 | ino = XFS_AGINO_TO_INO(mp, agno, agino); | 464 | ino = XFS_AGINO_TO_INO(mp, agno, agino); |
466 | bno = XFS_AGB_TO_DADDR(mp, agno, agbno); | ||
467 | /* | 465 | /* |
468 | * Skip if this inode is free. | 466 | * Skip if this inode is free. |
469 | */ | 467 | */ |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 25efa9b8a602..b612ce4520ae 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) | |||
761 | break; | 761 | break; |
762 | case XLOG_STATE_COVER_NEED: | 762 | case XLOG_STATE_COVER_NEED: |
763 | case XLOG_STATE_COVER_NEED2: | 763 | case XLOG_STATE_COVER_NEED2: |
764 | if (!xfs_trans_ail_tail(log->l_ailp) && | 764 | if (!xfs_ail_min_lsn(log->l_ailp) && |
765 | xlog_iclogs_empty(log)) { | 765 | xlog_iclogs_empty(log)) { |
766 | if (log->l_covered_state == XLOG_STATE_COVER_NEED) | 766 | if (log->l_covered_state == XLOG_STATE_COVER_NEED) |
767 | log->l_covered_state = XLOG_STATE_COVER_DONE; | 767 | log->l_covered_state = XLOG_STATE_COVER_DONE; |
@@ -801,7 +801,7 @@ xlog_assign_tail_lsn( | |||
801 | xfs_lsn_t tail_lsn; | 801 | xfs_lsn_t tail_lsn; |
802 | struct log *log = mp->m_log; | 802 | struct log *log = mp->m_log; |
803 | 803 | ||
804 | tail_lsn = xfs_trans_ail_tail(mp->m_ail); | 804 | tail_lsn = xfs_ail_min_lsn(mp->m_ail); |
805 | if (!tail_lsn) | 805 | if (!tail_lsn) |
806 | tail_lsn = atomic64_read(&log->l_last_sync_lsn); | 806 | tail_lsn = atomic64_read(&log->l_last_sync_lsn); |
807 | 807 | ||
@@ -1239,7 +1239,7 @@ xlog_grant_push_ail( | |||
1239 | * the filesystem is shutting down. | 1239 | * the filesystem is shutting down. |
1240 | */ | 1240 | */ |
1241 | if (!XLOG_FORCED_SHUTDOWN(log)) | 1241 | if (!XLOG_FORCED_SHUTDOWN(log)) |
1242 | xfs_trans_ail_push(log->l_ailp, threshold_lsn); | 1242 | xfs_ail_push(log->l_ailp, threshold_lsn); |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | /* | 1245 | /* |
@@ -3407,6 +3407,17 @@ xlog_verify_dest_ptr( | |||
3407 | xfs_emerg(log->l_mp, "%s: invalid ptr", __func__); | 3407 | xfs_emerg(log->l_mp, "%s: invalid ptr", __func__); |
3408 | } | 3408 | } |
3409 | 3409 | ||
3410 | /* | ||
3411 | * Check to make sure the grant write head didn't just over lap the tail. If | ||
3412 | * the cycles are the same, we can't be overlapping. Otherwise, make sure that | ||
3413 | * the cycles differ by exactly one and check the byte count. | ||
3414 | * | ||
3415 | * This check is run unlocked, so can give false positives. Rather than assert | ||
3416 | * on failures, use a warn-once flag and a panic tag to allow the admin to | ||
3417 | * determine if they want to panic the machine when such an error occurs. For | ||
3418 | * debug kernels this will have the same effect as using an assert but, unlinke | ||
3419 | * an assert, it can be turned off at runtime. | ||
3420 | */ | ||
3410 | STATIC void | 3421 | STATIC void |
3411 | xlog_verify_grant_tail( | 3422 | xlog_verify_grant_tail( |
3412 | struct log *log) | 3423 | struct log *log) |
@@ -3414,17 +3425,22 @@ xlog_verify_grant_tail( | |||
3414 | int tail_cycle, tail_blocks; | 3425 | int tail_cycle, tail_blocks; |
3415 | int cycle, space; | 3426 | int cycle, space; |
3416 | 3427 | ||
3417 | /* | ||
3418 | * Check to make sure the grant write head didn't just over lap the | ||
3419 | * tail. If the cycles are the same, we can't be overlapping. | ||
3420 | * Otherwise, make sure that the cycles differ by exactly one and | ||
3421 | * check the byte count. | ||
3422 | */ | ||
3423 | xlog_crack_grant_head(&log->l_grant_write_head, &cycle, &space); | 3428 | xlog_crack_grant_head(&log->l_grant_write_head, &cycle, &space); |
3424 | xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks); | 3429 | xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks); |
3425 | if (tail_cycle != cycle) { | 3430 | if (tail_cycle != cycle) { |
3426 | ASSERT(cycle - 1 == tail_cycle); | 3431 | if (cycle - 1 != tail_cycle && |
3427 | ASSERT(space <= BBTOB(tail_blocks)); | 3432 | !(log->l_flags & XLOG_TAIL_WARN)) { |
3433 | xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, | ||
3434 | "%s: cycle - 1 != tail_cycle", __func__); | ||
3435 | log->l_flags |= XLOG_TAIL_WARN; | ||
3436 | } | ||
3437 | |||
3438 | if (space > BBTOB(tail_blocks) && | ||
3439 | !(log->l_flags & XLOG_TAIL_WARN)) { | ||
3440 | xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, | ||
3441 | "%s: space > BBTOB(tail_blocks)", __func__); | ||
3442 | log->l_flags |= XLOG_TAIL_WARN; | ||
3443 | } | ||
3428 | } | 3444 | } |
3429 | } | 3445 | } |
3430 | 3446 | ||
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index ffae692c9832..5864850e9e34 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) | |||
144 | #define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ | 144 | #define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ |
145 | #define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being | 145 | #define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being |
146 | shutdown */ | 146 | shutdown */ |
147 | #define XLOG_TAIL_WARN 0x10 /* log tail verify warning issued */ | ||
147 | 148 | ||
148 | #ifdef __KERNEL__ | 149 | #ifdef __KERNEL__ |
149 | /* | 150 | /* |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index a62e8971539d..19af0ab0d0c6 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -203,12 +203,9 @@ typedef struct xfs_mount { | |||
203 | struct mutex m_icsb_mutex; /* balancer sync lock */ | 203 | struct mutex m_icsb_mutex; /* balancer sync lock */ |
204 | #endif | 204 | #endif |
205 | struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ | 205 | struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ |
206 | struct task_struct *m_sync_task; /* generalised sync thread */ | 206 | struct delayed_work m_sync_work; /* background sync work */ |
207 | xfs_sync_work_t m_sync_work; /* work item for VFS_SYNC */ | 207 | struct delayed_work m_reclaim_work; /* background inode reclaim */ |
208 | struct list_head m_sync_list; /* sync thread work item list */ | 208 | struct work_struct m_flush_work; /* background inode flush */ |
209 | spinlock_t m_sync_lock; /* work item list lock */ | ||
210 | int m_sync_seq; /* sync thread generation no. */ | ||
211 | wait_queue_head_t m_wait_single_sync_task; | ||
212 | __int64_t m_update_flags; /* sb flags we need to update | 209 | __int64_t m_update_flags; /* sb flags we need to update |
213 | on the next remount,rw */ | 210 | on the next remount,rw */ |
214 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ | 211 | struct shrinker m_inode_shrink; /* inode reclaim shrinker */ |
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 12aff9584e29..acdb92f14d51 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -28,74 +28,138 @@ | |||
28 | #include "xfs_trans_priv.h" | 28 | #include "xfs_trans_priv.h" |
29 | #include "xfs_error.h" | 29 | #include "xfs_error.h" |
30 | 30 | ||
31 | STATIC void xfs_ail_splice(struct xfs_ail *, struct list_head *, xfs_lsn_t); | 31 | struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */ |
32 | STATIC void xfs_ail_delete(struct xfs_ail *, xfs_log_item_t *); | ||
33 | STATIC xfs_log_item_t * xfs_ail_min(struct xfs_ail *); | ||
34 | STATIC xfs_log_item_t * xfs_ail_next(struct xfs_ail *, xfs_log_item_t *); | ||
35 | 32 | ||
36 | #ifdef DEBUG | 33 | #ifdef DEBUG |
37 | STATIC void xfs_ail_check(struct xfs_ail *, xfs_log_item_t *); | 34 | /* |
38 | #else | 35 | * Check that the list is sorted as it should be. |
36 | */ | ||
37 | STATIC void | ||
38 | xfs_ail_check( | ||
39 | struct xfs_ail *ailp, | ||
40 | xfs_log_item_t *lip) | ||
41 | { | ||
42 | xfs_log_item_t *prev_lip; | ||
43 | |||
44 | if (list_empty(&ailp->xa_ail)) | ||
45 | return; | ||
46 | |||
47 | /* | ||
48 | * Check the next and previous entries are valid. | ||
49 | */ | ||
50 | ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); | ||
51 | prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail); | ||
52 | if (&prev_lip->li_ail != &ailp->xa_ail) | ||
53 | ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); | ||
54 | |||
55 | prev_lip = list_entry(lip->li_ail.next, xfs_log_item_t, li_ail); | ||
56 | if (&prev_lip->li_ail != &ailp->xa_ail) | ||
57 | ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0); | ||
58 | |||
59 | |||
60 | #ifdef XFS_TRANS_DEBUG | ||
61 | /* | ||
62 | * Walk the list checking lsn ordering, and that every entry has the | ||
63 | * XFS_LI_IN_AIL flag set. This is really expensive, so only do it | ||
64 | * when specifically debugging the transaction subsystem. | ||
65 | */ | ||
66 | prev_lip = list_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); | ||
67 | list_for_each_entry(lip, &ailp->xa_ail, li_ail) { | ||
68 | if (&prev_lip->li_ail != &ailp->xa_ail) | ||
69 | ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); | ||
70 | ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); | ||
71 | prev_lip = lip; | ||
72 | } | ||
73 | #endif /* XFS_TRANS_DEBUG */ | ||
74 | } | ||
75 | #else /* !DEBUG */ | ||
39 | #define xfs_ail_check(a,l) | 76 | #define xfs_ail_check(a,l) |
40 | #endif /* DEBUG */ | 77 | #endif /* DEBUG */ |
41 | 78 | ||
79 | /* | ||
80 | * Return a pointer to the first item in the AIL. If the AIL is empty, then | ||
81 | * return NULL. | ||
82 | */ | ||
83 | static xfs_log_item_t * | ||
84 | xfs_ail_min( | ||
85 | struct xfs_ail *ailp) | ||
86 | { | ||
87 | if (list_empty(&ailp->xa_ail)) | ||
88 | return NULL; | ||
89 | |||
90 | return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Return a pointer to the last item in the AIL. If the AIL is empty, then | ||
95 | * return NULL. | ||
96 | */ | ||
97 | static xfs_log_item_t * | ||
98 | xfs_ail_max( | ||
99 | struct xfs_ail *ailp) | ||
100 | { | ||
101 | if (list_empty(&ailp->xa_ail)) | ||
102 | return NULL; | ||
103 | |||
104 | return list_entry(ailp->xa_ail.prev, xfs_log_item_t, li_ail); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Return a pointer to the item which follows the given item in the AIL. If | ||
109 | * the given item is the last item in the list, then return NULL. | ||
110 | */ | ||
111 | static xfs_log_item_t * | ||
112 | xfs_ail_next( | ||
113 | struct xfs_ail *ailp, | ||
114 | xfs_log_item_t *lip) | ||
115 | { | ||
116 | if (lip->li_ail.next == &ailp->xa_ail) | ||
117 | return NULL; | ||
118 | |||
119 | return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail); | ||
120 | } | ||
42 | 121 | ||
43 | /* | 122 | /* |
44 | * This is called by the log manager code to determine the LSN | 123 | * This is called by the log manager code to determine the LSN of the tail of |
45 | * of the tail of the log. This is exactly the LSN of the first | 124 | * the log. This is exactly the LSN of the first item in the AIL. If the AIL |
46 | * item in the AIL. If the AIL is empty, then this function | 125 | * is empty, then this function returns 0. |
47 | * returns 0. | ||
48 | * | 126 | * |
49 | * We need the AIL lock in order to get a coherent read of the | 127 | * We need the AIL lock in order to get a coherent read of the lsn of the last |
50 | * lsn of the last item in the AIL. | 128 | * item in the AIL. |
51 | */ | 129 | */ |
52 | xfs_lsn_t | 130 | xfs_lsn_t |
53 | xfs_trans_ail_tail( | 131 | xfs_ail_min_lsn( |
54 | struct xfs_ail *ailp) | 132 | struct xfs_ail *ailp) |
55 | { | 133 | { |
56 | xfs_lsn_t lsn; | 134 | xfs_lsn_t lsn = 0; |
57 | xfs_log_item_t *lip; | 135 | xfs_log_item_t *lip; |
58 | 136 | ||
59 | spin_lock(&ailp->xa_lock); | 137 | spin_lock(&ailp->xa_lock); |
60 | lip = xfs_ail_min(ailp); | 138 | lip = xfs_ail_min(ailp); |
61 | if (lip == NULL) { | 139 | if (lip) |
62 | lsn = (xfs_lsn_t)0; | ||
63 | } else { | ||
64 | lsn = lip->li_lsn; | 140 | lsn = lip->li_lsn; |
65 | } | ||
66 | spin_unlock(&ailp->xa_lock); | 141 | spin_unlock(&ailp->xa_lock); |
67 | 142 | ||
68 | return lsn; | 143 | return lsn; |
69 | } | 144 | } |
70 | 145 | ||
71 | /* | 146 | /* |
72 | * xfs_trans_push_ail | 147 | * Return the maximum lsn held in the AIL, or zero if the AIL is empty. |
73 | * | ||
74 | * This routine is called to move the tail of the AIL forward. It does this by | ||
75 | * trying to flush items in the AIL whose lsns are below the given | ||
76 | * threshold_lsn. | ||
77 | * | ||
78 | * the push is run asynchronously in a separate thread, so we return the tail | ||
79 | * of the log right now instead of the tail after the push. This means we will | ||
80 | * either continue right away, or we will sleep waiting on the async thread to | ||
81 | * do its work. | ||
82 | * | ||
83 | * We do this unlocked - we only need to know whether there is anything in the | ||
84 | * AIL at the time we are called. We don't need to access the contents of | ||
85 | * any of the objects, so the lock is not needed. | ||
86 | */ | 148 | */ |
87 | void | 149 | static xfs_lsn_t |
88 | xfs_trans_ail_push( | 150 | xfs_ail_max_lsn( |
89 | struct xfs_ail *ailp, | 151 | struct xfs_ail *ailp) |
90 | xfs_lsn_t threshold_lsn) | ||
91 | { | 152 | { |
92 | xfs_log_item_t *lip; | 153 | xfs_lsn_t lsn = 0; |
154 | xfs_log_item_t *lip; | ||
93 | 155 | ||
94 | lip = xfs_ail_min(ailp); | 156 | spin_lock(&ailp->xa_lock); |
95 | if (lip && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) { | 157 | lip = xfs_ail_max(ailp); |
96 | if (XFS_LSN_CMP(threshold_lsn, ailp->xa_target) > 0) | 158 | if (lip) |
97 | xfsaild_wakeup(ailp, threshold_lsn); | 159 | lsn = lip->li_lsn; |
98 | } | 160 | spin_unlock(&ailp->xa_lock); |
161 | |||
162 | return lsn; | ||
99 | } | 163 | } |
100 | 164 | ||
101 | /* | 165 | /* |
@@ -236,16 +300,57 @@ out: | |||
236 | } | 300 | } |
237 | 301 | ||
238 | /* | 302 | /* |
239 | * xfsaild_push does the work of pushing on the AIL. Returning a timeout of | 303 | * splice the log item list into the AIL at the given LSN. |
240 | * zero indicates that the caller should sleep until woken. | ||
241 | */ | 304 | */ |
242 | long | 305 | static void |
243 | xfsaild_push( | 306 | xfs_ail_splice( |
244 | struct xfs_ail *ailp, | 307 | struct xfs_ail *ailp, |
245 | xfs_lsn_t *last_lsn) | 308 | struct list_head *list, |
309 | xfs_lsn_t lsn) | ||
246 | { | 310 | { |
247 | long tout = 0; | 311 | xfs_log_item_t *next_lip; |
248 | xfs_lsn_t last_pushed_lsn = *last_lsn; | 312 | |
313 | /* If the list is empty, just insert the item. */ | ||
314 | if (list_empty(&ailp->xa_ail)) { | ||
315 | list_splice(list, &ailp->xa_ail); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) { | ||
320 | if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0) | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | ASSERT(&next_lip->li_ail == &ailp->xa_ail || | ||
325 | XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0); | ||
326 | |||
327 | list_splice_init(list, &next_lip->li_ail); | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * Delete the given item from the AIL. Return a pointer to the item. | ||
332 | */ | ||
333 | static void | ||
334 | xfs_ail_delete( | ||
335 | struct xfs_ail *ailp, | ||
336 | xfs_log_item_t *lip) | ||
337 | { | ||
338 | xfs_ail_check(ailp, lip); | ||
339 | list_del(&lip->li_ail); | ||
340 | xfs_trans_ail_cursor_clear(ailp, lip); | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * xfs_ail_worker does the work of pushing on the AIL. It will requeue itself | ||
345 | * to run at a later time if there is more work to do to complete the push. | ||
346 | */ | ||
347 | STATIC void | ||
348 | xfs_ail_worker( | ||
349 | struct work_struct *work) | ||
350 | { | ||
351 | struct xfs_ail *ailp = container_of(to_delayed_work(work), | ||
352 | struct xfs_ail, xa_work); | ||
353 | long tout; | ||
249 | xfs_lsn_t target = ailp->xa_target; | 354 | xfs_lsn_t target = ailp->xa_target; |
250 | xfs_lsn_t lsn; | 355 | xfs_lsn_t lsn; |
251 | xfs_log_item_t *lip; | 356 | xfs_log_item_t *lip; |
@@ -256,15 +361,15 @@ xfsaild_push( | |||
256 | 361 | ||
257 | spin_lock(&ailp->xa_lock); | 362 | spin_lock(&ailp->xa_lock); |
258 | xfs_trans_ail_cursor_init(ailp, cur); | 363 | xfs_trans_ail_cursor_init(ailp, cur); |
259 | lip = xfs_trans_ail_cursor_first(ailp, cur, *last_lsn); | 364 | lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn); |
260 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { | 365 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { |
261 | /* | 366 | /* |
262 | * AIL is empty or our push has reached the end. | 367 | * AIL is empty or our push has reached the end. |
263 | */ | 368 | */ |
264 | xfs_trans_ail_cursor_done(ailp, cur); | 369 | xfs_trans_ail_cursor_done(ailp, cur); |
265 | spin_unlock(&ailp->xa_lock); | 370 | spin_unlock(&ailp->xa_lock); |
266 | *last_lsn = 0; | 371 | ailp->xa_last_pushed_lsn = 0; |
267 | return tout; | 372 | return; |
268 | } | 373 | } |
269 | 374 | ||
270 | XFS_STATS_INC(xs_push_ail); | 375 | XFS_STATS_INC(xs_push_ail); |
@@ -301,13 +406,13 @@ xfsaild_push( | |||
301 | case XFS_ITEM_SUCCESS: | 406 | case XFS_ITEM_SUCCESS: |
302 | XFS_STATS_INC(xs_push_ail_success); | 407 | XFS_STATS_INC(xs_push_ail_success); |
303 | IOP_PUSH(lip); | 408 | IOP_PUSH(lip); |
304 | last_pushed_lsn = lsn; | 409 | ailp->xa_last_pushed_lsn = lsn; |
305 | break; | 410 | break; |
306 | 411 | ||
307 | case XFS_ITEM_PUSHBUF: | 412 | case XFS_ITEM_PUSHBUF: |
308 | XFS_STATS_INC(xs_push_ail_pushbuf); | 413 | XFS_STATS_INC(xs_push_ail_pushbuf); |
309 | IOP_PUSHBUF(lip); | 414 | IOP_PUSHBUF(lip); |
310 | last_pushed_lsn = lsn; | 415 | ailp->xa_last_pushed_lsn = lsn; |
311 | push_xfsbufd = 1; | 416 | push_xfsbufd = 1; |
312 | break; | 417 | break; |
313 | 418 | ||
@@ -319,7 +424,7 @@ xfsaild_push( | |||
319 | 424 | ||
320 | case XFS_ITEM_LOCKED: | 425 | case XFS_ITEM_LOCKED: |
321 | XFS_STATS_INC(xs_push_ail_locked); | 426 | XFS_STATS_INC(xs_push_ail_locked); |
322 | last_pushed_lsn = lsn; | 427 | ailp->xa_last_pushed_lsn = lsn; |
323 | stuck++; | 428 | stuck++; |
324 | break; | 429 | break; |
325 | 430 | ||
@@ -374,9 +479,23 @@ xfsaild_push( | |||
374 | wake_up_process(mp->m_ddev_targp->bt_task); | 479 | wake_up_process(mp->m_ddev_targp->bt_task); |
375 | } | 480 | } |
376 | 481 | ||
482 | /* assume we have more work to do in a short while */ | ||
483 | tout = 10; | ||
377 | if (!count) { | 484 | if (!count) { |
378 | /* We're past our target or empty, so idle */ | 485 | /* We're past our target or empty, so idle */ |
379 | last_pushed_lsn = 0; | 486 | ailp->xa_last_pushed_lsn = 0; |
487 | |||
488 | /* | ||
489 | * Check for an updated push target before clearing the | ||
490 | * XFS_AIL_PUSHING_BIT. If the target changed, we've got more | ||
491 | * work to do. Wait a bit longer before starting that work. | ||
492 | */ | ||
493 | smp_rmb(); | ||
494 | if (ailp->xa_target == target) { | ||
495 | clear_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags); | ||
496 | return; | ||
497 | } | ||
498 | tout = 50; | ||
380 | } else if (XFS_LSN_CMP(lsn, target) >= 0) { | 499 | } else if (XFS_LSN_CMP(lsn, target) >= 0) { |
381 | /* | 500 | /* |
382 | * We reached the target so wait a bit longer for I/O to | 501 | * We reached the target so wait a bit longer for I/O to |
@@ -384,7 +503,7 @@ xfsaild_push( | |||
384 | * start the next scan from the start of the AIL. | 503 | * start the next scan from the start of the AIL. |
385 | */ | 504 | */ |
386 | tout = 50; | 505 | tout = 50; |
387 | last_pushed_lsn = 0; | 506 | ailp->xa_last_pushed_lsn = 0; |
388 | } else if ((stuck * 100) / count > 90) { | 507 | } else if ((stuck * 100) / count > 90) { |
389 | /* | 508 | /* |
390 | * Either there is a lot of contention on the AIL or we | 509 | * Either there is a lot of contention on the AIL or we |
@@ -396,14 +515,61 @@ xfsaild_push( | |||
396 | * continuing from where we were. | 515 | * continuing from where we were. |
397 | */ | 516 | */ |
398 | tout = 20; | 517 | tout = 20; |
399 | } else { | ||
400 | /* more to do, but wait a short while before continuing */ | ||
401 | tout = 10; | ||
402 | } | 518 | } |
403 | *last_lsn = last_pushed_lsn; | 519 | |
404 | return tout; | 520 | /* There is more to do, requeue us. */ |
521 | queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, | ||
522 | msecs_to_jiffies(tout)); | ||
523 | } | ||
524 | |||
525 | /* | ||
526 | * This routine is called to move the tail of the AIL forward. It does this by | ||
527 | * trying to flush items in the AIL whose lsns are below the given | ||
528 | * threshold_lsn. | ||
529 | * | ||
530 | * The push is run asynchronously in a workqueue, which means the caller needs | ||
531 | * to handle waiting on the async flush for space to become available. | ||
532 | * We don't want to interrupt any push that is in progress, hence we only queue | ||
533 | * work if we set the pushing bit approriately. | ||
534 | * | ||
535 | * We do this unlocked - we only need to know whether there is anything in the | ||
536 | * AIL at the time we are called. We don't need to access the contents of | ||
537 | * any of the objects, so the lock is not needed. | ||
538 | */ | ||
539 | void | ||
540 | xfs_ail_push( | ||
541 | struct xfs_ail *ailp, | ||
542 | xfs_lsn_t threshold_lsn) | ||
543 | { | ||
544 | xfs_log_item_t *lip; | ||
545 | |||
546 | lip = xfs_ail_min(ailp); | ||
547 | if (!lip || XFS_FORCED_SHUTDOWN(ailp->xa_mount) || | ||
548 | XFS_LSN_CMP(threshold_lsn, ailp->xa_target) <= 0) | ||
549 | return; | ||
550 | |||
551 | /* | ||
552 | * Ensure that the new target is noticed in push code before it clears | ||
553 | * the XFS_AIL_PUSHING_BIT. | ||
554 | */ | ||
555 | smp_wmb(); | ||
556 | ailp->xa_target = threshold_lsn; | ||
557 | if (!test_and_set_bit(XFS_AIL_PUSHING_BIT, &ailp->xa_flags)) | ||
558 | queue_delayed_work(xfs_syncd_wq, &ailp->xa_work, 0); | ||
405 | } | 559 | } |
406 | 560 | ||
561 | /* | ||
562 | * Push out all items in the AIL immediately | ||
563 | */ | ||
564 | void | ||
565 | xfs_ail_push_all( | ||
566 | struct xfs_ail *ailp) | ||
567 | { | ||
568 | xfs_lsn_t threshold_lsn = xfs_ail_max_lsn(ailp); | ||
569 | |||
570 | if (threshold_lsn) | ||
571 | xfs_ail_push(ailp, threshold_lsn); | ||
572 | } | ||
407 | 573 | ||
408 | /* | 574 | /* |
409 | * This is to be called when an item is unlocked that may have | 575 | * This is to be called when an item is unlocked that may have |
@@ -615,7 +781,6 @@ xfs_trans_ail_init( | |||
615 | xfs_mount_t *mp) | 781 | xfs_mount_t *mp) |
616 | { | 782 | { |
617 | struct xfs_ail *ailp; | 783 | struct xfs_ail *ailp; |
618 | int error; | ||
619 | 784 | ||
620 | ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL); | 785 | ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL); |
621 | if (!ailp) | 786 | if (!ailp) |
@@ -624,15 +789,9 @@ xfs_trans_ail_init( | |||
624 | ailp->xa_mount = mp; | 789 | ailp->xa_mount = mp; |
625 | INIT_LIST_HEAD(&ailp->xa_ail); | 790 | INIT_LIST_HEAD(&ailp->xa_ail); |
626 | spin_lock_init(&ailp->xa_lock); | 791 | spin_lock_init(&ailp->xa_lock); |
627 | error = xfsaild_start(ailp); | 792 | INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker); |
628 | if (error) | ||
629 | goto out_free_ailp; | ||
630 | mp->m_ail = ailp; | 793 | mp->m_ail = ailp; |
631 | return 0; | 794 | return 0; |
632 | |||
633 | out_free_ailp: | ||
634 | kmem_free(ailp); | ||
635 | return error; | ||
636 | } | 795 | } |
637 | 796 | ||
638 | void | 797 | void |
@@ -641,124 +800,6 @@ xfs_trans_ail_destroy( | |||
641 | { | 800 | { |
642 | struct xfs_ail *ailp = mp->m_ail; | 801 | struct xfs_ail *ailp = mp->m_ail; |
643 | 802 | ||
644 | xfsaild_stop(ailp); | 803 | cancel_delayed_work_sync(&ailp->xa_work); |
645 | kmem_free(ailp); | 804 | kmem_free(ailp); |
646 | } | 805 | } |
647 | |||
648 | /* | ||
649 | * splice the log item list into the AIL at the given LSN. | ||
650 | */ | ||
651 | STATIC void | ||
652 | xfs_ail_splice( | ||
653 | struct xfs_ail *ailp, | ||
654 | struct list_head *list, | ||
655 | xfs_lsn_t lsn) | ||
656 | { | ||
657 | xfs_log_item_t *next_lip; | ||
658 | |||
659 | /* | ||
660 | * If the list is empty, just insert the item. | ||
661 | */ | ||
662 | if (list_empty(&ailp->xa_ail)) { | ||
663 | list_splice(list, &ailp->xa_ail); | ||
664 | return; | ||
665 | } | ||
666 | |||
667 | list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) { | ||
668 | if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0) | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | ASSERT((&next_lip->li_ail == &ailp->xa_ail) || | ||
673 | (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0)); | ||
674 | |||
675 | list_splice_init(list, &next_lip->li_ail); | ||
676 | return; | ||
677 | } | ||
678 | |||
679 | /* | ||
680 | * Delete the given item from the AIL. Return a pointer to the item. | ||
681 | */ | ||
682 | STATIC void | ||
683 | xfs_ail_delete( | ||
684 | struct xfs_ail *ailp, | ||
685 | xfs_log_item_t *lip) | ||
686 | { | ||
687 | xfs_ail_check(ailp, lip); | ||
688 | list_del(&lip->li_ail); | ||
689 | xfs_trans_ail_cursor_clear(ailp, lip); | ||
690 | } | ||
691 | |||
692 | /* | ||
693 | * Return a pointer to the first item in the AIL. | ||
694 | * If the AIL is empty, then return NULL. | ||
695 | */ | ||
696 | STATIC xfs_log_item_t * | ||
697 | xfs_ail_min( | ||
698 | struct xfs_ail *ailp) | ||
699 | { | ||
700 | if (list_empty(&ailp->xa_ail)) | ||
701 | return NULL; | ||
702 | |||
703 | return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); | ||
704 | } | ||
705 | |||
706 | /* | ||
707 | * Return a pointer to the item which follows | ||
708 | * the given item in the AIL. If the given item | ||
709 | * is the last item in the list, then return NULL. | ||
710 | */ | ||
711 | STATIC xfs_log_item_t * | ||
712 | xfs_ail_next( | ||
713 | struct xfs_ail *ailp, | ||
714 | xfs_log_item_t *lip) | ||
715 | { | ||
716 | if (lip->li_ail.next == &ailp->xa_ail) | ||
717 | return NULL; | ||
718 | |||
719 | return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail); | ||
720 | } | ||
721 | |||
722 | #ifdef DEBUG | ||
723 | /* | ||
724 | * Check that the list is sorted as it should be. | ||
725 | */ | ||
726 | STATIC void | ||
727 | xfs_ail_check( | ||
728 | struct xfs_ail *ailp, | ||
729 | xfs_log_item_t *lip) | ||
730 | { | ||
731 | xfs_log_item_t *prev_lip; | ||
732 | |||
733 | if (list_empty(&ailp->xa_ail)) | ||
734 | return; | ||
735 | |||
736 | /* | ||
737 | * Check the next and previous entries are valid. | ||
738 | */ | ||
739 | ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); | ||
740 | prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail); | ||
741 | if (&prev_lip->li_ail != &ailp->xa_ail) | ||
742 | ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); | ||
743 | |||
744 | prev_lip = list_entry(lip->li_ail.next, xfs_log_item_t, li_ail); | ||
745 | if (&prev_lip->li_ail != &ailp->xa_ail) | ||
746 | ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0); | ||
747 | |||
748 | |||
749 | #ifdef XFS_TRANS_DEBUG | ||
750 | /* | ||
751 | * Walk the list checking lsn ordering, and that every entry has the | ||
752 | * XFS_LI_IN_AIL flag set. This is really expensive, so only do it | ||
753 | * when specifically debugging the transaction subsystem. | ||
754 | */ | ||
755 | prev_lip = list_entry(&ailp->xa_ail, xfs_log_item_t, li_ail); | ||
756 | list_for_each_entry(lip, &ailp->xa_ail, li_ail) { | ||
757 | if (&prev_lip->li_ail != &ailp->xa_ail) | ||
758 | ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); | ||
759 | ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); | ||
760 | prev_lip = lip; | ||
761 | } | ||
762 | #endif /* XFS_TRANS_DEBUG */ | ||
763 | } | ||
764 | #endif /* DEBUG */ | ||
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index 35162c238fa3..6b164e9e9a1f 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h | |||
@@ -65,16 +65,22 @@ struct xfs_ail_cursor { | |||
65 | struct xfs_ail { | 65 | struct xfs_ail { |
66 | struct xfs_mount *xa_mount; | 66 | struct xfs_mount *xa_mount; |
67 | struct list_head xa_ail; | 67 | struct list_head xa_ail; |
68 | uint xa_gen; | ||
69 | struct task_struct *xa_task; | ||
70 | xfs_lsn_t xa_target; | 68 | xfs_lsn_t xa_target; |
71 | struct xfs_ail_cursor xa_cursors; | 69 | struct xfs_ail_cursor xa_cursors; |
72 | spinlock_t xa_lock; | 70 | spinlock_t xa_lock; |
71 | struct delayed_work xa_work; | ||
72 | xfs_lsn_t xa_last_pushed_lsn; | ||
73 | unsigned long xa_flags; | ||
73 | }; | 74 | }; |
74 | 75 | ||
76 | #define XFS_AIL_PUSHING_BIT 0 | ||
77 | |||
75 | /* | 78 | /* |
76 | * From xfs_trans_ail.c | 79 | * From xfs_trans_ail.c |
77 | */ | 80 | */ |
81 | |||
82 | extern struct workqueue_struct *xfs_ail_wq; /* AIL workqueue */ | ||
83 | |||
78 | void xfs_trans_ail_update_bulk(struct xfs_ail *ailp, | 84 | void xfs_trans_ail_update_bulk(struct xfs_ail *ailp, |
79 | struct xfs_log_item **log_items, int nr_items, | 85 | struct xfs_log_item **log_items, int nr_items, |
80 | xfs_lsn_t lsn) __releases(ailp->xa_lock); | 86 | xfs_lsn_t lsn) __releases(ailp->xa_lock); |
@@ -98,12 +104,13 @@ xfs_trans_ail_delete( | |||
98 | xfs_trans_ail_delete_bulk(ailp, &lip, 1); | 104 | xfs_trans_ail_delete_bulk(ailp, &lip, 1); |
99 | } | 105 | } |
100 | 106 | ||
101 | void xfs_trans_ail_push(struct xfs_ail *, xfs_lsn_t); | 107 | void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); |
108 | void xfs_ail_push_all(struct xfs_ail *); | ||
109 | xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp); | ||
110 | |||
102 | void xfs_trans_unlocked_item(struct xfs_ail *, | 111 | void xfs_trans_unlocked_item(struct xfs_ail *, |
103 | xfs_log_item_t *); | 112 | xfs_log_item_t *); |
104 | 113 | ||
105 | xfs_lsn_t xfs_trans_ail_tail(struct xfs_ail *ailp); | ||
106 | |||
107 | struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp, | 114 | struct xfs_log_item *xfs_trans_ail_cursor_first(struct xfs_ail *ailp, |
108 | struct xfs_ail_cursor *cur, | 115 | struct xfs_ail_cursor *cur, |
109 | xfs_lsn_t lsn); | 116 | xfs_lsn_t lsn); |
@@ -112,11 +119,6 @@ struct xfs_log_item *xfs_trans_ail_cursor_next(struct xfs_ail *ailp, | |||
112 | void xfs_trans_ail_cursor_done(struct xfs_ail *ailp, | 119 | void xfs_trans_ail_cursor_done(struct xfs_ail *ailp, |
113 | struct xfs_ail_cursor *cur); | 120 | struct xfs_ail_cursor *cur); |
114 | 121 | ||
115 | long xfsaild_push(struct xfs_ail *, xfs_lsn_t *); | ||
116 | void xfsaild_wakeup(struct xfs_ail *, xfs_lsn_t); | ||
117 | int xfsaild_start(struct xfs_ail *); | ||
118 | void xfsaild_stop(struct xfs_ail *); | ||
119 | |||
120 | #if BITS_PER_LONG != 64 | 122 | #if BITS_PER_LONG != 64 |
121 | static inline void | 123 | static inline void |
122 | xfs_trans_ail_copy_lsn( | 124 | xfs_trans_ail_copy_lsn( |
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index ad1b19aa6508..aef23309a742 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, | |||
86 | */ | 86 | */ |
87 | static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev) | 87 | static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev) |
88 | { | 88 | { |
89 | return pdev->dev.platform_data; | 89 | return pdev->mfd_cell; |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * Given a platform device that's been created by mfd_add_devices(), fetch | 93 | * Given a platform device that's been created by mfd_add_devices(), fetch |
94 | * the .mfd_data entry from the mfd_cell that created it. | 94 | * the .mfd_data entry from the mfd_cell that created it. |
95 | * Otherwise just return the platform_data pointer. | ||
96 | * This maintains compatibility with platform drivers whose devices aren't | ||
97 | * created by the mfd layer, and expect platform_data to contain what would've | ||
98 | * otherwise been in mfd_data. | ||
95 | */ | 99 | */ |
96 | static inline void *mfd_get_data(struct platform_device *pdev) | 100 | static inline void *mfd_get_data(struct platform_device *pdev) |
97 | { | 101 | { |
98 | return mfd_get_cell(pdev)->mfd_data; | 102 | const struct mfd_cell *cell = mfd_get_cell(pdev); |
103 | |||
104 | if (cell) | ||
105 | return cell->mfd_data; | ||
106 | else | ||
107 | return pdev->dev.platform_data; | ||
99 | } | 108 | } |
100 | 109 | ||
101 | extern int mfd_add_devices(struct device *parent, int id, | 110 | 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 d96db9825708..744942c95fec 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/mod_devicetable.h> | 15 | #include <linux/mod_devicetable.h> |
16 | 16 | ||
17 | struct mfd_cell; | ||
18 | |||
17 | struct platform_device { | 19 | struct platform_device { |
18 | const char * name; | 20 | const char * name; |
19 | int id; | 21 | int id; |
@@ -23,6 +25,9 @@ struct platform_device { | |||
23 | 25 | ||
24 | const struct platform_device_id *id_entry; | 26 | const struct platform_device_id *id_entry; |
25 | 27 | ||
28 | /* MFD cell pointer */ | ||
29 | struct mfd_cell *mfd_cell; | ||
30 | |||
26 | /* arch specific additions */ | 31 | /* arch specific additions */ |
27 | struct pdev_archdata archdata; | 32 | struct pdev_archdata archdata; |
28 | }; | 33 | }; |
diff --git a/mm/memory.c b/mm/memory.c index 9da8cab1b1b0..b623a249918c 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1410,6 +1410,13 @@ no_page_table: | |||
1410 | return page; | 1410 | return page; |
1411 | } | 1411 | } |
1412 | 1412 | ||
1413 | static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) | ||
1414 | { | ||
1415 | return (vma->vm_flags & VM_GROWSDOWN) && | ||
1416 | (vma->vm_start == addr) && | ||
1417 | !vma_stack_continue(vma->vm_prev, addr); | ||
1418 | } | ||
1419 | |||
1413 | /** | 1420 | /** |
1414 | * __get_user_pages() - pin user pages in memory | 1421 | * __get_user_pages() - pin user pages in memory |
1415 | * @tsk: task_struct of target task | 1422 | * @tsk: task_struct of target task |
@@ -1488,7 +1495,6 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1488 | vma = find_extend_vma(mm, start); | 1495 | vma = find_extend_vma(mm, start); |
1489 | if (!vma && in_gate_area(mm, start)) { | 1496 | if (!vma && in_gate_area(mm, start)) { |
1490 | unsigned long pg = start & PAGE_MASK; | 1497 | unsigned long pg = start & PAGE_MASK; |
1491 | struct vm_area_struct *gate_vma = get_gate_vma(mm); | ||
1492 | pgd_t *pgd; | 1498 | pgd_t *pgd; |
1493 | pud_t *pud; | 1499 | pud_t *pud; |
1494 | pmd_t *pmd; | 1500 | pmd_t *pmd; |
@@ -1513,10 +1519,11 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1513 | pte_unmap(pte); | 1519 | pte_unmap(pte); |
1514 | return i ? : -EFAULT; | 1520 | return i ? : -EFAULT; |
1515 | } | 1521 | } |
1522 | vma = get_gate_vma(mm); | ||
1516 | if (pages) { | 1523 | if (pages) { |
1517 | struct page *page; | 1524 | struct page *page; |
1518 | 1525 | ||
1519 | page = vm_normal_page(gate_vma, start, *pte); | 1526 | page = vm_normal_page(vma, start, *pte); |
1520 | if (!page) { | 1527 | if (!page) { |
1521 | if (!(gup_flags & FOLL_DUMP) && | 1528 | if (!(gup_flags & FOLL_DUMP) && |
1522 | is_zero_pfn(pte_pfn(*pte))) | 1529 | is_zero_pfn(pte_pfn(*pte))) |
@@ -1530,12 +1537,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1530 | get_page(page); | 1537 | get_page(page); |
1531 | } | 1538 | } |
1532 | pte_unmap(pte); | 1539 | pte_unmap(pte); |
1533 | if (vmas) | 1540 | goto next_page; |
1534 | vmas[i] = gate_vma; | ||
1535 | i++; | ||
1536 | start += PAGE_SIZE; | ||
1537 | nr_pages--; | ||
1538 | continue; | ||
1539 | } | 1541 | } |
1540 | 1542 | ||
1541 | if (!vma || | 1543 | if (!vma || |
@@ -1549,6 +1551,13 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1549 | continue; | 1551 | continue; |
1550 | } | 1552 | } |
1551 | 1553 | ||
1554 | /* | ||
1555 | * If we don't actually want the page itself, | ||
1556 | * and it's the stack guard page, just skip it. | ||
1557 | */ | ||
1558 | if (!pages && stack_guard_page(vma, start)) | ||
1559 | goto next_page; | ||
1560 | |||
1552 | do { | 1561 | do { |
1553 | struct page *page; | 1562 | struct page *page; |
1554 | unsigned int foll_flags = gup_flags; | 1563 | unsigned int foll_flags = gup_flags; |
@@ -1631,6 +1640,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1631 | flush_anon_page(vma, page, start); | 1640 | flush_anon_page(vma, page, start); |
1632 | flush_dcache_page(page); | 1641 | flush_dcache_page(page); |
1633 | } | 1642 | } |
1643 | next_page: | ||
1634 | if (vmas) | 1644 | if (vmas) |
1635 | vmas[i] = vma; | 1645 | vmas[i] = vma; |
1636 | i++; | 1646 | i++; |
diff --git a/mm/mlock.c b/mm/mlock.c index 2689a08c79af..6b55e3efe0df 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -135,13 +135,6 @@ void munlock_vma_page(struct page *page) | |||
135 | } | 135 | } |
136 | } | 136 | } |
137 | 137 | ||
138 | static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr) | ||
139 | { | ||
140 | return (vma->vm_flags & VM_GROWSDOWN) && | ||
141 | (vma->vm_start == addr) && | ||
142 | !vma_stack_continue(vma->vm_prev, addr); | ||
143 | } | ||
144 | |||
145 | /** | 138 | /** |
146 | * __mlock_vma_pages_range() - mlock a range of pages in the vma. | 139 | * __mlock_vma_pages_range() - mlock a range of pages in the vma. |
147 | * @vma: target vma | 140 | * @vma: target vma |
@@ -188,12 +181,6 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma, | |||
188 | if (vma->vm_flags & VM_LOCKED) | 181 | if (vma->vm_flags & VM_LOCKED) |
189 | gup_flags |= FOLL_MLOCK; | 182 | gup_flags |= FOLL_MLOCK; |
190 | 183 | ||
191 | /* We don't try to access the guard page of a stack vma */ | ||
192 | if (stack_guard_page(vma, start)) { | ||
193 | addr += PAGE_SIZE; | ||
194 | nr_pages--; | ||
195 | } | ||
196 | |||
197 | return __get_user_pages(current, mm, addr, nr_pages, gup_flags, | 184 | return __get_user_pages(current, mm, addr, nr_pages, gup_flags, |
198 | NULL, NULL, nonblocking); | 185 | NULL, NULL, nonblocking); |
199 | } | 186 | } |