diff options
318 files changed, 10357 insertions, 2594 deletions
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt index 3af4d29a8938..89aa89d526ac 100644 --- a/Documentation/arm/Samsung-S3C24XX/Overview.txt +++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt | |||
@@ -81,7 +81,8 @@ Adding New Machines | |||
81 | 81 | ||
82 | Any large scale modifications, or new drivers should be discussed | 82 | Any large scale modifications, or new drivers should be discussed |
83 | on the ARM kernel mailing list (linux-arm-kernel) before being | 83 | on the ARM kernel mailing list (linux-arm-kernel) before being |
84 | attempted. | 84 | attempted. See http://www.arm.linux.org.uk/mailinglists/ for the |
85 | mailing list information. | ||
85 | 86 | ||
86 | 87 | ||
87 | NAND | 88 | NAND |
@@ -120,6 +121,43 @@ Clock Management | |||
120 | various clock units | 121 | various clock units |
121 | 122 | ||
122 | 123 | ||
124 | Platform Data | ||
125 | ------------- | ||
126 | |||
127 | Whenever a device has platform specific data that is specified | ||
128 | on a per-machine basis, care should be taken to ensure the | ||
129 | following: | ||
130 | |||
131 | 1) that default data is not left in the device to confuse the | ||
132 | driver if a machine does not set it at startup | ||
133 | |||
134 | 2) the data should (if possible) be marked as __initdata, | ||
135 | to ensure that the data is thrown away if the machine is | ||
136 | not the one currently in use. | ||
137 | |||
138 | The best way of doing this is to make a function that | ||
139 | kmalloc()s an area of memory, and copies the __initdata | ||
140 | and then sets the relevant device's platform data. Making | ||
141 | the function `__init` takes care of ensuring it is discarded | ||
142 | with the rest of the initialisation code | ||
143 | |||
144 | static __init void s3c24xx_xxx_set_platdata(struct xxx_data *pd) | ||
145 | { | ||
146 | struct s3c2410_xxx_mach_info *npd; | ||
147 | |||
148 | npd = kmalloc(sizeof(struct s3c2410_xxx_mach_info), GFP_KERNEL); | ||
149 | if (npd) { | ||
150 | memcpy(npd, pd, sizeof(struct s3c2410_xxx_mach_info)); | ||
151 | s3c_device_xxx.dev.platform_data = npd; | ||
152 | } else { | ||
153 | printk(KERN_ERR "no memory for xxx platform data\n"); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | Note, since the code is marked as __init, it should not be | ||
158 | exported outside arch/arm/mach-s3c2410/, or exported to | ||
159 | modules via EXPORT_SYMBOL() and related functions. | ||
160 | |||
123 | Port Contributors | 161 | Port Contributors |
124 | ----------------- | 162 | ----------------- |
125 | 163 | ||
@@ -149,6 +187,7 @@ Document Changes | |||
149 | 06 Mar 2005 - BJD - Added Christer Weinigel | 187 | 06 Mar 2005 - BJD - Added Christer Weinigel |
150 | 08 Mar 2005 - BJD - Added LCVR to list of people, updated introduction | 188 | 08 Mar 2005 - BJD - Added LCVR to list of people, updated introduction |
151 | 08 Mar 2005 - BJD - Added section on adding machines | 189 | 08 Mar 2005 - BJD - Added section on adding machines |
190 | 09 Sep 2005 - BJD - Added section on platform data | ||
152 | 191 | ||
153 | Document Author | 192 | Document Author |
154 | --------------- | 193 | --------------- |
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt index a5fbc8e897fa..614de3124901 100644 --- a/Documentation/filesystems/ntfs.txt +++ b/Documentation/filesystems/ntfs.txt | |||
@@ -50,9 +50,14 @@ userspace utilities, etc. | |||
50 | Features | 50 | Features |
51 | ======== | 51 | ======== |
52 | 52 | ||
53 | - This is a complete rewrite of the NTFS driver that used to be in the kernel. | 53 | - This is a complete rewrite of the NTFS driver that used to be in the 2.4 and |
54 | This new driver implements NTFS read support and is functionally equivalent | 54 | earlier kernels. This new driver implements NTFS read support and is |
55 | to the old ntfs driver. | 55 | functionally equivalent to the old ntfs driver and it also implements limited |
56 | write support. The biggest limitation at present is that files/directories | ||
57 | cannot be created or deleted. See below for the list of write features that | ||
58 | are so far supported. Another limitation is that writing to compressed files | ||
59 | is not implemented at all. Also, neither read nor write access to encrypted | ||
60 | files is so far implemented. | ||
56 | - The new driver has full support for sparse files on NTFS 3.x volumes which | 61 | - The new driver has full support for sparse files on NTFS 3.x volumes which |
57 | the old driver isn't happy with. | 62 | the old driver isn't happy with. |
58 | - The new driver supports execution of binaries due to mmap() now being | 63 | - The new driver supports execution of binaries due to mmap() now being |
@@ -78,7 +83,20 @@ Features | |||
78 | - The new driver supports fsync(2), fdatasync(2), and msync(2). | 83 | - The new driver supports fsync(2), fdatasync(2), and msync(2). |
79 | - The new driver supports readv(2) and writev(2). | 84 | - The new driver supports readv(2) and writev(2). |
80 | - The new driver supports access time updates (including mtime and ctime). | 85 | - The new driver supports access time updates (including mtime and ctime). |
81 | 86 | - The new driver supports truncate(2) and open(2) with O_TRUNC. But at present | |
87 | only very limited support for highly fragmented files, i.e. ones which have | ||
88 | their data attribute split across multiple extents, is included. Another | ||
89 | limitation is that at present truncate(2) will never create sparse files, | ||
90 | since to mark a file sparse we need to modify the directory entry for the | ||
91 | file and we do not implement directory modifications yet. | ||
92 | - The new driver supports write(2) which can both overwrite existing data and | ||
93 | extend the file size so that you can write beyond the existing data. Also, | ||
94 | writing into sparse regions is supported and the holes are filled in with | ||
95 | clusters. But at present only limited support for highly fragmented files, | ||
96 | i.e. ones which have their data attribute split across multiple extents, is | ||
97 | included. Another limitation is that write(2) will never create sparse | ||
98 | files, since to mark a file sparse we need to modify the directory entry for | ||
99 | the file and we do not implement directory modifications yet. | ||
82 | 100 | ||
83 | Supported mount options | 101 | Supported mount options |
84 | ======================= | 102 | ======================= |
@@ -439,6 +457,22 @@ ChangeLog | |||
439 | 457 | ||
440 | Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. | 458 | Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. |
441 | 459 | ||
460 | 2.1.25: | ||
461 | - Write support is now extended with write(2) being able to both | ||
462 | overwrite existing file data and to extend files. Also, if a write | ||
463 | to a sparse region occurs, write(2) will fill in the hole. Note, | ||
464 | mmap(2) based writes still do not support writing into holes or | ||
465 | writing beyond the initialized size. | ||
466 | - Write support has a new feature and that is that truncate(2) and | ||
467 | open(2) with O_TRUNC are now implemented thus files can be both made | ||
468 | smaller and larger. | ||
469 | - Note: Both write(2) and truncate(2)/open(2) with O_TRUNC still have | ||
470 | limitations in that they | ||
471 | - only provide limited support for highly fragmented files. | ||
472 | - only work on regular, i.e. uncompressed and unencrypted files. | ||
473 | - never create sparse files although this will change once directory | ||
474 | operations are implemented. | ||
475 | - Lots of bug fixes and enhancements across the board. | ||
442 | 2.1.24: | 476 | 2.1.24: |
443 | - Support journals ($LogFile) which have been modified by chkdsk. This | 477 | - Support journals ($LogFile) which have been modified by chkdsk. This |
444 | means users can boot into Windows after we marked the volume dirty. | 478 | means users can boot into Windows after we marked the volume dirty. |
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 682367bd0f65..dc6d8342e5e6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -194,6 +194,13 @@ config ARCH_VERSATILE | |||
194 | help | 194 | help |
195 | This enables support for ARM Ltd Versatile board. | 195 | This enables support for ARM Ltd Versatile board. |
196 | 196 | ||
197 | config ARCH_REALVIEW | ||
198 | bool "RealView" | ||
199 | select ARM_AMBA | ||
200 | select ICST307 | ||
201 | help | ||
202 | This enables support for ARM Ltd RealView boards. | ||
203 | |||
197 | config ARCH_IMX | 204 | config ARCH_IMX |
198 | bool "IMX" | 205 | bool "IMX" |
199 | 206 | ||
@@ -244,6 +251,8 @@ source "arch/arm/mach-versatile/Kconfig" | |||
244 | 251 | ||
245 | source "arch/arm/mach-aaec2000/Kconfig" | 252 | source "arch/arm/mach-aaec2000/Kconfig" |
246 | 253 | ||
254 | source "arch/arm/mach-realview/Kconfig" | ||
255 | |||
247 | # Definitions to make life easier | 256 | # Definitions to make life easier |
248 | config ARCH_ACORN | 257 | config ARCH_ACORN |
249 | bool | 258 | bool |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 64cf480b0b02..d80749ae2a7e 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
@@ -99,6 +99,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 | |||
99 | machine-$(CONFIG_ARCH_IMX) := imx | 99 | machine-$(CONFIG_ARCH_IMX) := imx |
100 | machine-$(CONFIG_ARCH_H720X) := h720x | 100 | machine-$(CONFIG_ARCH_H720X) := h720x |
101 | machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 | 101 | machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 |
102 | machine-$(CONFIG_ARCH_REALVIEW) := realview | ||
102 | 103 | ||
103 | ifeq ($(CONFIG_ARCH_EBSA110),y) | 104 | ifeq ($(CONFIG_ARCH_EBSA110),y) |
104 | # This is what happens if you forget the IOCS16 line. | 105 | # This is what happens if you forget the IOCS16 line. |
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 5cdb4122f057..ad55680726ed 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
25 | #include <linux/device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | 28 | ||
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 21e2a518ad3a..174aa86ee816 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
25 | #include <linux/device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/dma-mapping.h> | 28 | #include <linux/dma-mapping.h> |
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 4af0cf5f3bfb..bb4eff614413 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c | |||
@@ -13,8 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/platform_device.h> |
17 | |||
18 | #include <asm/io.h> | 17 | #include <asm/io.h> |
19 | #include <asm/hardware/scoop.h> | 18 | #include <asm/hardware/scoop.h> |
20 | 19 | ||
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index c279e41ed10e..f74c926beb42 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig | |||
@@ -104,7 +104,7 @@ CONFIG_ARCH_IXCDP1100=y | |||
104 | CONFIG_ARCH_PRPMC1100=y | 104 | CONFIG_ARCH_PRPMC1100=y |
105 | CONFIG_ARCH_IXDP4XX=y | 105 | CONFIG_ARCH_IXDP4XX=y |
106 | CONFIG_CPU_IXP46X=y | 106 | CONFIG_CPU_IXP46X=y |
107 | CONFIG_MACH_GTWX5715=y | 107 | # CONFIG_MACH_GTWX5715 is not set |
108 | 108 | ||
109 | # | 109 | # |
110 | # IXP4xx Options | 110 | # IXP4xx Options |
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 71e5b99e519e..391f3ab3ff32 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile | |||
@@ -7,13 +7,27 @@ | |||
7 | lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ | 7 | lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ |
8 | csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ | 8 | csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ |
9 | copy_page.o delay.o findbit.o memchr.o memcpy.o \ | 9 | copy_page.o delay.o findbit.o memchr.o memcpy.o \ |
10 | memset.o memzero.o setbit.o strncpy_from_user.o \ | 10 | memmove.o memset.o memzero.o setbit.o \ |
11 | strnlen_user.o strchr.o strrchr.o testchangebit.o \ | 11 | strncpy_from_user.o strnlen_user.o \ |
12 | testclearbit.o testsetbit.o uaccess.o getuser.o \ | 12 | strchr.o strrchr.o \ |
13 | putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | 13 | testchangebit.o testclearbit.o testsetbit.o \ |
14 | getuser.o putuser.o clear_user.o \ | ||
15 | ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | ||
14 | ucmpdi2.o lib1funcs.o div64.o sha1.o \ | 16 | ucmpdi2.o lib1funcs.o div64.o sha1.o \ |
15 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o | 17 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o |
16 | 18 | ||
19 | # the code in uaccess.S is not preemption safe and | ||
20 | # probably faster on ARMv3 only | ||
21 | ifeq ($CONFIG_PREEMPT,y) | ||
22 | lib-y += copy_from_user.o copy_to_user.o | ||
23 | else | ||
24 | ifneq ($(CONFIG_CPU_32v3),y) | ||
25 | lib-y += copy_from_user.o copy_to_user.o | ||
26 | else | ||
27 | lib-y += uaccess.o | ||
28 | endif | ||
29 | endif | ||
30 | |||
17 | ifeq ($(CONFIG_CPU_32v3),y) | 31 | ifeq ($(CONFIG_CPU_32v3),y) |
18 | lib-y += io-readsw-armv3.o io-writesw-armv3.o | 32 | lib-y += io-readsw-armv3.o io-writesw-armv3.o |
19 | else | 33 | else |
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S new file mode 100644 index 000000000000..7ff9f831b3f9 --- /dev/null +++ b/arch/arm/lib/clear_user.S | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/clear_user.S | ||
3 | * | ||
4 | * Copyright (C) 1995, 1996,1997,1998 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/linkage.h> | ||
11 | #include <asm/assembler.h> | ||
12 | |||
13 | .text | ||
14 | |||
15 | /* Prototype: int __arch_clear_user(void *addr, size_t sz) | ||
16 | * Purpose : clear some user memory | ||
17 | * Params : addr - user memory address to clear | ||
18 | * : sz - number of bytes to clear | ||
19 | * Returns : number of bytes NOT cleared | ||
20 | */ | ||
21 | ENTRY(__arch_clear_user) | ||
22 | stmfd sp!, {r1, lr} | ||
23 | mov r2, #0 | ||
24 | cmp r1, #4 | ||
25 | blt 2f | ||
26 | ands ip, r0, #3 | ||
27 | beq 1f | ||
28 | cmp ip, #2 | ||
29 | USER( strbt r2, [r0], #1) | ||
30 | USER( strlebt r2, [r0], #1) | ||
31 | USER( strltbt r2, [r0], #1) | ||
32 | rsb ip, ip, #4 | ||
33 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
34 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
35 | USER( strplt r2, [r0], #4) | ||
36 | USER( strplt r2, [r0], #4) | ||
37 | bpl 1b | ||
38 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
39 | USER( strplt r2, [r0], #4) | ||
40 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
41 | USER( strnebt r2, [r0], #1) | ||
42 | USER( strnebt r2, [r0], #1) | ||
43 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
44 | USER( strnebt r2, [r0], #1) | ||
45 | mov r0, #0 | ||
46 | LOADREGS(fd,sp!, {r1, pc}) | ||
47 | |||
48 | .section .fixup,"ax" | ||
49 | .align 0 | ||
50 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
51 | .previous | ||
52 | |||
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S new file mode 100644 index 000000000000..7497393a0e81 --- /dev/null +++ b/arch/arm/lib/copy_from_user.S | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/copy_from_user.S | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Sep 29, 2005 | ||
6 | * Copyright: MontaVista Software, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/assembler.h> | ||
15 | |||
16 | /* | ||
17 | * Prototype: | ||
18 | * | ||
19 | * size_t __arch_copy_from_user(void *to, const void *from, size_t n) | ||
20 | * | ||
21 | * Purpose: | ||
22 | * | ||
23 | * copy a block to kernel memory from user memory | ||
24 | * | ||
25 | * Params: | ||
26 | * | ||
27 | * to = kernel memory | ||
28 | * from = user memory | ||
29 | * n = number of bytes to copy | ||
30 | * | ||
31 | * Return value: | ||
32 | * | ||
33 | * Number of bytes NOT copied. | ||
34 | */ | ||
35 | |||
36 | .macro ldr1w ptr reg abort | ||
37 | 100: ldrt \reg, [\ptr], #4 | ||
38 | .section __ex_table, "a" | ||
39 | .long 100b, \abort | ||
40 | .previous | ||
41 | .endm | ||
42 | |||
43 | .macro ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
44 | ldr1w \ptr, \reg1, \abort | ||
45 | ldr1w \ptr, \reg2, \abort | ||
46 | ldr1w \ptr, \reg3, \abort | ||
47 | ldr1w \ptr, \reg4, \abort | ||
48 | .endm | ||
49 | |||
50 | .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
51 | ldr4w \ptr, \reg1, \reg2, \reg3, \reg4, \abort | ||
52 | ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort | ||
53 | .endm | ||
54 | |||
55 | .macro ldr1b ptr reg cond=al abort | ||
56 | 100: ldr\cond\()bt \reg, [\ptr], #1 | ||
57 | .section __ex_table, "a" | ||
58 | .long 100b, \abort | ||
59 | .previous | ||
60 | .endm | ||
61 | |||
62 | .macro str1w ptr reg abort | ||
63 | str \reg, [\ptr], #4 | ||
64 | .endm | ||
65 | |||
66 | .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
67 | stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} | ||
68 | .endm | ||
69 | |||
70 | .macro str1b ptr reg cond=al abort | ||
71 | str\cond\()b \reg, [\ptr], #1 | ||
72 | .endm | ||
73 | |||
74 | .macro enter reg1 reg2 | ||
75 | mov r3, #0 | ||
76 | stmdb sp!, {r0, r2, r3, \reg1, \reg2} | ||
77 | .endm | ||
78 | |||
79 | .macro exit reg1 reg2 | ||
80 | add sp, sp, #8 | ||
81 | ldmfd sp!, {r0, \reg1, \reg2} | ||
82 | .endm | ||
83 | |||
84 | .text | ||
85 | |||
86 | ENTRY(__arch_copy_from_user) | ||
87 | |||
88 | #include "copy_template.S" | ||
89 | |||
90 | .section .fixup,"ax" | ||
91 | .align 0 | ||
92 | copy_abort_preamble | ||
93 | ldmfd sp!, {r1, r2} | ||
94 | sub r3, r0, r1 | ||
95 | rsb r1, r3, r2 | ||
96 | str r1, [sp] | ||
97 | bl __memzero | ||
98 | ldr r0, [sp], #4 | ||
99 | copy_abort_end | ||
100 | .previous | ||
101 | |||
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S new file mode 100644 index 000000000000..838e435e4922 --- /dev/null +++ b/arch/arm/lib/copy_template.S | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/copy_template.s | ||
3 | * | ||
4 | * Code template for optimized memory copy functions | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Sep 28, 2005 | ||
8 | * Copyright: MontaVista Software, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * This can be used to enable code to cacheline align the source pointer. | ||
17 | * Experiments on tested architectures (StrongARM and XScale) didn't show | ||
18 | * this a worthwhile thing to do. That might be different in the future. | ||
19 | */ | ||
20 | //#define CALGN(code...) code | ||
21 | #define CALGN(code...) | ||
22 | |||
23 | /* | ||
24 | * Theory of operation | ||
25 | * ------------------- | ||
26 | * | ||
27 | * This file provides the core code for a forward memory copy used in | ||
28 | * the implementation of memcopy(), copy_to_user() and copy_from_user(). | ||
29 | * | ||
30 | * The including file must define the following accessor macros | ||
31 | * according to the need of the given function: | ||
32 | * | ||
33 | * ldr1w ptr reg abort | ||
34 | * | ||
35 | * This loads one word from 'ptr', stores it in 'reg' and increments | ||
36 | * 'ptr' to the next word. The 'abort' argument is used for fixup tables. | ||
37 | * | ||
38 | * ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
39 | * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
40 | * | ||
41 | * This loads four or eight words starting from 'ptr', stores them | ||
42 | * in provided registers and increments 'ptr' past those words. | ||
43 | * The'abort' argument is used for fixup tables. | ||
44 | * | ||
45 | * ldr1b ptr reg cond abort | ||
46 | * | ||
47 | * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte. | ||
48 | * It also must apply the condition code if provided, otherwise the | ||
49 | * "al" condition is assumed by default. | ||
50 | * | ||
51 | * str1w ptr reg abort | ||
52 | * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
53 | * str1b ptr reg cond abort | ||
54 | * | ||
55 | * Same as their ldr* counterparts, but data is stored to 'ptr' location | ||
56 | * rather than being loaded. | ||
57 | * | ||
58 | * enter reg1 reg2 | ||
59 | * | ||
60 | * Preserve the provided registers on the stack plus any additional | ||
61 | * data as needed by the implementation including this code. Called | ||
62 | * upon code entry. | ||
63 | * | ||
64 | * exit reg1 reg2 | ||
65 | * | ||
66 | * Restore registers with the values previously saved with the | ||
67 | * 'preserv' macro. Called upon code termination. | ||
68 | */ | ||
69 | |||
70 | |||
71 | enter r4, lr | ||
72 | |||
73 | subs r2, r2, #4 | ||
74 | blt 8f | ||
75 | ands ip, r0, #3 | ||
76 | PLD( pld [r1, #0] ) | ||
77 | bne 9f | ||
78 | ands ip, r1, #3 | ||
79 | bne 10f | ||
80 | |||
81 | 1: subs r2, r2, #(28) | ||
82 | stmfd sp!, {r5 - r8} | ||
83 | blt 5f | ||
84 | |||
85 | CALGN( ands ip, r1, #31 ) | ||
86 | CALGN( rsb r3, ip, #32 ) | ||
87 | CALGN( sbcnes r4, r3, r2 ) @ C is always set here | ||
88 | CALGN( bcs 2f ) | ||
89 | CALGN( adr r4, 6f ) | ||
90 | CALGN( subs r2, r2, r3 ) @ C gets set | ||
91 | CALGN( add pc, r4, ip ) | ||
92 | |||
93 | PLD( pld [r1, #0] ) | ||
94 | 2: PLD( subs r2, r2, #96 ) | ||
95 | PLD( pld [r1, #28] ) | ||
96 | PLD( blt 4f ) | ||
97 | PLD( pld [r1, #60] ) | ||
98 | PLD( pld [r1, #92] ) | ||
99 | |||
100 | 3: PLD( pld [r1, #124] ) | ||
101 | 4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f | ||
102 | subs r2, r2, #32 | ||
103 | str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f | ||
104 | bge 3b | ||
105 | PLD( cmn r2, #96 ) | ||
106 | PLD( bge 4b ) | ||
107 | |||
108 | 5: ands ip, r2, #28 | ||
109 | rsb ip, ip, #32 | ||
110 | addne pc, pc, ip @ C is always clear here | ||
111 | b 7f | ||
112 | 6: nop | ||
113 | ldr1w r1, r3, abort=20f | ||
114 | ldr1w r1, r4, abort=20f | ||
115 | ldr1w r1, r5, abort=20f | ||
116 | ldr1w r1, r6, abort=20f | ||
117 | ldr1w r1, r7, abort=20f | ||
118 | ldr1w r1, r8, abort=20f | ||
119 | ldr1w r1, lr, abort=20f | ||
120 | |||
121 | add pc, pc, ip | ||
122 | nop | ||
123 | nop | ||
124 | str1w r0, r3, abort=20f | ||
125 | str1w r0, r4, abort=20f | ||
126 | str1w r0, r5, abort=20f | ||
127 | str1w r0, r6, abort=20f | ||
128 | str1w r0, r7, abort=20f | ||
129 | str1w r0, r8, abort=20f | ||
130 | str1w r0, lr, abort=20f | ||
131 | |||
132 | CALGN( bcs 2b ) | ||
133 | |||
134 | 7: ldmfd sp!, {r5 - r8} | ||
135 | |||
136 | 8: movs r2, r2, lsl #31 | ||
137 | ldr1b r1, r3, ne, abort=21f | ||
138 | ldr1b r1, r4, cs, abort=21f | ||
139 | ldr1b r1, ip, cs, abort=21f | ||
140 | str1b r0, r3, ne, abort=21f | ||
141 | str1b r0, r4, cs, abort=21f | ||
142 | str1b r0, ip, cs, abort=21f | ||
143 | |||
144 | exit r4, pc | ||
145 | |||
146 | 9: rsb ip, ip, #4 | ||
147 | cmp ip, #2 | ||
148 | ldr1b r1, r3, gt, abort=21f | ||
149 | ldr1b r1, r4, ge, abort=21f | ||
150 | ldr1b r1, lr, abort=21f | ||
151 | str1b r0, r3, gt, abort=21f | ||
152 | str1b r0, r4, ge, abort=21f | ||
153 | subs r2, r2, ip | ||
154 | str1b r0, lr, abort=21f | ||
155 | blt 8b | ||
156 | ands ip, r1, #3 | ||
157 | beq 1b | ||
158 | |||
159 | 10: bic r1, r1, #3 | ||
160 | cmp ip, #2 | ||
161 | ldr1w r1, lr, abort=21f | ||
162 | beq 17f | ||
163 | bgt 18f | ||
164 | |||
165 | |||
166 | .macro forward_copy_shift pull push | ||
167 | |||
168 | subs r2, r2, #28 | ||
169 | blt 14f | ||
170 | |||
171 | CALGN( ands ip, r1, #31 ) | ||
172 | CALGN( rsb ip, ip, #32 ) | ||
173 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
174 | CALGN( subcc r2, r2, ip ) | ||
175 | CALGN( bcc 15f ) | ||
176 | |||
177 | 11: stmfd sp!, {r5 - r9} | ||
178 | |||
179 | PLD( pld [r1, #0] ) | ||
180 | PLD( subs r2, r2, #96 ) | ||
181 | PLD( pld [r1, #28] ) | ||
182 | PLD( blt 13f ) | ||
183 | PLD( pld [r1, #60] ) | ||
184 | PLD( pld [r1, #92] ) | ||
185 | |||
186 | 12: PLD( pld [r1, #124] ) | ||
187 | 13: ldr4w r1, r4, r5, r6, r7, abort=19f | ||
188 | mov r3, lr, pull #\pull | ||
189 | subs r2, r2, #32 | ||
190 | ldr4w r1, r8, r9, ip, lr, abort=19f | ||
191 | orr r3, r3, r4, push #\push | ||
192 | mov r4, r4, pull #\pull | ||
193 | orr r4, r4, r5, push #\push | ||
194 | mov r5, r5, pull #\pull | ||
195 | orr r5, r5, r6, push #\push | ||
196 | mov r6, r6, pull #\pull | ||
197 | orr r6, r6, r7, push #\push | ||
198 | mov r7, r7, pull #\pull | ||
199 | orr r7, r7, r8, push #\push | ||
200 | mov r8, r8, pull #\pull | ||
201 | orr r8, r8, r9, push #\push | ||
202 | mov r9, r9, pull #\pull | ||
203 | orr r9, r9, ip, push #\push | ||
204 | mov ip, ip, pull #\pull | ||
205 | orr ip, ip, lr, push #\push | ||
206 | str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f | ||
207 | bge 12b | ||
208 | PLD( cmn r2, #96 ) | ||
209 | PLD( bge 13b ) | ||
210 | |||
211 | ldmfd sp!, {r5 - r9} | ||
212 | |||
213 | 14: ands ip, r2, #28 | ||
214 | beq 16f | ||
215 | |||
216 | 15: mov r3, lr, pull #\pull | ||
217 | ldr1w r1, lr, abort=21f | ||
218 | subs ip, ip, #4 | ||
219 | orr r3, r3, lr, push #\push | ||
220 | str1w r0, r3, abort=21f | ||
221 | bgt 15b | ||
222 | CALGN( cmp r2, #0 ) | ||
223 | CALGN( bge 11b ) | ||
224 | |||
225 | 16: sub r1, r1, #(\push / 8) | ||
226 | b 8b | ||
227 | |||
228 | .endm | ||
229 | |||
230 | |||
231 | forward_copy_shift pull=8 push=24 | ||
232 | |||
233 | 17: forward_copy_shift pull=16 push=16 | ||
234 | |||
235 | 18: forward_copy_shift pull=24 push=8 | ||
236 | |||
237 | |||
238 | /* | ||
239 | * Abort preanble and completion macros. | ||
240 | * If a fixup handler is required then those macros must surround it. | ||
241 | * It is assumed that the fixup code will handle the private part of | ||
242 | * the exit macro. | ||
243 | */ | ||
244 | |||
245 | .macro copy_abort_preamble | ||
246 | 19: ldmfd sp!, {r5 - r9} | ||
247 | b 21f | ||
248 | 20: ldmfd sp!, {r5 - r8} | ||
249 | 21: | ||
250 | .endm | ||
251 | |||
252 | .macro copy_abort_end | ||
253 | ldmfd sp!, {r4, pc} | ||
254 | .endm | ||
255 | |||
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S new file mode 100644 index 000000000000..4a6d8ea14022 --- /dev/null +++ b/arch/arm/lib/copy_to_user.S | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/copy_to_user.S | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Sep 29, 2005 | ||
6 | * Copyright: MontaVista Software, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/assembler.h> | ||
15 | |||
16 | /* | ||
17 | * Prototype: | ||
18 | * | ||
19 | * size_t __arch_copy_to_user(void *to, const void *from, size_t n) | ||
20 | * | ||
21 | * Purpose: | ||
22 | * | ||
23 | * copy a block to user memory from kernel memory | ||
24 | * | ||
25 | * Params: | ||
26 | * | ||
27 | * to = user memory | ||
28 | * from = kernel memory | ||
29 | * n = number of bytes to copy | ||
30 | * | ||
31 | * Return value: | ||
32 | * | ||
33 | * Number of bytes NOT copied. | ||
34 | */ | ||
35 | |||
36 | .macro ldr1w ptr reg abort | ||
37 | ldr \reg, [\ptr], #4 | ||
38 | .endm | ||
39 | |||
40 | .macro ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
41 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4} | ||
42 | .endm | ||
43 | |||
44 | .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
45 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} | ||
46 | .endm | ||
47 | |||
48 | .macro ldr1b ptr reg cond=al abort | ||
49 | ldr\cond\()b \reg, [\ptr], #1 | ||
50 | .endm | ||
51 | |||
52 | .macro str1w ptr reg abort | ||
53 | 100: strt \reg, [\ptr], #4 | ||
54 | .section __ex_table, "a" | ||
55 | .long 100b, \abort | ||
56 | .previous | ||
57 | .endm | ||
58 | |||
59 | .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
60 | str1w \ptr, \reg1, \abort | ||
61 | str1w \ptr, \reg2, \abort | ||
62 | str1w \ptr, \reg3, \abort | ||
63 | str1w \ptr, \reg4, \abort | ||
64 | str1w \ptr, \reg5, \abort | ||
65 | str1w \ptr, \reg6, \abort | ||
66 | str1w \ptr, \reg7, \abort | ||
67 | str1w \ptr, \reg8, \abort | ||
68 | .endm | ||
69 | |||
70 | .macro str1b ptr reg cond=al abort | ||
71 | 100: str\cond\()bt \reg, [\ptr], #1 | ||
72 | .section __ex_table, "a" | ||
73 | .long 100b, \abort | ||
74 | .previous | ||
75 | .endm | ||
76 | |||
77 | .macro enter reg1 reg2 | ||
78 | mov r3, #0 | ||
79 | stmdb sp!, {r0, r2, r3, \reg1, \reg2} | ||
80 | .endm | ||
81 | |||
82 | .macro exit reg1 reg2 | ||
83 | add sp, sp, #8 | ||
84 | ldmfd sp!, {r0, \reg1, \reg2} | ||
85 | .endm | ||
86 | |||
87 | .text | ||
88 | |||
89 | ENTRY(__arch_copy_to_user) | ||
90 | |||
91 | #include "copy_template.S" | ||
92 | |||
93 | .section .fixup,"ax" | ||
94 | .align 0 | ||
95 | copy_abort_preamble | ||
96 | ldmfd sp!, {r1, r2, r3} | ||
97 | sub r0, r0, r1 | ||
98 | rsb r0, r0, r2 | ||
99 | copy_abort_end | ||
100 | .previous | ||
101 | |||
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S index f5a593ceb8cc..7e71d6708a8d 100644 --- a/arch/arm/lib/memcpy.S +++ b/arch/arm/lib/memcpy.S | |||
@@ -1,393 +1,59 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/lib/memcpy.S | 2 | * linux/arch/arm/lib/memcpy.S |
3 | * | 3 | * |
4 | * Copyright (C) 1995-1999 Russell King | 4 | * Author: Nicolas Pitre |
5 | * Created: Sep 28, 2005 | ||
6 | * Copyright: MontaVista Software, Inc. | ||
5 | * | 7 | * |
6 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
9 | * | ||
10 | * ASM optimised string functions | ||
11 | */ | 11 | */ |
12 | |||
12 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
13 | #include <asm/assembler.h> | 14 | #include <asm/assembler.h> |
14 | 15 | ||
15 | .text | 16 | .macro ldr1w ptr reg abort |
16 | 17 | ldr \reg, [\ptr], #4 | |
17 | #define ENTER \ | 18 | .endm |
18 | mov ip,sp ;\ | ||
19 | stmfd sp!,{r0,r4-r9,fp,ip,lr,pc} ;\ | ||
20 | sub fp,ip,#4 | ||
21 | |||
22 | #define EXIT \ | ||
23 | LOADREGS(ea, fp, {r0, r4 - r9, fp, sp, pc}) | ||
24 | |||
25 | #define EXITEQ \ | ||
26 | LOADREGS(eqea, fp, {r0, r4 - r9, fp, sp, pc}) | ||
27 | |||
28 | /* | ||
29 | * Prototype: void memcpy(void *to,const void *from,unsigned long n); | ||
30 | */ | ||
31 | ENTRY(memcpy) | ||
32 | ENTRY(memmove) | ||
33 | ENTER | ||
34 | cmp r1, r0 | ||
35 | bcc 23f | ||
36 | subs r2, r2, #4 | ||
37 | blt 6f | ||
38 | PLD( pld [r1, #0] ) | ||
39 | ands ip, r0, #3 | ||
40 | bne 7f | ||
41 | ands ip, r1, #3 | ||
42 | bne 8f | ||
43 | 19 | ||
44 | 1: subs r2, r2, #8 | 20 | .macro ldr4w ptr reg1 reg2 reg3 reg4 abort |
45 | blt 5f | 21 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4} |
46 | subs r2, r2, #20 | 22 | .endm |
47 | blt 4f | ||
48 | PLD( pld [r1, #28] ) | ||
49 | PLD( subs r2, r2, #64 ) | ||
50 | PLD( blt 3f ) | ||
51 | 2: PLD( pld [r1, #60] ) | ||
52 | PLD( pld [r1, #92] ) | ||
53 | ldmia r1!, {r3 - r9, ip} | ||
54 | subs r2, r2, #32 | ||
55 | stmgeia r0!, {r3 - r9, ip} | ||
56 | ldmgeia r1!, {r3 - r9, ip} | ||
57 | subges r2, r2, #32 | ||
58 | stmia r0!, {r3 - r9, ip} | ||
59 | bge 2b | ||
60 | 3: PLD( ldmia r1!, {r3 - r9, ip} ) | ||
61 | PLD( adds r2, r2, #32 ) | ||
62 | PLD( stmgeia r0!, {r3 - r9, ip} ) | ||
63 | PLD( ldmgeia r1!, {r3 - r9, ip} ) | ||
64 | PLD( subges r2, r2, #32 ) | ||
65 | PLD( stmia r0!, {r3 - r9, ip} ) | ||
66 | 4: cmn r2, #16 | ||
67 | ldmgeia r1!, {r3 - r6} | ||
68 | subge r2, r2, #16 | ||
69 | stmgeia r0!, {r3 - r6} | ||
70 | adds r2, r2, #20 | ||
71 | ldmgeia r1!, {r3 - r5} | ||
72 | subge r2, r2, #12 | ||
73 | stmgeia r0!, {r3 - r5} | ||
74 | 5: adds r2, r2, #8 | ||
75 | blt 6f | ||
76 | subs r2, r2, #4 | ||
77 | ldrlt r3, [r1], #4 | ||
78 | ldmgeia r1!, {r4, r5} | ||
79 | subge r2, r2, #4 | ||
80 | strlt r3, [r0], #4 | ||
81 | stmgeia r0!, {r4, r5} | ||
82 | 23 | ||
83 | 6: adds r2, r2, #4 | 24 | .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort |
84 | EXITEQ | 25 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} |
85 | cmp r2, #2 | 26 | .endm |
86 | ldrb r3, [r1], #1 | ||
87 | ldrgeb r4, [r1], #1 | ||
88 | ldrgtb r5, [r1], #1 | ||
89 | strb r3, [r0], #1 | ||
90 | strgeb r4, [r0], #1 | ||
91 | strgtb r5, [r0], #1 | ||
92 | EXIT | ||
93 | 27 | ||
94 | 7: rsb ip, ip, #4 | 28 | .macro ldr1b ptr reg cond=al abort |
95 | cmp ip, #2 | 29 | ldr\cond\()b \reg, [\ptr], #1 |
96 | ldrb r3, [r1], #1 | 30 | .endm |
97 | ldrgeb r4, [r1], #1 | ||
98 | ldrgtb r5, [r1], #1 | ||
99 | strb r3, [r0], #1 | ||
100 | strgeb r4, [r0], #1 | ||
101 | strgtb r5, [r0], #1 | ||
102 | subs r2, r2, ip | ||
103 | blt 6b | ||
104 | ands ip, r1, #3 | ||
105 | beq 1b | ||
106 | 31 | ||
107 | 8: bic r1, r1, #3 | 32 | .macro str1w ptr reg abort |
108 | ldr r7, [r1], #4 | 33 | str \reg, [\ptr], #4 |
109 | cmp ip, #2 | 34 | .endm |
110 | bgt 18f | ||
111 | beq 13f | ||
112 | cmp r2, #12 | ||
113 | blt 11f | ||
114 | PLD( pld [r1, #12] ) | ||
115 | sub r2, r2, #12 | ||
116 | PLD( subs r2, r2, #32 ) | ||
117 | PLD( blt 10f ) | ||
118 | PLD( pld [r1, #28] ) | ||
119 | 9: PLD( pld [r1, #44] ) | ||
120 | 10: mov r3, r7, pull #8 | ||
121 | ldmia r1!, {r4 - r7} | ||
122 | subs r2, r2, #16 | ||
123 | orr r3, r3, r4, push #24 | ||
124 | mov r4, r4, pull #8 | ||
125 | orr r4, r4, r5, push #24 | ||
126 | mov r5, r5, pull #8 | ||
127 | orr r5, r5, r6, push #24 | ||
128 | mov r6, r6, pull #8 | ||
129 | orr r6, r6, r7, push #24 | ||
130 | stmia r0!, {r3 - r6} | ||
131 | bge 9b | ||
132 | PLD( cmn r2, #32 ) | ||
133 | PLD( bge 10b ) | ||
134 | PLD( add r2, r2, #32 ) | ||
135 | adds r2, r2, #12 | ||
136 | blt 12f | ||
137 | 11: mov r3, r7, pull #8 | ||
138 | ldr r7, [r1], #4 | ||
139 | subs r2, r2, #4 | ||
140 | orr r3, r3, r7, push #24 | ||
141 | str r3, [r0], #4 | ||
142 | bge 11b | ||
143 | 12: sub r1, r1, #3 | ||
144 | b 6b | ||
145 | 35 | ||
146 | 13: cmp r2, #12 | 36 | .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort |
147 | blt 16f | 37 | stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} |
148 | PLD( pld [r1, #12] ) | 38 | .endm |
149 | sub r2, r2, #12 | ||
150 | PLD( subs r2, r2, #32 ) | ||
151 | PLD( blt 15f ) | ||
152 | PLD( pld [r1, #28] ) | ||
153 | 14: PLD( pld [r1, #44] ) | ||
154 | 15: mov r3, r7, pull #16 | ||
155 | ldmia r1!, {r4 - r7} | ||
156 | subs r2, r2, #16 | ||
157 | orr r3, r3, r4, push #16 | ||
158 | mov r4, r4, pull #16 | ||
159 | orr r4, r4, r5, push #16 | ||
160 | mov r5, r5, pull #16 | ||
161 | orr r5, r5, r6, push #16 | ||
162 | mov r6, r6, pull #16 | ||
163 | orr r6, r6, r7, push #16 | ||
164 | stmia r0!, {r3 - r6} | ||
165 | bge 14b | ||
166 | PLD( cmn r2, #32 ) | ||
167 | PLD( bge 15b ) | ||
168 | PLD( add r2, r2, #32 ) | ||
169 | adds r2, r2, #12 | ||
170 | blt 17f | ||
171 | 16: mov r3, r7, pull #16 | ||
172 | ldr r7, [r1], #4 | ||
173 | subs r2, r2, #4 | ||
174 | orr r3, r3, r7, push #16 | ||
175 | str r3, [r0], #4 | ||
176 | bge 16b | ||
177 | 17: sub r1, r1, #2 | ||
178 | b 6b | ||
179 | 39 | ||
180 | 18: cmp r2, #12 | 40 | .macro str1b ptr reg cond=al abort |
181 | blt 21f | 41 | str\cond\()b \reg, [\ptr], #1 |
182 | PLD( pld [r1, #12] ) | 42 | .endm |
183 | sub r2, r2, #12 | ||
184 | PLD( subs r2, r2, #32 ) | ||
185 | PLD( blt 20f ) | ||
186 | PLD( pld [r1, #28] ) | ||
187 | 19: PLD( pld [r1, #44] ) | ||
188 | 20: mov r3, r7, pull #24 | ||
189 | ldmia r1!, {r4 - r7} | ||
190 | subs r2, r2, #16 | ||
191 | orr r3, r3, r4, push #8 | ||
192 | mov r4, r4, pull #24 | ||
193 | orr r4, r4, r5, push #8 | ||
194 | mov r5, r5, pull #24 | ||
195 | orr r5, r5, r6, push #8 | ||
196 | mov r6, r6, pull #24 | ||
197 | orr r6, r6, r7, push #8 | ||
198 | stmia r0!, {r3 - r6} | ||
199 | bge 19b | ||
200 | PLD( cmn r2, #32 ) | ||
201 | PLD( bge 20b ) | ||
202 | PLD( add r2, r2, #32 ) | ||
203 | adds r2, r2, #12 | ||
204 | blt 22f | ||
205 | 21: mov r3, r7, pull #24 | ||
206 | ldr r7, [r1], #4 | ||
207 | subs r2, r2, #4 | ||
208 | orr r3, r3, r7, push #8 | ||
209 | str r3, [r0], #4 | ||
210 | bge 21b | ||
211 | 22: sub r1, r1, #1 | ||
212 | b 6b | ||
213 | 43 | ||
44 | .macro enter reg1 reg2 | ||
45 | stmdb sp!, {r0, \reg1, \reg2} | ||
46 | .endm | ||
214 | 47 | ||
215 | 23: add r1, r1, r2 | 48 | .macro exit reg1 reg2 |
216 | add r0, r0, r2 | 49 | ldmfd sp!, {r0, \reg1, \reg2} |
217 | subs r2, r2, #4 | 50 | .endm |
218 | blt 29f | ||
219 | PLD( pld [r1, #-4] ) | ||
220 | ands ip, r0, #3 | ||
221 | bne 30f | ||
222 | ands ip, r1, #3 | ||
223 | bne 31f | ||
224 | 51 | ||
225 | 24: subs r2, r2, #8 | 52 | .text |
226 | blt 28f | ||
227 | subs r2, r2, #20 | ||
228 | blt 27f | ||
229 | PLD( pld [r1, #-32] ) | ||
230 | PLD( subs r2, r2, #64 ) | ||
231 | PLD( blt 26f ) | ||
232 | 25: PLD( pld [r1, #-64] ) | ||
233 | PLD( pld [r1, #-96] ) | ||
234 | ldmdb r1!, {r3 - r9, ip} | ||
235 | subs r2, r2, #32 | ||
236 | stmgedb r0!, {r3 - r9, ip} | ||
237 | ldmgedb r1!, {r3 - r9, ip} | ||
238 | subges r2, r2, #32 | ||
239 | stmdb r0!, {r3 - r9, ip} | ||
240 | bge 25b | ||
241 | 26: PLD( ldmdb r1!, {r3 - r9, ip} ) | ||
242 | PLD( adds r2, r2, #32 ) | ||
243 | PLD( stmgedb r0!, {r3 - r9, ip} ) | ||
244 | PLD( ldmgedb r1!, {r3 - r9, ip} ) | ||
245 | PLD( subges r2, r2, #32 ) | ||
246 | PLD( stmdb r0!, {r3 - r9, ip} ) | ||
247 | 27: cmn r2, #16 | ||
248 | ldmgedb r1!, {r3 - r6} | ||
249 | subge r2, r2, #16 | ||
250 | stmgedb r0!, {r3 - r6} | ||
251 | adds r2, r2, #20 | ||
252 | ldmgedb r1!, {r3 - r5} | ||
253 | subge r2, r2, #12 | ||
254 | stmgedb r0!, {r3 - r5} | ||
255 | 28: adds r2, r2, #8 | ||
256 | blt 29f | ||
257 | subs r2, r2, #4 | ||
258 | ldrlt r3, [r1, #-4]! | ||
259 | ldmgedb r1!, {r4, r5} | ||
260 | subge r2, r2, #4 | ||
261 | strlt r3, [r0, #-4]! | ||
262 | stmgedb r0!, {r4, r5} | ||
263 | 53 | ||
264 | 29: adds r2, r2, #4 | 54 | /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ |
265 | EXITEQ | ||
266 | cmp r2, #2 | ||
267 | ldrb r3, [r1, #-1]! | ||
268 | ldrgeb r4, [r1, #-1]! | ||
269 | ldrgtb r5, [r1, #-1]! | ||
270 | strb r3, [r0, #-1]! | ||
271 | strgeb r4, [r0, #-1]! | ||
272 | strgtb r5, [r0, #-1]! | ||
273 | EXIT | ||
274 | 55 | ||
275 | 30: cmp ip, #2 | 56 | ENTRY(memcpy) |
276 | ldrb r3, [r1, #-1]! | ||
277 | ldrgeb r4, [r1, #-1]! | ||
278 | ldrgtb r5, [r1, #-1]! | ||
279 | strb r3, [r0, #-1]! | ||
280 | strgeb r4, [r0, #-1]! | ||
281 | strgtb r5, [r0, #-1]! | ||
282 | subs r2, r2, ip | ||
283 | blt 29b | ||
284 | ands ip, r1, #3 | ||
285 | beq 24b | ||
286 | |||
287 | 31: bic r1, r1, #3 | ||
288 | ldr r3, [r1], #0 | ||
289 | cmp ip, #2 | ||
290 | blt 41f | ||
291 | beq 36f | ||
292 | cmp r2, #12 | ||
293 | blt 34f | ||
294 | PLD( pld [r1, #-16] ) | ||
295 | sub r2, r2, #12 | ||
296 | PLD( subs r2, r2, #32 ) | ||
297 | PLD( blt 33f ) | ||
298 | PLD( pld [r1, #-32] ) | ||
299 | 32: PLD( pld [r1, #-48] ) | ||
300 | 33: mov r7, r3, push #8 | ||
301 | ldmdb r1!, {r3, r4, r5, r6} | ||
302 | subs r2, r2, #16 | ||
303 | orr r7, r7, r6, pull #24 | ||
304 | mov r6, r6, push #8 | ||
305 | orr r6, r6, r5, pull #24 | ||
306 | mov r5, r5, push #8 | ||
307 | orr r5, r5, r4, pull #24 | ||
308 | mov r4, r4, push #8 | ||
309 | orr r4, r4, r3, pull #24 | ||
310 | stmdb r0!, {r4, r5, r6, r7} | ||
311 | bge 32b | ||
312 | PLD( cmn r2, #32 ) | ||
313 | PLD( bge 33b ) | ||
314 | PLD( add r2, r2, #32 ) | ||
315 | adds r2, r2, #12 | ||
316 | blt 35f | ||
317 | 34: mov ip, r3, push #8 | ||
318 | ldr r3, [r1, #-4]! | ||
319 | subs r2, r2, #4 | ||
320 | orr ip, ip, r3, pull #24 | ||
321 | str ip, [r0, #-4]! | ||
322 | bge 34b | ||
323 | 35: add r1, r1, #3 | ||
324 | b 29b | ||
325 | |||
326 | 36: cmp r2, #12 | ||
327 | blt 39f | ||
328 | PLD( pld [r1, #-16] ) | ||
329 | sub r2, r2, #12 | ||
330 | PLD( subs r2, r2, #32 ) | ||
331 | PLD( blt 38f ) | ||
332 | PLD( pld [r1, #-32] ) | ||
333 | 37: PLD( pld [r1, #-48] ) | ||
334 | 38: mov r7, r3, push #16 | ||
335 | ldmdb r1!, {r3, r4, r5, r6} | ||
336 | subs r2, r2, #16 | ||
337 | orr r7, r7, r6, pull #16 | ||
338 | mov r6, r6, push #16 | ||
339 | orr r6, r6, r5, pull #16 | ||
340 | mov r5, r5, push #16 | ||
341 | orr r5, r5, r4, pull #16 | ||
342 | mov r4, r4, push #16 | ||
343 | orr r4, r4, r3, pull #16 | ||
344 | stmdb r0!, {r4, r5, r6, r7} | ||
345 | bge 37b | ||
346 | PLD( cmn r2, #32 ) | ||
347 | PLD( bge 38b ) | ||
348 | PLD( add r2, r2, #32 ) | ||
349 | adds r2, r2, #12 | ||
350 | blt 40f | ||
351 | 39: mov ip, r3, push #16 | ||
352 | ldr r3, [r1, #-4]! | ||
353 | subs r2, r2, #4 | ||
354 | orr ip, ip, r3, pull #16 | ||
355 | str ip, [r0, #-4]! | ||
356 | bge 39b | ||
357 | 40: add r1, r1, #2 | ||
358 | b 29b | ||
359 | 57 | ||
360 | 41: cmp r2, #12 | 58 | #include "copy_template.S" |
361 | blt 44f | ||
362 | PLD( pld [r1, #-16] ) | ||
363 | sub r2, r2, #12 | ||
364 | PLD( subs r2, r2, #32 ) | ||
365 | PLD( blt 43f ) | ||
366 | PLD( pld [r1, #-32] ) | ||
367 | 42: PLD( pld [r1, #-48] ) | ||
368 | 43: mov r7, r3, push #24 | ||
369 | ldmdb r1!, {r3, r4, r5, r6} | ||
370 | subs r2, r2, #16 | ||
371 | orr r7, r7, r6, pull #8 | ||
372 | mov r6, r6, push #24 | ||
373 | orr r6, r6, r5, pull #8 | ||
374 | mov r5, r5, push #24 | ||
375 | orr r5, r5, r4, pull #8 | ||
376 | mov r4, r4, push #24 | ||
377 | orr r4, r4, r3, pull #8 | ||
378 | stmdb r0!, {r4, r5, r6, r7} | ||
379 | bge 42b | ||
380 | PLD( cmn r2, #32 ) | ||
381 | PLD( bge 43b ) | ||
382 | PLD( add r2, r2, #32 ) | ||
383 | adds r2, r2, #12 | ||
384 | blt 45f | ||
385 | 44: mov ip, r3, push #24 | ||
386 | ldr r3, [r1, #-4]! | ||
387 | subs r2, r2, #4 | ||
388 | orr ip, ip, r3, pull #8 | ||
389 | str ip, [r0, #-4]! | ||
390 | bge 44b | ||
391 | 45: add r1, r1, #1 | ||
392 | b 29b | ||
393 | 59 | ||
diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S new file mode 100644 index 000000000000..ef7fddc14ac9 --- /dev/null +++ b/arch/arm/lib/memmove.S | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/memmove.S | ||
3 | * | ||
4 | * Author: Nicolas Pitre | ||
5 | * Created: Sep 28, 2005 | ||
6 | * Copyright: (C) MontaVista Software Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/assembler.h> | ||
15 | |||
16 | /* | ||
17 | * This can be used to enable code to cacheline align the source pointer. | ||
18 | * Experiments on tested architectures (StrongARM and XScale) didn't show | ||
19 | * this a worthwhile thing to do. That might be different in the future. | ||
20 | */ | ||
21 | //#define CALGN(code...) code | ||
22 | #define CALGN(code...) | ||
23 | |||
24 | .text | ||
25 | |||
26 | /* | ||
27 | * Prototype: void *memmove(void *dest, const void *src, size_t n); | ||
28 | * | ||
29 | * Note: | ||
30 | * | ||
31 | * If the memory regions don't overlap, we simply branch to memcpy which is | ||
32 | * normally a bit faster. Otherwise the copy is done going downwards. This | ||
33 | * is a transposition of the code from copy_template.S but with the copy | ||
34 | * occurring in the opposite direction. | ||
35 | */ | ||
36 | |||
37 | ENTRY(memmove) | ||
38 | |||
39 | subs ip, r0, r1 | ||
40 | cmphi r2, ip | ||
41 | bls memcpy | ||
42 | |||
43 | stmfd sp!, {r0, r4, lr} | ||
44 | add r1, r1, r2 | ||
45 | add r0, r0, r2 | ||
46 | subs r2, r2, #4 | ||
47 | blt 8f | ||
48 | ands ip, r0, #3 | ||
49 | PLD( pld [r1, #-4] ) | ||
50 | bne 9f | ||
51 | ands ip, r1, #3 | ||
52 | bne 10f | ||
53 | |||
54 | 1: subs r2, r2, #(28) | ||
55 | stmfd sp!, {r5 - r8} | ||
56 | blt 5f | ||
57 | |||
58 | CALGN( ands ip, r1, #31 ) | ||
59 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
60 | CALGN( bcs 2f ) | ||
61 | CALGN( adr r4, 6f ) | ||
62 | CALGN( subs r2, r2, ip ) @ C is set here | ||
63 | CALGN( add pc, r4, ip ) | ||
64 | |||
65 | PLD( pld [r1, #-4] ) | ||
66 | 2: PLD( subs r2, r2, #96 ) | ||
67 | PLD( pld [r1, #-32] ) | ||
68 | PLD( blt 4f ) | ||
69 | PLD( pld [r1, #-64] ) | ||
70 | PLD( pld [r1, #-96] ) | ||
71 | |||
72 | 3: PLD( pld [r1, #-128] ) | ||
73 | 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} | ||
74 | subs r2, r2, #32 | ||
75 | stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} | ||
76 | bge 3b | ||
77 | PLD( cmn r2, #96 ) | ||
78 | PLD( bge 4b ) | ||
79 | |||
80 | 5: ands ip, r2, #28 | ||
81 | rsb ip, ip, #32 | ||
82 | addne pc, pc, ip @ C is always clear here | ||
83 | b 7f | ||
84 | 6: nop | ||
85 | ldr r3, [r1, #-4]! | ||
86 | ldr r4, [r1, #-4]! | ||
87 | ldr r5, [r1, #-4]! | ||
88 | ldr r6, [r1, #-4]! | ||
89 | ldr r7, [r1, #-4]! | ||
90 | ldr r8, [r1, #-4]! | ||
91 | ldr lr, [r1, #-4]! | ||
92 | |||
93 | add pc, pc, ip | ||
94 | nop | ||
95 | nop | ||
96 | str r3, [r0, #-4]! | ||
97 | str r4, [r0, #-4]! | ||
98 | str r5, [r0, #-4]! | ||
99 | str r6, [r0, #-4]! | ||
100 | str r7, [r0, #-4]! | ||
101 | str r8, [r0, #-4]! | ||
102 | str lr, [r0, #-4]! | ||
103 | |||
104 | CALGN( bcs 2b ) | ||
105 | |||
106 | 7: ldmfd sp!, {r5 - r8} | ||
107 | |||
108 | 8: movs r2, r2, lsl #31 | ||
109 | ldrneb r3, [r1, #-1]! | ||
110 | ldrcsb r4, [r1, #-1]! | ||
111 | ldrcsb ip, [r1, #-1] | ||
112 | strneb r3, [r0, #-1]! | ||
113 | strcsb r4, [r0, #-1]! | ||
114 | strcsb ip, [r0, #-1] | ||
115 | ldmfd sp!, {r0, r4, pc} | ||
116 | |||
117 | 9: cmp ip, #2 | ||
118 | ldrgtb r3, [r1, #-1]! | ||
119 | ldrgeb r4, [r1, #-1]! | ||
120 | ldrb lr, [r1, #-1]! | ||
121 | strgtb r3, [r0, #-1]! | ||
122 | strgeb r4, [r0, #-1]! | ||
123 | subs r2, r2, ip | ||
124 | strb lr, [r0, #-1]! | ||
125 | blt 8b | ||
126 | ands ip, r1, #3 | ||
127 | beq 1b | ||
128 | |||
129 | 10: bic r1, r1, #3 | ||
130 | cmp ip, #2 | ||
131 | ldr r3, [r1, #0] | ||
132 | beq 17f | ||
133 | blt 18f | ||
134 | |||
135 | |||
136 | .macro backward_copy_shift push pull | ||
137 | |||
138 | subs r2, r2, #28 | ||
139 | blt 14f | ||
140 | |||
141 | CALGN( ands ip, r1, #31 ) | ||
142 | CALGN( rsb ip, ip, #32 ) | ||
143 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
144 | CALGN( subcc r2, r2, ip ) | ||
145 | CALGN( bcc 15f ) | ||
146 | |||
147 | 11: stmfd sp!, {r5 - r9} | ||
148 | |||
149 | PLD( pld [r1, #-4] ) | ||
150 | PLD( subs r2, r2, #96 ) | ||
151 | PLD( pld [r1, #-32] ) | ||
152 | PLD( blt 13f ) | ||
153 | PLD( pld [r1, #-64] ) | ||
154 | PLD( pld [r1, #-96] ) | ||
155 | |||
156 | 12: PLD( pld [r1, #-128] ) | ||
157 | 13: ldmdb r1!, {r7, r8, r9, ip} | ||
158 | mov lr, r3, push #\push | ||
159 | subs r2, r2, #32 | ||
160 | ldmdb r1!, {r3, r4, r5, r6} | ||
161 | orr lr, lr, ip, pull #\pull | ||
162 | mov ip, ip, push #\push | ||
163 | orr ip, ip, r9, pull #\pull | ||
164 | mov r9, r9, push #\push | ||
165 | orr r9, r9, r8, pull #\pull | ||
166 | mov r8, r8, push #\push | ||
167 | orr r8, r8, r7, pull #\pull | ||
168 | mov r7, r7, push #\push | ||
169 | orr r7, r7, r6, pull #\pull | ||
170 | mov r6, r6, push #\push | ||
171 | orr r6, r6, r5, pull #\pull | ||
172 | mov r5, r5, push #\push | ||
173 | orr r5, r5, r4, pull #\pull | ||
174 | mov r4, r4, push #\push | ||
175 | orr r4, r4, r3, pull #\pull | ||
176 | stmdb r0!, {r4 - r9, ip, lr} | ||
177 | bge 12b | ||
178 | PLD( cmn r2, #96 ) | ||
179 | PLD( bge 13b ) | ||
180 | |||
181 | ldmfd sp!, {r5 - r9} | ||
182 | |||
183 | 14: ands ip, r2, #28 | ||
184 | beq 16f | ||
185 | |||
186 | 15: mov lr, r3, push #\push | ||
187 | ldr r3, [r1, #-4]! | ||
188 | subs ip, ip, #4 | ||
189 | orr lr, lr, r3, pull #\pull | ||
190 | str lr, [r0, #-4]! | ||
191 | bgt 15b | ||
192 | CALGN( cmp r2, #0 ) | ||
193 | CALGN( bge 11b ) | ||
194 | |||
195 | 16: add r1, r1, #(\pull / 8) | ||
196 | b 8b | ||
197 | |||
198 | .endm | ||
199 | |||
200 | |||
201 | backward_copy_shift push=8 pull=24 | ||
202 | |||
203 | 17: backward_copy_shift push=16 pull=16 | ||
204 | |||
205 | 18: backward_copy_shift push=24 pull=8 | ||
206 | |||
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S index d3ed0636c008..c28449157bea 100644 --- a/arch/arm/lib/uaccess.S +++ b/arch/arm/lib/uaccess.S | |||
@@ -657,41 +657,3 @@ USER( ldrgtbt r3, [r1], #1) @ May fault | |||
657 | LOADREGS(fd,sp!, {r4 - r7, pc}) | 657 | LOADREGS(fd,sp!, {r4 - r7, pc}) |
658 | .previous | 658 | .previous |
659 | 659 | ||
660 | /* Prototype: int __arch_clear_user(void *addr, size_t sz) | ||
661 | * Purpose : clear some user memory | ||
662 | * Params : addr - user memory address to clear | ||
663 | * : sz - number of bytes to clear | ||
664 | * Returns : number of bytes NOT cleared | ||
665 | */ | ||
666 | ENTRY(__arch_clear_user) | ||
667 | stmfd sp!, {r1, lr} | ||
668 | mov r2, #0 | ||
669 | cmp r1, #4 | ||
670 | blt 2f | ||
671 | ands ip, r0, #3 | ||
672 | beq 1f | ||
673 | cmp ip, #2 | ||
674 | USER( strbt r2, [r0], #1) | ||
675 | USER( strlebt r2, [r0], #1) | ||
676 | USER( strltbt r2, [r0], #1) | ||
677 | rsb ip, ip, #4 | ||
678 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
679 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
680 | USER( strplt r2, [r0], #4) | ||
681 | USER( strplt r2, [r0], #4) | ||
682 | bpl 1b | ||
683 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
684 | USER( strplt r2, [r0], #4) | ||
685 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
686 | USER( strnebt r2, [r0], #1) | ||
687 | USER( strnebt r2, [r0], #1) | ||
688 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
689 | USER( strnebt r2, [r0], #1) | ||
690 | mov r0, #0 | ||
691 | LOADREGS(fd,sp!, {r1, pc}) | ||
692 | |||
693 | .section .fixup,"ax" | ||
694 | .align 0 | ||
695 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
696 | .previous | ||
697 | |||
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c index 0c53dab80905..4e706d9ad368 100644 --- a/arch/arm/mach-aaec2000/core.c +++ b/arch/arm/mach-aaec2000/core.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 15261646dcdd..ed4614983adb 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c | |||
@@ -251,9 +251,33 @@ static struct platform_device serial_device = { | |||
251 | }, | 251 | }, |
252 | }; | 252 | }; |
253 | 253 | ||
254 | static struct resource am79c961_resources[] = { | ||
255 | { | ||
256 | .start = 0x220, | ||
257 | .end = 0x238, | ||
258 | .flags = IORESOURCE_IO, | ||
259 | }, { | ||
260 | .start = IRQ_EBSA110_ETHERNET, | ||
261 | .end = IRQ_EBSA110_ETHERNET, | ||
262 | .flags = IORESOURCE_IRQ, | ||
263 | }, | ||
264 | }; | ||
265 | |||
266 | static struct platform_device am79c961_device = { | ||
267 | .name = "am79c961", | ||
268 | .id = -1, | ||
269 | .num_resources = ARRAY_SIZE(am79c961_resources), | ||
270 | .resource = am79c961_resources, | ||
271 | }; | ||
272 | |||
273 | static struct platform_device *ebsa110_devices[] = { | ||
274 | &serial_device, | ||
275 | &am79c961_device, | ||
276 | }; | ||
277 | |||
254 | static int __init ebsa110_init(void) | 278 | static int __init ebsa110_init(void) |
255 | { | 279 | { |
256 | return platform_device_register(&serial_device); | 280 | return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices)); |
257 | } | 281 | } |
258 | 282 | ||
259 | arch_initcall(ebsa110_init); | 283 | arch_initcall(ebsa110_init); |
diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c index db9078ad008c..d75c8221d2a5 100644 --- a/arch/arm/mach-h720x/h7202-eval.c +++ b/arch/arm/mach-h720x/h7202-eval.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/types.h> | 19 | #include <linux/types.h> |
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/device.h> | 21 | #include <linux/platform_device.h> |
22 | 22 | ||
23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
24 | #include <asm/types.h> | 24 | #include <asm/types.h> |
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 837d7f0bda4c..37613ad68366 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | #include <linux/device.h> | 25 | #include <linux/platform_device.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index 4cbdc1fe04b1..708e1b3faa14 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/platform_device.h> | ||
17 | #include <asm/system.h> | 18 | #include <asm/system.h> |
18 | #include <asm/hardware.h> | 19 | #include <asm/hardware.h> |
19 | #include <asm/irq.h> | 20 | #include <asm/irq.h> |
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 764ceb49470a..4c0f7c65facf 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
27 | #include <linux/sysdev.h> | 27 | #include <linux/sysdev.h> |
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index aa34c58b96c4..93f7ccb22c27 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c index bb5091223b63..80770233b8d4 100644 --- a/arch/arm/mach-iop3xx/iop321-setup.c +++ b/arch/arm/mach-iop3xx/iop321-setup.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/major.h> | 17 | #include <linux/major.h> |
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/serial.h> | 20 | #include <linux/serial.h> |
21 | #include <linux/tty.h> | 21 | #include <linux/tty.h> |
22 | #include <linux/serial_core.h> | 22 | #include <linux/serial_core.h> |
diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c index a2533c3ab42f..53f60614498b 100644 --- a/arch/arm/mach-iop3xx/iop331-setup.c +++ b/arch/arm/mach-iop3xx/iop331-setup.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/major.h> | 16 | #include <linux/major.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/serial.h> | 19 | #include <linux/serial.h> |
20 | #include <linux/tty.h> | 20 | #include <linux/tty.h> |
21 | #include <linux/serial_core.h> | 21 | #include <linux/serial_core.h> |
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile index 1e6139d42a92..9621aeb61f46 100644 --- a/arch/arm/mach-ixp2000/Makefile +++ b/arch/arm/mach-ixp2000/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
3 | # | 3 | # |
4 | obj-y := core.o pci.o | 4 | obj-y := core.o pci.o uengine.o |
5 | obj-m := | 5 | obj-m := |
6 | obj-n := | 6 | obj-n := |
7 | obj- := | 7 | obj- := |
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 01c393c504d0..c93a98b2a32c 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/arm/mach-ixp2000/common.c | 2 | * arch/arm/mach-ixp2000/core.c |
3 | * | 3 | * |
4 | * Common routines used by all IXP2400/2800 based platforms. | 4 | * Common routines used by all IXP2400/2800 based platforms. |
5 | * | 5 | * |
@@ -49,7 +49,6 @@ static unsigned long ixp2000_slowport_irq_flags; | |||
49 | *************************************************************************/ | 49 | *************************************************************************/ |
50 | void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) | 50 | void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) |
51 | { | 51 | { |
52 | |||
53 | spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); | 52 | spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); |
54 | 53 | ||
55 | old_cfg->CCR = *IXP2000_SLOWPORT_CCR; | 54 | old_cfg->CCR = *IXP2000_SLOWPORT_CCR; |
@@ -62,7 +61,7 @@ void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg | |||
62 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); | 61 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); |
63 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); | 62 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); |
64 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); | 63 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); |
65 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC); | 64 | ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC); |
66 | } | 65 | } |
67 | 66 | ||
68 | void ixp2000_release_slowport(struct slowport_cfg *old_cfg) | 67 | void ixp2000_release_slowport(struct slowport_cfg *old_cfg) |
@@ -71,7 +70,7 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg) | |||
71 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); | 70 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); |
72 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); | 71 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); |
73 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); | 72 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); |
74 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC); | 73 | ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC); |
75 | 74 | ||
76 | spin_unlock_irqrestore(&ixp2000_slowport_lock, | 75 | spin_unlock_irqrestore(&ixp2000_slowport_lock, |
77 | ixp2000_slowport_irq_flags); | 76 | ixp2000_slowport_irq_flags); |
@@ -145,7 +144,7 @@ void __init ixp2000_map_io(void) | |||
145 | iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); | 144 | iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); |
146 | 145 | ||
147 | /* Set slowport to 8-bit mode. */ | 146 | /* Set slowport to 8-bit mode. */ |
148 | ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); | 147 | ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1); |
149 | } | 148 | } |
150 | 149 | ||
151 | 150 | ||
@@ -209,7 +208,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
209 | write_seqlock(&xtime_lock); | 208 | write_seqlock(&xtime_lock); |
210 | 209 | ||
211 | /* clear timer 1 */ | 210 | /* clear timer 1 */ |
212 | ixp2000_reg_write(IXP2000_T1_CLR, 1); | 211 | ixp2000_reg_wrb(IXP2000_T1_CLR, 1); |
213 | 212 | ||
214 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { | 213 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { |
215 | timer_tick(regs); | 214 | timer_tick(regs); |
@@ -252,12 +251,12 @@ void __init ixp2000_init_time(unsigned long tick_rate) | |||
252 | 251 | ||
253 | ixp2000_reg_write(IXP2000_T4_CLR, 0); | 252 | ixp2000_reg_write(IXP2000_T4_CLR, 0); |
254 | ixp2000_reg_write(IXP2000_T4_CLD, -1); | 253 | ixp2000_reg_write(IXP2000_T4_CLD, -1); |
255 | ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); | 254 | ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7)); |
256 | missing_jiffy_timer_csr = IXP2000_T4_CSR; | 255 | missing_jiffy_timer_csr = IXP2000_T4_CSR; |
257 | } else { | 256 | } else { |
258 | ixp2000_reg_write(IXP2000_T2_CLR, 0); | 257 | ixp2000_reg_write(IXP2000_T2_CLR, 0); |
259 | ixp2000_reg_write(IXP2000_T2_CLD, -1); | 258 | ixp2000_reg_write(IXP2000_T2_CLD, -1); |
260 | ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); | 259 | ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7)); |
261 | missing_jiffy_timer_csr = IXP2000_T2_CSR; | 260 | missing_jiffy_timer_csr = IXP2000_T2_CSR; |
262 | } | 261 | } |
263 | next_jiffy_time = 0xffffffff; | 262 | next_jiffy_time = 0xffffffff; |
@@ -279,7 +278,7 @@ static void update_gpio_int_csrs(void) | |||
279 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); | 278 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); |
280 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); | 279 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); |
281 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); | 280 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); |
282 | ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); | 281 | ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); |
283 | } | 282 | } |
284 | 283 | ||
285 | void gpio_line_config(int line, int direction) | 284 | void gpio_line_config(int line, int direction) |
@@ -297,9 +296,9 @@ void gpio_line_config(int line, int direction) | |||
297 | GPIO_IRQ_level_high &= ~(1 << line); | 296 | GPIO_IRQ_level_high &= ~(1 << line); |
298 | update_gpio_int_csrs(); | 297 | update_gpio_int_csrs(); |
299 | 298 | ||
300 | ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line); | 299 | ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line); |
301 | } else if (direction == GPIO_IN) { | 300 | } else if (direction == GPIO_IN) { |
302 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); | 301 | ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line); |
303 | } | 302 | } |
304 | local_irq_restore(flags); | 303 | local_irq_restore(flags); |
305 | } | 304 | } |
@@ -365,12 +364,12 @@ static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) | |||
365 | 364 | ||
366 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 365 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
367 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 366 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
368 | ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); | 367 | ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); |
369 | } | 368 | } |
370 | 369 | ||
371 | static void ixp2000_GPIO_irq_mask(unsigned int irq) | 370 | static void ixp2000_GPIO_irq_mask(unsigned int irq) |
372 | { | 371 | { |
373 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 372 | ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
374 | } | 373 | } |
375 | 374 | ||
376 | static void ixp2000_GPIO_irq_unmask(unsigned int irq) | 375 | static void ixp2000_GPIO_irq_unmask(unsigned int irq) |
@@ -389,9 +388,9 @@ static void ixp2000_pci_irq_mask(unsigned int irq) | |||
389 | { | 388 | { |
390 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; | 389 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; |
391 | if (irq == IRQ_IXP2000_PCIA) | 390 | if (irq == IRQ_IXP2000_PCIA) |
392 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); | 391 | ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); |
393 | else if (irq == IRQ_IXP2000_PCIB) | 392 | else if (irq == IRQ_IXP2000_PCIB) |
394 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); | 393 | ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); |
395 | } | 394 | } |
396 | 395 | ||
397 | static void ixp2000_pci_irq_unmask(unsigned int irq) | 396 | static void ixp2000_pci_irq_unmask(unsigned int irq) |
@@ -411,7 +410,7 @@ static struct irqchip ixp2000_pci_irq_chip = { | |||
411 | 410 | ||
412 | static void ixp2000_irq_mask(unsigned int irq) | 411 | static void ixp2000_irq_mask(unsigned int irq) |
413 | { | 412 | { |
414 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); | 413 | ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); |
415 | } | 414 | } |
416 | 415 | ||
417 | static void ixp2000_irq_unmask(unsigned int irq) | 416 | static void ixp2000_irq_unmask(unsigned int irq) |
@@ -443,7 +442,7 @@ void __init ixp2000_init_irq(void) | |||
443 | ixp2000_reg_write(IXP2000_GPIO_INCR, -1); | 442 | ixp2000_reg_write(IXP2000_GPIO_INCR, -1); |
444 | 443 | ||
445 | /* clear PCI interrupt sources */ | 444 | /* clear PCI interrupt sources */ |
446 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0); | 445 | ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0); |
447 | 446 | ||
448 | /* | 447 | /* |
449 | * Certain bits in the IRQ status register of the | 448 | * Certain bits in the IRQ status register of the |
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index 9aa54de44740..7719c478aa84 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/serial.h> | 32 | #include <linux/serial.h> |
33 | #include <linux/tty.h> | 33 | #include <linux/tty.h> |
34 | #include <linux/serial_core.h> | 34 | #include <linux/serial_core.h> |
35 | #include <linux/device.h> | 35 | #include <linux/platform_device.h> |
36 | 36 | ||
37 | #include <asm/io.h> | 37 | #include <asm/io.h> |
38 | #include <asm/irq.h> | 38 | #include <asm/irq.h> |
@@ -64,6 +64,35 @@ static struct sys_timer enp2611_timer = { | |||
64 | 64 | ||
65 | 65 | ||
66 | /************************************************************************* | 66 | /************************************************************************* |
67 | * ENP-2611 I/O | ||
68 | *************************************************************************/ | ||
69 | static struct map_desc enp2611_io_desc[] __initdata = { | ||
70 | { | ||
71 | .virtual = ENP2611_CALEB_VIRT_BASE, | ||
72 | .physical = ENP2611_CALEB_PHYS_BASE, | ||
73 | .length = ENP2611_CALEB_SIZE, | ||
74 | .type = MT_IXP2000_DEVICE | ||
75 | }, { | ||
76 | .virtual = ENP2611_PM3386_0_VIRT_BASE, | ||
77 | .physical = ENP2611_PM3386_0_PHYS_BASE, | ||
78 | .length = ENP2611_PM3386_0_SIZE, | ||
79 | .type = MT_IXP2000_DEVICE | ||
80 | }, { | ||
81 | .virtual = ENP2611_PM3386_1_VIRT_BASE, | ||
82 | .physical = ENP2611_PM3386_1_PHYS_BASE, | ||
83 | .length = ENP2611_PM3386_1_SIZE, | ||
84 | .type = MT_IXP2000_DEVICE | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | void __init enp2611_map_io(void) | ||
89 | { | ||
90 | ixp2000_map_io(); | ||
91 | iotable_init(enp2611_io_desc, ARRAY_SIZE(enp2611_io_desc)); | ||
92 | } | ||
93 | |||
94 | |||
95 | /************************************************************************* | ||
67 | * ENP-2611 PCI | 96 | * ENP-2611 PCI |
68 | *************************************************************************/ | 97 | *************************************************************************/ |
69 | static int enp2611_pci_setup(int nr, struct pci_sys_data *sys) | 98 | static int enp2611_pci_setup(int nr, struct pci_sys_data *sys) |
@@ -229,7 +258,7 @@ MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board") | |||
229 | .phys_io = IXP2000_UART_PHYS_BASE, | 258 | .phys_io = IXP2000_UART_PHYS_BASE, |
230 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, | 259 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, |
231 | .boot_params = 0x00000100, | 260 | .boot_params = 0x00000100, |
232 | .map_io = ixp2000_map_io, | 261 | .map_io = enp2611_map_io, |
233 | .init_irq = ixp2000_init_irq, | 262 | .init_irq = ixp2000_init_irq, |
234 | .timer = &enp2611_timer, | 263 | .timer = &enp2611_timer, |
235 | .init_machine = enp2611_init_machine, | 264 | .init_machine = enp2611_init_machine, |
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 8b4a839b6279..d628da56b4bc 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
@@ -81,7 +81,7 @@ static void ixdp2x00_irq_mask(unsigned int irq) | |||
81 | 81 | ||
82 | dummy = *board_irq_mask; | 82 | dummy = *board_irq_mask; |
83 | dummy |= IXP2000_BOARD_IRQ_MASK(irq); | 83 | dummy |= IXP2000_BOARD_IRQ_MASK(irq); |
84 | ixp2000_reg_write(board_irq_mask, dummy); | 84 | ixp2000_reg_wrb(board_irq_mask, dummy); |
85 | 85 | ||
86 | #ifdef CONFIG_ARCH_IXDP2400 | 86 | #ifdef CONFIG_ARCH_IXDP2400 |
87 | if (machine_is_ixdp2400()) | 87 | if (machine_is_ixdp2400()) |
@@ -101,7 +101,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq) | |||
101 | 101 | ||
102 | dummy = *board_irq_mask; | 102 | dummy = *board_irq_mask; |
103 | dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); | 103 | dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); |
104 | ixp2000_reg_write(board_irq_mask, dummy); | 104 | ixp2000_reg_wrb(board_irq_mask, dummy); |
105 | 105 | ||
106 | if (machine_is_ixdp2400()) | 106 | if (machine_is_ixdp2400()) |
107 | ixp2000_release_slowport(&old_cfg); | 107 | ixp2000_release_slowport(&old_cfg); |
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index fee1d7b73503..e6a882f35da2 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/serial.h> | 29 | #include <linux/serial.h> |
30 | #include <linux/tty.h> | 30 | #include <linux/tty.h> |
31 | #include <linux/serial_core.h> | 31 | #include <linux/serial_core.h> |
32 | #include <linux/device.h> | 32 | #include <linux/platform_device.h> |
33 | 33 | ||
34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
35 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
@@ -51,7 +51,7 @@ | |||
51 | *************************************************************************/ | 51 | *************************************************************************/ |
52 | static void ixdp2x01_irq_mask(unsigned int irq) | 52 | static void ixdp2x01_irq_mask(unsigned int irq) |
53 | { | 53 | { |
54 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, | 54 | ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG, |
55 | IXP2000_BOARD_IRQ_MASK(irq)); | 55 | IXP2000_BOARD_IRQ_MASK(irq)); |
56 | } | 56 | } |
57 | 57 | ||
@@ -114,7 +114,7 @@ void __init ixdp2x01_init_irq(void) | |||
114 | 114 | ||
115 | /* Mask all interrupts from CPLD, disable simulation */ | 115 | /* Mask all interrupts from CPLD, disable simulation */ |
116 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); | 116 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); |
117 | ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0); | 117 | ixp2000_reg_wrb(IXDP2X01_INT_SIM_REG, 0); |
118 | 118 | ||
119 | for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { | 119 | for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { |
120 | if (irq & valid_irq_mask) { | 120 | if (irq & valid_irq_mask) { |
@@ -299,7 +299,6 @@ struct hw_pci ixdp2x01_pci __initdata = { | |||
299 | 299 | ||
300 | int __init ixdp2x01_pci_init(void) | 300 | int __init ixdp2x01_pci_init(void) |
301 | { | 301 | { |
302 | |||
303 | pci_common_init(&ixdp2x01_pci); | 302 | pci_common_init(&ixdp2x01_pci); |
304 | return 0; | 303 | return 0; |
305 | } | 304 | } |
@@ -316,7 +315,7 @@ static struct flash_platform_data ixdp2x01_flash_platform_data = { | |||
316 | 315 | ||
317 | static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) | 316 | static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) |
318 | { | 317 | { |
319 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, | 318 | ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG, |
320 | ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); | 319 | ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); |
321 | return (ofs & IXDP2X01_FLASH_WINDOW_MASK); | 320 | return (ofs & IXDP2X01_FLASH_WINDOW_MASK); |
322 | } | 321 | } |
@@ -363,7 +362,7 @@ static struct platform_device *ixdp2x01_devices[] __initdata = { | |||
363 | 362 | ||
364 | static void __init ixdp2x01_init_machine(void) | 363 | static void __init ixdp2x01_init_machine(void) |
365 | { | 364 | { |
366 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, | 365 | ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG, |
367 | (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); | 366 | (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); |
368 | 367 | ||
369 | ixdp2x01_flash_data.nr_banks = | 368 | ixdp2x01_flash_data.nr_banks = |
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 522205acb316..d4bf1e1c0031 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c | |||
@@ -148,7 +148,7 @@ int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_re | |||
148 | local_irq_save(flags); | 148 | local_irq_save(flags); |
149 | temp = *(IXP2000_PCI_CONTROL); | 149 | temp = *(IXP2000_PCI_CONTROL); |
150 | if (temp & ((1 << 8) | (1 << 5))) { | 150 | if (temp & ((1 << 8) | (1 << 5))) { |
151 | ixp2000_reg_write(IXP2000_PCI_CONTROL, temp); | 151 | ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp); |
152 | } | 152 | } |
153 | 153 | ||
154 | temp = *(IXP2000_PCI_CMDSTAT); | 154 | temp = *(IXP2000_PCI_CMDSTAT); |
@@ -178,8 +178,8 @@ clear_master_aborts(void) | |||
178 | 178 | ||
179 | local_irq_save(flags); | 179 | local_irq_save(flags); |
180 | temp = *(IXP2000_PCI_CONTROL); | 180 | temp = *(IXP2000_PCI_CONTROL); |
181 | if (temp & ((1 << 8) | (1 << 5))) { | 181 | if (temp & ((1 << 8) | (1 << 5))) { |
182 | ixp2000_reg_write(IXP2000_PCI_CONTROL, temp); | 182 | ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp); |
183 | } | 183 | } |
184 | 184 | ||
185 | temp = *(IXP2000_PCI_CMDSTAT); | 185 | temp = *(IXP2000_PCI_CMDSTAT); |
diff --git a/arch/arm/mach-ixp2000/uengine.c b/arch/arm/mach-ixp2000/uengine.c new file mode 100644 index 000000000000..43e234349d4a --- /dev/null +++ b/arch/arm/mach-ixp2000/uengine.c | |||
@@ -0,0 +1,474 @@ | |||
1 | /* | ||
2 | * Generic library functions for the microengines found on the Intel | ||
3 | * IXP2000 series of network processors. | ||
4 | * | ||
5 | * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org> | ||
6 | * Dedicated to Marija Kulikova. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU Lesser General Public License as | ||
10 | * published by the Free Software Foundation; either version 2.1 of the | ||
11 | * License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <asm/hardware.h> | ||
21 | #include <asm/arch/ixp2000-regs.h> | ||
22 | #include <asm/arch/uengine.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | #define USTORE_ADDRESS 0x000 | ||
26 | #define USTORE_DATA_LOWER 0x004 | ||
27 | #define USTORE_DATA_UPPER 0x008 | ||
28 | #define CTX_ENABLES 0x018 | ||
29 | #define CC_ENABLE 0x01c | ||
30 | #define CSR_CTX_POINTER 0x020 | ||
31 | #define INDIRECT_CTX_STS 0x040 | ||
32 | #define ACTIVE_CTX_STS 0x044 | ||
33 | #define INDIRECT_CTX_SIG_EVENTS 0x048 | ||
34 | #define INDIRECT_CTX_WAKEUP_EVENTS 0x050 | ||
35 | #define NN_PUT 0x080 | ||
36 | #define NN_GET 0x084 | ||
37 | #define TIMESTAMP_LOW 0x0c0 | ||
38 | #define TIMESTAMP_HIGH 0x0c4 | ||
39 | #define T_INDEX_BYTE_INDEX 0x0f4 | ||
40 | #define LOCAL_CSR_STATUS 0x180 | ||
41 | |||
42 | u32 ixp2000_uengine_mask; | ||
43 | |||
44 | static void *ixp2000_uengine_csr_area(int uengine) | ||
45 | { | ||
46 | return ((void *)IXP2000_UENGINE_CSR_VIRT_BASE) + (uengine << 10); | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR | ||
51 | * space means that the microengine we tried to access was also trying | ||
52 | * to access its own CSR space on the same clock cycle as we did. When | ||
53 | * this happens, we lose the arbitration process by default, and the | ||
54 | * read or write we tried to do was not actually performed, so we try | ||
55 | * again until it succeeds. | ||
56 | */ | ||
57 | u32 ixp2000_uengine_csr_read(int uengine, int offset) | ||
58 | { | ||
59 | void *uebase; | ||
60 | u32 *local_csr_status; | ||
61 | u32 *reg; | ||
62 | u32 value; | ||
63 | |||
64 | uebase = ixp2000_uengine_csr_area(uengine); | ||
65 | |||
66 | local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS); | ||
67 | reg = (u32 *)(uebase + offset); | ||
68 | do { | ||
69 | value = ixp2000_reg_read(reg); | ||
70 | } while (ixp2000_reg_read(local_csr_status) & 1); | ||
71 | |||
72 | return value; | ||
73 | } | ||
74 | EXPORT_SYMBOL(ixp2000_uengine_csr_read); | ||
75 | |||
76 | void ixp2000_uengine_csr_write(int uengine, int offset, u32 value) | ||
77 | { | ||
78 | void *uebase; | ||
79 | u32 *local_csr_status; | ||
80 | u32 *reg; | ||
81 | |||
82 | uebase = ixp2000_uengine_csr_area(uengine); | ||
83 | |||
84 | local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS); | ||
85 | reg = (u32 *)(uebase + offset); | ||
86 | do { | ||
87 | ixp2000_reg_write(reg, value); | ||
88 | } while (ixp2000_reg_read(local_csr_status) & 1); | ||
89 | } | ||
90 | EXPORT_SYMBOL(ixp2000_uengine_csr_write); | ||
91 | |||
92 | void ixp2000_uengine_reset(u32 uengine_mask) | ||
93 | { | ||
94 | ixp2000_reg_write(IXP2000_RESET1, uengine_mask & ixp2000_uengine_mask); | ||
95 | ixp2000_reg_write(IXP2000_RESET1, 0); | ||
96 | } | ||
97 | EXPORT_SYMBOL(ixp2000_uengine_reset); | ||
98 | |||
99 | void ixp2000_uengine_set_mode(int uengine, u32 mode) | ||
100 | { | ||
101 | /* | ||
102 | * CTL_STR_PAR_EN: unconditionally enable parity checking on | ||
103 | * control store. | ||
104 | */ | ||
105 | mode |= 0x10000000; | ||
106 | ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode); | ||
107 | |||
108 | /* | ||
109 | * Enable updating of condition codes. | ||
110 | */ | ||
111 | ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000); | ||
112 | |||
113 | /* | ||
114 | * Initialise other per-microengine registers. | ||
115 | */ | ||
116 | ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00); | ||
117 | ixp2000_uengine_csr_write(uengine, NN_GET, 0x00); | ||
118 | ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0); | ||
119 | } | ||
120 | EXPORT_SYMBOL(ixp2000_uengine_set_mode); | ||
121 | |||
122 | static int make_even_parity(u32 x) | ||
123 | { | ||
124 | return hweight32(x) & 1; | ||
125 | } | ||
126 | |||
127 | static void ustore_write(int uengine, u64 insn) | ||
128 | { | ||
129 | /* | ||
130 | * Generate even parity for top and bottom 20 bits. | ||
131 | */ | ||
132 | insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41; | ||
133 | insn |= (u64)make_even_parity(insn & 0x000fffff) << 40; | ||
134 | |||
135 | /* | ||
136 | * Write to microstore. The second write auto-increments | ||
137 | * the USTORE_ADDRESS index register. | ||
138 | */ | ||
139 | ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn); | ||
140 | ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32)); | ||
141 | } | ||
142 | |||
143 | void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns) | ||
144 | { | ||
145 | int i; | ||
146 | |||
147 | /* | ||
148 | * Start writing to microstore at address 0. | ||
149 | */ | ||
150 | ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000); | ||
151 | for (i = 0; i < insns; i++) { | ||
152 | u64 insn; | ||
153 | |||
154 | insn = (((u64)ucode[0]) << 32) | | ||
155 | (((u64)ucode[1]) << 24) | | ||
156 | (((u64)ucode[2]) << 16) | | ||
157 | (((u64)ucode[3]) << 8) | | ||
158 | ((u64)ucode[4]); | ||
159 | ucode += 5; | ||
160 | |||
161 | ustore_write(uengine, insn); | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Pad with a few NOPs at the end (to avoid the microengine | ||
166 | * aborting as it prefetches beyond the last instruction), unless | ||
167 | * we run off the end of the instruction store first, at which | ||
168 | * point the address register will wrap back to zero. | ||
169 | */ | ||
170 | for (i = 0; i < 4; i++) { | ||
171 | u32 addr; | ||
172 | |||
173 | addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS); | ||
174 | if (addr == 0x80000000) | ||
175 | break; | ||
176 | ustore_write(uengine, 0xf0000c0300ULL); | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * End programming. | ||
181 | */ | ||
182 | ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000); | ||
183 | } | ||
184 | EXPORT_SYMBOL(ixp2000_uengine_load_microcode); | ||
185 | |||
186 | void ixp2000_uengine_init_context(int uengine, int context, int pc) | ||
187 | { | ||
188 | /* | ||
189 | * Select the right context for indirect access. | ||
190 | */ | ||
191 | ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context); | ||
192 | |||
193 | /* | ||
194 | * Initialise signal masks to immediately go to Ready state. | ||
195 | */ | ||
196 | ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1); | ||
197 | ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1); | ||
198 | |||
199 | /* | ||
200 | * Set program counter. | ||
201 | */ | ||
202 | ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc); | ||
203 | } | ||
204 | EXPORT_SYMBOL(ixp2000_uengine_init_context); | ||
205 | |||
206 | void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask) | ||
207 | { | ||
208 | u32 mask; | ||
209 | |||
210 | /* | ||
211 | * Enable the specified context to go to Executing state. | ||
212 | */ | ||
213 | mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES); | ||
214 | mask |= ctx_mask << 8; | ||
215 | ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask); | ||
216 | } | ||
217 | EXPORT_SYMBOL(ixp2000_uengine_start_contexts); | ||
218 | |||
219 | void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask) | ||
220 | { | ||
221 | u32 mask; | ||
222 | |||
223 | /* | ||
224 | * Disable the Ready->Executing transition. Note that this | ||
225 | * does not stop the context until it voluntarily yields. | ||
226 | */ | ||
227 | mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES); | ||
228 | mask &= ~(ctx_mask << 8); | ||
229 | ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask); | ||
230 | } | ||
231 | EXPORT_SYMBOL(ixp2000_uengine_stop_contexts); | ||
232 | |||
233 | static int check_ixp_type(struct ixp2000_uengine_code *c) | ||
234 | { | ||
235 | u32 product_id; | ||
236 | u32 rev; | ||
237 | |||
238 | product_id = ixp2000_reg_read(IXP2000_PRODUCT_ID); | ||
239 | if (((product_id >> 16) & 0x1f) != 0) | ||
240 | return 0; | ||
241 | |||
242 | switch ((product_id >> 8) & 0xff) { | ||
243 | case 0: /* IXP2800 */ | ||
244 | if (!(c->cpu_model_bitmask & 4)) | ||
245 | return 0; | ||
246 | break; | ||
247 | |||
248 | case 1: /* IXP2850 */ | ||
249 | if (!(c->cpu_model_bitmask & 8)) | ||
250 | return 0; | ||
251 | break; | ||
252 | |||
253 | case 2: /* IXP2400 */ | ||
254 | if (!(c->cpu_model_bitmask & 2)) | ||
255 | return 0; | ||
256 | break; | ||
257 | |||
258 | default: | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | rev = product_id & 0xff; | ||
263 | if (rev < c->cpu_min_revision || rev > c->cpu_max_revision) | ||
264 | return 0; | ||
265 | |||
266 | return 1; | ||
267 | } | ||
268 | |||
269 | static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b) | ||
270 | { | ||
271 | int offset; | ||
272 | int i; | ||
273 | |||
274 | offset = 0; | ||
275 | |||
276 | for (i = 0; i < 128; i++) { | ||
277 | u8 b3; | ||
278 | u8 b2; | ||
279 | u8 b1; | ||
280 | u8 b0; | ||
281 | |||
282 | b3 = (gpr_a[i] >> 24) & 0xff; | ||
283 | b2 = (gpr_a[i] >> 16) & 0xff; | ||
284 | b1 = (gpr_a[i] >> 8) & 0xff; | ||
285 | b0 = gpr_a[i] & 0xff; | ||
286 | |||
287 | // immed[@ai, (b1 << 8) | b0] | ||
288 | // 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII | ||
289 | ucode[offset++] = 0xf0; | ||
290 | ucode[offset++] = (b1 >> 4); | ||
291 | ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6); | ||
292 | ucode[offset++] = (b0 << 2); | ||
293 | ucode[offset++] = 0x80 | i; | ||
294 | |||
295 | // immed_w1[@ai, (b3 << 8) | b2] | ||
296 | // 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII | ||
297 | ucode[offset++] = 0xf4; | ||
298 | ucode[offset++] = 0x40 | (b3 >> 4); | ||
299 | ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6); | ||
300 | ucode[offset++] = (b2 << 2); | ||
301 | ucode[offset++] = 0x80 | i; | ||
302 | } | ||
303 | |||
304 | for (i = 0; i < 128; i++) { | ||
305 | u8 b3; | ||
306 | u8 b2; | ||
307 | u8 b1; | ||
308 | u8 b0; | ||
309 | |||
310 | b3 = (gpr_b[i] >> 24) & 0xff; | ||
311 | b2 = (gpr_b[i] >> 16) & 0xff; | ||
312 | b1 = (gpr_b[i] >> 8) & 0xff; | ||
313 | b0 = gpr_b[i] & 0xff; | ||
314 | |||
315 | // immed[@bi, (b1 << 8) | b0] | ||
316 | // 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV | ||
317 | ucode[offset++] = 0xf0; | ||
318 | ucode[offset++] = (b1 >> 4); | ||
319 | ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6); | ||
320 | ucode[offset++] = (i << 2) | 0x03; | ||
321 | ucode[offset++] = b0; | ||
322 | |||
323 | // immed_w1[@bi, (b3 << 8) | b2] | ||
324 | // 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV | ||
325 | ucode[offset++] = 0xf4; | ||
326 | ucode[offset++] = 0x40 | (b3 >> 4); | ||
327 | ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6); | ||
328 | ucode[offset++] = (i << 2) | 0x03; | ||
329 | ucode[offset++] = b2; | ||
330 | } | ||
331 | |||
332 | // ctx_arb[kill] | ||
333 | ucode[offset++] = 0xe0; | ||
334 | ucode[offset++] = 0x00; | ||
335 | ucode[offset++] = 0x01; | ||
336 | ucode[offset++] = 0x00; | ||
337 | ucode[offset++] = 0x00; | ||
338 | } | ||
339 | |||
340 | static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c) | ||
341 | { | ||
342 | int per_ctx_regs; | ||
343 | u32 *gpr_a; | ||
344 | u32 *gpr_b; | ||
345 | u8 *ucode; | ||
346 | int i; | ||
347 | |||
348 | gpr_a = kmalloc(128 * sizeof(u32), GFP_KERNEL); | ||
349 | gpr_b = kmalloc(128 * sizeof(u32), GFP_KERNEL); | ||
350 | ucode = kmalloc(513 * 5, GFP_KERNEL); | ||
351 | if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) { | ||
352 | kfree(ucode); | ||
353 | kfree(gpr_b); | ||
354 | kfree(gpr_a); | ||
355 | return 1; | ||
356 | } | ||
357 | |||
358 | per_ctx_regs = 16; | ||
359 | if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS) | ||
360 | per_ctx_regs = 32; | ||
361 | |||
362 | memset(gpr_a, 0, sizeof(gpr_a)); | ||
363 | memset(gpr_b, 0, sizeof(gpr_b)); | ||
364 | for (i = 0; i < 256; i++) { | ||
365 | struct ixp2000_reg_value *r = c->initial_reg_values + i; | ||
366 | u32 *bank; | ||
367 | int inc; | ||
368 | int j; | ||
369 | |||
370 | if (r->reg == -1) | ||
371 | break; | ||
372 | |||
373 | bank = (r->reg & 0x400) ? gpr_b : gpr_a; | ||
374 | inc = (r->reg & 0x80) ? 128 : per_ctx_regs; | ||
375 | |||
376 | j = r->reg & 0x7f; | ||
377 | while (j < 128) { | ||
378 | bank[j] = r->value; | ||
379 | j += inc; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | generate_ucode(ucode, gpr_a, gpr_b); | ||
384 | ixp2000_uengine_load_microcode(uengine, ucode, 513); | ||
385 | ixp2000_uengine_init_context(uengine, 0, 0); | ||
386 | ixp2000_uengine_start_contexts(uengine, 0x01); | ||
387 | for (i = 0; i < 100; i++) { | ||
388 | u32 status; | ||
389 | |||
390 | status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS); | ||
391 | if (!(status & 0x80000000)) | ||
392 | break; | ||
393 | } | ||
394 | ixp2000_uengine_stop_contexts(uengine, 0x01); | ||
395 | |||
396 | kfree(ucode); | ||
397 | kfree(gpr_b); | ||
398 | kfree(gpr_a); | ||
399 | |||
400 | return !!(i == 100); | ||
401 | } | ||
402 | |||
403 | int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c) | ||
404 | { | ||
405 | int ctx; | ||
406 | |||
407 | if (!check_ixp_type(c)) | ||
408 | return 1; | ||
409 | |||
410 | if (!(ixp2000_uengine_mask & (1 << uengine))) | ||
411 | return 1; | ||
412 | |||
413 | ixp2000_uengine_reset(1 << uengine); | ||
414 | ixp2000_uengine_set_mode(uengine, c->uengine_parameters); | ||
415 | if (set_initial_registers(uengine, c)) | ||
416 | return 1; | ||
417 | ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns); | ||
418 | |||
419 | for (ctx = 0; ctx < 8; ctx++) | ||
420 | ixp2000_uengine_init_context(uengine, ctx, 0); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | EXPORT_SYMBOL(ixp2000_uengine_load); | ||
425 | |||
426 | |||
427 | static int __init ixp2000_uengine_init(void) | ||
428 | { | ||
429 | int uengine; | ||
430 | u32 value; | ||
431 | |||
432 | /* | ||
433 | * Determine number of microengines present. | ||
434 | */ | ||
435 | switch ((ixp2000_reg_read(IXP2000_PRODUCT_ID) >> 8) & 0x1fff) { | ||
436 | case 0: /* IXP2800 */ | ||
437 | case 1: /* IXP2850 */ | ||
438 | ixp2000_uengine_mask = 0x00ff00ff; | ||
439 | break; | ||
440 | |||
441 | case 2: /* IXP2400 */ | ||
442 | ixp2000_uengine_mask = 0x000f000f; | ||
443 | break; | ||
444 | |||
445 | default: | ||
446 | printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n", | ||
447 | (unsigned int)ixp2000_reg_read(IXP2000_PRODUCT_ID)); | ||
448 | ixp2000_uengine_mask = 0x00000000; | ||
449 | break; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * Reset microengines. | ||
454 | */ | ||
455 | ixp2000_reg_write(IXP2000_RESET1, ixp2000_uengine_mask); | ||
456 | ixp2000_reg_write(IXP2000_RESET1, 0); | ||
457 | |||
458 | /* | ||
459 | * Synchronise timestamp counters across all microengines. | ||
460 | */ | ||
461 | value = ixp2000_reg_read(IXP2000_MISC_CONTROL); | ||
462 | ixp2000_reg_write(IXP2000_MISC_CONTROL, value & ~0x80); | ||
463 | for (uengine = 0; uengine < 32; uengine++) { | ||
464 | if (ixp2000_uengine_mask & (1 << uengine)) { | ||
465 | ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0); | ||
466 | ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0); | ||
467 | } | ||
468 | } | ||
469 | ixp2000_reg_write(IXP2000_MISC_CONTROL, value | 0x80); | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | subsys_initcall(ixp2000_uengine_init); | ||
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 6c396447c4e0..f3c687cf0071 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/serial.h> | 20 | #include <linux/serial.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/tty.h> | 22 | #include <linux/tty.h> |
23 | #include <linux/platform_device.h> | ||
23 | #include <linux/serial_core.h> | 24 | #include <linux/serial_core.h> |
24 | #include <linux/bootmem.h> | 25 | #include <linux/bootmem.h> |
25 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c index a20eabc132b0..4eb962fdb3a8 100644 --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c | |||
@@ -10,7 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/tty.h> | 11 | #include <linux/tty.h> |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | 15 | ||
16 | #include <asm/hardware.h> | 16 | #include <asm/hardware.h> |
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index d46a70063b0c..4ee6bd8a50b8 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
26 | #include <linux/mtd/mtd.h> | 26 | #include <linux/mtd/mtd.h> |
27 | #include <linux/mtd/partitions.h> | 27 | #include <linux/mtd/partitions.h> |
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 2798613696fa..fc824361430d 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/major.h> | 20 | #include <linux/major.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/mtd/mtd.h> | 24 | #include <linux/mtd/mtd.h> |
25 | #include <linux/mtd/partitions.h> | 25 | #include <linux/mtd/partitions.h> |
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index fd9183ff2ed5..a2eac853b2da 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c | |||
@@ -18,7 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/mtd/mtd.h> | 23 | #include <linux/mtd/mtd.h> |
24 | #include <linux/mtd/partitions.h> | 24 | #include <linux/mtd/partitions.h> |
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index d904e643f5ec..c851c2e4dfcb 100644 --- a/arch/arm/mach-omap1/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 21103df50415..a88524e7c315 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/device.h> | 31 | #include <linux/platform_device.h> |
32 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
33 | 33 | ||
34 | #include <linux/mtd/mtd.h> | 34 | #include <linux/mtd/mtd.h> |
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 2ba26e239108..354b157acb3a 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/mtd/mtd.h> | 18 | #include <linux/mtd/mtd.h> |
19 | #include <linux/mtd/partitions.h> | 19 | #include <linux/mtd/partitions.h> |
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index bf30b1acda0b..3f018b296861 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index e8b3981444cd..3c5d901efeaa 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | 17 | ||
18 | #include <asm/hardware.h> | 18 | #include <asm/hardware.h> |
19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 656f73bbcb5a..eb5f6d744a4a 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/major.h> | 18 | #include <linux/major.h> |
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index 370df113dc06..54162ba95414 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <asm/arch/akita.h> | 22 | #include <asm/arch/akita.h> |
23 | #include <asm/arch/corgi.h> | 23 | #include <asm/arch/corgi.h> |
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 136c269db0b7..591e5f32dbec 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <asm/hardware.h> | 19 | #include <asm/hardware.h> |
20 | #include <asm/mach-types.h> | 20 | #include <asm/mach-types.h> |
21 | 21 | ||
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 9c0289333301..9b48a90aefce 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 01a83ab09ac3..7de159e2ab42 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c | |||
@@ -18,7 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/fb.h> | 22 | #include <linux/fb.h> |
23 | 23 | ||
24 | #include <asm/setup.h> | 24 | #include <asm/setup.h> |
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index beccf455f796..9c6e77faec5b 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/sysdev.h> | 18 | #include <linux/sysdev.h> |
19 | #include <linux/major.h> | 19 | #include <linux/major.h> |
20 | #include <linux/fb.h> | 20 | #include <linux/fb.h> |
@@ -175,7 +175,7 @@ static struct platform_device sa1111_device = { | |||
175 | static struct resource smc91x_resources[] = { | 175 | static struct resource smc91x_resources[] = { |
176 | [0] = { | 176 | [0] = { |
177 | .name = "smc91x-regs", | 177 | .name = "smc91x-regs", |
178 | .start = 0x0c000000, | 178 | .start = 0x0c000c00, |
179 | .end = 0x0c0fffff, | 179 | .end = 0x0c0fffff, |
180 | .flags = IORESOURCE_MEM, | 180 | .flags = IORESOURCE_MEM, |
181 | }, | 181 | }, |
@@ -224,18 +224,75 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = { | |||
224 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), | 224 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), |
225 | }; | 225 | }; |
226 | 226 | ||
227 | static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data) | 227 | #define MMC_POLL_RATE msecs_to_jiffies(1000) |
228 | |||
229 | static void lubbock_mmc_poll(unsigned long); | ||
230 | static irqreturn_t (*mmc_detect_int)(int, void *, struct pt_regs *); | ||
231 | |||
232 | static struct timer_list mmc_timer = { | ||
233 | .function = lubbock_mmc_poll, | ||
234 | }; | ||
235 | |||
236 | static void lubbock_mmc_poll(unsigned long data) | ||
237 | { | ||
238 | unsigned long flags; | ||
239 | |||
240 | /* clear any previous irq state, then ... */ | ||
241 | local_irq_save(flags); | ||
242 | LUB_IRQ_SET_CLR &= ~(1 << 0); | ||
243 | local_irq_restore(flags); | ||
244 | |||
245 | /* poll until mmc/sd card is removed */ | ||
246 | if (LUB_IRQ_SET_CLR & (1 << 0)) | ||
247 | mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE); | ||
248 | else { | ||
249 | (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL); | ||
250 | enable_irq(LUBBOCK_SD_IRQ); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static irqreturn_t lubbock_detect_int(int irq, void *data, struct pt_regs *regs) | ||
255 | { | ||
256 | /* IRQ is level triggered; disable, and poll for removal */ | ||
257 | disable_irq(irq); | ||
258 | mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE); | ||
259 | |||
260 | return mmc_detect_int(irq, data, regs); | ||
261 | } | ||
262 | |||
263 | static int lubbock_mci_init(struct device *dev, | ||
264 | irqreturn_t (*detect_int)(int, void *, struct pt_regs *), | ||
265 | void *data) | ||
228 | { | 266 | { |
229 | /* setup GPIO for PXA25x MMC controller */ | 267 | /* setup GPIO for PXA25x MMC controller */ |
230 | pxa_gpio_mode(GPIO6_MMCCLK_MD); | 268 | pxa_gpio_mode(GPIO6_MMCCLK_MD); |
231 | pxa_gpio_mode(GPIO8_MMCCS0_MD); | 269 | pxa_gpio_mode(GPIO8_MMCCS0_MD); |
232 | 270 | ||
233 | return 0; | 271 | /* detect card insert/eject */ |
272 | mmc_detect_int = detect_int; | ||
273 | init_timer(&mmc_timer); | ||
274 | mmc_timer.data = (unsigned long) data; | ||
275 | return request_irq(LUBBOCK_SD_IRQ, lubbock_detect_int, | ||
276 | SA_SAMPLE_RANDOM, "lubbock-sd-detect", data); | ||
277 | } | ||
278 | |||
279 | static int lubbock_mci_get_ro(struct device *dev) | ||
280 | { | ||
281 | return (LUB_MISC_RD & (1 << 2)) != 0; | ||
282 | } | ||
283 | |||
284 | static void lubbock_mci_exit(struct device *dev, void *data) | ||
285 | { | ||
286 | free_irq(LUBBOCK_SD_IRQ, data); | ||
287 | del_timer_sync(&mmc_timer); | ||
234 | } | 288 | } |
235 | 289 | ||
236 | static struct pxamci_platform_data lubbock_mci_platform_data = { | 290 | static struct pxamci_platform_data lubbock_mci_platform_data = { |
237 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | 291 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, |
292 | .detect_delay = 1, | ||
238 | .init = lubbock_mci_init, | 293 | .init = lubbock_mci_init, |
294 | .get_ro = lubbock_mci_get_ro, | ||
295 | .exit = lubbock_mci_exit, | ||
239 | }; | 296 | }; |
240 | 297 | ||
241 | static void lubbock_irda_transceiver_mode(struct device *dev, int mode) | 298 | static void lubbock_irda_transceiver_mode(struct device *dev, int mode) |
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index a48c64026e1f..887a8cb7b721 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c | |||
@@ -14,7 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/sysdev.h> | 18 | #include <linux/sysdev.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 6d413f6701a7..ad6a13f95a62 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c | |||
@@ -16,7 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/fb.h> | 20 | #include <linux/fb.h> |
21 | 21 | ||
22 | #include <asm/hardware.h> | 22 | #include <asm/hardware.h> |
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 09a5d593f04b..c722a9a91fcc 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/device.h> | 19 | #include <linux/platform_device.h> |
20 | 20 | ||
21 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index b838842b6a20..6c6878cd2207 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/major.h> | 19 | #include <linux/major.h> |
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig new file mode 100644 index 000000000000..4b63dc9eabfe --- /dev/null +++ b/arch/arm/mach-realview/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | menu "RealView platform type" | ||
2 | depends on ARCH_REALVIEW | ||
3 | |||
4 | config MACH_REALVIEW_EB | ||
5 | bool "Support RealView/EB platform" | ||
6 | default n | ||
7 | select ARM_GIC | ||
8 | help | ||
9 | Include support for the ARM(R) RealView Emulation Baseboard platform. | ||
10 | |||
11 | endmenu | ||
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile new file mode 100644 index 000000000000..8d37ea1605fd --- /dev/null +++ b/arch/arm/mach-realview/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | obj-y := core.o clock.o | ||
6 | obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o | ||
diff --git a/arch/arm/mach-realview/Makefile.boot b/arch/arm/mach-realview/Makefile.boot new file mode 100644 index 000000000000..c7e75acfe6c9 --- /dev/null +++ b/arch/arm/mach-realview/Makefile.boot | |||
@@ -0,0 +1,4 @@ | |||
1 | zreladdr-y := 0x00008000 | ||
2 | params_phys-y := 0x00000100 | ||
3 | initrd_phys-y := 0x00800000 | ||
4 | |||
diff --git a/arch/arm/mach-realview/clock.c b/arch/arm/mach-realview/clock.c new file mode 100644 index 000000000000..002635c97bb6 --- /dev/null +++ b/arch/arm/mach-realview/clock.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-realview/clock.c | ||
3 | * | ||
4 | * Copyright (C) 2004 ARM Limited. | ||
5 | * Written by Deep Blue Solutions Limited. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/err.h> | ||
16 | |||
17 | #include <asm/semaphore.h> | ||
18 | #include <asm/hardware/clock.h> | ||
19 | #include <asm/hardware/icst307.h> | ||
20 | |||
21 | #include "clock.h" | ||
22 | |||
23 | static LIST_HEAD(clocks); | ||
24 | static DECLARE_MUTEX(clocks_sem); | ||
25 | |||
26 | struct clk *clk_get(struct device *dev, const char *id) | ||
27 | { | ||
28 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
29 | |||
30 | down(&clocks_sem); | ||
31 | list_for_each_entry(p, &clocks, node) { | ||
32 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
33 | clk = p; | ||
34 | break; | ||
35 | } | ||
36 | } | ||
37 | up(&clocks_sem); | ||
38 | |||
39 | return clk; | ||
40 | } | ||
41 | EXPORT_SYMBOL(clk_get); | ||
42 | |||
43 | void clk_put(struct clk *clk) | ||
44 | { | ||
45 | module_put(clk->owner); | ||
46 | } | ||
47 | EXPORT_SYMBOL(clk_put); | ||
48 | |||
49 | int clk_enable(struct clk *clk) | ||
50 | { | ||
51 | return 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL(clk_enable); | ||
54 | |||
55 | void clk_disable(struct clk *clk) | ||
56 | { | ||
57 | } | ||
58 | EXPORT_SYMBOL(clk_disable); | ||
59 | |||
60 | int clk_use(struct clk *clk) | ||
61 | { | ||
62 | return 0; | ||
63 | } | ||
64 | EXPORT_SYMBOL(clk_use); | ||
65 | |||
66 | void clk_unuse(struct clk *clk) | ||
67 | { | ||
68 | } | ||
69 | EXPORT_SYMBOL(clk_unuse); | ||
70 | |||
71 | unsigned long clk_get_rate(struct clk *clk) | ||
72 | { | ||
73 | return clk->rate; | ||
74 | } | ||
75 | EXPORT_SYMBOL(clk_get_rate); | ||
76 | |||
77 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
78 | { | ||
79 | return rate; | ||
80 | } | ||
81 | EXPORT_SYMBOL(clk_round_rate); | ||
82 | |||
83 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
84 | { | ||
85 | int ret = -EIO; | ||
86 | |||
87 | if (clk->setvco) { | ||
88 | struct icst307_vco vco; | ||
89 | |||
90 | vco = icst307_khz_to_vco(clk->params, rate / 1000); | ||
91 | clk->rate = icst307_khz(clk->params, vco) * 1000; | ||
92 | |||
93 | printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", | ||
94 | clk->name, vco.s, vco.r, vco.v); | ||
95 | |||
96 | clk->setvco(clk, vco); | ||
97 | ret = 0; | ||
98 | } | ||
99 | return ret; | ||
100 | } | ||
101 | EXPORT_SYMBOL(clk_set_rate); | ||
102 | |||
103 | /* | ||
104 | * These are fixed clocks. | ||
105 | */ | ||
106 | static struct clk kmi_clk = { | ||
107 | .name = "KMIREFCLK", | ||
108 | .rate = 24000000, | ||
109 | }; | ||
110 | |||
111 | static struct clk uart_clk = { | ||
112 | .name = "UARTCLK", | ||
113 | .rate = 24000000, | ||
114 | }; | ||
115 | |||
116 | static struct clk mmci_clk = { | ||
117 | .name = "MCLK", | ||
118 | .rate = 33000000, | ||
119 | }; | ||
120 | |||
121 | int clk_register(struct clk *clk) | ||
122 | { | ||
123 | down(&clocks_sem); | ||
124 | list_add(&clk->node, &clocks); | ||
125 | up(&clocks_sem); | ||
126 | return 0; | ||
127 | } | ||
128 | EXPORT_SYMBOL(clk_register); | ||
129 | |||
130 | void clk_unregister(struct clk *clk) | ||
131 | { | ||
132 | down(&clocks_sem); | ||
133 | list_del(&clk->node); | ||
134 | up(&clocks_sem); | ||
135 | } | ||
136 | EXPORT_SYMBOL(clk_unregister); | ||
137 | |||
138 | static int __init clk_init(void) | ||
139 | { | ||
140 | clk_register(&kmi_clk); | ||
141 | clk_register(&uart_clk); | ||
142 | clk_register(&mmci_clk); | ||
143 | return 0; | ||
144 | } | ||
145 | arch_initcall(clk_init); | ||
diff --git a/arch/arm/mach-realview/clock.h b/arch/arm/mach-realview/clock.h new file mode 100644 index 000000000000..dadba695e181 --- /dev/null +++ b/arch/arm/mach-realview/clock.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-realview/clock.h | ||
3 | * | ||
4 | * Copyright (C) 2004 ARM Limited. | ||
5 | * Written by Deep Blue Solutions Limited. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | struct module; | ||
12 | struct icst307_params; | ||
13 | |||
14 | struct clk { | ||
15 | struct list_head node; | ||
16 | unsigned long rate; | ||
17 | struct module *owner; | ||
18 | const char *name; | ||
19 | const struct icst307_params *params; | ||
20 | void *data; | ||
21 | void (*setvco)(struct clk *, struct icst307_vco vco); | ||
22 | }; | ||
23 | |||
24 | int clk_register(struct clk *clk); | ||
25 | void clk_unregister(struct clk *clk); | ||
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c new file mode 100644 index 000000000000..482eb512ebe8 --- /dev/null +++ b/arch/arm/mach-realview/core.c | |||
@@ -0,0 +1,605 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-realview/core.c | ||
3 | * | ||
4 | * Copyright (C) 1999 - 2003 ARM Limited | ||
5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | |||
28 | #include <asm/system.h> | ||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/leds.h> | ||
33 | #include <asm/mach-types.h> | ||
34 | #include <asm/hardware/amba.h> | ||
35 | #include <asm/hardware/amba_clcd.h> | ||
36 | #include <asm/hardware/arm_timer.h> | ||
37 | #include <asm/hardware/icst307.h> | ||
38 | |||
39 | #include <asm/mach/arch.h> | ||
40 | #include <asm/mach/flash.h> | ||
41 | #include <asm/mach/irq.h> | ||
42 | #include <asm/mach/time.h> | ||
43 | #include <asm/mach/map.h> | ||
44 | #include <asm/mach/mmc.h> | ||
45 | |||
46 | #include <asm/hardware/gic.h> | ||
47 | |||
48 | #include "core.h" | ||
49 | #include "clock.h" | ||
50 | |||
51 | #define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) | ||
52 | |||
53 | /* | ||
54 | * This is the RealView sched_clock implementation. This has | ||
55 | * a resolution of 41.7ns, and a maximum value of about 179s. | ||
56 | */ | ||
57 | unsigned long long sched_clock(void) | ||
58 | { | ||
59 | unsigned long long v; | ||
60 | |||
61 | v = (unsigned long long)readl(REALVIEW_REFCOUNTER) * 125; | ||
62 | do_div(v, 3); | ||
63 | |||
64 | return v; | ||
65 | } | ||
66 | |||
67 | |||
68 | #define REALVIEW_FLASHCTRL (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET) | ||
69 | |||
70 | static int realview_flash_init(void) | ||
71 | { | ||
72 | u32 val; | ||
73 | |||
74 | val = __raw_readl(REALVIEW_FLASHCTRL); | ||
75 | val &= ~REALVIEW_FLASHPROG_FLVPPEN; | ||
76 | __raw_writel(val, REALVIEW_FLASHCTRL); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static void realview_flash_exit(void) | ||
82 | { | ||
83 | u32 val; | ||
84 | |||
85 | val = __raw_readl(REALVIEW_FLASHCTRL); | ||
86 | val &= ~REALVIEW_FLASHPROG_FLVPPEN; | ||
87 | __raw_writel(val, REALVIEW_FLASHCTRL); | ||
88 | } | ||
89 | |||
90 | static void realview_flash_set_vpp(int on) | ||
91 | { | ||
92 | u32 val; | ||
93 | |||
94 | val = __raw_readl(REALVIEW_FLASHCTRL); | ||
95 | if (on) | ||
96 | val |= REALVIEW_FLASHPROG_FLVPPEN; | ||
97 | else | ||
98 | val &= ~REALVIEW_FLASHPROG_FLVPPEN; | ||
99 | __raw_writel(val, REALVIEW_FLASHCTRL); | ||
100 | } | ||
101 | |||
102 | static struct flash_platform_data realview_flash_data = { | ||
103 | .map_name = "cfi_probe", | ||
104 | .width = 4, | ||
105 | .init = realview_flash_init, | ||
106 | .exit = realview_flash_exit, | ||
107 | .set_vpp = realview_flash_set_vpp, | ||
108 | }; | ||
109 | |||
110 | static struct resource realview_flash_resource = { | ||
111 | .start = REALVIEW_FLASH_BASE, | ||
112 | .end = REALVIEW_FLASH_BASE + REALVIEW_FLASH_SIZE, | ||
113 | .flags = IORESOURCE_MEM, | ||
114 | }; | ||
115 | |||
116 | struct platform_device realview_flash_device = { | ||
117 | .name = "armflash", | ||
118 | .id = 0, | ||
119 | .dev = { | ||
120 | .platform_data = &realview_flash_data, | ||
121 | }, | ||
122 | .num_resources = 1, | ||
123 | .resource = &realview_flash_resource, | ||
124 | }; | ||
125 | |||
126 | static struct resource realview_smc91x_resources[] = { | ||
127 | [0] = { | ||
128 | .start = REALVIEW_ETH_BASE, | ||
129 | .end = REALVIEW_ETH_BASE + SZ_64K - 1, | ||
130 | .flags = IORESOURCE_MEM, | ||
131 | }, | ||
132 | [1] = { | ||
133 | .start = IRQ_ETH, | ||
134 | .end = IRQ_ETH, | ||
135 | .flags = IORESOURCE_IRQ, | ||
136 | }, | ||
137 | }; | ||
138 | |||
139 | struct platform_device realview_smc91x_device = { | ||
140 | .name = "smc91x", | ||
141 | .id = 0, | ||
142 | .num_resources = ARRAY_SIZE(realview_smc91x_resources), | ||
143 | .resource = realview_smc91x_resources, | ||
144 | }; | ||
145 | |||
146 | #define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET) | ||
147 | |||
148 | static unsigned int realview_mmc_status(struct device *dev) | ||
149 | { | ||
150 | struct amba_device *adev = container_of(dev, struct amba_device, dev); | ||
151 | u32 mask; | ||
152 | |||
153 | if (adev->res.start == REALVIEW_MMCI0_BASE) | ||
154 | mask = 1; | ||
155 | else | ||
156 | mask = 2; | ||
157 | |||
158 | return readl(REALVIEW_SYSMCI) & mask; | ||
159 | } | ||
160 | |||
161 | struct mmc_platform_data realview_mmc0_plat_data = { | ||
162 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
163 | .status = realview_mmc_status, | ||
164 | }; | ||
165 | |||
166 | struct mmc_platform_data realview_mmc1_plat_data = { | ||
167 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
168 | .status = realview_mmc_status, | ||
169 | }; | ||
170 | |||
171 | /* | ||
172 | * Clock handling | ||
173 | */ | ||
174 | static const struct icst307_params realview_oscvco_params = { | ||
175 | .ref = 24000, | ||
176 | .vco_max = 200000, | ||
177 | .vd_min = 4 + 8, | ||
178 | .vd_max = 511 + 8, | ||
179 | .rd_min = 1 + 2, | ||
180 | .rd_max = 127 + 2, | ||
181 | }; | ||
182 | |||
183 | static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco) | ||
184 | { | ||
185 | void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET; | ||
186 | void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC1_OFFSET; | ||
187 | u32 val; | ||
188 | |||
189 | val = readl(sys_osc) & ~0x7ffff; | ||
190 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | ||
191 | |||
192 | writel(0xa05f, sys_lock); | ||
193 | writel(val, sys_osc); | ||
194 | writel(0, sys_lock); | ||
195 | } | ||
196 | |||
197 | struct clk realview_clcd_clk = { | ||
198 | .name = "CLCDCLK", | ||
199 | .params = &realview_oscvco_params, | ||
200 | .setvco = realview_oscvco_set, | ||
201 | }; | ||
202 | |||
203 | /* | ||
204 | * CLCD support. | ||
205 | */ | ||
206 | #define SYS_CLCD_MODE_MASK (3 << 0) | ||
207 | #define SYS_CLCD_MODE_888 (0 << 0) | ||
208 | #define SYS_CLCD_MODE_5551 (1 << 0) | ||
209 | #define SYS_CLCD_MODE_565_RLSB (2 << 0) | ||
210 | #define SYS_CLCD_MODE_565_BLSB (3 << 0) | ||
211 | #define SYS_CLCD_NLCDIOON (1 << 2) | ||
212 | #define SYS_CLCD_VDDPOSSWITCH (1 << 3) | ||
213 | #define SYS_CLCD_PWR3V5SWITCH (1 << 4) | ||
214 | #define SYS_CLCD_ID_MASK (0x1f << 8) | ||
215 | #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) | ||
216 | #define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) | ||
217 | #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) | ||
218 | #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) | ||
219 | #define SYS_CLCD_ID_VGA (0x1f << 8) | ||
220 | |||
221 | static struct clcd_panel vga = { | ||
222 | .mode = { | ||
223 | .name = "VGA", | ||
224 | .refresh = 60, | ||
225 | .xres = 640, | ||
226 | .yres = 480, | ||
227 | .pixclock = 39721, | ||
228 | .left_margin = 40, | ||
229 | .right_margin = 24, | ||
230 | .upper_margin = 32, | ||
231 | .lower_margin = 11, | ||
232 | .hsync_len = 96, | ||
233 | .vsync_len = 2, | ||
234 | .sync = 0, | ||
235 | .vmode = FB_VMODE_NONINTERLACED, | ||
236 | }, | ||
237 | .width = -1, | ||
238 | .height = -1, | ||
239 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
240 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
241 | .bpp = 16, | ||
242 | }; | ||
243 | |||
244 | static struct clcd_panel sanyo_3_8_in = { | ||
245 | .mode = { | ||
246 | .name = "Sanyo QVGA", | ||
247 | .refresh = 116, | ||
248 | .xres = 320, | ||
249 | .yres = 240, | ||
250 | .pixclock = 100000, | ||
251 | .left_margin = 6, | ||
252 | .right_margin = 6, | ||
253 | .upper_margin = 5, | ||
254 | .lower_margin = 5, | ||
255 | .hsync_len = 6, | ||
256 | .vsync_len = 6, | ||
257 | .sync = 0, | ||
258 | .vmode = FB_VMODE_NONINTERLACED, | ||
259 | }, | ||
260 | .width = -1, | ||
261 | .height = -1, | ||
262 | .tim2 = TIM2_BCD, | ||
263 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
264 | .bpp = 16, | ||
265 | }; | ||
266 | |||
267 | static struct clcd_panel sanyo_2_5_in = { | ||
268 | .mode = { | ||
269 | .name = "Sanyo QVGA Portrait", | ||
270 | .refresh = 116, | ||
271 | .xres = 240, | ||
272 | .yres = 320, | ||
273 | .pixclock = 100000, | ||
274 | .left_margin = 20, | ||
275 | .right_margin = 10, | ||
276 | .upper_margin = 2, | ||
277 | .lower_margin = 2, | ||
278 | .hsync_len = 10, | ||
279 | .vsync_len = 2, | ||
280 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
281 | .vmode = FB_VMODE_NONINTERLACED, | ||
282 | }, | ||
283 | .width = -1, | ||
284 | .height = -1, | ||
285 | .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, | ||
286 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
287 | .bpp = 16, | ||
288 | }; | ||
289 | |||
290 | static struct clcd_panel epson_2_2_in = { | ||
291 | .mode = { | ||
292 | .name = "Epson QCIF", | ||
293 | .refresh = 390, | ||
294 | .xres = 176, | ||
295 | .yres = 220, | ||
296 | .pixclock = 62500, | ||
297 | .left_margin = 3, | ||
298 | .right_margin = 2, | ||
299 | .upper_margin = 1, | ||
300 | .lower_margin = 0, | ||
301 | .hsync_len = 3, | ||
302 | .vsync_len = 2, | ||
303 | .sync = 0, | ||
304 | .vmode = FB_VMODE_NONINTERLACED, | ||
305 | }, | ||
306 | .width = -1, | ||
307 | .height = -1, | ||
308 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
309 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
310 | .bpp = 16, | ||
311 | }; | ||
312 | |||
313 | /* | ||
314 | * Detect which LCD panel is connected, and return the appropriate | ||
315 | * clcd_panel structure. Note: we do not have any information on | ||
316 | * the required timings for the 8.4in panel, so we presently assume | ||
317 | * VGA timings. | ||
318 | */ | ||
319 | static struct clcd_panel *realview_clcd_panel(void) | ||
320 | { | ||
321 | void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; | ||
322 | struct clcd_panel *panel = &vga; | ||
323 | u32 val; | ||
324 | |||
325 | val = readl(sys_clcd) & SYS_CLCD_ID_MASK; | ||
326 | if (val == SYS_CLCD_ID_SANYO_3_8) | ||
327 | panel = &sanyo_3_8_in; | ||
328 | else if (val == SYS_CLCD_ID_SANYO_2_5) | ||
329 | panel = &sanyo_2_5_in; | ||
330 | else if (val == SYS_CLCD_ID_EPSON_2_2) | ||
331 | panel = &epson_2_2_in; | ||
332 | else if (val == SYS_CLCD_ID_VGA) | ||
333 | panel = &vga; | ||
334 | else { | ||
335 | printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", | ||
336 | val); | ||
337 | panel = &vga; | ||
338 | } | ||
339 | |||
340 | return panel; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Disable all display connectors on the interface module. | ||
345 | */ | ||
346 | static void realview_clcd_disable(struct clcd_fb *fb) | ||
347 | { | ||
348 | void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; | ||
349 | u32 val; | ||
350 | |||
351 | val = readl(sys_clcd); | ||
352 | val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | ||
353 | writel(val, sys_clcd); | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * Enable the relevant connector on the interface module. | ||
358 | */ | ||
359 | static void realview_clcd_enable(struct clcd_fb *fb) | ||
360 | { | ||
361 | void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; | ||
362 | u32 val; | ||
363 | |||
364 | val = readl(sys_clcd); | ||
365 | val &= ~SYS_CLCD_MODE_MASK; | ||
366 | |||
367 | switch (fb->fb.var.green.length) { | ||
368 | case 5: | ||
369 | val |= SYS_CLCD_MODE_5551; | ||
370 | break; | ||
371 | case 6: | ||
372 | val |= SYS_CLCD_MODE_565_RLSB; | ||
373 | break; | ||
374 | case 8: | ||
375 | val |= SYS_CLCD_MODE_888; | ||
376 | break; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * Set the MUX | ||
381 | */ | ||
382 | writel(val, sys_clcd); | ||
383 | |||
384 | /* | ||
385 | * And now enable the PSUs | ||
386 | */ | ||
387 | val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | ||
388 | writel(val, sys_clcd); | ||
389 | } | ||
390 | |||
391 | static unsigned long framesize = SZ_1M; | ||
392 | |||
393 | static int realview_clcd_setup(struct clcd_fb *fb) | ||
394 | { | ||
395 | dma_addr_t dma; | ||
396 | |||
397 | fb->panel = realview_clcd_panel(); | ||
398 | |||
399 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, | ||
400 | &dma, GFP_KERNEL); | ||
401 | if (!fb->fb.screen_base) { | ||
402 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | ||
403 | return -ENOMEM; | ||
404 | } | ||
405 | |||
406 | fb->fb.fix.smem_start = dma; | ||
407 | fb->fb.fix.smem_len = framesize; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int realview_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | ||
413 | { | ||
414 | return dma_mmap_writecombine(&fb->dev->dev, vma, | ||
415 | fb->fb.screen_base, | ||
416 | fb->fb.fix.smem_start, | ||
417 | fb->fb.fix.smem_len); | ||
418 | } | ||
419 | |||
420 | static void realview_clcd_remove(struct clcd_fb *fb) | ||
421 | { | ||
422 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | ||
423 | fb->fb.screen_base, fb->fb.fix.smem_start); | ||
424 | } | ||
425 | |||
426 | struct clcd_board clcd_plat_data = { | ||
427 | .name = "RealView", | ||
428 | .check = clcdfb_check, | ||
429 | .decode = clcdfb_decode, | ||
430 | .disable = realview_clcd_disable, | ||
431 | .enable = realview_clcd_enable, | ||
432 | .setup = realview_clcd_setup, | ||
433 | .mmap = realview_clcd_mmap, | ||
434 | .remove = realview_clcd_remove, | ||
435 | }; | ||
436 | |||
437 | #ifdef CONFIG_LEDS | ||
438 | #define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) | ||
439 | |||
440 | void realview_leds_event(led_event_t ledevt) | ||
441 | { | ||
442 | unsigned long flags; | ||
443 | u32 val; | ||
444 | |||
445 | local_irq_save(flags); | ||
446 | val = readl(VA_LEDS_BASE); | ||
447 | |||
448 | switch (ledevt) { | ||
449 | case led_idle_start: | ||
450 | val = val & ~REALVIEW_SYS_LED0; | ||
451 | break; | ||
452 | |||
453 | case led_idle_end: | ||
454 | val = val | REALVIEW_SYS_LED0; | ||
455 | break; | ||
456 | |||
457 | case led_timer: | ||
458 | val = val ^ REALVIEW_SYS_LED1; | ||
459 | break; | ||
460 | |||
461 | case led_halted: | ||
462 | val = 0; | ||
463 | break; | ||
464 | |||
465 | default: | ||
466 | break; | ||
467 | } | ||
468 | |||
469 | writel(val, VA_LEDS_BASE); | ||
470 | local_irq_restore(flags); | ||
471 | } | ||
472 | #endif /* CONFIG_LEDS */ | ||
473 | |||
474 | /* | ||
475 | * Where is the timer (VA)? | ||
476 | */ | ||
477 | #define TIMER0_VA_BASE __io_address(REALVIEW_TIMER0_1_BASE) | ||
478 | #define TIMER1_VA_BASE (__io_address(REALVIEW_TIMER0_1_BASE) + 0x20) | ||
479 | #define TIMER2_VA_BASE __io_address(REALVIEW_TIMER2_3_BASE) | ||
480 | #define TIMER3_VA_BASE (__io_address(REALVIEW_TIMER2_3_BASE) + 0x20) | ||
481 | |||
482 | /* | ||
483 | * How long is the timer interval? | ||
484 | */ | ||
485 | #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) | ||
486 | #if TIMER_INTERVAL >= 0x100000 | ||
487 | #define TIMER_RELOAD (TIMER_INTERVAL >> 8) | ||
488 | #define TIMER_DIVISOR (TIMER_CTRL_DIV256) | ||
489 | #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) | ||
490 | #elif TIMER_INTERVAL >= 0x10000 | ||
491 | #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ | ||
492 | #define TIMER_DIVISOR (TIMER_CTRL_DIV16) | ||
493 | #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) | ||
494 | #else | ||
495 | #define TIMER_RELOAD (TIMER_INTERVAL) | ||
496 | #define TIMER_DIVISOR (TIMER_CTRL_DIV1) | ||
497 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | ||
498 | #endif | ||
499 | |||
500 | /* | ||
501 | * Returns number of ms since last clock interrupt. Note that interrupts | ||
502 | * will have been disabled by do_gettimeoffset() | ||
503 | */ | ||
504 | static unsigned long realview_gettimeoffset(void) | ||
505 | { | ||
506 | unsigned long ticks1, ticks2, status; | ||
507 | |||
508 | /* | ||
509 | * Get the current number of ticks. Note that there is a race | ||
510 | * condition between us reading the timer and checking for | ||
511 | * an interrupt. We get around this by ensuring that the | ||
512 | * counter has not reloaded between our two reads. | ||
513 | */ | ||
514 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
515 | do { | ||
516 | ticks1 = ticks2; | ||
517 | status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET) | ||
518 | + ((IRQ_TIMERINT0_1 >> 5) << 2)); | ||
519 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
520 | } while (ticks2 > ticks1); | ||
521 | |||
522 | /* | ||
523 | * Number of ticks since last interrupt. | ||
524 | */ | ||
525 | ticks1 = TIMER_RELOAD - ticks2; | ||
526 | |||
527 | /* | ||
528 | * Interrupt pending? If so, we've reloaded once already. | ||
529 | * | ||
530 | * FIXME: Need to check this is effectively timer 0 that expires | ||
531 | */ | ||
532 | if (status & IRQMASK_TIMERINT0_1) | ||
533 | ticks1 += TIMER_RELOAD; | ||
534 | |||
535 | /* | ||
536 | * Convert the ticks to usecs | ||
537 | */ | ||
538 | return TICKS2USECS(ticks1); | ||
539 | } | ||
540 | |||
541 | /* | ||
542 | * IRQ handler for the timer | ||
543 | */ | ||
544 | static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
545 | { | ||
546 | write_seqlock(&xtime_lock); | ||
547 | |||
548 | // ...clear the interrupt | ||
549 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); | ||
550 | |||
551 | timer_tick(regs); | ||
552 | |||
553 | write_sequnlock(&xtime_lock); | ||
554 | |||
555 | return IRQ_HANDLED; | ||
556 | } | ||
557 | |||
558 | static struct irqaction realview_timer_irq = { | ||
559 | .name = "RealView Timer Tick", | ||
560 | .flags = SA_INTERRUPT | SA_TIMER, | ||
561 | .handler = realview_timer_interrupt, | ||
562 | }; | ||
563 | |||
564 | /* | ||
565 | * Set up timer interrupt, and return the current time in seconds. | ||
566 | */ | ||
567 | static void __init realview_timer_init(void) | ||
568 | { | ||
569 | u32 val; | ||
570 | |||
571 | /* | ||
572 | * set clock frequency: | ||
573 | * REALVIEW_REFCLK is 32KHz | ||
574 | * REALVIEW_TIMCLK is 1MHz | ||
575 | */ | ||
576 | val = readl(__io_address(REALVIEW_SCTL_BASE)); | ||
577 | writel((REALVIEW_TIMCLK << REALVIEW_TIMER1_EnSel) | | ||
578 | (REALVIEW_TIMCLK << REALVIEW_TIMER2_EnSel) | | ||
579 | (REALVIEW_TIMCLK << REALVIEW_TIMER3_EnSel) | | ||
580 | (REALVIEW_TIMCLK << REALVIEW_TIMER4_EnSel) | val, | ||
581 | __io_address(REALVIEW_SCTL_BASE)); | ||
582 | |||
583 | /* | ||
584 | * Initialise to a known state (all timers off) | ||
585 | */ | ||
586 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); | ||
587 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); | ||
588 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | ||
589 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | ||
590 | |||
591 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | ||
592 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); | ||
593 | writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | | ||
594 | TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); | ||
595 | |||
596 | /* | ||
597 | * Make irqs happen for the system timer | ||
598 | */ | ||
599 | setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); | ||
600 | } | ||
601 | |||
602 | struct sys_timer realview_timer = { | ||
603 | .init = realview_timer_init, | ||
604 | .offset = realview_gettimeoffset, | ||
605 | }; | ||
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h new file mode 100644 index 000000000000..575599db74db --- /dev/null +++ b/arch/arm/mach-realview/core.h | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-realview/core.h | ||
3 | * | ||
4 | * Copyright (C) 2004 ARM Limited | ||
5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef __ASM_ARCH_REALVIEW_H | ||
23 | #define __ASM_ARCH_REALVIEW_H | ||
24 | |||
25 | #include <asm/hardware/amba.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #define __io_address(n) __io(IO_ADDRESS(n)) | ||
29 | |||
30 | extern struct sys_timer realview_timer; | ||
31 | |||
32 | #define AMBA_DEVICE(name,busid,base,plat) \ | ||
33 | static struct amba_device name##_device = { \ | ||
34 | .dev = { \ | ||
35 | .coherent_dma_mask = ~0, \ | ||
36 | .bus_id = busid, \ | ||
37 | .platform_data = plat, \ | ||
38 | }, \ | ||
39 | .res = { \ | ||
40 | .start = REALVIEW_##base##_BASE, \ | ||
41 | .end = (REALVIEW_##base##_BASE) + SZ_4K - 1,\ | ||
42 | .flags = IORESOURCE_MEM, \ | ||
43 | }, \ | ||
44 | .dma_mask = ~0, \ | ||
45 | .irq = base##_IRQ, \ | ||
46 | /* .dma = base##_DMA,*/ \ | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * These devices are connected via the core APB bridge | ||
51 | */ | ||
52 | #define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } | ||
53 | #define GPIO2_DMA { 0, 0 } | ||
54 | #define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } | ||
55 | #define GPIO3_DMA { 0, 0 } | ||
56 | |||
57 | #define AACI_IRQ { IRQ_AACI, NO_IRQ } | ||
58 | #define AACI_DMA { 0x80, 0x81 } | ||
59 | #define MMCI0_IRQ { IRQ_MMCI0A,IRQ_MMCI0B } | ||
60 | #define MMCI0_DMA { 0x84, 0 } | ||
61 | #define KMI0_IRQ { IRQ_KMI0, NO_IRQ } | ||
62 | #define KMI0_DMA { 0, 0 } | ||
63 | #define KMI1_IRQ { IRQ_KMI1, NO_IRQ } | ||
64 | #define KMI1_DMA { 0, 0 } | ||
65 | |||
66 | /* | ||
67 | * These devices are connected directly to the multi-layer AHB switch | ||
68 | */ | ||
69 | #define SMC_IRQ { NO_IRQ, NO_IRQ } | ||
70 | #define SMC_DMA { 0, 0 } | ||
71 | #define MPMC_IRQ { NO_IRQ, NO_IRQ } | ||
72 | #define MPMC_DMA { 0, 0 } | ||
73 | #define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } | ||
74 | #define CLCD_DMA { 0, 0 } | ||
75 | #define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } | ||
76 | #define DMAC_DMA { 0, 0 } | ||
77 | |||
78 | /* | ||
79 | * These devices are connected via the core APB bridge | ||
80 | */ | ||
81 | #define SCTL_IRQ { NO_IRQ, NO_IRQ } | ||
82 | #define SCTL_DMA { 0, 0 } | ||
83 | #define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } | ||
84 | #define WATCHDOG_DMA { 0, 0 } | ||
85 | #define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } | ||
86 | #define GPIO0_DMA { 0, 0 } | ||
87 | #define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } | ||
88 | #define GPIO1_DMA { 0, 0 } | ||
89 | #define RTC_IRQ { IRQ_RTCINT, NO_IRQ } | ||
90 | #define RTC_DMA { 0, 0 } | ||
91 | |||
92 | /* | ||
93 | * These devices are connected via the DMA APB bridge | ||
94 | */ | ||
95 | #define SCI_IRQ { IRQ_SCIINT, NO_IRQ } | ||
96 | #define SCI_DMA { 7, 6 } | ||
97 | #define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } | ||
98 | #define UART0_DMA { 15, 14 } | ||
99 | #define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } | ||
100 | #define UART1_DMA { 13, 12 } | ||
101 | #define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } | ||
102 | #define UART2_DMA { 11, 10 } | ||
103 | #define UART3_IRQ { IRQ_UART3, NO_IRQ } | ||
104 | #define UART3_DMA { 0x86, 0x87 } | ||
105 | #define SSP_IRQ { IRQ_SSPINT, NO_IRQ } | ||
106 | #define SSP_DMA { 9, 8 } | ||
107 | |||
108 | |||
109 | extern struct platform_device realview_flash_device; | ||
110 | extern struct platform_device realview_smc91x_device; | ||
111 | extern struct mmc_platform_data realview_mmc0_plat_data; | ||
112 | extern struct mmc_platform_data realview_mmc1_plat_data; | ||
113 | extern struct clk realview_clcd_clk; | ||
114 | extern struct clcd_board clcd_plat_data; | ||
115 | |||
116 | extern void realview_leds_event(led_event_t ledevt); | ||
117 | |||
118 | #endif | ||
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c new file mode 100644 index 000000000000..01b264be5029 --- /dev/null +++ b/arch/arm/mach-realview/realview_eb.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-realview/realview_eb.c | ||
3 | * | ||
4 | * Copyright (C) 2004 ARM Limited | ||
5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/config.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | |||
27 | #include <asm/hardware.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/leds.h> | ||
31 | #include <asm/mach-types.h> | ||
32 | #include <asm/hardware/gic.h> | ||
33 | #include <asm/hardware/amba.h> | ||
34 | #include <asm/hardware/icst307.h> | ||
35 | |||
36 | #include <asm/mach/arch.h> | ||
37 | #include <asm/mach/map.h> | ||
38 | #include <asm/mach/mmc.h> | ||
39 | |||
40 | #include <asm/arch/irqs.h> | ||
41 | |||
42 | #include "core.h" | ||
43 | #include "clock.h" | ||
44 | |||
45 | static struct map_desc realview_eb_io_desc[] __initdata = { | ||
46 | { IO_ADDRESS(REALVIEW_SYS_BASE), REALVIEW_SYS_BASE, SZ_4K, MT_DEVICE }, | ||
47 | { IO_ADDRESS(REALVIEW_GIC_CPU_BASE), REALVIEW_GIC_CPU_BASE, SZ_4K, MT_DEVICE }, | ||
48 | { IO_ADDRESS(REALVIEW_GIC_DIST_BASE), REALVIEW_GIC_DIST_BASE, SZ_4K, MT_DEVICE }, | ||
49 | { IO_ADDRESS(REALVIEW_SCTL_BASE), REALVIEW_SCTL_BASE, SZ_4K, MT_DEVICE }, | ||
50 | { IO_ADDRESS(REALVIEW_TIMER0_1_BASE), REALVIEW_TIMER0_1_BASE, SZ_4K, MT_DEVICE }, | ||
51 | { IO_ADDRESS(REALVIEW_TIMER2_3_BASE), REALVIEW_TIMER2_3_BASE, SZ_4K, MT_DEVICE }, | ||
52 | #ifdef CONFIG_DEBUG_LL | ||
53 | { IO_ADDRESS(REALVIEW_UART0_BASE), REALVIEW_UART0_BASE, SZ_4K, MT_DEVICE }, | ||
54 | #endif | ||
55 | }; | ||
56 | |||
57 | static void __init realview_eb_map_io(void) | ||
58 | { | ||
59 | iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc)); | ||
60 | } | ||
61 | |||
62 | /* FPGA Primecells */ | ||
63 | AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); | ||
64 | AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &realview_mmc0_plat_data); | ||
65 | AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); | ||
66 | AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); | ||
67 | AMBA_DEVICE(uart3, "fpga:09", UART3, NULL); | ||
68 | |||
69 | /* DevChip Primecells */ | ||
70 | AMBA_DEVICE(smc, "dev:00", SMC, NULL); | ||
71 | AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); | ||
72 | AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); | ||
73 | AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); | ||
74 | AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); | ||
75 | AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); | ||
76 | AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); | ||
77 | AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL); | ||
78 | AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); | ||
79 | AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); | ||
80 | AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); | ||
81 | AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); | ||
82 | AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); | ||
83 | AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); | ||
84 | |||
85 | static struct amba_device *amba_devs[] __initdata = { | ||
86 | &dmac_device, | ||
87 | &uart0_device, | ||
88 | &uart1_device, | ||
89 | &uart2_device, | ||
90 | &uart3_device, | ||
91 | &smc_device, | ||
92 | &clcd_device, | ||
93 | &sctl_device, | ||
94 | &wdog_device, | ||
95 | &gpio0_device, | ||
96 | &gpio1_device, | ||
97 | &gpio2_device, | ||
98 | &rtc_device, | ||
99 | &sci0_device, | ||
100 | &ssp0_device, | ||
101 | &aaci_device, | ||
102 | &mmc0_device, | ||
103 | &kmi0_device, | ||
104 | &kmi1_device, | ||
105 | }; | ||
106 | |||
107 | static void __init gic_init_irq(void) | ||
108 | { | ||
109 | gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE)); | ||
110 | gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE)); | ||
111 | } | ||
112 | |||
113 | static void __init realview_eb_init(void) | ||
114 | { | ||
115 | int i; | ||
116 | |||
117 | clk_register(&realview_clcd_clk); | ||
118 | |||
119 | platform_device_register(&realview_flash_device); | ||
120 | platform_device_register(&realview_smc91x_device); | ||
121 | |||
122 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | ||
123 | struct amba_device *d = amba_devs[i]; | ||
124 | amba_device_register(d, &iomem_resource); | ||
125 | } | ||
126 | |||
127 | #ifdef CONFIG_LEDS | ||
128 | leds_event = realview_leds_event; | ||
129 | #endif | ||
130 | } | ||
131 | |||
132 | MACHINE_START(REALVIEW_EB, "ARM-RealView EB") | ||
133 | /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ | ||
134 | .phys_ram = 0x00000000, | ||
135 | .phys_io = REALVIEW_UART0_BASE, | ||
136 | .io_pg_offst = (IO_ADDRESS(REALVIEW_UART0_BASE) >> 18) & 0xfffc, | ||
137 | .boot_params = 0x00000100, | ||
138 | .map_io = realview_eb_map_io, | ||
139 | .init_irq = gic_init_irq, | ||
140 | .timer = &realview_timer, | ||
141 | .init_machine = realview_eb_init, | ||
142 | MACHINE_END | ||
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index 8b3d5dc35de5..82e8253b1fa0 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/list.h> | 32 | #include <linux/list.h> |
33 | #include <linux/errno.h> | 33 | #include <linux/errno.h> |
34 | #include <linux/err.h> | 34 | #include <linux/err.h> |
35 | #include <linux/device.h> | 35 | #include <linux/platform_device.h> |
36 | #include <linux/sysdev.h> | 36 | #include <linux/sysdev.h> |
37 | 37 | ||
38 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c index ca366e9e264d..687fe371369d 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/mach-s3c2410/cpu.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/device.h> | 29 | #include <linux/platform_device.h> |
30 | 30 | ||
31 | #include <asm/hardware.h> | 31 | #include <asm/hardware.h> |
32 | #include <asm/irq.h> | 32 | #include <asm/irq.h> |
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c index 08bc7d95a45d..f58406e6ef5a 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/mach-s3c2410/devs.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/timer.h> | 25 | #include <linux/timer.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/device.h> | 27 | #include <linux/platform_device.h> |
28 | 28 | ||
29 | #include <asm/mach/arch.h> | 29 | #include <asm/mach/arch.h> |
30 | #include <asm/mach/map.h> | 30 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h index d6328f96728b..52c4bab5c761 100644 --- a/arch/arm/mach-s3c2410/devs.h +++ b/arch/arm/mach-s3c2410/devs.h | |||
@@ -15,6 +15,7 @@ | |||
15 | * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv | 15 | * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv |
16 | */ | 16 | */ |
17 | #include <linux/config.h> | 17 | #include <linux/config.h> |
18 | #include <linux/platform_device.h> | ||
18 | 19 | ||
19 | extern struct platform_device *s3c24xx_uart_devs[]; | 20 | extern struct platform_device *s3c24xx_uart_devs[]; |
20 | 21 | ||
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index 5ae80f4e3e67..8390b685c2b6 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | #include <linux/timer.h> | 22 | #include <linux/timer.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/device.h> | 24 | #include <linux/platform_device.h> |
25 | 25 | ||
26 | #include <asm/mach/arch.h> | 26 | #include <asm/mach/arch.h> |
27 | #include <asm/mach/map.h> | 27 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index c1b5c63ec24a..0b71c896bbd1 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/list.h> | 41 | #include <linux/list.h> |
42 | #include <linux/timer.h> | 42 | #include <linux/timer.h> |
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/device.h> | 44 | #include <linux/platform_device.h> |
45 | #include <linux/dm9000.h> | 45 | #include <linux/dm9000.h> |
46 | 46 | ||
47 | #include <asm/mach/arch.h> | 47 | #include <asm/mach/arch.h> |
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index 7efeaaad2361..0aa8760598f7 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/list.h> | 34 | #include <linux/list.h> |
35 | #include <linux/timer.h> | 35 | #include <linux/timer.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/platform_device.h> | ||
37 | 38 | ||
38 | #include <asm/mach/arch.h> | 39 | #include <asm/mach/arch.h> |
39 | #include <asm/mach/map.h> | 40 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c index 5c0f2b091f95..378d640ab00b 100644 --- a/arch/arm/mach-s3c2410/mach-n30.c +++ b/arch/arm/mach-s3c2410/mach-n30.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/kthread.h> | 24 | #include <linux/kthread.h> |
25 | 25 | ||
26 | #include <asm/mach/arch.h> | 26 | #include <asm/mach/arch.h> |
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c index c22f8216032d..42b0eeff2e0f 100644 --- a/arch/arm/mach-s3c2410/mach-nexcoder.c +++ b/arch/arm/mach-s3c2410/mach-nexcoder.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/timer.h> | 19 | #include <linux/timer.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/device.h> | 22 | #include <linux/platform_device.h> |
23 | 23 | ||
24 | #include <linux/mtd/map.h> | 24 | #include <linux/mtd/map.h> |
25 | 25 | ||
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c index ad1459e402e2..a2eb9ed48fcd 100644 --- a/arch/arm/mach-s3c2410/mach-otom.c +++ b/arch/arm/mach-s3c2410/mach-otom.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/timer.h> | 16 | #include <linux/timer.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/device.h> | 18 | #include <linux/platform_device.h> |
19 | 19 | ||
20 | #include <asm/mach/arch.h> | 20 | #include <asm/mach/arch.h> |
21 | #include <asm/mach/map.h> | 21 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index 22d9e070fd68..24d69019a843 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA | 17 | * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA |
18 | * 14-Mar-2005 BJD Fixed __iomem warnings | 18 | * 14-Mar-2005 BJD Fixed __iomem warnings |
19 | * 20-Sep-2005 BJD Added static to non-exported items | 19 | * 20-Sep-2005 BJD Added static to non-exported items |
20 | * 31-Oct-2005 BJD Added LCD setup for framebuffer | ||
20 | */ | 21 | */ |
21 | 22 | ||
22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
@@ -27,6 +28,7 @@ | |||
27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
28 | #include <linux/tty.h> | 29 | #include <linux/tty.h> |
29 | #include <linux/console.h> | 30 | #include <linux/console.h> |
31 | #include <linux/platform_device.h> | ||
30 | #include <linux/serial_core.h> | 32 | #include <linux/serial_core.h> |
31 | #include <linux/serial.h> | 33 | #include <linux/serial.h> |
32 | 34 | ||
@@ -42,6 +44,9 @@ | |||
42 | 44 | ||
43 | #include <asm/arch/regs-serial.h> | 45 | #include <asm/arch/regs-serial.h> |
44 | #include <asm/arch/regs-gpio.h> | 46 | #include <asm/arch/regs-gpio.h> |
47 | #include <asm/arch/regs-lcd.h> | ||
48 | |||
49 | #include <asm/arch/fb.h> | ||
45 | 50 | ||
46 | #include "clock.h" | 51 | #include "clock.h" |
47 | #include "devs.h" | 52 | #include "devs.h" |
@@ -96,6 +101,66 @@ static struct s3c2410_uartcfg rx3715_uartcfgs[] = { | |||
96 | } | 101 | } |
97 | }; | 102 | }; |
98 | 103 | ||
104 | /* framebuffer lcd controller information */ | ||
105 | |||
106 | static struct s3c2410fb_mach_info rx3715_lcdcfg __initdata = { | ||
107 | .regs = { | ||
108 | .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | \ | ||
109 | S3C2410_LCDCON1_TFT | \ | ||
110 | S3C2410_LCDCON1_CLKVAL(0x0C), | ||
111 | |||
112 | .lcdcon2 = S3C2410_LCDCON2_VBPD(5) | \ | ||
113 | S3C2410_LCDCON2_LINEVAL(319) | \ | ||
114 | S3C2410_LCDCON2_VFPD(6) | \ | ||
115 | S3C2410_LCDCON2_VSPW(2), | ||
116 | |||
117 | .lcdcon3 = S3C2410_LCDCON3_HBPD(35) | \ | ||
118 | S3C2410_LCDCON3_HOZVAL(239) | \ | ||
119 | S3C2410_LCDCON3_HFPD(35), | ||
120 | |||
121 | .lcdcon4 = S3C2410_LCDCON4_MVAL(0) | \ | ||
122 | S3C2410_LCDCON4_HSPW(7), | ||
123 | |||
124 | .lcdcon5 = S3C2410_LCDCON5_INVVLINE | | ||
125 | S3C2410_LCDCON5_FRM565 | | ||
126 | S3C2410_LCDCON5_HWSWP, | ||
127 | }, | ||
128 | |||
129 | .lpcsel = 0xf82, | ||
130 | |||
131 | .gpccon = 0xaa955699, | ||
132 | .gpccon_mask = 0xffc003cc, | ||
133 | .gpcup = 0x0000ffff, | ||
134 | .gpcup_mask = 0xffffffff, | ||
135 | |||
136 | .gpdcon = 0xaa95aaa1, | ||
137 | .gpdcon_mask = 0xffc0fff0, | ||
138 | .gpdup = 0x0000faff, | ||
139 | .gpdup_mask = 0xffffffff, | ||
140 | |||
141 | .fixed_syncs = 1, | ||
142 | .width = 240, | ||
143 | .height = 320, | ||
144 | |||
145 | .xres = { | ||
146 | .min = 240, | ||
147 | .max = 240, | ||
148 | .defval = 240, | ||
149 | }, | ||
150 | |||
151 | .yres = { | ||
152 | .max = 320, | ||
153 | .min = 320, | ||
154 | .defval = 320, | ||
155 | }, | ||
156 | |||
157 | .bpp = { | ||
158 | .min = 16, | ||
159 | .max = 16, | ||
160 | .defval = 16, | ||
161 | }, | ||
162 | }; | ||
163 | |||
99 | static struct platform_device *rx3715_devices[] __initdata = { | 164 | static struct platform_device *rx3715_devices[] __initdata = { |
100 | &s3c_device_usb, | 165 | &s3c_device_usb, |
101 | &s3c_device_lcd, | 166 | &s3c_device_lcd, |
@@ -122,14 +187,12 @@ static void __init rx3715_init_irq(void) | |||
122 | s3c24xx_init_irq(); | 187 | s3c24xx_init_irq(); |
123 | } | 188 | } |
124 | 189 | ||
125 | #ifdef CONFIG_PM | ||
126 | static void __init rx3715_init_machine(void) | 190 | static void __init rx3715_init_machine(void) |
127 | { | 191 | { |
128 | s3c2410_pm_init(); | 192 | s3c2410_pm_init(); |
193 | s3c24xx_fb_set_platdata(&rx3715_lcdcfg); | ||
129 | } | 194 | } |
130 | #else | 195 | |
131 | #define rx3715_init_machine NULL | ||
132 | #endif | ||
133 | 196 | ||
134 | MACHINE_START(RX3715, "IPAQ-RX3715") | 197 | MACHINE_START(RX3715, "IPAQ-RX3715") |
135 | /* Maintainer: Ben Dooks <ben@fluff.org> */ | 198 | /* Maintainer: Ben Dooks <ben@fluff.org> */ |
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 2eda55a6b678..2c91965ee1c8 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/list.h> | 38 | #include <linux/list.h> |
39 | #include <linux/timer.h> | 39 | #include <linux/timer.h> |
40 | #include <linux/init.h> | 40 | #include <linux/init.h> |
41 | #include <linux/platform_device.h> | ||
41 | 42 | ||
42 | #include <asm/mach/arch.h> | 43 | #include <asm/mach/arch.h> |
43 | #include <asm/mach/map.h> | 44 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index 6950e61b7914..d666c621ad06 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/platform_device.h> | ||
31 | 32 | ||
32 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
33 | #include <asm/mach/map.h> | 34 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index a8bf5ec82602..0a2013a76549 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <linux/timer.h> | 28 | #include <linux/timer.h> |
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/device.h> | 30 | #include <linux/platform_device.h> |
31 | 31 | ||
32 | #include <asm/mach/arch.h> | 32 | #include <asm/mach/arch.h> |
33 | #include <asm/mach/map.h> | 33 | #include <asm/mach/map.h> |
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index 833fa36bce05..4d63e7133b48 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/list.h> | 26 | #include <linux/list.h> |
27 | #include <linux/timer.h> | 27 | #include <linux/timer.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/sysdev.h> | 30 | #include <linux/sysdev.h> |
31 | 31 | ||
32 | #include <asm/mach/arch.h> | 32 | #include <asm/mach/arch.h> |
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index c92cebff7f8e..edccd5eb06be 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/tty.h> | 21 | #include <linux/tty.h> |
22 | #include <linux/mtd/mtd.h> | 22 | #include <linux/mtd/mtd.h> |
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 23cb74885275..508593722bc7 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/tty.h> | 16 | #include <linux/tty.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/mtd/mtd.h> | 18 | #include <linux/mtd/mtd.h> |
19 | #include <linux/mtd/partitions.h> | 19 | #include <linux/mtd/partitions.h> |
20 | 20 | ||
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 7fd6e29c36b7..522abc036d3a 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/tty.h> | 22 | #include <linux/tty.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/mtd/mtd.h> | 25 | #include <linux/mtd/mtd.h> |
26 | #include <linux/mtd/partitions.h> | 26 | #include <linux/mtd/partitions.h> |
27 | #include <linux/timer.h> | 27 | #include <linux/timer.h> |
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 83eba8b54816..2abdc419e984 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/cpufreq.h> | 18 | #include <linux/cpufreq.h> |
19 | #include <linux/ioport.h> | 19 | #include <linux/ioport.h> |
20 | #include <linux/sched.h> /* just for sched_clock() - funny that */ | 20 | #include <linux/sched.h> /* just for sched_clock() - funny that */ |
21 | #include <linux/platform_device.h> | ||
21 | 22 | ||
22 | #include <asm/div64.h> | 23 | #include <asm/div64.h> |
23 | #include <asm/hardware.h> | 24 | #include <asm/hardware.h> |
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index 89af0c831e8f..2f671cc3cb99 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
7 | #include <linux/tty.h> | 7 | #include <linux/tty.h> |
8 | #include <linux/delay.h> | 8 | #include <linux/delay.h> |
9 | #include <linux/device.h> | 9 | #include <linux/platform_device.h> |
10 | #include <linux/ioport.h> | 10 | #include <linux/ioport.h> |
11 | #include <linux/mtd/mtd.h> | 11 | #include <linux/mtd/mtd.h> |
12 | #include <linux/mtd/partitions.h> | 12 | #include <linux/mtd/partitions.h> |
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index 052e4caedb89..69f1970646c6 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c | |||
@@ -8,7 +8,7 @@ | |||
8 | #include <linux/tty.h> | 8 | #include <linux/tty.h> |
9 | #include <linux/ioport.h> | 9 | #include <linux/ioport.h> |
10 | #include <linux/serial_core.h> | 10 | #include <linux/serial_core.h> |
11 | #include <linux/device.h> | 11 | #include <linux/platform_device.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | 13 | ||
14 | #include <asm/hardware.h> | 14 | #include <asm/hardware.h> |
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c index e17b58fb9c9c..58c18f9e9b7b 100644 --- a/arch/arm/mach-sa1100/pleb.c +++ b/arch/arm/mach-sa1100/pleb.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
7 | #include <linux/tty.h> | 7 | #include <linux/tty.h> |
8 | #include <linux/ioport.h> | 8 | #include <linux/ioport.h> |
9 | #include <linux/device.h> | 9 | #include <linux/platform_device.h> |
10 | 10 | ||
11 | #include <linux/mtd/partitions.h> | 11 | #include <linux/mtd/partitions.h> |
12 | 12 | ||
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index cfb6658e5cdf..439ddc9b06d6 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include <linux/proc_fs.h> | 10 | #include <linux/proc_fs.h> |
11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
12 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
13 | #include <linux/device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/mtd/mtd.h> | 14 | #include <linux/mtd/mtd.h> |
15 | #include <linux/mtd/partitions.h> | 15 | #include <linux/mtd/partitions.h> |
16 | 16 | ||
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 7e4bdd07f4af..a1ca46630dda 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
25 | #include <linux/platform_device.h> | ||
25 | #include <linux/sysdev.h> | 26 | #include <linux/sysdev.h> |
26 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
27 | 28 | ||
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c54e04c995ee..5568403e984d 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -120,8 +120,8 @@ config CPU_ARM925T | |||
120 | 120 | ||
121 | # ARM926T | 121 | # ARM926T |
122 | config CPU_ARM926T | 122 | config CPU_ARM926T |
123 | bool "Support ARM926T processor" if ARCH_INTEGRATOR | 123 | bool "Support ARM926T processor" |
124 | depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX | 124 | depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB |
125 | default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX | 125 | default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX |
126 | select CPU_32v5 | 126 | select CPU_32v5 |
127 | select CPU_ABRT_EV5TJ | 127 | select CPU_ABRT_EV5TJ |
@@ -242,7 +242,7 @@ config CPU_XSCALE | |||
242 | # ARMv6 | 242 | # ARMv6 |
243 | config CPU_V6 | 243 | config CPU_V6 |
244 | bool "Support ARM V6 processor" | 244 | bool "Support ARM V6 processor" |
245 | depends on ARCH_INTEGRATOR | 245 | depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB |
246 | select CPU_32v6 | 246 | select CPU_32v6 |
247 | select CPU_ABRT_EV6 | 247 | select CPU_ABRT_EV6 |
248 | select CPU_CACHE_V6 | 248 | select CPU_CACHE_V6 |
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c index 14a836d7ac25..205e2d0b826d 100644 --- a/arch/arm/plat-omap/usb.c +++ b/arch/arm/plat-omap/usb.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/usb_otg.h> | 30 | #include <linux/usb_otg.h> |
31 | 31 | ||
32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 5383e5e2d9b7..bac0da731ee3 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
@@ -1042,8 +1042,3 @@ config X86_TRAMPOLINE | |||
1042 | bool | 1042 | bool |
1043 | depends on X86_SMP || (X86_VOYAGER && SMP) | 1043 | depends on X86_SMP || (X86_VOYAGER && SMP) |
1044 | default y | 1044 | default y |
1045 | |||
1046 | config PC | ||
1047 | bool | ||
1048 | depends on X86 && !EMBEDDED | ||
1049 | default y | ||
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 9204be6eedb3..7c724ffa08bb 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
@@ -803,7 +803,6 @@ no_apic: | |||
803 | 803 | ||
804 | void __init init_apic_mappings(void) | 804 | void __init init_apic_mappings(void) |
805 | { | 805 | { |
806 | unsigned int orig_apicid; | ||
807 | unsigned long apic_phys; | 806 | unsigned long apic_phys; |
808 | 807 | ||
809 | /* | 808 | /* |
@@ -825,11 +824,8 @@ void __init init_apic_mappings(void) | |||
825 | * Fetch the APIC ID of the BSP in case we have a | 824 | * Fetch the APIC ID of the BSP in case we have a |
826 | * default configuration (or the MP table is broken). | 825 | * default configuration (or the MP table is broken). |
827 | */ | 826 | */ |
828 | orig_apicid = boot_cpu_physical_apicid; | 827 | if (boot_cpu_physical_apicid == -1U) |
829 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); | 828 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); |
830 | if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid)) | ||
831 | printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)", | ||
832 | orig_apicid, boot_cpu_physical_apicid); | ||
833 | 829 | ||
834 | #ifdef CONFIG_X86_IO_APIC | 830 | #ifdef CONFIG_X86_IO_APIC |
835 | { | 831 | { |
@@ -1259,81 +1255,40 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) | |||
1259 | } | 1255 | } |
1260 | 1256 | ||
1261 | /* | 1257 | /* |
1262 | * This initializes the IO-APIC and APIC hardware. | 1258 | * This initializes the IO-APIC and APIC hardware if this is |
1259 | * a UP kernel. | ||
1263 | */ | 1260 | */ |
1264 | int __init APIC_init(void) | 1261 | int __init APIC_init_uniprocessor (void) |
1265 | { | 1262 | { |
1266 | if (enable_local_apic < 0) { | 1263 | if (enable_local_apic < 0) |
1267 | printk(KERN_INFO "APIC disabled\n"); | 1264 | clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); |
1268 | return -1; | ||
1269 | } | ||
1270 | 1265 | ||
1271 | /* See if we have a SMP configuration or have forced enabled | 1266 | if (!smp_found_config && !cpu_has_apic) |
1272 | * the local apic. | ||
1273 | */ | ||
1274 | if (!smp_found_config && !acpi_lapic && !cpu_has_apic) { | ||
1275 | enable_local_apic = -1; | ||
1276 | return -1; | 1267 | return -1; |
1277 | } | ||
1278 | 1268 | ||
1279 | /* | 1269 | /* |
1280 | * Complain if the BIOS pretends there is an apic. | 1270 | * Complain if the BIOS pretends there is one. |
1281 | * Then get out because we don't have an a local apic. | ||
1282 | */ | 1271 | */ |
1283 | if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { | 1272 | if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { |
1284 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | 1273 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", |
1285 | boot_cpu_physical_apicid); | 1274 | boot_cpu_physical_apicid); |
1286 | printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); | ||
1287 | enable_local_apic = -1; | ||
1288 | return -1; | 1275 | return -1; |
1289 | } | 1276 | } |
1290 | 1277 | ||
1291 | verify_local_APIC(); | 1278 | verify_local_APIC(); |
1292 | 1279 | ||
1293 | /* | ||
1294 | * Should not be necessary because the MP table should list the boot | ||
1295 | * CPU too, but we do it for the sake of robustness anyway. | ||
1296 | * Makes no sense to do this check in clustered apic mode, so skip it | ||
1297 | */ | ||
1298 | if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { | ||
1299 | printk("weird, boot CPU (#%d) not listed by the BIOS.\n", | ||
1300 | boot_cpu_physical_apicid); | ||
1301 | physid_set(boot_cpu_physical_apicid, phys_cpu_present_map); | ||
1302 | } | ||
1303 | |||
1304 | /* | ||
1305 | * Switch from PIC to APIC mode. | ||
1306 | */ | ||
1307 | connect_bsp_APIC(); | 1280 | connect_bsp_APIC(); |
1308 | setup_local_APIC(); | ||
1309 | 1281 | ||
1310 | #ifdef CONFIG_X86_IO_APIC | 1282 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); |
1311 | /* | ||
1312 | * Now start the IO-APICs | ||
1313 | */ | ||
1314 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) | ||
1315 | setup_IO_APIC(); | ||
1316 | #endif | ||
1317 | return 0; | ||
1318 | } | ||
1319 | 1283 | ||
1320 | void __init APIC_late_time_init(void) | 1284 | setup_local_APIC(); |
1321 | { | ||
1322 | /* Improve our loops per jiffy estimate */ | ||
1323 | loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz; | ||
1324 | boot_cpu_data.loops_per_jiffy = loops_per_jiffy; | ||
1325 | cpu_data[0].loops_per_jiffy = loops_per_jiffy; | ||
1326 | |||
1327 | /* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is | ||
1328 | * initialized. So redo it here to ensure the boot cpu is setup | ||
1329 | * properly. | ||
1330 | */ | ||
1331 | if (nmi_watchdog == NMI_LOCAL_APIC) | ||
1332 | setup_apic_nmi_watchdog(); | ||
1333 | 1285 | ||
1334 | #ifdef CONFIG_X86_IO_APIC | 1286 | #ifdef CONFIG_X86_IO_APIC |
1335 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) | 1287 | if (smp_found_config) |
1336 | IO_APIC_late_time_init(); | 1288 | if (!skip_ioapic_setup && nr_ioapics) |
1289 | setup_IO_APIC(); | ||
1337 | #endif | 1290 | #endif |
1338 | setup_boot_APIC_clock(); | 1291 | setup_boot_APIC_clock(); |
1292 | |||
1293 | return 0; | ||
1339 | } | 1294 | } |
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d86f24909284..323ef8ab3244 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c | |||
@@ -435,8 +435,4 @@ void __init init_IRQ(void) | |||
435 | setup_irq(FPU_IRQ, &fpu_irq); | 435 | setup_irq(FPU_IRQ, &fpu_irq); |
436 | 436 | ||
437 | irq_ctx_init(smp_processor_id()); | 437 | irq_ctx_init(smp_processor_id()); |
438 | |||
439 | #ifdef CONFIG_X86_LOCAL_APIC | ||
440 | APIC_init(); | ||
441 | #endif | ||
442 | } | 438 | } |
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5a77c52b20a9..cc5d7ac5b2e7 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -2387,15 +2387,11 @@ void __init setup_IO_APIC(void) | |||
2387 | sync_Arb_IDs(); | 2387 | sync_Arb_IDs(); |
2388 | setup_IO_APIC_irqs(); | 2388 | setup_IO_APIC_irqs(); |
2389 | init_IO_APIC_traps(); | 2389 | init_IO_APIC_traps(); |
2390 | check_timer(); | ||
2390 | if (!acpi_ioapic) | 2391 | if (!acpi_ioapic) |
2391 | print_IO_APIC(); | 2392 | print_IO_APIC(); |
2392 | } | 2393 | } |
2393 | 2394 | ||
2394 | void __init IO_APIC_late_time_init(void) | ||
2395 | { | ||
2396 | check_timer(); | ||
2397 | } | ||
2398 | |||
2399 | /* | 2395 | /* |
2400 | * Called after all the initialization is done. If we didnt find any | 2396 | * Called after all the initialization is done. If we didnt find any |
2401 | * APIC bugs then we can allow the modify fast path | 2397 | * APIC bugs then we can allow the modify fast path |
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 5a2bbe0c4fff..01b618e73ecd 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
@@ -1078,16 +1078,6 @@ void *xquad_portio; | |||
1078 | EXPORT_SYMBOL(xquad_portio); | 1078 | EXPORT_SYMBOL(xquad_portio); |
1079 | #endif | 1079 | #endif |
1080 | 1080 | ||
1081 | /* | ||
1082 | * Fall back to non SMP mode after errors. | ||
1083 | * | ||
1084 | */ | ||
1085 | static __init void disable_smp(void) | ||
1086 | { | ||
1087 | cpu_set(0, cpu_sibling_map[0]); | ||
1088 | cpu_set(0, cpu_core_map[0]); | ||
1089 | } | ||
1090 | |||
1091 | static void __init smp_boot_cpus(unsigned int max_cpus) | 1081 | static void __init smp_boot_cpus(unsigned int max_cpus) |
1092 | { | 1082 | { |
1093 | int apicid, cpu, bit, kicked; | 1083 | int apicid, cpu, bit, kicked; |
@@ -1100,6 +1090,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1100 | printk("CPU%d: ", 0); | 1090 | printk("CPU%d: ", 0); |
1101 | print_cpu_info(&cpu_data[0]); | 1091 | print_cpu_info(&cpu_data[0]); |
1102 | 1092 | ||
1093 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); | ||
1103 | boot_cpu_logical_apicid = logical_smp_processor_id(); | 1094 | boot_cpu_logical_apicid = logical_smp_processor_id(); |
1104 | x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; | 1095 | x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; |
1105 | 1096 | ||
@@ -1111,27 +1102,68 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1111 | cpus_clear(cpu_core_map[0]); | 1102 | cpus_clear(cpu_core_map[0]); |
1112 | cpu_set(0, cpu_core_map[0]); | 1103 | cpu_set(0, cpu_core_map[0]); |
1113 | 1104 | ||
1114 | map_cpu_to_logical_apicid(); | ||
1115 | |||
1116 | /* | 1105 | /* |
1117 | * If we couldn't find an SMP configuration at boot time, | 1106 | * If we couldn't find an SMP configuration at boot time, |
1118 | * get out of here now! | 1107 | * get out of here now! |
1119 | */ | 1108 | */ |
1120 | if (!smp_found_config && !acpi_lapic) { | 1109 | if (!smp_found_config && !acpi_lapic) { |
1121 | printk(KERN_NOTICE "SMP motherboard not detected.\n"); | 1110 | printk(KERN_NOTICE "SMP motherboard not detected.\n"); |
1122 | disable_smp(); | 1111 | smpboot_clear_io_apic_irqs(); |
1112 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
1113 | if (APIC_init_uniprocessor()) | ||
1114 | printk(KERN_NOTICE "Local APIC not detected." | ||
1115 | " Using dummy APIC emulation.\n"); | ||
1116 | map_cpu_to_logical_apicid(); | ||
1117 | cpu_set(0, cpu_sibling_map[0]); | ||
1118 | cpu_set(0, cpu_core_map[0]); | ||
1119 | return; | ||
1120 | } | ||
1121 | |||
1122 | /* | ||
1123 | * Should not be necessary because the MP table should list the boot | ||
1124 | * CPU too, but we do it for the sake of robustness anyway. | ||
1125 | * Makes no sense to do this check in clustered apic mode, so skip it | ||
1126 | */ | ||
1127 | if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { | ||
1128 | printk("weird, boot CPU (#%d) not listed by the BIOS.\n", | ||
1129 | boot_cpu_physical_apicid); | ||
1130 | physid_set(hard_smp_processor_id(), phys_cpu_present_map); | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * If we couldn't find a local APIC, then get out of here now! | ||
1135 | */ | ||
1136 | if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) { | ||
1137 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | ||
1138 | boot_cpu_physical_apicid); | ||
1139 | printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); | ||
1140 | smpboot_clear_io_apic_irqs(); | ||
1141 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
1142 | cpu_set(0, cpu_sibling_map[0]); | ||
1143 | cpu_set(0, cpu_core_map[0]); | ||
1123 | return; | 1144 | return; |
1124 | } | 1145 | } |
1125 | 1146 | ||
1147 | verify_local_APIC(); | ||
1148 | |||
1126 | /* | 1149 | /* |
1127 | * If SMP should be disabled, then really disable it! | 1150 | * If SMP should be disabled, then really disable it! |
1128 | */ | 1151 | */ |
1129 | if (!max_cpus || (enable_local_apic < 0)) { | 1152 | if (!max_cpus) { |
1130 | printk(KERN_INFO "SMP mode deactivated.\n"); | 1153 | smp_found_config = 0; |
1131 | disable_smp(); | 1154 | printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); |
1155 | smpboot_clear_io_apic_irqs(); | ||
1156 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
1157 | cpu_set(0, cpu_sibling_map[0]); | ||
1158 | cpu_set(0, cpu_core_map[0]); | ||
1132 | return; | 1159 | return; |
1133 | } | 1160 | } |
1134 | 1161 | ||
1162 | connect_bsp_APIC(); | ||
1163 | setup_local_APIC(); | ||
1164 | map_cpu_to_logical_apicid(); | ||
1165 | |||
1166 | |||
1135 | setup_portio_remap(); | 1167 | setup_portio_remap(); |
1136 | 1168 | ||
1137 | /* | 1169 | /* |
@@ -1212,6 +1244,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
1212 | cpu_set(0, cpu_sibling_map[0]); | 1244 | cpu_set(0, cpu_sibling_map[0]); |
1213 | cpu_set(0, cpu_core_map[0]); | 1245 | cpu_set(0, cpu_core_map[0]); |
1214 | 1246 | ||
1247 | smpboot_setup_io_apic(); | ||
1248 | |||
1249 | setup_boot_APIC_clock(); | ||
1250 | |||
1215 | /* | 1251 | /* |
1216 | * Synchronize the TSC with the AP | 1252 | * Synchronize the TSC with the AP |
1217 | */ | 1253 | */ |
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 07471bba2dc6..41c5b2dc6200 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -440,8 +440,8 @@ static int time_init_device(void) | |||
440 | 440 | ||
441 | device_initcall(time_init_device); | 441 | device_initcall(time_init_device); |
442 | 442 | ||
443 | extern void (*late_time_init)(void); | ||
444 | #ifdef CONFIG_HPET_TIMER | 443 | #ifdef CONFIG_HPET_TIMER |
444 | extern void (*late_time_init)(void); | ||
445 | /* Duplicate of time_init() below, with hpet_enable part added */ | 445 | /* Duplicate of time_init() below, with hpet_enable part added */ |
446 | static void __init hpet_time_init(void) | 446 | static void __init hpet_time_init(void) |
447 | { | 447 | { |
@@ -458,11 +458,6 @@ static void __init hpet_time_init(void) | |||
458 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | 458 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); |
459 | 459 | ||
460 | time_init_hook(); | 460 | time_init_hook(); |
461 | |||
462 | #ifdef CONFIG_X86_LOCAL_APIC | ||
463 | if (enable_local_apic >= 0) | ||
464 | APIC_late_time_init(); | ||
465 | #endif | ||
466 | } | 461 | } |
467 | #endif | 462 | #endif |
468 | 463 | ||
@@ -487,9 +482,4 @@ void __init time_init(void) | |||
487 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | 482 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); |
488 | 483 | ||
489 | time_init_hook(); | 484 | time_init_hook(); |
490 | |||
491 | #ifdef CONFIG_X86_LOCAL_APIC | ||
492 | if (enable_local_apic >= 0) | ||
493 | late_time_init = APIC_late_time_init; | ||
494 | #endif | ||
495 | } | 485 | } |
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index 330fd2b68075..3984226a8b98 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c | |||
@@ -398,7 +398,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); | |||
398 | */ | 398 | */ |
399 | static u16 toshiba_line_size; | 399 | static u16 toshiba_line_size; |
400 | 400 | ||
401 | static struct dmi_system_id __devinit toshiba_ohci1394_dmi_table[] = { | 401 | static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { |
402 | { | 402 | { |
403 | .ident = "Toshiba PS5 based laptop", | 403 | .ident = "Toshiba PS5 based laptop", |
404 | .matches = { | 404 | .matches = { |
diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c index 708634b685e4..cb76916b014d 100644 --- a/arch/m32r/kernel/setup_m32700ut.c +++ b/arch/m32r/kernel/setup_m32700ut.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/device.h> | 18 | #include <linux/platform_device.h> |
19 | 19 | ||
20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
21 | #include <asm/m32r.h> | 21 | #include <asm/m32r.h> |
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c index 4e709809efc5..501d798cf050 100644 --- a/arch/m32r/kernel/setup_mappi.c +++ b/arch/m32r/kernel/setup_mappi.c | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | 15 | ||
16 | #include <asm/system.h> | 16 | #include <asm/system.h> |
17 | #include <asm/m32r.h> | 17 | #include <asm/m32r.h> |
diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c index a1d801598aa4..7f2db5bfd626 100644 --- a/arch/m32r/kernel/setup_mappi2.c +++ b/arch/m32r/kernel/setup_mappi2.c | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | 15 | ||
16 | #include <asm/system.h> | 16 | #include <asm/system.h> |
17 | #include <asm/m32r.h> | 17 | #include <asm/m32r.h> |
diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c index a76412e883e8..9c79341a7b45 100644 --- a/arch/m32r/kernel/setup_mappi3.c +++ b/arch/m32r/kernel/setup_mappi3.c | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | 15 | ||
16 | #include <asm/system.h> | 16 | #include <asm/system.h> |
17 | #include <asm/m32r.h> | 17 | #include <asm/m32r.h> |
diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c index d7b7ec6d30f8..1fbb140854e7 100644 --- a/arch/m32r/kernel/setup_opsput.c +++ b/arch/m32r/kernel/setup_opsput.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/device.h> | 19 | #include <linux/platform_device.h> |
20 | 20 | ||
21 | #include <asm/system.h> | 21 | #include <asm/system.h> |
22 | #include <asm/m32r.h> | 22 | #include <asm/m32r.h> |
diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c index 1f7b465c8038..48d3f54f88f8 100644 --- a/arch/mips/au1000/common/platform.c +++ b/arch/mips/au1000/common/platform.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
12 | #include <linux/platform_device.h> | ||
12 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
14 | #include <linux/resource.h> | 15 | #include <linux/resource.h> |
diff --git a/arch/ppc/platforms/4xx/ibm440ep.c b/arch/ppc/platforms/4xx/ibm440ep.c index 4712de8ff80f..65ac0b9c2d05 100644 --- a/arch/ppc/platforms/4xx/ibm440ep.c +++ b/arch/ppc/platforms/4xx/ibm440ep.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/platform_device.h> | ||
17 | #include <platforms/4xx/ibm440ep.h> | 18 | #include <platforms/4xx/ibm440ep.h> |
18 | #include <asm/ocp.h> | 19 | #include <asm/ocp.h> |
19 | #include <asm/ppc4xx_pic.h> | 20 | #include <asm/ppc4xx_pic.h> |
diff --git a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c index d90627b68faa..7e33bb635443 100644 --- a/arch/ppc/platforms/4xx/ibmstb4.c +++ b/arch/ppc/platforms/4xx/ibmstb4.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/platform_device.h> | ||
13 | #include <asm/ocp.h> | 14 | #include <asm/ocp.h> |
14 | #include <asm/ppc4xx_pic.h> | 15 | #include <asm/ppc4xx_pic.h> |
15 | #include <platforms/4xx/ibmstb4.h> | 16 | #include <platforms/4xx/ibmstb4.h> |
diff --git a/arch/ppc/platforms/4xx/redwood5.c b/arch/ppc/platforms/4xx/redwood5.c index bee8b4ac8afd..611ac861804d 100644 --- a/arch/ppc/platforms/4xx/redwood5.c +++ b/arch/ppc/platforms/4xx/redwood5.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/config.h> | 14 | #include <linux/config.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/pagemap.h> | 16 | #include <linux/pagemap.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/ioport.h> | 18 | #include <linux/ioport.h> |
19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
20 | #include <asm/machdep.h> | 20 | #include <asm/machdep.h> |
diff --git a/arch/ppc/platforms/4xx/redwood6.c b/arch/ppc/platforms/4xx/redwood6.c index 8b1012994dfc..b13116691289 100644 --- a/arch/ppc/platforms/4xx/redwood6.c +++ b/arch/ppc/platforms/4xx/redwood6.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/pagemap.h> | 14 | #include <linux/pagemap.h> |
15 | #include <linux/device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/ioport.h> | 16 | #include <linux/ioport.h> |
17 | #include <asm/io.h> | 17 | #include <asm/io.h> |
18 | #include <asm/ppc4xx_pic.h> | 18 | #include <asm/ppc4xx_pic.h> |
diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c index a9052305c35d..108a6e265185 100644 --- a/arch/ppc/platforms/chrp_pegasos_eth.c +++ b/arch/ppc/platforms/chrp_pegasos_eth.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/ioport.h> | 15 | #include <linux/ioport.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/mv643xx.h> | 17 | #include <linux/mv643xx.h> |
18 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
19 | 19 | ||
diff --git a/arch/ppc/platforms/cpci690.c b/arch/ppc/platforms/cpci690.c index f64ac2acb603..6ca7bcac9474 100644 --- a/arch/ppc/platforms/cpci690.c +++ b/arch/ppc/platforms/cpci690.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/initrd.h> | 21 | #include <linux/initrd.h> |
22 | #include <linux/root_dev.h> | 22 | #include <linux/root_dev.h> |
23 | #include <linux/mv643xx.h> | 23 | #include <linux/mv643xx.h> |
24 | #include <linux/platform_device.h> | ||
24 | #include <asm/bootinfo.h> | 25 | #include <asm/bootinfo.h> |
25 | #include <asm/machdep.h> | 26 | #include <asm/machdep.h> |
26 | #include <asm/todc.h> | 27 | #include <asm/todc.h> |
diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c index aa50637a5cfb..32358b3fb236 100644 --- a/arch/ppc/platforms/ev64260.c +++ b/arch/ppc/platforms/ev64260.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/console.h> | 33 | #include <linux/console.h> |
34 | #include <linux/initrd.h> | 34 | #include <linux/initrd.h> |
35 | #include <linux/root_dev.h> | 35 | #include <linux/root_dev.h> |
36 | #include <linux/platform_device.h> | ||
36 | #if !defined(CONFIG_SERIAL_MPSC_CONSOLE) | 37 | #if !defined(CONFIG_SERIAL_MPSC_CONSOLE) |
37 | #include <linux/serial.h> | 38 | #include <linux/serial.h> |
38 | #include <linux/tty.h> | 39 | #include <linux/tty.h> |
diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c index 53388a1c334f..b1324564456e 100644 --- a/arch/ppc/platforms/ev64360.c +++ b/arch/ppc/platforms/ev64360.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/bootmem.h> | 25 | #include <linux/bootmem.h> |
26 | #include <linux/mtd/physmap.h> | 26 | #include <linux/mtd/physmap.h> |
27 | #include <linux/mv643xx.h> | 27 | #include <linux/mv643xx.h> |
28 | #include <linux/platform_device.h> | ||
28 | #ifdef CONFIG_BOOTIMG | 29 | #ifdef CONFIG_BOOTIMG |
29 | #include <linux/bootimg.h> | 30 | #include <linux/bootimg.h> |
30 | #endif | 31 | #endif |
diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c index b6a66d5e9d83..50039a204c24 100644 --- a/arch/ppc/platforms/hdpu.c +++ b/arch/ppc/platforms/hdpu.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/ide.h> | 23 | #include <linux/ide.h> |
24 | #include <linux/seq_file.h> | 24 | #include <linux/seq_file.h> |
25 | #include <linux/platform_device.h> | ||
25 | 26 | ||
26 | #include <linux/initrd.h> | 27 | #include <linux/initrd.h> |
27 | #include <linux/root_dev.h> | 28 | #include <linux/root_dev.h> |
diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c index a301c5ac58dd..6e58e30ceed1 100644 --- a/arch/ppc/platforms/katana.c +++ b/arch/ppc/platforms/katana.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
30 | #include <linux/mtd/physmap.h> | 30 | #include <linux/mtd/physmap.h> |
31 | #include <linux/mv643xx.h> | 31 | #include <linux/mv643xx.h> |
32 | #include <linux/platform_device.h> | ||
32 | #ifdef CONFIG_BOOTIMG | 33 | #ifdef CONFIG_BOOTIMG |
33 | #include <linux/bootimg.h> | 34 | #include <linux/bootimg.h> |
34 | #endif | 35 | #endif |
diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c index 6f97911c330d..708b8739ecdd 100644 --- a/arch/ppc/platforms/radstone_ppc7d.c +++ b/arch/ppc/platforms/radstone_ppc7d.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/serial_core.h> | 40 | #include <linux/serial_core.h> |
41 | #include <linux/mv643xx.h> | 41 | #include <linux/mv643xx.h> |
42 | #include <linux/netdevice.h> | 42 | #include <linux/netdevice.h> |
43 | #include <linux/platform_device.h> | ||
43 | 44 | ||
44 | #include <asm/system.h> | 45 | #include <asm/system.h> |
45 | #include <asm/pgtable.h> | 46 | #include <asm/pgtable.h> |
diff --git a/arch/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c index ad5182efca1d..da3c74bfdc92 100644 --- a/arch/ppc/syslib/mpc52xx_devices.c +++ b/arch/ppc/syslib/mpc52xx_devices.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/fsl_devices.h> | 16 | #include <linux/fsl_devices.h> |
17 | #include <linux/resource.h> | 17 | #include <linux/resource.h> |
18 | #include <linux/platform_device.h> | ||
18 | #include <asm/mpc52xx.h> | 19 | #include <asm/mpc52xx.h> |
19 | #include <asm/ppc_sys.h> | 20 | #include <asm/ppc_sys.h> |
20 | 21 | ||
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c index a781c50d2f4c..94ea346b7b4b 100644 --- a/arch/ppc/syslib/mv64x60.c +++ b/arch/ppc/syslib/mv64x60.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/mv643xx.h> | 21 | #include <linux/mv643xx.h> |
22 | #include <linux/platform_device.h> | ||
22 | 23 | ||
23 | #include <asm/byteorder.h> | 24 | #include <asm/byteorder.h> |
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c index 6f88ba93412b..e960fe935325 100644 --- a/arch/ppc/syslib/pq2_devices.c +++ b/arch/ppc/syslib/pq2_devices.c | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/ioport.h> | 17 | #include <linux/ioport.h> |
18 | #include <asm/cpm2.h> | 18 | #include <asm/cpm2.h> |
19 | #include <asm/irq.h> | 19 | #include <asm/irq.h> |
diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c index c18919941ec0..1c1d65fb12df 100644 --- a/arch/sh/boards/superh/microdev/setup.c +++ b/arch/sh/boards/superh/microdev/setup.c | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/config.h> | 14 | #include <linux/config.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/ioport.h> | 17 | #include <linux/ioport.h> |
18 | #include <asm/io.h> | 18 | #include <asm/io.h> |
19 | #include <asm/mach/irq.h> | 19 | #include <asm/mach/irq.h> |
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 1495007bf6c0..721e2601a75d 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "linux/ctype.h" | 20 | #include "linux/ctype.h" |
21 | #include "linux/bootmem.h" | 21 | #include "linux/bootmem.h" |
22 | #include "linux/ethtool.h" | 22 | #include "linux/ethtool.h" |
23 | #include "linux/platform_device.h" | ||
23 | #include "asm/uaccess.h" | 24 | #include "asm/uaccess.h" |
24 | #include "user_util.h" | 25 | #include "user_util.h" |
25 | #include "kern_util.h" | 26 | #include "kern_util.h" |
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f73134333f64..b2c86257b0f8 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include "linux/blkpg.h" | 35 | #include "linux/blkpg.h" |
36 | #include "linux/genhd.h" | 36 | #include "linux/genhd.h" |
37 | #include "linux/spinlock.h" | 37 | #include "linux/spinlock.h" |
38 | #include "linux/platform_device.h" | ||
38 | #include "asm/segment.h" | 39 | #include "asm/segment.h" |
39 | #include "asm/uaccess.h" | 40 | #include "asm/uaccess.h" |
40 | #include "asm/irq.h" | 41 | #include "asm/irq.h" |
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c index 498d7dced1f4..0682ffd38175 100644 --- a/arch/xtensa/platform-iss/network.c +++ b/arch/xtensa/platform-iss/network.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/ethtool.h> | 33 | #include <linux/ethtool.h> |
34 | #include <linux/rtnetlink.h> | 34 | #include <linux/rtnetlink.h> |
35 | #include <linux/timer.h> | 35 | #include <linux/timer.h> |
36 | #include <linux/platform_device.h> | ||
36 | 37 | ||
37 | #include <xtensa/simcall.h> | 38 | #include <xtensa/simcall.h> |
38 | 39 | ||
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 08d9cc99c7de..d597c922af11 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -10,7 +10,7 @@ | |||
10 | * information. | 10 | * information. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/dma-mapping.h> | 16 | #include <linux/dma-mapping.h> |
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index 5281f8e70510..ecacca9c877e 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c | |||
@@ -2059,10 +2059,8 @@ static void cfq_put_cfqd(struct cfq_data *cfqd) | |||
2059 | if (!atomic_dec_and_test(&cfqd->ref)) | 2059 | if (!atomic_dec_and_test(&cfqd->ref)) |
2060 | return; | 2060 | return; |
2061 | 2061 | ||
2062 | blk_put_queue(q); | ||
2063 | |||
2064 | cfq_shutdown_timer_wq(cfqd); | 2062 | cfq_shutdown_timer_wq(cfqd); |
2065 | q->elevator->elevator_data = NULL; | 2063 | blk_put_queue(q); |
2066 | 2064 | ||
2067 | mempool_destroy(cfqd->crq_pool); | 2065 | mempool_destroy(cfqd->crq_pool); |
2068 | kfree(cfqd->crq_hash); | 2066 | kfree(cfqd->crq_hash); |
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 00895477155e..5eadbb9d4d71 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c | |||
@@ -177,7 +177,7 @@ static int print_unex = 1; | |||
177 | #include <linux/interrupt.h> | 177 | #include <linux/interrupt.h> |
178 | #include <linux/init.h> | 178 | #include <linux/init.h> |
179 | #include <linux/devfs_fs_kernel.h> | 179 | #include <linux/devfs_fs_kernel.h> |
180 | #include <linux/device.h> | 180 | #include <linux/platform_device.h> |
181 | #include <linux/buffer_head.h> /* for invalidate_buffers() */ | 181 | #include <linux/buffer_head.h> /* for invalidate_buffers() */ |
182 | 182 | ||
183 | /* | 183 | /* |
diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c index f56b8edb06e4..e54f006e7e60 100644 --- a/drivers/block/noop-iosched.c +++ b/drivers/block/noop-iosched.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | static void elevator_noop_add_request(request_queue_t *q, struct request *rq) | 10 | static void elevator_noop_add_request(request_queue_t *q, struct request *rq) |
11 | { | 11 | { |
12 | rq->flags |= REQ_NOMERGE; | ||
12 | elv_dispatch_add_tail(q, rq); | 13 | elv_dispatch_add_tail(q, rq); |
13 | } | 14 | } |
14 | 15 | ||
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c index 887b8b2d7882..d724c0de4f28 100644 --- a/drivers/char/s3c2410-rtc.c +++ b/drivers/char/s3c2410-rtc.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/rtc.h> | 25 | #include <linux/rtc.h> |
26 | #include <linux/bcd.h> | 26 | #include <linux/bcd.h> |
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index f86c15587238..d05067dcea01 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/dmi.h> | 48 | #include <linux/dmi.h> |
49 | #include <linux/err.h> | 49 | #include <linux/err.h> |
50 | #include <linux/kfifo.h> | 50 | #include <linux/kfifo.h> |
51 | #include <linux/platform_device.h> | ||
51 | 52 | ||
52 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
53 | #include <asm/io.h> | 54 | #include <asm/io.h> |
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index eb7058cbf015..24355b23b2ca 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c | |||
@@ -17,7 +17,7 @@ | |||
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | #include <linux/device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c index 683278bc5241..94641085faf8 100644 --- a/drivers/char/vr41xx_giu.c +++ b/drivers/char/vr41xx_giu.c | |||
@@ -19,7 +19,7 @@ | |||
19 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | #include <linux/device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
diff --git a/drivers/char/vr41xx_rtc.c b/drivers/char/vr41xx_rtc.c index a6dbe4da030c..5e3292df69d8 100644 --- a/drivers/char/vr41xx_rtc.c +++ b/drivers/char/vr41xx_rtc.c | |||
@@ -17,7 +17,7 @@ | |||
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | #include <linux/device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/ioport.h> | 23 | #include <linux/ioport.h> |
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index 75ca84ed4adf..da631c114fd1 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/reboot.h> | 29 | #include <linux/reboot.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/device.h> | 32 | #include <linux/platform_device.h> |
33 | 33 | ||
34 | #include <asm/hardware/arm_twd.h> | 34 | #include <asm/hardware/arm_twd.h> |
35 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -396,6 +396,7 @@ static int __devexit mpcore_wdt_remove(struct device *dev) | |||
396 | } | 396 | } |
397 | 397 | ||
398 | static struct device_driver mpcore_wdt_driver = { | 398 | static struct device_driver mpcore_wdt_driver = { |
399 | .owner = THIS_MODULE, | ||
399 | .name = "mpcore_wdt", | 400 | .name = "mpcore_wdt", |
400 | .bus = &platform_bus_type, | 401 | .bus = &platform_bus_type, |
401 | .probe = mpcore_wdt_probe, | 402 | .probe = mpcore_wdt_probe, |
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c index 6d3ff0836c44..119b3c541d95 100644 --- a/drivers/char/watchdog/mv64x60_wdt.c +++ b/drivers/char/watchdog/mv64x60_wdt.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/miscdevice.h> | 22 | #include <linux/miscdevice.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/watchdog.h> | 24 | #include <linux/watchdog.h> |
25 | #include <linux/platform_device.h> | ||
26 | |||
25 | #include <asm/mv64x60.h> | 27 | #include <asm/mv64x60.h> |
26 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
27 | #include <asm/io.h> | 29 | #include <asm/io.h> |
@@ -211,6 +213,7 @@ static int __devexit mv64x60_wdt_remove(struct device *dev) | |||
211 | } | 213 | } |
212 | 214 | ||
213 | static struct device_driver mv64x60_wdt_driver = { | 215 | static struct device_driver mv64x60_wdt_driver = { |
216 | .owner = THIS_MODULE, | ||
214 | .name = MV64x60_WDT_NAME, | 217 | .name = MV64x60_WDT_NAME, |
215 | .bus = &platform_bus_type, | 218 | .bus = &platform_bus_type, |
216 | .probe = mv64x60_wdt_probe, | 219 | .probe = mv64x60_wdt_probe, |
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 5308e5c8f29a..d9ef55bdf88a 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Berkshire PCI-PC Watchdog Card Driver | 2 | * Berkshire PCI-PC Watchdog Card Driver |
3 | * | 3 | * |
4 | * (c) Copyright 2003 Wim Van Sebroeck <wim@iguana.be>. | 4 | * (c) Copyright 2003-2005 Wim Van Sebroeck <wim@iguana.be>. |
5 | * | 5 | * |
6 | * Based on source code of the following authors: | 6 | * Based on source code of the following authors: |
7 | * Ken Hollis <kenji@bitgate.com>, | 7 | * Ken Hollis <kenji@bitgate.com>, |
@@ -21,7 +21,9 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * A bells and whistles driver is available from http://www.pcwd.de/ | 24 | * A bells and whistles driver is available from: |
25 | * http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/ | ||
26 | * | ||
25 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ | 27 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ |
26 | */ | 28 | */ |
27 | 29 | ||
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index b732020acadb..751cb77b0715 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <linux/watchdog.h> | 44 | #include <linux/watchdog.h> |
45 | #include <linux/fs.h> | 45 | #include <linux/fs.h> |
46 | #include <linux/init.h> | 46 | #include <linux/init.h> |
47 | #include <linux/device.h> | 47 | #include <linux/platform_device.h> |
48 | #include <linux/interrupt.h> | 48 | #include <linux/interrupt.h> |
49 | 49 | ||
50 | #include <asm/uaccess.h> | 50 | #include <asm/uaccess.h> |
@@ -497,6 +497,7 @@ static int s3c2410wdt_resume(struct device *dev) | |||
497 | 497 | ||
498 | 498 | ||
499 | static struct device_driver s3c2410wdt_driver = { | 499 | static struct device_driver s3c2410wdt_driver = { |
500 | .owner = THIS_MODULE, | ||
500 | .name = "s3c2410-wdt", | 501 | .name = "s3c2410-wdt", |
501 | .bus = &platform_bus_type, | 502 | .bus = &platform_bus_type, |
502 | .probe = s3c2410wdt_probe, | 503 | .probe = s3c2410wdt_probe, |
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index b5d821015421..d15ca9a3986f 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c | |||
@@ -359,5 +359,5 @@ module_exit(wdt_exit); | |||
359 | 359 | ||
360 | MODULE_LICENSE("GPL"); | 360 | MODULE_LICENSE("GPL"); |
361 | MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>"); | 361 | MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>"); |
362 | MODULE_DESCRIPTION("w38627hf WDT driver"); | 362 | MODULE_DESCRIPTION("w83627hf WDT driver"); |
363 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 363 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c index 15677f20bd85..0f97a0cb0ff4 100644 --- a/drivers/eisa/virtual_root.c +++ b/drivers/eisa/virtual_root.c | |||
@@ -9,7 +9,7 @@ | |||
9 | 9 | ||
10 | #include <linux/config.h> | 10 | #include <linux/config.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/device.h> | 12 | #include <linux/platform_device.h> |
13 | #include <linux/eisa.h> | 13 | #include <linux/eisa.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 955537fe9958..8ed6ddbb9c5d 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c | |||
@@ -20,7 +20,7 @@ | |||
20 | * GNU General Public License for more details. | 20 | * GNU General Public License for more details. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 4f4ba9b6d182..125929c9048f 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/errno.h> | 42 | #include <linux/errno.h> |
43 | #include <linux/blkdev.h> | 43 | #include <linux/blkdev.h> |
44 | #include <linux/device.h> | 44 | #include <linux/platform_device.h> |
45 | #include <linux/spinlock.h> | 45 | #include <linux/spinlock.h> |
46 | #include <linux/moduleparam.h> | 46 | #include <linux/moduleparam.h> |
47 | #include <linux/firmware.h> | 47 | #include <linux/firmware.h> |
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 0015da5668a1..1e5dfc7805e2 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c | |||
@@ -27,7 +27,7 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/input.h> | 31 | #include <linux/input.h> |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 9888fae1f37a..cfae4ad00fae 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c | |||
@@ -11,7 +11,7 @@ | |||
11 | * | 11 | * |
12 | * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund | 12 | * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund |
13 | * | 13 | * |
14 | * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>, | 14 | * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>, |
15 | * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> | 15 | * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> |
16 | * | 16 | * |
17 | * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005: | 17 | * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005: |
@@ -35,7 +35,7 @@ | |||
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
37 | #include <linux/sched.h> | 37 | #include <linux/sched.h> |
38 | #include <linux/device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
40 | 40 | ||
41 | #include <asm/io.h> | 41 | #include <asm/io.h> |
@@ -184,7 +184,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, | |||
184 | do { | 184 | do { |
185 | interrupted = wait_event_interruptible_timeout ( | 185 | interrupted = wait_event_interruptible_timeout ( |
186 | iop3xx_adap->waitq, | 186 | iop3xx_adap->waitq, |
187 | (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), | 187 | (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), |
188 | 1 * HZ; | 188 | 1 * HZ; |
189 | ); | 189 | ); |
190 | if ((rc = iop3xx_i2c_error(sr)) < 0) { | 190 | if ((rc = iop3xx_i2c_error(sr)) < 0) { |
@@ -472,9 +472,10 @@ iop3xx_i2c_probe(struct device *dev) | |||
472 | goto release_region; | 472 | goto release_region; |
473 | } | 473 | } |
474 | 474 | ||
475 | res = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0, | 475 | ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0, |
476 | pdev->name, adapter_data); | 476 | pdev->name, adapter_data); |
477 | if (res) { | 477 | |
478 | if (ret) { | ||
478 | ret = -EIO; | 479 | ret = -EIO; |
479 | goto unmap; | 480 | goto unmap; |
480 | } | 481 | } |
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 4fdc02411609..03672c9ca409 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/errno.h> | 38 | #include <linux/errno.h> |
39 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
40 | #include <linux/i2c-isa.h> | 40 | #include <linux/i2c-isa.h> |
41 | #include <linux/platform_device.h> | ||
41 | 42 | ||
42 | static u32 isa_func(struct i2c_adapter *adapter); | 43 | static u32 isa_func(struct i2c_adapter *adapter); |
43 | 44 | ||
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index 42016ee6ef13..64552a376f2d 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/device.h> | 31 | #include <linux/platform_device.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
34 | #include <linux/i2c-algo-bit.h> | 34 | #include <linux/i2c-algo-bit.h> |
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 69303ab65e04..cc652c350814 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/device.h> | 31 | #include <linux/platform_device.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
34 | #include <linux/i2c-algo-bit.h> | 34 | #include <linux/i2c-algo-bit.h> |
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 8491633005b8..65b939a059e9 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/platform_device.h> | ||
23 | |||
22 | #include <asm/io.h> | 24 | #include <asm/io.h> |
23 | #include <linux/fsl_devices.h> | 25 | #include <linux/fsl_devices.h> |
24 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index d0d2a6f1386e..6b48027b2ee3 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/mv643xx.h> | 19 | #include <linux/mv643xx.h> |
20 | #include <linux/platform_device.h> | ||
21 | |||
20 | #include <asm/io.h> | 22 | #include <asm/io.h> |
21 | 23 | ||
22 | /* Register defines */ | 24 | /* Register defines */ |
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 44b595d90a4a..67ccbea24ba4 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/i2c-pxa.h> | 32 | #include <linux/i2c-pxa.h> |
33 | #include <linux/platform_device.h> | ||
33 | 34 | ||
34 | #include <asm/hardware.h> | 35 | #include <asm/hardware.h> |
35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6ced28e90070..1b582262e677 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
35 | #include <linux/err.h> | 35 | #include <linux/err.h> |
36 | #include <linux/device.h> | 36 | #include <linux/platform_device.h> |
37 | 37 | ||
38 | #include <asm/hardware.h> | 38 | #include <asm/hardware.h> |
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
@@ -918,8 +918,11 @@ static int __init i2c_adap_s3c_init(void) | |||
918 | int ret; | 918 | int ret; |
919 | 919 | ||
920 | ret = driver_register(&s3c2410_i2c_driver); | 920 | ret = driver_register(&s3c2410_i2c_driver); |
921 | if (ret == 0) | 921 | if (ret == 0) { |
922 | ret = driver_register(&s3c2440_i2c_driver); | 922 | ret = driver_register(&s3c2440_i2c_driver); |
923 | if (ret) | ||
924 | driver_unregister(&s3c2410_i2c_driver); | ||
925 | } | ||
923 | 926 | ||
924 | return ret; | 927 | return ret; |
925 | } | 928 | } |
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index eaa4742e04fa..9dbb72fffbe2 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c | |||
@@ -27,7 +27,7 @@ | |||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/usb_ch9.h> | 31 | #include <linux/usb_ch9.h> |
32 | #include <linux/usb_gadget.h> | 32 | #include <linux/usb_gadget.h> |
33 | #include <linux/usb.h> | 33 | #include <linux/usb.h> |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 02e335a04f09..82ea1b7ec914 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/idr.h> | 31 | #include <linux/idr.h> |
32 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
33 | #include <linux/platform_device.h> | ||
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
34 | 35 | ||
35 | 36 | ||
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ea14c8f1c82b..8af0bd1424d2 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/i2c.h> | 35 | #include <linux/i2c.h> |
36 | #include <linux/i2c-dev.h> | 36 | #include <linux/i2c-dev.h> |
37 | #include <linux/platform_device.h> | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
39 | static struct i2c_client i2cdev_client_template; | 40 | static struct i2c_client i2cdev_client_template; |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index a4696cd0978c..9f2352bd8348 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -565,6 +565,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon | |||
565 | case EV_LED: bits = dev->ledbit; max = LED_MAX; break; | 565 | case EV_LED: bits = dev->ledbit; max = LED_MAX; break; |
566 | case EV_SND: bits = dev->sndbit; max = SND_MAX; break; | 566 | case EV_SND: bits = dev->sndbit; max = SND_MAX; break; |
567 | case EV_FF: bits = dev->ffbit; max = FF_MAX; break; | 567 | case EV_FF: bits = dev->ffbit; max = FF_MAX; break; |
568 | case EV_SW: bits = dev->swbit; max = SW_MAX; break; | ||
568 | default: return -EINVAL; | 569 | default: return -EINVAL; |
569 | } | 570 | } |
570 | bit_to_user(bits, max); | 571 | bit_to_user(bits, max); |
@@ -579,6 +580,9 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon | |||
579 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | 580 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) |
580 | bit_to_user(dev->snd, SND_MAX); | 581 | bit_to_user(dev->snd, SND_MAX); |
581 | 582 | ||
583 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | ||
584 | bit_to_user(dev->sw, SW_MAX); | ||
585 | |||
582 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | 586 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { |
583 | int len; | 587 | int len; |
584 | if (!dev->name) return -ENOENT; | 588 | if (!dev->name) return -ENOENT; |
diff --git a/drivers/input/input.c b/drivers/input/input.c index 3b1685ff9d10..1a1654caedd5 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -730,7 +730,7 @@ static void input_register_classdevice(struct input_dev *dev) | |||
730 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); | 730 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); |
731 | 731 | ||
732 | path = kobject_get_path(&dev->cdev.class->subsys.kset.kobj, GFP_KERNEL); | 732 | path = kobject_get_path(&dev->cdev.class->subsys.kset.kobj, GFP_KERNEL); |
733 | printk(KERN_INFO "input: %s/%s as %s\n", | 733 | printk(KERN_INFO "input: %s as %s/%s\n", |
734 | dev->name ? dev->name : "Unspecified device", | 734 | dev->name ? dev->name : "Unspecified device", |
735 | path ? path : "", dev->cdev.class_id); | 735 | path ? path : "", dev->cdev.class_id); |
736 | kfree(path); | 736 | kfree(path); |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 571a68691a4a..4a917748fd9f 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -13,11 +13,11 @@ menuconfig INPUT_KEYBOARD | |||
13 | if INPUT_KEYBOARD | 13 | if INPUT_KEYBOARD |
14 | 14 | ||
15 | config KEYBOARD_ATKBD | 15 | config KEYBOARD_ATKBD |
16 | tristate "AT keyboard" if !PC | 16 | tristate "AT keyboard" if !X86_PC |
17 | default y | 17 | default y |
18 | select SERIO | 18 | select SERIO |
19 | select SERIO_LIBPS2 | 19 | select SERIO_LIBPS2 |
20 | select SERIO_I8042 if PC | 20 | select SERIO_I8042 if X86_PC |
21 | select SERIO_GSCPS2 if GSC | 21 | select SERIO_GSCPS2 if GSC |
22 | help | 22 | help |
23 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually | 23 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually |
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 3210d298b3bc..d00d14bb637a 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/input.h> | 17 | #include <linux/input.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 7f06780a437f..9481132532d0 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c | |||
@@ -441,7 +441,7 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, | |||
441 | input_sync (lk->dev); | 441 | input_sync (lk->dev); |
442 | break; | 442 | break; |
443 | case LK_METRONOME: | 443 | case LK_METRONOME: |
444 | DBG (KERN_INFO "Got %#d and don't " | 444 | DBG (KERN_INFO "Got LK_METRONOME and don't " |
445 | "know how to handle...\n"); | 445 | "know how to handle...\n"); |
446 | break; | 446 | break; |
447 | case LK_OUTPUT_ERROR: | 447 | case LK_OUTPUT_ERROR: |
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index cee9c734a048..0fa38a559cdf 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/input.h> | 17 | #include <linux/input.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index e34633c37fdd..68ac97f101b0 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c | |||
@@ -71,7 +71,7 @@ static int __init pcspkr_init(void) | |||
71 | return -ENOMEM; | 71 | return -ENOMEM; |
72 | 72 | ||
73 | pcspkr_dev->name = "PC Speaker"; | 73 | pcspkr_dev->name = "PC Speaker"; |
74 | pcspkr_dev->name = "isa0061/input0"; | 74 | pcspkr_dev->phys = "isa0061/input0"; |
75 | pcspkr_dev->id.bustype = BUS_ISA; | 75 | pcspkr_dev->id.bustype = BUS_ISA; |
76 | pcspkr_dev->id.vendor = 0x001f; | 76 | pcspkr_dev->id.vendor = 0x001f; |
77 | pcspkr_dev->id.product = 0x0001; | 77 | pcspkr_dev->id.product = 0x0001; |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 537154dd7a87..574b18a523af 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
@@ -17,7 +17,7 @@ config MOUSE_PS2 | |||
17 | default y | 17 | default y |
18 | select SERIO | 18 | select SERIO |
19 | select SERIO_LIBPS2 | 19 | select SERIO_LIBPS2 |
20 | select SERIO_I8042 if PC | 20 | select SERIO_I8042 if X86_PC |
21 | select SERIO_GSCPS2 if GSC | 21 | select SERIO_GSCPS2 if GSC |
22 | ---help--- | 22 | ---help--- |
23 | Say Y here if you have a PS/2 mouse connected to your system. This | 23 | Say Y here if you have a PS/2 mouse connected to your system. This |
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index dd0f5bd90241..4da6c86b5d76 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/serio.h> | 37 | #include <linux/serio.h> |
38 | #include <linux/errno.h> | 38 | #include <linux/errno.h> |
39 | #include <linux/err.h> | 39 | #include <linux/err.h> |
40 | #include <linux/platform_device.h> | ||
40 | 41 | ||
41 | #include <asm/io.h> | 42 | #include <asm/io.h> |
42 | 43 | ||
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 4bc40f159996..01e186422021 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/serio.h> | 20 | #include <linux/serio.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/rcupdate.h> | 22 | #include <linux/rcupdate.h> |
23 | #include <linux/platform_device.h> | ||
23 | 24 | ||
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
25 | 26 | ||
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 9880fc145d90..d857f7081adb 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/ioport.h> | 15 | #include <linux/ioport.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 46093c507988..b44d255596c2 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
38 | #include <linux/err.h> | 38 | #include <linux/err.h> |
39 | #include <linux/bitops.h> | 39 | #include <linux/bitops.h> |
40 | #include <linux/platform_device.h> | ||
40 | 41 | ||
41 | #include <asm/io.h> | 42 | #include <asm/io.h> |
42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 106f5eefd89a..52c49258f8a4 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/serio.h> | 35 | #include <linux/serio.h> |
36 | #include <linux/err.h> | 36 | #include <linux/err.h> |
37 | #include <linux/platform_device.h> | ||
37 | 38 | ||
38 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
39 | #include <asm/hardware.h> | 40 | #include <asm/hardware.h> |
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 0ba3e6562bff..15e88eeae8d6 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | 12 | ||
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/input.h> | 16 | #include <linux/input.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index cdb6d0283195..8f02c155fdc0 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c | |||
@@ -723,6 +723,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id, | |||
723 | 723 | ||
724 | sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id); | 724 | sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id); |
725 | 725 | ||
726 | hid->input = input_dev; | ||
726 | hid->id = default_id; | 727 | hid->id = default_id; |
727 | hid->original_handler_id = original_handler_id; | 728 | hid->original_handler_id = original_handler_id; |
728 | hid->current_handler_id = current_handler_id; | 729 | hid->current_handler_id = current_handler_id; |
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 720e7a326308..7daa0ed7331c 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/device.h> | 21 | #include <linux/platform_device.h> |
22 | 22 | ||
23 | #include <asm/dma.h> | 23 | #include <asm/dma.h> |
24 | #include <asm/hardware.h> | 24 | #include <asm/hardware.h> |
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 46de5c940555..9c4dd682ac74 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/miscdevice.h> | 21 | #include <linux/miscdevice.h> |
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | #include <linux/proc_fs.h> | 23 | #include <linux/proc_fs.h> |
24 | #include <linux/device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
26 | #include <linux/hdpu_features.h> | 26 | #include <linux/hdpu_features.h> |
27 | 27 | ||
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index c203b27269ea..165f3405df27 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <linux/hdpu_features.h> | 21 | #include <linux/hdpu_features.h> |
22 | #include <linux/pci.h> | 22 | #include <linux/pci.h> |
23 | 23 | ||
24 | #include <linux/device.h> | 24 | #include <linux/platform_device.h> |
25 | 25 | ||
26 | static int hdpu_nexus_probe(struct device *ddev); | 26 | static int hdpu_nexus_probe(struct device *ddev); |
27 | static int hdpu_nexus_remove(struct device *ddev); | 27 | static int hdpu_nexus_remove(struct device *ddev); |
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index d575e3a018bc..f31e247b2cbe 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
23 | #include <linux/device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 3ace875decc4..942668e93a74 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index 63104c73ca3c..bfe994e59265 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/ioport.h> | 34 | #include <linux/ioport.h> |
35 | #include <linux/device.h> | 35 | #include <linux/device.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | #include <linux/platform_device.h> | |
38 | #include <linux/mtd/mtd.h> | 38 | #include <linux/mtd/mtd.h> |
39 | #include <linux/mtd/map.h> | 39 | #include <linux/mtd/map.h> |
40 | #include <linux/mtd/partitions.h> | 40 | #include <linux/mtd/partitions.h> |
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index e39a98a0171c..d14a0185b8f4 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/ioport.h> | 34 | #include <linux/ioport.h> |
35 | #include <linux/device.h> | 35 | #include <linux/platform_device.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | 37 | ||
38 | #include <linux/mtd/mtd.h> | 38 | #include <linux/mtd/mtd.h> |
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 1e5d6e1d05f3..00b9f67580f1 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
27 | #include <linux/device.h> | 27 | #include <linux/device.h> |
28 | #include <linux/platform_device.h> | ||
28 | 29 | ||
29 | #include <linux/mtd/mtd.h> | 30 | #include <linux/mtd/mtd.h> |
30 | #include <linux/mtd/map.h> | 31 | #include <linux/mtd/map.h> |
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index da316e543237..733a9297a562 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/ioport.h> | 24 | #include <linux/ioport.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/platform_device.h> | ||
26 | 27 | ||
27 | #include <linux/mtd/mtd.h> | 28 | #include <linux/mtd/mtd.h> |
28 | #include <linux/mtd/map.h> | 29 | #include <linux/mtd/map.h> |
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index fa84566245a7..7f370bb794fe 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c | |||
@@ -30,7 +30,7 @@ | |||
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 30 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <linux/device.h> | 33 | #include <linux/platform_device.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/types.h> | 35 | #include <linux/types.h> |
36 | #include <linux/kernel.h> | 36 | #include <linux/kernel.h> |
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index a0577ea00c3c..104576b5be34 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
32 | #include <linux/device.h> | 32 | #include <linux/device.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/platform_device.h> | ||
34 | 35 | ||
35 | #include <linux/mtd/mtd.h> | 36 | #include <linux/mtd/mtd.h> |
36 | #include <linux/mtd/map.h> | 37 | #include <linux/mtd/map.h> |
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c81bec7b14d5..c8d0da19d897 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | 18 | ||
19 | #include <linux/mtd/mtd.h> | 19 | #include <linux/mtd/mtd.h> |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index b58ba236a9eb..2df5e47d1f5c 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -48,7 +48,7 @@ | |||
48 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
49 | #include <linux/string.h> | 49 | #include <linux/string.h> |
50 | #include <linux/ioport.h> | 50 | #include <linux/ioport.h> |
51 | #include <linux/device.h> | 51 | #include <linux/platform_device.h> |
52 | #include <linux/delay.h> | 52 | #include <linux/delay.h> |
53 | #include <linux/err.h> | 53 | #include <linux/err.h> |
54 | #include <linux/slab.h> | 54 | #include <linux/slab.h> |
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 3d50e953faaa..877891a29aaa 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c | |||
@@ -26,11 +26,11 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/crc32.h> | 27 | #include <linux/crc32.h> |
28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
29 | #include <linux/platform_device.h> | ||
29 | 30 | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/hardware.h> | 31 | #include <asm/hardware.h> |
33 | #include <asm/io.h> | 32 | #include <asm/io.h> |
33 | #include <asm/system.h> | ||
34 | 34 | ||
35 | #define TX_BUFFERS 15 | 35 | #define TX_BUFFERS 15 |
36 | #define RX_BUFFERS 25 | 36 | #define RX_BUFFERS 25 |
@@ -280,10 +280,13 @@ static void am79c961_timer(unsigned long data) | |||
280 | lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; | 280 | lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; |
281 | carrier = netif_carrier_ok(dev); | 281 | carrier = netif_carrier_ok(dev); |
282 | 282 | ||
283 | if (lnkstat && !carrier) | 283 | if (lnkstat && !carrier) { |
284 | netif_carrier_on(dev); | 284 | netif_carrier_on(dev); |
285 | else if (!lnkstat && carrier) | 285 | printk("%s: link up\n", dev->name); |
286 | } else if (!lnkstat && carrier) { | ||
286 | netif_carrier_off(dev); | 287 | netif_carrier_off(dev); |
288 | printk("%s: link down\n", dev->name); | ||
289 | } | ||
287 | 290 | ||
288 | mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500)); | 291 | mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500)); |
289 | } | 292 | } |
@@ -665,17 +668,25 @@ static void __init am79c961_banner(void) | |||
665 | printk(KERN_INFO "%s", version); | 668 | printk(KERN_INFO "%s", version); |
666 | } | 669 | } |
667 | 670 | ||
668 | static int __init am79c961_init(void) | 671 | static int __init am79c961_probe(struct device *_dev) |
669 | { | 672 | { |
673 | struct platform_device *pdev = to_platform_device(_dev); | ||
674 | struct resource *res; | ||
670 | struct net_device *dev; | 675 | struct net_device *dev; |
671 | struct dev_priv *priv; | 676 | struct dev_priv *priv; |
672 | int i, ret; | 677 | int i, ret; |
673 | 678 | ||
679 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
680 | if (!res) | ||
681 | return -ENODEV; | ||
682 | |||
674 | dev = alloc_etherdev(sizeof(struct dev_priv)); | 683 | dev = alloc_etherdev(sizeof(struct dev_priv)); |
675 | ret = -ENOMEM; | 684 | ret = -ENOMEM; |
676 | if (!dev) | 685 | if (!dev) |
677 | goto out; | 686 | goto out; |
678 | 687 | ||
688 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
689 | |||
679 | priv = netdev_priv(dev); | 690 | priv = netdev_priv(dev); |
680 | 691 | ||
681 | /* | 692 | /* |
@@ -683,8 +694,8 @@ static int __init am79c961_init(void) | |||
683 | * The PNP initialisation should have been | 694 | * The PNP initialisation should have been |
684 | * done by the ether bootp loader. | 695 | * done by the ether bootp loader. |
685 | */ | 696 | */ |
686 | dev->base_addr = 0x220; | 697 | dev->base_addr = res->start; |
687 | dev->irq = IRQ_EBSA110_ETHERNET; | 698 | dev->irq = platform_get_irq(pdev, 0); |
688 | 699 | ||
689 | ret = -ENODEV; | 700 | ret = -ENODEV; |
690 | if (!request_region(dev->base_addr, 0x18, dev->name)) | 701 | if (!request_region(dev->base_addr, 0x18, dev->name)) |
@@ -705,11 +716,11 @@ static int __init am79c961_init(void) | |||
705 | inb(dev->base_addr + 4) != 0x2b) | 716 | inb(dev->base_addr + 4) != 0x2b) |
706 | goto release; | 717 | goto release; |
707 | 718 | ||
708 | am79c961_banner(); | ||
709 | |||
710 | for (i = 0; i < 6; i++) | 719 | for (i = 0; i < 6; i++) |
711 | dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff; | 720 | dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff; |
712 | 721 | ||
722 | am79c961_banner(); | ||
723 | |||
713 | spin_lock_init(&priv->chip_lock); | 724 | spin_lock_init(&priv->chip_lock); |
714 | init_timer(&priv->timer); | 725 | init_timer(&priv->timer); |
715 | priv->timer.data = (unsigned long)dev; | 726 | priv->timer.data = (unsigned long)dev; |
@@ -732,6 +743,7 @@ static int __init am79c961_init(void) | |||
732 | if (ret == 0) { | 743 | if (ret == 0) { |
733 | printk(KERN_INFO "%s: ether address ", dev->name); | 744 | printk(KERN_INFO "%s: ether address ", dev->name); |
734 | 745 | ||
746 | /* Retrive and print the ethernet address. */ | ||
735 | for (i = 0; i < 6; i++) | 747 | for (i = 0; i < 6; i++) |
736 | printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); | 748 | printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); |
737 | 749 | ||
@@ -746,4 +758,15 @@ out: | |||
746 | return ret; | 758 | return ret; |
747 | } | 759 | } |
748 | 760 | ||
761 | static struct device_driver am79c961_driver = { | ||
762 | .name = "am79c961", | ||
763 | .bus = &platform_bus_type, | ||
764 | .probe = am79c961_probe, | ||
765 | }; | ||
766 | |||
767 | static int __init am79c961_init(void) | ||
768 | { | ||
769 | return driver_register(&am79c961_driver); | ||
770 | } | ||
771 | |||
749 | __initcall(am79c961_init); | 772 | __initcall(am79c961_init); |
diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h index 1e9b05050cbe..6a49ac7f6d46 100644 --- a/drivers/net/arm/am79c961a.h +++ b/drivers/net/arm/am79c961a.h | |||
@@ -143,6 +143,4 @@ struct dev_priv { | |||
143 | struct timer_list timer; | 143 | struct timer_list timer; |
144 | }; | 144 | }; |
145 | 145 | ||
146 | extern int am79c961_probe (struct net_device *dev); | ||
147 | |||
148 | #endif | 146 | #endif |
diff --git a/drivers/net/depca.c b/drivers/net/depca.c index c4aa5fe2840e..4d26e5e7d18b 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c | |||
@@ -254,7 +254,7 @@ | |||
254 | #include <linux/unistd.h> | 254 | #include <linux/unistd.h> |
255 | #include <linux/ctype.h> | 255 | #include <linux/ctype.h> |
256 | #include <linux/moduleparam.h> | 256 | #include <linux/moduleparam.h> |
257 | #include <linux/device.h> | 257 | #include <linux/platform_device.h> |
258 | #include <linux/bitops.h> | 258 | #include <linux/bitops.h> |
259 | 259 | ||
260 | #include <asm/uaccess.h> | 260 | #include <asm/uaccess.h> |
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index abce1f730d00..c0af6fb1fbba 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c | |||
@@ -66,6 +66,7 @@ | |||
66 | #include <linux/mii.h> | 66 | #include <linux/mii.h> |
67 | #include <linux/dm9000.h> | 67 | #include <linux/dm9000.h> |
68 | #include <linux/delay.h> | 68 | #include <linux/delay.h> |
69 | #include <linux/platform_device.h> | ||
69 | 70 | ||
70 | #include <asm/delay.h> | 71 | #include <asm/delay.h> |
71 | #include <asm/irq.h> | 72 | #include <asm/irq.h> |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index ae5a2ed3b264..962580f2c4ab 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -81,7 +81,7 @@ | |||
81 | #include <linux/if_vlan.h> | 81 | #include <linux/if_vlan.h> |
82 | #include <linux/spinlock.h> | 82 | #include <linux/spinlock.h> |
83 | #include <linux/mm.h> | 83 | #include <linux/mm.h> |
84 | #include <linux/device.h> | 84 | #include <linux/platform_device.h> |
85 | #include <linux/ip.h> | 85 | #include <linux/ip.h> |
86 | #include <linux/tcp.h> | 86 | #include <linux/tcp.h> |
87 | #include <linux/udp.h> | 87 | #include <linux/udp.h> |
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 1eca1dbca7f1..5a74d3d3dbe1 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/version.h> | 35 | #include <linux/version.h> |
36 | #include <linux/platform_device.h> | ||
36 | #include <asm/ocp.h> | 37 | #include <asm/ocp.h> |
37 | #include <linux/crc32.h> | 38 | #include <linux/crc32.h> |
38 | #include <linux/mii.h> | 39 | #include <linux/mii.h> |
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index b886b07412a6..e1aa9910503b 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
25 | #include <linux/platform_device.h> | ||
25 | #include <linux/pm.h> | 26 | #include <linux/pm.h> |
26 | 27 | ||
27 | #include <net/irda/irda.h> | 28 | #include <net/irda/irda.h> |
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 06883309916d..76e0b9fb5e96 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/rtnetlink.h> | 29 | #include <linux/rtnetlink.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/dma-mapping.h> | 33 | #include <linux/dma-mapping.h> |
34 | 34 | ||
35 | #include <net/irda/irda.h> | 35 | #include <net/irda/irda.h> |
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 140b7cdb1f7e..a1d207f2fa68 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/rtnetlink.h> | 53 | #include <linux/rtnetlink.h> |
54 | #include <linux/serial_reg.h> | 54 | #include <linux/serial_reg.h> |
55 | #include <linux/dma-mapping.h> | 55 | #include <linux/dma-mapping.h> |
56 | #include <linux/platform_device.h> | ||
56 | 57 | ||
57 | #include <asm/io.h> | 58 | #include <asm/io.h> |
58 | #include <asm/dma.h> | 59 | #include <asm/dma.h> |
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 8423cb6875f0..a74a5cfaf5bc 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/netdevice.h> | 33 | #include <linux/netdevice.h> |
34 | #include <linux/etherdevice.h> | 34 | #include <linux/etherdevice.h> |
35 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
36 | #include <linux/device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/dma-mapping.h> | 37 | #include <linux/dma-mapping.h> |
38 | 38 | ||
39 | #include <asm/bootinfo.h> | 39 | #include <asm/bootinfo.h> |
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 405e18365ede..e9c999d7eb39 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c | |||
@@ -47,7 +47,7 @@ | |||
47 | #include <linux/netdevice.h> | 47 | #include <linux/netdevice.h> |
48 | #include <linux/etherdevice.h> | 48 | #include <linux/etherdevice.h> |
49 | #include <linux/skbuff.h> | 49 | #include <linux/skbuff.h> |
50 | #include <linux/device.h> | 50 | #include <linux/platform_device.h> |
51 | #include <linux/dma-mapping.h> | 51 | #include <linux/dma-mapping.h> |
52 | 52 | ||
53 | #include <asm/bootinfo.h> | 53 | #include <asm/bootinfo.h> |
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index f79f7ee72ab8..bbffb585b3b3 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/etherdevice.h> | 14 | #include <linux/etherdevice.h> |
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/platform_device.h> | ||
16 | #include <asm/io.h> | 17 | #include <asm/io.h> |
17 | #include <asm/mips-boards/simint.h> | 18 | #include <asm/mips-boards/simint.h> |
18 | 19 | ||
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 8fbba21d975b..71f2c6705bc3 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include <linux/bitops.h> | 39 | #include <linux/bitops.h> |
40 | #include <linux/delay.h> | 40 | #include <linux/delay.h> |
41 | #include <linux/ethtool.h> | 41 | #include <linux/ethtool.h> |
42 | #include <linux/platform_device.h> | ||
43 | |||
42 | #include <asm/io.h> | 44 | #include <asm/io.h> |
43 | #include <asm/types.h> | 45 | #include <asm/types.h> |
44 | #include <asm/pgtable.h> | 46 | #include <asm/pgtable.h> |
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index c573bb351d4c..74d5f1a6fdea 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c | |||
@@ -77,7 +77,7 @@ static const char version[] = | |||
77 | #include <linux/errno.h> | 77 | #include <linux/errno.h> |
78 | #include <linux/ioport.h> | 78 | #include <linux/ioport.h> |
79 | #include <linux/crc32.h> | 79 | #include <linux/crc32.h> |
80 | #include <linux/device.h> | 80 | #include <linux/platform_device.h> |
81 | #include <linux/spinlock.h> | 81 | #include <linux/spinlock.h> |
82 | #include <linux/ethtool.h> | 82 | #include <linux/ethtool.h> |
83 | #include <linux/mii.h> | 83 | #include <linux/mii.h> |
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index eb1423ede75c..d04c918ebef8 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c | |||
@@ -29,6 +29,7 @@ static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/netdevice.h> | 30 | #include <linux/netdevice.h> |
31 | #include <linux/trdevice.h> | 31 | #include <linux/trdevice.h> |
32 | #include <linux/platform_device.h> | ||
32 | 33 | ||
33 | #include <asm/system.h> | 34 | #include <asm/system.h> |
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 3c7c66204f74..72cf708396be 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c | |||
@@ -36,6 +36,7 @@ static const char version[] = "skisa.c: v1.03 09/12/2002 by Jochen Friedrich\n"; | |||
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/netdevice.h> | 37 | #include <linux/netdevice.h> |
38 | #include <linux/trdevice.h> | 38 | #include <linux/trdevice.h> |
39 | #include <linux/platform_device.h> | ||
39 | 40 | ||
40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
41 | #include <asm/io.h> | 42 | #include <asm/io.h> |
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index ba48cef3a9dc..87302c548c24 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include <linux/notifier.h> | 42 | #include <linux/notifier.h> |
43 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
44 | #include <linux/spinlock.h> | 44 | #include <linux/spinlock.h> |
45 | #include <linux/device.h> | 45 | #include <linux/platform_device.h> |
46 | 46 | ||
47 | #include <asm/io.h> | 47 | #include <asm/io.h> |
48 | #include <asm/irq.h> | 48 | #include <asm/irq.h> |
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index b57a0b98b4d6..561706ba4499 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include <asm/errno.h> | 37 | #include <asm/errno.h> |
38 | #include <linux/irq.h> | 38 | #include <linux/irq.h> |
39 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
40 | #include <linux/device.h> | 40 | #include <linux/platform_device.h> |
41 | 41 | ||
42 | #include <asm/io.h> | 42 | #include <asm/io.h> |
43 | #include <asm/hd64465/hd64465.h> | 43 | #include <asm/hd64465/hd64465.h> |
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 4a41f67d185d..7ce455d01cc9 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c | |||
@@ -47,7 +47,7 @@ | |||
47 | #include <linux/delay.h> | 47 | #include <linux/delay.h> |
48 | #include <linux/workqueue.h> | 48 | #include <linux/workqueue.h> |
49 | #include <linux/interrupt.h> | 49 | #include <linux/interrupt.h> |
50 | #include <linux/device.h> | 50 | #include <linux/platform_device.h> |
51 | #include <linux/bitops.h> | 51 | #include <linux/bitops.h> |
52 | #include <asm/irq.h> | 52 | #include <asm/irq.h> |
53 | #include <asm/io.h> | 53 | #include <asm/io.h> |
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index c6ed70ea4812..2c22b4b3619d 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
28 | #include <asm/irq.h> | 28 | #include <asm/irq.h> |
29 | #include <asm/io.h> | 29 | #include <asm/io.h> |
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 3397ff28de6a..356a6fb416a1 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <asm/irq.h> | 27 | #include <asm/irq.h> |
28 | #include <asm/io.h> | 28 | #include <asm/io.h> |
29 | #include <asm/bitops.h> | 29 | #include <asm/bitops.h> |
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 2558c3cc91ec..47b5ade95bde 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index c2a12d53f6c7..7fa18fb814bc 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/ioport.h> | 23 | #include <linux/ioport.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <linux/platform_device.h> | ||
26 | 27 | ||
27 | #include <asm/hardware.h> | 28 | #include <asm/hardware.h> |
28 | #include <asm/io.h> | 29 | #include <asm/io.h> |
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index bbe69b07ce50..5209d8c7764f 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/device.h> | 20 | #include <linux/platform_device.h> |
21 | 21 | ||
22 | #include <pcmcia/ss.h> | 22 | #include <pcmcia/ss.h> |
23 | 23 | ||
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index bd924336a49f..fe5ea36e7de3 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/device.h> | 19 | #include <linux/platform_device.h> |
20 | 20 | ||
21 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
22 | #include <asm/hardware.h> | 22 | #include <asm/hardware.h> |
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index acf60ffc8a12..6d441ec75c6a 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/config.h> | 35 | #include <linux/config.h> |
36 | #include <linux/platform_device.h> | ||
36 | 37 | ||
37 | #include <pcmcia/cs_types.h> | 38 | #include <pcmcia/cs_types.h> |
38 | #include <pcmcia/cs.h> | 39 | #include <pcmcia/cs.h> |
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index f158b67f6610..e31263864377 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <linux/ioport.h> | 44 | #include <linux/ioport.h> |
45 | #include <linux/delay.h> | 45 | #include <linux/delay.h> |
46 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
47 | #include <linux/device.h> | 47 | #include <linux/platform_device.h> |
48 | #include <linux/bitops.h> | 48 | #include <linux/bitops.h> |
49 | 49 | ||
50 | #include <asm/io.h> | 50 | #include <asm/io.h> |
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 3d2dca675e02..38a028c725d4 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/platform_device.h> | ||
27 | 28 | ||
28 | #include <asm/io.h> | 29 | #include <asm/io.h> |
29 | 30 | ||
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index f24d84538fd5..71dd1ebbe58f 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/completion.h> | 31 | #include <linux/completion.h> |
32 | #include <linux/transport_class.h> | 32 | #include <linux/transport_class.h> |
33 | #include <linux/platform_device.h> | ||
33 | 34 | ||
34 | #include <scsi/scsi_device.h> | 35 | #include <scsi/scsi_device.h> |
35 | #include <scsi/scsi_host.h> | 36 | #include <scsi/scsi_host.h> |
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 00d6a6657ebc..a440ea38efaa 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c | |||
@@ -180,12 +180,22 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne | |||
180 | return; | 180 | return; |
181 | } | 181 | } |
182 | count = min(pc->sg->length - pc->b_count, bcount); | 182 | count = min(pc->sg->length - pc->b_count, bcount); |
183 | buf = kmap_atomic(pc->sg->page, KM_IRQ0); | 183 | if (PageHighMem(pc->sg->page)) { |
184 | drive->hwif->atapi_input_bytes(drive, | 184 | unsigned long flags; |
185 | buf + pc->b_count + pc->sg->offset, count); | 185 | |
186 | kunmap_atomic(buf, KM_IRQ0); | 186 | local_irq_save(flags); |
187 | bcount -= count; | 187 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + |
188 | pc->b_count += count; | 188 | pc->sg->offset; |
189 | drive->hwif->atapi_input_bytes(drive, | ||
190 | buf + pc->b_count, count); | ||
191 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | ||
192 | local_irq_restore(flags); | ||
193 | } else { | ||
194 | buf = page_address(pc->sg->page) + pc->sg->offset; | ||
195 | drive->hwif->atapi_input_bytes(drive, | ||
196 | buf + pc->b_count, count); | ||
197 | } | ||
198 | bcount -= count; pc->b_count += count; | ||
189 | if (pc->b_count == pc->sg->length) { | 199 | if (pc->b_count == pc->sg->length) { |
190 | pc->sg++; | 200 | pc->sg++; |
191 | pc->b_count = 0; | 201 | pc->b_count = 0; |
@@ -205,12 +215,22 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign | |||
205 | return; | 215 | return; |
206 | } | 216 | } |
207 | count = min(pc->sg->length - pc->b_count, bcount); | 217 | count = min(pc->sg->length - pc->b_count, bcount); |
208 | buf = kmap_atomic(pc->sg->page, KM_IRQ0); | 218 | if (PageHighMem(pc->sg->page)) { |
209 | drive->hwif->atapi_output_bytes(drive, | 219 | unsigned long flags; |
210 | buf + pc->b_count + pc->sg->offset, count); | 220 | |
211 | kunmap_atomic(buf, KM_IRQ0); | 221 | local_irq_save(flags); |
212 | bcount -= count; | 222 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + |
213 | pc->b_count += count; | 223 | pc->sg->offset; |
224 | drive->hwif->atapi_output_bytes(drive, | ||
225 | buf + pc->b_count, count); | ||
226 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | ||
227 | local_irq_restore(flags); | ||
228 | } else { | ||
229 | buf = page_address(pc->sg->page) + pc->sg->offset; | ||
230 | drive->hwif->atapi_output_bytes(drive, | ||
231 | buf + pc->b_count, count); | ||
232 | } | ||
233 | bcount -= count; pc->b_count += count; | ||
214 | if (pc->b_count == pc->sg->length) { | 234 | if (pc->b_count == pc->sg->length) { |
215 | pc->sg++; | 235 | pc->sg++; |
216 | pc->b_count = 0; | 236 | pc->b_count = 0; |
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 8be7dc0b47b8..ff18fa7044c5 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -295,28 +295,6 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) | |||
295 | } | 295 | } |
296 | 296 | ||
297 | /** | 297 | /** |
298 | * ata_exec - issue ATA command to host controller | ||
299 | * @ap: port to which command is being issued | ||
300 | * @tf: ATA taskfile register set | ||
301 | * | ||
302 | * Issues PIO/MMIO write to ATA command register, with proper | ||
303 | * synchronization with interrupt handler / other threads. | ||
304 | * | ||
305 | * LOCKING: | ||
306 | * Obtains host_set lock. | ||
307 | */ | ||
308 | |||
309 | static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf) | ||
310 | { | ||
311 | unsigned long flags; | ||
312 | |||
313 | DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); | ||
314 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
315 | ap->ops->exec_command(ap, tf); | ||
316 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * ata_tf_to_host - issue ATA taskfile to host controller | 298 | * ata_tf_to_host - issue ATA taskfile to host controller |
321 | * @ap: port to which command is being issued | 299 | * @ap: port to which command is being issued |
322 | * @tf: ATA taskfile register set | 300 | * @tf: ATA taskfile register set |
@@ -326,30 +304,11 @@ static inline void ata_exec(struct ata_port *ap, const struct ata_taskfile *tf) | |||
326 | * other threads. | 304 | * other threads. |
327 | * | 305 | * |
328 | * LOCKING: | 306 | * LOCKING: |
329 | * Obtains host_set lock. | ||
330 | */ | ||
331 | |||
332 | static void ata_tf_to_host(struct ata_port *ap, const struct ata_taskfile *tf) | ||
333 | { | ||
334 | ap->ops->tf_load(ap, tf); | ||
335 | |||
336 | ata_exec(ap, tf); | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * ata_tf_to_host_nolock - issue ATA taskfile to host controller | ||
341 | * @ap: port to which command is being issued | ||
342 | * @tf: ATA taskfile register set | ||
343 | * | ||
344 | * Issues ATA taskfile register set to ATA host controller, | ||
345 | * with proper synchronization with interrupt handler and | ||
346 | * other threads. | ||
347 | * | ||
348 | * LOCKING: | ||
349 | * spin_lock_irqsave(host_set lock) | 307 | * spin_lock_irqsave(host_set lock) |
350 | */ | 308 | */ |
351 | 309 | ||
352 | void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf) | 310 | static inline void ata_tf_to_host(struct ata_port *ap, |
311 | const struct ata_taskfile *tf) | ||
353 | { | 312 | { |
354 | ap->ops->tf_load(ap, tf); | 313 | ap->ops->tf_load(ap, tf); |
355 | ap->ops->exec_command(ap, tf); | 314 | ap->ops->exec_command(ap, tf); |
@@ -1912,12 +1871,14 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) | |||
1912 | * | 1871 | * |
1913 | * LOCKING: | 1872 | * LOCKING: |
1914 | * PCI/etc. bus probe sem. | 1873 | * PCI/etc. bus probe sem. |
1874 | * Obtains host_set lock. | ||
1915 | * | 1875 | * |
1916 | */ | 1876 | */ |
1917 | 1877 | ||
1918 | static unsigned int ata_bus_edd(struct ata_port *ap) | 1878 | static unsigned int ata_bus_edd(struct ata_port *ap) |
1919 | { | 1879 | { |
1920 | struct ata_taskfile tf; | 1880 | struct ata_taskfile tf; |
1881 | unsigned long flags; | ||
1921 | 1882 | ||
1922 | /* set up execute-device-diag (bus reset) taskfile */ | 1883 | /* set up execute-device-diag (bus reset) taskfile */ |
1923 | /* also, take interrupts to a known state (disabled) */ | 1884 | /* also, take interrupts to a known state (disabled) */ |
@@ -1928,7 +1889,9 @@ static unsigned int ata_bus_edd(struct ata_port *ap) | |||
1928 | tf.protocol = ATA_PROT_NODATA; | 1889 | tf.protocol = ATA_PROT_NODATA; |
1929 | 1890 | ||
1930 | /* do bus reset */ | 1891 | /* do bus reset */ |
1892 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
1931 | ata_tf_to_host(ap, &tf); | 1893 | ata_tf_to_host(ap, &tf); |
1894 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
1932 | 1895 | ||
1933 | /* spec says at least 2ms. but who knows with those | 1896 | /* spec says at least 2ms. but who knows with those |
1934 | * crazy ATAPI devices... | 1897 | * crazy ATAPI devices... |
@@ -3555,7 +3518,7 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) | |||
3555 | 3518 | ||
3556 | switch (qc->tf.protocol) { | 3519 | switch (qc->tf.protocol) { |
3557 | case ATA_PROT_NODATA: | 3520 | case ATA_PROT_NODATA: |
3558 | ata_tf_to_host_nolock(ap, &qc->tf); | 3521 | ata_tf_to_host(ap, &qc->tf); |
3559 | break; | 3522 | break; |
3560 | 3523 | ||
3561 | case ATA_PROT_DMA: | 3524 | case ATA_PROT_DMA: |
@@ -3566,20 +3529,20 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) | |||
3566 | 3529 | ||
3567 | case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ | 3530 | case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ |
3568 | ata_qc_set_polling(qc); | 3531 | ata_qc_set_polling(qc); |
3569 | ata_tf_to_host_nolock(ap, &qc->tf); | 3532 | ata_tf_to_host(ap, &qc->tf); |
3570 | ap->hsm_task_state = HSM_ST; | 3533 | ap->hsm_task_state = HSM_ST; |
3571 | queue_work(ata_wq, &ap->pio_task); | 3534 | queue_work(ata_wq, &ap->pio_task); |
3572 | break; | 3535 | break; |
3573 | 3536 | ||
3574 | case ATA_PROT_ATAPI: | 3537 | case ATA_PROT_ATAPI: |
3575 | ata_qc_set_polling(qc); | 3538 | ata_qc_set_polling(qc); |
3576 | ata_tf_to_host_nolock(ap, &qc->tf); | 3539 | ata_tf_to_host(ap, &qc->tf); |
3577 | queue_work(ata_wq, &ap->packet_task); | 3540 | queue_work(ata_wq, &ap->packet_task); |
3578 | break; | 3541 | break; |
3579 | 3542 | ||
3580 | case ATA_PROT_ATAPI_NODATA: | 3543 | case ATA_PROT_ATAPI_NODATA: |
3581 | ap->flags |= ATA_FLAG_NOINTR; | 3544 | ap->flags |= ATA_FLAG_NOINTR; |
3582 | ata_tf_to_host_nolock(ap, &qc->tf); | 3545 | ata_tf_to_host(ap, &qc->tf); |
3583 | queue_work(ata_wq, &ap->packet_task); | 3546 | queue_work(ata_wq, &ap->packet_task); |
3584 | break; | 3547 | break; |
3585 | 3548 | ||
@@ -4126,8 +4089,6 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, | |||
4126 | host->unique_id = ata_unique_id++; | 4089 | host->unique_id = ata_unique_id++; |
4127 | host->max_cmd_len = 12; | 4090 | host->max_cmd_len = 12; |
4128 | 4091 | ||
4129 | scsi_assign_lock(host, &host_set->lock); | ||
4130 | |||
4131 | ap->flags = ATA_FLAG_PORT_DISABLED; | 4092 | ap->flags = ATA_FLAG_PORT_DISABLED; |
4132 | ap->id = host->unique_id; | 4093 | ap->id = host->unique_id; |
4133 | ap->host = host; | 4094 | ap->host = host; |
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 1e3792f86fcf..248baae96486 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <scsi/scsi.h> | 39 | #include <scsi/scsi.h> |
40 | #include "scsi.h" | 40 | #include "scsi.h" |
41 | #include <scsi/scsi_host.h> | 41 | #include <scsi/scsi_host.h> |
42 | #include <scsi/scsi_device.h> | ||
42 | #include <linux/libata.h> | 43 | #include <linux/libata.h> |
43 | #include <linux/hdreg.h> | 44 | #include <linux/hdreg.h> |
44 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
@@ -2405,8 +2406,12 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
2405 | struct ata_port *ap; | 2406 | struct ata_port *ap; |
2406 | struct ata_device *dev; | 2407 | struct ata_device *dev; |
2407 | struct scsi_device *scsidev = cmd->device; | 2408 | struct scsi_device *scsidev = cmd->device; |
2409 | struct Scsi_Host *shost = scsidev->host; | ||
2408 | 2410 | ||
2409 | ap = (struct ata_port *) &scsidev->host->hostdata[0]; | 2411 | ap = (struct ata_port *) &shost->hostdata[0]; |
2412 | |||
2413 | spin_unlock(shost->host_lock); | ||
2414 | spin_lock(&ap->host_set->lock); | ||
2410 | 2415 | ||
2411 | ata_scsi_dump_cdb(ap, cmd); | 2416 | ata_scsi_dump_cdb(ap, cmd); |
2412 | 2417 | ||
@@ -2429,6 +2434,8 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
2429 | ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); | 2434 | ata_scsi_translate(ap, dev, cmd, done, atapi_xlat); |
2430 | 2435 | ||
2431 | out_unlock: | 2436 | out_unlock: |
2437 | spin_unlock(&ap->host_set->lock); | ||
2438 | spin_lock(shost->host_lock); | ||
2432 | return 0; | 2439 | return 0; |
2433 | } | 2440 | } |
2434 | 2441 | ||
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 10ecd9e15e4f..fad051ca4672 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h | |||
@@ -48,7 +48,6 @@ extern int ata_qc_issue(struct ata_queued_cmd *qc); | |||
48 | extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); | 48 | extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); |
49 | extern void ata_dev_select(struct ata_port *ap, unsigned int device, | 49 | extern void ata_dev_select(struct ata_port *ap, unsigned int device, |
50 | unsigned int wait, unsigned int can_sleep); | 50 | unsigned int wait, unsigned int can_sleep); |
51 | extern void ata_tf_to_host_nolock(struct ata_port *ap, const struct ata_taskfile *tf); | ||
52 | extern void swap_buf_le16(u16 *buf, unsigned int buf_words); | 51 | extern void swap_buf_le16(u16 *buf, unsigned int buf_words); |
53 | extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); | 52 | extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); |
54 | extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); | 53 | extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); |
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index afb7ddf200e0..f47d2c454e33 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/sysrq.h> | 33 | #include <linux/sysrq.h> |
34 | #include <linux/mca.h> | 34 | #include <linux/mca.h> |
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/tty.h> | 37 | #include <linux/tty.h> |
38 | #include <linux/tty_flip.h> | 38 | #include <linux/tty_flip.h> |
39 | #include <linux/serial_reg.h> | 39 | #include <linux/serial_reg.h> |
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 5b3933b0c997..4a54ff584700 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/console.h> | 37 | #include <linux/console.h> |
38 | #include <linux/sysrq.h> | 38 | #include <linux/sysrq.h> |
39 | #include <linux/device.h> | 39 | #include <linux/platform_device.h> |
40 | #include <linux/tty.h> | 40 | #include <linux/tty.h> |
41 | #include <linux/tty_flip.h> | 41 | #include <linux/tty_flip.h> |
42 | #include <linux/serial_core.h> | 42 | #include <linux/serial_core.h> |
@@ -995,6 +995,7 @@ static int __init imx_serial_init(void) | |||
995 | static void __exit imx_serial_exit(void) | 995 | static void __exit imx_serial_exit(void) |
996 | { | 996 | { |
997 | uart_unregister_driver(&imx_reg); | 997 | uart_unregister_driver(&imx_reg); |
998 | driver_unregister(&serial_imx_driver); | ||
998 | } | 999 | } |
999 | 1000 | ||
1000 | module_init(imx_serial_init); | 1001 | module_init(imx_serial_init); |
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 8a79968f8ce1..0dd08a09e7e6 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c | |||
@@ -45,7 +45,7 @@ | |||
45 | */ | 45 | */ |
46 | 46 | ||
47 | #include <linux/config.h> | 47 | #include <linux/config.h> |
48 | #include <linux/device.h> | 48 | #include <linux/platform_device.h> |
49 | #include <linux/module.h> | 49 | #include <linux/module.h> |
50 | #include <linux/tty.h> | 50 | #include <linux/tty.h> |
51 | #include <linux/serial.h> | 51 | #include <linux/serial.h> |
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index aec83f577ce6..ba8838b234da 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c | |||
@@ -52,6 +52,8 @@ | |||
52 | * 4) AFAICT, hardware flow control isn't supported by the controller --MAG. | 52 | * 4) AFAICT, hardware flow control isn't supported by the controller --MAG. |
53 | */ | 53 | */ |
54 | 54 | ||
55 | #include <linux/platform_device.h> | ||
56 | |||
55 | #include "mpsc.h" | 57 | #include "mpsc.h" |
56 | 58 | ||
57 | /* | 59 | /* |
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 8cc4cedadd99..16b2f9417af9 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <linux/circ_buf.h> | 39 | #include <linux/circ_buf.h> |
40 | #include <linux/delay.h> | 40 | #include <linux/delay.h> |
41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
42 | #include <linux/device.h> | 42 | #include <linux/platform_device.h> |
43 | #include <linux/tty.h> | 43 | #include <linux/tty.h> |
44 | #include <linux/tty_flip.h> | 44 | #include <linux/tty_flip.h> |
45 | #include <linux/serial_core.h> | 45 | #include <linux/serial_core.h> |
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 06a17dff1a73..036792328d49 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c | |||
@@ -63,7 +63,7 @@ | |||
63 | 63 | ||
64 | #include <linux/module.h> | 64 | #include <linux/module.h> |
65 | #include <linux/ioport.h> | 65 | #include <linux/ioport.h> |
66 | #include <linux/device.h> | 66 | #include <linux/platform_device.h> |
67 | #include <linux/init.h> | 67 | #include <linux/init.h> |
68 | #include <linux/sysrq.h> | 68 | #include <linux/sysrq.h> |
69 | #include <linux/console.h> | 69 | #include <linux/console.h> |
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index c4a789e6af44..ed618cc7ae96 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/console.h> | 36 | #include <linux/console.h> |
37 | #include <linux/sysrq.h> | 37 | #include <linux/sysrq.h> |
38 | #include <linux/device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/tty.h> | 39 | #include <linux/tty.h> |
40 | #include <linux/tty_flip.h> | 40 | #include <linux/tty_flip.h> |
41 | #include <linux/serial_core.h> | 41 | #include <linux/serial_core.h> |
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 2b623ab0e36e..01696b3e3f61 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #include <linux/console.h> | 28 | #include <linux/console.h> |
29 | #include <linux/device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/err.h> | 30 | #include <linux/err.h> |
31 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 02106bebd5c1..975ace3f5b1e 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c | |||
@@ -50,7 +50,7 @@ | |||
50 | #include <linux/list.h> | 50 | #include <linux/list.h> |
51 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
52 | #include <linux/version.h> | 52 | #include <linux/version.h> |
53 | 53 | #include <linux/platform_device.h> | |
54 | #include <linux/usb.h> | 54 | #include <linux/usb.h> |
55 | #include <linux/usb_gadget.h> | 55 | #include <linux/usb_gadget.h> |
56 | 56 | ||
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 9b3673904daf..bc6269f10cbb 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c | |||
@@ -21,6 +21,8 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/platform_device.h> | ||
25 | |||
24 | #include "lh7a40x_udc.h" | 26 | #include "lh7a40x_udc.h" |
25 | 27 | ||
26 | //#define DEBUG printk | 28 | //#define DEBUG printk |
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 41c96b0afbb3..387692a3611e 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
39 | #include <linux/mm.h> | 39 | #include <linux/mm.h> |
40 | #include <linux/moduleparam.h> | 40 | #include <linux/moduleparam.h> |
41 | #include <linux/device.h> | 41 | #include <linux/platform_device.h> |
42 | #include <linux/usb_ch9.h> | 42 | #include <linux/usb_ch9.h> |
43 | #include <linux/usb_gadget.h> | 43 | #include <linux/usb_gadget.h> |
44 | #include <linux/usb_otg.h> | 44 | #include <linux/usb_otg.h> |
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index f83a9262f953..ee9cd7869d92 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
44 | #include <linux/proc_fs.h> | 44 | #include <linux/proc_fs.h> |
45 | #include <linux/mm.h> | 45 | #include <linux/mm.h> |
46 | #include <linux/device.h> | 46 | #include <linux/platform_device.h> |
47 | #include <linux/dma-mapping.h> | 47 | #include <linux/dma-mapping.h> |
48 | 48 | ||
49 | #include <asm/byteorder.h> | 49 | #include <asm/byteorder.h> |
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index ddb8fc591466..f9c3f5b8dd1c 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <linux/interrupt.h> | 70 | #include <linux/interrupt.h> |
71 | #include <linux/usb.h> | 71 | #include <linux/usb.h> |
72 | #include <linux/usb_isp116x.h> | 72 | #include <linux/usb_isp116x.h> |
73 | #include <linux/platform_device.h> | ||
73 | 74 | ||
74 | #include <asm/io.h> | 75 | #include <asm/io.h> |
75 | #include <asm/irq.h> | 76 | #include <asm/irq.h> |
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index a277e258eb6c..f0c78cf14b6c 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c | |||
@@ -18,6 +18,8 @@ | |||
18 | * This file is licenced under the GPL. | 18 | * This file is licenced under the GPL. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
21 | #include <asm/mach-au1x00/au1000.h> | 23 | #include <asm/mach-au1x00/au1000.h> |
22 | 24 | ||
23 | #define USBH_ENABLE_BE (1<<0) | 25 | #define USBH_ENABLE_BE (1<<0) |
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 238fa4ade615..336c766c6e29 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c | |||
@@ -16,6 +16,8 @@ | |||
16 | * This file is licenced under the GPL. | 16 | * This file is licenced under the GPL. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/platform_device.h> | ||
20 | |||
19 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
20 | 22 | ||
21 | 23 | ||
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 49815ec4b842..e46cc540cf4d 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/signal.h> /* SA_INTERRUPT */ | 17 | #include <linux/signal.h> /* SA_INTERRUPT */ |
18 | #include <linux/jiffies.h> | 18 | #include <linux/jiffies.h> |
19 | #include <linux/platform_device.h> | ||
19 | 20 | ||
20 | #include <asm/hardware.h> | 21 | #include <asm/hardware.h> |
21 | #include <asm/io.h> | 22 | #include <asm/io.h> |
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 4832e57ae579..92cf6f4a1374 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c | |||
@@ -14,6 +14,8 @@ | |||
14 | * This file is licenced under the GPL. | 14 | * This file is licenced under the GPL. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/platform_device.h> | ||
18 | |||
17 | /* configure so an HC device and id are always provided */ | 19 | /* configure so an HC device and id are always provided */ |
18 | /* always called with process context; sleeping is OK */ | 20 | /* always called with process context; sleeping is OK */ |
19 | 21 | ||
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index f4a4aeda40b7..59e20568e8f9 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c | |||
@@ -21,6 +21,8 @@ | |||
21 | 21 | ||
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/signal.h> | 23 | #include <linux/signal.h> |
24 | #include <linux/platform_device.h> | ||
25 | |||
24 | #include <asm/mach-types.h> | 26 | #include <asm/mach-types.h> |
25 | #include <asm/hardware.h> | 27 | #include <asm/hardware.h> |
26 | #include <asm/arch/pxa-regs.h> | 28 | #include <asm/arch/pxa-regs.h> |
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index fab420a2ce71..ee1fc605b402 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c | |||
@@ -19,6 +19,8 @@ | |||
19 | * This file is licenced under the GPL. | 19 | * This file is licenced under the GPL. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/platform_device.h> | ||
23 | |||
22 | #include <asm/hardware.h> | 24 | #include <asm/hardware.h> |
23 | #include <asm/hardware/clock.h> | 25 | #include <asm/hardware/clock.h> |
24 | #include <asm/arch/usb-control.h> | 26 | #include <asm/arch/usb-control.h> |
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index b7fd3f644e1e..b1aa350fd32f 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
@@ -138,11 +138,23 @@ reset_needed: | |||
138 | } | 138 | } |
139 | EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); | 139 | EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); |
140 | 140 | ||
141 | static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) | ||
142 | { | ||
143 | u16 cmd; | ||
144 | return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); | ||
145 | } | ||
146 | |||
147 | #define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) | ||
148 | #define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) | ||
149 | |||
141 | static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) | 150 | static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) |
142 | { | 151 | { |
143 | unsigned long base = 0; | 152 | unsigned long base = 0; |
144 | int i; | 153 | int i; |
145 | 154 | ||
155 | if (!pio_enabled(pdev)) | ||
156 | return; | ||
157 | |||
146 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | 158 | for (i = 0; i < PCI_ROM_RESOURCE; i++) |
147 | if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { | 159 | if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { |
148 | base = pci_resource_start(pdev, i); | 160 | base = pci_resource_start(pdev, i); |
@@ -153,12 +165,20 @@ static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) | |||
153 | uhci_check_and_reset_hc(pdev, base); | 165 | uhci_check_and_reset_hc(pdev, base); |
154 | } | 166 | } |
155 | 167 | ||
168 | static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) | ||
169 | { | ||
170 | return pci_resource_start(pdev, idx) && mmio_enabled(pdev); | ||
171 | } | ||
172 | |||
156 | static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | 173 | static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) |
157 | { | 174 | { |
158 | void __iomem *base; | 175 | void __iomem *base; |
159 | int wait_time; | 176 | int wait_time; |
160 | u32 control; | 177 | u32 control; |
161 | 178 | ||
179 | if (!mmio_resource_enabled(pdev, 0)) | ||
180 | return; | ||
181 | |||
162 | base = ioremap_nocache(pci_resource_start(pdev, 0), | 182 | base = ioremap_nocache(pci_resource_start(pdev, 0), |
163 | pci_resource_len(pdev, 0)); | 183 | pci_resource_len(pdev, 0)); |
164 | if (base == NULL) return; | 184 | if (base == NULL) return; |
@@ -201,6 +221,9 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) | |||
201 | u32 hcc_params, val, temp; | 221 | u32 hcc_params, val, temp; |
202 | u8 cap_length; | 222 | u8 cap_length; |
203 | 223 | ||
224 | if (!mmio_resource_enabled(pdev, 0)) | ||
225 | return; | ||
226 | |||
204 | base = ioremap_nocache(pci_resource_start(pdev, 0), | 227 | base = ioremap_nocache(pci_resource_start(pdev, 0), |
205 | pci_resource_len(pdev, 0)); | 228 | pci_resource_len(pdev, 0)); |
206 | if (base == NULL) return; | 229 | if (base == NULL) return; |
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 40169d9cf2b1..5607c0ae6835 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/interrupt.h> | 54 | #include <linux/interrupt.h> |
55 | #include <linux/usb.h> | 55 | #include <linux/usb.h> |
56 | #include <linux/usb_sl811.h> | 56 | #include <linux/usb_sl811.h> |
57 | #include <linux/platform_device.h> | ||
57 | 58 | ||
58 | #include <asm/io.h> | 59 | #include <asm/io.h> |
59 | #include <asm/irq.h> | 60 | #include <asm/irq.h> |
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 38aebe361ca1..e73faf831b24 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/ioport.h> | 21 | #include <linux/ioport.h> |
22 | #include <linux/platform_device.h> | ||
22 | 23 | ||
23 | #include <pcmcia/cs_types.h> | 24 | #include <pcmcia/cs_types.h> |
24 | #include <pcmcia/cs.h> | 25 | #include <pcmcia/cs.h> |
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index f02965f39501..9b6a39348f81 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/fb.h> | 28 | #include <linux/fb.h> |
29 | #include <linux/device.h> | 29 | #include <linux/platform_device.h> |
30 | #include <linux/dma-mapping.h> | 30 | #include <linux/dma-mapping.h> |
31 | 31 | ||
32 | #include <asm/hardware.h> | 32 | #include <asm/hardware.h> |
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index d28457e0c063..126daff1c848 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/fb.h> | 47 | #include <linux/fb.h> |
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/arcfb.h> | 49 | #include <linux/arcfb.h> |
50 | #include <linux/platform_device.h> | ||
50 | 51 | ||
51 | #include <asm/uaccess.h> | 52 | #include <asm/uaccess.h> |
52 | 53 | ||
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 1991fdb32dfb..4867498f68e8 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
19 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
20 | #include <linux/backlight.h> | 20 | #include <linux/backlight.h> |
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 1dbb82dca40b..1785686a7f11 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <linux/slab.h> | 6 | #include <linux/slab.h> |
7 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
8 | #include <linux/interrupt.h> | 8 | #include <linux/interrupt.h> |
9 | #include <linux/platform_device.h> | ||
10 | |||
9 | #include <asm/setup.h> | 11 | #include <asm/setup.h> |
10 | #include <asm/system.h> | 12 | #include <asm/system.h> |
11 | #include <asm/irq.h> | 13 | #include <asm/irq.h> |
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 116e808d71cd..7363d0b25fdf 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c | |||
@@ -54,6 +54,8 @@ | |||
54 | #include <linux/fb.h> | 54 | #include <linux/fb.h> |
55 | #include <linux/init.h> | 55 | #include <linux/init.h> |
56 | #include <linux/ioport.h> | 56 | #include <linux/ioport.h> |
57 | #include <linux/platform_device.h> | ||
58 | |||
57 | #include <asm/types.h> | 59 | #include <asm/types.h> |
58 | #include <asm/io.h> | 60 | #include <asm/io.h> |
59 | #include <asm/uaccess.h> | 61 | #include <asm/uaccess.h> |
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 485604cd4462..316bfe994811 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/fb.h> | 17 | #include <linux/fb.h> |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 0b9301facbd3..64d9bcc38da3 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/ioport.h> | 32 | #include <linux/ioport.h> |
33 | #include <linux/cpufreq.h> | 33 | #include <linux/cpufreq.h> |
34 | #include <linux/device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
36 | 36 | ||
37 | #include <asm/hardware.h> | 37 | #include <asm/hardware.h> |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 6206da9dd5da..efd9333b05c2 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
38 | #include <linux/cpufreq.h> | 38 | #include <linux/cpufreq.h> |
39 | #include <linux/device.h> | 39 | #include <linux/platform_device.h> |
40 | #include <linux/dma-mapping.h> | 40 | #include <linux/dma-mapping.h> |
41 | 41 | ||
42 | #include <asm/hardware.h> | 42 | #include <asm/hardware.h> |
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index 162012bb9264..8416b2e2b501 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/platform_device.h> | ||
21 | 22 | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | #include <asm/setup.h> | 24 | #include <asm/setup.h> |
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index cb2f7a1de947..f4437430dc5f 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c | |||
@@ -30,7 +30,7 @@ | |||
30 | 30 | ||
31 | #include <linux/config.h> | 31 | #include <linux/config.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/device.h> | 33 | #include <linux/platform_device.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | 35 | ||
36 | #include <linux/types.h> | 36 | #include <linux/types.h> |
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 3862d3cb1fb2..3cef90456a4b 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -86,6 +86,7 @@ | |||
86 | #include <linux/interrupt.h> | 86 | #include <linux/interrupt.h> |
87 | #include <linux/workqueue.h> | 87 | #include <linux/workqueue.h> |
88 | #include <linux/wait.h> | 88 | #include <linux/wait.h> |
89 | #include <linux/platform_device.h> | ||
89 | 90 | ||
90 | #include <asm/io.h> | 91 | #include <asm/io.h> |
91 | #include <asm/uaccess.h> | 92 | #include <asm/uaccess.h> |
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 78e5f194b0df..3d35b28aaac7 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c | |||
@@ -173,7 +173,7 @@ | |||
173 | #include <linux/init.h> | 173 | #include <linux/init.h> |
174 | #include <linux/ioport.h> | 174 | #include <linux/ioport.h> |
175 | #include <linux/cpufreq.h> | 175 | #include <linux/cpufreq.h> |
176 | #include <linux/device.h> | 176 | #include <linux/platform_device.h> |
177 | #include <linux/dma-mapping.h> | 177 | #include <linux/dma-mapping.h> |
178 | 178 | ||
179 | #include <asm/hardware.h> | 179 | #include <asm/hardware.h> |
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 8413907b379a..cf5106eab2d5 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/fb.h> | 18 | #include <linux/fb.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/ioport.h> | 20 | #include <linux/ioport.h> |
21 | #include <linux/platform_device.h> | ||
22 | |||
21 | #include <asm/io.h> | 23 | #include <asm/io.h> |
22 | #include <asm/mtrr.h> | 24 | #include <asm/mtrr.h> |
23 | 25 | ||
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index b1243da55fc5..3cc23106641d 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
20 | #include <linux/ioport.h> | 20 | #include <linux/ioport.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/platform_device.h> | ||
23 | |||
22 | #include <video/vga.h> | 24 | #include <video/vga.h> |
23 | #include <asm/io.h> | 25 | #include <asm/io.h> |
24 | #include <asm/mtrr.h> | 26 | #include <asm/mtrr.h> |
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index b137a3fe0752..92d46555dd86 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/platform_device.h> | ||
24 | |||
23 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
24 | #include <linux/fb.h> | 26 | #include <linux/fb.h> |
25 | #include <linux/init.h> | 27 | #include <linux/init.h> |
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 752bf88906a9..cf8cdb108fd9 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | #include <asm/io.h> | 31 | #include <asm/io.h> |
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index 72fdc10dfdd7..8848e4dfa026 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS | |||
@@ -32,6 +32,10 @@ Domen Puncer | |||
32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) | 32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) |
33 | Vince Negri and Dave Stahl (for finding an important caching bug) | 33 | Vince Negri and Dave Stahl (for finding an important caching bug) |
34 | Adrian Bunk (kcalloc cleanups) | 34 | Adrian Bunk (kcalloc cleanups) |
35 | Miklos Szeredi | ||
36 | Kazeon team for various fixes especially for 2.4 version. | ||
37 | Asser Ferno (Change Notify support) | ||
38 | Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup | ||
35 | 39 | ||
36 | Test case and Bug Report contributors | 40 | Test case and Bug Report contributors |
37 | ------------------------------------- | 41 | ------------------------------------- |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3196d4c4eed3..5bab24f59053 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,8 +1,52 @@ | |||
1 | Version 1.39 | ||
2 | ------------ | ||
3 | Defer close of a file handle slightly if pending writes depend on that file handle | ||
4 | (this reduces the EBADF bad file handle errors that can be logged under heavy | ||
5 | stress on writes). | ||
6 | |||
7 | Version 1.38 | ||
8 | ------------ | ||
9 | Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket) | ||
10 | to be smaller at first (but increasing) so large write performance performance | ||
11 | over GigE is better. Do not hang thread on illegal byte range lock response | ||
12 | from Windows (Windows can send an RFC1001 size which does not match smb size) by | ||
13 | allowing an SMBs TCP length to be up to a few bytes longer than it should be. | ||
14 | wsize and rsize can now be larger than negotiated buffer size if server | ||
15 | supports large readx/writex, even when directio mount flag not specified. | ||
16 | Write size will in many cases now be 16K instead of 4K which greatly helps | ||
17 | file copy performance on lightly loaded networks. Fix oops in dnotify | ||
18 | when experimental config flag enabled. Make cifsFYI more granular. | ||
19 | |||
20 | Version 1.37 | ||
21 | ------------ | ||
22 | Fix readdir caching when unlink removes file in current search buffer, | ||
23 | and this is followed by a rewind search to just before the deleted entry. | ||
24 | Do not attempt to set ctime unless atime and/or mtime change requested | ||
25 | (most servers throw it away anyway). Fix length check of received smbs | ||
26 | to be more accurate. Fix big endian problem with mapchars mount option, | ||
27 | and with a field returned by statfs. | ||
28 | |||
29 | Version 1.36 | ||
30 | ------------ | ||
31 | Add support for mounting to older pre-CIFS servers such as Windows9x and ME. | ||
32 | For these older servers, add option for passing netbios name of server in | ||
33 | on mount (servernetbiosname). Add suspend support for power management, to | ||
34 | avoid cifsd thread preventing software suspend from working. | ||
35 | Add mount option for disabling the default behavior of sending byte range lock | ||
36 | requests to the server (necessary for certain applications which break with | ||
37 | mandatory lock behavior such as Evolution), and also mount option for | ||
38 | requesting case insensitive matching for path based requests (requesting | ||
39 | case sensitive is the default). | ||
40 | |||
1 | Version 1.35 | 41 | Version 1.35 |
2 | ------------ | 42 | ------------ |
3 | Add writepage performance improvements. Fix path name conversions | 43 | Add writepage performance improvements. Fix path name conversions |
4 | for long filenames on mounts which were done with "mapchars" mount option | 44 | for long filenames on mounts which were done with "mapchars" mount option |
5 | specified. | 45 | specified. Ensure multiplex ids do not collide. Fix case in which |
46 | rmmod can oops if done soon after last unmount. Fix truncated | ||
47 | search (readdir) output when resume filename was a long filename. | ||
48 | Fix filename conversion when mapchars mount option was specified and | ||
49 | filename was a long filename. | ||
6 | 50 | ||
7 | Version 1.34 | 51 | Version 1.34 |
8 | ------------ | 52 | ------------ |
@@ -11,7 +55,7 @@ Do not oops if root user kills cifs oplock kernel thread or | |||
11 | kills the cifsd thread (NB: killing the cifs kernel threads is not | 55 | kills the cifsd thread (NB: killing the cifs kernel threads is not |
12 | recommended, unmount and rmmod cifs will kill them when they are | 56 | recommended, unmount and rmmod cifs will kill them when they are |
13 | no longer needed). Fix readdir to ASCII servers (ie older servers | 57 | no longer needed). Fix readdir to ASCII servers (ie older servers |
14 | which do not support Unicode) and also require asterik. | 58 | which do not support Unicode) and also require asterisk. |
15 | Fix out of memory case in which data could be written one page | 59 | Fix out of memory case in which data could be written one page |
16 | off in the page cache. | 60 | off in the page cache. |
17 | 61 | ||
@@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call. | |||
101 | 145 | ||
102 | Version 1.25 | 146 | Version 1.25 |
103 | ------------ | 147 | ------------ |
104 | Fix internationlization problem in cifs readdir with filenames that map to | 148 | Fix internationalization problem in cifs readdir with filenames that map to |
105 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround | 149 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround |
106 | for readdir to netapp servers. Fix search rewind (seek into readdir to return | 150 | for readdir to netapp servers. Fix search rewind (seek into readdir to return |
107 | non-consecutive entries). Do not do readdir when server negotiates | 151 | non-consecutive entries). Do not do readdir when server negotiates |
@@ -276,7 +320,7 @@ Fix caching problem when files opened by multiple clients in which | |||
276 | page cache could contain stale data, and write through did | 320 | page cache could contain stale data, and write through did |
277 | not occur often enough while file was still open when read ahead | 321 | not occur often enough while file was still open when read ahead |
278 | (read oplock) not allowed. Treat "sep=" when first mount option | 322 | (read oplock) not allowed. Treat "sep=" when first mount option |
279 | as an overrride of comma as the default separator between mount | 323 | as an override of comma as the default separator between mount |
280 | options. | 324 | options. |
281 | 325 | ||
282 | Version 1.01 | 326 | Version 1.01 |
@@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string. | |||
286 | Version 1.00 | 330 | Version 1.00 |
287 | ------------ | 331 | ------------ |
288 | Gracefully clean up failed mounts when attempting to mount to servers such as | 332 | Gracefully clean up failed mounts when attempting to mount to servers such as |
289 | Windows 98 that terminate tcp sessions during prototocol negotiation. Handle | 333 | Windows 98 that terminate tcp sessions during protocol negotiation. Handle |
290 | embedded commas in mount parsing of passwords. | 334 | embedded commas in mount parsing of passwords. |
291 | 335 | ||
292 | Version 0.99 | 336 | Version 0.99 |
@@ -295,7 +339,7 @@ Invalidate local inode cached pages on oplock break and when last file | |||
295 | instance is closed so that the client does not continue using stale local | 339 | instance is closed so that the client does not continue using stale local |
296 | copy rather than later modified server copy of file. Do not reconnect | 340 | copy rather than later modified server copy of file. Do not reconnect |
297 | when server drops the tcp session prematurely before negotiate | 341 | when server drops the tcp session prematurely before negotiate |
298 | protocol response. Fix oops in roepen_file when dentry freed. Allow | 342 | protocol response. Fix oops in reopen_file when dentry freed. Allow |
299 | the support for CIFS Unix Extensions to be disabled via proc interface. | 343 | the support for CIFS Unix Extensions to be disabled via proc interface. |
300 | 344 | ||
301 | Version 0.98 | 345 | Version 0.98 |
@@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early | |||
637 | Version 0.41 | 681 | Version 0.41 |
638 | ------------ | 682 | ------------ |
639 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked | 683 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked |
640 | files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. | 684 | files now return the correct number of links on fstat as they are repeatedly linked and unlinked. |
641 | 685 | ||
642 | Version 0.40 | 686 | Version 0.40 |
643 | ------------ | 687 | ------------ |
@@ -704,7 +748,7 @@ session) | |||
704 | and cleaned them up and made them more consistent with other cifs functions. | 748 | and cleaned them up and made them more consistent with other cifs functions. |
705 | 749 | ||
706 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways | 750 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways |
707 | (with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, | 751 | (with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed, |
708 | nor is the symlink support using the Unix extensions | 752 | nor is the symlink support using the Unix extensions |
709 | 753 | ||
710 | 8) Started adding the readlink and follow_link code | 754 | 8) Started adding the readlink and follow_link code |
diff --git a/fs/cifs/README b/fs/cifs/README index 34b0cf7111f3..bb90941826ad 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -294,8 +294,10 @@ A partial list of the supported mount options follows: | |||
294 | during the local client kernel build will be used. | 294 | during the local client kernel build will be used. |
295 | If server does not support Unicode, this parameter is | 295 | If server does not support Unicode, this parameter is |
296 | unused. | 296 | unused. |
297 | rsize default read size | 297 | rsize default read size (usually 16K) |
298 | wsize default write size | 298 | wsize default write size (usually 16K, 32K is often better over GigE) |
299 | maximum wsize currently allowed by CIFS is 57344 (14 4096 byte | ||
300 | pages) | ||
299 | rw mount the network share read-write (note that the | 301 | rw mount the network share read-write (note that the |
300 | server may still consider the share read-only) | 302 | server may still consider the share read-only) |
301 | ro mount network share read-only | 303 | ro mount network share read-only |
@@ -407,6 +409,13 @@ A partial list of the supported mount options follows: | |||
407 | This has no effect if the server does not support | 409 | This has no effect if the server does not support |
408 | Unicode on the wire. | 410 | Unicode on the wire. |
409 | nomapchars Do not translate any of these seven characters (default). | 411 | nomapchars Do not translate any of these seven characters (default). |
412 | nocase Request case insensitive path name matching (case | ||
413 | sensitive is the default if the server suports it). | ||
414 | nobrl Do not send byte range lock requests to the server. | ||
415 | This is necessary for certain applications that break | ||
416 | with cifs style mandatory byte range locks (and most | ||
417 | cifs servers do not yet support requesting advisory | ||
418 | byte range locks). | ||
410 | remount remount the share (often used to change from ro to rw mounts | 419 | remount remount the share (often used to change from ro to rw mounts |
411 | or vice versa) | 420 | or vice versa) |
412 | 421 | ||
@@ -473,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in | |||
473 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable | 482 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable |
474 | tracing to the kernel message log type: | 483 | tracing to the kernel message log type: |
475 | 484 | ||
476 | echo 1 > /proc/fs/cifs/cifsFYI | 485 | echo 7 > /proc/fs/cifs/cifsFYI |
477 | 486 | ||
478 | and for more extensive tracing including the start of smb requests and responses | 487 | cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel |
488 | logging of various informational messages. 2 enables logging of non-zero | ||
489 | SMB return codes while 4 enables logging of requests that take longer | ||
490 | than one second to complete (except for byte range lock requests). | ||
491 | Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the | ||
492 | source code (typically by setting it in the beginning of cifsglob.h), | ||
493 | and setting it to seven enables all three. Finally, tracing | ||
494 | the start of smb requests and responses can be enabled via: | ||
479 | 495 | ||
480 | echo 1 > /proc/fs/cifs/traceSMB | 496 | echo 1 > /proc/fs/cifs/traceSMB |
481 | 497 | ||
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 8cc881694e29..c909298d11ed 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
@@ -1,4 +1,4 @@ | |||
1 | version 1.34 April 29, 2005 | 1 | version 1.37 October 9, 2005 |
2 | 2 | ||
3 | A Partial List of Missing Features | 3 | A Partial List of Missing Features |
4 | ================================== | 4 | ================================== |
@@ -7,14 +7,14 @@ Contributions are welcome. There are plenty of opportunities | |||
7 | for visible, important contributions to this module. Here | 7 | for visible, important contributions to this module. Here |
8 | is a partial list of the known problems and missing features: | 8 | is a partial list of the known problems and missing features: |
9 | 9 | ||
10 | a) Support for SecurityDescriptors for chmod/chgrp/chown so | 10 | a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown |
11 | these can be supported for Windows servers | 11 | so that these operations can be supported to Windows servers |
12 | 12 | ||
13 | b) Better pam/winbind integration (e.g. to handle uid mapping | 13 | b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS |
14 | better) | 14 | SecurityDescriptors |
15 | 15 | ||
16 | c) multi-user mounts - multiplexed sessionsetups over single vc | 16 | c) Better pam/winbind integration (e.g. to handle uid mapping |
17 | (ie tcp session) - more testing needed | 17 | better) |
18 | 18 | ||
19 | d) Kerberos/SPNEGO session setup support - (started) | 19 | d) Kerberos/SPNEGO session setup support - (started) |
20 | 20 | ||
@@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than | |||
29 | using FindNotify or equivalent. - (started) | 29 | using FindNotify or equivalent. - (started) |
30 | 30 | ||
31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS | 31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS |
32 | style byte range lock differences | 32 | style byte range lock differences. Save byte range locks so |
33 | reconnect can replay them. | ||
33 | 34 | ||
34 | h) quota support | 35 | h) Support unlock all (unlock 0,MAX_OFFSET) |
36 | by unlocking all known byte range locks that we locked on the file. | ||
35 | 37 | ||
36 | j) finish writepages support (multi-page write behind for improved | 38 | i) quota support (needs minor kernel change since quota calls |
37 | performance) and syncpage | 39 | to make it to network filesystems or deviceless filesystems) |
40 | |||
41 | j) investigate sync behavior (including syncpage) and check | ||
42 | for proper behavior of intr/nointr | ||
38 | 43 | ||
39 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the | 44 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the |
40 | extra copy in/out of the socket buffers in some cases. | 45 | extra copy in/out of the socket buffers in some cases. |
@@ -57,20 +62,18 @@ p) Add support for storing symlink and fifo info to Windows servers | |||
57 | in the Extended Attribute format their SFU clients would recognize. | 62 | in the Extended Attribute format their SFU clients would recognize. |
58 | 63 | ||
59 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows | 64 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows |
60 | will autorefresh (started) | 65 | will autorefresh (partially complete by Asser). Needs minor kernel |
66 | vfs change to support removing D_NOTIFY on a file. | ||
61 | 67 | ||
62 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of | 68 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of |
63 | the CIFS statistics (started) | 69 | the CIFS statistics (started) |
64 | 70 | ||
65 | q) implement support for security and trusted categories of xattrs | 71 | s) implement support for security and trusted categories of xattrs |
66 | (requires minor protocol extension) to enable better support for SELINUX | 72 | (requires minor protocol extension) to enable better support for SELINUX |
67 | 73 | ||
68 | r) Implement O_DIRECT flag on open (already supported on mount) | 74 | t) Implement O_DIRECT flag on open (already supported on mount) |
69 | |||
70 | s) Allow remapping of last remaining character (\) to +0xF000 which | ||
71 | (this character is valid for POSIX but not for Windows) | ||
72 | 75 | ||
73 | t) Create UID mapping facility so server UIDs can be mapped on a per | 76 | u) Create UID mapping facility so server UIDs can be mapped on a per |
74 | mount or a per server basis to client UIDs or nobody if no mapping | 77 | mount or a per server basis to client UIDs or nobody if no mapping |
75 | exists. This is helpful when Unix extensions are negotiated to | 78 | exists. This is helpful when Unix extensions are negotiated to |
76 | allow better permission checking when UIDs differ on the server | 79 | allow better permission checking when UIDs differ on the server |
@@ -78,6 +81,17 @@ and client. Add new protocol request to the CIFS protocol | |||
78 | standard for asking the server for the corresponding name of a | 81 | standard for asking the server for the corresponding name of a |
79 | particular uid. | 82 | particular uid. |
80 | 83 | ||
84 | v) Add support for CIFS Unix and also the newer POSIX extensions to the | ||
85 | server side for Samba 4. | ||
86 | |||
87 | w) Finish up the dos time conversion routines needed to return old server | ||
88 | time to the client (default time, of now or time 0 is used now for these | ||
89 | very old servers) | ||
90 | |||
91 | x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) | ||
92 | |||
93 | y) Finish testing of Windows 9x/Windows ME server support (started). | ||
94 | |||
81 | KNOWN BUGS (updated April 29, 2005) | 95 | KNOWN BUGS (updated April 29, 2005) |
82 | ==================================== | 96 | ==================================== |
83 | See http://bugzilla.samba.org - search on product "CifsVFS" for | 97 | See http://bugzilla.samba.org - search on product "CifsVFS" for |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index e02010dd73ec..98539e2afe81 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
@@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx, | |||
191 | unsigned char **eoc, | 191 | unsigned char **eoc, |
192 | unsigned int *cls, unsigned int *con, unsigned int *tag) | 192 | unsigned int *cls, unsigned int *con, unsigned int *tag) |
193 | { | 193 | { |
194 | unsigned int def, len; | 194 | unsigned int def = 0; |
195 | unsigned int len = 0; | ||
195 | 196 | ||
196 | if (!asn1_id_decode(ctx, cls, con, tag)) | 197 | if (!asn1_id_decode(ctx, cls, con, tag)) |
197 | return 0; | 198 | return 0; |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4061e43471c1..22a444a3fe4c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
81 | buf += length; | 81 | buf += length; |
82 | length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); | 82 | length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); |
83 | buf += length; | 83 | buf += length; |
84 | length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid); | ||
85 | buf += length; | ||
84 | length = sprintf(buf, "Servers:"); | 86 | length = sprintf(buf, "Servers:"); |
85 | buf += length; | 87 | buf += length; |
86 | 88 | ||
@@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
97 | } else { | 99 | } else { |
98 | length = | 100 | length = |
99 | sprintf(buf, | 101 | sprintf(buf, |
100 | "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", | 102 | "\n%d) Name: %s Domain: %s Mounts: %d OS: %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t", |
101 | i, ses->serverName, ses->serverDomain, | 103 | i, ses->serverName, ses->serverDomain, |
102 | atomic_read(&ses->inUse), | 104 | atomic_read(&ses->inUse), |
103 | ses->serverOS, ses->serverNOS, | 105 | ses->serverOS, ses->serverNOS, |
@@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
105 | buf += length; | 107 | buf += length; |
106 | } | 108 | } |
107 | if(ses->server) { | 109 | if(ses->server) { |
108 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", | 110 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d", |
109 | ses->server->tcpStatus, | 111 | ses->server->tcpStatus, |
110 | atomic_read(&ses->server->socketUseCount), | 112 | atomic_read(&ses->server->socketUseCount), |
111 | ses->server->secMode, | 113 | ses->server->secMode, |
112 | atomic_read(&ses->server->inFlight)); | 114 | atomic_read(&ses->server->inFlight)); |
113 | 115 | ||
116 | #ifdef CONFIG_CIFS_STATS2 | ||
117 | buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d", | ||
118 | atomic_read(&ses->server->inSend), | ||
119 | atomic_read(&ses->server->num_waiters)); | ||
120 | #endif | ||
121 | |||
114 | length = sprintf(buf, "\nMIDs:\n"); | 122 | length = sprintf(buf, "\nMIDs:\n"); |
115 | buf += length; | 123 | buf += length; |
116 | 124 | ||
@@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
149 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | 157 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); |
150 | length = | 158 | length = |
151 | sprintf(buf, | 159 | sprintf(buf, |
152 | "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", | 160 | "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", |
153 | i, tcon->treeName, | 161 | i, tcon->treeName, |
154 | atomic_read(&tcon->useCount), | 162 | atomic_read(&tcon->useCount), |
155 | tcon->nativeFileSystem, | 163 | tcon->nativeFileSystem, |
@@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
195 | } | 203 | } |
196 | 204 | ||
197 | #ifdef CONFIG_CIFS_STATS | 205 | #ifdef CONFIG_CIFS_STATS |
206 | |||
207 | static int | ||
208 | cifs_stats_write(struct file *file, const char __user *buffer, | ||
209 | unsigned long count, void *data) | ||
210 | { | ||
211 | char c; | ||
212 | int rc; | ||
213 | struct list_head *tmp; | ||
214 | struct cifsTconInfo *tcon; | ||
215 | |||
216 | rc = get_user(c, buffer); | ||
217 | if (rc) | ||
218 | return rc; | ||
219 | |||
220 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { | ||
221 | read_lock(&GlobalSMBSeslock); | ||
222 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
223 | tcon = list_entry(tmp, struct cifsTconInfo, | ||
224 | cifsConnectionList); | ||
225 | atomic_set(&tcon->num_smbs_sent, 0); | ||
226 | atomic_set(&tcon->num_writes, 0); | ||
227 | atomic_set(&tcon->num_reads, 0); | ||
228 | atomic_set(&tcon->num_oplock_brks, 0); | ||
229 | atomic_set(&tcon->num_opens, 0); | ||
230 | atomic_set(&tcon->num_closes, 0); | ||
231 | atomic_set(&tcon->num_deletes, 0); | ||
232 | atomic_set(&tcon->num_mkdirs, 0); | ||
233 | atomic_set(&tcon->num_rmdirs, 0); | ||
234 | atomic_set(&tcon->num_renames, 0); | ||
235 | atomic_set(&tcon->num_t2renames, 0); | ||
236 | atomic_set(&tcon->num_ffirst, 0); | ||
237 | atomic_set(&tcon->num_fnext, 0); | ||
238 | atomic_set(&tcon->num_fclose, 0); | ||
239 | atomic_set(&tcon->num_hardlinks, 0); | ||
240 | atomic_set(&tcon->num_symlinks, 0); | ||
241 | atomic_set(&tcon->num_locks, 0); | ||
242 | } | ||
243 | read_unlock(&GlobalSMBSeslock); | ||
244 | } | ||
245 | |||
246 | return count; | ||
247 | } | ||
248 | |||
198 | static int | 249 | static int |
199 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | 250 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, |
200 | int count, int *eof, void *data) | 251 | int count, int *eof, void *data) |
@@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | |||
254 | buf += sprintf(buf, "\tDISCONNECTED "); | 305 | buf += sprintf(buf, "\tDISCONNECTED "); |
255 | length += 14; | 306 | length += 14; |
256 | } | 307 | } |
257 | item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", | 308 | item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d", |
258 | atomic_read(&tcon->num_smbs_sent), | 309 | atomic_read(&tcon->num_smbs_sent), |
259 | atomic_read(&tcon->num_oplock_brks)); | 310 | atomic_read(&tcon->num_oplock_brks)); |
260 | buf += item_length; | 311 | buf += item_length; |
261 | length += item_length; | 312 | length += item_length; |
262 | item_length = sprintf(buf,"\nReads: %d Bytes %lld", | 313 | item_length = sprintf(buf, "\nReads: %d Bytes: %lld", |
263 | atomic_read(&tcon->num_reads), | 314 | atomic_read(&tcon->num_reads), |
264 | (long long)(tcon->bytes_read)); | 315 | (long long)(tcon->bytes_read)); |
265 | buf += item_length; | 316 | buf += item_length; |
266 | length += item_length; | 317 | length += item_length; |
267 | item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", | 318 | item_length = sprintf(buf, "\nWrites: %d Bytes: %lld", |
268 | atomic_read(&tcon->num_writes), | 319 | atomic_read(&tcon->num_writes), |
269 | (long long)(tcon->bytes_written)); | 320 | (long long)(tcon->bytes_written)); |
321 | buf += item_length; | ||
322 | length += item_length; | ||
323 | item_length = sprintf(buf, | ||
324 | "\nLocks: %d HardLinks: %d Symlinks: %d", | ||
325 | atomic_read(&tcon->num_locks), | ||
326 | atomic_read(&tcon->num_hardlinks), | ||
327 | atomic_read(&tcon->num_symlinks)); | ||
328 | buf += item_length; | ||
329 | length += item_length; | ||
330 | |||
331 | item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d", | ||
332 | atomic_read(&tcon->num_opens), | ||
333 | atomic_read(&tcon->num_closes), | ||
334 | atomic_read(&tcon->num_deletes)); | ||
270 | buf += item_length; | 335 | buf += item_length; |
271 | length += item_length; | 336 | length += item_length; |
272 | item_length = sprintf(buf, | 337 | item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d", |
273 | "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", | ||
274 | atomic_read(&tcon->num_opens), | ||
275 | atomic_read(&tcon->num_deletes), | ||
276 | atomic_read(&tcon->num_mkdirs), | 338 | atomic_read(&tcon->num_mkdirs), |
277 | atomic_read(&tcon->num_rmdirs)); | 339 | atomic_read(&tcon->num_rmdirs)); |
278 | buf += item_length; | 340 | buf += item_length; |
279 | length += item_length; | 341 | length += item_length; |
280 | item_length = sprintf(buf, | 342 | item_length = sprintf(buf, "\nRenames: %d T2 Renames %d", |
281 | "\nRenames: %d T2 Renames %d", | ||
282 | atomic_read(&tcon->num_renames), | 343 | atomic_read(&tcon->num_renames), |
283 | atomic_read(&tcon->num_t2renames)); | 344 | atomic_read(&tcon->num_t2renames)); |
284 | buf += item_length; | 345 | buf += item_length; |
285 | length += item_length; | 346 | length += item_length; |
347 | item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d", | ||
348 | atomic_read(&tcon->num_ffirst), | ||
349 | atomic_read(&tcon->num_fnext), | ||
350 | atomic_read(&tcon->num_fclose)); | ||
351 | buf += item_length; | ||
352 | length += item_length; | ||
286 | } | 353 | } |
287 | read_unlock(&GlobalSMBSeslock); | 354 | read_unlock(&GlobalSMBSeslock); |
288 | 355 | ||
@@ -341,8 +408,10 @@ cifs_proc_init(void) | |||
341 | cifs_debug_data_read, NULL); | 408 | cifs_debug_data_read, NULL); |
342 | 409 | ||
343 | #ifdef CONFIG_CIFS_STATS | 410 | #ifdef CONFIG_CIFS_STATS |
344 | create_proc_read_entry("Stats", 0, proc_fs_cifs, | 411 | pde = create_proc_read_entry("Stats", 0, proc_fs_cifs, |
345 | cifs_stats_read, NULL); | 412 | cifs_stats_read, NULL); |
413 | if (pde) | ||
414 | pde->write_proc = cifs_stats_write; | ||
346 | #endif | 415 | #endif |
347 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, | 416 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, |
348 | cifsFYI_read, NULL); | 417 | cifsFYI_read, NULL); |
@@ -360,7 +429,7 @@ cifs_proc_init(void) | |||
360 | if (pde) | 429 | if (pde) |
361 | pde->write_proc = oplockEnabled_write; | 430 | pde->write_proc = oplockEnabled_write; |
362 | 431 | ||
363 | pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs, | 432 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, |
364 | quotaEnabled_read, NULL); | 433 | quotaEnabled_read, NULL); |
365 | if (pde) | 434 | if (pde) |
366 | pde->write_proc = quotaEnabled_write; | 435 | pde->write_proc = quotaEnabled_write; |
@@ -419,7 +488,7 @@ cifs_proc_clean(void) | |||
419 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); | 488 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); |
420 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); | 489 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); |
421 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); | 490 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); |
422 | remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs); | 491 | remove_proc_entry("Experimental",proc_fs_cifs); |
423 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); | 492 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); |
424 | remove_proc_entry("cifs", proc_root_fs); | 493 | remove_proc_entry("cifs", proc_root_fs); |
425 | } | 494 | } |
@@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer, | |||
459 | cifsFYI = 0; | 528 | cifsFYI = 0; |
460 | else if (c == '1' || c == 'y' || c == 'Y') | 529 | else if (c == '1' || c == 'y' || c == 'Y') |
461 | cifsFYI = 1; | 530 | cifsFYI = 1; |
531 | else if((c > '1') && (c <= '9')) | ||
532 | cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */ | ||
462 | 533 | ||
463 | return count; | 534 | return count; |
464 | } | 535 | } |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index bf24d2828f68..4304d9dcfb6c 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
@@ -26,6 +26,9 @@ | |||
26 | void cifs_dump_mem(char *label, void *data, int length); | 26 | void cifs_dump_mem(char *label, void *data, int length); |
27 | extern int traceSMB; /* flag which enables the function below */ | 27 | extern int traceSMB; /* flag which enables the function below */ |
28 | void dump_smb(struct smb_hdr *, int); | 28 | void dump_smb(struct smb_hdr *, int); |
29 | #define CIFS_INFO 0x01 | ||
30 | #define CIFS_RC 0x02 | ||
31 | #define CIFS_TIMER 0x04 | ||
29 | 32 | ||
30 | /* | 33 | /* |
31 | * debug ON | 34 | * debug ON |
@@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int); | |||
36 | 39 | ||
37 | /* information message: e.g., configuration, major event */ | 40 | /* information message: e.g., configuration, major event */ |
38 | extern int cifsFYI; | 41 | extern int cifsFYI; |
39 | #define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) | 42 | #define cifsfyi(format,arg...) if (cifsFYI & CIFS_INFO) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) |
40 | 43 | ||
41 | #define cFYI(button,prspec) if (button) cifsfyi prspec | 44 | #define cFYI(button,prspec) if (button) cifsfyi prspec |
42 | 45 | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ec00d61d5308..f799f6f0e729 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -24,6 +24,9 @@ | |||
24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ | 24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ |
25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ | 25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ |
26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ | 26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ |
27 | #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ | ||
28 | #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ | ||
29 | #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ | ||
27 | 30 | ||
28 | struct cifs_sb_info { | 31 | struct cifs_sb_info { |
29 | struct cifsTconInfo *tcon; /* primary mount */ | 32 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1ebf7dafc1d7..877095a1192a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0; | |||
59 | unsigned int sign_CIFS_PDUs = 1; | 59 | unsigned int sign_CIFS_PDUs = 1; |
60 | extern struct task_struct * oplockThread; /* remove sparse warning */ | 60 | extern struct task_struct * oplockThread; /* remove sparse warning */ |
61 | struct task_struct * oplockThread = NULL; | 61 | struct task_struct * oplockThread = NULL; |
62 | extern struct task_struct * dnotifyThread; /* remove sparse warning */ | ||
63 | struct task_struct * dnotifyThread = NULL; | ||
62 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | 64 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
63 | module_param(CIFSMaxBufSize, int, 0); | 65 | module_param(CIFSMaxBufSize, int, 0); |
64 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); | 66 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); |
@@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0); | |||
73 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); | 75 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); |
74 | 76 | ||
75 | static DECLARE_COMPLETION(cifs_oplock_exited); | 77 | static DECLARE_COMPLETION(cifs_oplock_exited); |
78 | static DECLARE_COMPLETION(cifs_dnotify_exited); | ||
76 | 79 | ||
77 | extern mempool_t *cifs_sm_req_poolp; | 80 | extern mempool_t *cifs_sm_req_poolp; |
78 | extern mempool_t *cifs_req_poolp; | 81 | extern mempool_t *cifs_req_poolp; |
@@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) | |||
202 | #endif /* CIFS_EXPERIMENTAL */ | 205 | #endif /* CIFS_EXPERIMENTAL */ |
203 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); | 206 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); |
204 | 207 | ||
208 | /* Old Windows servers do not support level 103, retry with level | ||
209 | one if old server failed the previous call */ | ||
210 | if(rc) | ||
211 | rc = SMBOldQFSInfo(xid, pTcon, buf); | ||
205 | /* | 212 | /* |
206 | int f_type; | 213 | int f_type; |
207 | __fsid_t f_fsid; | 214 | __fsid_t f_fsid; |
@@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
253 | cifs_inode->clientCanCacheAll = FALSE; | 260 | cifs_inode->clientCanCacheAll = FALSE; |
254 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; | 261 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; |
255 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 262 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
256 | 263 | cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; | |
257 | INIT_LIST_HEAD(&cifs_inode->openFileList); | 264 | INIT_LIST_HEAD(&cifs_inode->openFileList); |
258 | return &cifs_inode->vfs_inode; | 265 | return &cifs_inode->vfs_inode; |
259 | } | 266 | } |
@@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = { | |||
398 | }; | 405 | }; |
399 | #endif | 406 | #endif |
400 | 407 | ||
408 | static void cifs_umount_begin(struct super_block * sblock) | ||
409 | { | ||
410 | struct cifs_sb_info *cifs_sb; | ||
411 | struct cifsTconInfo * tcon; | ||
412 | |||
413 | cifs_sb = CIFS_SB(sblock); | ||
414 | if(cifs_sb == NULL) | ||
415 | return; | ||
416 | |||
417 | tcon = cifs_sb->tcon; | ||
418 | if(tcon == NULL) | ||
419 | return; | ||
420 | down(&tcon->tconSem); | ||
421 | if (atomic_read(&tcon->useCount) == 1) | ||
422 | tcon->tidStatus = CifsExiting; | ||
423 | up(&tcon->tconSem); | ||
424 | |||
425 | if(tcon->ses && tcon->ses->server) | ||
426 | { | ||
427 | cERROR(1,("wake up tasks now - umount begin not complete")); | ||
428 | wake_up_all(&tcon->ses->server->request_q); | ||
429 | } | ||
430 | /* BB FIXME - finish add checks for tidStatus BB */ | ||
431 | |||
432 | return; | ||
433 | } | ||
434 | |||
435 | |||
401 | static int cifs_remount(struct super_block *sb, int *flags, char *data) | 436 | static int cifs_remount(struct super_block *sb, int *flags, char *data) |
402 | { | 437 | { |
403 | *flags |= MS_NODIRATIME; | 438 | *flags |= MS_NODIRATIME; |
@@ -415,7 +450,7 @@ struct super_operations cifs_super_ops = { | |||
415 | unless later we add lazy close of inodes or unless the kernel forgets to call | 450 | unless later we add lazy close of inodes or unless the kernel forgets to call |
416 | us with the same number of releases (closes) as opens */ | 451 | us with the same number of releases (closes) as opens */ |
417 | .show_options = cifs_show_options, | 452 | .show_options = cifs_show_options, |
418 | /* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ | 453 | /* .umount_begin = cifs_umount_begin, */ /* BB finish in the future */ |
419 | .remount_fs = cifs_remount, | 454 | .remount_fs = cifs_remount, |
420 | }; | 455 | }; |
421 | 456 | ||
@@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg) | |||
783 | do { | 818 | do { |
784 | if (try_to_freeze()) | 819 | if (try_to_freeze()) |
785 | continue; | 820 | continue; |
786 | set_current_state(TASK_INTERRUPTIBLE); | ||
787 | 821 | ||
788 | schedule_timeout(1*HZ); | ||
789 | spin_lock(&GlobalMid_Lock); | 822 | spin_lock(&GlobalMid_Lock); |
790 | if(list_empty(&GlobalOplock_Q)) { | 823 | if(list_empty(&GlobalOplock_Q)) { |
791 | spin_unlock(&GlobalMid_Lock); | 824 | spin_unlock(&GlobalMid_Lock); |
@@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg) | |||
834 | } | 867 | } |
835 | } else | 868 | } else |
836 | spin_unlock(&GlobalMid_Lock); | 869 | spin_unlock(&GlobalMid_Lock); |
870 | set_current_state(TASK_INTERRUPTIBLE); | ||
871 | schedule_timeout(1); /* yield in case q were corrupt */ | ||
837 | } | 872 | } |
838 | } while(!signal_pending(current)); | 873 | } while(!signal_pending(current)); |
839 | complete_and_exit (&cifs_oplock_exited, 0); | ||
840 | oplockThread = NULL; | 874 | oplockThread = NULL; |
875 | complete_and_exit (&cifs_oplock_exited, 0); | ||
876 | } | ||
877 | |||
878 | static int cifs_dnotify_thread(void * dummyarg) | ||
879 | { | ||
880 | daemonize("cifsdnotifyd"); | ||
881 | allow_signal(SIGTERM); | ||
882 | |||
883 | dnotifyThread = current; | ||
884 | do { | ||
885 | if(try_to_freeze()) | ||
886 | continue; | ||
887 | set_current_state(TASK_INTERRUPTIBLE); | ||
888 | schedule_timeout(39*HZ); | ||
889 | } while(!signal_pending(current)); | ||
890 | complete_and_exit (&cifs_dnotify_exited, 0); | ||
841 | } | 891 | } |
842 | 892 | ||
843 | static int __init | 893 | static int __init |
@@ -851,6 +901,10 @@ init_cifs(void) | |||
851 | INIT_LIST_HEAD(&GlobalSMBSessionList); | 901 | INIT_LIST_HEAD(&GlobalSMBSessionList); |
852 | INIT_LIST_HEAD(&GlobalTreeConnectionList); | 902 | INIT_LIST_HEAD(&GlobalTreeConnectionList); |
853 | INIT_LIST_HEAD(&GlobalOplock_Q); | 903 | INIT_LIST_HEAD(&GlobalOplock_Q); |
904 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
905 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | ||
906 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); | ||
907 | #endif | ||
854 | /* | 908 | /* |
855 | * Initialize Global counters | 909 | * Initialize Global counters |
856 | */ | 910 | */ |
@@ -886,10 +940,16 @@ init_cifs(void) | |||
886 | if (!rc) { | 940 | if (!rc) { |
887 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, | 941 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, |
888 | CLONE_FS | CLONE_FILES | CLONE_VM); | 942 | CLONE_FS | CLONE_FILES | CLONE_VM); |
889 | if(rc > 0) | 943 | if(rc > 0) { |
890 | return 0; | 944 | rc = (int)kernel_thread(cifs_dnotify_thread, NULL, |
891 | else | 945 | CLONE_FS | CLONE_FILES | CLONE_VM); |
946 | if(rc > 0) | ||
947 | return 0; | ||
948 | else | ||
949 | cERROR(1,("error %d create dnotify thread", rc)); | ||
950 | } else { | ||
892 | cERROR(1,("error %d create oplock thread",rc)); | 951 | cERROR(1,("error %d create oplock thread",rc)); |
952 | } | ||
893 | } | 953 | } |
894 | cifs_destroy_request_bufs(); | 954 | cifs_destroy_request_bufs(); |
895 | } | 955 | } |
@@ -918,6 +978,10 @@ exit_cifs(void) | |||
918 | send_sig(SIGTERM, oplockThread, 1); | 978 | send_sig(SIGTERM, oplockThread, 1); |
919 | wait_for_completion(&cifs_oplock_exited); | 979 | wait_for_completion(&cifs_oplock_exited); |
920 | } | 980 | } |
981 | if(dnotifyThread) { | ||
982 | send_sig(SIGTERM, dnotifyThread, 1); | ||
983 | wait_for_completion(&cifs_dnotify_exited); | ||
984 | } | ||
921 | } | 985 | } |
922 | 986 | ||
923 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); | 987 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 1fd21f66f243..1223fa81dbd2 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); | |||
81 | 81 | ||
82 | /* Functions related to dir entries */ | 82 | /* Functions related to dir entries */ |
83 | extern struct dentry_operations cifs_dentry_ops; | 83 | extern struct dentry_operations cifs_dentry_ops; |
84 | extern struct dentry_operations cifs_ci_dentry_ops; | ||
84 | 85 | ||
85 | /* Functions related to symlinks */ | 86 | /* Functions related to symlinks */ |
86 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); | 87 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); |
@@ -96,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 97 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
97 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 98 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
98 | unsigned int command, unsigned long arg); | 99 | unsigned int command, unsigned long arg); |
99 | #define CIFS_VERSION "1.35" | 100 | #define CIFS_VERSION "1.39" |
100 | #endif /* _CIFSFS_H */ | 101 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 81babab265e1..1ba08f8c5bc4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -110,8 +110,9 @@ enum protocolEnum { | |||
110 | */ | 110 | */ |
111 | 111 | ||
112 | struct TCP_Server_Info { | 112 | struct TCP_Server_Info { |
113 | char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ | 113 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
114 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ | 114 | char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; |
115 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; | ||
115 | struct socket *ssocket; | 116 | struct socket *ssocket; |
116 | union { | 117 | union { |
117 | struct sockaddr_in sockAddr; | 118 | struct sockaddr_in sockAddr; |
@@ -122,13 +123,17 @@ struct TCP_Server_Info { | |||
122 | struct list_head pending_mid_q; | 123 | struct list_head pending_mid_q; |
123 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | 124 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ |
124 | unsigned short server_codepage; /* codepage for the server */ | 125 | unsigned short server_codepage; /* codepage for the server */ |
125 | unsigned long ip_address; /* IP addr for the server if known */ | 126 | unsigned long ip_address; /* IP addr for the server if known */ |
126 | enum protocolEnum protocolType; | 127 | enum protocolEnum protocolType; |
127 | char versionMajor; | 128 | char versionMajor; |
128 | char versionMinor; | 129 | char versionMinor; |
129 | unsigned svlocal:1; /* local server or remote */ | 130 | unsigned svlocal:1; /* local server or remote */ |
130 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ | 131 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ |
131 | atomic_t inFlight; /* number of requests on the wire to server */ | 132 | atomic_t inFlight; /* number of requests on the wire to server */ |
133 | #ifdef CONFIG_CIFS_STATS2 | ||
134 | atomic_t inSend; /* requests trying to send */ | ||
135 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
136 | #endif | ||
132 | enum statusEnum tcpStatus; /* what we think the status is */ | 137 | enum statusEnum tcpStatus; /* what we think the status is */ |
133 | struct semaphore tcpSem; | 138 | struct semaphore tcpSem; |
134 | struct task_struct *tsk; | 139 | struct task_struct *tsk; |
@@ -147,8 +152,10 @@ struct TCP_Server_Info { | |||
147 | /* (returned on Negotiate */ | 152 | /* (returned on Negotiate */ |
148 | int capabilities; /* allow selective disabling of caps by smb sess */ | 153 | int capabilities; /* allow selective disabling of caps by smb sess */ |
149 | __u16 timeZone; | 154 | __u16 timeZone; |
155 | __u16 CurrentMid; /* multiplex id - rotating counter */ | ||
150 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | 156 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; |
151 | char workstation_RFC1001_name[16]; /* 16th byte is always zero */ | 157 | /* 16th byte of RFC1001 workstation name is always null */ |
158 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; | ||
152 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 159 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
153 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | 160 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; |
154 | }; | 161 | }; |
@@ -214,19 +221,41 @@ struct cifsTconInfo { | |||
214 | atomic_t num_reads; | 221 | atomic_t num_reads; |
215 | atomic_t num_oplock_brks; | 222 | atomic_t num_oplock_brks; |
216 | atomic_t num_opens; | 223 | atomic_t num_opens; |
224 | atomic_t num_closes; | ||
217 | atomic_t num_deletes; | 225 | atomic_t num_deletes; |
218 | atomic_t num_mkdirs; | 226 | atomic_t num_mkdirs; |
219 | atomic_t num_rmdirs; | 227 | atomic_t num_rmdirs; |
220 | atomic_t num_renames; | 228 | atomic_t num_renames; |
221 | atomic_t num_t2renames; | 229 | atomic_t num_t2renames; |
230 | atomic_t num_ffirst; | ||
231 | atomic_t num_fnext; | ||
232 | atomic_t num_fclose; | ||
233 | atomic_t num_hardlinks; | ||
234 | atomic_t num_symlinks; | ||
235 | atomic_t num_locks; | ||
236 | #ifdef CONFIG_CIFS_STATS2 | ||
237 | unsigned long long time_writes; | ||
238 | unsigned long long time_reads; | ||
239 | unsigned long long time_opens; | ||
240 | unsigned long long time_deletes; | ||
241 | unsigned long long time_closes; | ||
242 | unsigned long long time_mkdirs; | ||
243 | unsigned long long time_rmdirs; | ||
244 | unsigned long long time_renames; | ||
245 | unsigned long long time_t2renames; | ||
246 | unsigned long long time_ffirst; | ||
247 | unsigned long long time_fnext; | ||
248 | unsigned long long time_fclose; | ||
249 | #endif /* CONFIG_CIFS_STATS2 */ | ||
222 | __u64 bytes_read; | 250 | __u64 bytes_read; |
223 | __u64 bytes_written; | 251 | __u64 bytes_written; |
224 | spinlock_t stat_lock; | 252 | spinlock_t stat_lock; |
225 | #endif | 253 | #endif /* CONFIG_CIFS_STATS */ |
226 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; | 254 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; |
227 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ | 255 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ |
228 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; | 256 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; |
229 | unsigned retry:1; | 257 | unsigned retry:1; |
258 | unsigned nocase:1; | ||
230 | /* BB add field for back pointer to sb struct? */ | 259 | /* BB add field for back pointer to sb struct? */ |
231 | }; | 260 | }; |
232 | 261 | ||
@@ -270,6 +299,7 @@ struct cifsFileInfo { | |||
270 | struct inode * pInode; /* needed for oplock break */ | 299 | struct inode * pInode; /* needed for oplock break */ |
271 | unsigned closePend:1; /* file is marked to close */ | 300 | unsigned closePend:1; /* file is marked to close */ |
272 | unsigned invalidHandle:1; /* file closed via session abend */ | 301 | unsigned invalidHandle:1; /* file closed via session abend */ |
302 | atomic_t wrtPending; /* handle in use - defer close */ | ||
273 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | 303 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ |
274 | char * search_resume_name; /* BB removeme BB */ | 304 | char * search_resume_name; /* BB removeme BB */ |
275 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ | 305 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ |
@@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb) | |||
306 | return sb->s_fs_info; | 336 | return sb->s_fs_info; |
307 | } | 337 | } |
308 | 338 | ||
339 | static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) | ||
340 | { | ||
341 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | ||
342 | return '/'; | ||
343 | else | ||
344 | return '\\'; | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_CIFS_STATS | ||
348 | #define cifs_stats_inc atomic_inc | ||
349 | |||
350 | static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon, | ||
351 | unsigned int bytes) | ||
352 | { | ||
353 | if (bytes) { | ||
354 | spin_lock(&tcon->stat_lock); | ||
355 | tcon->bytes_written += bytes; | ||
356 | spin_unlock(&tcon->stat_lock); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | ||
361 | unsigned int bytes) | ||
362 | { | ||
363 | spin_lock(&tcon->stat_lock); | ||
364 | tcon->bytes_read += bytes; | ||
365 | spin_unlock(&tcon->stat_lock); | ||
366 | } | ||
367 | #else | ||
368 | |||
369 | #define cifs_stats_inc(field) do {} while(0) | ||
370 | #define cifs_stats_bytes_written(tcon, bytes) do {} while(0) | ||
371 | #define cifs_stats_bytes_read(tcon, bytes) do {} while(0) | ||
372 | |||
373 | #endif | ||
309 | 374 | ||
310 | /* one of these for every pending CIFS request to the server */ | 375 | /* one of these for every pending CIFS request to the server */ |
311 | struct mid_q_entry { | 376 | struct mid_q_entry { |
@@ -313,7 +378,11 @@ struct mid_q_entry { | |||
313 | __u16 mid; /* multiplex id */ | 378 | __u16 mid; /* multiplex id */ |
314 | __u16 pid; /* process id */ | 379 | __u16 pid; /* process id */ |
315 | __u32 sequence_number; /* for CIFS signing */ | 380 | __u32 sequence_number; /* for CIFS signing */ |
316 | struct timeval when_sent; /* time when smb sent */ | 381 | unsigned long when_alloc; /* when mid was created */ |
382 | #ifdef CONFIG_CIFS_STATS2 | ||
383 | unsigned long when_sent; /* time when smb send finished */ | ||
384 | unsigned long when_received; /* when demux complete (taken off wire) */ | ||
385 | #endif | ||
317 | struct cifsSesInfo *ses; /* smb was sent to this server */ | 386 | struct cifsSesInfo *ses; /* smb was sent to this server */ |
318 | struct task_struct *tsk; /* task waiting for response */ | 387 | struct task_struct *tsk; /* task waiting for response */ |
319 | struct smb_hdr *resp_buf; /* response buffer */ | 388 | struct smb_hdr *resp_buf; /* response buffer */ |
@@ -331,6 +400,20 @@ struct oplock_q_entry { | |||
331 | __u16 netfid; | 400 | __u16 netfid; |
332 | }; | 401 | }; |
333 | 402 | ||
403 | /* for pending dnotify requests */ | ||
404 | struct dir_notify_req { | ||
405 | struct list_head lhead; | ||
406 | __le16 Pid; | ||
407 | __le16 PidHigh; | ||
408 | __u16 Mid; | ||
409 | __u16 Tid; | ||
410 | __u16 Uid; | ||
411 | __u16 netfid; | ||
412 | __u32 filter; /* CompletionFilter (for multishot) */ | ||
413 | int multishot; | ||
414 | struct file * pfile; | ||
415 | }; | ||
416 | |||
334 | #define MID_FREE 0 | 417 | #define MID_FREE 0 |
335 | #define MID_REQUEST_ALLOCATED 1 | 418 | #define MID_REQUEST_ALLOCATED 1 |
336 | #define MID_REQUEST_SUBMITTED 2 | 419 | #define MID_REQUEST_SUBMITTED 2 |
@@ -399,6 +482,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ | |||
399 | 482 | ||
400 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 483 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; |
401 | 484 | ||
485 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ | ||
486 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */ | ||
487 | |||
402 | /* | 488 | /* |
403 | * Global transaction id (XID) information | 489 | * Global transaction id (XID) information |
404 | */ | 490 | */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index aede6a813167..48a05b9df7eb 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -36,9 +36,11 @@ | |||
36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ | 36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ |
37 | #define SMB_COM_DELETE 0x06 /* trivial response */ | 37 | #define SMB_COM_DELETE 0x06 /* trivial response */ |
38 | #define SMB_COM_RENAME 0x07 /* trivial response */ | 38 | #define SMB_COM_RENAME 0x07 /* trivial response */ |
39 | #define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */ | ||
39 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | 40 | #define SMB_COM_SETATTR 0x09 /* trivial response */ |
40 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | 41 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ |
41 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | 42 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ |
43 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ | ||
42 | #define SMB_COM_READ_ANDX 0x2E | 44 | #define SMB_COM_READ_ANDX 0x2E |
43 | #define SMB_COM_WRITE_ANDX 0x2F | 45 | #define SMB_COM_WRITE_ANDX 0x2F |
44 | #define SMB_COM_TRANSACTION2 0x32 | 46 | #define SMB_COM_TRANSACTION2 0x32 |
@@ -52,6 +54,7 @@ | |||
52 | #define SMB_COM_NT_TRANSACT 0xA0 | 54 | #define SMB_COM_NT_TRANSACT 0xA0 |
53 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 | 55 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 |
54 | #define SMB_COM_NT_CREATE_ANDX 0xA2 | 56 | #define SMB_COM_NT_CREATE_ANDX 0xA2 |
57 | #define SMB_COM_NT_CANCEL 0xA4 /* no response */ | ||
55 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ | 58 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ |
56 | 59 | ||
57 | /* Transact2 subcommand codes */ | 60 | /* Transact2 subcommand codes */ |
@@ -59,6 +62,7 @@ | |||
59 | #define TRANS2_FIND_FIRST 0x01 | 62 | #define TRANS2_FIND_FIRST 0x01 |
60 | #define TRANS2_FIND_NEXT 0x02 | 63 | #define TRANS2_FIND_NEXT 0x02 |
61 | #define TRANS2_QUERY_FS_INFORMATION 0x03 | 64 | #define TRANS2_QUERY_FS_INFORMATION 0x03 |
65 | #define TRANS2_SET_FS_INFORMATION 0x04 | ||
62 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 | 66 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 |
63 | #define TRANS2_SET_PATH_INFORMATION 0x06 | 67 | #define TRANS2_SET_PATH_INFORMATION 0x06 |
64 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 | 68 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 |
@@ -76,7 +80,7 @@ | |||
76 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 | 80 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 |
77 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 | 81 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 |
78 | 82 | ||
79 | #define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */ | 83 | #define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ |
80 | 84 | ||
81 | /* internal cifs vfs structures */ | 85 | /* internal cifs vfs structures */ |
82 | /***************************************************************** | 86 | /***************************************************************** |
@@ -129,10 +133,11 @@ | |||
129 | /* | 133 | /* |
130 | * SMB flag definitions | 134 | * SMB flag definitions |
131 | */ | 135 | */ |
132 | #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */ | 136 | #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */ |
133 | #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ | 137 | #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ |
134 | #define SMBFLG_RSVD 0x04 | 138 | #define SMBFLG_RSVD 0x04 |
135 | #define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */ | 139 | #define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off |
140 | implies case sensitive file handling request) */ | ||
136 | #define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ | 141 | #define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ |
137 | #define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ | 142 | #define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ |
138 | #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ | 143 | #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ |
@@ -141,7 +146,8 @@ | |||
141 | /* | 146 | /* |
142 | * SMB flag2 definitions | 147 | * SMB flag2 definitions |
143 | */ | 148 | */ |
144 | #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) path names in response */ | 149 | #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) |
150 | path names in response */ | ||
145 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) | 151 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) |
146 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) | 152 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) |
147 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) | 153 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) |
@@ -160,32 +166,32 @@ | |||
160 | * file and can have any suitable combination of the following values: | 166 | * file and can have any suitable combination of the following values: |
161 | */ | 167 | */ |
162 | 168 | ||
163 | #define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ | 169 | #define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ |
164 | #define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ | 170 | #define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ |
165 | #define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ | 171 | #define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ |
166 | #define FILE_READ_EA 0x00000008 /* Extended attributes associated */ | 172 | #define FILE_READ_EA 0x00000008 /* Extended attributes associated */ |
167 | /* with the file can be read */ | 173 | /* with the file can be read */ |
168 | #define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ | 174 | #define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ |
169 | /* with the file can be written */ | 175 | /* with the file can be written */ |
170 | #define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ | 176 | #define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ |
171 | /* the file using system paging I/O */ | 177 | /* the file using system paging I/O */ |
172 | #define FILE_DELETE_CHILD 0x00000040 | 178 | #define FILE_DELETE_CHILD 0x00000040 |
173 | #define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ | 179 | #define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ |
174 | /* file can be read */ | 180 | /* file can be read */ |
175 | #define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ | 181 | #define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ |
176 | /* file can be written */ | 182 | /* file can be written */ |
177 | #define DELETE 0x00010000 /* The file can be deleted */ | 183 | #define DELETE 0x00010000 /* The file can be deleted */ |
178 | #define READ_CONTROL 0x00020000 /* The access control list and */ | 184 | #define READ_CONTROL 0x00020000 /* The access control list and */ |
179 | /* ownership associated with the */ | 185 | /* ownership associated with the */ |
180 | /* file can be read */ | 186 | /* file can be read */ |
181 | #define WRITE_DAC 0x00040000 /* The access control list and */ | 187 | #define WRITE_DAC 0x00040000 /* The access control list and */ |
182 | /* ownership associated with the */ | 188 | /* ownership associated with the */ |
183 | /* file can be written. */ | 189 | /* file can be written. */ |
184 | #define WRITE_OWNER 0x00080000 /* Ownership information associated */ | 190 | #define WRITE_OWNER 0x00080000 /* Ownership information associated */ |
185 | /* with the file can be written */ | 191 | /* with the file can be written */ |
186 | #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ | 192 | #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ |
187 | /* synchronize with the completion */ | 193 | /* synchronize with the completion */ |
188 | /* of an input/output request */ | 194 | /* of an input/output request */ |
189 | #define GENERIC_ALL 0x10000000 | 195 | #define GENERIC_ALL 0x10000000 |
190 | #define GENERIC_EXECUTE 0x20000000 | 196 | #define GENERIC_EXECUTE 0x20000000 |
191 | #define GENERIC_WRITE 0x40000000 | 197 | #define GENERIC_WRITE 0x40000000 |
@@ -193,7 +199,7 @@ | |||
193 | /* In summary - Relevant file */ | 199 | /* In summary - Relevant file */ |
194 | /* access flags from CIFS are */ | 200 | /* access flags from CIFS are */ |
195 | /* file_read_data, file_write_data */ | 201 | /* file_read_data, file_write_data */ |
196 | /* file_execute, file_read_attributes */ | 202 | /* file_execute, file_read_attributes*/ |
197 | /* write_dac, and delete. */ | 203 | /* write_dac, and delete. */ |
198 | 204 | ||
199 | /* | 205 | /* |
@@ -238,7 +244,8 @@ | |||
238 | #define ATTR_SPARSE 0x0200 | 244 | #define ATTR_SPARSE 0x0200 |
239 | #define ATTR_REPARSE 0x0400 | 245 | #define ATTR_REPARSE 0x0400 |
240 | #define ATTR_COMPRESSED 0x0800 | 246 | #define ATTR_COMPRESSED 0x0800 |
241 | #define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */ | 247 | #define ATTR_OFFLINE 0x1000 /* ie file not immediately available - |
248 | on offline storage */ | ||
242 | #define ATTR_NOT_CONTENT_INDEXED 0x2000 | 249 | #define ATTR_NOT_CONTENT_INDEXED 0x2000 |
243 | #define ATTR_ENCRYPTED 0x4000 | 250 | #define ATTR_ENCRYPTED 0x4000 |
244 | #define ATTR_POSIX_SEMANTICS 0x01000000 | 251 | #define ATTR_POSIX_SEMANTICS 0x01000000 |
@@ -267,10 +274,18 @@ | |||
267 | /* CreateOptions */ | 274 | /* CreateOptions */ |
268 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ | 275 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ |
269 | #define CREATE_WRITE_THROUGH 0x00000002 | 276 | #define CREATE_WRITE_THROUGH 0x00000002 |
270 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | 277 | #define CREATE_SEQUENTIAL 0x00000004 |
278 | #define CREATE_SYNC_ALERT 0x00000010 | ||
279 | #define CREATE_ASYNC_ALERT 0x00000020 | ||
280 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | ||
281 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 | ||
282 | #define CREATE_EIGHT_DOT_THREE 0x00000400 | ||
271 | #define CREATE_RANDOM_ACCESS 0x00000800 | 283 | #define CREATE_RANDOM_ACCESS 0x00000800 |
272 | #define CREATE_DELETE_ON_CLOSE 0x00001000 | 284 | #define CREATE_DELETE_ON_CLOSE 0x00001000 |
285 | #define CREATE_OPEN_BY_ID 0x00002000 | ||
273 | #define OPEN_REPARSE_POINT 0x00200000 | 286 | #define OPEN_REPARSE_POINT 0x00200000 |
287 | #define CREATE_OPTIONS_MASK 0x007FFFFF | ||
288 | #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ | ||
274 | 289 | ||
275 | /* ImpersonationLevel flags */ | 290 | /* ImpersonationLevel flags */ |
276 | #define SECURITY_ANONYMOUS 0 | 291 | #define SECURITY_ANONYMOUS 0 |
@@ -297,10 +312,10 @@ | |||
297 | #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ | 312 | #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ |
298 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ | 313 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ |
299 | 314 | ||
300 | #pragma pack(1) | ||
301 | |||
302 | struct smb_hdr { | 315 | struct smb_hdr { |
303 | __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */ | 316 | __u32 smb_buf_length; /* big endian on wire *//* BB length is only two |
317 | or three bytes - with one or two byte type preceding it that are | ||
318 | zero - we could mask the type byte off just in case BB */ | ||
304 | __u8 Protocol[4]; | 319 | __u8 Protocol[4]; |
305 | __u8 Command; | 320 | __u8 Command; |
306 | union { | 321 | union { |
@@ -308,9 +323,9 @@ struct smb_hdr { | |||
308 | __u8 ErrorClass; | 323 | __u8 ErrorClass; |
309 | __u8 Reserved; | 324 | __u8 Reserved; |
310 | __le16 Error; | 325 | __le16 Error; |
311 | } DosError; | 326 | } __attribute__((packed)) DosError; |
312 | __le32 CifsError; | 327 | __le32 CifsError; |
313 | } Status; | 328 | } __attribute__((packed)) Status; |
314 | __u8 Flags; | 329 | __u8 Flags; |
315 | __le16 Flags2; /* note: le */ | 330 | __le16 Flags2; /* note: le */ |
316 | __le16 PidHigh; | 331 | __le16 PidHigh; |
@@ -318,16 +333,16 @@ struct smb_hdr { | |||
318 | struct { | 333 | struct { |
319 | __le32 SequenceNumber; /* le */ | 334 | __le32 SequenceNumber; /* le */ |
320 | __u32 Reserved; /* zero */ | 335 | __u32 Reserved; /* zero */ |
321 | } Sequence; | 336 | } __attribute__((packed)) Sequence; |
322 | __u8 SecuritySignature[8]; /* le */ | 337 | __u8 SecuritySignature[8]; /* le */ |
323 | } Signature; | 338 | } __attribute__((packed)) Signature; |
324 | __u8 pad[2]; | 339 | __u8 pad[2]; |
325 | __u16 Tid; | 340 | __u16 Tid; |
326 | __le16 Pid; | 341 | __le16 Pid; |
327 | __u16 Uid; | 342 | __u16 Uid; |
328 | __u16 Mid; | 343 | __u16 Mid; |
329 | __u8 WordCount; | 344 | __u8 WordCount; |
330 | }; | 345 | } __attribute__((packed)); |
331 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | 346 | /* given a pointer to an smb_hdr retrieve the value of byte count */ |
332 | #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) | 347 | #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) |
333 | #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) | 348 | #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) |
@@ -379,7 +394,7 @@ typedef struct negotiate_req { | |||
379 | struct smb_hdr hdr; /* wct = 0 */ | 394 | struct smb_hdr hdr; /* wct = 0 */ |
380 | __le16 ByteCount; | 395 | __le16 ByteCount; |
381 | unsigned char DialectsArray[1]; | 396 | unsigned char DialectsArray[1]; |
382 | } NEGOTIATE_REQ; | 397 | } __attribute__((packed)) NEGOTIATE_REQ; |
383 | 398 | ||
384 | typedef struct negotiate_rsp { | 399 | typedef struct negotiate_rsp { |
385 | struct smb_hdr hdr; /* wct = 17 */ | 400 | struct smb_hdr hdr; /* wct = 17 */ |
@@ -397,16 +412,16 @@ typedef struct negotiate_rsp { | |||
397 | __u8 EncryptionKeyLength; | 412 | __u8 EncryptionKeyLength; |
398 | __u16 ByteCount; | 413 | __u16 ByteCount; |
399 | union { | 414 | union { |
400 | unsigned char EncryptionKey[1]; /* if cap extended security is off */ | 415 | unsigned char EncryptionKey[1]; /* cap extended security off */ |
401 | /* followed by Domain name - if extended security is off */ | 416 | /* followed by Domain name - if extended security is off */ |
402 | /* followed by 16 bytes of server GUID */ | 417 | /* followed by 16 bytes of server GUID */ |
403 | /* followed by security blob if cap_extended_security negotiated */ | 418 | /* then security blob if cap_extended_security negotiated */ |
404 | struct { | 419 | struct { |
405 | unsigned char GUID[16]; | 420 | unsigned char GUID[16]; |
406 | unsigned char SecurityBlob[1]; | 421 | unsigned char SecurityBlob[1]; |
407 | } extended_response; | 422 | } __attribute__((packed)) extended_response; |
408 | } u; | 423 | } __attribute__((packed)) u; |
409 | } NEGOTIATE_RSP; | 424 | } __attribute__((packed)) NEGOTIATE_RSP; |
410 | 425 | ||
411 | /* SecurityMode bits */ | 426 | /* SecurityMode bits */ |
412 | #define SECMODE_USER 0x01 /* off indicates share level security */ | 427 | #define SECMODE_USER 0x01 /* off indicates share level security */ |
@@ -452,7 +467,8 @@ typedef union smb_com_session_setup_andx { | |||
452 | unsigned char SecurityBlob[1]; /* followed by */ | 467 | unsigned char SecurityBlob[1]; /* followed by */ |
453 | /* STRING NativeOS */ | 468 | /* STRING NativeOS */ |
454 | /* STRING NativeLanMan */ | 469 | /* STRING NativeLanMan */ |
455 | } req; /* NTLM request format (with extended security */ | 470 | } __attribute__((packed)) req; /* NTLM request format (with |
471 | extended security */ | ||
456 | 472 | ||
457 | struct { /* request format */ | 473 | struct { /* request format */ |
458 | struct smb_hdr hdr; /* wct = 13 */ | 474 | struct smb_hdr hdr; /* wct = 13 */ |
@@ -463,18 +479,19 @@ typedef union smb_com_session_setup_andx { | |||
463 | __le16 MaxMpxCount; | 479 | __le16 MaxMpxCount; |
464 | __le16 VcNumber; | 480 | __le16 VcNumber; |
465 | __u32 SessionKey; | 481 | __u32 SessionKey; |
466 | __le16 CaseInsensitivePasswordLength; /* ASCII password length */ | 482 | __le16 CaseInsensitivePasswordLength; /* ASCII password len */ |
467 | __le16 CaseSensitivePasswordLength; /* Unicode password length */ | 483 | __le16 CaseSensitivePasswordLength; /* Unicode password length*/ |
468 | __u32 Reserved; /* see below */ | 484 | __u32 Reserved; /* see below */ |
469 | __le32 Capabilities; | 485 | __le32 Capabilities; |
470 | __le16 ByteCount; | 486 | __le16 ByteCount; |
471 | unsigned char CaseInsensitivePassword[1]; /* followed by: */ | 487 | unsigned char CaseInsensitivePassword[1]; /* followed by: */ |
472 | /* unsigned char * CaseSensitivePassword; */ | 488 | /* unsigned char * CaseSensitivePassword; */ |
473 | /* STRING AccountName */ | 489 | /* STRING AccountName */ |
474 | /* STRING PrimaryDomain */ | 490 | /* STRING PrimaryDomain */ |
475 | /* STRING NativeOS */ | 491 | /* STRING NativeOS */ |
476 | /* STRING NativeLanMan */ | 492 | /* STRING NativeLanMan */ |
477 | } req_no_secext; /* NTLM request format (without extended security */ | 493 | } __attribute__((packed)) req_no_secext; /* NTLM request format (without |
494 | extended security */ | ||
478 | 495 | ||
479 | struct { /* default (NTLM) response format */ | 496 | struct { /* default (NTLM) response format */ |
480 | struct smb_hdr hdr; /* wct = 4 */ | 497 | struct smb_hdr hdr; /* wct = 4 */ |
@@ -488,7 +505,7 @@ typedef union smb_com_session_setup_andx { | |||
488 | /* unsigned char * NativeOS; */ | 505 | /* unsigned char * NativeOS; */ |
489 | /* unsigned char * NativeLanMan; */ | 506 | /* unsigned char * NativeLanMan; */ |
490 | /* unsigned char * PrimaryDomain; */ | 507 | /* unsigned char * PrimaryDomain; */ |
491 | } resp; /* NTLM response format (with or without extended security */ | 508 | } __attribute__((packed)) resp; /* NTLM response format (with or without extended security */ |
492 | 509 | ||
493 | struct { /* request format */ | 510 | struct { /* request format */ |
494 | struct smb_hdr hdr; /* wct = 10 */ | 511 | struct smb_hdr hdr; /* wct = 10 */ |
@@ -507,7 +524,7 @@ typedef union smb_com_session_setup_andx { | |||
507 | /* STRING PrimaryDomain */ | 524 | /* STRING PrimaryDomain */ |
508 | /* STRING NativeOS */ | 525 | /* STRING NativeOS */ |
509 | /* STRING NativeLanMan */ | 526 | /* STRING NativeLanMan */ |
510 | } old_req; /* pre-NTLM (LANMAN2.1) request format */ | 527 | } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) request format */ |
511 | 528 | ||
512 | struct { /* default (NTLM) response format */ | 529 | struct { /* default (NTLM) response format */ |
513 | struct smb_hdr hdr; /* wct = 3 */ | 530 | struct smb_hdr hdr; /* wct = 3 */ |
@@ -519,8 +536,8 @@ typedef union smb_com_session_setup_andx { | |||
519 | unsigned char NativeOS[1]; /* followed by */ | 536 | unsigned char NativeOS[1]; /* followed by */ |
520 | /* unsigned char * NativeLanMan; */ | 537 | /* unsigned char * NativeLanMan; */ |
521 | /* unsigned char * PrimaryDomain; */ | 538 | /* unsigned char * PrimaryDomain; */ |
522 | } old_resp; /* pre-NTLM (LANMAN2.1) response format */ | 539 | } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response format */ |
523 | } SESSION_SETUP_ANDX; | 540 | } __attribute__((packed)) SESSION_SETUP_ANDX; |
524 | 541 | ||
525 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" | 542 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" |
526 | 543 | ||
@@ -530,7 +547,8 @@ typedef union smb_com_session_setup_andx { | |||
530 | #define CAP_NT_SMBS 0x00000010 | 547 | #define CAP_NT_SMBS 0x00000010 |
531 | #define CAP_STATUS32 0x00000040 | 548 | #define CAP_STATUS32 0x00000040 |
532 | #define CAP_LEVEL_II_OPLOCKS 0x00000080 | 549 | #define CAP_LEVEL_II_OPLOCKS 0x00000080 |
533 | #define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */ | 550 | #define CAP_NT_FIND 0x00000200 /* reserved should be zero |
551 | (because NT_SMBs implies the same thing?) */ | ||
534 | #define CAP_BULK_TRANSFER 0x20000000 | 552 | #define CAP_BULK_TRANSFER 0x20000000 |
535 | #define CAP_EXTENDED_SECURITY 0x80000000 | 553 | #define CAP_EXTENDED_SECURITY 0x80000000 |
536 | 554 | ||
@@ -548,7 +566,7 @@ typedef struct smb_com_tconx_req { | |||
548 | unsigned char Password[1]; /* followed by */ | 566 | unsigned char Password[1]; /* followed by */ |
549 | /* STRING Path *//* \\server\share name */ | 567 | /* STRING Path *//* \\server\share name */ |
550 | /* STRING Service */ | 568 | /* STRING Service */ |
551 | } TCONX_REQ; | 569 | } __attribute__((packed)) TCONX_REQ; |
552 | 570 | ||
553 | typedef struct smb_com_tconx_rsp { | 571 | typedef struct smb_com_tconx_rsp { |
554 | struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ | 572 | struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ |
@@ -559,13 +577,14 @@ typedef struct smb_com_tconx_rsp { | |||
559 | __u16 ByteCount; | 577 | __u16 ByteCount; |
560 | unsigned char Service[1]; /* always ASCII, not Unicode */ | 578 | unsigned char Service[1]; /* always ASCII, not Unicode */ |
561 | /* STRING NativeFileSystem */ | 579 | /* STRING NativeFileSystem */ |
562 | } TCONX_RSP; | 580 | } __attribute__((packed)) TCONX_RSP; |
563 | 581 | ||
564 | /* tree connect Flags */ | 582 | /* tree connect Flags */ |
565 | #define DISCONNECT_TID 0x0001 | 583 | #define DISCONNECT_TID 0x0001 |
566 | #define TCON_EXTENDED_SECINFO 0x0008 | 584 | #define TCON_EXTENDED_SECINFO 0x0008 |
567 | /* OptionalSupport bits */ | 585 | /* OptionalSupport bits */ |
568 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */ | 586 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* "must have" directory search bits |
587 | (exclusive searches supported) */ | ||
569 | #define SMB_SHARE_IS_IN_DFS 0x0002 | 588 | #define SMB_SHARE_IS_IN_DFS 0x0002 |
570 | 589 | ||
571 | typedef struct smb_com_logoff_andx_req { | 590 | typedef struct smb_com_logoff_andx_req { |
@@ -574,7 +593,7 @@ typedef struct smb_com_logoff_andx_req { | |||
574 | __u8 AndXReserved; | 593 | __u8 AndXReserved; |
575 | __u16 AndXOffset; | 594 | __u16 AndXOffset; |
576 | __u16 ByteCount; | 595 | __u16 ByteCount; |
577 | } LOGOFF_ANDX_REQ; | 596 | } __attribute__((packed)) LOGOFF_ANDX_REQ; |
578 | 597 | ||
579 | typedef struct smb_com_logoff_andx_rsp { | 598 | typedef struct smb_com_logoff_andx_rsp { |
580 | struct smb_hdr hdr; /* wct = 2 */ | 599 | struct smb_hdr hdr; /* wct = 2 */ |
@@ -582,38 +601,39 @@ typedef struct smb_com_logoff_andx_rsp { | |||
582 | __u8 AndXReserved; | 601 | __u8 AndXReserved; |
583 | __u16 AndXOffset; | 602 | __u16 AndXOffset; |
584 | __u16 ByteCount; | 603 | __u16 ByteCount; |
585 | } LOGOFF_ANDX_RSP; | 604 | } __attribute__((packed)) LOGOFF_ANDX_RSP; |
586 | 605 | ||
587 | typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ | 606 | typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ |
588 | struct { | 607 | struct { |
589 | struct smb_hdr hdr; /* wct = 0 */ | 608 | struct smb_hdr hdr; /* wct = 0 */ |
590 | __u16 ByteCount; /* bcc = 0 */ | 609 | __u16 ByteCount; /* bcc = 0 */ |
591 | } req; | 610 | } __attribute__((packed)) req; |
592 | struct { | 611 | struct { |
593 | struct smb_hdr hdr; /* wct = 0 */ | 612 | struct smb_hdr hdr; /* wct = 0 */ |
594 | __u16 ByteCount; /* bcc = 0 */ | 613 | __u16 ByteCount; /* bcc = 0 */ |
595 | } resp; | 614 | } __attribute__((packed)) resp; |
596 | } TREE_DISCONNECT; | 615 | } __attribute__((packed)) TREE_DISCONNECT; |
597 | 616 | ||
598 | typedef struct smb_com_close_req { | 617 | typedef struct smb_com_close_req { |
599 | struct smb_hdr hdr; /* wct = 3 */ | 618 | struct smb_hdr hdr; /* wct = 3 */ |
600 | __u16 FileID; | 619 | __u16 FileID; |
601 | __u32 LastWriteTime; /* should be zero */ | 620 | __u32 LastWriteTime; /* should be zero */ |
602 | __u16 ByteCount; /* 0 */ | 621 | __u16 ByteCount; /* 0 */ |
603 | } CLOSE_REQ; | 622 | } __attribute__((packed)) CLOSE_REQ; |
604 | 623 | ||
605 | typedef struct smb_com_close_rsp { | 624 | typedef struct smb_com_close_rsp { |
606 | struct smb_hdr hdr; /* wct = 0 */ | 625 | struct smb_hdr hdr; /* wct = 0 */ |
607 | __u16 ByteCount; /* bct = 0 */ | 626 | __u16 ByteCount; /* bct = 0 */ |
608 | } CLOSE_RSP; | 627 | } __attribute__((packed)) CLOSE_RSP; |
609 | 628 | ||
610 | typedef struct smb_com_findclose_req { | 629 | typedef struct smb_com_findclose_req { |
611 | struct smb_hdr hdr; /* wct = 1 */ | 630 | struct smb_hdr hdr; /* wct = 1 */ |
612 | __u16 FileID; | 631 | __u16 FileID; |
613 | __u16 ByteCount; /* 0 */ | 632 | __u16 ByteCount; /* 0 */ |
614 | } FINDCLOSE_REQ; | 633 | } __attribute__((packed)) FINDCLOSE_REQ; |
615 | 634 | ||
616 | /* OpenFlags */ | 635 | /* OpenFlags */ |
636 | #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ | ||
617 | #define REQ_OPLOCK 0x00000002 | 637 | #define REQ_OPLOCK 0x00000002 |
618 | #define REQ_BATCHOPLOCK 0x00000004 | 638 | #define REQ_BATCHOPLOCK 0x00000004 |
619 | #define REQ_OPENDIRONLY 0x00000008 | 639 | #define REQ_OPENDIRONLY 0x00000008 |
@@ -637,7 +657,7 @@ typedef struct smb_com_open_req { /* also handles create */ | |||
637 | __u8 SecurityFlags; | 657 | __u8 SecurityFlags; |
638 | __le16 ByteCount; | 658 | __le16 ByteCount; |
639 | char fileName[1]; | 659 | char fileName[1]; |
640 | } OPEN_REQ; | 660 | } __attribute__((packed)) OPEN_REQ; |
641 | 661 | ||
642 | /* open response: oplock levels */ | 662 | /* open response: oplock levels */ |
643 | #define OPLOCK_NONE 0 | 663 | #define OPLOCK_NONE 0 |
@@ -667,7 +687,63 @@ typedef struct smb_com_open_rsp { | |||
667 | __le16 DeviceState; | 687 | __le16 DeviceState; |
668 | __u8 DirectoryFlag; | 688 | __u8 DirectoryFlag; |
669 | __u16 ByteCount; /* bct = 0 */ | 689 | __u16 ByteCount; /* bct = 0 */ |
670 | } OPEN_RSP; | 690 | } __attribute__((packed)) OPEN_RSP; |
691 | |||
692 | /* format of legacy open request */ | ||
693 | typedef struct smb_com_openx_req { | ||
694 | struct smb_hdr hdr; /* wct = 15 */ | ||
695 | __u8 AndXCommand; | ||
696 | __u8 AndXReserved; | ||
697 | __le16 AndXOffset; | ||
698 | __le16 OpenFlags; | ||
699 | __le16 Mode; | ||
700 | __le16 Sattr; /* search attributes */ | ||
701 | __le16 FileAttributes; /* dos attrs */ | ||
702 | __le32 CreateTime; /* os2 format */ | ||
703 | __le16 OpenFunction; | ||
704 | __le32 EndOfFile; | ||
705 | __le32 Timeout; | ||
706 | __le32 Reserved; | ||
707 | __le16 ByteCount; /* file name follows */ | ||
708 | char fileName[1]; | ||
709 | } __attribute__((packed)) OPENX_REQ; | ||
710 | |||
711 | typedef struct smb_com_openx_rsp { | ||
712 | struct smb_hdr hdr; /* wct = 15 */ | ||
713 | __u8 AndXCommand; | ||
714 | __u8 AndXReserved; | ||
715 | __le16 AndXOffset; | ||
716 | __u16 Fid; | ||
717 | __le16 FileAttributes; | ||
718 | __le32 LastWriteTime; /* os2 format */ | ||
719 | __le32 EndOfFile; | ||
720 | __le16 Access; | ||
721 | __le16 FileType; | ||
722 | __le16 IPCState; | ||
723 | __le16 Action; | ||
724 | __u32 FileId; | ||
725 | __u16 Reserved; | ||
726 | __u16 ByteCount; | ||
727 | } __attribute__((packed)) OPENX_RSP; | ||
728 | |||
729 | /* Legacy write request for older servers */ | ||
730 | typedef struct smb_com_writex_req { | ||
731 | struct smb_hdr hdr; /* wct = 12 */ | ||
732 | __u8 AndXCommand; | ||
733 | __u8 AndXReserved; | ||
734 | __le16 AndXOffset; | ||
735 | __u16 Fid; | ||
736 | __le32 OffsetLow; | ||
737 | __u32 Reserved; /* Timeout */ | ||
738 | __le16 WriteMode; /* 1 = write through */ | ||
739 | __le16 Remaining; | ||
740 | __le16 Reserved2; | ||
741 | __le16 DataLengthLow; | ||
742 | __le16 DataOffset; | ||
743 | __le16 ByteCount; | ||
744 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | ||
745 | char Data[0]; | ||
746 | } __attribute__((packed)) WRITEX_REQ; | ||
671 | 747 | ||
672 | typedef struct smb_com_write_req { | 748 | typedef struct smb_com_write_req { |
673 | struct smb_hdr hdr; /* wct = 14 */ | 749 | struct smb_hdr hdr; /* wct = 14 */ |
@@ -686,7 +762,7 @@ typedef struct smb_com_write_req { | |||
686 | __le16 ByteCount; | 762 | __le16 ByteCount; |
687 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | 763 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ |
688 | char Data[0]; | 764 | char Data[0]; |
689 | } WRITE_REQ; | 765 | } __attribute__((packed)) WRITE_REQ; |
690 | 766 | ||
691 | typedef struct smb_com_write_rsp { | 767 | typedef struct smb_com_write_rsp { |
692 | struct smb_hdr hdr; /* wct = 6 */ | 768 | struct smb_hdr hdr; /* wct = 6 */ |
@@ -698,7 +774,22 @@ typedef struct smb_com_write_rsp { | |||
698 | __le16 CountHigh; | 774 | __le16 CountHigh; |
699 | __u16 Reserved; | 775 | __u16 Reserved; |
700 | __u16 ByteCount; | 776 | __u16 ByteCount; |
701 | } WRITE_RSP; | 777 | } __attribute__((packed)) WRITE_RSP; |
778 | |||
779 | /* legacy read request for older servers */ | ||
780 | typedef struct smb_com_readx_req { | ||
781 | struct smb_hdr hdr; /* wct = 10 */ | ||
782 | __u8 AndXCommand; | ||
783 | __u8 AndXReserved; | ||
784 | __le16 AndXOffset; | ||
785 | __u16 Fid; | ||
786 | __le32 OffsetLow; | ||
787 | __le16 MaxCount; | ||
788 | __le16 MinCount; /* obsolete */ | ||
789 | __le32 Reserved; | ||
790 | __le16 Remaining; | ||
791 | __le16 ByteCount; | ||
792 | } __attribute__((packed)) READX_REQ; | ||
702 | 793 | ||
703 | typedef struct smb_com_read_req { | 794 | typedef struct smb_com_read_req { |
704 | struct smb_hdr hdr; /* wct = 12 */ | 795 | struct smb_hdr hdr; /* wct = 12 */ |
@@ -713,7 +804,7 @@ typedef struct smb_com_read_req { | |||
713 | __le16 Remaining; | 804 | __le16 Remaining; |
714 | __le32 OffsetHigh; | 805 | __le32 OffsetHigh; |
715 | __le16 ByteCount; | 806 | __le16 ByteCount; |
716 | } READ_REQ; | 807 | } __attribute__((packed)) READ_REQ; |
717 | 808 | ||
718 | typedef struct smb_com_read_rsp { | 809 | typedef struct smb_com_read_rsp { |
719 | struct smb_hdr hdr; /* wct = 12 */ | 810 | struct smb_hdr hdr; /* wct = 12 */ |
@@ -730,7 +821,7 @@ typedef struct smb_com_read_rsp { | |||
730 | __u16 ByteCount; | 821 | __u16 ByteCount; |
731 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | 822 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ |
732 | char Data[1]; | 823 | char Data[1]; |
733 | } READ_RSP; | 824 | } __attribute__((packed)) READ_RSP; |
734 | 825 | ||
735 | typedef struct locking_andx_range { | 826 | typedef struct locking_andx_range { |
736 | __le16 Pid; | 827 | __le16 Pid; |
@@ -739,7 +830,7 @@ typedef struct locking_andx_range { | |||
739 | __le32 OffsetLow; | 830 | __le32 OffsetLow; |
740 | __le32 LengthHigh; | 831 | __le32 LengthHigh; |
741 | __le32 LengthLow; | 832 | __le32 LengthLow; |
742 | } LOCKING_ANDX_RANGE; | 833 | } __attribute__((packed)) LOCKING_ANDX_RANGE; |
743 | 834 | ||
744 | #define LOCKING_ANDX_SHARED_LOCK 0x01 | 835 | #define LOCKING_ANDX_SHARED_LOCK 0x01 |
745 | #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 | 836 | #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 |
@@ -760,7 +851,7 @@ typedef struct smb_com_lock_req { | |||
760 | __le16 NumberOfLocks; | 851 | __le16 NumberOfLocks; |
761 | __le16 ByteCount; | 852 | __le16 ByteCount; |
762 | LOCKING_ANDX_RANGE Locks[1]; | 853 | LOCKING_ANDX_RANGE Locks[1]; |
763 | } LOCK_REQ; | 854 | } __attribute__((packed)) LOCK_REQ; |
764 | 855 | ||
765 | 856 | ||
766 | typedef struct cifs_posix_lock { | 857 | typedef struct cifs_posix_lock { |
@@ -770,7 +861,7 @@ typedef struct cifs_posix_lock { | |||
770 | __le64 start; | 861 | __le64 start; |
771 | __le64 length; | 862 | __le64 length; |
772 | /* BB what about additional owner info to identify network client */ | 863 | /* BB what about additional owner info to identify network client */ |
773 | } CIFS_POSIX_LOCK; | 864 | } __attribute__((packed)) CIFS_POSIX_LOCK; |
774 | 865 | ||
775 | typedef struct smb_com_lock_rsp { | 866 | typedef struct smb_com_lock_rsp { |
776 | struct smb_hdr hdr; /* wct = 2 */ | 867 | struct smb_hdr hdr; /* wct = 2 */ |
@@ -778,7 +869,7 @@ typedef struct smb_com_lock_rsp { | |||
778 | __u8 AndXReserved; | 869 | __u8 AndXReserved; |
779 | __le16 AndXOffset; | 870 | __le16 AndXOffset; |
780 | __u16 ByteCount; | 871 | __u16 ByteCount; |
781 | } LOCK_RSP; | 872 | } __attribute__((packed)) LOCK_RSP; |
782 | 873 | ||
783 | typedef struct smb_com_rename_req { | 874 | typedef struct smb_com_rename_req { |
784 | struct smb_hdr hdr; /* wct = 1 */ | 875 | struct smb_hdr hdr; /* wct = 1 */ |
@@ -788,7 +879,7 @@ typedef struct smb_com_rename_req { | |||
788 | unsigned char OldFileName[1]; | 879 | unsigned char OldFileName[1]; |
789 | /* followed by __u8 BufferFormat2 */ | 880 | /* followed by __u8 BufferFormat2 */ |
790 | /* followed by NewFileName */ | 881 | /* followed by NewFileName */ |
791 | } RENAME_REQ; | 882 | } __attribute__((packed)) RENAME_REQ; |
792 | 883 | ||
793 | /* copy request flags */ | 884 | /* copy request flags */ |
794 | #define COPY_MUST_BE_FILE 0x0001 | 885 | #define COPY_MUST_BE_FILE 0x0001 |
@@ -808,7 +899,7 @@ typedef struct smb_com_copy_req { | |||
808 | unsigned char OldFileName[1]; | 899 | unsigned char OldFileName[1]; |
809 | /* followed by __u8 BufferFormat2 */ | 900 | /* followed by __u8 BufferFormat2 */ |
810 | /* followed by NewFileName string */ | 901 | /* followed by NewFileName string */ |
811 | } COPY_REQ; | 902 | } __attribute__((packed)) COPY_REQ; |
812 | 903 | ||
813 | typedef struct smb_com_copy_rsp { | 904 | typedef struct smb_com_copy_rsp { |
814 | struct smb_hdr hdr; /* wct = 1 */ | 905 | struct smb_hdr hdr; /* wct = 1 */ |
@@ -816,7 +907,7 @@ typedef struct smb_com_copy_rsp { | |||
816 | __u16 ByteCount; /* may be zero */ | 907 | __u16 ByteCount; /* may be zero */ |
817 | __u8 BufferFormat; /* 0x04 - only present if errored file follows */ | 908 | __u8 BufferFormat; /* 0x04 - only present if errored file follows */ |
818 | unsigned char ErrorFileName[1]; /* only present if error in copy */ | 909 | unsigned char ErrorFileName[1]; /* only present if error in copy */ |
819 | } COPY_RSP; | 910 | } __attribute__((packed)) COPY_RSP; |
820 | 911 | ||
821 | #define CREATE_HARD_LINK 0x103 | 912 | #define CREATE_HARD_LINK 0x103 |
822 | #define MOVEFILE_COPY_ALLOWED 0x0002 | 913 | #define MOVEFILE_COPY_ALLOWED 0x0002 |
@@ -832,12 +923,12 @@ typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ | |||
832 | unsigned char OldFileName[1]; | 923 | unsigned char OldFileName[1]; |
833 | /* followed by __u8 BufferFormat2 */ | 924 | /* followed by __u8 BufferFormat2 */ |
834 | /* followed by NewFileName */ | 925 | /* followed by NewFileName */ |
835 | } NT_RENAME_REQ; | 926 | } __attribute__((packed)) NT_RENAME_REQ; |
836 | 927 | ||
837 | typedef struct smb_com_rename_rsp { | 928 | typedef struct smb_com_rename_rsp { |
838 | struct smb_hdr hdr; /* wct = 0 */ | 929 | struct smb_hdr hdr; /* wct = 0 */ |
839 | __u16 ByteCount; /* bct = 0 */ | 930 | __u16 ByteCount; /* bct = 0 */ |
840 | } RENAME_RSP; | 931 | } __attribute__((packed)) RENAME_RSP; |
841 | 932 | ||
842 | typedef struct smb_com_delete_file_req { | 933 | typedef struct smb_com_delete_file_req { |
843 | struct smb_hdr hdr; /* wct = 1 */ | 934 | struct smb_hdr hdr; /* wct = 1 */ |
@@ -845,36 +936,52 @@ typedef struct smb_com_delete_file_req { | |||
845 | __le16 ByteCount; | 936 | __le16 ByteCount; |
846 | __u8 BufferFormat; /* 4 = ASCII */ | 937 | __u8 BufferFormat; /* 4 = ASCII */ |
847 | unsigned char fileName[1]; | 938 | unsigned char fileName[1]; |
848 | } DELETE_FILE_REQ; | 939 | } __attribute__((packed)) DELETE_FILE_REQ; |
849 | 940 | ||
850 | typedef struct smb_com_delete_file_rsp { | 941 | typedef struct smb_com_delete_file_rsp { |
851 | struct smb_hdr hdr; /* wct = 0 */ | 942 | struct smb_hdr hdr; /* wct = 0 */ |
852 | __u16 ByteCount; /* bct = 0 */ | 943 | __u16 ByteCount; /* bct = 0 */ |
853 | } DELETE_FILE_RSP; | 944 | } __attribute__((packed)) DELETE_FILE_RSP; |
854 | 945 | ||
855 | typedef struct smb_com_delete_directory_req { | 946 | typedef struct smb_com_delete_directory_req { |
856 | struct smb_hdr hdr; /* wct = 0 */ | 947 | struct smb_hdr hdr; /* wct = 0 */ |
857 | __le16 ByteCount; | 948 | __le16 ByteCount; |
858 | __u8 BufferFormat; /* 4 = ASCII */ | 949 | __u8 BufferFormat; /* 4 = ASCII */ |
859 | unsigned char DirName[1]; | 950 | unsigned char DirName[1]; |
860 | } DELETE_DIRECTORY_REQ; | 951 | } __attribute__((packed)) DELETE_DIRECTORY_REQ; |
861 | 952 | ||
862 | typedef struct smb_com_delete_directory_rsp { | 953 | typedef struct smb_com_delete_directory_rsp { |
863 | struct smb_hdr hdr; /* wct = 0 */ | 954 | struct smb_hdr hdr; /* wct = 0 */ |
864 | __u16 ByteCount; /* bct = 0 */ | 955 | __u16 ByteCount; /* bct = 0 */ |
865 | } DELETE_DIRECTORY_RSP; | 956 | } __attribute__((packed)) DELETE_DIRECTORY_RSP; |
866 | 957 | ||
867 | typedef struct smb_com_create_directory_req { | 958 | typedef struct smb_com_create_directory_req { |
868 | struct smb_hdr hdr; /* wct = 0 */ | 959 | struct smb_hdr hdr; /* wct = 0 */ |
869 | __le16 ByteCount; | 960 | __le16 ByteCount; |
870 | __u8 BufferFormat; /* 4 = ASCII */ | 961 | __u8 BufferFormat; /* 4 = ASCII */ |
871 | unsigned char DirName[1]; | 962 | unsigned char DirName[1]; |
872 | } CREATE_DIRECTORY_REQ; | 963 | } __attribute__((packed)) CREATE_DIRECTORY_REQ; |
873 | 964 | ||
874 | typedef struct smb_com_create_directory_rsp { | 965 | typedef struct smb_com_create_directory_rsp { |
875 | struct smb_hdr hdr; /* wct = 0 */ | 966 | struct smb_hdr hdr; /* wct = 0 */ |
876 | __u16 ByteCount; /* bct = 0 */ | 967 | __u16 ByteCount; /* bct = 0 */ |
877 | } CREATE_DIRECTORY_RSP; | 968 | } __attribute__((packed)) CREATE_DIRECTORY_RSP; |
969 | |||
970 | typedef struct smb_com_query_information_req { | ||
971 | struct smb_hdr hdr; /* wct = 0 */ | ||
972 | __le16 ByteCount; /* 1 + namelen + 1 */ | ||
973 | __u8 BufferFormat; /* 4 = ASCII */ | ||
974 | unsigned char FileName[1]; | ||
975 | } __attribute__((packed)) QUERY_INFORMATION_REQ; | ||
976 | |||
977 | typedef struct smb_com_query_information_rsp { | ||
978 | struct smb_hdr hdr; /* wct = 10 */ | ||
979 | __le16 attr; | ||
980 | __le32 last_write_time; | ||
981 | __le32 size; | ||
982 | __u16 reserved[5]; | ||
983 | __le16 ByteCount; /* bcc = 0 */ | ||
984 | } __attribute__((packed)) QUERY_INFORMATION_RSP; | ||
878 | 985 | ||
879 | typedef struct smb_com_setattr_req { | 986 | typedef struct smb_com_setattr_req { |
880 | struct smb_hdr hdr; /* wct = 8 */ | 987 | struct smb_hdr hdr; /* wct = 8 */ |
@@ -885,12 +992,12 @@ typedef struct smb_com_setattr_req { | |||
885 | __u16 ByteCount; | 992 | __u16 ByteCount; |
886 | __u8 BufferFormat; /* 4 = ASCII */ | 993 | __u8 BufferFormat; /* 4 = ASCII */ |
887 | unsigned char fileName[1]; | 994 | unsigned char fileName[1]; |
888 | } SETATTR_REQ; | 995 | } __attribute__((packed)) SETATTR_REQ; |
889 | 996 | ||
890 | typedef struct smb_com_setattr_rsp { | 997 | typedef struct smb_com_setattr_rsp { |
891 | struct smb_hdr hdr; /* wct = 0 */ | 998 | struct smb_hdr hdr; /* wct = 0 */ |
892 | __u16 ByteCount; /* bct = 0 */ | 999 | __u16 ByteCount; /* bct = 0 */ |
893 | } SETATTR_RSP; | 1000 | } __attribute__((packed)) SETATTR_RSP; |
894 | 1001 | ||
895 | /* empty wct response to setattr */ | 1002 | /* empty wct response to setattr */ |
896 | 1003 | ||
@@ -920,7 +1027,7 @@ typedef struct smb_com_transaction_ioctl_req { | |||
920 | __le16 ByteCount; | 1027 | __le16 ByteCount; |
921 | __u8 Pad[3]; | 1028 | __u8 Pad[3]; |
922 | __u8 Data[1]; | 1029 | __u8 Data[1]; |
923 | } TRANSACT_IOCTL_REQ; | 1030 | } __attribute__((packed)) TRANSACT_IOCTL_REQ; |
924 | 1031 | ||
925 | typedef struct smb_com_transaction_ioctl_rsp { | 1032 | typedef struct smb_com_transaction_ioctl_rsp { |
926 | struct smb_hdr hdr; /* wct = 19 */ | 1033 | struct smb_hdr hdr; /* wct = 19 */ |
@@ -937,7 +1044,7 @@ typedef struct smb_com_transaction_ioctl_rsp { | |||
937 | __le16 ReturnedDataLen; | 1044 | __le16 ReturnedDataLen; |
938 | __u16 ByteCount; | 1045 | __u16 ByteCount; |
939 | __u8 Pad[3]; | 1046 | __u8 Pad[3]; |
940 | } TRANSACT_IOCTL_RSP; | 1047 | } __attribute__((packed)) TRANSACT_IOCTL_RSP; |
941 | 1048 | ||
942 | typedef struct smb_com_transaction_change_notify_req { | 1049 | typedef struct smb_com_transaction_change_notify_req { |
943 | struct smb_hdr hdr; /* wct = 23 */ | 1050 | struct smb_hdr hdr; /* wct = 23 */ |
@@ -961,7 +1068,7 @@ typedef struct smb_com_transaction_change_notify_req { | |||
961 | __le16 ByteCount; | 1068 | __le16 ByteCount; |
962 | /* __u8 Pad[3];*/ | 1069 | /* __u8 Pad[3];*/ |
963 | /* __u8 Data[1];*/ | 1070 | /* __u8 Data[1];*/ |
964 | } TRANSACT_CHANGE_NOTIFY_REQ; | 1071 | } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; |
965 | 1072 | ||
966 | typedef struct smb_com_transaction_change_notify_rsp { | 1073 | typedef struct smb_com_transaction_change_notify_rsp { |
967 | struct smb_hdr hdr; /* wct = 18 */ | 1074 | struct smb_hdr hdr; /* wct = 18 */ |
@@ -977,7 +1084,7 @@ typedef struct smb_com_transaction_change_notify_rsp { | |||
977 | __u8 SetupCount; /* 0 */ | 1084 | __u8 SetupCount; /* 0 */ |
978 | __u16 ByteCount; | 1085 | __u16 ByteCount; |
979 | /* __u8 Pad[3]; */ | 1086 | /* __u8 Pad[3]; */ |
980 | } TRANSACT_CHANGE_NOTIFY_RSP; | 1087 | } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP; |
981 | /* Completion Filter flags for Notify */ | 1088 | /* Completion Filter flags for Notify */ |
982 | #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 | 1089 | #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 |
983 | #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 | 1090 | #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 |
@@ -1008,7 +1115,7 @@ struct file_notify_information { | |||
1008 | __le32 Action; | 1115 | __le32 Action; |
1009 | __le32 FileNameLength; | 1116 | __le32 FileNameLength; |
1010 | __u8 FileName[0]; | 1117 | __u8 FileName[0]; |
1011 | }; | 1118 | } __attribute__((packed)); |
1012 | 1119 | ||
1013 | struct reparse_data { | 1120 | struct reparse_data { |
1014 | __u32 ReparseTag; | 1121 | __u32 ReparseTag; |
@@ -1019,7 +1126,7 @@ struct reparse_data { | |||
1019 | __u16 TargetNameOffset; | 1126 | __u16 TargetNameOffset; |
1020 | __u16 TargetNameLen; | 1127 | __u16 TargetNameLen; |
1021 | char LinkNamesBuf[1]; | 1128 | char LinkNamesBuf[1]; |
1022 | }; | 1129 | } __attribute__((packed)); |
1023 | 1130 | ||
1024 | struct cifs_quota_data { | 1131 | struct cifs_quota_data { |
1025 | __u32 rsrvd1; /* 0 */ | 1132 | __u32 rsrvd1; /* 0 */ |
@@ -1029,7 +1136,7 @@ struct cifs_quota_data { | |||
1029 | __u64 soft_limit; | 1136 | __u64 soft_limit; |
1030 | __u64 hard_limit; | 1137 | __u64 hard_limit; |
1031 | char sid[1]; /* variable size? */ | 1138 | char sid[1]; /* variable size? */ |
1032 | }; | 1139 | } __attribute__((packed)); |
1033 | 1140 | ||
1034 | /* quota sub commands */ | 1141 | /* quota sub commands */ |
1035 | #define QUOTA_LIST_CONTINUE 0 | 1142 | #define QUOTA_LIST_CONTINUE 0 |
@@ -1055,12 +1162,12 @@ struct trans2_req { | |||
1055 | __u8 Reserved3; | 1162 | __u8 Reserved3; |
1056 | __le16 SubCommand; /* 1st setup word - SetupCount words follow */ | 1163 | __le16 SubCommand; /* 1st setup word - SetupCount words follow */ |
1057 | __le16 ByteCount; | 1164 | __le16 ByteCount; |
1058 | }; | 1165 | } __attribute__((packed)); |
1059 | 1166 | ||
1060 | struct smb_t2_req { | 1167 | struct smb_t2_req { |
1061 | struct smb_hdr hdr; | 1168 | struct smb_hdr hdr; |
1062 | struct trans2_req t2_req; | 1169 | struct trans2_req t2_req; |
1063 | }; | 1170 | } __attribute__((packed)); |
1064 | 1171 | ||
1065 | struct trans2_resp { | 1172 | struct trans2_resp { |
1066 | /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ | 1173 | /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ |
@@ -1079,12 +1186,12 @@ struct trans2_resp { | |||
1079 | __u16 ByteCount; | 1186 | __u16 ByteCount; |
1080 | __u16 Reserved2;*/ | 1187 | __u16 Reserved2;*/ |
1081 | /* data area follows */ | 1188 | /* data area follows */ |
1082 | }; | 1189 | } __attribute__((packed)); |
1083 | 1190 | ||
1084 | struct smb_t2_rsp { | 1191 | struct smb_t2_rsp { |
1085 | struct smb_hdr hdr; | 1192 | struct smb_hdr hdr; |
1086 | struct trans2_resp t2_rsp; | 1193 | struct trans2_resp t2_rsp; |
1087 | }; | 1194 | } __attribute__((packed)); |
1088 | 1195 | ||
1089 | /* PathInfo/FileInfo infolevels */ | 1196 | /* PathInfo/FileInfo infolevels */ |
1090 | #define SMB_INFO_STANDARD 1 | 1197 | #define SMB_INFO_STANDARD 1 |
@@ -1171,14 +1278,14 @@ typedef struct smb_com_transaction2_qpi_req { | |||
1171 | __le16 InformationLevel; | 1278 | __le16 InformationLevel; |
1172 | __u32 Reserved4; | 1279 | __u32 Reserved4; |
1173 | char FileName[1]; | 1280 | char FileName[1]; |
1174 | } TRANSACTION2_QPI_REQ; | 1281 | } __attribute__((packed)) TRANSACTION2_QPI_REQ; |
1175 | 1282 | ||
1176 | typedef struct smb_com_transaction2_qpi_rsp { | 1283 | typedef struct smb_com_transaction2_qpi_rsp { |
1177 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1284 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
1178 | struct trans2_resp t2; | 1285 | struct trans2_resp t2; |
1179 | __u16 ByteCount; | 1286 | __u16 ByteCount; |
1180 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | 1287 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ |
1181 | } TRANSACTION2_QPI_RSP; | 1288 | } __attribute__((packed)) TRANSACTION2_QPI_RSP; |
1182 | 1289 | ||
1183 | typedef struct smb_com_transaction2_spi_req { | 1290 | typedef struct smb_com_transaction2_spi_req { |
1184 | struct smb_hdr hdr; /* wct = 15 */ | 1291 | struct smb_hdr hdr; /* wct = 15 */ |
@@ -1204,21 +1311,21 @@ typedef struct smb_com_transaction2_spi_req { | |||
1204 | __le16 InformationLevel; | 1311 | __le16 InformationLevel; |
1205 | __u32 Reserved4; | 1312 | __u32 Reserved4; |
1206 | char FileName[1]; | 1313 | char FileName[1]; |
1207 | } TRANSACTION2_SPI_REQ; | 1314 | } __attribute__((packed)) TRANSACTION2_SPI_REQ; |
1208 | 1315 | ||
1209 | typedef struct smb_com_transaction2_spi_rsp { | 1316 | typedef struct smb_com_transaction2_spi_rsp { |
1210 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1317 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
1211 | struct trans2_resp t2; | 1318 | struct trans2_resp t2; |
1212 | __u16 ByteCount; | 1319 | __u16 ByteCount; |
1213 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | 1320 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ |
1214 | } TRANSACTION2_SPI_RSP; | 1321 | } __attribute__((packed)) TRANSACTION2_SPI_RSP; |
1215 | 1322 | ||
1216 | struct set_file_rename { | 1323 | struct set_file_rename { |
1217 | __le32 overwrite; /* 1 = overwrite dest */ | 1324 | __le32 overwrite; /* 1 = overwrite dest */ |
1218 | __u32 root_fid; /* zero */ | 1325 | __u32 root_fid; /* zero */ |
1219 | __le32 target_name_len; | 1326 | __le32 target_name_len; |
1220 | char target_name[0]; /* Must be unicode */ | 1327 | char target_name[0]; /* Must be unicode */ |
1221 | }; | 1328 | } __attribute__((packed)); |
1222 | 1329 | ||
1223 | struct smb_com_transaction2_sfi_req { | 1330 | struct smb_com_transaction2_sfi_req { |
1224 | struct smb_hdr hdr; /* wct = 15 */ | 1331 | struct smb_hdr hdr; /* wct = 15 */ |
@@ -1244,7 +1351,7 @@ struct smb_com_transaction2_sfi_req { | |||
1244 | __u16 Fid; | 1351 | __u16 Fid; |
1245 | __le16 InformationLevel; | 1352 | __le16 InformationLevel; |
1246 | __u16 Reserved4; | 1353 | __u16 Reserved4; |
1247 | }; | 1354 | } __attribute__((packed)); |
1248 | 1355 | ||
1249 | struct smb_com_transaction2_sfi_rsp { | 1356 | struct smb_com_transaction2_sfi_rsp { |
1250 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1357 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
@@ -1252,7 +1359,7 @@ struct smb_com_transaction2_sfi_rsp { | |||
1252 | __u16 ByteCount; | 1359 | __u16 ByteCount; |
1253 | __u16 Reserved2; /* parameter word reserved - | 1360 | __u16 Reserved2; /* parameter word reserved - |
1254 | present for infolevels > 100 */ | 1361 | present for infolevels > 100 */ |
1255 | }; | 1362 | } __attribute__((packed)); |
1256 | 1363 | ||
1257 | struct smb_t2_qfi_req { | 1364 | struct smb_t2_qfi_req { |
1258 | struct smb_hdr hdr; | 1365 | struct smb_hdr hdr; |
@@ -1260,7 +1367,7 @@ struct smb_t2_qfi_req { | |||
1260 | __u8 Pad; | 1367 | __u8 Pad; |
1261 | __u16 Fid; | 1368 | __u16 Fid; |
1262 | __le16 InformationLevel; | 1369 | __le16 InformationLevel; |
1263 | }; | 1370 | } __attribute__((packed)); |
1264 | 1371 | ||
1265 | struct smb_t2_qfi_rsp { | 1372 | struct smb_t2_qfi_rsp { |
1266 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1373 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
@@ -1268,7 +1375,7 @@ struct smb_t2_qfi_rsp { | |||
1268 | __u16 ByteCount; | 1375 | __u16 ByteCount; |
1269 | __u16 Reserved2; /* parameter word reserved - | 1376 | __u16 Reserved2; /* parameter word reserved - |
1270 | present for infolevels > 100 */ | 1377 | present for infolevels > 100 */ |
1271 | }; | 1378 | } __attribute__((packed)); |
1272 | 1379 | ||
1273 | /* | 1380 | /* |
1274 | * Flags on T2 FINDFIRST and FINDNEXT | 1381 | * Flags on T2 FINDFIRST and FINDNEXT |
@@ -1310,13 +1417,13 @@ typedef struct smb_com_transaction2_ffirst_req { | |||
1310 | __le16 InformationLevel; | 1417 | __le16 InformationLevel; |
1311 | __le32 SearchStorageType; | 1418 | __le32 SearchStorageType; |
1312 | char FileName[1]; | 1419 | char FileName[1]; |
1313 | } TRANSACTION2_FFIRST_REQ; | 1420 | } __attribute__((packed)) TRANSACTION2_FFIRST_REQ; |
1314 | 1421 | ||
1315 | typedef struct smb_com_transaction2_ffirst_rsp { | 1422 | typedef struct smb_com_transaction2_ffirst_rsp { |
1316 | struct smb_hdr hdr; /* wct = 10 */ | 1423 | struct smb_hdr hdr; /* wct = 10 */ |
1317 | struct trans2_resp t2; | 1424 | struct trans2_resp t2; |
1318 | __u16 ByteCount; | 1425 | __u16 ByteCount; |
1319 | } TRANSACTION2_FFIRST_RSP; | 1426 | } __attribute__((packed)) TRANSACTION2_FFIRST_RSP; |
1320 | 1427 | ||
1321 | typedef struct smb_com_transaction2_ffirst_rsp_parms { | 1428 | typedef struct smb_com_transaction2_ffirst_rsp_parms { |
1322 | __u16 SearchHandle; | 1429 | __u16 SearchHandle; |
@@ -1324,7 +1431,7 @@ typedef struct smb_com_transaction2_ffirst_rsp_parms { | |||
1324 | __le16 EndofSearch; | 1431 | __le16 EndofSearch; |
1325 | __le16 EAErrorOffset; | 1432 | __le16 EAErrorOffset; |
1326 | __le16 LastNameOffset; | 1433 | __le16 LastNameOffset; |
1327 | } T2_FFIRST_RSP_PARMS; | 1434 | } __attribute__((packed)) T2_FFIRST_RSP_PARMS; |
1328 | 1435 | ||
1329 | typedef struct smb_com_transaction2_fnext_req { | 1436 | typedef struct smb_com_transaction2_fnext_req { |
1330 | struct smb_hdr hdr; /* wct = 15 */ | 1437 | struct smb_hdr hdr; /* wct = 15 */ |
@@ -1352,20 +1459,20 @@ typedef struct smb_com_transaction2_fnext_req { | |||
1352 | __u32 ResumeKey; | 1459 | __u32 ResumeKey; |
1353 | __le16 SearchFlags; | 1460 | __le16 SearchFlags; |
1354 | char ResumeFileName[1]; | 1461 | char ResumeFileName[1]; |
1355 | } TRANSACTION2_FNEXT_REQ; | 1462 | } __attribute__((packed)) TRANSACTION2_FNEXT_REQ; |
1356 | 1463 | ||
1357 | typedef struct smb_com_transaction2_fnext_rsp { | 1464 | typedef struct smb_com_transaction2_fnext_rsp { |
1358 | struct smb_hdr hdr; /* wct = 10 */ | 1465 | struct smb_hdr hdr; /* wct = 10 */ |
1359 | struct trans2_resp t2; | 1466 | struct trans2_resp t2; |
1360 | __u16 ByteCount; | 1467 | __u16 ByteCount; |
1361 | } TRANSACTION2_FNEXT_RSP; | 1468 | } __attribute__((packed)) TRANSACTION2_FNEXT_RSP; |
1362 | 1469 | ||
1363 | typedef struct smb_com_transaction2_fnext_rsp_parms { | 1470 | typedef struct smb_com_transaction2_fnext_rsp_parms { |
1364 | __le16 SearchCount; | 1471 | __le16 SearchCount; |
1365 | __le16 EndofSearch; | 1472 | __le16 EndofSearch; |
1366 | __le16 EAErrorOffset; | 1473 | __le16 EAErrorOffset; |
1367 | __le16 LastNameOffset; | 1474 | __le16 LastNameOffset; |
1368 | } T2_FNEXT_RSP_PARMS; | 1475 | } __attribute__((packed)) T2_FNEXT_RSP_PARMS; |
1369 | 1476 | ||
1370 | /* QFSInfo Levels */ | 1477 | /* QFSInfo Levels */ |
1371 | #define SMB_INFO_ALLOCATION 1 | 1478 | #define SMB_INFO_ALLOCATION 1 |
@@ -1402,14 +1509,51 @@ typedef struct smb_com_transaction2_qfsi_req { | |||
1402 | __le16 ByteCount; | 1509 | __le16 ByteCount; |
1403 | __u8 Pad; | 1510 | __u8 Pad; |
1404 | __le16 InformationLevel; | 1511 | __le16 InformationLevel; |
1405 | } TRANSACTION2_QFSI_REQ; | 1512 | } __attribute__((packed)) TRANSACTION2_QFSI_REQ; |
1406 | 1513 | ||
1407 | typedef struct smb_com_transaction_qfsi_rsp { | 1514 | typedef struct smb_com_transaction_qfsi_rsp { |
1408 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1515 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
1409 | struct trans2_resp t2; | 1516 | struct trans2_resp t2; |
1410 | __u16 ByteCount; | 1517 | __u16 ByteCount; |
1411 | __u8 Pad; /* may be three bytes *//* followed by data area */ | 1518 | __u8 Pad; /* may be three bytes *//* followed by data area */ |
1412 | } TRANSACTION2_QFSI_RSP; | 1519 | } __attribute__((packed)) TRANSACTION2_QFSI_RSP; |
1520 | |||
1521 | |||
1522 | /* SETFSInfo Levels */ | ||
1523 | #define SMB_SET_CIFS_UNIX_INFO 0x200 | ||
1524 | typedef struct smb_com_transaction2_setfsi_req { | ||
1525 | struct smb_hdr hdr; /* wct = 15 */ | ||
1526 | __le16 TotalParameterCount; | ||
1527 | __le16 TotalDataCount; | ||
1528 | __le16 MaxParameterCount; | ||
1529 | __le16 MaxDataCount; | ||
1530 | __u8 MaxSetupCount; | ||
1531 | __u8 Reserved; | ||
1532 | __le16 Flags; | ||
1533 | __le32 Timeout; | ||
1534 | __u16 Reserved2; | ||
1535 | __le16 ParameterCount; /* 4 */ | ||
1536 | __le16 ParameterOffset; | ||
1537 | __le16 DataCount; /* 12 */ | ||
1538 | __le16 DataOffset; | ||
1539 | __u8 SetupCount; /* one */ | ||
1540 | __u8 Reserved3; | ||
1541 | __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */ | ||
1542 | __le16 ByteCount; | ||
1543 | __u8 Pad; | ||
1544 | __u16 FileNum; /* Parameters start. */ | ||
1545 | __le16 InformationLevel;/* Parameters end. */ | ||
1546 | __le16 ClientUnixMajor; /* Data start. */ | ||
1547 | __le16 ClientUnixMinor; | ||
1548 | __le64 ClientUnixCap; /* Data end */ | ||
1549 | } __attribute__((packed)) TRANSACTION2_SETFSI_REQ; | ||
1550 | |||
1551 | typedef struct smb_com_transaction2_setfsi_rsp { | ||
1552 | struct smb_hdr hdr; /* wct = 10 */ | ||
1553 | struct trans2_resp t2; | ||
1554 | __u16 ByteCount; | ||
1555 | } __attribute__((packed)) TRANSACTION2_SETFSI_RSP; | ||
1556 | |||
1413 | 1557 | ||
1414 | typedef struct smb_com_transaction2_get_dfs_refer_req { | 1558 | typedef struct smb_com_transaction2_get_dfs_refer_req { |
1415 | struct smb_hdr hdr; /* wct = 15 */ | 1559 | struct smb_hdr hdr; /* wct = 15 */ |
@@ -1433,7 +1577,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { | |||
1433 | __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ | 1577 | __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ |
1434 | __le16 MaxReferralLevel; | 1578 | __le16 MaxReferralLevel; |
1435 | char RequestFileName[1]; | 1579 | char RequestFileName[1]; |
1436 | } TRANSACTION2_GET_DFS_REFER_REQ; | 1580 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; |
1437 | 1581 | ||
1438 | typedef struct dfs_referral_level_3 { | 1582 | typedef struct dfs_referral_level_3 { |
1439 | __le16 VersionNumber; | 1583 | __le16 VersionNumber; |
@@ -1445,7 +1589,7 @@ typedef struct dfs_referral_level_3 { | |||
1445 | __le16 DfsPathOffset; | 1589 | __le16 DfsPathOffset; |
1446 | __le16 DfsAlternatePathOffset; | 1590 | __le16 DfsAlternatePathOffset; |
1447 | __le16 NetworkAddressOffset; | 1591 | __le16 NetworkAddressOffset; |
1448 | } REFERRAL3; | 1592 | } __attribute__((packed)) REFERRAL3; |
1449 | 1593 | ||
1450 | typedef struct smb_com_transaction_get_dfs_refer_rsp { | 1594 | typedef struct smb_com_transaction_get_dfs_refer_rsp { |
1451 | struct smb_hdr hdr; /* wct = 10 */ | 1595 | struct smb_hdr hdr; /* wct = 10 */ |
@@ -1458,7 +1602,7 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp { | |||
1458 | __u16 Pad2; | 1602 | __u16 Pad2; |
1459 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ | 1603 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ |
1460 | /* followed by the strings pointed to by the referral structures */ | 1604 | /* followed by the strings pointed to by the referral structures */ |
1461 | } TRANSACTION2_GET_DFS_REFER_RSP; | 1605 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP; |
1462 | 1606 | ||
1463 | /* DFS Flags */ | 1607 | /* DFS Flags */ |
1464 | #define DFSREF_REFERRAL_SERVER 0x0001 | 1608 | #define DFSREF_REFERRAL_SERVER 0x0001 |
@@ -1512,7 +1656,7 @@ struct serverInfo { | |||
1512 | unsigned char versionMinor; | 1656 | unsigned char versionMinor; |
1513 | unsigned long type; | 1657 | unsigned long type; |
1514 | unsigned int commentOffset; | 1658 | unsigned int commentOffset; |
1515 | }; | 1659 | } __attribute__((packed)); |
1516 | 1660 | ||
1517 | /* | 1661 | /* |
1518 | * The following structure is the format of the data returned on a NetShareEnum | 1662 | * The following structure is the format of the data returned on a NetShareEnum |
@@ -1524,39 +1668,55 @@ struct shareInfo { | |||
1524 | char pad; | 1668 | char pad; |
1525 | unsigned short type; | 1669 | unsigned short type; |
1526 | unsigned int commentOffset; | 1670 | unsigned int commentOffset; |
1527 | }; | 1671 | } __attribute__((packed)); |
1528 | 1672 | ||
1529 | struct aliasInfo { | 1673 | struct aliasInfo { |
1530 | char aliasName[9]; | 1674 | char aliasName[9]; |
1531 | char pad; | 1675 | char pad; |
1532 | unsigned int commentOffset; | 1676 | unsigned int commentOffset; |
1533 | unsigned char type[2]; | 1677 | unsigned char type[2]; |
1534 | }; | 1678 | } __attribute__((packed)); |
1535 | 1679 | ||
1536 | struct aliasInfo92 { | 1680 | struct aliasInfo92 { |
1537 | int aliasNameOffset; | 1681 | int aliasNameOffset; |
1538 | int serverNameOffset; | 1682 | int serverNameOffset; |
1539 | int shareNameOffset; | 1683 | int shareNameOffset; |
1540 | }; | 1684 | } __attribute__((packed)); |
1541 | 1685 | ||
1542 | typedef struct { | 1686 | typedef struct { |
1543 | __le64 TotalAllocationUnits; | 1687 | __le64 TotalAllocationUnits; |
1544 | __le64 FreeAllocationUnits; | 1688 | __le64 FreeAllocationUnits; |
1545 | __le32 SectorsPerAllocationUnit; | 1689 | __le32 SectorsPerAllocationUnit; |
1546 | __le32 BytesPerSector; | 1690 | __le32 BytesPerSector; |
1547 | } FILE_SYSTEM_INFO; /* size info, level 0x103 */ | 1691 | } __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */ |
1692 | |||
1693 | typedef struct { | ||
1694 | __le32 fsid; | ||
1695 | __le32 SectorsPerAllocationUnit; | ||
1696 | __le32 TotalAllocationUnits; | ||
1697 | __le32 FreeAllocationUnits; | ||
1698 | __le16 BytesPerSector; | ||
1699 | } __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO; | ||
1548 | 1700 | ||
1549 | typedef struct { | 1701 | typedef struct { |
1550 | __le16 MajorVersionNumber; | 1702 | __le16 MajorVersionNumber; |
1551 | __le16 MinorVersionNumber; | 1703 | __le16 MinorVersionNumber; |
1552 | __le64 Capability; | 1704 | __le64 Capability; |
1553 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ | 1705 | } __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ |
1706 | |||
1707 | /* Version numbers for CIFS UNIX major and minor. */ | ||
1708 | #define CIFS_UNIX_MAJOR_VERSION 1 | ||
1709 | #define CIFS_UNIX_MINOR_VERSION 0 | ||
1710 | |||
1554 | /* Linux/Unix extensions capability flags */ | 1711 | /* Linux/Unix extensions capability flags */ |
1555 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ | 1712 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ |
1556 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ | 1713 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ |
1557 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ | 1714 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ |
1558 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ | 1715 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ |
1716 | #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Use POSIX pathnames on the wire. */ | ||
1717 | |||
1559 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ | 1718 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ |
1719 | |||
1560 | typedef struct { | 1720 | typedef struct { |
1561 | /* For undefined recommended transfer size return -1 in that field */ | 1721 | /* For undefined recommended transfer size return -1 in that field */ |
1562 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ | 1722 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ |
@@ -1577,7 +1737,7 @@ typedef struct { | |||
1577 | __le64 FileSysIdentifier; /* fsid */ | 1737 | __le64 FileSysIdentifier; /* fsid */ |
1578 | /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ | 1738 | /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ |
1579 | /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ | 1739 | /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ |
1580 | } FILE_SYSTEM_POSIX_INFO; | 1740 | } __attribute__((packed)) FILE_SYSTEM_POSIX_INFO; |
1581 | 1741 | ||
1582 | /* DeviceType Flags */ | 1742 | /* DeviceType Flags */ |
1583 | #define FILE_DEVICE_CD_ROM 0x00000002 | 1743 | #define FILE_DEVICE_CD_ROM 0x00000002 |
@@ -1602,14 +1762,14 @@ typedef struct { | |||
1602 | typedef struct { | 1762 | typedef struct { |
1603 | __le32 DeviceType; | 1763 | __le32 DeviceType; |
1604 | __le32 DeviceCharacteristics; | 1764 | __le32 DeviceCharacteristics; |
1605 | } FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ | 1765 | } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ |
1606 | 1766 | ||
1607 | typedef struct { | 1767 | typedef struct { |
1608 | __le32 Attributes; | 1768 | __le32 Attributes; |
1609 | __le32 MaxPathNameComponentLength; | 1769 | __le32 MaxPathNameComponentLength; |
1610 | __le32 FileSystemNameLen; | 1770 | __le32 FileSystemNameLen; |
1611 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ | 1771 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ |
1612 | } FILE_SYSTEM_ATTRIBUTE_INFO; | 1772 | } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; |
1613 | 1773 | ||
1614 | /******************************************************************************/ | 1774 | /******************************************************************************/ |
1615 | /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ | 1775 | /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ |
@@ -1636,7 +1796,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */ | |||
1636 | __le32 AlignmentRequirement; | 1796 | __le32 AlignmentRequirement; |
1637 | __le32 FileNameLength; | 1797 | __le32 FileNameLength; |
1638 | char FileName[1]; | 1798 | char FileName[1]; |
1639 | } FILE_ALL_INFO; /* level 0x107 QPathInfo */ | 1799 | } __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ |
1640 | 1800 | ||
1641 | /* defines for enumerating possible values of the Unix type field below */ | 1801 | /* defines for enumerating possible values of the Unix type field below */ |
1642 | #define UNIX_FILE 0 | 1802 | #define UNIX_FILE 0 |
@@ -1660,11 +1820,11 @@ typedef struct { | |||
1660 | __u64 UniqueId; | 1820 | __u64 UniqueId; |
1661 | __le64 Permissions; | 1821 | __le64 Permissions; |
1662 | __le64 Nlinks; | 1822 | __le64 Nlinks; |
1663 | } FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ | 1823 | } __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ |
1664 | 1824 | ||
1665 | typedef struct { | 1825 | typedef struct { |
1666 | char LinkDest[1]; | 1826 | char LinkDest[1]; |
1667 | } FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ | 1827 | } __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ |
1668 | 1828 | ||
1669 | /* The following three structures are needed only for | 1829 | /* The following three structures are needed only for |
1670 | setting time to NT4 and some older servers via | 1830 | setting time to NT4 and some older servers via |
@@ -1673,13 +1833,13 @@ typedef struct { | |||
1673 | __u16 Day:5; | 1833 | __u16 Day:5; |
1674 | __u16 Month:4; | 1834 | __u16 Month:4; |
1675 | __u16 Year:7; | 1835 | __u16 Year:7; |
1676 | } SMB_DATE; | 1836 | } __attribute__((packed)) SMB_DATE; |
1677 | 1837 | ||
1678 | typedef struct { | 1838 | typedef struct { |
1679 | __u16 TwoSeconds:5; | 1839 | __u16 TwoSeconds:5; |
1680 | __u16 Minutes:6; | 1840 | __u16 Minutes:6; |
1681 | __u16 Hours:5; | 1841 | __u16 Hours:5; |
1682 | } SMB_TIME; | 1842 | } __attribute__((packed)) SMB_TIME; |
1683 | 1843 | ||
1684 | typedef struct { | 1844 | typedef struct { |
1685 | __le16 CreationDate; /* SMB Date see above */ | 1845 | __le16 CreationDate; /* SMB Date see above */ |
@@ -1692,7 +1852,7 @@ typedef struct { | |||
1692 | __le32 AllocationSize; | 1852 | __le32 AllocationSize; |
1693 | __le16 Attributes; /* verify not u32 */ | 1853 | __le16 Attributes; /* verify not u32 */ |
1694 | __le32 EASize; | 1854 | __le32 EASize; |
1695 | } FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ | 1855 | } __attribute__((packed)) FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ |
1696 | 1856 | ||
1697 | typedef struct { | 1857 | typedef struct { |
1698 | __le64 CreationTime; | 1858 | __le64 CreationTime; |
@@ -1701,19 +1861,19 @@ typedef struct { | |||
1701 | __le64 ChangeTime; | 1861 | __le64 ChangeTime; |
1702 | __le32 Attributes; | 1862 | __le32 Attributes; |
1703 | __u32 Pad; | 1863 | __u32 Pad; |
1704 | } FILE_BASIC_INFO; /* size info, level 0x101 */ | 1864 | } __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ |
1705 | 1865 | ||
1706 | struct file_allocation_info { | 1866 | struct file_allocation_info { |
1707 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ | 1867 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ |
1708 | }; /* size used on disk, level 0x103 for set, 0x105 for query */ | 1868 | } __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */ |
1709 | 1869 | ||
1710 | struct file_end_of_file_info { | 1870 | struct file_end_of_file_info { |
1711 | __le64 FileSize; /* offset to end of file */ | 1871 | __le64 FileSize; /* offset to end of file */ |
1712 | }; /* size info, level 0x104 for set, 0x106 for query */ | 1872 | } __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ |
1713 | 1873 | ||
1714 | struct file_alt_name_info { | 1874 | struct file_alt_name_info { |
1715 | __u8 alt_name[1]; | 1875 | __u8 alt_name[1]; |
1716 | }; /* level 0x0108 */ | 1876 | } __attribute__((packed)); /* level 0x0108 */ |
1717 | 1877 | ||
1718 | struct file_stream_info { | 1878 | struct file_stream_info { |
1719 | __le32 number_of_streams; /* BB check sizes and verify location */ | 1879 | __le32 number_of_streams; /* BB check sizes and verify location */ |
@@ -1730,7 +1890,7 @@ struct file_compression_info { | |||
1730 | __u8 ch_shift; | 1890 | __u8 ch_shift; |
1731 | __u8 cl_shift; | 1891 | __u8 cl_shift; |
1732 | __u8 pad[3]; | 1892 | __u8 pad[3]; |
1733 | }; /* level 0x10b */ | 1893 | } __attribute__((packed)); /* level 0x10b */ |
1734 | 1894 | ||
1735 | /* POSIX ACL set/query path info structures */ | 1895 | /* POSIX ACL set/query path info structures */ |
1736 | #define CIFS_ACL_VERSION 1 | 1896 | #define CIFS_ACL_VERSION 1 |
@@ -1738,7 +1898,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */ | |||
1738 | __u8 cifs_e_tag; | 1898 | __u8 cifs_e_tag; |
1739 | __u8 cifs_e_perm; | 1899 | __u8 cifs_e_perm; |
1740 | __le64 cifs_uid; /* or gid */ | 1900 | __le64 cifs_uid; /* or gid */ |
1741 | }; | 1901 | } __attribute__((packed)); |
1742 | 1902 | ||
1743 | struct cifs_posix_acl { /* access conrol list (ACL) */ | 1903 | struct cifs_posix_acl { /* access conrol list (ACL) */ |
1744 | __le16 version; | 1904 | __le16 version; |
@@ -1747,7 +1907,7 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ | |||
1747 | struct cifs_posix_ace ace_array[0]; | 1907 | struct cifs_posix_ace ace_array[0]; |
1748 | /* followed by | 1908 | /* followed by |
1749 | struct cifs_posix_ace default_ace_arraay[] */ | 1909 | struct cifs_posix_ace default_ace_arraay[] */ |
1750 | }; /* level 0x204 */ | 1910 | } __attribute__((packed)); /* level 0x204 */ |
1751 | 1911 | ||
1752 | /* types of access control entries already defined in posix_acl.h */ | 1912 | /* types of access control entries already defined in posix_acl.h */ |
1753 | /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 | 1913 | /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 |
@@ -1766,15 +1926,15 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ | |||
1766 | 1926 | ||
1767 | struct file_internal_info { | 1927 | struct file_internal_info { |
1768 | __u64 UniqueId; /* inode number */ | 1928 | __u64 UniqueId; /* inode number */ |
1769 | }; /* level 0x3ee */ | 1929 | } __attribute__((packed)); /* level 0x3ee */ |
1770 | struct file_mode_info { | 1930 | struct file_mode_info { |
1771 | __le32 Mode; | 1931 | __le32 Mode; |
1772 | }; /* level 0x3f8 */ | 1932 | } __attribute__((packed)); /* level 0x3f8 */ |
1773 | 1933 | ||
1774 | struct file_attrib_tag { | 1934 | struct file_attrib_tag { |
1775 | __le32 Attribute; | 1935 | __le32 Attribute; |
1776 | __le32 ReparseTag; | 1936 | __le32 ReparseTag; |
1777 | }; /* level 0x40b */ | 1937 | } __attribute__((packed)); /* level 0x40b */ |
1778 | 1938 | ||
1779 | 1939 | ||
1780 | /********************************************************/ | 1940 | /********************************************************/ |
@@ -1798,7 +1958,7 @@ typedef struct { | |||
1798 | __le64 Permissions; | 1958 | __le64 Permissions; |
1799 | __le64 Nlinks; | 1959 | __le64 Nlinks; |
1800 | char FileName[1]; | 1960 | char FileName[1]; |
1801 | } FILE_UNIX_INFO; /* level 0x202 */ | 1961 | } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ |
1802 | 1962 | ||
1803 | typedef struct { | 1963 | typedef struct { |
1804 | __le32 NextEntryOffset; | 1964 | __le32 NextEntryOffset; |
@@ -1812,7 +1972,7 @@ typedef struct { | |||
1812 | __le32 ExtFileAttributes; | 1972 | __le32 ExtFileAttributes; |
1813 | __le32 FileNameLength; | 1973 | __le32 FileNameLength; |
1814 | char FileName[1]; | 1974 | char FileName[1]; |
1815 | } FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ | 1975 | } __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ |
1816 | 1976 | ||
1817 | typedef struct { | 1977 | typedef struct { |
1818 | __le32 NextEntryOffset; | 1978 | __le32 NextEntryOffset; |
@@ -1827,7 +1987,7 @@ typedef struct { | |||
1827 | __le32 FileNameLength; | 1987 | __le32 FileNameLength; |
1828 | __le32 EaSize; /* length of the xattrs */ | 1988 | __le32 EaSize; /* length of the xattrs */ |
1829 | char FileName[1]; | 1989 | char FileName[1]; |
1830 | } FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ | 1990 | } __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ |
1831 | 1991 | ||
1832 | typedef struct { | 1992 | typedef struct { |
1833 | __le32 NextEntryOffset; | 1993 | __le32 NextEntryOffset; |
@@ -1844,7 +2004,7 @@ typedef struct { | |||
1844 | __le32 Reserved; | 2004 | __le32 Reserved; |
1845 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | 2005 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ |
1846 | char FileName[1]; | 2006 | char FileName[1]; |
1847 | } SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ | 2007 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ |
1848 | 2008 | ||
1849 | typedef struct { | 2009 | typedef struct { |
1850 | __le32 NextEntryOffset; | 2010 | __le32 NextEntryOffset; |
@@ -1862,18 +2022,18 @@ typedef struct { | |||
1862 | __u8 Reserved; | 2022 | __u8 Reserved; |
1863 | __u8 ShortName[12]; | 2023 | __u8 ShortName[12]; |
1864 | char FileName[1]; | 2024 | char FileName[1]; |
1865 | } FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ | 2025 | } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ |
1866 | 2026 | ||
1867 | 2027 | ||
1868 | struct gea { | 2028 | struct gea { |
1869 | unsigned char name_len; | 2029 | unsigned char name_len; |
1870 | char name[1]; | 2030 | char name[1]; |
1871 | }; | 2031 | } __attribute__((packed)); |
1872 | 2032 | ||
1873 | struct gealist { | 2033 | struct gealist { |
1874 | unsigned long list_len; | 2034 | unsigned long list_len; |
1875 | struct gea list[1]; | 2035 | struct gea list[1]; |
1876 | }; | 2036 | } __attribute__((packed)); |
1877 | 2037 | ||
1878 | struct fea { | 2038 | struct fea { |
1879 | unsigned char EA_flags; | 2039 | unsigned char EA_flags; |
@@ -1881,21 +2041,21 @@ struct fea { | |||
1881 | __le16 value_len; | 2041 | __le16 value_len; |
1882 | char name[1]; | 2042 | char name[1]; |
1883 | /* optionally followed by value */ | 2043 | /* optionally followed by value */ |
1884 | }; | 2044 | } __attribute__((packed)); |
1885 | /* flags for _FEA.fEA */ | 2045 | /* flags for _FEA.fEA */ |
1886 | #define FEA_NEEDEA 0x80 /* need EA bit */ | 2046 | #define FEA_NEEDEA 0x80 /* need EA bit */ |
1887 | 2047 | ||
1888 | struct fealist { | 2048 | struct fealist { |
1889 | __le32 list_len; | 2049 | __le32 list_len; |
1890 | struct fea list[1]; | 2050 | struct fea list[1]; |
1891 | }; | 2051 | } __attribute__((packed)); |
1892 | 2052 | ||
1893 | /* used to hold an arbitrary blob of data */ | 2053 | /* used to hold an arbitrary blob of data */ |
1894 | struct data_blob { | 2054 | struct data_blob { |
1895 | __u8 *data; | 2055 | __u8 *data; |
1896 | size_t length; | 2056 | size_t length; |
1897 | void (*free) (struct data_blob * data_blob); | 2057 | void (*free) (struct data_blob * data_blob); |
1898 | }; | 2058 | } __attribute__((packed)); |
1899 | 2059 | ||
1900 | 2060 | ||
1901 | #ifdef CONFIG_CIFS_POSIX | 2061 | #ifdef CONFIG_CIFS_POSIX |
@@ -1907,18 +2067,17 @@ struct data_blob { | |||
1907 | perhaps add a CreateDevice - to create Pipes and other special .inodes | 2067 | perhaps add a CreateDevice - to create Pipes and other special .inodes |
1908 | Also note POSIX open flags | 2068 | Also note POSIX open flags |
1909 | 2) Close - to return the last write time to do cache across close more safely | 2069 | 2) Close - to return the last write time to do cache across close more safely |
1910 | 3) PosixQFSInfo - to return statfs info | 2070 | 3) FindFirst return unique inode number - what about resume key, two |
1911 | 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) | 2071 | forms short (matches readdir) and full (enough info to cache inodes) |
1912 | 5) Mkdir - set mode | 2072 | 4) Mkdir - set mode |
1913 | 2073 | ||
1914 | And under consideration: | 2074 | And under consideration: |
1915 | 6) FindClose2 (return nanosecond timestamp ??) | 2075 | 5) FindClose2 (return nanosecond timestamp ??) |
1916 | 7) Use nanosecond timestamps throughout all time fields if | 2076 | 6) Use nanosecond timestamps throughout all time fields if |
1917 | corresponding attribute flag is set | 2077 | corresponding attribute flag is set |
1918 | 8) sendfile - handle based copy | 2078 | 7) sendfile - handle based copy |
1919 | 9) Direct i/o | 2079 | 8) Direct i/o |
1920 | 10) "POSIX ACL" support | 2080 | 9) Misc fcntls? |
1921 | 11) Misc fcntls? | ||
1922 | 2081 | ||
1923 | what about fixing 64 bit alignment | 2082 | what about fixing 64 bit alignment |
1924 | 2083 | ||
@@ -1974,7 +2133,7 @@ struct data_blob { | |||
1974 | 2133 | ||
1975 | */ | 2134 | */ |
1976 | 2135 | ||
1977 | /* xsymlink is a symlink format that can be used | 2136 | /* xsymlink is a symlink format (used by MacOS) that can be used |
1978 | to save symlink info in a regular file when | 2137 | to save symlink info in a regular file when |
1979 | mounted to operating systems that do not | 2138 | mounted to operating systems that do not |
1980 | support the cifs Unix extensions or EAs (for xattr | 2139 | support the cifs Unix extensions or EAs (for xattr |
@@ -1999,7 +2158,7 @@ struct xsymlink { | |||
1999 | char cr2; /* \n */ | 2158 | char cr2; /* \n */ |
2000 | /* if room left, then end with \n then 0x20s by convention but not required */ | 2159 | /* if room left, then end with \n then 0x20s by convention but not required */ |
2001 | char path[1024]; | 2160 | char path[1024]; |
2002 | }; | 2161 | } __attribute__((packed)); |
2003 | 2162 | ||
2004 | typedef struct file_xattr_info { | 2163 | typedef struct file_xattr_info { |
2005 | /* BB do we need another field for flags? BB */ | 2164 | /* BB do we need another field for flags? BB */ |
@@ -2007,7 +2166,7 @@ typedef struct file_xattr_info { | |||
2007 | __u32 xattr_value_len; | 2166 | __u32 xattr_value_len; |
2008 | char xattr_name[0]; | 2167 | char xattr_name[0]; |
2009 | /* followed by xattr_value[xattr_value_len], no pad */ | 2168 | /* followed by xattr_value[xattr_value_len], no pad */ |
2010 | } FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ | 2169 | } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ |
2011 | 2170 | ||
2012 | 2171 | ||
2013 | /* flags for chattr command */ | 2172 | /* flags for chattr command */ |
@@ -2033,10 +2192,8 @@ typedef struct file_xattr_info { | |||
2033 | typedef struct file_chattr_info { | 2192 | typedef struct file_chattr_info { |
2034 | __le64 mask; /* list of all possible attribute bits */ | 2193 | __le64 mask; /* list of all possible attribute bits */ |
2035 | __le64 mode; /* list of actual attribute bits on this inode */ | 2194 | __le64 mode; /* list of actual attribute bits on this inode */ |
2036 | } FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ | 2195 | } __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ |
2037 | 2196 | ||
2038 | #endif | 2197 | #endif |
2039 | 2198 | ||
2040 | #pragma pack() /* resume default structure packing */ | ||
2041 | |||
2042 | #endif /* _CIFSPDU_H */ | 2199 | #endif /* _CIFSPDU_H */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ea239dea571e..d301149b1bb0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
47 | struct smb_hdr * /* input */ , | 47 | struct smb_hdr * /* input */ , |
48 | struct smb_hdr * /* out */ , | 48 | struct smb_hdr * /* out */ , |
49 | int * /* bytes returned */ , const int long_op); | 49 | int * /* bytes returned */ , const int long_op); |
50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | ||
51 | struct kvec *, int /* nvec */, | ||
52 | int * /* bytes returned */ , const int long_op); | ||
50 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
51 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
52 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 55 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
53 | extern int is_size_safe_to_change(struct cifsInodeInfo *); | 56 | extern int is_size_safe_to_change(struct cifsInodeInfo *); |
57 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); | ||
54 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 58 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
59 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | ||
55 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 60 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
56 | enum securityEnum *secType); | 61 | enum securityEnum *secType); |
57 | extern int cifs_inet_pton(int, char * source, void *dst); | 62 | extern int cifs_inet_pton(int, char * source, void *dst); |
58 | extern int map_smb_to_linux_error(struct smb_hdr *smb); | 63 | extern int map_smb_to_linux_error(struct smb_hdr *smb); |
59 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 64 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
60 | const struct cifsTconInfo *, int /* specifies length | 65 | const struct cifsTconInfo *, int /* length of |
61 | of fixed section (word count) in two byte units */ | 66 | fixed section (word count) in two byte units */); |
62 | ); | 67 | extern __u16 GetNextMid(struct TCP_Server_Info *server); |
63 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, | 68 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, |
64 | struct cifsTconInfo *); | 69 | struct cifsTconInfo *); |
65 | extern void DeleteOplockQEntry(struct oplock_q_entry *); | 70 | extern void DeleteOplockQEntry(struct oplock_q_entry *); |
@@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
89 | 94 | ||
90 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, |
91 | const char *searchName, const struct nls_table *nls_codepage, | 96 | const char *searchName, const struct nls_table *nls_codepage, |
92 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); | 97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); |
93 | 98 | ||
94 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 99 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, |
95 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | 100 | __u16 searchHandle, struct cifs_search_info * psrch_inf); |
@@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | |||
101 | const unsigned char *searchName, | 106 | const unsigned char *searchName, |
102 | FILE_ALL_INFO * findData, | 107 | FILE_ALL_INFO * findData, |
103 | const struct nls_table *nls_codepage, int remap); | 108 | const struct nls_table *nls_codepage, int remap); |
109 | extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
110 | const unsigned char *searchName, | ||
111 | FILE_ALL_INFO * findData, | ||
112 | const struct nls_table *nls_codepage, int remap); | ||
104 | 113 | ||
105 | extern int CIFSSMBUnixQPathInfo(const int xid, | 114 | extern int CIFSSMBUnixQPathInfo(const int xid, |
106 | struct cifsTconInfo *tcon, | 115 | struct cifsTconInfo *tcon, |
@@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | |||
125 | int remap); | 134 | int remap); |
126 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | 135 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, |
127 | struct kstatfs *FSData); | 136 | struct kstatfs *FSData); |
137 | extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, | ||
138 | struct kstatfs *FSData); | ||
139 | extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | ||
140 | __u64 cap); | ||
141 | |||
128 | extern int CIFSSMBQFSAttributeInfo(const int xid, | 142 | extern int CIFSSMBQFSAttributeInfo(const int xid, |
129 | struct cifsTconInfo *tcon); | 143 | struct cifsTconInfo *tcon); |
130 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); | 144 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); |
@@ -207,6 +221,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | |||
207 | const int access_flags, const int omode, | 221 | const int access_flags, const int omode, |
208 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | 222 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, |
209 | const struct nls_table *nls_codepage, int remap); | 223 | const struct nls_table *nls_codepage, int remap); |
224 | extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
225 | const char *fileName, const int disposition, | ||
226 | const int access_flags, const int omode, | ||
227 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | ||
228 | const struct nls_table *nls_codepage, int remap); | ||
210 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | 229 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, |
211 | const int smb_file_id); | 230 | const int smb_file_id); |
212 | 231 | ||
@@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
222 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 241 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
223 | const int netfid, const unsigned int count, | 242 | const int netfid, const unsigned int count, |
224 | const __u64 offset, unsigned int *nbytes, | 243 | const __u64 offset, unsigned int *nbytes, |
225 | const char __user *buf,const int long_op); | 244 | struct kvec *iov, const int nvec, const int long_op); |
226 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 245 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
227 | const unsigned char *searchName, __u64 * inode_number, | 246 | const unsigned char *searchName, __u64 * inode_number, |
228 | const struct nls_table *nls_codepage, | 247 | const struct nls_table *nls_codepage, |
@@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid, | |||
264 | int remap_special_chars); | 283 | int remap_special_chars); |
265 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 284 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
266 | const int notify_subdirs,const __u16 netfid, | 285 | const int notify_subdirs,const __u16 netfid, |
267 | __u32 filter, const struct nls_table *nls_codepage); | 286 | __u32 filter, struct file * file, int multishot, |
287 | const struct nls_table *nls_codepage); | ||
268 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 288 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
269 | const unsigned char *searchName, char * EAData, | 289 | const unsigned char *searchName, char * EAData, |
270 | size_t bufsize, const struct nls_table *nls_codepage, | 290 | size_t bufsize, const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0db0b313d715..9312bfc56682 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon | 125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon |
126 | , nls_codepage); | 126 | , nls_codepage); |
127 | up(&tcon->ses->sesSem); | 127 | up(&tcon->ses->sesSem); |
128 | /* BB FIXME add code to check if wsize needs | ||
129 | update due to negotiated smb buffer size | ||
130 | shrinking */ | ||
128 | if(rc == 0) | 131 | if(rc == 0) |
129 | atomic_inc(&tconInfoReconnectCount); | 132 | atomic_inc(&tconInfoReconnectCount); |
130 | 133 | ||
@@ -166,11 +169,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
166 | 169 | ||
167 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); | 170 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); |
168 | 171 | ||
169 | #ifdef CONFIG_CIFS_STATS | 172 | if(tcon != NULL) |
170 | if(tcon != NULL) { | 173 | cifs_stats_inc(&tcon->num_smbs_sent); |
171 | atomic_inc(&tcon->num_smbs_sent); | 174 | |
172 | } | ||
173 | #endif /* CONFIG_CIFS_STATS */ | ||
174 | return rc; | 175 | return rc; |
175 | } | 176 | } |
176 | 177 | ||
@@ -222,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
222 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 223 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
223 | tcon, nls_codepage); | 224 | tcon, nls_codepage); |
224 | up(&tcon->ses->sesSem); | 225 | up(&tcon->ses->sesSem); |
226 | /* BB FIXME add code to check if wsize needs | ||
227 | update due to negotiated smb buffer size | ||
228 | shrinking */ | ||
225 | if(rc == 0) | 229 | if(rc == 0) |
226 | atomic_inc(&tconInfoReconnectCount); | 230 | atomic_inc(&tconInfoReconnectCount); |
227 | 231 | ||
@@ -269,11 +273,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
269 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 273 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
270 | wct /*wct */ ); | 274 | wct /*wct */ ); |
271 | 275 | ||
272 | #ifdef CONFIG_CIFS_STATS | 276 | if(tcon != NULL) |
273 | if(tcon != NULL) { | 277 | cifs_stats_inc(&tcon->num_smbs_sent); |
274 | atomic_inc(&tcon->num_smbs_sent); | 278 | |
275 | } | ||
276 | #endif /* CONFIG_CIFS_STATS */ | ||
277 | return rc; | 279 | return rc; |
278 | } | 280 | } |
279 | 281 | ||
@@ -330,7 +332,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
330 | (void **) &pSMB, (void **) &pSMBr); | 332 | (void **) &pSMB, (void **) &pSMBr); |
331 | if (rc) | 333 | if (rc) |
332 | return rc; | 334 | return rc; |
333 | 335 | pSMB->hdr.Mid = GetNextMid(server); | |
334 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 336 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
335 | if (extended_security) | 337 | if (extended_security) |
336 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 338 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
@@ -422,8 +424,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
422 | } | 424 | } |
423 | 425 | ||
424 | } | 426 | } |
425 | if (pSMB) | 427 | |
426 | cifs_buf_release(pSMB); | 428 | cifs_buf_release(pSMB); |
427 | return rc; | 429 | return rc; |
428 | } | 430 | } |
429 | 431 | ||
@@ -518,6 +520,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
518 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | 520 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ |
519 | 521 | ||
520 | if(ses->server) { | 522 | if(ses->server) { |
523 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
524 | |||
521 | if(ses->server->secMode & | 525 | if(ses->server->secMode & |
522 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 526 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
523 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 527 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
@@ -537,9 +541,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
537 | rc = -ESHUTDOWN; | 541 | rc = -ESHUTDOWN; |
538 | } | 542 | } |
539 | } | 543 | } |
540 | if (pSMB) | ||
541 | cifs_small_buf_release(pSMB); | ||
542 | up(&ses->sesSem); | 544 | up(&ses->sesSem); |
545 | cifs_small_buf_release(pSMB); | ||
543 | 546 | ||
544 | /* if session dead then we do not need to do ulogoff, | 547 | /* if session dead then we do not need to do ulogoff, |
545 | since server closed smb session, no sense reporting | 548 | since server closed smb session, no sense reporting |
@@ -583,14 +586,10 @@ DelFileRetry: | |||
583 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 586 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
584 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 587 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
585 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 588 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
589 | cifs_stats_inc(&tcon->num_deletes); | ||
586 | if (rc) { | 590 | if (rc) { |
587 | cFYI(1, ("Error in RMFile = %d", rc)); | 591 | cFYI(1, ("Error in RMFile = %d", rc)); |
588 | } | 592 | } |
589 | #ifdef CONFIG_CIFS_STATS | ||
590 | else { | ||
591 | atomic_inc(&tcon->num_deletes); | ||
592 | } | ||
593 | #endif | ||
594 | 593 | ||
595 | cifs_buf_release(pSMB); | 594 | cifs_buf_release(pSMB); |
596 | if (rc == -EAGAIN) | 595 | if (rc == -EAGAIN) |
@@ -632,14 +631,10 @@ RmDirRetry: | |||
632 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 631 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
633 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 632 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
634 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 633 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
634 | cifs_stats_inc(&tcon->num_rmdirs); | ||
635 | if (rc) { | 635 | if (rc) { |
636 | cFYI(1, ("Error in RMDir = %d", rc)); | 636 | cFYI(1, ("Error in RMDir = %d", rc)); |
637 | } | 637 | } |
638 | #ifdef CONFIG_CIFS_STATS | ||
639 | else { | ||
640 | atomic_inc(&tcon->num_rmdirs); | ||
641 | } | ||
642 | #endif | ||
643 | 638 | ||
644 | cifs_buf_release(pSMB); | 639 | cifs_buf_release(pSMB); |
645 | if (rc == -EAGAIN) | 640 | if (rc == -EAGAIN) |
@@ -680,20 +675,161 @@ MkDirRetry: | |||
680 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 675 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
681 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 676 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
682 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 677 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
678 | cifs_stats_inc(&tcon->num_mkdirs); | ||
683 | if (rc) { | 679 | if (rc) { |
684 | cFYI(1, ("Error in Mkdir = %d", rc)); | 680 | cFYI(1, ("Error in Mkdir = %d", rc)); |
685 | } | 681 | } |
686 | #ifdef CONFIG_CIFS_STATS | 682 | |
687 | else { | ||
688 | atomic_inc(&tcon->num_mkdirs); | ||
689 | } | ||
690 | #endif | ||
691 | cifs_buf_release(pSMB); | 683 | cifs_buf_release(pSMB); |
692 | if (rc == -EAGAIN) | 684 | if (rc == -EAGAIN) |
693 | goto MkDirRetry; | 685 | goto MkDirRetry; |
694 | return rc; | 686 | return rc; |
695 | } | 687 | } |
696 | 688 | ||
689 | static __u16 convert_disposition(int disposition) | ||
690 | { | ||
691 | __u16 ofun = 0; | ||
692 | |||
693 | switch (disposition) { | ||
694 | case FILE_SUPERSEDE: | ||
695 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
696 | break; | ||
697 | case FILE_OPEN: | ||
698 | ofun = SMBOPEN_OAPPEND; | ||
699 | break; | ||
700 | case FILE_CREATE: | ||
701 | ofun = SMBOPEN_OCREATE; | ||
702 | break; | ||
703 | case FILE_OPEN_IF: | ||
704 | ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND; | ||
705 | break; | ||
706 | case FILE_OVERWRITE: | ||
707 | ofun = SMBOPEN_OTRUNC; | ||
708 | break; | ||
709 | case FILE_OVERWRITE_IF: | ||
710 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
711 | break; | ||
712 | default: | ||
713 | cFYI(1,("unknown disposition %d",disposition)); | ||
714 | ofun = SMBOPEN_OAPPEND; /* regular open */ | ||
715 | } | ||
716 | return ofun; | ||
717 | } | ||
718 | |||
719 | int | ||
720 | SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
721 | const char *fileName, const int openDisposition, | ||
722 | const int access_flags, const int create_options, __u16 * netfid, | ||
723 | int *pOplock, FILE_ALL_INFO * pfile_info, | ||
724 | const struct nls_table *nls_codepage, int remap) | ||
725 | { | ||
726 | int rc = -EACCES; | ||
727 | OPENX_REQ *pSMB = NULL; | ||
728 | OPENX_RSP *pSMBr = NULL; | ||
729 | int bytes_returned; | ||
730 | int name_len; | ||
731 | __u16 count; | ||
732 | |||
733 | OldOpenRetry: | ||
734 | rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, | ||
735 | (void **) &pSMBr); | ||
736 | if (rc) | ||
737 | return rc; | ||
738 | |||
739 | pSMB->AndXCommand = 0xFF; /* none */ | ||
740 | |||
741 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
742 | count = 1; /* account for one byte pad to word boundary */ | ||
743 | name_len = | ||
744 | cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), | ||
745 | fileName, PATH_MAX, nls_codepage, remap); | ||
746 | name_len++; /* trailing null */ | ||
747 | name_len *= 2; | ||
748 | } else { /* BB improve check for buffer overruns BB */ | ||
749 | count = 0; /* no pad */ | ||
750 | name_len = strnlen(fileName, PATH_MAX); | ||
751 | name_len++; /* trailing null */ | ||
752 | strncpy(pSMB->fileName, fileName, name_len); | ||
753 | } | ||
754 | if (*pOplock & REQ_OPLOCK) | ||
755 | pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); | ||
756 | else if (*pOplock & REQ_BATCHOPLOCK) { | ||
757 | pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); | ||
758 | } | ||
759 | pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); | ||
760 | /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ | ||
761 | /* 0 = read | ||
762 | 1 = write | ||
763 | 2 = rw | ||
764 | 3 = execute | ||
765 | */ | ||
766 | pSMB->Mode = cpu_to_le16(2); | ||
767 | pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ | ||
768 | /* set file as system file if special file such | ||
769 | as fifo and server expecting SFU style and | ||
770 | no Unix extensions */ | ||
771 | |||
772 | if(create_options & CREATE_OPTION_SPECIAL) | ||
773 | pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM); | ||
774 | else | ||
775 | pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */ | ||
776 | |||
777 | /* if ((omode & S_IWUGO) == 0) | ||
778 | pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ | ||
779 | /* Above line causes problems due to vfs splitting create into two | ||
780 | pieces - need to set mode after file created not while it is | ||
781 | being created */ | ||
782 | |||
783 | /* BB FIXME BB */ | ||
784 | /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */ | ||
785 | /* BB FIXME END BB */ | ||
786 | |||
787 | pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); | ||
788 | pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); | ||
789 | count += name_len; | ||
790 | pSMB->hdr.smb_buf_length += count; | ||
791 | |||
792 | pSMB->ByteCount = cpu_to_le16(count); | ||
793 | /* long_op set to 1 to allow for oplock break timeouts */ | ||
794 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
795 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | ||
796 | cifs_stats_inc(&tcon->num_opens); | ||
797 | if (rc) { | ||
798 | cFYI(1, ("Error in Open = %d", rc)); | ||
799 | } else { | ||
800 | /* BB verify if wct == 15 */ | ||
801 | |||
802 | /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ | ||
803 | |||
804 | *netfid = pSMBr->Fid; /* cifs fid stays in le */ | ||
805 | /* Let caller know file was created so we can set the mode. */ | ||
806 | /* Do we care about the CreateAction in any other cases? */ | ||
807 | /* BB FIXME BB */ | ||
808 | /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) | ||
809 | *pOplock |= CIFS_CREATE_ACTION; */ | ||
810 | /* BB FIXME END */ | ||
811 | |||
812 | if(pfile_info) { | ||
813 | pfile_info->CreationTime = 0; /* BB convert CreateTime*/ | ||
814 | pfile_info->LastAccessTime = 0; /* BB fixme */ | ||
815 | pfile_info->LastWriteTime = 0; /* BB fixme */ | ||
816 | pfile_info->ChangeTime = 0; /* BB fixme */ | ||
817 | pfile_info->Attributes = | ||
818 | cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); | ||
819 | /* the file_info buf is endian converted by caller */ | ||
820 | pfile_info->AllocationSize = | ||
821 | cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); | ||
822 | pfile_info->EndOfFile = pfile_info->AllocationSize; | ||
823 | pfile_info->NumberOfLinks = cpu_to_le32(1); | ||
824 | } | ||
825 | } | ||
826 | |||
827 | cifs_buf_release(pSMB); | ||
828 | if (rc == -EAGAIN) | ||
829 | goto OldOpenRetry; | ||
830 | return rc; | ||
831 | } | ||
832 | |||
697 | int | 833 | int |
698 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 834 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, |
699 | const char *fileName, const int openDisposition, | 835 | const char *fileName, const int openDisposition, |
@@ -738,7 +874,13 @@ openRetry: | |||
738 | } | 874 | } |
739 | pSMB->DesiredAccess = cpu_to_le32(access_flags); | 875 | pSMB->DesiredAccess = cpu_to_le32(access_flags); |
740 | pSMB->AllocationSize = 0; | 876 | pSMB->AllocationSize = 0; |
741 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | 877 | /* set file as system file if special file such |
878 | as fifo and server expecting SFU style and | ||
879 | no Unix extensions */ | ||
880 | if(create_options & CREATE_OPTION_SPECIAL) | ||
881 | pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); | ||
882 | else | ||
883 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | ||
742 | /* XP does not handle ATTR_POSIX_SEMANTICS */ | 884 | /* XP does not handle ATTR_POSIX_SEMANTICS */ |
743 | /* but it helps speed up case sensitive checks for other | 885 | /* but it helps speed up case sensitive checks for other |
744 | servers such as Samba */ | 886 | servers such as Samba */ |
@@ -752,7 +894,7 @@ openRetry: | |||
752 | being created */ | 894 | being created */ |
753 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); | 895 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); |
754 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); | 896 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); |
755 | pSMB->CreateOptions = cpu_to_le32(create_options); | 897 | pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); |
756 | /* BB Expirement with various impersonation levels and verify */ | 898 | /* BB Expirement with various impersonation levels and verify */ |
757 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); | 899 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); |
758 | pSMB->SecurityFlags = | 900 | pSMB->SecurityFlags = |
@@ -765,6 +907,7 @@ openRetry: | |||
765 | /* long_op set to 1 to allow for oplock break timeouts */ | 907 | /* long_op set to 1 to allow for oplock break timeouts */ |
766 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 908 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
767 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | 909 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); |
910 | cifs_stats_inc(&tcon->num_opens); | ||
768 | if (rc) { | 911 | if (rc) { |
769 | cFYI(1, ("Error in Open = %d", rc)); | 912 | cFYI(1, ("Error in Open = %d", rc)); |
770 | } else { | 913 | } else { |
@@ -782,11 +925,8 @@ openRetry: | |||
782 | pfile_info->EndOfFile = pSMBr->EndOfFile; | 925 | pfile_info->EndOfFile = pSMBr->EndOfFile; |
783 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 926 | pfile_info->NumberOfLinks = cpu_to_le32(1); |
784 | } | 927 | } |
785 | |||
786 | #ifdef CONFIG_CIFS_STATS | ||
787 | atomic_inc(&tcon->num_opens); | ||
788 | #endif | ||
789 | } | 928 | } |
929 | |||
790 | cifs_buf_release(pSMB); | 930 | cifs_buf_release(pSMB); |
791 | if (rc == -EAGAIN) | 931 | if (rc == -EAGAIN) |
792 | goto openRetry; | 932 | goto openRetry; |
@@ -807,11 +947,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
807 | READ_RSP *pSMBr = NULL; | 947 | READ_RSP *pSMBr = NULL; |
808 | char *pReadData = NULL; | 948 | char *pReadData = NULL; |
809 | int bytes_returned; | 949 | int bytes_returned; |
950 | int wct; | ||
810 | 951 | ||
811 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | 952 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); |
953 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
954 | wct = 12; | ||
955 | else | ||
956 | wct = 10; /* old style read */ | ||
812 | 957 | ||
813 | *nbytes = 0; | 958 | *nbytes = 0; |
814 | rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, | 959 | rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, |
815 | (void **) &pSMBr); | 960 | (void **) &pSMBr); |
816 | if (rc) | 961 | if (rc) |
817 | return rc; | 962 | return rc; |
@@ -823,14 +968,26 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
823 | pSMB->AndXCommand = 0xFF; /* none */ | 968 | pSMB->AndXCommand = 0xFF; /* none */ |
824 | pSMB->Fid = netfid; | 969 | pSMB->Fid = netfid; |
825 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 970 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); |
826 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 971 | if(wct == 12) |
972 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | ||
973 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ | ||
974 | return -EIO; | ||
975 | |||
827 | pSMB->Remaining = 0; | 976 | pSMB->Remaining = 0; |
828 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 977 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
829 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); | 978 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); |
830 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | 979 | if(wct == 12) |
831 | 980 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ | |
981 | else { | ||
982 | /* old style read */ | ||
983 | struct smb_com_readx_req * pSMBW = | ||
984 | (struct smb_com_readx_req *)pSMB; | ||
985 | pSMBW->ByteCount = 0; | ||
986 | } | ||
987 | |||
832 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 988 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
833 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 989 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
990 | cifs_stats_inc(&tcon->num_reads); | ||
834 | if (rc) { | 991 | if (rc) { |
835 | cERROR(1, ("Send error in read = %d", rc)); | 992 | cERROR(1, ("Send error in read = %d", rc)); |
836 | } else { | 993 | } else { |
@@ -876,12 +1033,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
876 | int rc = -EACCES; | 1033 | int rc = -EACCES; |
877 | WRITE_REQ *pSMB = NULL; | 1034 | WRITE_REQ *pSMB = NULL; |
878 | WRITE_RSP *pSMBr = NULL; | 1035 | WRITE_RSP *pSMBr = NULL; |
879 | int bytes_returned; | 1036 | int bytes_returned, wct; |
880 | __u32 bytes_sent; | 1037 | __u32 bytes_sent; |
881 | __u16 byte_count; | 1038 | __u16 byte_count; |
882 | 1039 | ||
883 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ | 1040 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ |
884 | rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, | 1041 | if(tcon->ses == NULL) |
1042 | return -ECONNABORTED; | ||
1043 | |||
1044 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
1045 | wct = 14; | ||
1046 | else | ||
1047 | wct = 12; | ||
1048 | |||
1049 | rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, | ||
885 | (void **) &pSMBr); | 1050 | (void **) &pSMBr); |
886 | if (rc) | 1051 | if (rc) |
887 | return rc; | 1052 | return rc; |
@@ -892,7 +1057,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
892 | pSMB->AndXCommand = 0xFF; /* none */ | 1057 | pSMB->AndXCommand = 0xFF; /* none */ |
893 | pSMB->Fid = netfid; | 1058 | pSMB->Fid = netfid; |
894 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1059 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
895 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1060 | if(wct == 14) |
1061 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
1062 | else if((offset >> 32) > 0) /* can not handle this big offset for old */ | ||
1063 | return -EIO; | ||
1064 | |||
896 | pSMB->Reserved = 0xFFFFFFFF; | 1065 | pSMB->Reserved = 0xFFFFFFFF; |
897 | pSMB->WriteMode = 0; | 1066 | pSMB->WriteMode = 0; |
898 | pSMB->Remaining = 0; | 1067 | pSMB->Remaining = 0; |
@@ -911,7 +1080,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
911 | if (bytes_sent > count) | 1080 | if (bytes_sent > count) |
912 | bytes_sent = count; | 1081 | bytes_sent = count; |
913 | pSMB->DataOffset = | 1082 | pSMB->DataOffset = |
914 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1083 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
915 | if(buf) | 1084 | if(buf) |
916 | memcpy(pSMB->Data,buf,bytes_sent); | 1085 | memcpy(pSMB->Data,buf,bytes_sent); |
917 | else if(ubuf) { | 1086 | else if(ubuf) { |
@@ -919,20 +1088,31 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
919 | cifs_buf_release(pSMB); | 1088 | cifs_buf_release(pSMB); |
920 | return -EFAULT; | 1089 | return -EFAULT; |
921 | } | 1090 | } |
922 | } else { | 1091 | } else if (count != 0) { |
923 | /* No buffer */ | 1092 | /* No buffer */ |
924 | cifs_buf_release(pSMB); | 1093 | cifs_buf_release(pSMB); |
925 | return -EINVAL; | 1094 | return -EINVAL; |
1095 | } /* else setting file size with write of zero bytes */ | ||
1096 | if(wct == 14) | ||
1097 | byte_count = bytes_sent + 1; /* pad */ | ||
1098 | else /* wct == 12 */ { | ||
1099 | byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ | ||
926 | } | 1100 | } |
927 | |||
928 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | ||
929 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1101 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
930 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | 1102 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
931 | pSMB->hdr.smb_buf_length += bytes_sent+1; | 1103 | pSMB->hdr.smb_buf_length += byte_count; |
932 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1104 | |
1105 | if(wct == 14) | ||
1106 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1107 | else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */ | ||
1108 | struct smb_com_writex_req * pSMBW = | ||
1109 | (struct smb_com_writex_req *)pSMB; | ||
1110 | pSMBW->ByteCount = cpu_to_le16(byte_count); | ||
1111 | } | ||
933 | 1112 | ||
934 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1113 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
935 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); | 1114 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); |
1115 | cifs_stats_inc(&tcon->num_writes); | ||
936 | if (rc) { | 1116 | if (rc) { |
937 | cFYI(1, ("Send error in write = %d", rc)); | 1117 | cFYI(1, ("Send error in write = %d", rc)); |
938 | *nbytes = 0; | 1118 | *nbytes = 0; |
@@ -951,56 +1131,72 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
951 | } | 1131 | } |
952 | 1132 | ||
953 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1133 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
954 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1134 | int |
1135 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
955 | const int netfid, const unsigned int count, | 1136 | const int netfid, const unsigned int count, |
956 | const __u64 offset, unsigned int *nbytes, const char __user *buf, | 1137 | const __u64 offset, unsigned int *nbytes, struct kvec *iov, |
957 | const int long_op) | 1138 | int n_vec, const int long_op) |
958 | { | 1139 | { |
959 | int rc = -EACCES; | 1140 | int rc = -EACCES; |
960 | WRITE_REQ *pSMB = NULL; | 1141 | WRITE_REQ *pSMB = NULL; |
961 | WRITE_RSP *pSMBr = NULL; | 1142 | int bytes_returned, wct; |
962 | /*int bytes_returned;*/ | 1143 | int smb_hdr_len; |
963 | unsigned bytes_sent; | ||
964 | __u16 byte_count; | ||
965 | 1144 | ||
966 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 1145 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ |
967 | 1146 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | |
1147 | wct = 14; | ||
1148 | else | ||
1149 | wct = 12; | ||
1150 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); | ||
968 | if (rc) | 1151 | if (rc) |
969 | return rc; | 1152 | return rc; |
970 | |||
971 | pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ | ||
972 | |||
973 | /* tcon and ses pointer are checked in smb_init */ | 1153 | /* tcon and ses pointer are checked in smb_init */ |
974 | if (tcon->ses->server == NULL) | 1154 | if (tcon->ses->server == NULL) |
975 | return -ECONNABORTED; | 1155 | return -ECONNABORTED; |
976 | 1156 | ||
977 | pSMB->AndXCommand = 0xFF; /* none */ | 1157 | pSMB->AndXCommand = 0xFF; /* none */ |
978 | pSMB->Fid = netfid; | 1158 | pSMB->Fid = netfid; |
979 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1159 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
980 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1160 | if(wct == 14) |
1161 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
1162 | else if((offset >> 32) > 0) /* can not handle this big offset for old */ | ||
1163 | return -EIO; | ||
981 | pSMB->Reserved = 0xFFFFFFFF; | 1164 | pSMB->Reserved = 0xFFFFFFFF; |
982 | pSMB->WriteMode = 0; | 1165 | pSMB->WriteMode = 0; |
983 | pSMB->Remaining = 0; | 1166 | pSMB->Remaining = 0; |
984 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; | 1167 | |
985 | if (bytes_sent > count) | ||
986 | bytes_sent = count; | ||
987 | pSMB->DataLengthHigh = 0; | ||
988 | pSMB->DataOffset = | 1168 | pSMB->DataOffset = |
989 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1169 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
990 | 1170 | ||
991 | byte_count = bytes_sent + 1 /* pad */ ; | 1171 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); |
992 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent); | 1172 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); |
993 | pSMB->DataLengthHigh = 0; | 1173 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
994 | pSMB->hdr.smb_buf_length += byte_count; | 1174 | if(wct == 14) |
995 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1175 | pSMB->hdr.smb_buf_length += count+1; |
1176 | else /* wct == 12 */ | ||
1177 | pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ | ||
1178 | if(wct == 14) | ||
1179 | pSMB->ByteCount = cpu_to_le16(count + 1); | ||
1180 | else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { | ||
1181 | struct smb_com_writex_req * pSMBW = | ||
1182 | (struct smb_com_writex_req *)pSMB; | ||
1183 | pSMBW->ByteCount = cpu_to_le16(count + 5); | ||
1184 | } | ||
1185 | iov[0].iov_base = pSMB; | ||
1186 | iov[0].iov_len = smb_hdr_len + 4; | ||
996 | 1187 | ||
997 | /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1188 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, |
998 | (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ | 1189 | long_op); |
1190 | cifs_stats_inc(&tcon->num_writes); | ||
999 | if (rc) { | 1191 | if (rc) { |
1000 | cFYI(1, ("Send error in write2 (large write) = %d", rc)); | 1192 | cFYI(1, ("Send error Write2 = %d", rc)); |
1001 | *nbytes = 0; | 1193 | *nbytes = 0; |
1002 | } else | 1194 | } else { |
1003 | *nbytes = le16_to_cpu(pSMBr->Count); | 1195 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; |
1196 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | ||
1197 | *nbytes = (*nbytes) << 16; | ||
1198 | *nbytes += le16_to_cpu(pSMBr->Count); | ||
1199 | } | ||
1004 | 1200 | ||
1005 | cifs_small_buf_release(pSMB); | 1201 | cifs_small_buf_release(pSMB); |
1006 | 1202 | ||
@@ -1009,6 +1205,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1009 | 1205 | ||
1010 | return rc; | 1206 | return rc; |
1011 | } | 1207 | } |
1208 | |||
1209 | |||
1012 | #endif /* CIFS_EXPERIMENTAL */ | 1210 | #endif /* CIFS_EXPERIMENTAL */ |
1013 | 1211 | ||
1014 | int | 1212 | int |
@@ -1065,7 +1263,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1065 | 1263 | ||
1066 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1264 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1067 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1265 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); |
1068 | 1266 | cifs_stats_inc(&tcon->num_locks); | |
1069 | if (rc) { | 1267 | if (rc) { |
1070 | cFYI(1, ("Send error in Lock = %d", rc)); | 1268 | cFYI(1, ("Send error in Lock = %d", rc)); |
1071 | } | 1269 | } |
@@ -1099,6 +1297,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
1099 | pSMB->ByteCount = 0; | 1297 | pSMB->ByteCount = 0; |
1100 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1298 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1101 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1299 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1300 | cifs_stats_inc(&tcon->num_closes); | ||
1102 | if (rc) { | 1301 | if (rc) { |
1103 | if(rc!=-EINTR) { | 1302 | if(rc!=-EINTR) { |
1104 | /* EINTR is expected when user ctl-c to kill app */ | 1303 | /* EINTR is expected when user ctl-c to kill app */ |
@@ -1171,16 +1370,11 @@ renameRetry: | |||
1171 | 1370 | ||
1172 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1371 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1173 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1372 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1373 | cifs_stats_inc(&tcon->num_renames); | ||
1174 | if (rc) { | 1374 | if (rc) { |
1175 | cFYI(1, ("Send error in rename = %d", rc)); | 1375 | cFYI(1, ("Send error in rename = %d", rc)); |
1176 | } | 1376 | } |
1177 | 1377 | ||
1178 | #ifdef CONFIG_CIFS_STATS | ||
1179 | else { | ||
1180 | atomic_inc(&tcon->num_renames); | ||
1181 | } | ||
1182 | #endif | ||
1183 | |||
1184 | cifs_buf_release(pSMB); | 1378 | cifs_buf_release(pSMB); |
1185 | 1379 | ||
1186 | if (rc == -EAGAIN) | 1380 | if (rc == -EAGAIN) |
@@ -1255,14 +1449,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | |||
1255 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1449 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1256 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | 1450 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, |
1257 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1451 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1452 | cifs_stats_inc(&pTcon->num_t2renames); | ||
1258 | if (rc) { | 1453 | if (rc) { |
1259 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); | 1454 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); |
1260 | } | 1455 | } |
1261 | #ifdef CONFIG_CIFS_STATS | 1456 | |
1262 | else { | ||
1263 | atomic_inc(&pTcon->num_t2renames); | ||
1264 | } | ||
1265 | #endif | ||
1266 | cifs_buf_release(pSMB); | 1457 | cifs_buf_release(pSMB); |
1267 | 1458 | ||
1268 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1459 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
@@ -1416,6 +1607,7 @@ createSymLinkRetry: | |||
1416 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1607 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1417 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1608 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1418 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1609 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1610 | cifs_stats_inc(&tcon->num_symlinks); | ||
1419 | if (rc) { | 1611 | if (rc) { |
1420 | cFYI(1, | 1612 | cFYI(1, |
1421 | ("Send error in SetPathInfo (create symlink) = %d", | 1613 | ("Send error in SetPathInfo (create symlink) = %d", |
@@ -1505,6 +1697,7 @@ createHardLinkRetry: | |||
1505 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1697 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1506 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1698 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1507 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1699 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1700 | cifs_stats_inc(&tcon->num_hardlinks); | ||
1508 | if (rc) { | 1701 | if (rc) { |
1509 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); | 1702 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); |
1510 | } | 1703 | } |
@@ -1575,6 +1768,7 @@ winCreateHardLinkRetry: | |||
1575 | 1768 | ||
1576 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1769 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1577 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1770 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1771 | cifs_stats_inc(&tcon->num_hardlinks); | ||
1578 | if (rc) { | 1772 | if (rc) { |
1579 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); | 1773 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); |
1580 | } | 1774 | } |
@@ -1775,8 +1969,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
1775 | } | 1969 | } |
1776 | } | 1970 | } |
1777 | qreparse_out: | 1971 | qreparse_out: |
1778 | if (pSMB) | 1972 | cifs_buf_release(pSMB); |
1779 | cifs_buf_release(pSMB); | ||
1780 | 1973 | ||
1781 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1974 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1782 | since file handle passed in no longer valid */ | 1975 | since file handle passed in no longer valid */ |
@@ -2165,6 +2358,67 @@ GetExtAttrOut: | |||
2165 | 2358 | ||
2166 | #endif /* CONFIG_POSIX */ | 2359 | #endif /* CONFIG_POSIX */ |
2167 | 2360 | ||
2361 | /* Legacy Query Path Information call for lookup to old servers such | ||
2362 | as Win9x/WinME */ | ||
2363 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
2364 | const unsigned char *searchName, | ||
2365 | FILE_ALL_INFO * pFinfo, | ||
2366 | const struct nls_table *nls_codepage, int remap) | ||
2367 | { | ||
2368 | QUERY_INFORMATION_REQ * pSMB; | ||
2369 | QUERY_INFORMATION_RSP * pSMBr; | ||
2370 | int rc = 0; | ||
2371 | int bytes_returned; | ||
2372 | int name_len; | ||
2373 | |||
2374 | cFYI(1, ("In SMBQPath path %s", searchName)); | ||
2375 | QInfRetry: | ||
2376 | rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, | ||
2377 | (void **) &pSMBr); | ||
2378 | if (rc) | ||
2379 | return rc; | ||
2380 | |||
2381 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2382 | name_len = | ||
2383 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | ||
2384 | PATH_MAX, nls_codepage, remap); | ||
2385 | name_len++; /* trailing null */ | ||
2386 | name_len *= 2; | ||
2387 | } else { | ||
2388 | name_len = strnlen(searchName, PATH_MAX); | ||
2389 | name_len++; /* trailing null */ | ||
2390 | strncpy(pSMB->FileName, searchName, name_len); | ||
2391 | } | ||
2392 | pSMB->BufferFormat = 0x04; | ||
2393 | name_len++; /* account for buffer type byte */ | ||
2394 | pSMB->hdr.smb_buf_length += (__u16) name_len; | ||
2395 | pSMB->ByteCount = cpu_to_le16(name_len); | ||
2396 | |||
2397 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2398 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2399 | if (rc) { | ||
2400 | cFYI(1, ("Send error in QueryInfo = %d", rc)); | ||
2401 | } else if (pFinfo) { /* decode response */ | ||
2402 | memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); | ||
2403 | pFinfo->AllocationSize = | ||
2404 | cpu_to_le64(le32_to_cpu(pSMBr->size)); | ||
2405 | pFinfo->EndOfFile = pFinfo->AllocationSize; | ||
2406 | pFinfo->Attributes = | ||
2407 | cpu_to_le32(le16_to_cpu(pSMBr->attr)); | ||
2408 | } else | ||
2409 | rc = -EIO; /* bad buffer passed in */ | ||
2410 | |||
2411 | cifs_buf_release(pSMB); | ||
2412 | |||
2413 | if (rc == -EAGAIN) | ||
2414 | goto QInfRetry; | ||
2415 | |||
2416 | return rc; | ||
2417 | } | ||
2418 | |||
2419 | |||
2420 | |||
2421 | |||
2168 | int | 2422 | int |
2169 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 2423 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, |
2170 | const unsigned char *searchName, | 2424 | const unsigned char *searchName, |
@@ -2396,7 +2650,7 @@ findUniqueRetry: | |||
2396 | if (rc) { | 2650 | if (rc) { |
2397 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); | 2651 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); |
2398 | } else { /* decode response */ | 2652 | } else { /* decode response */ |
2399 | 2653 | cifs_stats_inc(&tcon->num_ffirst); | |
2400 | /* BB fill in */ | 2654 | /* BB fill in */ |
2401 | } | 2655 | } |
2402 | 2656 | ||
@@ -2414,7 +2668,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | |||
2414 | const char *searchName, | 2668 | const char *searchName, |
2415 | const struct nls_table *nls_codepage, | 2669 | const struct nls_table *nls_codepage, |
2416 | __u16 * pnetfid, | 2670 | __u16 * pnetfid, |
2417 | struct cifs_search_info * psrch_inf, int remap) | 2671 | struct cifs_search_info * psrch_inf, int remap, const char dirsep) |
2418 | { | 2672 | { |
2419 | /* level 257 SMB_ */ | 2673 | /* level 257 SMB_ */ |
2420 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | 2674 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; |
@@ -2441,7 +2695,7 @@ findFirstRetry: | |||
2441 | it got remapped to 0xF03A as if it were part of the | 2695 | it got remapped to 0xF03A as if it were part of the |
2442 | directory name instead of a wildcard */ | 2696 | directory name instead of a wildcard */ |
2443 | name_len *= 2; | 2697 | name_len *= 2; |
2444 | pSMB->FileName[name_len] = '\\'; | 2698 | pSMB->FileName[name_len] = dirsep; |
2445 | pSMB->FileName[name_len+1] = 0; | 2699 | pSMB->FileName[name_len+1] = 0; |
2446 | pSMB->FileName[name_len+2] = '*'; | 2700 | pSMB->FileName[name_len+2] = '*'; |
2447 | pSMB->FileName[name_len+3] = 0; | 2701 | pSMB->FileName[name_len+3] = 0; |
@@ -2455,7 +2709,7 @@ findFirstRetry: | |||
2455 | if(name_len > buffersize-header) | 2709 | if(name_len > buffersize-header) |
2456 | free buffer exit; BB */ | 2710 | free buffer exit; BB */ |
2457 | strncpy(pSMB->FileName, searchName, name_len); | 2711 | strncpy(pSMB->FileName, searchName, name_len); |
2458 | pSMB->FileName[name_len] = '\\'; | 2712 | pSMB->FileName[name_len] = dirsep; |
2459 | pSMB->FileName[name_len+1] = '*'; | 2713 | pSMB->FileName[name_len+1] = '*'; |
2460 | pSMB->FileName[name_len+2] = 0; | 2714 | pSMB->FileName[name_len+2] = 0; |
2461 | name_len += 3; | 2715 | name_len += 3; |
@@ -2496,6 +2750,7 @@ findFirstRetry: | |||
2496 | 2750 | ||
2497 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2751 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2498 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2752 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2753 | cifs_stats_inc(&tcon->num_ffirst); | ||
2499 | 2754 | ||
2500 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ | 2755 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ |
2501 | /* BB Add code to handle unsupported level rc */ | 2756 | /* BB Add code to handle unsupported level rc */ |
@@ -2617,7 +2872,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
2617 | 2872 | ||
2618 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2873 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2619 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2874 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2620 | 2875 | cifs_stats_inc(&tcon->num_fnext); | |
2621 | if (rc) { | 2876 | if (rc) { |
2622 | if (rc == -EBADF) { | 2877 | if (rc == -EBADF) { |
2623 | psrch_inf->endOfSearch = TRUE; | 2878 | psrch_inf->endOfSearch = TRUE; |
@@ -2694,6 +2949,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle | |||
2694 | if (rc) { | 2949 | if (rc) { |
2695 | cERROR(1, ("Send error in FindClose = %d", rc)); | 2950 | cERROR(1, ("Send error in FindClose = %d", rc)); |
2696 | } | 2951 | } |
2952 | cifs_stats_inc(&tcon->num_fclose); | ||
2697 | cifs_small_buf_release(pSMB); | 2953 | cifs_small_buf_release(pSMB); |
2698 | 2954 | ||
2699 | /* Since session is dead, search handle closed on server already */ | 2955 | /* Since session is dead, search handle closed on server already */ |
@@ -2827,7 +3083,10 @@ getDFSRetry: | |||
2827 | (void **) &pSMBr); | 3083 | (void **) &pSMBr); |
2828 | if (rc) | 3084 | if (rc) |
2829 | return rc; | 3085 | return rc; |
2830 | 3086 | ||
3087 | /* server pointer checked in called function, | ||
3088 | but should never be null here anyway */ | ||
3089 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
2831 | pSMB->hdr.Tid = ses->ipc_tid; | 3090 | pSMB->hdr.Tid = ses->ipc_tid; |
2832 | pSMB->hdr.Uid = ses->Suid; | 3091 | pSMB->hdr.Uid = ses->Suid; |
2833 | if (ses->capabilities & CAP_STATUS32) { | 3092 | if (ses->capabilities & CAP_STATUS32) { |
@@ -2968,6 +3227,92 @@ GetDFSRefExit: | |||
2968 | return rc; | 3227 | return rc; |
2969 | } | 3228 | } |
2970 | 3229 | ||
3230 | /* Query File System Info such as free space to old servers such as Win 9x */ | ||
3231 | int | ||
3232 | SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | ||
3233 | { | ||
3234 | /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ | ||
3235 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
3236 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
3237 | FILE_SYSTEM_ALLOC_INFO *response_data; | ||
3238 | int rc = 0; | ||
3239 | int bytes_returned = 0; | ||
3240 | __u16 params, byte_count; | ||
3241 | |||
3242 | cFYI(1, ("OldQFSInfo")); | ||
3243 | oldQFSInfoRetry: | ||
3244 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3245 | (void **) &pSMBr); | ||
3246 | if (rc) | ||
3247 | return rc; | ||
3248 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3249 | (void **) &pSMBr); | ||
3250 | if (rc) | ||
3251 | return rc; | ||
3252 | |||
3253 | params = 2; /* level */ | ||
3254 | pSMB->TotalDataCount = 0; | ||
3255 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3256 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
3257 | pSMB->MaxSetupCount = 0; | ||
3258 | pSMB->Reserved = 0; | ||
3259 | pSMB->Flags = 0; | ||
3260 | pSMB->Timeout = 0; | ||
3261 | pSMB->Reserved2 = 0; | ||
3262 | byte_count = params + 1 /* pad */ ; | ||
3263 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
3264 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3265 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
3266 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
3267 | pSMB->DataCount = 0; | ||
3268 | pSMB->DataOffset = 0; | ||
3269 | pSMB->SetupCount = 1; | ||
3270 | pSMB->Reserved3 = 0; | ||
3271 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
3272 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); | ||
3273 | pSMB->hdr.smb_buf_length += byte_count; | ||
3274 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3275 | |||
3276 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3277 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3278 | if (rc) { | ||
3279 | cFYI(1, ("Send error in QFSInfo = %d", rc)); | ||
3280 | } else { /* decode response */ | ||
3281 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3282 | |||
3283 | if (rc || (pSMBr->ByteCount < 18)) | ||
3284 | rc = -EIO; /* bad smb */ | ||
3285 | else { | ||
3286 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3287 | cFYI(1,("qfsinf resp BCC: %d Offset %d", | ||
3288 | pSMBr->ByteCount, data_offset)); | ||
3289 | |||
3290 | response_data = | ||
3291 | (FILE_SYSTEM_ALLOC_INFO *) | ||
3292 | (((char *) &pSMBr->hdr.Protocol) + data_offset); | ||
3293 | FSData->f_bsize = | ||
3294 | le16_to_cpu(response_data->BytesPerSector) * | ||
3295 | le32_to_cpu(response_data-> | ||
3296 | SectorsPerAllocationUnit); | ||
3297 | FSData->f_blocks = | ||
3298 | le32_to_cpu(response_data->TotalAllocationUnits); | ||
3299 | FSData->f_bfree = FSData->f_bavail = | ||
3300 | le32_to_cpu(response_data->FreeAllocationUnits); | ||
3301 | cFYI(1, | ||
3302 | ("Blocks: %lld Free: %lld Block size %ld", | ||
3303 | (unsigned long long)FSData->f_blocks, | ||
3304 | (unsigned long long)FSData->f_bfree, | ||
3305 | FSData->f_bsize)); | ||
3306 | } | ||
3307 | } | ||
3308 | cifs_buf_release(pSMB); | ||
3309 | |||
3310 | if (rc == -EAGAIN) | ||
3311 | goto oldQFSInfoRetry; | ||
3312 | |||
3313 | return rc; | ||
3314 | } | ||
3315 | |||
2971 | int | 3316 | int |
2972 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | 3317 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) |
2973 | { | 3318 | { |
@@ -2989,7 +3334,7 @@ QFSInfoRetry: | |||
2989 | params = 2; /* level */ | 3334 | params = 2; /* level */ |
2990 | pSMB->TotalDataCount = 0; | 3335 | pSMB->TotalDataCount = 0; |
2991 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3336 | pSMB->MaxParameterCount = cpu_to_le16(2); |
2992 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 3337 | pSMB->MaxDataCount = cpu_to_le16(1000); |
2993 | pSMB->MaxSetupCount = 0; | 3338 | pSMB->MaxSetupCount = 0; |
2994 | pSMB->Reserved = 0; | 3339 | pSMB->Reserved = 0; |
2995 | pSMB->Flags = 0; | 3340 | pSMB->Flags = 0; |
@@ -3012,17 +3357,14 @@ QFSInfoRetry: | |||
3012 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3357 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
3013 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3358 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
3014 | if (rc) { | 3359 | if (rc) { |
3015 | cERROR(1, ("Send error in QFSInfo = %d", rc)); | 3360 | cFYI(1, ("Send error in QFSInfo = %d", rc)); |
3016 | } else { /* decode response */ | 3361 | } else { /* decode response */ |
3017 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3362 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
3018 | 3363 | ||
3019 | if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ | 3364 | if (rc || (pSMBr->ByteCount < 24)) |
3020 | rc = -EIO; /* bad smb */ | 3365 | rc = -EIO; /* bad smb */ |
3021 | else { | 3366 | else { |
3022 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 3367 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
3023 | cFYI(1, | ||
3024 | ("Decoding qfsinfo response. BCC: %d Offset %d", | ||
3025 | pSMBr->ByteCount, data_offset)); | ||
3026 | 3368 | ||
3027 | response_data = | 3369 | response_data = |
3028 | (FILE_SYSTEM_INFO | 3370 | (FILE_SYSTEM_INFO |
@@ -3257,6 +3599,77 @@ QFSUnixRetry: | |||
3257 | return rc; | 3599 | return rc; |
3258 | } | 3600 | } |
3259 | 3601 | ||
3602 | int | ||
3603 | CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) | ||
3604 | { | ||
3605 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ | ||
3606 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | ||
3607 | TRANSACTION2_SETFSI_RSP *pSMBr = NULL; | ||
3608 | int rc = 0; | ||
3609 | int bytes_returned = 0; | ||
3610 | __u16 params, param_offset, offset, byte_count; | ||
3611 | |||
3612 | cFYI(1, ("In SETFSUnixInfo")); | ||
3613 | SETFSUnixRetry: | ||
3614 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3615 | (void **) &pSMBr); | ||
3616 | if (rc) | ||
3617 | return rc; | ||
3618 | |||
3619 | params = 4; /* 2 bytes zero followed by info level. */ | ||
3620 | pSMB->MaxSetupCount = 0; | ||
3621 | pSMB->Reserved = 0; | ||
3622 | pSMB->Flags = 0; | ||
3623 | pSMB->Timeout = 0; | ||
3624 | pSMB->Reserved2 = 0; | ||
3625 | param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4; | ||
3626 | offset = param_offset + params; | ||
3627 | |||
3628 | pSMB->MaxParameterCount = cpu_to_le16(4); | ||
3629 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
3630 | pSMB->SetupCount = 1; | ||
3631 | pSMB->Reserved3 = 0; | ||
3632 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | ||
3633 | byte_count = 1 /* pad */ + params + 12; | ||
3634 | |||
3635 | pSMB->DataCount = cpu_to_le16(12); | ||
3636 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3637 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3638 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3639 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3640 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3641 | |||
3642 | /* Params. */ | ||
3643 | pSMB->FileNum = 0; | ||
3644 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); | ||
3645 | |||
3646 | /* Data. */ | ||
3647 | pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); | ||
3648 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | ||
3649 | pSMB->ClientUnixCap = cpu_to_le64(cap); | ||
3650 | |||
3651 | pSMB->hdr.smb_buf_length += byte_count; | ||
3652 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3653 | |||
3654 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3655 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3656 | if (rc) { | ||
3657 | cERROR(1, ("Send error in SETFSUnixInfo = %d", rc)); | ||
3658 | } else { /* decode response */ | ||
3659 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3660 | if (rc) { | ||
3661 | rc = -EIO; /* bad smb */ | ||
3662 | } | ||
3663 | } | ||
3664 | cifs_buf_release(pSMB); | ||
3665 | |||
3666 | if (rc == -EAGAIN) | ||
3667 | goto SETFSUnixRetry; | ||
3668 | |||
3669 | return rc; | ||
3670 | } | ||
3671 | |||
3672 | |||
3260 | 3673 | ||
3261 | int | 3674 | int |
3262 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 3675 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |
@@ -3321,16 +3734,16 @@ QFSPosixRetry: | |||
3321 | le64_to_cpu(response_data->TotalBlocks); | 3734 | le64_to_cpu(response_data->TotalBlocks); |
3322 | FSData->f_bfree = | 3735 | FSData->f_bfree = |
3323 | le64_to_cpu(response_data->BlocksAvail); | 3736 | le64_to_cpu(response_data->BlocksAvail); |
3324 | if(response_data->UserBlocksAvail == -1) { | 3737 | if(response_data->UserBlocksAvail == cpu_to_le64(-1)) { |
3325 | FSData->f_bavail = FSData->f_bfree; | 3738 | FSData->f_bavail = FSData->f_bfree; |
3326 | } else { | 3739 | } else { |
3327 | FSData->f_bavail = | 3740 | FSData->f_bavail = |
3328 | le64_to_cpu(response_data->UserBlocksAvail); | 3741 | le64_to_cpu(response_data->UserBlocksAvail); |
3329 | } | 3742 | } |
3330 | if(response_data->TotalFileNodes != -1) | 3743 | if(response_data->TotalFileNodes != cpu_to_le64(-1)) |
3331 | FSData->f_files = | 3744 | FSData->f_files = |
3332 | le64_to_cpu(response_data->TotalFileNodes); | 3745 | le64_to_cpu(response_data->TotalFileNodes); |
3333 | if(response_data->FreeFileNodes != -1) | 3746 | if(response_data->FreeFileNodes != cpu_to_le64(-1)) |
3334 | FSData->f_ffree = | 3747 | FSData->f_ffree = |
3335 | le64_to_cpu(response_data->FreeFileNodes); | 3748 | le64_to_cpu(response_data->FreeFileNodes); |
3336 | } | 3749 | } |
@@ -3376,7 +3789,7 @@ SetEOFRetry: | |||
3376 | PATH_MAX, nls_codepage, remap); | 3789 | PATH_MAX, nls_codepage, remap); |
3377 | name_len++; /* trailing null */ | 3790 | name_len++; /* trailing null */ |
3378 | name_len *= 2; | 3791 | name_len *= 2; |
3379 | } else { /* BB improve the check for buffer overruns BB */ | 3792 | } else { /* BB improve the check for buffer overruns BB */ |
3380 | name_len = strnlen(fileName, PATH_MAX); | 3793 | name_len = strnlen(fileName, PATH_MAX); |
3381 | name_len++; /* trailing null */ | 3794 | name_len++; /* trailing null */ |
3382 | strncpy(pSMB->FileName, fileName, name_len); | 3795 | strncpy(pSMB->FileName, fileName, name_len); |
@@ -3384,7 +3797,7 @@ SetEOFRetry: | |||
3384 | params = 6 + name_len; | 3797 | params = 6 + name_len; |
3385 | data_count = sizeof (struct file_end_of_file_info); | 3798 | data_count = sizeof (struct file_end_of_file_info); |
3386 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3799 | pSMB->MaxParameterCount = cpu_to_le16(2); |
3387 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | 3800 | pSMB->MaxDataCount = cpu_to_le16(4100); |
3388 | pSMB->MaxSetupCount = 0; | 3801 | pSMB->MaxSetupCount = 0; |
3389 | pSMB->Reserved = 0; | 3802 | pSMB->Reserved = 0; |
3390 | pSMB->Flags = 0; | 3803 | pSMB->Flags = 0; |
@@ -3766,7 +4179,7 @@ setPermsRetry: | |||
3766 | PATH_MAX, nls_codepage, remap); | 4179 | PATH_MAX, nls_codepage, remap); |
3767 | name_len++; /* trailing null */ | 4180 | name_len++; /* trailing null */ |
3768 | name_len *= 2; | 4181 | name_len *= 2; |
3769 | } else { /* BB improve the check for buffer overruns BB */ | 4182 | } else { /* BB improve the check for buffer overruns BB */ |
3770 | name_len = strnlen(fileName, PATH_MAX); | 4183 | name_len = strnlen(fileName, PATH_MAX); |
3771 | name_len++; /* trailing null */ | 4184 | name_len++; /* trailing null */ |
3772 | strncpy(pSMB->FileName, fileName, name_len); | 4185 | strncpy(pSMB->FileName, fileName, name_len); |
@@ -3839,12 +4252,14 @@ setPermsRetry: | |||
3839 | } | 4252 | } |
3840 | 4253 | ||
3841 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 4254 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
3842 | const int notify_subdirs, const __u16 netfid, | 4255 | const int notify_subdirs, const __u16 netfid, |
3843 | __u32 filter, const struct nls_table *nls_codepage) | 4256 | __u32 filter, struct file * pfile, int multishot, |
4257 | const struct nls_table *nls_codepage) | ||
3844 | { | 4258 | { |
3845 | int rc = 0; | 4259 | int rc = 0; |
3846 | struct smb_com_transaction_change_notify_req * pSMB = NULL; | 4260 | struct smb_com_transaction_change_notify_req * pSMB = NULL; |
3847 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; | 4261 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; |
4262 | struct dir_notify_req *dnotify_req; | ||
3848 | int bytes_returned; | 4263 | int bytes_returned; |
3849 | 4264 | ||
3850 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); | 4265 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); |
@@ -3877,6 +4292,28 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
3877 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); | 4292 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); |
3878 | if (rc) { | 4293 | if (rc) { |
3879 | cFYI(1, ("Error in Notify = %d", rc)); | 4294 | cFYI(1, ("Error in Notify = %d", rc)); |
4295 | } else { | ||
4296 | /* Add file to outstanding requests */ | ||
4297 | /* BB change to kmem cache alloc */ | ||
4298 | dnotify_req = (struct dir_notify_req *) kmalloc( | ||
4299 | sizeof(struct dir_notify_req), | ||
4300 | GFP_KERNEL); | ||
4301 | if(dnotify_req) { | ||
4302 | dnotify_req->Pid = pSMB->hdr.Pid; | ||
4303 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | ||
4304 | dnotify_req->Mid = pSMB->hdr.Mid; | ||
4305 | dnotify_req->Tid = pSMB->hdr.Tid; | ||
4306 | dnotify_req->Uid = pSMB->hdr.Uid; | ||
4307 | dnotify_req->netfid = netfid; | ||
4308 | dnotify_req->pfile = pfile; | ||
4309 | dnotify_req->filter = filter; | ||
4310 | dnotify_req->multishot = multishot; | ||
4311 | spin_lock(&GlobalMid_Lock); | ||
4312 | list_add_tail(&dnotify_req->lhead, | ||
4313 | &GlobalDnotifyReqList); | ||
4314 | spin_unlock(&GlobalMid_Lock); | ||
4315 | } else | ||
4316 | rc = -ENOMEM; | ||
3880 | } | 4317 | } |
3881 | cifs_buf_release(pSMB); | 4318 | cifs_buf_release(pSMB); |
3882 | return rc; | 4319 | return rc; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 47360156cc54..d74367a08d51 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
30 | #include <linux/mempool.h> | 30 | #include <linux/mempool.h> |
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/completion.h> | ||
33 | #include <linux/pagevec.h> | ||
32 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
33 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
34 | #include "cifspdu.h" | 36 | #include "cifspdu.h" |
@@ -44,6 +46,8 @@ | |||
44 | #define CIFS_PORT 445 | 46 | #define CIFS_PORT 445 |
45 | #define RFC1001_PORT 139 | 47 | #define RFC1001_PORT 139 |
46 | 48 | ||
49 | static DECLARE_COMPLETION(cifsd_complete); | ||
50 | |||
47 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | 51 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, |
48 | unsigned char *p24); | 52 | unsigned char *p24); |
49 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 53 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
@@ -60,6 +64,7 @@ struct smb_vol { | |||
60 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ | 64 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ |
61 | char *iocharset; /* local code page for mapping to and from Unicode */ | 65 | char *iocharset; /* local code page for mapping to and from Unicode */ |
62 | char source_rfc1001_name[16]; /* netbios name of client */ | 66 | char source_rfc1001_name[16]; /* netbios name of client */ |
67 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | ||
63 | uid_t linux_uid; | 68 | uid_t linux_uid; |
64 | gid_t linux_gid; | 69 | gid_t linux_gid; |
65 | mode_t file_mode; | 70 | mode_t file_mode; |
@@ -74,6 +79,10 @@ struct smb_vol { | |||
74 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | 79 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ |
75 | unsigned direct_io:1; | 80 | unsigned direct_io:1; |
76 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | 81 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ |
82 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | ||
83 | unsigned sfu_emul:1; | ||
84 | unsigned nocase; /* request case insensitive filenames */ | ||
85 | unsigned nobrl; /* disable sending byte range locks to srv */ | ||
77 | unsigned int rsize; | 86 | unsigned int rsize; |
78 | unsigned int wsize; | 87 | unsigned int wsize; |
79 | unsigned int sockopt; | 88 | unsigned int sockopt; |
@@ -82,7 +91,8 @@ struct smb_vol { | |||
82 | 91 | ||
83 | static int ipv4_connect(struct sockaddr_in *psin_server, | 92 | static int ipv4_connect(struct sockaddr_in *psin_server, |
84 | struct socket **csocket, | 93 | struct socket **csocket, |
85 | char * netb_name); | 94 | char * netb_name, |
95 | char * server_netb_name); | ||
86 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | 96 | static int ipv6_connect(struct sockaddr_in6 *psin_server, |
87 | struct socket **csocket); | 97 | struct socket **csocket); |
88 | 98 | ||
@@ -175,9 +185,11 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
175 | } else { | 185 | } else { |
176 | rc = ipv4_connect(&server->addr.sockAddr, | 186 | rc = ipv4_connect(&server->addr.sockAddr, |
177 | &server->ssocket, | 187 | &server->ssocket, |
178 | server->workstation_RFC1001_name); | 188 | server->workstation_RFC1001_name, |
189 | server->server_RFC1001_name); | ||
179 | } | 190 | } |
180 | if(rc) { | 191 | if(rc) { |
192 | cFYI(1,("reconnect error %d",rc)); | ||
181 | msleep(3000); | 193 | msleep(3000); |
182 | } else { | 194 | } else { |
183 | atomic_inc(&tcpSesReconnectCount); | 195 | atomic_inc(&tcpSesReconnectCount); |
@@ -293,12 +305,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) | |||
293 | byte_count += total_in_buf2; | 305 | byte_count += total_in_buf2; |
294 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | 306 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); |
295 | 307 | ||
296 | byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); | 308 | byte_count = pTargetSMB->smb_buf_length; |
297 | byte_count += total_in_buf2; | 309 | byte_count += total_in_buf2; |
298 | 310 | ||
299 | /* BB also add check that we are not beyond maximum buffer size */ | 311 | /* BB also add check that we are not beyond maximum buffer size */ |
300 | 312 | ||
301 | pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); | 313 | pTargetSMB->smb_buf_length = byte_count; |
302 | 314 | ||
303 | if(remaining == total_in_buf2) { | 315 | if(remaining == total_in_buf2) { |
304 | cFYI(1,("found the last secondary response")); | 316 | cFYI(1,("found the last secondary response")); |
@@ -323,7 +335,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
323 | struct cifsSesInfo *ses; | 335 | struct cifsSesInfo *ses; |
324 | struct task_struct *task_to_wake = NULL; | 336 | struct task_struct *task_to_wake = NULL; |
325 | struct mid_q_entry *mid_entry; | 337 | struct mid_q_entry *mid_entry; |
326 | char *temp; | 338 | char temp; |
327 | int isLargeBuf = FALSE; | 339 | int isLargeBuf = FALSE; |
328 | int isMultiRsp; | 340 | int isMultiRsp; |
329 | int reconnect; | 341 | int reconnect; |
@@ -337,6 +349,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
337 | atomic_inc(&tcpSesAllocCount); | 349 | atomic_inc(&tcpSesAllocCount); |
338 | length = tcpSesAllocCount.counter; | 350 | length = tcpSesAllocCount.counter; |
339 | write_unlock(&GlobalSMBSeslock); | 351 | write_unlock(&GlobalSMBSeslock); |
352 | complete(&cifsd_complete); | ||
340 | if(length > 1) { | 353 | if(length > 1) { |
341 | mempool_resize(cifs_req_poolp, | 354 | mempool_resize(cifs_req_poolp, |
342 | length + cifs_min_rcv, | 355 | length + cifs_min_rcv, |
@@ -424,22 +437,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
424 | continue; | 437 | continue; |
425 | } | 438 | } |
426 | 439 | ||
427 | /* the right amount was read from socket - 4 bytes */ | 440 | /* The right amount was read from socket - 4 bytes */ |
441 | /* so we can now interpret the length field */ | ||
442 | |||
443 | /* the first byte big endian of the length field, | ||
444 | is actually not part of the length but the type | ||
445 | with the most common, zero, as regular data */ | ||
446 | temp = *((char *) smb_buffer); | ||
428 | 447 | ||
448 | /* Note that FC 1001 length is big endian on the wire, | ||
449 | but we convert it here so it is always manipulated | ||
450 | as host byte order */ | ||
429 | pdu_length = ntohl(smb_buffer->smb_buf_length); | 451 | pdu_length = ntohl(smb_buffer->smb_buf_length); |
430 | cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); | 452 | smb_buffer->smb_buf_length = pdu_length; |
453 | |||
454 | cFYI(1,("rfc1002 length 0x%x)", pdu_length+4)); | ||
431 | 455 | ||
432 | temp = (char *) smb_buffer; | 456 | if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { |
433 | if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { | ||
434 | continue; | 457 | continue; |
435 | } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { | 458 | } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { |
436 | cFYI(1,("Good RFC 1002 session rsp")); | 459 | cFYI(1,("Good RFC 1002 session rsp")); |
437 | continue; | 460 | continue; |
438 | } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { | 461 | } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { |
439 | /* we get this from Windows 98 instead of | 462 | /* we get this from Windows 98 instead of |
440 | an error on SMB negprot response */ | 463 | an error on SMB negprot response */ |
441 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", | 464 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", |
442 | temp[4])); | 465 | pdu_length)); |
443 | if(server->tcpStatus == CifsNew) { | 466 | if(server->tcpStatus == CifsNew) { |
444 | /* if nack on negprot (rather than | 467 | /* if nack on negprot (rather than |
445 | ret of smb negprot error) reconnecting | 468 | ret of smb negprot error) reconnecting |
@@ -461,9 +484,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
461 | wake_up(&server->response_q); | 484 | wake_up(&server->response_q); |
462 | continue; | 485 | continue; |
463 | } | 486 | } |
464 | } else if (temp[0] != (char) 0) { | 487 | } else if (temp != (char) 0) { |
465 | cERROR(1,("Unknown RFC 1002 frame")); | 488 | cERROR(1,("Unknown RFC 1002 frame")); |
466 | cifs_dump_mem(" Received Data: ", temp, length); | 489 | cifs_dump_mem(" Received Data: ", (char *)smb_buffer, |
490 | length); | ||
467 | cifs_reconnect(server); | 491 | cifs_reconnect(server); |
468 | csocket = server->ssocket; | 492 | csocket = server->ssocket; |
469 | continue; | 493 | continue; |
@@ -533,7 +557,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
533 | 557 | ||
534 | dump_smb(smb_buffer, length); | 558 | dump_smb(smb_buffer, length); |
535 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { | 559 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { |
536 | cERROR(1, ("Bad SMB Received ")); | 560 | cifs_dump_mem("Bad SMB: ", smb_buffer, 48); |
537 | continue; | 561 | continue; |
538 | } | 562 | } |
539 | 563 | ||
@@ -581,6 +605,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
581 | multi_t2_fnd: | 605 | multi_t2_fnd: |
582 | task_to_wake = mid_entry->tsk; | 606 | task_to_wake = mid_entry->tsk; |
583 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 607 | mid_entry->midState = MID_RESPONSE_RECEIVED; |
608 | #ifdef CONFIG_CIFS_STATS2 | ||
609 | mid_entry->when_received = jiffies; | ||
610 | #endif | ||
584 | break; | 611 | break; |
585 | } | 612 | } |
586 | } | 613 | } |
@@ -598,7 +625,8 @@ multi_t2_fnd: | |||
598 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) | 625 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) |
599 | && (isMultiRsp == FALSE)) { | 626 | && (isMultiRsp == FALSE)) { |
600 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | 627 | cERROR(1, ("No task to wake, unknown frame rcvd!")); |
601 | cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); | 628 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, |
629 | sizeof(struct smb_hdr)); | ||
602 | } | 630 | } |
603 | } /* end while !EXITING */ | 631 | } /* end while !EXITING */ |
604 | 632 | ||
@@ -676,7 +704,7 @@ multi_t2_fnd: | |||
676 | msleep(125); | 704 | msleep(125); |
677 | } | 705 | } |
678 | 706 | ||
679 | if (list_empty(&server->pending_mid_q)) { | 707 | if (!list_empty(&server->pending_mid_q)) { |
680 | /* mpx threads have not exited yet give them | 708 | /* mpx threads have not exited yet give them |
681 | at least the smb send timeout time for long ops */ | 709 | at least the smb send timeout time for long ops */ |
682 | /* due to delays on oplock break requests, we need | 710 | /* due to delays on oplock break requests, we need |
@@ -713,7 +741,7 @@ multi_t2_fnd: | |||
713 | GFP_KERNEL); | 741 | GFP_KERNEL); |
714 | } | 742 | } |
715 | 743 | ||
716 | msleep(250); | 744 | complete_and_exit(&cifsd_complete, 0); |
717 | return 0; | 745 | return 0; |
718 | } | 746 | } |
719 | 747 | ||
@@ -737,7 +765,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
737 | toupper(system_utsname.nodename[i]); | 765 | toupper(system_utsname.nodename[i]); |
738 | } | 766 | } |
739 | vol->source_rfc1001_name[15] = 0; | 767 | vol->source_rfc1001_name[15] = 0; |
740 | 768 | /* null target name indicates to use *SMBSERVR default called name | |
769 | if we end up sending RFC1001 session initialize */ | ||
770 | vol->target_rfc1001_name[0] = 0; | ||
741 | vol->linux_uid = current->uid; /* current->euid instead? */ | 771 | vol->linux_uid = current->uid; /* current->euid instead? */ |
742 | vol->linux_gid = current->gid; | 772 | vol->linux_gid = current->gid; |
743 | vol->dir_mode = S_IRWXUGO; | 773 | vol->dir_mode = S_IRWXUGO; |
@@ -747,6 +777,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
747 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 777 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
748 | vol->rw = TRUE; | 778 | vol->rw = TRUE; |
749 | 779 | ||
780 | /* default is always to request posix paths. */ | ||
781 | vol->posix_paths = 1; | ||
782 | |||
750 | if (!options) | 783 | if (!options) |
751 | return 1; | 784 | return 1; |
752 | 785 | ||
@@ -987,7 +1020,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
987 | /* The string has 16th byte zero still from | 1020 | /* The string has 16th byte zero still from |
988 | set at top of the function */ | 1021 | set at top of the function */ |
989 | if((i==15) && (value[i] != 0)) | 1022 | if((i==15) && (value[i] != 0)) |
990 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); | 1023 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n"); |
1024 | } | ||
1025 | } else if (strnicmp(data, "servern", 7) == 0) { | ||
1026 | /* servernetbiosname specified override *SMBSERVER */ | ||
1027 | if (!value || !*value || (*value == ' ')) { | ||
1028 | cFYI(1,("empty server netbiosname specified")); | ||
1029 | } else { | ||
1030 | /* last byte, type, is 0x20 for servr type */ | ||
1031 | memset(vol->target_rfc1001_name,0x20,16); | ||
1032 | |||
1033 | for(i=0;i<15;i++) { | ||
1034 | /* BB are there cases in which a comma can be | ||
1035 | valid in this workstation netbios name (and need | ||
1036 | special handling)? */ | ||
1037 | |||
1038 | /* user or mount helper must uppercase netbiosname */ | ||
1039 | if (value[i]==0) | ||
1040 | break; | ||
1041 | else | ||
1042 | vol->target_rfc1001_name[i] = value[i]; | ||
1043 | } | ||
1044 | /* The string has 16th byte zero still from | ||
1045 | set at top of the function */ | ||
1046 | if((i==15) && (value[i] != 0)) | ||
1047 | printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n"); | ||
991 | } | 1048 | } |
992 | } else if (strnicmp(data, "credentials", 4) == 0) { | 1049 | } else if (strnicmp(data, "credentials", 4) == 0) { |
993 | /* ignore */ | 1050 | /* ignore */ |
@@ -1025,6 +1082,27 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
1025 | vol->remap = 1; | 1082 | vol->remap = 1; |
1026 | } else if (strnicmp(data, "nomapchars", 10) == 0) { | 1083 | } else if (strnicmp(data, "nomapchars", 10) == 0) { |
1027 | vol->remap = 0; | 1084 | vol->remap = 0; |
1085 | } else if (strnicmp(data, "sfu", 3) == 0) { | ||
1086 | vol->sfu_emul = 1; | ||
1087 | } else if (strnicmp(data, "nosfu", 5) == 0) { | ||
1088 | vol->sfu_emul = 0; | ||
1089 | } else if (strnicmp(data, "posixpaths", 10) == 0) { | ||
1090 | vol->posix_paths = 1; | ||
1091 | } else if (strnicmp(data, "noposixpaths", 12) == 0) { | ||
1092 | vol->posix_paths = 0; | ||
1093 | } else if ((strnicmp(data, "nocase", 6) == 0) || | ||
1094 | (strnicmp(data, "ignorecase", 10) == 0)) { | ||
1095 | vol->nocase = 1; | ||
1096 | } else if (strnicmp(data, "brl", 3) == 0) { | ||
1097 | vol->nobrl = 0; | ||
1098 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | ||
1099 | (strnicmp(data, "nolock", 6) == 0)) { | ||
1100 | vol->nobrl = 1; | ||
1101 | /* turn off mandatory locking in mode | ||
1102 | if remote locking is turned off since the | ||
1103 | local vfs will do advisory */ | ||
1104 | if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) | ||
1105 | vol->file_mode = S_IALLUGO; | ||
1028 | } else if (strnicmp(data, "setuids", 7) == 0) { | 1106 | } else if (strnicmp(data, "setuids", 7) == 0) { |
1029 | vol->setuids = 1; | 1107 | vol->setuids = 1; |
1030 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1108 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
@@ -1244,7 +1322,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length) | |||
1244 | 1322 | ||
1245 | static int | 1323 | static int |
1246 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | 1324 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, |
1247 | char * netbios_name) | 1325 | char * netbios_name, char * target_name) |
1248 | { | 1326 | { |
1249 | int rc = 0; | 1327 | int rc = 0; |
1250 | int connected = 0; | 1328 | int connected = 0; |
@@ -1309,10 +1387,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1309 | /* Eventually check for other socket options to change from | 1387 | /* Eventually check for other socket options to change from |
1310 | the default. sock_setsockopt not used because it expects | 1388 | the default. sock_setsockopt not used because it expects |
1311 | user space buffer */ | 1389 | user space buffer */ |
1390 | cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf, | ||
1391 | (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); | ||
1312 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | 1392 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; |
1393 | /* make the bufsizes depend on wsize/rsize and max requests */ | ||
1394 | if((*csocket)->sk->sk_sndbuf < (200 * 1024)) | ||
1395 | (*csocket)->sk->sk_sndbuf = 200 * 1024; | ||
1396 | if((*csocket)->sk->sk_rcvbuf < (140 * 1024)) | ||
1397 | (*csocket)->sk->sk_rcvbuf = 140 * 1024; | ||
1313 | 1398 | ||
1314 | /* send RFC1001 sessinit */ | 1399 | /* send RFC1001 sessinit */ |
1315 | |||
1316 | if(psin_server->sin_port == htons(RFC1001_PORT)) { | 1400 | if(psin_server->sin_port == htons(RFC1001_PORT)) { |
1317 | /* some servers require RFC1001 sessinit before sending | 1401 | /* some servers require RFC1001 sessinit before sending |
1318 | negprot - BB check reconnection in case where second | 1402 | negprot - BB check reconnection in case where second |
@@ -1322,8 +1406,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1322 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); | 1406 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); |
1323 | if(ses_init_buf) { | 1407 | if(ses_init_buf) { |
1324 | ses_init_buf->trailer.session_req.called_len = 32; | 1408 | ses_init_buf->trailer.session_req.called_len = 32; |
1325 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | 1409 | if(target_name && (target_name[0] != 0)) { |
1326 | DEFAULT_CIFS_CALLED_NAME,16); | 1410 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, |
1411 | target_name, 16); | ||
1412 | } else { | ||
1413 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | ||
1414 | DEFAULT_CIFS_CALLED_NAME,16); | ||
1415 | } | ||
1416 | |||
1327 | ses_init_buf->trailer.session_req.calling_len = 32; | 1417 | ses_init_buf->trailer.session_req.calling_len = 32; |
1328 | /* calling name ends in null (byte 16) from old smb | 1418 | /* calling name ends in null (byte 16) from old smb |
1329 | convention. */ | 1419 | convention. */ |
@@ -1556,7 +1646,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1556 | sin_server.sin_port = htons(volume_info.port); | 1646 | sin_server.sin_port = htons(volume_info.port); |
1557 | else | 1647 | else |
1558 | sin_server.sin_port = 0; | 1648 | sin_server.sin_port = 0; |
1559 | rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); | 1649 | rc = ipv4_connect(&sin_server,&csocket, |
1650 | volume_info.source_rfc1001_name, | ||
1651 | volume_info.target_rfc1001_name); | ||
1560 | if (rc < 0) { | 1652 | if (rc < 0) { |
1561 | cERROR(1, | 1653 | cERROR(1, |
1562 | ("Error connecting to IPv4 socket. Aborting operation")); | 1654 | ("Error connecting to IPv4 socket. Aborting operation")); |
@@ -1606,9 +1698,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1606 | kfree(volume_info.password); | 1698 | kfree(volume_info.password); |
1607 | FreeXid(xid); | 1699 | FreeXid(xid); |
1608 | return rc; | 1700 | return rc; |
1609 | } else | 1701 | } |
1610 | rc = 0; | 1702 | wait_for_completion(&cifsd_complete); |
1703 | rc = 0; | ||
1611 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); | 1704 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); |
1705 | memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16); | ||
1612 | srvTcp->sequence_number = 0; | 1706 | srvTcp->sequence_number = 0; |
1613 | } | 1707 | } |
1614 | } | 1708 | } |
@@ -1653,17 +1747,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1653 | 1747 | ||
1654 | /* search for existing tcon to this server share */ | 1748 | /* search for existing tcon to this server share */ |
1655 | if (!rc) { | 1749 | if (!rc) { |
1656 | if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | 1750 | if(volume_info.rsize > CIFSMaxBufSize) { |
1751 | cERROR(1,("rsize %d too large, using MaxBufSize", | ||
1752 | volume_info.rsize)); | ||
1753 | cifs_sb->rsize = CIFSMaxBufSize; | ||
1754 | } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | ||
1657 | cifs_sb->rsize = volume_info.rsize; | 1755 | cifs_sb->rsize = volume_info.rsize; |
1658 | else | 1756 | else /* default */ |
1659 | cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ | 1757 | cifs_sb->rsize = CIFSMaxBufSize; |
1660 | if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize)) | 1758 | |
1759 | if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { | ||
1760 | cERROR(1,("wsize %d too large using 4096 instead", | ||
1761 | volume_info.wsize)); | ||
1762 | cifs_sb->wsize = 4096; | ||
1763 | } else if(volume_info.wsize) | ||
1661 | cifs_sb->wsize = volume_info.wsize; | 1764 | cifs_sb->wsize = volume_info.wsize; |
1662 | else | 1765 | else |
1663 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ | 1766 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ |
1664 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { | 1767 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { |
1665 | cifs_sb->rsize = PAGE_CACHE_SIZE; | 1768 | cifs_sb->rsize = PAGE_CACHE_SIZE; |
1666 | cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); | 1769 | /* Windows ME does this */ |
1770 | cFYI(1,("Attempt to set readsize for mount to less than one page (4096)")); | ||
1667 | } | 1771 | } |
1668 | cifs_sb->mnt_uid = volume_info.linux_uid; | 1772 | cifs_sb->mnt_uid = volume_info.linux_uid; |
1669 | cifs_sb->mnt_gid = volume_info.linux_gid; | 1773 | cifs_sb->mnt_gid = volume_info.linux_gid; |
@@ -1681,8 +1785,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1681 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; | 1785 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; |
1682 | if(volume_info.no_xattr) | 1786 | if(volume_info.no_xattr) |
1683 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | 1787 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; |
1788 | if(volume_info.sfu_emul) | ||
1789 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | ||
1790 | if(volume_info.nobrl) | ||
1791 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | ||
1792 | |||
1684 | if(volume_info.direct_io) { | 1793 | if(volume_info.direct_io) { |
1685 | cERROR(1,("mounting share using direct i/o")); | 1794 | cFYI(1,("mounting share using direct i/o")); |
1686 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 1795 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
1687 | } | 1796 | } |
1688 | 1797 | ||
@@ -1696,6 +1805,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1696 | to the same server share the last value passed in | 1805 | to the same server share the last value passed in |
1697 | for the retry flag is used */ | 1806 | for the retry flag is used */ |
1698 | tcon->retry = volume_info.retry; | 1807 | tcon->retry = volume_info.retry; |
1808 | tcon->nocase = volume_info.nocase; | ||
1699 | } else { | 1809 | } else { |
1700 | tcon = tconInfoAlloc(); | 1810 | tcon = tconInfoAlloc(); |
1701 | if (tcon == NULL) | 1811 | if (tcon == NULL) |
@@ -1724,6 +1834,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1724 | if (!rc) { | 1834 | if (!rc) { |
1725 | atomic_inc(&pSesInfo->inUse); | 1835 | atomic_inc(&pSesInfo->inUse); |
1726 | tcon->retry = volume_info.retry; | 1836 | tcon->retry = volume_info.retry; |
1837 | tcon->nocase = volume_info.nocase; | ||
1727 | } | 1838 | } |
1728 | } | 1839 | } |
1729 | } | 1840 | } |
@@ -1745,8 +1856,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1745 | spin_lock(&GlobalMid_Lock); | 1856 | spin_lock(&GlobalMid_Lock); |
1746 | srvTcp->tcpStatus = CifsExiting; | 1857 | srvTcp->tcpStatus = CifsExiting; |
1747 | spin_unlock(&GlobalMid_Lock); | 1858 | spin_unlock(&GlobalMid_Lock); |
1748 | if(srvTcp->tsk) | 1859 | if(srvTcp->tsk) { |
1749 | send_sig(SIGKILL,srvTcp->tsk,1); | 1860 | send_sig(SIGKILL,srvTcp->tsk,1); |
1861 | wait_for_completion(&cifsd_complete); | ||
1862 | } | ||
1750 | } | 1863 | } |
1751 | /* If find_unc succeeded then rc == 0 so we can not end */ | 1864 | /* If find_unc succeeded then rc == 0 so we can not end */ |
1752 | if (tcon) /* up accidently freeing someone elses tcon struct */ | 1865 | if (tcon) /* up accidently freeing someone elses tcon struct */ |
@@ -1759,8 +1872,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1759 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); | 1872 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); |
1760 | /* if the socketUseCount is now zero */ | 1873 | /* if the socketUseCount is now zero */ |
1761 | if((temp_rc == -ESHUTDOWN) && | 1874 | if((temp_rc == -ESHUTDOWN) && |
1762 | (pSesInfo->server->tsk)) | 1875 | (pSesInfo->server->tsk)) { |
1763 | send_sig(SIGKILL,pSesInfo->server->tsk,1); | 1876 | send_sig(SIGKILL,pSesInfo->server->tsk,1); |
1877 | wait_for_completion(&cifsd_complete); | ||
1878 | } | ||
1764 | } else | 1879 | } else |
1765 | cFYI(1, ("No session or bad tcon")); | 1880 | cFYI(1, ("No session or bad tcon")); |
1766 | sesInfoFree(pSesInfo); | 1881 | sesInfoFree(pSesInfo); |
@@ -1783,8 +1898,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1783 | cFYI(1,("server negotiated posix acl support")); | 1898 | cFYI(1,("server negotiated posix acl support")); |
1784 | sb->s_flags |= MS_POSIXACL; | 1899 | sb->s_flags |= MS_POSIXACL; |
1785 | } | 1900 | } |
1901 | |||
1902 | /* Try and negotiate POSIX pathnames if we can. */ | ||
1903 | if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP & | ||
1904 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | ||
1905 | if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) { | ||
1906 | cFYI(1,("negotiated posix pathnames support")); | ||
1907 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; | ||
1908 | } else { | ||
1909 | cFYI(1,("posix pathnames support requested but not supported")); | ||
1910 | } | ||
1911 | } | ||
1786 | } | 1912 | } |
1787 | } | 1913 | } |
1914 | if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) | ||
1915 | cifs_sb->wsize = min(cifs_sb->wsize, | ||
1916 | (tcon->ses->server->maxBuf - | ||
1917 | MAX_CIFS_HDR_SIZE)); | ||
1918 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) | ||
1919 | cifs_sb->rsize = min(cifs_sb->rsize, | ||
1920 | (tcon->ses->server->maxBuf - | ||
1921 | MAX_CIFS_HDR_SIZE)); | ||
1788 | } | 1922 | } |
1789 | 1923 | ||
1790 | /* volume_info.password is freed above when existing session found | 1924 | /* volume_info.password is freed above when existing session found |
@@ -1832,6 +1966,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
1832 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 1966 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
1833 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | 1967 | NULL /* no tCon exists yet */ , 13 /* wct */ ); |
1834 | 1968 | ||
1969 | smb_buffer->Mid = GetNextMid(ses->server); | ||
1835 | pSMB->req_no_secext.AndXCommand = 0xFF; | 1970 | pSMB->req_no_secext.AndXCommand = 0xFF; |
1836 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 1971 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
1837 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | 1972 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); |
@@ -2107,6 +2242,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2107 | /* send SMBsessionSetup here */ | 2242 | /* send SMBsessionSetup here */ |
2108 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2243 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
2109 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2244 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
2245 | |||
2246 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2110 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2247 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
2111 | pSMB->req.AndXCommand = 0xFF; | 2248 | pSMB->req.AndXCommand = 0xFF; |
2112 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 2249 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
@@ -2373,6 +2510,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
2373 | /* send SMBsessionSetup here */ | 2510 | /* send SMBsessionSetup here */ |
2374 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2511 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
2375 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2512 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
2513 | |||
2514 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2376 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2515 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
2377 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | 2516 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); |
2378 | 2517 | ||
@@ -2715,6 +2854,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2715 | /* send SMBsessionSetup here */ | 2854 | /* send SMBsessionSetup here */ |
2716 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2855 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
2717 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2856 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
2857 | |||
2858 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2718 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | 2859 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); |
2719 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2860 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
2720 | pSMB->req.AndXCommand = 0xFF; | 2861 | pSMB->req.AndXCommand = 0xFF; |
@@ -3086,6 +3227,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3086 | 3227 | ||
3087 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | 3228 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, |
3088 | NULL /*no tid */ , 4 /*wct */ ); | 3229 | NULL /*no tid */ , 4 /*wct */ ); |
3230 | |||
3231 | smb_buffer->Mid = GetNextMid(ses->server); | ||
3089 | smb_buffer->Uid = ses->Suid; | 3232 | smb_buffer->Uid = ses->Suid; |
3090 | pSMB = (TCONX_REQ *) smb_buffer; | 3233 | pSMB = (TCONX_REQ *) smb_buffer; |
3091 | pSMBr = (TCONX_RSP *) smb_buffer_response; | 3234 | pSMBr = (TCONX_RSP *) smb_buffer_response; |
@@ -3207,8 +3350,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3207 | return 0; | 3350 | return 0; |
3208 | } else if (rc == -ESHUTDOWN) { | 3351 | } else if (rc == -ESHUTDOWN) { |
3209 | cFYI(1,("Waking up socket by sending it signal")); | 3352 | cFYI(1,("Waking up socket by sending it signal")); |
3210 | if(cifsd_task) | 3353 | if(cifsd_task) { |
3211 | send_sig(SIGKILL,cifsd_task,1); | 3354 | send_sig(SIGKILL,cifsd_task,1); |
3355 | wait_for_completion(&cifsd_complete); | ||
3356 | } | ||
3212 | rc = 0; | 3357 | rc = 0; |
3213 | } /* else - we have an smb session | 3358 | } /* else - we have an smb session |
3214 | left on this socket do not kill cifsd */ | 3359 | left on this socket do not kill cifsd */ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d335269bd91c..8dfe717a332a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry) | |||
48 | struct dentry *temp; | 48 | struct dentry *temp; |
49 | int namelen = 0; | 49 | int namelen = 0; |
50 | char *full_path; | 50 | char *full_path; |
51 | char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); | ||
51 | 52 | ||
52 | if(direntry == NULL) | 53 | if(direntry == NULL) |
53 | return NULL; /* not much we can do if dentry is freed and | 54 | return NULL; /* not much we can do if dentry is freed and |
@@ -74,7 +75,7 @@ cifs_bp_rename_retry: | |||
74 | if (namelen < 0) { | 75 | if (namelen < 0) { |
75 | break; | 76 | break; |
76 | } else { | 77 | } else { |
77 | full_path[namelen] = '\\'; | 78 | full_path[namelen] = dirsep; |
78 | strncpy(full_path + namelen + 1, temp->d_name.name, | 79 | strncpy(full_path + namelen + 1, temp->d_name.name, |
79 | temp->d_name.len); | 80 | temp->d_name.len); |
80 | cFYI(0, (" name: %s ", full_path + namelen)); | 81 | cFYI(0, (" name: %s ", full_path + namelen)); |
@@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
183 | desiredAccess, CREATE_NOT_DIR, | 184 | desiredAccess, CREATE_NOT_DIR, |
184 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 185 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
185 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 186 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
187 | if(rc == -EIO) { | ||
188 | /* old server, retry the open legacy style */ | ||
189 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
190 | desiredAccess, CREATE_NOT_DIR, | ||
191 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | ||
192 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
193 | } | ||
186 | if (rc) { | 194 | if (rc) { |
187 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | 195 | cFYI(1, ("cifs_create returned 0x%x ", rc)); |
188 | } else { | 196 | } else { |
@@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
208 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 216 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
209 | } | 217 | } |
210 | else { | 218 | else { |
211 | /* BB implement via Windows security descriptors */ | 219 | /* BB implement mode setting via Windows security descriptors */ |
212 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ | 220 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ |
213 | /* could set r/o dos attribute if mode & 0222 == 0 */ | 221 | /* could set r/o dos attribute if mode & 0222 == 0 */ |
214 | } | 222 | } |
@@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
225 | } | 233 | } |
226 | 234 | ||
227 | if (rc != 0) { | 235 | if (rc != 0) { |
228 | cFYI(1,("Create worked but get_inode_info failed with rc = %d", | 236 | cFYI(1, |
237 | ("Create worked but get_inode_info failed rc = %d", | ||
229 | rc)); | 238 | rc)); |
230 | } else { | 239 | } else { |
231 | direntry->d_op = &cifs_dentry_ops; | 240 | if (pTcon->nocase) |
241 | direntry->d_op = &cifs_ci_dentry_ops; | ||
242 | else | ||
243 | direntry->d_op = &cifs_dentry_ops; | ||
232 | d_instantiate(direntry, newinode); | 244 | d_instantiate(direntry, newinode); |
233 | } | 245 | } |
234 | if((nd->flags & LOOKUP_OPEN) == FALSE) { | 246 | if((nd->flags & LOOKUP_OPEN) == FALSE) { |
@@ -302,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
302 | up(&direntry->d_sb->s_vfs_rename_sem); | 314 | up(&direntry->d_sb->s_vfs_rename_sem); |
303 | if(full_path == NULL) | 315 | if(full_path == NULL) |
304 | rc = -ENOMEM; | 316 | rc = -ENOMEM; |
305 | 317 | else if (pTcon->ses->capabilities & CAP_UNIX) { | |
306 | if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { | ||
307 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 318 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
308 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 319 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
309 | mode,(__u64)current->euid,(__u64)current->egid, | 320 | mode,(__u64)current->euid,(__u64)current->egid, |
@@ -321,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
321 | if(!rc) { | 332 | if(!rc) { |
322 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 333 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
323 | inode->i_sb,xid); | 334 | inode->i_sb,xid); |
324 | direntry->d_op = &cifs_dentry_ops; | 335 | if (pTcon->nocase) |
336 | direntry->d_op = &cifs_ci_dentry_ops; | ||
337 | else | ||
338 | direntry->d_op = &cifs_dentry_ops; | ||
325 | if(rc == 0) | 339 | if(rc == 0) |
326 | d_instantiate(direntry, newinode); | 340 | d_instantiate(direntry, newinode); |
327 | } | 341 | } |
342 | } else { | ||
343 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
344 | int oplock = 0; | ||
345 | u16 fileHandle; | ||
346 | FILE_ALL_INFO * buf; | ||
347 | |||
348 | cFYI(1,("sfu compat create special file")); | ||
349 | |||
350 | buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); | ||
351 | if(buf == NULL) { | ||
352 | kfree(full_path); | ||
353 | FreeXid(xid); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
358 | FILE_CREATE, /* fail if exists */ | ||
359 | GENERIC_WRITE /* BB would | ||
360 | WRITE_OWNER | WRITE_DAC be better? */, | ||
361 | /* Create a file and set the | ||
362 | file attribute to SYSTEM */ | ||
363 | CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, | ||
364 | &fileHandle, &oplock, buf, | ||
365 | cifs_sb->local_nls, | ||
366 | cifs_sb->mnt_cifs_flags & | ||
367 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
368 | |||
369 | if(!rc) { | ||
370 | /* BB Do not bother to decode buf since no | ||
371 | local inode yet to put timestamps in */ | ||
372 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
373 | d_drop(direntry); | ||
374 | } | ||
375 | kfree(buf); | ||
376 | /* add code here to set EAs */ | ||
377 | } | ||
328 | } | 378 | } |
329 | 379 | ||
330 | kfree(full_path); | 380 | kfree(full_path); |
@@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
381 | parent_dir_inode->i_sb,xid); | 431 | parent_dir_inode->i_sb,xid); |
382 | 432 | ||
383 | if ((rc == 0) && (newInode != NULL)) { | 433 | if ((rc == 0) && (newInode != NULL)) { |
384 | direntry->d_op = &cifs_dentry_ops; | 434 | if (pTcon->nocase) |
435 | direntry->d_op = &cifs_ci_dentry_ops; | ||
436 | else | ||
437 | direntry->d_op = &cifs_dentry_ops; | ||
385 | d_add(direntry, newInode); | 438 | d_add(direntry, newInode); |
386 | 439 | ||
387 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ | 440 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ |
@@ -440,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = { | |||
440 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ | 493 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ |
441 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ | 494 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ |
442 | }; | 495 | }; |
496 | |||
497 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | ||
498 | { | ||
499 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
500 | unsigned long hash; | ||
501 | int i; | ||
502 | |||
503 | hash = init_name_hash(); | ||
504 | for (i = 0; i < q->len; i++) | ||
505 | hash = partial_name_hash(nls_tolower(codepage, q->name[i]), | ||
506 | hash); | ||
507 | q->hash = end_name_hash(hash); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | ||
513 | struct qstr *b) | ||
514 | { | ||
515 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
516 | |||
517 | if ((a->len == b->len) && | ||
518 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | ||
519 | /* | ||
520 | * To preserve case, don't let an existing negative dentry's | ||
521 | * case take precedence. If a is not a negative dentry, this | ||
522 | * should have no side effects | ||
523 | */ | ||
524 | memcpy((unsigned char *)a->name, b->name, a->len); | ||
525 | return 0; | ||
526 | } | ||
527 | return 1; | ||
528 | } | ||
529 | |||
530 | struct dentry_operations cifs_ci_dentry_ops = { | ||
531 | .d_revalidate = cifs_d_revalidate, | ||
532 | .d_hash = cifs_ci_hash, | ||
533 | .d_compare = cifs_ci_compare, | ||
534 | }; | ||
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 7d2a9202c39a..a7a47bb36bf3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c | |||
@@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; | 78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; |
79 | __u16 netfid; | 79 | __u16 netfid; |
80 | 80 | ||
81 | |||
82 | if(experimEnabled == 0) | ||
83 | return 0; | ||
84 | |||
81 | xid = GetXid(); | 85 | xid = GetXid(); |
82 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 86 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
83 | pTcon = cifs_sb->tcon; | 87 | pTcon = cifs_sb->tcon; |
@@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
100 | } else { | 104 | } else { |
101 | filter = convert_to_cifs_notify_flags(arg); | 105 | filter = convert_to_cifs_notify_flags(arg); |
102 | if(filter != 0) { | 106 | if(filter != 0) { |
103 | rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, | 107 | rc = CIFSSMBNotify(xid, pTcon, |
104 | filter, cifs_sb->local_nls); | 108 | 0 /* no subdirs */, netfid, |
109 | filter, file, arg & DN_MULTISHOT, | ||
110 | cifs_sb->local_nls); | ||
105 | } else { | 111 | } else { |
106 | rc = -EINVAL; | 112 | rc = -EINVAL; |
107 | } | 113 | } |
@@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
109 | it would close automatically but may be a way | 115 | it would close automatically but may be a way |
110 | to do it easily when inode freed or when | 116 | to do it easily when inode freed or when |
111 | notify info is cleared/changed */ | 117 | notify info is cleared/changed */ |
112 | cERROR(1,("notify rc %d",rc)); | 118 | cFYI(1,("notify rc %d",rc)); |
113 | } | 119 | } |
114 | } | 120 | } |
115 | 121 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3497125189df..da4f5e10b3cc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -21,11 +21,15 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/backing-dev.h> | ||
24 | #include <linux/stat.h> | 25 | #include <linux/stat.h> |
25 | #include <linux/fcntl.h> | 26 | #include <linux/fcntl.h> |
27 | #include <linux/mpage.h> | ||
26 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
27 | #include <linux/pagevec.h> | 29 | #include <linux/pagevec.h> |
28 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/writeback.h> | ||
32 | #include <linux/delay.h> | ||
29 | #include <asm/div64.h> | 33 | #include <asm/div64.h> |
30 | #include "cifsfs.h" | 34 | #include "cifsfs.h" |
31 | #include "cifspdu.h" | 35 | #include "cifspdu.h" |
@@ -47,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
47 | private_data->pInode = inode; | 51 | private_data->pInode = inode; |
48 | private_data->invalidHandle = FALSE; | 52 | private_data->invalidHandle = FALSE; |
49 | private_data->closePend = FALSE; | 53 | private_data->closePend = FALSE; |
54 | /* we have to track num writers to the inode, since writepages | ||
55 | does not tell us which handle the write is for so there can | ||
56 | be a close (overlapping with write) of the filehandle that | ||
57 | cifs_writepages chose to use */ | ||
58 | atomic_set(&private_data->wrtPending,0); | ||
50 | 59 | ||
51 | return private_data; | 60 | return private_data; |
52 | } | 61 | } |
@@ -256,6 +265,13 @@ int cifs_open(struct inode *inode, struct file *file) | |||
256 | CREATE_NOT_DIR, &netfid, &oplock, buf, | 265 | CREATE_NOT_DIR, &netfid, &oplock, buf, |
257 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 266 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
258 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 267 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
268 | if (rc == -EIO) { | ||
269 | /* Old server, try legacy style OpenX */ | ||
270 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
271 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
272 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
273 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
274 | } | ||
259 | if (rc) { | 275 | if (rc) { |
260 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | 276 | cFYI(1, ("cifs_open returned 0x%x ", rc)); |
261 | goto out; | 277 | goto out; |
@@ -463,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file) | |||
463 | /* no sense reconnecting to close a file that is | 479 | /* no sense reconnecting to close a file that is |
464 | already closed */ | 480 | already closed */ |
465 | if (pTcon->tidStatus != CifsNeedReconnect) { | 481 | if (pTcon->tidStatus != CifsNeedReconnect) { |
482 | int timeout = 2; | ||
483 | while((atomic_read(&pSMBFile->wrtPending) != 0) | ||
484 | && (timeout < 1000) ) { | ||
485 | /* Give write a better chance to get to | ||
486 | server ahead of the close. We do not | ||
487 | want to add a wait_q here as it would | ||
488 | increase the memory utilization as | ||
489 | the struct would be in each open file, | ||
490 | but this should give enough time to | ||
491 | clear the socket */ | ||
492 | cERROR(1,("close with pending writes")); | ||
493 | msleep(timeout); | ||
494 | timeout *= 4; | ||
495 | } | ||
466 | write_unlock(&file->f_owner.lock); | 496 | write_unlock(&file->f_owner.lock); |
467 | rc = CIFSSMBClose(xid, pTcon, | 497 | rc = CIFSSMBClose(xid, pTcon, |
468 | pSMBFile->netfid); | 498 | pSMBFile->netfid); |
@@ -744,14 +774,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
744 | 15 seconds is plenty */ | 774 | 15 seconds is plenty */ |
745 | } | 775 | } |
746 | 776 | ||
747 | #ifdef CONFIG_CIFS_STATS | 777 | cifs_stats_bytes_written(pTcon, total_written); |
748 | if (total_written > 0) { | ||
749 | atomic_inc(&pTcon->num_writes); | ||
750 | spin_lock(&pTcon->stat_lock); | ||
751 | pTcon->bytes_written += total_written; | ||
752 | spin_unlock(&pTcon->stat_lock); | ||
753 | } | ||
754 | #endif | ||
755 | 778 | ||
756 | /* since the write may have blocked check these pointers again */ | 779 | /* since the write may have blocked check these pointers again */ |
757 | if (file->f_dentry) { | 780 | if (file->f_dentry) { |
@@ -791,9 +814,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
791 | 814 | ||
792 | pTcon = cifs_sb->tcon; | 815 | pTcon = cifs_sb->tcon; |
793 | 816 | ||
794 | /* cFYI(1, | 817 | cFYI(1,("write %zd bytes to offset %lld of %s", write_size, |
795 | (" write %d bytes to offset %lld of %s", write_size, | 818 | *poffset, file->f_dentry->d_name.name)); |
796 | *poffset, file->f_dentry->d_name.name)); */ | ||
797 | 819 | ||
798 | if (file->private_data == NULL) | 820 | if (file->private_data == NULL) |
799 | return -EBADF; | 821 | return -EBADF; |
@@ -846,7 +868,26 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
846 | if (rc != 0) | 868 | if (rc != 0) |
847 | break; | 869 | break; |
848 | } | 870 | } |
849 | 871 | #ifdef CONFIG_CIFS_EXPERIMENTAL | |
872 | /* BB FIXME We can not sign across two buffers yet */ | ||
873 | if((experimEnabled) && ((pTcon->ses->server->secMode & | ||
874 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | ||
875 | struct kvec iov[2]; | ||
876 | unsigned int len; | ||
877 | |||
878 | len = min((size_t)cifs_sb->wsize, | ||
879 | write_size - total_written); | ||
880 | /* iov[0] is reserved for smb header */ | ||
881 | iov[1].iov_base = (char *)write_data + | ||
882 | total_written; | ||
883 | iov[1].iov_len = len; | ||
884 | rc = CIFSSMBWrite2(xid, pTcon, | ||
885 | open_file->netfid, len, | ||
886 | *poffset, &bytes_written, | ||
887 | iov, 1, long_op); | ||
888 | } else | ||
889 | /* BB FIXME fixup indentation of line below */ | ||
890 | #endif | ||
850 | rc = CIFSSMBWrite(xid, pTcon, | 891 | rc = CIFSSMBWrite(xid, pTcon, |
851 | open_file->netfid, | 892 | open_file->netfid, |
852 | min_t(const int, cifs_sb->wsize, | 893 | min_t(const int, cifs_sb->wsize, |
@@ -867,14 +908,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
867 | 15 seconds is plenty */ | 908 | 15 seconds is plenty */ |
868 | } | 909 | } |
869 | 910 | ||
870 | #ifdef CONFIG_CIFS_STATS | 911 | cifs_stats_bytes_written(pTcon, total_written); |
871 | if (total_written > 0) { | ||
872 | atomic_inc(&pTcon->num_writes); | ||
873 | spin_lock(&pTcon->stat_lock); | ||
874 | pTcon->bytes_written += total_written; | ||
875 | spin_unlock(&pTcon->stat_lock); | ||
876 | } | ||
877 | #endif | ||
878 | 912 | ||
879 | /* since the write may have blocked check these pointers again */ | 913 | /* since the write may have blocked check these pointers again */ |
880 | if (file->f_dentry) { | 914 | if (file->f_dentry) { |
@@ -893,6 +927,43 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
893 | return total_written; | 927 | return total_written; |
894 | } | 928 | } |
895 | 929 | ||
930 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | ||
931 | { | ||
932 | struct cifsFileInfo *open_file; | ||
933 | int rc; | ||
934 | |||
935 | read_lock(&GlobalSMBSeslock); | ||
936 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | ||
937 | if (open_file->closePend) | ||
938 | continue; | ||
939 | if (open_file->pfile && | ||
940 | ((open_file->pfile->f_flags & O_RDWR) || | ||
941 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
942 | atomic_inc(&open_file->wrtPending); | ||
943 | read_unlock(&GlobalSMBSeslock); | ||
944 | if((open_file->invalidHandle) && | ||
945 | (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { | ||
946 | rc = cifs_reopen_file(&cifs_inode->vfs_inode, | ||
947 | open_file->pfile, FALSE); | ||
948 | /* if it fails, try another handle - might be */ | ||
949 | /* dangerous to hold up writepages with retry */ | ||
950 | if(rc) { | ||
951 | cFYI(1,("failed on reopen file in wp")); | ||
952 | read_lock(&GlobalSMBSeslock); | ||
953 | /* can not use this handle, no write | ||
954 | pending on this one after all */ | ||
955 | atomic_dec | ||
956 | (&open_file->wrtPending); | ||
957 | continue; | ||
958 | } | ||
959 | } | ||
960 | return open_file; | ||
961 | } | ||
962 | } | ||
963 | read_unlock(&GlobalSMBSeslock); | ||
964 | return NULL; | ||
965 | } | ||
966 | |||
896 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | 967 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) |
897 | { | 968 | { |
898 | struct address_space *mapping = page->mapping; | 969 | struct address_space *mapping = page->mapping; |
@@ -903,10 +974,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
903 | struct cifs_sb_info *cifs_sb; | 974 | struct cifs_sb_info *cifs_sb; |
904 | struct cifsTconInfo *pTcon; | 975 | struct cifsTconInfo *pTcon; |
905 | struct inode *inode; | 976 | struct inode *inode; |
906 | struct cifsInodeInfo *cifsInode; | 977 | struct cifsFileInfo *open_file; |
907 | struct cifsFileInfo *open_file = NULL; | ||
908 | struct list_head *tmp; | ||
909 | struct list_head *tmp1; | ||
910 | 978 | ||
911 | if (!mapping || !mapping->host) | 979 | if (!mapping || !mapping->host) |
912 | return -EFAULT; | 980 | return -EFAULT; |
@@ -934,49 +1002,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
934 | if (mapping->host->i_size - offset < (loff_t)to) | 1002 | if (mapping->host->i_size - offset < (loff_t)to) |
935 | to = (unsigned)(mapping->host->i_size - offset); | 1003 | to = (unsigned)(mapping->host->i_size - offset); |
936 | 1004 | ||
937 | cifsInode = CIFS_I(mapping->host); | 1005 | open_file = find_writable_file(CIFS_I(mapping->host)); |
938 | read_lock(&GlobalSMBSeslock); | 1006 | if (open_file) { |
939 | /* BB we should start at the end */ | 1007 | bytes_written = cifs_write(open_file->pfile, write_data, |
940 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1008 | to-from, &offset); |
941 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1009 | atomic_dec(&open_file->wrtPending); |
942 | if (open_file->closePend) | ||
943 | continue; | ||
944 | /* We check if file is open for writing first */ | ||
945 | if ((open_file->pfile) && | ||
946 | ((open_file->pfile->f_flags & O_RDWR) || | ||
947 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
948 | read_unlock(&GlobalSMBSeslock); | ||
949 | bytes_written = cifs_write(open_file->pfile, | ||
950 | write_data, to-from, | ||
951 | &offset); | ||
952 | read_lock(&GlobalSMBSeslock); | ||
953 | /* Does mm or vfs already set times? */ | 1010 | /* Does mm or vfs already set times? */ |
954 | inode->i_atime = | 1011 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
955 | inode->i_mtime = current_fs_time(inode->i_sb); | 1012 | if ((bytes_written > 0) && (offset)) { |
956 | if ((bytes_written > 0) && (offset)) { | 1013 | rc = 0; |
957 | rc = 0; | 1014 | } else if (bytes_written < 0) { |
958 | } else if (bytes_written < 0) { | 1015 | if (rc != -EBADF) |
959 | if (rc == -EBADF) { | 1016 | rc = bytes_written; |
960 | /* have seen a case in which kernel seemed to | ||
961 | have closed/freed a file even with writes | ||
962 | active so we might as well see if there are | ||
963 | other file structs to try for the same | ||
964 | inode before giving up */ | ||
965 | continue; | ||
966 | } else | ||
967 | rc = bytes_written; | ||
968 | } | ||
969 | break; /* now that we found a valid file handle and | ||
970 | tried to write to it we are done, no sense | ||
971 | continuing to loop looking for another */ | ||
972 | } | ||
973 | if (tmp->next == NULL) { | ||
974 | cFYI(1, ("File instance %p removed", tmp)); | ||
975 | break; | ||
976 | } | 1017 | } |
977 | } | 1018 | } else { |
978 | read_unlock(&GlobalSMBSeslock); | ||
979 | if (open_file == NULL) { | ||
980 | cFYI(1, ("No writeable filehandles for inode")); | 1019 | cFYI(1, ("No writeable filehandles for inode")); |
981 | rc = -EIO; | 1020 | rc = -EIO; |
982 | } | 1021 | } |
@@ -985,20 +1024,207 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
985 | return rc; | 1024 | return rc; |
986 | } | 1025 | } |
987 | 1026 | ||
988 | #if 0 | 1027 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
989 | static int cifs_writepages(struct address_space *mapping, | 1028 | static int cifs_writepages(struct address_space *mapping, |
990 | struct writeback_control *wbc) | 1029 | struct writeback_control *wbc) |
991 | { | 1030 | { |
992 | int rc = -EFAULT; | 1031 | struct backing_dev_info *bdi = mapping->backing_dev_info; |
1032 | unsigned int bytes_to_write; | ||
1033 | unsigned int bytes_written; | ||
1034 | struct cifs_sb_info *cifs_sb; | ||
1035 | int done = 0; | ||
1036 | pgoff_t end = -1; | ||
1037 | pgoff_t index; | ||
1038 | int is_range = 0; | ||
1039 | struct kvec iov[32]; | ||
1040 | int len; | ||
1041 | int n_iov = 0; | ||
1042 | pgoff_t next; | ||
1043 | int nr_pages; | ||
1044 | __u64 offset = 0; | ||
1045 | struct cifsFileInfo *open_file; | ||
1046 | struct page *page; | ||
1047 | struct pagevec pvec; | ||
1048 | int rc = 0; | ||
1049 | int scanned = 0; | ||
993 | int xid; | 1050 | int xid; |
994 | 1051 | ||
1052 | cifs_sb = CIFS_SB(mapping->host->i_sb); | ||
1053 | |||
1054 | /* | ||
1055 | * If wsize is smaller that the page cache size, default to writing | ||
1056 | * one page at a time via cifs_writepage | ||
1057 | */ | ||
1058 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | ||
1059 | return generic_writepages(mapping, wbc); | ||
1060 | |||
1061 | /* BB FIXME we do not have code to sign across multiple buffers yet, | ||
1062 | so go to older writepage style write which we can sign if needed */ | ||
1063 | if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) | ||
1064 | if(cifs_sb->tcon->ses->server->secMode & | ||
1065 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1066 | return generic_writepages(mapping, wbc); | ||
1067 | |||
1068 | /* | ||
1069 | * BB: Is this meaningful for a non-block-device file system? | ||
1070 | * If it is, we should test it again after we do I/O | ||
1071 | */ | ||
1072 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
1073 | wbc->encountered_congestion = 1; | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
995 | xid = GetXid(); | 1077 | xid = GetXid(); |
996 | 1078 | ||
997 | /* Find contiguous pages then iterate through repeating | 1079 | pagevec_init(&pvec, 0); |
998 | call 16K write then Setpageuptodate or if LARGE_WRITE_X | 1080 | if (wbc->sync_mode == WB_SYNC_NONE) |
999 | support then send larger writes via kevec so as to eliminate | 1081 | index = mapping->writeback_index; /* Start from prev offset */ |
1000 | a memcpy */ | 1082 | else { |
1083 | index = 0; | ||
1084 | scanned = 1; | ||
1085 | } | ||
1086 | if (wbc->start || wbc->end) { | ||
1087 | index = wbc->start >> PAGE_CACHE_SHIFT; | ||
1088 | end = wbc->end >> PAGE_CACHE_SHIFT; | ||
1089 | is_range = 1; | ||
1090 | scanned = 1; | ||
1091 | } | ||
1092 | retry: | ||
1093 | while (!done && (index <= end) && | ||
1094 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | ||
1095 | PAGECACHE_TAG_DIRTY, | ||
1096 | min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { | ||
1097 | int first; | ||
1098 | unsigned int i; | ||
1099 | |||
1100 | first = -1; | ||
1101 | next = 0; | ||
1102 | n_iov = 0; | ||
1103 | bytes_to_write = 0; | ||
1104 | |||
1105 | for (i = 0; i < nr_pages; i++) { | ||
1106 | page = pvec.pages[i]; | ||
1107 | /* | ||
1108 | * At this point we hold neither mapping->tree_lock nor | ||
1109 | * lock on the page itself: the page may be truncated or | ||
1110 | * invalidated (changing page->mapping to NULL), or even | ||
1111 | * swizzled back from swapper_space to tmpfs file | ||
1112 | * mapping | ||
1113 | */ | ||
1114 | |||
1115 | if (first < 0) | ||
1116 | lock_page(page); | ||
1117 | else if (TestSetPageLocked(page)) | ||
1118 | break; | ||
1119 | |||
1120 | if (unlikely(page->mapping != mapping)) { | ||
1121 | unlock_page(page); | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | if (unlikely(is_range) && (page->index > end)) { | ||
1126 | done = 1; | ||
1127 | unlock_page(page); | ||
1128 | break; | ||
1129 | } | ||
1130 | |||
1131 | if (next && (page->index != next)) { | ||
1132 | /* Not next consecutive page */ | ||
1133 | unlock_page(page); | ||
1134 | break; | ||
1135 | } | ||
1136 | |||
1137 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1138 | wait_on_page_writeback(page); | ||
1139 | |||
1140 | if (PageWriteback(page) || | ||
1141 | !test_clear_page_dirty(page)) { | ||
1142 | unlock_page(page); | ||
1143 | break; | ||
1144 | } | ||
1145 | |||
1146 | if (page_offset(page) >= mapping->host->i_size) { | ||
1147 | done = 1; | ||
1148 | unlock_page(page); | ||
1149 | break; | ||
1150 | } | ||
1151 | |||
1152 | /* | ||
1153 | * BB can we get rid of this? pages are held by pvec | ||
1154 | */ | ||
1155 | page_cache_get(page); | ||
1156 | |||
1157 | len = min(mapping->host->i_size - page_offset(page), | ||
1158 | (loff_t)PAGE_CACHE_SIZE); | ||
1159 | |||
1160 | /* reserve iov[0] for the smb header */ | ||
1161 | n_iov++; | ||
1162 | iov[n_iov].iov_base = kmap(page); | ||
1163 | iov[n_iov].iov_len = len; | ||
1164 | bytes_to_write += len; | ||
1165 | |||
1166 | if (first < 0) { | ||
1167 | first = i; | ||
1168 | offset = page_offset(page); | ||
1169 | } | ||
1170 | next = page->index + 1; | ||
1171 | if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) | ||
1172 | break; | ||
1173 | } | ||
1174 | if (n_iov) { | ||
1175 | /* Search for a writable handle every time we call | ||
1176 | * CIFSSMBWrite2. We can't rely on the last handle | ||
1177 | * we used to still be valid | ||
1178 | */ | ||
1179 | open_file = find_writable_file(CIFS_I(mapping->host)); | ||
1180 | if (!open_file) { | ||
1181 | cERROR(1, ("No writable handles for inode")); | ||
1182 | rc = -EBADF; | ||
1183 | } else { | ||
1184 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, | ||
1185 | open_file->netfid, | ||
1186 | bytes_to_write, offset, | ||
1187 | &bytes_written, iov, n_iov, | ||
1188 | 1); | ||
1189 | atomic_dec(&open_file->wrtPending); | ||
1190 | if (rc || bytes_written < bytes_to_write) { | ||
1191 | cERROR(1,("Write2 ret %d, written = %d", | ||
1192 | rc, bytes_written)); | ||
1193 | /* BB what if continued retry is | ||
1194 | requested via mount flags? */ | ||
1195 | set_bit(AS_EIO, &mapping->flags); | ||
1196 | SetPageError(page); | ||
1197 | } else { | ||
1198 | cifs_stats_bytes_written(cifs_sb->tcon, | ||
1199 | bytes_written); | ||
1200 | } | ||
1201 | } | ||
1202 | for (i = 0; i < n_iov; i++) { | ||
1203 | page = pvec.pages[first + i]; | ||
1204 | kunmap(page); | ||
1205 | unlock_page(page); | ||
1206 | page_cache_release(page); | ||
1207 | } | ||
1208 | if ((wbc->nr_to_write -= n_iov) <= 0) | ||
1209 | done = 1; | ||
1210 | index = next; | ||
1211 | } | ||
1212 | pagevec_release(&pvec); | ||
1213 | } | ||
1214 | if (!scanned && !done) { | ||
1215 | /* | ||
1216 | * We hit the last page and there is more work to be done: wrap | ||
1217 | * back to the start of the file | ||
1218 | */ | ||
1219 | scanned = 1; | ||
1220 | index = 0; | ||
1221 | goto retry; | ||
1222 | } | ||
1223 | if (!is_range) | ||
1224 | mapping->writeback_index = index; | ||
1225 | |||
1001 | FreeXid(xid); | 1226 | FreeXid(xid); |
1227 | |||
1002 | return rc; | 1228 | return rc; |
1003 | } | 1229 | } |
1004 | #endif | 1230 | #endif |
@@ -1207,12 +1433,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1207 | if (rc != 0) | 1433 | if (rc != 0) |
1208 | break; | 1434 | break; |
1209 | } | 1435 | } |
1210 | |||
1211 | rc = CIFSSMBRead(xid, pTcon, | 1436 | rc = CIFSSMBRead(xid, pTcon, |
1212 | open_file->netfid, | 1437 | open_file->netfid, |
1213 | current_read_size, *poffset, | 1438 | current_read_size, *poffset, |
1214 | &bytes_read, &smb_read_data); | 1439 | &bytes_read, &smb_read_data); |
1215 | |||
1216 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1440 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
1217 | if (copy_to_user(current_offset, | 1441 | if (copy_to_user(current_offset, |
1218 | smb_read_data + 4 /* RFC1001 hdr */ | 1442 | smb_read_data + 4 /* RFC1001 hdr */ |
@@ -1235,12 +1459,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1235 | return rc; | 1459 | return rc; |
1236 | } | 1460 | } |
1237 | } else { | 1461 | } else { |
1238 | #ifdef CONFIG_CIFS_STATS | 1462 | cifs_stats_bytes_read(pTcon, bytes_read); |
1239 | atomic_inc(&pTcon->num_reads); | ||
1240 | spin_lock(&pTcon->stat_lock); | ||
1241 | pTcon->bytes_read += total_read; | ||
1242 | spin_unlock(&pTcon->stat_lock); | ||
1243 | #endif | ||
1244 | *poffset += bytes_read; | 1463 | *poffset += bytes_read; |
1245 | } | 1464 | } |
1246 | } | 1465 | } |
@@ -1280,6 +1499,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1280 | total_read += bytes_read, current_offset += bytes_read) { | 1499 | total_read += bytes_read, current_offset += bytes_read) { |
1281 | current_read_size = min_t(const int, read_size - total_read, | 1500 | current_read_size = min_t(const int, read_size - total_read, |
1282 | cifs_sb->rsize); | 1501 | cifs_sb->rsize); |
1502 | /* For windows me and 9x we do not want to request more | ||
1503 | than it negotiated since it will refuse the read then */ | ||
1504 | if((pTcon->ses) && | ||
1505 | !(pTcon->ses->capabilities & CAP_LARGE_FILES)) { | ||
1506 | current_read_size = min_t(const int, current_read_size, | ||
1507 | pTcon->ses->server->maxBuf - 128); | ||
1508 | } | ||
1283 | rc = -EAGAIN; | 1509 | rc = -EAGAIN; |
1284 | while (rc == -EAGAIN) { | 1510 | while (rc == -EAGAIN) { |
1285 | if ((open_file->invalidHandle) && | 1511 | if ((open_file->invalidHandle) && |
@@ -1289,11 +1515,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1289 | if (rc != 0) | 1515 | if (rc != 0) |
1290 | break; | 1516 | break; |
1291 | } | 1517 | } |
1292 | |||
1293 | rc = CIFSSMBRead(xid, pTcon, | 1518 | rc = CIFSSMBRead(xid, pTcon, |
1294 | open_file->netfid, | 1519 | open_file->netfid, |
1295 | current_read_size, *poffset, | 1520 | current_read_size, *poffset, |
1296 | &bytes_read, ¤t_offset); | 1521 | &bytes_read, ¤t_offset); |
1297 | } | 1522 | } |
1298 | if (rc || (bytes_read == 0)) { | 1523 | if (rc || (bytes_read == 0)) { |
1299 | if (total_read) { | 1524 | if (total_read) { |
@@ -1303,12 +1528,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1303 | return rc; | 1528 | return rc; |
1304 | } | 1529 | } |
1305 | } else { | 1530 | } else { |
1306 | #ifdef CONFIG_CIFS_STATS | 1531 | cifs_stats_bytes_read(pTcon, total_read); |
1307 | atomic_inc(&pTcon->num_reads); | ||
1308 | spin_lock(&pTcon->stat_lock); | ||
1309 | pTcon->bytes_read += total_read; | ||
1310 | spin_unlock(&pTcon->stat_lock); | ||
1311 | #endif | ||
1312 | *poffset += bytes_read; | 1532 | *poffset += bytes_read; |
1313 | } | 1533 | } |
1314 | } | 1534 | } |
@@ -1452,10 +1672,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1452 | } | 1672 | } |
1453 | 1673 | ||
1454 | rc = CIFSSMBRead(xid, pTcon, | 1674 | rc = CIFSSMBRead(xid, pTcon, |
1455 | open_file->netfid, | 1675 | open_file->netfid, |
1456 | read_size, offset, | 1676 | read_size, offset, |
1457 | &bytes_read, &smb_read_data); | 1677 | &bytes_read, &smb_read_data); |
1458 | /* BB need to check return code here */ | 1678 | |
1679 | /* BB more RC checks ? */ | ||
1459 | if (rc== -EAGAIN) { | 1680 | if (rc== -EAGAIN) { |
1460 | if (smb_read_data) { | 1681 | if (smb_read_data) { |
1461 | cifs_buf_release(smb_read_data); | 1682 | cifs_buf_release(smb_read_data); |
@@ -1480,12 +1701,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1480 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); | 1701 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); |
1481 | 1702 | ||
1482 | i += bytes_read >> PAGE_CACHE_SHIFT; | 1703 | i += bytes_read >> PAGE_CACHE_SHIFT; |
1483 | #ifdef CONFIG_CIFS_STATS | 1704 | cifs_stats_bytes_read(pTcon, bytes_read); |
1484 | atomic_inc(&pTcon->num_reads); | ||
1485 | spin_lock(&pTcon->stat_lock); | ||
1486 | pTcon->bytes_read += bytes_read; | ||
1487 | spin_unlock(&pTcon->stat_lock); | ||
1488 | #endif | ||
1489 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | 1705 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { |
1490 | i++; /* account for partial page */ | 1706 | i++; /* account for partial page */ |
1491 | 1707 | ||
@@ -1603,40 +1819,21 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
1603 | page caching in the current Linux kernel design */ | 1819 | page caching in the current Linux kernel design */ |
1604 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | 1820 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) |
1605 | { | 1821 | { |
1606 | struct list_head *tmp; | ||
1607 | struct list_head *tmp1; | ||
1608 | struct cifsFileInfo *open_file = NULL; | 1822 | struct cifsFileInfo *open_file = NULL; |
1609 | int rc = TRUE; | ||
1610 | 1823 | ||
1611 | if (cifsInode == NULL) | 1824 | if (cifsInode) |
1612 | return rc; | 1825 | open_file = find_writable_file(cifsInode); |
1613 | 1826 | ||
1614 | read_lock(&GlobalSMBSeslock); | 1827 | if(open_file) { |
1615 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1828 | /* there is not actually a write pending so let |
1616 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1829 | this handle go free and allow it to |
1617 | if (open_file == NULL) | 1830 | be closable if needed */ |
1618 | break; | 1831 | atomic_dec(&open_file->wrtPending); |
1619 | if (open_file->closePend) | 1832 | return 0; |
1620 | continue; | 1833 | } else |
1621 | /* We check if file is open for writing, | 1834 | return 1; |
1622 | BB we could supplement this with a check to see if file size | ||
1623 | changes have been flushed to server - ie inode metadata dirty */ | ||
1624 | if ((open_file->pfile) && | ||
1625 | ((open_file->pfile->f_flags & O_RDWR) || | ||
1626 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1627 | rc = FALSE; | ||
1628 | break; | ||
1629 | } | ||
1630 | if (tmp->next == NULL) { | ||
1631 | cFYI(1, ("File instance %p removed", tmp)); | ||
1632 | break; | ||
1633 | } | ||
1634 | } | ||
1635 | read_unlock(&GlobalSMBSeslock); | ||
1636 | return rc; | ||
1637 | } | 1835 | } |
1638 | 1836 | ||
1639 | |||
1640 | static int cifs_prepare_write(struct file *file, struct page *page, | 1837 | static int cifs_prepare_write(struct file *file, struct page *page, |
1641 | unsigned from, unsigned to) | 1838 | unsigned from, unsigned to) |
1642 | { | 1839 | { |
@@ -1676,6 +1873,9 @@ struct address_space_operations cifs_addr_ops = { | |||
1676 | .readpage = cifs_readpage, | 1873 | .readpage = cifs_readpage, |
1677 | .readpages = cifs_readpages, | 1874 | .readpages = cifs_readpages, |
1678 | .writepage = cifs_writepage, | 1875 | .writepage = cifs_writepage, |
1876 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1877 | .writepages = cifs_writepages, | ||
1878 | #endif | ||
1679 | .prepare_write = cifs_prepare_write, | 1879 | .prepare_write = cifs_prepare_write, |
1680 | .commit_write = cifs_commit_write, | 1880 | .commit_write = cifs_commit_write, |
1681 | .set_page_dirty = __set_page_dirty_nobuffers, | 1881 | .set_page_dirty = __set_page_dirty_nobuffers, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8d336a900255..912d401600f6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
166 | inode->i_fop = &cifs_file_direct_ops; | 166 | inode->i_fop = &cifs_file_direct_ops; |
167 | else | 167 | else |
168 | inode->i_fop = &cifs_file_ops; | 168 | inode->i_fop = &cifs_file_ops; |
169 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
170 | inode->i_fop->lock = NULL; | ||
169 | inode->i_data.a_ops = &cifs_addr_ops; | 171 | inode->i_data.a_ops = &cifs_addr_ops; |
172 | /* check if server can support readpages */ | ||
173 | if(pTcon->ses->server->maxBuf < | ||
174 | 4096 + MAX_CIFS_HDR_SIZE) | ||
175 | inode->i_data.a_ops->readpages = NULL; | ||
170 | } else if (S_ISDIR(inode->i_mode)) { | 176 | } else if (S_ISDIR(inode->i_mode)) { |
171 | cFYI(1, (" Directory inode")); | 177 | cFYI(1, (" Directory inode")); |
172 | inode->i_op = &cifs_dir_inode_ops; | 178 | inode->i_op = &cifs_dir_inode_ops; |
@@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode, | |||
213 | pfindData = (FILE_ALL_INFO *)buf; | 219 | pfindData = (FILE_ALL_INFO *)buf; |
214 | /* could do find first instead but this returns more info */ | 220 | /* could do find first instead but this returns more info */ |
215 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, | 221 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, |
216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 222 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
217 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 223 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
224 | /* BB optimize code so we do not make the above call | ||
225 | when server claims no NT SMB support and the above call | ||
226 | failed at least once - set flag in tcon or mount */ | ||
227 | if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { | ||
228 | rc = SMBQueryInformation(xid, pTcon, search_path, | ||
229 | pfindData, cifs_sb->local_nls, | ||
230 | cifs_sb->mnt_cifs_flags & | ||
231 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
232 | } | ||
233 | |||
218 | } | 234 | } |
219 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 235 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ |
220 | if (rc) { | 236 | if (rc) { |
@@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode, | |||
320 | on dirs */ | 336 | on dirs */ |
321 | inode->i_mode = cifs_sb->mnt_dir_mode; | 337 | inode->i_mode = cifs_sb->mnt_dir_mode; |
322 | inode->i_mode |= S_IFDIR; | 338 | inode->i_mode |= S_IFDIR; |
339 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
340 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && | ||
341 | /* No need to le64 convert size of zero */ | ||
342 | (pfindData->EndOfFile == 0)) { | ||
343 | inode->i_mode = cifs_sb->mnt_file_mode; | ||
344 | inode->i_mode |= S_IFIFO; | ||
345 | /* BB Finish for SFU style symlinks and devies */ | ||
346 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
347 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ | ||
348 | |||
323 | } else { | 349 | } else { |
324 | inode->i_mode |= S_IFREG; | 350 | inode->i_mode |= S_IFREG; |
325 | /* treat the dos attribute of read-only as read-only | 351 | /* treat the dos attribute of read-only as read-only |
@@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
359 | inode->i_fop = &cifs_file_direct_ops; | 385 | inode->i_fop = &cifs_file_direct_ops; |
360 | else | 386 | else |
361 | inode->i_fop = &cifs_file_ops; | 387 | inode->i_fop = &cifs_file_ops; |
388 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
389 | inode->i_fop->lock = NULL; | ||
362 | inode->i_data.a_ops = &cifs_addr_ops; | 390 | inode->i_data.a_ops = &cifs_addr_ops; |
391 | if(pTcon->ses->server->maxBuf < | ||
392 | 4096 + MAX_CIFS_HDR_SIZE) | ||
393 | inode->i_data.a_ops->readpages = NULL; | ||
363 | } else if (S_ISDIR(inode->i_mode)) { | 394 | } else if (S_ISDIR(inode->i_mode)) { |
364 | cFYI(1, (" Directory inode ")); | 395 | cFYI(1, (" Directory inode ")); |
365 | inode->i_op = &cifs_dir_inode_ops; | 396 | inode->i_op = &cifs_dir_inode_ops; |
@@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
577 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 608 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
578 | inode->i_sb,xid); | 609 | inode->i_sb,xid); |
579 | 610 | ||
580 | direntry->d_op = &cifs_dentry_ops; | 611 | if (pTcon->nocase) |
612 | direntry->d_op = &cifs_ci_dentry_ops; | ||
613 | else | ||
614 | direntry->d_op = &cifs_dentry_ops; | ||
581 | d_instantiate(direntry, newinode); | 615 | d_instantiate(direntry, newinode); |
582 | if (direntry->d_inode) | 616 | if (direntry->d_inode) |
583 | direntry->d_inode->i_nlink = 2; | 617 | direntry->d_inode->i_nlink = 2; |
@@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
928 | struct cifsTconInfo *pTcon; | 962 | struct cifsTconInfo *pTcon; |
929 | char *full_path = NULL; | 963 | char *full_path = NULL; |
930 | int rc = -EACCES; | 964 | int rc = -EACCES; |
931 | int found = FALSE; | ||
932 | struct cifsFileInfo *open_file = NULL; | 965 | struct cifsFileInfo *open_file = NULL; |
933 | FILE_BASIC_INFO time_buf; | 966 | FILE_BASIC_INFO time_buf; |
934 | int set_time = FALSE; | 967 | int set_time = FALSE; |
@@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
936 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | 969 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; |
937 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | 970 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; |
938 | struct cifsInodeInfo *cifsInode; | 971 | struct cifsInodeInfo *cifsInode; |
939 | struct list_head *tmp; | ||
940 | 972 | ||
941 | xid = GetXid(); | 973 | xid = GetXid(); |
942 | 974 | ||
@@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
961 | filemap_fdatawait(direntry->d_inode->i_mapping); | 993 | filemap_fdatawait(direntry->d_inode->i_mapping); |
962 | 994 | ||
963 | if (attrs->ia_valid & ATTR_SIZE) { | 995 | if (attrs->ia_valid & ATTR_SIZE) { |
964 | read_lock(&GlobalSMBSeslock); | ||
965 | /* To avoid spurious oplock breaks from server, in the case of | 996 | /* To avoid spurious oplock breaks from server, in the case of |
966 | inodes that we already have open, avoid doing path based | 997 | inodes that we already have open, avoid doing path based |
967 | setting of file size if we can do it by handle. | 998 | setting of file size if we can do it by handle. |
@@ -969,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
969 | when the local oplock break takes longer to flush | 1000 | when the local oplock break takes longer to flush |
970 | writebehind data than the SMB timeout for the SetPathInfo | 1001 | writebehind data than the SMB timeout for the SetPathInfo |
971 | request would allow */ | 1002 | request would allow */ |
972 | list_for_each(tmp, &cifsInode->openFileList) { | 1003 | open_file = find_writable_file(cifsInode); |
973 | open_file = list_entry(tmp, struct cifsFileInfo, | 1004 | if (open_file) { |
974 | flist); | 1005 | __u16 nfid = open_file->netfid; |
975 | /* We check if file is open for writing first */ | 1006 | __u32 npid = open_file->pid; |
976 | if ((open_file->pfile) && | 1007 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, |
977 | ((open_file->pfile->f_flags & O_RDWR) || | 1008 | nfid, npid, FALSE); |
978 | (open_file->pfile->f_flags & O_WRONLY))) { | 1009 | atomic_dec(&open_file->wrtPending); |
979 | if (open_file->invalidHandle == FALSE) { | 1010 | cFYI(1,("SetFSize for attrs rc = %d", rc)); |
980 | /* we found a valid, writeable network | 1011 | if(rc == -EINVAL) { |
981 | file handle to use to try to set the | 1012 | int bytes_written; |
982 | file size */ | 1013 | rc = CIFSSMBWrite(xid, pTcon, |
983 | __u16 nfid = open_file->netfid; | 1014 | nfid, 0, attrs->ia_size, |
984 | __u32 npid = open_file->pid; | 1015 | &bytes_written, NULL, NULL, |
985 | read_unlock(&GlobalSMBSeslock); | 1016 | 1 /* 45 seconds */); |
986 | found = TRUE; | 1017 | cFYI(1,("Wrt seteof rc %d", rc)); |
987 | rc = CIFSSMBSetFileSize(xid, pTcon, | ||
988 | attrs->ia_size, nfid, npid, | ||
989 | FALSE); | ||
990 | cFYI(1, ("SetFileSize by handle " | ||
991 | "(setattrs) rc = %d", rc)); | ||
992 | /* Do not need reopen and retry on | ||
993 | EAGAIN since we will retry by | ||
994 | pathname below */ | ||
995 | |||
996 | /* now that we found one valid file | ||
997 | handle no sense continuing to loop | ||
998 | trying others, so break here */ | ||
999 | break; | ||
1000 | } | ||
1001 | } | 1018 | } |
1002 | } | 1019 | } |
1003 | if (found == FALSE) | ||
1004 | read_unlock(&GlobalSMBSeslock); | ||
1005 | |||
1006 | if (rc != 0) { | 1020 | if (rc != 0) { |
1007 | /* Set file size by pathname rather than by handle | 1021 | /* Set file size by pathname rather than by handle |
1008 | either because no valid, writeable file handle for | 1022 | either because no valid, writeable file handle for |
@@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1013 | cifs_sb->local_nls, | 1027 | cifs_sb->local_nls, |
1014 | cifs_sb->mnt_cifs_flags & | 1028 | cifs_sb->mnt_cifs_flags & |
1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1029 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1016 | cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | 1030 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); |
1031 | if(rc == -EINVAL) { | ||
1032 | __u16 netfid; | ||
1033 | int oplock = FALSE; | ||
1034 | |||
1035 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
1036 | FILE_OPEN, | ||
1037 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1038 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1039 | NULL, cifs_sb->local_nls, | ||
1040 | cifs_sb->mnt_cifs_flags & | ||
1041 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1042 | if (rc==0) { | ||
1043 | int bytes_written; | ||
1044 | rc = CIFSSMBWrite(xid, pTcon, | ||
1045 | netfid, 0, | ||
1046 | attrs->ia_size, | ||
1047 | &bytes_written, NULL, | ||
1048 | NULL, 1 /* 45 sec */); | ||
1049 | cFYI(1,("wrt seteof rc %d",rc)); | ||
1050 | CIFSSMBClose(xid, pTcon, netfid); | ||
1051 | } | ||
1052 | |||
1053 | } | ||
1017 | } | 1054 | } |
1018 | 1055 | ||
1019 | /* Server is ok setting allocation size implicitly - no need | 1056 | /* Server is ok setting allocation size implicitly - no need |
@@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1026 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); | 1063 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); |
1027 | cifs_truncate_page(direntry->d_inode->i_mapping, | 1064 | cifs_truncate_page(direntry->d_inode->i_mapping, |
1028 | direntry->d_inode->i_size); | 1065 | direntry->d_inode->i_size); |
1029 | } | 1066 | } else |
1067 | goto cifs_setattr_exit; | ||
1030 | } | 1068 | } |
1031 | if (attrs->ia_valid & ATTR_UID) { | 1069 | if (attrs->ia_valid & ATTR_UID) { |
1032 | cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | 1070 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); |
1033 | uid = attrs->ia_uid; | 1071 | uid = attrs->ia_uid; |
1034 | /* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||
1035 | } | 1072 | } |
1036 | if (attrs->ia_valid & ATTR_GID) { | 1073 | if (attrs->ia_valid & ATTR_GID) { |
1037 | cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | 1074 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); |
1038 | gid = attrs->ia_gid; | 1075 | gid = attrs->ia_gid; |
1039 | /* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||
1040 | } | 1076 | } |
1041 | 1077 | ||
1042 | time_buf.Attributes = 0; | 1078 | time_buf.Attributes = 0; |
1043 | if (attrs->ia_valid & ATTR_MODE) { | 1079 | if (attrs->ia_valid & ATTR_MODE) { |
1044 | cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | 1080 | cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); |
1045 | mode = attrs->ia_mode; | 1081 | mode = attrs->ia_mode; |
1046 | /* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||
1047 | } | 1082 | } |
1048 | 1083 | ||
1049 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 1084 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
@@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1083 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | 1118 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); |
1084 | } else | 1119 | } else |
1085 | time_buf.LastWriteTime = 0; | 1120 | time_buf.LastWriteTime = 0; |
1086 | 1121 | /* Do not set ctime explicitly unless other time | |
1087 | if (attrs->ia_valid & ATTR_CTIME) { | 1122 | stamps are changed explicitly (i.e. by utime() |
1123 | since we would then have a mix of client and | ||
1124 | server times */ | ||
1125 | |||
1126 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1088 | set_time = TRUE; | 1127 | set_time = TRUE; |
1089 | cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | 1128 | /* Although Samba throws this field away |
1129 | it may be useful to Windows - but we do | ||
1130 | not want to set ctime unless some other | ||
1131 | timestamp is changing */ | ||
1132 | cFYI(1, ("CIFS - CTIME changed ")); | ||
1090 | time_buf.ChangeTime = | 1133 | time_buf.ChangeTime = |
1091 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | 1134 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); |
1092 | } else | 1135 | } else |
1093 | time_buf.ChangeTime = 0; | 1136 | time_buf.ChangeTime = 0; |
1094 | 1137 | ||
1095 | if (set_time || time_buf.Attributes) { | 1138 | if (set_time || time_buf.Attributes) { |
1096 | /* BB what if setting one attribute fails (such as size) but | ||
1097 | time setting works? */ | ||
1098 | time_buf.CreationTime = 0; /* do not change */ | 1139 | time_buf.CreationTime = 0; /* do not change */ |
1099 | /* In the future we should experiment - try setting timestamps | 1140 | /* In the future we should experiment - try setting timestamps |
1100 | via Handle (SetFileInfo) instead of by path */ | 1141 | via Handle (SetFileInfo) instead of by path */ |
@@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1133 | &time_buf, cifs_sb->local_nls); */ | 1174 | &time_buf, cifs_sb->local_nls); */ |
1134 | } | 1175 | } |
1135 | } | 1176 | } |
1177 | /* Even if error on time set, no sense failing the call if | ||
1178 | the server would set the time to a reasonable value anyway, | ||
1179 | and this check ensures that we are not being called from | ||
1180 | sys_utimes in which case we ought to fail the call back to | ||
1181 | the user when the server rejects the call */ | ||
1182 | if((rc) && (attrs->ia_valid && | ||
1183 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | ||
1184 | rc = 0; | ||
1136 | } | 1185 | } |
1137 | 1186 | ||
1138 | /* do not need local check to inode_check_ok since the server does | 1187 | /* do not need local check to inode_check_ok since the server does |
1139 | that */ | 1188 | that */ |
1140 | if (!rc) | 1189 | if (!rc) |
1141 | rc = inode_setattr(direntry->d_inode, attrs); | 1190 | rc = inode_setattr(direntry->d_inode, attrs); |
1191 | cifs_setattr_exit: | ||
1142 | kfree(full_path); | 1192 | kfree(full_path); |
1143 | FreeXid(xid); | 1193 | FreeXid(xid); |
1144 | return rc; | 1194 | return rc; |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index ab925ef4f863..b43e071fe110 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
198 | ("Create symlink worked but get_inode_info failed with rc = %d ", | 198 | ("Create symlink worked but get_inode_info failed with rc = %d ", |
199 | rc)); | 199 | rc)); |
200 | } else { | 200 | } else { |
201 | direntry->d_op = &cifs_dentry_ops; | 201 | if (pTcon->nocase) |
202 | direntry->d_op = &cifs_ci_dentry_ops; | ||
203 | else | ||
204 | direntry->d_op = &cifs_dentry_ops; | ||
202 | d_instantiate(direntry, newinode); | 205 | d_instantiate(direntry, newinode); |
203 | } | 206 | } |
204 | } | 207 | } |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 20ae4153f791..eba1de917f2a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp; | |||
34 | extern mempool_t *cifs_req_poolp; | 34 | extern mempool_t *cifs_req_poolp; |
35 | extern struct task_struct * oplockThread; | 35 | extern struct task_struct * oplockThread; |
36 | 36 | ||
37 | static __u16 GlobalMid; /* multiplex id - rotating counter */ | ||
38 | |||
39 | /* The xid serves as a useful identifier for each incoming vfs request, | 37 | /* The xid serves as a useful identifier for each incoming vfs request, |
40 | in a similar way to the mid which is useful to track each sent smb, | 38 | in a similar way to the mid which is useful to track each sent smb, |
41 | and CurrentXid can also provide a running counter (although it | 39 | and CurrentXid can also provide a running counter (although it |
@@ -51,6 +49,8 @@ _GetXid(void) | |||
51 | GlobalTotalActiveXid++; | 49 | GlobalTotalActiveXid++; |
52 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) | 50 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) |
53 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ | 51 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ |
52 | if(GlobalTotalActiveXid > 65000) | ||
53 | cFYI(1,("warning: more than 65000 requests active")); | ||
54 | xid = GlobalCurrentXid++; | 54 | xid = GlobalCurrentXid++; |
55 | spin_unlock(&GlobalMid_Lock); | 55 | spin_unlock(&GlobalMid_Lock); |
56 | return xid; | 56 | return xid; |
@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free) | |||
218 | return; | 218 | return; |
219 | } | 219 | } |
220 | 220 | ||
221 | /* | ||
222 | Find a free multiplex id (SMB mid). Otherwise there could be | ||
223 | mid collisions which might cause problems, demultiplexing the | ||
224 | wrong response to this request. Multiplex ids could collide if | ||
225 | one of a series requests takes much longer than the others, or | ||
226 | if a very large number of long lived requests (byte range | ||
227 | locks or FindNotify requests) are pending. No more than | ||
228 | 64K-1 requests can be outstanding at one time. If no | ||
229 | mids are available, return zero. A future optimization | ||
230 | could make the combination of mids and uid the key we use | ||
231 | to demultiplex on (rather than mid alone). | ||
232 | In addition to the above check, the cifs demultiplex | ||
233 | code already used the command code as a secondary | ||
234 | check of the frame and if signing is negotiated the | ||
235 | response would be discarded if the mid were the same | ||
236 | but the signature was wrong. Since the mid is not put in the | ||
237 | pending queue until later (when it is about to be dispatched) | ||
238 | we do have to limit the number of outstanding requests | ||
239 | to somewhat less than 64K-1 although it is hard to imagine | ||
240 | so many threads being in the vfs at one time. | ||
241 | */ | ||
242 | __u16 GetNextMid(struct TCP_Server_Info *server) | ||
243 | { | ||
244 | __u16 mid = 0; | ||
245 | __u16 last_mid; | ||
246 | int collision; | ||
247 | |||
248 | if(server == NULL) | ||
249 | return mid; | ||
250 | |||
251 | spin_lock(&GlobalMid_Lock); | ||
252 | last_mid = server->CurrentMid; /* we do not want to loop forever */ | ||
253 | server->CurrentMid++; | ||
254 | /* This nested loop looks more expensive than it is. | ||
255 | In practice the list of pending requests is short, | ||
256 | fewer than 50, and the mids are likely to be unique | ||
257 | on the first pass through the loop unless some request | ||
258 | takes longer than the 64 thousand requests before it | ||
259 | (and it would also have to have been a request that | ||
260 | did not time out) */ | ||
261 | while(server->CurrentMid != last_mid) { | ||
262 | struct list_head *tmp; | ||
263 | struct mid_q_entry *mid_entry; | ||
264 | |||
265 | collision = 0; | ||
266 | if(server->CurrentMid == 0) | ||
267 | server->CurrentMid++; | ||
268 | |||
269 | list_for_each(tmp, &server->pending_mid_q) { | ||
270 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
271 | |||
272 | if ((mid_entry->mid == server->CurrentMid) && | ||
273 | (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | ||
274 | /* This mid is in use, try a different one */ | ||
275 | collision = 1; | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | if(collision == 0) { | ||
280 | mid = server->CurrentMid; | ||
281 | break; | ||
282 | } | ||
283 | server->CurrentMid++; | ||
284 | } | ||
285 | spin_unlock(&GlobalMid_Lock); | ||
286 | return mid; | ||
287 | } | ||
288 | |||
289 | /* NB: MID can not be set if treeCon not passed in, in that | ||
290 | case it is responsbility of caller to set the mid */ | ||
221 | void | 291 | void |
222 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | 292 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , |
223 | const struct cifsTconInfo *treeCon, int word_count | 293 | const struct cifsTconInfo *treeCon, int word_count |
@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
233 | (2 * word_count) + sizeof (struct smb_hdr) - | 303 | (2 * word_count) + sizeof (struct smb_hdr) - |
234 | 4 /* RFC 1001 length field does not count */ + | 304 | 4 /* RFC 1001 length field does not count */ + |
235 | 2 /* for bcc field itself */ ; | 305 | 2 /* for bcc field itself */ ; |
236 | /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */ | 306 | /* Note that this is the only network field that has to be converted |
307 | to big endian and it is done just before we send it */ | ||
237 | 308 | ||
238 | buffer->Protocol[0] = 0xFF; | 309 | buffer->Protocol[0] = 0xFF; |
239 | buffer->Protocol[1] = 'S'; | 310 | buffer->Protocol[1] = 'S'; |
@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
245 | buffer->Pid = cpu_to_le16((__u16)current->tgid); | 316 | buffer->Pid = cpu_to_le16((__u16)current->tgid); |
246 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); | 317 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); |
247 | spin_lock(&GlobalMid_Lock); | 318 | spin_lock(&GlobalMid_Lock); |
248 | GlobalMid++; | ||
249 | buffer->Mid = GlobalMid; | ||
250 | spin_unlock(&GlobalMid_Lock); | 319 | spin_unlock(&GlobalMid_Lock); |
251 | if (treeCon) { | 320 | if (treeCon) { |
252 | buffer->Tid = treeCon->tid; | 321 | buffer->Tid = treeCon->tid; |
@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
256 | if (treeCon->ses->capabilities & CAP_STATUS32) { | 325 | if (treeCon->ses->capabilities & CAP_STATUS32) { |
257 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; | 326 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; |
258 | } | 327 | } |
259 | 328 | /* Uid is not converted */ | |
260 | buffer->Uid = treeCon->ses->Suid; /* always in LE format */ | 329 | buffer->Uid = treeCon->ses->Suid; |
330 | buffer->Mid = GetNextMid(treeCon->ses->server); | ||
261 | if(multiuser_mount != 0) { | 331 | if(multiuser_mount != 0) { |
262 | /* For the multiuser case, there are few obvious technically */ | 332 | /* For the multiuser case, there are few obvious technically */ |
263 | /* possible mechanisms to match the local linux user (uid) */ | 333 | /* possible mechanisms to match the local linux user (uid) */ |
@@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
305 | } | 375 | } |
306 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) | 376 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) |
307 | buffer->Flags2 |= SMBFLG2_DFS; | 377 | buffer->Flags2 |= SMBFLG2_DFS; |
378 | if (treeCon->nocase) | ||
379 | buffer->Flags |= SMBFLG_CASELESS; | ||
308 | if((treeCon->ses) && (treeCon->ses->server)) | 380 | if((treeCon->ses) && (treeCon->ses->server)) |
309 | if(treeCon->ses->server->secMode & | 381 | if(treeCon->ses->server->secMode & |
310 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 382 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
@@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) | |||
347 | int | 419 | int |
348 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) | 420 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) |
349 | { | 421 | { |
350 | __u32 len = be32_to_cpu(smb->smb_buf_length); | 422 | __u32 len = smb->smb_buf_length; |
423 | __u32 clc_len; /* calculated length */ | ||
351 | cFYI(0, | 424 | cFYI(0, |
352 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", | 425 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", |
353 | length, len)); | 426 | length, len)); |
@@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
368 | cERROR(1, | 441 | cERROR(1, |
369 | ("smb_buf_length greater than MaxBufSize")); | 442 | ("smb_buf_length greater than MaxBufSize")); |
370 | cERROR(1, | 443 | cERROR(1, |
371 | ("bad smb detected. Illegal length. The mid=%d", | 444 | ("bad smb detected. Illegal length. mid=%d", |
372 | smb->Mid)); | 445 | smb->Mid)); |
373 | return 1; | 446 | return 1; |
374 | } | 447 | } |
375 | 448 | ||
376 | if (checkSMBhdr(smb, mid)) | 449 | if (checkSMBhdr(smb, mid)) |
377 | return 1; | 450 | return 1; |
378 | 451 | clc_len = smbCalcSize_LE(smb); | |
379 | if ((4 + len != smbCalcSize(smb)) | 452 | if ((4 + len != clc_len) |
380 | || (4 + len != (unsigned int)length)) { | 453 | || (4 + len != (unsigned int)length)) { |
381 | return 0; | 454 | cERROR(1, ("Calculated size 0x%x vs actual length 0x%x", |
382 | } else { | 455 | clc_len, 4 + len)); |
383 | cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); | 456 | cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); |
384 | cERROR(1, | 457 | /* Windows XP can return a few bytes too much, presumably |
385 | ("bad smb size detected. The Mid=%d", smb->Mid)); | 458 | an illegal pad, at the end of byte range lock responses |
386 | return 1; | 459 | so we allow for up to eight byte pad, as long as actual |
460 | received length is as long or longer than calculated length */ | ||
461 | if((4+len > clc_len) && (len <= clc_len + 3)) | ||
462 | return 0; | ||
463 | else | ||
464 | return 1; | ||
387 | } | 465 | } |
466 | return 0; | ||
388 | } | 467 | } |
389 | int | 468 | int |
390 | is_valid_oplock_break(struct smb_hdr *buf) | 469 | is_valid_oplock_break(struct smb_hdr *buf) |
@@ -448,9 +527,7 @@ is_valid_oplock_break(struct smb_hdr *buf) | |||
448 | list_for_each(tmp, &GlobalTreeConnectionList) { | 527 | list_for_each(tmp, &GlobalTreeConnectionList) { |
449 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 528 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
450 | if (tcon->tid == buf->Tid) { | 529 | if (tcon->tid == buf->Tid) { |
451 | #ifdef CONFIG_CIFS_STATS | 530 | cifs_stats_inc(&tcon->num_oplock_brks); |
452 | atomic_inc(&tcon->num_oplock_brks); | ||
453 | #endif | ||
454 | list_for_each(tmp1,&tcon->openFileList){ | 531 | list_for_each(tmp1,&tcon->openFileList){ |
455 | netfile = list_entry(tmp1,struct cifsFileInfo, | 532 | netfile = list_entry(tmp1,struct cifsFileInfo, |
456 | tlist); | 533 | tlist); |
@@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | |||
603 | int i,j,charlen; | 680 | int i,j,charlen; |
604 | int len_remaining = maxlen; | 681 | int len_remaining = maxlen; |
605 | char src_char; | 682 | char src_char; |
683 | __u16 temp; | ||
606 | 684 | ||
607 | if(!mapChars) | 685 | if(!mapChars) |
608 | return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); | 686 | return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); |
@@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | |||
639 | break;*/ | 717 | break;*/ |
640 | default: | 718 | default: |
641 | charlen = cp->char2uni(source+i, | 719 | charlen = cp->char2uni(source+i, |
642 | len_remaining, target+j); | 720 | len_remaining, &temp); |
643 | /* if no match, use question mark, which | 721 | /* if no match, use question mark, which |
644 | at least in some cases servers as wild card */ | 722 | at least in some cases servers as wild card */ |
645 | if(charlen < 1) { | 723 | if(charlen < 1) { |
646 | target[j] = cpu_to_le16(0x003f); | 724 | target[j] = cpu_to_le16(0x003f); |
647 | charlen = 1; | 725 | charlen = 1; |
648 | } | 726 | } else |
727 | target[j] = cpu_to_le16(temp); | ||
649 | len_remaining -= charlen; | 728 | len_remaining -= charlen; |
650 | /* character may take more than one byte in the | 729 | /* character may take more than one byte in the |
651 | the source string, but will take exactly two | 730 | the source string, but will take exactly two |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index a92af41d4411..f7814689844b 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | |||
133 | int | 133 | int |
134 | cifs_inet_pton(int address_family, char *cp,void *dst) | 134 | cifs_inet_pton(int address_family, char *cp,void *dst) |
135 | { | 135 | { |
136 | struct in_addr address; | ||
137 | int value; | 136 | int value; |
138 | int digit; | 137 | int digit; |
139 | int i; | 138 | int i; |
@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst) | |||
190 | if (value > addr_class_max[end - bytes]) | 189 | if (value > addr_class_max[end - bytes]) |
191 | return 0; | 190 | return 0; |
192 | 191 | ||
193 | address.s_addr = *((__be32 *) bytes) | htonl(value); | 192 | *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value); |
194 | *((__be32 *)dst) = address.s_addr; | ||
195 | return 1; /* success */ | 193 | return 1; /* success */ |
196 | } | 194 | } |
197 | 195 | ||
@@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) | |||
815 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { | 813 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { |
816 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ | 814 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ |
817 | __u32 err = le32_to_cpu(smb->Status.CifsError); | 815 | __u32 err = le32_to_cpu(smb->Status.CifsError); |
818 | if(cifsFYI) | 816 | if(cifsFYI & CIFS_RC) |
819 | cifs_print_status(err); | 817 | cifs_print_status(err); |
820 | ntstatus_to_dos(err, &smberrclass, &smberrcode); | 818 | ntstatus_to_dos(err, &smberrclass, &smberrcode); |
821 | } else { | 819 | } else { |
@@ -870,7 +868,14 @@ unsigned int | |||
870 | smbCalcSize(struct smb_hdr *ptr) | 868 | smbCalcSize(struct smb_hdr *ptr) |
871 | { | 869 | { |
872 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | 870 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + |
873 | BCC(ptr)); | 871 | 2 /* size of the bcc field */ + BCC(ptr)); |
872 | } | ||
873 | |||
874 | unsigned int | ||
875 | smbCalcSize_LE(struct smb_hdr *ptr) | ||
876 | { | ||
877 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | ||
878 | 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); | ||
874 | } | 879 | } |
875 | 880 | ||
876 | /* The following are taken from fs/ntfs/util.c */ | 881 | /* The following are taken from fs/ntfs/util.c */ |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 6facb41117a3..803389b64a2c 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
@@ -19,8 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #pragma pack(1) | ||
23 | |||
24 | #define NTLMSSP_SIGNATURE "NTLMSSP" | 22 | #define NTLMSSP_SIGNATURE "NTLMSSP" |
25 | /* Message Types */ | 23 | /* Message Types */ |
26 | #define NtLmNegotiate cpu_to_le32(1) | 24 | #define NtLmNegotiate cpu_to_le32(1) |
@@ -63,7 +61,7 @@ typedef struct _SECURITY_BUFFER { | |||
63 | __le16 Length; | 61 | __le16 Length; |
64 | __le16 MaximumLength; | 62 | __le16 MaximumLength; |
65 | __le32 Buffer; /* offset to buffer */ | 63 | __le32 Buffer; /* offset to buffer */ |
66 | } SECURITY_BUFFER; | 64 | } __attribute__((packed)) SECURITY_BUFFER; |
67 | 65 | ||
68 | typedef struct _NEGOTIATE_MESSAGE { | 66 | typedef struct _NEGOTIATE_MESSAGE { |
69 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 67 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; |
@@ -73,7 +71,7 @@ typedef struct _NEGOTIATE_MESSAGE { | |||
73 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ | 71 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ |
74 | char DomainString[0]; | 72 | char DomainString[0]; |
75 | /* followed by WorkstationString */ | 73 | /* followed by WorkstationString */ |
76 | } NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; | 74 | } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; |
77 | 75 | ||
78 | typedef struct _CHALLENGE_MESSAGE { | 76 | typedef struct _CHALLENGE_MESSAGE { |
79 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 77 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; |
@@ -83,7 +81,7 @@ typedef struct _CHALLENGE_MESSAGE { | |||
83 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; | 81 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; |
84 | __u8 Reserved[8]; | 82 | __u8 Reserved[8]; |
85 | SECURITY_BUFFER TargetInfoArray; | 83 | SECURITY_BUFFER TargetInfoArray; |
86 | } CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; | 84 | } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; |
87 | 85 | ||
88 | typedef struct _AUTHENTICATE_MESSAGE { | 86 | typedef struct _AUTHENTICATE_MESSAGE { |
89 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 87 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; |
@@ -96,6 +94,4 @@ typedef struct _AUTHENTICATE_MESSAGE { | |||
96 | SECURITY_BUFFER SessionKey; | 94 | SECURITY_BUFFER SessionKey; |
97 | __le32 NegotiateFlags; | 95 | __le32 NegotiateFlags; |
98 | char UserString[0]; | 96 | char UserString[0]; |
99 | } AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; | 97 | } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; |
100 | |||
101 | #pragma pack() /* resume default structure packing */ | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 22557716f9af..a86bd1c07602 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
91 | } | 91 | } |
92 | 92 | ||
93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); | 93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); |
94 | tmp_dentry->d_op = &cifs_dentry_ops; | 94 | if (pTcon->nocase) |
95 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | ||
96 | else | ||
97 | tmp_dentry->d_op = &cifs_dentry_ops; | ||
95 | if(*ptmp_inode == NULL) | 98 | if(*ptmp_inode == NULL) |
96 | return rc; | 99 | return rc; |
97 | rc = 1; | 100 | rc = 1; |
@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
148 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; | 151 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; |
149 | } | 152 | } |
150 | tmp_inode->i_mode |= S_IFDIR; | 153 | tmp_inode->i_mode |= S_IFDIR; |
154 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
155 | (attr & ATTR_SYSTEM) && (end_of_file == 0)) { | ||
156 | *pobject_type = DT_FIFO; | ||
157 | tmp_inode->i_mode |= S_IFIFO; | ||
158 | /* BB Finish for SFU style symlinks and devies */ | ||
159 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
160 | (attr & ATTR_SYSTEM) && ) { */ | ||
151 | /* we no longer mark these because we could not follow them */ | 161 | /* we no longer mark these because we could not follow them */ |
152 | /* } else if (attr & ATTR_REPARSE) { | 162 | /* } else if (attr & ATTR_REPARSE) { |
153 | *pobject_type = DT_LNK; | 163 | *pobject_type = DT_LNK; |
@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
187 | tmp_inode->i_fop = &cifs_file_direct_ops; | 197 | tmp_inode->i_fop = &cifs_file_direct_ops; |
188 | else | 198 | else |
189 | tmp_inode->i_fop = &cifs_file_ops; | 199 | tmp_inode->i_fop = &cifs_file_ops; |
200 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
201 | tmp_inode->i_fop->lock = NULL; | ||
190 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 202 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
191 | 203 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | |
204 | (cifs_sb->tcon->ses->server->maxBuf < | ||
205 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
206 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
192 | if(isNewInode) | 207 | if(isNewInode) |
193 | return; /* No sense invalidating pages for new inode since we | 208 | return; /* No sense invalidating pages for new inode |
194 | have not started caching readahead file data yet */ | 209 | since have not started caching readahead file |
210 | data yet */ | ||
195 | 211 | ||
196 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | 212 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && |
197 | (local_size == tmp_inode->i_size)) { | 213 | (local_size == tmp_inode->i_size)) { |
@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
290 | tmp_inode->i_fop = &cifs_file_direct_ops; | 306 | tmp_inode->i_fop = &cifs_file_direct_ops; |
291 | else | 307 | else |
292 | tmp_inode->i_fop = &cifs_file_ops; | 308 | tmp_inode->i_fop = &cifs_file_ops; |
309 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
310 | tmp_inode->i_fop->lock = NULL; | ||
293 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 311 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
312 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
313 | (cifs_sb->tcon->ses->server->maxBuf < | ||
314 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
315 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
294 | 316 | ||
295 | if(isNewInode) | 317 | if(isNewInode) |
296 | return; /* No sense invalidating pages for new inode since we | 318 | return; /* No sense invalidating pages for new inode since we |
@@ -374,7 +396,8 @@ ffirst_retry: | |||
374 | 396 | ||
375 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | 397 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, |
376 | &cifsFile->netfid, &cifsFile->srch_inf, | 398 | &cifsFile->netfid, &cifsFile->srch_inf, |
377 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 399 | cifs_sb->mnt_cifs_flags & |
400 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | ||
378 | if(rc == 0) | 401 | if(rc == 0) |
379 | cifsFile->invalidHandle = FALSE; | 402 | cifsFile->invalidHandle = FALSE; |
380 | if((rc == -EOPNOTSUPP) && | 403 | if((rc == -EOPNOTSUPP) && |
@@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
491 | return rc; | 514 | return rc; |
492 | } | 515 | } |
493 | 516 | ||
517 | /* Check if directory that we are searching has changed so we can decide | ||
518 | whether we can use the cached search results from the previous search */ | ||
519 | static int is_dir_changed(struct file * file) | ||
520 | { | ||
521 | struct inode * inode; | ||
522 | struct cifsInodeInfo *cifsInfo; | ||
523 | |||
524 | if(file->f_dentry == NULL) | ||
525 | return 0; | ||
526 | |||
527 | inode = file->f_dentry->d_inode; | ||
528 | |||
529 | if(inode == NULL) | ||
530 | return 0; | ||
531 | |||
532 | cifsInfo = CIFS_I(inode); | ||
533 | |||
534 | if(cifsInfo->time == 0) | ||
535 | return 1; /* directory was changed, perhaps due to unlink */ | ||
536 | else | ||
537 | return 0; | ||
538 | |||
539 | } | ||
540 | |||
494 | /* find the corresponding entry in the search */ | 541 | /* find the corresponding entry in the search */ |
495 | /* Note that the SMB server returns search entries for . and .. which | 542 | /* Note that the SMB server returns search entries for . and .. which |
496 | complicates logic here if we choose to parse for them and we do not | 543 | complicates logic here if we choose to parse for them and we do not |
@@ -507,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
507 | struct cifsFileInfo * cifsFile = file->private_data; | 554 | struct cifsFileInfo * cifsFile = file->private_data; |
508 | /* check if index in the buffer */ | 555 | /* check if index in the buffer */ |
509 | 556 | ||
510 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) | 557 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || |
558 | (num_to_ret == NULL)) | ||
511 | return -ENOENT; | 559 | return -ENOENT; |
512 | 560 | ||
513 | *ppCurrentEntry = NULL; | 561 | *ppCurrentEntry = NULL; |
@@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
515 | cifsFile->srch_inf.index_of_last_entry - | 563 | cifsFile->srch_inf.index_of_last_entry - |
516 | cifsFile->srch_inf.entries_in_buffer; | 564 | cifsFile->srch_inf.entries_in_buffer; |
517 | /* dump_cifs_file_struct(file, "In fce ");*/ | 565 | /* dump_cifs_file_struct(file, "In fce ");*/ |
518 | if(index_to_find < first_entry_in_buffer) { | 566 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
567 | is_dir_changed(file)) || | ||
568 | (index_to_find < first_entry_in_buffer)) { | ||
519 | /* close and restart search */ | 569 | /* close and restart search */ |
520 | cFYI(1,("search backing up - close and restart search")); | 570 | cFYI(1,("search backing up - close and restart search")); |
521 | cifsFile->invalidHandle = TRUE; | 571 | cifsFile->invalidHandle = TRUE; |
@@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
536 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 586 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && |
537 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ | 587 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ |
538 | cFYI(1,("calling findnext2")); | 588 | cFYI(1,("calling findnext2")); |
539 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); | 589 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, |
590 | &cifsFile->srch_inf); | ||
540 | if(rc) | 591 | if(rc) |
541 | return -ENOENT; | 592 | return -ENOENT; |
542 | } | 593 | } |
@@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
548 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 599 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + |
549 | smbCalcSize((struct smb_hdr *) | 600 | smbCalcSize((struct smb_hdr *) |
550 | cifsFile->srch_inf.ntwrk_buf_start); | 601 | cifsFile->srch_inf.ntwrk_buf_start); |
551 | /* dump_cifs_file_struct(file,"found entry in fce "); */ | ||
552 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 602 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry |
553 | - cifsFile->srch_inf.entries_in_buffer; | 603 | - cifsFile->srch_inf.entries_in_buffer; |
554 | pos_in_buf = index_to_find - first_entry_in_buffer; | 604 | pos_in_buf = index_to_find - first_entry_in_buffer; |
555 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | 605 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); |
556 | current_entry = cifsFile->srch_inf.srch_entries_start; | 606 | current_entry = cifsFile->srch_inf.srch_entries_start; |
557 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | 607 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { |
558 | /* go entry to next entry figuring out which we need to start with */ | 608 | /* go entry by entry figuring out which is first */ |
559 | /* if( . or ..) | 609 | /* if( . or ..) |
560 | skip */ | 610 | skip */ |
561 | rc = cifs_entry_is_dot(current_entry,cifsFile); | 611 | rc = cifs_entry_is_dot(current_entry,cifsFile); |
@@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
582 | } | 632 | } |
583 | 633 | ||
584 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { | 634 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { |
585 | cFYI(1,("can not return entries when pos_in_buf beyond last entry")); | 635 | cFYI(1,("can not return entries pos_in_buf beyond last entry")); |
586 | *num_to_ret = 0; | 636 | *num_to_ret = 0; |
587 | } else | 637 | } else |
588 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; | 638 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; |
589 | /* dump_cifs_file_struct(file, "end fce ");*/ | ||
590 | 639 | ||
591 | return rc; | 640 | return rc; |
592 | } | 641 | } |
@@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
721 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); | 770 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); |
722 | } | 771 | } |
723 | 772 | ||
724 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); | 773 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, |
774 | tmp_inode->i_ino,obj_type); | ||
725 | if(rc) { | 775 | if(rc) { |
726 | cFYI(1,("filldir rc = %d",rc)); | 776 | cFYI(1,("filldir rc = %d",rc)); |
727 | } | 777 | } |
@@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
805 | FreeXid(xid); | 855 | FreeXid(xid); |
806 | return -EIO; | 856 | return -EIO; |
807 | } | 857 | } |
808 | /* dump_cifs_file_struct(file, "Begin rdir "); */ | ||
809 | 858 | ||
810 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 859 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
811 | pTcon = cifs_sb->tcon; | 860 | pTcon = cifs_sb->tcon; |
812 | if(pTcon == NULL) | 861 | if(pTcon == NULL) |
813 | return -EINVAL; | 862 | return -EINVAL; |
814 | 863 | ||
815 | /* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ | ||
816 | |||
817 | switch ((int) file->f_pos) { | 864 | switch ((int) file->f_pos) { |
818 | case 0: | 865 | case 0: |
819 | /*if (filldir(direntry, ".", 1, file->f_pos, | 866 | /*if (filldir(direntry, ".", 1, file->f_pos, |
@@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
866 | cifsFile->search_resume_name = NULL; */ | 913 | cifsFile->search_resume_name = NULL; */ |
867 | 914 | ||
868 | /* BB account for . and .. in f_pos as special case */ | 915 | /* BB account for . and .. in f_pos as special case */ |
869 | /* dump_cifs_file_struct(file, "rdir after default ");*/ | ||
870 | 916 | ||
871 | rc = find_cifs_entry(xid,pTcon, file, | 917 | rc = find_cifs_entry(xid,pTcon, file, |
872 | ¤t_entry,&num_to_fill); | 918 | ¤t_entry,&num_to_fill); |
@@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
906 | cifs_save_resume_key(current_entry,cifsFile); | 952 | cifs_save_resume_key(current_entry,cifsFile); |
907 | break; | 953 | break; |
908 | } else | 954 | } else |
909 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | 955 | current_entry = nxt_dir_entry(current_entry, |
956 | end_of_smb); | ||
910 | } | 957 | } |
911 | kfree(tmp_buf); | 958 | kfree(tmp_buf); |
912 | break; | 959 | break; |
913 | } /* end switch */ | 960 | } /* end switch */ |
914 | 961 | ||
915 | rddir2_exit: | 962 | rddir2_exit: |
916 | /* dump_cifs_file_struct(file, "end rdir "); */ | ||
917 | FreeXid(xid); | 963 | FreeXid(xid); |
918 | return rc; | 964 | return rc; |
919 | } | 965 | } |
diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h index 806c0ed06da9..9222033cad8e 100644 --- a/fs/cifs/rfc1002pdu.h +++ b/fs/cifs/rfc1002pdu.h | |||
@@ -21,8 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #pragma pack(1) | ||
25 | |||
26 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ | 24 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ |
27 | 25 | ||
28 | /* RFC 1002 session packet types */ | 26 | /* RFC 1002 session packet types */ |
@@ -48,17 +46,17 @@ struct rfc1002_session_packet { | |||
48 | __u8 calling_len; | 46 | __u8 calling_len; |
49 | __u8 calling_name[32]; | 47 | __u8 calling_name[32]; |
50 | __u8 scope2; /* null */ | 48 | __u8 scope2; /* null */ |
51 | } session_req; | 49 | } __attribute__((packed)) session_req; |
52 | struct { | 50 | struct { |
53 | __u32 retarget_ip_addr; | 51 | __u32 retarget_ip_addr; |
54 | __u16 port; | 52 | __u16 port; |
55 | } retarget_resp; | 53 | } __attribute__((packed)) retarget_resp; |
56 | __u8 neg_ses_resp_error_code; | 54 | __u8 neg_ses_resp_error_code; |
57 | /* POSITIVE_SESSION_RESPONSE packet does not include trailer. | 55 | /* POSITIVE_SESSION_RESPONSE packet does not include trailer. |
58 | SESSION_KEEP_ALIVE packet also does not include a trailer. | 56 | SESSION_KEEP_ALIVE packet also does not include a trailer. |
59 | Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ | 57 | Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ |
60 | } trailer; | 58 | } __attribute__((packed)) trailer; |
61 | }; | 59 | } __attribute__((packed)); |
62 | 60 | ||
63 | /* Negative Session Response error codes */ | 61 | /* Negative Session Response error codes */ |
64 | #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ | 62 | #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ |
@@ -74,6 +72,3 @@ server netbios name). Currently server names are resolved only via DNS | |||
74 | (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ | 72 | (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ |
75 | 73 | ||
76 | #define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " | 74 | #define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " |
77 | |||
78 | #pragma pack() /* resume default structure packing */ | ||
79 | |||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0046c219833d..981ea0d8b9cd 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
49 | return NULL; | 49 | return NULL; |
50 | } | 50 | } |
51 | 51 | ||
52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); | 52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, |
53 | SLAB_KERNEL | SLAB_NOFS); | ||
53 | if (temp == NULL) | 54 | if (temp == NULL) |
54 | return temp; | 55 | return temp; |
55 | else { | 56 | else { |
@@ -58,7 +59,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
58 | temp->pid = current->pid; | 59 | temp->pid = current->pid; |
59 | temp->command = smb_buffer->Command; | 60 | temp->command = smb_buffer->Command; |
60 | cFYI(1, ("For smb_command %d", temp->command)); | 61 | cFYI(1, ("For smb_command %d", temp->command)); |
61 | do_gettimeofday(&temp->when_sent); | 62 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
63 | /* when mid allocated can be before when sent */ | ||
64 | temp->when_alloc = jiffies; | ||
62 | temp->ses = ses; | 65 | temp->ses = ses; |
63 | temp->tsk = current; | 66 | temp->tsk = current; |
64 | } | 67 | } |
@@ -74,6 +77,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
74 | static void | 77 | static void |
75 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 78 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
76 | { | 79 | { |
80 | #ifdef CONFIG_CIFS_STATS2 | ||
81 | unsigned long now; | ||
82 | #endif | ||
77 | spin_lock(&GlobalMid_Lock); | 83 | spin_lock(&GlobalMid_Lock); |
78 | midEntry->midState = MID_FREE; | 84 | midEntry->midState = MID_FREE; |
79 | list_del(&midEntry->qhead); | 85 | list_del(&midEntry->qhead); |
@@ -83,6 +89,22 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
83 | cifs_buf_release(midEntry->resp_buf); | 89 | cifs_buf_release(midEntry->resp_buf); |
84 | else | 90 | else |
85 | cifs_small_buf_release(midEntry->resp_buf); | 91 | cifs_small_buf_release(midEntry->resp_buf); |
92 | #ifdef CONFIG_CIFS_STATS2 | ||
93 | now = jiffies; | ||
94 | /* commands taking longer than one second are indications that | ||
95 | something is wrong, unless it is quite a slow link or server */ | ||
96 | if((now - midEntry->when_alloc) > HZ) { | ||
97 | if((cifsFYI & CIFS_TIMER) && | ||
98 | (midEntry->command != SMB_COM_LOCKING_ANDX)) { | ||
99 | printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d", | ||
100 | midEntry->command, midEntry->mid); | ||
101 | printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n", | ||
102 | now - midEntry->when_alloc, | ||
103 | now - midEntry->when_sent, | ||
104 | now - midEntry->when_received); | ||
105 | } | ||
106 | } | ||
107 | #endif | ||
86 | mempool_free(midEntry, cifs_mid_poolp); | 108 | mempool_free(midEntry, cifs_mid_poolp); |
87 | } | 109 | } |
88 | 110 | ||
@@ -146,32 +168,37 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
146 | Flags2 is converted in SendReceive */ | 168 | Flags2 is converted in SendReceive */ |
147 | 169 | ||
148 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 170 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
149 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 171 | cFYI(1, ("Sending smb of length %d", smb_buf_length)); |
150 | dump_smb(smb_buffer, len); | 172 | dump_smb(smb_buffer, len); |
151 | 173 | ||
152 | while (len > 0) { | 174 | while (len > 0) { |
153 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); | 175 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); |
154 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 176 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
155 | i++; | 177 | i++; |
156 | if(i > 60) { | 178 | /* smaller timeout here than send2 since smaller size */ |
179 | /* Although it may not be required, this also is smaller | ||
180 | oplock break time */ | ||
181 | if(i > 12) { | ||
157 | cERROR(1, | 182 | cERROR(1, |
158 | ("sends on sock %p stuck for 30 seconds", | 183 | ("sends on sock %p stuck for 7 seconds", |
159 | ssocket)); | 184 | ssocket)); |
160 | rc = -EAGAIN; | 185 | rc = -EAGAIN; |
161 | break; | 186 | break; |
162 | } | 187 | } |
163 | msleep(500); | 188 | msleep(1 << i); |
164 | continue; | 189 | continue; |
165 | } | 190 | } |
166 | if (rc < 0) | 191 | if (rc < 0) |
167 | break; | 192 | break; |
193 | else | ||
194 | i = 0; /* reset i after each successful send */ | ||
168 | iov.iov_base += rc; | 195 | iov.iov_base += rc; |
169 | iov.iov_len -= rc; | 196 | iov.iov_len -= rc; |
170 | len -= rc; | 197 | len -= rc; |
171 | } | 198 | } |
172 | 199 | ||
173 | if (rc < 0) { | 200 | if (rc < 0) { |
174 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 201 | cERROR(1,("Error %d sending data on socket to server", rc)); |
175 | } else { | 202 | } else { |
176 | rc = 0; | 203 | rc = 0; |
177 | } | 204 | } |
@@ -179,26 +206,21 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
179 | return rc; | 206 | return rc; |
180 | } | 207 | } |
181 | 208 | ||
182 | #ifdef CIFS_EXPERIMENTAL | 209 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
183 | /* BB finish off this function, adding support for writing set of pages as iovec */ | 210 | static int |
184 | /* and also adding support for operations that need to parse the response smb */ | 211 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, |
185 | 212 | struct sockaddr *sin) | |
186 | int | ||
187 | smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | ||
188 | unsigned int smb_buf_length, struct kvec * write_vector | ||
189 | /* page list */, struct sockaddr *sin) | ||
190 | { | 213 | { |
191 | int rc = 0; | 214 | int rc = 0; |
192 | int i = 0; | 215 | int i = 0; |
193 | struct msghdr smb_msg; | 216 | struct msghdr smb_msg; |
194 | number_of_pages += 1; /* account for SMB header */ | 217 | struct smb_hdr *smb_buffer = iov[0].iov_base; |
195 | struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); | 218 | unsigned int len = iov[0].iov_len; |
196 | unsigned len = smb_buf_length + 4; | 219 | unsigned int total_len; |
197 | 220 | int first_vec = 0; | |
221 | |||
198 | if(ssocket == NULL) | 222 | if(ssocket == NULL) |
199 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 223 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
200 | iov.iov_base = smb_buffer; | ||
201 | iov.iov_len = len; | ||
202 | 224 | ||
203 | smb_msg.msg_name = sin; | 225 | smb_msg.msg_name = sin; |
204 | smb_msg.msg_namelen = sizeof (struct sockaddr); | 226 | smb_msg.msg_namelen = sizeof (struct sockaddr); |
@@ -211,49 +233,80 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
211 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | 233 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send |
212 | Flags2 is converted in SendReceive */ | 234 | Flags2 is converted in SendReceive */ |
213 | 235 | ||
236 | |||
237 | total_len = 0; | ||
238 | for (i = 0; i < n_vec; i++) | ||
239 | total_len += iov[i].iov_len; | ||
240 | |||
214 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 241 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
215 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 242 | cFYI(1, ("Sending smb: total_len %d", total_len)); |
216 | dump_smb(smb_buffer, len); | 243 | dump_smb(smb_buffer, len); |
217 | 244 | ||
218 | while (len > 0) { | 245 | while (total_len) { |
219 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, | 246 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], |
220 | len); | 247 | n_vec - first_vec, total_len); |
221 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 248 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
222 | i++; | 249 | i++; |
223 | if(i > 60) { | 250 | if(i >= 14) { |
224 | cERROR(1, | 251 | cERROR(1, |
225 | ("sends on sock %p stuck for 30 seconds", | 252 | ("sends on sock %p stuck for 15 seconds", |
226 | ssocket)); | 253 | ssocket)); |
227 | rc = -EAGAIN; | 254 | rc = -EAGAIN; |
228 | break; | 255 | break; |
229 | } | 256 | } |
230 | msleep(500); | 257 | msleep(1 << i); |
231 | continue; | 258 | continue; |
232 | } | 259 | } |
233 | if (rc < 0) | 260 | if (rc < 0) |
234 | break; | 261 | break; |
235 | iov.iov_base += rc; | 262 | |
236 | iov.iov_len -= rc; | 263 | if (rc >= total_len) { |
237 | len -= rc; | 264 | WARN_ON(rc > total_len); |
265 | break; | ||
266 | } | ||
267 | if(rc == 0) { | ||
268 | /* should never happen, letting socket clear before | ||
269 | retrying is our only obvious option here */ | ||
270 | cERROR(1,("tcp sent no data")); | ||
271 | msleep(500); | ||
272 | continue; | ||
273 | } | ||
274 | total_len -= rc; | ||
275 | /* the line below resets i */ | ||
276 | for (i = first_vec; i < n_vec; i++) { | ||
277 | if (iov[i].iov_len) { | ||
278 | if (rc > iov[i].iov_len) { | ||
279 | rc -= iov[i].iov_len; | ||
280 | iov[i].iov_len = 0; | ||
281 | } else { | ||
282 | iov[i].iov_base += rc; | ||
283 | iov[i].iov_len -= rc; | ||
284 | first_vec = i; | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | i = 0; /* in case we get ENOSPC on the next send */ | ||
238 | } | 290 | } |
239 | 291 | ||
240 | if (rc < 0) { | 292 | if (rc < 0) { |
241 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 293 | cERROR(1,("Error %d sending data on socket to server", rc)); |
242 | } else { | 294 | } else |
243 | rc = 0; | 295 | rc = 0; |
244 | } | ||
245 | 296 | ||
246 | return rc; | 297 | return rc; |
247 | } | 298 | } |
248 | 299 | ||
249 | |||
250 | int | 300 | int |
251 | CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | 301 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
252 | struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) | 302 | struct kvec *iov, int n_vec, int *pbytes_returned, |
303 | const int long_op) | ||
253 | { | 304 | { |
254 | int rc = 0; | 305 | int rc = 0; |
255 | unsigned long timeout = 15 * HZ; | 306 | unsigned int receive_len; |
256 | struct mid_q_entry *midQ = NULL; | 307 | unsigned long timeout; |
308 | struct mid_q_entry *midQ; | ||
309 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
257 | 310 | ||
258 | if (ses == NULL) { | 311 | if (ses == NULL) { |
259 | cERROR(1,("Null smb session")); | 312 | cERROR(1,("Null smb session")); |
@@ -263,14 +316,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
263 | cERROR(1,("Null tcp session")); | 316 | cERROR(1,("Null tcp session")); |
264 | return -EIO; | 317 | return -EIO; |
265 | } | 318 | } |
266 | if(pbytes_returned == NULL) | ||
267 | return -EIO; | ||
268 | else | ||
269 | *pbytes_returned = 0; | ||
270 | 319 | ||
271 | 320 | if(ses->server->tcpStatus == CifsExiting) | |
272 | |||
273 | if(ses->server->tcpStatus == CIFS_EXITING) | ||
274 | return -ENOENT; | 321 | return -ENOENT; |
275 | 322 | ||
276 | /* Ensure that we do not send more than 50 overlapping requests | 323 | /* Ensure that we do not send more than 50 overlapping requests |
@@ -282,11 +329,18 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
282 | } else { | 329 | } else { |
283 | spin_lock(&GlobalMid_Lock); | 330 | spin_lock(&GlobalMid_Lock); |
284 | while(1) { | 331 | while(1) { |
285 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | 332 | if(atomic_read(&ses->server->inFlight) >= |
333 | cifs_max_pending){ | ||
286 | spin_unlock(&GlobalMid_Lock); | 334 | spin_unlock(&GlobalMid_Lock); |
335 | #ifdef CONFIG_CIFS_STATS2 | ||
336 | atomic_inc(&ses->server->num_waiters); | ||
337 | #endif | ||
287 | wait_event(ses->server->request_q, | 338 | wait_event(ses->server->request_q, |
288 | atomic_read(&ses->server->inFlight) | 339 | atomic_read(&ses->server->inFlight) |
289 | < cifs_max_pending); | 340 | < cifs_max_pending); |
341 | #ifdef CONFIG_CIFS_STATS2 | ||
342 | atomic_dec(&ses->server->num_waiters); | ||
343 | #endif | ||
290 | spin_lock(&GlobalMid_Lock); | 344 | spin_lock(&GlobalMid_Lock); |
291 | } else { | 345 | } else { |
292 | if(ses->server->tcpStatus == CifsExiting) { | 346 | if(ses->server->tcpStatus == CifsExiting) { |
@@ -314,17 +368,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
314 | 368 | ||
315 | if (ses->server->tcpStatus == CifsExiting) { | 369 | if (ses->server->tcpStatus == CifsExiting) { |
316 | rc = -ENOENT; | 370 | rc = -ENOENT; |
317 | goto cifs_out_label; | 371 | goto out_unlock2; |
318 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 372 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { |
319 | cFYI(1,("tcp session dead - return to caller to retry")); | 373 | cFYI(1,("tcp session dead - return to caller to retry")); |
320 | rc = -EAGAIN; | 374 | rc = -EAGAIN; |
321 | goto cifs_out_label; | 375 | goto out_unlock2; |
322 | } else if (ses->status != CifsGood) { | 376 | } else if (ses->status != CifsGood) { |
323 | /* check if SMB session is bad because we are setting it up */ | 377 | /* check if SMB session is bad because we are setting it up */ |
324 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 378 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
325 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | 379 | (in_buf->Command != SMB_COM_NEGOTIATE)) { |
326 | rc = -EAGAIN; | 380 | rc = -EAGAIN; |
327 | goto cifs_out_label; | 381 | goto out_unlock2; |
328 | } /* else ok - we are setting up session */ | 382 | } /* else ok - we are setting up session */ |
329 | } | 383 | } |
330 | midQ = AllocMidQEntry(in_buf, ses); | 384 | midQ = AllocMidQEntry(in_buf, ses); |
@@ -338,51 +392,162 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
338 | return -ENOMEM; | 392 | return -ENOMEM; |
339 | } | 393 | } |
340 | 394 | ||
341 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 395 | /* BB FIXME */ |
342 | up(&ses->server->tcpSem); | 396 | /* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ |
343 | cERROR(1, | 397 | |
344 | ("Illegal length, greater than maximum frame, %d ", | 398 | midQ->midState = MID_REQUEST_SUBMITTED; |
345 | in_buf->smb_buf_length)); | 399 | #ifdef CONFIG_CIFS_STATS2 |
400 | atomic_inc(&ses->server->inSend); | ||
401 | #endif | ||
402 | rc = smb_send2(ses->server->ssocket, iov, n_vec, | ||
403 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
404 | #ifdef CONFIG_CIFS_STATS2 | ||
405 | atomic_dec(&ses->server->inSend); | ||
406 | midQ->when_sent = jiffies; | ||
407 | #endif | ||
408 | if(rc < 0) { | ||
346 | DeleteMidQEntry(midQ); | 409 | DeleteMidQEntry(midQ); |
410 | up(&ses->server->tcpSem); | ||
347 | /* If not lock req, update # of requests on wire to server */ | 411 | /* If not lock req, update # of requests on wire to server */ |
348 | if(long_op < 3) { | 412 | if(long_op < 3) { |
349 | atomic_dec(&ses->server->inFlight); | 413 | atomic_dec(&ses->server->inFlight); |
350 | wake_up(&ses->server->request_q); | 414 | wake_up(&ses->server->request_q); |
351 | } | 415 | } |
352 | return -EIO; | 416 | return rc; |
417 | } else | ||
418 | up(&ses->server->tcpSem); | ||
419 | if (long_op == -1) | ||
420 | goto cifs_no_response_exit2; | ||
421 | else if (long_op == 2) /* writes past end of file can take loong time */ | ||
422 | timeout = 180 * HZ; | ||
423 | else if (long_op == 1) | ||
424 | timeout = 45 * HZ; /* should be greater than | ||
425 | servers oplock break timeout (about 43 seconds) */ | ||
426 | else if (long_op > 2) { | ||
427 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
428 | } else | ||
429 | timeout = 15 * HZ; | ||
430 | /* wait for 15 seconds or until woken up due to response arriving or | ||
431 | due to last connection to this server being unmounted */ | ||
432 | if (signal_pending(current)) { | ||
433 | /* if signal pending do not hold up user for full smb timeout | ||
434 | but we still give response a change to complete */ | ||
435 | timeout = 2 * HZ; | ||
436 | } | ||
437 | |||
438 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
439 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | ||
440 | timeout += jiffies; | ||
441 | wait_event(ses->server->response_q, | ||
442 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
443 | time_after(jiffies, timeout) || | ||
444 | ((ses->server->tcpStatus != CifsGood) && | ||
445 | (ses->server->tcpStatus != CifsNew))); | ||
446 | } else { | ||
447 | wait_event(ses->server->response_q, | ||
448 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
449 | ((ses->server->tcpStatus != CifsGood) && | ||
450 | (ses->server->tcpStatus != CifsNew))); | ||
353 | } | 451 | } |
354 | 452 | ||
355 | /* BB can we sign efficiently in this path? */ | 453 | spin_lock(&GlobalMid_Lock); |
356 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 454 | if (midQ->resp_buf) { |
455 | spin_unlock(&GlobalMid_Lock); | ||
456 | receive_len = midQ->resp_buf->smb_buf_length; | ||
457 | } else { | ||
458 | cERROR(1,("No response to cmd %d mid %d", | ||
459 | midQ->command, midQ->mid)); | ||
460 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
461 | if(ses->server->tcpStatus == CifsExiting) | ||
462 | rc = -EHOSTDOWN; | ||
463 | else { | ||
464 | ses->server->tcpStatus = CifsNeedReconnect; | ||
465 | midQ->midState = MID_RETRY_NEEDED; | ||
466 | } | ||
467 | } | ||
357 | 468 | ||
358 | midQ->midState = MID_REQUEST_SUBMITTED; | 469 | if (rc != -EHOSTDOWN) { |
359 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 470 | if(midQ->midState == MID_RETRY_NEEDED) { |
360 | piovec, | 471 | rc = -EAGAIN; |
361 | (struct sockaddr *) &(ses->server->addr.sockAddr));*/ | 472 | cFYI(1,("marking request for retry")); |
362 | if(rc < 0) { | 473 | } else { |
474 | rc = -EIO; | ||
475 | } | ||
476 | } | ||
477 | spin_unlock(&GlobalMid_Lock); | ||
363 | DeleteMidQEntry(midQ); | 478 | DeleteMidQEntry(midQ); |
364 | up(&ses->server->tcpSem); | ||
365 | /* If not lock req, update # of requests on wire to server */ | 479 | /* If not lock req, update # of requests on wire to server */ |
366 | if(long_op < 3) { | 480 | if(long_op < 3) { |
367 | atomic_dec(&ses->server->inFlight); | 481 | atomic_dec(&ses->server->inFlight); |
368 | wake_up(&ses->server->request_q); | 482 | wake_up(&ses->server->request_q); |
369 | } | 483 | } |
370 | return rc; | 484 | return rc; |
371 | } else | 485 | } |
372 | up(&ses->server->tcpSem); | 486 | |
373 | cifs_out_label: | 487 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
374 | if(midQ) | 488 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
375 | DeleteMidQEntry(midQ); | 489 | receive_len, xid)); |
376 | 490 | rc = -EIO; | |
491 | } else { /* rcvd frame is ok */ | ||
492 | |||
493 | if (midQ->resp_buf && | ||
494 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
495 | in_buf->smb_buf_length = receive_len; | ||
496 | /* BB verify that length would not overrun small buf */ | ||
497 | memcpy((char *)in_buf + 4, | ||
498 | (char *)midQ->resp_buf + 4, | ||
499 | receive_len); | ||
500 | |||
501 | dump_smb(in_buf, 80); | ||
502 | /* convert the length into a more usable form */ | ||
503 | if((receive_len > 24) && | ||
504 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
505 | SECMODE_SIGN_ENABLED))) { | ||
506 | rc = cifs_verify_signature(in_buf, | ||
507 | ses->server->mac_signing_key, | ||
508 | midQ->sequence_number+1); | ||
509 | if(rc) { | ||
510 | cERROR(1,("Unexpected SMB signature")); | ||
511 | /* BB FIXME add code to kill session */ | ||
512 | } | ||
513 | } | ||
514 | |||
515 | *pbytes_returned = in_buf->smb_buf_length; | ||
516 | |||
517 | /* BB special case reconnect tid and uid here? */ | ||
518 | rc = map_smb_to_linux_error(in_buf); | ||
519 | |||
520 | /* convert ByteCount if necessary */ | ||
521 | if (receive_len >= | ||
522 | sizeof (struct smb_hdr) - | ||
523 | 4 /* do not count RFC1001 header */ + | ||
524 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | ||
525 | BCC(in_buf) = le16_to_cpu(BCC(in_buf)); | ||
526 | } else { | ||
527 | rc = -EIO; | ||
528 | cFYI(1,("Bad MID state?")); | ||
529 | } | ||
530 | } | ||
531 | cifs_no_response_exit2: | ||
532 | DeleteMidQEntry(midQ); | ||
533 | |||
377 | if(long_op < 3) { | 534 | if(long_op < 3) { |
378 | atomic_dec(&ses->server->inFlight); | 535 | atomic_dec(&ses->server->inFlight); |
379 | wake_up(&ses->server->request_q); | 536 | wake_up(&ses->server->request_q); |
380 | } | 537 | } |
381 | 538 | ||
382 | return rc; | 539 | return rc; |
383 | } | ||
384 | 540 | ||
541 | out_unlock2: | ||
542 | up(&ses->server->tcpSem); | ||
543 | /* If not lock req, update # of requests on wire to server */ | ||
544 | if(long_op < 3) { | ||
545 | atomic_dec(&ses->server->inFlight); | ||
546 | wake_up(&ses->server->request_q); | ||
547 | } | ||
385 | 548 | ||
549 | return rc; | ||
550 | } | ||
386 | #endif /* CIFS_EXPERIMENTAL */ | 551 | #endif /* CIFS_EXPERIMENTAL */ |
387 | 552 | ||
388 | int | 553 | int |
@@ -419,9 +584,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
419 | if(atomic_read(&ses->server->inFlight) >= | 584 | if(atomic_read(&ses->server->inFlight) >= |
420 | cifs_max_pending){ | 585 | cifs_max_pending){ |
421 | spin_unlock(&GlobalMid_Lock); | 586 | spin_unlock(&GlobalMid_Lock); |
587 | #ifdef CONFIG_CIFS_STATS2 | ||
588 | atomic_inc(&ses->server->num_waiters); | ||
589 | #endif | ||
422 | wait_event(ses->server->request_q, | 590 | wait_event(ses->server->request_q, |
423 | atomic_read(&ses->server->inFlight) | 591 | atomic_read(&ses->server->inFlight) |
424 | < cifs_max_pending); | 592 | < cifs_max_pending); |
593 | #ifdef CONFIG_CIFS_STATS2 | ||
594 | atomic_dec(&ses->server->num_waiters); | ||
595 | #endif | ||
425 | spin_lock(&GlobalMid_Lock); | 596 | spin_lock(&GlobalMid_Lock); |
426 | } else { | 597 | } else { |
427 | if(ses->server->tcpStatus == CifsExiting) { | 598 | if(ses->server->tcpStatus == CifsExiting) { |
@@ -490,8 +661,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
490 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 661 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
491 | 662 | ||
492 | midQ->midState = MID_REQUEST_SUBMITTED; | 663 | midQ->midState = MID_REQUEST_SUBMITTED; |
664 | #ifdef CONFIG_CIFS_STATS2 | ||
665 | atomic_inc(&ses->server->inSend); | ||
666 | #endif | ||
493 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 667 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
494 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 668 | (struct sockaddr *) &(ses->server->addr.sockAddr)); |
669 | #ifdef CONFIG_CIFS_STATS2 | ||
670 | atomic_dec(&ses->server->inSend); | ||
671 | midQ->when_sent = jiffies; | ||
672 | #endif | ||
495 | if(rc < 0) { | 673 | if(rc < 0) { |
496 | DeleteMidQEntry(midQ); | 674 | DeleteMidQEntry(midQ); |
497 | up(&ses->server->tcpSem); | 675 | up(&ses->server->tcpSem); |
@@ -506,7 +684,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
506 | if (long_op == -1) | 684 | if (long_op == -1) |
507 | goto cifs_no_response_exit; | 685 | goto cifs_no_response_exit; |
508 | else if (long_op == 2) /* writes past end of file can take loong time */ | 686 | else if (long_op == 2) /* writes past end of file can take loong time */ |
509 | timeout = 300 * HZ; | 687 | timeout = 180 * HZ; |
510 | else if (long_op == 1) | 688 | else if (long_op == 1) |
511 | timeout = 45 * HZ; /* should be greater than | 689 | timeout = 45 * HZ; /* should be greater than |
512 | servers oplock break timeout (about 43 seconds) */ | 690 | servers oplock break timeout (about 43 seconds) */ |
@@ -540,9 +718,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
540 | spin_lock(&GlobalMid_Lock); | 718 | spin_lock(&GlobalMid_Lock); |
541 | if (midQ->resp_buf) { | 719 | if (midQ->resp_buf) { |
542 | spin_unlock(&GlobalMid_Lock); | 720 | spin_unlock(&GlobalMid_Lock); |
543 | receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); | 721 | receive_len = midQ->resp_buf->smb_buf_length; |
544 | } else { | 722 | } else { |
545 | cERROR(1,("No response buffer")); | 723 | cERROR(1,("No response for cmd %d mid %d", |
724 | midQ->command, midQ->mid)); | ||
546 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | 725 | if(midQ->midState == MID_REQUEST_SUBMITTED) { |
547 | if(ses->server->tcpStatus == CifsExiting) | 726 | if(ses->server->tcpStatus == CifsExiting) |
548 | rc = -EHOSTDOWN; | 727 | rc = -EHOSTDOWN; |
@@ -610,7 +789,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
610 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); | 789 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); |
611 | } else { | 790 | } else { |
612 | rc = -EIO; | 791 | rc = -EIO; |
613 | cFYI(1,("Bad MID state? ")); | 792 | cERROR(1,("Bad MID state? ")); |
614 | } | 793 | } |
615 | } | 794 | } |
616 | cifs_no_response_exit: | 795 | cifs_no_response_exit: |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index ffab4783ac64..c27f8d4098be 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -247,7 +247,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
247 | wait_queue_head_t *wqh; | 247 | wait_queue_head_t *wqh; |
248 | 248 | ||
249 | if (!atomic_read(&inode->i_count)) | 249 | if (!atomic_read(&inode->i_count)) |
250 | WARN_ON(!(inode->i_state & I_WILL_FREE)); | 250 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); |
251 | else | 251 | else |
252 | WARN_ON(inode->i_state & I_WILL_FREE); | 252 | WARN_ON(inode->i_state & I_WILL_FREE); |
253 | 253 | ||
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index de58579a1d0e..50a7749cfca1 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog | |||
@@ -1,18 +1,15 @@ | |||
1 | ToDo/Notes: | 1 | ToDo/Notes: |
2 | - Find and fix bugs. | 2 | - Find and fix bugs. |
3 | - In between ntfs_prepare/commit_write, need exclusion between | 3 | - The only places in the kernel where a file is resized are |
4 | simultaneous file extensions. This is given to us by holding i_sem | 4 | ntfs_file_write*() and ntfs_truncate() for both of which i_sem is |
5 | on the inode. The only places in the kernel when a file is resized | 5 | held. Just have to be careful in read-/writepage and other helpers |
6 | are prepare/commit write and truncate for both of which i_sem is | 6 | not running under i_sem that we play nice... Also need to be careful |
7 | held. Just have to be careful in readpage/writepage and all other | 7 | with initialized_size extension in ntfs_file_write*() and writepage. |
8 | helpers not running under i_sem that we play nice... | 8 | UPDATE: The only things that need to be checked are the compressed |
9 | Also need to be careful with initialized_size extention in | 9 | write and the other attribute resize/write cases like index |
10 | ntfs_prepare_write. Basically, just be _very_ careful in this code... | 10 | attributes, etc. For now none of these are implemented so are safe. |
11 | UPDATE: The only things that need to be checked are read/writepage | 11 | - Implement filling in of holes in aops.c::ntfs_writepage() and its |
12 | which do not hold i_sem. Note writepage cannot change i_size but it | 12 | helpers. |
13 | needs to cope with a concurrent i_size change, just like readpage. | ||
14 | Also both need to cope with concurrent changes to the other sizes, | ||
15 | i.e. initialized/allocated/compressed size, as well. | ||
16 | - Implement mft.c::sync_mft_mirror_umount(). We currently will just | 13 | - Implement mft.c::sync_mft_mirror_umount(). We currently will just |
17 | leave the volume dirty on umount if the final iput(vol->mft_ino) | 14 | leave the volume dirty on umount if the final iput(vol->mft_ino) |
18 | causes a write of any mirrored mft records due to the mft mirror | 15 | causes a write of any mirrored mft records due to the mft mirror |
@@ -22,6 +19,68 @@ ToDo/Notes: | |||
22 | - Enable the code for setting the NT4 compatibility flag when we start | 19 | - Enable the code for setting the NT4 compatibility flag when we start |
23 | making NTFS 1.2 specific modifications. | 20 | making NTFS 1.2 specific modifications. |
24 | 21 | ||
22 | 2.1.25 - (Almost) fully implement write(2) and truncate(2). | ||
23 | |||
24 | - Change ntfs_map_runlist_nolock(), ntfs_attr_find_vcn_nolock() and | ||
25 | {__,}ntfs_cluster_free() to also take an optional attribute search | ||
26 | context as argument. This allows calling these functions with the | ||
27 | mft record mapped. Update all callers. | ||
28 | - Fix potential deadlock in ntfs_mft_data_extend_allocation_nolock() | ||
29 | error handling by passing in the active search context when calling | ||
30 | ntfs_cluster_free(). | ||
31 | - Change ntfs_cluster_alloc() to take an extra boolean parameter | ||
32 | specifying whether the cluster are being allocated to extend an | ||
33 | attribute or to fill a hole. | ||
34 | - Change ntfs_attr_make_non_resident() to call ntfs_cluster_alloc() | ||
35 | with @is_extension set to TRUE and remove the runlist terminator | ||
36 | fixup code as this is now done by ntfs_cluster_alloc(). | ||
37 | - Change ntfs_attr_make_non_resident to take the attribute value size | ||
38 | as an extra parameter. This is needed since we need to know the size | ||
39 | before we can map the mft record and our callers always know it. The | ||
40 | reason we cannot simply read the size from the vfs inode i_size is | ||
41 | that this is not necessarily uptodate. This happens when | ||
42 | ntfs_attr_make_non_resident() is called in the ->truncate call path. | ||
43 | - Fix ntfs_attr_make_non_resident() to update the vfs inode i_blocks | ||
44 | which is zero for a resident attribute but should no longer be zero | ||
45 | once the attribute is non-resident as it then has real clusters | ||
46 | allocated. | ||
47 | - Add fs/ntfs/attrib.[hc]::ntfs_attr_extend_allocation(), a function to | ||
48 | extend the allocation of an attributes. Optionally, the data size, | ||
49 | but not the initialized size can be extended, too. | ||
50 | - Implement fs/ntfs/inode.[hc]::ntfs_truncate(). It only supports | ||
51 | uncompressed and unencrypted files and it never creates sparse files | ||
52 | at least for the moment (making a file sparse requires us to modify | ||
53 | its directory entries and we do not support directory operations at | ||
54 | the moment). Also, support for highly fragmented files, i.e. ones | ||
55 | whose data attribute is split across multiple extents, is severly | ||
56 | limited. When such a case is encountered, EOPNOTSUPP is returned. | ||
57 | - Enable ATTR_SIZE attribute changes in ntfs_setattr(). This completes | ||
58 | the initial implementation of file truncation. Now both open(2)ing | ||
59 | a file with the O_TRUNC flag and the {,f}truncate(2) system calls | ||
60 | will resize a file appropriately. The limitations are that only | ||
61 | uncompressed and unencrypted files are supported. Also, there is | ||
62 | only very limited support for highly fragmented files (the ones whose | ||
63 | $DATA attribute is split into multiple attribute extents). | ||
64 | - In attrib.c::ntfs_attr_set() call balance_dirty_pages_ratelimited() | ||
65 | and cond_resched() in the main loop as we could be dirtying a lot of | ||
66 | pages and this ensures we play nice with the VM and the system as a | ||
67 | whole. | ||
68 | - Implement file operations ->write, ->aio_write, ->writev for regular | ||
69 | files. This replaces the old use of generic_file_write(), et al and | ||
70 | the address space operations ->prepare_write and ->commit_write. | ||
71 | This means that both sparse and non-sparse (unencrypted and | ||
72 | uncompressed) files can now be extended using the normal write(2) | ||
73 | code path. There are two limitations at present and these are that | ||
74 | we never create sparse files and that we only have limited support | ||
75 | for highly fragmented files, i.e. ones whose data attribute is split | ||
76 | across multiple extents. When such a case is encountered, | ||
77 | EOPNOTSUPP is returned. | ||
78 | - $EA attributes can be both resident and non-resident. | ||
79 | - Use %z for size_t to fix compilation warnings. (Andrew Morton) | ||
80 | - Fix compilation warnings with gcc-4.0.2 on SUSE 10.0. | ||
81 | - Document extended attribute ($EA) NEED_EA flag. (Based on libntfs | ||
82 | patch by Yura Pakhuchiy.) | ||
83 | |||
25 | 2.1.24 - Lots of bug fixes and support more clean journal states. | 84 | 2.1.24 - Lots of bug fixes and support more clean journal states. |
26 | 85 | ||
27 | - Support journals ($LogFile) which have been modified by chkdsk. This | 86 | - Support journals ($LogFile) which have been modified by chkdsk. This |
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index 894b2b876d35..d0d45d1c853a 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile | |||
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ | |||
6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ | 6 | index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ |
7 | unistr.o upcase.o | 7 | unistr.o upcase.o |
8 | 8 | ||
9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.24\" | 9 | EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25\" |
10 | 10 | ||
11 | ifeq ($(CONFIG_NTFS_DEBUG),y) | 11 | ifeq ($(CONFIG_NTFS_DEBUG),y) |
12 | EXTRA_CFLAGS += -DDEBUG | 12 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 5e80c07c6a4d..1c0a4315876a 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
@@ -1391,8 +1391,7 @@ retry_writepage: | |||
1391 | if (NInoEncrypted(ni)) { | 1391 | if (NInoEncrypted(ni)) { |
1392 | unlock_page(page); | 1392 | unlock_page(page); |
1393 | BUG_ON(ni->type != AT_DATA); | 1393 | BUG_ON(ni->type != AT_DATA); |
1394 | ntfs_debug("Denying write access to encrypted " | 1394 | ntfs_debug("Denying write access to encrypted file."); |
1395 | "file."); | ||
1396 | return -EACCES; | 1395 | return -EACCES; |
1397 | } | 1396 | } |
1398 | /* Compressed data streams are handled in compress.c. */ | 1397 | /* Compressed data streams are handled in compress.c. */ |
@@ -1508,8 +1507,8 @@ retry_writepage: | |||
1508 | /* Zero out of bounds area in the page cache page. */ | 1507 | /* Zero out of bounds area in the page cache page. */ |
1509 | memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); | 1508 | memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); |
1510 | kunmap_atomic(kaddr, KM_USER0); | 1509 | kunmap_atomic(kaddr, KM_USER0); |
1511 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1512 | flush_dcache_page(page); | 1510 | flush_dcache_page(page); |
1511 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1513 | /* We are done with the page. */ | 1512 | /* We are done with the page. */ |
1514 | end_page_writeback(page); | 1513 | end_page_writeback(page); |
1515 | /* Finally, mark the mft record dirty, so it gets written back. */ | 1514 | /* Finally, mark the mft record dirty, so it gets written back. */ |
@@ -1542,830 +1541,6 @@ err_out: | |||
1542 | return err; | 1541 | return err; |
1543 | } | 1542 | } |
1544 | 1543 | ||
1545 | /** | ||
1546 | * ntfs_prepare_nonresident_write - | ||
1547 | * | ||
1548 | */ | ||
1549 | static int ntfs_prepare_nonresident_write(struct page *page, | ||
1550 | unsigned from, unsigned to) | ||
1551 | { | ||
1552 | VCN vcn; | ||
1553 | LCN lcn; | ||
1554 | s64 initialized_size; | ||
1555 | loff_t i_size; | ||
1556 | sector_t block, ablock, iblock; | ||
1557 | struct inode *vi; | ||
1558 | ntfs_inode *ni; | ||
1559 | ntfs_volume *vol; | ||
1560 | runlist_element *rl; | ||
1561 | struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; | ||
1562 | unsigned long flags; | ||
1563 | unsigned int vcn_ofs, block_start, block_end, blocksize; | ||
1564 | int err; | ||
1565 | BOOL is_retry; | ||
1566 | unsigned char blocksize_bits; | ||
1567 | |||
1568 | vi = page->mapping->host; | ||
1569 | ni = NTFS_I(vi); | ||
1570 | vol = ni->vol; | ||
1571 | |||
1572 | ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " | ||
1573 | "0x%lx, from = %u, to = %u.", ni->mft_no, ni->type, | ||
1574 | page->index, from, to); | ||
1575 | |||
1576 | BUG_ON(!NInoNonResident(ni)); | ||
1577 | |||
1578 | blocksize_bits = vi->i_blkbits; | ||
1579 | blocksize = 1 << blocksize_bits; | ||
1580 | |||
1581 | /* | ||
1582 | * create_empty_buffers() will create uptodate/dirty buffers if the | ||
1583 | * page is uptodate/dirty. | ||
1584 | */ | ||
1585 | if (!page_has_buffers(page)) | ||
1586 | create_empty_buffers(page, blocksize, 0); | ||
1587 | bh = head = page_buffers(page); | ||
1588 | if (unlikely(!bh)) | ||
1589 | return -ENOMEM; | ||
1590 | |||
1591 | /* The first block in the page. */ | ||
1592 | block = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); | ||
1593 | |||
1594 | read_lock_irqsave(&ni->size_lock, flags); | ||
1595 | /* | ||
1596 | * The first out of bounds block for the allocated size. No need to | ||
1597 | * round up as allocated_size is in multiples of cluster size and the | ||
1598 | * minimum cluster size is 512 bytes, which is equal to the smallest | ||
1599 | * blocksize. | ||
1600 | */ | ||
1601 | ablock = ni->allocated_size >> blocksize_bits; | ||
1602 | i_size = i_size_read(vi); | ||
1603 | initialized_size = ni->initialized_size; | ||
1604 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1605 | |||
1606 | /* The last (fully or partially) initialized block. */ | ||
1607 | iblock = initialized_size >> blocksize_bits; | ||
1608 | |||
1609 | /* Loop through all the buffers in the page. */ | ||
1610 | block_start = 0; | ||
1611 | rl = NULL; | ||
1612 | err = 0; | ||
1613 | do { | ||
1614 | block_end = block_start + blocksize; | ||
1615 | /* | ||
1616 | * If buffer @bh is outside the write, just mark it uptodate | ||
1617 | * if the page is uptodate and continue with the next buffer. | ||
1618 | */ | ||
1619 | if (block_end <= from || block_start >= to) { | ||
1620 | if (PageUptodate(page)) { | ||
1621 | if (!buffer_uptodate(bh)) | ||
1622 | set_buffer_uptodate(bh); | ||
1623 | } | ||
1624 | continue; | ||
1625 | } | ||
1626 | /* | ||
1627 | * @bh is at least partially being written to. | ||
1628 | * Make sure it is not marked as new. | ||
1629 | */ | ||
1630 | //if (buffer_new(bh)) | ||
1631 | // clear_buffer_new(bh); | ||
1632 | |||
1633 | if (block >= ablock) { | ||
1634 | // TODO: block is above allocated_size, need to | ||
1635 | // allocate it. Best done in one go to accommodate not | ||
1636 | // only block but all above blocks up to and including: | ||
1637 | // ((page->index << PAGE_CACHE_SHIFT) + to + blocksize | ||
1638 | // - 1) >> blobksize_bits. Obviously will need to round | ||
1639 | // up to next cluster boundary, too. This should be | ||
1640 | // done with a helper function, so it can be reused. | ||
1641 | ntfs_error(vol->sb, "Writing beyond allocated size " | ||
1642 | "is not supported yet. Sorry."); | ||
1643 | err = -EOPNOTSUPP; | ||
1644 | goto err_out; | ||
1645 | // Need to update ablock. | ||
1646 | // Need to set_buffer_new() on all block bhs that are | ||
1647 | // newly allocated. | ||
1648 | } | ||
1649 | /* | ||
1650 | * Now we have enough allocated size to fulfill the whole | ||
1651 | * request, i.e. block < ablock is true. | ||
1652 | */ | ||
1653 | if (unlikely((block >= iblock) && | ||
1654 | (initialized_size < i_size))) { | ||
1655 | /* | ||
1656 | * If this page is fully outside initialized size, zero | ||
1657 | * out all pages between the current initialized size | ||
1658 | * and the current page. Just use ntfs_readpage() to do | ||
1659 | * the zeroing transparently. | ||
1660 | */ | ||
1661 | if (block > iblock) { | ||
1662 | // TODO: | ||
1663 | // For each page do: | ||
1664 | // - read_cache_page() | ||
1665 | // Again for each page do: | ||
1666 | // - wait_on_page_locked() | ||
1667 | // - Check (PageUptodate(page) && | ||
1668 | // !PageError(page)) | ||
1669 | // Update initialized size in the attribute and | ||
1670 | // in the inode. | ||
1671 | // Again, for each page do: | ||
1672 | // __set_page_dirty_buffers(); | ||
1673 | // page_cache_release() | ||
1674 | // We don't need to wait on the writes. | ||
1675 | // Update iblock. | ||
1676 | } | ||
1677 | /* | ||
1678 | * The current page straddles initialized size. Zero | ||
1679 | * all non-uptodate buffers and set them uptodate (and | ||
1680 | * dirty?). Note, there aren't any non-uptodate buffers | ||
1681 | * if the page is uptodate. | ||
1682 | * FIXME: For an uptodate page, the buffers may need to | ||
1683 | * be written out because they were not initialized on | ||
1684 | * disk before. | ||
1685 | */ | ||
1686 | if (!PageUptodate(page)) { | ||
1687 | // TODO: | ||
1688 | // Zero any non-uptodate buffers up to i_size. | ||
1689 | // Set them uptodate and dirty. | ||
1690 | } | ||
1691 | // TODO: | ||
1692 | // Update initialized size in the attribute and in the | ||
1693 | // inode (up to i_size). | ||
1694 | // Update iblock. | ||
1695 | // FIXME: This is inefficient. Try to batch the two | ||
1696 | // size changes to happen in one go. | ||
1697 | ntfs_error(vol->sb, "Writing beyond initialized size " | ||
1698 | "is not supported yet. Sorry."); | ||
1699 | err = -EOPNOTSUPP; | ||
1700 | goto err_out; | ||
1701 | // Do NOT set_buffer_new() BUT DO clear buffer range | ||
1702 | // outside write request range. | ||
1703 | // set_buffer_uptodate() on complete buffers as well as | ||
1704 | // set_buffer_dirty(). | ||
1705 | } | ||
1706 | |||
1707 | /* Need to map unmapped buffers. */ | ||
1708 | if (!buffer_mapped(bh)) { | ||
1709 | /* Unmapped buffer. Need to map it. */ | ||
1710 | bh->b_bdev = vol->sb->s_bdev; | ||
1711 | |||
1712 | /* Convert block into corresponding vcn and offset. */ | ||
1713 | vcn = (VCN)block << blocksize_bits >> | ||
1714 | vol->cluster_size_bits; | ||
1715 | vcn_ofs = ((VCN)block << blocksize_bits) & | ||
1716 | vol->cluster_size_mask; | ||
1717 | |||
1718 | is_retry = FALSE; | ||
1719 | if (!rl) { | ||
1720 | lock_retry_remap: | ||
1721 | down_read(&ni->runlist.lock); | ||
1722 | rl = ni->runlist.rl; | ||
1723 | } | ||
1724 | if (likely(rl != NULL)) { | ||
1725 | /* Seek to element containing target vcn. */ | ||
1726 | while (rl->length && rl[1].vcn <= vcn) | ||
1727 | rl++; | ||
1728 | lcn = ntfs_rl_vcn_to_lcn(rl, vcn); | ||
1729 | } else | ||
1730 | lcn = LCN_RL_NOT_MAPPED; | ||
1731 | if (unlikely(lcn < 0)) { | ||
1732 | /* | ||
1733 | * We extended the attribute allocation above. | ||
1734 | * If we hit an ENOENT here it means that the | ||
1735 | * allocation was insufficient which is a bug. | ||
1736 | */ | ||
1737 | BUG_ON(lcn == LCN_ENOENT); | ||
1738 | |||
1739 | /* It is a hole, need to instantiate it. */ | ||
1740 | if (lcn == LCN_HOLE) { | ||
1741 | // TODO: Instantiate the hole. | ||
1742 | // clear_buffer_new(bh); | ||
1743 | // unmap_underlying_metadata(bh->b_bdev, | ||
1744 | // bh->b_blocknr); | ||
1745 | // For non-uptodate buffers, need to | ||
1746 | // zero out the region outside the | ||
1747 | // request in this bh or all bhs, | ||
1748 | // depending on what we implemented | ||
1749 | // above. | ||
1750 | // Need to flush_dcache_page(). | ||
1751 | // Or could use set_buffer_new() | ||
1752 | // instead? | ||
1753 | ntfs_error(vol->sb, "Writing into " | ||
1754 | "sparse regions is " | ||
1755 | "not supported yet. " | ||
1756 | "Sorry."); | ||
1757 | err = -EOPNOTSUPP; | ||
1758 | if (!rl) | ||
1759 | up_read(&ni->runlist.lock); | ||
1760 | goto err_out; | ||
1761 | } else if (!is_retry && | ||
1762 | lcn == LCN_RL_NOT_MAPPED) { | ||
1763 | is_retry = TRUE; | ||
1764 | /* | ||
1765 | * Attempt to map runlist, dropping | ||
1766 | * lock for the duration. | ||
1767 | */ | ||
1768 | up_read(&ni->runlist.lock); | ||
1769 | err = ntfs_map_runlist(ni, vcn); | ||
1770 | if (likely(!err)) | ||
1771 | goto lock_retry_remap; | ||
1772 | rl = NULL; | ||
1773 | } else if (!rl) | ||
1774 | up_read(&ni->runlist.lock); | ||
1775 | /* | ||
1776 | * Failed to map the buffer, even after | ||
1777 | * retrying. | ||
1778 | */ | ||
1779 | if (!err) | ||
1780 | err = -EIO; | ||
1781 | bh->b_blocknr = -1; | ||
1782 | ntfs_error(vol->sb, "Failed to write to inode " | ||
1783 | "0x%lx, attribute type 0x%x, " | ||
1784 | "vcn 0x%llx, offset 0x%x " | ||
1785 | "because its location on disk " | ||
1786 | "could not be determined%s " | ||
1787 | "(error code %i).", | ||
1788 | ni->mft_no, ni->type, | ||
1789 | (unsigned long long)vcn, | ||
1790 | vcn_ofs, is_retry ? " even " | ||
1791 | "after retrying" : "", err); | ||
1792 | goto err_out; | ||
1793 | } | ||
1794 | /* We now have a successful remap, i.e. lcn >= 0. */ | ||
1795 | |||
1796 | /* Setup buffer head to correct block. */ | ||
1797 | bh->b_blocknr = ((lcn << vol->cluster_size_bits) | ||
1798 | + vcn_ofs) >> blocksize_bits; | ||
1799 | set_buffer_mapped(bh); | ||
1800 | |||
1801 | // FIXME: Something analogous to this is needed for | ||
1802 | // each newly allocated block, i.e. BH_New. | ||
1803 | // FIXME: Might need to take this out of the | ||
1804 | // if (!buffer_mapped(bh)) {}, depending on how we | ||
1805 | // implement things during the allocated_size and | ||
1806 | // initialized_size extension code above. | ||
1807 | if (buffer_new(bh)) { | ||
1808 | clear_buffer_new(bh); | ||
1809 | unmap_underlying_metadata(bh->b_bdev, | ||
1810 | bh->b_blocknr); | ||
1811 | if (PageUptodate(page)) { | ||
1812 | set_buffer_uptodate(bh); | ||
1813 | continue; | ||
1814 | } | ||
1815 | /* | ||
1816 | * Page is _not_ uptodate, zero surrounding | ||
1817 | * region. NOTE: This is how we decide if to | ||
1818 | * zero or not! | ||
1819 | */ | ||
1820 | if (block_end > to || block_start < from) { | ||
1821 | void *kaddr; | ||
1822 | |||
1823 | kaddr = kmap_atomic(page, KM_USER0); | ||
1824 | if (block_end > to) | ||
1825 | memset(kaddr + to, 0, | ||
1826 | block_end - to); | ||
1827 | if (block_start < from) | ||
1828 | memset(kaddr + block_start, 0, | ||
1829 | from - | ||
1830 | block_start); | ||
1831 | flush_dcache_page(page); | ||
1832 | kunmap_atomic(kaddr, KM_USER0); | ||
1833 | } | ||
1834 | continue; | ||
1835 | } | ||
1836 | } | ||
1837 | /* @bh is mapped, set it uptodate if the page is uptodate. */ | ||
1838 | if (PageUptodate(page)) { | ||
1839 | if (!buffer_uptodate(bh)) | ||
1840 | set_buffer_uptodate(bh); | ||
1841 | continue; | ||
1842 | } | ||
1843 | /* | ||
1844 | * The page is not uptodate. The buffer is mapped. If it is not | ||
1845 | * uptodate, and it is only partially being written to, we need | ||
1846 | * to read the buffer in before the write, i.e. right now. | ||
1847 | */ | ||
1848 | if (!buffer_uptodate(bh) && | ||
1849 | (block_start < from || block_end > to)) { | ||
1850 | ll_rw_block(READ, 1, &bh); | ||
1851 | *wait_bh++ = bh; | ||
1852 | } | ||
1853 | } while (block++, block_start = block_end, | ||
1854 | (bh = bh->b_this_page) != head); | ||
1855 | |||
1856 | /* Release the lock if we took it. */ | ||
1857 | if (rl) { | ||
1858 | up_read(&ni->runlist.lock); | ||
1859 | rl = NULL; | ||
1860 | } | ||
1861 | |||
1862 | /* If we issued read requests, let them complete. */ | ||
1863 | while (wait_bh > wait) { | ||
1864 | wait_on_buffer(*--wait_bh); | ||
1865 | if (!buffer_uptodate(*wait_bh)) | ||
1866 | return -EIO; | ||
1867 | } | ||
1868 | |||
1869 | ntfs_debug("Done."); | ||
1870 | return 0; | ||
1871 | err_out: | ||
1872 | /* | ||
1873 | * Zero out any newly allocated blocks to avoid exposing stale data. | ||
1874 | * If BH_New is set, we know that the block was newly allocated in the | ||
1875 | * above loop. | ||
1876 | * FIXME: What about initialized_size increments? Have we done all the | ||
1877 | * required zeroing above? If not this error handling is broken, and | ||
1878 | * in particular the if (block_end <= from) check is completely bogus. | ||
1879 | */ | ||
1880 | bh = head; | ||
1881 | block_start = 0; | ||
1882 | is_retry = FALSE; | ||
1883 | do { | ||
1884 | block_end = block_start + blocksize; | ||
1885 | if (block_end <= from) | ||
1886 | continue; | ||
1887 | if (block_start >= to) | ||
1888 | break; | ||
1889 | if (buffer_new(bh)) { | ||
1890 | void *kaddr; | ||
1891 | |||
1892 | clear_buffer_new(bh); | ||
1893 | kaddr = kmap_atomic(page, KM_USER0); | ||
1894 | memset(kaddr + block_start, 0, bh->b_size); | ||
1895 | kunmap_atomic(kaddr, KM_USER0); | ||
1896 | set_buffer_uptodate(bh); | ||
1897 | mark_buffer_dirty(bh); | ||
1898 | is_retry = TRUE; | ||
1899 | } | ||
1900 | } while (block_start = block_end, (bh = bh->b_this_page) != head); | ||
1901 | if (is_retry) | ||
1902 | flush_dcache_page(page); | ||
1903 | if (rl) | ||
1904 | up_read(&ni->runlist.lock); | ||
1905 | return err; | ||
1906 | } | ||
1907 | |||
1908 | /** | ||
1909 | * ntfs_prepare_write - prepare a page for receiving data | ||
1910 | * | ||
1911 | * This is called from generic_file_write() with i_sem held on the inode | ||
1912 | * (@page->mapping->host). The @page is locked but not kmap()ped. The source | ||
1913 | * data has not yet been copied into the @page. | ||
1914 | * | ||
1915 | * Need to extend the attribute/fill in holes if necessary, create blocks and | ||
1916 | * make partially overwritten blocks uptodate, | ||
1917 | * | ||
1918 | * i_size is not to be modified yet. | ||
1919 | * | ||
1920 | * Return 0 on success or -errno on error. | ||
1921 | * | ||
1922 | * Should be using block_prepare_write() [support for sparse files] or | ||
1923 | * cont_prepare_write() [no support for sparse files]. Cannot do that due to | ||
1924 | * ntfs specifics but can look at them for implementation guidance. | ||
1925 | * | ||
1926 | * Note: In the range, @from is inclusive and @to is exclusive, i.e. @from is | ||
1927 | * the first byte in the page that will be written to and @to is the first byte | ||
1928 | * after the last byte that will be written to. | ||
1929 | */ | ||
1930 | static int ntfs_prepare_write(struct file *file, struct page *page, | ||
1931 | unsigned from, unsigned to) | ||
1932 | { | ||
1933 | s64 new_size; | ||
1934 | loff_t i_size; | ||
1935 | struct inode *vi = page->mapping->host; | ||
1936 | ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi); | ||
1937 | ntfs_volume *vol = ni->vol; | ||
1938 | ntfs_attr_search_ctx *ctx = NULL; | ||
1939 | MFT_RECORD *m = NULL; | ||
1940 | ATTR_RECORD *a; | ||
1941 | u8 *kaddr; | ||
1942 | u32 attr_len; | ||
1943 | int err; | ||
1944 | |||
1945 | ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " | ||
1946 | "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, | ||
1947 | page->index, from, to); | ||
1948 | BUG_ON(!PageLocked(page)); | ||
1949 | BUG_ON(from > PAGE_CACHE_SIZE); | ||
1950 | BUG_ON(to > PAGE_CACHE_SIZE); | ||
1951 | BUG_ON(from > to); | ||
1952 | BUG_ON(NInoMstProtected(ni)); | ||
1953 | /* | ||
1954 | * If a previous ntfs_truncate() failed, repeat it and abort if it | ||
1955 | * fails again. | ||
1956 | */ | ||
1957 | if (unlikely(NInoTruncateFailed(ni))) { | ||
1958 | down_write(&vi->i_alloc_sem); | ||
1959 | err = ntfs_truncate(vi); | ||
1960 | up_write(&vi->i_alloc_sem); | ||
1961 | if (err || NInoTruncateFailed(ni)) { | ||
1962 | if (!err) | ||
1963 | err = -EIO; | ||
1964 | goto err_out; | ||
1965 | } | ||
1966 | } | ||
1967 | /* If the attribute is not resident, deal with it elsewhere. */ | ||
1968 | if (NInoNonResident(ni)) { | ||
1969 | /* | ||
1970 | * Only unnamed $DATA attributes can be compressed, encrypted, | ||
1971 | * and/or sparse. | ||
1972 | */ | ||
1973 | if (ni->type == AT_DATA && !ni->name_len) { | ||
1974 | /* If file is encrypted, deny access, just like NT4. */ | ||
1975 | if (NInoEncrypted(ni)) { | ||
1976 | ntfs_debug("Denying write access to encrypted " | ||
1977 | "file."); | ||
1978 | return -EACCES; | ||
1979 | } | ||
1980 | /* Compressed data streams are handled in compress.c. */ | ||
1981 | if (NInoCompressed(ni)) { | ||
1982 | // TODO: Implement and replace this check with | ||
1983 | // return ntfs_write_compressed_block(page); | ||
1984 | ntfs_error(vi->i_sb, "Writing to compressed " | ||
1985 | "files is not supported yet. " | ||
1986 | "Sorry."); | ||
1987 | return -EOPNOTSUPP; | ||
1988 | } | ||
1989 | // TODO: Implement and remove this check. | ||
1990 | if (NInoSparse(ni)) { | ||
1991 | ntfs_error(vi->i_sb, "Writing to sparse files " | ||
1992 | "is not supported yet. Sorry."); | ||
1993 | return -EOPNOTSUPP; | ||
1994 | } | ||
1995 | } | ||
1996 | /* Normal data stream. */ | ||
1997 | return ntfs_prepare_nonresident_write(page, from, to); | ||
1998 | } | ||
1999 | /* | ||
2000 | * Attribute is resident, implying it is not compressed, encrypted, or | ||
2001 | * sparse. | ||
2002 | */ | ||
2003 | BUG_ON(page_has_buffers(page)); | ||
2004 | new_size = ((s64)page->index << PAGE_CACHE_SHIFT) + to; | ||
2005 | /* If we do not need to resize the attribute allocation we are done. */ | ||
2006 | if (new_size <= i_size_read(vi)) | ||
2007 | goto done; | ||
2008 | /* Map, pin, and lock the (base) mft record. */ | ||
2009 | if (!NInoAttr(ni)) | ||
2010 | base_ni = ni; | ||
2011 | else | ||
2012 | base_ni = ni->ext.base_ntfs_ino; | ||
2013 | m = map_mft_record(base_ni); | ||
2014 | if (IS_ERR(m)) { | ||
2015 | err = PTR_ERR(m); | ||
2016 | m = NULL; | ||
2017 | ctx = NULL; | ||
2018 | goto err_out; | ||
2019 | } | ||
2020 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
2021 | if (unlikely(!ctx)) { | ||
2022 | err = -ENOMEM; | ||
2023 | goto err_out; | ||
2024 | } | ||
2025 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
2026 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
2027 | if (unlikely(err)) { | ||
2028 | if (err == -ENOENT) | ||
2029 | err = -EIO; | ||
2030 | goto err_out; | ||
2031 | } | ||
2032 | m = ctx->mrec; | ||
2033 | a = ctx->attr; | ||
2034 | /* The total length of the attribute value. */ | ||
2035 | attr_len = le32_to_cpu(a->data.resident.value_length); | ||
2036 | /* Fix an eventual previous failure of ntfs_commit_write(). */ | ||
2037 | i_size = i_size_read(vi); | ||
2038 | if (unlikely(attr_len > i_size)) { | ||
2039 | attr_len = i_size; | ||
2040 | a->data.resident.value_length = cpu_to_le32(attr_len); | ||
2041 | } | ||
2042 | /* If we do not need to resize the attribute allocation we are done. */ | ||
2043 | if (new_size <= attr_len) | ||
2044 | goto done_unm; | ||
2045 | /* Check if new size is allowed in $AttrDef. */ | ||
2046 | err = ntfs_attr_size_bounds_check(vol, ni->type, new_size); | ||
2047 | if (unlikely(err)) { | ||
2048 | if (err == -ERANGE) { | ||
2049 | ntfs_error(vol->sb, "Write would cause the inode " | ||
2050 | "0x%lx to exceed the maximum size for " | ||
2051 | "its attribute type (0x%x). Aborting " | ||
2052 | "write.", vi->i_ino, | ||
2053 | le32_to_cpu(ni->type)); | ||
2054 | } else { | ||
2055 | ntfs_error(vol->sb, "Inode 0x%lx has unknown " | ||
2056 | "attribute type 0x%x. Aborting " | ||
2057 | "write.", vi->i_ino, | ||
2058 | le32_to_cpu(ni->type)); | ||
2059 | err = -EIO; | ||
2060 | } | ||
2061 | goto err_out2; | ||
2062 | } | ||
2063 | /* | ||
2064 | * Extend the attribute record to be able to store the new attribute | ||
2065 | * size. | ||
2066 | */ | ||
2067 | if (new_size >= vol->mft_record_size || ntfs_attr_record_resize(m, a, | ||
2068 | le16_to_cpu(a->data.resident.value_offset) + | ||
2069 | new_size)) { | ||
2070 | /* Not enough space in the mft record. */ | ||
2071 | ntfs_error(vol->sb, "Not enough space in the mft record for " | ||
2072 | "the resized attribute value. This is not " | ||
2073 | "supported yet. Aborting write."); | ||
2074 | err = -EOPNOTSUPP; | ||
2075 | goto err_out2; | ||
2076 | } | ||
2077 | /* | ||
2078 | * We have enough space in the mft record to fit the write. This | ||
2079 | * implies the attribute is smaller than the mft record and hence the | ||
2080 | * attribute must be in a single page and hence page->index must be 0. | ||
2081 | */ | ||
2082 | BUG_ON(page->index); | ||
2083 | /* | ||
2084 | * If the beginning of the write is past the old size, enlarge the | ||
2085 | * attribute value up to the beginning of the write and fill it with | ||
2086 | * zeroes. | ||
2087 | */ | ||
2088 | if (from > attr_len) { | ||
2089 | memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) + | ||
2090 | attr_len, 0, from - attr_len); | ||
2091 | a->data.resident.value_length = cpu_to_le32(from); | ||
2092 | /* Zero the corresponding area in the page as well. */ | ||
2093 | if (PageUptodate(page)) { | ||
2094 | kaddr = kmap_atomic(page, KM_USER0); | ||
2095 | memset(kaddr + attr_len, 0, from - attr_len); | ||
2096 | kunmap_atomic(kaddr, KM_USER0); | ||
2097 | flush_dcache_page(page); | ||
2098 | } | ||
2099 | } | ||
2100 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2101 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2102 | done_unm: | ||
2103 | ntfs_attr_put_search_ctx(ctx); | ||
2104 | unmap_mft_record(base_ni); | ||
2105 | /* | ||
2106 | * Because resident attributes are handled by memcpy() to/from the | ||
2107 | * corresponding MFT record, and because this form of i/o is byte | ||
2108 | * aligned rather than block aligned, there is no need to bring the | ||
2109 | * page uptodate here as in the non-resident case where we need to | ||
2110 | * bring the buffers straddled by the write uptodate before | ||
2111 | * generic_file_write() does the copying from userspace. | ||
2112 | * | ||
2113 | * We thus defer the uptodate bringing of the page region outside the | ||
2114 | * region written to to ntfs_commit_write(), which makes the code | ||
2115 | * simpler and saves one atomic kmap which is good. | ||
2116 | */ | ||
2117 | done: | ||
2118 | ntfs_debug("Done."); | ||
2119 | return 0; | ||
2120 | err_out: | ||
2121 | if (err == -ENOMEM) | ||
2122 | ntfs_warning(vi->i_sb, "Error allocating memory required to " | ||
2123 | "prepare the write."); | ||
2124 | else { | ||
2125 | ntfs_error(vi->i_sb, "Resident attribute prepare write failed " | ||
2126 | "with error %i.", err); | ||
2127 | NVolSetErrors(vol); | ||
2128 | make_bad_inode(vi); | ||
2129 | } | ||
2130 | err_out2: | ||
2131 | if (ctx) | ||
2132 | ntfs_attr_put_search_ctx(ctx); | ||
2133 | if (m) | ||
2134 | unmap_mft_record(base_ni); | ||
2135 | return err; | ||
2136 | } | ||
2137 | |||
2138 | /** | ||
2139 | * ntfs_commit_nonresident_write - | ||
2140 | * | ||
2141 | */ | ||
2142 | static int ntfs_commit_nonresident_write(struct page *page, | ||
2143 | unsigned from, unsigned to) | ||
2144 | { | ||
2145 | s64 pos = ((s64)page->index << PAGE_CACHE_SHIFT) + to; | ||
2146 | struct inode *vi = page->mapping->host; | ||
2147 | struct buffer_head *bh, *head; | ||
2148 | unsigned int block_start, block_end, blocksize; | ||
2149 | BOOL partial; | ||
2150 | |||
2151 | ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " | ||
2152 | "0x%lx, from = %u, to = %u.", vi->i_ino, | ||
2153 | NTFS_I(vi)->type, page->index, from, to); | ||
2154 | blocksize = 1 << vi->i_blkbits; | ||
2155 | |||
2156 | // FIXME: We need a whole slew of special cases in here for compressed | ||
2157 | // files for example... | ||
2158 | // For now, we know ntfs_prepare_write() would have failed so we can't | ||
2159 | // get here in any of the cases which we have to special case, so we | ||
2160 | // are just a ripped off, unrolled generic_commit_write(). | ||
2161 | |||
2162 | bh = head = page_buffers(page); | ||
2163 | block_start = 0; | ||
2164 | partial = FALSE; | ||
2165 | do { | ||
2166 | block_end = block_start + blocksize; | ||
2167 | if (block_end <= from || block_start >= to) { | ||
2168 | if (!buffer_uptodate(bh)) | ||
2169 | partial = TRUE; | ||
2170 | } else { | ||
2171 | set_buffer_uptodate(bh); | ||
2172 | mark_buffer_dirty(bh); | ||
2173 | } | ||
2174 | } while (block_start = block_end, (bh = bh->b_this_page) != head); | ||
2175 | /* | ||
2176 | * If this is a partial write which happened to make all buffers | ||
2177 | * uptodate then we can optimize away a bogus ->readpage() for the next | ||
2178 | * read(). Here we 'discover' whether the page went uptodate as a | ||
2179 | * result of this (potentially partial) write. | ||
2180 | */ | ||
2181 | if (!partial) | ||
2182 | SetPageUptodate(page); | ||
2183 | /* | ||
2184 | * Not convinced about this at all. See disparity comment above. For | ||
2185 | * now we know ntfs_prepare_write() would have failed in the write | ||
2186 | * exceeds i_size case, so this will never trigger which is fine. | ||
2187 | */ | ||
2188 | if (pos > i_size_read(vi)) { | ||
2189 | ntfs_error(vi->i_sb, "Writing beyond the existing file size is " | ||
2190 | "not supported yet. Sorry."); | ||
2191 | return -EOPNOTSUPP; | ||
2192 | // vi->i_size = pos; | ||
2193 | // mark_inode_dirty(vi); | ||
2194 | } | ||
2195 | ntfs_debug("Done."); | ||
2196 | return 0; | ||
2197 | } | ||
2198 | |||
2199 | /** | ||
2200 | * ntfs_commit_write - commit the received data | ||
2201 | * | ||
2202 | * This is called from generic_file_write() with i_sem held on the inode | ||
2203 | * (@page->mapping->host). The @page is locked but not kmap()ped. The source | ||
2204 | * data has already been copied into the @page. ntfs_prepare_write() has been | ||
2205 | * called before the data copied and it returned success so we can take the | ||
2206 | * results of various BUG checks and some error handling for granted. | ||
2207 | * | ||
2208 | * Need to mark modified blocks dirty so they get written out later when | ||
2209 | * ntfs_writepage() is invoked by the VM. | ||
2210 | * | ||
2211 | * Return 0 on success or -errno on error. | ||
2212 | * | ||
2213 | * Should be using generic_commit_write(). This marks buffers uptodate and | ||
2214 | * dirty, sets the page uptodate if all buffers in the page are uptodate, and | ||
2215 | * updates i_size if the end of io is beyond i_size. In that case, it also | ||
2216 | * marks the inode dirty. | ||
2217 | * | ||
2218 | * Cannot use generic_commit_write() due to ntfs specialities but can look at | ||
2219 | * it for implementation guidance. | ||
2220 | * | ||
2221 | * If things have gone as outlined in ntfs_prepare_write(), then we do not | ||
2222 | * need to do any page content modifications here at all, except in the write | ||
2223 | * to resident attribute case, where we need to do the uptodate bringing here | ||
2224 | * which we combine with the copying into the mft record which means we save | ||
2225 | * one atomic kmap. | ||
2226 | */ | ||
2227 | static int ntfs_commit_write(struct file *file, struct page *page, | ||
2228 | unsigned from, unsigned to) | ||
2229 | { | ||
2230 | struct inode *vi = page->mapping->host; | ||
2231 | ntfs_inode *base_ni, *ni = NTFS_I(vi); | ||
2232 | char *kaddr, *kattr; | ||
2233 | ntfs_attr_search_ctx *ctx; | ||
2234 | MFT_RECORD *m; | ||
2235 | ATTR_RECORD *a; | ||
2236 | u32 attr_len; | ||
2237 | int err; | ||
2238 | |||
2239 | ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index " | ||
2240 | "0x%lx, from = %u, to = %u.", vi->i_ino, ni->type, | ||
2241 | page->index, from, to); | ||
2242 | /* If the attribute is not resident, deal with it elsewhere. */ | ||
2243 | if (NInoNonResident(ni)) { | ||
2244 | /* Only unnamed $DATA attributes can be compressed/encrypted. */ | ||
2245 | if (ni->type == AT_DATA && !ni->name_len) { | ||
2246 | /* Encrypted files need separate handling. */ | ||
2247 | if (NInoEncrypted(ni)) { | ||
2248 | // We never get here at present! | ||
2249 | BUG(); | ||
2250 | } | ||
2251 | /* Compressed data streams are handled in compress.c. */ | ||
2252 | if (NInoCompressed(ni)) { | ||
2253 | // TODO: Implement this! | ||
2254 | // return ntfs_write_compressed_block(page); | ||
2255 | // We never get here at present! | ||
2256 | BUG(); | ||
2257 | } | ||
2258 | } | ||
2259 | /* Normal data stream. */ | ||
2260 | return ntfs_commit_nonresident_write(page, from, to); | ||
2261 | } | ||
2262 | /* | ||
2263 | * Attribute is resident, implying it is not compressed, encrypted, or | ||
2264 | * sparse. | ||
2265 | */ | ||
2266 | if (!NInoAttr(ni)) | ||
2267 | base_ni = ni; | ||
2268 | else | ||
2269 | base_ni = ni->ext.base_ntfs_ino; | ||
2270 | /* Map, pin, and lock the mft record. */ | ||
2271 | m = map_mft_record(base_ni); | ||
2272 | if (IS_ERR(m)) { | ||
2273 | err = PTR_ERR(m); | ||
2274 | m = NULL; | ||
2275 | ctx = NULL; | ||
2276 | goto err_out; | ||
2277 | } | ||
2278 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
2279 | if (unlikely(!ctx)) { | ||
2280 | err = -ENOMEM; | ||
2281 | goto err_out; | ||
2282 | } | ||
2283 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
2284 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
2285 | if (unlikely(err)) { | ||
2286 | if (err == -ENOENT) | ||
2287 | err = -EIO; | ||
2288 | goto err_out; | ||
2289 | } | ||
2290 | a = ctx->attr; | ||
2291 | /* The total length of the attribute value. */ | ||
2292 | attr_len = le32_to_cpu(a->data.resident.value_length); | ||
2293 | BUG_ON(from > attr_len); | ||
2294 | kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); | ||
2295 | kaddr = kmap_atomic(page, KM_USER0); | ||
2296 | /* Copy the received data from the page to the mft record. */ | ||
2297 | memcpy(kattr + from, kaddr + from, to - from); | ||
2298 | /* Update the attribute length if necessary. */ | ||
2299 | if (to > attr_len) { | ||
2300 | attr_len = to; | ||
2301 | a->data.resident.value_length = cpu_to_le32(attr_len); | ||
2302 | } | ||
2303 | /* | ||
2304 | * If the page is not uptodate, bring the out of bounds area(s) | ||
2305 | * uptodate by copying data from the mft record to the page. | ||
2306 | */ | ||
2307 | if (!PageUptodate(page)) { | ||
2308 | if (from > 0) | ||
2309 | memcpy(kaddr, kattr, from); | ||
2310 | if (to < attr_len) | ||
2311 | memcpy(kaddr + to, kattr + to, attr_len - to); | ||
2312 | /* Zero the region outside the end of the attribute value. */ | ||
2313 | if (attr_len < PAGE_CACHE_SIZE) | ||
2314 | memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); | ||
2315 | /* | ||
2316 | * The probability of not having done any of the above is | ||
2317 | * extremely small, so we just flush unconditionally. | ||
2318 | */ | ||
2319 | flush_dcache_page(page); | ||
2320 | SetPageUptodate(page); | ||
2321 | } | ||
2322 | kunmap_atomic(kaddr, KM_USER0); | ||
2323 | /* Update i_size if necessary. */ | ||
2324 | if (i_size_read(vi) < attr_len) { | ||
2325 | unsigned long flags; | ||
2326 | |||
2327 | write_lock_irqsave(&ni->size_lock, flags); | ||
2328 | ni->allocated_size = ni->initialized_size = attr_len; | ||
2329 | i_size_write(vi, attr_len); | ||
2330 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2331 | } | ||
2332 | /* Mark the mft record dirty, so it gets written back. */ | ||
2333 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2334 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2335 | ntfs_attr_put_search_ctx(ctx); | ||
2336 | unmap_mft_record(base_ni); | ||
2337 | ntfs_debug("Done."); | ||
2338 | return 0; | ||
2339 | err_out: | ||
2340 | if (err == -ENOMEM) { | ||
2341 | ntfs_warning(vi->i_sb, "Error allocating memory required to " | ||
2342 | "commit the write."); | ||
2343 | if (PageUptodate(page)) { | ||
2344 | ntfs_warning(vi->i_sb, "Page is uptodate, setting " | ||
2345 | "dirty so the write will be retried " | ||
2346 | "later on by the VM."); | ||
2347 | /* | ||
2348 | * Put the page on mapping->dirty_pages, but leave its | ||
2349 | * buffers' dirty state as-is. | ||
2350 | */ | ||
2351 | __set_page_dirty_nobuffers(page); | ||
2352 | err = 0; | ||
2353 | } else | ||
2354 | ntfs_error(vi->i_sb, "Page is not uptodate. Written " | ||
2355 | "data has been lost."); | ||
2356 | } else { | ||
2357 | ntfs_error(vi->i_sb, "Resident attribute commit write failed " | ||
2358 | "with error %i.", err); | ||
2359 | NVolSetErrors(ni->vol); | ||
2360 | make_bad_inode(vi); | ||
2361 | } | ||
2362 | if (ctx) | ||
2363 | ntfs_attr_put_search_ctx(ctx); | ||
2364 | if (m) | ||
2365 | unmap_mft_record(base_ni); | ||
2366 | return err; | ||
2367 | } | ||
2368 | |||
2369 | #endif /* NTFS_RW */ | 1544 | #endif /* NTFS_RW */ |
2370 | 1545 | ||
2371 | /** | 1546 | /** |
@@ -2377,9 +1552,6 @@ struct address_space_operations ntfs_aops = { | |||
2377 | disk request queue. */ | 1552 | disk request queue. */ |
2378 | #ifdef NTFS_RW | 1553 | #ifdef NTFS_RW |
2379 | .writepage = ntfs_writepage, /* Write dirty page to disk. */ | 1554 | .writepage = ntfs_writepage, /* Write dirty page to disk. */ |
2380 | .prepare_write = ntfs_prepare_write, /* Prepare page and buffers | ||
2381 | ready to receive data. */ | ||
2382 | .commit_write = ntfs_commit_write, /* Commit received data. */ | ||
2383 | #endif /* NTFS_RW */ | 1555 | #endif /* NTFS_RW */ |
2384 | }; | 1556 | }; |
2385 | 1557 | ||
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index 3f9a4ff42ee5..eda056bac256 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c | |||
@@ -21,7 +21,9 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
24 | #include <linux/sched.h> | ||
24 | #include <linux/swap.h> | 25 | #include <linux/swap.h> |
26 | #include <linux/writeback.h> | ||
25 | 27 | ||
26 | #include "attrib.h" | 28 | #include "attrib.h" |
27 | #include "debug.h" | 29 | #include "debug.h" |
@@ -36,9 +38,27 @@ | |||
36 | * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode | 38 | * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode |
37 | * @ni: ntfs inode for which to map (part of) a runlist | 39 | * @ni: ntfs inode for which to map (part of) a runlist |
38 | * @vcn: map runlist part containing this vcn | 40 | * @vcn: map runlist part containing this vcn |
41 | * @ctx: active attribute search context if present or NULL if not | ||
39 | * | 42 | * |
40 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. | 43 | * Map the part of a runlist containing the @vcn of the ntfs inode @ni. |
41 | * | 44 | * |
45 | * If @ctx is specified, it is an active search context of @ni and its base mft | ||
46 | * record. This is needed when ntfs_map_runlist_nolock() encounters unmapped | ||
47 | * runlist fragments and allows their mapping. If you do not have the mft | ||
48 | * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock() | ||
49 | * will perform the necessary mapping and unmapping. | ||
50 | * | ||
51 | * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and | ||
52 | * restores it before returning. Thus, @ctx will be left pointing to the same | ||
53 | * attribute on return as on entry. However, the actual pointers in @ctx may | ||
54 | * point to different memory locations on return, so you must remember to reset | ||
55 | * any cached pointers from the @ctx, i.e. after the call to | ||
56 | * ntfs_map_runlist_nolock(), you will probably want to do: | ||
57 | * m = ctx->mrec; | ||
58 | * a = ctx->attr; | ||
59 | * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that | ||
60 | * you cache ctx->mrec in a variable @m of type MFT_RECORD *. | ||
61 | * | ||
42 | * Return 0 on success and -errno on error. There is one special error code | 62 | * Return 0 on success and -errno on error. There is one special error code |
43 | * which is not an error as such. This is -ENOENT. It means that @vcn is out | 63 | * which is not an error as such. This is -ENOENT. It means that @vcn is out |
44 | * of bounds of the runlist. | 64 | * of bounds of the runlist. |
@@ -46,19 +66,32 @@ | |||
46 | * Note the runlist can be NULL after this function returns if @vcn is zero and | 66 | * Note the runlist can be NULL after this function returns if @vcn is zero and |
47 | * the attribute has zero allocated size, i.e. there simply is no runlist. | 67 | * the attribute has zero allocated size, i.e. there simply is no runlist. |
48 | * | 68 | * |
49 | * Locking: - The runlist must be locked for writing. | 69 | * WARNING: If @ctx is supplied, regardless of whether success or failure is |
50 | * - This function modifies the runlist. | 70 | * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx |
71 | * is no longer valid, i.e. you need to either call | ||
72 | * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. | ||
73 | * In that case PTR_ERR(@ctx->mrec) will give you the error code for | ||
74 | * why the mapping of the old inode failed. | ||
75 | * | ||
76 | * Locking: - The runlist described by @ni must be locked for writing on entry | ||
77 | * and is locked on return. Note the runlist will be modified. | ||
78 | * - If @ctx is NULL, the base mft record of @ni must not be mapped on | ||
79 | * entry and it will be left unmapped on return. | ||
80 | * - If @ctx is not NULL, the base mft record must be mapped on entry | ||
81 | * and it will be left mapped on return. | ||
51 | */ | 82 | */ |
52 | int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | 83 | int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx) |
53 | { | 84 | { |
54 | VCN end_vcn; | 85 | VCN end_vcn; |
86 | unsigned long flags; | ||
55 | ntfs_inode *base_ni; | 87 | ntfs_inode *base_ni; |
56 | MFT_RECORD *m; | 88 | MFT_RECORD *m; |
57 | ATTR_RECORD *a; | 89 | ATTR_RECORD *a; |
58 | ntfs_attr_search_ctx *ctx; | ||
59 | runlist_element *rl; | 90 | runlist_element *rl; |
60 | unsigned long flags; | 91 | struct page *put_this_page = NULL; |
61 | int err = 0; | 92 | int err = 0; |
93 | BOOL ctx_is_temporary, ctx_needs_reset; | ||
94 | ntfs_attr_search_ctx old_ctx = { NULL, }; | ||
62 | 95 | ||
63 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", | 96 | ntfs_debug("Mapping runlist part containing vcn 0x%llx.", |
64 | (unsigned long long)vcn); | 97 | (unsigned long long)vcn); |
@@ -66,20 +99,77 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
66 | base_ni = ni; | 99 | base_ni = ni; |
67 | else | 100 | else |
68 | base_ni = ni->ext.base_ntfs_ino; | 101 | base_ni = ni->ext.base_ntfs_ino; |
69 | m = map_mft_record(base_ni); | 102 | if (!ctx) { |
70 | if (IS_ERR(m)) | 103 | ctx_is_temporary = ctx_needs_reset = TRUE; |
71 | return PTR_ERR(m); | 104 | m = map_mft_record(base_ni); |
72 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | 105 | if (IS_ERR(m)) |
73 | if (unlikely(!ctx)) { | 106 | return PTR_ERR(m); |
74 | err = -ENOMEM; | 107 | ctx = ntfs_attr_get_search_ctx(base_ni, m); |
75 | goto err_out; | 108 | if (unlikely(!ctx)) { |
109 | err = -ENOMEM; | ||
110 | goto err_out; | ||
111 | } | ||
112 | } else { | ||
113 | VCN allocated_size_vcn; | ||
114 | |||
115 | BUG_ON(IS_ERR(ctx->mrec)); | ||
116 | a = ctx->attr; | ||
117 | BUG_ON(!a->non_resident); | ||
118 | ctx_is_temporary = FALSE; | ||
119 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); | ||
120 | read_lock_irqsave(&ni->size_lock, flags); | ||
121 | allocated_size_vcn = ni->allocated_size >> | ||
122 | ni->vol->cluster_size_bits; | ||
123 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
124 | if (!a->data.non_resident.lowest_vcn && end_vcn <= 0) | ||
125 | end_vcn = allocated_size_vcn - 1; | ||
126 | /* | ||
127 | * If we already have the attribute extent containing @vcn in | ||
128 | * @ctx, no need to look it up again. We slightly cheat in | ||
129 | * that if vcn exceeds the allocated size, we will refuse to | ||
130 | * map the runlist below, so there is definitely no need to get | ||
131 | * the right attribute extent. | ||
132 | */ | ||
133 | if (vcn >= allocated_size_vcn || (a->type == ni->type && | ||
134 | a->name_length == ni->name_len && | ||
135 | !memcmp((u8*)a + le16_to_cpu(a->name_offset), | ||
136 | ni->name, ni->name_len) && | ||
137 | sle64_to_cpu(a->data.non_resident.lowest_vcn) | ||
138 | <= vcn && end_vcn >= vcn)) | ||
139 | ctx_needs_reset = FALSE; | ||
140 | else { | ||
141 | /* Save the old search context. */ | ||
142 | old_ctx = *ctx; | ||
143 | /* | ||
144 | * If the currently mapped (extent) inode is not the | ||
145 | * base inode we will unmap it when we reinitialize the | ||
146 | * search context which means we need to get a | ||
147 | * reference to the page containing the mapped mft | ||
148 | * record so we do not accidentally drop changes to the | ||
149 | * mft record when it has not been marked dirty yet. | ||
150 | */ | ||
151 | if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino != | ||
152 | old_ctx.base_ntfs_ino) { | ||
153 | put_this_page = old_ctx.ntfs_ino->page; | ||
154 | page_cache_get(put_this_page); | ||
155 | } | ||
156 | /* | ||
157 | * Reinitialize the search context so we can lookup the | ||
158 | * needed attribute extent. | ||
159 | */ | ||
160 | ntfs_attr_reinit_search_ctx(ctx); | ||
161 | ctx_needs_reset = TRUE; | ||
162 | } | ||
76 | } | 163 | } |
77 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 164 | if (ctx_needs_reset) { |
78 | CASE_SENSITIVE, vcn, NULL, 0, ctx); | 165 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
79 | if (unlikely(err)) { | 166 | CASE_SENSITIVE, vcn, NULL, 0, ctx); |
80 | if (err == -ENOENT) | 167 | if (unlikely(err)) { |
81 | err = -EIO; | 168 | if (err == -ENOENT) |
82 | goto err_out; | 169 | err = -EIO; |
170 | goto err_out; | ||
171 | } | ||
172 | BUG_ON(!ctx->attr->non_resident); | ||
83 | } | 173 | } |
84 | a = ctx->attr; | 174 | a = ctx->attr; |
85 | /* | 175 | /* |
@@ -89,11 +179,9 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
89 | * ntfs_mapping_pairs_decompress() fails. | 179 | * ntfs_mapping_pairs_decompress() fails. |
90 | */ | 180 | */ |
91 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; | 181 | end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; |
92 | if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1)) { | 182 | if (!a->data.non_resident.lowest_vcn && end_vcn == 1) |
93 | read_lock_irqsave(&ni->size_lock, flags); | 183 | end_vcn = sle64_to_cpu(a->data.non_resident.allocated_size) >> |
94 | end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits; | 184 | ni->vol->cluster_size_bits; |
95 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
96 | } | ||
97 | if (unlikely(vcn >= end_vcn)) { | 185 | if (unlikely(vcn >= end_vcn)) { |
98 | err = -ENOENT; | 186 | err = -ENOENT; |
99 | goto err_out; | 187 | goto err_out; |
@@ -104,9 +192,93 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn) | |||
104 | else | 192 | else |
105 | ni->runlist.rl = rl; | 193 | ni->runlist.rl = rl; |
106 | err_out: | 194 | err_out: |
107 | if (likely(ctx)) | 195 | if (ctx_is_temporary) { |
108 | ntfs_attr_put_search_ctx(ctx); | 196 | if (likely(ctx)) |
109 | unmap_mft_record(base_ni); | 197 | ntfs_attr_put_search_ctx(ctx); |
198 | unmap_mft_record(base_ni); | ||
199 | } else if (ctx_needs_reset) { | ||
200 | /* | ||
201 | * If there is no attribute list, restoring the search context | ||
202 | * is acomplished simply by copying the saved context back over | ||
203 | * the caller supplied context. If there is an attribute list, | ||
204 | * things are more complicated as we need to deal with mapping | ||
205 | * of mft records and resulting potential changes in pointers. | ||
206 | */ | ||
207 | if (NInoAttrList(base_ni)) { | ||
208 | /* | ||
209 | * If the currently mapped (extent) inode is not the | ||
210 | * one we had before, we need to unmap it and map the | ||
211 | * old one. | ||
212 | */ | ||
213 | if (ctx->ntfs_ino != old_ctx.ntfs_ino) { | ||
214 | /* | ||
215 | * If the currently mapped inode is not the | ||
216 | * base inode, unmap it. | ||
217 | */ | ||
218 | if (ctx->base_ntfs_ino && ctx->ntfs_ino != | ||
219 | ctx->base_ntfs_ino) { | ||
220 | unmap_extent_mft_record(ctx->ntfs_ino); | ||
221 | ctx->mrec = ctx->base_mrec; | ||
222 | BUG_ON(!ctx->mrec); | ||
223 | } | ||
224 | /* | ||
225 | * If the old mapped inode is not the base | ||
226 | * inode, map it. | ||
227 | */ | ||
228 | if (old_ctx.base_ntfs_ino && | ||
229 | old_ctx.ntfs_ino != | ||
230 | old_ctx.base_ntfs_ino) { | ||
231 | retry_map: | ||
232 | ctx->mrec = map_mft_record( | ||
233 | old_ctx.ntfs_ino); | ||
234 | /* | ||
235 | * Something bad has happened. If out | ||
236 | * of memory retry till it succeeds. | ||
237 | * Any other errors are fatal and we | ||
238 | * return the error code in ctx->mrec. | ||
239 | * Let the caller deal with it... We | ||
240 | * just need to fudge things so the | ||
241 | * caller can reinit and/or put the | ||
242 | * search context safely. | ||
243 | */ | ||
244 | if (IS_ERR(ctx->mrec)) { | ||
245 | if (PTR_ERR(ctx->mrec) == | ||
246 | -ENOMEM) { | ||
247 | schedule(); | ||
248 | goto retry_map; | ||
249 | } else | ||
250 | old_ctx.ntfs_ino = | ||
251 | old_ctx. | ||
252 | base_ntfs_ino; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | /* Update the changed pointers in the saved context. */ | ||
257 | if (ctx->mrec != old_ctx.mrec) { | ||
258 | if (!IS_ERR(ctx->mrec)) | ||
259 | old_ctx.attr = (ATTR_RECORD*)( | ||
260 | (u8*)ctx->mrec + | ||
261 | ((u8*)old_ctx.attr - | ||
262 | (u8*)old_ctx.mrec)); | ||
263 | old_ctx.mrec = ctx->mrec; | ||
264 | } | ||
265 | } | ||
266 | /* Restore the search context to the saved one. */ | ||
267 | *ctx = old_ctx; | ||
268 | /* | ||
269 | * We drop the reference on the page we took earlier. In the | ||
270 | * case that IS_ERR(ctx->mrec) is true this means we might lose | ||
271 | * some changes to the mft record that had been made between | ||
272 | * the last time it was marked dirty/written out and now. This | ||
273 | * at this stage is not a problem as the mapping error is fatal | ||
274 | * enough that the mft record cannot be written out anyway and | ||
275 | * the caller is very likely to shutdown the whole inode | ||
276 | * immediately and mark the volume dirty for chkdsk to pick up | ||
277 | * the pieces anyway. | ||
278 | */ | ||
279 | if (put_this_page) | ||
280 | page_cache_release(put_this_page); | ||
281 | } | ||
110 | return err; | 282 | return err; |
111 | } | 283 | } |
112 | 284 | ||
@@ -122,8 +294,8 @@ err_out: | |||
122 | * of bounds of the runlist. | 294 | * of bounds of the runlist. |
123 | * | 295 | * |
124 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. | 296 | * Locking: - The runlist must be unlocked on entry and is unlocked on return. |
125 | * - This function takes the runlist lock for writing and modifies the | 297 | * - This function takes the runlist lock for writing and may modify |
126 | * runlist. | 298 | * the runlist. |
127 | */ | 299 | */ |
128 | int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | 300 | int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) |
129 | { | 301 | { |
@@ -133,7 +305,7 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn) | |||
133 | /* Make sure someone else didn't do the work while we were sleeping. */ | 305 | /* Make sure someone else didn't do the work while we were sleeping. */ |
134 | if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= | 306 | if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= |
135 | LCN_RL_NOT_MAPPED)) | 307 | LCN_RL_NOT_MAPPED)) |
136 | err = ntfs_map_runlist_nolock(ni, vcn); | 308 | err = ntfs_map_runlist_nolock(ni, vcn, NULL); |
137 | up_write(&ni->runlist.lock); | 309 | up_write(&ni->runlist.lock); |
138 | return err; | 310 | return err; |
139 | } | 311 | } |
@@ -212,7 +384,7 @@ retry_remap: | |||
212 | goto retry_remap; | 384 | goto retry_remap; |
213 | } | 385 | } |
214 | } | 386 | } |
215 | err = ntfs_map_runlist_nolock(ni, vcn); | 387 | err = ntfs_map_runlist_nolock(ni, vcn, NULL); |
216 | if (!write_locked) { | 388 | if (!write_locked) { |
217 | up_write(&ni->runlist.lock); | 389 | up_write(&ni->runlist.lock); |
218 | down_read(&ni->runlist.lock); | 390 | down_read(&ni->runlist.lock); |
@@ -236,9 +408,9 @@ retry_remap: | |||
236 | 408 | ||
237 | /** | 409 | /** |
238 | * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode | 410 | * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode |
239 | * @ni: ntfs inode describing the runlist to search | 411 | * @ni: ntfs inode describing the runlist to search |
240 | * @vcn: vcn to find | 412 | * @vcn: vcn to find |
241 | * @write_locked: true if the runlist is locked for writing | 413 | * @ctx: active attribute search context if present or NULL if not |
242 | * | 414 | * |
243 | * Find the virtual cluster number @vcn in the runlist described by the ntfs | 415 | * Find the virtual cluster number @vcn in the runlist described by the ntfs |
244 | * inode @ni and return the address of the runlist element containing the @vcn. | 416 | * inode @ni and return the address of the runlist element containing the @vcn. |
@@ -246,9 +418,22 @@ retry_remap: | |||
246 | * If the @vcn is not mapped yet, the attempt is made to map the attribute | 418 | * If the @vcn is not mapped yet, the attempt is made to map the attribute |
247 | * extent containing the @vcn and the vcn to lcn conversion is retried. | 419 | * extent containing the @vcn and the vcn to lcn conversion is retried. |
248 | * | 420 | * |
249 | * If @write_locked is true the caller has locked the runlist for writing and | 421 | * If @ctx is specified, it is an active search context of @ni and its base mft |
250 | * if false for reading. | 422 | * record. This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped |
251 | * | 423 | * runlist fragments and allows their mapping. If you do not have the mft |
424 | * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock() | ||
425 | * will perform the necessary mapping and unmapping. | ||
426 | * | ||
427 | * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and | ||
428 | * restores it before returning. Thus, @ctx will be left pointing to the same | ||
429 | * attribute on return as on entry. However, the actual pointers in @ctx may | ||
430 | * point to different memory locations on return, so you must remember to reset | ||
431 | * any cached pointers from the @ctx, i.e. after the call to | ||
432 | * ntfs_attr_find_vcn_nolock(), you will probably want to do: | ||
433 | * m = ctx->mrec; | ||
434 | * a = ctx->attr; | ||
435 | * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that | ||
436 | * you cache ctx->mrec in a variable @m of type MFT_RECORD *. | ||
252 | * Note you need to distinguish between the lcn of the returned runlist element | 437 | * Note you need to distinguish between the lcn of the returned runlist element |
253 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on | 438 | * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on |
254 | * read and allocate clusters on write. | 439 | * read and allocate clusters on write. |
@@ -263,22 +448,31 @@ retry_remap: | |||
263 | * -ENOMEM - Not enough memory to map runlist. | 448 | * -ENOMEM - Not enough memory to map runlist. |
264 | * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). | 449 | * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). |
265 | * | 450 | * |
266 | * Locking: - The runlist must be locked on entry and is left locked on return. | 451 | * WARNING: If @ctx is supplied, regardless of whether success or failure is |
267 | * - If @write_locked is FALSE, i.e. the runlist is locked for reading, | 452 | * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx |
268 | * the lock may be dropped inside the function so you cannot rely on | 453 | * is no longer valid, i.e. you need to either call |
269 | * the runlist still being the same when this function returns. | 454 | * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. |
455 | * In that case PTR_ERR(@ctx->mrec) will give you the error code for | ||
456 | * why the mapping of the old inode failed. | ||
457 | * | ||
458 | * Locking: - The runlist described by @ni must be locked for writing on entry | ||
459 | * and is locked on return. Note the runlist may be modified when | ||
460 | * needed runlist fragments need to be mapped. | ||
461 | * - If @ctx is NULL, the base mft record of @ni must not be mapped on | ||
462 | * entry and it will be left unmapped on return. | ||
463 | * - If @ctx is not NULL, the base mft record must be mapped on entry | ||
464 | * and it will be left mapped on return. | ||
270 | */ | 465 | */ |
271 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, | 466 | runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, |
272 | const BOOL write_locked) | 467 | ntfs_attr_search_ctx *ctx) |
273 | { | 468 | { |
274 | unsigned long flags; | 469 | unsigned long flags; |
275 | runlist_element *rl; | 470 | runlist_element *rl; |
276 | int err = 0; | 471 | int err = 0; |
277 | BOOL is_retry = FALSE; | 472 | BOOL is_retry = FALSE; |
278 | 473 | ||
279 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", | 474 | ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.", |
280 | ni->mft_no, (unsigned long long)vcn, | 475 | ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out"); |
281 | write_locked ? "write" : "read"); | ||
282 | BUG_ON(!ni); | 476 | BUG_ON(!ni); |
283 | BUG_ON(!NInoNonResident(ni)); | 477 | BUG_ON(!NInoNonResident(ni)); |
284 | BUG_ON(vcn < 0); | 478 | BUG_ON(vcn < 0); |
@@ -312,33 +506,22 @@ retry_remap: | |||
312 | } | 506 | } |
313 | if (!err && !is_retry) { | 507 | if (!err && !is_retry) { |
314 | /* | 508 | /* |
315 | * The @vcn is in an unmapped region, map the runlist and | 509 | * If the search context is invalid we cannot map the unmapped |
316 | * retry. | 510 | * region. |
317 | */ | 511 | */ |
318 | if (!write_locked) { | 512 | if (IS_ERR(ctx->mrec)) |
319 | up_read(&ni->runlist.lock); | 513 | err = PTR_ERR(ctx->mrec); |
320 | down_write(&ni->runlist.lock); | 514 | else { |
321 | if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) != | 515 | /* |
322 | LCN_RL_NOT_MAPPED)) { | 516 | * The @vcn is in an unmapped region, map the runlist |
323 | up_write(&ni->runlist.lock); | 517 | * and retry. |
324 | down_read(&ni->runlist.lock); | 518 | */ |
519 | err = ntfs_map_runlist_nolock(ni, vcn, ctx); | ||
520 | if (likely(!err)) { | ||
521 | is_retry = TRUE; | ||
325 | goto retry_remap; | 522 | goto retry_remap; |
326 | } | 523 | } |
327 | } | 524 | } |
328 | err = ntfs_map_runlist_nolock(ni, vcn); | ||
329 | if (!write_locked) { | ||
330 | up_write(&ni->runlist.lock); | ||
331 | down_read(&ni->runlist.lock); | ||
332 | } | ||
333 | if (likely(!err)) { | ||
334 | is_retry = TRUE; | ||
335 | goto retry_remap; | ||
336 | } | ||
337 | /* | ||
338 | * -EINVAL coming from a failed mapping attempt is equivalent | ||
339 | * to i/o error for us as it should not happen in our code | ||
340 | * paths. | ||
341 | */ | ||
342 | if (err == -EINVAL) | 525 | if (err == -EINVAL) |
343 | err = -EIO; | 526 | err = -EIO; |
344 | } else if (!err) | 527 | } else if (!err) |
@@ -1011,6 +1194,7 @@ int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, | |||
1011 | ntfs_inode *base_ni; | 1194 | ntfs_inode *base_ni; |
1012 | 1195 | ||
1013 | ntfs_debug("Entering."); | 1196 | ntfs_debug("Entering."); |
1197 | BUG_ON(IS_ERR(ctx->mrec)); | ||
1014 | if (ctx->base_ntfs_ino) | 1198 | if (ctx->base_ntfs_ino) |
1015 | base_ni = ctx->base_ntfs_ino; | 1199 | base_ni = ctx->base_ntfs_ino; |
1016 | else | 1200 | else |
@@ -1227,7 +1411,7 @@ int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type) | |||
1227 | */ | 1411 | */ |
1228 | int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type) | 1412 | int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type) |
1229 | { | 1413 | { |
1230 | if (type == AT_INDEX_ALLOCATION || type == AT_EA) | 1414 | if (type == AT_INDEX_ALLOCATION) |
1231 | return -EPERM; | 1415 | return -EPERM; |
1232 | return 0; | 1416 | return 0; |
1233 | } | 1417 | } |
@@ -1319,10 +1503,17 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, | |||
1319 | /** | 1503 | /** |
1320 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute | 1504 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute |
1321 | * @ni: ntfs inode describing the attribute to convert | 1505 | * @ni: ntfs inode describing the attribute to convert |
1506 | * @data_size: size of the resident data to copy to the non-resident attribute | ||
1322 | * | 1507 | * |
1323 | * Convert the resident ntfs attribute described by the ntfs inode @ni to a | 1508 | * Convert the resident ntfs attribute described by the ntfs inode @ni to a |
1324 | * non-resident one. | 1509 | * non-resident one. |
1325 | * | 1510 | * |
1511 | * @data_size must be equal to the attribute value size. This is needed since | ||
1512 | * we need to know the size before we can map the mft record and our callers | ||
1513 | * always know it. The reason we cannot simply read the size from the vfs | ||
1514 | * inode i_size is that this is not necessarily uptodate. This happens when | ||
1515 | * ntfs_attr_make_non_resident() is called in the ->truncate call path(s). | ||
1516 | * | ||
1326 | * Return 0 on success and -errno on error. The following error return codes | 1517 | * Return 0 on success and -errno on error. The following error return codes |
1327 | * are defined: | 1518 | * are defined: |
1328 | * -EPERM - The attribute is not allowed to be non-resident. | 1519 | * -EPERM - The attribute is not allowed to be non-resident. |
@@ -1343,7 +1534,7 @@ int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, | |||
1343 | * | 1534 | * |
1344 | * Locking: - The caller must hold i_sem on the inode. | 1535 | * Locking: - The caller must hold i_sem on the inode. |
1345 | */ | 1536 | */ |
1346 | int ntfs_attr_make_non_resident(ntfs_inode *ni) | 1537 | int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) |
1347 | { | 1538 | { |
1348 | s64 new_size; | 1539 | s64 new_size; |
1349 | struct inode *vi = VFS_I(ni); | 1540 | struct inode *vi = VFS_I(ni); |
@@ -1381,11 +1572,9 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1381 | * The size needs to be aligned to a cluster boundary for allocation | 1572 | * The size needs to be aligned to a cluster boundary for allocation |
1382 | * purposes. | 1573 | * purposes. |
1383 | */ | 1574 | */ |
1384 | new_size = (i_size_read(vi) + vol->cluster_size - 1) & | 1575 | new_size = (data_size + vol->cluster_size - 1) & |
1385 | ~(vol->cluster_size - 1); | 1576 | ~(vol->cluster_size - 1); |
1386 | if (new_size > 0) { | 1577 | if (new_size > 0) { |
1387 | runlist_element *rl2; | ||
1388 | |||
1389 | /* | 1578 | /* |
1390 | * Will need the page later and since the page lock nests | 1579 | * Will need the page later and since the page lock nests |
1391 | * outside all ntfs locks, we need to get the page now. | 1580 | * outside all ntfs locks, we need to get the page now. |
@@ -1396,7 +1585,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1396 | return -ENOMEM; | 1585 | return -ENOMEM; |
1397 | /* Start by allocating clusters to hold the attribute value. */ | 1586 | /* Start by allocating clusters to hold the attribute value. */ |
1398 | rl = ntfs_cluster_alloc(vol, 0, new_size >> | 1587 | rl = ntfs_cluster_alloc(vol, 0, new_size >> |
1399 | vol->cluster_size_bits, -1, DATA_ZONE); | 1588 | vol->cluster_size_bits, -1, DATA_ZONE, TRUE); |
1400 | if (IS_ERR(rl)) { | 1589 | if (IS_ERR(rl)) { |
1401 | err = PTR_ERR(rl); | 1590 | err = PTR_ERR(rl); |
1402 | ntfs_debug("Failed to allocate cluster%s, error code " | 1591 | ntfs_debug("Failed to allocate cluster%s, error code " |
@@ -1405,12 +1594,6 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1405 | err); | 1594 | err); |
1406 | goto page_err_out; | 1595 | goto page_err_out; |
1407 | } | 1596 | } |
1408 | /* Change the runlist terminator to LCN_ENOENT. */ | ||
1409 | rl2 = rl; | ||
1410 | while (rl2->length) | ||
1411 | rl2++; | ||
1412 | BUG_ON(rl2->lcn != LCN_RL_NOT_MAPPED); | ||
1413 | rl2->lcn = LCN_ENOENT; | ||
1414 | } else { | 1597 | } else { |
1415 | rl = NULL; | 1598 | rl = NULL; |
1416 | page = NULL; | 1599 | page = NULL; |
@@ -1473,7 +1656,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1473 | * attribute value. | 1656 | * attribute value. |
1474 | */ | 1657 | */ |
1475 | attr_size = le32_to_cpu(a->data.resident.value_length); | 1658 | attr_size = le32_to_cpu(a->data.resident.value_length); |
1476 | BUG_ON(attr_size != i_size_read(vi)); | 1659 | BUG_ON(attr_size != data_size); |
1477 | if (page && !PageUptodate(page)) { | 1660 | if (page && !PageUptodate(page)) { |
1478 | kaddr = kmap_atomic(page, KM_USER0); | 1661 | kaddr = kmap_atomic(page, KM_USER0); |
1479 | memcpy(kaddr, (u8*)a + | 1662 | memcpy(kaddr, (u8*)a + |
@@ -1538,7 +1721,9 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni) | |||
1538 | ffs(ni->itype.compressed.block_size) - 1; | 1721 | ffs(ni->itype.compressed.block_size) - 1; |
1539 | ni->itype.compressed.block_clusters = 1U << | 1722 | ni->itype.compressed.block_clusters = 1U << |
1540 | a->data.non_resident.compression_unit; | 1723 | a->data.non_resident.compression_unit; |
1541 | } | 1724 | vi->i_blocks = ni->itype.compressed.size >> 9; |
1725 | } else | ||
1726 | vi->i_blocks = ni->allocated_size >> 9; | ||
1542 | write_unlock_irqrestore(&ni->size_lock, flags); | 1727 | write_unlock_irqrestore(&ni->size_lock, flags); |
1543 | /* | 1728 | /* |
1544 | * This needs to be last since the address space operations ->readpage | 1729 | * This needs to be last since the address space operations ->readpage |
@@ -1652,6 +1837,640 @@ page_err_out: | |||
1652 | } | 1837 | } |
1653 | 1838 | ||
1654 | /** | 1839 | /** |
1840 | * ntfs_attr_extend_allocation - extend the allocated space of an attribute | ||
1841 | * @ni: ntfs inode of the attribute whose allocation to extend | ||
1842 | * @new_alloc_size: new size in bytes to which to extend the allocation to | ||
1843 | * @new_data_size: new size in bytes to which to extend the data to | ||
1844 | * @data_start: beginning of region which is required to be non-sparse | ||
1845 | * | ||
1846 | * Extend the allocated space of an attribute described by the ntfs inode @ni | ||
1847 | * to @new_alloc_size bytes. If @data_start is -1, the whole extension may be | ||
1848 | * implemented as a hole in the file (as long as both the volume and the ntfs | ||
1849 | * inode @ni have sparse support enabled). If @data_start is >= 0, then the | ||
1850 | * region between the old allocated size and @data_start - 1 may be made sparse | ||
1851 | * but the regions between @data_start and @new_alloc_size must be backed by | ||
1852 | * actual clusters. | ||
1853 | * | ||
1854 | * If @new_data_size is -1, it is ignored. If it is >= 0, then the data size | ||
1855 | * of the attribute is extended to @new_data_size. Note that the i_size of the | ||
1856 | * vfs inode is not updated. Only the data size in the base attribute record | ||
1857 | * is updated. The caller has to update i_size separately if this is required. | ||
1858 | * WARNING: It is a BUG() for @new_data_size to be smaller than the old data | ||
1859 | * size as well as for @new_data_size to be greater than @new_alloc_size. | ||
1860 | * | ||
1861 | * For resident attributes this involves resizing the attribute record and if | ||
1862 | * necessary moving it and/or other attributes into extent mft records and/or | ||
1863 | * converting the attribute to a non-resident attribute which in turn involves | ||
1864 | * extending the allocation of a non-resident attribute as described below. | ||
1865 | * | ||
1866 | * For non-resident attributes this involves allocating clusters in the data | ||
1867 | * zone on the volume (except for regions that are being made sparse) and | ||
1868 | * extending the run list to describe the allocated clusters as well as | ||
1869 | * updating the mapping pairs array of the attribute. This in turn involves | ||
1870 | * resizing the attribute record and if necessary moving it and/or other | ||
1871 | * attributes into extent mft records and/or splitting the attribute record | ||
1872 | * into multiple extent attribute records. | ||
1873 | * | ||
1874 | * Also, the attribute list attribute is updated if present and in some of the | ||
1875 | * above cases (the ones where extent mft records/attributes come into play), | ||
1876 | * an attribute list attribute is created if not already present. | ||
1877 | * | ||
1878 | * Return the new allocated size on success and -errno on error. In the case | ||
1879 | * that an error is encountered but a partial extension at least up to | ||
1880 | * @data_start (if present) is possible, the allocation is partially extended | ||
1881 | * and this is returned. This means the caller must check the returned size to | ||
1882 | * determine if the extension was partial. If @data_start is -1 then partial | ||
1883 | * allocations are not performed. | ||
1884 | * | ||
1885 | * WARNING: Do not call ntfs_attr_extend_allocation() for $MFT/$DATA. | ||
1886 | * | ||
1887 | * Locking: This function takes the runlist lock of @ni for writing as well as | ||
1888 | * locking the mft record of the base ntfs inode. These locks are maintained | ||
1889 | * throughout execution of the function. These locks are required so that the | ||
1890 | * attribute can be resized safely and so that it can for example be converted | ||
1891 | * from resident to non-resident safely. | ||
1892 | * | ||
1893 | * TODO: At present attribute list attribute handling is not implemented. | ||
1894 | * | ||
1895 | * TODO: At present it is not safe to call this function for anything other | ||
1896 | * than the $DATA attribute(s) of an uncompressed and unencrypted file. | ||
1897 | */ | ||
1898 | s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, | ||
1899 | const s64 new_data_size, const s64 data_start) | ||
1900 | { | ||
1901 | VCN vcn; | ||
1902 | s64 ll, allocated_size, start = data_start; | ||
1903 | struct inode *vi = VFS_I(ni); | ||
1904 | ntfs_volume *vol = ni->vol; | ||
1905 | ntfs_inode *base_ni; | ||
1906 | MFT_RECORD *m; | ||
1907 | ATTR_RECORD *a; | ||
1908 | ntfs_attr_search_ctx *ctx; | ||
1909 | runlist_element *rl, *rl2; | ||
1910 | unsigned long flags; | ||
1911 | int err, mp_size; | ||
1912 | u32 attr_len = 0; /* Silence stupid gcc warning. */ | ||
1913 | BOOL mp_rebuilt; | ||
1914 | |||
1915 | #ifdef NTFS_DEBUG | ||
1916 | read_lock_irqsave(&ni->size_lock, flags); | ||
1917 | allocated_size = ni->allocated_size; | ||
1918 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1919 | ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " | ||
1920 | "old_allocated_size 0x%llx, " | ||
1921 | "new_allocated_size 0x%llx, new_data_size 0x%llx, " | ||
1922 | "data_start 0x%llx.", vi->i_ino, | ||
1923 | (unsigned)le32_to_cpu(ni->type), | ||
1924 | (unsigned long long)allocated_size, | ||
1925 | (unsigned long long)new_alloc_size, | ||
1926 | (unsigned long long)new_data_size, | ||
1927 | (unsigned long long)start); | ||
1928 | #endif | ||
1929 | retry_extend: | ||
1930 | /* | ||
1931 | * For non-resident attributes, @start and @new_size need to be aligned | ||
1932 | * to cluster boundaries for allocation purposes. | ||
1933 | */ | ||
1934 | if (NInoNonResident(ni)) { | ||
1935 | if (start > 0) | ||
1936 | start &= ~(s64)vol->cluster_size_mask; | ||
1937 | new_alloc_size = (new_alloc_size + vol->cluster_size - 1) & | ||
1938 | ~(s64)vol->cluster_size_mask; | ||
1939 | } | ||
1940 | BUG_ON(new_data_size >= 0 && new_data_size > new_alloc_size); | ||
1941 | /* Check if new size is allowed in $AttrDef. */ | ||
1942 | err = ntfs_attr_size_bounds_check(vol, ni->type, new_alloc_size); | ||
1943 | if (unlikely(err)) { | ||
1944 | /* Only emit errors when the write will fail completely. */ | ||
1945 | read_lock_irqsave(&ni->size_lock, flags); | ||
1946 | allocated_size = ni->allocated_size; | ||
1947 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1948 | if (start < 0 || start >= allocated_size) { | ||
1949 | if (err == -ERANGE) { | ||
1950 | ntfs_error(vol->sb, "Cannot extend allocation " | ||
1951 | "of inode 0x%lx, attribute " | ||
1952 | "type 0x%x, because the new " | ||
1953 | "allocation would exceed the " | ||
1954 | "maximum allowed size for " | ||
1955 | "this attribute type.", | ||
1956 | vi->i_ino, (unsigned) | ||
1957 | le32_to_cpu(ni->type)); | ||
1958 | } else { | ||
1959 | ntfs_error(vol->sb, "Cannot extend allocation " | ||
1960 | "of inode 0x%lx, attribute " | ||
1961 | "type 0x%x, because this " | ||
1962 | "attribute type is not " | ||
1963 | "defined on the NTFS volume. " | ||
1964 | "Possible corruption! You " | ||
1965 | "should run chkdsk!", | ||
1966 | vi->i_ino, (unsigned) | ||
1967 | le32_to_cpu(ni->type)); | ||
1968 | } | ||
1969 | } | ||
1970 | /* Translate error code to be POSIX conformant for write(2). */ | ||
1971 | if (err == -ERANGE) | ||
1972 | err = -EFBIG; | ||
1973 | else | ||
1974 | err = -EIO; | ||
1975 | return err; | ||
1976 | } | ||
1977 | if (!NInoAttr(ni)) | ||
1978 | base_ni = ni; | ||
1979 | else | ||
1980 | base_ni = ni->ext.base_ntfs_ino; | ||
1981 | /* | ||
1982 | * We will be modifying both the runlist (if non-resident) and the mft | ||
1983 | * record so lock them both down. | ||
1984 | */ | ||
1985 | down_write(&ni->runlist.lock); | ||
1986 | m = map_mft_record(base_ni); | ||
1987 | if (IS_ERR(m)) { | ||
1988 | err = PTR_ERR(m); | ||
1989 | m = NULL; | ||
1990 | ctx = NULL; | ||
1991 | goto err_out; | ||
1992 | } | ||
1993 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
1994 | if (unlikely(!ctx)) { | ||
1995 | err = -ENOMEM; | ||
1996 | goto err_out; | ||
1997 | } | ||
1998 | read_lock_irqsave(&ni->size_lock, flags); | ||
1999 | allocated_size = ni->allocated_size; | ||
2000 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
2001 | /* | ||
2002 | * If non-resident, seek to the last extent. If resident, there is | ||
2003 | * only one extent, so seek to that. | ||
2004 | */ | ||
2005 | vcn = NInoNonResident(ni) ? allocated_size >> vol->cluster_size_bits : | ||
2006 | 0; | ||
2007 | /* | ||
2008 | * Abort if someone did the work whilst we waited for the locks. If we | ||
2009 | * just converted the attribute from resident to non-resident it is | ||
2010 | * likely that exactly this has happened already. We cannot quite | ||
2011 | * abort if we need to update the data size. | ||
2012 | */ | ||
2013 | if (unlikely(new_alloc_size <= allocated_size)) { | ||
2014 | ntfs_debug("Allocated size already exceeds requested size."); | ||
2015 | new_alloc_size = allocated_size; | ||
2016 | if (new_data_size < 0) | ||
2017 | goto done; | ||
2018 | /* | ||
2019 | * We want the first attribute extent so that we can update the | ||
2020 | * data size. | ||
2021 | */ | ||
2022 | vcn = 0; | ||
2023 | } | ||
2024 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
2025 | CASE_SENSITIVE, vcn, NULL, 0, ctx); | ||
2026 | if (unlikely(err)) { | ||
2027 | if (err == -ENOENT) | ||
2028 | err = -EIO; | ||
2029 | goto err_out; | ||
2030 | } | ||
2031 | m = ctx->mrec; | ||
2032 | a = ctx->attr; | ||
2033 | /* Use goto to reduce indentation. */ | ||
2034 | if (a->non_resident) | ||
2035 | goto do_non_resident_extend; | ||
2036 | BUG_ON(NInoNonResident(ni)); | ||
2037 | /* The total length of the attribute value. */ | ||
2038 | attr_len = le32_to_cpu(a->data.resident.value_length); | ||
2039 | /* | ||
2040 | * Extend the attribute record to be able to store the new attribute | ||
2041 | * size. ntfs_attr_record_resize() will not do anything if the size is | ||
2042 | * not changing. | ||
2043 | */ | ||
2044 | if (new_alloc_size < vol->mft_record_size && | ||
2045 | !ntfs_attr_record_resize(m, a, | ||
2046 | le16_to_cpu(a->data.resident.value_offset) + | ||
2047 | new_alloc_size)) { | ||
2048 | /* The resize succeeded! */ | ||
2049 | write_lock_irqsave(&ni->size_lock, flags); | ||
2050 | ni->allocated_size = le32_to_cpu(a->length) - | ||
2051 | le16_to_cpu(a->data.resident.value_offset); | ||
2052 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2053 | if (new_data_size >= 0) { | ||
2054 | BUG_ON(new_data_size < attr_len); | ||
2055 | a->data.resident.value_length = | ||
2056 | cpu_to_le32((u32)new_data_size); | ||
2057 | } | ||
2058 | goto flush_done; | ||
2059 | } | ||
2060 | /* | ||
2061 | * We have to drop all the locks so we can call | ||
2062 | * ntfs_attr_make_non_resident(). This could be optimised by try- | ||
2063 | * locking the first page cache page and only if that fails dropping | ||
2064 | * the locks, locking the page, and redoing all the locking and | ||
2065 | * lookups. While this would be a huge optimisation, it is not worth | ||
2066 | * it as this is definitely a slow code path. | ||
2067 | */ | ||
2068 | ntfs_attr_put_search_ctx(ctx); | ||
2069 | unmap_mft_record(base_ni); | ||
2070 | up_write(&ni->runlist.lock); | ||
2071 | /* | ||
2072 | * Not enough space in the mft record, try to make the attribute | ||
2073 | * non-resident and if successful restart the extension process. | ||
2074 | */ | ||
2075 | err = ntfs_attr_make_non_resident(ni, attr_len); | ||
2076 | if (likely(!err)) | ||
2077 | goto retry_extend; | ||
2078 | /* | ||
2079 | * Could not make non-resident. If this is due to this not being | ||
2080 | * permitted for this attribute type or there not being enough space, | ||
2081 | * try to make other attributes non-resident. Otherwise fail. | ||
2082 | */ | ||
2083 | if (unlikely(err != -EPERM && err != -ENOSPC)) { | ||
2084 | /* Only emit errors when the write will fail completely. */ | ||
2085 | read_lock_irqsave(&ni->size_lock, flags); | ||
2086 | allocated_size = ni->allocated_size; | ||
2087 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
2088 | if (start < 0 || start >= allocated_size) | ||
2089 | ntfs_error(vol->sb, "Cannot extend allocation of " | ||
2090 | "inode 0x%lx, attribute type 0x%x, " | ||
2091 | "because the conversion from resident " | ||
2092 | "to non-resident attribute failed " | ||
2093 | "with error code %i.", vi->i_ino, | ||
2094 | (unsigned)le32_to_cpu(ni->type), err); | ||
2095 | if (err != -ENOMEM) | ||
2096 | err = -EIO; | ||
2097 | goto conv_err_out; | ||
2098 | } | ||
2099 | /* TODO: Not implemented from here, abort. */ | ||
2100 | read_lock_irqsave(&ni->size_lock, flags); | ||
2101 | allocated_size = ni->allocated_size; | ||
2102 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
2103 | if (start < 0 || start >= allocated_size) { | ||
2104 | if (err == -ENOSPC) | ||
2105 | ntfs_error(vol->sb, "Not enough space in the mft " | ||
2106 | "record/on disk for the non-resident " | ||
2107 | "attribute value. This case is not " | ||
2108 | "implemented yet."); | ||
2109 | else /* if (err == -EPERM) */ | ||
2110 | ntfs_error(vol->sb, "This attribute type may not be " | ||
2111 | "non-resident. This case is not " | ||
2112 | "implemented yet."); | ||
2113 | } | ||
2114 | err = -EOPNOTSUPP; | ||
2115 | goto conv_err_out; | ||
2116 | #if 0 | ||
2117 | // TODO: Attempt to make other attributes non-resident. | ||
2118 | if (!err) | ||
2119 | goto do_resident_extend; | ||
2120 | /* | ||
2121 | * Both the attribute list attribute and the standard information | ||
2122 | * attribute must remain in the base inode. Thus, if this is one of | ||
2123 | * these attributes, we have to try to move other attributes out into | ||
2124 | * extent mft records instead. | ||
2125 | */ | ||
2126 | if (ni->type == AT_ATTRIBUTE_LIST || | ||
2127 | ni->type == AT_STANDARD_INFORMATION) { | ||
2128 | // TODO: Attempt to move other attributes into extent mft | ||
2129 | // records. | ||
2130 | err = -EOPNOTSUPP; | ||
2131 | if (!err) | ||
2132 | goto do_resident_extend; | ||
2133 | goto err_out; | ||
2134 | } | ||
2135 | // TODO: Attempt to move this attribute to an extent mft record, but | ||
2136 | // only if it is not already the only attribute in an mft record in | ||
2137 | // which case there would be nothing to gain. | ||
2138 | err = -EOPNOTSUPP; | ||
2139 | if (!err) | ||
2140 | goto do_resident_extend; | ||
2141 | /* There is nothing we can do to make enough space. )-: */ | ||
2142 | goto err_out; | ||
2143 | #endif | ||
2144 | do_non_resident_extend: | ||
2145 | BUG_ON(!NInoNonResident(ni)); | ||
2146 | if (new_alloc_size == allocated_size) { | ||
2147 | BUG_ON(vcn); | ||
2148 | goto alloc_done; | ||
2149 | } | ||
2150 | /* | ||
2151 | * If the data starts after the end of the old allocation, this is a | ||
2152 | * $DATA attribute and sparse attributes are enabled on the volume and | ||
2153 | * for this inode, then create a sparse region between the old | ||
2154 | * allocated size and the start of the data. Otherwise simply proceed | ||
2155 | * with filling the whole space between the old allocated size and the | ||
2156 | * new allocated size with clusters. | ||
2157 | */ | ||
2158 | if ((start >= 0 && start <= allocated_size) || ni->type != AT_DATA || | ||
2159 | !NVolSparseEnabled(vol) || NInoSparseDisabled(ni)) | ||
2160 | goto skip_sparse; | ||
2161 | // TODO: This is not implemented yet. We just fill in with real | ||
2162 | // clusters for now... | ||
2163 | ntfs_debug("Inserting holes is not-implemented yet. Falling back to " | ||
2164 | "allocating real clusters instead."); | ||
2165 | skip_sparse: | ||
2166 | rl = ni->runlist.rl; | ||
2167 | if (likely(rl)) { | ||
2168 | /* Seek to the end of the runlist. */ | ||
2169 | while (rl->length) | ||
2170 | rl++; | ||
2171 | } | ||
2172 | /* If this attribute extent is not mapped, map it now. */ | ||
2173 | if (unlikely(!rl || rl->lcn == LCN_RL_NOT_MAPPED || | ||
2174 | (rl->lcn == LCN_ENOENT && rl > ni->runlist.rl && | ||
2175 | (rl-1)->lcn == LCN_RL_NOT_MAPPED))) { | ||
2176 | if (!rl && !allocated_size) | ||
2177 | goto first_alloc; | ||
2178 | rl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl); | ||
2179 | if (IS_ERR(rl)) { | ||
2180 | err = PTR_ERR(rl); | ||
2181 | if (start < 0 || start >= allocated_size) | ||
2182 | ntfs_error(vol->sb, "Cannot extend allocation " | ||
2183 | "of inode 0x%lx, attribute " | ||
2184 | "type 0x%x, because the " | ||
2185 | "mapping of a runlist " | ||
2186 | "fragment failed with error " | ||
2187 | "code %i.", vi->i_ino, | ||
2188 | (unsigned)le32_to_cpu(ni->type), | ||
2189 | err); | ||
2190 | if (err != -ENOMEM) | ||
2191 | err = -EIO; | ||
2192 | goto err_out; | ||
2193 | } | ||
2194 | ni->runlist.rl = rl; | ||
2195 | /* Seek to the end of the runlist. */ | ||
2196 | while (rl->length) | ||
2197 | rl++; | ||
2198 | } | ||
2199 | /* | ||
2200 | * We now know the runlist of the last extent is mapped and @rl is at | ||
2201 | * the end of the runlist. We want to begin allocating clusters | ||
2202 | * starting at the last allocated cluster to reduce fragmentation. If | ||
2203 | * there are no valid LCNs in the attribute we let the cluster | ||
2204 | * allocator choose the starting cluster. | ||
2205 | */ | ||
2206 | /* If the last LCN is a hole or simillar seek back to last real LCN. */ | ||
2207 | while (rl->lcn < 0 && rl > ni->runlist.rl) | ||
2208 | rl--; | ||
2209 | first_alloc: | ||
2210 | // FIXME: Need to implement partial allocations so at least part of the | ||
2211 | // write can be performed when start >= 0. (Needed for POSIX write(2) | ||
2212 | // conformance.) | ||
2213 | rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits, | ||
2214 | (new_alloc_size - allocated_size) >> | ||
2215 | vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ? | ||
2216 | rl->lcn + rl->length : -1, DATA_ZONE, TRUE); | ||
2217 | if (IS_ERR(rl2)) { | ||
2218 | err = PTR_ERR(rl2); | ||
2219 | if (start < 0 || start >= allocated_size) | ||
2220 | ntfs_error(vol->sb, "Cannot extend allocation of " | ||
2221 | "inode 0x%lx, attribute type 0x%x, " | ||
2222 | "because the allocation of clusters " | ||
2223 | "failed with error code %i.", vi->i_ino, | ||
2224 | (unsigned)le32_to_cpu(ni->type), err); | ||
2225 | if (err != -ENOMEM && err != -ENOSPC) | ||
2226 | err = -EIO; | ||
2227 | goto err_out; | ||
2228 | } | ||
2229 | rl = ntfs_runlists_merge(ni->runlist.rl, rl2); | ||
2230 | if (IS_ERR(rl)) { | ||
2231 | err = PTR_ERR(rl); | ||
2232 | if (start < 0 || start >= allocated_size) | ||
2233 | ntfs_error(vol->sb, "Cannot extend allocation of " | ||
2234 | "inode 0x%lx, attribute type 0x%x, " | ||
2235 | "because the runlist merge failed " | ||
2236 | "with error code %i.", vi->i_ino, | ||
2237 | (unsigned)le32_to_cpu(ni->type), err); | ||
2238 | if (err != -ENOMEM) | ||
2239 | err = -EIO; | ||
2240 | if (ntfs_cluster_free_from_rl(vol, rl2)) { | ||
2241 | ntfs_error(vol->sb, "Failed to release allocated " | ||
2242 | "cluster(s) in error code path. Run " | ||
2243 | "chkdsk to recover the lost " | ||
2244 | "cluster(s)."); | ||
2245 | NVolSetErrors(vol); | ||
2246 | } | ||
2247 | ntfs_free(rl2); | ||
2248 | goto err_out; | ||
2249 | } | ||
2250 | ni->runlist.rl = rl; | ||
2251 | ntfs_debug("Allocated 0x%llx clusters.", (long long)(new_alloc_size - | ||
2252 | allocated_size) >> vol->cluster_size_bits); | ||
2253 | /* Find the runlist element with which the attribute extent starts. */ | ||
2254 | ll = sle64_to_cpu(a->data.non_resident.lowest_vcn); | ||
2255 | rl2 = ntfs_rl_find_vcn_nolock(rl, ll); | ||
2256 | BUG_ON(!rl2); | ||
2257 | BUG_ON(!rl2->length); | ||
2258 | BUG_ON(rl2->lcn < LCN_HOLE); | ||
2259 | mp_rebuilt = FALSE; | ||
2260 | /* Get the size for the new mapping pairs array for this extent. */ | ||
2261 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1); | ||
2262 | if (unlikely(mp_size <= 0)) { | ||
2263 | err = mp_size; | ||
2264 | if (start < 0 || start >= allocated_size) | ||
2265 | ntfs_error(vol->sb, "Cannot extend allocation of " | ||
2266 | "inode 0x%lx, attribute type 0x%x, " | ||
2267 | "because determining the size for the " | ||
2268 | "mapping pairs failed with error code " | ||
2269 | "%i.", vi->i_ino, | ||
2270 | (unsigned)le32_to_cpu(ni->type), err); | ||
2271 | err = -EIO; | ||
2272 | goto undo_alloc; | ||
2273 | } | ||
2274 | /* Extend the attribute record to fit the bigger mapping pairs array. */ | ||
2275 | attr_len = le32_to_cpu(a->length); | ||
2276 | err = ntfs_attr_record_resize(m, a, mp_size + | ||
2277 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); | ||
2278 | if (unlikely(err)) { | ||
2279 | BUG_ON(err != -ENOSPC); | ||
2280 | // TODO: Deal with this by moving this extent to a new mft | ||
2281 | // record or by starting a new extent in a new mft record, | ||
2282 | // possibly by extending this extent partially and filling it | ||
2283 | // and creating a new extent for the remainder, or by making | ||
2284 | // other attributes non-resident and/or by moving other | ||
2285 | // attributes out of this mft record. | ||
2286 | if (start < 0 || start >= allocated_size) | ||
2287 | ntfs_error(vol->sb, "Not enough space in the mft " | ||
2288 | "record for the extended attribute " | ||
2289 | "record. This case is not " | ||
2290 | "implemented yet."); | ||
2291 | err = -EOPNOTSUPP; | ||
2292 | goto undo_alloc; | ||
2293 | } | ||
2294 | mp_rebuilt = TRUE; | ||
2295 | /* Generate the mapping pairs array directly into the attr record. */ | ||
2296 | err = ntfs_mapping_pairs_build(vol, (u8*)a + | ||
2297 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), | ||
2298 | mp_size, rl2, ll, -1, NULL); | ||
2299 | if (unlikely(err)) { | ||
2300 | if (start < 0 || start >= allocated_size) | ||
2301 | ntfs_error(vol->sb, "Cannot extend allocation of " | ||
2302 | "inode 0x%lx, attribute type 0x%x, " | ||
2303 | "because building the mapping pairs " | ||
2304 | "failed with error code %i.", vi->i_ino, | ||
2305 | (unsigned)le32_to_cpu(ni->type), err); | ||
2306 | err = -EIO; | ||
2307 | goto undo_alloc; | ||
2308 | } | ||
2309 | /* Update the highest_vcn. */ | ||
2310 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> | ||
2311 | vol->cluster_size_bits) - 1); | ||
2312 | /* | ||
2313 | * We now have extended the allocated size of the attribute. Reflect | ||
2314 | * this in the ntfs_inode structure and the attribute record. | ||
2315 | */ | ||
2316 | if (a->data.non_resident.lowest_vcn) { | ||
2317 | /* | ||
2318 | * We are not in the first attribute extent, switch to it, but | ||
2319 | * first ensure the changes will make it to disk later. | ||
2320 | */ | ||
2321 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2322 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2323 | ntfs_attr_reinit_search_ctx(ctx); | ||
2324 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
2325 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
2326 | if (unlikely(err)) | ||
2327 | goto restore_undo_alloc; | ||
2328 | /* @m is not used any more so no need to set it. */ | ||
2329 | a = ctx->attr; | ||
2330 | } | ||
2331 | write_lock_irqsave(&ni->size_lock, flags); | ||
2332 | ni->allocated_size = new_alloc_size; | ||
2333 | a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); | ||
2334 | /* | ||
2335 | * FIXME: This would fail if @ni is a directory, $MFT, or an index, | ||
2336 | * since those can have sparse/compressed set. For example can be | ||
2337 | * set compressed even though it is not compressed itself and in that | ||
2338 | * case the bit means that files are to be created compressed in the | ||
2339 | * directory... At present this is ok as this code is only called for | ||
2340 | * regular files, and only for their $DATA attribute(s). | ||
2341 | * FIXME: The calculation is wrong if we created a hole above. For now | ||
2342 | * it does not matter as we never create holes. | ||
2343 | */ | ||
2344 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
2345 | ni->itype.compressed.size += new_alloc_size - allocated_size; | ||
2346 | a->data.non_resident.compressed_size = | ||
2347 | cpu_to_sle64(ni->itype.compressed.size); | ||
2348 | vi->i_blocks = ni->itype.compressed.size >> 9; | ||
2349 | } else | ||
2350 | vi->i_blocks = new_alloc_size >> 9; | ||
2351 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2352 | alloc_done: | ||
2353 | if (new_data_size >= 0) { | ||
2354 | BUG_ON(new_data_size < | ||
2355 | sle64_to_cpu(a->data.non_resident.data_size)); | ||
2356 | a->data.non_resident.data_size = cpu_to_sle64(new_data_size); | ||
2357 | } | ||
2358 | flush_done: | ||
2359 | /* Ensure the changes make it to disk. */ | ||
2360 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2361 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2362 | done: | ||
2363 | ntfs_attr_put_search_ctx(ctx); | ||
2364 | unmap_mft_record(base_ni); | ||
2365 | up_write(&ni->runlist.lock); | ||
2366 | ntfs_debug("Done, new_allocated_size 0x%llx.", | ||
2367 | (unsigned long long)new_alloc_size); | ||
2368 | return new_alloc_size; | ||
2369 | restore_undo_alloc: | ||
2370 | if (start < 0 || start >= allocated_size) | ||
2371 | ntfs_error(vol->sb, "Cannot complete extension of allocation " | ||
2372 | "of inode 0x%lx, attribute type 0x%x, because " | ||
2373 | "lookup of first attribute extent failed with " | ||
2374 | "error code %i.", vi->i_ino, | ||
2375 | (unsigned)le32_to_cpu(ni->type), err); | ||
2376 | if (err == -ENOENT) | ||
2377 | err = -EIO; | ||
2378 | ntfs_attr_reinit_search_ctx(ctx); | ||
2379 | if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, | ||
2380 | allocated_size >> vol->cluster_size_bits, NULL, 0, | ||
2381 | ctx)) { | ||
2382 | ntfs_error(vol->sb, "Failed to find last attribute extent of " | ||
2383 | "attribute in error code path. Run chkdsk to " | ||
2384 | "recover."); | ||
2385 | write_lock_irqsave(&ni->size_lock, flags); | ||
2386 | ni->allocated_size = new_alloc_size; | ||
2387 | /* | ||
2388 | * FIXME: This would fail if @ni is a directory... See above. | ||
2389 | * FIXME: The calculation is wrong if we created a hole above. | ||
2390 | * For now it does not matter as we never create holes. | ||
2391 | */ | ||
2392 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
2393 | ni->itype.compressed.size += new_alloc_size - | ||
2394 | allocated_size; | ||
2395 | vi->i_blocks = ni->itype.compressed.size >> 9; | ||
2396 | } else | ||
2397 | vi->i_blocks = new_alloc_size >> 9; | ||
2398 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2399 | ntfs_attr_put_search_ctx(ctx); | ||
2400 | unmap_mft_record(base_ni); | ||
2401 | up_write(&ni->runlist.lock); | ||
2402 | /* | ||
2403 | * The only thing that is now wrong is the allocated size of the | ||
2404 | * base attribute extent which chkdsk should be able to fix. | ||
2405 | */ | ||
2406 | NVolSetErrors(vol); | ||
2407 | return err; | ||
2408 | } | ||
2409 | ctx->attr->data.non_resident.highest_vcn = cpu_to_sle64( | ||
2410 | (allocated_size >> vol->cluster_size_bits) - 1); | ||
2411 | undo_alloc: | ||
2412 | ll = allocated_size >> vol->cluster_size_bits; | ||
2413 | if (ntfs_cluster_free(ni, ll, -1, ctx) < 0) { | ||
2414 | ntfs_error(vol->sb, "Failed to release allocated cluster(s) " | ||
2415 | "in error code path. Run chkdsk to recover " | ||
2416 | "the lost cluster(s)."); | ||
2417 | NVolSetErrors(vol); | ||
2418 | } | ||
2419 | m = ctx->mrec; | ||
2420 | a = ctx->attr; | ||
2421 | /* | ||
2422 | * If the runlist truncation fails and/or the search context is no | ||
2423 | * longer valid, we cannot resize the attribute record or build the | ||
2424 | * mapping pairs array thus we mark the inode bad so that no access to | ||
2425 | * the freed clusters can happen. | ||
2426 | */ | ||
2427 | if (ntfs_rl_truncate_nolock(vol, &ni->runlist, ll) || IS_ERR(m)) { | ||
2428 | ntfs_error(vol->sb, "Failed to %s in error code path. Run " | ||
2429 | "chkdsk to recover.", IS_ERR(m) ? | ||
2430 | "restore attribute search context" : | ||
2431 | "truncate attribute runlist"); | ||
2432 | make_bad_inode(vi); | ||
2433 | make_bad_inode(VFS_I(base_ni)); | ||
2434 | NVolSetErrors(vol); | ||
2435 | } else if (mp_rebuilt) { | ||
2436 | if (ntfs_attr_record_resize(m, a, attr_len)) { | ||
2437 | ntfs_error(vol->sb, "Failed to restore attribute " | ||
2438 | "record in error code path. Run " | ||
2439 | "chkdsk to recover."); | ||
2440 | make_bad_inode(vi); | ||
2441 | make_bad_inode(VFS_I(base_ni)); | ||
2442 | NVolSetErrors(vol); | ||
2443 | } else /* if (success) */ { | ||
2444 | if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( | ||
2445 | a->data.non_resident. | ||
2446 | mapping_pairs_offset), attr_len - | ||
2447 | le16_to_cpu(a->data.non_resident. | ||
2448 | mapping_pairs_offset), rl2, ll, -1, | ||
2449 | NULL)) { | ||
2450 | ntfs_error(vol->sb, "Failed to restore " | ||
2451 | "mapping pairs array in error " | ||
2452 | "code path. Run chkdsk to " | ||
2453 | "recover."); | ||
2454 | make_bad_inode(vi); | ||
2455 | make_bad_inode(VFS_I(base_ni)); | ||
2456 | NVolSetErrors(vol); | ||
2457 | } | ||
2458 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2459 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2460 | } | ||
2461 | } | ||
2462 | err_out: | ||
2463 | if (ctx) | ||
2464 | ntfs_attr_put_search_ctx(ctx); | ||
2465 | if (m) | ||
2466 | unmap_mft_record(base_ni); | ||
2467 | up_write(&ni->runlist.lock); | ||
2468 | conv_err_out: | ||
2469 | ntfs_debug("Failed. Returning error code %i.", err); | ||
2470 | return err; | ||
2471 | } | ||
2472 | |||
2473 | /** | ||
1655 | * ntfs_attr_set - fill (a part of) an attribute with a byte | 2474 | * ntfs_attr_set - fill (a part of) an attribute with a byte |
1656 | * @ni: ntfs inode describing the attribute to fill | 2475 | * @ni: ntfs inode describing the attribute to fill |
1657 | * @ofs: offset inside the attribute at which to start to fill | 2476 | * @ofs: offset inside the attribute at which to start to fill |
@@ -1773,6 +2592,8 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) | |||
1773 | /* Finally unlock and release the page. */ | 2592 | /* Finally unlock and release the page. */ |
1774 | unlock_page(page); | 2593 | unlock_page(page); |
1775 | page_cache_release(page); | 2594 | page_cache_release(page); |
2595 | balance_dirty_pages_ratelimited(mapping); | ||
2596 | cond_resched(); | ||
1776 | } | 2597 | } |
1777 | /* If there is a last partial page, need to do it the slow way. */ | 2598 | /* If there is a last partial page, need to do it the slow way. */ |
1778 | if (end_ofs) { | 2599 | if (end_ofs) { |
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h index 0618ed6fd7b3..9074886b44ba 100644 --- a/fs/ntfs/attrib.h +++ b/fs/ntfs/attrib.h | |||
@@ -60,14 +60,15 @@ typedef struct { | |||
60 | ATTR_RECORD *base_attr; | 60 | ATTR_RECORD *base_attr; |
61 | } ntfs_attr_search_ctx; | 61 | } ntfs_attr_search_ctx; |
62 | 62 | ||
63 | extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn); | 63 | extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, |
64 | ntfs_attr_search_ctx *ctx); | ||
64 | extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); | 65 | extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn); |
65 | 66 | ||
66 | extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, | 67 | extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, |
67 | const BOOL write_locked); | 68 | const BOOL write_locked); |
68 | 69 | ||
69 | extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, | 70 | extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, |
70 | const VCN vcn, const BOOL write_locked); | 71 | const VCN vcn, ntfs_attr_search_ctx *ctx); |
71 | 72 | ||
72 | int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, | 73 | int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, |
73 | const u32 name_len, const IGNORE_CASE_BOOL ic, | 74 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
@@ -102,7 +103,10 @@ extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size); | |||
102 | extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, | 103 | extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, |
103 | const u32 new_size); | 104 | const u32 new_size); |
104 | 105 | ||
105 | extern int ntfs_attr_make_non_resident(ntfs_inode *ni); | 106 | extern int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size); |
107 | |||
108 | extern s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, | ||
109 | const s64 new_data_size, const s64 data_start); | ||
106 | 110 | ||
107 | extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, | 111 | extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, |
108 | const u8 val); | 112 | const u8 val); |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index be9fd1dd423d..727533891813 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -19,11 +19,24 @@ | |||
19 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/pagemap.h> | ||
23 | #include <linux/buffer_head.h> | 22 | #include <linux/buffer_head.h> |
23 | #include <linux/pagemap.h> | ||
24 | #include <linux/pagevec.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/swap.h> | ||
27 | #include <linux/uio.h> | ||
28 | #include <linux/writeback.h> | ||
24 | 29 | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | |||
33 | #include "attrib.h" | ||
34 | #include "bitmap.h" | ||
25 | #include "inode.h" | 35 | #include "inode.h" |
26 | #include "debug.h" | 36 | #include "debug.h" |
37 | #include "lcnalloc.h" | ||
38 | #include "malloc.h" | ||
39 | #include "mft.h" | ||
27 | #include "ntfs.h" | 40 | #include "ntfs.h" |
28 | 41 | ||
29 | /** | 42 | /** |
@@ -56,6 +69,2185 @@ static int ntfs_file_open(struct inode *vi, struct file *filp) | |||
56 | #ifdef NTFS_RW | 69 | #ifdef NTFS_RW |
57 | 70 | ||
58 | /** | 71 | /** |
72 | * ntfs_attr_extend_initialized - extend the initialized size of an attribute | ||
73 | * @ni: ntfs inode of the attribute to extend | ||
74 | * @new_init_size: requested new initialized size in bytes | ||
75 | * @cached_page: store any allocated but unused page here | ||
76 | * @lru_pvec: lru-buffering pagevec of the caller | ||
77 | * | ||
78 | * Extend the initialized size of an attribute described by the ntfs inode @ni | ||
79 | * to @new_init_size bytes. This involves zeroing any non-sparse space between | ||
80 | * the old initialized size and @new_init_size both in the page cache and on | ||
81 | * disk (if relevant complete pages are already uptodate in the page cache then | ||
82 | * these are simply marked dirty). | ||
83 | * | ||
84 | * As a side-effect, the file size (vfs inode->i_size) may be incremented as, | ||
85 | * in the resident attribute case, it is tied to the initialized size and, in | ||
86 | * the non-resident attribute case, it may not fall below the initialized size. | ||
87 | * | ||
88 | * Note that if the attribute is resident, we do not need to touch the page | ||
89 | * cache at all. This is because if the page cache page is not uptodate we | ||
90 | * bring it uptodate later, when doing the write to the mft record since we | ||
91 | * then already have the page mapped. And if the page is uptodate, the | ||
92 | * non-initialized region will already have been zeroed when the page was | ||
93 | * brought uptodate and the region may in fact already have been overwritten | ||
94 | * with new data via mmap() based writes, so we cannot just zero it. And since | ||
95 | * POSIX specifies that the behaviour of resizing a file whilst it is mmap()ped | ||
96 | * is unspecified, we choose not to do zeroing and thus we do not need to touch | ||
97 | * the page at all. For a more detailed explanation see ntfs_truncate() in | ||
98 | * fs/ntfs/inode.c. | ||
99 | * | ||
100 | * @cached_page and @lru_pvec are just optimizations for dealing with multiple | ||
101 | * pages. | ||
102 | * | ||
103 | * Return 0 on success and -errno on error. In the case that an error is | ||
104 | * encountered it is possible that the initialized size will already have been | ||
105 | * incremented some way towards @new_init_size but it is guaranteed that if | ||
106 | * this is the case, the necessary zeroing will also have happened and that all | ||
107 | * metadata is self-consistent. | ||
108 | * | ||
109 | * Locking: i_sem on the vfs inode corrseponsind to the ntfs inode @ni must be | ||
110 | * held by the caller. | ||
111 | */ | ||
112 | static int ntfs_attr_extend_initialized(ntfs_inode *ni, const s64 new_init_size, | ||
113 | struct page **cached_page, struct pagevec *lru_pvec) | ||
114 | { | ||
115 | s64 old_init_size; | ||
116 | loff_t old_i_size; | ||
117 | pgoff_t index, end_index; | ||
118 | unsigned long flags; | ||
119 | struct inode *vi = VFS_I(ni); | ||
120 | ntfs_inode *base_ni; | ||
121 | MFT_RECORD *m = NULL; | ||
122 | ATTR_RECORD *a; | ||
123 | ntfs_attr_search_ctx *ctx = NULL; | ||
124 | struct address_space *mapping; | ||
125 | struct page *page = NULL; | ||
126 | u8 *kattr; | ||
127 | int err; | ||
128 | u32 attr_len; | ||
129 | |||
130 | read_lock_irqsave(&ni->size_lock, flags); | ||
131 | old_init_size = ni->initialized_size; | ||
132 | old_i_size = i_size_read(vi); | ||
133 | BUG_ON(new_init_size > ni->allocated_size); | ||
134 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
135 | ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " | ||
136 | "old_initialized_size 0x%llx, " | ||
137 | "new_initialized_size 0x%llx, i_size 0x%llx.", | ||
138 | vi->i_ino, (unsigned)le32_to_cpu(ni->type), | ||
139 | (unsigned long long)old_init_size, | ||
140 | (unsigned long long)new_init_size, old_i_size); | ||
141 | if (!NInoAttr(ni)) | ||
142 | base_ni = ni; | ||
143 | else | ||
144 | base_ni = ni->ext.base_ntfs_ino; | ||
145 | /* Use goto to reduce indentation and we need the label below anyway. */ | ||
146 | if (NInoNonResident(ni)) | ||
147 | goto do_non_resident_extend; | ||
148 | BUG_ON(old_init_size != old_i_size); | ||
149 | m = map_mft_record(base_ni); | ||
150 | if (IS_ERR(m)) { | ||
151 | err = PTR_ERR(m); | ||
152 | m = NULL; | ||
153 | goto err_out; | ||
154 | } | ||
155 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
156 | if (unlikely(!ctx)) { | ||
157 | err = -ENOMEM; | ||
158 | goto err_out; | ||
159 | } | ||
160 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
161 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
162 | if (unlikely(err)) { | ||
163 | if (err == -ENOENT) | ||
164 | err = -EIO; | ||
165 | goto err_out; | ||
166 | } | ||
167 | m = ctx->mrec; | ||
168 | a = ctx->attr; | ||
169 | BUG_ON(a->non_resident); | ||
170 | /* The total length of the attribute value. */ | ||
171 | attr_len = le32_to_cpu(a->data.resident.value_length); | ||
172 | BUG_ON(old_i_size != (loff_t)attr_len); | ||
173 | /* | ||
174 | * Do the zeroing in the mft record and update the attribute size in | ||
175 | * the mft record. | ||
176 | */ | ||
177 | kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); | ||
178 | memset(kattr + attr_len, 0, new_init_size - attr_len); | ||
179 | a->data.resident.value_length = cpu_to_le32((u32)new_init_size); | ||
180 | /* Finally, update the sizes in the vfs and ntfs inodes. */ | ||
181 | write_lock_irqsave(&ni->size_lock, flags); | ||
182 | i_size_write(vi, new_init_size); | ||
183 | ni->initialized_size = new_init_size; | ||
184 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
185 | goto done; | ||
186 | do_non_resident_extend: | ||
187 | /* | ||
188 | * If the new initialized size @new_init_size exceeds the current file | ||
189 | * size (vfs inode->i_size), we need to extend the file size to the | ||
190 | * new initialized size. | ||
191 | */ | ||
192 | if (new_init_size > old_i_size) { | ||
193 | m = map_mft_record(base_ni); | ||
194 | if (IS_ERR(m)) { | ||
195 | err = PTR_ERR(m); | ||
196 | m = NULL; | ||
197 | goto err_out; | ||
198 | } | ||
199 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
200 | if (unlikely(!ctx)) { | ||
201 | err = -ENOMEM; | ||
202 | goto err_out; | ||
203 | } | ||
204 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
205 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
206 | if (unlikely(err)) { | ||
207 | if (err == -ENOENT) | ||
208 | err = -EIO; | ||
209 | goto err_out; | ||
210 | } | ||
211 | m = ctx->mrec; | ||
212 | a = ctx->attr; | ||
213 | BUG_ON(!a->non_resident); | ||
214 | BUG_ON(old_i_size != (loff_t) | ||
215 | sle64_to_cpu(a->data.non_resident.data_size)); | ||
216 | a->data.non_resident.data_size = cpu_to_sle64(new_init_size); | ||
217 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
218 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
219 | /* Update the file size in the vfs inode. */ | ||
220 | i_size_write(vi, new_init_size); | ||
221 | ntfs_attr_put_search_ctx(ctx); | ||
222 | ctx = NULL; | ||
223 | unmap_mft_record(base_ni); | ||
224 | m = NULL; | ||
225 | } | ||
226 | mapping = vi->i_mapping; | ||
227 | index = old_init_size >> PAGE_CACHE_SHIFT; | ||
228 | end_index = (new_init_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
229 | do { | ||
230 | /* | ||
231 | * Read the page. If the page is not present, this will zero | ||
232 | * the uninitialized regions for us. | ||
233 | */ | ||
234 | page = read_cache_page(mapping, index, | ||
235 | (filler_t*)mapping->a_ops->readpage, NULL); | ||
236 | if (IS_ERR(page)) { | ||
237 | err = PTR_ERR(page); | ||
238 | goto init_err_out; | ||
239 | } | ||
240 | wait_on_page_locked(page); | ||
241 | if (unlikely(!PageUptodate(page) || PageError(page))) { | ||
242 | page_cache_release(page); | ||
243 | err = -EIO; | ||
244 | goto init_err_out; | ||
245 | } | ||
246 | /* | ||
247 | * Update the initialized size in the ntfs inode. This is | ||
248 | * enough to make ntfs_writepage() work. | ||
249 | */ | ||
250 | write_lock_irqsave(&ni->size_lock, flags); | ||
251 | ni->initialized_size = (index + 1) << PAGE_CACHE_SHIFT; | ||
252 | if (ni->initialized_size > new_init_size) | ||
253 | ni->initialized_size = new_init_size; | ||
254 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
255 | /* Set the page dirty so it gets written out. */ | ||
256 | set_page_dirty(page); | ||
257 | page_cache_release(page); | ||
258 | /* | ||
259 | * Play nice with the vm and the rest of the system. This is | ||
260 | * very much needed as we can potentially be modifying the | ||
261 | * initialised size from a very small value to a really huge | ||
262 | * value, e.g. | ||
263 | * f = open(somefile, O_TRUNC); | ||
264 | * truncate(f, 10GiB); | ||
265 | * seek(f, 10GiB); | ||
266 | * write(f, 1); | ||
267 | * And this would mean we would be marking dirty hundreds of | ||
268 | * thousands of pages or as in the above example more than | ||
269 | * two and a half million pages! | ||
270 | * | ||
271 | * TODO: For sparse pages could optimize this workload by using | ||
272 | * the FsMisc / MiscFs page bit as a "PageIsSparse" bit. This | ||
273 | * would be set in readpage for sparse pages and here we would | ||
274 | * not need to mark dirty any pages which have this bit set. | ||
275 | * The only caveat is that we have to clear the bit everywhere | ||
276 | * where we allocate any clusters that lie in the page or that | ||
277 | * contain the page. | ||
278 | * | ||
279 | * TODO: An even greater optimization would be for us to only | ||
280 | * call readpage() on pages which are not in sparse regions as | ||
281 | * determined from the runlist. This would greatly reduce the | ||
282 | * number of pages we read and make dirty in the case of sparse | ||
283 | * files. | ||
284 | */ | ||
285 | balance_dirty_pages_ratelimited(mapping); | ||
286 | cond_resched(); | ||
287 | } while (++index < end_index); | ||
288 | read_lock_irqsave(&ni->size_lock, flags); | ||
289 | BUG_ON(ni->initialized_size != new_init_size); | ||
290 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
291 | /* Now bring in sync the initialized_size in the mft record. */ | ||
292 | m = map_mft_record(base_ni); | ||
293 | if (IS_ERR(m)) { | ||
294 | err = PTR_ERR(m); | ||
295 | m = NULL; | ||
296 | goto init_err_out; | ||
297 | } | ||
298 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
299 | if (unlikely(!ctx)) { | ||
300 | err = -ENOMEM; | ||
301 | goto init_err_out; | ||
302 | } | ||
303 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
304 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
305 | if (unlikely(err)) { | ||
306 | if (err == -ENOENT) | ||
307 | err = -EIO; | ||
308 | goto init_err_out; | ||
309 | } | ||
310 | m = ctx->mrec; | ||
311 | a = ctx->attr; | ||
312 | BUG_ON(!a->non_resident); | ||
313 | a->data.non_resident.initialized_size = cpu_to_sle64(new_init_size); | ||
314 | done: | ||
315 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
316 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
317 | if (ctx) | ||
318 | ntfs_attr_put_search_ctx(ctx); | ||
319 | if (m) | ||
320 | unmap_mft_record(base_ni); | ||
321 | ntfs_debug("Done, initialized_size 0x%llx, i_size 0x%llx.", | ||
322 | (unsigned long long)new_init_size, i_size_read(vi)); | ||
323 | return 0; | ||
324 | init_err_out: | ||
325 | write_lock_irqsave(&ni->size_lock, flags); | ||
326 | ni->initialized_size = old_init_size; | ||
327 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
328 | err_out: | ||
329 | if (ctx) | ||
330 | ntfs_attr_put_search_ctx(ctx); | ||
331 | if (m) | ||
332 | unmap_mft_record(base_ni); | ||
333 | ntfs_debug("Failed. Returning error code %i.", err); | ||
334 | return err; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * ntfs_fault_in_pages_readable - | ||
339 | * | ||
340 | * Fault a number of userspace pages into pagetables. | ||
341 | * | ||
342 | * Unlike include/linux/pagemap.h::fault_in_pages_readable(), this one copes | ||
343 | * with more than two userspace pages as well as handling the single page case | ||
344 | * elegantly. | ||
345 | * | ||
346 | * If you find this difficult to understand, then think of the while loop being | ||
347 | * the following code, except that we do without the integer variable ret: | ||
348 | * | ||
349 | * do { | ||
350 | * ret = __get_user(c, uaddr); | ||
351 | * uaddr += PAGE_SIZE; | ||
352 | * } while (!ret && uaddr < end); | ||
353 | * | ||
354 | * Note, the final __get_user() may well run out-of-bounds of the user buffer, | ||
355 | * but _not_ out-of-bounds of the page the user buffer belongs to, and since | ||
356 | * this is only a read and not a write, and since it is still in the same page, | ||
357 | * it should not matter and this makes the code much simpler. | ||
358 | */ | ||
359 | static inline void ntfs_fault_in_pages_readable(const char __user *uaddr, | ||
360 | int bytes) | ||
361 | { | ||
362 | const char __user *end; | ||
363 | volatile char c; | ||
364 | |||
365 | /* Set @end to the first byte outside the last page we care about. */ | ||
366 | end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes); | ||
367 | |||
368 | while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end)) | ||
369 | ; | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * ntfs_fault_in_pages_readable_iovec - | ||
374 | * | ||
375 | * Same as ntfs_fault_in_pages_readable() but operates on an array of iovecs. | ||
376 | */ | ||
377 | static inline void ntfs_fault_in_pages_readable_iovec(const struct iovec *iov, | ||
378 | size_t iov_ofs, int bytes) | ||
379 | { | ||
380 | do { | ||
381 | const char __user *buf; | ||
382 | unsigned len; | ||
383 | |||
384 | buf = iov->iov_base + iov_ofs; | ||
385 | len = iov->iov_len - iov_ofs; | ||
386 | if (len > bytes) | ||
387 | len = bytes; | ||
388 | ntfs_fault_in_pages_readable(buf, len); | ||
389 | bytes -= len; | ||
390 | iov++; | ||
391 | iov_ofs = 0; | ||
392 | } while (bytes); | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * __ntfs_grab_cache_pages - obtain a number of locked pages | ||
397 | * @mapping: address space mapping from which to obtain page cache pages | ||
398 | * @index: starting index in @mapping at which to begin obtaining pages | ||
399 | * @nr_pages: number of page cache pages to obtain | ||
400 | * @pages: array of pages in which to return the obtained page cache pages | ||
401 | * @cached_page: allocated but as yet unused page | ||
402 | * @lru_pvec: lru-buffering pagevec of caller | ||
403 | * | ||
404 | * Obtain @nr_pages locked page cache pages from the mapping @maping and | ||
405 | * starting at index @index. | ||
406 | * | ||
407 | * If a page is newly created, increment its refcount and add it to the | ||
408 | * caller's lru-buffering pagevec @lru_pvec. | ||
409 | * | ||
410 | * This is the same as mm/filemap.c::__grab_cache_page(), except that @nr_pages | ||
411 | * are obtained at once instead of just one page and that 0 is returned on | ||
412 | * success and -errno on error. | ||
413 | * | ||
414 | * Note, the page locks are obtained in ascending page index order. | ||
415 | */ | ||
416 | static inline int __ntfs_grab_cache_pages(struct address_space *mapping, | ||
417 | pgoff_t index, const unsigned nr_pages, struct page **pages, | ||
418 | struct page **cached_page, struct pagevec *lru_pvec) | ||
419 | { | ||
420 | int err, nr; | ||
421 | |||
422 | BUG_ON(!nr_pages); | ||
423 | err = nr = 0; | ||
424 | do { | ||
425 | pages[nr] = find_lock_page(mapping, index); | ||
426 | if (!pages[nr]) { | ||
427 | if (!*cached_page) { | ||
428 | *cached_page = page_cache_alloc(mapping); | ||
429 | if (unlikely(!*cached_page)) { | ||
430 | err = -ENOMEM; | ||
431 | goto err_out; | ||
432 | } | ||
433 | } | ||
434 | err = add_to_page_cache(*cached_page, mapping, index, | ||
435 | GFP_KERNEL); | ||
436 | if (unlikely(err)) { | ||
437 | if (err == -EEXIST) | ||
438 | continue; | ||
439 | goto err_out; | ||
440 | } | ||
441 | pages[nr] = *cached_page; | ||
442 | page_cache_get(*cached_page); | ||
443 | if (unlikely(!pagevec_add(lru_pvec, *cached_page))) | ||
444 | __pagevec_lru_add(lru_pvec); | ||
445 | *cached_page = NULL; | ||
446 | } | ||
447 | index++; | ||
448 | nr++; | ||
449 | } while (nr < nr_pages); | ||
450 | out: | ||
451 | return err; | ||
452 | err_out: | ||
453 | while (nr > 0) { | ||
454 | unlock_page(pages[--nr]); | ||
455 | page_cache_release(pages[nr]); | ||
456 | } | ||
457 | goto out; | ||
458 | } | ||
459 | |||
460 | static inline int ntfs_submit_bh_for_read(struct buffer_head *bh) | ||
461 | { | ||
462 | lock_buffer(bh); | ||
463 | get_bh(bh); | ||
464 | bh->b_end_io = end_buffer_read_sync; | ||
465 | return submit_bh(READ, bh); | ||
466 | } | ||
467 | |||
468 | /** | ||
469 | * ntfs_prepare_pages_for_non_resident_write - prepare pages for receiving data | ||
470 | * @pages: array of destination pages | ||
471 | * @nr_pages: number of pages in @pages | ||
472 | * @pos: byte position in file at which the write begins | ||
473 | * @bytes: number of bytes to be written | ||
474 | * | ||
475 | * This is called for non-resident attributes from ntfs_file_buffered_write() | ||
476 | * with i_sem held on the inode (@pages[0]->mapping->host). There are | ||
477 | * @nr_pages pages in @pages which are locked but not kmap()ped. The source | ||
478 | * data has not yet been copied into the @pages. | ||
479 | * | ||
480 | * Need to fill any holes with actual clusters, allocate buffers if necessary, | ||
481 | * ensure all the buffers are mapped, and bring uptodate any buffers that are | ||
482 | * only partially being written to. | ||
483 | * | ||
484 | * If @nr_pages is greater than one, we are guaranteed that the cluster size is | ||
485 | * greater than PAGE_CACHE_SIZE, that all pages in @pages are entirely inside | ||
486 | * the same cluster and that they are the entirety of that cluster, and that | ||
487 | * the cluster is sparse, i.e. we need to allocate a cluster to fill the hole. | ||
488 | * | ||
489 | * i_size is not to be modified yet. | ||
490 | * | ||
491 | * Return 0 on success or -errno on error. | ||
492 | */ | ||
493 | static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, | ||
494 | unsigned nr_pages, s64 pos, size_t bytes) | ||
495 | { | ||
496 | VCN vcn, highest_vcn = 0, cpos, cend, bh_cpos, bh_cend; | ||
497 | LCN lcn; | ||
498 | s64 bh_pos, vcn_len, end, initialized_size; | ||
499 | sector_t lcn_block; | ||
500 | struct page *page; | ||
501 | struct inode *vi; | ||
502 | ntfs_inode *ni, *base_ni = NULL; | ||
503 | ntfs_volume *vol; | ||
504 | runlist_element *rl, *rl2; | ||
505 | struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; | ||
506 | ntfs_attr_search_ctx *ctx = NULL; | ||
507 | MFT_RECORD *m = NULL; | ||
508 | ATTR_RECORD *a = NULL; | ||
509 | unsigned long flags; | ||
510 | u32 attr_rec_len = 0; | ||
511 | unsigned blocksize, u; | ||
512 | int err, mp_size; | ||
513 | BOOL rl_write_locked, was_hole, is_retry; | ||
514 | unsigned char blocksize_bits; | ||
515 | struct { | ||
516 | u8 runlist_merged:1; | ||
517 | u8 mft_attr_mapped:1; | ||
518 | u8 mp_rebuilt:1; | ||
519 | u8 attr_switched:1; | ||
520 | } status = { 0, 0, 0, 0 }; | ||
521 | |||
522 | BUG_ON(!nr_pages); | ||
523 | BUG_ON(!pages); | ||
524 | BUG_ON(!*pages); | ||
525 | vi = pages[0]->mapping->host; | ||
526 | ni = NTFS_I(vi); | ||
527 | vol = ni->vol; | ||
528 | ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page " | ||
529 | "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.", | ||
530 | vi->i_ino, ni->type, pages[0]->index, nr_pages, | ||
531 | (long long)pos, bytes); | ||
532 | blocksize_bits = vi->i_blkbits; | ||
533 | blocksize = 1 << blocksize_bits; | ||
534 | u = 0; | ||
535 | do { | ||
536 | struct page *page = pages[u]; | ||
537 | /* | ||
538 | * create_empty_buffers() will create uptodate/dirty buffers if | ||
539 | * the page is uptodate/dirty. | ||
540 | */ | ||
541 | if (!page_has_buffers(page)) { | ||
542 | create_empty_buffers(page, blocksize, 0); | ||
543 | if (unlikely(!page_has_buffers(page))) | ||
544 | return -ENOMEM; | ||
545 | } | ||
546 | } while (++u < nr_pages); | ||
547 | rl_write_locked = FALSE; | ||
548 | rl = NULL; | ||
549 | err = 0; | ||
550 | vcn = lcn = -1; | ||
551 | vcn_len = 0; | ||
552 | lcn_block = -1; | ||
553 | was_hole = FALSE; | ||
554 | cpos = pos >> vol->cluster_size_bits; | ||
555 | end = pos + bytes; | ||
556 | cend = (end + vol->cluster_size - 1) >> vol->cluster_size_bits; | ||
557 | /* | ||
558 | * Loop over each page and for each page over each buffer. Use goto to | ||
559 | * reduce indentation. | ||
560 | */ | ||
561 | u = 0; | ||
562 | do_next_page: | ||
563 | page = pages[u]; | ||
564 | bh_pos = (s64)page->index << PAGE_CACHE_SHIFT; | ||
565 | bh = head = page_buffers(page); | ||
566 | do { | ||
567 | VCN cdelta; | ||
568 | s64 bh_end; | ||
569 | unsigned bh_cofs; | ||
570 | |||
571 | /* Clear buffer_new on all buffers to reinitialise state. */ | ||
572 | if (buffer_new(bh)) | ||
573 | clear_buffer_new(bh); | ||
574 | bh_end = bh_pos + blocksize; | ||
575 | bh_cpos = bh_pos >> vol->cluster_size_bits; | ||
576 | bh_cofs = bh_pos & vol->cluster_size_mask; | ||
577 | if (buffer_mapped(bh)) { | ||
578 | /* | ||
579 | * The buffer is already mapped. If it is uptodate, | ||
580 | * ignore it. | ||
581 | */ | ||
582 | if (buffer_uptodate(bh)) | ||
583 | continue; | ||
584 | /* | ||
585 | * The buffer is not uptodate. If the page is uptodate | ||
586 | * set the buffer uptodate and otherwise ignore it. | ||
587 | */ | ||
588 | if (PageUptodate(page)) { | ||
589 | set_buffer_uptodate(bh); | ||
590 | continue; | ||
591 | } | ||
592 | /* | ||
593 | * Neither the page nor the buffer are uptodate. If | ||
594 | * the buffer is only partially being written to, we | ||
595 | * need to read it in before the write, i.e. now. | ||
596 | */ | ||
597 | if ((bh_pos < pos && bh_end > pos) || | ||
598 | (bh_pos < end && bh_end > end)) { | ||
599 | /* | ||
600 | * If the buffer is fully or partially within | ||
601 | * the initialized size, do an actual read. | ||
602 | * Otherwise, simply zero the buffer. | ||
603 | */ | ||
604 | read_lock_irqsave(&ni->size_lock, flags); | ||
605 | initialized_size = ni->initialized_size; | ||
606 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
607 | if (bh_pos < initialized_size) { | ||
608 | ntfs_submit_bh_for_read(bh); | ||
609 | *wait_bh++ = bh; | ||
610 | } else { | ||
611 | u8 *kaddr = kmap_atomic(page, KM_USER0); | ||
612 | memset(kaddr + bh_offset(bh), 0, | ||
613 | blocksize); | ||
614 | kunmap_atomic(kaddr, KM_USER0); | ||
615 | flush_dcache_page(page); | ||
616 | set_buffer_uptodate(bh); | ||
617 | } | ||
618 | } | ||
619 | continue; | ||
620 | } | ||
621 | /* Unmapped buffer. Need to map it. */ | ||
622 | bh->b_bdev = vol->sb->s_bdev; | ||
623 | /* | ||
624 | * If the current buffer is in the same clusters as the map | ||
625 | * cache, there is no need to check the runlist again. The | ||
626 | * map cache is made up of @vcn, which is the first cached file | ||
627 | * cluster, @vcn_len which is the number of cached file | ||
628 | * clusters, @lcn is the device cluster corresponding to @vcn, | ||
629 | * and @lcn_block is the block number corresponding to @lcn. | ||
630 | */ | ||
631 | cdelta = bh_cpos - vcn; | ||
632 | if (likely(!cdelta || (cdelta > 0 && cdelta < vcn_len))) { | ||
633 | map_buffer_cached: | ||
634 | BUG_ON(lcn < 0); | ||
635 | bh->b_blocknr = lcn_block + | ||
636 | (cdelta << (vol->cluster_size_bits - | ||
637 | blocksize_bits)) + | ||
638 | (bh_cofs >> blocksize_bits); | ||
639 | set_buffer_mapped(bh); | ||
640 | /* | ||
641 | * If the page is uptodate so is the buffer. If the | ||
642 | * buffer is fully outside the write, we ignore it if | ||
643 | * it was already allocated and we mark it dirty so it | ||
644 | * gets written out if we allocated it. On the other | ||
645 | * hand, if we allocated the buffer but we are not | ||
646 | * marking it dirty we set buffer_new so we can do | ||
647 | * error recovery. | ||
648 | */ | ||
649 | if (PageUptodate(page)) { | ||
650 | if (!buffer_uptodate(bh)) | ||
651 | set_buffer_uptodate(bh); | ||
652 | if (unlikely(was_hole)) { | ||
653 | /* We allocated the buffer. */ | ||
654 | unmap_underlying_metadata(bh->b_bdev, | ||
655 | bh->b_blocknr); | ||
656 | if (bh_end <= pos || bh_pos >= end) | ||
657 | mark_buffer_dirty(bh); | ||
658 | else | ||
659 | set_buffer_new(bh); | ||
660 | } | ||
661 | continue; | ||
662 | } | ||
663 | /* Page is _not_ uptodate. */ | ||
664 | if (likely(!was_hole)) { | ||
665 | /* | ||
666 | * Buffer was already allocated. If it is not | ||
667 | * uptodate and is only partially being written | ||
668 | * to, we need to read it in before the write, | ||
669 | * i.e. now. | ||
670 | */ | ||
671 | if (!buffer_uptodate(bh) && bh_pos < end && | ||
672 | bh_end > pos && | ||
673 | (bh_pos < pos || | ||
674 | bh_end > end)) { | ||
675 | /* | ||
676 | * If the buffer is fully or partially | ||
677 | * within the initialized size, do an | ||
678 | * actual read. Otherwise, simply zero | ||
679 | * the buffer. | ||
680 | */ | ||
681 | read_lock_irqsave(&ni->size_lock, | ||
682 | flags); | ||
683 | initialized_size = ni->initialized_size; | ||
684 | read_unlock_irqrestore(&ni->size_lock, | ||
685 | flags); | ||
686 | if (bh_pos < initialized_size) { | ||
687 | ntfs_submit_bh_for_read(bh); | ||
688 | *wait_bh++ = bh; | ||
689 | } else { | ||
690 | u8 *kaddr = kmap_atomic(page, | ||
691 | KM_USER0); | ||
692 | memset(kaddr + bh_offset(bh), | ||
693 | 0, blocksize); | ||
694 | kunmap_atomic(kaddr, KM_USER0); | ||
695 | flush_dcache_page(page); | ||
696 | set_buffer_uptodate(bh); | ||
697 | } | ||
698 | } | ||
699 | continue; | ||
700 | } | ||
701 | /* We allocated the buffer. */ | ||
702 | unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); | ||
703 | /* | ||
704 | * If the buffer is fully outside the write, zero it, | ||
705 | * set it uptodate, and mark it dirty so it gets | ||
706 | * written out. If it is partially being written to, | ||
707 | * zero region surrounding the write but leave it to | ||
708 | * commit write to do anything else. Finally, if the | ||
709 | * buffer is fully being overwritten, do nothing. | ||
710 | */ | ||
711 | if (bh_end <= pos || bh_pos >= end) { | ||
712 | if (!buffer_uptodate(bh)) { | ||
713 | u8 *kaddr = kmap_atomic(page, KM_USER0); | ||
714 | memset(kaddr + bh_offset(bh), 0, | ||
715 | blocksize); | ||
716 | kunmap_atomic(kaddr, KM_USER0); | ||
717 | flush_dcache_page(page); | ||
718 | set_buffer_uptodate(bh); | ||
719 | } | ||
720 | mark_buffer_dirty(bh); | ||
721 | continue; | ||
722 | } | ||
723 | set_buffer_new(bh); | ||
724 | if (!buffer_uptodate(bh) && | ||
725 | (bh_pos < pos || bh_end > end)) { | ||
726 | u8 *kaddr; | ||
727 | unsigned pofs; | ||
728 | |||
729 | kaddr = kmap_atomic(page, KM_USER0); | ||
730 | if (bh_pos < pos) { | ||
731 | pofs = bh_pos & ~PAGE_CACHE_MASK; | ||
732 | memset(kaddr + pofs, 0, pos - bh_pos); | ||
733 | } | ||
734 | if (bh_end > end) { | ||
735 | pofs = end & ~PAGE_CACHE_MASK; | ||
736 | memset(kaddr + pofs, 0, bh_end - end); | ||
737 | } | ||
738 | kunmap_atomic(kaddr, KM_USER0); | ||
739 | flush_dcache_page(page); | ||
740 | } | ||
741 | continue; | ||
742 | } | ||
743 | /* | ||
744 | * Slow path: this is the first buffer in the cluster. If it | ||
745 | * is outside allocated size and is not uptodate, zero it and | ||
746 | * set it uptodate. | ||
747 | */ | ||
748 | read_lock_irqsave(&ni->size_lock, flags); | ||
749 | initialized_size = ni->allocated_size; | ||
750 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
751 | if (bh_pos > initialized_size) { | ||
752 | if (PageUptodate(page)) { | ||
753 | if (!buffer_uptodate(bh)) | ||
754 | set_buffer_uptodate(bh); | ||
755 | } else if (!buffer_uptodate(bh)) { | ||
756 | u8 *kaddr = kmap_atomic(page, KM_USER0); | ||
757 | memset(kaddr + bh_offset(bh), 0, blocksize); | ||
758 | kunmap_atomic(kaddr, KM_USER0); | ||
759 | flush_dcache_page(page); | ||
760 | set_buffer_uptodate(bh); | ||
761 | } | ||
762 | continue; | ||
763 | } | ||
764 | is_retry = FALSE; | ||
765 | if (!rl) { | ||
766 | down_read(&ni->runlist.lock); | ||
767 | retry_remap: | ||
768 | rl = ni->runlist.rl; | ||
769 | } | ||
770 | if (likely(rl != NULL)) { | ||
771 | /* Seek to element containing target cluster. */ | ||
772 | while (rl->length && rl[1].vcn <= bh_cpos) | ||
773 | rl++; | ||
774 | lcn = ntfs_rl_vcn_to_lcn(rl, bh_cpos); | ||
775 | if (likely(lcn >= 0)) { | ||
776 | /* | ||
777 | * Successful remap, setup the map cache and | ||
778 | * use that to deal with the buffer. | ||
779 | */ | ||
780 | was_hole = FALSE; | ||
781 | vcn = bh_cpos; | ||
782 | vcn_len = rl[1].vcn - vcn; | ||
783 | lcn_block = lcn << (vol->cluster_size_bits - | ||
784 | blocksize_bits); | ||
785 | cdelta = 0; | ||
786 | /* | ||
787 | * If the number of remaining clusters touched | ||
788 | * by the write is smaller or equal to the | ||
789 | * number of cached clusters, unlock the | ||
790 | * runlist as the map cache will be used from | ||
791 | * now on. | ||
792 | */ | ||
793 | if (likely(vcn + vcn_len >= cend)) { | ||
794 | if (rl_write_locked) { | ||
795 | up_write(&ni->runlist.lock); | ||
796 | rl_write_locked = FALSE; | ||
797 | } else | ||
798 | up_read(&ni->runlist.lock); | ||
799 | rl = NULL; | ||
800 | } | ||
801 | goto map_buffer_cached; | ||
802 | } | ||
803 | } else | ||
804 | lcn = LCN_RL_NOT_MAPPED; | ||
805 | /* | ||
806 | * If it is not a hole and not out of bounds, the runlist is | ||
807 | * probably unmapped so try to map it now. | ||
808 | */ | ||
809 | if (unlikely(lcn != LCN_HOLE && lcn != LCN_ENOENT)) { | ||
810 | if (likely(!is_retry && lcn == LCN_RL_NOT_MAPPED)) { | ||
811 | /* Attempt to map runlist. */ | ||
812 | if (!rl_write_locked) { | ||
813 | /* | ||
814 | * We need the runlist locked for | ||
815 | * writing, so if it is locked for | ||
816 | * reading relock it now and retry in | ||
817 | * case it changed whilst we dropped | ||
818 | * the lock. | ||
819 | */ | ||
820 | up_read(&ni->runlist.lock); | ||
821 | down_write(&ni->runlist.lock); | ||
822 | rl_write_locked = TRUE; | ||
823 | goto retry_remap; | ||
824 | } | ||
825 | err = ntfs_map_runlist_nolock(ni, bh_cpos, | ||
826 | NULL); | ||
827 | if (likely(!err)) { | ||
828 | is_retry = TRUE; | ||
829 | goto retry_remap; | ||
830 | } | ||
831 | /* | ||
832 | * If @vcn is out of bounds, pretend @lcn is | ||
833 | * LCN_ENOENT. As long as the buffer is out | ||
834 | * of bounds this will work fine. | ||
835 | */ | ||
836 | if (err == -ENOENT) { | ||
837 | lcn = LCN_ENOENT; | ||
838 | err = 0; | ||
839 | goto rl_not_mapped_enoent; | ||
840 | } | ||
841 | } else | ||
842 | err = -EIO; | ||
843 | /* Failed to map the buffer, even after retrying. */ | ||
844 | bh->b_blocknr = -1; | ||
845 | ntfs_error(vol->sb, "Failed to write to inode 0x%lx, " | ||
846 | "attribute type 0x%x, vcn 0x%llx, " | ||
847 | "vcn offset 0x%x, because its " | ||
848 | "location on disk could not be " | ||
849 | "determined%s (error code %i).", | ||
850 | ni->mft_no, ni->type, | ||
851 | (unsigned long long)bh_cpos, | ||
852 | (unsigned)bh_pos & | ||
853 | vol->cluster_size_mask, | ||
854 | is_retry ? " even after retrying" : "", | ||
855 | err); | ||
856 | break; | ||
857 | } | ||
858 | rl_not_mapped_enoent: | ||
859 | /* | ||
860 | * The buffer is in a hole or out of bounds. We need to fill | ||
861 | * the hole, unless the buffer is in a cluster which is not | ||
862 | * touched by the write, in which case we just leave the buffer | ||
863 | * unmapped. This can only happen when the cluster size is | ||
864 | * less than the page cache size. | ||
865 | */ | ||
866 | if (unlikely(vol->cluster_size < PAGE_CACHE_SIZE)) { | ||
867 | bh_cend = (bh_end + vol->cluster_size - 1) >> | ||
868 | vol->cluster_size_bits; | ||
869 | if ((bh_cend <= cpos || bh_cpos >= cend)) { | ||
870 | bh->b_blocknr = -1; | ||
871 | /* | ||
872 | * If the buffer is uptodate we skip it. If it | ||
873 | * is not but the page is uptodate, we can set | ||
874 | * the buffer uptodate. If the page is not | ||
875 | * uptodate, we can clear the buffer and set it | ||
876 | * uptodate. Whether this is worthwhile is | ||
877 | * debatable and this could be removed. | ||
878 | */ | ||
879 | if (PageUptodate(page)) { | ||
880 | if (!buffer_uptodate(bh)) | ||
881 | set_buffer_uptodate(bh); | ||
882 | } else if (!buffer_uptodate(bh)) { | ||
883 | u8 *kaddr = kmap_atomic(page, KM_USER0); | ||
884 | memset(kaddr + bh_offset(bh), 0, | ||
885 | blocksize); | ||
886 | kunmap_atomic(kaddr, KM_USER0); | ||
887 | flush_dcache_page(page); | ||
888 | set_buffer_uptodate(bh); | ||
889 | } | ||
890 | continue; | ||
891 | } | ||
892 | } | ||
893 | /* | ||
894 | * Out of bounds buffer is invalid if it was not really out of | ||
895 | * bounds. | ||
896 | */ | ||
897 | BUG_ON(lcn != LCN_HOLE); | ||
898 | /* | ||
899 | * We need the runlist locked for writing, so if it is locked | ||
900 | * for reading relock it now and retry in case it changed | ||
901 | * whilst we dropped the lock. | ||
902 | */ | ||
903 | BUG_ON(!rl); | ||
904 | if (!rl_write_locked) { | ||
905 | up_read(&ni->runlist.lock); | ||
906 | down_write(&ni->runlist.lock); | ||
907 | rl_write_locked = TRUE; | ||
908 | goto retry_remap; | ||
909 | } | ||
910 | /* Find the previous last allocated cluster. */ | ||
911 | BUG_ON(rl->lcn != LCN_HOLE); | ||
912 | lcn = -1; | ||
913 | rl2 = rl; | ||
914 | while (--rl2 >= ni->runlist.rl) { | ||
915 | if (rl2->lcn >= 0) { | ||
916 | lcn = rl2->lcn + rl2->length; | ||
917 | break; | ||
918 | } | ||
919 | } | ||
920 | rl2 = ntfs_cluster_alloc(vol, bh_cpos, 1, lcn, DATA_ZONE, | ||
921 | FALSE); | ||
922 | if (IS_ERR(rl2)) { | ||
923 | err = PTR_ERR(rl2); | ||
924 | ntfs_debug("Failed to allocate cluster, error code %i.", | ||
925 | err); | ||
926 | break; | ||
927 | } | ||
928 | lcn = rl2->lcn; | ||
929 | rl = ntfs_runlists_merge(ni->runlist.rl, rl2); | ||
930 | if (IS_ERR(rl)) { | ||
931 | err = PTR_ERR(rl); | ||
932 | if (err != -ENOMEM) | ||
933 | err = -EIO; | ||
934 | if (ntfs_cluster_free_from_rl(vol, rl2)) { | ||
935 | ntfs_error(vol->sb, "Failed to release " | ||
936 | "allocated cluster in error " | ||
937 | "code path. Run chkdsk to " | ||
938 | "recover the lost cluster."); | ||
939 | NVolSetErrors(vol); | ||
940 | } | ||
941 | ntfs_free(rl2); | ||
942 | break; | ||
943 | } | ||
944 | ni->runlist.rl = rl; | ||
945 | status.runlist_merged = 1; | ||
946 | ntfs_debug("Allocated cluster, lcn 0x%llx.", lcn); | ||
947 | /* Map and lock the mft record and get the attribute record. */ | ||
948 | if (!NInoAttr(ni)) | ||
949 | base_ni = ni; | ||
950 | else | ||
951 | base_ni = ni->ext.base_ntfs_ino; | ||
952 | m = map_mft_record(base_ni); | ||
953 | if (IS_ERR(m)) { | ||
954 | err = PTR_ERR(m); | ||
955 | break; | ||
956 | } | ||
957 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
958 | if (unlikely(!ctx)) { | ||
959 | err = -ENOMEM; | ||
960 | unmap_mft_record(base_ni); | ||
961 | break; | ||
962 | } | ||
963 | status.mft_attr_mapped = 1; | ||
964 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
965 | CASE_SENSITIVE, bh_cpos, NULL, 0, ctx); | ||
966 | if (unlikely(err)) { | ||
967 | if (err == -ENOENT) | ||
968 | err = -EIO; | ||
969 | break; | ||
970 | } | ||
971 | m = ctx->mrec; | ||
972 | a = ctx->attr; | ||
973 | /* | ||
974 | * Find the runlist element with which the attribute extent | ||
975 | * starts. Note, we cannot use the _attr_ version because we | ||
976 | * have mapped the mft record. That is ok because we know the | ||
977 | * runlist fragment must be mapped already to have ever gotten | ||
978 | * here, so we can just use the _rl_ version. | ||
979 | */ | ||
980 | vcn = sle64_to_cpu(a->data.non_resident.lowest_vcn); | ||
981 | rl2 = ntfs_rl_find_vcn_nolock(rl, vcn); | ||
982 | BUG_ON(!rl2); | ||
983 | BUG_ON(!rl2->length); | ||
984 | BUG_ON(rl2->lcn < LCN_HOLE); | ||
985 | highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); | ||
986 | /* | ||
987 | * If @highest_vcn is zero, calculate the real highest_vcn | ||
988 | * (which can really be zero). | ||
989 | */ | ||
990 | if (!highest_vcn) | ||
991 | highest_vcn = (sle64_to_cpu( | ||
992 | a->data.non_resident.allocated_size) >> | ||
993 | vol->cluster_size_bits) - 1; | ||
994 | /* | ||
995 | * Determine the size of the mapping pairs array for the new | ||
996 | * extent, i.e. the old extent with the hole filled. | ||
997 | */ | ||
998 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, vcn, | ||
999 | highest_vcn); | ||
1000 | if (unlikely(mp_size <= 0)) { | ||
1001 | if (!(err = mp_size)) | ||
1002 | err = -EIO; | ||
1003 | ntfs_debug("Failed to get size for mapping pairs " | ||
1004 | "array, error code %i.", err); | ||
1005 | break; | ||
1006 | } | ||
1007 | /* | ||
1008 | * Resize the attribute record to fit the new mapping pairs | ||
1009 | * array. | ||
1010 | */ | ||
1011 | attr_rec_len = le32_to_cpu(a->length); | ||
1012 | err = ntfs_attr_record_resize(m, a, mp_size + le16_to_cpu( | ||
1013 | a->data.non_resident.mapping_pairs_offset)); | ||
1014 | if (unlikely(err)) { | ||
1015 | BUG_ON(err != -ENOSPC); | ||
1016 | // TODO: Deal with this by using the current attribute | ||
1017 | // and fill it with as much of the mapping pairs | ||
1018 | // array as possible. Then loop over each attribute | ||
1019 | // extent rewriting the mapping pairs arrays as we go | ||
1020 | // along and if when we reach the end we have not | ||
1021 | // enough space, try to resize the last attribute | ||
1022 | // extent and if even that fails, add a new attribute | ||
1023 | // extent. | ||
1024 | // We could also try to resize at each step in the hope | ||
1025 | // that we will not need to rewrite every single extent. | ||
1026 | // Note, we may need to decompress some extents to fill | ||
1027 | // the runlist as we are walking the extents... | ||
1028 | ntfs_error(vol->sb, "Not enough space in the mft " | ||
1029 | "record for the extended attribute " | ||
1030 | "record. This case is not " | ||
1031 | "implemented yet."); | ||
1032 | err = -EOPNOTSUPP; | ||
1033 | break ; | ||
1034 | } | ||
1035 | status.mp_rebuilt = 1; | ||
1036 | /* | ||
1037 | * Generate the mapping pairs array directly into the attribute | ||
1038 | * record. | ||
1039 | */ | ||
1040 | err = ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( | ||
1041 | a->data.non_resident.mapping_pairs_offset), | ||
1042 | mp_size, rl2, vcn, highest_vcn, NULL); | ||
1043 | if (unlikely(err)) { | ||
1044 | ntfs_error(vol->sb, "Cannot fill hole in inode 0x%lx, " | ||
1045 | "attribute type 0x%x, because building " | ||
1046 | "the mapping pairs failed with error " | ||
1047 | "code %i.", vi->i_ino, | ||
1048 | (unsigned)le32_to_cpu(ni->type), err); | ||
1049 | err = -EIO; | ||
1050 | break; | ||
1051 | } | ||
1052 | /* Update the highest_vcn but only if it was not set. */ | ||
1053 | if (unlikely(!a->data.non_resident.highest_vcn)) | ||
1054 | a->data.non_resident.highest_vcn = | ||
1055 | cpu_to_sle64(highest_vcn); | ||
1056 | /* | ||
1057 | * If the attribute is sparse/compressed, update the compressed | ||
1058 | * size in the ntfs_inode structure and the attribute record. | ||
1059 | */ | ||
1060 | if (likely(NInoSparse(ni) || NInoCompressed(ni))) { | ||
1061 | /* | ||
1062 | * If we are not in the first attribute extent, switch | ||
1063 | * to it, but first ensure the changes will make it to | ||
1064 | * disk later. | ||
1065 | */ | ||
1066 | if (a->data.non_resident.lowest_vcn) { | ||
1067 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1068 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
1069 | ntfs_attr_reinit_search_ctx(ctx); | ||
1070 | err = ntfs_attr_lookup(ni->type, ni->name, | ||
1071 | ni->name_len, CASE_SENSITIVE, | ||
1072 | 0, NULL, 0, ctx); | ||
1073 | if (unlikely(err)) { | ||
1074 | status.attr_switched = 1; | ||
1075 | break; | ||
1076 | } | ||
1077 | /* @m is not used any more so do not set it. */ | ||
1078 | a = ctx->attr; | ||
1079 | } | ||
1080 | write_lock_irqsave(&ni->size_lock, flags); | ||
1081 | ni->itype.compressed.size += vol->cluster_size; | ||
1082 | a->data.non_resident.compressed_size = | ||
1083 | cpu_to_sle64(ni->itype.compressed.size); | ||
1084 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
1085 | } | ||
1086 | /* Ensure the changes make it to disk. */ | ||
1087 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1088 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
1089 | ntfs_attr_put_search_ctx(ctx); | ||
1090 | unmap_mft_record(base_ni); | ||
1091 | /* Successfully filled the hole. */ | ||
1092 | status.runlist_merged = 0; | ||
1093 | status.mft_attr_mapped = 0; | ||
1094 | status.mp_rebuilt = 0; | ||
1095 | /* Setup the map cache and use that to deal with the buffer. */ | ||
1096 | was_hole = TRUE; | ||
1097 | vcn = bh_cpos; | ||
1098 | vcn_len = 1; | ||
1099 | lcn_block = lcn << (vol->cluster_size_bits - blocksize_bits); | ||
1100 | cdelta = 0; | ||
1101 | /* | ||
1102 | * If the number of remaining clusters in the @pages is smaller | ||
1103 | * or equal to the number of cached clusters, unlock the | ||
1104 | * runlist as the map cache will be used from now on. | ||
1105 | */ | ||
1106 | if (likely(vcn + vcn_len >= cend)) { | ||
1107 | up_write(&ni->runlist.lock); | ||
1108 | rl_write_locked = FALSE; | ||
1109 | rl = NULL; | ||
1110 | } | ||
1111 | goto map_buffer_cached; | ||
1112 | } while (bh_pos += blocksize, (bh = bh->b_this_page) != head); | ||
1113 | /* If there are no errors, do the next page. */ | ||
1114 | if (likely(!err && ++u < nr_pages)) | ||
1115 | goto do_next_page; | ||
1116 | /* If there are no errors, release the runlist lock if we took it. */ | ||
1117 | if (likely(!err)) { | ||
1118 | if (unlikely(rl_write_locked)) { | ||
1119 | up_write(&ni->runlist.lock); | ||
1120 | rl_write_locked = FALSE; | ||
1121 | } else if (unlikely(rl)) | ||
1122 | up_read(&ni->runlist.lock); | ||
1123 | rl = NULL; | ||
1124 | } | ||
1125 | /* If we issued read requests, let them complete. */ | ||
1126 | read_lock_irqsave(&ni->size_lock, flags); | ||
1127 | initialized_size = ni->initialized_size; | ||
1128 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1129 | while (wait_bh > wait) { | ||
1130 | bh = *--wait_bh; | ||
1131 | wait_on_buffer(bh); | ||
1132 | if (likely(buffer_uptodate(bh))) { | ||
1133 | page = bh->b_page; | ||
1134 | bh_pos = ((s64)page->index << PAGE_CACHE_SHIFT) + | ||
1135 | bh_offset(bh); | ||
1136 | /* | ||
1137 | * If the buffer overflows the initialized size, need | ||
1138 | * to zero the overflowing region. | ||
1139 | */ | ||
1140 | if (unlikely(bh_pos + blocksize > initialized_size)) { | ||
1141 | u8 *kaddr; | ||
1142 | int ofs = 0; | ||
1143 | |||
1144 | if (likely(bh_pos < initialized_size)) | ||
1145 | ofs = initialized_size - bh_pos; | ||
1146 | kaddr = kmap_atomic(page, KM_USER0); | ||
1147 | memset(kaddr + bh_offset(bh) + ofs, 0, | ||
1148 | blocksize - ofs); | ||
1149 | kunmap_atomic(kaddr, KM_USER0); | ||
1150 | flush_dcache_page(page); | ||
1151 | } | ||
1152 | } else /* if (unlikely(!buffer_uptodate(bh))) */ | ||
1153 | err = -EIO; | ||
1154 | } | ||
1155 | if (likely(!err)) { | ||
1156 | /* Clear buffer_new on all buffers. */ | ||
1157 | u = 0; | ||
1158 | do { | ||
1159 | bh = head = page_buffers(pages[u]); | ||
1160 | do { | ||
1161 | if (buffer_new(bh)) | ||
1162 | clear_buffer_new(bh); | ||
1163 | } while ((bh = bh->b_this_page) != head); | ||
1164 | } while (++u < nr_pages); | ||
1165 | ntfs_debug("Done."); | ||
1166 | return err; | ||
1167 | } | ||
1168 | if (status.attr_switched) { | ||
1169 | /* Get back to the attribute extent we modified. */ | ||
1170 | ntfs_attr_reinit_search_ctx(ctx); | ||
1171 | if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
1172 | CASE_SENSITIVE, bh_cpos, NULL, 0, ctx)) { | ||
1173 | ntfs_error(vol->sb, "Failed to find required " | ||
1174 | "attribute extent of attribute in " | ||
1175 | "error code path. Run chkdsk to " | ||
1176 | "recover."); | ||
1177 | write_lock_irqsave(&ni->size_lock, flags); | ||
1178 | ni->itype.compressed.size += vol->cluster_size; | ||
1179 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
1180 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1181 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
1182 | /* | ||
1183 | * The only thing that is now wrong is the compressed | ||
1184 | * size of the base attribute extent which chkdsk | ||
1185 | * should be able to fix. | ||
1186 | */ | ||
1187 | NVolSetErrors(vol); | ||
1188 | } else { | ||
1189 | m = ctx->mrec; | ||
1190 | a = ctx->attr; | ||
1191 | status.attr_switched = 0; | ||
1192 | } | ||
1193 | } | ||
1194 | /* | ||
1195 | * If the runlist has been modified, need to restore it by punching a | ||
1196 | * hole into it and we then need to deallocate the on-disk cluster as | ||
1197 | * well. Note, we only modify the runlist if we are able to generate a | ||
1198 | * new mapping pairs array, i.e. only when the mapped attribute extent | ||
1199 | * is not switched. | ||
1200 | */ | ||
1201 | if (status.runlist_merged && !status.attr_switched) { | ||
1202 | BUG_ON(!rl_write_locked); | ||
1203 | /* Make the file cluster we allocated sparse in the runlist. */ | ||
1204 | if (ntfs_rl_punch_nolock(vol, &ni->runlist, bh_cpos, 1)) { | ||
1205 | ntfs_error(vol->sb, "Failed to punch hole into " | ||
1206 | "attribute runlist in error code " | ||
1207 | "path. Run chkdsk to recover the " | ||
1208 | "lost cluster."); | ||
1209 | make_bad_inode(vi); | ||
1210 | make_bad_inode(VFS_I(base_ni)); | ||
1211 | NVolSetErrors(vol); | ||
1212 | } else /* if (success) */ { | ||
1213 | status.runlist_merged = 0; | ||
1214 | /* | ||
1215 | * Deallocate the on-disk cluster we allocated but only | ||
1216 | * if we succeeded in punching its vcn out of the | ||
1217 | * runlist. | ||
1218 | */ | ||
1219 | down_write(&vol->lcnbmp_lock); | ||
1220 | if (ntfs_bitmap_clear_bit(vol->lcnbmp_ino, lcn)) { | ||
1221 | ntfs_error(vol->sb, "Failed to release " | ||
1222 | "allocated cluster in error " | ||
1223 | "code path. Run chkdsk to " | ||
1224 | "recover the lost cluster."); | ||
1225 | NVolSetErrors(vol); | ||
1226 | } | ||
1227 | up_write(&vol->lcnbmp_lock); | ||
1228 | } | ||
1229 | } | ||
1230 | /* | ||
1231 | * Resize the attribute record to its old size and rebuild the mapping | ||
1232 | * pairs array. Note, we only can do this if the runlist has been | ||
1233 | * restored to its old state which also implies that the mapped | ||
1234 | * attribute extent is not switched. | ||
1235 | */ | ||
1236 | if (status.mp_rebuilt && !status.runlist_merged) { | ||
1237 | if (ntfs_attr_record_resize(m, a, attr_rec_len)) { | ||
1238 | ntfs_error(vol->sb, "Failed to restore attribute " | ||
1239 | "record in error code path. Run " | ||
1240 | "chkdsk to recover."); | ||
1241 | make_bad_inode(vi); | ||
1242 | make_bad_inode(VFS_I(base_ni)); | ||
1243 | NVolSetErrors(vol); | ||
1244 | } else /* if (success) */ { | ||
1245 | if (ntfs_mapping_pairs_build(vol, (u8*)a + | ||
1246 | le16_to_cpu(a->data.non_resident. | ||
1247 | mapping_pairs_offset), attr_rec_len - | ||
1248 | le16_to_cpu(a->data.non_resident. | ||
1249 | mapping_pairs_offset), ni->runlist.rl, | ||
1250 | vcn, highest_vcn, NULL)) { | ||
1251 | ntfs_error(vol->sb, "Failed to restore " | ||
1252 | "mapping pairs array in error " | ||
1253 | "code path. Run chkdsk to " | ||
1254 | "recover."); | ||
1255 | make_bad_inode(vi); | ||
1256 | make_bad_inode(VFS_I(base_ni)); | ||
1257 | NVolSetErrors(vol); | ||
1258 | } | ||
1259 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1260 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
1261 | } | ||
1262 | } | ||
1263 | /* Release the mft record and the attribute. */ | ||
1264 | if (status.mft_attr_mapped) { | ||
1265 | ntfs_attr_put_search_ctx(ctx); | ||
1266 | unmap_mft_record(base_ni); | ||
1267 | } | ||
1268 | /* Release the runlist lock. */ | ||
1269 | if (rl_write_locked) | ||
1270 | up_write(&ni->runlist.lock); | ||
1271 | else if (rl) | ||
1272 | up_read(&ni->runlist.lock); | ||
1273 | /* | ||
1274 | * Zero out any newly allocated blocks to avoid exposing stale data. | ||
1275 | * If BH_New is set, we know that the block was newly allocated above | ||
1276 | * and that it has not been fully zeroed and marked dirty yet. | ||
1277 | */ | ||
1278 | nr_pages = u; | ||
1279 | u = 0; | ||
1280 | end = bh_cpos << vol->cluster_size_bits; | ||
1281 | do { | ||
1282 | page = pages[u]; | ||
1283 | bh = head = page_buffers(page); | ||
1284 | do { | ||
1285 | if (u == nr_pages && | ||
1286 | ((s64)page->index << PAGE_CACHE_SHIFT) + | ||
1287 | bh_offset(bh) >= end) | ||
1288 | break; | ||
1289 | if (!buffer_new(bh)) | ||
1290 | continue; | ||
1291 | clear_buffer_new(bh); | ||
1292 | if (!buffer_uptodate(bh)) { | ||
1293 | if (PageUptodate(page)) | ||
1294 | set_buffer_uptodate(bh); | ||
1295 | else { | ||
1296 | u8 *kaddr = kmap_atomic(page, KM_USER0); | ||
1297 | memset(kaddr + bh_offset(bh), 0, | ||
1298 | blocksize); | ||
1299 | kunmap_atomic(kaddr, KM_USER0); | ||
1300 | flush_dcache_page(page); | ||
1301 | set_buffer_uptodate(bh); | ||
1302 | } | ||
1303 | } | ||
1304 | mark_buffer_dirty(bh); | ||
1305 | } while ((bh = bh->b_this_page) != head); | ||
1306 | } while (++u <= nr_pages); | ||
1307 | ntfs_error(vol->sb, "Failed. Returning error code %i.", err); | ||
1308 | return err; | ||
1309 | } | ||
1310 | |||
1311 | /* | ||
1312 | * Copy as much as we can into the pages and return the number of bytes which | ||
1313 | * were sucessfully copied. If a fault is encountered then clear the pages | ||
1314 | * out to (ofs + bytes) and return the number of bytes which were copied. | ||
1315 | */ | ||
1316 | static inline size_t ntfs_copy_from_user(struct page **pages, | ||
1317 | unsigned nr_pages, unsigned ofs, const char __user *buf, | ||
1318 | size_t bytes) | ||
1319 | { | ||
1320 | struct page **last_page = pages + nr_pages; | ||
1321 | char *kaddr; | ||
1322 | size_t total = 0; | ||
1323 | unsigned len; | ||
1324 | int left; | ||
1325 | |||
1326 | do { | ||
1327 | len = PAGE_CACHE_SIZE - ofs; | ||
1328 | if (len > bytes) | ||
1329 | len = bytes; | ||
1330 | kaddr = kmap_atomic(*pages, KM_USER0); | ||
1331 | left = __copy_from_user_inatomic(kaddr + ofs, buf, len); | ||
1332 | kunmap_atomic(kaddr, KM_USER0); | ||
1333 | if (unlikely(left)) { | ||
1334 | /* Do it the slow way. */ | ||
1335 | kaddr = kmap(*pages); | ||
1336 | left = __copy_from_user(kaddr + ofs, buf, len); | ||
1337 | kunmap(*pages); | ||
1338 | if (unlikely(left)) | ||
1339 | goto err_out; | ||
1340 | } | ||
1341 | total += len; | ||
1342 | bytes -= len; | ||
1343 | if (!bytes) | ||
1344 | break; | ||
1345 | buf += len; | ||
1346 | ofs = 0; | ||
1347 | } while (++pages < last_page); | ||
1348 | out: | ||
1349 | return total; | ||
1350 | err_out: | ||
1351 | total += len - left; | ||
1352 | /* Zero the rest of the target like __copy_from_user(). */ | ||
1353 | while (++pages < last_page) { | ||
1354 | bytes -= len; | ||
1355 | if (!bytes) | ||
1356 | break; | ||
1357 | len = PAGE_CACHE_SIZE; | ||
1358 | if (len > bytes) | ||
1359 | len = bytes; | ||
1360 | kaddr = kmap_atomic(*pages, KM_USER0); | ||
1361 | memset(kaddr, 0, len); | ||
1362 | kunmap_atomic(kaddr, KM_USER0); | ||
1363 | } | ||
1364 | goto out; | ||
1365 | } | ||
1366 | |||
1367 | static size_t __ntfs_copy_from_user_iovec(char *vaddr, | ||
1368 | const struct iovec *iov, size_t iov_ofs, size_t bytes) | ||
1369 | { | ||
1370 | size_t total = 0; | ||
1371 | |||
1372 | while (1) { | ||
1373 | const char __user *buf = iov->iov_base + iov_ofs; | ||
1374 | unsigned len; | ||
1375 | size_t left; | ||
1376 | |||
1377 | len = iov->iov_len - iov_ofs; | ||
1378 | if (len > bytes) | ||
1379 | len = bytes; | ||
1380 | left = __copy_from_user_inatomic(vaddr, buf, len); | ||
1381 | total += len; | ||
1382 | bytes -= len; | ||
1383 | vaddr += len; | ||
1384 | if (unlikely(left)) { | ||
1385 | /* | ||
1386 | * Zero the rest of the target like __copy_from_user(). | ||
1387 | */ | ||
1388 | memset(vaddr, 0, bytes); | ||
1389 | total -= left; | ||
1390 | break; | ||
1391 | } | ||
1392 | if (!bytes) | ||
1393 | break; | ||
1394 | iov++; | ||
1395 | iov_ofs = 0; | ||
1396 | } | ||
1397 | return total; | ||
1398 | } | ||
1399 | |||
1400 | static inline void ntfs_set_next_iovec(const struct iovec **iovp, | ||
1401 | size_t *iov_ofsp, size_t bytes) | ||
1402 | { | ||
1403 | const struct iovec *iov = *iovp; | ||
1404 | size_t iov_ofs = *iov_ofsp; | ||
1405 | |||
1406 | while (bytes) { | ||
1407 | unsigned len; | ||
1408 | |||
1409 | len = iov->iov_len - iov_ofs; | ||
1410 | if (len > bytes) | ||
1411 | len = bytes; | ||
1412 | bytes -= len; | ||
1413 | iov_ofs += len; | ||
1414 | if (iov->iov_len == iov_ofs) { | ||
1415 | iov++; | ||
1416 | iov_ofs = 0; | ||
1417 | } | ||
1418 | } | ||
1419 | *iovp = iov; | ||
1420 | *iov_ofsp = iov_ofs; | ||
1421 | } | ||
1422 | |||
1423 | /* | ||
1424 | * This has the same side-effects and return value as ntfs_copy_from_user(). | ||
1425 | * The difference is that on a fault we need to memset the remainder of the | ||
1426 | * pages (out to offset + bytes), to emulate ntfs_copy_from_user()'s | ||
1427 | * single-segment behaviour. | ||
1428 | * | ||
1429 | * We call the same helper (__ntfs_copy_from_user_iovec()) both when atomic and | ||
1430 | * when not atomic. This is ok because __ntfs_copy_from_user_iovec() calls | ||
1431 | * __copy_from_user_inatomic() and it is ok to call this when non-atomic. In | ||
1432 | * fact, the only difference between __copy_from_user_inatomic() and | ||
1433 | * __copy_from_user() is that the latter calls might_sleep(). And on many | ||
1434 | * architectures __copy_from_user_inatomic() is just defined to | ||
1435 | * __copy_from_user() so it makes no difference at all on those architectures. | ||
1436 | */ | ||
1437 | static inline size_t ntfs_copy_from_user_iovec(struct page **pages, | ||
1438 | unsigned nr_pages, unsigned ofs, const struct iovec **iov, | ||
1439 | size_t *iov_ofs, size_t bytes) | ||
1440 | { | ||
1441 | struct page **last_page = pages + nr_pages; | ||
1442 | char *kaddr; | ||
1443 | size_t copied, len, total = 0; | ||
1444 | |||
1445 | do { | ||
1446 | len = PAGE_CACHE_SIZE - ofs; | ||
1447 | if (len > bytes) | ||
1448 | len = bytes; | ||
1449 | kaddr = kmap_atomic(*pages, KM_USER0); | ||
1450 | copied = __ntfs_copy_from_user_iovec(kaddr + ofs, | ||
1451 | *iov, *iov_ofs, len); | ||
1452 | kunmap_atomic(kaddr, KM_USER0); | ||
1453 | if (unlikely(copied != len)) { | ||
1454 | /* Do it the slow way. */ | ||
1455 | kaddr = kmap(*pages); | ||
1456 | copied = __ntfs_copy_from_user_iovec(kaddr + ofs, | ||
1457 | *iov, *iov_ofs, len); | ||
1458 | kunmap(*pages); | ||
1459 | if (unlikely(copied != len)) | ||
1460 | goto err_out; | ||
1461 | } | ||
1462 | total += len; | ||
1463 | bytes -= len; | ||
1464 | if (!bytes) | ||
1465 | break; | ||
1466 | ntfs_set_next_iovec(iov, iov_ofs, len); | ||
1467 | ofs = 0; | ||
1468 | } while (++pages < last_page); | ||
1469 | out: | ||
1470 | return total; | ||
1471 | err_out: | ||
1472 | total += copied; | ||
1473 | /* Zero the rest of the target like __copy_from_user(). */ | ||
1474 | while (++pages < last_page) { | ||
1475 | bytes -= len; | ||
1476 | if (!bytes) | ||
1477 | break; | ||
1478 | len = PAGE_CACHE_SIZE; | ||
1479 | if (len > bytes) | ||
1480 | len = bytes; | ||
1481 | kaddr = kmap_atomic(*pages, KM_USER0); | ||
1482 | memset(kaddr, 0, len); | ||
1483 | kunmap_atomic(kaddr, KM_USER0); | ||
1484 | } | ||
1485 | goto out; | ||
1486 | } | ||
1487 | |||
1488 | static inline void ntfs_flush_dcache_pages(struct page **pages, | ||
1489 | unsigned nr_pages) | ||
1490 | { | ||
1491 | BUG_ON(!nr_pages); | ||
1492 | do { | ||
1493 | /* | ||
1494 | * Warning: Do not do the decrement at the same time as the | ||
1495 | * call because flush_dcache_page() is a NULL macro on i386 | ||
1496 | * and hence the decrement never happens. | ||
1497 | */ | ||
1498 | flush_dcache_page(pages[nr_pages]); | ||
1499 | } while (--nr_pages > 0); | ||
1500 | } | ||
1501 | |||
1502 | /** | ||
1503 | * ntfs_commit_pages_after_non_resident_write - commit the received data | ||
1504 | * @pages: array of destination pages | ||
1505 | * @nr_pages: number of pages in @pages | ||
1506 | * @pos: byte position in file at which the write begins | ||
1507 | * @bytes: number of bytes to be written | ||
1508 | * | ||
1509 | * See description of ntfs_commit_pages_after_write(), below. | ||
1510 | */ | ||
1511 | static inline int ntfs_commit_pages_after_non_resident_write( | ||
1512 | struct page **pages, const unsigned nr_pages, | ||
1513 | s64 pos, size_t bytes) | ||
1514 | { | ||
1515 | s64 end, initialized_size; | ||
1516 | struct inode *vi; | ||
1517 | ntfs_inode *ni, *base_ni; | ||
1518 | struct buffer_head *bh, *head; | ||
1519 | ntfs_attr_search_ctx *ctx; | ||
1520 | MFT_RECORD *m; | ||
1521 | ATTR_RECORD *a; | ||
1522 | unsigned long flags; | ||
1523 | unsigned blocksize, u; | ||
1524 | int err; | ||
1525 | |||
1526 | vi = pages[0]->mapping->host; | ||
1527 | ni = NTFS_I(vi); | ||
1528 | blocksize = 1 << vi->i_blkbits; | ||
1529 | end = pos + bytes; | ||
1530 | u = 0; | ||
1531 | do { | ||
1532 | s64 bh_pos; | ||
1533 | struct page *page; | ||
1534 | BOOL partial; | ||
1535 | |||
1536 | page = pages[u]; | ||
1537 | bh_pos = (s64)page->index << PAGE_CACHE_SHIFT; | ||
1538 | bh = head = page_buffers(page); | ||
1539 | partial = FALSE; | ||
1540 | do { | ||
1541 | s64 bh_end; | ||
1542 | |||
1543 | bh_end = bh_pos + blocksize; | ||
1544 | if (bh_end <= pos || bh_pos >= end) { | ||
1545 | if (!buffer_uptodate(bh)) | ||
1546 | partial = TRUE; | ||
1547 | } else { | ||
1548 | set_buffer_uptodate(bh); | ||
1549 | mark_buffer_dirty(bh); | ||
1550 | } | ||
1551 | } while (bh_pos += blocksize, (bh = bh->b_this_page) != head); | ||
1552 | /* | ||
1553 | * If all buffers are now uptodate but the page is not, set the | ||
1554 | * page uptodate. | ||
1555 | */ | ||
1556 | if (!partial && !PageUptodate(page)) | ||
1557 | SetPageUptodate(page); | ||
1558 | } while (++u < nr_pages); | ||
1559 | /* | ||
1560 | * Finally, if we do not need to update initialized_size or i_size we | ||
1561 | * are finished. | ||
1562 | */ | ||
1563 | read_lock_irqsave(&ni->size_lock, flags); | ||
1564 | initialized_size = ni->initialized_size; | ||
1565 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1566 | if (end <= initialized_size) { | ||
1567 | ntfs_debug("Done."); | ||
1568 | return 0; | ||
1569 | } | ||
1570 | /* | ||
1571 | * Update initialized_size/i_size as appropriate, both in the inode and | ||
1572 | * the mft record. | ||
1573 | */ | ||
1574 | if (!NInoAttr(ni)) | ||
1575 | base_ni = ni; | ||
1576 | else | ||
1577 | base_ni = ni->ext.base_ntfs_ino; | ||
1578 | /* Map, pin, and lock the mft record. */ | ||
1579 | m = map_mft_record(base_ni); | ||
1580 | if (IS_ERR(m)) { | ||
1581 | err = PTR_ERR(m); | ||
1582 | m = NULL; | ||
1583 | ctx = NULL; | ||
1584 | goto err_out; | ||
1585 | } | ||
1586 | BUG_ON(!NInoNonResident(ni)); | ||
1587 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
1588 | if (unlikely(!ctx)) { | ||
1589 | err = -ENOMEM; | ||
1590 | goto err_out; | ||
1591 | } | ||
1592 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
1593 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
1594 | if (unlikely(err)) { | ||
1595 | if (err == -ENOENT) | ||
1596 | err = -EIO; | ||
1597 | goto err_out; | ||
1598 | } | ||
1599 | a = ctx->attr; | ||
1600 | BUG_ON(!a->non_resident); | ||
1601 | write_lock_irqsave(&ni->size_lock, flags); | ||
1602 | BUG_ON(end > ni->allocated_size); | ||
1603 | ni->initialized_size = end; | ||
1604 | a->data.non_resident.initialized_size = cpu_to_sle64(end); | ||
1605 | if (end > i_size_read(vi)) { | ||
1606 | i_size_write(vi, end); | ||
1607 | a->data.non_resident.data_size = | ||
1608 | a->data.non_resident.initialized_size; | ||
1609 | } | ||
1610 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
1611 | /* Mark the mft record dirty, so it gets written back. */ | ||
1612 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1613 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
1614 | ntfs_attr_put_search_ctx(ctx); | ||
1615 | unmap_mft_record(base_ni); | ||
1616 | ntfs_debug("Done."); | ||
1617 | return 0; | ||
1618 | err_out: | ||
1619 | if (ctx) | ||
1620 | ntfs_attr_put_search_ctx(ctx); | ||
1621 | if (m) | ||
1622 | unmap_mft_record(base_ni); | ||
1623 | ntfs_error(vi->i_sb, "Failed to update initialized_size/i_size (error " | ||
1624 | "code %i).", err); | ||
1625 | if (err != -ENOMEM) { | ||
1626 | NVolSetErrors(ni->vol); | ||
1627 | make_bad_inode(VFS_I(base_ni)); | ||
1628 | make_bad_inode(vi); | ||
1629 | } | ||
1630 | return err; | ||
1631 | } | ||
1632 | |||
1633 | /** | ||
1634 | * ntfs_commit_pages_after_write - commit the received data | ||
1635 | * @pages: array of destination pages | ||
1636 | * @nr_pages: number of pages in @pages | ||
1637 | * @pos: byte position in file at which the write begins | ||
1638 | * @bytes: number of bytes to be written | ||
1639 | * | ||
1640 | * This is called from ntfs_file_buffered_write() with i_sem held on the inode | ||
1641 | * (@pages[0]->mapping->host). There are @nr_pages pages in @pages which are | ||
1642 | * locked but not kmap()ped. The source data has already been copied into the | ||
1643 | * @page. ntfs_prepare_pages_for_non_resident_write() has been called before | ||
1644 | * the data was copied (for non-resident attributes only) and it returned | ||
1645 | * success. | ||
1646 | * | ||
1647 | * Need to set uptodate and mark dirty all buffers within the boundary of the | ||
1648 | * write. If all buffers in a page are uptodate we set the page uptodate, too. | ||
1649 | * | ||
1650 | * Setting the buffers dirty ensures that they get written out later when | ||
1651 | * ntfs_writepage() is invoked by the VM. | ||
1652 | * | ||
1653 | * Finally, we need to update i_size and initialized_size as appropriate both | ||
1654 | * in the inode and the mft record. | ||
1655 | * | ||
1656 | * This is modelled after fs/buffer.c::generic_commit_write(), which marks | ||
1657 | * buffers uptodate and dirty, sets the page uptodate if all buffers in the | ||
1658 | * page are uptodate, and updates i_size if the end of io is beyond i_size. In | ||
1659 | * that case, it also marks the inode dirty. | ||
1660 | * | ||
1661 | * If things have gone as outlined in | ||
1662 | * ntfs_prepare_pages_for_non_resident_write(), we do not need to do any page | ||
1663 | * content modifications here for non-resident attributes. For resident | ||
1664 | * attributes we need to do the uptodate bringing here which we combine with | ||
1665 | * the copying into the mft record which means we save one atomic kmap. | ||
1666 | * | ||
1667 | * Return 0 on success or -errno on error. | ||
1668 | */ | ||
1669 | static int ntfs_commit_pages_after_write(struct page **pages, | ||
1670 | const unsigned nr_pages, s64 pos, size_t bytes) | ||
1671 | { | ||
1672 | s64 end, initialized_size; | ||
1673 | loff_t i_size; | ||
1674 | struct inode *vi; | ||
1675 | ntfs_inode *ni, *base_ni; | ||
1676 | struct page *page; | ||
1677 | ntfs_attr_search_ctx *ctx; | ||
1678 | MFT_RECORD *m; | ||
1679 | ATTR_RECORD *a; | ||
1680 | char *kattr, *kaddr; | ||
1681 | unsigned long flags; | ||
1682 | u32 attr_len; | ||
1683 | int err; | ||
1684 | |||
1685 | BUG_ON(!nr_pages); | ||
1686 | BUG_ON(!pages); | ||
1687 | page = pages[0]; | ||
1688 | BUG_ON(!page); | ||
1689 | vi = page->mapping->host; | ||
1690 | ni = NTFS_I(vi); | ||
1691 | ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, start page " | ||
1692 | "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.", | ||
1693 | vi->i_ino, ni->type, page->index, nr_pages, | ||
1694 | (long long)pos, bytes); | ||
1695 | if (NInoNonResident(ni)) | ||
1696 | return ntfs_commit_pages_after_non_resident_write(pages, | ||
1697 | nr_pages, pos, bytes); | ||
1698 | BUG_ON(nr_pages > 1); | ||
1699 | /* | ||
1700 | * Attribute is resident, implying it is not compressed, encrypted, or | ||
1701 | * sparse. | ||
1702 | */ | ||
1703 | if (!NInoAttr(ni)) | ||
1704 | base_ni = ni; | ||
1705 | else | ||
1706 | base_ni = ni->ext.base_ntfs_ino; | ||
1707 | BUG_ON(NInoNonResident(ni)); | ||
1708 | /* Map, pin, and lock the mft record. */ | ||
1709 | m = map_mft_record(base_ni); | ||
1710 | if (IS_ERR(m)) { | ||
1711 | err = PTR_ERR(m); | ||
1712 | m = NULL; | ||
1713 | ctx = NULL; | ||
1714 | goto err_out; | ||
1715 | } | ||
1716 | ctx = ntfs_attr_get_search_ctx(base_ni, m); | ||
1717 | if (unlikely(!ctx)) { | ||
1718 | err = -ENOMEM; | ||
1719 | goto err_out; | ||
1720 | } | ||
1721 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | ||
1722 | CASE_SENSITIVE, 0, NULL, 0, ctx); | ||
1723 | if (unlikely(err)) { | ||
1724 | if (err == -ENOENT) | ||
1725 | err = -EIO; | ||
1726 | goto err_out; | ||
1727 | } | ||
1728 | a = ctx->attr; | ||
1729 | BUG_ON(a->non_resident); | ||
1730 | /* The total length of the attribute value. */ | ||
1731 | attr_len = le32_to_cpu(a->data.resident.value_length); | ||
1732 | i_size = i_size_read(vi); | ||
1733 | BUG_ON(attr_len != i_size); | ||
1734 | BUG_ON(pos > attr_len); | ||
1735 | end = pos + bytes; | ||
1736 | BUG_ON(end > le32_to_cpu(a->length) - | ||
1737 | le16_to_cpu(a->data.resident.value_offset)); | ||
1738 | kattr = (u8*)a + le16_to_cpu(a->data.resident.value_offset); | ||
1739 | kaddr = kmap_atomic(page, KM_USER0); | ||
1740 | /* Copy the received data from the page to the mft record. */ | ||
1741 | memcpy(kattr + pos, kaddr + pos, bytes); | ||
1742 | /* Update the attribute length if necessary. */ | ||
1743 | if (end > attr_len) { | ||
1744 | attr_len = end; | ||
1745 | a->data.resident.value_length = cpu_to_le32(attr_len); | ||
1746 | } | ||
1747 | /* | ||
1748 | * If the page is not uptodate, bring the out of bounds area(s) | ||
1749 | * uptodate by copying data from the mft record to the page. | ||
1750 | */ | ||
1751 | if (!PageUptodate(page)) { | ||
1752 | if (pos > 0) | ||
1753 | memcpy(kaddr, kattr, pos); | ||
1754 | if (end < attr_len) | ||
1755 | memcpy(kaddr + end, kattr + end, attr_len - end); | ||
1756 | /* Zero the region outside the end of the attribute value. */ | ||
1757 | memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); | ||
1758 | flush_dcache_page(page); | ||
1759 | SetPageUptodate(page); | ||
1760 | } | ||
1761 | kunmap_atomic(kaddr, KM_USER0); | ||
1762 | /* Update initialized_size/i_size if necessary. */ | ||
1763 | read_lock_irqsave(&ni->size_lock, flags); | ||
1764 | initialized_size = ni->initialized_size; | ||
1765 | BUG_ON(end > ni->allocated_size); | ||
1766 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1767 | BUG_ON(initialized_size != i_size); | ||
1768 | if (end > initialized_size) { | ||
1769 | unsigned long flags; | ||
1770 | |||
1771 | write_lock_irqsave(&ni->size_lock, flags); | ||
1772 | ni->initialized_size = end; | ||
1773 | i_size_write(vi, end); | ||
1774 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
1775 | } | ||
1776 | /* Mark the mft record dirty, so it gets written back. */ | ||
1777 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
1778 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
1779 | ntfs_attr_put_search_ctx(ctx); | ||
1780 | unmap_mft_record(base_ni); | ||
1781 | ntfs_debug("Done."); | ||
1782 | return 0; | ||
1783 | err_out: | ||
1784 | if (err == -ENOMEM) { | ||
1785 | ntfs_warning(vi->i_sb, "Error allocating memory required to " | ||
1786 | "commit the write."); | ||
1787 | if (PageUptodate(page)) { | ||
1788 | ntfs_warning(vi->i_sb, "Page is uptodate, setting " | ||
1789 | "dirty so the write will be retried " | ||
1790 | "later on by the VM."); | ||
1791 | /* | ||
1792 | * Put the page on mapping->dirty_pages, but leave its | ||
1793 | * buffers' dirty state as-is. | ||
1794 | */ | ||
1795 | __set_page_dirty_nobuffers(page); | ||
1796 | err = 0; | ||
1797 | } else | ||
1798 | ntfs_error(vi->i_sb, "Page is not uptodate. Written " | ||
1799 | "data has been lost."); | ||
1800 | } else { | ||
1801 | ntfs_error(vi->i_sb, "Resident attribute commit write failed " | ||
1802 | "with error %i.", err); | ||
1803 | NVolSetErrors(ni->vol); | ||
1804 | make_bad_inode(VFS_I(base_ni)); | ||
1805 | make_bad_inode(vi); | ||
1806 | } | ||
1807 | if (ctx) | ||
1808 | ntfs_attr_put_search_ctx(ctx); | ||
1809 | if (m) | ||
1810 | unmap_mft_record(base_ni); | ||
1811 | return err; | ||
1812 | } | ||
1813 | |||
1814 | /** | ||
1815 | * ntfs_file_buffered_write - | ||
1816 | * | ||
1817 | * Locking: The vfs is holding ->i_sem on the inode. | ||
1818 | */ | ||
1819 | static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, | ||
1820 | const struct iovec *iov, unsigned long nr_segs, | ||
1821 | loff_t pos, loff_t *ppos, size_t count) | ||
1822 | { | ||
1823 | struct file *file = iocb->ki_filp; | ||
1824 | struct address_space *mapping = file->f_mapping; | ||
1825 | struct inode *vi = mapping->host; | ||
1826 | ntfs_inode *ni = NTFS_I(vi); | ||
1827 | ntfs_volume *vol = ni->vol; | ||
1828 | struct page *pages[NTFS_MAX_PAGES_PER_CLUSTER]; | ||
1829 | struct page *cached_page = NULL; | ||
1830 | char __user *buf = NULL; | ||
1831 | s64 end, ll; | ||
1832 | VCN last_vcn; | ||
1833 | LCN lcn; | ||
1834 | unsigned long flags; | ||
1835 | size_t bytes, iov_ofs = 0; /* Offset in the current iovec. */ | ||
1836 | ssize_t status, written; | ||
1837 | unsigned nr_pages; | ||
1838 | int err; | ||
1839 | struct pagevec lru_pvec; | ||
1840 | |||
1841 | ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " | ||
1842 | "pos 0x%llx, count 0x%lx.", | ||
1843 | vi->i_ino, (unsigned)le32_to_cpu(ni->type), | ||
1844 | (unsigned long long)pos, (unsigned long)count); | ||
1845 | if (unlikely(!count)) | ||
1846 | return 0; | ||
1847 | BUG_ON(NInoMstProtected(ni)); | ||
1848 | /* | ||
1849 | * If the attribute is not an index root and it is encrypted or | ||
1850 | * compressed, we cannot write to it yet. Note we need to check for | ||
1851 | * AT_INDEX_ALLOCATION since this is the type of both directory and | ||
1852 | * index inodes. | ||
1853 | */ | ||
1854 | if (ni->type != AT_INDEX_ALLOCATION) { | ||
1855 | /* If file is encrypted, deny access, just like NT4. */ | ||
1856 | if (NInoEncrypted(ni)) { | ||
1857 | /* | ||
1858 | * Reminder for later: Encrypted files are _always_ | ||
1859 | * non-resident so that the content can always be | ||
1860 | * encrypted. | ||
1861 | */ | ||
1862 | ntfs_debug("Denying write access to encrypted file."); | ||
1863 | return -EACCES; | ||
1864 | } | ||
1865 | if (NInoCompressed(ni)) { | ||
1866 | /* Only unnamed $DATA attribute can be compressed. */ | ||
1867 | BUG_ON(ni->type != AT_DATA); | ||
1868 | BUG_ON(ni->name_len); | ||
1869 | /* | ||
1870 | * Reminder for later: If resident, the data is not | ||
1871 | * actually compressed. Only on the switch to non- | ||
1872 | * resident does compression kick in. This is in | ||
1873 | * contrast to encrypted files (see above). | ||
1874 | */ | ||
1875 | ntfs_error(vi->i_sb, "Writing to compressed files is " | ||
1876 | "not implemented yet. Sorry."); | ||
1877 | return -EOPNOTSUPP; | ||
1878 | } | ||
1879 | } | ||
1880 | /* | ||
1881 | * If a previous ntfs_truncate() failed, repeat it and abort if it | ||
1882 | * fails again. | ||
1883 | */ | ||
1884 | if (unlikely(NInoTruncateFailed(ni))) { | ||
1885 | down_write(&vi->i_alloc_sem); | ||
1886 | err = ntfs_truncate(vi); | ||
1887 | up_write(&vi->i_alloc_sem); | ||
1888 | if (err || NInoTruncateFailed(ni)) { | ||
1889 | if (!err) | ||
1890 | err = -EIO; | ||
1891 | ntfs_error(vol->sb, "Cannot perform write to inode " | ||
1892 | "0x%lx, attribute type 0x%x, because " | ||
1893 | "ntfs_truncate() failed (error code " | ||
1894 | "%i).", vi->i_ino, | ||
1895 | (unsigned)le32_to_cpu(ni->type), err); | ||
1896 | return err; | ||
1897 | } | ||
1898 | } | ||
1899 | /* The first byte after the write. */ | ||
1900 | end = pos + count; | ||
1901 | /* | ||
1902 | * If the write goes beyond the allocated size, extend the allocation | ||
1903 | * to cover the whole of the write, rounded up to the nearest cluster. | ||
1904 | */ | ||
1905 | read_lock_irqsave(&ni->size_lock, flags); | ||
1906 | ll = ni->allocated_size; | ||
1907 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1908 | if (end > ll) { | ||
1909 | /* Extend the allocation without changing the data size. */ | ||
1910 | ll = ntfs_attr_extend_allocation(ni, end, -1, pos); | ||
1911 | if (likely(ll >= 0)) { | ||
1912 | BUG_ON(pos >= ll); | ||
1913 | /* If the extension was partial truncate the write. */ | ||
1914 | if (end > ll) { | ||
1915 | ntfs_debug("Truncating write to inode 0x%lx, " | ||
1916 | "attribute type 0x%x, because " | ||
1917 | "the allocation was only " | ||
1918 | "partially extended.", | ||
1919 | vi->i_ino, (unsigned) | ||
1920 | le32_to_cpu(ni->type)); | ||
1921 | end = ll; | ||
1922 | count = ll - pos; | ||
1923 | } | ||
1924 | } else { | ||
1925 | err = ll; | ||
1926 | read_lock_irqsave(&ni->size_lock, flags); | ||
1927 | ll = ni->allocated_size; | ||
1928 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1929 | /* Perform a partial write if possible or fail. */ | ||
1930 | if (pos < ll) { | ||
1931 | ntfs_debug("Truncating write to inode 0x%lx, " | ||
1932 | "attribute type 0x%x, because " | ||
1933 | "extending the allocation " | ||
1934 | "failed (error code %i).", | ||
1935 | vi->i_ino, (unsigned) | ||
1936 | le32_to_cpu(ni->type), err); | ||
1937 | end = ll; | ||
1938 | count = ll - pos; | ||
1939 | } else { | ||
1940 | ntfs_error(vol->sb, "Cannot perform write to " | ||
1941 | "inode 0x%lx, attribute type " | ||
1942 | "0x%x, because extending the " | ||
1943 | "allocation failed (error " | ||
1944 | "code %i).", vi->i_ino, | ||
1945 | (unsigned) | ||
1946 | le32_to_cpu(ni->type), err); | ||
1947 | return err; | ||
1948 | } | ||
1949 | } | ||
1950 | } | ||
1951 | pagevec_init(&lru_pvec, 0); | ||
1952 | written = 0; | ||
1953 | /* | ||
1954 | * If the write starts beyond the initialized size, extend it up to the | ||
1955 | * beginning of the write and initialize all non-sparse space between | ||
1956 | * the old initialized size and the new one. This automatically also | ||
1957 | * increments the vfs inode->i_size to keep it above or equal to the | ||
1958 | * initialized_size. | ||
1959 | */ | ||
1960 | read_lock_irqsave(&ni->size_lock, flags); | ||
1961 | ll = ni->initialized_size; | ||
1962 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
1963 | if (pos > ll) { | ||
1964 | err = ntfs_attr_extend_initialized(ni, pos, &cached_page, | ||
1965 | &lru_pvec); | ||
1966 | if (err < 0) { | ||
1967 | ntfs_error(vol->sb, "Cannot perform write to inode " | ||
1968 | "0x%lx, attribute type 0x%x, because " | ||
1969 | "extending the initialized size " | ||
1970 | "failed (error code %i).", vi->i_ino, | ||
1971 | (unsigned)le32_to_cpu(ni->type), err); | ||
1972 | status = err; | ||
1973 | goto err_out; | ||
1974 | } | ||
1975 | } | ||
1976 | /* | ||
1977 | * Determine the number of pages per cluster for non-resident | ||
1978 | * attributes. | ||
1979 | */ | ||
1980 | nr_pages = 1; | ||
1981 | if (vol->cluster_size > PAGE_CACHE_SIZE && NInoNonResident(ni)) | ||
1982 | nr_pages = vol->cluster_size >> PAGE_CACHE_SHIFT; | ||
1983 | /* Finally, perform the actual write. */ | ||
1984 | last_vcn = -1; | ||
1985 | if (likely(nr_segs == 1)) | ||
1986 | buf = iov->iov_base; | ||
1987 | do { | ||
1988 | VCN vcn; | ||
1989 | pgoff_t idx, start_idx; | ||
1990 | unsigned ofs, do_pages, u; | ||
1991 | size_t copied; | ||
1992 | |||
1993 | start_idx = idx = pos >> PAGE_CACHE_SHIFT; | ||
1994 | ofs = pos & ~PAGE_CACHE_MASK; | ||
1995 | bytes = PAGE_CACHE_SIZE - ofs; | ||
1996 | do_pages = 1; | ||
1997 | if (nr_pages > 1) { | ||
1998 | vcn = pos >> vol->cluster_size_bits; | ||
1999 | if (vcn != last_vcn) { | ||
2000 | last_vcn = vcn; | ||
2001 | /* | ||
2002 | * Get the lcn of the vcn the write is in. If | ||
2003 | * it is a hole, need to lock down all pages in | ||
2004 | * the cluster. | ||
2005 | */ | ||
2006 | down_read(&ni->runlist.lock); | ||
2007 | lcn = ntfs_attr_vcn_to_lcn_nolock(ni, pos >> | ||
2008 | vol->cluster_size_bits, FALSE); | ||
2009 | up_read(&ni->runlist.lock); | ||
2010 | if (unlikely(lcn < LCN_HOLE)) { | ||
2011 | status = -EIO; | ||
2012 | if (lcn == LCN_ENOMEM) | ||
2013 | status = -ENOMEM; | ||
2014 | else | ||
2015 | ntfs_error(vol->sb, "Cannot " | ||
2016 | "perform write to " | ||
2017 | "inode 0x%lx, " | ||
2018 | "attribute type 0x%x, " | ||
2019 | "because the attribute " | ||
2020 | "is corrupt.", | ||
2021 | vi->i_ino, (unsigned) | ||
2022 | le32_to_cpu(ni->type)); | ||
2023 | break; | ||
2024 | } | ||
2025 | if (lcn == LCN_HOLE) { | ||
2026 | start_idx = (pos & ~(s64) | ||
2027 | vol->cluster_size_mask) | ||
2028 | >> PAGE_CACHE_SHIFT; | ||
2029 | bytes = vol->cluster_size - (pos & | ||
2030 | vol->cluster_size_mask); | ||
2031 | do_pages = nr_pages; | ||
2032 | } | ||
2033 | } | ||
2034 | } | ||
2035 | if (bytes > count) | ||
2036 | bytes = count; | ||
2037 | /* | ||
2038 | * Bring in the user page(s) that we will copy from _first_. | ||
2039 | * Otherwise there is a nasty deadlock on copying from the same | ||
2040 | * page(s) as we are writing to, without it/them being marked | ||
2041 | * up-to-date. Note, at present there is nothing to stop the | ||
2042 | * pages being swapped out between us bringing them into memory | ||
2043 | * and doing the actual copying. | ||
2044 | */ | ||
2045 | if (likely(nr_segs == 1)) | ||
2046 | ntfs_fault_in_pages_readable(buf, bytes); | ||
2047 | else | ||
2048 | ntfs_fault_in_pages_readable_iovec(iov, iov_ofs, bytes); | ||
2049 | /* Get and lock @do_pages starting at index @start_idx. */ | ||
2050 | status = __ntfs_grab_cache_pages(mapping, start_idx, do_pages, | ||
2051 | pages, &cached_page, &lru_pvec); | ||
2052 | if (unlikely(status)) | ||
2053 | break; | ||
2054 | /* | ||
2055 | * For non-resident attributes, we need to fill any holes with | ||
2056 | * actual clusters and ensure all bufferes are mapped. We also | ||
2057 | * need to bring uptodate any buffers that are only partially | ||
2058 | * being written to. | ||
2059 | */ | ||
2060 | if (NInoNonResident(ni)) { | ||
2061 | status = ntfs_prepare_pages_for_non_resident_write( | ||
2062 | pages, do_pages, pos, bytes); | ||
2063 | if (unlikely(status)) { | ||
2064 | loff_t i_size; | ||
2065 | |||
2066 | do { | ||
2067 | unlock_page(pages[--do_pages]); | ||
2068 | page_cache_release(pages[do_pages]); | ||
2069 | } while (do_pages); | ||
2070 | /* | ||
2071 | * The write preparation may have instantiated | ||
2072 | * allocated space outside i_size. Trim this | ||
2073 | * off again. We can ignore any errors in this | ||
2074 | * case as we will just be waisting a bit of | ||
2075 | * allocated space, which is not a disaster. | ||
2076 | */ | ||
2077 | i_size = i_size_read(vi); | ||
2078 | if (pos + bytes > i_size) | ||
2079 | vmtruncate(vi, i_size); | ||
2080 | break; | ||
2081 | } | ||
2082 | } | ||
2083 | u = (pos >> PAGE_CACHE_SHIFT) - pages[0]->index; | ||
2084 | if (likely(nr_segs == 1)) { | ||
2085 | copied = ntfs_copy_from_user(pages + u, do_pages - u, | ||
2086 | ofs, buf, bytes); | ||
2087 | buf += copied; | ||
2088 | } else | ||
2089 | copied = ntfs_copy_from_user_iovec(pages + u, | ||
2090 | do_pages - u, ofs, &iov, &iov_ofs, | ||
2091 | bytes); | ||
2092 | ntfs_flush_dcache_pages(pages + u, do_pages - u); | ||
2093 | status = ntfs_commit_pages_after_write(pages, do_pages, pos, | ||
2094 | bytes); | ||
2095 | if (likely(!status)) { | ||
2096 | written += copied; | ||
2097 | count -= copied; | ||
2098 | pos += copied; | ||
2099 | if (unlikely(copied != bytes)) | ||
2100 | status = -EFAULT; | ||
2101 | } | ||
2102 | do { | ||
2103 | unlock_page(pages[--do_pages]); | ||
2104 | mark_page_accessed(pages[do_pages]); | ||
2105 | page_cache_release(pages[do_pages]); | ||
2106 | } while (do_pages); | ||
2107 | if (unlikely(status)) | ||
2108 | break; | ||
2109 | balance_dirty_pages_ratelimited(mapping); | ||
2110 | cond_resched(); | ||
2111 | } while (count); | ||
2112 | err_out: | ||
2113 | *ppos = pos; | ||
2114 | if (cached_page) | ||
2115 | page_cache_release(cached_page); | ||
2116 | /* For now, when the user asks for O_SYNC, we actually give O_DSYNC. */ | ||
2117 | if (likely(!status)) { | ||
2118 | if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(vi))) { | ||
2119 | if (!mapping->a_ops->writepage || !is_sync_kiocb(iocb)) | ||
2120 | status = generic_osync_inode(vi, mapping, | ||
2121 | OSYNC_METADATA|OSYNC_DATA); | ||
2122 | } | ||
2123 | } | ||
2124 | pagevec_lru_add(&lru_pvec); | ||
2125 | ntfs_debug("Done. Returning %s (written 0x%lx, status %li).", | ||
2126 | written ? "written" : "status", (unsigned long)written, | ||
2127 | (long)status); | ||
2128 | return written ? written : status; | ||
2129 | } | ||
2130 | |||
2131 | /** | ||
2132 | * ntfs_file_aio_write_nolock - | ||
2133 | */ | ||
2134 | static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, | ||
2135 | const struct iovec *iov, unsigned long nr_segs, loff_t *ppos) | ||
2136 | { | ||
2137 | struct file *file = iocb->ki_filp; | ||
2138 | struct address_space *mapping = file->f_mapping; | ||
2139 | struct inode *inode = mapping->host; | ||
2140 | loff_t pos; | ||
2141 | unsigned long seg; | ||
2142 | size_t count; /* after file limit checks */ | ||
2143 | ssize_t written, err; | ||
2144 | |||
2145 | count = 0; | ||
2146 | for (seg = 0; seg < nr_segs; seg++) { | ||
2147 | const struct iovec *iv = &iov[seg]; | ||
2148 | /* | ||
2149 | * If any segment has a negative length, or the cumulative | ||
2150 | * length ever wraps negative then return -EINVAL. | ||
2151 | */ | ||
2152 | count += iv->iov_len; | ||
2153 | if (unlikely((ssize_t)(count|iv->iov_len) < 0)) | ||
2154 | return -EINVAL; | ||
2155 | if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len)) | ||
2156 | continue; | ||
2157 | if (!seg) | ||
2158 | return -EFAULT; | ||
2159 | nr_segs = seg; | ||
2160 | count -= iv->iov_len; /* This segment is no good */ | ||
2161 | break; | ||
2162 | } | ||
2163 | pos = *ppos; | ||
2164 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | ||
2165 | /* We can write back this queue in page reclaim. */ | ||
2166 | current->backing_dev_info = mapping->backing_dev_info; | ||
2167 | written = 0; | ||
2168 | err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode)); | ||
2169 | if (err) | ||
2170 | goto out; | ||
2171 | if (!count) | ||
2172 | goto out; | ||
2173 | err = remove_suid(file->f_dentry); | ||
2174 | if (err) | ||
2175 | goto out; | ||
2176 | inode_update_time(inode, 1); | ||
2177 | written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos, | ||
2178 | count); | ||
2179 | out: | ||
2180 | current->backing_dev_info = NULL; | ||
2181 | return written ? written : err; | ||
2182 | } | ||
2183 | |||
2184 | /** | ||
2185 | * ntfs_file_aio_write - | ||
2186 | */ | ||
2187 | static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const char __user *buf, | ||
2188 | size_t count, loff_t pos) | ||
2189 | { | ||
2190 | struct file *file = iocb->ki_filp; | ||
2191 | struct address_space *mapping = file->f_mapping; | ||
2192 | struct inode *inode = mapping->host; | ||
2193 | ssize_t ret; | ||
2194 | struct iovec local_iov = { .iov_base = (void __user *)buf, | ||
2195 | .iov_len = count }; | ||
2196 | |||
2197 | BUG_ON(iocb->ki_pos != pos); | ||
2198 | |||
2199 | down(&inode->i_sem); | ||
2200 | ret = ntfs_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos); | ||
2201 | up(&inode->i_sem); | ||
2202 | if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { | ||
2203 | int err = sync_page_range(inode, mapping, pos, ret); | ||
2204 | if (err < 0) | ||
2205 | ret = err; | ||
2206 | } | ||
2207 | return ret; | ||
2208 | } | ||
2209 | |||
2210 | /** | ||
2211 | * ntfs_file_writev - | ||
2212 | * | ||
2213 | * Basically the same as generic_file_writev() except that it ends up calling | ||
2214 | * ntfs_file_aio_write_nolock() instead of __generic_file_aio_write_nolock(). | ||
2215 | */ | ||
2216 | static ssize_t ntfs_file_writev(struct file *file, const struct iovec *iov, | ||
2217 | unsigned long nr_segs, loff_t *ppos) | ||
2218 | { | ||
2219 | struct address_space *mapping = file->f_mapping; | ||
2220 | struct inode *inode = mapping->host; | ||
2221 | struct kiocb kiocb; | ||
2222 | ssize_t ret; | ||
2223 | |||
2224 | down(&inode->i_sem); | ||
2225 | init_sync_kiocb(&kiocb, file); | ||
2226 | ret = ntfs_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos); | ||
2227 | if (ret == -EIOCBQUEUED) | ||
2228 | ret = wait_on_sync_kiocb(&kiocb); | ||
2229 | up(&inode->i_sem); | ||
2230 | if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) { | ||
2231 | int err = sync_page_range(inode, mapping, *ppos - ret, ret); | ||
2232 | if (err < 0) | ||
2233 | ret = err; | ||
2234 | } | ||
2235 | return ret; | ||
2236 | } | ||
2237 | |||
2238 | /** | ||
2239 | * ntfs_file_write - simple wrapper for ntfs_file_writev() | ||
2240 | */ | ||
2241 | static ssize_t ntfs_file_write(struct file *file, const char __user *buf, | ||
2242 | size_t count, loff_t *ppos) | ||
2243 | { | ||
2244 | struct iovec local_iov = { .iov_base = (void __user *)buf, | ||
2245 | .iov_len = count }; | ||
2246 | |||
2247 | return ntfs_file_writev(file, &local_iov, 1, ppos); | ||
2248 | } | ||
2249 | |||
2250 | /** | ||
59 | * ntfs_file_fsync - sync a file to disk | 2251 | * ntfs_file_fsync - sync a file to disk |
60 | * @filp: file to be synced | 2252 | * @filp: file to be synced |
61 | * @dentry: dentry describing the file to sync | 2253 | * @dentry: dentry describing the file to sync |
@@ -113,39 +2305,39 @@ static int ntfs_file_fsync(struct file *filp, struct dentry *dentry, | |||
113 | #endif /* NTFS_RW */ | 2305 | #endif /* NTFS_RW */ |
114 | 2306 | ||
115 | struct file_operations ntfs_file_ops = { | 2307 | struct file_operations ntfs_file_ops = { |
116 | .llseek = generic_file_llseek, /* Seek inside file. */ | 2308 | .llseek = generic_file_llseek, /* Seek inside file. */ |
117 | .read = generic_file_read, /* Read from file. */ | 2309 | .read = generic_file_read, /* Read from file. */ |
118 | .aio_read = generic_file_aio_read, /* Async read from file. */ | 2310 | .aio_read = generic_file_aio_read, /* Async read from file. */ |
119 | .readv = generic_file_readv, /* Read from file. */ | 2311 | .readv = generic_file_readv, /* Read from file. */ |
120 | #ifdef NTFS_RW | 2312 | #ifdef NTFS_RW |
121 | .write = generic_file_write, /* Write to file. */ | 2313 | .write = ntfs_file_write, /* Write to file. */ |
122 | .aio_write = generic_file_aio_write, /* Async write to file. */ | 2314 | .aio_write = ntfs_file_aio_write, /* Async write to file. */ |
123 | .writev = generic_file_writev, /* Write to file. */ | 2315 | .writev = ntfs_file_writev, /* Write to file. */ |
124 | /*.release = ,*/ /* Last file is closed. See | 2316 | /*.release = ,*/ /* Last file is closed. See |
125 | fs/ext2/file.c:: | 2317 | fs/ext2/file.c:: |
126 | ext2_release_file() for | 2318 | ext2_release_file() for |
127 | how to use this to discard | 2319 | how to use this to discard |
128 | preallocated space for | 2320 | preallocated space for |
129 | write opened files. */ | 2321 | write opened files. */ |
130 | .fsync = ntfs_file_fsync, /* Sync a file to disk. */ | 2322 | .fsync = ntfs_file_fsync, /* Sync a file to disk. */ |
131 | /*.aio_fsync = ,*/ /* Sync all outstanding async | 2323 | /*.aio_fsync = ,*/ /* Sync all outstanding async |
132 | i/o operations on a | 2324 | i/o operations on a |
133 | kiocb. */ | 2325 | kiocb. */ |
134 | #endif /* NTFS_RW */ | 2326 | #endif /* NTFS_RW */ |
135 | /*.ioctl = ,*/ /* Perform function on the | 2327 | /*.ioctl = ,*/ /* Perform function on the |
136 | mounted filesystem. */ | 2328 | mounted filesystem. */ |
137 | .mmap = generic_file_mmap, /* Mmap file. */ | 2329 | .mmap = generic_file_mmap, /* Mmap file. */ |
138 | .open = ntfs_file_open, /* Open file. */ | 2330 | .open = ntfs_file_open, /* Open file. */ |
139 | .sendfile = generic_file_sendfile, /* Zero-copy data send with | 2331 | .sendfile = generic_file_sendfile, /* Zero-copy data send with |
140 | the data source being on | 2332 | the data source being on |
141 | the ntfs partition. We | 2333 | the ntfs partition. We do |
142 | do not need to care about | 2334 | not need to care about the |
143 | the data destination. */ | 2335 | data destination. */ |
144 | /*.sendpage = ,*/ /* Zero-copy data send with | 2336 | /*.sendpage = ,*/ /* Zero-copy data send with |
145 | the data destination being | 2337 | the data destination being |
146 | on the ntfs partition. We | 2338 | on the ntfs partition. We |
147 | do not need to care about | 2339 | do not need to care about |
148 | the data source. */ | 2340 | the data source. */ |
149 | }; | 2341 | }; |
150 | 2342 | ||
151 | struct inode_operations ntfs_file_inode_ops = { | 2343 | struct inode_operations ntfs_file_inode_ops = { |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 7ec045131808..b24f4c4b2c5c 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "debug.h" | 30 | #include "debug.h" |
31 | #include "inode.h" | 31 | #include "inode.h" |
32 | #include "attrib.h" | 32 | #include "attrib.h" |
33 | #include "lcnalloc.h" | ||
33 | #include "malloc.h" | 34 | #include "malloc.h" |
34 | #include "mft.h" | 35 | #include "mft.h" |
35 | #include "time.h" | 36 | #include "time.h" |
@@ -2291,11 +2292,16 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) | |||
2291 | 2292 | ||
2292 | #ifdef NTFS_RW | 2293 | #ifdef NTFS_RW |
2293 | 2294 | ||
2295 | static const char *es = " Leaving inconsistent metadata. Unmount and run " | ||
2296 | "chkdsk."; | ||
2297 | |||
2294 | /** | 2298 | /** |
2295 | * ntfs_truncate - called when the i_size of an ntfs inode is changed | 2299 | * ntfs_truncate - called when the i_size of an ntfs inode is changed |
2296 | * @vi: inode for which the i_size was changed | 2300 | * @vi: inode for which the i_size was changed |
2297 | * | 2301 | * |
2298 | * We do not support i_size changes yet. | 2302 | * We only support i_size changes for normal files at present, i.e. not |
2303 | * compressed and not encrypted. This is enforced in ntfs_setattr(), see | ||
2304 | * below. | ||
2299 | * | 2305 | * |
2300 | * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and | 2306 | * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and |
2301 | * that the change is allowed. | 2307 | * that the change is allowed. |
@@ -2306,80 +2312,499 @@ int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt) | |||
2306 | * Returns 0 on success or -errno on error. | 2312 | * Returns 0 on success or -errno on error. |
2307 | * | 2313 | * |
2308 | * Called with ->i_sem held. In all but one case ->i_alloc_sem is held for | 2314 | * Called with ->i_sem held. In all but one case ->i_alloc_sem is held for |
2309 | * writing. The only case where ->i_alloc_sem is not held is | 2315 | * writing. The only case in the kernel where ->i_alloc_sem is not held is |
2310 | * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called | 2316 | * mm/filemap.c::generic_file_buffered_write() where vmtruncate() is called |
2311 | * with the current i_size as the offset which means that it is a noop as far | 2317 | * with the current i_size as the offset. The analogous place in NTFS is in |
2312 | * as ntfs_truncate() is concerned. | 2318 | * fs/ntfs/file.c::ntfs_file_buffered_write() where we call vmtruncate() again |
2319 | * without holding ->i_alloc_sem. | ||
2313 | */ | 2320 | */ |
2314 | int ntfs_truncate(struct inode *vi) | 2321 | int ntfs_truncate(struct inode *vi) |
2315 | { | 2322 | { |
2316 | ntfs_inode *ni = NTFS_I(vi); | 2323 | s64 new_size, old_size, nr_freed, new_alloc_size, old_alloc_size; |
2324 | VCN highest_vcn; | ||
2325 | unsigned long flags; | ||
2326 | ntfs_inode *base_ni, *ni = NTFS_I(vi); | ||
2317 | ntfs_volume *vol = ni->vol; | 2327 | ntfs_volume *vol = ni->vol; |
2318 | ntfs_attr_search_ctx *ctx; | 2328 | ntfs_attr_search_ctx *ctx; |
2319 | MFT_RECORD *m; | 2329 | MFT_RECORD *m; |
2320 | ATTR_RECORD *a; | 2330 | ATTR_RECORD *a; |
2321 | const char *te = " Leaving file length out of sync with i_size."; | 2331 | const char *te = " Leaving file length out of sync with i_size."; |
2322 | int err; | 2332 | int err, mp_size, size_change, alloc_change; |
2333 | u32 attr_len; | ||
2323 | 2334 | ||
2324 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); | 2335 | ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); |
2325 | BUG_ON(NInoAttr(ni)); | 2336 | BUG_ON(NInoAttr(ni)); |
2337 | BUG_ON(S_ISDIR(vi->i_mode)); | ||
2338 | BUG_ON(NInoMstProtected(ni)); | ||
2326 | BUG_ON(ni->nr_extents < 0); | 2339 | BUG_ON(ni->nr_extents < 0); |
2327 | m = map_mft_record(ni); | 2340 | retry_truncate: |
2341 | /* | ||
2342 | * Lock the runlist for writing and map the mft record to ensure it is | ||
2343 | * safe to mess with the attribute runlist and sizes. | ||
2344 | */ | ||
2345 | down_write(&ni->runlist.lock); | ||
2346 | if (!NInoAttr(ni)) | ||
2347 | base_ni = ni; | ||
2348 | else | ||
2349 | base_ni = ni->ext.base_ntfs_ino; | ||
2350 | m = map_mft_record(base_ni); | ||
2328 | if (IS_ERR(m)) { | 2351 | if (IS_ERR(m)) { |
2329 | err = PTR_ERR(m); | 2352 | err = PTR_ERR(m); |
2330 | ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " | 2353 | ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " |
2331 | "(error code %d).%s", vi->i_ino, err, te); | 2354 | "(error code %d).%s", vi->i_ino, err, te); |
2332 | ctx = NULL; | 2355 | ctx = NULL; |
2333 | m = NULL; | 2356 | m = NULL; |
2334 | goto err_out; | 2357 | goto old_bad_out; |
2335 | } | 2358 | } |
2336 | ctx = ntfs_attr_get_search_ctx(ni, m); | 2359 | ctx = ntfs_attr_get_search_ctx(base_ni, m); |
2337 | if (unlikely(!ctx)) { | 2360 | if (unlikely(!ctx)) { |
2338 | ntfs_error(vi->i_sb, "Failed to allocate a search context for " | 2361 | ntfs_error(vi->i_sb, "Failed to allocate a search context for " |
2339 | "inode 0x%lx (not enough memory).%s", | 2362 | "inode 0x%lx (not enough memory).%s", |
2340 | vi->i_ino, te); | 2363 | vi->i_ino, te); |
2341 | err = -ENOMEM; | 2364 | err = -ENOMEM; |
2342 | goto err_out; | 2365 | goto old_bad_out; |
2343 | } | 2366 | } |
2344 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, | 2367 | err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, |
2345 | CASE_SENSITIVE, 0, NULL, 0, ctx); | 2368 | CASE_SENSITIVE, 0, NULL, 0, ctx); |
2346 | if (unlikely(err)) { | 2369 | if (unlikely(err)) { |
2347 | if (err == -ENOENT) | 2370 | if (err == -ENOENT) { |
2348 | ntfs_error(vi->i_sb, "Open attribute is missing from " | 2371 | ntfs_error(vi->i_sb, "Open attribute is missing from " |
2349 | "mft record. Inode 0x%lx is corrupt. " | 2372 | "mft record. Inode 0x%lx is corrupt. " |
2350 | "Run chkdsk.", vi->i_ino); | 2373 | "Run chkdsk.%s", vi->i_ino, te); |
2351 | else | 2374 | err = -EIO; |
2375 | } else | ||
2352 | ntfs_error(vi->i_sb, "Failed to lookup attribute in " | 2376 | ntfs_error(vi->i_sb, "Failed to lookup attribute in " |
2353 | "inode 0x%lx (error code %d).", | 2377 | "inode 0x%lx (error code %d).%s", |
2354 | vi->i_ino, err); | 2378 | vi->i_ino, err, te); |
2355 | goto err_out; | 2379 | goto old_bad_out; |
2356 | } | 2380 | } |
2381 | m = ctx->mrec; | ||
2357 | a = ctx->attr; | 2382 | a = ctx->attr; |
2358 | /* If the size has not changed there is nothing to do. */ | 2383 | /* |
2359 | if (ntfs_attr_size(a) == i_size_read(vi)) | 2384 | * The i_size of the vfs inode is the new size for the attribute value. |
2360 | goto done; | 2385 | */ |
2361 | // TODO: Implement the truncate... | 2386 | new_size = i_size_read(vi); |
2362 | ntfs_error(vi->i_sb, "Inode size has changed but this is not " | 2387 | /* The current size of the attribute value is the old size. */ |
2363 | "implemented yet. Resetting inode size to old value. " | 2388 | old_size = ntfs_attr_size(a); |
2364 | " This is most likely a bug in the ntfs driver!"); | 2389 | /* Calculate the new allocated size. */ |
2365 | i_size_write(vi, ntfs_attr_size(a)); | 2390 | if (NInoNonResident(ni)) |
2366 | done: | 2391 | new_alloc_size = (new_size + vol->cluster_size - 1) & |
2392 | ~(s64)vol->cluster_size_mask; | ||
2393 | else | ||
2394 | new_alloc_size = (new_size + 7) & ~7; | ||
2395 | /* The current allocated size is the old allocated size. */ | ||
2396 | read_lock_irqsave(&ni->size_lock, flags); | ||
2397 | old_alloc_size = ni->allocated_size; | ||
2398 | read_unlock_irqrestore(&ni->size_lock, flags); | ||
2399 | /* | ||
2400 | * The change in the file size. This will be 0 if no change, >0 if the | ||
2401 | * size is growing, and <0 if the size is shrinking. | ||
2402 | */ | ||
2403 | size_change = -1; | ||
2404 | if (new_size - old_size >= 0) { | ||
2405 | size_change = 1; | ||
2406 | if (new_size == old_size) | ||
2407 | size_change = 0; | ||
2408 | } | ||
2409 | /* As above for the allocated size. */ | ||
2410 | alloc_change = -1; | ||
2411 | if (new_alloc_size - old_alloc_size >= 0) { | ||
2412 | alloc_change = 1; | ||
2413 | if (new_alloc_size == old_alloc_size) | ||
2414 | alloc_change = 0; | ||
2415 | } | ||
2416 | /* | ||
2417 | * If neither the size nor the allocation are being changed there is | ||
2418 | * nothing to do. | ||
2419 | */ | ||
2420 | if (!size_change && !alloc_change) | ||
2421 | goto unm_done; | ||
2422 | /* If the size is changing, check if new size is allowed in $AttrDef. */ | ||
2423 | if (size_change) { | ||
2424 | err = ntfs_attr_size_bounds_check(vol, ni->type, new_size); | ||
2425 | if (unlikely(err)) { | ||
2426 | if (err == -ERANGE) { | ||
2427 | ntfs_error(vol->sb, "Truncate would cause the " | ||
2428 | "inode 0x%lx to %simum size " | ||
2429 | "for its attribute type " | ||
2430 | "(0x%x). Aborting truncate.", | ||
2431 | vi->i_ino, | ||
2432 | new_size > old_size ? "exceed " | ||
2433 | "the max" : "go under the min", | ||
2434 | le32_to_cpu(ni->type)); | ||
2435 | err = -EFBIG; | ||
2436 | } else { | ||
2437 | ntfs_error(vol->sb, "Inode 0x%lx has unknown " | ||
2438 | "attribute type 0x%x. " | ||
2439 | "Aborting truncate.", | ||
2440 | vi->i_ino, | ||
2441 | le32_to_cpu(ni->type)); | ||
2442 | err = -EIO; | ||
2443 | } | ||
2444 | /* Reset the vfs inode size to the old size. */ | ||
2445 | i_size_write(vi, old_size); | ||
2446 | goto err_out; | ||
2447 | } | ||
2448 | } | ||
2449 | if (NInoCompressed(ni) || NInoEncrypted(ni)) { | ||
2450 | ntfs_warning(vi->i_sb, "Changes in inode size are not " | ||
2451 | "supported yet for %s files, ignoring.", | ||
2452 | NInoCompressed(ni) ? "compressed" : | ||
2453 | "encrypted"); | ||
2454 | err = -EOPNOTSUPP; | ||
2455 | goto bad_out; | ||
2456 | } | ||
2457 | if (a->non_resident) | ||
2458 | goto do_non_resident_truncate; | ||
2459 | BUG_ON(NInoNonResident(ni)); | ||
2460 | /* Resize the attribute record to best fit the new attribute size. */ | ||
2461 | if (new_size < vol->mft_record_size && | ||
2462 | !ntfs_resident_attr_value_resize(m, a, new_size)) { | ||
2463 | unsigned long flags; | ||
2464 | |||
2465 | /* The resize succeeded! */ | ||
2466 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2467 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2468 | write_lock_irqsave(&ni->size_lock, flags); | ||
2469 | /* Update the sizes in the ntfs inode and all is done. */ | ||
2470 | ni->allocated_size = le32_to_cpu(a->length) - | ||
2471 | le16_to_cpu(a->data.resident.value_offset); | ||
2472 | /* | ||
2473 | * Note ntfs_resident_attr_value_resize() has already done any | ||
2474 | * necessary data clearing in the attribute record. When the | ||
2475 | * file is being shrunk vmtruncate() will already have cleared | ||
2476 | * the top part of the last partial page, i.e. since this is | ||
2477 | * the resident case this is the page with index 0. However, | ||
2478 | * when the file is being expanded, the page cache page data | ||
2479 | * between the old data_size, i.e. old_size, and the new_size | ||
2480 | * has not been zeroed. Fortunately, we do not need to zero it | ||
2481 | * either since on one hand it will either already be zero due | ||
2482 | * to both readpage and writepage clearing partial page data | ||
2483 | * beyond i_size in which case there is nothing to do or in the | ||
2484 | * case of the file being mmap()ped at the same time, POSIX | ||
2485 | * specifies that the behaviour is unspecified thus we do not | ||
2486 | * have to do anything. This means that in our implementation | ||
2487 | * in the rare case that the file is mmap()ped and a write | ||
2488 | * occured into the mmap()ped region just beyond the file size | ||
2489 | * and writepage has not yet been called to write out the page | ||
2490 | * (which would clear the area beyond the file size) and we now | ||
2491 | * extend the file size to incorporate this dirty region | ||
2492 | * outside the file size, a write of the page would result in | ||
2493 | * this data being written to disk instead of being cleared. | ||
2494 | * Given both POSIX and the Linux mmap(2) man page specify that | ||
2495 | * this corner case is undefined, we choose to leave it like | ||
2496 | * that as this is much simpler for us as we cannot lock the | ||
2497 | * relevant page now since we are holding too many ntfs locks | ||
2498 | * which would result in a lock reversal deadlock. | ||
2499 | */ | ||
2500 | ni->initialized_size = new_size; | ||
2501 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2502 | goto unm_done; | ||
2503 | } | ||
2504 | /* If the above resize failed, this must be an attribute extension. */ | ||
2505 | BUG_ON(size_change < 0); | ||
2506 | /* | ||
2507 | * We have to drop all the locks so we can call | ||
2508 | * ntfs_attr_make_non_resident(). This could be optimised by try- | ||
2509 | * locking the first page cache page and only if that fails dropping | ||
2510 | * the locks, locking the page, and redoing all the locking and | ||
2511 | * lookups. While this would be a huge optimisation, it is not worth | ||
2512 | * it as this is definitely a slow code path as it only ever can happen | ||
2513 | * once for any given file. | ||
2514 | */ | ||
2367 | ntfs_attr_put_search_ctx(ctx); | 2515 | ntfs_attr_put_search_ctx(ctx); |
2368 | unmap_mft_record(ni); | 2516 | unmap_mft_record(base_ni); |
2369 | NInoClearTruncateFailed(ni); | 2517 | up_write(&ni->runlist.lock); |
2370 | ntfs_debug("Done."); | 2518 | /* |
2371 | return 0; | 2519 | * Not enough space in the mft record, try to make the attribute |
2372 | err_out: | 2520 | * non-resident and if successful restart the truncation process. |
2373 | if (err != -ENOMEM) { | 2521 | */ |
2522 | err = ntfs_attr_make_non_resident(ni, old_size); | ||
2523 | if (likely(!err)) | ||
2524 | goto retry_truncate; | ||
2525 | /* | ||
2526 | * Could not make non-resident. If this is due to this not being | ||
2527 | * permitted for this attribute type or there not being enough space, | ||
2528 | * try to make other attributes non-resident. Otherwise fail. | ||
2529 | */ | ||
2530 | if (unlikely(err != -EPERM && err != -ENOSPC)) { | ||
2531 | ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, attribute " | ||
2532 | "type 0x%x, because the conversion from " | ||
2533 | "resident to non-resident attribute failed " | ||
2534 | "with error code %i.", vi->i_ino, | ||
2535 | (unsigned)le32_to_cpu(ni->type), err); | ||
2536 | if (err != -ENOMEM) | ||
2537 | err = -EIO; | ||
2538 | goto conv_err_out; | ||
2539 | } | ||
2540 | /* TODO: Not implemented from here, abort. */ | ||
2541 | if (err == -ENOSPC) | ||
2542 | ntfs_error(vol->sb, "Not enough space in the mft record/on " | ||
2543 | "disk for the non-resident attribute value. " | ||
2544 | "This case is not implemented yet."); | ||
2545 | else /* if (err == -EPERM) */ | ||
2546 | ntfs_error(vol->sb, "This attribute type may not be " | ||
2547 | "non-resident. This case is not implemented " | ||
2548 | "yet."); | ||
2549 | err = -EOPNOTSUPP; | ||
2550 | goto conv_err_out; | ||
2551 | #if 0 | ||
2552 | // TODO: Attempt to make other attributes non-resident. | ||
2553 | if (!err) | ||
2554 | goto do_resident_extend; | ||
2555 | /* | ||
2556 | * Both the attribute list attribute and the standard information | ||
2557 | * attribute must remain in the base inode. Thus, if this is one of | ||
2558 | * these attributes, we have to try to move other attributes out into | ||
2559 | * extent mft records instead. | ||
2560 | */ | ||
2561 | if (ni->type == AT_ATTRIBUTE_LIST || | ||
2562 | ni->type == AT_STANDARD_INFORMATION) { | ||
2563 | // TODO: Attempt to move other attributes into extent mft | ||
2564 | // records. | ||
2565 | err = -EOPNOTSUPP; | ||
2566 | if (!err) | ||
2567 | goto do_resident_extend; | ||
2568 | goto err_out; | ||
2569 | } | ||
2570 | // TODO: Attempt to move this attribute to an extent mft record, but | ||
2571 | // only if it is not already the only attribute in an mft record in | ||
2572 | // which case there would be nothing to gain. | ||
2573 | err = -EOPNOTSUPP; | ||
2574 | if (!err) | ||
2575 | goto do_resident_extend; | ||
2576 | /* There is nothing we can do to make enough space. )-: */ | ||
2577 | goto err_out; | ||
2578 | #endif | ||
2579 | do_non_resident_truncate: | ||
2580 | BUG_ON(!NInoNonResident(ni)); | ||
2581 | if (alloc_change < 0) { | ||
2582 | highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); | ||
2583 | if (highest_vcn > 0 && | ||
2584 | old_alloc_size >> vol->cluster_size_bits > | ||
2585 | highest_vcn + 1) { | ||
2586 | /* | ||
2587 | * This attribute has multiple extents. Not yet | ||
2588 | * supported. | ||
2589 | */ | ||
2590 | ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, " | ||
2591 | "attribute type 0x%x, because the " | ||
2592 | "attribute is highly fragmented (it " | ||
2593 | "consists of multiple extents) and " | ||
2594 | "this case is not implemented yet.", | ||
2595 | vi->i_ino, | ||
2596 | (unsigned)le32_to_cpu(ni->type)); | ||
2597 | err = -EOPNOTSUPP; | ||
2598 | goto bad_out; | ||
2599 | } | ||
2600 | } | ||
2601 | /* | ||
2602 | * If the size is shrinking, need to reduce the initialized_size and | ||
2603 | * the data_size before reducing the allocation. | ||
2604 | */ | ||
2605 | if (size_change < 0) { | ||
2606 | /* | ||
2607 | * Make the valid size smaller (i_size is already up-to-date). | ||
2608 | */ | ||
2609 | write_lock_irqsave(&ni->size_lock, flags); | ||
2610 | if (new_size < ni->initialized_size) { | ||
2611 | ni->initialized_size = new_size; | ||
2612 | a->data.non_resident.initialized_size = | ||
2613 | cpu_to_sle64(new_size); | ||
2614 | } | ||
2615 | a->data.non_resident.data_size = cpu_to_sle64(new_size); | ||
2616 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2617 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2618 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2619 | /* If the allocated size is not changing, we are done. */ | ||
2620 | if (!alloc_change) | ||
2621 | goto unm_done; | ||
2622 | /* | ||
2623 | * If the size is shrinking it makes no sense for the | ||
2624 | * allocation to be growing. | ||
2625 | */ | ||
2626 | BUG_ON(alloc_change > 0); | ||
2627 | } else /* if (size_change >= 0) */ { | ||
2628 | /* | ||
2629 | * The file size is growing or staying the same but the | ||
2630 | * allocation can be shrinking, growing or staying the same. | ||
2631 | */ | ||
2632 | if (alloc_change > 0) { | ||
2633 | /* | ||
2634 | * We need to extend the allocation and possibly update | ||
2635 | * the data size. If we are updating the data size, | ||
2636 | * since we are not touching the initialized_size we do | ||
2637 | * not need to worry about the actual data on disk. | ||
2638 | * And as far as the page cache is concerned, there | ||
2639 | * will be no pages beyond the old data size and any | ||
2640 | * partial region in the last page between the old and | ||
2641 | * new data size (or the end of the page if the new | ||
2642 | * data size is outside the page) does not need to be | ||
2643 | * modified as explained above for the resident | ||
2644 | * attribute truncate case. To do this, we simply drop | ||
2645 | * the locks we hold and leave all the work to our | ||
2646 | * friendly helper ntfs_attr_extend_allocation(). | ||
2647 | */ | ||
2648 | ntfs_attr_put_search_ctx(ctx); | ||
2649 | unmap_mft_record(base_ni); | ||
2650 | up_write(&ni->runlist.lock); | ||
2651 | err = ntfs_attr_extend_allocation(ni, new_size, | ||
2652 | size_change > 0 ? new_size : -1, -1); | ||
2653 | /* | ||
2654 | * ntfs_attr_extend_allocation() will have done error | ||
2655 | * output already. | ||
2656 | */ | ||
2657 | goto done; | ||
2658 | } | ||
2659 | if (!alloc_change) | ||
2660 | goto alloc_done; | ||
2661 | } | ||
2662 | /* alloc_change < 0 */ | ||
2663 | /* Free the clusters. */ | ||
2664 | nr_freed = ntfs_cluster_free(ni, new_alloc_size >> | ||
2665 | vol->cluster_size_bits, -1, ctx); | ||
2666 | m = ctx->mrec; | ||
2667 | a = ctx->attr; | ||
2668 | if (unlikely(nr_freed < 0)) { | ||
2669 | ntfs_error(vol->sb, "Failed to release cluster(s) (error code " | ||
2670 | "%lli). Unmount and run chkdsk to recover " | ||
2671 | "the lost cluster(s).", (long long)nr_freed); | ||
2374 | NVolSetErrors(vol); | 2672 | NVolSetErrors(vol); |
2673 | nr_freed = 0; | ||
2674 | } | ||
2675 | /* Truncate the runlist. */ | ||
2676 | err = ntfs_rl_truncate_nolock(vol, &ni->runlist, | ||
2677 | new_alloc_size >> vol->cluster_size_bits); | ||
2678 | /* | ||
2679 | * If the runlist truncation failed and/or the search context is no | ||
2680 | * longer valid, we cannot resize the attribute record or build the | ||
2681 | * mapping pairs array thus we mark the inode bad so that no access to | ||
2682 | * the freed clusters can happen. | ||
2683 | */ | ||
2684 | if (unlikely(err || IS_ERR(m))) { | ||
2685 | ntfs_error(vol->sb, "Failed to %s (error code %li).%s", | ||
2686 | IS_ERR(m) ? | ||
2687 | "restore attribute search context" : | ||
2688 | "truncate attribute runlist", | ||
2689 | IS_ERR(m) ? PTR_ERR(m) : err, es); | ||
2690 | err = -EIO; | ||
2691 | goto bad_out; | ||
2692 | } | ||
2693 | /* Get the size for the shrunk mapping pairs array for the runlist. */ | ||
2694 | mp_size = ntfs_get_size_for_mapping_pairs(vol, ni->runlist.rl, 0, -1); | ||
2695 | if (unlikely(mp_size <= 0)) { | ||
2696 | ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " | ||
2697 | "attribute type 0x%x, because determining the " | ||
2698 | "size for the mapping pairs failed with error " | ||
2699 | "code %i.%s", vi->i_ino, | ||
2700 | (unsigned)le32_to_cpu(ni->type), mp_size, es); | ||
2701 | err = -EIO; | ||
2702 | goto bad_out; | ||
2703 | } | ||
2704 | /* | ||
2705 | * Shrink the attribute record for the new mapping pairs array. Note, | ||
2706 | * this cannot fail since we are making the attribute smaller thus by | ||
2707 | * definition there is enough space to do so. | ||
2708 | */ | ||
2709 | attr_len = le32_to_cpu(a->length); | ||
2710 | err = ntfs_attr_record_resize(m, a, mp_size + | ||
2711 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); | ||
2712 | BUG_ON(err); | ||
2713 | /* | ||
2714 | * Generate the mapping pairs array directly into the attribute record. | ||
2715 | */ | ||
2716 | err = ntfs_mapping_pairs_build(vol, (u8*)a + | ||
2717 | le16_to_cpu(a->data.non_resident.mapping_pairs_offset), | ||
2718 | mp_size, ni->runlist.rl, 0, -1, NULL); | ||
2719 | if (unlikely(err)) { | ||
2720 | ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " | ||
2721 | "attribute type 0x%x, because building the " | ||
2722 | "mapping pairs failed with error code %i.%s", | ||
2723 | vi->i_ino, (unsigned)le32_to_cpu(ni->type), | ||
2724 | err, es); | ||
2725 | err = -EIO; | ||
2726 | goto bad_out; | ||
2727 | } | ||
2728 | /* Update the allocated/compressed size as well as the highest vcn. */ | ||
2729 | a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> | ||
2730 | vol->cluster_size_bits) - 1); | ||
2731 | write_lock_irqsave(&ni->size_lock, flags); | ||
2732 | ni->allocated_size = new_alloc_size; | ||
2733 | a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); | ||
2734 | if (NInoSparse(ni) || NInoCompressed(ni)) { | ||
2735 | if (nr_freed) { | ||
2736 | ni->itype.compressed.size -= nr_freed << | ||
2737 | vol->cluster_size_bits; | ||
2738 | BUG_ON(ni->itype.compressed.size < 0); | ||
2739 | a->data.non_resident.compressed_size = cpu_to_sle64( | ||
2740 | ni->itype.compressed.size); | ||
2741 | vi->i_blocks = ni->itype.compressed.size >> 9; | ||
2742 | } | ||
2743 | } else | ||
2744 | vi->i_blocks = new_alloc_size >> 9; | ||
2745 | write_unlock_irqrestore(&ni->size_lock, flags); | ||
2746 | /* | ||
2747 | * We have shrunk the allocation. If this is a shrinking truncate we | ||
2748 | * have already dealt with the initialized_size and the data_size above | ||
2749 | * and we are done. If the truncate is only changing the allocation | ||
2750 | * and not the data_size, we are also done. If this is an extending | ||
2751 | * truncate, need to extend the data_size now which is ensured by the | ||
2752 | * fact that @size_change is positive. | ||
2753 | */ | ||
2754 | alloc_done: | ||
2755 | /* | ||
2756 | * If the size is growing, need to update it now. If it is shrinking, | ||
2757 | * we have already updated it above (before the allocation change). | ||
2758 | */ | ||
2759 | if (size_change > 0) | ||
2760 | a->data.non_resident.data_size = cpu_to_sle64(new_size); | ||
2761 | /* Ensure the modified mft record is written out. */ | ||
2762 | flush_dcache_mft_record_page(ctx->ntfs_ino); | ||
2763 | mark_mft_record_dirty(ctx->ntfs_ino); | ||
2764 | unm_done: | ||
2765 | ntfs_attr_put_search_ctx(ctx); | ||
2766 | unmap_mft_record(base_ni); | ||
2767 | up_write(&ni->runlist.lock); | ||
2768 | done: | ||
2769 | /* Update the mtime and ctime on the base inode. */ | ||
2770 | inode_update_time(VFS_I(base_ni), 1); | ||
2771 | if (likely(!err)) { | ||
2772 | NInoClearTruncateFailed(ni); | ||
2773 | ntfs_debug("Done."); | ||
2774 | } | ||
2775 | return err; | ||
2776 | old_bad_out: | ||
2777 | old_size = -1; | ||
2778 | bad_out: | ||
2779 | if (err != -ENOMEM && err != -EOPNOTSUPP) { | ||
2375 | make_bad_inode(vi); | 2780 | make_bad_inode(vi); |
2781 | make_bad_inode(VFS_I(base_ni)); | ||
2782 | NVolSetErrors(vol); | ||
2376 | } | 2783 | } |
2784 | if (err != -EOPNOTSUPP) | ||
2785 | NInoSetTruncateFailed(ni); | ||
2786 | else if (old_size >= 0) | ||
2787 | i_size_write(vi, old_size); | ||
2788 | err_out: | ||
2377 | if (ctx) | 2789 | if (ctx) |
2378 | ntfs_attr_put_search_ctx(ctx); | 2790 | ntfs_attr_put_search_ctx(ctx); |
2379 | if (m) | 2791 | if (m) |
2380 | unmap_mft_record(ni); | 2792 | unmap_mft_record(base_ni); |
2381 | NInoSetTruncateFailed(ni); | 2793 | up_write(&ni->runlist.lock); |
2794 | out: | ||
2795 | ntfs_debug("Failed. Returning error code %i.", err); | ||
2382 | return err; | 2796 | return err; |
2797 | conv_err_out: | ||
2798 | if (err != -ENOMEM && err != -EOPNOTSUPP) { | ||
2799 | make_bad_inode(vi); | ||
2800 | make_bad_inode(VFS_I(base_ni)); | ||
2801 | NVolSetErrors(vol); | ||
2802 | } | ||
2803 | if (err != -EOPNOTSUPP) | ||
2804 | NInoSetTruncateFailed(ni); | ||
2805 | else | ||
2806 | i_size_write(vi, old_size); | ||
2807 | goto out; | ||
2383 | } | 2808 | } |
2384 | 2809 | ||
2385 | /** | 2810 | /** |
@@ -2420,8 +2845,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
2420 | 2845 | ||
2421 | err = inode_change_ok(vi, attr); | 2846 | err = inode_change_ok(vi, attr); |
2422 | if (err) | 2847 | if (err) |
2423 | return err; | 2848 | goto out; |
2424 | |||
2425 | /* We do not support NTFS ACLs yet. */ | 2849 | /* We do not support NTFS ACLs yet. */ |
2426 | if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) { | 2850 | if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) { |
2427 | ntfs_warning(vi->i_sb, "Changes in user/group/mode are not " | 2851 | ntfs_warning(vi->i_sb, "Changes in user/group/mode are not " |
@@ -2429,14 +2853,22 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
2429 | err = -EOPNOTSUPP; | 2853 | err = -EOPNOTSUPP; |
2430 | goto out; | 2854 | goto out; |
2431 | } | 2855 | } |
2432 | |||
2433 | if (ia_valid & ATTR_SIZE) { | 2856 | if (ia_valid & ATTR_SIZE) { |
2434 | if (attr->ia_size != i_size_read(vi)) { | 2857 | if (attr->ia_size != i_size_read(vi)) { |
2435 | ntfs_warning(vi->i_sb, "Changes in inode size are not " | 2858 | ntfs_inode *ni = NTFS_I(vi); |
2436 | "supported yet, ignoring."); | 2859 | /* |
2437 | err = -EOPNOTSUPP; | 2860 | * FIXME: For now we do not support resizing of |
2438 | // TODO: Implement... | 2861 | * compressed or encrypted files yet. |
2439 | // err = vmtruncate(vi, attr->ia_size); | 2862 | */ |
2863 | if (NInoCompressed(ni) || NInoEncrypted(ni)) { | ||
2864 | ntfs_warning(vi->i_sb, "Changes in inode size " | ||
2865 | "are not supported yet for " | ||
2866 | "%s files, ignoring.", | ||
2867 | NInoCompressed(ni) ? | ||
2868 | "compressed" : "encrypted"); | ||
2869 | err = -EOPNOTSUPP; | ||
2870 | } else | ||
2871 | err = vmtruncate(vi, attr->ia_size); | ||
2440 | if (err || ia_valid == ATTR_SIZE) | 2872 | if (err || ia_valid == ATTR_SIZE) |
2441 | goto out; | 2873 | goto out; |
2442 | } else { | 2874 | } else { |
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 5c248d404f05..f5678d5d7919 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h | |||
@@ -1021,10 +1021,17 @@ enum { | |||
1021 | FILE_NAME_POSIX = 0x00, | 1021 | FILE_NAME_POSIX = 0x00, |
1022 | /* This is the largest namespace. It is case sensitive and allows all | 1022 | /* This is the largest namespace. It is case sensitive and allows all |
1023 | Unicode characters except for: '\0' and '/'. Beware that in | 1023 | Unicode characters except for: '\0' and '/'. Beware that in |
1024 | WinNT/2k files which eg have the same name except for their case | 1024 | WinNT/2k/2003 by default files which eg have the same name except |
1025 | will not be distinguished by the standard utilities and thus a "del | 1025 | for their case will not be distinguished by the standard utilities |
1026 | filename" will delete both "filename" and "fileName" without | 1026 | and thus a "del filename" will delete both "filename" and "fileName" |
1027 | warning. */ | 1027 | without warning. However if for example Services For Unix (SFU) are |
1028 | installed and the case sensitive option was enabled at installation | ||
1029 | time, then you can create/access/delete such files. | ||
1030 | Note that even SFU places restrictions on the filenames beyond the | ||
1031 | '\0' and '/' and in particular the following set of characters is | ||
1032 | not allowed: '"', '/', '<', '>', '\'. All other characters, | ||
1033 | including the ones no allowed in WIN32 namespace are allowed. | ||
1034 | Tested with SFU 3.5 (this is now free) running on Windows XP. */ | ||
1028 | FILE_NAME_WIN32 = 0x01, | 1035 | FILE_NAME_WIN32 = 0x01, |
1029 | /* The standard WinNT/2k NTFS long filenames. Case insensitive. All | 1036 | /* The standard WinNT/2k NTFS long filenames. Case insensitive. All |
1030 | Unicode chars except: '\0', '"', '*', '/', ':', '<', '>', '?', '\', | 1037 | Unicode chars except: '\0', '"', '*', '/', ':', '<', '>', '?', '\', |
@@ -2367,7 +2374,9 @@ typedef struct { | |||
2367 | * Extended attribute flags (8-bit). | 2374 | * Extended attribute flags (8-bit). |
2368 | */ | 2375 | */ |
2369 | enum { | 2376 | enum { |
2370 | NEED_EA = 0x80 | 2377 | NEED_EA = 0x80 /* If set the file to which the EA belongs |
2378 | cannot be interpreted without understanding | ||
2379 | the associates extended attributes. */ | ||
2371 | } __attribute__ ((__packed__)); | 2380 | } __attribute__ ((__packed__)); |
2372 | 2381 | ||
2373 | typedef u8 EA_FLAGS; | 2382 | typedef u8 EA_FLAGS; |
@@ -2375,20 +2384,20 @@ typedef u8 EA_FLAGS; | |||
2375 | /* | 2384 | /* |
2376 | * Attribute: Extended attribute (EA) (0xe0). | 2385 | * Attribute: Extended attribute (EA) (0xe0). |
2377 | * | 2386 | * |
2378 | * NOTE: Always non-resident. (Is this true?) | 2387 | * NOTE: Can be resident or non-resident. |
2379 | * | 2388 | * |
2380 | * Like the attribute list and the index buffer list, the EA attribute value is | 2389 | * Like the attribute list and the index buffer list, the EA attribute value is |
2381 | * a sequence of EA_ATTR variable length records. | 2390 | * a sequence of EA_ATTR variable length records. |
2382 | * | ||
2383 | * FIXME: It appears weird that the EA name is not unicode. Is it true? | ||
2384 | */ | 2391 | */ |
2385 | typedef struct { | 2392 | typedef struct { |
2386 | le32 next_entry_offset; /* Offset to the next EA_ATTR. */ | 2393 | le32 next_entry_offset; /* Offset to the next EA_ATTR. */ |
2387 | EA_FLAGS flags; /* Flags describing the EA. */ | 2394 | EA_FLAGS flags; /* Flags describing the EA. */ |
2388 | u8 ea_name_length; /* Length of the name of the EA in bytes. */ | 2395 | u8 ea_name_length; /* Length of the name of the EA in bytes |
2396 | excluding the '\0' byte terminator. */ | ||
2389 | le16 ea_value_length; /* Byte size of the EA's value. */ | 2397 | le16 ea_value_length; /* Byte size of the EA's value. */ |
2390 | u8 ea_name[0]; /* Name of the EA. */ | 2398 | u8 ea_name[0]; /* Name of the EA. Note this is ASCII, not |
2391 | u8 ea_value[0]; /* The value of the EA. Immediately follows | 2399 | Unicode and it is zero terminated. */ |
2400 | u8 ea_value[0]; /* The value of the EA. Immediately follows | ||
2392 | the name. */ | 2401 | the name. */ |
2393 | } __attribute__ ((__packed__)) EA_ATTR; | 2402 | } __attribute__ ((__packed__)) EA_ATTR; |
2394 | 2403 | ||
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c index 5af3bf0b7eee..29cabf93d2d2 100644 --- a/fs/ntfs/lcnalloc.c +++ b/fs/ntfs/lcnalloc.c | |||
@@ -76,6 +76,7 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | |||
76 | * @count: number of clusters to allocate | 76 | * @count: number of clusters to allocate |
77 | * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none) | 77 | * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none) |
78 | * @zone: zone from which to allocate the clusters | 78 | * @zone: zone from which to allocate the clusters |
79 | * @is_extension: if TRUE, this is an attribute extension | ||
79 | * | 80 | * |
80 | * Allocate @count clusters preferably starting at cluster @start_lcn or at the | 81 | * Allocate @count clusters preferably starting at cluster @start_lcn or at the |
81 | * current allocator position if @start_lcn is -1, on the mounted ntfs volume | 82 | * current allocator position if @start_lcn is -1, on the mounted ntfs volume |
@@ -86,6 +87,13 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | |||
86 | * @start_vcn specifies the vcn of the first allocated cluster. This makes | 87 | * @start_vcn specifies the vcn of the first allocated cluster. This makes |
87 | * merging the resulting runlist with the old runlist easier. | 88 | * merging the resulting runlist with the old runlist easier. |
88 | * | 89 | * |
90 | * If @is_extension is TRUE, the caller is allocating clusters to extend an | ||
91 | * attribute and if it is FALSE, the caller is allocating clusters to fill a | ||
92 | * hole in an attribute. Practically the difference is that if @is_extension | ||
93 | * is TRUE the returned runlist will be terminated with LCN_ENOENT and if | ||
94 | * @is_extension is FALSE the runlist will be terminated with | ||
95 | * LCN_RL_NOT_MAPPED. | ||
96 | * | ||
89 | * You need to check the return value with IS_ERR(). If this is false, the | 97 | * You need to check the return value with IS_ERR(). If this is false, the |
90 | * function was successful and the return value is a runlist describing the | 98 | * function was successful and the return value is a runlist describing the |
91 | * allocated cluster(s). If IS_ERR() is true, the function failed and | 99 | * allocated cluster(s). If IS_ERR() is true, the function failed and |
@@ -137,7 +145,8 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | |||
137 | */ | 145 | */ |
138 | runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, | 146 | runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, |
139 | const s64 count, const LCN start_lcn, | 147 | const s64 count, const LCN start_lcn, |
140 | const NTFS_CLUSTER_ALLOCATION_ZONES zone) | 148 | const NTFS_CLUSTER_ALLOCATION_ZONES zone, |
149 | const BOOL is_extension) | ||
141 | { | 150 | { |
142 | LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn; | 151 | LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn; |
143 | LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size; | 152 | LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size; |
@@ -310,7 +319,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, | |||
310 | continue; | 319 | continue; |
311 | } | 320 | } |
312 | bit = 1 << (lcn & 7); | 321 | bit = 1 << (lcn & 7); |
313 | ntfs_debug("bit %i.", bit); | 322 | ntfs_debug("bit 0x%x.", bit); |
314 | /* If the bit is already set, go onto the next one. */ | 323 | /* If the bit is already set, go onto the next one. */ |
315 | if (*byte & bit) { | 324 | if (*byte & bit) { |
316 | lcn++; | 325 | lcn++; |
@@ -729,7 +738,7 @@ out: | |||
729 | /* Add runlist terminator element. */ | 738 | /* Add runlist terminator element. */ |
730 | if (likely(rl)) { | 739 | if (likely(rl)) { |
731 | rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; | 740 | rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; |
732 | rl[rlpos].lcn = LCN_RL_NOT_MAPPED; | 741 | rl[rlpos].lcn = is_extension ? LCN_ENOENT : LCN_RL_NOT_MAPPED; |
733 | rl[rlpos].length = 0; | 742 | rl[rlpos].length = 0; |
734 | } | 743 | } |
735 | if (likely(page && !IS_ERR(page))) { | 744 | if (likely(page && !IS_ERR(page))) { |
@@ -782,6 +791,7 @@ out: | |||
782 | * @ni: ntfs inode whose runlist describes the clusters to free | 791 | * @ni: ntfs inode whose runlist describes the clusters to free |
783 | * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters | 792 | * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters |
784 | * @count: number of clusters to free or -1 for all clusters | 793 | * @count: number of clusters to free or -1 for all clusters |
794 | * @ctx: active attribute search context if present or NULL if not | ||
785 | * @is_rollback: true if this is a rollback operation | 795 | * @is_rollback: true if this is a rollback operation |
786 | * | 796 | * |
787 | * Free @count clusters starting at the cluster @start_vcn in the runlist | 797 | * Free @count clusters starting at the cluster @start_vcn in the runlist |
@@ -791,15 +801,39 @@ out: | |||
791 | * deallocated. Thus, to completely free all clusters in a runlist, use | 801 | * deallocated. Thus, to completely free all clusters in a runlist, use |
792 | * @start_vcn = 0 and @count = -1. | 802 | * @start_vcn = 0 and @count = -1. |
793 | * | 803 | * |
804 | * If @ctx is specified, it is an active search context of @ni and its base mft | ||
805 | * record. This is needed when __ntfs_cluster_free() encounters unmapped | ||
806 | * runlist fragments and allows their mapping. If you do not have the mft | ||
807 | * record mapped, you can specify @ctx as NULL and __ntfs_cluster_free() will | ||
808 | * perform the necessary mapping and unmapping. | ||
809 | * | ||
810 | * Note, __ntfs_cluster_free() saves the state of @ctx on entry and restores it | ||
811 | * before returning. Thus, @ctx will be left pointing to the same attribute on | ||
812 | * return as on entry. However, the actual pointers in @ctx may point to | ||
813 | * different memory locations on return, so you must remember to reset any | ||
814 | * cached pointers from the @ctx, i.e. after the call to __ntfs_cluster_free(), | ||
815 | * you will probably want to do: | ||
816 | * m = ctx->mrec; | ||
817 | * a = ctx->attr; | ||
818 | * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that | ||
819 | * you cache ctx->mrec in a variable @m of type MFT_RECORD *. | ||
820 | * | ||
794 | * @is_rollback should always be FALSE, it is for internal use to rollback | 821 | * @is_rollback should always be FALSE, it is for internal use to rollback |
795 | * errors. You probably want to use ntfs_cluster_free() instead. | 822 | * errors. You probably want to use ntfs_cluster_free() instead. |
796 | * | 823 | * |
797 | * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller | 824 | * Note, __ntfs_cluster_free() does not modify the runlist, so you have to |
798 | * has to deal with it later. | 825 | * remove from the runlist or mark sparse the freed runs later. |
799 | * | 826 | * |
800 | * Return the number of deallocated clusters (not counting sparse ones) on | 827 | * Return the number of deallocated clusters (not counting sparse ones) on |
801 | * success and -errno on error. | 828 | * success and -errno on error. |
802 | * | 829 | * |
830 | * WARNING: If @ctx is supplied, regardless of whether success or failure is | ||
831 | * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx | ||
832 | * is no longer valid, i.e. you need to either call | ||
833 | * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. | ||
834 | * In that case PTR_ERR(@ctx->mrec) will give you the error code for | ||
835 | * why the mapping of the old inode failed. | ||
836 | * | ||
803 | * Locking: - The runlist described by @ni must be locked for writing on entry | 837 | * Locking: - The runlist described by @ni must be locked for writing on entry |
804 | * and is locked on return. Note the runlist may be modified when | 838 | * and is locked on return. Note the runlist may be modified when |
805 | * needed runlist fragments need to be mapped. | 839 | * needed runlist fragments need to be mapped. |
@@ -807,9 +841,13 @@ out: | |||
807 | * on return. | 841 | * on return. |
808 | * - This function takes the volume lcn bitmap lock for writing and | 842 | * - This function takes the volume lcn bitmap lock for writing and |
809 | * modifies the bitmap contents. | 843 | * modifies the bitmap contents. |
844 | * - If @ctx is NULL, the base mft record of @ni must not be mapped on | ||
845 | * entry and it will be left unmapped on return. | ||
846 | * - If @ctx is not NULL, the base mft record must be mapped on entry | ||
847 | * and it will be left mapped on return. | ||
810 | */ | 848 | */ |
811 | s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, | 849 | s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, |
812 | const BOOL is_rollback) | 850 | ntfs_attr_search_ctx *ctx, const BOOL is_rollback) |
813 | { | 851 | { |
814 | s64 delta, to_free, total_freed, real_freed; | 852 | s64 delta, to_free, total_freed, real_freed; |
815 | ntfs_volume *vol; | 853 | ntfs_volume *vol; |
@@ -839,7 +877,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, | |||
839 | 877 | ||
840 | total_freed = real_freed = 0; | 878 | total_freed = real_freed = 0; |
841 | 879 | ||
842 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, TRUE); | 880 | rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx); |
843 | if (IS_ERR(rl)) { | 881 | if (IS_ERR(rl)) { |
844 | if (!is_rollback) | 882 | if (!is_rollback) |
845 | ntfs_error(vol->sb, "Failed to find first runlist " | 883 | ntfs_error(vol->sb, "Failed to find first runlist " |
@@ -893,7 +931,7 @@ s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, | |||
893 | 931 | ||
894 | /* Attempt to map runlist. */ | 932 | /* Attempt to map runlist. */ |
895 | vcn = rl->vcn; | 933 | vcn = rl->vcn; |
896 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, TRUE); | 934 | rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx); |
897 | if (IS_ERR(rl)) { | 935 | if (IS_ERR(rl)) { |
898 | err = PTR_ERR(rl); | 936 | err = PTR_ERR(rl); |
899 | if (!is_rollback) | 937 | if (!is_rollback) |
@@ -961,7 +999,7 @@ err_out: | |||
961 | * If rollback fails, set the volume errors flag, emit an error | 999 | * If rollback fails, set the volume errors flag, emit an error |
962 | * message, and return the error code. | 1000 | * message, and return the error code. |
963 | */ | 1001 | */ |
964 | delta = __ntfs_cluster_free(ni, start_vcn, total_freed, TRUE); | 1002 | delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, TRUE); |
965 | if (delta < 0) { | 1003 | if (delta < 0) { |
966 | ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " | 1004 | ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " |
967 | "inconsistent metadata! Unmount and run " | 1005 | "inconsistent metadata! Unmount and run " |
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h index a6a8827882e7..72cbca7003b2 100644 --- a/fs/ntfs/lcnalloc.h +++ b/fs/ntfs/lcnalloc.h | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | 29 | ||
30 | #include "attrib.h" | ||
30 | #include "types.h" | 31 | #include "types.h" |
31 | #include "inode.h" | 32 | #include "inode.h" |
32 | #include "runlist.h" | 33 | #include "runlist.h" |
@@ -41,16 +42,18 @@ typedef enum { | |||
41 | 42 | ||
42 | extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, | 43 | extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, |
43 | const VCN start_vcn, const s64 count, const LCN start_lcn, | 44 | const VCN start_vcn, const s64 count, const LCN start_lcn, |
44 | const NTFS_CLUSTER_ALLOCATION_ZONES zone); | 45 | const NTFS_CLUSTER_ALLOCATION_ZONES zone, |
46 | const BOOL is_extension); | ||
45 | 47 | ||
46 | extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, | 48 | extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, |
47 | s64 count, const BOOL is_rollback); | 49 | s64 count, ntfs_attr_search_ctx *ctx, const BOOL is_rollback); |
48 | 50 | ||
49 | /** | 51 | /** |
50 | * ntfs_cluster_free - free clusters on an ntfs volume | 52 | * ntfs_cluster_free - free clusters on an ntfs volume |
51 | * @ni: ntfs inode whose runlist describes the clusters to free | 53 | * @ni: ntfs inode whose runlist describes the clusters to free |
52 | * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters | 54 | * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters |
53 | * @count: number of clusters to free or -1 for all clusters | 55 | * @count: number of clusters to free or -1 for all clusters |
56 | * @ctx: active attribute search context if present or NULL if not | ||
54 | * | 57 | * |
55 | * Free @count clusters starting at the cluster @start_vcn in the runlist | 58 | * Free @count clusters starting at the cluster @start_vcn in the runlist |
56 | * described by the ntfs inode @ni. | 59 | * described by the ntfs inode @ni. |
@@ -59,12 +62,36 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, | |||
59 | * deallocated. Thus, to completely free all clusters in a runlist, use | 62 | * deallocated. Thus, to completely free all clusters in a runlist, use |
60 | * @start_vcn = 0 and @count = -1. | 63 | * @start_vcn = 0 and @count = -1. |
61 | * | 64 | * |
62 | * Note, ntfs_cluster_free() does not modify the runlist at all, so the caller | 65 | * If @ctx is specified, it is an active search context of @ni and its base mft |
63 | * has to deal with it later. | 66 | * record. This is needed when ntfs_cluster_free() encounters unmapped runlist |
67 | * fragments and allows their mapping. If you do not have the mft record | ||
68 | * mapped, you can specify @ctx as NULL and ntfs_cluster_free() will perform | ||
69 | * the necessary mapping and unmapping. | ||
70 | * | ||
71 | * Note, ntfs_cluster_free() saves the state of @ctx on entry and restores it | ||
72 | * before returning. Thus, @ctx will be left pointing to the same attribute on | ||
73 | * return as on entry. However, the actual pointers in @ctx may point to | ||
74 | * different memory locations on return, so you must remember to reset any | ||
75 | * cached pointers from the @ctx, i.e. after the call to ntfs_cluster_free(), | ||
76 | * you will probably want to do: | ||
77 | * m = ctx->mrec; | ||
78 | * a = ctx->attr; | ||
79 | * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that | ||
80 | * you cache ctx->mrec in a variable @m of type MFT_RECORD *. | ||
81 | * | ||
82 | * Note, ntfs_cluster_free() does not modify the runlist, so you have to remove | ||
83 | * from the runlist or mark sparse the freed runs later. | ||
64 | * | 84 | * |
65 | * Return the number of deallocated clusters (not counting sparse ones) on | 85 | * Return the number of deallocated clusters (not counting sparse ones) on |
66 | * success and -errno on error. | 86 | * success and -errno on error. |
67 | * | 87 | * |
88 | * WARNING: If @ctx is supplied, regardless of whether success or failure is | ||
89 | * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx | ||
90 | * is no longer valid, i.e. you need to either call | ||
91 | * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. | ||
92 | * In that case PTR_ERR(@ctx->mrec) will give you the error code for | ||
93 | * why the mapping of the old inode failed. | ||
94 | * | ||
68 | * Locking: - The runlist described by @ni must be locked for writing on entry | 95 | * Locking: - The runlist described by @ni must be locked for writing on entry |
69 | * and is locked on return. Note the runlist may be modified when | 96 | * and is locked on return. Note the runlist may be modified when |
70 | * needed runlist fragments need to be mapped. | 97 | * needed runlist fragments need to be mapped. |
@@ -72,11 +99,15 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, | |||
72 | * on return. | 99 | * on return. |
73 | * - This function takes the volume lcn bitmap lock for writing and | 100 | * - This function takes the volume lcn bitmap lock for writing and |
74 | * modifies the bitmap contents. | 101 | * modifies the bitmap contents. |
102 | * - If @ctx is NULL, the base mft record of @ni must not be mapped on | ||
103 | * entry and it will be left unmapped on return. | ||
104 | * - If @ctx is not NULL, the base mft record must be mapped on entry | ||
105 | * and it will be left mapped on return. | ||
75 | */ | 106 | */ |
76 | static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, | 107 | static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, |
77 | s64 count) | 108 | s64 count, ntfs_attr_search_ctx *ctx) |
78 | { | 109 | { |
79 | return __ntfs_cluster_free(ni, start_vcn, count, FALSE); | 110 | return __ntfs_cluster_free(ni, start_vcn, count, ctx, FALSE); |
80 | } | 111 | } |
81 | 112 | ||
82 | extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, | 113 | extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, |
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index 590887b943f5..e38e402e4103 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h | |||
@@ -39,8 +39,7 @@ | |||
39 | * If there was insufficient memory to complete the request, return NULL. | 39 | * If there was insufficient memory to complete the request, return NULL. |
40 | * Depending on @gfp_mask the allocation may be guaranteed to succeed. | 40 | * Depending on @gfp_mask the allocation may be guaranteed to succeed. |
41 | */ | 41 | */ |
42 | static inline void *__ntfs_malloc(unsigned long size, | 42 | static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask) |
43 | gfp_t gfp_mask) | ||
44 | { | 43 | { |
45 | if (likely(size <= PAGE_SIZE)) { | 44 | if (likely(size <= PAGE_SIZE)) { |
46 | BUG_ON(!size); | 45 | BUG_ON(!size); |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index b011369b5956..0c65cbb8c5cf 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
@@ -49,7 +49,8 @@ static inline MFT_RECORD *map_mft_record_page(ntfs_inode *ni) | |||
49 | ntfs_volume *vol = ni->vol; | 49 | ntfs_volume *vol = ni->vol; |
50 | struct inode *mft_vi = vol->mft_ino; | 50 | struct inode *mft_vi = vol->mft_ino; |
51 | struct page *page; | 51 | struct page *page; |
52 | unsigned long index, ofs, end_index; | 52 | unsigned long index, end_index; |
53 | unsigned ofs; | ||
53 | 54 | ||
54 | BUG_ON(ni->page); | 55 | BUG_ON(ni->page); |
55 | /* | 56 | /* |
@@ -1308,7 +1309,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1308 | ll = mftbmp_ni->allocated_size; | 1309 | ll = mftbmp_ni->allocated_size; |
1309 | read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); | 1310 | read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); |
1310 | rl = ntfs_attr_find_vcn_nolock(mftbmp_ni, | 1311 | rl = ntfs_attr_find_vcn_nolock(mftbmp_ni, |
1311 | (ll - 1) >> vol->cluster_size_bits, TRUE); | 1312 | (ll - 1) >> vol->cluster_size_bits, NULL); |
1312 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { | 1313 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { |
1313 | up_write(&mftbmp_ni->runlist.lock); | 1314 | up_write(&mftbmp_ni->runlist.lock); |
1314 | ntfs_error(vol->sb, "Failed to determine last allocated " | 1315 | ntfs_error(vol->sb, "Failed to determine last allocated " |
@@ -1354,7 +1355,8 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol) | |||
1354 | up_write(&vol->lcnbmp_lock); | 1355 | up_write(&vol->lcnbmp_lock); |
1355 | ntfs_unmap_page(page); | 1356 | ntfs_unmap_page(page); |
1356 | /* Allocate a cluster from the DATA_ZONE. */ | 1357 | /* Allocate a cluster from the DATA_ZONE. */ |
1357 | rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE); | 1358 | rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE, |
1359 | TRUE); | ||
1358 | if (IS_ERR(rl2)) { | 1360 | if (IS_ERR(rl2)) { |
1359 | up_write(&mftbmp_ni->runlist.lock); | 1361 | up_write(&mftbmp_ni->runlist.lock); |
1360 | ntfs_error(vol->sb, "Failed to allocate a cluster for " | 1362 | ntfs_error(vol->sb, "Failed to allocate a cluster for " |
@@ -1738,7 +1740,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1738 | ll = mft_ni->allocated_size; | 1740 | ll = mft_ni->allocated_size; |
1739 | read_unlock_irqrestore(&mft_ni->size_lock, flags); | 1741 | read_unlock_irqrestore(&mft_ni->size_lock, flags); |
1740 | rl = ntfs_attr_find_vcn_nolock(mft_ni, | 1742 | rl = ntfs_attr_find_vcn_nolock(mft_ni, |
1741 | (ll - 1) >> vol->cluster_size_bits, TRUE); | 1743 | (ll - 1) >> vol->cluster_size_bits, NULL); |
1742 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { | 1744 | if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { |
1743 | up_write(&mft_ni->runlist.lock); | 1745 | up_write(&mft_ni->runlist.lock); |
1744 | ntfs_error(vol->sb, "Failed to determine last allocated " | 1746 | ntfs_error(vol->sb, "Failed to determine last allocated " |
@@ -1779,7 +1781,8 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol) | |||
1779 | nr > min_nr ? "default" : "minimal", (long long)nr); | 1781 | nr > min_nr ? "default" : "minimal", (long long)nr); |
1780 | old_last_vcn = rl[1].vcn; | 1782 | old_last_vcn = rl[1].vcn; |
1781 | do { | 1783 | do { |
1782 | rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE); | 1784 | rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE, |
1785 | TRUE); | ||
1783 | if (likely(!IS_ERR(rl2))) | 1786 | if (likely(!IS_ERR(rl2))) |
1784 | break; | 1787 | break; |
1785 | if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) { | 1788 | if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) { |
@@ -1951,20 +1954,21 @@ restore_undo_alloc: | |||
1951 | NVolSetErrors(vol); | 1954 | NVolSetErrors(vol); |
1952 | return ret; | 1955 | return ret; |
1953 | } | 1956 | } |
1954 | a = ctx->attr; | 1957 | ctx->attr->data.non_resident.highest_vcn = |
1955 | a->data.non_resident.highest_vcn = cpu_to_sle64(old_last_vcn - 1); | 1958 | cpu_to_sle64(old_last_vcn - 1); |
1956 | undo_alloc: | 1959 | undo_alloc: |
1957 | if (ntfs_cluster_free(mft_ni, old_last_vcn, -1) < 0) { | 1960 | if (ntfs_cluster_free(mft_ni, old_last_vcn, -1, ctx) < 0) { |
1958 | ntfs_error(vol->sb, "Failed to free clusters from mft data " | 1961 | ntfs_error(vol->sb, "Failed to free clusters from mft data " |
1959 | "attribute.%s", es); | 1962 | "attribute.%s", es); |
1960 | NVolSetErrors(vol); | 1963 | NVolSetErrors(vol); |
1961 | } | 1964 | } |
1965 | a = ctx->attr; | ||
1962 | if (ntfs_rl_truncate_nolock(vol, &mft_ni->runlist, old_last_vcn)) { | 1966 | if (ntfs_rl_truncate_nolock(vol, &mft_ni->runlist, old_last_vcn)) { |
1963 | ntfs_error(vol->sb, "Failed to truncate mft data attribute " | 1967 | ntfs_error(vol->sb, "Failed to truncate mft data attribute " |
1964 | "runlist.%s", es); | 1968 | "runlist.%s", es); |
1965 | NVolSetErrors(vol); | 1969 | NVolSetErrors(vol); |
1966 | } | 1970 | } |
1967 | if (mp_rebuilt) { | 1971 | if (mp_rebuilt && !IS_ERR(ctx->mrec)) { |
1968 | if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( | 1972 | if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( |
1969 | a->data.non_resident.mapping_pairs_offset), | 1973 | a->data.non_resident.mapping_pairs_offset), |
1970 | old_alen - le16_to_cpu( | 1974 | old_alen - le16_to_cpu( |
@@ -1981,6 +1985,10 @@ undo_alloc: | |||
1981 | } | 1985 | } |
1982 | flush_dcache_mft_record_page(ctx->ntfs_ino); | 1986 | flush_dcache_mft_record_page(ctx->ntfs_ino); |
1983 | mark_mft_record_dirty(ctx->ntfs_ino); | 1987 | mark_mft_record_dirty(ctx->ntfs_ino); |
1988 | } else if (IS_ERR(ctx->mrec)) { | ||
1989 | ntfs_error(vol->sb, "Failed to restore attribute search " | ||
1990 | "context.%s", es); | ||
1991 | NVolSetErrors(vol); | ||
1984 | } | 1992 | } |
1985 | if (ctx) | 1993 | if (ctx) |
1986 | ntfs_attr_put_search_ctx(ctx); | 1994 | ntfs_attr_put_search_ctx(ctx); |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 453d0d51ea4b..6c16db9e1a8a 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -1447,7 +1447,7 @@ not_enabled: | |||
1447 | if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) { | 1447 | if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) { |
1448 | ntfs_error(vol->sb, "Found corrupt $UsnJrnl/$DATA/$Max " | 1448 | ntfs_error(vol->sb, "Found corrupt $UsnJrnl/$DATA/$Max " |
1449 | "attribute (size is 0x%llx but should be at " | 1449 | "attribute (size is 0x%llx but should be at " |
1450 | "least 0x%x bytes).", i_size_read(tmp_ino), | 1450 | "least 0x%zx bytes).", i_size_read(tmp_ino), |
1451 | sizeof(USN_HEADER)); | 1451 | sizeof(USN_HEADER)); |
1452 | return FALSE; | 1452 | return FALSE; |
1453 | } | 1453 | } |
diff --git a/include/asm-arm/arch-ixp2000/enp2611.h b/include/asm-arm/arch-ixp2000/enp2611.h index 31ae88674968..95128d9f5026 100644 --- a/include/asm-arm/arch-ixp2000/enp2611.h +++ b/include/asm-arm/arch-ixp2000/enp2611.h | |||
@@ -21,8 +21,20 @@ | |||
21 | #ifndef __ENP2611_H | 21 | #ifndef __ENP2611_H |
22 | #define __ENP2611_H | 22 | #define __ENP2611_H |
23 | 23 | ||
24 | #define ENP2611_GPIO_SCL 0x07 | 24 | #define ENP2611_CALEB_PHYS_BASE 0xc5000000 |
25 | #define ENP2611_GPIO_SDA 0x06 | 25 | #define ENP2611_CALEB_VIRT_BASE 0xfe000000 |
26 | #define ENP2611_CALEB_SIZE 0x00100000 | ||
27 | |||
28 | #define ENP2611_PM3386_0_PHYS_BASE 0xc6000000 | ||
29 | #define ENP2611_PM3386_0_VIRT_BASE 0xfe100000 | ||
30 | #define ENP2611_PM3386_0_SIZE 0x00100000 | ||
31 | |||
32 | #define ENP2611_PM3386_1_PHYS_BASE 0xc6400000 | ||
33 | #define ENP2611_PM3386_1_VIRT_BASE 0xfe200000 | ||
34 | #define ENP2611_PM3386_1_SIZE 0x00100000 | ||
35 | |||
36 | #define ENP2611_GPIO_SCL 7 | ||
37 | #define ENP2611_GPIO_SDA 6 | ||
26 | 38 | ||
27 | 39 | ||
28 | #endif | 40 | #endif |
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index def089d693d2..fc5ac6aec4f2 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h | |||
@@ -59,14 +59,15 @@ | |||
59 | #define IXP2000_CAP_SIZE 0x00100000 | 59 | #define IXP2000_CAP_SIZE 0x00100000 |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * Addresses for specific on-chip peripherals | 62 | * Addresses for specific on-chip peripherals. |
63 | */ | 63 | */ |
64 | #define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfef80000 | 64 | #define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfef80000 |
65 | #define IXP2000_GLOBAL_REG_VIRT_BASE 0xfef04000 | 65 | #define IXP2000_GLOBAL_REG_VIRT_BASE 0xfef04000 |
66 | #define IXP2000_UART_PHYS_BASE 0xc0030000 | 66 | #define IXP2000_UART_PHYS_BASE 0xc0030000 |
67 | #define IXP2000_UART_VIRT_BASE 0xfef30000 | 67 | #define IXP2000_UART_VIRT_BASE 0xfef30000 |
68 | #define IXP2000_TIMER_VIRT_BASE 0xfef20000 | 68 | #define IXP2000_TIMER_VIRT_BASE 0xfef20000 |
69 | #define IXP2000_GPIO_VIRT_BASE 0Xfef10000 | 69 | #define IXP2000_UENGINE_CSR_VIRT_BASE 0xfef18000 |
70 | #define IXP2000_GPIO_VIRT_BASE 0xfef10000 | ||
70 | 71 | ||
71 | /* | 72 | /* |
72 | * Devices outside of the 0xc0000000 -> 0xc0100000 range. The virtual | 73 | * Devices outside of the 0xc0000000 -> 0xc0100000 range. The virtual |
@@ -252,7 +253,7 @@ | |||
252 | #define IXP2000_PCI_XSCALE_INT_ENABLE IXP2000_PCI_CSR(0x15C) | 253 | #define IXP2000_PCI_XSCALE_INT_ENABLE IXP2000_PCI_CSR(0x15C) |
253 | 254 | ||
254 | #define IXP2000_PCICNTL_PNR (1<<17) /* PCI not Reset bit of PCI_CONTROL */ | 255 | #define IXP2000_PCICNTL_PNR (1<<17) /* PCI not Reset bit of PCI_CONTROL */ |
255 | #define IXP2000_PCICNTL_PCF (1<<28) /* PCI Centrolfunction bit */ | 256 | #define IXP2000_PCICNTL_PCF (1<<28) /* PCI Central function bit */ |
256 | #define IXP2000_XSCALE_INT (1<<1) /* Interrupt from XScale to PCI */ | 257 | #define IXP2000_XSCALE_INT (1<<1) /* Interrupt from XScale to PCI */ |
257 | 258 | ||
258 | /* These are from the IRQ register in the PCI ISR register */ | 259 | /* These are from the IRQ register in the PCI ISR register */ |
diff --git a/include/asm-arm/arch-ixp2000/system.h b/include/asm-arm/arch-ixp2000/system.h index 4f489cc0dfa5..ddbbb34b5f95 100644 --- a/include/asm-arm/arch-ixp2000/system.h +++ b/include/asm-arm/arch-ixp2000/system.h | |||
@@ -26,29 +26,24 @@ static inline void arch_reset(char mode) | |||
26 | * RedBoot bank. | 26 | * RedBoot bank. |
27 | */ | 27 | */ |
28 | if (machine_is_ixdp2401()) { | 28 | if (machine_is_ixdp2401()) { |
29 | *IXDP2X01_CPLD_FLASH_REG = ((0 >> IXDP2X01_FLASH_WINDOW_BITS) | 29 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, |
30 | | IXDP2X01_CPLD_FLASH_INTERN); | 30 | ((0 >> IXDP2X01_FLASH_WINDOW_BITS) |
31 | *IXDP2X01_CPLD_RESET_REG = 0xffffffff; | 31 | | IXDP2X01_CPLD_FLASH_INTERN)); |
32 | ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0xffffffff); | ||
32 | } | 33 | } |
33 | 34 | ||
34 | /* | 35 | /* |
35 | * On IXDP2801 we need to write this magic sequence to the CPLD | 36 | * On IXDP2801 we need to write this magic sequence to the CPLD |
36 | * to cause a complete reset of the CPU and all external devices | 37 | * to cause a complete reset of the CPU and all external devices |
37 | * and moves the flash bank register back to 0. | 38 | * and move the flash bank register back to 0. |
38 | */ | 39 | */ |
39 | if (machine_is_ixdp2801()) { | 40 | if (machine_is_ixdp2801()) { |
40 | unsigned long reset_reg = *IXDP2X01_CPLD_RESET_REG; | 41 | unsigned long reset_reg = *IXDP2X01_CPLD_RESET_REG; |
42 | |||
41 | reset_reg = 0x55AA0000 | (reset_reg & 0x0000FFFF); | 43 | reset_reg = 0x55AA0000 | (reset_reg & 0x0000FFFF); |
42 | *IXDP2X01_CPLD_RESET_REG = reset_reg; | 44 | ixp2000_reg_write(IXDP2X01_CPLD_RESET_REG, reset_reg); |
43 | mb(); | 45 | ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0x80000000); |
44 | *IXDP2X01_CPLD_RESET_REG = 0x80000000; | ||
45 | } | 46 | } |
46 | 47 | ||
47 | /* | 48 | ixp2000_reg_wrb(IXP2000_RESET0, RSTALL); |
48 | * We do a reset all if we are PCI master. We could be a slave and we | ||
49 | * don't want to do anything funky on the PCI bus. | ||
50 | */ | ||
51 | if (*IXP2000_STRAP_OPTIONS & CFG_PCI_BOOT_HOST) { | ||
52 | *(IXP2000_RESET0) |= (RSTALL); | ||
53 | } | ||
54 | } | 49 | } |
diff --git a/include/asm-arm/arch-ixp2000/uengine.h b/include/asm-arm/arch-ixp2000/uengine.h new file mode 100644 index 000000000000..b442d65c6593 --- /dev/null +++ b/include/asm-arm/arch-ixp2000/uengine.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Generic library functions for the microengines found on the Intel | ||
3 | * IXP2000 series of network processors. | ||
4 | * | ||
5 | * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org> | ||
6 | * Dedicated to Marija Kulikova. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU Lesser General Public License as | ||
10 | * published by the Free Software Foundation; either version 2.1 of the | ||
11 | * License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #ifndef __IXP2000_UENGINE_H | ||
15 | #define __IXP2000_UENGINE_H | ||
16 | |||
17 | extern u32 ixp2000_uengine_mask; | ||
18 | |||
19 | struct ixp2000_uengine_code | ||
20 | { | ||
21 | u32 cpu_model_bitmask; | ||
22 | u8 cpu_min_revision; | ||
23 | u8 cpu_max_revision; | ||
24 | |||
25 | u32 uengine_parameters; | ||
26 | |||
27 | struct ixp2000_reg_value { | ||
28 | int reg; | ||
29 | u32 value; | ||
30 | } *initial_reg_values; | ||
31 | |||
32 | int num_insns; | ||
33 | u8 *insns; | ||
34 | }; | ||
35 | |||
36 | u32 ixp2000_uengine_csr_read(int uengine, int offset); | ||
37 | void ixp2000_uengine_csr_write(int uengine, int offset, u32 value); | ||
38 | void ixp2000_uengine_reset(u32 uengine_mask); | ||
39 | void ixp2000_uengine_set_mode(int uengine, u32 mode); | ||
40 | void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns); | ||
41 | void ixp2000_uengine_init_context(int uengine, int context, int pc); | ||
42 | void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask); | ||
43 | void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask); | ||
44 | int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c); | ||
45 | |||
46 | #define IXP2000_UENGINE_8_CONTEXTS 0x00000000 | ||
47 | #define IXP2000_UENGINE_4_CONTEXTS 0x80000000 | ||
48 | #define IXP2000_UENGINE_PRN_UPDATE_EVERY 0x40000000 | ||
49 | #define IXP2000_UENGINE_PRN_UPDATE_ON_ACCESS 0x00000000 | ||
50 | #define IXP2000_UENGINE_NN_FROM_SELF 0x00100000 | ||
51 | #define IXP2000_UENGINE_NN_FROM_PREVIOUS 0x00000000 | ||
52 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_3 0x000c0000 | ||
53 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_2 0x00080000 | ||
54 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_1 0x00040000 | ||
55 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_0 0x00000000 | ||
56 | #define IXP2000_UENGINE_LM_ADDR1_GLOBAL 0x00020000 | ||
57 | #define IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT 0x00000000 | ||
58 | #define IXP2000_UENGINE_LM_ADDR0_GLOBAL 0x00010000 | ||
59 | #define IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT 0x00000000 | ||
60 | |||
61 | |||
62 | #endif | ||
diff --git a/include/asm-arm/arch-realview/debug-macro.S b/include/asm-arm/arch-realview/debug-macro.S new file mode 100644 index 000000000000..ed28bd012236 --- /dev/null +++ b/include/asm-arm/arch-realview/debug-macro.S | |||
@@ -0,0 +1,38 @@ | |||
1 | /* linux/include/asm-arm/arch-realview/debug-macro.S | ||
2 | * | ||
3 | * Debugging macro include header | ||
4 | * | ||
5 | * Copyright (C) 1994-1999 Russell King | ||
6 | * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <asm/hardware/amba_serial.h> | ||
15 | |||
16 | .macro addruart,rx | ||
17 | mrc p15, 0, \rx, c1, c0 | ||
18 | tst \rx, #1 @ MMU enabled? | ||
19 | moveq \rx, #0x10000000 | ||
20 | movne \rx, #0xf1000000 @ virtual base | ||
21 | orr \rx, \rx, #0x00009000 | ||
22 | .endm | ||
23 | |||
24 | .macro senduart,rd,rx | ||
25 | strb \rd, [\rx, #UART01x_DR] | ||
26 | .endm | ||
27 | |||
28 | .macro waituart,rd,rx | ||
29 | 1001: ldr \rd, [\rx, #0x18] @ UARTFLG | ||
30 | tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full | ||
31 | bne 1001b | ||
32 | .endm | ||
33 | |||
34 | .macro busyuart,rd,rx | ||
35 | 1001: ldr \rd, [\rx, #0x18] @ UARTFLG | ||
36 | tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy | ||
37 | bne 1001b | ||
38 | .endm | ||
diff --git a/include/asm-arm/arch-realview/dma.h b/include/asm-arm/arch-realview/dma.h new file mode 100644 index 000000000000..744491a74bd9 --- /dev/null +++ b/include/asm-arm/arch-realview/dma.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/dma.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited. | ||
5 | * Copyright (C) 1997,1998 Russell King | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #ifndef __ASM_ARCH_DMA_H | ||
22 | #define __ASM_ARCH_DMA_H | ||
23 | |||
24 | #define MAX_DMA_ADDRESS 0xffffffff | ||
25 | #define MAX_DMA_CHANNELS 0 | ||
26 | |||
27 | #endif /* _ASM_ARCH_DMA_H */ | ||
diff --git a/include/asm-arm/arch-realview/entry-macro.S b/include/asm-arm/arch-realview/entry-macro.S new file mode 100644 index 000000000000..2712ba77bb3a --- /dev/null +++ b/include/asm-arm/arch-realview/entry-macro.S | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * include/asm-arm/arch-realview/entry-macro.S | ||
3 | * | ||
4 | * Low-level IRQ helper macros for RealView platforms | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | */ | ||
10 | |||
11 | #include <asm/hardware/gic.h> | ||
12 | |||
13 | .macro disable_fiq | ||
14 | .endm | ||
15 | |||
16 | /* | ||
17 | * The interrupt numbering scheme is defined in the | ||
18 | * interrupt controller spec. To wit: | ||
19 | * | ||
20 | * Interrupts 0-15 are IPI | ||
21 | * 16-28 are reserved | ||
22 | * 29-31 are local. We allow 30 to be used for the watchdog. | ||
23 | * 32-1020 are global | ||
24 | * 1021-1022 are reserved | ||
25 | * 1023 is "spurious" (no interrupt) | ||
26 | * | ||
27 | * For now, we ignore all local interrupts so only return an interrupt if it's | ||
28 | * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs. | ||
29 | * | ||
30 | * A simple read from the controller will tell us the number of the highest | ||
31 | * priority enabled interrupt. We then just need to check whether it is in the | ||
32 | * valid range for an IRQ (30-1020 inclusive). | ||
33 | */ | ||
34 | |||
35 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp | ||
36 | |||
37 | ldr \base, =IO_ADDRESS(REALVIEW_GIC_CPU_BASE) | ||
38 | ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, 9-0 = int # */ | ||
39 | |||
40 | ldr \tmp, =1021 | ||
41 | |||
42 | bic \irqnr, \irqstat, #0x1c00 | ||
43 | |||
44 | cmp \irqnr, #29 | ||
45 | cmpcc \irqnr, \irqnr | ||
46 | cmpne \irqnr, \tmp | ||
47 | cmpcs \irqnr, \irqnr | ||
48 | |||
49 | .endm | ||
diff --git a/include/asm-arm/arch-realview/hardware.h b/include/asm-arm/arch-realview/hardware.h new file mode 100644 index 000000000000..67879cdb6ef2 --- /dev/null +++ b/include/asm-arm/arch-realview/hardware.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/hardware.h | ||
3 | * | ||
4 | * This file contains the hardware definitions of the RealView boards. | ||
5 | * | ||
6 | * Copyright (C) 2003 ARM Limited. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | #ifndef __ASM_ARCH_HARDWARE_H | ||
23 | #define __ASM_ARCH_HARDWARE_H | ||
24 | |||
25 | #include <asm/sizes.h> | ||
26 | #include <asm/arch/platform.h> | ||
27 | |||
28 | /* macro to get at IO space when running virtually */ | ||
29 | #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) | ||
30 | |||
31 | #endif | ||
diff --git a/include/asm-arm/arch-realview/io.h b/include/asm-arm/arch-realview/io.h new file mode 100644 index 000000000000..d444a68ac330 --- /dev/null +++ b/include/asm-arm/arch-realview/io.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/io.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #ifndef __ASM_ARM_ARCH_IO_H | ||
21 | #define __ASM_ARM_ARCH_IO_H | ||
22 | |||
23 | #define IO_SPACE_LIMIT 0xffffffff | ||
24 | |||
25 | static inline void __iomem *__io(unsigned long addr) | ||
26 | { | ||
27 | return (void __iomem *)addr; | ||
28 | } | ||
29 | |||
30 | #define __io(a) __io(a) | ||
31 | #define __mem_pci(a) (a) | ||
32 | #define __mem_isa(a) (a) | ||
33 | |||
34 | #endif | ||
diff --git a/include/asm-arm/arch-realview/irqs.h b/include/asm-arm/arch-realview/irqs.h new file mode 100644 index 000000000000..ff376494e5b1 --- /dev/null +++ b/include/asm-arm/arch-realview/irqs.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/irqs.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited | ||
5 | * Copyright (C) 2000 Deep Blue Solutions Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <asm/arch/platform.h> | ||
23 | |||
24 | /* | ||
25 | * IRQ interrupts definitions are the same the INT definitions | ||
26 | * held within platform.h | ||
27 | */ | ||
28 | #define IRQ_GIC_START 32 | ||
29 | #define IRQ_WDOGINT (IRQ_GIC_START + INT_WDOGINT) | ||
30 | #define IRQ_SOFTINT (IRQ_GIC_START + INT_SOFTINT) | ||
31 | #define IRQ_COMMRx (IRQ_GIC_START + INT_COMMRx) | ||
32 | #define IRQ_COMMTx (IRQ_GIC_START + INT_COMMTx) | ||
33 | #define IRQ_TIMERINT0_1 (IRQ_GIC_START + INT_TIMERINT0_1) | ||
34 | #define IRQ_TIMERINT2_3 (IRQ_GIC_START + INT_TIMERINT2_3) | ||
35 | #define IRQ_GPIOINT0 (IRQ_GIC_START + INT_GPIOINT0) | ||
36 | #define IRQ_GPIOINT1 (IRQ_GIC_START + INT_GPIOINT1) | ||
37 | #define IRQ_GPIOINT2 (IRQ_GIC_START + INT_GPIOINT2) | ||
38 | #define IRQ_GPIOINT3 (IRQ_GIC_START + INT_GPIOINT3) | ||
39 | #define IRQ_RTCINT (IRQ_GIC_START + INT_RTCINT) | ||
40 | #define IRQ_SSPINT (IRQ_GIC_START + INT_SSPINT) | ||
41 | #define IRQ_UARTINT0 (IRQ_GIC_START + INT_UARTINT0) | ||
42 | #define IRQ_UARTINT1 (IRQ_GIC_START + INT_UARTINT1) | ||
43 | #define IRQ_UARTINT2 (IRQ_GIC_START + INT_UARTINT2) | ||
44 | #define IRQ_UART3 (IRQ_GIC_START + INT_UARTINT3) | ||
45 | #define IRQ_SCIINT (IRQ_GIC_START + INT_SCIINT) | ||
46 | #define IRQ_CLCDINT (IRQ_GIC_START + INT_CLCDINT) | ||
47 | #define IRQ_DMAINT (IRQ_GIC_START + INT_DMAINT) | ||
48 | #define IRQ_PWRFAILINT (IRQ_GIC_START + INT_PWRFAILINT) | ||
49 | #define IRQ_MBXINT (IRQ_GIC_START + INT_MBXINT) | ||
50 | #define IRQ_GNDINT (IRQ_GIC_START + INT_GNDINT) | ||
51 | #define IRQ_MMCI0B (IRQ_GIC_START + INT_MMCI0B) | ||
52 | #define IRQ_MMCI1B (IRQ_GIC_START + INT_MMCI1B) | ||
53 | #define IRQ_KMI0 (IRQ_GIC_START + INT_KMI0) | ||
54 | #define IRQ_KMI1 (IRQ_GIC_START + INT_KMI1) | ||
55 | #define IRQ_SCI3 (IRQ_GIC_START + INT_SCI3) | ||
56 | #define IRQ_CLCD (IRQ_GIC_START + INT_CLCD) | ||
57 | #define IRQ_TOUCH (IRQ_GIC_START + INT_TOUCH) | ||
58 | #define IRQ_KEYPAD (IRQ_GIC_START + INT_KEYPAD) | ||
59 | #define IRQ_DoC (IRQ_GIC_START + INT_DoC) | ||
60 | #define IRQ_MMCI0A (IRQ_GIC_START + INT_MMCI0A) | ||
61 | #define IRQ_MMCI1A (IRQ_GIC_START + INT_MMCI1A) | ||
62 | #define IRQ_AACI (IRQ_GIC_START + INT_AACI) | ||
63 | #define IRQ_ETH (IRQ_GIC_START + INT_ETH) | ||
64 | #define IRQ_USB (IRQ_GIC_START + INT_USB) | ||
65 | |||
66 | #define IRQMASK_WDOGINT INTMASK_WDOGINT | ||
67 | #define IRQMASK_SOFTINT INTMASK_SOFTINT | ||
68 | #define IRQMASK_COMMRx INTMASK_COMMRx | ||
69 | #define IRQMASK_COMMTx INTMASK_COMMTx | ||
70 | #define IRQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1 | ||
71 | #define IRQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3 | ||
72 | #define IRQMASK_GPIOINT0 INTMASK_GPIOINT0 | ||
73 | #define IRQMASK_GPIOINT1 INTMASK_GPIOINT1 | ||
74 | #define IRQMASK_GPIOINT2 INTMASK_GPIOINT2 | ||
75 | #define IRQMASK_GPIOINT3 INTMASK_GPIOINT3 | ||
76 | #define IRQMASK_RTCINT INTMASK_RTCINT | ||
77 | #define IRQMASK_SSPINT INTMASK_SSPINT | ||
78 | #define IRQMASK_UARTINT0 INTMASK_UARTINT0 | ||
79 | #define IRQMASK_UARTINT1 INTMASK_UARTINT1 | ||
80 | #define IRQMASK_UARTINT2 INTMASK_UARTINT2 | ||
81 | #define IRQMASK_SCIINT INTMASK_SCIINT | ||
82 | #define IRQMASK_CLCDINT INTMASK_CLCDINT | ||
83 | #define IRQMASK_DMAINT INTMASK_DMAINT | ||
84 | #define IRQMASK_PWRFAILINT INTMASK_PWRFAILINT | ||
85 | #define IRQMASK_MBXINT INTMASK_MBXINT | ||
86 | #define IRQMASK_GNDINT INTMASK_GNDINT | ||
87 | #define IRQMASK_MMCI0B INTMASK_MMCI0B | ||
88 | #define IRQMASK_MMCI1B INTMASK_MMCI1B | ||
89 | #define IRQMASK_KMI0 INTMASK_KMI0 | ||
90 | #define IRQMASK_KMI1 INTMASK_KMI1 | ||
91 | #define IRQMASK_SCI3 INTMASK_SCI3 | ||
92 | #define IRQMASK_UART3 INTMASK_UART3 | ||
93 | #define IRQMASK_CLCD INTMASK_CLCD | ||
94 | #define IRQMASK_TOUCH INTMASK_TOUCH | ||
95 | #define IRQMASK_KEYPAD INTMASK_KEYPAD | ||
96 | #define IRQMASK_DoC INTMASK_DoC | ||
97 | #define IRQMASK_MMCI0A INTMASK_MMCI0A | ||
98 | #define IRQMASK_MMCI1A INTMASK_MMCI1A | ||
99 | #define IRQMASK_AACI INTMASK_AACI | ||
100 | #define IRQMASK_ETH INTMASK_ETH | ||
101 | #define IRQMASK_USB INTMASK_USB | ||
102 | |||
103 | #define NR_IRQS (IRQ_GIC_START + 64) | ||
diff --git a/include/asm-arm/arch-realview/memory.h b/include/asm-arm/arch-realview/memory.h new file mode 100644 index 000000000000..99667d5cc617 --- /dev/null +++ b/include/asm-arm/arch-realview/memory.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/memory.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #ifndef __ASM_ARCH_MEMORY_H | ||
21 | #define __ASM_ARCH_MEMORY_H | ||
22 | |||
23 | /* | ||
24 | * Physical DRAM offset. | ||
25 | */ | ||
26 | #define PHYS_OFFSET (0x00000000UL) | ||
27 | |||
28 | /* | ||
29 | * Virtual view <-> DMA view memory address translations | ||
30 | * virt_to_bus: Used to translate the virtual address to an | ||
31 | * address suitable to be passed to set_dma_addr | ||
32 | * bus_to_virt: Used to convert an address for DMA operations | ||
33 | * to an address that the kernel can use. | ||
34 | */ | ||
35 | #define __virt_to_bus(x) ((x) - PAGE_OFFSET) | ||
36 | #define __bus_to_virt(x) ((x) + PAGE_OFFSET) | ||
37 | |||
38 | #endif | ||
diff --git a/include/asm-arm/arch-realview/param.h b/include/asm-arm/arch-realview/param.h new file mode 100644 index 000000000000..89b1235d32bd --- /dev/null +++ b/include/asm-arm/arch-realview/param.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/param.h | ||
3 | * | ||
4 | * Copyright (C) 2002 ARM Limited | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h new file mode 100644 index 000000000000..4b6de13a6b9a --- /dev/null +++ b/include/asm-arm/arch-realview/platform.h | |||
@@ -0,0 +1,395 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/platform.h | ||
3 | * | ||
4 | * Copyright (c) ARM Limited 2003. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef __address_h | ||
22 | #define __address_h 1 | ||
23 | |||
24 | /* | ||
25 | * Memory definitions | ||
26 | */ | ||
27 | #define REALVIEW_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)...*/ | ||
28 | #define REALVIEW_BOOT_ROM_HI 0x30000000 | ||
29 | #define REALVIEW_BOOT_ROM_BASE REALVIEW_BOOT_ROM_HI /* Normal position */ | ||
30 | #define REALVIEW_BOOT_ROM_SIZE SZ_64M | ||
31 | |||
32 | #define REALVIEW_SSRAM_BASE /* REALVIEW_SSMC_BASE ? */ | ||
33 | #define REALVIEW_SSRAM_SIZE SZ_2M | ||
34 | |||
35 | #define REALVIEW_FLASH_BASE 0x40000000 | ||
36 | #define REALVIEW_FLASH_SIZE SZ_64M | ||
37 | |||
38 | /* | ||
39 | * SDRAM | ||
40 | */ | ||
41 | #define REALVIEW_SDRAM_BASE 0x00000000 | ||
42 | |||
43 | /* | ||
44 | * Logic expansion modules | ||
45 | * | ||
46 | */ | ||
47 | |||
48 | |||
49 | /* ------------------------------------------------------------------------ | ||
50 | * RealView Registers | ||
51 | * ------------------------------------------------------------------------ | ||
52 | * | ||
53 | */ | ||
54 | #define REALVIEW_SYS_ID_OFFSET 0x00 | ||
55 | #define REALVIEW_SYS_SW_OFFSET 0x04 | ||
56 | #define REALVIEW_SYS_LED_OFFSET 0x08 | ||
57 | #define REALVIEW_SYS_OSC0_OFFSET 0x0C | ||
58 | |||
59 | #define REALVIEW_SYS_OSC1_OFFSET 0x10 | ||
60 | #define REALVIEW_SYS_OSC2_OFFSET 0x14 | ||
61 | #define REALVIEW_SYS_OSC3_OFFSET 0x18 | ||
62 | #define REALVIEW_SYS_OSC4_OFFSET 0x1C /* OSC1 for RealView/AB */ | ||
63 | |||
64 | #define REALVIEW_SYS_LOCK_OFFSET 0x20 | ||
65 | #define REALVIEW_SYS_100HZ_OFFSET 0x24 | ||
66 | #define REALVIEW_SYS_CFGDATA1_OFFSET 0x28 | ||
67 | #define REALVIEW_SYS_CFGDATA2_OFFSET 0x2C | ||
68 | #define REALVIEW_SYS_FLAGS_OFFSET 0x30 | ||
69 | #define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 | ||
70 | #define REALVIEW_SYS_FLAGSCLR_OFFSET 0x34 | ||
71 | #define REALVIEW_SYS_NVFLAGS_OFFSET 0x38 | ||
72 | #define REALVIEW_SYS_NVFLAGSSET_OFFSET 0x38 | ||
73 | #define REALVIEW_SYS_NVFLAGSCLR_OFFSET 0x3C | ||
74 | #define REALVIEW_SYS_RESETCTL_OFFSET 0x40 | ||
75 | #define REALVIEW_SYS_PCICTL_OFFSET 0x44 | ||
76 | #define REALVIEW_SYS_MCI_OFFSET 0x48 | ||
77 | #define REALVIEW_SYS_FLASH_OFFSET 0x4C | ||
78 | #define REALVIEW_SYS_CLCD_OFFSET 0x50 | ||
79 | #define REALVIEW_SYS_CLCDSER_OFFSET 0x54 | ||
80 | #define REALVIEW_SYS_BOOTCS_OFFSET 0x58 | ||
81 | #define REALVIEW_SYS_24MHz_OFFSET 0x5C | ||
82 | #define REALVIEW_SYS_MISC_OFFSET 0x60 | ||
83 | #define REALVIEW_SYS_IOSEL_OFFSET 0x70 | ||
84 | #define REALVIEW_SYS_TEST_OSC0_OFFSET 0x80 | ||
85 | #define REALVIEW_SYS_TEST_OSC1_OFFSET 0x84 | ||
86 | #define REALVIEW_SYS_TEST_OSC2_OFFSET 0x88 | ||
87 | #define REALVIEW_SYS_TEST_OSC3_OFFSET 0x8C | ||
88 | #define REALVIEW_SYS_TEST_OSC4_OFFSET 0x90 | ||
89 | |||
90 | #define REALVIEW_SYS_BASE 0x10000000 | ||
91 | #define REALVIEW_SYS_ID (REALVIEW_SYS_BASE + REALVIEW_SYS_ID_OFFSET) | ||
92 | #define REALVIEW_SYS_SW (REALVIEW_SYS_BASE + REALVIEW_SYS_SW_OFFSET) | ||
93 | #define REALVIEW_SYS_LED (REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET) | ||
94 | #define REALVIEW_SYS_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC0_OFFSET) | ||
95 | #define REALVIEW_SYS_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC1_OFFSET) | ||
96 | |||
97 | #define REALVIEW_SYS_LOCK (REALVIEW_SYS_BASE + REALVIEW_SYS_LOCK_OFFSET) | ||
98 | #define REALVIEW_SYS_100HZ (REALVIEW_SYS_BASE + REALVIEW_SYS_100HZ_OFFSET) | ||
99 | #define REALVIEW_SYS_CFGDATA1 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA1_OFFSET) | ||
100 | #define REALVIEW_SYS_CFGDATA2 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA2_OFFSET) | ||
101 | #define REALVIEW_SYS_FLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGS_OFFSET) | ||
102 | #define REALVIEW_SYS_FLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSSET_OFFSET) | ||
103 | #define REALVIEW_SYS_FLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSCLR_OFFSET) | ||
104 | #define REALVIEW_SYS_NVFLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGS_OFFSET) | ||
105 | #define REALVIEW_SYS_NVFLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSSET_OFFSET) | ||
106 | #define REALVIEW_SYS_NVFLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSCLR_OFFSET) | ||
107 | #define REALVIEW_SYS_RESETCTL (REALVIEW_SYS_BASE + REALVIEW_SYS_RESETCTL_OFFSET) | ||
108 | #define REALVIEW_SYS_PCICTL (REALVIEW_SYS_BASE + REALVIEW_SYS_PCICTL_OFFSET) | ||
109 | #define REALVIEW_SYS_MCI (REALVIEW_SYS_BASE + REALVIEW_SYS_MCI_OFFSET) | ||
110 | #define REALVIEW_SYS_FLASH (REALVIEW_SYS_BASE + REALVIEW_SYS_FLASH_OFFSET) | ||
111 | #define REALVIEW_SYS_CLCD (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCD_OFFSET) | ||
112 | #define REALVIEW_SYS_CLCDSER (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCDSER_OFFSET) | ||
113 | #define REALVIEW_SYS_BOOTCS (REALVIEW_SYS_BASE + REALVIEW_SYS_BOOTCS_OFFSET) | ||
114 | #define REALVIEW_SYS_24MHz (REALVIEW_SYS_BASE + REALVIEW_SYS_24MHz_OFFSET) | ||
115 | #define REALVIEW_SYS_MISC (REALVIEW_SYS_BASE + REALVIEW_SYS_MISC_OFFSET) | ||
116 | #define REALVIEW_SYS_IOSEL (REALVIEW_SYS_BASE + REALVIEW_SYS_IOSEL_OFFSET) | ||
117 | #define REALVIEW_SYS_TEST_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC0_OFFSET) | ||
118 | #define REALVIEW_SYS_TEST_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC1_OFFSET) | ||
119 | #define REALVIEW_SYS_TEST_OSC2 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC2_OFFSET) | ||
120 | #define REALVIEW_SYS_TEST_OSC3 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC3_OFFSET) | ||
121 | #define REALVIEW_SYS_TEST_OSC4 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC4_OFFSET) | ||
122 | |||
123 | /* | ||
124 | * Values for REALVIEW_SYS_RESET_CTRL | ||
125 | */ | ||
126 | #define REALVIEW_SYS_CTRL_RESET_CONFIGCLR 0x01 | ||
127 | #define REALVIEW_SYS_CTRL_RESET_CONFIGINIT 0x02 | ||
128 | #define REALVIEW_SYS_CTRL_RESET_DLLRESET 0x03 | ||
129 | #define REALVIEW_SYS_CTRL_RESET_PLLRESET 0x04 | ||
130 | #define REALVIEW_SYS_CTRL_RESET_POR 0x05 | ||
131 | #define REALVIEW_SYS_CTRL_RESET_DoC 0x06 | ||
132 | |||
133 | #define REALVIEW_SYS_CTRL_LED (1 << 0) | ||
134 | |||
135 | |||
136 | /* ------------------------------------------------------------------------ | ||
137 | * RealView control registers | ||
138 | * ------------------------------------------------------------------------ | ||
139 | */ | ||
140 | |||
141 | /* | ||
142 | * REALVIEW_IDFIELD | ||
143 | * | ||
144 | * 31:24 = manufacturer (0x41 = ARM) | ||
145 | * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus) | ||
146 | * 15:12 = FPGA (0x3 = XVC600 or XVC600E) | ||
147 | * 11:4 = build value | ||
148 | * 3:0 = revision number (0x1 = rev B (AHB)) | ||
149 | */ | ||
150 | |||
151 | /* | ||
152 | * REALVIEW_SYS_LOCK | ||
153 | * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL, | ||
154 | * SYS_CLD, SYS_BOOTCS | ||
155 | */ | ||
156 | #define REALVIEW_SYS_LOCK_LOCKED (1 << 16) | ||
157 | #define REALVIEW_SYS_LOCKVAL_MASK 0xFFFF /* write 0xA05F to enable write access */ | ||
158 | |||
159 | /* | ||
160 | * REALVIEW_SYS_FLASH | ||
161 | */ | ||
162 | #define REALVIEW_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */ | ||
163 | |||
164 | /* | ||
165 | * REALVIEW_INTREG | ||
166 | * - used to acknowledge and control MMCI and UART interrupts | ||
167 | */ | ||
168 | #define REALVIEW_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */ | ||
169 | #define REALVIEW_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */ | ||
170 | #define REALVIEW_INTREG_CARDIN 0x08 /* MMCI card in detect */ | ||
171 | /* write 1 to acknowledge and clear */ | ||
172 | #define REALVIEW_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */ | ||
173 | #define REALVIEW_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */ | ||
174 | |||
175 | /* | ||
176 | * REALVIEW peripheral addresses | ||
177 | */ | ||
178 | #define REALVIEW_SCTL_BASE 0x10001000 /* System controller */ | ||
179 | #define REALVIEW_I2C_BASE 0x10002000 /* I2C control */ | ||
180 | /* Reserved 0x10003000 */ | ||
181 | #define REALVIEW_AACI_BASE 0x10004000 /* Audio */ | ||
182 | #define REALVIEW_MMCI0_BASE 0x10005000 /* MMC interface */ | ||
183 | #define REALVIEW_KMI0_BASE 0x10006000 /* KMI interface */ | ||
184 | #define REALVIEW_KMI1_BASE 0x10007000 /* KMI 2nd interface */ | ||
185 | #define REALVIEW_CHAR_LCD_BASE 0x10008000 /* Character LCD */ | ||
186 | #define REALVIEW_UART0_BASE 0x10009000 /* UART 0 */ | ||
187 | #define REALVIEW_UART1_BASE 0x1000A000 /* UART 1 */ | ||
188 | #define REALVIEW_UART2_BASE 0x1000B000 /* UART 2 */ | ||
189 | #define REALVIEW_UART3_BASE 0x1000C000 /* UART 3 */ | ||
190 | #define REALVIEW_SSP_BASE 0x1000D000 /* Synchronous Serial Port */ | ||
191 | #define REALVIEW_SCI_BASE 0x1000E000 /* Smart card controller */ | ||
192 | /* Reserved 0x1000F000 */ | ||
193 | #define REALVIEW_WATCHDOG_BASE 0x10010000 /* watchdog interface */ | ||
194 | #define REALVIEW_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */ | ||
195 | #define REALVIEW_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */ | ||
196 | #define REALVIEW_GPIO0_BASE 0x10013000 /* GPIO port 0 */ | ||
197 | #define REALVIEW_GPIO1_BASE 0x10014000 /* GPIO port 1 */ | ||
198 | #define REALVIEW_GPIO2_BASE 0x10015000 /* GPIO port 2 */ | ||
199 | /* Reserved 0x10016000 */ | ||
200 | #define REALVIEW_RTC_BASE 0x10017000 /* Real Time Clock */ | ||
201 | #define REALVIEW_DMC_BASE 0x10018000 /* DMC configuration */ | ||
202 | #define REALVIEW_PCI_CORE_BASE 0x10019000 /* PCI configuration */ | ||
203 | /* Reserved 0x1001A000 - 0x1001FFFF */ | ||
204 | #define REALVIEW_CLCD_BASE 0x10020000 /* CLCD */ | ||
205 | #define REALVIEW_DMAC_BASE 0x10030000 /* DMA controller */ | ||
206 | #define REALVIEW_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */ | ||
207 | #define REALVIEW_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */ | ||
208 | #define REALVIEW_SMC_BASE 0x10080000 /* SMC */ | ||
209 | /* Reserved 0x10090000 - 0x100EFFFF */ | ||
210 | |||
211 | #define REALVIEW_ETH_BASE 0x4E000000 /* Ethernet */ | ||
212 | |||
213 | /* PCI space */ | ||
214 | #define REALVIEW_PCI_BASE 0x41000000 /* PCI Interface */ | ||
215 | #define REALVIEW_PCI_CFG_BASE 0x42000000 | ||
216 | #define REALVIEW_PCI_MEM_BASE0 0x44000000 | ||
217 | #define REALVIEW_PCI_MEM_BASE1 0x50000000 | ||
218 | #define REALVIEW_PCI_MEM_BASE2 0x60000000 | ||
219 | /* Sizes of above maps */ | ||
220 | #define REALVIEW_PCI_BASE_SIZE 0x01000000 | ||
221 | #define REALVIEW_PCI_CFG_BASE_SIZE 0x02000000 | ||
222 | #define REALVIEW_PCI_MEM_BASE0_SIZE 0x0c000000 /* 32Mb */ | ||
223 | #define REALVIEW_PCI_MEM_BASE1_SIZE 0x10000000 /* 256Mb */ | ||
224 | #define REALVIEW_PCI_MEM_BASE2_SIZE 0x10000000 /* 256Mb */ | ||
225 | |||
226 | #define REALVIEW_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */ | ||
227 | #define REALVIEW_LT_BASE 0x80000000 /* Logic Tile expansion */ | ||
228 | |||
229 | /* | ||
230 | * Disk on Chip | ||
231 | */ | ||
232 | #define REALVIEW_DOC_BASE 0x2C000000 | ||
233 | #define REALVIEW_DOC_SIZE (16 << 20) | ||
234 | #define REALVIEW_DOC_PAGE_SIZE 512 | ||
235 | #define REALVIEW_DOC_TOTAL_PAGES (DOC_SIZE / PAGE_SIZE) | ||
236 | |||
237 | #define ERASE_UNIT_PAGES 32 | ||
238 | #define START_PAGE 0x80 | ||
239 | |||
240 | /* | ||
241 | * LED settings, bits [7:0] | ||
242 | */ | ||
243 | #define REALVIEW_SYS_LED0 (1 << 0) | ||
244 | #define REALVIEW_SYS_LED1 (1 << 1) | ||
245 | #define REALVIEW_SYS_LED2 (1 << 2) | ||
246 | #define REALVIEW_SYS_LED3 (1 << 3) | ||
247 | #define REALVIEW_SYS_LED4 (1 << 4) | ||
248 | #define REALVIEW_SYS_LED5 (1 << 5) | ||
249 | #define REALVIEW_SYS_LED6 (1 << 6) | ||
250 | #define REALVIEW_SYS_LED7 (1 << 7) | ||
251 | |||
252 | #define ALL_LEDS 0xFF | ||
253 | |||
254 | #define LED_BANK REALVIEW_SYS_LED | ||
255 | |||
256 | /* | ||
257 | * Control registers | ||
258 | */ | ||
259 | #define REALVIEW_IDFIELD_OFFSET 0x0 /* RealView build information */ | ||
260 | #define REALVIEW_FLASHPROG_OFFSET 0x4 /* Flash devices */ | ||
261 | #define REALVIEW_INTREG_OFFSET 0x8 /* Interrupt control */ | ||
262 | #define REALVIEW_DECODE_OFFSET 0xC /* Fitted logic modules */ | ||
263 | |||
264 | /* ------------------------------------------------------------------------ | ||
265 | * Interrupts - bit assignment (primary) | ||
266 | * ------------------------------------------------------------------------ | ||
267 | */ | ||
268 | #define INT_WDOGINT 0 /* Watchdog timer */ | ||
269 | #define INT_SOFTINT 1 /* Software interrupt */ | ||
270 | #define INT_COMMRx 2 /* Debug Comm Rx interrupt */ | ||
271 | #define INT_COMMTx 3 /* Debug Comm Tx interrupt */ | ||
272 | #define INT_TIMERINT0_1 4 /* Timer 0 and 1 */ | ||
273 | #define INT_TIMERINT2_3 5 /* Timer 2 and 3 */ | ||
274 | #define INT_GPIOINT0 6 /* GPIO 0 */ | ||
275 | #define INT_GPIOINT1 7 /* GPIO 1 */ | ||
276 | #define INT_GPIOINT2 8 /* GPIO 2 */ | ||
277 | /* 9 reserved */ | ||
278 | #define INT_RTCINT 10 /* Real Time Clock */ | ||
279 | #define INT_SSPINT 11 /* Synchronous Serial Port */ | ||
280 | #define INT_UARTINT0 12 /* UART 0 on development chip */ | ||
281 | #define INT_UARTINT1 13 /* UART 1 on development chip */ | ||
282 | #define INT_UARTINT2 14 /* UART 2 on development chip */ | ||
283 | #define INT_UARTINT3 15 /* UART 3 on development chip */ | ||
284 | #define INT_SCIINT 16 /* Smart Card Interface */ | ||
285 | #define INT_MMCI0A 17 /* Multimedia Card 0A */ | ||
286 | #define INT_MMCI0B 18 /* Multimedia Card 0B */ | ||
287 | #define INT_AACI 19 /* Audio Codec */ | ||
288 | #define INT_KMI0 20 /* Keyboard/Mouse port 0 */ | ||
289 | #define INT_KMI1 21 /* Keyboard/Mouse port 1 */ | ||
290 | #define INT_CHARLCD 22 /* Character LCD */ | ||
291 | #define INT_CLCDINT 23 /* CLCD controller */ | ||
292 | #define INT_DMAINT 24 /* DMA controller */ | ||
293 | #define INT_PWRFAILINT 25 /* Power failure */ | ||
294 | #define INT_PISMO 26 | ||
295 | #define INT_DoC 27 /* Disk on Chip memory controller */ | ||
296 | #define INT_ETH 28 /* Ethernet controller */ | ||
297 | #define INT_USB 29 /* USB controller */ | ||
298 | #define INT_TSPENINT 30 /* Touchscreen pen */ | ||
299 | #define INT_TSKPADINT 31 /* Touchscreen keypad */ | ||
300 | |||
301 | /* | ||
302 | * Interrupt bit positions | ||
303 | * | ||
304 | */ | ||
305 | #define INTMASK_WDOGINT (1 << INT_WDOGINT) | ||
306 | #define INTMASK_SOFTINT (1 << INT_SOFTINT) | ||
307 | #define INTMASK_COMMRx (1 << INT_COMMRx) | ||
308 | #define INTMASK_COMMTx (1 << INT_COMMTx) | ||
309 | #define INTMASK_TIMERINT0_1 (1 << INT_TIMERINT0_1) | ||
310 | #define INTMASK_TIMERINT2_3 (1 << INT_TIMERINT2_3) | ||
311 | #define INTMASK_GPIOINT0 (1 << INT_GPIOINT0) | ||
312 | #define INTMASK_GPIOINT1 (1 << INT_GPIOINT1) | ||
313 | #define INTMASK_GPIOINT2 (1 << INT_GPIOINT2) | ||
314 | #define INTMASK_RTCINT (1 << INT_RTCINT) | ||
315 | #define INTMASK_SSPINT (1 << INT_SSPINT) | ||
316 | #define INTMASK_UARTINT0 (1 << INT_UARTINT0) | ||
317 | #define INTMASK_UARTINT1 (1 << INT_UARTINT1) | ||
318 | #define INTMASK_UARTINT2 (1 << INT_UARTINT2) | ||
319 | #define INTMASK_UARTINT3 (1 << INT_UARTINT3) | ||
320 | #define INTMASK_SCIINT (1 << INT_SCIINT) | ||
321 | #define INTMASK_MMCI0A (1 << INT_MMCI0A) | ||
322 | #define INTMASK_MMCI0B (1 << INT_MMCI0B) | ||
323 | #define INTMASK_AACI (1 << INT_AACI) | ||
324 | #define INTMASK_KMI0 (1 << INT_KMI0) | ||
325 | #define INTMASK_KMI1 (1 << INT_KMI1) | ||
326 | #define INTMASK_CHARLCD (1 << INT_CHARLCD) | ||
327 | #define INTMASK_CLCDINT (1 << INT_CLCDINT) | ||
328 | #define INTMASK_DMAINT (1 << INT_DMAINT) | ||
329 | #define INTMASK_PWRFAILINT (1 << INT_PWRFAILINT) | ||
330 | #define INTMASK_PISMO (1 << INT_PISMO) | ||
331 | #define INTMASK_DoC (1 << INT_DoC) | ||
332 | #define INTMASK_ETH (1 << INT_ETH) | ||
333 | #define INTMASK_USB (1 << INT_USB) | ||
334 | #define INTMASK_TSPENINT (1 << INT_TSPENINT) | ||
335 | #define INTMASK_TSKPADINT (1 << INT_TSKPADINT) | ||
336 | |||
337 | #define MAXIRQNUM 31 | ||
338 | #define MAXFIQNUM 31 | ||
339 | #define MAXSWINUM 31 | ||
340 | |||
341 | /* | ||
342 | * Application Flash | ||
343 | * | ||
344 | */ | ||
345 | #define FLASH_BASE REALVIEW_FLASH_BASE | ||
346 | #define FLASH_SIZE REALVIEW_FLASH_SIZE | ||
347 | #define FLASH_END (FLASH_BASE + FLASH_SIZE - 1) | ||
348 | #define FLASH_BLOCK_SIZE SZ_128K | ||
349 | |||
350 | /* | ||
351 | * Boot Flash | ||
352 | * | ||
353 | */ | ||
354 | #define EPROM_BASE REALVIEW_BOOT_ROM_HI | ||
355 | #define EPROM_SIZE REALVIEW_BOOT_ROM_SIZE | ||
356 | #define EPROM_END (EPROM_BASE + EPROM_SIZE - 1) | ||
357 | |||
358 | /* | ||
359 | * Clean base - dummy | ||
360 | * | ||
361 | */ | ||
362 | #define CLEAN_BASE EPROM_BASE | ||
363 | |||
364 | /* | ||
365 | * System controller bit assignment | ||
366 | */ | ||
367 | #define REALVIEW_REFCLK 0 | ||
368 | #define REALVIEW_TIMCLK 1 | ||
369 | |||
370 | #define REALVIEW_TIMER1_EnSel 15 | ||
371 | #define REALVIEW_TIMER2_EnSel 17 | ||
372 | #define REALVIEW_TIMER3_EnSel 19 | ||
373 | #define REALVIEW_TIMER4_EnSel 21 | ||
374 | |||
375 | |||
376 | #define MAX_TIMER 2 | ||
377 | #define MAX_PERIOD 699050 | ||
378 | #define TICKS_PER_uSEC 1 | ||
379 | |||
380 | /* | ||
381 | * These are useconds NOT ticks. | ||
382 | * | ||
383 | */ | ||
384 | #define mSEC_1 1000 | ||
385 | #define mSEC_5 (mSEC_1 * 5) | ||
386 | #define mSEC_10 (mSEC_1 * 10) | ||
387 | #define mSEC_25 (mSEC_1 * 25) | ||
388 | #define SEC_1 (mSEC_1 * 1000) | ||
389 | |||
390 | #define REALVIEW_CSR_BASE 0x10000000 | ||
391 | #define REALVIEW_CSR_SIZE 0x10000000 | ||
392 | |||
393 | #endif | ||
394 | |||
395 | /* END */ | ||
diff --git a/include/asm-arm/arch-realview/system.h b/include/asm-arm/arch-realview/system.h new file mode 100644 index 000000000000..9f8fcbca0869 --- /dev/null +++ b/include/asm-arm/arch-realview/system.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/system.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited | ||
5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #ifndef __ASM_ARCH_SYSTEM_H | ||
22 | #define __ASM_ARCH_SYSTEM_H | ||
23 | |||
24 | #include <asm/hardware.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/arch/platform.h> | ||
27 | |||
28 | static inline void arch_idle(void) | ||
29 | { | ||
30 | /* | ||
31 | * This should do all the clock switching | ||
32 | * and wait for interrupt tricks | ||
33 | */ | ||
34 | cpu_do_idle(); | ||
35 | } | ||
36 | |||
37 | static inline void arch_reset(char mode) | ||
38 | { | ||
39 | unsigned int hdr_ctrl = (IO_ADDRESS(REALVIEW_SYS_BASE) + REALVIEW_SYS_RESETCTL_OFFSET); | ||
40 | unsigned int val; | ||
41 | |||
42 | /* | ||
43 | * To reset, we hit the on-board reset register | ||
44 | * in the system FPGA | ||
45 | */ | ||
46 | val = __raw_readl(hdr_ctrl); | ||
47 | val |= REALVIEW_SYS_CTRL_RESET_CONFIGCLR; | ||
48 | __raw_writel(val, hdr_ctrl); | ||
49 | } | ||
50 | |||
51 | #endif | ||
diff --git a/include/asm-arm/arch-realview/timex.h b/include/asm-arm/arch-realview/timex.h new file mode 100644 index 000000000000..5b9d82d0a5e0 --- /dev/null +++ b/include/asm-arm/arch-realview/timex.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/timex.h | ||
3 | * | ||
4 | * RealView architecture timex specifications | ||
5 | * | ||
6 | * Copyright (C) 2003 ARM Limited | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #define CLOCK_TICK_RATE (50000000 / 16) | ||
diff --git a/include/asm-arm/arch-realview/uncompress.h b/include/asm-arm/arch-realview/uncompress.h new file mode 100644 index 000000000000..b5e4d360665b --- /dev/null +++ b/include/asm-arm/arch-realview/uncompress.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/uncompress.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | #include <asm/hardware.h> | ||
21 | |||
22 | #define AMBA_UART_DR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x00)) | ||
23 | #define AMBA_UART_LCRH (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x2c)) | ||
24 | #define AMBA_UART_CR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x30)) | ||
25 | #define AMBA_UART_FR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x18)) | ||
26 | |||
27 | /* | ||
28 | * This does not append a newline | ||
29 | */ | ||
30 | static void putstr(const char *s) | ||
31 | { | ||
32 | while (*s) { | ||
33 | while (AMBA_UART_FR & (1 << 5)) | ||
34 | barrier(); | ||
35 | |||
36 | AMBA_UART_DR = *s; | ||
37 | |||
38 | if (*s == '\n') { | ||
39 | while (AMBA_UART_FR & (1 << 5)) | ||
40 | barrier(); | ||
41 | |||
42 | AMBA_UART_DR = '\r'; | ||
43 | } | ||
44 | s++; | ||
45 | } | ||
46 | while (AMBA_UART_FR & (1 << 3)) | ||
47 | barrier(); | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * nothing to do | ||
52 | */ | ||
53 | #define arch_decomp_setup() | ||
54 | #define arch_decomp_wdog() | ||
diff --git a/include/asm-arm/arch-realview/vmalloc.h b/include/asm-arm/arch-realview/vmalloc.h new file mode 100644 index 000000000000..0ad49af186af --- /dev/null +++ b/include/asm-arm/arch-realview/vmalloc.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * linux/include/asm-arm/arch-realview/vmalloc.h | ||
3 | * | ||
4 | * Copyright (C) 2003 ARM Limited | ||
5 | * Copyright (C) 2000 Russell King. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #define VMALLOC_END (PAGE_OFFSET + 0x18000000) | ||
diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h index fdd62e8cd6cb..7fdde9b91cb4 100644 --- a/include/asm-arm/arch-s3c2410/regs-iis.h +++ b/include/asm-arm/arch-s3c2410/regs-iis.h | |||
@@ -55,6 +55,7 @@ | |||
55 | #define S3C2410_IISMOD_16FS (0<<0) | 55 | #define S3C2410_IISMOD_16FS (0<<0) |
56 | #define S3C2410_IISMOD_32FS (1<<0) | 56 | #define S3C2410_IISMOD_32FS (1<<0) |
57 | #define S3C2410_IISMOD_48FS (2<<0) | 57 | #define S3C2410_IISMOD_48FS (2<<0) |
58 | #define S3C2410_IISMOD_FS_MASK (3<<0) | ||
58 | 59 | ||
59 | #define S3C2410_IISPSR (0x08) | 60 | #define S3C2410_IISPSR (0x08) |
60 | #define S3C2410_IISPSR_INTMASK (31<<5) | 61 | #define S3C2410_IISPSR_INTMASK (31<<5) |
diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h index ce4cf5c1c05d..6b8d73dc1ab0 100644 --- a/include/asm-arm/hardware/amba_clcd.h +++ b/include/asm-arm/hardware/amba_clcd.h | |||
@@ -22,7 +22,7 @@ | |||
22 | #define CLCD_UBAS 0x00000010 | 22 | #define CLCD_UBAS 0x00000010 |
23 | #define CLCD_LBAS 0x00000014 | 23 | #define CLCD_LBAS 0x00000014 |
24 | 24 | ||
25 | #ifndef CONFIG_ARCH_VERSATILE | 25 | #if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW) |
26 | #define CLCD_IENB 0x00000018 | 26 | #define CLCD_IENB 0x00000018 |
27 | #define CLCD_CNTL 0x0000001c | 27 | #define CLCD_CNTL 0x0000001c |
28 | #else | 28 | #else |
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index a515e2aed829..8c454aa58ac6 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h | |||
@@ -118,8 +118,7 @@ extern void release_lapic_nmi(void); | |||
118 | extern void disable_timer_nmi_watchdog(void); | 118 | extern void disable_timer_nmi_watchdog(void); |
119 | extern void enable_timer_nmi_watchdog(void); | 119 | extern void enable_timer_nmi_watchdog(void); |
120 | extern void nmi_watchdog_tick (struct pt_regs * regs); | 120 | extern void nmi_watchdog_tick (struct pt_regs * regs); |
121 | extern int APIC_init(void); | 121 | extern int APIC_init_uniprocessor (void); |
122 | extern void APIC_late_time_init(void); | ||
123 | extern void disable_APIC_timer(void); | 122 | extern void disable_APIC_timer(void); |
124 | extern void enable_APIC_timer(void); | 123 | extern void enable_APIC_timer(void); |
125 | 124 | ||
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 9139b89497a1..622815bf3243 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h | |||
@@ -55,7 +55,6 @@ void init_8259A(int aeoi); | |||
55 | void FASTCALL(send_IPI_self(int vector)); | 55 | void FASTCALL(send_IPI_self(int vector)); |
56 | void init_VISWS_APIC_irqs(void); | 56 | void init_VISWS_APIC_irqs(void); |
57 | void setup_IO_APIC(void); | 57 | void setup_IO_APIC(void); |
58 | void IO_APIC_late_time_init(void); | ||
59 | void disable_IO_APIC(void); | 58 | void disable_IO_APIC(void); |
60 | void print_IO_APIC(void); | 59 | void print_IO_APIC(void); |
61 | int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); | 60 | int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); |
diff --git a/include/asm-i386/mach-default/smpboot_hooks.h b/include/asm-i386/mach-default/smpboot_hooks.h index d7c70c144f9f..7f45f6311059 100644 --- a/include/asm-i386/mach-default/smpboot_hooks.h +++ b/include/asm-i386/mach-default/smpboot_hooks.h | |||
@@ -1,6 +1,11 @@ | |||
1 | /* two abstractions specific to kernel/smpboot.c, mainly to cater to visws | 1 | /* two abstractions specific to kernel/smpboot.c, mainly to cater to visws |
2 | * which needs to alter them. */ | 2 | * which needs to alter them. */ |
3 | 3 | ||
4 | static inline void smpboot_clear_io_apic_irqs(void) | ||
5 | { | ||
6 | io_apic_irqs = 0; | ||
7 | } | ||
8 | |||
4 | static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) | 9 | static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) |
5 | { | 10 | { |
6 | CMOS_WRITE(0xa, 0xf); | 11 | CMOS_WRITE(0xa, 0xf); |
@@ -27,3 +32,13 @@ static inline void smpboot_restore_warm_reset_vector(void) | |||
27 | 32 | ||
28 | *((volatile long *) phys_to_virt(0x467)) = 0; | 33 | *((volatile long *) phys_to_virt(0x467)) = 0; |
29 | } | 34 | } |
35 | |||
36 | static inline void smpboot_setup_io_apic(void) | ||
37 | { | ||
38 | /* | ||
39 | * Here we can be sure that there is an IO-APIC in the system. Let's | ||
40 | * go and set it up: | ||
41 | */ | ||
42 | if (!skip_ioapic_setup && nr_ioapics) | ||
43 | setup_IO_APIC(); | ||
44 | } | ||
diff --git a/include/asm-i386/mach-visws/smpboot_hooks.h b/include/asm-i386/mach-visws/smpboot_hooks.h index 14d8e0375f7a..d926471fa359 100644 --- a/include/asm-i386/mach-visws/smpboot_hooks.h +++ b/include/asm-i386/mach-visws/smpboot_hooks.h | |||
@@ -11,7 +11,14 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) | |||
11 | 11 | ||
12 | /* for visws do nothing for any of these */ | 12 | /* for visws do nothing for any of these */ |
13 | 13 | ||
14 | static inline void smpboot_clear_io_apic_irqs(void) | ||
15 | { | ||
16 | } | ||
17 | |||
14 | static inline void smpboot_restore_warm_reset_vector(void) | 18 | static inline void smpboot_restore_warm_reset_vector(void) |
15 | { | 19 | { |
16 | } | 20 | } |
17 | 21 | ||
22 | static inline void smpboot_setup_io_apic(void) | ||
23 | { | ||
24 | } | ||
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h index 549f44843c5e..bba5305c29ed 100644 --- a/include/asm-ppc/ppc_sys.h +++ b/include/asm-ppc/ppc_sys.h | |||
@@ -18,7 +18,7 @@ | |||
18 | #define __ASM_PPC_SYS_H | 18 | #define __ASM_PPC_SYS_H |
19 | 19 | ||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | 23 | ||
24 | #if defined(CONFIG_8260) | 24 | #if defined(CONFIG_8260) |
diff --git a/include/linux/device.h b/include/linux/device.h index a9e72ac3fb9f..17cbc6db67b4 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -396,32 +396,6 @@ extern struct device * get_device(struct device * dev); | |||
396 | extern void put_device(struct device * dev); | 396 | extern void put_device(struct device * dev); |
397 | 397 | ||
398 | 398 | ||
399 | /* drivers/base/platform.c */ | ||
400 | |||
401 | struct platform_device { | ||
402 | const char * name; | ||
403 | u32 id; | ||
404 | struct device dev; | ||
405 | u32 num_resources; | ||
406 | struct resource * resource; | ||
407 | }; | ||
408 | |||
409 | #define to_platform_device(x) container_of((x), struct platform_device, dev) | ||
410 | |||
411 | extern int platform_device_register(struct platform_device *); | ||
412 | extern void platform_device_unregister(struct platform_device *); | ||
413 | |||
414 | extern struct bus_type platform_bus_type; | ||
415 | extern struct device platform_bus; | ||
416 | |||
417 | extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int); | ||
418 | extern int platform_get_irq(struct platform_device *, unsigned int); | ||
419 | extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, char *); | ||
420 | extern int platform_get_irq_byname(struct platform_device *, char *); | ||
421 | extern int platform_add_devices(struct platform_device **, int); | ||
422 | |||
423 | extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int); | ||
424 | |||
425 | /* drivers/base/power.c */ | 399 | /* drivers/base/power.c */ |
426 | extern void device_shutdown(void); | 400 | extern void device_shutdown(void); |
427 | 401 | ||
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h new file mode 100644 index 000000000000..a726225e0afe --- /dev/null +++ b/include/linux/platform_device.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * platform_device.h - generic, centralized driver model | ||
3 | * | ||
4 | * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org> | ||
5 | * | ||
6 | * This file is released under the GPLv2 | ||
7 | * | ||
8 | * See Documentation/driver-model/ for more information. | ||
9 | */ | ||
10 | |||
11 | #ifndef _PLATFORM_DEVICE_H_ | ||
12 | #define _PLATFORM_DEVICE_H_ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | |||
16 | struct platform_device { | ||
17 | const char * name; | ||
18 | u32 id; | ||
19 | struct device dev; | ||
20 | u32 num_resources; | ||
21 | struct resource * resource; | ||
22 | }; | ||
23 | |||
24 | #define to_platform_device(x) container_of((x), struct platform_device, dev) | ||
25 | |||
26 | extern int platform_device_register(struct platform_device *); | ||
27 | extern void platform_device_unregister(struct platform_device *); | ||
28 | |||
29 | extern struct bus_type platform_bus_type; | ||
30 | extern struct device platform_bus; | ||
31 | |||
32 | extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int); | ||
33 | extern int platform_get_irq(struct platform_device *, unsigned int); | ||
34 | extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, char *); | ||
35 | extern int platform_get_irq_byname(struct platform_device *, char *); | ||
36 | extern int platform_add_devices(struct platform_device **, int); | ||
37 | |||
38 | extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int); | ||
39 | |||
40 | #endif /* _PLATFORM_DEVICE_H_ */ | ||
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 317a979b24de..2b799d40d669 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h | |||
@@ -12,7 +12,7 @@ | |||
12 | #define _LINUX_SERIAL_8250_H | 12 | #define _LINUX_SERIAL_8250_H |
13 | 13 | ||
14 | #include <linux/serial_core.h> | 14 | #include <linux/serial_core.h> |
15 | #include <linux/device.h> | 15 | #include <linux/platform_device.h> |
16 | 16 | ||
17 | /* | 17 | /* |
18 | * This is the platform device platform_data structure | 18 | * This is the platform device platform_data structure |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 14cb2718cb77..46e3c0bf3c94 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
@@ -1055,6 +1055,7 @@ typedef struct { | |||
1055 | unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ | 1055 | unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ |
1056 | unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ | 1056 | unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ |
1057 | unsigned char ca0108_chip; /* Audigy 2 Value */ | 1057 | unsigned char ca0108_chip; /* Audigy 2 Value */ |
1058 | unsigned char ca_cardbus_chip; /* Audigy 2 ZS Notebook */ | ||
1058 | unsigned char ca0151_chip; /* P16V */ | 1059 | unsigned char ca0151_chip; /* P16V */ |
1059 | unsigned char spk71; /* Has 7.1 speakers */ | 1060 | unsigned char spk71; /* Has 7.1 speakers */ |
1060 | unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ | 1061 | unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ |
diff --git a/init/main.c b/init/main.c index 4075d97e94b1..f142d4035341 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -64,6 +64,10 @@ | |||
64 | #endif | 64 | #endif |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | #ifdef CONFIG_X86_LOCAL_APIC | ||
68 | #include <asm/smp.h> | ||
69 | #endif | ||
70 | |||
67 | /* | 71 | /* |
68 | * Versions of gcc older than that listed below may actually compile | 72 | * Versions of gcc older than that listed below may actually compile |
69 | * and link okay, but the end product can have subtle run time bugs. | 73 | * and link okay, but the end product can have subtle run time bugs. |
@@ -310,7 +314,14 @@ extern void setup_arch(char **); | |||
310 | 314 | ||
311 | #ifndef CONFIG_SMP | 315 | #ifndef CONFIG_SMP |
312 | 316 | ||
317 | #ifdef CONFIG_X86_LOCAL_APIC | ||
318 | static void __init smp_init(void) | ||
319 | { | ||
320 | APIC_init_uniprocessor(); | ||
321 | } | ||
322 | #else | ||
313 | #define smp_init() do { } while (0) | 323 | #define smp_init() do { } while (0) |
324 | #endif | ||
314 | 325 | ||
315 | static inline void setup_per_cpu_areas(void) { } | 326 | static inline void setup_per_cpu_areas(void) { } |
316 | static inline void smp_prepare_cpus(unsigned int maxcpus) { } | 327 | static inline void smp_prepare_cpus(unsigned int maxcpus) { } |
@@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec) | |||
259 | pagevec_reinit(pvec); | 259 | pagevec_reinit(pvec); |
260 | } | 260 | } |
261 | 261 | ||
262 | EXPORT_SYMBOL(__pagevec_release); | ||
263 | |||
262 | /* | 264 | /* |
263 | * pagevec_release() for pages which are known to not be on the LRU | 265 | * pagevec_release() for pages which are known to not be on the LRU |
264 | * | 266 | * |
@@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping, | |||
387 | return pagevec_count(pvec); | 389 | return pagevec_count(pvec); |
388 | } | 390 | } |
389 | 391 | ||
392 | EXPORT_SYMBOL(pagevec_lookup_tag); | ||
390 | 393 | ||
391 | #ifdef CONFIG_SMP | 394 | #ifdef CONFIG_SMP |
392 | /* | 395 | /* |
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 877bb00d3295..d1f9da498729 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/wait.h> | 18 | #include <linux/wait.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
diff --git a/sound/core/init.c b/sound/core/init.c index 59202de1d2ce..41e224986f35 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
31 | #include <linux/platform_device.h> | ||
32 | |||
31 | #include <sound/core.h> | 33 | #include <sound/core.h> |
32 | #include <sound/control.h> | 34 | #include <sound/control.h> |
33 | #include <sound/info.h> | 35 | #include <sound/info.h> |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e9cd8e054f25..53aeff0b783a 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -579,6 +579,30 @@ static int __devinit snd_emu10k1_ecard_init(emu10k1_t * emu) | |||
579 | return 0; | 579 | return 0; |
580 | } | 580 | } |
581 | 581 | ||
582 | static int __devinit snd_emu10k1_cardbus_init(emu10k1_t * emu) | ||
583 | { | ||
584 | unsigned long special_port; | ||
585 | unsigned int value; | ||
586 | |||
587 | /* Special initialisation routine | ||
588 | * before the rest of the IO-Ports become active. | ||
589 | */ | ||
590 | special_port = emu->port + 0x38; | ||
591 | value = inl(special_port); | ||
592 | outl(0x00d00000, special_port); | ||
593 | value = inl(special_port); | ||
594 | outl(0x00d00001, special_port); | ||
595 | value = inl(special_port); | ||
596 | outl(0x00d0005f, special_port); | ||
597 | value = inl(special_port); | ||
598 | outl(0x00d0007f, special_port); | ||
599 | value = inl(special_port); | ||
600 | outl(0x0090007f, special_port); | ||
601 | value = inl(special_port); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
582 | /* | 606 | /* |
583 | * Create the EMU10K1 instance | 607 | * Create the EMU10K1 instance |
584 | */ | 608 | */ |
@@ -624,6 +648,16 @@ static emu_chip_details_t emu_chip_details[] = { | |||
624 | .ca0108_chip = 1, | 648 | .ca0108_chip = 1, |
625 | .spk71 = 1, | 649 | .spk71 = 1, |
626 | .ac97_chip = 1} , | 650 | .ac97_chip = 1} , |
651 | /* Audigy 2 ZS Notebook Cardbus card.*/ | ||
652 | /* Tested by James@superbug.co.uk 30th October 2005 */ | ||
653 | /* Not working yet, but progressing. */ | ||
654 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, | ||
655 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", | ||
656 | .id = "Audigy2", | ||
657 | .emu10k2_chip = 1, | ||
658 | .ca0108_chip = 1, | ||
659 | .ca_cardbus_chip = 1, | ||
660 | .spk71 = 1} , | ||
627 | {.vendor = 0x1102, .device = 0x0008, | 661 | {.vendor = 0x1102, .device = 0x0008, |
628 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 662 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
629 | .id = "Audigy2", | 663 | .id = "Audigy2", |
@@ -1011,6 +1045,11 @@ int __devinit snd_emu10k1_create(snd_card_t * card, | |||
1011 | snd_emu10k1_free(emu); | 1045 | snd_emu10k1_free(emu); |
1012 | return err; | 1046 | return err; |
1013 | } | 1047 | } |
1048 | } else if (emu->card_capabilities->ca_cardbus_chip) { | ||
1049 | if ((err = snd_emu10k1_cardbus_init(emu)) < 0) { | ||
1050 | snd_emu10k1_free(emu); | ||
1051 | return err; | ||
1052 | } | ||
1014 | } else { | 1053 | } else { |
1015 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version | 1054 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version |
1016 | does not support this, it shouldn't do any harm */ | 1055 | does not support this, it shouldn't do any harm */ |