diff options
Diffstat (limited to 'fs/cifs')
47 files changed, 7429 insertions, 5544 deletions
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index 7f7fa3c302af..ea940b1db77b 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS | |||
@@ -35,7 +35,7 @@ Adrian Bunk (kcalloc cleanups) | |||
35 | Miklos Szeredi | 35 | Miklos Szeredi |
36 | Kazeon team for various fixes especially for 2.4 version. | 36 | Kazeon team for various fixes especially for 2.4 version. |
37 | Asser Ferno (Change Notify support) | 37 | Asser Ferno (Change Notify support) |
38 | Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup | 38 | Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanup |
39 | Gunter Kukkukk (testing and suggestions for support of old servers) | 39 | Gunter Kukkukk (testing and suggestions for support of old servers) |
40 | Igor Mammedov (DFS support) | 40 | Igor Mammedov (DFS support) |
41 | Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) | 41 | Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code) |
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 917b7d449bb2..f66cc1625150 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -2,6 +2,13 @@ config CIFS | |||
2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" | 2 | tristate "CIFS support (advanced network filesystem, SMBFS successor)" |
3 | depends on INET | 3 | depends on INET |
4 | select NLS | 4 | select NLS |
5 | select CRYPTO | ||
6 | select CRYPTO_MD4 | ||
7 | select CRYPTO_MD5 | ||
8 | select CRYPTO_HMAC | ||
9 | select CRYPTO_ARC4 | ||
10 | select CRYPTO_ECB | ||
11 | select CRYPTO_DES | ||
5 | help | 12 | help |
6 | This is the client VFS module for the Common Internet File System | 13 | This is the client VFS module for the Common Internet File System |
7 | (CIFS) protocol which is the successor to the Server Message Block | 14 | (CIFS) protocol which is the successor to the Server Message Block |
@@ -140,16 +147,15 @@ config CIFS_FSCACHE | |||
140 | to be cached locally on disk through the general filesystem cache | 147 | to be cached locally on disk through the general filesystem cache |
141 | manager. If unsure, say N. | 148 | manager. If unsure, say N. |
142 | 149 | ||
143 | config CIFS_EXPERIMENTAL | 150 | config CIFS_ACL |
144 | bool "CIFS Experimental Features (EXPERIMENTAL)" | 151 | bool "Provide CIFS ACL support (EXPERIMENTAL)" |
145 | depends on CIFS && EXPERIMENTAL | 152 | depends on EXPERIMENTAL && CIFS_XATTR && KEYS |
146 | help | 153 | help |
147 | Enables cifs features under testing. These features are | 154 | Allows to fetch CIFS/NTFS ACL from the server. The DACL blob |
148 | experimental and currently include DFS support and directory | 155 | is handed over to the application/caller. |
149 | change notification ie fcntl(F_DNOTIFY), as well as the upcall | ||
150 | mechanism which will be used for Kerberos session negotiation | ||
151 | and uid remapping. Some of these features also may depend on | ||
152 | setting a value of 1 to the pseudo-file /proc/fs/cifs/Experimental | ||
153 | (which is disabled by default). See the file fs/cifs/README | ||
154 | for more details. If unsure, say N. | ||
155 | 156 | ||
157 | config CIFS_NFSD_EXPORT | ||
158 | bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)" | ||
159 | depends on CIFS && EXPERIMENTAL && BROKEN | ||
160 | help | ||
161 | Allows NFS server to export a CIFS mounted share (nfsd over cifs) | ||
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index adefa60a9bdc..005d524c3a4a 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
@@ -4,9 +4,11 @@ | |||
4 | obj-$(CONFIG_CIFS) += cifs.o | 4 | obj-$(CONFIG_CIFS) += cifs.o |
5 | 5 | ||
6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | 6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ |
7 | link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \ | 7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ |
8 | md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ | 8 | cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ |
9 | readdir.o ioctl.o sess.o export.o cifsacl.o | 9 | readdir.o ioctl.o sess.o export.o |
10 | |||
11 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o | ||
10 | 12 | ||
11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 13 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o |
12 | 14 | ||
diff --git a/fs/cifs/README b/fs/cifs/README index 7099a526f775..c5c2c5e5f0f2 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -337,6 +337,15 @@ A partial list of the supported mount options follows: | |||
337 | wsize default write size (default 57344) | 337 | wsize default write size (default 57344) |
338 | maximum wsize currently allowed by CIFS is 57344 (fourteen | 338 | maximum wsize currently allowed by CIFS is 57344 (fourteen |
339 | 4096 byte pages) | 339 | 4096 byte pages) |
340 | actimeo=n attribute cache timeout in seconds (default 1 second). | ||
341 | After this timeout, the cifs client requests fresh attribute | ||
342 | information from the server. This option allows to tune the | ||
343 | attribute cache timeout to suit the workload needs. Shorter | ||
344 | timeouts mean better the cache coherency, but increased number | ||
345 | of calls to the server. Longer timeouts mean reduced number | ||
346 | of calls to the server at the expense of less stricter cache | ||
347 | coherency checks (i.e. incorrect attribute cache for a short | ||
348 | period of time). | ||
340 | rw mount the network share read-write (note that the | 349 | rw mount the network share read-write (note that the |
341 | server may still consider the share read-only) | 350 | server may still consider the share read-only) |
342 | ro mount network share read-only | 351 | ro mount network share read-only |
@@ -443,6 +452,14 @@ A partial list of the supported mount options follows: | |||
443 | if oplock (caching token) is granted and held. Note that | 452 | if oplock (caching token) is granted and held. Note that |
444 | direct allows write operations larger than page size | 453 | direct allows write operations larger than page size |
445 | to be sent to the server. | 454 | to be sent to the server. |
455 | strictcache Use for switching on strict cache mode. In this mode the | ||
456 | client read from the cache all the time it has Oplock Level II, | ||
457 | otherwise - read from the server. All written data are stored | ||
458 | in the cache, but if the client doesn't have Exclusive Oplock, | ||
459 | it writes the data to the server. | ||
460 | rwpidforward Forward pid of a process who opened a file to any read or write | ||
461 | operation on that file. This prevent applications like WINE | ||
462 | from failing on read and write if we use mandatory brlock style. | ||
446 | acl Allow setfacl and getfacl to manage posix ACLs if server | 463 | acl Allow setfacl and getfacl to manage posix ACLs if server |
447 | supports them. (default) | 464 | supports them. (default) |
448 | noacl Do not allow setfacl and getfacl calls on this mount | 465 | noacl Do not allow setfacl and getfacl calls on this mount |
@@ -527,6 +544,11 @@ A partial list of the supported mount options follows: | |||
527 | SFU does). In the future the bottom 9 bits of the | 544 | SFU does). In the future the bottom 9 bits of the |
528 | mode also will be emulated using queries of the security | 545 | mode also will be emulated using queries of the security |
529 | descriptor (ACL). | 546 | descriptor (ACL). |
547 | mfsymlinks Enable support for Minshall+French symlinks | ||
548 | (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks) | ||
549 | This option is ignored when specified together with the | ||
550 | 'sfu' option. Minshall+French symlinks are used even if | ||
551 | the server supports the CIFS Unix Extensions. | ||
530 | sign Must use packet signing (helps avoid unwanted data modification | 552 | sign Must use packet signing (helps avoid unwanted data modification |
531 | by intermediate systems in the route). Note that signing | 553 | by intermediate systems in the route). Note that signing |
532 | does not work with lanman or plaintext authentication. | 554 | does not work with lanman or plaintext authentication. |
@@ -666,22 +688,6 @@ LinuxExtensionsEnabled If set to one then the client will attempt to | |||
666 | support and want to map the uid and gid fields | 688 | support and want to map the uid and gid fields |
667 | to values supplied at mount (rather than the | 689 | to values supplied at mount (rather than the |
668 | actual values, then set this to zero. (default 1) | 690 | actual values, then set this to zero. (default 1) |
669 | Experimental When set to 1 used to enable certain experimental | ||
670 | features (currently enables multipage writes | ||
671 | when signing is enabled, the multipage write | ||
672 | performance enhancement was disabled when | ||
673 | signing turned on in case buffer was modified | ||
674 | just before it was sent, also this flag will | ||
675 | be used to use the new experimental directory change | ||
676 | notification code). When set to 2 enables | ||
677 | an additional experimental feature, "raw ntlmssp" | ||
678 | session establishment support (which allows | ||
679 | specifying "sec=ntlmssp" on mount). The Linux cifs | ||
680 | module will use ntlmv2 authentication encapsulated | ||
681 | in "raw ntlmssp" (not using SPNEGO) when | ||
682 | "sec=ntlmssp" is specified on mount. | ||
683 | This support also requires building cifs with | ||
684 | the CONFIG_CIFS_EXPERIMENTAL configuration flag. | ||
685 | 691 | ||
686 | These experimental features and tracing can be enabled by changing flags in | 692 | These experimental features and tracing can be enabled by changing flags in |
687 | /proc/fs/cifs (after the cifs module has been installed or built into the | 693 | /proc/fs/cifs (after the cifs module has been installed or built into the |
@@ -701,18 +707,6 @@ the start of smb requests and responses can be enabled via: | |||
701 | 707 | ||
702 | echo 1 > /proc/fs/cifs/traceSMB | 708 | echo 1 > /proc/fs/cifs/traceSMB |
703 | 709 | ||
704 | Two other experimental features are under development. To test these | ||
705 | requires enabling CONFIG_CIFS_EXPERIMENTAL | ||
706 | |||
707 | cifsacl support needed to retrieve approximated mode bits based on | ||
708 | the contents on the CIFS ACL. | ||
709 | |||
710 | lease support: cifs will check the oplock state before calling into | ||
711 | the vfs to see if we can grant a lease on a file. | ||
712 | |||
713 | DNOTIFY fcntl: needed for support of directory change | ||
714 | notification and perhaps later for file leases) | ||
715 | |||
716 | Per share (per client mount) statistics are available in /proc/fs/cifs/Stats | 710 | Per share (per client mount) statistics are available in /proc/fs/cifs/Stats |
717 | if the kernel was configured with cifs statistics enabled. The statistics | 711 | if the kernel was configured with cifs statistics enabled. The statistics |
718 | represent the number of successful (ie non-zero return code from the server) | 712 | represent the number of successful (ie non-zero return code from the server) |
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 5aff46c61e52..355abcdcda98 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for | |||
81 | 81 | ||
82 | v) mount check for unmatched uids | 82 | v) mount check for unmatched uids |
83 | 83 | ||
84 | w) Add support for new vfs entry points for setlease and fallocate | 84 | w) Add support for new vfs entry point for fallocate |
85 | 85 | ||
86 | x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of | 86 | x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of |
87 | processes can proceed better in parallel (on the server) | 87 | processes can proceed better in parallel (on the server) |
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 224d7bbd1fcc..545509c3313b 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c | |||
@@ -50,7 +50,7 @@ void cifs_fscache_unregister(void) | |||
50 | */ | 50 | */ |
51 | struct cifs_server_key { | 51 | struct cifs_server_key { |
52 | uint16_t family; /* address family */ | 52 | uint16_t family; /* address family */ |
53 | uint16_t port; /* IP port */ | 53 | __be16 port; /* IP port */ |
54 | union { | 54 | union { |
55 | struct in_addr ipv4_addr; | 55 | struct in_addr ipv4_addr; |
56 | struct in6_addr ipv6_addr; | 56 | struct in6_addr ipv6_addr; |
@@ -64,7 +64,9 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | |||
64 | void *buffer, uint16_t maxbuf) | 64 | void *buffer, uint16_t maxbuf) |
65 | { | 65 | { |
66 | const struct TCP_Server_Info *server = cookie_netfs_data; | 66 | const struct TCP_Server_Info *server = cookie_netfs_data; |
67 | const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr; | 67 | const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr; |
68 | const struct sockaddr_in *addr = (struct sockaddr_in *) sa; | ||
69 | const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa; | ||
68 | struct cifs_server_key *key = buffer; | 70 | struct cifs_server_key *key = buffer; |
69 | uint16_t key_len = sizeof(struct cifs_server_key); | 71 | uint16_t key_len = sizeof(struct cifs_server_key); |
70 | 72 | ||
@@ -76,21 +78,21 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | |||
76 | */ | 78 | */ |
77 | switch (sa->sa_family) { | 79 | switch (sa->sa_family) { |
78 | case AF_INET: | 80 | case AF_INET: |
79 | key->family = server->addr.sockAddr.sin_family; | 81 | key->family = sa->sa_family; |
80 | key->port = server->addr.sockAddr.sin_port; | 82 | key->port = addr->sin_port; |
81 | key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr; | 83 | key->addr[0].ipv4_addr = addr->sin_addr; |
82 | key_len += sizeof(key->addr[0].ipv4_addr); | 84 | key_len += sizeof(key->addr[0].ipv4_addr); |
83 | break; | 85 | break; |
84 | 86 | ||
85 | case AF_INET6: | 87 | case AF_INET6: |
86 | key->family = server->addr.sockAddr6.sin6_family; | 88 | key->family = sa->sa_family; |
87 | key->port = server->addr.sockAddr6.sin6_port; | 89 | key->port = addr6->sin6_port; |
88 | key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr; | 90 | key->addr[0].ipv6_addr = addr6->sin6_addr; |
89 | key_len += sizeof(key->addr[0].ipv6_addr); | 91 | key_len += sizeof(key->addr[0].ipv6_addr); |
90 | break; | 92 | break; |
91 | 93 | ||
92 | default: | 94 | default: |
93 | cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family); | 95 | cERROR(1, "Unknown network family '%d'", sa->sa_family); |
94 | key_len = 0; | 96 | key_len = 0; |
95 | break; | 97 | break; |
96 | } | 98 | } |
@@ -144,13 +146,13 @@ static char *extract_sharename(const char *treename) | |||
144 | static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer, | 146 | static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer, |
145 | uint16_t maxbuf) | 147 | uint16_t maxbuf) |
146 | { | 148 | { |
147 | const struct cifsTconInfo *tcon = cookie_netfs_data; | 149 | const struct cifs_tcon *tcon = cookie_netfs_data; |
148 | char *sharename; | 150 | char *sharename; |
149 | uint16_t len; | 151 | uint16_t len; |
150 | 152 | ||
151 | sharename = extract_sharename(tcon->treeName); | 153 | sharename = extract_sharename(tcon->treeName); |
152 | if (IS_ERR(sharename)) { | 154 | if (IS_ERR(sharename)) { |
153 | cFYI(1, "CIFS: couldn't extract sharename\n"); | 155 | cFYI(1, "%s: couldn't extract sharename\n", __func__); |
154 | sharename = NULL; | 156 | sharename = NULL; |
155 | return 0; | 157 | return 0; |
156 | } | 158 | } |
@@ -171,7 +173,7 @@ cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer, | |||
171 | uint16_t maxbuf) | 173 | uint16_t maxbuf) |
172 | { | 174 | { |
173 | struct cifs_fscache_super_auxdata auxdata; | 175 | struct cifs_fscache_super_auxdata auxdata; |
174 | const struct cifsTconInfo *tcon = cookie_netfs_data; | 176 | const struct cifs_tcon *tcon = cookie_netfs_data; |
175 | 177 | ||
176 | memset(&auxdata, 0, sizeof(auxdata)); | 178 | memset(&auxdata, 0, sizeof(auxdata)); |
177 | auxdata.resource_id = tcon->resource_id; | 179 | auxdata.resource_id = tcon->resource_id; |
@@ -190,7 +192,7 @@ fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, | |||
190 | uint16_t datalen) | 192 | uint16_t datalen) |
191 | { | 193 | { |
192 | struct cifs_fscache_super_auxdata auxdata; | 194 | struct cifs_fscache_super_auxdata auxdata; |
193 | const struct cifsTconInfo *tcon = cookie_netfs_data; | 195 | const struct cifs_tcon *tcon = cookie_netfs_data; |
194 | 196 | ||
195 | if (datalen != sizeof(auxdata)) | 197 | if (datalen != sizeof(auxdata)) |
196 | return FSCACHE_CHECKAUX_OBSOLETE; | 198 | return FSCACHE_CHECKAUX_OBSOLETE; |
@@ -300,7 +302,7 @@ static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data) | |||
300 | pagevec_init(&pvec, 0); | 302 | pagevec_init(&pvec, 0); |
301 | first = 0; | 303 | first = 0; |
302 | 304 | ||
303 | cFYI(1, "cifs inode 0x%p now uncached", cifsi); | 305 | cFYI(1, "%s: cifs inode 0x%p now uncached", __func__, cifsi); |
304 | 306 | ||
305 | for (;;) { | 307 | for (;;) { |
306 | nr_pages = pagevec_lookup(&pvec, | 308 | nr_pages = pagevec_lookup(&pvec, |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index eb1ba493489f..2fe3cf13b2e9 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -63,7 +63,7 @@ void cifs_dump_detail(struct smb_hdr *smb) | |||
63 | cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", | 63 | cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", |
64 | smb->Command, smb->Status.CifsError, | 64 | smb->Command, smb->Status.CifsError, |
65 | smb->Flags, smb->Flags2, smb->Mid, smb->Pid); | 65 | smb->Flags, smb->Flags2, smb->Mid, smb->Pid); |
66 | cERROR(1, "smb buf %p len %d", smb, smbCalcSize_LE(smb)); | 66 | cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb)); |
67 | } | 67 | } |
68 | 68 | ||
69 | 69 | ||
@@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server) | |||
79 | spin_lock(&GlobalMid_Lock); | 79 | spin_lock(&GlobalMid_Lock); |
80 | list_for_each(tmp, &server->pending_mid_q) { | 80 | list_for_each(tmp, &server->pending_mid_q) { |
81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
82 | cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", | 82 | cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d", |
83 | mid_entry->midState, | 83 | mid_entry->midState, |
84 | (int)mid_entry->command, | 84 | (int)mid_entry->command, |
85 | mid_entry->pid, | 85 | mid_entry->pid, |
86 | mid_entry->tsk, | 86 | mid_entry->callback_data, |
87 | mid_entry->mid); | 87 | mid_entry->mid); |
88 | #ifdef CONFIG_CIFS_STATS2 | 88 | #ifdef CONFIG_CIFS_STATS2 |
89 | cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", | 89 | cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", |
@@ -110,8 +110,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
110 | struct list_head *tmp1, *tmp2, *tmp3; | 110 | struct list_head *tmp1, *tmp2, *tmp3; |
111 | struct mid_q_entry *mid_entry; | 111 | struct mid_q_entry *mid_entry; |
112 | struct TCP_Server_Info *server; | 112 | struct TCP_Server_Info *server; |
113 | struct cifsSesInfo *ses; | 113 | struct cifs_ses *ses; |
114 | struct cifsTconInfo *tcon; | 114 | struct cifs_tcon *tcon; |
115 | int i, j; | 115 | int i, j; |
116 | __u32 dev_type; | 116 | __u32 dev_type; |
117 | 117 | ||
@@ -119,42 +119,40 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
119 | "Display Internal CIFS Data Structures for Debugging\n" | 119 | "Display Internal CIFS Data Structures for Debugging\n" |
120 | "---------------------------------------------------\n"); | 120 | "---------------------------------------------------\n"); |
121 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); | 121 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); |
122 | seq_printf(m, "Features: "); | 122 | seq_printf(m, "Features:"); |
123 | #ifdef CONFIG_CIFS_DFS_UPCALL | 123 | #ifdef CONFIG_CIFS_DFS_UPCALL |
124 | seq_printf(m, "dfs"); | 124 | seq_printf(m, " dfs"); |
125 | seq_putc(m, ' '); | ||
126 | #endif | 125 | #endif |
127 | #ifdef CONFIG_CIFS_FSCACHE | 126 | #ifdef CONFIG_CIFS_FSCACHE |
128 | seq_printf(m, "fscache"); | 127 | seq_printf(m, " fscache"); |
129 | seq_putc(m, ' '); | ||
130 | #endif | 128 | #endif |
131 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 129 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
132 | seq_printf(m, "lanman"); | 130 | seq_printf(m, " lanman"); |
133 | seq_putc(m, ' '); | ||
134 | #endif | 131 | #endif |
135 | #ifdef CONFIG_CIFS_POSIX | 132 | #ifdef CONFIG_CIFS_POSIX |
136 | seq_printf(m, "posix"); | 133 | seq_printf(m, " posix"); |
137 | seq_putc(m, ' '); | ||
138 | #endif | 134 | #endif |
139 | #ifdef CONFIG_CIFS_UPCALL | 135 | #ifdef CONFIG_CIFS_UPCALL |
140 | seq_printf(m, "spnego"); | 136 | seq_printf(m, " spnego"); |
141 | seq_putc(m, ' '); | ||
142 | #endif | 137 | #endif |
143 | #ifdef CONFIG_CIFS_XATTR | 138 | #ifdef CONFIG_CIFS_XATTR |
144 | seq_printf(m, "xattr"); | 139 | seq_printf(m, " xattr"); |
140 | #endif | ||
141 | #ifdef CONFIG_CIFS_ACL | ||
142 | seq_printf(m, " acl"); | ||
145 | #endif | 143 | #endif |
146 | seq_putc(m, '\n'); | 144 | seq_putc(m, '\n'); |
147 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); | 145 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); |
148 | seq_printf(m, "Servers:"); | 146 | seq_printf(m, "Servers:"); |
149 | 147 | ||
150 | i = 0; | 148 | i = 0; |
151 | read_lock(&cifs_tcp_ses_lock); | 149 | spin_lock(&cifs_tcp_ses_lock); |
152 | list_for_each(tmp1, &cifs_tcp_ses_list) { | 150 | list_for_each(tmp1, &cifs_tcp_ses_list) { |
153 | server = list_entry(tmp1, struct TCP_Server_Info, | 151 | server = list_entry(tmp1, struct TCP_Server_Info, |
154 | tcp_ses_list); | 152 | tcp_ses_list); |
155 | i++; | 153 | i++; |
156 | list_for_each(tmp2, &server->smb_ses_list) { | 154 | list_for_each(tmp2, &server->smb_ses_list) { |
157 | ses = list_entry(tmp2, struct cifsSesInfo, | 155 | ses = list_entry(tmp2, struct cifs_ses, |
158 | smb_ses_list); | 156 | smb_ses_list); |
159 | if ((ses->serverDomain == NULL) || | 157 | if ((ses->serverDomain == NULL) || |
160 | (ses->serverOS == NULL) || | 158 | (ses->serverOS == NULL) || |
@@ -173,7 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
173 | seq_printf(m, "TCP status: %d\n\tLocal Users To " | 171 | seq_printf(m, "TCP status: %d\n\tLocal Users To " |
174 | "Server: %d SecMode: 0x%x Req On Wire: %d", | 172 | "Server: %d SecMode: 0x%x Req On Wire: %d", |
175 | server->tcpStatus, server->srv_count, | 173 | server->tcpStatus, server->srv_count, |
176 | server->secMode, | 174 | server->sec_mode, |
177 | atomic_read(&server->inFlight)); | 175 | atomic_read(&server->inFlight)); |
178 | 176 | ||
179 | #ifdef CONFIG_CIFS_STATS2 | 177 | #ifdef CONFIG_CIFS_STATS2 |
@@ -185,7 +183,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
185 | seq_puts(m, "\n\tShares:"); | 183 | seq_puts(m, "\n\tShares:"); |
186 | j = 0; | 184 | j = 0; |
187 | list_for_each(tmp3, &ses->tcon_list) { | 185 | list_for_each(tmp3, &ses->tcon_list) { |
188 | tcon = list_entry(tmp3, struct cifsTconInfo, | 186 | tcon = list_entry(tmp3, struct cifs_tcon, |
189 | tcon_list); | 187 | tcon_list); |
190 | ++j; | 188 | ++j; |
191 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | 189 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); |
@@ -220,17 +218,17 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
220 | mid_entry = list_entry(tmp3, struct mid_q_entry, | 218 | mid_entry = list_entry(tmp3, struct mid_q_entry, |
221 | qhead); | 219 | qhead); |
222 | seq_printf(m, "\tState: %d com: %d pid:" | 220 | seq_printf(m, "\tState: %d com: %d pid:" |
223 | " %d tsk: %p mid %d\n", | 221 | " %d cbdata: %p mid %d\n", |
224 | mid_entry->midState, | 222 | mid_entry->midState, |
225 | (int)mid_entry->command, | 223 | (int)mid_entry->command, |
226 | mid_entry->pid, | 224 | mid_entry->pid, |
227 | mid_entry->tsk, | 225 | mid_entry->callback_data, |
228 | mid_entry->mid); | 226 | mid_entry->mid); |
229 | } | 227 | } |
230 | spin_unlock(&GlobalMid_Lock); | 228 | spin_unlock(&GlobalMid_Lock); |
231 | } | 229 | } |
232 | } | 230 | } |
233 | read_unlock(&cifs_tcp_ses_lock); | 231 | spin_unlock(&cifs_tcp_ses_lock); |
234 | seq_putc(m, '\n'); | 232 | seq_putc(m, '\n'); |
235 | 233 | ||
236 | /* BB add code to dump additional info such as TCP session info now */ | 234 | /* BB add code to dump additional info such as TCP session info now */ |
@@ -258,8 +256,8 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
258 | int rc; | 256 | int rc; |
259 | struct list_head *tmp1, *tmp2, *tmp3; | 257 | struct list_head *tmp1, *tmp2, *tmp3; |
260 | struct TCP_Server_Info *server; | 258 | struct TCP_Server_Info *server; |
261 | struct cifsSesInfo *ses; | 259 | struct cifs_ses *ses; |
262 | struct cifsTconInfo *tcon; | 260 | struct cifs_tcon *tcon; |
263 | 261 | ||
264 | rc = get_user(c, buffer); | 262 | rc = get_user(c, buffer); |
265 | if (rc) | 263 | if (rc) |
@@ -270,16 +268,16 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
270 | atomic_set(&totBufAllocCount, 0); | 268 | atomic_set(&totBufAllocCount, 0); |
271 | atomic_set(&totSmBufAllocCount, 0); | 269 | atomic_set(&totSmBufAllocCount, 0); |
272 | #endif /* CONFIG_CIFS_STATS2 */ | 270 | #endif /* CONFIG_CIFS_STATS2 */ |
273 | read_lock(&cifs_tcp_ses_lock); | 271 | spin_lock(&cifs_tcp_ses_lock); |
274 | list_for_each(tmp1, &cifs_tcp_ses_list) { | 272 | list_for_each(tmp1, &cifs_tcp_ses_list) { |
275 | server = list_entry(tmp1, struct TCP_Server_Info, | 273 | server = list_entry(tmp1, struct TCP_Server_Info, |
276 | tcp_ses_list); | 274 | tcp_ses_list); |
277 | list_for_each(tmp2, &server->smb_ses_list) { | 275 | list_for_each(tmp2, &server->smb_ses_list) { |
278 | ses = list_entry(tmp2, struct cifsSesInfo, | 276 | ses = list_entry(tmp2, struct cifs_ses, |
279 | smb_ses_list); | 277 | smb_ses_list); |
280 | list_for_each(tmp3, &ses->tcon_list) { | 278 | list_for_each(tmp3, &ses->tcon_list) { |
281 | tcon = list_entry(tmp3, | 279 | tcon = list_entry(tmp3, |
282 | struct cifsTconInfo, | 280 | struct cifs_tcon, |
283 | tcon_list); | 281 | tcon_list); |
284 | atomic_set(&tcon->num_smbs_sent, 0); | 282 | atomic_set(&tcon->num_smbs_sent, 0); |
285 | atomic_set(&tcon->num_writes, 0); | 283 | atomic_set(&tcon->num_writes, 0); |
@@ -303,7 +301,7 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
303 | } | 301 | } |
304 | } | 302 | } |
305 | } | 303 | } |
306 | read_unlock(&cifs_tcp_ses_lock); | 304 | spin_unlock(&cifs_tcp_ses_lock); |
307 | } | 305 | } |
308 | 306 | ||
309 | return count; | 307 | return count; |
@@ -314,8 +312,8 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
314 | int i; | 312 | int i; |
315 | struct list_head *tmp1, *tmp2, *tmp3; | 313 | struct list_head *tmp1, *tmp2, *tmp3; |
316 | struct TCP_Server_Info *server; | 314 | struct TCP_Server_Info *server; |
317 | struct cifsSesInfo *ses; | 315 | struct cifs_ses *ses; |
318 | struct cifsTconInfo *tcon; | 316 | struct cifs_tcon *tcon; |
319 | 317 | ||
320 | seq_printf(m, | 318 | seq_printf(m, |
321 | "Resources in use\nCIFS Session: %d\n", | 319 | "Resources in use\nCIFS Session: %d\n", |
@@ -333,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
333 | atomic_read(&totSmBufAllocCount)); | 331 | atomic_read(&totSmBufAllocCount)); |
334 | #endif /* CONFIG_CIFS_STATS2 */ | 332 | #endif /* CONFIG_CIFS_STATS2 */ |
335 | 333 | ||
336 | seq_printf(m, "Operations (MIDs): %d\n", midCount.counter); | 334 | seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount)); |
337 | seq_printf(m, | 335 | seq_printf(m, |
338 | "\n%d session %d share reconnects\n", | 336 | "\n%d session %d share reconnects\n", |
339 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); | 337 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); |
@@ -343,16 +341,16 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
343 | GlobalCurrentXid, GlobalMaxActiveXid); | 341 | GlobalCurrentXid, GlobalMaxActiveXid); |
344 | 342 | ||
345 | i = 0; | 343 | i = 0; |
346 | read_lock(&cifs_tcp_ses_lock); | 344 | spin_lock(&cifs_tcp_ses_lock); |
347 | list_for_each(tmp1, &cifs_tcp_ses_list) { | 345 | list_for_each(tmp1, &cifs_tcp_ses_list) { |
348 | server = list_entry(tmp1, struct TCP_Server_Info, | 346 | server = list_entry(tmp1, struct TCP_Server_Info, |
349 | tcp_ses_list); | 347 | tcp_ses_list); |
350 | list_for_each(tmp2, &server->smb_ses_list) { | 348 | list_for_each(tmp2, &server->smb_ses_list) { |
351 | ses = list_entry(tmp2, struct cifsSesInfo, | 349 | ses = list_entry(tmp2, struct cifs_ses, |
352 | smb_ses_list); | 350 | smb_ses_list); |
353 | list_for_each(tmp3, &ses->tcon_list) { | 351 | list_for_each(tmp3, &ses->tcon_list) { |
354 | tcon = list_entry(tmp3, | 352 | tcon = list_entry(tmp3, |
355 | struct cifsTconInfo, | 353 | struct cifs_tcon, |
356 | tcon_list); | 354 | tcon_list); |
357 | i++; | 355 | i++; |
358 | seq_printf(m, "\n%d) %s", i, tcon->treeName); | 356 | seq_printf(m, "\n%d) %s", i, tcon->treeName); |
@@ -397,7 +395,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
397 | } | 395 | } |
398 | } | 396 | } |
399 | } | 397 | } |
400 | read_unlock(&cifs_tcp_ses_lock); | 398 | spin_unlock(&cifs_tcp_ses_lock); |
401 | 399 | ||
402 | seq_putc(m, '\n'); | 400 | seq_putc(m, '\n'); |
403 | return 0; | 401 | return 0; |
@@ -425,7 +423,6 @@ static const struct file_operations cifs_lookup_cache_proc_fops; | |||
425 | static const struct file_operations traceSMB_proc_fops; | 423 | static const struct file_operations traceSMB_proc_fops; |
426 | static const struct file_operations cifs_multiuser_mount_proc_fops; | 424 | static const struct file_operations cifs_multiuser_mount_proc_fops; |
427 | static const struct file_operations cifs_security_flags_proc_fops; | 425 | static const struct file_operations cifs_security_flags_proc_fops; |
428 | static const struct file_operations cifs_experimental_proc_fops; | ||
429 | static const struct file_operations cifs_linux_ext_proc_fops; | 426 | static const struct file_operations cifs_linux_ext_proc_fops; |
430 | 427 | ||
431 | void | 428 | void |
@@ -443,8 +440,6 @@ cifs_proc_init(void) | |||
443 | proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); | 440 | proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); |
444 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); | 441 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); |
445 | proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); | 442 | proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); |
446 | proc_create("Experimental", 0, proc_fs_cifs, | ||
447 | &cifs_experimental_proc_fops); | ||
448 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, | 443 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, |
449 | &cifs_linux_ext_proc_fops); | 444 | &cifs_linux_ext_proc_fops); |
450 | proc_create("MultiuserMount", 0, proc_fs_cifs, | 445 | proc_create("MultiuserMount", 0, proc_fs_cifs, |
@@ -471,7 +466,6 @@ cifs_proc_clean(void) | |||
471 | remove_proc_entry("OplockEnabled", proc_fs_cifs); | 466 | remove_proc_entry("OplockEnabled", proc_fs_cifs); |
472 | remove_proc_entry("SecurityFlags", proc_fs_cifs); | 467 | remove_proc_entry("SecurityFlags", proc_fs_cifs); |
473 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); | 468 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); |
474 | remove_proc_entry("Experimental", proc_fs_cifs); | ||
475 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); | 469 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); |
476 | remove_proc_entry("fs/cifs", NULL); | 470 | remove_proc_entry("fs/cifs", NULL); |
477 | } | 471 | } |
@@ -552,45 +546,6 @@ static const struct file_operations cifs_oplock_proc_fops = { | |||
552 | .write = cifs_oplock_proc_write, | 546 | .write = cifs_oplock_proc_write, |
553 | }; | 547 | }; |
554 | 548 | ||
555 | static int cifs_experimental_proc_show(struct seq_file *m, void *v) | ||
556 | { | ||
557 | seq_printf(m, "%d\n", experimEnabled); | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int cifs_experimental_proc_open(struct inode *inode, struct file *file) | ||
562 | { | ||
563 | return single_open(file, cifs_experimental_proc_show, NULL); | ||
564 | } | ||
565 | |||
566 | static ssize_t cifs_experimental_proc_write(struct file *file, | ||
567 | const char __user *buffer, size_t count, loff_t *ppos) | ||
568 | { | ||
569 | char c; | ||
570 | int rc; | ||
571 | |||
572 | rc = get_user(c, buffer); | ||
573 | if (rc) | ||
574 | return rc; | ||
575 | if (c == '0' || c == 'n' || c == 'N') | ||
576 | experimEnabled = 0; | ||
577 | else if (c == '1' || c == 'y' || c == 'Y') | ||
578 | experimEnabled = 1; | ||
579 | else if (c == '2') | ||
580 | experimEnabled = 2; | ||
581 | |||
582 | return count; | ||
583 | } | ||
584 | |||
585 | static const struct file_operations cifs_experimental_proc_fops = { | ||
586 | .owner = THIS_MODULE, | ||
587 | .open = cifs_experimental_proc_open, | ||
588 | .read = seq_read, | ||
589 | .llseek = seq_lseek, | ||
590 | .release = single_release, | ||
591 | .write = cifs_experimental_proc_write, | ||
592 | }; | ||
593 | |||
594 | static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) | 549 | static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) |
595 | { | 550 | { |
596 | seq_printf(m, "%d\n", linuxExtEnabled); | 551 | seq_printf(m, "%d\n", linuxExtEnabled); |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index aa316891ac0c..8942b28cf807 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
@@ -34,7 +34,7 @@ void cifs_dump_mids(struct TCP_Server_Info *); | |||
34 | extern int traceSMB; /* flag which enables the function below */ | 34 | extern int traceSMB; /* flag which enables the function below */ |
35 | void dump_smb(struct smb_hdr *, int); | 35 | void dump_smb(struct smb_hdr *, int); |
36 | #define CIFS_INFO 0x01 | 36 | #define CIFS_INFO 0x01 |
37 | #define CIFS_RC 0x02 | 37 | #define CIFS_RC 0x02 |
38 | #define CIFS_TIMER 0x04 | 38 | #define CIFS_TIMER 0x04 |
39 | 39 | ||
40 | /* | 40 | /* |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index d6ced7aa23cf..8d8f28c94c0f 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -44,8 +44,7 @@ static void cifs_dfs_expire_automounts(struct work_struct *work) | |||
44 | void cifs_dfs_release_automount_timer(void) | 44 | void cifs_dfs_release_automount_timer(void) |
45 | { | 45 | { |
46 | BUG_ON(!list_empty(&cifs_dfs_automount_list)); | 46 | BUG_ON(!list_empty(&cifs_dfs_automount_list)); |
47 | cancel_delayed_work(&cifs_dfs_automount_task); | 47 | cancel_delayed_work_sync(&cifs_dfs_automount_task); |
48 | flush_scheduled_work(); | ||
49 | } | 48 | } |
50 | 49 | ||
51 | /** | 50 | /** |
@@ -54,7 +53,7 @@ void cifs_dfs_release_automount_timer(void) | |||
54 | * | 53 | * |
55 | * Extracts sharename form full UNC. | 54 | * Extracts sharename form full UNC. |
56 | * i.e. strips from UNC trailing path that is not part of share | 55 | * i.e. strips from UNC trailing path that is not part of share |
57 | * name and fixup missing '\' in the begining of DFS node refferal | 56 | * name and fixup missing '\' in the beginning of DFS node refferal |
58 | * if necessary. | 57 | * if necessary. |
59 | * Returns pointer to share name on success or ERR_PTR on error. | 58 | * Returns pointer to share name on success or ERR_PTR on error. |
60 | * Caller is responsible for freeing returned string. | 59 | * Caller is responsible for freeing returned string. |
@@ -256,35 +255,6 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, | |||
256 | 255 | ||
257 | } | 256 | } |
258 | 257 | ||
259 | static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | ||
260 | struct list_head *mntlist) | ||
261 | { | ||
262 | /* stolen from afs code */ | ||
263 | int err; | ||
264 | |||
265 | mntget(newmnt); | ||
266 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist); | ||
267 | switch (err) { | ||
268 | case 0: | ||
269 | path_put(&nd->path); | ||
270 | nd->path.mnt = newmnt; | ||
271 | nd->path.dentry = dget(newmnt->mnt_root); | ||
272 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
273 | cifs_dfs_mountpoint_expiry_timeout); | ||
274 | break; | ||
275 | case -EBUSY: | ||
276 | /* someone else made a mount here whilst we were busy */ | ||
277 | while (d_mountpoint(nd->path.dentry) && | ||
278 | follow_down(&nd->path)) | ||
279 | ; | ||
280 | err = 0; | ||
281 | default: | ||
282 | mntput(newmnt); | ||
283 | break; | ||
284 | } | ||
285 | return err; | ||
286 | } | ||
287 | |||
288 | static void dump_referral(const struct dfs_info3_param *ref) | 258 | static void dump_referral(const struct dfs_info3_param *ref) |
289 | { | 259 | { |
290 | cFYI(1, "DFS: ref path: %s", ref->path_name); | 260 | cFYI(1, "DFS: ref path: %s", ref->path_name); |
@@ -294,34 +264,23 @@ static void dump_referral(const struct dfs_info3_param *ref) | |||
294 | ref->path_consumed); | 264 | ref->path_consumed); |
295 | } | 265 | } |
296 | 266 | ||
297 | 267 | /* | |
298 | static void* | 268 | * Create a vfsmount that we can automount |
299 | cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | 269 | */ |
270 | static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) | ||
300 | { | 271 | { |
301 | struct dfs_info3_param *referrals = NULL; | 272 | struct dfs_info3_param *referrals = NULL; |
302 | unsigned int num_referrals = 0; | 273 | unsigned int num_referrals = 0; |
303 | struct cifs_sb_info *cifs_sb; | 274 | struct cifs_sb_info *cifs_sb; |
304 | struct cifsSesInfo *ses; | 275 | struct cifs_ses *ses; |
305 | char *full_path = NULL; | 276 | char *full_path; |
306 | int xid, i; | 277 | int xid, i; |
307 | int rc = 0; | 278 | int rc; |
308 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 279 | struct vfsmount *mnt; |
280 | struct tcon_link *tlink; | ||
309 | 281 | ||
310 | cFYI(1, "in %s", __func__); | 282 | cFYI(1, "in %s", __func__); |
311 | BUG_ON(IS_ROOT(dentry)); | 283 | BUG_ON(IS_ROOT(mntpt)); |
312 | |||
313 | xid = GetXid(); | ||
314 | |||
315 | dput(nd->path.dentry); | ||
316 | nd->path.dentry = dget(dentry); | ||
317 | |||
318 | cifs_sb = CIFS_SB(dentry->d_inode->i_sb); | ||
319 | ses = cifs_sb->tcon->ses; | ||
320 | |||
321 | if (!ses) { | ||
322 | rc = -EINVAL; | ||
323 | goto out_err; | ||
324 | } | ||
325 | 284 | ||
326 | /* | 285 | /* |
327 | * The MSDFS spec states that paths in DFS referral requests and | 286 | * The MSDFS spec states that paths in DFS referral requests and |
@@ -329,56 +288,83 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
329 | * the double backslashes usually used in the UNC. This function | 288 | * the double backslashes usually used in the UNC. This function |
330 | * gives us the latter, so we must adjust the result. | 289 | * gives us the latter, so we must adjust the result. |
331 | */ | 290 | */ |
332 | full_path = build_path_from_dentry(dentry); | 291 | mnt = ERR_PTR(-ENOMEM); |
333 | if (full_path == NULL) { | 292 | full_path = build_path_from_dentry(mntpt); |
334 | rc = -ENOMEM; | 293 | if (full_path == NULL) |
335 | goto out_err; | 294 | goto cdda_exit; |
295 | |||
296 | cifs_sb = CIFS_SB(mntpt->d_inode->i_sb); | ||
297 | tlink = cifs_sb_tlink(cifs_sb); | ||
298 | if (IS_ERR(tlink)) { | ||
299 | mnt = ERR_CAST(tlink); | ||
300 | goto free_full_path; | ||
336 | } | 301 | } |
302 | ses = tlink_tcon(tlink)->ses; | ||
337 | 303 | ||
338 | rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls, | 304 | xid = GetXid(); |
305 | rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, | ||
339 | &num_referrals, &referrals, | 306 | &num_referrals, &referrals, |
340 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 307 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
308 | FreeXid(xid); | ||
309 | |||
310 | cifs_put_tlink(tlink); | ||
341 | 311 | ||
312 | mnt = ERR_PTR(-ENOENT); | ||
342 | for (i = 0; i < num_referrals; i++) { | 313 | for (i = 0; i < num_referrals; i++) { |
343 | int len; | 314 | int len; |
344 | dump_referral(referrals+i); | 315 | dump_referral(referrals + i); |
345 | /* connect to a node */ | 316 | /* connect to a node */ |
346 | len = strlen(referrals[i].node_name); | 317 | len = strlen(referrals[i].node_name); |
347 | if (len < 2) { | 318 | if (len < 2) { |
348 | cERROR(1, "%s: Net Address path too short: %s", | 319 | cERROR(1, "%s: Net Address path too short: %s", |
349 | __func__, referrals[i].node_name); | 320 | __func__, referrals[i].node_name); |
350 | rc = -EINVAL; | 321 | mnt = ERR_PTR(-EINVAL); |
351 | goto out_err; | 322 | break; |
352 | } | 323 | } |
353 | mnt = cifs_dfs_do_refmount(cifs_sb, | 324 | mnt = cifs_dfs_do_refmount(cifs_sb, |
354 | full_path, referrals + i); | 325 | full_path, referrals + i); |
355 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, | 326 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, |
356 | referrals[i].node_name, mnt); | 327 | referrals[i].node_name, mnt); |
357 | |||
358 | /* complete mount procedure if we accured submount */ | ||
359 | if (!IS_ERR(mnt)) | 328 | if (!IS_ERR(mnt)) |
360 | break; | 329 | goto success; |
361 | } | 330 | } |
362 | 331 | ||
363 | /* we need it cause for() above could exit without valid submount */ | 332 | /* no valid submounts were found; return error from get_dfs_path() by |
364 | rc = PTR_ERR(mnt); | 333 | * preference */ |
365 | if (IS_ERR(mnt)) | 334 | if (rc != 0) |
366 | goto out_err; | 335 | mnt = ERR_PTR(rc); |
367 | 336 | ||
368 | rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); | 337 | success: |
369 | |||
370 | out: | ||
371 | FreeXid(xid); | ||
372 | free_dfs_info_array(referrals, num_referrals); | 338 | free_dfs_info_array(referrals, num_referrals); |
339 | free_full_path: | ||
373 | kfree(full_path); | 340 | kfree(full_path); |
341 | cdda_exit: | ||
374 | cFYI(1, "leaving %s" , __func__); | 342 | cFYI(1, "leaving %s" , __func__); |
375 | return ERR_PTR(rc); | 343 | return mnt; |
376 | out_err: | 344 | } |
377 | path_put(&nd->path); | 345 | |
378 | goto out; | 346 | /* |
347 | * Attempt to automount the referral | ||
348 | */ | ||
349 | struct vfsmount *cifs_dfs_d_automount(struct path *path) | ||
350 | { | ||
351 | struct vfsmount *newmnt; | ||
352 | |||
353 | cFYI(1, "in %s", __func__); | ||
354 | |||
355 | newmnt = cifs_dfs_do_automount(path->dentry); | ||
356 | if (IS_ERR(newmnt)) { | ||
357 | cFYI(1, "leaving %s [automount failed]" , __func__); | ||
358 | return newmnt; | ||
359 | } | ||
360 | |||
361 | mntget(newmnt); /* prevent immediate expiration */ | ||
362 | mnt_set_expiry(newmnt, &cifs_dfs_automount_list); | ||
363 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
364 | cifs_dfs_mountpoint_expiry_timeout); | ||
365 | cFYI(1, "leaving %s [ok]" , __func__); | ||
366 | return newmnt; | ||
379 | } | 367 | } |
380 | 368 | ||
381 | const struct inode_operations cifs_dfs_referral_inode_operations = { | 369 | const struct inode_operations cifs_dfs_referral_inode_operations = { |
382 | .follow_link = cifs_dfs_follow_mountpoint, | ||
383 | }; | 370 | }; |
384 | |||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 9e771450c3b8..7260e11e21f8 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -15,6 +15,8 @@ | |||
15 | * the GNU Lesser General Public License for more details. | 15 | * the GNU Lesser General Public License for more details. |
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | #include <linux/rbtree.h> | ||
19 | |||
18 | #ifndef _CIFS_FS_SB_H | 20 | #ifndef _CIFS_FS_SB_H |
19 | #define _CIFS_FS_SB_H | 21 | #define _CIFS_FS_SB_H |
20 | 22 | ||
@@ -36,23 +38,28 @@ | |||
36 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ | 38 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ |
37 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ | 39 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ |
38 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ | 40 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ |
41 | #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ | ||
42 | #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ | ||
43 | #define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */ | ||
44 | #define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */ | ||
45 | #define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */ | ||
39 | 46 | ||
40 | struct cifs_sb_info { | 47 | struct cifs_sb_info { |
41 | struct cifsTconInfo *tcon; /* primary mount */ | 48 | struct rb_root tlink_tree; |
42 | struct list_head nested_tcon_q; | 49 | spinlock_t tlink_tree_lock; |
50 | struct tcon_link *master_tlink; | ||
43 | struct nls_table *local_nls; | 51 | struct nls_table *local_nls; |
44 | unsigned int rsize; | 52 | unsigned int rsize; |
45 | unsigned int wsize; | 53 | unsigned int wsize; |
54 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | ||
55 | atomic_t active; | ||
46 | uid_t mnt_uid; | 56 | uid_t mnt_uid; |
47 | gid_t mnt_gid; | 57 | gid_t mnt_gid; |
48 | mode_t mnt_file_mode; | 58 | mode_t mnt_file_mode; |
49 | mode_t mnt_dir_mode; | 59 | mode_t mnt_dir_mode; |
50 | int mnt_cifs_flags; | 60 | unsigned int mnt_cifs_flags; |
51 | int prepathlen; | 61 | char *mountdata; /* options received at mount time or via DFS refs */ |
52 | char *prepath; /* relative path under the share to mount to */ | ||
53 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
54 | char *mountdata; /* mount options received at mount time */ | ||
55 | #endif | ||
56 | struct backing_dev_info bdi; | 62 | struct backing_dev_info bdi; |
63 | struct delayed_work prune_tlinks; | ||
57 | }; | 64 | }; |
58 | #endif /* _CIFS_FS_SB_H */ | 65 | #endif /* _CIFS_FS_SB_H */ |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 87044906cd1f..2272fd5fe5b7 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -95,9 +95,11 @@ struct key_type cifs_spnego_key_type = { | |||
95 | 95 | ||
96 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ | 96 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ |
97 | struct key * | 97 | struct key * |
98 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | 98 | cifs_get_spnego_key(struct cifs_ses *sesInfo) |
99 | { | 99 | { |
100 | struct TCP_Server_Info *server = sesInfo->server; | 100 | struct TCP_Server_Info *server = sesInfo->server; |
101 | struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; | ||
102 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; | ||
101 | char *description, *dp; | 103 | char *description, *dp; |
102 | size_t desc_len; | 104 | size_t desc_len; |
103 | struct key *spnego_key; | 105 | struct key *spnego_key; |
@@ -111,7 +113,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
111 | MAX_MECH_STR_LEN + | 113 | MAX_MECH_STR_LEN + |
112 | UID_KEY_LEN + (sizeof(uid_t) * 2) + | 114 | UID_KEY_LEN + (sizeof(uid_t) * 2) + |
113 | CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + | 115 | CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + |
114 | USER_KEY_LEN + strlen(sesInfo->userName) + | 116 | USER_KEY_LEN + strlen(sesInfo->user_name) + |
115 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; | 117 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; |
116 | 118 | ||
117 | spnego_key = ERR_PTR(-ENOMEM); | 119 | spnego_key = ERR_PTR(-ENOMEM); |
@@ -127,10 +129,10 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
127 | dp = description + strlen(description); | 129 | dp = description + strlen(description); |
128 | 130 | ||
129 | /* add the server address */ | 131 | /* add the server address */ |
130 | if (server->addr.sockAddr.sin_family == AF_INET) | 132 | if (server->dstaddr.ss_family == AF_INET) |
131 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); | 133 | sprintf(dp, "ip4=%pI4", &sa->sin_addr); |
132 | else if (server->addr.sockAddr.sin_family == AF_INET6) | 134 | else if (server->dstaddr.ss_family == AF_INET6) |
133 | sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr); | 135 | sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); |
134 | else | 136 | else |
135 | goto out; | 137 | goto out; |
136 | 138 | ||
@@ -151,7 +153,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
151 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); | 153 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); |
152 | 154 | ||
153 | dp = description + strlen(description); | 155 | dp = description + strlen(description); |
154 | sprintf(dp, ";user=%s", sesInfo->userName); | 156 | sprintf(dp, ";user=%s", sesInfo->user_name); |
155 | 157 | ||
156 | dp = description + strlen(description); | 158 | dp = description + strlen(description); |
157 | sprintf(dp, ";pid=0x%x", current->pid); | 159 | sprintf(dp, ";pid=0x%x", current->pid); |
diff --git a/fs/cifs/cifs_spnego.h b/fs/cifs/cifs_spnego.h index e4041ec4d712..31bef9ee078b 100644 --- a/fs/cifs/cifs_spnego.h +++ b/fs/cifs/cifs_spnego.h | |||
@@ -41,7 +41,7 @@ struct cifs_spnego_msg { | |||
41 | 41 | ||
42 | #ifdef __KERNEL__ | 42 | #ifdef __KERNEL__ |
43 | extern struct key_type cifs_spnego_key_type; | 43 | extern struct key_type cifs_spnego_key_type; |
44 | extern struct key *cifs_get_spnego_key(struct cifsSesInfo *sesInfo); | 44 | extern struct key *cifs_get_spnego_key(struct cifs_ses *sesInfo); |
45 | #endif /* KERNEL */ | 45 | #endif /* KERNEL */ |
46 | 46 | ||
47 | #endif /* _CIFS_SPNEGO_H */ | 47 | #endif /* _CIFS_SPNEGO_H */ |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 430f510a1720..1b2e180b018d 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
44 | int charlen, outlen = 0; | 44 | int charlen, outlen = 0; |
45 | int maxwords = maxbytes / 2; | 45 | int maxwords = maxbytes / 2; |
46 | char tmp[NLS_MAX_CHARSET_SIZE]; | 46 | char tmp[NLS_MAX_CHARSET_SIZE]; |
47 | __u16 ftmp; | ||
47 | 48 | ||
48 | for (i = 0; i < maxwords && from[i]; i++) { | 49 | for (i = 0; i < maxwords; i++) { |
49 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, | 50 | ftmp = get_unaligned_le16(&from[i]); |
50 | NLS_MAX_CHARSET_SIZE); | 51 | if (ftmp == 0) |
52 | break; | ||
53 | |||
54 | charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); | ||
51 | if (charlen > 0) | 55 | if (charlen > 0) |
52 | outlen += charlen; | 56 | outlen += charlen; |
53 | else | 57 | else |
@@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
58 | } | 62 | } |
59 | 63 | ||
60 | /* | 64 | /* |
61 | * cifs_mapchar - convert a little-endian char to proper char in codepage | 65 | * cifs_mapchar - convert a host-endian char to proper char in codepage |
62 | * @target - where converted character should be copied | 66 | * @target - where converted character should be copied |
63 | * @src_char - 2 byte little-endian source character | 67 | * @src_char - 2 byte host-endian source character |
64 | * @cp - codepage to which character should be converted | 68 | * @cp - codepage to which character should be converted |
65 | * @mapchar - should character be mapped according to mapchars mount option? | 69 | * @mapchar - should character be mapped according to mapchars mount option? |
66 | * | 70 | * |
@@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
69 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | 73 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). |
70 | */ | 74 | */ |
71 | static int | 75 | static int |
72 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | 76 | cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, |
73 | bool mapchar) | 77 | bool mapchar) |
74 | { | 78 | { |
75 | int len = 1; | 79 | int len = 1; |
@@ -82,11 +86,11 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | |||
82 | * build_path_from_dentry are modified, as they use slash as | 86 | * build_path_from_dentry are modified, as they use slash as |
83 | * separator. | 87 | * separator. |
84 | */ | 88 | */ |
85 | switch (le16_to_cpu(src_char)) { | 89 | switch (src_char) { |
86 | case UNI_COLON: | 90 | case UNI_COLON: |
87 | *target = ':'; | 91 | *target = ':'; |
88 | break; | 92 | break; |
89 | case UNI_ASTERIK: | 93 | case UNI_ASTERISK: |
90 | *target = '*'; | 94 | *target = '*'; |
91 | break; | 95 | break; |
92 | case UNI_QUESTION: | 96 | case UNI_QUESTION: |
@@ -109,8 +113,7 @@ out: | |||
109 | return len; | 113 | return len; |
110 | 114 | ||
111 | cp_convert: | 115 | cp_convert: |
112 | len = cp->uni2char(le16_to_cpu(src_char), target, | 116 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); |
113 | NLS_MAX_CHARSET_SIZE); | ||
114 | if (len <= 0) { | 117 | if (len <= 0) { |
115 | *target = '?'; | 118 | *target = '?'; |
116 | len = 1; | 119 | len = 1; |
@@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |||
149 | int nullsize = nls_nullsize(codepage); | 152 | int nullsize = nls_nullsize(codepage); |
150 | int fromwords = fromlen / 2; | 153 | int fromwords = fromlen / 2; |
151 | char tmp[NLS_MAX_CHARSET_SIZE]; | 154 | char tmp[NLS_MAX_CHARSET_SIZE]; |
155 | __u16 ftmp; | ||
152 | 156 | ||
153 | /* | 157 | /* |
154 | * because the chars can be of varying widths, we need to take care | 158 | * because the chars can be of varying widths, we need to take care |
@@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |||
158 | */ | 162 | */ |
159 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | 163 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); |
160 | 164 | ||
161 | for (i = 0; i < fromwords && from[i]; i++) { | 165 | for (i = 0; i < fromwords; i++) { |
166 | ftmp = get_unaligned_le16(&from[i]); | ||
167 | if (ftmp == 0) | ||
168 | break; | ||
169 | |||
162 | /* | 170 | /* |
163 | * check to see if converting this character might make the | 171 | * check to see if converting this character might make the |
164 | * conversion bleed into the null terminator | 172 | * conversion bleed into the null terminator |
165 | */ | 173 | */ |
166 | if (outlen >= safelen) { | 174 | if (outlen >= safelen) { |
167 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | 175 | charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar); |
168 | if ((outlen + charlen) > (tolen - nullsize)) | 176 | if ((outlen + charlen) > (tolen - nullsize)) |
169 | break; | 177 | break; |
170 | } | 178 | } |
171 | 179 | ||
172 | /* put converted char into 'to' buffer */ | 180 | /* put converted char into 'to' buffer */ |
173 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | 181 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); |
174 | outlen += charlen; | 182 | outlen += charlen; |
175 | } | 183 | } |
176 | 184 | ||
@@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, | |||
193 | { | 201 | { |
194 | int charlen; | 202 | int charlen; |
195 | int i; | 203 | int i; |
196 | wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */ | 204 | wchar_t wchar_to; /* needed to quiet sparse */ |
197 | 205 | ||
198 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { | 206 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { |
199 | 207 | charlen = codepage->char2uni(from, len, &wchar_to); | |
200 | /* works for 2.4.0 kernel or later */ | ||
201 | charlen = codepage->char2uni(from, len, &wchar_to[i]); | ||
202 | if (charlen < 1) { | 208 | if (charlen < 1) { |
203 | cERROR(1, "strtoUCS: char2uni of %d returned %d", | 209 | cERROR(1, "strtoUCS: char2uni of 0x%x returned %d", |
204 | (int)*from, charlen); | 210 | *from, charlen); |
205 | /* A question mark */ | 211 | /* A question mark */ |
206 | to[i] = cpu_to_le16(0x003f); | 212 | wchar_to = 0x003f; |
207 | charlen = 1; | 213 | charlen = 1; |
208 | } else | 214 | } |
209 | to[i] = cpu_to_le16(wchar_to[i]); | 215 | put_unaligned_le16(wchar_to, &to[i]); |
210 | |||
211 | } | 216 | } |
212 | 217 | ||
213 | to[i] = 0; | 218 | put_unaligned_le16(0, &to[i]); |
214 | return i; | 219 | return i; |
215 | } | 220 | } |
216 | 221 | ||
@@ -252,3 +257,76 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, | |||
252 | return dst; | 257 | return dst; |
253 | } | 258 | } |
254 | 259 | ||
260 | /* | ||
261 | * Convert 16 bit Unicode pathname to wire format from string in current code | ||
262 | * page. Conversion may involve remapping up the six characters that are | ||
263 | * only legal in POSIX-like OS (if they are present in the string). Path | ||
264 | * names are little endian 16 bit Unicode on the wire | ||
265 | */ | ||
266 | int | ||
267 | cifsConvertToUCS(__le16 *target, const char *source, int srclen, | ||
268 | const struct nls_table *cp, int mapChars) | ||
269 | { | ||
270 | int i, j, charlen; | ||
271 | char src_char; | ||
272 | __le16 dst_char; | ||
273 | wchar_t tmp; | ||
274 | |||
275 | if (!mapChars) | ||
276 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | ||
277 | |||
278 | for (i = 0, j = 0; i < srclen; j++) { | ||
279 | src_char = source[i]; | ||
280 | charlen = 1; | ||
281 | switch (src_char) { | ||
282 | case 0: | ||
283 | put_unaligned(0, &target[j]); | ||
284 | goto ctoUCS_out; | ||
285 | case ':': | ||
286 | dst_char = cpu_to_le16(UNI_COLON); | ||
287 | break; | ||
288 | case '*': | ||
289 | dst_char = cpu_to_le16(UNI_ASTERISK); | ||
290 | break; | ||
291 | case '?': | ||
292 | dst_char = cpu_to_le16(UNI_QUESTION); | ||
293 | break; | ||
294 | case '<': | ||
295 | dst_char = cpu_to_le16(UNI_LESSTHAN); | ||
296 | break; | ||
297 | case '>': | ||
298 | dst_char = cpu_to_le16(UNI_GRTRTHAN); | ||
299 | break; | ||
300 | case '|': | ||
301 | dst_char = cpu_to_le16(UNI_PIPE); | ||
302 | break; | ||
303 | /* | ||
304 | * FIXME: We can not handle remapping backslash (UNI_SLASH) | ||
305 | * until all the calls to build_path_from_dentry are modified, | ||
306 | * as they use backslash as separator. | ||
307 | */ | ||
308 | default: | ||
309 | charlen = cp->char2uni(source + i, srclen - i, &tmp); | ||
310 | dst_char = cpu_to_le16(tmp); | ||
311 | |||
312 | /* | ||
313 | * if no match, use question mark, which at least in | ||
314 | * some cases serves as wild card | ||
315 | */ | ||
316 | if (charlen < 1) { | ||
317 | dst_char = cpu_to_le16(0x003f); | ||
318 | charlen = 1; | ||
319 | } | ||
320 | } | ||
321 | /* | ||
322 | * character may take more than one byte in the source string, | ||
323 | * but will take exactly two bytes in the target string | ||
324 | */ | ||
325 | i += charlen; | ||
326 | put_unaligned(dst_char, &target[j]); | ||
327 | } | ||
328 | |||
329 | ctoUCS_out: | ||
330 | return i; | ||
331 | } | ||
332 | |||
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 7fe6b52df507..6d02fd560566 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
@@ -44,7 +44,7 @@ | |||
44 | * reserved symbols (along with \ and /), otherwise illegal to store | 44 | * reserved symbols (along with \ and /), otherwise illegal to store |
45 | * in filenames in NTFS | 45 | * in filenames in NTFS |
46 | */ | 46 | */ |
47 | #define UNI_ASTERIK (__u16) ('*' + 0xF000) | 47 | #define UNI_ASTERISK (__u16) ('*' + 0xF000) |
48 | #define UNI_QUESTION (__u16) ('?' + 0xF000) | 48 | #define UNI_QUESTION (__u16) ('?' + 0xF000) |
49 | #define UNI_COLON (__u16) (':' + 0xF000) | 49 | #define UNI_COLON (__u16) (':' + 0xF000) |
50 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | 50 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) |
@@ -82,6 +82,9 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); | |||
82 | char *cifs_strndup_from_ucs(const char *src, const int maxlen, | 82 | char *cifs_strndup_from_ucs(const char *src, const int maxlen, |
83 | const bool is_unicode, | 83 | const bool is_unicode, |
84 | const struct nls_table *codepage); | 84 | const struct nls_table *codepage); |
85 | extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
86 | const struct nls_table *cp, int mapChars); | ||
87 | |||
85 | #endif | 88 | #endif |
86 | 89 | ||
87 | /* | 90 | /* |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 85d7cf7ff2c8..21de1d6d5849 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -23,76 +23,405 @@ | |||
23 | 23 | ||
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/string.h> | ||
27 | #include <linux/keyctl.h> | ||
28 | #include <linux/key-type.h> | ||
29 | #include <keys/user-type.h> | ||
26 | #include "cifspdu.h" | 30 | #include "cifspdu.h" |
27 | #include "cifsglob.h" | 31 | #include "cifsglob.h" |
28 | #include "cifsacl.h" | 32 | #include "cifsacl.h" |
29 | #include "cifsproto.h" | 33 | #include "cifsproto.h" |
30 | #include "cifs_debug.h" | 34 | #include "cifs_debug.h" |
31 | 35 | ||
32 | 36 | /* security id for everyone/world system group */ | |
33 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
34 | |||
35 | static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { | ||
36 | {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, | ||
37 | {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, | ||
38 | {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, | ||
39 | {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, | ||
40 | {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"}, | ||
41 | {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"}, | ||
42 | {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} } | ||
43 | ; | ||
44 | |||
45 | |||
46 | /* security id for everyone */ | ||
47 | static const struct cifs_sid sid_everyone = { | 37 | static const struct cifs_sid sid_everyone = { |
48 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; | 38 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; |
39 | /* security id for Authenticated Users system group */ | ||
40 | static const struct cifs_sid sid_authusers = { | ||
41 | 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} }; | ||
49 | /* group users */ | 42 | /* group users */ |
50 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; | 43 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; |
51 | 44 | ||
45 | const struct cred *root_cred; | ||
52 | 46 | ||
53 | int match_sid(struct cifs_sid *ctsid) | 47 | static void |
48 | shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem, | ||
49 | int *nr_del) | ||
54 | { | 50 | { |
55 | int i, j; | 51 | struct rb_node *node; |
56 | int num_subauth, num_sat, num_saw; | 52 | struct rb_node *tmp; |
57 | struct cifs_sid *cwsid; | 53 | struct cifs_sid_id *psidid; |
54 | |||
55 | node = rb_first(root); | ||
56 | while (node) { | ||
57 | tmp = node; | ||
58 | node = rb_next(tmp); | ||
59 | psidid = rb_entry(tmp, struct cifs_sid_id, rbnode); | ||
60 | if (nr_to_scan == 0 || *nr_del == nr_to_scan) | ||
61 | ++(*nr_rem); | ||
62 | else { | ||
63 | if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) | ||
64 | && psidid->refcount == 0) { | ||
65 | rb_erase(tmp, root); | ||
66 | ++(*nr_del); | ||
67 | } else | ||
68 | ++(*nr_rem); | ||
69 | } | ||
70 | } | ||
71 | } | ||
58 | 72 | ||
59 | if (!ctsid) | 73 | /* |
60 | return -1; | 74 | * Run idmap cache shrinker. |
75 | */ | ||
76 | static int | ||
77 | cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc) | ||
78 | { | ||
79 | int nr_to_scan = sc->nr_to_scan; | ||
80 | int nr_del = 0; | ||
81 | int nr_rem = 0; | ||
82 | struct rb_root *root; | ||
83 | |||
84 | root = &uidtree; | ||
85 | spin_lock(&siduidlock); | ||
86 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
87 | spin_unlock(&siduidlock); | ||
88 | |||
89 | root = &gidtree; | ||
90 | spin_lock(&sidgidlock); | ||
91 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
92 | spin_unlock(&sidgidlock); | ||
93 | |||
94 | return nr_rem; | ||
95 | } | ||
96 | |||
97 | static struct shrinker cifs_shrinker = { | ||
98 | .shrink = cifs_idmap_shrinker, | ||
99 | .seeks = DEFAULT_SEEKS, | ||
100 | }; | ||
61 | 101 | ||
62 | for (i = 0; i < NUM_WK_SIDS; ++i) { | 102 | static int |
63 | cwsid = &(wksidarr[i].cifssid); | 103 | cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) |
104 | { | ||
105 | char *payload; | ||
106 | |||
107 | payload = kmalloc(datalen, GFP_KERNEL); | ||
108 | if (!payload) | ||
109 | return -ENOMEM; | ||
64 | 110 | ||
65 | /* compare the revision */ | 111 | memcpy(payload, data, datalen); |
66 | if (ctsid->revision != cwsid->revision) | 112 | key->payload.data = payload; |
67 | continue; | 113 | return 0; |
114 | } | ||
68 | 115 | ||
69 | /* compare all of the six auth values */ | 116 | static inline void |
70 | for (j = 0; j < 6; ++j) { | 117 | cifs_idmap_key_destroy(struct key *key) |
71 | if (ctsid->authority[j] != cwsid->authority[j]) | 118 | { |
72 | break; | 119 | kfree(key->payload.data); |
120 | } | ||
121 | |||
122 | struct key_type cifs_idmap_key_type = { | ||
123 | .name = "cifs.idmap", | ||
124 | .instantiate = cifs_idmap_key_instantiate, | ||
125 | .destroy = cifs_idmap_key_destroy, | ||
126 | .describe = user_describe, | ||
127 | .match = user_match, | ||
128 | }; | ||
129 | |||
130 | static void | ||
131 | sid_to_str(struct cifs_sid *sidptr, char *sidstr) | ||
132 | { | ||
133 | int i; | ||
134 | unsigned long saval; | ||
135 | char *strptr; | ||
136 | |||
137 | strptr = sidstr; | ||
138 | |||
139 | sprintf(strptr, "%s", "S"); | ||
140 | strptr = sidstr + strlen(sidstr); | ||
141 | |||
142 | sprintf(strptr, "-%d", sidptr->revision); | ||
143 | strptr = sidstr + strlen(sidstr); | ||
144 | |||
145 | for (i = 0; i < 6; ++i) { | ||
146 | if (sidptr->authority[i]) { | ||
147 | sprintf(strptr, "-%d", sidptr->authority[i]); | ||
148 | strptr = sidstr + strlen(sidstr); | ||
73 | } | 149 | } |
74 | if (j < 6) | 150 | } |
75 | continue; /* all of the auth values did not match */ | 151 | |
76 | 152 | for (i = 0; i < sidptr->num_subauth; ++i) { | |
77 | /* compare all of the subauth values if any */ | 153 | saval = le32_to_cpu(sidptr->sub_auth[i]); |
78 | num_sat = ctsid->num_subauth; | 154 | sprintf(strptr, "-%ld", saval); |
79 | num_saw = cwsid->num_subauth; | 155 | strptr = sidstr + strlen(sidstr); |
80 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | 156 | } |
81 | if (num_subauth) { | 157 | } |
82 | for (j = 0; j < num_subauth; ++j) { | 158 | |
83 | if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) | 159 | static void |
84 | break; | 160 | id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, |
85 | } | 161 | struct cifs_sid_id **psidid, char *typestr) |
86 | if (j < num_subauth) | 162 | { |
87 | continue; /* all sub_auth values do not match */ | 163 | int rc; |
164 | char *strptr; | ||
165 | struct rb_node *node = root->rb_node; | ||
166 | struct rb_node *parent = NULL; | ||
167 | struct rb_node **linkto = &(root->rb_node); | ||
168 | struct cifs_sid_id *lsidid; | ||
169 | |||
170 | while (node) { | ||
171 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
172 | parent = node; | ||
173 | rc = compare_sids(sidptr, &((lsidid)->sid)); | ||
174 | if (rc > 0) { | ||
175 | linkto = &(node->rb_left); | ||
176 | node = node->rb_left; | ||
177 | } else if (rc < 0) { | ||
178 | linkto = &(node->rb_right); | ||
179 | node = node->rb_right; | ||
88 | } | 180 | } |
181 | } | ||
182 | |||
183 | memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); | ||
184 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); | ||
185 | (*psidid)->refcount = 0; | ||
186 | |||
187 | sprintf((*psidid)->sidstr, "%s", typestr); | ||
188 | strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); | ||
189 | sid_to_str(&(*psidid)->sid, strptr); | ||
190 | |||
191 | clear_bit(SID_ID_PENDING, &(*psidid)->state); | ||
192 | clear_bit(SID_ID_MAPPED, &(*psidid)->state); | ||
193 | |||
194 | rb_link_node(&(*psidid)->rbnode, parent, linkto); | ||
195 | rb_insert_color(&(*psidid)->rbnode, root); | ||
196 | } | ||
89 | 197 | ||
90 | cFYI(1, "matching sid: %s\n", wksidarr[i].sidname); | 198 | static struct cifs_sid_id * |
91 | return 0; /* sids compare/match */ | 199 | id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) |
200 | { | ||
201 | int rc; | ||
202 | struct rb_node *node = root->rb_node; | ||
203 | struct cifs_sid_id *lsidid; | ||
204 | |||
205 | while (node) { | ||
206 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
207 | rc = compare_sids(sidptr, &((lsidid)->sid)); | ||
208 | if (rc > 0) { | ||
209 | node = node->rb_left; | ||
210 | } else if (rc < 0) { | ||
211 | node = node->rb_right; | ||
212 | } else /* node found */ | ||
213 | return lsidid; | ||
92 | } | 214 | } |
93 | 215 | ||
94 | cFYI(1, "No matching sid"); | 216 | return NULL; |
95 | return -1; | 217 | } |
218 | |||
219 | static int | ||
220 | sidid_pending_wait(void *unused) | ||
221 | { | ||
222 | schedule(); | ||
223 | return signal_pending(current) ? -ERESTARTSYS : 0; | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, | ||
228 | struct cifs_fattr *fattr, uint sidtype) | ||
229 | { | ||
230 | int rc; | ||
231 | unsigned long cid; | ||
232 | struct key *idkey; | ||
233 | const struct cred *saved_cred; | ||
234 | struct cifs_sid_id *psidid, *npsidid; | ||
235 | struct rb_root *cidtree; | ||
236 | spinlock_t *cidlock; | ||
237 | |||
238 | if (sidtype == SIDOWNER) { | ||
239 | cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */ | ||
240 | cidlock = &siduidlock; | ||
241 | cidtree = &uidtree; | ||
242 | } else if (sidtype == SIDGROUP) { | ||
243 | cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */ | ||
244 | cidlock = &sidgidlock; | ||
245 | cidtree = &gidtree; | ||
246 | } else | ||
247 | return -ENOENT; | ||
248 | |||
249 | spin_lock(cidlock); | ||
250 | psidid = id_rb_search(cidtree, psid); | ||
251 | |||
252 | if (!psidid) { /* node does not exist, allocate one & attempt adding */ | ||
253 | spin_unlock(cidlock); | ||
254 | npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); | ||
255 | if (!npsidid) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); | ||
259 | if (!npsidid->sidstr) { | ||
260 | kfree(npsidid); | ||
261 | return -ENOMEM; | ||
262 | } | ||
263 | |||
264 | spin_lock(cidlock); | ||
265 | psidid = id_rb_search(cidtree, psid); | ||
266 | if (psidid) { /* node happened to get inserted meanwhile */ | ||
267 | ++psidid->refcount; | ||
268 | spin_unlock(cidlock); | ||
269 | kfree(npsidid->sidstr); | ||
270 | kfree(npsidid); | ||
271 | } else { | ||
272 | psidid = npsidid; | ||
273 | id_rb_insert(cidtree, psid, &psidid, | ||
274 | sidtype == SIDOWNER ? "os:" : "gs:"); | ||
275 | ++psidid->refcount; | ||
276 | spin_unlock(cidlock); | ||
277 | } | ||
278 | } else { | ||
279 | ++psidid->refcount; | ||
280 | spin_unlock(cidlock); | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * If we are here, it is safe to access psidid and its fields | ||
285 | * since a reference was taken earlier while holding the spinlock. | ||
286 | * A reference on the node is put without holding the spinlock | ||
287 | * and it is OK to do so in this case, shrinker will not erase | ||
288 | * this node until all references are put and we do not access | ||
289 | * any fields of the node after a reference is put . | ||
290 | */ | ||
291 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | ||
292 | cid = psidid->id; | ||
293 | psidid->time = jiffies; /* update ts for accessing */ | ||
294 | goto sid_to_id_out; | ||
295 | } | ||
296 | |||
297 | if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) | ||
298 | goto sid_to_id_out; | ||
299 | |||
300 | if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { | ||
301 | saved_cred = override_creds(root_cred); | ||
302 | idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); | ||
303 | if (IS_ERR(idkey)) | ||
304 | cFYI(1, "%s: Can't map SID to an id", __func__); | ||
305 | else { | ||
306 | cid = *(unsigned long *)idkey->payload.value; | ||
307 | psidid->id = cid; | ||
308 | set_bit(SID_ID_MAPPED, &psidid->state); | ||
309 | key_put(idkey); | ||
310 | kfree(psidid->sidstr); | ||
311 | } | ||
312 | revert_creds(saved_cred); | ||
313 | psidid->time = jiffies; /* update ts for accessing */ | ||
314 | clear_bit(SID_ID_PENDING, &psidid->state); | ||
315 | wake_up_bit(&psidid->state, SID_ID_PENDING); | ||
316 | } else { | ||
317 | rc = wait_on_bit(&psidid->state, SID_ID_PENDING, | ||
318 | sidid_pending_wait, TASK_INTERRUPTIBLE); | ||
319 | if (rc) { | ||
320 | cFYI(1, "%s: sidid_pending_wait interrupted %d", | ||
321 | __func__, rc); | ||
322 | --psidid->refcount; /* decremented without spinlock */ | ||
323 | return rc; | ||
324 | } | ||
325 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | ||
326 | cid = psidid->id; | ||
327 | } | ||
328 | |||
329 | sid_to_id_out: | ||
330 | --psidid->refcount; /* decremented without spinlock */ | ||
331 | if (sidtype == SIDOWNER) | ||
332 | fattr->cf_uid = cid; | ||
333 | else | ||
334 | fattr->cf_gid = cid; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | int | ||
340 | init_cifs_idmap(void) | ||
341 | { | ||
342 | struct cred *cred; | ||
343 | struct key *keyring; | ||
344 | int ret; | ||
345 | |||
346 | cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name); | ||
347 | |||
348 | /* create an override credential set with a special thread keyring in | ||
349 | * which requests are cached | ||
350 | * | ||
351 | * this is used to prevent malicious redirections from being installed | ||
352 | * with add_key(). | ||
353 | */ | ||
354 | cred = prepare_kernel_cred(NULL); | ||
355 | if (!cred) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, | ||
359 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
360 | KEY_USR_VIEW | KEY_USR_READ, | ||
361 | KEY_ALLOC_NOT_IN_QUOTA); | ||
362 | if (IS_ERR(keyring)) { | ||
363 | ret = PTR_ERR(keyring); | ||
364 | goto failed_put_cred; | ||
365 | } | ||
366 | |||
367 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
368 | if (ret < 0) | ||
369 | goto failed_put_key; | ||
370 | |||
371 | ret = register_key_type(&cifs_idmap_key_type); | ||
372 | if (ret < 0) | ||
373 | goto failed_put_key; | ||
374 | |||
375 | /* instruct request_key() to use this special keyring as a cache for | ||
376 | * the results it looks up */ | ||
377 | cred->thread_keyring = keyring; | ||
378 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | ||
379 | root_cred = cred; | ||
380 | |||
381 | spin_lock_init(&siduidlock); | ||
382 | uidtree = RB_ROOT; | ||
383 | spin_lock_init(&sidgidlock); | ||
384 | gidtree = RB_ROOT; | ||
385 | |||
386 | register_shrinker(&cifs_shrinker); | ||
387 | |||
388 | cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring)); | ||
389 | return 0; | ||
390 | |||
391 | failed_put_key: | ||
392 | key_put(keyring); | ||
393 | failed_put_cred: | ||
394 | put_cred(cred); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | void | ||
399 | exit_cifs_idmap(void) | ||
400 | { | ||
401 | key_revoke(root_cred->thread_keyring); | ||
402 | unregister_key_type(&cifs_idmap_key_type); | ||
403 | put_cred(root_cred); | ||
404 | unregister_shrinker(&cifs_shrinker); | ||
405 | cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name); | ||
406 | } | ||
407 | |||
408 | void | ||
409 | cifs_destroy_idmaptrees(void) | ||
410 | { | ||
411 | struct rb_root *root; | ||
412 | struct rb_node *node; | ||
413 | |||
414 | root = &uidtree; | ||
415 | spin_lock(&siduidlock); | ||
416 | while ((node = rb_first(root))) | ||
417 | rb_erase(node, root); | ||
418 | spin_unlock(&siduidlock); | ||
419 | |||
420 | root = &gidtree; | ||
421 | spin_lock(&sidgidlock); | ||
422 | while ((node = rb_first(root))) | ||
423 | rb_erase(node, root); | ||
424 | spin_unlock(&sidgidlock); | ||
96 | } | 425 | } |
97 | 426 | ||
98 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are | 427 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are |
@@ -103,16 +432,24 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
103 | int num_subauth, num_sat, num_saw; | 432 | int num_subauth, num_sat, num_saw; |
104 | 433 | ||
105 | if ((!ctsid) || (!cwsid)) | 434 | if ((!ctsid) || (!cwsid)) |
106 | return 0; | 435 | return 1; |
107 | 436 | ||
108 | /* compare the revision */ | 437 | /* compare the revision */ |
109 | if (ctsid->revision != cwsid->revision) | 438 | if (ctsid->revision != cwsid->revision) { |
110 | return 0; | 439 | if (ctsid->revision > cwsid->revision) |
440 | return 1; | ||
441 | else | ||
442 | return -1; | ||
443 | } | ||
111 | 444 | ||
112 | /* compare all of the six auth values */ | 445 | /* compare all of the six auth values */ |
113 | for (i = 0; i < 6; ++i) { | 446 | for (i = 0; i < 6; ++i) { |
114 | if (ctsid->authority[i] != cwsid->authority[i]) | 447 | if (ctsid->authority[i] != cwsid->authority[i]) { |
115 | return 0; | 448 | if (ctsid->authority[i] > cwsid->authority[i]) |
449 | return 1; | ||
450 | else | ||
451 | return -1; | ||
452 | } | ||
116 | } | 453 | } |
117 | 454 | ||
118 | /* compare all of the subauth values if any */ | 455 | /* compare all of the subauth values if any */ |
@@ -121,12 +458,17 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
121 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | 458 | num_subauth = num_sat < num_saw ? num_sat : num_saw; |
122 | if (num_subauth) { | 459 | if (num_subauth) { |
123 | for (i = 0; i < num_subauth; ++i) { | 460 | for (i = 0; i < num_subauth; ++i) { |
124 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) | 461 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { |
125 | return 0; | 462 | if (le32_to_cpu(ctsid->sub_auth[i]) > |
463 | le32_to_cpu(cwsid->sub_auth[i])) | ||
464 | return 1; | ||
465 | else | ||
466 | return -1; | ||
467 | } | ||
126 | } | 468 | } |
127 | } | 469 | } |
128 | 470 | ||
129 | return 1; /* sids compare/match */ | 471 | return 0; /* sids compare/match */ |
130 | } | 472 | } |
131 | 473 | ||
132 | 474 | ||
@@ -367,32 +709,42 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
367 | if (num_aces > 0) { | 709 | if (num_aces > 0) { |
368 | umode_t user_mask = S_IRWXU; | 710 | umode_t user_mask = S_IRWXU; |
369 | umode_t group_mask = S_IRWXG; | 711 | umode_t group_mask = S_IRWXG; |
370 | umode_t other_mask = S_IRWXO; | 712 | umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; |
371 | 713 | ||
372 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), | 714 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), |
373 | GFP_KERNEL); | 715 | GFP_KERNEL); |
716 | if (!ppace) { | ||
717 | cERROR(1, "DACL memory allocation error"); | ||
718 | return; | ||
719 | } | ||
374 | 720 | ||
375 | for (i = 0; i < num_aces; ++i) { | 721 | for (i = 0; i < num_aces; ++i) { |
376 | ppace[i] = (struct cifs_ace *) (acl_base + acl_size); | 722 | ppace[i] = (struct cifs_ace *) (acl_base + acl_size); |
377 | #ifdef CONFIG_CIFS_DEBUG2 | 723 | #ifdef CONFIG_CIFS_DEBUG2 |
378 | dump_ace(ppace[i], end_of_acl); | 724 | dump_ace(ppace[i], end_of_acl); |
379 | #endif | 725 | #endif |
380 | if (compare_sids(&(ppace[i]->sid), pownersid)) | 726 | if (compare_sids(&(ppace[i]->sid), pownersid) == 0) |
381 | access_flags_to_mode(ppace[i]->access_req, | 727 | access_flags_to_mode(ppace[i]->access_req, |
382 | ppace[i]->type, | 728 | ppace[i]->type, |
383 | &fattr->cf_mode, | 729 | &fattr->cf_mode, |
384 | &user_mask); | 730 | &user_mask); |
385 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) | 731 | if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) |
386 | access_flags_to_mode(ppace[i]->access_req, | 732 | access_flags_to_mode(ppace[i]->access_req, |
387 | ppace[i]->type, | 733 | ppace[i]->type, |
388 | &fattr->cf_mode, | 734 | &fattr->cf_mode, |
389 | &group_mask); | 735 | &group_mask); |
390 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) | 736 | if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) |
737 | access_flags_to_mode(ppace[i]->access_req, | ||
738 | ppace[i]->type, | ||
739 | &fattr->cf_mode, | ||
740 | &other_mask); | ||
741 | if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0) | ||
391 | access_flags_to_mode(ppace[i]->access_req, | 742 | access_flags_to_mode(ppace[i]->access_req, |
392 | ppace[i]->type, | 743 | ppace[i]->type, |
393 | &fattr->cf_mode, | 744 | &fattr->cf_mode, |
394 | &other_mask); | 745 | &other_mask); |
395 | 746 | ||
747 | |||
396 | /* memcpy((void *)(&(cifscred->aces[i])), | 748 | /* memcpy((void *)(&(cifscred->aces[i])), |
397 | (void *)ppace[i], | 749 | (void *)ppace[i], |
398 | sizeof(struct cifs_ace)); */ | 750 | sizeof(struct cifs_ace)); */ |
@@ -464,10 +816,10 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
464 | 816 | ||
465 | 817 | ||
466 | /* Convert CIFS ACL to POSIX form */ | 818 | /* Convert CIFS ACL to POSIX form */ |
467 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | 819 | static int parse_sec_desc(struct cifs_sb_info *cifs_sb, |
468 | struct cifs_fattr *fattr) | 820 | struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr) |
469 | { | 821 | { |
470 | int rc; | 822 | int rc = 0; |
471 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 823 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
472 | struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ | 824 | struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ |
473 | char *end_of_acl = ((char *)pntsd) + acl_len; | 825 | char *end_of_acl = ((char *)pntsd) + acl_len; |
@@ -489,12 +841,26 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
489 | le32_to_cpu(pntsd->sacloffset), dacloffset); | 841 | le32_to_cpu(pntsd->sacloffset), dacloffset); |
490 | /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ | 842 | /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ |
491 | rc = parse_sid(owner_sid_ptr, end_of_acl); | 843 | rc = parse_sid(owner_sid_ptr, end_of_acl); |
492 | if (rc) | 844 | if (rc) { |
845 | cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc); | ||
493 | return rc; | 846 | return rc; |
847 | } | ||
848 | rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER); | ||
849 | if (rc) { | ||
850 | cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc); | ||
851 | return rc; | ||
852 | } | ||
494 | 853 | ||
495 | rc = parse_sid(group_sid_ptr, end_of_acl); | 854 | rc = parse_sid(group_sid_ptr, end_of_acl); |
496 | if (rc) | 855 | if (rc) { |
856 | cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc); | ||
857 | return rc; | ||
858 | } | ||
859 | rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); | ||
860 | if (rc) { | ||
861 | cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc); | ||
497 | return rc; | 862 | return rc; |
863 | } | ||
498 | 864 | ||
499 | if (dacloffset) | 865 | if (dacloffset) |
500 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, | 866 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, |
@@ -509,7 +875,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
509 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, | 875 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, |
510 | sizeof(struct cifs_sid)); */ | 876 | sizeof(struct cifs_sid)); */ |
511 | 877 | ||
512 | return 0; | 878 | return rc; |
513 | } | 879 | } |
514 | 880 | ||
515 | 881 | ||
@@ -557,13 +923,20 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, | |||
557 | { | 923 | { |
558 | struct cifs_ntsd *pntsd = NULL; | 924 | struct cifs_ntsd *pntsd = NULL; |
559 | int xid, rc; | 925 | int xid, rc; |
926 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
927 | |||
928 | if (IS_ERR(tlink)) | ||
929 | return ERR_CAST(tlink); | ||
560 | 930 | ||
561 | xid = GetXid(); | 931 | xid = GetXid(); |
562 | rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); | 932 | rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); |
563 | FreeXid(xid); | 933 | FreeXid(xid); |
564 | 934 | ||
935 | cifs_put_tlink(tlink); | ||
565 | 936 | ||
566 | cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); | 937 | cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); |
938 | if (rc) | ||
939 | return ERR_PTR(rc); | ||
567 | return pntsd; | 940 | return pntsd; |
568 | } | 941 | } |
569 | 942 | ||
@@ -574,28 +947,34 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, | |||
574 | int oplock = 0; | 947 | int oplock = 0; |
575 | int xid, rc; | 948 | int xid, rc; |
576 | __u16 fid; | 949 | __u16 fid; |
950 | struct cifs_tcon *tcon; | ||
951 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
577 | 952 | ||
953 | if (IS_ERR(tlink)) | ||
954 | return ERR_CAST(tlink); | ||
955 | |||
956 | tcon = tlink_tcon(tlink); | ||
578 | xid = GetXid(); | 957 | xid = GetXid(); |
579 | 958 | ||
580 | rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0, | 959 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, |
581 | &fid, &oplock, NULL, cifs_sb->local_nls, | 960 | &fid, &oplock, NULL, cifs_sb->local_nls, |
582 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 961 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
583 | if (rc) { | 962 | if (!rc) { |
584 | cERROR(1, "Unable to open file to get ACL"); | 963 | rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); |
585 | goto out; | 964 | CIFSSMBClose(xid, tcon, fid); |
586 | } | 965 | } |
587 | 966 | ||
588 | rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); | 967 | cifs_put_tlink(tlink); |
589 | cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); | ||
590 | |||
591 | CIFSSMBClose(xid, cifs_sb->tcon, fid); | ||
592 | out: | ||
593 | FreeXid(xid); | 968 | FreeXid(xid); |
969 | |||
970 | cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); | ||
971 | if (rc) | ||
972 | return ERR_PTR(rc); | ||
594 | return pntsd; | 973 | return pntsd; |
595 | } | 974 | } |
596 | 975 | ||
597 | /* Retrieve an ACL from the server */ | 976 | /* Retrieve an ACL from the server */ |
598 | static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | 977 | struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, |
599 | struct inode *inode, const char *path, | 978 | struct inode *inode, const char *path, |
600 | u32 *pacllen) | 979 | u32 *pacllen) |
601 | { | 980 | { |
@@ -603,7 +982,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | |||
603 | struct cifsFileInfo *open_file = NULL; | 982 | struct cifsFileInfo *open_file = NULL; |
604 | 983 | ||
605 | if (inode) | 984 | if (inode) |
606 | open_file = find_readable_file(CIFS_I(inode)); | 985 | open_file = find_readable_file(CIFS_I(inode), true); |
607 | if (!open_file) | 986 | if (!open_file) |
608 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); | 987 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); |
609 | 988 | ||
@@ -616,10 +995,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, | |||
616 | struct cifs_ntsd *pnntsd, u32 acllen) | 995 | struct cifs_ntsd *pnntsd, u32 acllen) |
617 | { | 996 | { |
618 | int xid, rc; | 997 | int xid, rc; |
998 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
999 | |||
1000 | if (IS_ERR(tlink)) | ||
1001 | return PTR_ERR(tlink); | ||
619 | 1002 | ||
620 | xid = GetXid(); | 1003 | xid = GetXid(); |
621 | rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); | 1004 | rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen); |
622 | FreeXid(xid); | 1005 | FreeXid(xid); |
1006 | cifs_put_tlink(tlink); | ||
623 | 1007 | ||
624 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); | 1008 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); |
625 | return rc; | 1009 | return rc; |
@@ -631,10 +1015,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, | |||
631 | int oplock = 0; | 1015 | int oplock = 0; |
632 | int xid, rc; | 1016 | int xid, rc; |
633 | __u16 fid; | 1017 | __u16 fid; |
1018 | struct cifs_tcon *tcon; | ||
1019 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
1020 | |||
1021 | if (IS_ERR(tlink)) | ||
1022 | return PTR_ERR(tlink); | ||
634 | 1023 | ||
1024 | tcon = tlink_tcon(tlink); | ||
635 | xid = GetXid(); | 1025 | xid = GetXid(); |
636 | 1026 | ||
637 | rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0, | 1027 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, |
638 | &fid, &oplock, NULL, cifs_sb->local_nls, | 1028 | &fid, &oplock, NULL, cifs_sb->local_nls, |
639 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 1029 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
640 | if (rc) { | 1030 | if (rc) { |
@@ -642,17 +1032,18 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, | |||
642 | goto out; | 1032 | goto out; |
643 | } | 1033 | } |
644 | 1034 | ||
645 | rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); | 1035 | rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); |
646 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); | 1036 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); |
647 | 1037 | ||
648 | CIFSSMBClose(xid, cifs_sb->tcon, fid); | 1038 | CIFSSMBClose(xid, tcon, fid); |
649 | out: | 1039 | out: |
650 | FreeXid(xid); | 1040 | FreeXid(xid); |
1041 | cifs_put_tlink(tlink); | ||
651 | return rc; | 1042 | return rc; |
652 | } | 1043 | } |
653 | 1044 | ||
654 | /* Set an ACL on the server */ | 1045 | /* Set an ACL on the server */ |
655 | static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | 1046 | int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, |
656 | struct inode *inode, const char *path) | 1047 | struct inode *inode, const char *path) |
657 | { | 1048 | { |
658 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1049 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
@@ -661,7 +1052,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
661 | 1052 | ||
662 | cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); | 1053 | cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); |
663 | 1054 | ||
664 | open_file = find_readable_file(CIFS_I(inode)); | 1055 | open_file = find_readable_file(CIFS_I(inode), true); |
665 | if (!open_file) | 1056 | if (!open_file) |
666 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); | 1057 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); |
667 | 1058 | ||
@@ -671,7 +1062,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
671 | } | 1062 | } |
672 | 1063 | ||
673 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 1064 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
674 | void | 1065 | int |
675 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | 1066 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, |
676 | struct inode *inode, const char *path, const __u16 *pfid) | 1067 | struct inode *inode, const char *path, const __u16 *pfid) |
677 | { | 1068 | { |
@@ -687,17 +1078,21 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | |||
687 | pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); | 1078 | pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); |
688 | 1079 | ||
689 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ | 1080 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ |
690 | if (pntsd) | 1081 | if (IS_ERR(pntsd)) { |
691 | rc = parse_sec_desc(pntsd, acllen, fattr); | 1082 | rc = PTR_ERR(pntsd); |
692 | if (rc) | 1083 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); |
693 | cFYI(1, "parse sec desc failed rc = %d", rc); | 1084 | } else { |
1085 | rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr); | ||
1086 | kfree(pntsd); | ||
1087 | if (rc) | ||
1088 | cERROR(1, "parse sec desc failed rc = %d", rc); | ||
1089 | } | ||
694 | 1090 | ||
695 | kfree(pntsd); | 1091 | return rc; |
696 | return; | ||
697 | } | 1092 | } |
698 | 1093 | ||
699 | /* Convert mode bits to an ACL so we can update the ACL on the server */ | 1094 | /* Convert mode bits to an ACL so we can update the ACL on the server */ |
700 | int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | 1095 | int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) |
701 | { | 1096 | { |
702 | int rc = 0; | 1097 | int rc = 0; |
703 | __u32 secdesclen = 0; | 1098 | __u32 secdesclen = 0; |
@@ -712,7 +1107,10 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
712 | /* Add three ACEs for owner, group, everyone getting rid of | 1107 | /* Add three ACEs for owner, group, everyone getting rid of |
713 | other ACEs as chmod disables ACEs and set the security descriptor */ | 1108 | other ACEs as chmod disables ACEs and set the security descriptor */ |
714 | 1109 | ||
715 | if (pntsd) { | 1110 | if (IS_ERR(pntsd)) { |
1111 | rc = PTR_ERR(pntsd); | ||
1112 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); | ||
1113 | } else { | ||
716 | /* allocate memory for the smb header, | 1114 | /* allocate memory for the smb header, |
717 | set security descriptor request security descriptor | 1115 | set security descriptor request security descriptor |
718 | parameters, and secuirty descriptor itself */ | 1116 | parameters, and secuirty descriptor itself */ |
@@ -742,4 +1140,3 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
742 | 1140 | ||
743 | return rc; | 1141 | return rc; |
744 | } | 1142 | } |
745 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 6c8096cf5155..5c902c7ce524 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h | |||
@@ -39,6 +39,15 @@ | |||
39 | #define ACCESS_ALLOWED 0 | 39 | #define ACCESS_ALLOWED 0 |
40 | #define ACCESS_DENIED 1 | 40 | #define ACCESS_DENIED 1 |
41 | 41 | ||
42 | #define SIDOWNER 1 | ||
43 | #define SIDGROUP 2 | ||
44 | #define SIDLEN 150 /* S- 1 revision- 6 authorities- max 5 sub authorities */ | ||
45 | |||
46 | #define SID_ID_MAPPED 0 | ||
47 | #define SID_ID_PENDING 1 | ||
48 | #define SID_MAP_EXPIRE (3600 * HZ) /* map entry expires after one hour */ | ||
49 | #define SID_MAP_RETRY (300 * HZ) /* wait 5 minutes for next attempt to map */ | ||
50 | |||
42 | struct cifs_ntsd { | 51 | struct cifs_ntsd { |
43 | __le16 revision; /* revision level */ | 52 | __le16 revision; /* revision level */ |
44 | __le16 type; | 53 | __le16 type; |
@@ -74,11 +83,21 @@ struct cifs_wksid { | |||
74 | char sidname[SIDNAMELENGTH]; | 83 | char sidname[SIDNAMELENGTH]; |
75 | } __attribute__((packed)); | 84 | } __attribute__((packed)); |
76 | 85 | ||
77 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 86 | struct cifs_sid_id { |
87 | unsigned int refcount; /* increment with spinlock, decrement without */ | ||
88 | unsigned long id; | ||
89 | unsigned long time; | ||
90 | unsigned long state; | ||
91 | char *sidstr; | ||
92 | struct rb_node rbnode; | ||
93 | struct cifs_sid sid; | ||
94 | }; | ||
78 | 95 | ||
79 | extern int match_sid(struct cifs_sid *); | 96 | #ifdef __KERNEL__ |
80 | extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); | 97 | extern struct key_type cifs_idmap_key_type; |
98 | extern const struct cred *root_cred; | ||
99 | #endif /* KERNEL */ | ||
81 | 100 | ||
82 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 101 | extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); |
83 | 102 | ||
84 | #endif /* _CIFSACL_H */ | 103 | #endif /* _CIFSACL_H */ |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 35042d8f7338..5a0ee7f2af06 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -24,39 +24,50 @@ | |||
24 | #include "cifspdu.h" | 24 | #include "cifspdu.h" |
25 | #include "cifsglob.h" | 25 | #include "cifsglob.h" |
26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
27 | #include "md5.h" | ||
28 | #include "cifs_unicode.h" | 27 | #include "cifs_unicode.h" |
29 | #include "cifsproto.h" | 28 | #include "cifsproto.h" |
29 | #include "ntlmssp.h" | ||
30 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
31 | #include <linux/random.h> | 31 | #include <linux/random.h> |
32 | 32 | ||
33 | /* Calculate and return the CIFS signature based on the mac key and SMB PDU */ | 33 | /* |
34 | /* the 16 byte signature must be allocated by the caller */ | 34 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. |
35 | /* Note we only use the 1st eight bytes */ | 35 | * The 16 byte signature must be allocated by the caller. Note we only use the |
36 | /* Note that the smb header signature field on input contains the | 36 | * 1st eight bytes and that the smb header signature field on input contains |
37 | sequence number before this function is called */ | 37 | * the sequence number before this function is called. Also, this function |
38 | 38 | * should be called with the server->srv_mutex held. | |
39 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | 39 | */ |
40 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); | ||
41 | extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | ||
42 | unsigned char *p24); | ||
43 | |||
44 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | 40 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
45 | const struct mac_key *key, char *signature) | 41 | struct TCP_Server_Info *server, char *signature) |
46 | { | 42 | { |
47 | struct MD5Context context; | 43 | int rc; |
48 | 44 | ||
49 | if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL)) | 45 | if (cifs_pdu == NULL || signature == NULL || server == NULL) |
50 | return -EINVAL; | 46 | return -EINVAL; |
51 | 47 | ||
52 | cifs_MD5_init(&context); | 48 | if (!server->secmech.sdescmd5) { |
53 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 49 | cERROR(1, "%s: Can't generate signature\n", __func__); |
54 | cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); | 50 | return -1; |
51 | } | ||
52 | |||
53 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
54 | if (rc) { | ||
55 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
56 | return rc; | ||
57 | } | ||
58 | |||
59 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
60 | server->session_key.response, server->session_key.len); | ||
61 | |||
62 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
63 | cifs_pdu->Protocol, be32_to_cpu(cifs_pdu->smb_buf_length)); | ||
64 | |||
65 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); | ||
55 | 66 | ||
56 | cifs_MD5_final(signature, &context); | ||
57 | return 0; | 67 | return 0; |
58 | } | 68 | } |
59 | 69 | ||
70 | /* must be called with server->srv_mutex held */ | ||
60 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | 71 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, |
61 | __u32 *pexpected_response_sequence_number) | 72 | __u32 *pexpected_response_sequence_number) |
62 | { | 73 | { |
@@ -69,17 +80,14 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
69 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 80 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
70 | return rc; | 81 | return rc; |
71 | 82 | ||
72 | spin_lock(&GlobalMid_Lock); | ||
73 | cifs_pdu->Signature.Sequence.SequenceNumber = | 83 | cifs_pdu->Signature.Sequence.SequenceNumber = |
74 | cpu_to_le32(server->sequence_number); | 84 | cpu_to_le32(server->sequence_number); |
75 | cifs_pdu->Signature.Sequence.Reserved = 0; | 85 | cifs_pdu->Signature.Sequence.Reserved = 0; |
76 | 86 | ||
77 | *pexpected_response_sequence_number = server->sequence_number++; | 87 | *pexpected_response_sequence_number = server->sequence_number++; |
78 | server->sequence_number++; | 88 | server->sequence_number++; |
79 | spin_unlock(&GlobalMid_Lock); | ||
80 | 89 | ||
81 | rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key, | 90 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); |
82 | smb_signature); | ||
83 | if (rc) | 91 | if (rc) |
84 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 92 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
85 | else | 93 | else |
@@ -89,16 +97,28 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
89 | } | 97 | } |
90 | 98 | ||
91 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | 99 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, |
92 | const struct mac_key *key, char *signature) | 100 | struct TCP_Server_Info *server, char *signature) |
93 | { | 101 | { |
94 | struct MD5Context context; | ||
95 | int i; | 102 | int i; |
103 | int rc; | ||
96 | 104 | ||
97 | if ((iov == NULL) || (signature == NULL) || (key == NULL)) | 105 | if (iov == NULL || signature == NULL || server == NULL) |
98 | return -EINVAL; | 106 | return -EINVAL; |
99 | 107 | ||
100 | cifs_MD5_init(&context); | 108 | if (!server->secmech.sdescmd5) { |
101 | cifs_MD5_update(&context, (char *)&key->data, key->len); | 109 | cERROR(1, "%s: Can't generate signature\n", __func__); |
110 | return -1; | ||
111 | } | ||
112 | |||
113 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
114 | if (rc) { | ||
115 | cERROR(1, "%s: Oould not init md5\n", __func__); | ||
116 | return rc; | ||
117 | } | ||
118 | |||
119 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
120 | server->session_key.response, server->session_key.len); | ||
121 | |||
102 | for (i = 0; i < n_vec; i++) { | 122 | for (i = 0; i < n_vec; i++) { |
103 | if (iov[i].iov_len == 0) | 123 | if (iov[i].iov_len == 0) |
104 | continue; | 124 | continue; |
@@ -111,18 +131,19 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
111 | if (i == 0) { | 131 | if (i == 0) { |
112 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 132 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
113 | break; /* nothing to sign or corrupt header */ | 133 | break; /* nothing to sign or corrupt header */ |
114 | cifs_MD5_update(&context, iov[0].iov_base+4, | 134 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
115 | iov[0].iov_len-4); | 135 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
116 | } else | 136 | } else |
117 | cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len); | 137 | crypto_shash_update(&server->secmech.sdescmd5->shash, |
138 | iov[i].iov_base, iov[i].iov_len); | ||
118 | } | 139 | } |
119 | 140 | ||
120 | cifs_MD5_final(signature, &context); | 141 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); |
121 | 142 | ||
122 | return 0; | 143 | return rc; |
123 | } | 144 | } |
124 | 145 | ||
125 | 146 | /* must be called with server->srv_mutex held */ | |
126 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 147 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
127 | __u32 *pexpected_response_sequence_number) | 148 | __u32 *pexpected_response_sequence_number) |
128 | { | 149 | { |
@@ -136,17 +157,14 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
136 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 157 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
137 | return rc; | 158 | return rc; |
138 | 159 | ||
139 | spin_lock(&GlobalMid_Lock); | ||
140 | cifs_pdu->Signature.Sequence.SequenceNumber = | 160 | cifs_pdu->Signature.Sequence.SequenceNumber = |
141 | cpu_to_le32(server->sequence_number); | 161 | cpu_to_le32(server->sequence_number); |
142 | cifs_pdu->Signature.Sequence.Reserved = 0; | 162 | cifs_pdu->Signature.Sequence.Reserved = 0; |
143 | 163 | ||
144 | *pexpected_response_sequence_number = server->sequence_number++; | 164 | *pexpected_response_sequence_number = server->sequence_number++; |
145 | server->sequence_number++; | 165 | server->sequence_number++; |
146 | spin_unlock(&GlobalMid_Lock); | ||
147 | 166 | ||
148 | rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key, | 167 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); |
149 | smb_signature); | ||
150 | if (rc) | 168 | if (rc) |
151 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 169 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
152 | else | 170 | else |
@@ -156,17 +174,17 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
156 | } | 174 | } |
157 | 175 | ||
158 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, | 176 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, |
159 | const struct mac_key *mac_key, | 177 | struct TCP_Server_Info *server, |
160 | __u32 expected_sequence_number) | 178 | __u32 expected_sequence_number) |
161 | { | 179 | { |
162 | unsigned int rc; | 180 | unsigned int rc; |
163 | char server_response_sig[8]; | 181 | char server_response_sig[8]; |
164 | char what_we_think_sig_should_be[20]; | 182 | char what_we_think_sig_should_be[20]; |
165 | 183 | ||
166 | if ((cifs_pdu == NULL) || (mac_key == NULL)) | 184 | if (cifs_pdu == NULL || server == NULL) |
167 | return -EINVAL; | 185 | return -EINVAL; |
168 | 186 | ||
169 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | 187 | if (!server->session_estab) |
170 | return 0; | 188 | return 0; |
171 | 189 | ||
172 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { | 190 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { |
@@ -192,8 +210,10 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
192 | cpu_to_le32(expected_sequence_number); | 210 | cpu_to_le32(expected_sequence_number); |
193 | cifs_pdu->Signature.Sequence.Reserved = 0; | 211 | cifs_pdu->Signature.Sequence.Reserved = 0; |
194 | 212 | ||
195 | rc = cifs_calculate_signature(cifs_pdu, mac_key, | 213 | mutex_lock(&server->srv_mutex); |
214 | rc = cifs_calculate_signature(cifs_pdu, server, | ||
196 | what_we_think_sig_should_be); | 215 | what_we_think_sig_should_be); |
216 | mutex_unlock(&server->srv_mutex); | ||
197 | 217 | ||
198 | if (rc) | 218 | if (rc) |
199 | return rc; | 219 | return rc; |
@@ -208,26 +228,51 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
208 | 228 | ||
209 | } | 229 | } |
210 | 230 | ||
211 | /* We fill in key by putting in 40 byte array which was allocated by caller */ | 231 | /* first calculate 24 bytes ntlm response and then 16 byte session key */ |
212 | int cifs_calculate_mac_key(struct mac_key *key, const char *rn, | 232 | int setup_ntlm_response(struct cifs_ses *ses) |
213 | const char *password) | ||
214 | { | 233 | { |
215 | char temp_key[16]; | 234 | int rc = 0; |
216 | if ((key == NULL) || (rn == NULL)) | 235 | unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; |
236 | char temp_key[CIFS_SESS_KEY_SIZE]; | ||
237 | |||
238 | if (!ses) | ||
217 | return -EINVAL; | 239 | return -EINVAL; |
218 | 240 | ||
219 | E_md4hash(password, temp_key); | 241 | ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); |
220 | mdfour(key->data.ntlm, temp_key, 16); | 242 | if (!ses->auth_key.response) { |
221 | memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE); | 243 | cERROR(1, "NTLM can't allocate (%u bytes) memory", temp_len); |
222 | key->len = 40; | 244 | return -ENOMEM; |
223 | return 0; | 245 | } |
246 | ses->auth_key.len = temp_len; | ||
247 | |||
248 | rc = SMBNTencrypt(ses->password, ses->server->cryptkey, | ||
249 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
250 | if (rc) { | ||
251 | cFYI(1, "%s Can't generate NTLM response, error: %d", | ||
252 | __func__, rc); | ||
253 | return rc; | ||
254 | } | ||
255 | |||
256 | rc = E_md4hash(ses->password, temp_key); | ||
257 | if (rc) { | ||
258 | cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); | ||
259 | return rc; | ||
260 | } | ||
261 | |||
262 | rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); | ||
263 | if (rc) | ||
264 | cFYI(1, "%s Can't generate NTLM session key, error: %d", | ||
265 | __func__, rc); | ||
266 | |||
267 | return rc; | ||
224 | } | 268 | } |
225 | 269 | ||
226 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 270 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
227 | void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | 271 | int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, |
228 | char *lnm_session_key) | 272 | char *lnm_session_key) |
229 | { | 273 | { |
230 | int i; | 274 | int i; |
275 | int rc; | ||
231 | char password_with_pad[CIFS_ENCPWD_SIZE]; | 276 | char password_with_pad[CIFS_ENCPWD_SIZE]; |
232 | 277 | ||
233 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | 278 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); |
@@ -238,7 +283,7 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | |||
238 | memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); | 283 | memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); |
239 | memcpy(lnm_session_key, password_with_pad, | 284 | memcpy(lnm_session_key, password_with_pad, |
240 | CIFS_ENCPWD_SIZE); | 285 | CIFS_ENCPWD_SIZE); |
241 | return; | 286 | return 0; |
242 | } | 287 | } |
243 | 288 | ||
244 | /* calculate old style session key */ | 289 | /* calculate old style session key */ |
@@ -255,116 +300,463 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, | |||
255 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) | 300 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) |
256 | password_with_pad[i] = toupper(password_with_pad[i]); | 301 | password_with_pad[i] = toupper(password_with_pad[i]); |
257 | 302 | ||
258 | SMBencrypt(password_with_pad, cryptkey, lnm_session_key); | 303 | rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key); |
259 | 304 | ||
260 | /* clear password before we return/free memory */ | 305 | return rc; |
261 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | ||
262 | } | 306 | } |
263 | #endif /* CIFS_WEAK_PW_HASH */ | 307 | #endif /* CIFS_WEAK_PW_HASH */ |
264 | 308 | ||
265 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | 309 | /* Build a proper attribute value/target info pairs blob. |
310 | * Fill in netbios and dns domain name and workstation name | ||
311 | * and client time (total five av pairs and + one end of fields indicator. | ||
312 | * Allocate domain name which gets freed when session struct is deallocated. | ||
313 | */ | ||
314 | static int | ||
315 | build_avpair_blob(struct cifs_ses *ses, const struct nls_table *nls_cp) | ||
316 | { | ||
317 | unsigned int dlen; | ||
318 | unsigned int wlen; | ||
319 | unsigned int size = 6 * sizeof(struct ntlmssp2_name); | ||
320 | __le64 curtime; | ||
321 | char *defdmname = "WORKGROUP"; | ||
322 | unsigned char *blobptr; | ||
323 | struct ntlmssp2_name *attrptr; | ||
324 | |||
325 | if (!ses->domainName) { | ||
326 | ses->domainName = kstrdup(defdmname, GFP_KERNEL); | ||
327 | if (!ses->domainName) | ||
328 | return -ENOMEM; | ||
329 | } | ||
330 | |||
331 | dlen = strlen(ses->domainName); | ||
332 | wlen = strlen(ses->server->hostname); | ||
333 | |||
334 | /* The length of this blob is a size which is | ||
335 | * six times the size of a structure which holds name/size + | ||
336 | * two times the unicode length of a domain name + | ||
337 | * two times the unicode length of a server name + | ||
338 | * size of a timestamp (which is 8 bytes). | ||
339 | */ | ||
340 | ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8; | ||
341 | ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL); | ||
342 | if (!ses->auth_key.response) { | ||
343 | ses->auth_key.len = 0; | ||
344 | cERROR(1, "Challenge target info allocation failure"); | ||
345 | return -ENOMEM; | ||
346 | } | ||
347 | |||
348 | blobptr = ses->auth_key.response; | ||
349 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
350 | |||
351 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); | ||
352 | attrptr->length = cpu_to_le16(2 * dlen); | ||
353 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
354 | cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); | ||
355 | |||
356 | blobptr += 2 * dlen; | ||
357 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
358 | |||
359 | attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_COMPUTER_NAME); | ||
360 | attrptr->length = cpu_to_le16(2 * wlen); | ||
361 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
362 | cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp); | ||
363 | |||
364 | blobptr += 2 * wlen; | ||
365 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
366 | |||
367 | attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_DOMAIN_NAME); | ||
368 | attrptr->length = cpu_to_le16(2 * dlen); | ||
369 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
370 | cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); | ||
371 | |||
372 | blobptr += 2 * dlen; | ||
373 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
374 | |||
375 | attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_COMPUTER_NAME); | ||
376 | attrptr->length = cpu_to_le16(2 * wlen); | ||
377 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
378 | cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp); | ||
379 | |||
380 | blobptr += 2 * wlen; | ||
381 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
382 | |||
383 | attrptr->type = cpu_to_le16(NTLMSSP_AV_TIMESTAMP); | ||
384 | attrptr->length = cpu_to_le16(sizeof(__le64)); | ||
385 | blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); | ||
386 | curtime = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
387 | memcpy(blobptr, &curtime, sizeof(__le64)); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /* Server has provided av pairs/target info in the type 2 challenge | ||
393 | * packet and we have plucked it and stored within smb session. | ||
394 | * We parse that blob here to find netbios domain name to be used | ||
395 | * as part of ntlmv2 authentication (in Target String), if not already | ||
396 | * specified on the command line. | ||
397 | * If this function returns without any error but without fetching | ||
398 | * domain name, authentication may fail against some server but | ||
399 | * may not fail against other (those who are not very particular | ||
400 | * about target string i.e. for some, just user name might suffice. | ||
401 | */ | ||
402 | static int | ||
403 | find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) | ||
404 | { | ||
405 | unsigned int attrsize; | ||
406 | unsigned int type; | ||
407 | unsigned int onesize = sizeof(struct ntlmssp2_name); | ||
408 | unsigned char *blobptr; | ||
409 | unsigned char *blobend; | ||
410 | struct ntlmssp2_name *attrptr; | ||
411 | |||
412 | if (!ses->auth_key.len || !ses->auth_key.response) | ||
413 | return 0; | ||
414 | |||
415 | blobptr = ses->auth_key.response; | ||
416 | blobend = blobptr + ses->auth_key.len; | ||
417 | |||
418 | while (blobptr + onesize < blobend) { | ||
419 | attrptr = (struct ntlmssp2_name *) blobptr; | ||
420 | type = le16_to_cpu(attrptr->type); | ||
421 | if (type == NTLMSSP_AV_EOL) | ||
422 | break; | ||
423 | blobptr += 2; /* advance attr type */ | ||
424 | attrsize = le16_to_cpu(attrptr->length); | ||
425 | blobptr += 2; /* advance attr size */ | ||
426 | if (blobptr + attrsize > blobend) | ||
427 | break; | ||
428 | if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { | ||
429 | if (!attrsize) | ||
430 | break; | ||
431 | if (!ses->domainName) { | ||
432 | ses->domainName = | ||
433 | kmalloc(attrsize + 1, GFP_KERNEL); | ||
434 | if (!ses->domainName) | ||
435 | return -ENOMEM; | ||
436 | cifs_from_ucs2(ses->domainName, | ||
437 | (__le16 *)blobptr, attrsize, attrsize, | ||
438 | nls_cp, false); | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | blobptr += attrsize; /* advance attr value */ | ||
443 | } | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, | ||
266 | const struct nls_table *nls_cp) | 449 | const struct nls_table *nls_cp) |
267 | { | 450 | { |
268 | int rc = 0; | 451 | int rc = 0; |
269 | int len; | 452 | int len; |
270 | char nt_hash[16]; | 453 | char nt_hash[CIFS_NTHASH_SIZE]; |
271 | struct HMACMD5Context *pctxt; | ||
272 | wchar_t *user; | 454 | wchar_t *user; |
273 | wchar_t *domain; | 455 | wchar_t *domain; |
456 | wchar_t *server; | ||
274 | 457 | ||
275 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | 458 | if (!ses->server->secmech.sdeschmacmd5) { |
276 | 459 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | |
277 | if (pctxt == NULL) | 460 | return -1; |
278 | return -ENOMEM; | 461 | } |
279 | 462 | ||
280 | /* calculate md4 hash of password */ | 463 | /* calculate md4 hash of password */ |
281 | E_md4hash(ses->password, nt_hash); | 464 | E_md4hash(ses->password, nt_hash); |
282 | 465 | ||
283 | /* convert Domainname to unicode and uppercase */ | 466 | crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, |
284 | hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); | 467 | CIFS_NTHASH_SIZE); |
468 | |||
469 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
470 | if (rc) { | ||
471 | cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); | ||
472 | return rc; | ||
473 | } | ||
285 | 474 | ||
286 | /* convert ses->userName to unicode and uppercase */ | 475 | /* convert ses->user_name to unicode and uppercase */ |
287 | len = strlen(ses->userName); | 476 | len = strlen(ses->user_name); |
288 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 477 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
289 | if (user == NULL) | 478 | if (user == NULL) { |
479 | cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); | ||
480 | rc = -ENOMEM; | ||
290 | goto calc_exit_2; | 481 | goto calc_exit_2; |
291 | len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); | 482 | } |
483 | len = cifs_strtoUCS((__le16 *)user, ses->user_name, len, nls_cp); | ||
292 | UniStrupr(user); | 484 | UniStrupr(user); |
293 | hmac_md5_update((char *)user, 2*len, pctxt); | 485 | |
486 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
487 | (char *)user, 2 * len); | ||
294 | 488 | ||
295 | /* convert ses->domainName to unicode and uppercase */ | 489 | /* convert ses->domainName to unicode and uppercase */ |
296 | if (ses->domainName) { | 490 | if (ses->domainName) { |
297 | len = strlen(ses->domainName); | 491 | len = strlen(ses->domainName); |
298 | 492 | ||
299 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 493 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
300 | if (domain == NULL) | 494 | if (domain == NULL) { |
495 | cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); | ||
496 | rc = -ENOMEM; | ||
301 | goto calc_exit_1; | 497 | goto calc_exit_1; |
498 | } | ||
302 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, | 499 | len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, |
303 | nls_cp); | 500 | nls_cp); |
304 | /* the following line was removed since it didn't work well | 501 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, |
305 | with lower cased domain name that passed as an option. | 502 | (char *)domain, 2 * len); |
306 | Maybe converting the domain name earlier makes sense */ | ||
307 | /* UniStrupr(domain); */ | ||
308 | |||
309 | hmac_md5_update((char *)domain, 2*len, pctxt); | ||
310 | |||
311 | kfree(domain); | 503 | kfree(domain); |
504 | } else if (ses->serverName) { | ||
505 | len = strlen(ses->serverName); | ||
506 | |||
507 | server = kmalloc(2 + (len * 2), GFP_KERNEL); | ||
508 | if (server == NULL) { | ||
509 | cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); | ||
510 | rc = -ENOMEM; | ||
511 | goto calc_exit_1; | ||
512 | } | ||
513 | len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, | ||
514 | nls_cp); | ||
515 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
516 | (char *)server, 2 * len); | ||
517 | kfree(server); | ||
312 | } | 518 | } |
519 | |||
520 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
521 | ntlmv2_hash); | ||
522 | |||
313 | calc_exit_1: | 523 | calc_exit_1: |
314 | kfree(user); | 524 | kfree(user); |
315 | calc_exit_2: | 525 | calc_exit_2: |
316 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 526 | return rc; |
317 | compare with the NTLM example */ | 527 | } |
318 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); | 528 | |
529 | static int | ||
530 | CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) | ||
531 | { | ||
532 | int rc; | ||
533 | unsigned int offset = CIFS_SESS_KEY_SIZE + 8; | ||
534 | |||
535 | if (!ses->server->secmech.sdeschmacmd5) { | ||
536 | cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); | ||
537 | return -1; | ||
538 | } | ||
539 | |||
540 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
541 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
542 | |||
543 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); | ||
544 | if (rc) { | ||
545 | cERROR(1, "CalcNTLMv2_response: could not init hmacmd5"); | ||
546 | return rc; | ||
547 | } | ||
548 | |||
549 | if (ses->server->secType == RawNTLMSSP) | ||
550 | memcpy(ses->auth_key.response + offset, | ||
551 | ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
552 | else | ||
553 | memcpy(ses->auth_key.response + offset, | ||
554 | ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE); | ||
555 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
556 | ses->auth_key.response + offset, ses->auth_key.len - offset); | ||
557 | |||
558 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
559 | ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
319 | 560 | ||
320 | kfree(pctxt); | ||
321 | return rc; | 561 | return rc; |
322 | } | 562 | } |
323 | 563 | ||
324 | void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, | 564 | |
325 | const struct nls_table *nls_cp) | 565 | int |
566 | setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) | ||
326 | { | 567 | { |
327 | int rc; | 568 | int rc; |
328 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; | 569 | int baselen; |
329 | struct HMACMD5Context context; | 570 | unsigned int tilen; |
571 | struct ntlmv2_resp *buf; | ||
572 | char ntlmv2_hash[16]; | ||
573 | unsigned char *tiblob = NULL; /* target info blob */ | ||
574 | |||
575 | if (ses->server->secType == RawNTLMSSP) { | ||
576 | if (!ses->domainName) { | ||
577 | rc = find_domain_name(ses, nls_cp); | ||
578 | if (rc) { | ||
579 | cERROR(1, "error %d finding domain name", rc); | ||
580 | goto setup_ntlmv2_rsp_ret; | ||
581 | } | ||
582 | } | ||
583 | } else { | ||
584 | rc = build_avpair_blob(ses, nls_cp); | ||
585 | if (rc) { | ||
586 | cERROR(1, "error %d building av pair blob", rc); | ||
587 | goto setup_ntlmv2_rsp_ret; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); | ||
592 | tilen = ses->auth_key.len; | ||
593 | tiblob = ses->auth_key.response; | ||
330 | 594 | ||
595 | ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); | ||
596 | if (!ses->auth_key.response) { | ||
597 | rc = ENOMEM; | ||
598 | ses->auth_key.len = 0; | ||
599 | cERROR(1, "%s: Can't allocate auth blob", __func__); | ||
600 | goto setup_ntlmv2_rsp_ret; | ||
601 | } | ||
602 | ses->auth_key.len += baselen; | ||
603 | |||
604 | buf = (struct ntlmv2_resp *) | ||
605 | (ses->auth_key.response + CIFS_SESS_KEY_SIZE); | ||
331 | buf->blob_signature = cpu_to_le32(0x00000101); | 606 | buf->blob_signature = cpu_to_le32(0x00000101); |
332 | buf->reserved = 0; | 607 | buf->reserved = 0; |
333 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 608 | buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); |
334 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); | 609 | get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); |
335 | buf->reserved2 = 0; | 610 | buf->reserved2 = 0; |
336 | buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); | ||
337 | buf->names[0].length = 0; | ||
338 | buf->names[1].type = 0; | ||
339 | buf->names[1].length = 0; | ||
340 | 611 | ||
341 | /* calculate buf->ntlmv2_hash */ | 612 | memcpy(ses->auth_key.response + baselen, tiblob, tilen); |
342 | rc = calc_ntlmv2_hash(ses, nls_cp); | 613 | |
343 | if (rc) | 614 | /* calculate ntlmv2_hash */ |
615 | rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); | ||
616 | if (rc) { | ||
344 | cERROR(1, "could not get v2 hash rc %d", rc); | 617 | cERROR(1, "could not get v2 hash rc %d", rc); |
345 | CalcNTLMv2_response(ses, resp_buf); | 618 | goto setup_ntlmv2_rsp_ret; |
619 | } | ||
620 | |||
621 | /* calculate first part of the client response (CR1) */ | ||
622 | rc = CalcNTLMv2_response(ses, ntlmv2_hash); | ||
623 | if (rc) { | ||
624 | cERROR(1, "Could not calculate CR1 rc: %d", rc); | ||
625 | goto setup_ntlmv2_rsp_ret; | ||
626 | } | ||
627 | |||
628 | /* now calculate the session key for NTLMv2 */ | ||
629 | crypto_shash_setkey(ses->server->secmech.hmacmd5, | ||
630 | ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); | ||
346 | 631 | ||
347 | /* now calculate the MAC key for NTLMv2 */ | 632 | rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); |
348 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); | 633 | if (rc) { |
349 | hmac_md5_update(resp_buf, 16, &context); | 634 | cERROR(1, "%s: Could not init hmacmd5\n", __func__); |
350 | hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context); | 635 | goto setup_ntlmv2_rsp_ret; |
636 | } | ||
637 | |||
638 | crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, | ||
639 | ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
640 | CIFS_HMAC_MD5_HASH_SIZE); | ||
641 | |||
642 | rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, | ||
643 | ses->auth_key.response); | ||
351 | 644 | ||
352 | memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf, | 645 | setup_ntlmv2_rsp_ret: |
353 | sizeof(struct ntlmv2_resp)); | 646 | kfree(tiblob); |
354 | ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); | 647 | |
648 | return rc; | ||
355 | } | 649 | } |
356 | 650 | ||
357 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, | 651 | int |
358 | char *v2_session_response) | 652 | calc_seckey(struct cifs_ses *ses) |
359 | { | 653 | { |
360 | struct HMACMD5Context context; | 654 | int rc; |
361 | /* rest of v2 struct already generated */ | 655 | struct crypto_blkcipher *tfm_arc4; |
362 | memcpy(v2_session_response + 8, ses->server->cryptKey, 8); | 656 | struct scatterlist sgin, sgout; |
363 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); | 657 | struct blkcipher_desc desc; |
658 | unsigned char sec_key[CIFS_SESS_KEY_SIZE]; /* a nonce */ | ||
659 | |||
660 | get_random_bytes(sec_key, CIFS_SESS_KEY_SIZE); | ||
661 | |||
662 | tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); | ||
663 | if (IS_ERR(tfm_arc4)) { | ||
664 | rc = PTR_ERR(tfm_arc4); | ||
665 | cERROR(1, "could not allocate crypto API arc4\n"); | ||
666 | return rc; | ||
667 | } | ||
668 | |||
669 | desc.tfm = tfm_arc4; | ||
670 | |||
671 | crypto_blkcipher_setkey(tfm_arc4, ses->auth_key.response, | ||
672 | CIFS_SESS_KEY_SIZE); | ||
673 | |||
674 | sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE); | ||
675 | sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); | ||
676 | |||
677 | rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE); | ||
678 | if (rc) { | ||
679 | cERROR(1, "could not encrypt session key rc: %d\n", rc); | ||
680 | crypto_free_blkcipher(tfm_arc4); | ||
681 | return rc; | ||
682 | } | ||
683 | |||
684 | /* make secondary_key/nonce as session key */ | ||
685 | memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); | ||
686 | /* and make len as that of session key only */ | ||
687 | ses->auth_key.len = CIFS_SESS_KEY_SIZE; | ||
688 | |||
689 | crypto_free_blkcipher(tfm_arc4); | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | void | ||
695 | cifs_crypto_shash_release(struct TCP_Server_Info *server) | ||
696 | { | ||
697 | if (server->secmech.md5) | ||
698 | crypto_free_shash(server->secmech.md5); | ||
364 | 699 | ||
365 | hmac_md5_update(v2_session_response+8, | 700 | if (server->secmech.hmacmd5) |
366 | sizeof(struct ntlmv2_resp) - 8, &context); | 701 | crypto_free_shash(server->secmech.hmacmd5); |
367 | 702 | ||
368 | hmac_md5_final(v2_session_response, &context); | 703 | kfree(server->secmech.sdeschmacmd5); |
369 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ | 704 | |
705 | kfree(server->secmech.sdescmd5); | ||
706 | } | ||
707 | |||
708 | int | ||
709 | cifs_crypto_shash_allocate(struct TCP_Server_Info *server) | ||
710 | { | ||
711 | int rc; | ||
712 | unsigned int size; | ||
713 | |||
714 | server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); | ||
715 | if (IS_ERR(server->secmech.hmacmd5)) { | ||
716 | cERROR(1, "could not allocate crypto hmacmd5\n"); | ||
717 | return PTR_ERR(server->secmech.hmacmd5); | ||
718 | } | ||
719 | |||
720 | server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); | ||
721 | if (IS_ERR(server->secmech.md5)) { | ||
722 | cERROR(1, "could not allocate crypto md5\n"); | ||
723 | rc = PTR_ERR(server->secmech.md5); | ||
724 | goto crypto_allocate_md5_fail; | ||
725 | } | ||
726 | |||
727 | size = sizeof(struct shash_desc) + | ||
728 | crypto_shash_descsize(server->secmech.hmacmd5); | ||
729 | server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL); | ||
730 | if (!server->secmech.sdeschmacmd5) { | ||
731 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc hmacmd5\n"); | ||
732 | rc = -ENOMEM; | ||
733 | goto crypto_allocate_hmacmd5_sdesc_fail; | ||
734 | } | ||
735 | server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5; | ||
736 | server->secmech.sdeschmacmd5->shash.flags = 0x0; | ||
737 | |||
738 | |||
739 | size = sizeof(struct shash_desc) + | ||
740 | crypto_shash_descsize(server->secmech.md5); | ||
741 | server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); | ||
742 | if (!server->secmech.sdescmd5) { | ||
743 | cERROR(1, "cifs_crypto_shash_allocate: can't alloc md5\n"); | ||
744 | rc = -ENOMEM; | ||
745 | goto crypto_allocate_md5_sdesc_fail; | ||
746 | } | ||
747 | server->secmech.sdescmd5->shash.tfm = server->secmech.md5; | ||
748 | server->secmech.sdescmd5->shash.flags = 0x0; | ||
749 | |||
750 | return 0; | ||
751 | |||
752 | crypto_allocate_md5_sdesc_fail: | ||
753 | kfree(server->secmech.sdeschmacmd5); | ||
754 | |||
755 | crypto_allocate_hmacmd5_sdesc_fail: | ||
756 | crypto_free_shash(server->secmech.md5); | ||
757 | |||
758 | crypto_allocate_md5_fail: | ||
759 | crypto_free_shash(server->secmech.hmacmd5); | ||
760 | |||
761 | return rc; | ||
370 | } | 762 | } |
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h deleted file mode 100644 index 15d2ec006474..000000000000 --- a/fs/cifs/cifsencrypt.h +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsencrypt.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2005 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * Externs for misc. small encryption routines | ||
8 | * so we do not have to put them in cifsproto.h | ||
9 | * | ||
10 | * This library is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU Lesser General Public License as published | ||
12 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This library is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
18 | * the GNU Lesser General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU Lesser General Public License | ||
21 | * along with this library; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | /* md4.c */ | ||
26 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | ||
27 | /* smbdes.c */ | ||
28 | extern void E_P16(unsigned char *p14, unsigned char *p16); | ||
29 | extern void E_P24(unsigned char *p21, const unsigned char *c8, | ||
30 | unsigned char *p24); | ||
31 | |||
32 | |||
33 | |||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b7431afdd76d..bc4b12ca537b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -35,7 +35,8 @@ | |||
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/kthread.h> | 36 | #include <linux/kthread.h> |
37 | #include <linux/freezer.h> | 37 | #include <linux/freezer.h> |
38 | #include <linux/smp_lock.h> | 38 | #include <linux/namei.h> |
39 | #include <net/ipv6.h> | ||
39 | #include "cifsfs.h" | 40 | #include "cifsfs.h" |
40 | #include "cifspdu.h" | 41 | #include "cifspdu.h" |
41 | #define DECLARE_GLOBALS_HERE | 42 | #define DECLARE_GLOBALS_HERE |
@@ -53,7 +54,6 @@ int cifsFYI = 0; | |||
53 | int cifsERROR = 1; | 54 | int cifsERROR = 1; |
54 | int traceSMB = 0; | 55 | int traceSMB = 0; |
55 | unsigned int oplockEnabled = 1; | 56 | unsigned int oplockEnabled = 1; |
56 | unsigned int experimEnabled = 0; | ||
57 | unsigned int linuxExtEnabled = 1; | 57 | unsigned int linuxExtEnabled = 1; |
58 | unsigned int lookupCacheEnabled = 1; | 58 | unsigned int lookupCacheEnabled = 1; |
59 | unsigned int multiuser_mount = 0; | 59 | unsigned int multiuser_mount = 0; |
@@ -77,71 +77,59 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ; | |||
77 | module_param(cifs_max_pending, int, 0); | 77 | module_param(cifs_max_pending, int, 0); |
78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " | 78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " |
79 | "Default: 50 Range: 2 to 256"); | 79 | "Default: 50 Range: 2 to 256"); |
80 | 80 | unsigned short echo_retries = 5; | |
81 | module_param(echo_retries, ushort, 0644); | ||
82 | MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " | ||
83 | "reconnecting server. Default: 5. 0 means " | ||
84 | "never reconnect."); | ||
81 | extern mempool_t *cifs_sm_req_poolp; | 85 | extern mempool_t *cifs_sm_req_poolp; |
82 | extern mempool_t *cifs_req_poolp; | 86 | extern mempool_t *cifs_req_poolp; |
83 | extern mempool_t *cifs_mid_poolp; | 87 | extern mempool_t *cifs_mid_poolp; |
84 | 88 | ||
89 | void | ||
90 | cifs_sb_active(struct super_block *sb) | ||
91 | { | ||
92 | struct cifs_sb_info *server = CIFS_SB(sb); | ||
93 | |||
94 | if (atomic_inc_return(&server->active) == 1) | ||
95 | atomic_inc(&sb->s_active); | ||
96 | } | ||
97 | |||
98 | void | ||
99 | cifs_sb_deactive(struct super_block *sb) | ||
100 | { | ||
101 | struct cifs_sb_info *server = CIFS_SB(sb); | ||
102 | |||
103 | if (atomic_dec_and_test(&server->active)) | ||
104 | deactivate_super(sb); | ||
105 | } | ||
106 | |||
85 | static int | 107 | static int |
86 | cifs_read_super(struct super_block *sb, void *data, | 108 | cifs_read_super(struct super_block *sb) |
87 | const char *devname, int silent) | ||
88 | { | 109 | { |
89 | struct inode *inode; | 110 | struct inode *inode; |
90 | struct cifs_sb_info *cifs_sb; | 111 | struct cifs_sb_info *cifs_sb; |
91 | int rc = 0; | 112 | int rc = 0; |
92 | 113 | ||
93 | /* BB should we make this contingent on mount parm? */ | ||
94 | sb->s_flags |= MS_NODIRATIME | MS_NOATIME; | ||
95 | sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); | ||
96 | cifs_sb = CIFS_SB(sb); | 114 | cifs_sb = CIFS_SB(sb); |
97 | if (cifs_sb == NULL) | ||
98 | return -ENOMEM; | ||
99 | 115 | ||
100 | rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); | 116 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIXACL) |
101 | if (rc) { | 117 | sb->s_flags |= MS_POSIXACL; |
102 | kfree(cifs_sb); | ||
103 | return rc; | ||
104 | } | ||
105 | 118 | ||
106 | #ifdef CONFIG_CIFS_DFS_UPCALL | 119 | if (cifs_sb_master_tcon(cifs_sb)->ses->capabilities & CAP_LARGE_FILES) |
107 | /* copy mount params to sb for use in submounts */ | 120 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
108 | /* BB: should we move this after the mount so we | 121 | else |
109 | * do not have to do the copy on failed mounts? | 122 | sb->s_maxbytes = MAX_NON_LFS; |
110 | * BB: May be it is better to do simple copy before | ||
111 | * complex operation (mount), and in case of fail | ||
112 | * just exit instead of doing mount and attempting | ||
113 | * undo it if this copy fails?*/ | ||
114 | if (data) { | ||
115 | int len = strlen(data); | ||
116 | cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); | ||
117 | if (cifs_sb->mountdata == NULL) { | ||
118 | bdi_destroy(&cifs_sb->bdi); | ||
119 | kfree(sb->s_fs_info); | ||
120 | sb->s_fs_info = NULL; | ||
121 | return -ENOMEM; | ||
122 | } | ||
123 | strncpy(cifs_sb->mountdata, data, len + 1); | ||
124 | cifs_sb->mountdata[len] = '\0'; | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | rc = cifs_mount(sb, cifs_sb, data, devname); | ||
129 | 123 | ||
130 | if (rc) { | 124 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
131 | if (!silent) | 125 | sb->s_time_gran = 100; |
132 | cERROR(1, "cifs_mount failed w/return code = %d", rc); | ||
133 | goto out_mount_failed; | ||
134 | } | ||
135 | 126 | ||
136 | sb->s_magic = CIFS_MAGIC_NUMBER; | 127 | sb->s_magic = CIFS_MAGIC_NUMBER; |
137 | sb->s_op = &cifs_super_ops; | 128 | sb->s_op = &cifs_super_ops; |
138 | sb->s_bdi = &cifs_sb->bdi; | 129 | sb->s_bdi = &cifs_sb->bdi; |
139 | /* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) | ||
140 | sb->s_blocksize = | ||
141 | cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ | ||
142 | sb->s_blocksize = CIFS_MAX_MSGSIZE; | 130 | sb->s_blocksize = CIFS_MAX_MSGSIZE; |
143 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ | 131 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ |
144 | inode = cifs_root_iget(sb, ROOT_I); | 132 | inode = cifs_root_iget(sb); |
145 | 133 | ||
146 | if (IS_ERR(inode)) { | 134 | if (IS_ERR(inode)) { |
147 | rc = PTR_ERR(inode); | 135 | rc = PTR_ERR(inode); |
@@ -156,12 +144,18 @@ cifs_read_super(struct super_block *sb, void *data, | |||
156 | goto out_no_root; | 144 | goto out_no_root; |
157 | } | 145 | } |
158 | 146 | ||
159 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 147 | /* do that *after* d_alloc_root() - we want NULL ->d_op for root here */ |
148 | if (cifs_sb_master_tcon(cifs_sb)->nocase) | ||
149 | sb->s_d_op = &cifs_ci_dentry_ops; | ||
150 | else | ||
151 | sb->s_d_op = &cifs_dentry_ops; | ||
152 | |||
153 | #ifdef CIFS_NFSD_EXPORT | ||
160 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 154 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
161 | cFYI(1, "export ops supported"); | 155 | cFYI(1, "export ops supported"); |
162 | sb->s_export_op = &cifs_export_ops; | 156 | sb->s_export_op = &cifs_export_ops; |
163 | } | 157 | } |
164 | #endif /* EXPERIMENTAL */ | 158 | #endif /* CIFS_NFSD_EXPORT */ |
165 | 159 | ||
166 | return 0; | 160 | return 0; |
167 | 161 | ||
@@ -170,53 +164,14 @@ out_no_root: | |||
170 | if (inode) | 164 | if (inode) |
171 | iput(inode); | 165 | iput(inode); |
172 | 166 | ||
173 | cifs_umount(sb, cifs_sb); | ||
174 | |||
175 | out_mount_failed: | ||
176 | if (cifs_sb) { | ||
177 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
178 | if (cifs_sb->mountdata) { | ||
179 | kfree(cifs_sb->mountdata); | ||
180 | cifs_sb->mountdata = NULL; | ||
181 | } | ||
182 | #endif | ||
183 | unload_nls(cifs_sb->local_nls); | ||
184 | bdi_destroy(&cifs_sb->bdi); | ||
185 | kfree(cifs_sb); | ||
186 | } | ||
187 | return rc; | 167 | return rc; |
188 | } | 168 | } |
189 | 169 | ||
190 | static void | 170 | static void cifs_kill_sb(struct super_block *sb) |
191 | cifs_put_super(struct super_block *sb) | ||
192 | { | 171 | { |
193 | int rc = 0; | 172 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
194 | struct cifs_sb_info *cifs_sb; | 173 | kill_anon_super(sb); |
195 | 174 | cifs_umount(cifs_sb); | |
196 | cFYI(1, "In cifs_put_super"); | ||
197 | cifs_sb = CIFS_SB(sb); | ||
198 | if (cifs_sb == NULL) { | ||
199 | cFYI(1, "Empty cifs superblock info passed to unmount"); | ||
200 | return; | ||
201 | } | ||
202 | |||
203 | lock_kernel(); | ||
204 | |||
205 | rc = cifs_umount(sb, cifs_sb); | ||
206 | if (rc) | ||
207 | cERROR(1, "cifs_umount failed with return code %d", rc); | ||
208 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
209 | if (cifs_sb->mountdata) { | ||
210 | kfree(cifs_sb->mountdata); | ||
211 | cifs_sb->mountdata = NULL; | ||
212 | } | ||
213 | #endif | ||
214 | |||
215 | unload_nls(cifs_sb->local_nls); | ||
216 | bdi_destroy(&cifs_sb->bdi); | ||
217 | kfree(cifs_sb); | ||
218 | |||
219 | unlock_kernel(); | ||
220 | } | 175 | } |
221 | 176 | ||
222 | static int | 177 | static int |
@@ -224,7 +179,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
224 | { | 179 | { |
225 | struct super_block *sb = dentry->d_sb; | 180 | struct super_block *sb = dentry->d_sb; |
226 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 181 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
227 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 182 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
228 | int rc = -EOPNOTSUPP; | 183 | int rc = -EOPNOTSUPP; |
229 | int xid; | 184 | int xid; |
230 | 185 | ||
@@ -269,7 +224,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
269 | return 0; | 224 | return 0; |
270 | } | 225 | } |
271 | 226 | ||
272 | static int cifs_permission(struct inode *inode, int mask) | 227 | static int cifs_permission(struct inode *inode, int mask, unsigned int flags) |
273 | { | 228 | { |
274 | struct cifs_sb_info *cifs_sb; | 229 | struct cifs_sb_info *cifs_sb; |
275 | 230 | ||
@@ -284,7 +239,7 @@ static int cifs_permission(struct inode *inode, int mask) | |||
284 | on the client (above and beyond ACL on servers) for | 239 | on the client (above and beyond ACL on servers) for |
285 | servers which do not support setting and viewing mode bits, | 240 | servers which do not support setting and viewing mode bits, |
286 | so allowing client to check permissions is useful */ | 241 | so allowing client to check permissions is useful */ |
287 | return generic_permission(inode, mask, NULL); | 242 | return generic_permission(inode, mask, flags, NULL); |
288 | } | 243 | } |
289 | 244 | ||
290 | static struct kmem_cache *cifs_inode_cachep; | 245 | static struct kmem_cache *cifs_inode_cachep; |
@@ -304,16 +259,16 @@ cifs_alloc_inode(struct super_block *sb) | |||
304 | return NULL; | 259 | return NULL; |
305 | cifs_inode->cifsAttrs = 0x20; /* default */ | 260 | cifs_inode->cifsAttrs = 0x20; /* default */ |
306 | cifs_inode->time = 0; | 261 | cifs_inode->time = 0; |
307 | cifs_inode->write_behind_rc = 0; | ||
308 | /* Until the file is open and we have gotten oplock | 262 | /* Until the file is open and we have gotten oplock |
309 | info back from the server, can not assume caching of | 263 | info back from the server, can not assume caching of |
310 | file data or metadata */ | 264 | file data or metadata */ |
311 | cifs_inode->clientCanCacheRead = false; | 265 | cifs_set_oplock_level(cifs_inode, 0); |
312 | cifs_inode->clientCanCacheAll = false; | ||
313 | cifs_inode->delete_pending = false; | 266 | cifs_inode->delete_pending = false; |
314 | cifs_inode->invalid_mapping = false; | 267 | cifs_inode->invalid_mapping = false; |
315 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 268 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
316 | cifs_inode->server_eof = 0; | 269 | cifs_inode->server_eof = 0; |
270 | cifs_inode->uniqueid = 0; | ||
271 | cifs_inode->createtime = 0; | ||
317 | 272 | ||
318 | /* Can not set i_flags here - they get immediately overwritten | 273 | /* Can not set i_flags here - they get immediately overwritten |
319 | to zero by the VFS */ | 274 | to zero by the VFS */ |
@@ -322,10 +277,17 @@ cifs_alloc_inode(struct super_block *sb) | |||
322 | return &cifs_inode->vfs_inode; | 277 | return &cifs_inode->vfs_inode; |
323 | } | 278 | } |
324 | 279 | ||
280 | static void cifs_i_callback(struct rcu_head *head) | ||
281 | { | ||
282 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
283 | INIT_LIST_HEAD(&inode->i_dentry); | ||
284 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | ||
285 | } | ||
286 | |||
325 | static void | 287 | static void |
326 | cifs_destroy_inode(struct inode *inode) | 288 | cifs_destroy_inode(struct inode *inode) |
327 | { | 289 | { |
328 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | 290 | call_rcu(&inode->i_rcu, cifs_i_callback); |
329 | } | 291 | } |
330 | 292 | ||
331 | static void | 293 | static void |
@@ -339,24 +301,56 @@ cifs_evict_inode(struct inode *inode) | |||
339 | static void | 301 | static void |
340 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 302 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) |
341 | { | 303 | { |
304 | struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; | ||
305 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; | ||
306 | |||
342 | seq_printf(s, ",addr="); | 307 | seq_printf(s, ",addr="); |
343 | 308 | ||
344 | switch (server->addr.sockAddr.sin_family) { | 309 | switch (server->dstaddr.ss_family) { |
345 | case AF_INET: | 310 | case AF_INET: |
346 | seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr); | 311 | seq_printf(s, "%pI4", &sa->sin_addr.s_addr); |
347 | break; | 312 | break; |
348 | case AF_INET6: | 313 | case AF_INET6: |
349 | seq_printf(s, "%pI6", | 314 | seq_printf(s, "%pI6", &sa6->sin6_addr.s6_addr); |
350 | &server->addr.sockAddr6.sin6_addr.s6_addr); | 315 | if (sa6->sin6_scope_id) |
351 | if (server->addr.sockAddr6.sin6_scope_id) | 316 | seq_printf(s, "%%%u", sa6->sin6_scope_id); |
352 | seq_printf(s, "%%%u", | ||
353 | server->addr.sockAddr6.sin6_scope_id); | ||
354 | break; | 317 | break; |
355 | default: | 318 | default: |
356 | seq_printf(s, "(unknown)"); | 319 | seq_printf(s, "(unknown)"); |
357 | } | 320 | } |
358 | } | 321 | } |
359 | 322 | ||
323 | static void | ||
324 | cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server) | ||
325 | { | ||
326 | seq_printf(s, ",sec="); | ||
327 | |||
328 | switch (server->secType) { | ||
329 | case LANMAN: | ||
330 | seq_printf(s, "lanman"); | ||
331 | break; | ||
332 | case NTLMv2: | ||
333 | seq_printf(s, "ntlmv2"); | ||
334 | break; | ||
335 | case NTLM: | ||
336 | seq_printf(s, "ntlm"); | ||
337 | break; | ||
338 | case Kerberos: | ||
339 | seq_printf(s, "krb5"); | ||
340 | break; | ||
341 | case RawNTLMSSP: | ||
342 | seq_printf(s, "ntlmssp"); | ||
343 | break; | ||
344 | default: | ||
345 | /* shouldn't ever happen */ | ||
346 | seq_printf(s, "unknown"); | ||
347 | break; | ||
348 | } | ||
349 | |||
350 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
351 | seq_printf(s, "i"); | ||
352 | } | ||
353 | |||
360 | /* | 354 | /* |
361 | * cifs_show_options() is for displaying mount options in /proc/mounts. | 355 | * cifs_show_options() is for displaying mount options in /proc/mounts. |
362 | * Not all settable options are displayed but most of the important | 356 | * Not all settable options are displayed but most of the important |
@@ -366,14 +360,38 @@ static int | |||
366 | cifs_show_options(struct seq_file *s, struct vfsmount *m) | 360 | cifs_show_options(struct seq_file *s, struct vfsmount *m) |
367 | { | 361 | { |
368 | struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); | 362 | struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb); |
369 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 363 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
364 | struct sockaddr *srcaddr; | ||
365 | srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; | ||
366 | |||
367 | cifs_show_security(s, tcon->ses->server); | ||
370 | 368 | ||
371 | seq_printf(s, ",unc=%s", tcon->treeName); | 369 | seq_printf(s, ",unc=%s", tcon->treeName); |
372 | if (tcon->ses->userName) | 370 | |
373 | seq_printf(s, ",username=%s", tcon->ses->userName); | 371 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) |
372 | seq_printf(s, ",multiuser"); | ||
373 | else if (tcon->ses->user_name) | ||
374 | seq_printf(s, ",username=%s", tcon->ses->user_name); | ||
375 | |||
374 | if (tcon->ses->domainName) | 376 | if (tcon->ses->domainName) |
375 | seq_printf(s, ",domain=%s", tcon->ses->domainName); | 377 | seq_printf(s, ",domain=%s", tcon->ses->domainName); |
376 | 378 | ||
379 | if (srcaddr->sa_family != AF_UNSPEC) { | ||
380 | struct sockaddr_in *saddr4; | ||
381 | struct sockaddr_in6 *saddr6; | ||
382 | saddr4 = (struct sockaddr_in *)srcaddr; | ||
383 | saddr6 = (struct sockaddr_in6 *)srcaddr; | ||
384 | if (srcaddr->sa_family == AF_INET6) | ||
385 | seq_printf(s, ",srcaddr=%pI6c", | ||
386 | &saddr6->sin6_addr); | ||
387 | else if (srcaddr->sa_family == AF_INET) | ||
388 | seq_printf(s, ",srcaddr=%pI4", | ||
389 | &saddr4->sin_addr.s_addr); | ||
390 | else | ||
391 | seq_printf(s, ",srcaddr=BAD-AF:%i", | ||
392 | (int)(srcaddr->sa_family)); | ||
393 | } | ||
394 | |||
377 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); | 395 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); |
378 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) | 396 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
379 | seq_printf(s, ",forceuid"); | 397 | seq_printf(s, ",forceuid"); |
@@ -398,14 +416,20 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
398 | seq_printf(s, ",nocase"); | 416 | seq_printf(s, ",nocase"); |
399 | if (tcon->retry) | 417 | if (tcon->retry) |
400 | seq_printf(s, ",hard"); | 418 | seq_printf(s, ",hard"); |
401 | if (cifs_sb->prepath) | 419 | if (tcon->unix_ext) |
402 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); | 420 | seq_printf(s, ",unix"); |
421 | else | ||
422 | seq_printf(s, ",nounix"); | ||
403 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | 423 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) |
404 | seq_printf(s, ",posixpaths"); | 424 | seq_printf(s, ",posixpaths"); |
405 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) | 425 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) |
406 | seq_printf(s, ",setuids"); | 426 | seq_printf(s, ",setuids"); |
407 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | 427 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) |
408 | seq_printf(s, ",serverino"); | 428 | seq_printf(s, ",serverino"); |
429 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | ||
430 | seq_printf(s, ",rwpidforward"); | ||
431 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) | ||
432 | seq_printf(s, ",forcemand"); | ||
409 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 433 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) |
410 | seq_printf(s, ",directio"); | 434 | seq_printf(s, ",directio"); |
411 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 435 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
@@ -422,9 +446,15 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
422 | seq_printf(s, ",dynperm"); | 446 | seq_printf(s, ",dynperm"); |
423 | if (m->mnt_sb->s_flags & MS_POSIXACL) | 447 | if (m->mnt_sb->s_flags & MS_POSIXACL) |
424 | seq_printf(s, ",acl"); | 448 | seq_printf(s, ",acl"); |
449 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) | ||
450 | seq_printf(s, ",mfsymlinks"); | ||
451 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) | ||
452 | seq_printf(s, ",fsc"); | ||
425 | 453 | ||
426 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); | 454 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); |
427 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | 455 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); |
456 | /* convert actimeo and display it in seconds */ | ||
457 | seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); | ||
428 | 458 | ||
429 | return 0; | 459 | return 0; |
430 | } | 460 | } |
@@ -432,25 +462,23 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
432 | static void cifs_umount_begin(struct super_block *sb) | 462 | static void cifs_umount_begin(struct super_block *sb) |
433 | { | 463 | { |
434 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 464 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
435 | struct cifsTconInfo *tcon; | 465 | struct cifs_tcon *tcon; |
436 | 466 | ||
437 | if (cifs_sb == NULL) | 467 | if (cifs_sb == NULL) |
438 | return; | 468 | return; |
439 | 469 | ||
440 | tcon = cifs_sb->tcon; | 470 | tcon = cifs_sb_master_tcon(cifs_sb); |
441 | if (tcon == NULL) | ||
442 | return; | ||
443 | 471 | ||
444 | read_lock(&cifs_tcp_ses_lock); | 472 | spin_lock(&cifs_tcp_ses_lock); |
445 | if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { | 473 | if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { |
446 | /* we have other mounts to same share or we have | 474 | /* we have other mounts to same share or we have |
447 | already tried to force umount this and woken up | 475 | already tried to force umount this and woken up |
448 | all waiting network requests, nothing to do */ | 476 | all waiting network requests, nothing to do */ |
449 | read_unlock(&cifs_tcp_ses_lock); | 477 | spin_unlock(&cifs_tcp_ses_lock); |
450 | return; | 478 | return; |
451 | } else if (tcon->tc_count == 1) | 479 | } else if (tcon->tc_count == 1) |
452 | tcon->tidStatus = CifsExiting; | 480 | tcon->tidStatus = CifsExiting; |
453 | read_unlock(&cifs_tcp_ses_lock); | 481 | spin_unlock(&cifs_tcp_ses_lock); |
454 | 482 | ||
455 | /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ | 483 | /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ |
456 | /* cancel_notify_requests(tcon); */ | 484 | /* cancel_notify_requests(tcon); */ |
@@ -491,7 +519,6 @@ static int cifs_drop_inode(struct inode *inode) | |||
491 | } | 519 | } |
492 | 520 | ||
493 | static const struct super_operations cifs_super_ops = { | 521 | static const struct super_operations cifs_super_ops = { |
494 | .put_super = cifs_put_super, | ||
495 | .statfs = cifs_statfs, | 522 | .statfs = cifs_statfs, |
496 | .alloc_inode = cifs_alloc_inode, | 523 | .alloc_inode = cifs_alloc_inode, |
497 | .destroy_inode = cifs_destroy_inode, | 524 | .destroy_inode = cifs_destroy_inode, |
@@ -509,28 +536,151 @@ static const struct super_operations cifs_super_ops = { | |||
509 | #endif | 536 | #endif |
510 | }; | 537 | }; |
511 | 538 | ||
512 | static int | 539 | /* |
513 | cifs_get_sb(struct file_system_type *fs_type, | 540 | * Get root dentry from superblock according to prefix path mount option. |
514 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 541 | * Return dentry with refcount + 1 on success and NULL otherwise. |
542 | */ | ||
543 | static struct dentry * | ||
544 | cifs_get_root(struct smb_vol *vol, struct super_block *sb) | ||
545 | { | ||
546 | struct dentry *dentry; | ||
547 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
548 | char *full_path = NULL; | ||
549 | char *s, *p; | ||
550 | char sep; | ||
551 | int xid; | ||
552 | |||
553 | full_path = cifs_build_path_to_root(vol, cifs_sb, | ||
554 | cifs_sb_master_tcon(cifs_sb)); | ||
555 | if (full_path == NULL) | ||
556 | return ERR_PTR(-ENOMEM); | ||
557 | |||
558 | cFYI(1, "Get root dentry for %s", full_path); | ||
559 | |||
560 | xid = GetXid(); | ||
561 | sep = CIFS_DIR_SEP(cifs_sb); | ||
562 | dentry = dget(sb->s_root); | ||
563 | p = s = full_path; | ||
564 | |||
565 | do { | ||
566 | struct inode *dir = dentry->d_inode; | ||
567 | struct dentry *child; | ||
568 | |||
569 | /* skip separators */ | ||
570 | while (*s == sep) | ||
571 | s++; | ||
572 | if (!*s) | ||
573 | break; | ||
574 | p = s++; | ||
575 | /* next separator */ | ||
576 | while (*s && *s != sep) | ||
577 | s++; | ||
578 | |||
579 | mutex_lock(&dir->i_mutex); | ||
580 | child = lookup_one_len(p, dentry, s - p); | ||
581 | mutex_unlock(&dir->i_mutex); | ||
582 | dput(dentry); | ||
583 | dentry = child; | ||
584 | } while (!IS_ERR(dentry)); | ||
585 | _FreeXid(xid); | ||
586 | kfree(full_path); | ||
587 | return dentry; | ||
588 | } | ||
589 | |||
590 | static int cifs_set_super(struct super_block *sb, void *data) | ||
591 | { | ||
592 | struct cifs_mnt_data *mnt_data = data; | ||
593 | sb->s_fs_info = mnt_data->cifs_sb; | ||
594 | return set_anon_super(sb, NULL); | ||
595 | } | ||
596 | |||
597 | static struct dentry * | ||
598 | cifs_do_mount(struct file_system_type *fs_type, | ||
599 | int flags, const char *dev_name, void *data) | ||
515 | { | 600 | { |
516 | int rc; | 601 | int rc; |
517 | struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); | 602 | struct super_block *sb; |
603 | struct cifs_sb_info *cifs_sb; | ||
604 | struct smb_vol *volume_info; | ||
605 | struct cifs_mnt_data mnt_data; | ||
606 | struct dentry *root; | ||
518 | 607 | ||
519 | cFYI(1, "Devname: %s flags: %d ", dev_name, flags); | 608 | cFYI(1, "Devname: %s flags: %d ", dev_name, flags); |
520 | 609 | ||
521 | if (IS_ERR(sb)) | 610 | volume_info = cifs_get_volume_info((char *)data, dev_name); |
522 | return PTR_ERR(sb); | 611 | if (IS_ERR(volume_info)) |
612 | return ERR_CAST(volume_info); | ||
523 | 613 | ||
524 | sb->s_flags = flags; | 614 | cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); |
615 | if (cifs_sb == NULL) { | ||
616 | root = ERR_PTR(-ENOMEM); | ||
617 | goto out_nls; | ||
618 | } | ||
619 | |||
620 | cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); | ||
621 | if (cifs_sb->mountdata == NULL) { | ||
622 | root = ERR_PTR(-ENOMEM); | ||
623 | goto out_cifs_sb; | ||
624 | } | ||
525 | 625 | ||
526 | rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0); | 626 | cifs_setup_cifs_sb(volume_info, cifs_sb); |
627 | |||
628 | rc = cifs_mount(cifs_sb, volume_info); | ||
527 | if (rc) { | 629 | if (rc) { |
528 | deactivate_locked_super(sb); | 630 | if (!(flags & MS_SILENT)) |
529 | return rc; | 631 | cERROR(1, "cifs_mount failed w/return code = %d", rc); |
632 | root = ERR_PTR(rc); | ||
633 | goto out_mountdata; | ||
530 | } | 634 | } |
531 | sb->s_flags |= MS_ACTIVE; | 635 | |
532 | simple_set_mnt(mnt, sb); | 636 | mnt_data.vol = volume_info; |
533 | return 0; | 637 | mnt_data.cifs_sb = cifs_sb; |
638 | mnt_data.flags = flags; | ||
639 | |||
640 | sb = sget(fs_type, cifs_match_super, cifs_set_super, &mnt_data); | ||
641 | if (IS_ERR(sb)) { | ||
642 | root = ERR_CAST(sb); | ||
643 | cifs_umount(cifs_sb); | ||
644 | goto out; | ||
645 | } | ||
646 | |||
647 | if (sb->s_root) { | ||
648 | cFYI(1, "Use existing superblock"); | ||
649 | cifs_umount(cifs_sb); | ||
650 | } else { | ||
651 | sb->s_flags = flags; | ||
652 | /* BB should we make this contingent on mount parm? */ | ||
653 | sb->s_flags |= MS_NODIRATIME | MS_NOATIME; | ||
654 | |||
655 | rc = cifs_read_super(sb); | ||
656 | if (rc) { | ||
657 | root = ERR_PTR(rc); | ||
658 | goto out_super; | ||
659 | } | ||
660 | |||
661 | sb->s_flags |= MS_ACTIVE; | ||
662 | } | ||
663 | |||
664 | root = cifs_get_root(volume_info, sb); | ||
665 | if (IS_ERR(root)) | ||
666 | goto out_super; | ||
667 | |||
668 | cFYI(1, "dentry root is: %p", root); | ||
669 | goto out; | ||
670 | |||
671 | out_super: | ||
672 | deactivate_locked_super(sb); | ||
673 | out: | ||
674 | cifs_cleanup_volume_info(volume_info); | ||
675 | return root; | ||
676 | |||
677 | out_mountdata: | ||
678 | kfree(cifs_sb->mountdata); | ||
679 | out_cifs_sb: | ||
680 | kfree(cifs_sb); | ||
681 | out_nls: | ||
682 | unload_nls(volume_info->local_nls); | ||
683 | goto out; | ||
534 | } | 684 | } |
535 | 685 | ||
536 | static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | 686 | static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, |
@@ -538,10 +688,17 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
538 | { | 688 | { |
539 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; | 689 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
540 | ssize_t written; | 690 | ssize_t written; |
691 | int rc; | ||
541 | 692 | ||
542 | written = generic_file_aio_write(iocb, iov, nr_segs, pos); | 693 | written = generic_file_aio_write(iocb, iov, nr_segs, pos); |
543 | if (!CIFS_I(inode)->clientCanCacheAll) | 694 | |
544 | filemap_fdatawrite(inode->i_mapping); | 695 | if (CIFS_I(inode)->clientCanCacheAll) |
696 | return written; | ||
697 | |||
698 | rc = filemap_fdatawrite(inode->i_mapping); | ||
699 | if (rc) | ||
700 | cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode); | ||
701 | |||
545 | return written; | 702 | return written; |
546 | } | 703 | } |
547 | 704 | ||
@@ -549,25 +706,41 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | |||
549 | { | 706 | { |
550 | /* origin == SEEK_END => we must revalidate the cached file length */ | 707 | /* origin == SEEK_END => we must revalidate the cached file length */ |
551 | if (origin == SEEK_END) { | 708 | if (origin == SEEK_END) { |
552 | int retval; | 709 | int rc; |
553 | 710 | struct inode *inode = file->f_path.dentry->d_inode; | |
554 | /* some applications poll for the file length in this strange | 711 | |
555 | way so we must seek to end on non-oplocked files by | 712 | /* |
556 | setting the revalidate time to zero */ | 713 | * We need to be sure that all dirty pages are written and the |
557 | CIFS_I(file->f_path.dentry->d_inode)->time = 0; | 714 | * server has the newest file length. |
558 | 715 | */ | |
559 | retval = cifs_revalidate_file(file); | 716 | if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && |
560 | if (retval < 0) | 717 | inode->i_mapping->nrpages != 0) { |
561 | return (loff_t)retval; | 718 | rc = filemap_fdatawait(inode->i_mapping); |
719 | if (rc) { | ||
720 | mapping_set_error(inode->i_mapping, rc); | ||
721 | return rc; | ||
722 | } | ||
723 | } | ||
724 | /* | ||
725 | * Some applications poll for the file length in this strange | ||
726 | * way so we must seek to end on non-oplocked files by | ||
727 | * setting the revalidate time to zero. | ||
728 | */ | ||
729 | CIFS_I(inode)->time = 0; | ||
730 | |||
731 | rc = cifs_revalidate_file_attr(file); | ||
732 | if (rc < 0) | ||
733 | return (loff_t)rc; | ||
562 | } | 734 | } |
563 | return generic_file_llseek_unlocked(file, offset, origin); | 735 | return generic_file_llseek_unlocked(file, offset, origin); |
564 | } | 736 | } |
565 | 737 | ||
566 | static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) | 738 | static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) |
567 | { | 739 | { |
568 | /* note that this is called by vfs setlease with the BKL held | 740 | /* note that this is called by vfs setlease with lock_flocks held |
569 | although I doubt that BKL is needed here in cifs */ | 741 | to protect *lease from going away */ |
570 | struct inode *inode = file->f_path.dentry->d_inode; | 742 | struct inode *inode = file->f_path.dentry->d_inode; |
743 | struct cifsFileInfo *cfile = file->private_data; | ||
571 | 744 | ||
572 | if (!(S_ISREG(inode->i_mode))) | 745 | if (!(S_ISREG(inode->i_mode))) |
573 | return -EINVAL; | 746 | return -EINVAL; |
@@ -578,8 +751,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) | |||
578 | ((arg == F_WRLCK) && | 751 | ((arg == F_WRLCK) && |
579 | (CIFS_I(inode)->clientCanCacheAll))) | 752 | (CIFS_I(inode)->clientCanCacheAll))) |
580 | return generic_setlease(file, arg, lease); | 753 | return generic_setlease(file, arg, lease); |
581 | else if (CIFS_SB(inode->i_sb)->tcon->local_lease && | 754 | else if (tlink_tcon(cfile->tlink)->local_lease && |
582 | !CIFS_I(inode)->clientCanCacheRead) | 755 | !CIFS_I(inode)->clientCanCacheRead) |
583 | /* If the server claims to support oplock on this | 756 | /* If the server claims to support oplock on this |
584 | file, then we still need to check oplock even | 757 | file, then we still need to check oplock even |
585 | if the local_lease mount option is set, but there | 758 | if the local_lease mount option is set, but there |
@@ -595,8 +768,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) | |||
595 | struct file_system_type cifs_fs_type = { | 768 | struct file_system_type cifs_fs_type = { |
596 | .owner = THIS_MODULE, | 769 | .owner = THIS_MODULE, |
597 | .name = "cifs", | 770 | .name = "cifs", |
598 | .get_sb = cifs_get_sb, | 771 | .mount = cifs_do_mount, |
599 | .kill_sb = kill_anon_super, | 772 | .kill_sb = cifs_kill_sb, |
600 | /* .fs_flags */ | 773 | /* .fs_flags */ |
601 | }; | 774 | }; |
602 | const struct inode_operations cifs_dir_inode_ops = { | 775 | const struct inode_operations cifs_dir_inode_ops = { |
@@ -670,11 +843,31 @@ const struct file_operations cifs_file_ops = { | |||
670 | .setlease = cifs_setlease, | 843 | .setlease = cifs_setlease, |
671 | }; | 844 | }; |
672 | 845 | ||
846 | const struct file_operations cifs_file_strict_ops = { | ||
847 | .read = do_sync_read, | ||
848 | .write = do_sync_write, | ||
849 | .aio_read = cifs_strict_readv, | ||
850 | .aio_write = cifs_strict_writev, | ||
851 | .open = cifs_open, | ||
852 | .release = cifs_close, | ||
853 | .lock = cifs_lock, | ||
854 | .fsync = cifs_strict_fsync, | ||
855 | .flush = cifs_flush, | ||
856 | .mmap = cifs_file_strict_mmap, | ||
857 | .splice_read = generic_file_splice_read, | ||
858 | .llseek = cifs_llseek, | ||
859 | #ifdef CONFIG_CIFS_POSIX | ||
860 | .unlocked_ioctl = cifs_ioctl, | ||
861 | #endif /* CONFIG_CIFS_POSIX */ | ||
862 | .setlease = cifs_setlease, | ||
863 | }; | ||
864 | |||
673 | const struct file_operations cifs_file_direct_ops = { | 865 | const struct file_operations cifs_file_direct_ops = { |
674 | /* no aio, no readv - | 866 | /* BB reevaluate whether they can be done with directio, no cache */ |
675 | BB reevaluate whether they can be done with directio, no cache */ | 867 | .read = do_sync_read, |
676 | .read = cifs_user_read, | 868 | .write = do_sync_write, |
677 | .write = cifs_user_write, | 869 | .aio_read = cifs_user_readv, |
870 | .aio_write = cifs_user_writev, | ||
678 | .open = cifs_open, | 871 | .open = cifs_open, |
679 | .release = cifs_close, | 872 | .release = cifs_close, |
680 | .lock = cifs_lock, | 873 | .lock = cifs_lock, |
@@ -688,6 +881,7 @@ const struct file_operations cifs_file_direct_ops = { | |||
688 | .llseek = cifs_llseek, | 881 | .llseek = cifs_llseek, |
689 | .setlease = cifs_setlease, | 882 | .setlease = cifs_setlease, |
690 | }; | 883 | }; |
884 | |||
691 | const struct file_operations cifs_file_nobrl_ops = { | 885 | const struct file_operations cifs_file_nobrl_ops = { |
692 | .read = do_sync_read, | 886 | .read = do_sync_read, |
693 | .write = do_sync_write, | 887 | .write = do_sync_write, |
@@ -706,11 +900,30 @@ const struct file_operations cifs_file_nobrl_ops = { | |||
706 | .setlease = cifs_setlease, | 900 | .setlease = cifs_setlease, |
707 | }; | 901 | }; |
708 | 902 | ||
903 | const struct file_operations cifs_file_strict_nobrl_ops = { | ||
904 | .read = do_sync_read, | ||
905 | .write = do_sync_write, | ||
906 | .aio_read = cifs_strict_readv, | ||
907 | .aio_write = cifs_strict_writev, | ||
908 | .open = cifs_open, | ||
909 | .release = cifs_close, | ||
910 | .fsync = cifs_strict_fsync, | ||
911 | .flush = cifs_flush, | ||
912 | .mmap = cifs_file_strict_mmap, | ||
913 | .splice_read = generic_file_splice_read, | ||
914 | .llseek = cifs_llseek, | ||
915 | #ifdef CONFIG_CIFS_POSIX | ||
916 | .unlocked_ioctl = cifs_ioctl, | ||
917 | #endif /* CONFIG_CIFS_POSIX */ | ||
918 | .setlease = cifs_setlease, | ||
919 | }; | ||
920 | |||
709 | const struct file_operations cifs_file_direct_nobrl_ops = { | 921 | const struct file_operations cifs_file_direct_nobrl_ops = { |
710 | /* no mmap, no aio, no readv - | 922 | /* BB reevaluate whether they can be done with directio, no cache */ |
711 | BB reevaluate whether they can be done with directio, no cache */ | 923 | .read = do_sync_read, |
712 | .read = cifs_user_read, | 924 | .write = do_sync_write, |
713 | .write = cifs_user_write, | 925 | .aio_read = cifs_user_readv, |
926 | .aio_write = cifs_user_writev, | ||
714 | .open = cifs_open, | 927 | .open = cifs_open, |
715 | .release = cifs_close, | 928 | .release = cifs_close, |
716 | .fsync = cifs_fsync, | 929 | .fsync = cifs_fsync, |
@@ -873,10 +1086,10 @@ init_cifs(void) | |||
873 | int rc = 0; | 1086 | int rc = 0; |
874 | cifs_proc_init(); | 1087 | cifs_proc_init(); |
875 | INIT_LIST_HEAD(&cifs_tcp_ses_list); | 1088 | INIT_LIST_HEAD(&cifs_tcp_ses_list); |
876 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1089 | #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ |
877 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | 1090 | INIT_LIST_HEAD(&GlobalDnotifyReqList); |
878 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); | 1091 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); |
879 | #endif | 1092 | #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ |
880 | /* | 1093 | /* |
881 | * Initialize Global counters | 1094 | * Initialize Global counters |
882 | */ | 1095 | */ |
@@ -897,9 +1110,8 @@ init_cifs(void) | |||
897 | GlobalCurrentXid = 0; | 1110 | GlobalCurrentXid = 0; |
898 | GlobalTotalActiveXid = 0; | 1111 | GlobalTotalActiveXid = 0; |
899 | GlobalMaxActiveXid = 0; | 1112 | GlobalMaxActiveXid = 0; |
900 | memset(Local_System_Name, 0, 15); | 1113 | spin_lock_init(&cifs_tcp_ses_lock); |
901 | rwlock_init(&GlobalSMBSeslock); | 1114 | spin_lock_init(&cifs_file_list_lock); |
902 | rwlock_init(&cifs_tcp_ses_lock); | ||
903 | spin_lock_init(&GlobalMid_Lock); | 1115 | spin_lock_init(&GlobalMid_Lock); |
904 | 1116 | ||
905 | if (cifs_max_pending < 2) { | 1117 | if (cifs_max_pending < 2) { |
@@ -912,11 +1124,11 @@ init_cifs(void) | |||
912 | 1124 | ||
913 | rc = cifs_fscache_register(); | 1125 | rc = cifs_fscache_register(); |
914 | if (rc) | 1126 | if (rc) |
915 | goto out; | 1127 | goto out_clean_proc; |
916 | 1128 | ||
917 | rc = cifs_init_inodecache(); | 1129 | rc = cifs_init_inodecache(); |
918 | if (rc) | 1130 | if (rc) |
919 | goto out_clean_proc; | 1131 | goto out_unreg_fscache; |
920 | 1132 | ||
921 | rc = cifs_init_mids(); | 1133 | rc = cifs_init_mids(); |
922 | if (rc) | 1134 | if (rc) |
@@ -926,31 +1138,42 @@ init_cifs(void) | |||
926 | if (rc) | 1138 | if (rc) |
927 | goto out_destroy_mids; | 1139 | goto out_destroy_mids; |
928 | 1140 | ||
929 | rc = register_filesystem(&cifs_fs_type); | ||
930 | if (rc) | ||
931 | goto out_destroy_request_bufs; | ||
932 | #ifdef CONFIG_CIFS_UPCALL | 1141 | #ifdef CONFIG_CIFS_UPCALL |
933 | rc = register_key_type(&cifs_spnego_key_type); | 1142 | rc = register_key_type(&cifs_spnego_key_type); |
934 | if (rc) | 1143 | if (rc) |
935 | goto out_unregister_filesystem; | 1144 | goto out_destroy_request_bufs; |
936 | #endif | 1145 | #endif /* CONFIG_CIFS_UPCALL */ |
1146 | |||
1147 | #ifdef CONFIG_CIFS_ACL | ||
1148 | rc = init_cifs_idmap(); | ||
1149 | if (rc) | ||
1150 | goto out_register_key_type; | ||
1151 | #endif /* CONFIG_CIFS_ACL */ | ||
1152 | |||
1153 | rc = register_filesystem(&cifs_fs_type); | ||
1154 | if (rc) | ||
1155 | goto out_init_cifs_idmap; | ||
937 | 1156 | ||
938 | return 0; | 1157 | return 0; |
939 | 1158 | ||
1159 | out_init_cifs_idmap: | ||
1160 | #ifdef CONFIG_CIFS_ACL | ||
1161 | exit_cifs_idmap(); | ||
1162 | out_register_key_type: | ||
1163 | #endif | ||
940 | #ifdef CONFIG_CIFS_UPCALL | 1164 | #ifdef CONFIG_CIFS_UPCALL |
941 | out_unregister_filesystem: | 1165 | unregister_key_type(&cifs_spnego_key_type); |
942 | unregister_filesystem(&cifs_fs_type); | 1166 | out_destroy_request_bufs: |
943 | #endif | 1167 | #endif |
944 | out_destroy_request_bufs: | ||
945 | cifs_destroy_request_bufs(); | 1168 | cifs_destroy_request_bufs(); |
946 | out_destroy_mids: | 1169 | out_destroy_mids: |
947 | cifs_destroy_mids(); | 1170 | cifs_destroy_mids(); |
948 | out_destroy_inodecache: | 1171 | out_destroy_inodecache: |
949 | cifs_destroy_inodecache(); | 1172 | cifs_destroy_inodecache(); |
950 | out_clean_proc: | 1173 | out_unreg_fscache: |
951 | cifs_proc_clean(); | ||
952 | cifs_fscache_unregister(); | 1174 | cifs_fscache_unregister(); |
953 | out: | 1175 | out_clean_proc: |
1176 | cifs_proc_clean(); | ||
954 | return rc; | 1177 | return rc; |
955 | } | 1178 | } |
956 | 1179 | ||
@@ -963,6 +1186,10 @@ exit_cifs(void) | |||
963 | #ifdef CONFIG_CIFS_DFS_UPCALL | 1186 | #ifdef CONFIG_CIFS_DFS_UPCALL |
964 | cifs_dfs_release_automount_timer(); | 1187 | cifs_dfs_release_automount_timer(); |
965 | #endif | 1188 | #endif |
1189 | #ifdef CONFIG_CIFS_ACL | ||
1190 | cifs_destroy_idmaptrees(); | ||
1191 | exit_cifs_idmap(); | ||
1192 | #endif | ||
966 | #ifdef CONFIG_CIFS_UPCALL | 1193 | #ifdef CONFIG_CIFS_UPCALL |
967 | unregister_key_type(&cifs_spnego_key_type); | 1194 | unregister_key_type(&cifs_spnego_key_type); |
968 | #endif | 1195 | #endif |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d82f5fb4761e..036ca83e5f46 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -42,14 +42,12 @@ extern const struct address_space_operations cifs_addr_ops; | |||
42 | extern const struct address_space_operations cifs_addr_ops_smallbuf; | 42 | extern const struct address_space_operations cifs_addr_ops_smallbuf; |
43 | 43 | ||
44 | /* Functions related to super block operations */ | 44 | /* Functions related to super block operations */ |
45 | /* extern const struct super_operations cifs_super_ops;*/ | 45 | extern void cifs_sb_active(struct super_block *sb); |
46 | extern void cifs_read_inode(struct inode *); | 46 | extern void cifs_sb_deactive(struct super_block *sb); |
47 | /*extern void cifs_delete_inode(struct inode *);*/ /* BB not needed yet */ | ||
48 | /* extern void cifs_write_inode(struct inode *); */ /* BB not needed yet */ | ||
49 | 47 | ||
50 | /* Functions related to inodes */ | 48 | /* Functions related to inodes */ |
51 | extern const struct inode_operations cifs_dir_inode_ops; | 49 | extern const struct inode_operations cifs_dir_inode_ops; |
52 | extern struct inode *cifs_root_iget(struct super_block *, unsigned long); | 50 | extern struct inode *cifs_root_iget(struct super_block *); |
53 | extern int cifs_create(struct inode *, struct dentry *, int, | 51 | extern int cifs_create(struct inode *, struct dentry *, int, |
54 | struct nameidata *); | 52 | struct nameidata *); |
55 | extern struct dentry *cifs_lookup(struct inode *, struct dentry *, | 53 | extern struct dentry *cifs_lookup(struct inode *, struct dentry *, |
@@ -61,8 +59,11 @@ extern int cifs_mkdir(struct inode *, struct dentry *, int); | |||
61 | extern int cifs_rmdir(struct inode *, struct dentry *); | 59 | extern int cifs_rmdir(struct inode *, struct dentry *); |
62 | extern int cifs_rename(struct inode *, struct dentry *, struct inode *, | 60 | extern int cifs_rename(struct inode *, struct dentry *, struct inode *, |
63 | struct dentry *); | 61 | struct dentry *); |
62 | extern int cifs_revalidate_file_attr(struct file *filp); | ||
63 | extern int cifs_revalidate_dentry_attr(struct dentry *); | ||
64 | extern int cifs_revalidate_file(struct file *filp); | 64 | extern int cifs_revalidate_file(struct file *filp); |
65 | extern int cifs_revalidate_dentry(struct dentry *); | 65 | extern int cifs_revalidate_dentry(struct dentry *); |
66 | extern int cifs_invalidate_mapping(struct inode *inode); | ||
66 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 67 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
67 | extern int cifs_setattr(struct dentry *, struct iattr *); | 68 | extern int cifs_setattr(struct dentry *, struct iattr *); |
68 | 69 | ||
@@ -74,19 +75,27 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations; | |||
74 | /* Functions related to files and directories */ | 75 | /* Functions related to files and directories */ |
75 | extern const struct file_operations cifs_file_ops; | 76 | extern const struct file_operations cifs_file_ops; |
76 | extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ | 77 | extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ |
77 | extern const struct file_operations cifs_file_nobrl_ops; | 78 | extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */ |
78 | extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */ | 79 | extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */ |
80 | extern const struct file_operations cifs_file_direct_nobrl_ops; | ||
81 | extern const struct file_operations cifs_file_strict_nobrl_ops; | ||
79 | extern int cifs_open(struct inode *inode, struct file *file); | 82 | extern int cifs_open(struct inode *inode, struct file *file); |
80 | extern int cifs_close(struct inode *inode, struct file *file); | 83 | extern int cifs_close(struct inode *inode, struct file *file); |
81 | extern int cifs_closedir(struct inode *inode, struct file *file); | 84 | extern int cifs_closedir(struct inode *inode, struct file *file); |
82 | extern ssize_t cifs_user_read(struct file *file, char __user *read_data, | 85 | extern ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, |
83 | size_t read_size, loff_t *poffset); | 86 | unsigned long nr_segs, loff_t pos); |
84 | extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 87 | extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, |
85 | size_t write_size, loff_t *poffset); | 88 | unsigned long nr_segs, loff_t pos); |
89 | extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, | ||
90 | unsigned long nr_segs, loff_t pos); | ||
91 | extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | ||
92 | unsigned long nr_segs, loff_t pos); | ||
86 | extern int cifs_lock(struct file *, int, struct file_lock *); | 93 | extern int cifs_lock(struct file *, int, struct file_lock *); |
87 | extern int cifs_fsync(struct file *, int); | 94 | extern int cifs_fsync(struct file *, int); |
95 | extern int cifs_strict_fsync(struct file *, int); | ||
88 | extern int cifs_flush(struct file *, fl_owner_t id); | 96 | extern int cifs_flush(struct file *, fl_owner_t id); |
89 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); | 97 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); |
98 | extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); | ||
90 | extern const struct file_operations cifs_dir_ops; | 99 | extern const struct file_operations cifs_dir_ops; |
91 | extern int cifs_dir_open(struct inode *inode, struct file *file); | 100 | extern int cifs_dir_open(struct inode *inode, struct file *file); |
92 | extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); | 101 | extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); |
@@ -95,6 +104,12 @@ extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); | |||
95 | extern const struct dentry_operations cifs_dentry_ops; | 104 | extern const struct dentry_operations cifs_dentry_ops; |
96 | extern const struct dentry_operations cifs_ci_dentry_ops; | 105 | extern const struct dentry_operations cifs_ci_dentry_ops; |
97 | 106 | ||
107 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
108 | extern struct vfsmount *cifs_dfs_d_automount(struct path *path); | ||
109 | #else | ||
110 | #define cifs_dfs_d_automount NULL | ||
111 | #endif | ||
112 | |||
98 | /* Functions related to symlinks */ | 113 | /* Functions related to symlinks */ |
99 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); | 114 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); |
100 | extern void cifs_put_link(struct dentry *direntry, | 115 | extern void cifs_put_link(struct dentry *direntry, |
@@ -104,15 +119,15 @@ extern int cifs_readlink(struct dentry *direntry, char __user *buffer, | |||
104 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, | 119 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, |
105 | const char *symname); | 120 | const char *symname); |
106 | extern int cifs_removexattr(struct dentry *, const char *); | 121 | extern int cifs_removexattr(struct dentry *, const char *); |
107 | extern int cifs_setxattr(struct dentry *, const char *, const void *, | 122 | extern int cifs_setxattr(struct dentry *, const char *, const void *, |
108 | size_t, int); | 123 | size_t, int); |
109 | extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | 124 | extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); |
110 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 125 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
111 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | 126 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); |
112 | 127 | ||
113 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 128 | #ifdef CIFS_NFSD_EXPORT |
114 | extern const struct export_operations cifs_export_ops; | 129 | extern const struct export_operations cifs_export_ops; |
115 | #endif /* EXPERIMENTAL */ | 130 | #endif /* CIFS_NFSD_EXPORT */ |
116 | 131 | ||
117 | #define CIFS_VERSION "1.65" | 132 | #define CIFS_VERSION "1.74" |
118 | #endif /* _CIFSFS_H */ | 133 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0cdfb8c32ac6..6255fa812c7a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -25,6 +25,9 @@ | |||
25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
26 | #include "cifs_fs_sb.h" | 26 | #include "cifs_fs_sb.h" |
27 | #include "cifsacl.h" | 27 | #include "cifsacl.h" |
28 | #include <crypto/internal/hash.h> | ||
29 | #include <linux/scatterlist.h> | ||
30 | |||
28 | /* | 31 | /* |
29 | * The sizes of various internal tables and strings | 32 | * The sizes of various internal tables and strings |
30 | */ | 33 | */ |
@@ -34,14 +37,23 @@ | |||
34 | 37 | ||
35 | #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) | 38 | #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) |
36 | #define MAX_SERVER_SIZE 15 | 39 | #define MAX_SERVER_SIZE 15 |
37 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ | 40 | #define MAX_SHARE_SIZE 80 |
38 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | 41 | #define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ |
39 | termination then *2 for unicode versions */ | 42 | #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ |
40 | #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ | ||
41 | 43 | ||
42 | #define CIFS_MIN_RCV_POOL 4 | 44 | #define CIFS_MIN_RCV_POOL 4 |
43 | 45 | ||
44 | /* | 46 | /* |
47 | * default attribute cache timeout (jiffies) | ||
48 | */ | ||
49 | #define CIFS_DEF_ACTIMEO (1 * HZ) | ||
50 | |||
51 | /* | ||
52 | * max attribute cache timeout (jiffies) - 2^30 | ||
53 | */ | ||
54 | #define CIFS_MAX_ACTIMEO (1 << 30) | ||
55 | |||
56 | /* | ||
45 | * MAX_REQ is the maximum number of requests that WE will send | 57 | * MAX_REQ is the maximum number of requests that WE will send |
46 | * on one socket concurrently. It also matches the most common | 58 | * on one socket concurrently. It also matches the most common |
47 | * value of max multiplex returned by servers. We may | 59 | * value of max multiplex returned by servers. We may |
@@ -74,12 +86,13 @@ | |||
74 | * CIFS vfs client Status information (based on what we know.) | 86 | * CIFS vfs client Status information (based on what we know.) |
75 | */ | 87 | */ |
76 | 88 | ||
77 | /* associated with each tcp and smb session */ | 89 | /* associated with each tcp and smb session */ |
78 | enum statusEnum { | 90 | enum statusEnum { |
79 | CifsNew = 0, | 91 | CifsNew = 0, |
80 | CifsGood, | 92 | CifsGood, |
81 | CifsExiting, | 93 | CifsExiting, |
82 | CifsNeedReconnect | 94 | CifsNeedReconnect, |
95 | CifsNeedNegotiate | ||
83 | }; | 96 | }; |
84 | 97 | ||
85 | enum securityEnum { | 98 | enum securityEnum { |
@@ -97,16 +110,31 @@ enum protocolEnum { | |||
97 | /* Netbios frames protocol not supported at this time */ | 110 | /* Netbios frames protocol not supported at this time */ |
98 | }; | 111 | }; |
99 | 112 | ||
100 | struct mac_key { | 113 | struct session_key { |
101 | unsigned int len; | 114 | unsigned int len; |
102 | union { | 115 | char *response; |
103 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; | 116 | }; |
104 | char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */ | 117 | |
105 | struct { | 118 | /* crypto security descriptor definition */ |
106 | char key[16]; | 119 | struct sdesc { |
107 | struct ntlmv2_resp resp; | 120 | struct shash_desc shash; |
108 | } ntlmv2; | 121 | char ctx[]; |
109 | } data; | 122 | }; |
123 | |||
124 | /* crypto hashing related structure/fields, not specific to a sec mech */ | ||
125 | struct cifs_secmech { | ||
126 | struct crypto_shash *hmacmd5; /* hmac-md5 hash function */ | ||
127 | struct crypto_shash *md5; /* md5 hash function */ | ||
128 | struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */ | ||
129 | struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */ | ||
130 | }; | ||
131 | |||
132 | /* per smb session structure/fields */ | ||
133 | struct ntlmssp_auth { | ||
134 | __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */ | ||
135 | __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */ | ||
136 | unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */ | ||
137 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlmssp */ | ||
110 | }; | 138 | }; |
111 | 139 | ||
112 | struct cifs_cred { | 140 | struct cifs_cred { |
@@ -127,79 +155,181 @@ struct cifs_cred { | |||
127 | ***************************************************************** | 155 | ***************************************************************** |
128 | */ | 156 | */ |
129 | 157 | ||
158 | struct smb_vol { | ||
159 | char *username; | ||
160 | char *password; | ||
161 | char *domainname; | ||
162 | char *UNC; | ||
163 | char *UNCip; | ||
164 | char *iocharset; /* local code page for mapping to and from Unicode */ | ||
165 | char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ | ||
166 | char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ | ||
167 | uid_t cred_uid; | ||
168 | uid_t linux_uid; | ||
169 | gid_t linux_gid; | ||
170 | mode_t file_mode; | ||
171 | mode_t dir_mode; | ||
172 | unsigned secFlg; | ||
173 | bool retry:1; | ||
174 | bool intr:1; | ||
175 | bool setuids:1; | ||
176 | bool override_uid:1; | ||
177 | bool override_gid:1; | ||
178 | bool dynperm:1; | ||
179 | bool noperm:1; | ||
180 | bool no_psx_acl:1; /* set if posix acl support should be disabled */ | ||
181 | bool cifs_acl:1; | ||
182 | bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ | ||
183 | bool server_ino:1; /* use inode numbers from server ie UniqueId */ | ||
184 | bool direct_io:1; | ||
185 | bool strict_io:1; /* strict cache behavior */ | ||
186 | bool remap:1; /* set to remap seven reserved chars in filenames */ | ||
187 | bool posix_paths:1; /* unset to not ask for posix pathnames. */ | ||
188 | bool no_linux_ext:1; | ||
189 | bool sfu_emul:1; | ||
190 | bool nullauth:1; /* attempt to authenticate with null user */ | ||
191 | bool nocase:1; /* request case insensitive filenames */ | ||
192 | bool nobrl:1; /* disable sending byte range locks to srv */ | ||
193 | bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ | ||
194 | bool seal:1; /* request transport encryption on share */ | ||
195 | bool nodfs:1; /* Do not request DFS, even if available */ | ||
196 | bool local_lease:1; /* check leases only on local system, not remote */ | ||
197 | bool noblocksnd:1; | ||
198 | bool noautotune:1; | ||
199 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | ||
200 | bool fsc:1; /* enable fscache */ | ||
201 | bool mfsymlinks:1; /* use Minshall+French Symlinks */ | ||
202 | bool multiuser:1; | ||
203 | bool rwpidforward:1; /* pid forward for read/write operations */ | ||
204 | unsigned int rsize; | ||
205 | unsigned int wsize; | ||
206 | bool sockopt_tcp_nodelay:1; | ||
207 | unsigned short int port; | ||
208 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | ||
209 | char *prepath; | ||
210 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | ||
211 | struct nls_table *local_nls; | ||
212 | }; | ||
213 | |||
214 | #define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \ | ||
215 | CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \ | ||
216 | CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \ | ||
217 | CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \ | ||
218 | CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \ | ||
219 | CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \ | ||
220 | CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \ | ||
221 | CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \ | ||
222 | CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO) | ||
223 | |||
224 | #define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \ | ||
225 | MS_NODEV | MS_SYNCHRONOUS) | ||
226 | |||
227 | struct cifs_mnt_data { | ||
228 | struct cifs_sb_info *cifs_sb; | ||
229 | struct smb_vol *vol; | ||
230 | int flags; | ||
231 | }; | ||
232 | |||
130 | struct TCP_Server_Info { | 233 | struct TCP_Server_Info { |
131 | struct list_head tcp_ses_list; | 234 | struct list_head tcp_ses_list; |
132 | struct list_head smb_ses_list; | 235 | struct list_head smb_ses_list; |
133 | int srv_count; /* reference counter */ | 236 | int srv_count; /* reference counter */ |
134 | /* 15 character server name + 0x20 16th byte indicating type = srv */ | 237 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
135 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 238 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
239 | enum statusEnum tcpStatus; /* what we think the status is */ | ||
136 | char *hostname; /* hostname portion of UNC string */ | 240 | char *hostname; /* hostname portion of UNC string */ |
137 | struct socket *ssocket; | 241 | struct socket *ssocket; |
138 | union { | 242 | struct sockaddr_storage dstaddr; |
139 | struct sockaddr_in sockAddr; | 243 | struct sockaddr_storage srcaddr; /* locally bind to this IP */ |
140 | struct sockaddr_in6 sockAddr6; | 244 | #ifdef CONFIG_NET_NS |
141 | } addr; | 245 | struct net *net; |
246 | #endif | ||
142 | wait_queue_head_t response_q; | 247 | wait_queue_head_t response_q; |
143 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ | 248 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ |
144 | struct list_head pending_mid_q; | 249 | struct list_head pending_mid_q; |
145 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | ||
146 | unsigned short server_codepage; /* codepage for the server */ | ||
147 | enum protocolEnum protocolType; | ||
148 | char versionMajor; | ||
149 | char versionMinor; | ||
150 | bool svlocal:1; /* local server or remote */ | ||
151 | bool noblocksnd; /* use blocking sendmsg */ | 250 | bool noblocksnd; /* use blocking sendmsg */ |
152 | bool noautotune; /* do not autotune send buf sizes */ | 251 | bool noautotune; /* do not autotune send buf sizes */ |
153 | bool tcp_nodelay; | 252 | bool tcp_nodelay; |
154 | atomic_t inFlight; /* number of requests on the wire to server */ | 253 | atomic_t inFlight; /* number of requests on the wire to server */ |
155 | #ifdef CONFIG_CIFS_STATS2 | ||
156 | atomic_t inSend; /* requests trying to send */ | ||
157 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
158 | #endif | ||
159 | enum statusEnum tcpStatus; /* what we think the status is */ | ||
160 | struct mutex srv_mutex; | 254 | struct mutex srv_mutex; |
161 | struct task_struct *tsk; | 255 | struct task_struct *tsk; |
162 | char server_GUID[16]; | 256 | char server_GUID[16]; |
163 | char secMode; | 257 | char sec_mode; |
258 | bool session_estab; /* mark when very first sess is established */ | ||
259 | u16 dialect; /* dialect index that server chose */ | ||
164 | enum securityEnum secType; | 260 | enum securityEnum secType; |
165 | unsigned int maxReq; /* Clients should submit no more */ | 261 | unsigned int maxReq; /* Clients should submit no more */ |
166 | /* than maxReq distinct unanswered SMBs to the server when using */ | 262 | /* than maxReq distinct unanswered SMBs to the server when using */ |
167 | /* multiplexed reads or writes */ | 263 | /* multiplexed reads or writes */ |
168 | unsigned int maxBuf; /* maxBuf specifies the maximum */ | 264 | unsigned int maxBuf; /* maxBuf specifies the maximum */ |
169 | /* message size the server can send or receive for non-raw SMBs */ | 265 | /* message size the server can send or receive for non-raw SMBs */ |
266 | /* maxBuf is returned by SMB NegotiateProtocol so maxBuf is only 0 */ | ||
267 | /* when socket is setup (and during reconnect) before NegProt sent */ | ||
170 | unsigned int max_rw; /* maxRw specifies the maximum */ | 268 | unsigned int max_rw; /* maxRw specifies the maximum */ |
171 | /* message size the server can send or receive for */ | 269 | /* message size the server can send or receive for */ |
172 | /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ | 270 | /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ |
173 | unsigned int max_vcs; /* maximum number of smb sessions, at least | 271 | unsigned int max_vcs; /* maximum number of smb sessions, at least |
174 | those that can be specified uniquely with | 272 | those that can be specified uniquely with |
175 | vcnumbers */ | 273 | vcnumbers */ |
176 | char sessid[4]; /* unique token id for this session */ | ||
177 | /* (returned on Negotiate */ | ||
178 | int capabilities; /* allow selective disabling of caps by smb sess */ | 274 | int capabilities; /* allow selective disabling of caps by smb sess */ |
179 | int timeAdj; /* Adjust for difference in server time zone in sec */ | 275 | int timeAdj; /* Adjust for difference in server time zone in sec */ |
180 | __u16 CurrentMid; /* multiplex id - rotating counter */ | 276 | __u16 CurrentMid; /* multiplex id - rotating counter */ |
181 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | 277 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ |
182 | /* 16th byte of RFC1001 workstation name is always null */ | 278 | /* 16th byte of RFC1001 workstation name is always null */ |
183 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 279 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
184 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 280 | __u32 sequence_number; /* for signing, protected by srv_mutex */ |
185 | struct mac_key mac_signing_key; | 281 | struct session_key session_key; |
186 | char ntlmv2_hash[16]; | ||
187 | unsigned long lstrp; /* when we got last response from this server */ | 282 | unsigned long lstrp; /* when we got last response from this server */ |
188 | u16 dialect; /* dialect index that server chose */ | 283 | struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ |
189 | /* extended security flavors that server supports */ | 284 | /* extended security flavors that server supports */ |
285 | bool sec_ntlmssp; /* supports NTLMSSP */ | ||
286 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | ||
190 | bool sec_kerberos; /* supports plain Kerberos */ | 287 | bool sec_kerberos; /* supports plain Kerberos */ |
191 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 288 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
192 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 289 | struct delayed_work echo; /* echo ping workqueue job */ |
193 | bool sec_ntlmssp; /* supports NTLMSSP */ | ||
194 | #ifdef CONFIG_CIFS_FSCACHE | 290 | #ifdef CONFIG_CIFS_FSCACHE |
195 | struct fscache_cookie *fscache; /* client index cache cookie */ | 291 | struct fscache_cookie *fscache; /* client index cache cookie */ |
196 | #endif | 292 | #endif |
293 | #ifdef CONFIG_CIFS_STATS2 | ||
294 | atomic_t inSend; /* requests trying to send */ | ||
295 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
296 | #endif | ||
197 | }; | 297 | }; |
198 | 298 | ||
199 | /* | 299 | /* |
300 | * Macros to allow the TCP_Server_Info->net field and related code to drop out | ||
301 | * when CONFIG_NET_NS isn't set. | ||
302 | */ | ||
303 | |||
304 | #ifdef CONFIG_NET_NS | ||
305 | |||
306 | static inline struct net *cifs_net_ns(struct TCP_Server_Info *srv) | ||
307 | { | ||
308 | return srv->net; | ||
309 | } | ||
310 | |||
311 | static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net) | ||
312 | { | ||
313 | srv->net = net; | ||
314 | } | ||
315 | |||
316 | #else | ||
317 | |||
318 | static inline struct net *cifs_net_ns(struct TCP_Server_Info *srv) | ||
319 | { | ||
320 | return &init_net; | ||
321 | } | ||
322 | |||
323 | static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net) | ||
324 | { | ||
325 | } | ||
326 | |||
327 | #endif | ||
328 | |||
329 | /* | ||
200 | * Session structure. One of these for each uid session with a particular host | 330 | * Session structure. One of these for each uid session with a particular host |
201 | */ | 331 | */ |
202 | struct cifsSesInfo { | 332 | struct cifs_ses { |
203 | struct list_head smb_ses_list; | 333 | struct list_head smb_ses_list; |
204 | struct list_head tcon_list; | 334 | struct list_head tcon_list; |
205 | struct mutex session_mutex; | 335 | struct mutex session_mutex; |
@@ -219,9 +349,12 @@ struct cifsSesInfo { | |||
219 | int capabilities; | 349 | int capabilities; |
220 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 350 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for |
221 | TCP names - will ipv6 and sctp addresses fit? */ | 351 | TCP names - will ipv6 and sctp addresses fit? */ |
222 | char userName[MAX_USERNAME_SIZE + 1]; | 352 | char *user_name; /* must not be null except during init of sess |
353 | and after mount option parsing we fill it */ | ||
223 | char *domainName; | 354 | char *domainName; |
224 | char *password; | 355 | char *password; |
356 | struct session_key auth_key; | ||
357 | struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */ | ||
225 | bool need_reconnect:1; /* connection reset, uid now invalid */ | 358 | bool need_reconnect:1; /* connection reset, uid now invalid */ |
226 | }; | 359 | }; |
227 | /* no more than one of the following three session flags may be set */ | 360 | /* no more than one of the following three session flags may be set */ |
@@ -236,11 +369,11 @@ struct cifsSesInfo { | |||
236 | * there is one of these for each connection to a resource on a particular | 369 | * there is one of these for each connection to a resource on a particular |
237 | * session | 370 | * session |
238 | */ | 371 | */ |
239 | struct cifsTconInfo { | 372 | struct cifs_tcon { |
240 | struct list_head tcon_list; | 373 | struct list_head tcon_list; |
241 | int tc_count; | 374 | int tc_count; |
242 | struct list_head openFileList; | 375 | struct list_head openFileList; |
243 | struct cifsSesInfo *ses; /* pointer to session associated with */ | 376 | struct cifs_ses *ses; /* pointer to session associated with */ |
244 | char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ | 377 | char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ |
245 | char *nativeFileSystem; | 378 | char *nativeFileSystem; |
246 | char *password; /* for share-level security */ | 379 | char *password; /* for share-level security */ |
@@ -308,6 +441,45 @@ struct cifsTconInfo { | |||
308 | }; | 441 | }; |
309 | 442 | ||
310 | /* | 443 | /* |
444 | * This is a refcounted and timestamped container for a tcon pointer. The | ||
445 | * container holds a tcon reference. It is considered safe to free one of | ||
446 | * these when the tl_count goes to 0. The tl_time is the time of the last | ||
447 | * "get" on the container. | ||
448 | */ | ||
449 | struct tcon_link { | ||
450 | struct rb_node tl_rbnode; | ||
451 | uid_t tl_uid; | ||
452 | unsigned long tl_flags; | ||
453 | #define TCON_LINK_MASTER 0 | ||
454 | #define TCON_LINK_PENDING 1 | ||
455 | #define TCON_LINK_IN_TREE 2 | ||
456 | unsigned long tl_time; | ||
457 | atomic_t tl_count; | ||
458 | struct cifs_tcon *tl_tcon; | ||
459 | }; | ||
460 | |||
461 | extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb); | ||
462 | |||
463 | static inline struct cifs_tcon * | ||
464 | tlink_tcon(struct tcon_link *tlink) | ||
465 | { | ||
466 | return tlink->tl_tcon; | ||
467 | } | ||
468 | |||
469 | extern void cifs_put_tlink(struct tcon_link *tlink); | ||
470 | |||
471 | static inline struct tcon_link * | ||
472 | cifs_get_tlink(struct tcon_link *tlink) | ||
473 | { | ||
474 | if (tlink && !IS_ERR(tlink)) | ||
475 | atomic_inc(&tlink->tl_count); | ||
476 | return tlink; | ||
477 | } | ||
478 | |||
479 | /* This function is always expected to succeed */ | ||
480 | extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb); | ||
481 | |||
482 | /* | ||
311 | * This info hangs off the cifsFileInfo structure, pointed to by llist. | 483 | * This info hangs off the cifsFileInfo structure, pointed to by llist. |
312 | * This is used to track byte stream locks on the file | 484 | * This is used to track byte stream locks on the file |
313 | */ | 485 | */ |
@@ -345,34 +517,37 @@ struct cifsFileInfo { | |||
345 | __u16 netfid; /* file id from remote */ | 517 | __u16 netfid; /* file id from remote */ |
346 | /* BB add lock scope info here if needed */ ; | 518 | /* BB add lock scope info here if needed */ ; |
347 | /* lock scope id (0 if none) */ | 519 | /* lock scope id (0 if none) */ |
348 | struct file *pfile; /* needed for writepage */ | 520 | struct dentry *dentry; |
349 | struct inode *pInode; /* needed for oplock break */ | 521 | unsigned int f_flags; |
350 | struct vfsmount *mnt; | 522 | struct tcon_link *tlink; |
351 | struct mutex lock_mutex; | 523 | struct mutex lock_mutex; |
352 | struct list_head llist; /* list of byte range locks we have. */ | 524 | struct list_head llist; /* list of byte range locks we have. */ |
353 | bool closePend:1; /* file is marked to close */ | ||
354 | bool invalidHandle:1; /* file closed via session abend */ | 525 | bool invalidHandle:1; /* file closed via session abend */ |
355 | bool oplock_break_cancelled:1; | 526 | bool oplock_break_cancelled:1; |
356 | atomic_t count; /* reference count */ | 527 | int count; /* refcount protected by cifs_file_list_lock */ |
357 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 528 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
358 | struct cifs_search_info srch_inf; | 529 | struct cifs_search_info srch_inf; |
359 | struct work_struct oplock_break; /* work for oplock breaks */ | 530 | struct work_struct oplock_break; /* work for oplock breaks */ |
360 | }; | 531 | }; |
361 | 532 | ||
362 | /* Take a reference on the file private data */ | 533 | struct cifs_io_parms { |
534 | __u16 netfid; | ||
535 | __u32 pid; | ||
536 | __u64 offset; | ||
537 | unsigned int length; | ||
538 | struct cifs_tcon *tcon; | ||
539 | }; | ||
540 | |||
541 | /* | ||
542 | * Take a reference on the file private data. Must be called with | ||
543 | * cifs_file_list_lock held. | ||
544 | */ | ||
363 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) | 545 | static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) |
364 | { | 546 | { |
365 | atomic_inc(&cifs_file->count); | 547 | ++cifs_file->count; |
366 | } | 548 | } |
367 | 549 | ||
368 | /* Release a reference on the file private data */ | 550 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file); |
369 | static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | ||
370 | { | ||
371 | if (atomic_dec_and_test(&cifs_file->count)) { | ||
372 | iput(cifs_file->pInode); | ||
373 | kfree(cifs_file); | ||
374 | } | ||
375 | } | ||
376 | 551 | ||
377 | /* | 552 | /* |
378 | * One of these for each file inode | 553 | * One of these for each file inode |
@@ -382,15 +557,15 @@ struct cifsInodeInfo { | |||
382 | struct list_head lockList; | 557 | struct list_head lockList; |
383 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ | 558 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ |
384 | struct list_head openFileList; | 559 | struct list_head openFileList; |
385 | int write_behind_rc; | ||
386 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 560 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
387 | unsigned long time; /* jiffies of last update/check of inode */ | 561 | bool clientCanCacheRead; /* read oplock */ |
388 | bool clientCanCacheRead:1; /* read oplock */ | 562 | bool clientCanCacheAll; /* read and writebehind oplock */ |
389 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 563 | bool delete_pending; /* DELETE_ON_CLOSE is set */ |
390 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | 564 | bool invalid_mapping; /* pagecache is invalid */ |
391 | bool invalid_mapping:1; /* pagecache is invalid */ | 565 | unsigned long time; /* jiffies of last update of inode */ |
392 | u64 server_eof; /* current file size on server */ | 566 | u64 server_eof; /* current file size on server */ |
393 | u64 uniqueid; /* server inode number */ | 567 | u64 uniqueid; /* server inode number */ |
568 | u64 createtime; /* creation time on server */ | ||
394 | #ifdef CONFIG_CIFS_FSCACHE | 569 | #ifdef CONFIG_CIFS_FSCACHE |
395 | struct fscache_cookie *fscache; | 570 | struct fscache_cookie *fscache; |
396 | #endif | 571 | #endif |
@@ -417,10 +592,30 @@ static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) | |||
417 | return '\\'; | 592 | return '\\'; |
418 | } | 593 | } |
419 | 594 | ||
595 | static inline void | ||
596 | convert_delimiter(char *path, char delim) | ||
597 | { | ||
598 | int i; | ||
599 | char old_delim; | ||
600 | |||
601 | if (path == NULL) | ||
602 | return; | ||
603 | |||
604 | if (delim == '/') | ||
605 | old_delim = '\\'; | ||
606 | else | ||
607 | old_delim = '/'; | ||
608 | |||
609 | for (i = 0; path[i] != '\0'; i++) { | ||
610 | if (path[i] == old_delim) | ||
611 | path[i] = delim; | ||
612 | } | ||
613 | } | ||
614 | |||
420 | #ifdef CONFIG_CIFS_STATS | 615 | #ifdef CONFIG_CIFS_STATS |
421 | #define cifs_stats_inc atomic_inc | 616 | #define cifs_stats_inc atomic_inc |
422 | 617 | ||
423 | static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon, | 618 | static inline void cifs_stats_bytes_written(struct cifs_tcon *tcon, |
424 | unsigned int bytes) | 619 | unsigned int bytes) |
425 | { | 620 | { |
426 | if (bytes) { | 621 | if (bytes) { |
@@ -430,7 +625,7 @@ static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon, | |||
430 | } | 625 | } |
431 | } | 626 | } |
432 | 627 | ||
433 | static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | 628 | static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon, |
434 | unsigned int bytes) | 629 | unsigned int bytes) |
435 | { | 630 | { |
436 | spin_lock(&tcon->stat_lock); | 631 | spin_lock(&tcon->stat_lock); |
@@ -445,6 +640,17 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | |||
445 | 640 | ||
446 | #endif | 641 | #endif |
447 | 642 | ||
643 | struct mid_q_entry; | ||
644 | |||
645 | /* | ||
646 | * This is the prototype for the mid callback function. When creating one, | ||
647 | * take special care to avoid deadlocks. Things to bear in mind: | ||
648 | * | ||
649 | * - it will be called by cifsd, with no locks held | ||
650 | * - the mid will be removed from any lists | ||
651 | */ | ||
652 | typedef void (mid_callback_t)(struct mid_q_entry *mid); | ||
653 | |||
448 | /* one of these for every pending CIFS request to the server */ | 654 | /* one of these for every pending CIFS request to the server */ |
449 | struct mid_q_entry { | 655 | struct mid_q_entry { |
450 | struct list_head qhead; /* mids waiting on reply from this server */ | 656 | struct list_head qhead; /* mids waiting on reply from this server */ |
@@ -456,7 +662,8 @@ struct mid_q_entry { | |||
456 | unsigned long when_sent; /* time when smb send finished */ | 662 | unsigned long when_sent; /* time when smb send finished */ |
457 | unsigned long when_received; /* when demux complete (taken off wire) */ | 663 | unsigned long when_received; /* when demux complete (taken off wire) */ |
458 | #endif | 664 | #endif |
459 | struct task_struct *tsk; /* task waiting for response */ | 665 | mid_callback_t *callback; /* call completion callback */ |
666 | void *callback_data; /* general purpose pointer for callback */ | ||
460 | struct smb_hdr *resp_buf; /* response buffer */ | 667 | struct smb_hdr *resp_buf; /* response buffer */ |
461 | int midState; /* wish this were enum but can not pass to wait_event */ | 668 | int midState; /* wish this were enum but can not pass to wait_event */ |
462 | __u8 command; /* smb command code */ | 669 | __u8 command; /* smb command code */ |
@@ -468,22 +675,22 @@ struct mid_q_entry { | |||
468 | struct oplock_q_entry { | 675 | struct oplock_q_entry { |
469 | struct list_head qhead; | 676 | struct list_head qhead; |
470 | struct inode *pinode; | 677 | struct inode *pinode; |
471 | struct cifsTconInfo *tcon; | 678 | struct cifs_tcon *tcon; |
472 | __u16 netfid; | 679 | __u16 netfid; |
473 | }; | 680 | }; |
474 | 681 | ||
475 | /* for pending dnotify requests */ | 682 | /* for pending dnotify requests */ |
476 | struct dir_notify_req { | 683 | struct dir_notify_req { |
477 | struct list_head lhead; | 684 | struct list_head lhead; |
478 | __le16 Pid; | 685 | __le16 Pid; |
479 | __le16 PidHigh; | 686 | __le16 PidHigh; |
480 | __u16 Mid; | 687 | __u16 Mid; |
481 | __u16 Tid; | 688 | __u16 Tid; |
482 | __u16 Uid; | 689 | __u16 Uid; |
483 | __u16 netfid; | 690 | __u16 netfid; |
484 | __u32 filter; /* CompletionFilter (for multishot) */ | 691 | __u32 filter; /* CompletionFilter (for multishot) */ |
485 | int multishot; | 692 | int multishot; |
486 | struct file *pfile; | 693 | struct file *pfile; |
487 | }; | 694 | }; |
488 | 695 | ||
489 | struct dfs_info3_param { | 696 | struct dfs_info3_param { |
@@ -511,6 +718,7 @@ struct cifs_fattr { | |||
511 | u64 cf_uniqueid; | 718 | u64 cf_uniqueid; |
512 | u64 cf_eof; | 719 | u64 cf_eof; |
513 | u64 cf_bytes; | 720 | u64 cf_bytes; |
721 | u64 cf_createtime; | ||
514 | uid_t cf_uid; | 722 | uid_t cf_uid; |
515 | gid_t cf_gid; | 723 | gid_t cf_gid; |
516 | umode_t cf_mode; | 724 | umode_t cf_mode; |
@@ -549,7 +757,8 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
549 | #define MID_REQUEST_SUBMITTED 2 | 757 | #define MID_REQUEST_SUBMITTED 2 |
550 | #define MID_RESPONSE_RECEIVED 4 | 758 | #define MID_RESPONSE_RECEIVED 4 |
551 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ | 759 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ |
552 | #define MID_NO_RESP_NEEDED 0x10 | 760 | #define MID_RESPONSE_MALFORMED 0x10 |
761 | #define MID_SHUTDOWN 0x20 | ||
553 | 762 | ||
554 | /* Types of response buffer returned from SendReceive2 */ | 763 | /* Types of response buffer returned from SendReceive2 */ |
555 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ | 764 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ |
@@ -558,12 +767,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
558 | #define CIFS_IOVEC 4 /* array of response buffers */ | 767 | #define CIFS_IOVEC 4 /* array of response buffers */ |
559 | 768 | ||
560 | /* Type of Request to SendReceive2 */ | 769 | /* Type of Request to SendReceive2 */ |
561 | #define CIFS_STD_OP 0 /* normal request timeout */ | 770 | #define CIFS_BLOCKING_OP 1 /* operation can block */ |
562 | #define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ | 771 | #define CIFS_ASYNC_OP 2 /* do not wait for response */ |
563 | #define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ | 772 | #define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */ |
564 | #define CIFS_BLOCKING_OP 4 /* operation can block */ | ||
565 | #define CIFS_ASYNC_OP 8 /* do not wait for response */ | ||
566 | #define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */ | ||
567 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ | 773 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ |
568 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ | 774 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ |
569 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ | 775 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ |
@@ -633,7 +839,7 @@ require use of the stronger protocol */ | |||
633 | * GlobalMid_Lock protects: | 839 | * GlobalMid_Lock protects: |
634 | * list operations on pending_mid_q and oplockQ | 840 | * list operations on pending_mid_q and oplockQ |
635 | * updates to XID counters, multiplex id and SMB sequence numbers | 841 | * updates to XID counters, multiplex id and SMB sequence numbers |
636 | * GlobalSMBSesLock protects: | 842 | * cifs_file_list_lock protects: |
637 | * list operations on tcp and SMB session lists and tCon lists | 843 | * list operations on tcp and SMB session lists and tCon lists |
638 | * f_owner.lock protects certain per file struct operations | 844 | * f_owner.lock protects certain per file struct operations |
639 | * mapping->page_lock protects certain per page operations | 845 | * mapping->page_lock protects certain per page operations |
@@ -667,7 +873,7 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; | |||
667 | * the reference counters for the server, smb session, and tcon. Finally, | 873 | * the reference counters for the server, smb session, and tcon. Finally, |
668 | * changes to the tcon->tidStatus should be done while holding this lock. | 874 | * changes to the tcon->tidStatus should be done while holding this lock. |
669 | */ | 875 | */ |
670 | GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; | 876 | GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock; |
671 | 877 | ||
672 | /* | 878 | /* |
673 | * This lock protects the cifs_file->llist and cifs_file->flist | 879 | * This lock protects the cifs_file->llist and cifs_file->flist |
@@ -676,12 +882,14 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; | |||
676 | * If cifs_tcp_ses_lock and the lock below are both needed to be held, then | 882 | * If cifs_tcp_ses_lock and the lock below are both needed to be held, then |
677 | * the cifs_tcp_ses_lock must be grabbed first and released last. | 883 | * the cifs_tcp_ses_lock must be grabbed first and released last. |
678 | */ | 884 | */ |
679 | GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; | 885 | GLOBAL_EXTERN spinlock_t cifs_file_list_lock; |
680 | 886 | ||
887 | #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ | ||
681 | /* Outstanding dir notify requests */ | 888 | /* Outstanding dir notify requests */ |
682 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; | 889 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; |
683 | /* DirNotify response queue */ | 890 | /* DirNotify response queue */ |
684 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; | 891 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; |
892 | #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ | ||
685 | 893 | ||
686 | /* | 894 | /* |
687 | * Global transaction id (XID) information | 895 | * Global transaction id (XID) information |
@@ -691,8 +899,6 @@ GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ | |||
691 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ | 899 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ |
692 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ | 900 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ |
693 | /* on midQ entries */ | 901 | /* on midQ entries */ |
694 | GLOBAL_EXTERN char Local_System_Name[15]; | ||
695 | |||
696 | /* | 902 | /* |
697 | * Global counters, updated atomically | 903 | * Global counters, updated atomically |
698 | */ | 904 | */ |
@@ -717,7 +923,6 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions | |||
717 | have the uid/password or Kerberos credential | 923 | have the uid/password or Kerberos credential |
718 | or equivalent for current user */ | 924 | or equivalent for current user */ |
719 | GLOBAL_EXTERN unsigned int oplockEnabled; | 925 | GLOBAL_EXTERN unsigned int oplockEnabled; |
720 | GLOBAL_EXTERN unsigned int experimEnabled; | ||
721 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; | 926 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; |
722 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent | 927 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent |
723 | with more secure ntlmssp2 challenge/resp */ | 928 | with more secure ntlmssp2 challenge/resp */ |
@@ -728,6 +933,14 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
728 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 933 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
729 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 934 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
730 | 935 | ||
936 | /* reconnect after this many failed echo attempts */ | ||
937 | GLOBAL_EXTERN unsigned short echo_retries; | ||
938 | |||
939 | GLOBAL_EXTERN struct rb_root uidtree; | ||
940 | GLOBAL_EXTERN struct rb_root gidtree; | ||
941 | GLOBAL_EXTERN spinlock_t siduidlock; | ||
942 | GLOBAL_EXTERN spinlock_t sidgidlock; | ||
943 | |||
731 | void cifs_oplock_break(struct work_struct *work); | 944 | void cifs_oplock_break(struct work_struct *work); |
732 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); | 945 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); |
733 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); | 946 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 14d036d8db11..de3aa285de03 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #define _CIFSPDU_H | 23 | #define _CIFSPDU_H |
24 | 24 | ||
25 | #include <net/sock.h> | 25 | #include <net/sock.h> |
26 | #include <asm/unaligned.h> | ||
26 | #include "smbfsctl.h" | 27 | #include "smbfsctl.h" |
27 | 28 | ||
28 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 29 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
@@ -50,6 +51,7 @@ | |||
50 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | 51 | #define SMB_COM_SETATTR 0x09 /* trivial response */ |
51 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | 52 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ |
52 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | 53 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ |
54 | #define SMB_COM_ECHO 0x2B /* echo request */ | ||
53 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ | 55 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ |
54 | #define SMB_COM_READ_ANDX 0x2E | 56 | #define SMB_COM_READ_ANDX 0x2E |
55 | #define SMB_COM_WRITE_ANDX 0x2F | 57 | #define SMB_COM_WRITE_ANDX 0x2F |
@@ -131,9 +133,20 @@ | |||
131 | #define CIFS_CRYPTO_KEY_SIZE (8) | 133 | #define CIFS_CRYPTO_KEY_SIZE (8) |
132 | 134 | ||
133 | /* | 135 | /* |
136 | * Size of the ntlm client response | ||
137 | */ | ||
138 | #define CIFS_AUTH_RESP_SIZE (24) | ||
139 | |||
140 | /* | ||
134 | * Size of the session key (crypto key encrypted with the password | 141 | * Size of the session key (crypto key encrypted with the password |
135 | */ | 142 | */ |
136 | #define CIFS_SESS_KEY_SIZE (24) | 143 | #define CIFS_SESS_KEY_SIZE (16) |
144 | |||
145 | #define CIFS_CLIENT_CHALLENGE_SIZE (8) | ||
146 | #define CIFS_SERVER_CHALLENGE_SIZE (8) | ||
147 | #define CIFS_HMAC_MD5_HASH_SIZE (16) | ||
148 | #define CIFS_CPHTXT_SIZE (16) | ||
149 | #define CIFS_NTHASH_SIZE (16) | ||
137 | 150 | ||
138 | /* | 151 | /* |
139 | * Maximum user name length | 152 | * Maximum user name length |
@@ -384,9 +397,9 @@ | |||
384 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ | 397 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ |
385 | 398 | ||
386 | struct smb_hdr { | 399 | struct smb_hdr { |
387 | __u32 smb_buf_length; /* big endian on wire *//* BB length is only two | 400 | __be32 smb_buf_length; /* BB length is only two (rarely three) bytes, |
388 | or three bytes - with one or two byte type preceding it that are | 401 | with one or two byte "type" preceding it that will be |
389 | zero - we could mask the type byte off just in case BB */ | 402 | zero - we could mask the type byte off */ |
390 | __u8 Protocol[4]; | 403 | __u8 Protocol[4]; |
391 | __u8 Command; | 404 | __u8 Command; |
392 | union { | 405 | union { |
@@ -414,11 +427,34 @@ struct smb_hdr { | |||
414 | __u16 Mid; | 427 | __u16 Mid; |
415 | __u8 WordCount; | 428 | __u8 WordCount; |
416 | } __attribute__((packed)); | 429 | } __attribute__((packed)); |
417 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | 430 | |
418 | #define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) | 431 | /* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */ |
419 | #define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) | 432 | static inline void * |
433 | BCC(struct smb_hdr *smb) | ||
434 | { | ||
435 | return (void *)smb + sizeof(*smb) + 2 * smb->WordCount; | ||
436 | } | ||
437 | |||
420 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ | 438 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ |
421 | #define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2) | 439 | #define pByteArea(smb_var) (BCC(smb_var) + 2) |
440 | |||
441 | /* get the unconverted ByteCount for a SMB packet and return it */ | ||
442 | static inline __u16 | ||
443 | get_bcc(struct smb_hdr *hdr) | ||
444 | { | ||
445 | __le16 *bc_ptr = (__le16 *)BCC(hdr); | ||
446 | |||
447 | return get_unaligned_le16(bc_ptr); | ||
448 | } | ||
449 | |||
450 | /* set the ByteCount for a SMB packet in little-endian */ | ||
451 | static inline void | ||
452 | put_bcc(__u16 count, struct smb_hdr *hdr) | ||
453 | { | ||
454 | __le16 *bc_ptr = (__le16 *)BCC(hdr); | ||
455 | |||
456 | put_unaligned_le16(count, bc_ptr); | ||
457 | } | ||
422 | 458 | ||
423 | /* | 459 | /* |
424 | * Computer Name Length (since Netbios name was length 16 with last byte 0x20) | 460 | * Computer Name Length (since Netbios name was length 16 with last byte 0x20) |
@@ -663,7 +699,6 @@ struct ntlmv2_resp { | |||
663 | __le64 time; | 699 | __le64 time; |
664 | __u64 client_chal; /* random */ | 700 | __u64 client_chal; /* random */ |
665 | __u32 reserved2; | 701 | __u32 reserved2; |
666 | struct ntlmssp2_name names[2]; | ||
667 | /* array of name entries could follow ending in minimum 4 byte struct */ | 702 | /* array of name entries could follow ending in minimum 4 byte struct */ |
668 | } __attribute__((packed)); | 703 | } __attribute__((packed)); |
669 | 704 | ||
@@ -750,6 +785,20 @@ typedef struct smb_com_tconx_rsp_ext { | |||
750 | * | 785 | * |
751 | */ | 786 | */ |
752 | 787 | ||
788 | typedef struct smb_com_echo_req { | ||
789 | struct smb_hdr hdr; | ||
790 | __le16 EchoCount; | ||
791 | __le16 ByteCount; | ||
792 | char Data[1]; | ||
793 | } __attribute__((packed)) ECHO_REQ; | ||
794 | |||
795 | typedef struct smb_com_echo_rsp { | ||
796 | struct smb_hdr hdr; | ||
797 | __le16 SequenceNumber; | ||
798 | __le16 ByteCount; | ||
799 | char Data[1]; | ||
800 | } __attribute__((packed)) ECHO_RSP; | ||
801 | |||
753 | typedef struct smb_com_logoff_andx_req { | 802 | typedef struct smb_com_logoff_andx_req { |
754 | struct smb_hdr hdr; /* wct = 2 */ | 803 | struct smb_hdr hdr; /* wct = 2 */ |
755 | __u8 AndXCommand; | 804 | __u8 AndXCommand; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1d60c655e3e0..8df28e925e5b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -53,24 +53,37 @@ do { \ | |||
53 | cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ | 53 | cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ |
54 | __func__, curr_xid, (int)rc); \ | 54 | __func__, curr_xid, (int)rc); \ |
55 | } while (0) | 55 | } while (0) |
56 | extern int init_cifs_idmap(void); | ||
57 | extern void exit_cifs_idmap(void); | ||
58 | extern void cifs_destroy_idmaptrees(void); | ||
56 | extern char *build_path_from_dentry(struct dentry *); | 59 | extern char *build_path_from_dentry(struct dentry *); |
57 | extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb); | 60 | extern char *cifs_build_path_to_root(struct smb_vol *vol, |
61 | struct cifs_sb_info *cifs_sb, | ||
62 | struct cifs_tcon *tcon); | ||
58 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); | 63 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); |
59 | extern char *cifs_compose_mount_options(const char *sb_mountdata, | 64 | extern char *cifs_compose_mount_options(const char *sb_mountdata, |
60 | const char *fullpath, const struct dfs_info3_param *ref, | 65 | const char *fullpath, const struct dfs_info3_param *ref, |
61 | char **devname); | 66 | char **devname); |
62 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ | 67 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ |
63 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | 68 | extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, |
69 | struct TCP_Server_Info *server); | ||
70 | extern void DeleteMidQEntry(struct mid_q_entry *midEntry); | ||
71 | extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | ||
72 | unsigned int nvec, mid_callback_t *callback, | ||
73 | void *cbdata, bool ignore_pend); | ||
74 | extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, | ||
64 | struct smb_hdr * /* input */ , | 75 | struct smb_hdr * /* input */ , |
65 | struct smb_hdr * /* out */ , | 76 | struct smb_hdr * /* out */ , |
66 | int * /* bytes returned */ , const int long_op); | 77 | int * /* bytes returned */ , const int long_op); |
67 | extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | 78 | extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, |
68 | struct smb_hdr *in_buf, int flags); | 79 | struct smb_hdr *in_buf, int flags); |
69 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 80 | extern int cifs_check_receive(struct mid_q_entry *mid, |
81 | struct TCP_Server_Info *server, bool log_error); | ||
82 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, | ||
70 | struct kvec *, int /* nvec to send */, | 83 | struct kvec *, int /* nvec to send */, |
71 | int * /* type of buf returned */ , const int flags); | 84 | int * /* type of buf returned */ , const int flags); |
72 | extern int SendReceiveBlockingLock(const unsigned int xid, | 85 | extern int SendReceiveBlockingLock(const unsigned int xid, |
73 | struct cifsTconInfo *ptcon, | 86 | struct cifs_tcon *ptcon, |
74 | struct smb_hdr *in_buf , | 87 | struct smb_hdr *in_buf , |
75 | struct smb_hdr *out_buf, | 88 | struct smb_hdr *out_buf, |
76 | int *bytes_returned); | 89 | int *bytes_returned); |
@@ -78,39 +91,39 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); | |||
78 | extern bool is_valid_oplock_break(struct smb_hdr *smb, | 91 | extern bool is_valid_oplock_break(struct smb_hdr *smb, |
79 | struct TCP_Server_Info *); | 92 | struct TCP_Server_Info *); |
80 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | 93 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); |
81 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); | 94 | extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
82 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 95 | unsigned int bytes_written); |
83 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *); | 96 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); |
84 | #endif | 97 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); |
85 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 98 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
86 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | ||
87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 99 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
88 | struct TCP_Server_Info *server); | 100 | struct TCP_Server_Info *server); |
89 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); | 101 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); |
90 | extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); | 102 | extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); |
91 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | 103 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, |
92 | const unsigned short int port); | 104 | const unsigned short int port); |
93 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 105 | extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr); |
94 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 106 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
95 | const struct cifsTconInfo *, int /* length of | 107 | const struct cifs_tcon *, int /* length of |
96 | fixed section (word count) in two byte units */); | 108 | fixed section (word count) in two byte units */); |
97 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, | 109 | extern int small_smb_init_no_tc(const int smb_cmd, const int wct, |
98 | struct cifsSesInfo *ses, | 110 | struct cifs_ses *ses, |
99 | void **request_buf); | 111 | void **request_buf); |
100 | extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 112 | extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses, |
101 | const struct nls_table *nls_cp); | 113 | const struct nls_table *nls_cp); |
102 | extern __u16 GetNextMid(struct TCP_Server_Info *server); | 114 | extern __u16 GetNextMid(struct TCP_Server_Info *server); |
103 | extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); | 115 | extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); |
104 | extern u64 cifs_UnixTimeToNT(struct timespec); | 116 | extern u64 cifs_UnixTimeToNT(struct timespec); |
105 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | 117 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, |
106 | int offset); | 118 | int offset); |
119 | extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock); | ||
107 | 120 | ||
108 | extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, | 121 | extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle, |
109 | __u16 fileHandle, struct file *file, | 122 | struct file *file, struct tcon_link *tlink, |
110 | struct vfsmount *mnt, unsigned int oflags); | 123 | __u32 oplock); |
111 | extern int cifs_posix_open(char *full_path, struct inode **pinode, | 124 | extern int cifs_posix_open(char *full_path, struct inode **pinode, |
112 | struct super_block *sb, | 125 | struct super_block *sb, |
113 | int mode, int oflags, | 126 | int mode, unsigned int f_flags, |
114 | __u32 *poplock, __u16 *pnetfid, int xid); | 127 | __u32 *poplock, __u16 *pnetfid, int xid); |
115 | void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr); | 128 | void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr); |
116 | extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, | 129 | extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, |
@@ -129,107 +142,117 @@ extern int cifs_get_file_info_unix(struct file *filp); | |||
129 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 142 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
130 | const unsigned char *search_path, | 143 | const unsigned char *search_path, |
131 | struct super_block *sb, int xid); | 144 | struct super_block *sb, int xid); |
132 | extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, | 145 | extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, |
133 | struct cifs_fattr *fattr, struct inode *inode, | 146 | struct cifs_fattr *fattr, struct inode *inode, |
134 | const char *path, const __u16 *pfid); | 147 | const char *path, const __u16 *pfid); |
135 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); | 148 | extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64); |
149 | extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, | ||
150 | const char *, u32 *); | ||
151 | extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, | ||
152 | const char *); | ||
136 | 153 | ||
137 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 154 | extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, |
138 | const char *); | 155 | struct cifs_sb_info *cifs_sb); |
139 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); | 156 | extern int cifs_match_super(struct super_block *, void *); |
157 | extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); | ||
158 | extern struct smb_vol *cifs_get_volume_info(char *mount_data, | ||
159 | const char *devname); | ||
160 | extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); | ||
161 | extern void cifs_umount(struct cifs_sb_info *); | ||
140 | extern void cifs_dfs_release_automount_timer(void); | 162 | extern void cifs_dfs_release_automount_timer(void); |
141 | void cifs_proc_init(void); | 163 | void cifs_proc_init(void); |
142 | void cifs_proc_clean(void); | 164 | void cifs_proc_clean(void); |
143 | 165 | ||
144 | extern int cifs_negotiate_protocol(unsigned int xid, | 166 | extern int cifs_negotiate_protocol(unsigned int xid, |
145 | struct cifsSesInfo *ses); | 167 | struct cifs_ses *ses); |
146 | extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | 168 | extern int cifs_setup_session(unsigned int xid, struct cifs_ses *ses, |
147 | struct nls_table *nls_info); | 169 | struct nls_table *nls_info); |
148 | extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); | 170 | extern int CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses); |
149 | 171 | ||
150 | extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | 172 | extern int CIFSTCon(unsigned int xid, struct cifs_ses *ses, |
151 | const char *tree, struct cifsTconInfo *tcon, | 173 | const char *tree, struct cifs_tcon *tcon, |
152 | const struct nls_table *); | 174 | const struct nls_table *); |
153 | 175 | ||
154 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 176 | extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, |
155 | const char *searchName, const struct nls_table *nls_codepage, | 177 | const char *searchName, const struct nls_table *nls_codepage, |
156 | __u16 *searchHandle, struct cifs_search_info *psrch_inf, | 178 | __u16 *searchHandle, struct cifs_search_info *psrch_inf, |
157 | int map, const char dirsep); | 179 | int map, const char dirsep); |
158 | 180 | ||
159 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 181 | extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon, |
160 | __u16 searchHandle, struct cifs_search_info *psrch_inf); | 182 | __u16 searchHandle, struct cifs_search_info *psrch_inf); |
161 | 183 | ||
162 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, | 184 | extern int CIFSFindClose(const int, struct cifs_tcon *tcon, |
163 | const __u16 search_handle); | 185 | const __u16 search_handle); |
164 | 186 | ||
165 | extern int CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon, | 187 | extern int CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon, |
166 | u16 netfid, FILE_ALL_INFO *pFindData); | 188 | u16 netfid, FILE_ALL_INFO *pFindData); |
167 | extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 189 | extern int CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon, |
168 | const unsigned char *searchName, | 190 | const unsigned char *searchName, |
169 | FILE_ALL_INFO *findData, | 191 | FILE_ALL_INFO *findData, |
170 | int legacy /* whether to use old info level */, | 192 | int legacy /* whether to use old info level */, |
171 | const struct nls_table *nls_codepage, int remap); | 193 | const struct nls_table *nls_codepage, int remap); |
172 | extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | 194 | extern int SMBQueryInformation(const int xid, struct cifs_tcon *tcon, |
173 | const unsigned char *searchName, | 195 | const unsigned char *searchName, |
174 | FILE_ALL_INFO *findData, | 196 | FILE_ALL_INFO *findData, |
175 | const struct nls_table *nls_codepage, int remap); | 197 | const struct nls_table *nls_codepage, int remap); |
176 | 198 | ||
177 | extern int CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon, | 199 | extern int CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon, |
178 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData); | 200 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData); |
179 | extern int CIFSSMBUnixQPathInfo(const int xid, | 201 | extern int CIFSSMBUnixQPathInfo(const int xid, |
180 | struct cifsTconInfo *tcon, | 202 | struct cifs_tcon *tcon, |
181 | const unsigned char *searchName, | 203 | const unsigned char *searchName, |
182 | FILE_UNIX_BASIC_INFO *pFindData, | 204 | FILE_UNIX_BASIC_INFO *pFindData, |
183 | const struct nls_table *nls_codepage, int remap); | 205 | const struct nls_table *nls_codepage, int remap); |
184 | 206 | ||
185 | extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | 207 | extern int CIFSGetDFSRefer(const int xid, struct cifs_ses *ses, |
186 | const unsigned char *searchName, | 208 | const unsigned char *searchName, |
187 | struct dfs_info3_param **target_nodes, | 209 | struct dfs_info3_param **target_nodes, |
188 | unsigned int *number_of_nodes_in_array, | 210 | unsigned int *number_of_nodes_in_array, |
189 | const struct nls_table *nls_codepage, int remap); | 211 | const struct nls_table *nls_codepage, int remap); |
190 | 212 | ||
191 | extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | 213 | extern int get_dfs_path(int xid, struct cifs_ses *pSesInfo, |
192 | const char *old_path, | 214 | const char *old_path, |
193 | const struct nls_table *nls_codepage, | 215 | const struct nls_table *nls_codepage, |
194 | unsigned int *pnum_referrals, | 216 | unsigned int *pnum_referrals, |
195 | struct dfs_info3_param **preferrals, | 217 | struct dfs_info3_param **preferrals, |
196 | int remap); | 218 | int remap); |
197 | extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | 219 | extern void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, |
198 | struct super_block *sb, struct smb_vol *vol); | 220 | struct cifs_sb_info *cifs_sb, |
199 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | 221 | struct smb_vol *vol); |
222 | extern int CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, | ||
200 | struct kstatfs *FSData); | 223 | struct kstatfs *FSData); |
201 | extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, | 224 | extern int SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, |
202 | struct kstatfs *FSData); | 225 | struct kstatfs *FSData); |
203 | extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | 226 | extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, |
204 | __u64 cap); | 227 | __u64 cap); |
205 | 228 | ||
206 | extern int CIFSSMBQFSAttributeInfo(const int xid, | 229 | extern int CIFSSMBQFSAttributeInfo(const int xid, |
207 | struct cifsTconInfo *tcon); | 230 | struct cifs_tcon *tcon); |
208 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); | 231 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon); |
209 | extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon); | 232 | extern int CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon); |
210 | extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 233 | extern int CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon, |
211 | struct kstatfs *FSData); | 234 | struct kstatfs *FSData); |
212 | 235 | ||
213 | extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, | 236 | extern int CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon, |
214 | const char *fileName, const FILE_BASIC_INFO *data, | 237 | const char *fileName, const FILE_BASIC_INFO *data, |
215 | const struct nls_table *nls_codepage, | 238 | const struct nls_table *nls_codepage, |
216 | int remap_special_chars); | 239 | int remap_special_chars); |
217 | extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, | 240 | extern int CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon, |
218 | const FILE_BASIC_INFO *data, __u16 fid, | 241 | const FILE_BASIC_INFO *data, __u16 fid, |
219 | __u32 pid_of_opener); | 242 | __u32 pid_of_opener); |
220 | extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, | 243 | extern int CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon, |
221 | bool delete_file, __u16 fid, __u32 pid_of_opener); | 244 | bool delete_file, __u16 fid, __u32 pid_of_opener); |
222 | #if 0 | 245 | #if 0 |
223 | extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, | 246 | extern int CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, |
224 | char *fileName, __u16 dos_attributes, | 247 | char *fileName, __u16 dos_attributes, |
225 | const struct nls_table *nls_codepage); | 248 | const struct nls_table *nls_codepage); |
226 | #endif /* possibly unneeded function */ | 249 | #endif /* possibly unneeded function */ |
227 | extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, | 250 | extern int CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, |
228 | const char *fileName, __u64 size, | 251 | const char *fileName, __u64 size, |
229 | bool setAllocationSizeFlag, | 252 | bool setAllocationSizeFlag, |
230 | const struct nls_table *nls_codepage, | 253 | const struct nls_table *nls_codepage, |
231 | int remap_special_chars); | 254 | int remap_special_chars); |
232 | extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, | 255 | extern int CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, |
233 | __u64 size, __u16 fileHandle, __u32 opener_pid, | 256 | __u64 size, __u16 fileHandle, __u32 opener_pid, |
234 | bool AllocSizeFlag); | 257 | bool AllocSizeFlag); |
235 | 258 | ||
@@ -243,169 +266,195 @@ struct cifs_unix_set_info_args { | |||
243 | dev_t device; | 266 | dev_t device; |
244 | }; | 267 | }; |
245 | 268 | ||
246 | extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, | 269 | extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon, |
247 | const struct cifs_unix_set_info_args *args, | 270 | const struct cifs_unix_set_info_args *args, |
248 | u16 fid, u32 pid_of_opener); | 271 | u16 fid, u32 pid_of_opener); |
249 | 272 | ||
250 | extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon, | 273 | extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *pTcon, |
251 | char *fileName, | 274 | char *fileName, |
252 | const struct cifs_unix_set_info_args *args, | 275 | const struct cifs_unix_set_info_args *args, |
253 | const struct nls_table *nls_codepage, | 276 | const struct nls_table *nls_codepage, |
254 | int remap_special_chars); | 277 | int remap_special_chars); |
255 | 278 | ||
256 | extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, | 279 | extern int CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon, |
257 | const char *newName, | 280 | const char *newName, |
258 | const struct nls_table *nls_codepage, | 281 | const struct nls_table *nls_codepage, |
259 | int remap_special_chars); | 282 | int remap_special_chars); |
260 | extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, | 283 | extern int CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, |
261 | const char *name, const struct nls_table *nls_codepage, | 284 | const char *name, const struct nls_table *nls_codepage, |
262 | int remap_special_chars); | 285 | int remap_special_chars); |
263 | extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, | 286 | extern int CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, |
264 | const char *name, __u16 type, | 287 | const char *name, __u16 type, |
265 | const struct nls_table *nls_codepage, | 288 | const struct nls_table *nls_codepage, |
266 | int remap_special_chars); | 289 | int remap_special_chars); |
267 | extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, | 290 | extern int CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, |
268 | const char *name, | 291 | const char *name, |
269 | const struct nls_table *nls_codepage, | 292 | const struct nls_table *nls_codepage, |
270 | int remap_special_chars); | 293 | int remap_special_chars); |
271 | extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, | 294 | extern int CIFSSMBRename(const int xid, struct cifs_tcon *tcon, |
272 | const char *fromName, const char *toName, | 295 | const char *fromName, const char *toName, |
273 | const struct nls_table *nls_codepage, | 296 | const struct nls_table *nls_codepage, |
274 | int remap_special_chars); | 297 | int remap_special_chars); |
275 | extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, | 298 | extern int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon, |
276 | int netfid, const char *target_name, | 299 | int netfid, const char *target_name, |
277 | const struct nls_table *nls_codepage, | 300 | const struct nls_table *nls_codepage, |
278 | int remap_special_chars); | 301 | int remap_special_chars); |
279 | extern int CIFSCreateHardLink(const int xid, | 302 | extern int CIFSCreateHardLink(const int xid, |
280 | struct cifsTconInfo *tcon, | 303 | struct cifs_tcon *tcon, |
281 | const char *fromName, const char *toName, | 304 | const char *fromName, const char *toName, |
282 | const struct nls_table *nls_codepage, | 305 | const struct nls_table *nls_codepage, |
283 | int remap_special_chars); | 306 | int remap_special_chars); |
284 | extern int CIFSUnixCreateHardLink(const int xid, | 307 | extern int CIFSUnixCreateHardLink(const int xid, |
285 | struct cifsTconInfo *tcon, | 308 | struct cifs_tcon *tcon, |
286 | const char *fromName, const char *toName, | 309 | const char *fromName, const char *toName, |
287 | const struct nls_table *nls_codepage, | 310 | const struct nls_table *nls_codepage, |
288 | int remap_special_chars); | 311 | int remap_special_chars); |
289 | extern int CIFSUnixCreateSymLink(const int xid, | 312 | extern int CIFSUnixCreateSymLink(const int xid, |
290 | struct cifsTconInfo *tcon, | 313 | struct cifs_tcon *tcon, |
291 | const char *fromName, const char *toName, | 314 | const char *fromName, const char *toName, |
292 | const struct nls_table *nls_codepage); | 315 | const struct nls_table *nls_codepage); |
293 | extern int CIFSSMBUnixQuerySymLink(const int xid, | 316 | extern int CIFSSMBUnixQuerySymLink(const int xid, |
294 | struct cifsTconInfo *tcon, | 317 | struct cifs_tcon *tcon, |
295 | const unsigned char *searchName, char **syminfo, | 318 | const unsigned char *searchName, char **syminfo, |
296 | const struct nls_table *nls_codepage); | 319 | const struct nls_table *nls_codepage); |
320 | #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL | ||
297 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, | 321 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, |
298 | struct cifsTconInfo *tcon, | 322 | struct cifs_tcon *tcon, |
299 | const unsigned char *searchName, | 323 | const unsigned char *searchName, |
300 | char *symlinkinfo, const int buflen, __u16 fid, | 324 | char *symlinkinfo, const int buflen, __u16 fid, |
301 | const struct nls_table *nls_codepage); | 325 | const struct nls_table *nls_codepage); |
302 | 326 | #endif /* temporarily unused until cifs_symlink fixed */ | |
303 | extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 327 | extern int CIFSSMBOpen(const int xid, struct cifs_tcon *tcon, |
304 | const char *fileName, const int disposition, | 328 | const char *fileName, const int disposition, |
305 | const int access_flags, const int omode, | 329 | const int access_flags, const int omode, |
306 | __u16 *netfid, int *pOplock, FILE_ALL_INFO *, | 330 | __u16 *netfid, int *pOplock, FILE_ALL_INFO *, |
307 | const struct nls_table *nls_codepage, int remap); | 331 | const struct nls_table *nls_codepage, int remap); |
308 | extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | 332 | extern int SMBLegacyOpen(const int xid, struct cifs_tcon *tcon, |
309 | const char *fileName, const int disposition, | 333 | const char *fileName, const int disposition, |
310 | const int access_flags, const int omode, | 334 | const int access_flags, const int omode, |
311 | __u16 *netfid, int *pOplock, FILE_ALL_INFO *, | 335 | __u16 *netfid, int *pOplock, FILE_ALL_INFO *, |
312 | const struct nls_table *nls_codepage, int remap); | 336 | const struct nls_table *nls_codepage, int remap); |
313 | extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, | 337 | extern int CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, |
314 | u32 posix_flags, __u64 mode, __u16 *netfid, | 338 | u32 posix_flags, __u64 mode, __u16 *netfid, |
315 | FILE_UNIX_BASIC_INFO *pRetData, | 339 | FILE_UNIX_BASIC_INFO *pRetData, |
316 | __u32 *pOplock, const char *name, | 340 | __u32 *pOplock, const char *name, |
317 | const struct nls_table *nls_codepage, int remap); | 341 | const struct nls_table *nls_codepage, int remap); |
318 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | 342 | extern int CIFSSMBClose(const int xid, struct cifs_tcon *tcon, |
319 | const int smb_file_id); | 343 | const int smb_file_id); |
320 | 344 | ||
321 | extern int CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, | 345 | extern int CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, |
322 | const int smb_file_id); | 346 | const int smb_file_id); |
323 | 347 | ||
324 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 348 | extern int CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, |
325 | const int netfid, unsigned int count, | 349 | unsigned int *nbytes, char **buf, |
326 | const __u64 lseek, unsigned int *nbytes, char **buf, | ||
327 | int *return_buf_type); | 350 | int *return_buf_type); |
328 | extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 351 | extern int CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms, |
329 | const int netfid, const unsigned int count, | 352 | unsigned int *nbytes, const char *buf, |
330 | const __u64 lseek, unsigned int *nbytes, | 353 | const char __user *ubuf, const int long_op); |
331 | const char *buf, const char __user *ubuf, | 354 | extern int CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms, |
355 | unsigned int *nbytes, struct kvec *iov, const int nvec, | ||
332 | const int long_op); | 356 | const int long_op); |
333 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 357 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon, |
334 | const int netfid, const unsigned int count, | ||
335 | const __u64 offset, unsigned int *nbytes, | ||
336 | struct kvec *iov, const int nvec, const int long_op); | ||
337 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | ||
338 | const unsigned char *searchName, __u64 *inode_number, | 358 | const unsigned char *searchName, __u64 *inode_number, |
339 | const struct nls_table *nls_codepage, | 359 | const struct nls_table *nls_codepage, |
340 | int remap_special_chars); | 360 | int remap_special_chars); |
341 | extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
342 | const struct nls_table *cp, int mapChars); | ||
343 | 361 | ||
344 | extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 362 | extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon, |
345 | const __u16 netfid, const __u64 len, | 363 | const __u16 netfid, const __u64 len, |
346 | const __u64 offset, const __u32 numUnlock, | 364 | const __u64 offset, const __u32 numUnlock, |
347 | const __u32 numLock, const __u8 lockType, | 365 | const __u32 numLock, const __u8 lockType, |
348 | const bool waitFlag); | 366 | const bool waitFlag, const __u8 oplock_level); |
349 | extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | 367 | extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, |
350 | const __u16 smb_file_id, const int get_flag, | 368 | const __u16 smb_file_id, const int get_flag, |
351 | const __u64 len, struct file_lock *, | 369 | const __u64 len, struct file_lock *, |
352 | const __u16 lock_type, const bool waitFlag); | 370 | const __u16 lock_type, const bool waitFlag); |
353 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); | 371 | extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon); |
354 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); | 372 | extern int CIFSSMBEcho(struct TCP_Server_Info *server); |
373 | extern int CIFSSMBLogoff(const int xid, struct cifs_ses *ses); | ||
355 | 374 | ||
356 | extern struct cifsSesInfo *sesInfoAlloc(void); | 375 | extern struct cifs_ses *sesInfoAlloc(void); |
357 | extern void sesInfoFree(struct cifsSesInfo *); | 376 | extern void sesInfoFree(struct cifs_ses *); |
358 | extern struct cifsTconInfo *tconInfoAlloc(void); | 377 | extern struct cifs_tcon *tconInfoAlloc(void); |
359 | extern void tconInfoFree(struct cifsTconInfo *); | 378 | extern void tconInfoFree(struct cifs_tcon *); |
360 | 379 | ||
361 | extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); | 380 | extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); |
362 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, | 381 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, |
363 | __u32 *); | 382 | __u32 *); |
364 | extern int cifs_verify_signature(struct smb_hdr *, | 383 | extern int cifs_verify_signature(struct smb_hdr *, |
365 | const struct mac_key *mac_key, | 384 | struct TCP_Server_Info *server, |
366 | __u32 expected_sequence_number); | 385 | __u32 expected_sequence_number); |
367 | extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, | 386 | extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *); |
368 | const char *pass); | 387 | extern int setup_ntlm_response(struct cifs_ses *); |
369 | extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); | 388 | extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); |
370 | extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, | 389 | extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *); |
371 | const struct nls_table *); | 390 | extern void cifs_crypto_shash_release(struct TCP_Server_Info *); |
391 | extern int calc_seckey(struct cifs_ses *); | ||
392 | |||
372 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 393 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
373 | extern void calc_lanman_hash(const char *password, const char *cryptkey, | 394 | extern int calc_lanman_hash(const char *password, const char *cryptkey, |
374 | bool encrypt, char *lnm_session_key); | 395 | bool encrypt, char *lnm_session_key); |
375 | #endif /* CIFS_WEAK_PW_HASH */ | 396 | #endif /* CIFS_WEAK_PW_HASH */ |
397 | #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* unused temporarily */ | ||
398 | extern int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon, | ||
399 | const int notify_subdirs, const __u16 netfid, | ||
400 | __u32 filter, struct file *file, int multishot, | ||
401 | const struct nls_table *nls_codepage); | ||
402 | #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ | ||
376 | extern int CIFSSMBCopy(int xid, | 403 | extern int CIFSSMBCopy(int xid, |
377 | struct cifsTconInfo *source_tcon, | 404 | struct cifs_tcon *source_tcon, |
378 | const char *fromName, | 405 | const char *fromName, |
379 | const __u16 target_tid, | 406 | const __u16 target_tid, |
380 | const char *toName, const int flags, | 407 | const char *toName, const int flags, |
381 | const struct nls_table *nls_codepage, | 408 | const struct nls_table *nls_codepage, |
382 | int remap_special_chars); | 409 | int remap_special_chars); |
383 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 410 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon, |
384 | const int notify_subdirs, const __u16 netfid, | ||
385 | __u32 filter, struct file *file, int multishot, | ||
386 | const struct nls_table *nls_codepage); | ||
387 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | ||
388 | const unsigned char *searchName, | 411 | const unsigned char *searchName, |
389 | const unsigned char *ea_name, char *EAData, | 412 | const unsigned char *ea_name, char *EAData, |
390 | size_t bufsize, const struct nls_table *nls_codepage, | 413 | size_t bufsize, const struct nls_table *nls_codepage, |
391 | int remap_special_chars); | 414 | int remap_special_chars); |
392 | extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, | 415 | extern int CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, |
393 | const char *fileName, const char *ea_name, | 416 | const char *fileName, const char *ea_name, |
394 | const void *ea_value, const __u16 ea_value_len, | 417 | const void *ea_value, const __u16 ea_value_len, |
395 | const struct nls_table *nls_codepage, int remap_special_chars); | 418 | const struct nls_table *nls_codepage, int remap_special_chars); |
396 | extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, | 419 | extern int CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, |
397 | __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen); | 420 | __u16 fid, struct cifs_ntsd **acl_inf, __u32 *buflen); |
398 | extern int CIFSSMBSetCIFSACL(const int, struct cifsTconInfo *, __u16, | 421 | extern int CIFSSMBSetCIFSACL(const int, struct cifs_tcon *, __u16, |
399 | struct cifs_ntsd *, __u32); | 422 | struct cifs_ntsd *, __u32); |
400 | extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | 423 | extern int CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon, |
401 | const unsigned char *searchName, | 424 | const unsigned char *searchName, |
402 | char *acl_inf, const int buflen, const int acl_type, | 425 | char *acl_inf, const int buflen, const int acl_type, |
403 | const struct nls_table *nls_codepage, int remap_special_chars); | 426 | const struct nls_table *nls_codepage, int remap_special_chars); |
404 | extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, | 427 | extern int CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon, |
405 | const unsigned char *fileName, | 428 | const unsigned char *fileName, |
406 | const char *local_acl, const int buflen, const int acl_type, | 429 | const char *local_acl, const int buflen, const int acl_type, |
407 | const struct nls_table *nls_codepage, int remap_special_chars); | 430 | const struct nls_table *nls_codepage, int remap_special_chars); |
408 | extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, | 431 | extern int CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon, |
409 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask); | 432 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask); |
410 | extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); | 433 | extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb); |
434 | extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr); | ||
435 | extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr, | ||
436 | const unsigned char *path, | ||
437 | struct cifs_sb_info *cifs_sb, int xid); | ||
438 | extern int mdfour(unsigned char *, unsigned char *, int); | ||
439 | extern int E_md4hash(const unsigned char *passwd, unsigned char *p16); | ||
440 | extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, | ||
441 | unsigned char *p24); | ||
442 | |||
443 | /* asynchronous write support */ | ||
444 | struct cifs_writedata { | ||
445 | struct kref refcount; | ||
446 | enum writeback_sync_modes sync_mode; | ||
447 | struct work_struct work; | ||
448 | struct cifsFileInfo *cfile; | ||
449 | __u64 offset; | ||
450 | unsigned int bytes; | ||
451 | int result; | ||
452 | unsigned int nr_pages; | ||
453 | struct page *pages[1]; | ||
454 | }; | ||
455 | |||
456 | int cifs_async_writev(struct cifs_writedata *wdata); | ||
457 | struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages); | ||
458 | void cifs_writedata_release(struct kref *refcount); | ||
459 | |||
411 | #endif /* _CIFSPROTO_H */ | 460 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 7e83b356cc9e..1a9fe7f816d1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/vfs.h> | 32 | #include <linux/vfs.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/posix_acl_xattr.h> | 34 | #include <linux/posix_acl_xattr.h> |
35 | #include <linux/pagemap.h> | ||
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
36 | #include "cifspdu.h" | 37 | #include "cifspdu.h" |
37 | #include "cifsglob.h" | 38 | #include "cifsglob.h" |
@@ -84,30 +85,30 @@ static struct { | |||
84 | 85 | ||
85 | /* Mark as invalid, all open files on tree connections since they | 86 | /* Mark as invalid, all open files on tree connections since they |
86 | were closed when session to server was lost */ | 87 | were closed when session to server was lost */ |
87 | static void mark_open_files_invalid(struct cifsTconInfo *pTcon) | 88 | static void mark_open_files_invalid(struct cifs_tcon *pTcon) |
88 | { | 89 | { |
89 | struct cifsFileInfo *open_file = NULL; | 90 | struct cifsFileInfo *open_file = NULL; |
90 | struct list_head *tmp; | 91 | struct list_head *tmp; |
91 | struct list_head *tmp1; | 92 | struct list_head *tmp1; |
92 | 93 | ||
93 | /* list all files open on tree connection and mark them invalid */ | 94 | /* list all files open on tree connection and mark them invalid */ |
94 | write_lock(&GlobalSMBSeslock); | 95 | spin_lock(&cifs_file_list_lock); |
95 | list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { | 96 | list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { |
96 | open_file = list_entry(tmp, struct cifsFileInfo, tlist); | 97 | open_file = list_entry(tmp, struct cifsFileInfo, tlist); |
97 | open_file->invalidHandle = true; | 98 | open_file->invalidHandle = true; |
98 | open_file->oplock_break_cancelled = true; | 99 | open_file->oplock_break_cancelled = true; |
99 | } | 100 | } |
100 | write_unlock(&GlobalSMBSeslock); | 101 | spin_unlock(&cifs_file_list_lock); |
101 | /* BB Add call to invalidate_inodes(sb) for all superblocks mounted | 102 | /* BB Add call to invalidate_inodes(sb) for all superblocks mounted |
102 | to this tcon */ | 103 | to this tcon */ |
103 | } | 104 | } |
104 | 105 | ||
105 | /* reconnect the socket, tcon, and smb session if needed */ | 106 | /* reconnect the socket, tcon, and smb session if needed */ |
106 | static int | 107 | static int |
107 | cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | 108 | cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) |
108 | { | 109 | { |
109 | int rc = 0; | 110 | int rc = 0; |
110 | struct cifsSesInfo *ses; | 111 | struct cifs_ses *ses; |
111 | struct TCP_Server_Info *server; | 112 | struct TCP_Server_Info *server; |
112 | struct nls_table *nls_codepage; | 113 | struct nls_table *nls_codepage; |
113 | 114 | ||
@@ -136,18 +137,15 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | |||
136 | } | 137 | } |
137 | } | 138 | } |
138 | 139 | ||
139 | if (ses->status == CifsExiting) | ||
140 | return -EIO; | ||
141 | |||
142 | /* | 140 | /* |
143 | * Give demultiplex thread up to 10 seconds to reconnect, should be | 141 | * Give demultiplex thread up to 10 seconds to reconnect, should be |
144 | * greater than cifs socket timeout which is 7 seconds | 142 | * greater than cifs socket timeout which is 7 seconds |
145 | */ | 143 | */ |
146 | while (server->tcpStatus == CifsNeedReconnect) { | 144 | while (server->tcpStatus == CifsNeedReconnect) { |
147 | wait_event_interruptible_timeout(server->response_q, | 145 | wait_event_interruptible_timeout(server->response_q, |
148 | (server->tcpStatus == CifsGood), 10 * HZ); | 146 | (server->tcpStatus != CifsNeedReconnect), 10 * HZ); |
149 | 147 | ||
150 | /* is TCP session is reestablished now ?*/ | 148 | /* are we still trying to reconnect? */ |
151 | if (server->tcpStatus != CifsNeedReconnect) | 149 | if (server->tcpStatus != CifsNeedReconnect) |
152 | break; | 150 | break; |
153 | 151 | ||
@@ -156,7 +154,7 @@ cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command) | |||
156 | * retrying until process is killed or server comes | 154 | * retrying until process is killed or server comes |
157 | * back on-line | 155 | * back on-line |
158 | */ | 156 | */ |
159 | if (!tcon->retry || ses->status == CifsExiting) { | 157 | if (!tcon->retry) { |
160 | cFYI(1, "gave up waiting on reconnect in smb_init"); | 158 | cFYI(1, "gave up waiting on reconnect in smb_init"); |
161 | return -EHOSTDOWN; | 159 | return -EHOSTDOWN; |
162 | } | 160 | } |
@@ -229,7 +227,7 @@ out: | |||
229 | SMB information in the SMB header. If the return code is zero, this | 227 | SMB information in the SMB header. If the return code is zero, this |
230 | function must have filled in request_buf pointer */ | 228 | function must have filled in request_buf pointer */ |
231 | static int | 229 | static int |
232 | small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | 230 | small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon, |
233 | void **request_buf) | 231 | void **request_buf) |
234 | { | 232 | { |
235 | int rc; | 233 | int rc; |
@@ -255,7 +253,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
255 | 253 | ||
256 | int | 254 | int |
257 | small_smb_init_no_tc(const int smb_command, const int wct, | 255 | small_smb_init_no_tc(const int smb_command, const int wct, |
258 | struct cifsSesInfo *ses, void **request_buf) | 256 | struct cifs_ses *ses, void **request_buf) |
259 | { | 257 | { |
260 | int rc; | 258 | int rc; |
261 | struct smb_hdr *buffer; | 259 | struct smb_hdr *buffer; |
@@ -281,7 +279,7 @@ small_smb_init_no_tc(const int smb_command, const int wct, | |||
281 | 279 | ||
282 | /* If the return code is zero, this function must fill in request_buf pointer */ | 280 | /* If the return code is zero, this function must fill in request_buf pointer */ |
283 | static int | 281 | static int |
284 | __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | 282 | __smb_init(int smb_command, int wct, struct cifs_tcon *tcon, |
285 | void **request_buf, void **response_buf) | 283 | void **request_buf, void **response_buf) |
286 | { | 284 | { |
287 | *request_buf = cifs_buf_get(); | 285 | *request_buf = cifs_buf_get(); |
@@ -307,7 +305,7 @@ __smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
307 | 305 | ||
308 | /* If the return code is zero, this function must fill in request_buf pointer */ | 306 | /* If the return code is zero, this function must fill in request_buf pointer */ |
309 | static int | 307 | static int |
310 | smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | 308 | smb_init(int smb_command, int wct, struct cifs_tcon *tcon, |
311 | void **request_buf, void **response_buf) | 309 | void **request_buf, void **response_buf) |
312 | { | 310 | { |
313 | int rc; | 311 | int rc; |
@@ -320,7 +318,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
320 | } | 318 | } |
321 | 319 | ||
322 | static int | 320 | static int |
323 | smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, | 321 | smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon, |
324 | void **request_buf, void **response_buf) | 322 | void **request_buf, void **response_buf) |
325 | { | 323 | { |
326 | if (tcon->ses->need_reconnect || tcon->need_reconnect) | 324 | if (tcon->ses->need_reconnect || tcon->need_reconnect) |
@@ -331,39 +329,45 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
331 | 329 | ||
332 | static int validate_t2(struct smb_t2_rsp *pSMB) | 330 | static int validate_t2(struct smb_t2_rsp *pSMB) |
333 | { | 331 | { |
334 | int rc = -EINVAL; | 332 | unsigned int total_size; |
335 | int total_size; | 333 | |
336 | char *pBCC; | 334 | /* check for plausible wct */ |
335 | if (pSMB->hdr.WordCount < 10) | ||
336 | goto vt2_err; | ||
337 | 337 | ||
338 | /* check for plausible wct, bcc and t2 data and parm sizes */ | ||
339 | /* check for parm and data offset going beyond end of smb */ | 338 | /* check for parm and data offset going beyond end of smb */ |
340 | if (pSMB->hdr.WordCount >= 10) { | 339 | if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || |
341 | if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && | 340 | get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) |
342 | (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { | 341 | goto vt2_err; |
343 | /* check that bcc is at least as big as parms + data */ | 342 | |
344 | /* check that bcc is less than negotiated smb buffer */ | 343 | total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); |
345 | total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); | 344 | if (total_size >= 512) |
346 | if (total_size < 512) { | 345 | goto vt2_err; |
347 | total_size += | 346 | |
348 | le16_to_cpu(pSMB->t2_rsp.DataCount); | 347 | /* check that bcc is at least as big as parms + data, and that it is |
349 | /* BCC le converted in SendReceive */ | 348 | * less than negotiated smb buffer |
350 | pBCC = (pSMB->hdr.WordCount * 2) + | 349 | */ |
351 | sizeof(struct smb_hdr) + | 350 | total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); |
352 | (char *)pSMB; | 351 | if (total_size > get_bcc(&pSMB->hdr) || |
353 | if ((total_size <= (*(u16 *)pBCC)) && | 352 | total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) |
354 | (total_size < | 353 | goto vt2_err; |
355 | CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { | 354 | |
356 | return 0; | 355 | return 0; |
357 | } | 356 | vt2_err: |
358 | } | ||
359 | } | ||
360 | } | ||
361 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, | 357 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, |
362 | sizeof(struct smb_t2_rsp) + 16); | 358 | sizeof(struct smb_t2_rsp) + 16); |
363 | return rc; | 359 | return -EINVAL; |
364 | } | 360 | } |
361 | |||
362 | static inline void inc_rfc1001_len(void *pSMB, int count) | ||
363 | { | ||
364 | struct smb_hdr *hdr = (struct smb_hdr *)pSMB; | ||
365 | |||
366 | be32_add_cpu(&hdr->smb_buf_length, count); | ||
367 | } | ||
368 | |||
365 | int | 369 | int |
366 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | 370 | CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) |
367 | { | 371 | { |
368 | NEGOTIATE_REQ *pSMB; | 372 | NEGOTIATE_REQ *pSMB; |
369 | NEGOTIATE_RSP *pSMBr; | 373 | NEGOTIATE_RSP *pSMBr; |
@@ -401,15 +405,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
401 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { | 405 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { |
402 | cFYI(1, "Kerberos only mechanism, enable extended security"); | 406 | cFYI(1, "Kerberos only mechanism, enable extended security"); |
403 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 407 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
404 | } | 408 | } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) |
405 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
406 | else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) | ||
407 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 409 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
408 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { | 410 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { |
409 | cFYI(1, "NTLMSSP only mechanism, enable extended security"); | 411 | cFYI(1, "NTLMSSP only mechanism, enable extended security"); |
410 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 412 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
411 | } | 413 | } |
412 | #endif | ||
413 | 414 | ||
414 | count = 0; | 415 | count = 0; |
415 | for (i = 0; i < CIFS_NUM_PROT; i++) { | 416 | for (i = 0; i < CIFS_NUM_PROT; i++) { |
@@ -417,7 +418,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
417 | count += strlen(protocols[i].name) + 1; | 418 | count += strlen(protocols[i].name) + 1; |
418 | /* null at end of source and target buffers anyway */ | 419 | /* null at end of source and target buffers anyway */ |
419 | } | 420 | } |
420 | pSMB->hdr.smb_buf_length += count; | 421 | inc_rfc1001_len(pSMB, count); |
421 | pSMB->ByteCount = cpu_to_le16(count); | 422 | pSMB->ByteCount = cpu_to_le16(count); |
422 | 423 | ||
423 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 424 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
@@ -450,12 +451,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
450 | rc = -EOPNOTSUPP; | 451 | rc = -EOPNOTSUPP; |
451 | goto neg_err_exit; | 452 | goto neg_err_exit; |
452 | } | 453 | } |
453 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); | 454 | server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode); |
454 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | 455 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); |
455 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | 456 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), |
456 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 457 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
457 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | 458 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); |
458 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
459 | /* even though we do not use raw we might as well set this | 459 | /* even though we do not use raw we might as well set this |
460 | accurately, in case we ever find a need for it */ | 460 | accurately, in case we ever find a need for it */ |
461 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 461 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { |
@@ -503,9 +503,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
503 | 503 | ||
504 | if (rsp->EncryptionKeyLength == | 504 | if (rsp->EncryptionKeyLength == |
505 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | 505 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { |
506 | memcpy(server->cryptKey, rsp->EncryptionKey, | 506 | memcpy(ses->server->cryptkey, rsp->EncryptionKey, |
507 | CIFS_CRYPTO_KEY_SIZE); | 507 | CIFS_CRYPTO_KEY_SIZE); |
508 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | 508 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { |
509 | rc = -EIO; /* need cryptkey unless plain text */ | 509 | rc = -EIO; /* need cryptkey unless plain text */ |
510 | goto neg_err_exit; | 510 | goto neg_err_exit; |
511 | } | 511 | } |
@@ -527,11 +527,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
527 | goto neg_err_exit; | 527 | goto neg_err_exit; |
528 | } | 528 | } |
529 | /* else wct == 17 NTLM */ | 529 | /* else wct == 17 NTLM */ |
530 | server->secMode = pSMBr->SecurityMode; | 530 | server->sec_mode = pSMBr->SecurityMode; |
531 | if ((server->secMode & SECMODE_USER) == 0) | 531 | if ((server->sec_mode & SECMODE_USER) == 0) |
532 | cFYI(1, "share mode security"); | 532 | cFYI(1, "share mode security"); |
533 | 533 | ||
534 | if ((server->secMode & SECMODE_PW_ENCRYPT) == 0) | 534 | if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0) |
535 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 535 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
536 | if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) | 536 | if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) |
537 | #endif /* CIFS_WEAK_PW_HASH */ | 537 | #endif /* CIFS_WEAK_PW_HASH */ |
@@ -550,10 +550,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
550 | server->secType = RawNTLMSSP; | 550 | server->secType = RawNTLMSSP; |
551 | else if (secFlags & CIFSSEC_MAY_LANMAN) | 551 | else if (secFlags & CIFSSEC_MAY_LANMAN) |
552 | server->secType = LANMAN; | 552 | server->secType = LANMAN; |
553 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
554 | else if (secFlags & CIFSSEC_MAY_PLNTXT) | ||
555 | server->secType = ?? | ||
556 | #endif */ | ||
557 | else { | 553 | else { |
558 | rc = -EOPNOTSUPP; | 554 | rc = -EOPNOTSUPP; |
559 | cERROR(1, "Invalid security type"); | 555 | cERROR(1, "Invalid security type"); |
@@ -569,33 +565,24 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
569 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 565 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
570 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 566 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
571 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); | 567 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); |
572 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | ||
573 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 568 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
574 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 569 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); |
575 | server->timeAdj *= 60; | 570 | server->timeAdj *= 60; |
576 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 571 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
577 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, | 572 | memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, |
578 | CIFS_CRYPTO_KEY_SIZE); | 573 | CIFS_CRYPTO_KEY_SIZE); |
579 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | 574 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || |
580 | && (pSMBr->EncryptionKeyLength == 0)) { | 575 | server->capabilities & CAP_EXTENDED_SECURITY) && |
576 | (pSMBr->EncryptionKeyLength == 0)) { | ||
581 | /* decode security blob */ | 577 | /* decode security blob */ |
582 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | 578 | count = get_bcc(&pSMBr->hdr); |
583 | rc = -EIO; /* no crypt key only if plain text pwd */ | ||
584 | goto neg_err_exit; | ||
585 | } | ||
586 | |||
587 | /* BB might be helpful to save off the domain of server here */ | ||
588 | |||
589 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && | ||
590 | (server->capabilities & CAP_EXTENDED_SECURITY)) { | ||
591 | count = pSMBr->ByteCount; | ||
592 | if (count < 16) { | 579 | if (count < 16) { |
593 | rc = -EIO; | 580 | rc = -EIO; |
594 | goto neg_err_exit; | 581 | goto neg_err_exit; |
595 | } | 582 | } |
596 | read_lock(&cifs_tcp_ses_lock); | 583 | spin_lock(&cifs_tcp_ses_lock); |
597 | if (server->srv_count > 1) { | 584 | if (server->srv_count > 1) { |
598 | read_unlock(&cifs_tcp_ses_lock); | 585 | spin_unlock(&cifs_tcp_ses_lock); |
599 | if (memcmp(server->server_GUID, | 586 | if (memcmp(server->server_GUID, |
600 | pSMBr->u.extended_response. | 587 | pSMBr->u.extended_response. |
601 | GUID, 16) != 0) { | 588 | GUID, 16) != 0) { |
@@ -605,7 +592,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
605 | 16); | 592 | 16); |
606 | } | 593 | } |
607 | } else { | 594 | } else { |
608 | read_unlock(&cifs_tcp_ses_lock); | 595 | spin_unlock(&cifs_tcp_ses_lock); |
609 | memcpy(server->server_GUID, | 596 | memcpy(server->server_GUID, |
610 | pSMBr->u.extended_response.GUID, 16); | 597 | pSMBr->u.extended_response.GUID, 16); |
611 | } | 598 | } |
@@ -620,14 +607,19 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
620 | rc = 0; | 607 | rc = 0; |
621 | else | 608 | else |
622 | rc = -EINVAL; | 609 | rc = -EINVAL; |
623 | 610 | if (server->secType == Kerberos) { | |
624 | if (server->sec_kerberos || server->sec_mskerberos) | 611 | if (!server->sec_kerberos && |
625 | server->secType = Kerberos; | 612 | !server->sec_mskerberos) |
626 | else if (server->sec_ntlmssp) | 613 | rc = -EOPNOTSUPP; |
627 | server->secType = RawNTLMSSP; | 614 | } else if (server->secType == RawNTLMSSP) { |
628 | else | 615 | if (!server->sec_ntlmssp) |
629 | rc = -EOPNOTSUPP; | 616 | rc = -EOPNOTSUPP; |
617 | } else | ||
618 | rc = -EOPNOTSUPP; | ||
630 | } | 619 | } |
620 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | ||
621 | rc = -EIO; /* no crypt key only if plain text pwd */ | ||
622 | goto neg_err_exit; | ||
631 | } else | 623 | } else |
632 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | 624 | server->capabilities &= ~CAP_EXTENDED_SECURITY; |
633 | 625 | ||
@@ -638,27 +630,27 @@ signing_check: | |||
638 | /* MUST_SIGN already includes the MAY_SIGN FLAG | 630 | /* MUST_SIGN already includes the MAY_SIGN FLAG |
639 | so if this is zero it means that signing is disabled */ | 631 | so if this is zero it means that signing is disabled */ |
640 | cFYI(1, "Signing disabled"); | 632 | cFYI(1, "Signing disabled"); |
641 | if (server->secMode & SECMODE_SIGN_REQUIRED) { | 633 | if (server->sec_mode & SECMODE_SIGN_REQUIRED) { |
642 | cERROR(1, "Server requires " | 634 | cERROR(1, "Server requires " |
643 | "packet signing to be enabled in " | 635 | "packet signing to be enabled in " |
644 | "/proc/fs/cifs/SecurityFlags."); | 636 | "/proc/fs/cifs/SecurityFlags."); |
645 | rc = -EOPNOTSUPP; | 637 | rc = -EOPNOTSUPP; |
646 | } | 638 | } |
647 | server->secMode &= | 639 | server->sec_mode &= |
648 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | 640 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); |
649 | } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { | 641 | } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { |
650 | /* signing required */ | 642 | /* signing required */ |
651 | cFYI(1, "Must sign - secFlags 0x%x", secFlags); | 643 | cFYI(1, "Must sign - secFlags 0x%x", secFlags); |
652 | if ((server->secMode & | 644 | if ((server->sec_mode & |
653 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { | 645 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { |
654 | cERROR(1, "signing required but server lacks support"); | 646 | cERROR(1, "signing required but server lacks support"); |
655 | rc = -EOPNOTSUPP; | 647 | rc = -EOPNOTSUPP; |
656 | } else | 648 | } else |
657 | server->secMode |= SECMODE_SIGN_REQUIRED; | 649 | server->sec_mode |= SECMODE_SIGN_REQUIRED; |
658 | } else { | 650 | } else { |
659 | /* signing optional ie CIFSSEC_MAY_SIGN */ | 651 | /* signing optional ie CIFSSEC_MAY_SIGN */ |
660 | if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | 652 | if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0) |
661 | server->secMode &= | 653 | server->sec_mode &= |
662 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | 654 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); |
663 | } | 655 | } |
664 | 656 | ||
@@ -670,7 +662,7 @@ neg_err_exit: | |||
670 | } | 662 | } |
671 | 663 | ||
672 | int | 664 | int |
673 | CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | 665 | CIFSSMBTDis(const int xid, struct cifs_tcon *tcon) |
674 | { | 666 | { |
675 | struct smb_hdr *smb_buffer; | 667 | struct smb_hdr *smb_buffer; |
676 | int rc = 0; | 668 | int rc = 0; |
@@ -707,8 +699,57 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
707 | return rc; | 699 | return rc; |
708 | } | 700 | } |
709 | 701 | ||
702 | /* | ||
703 | * This is a no-op for now. We're not really interested in the reply, but | ||
704 | * rather in the fact that the server sent one and that server->lstrp | ||
705 | * gets updated. | ||
706 | * | ||
707 | * FIXME: maybe we should consider checking that the reply matches request? | ||
708 | */ | ||
709 | static void | ||
710 | cifs_echo_callback(struct mid_q_entry *mid) | ||
711 | { | ||
712 | struct TCP_Server_Info *server = mid->callback_data; | ||
713 | |||
714 | DeleteMidQEntry(mid); | ||
715 | atomic_dec(&server->inFlight); | ||
716 | wake_up(&server->request_q); | ||
717 | } | ||
718 | |||
719 | int | ||
720 | CIFSSMBEcho(struct TCP_Server_Info *server) | ||
721 | { | ||
722 | ECHO_REQ *smb; | ||
723 | int rc = 0; | ||
724 | struct kvec iov; | ||
725 | |||
726 | cFYI(1, "In echo request"); | ||
727 | |||
728 | rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); | ||
729 | if (rc) | ||
730 | return rc; | ||
731 | |||
732 | /* set up echo request */ | ||
733 | smb->hdr.Tid = 0xffff; | ||
734 | smb->hdr.WordCount = 1; | ||
735 | put_unaligned_le16(1, &smb->EchoCount); | ||
736 | put_bcc(1, &smb->hdr); | ||
737 | smb->Data[0] = 'a'; | ||
738 | inc_rfc1001_len(smb, 3); | ||
739 | iov.iov_base = smb; | ||
740 | iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; | ||
741 | |||
742 | rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true); | ||
743 | if (rc) | ||
744 | cFYI(1, "Echo request failed: %d", rc); | ||
745 | |||
746 | cifs_small_buf_release(smb); | ||
747 | |||
748 | return rc; | ||
749 | } | ||
750 | |||
710 | int | 751 | int |
711 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | 752 | CIFSSMBLogoff(const int xid, struct cifs_ses *ses) |
712 | { | 753 | { |
713 | LOGOFF_ANDX_REQ *pSMB; | 754 | LOGOFF_ANDX_REQ *pSMB; |
714 | int rc = 0; | 755 | int rc = 0; |
@@ -735,7 +776,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
735 | 776 | ||
736 | pSMB->hdr.Mid = GetNextMid(ses->server); | 777 | pSMB->hdr.Mid = GetNextMid(ses->server); |
737 | 778 | ||
738 | if (ses->server->secMode & | 779 | if (ses->server->sec_mode & |
739 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 780 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
740 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 781 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
741 | 782 | ||
@@ -755,7 +796,7 @@ session_already_dead: | |||
755 | } | 796 | } |
756 | 797 | ||
757 | int | 798 | int |
758 | CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 799 | CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName, |
759 | __u16 type, const struct nls_table *nls_codepage, int remap) | 800 | __u16 type, const struct nls_table *nls_codepage, int remap) |
760 | { | 801 | { |
761 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 802 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
@@ -813,7 +854,7 @@ PsxDelete: | |||
813 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 854 | pSMB->TotalParameterCount = pSMB->ParameterCount; |
814 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); | 855 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK); |
815 | pSMB->Reserved4 = 0; | 856 | pSMB->Reserved4 = 0; |
816 | pSMB->hdr.smb_buf_length += byte_count; | 857 | inc_rfc1001_len(pSMB, byte_count); |
817 | pSMB->ByteCount = cpu_to_le16(byte_count); | 858 | pSMB->ByteCount = cpu_to_le16(byte_count); |
818 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 859 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
819 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 860 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -830,7 +871,7 @@ PsxDelete: | |||
830 | } | 871 | } |
831 | 872 | ||
832 | int | 873 | int |
833 | CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 874 | CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName, |
834 | const struct nls_table *nls_codepage, int remap) | 875 | const struct nls_table *nls_codepage, int remap) |
835 | { | 876 | { |
836 | DELETE_FILE_REQ *pSMB = NULL; | 877 | DELETE_FILE_REQ *pSMB = NULL; |
@@ -859,7 +900,7 @@ DelFileRetry: | |||
859 | pSMB->SearchAttributes = | 900 | pSMB->SearchAttributes = |
860 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); | 901 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); |
861 | pSMB->BufferFormat = 0x04; | 902 | pSMB->BufferFormat = 0x04; |
862 | pSMB->hdr.smb_buf_length += name_len + 1; | 903 | inc_rfc1001_len(pSMB, name_len + 1); |
863 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 904 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
864 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 905 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
865 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 906 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -875,7 +916,7 @@ DelFileRetry: | |||
875 | } | 916 | } |
876 | 917 | ||
877 | int | 918 | int |
878 | CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName, | 919 | CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName, |
879 | const struct nls_table *nls_codepage, int remap) | 920 | const struct nls_table *nls_codepage, int remap) |
880 | { | 921 | { |
881 | DELETE_DIRECTORY_REQ *pSMB = NULL; | 922 | DELETE_DIRECTORY_REQ *pSMB = NULL; |
@@ -903,7 +944,7 @@ RmDirRetry: | |||
903 | } | 944 | } |
904 | 945 | ||
905 | pSMB->BufferFormat = 0x04; | 946 | pSMB->BufferFormat = 0x04; |
906 | pSMB->hdr.smb_buf_length += name_len + 1; | 947 | inc_rfc1001_len(pSMB, name_len + 1); |
907 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 948 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
908 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 949 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
909 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 950 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -918,7 +959,7 @@ RmDirRetry: | |||
918 | } | 959 | } |
919 | 960 | ||
920 | int | 961 | int |
921 | CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, | 962 | CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon, |
922 | const char *name, const struct nls_table *nls_codepage, int remap) | 963 | const char *name, const struct nls_table *nls_codepage, int remap) |
923 | { | 964 | { |
924 | int rc = 0; | 965 | int rc = 0; |
@@ -946,7 +987,7 @@ MkDirRetry: | |||
946 | } | 987 | } |
947 | 988 | ||
948 | pSMB->BufferFormat = 0x04; | 989 | pSMB->BufferFormat = 0x04; |
949 | pSMB->hdr.smb_buf_length += name_len + 1; | 990 | inc_rfc1001_len(pSMB, name_len + 1); |
950 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 991 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
951 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 992 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
952 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 993 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -961,7 +1002,7 @@ MkDirRetry: | |||
961 | } | 1002 | } |
962 | 1003 | ||
963 | int | 1004 | int |
964 | CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags, | 1005 | CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags, |
965 | __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData, | 1006 | __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData, |
966 | __u32 *pOplock, const char *name, | 1007 | __u32 *pOplock, const char *name, |
967 | const struct nls_table *nls_codepage, int remap) | 1008 | const struct nls_table *nls_codepage, int remap) |
@@ -1024,7 +1065,7 @@ PsxCreat: | |||
1024 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 1065 | pSMB->TotalParameterCount = pSMB->ParameterCount; |
1025 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); | 1066 | pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN); |
1026 | pSMB->Reserved4 = 0; | 1067 | pSMB->Reserved4 = 0; |
1027 | pSMB->hdr.smb_buf_length += byte_count; | 1068 | inc_rfc1001_len(pSMB, byte_count); |
1028 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1069 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1029 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1070 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1030 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1071 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -1036,7 +1077,7 @@ PsxCreat: | |||
1036 | cFYI(1, "copying inode info"); | 1077 | cFYI(1, "copying inode info"); |
1037 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 1078 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
1038 | 1079 | ||
1039 | if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) { | 1080 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { |
1040 | rc = -EIO; /* bad smb */ | 1081 | rc = -EIO; /* bad smb */ |
1041 | goto psx_create_err; | 1082 | goto psx_create_err; |
1042 | } | 1083 | } |
@@ -1057,7 +1098,7 @@ PsxCreat: | |||
1057 | pRetData->Type = cpu_to_le32(-1); /* unknown */ | 1098 | pRetData->Type = cpu_to_le32(-1); /* unknown */ |
1058 | cFYI(DBG2, "unknown type"); | 1099 | cFYI(DBG2, "unknown type"); |
1059 | } else { | 1100 | } else { |
1060 | if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) | 1101 | if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP) |
1061 | + sizeof(FILE_UNIX_BASIC_INFO)) { | 1102 | + sizeof(FILE_UNIX_BASIC_INFO)) { |
1062 | cERROR(1, "Open response data too small"); | 1103 | cERROR(1, "Open response data too small"); |
1063 | pRetData->Type = cpu_to_le32(-1); | 1104 | pRetData->Type = cpu_to_le32(-1); |
@@ -1127,7 +1168,7 @@ access_flags_to_smbopen_mode(const int access_flags) | |||
1127 | } | 1168 | } |
1128 | 1169 | ||
1129 | int | 1170 | int |
1130 | SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | 1171 | SMBLegacyOpen(const int xid, struct cifs_tcon *tcon, |
1131 | const char *fileName, const int openDisposition, | 1172 | const char *fileName, const int openDisposition, |
1132 | const int access_flags, const int create_options, __u16 *netfid, | 1173 | const int access_flags, const int create_options, __u16 *netfid, |
1133 | int *pOplock, FILE_ALL_INFO *pfile_info, | 1174 | int *pOplock, FILE_ALL_INFO *pfile_info, |
@@ -1189,12 +1230,12 @@ OldOpenRetry: | |||
1189 | pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); | 1230 | pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); |
1190 | pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); | 1231 | pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); |
1191 | count += name_len; | 1232 | count += name_len; |
1192 | pSMB->hdr.smb_buf_length += count; | 1233 | inc_rfc1001_len(pSMB, count); |
1193 | 1234 | ||
1194 | pSMB->ByteCount = cpu_to_le16(count); | 1235 | pSMB->ByteCount = cpu_to_le16(count); |
1195 | /* long_op set to 1 to allow for oplock break timeouts */ | 1236 | /* long_op set to 1 to allow for oplock break timeouts */ |
1196 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1237 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1197 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1238 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
1198 | cifs_stats_inc(&tcon->num_opens); | 1239 | cifs_stats_inc(&tcon->num_opens); |
1199 | if (rc) { | 1240 | if (rc) { |
1200 | cFYI(1, "Error in Open = %d", rc); | 1241 | cFYI(1, "Error in Open = %d", rc); |
@@ -1234,7 +1275,7 @@ OldOpenRetry: | |||
1234 | } | 1275 | } |
1235 | 1276 | ||
1236 | int | 1277 | int |
1237 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 1278 | CIFSSMBOpen(const int xid, struct cifs_tcon *tcon, |
1238 | const char *fileName, const int openDisposition, | 1279 | const char *fileName, const int openDisposition, |
1239 | const int access_flags, const int create_options, __u16 *netfid, | 1280 | const int access_flags, const int create_options, __u16 *netfid, |
1240 | int *pOplock, FILE_ALL_INFO *pfile_info, | 1281 | int *pOplock, FILE_ALL_INFO *pfile_info, |
@@ -1302,12 +1343,12 @@ openRetry: | |||
1302 | SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; | 1343 | SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY; |
1303 | 1344 | ||
1304 | count += name_len; | 1345 | count += name_len; |
1305 | pSMB->hdr.smb_buf_length += count; | 1346 | inc_rfc1001_len(pSMB, count); |
1306 | 1347 | ||
1307 | pSMB->ByteCount = cpu_to_le16(count); | 1348 | pSMB->ByteCount = cpu_to_le16(count); |
1308 | /* long_op set to 1 to allow for oplock break timeouts */ | 1349 | /* long_op set to 1 to allow for oplock break timeouts */ |
1309 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1350 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1310 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1351 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
1311 | cifs_stats_inc(&tcon->num_opens); | 1352 | cifs_stats_inc(&tcon->num_opens); |
1312 | if (rc) { | 1353 | if (rc) { |
1313 | cFYI(1, "Error in Open = %d", rc); | 1354 | cFYI(1, "Error in Open = %d", rc); |
@@ -1336,8 +1377,7 @@ openRetry: | |||
1336 | } | 1377 | } |
1337 | 1378 | ||
1338 | int | 1379 | int |
1339 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | 1380 | CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, |
1340 | const unsigned int count, const __u64 lseek, unsigned int *nbytes, | ||
1341 | char **buf, int *pbuf_type) | 1381 | char **buf, int *pbuf_type) |
1342 | { | 1382 | { |
1343 | int rc = -EACCES; | 1383 | int rc = -EACCES; |
@@ -1347,13 +1387,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
1347 | int wct; | 1387 | int wct; |
1348 | int resp_buf_type = 0; | 1388 | int resp_buf_type = 0; |
1349 | struct kvec iov[1]; | 1389 | struct kvec iov[1]; |
1390 | __u32 pid = io_parms->pid; | ||
1391 | __u16 netfid = io_parms->netfid; | ||
1392 | __u64 offset = io_parms->offset; | ||
1393 | struct cifs_tcon *tcon = io_parms->tcon; | ||
1394 | unsigned int count = io_parms->length; | ||
1350 | 1395 | ||
1351 | cFYI(1, "Reading %d bytes on fid %d", count, netfid); | 1396 | cFYI(1, "Reading %d bytes on fid %d", count, netfid); |
1352 | if (tcon->ses->capabilities & CAP_LARGE_FILES) | 1397 | if (tcon->ses->capabilities & CAP_LARGE_FILES) |
1353 | wct = 12; | 1398 | wct = 12; |
1354 | else { | 1399 | else { |
1355 | wct = 10; /* old style read */ | 1400 | wct = 10; /* old style read */ |
1356 | if ((lseek >> 32) > 0) { | 1401 | if ((offset >> 32) > 0) { |
1357 | /* can not handle this big offset for old */ | 1402 | /* can not handle this big offset for old */ |
1358 | return -EIO; | 1403 | return -EIO; |
1359 | } | 1404 | } |
@@ -1364,15 +1409,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
1364 | if (rc) | 1409 | if (rc) |
1365 | return rc; | 1410 | return rc; |
1366 | 1411 | ||
1412 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid); | ||
1413 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); | ||
1414 | |||
1367 | /* tcon and ses pointer are checked in smb_init */ | 1415 | /* tcon and ses pointer are checked in smb_init */ |
1368 | if (tcon->ses->server == NULL) | 1416 | if (tcon->ses->server == NULL) |
1369 | return -ECONNABORTED; | 1417 | return -ECONNABORTED; |
1370 | 1418 | ||
1371 | pSMB->AndXCommand = 0xFF; /* none */ | 1419 | pSMB->AndXCommand = 0xFF; /* none */ |
1372 | pSMB->Fid = netfid; | 1420 | pSMB->Fid = netfid; |
1373 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 1421 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
1374 | if (wct == 12) | 1422 | if (wct == 12) |
1375 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 1423 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); |
1376 | 1424 | ||
1377 | pSMB->Remaining = 0; | 1425 | pSMB->Remaining = 0; |
1378 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 1426 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
@@ -1387,9 +1435,9 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
1387 | } | 1435 | } |
1388 | 1436 | ||
1389 | iov[0].iov_base = (char *)pSMB; | 1437 | iov[0].iov_base = (char *)pSMB; |
1390 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 1438 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; |
1391 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 1439 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
1392 | &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); | 1440 | &resp_buf_type, CIFS_LOG_ERROR); |
1393 | cifs_stats_inc(&tcon->num_reads); | 1441 | cifs_stats_inc(&tcon->num_reads); |
1394 | pSMBr = (READ_RSP *)iov[0].iov_base; | 1442 | pSMBr = (READ_RSP *)iov[0].iov_base; |
1395 | if (rc) { | 1443 | if (rc) { |
@@ -1441,9 +1489,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
1441 | 1489 | ||
1442 | 1490 | ||
1443 | int | 1491 | int |
1444 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 1492 | CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms, |
1445 | const int netfid, const unsigned int count, | 1493 | unsigned int *nbytes, const char *buf, |
1446 | const __u64 offset, unsigned int *nbytes, const char *buf, | ||
1447 | const char __user *ubuf, const int long_op) | 1494 | const char __user *ubuf, const int long_op) |
1448 | { | 1495 | { |
1449 | int rc = -EACCES; | 1496 | int rc = -EACCES; |
@@ -1452,6 +1499,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1452 | int bytes_returned, wct; | 1499 | int bytes_returned, wct; |
1453 | __u32 bytes_sent; | 1500 | __u32 bytes_sent; |
1454 | __u16 byte_count; | 1501 | __u16 byte_count; |
1502 | __u32 pid = io_parms->pid; | ||
1503 | __u16 netfid = io_parms->netfid; | ||
1504 | __u64 offset = io_parms->offset; | ||
1505 | struct cifs_tcon *tcon = io_parms->tcon; | ||
1506 | unsigned int count = io_parms->length; | ||
1455 | 1507 | ||
1456 | *nbytes = 0; | 1508 | *nbytes = 0; |
1457 | 1509 | ||
@@ -1473,6 +1525,10 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1473 | (void **) &pSMBr); | 1525 | (void **) &pSMBr); |
1474 | if (rc) | 1526 | if (rc) |
1475 | return rc; | 1527 | return rc; |
1528 | |||
1529 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid); | ||
1530 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); | ||
1531 | |||
1476 | /* tcon and ses pointer are checked in smb_init */ | 1532 | /* tcon and ses pointer are checked in smb_init */ |
1477 | if (tcon->ses->server == NULL) | 1533 | if (tcon->ses->server == NULL) |
1478 | return -ECONNABORTED; | 1534 | return -ECONNABORTED; |
@@ -1521,7 +1577,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1521 | 1577 | ||
1522 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1578 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
1523 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | 1579 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
1524 | pSMB->hdr.smb_buf_length += byte_count; | 1580 | inc_rfc1001_len(pSMB, byte_count); |
1525 | 1581 | ||
1526 | if (wct == 14) | 1582 | if (wct == 14) |
1527 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1583 | pSMB->ByteCount = cpu_to_le16(byte_count); |
@@ -1559,17 +1615,259 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1559 | return rc; | 1615 | return rc; |
1560 | } | 1616 | } |
1561 | 1617 | ||
1618 | void | ||
1619 | cifs_writedata_release(struct kref *refcount) | ||
1620 | { | ||
1621 | struct cifs_writedata *wdata = container_of(refcount, | ||
1622 | struct cifs_writedata, refcount); | ||
1623 | |||
1624 | if (wdata->cfile) | ||
1625 | cifsFileInfo_put(wdata->cfile); | ||
1626 | |||
1627 | kfree(wdata); | ||
1628 | } | ||
1629 | |||
1630 | /* | ||
1631 | * Write failed with a retryable error. Resend the write request. It's also | ||
1632 | * possible that the page was redirtied so re-clean the page. | ||
1633 | */ | ||
1634 | static void | ||
1635 | cifs_writev_requeue(struct cifs_writedata *wdata) | ||
1636 | { | ||
1637 | int i, rc; | ||
1638 | struct inode *inode = wdata->cfile->dentry->d_inode; | ||
1639 | |||
1640 | for (i = 0; i < wdata->nr_pages; i++) { | ||
1641 | lock_page(wdata->pages[i]); | ||
1642 | clear_page_dirty_for_io(wdata->pages[i]); | ||
1643 | } | ||
1644 | |||
1645 | do { | ||
1646 | rc = cifs_async_writev(wdata); | ||
1647 | } while (rc == -EAGAIN); | ||
1648 | |||
1649 | for (i = 0; i < wdata->nr_pages; i++) { | ||
1650 | if (rc != 0) | ||
1651 | SetPageError(wdata->pages[i]); | ||
1652 | unlock_page(wdata->pages[i]); | ||
1653 | } | ||
1654 | |||
1655 | mapping_set_error(inode->i_mapping, rc); | ||
1656 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
1657 | } | ||
1658 | |||
1659 | static void | ||
1660 | cifs_writev_complete(struct work_struct *work) | ||
1661 | { | ||
1662 | struct cifs_writedata *wdata = container_of(work, | ||
1663 | struct cifs_writedata, work); | ||
1664 | struct inode *inode = wdata->cfile->dentry->d_inode; | ||
1665 | int i = 0; | ||
1666 | |||
1667 | if (wdata->result == 0) { | ||
1668 | cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes); | ||
1669 | cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink), | ||
1670 | wdata->bytes); | ||
1671 | } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN) | ||
1672 | return cifs_writev_requeue(wdata); | ||
1673 | |||
1674 | for (i = 0; i < wdata->nr_pages; i++) { | ||
1675 | struct page *page = wdata->pages[i]; | ||
1676 | if (wdata->result == -EAGAIN) | ||
1677 | __set_page_dirty_nobuffers(page); | ||
1678 | else if (wdata->result < 0) | ||
1679 | SetPageError(page); | ||
1680 | end_page_writeback(page); | ||
1681 | page_cache_release(page); | ||
1682 | } | ||
1683 | if (wdata->result != -EAGAIN) | ||
1684 | mapping_set_error(inode->i_mapping, wdata->result); | ||
1685 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
1686 | } | ||
1687 | |||
1688 | struct cifs_writedata * | ||
1689 | cifs_writedata_alloc(unsigned int nr_pages) | ||
1690 | { | ||
1691 | struct cifs_writedata *wdata; | ||
1692 | |||
1693 | /* this would overflow */ | ||
1694 | if (nr_pages == 0) { | ||
1695 | cERROR(1, "%s: called with nr_pages == 0!", __func__); | ||
1696 | return NULL; | ||
1697 | } | ||
1698 | |||
1699 | /* writedata + number of page pointers */ | ||
1700 | wdata = kzalloc(sizeof(*wdata) + | ||
1701 | sizeof(struct page *) * (nr_pages - 1), GFP_NOFS); | ||
1702 | if (wdata != NULL) { | ||
1703 | INIT_WORK(&wdata->work, cifs_writev_complete); | ||
1704 | kref_init(&wdata->refcount); | ||
1705 | } | ||
1706 | return wdata; | ||
1707 | } | ||
1708 | |||
1709 | /* | ||
1710 | * Check the midState and signature on received buffer (if any), and queue the | ||
1711 | * workqueue completion task. | ||
1712 | */ | ||
1713 | static void | ||
1714 | cifs_writev_callback(struct mid_q_entry *mid) | ||
1715 | { | ||
1716 | struct cifs_writedata *wdata = mid->callback_data; | ||
1717 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | ||
1718 | unsigned int written; | ||
1719 | WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; | ||
1720 | |||
1721 | switch (mid->midState) { | ||
1722 | case MID_RESPONSE_RECEIVED: | ||
1723 | wdata->result = cifs_check_receive(mid, tcon->ses->server, 0); | ||
1724 | if (wdata->result != 0) | ||
1725 | break; | ||
1726 | |||
1727 | written = le16_to_cpu(smb->CountHigh); | ||
1728 | written <<= 16; | ||
1729 | written += le16_to_cpu(smb->Count); | ||
1730 | /* | ||
1731 | * Mask off high 16 bits when bytes written as returned | ||
1732 | * by the server is greater than bytes requested by the | ||
1733 | * client. OS/2 servers are known to set incorrect | ||
1734 | * CountHigh values. | ||
1735 | */ | ||
1736 | if (written > wdata->bytes) | ||
1737 | written &= 0xFFFF; | ||
1738 | |||
1739 | if (written < wdata->bytes) | ||
1740 | wdata->result = -ENOSPC; | ||
1741 | else | ||
1742 | wdata->bytes = written; | ||
1743 | break; | ||
1744 | case MID_REQUEST_SUBMITTED: | ||
1745 | case MID_RETRY_NEEDED: | ||
1746 | wdata->result = -EAGAIN; | ||
1747 | break; | ||
1748 | default: | ||
1749 | wdata->result = -EIO; | ||
1750 | break; | ||
1751 | } | ||
1752 | |||
1753 | queue_work(system_nrt_wq, &wdata->work); | ||
1754 | DeleteMidQEntry(mid); | ||
1755 | atomic_dec(&tcon->ses->server->inFlight); | ||
1756 | wake_up(&tcon->ses->server->request_q); | ||
1757 | } | ||
1758 | |||
1759 | /* cifs_async_writev - send an async write, and set up mid to handle result */ | ||
1760 | int | ||
1761 | cifs_async_writev(struct cifs_writedata *wdata) | ||
1762 | { | ||
1763 | int i, rc = -EACCES; | ||
1764 | WRITE_REQ *smb = NULL; | ||
1765 | int wct; | ||
1766 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | ||
1767 | struct inode *inode = wdata->cfile->dentry->d_inode; | ||
1768 | struct kvec *iov = NULL; | ||
1769 | |||
1770 | if (tcon->ses->capabilities & CAP_LARGE_FILES) { | ||
1771 | wct = 14; | ||
1772 | } else { | ||
1773 | wct = 12; | ||
1774 | if (wdata->offset >> 32 > 0) { | ||
1775 | /* can not handle big offset for old srv */ | ||
1776 | return -EIO; | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb); | ||
1781 | if (rc) | ||
1782 | goto async_writev_out; | ||
1783 | |||
1784 | /* 1 iov per page + 1 for header */ | ||
1785 | iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS); | ||
1786 | if (iov == NULL) { | ||
1787 | rc = -ENOMEM; | ||
1788 | goto async_writev_out; | ||
1789 | } | ||
1790 | |||
1791 | smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid); | ||
1792 | smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16)); | ||
1793 | |||
1794 | smb->AndXCommand = 0xFF; /* none */ | ||
1795 | smb->Fid = wdata->cfile->netfid; | ||
1796 | smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF); | ||
1797 | if (wct == 14) | ||
1798 | smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32); | ||
1799 | smb->Reserved = 0xFFFFFFFF; | ||
1800 | smb->WriteMode = 0; | ||
1801 | smb->Remaining = 0; | ||
1802 | |||
1803 | smb->DataOffset = | ||
1804 | cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4); | ||
1805 | |||
1806 | /* 4 for RFC1001 length + 1 for BCC */ | ||
1807 | iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1; | ||
1808 | iov[0].iov_base = smb; | ||
1809 | |||
1810 | /* marshal up the pages into iov array */ | ||
1811 | wdata->bytes = 0; | ||
1812 | for (i = 0; i < wdata->nr_pages; i++) { | ||
1813 | iov[i + 1].iov_len = min(inode->i_size - | ||
1814 | page_offset(wdata->pages[i]), | ||
1815 | (loff_t)PAGE_CACHE_SIZE); | ||
1816 | iov[i + 1].iov_base = kmap(wdata->pages[i]); | ||
1817 | wdata->bytes += iov[i + 1].iov_len; | ||
1818 | } | ||
1819 | |||
1820 | cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes); | ||
1821 | |||
1822 | smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF); | ||
1823 | smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16); | ||
1824 | |||
1825 | if (wct == 14) { | ||
1826 | inc_rfc1001_len(&smb->hdr, wdata->bytes + 1); | ||
1827 | put_bcc(wdata->bytes + 1, &smb->hdr); | ||
1828 | } else { | ||
1829 | /* wct == 12 */ | ||
1830 | struct smb_com_writex_req *smbw = | ||
1831 | (struct smb_com_writex_req *)smb; | ||
1832 | inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5); | ||
1833 | put_bcc(wdata->bytes + 5, &smbw->hdr); | ||
1834 | iov[0].iov_len += 4; /* pad bigger by four bytes */ | ||
1835 | } | ||
1836 | |||
1837 | kref_get(&wdata->refcount); | ||
1838 | rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1, | ||
1839 | cifs_writev_callback, wdata, false); | ||
1840 | |||
1841 | if (rc == 0) | ||
1842 | cifs_stats_inc(&tcon->num_writes); | ||
1843 | else | ||
1844 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
1845 | |||
1846 | /* send is done, unmap pages */ | ||
1847 | for (i = 0; i < wdata->nr_pages; i++) | ||
1848 | kunmap(wdata->pages[i]); | ||
1849 | |||
1850 | async_writev_out: | ||
1851 | cifs_small_buf_release(smb); | ||
1852 | kfree(iov); | ||
1853 | return rc; | ||
1854 | } | ||
1855 | |||
1562 | int | 1856 | int |
1563 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1857 | CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms, |
1564 | const int netfid, const unsigned int count, | 1858 | unsigned int *nbytes, struct kvec *iov, int n_vec, |
1565 | const __u64 offset, unsigned int *nbytes, struct kvec *iov, | 1859 | const int long_op) |
1566 | int n_vec, const int long_op) | ||
1567 | { | 1860 | { |
1568 | int rc = -EACCES; | 1861 | int rc = -EACCES; |
1569 | WRITE_REQ *pSMB = NULL; | 1862 | WRITE_REQ *pSMB = NULL; |
1570 | int wct; | 1863 | int wct; |
1571 | int smb_hdr_len; | 1864 | int smb_hdr_len; |
1572 | int resp_buf_type = 0; | 1865 | int resp_buf_type = 0; |
1866 | __u32 pid = io_parms->pid; | ||
1867 | __u16 netfid = io_parms->netfid; | ||
1868 | __u64 offset = io_parms->offset; | ||
1869 | struct cifs_tcon *tcon = io_parms->tcon; | ||
1870 | unsigned int count = io_parms->length; | ||
1573 | 1871 | ||
1574 | *nbytes = 0; | 1872 | *nbytes = 0; |
1575 | 1873 | ||
@@ -1587,6 +1885,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1587 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); | 1885 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); |
1588 | if (rc) | 1886 | if (rc) |
1589 | return rc; | 1887 | return rc; |
1888 | |||
1889 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid); | ||
1890 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16)); | ||
1891 | |||
1590 | /* tcon and ses pointer are checked in smb_init */ | 1892 | /* tcon and ses pointer are checked in smb_init */ |
1591 | if (tcon->ses->server == NULL) | 1893 | if (tcon->ses->server == NULL) |
1592 | return -ECONNABORTED; | 1894 | return -ECONNABORTED; |
@@ -1605,11 +1907,12 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1605 | 1907 | ||
1606 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); | 1908 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); |
1607 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); | 1909 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); |
1608 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ | 1910 | /* header + 1 byte pad */ |
1911 | smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1; | ||
1609 | if (wct == 14) | 1912 | if (wct == 14) |
1610 | pSMB->hdr.smb_buf_length += count+1; | 1913 | inc_rfc1001_len(pSMB, count + 1); |
1611 | else /* wct == 12 */ | 1914 | else /* wct == 12 */ |
1612 | pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ | 1915 | inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */ |
1613 | if (wct == 14) | 1916 | if (wct == 14) |
1614 | pSMB->ByteCount = cpu_to_le16(count + 1); | 1917 | pSMB->ByteCount = cpu_to_le16(count + 1); |
1615 | else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { | 1918 | else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { |
@@ -1661,10 +1964,11 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1661 | 1964 | ||
1662 | 1965 | ||
1663 | int | 1966 | int |
1664 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 1967 | CIFSSMBLock(const int xid, struct cifs_tcon *tcon, |
1665 | const __u16 smb_file_id, const __u64 len, | 1968 | const __u16 smb_file_id, const __u64 len, |
1666 | const __u64 offset, const __u32 numUnlock, | 1969 | const __u64 offset, const __u32 numUnlock, |
1667 | const __u32 numLock, const __u8 lockType, const bool waitFlag) | 1970 | const __u32 numLock, const __u8 lockType, |
1971 | const bool waitFlag, const __u8 oplock_level) | ||
1668 | { | 1972 | { |
1669 | int rc = 0; | 1973 | int rc = 0; |
1670 | LOCK_REQ *pSMB = NULL; | 1974 | LOCK_REQ *pSMB = NULL; |
@@ -1692,6 +1996,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1692 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | 1996 | pSMB->NumberOfLocks = cpu_to_le16(numLock); |
1693 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | 1997 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); |
1694 | pSMB->LockType = lockType; | 1998 | pSMB->LockType = lockType; |
1999 | pSMB->OplockLevel = oplock_level; | ||
1695 | pSMB->AndXCommand = 0xFF; /* none */ | 2000 | pSMB->AndXCommand = 0xFF; /* none */ |
1696 | pSMB->Fid = smb_file_id; /* netfid stays le */ | 2001 | pSMB->Fid = smb_file_id; /* netfid stays le */ |
1697 | 2002 | ||
@@ -1707,7 +2012,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1707 | /* oplock break */ | 2012 | /* oplock break */ |
1708 | count = 0; | 2013 | count = 0; |
1709 | } | 2014 | } |
1710 | pSMB->hdr.smb_buf_length += count; | 2015 | inc_rfc1001_len(pSMB, count); |
1711 | pSMB->ByteCount = cpu_to_le16(count); | 2016 | pSMB->ByteCount = cpu_to_le16(count); |
1712 | 2017 | ||
1713 | if (waitFlag) { | 2018 | if (waitFlag) { |
@@ -1729,7 +2034,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1729 | } | 2034 | } |
1730 | 2035 | ||
1731 | int | 2036 | int |
1732 | CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | 2037 | CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, |
1733 | const __u16 smb_file_id, const int get_flag, const __u64 len, | 2038 | const __u16 smb_file_id, const int get_flag, const __u64 len, |
1734 | struct file_lock *pLockData, const __u16 lock_type, | 2039 | struct file_lock *pLockData, const __u16 lock_type, |
1735 | const bool waitFlag) | 2040 | const bool waitFlag) |
@@ -1798,14 +2103,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1798 | pSMB->Fid = smb_file_id; | 2103 | pSMB->Fid = smb_file_id; |
1799 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); | 2104 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK); |
1800 | pSMB->Reserved4 = 0; | 2105 | pSMB->Reserved4 = 0; |
1801 | pSMB->hdr.smb_buf_length += byte_count; | 2106 | inc_rfc1001_len(pSMB, byte_count); |
1802 | pSMB->ByteCount = cpu_to_le16(byte_count); | 2107 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1803 | if (waitFlag) { | 2108 | if (waitFlag) { |
1804 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, | 2109 | rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, |
1805 | (struct smb_hdr *) pSMBr, &bytes_returned); | 2110 | (struct smb_hdr *) pSMBr, &bytes_returned); |
1806 | } else { | 2111 | } else { |
1807 | iov[0].iov_base = (char *)pSMB; | 2112 | iov[0].iov_base = (char *)pSMB; |
1808 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 2113 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; |
1809 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 2114 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
1810 | &resp_buf_type, timeout); | 2115 | &resp_buf_type, timeout); |
1811 | pSMB = NULL; /* request buf already freed by SendReceive2. Do | 2116 | pSMB = NULL; /* request buf already freed by SendReceive2. Do |
@@ -1821,7 +2126,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1821 | __u16 data_count; | 2126 | __u16 data_count; |
1822 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 2127 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
1823 | 2128 | ||
1824 | if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) { | 2129 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { |
1825 | rc = -EIO; /* bad smb */ | 2130 | rc = -EIO; /* bad smb */ |
1826 | goto plk_err_exit; | 2131 | goto plk_err_exit; |
1827 | } | 2132 | } |
@@ -1843,10 +2148,10 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | |||
1843 | __constant_cpu_to_le16(CIFS_WRLCK)) | 2148 | __constant_cpu_to_le16(CIFS_WRLCK)) |
1844 | pLockData->fl_type = F_WRLCK; | 2149 | pLockData->fl_type = F_WRLCK; |
1845 | 2150 | ||
1846 | pLockData->fl_start = parm_data->start; | 2151 | pLockData->fl_start = le64_to_cpu(parm_data->start); |
1847 | pLockData->fl_end = parm_data->start + | 2152 | pLockData->fl_end = pLockData->fl_start + |
1848 | parm_data->length - 1; | 2153 | le64_to_cpu(parm_data->length) - 1; |
1849 | pLockData->fl_pid = parm_data->pid; | 2154 | pLockData->fl_pid = le32_to_cpu(parm_data->pid); |
1850 | } | 2155 | } |
1851 | } | 2156 | } |
1852 | 2157 | ||
@@ -1867,7 +2172,7 @@ plk_err_exit: | |||
1867 | 2172 | ||
1868 | 2173 | ||
1869 | int | 2174 | int |
1870 | CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | 2175 | CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id) |
1871 | { | 2176 | { |
1872 | int rc = 0; | 2177 | int rc = 0; |
1873 | CLOSE_REQ *pSMB = NULL; | 2178 | CLOSE_REQ *pSMB = NULL; |
@@ -1900,7 +2205,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
1900 | } | 2205 | } |
1901 | 2206 | ||
1902 | int | 2207 | int |
1903 | CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | 2208 | CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id) |
1904 | { | 2209 | { |
1905 | int rc = 0; | 2210 | int rc = 0; |
1906 | FLUSH_REQ *pSMB = NULL; | 2211 | FLUSH_REQ *pSMB = NULL; |
@@ -1921,7 +2226,7 @@ CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
1921 | } | 2226 | } |
1922 | 2227 | ||
1923 | int | 2228 | int |
1924 | CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, | 2229 | CIFSSMBRename(const int xid, struct cifs_tcon *tcon, |
1925 | const char *fromName, const char *toName, | 2230 | const char *fromName, const char *toName, |
1926 | const struct nls_table *nls_codepage, int remap) | 2231 | const struct nls_table *nls_codepage, int remap) |
1927 | { | 2232 | { |
@@ -1971,7 +2276,7 @@ renameRetry: | |||
1971 | } | 2276 | } |
1972 | 2277 | ||
1973 | count = 1 /* 1st signature byte */ + name_len + name_len2; | 2278 | count = 1 /* 1st signature byte */ + name_len + name_len2; |
1974 | pSMB->hdr.smb_buf_length += count; | 2279 | inc_rfc1001_len(pSMB, count); |
1975 | pSMB->ByteCount = cpu_to_le16(count); | 2280 | pSMB->ByteCount = cpu_to_le16(count); |
1976 | 2281 | ||
1977 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2282 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -1988,7 +2293,7 @@ renameRetry: | |||
1988 | return rc; | 2293 | return rc; |
1989 | } | 2294 | } |
1990 | 2295 | ||
1991 | int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, | 2296 | int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon, |
1992 | int netfid, const char *target_name, | 2297 | int netfid, const char *target_name, |
1993 | const struct nls_table *nls_codepage, int remap) | 2298 | const struct nls_table *nls_codepage, int remap) |
1994 | { | 2299 | { |
@@ -2051,7 +2356,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, | |||
2051 | pSMB->InformationLevel = | 2356 | pSMB->InformationLevel = |
2052 | cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); | 2357 | cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); |
2053 | pSMB->Reserved4 = 0; | 2358 | pSMB->Reserved4 = 0; |
2054 | pSMB->hdr.smb_buf_length += byte_count; | 2359 | inc_rfc1001_len(pSMB, byte_count); |
2055 | pSMB->ByteCount = cpu_to_le16(byte_count); | 2360 | pSMB->ByteCount = cpu_to_le16(byte_count); |
2056 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | 2361 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, |
2057 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2362 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -2068,7 +2373,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon, | |||
2068 | } | 2373 | } |
2069 | 2374 | ||
2070 | int | 2375 | int |
2071 | CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName, | 2376 | CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName, |
2072 | const __u16 target_tid, const char *toName, const int flags, | 2377 | const __u16 target_tid, const char *toName, const int flags, |
2073 | const struct nls_table *nls_codepage, int remap) | 2378 | const struct nls_table *nls_codepage, int remap) |
2074 | { | 2379 | { |
@@ -2118,7 +2423,7 @@ copyRetry: | |||
2118 | } | 2423 | } |
2119 | 2424 | ||
2120 | count = 1 /* 1st signature byte */ + name_len + name_len2; | 2425 | count = 1 /* 1st signature byte */ + name_len + name_len2; |
2121 | pSMB->hdr.smb_buf_length += count; | 2426 | inc_rfc1001_len(pSMB, count); |
2122 | pSMB->ByteCount = cpu_to_le16(count); | 2427 | pSMB->ByteCount = cpu_to_le16(count); |
2123 | 2428 | ||
2124 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2429 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -2136,7 +2441,7 @@ copyRetry: | |||
2136 | } | 2441 | } |
2137 | 2442 | ||
2138 | int | 2443 | int |
2139 | CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, | 2444 | CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon, |
2140 | const char *fromName, const char *toName, | 2445 | const char *fromName, const char *toName, |
2141 | const struct nls_table *nls_codepage) | 2446 | const struct nls_table *nls_codepage) |
2142 | { | 2447 | { |
@@ -2208,7 +2513,7 @@ createSymLinkRetry: | |||
2208 | pSMB->DataOffset = cpu_to_le16(offset); | 2513 | pSMB->DataOffset = cpu_to_le16(offset); |
2209 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); | 2514 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); |
2210 | pSMB->Reserved4 = 0; | 2515 | pSMB->Reserved4 = 0; |
2211 | pSMB->hdr.smb_buf_length += byte_count; | 2516 | inc_rfc1001_len(pSMB, byte_count); |
2212 | pSMB->ByteCount = cpu_to_le16(byte_count); | 2517 | pSMB->ByteCount = cpu_to_le16(byte_count); |
2213 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2518 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2214 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2519 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -2225,7 +2530,7 @@ createSymLinkRetry: | |||
2225 | } | 2530 | } |
2226 | 2531 | ||
2227 | int | 2532 | int |
2228 | CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, | 2533 | CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon, |
2229 | const char *fromName, const char *toName, | 2534 | const char *fromName, const char *toName, |
2230 | const struct nls_table *nls_codepage, int remap) | 2535 | const struct nls_table *nls_codepage, int remap) |
2231 | { | 2536 | { |
@@ -2294,7 +2599,7 @@ createHardLinkRetry: | |||
2294 | pSMB->DataOffset = cpu_to_le16(offset); | 2599 | pSMB->DataOffset = cpu_to_le16(offset); |
2295 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); | 2600 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); |
2296 | pSMB->Reserved4 = 0; | 2601 | pSMB->Reserved4 = 0; |
2297 | pSMB->hdr.smb_buf_length += byte_count; | 2602 | inc_rfc1001_len(pSMB, byte_count); |
2298 | pSMB->ByteCount = cpu_to_le16(byte_count); | 2603 | pSMB->ByteCount = cpu_to_le16(byte_count); |
2299 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2604 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2300 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2605 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -2310,7 +2615,7 @@ createHardLinkRetry: | |||
2310 | } | 2615 | } |
2311 | 2616 | ||
2312 | int | 2617 | int |
2313 | CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, | 2618 | CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon, |
2314 | const char *fromName, const char *toName, | 2619 | const char *fromName, const char *toName, |
2315 | const struct nls_table *nls_codepage, int remap) | 2620 | const struct nls_table *nls_codepage, int remap) |
2316 | { | 2621 | { |
@@ -2365,7 +2670,7 @@ winCreateHardLinkRetry: | |||
2365 | } | 2670 | } |
2366 | 2671 | ||
2367 | count = 1 /* string type byte */ + name_len + name_len2; | 2672 | count = 1 /* string type byte */ + name_len + name_len2; |
2368 | pSMB->hdr.smb_buf_length += count; | 2673 | inc_rfc1001_len(pSMB, count); |
2369 | pSMB->ByteCount = cpu_to_le16(count); | 2674 | pSMB->ByteCount = cpu_to_le16(count); |
2370 | 2675 | ||
2371 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2676 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -2382,7 +2687,7 @@ winCreateHardLinkRetry: | |||
2382 | } | 2687 | } |
2383 | 2688 | ||
2384 | int | 2689 | int |
2385 | CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, | 2690 | CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon, |
2386 | const unsigned char *searchName, char **symlinkinfo, | 2691 | const unsigned char *searchName, char **symlinkinfo, |
2387 | const struct nls_table *nls_codepage) | 2692 | const struct nls_table *nls_codepage) |
2388 | { | 2693 | { |
@@ -2436,7 +2741,7 @@ querySymLinkRetry: | |||
2436 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 2741 | pSMB->ParameterCount = pSMB->TotalParameterCount; |
2437 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); | 2742 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); |
2438 | pSMB->Reserved4 = 0; | 2743 | pSMB->Reserved4 = 0; |
2439 | pSMB->hdr.smb_buf_length += byte_count; | 2744 | inc_rfc1001_len(pSMB, byte_count); |
2440 | pSMB->ByteCount = cpu_to_le16(byte_count); | 2745 | pSMB->ByteCount = cpu_to_le16(byte_count); |
2441 | 2746 | ||
2442 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2747 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -2448,7 +2753,7 @@ querySymLinkRetry: | |||
2448 | 2753 | ||
2449 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 2754 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
2450 | /* BB also check enough total bytes returned */ | 2755 | /* BB also check enough total bytes returned */ |
2451 | if (rc || (pSMBr->ByteCount < 2)) | 2756 | if (rc || get_bcc(&pSMBr->hdr) < 2) |
2452 | rc = -EIO; | 2757 | rc = -EIO; |
2453 | else { | 2758 | else { |
2454 | bool is_unicode; | 2759 | bool is_unicode; |
@@ -2475,98 +2780,19 @@ querySymLinkRetry: | |||
2475 | return rc; | 2780 | return rc; |
2476 | } | 2781 | } |
2477 | 2782 | ||
2478 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 2783 | #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL |
2479 | /* Initialize NT TRANSACT SMB into small smb request buffer. | 2784 | /* |
2480 | This assumes that all NT TRANSACTS that we init here have | 2785 | * Recent Windows versions now create symlinks more frequently |
2481 | total parm and data under about 400 bytes (to fit in small cifs | 2786 | * and they use the "reparse point" mechanism below. We can of course |
2482 | buffer size), which is the case so far, it easily fits. NB: | 2787 | * do symlinks nicely to Samba and other servers which support the |
2483 | Setup words themselves and ByteCount | 2788 | * CIFS Unix Extensions and we can also do SFU symlinks and "client only" |
2484 | MaxSetupCount (size of returned setup area) and | 2789 | * "MF" symlinks optionally, but for recent Windows we really need to |
2485 | MaxParameterCount (returned parms size) must be set by caller */ | 2790 | * reenable the code below and fix the cifs_symlink callers to handle this. |
2486 | static int | 2791 | * In the interim this code has been moved to its own config option so |
2487 | smb_init_nttransact(const __u16 sub_command, const int setup_count, | 2792 | * it is not compiled in by default until callers fixed up and more tested. |
2488 | const int parm_len, struct cifsTconInfo *tcon, | 2793 | */ |
2489 | void **ret_buf) | ||
2490 | { | ||
2491 | int rc; | ||
2492 | __u32 temp_offset; | ||
2493 | struct smb_com_ntransact_req *pSMB; | ||
2494 | |||
2495 | rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, | ||
2496 | (void **)&pSMB); | ||
2497 | if (rc) | ||
2498 | return rc; | ||
2499 | *ret_buf = (void *)pSMB; | ||
2500 | pSMB->Reserved = 0; | ||
2501 | pSMB->TotalParameterCount = cpu_to_le32(parm_len); | ||
2502 | pSMB->TotalDataCount = 0; | ||
2503 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
2504 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
2505 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2506 | pSMB->DataCount = pSMB->TotalDataCount; | ||
2507 | temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + | ||
2508 | (setup_count * 2) - 4 /* for rfc1001 length itself */; | ||
2509 | pSMB->ParameterOffset = cpu_to_le32(temp_offset); | ||
2510 | pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); | ||
2511 | pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ | ||
2512 | pSMB->SubCommand = cpu_to_le16(sub_command); | ||
2513 | return 0; | ||
2514 | } | ||
2515 | |||
2516 | static int | ||
2517 | validate_ntransact(char *buf, char **ppparm, char **ppdata, | ||
2518 | __u32 *pparmlen, __u32 *pdatalen) | ||
2519 | { | ||
2520 | char *end_of_smb; | ||
2521 | __u32 data_count, data_offset, parm_count, parm_offset; | ||
2522 | struct smb_com_ntransact_rsp *pSMBr; | ||
2523 | |||
2524 | *pdatalen = 0; | ||
2525 | *pparmlen = 0; | ||
2526 | |||
2527 | if (buf == NULL) | ||
2528 | return -EINVAL; | ||
2529 | |||
2530 | pSMBr = (struct smb_com_ntransact_rsp *)buf; | ||
2531 | |||
2532 | /* ByteCount was converted from little endian in SendReceive */ | ||
2533 | end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + | ||
2534 | (char *)&pSMBr->ByteCount; | ||
2535 | |||
2536 | data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
2537 | data_count = le32_to_cpu(pSMBr->DataCount); | ||
2538 | parm_offset = le32_to_cpu(pSMBr->ParameterOffset); | ||
2539 | parm_count = le32_to_cpu(pSMBr->ParameterCount); | ||
2540 | |||
2541 | *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; | ||
2542 | *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; | ||
2543 | |||
2544 | /* should we also check that parm and data areas do not overlap? */ | ||
2545 | if (*ppparm > end_of_smb) { | ||
2546 | cFYI(1, "parms start after end of smb"); | ||
2547 | return -EINVAL; | ||
2548 | } else if (parm_count + *ppparm > end_of_smb) { | ||
2549 | cFYI(1, "parm end after end of smb"); | ||
2550 | return -EINVAL; | ||
2551 | } else if (*ppdata > end_of_smb) { | ||
2552 | cFYI(1, "data starts after end of smb"); | ||
2553 | return -EINVAL; | ||
2554 | } else if (data_count + *ppdata > end_of_smb) { | ||
2555 | cFYI(1, "data %p + count %d (%p) past smb end %p start %p", | ||
2556 | *ppdata, data_count, (data_count + *ppdata), | ||
2557 | end_of_smb, pSMBr); | ||
2558 | return -EINVAL; | ||
2559 | } else if (parm_count + data_count > pSMBr->ByteCount) { | ||
2560 | cFYI(1, "parm count and data count larger than SMB"); | ||
2561 | return -EINVAL; | ||
2562 | } | ||
2563 | *pdatalen = data_count; | ||
2564 | *pparmlen = parm_count; | ||
2565 | return 0; | ||
2566 | } | ||
2567 | |||
2568 | int | 2794 | int |
2569 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | 2795 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon, |
2570 | const unsigned char *searchName, | 2796 | const unsigned char *searchName, |
2571 | char *symlinkinfo, const int buflen, __u16 fid, | 2797 | char *symlinkinfo, const int buflen, __u16 fid, |
2572 | const struct nls_table *nls_codepage) | 2798 | const struct nls_table *nls_codepage) |
@@ -2609,14 +2835,14 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
2609 | } else { /* decode response */ | 2835 | } else { /* decode response */ |
2610 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); | 2836 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); |
2611 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); | 2837 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); |
2612 | if ((pSMBr->ByteCount < 2) || (data_offset > 512)) { | 2838 | if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { |
2613 | /* BB also check enough total bytes returned */ | 2839 | /* BB also check enough total bytes returned */ |
2614 | rc = -EIO; /* bad smb */ | 2840 | rc = -EIO; /* bad smb */ |
2615 | goto qreparse_out; | 2841 | goto qreparse_out; |
2616 | } | 2842 | } |
2617 | if (data_count && (data_count < 2048)) { | 2843 | if (data_count && (data_count < 2048)) { |
2618 | char *end_of_smb = 2 /* sizeof byte count */ + | 2844 | char *end_of_smb = 2 /* sizeof byte count */ + |
2619 | pSMBr->ByteCount + (char *)&pSMBr->ByteCount; | 2845 | get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; |
2620 | 2846 | ||
2621 | struct reparse_data *reparse_buf = | 2847 | struct reparse_data *reparse_buf = |
2622 | (struct reparse_data *) | 2848 | (struct reparse_data *) |
@@ -2666,7 +2892,7 @@ qreparse_out: | |||
2666 | 2892 | ||
2667 | return rc; | 2893 | return rc; |
2668 | } | 2894 | } |
2669 | #endif /* CIFS_EXPERIMENTAL */ | 2895 | #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ |
2670 | 2896 | ||
2671 | #ifdef CONFIG_CIFS_POSIX | 2897 | #ifdef CONFIG_CIFS_POSIX |
2672 | 2898 | ||
@@ -2804,7 +3030,7 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL, | |||
2804 | } | 3030 | } |
2805 | 3031 | ||
2806 | int | 3032 | int |
2807 | CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | 3033 | CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon, |
2808 | const unsigned char *searchName, | 3034 | const unsigned char *searchName, |
2809 | char *acl_inf, const int buflen, const int acl_type, | 3035 | char *acl_inf, const int buflen, const int acl_type, |
2810 | const struct nls_table *nls_codepage, int remap) | 3036 | const struct nls_table *nls_codepage, int remap) |
@@ -2862,7 +3088,7 @@ queryAclRetry: | |||
2862 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 3088 | pSMB->ParameterCount = pSMB->TotalParameterCount; |
2863 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); | 3089 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL); |
2864 | pSMB->Reserved4 = 0; | 3090 | pSMB->Reserved4 = 0; |
2865 | pSMB->hdr.smb_buf_length += byte_count; | 3091 | inc_rfc1001_len(pSMB, byte_count); |
2866 | pSMB->ByteCount = cpu_to_le16(byte_count); | 3092 | pSMB->ByteCount = cpu_to_le16(byte_count); |
2867 | 3093 | ||
2868 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3094 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -2874,8 +3100,8 @@ queryAclRetry: | |||
2874 | /* decode response */ | 3100 | /* decode response */ |
2875 | 3101 | ||
2876 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3102 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
2877 | if (rc || (pSMBr->ByteCount < 2)) | ||
2878 | /* BB also check enough total bytes returned */ | 3103 | /* BB also check enough total bytes returned */ |
3104 | if (rc || get_bcc(&pSMBr->hdr) < 2) | ||
2879 | rc = -EIO; /* bad smb */ | 3105 | rc = -EIO; /* bad smb */ |
2880 | else { | 3106 | else { |
2881 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 3107 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
@@ -2892,7 +3118,7 @@ queryAclRetry: | |||
2892 | } | 3118 | } |
2893 | 3119 | ||
2894 | int | 3120 | int |
2895 | CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, | 3121 | CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon, |
2896 | const unsigned char *fileName, | 3122 | const unsigned char *fileName, |
2897 | const char *local_acl, const int buflen, | 3123 | const char *local_acl, const int buflen, |
2898 | const int acl_type, | 3124 | const int acl_type, |
@@ -2956,7 +3182,7 @@ setAclRetry: | |||
2956 | pSMB->ParameterCount = cpu_to_le16(params); | 3182 | pSMB->ParameterCount = cpu_to_le16(params); |
2957 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 3183 | pSMB->TotalParameterCount = pSMB->ParameterCount; |
2958 | pSMB->Reserved4 = 0; | 3184 | pSMB->Reserved4 = 0; |
2959 | pSMB->hdr.smb_buf_length += byte_count; | 3185 | inc_rfc1001_len(pSMB, byte_count); |
2960 | pSMB->ByteCount = cpu_to_le16(byte_count); | 3186 | pSMB->ByteCount = cpu_to_le16(byte_count); |
2961 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3187 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2962 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3188 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -2972,7 +3198,7 @@ setACLerrorExit: | |||
2972 | 3198 | ||
2973 | /* BB fix tabs in this function FIXME BB */ | 3199 | /* BB fix tabs in this function FIXME BB */ |
2974 | int | 3200 | int |
2975 | CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon, | 3201 | CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon, |
2976 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask) | 3202 | const int netfid, __u64 *pExtAttrBits, __u64 *pMask) |
2977 | { | 3203 | { |
2978 | int rc = 0; | 3204 | int rc = 0; |
@@ -3014,7 +3240,7 @@ GetExtAttrRetry: | |||
3014 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); | 3240 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS); |
3015 | pSMB->Pad = 0; | 3241 | pSMB->Pad = 0; |
3016 | pSMB->Fid = netfid; | 3242 | pSMB->Fid = netfid; |
3017 | pSMB->hdr.smb_buf_length += byte_count; | 3243 | inc_rfc1001_len(pSMB, byte_count); |
3018 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); | 3244 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); |
3019 | 3245 | ||
3020 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3246 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3024,8 +3250,8 @@ GetExtAttrRetry: | |||
3024 | } else { | 3250 | } else { |
3025 | /* decode response */ | 3251 | /* decode response */ |
3026 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3252 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
3027 | if (rc || (pSMBr->ByteCount < 2)) | ||
3028 | /* BB also check enough total bytes returned */ | 3253 | /* BB also check enough total bytes returned */ |
3254 | if (rc || get_bcc(&pSMBr->hdr) < 2) | ||
3029 | /* If rc should we check for EOPNOSUPP and | 3255 | /* If rc should we check for EOPNOSUPP and |
3030 | disable the srvino flag? or in caller? */ | 3256 | disable the srvino flag? or in caller? */ |
3031 | rc = -EIO; /* bad smb */ | 3257 | rc = -EIO; /* bad smb */ |
@@ -3054,10 +3280,101 @@ GetExtAttrOut: | |||
3054 | 3280 | ||
3055 | #endif /* CONFIG_POSIX */ | 3281 | #endif /* CONFIG_POSIX */ |
3056 | 3282 | ||
3057 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 3283 | #ifdef CONFIG_CIFS_ACL |
3284 | /* | ||
3285 | * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that | ||
3286 | * all NT TRANSACTS that we init here have total parm and data under about 400 | ||
3287 | * bytes (to fit in small cifs buffer size), which is the case so far, it | ||
3288 | * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of | ||
3289 | * returned setup area) and MaxParameterCount (returned parms size) must be set | ||
3290 | * by caller | ||
3291 | */ | ||
3292 | static int | ||
3293 | smb_init_nttransact(const __u16 sub_command, const int setup_count, | ||
3294 | const int parm_len, struct cifs_tcon *tcon, | ||
3295 | void **ret_buf) | ||
3296 | { | ||
3297 | int rc; | ||
3298 | __u32 temp_offset; | ||
3299 | struct smb_com_ntransact_req *pSMB; | ||
3300 | |||
3301 | rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, | ||
3302 | (void **)&pSMB); | ||
3303 | if (rc) | ||
3304 | return rc; | ||
3305 | *ret_buf = (void *)pSMB; | ||
3306 | pSMB->Reserved = 0; | ||
3307 | pSMB->TotalParameterCount = cpu_to_le32(parm_len); | ||
3308 | pSMB->TotalDataCount = 0; | ||
3309 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
3310 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
3311 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3312 | pSMB->DataCount = pSMB->TotalDataCount; | ||
3313 | temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + | ||
3314 | (setup_count * 2) - 4 /* for rfc1001 length itself */; | ||
3315 | pSMB->ParameterOffset = cpu_to_le32(temp_offset); | ||
3316 | pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); | ||
3317 | pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ | ||
3318 | pSMB->SubCommand = cpu_to_le16(sub_command); | ||
3319 | return 0; | ||
3320 | } | ||
3321 | |||
3322 | static int | ||
3323 | validate_ntransact(char *buf, char **ppparm, char **ppdata, | ||
3324 | __u32 *pparmlen, __u32 *pdatalen) | ||
3325 | { | ||
3326 | char *end_of_smb; | ||
3327 | __u32 data_count, data_offset, parm_count, parm_offset; | ||
3328 | struct smb_com_ntransact_rsp *pSMBr; | ||
3329 | u16 bcc; | ||
3330 | |||
3331 | *pdatalen = 0; | ||
3332 | *pparmlen = 0; | ||
3333 | |||
3334 | if (buf == NULL) | ||
3335 | return -EINVAL; | ||
3336 | |||
3337 | pSMBr = (struct smb_com_ntransact_rsp *)buf; | ||
3338 | |||
3339 | bcc = get_bcc(&pSMBr->hdr); | ||
3340 | end_of_smb = 2 /* sizeof byte count */ + bcc + | ||
3341 | (char *)&pSMBr->ByteCount; | ||
3342 | |||
3343 | data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
3344 | data_count = le32_to_cpu(pSMBr->DataCount); | ||
3345 | parm_offset = le32_to_cpu(pSMBr->ParameterOffset); | ||
3346 | parm_count = le32_to_cpu(pSMBr->ParameterCount); | ||
3347 | |||
3348 | *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; | ||
3349 | *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; | ||
3350 | |||
3351 | /* should we also check that parm and data areas do not overlap? */ | ||
3352 | if (*ppparm > end_of_smb) { | ||
3353 | cFYI(1, "parms start after end of smb"); | ||
3354 | return -EINVAL; | ||
3355 | } else if (parm_count + *ppparm > end_of_smb) { | ||
3356 | cFYI(1, "parm end after end of smb"); | ||
3357 | return -EINVAL; | ||
3358 | } else if (*ppdata > end_of_smb) { | ||
3359 | cFYI(1, "data starts after end of smb"); | ||
3360 | return -EINVAL; | ||
3361 | } else if (data_count + *ppdata > end_of_smb) { | ||
3362 | cFYI(1, "data %p + count %d (%p) past smb end %p start %p", | ||
3363 | *ppdata, data_count, (data_count + *ppdata), | ||
3364 | end_of_smb, pSMBr); | ||
3365 | return -EINVAL; | ||
3366 | } else if (parm_count + data_count > bcc) { | ||
3367 | cFYI(1, "parm count and data count larger than SMB"); | ||
3368 | return -EINVAL; | ||
3369 | } | ||
3370 | *pdatalen = data_count; | ||
3371 | *pparmlen = parm_count; | ||
3372 | return 0; | ||
3373 | } | ||
3374 | |||
3058 | /* Get Security Descriptor (by handle) from remote server for a file or dir */ | 3375 | /* Get Security Descriptor (by handle) from remote server for a file or dir */ |
3059 | int | 3376 | int |
3060 | CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | 3377 | CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid, |
3061 | struct cifs_ntsd **acl_inf, __u32 *pbuflen) | 3378 | struct cifs_ntsd **acl_inf, __u32 *pbuflen) |
3062 | { | 3379 | { |
3063 | int rc = 0; | 3380 | int rc = 0; |
@@ -3082,12 +3399,12 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | |||
3082 | pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | | 3399 | pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | |
3083 | CIFS_ACL_DACL); | 3400 | CIFS_ACL_DACL); |
3084 | pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ | 3401 | pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ |
3085 | pSMB->hdr.smb_buf_length += 11; | 3402 | inc_rfc1001_len(pSMB, 11); |
3086 | iov[0].iov_base = (char *)pSMB; | 3403 | iov[0].iov_base = (char *)pSMB; |
3087 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 3404 | iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4; |
3088 | 3405 | ||
3089 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 3406 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
3090 | CIFS_STD_OP); | 3407 | 0); |
3091 | cifs_stats_inc(&tcon->num_acl_get); | 3408 | cifs_stats_inc(&tcon->num_acl_get); |
3092 | if (rc) { | 3409 | if (rc) { |
3093 | cFYI(1, "Send error in QuerySecDesc = %d", rc); | 3410 | cFYI(1, "Send error in QuerySecDesc = %d", rc); |
@@ -3149,7 +3466,7 @@ qsec_out: | |||
3149 | } | 3466 | } |
3150 | 3467 | ||
3151 | int | 3468 | int |
3152 | CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | 3469 | CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid, |
3153 | struct cifs_ntsd *pntsd, __u32 acllen) | 3470 | struct cifs_ntsd *pntsd, __u32 acllen) |
3154 | { | 3471 | { |
3155 | __u16 byte_count, param_count, data_count, param_offset, data_offset; | 3472 | __u16 byte_count, param_count, data_count, param_offset, data_offset; |
@@ -3193,10 +3510,9 @@ setCifsAclRetry: | |||
3193 | memcpy((char *) &pSMBr->hdr.Protocol + data_offset, | 3510 | memcpy((char *) &pSMBr->hdr.Protocol + data_offset, |
3194 | (char *) pntsd, | 3511 | (char *) pntsd, |
3195 | acllen); | 3512 | acllen); |
3196 | pSMB->hdr.smb_buf_length += (byte_count + data_count); | 3513 | inc_rfc1001_len(pSMB, byte_count + data_count); |
3197 | |||
3198 | } else | 3514 | } else |
3199 | pSMB->hdr.smb_buf_length += byte_count; | 3515 | inc_rfc1001_len(pSMB, byte_count); |
3200 | 3516 | ||
3201 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3517 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
3202 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3518 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -3212,11 +3528,11 @@ setCifsAclRetry: | |||
3212 | return (rc); | 3528 | return (rc); |
3213 | } | 3529 | } |
3214 | 3530 | ||
3215 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 3531 | #endif /* CONFIG_CIFS_ACL */ |
3216 | 3532 | ||
3217 | /* Legacy Query Path Information call for lookup to old servers such | 3533 | /* Legacy Query Path Information call for lookup to old servers such |
3218 | as Win9x/WinME */ | 3534 | as Win9x/WinME */ |
3219 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | 3535 | int SMBQueryInformation(const int xid, struct cifs_tcon *tcon, |
3220 | const unsigned char *searchName, | 3536 | const unsigned char *searchName, |
3221 | FILE_ALL_INFO *pFinfo, | 3537 | FILE_ALL_INFO *pFinfo, |
3222 | const struct nls_table *nls_codepage, int remap) | 3538 | const struct nls_table *nls_codepage, int remap) |
@@ -3247,7 +3563,7 @@ QInfRetry: | |||
3247 | } | 3563 | } |
3248 | pSMB->BufferFormat = 0x04; | 3564 | pSMB->BufferFormat = 0x04; |
3249 | name_len++; /* account for buffer type byte */ | 3565 | name_len++; /* account for buffer type byte */ |
3250 | pSMB->hdr.smb_buf_length += (__u16) name_len; | 3566 | inc_rfc1001_len(pSMB, (__u16)name_len); |
3251 | pSMB->ByteCount = cpu_to_le16(name_len); | 3567 | pSMB->ByteCount = cpu_to_le16(name_len); |
3252 | 3568 | ||
3253 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3569 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3284,7 +3600,7 @@ QInfRetry: | |||
3284 | } | 3600 | } |
3285 | 3601 | ||
3286 | int | 3602 | int |
3287 | CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon, | 3603 | CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon, |
3288 | u16 netfid, FILE_ALL_INFO *pFindData) | 3604 | u16 netfid, FILE_ALL_INFO *pFindData) |
3289 | { | 3605 | { |
3290 | struct smb_t2_qfi_req *pSMB = NULL; | 3606 | struct smb_t2_qfi_req *pSMB = NULL; |
@@ -3322,7 +3638,7 @@ QFileInfoRetry: | |||
3322 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); | 3638 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); |
3323 | pSMB->Pad = 0; | 3639 | pSMB->Pad = 0; |
3324 | pSMB->Fid = netfid; | 3640 | pSMB->Fid = netfid; |
3325 | pSMB->hdr.smb_buf_length += byte_count; | 3641 | inc_rfc1001_len(pSMB, byte_count); |
3326 | 3642 | ||
3327 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3643 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
3328 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3644 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -3333,7 +3649,7 @@ QFileInfoRetry: | |||
3333 | 3649 | ||
3334 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ | 3650 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ |
3335 | rc = -EIO; | 3651 | rc = -EIO; |
3336 | else if (pSMBr->ByteCount < 40) | 3652 | else if (get_bcc(&pSMBr->hdr) < 40) |
3337 | rc = -EIO; /* bad smb */ | 3653 | rc = -EIO; /* bad smb */ |
3338 | else if (pFindData) { | 3654 | else if (pFindData) { |
3339 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 3655 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
@@ -3351,7 +3667,7 @@ QFileInfoRetry: | |||
3351 | } | 3667 | } |
3352 | 3668 | ||
3353 | int | 3669 | int |
3354 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 3670 | CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon, |
3355 | const unsigned char *searchName, | 3671 | const unsigned char *searchName, |
3356 | FILE_ALL_INFO *pFindData, | 3672 | FILE_ALL_INFO *pFindData, |
3357 | int legacy /* old style infolevel */, | 3673 | int legacy /* old style infolevel */, |
@@ -3409,7 +3725,7 @@ QPathInfoRetry: | |||
3409 | else | 3725 | else |
3410 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); | 3726 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); |
3411 | pSMB->Reserved4 = 0; | 3727 | pSMB->Reserved4 = 0; |
3412 | pSMB->hdr.smb_buf_length += byte_count; | 3728 | inc_rfc1001_len(pSMB, byte_count); |
3413 | pSMB->ByteCount = cpu_to_le16(byte_count); | 3729 | pSMB->ByteCount = cpu_to_le16(byte_count); |
3414 | 3730 | ||
3415 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3731 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3421,9 +3737,9 @@ QPathInfoRetry: | |||
3421 | 3737 | ||
3422 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ | 3738 | if (rc) /* BB add auto retry on EOPNOTSUPP? */ |
3423 | rc = -EIO; | 3739 | rc = -EIO; |
3424 | else if (!legacy && (pSMBr->ByteCount < 40)) | 3740 | else if (!legacy && get_bcc(&pSMBr->hdr) < 40) |
3425 | rc = -EIO; /* bad smb */ | 3741 | rc = -EIO; /* bad smb */ |
3426 | else if (legacy && (pSMBr->ByteCount < 24)) | 3742 | else if (legacy && get_bcc(&pSMBr->hdr) < 24) |
3427 | rc = -EIO; /* 24 or 26 expected but we do not read | 3743 | rc = -EIO; /* 24 or 26 expected but we do not read |
3428 | last field */ | 3744 | last field */ |
3429 | else if (pFindData) { | 3745 | else if (pFindData) { |
@@ -3452,7 +3768,7 @@ QPathInfoRetry: | |||
3452 | } | 3768 | } |
3453 | 3769 | ||
3454 | int | 3770 | int |
3455 | CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon, | 3771 | CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon, |
3456 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData) | 3772 | u16 netfid, FILE_UNIX_BASIC_INFO *pFindData) |
3457 | { | 3773 | { |
3458 | struct smb_t2_qfi_req *pSMB = NULL; | 3774 | struct smb_t2_qfi_req *pSMB = NULL; |
@@ -3490,7 +3806,7 @@ UnixQFileInfoRetry: | |||
3490 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | 3806 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); |
3491 | pSMB->Pad = 0; | 3807 | pSMB->Pad = 0; |
3492 | pSMB->Fid = netfid; | 3808 | pSMB->Fid = netfid; |
3493 | pSMB->hdr.smb_buf_length += byte_count; | 3809 | inc_rfc1001_len(pSMB, byte_count); |
3494 | 3810 | ||
3495 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3811 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
3496 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3812 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -3499,7 +3815,7 @@ UnixQFileInfoRetry: | |||
3499 | } else { /* decode response */ | 3815 | } else { /* decode response */ |
3500 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3816 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
3501 | 3817 | ||
3502 | if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { | 3818 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { |
3503 | cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" | 3819 | cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" |
3504 | "Unix Extensions can be disabled on mount " | 3820 | "Unix Extensions can be disabled on mount " |
3505 | "by specifying the nosfu mount option."); | 3821 | "by specifying the nosfu mount option."); |
@@ -3521,7 +3837,7 @@ UnixQFileInfoRetry: | |||
3521 | } | 3837 | } |
3522 | 3838 | ||
3523 | int | 3839 | int |
3524 | CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, | 3840 | CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon, |
3525 | const unsigned char *searchName, | 3841 | const unsigned char *searchName, |
3526 | FILE_UNIX_BASIC_INFO *pFindData, | 3842 | FILE_UNIX_BASIC_INFO *pFindData, |
3527 | const struct nls_table *nls_codepage, int remap) | 3843 | const struct nls_table *nls_codepage, int remap) |
@@ -3575,7 +3891,7 @@ UnixQPathInfoRetry: | |||
3575 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 3891 | pSMB->ParameterCount = pSMB->TotalParameterCount; |
3576 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); | 3892 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); |
3577 | pSMB->Reserved4 = 0; | 3893 | pSMB->Reserved4 = 0; |
3578 | pSMB->hdr.smb_buf_length += byte_count; | 3894 | inc_rfc1001_len(pSMB, byte_count); |
3579 | pSMB->ByteCount = cpu_to_le16(byte_count); | 3895 | pSMB->ByteCount = cpu_to_le16(byte_count); |
3580 | 3896 | ||
3581 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3897 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3585,7 +3901,7 @@ UnixQPathInfoRetry: | |||
3585 | } else { /* decode response */ | 3901 | } else { /* decode response */ |
3586 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3902 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
3587 | 3903 | ||
3588 | if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { | 3904 | if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { |
3589 | cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" | 3905 | cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n" |
3590 | "Unix Extensions can be disabled on mount " | 3906 | "Unix Extensions can be disabled on mount " |
3591 | "by specifying the nosfu mount option."); | 3907 | "by specifying the nosfu mount option."); |
@@ -3607,7 +3923,7 @@ UnixQPathInfoRetry: | |||
3607 | 3923 | ||
3608 | /* xid, tcon, searchName and codepage are input parms, rest are returned */ | 3924 | /* xid, tcon, searchName and codepage are input parms, rest are returned */ |
3609 | int | 3925 | int |
3610 | CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 3926 | CIFSFindFirst(const int xid, struct cifs_tcon *tcon, |
3611 | const char *searchName, | 3927 | const char *searchName, |
3612 | const struct nls_table *nls_codepage, | 3928 | const struct nls_table *nls_codepage, |
3613 | __u16 *pnetfid, | 3929 | __u16 *pnetfid, |
@@ -3689,7 +4005,7 @@ findFirstRetry: | |||
3689 | 4005 | ||
3690 | /* BB what should we set StorageType to? Does it matter? BB */ | 4006 | /* BB what should we set StorageType to? Does it matter? BB */ |
3691 | pSMB->SearchStorageType = 0; | 4007 | pSMB->SearchStorageType = 0; |
3692 | pSMB->hdr.smb_buf_length += byte_count; | 4008 | inc_rfc1001_len(pSMB, byte_count); |
3693 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4009 | pSMB->ByteCount = cpu_to_le16(byte_count); |
3694 | 4010 | ||
3695 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4011 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3755,7 +4071,7 @@ findFirstRetry: | |||
3755 | return rc; | 4071 | return rc; |
3756 | } | 4072 | } |
3757 | 4073 | ||
3758 | int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 4074 | int CIFSFindNext(const int xid, struct cifs_tcon *tcon, |
3759 | __u16 searchHandle, struct cifs_search_info *psrch_inf) | 4075 | __u16 searchHandle, struct cifs_search_info *psrch_inf) |
3760 | { | 4076 | { |
3761 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; | 4077 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; |
@@ -3818,7 +4134,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
3818 | byte_count = params + 1 /* pad */ ; | 4134 | byte_count = params + 1 /* pad */ ; |
3819 | pSMB->TotalParameterCount = cpu_to_le16(params); | 4135 | pSMB->TotalParameterCount = cpu_to_le16(params); |
3820 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 4136 | pSMB->ParameterCount = pSMB->TotalParameterCount; |
3821 | pSMB->hdr.smb_buf_length += byte_count; | 4137 | inc_rfc1001_len(pSMB, byte_count); |
3822 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4138 | pSMB->ByteCount = cpu_to_le16(byte_count); |
3823 | 4139 | ||
3824 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4140 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3893,7 +4209,7 @@ FNext2_err_exit: | |||
3893 | } | 4209 | } |
3894 | 4210 | ||
3895 | int | 4211 | int |
3896 | CIFSFindClose(const int xid, struct cifsTconInfo *tcon, | 4212 | CIFSFindClose(const int xid, struct cifs_tcon *tcon, |
3897 | const __u16 searchHandle) | 4213 | const __u16 searchHandle) |
3898 | { | 4214 | { |
3899 | int rc = 0; | 4215 | int rc = 0; |
@@ -3925,7 +4241,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, | |||
3925 | } | 4241 | } |
3926 | 4242 | ||
3927 | int | 4243 | int |
3928 | CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 4244 | CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon, |
3929 | const unsigned char *searchName, | 4245 | const unsigned char *searchName, |
3930 | __u64 *inode_number, | 4246 | __u64 *inode_number, |
3931 | const struct nls_table *nls_codepage, int remap) | 4247 | const struct nls_table *nls_codepage, int remap) |
@@ -3980,7 +4296,7 @@ GetInodeNumberRetry: | |||
3980 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 4296 | pSMB->ParameterCount = pSMB->TotalParameterCount; |
3981 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); | 4297 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO); |
3982 | pSMB->Reserved4 = 0; | 4298 | pSMB->Reserved4 = 0; |
3983 | pSMB->hdr.smb_buf_length += byte_count; | 4299 | inc_rfc1001_len(pSMB, byte_count); |
3984 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4300 | pSMB->ByteCount = cpu_to_le16(byte_count); |
3985 | 4301 | ||
3986 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4302 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -3990,8 +4306,8 @@ GetInodeNumberRetry: | |||
3990 | } else { | 4306 | } else { |
3991 | /* decode response */ | 4307 | /* decode response */ |
3992 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4308 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
3993 | if (rc || (pSMBr->ByteCount < 2)) | ||
3994 | /* BB also check enough total bytes returned */ | 4309 | /* BB also check enough total bytes returned */ |
4310 | if (rc || get_bcc(&pSMBr->hdr) < 2) | ||
3995 | /* If rc should we check for EOPNOSUPP and | 4311 | /* If rc should we check for EOPNOSUPP and |
3996 | disable the srvino flag? or in caller? */ | 4312 | disable the srvino flag? or in caller? */ |
3997 | rc = -EIO; /* bad smb */ | 4313 | rc = -EIO; /* bad smb */ |
@@ -4127,7 +4443,7 @@ parse_DFS_referrals_exit: | |||
4127 | } | 4443 | } |
4128 | 4444 | ||
4129 | int | 4445 | int |
4130 | CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | 4446 | CIFSGetDFSRefer(const int xid, struct cifs_ses *ses, |
4131 | const unsigned char *searchName, | 4447 | const unsigned char *searchName, |
4132 | struct dfs_info3_param **target_nodes, | 4448 | struct dfs_info3_param **target_nodes, |
4133 | unsigned int *num_of_nodes, | 4449 | unsigned int *num_of_nodes, |
@@ -4176,7 +4492,7 @@ getDFSRetry: | |||
4176 | } | 4492 | } |
4177 | 4493 | ||
4178 | if (ses->server) { | 4494 | if (ses->server) { |
4179 | if (ses->server->secMode & | 4495 | if (ses->server->sec_mode & |
4180 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 4496 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
4181 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 4497 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
4182 | } | 4498 | } |
@@ -4204,7 +4520,7 @@ getDFSRetry: | |||
4204 | pSMB->ParameterCount = cpu_to_le16(params); | 4520 | pSMB->ParameterCount = cpu_to_le16(params); |
4205 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 4521 | pSMB->TotalParameterCount = pSMB->ParameterCount; |
4206 | pSMB->MaxReferralLevel = cpu_to_le16(3); | 4522 | pSMB->MaxReferralLevel = cpu_to_le16(3); |
4207 | pSMB->hdr.smb_buf_length += byte_count; | 4523 | inc_rfc1001_len(pSMB, byte_count); |
4208 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4524 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4209 | 4525 | ||
4210 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 4526 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
@@ -4216,13 +4532,13 @@ getDFSRetry: | |||
4216 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4532 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4217 | 4533 | ||
4218 | /* BB Also check if enough total bytes returned? */ | 4534 | /* BB Also check if enough total bytes returned? */ |
4219 | if (rc || (pSMBr->ByteCount < 17)) { | 4535 | if (rc || get_bcc(&pSMBr->hdr) < 17) { |
4220 | rc = -EIO; /* bad smb */ | 4536 | rc = -EIO; /* bad smb */ |
4221 | goto GetDFSRefExit; | 4537 | goto GetDFSRefExit; |
4222 | } | 4538 | } |
4223 | 4539 | ||
4224 | cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d", | 4540 | cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d", |
4225 | pSMBr->ByteCount, | 4541 | get_bcc(&pSMBr->hdr), |
4226 | le16_to_cpu(pSMBr->t2.DataOffset)); | 4542 | le16_to_cpu(pSMBr->t2.DataOffset)); |
4227 | 4543 | ||
4228 | /* parse returned result into more usable form */ | 4544 | /* parse returned result into more usable form */ |
@@ -4241,7 +4557,7 @@ GetDFSRefExit: | |||
4241 | 4557 | ||
4242 | /* Query File System Info such as free space to old servers such as Win 9x */ | 4558 | /* Query File System Info such as free space to old servers such as Win 9x */ |
4243 | int | 4559 | int |
4244 | SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | 4560 | SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData) |
4245 | { | 4561 | { |
4246 | /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ | 4562 | /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ |
4247 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 4563 | TRANSACTION2_QFSI_REQ *pSMB = NULL; |
@@ -4278,7 +4594,7 @@ oldQFSInfoRetry: | |||
4278 | pSMB->Reserved3 = 0; | 4594 | pSMB->Reserved3 = 0; |
4279 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 4595 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); |
4280 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); | 4596 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); |
4281 | pSMB->hdr.smb_buf_length += byte_count; | 4597 | inc_rfc1001_len(pSMB, byte_count); |
4282 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4598 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4283 | 4599 | ||
4284 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4600 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4288,12 +4604,12 @@ oldQFSInfoRetry: | |||
4288 | } else { /* decode response */ | 4604 | } else { /* decode response */ |
4289 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4605 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4290 | 4606 | ||
4291 | if (rc || (pSMBr->ByteCount < 18)) | 4607 | if (rc || get_bcc(&pSMBr->hdr) < 18) |
4292 | rc = -EIO; /* bad smb */ | 4608 | rc = -EIO; /* bad smb */ |
4293 | else { | 4609 | else { |
4294 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 4610 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
4295 | cFYI(1, "qfsinf resp BCC: %d Offset %d", | 4611 | cFYI(1, "qfsinf resp BCC: %d Offset %d", |
4296 | pSMBr->ByteCount, data_offset); | 4612 | get_bcc(&pSMBr->hdr), data_offset); |
4297 | 4613 | ||
4298 | response_data = (FILE_SYSTEM_ALLOC_INFO *) | 4614 | response_data = (FILE_SYSTEM_ALLOC_INFO *) |
4299 | (((char *) &pSMBr->hdr.Protocol) + data_offset); | 4615 | (((char *) &pSMBr->hdr.Protocol) + data_offset); |
@@ -4320,7 +4636,7 @@ oldQFSInfoRetry: | |||
4320 | } | 4636 | } |
4321 | 4637 | ||
4322 | int | 4638 | int |
4323 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | 4639 | CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData) |
4324 | { | 4640 | { |
4325 | /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ | 4641 | /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ |
4326 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 4642 | TRANSACTION2_QFSI_REQ *pSMB = NULL; |
@@ -4357,7 +4673,7 @@ QFSInfoRetry: | |||
4357 | pSMB->Reserved3 = 0; | 4673 | pSMB->Reserved3 = 0; |
4358 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 4674 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); |
4359 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); | 4675 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); |
4360 | pSMB->hdr.smb_buf_length += byte_count; | 4676 | inc_rfc1001_len(pSMB, byte_count); |
4361 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4677 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4362 | 4678 | ||
4363 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4679 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4367,7 +4683,7 @@ QFSInfoRetry: | |||
4367 | } else { /* decode response */ | 4683 | } else { /* decode response */ |
4368 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4684 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4369 | 4685 | ||
4370 | if (rc || (pSMBr->ByteCount < 24)) | 4686 | if (rc || get_bcc(&pSMBr->hdr) < 24) |
4371 | rc = -EIO; /* bad smb */ | 4687 | rc = -EIO; /* bad smb */ |
4372 | else { | 4688 | else { |
4373 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 4689 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
@@ -4399,7 +4715,7 @@ QFSInfoRetry: | |||
4399 | } | 4715 | } |
4400 | 4716 | ||
4401 | int | 4717 | int |
4402 | CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon) | 4718 | CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon) |
4403 | { | 4719 | { |
4404 | /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ | 4720 | /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ |
4405 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 4721 | TRANSACTION2_QFSI_REQ *pSMB = NULL; |
@@ -4437,7 +4753,7 @@ QFSAttributeRetry: | |||
4437 | pSMB->Reserved3 = 0; | 4753 | pSMB->Reserved3 = 0; |
4438 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 4754 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); |
4439 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); | 4755 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); |
4440 | pSMB->hdr.smb_buf_length += byte_count; | 4756 | inc_rfc1001_len(pSMB, byte_count); |
4441 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4757 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4442 | 4758 | ||
4443 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4759 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4447,7 +4763,7 @@ QFSAttributeRetry: | |||
4447 | } else { /* decode response */ | 4763 | } else { /* decode response */ |
4448 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4764 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4449 | 4765 | ||
4450 | if (rc || (pSMBr->ByteCount < 13)) { | 4766 | if (rc || get_bcc(&pSMBr->hdr) < 13) { |
4451 | /* BB also check if enough bytes returned */ | 4767 | /* BB also check if enough bytes returned */ |
4452 | rc = -EIO; /* bad smb */ | 4768 | rc = -EIO; /* bad smb */ |
4453 | } else { | 4769 | } else { |
@@ -4469,7 +4785,7 @@ QFSAttributeRetry: | |||
4469 | } | 4785 | } |
4470 | 4786 | ||
4471 | int | 4787 | int |
4472 | CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon) | 4788 | CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon) |
4473 | { | 4789 | { |
4474 | /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ | 4790 | /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ |
4475 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 4791 | TRANSACTION2_QFSI_REQ *pSMB = NULL; |
@@ -4508,7 +4824,7 @@ QFSDeviceRetry: | |||
4508 | pSMB->Reserved3 = 0; | 4824 | pSMB->Reserved3 = 0; |
4509 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 4825 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); |
4510 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); | 4826 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); |
4511 | pSMB->hdr.smb_buf_length += byte_count; | 4827 | inc_rfc1001_len(pSMB, byte_count); |
4512 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4828 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4513 | 4829 | ||
4514 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4830 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4518,7 +4834,8 @@ QFSDeviceRetry: | |||
4518 | } else { /* decode response */ | 4834 | } else { /* decode response */ |
4519 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4835 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4520 | 4836 | ||
4521 | if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO))) | 4837 | if (rc || get_bcc(&pSMBr->hdr) < |
4838 | sizeof(FILE_SYSTEM_DEVICE_INFO)) | ||
4522 | rc = -EIO; /* bad smb */ | 4839 | rc = -EIO; /* bad smb */ |
4523 | else { | 4840 | else { |
4524 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 4841 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
@@ -4539,7 +4856,7 @@ QFSDeviceRetry: | |||
4539 | } | 4856 | } |
4540 | 4857 | ||
4541 | int | 4858 | int |
4542 | CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon) | 4859 | CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon) |
4543 | { | 4860 | { |
4544 | /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ | 4861 | /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ |
4545 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | 4862 | TRANSACTION2_QFSI_REQ *pSMB = NULL; |
@@ -4577,7 +4894,7 @@ QFSUnixRetry: | |||
4577 | pSMB->Reserved3 = 0; | 4894 | pSMB->Reserved3 = 0; |
4578 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 4895 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); |
4579 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); | 4896 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); |
4580 | pSMB->hdr.smb_buf_length += byte_count; | 4897 | inc_rfc1001_len(pSMB, byte_count); |
4581 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4898 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4582 | 4899 | ||
4583 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4900 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4587,7 +4904,7 @@ QFSUnixRetry: | |||
4587 | } else { /* decode response */ | 4904 | } else { /* decode response */ |
4588 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 4905 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4589 | 4906 | ||
4590 | if (rc || (pSMBr->ByteCount < 13)) { | 4907 | if (rc || get_bcc(&pSMBr->hdr) < 13) { |
4591 | rc = -EIO; /* bad smb */ | 4908 | rc = -EIO; /* bad smb */ |
4592 | } else { | 4909 | } else { |
4593 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 4910 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
@@ -4609,7 +4926,7 @@ QFSUnixRetry: | |||
4609 | } | 4926 | } |
4610 | 4927 | ||
4611 | int | 4928 | int |
4612 | CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) | 4929 | CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap) |
4613 | { | 4930 | { |
4614 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ | 4931 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ |
4615 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | 4932 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; |
@@ -4660,7 +4977,7 @@ SETFSUnixRetry: | |||
4660 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | 4977 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); |
4661 | pSMB->ClientUnixCap = cpu_to_le64(cap); | 4978 | pSMB->ClientUnixCap = cpu_to_le64(cap); |
4662 | 4979 | ||
4663 | pSMB->hdr.smb_buf_length += byte_count; | 4980 | inc_rfc1001_len(pSMB, byte_count); |
4664 | pSMB->ByteCount = cpu_to_le16(byte_count); | 4981 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4665 | 4982 | ||
4666 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4983 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4683,7 +5000,7 @@ SETFSUnixRetry: | |||
4683 | 5000 | ||
4684 | 5001 | ||
4685 | int | 5002 | int |
4686 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 5003 | CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon, |
4687 | struct kstatfs *FSData) | 5004 | struct kstatfs *FSData) |
4688 | { | 5005 | { |
4689 | /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ | 5006 | /* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */ |
@@ -4722,7 +5039,7 @@ QFSPosixRetry: | |||
4722 | pSMB->Reserved3 = 0; | 5039 | pSMB->Reserved3 = 0; |
4723 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | 5040 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); |
4724 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); | 5041 | pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO); |
4725 | pSMB->hdr.smb_buf_length += byte_count; | 5042 | inc_rfc1001_len(pSMB, byte_count); |
4726 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5043 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4727 | 5044 | ||
4728 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5045 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4732,7 +5049,7 @@ QFSPosixRetry: | |||
4732 | } else { /* decode response */ | 5049 | } else { /* decode response */ |
4733 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 5050 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
4734 | 5051 | ||
4735 | if (rc || (pSMBr->ByteCount < 13)) { | 5052 | if (rc || get_bcc(&pSMBr->hdr) < 13) { |
4736 | rc = -EIO; /* bad smb */ | 5053 | rc = -EIO; /* bad smb */ |
4737 | } else { | 5054 | } else { |
4738 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 5055 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
@@ -4776,7 +5093,7 @@ QFSPosixRetry: | |||
4776 | in Samba which this routine can run into */ | 5093 | in Samba which this routine can run into */ |
4777 | 5094 | ||
4778 | int | 5095 | int |
4779 | CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 5096 | CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName, |
4780 | __u64 size, bool SetAllocation, | 5097 | __u64 size, bool SetAllocation, |
4781 | const struct nls_table *nls_codepage, int remap) | 5098 | const struct nls_table *nls_codepage, int remap) |
4782 | { | 5099 | { |
@@ -4848,7 +5165,7 @@ SetEOFRetry: | |||
4848 | pSMB->ParameterCount = cpu_to_le16(params); | 5165 | pSMB->ParameterCount = cpu_to_le16(params); |
4849 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 5166 | pSMB->TotalParameterCount = pSMB->ParameterCount; |
4850 | pSMB->Reserved4 = 0; | 5167 | pSMB->Reserved4 = 0; |
4851 | pSMB->hdr.smb_buf_length += byte_count; | 5168 | inc_rfc1001_len(pSMB, byte_count); |
4852 | parm_data->FileSize = cpu_to_le64(size); | 5169 | parm_data->FileSize = cpu_to_le64(size); |
4853 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5170 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4854 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5171 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -4865,11 +5182,10 @@ SetEOFRetry: | |||
4865 | } | 5182 | } |
4866 | 5183 | ||
4867 | int | 5184 | int |
4868 | CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | 5185 | CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size, |
4869 | __u16 fid, __u32 pid_of_opener, bool SetAllocation) | 5186 | __u16 fid, __u32 pid_of_opener, bool SetAllocation) |
4870 | { | 5187 | { |
4871 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 5188 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
4872 | char *data_offset; | ||
4873 | struct file_end_of_file_info *parm_data; | 5189 | struct file_end_of_file_info *parm_data; |
4874 | int rc = 0; | 5190 | int rc = 0; |
4875 | __u16 params, param_offset, offset, byte_count, count; | 5191 | __u16 params, param_offset, offset, byte_count, count; |
@@ -4893,8 +5209,6 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
4893 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | 5209 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; |
4894 | offset = param_offset + params; | 5210 | offset = param_offset + params; |
4895 | 5211 | ||
4896 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | ||
4897 | |||
4898 | count = sizeof(struct file_end_of_file_info); | 5212 | count = sizeof(struct file_end_of_file_info); |
4899 | pSMB->MaxParameterCount = cpu_to_le16(2); | 5213 | pSMB->MaxParameterCount = cpu_to_le16(2); |
4900 | /* BB find exact max SMB PDU from sess structure BB */ | 5214 | /* BB find exact max SMB PDU from sess structure BB */ |
@@ -4930,7 +5244,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
4930 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); | 5244 | cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); |
4931 | } | 5245 | } |
4932 | pSMB->Reserved4 = 0; | 5246 | pSMB->Reserved4 = 0; |
4933 | pSMB->hdr.smb_buf_length += byte_count; | 5247 | inc_rfc1001_len(pSMB, byte_count); |
4934 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5248 | pSMB->ByteCount = cpu_to_le16(byte_count); |
4935 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | 5249 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
4936 | if (rc) { | 5250 | if (rc) { |
@@ -4950,7 +5264,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
4950 | time and resort to the original setpathinfo level which takes the ancient | 5264 | time and resort to the original setpathinfo level which takes the ancient |
4951 | DOS time format with 2 second granularity */ | 5265 | DOS time format with 2 second granularity */ |
4952 | int | 5266 | int |
4953 | CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, | 5267 | CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon, |
4954 | const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) | 5268 | const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) |
4955 | { | 5269 | { |
4956 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 5270 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
@@ -4998,7 +5312,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, | |||
4998 | else | 5312 | else |
4999 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); | 5313 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); |
5000 | pSMB->Reserved4 = 0; | 5314 | pSMB->Reserved4 = 0; |
5001 | pSMB->hdr.smb_buf_length += byte_count; | 5315 | inc_rfc1001_len(pSMB, byte_count); |
5002 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5316 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5003 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); | 5317 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); |
5004 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | 5318 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
@@ -5012,7 +5326,7 @@ CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, | |||
5012 | } | 5326 | } |
5013 | 5327 | ||
5014 | int | 5328 | int |
5015 | CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, | 5329 | CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon, |
5016 | bool delete_file, __u16 fid, __u32 pid_of_opener) | 5330 | bool delete_file, __u16 fid, __u32 pid_of_opener) |
5017 | { | 5331 | { |
5018 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 5332 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
@@ -5057,7 +5371,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, | |||
5057 | pSMB->Fid = fid; | 5371 | pSMB->Fid = fid; |
5058 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); | 5372 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO); |
5059 | pSMB->Reserved4 = 0; | 5373 | pSMB->Reserved4 = 0; |
5060 | pSMB->hdr.smb_buf_length += byte_count; | 5374 | inc_rfc1001_len(pSMB, byte_count); |
5061 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5375 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5062 | *data_offset = delete_file ? 1 : 0; | 5376 | *data_offset = delete_file ? 1 : 0; |
5063 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | 5377 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); |
@@ -5068,7 +5382,7 @@ CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon, | |||
5068 | } | 5382 | } |
5069 | 5383 | ||
5070 | int | 5384 | int |
5071 | CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, | 5385 | CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon, |
5072 | const char *fileName, const FILE_BASIC_INFO *data, | 5386 | const char *fileName, const FILE_BASIC_INFO *data, |
5073 | const struct nls_table *nls_codepage, int remap) | 5387 | const struct nls_table *nls_codepage, int remap) |
5074 | { | 5388 | { |
@@ -5130,7 +5444,7 @@ SetTimesRetry: | |||
5130 | else | 5444 | else |
5131 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); | 5445 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); |
5132 | pSMB->Reserved4 = 0; | 5446 | pSMB->Reserved4 = 0; |
5133 | pSMB->hdr.smb_buf_length += byte_count; | 5447 | inc_rfc1001_len(pSMB, byte_count); |
5134 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); | 5448 | memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); |
5135 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5449 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5136 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5450 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -5152,7 +5466,7 @@ SetTimesRetry: | |||
5152 | handling it anyway and NT4 was what we thought it would be needed for | 5466 | handling it anyway and NT4 was what we thought it would be needed for |
5153 | Do not delete it until we prove whether needed for Win9x though */ | 5467 | Do not delete it until we prove whether needed for Win9x though */ |
5154 | int | 5468 | int |
5155 | CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, | 5469 | CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName, |
5156 | __u16 dos_attrs, const struct nls_table *nls_codepage) | 5470 | __u16 dos_attrs, const struct nls_table *nls_codepage) |
5157 | { | 5471 | { |
5158 | SETATTR_REQ *pSMB = NULL; | 5472 | SETATTR_REQ *pSMB = NULL; |
@@ -5182,7 +5496,7 @@ SetAttrLgcyRetry: | |||
5182 | } | 5496 | } |
5183 | pSMB->attr = cpu_to_le16(dos_attrs); | 5497 | pSMB->attr = cpu_to_le16(dos_attrs); |
5184 | pSMB->BufferFormat = 0x04; | 5498 | pSMB->BufferFormat = 0x04; |
5185 | pSMB->hdr.smb_buf_length += name_len + 1; | 5499 | inc_rfc1001_len(pSMB, name_len + 1); |
5186 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 5500 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
5187 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5501 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
5188 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 5502 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -5208,7 +5522,7 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | |||
5208 | * Samba server ignores set of file size to zero due to bugs in some | 5522 | * Samba server ignores set of file size to zero due to bugs in some |
5209 | * older clients, but we should be precise - we use SetFileSize to | 5523 | * older clients, but we should be precise - we use SetFileSize to |
5210 | * set file size and do not want to truncate file size to zero | 5524 | * set file size and do not want to truncate file size to zero |
5211 | * accidently as happened on one Samba server beta by putting | 5525 | * accidentally as happened on one Samba server beta by putting |
5212 | * zero instead of -1 here | 5526 | * zero instead of -1 here |
5213 | */ | 5527 | */ |
5214 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | 5528 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); |
@@ -5240,7 +5554,7 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | |||
5240 | } | 5554 | } |
5241 | 5555 | ||
5242 | int | 5556 | int |
5243 | CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, | 5557 | CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon, |
5244 | const struct cifs_unix_set_info_args *args, | 5558 | const struct cifs_unix_set_info_args *args, |
5245 | u16 fid, u32 pid_of_opener) | 5559 | u16 fid, u32 pid_of_opener) |
5246 | { | 5560 | { |
@@ -5287,7 +5601,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, | |||
5287 | pSMB->Fid = fid; | 5601 | pSMB->Fid = fid; |
5288 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | 5602 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); |
5289 | pSMB->Reserved4 = 0; | 5603 | pSMB->Reserved4 = 0; |
5290 | pSMB->hdr.smb_buf_length += byte_count; | 5604 | inc_rfc1001_len(pSMB, byte_count); |
5291 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5605 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5292 | 5606 | ||
5293 | cifs_fill_unix_set_info(data_offset, args); | 5607 | cifs_fill_unix_set_info(data_offset, args); |
@@ -5303,7 +5617,7 @@ CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, | |||
5303 | } | 5617 | } |
5304 | 5618 | ||
5305 | int | 5619 | int |
5306 | CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | 5620 | CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName, |
5307 | const struct cifs_unix_set_info_args *args, | 5621 | const struct cifs_unix_set_info_args *args, |
5308 | const struct nls_table *nls_codepage, int remap) | 5622 | const struct nls_table *nls_codepage, int remap) |
5309 | { | 5623 | { |
@@ -5363,7 +5677,7 @@ setPermsRetry: | |||
5363 | pSMB->TotalDataCount = pSMB->DataCount; | 5677 | pSMB->TotalDataCount = pSMB->DataCount; |
5364 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | 5678 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); |
5365 | pSMB->Reserved4 = 0; | 5679 | pSMB->Reserved4 = 0; |
5366 | pSMB->hdr.smb_buf_length += byte_count; | 5680 | inc_rfc1001_len(pSMB, byte_count); |
5367 | 5681 | ||
5368 | cifs_fill_unix_set_info(data_offset, args); | 5682 | cifs_fill_unix_set_info(data_offset, args); |
5369 | 5683 | ||
@@ -5379,79 +5693,6 @@ setPermsRetry: | |||
5379 | return rc; | 5693 | return rc; |
5380 | } | 5694 | } |
5381 | 5695 | ||
5382 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | ||
5383 | const int notify_subdirs, const __u16 netfid, | ||
5384 | __u32 filter, struct file *pfile, int multishot, | ||
5385 | const struct nls_table *nls_codepage) | ||
5386 | { | ||
5387 | int rc = 0; | ||
5388 | struct smb_com_transaction_change_notify_req *pSMB = NULL; | ||
5389 | struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; | ||
5390 | struct dir_notify_req *dnotify_req; | ||
5391 | int bytes_returned; | ||
5392 | |||
5393 | cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); | ||
5394 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | ||
5395 | (void **) &pSMBr); | ||
5396 | if (rc) | ||
5397 | return rc; | ||
5398 | |||
5399 | pSMB->TotalParameterCount = 0 ; | ||
5400 | pSMB->TotalDataCount = 0; | ||
5401 | pSMB->MaxParameterCount = cpu_to_le32(2); | ||
5402 | /* BB find exact data count max from sess structure BB */ | ||
5403 | pSMB->MaxDataCount = 0; /* same in little endian or be */ | ||
5404 | /* BB VERIFY verify which is correct for above BB */ | ||
5405 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
5406 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
5407 | |||
5408 | pSMB->MaxSetupCount = 4; | ||
5409 | pSMB->Reserved = 0; | ||
5410 | pSMB->ParameterOffset = 0; | ||
5411 | pSMB->DataCount = 0; | ||
5412 | pSMB->DataOffset = 0; | ||
5413 | pSMB->SetupCount = 4; /* single byte does not need le conversion */ | ||
5414 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); | ||
5415 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
5416 | if (notify_subdirs) | ||
5417 | pSMB->WatchTree = 1; /* one byte - no le conversion needed */ | ||
5418 | pSMB->Reserved2 = 0; | ||
5419 | pSMB->CompletionFilter = cpu_to_le32(filter); | ||
5420 | pSMB->Fid = netfid; /* file handle always le */ | ||
5421 | pSMB->ByteCount = 0; | ||
5422 | |||
5423 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
5424 | (struct smb_hdr *)pSMBr, &bytes_returned, | ||
5425 | CIFS_ASYNC_OP); | ||
5426 | if (rc) { | ||
5427 | cFYI(1, "Error in Notify = %d", rc); | ||
5428 | } else { | ||
5429 | /* Add file to outstanding requests */ | ||
5430 | /* BB change to kmem cache alloc */ | ||
5431 | dnotify_req = kmalloc( | ||
5432 | sizeof(struct dir_notify_req), | ||
5433 | GFP_KERNEL); | ||
5434 | if (dnotify_req) { | ||
5435 | dnotify_req->Pid = pSMB->hdr.Pid; | ||
5436 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | ||
5437 | dnotify_req->Mid = pSMB->hdr.Mid; | ||
5438 | dnotify_req->Tid = pSMB->hdr.Tid; | ||
5439 | dnotify_req->Uid = pSMB->hdr.Uid; | ||
5440 | dnotify_req->netfid = netfid; | ||
5441 | dnotify_req->pfile = pfile; | ||
5442 | dnotify_req->filter = filter; | ||
5443 | dnotify_req->multishot = multishot; | ||
5444 | spin_lock(&GlobalMid_Lock); | ||
5445 | list_add_tail(&dnotify_req->lhead, | ||
5446 | &GlobalDnotifyReqList); | ||
5447 | spin_unlock(&GlobalMid_Lock); | ||
5448 | } else | ||
5449 | rc = -ENOMEM; | ||
5450 | } | ||
5451 | cifs_buf_release(pSMB); | ||
5452 | return rc; | ||
5453 | } | ||
5454 | |||
5455 | #ifdef CONFIG_CIFS_XATTR | 5696 | #ifdef CONFIG_CIFS_XATTR |
5456 | /* | 5697 | /* |
5457 | * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common | 5698 | * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common |
@@ -5463,7 +5704,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
5463 | * the data isn't copied to it, but the length is returned. | 5704 | * the data isn't copied to it, but the length is returned. |
5464 | */ | 5705 | */ |
5465 | ssize_t | 5706 | ssize_t |
5466 | CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 5707 | CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon, |
5467 | const unsigned char *searchName, const unsigned char *ea_name, | 5708 | const unsigned char *searchName, const unsigned char *ea_name, |
5468 | char *EAData, size_t buf_size, | 5709 | char *EAData, size_t buf_size, |
5469 | const struct nls_table *nls_codepage, int remap) | 5710 | const struct nls_table *nls_codepage, int remap) |
@@ -5521,7 +5762,7 @@ QAllEAsRetry: | |||
5521 | pSMB->ParameterCount = pSMB->TotalParameterCount; | 5762 | pSMB->ParameterCount = pSMB->TotalParameterCount; |
5522 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); | 5763 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); |
5523 | pSMB->Reserved4 = 0; | 5764 | pSMB->Reserved4 = 0; |
5524 | pSMB->hdr.smb_buf_length += byte_count; | 5765 | inc_rfc1001_len(pSMB, byte_count); |
5525 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5766 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5526 | 5767 | ||
5527 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5768 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
@@ -5537,7 +5778,7 @@ QAllEAsRetry: | |||
5537 | of these trans2 responses */ | 5778 | of these trans2 responses */ |
5538 | 5779 | ||
5539 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 5780 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
5540 | if (rc || (pSMBr->ByteCount < 4)) { | 5781 | if (rc || get_bcc(&pSMBr->hdr) < 4) { |
5541 | rc = -EIO; /* bad smb */ | 5782 | rc = -EIO; /* bad smb */ |
5542 | goto QAllEAsOut; | 5783 | goto QAllEAsOut; |
5543 | } | 5784 | } |
@@ -5562,7 +5803,7 @@ QAllEAsRetry: | |||
5562 | } | 5803 | } |
5563 | 5804 | ||
5564 | /* make sure list_len doesn't go past end of SMB */ | 5805 | /* make sure list_len doesn't go past end of SMB */ |
5565 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); | 5806 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); |
5566 | if ((char *)ea_response_data + list_len > end_of_smb) { | 5807 | if ((char *)ea_response_data + list_len > end_of_smb) { |
5567 | cFYI(1, "EA list appears to go beyond SMB"); | 5808 | cFYI(1, "EA list appears to go beyond SMB"); |
5568 | rc = -EIO; | 5809 | rc = -EIO; |
@@ -5644,7 +5885,7 @@ QAllEAsOut: | |||
5644 | } | 5885 | } |
5645 | 5886 | ||
5646 | int | 5887 | int |
5647 | CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 5888 | CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName, |
5648 | const char *ea_name, const void *ea_value, | 5889 | const char *ea_name, const void *ea_value, |
5649 | const __u16 ea_value_len, const struct nls_table *nls_codepage, | 5890 | const __u16 ea_value_len, const struct nls_table *nls_codepage, |
5650 | int remap) | 5891 | int remap) |
@@ -5734,7 +5975,7 @@ SetEARetry: | |||
5734 | pSMB->ParameterCount = cpu_to_le16(params); | 5975 | pSMB->ParameterCount = cpu_to_le16(params); |
5735 | pSMB->TotalParameterCount = pSMB->ParameterCount; | 5976 | pSMB->TotalParameterCount = pSMB->ParameterCount; |
5736 | pSMB->Reserved4 = 0; | 5977 | pSMB->Reserved4 = 0; |
5737 | pSMB->hdr.smb_buf_length += byte_count; | 5978 | inc_rfc1001_len(pSMB, byte_count); |
5738 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5979 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5739 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5980 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
5740 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 5981 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
@@ -5748,5 +5989,99 @@ SetEARetry: | |||
5748 | 5989 | ||
5749 | return rc; | 5990 | return rc; |
5750 | } | 5991 | } |
5751 | |||
5752 | #endif | 5992 | #endif |
5993 | |||
5994 | #ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */ | ||
5995 | /* | ||
5996 | * Years ago the kernel added a "dnotify" function for Samba server, | ||
5997 | * to allow network clients (such as Windows) to display updated | ||
5998 | * lists of files in directory listings automatically when | ||
5999 | * files are added by one user when another user has the | ||
6000 | * same directory open on their desktop. The Linux cifs kernel | ||
6001 | * client hooked into the kernel side of this interface for | ||
6002 | * the same reason, but ironically when the VFS moved from | ||
6003 | * "dnotify" to "inotify" it became harder to plug in Linux | ||
6004 | * network file system clients (the most obvious use case | ||
6005 | * for notify interfaces is when multiple users can update | ||
6006 | * the contents of the same directory - exactly what network | ||
6007 | * file systems can do) although the server (Samba) could | ||
6008 | * still use it. For the short term we leave the worker | ||
6009 | * function ifdeffed out (below) until inotify is fixed | ||
6010 | * in the VFS to make it easier to plug in network file | ||
6011 | * system clients. If inotify turns out to be permanently | ||
6012 | * incompatible for network fs clients, we could instead simply | ||
6013 | * expose this config flag by adding a future cifs (and smb2) notify ioctl. | ||
6014 | */ | ||
6015 | int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon, | ||
6016 | const int notify_subdirs, const __u16 netfid, | ||
6017 | __u32 filter, struct file *pfile, int multishot, | ||
6018 | const struct nls_table *nls_codepage) | ||
6019 | { | ||
6020 | int rc = 0; | ||
6021 | struct smb_com_transaction_change_notify_req *pSMB = NULL; | ||
6022 | struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL; | ||
6023 | struct dir_notify_req *dnotify_req; | ||
6024 | int bytes_returned; | ||
6025 | |||
6026 | cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid); | ||
6027 | rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, | ||
6028 | (void **) &pSMBr); | ||
6029 | if (rc) | ||
6030 | return rc; | ||
6031 | |||
6032 | pSMB->TotalParameterCount = 0 ; | ||
6033 | pSMB->TotalDataCount = 0; | ||
6034 | pSMB->MaxParameterCount = cpu_to_le32(2); | ||
6035 | /* BB find exact data count max from sess structure BB */ | ||
6036 | pSMB->MaxDataCount = 0; /* same in little endian or be */ | ||
6037 | /* BB VERIFY verify which is correct for above BB */ | ||
6038 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
6039 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
6040 | |||
6041 | pSMB->MaxSetupCount = 4; | ||
6042 | pSMB->Reserved = 0; | ||
6043 | pSMB->ParameterOffset = 0; | ||
6044 | pSMB->DataCount = 0; | ||
6045 | pSMB->DataOffset = 0; | ||
6046 | pSMB->SetupCount = 4; /* single byte does not need le conversion */ | ||
6047 | pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); | ||
6048 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
6049 | if (notify_subdirs) | ||
6050 | pSMB->WatchTree = 1; /* one byte - no le conversion needed */ | ||
6051 | pSMB->Reserved2 = 0; | ||
6052 | pSMB->CompletionFilter = cpu_to_le32(filter); | ||
6053 | pSMB->Fid = netfid; /* file handle always le */ | ||
6054 | pSMB->ByteCount = 0; | ||
6055 | |||
6056 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
6057 | (struct smb_hdr *)pSMBr, &bytes_returned, | ||
6058 | CIFS_ASYNC_OP); | ||
6059 | if (rc) { | ||
6060 | cFYI(1, "Error in Notify = %d", rc); | ||
6061 | } else { | ||
6062 | /* Add file to outstanding requests */ | ||
6063 | /* BB change to kmem cache alloc */ | ||
6064 | dnotify_req = kmalloc( | ||
6065 | sizeof(struct dir_notify_req), | ||
6066 | GFP_KERNEL); | ||
6067 | if (dnotify_req) { | ||
6068 | dnotify_req->Pid = pSMB->hdr.Pid; | ||
6069 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | ||
6070 | dnotify_req->Mid = pSMB->hdr.Mid; | ||
6071 | dnotify_req->Tid = pSMB->hdr.Tid; | ||
6072 | dnotify_req->Uid = pSMB->hdr.Uid; | ||
6073 | dnotify_req->netfid = netfid; | ||
6074 | dnotify_req->pfile = pfile; | ||
6075 | dnotify_req->filter = filter; | ||
6076 | dnotify_req->multishot = multishot; | ||
6077 | spin_lock(&GlobalMid_Lock); | ||
6078 | list_add_tail(&dnotify_req->lhead, | ||
6079 | &GlobalDnotifyReqList); | ||
6080 | spin_unlock(&GlobalMid_Lock); | ||
6081 | } else | ||
6082 | rc = -ENOMEM; | ||
6083 | } | ||
6084 | cifs_buf_release(pSMB); | ||
6085 | return rc; | ||
6086 | } | ||
6087 | #endif /* was needed for dnotify, and will be needed for inotify when VFS fix */ | ||
diff --git a/fs/cifs/cn_cifs.h b/fs/cifs/cn_cifs.h deleted file mode 100644 index ea59ccac2eb1..000000000000 --- a/fs/cifs/cn_cifs.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* | ||
2 | * fs/cifs/cn_cifs.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2002 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * This library is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU Lesser General Public License as published | ||
9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This library 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 | ||
15 | * the GNU Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public License | ||
18 | * along with this library; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef _CN_CIFS_H | ||
23 | #define _CN_CIFS_H | ||
24 | #ifdef CONFIG_CIFS_UPCALL | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/connector.h> | ||
27 | |||
28 | struct cifs_upcall { | ||
29 | char signature[4]; /* CIFS */ | ||
30 | enum command { | ||
31 | CIFS_GET_IP = 0x00000001, /* get ip address for hostname */ | ||
32 | CIFS_GET_SECBLOB = 0x00000002, /* get SPNEGO wrapped blob */ | ||
33 | } command; | ||
34 | /* union cifs upcall data follows */ | ||
35 | }; | ||
36 | #endif /* CIFS_UPCALL */ | ||
37 | #endif /* _CN_CIFS_H */ | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 88c84a38bccb..ccc1afa0bf3b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -47,69 +47,26 @@ | |||
47 | #include "ntlmssp.h" | 47 | #include "ntlmssp.h" |
48 | #include "nterr.h" | 48 | #include "nterr.h" |
49 | #include "rfc1002pdu.h" | 49 | #include "rfc1002pdu.h" |
50 | #include "cn_cifs.h" | ||
51 | #include "fscache.h" | 50 | #include "fscache.h" |
52 | 51 | ||
53 | #define CIFS_PORT 445 | 52 | #define CIFS_PORT 445 |
54 | #define RFC1001_PORT 139 | 53 | #define RFC1001_PORT 139 |
55 | 54 | ||
56 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 55 | /* SMB echo "timeout" -- FIXME: tunable? */ |
57 | unsigned char *p24); | 56 | #define SMB_ECHO_INTERVAL (60 * HZ) |
58 | 57 | ||
59 | extern mempool_t *cifs_req_poolp; | 58 | extern mempool_t *cifs_req_poolp; |
60 | 59 | ||
61 | struct smb_vol { | 60 | /* FIXME: should these be tunable? */ |
62 | char *username; | 61 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
63 | char *password; | 62 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
64 | char *domainname; | 63 | |
65 | char *UNC; | 64 | static int ip_connect(struct TCP_Server_Info *server); |
66 | char *UNCip; | 65 | static int generic_ip_connect(struct TCP_Server_Info *server); |
67 | char *iocharset; /* local code page for mapping to and from Unicode */ | 66 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
68 | char source_rfc1001_name[16]; /* netbios name of client */ | 67 | static void cifs_prune_tlinks(struct work_struct *work); |
69 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 68 | static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, |
70 | uid_t cred_uid; | 69 | const char *devname); |
71 | uid_t linux_uid; | ||
72 | gid_t linux_gid; | ||
73 | mode_t file_mode; | ||
74 | mode_t dir_mode; | ||
75 | unsigned secFlg; | ||
76 | bool retry:1; | ||
77 | bool intr:1; | ||
78 | bool setuids:1; | ||
79 | bool override_uid:1; | ||
80 | bool override_gid:1; | ||
81 | bool dynperm:1; | ||
82 | bool noperm:1; | ||
83 | bool no_psx_acl:1; /* set if posix acl support should be disabled */ | ||
84 | bool cifs_acl:1; | ||
85 | bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ | ||
86 | bool server_ino:1; /* use inode numbers from server ie UniqueId */ | ||
87 | bool direct_io:1; | ||
88 | bool remap:1; /* set to remap seven reserved chars in filenames */ | ||
89 | bool posix_paths:1; /* unset to not ask for posix pathnames. */ | ||
90 | bool no_linux_ext:1; | ||
91 | bool sfu_emul:1; | ||
92 | bool nullauth:1; /* attempt to authenticate with null user */ | ||
93 | bool nocase:1; /* request case insensitive filenames */ | ||
94 | bool nobrl:1; /* disable sending byte range locks to srv */ | ||
95 | bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ | ||
96 | bool seal:1; /* request transport encryption on share */ | ||
97 | bool nodfs:1; /* Do not request DFS, even if available */ | ||
98 | bool local_lease:1; /* check leases only on local system, not remote */ | ||
99 | bool noblocksnd:1; | ||
100 | bool noautotune:1; | ||
101 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | ||
102 | bool fsc:1; /* enable fscache */ | ||
103 | unsigned int rsize; | ||
104 | unsigned int wsize; | ||
105 | bool sockopt_tcp_nodelay:1; | ||
106 | unsigned short int port; | ||
107 | char *prepath; | ||
108 | struct nls_table *local_nls; | ||
109 | }; | ||
110 | |||
111 | static int ipv4_connect(struct TCP_Server_Info *server); | ||
112 | static int ipv6_connect(struct TCP_Server_Info *server); | ||
113 | 70 | ||
114 | /* | 71 | /* |
115 | * cifs tcp session reconnection | 72 | * cifs tcp session reconnection |
@@ -124,9 +81,10 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
124 | { | 81 | { |
125 | int rc = 0; | 82 | int rc = 0; |
126 | struct list_head *tmp, *tmp2; | 83 | struct list_head *tmp, *tmp2; |
127 | struct cifsSesInfo *ses; | 84 | struct cifs_ses *ses; |
128 | struct cifsTconInfo *tcon; | 85 | struct cifs_tcon *tcon; |
129 | struct mid_q_entry *mid_entry; | 86 | struct mid_q_entry *mid_entry; |
87 | struct list_head retry_list; | ||
130 | 88 | ||
131 | spin_lock(&GlobalMid_Lock); | 89 | spin_lock(&GlobalMid_Lock); |
132 | if (server->tcpStatus == CifsExiting) { | 90 | if (server->tcpStatus == CifsExiting) { |
@@ -143,18 +101,21 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
143 | 101 | ||
144 | /* before reconnecting the tcp session, mark the smb session (uid) | 102 | /* before reconnecting the tcp session, mark the smb session (uid) |
145 | and the tid bad so they are not used until reconnected */ | 103 | and the tid bad so they are not used until reconnected */ |
146 | read_lock(&cifs_tcp_ses_lock); | 104 | cFYI(1, "%s: marking sessions and tcons for reconnect", __func__); |
105 | spin_lock(&cifs_tcp_ses_lock); | ||
147 | list_for_each(tmp, &server->smb_ses_list) { | 106 | list_for_each(tmp, &server->smb_ses_list) { |
148 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 107 | ses = list_entry(tmp, struct cifs_ses, smb_ses_list); |
149 | ses->need_reconnect = true; | 108 | ses->need_reconnect = true; |
150 | ses->ipc_tid = 0; | 109 | ses->ipc_tid = 0; |
151 | list_for_each(tmp2, &ses->tcon_list) { | 110 | list_for_each(tmp2, &ses->tcon_list) { |
152 | tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list); | 111 | tcon = list_entry(tmp2, struct cifs_tcon, tcon_list); |
153 | tcon->need_reconnect = true; | 112 | tcon->need_reconnect = true; |
154 | } | 113 | } |
155 | } | 114 | } |
156 | read_unlock(&cifs_tcp_ses_lock); | 115 | spin_unlock(&cifs_tcp_ses_lock); |
116 | |||
157 | /* do not want to be sending data on a socket we are freeing */ | 117 | /* do not want to be sending data on a socket we are freeing */ |
118 | cFYI(1, "%s: tearing down socket", __func__); | ||
158 | mutex_lock(&server->srv_mutex); | 119 | mutex_lock(&server->srv_mutex); |
159 | if (server->ssocket) { | 120 | if (server->ssocket) { |
160 | cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, | 121 | cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, |
@@ -166,30 +127,38 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
166 | sock_release(server->ssocket); | 127 | sock_release(server->ssocket); |
167 | server->ssocket = NULL; | 128 | server->ssocket = NULL; |
168 | } | 129 | } |
130 | server->sequence_number = 0; | ||
131 | server->session_estab = false; | ||
132 | kfree(server->session_key.response); | ||
133 | server->session_key.response = NULL; | ||
134 | server->session_key.len = 0; | ||
135 | server->lstrp = jiffies; | ||
136 | mutex_unlock(&server->srv_mutex); | ||
169 | 137 | ||
138 | /* mark submitted MIDs for retry and issue callback */ | ||
139 | INIT_LIST_HEAD(&retry_list); | ||
140 | cFYI(1, "%s: moving mids to private list", __func__); | ||
170 | spin_lock(&GlobalMid_Lock); | 141 | spin_lock(&GlobalMid_Lock); |
171 | list_for_each(tmp, &server->pending_mid_q) { | 142 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
172 | mid_entry = list_entry(tmp, struct | 143 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
173 | mid_q_entry, | 144 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) |
174 | qhead); | ||
175 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | ||
176 | /* Mark other intransit requests as needing | ||
177 | retry so we do not immediately mark the | ||
178 | session bad again (ie after we reconnect | ||
179 | below) as they timeout too */ | ||
180 | mid_entry->midState = MID_RETRY_NEEDED; | 145 | mid_entry->midState = MID_RETRY_NEEDED; |
181 | } | 146 | list_move(&mid_entry->qhead, &retry_list); |
182 | } | 147 | } |
183 | spin_unlock(&GlobalMid_Lock); | 148 | spin_unlock(&GlobalMid_Lock); |
184 | mutex_unlock(&server->srv_mutex); | ||
185 | 149 | ||
186 | while ((server->tcpStatus != CifsExiting) && | 150 | cFYI(1, "%s: issuing mid callbacks", __func__); |
187 | (server->tcpStatus != CifsGood)) { | 151 | list_for_each_safe(tmp, tmp2, &retry_list) { |
152 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
153 | list_del_init(&mid_entry->qhead); | ||
154 | mid_entry->callback(mid_entry); | ||
155 | } | ||
156 | |||
157 | do { | ||
188 | try_to_freeze(); | 158 | try_to_freeze(); |
189 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 159 | |
190 | rc = ipv6_connect(server); | 160 | /* we should try only the port we connected to before */ |
191 | else | 161 | rc = generic_ip_connect(server); |
192 | rc = ipv4_connect(server); | ||
193 | if (rc) { | 162 | if (rc) { |
194 | cFYI(1, "reconnect error %d", rc); | 163 | cFYI(1, "reconnect error %d", rc); |
195 | msleep(3000); | 164 | msleep(3000); |
@@ -197,13 +166,11 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
197 | atomic_inc(&tcpSesReconnectCount); | 166 | atomic_inc(&tcpSesReconnectCount); |
198 | spin_lock(&GlobalMid_Lock); | 167 | spin_lock(&GlobalMid_Lock); |
199 | if (server->tcpStatus != CifsExiting) | 168 | if (server->tcpStatus != CifsExiting) |
200 | server->tcpStatus = CifsGood; | 169 | server->tcpStatus = CifsNeedNegotiate; |
201 | server->sequence_number = 0; | ||
202 | spin_unlock(&GlobalMid_Lock); | 170 | spin_unlock(&GlobalMid_Lock); |
203 | /* atomic_set(&server->inFlight,0);*/ | ||
204 | wake_up(&server->response_q); | ||
205 | } | 171 | } |
206 | } | 172 | } while (server->tcpStatus == CifsNeedReconnect); |
173 | |||
207 | return rc; | 174 | return rc; |
208 | } | 175 | } |
209 | 176 | ||
@@ -217,9 +184,8 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
217 | static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | 184 | static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) |
218 | { | 185 | { |
219 | struct smb_t2_rsp *pSMBt; | 186 | struct smb_t2_rsp *pSMBt; |
220 | int total_data_size; | ||
221 | int data_in_this_rsp; | ||
222 | int remaining; | 187 | int remaining; |
188 | __u16 total_data_size, data_in_this_rsp; | ||
223 | 189 | ||
224 | if (pSMB->Command != SMB_COM_TRANSACTION2) | 190 | if (pSMB->Command != SMB_COM_TRANSACTION2) |
225 | return 0; | 191 | return 0; |
@@ -233,93 +199,124 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | |||
233 | 199 | ||
234 | pSMBt = (struct smb_t2_rsp *)pSMB; | 200 | pSMBt = (struct smb_t2_rsp *)pSMB; |
235 | 201 | ||
236 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | 202 | total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); |
237 | data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); | 203 | data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); |
238 | |||
239 | remaining = total_data_size - data_in_this_rsp; | ||
240 | 204 | ||
241 | if (remaining == 0) | 205 | if (total_data_size == data_in_this_rsp) |
242 | return 0; | 206 | return 0; |
243 | else if (remaining < 0) { | 207 | else if (total_data_size < data_in_this_rsp) { |
244 | cFYI(1, "total data %d smaller than data in frame %d", | 208 | cFYI(1, "total data %d smaller than data in frame %d", |
245 | total_data_size, data_in_this_rsp); | 209 | total_data_size, data_in_this_rsp); |
246 | return -EINVAL; | 210 | return -EINVAL; |
247 | } else { | ||
248 | cFYI(1, "missing %d bytes from transact2, check next response", | ||
249 | remaining); | ||
250 | if (total_data_size > maxBufSize) { | ||
251 | cERROR(1, "TotalDataSize %d is over maximum buffer %d", | ||
252 | total_data_size, maxBufSize); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | return remaining; | ||
256 | } | 211 | } |
212 | |||
213 | remaining = total_data_size - data_in_this_rsp; | ||
214 | |||
215 | cFYI(1, "missing %d bytes from transact2, check next response", | ||
216 | remaining); | ||
217 | if (total_data_size > maxBufSize) { | ||
218 | cERROR(1, "TotalDataSize %d is over maximum buffer %d", | ||
219 | total_data_size, maxBufSize); | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | return remaining; | ||
257 | } | 223 | } |
258 | 224 | ||
259 | static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) | 225 | static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) |
260 | { | 226 | { |
261 | struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; | 227 | struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; |
262 | struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; | 228 | struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; |
263 | int total_data_size; | ||
264 | int total_in_buf; | ||
265 | int remaining; | ||
266 | int total_in_buf2; | ||
267 | char *data_area_of_target; | 229 | char *data_area_of_target; |
268 | char *data_area_of_buf2; | 230 | char *data_area_of_buf2; |
269 | __u16 byte_count; | 231 | int remaining; |
232 | unsigned int byte_count, total_in_buf; | ||
233 | __u16 total_data_size, total_in_buf2; | ||
270 | 234 | ||
271 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | 235 | total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); |
272 | 236 | ||
273 | if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { | 237 | if (total_data_size != |
238 | get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount)) | ||
274 | cFYI(1, "total data size of primary and secondary t2 differ"); | 239 | cFYI(1, "total data size of primary and secondary t2 differ"); |
275 | } | ||
276 | 240 | ||
277 | total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); | 241 | total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); |
278 | 242 | ||
279 | remaining = total_data_size - total_in_buf; | 243 | remaining = total_data_size - total_in_buf; |
280 | 244 | ||
281 | if (remaining < 0) | 245 | if (remaining < 0) |
282 | return -EINVAL; | 246 | return -EPROTO; |
283 | 247 | ||
284 | if (remaining == 0) /* nothing to do, ignore */ | 248 | if (remaining == 0) /* nothing to do, ignore */ |
285 | return 0; | 249 | return 0; |
286 | 250 | ||
287 | total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); | 251 | total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount); |
288 | if (remaining < total_in_buf2) { | 252 | if (remaining < total_in_buf2) { |
289 | cFYI(1, "transact2 2nd response contains too much data"); | 253 | cFYI(1, "transact2 2nd response contains too much data"); |
290 | } | 254 | } |
291 | 255 | ||
292 | /* find end of first SMB data area */ | 256 | /* find end of first SMB data area */ |
293 | data_area_of_target = (char *)&pSMBt->hdr.Protocol + | 257 | data_area_of_target = (char *)&pSMBt->hdr.Protocol + |
294 | le16_to_cpu(pSMBt->t2_rsp.DataOffset); | 258 | get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); |
295 | /* validate target area */ | 259 | /* validate target area */ |
296 | 260 | ||
297 | data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + | 261 | data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol + |
298 | le16_to_cpu(pSMB2->t2_rsp.DataOffset); | 262 | get_unaligned_le16(&pSMB2->t2_rsp.DataOffset); |
299 | 263 | ||
300 | data_area_of_target += total_in_buf; | 264 | data_area_of_target += total_in_buf; |
301 | 265 | ||
302 | /* copy second buffer into end of first buffer */ | 266 | /* copy second buffer into end of first buffer */ |
303 | memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); | ||
304 | total_in_buf += total_in_buf2; | 267 | total_in_buf += total_in_buf2; |
305 | pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); | 268 | /* is the result too big for the field? */ |
306 | byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); | 269 | if (total_in_buf > USHRT_MAX) |
307 | byte_count += total_in_buf2; | 270 | return -EPROTO; |
308 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | 271 | put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); |
309 | 272 | ||
310 | byte_count = pTargetSMB->smb_buf_length; | 273 | /* fix up the BCC */ |
274 | byte_count = get_bcc(pTargetSMB); | ||
311 | byte_count += total_in_buf2; | 275 | byte_count += total_in_buf2; |
276 | /* is the result too big for the field? */ | ||
277 | if (byte_count > USHRT_MAX) | ||
278 | return -EPROTO; | ||
279 | put_bcc(byte_count, pTargetSMB); | ||
312 | 280 | ||
313 | /* BB also add check that we are not beyond maximum buffer size */ | 281 | byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); |
282 | byte_count += total_in_buf2; | ||
283 | /* don't allow buffer to overflow */ | ||
284 | if (byte_count > CIFSMaxBufSize) | ||
285 | return -ENOBUFS; | ||
286 | pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); | ||
314 | 287 | ||
315 | pTargetSMB->smb_buf_length = byte_count; | 288 | memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); |
316 | 289 | ||
317 | if (remaining == total_in_buf2) { | 290 | if (remaining == total_in_buf2) { |
318 | cFYI(1, "found the last secondary response"); | 291 | cFYI(1, "found the last secondary response"); |
319 | return 0; /* we are done */ | 292 | return 0; /* we are done */ |
320 | } else /* more responses to go */ | 293 | } else /* more responses to go */ |
321 | return 1; | 294 | return 1; |
295 | } | ||
296 | |||
297 | static void | ||
298 | cifs_echo_request(struct work_struct *work) | ||
299 | { | ||
300 | int rc; | ||
301 | struct TCP_Server_Info *server = container_of(work, | ||
302 | struct TCP_Server_Info, echo.work); | ||
303 | |||
304 | /* | ||
305 | * We cannot send an echo until the NEGOTIATE_PROTOCOL request is | ||
306 | * done, which is indicated by maxBuf != 0. Also, no need to ping if | ||
307 | * we got a response recently | ||
308 | */ | ||
309 | if (server->maxBuf == 0 || | ||
310 | time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) | ||
311 | goto requeue_echo; | ||
312 | |||
313 | rc = CIFSSMBEcho(server); | ||
314 | if (rc) | ||
315 | cFYI(1, "Unable to send echo request to server: %s", | ||
316 | server->hostname); | ||
322 | 317 | ||
318 | requeue_echo: | ||
319 | queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL); | ||
323 | } | 320 | } |
324 | 321 | ||
325 | static int | 322 | static int |
@@ -333,8 +330,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
333 | struct msghdr smb_msg; | 330 | struct msghdr smb_msg; |
334 | struct kvec iov; | 331 | struct kvec iov; |
335 | struct socket *csocket = server->ssocket; | 332 | struct socket *csocket = server->ssocket; |
336 | struct list_head *tmp; | 333 | struct list_head *tmp, *tmp2; |
337 | struct cifsSesInfo *ses; | ||
338 | struct task_struct *task_to_wake = NULL; | 334 | struct task_struct *task_to_wake = NULL; |
339 | struct mid_q_entry *mid_entry; | 335 | struct mid_q_entry *mid_entry; |
340 | char temp; | 336 | char temp; |
@@ -387,7 +383,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
387 | smb_msg.msg_control = NULL; | 383 | smb_msg.msg_control = NULL; |
388 | smb_msg.msg_controllen = 0; | 384 | smb_msg.msg_controllen = 0; |
389 | pdu_length = 4; /* enough to get RFC1001 header */ | 385 | pdu_length = 4; /* enough to get RFC1001 header */ |
386 | |||
390 | incomplete_rcv: | 387 | incomplete_rcv: |
388 | if (echo_retries > 0 && server->tcpStatus == CifsGood && | ||
389 | time_after(jiffies, server->lstrp + | ||
390 | (echo_retries * SMB_ECHO_INTERVAL))) { | ||
391 | cERROR(1, "Server %s has not responded in %d seconds. " | ||
392 | "Reconnecting...", server->hostname, | ||
393 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | ||
394 | cifs_reconnect(server); | ||
395 | csocket = server->ssocket; | ||
396 | wake_up(&server->response_q); | ||
397 | continue; | ||
398 | } | ||
399 | |||
391 | length = | 400 | length = |
392 | kernel_recvmsg(csocket, &smb_msg, | 401 | kernel_recvmsg(csocket, &smb_msg, |
393 | &iov, 1, pdu_length, 0 /* BB other flags? */); | 402 | &iov, 1, pdu_length, 0 /* BB other flags? */); |
@@ -441,8 +450,7 @@ incomplete_rcv: | |||
441 | /* Note that FC 1001 length is big endian on the wire, | 450 | /* Note that FC 1001 length is big endian on the wire, |
442 | but we convert it here so it is always manipulated | 451 | but we convert it here so it is always manipulated |
443 | as host byte order */ | 452 | as host byte order */ |
444 | pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length); | 453 | pdu_length = be32_to_cpu(smb_buffer->smb_buf_length); |
445 | smb_buffer->smb_buf_length = pdu_length; | ||
446 | 454 | ||
447 | cFYI(1, "rfc1002 length 0x%x", pdu_length+4); | 455 | cFYI(1, "rfc1002 length 0x%x", pdu_length+4); |
448 | 456 | ||
@@ -464,7 +472,7 @@ incomplete_rcv: | |||
464 | * initialize frame) | 472 | * initialize frame) |
465 | */ | 473 | */ |
466 | cifs_set_port((struct sockaddr *) | 474 | cifs_set_port((struct sockaddr *) |
467 | &server->addr.sockAddr, CIFS_PORT); | 475 | &server->dstaddr, CIFS_PORT); |
468 | cifs_reconnect(server); | 476 | cifs_reconnect(server); |
469 | csocket = server->ssocket; | 477 | csocket = server->ssocket; |
470 | wake_up(&server->response_q); | 478 | wake_up(&server->response_q); |
@@ -538,73 +546,92 @@ incomplete_rcv: | |||
538 | else if (reconnect == 1) | 546 | else if (reconnect == 1) |
539 | continue; | 547 | continue; |
540 | 548 | ||
541 | length += 4; /* account for rfc1002 hdr */ | 549 | total_read += 4; /* account for rfc1002 hdr */ |
542 | 550 | ||
551 | dump_smb(smb_buffer, total_read); | ||
543 | 552 | ||
544 | dump_smb(smb_buffer, length); | 553 | /* |
545 | if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) { | 554 | * We know that we received enough to get to the MID as we |
546 | cifs_dump_mem("Bad SMB: ", smb_buffer, 48); | 555 | * checked the pdu_length earlier. Now check to see |
547 | continue; | 556 | * if the rest of the header is OK. We borrow the length |
548 | } | 557 | * var for the rest of the loop to avoid a new stack var. |
558 | * | ||
559 | * 48 bytes is enough to display the header and a little bit | ||
560 | * into the payload for debugging purposes. | ||
561 | */ | ||
562 | length = checkSMB(smb_buffer, smb_buffer->Mid, total_read); | ||
563 | if (length != 0) | ||
564 | cifs_dump_mem("Bad SMB: ", smb_buffer, | ||
565 | min_t(unsigned int, total_read, 48)); | ||
549 | 566 | ||
567 | mid_entry = NULL; | ||
568 | server->lstrp = jiffies; | ||
550 | 569 | ||
551 | task_to_wake = NULL; | ||
552 | spin_lock(&GlobalMid_Lock); | 570 | spin_lock(&GlobalMid_Lock); |
553 | list_for_each(tmp, &server->pending_mid_q) { | 571 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
554 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 572 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
555 | 573 | ||
556 | if ((mid_entry->mid == smb_buffer->Mid) && | 574 | if (mid_entry->mid != smb_buffer->Mid || |
557 | (mid_entry->midState == MID_REQUEST_SUBMITTED) && | 575 | mid_entry->midState != MID_REQUEST_SUBMITTED || |
558 | (mid_entry->command == smb_buffer->Command)) { | 576 | mid_entry->command != smb_buffer->Command) { |
559 | if (check2ndT2(smb_buffer,server->maxBuf) > 0) { | 577 | mid_entry = NULL; |
560 | /* We have a multipart transact2 resp */ | 578 | continue; |
561 | isMultiRsp = true; | 579 | } |
562 | if (mid_entry->resp_buf) { | 580 | |
563 | /* merge response - fix up 1st*/ | 581 | if (length == 0 && |
564 | if (coalesce_t2(smb_buffer, | 582 | check2ndT2(smb_buffer, server->maxBuf) > 0) { |
565 | mid_entry->resp_buf)) { | 583 | /* We have a multipart transact2 resp */ |
566 | mid_entry->multiRsp = | 584 | isMultiRsp = true; |
567 | true; | 585 | if (mid_entry->resp_buf) { |
568 | break; | 586 | /* merge response - fix up 1st*/ |
569 | } else { | 587 | length = coalesce_t2(smb_buffer, |
570 | /* all parts received */ | 588 | mid_entry->resp_buf); |
571 | mid_entry->multiEnd = | 589 | if (length > 0) { |
572 | true; | 590 | length = 0; |
573 | goto multi_t2_fnd; | 591 | mid_entry->multiRsp = true; |
574 | } | 592 | break; |
575 | } else { | 593 | } else { |
576 | if (!isLargeBuf) { | 594 | /* all parts received or |
577 | cERROR(1, "1st trans2 resp needs bigbuf"); | 595 | * packet is malformed |
578 | /* BB maybe we can fix this up, switch | 596 | */ |
579 | to already allocated large buffer? */ | 597 | mid_entry->multiEnd = true; |
580 | } else { | 598 | goto multi_t2_fnd; |
581 | /* Have first buffer */ | 599 | } |
582 | mid_entry->resp_buf = | 600 | } else { |
583 | smb_buffer; | 601 | if (!isLargeBuf) { |
584 | mid_entry->largeBuf = | 602 | /* |
585 | true; | 603 | * FIXME: switch to already |
586 | bigbuf = NULL; | 604 | * allocated largebuf? |
587 | } | 605 | */ |
606 | cERROR(1, "1st trans2 resp " | ||
607 | "needs bigbuf"); | ||
608 | } else { | ||
609 | /* Have first buffer */ | ||
610 | mid_entry->resp_buf = | ||
611 | smb_buffer; | ||
612 | mid_entry->largeBuf = true; | ||
613 | bigbuf = NULL; | ||
588 | } | 614 | } |
589 | break; | ||
590 | } | 615 | } |
591 | mid_entry->resp_buf = smb_buffer; | 616 | break; |
592 | mid_entry->largeBuf = isLargeBuf; | 617 | } |
618 | mid_entry->resp_buf = smb_buffer; | ||
619 | mid_entry->largeBuf = isLargeBuf; | ||
593 | multi_t2_fnd: | 620 | multi_t2_fnd: |
594 | task_to_wake = mid_entry->tsk; | 621 | if (length == 0) |
595 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 622 | mid_entry->midState = MID_RESPONSE_RECEIVED; |
623 | else | ||
624 | mid_entry->midState = MID_RESPONSE_MALFORMED; | ||
596 | #ifdef CONFIG_CIFS_STATS2 | 625 | #ifdef CONFIG_CIFS_STATS2 |
597 | mid_entry->when_received = jiffies; | 626 | mid_entry->when_received = jiffies; |
598 | #endif | 627 | #endif |
599 | /* so we do not time out requests to server | 628 | list_del_init(&mid_entry->qhead); |
600 | which is still responding (since server could | 629 | break; |
601 | be busy but not dead) */ | ||
602 | server->lstrp = jiffies; | ||
603 | break; | ||
604 | } | ||
605 | } | 630 | } |
606 | spin_unlock(&GlobalMid_Lock); | 631 | spin_unlock(&GlobalMid_Lock); |
607 | if (task_to_wake) { | 632 | |
633 | if (mid_entry != NULL) { | ||
634 | mid_entry->callback(mid_entry); | ||
608 | /* Was previous buf put in mpx struct for multi-rsp? */ | 635 | /* Was previous buf put in mpx struct for multi-rsp? */ |
609 | if (!isMultiRsp) { | 636 | if (!isMultiRsp) { |
610 | /* smb buffer will be freed by user thread */ | 637 | /* smb buffer will be freed by user thread */ |
@@ -613,11 +640,13 @@ multi_t2_fnd: | |||
613 | else | 640 | else |
614 | smallbuf = NULL; | 641 | smallbuf = NULL; |
615 | } | 642 | } |
616 | wake_up_process(task_to_wake); | 643 | } else if (length != 0) { |
644 | /* response sanity checks failed */ | ||
645 | continue; | ||
617 | } else if (!is_valid_oplock_break(smb_buffer, server) && | 646 | } else if (!is_valid_oplock_break(smb_buffer, server) && |
618 | !isMultiRsp) { | 647 | !isMultiRsp) { |
619 | cERROR(1, "No task to wake, unknown frame received! " | 648 | cERROR(1, "No task to wake, unknown frame received! " |
620 | "NumMids %d", midCount.counter); | 649 | "NumMids %d", atomic_read(&midCount)); |
621 | cifs_dump_mem("Received Data is: ", (char *)smb_buffer, | 650 | cifs_dump_mem("Received Data is: ", (char *)smb_buffer, |
622 | sizeof(struct smb_hdr)); | 651 | sizeof(struct smb_hdr)); |
623 | #ifdef CONFIG_CIFS_DEBUG2 | 652 | #ifdef CONFIG_CIFS_DEBUG2 |
@@ -629,9 +658,9 @@ multi_t2_fnd: | |||
629 | } /* end while !EXITING */ | 658 | } /* end while !EXITING */ |
630 | 659 | ||
631 | /* take it off the list, if it's not already */ | 660 | /* take it off the list, if it's not already */ |
632 | write_lock(&cifs_tcp_ses_lock); | 661 | spin_lock(&cifs_tcp_ses_lock); |
633 | list_del_init(&server->tcp_ses_list); | 662 | list_del_init(&server->tcp_ses_list); |
634 | write_unlock(&cifs_tcp_ses_lock); | 663 | spin_unlock(&cifs_tcp_ses_lock); |
635 | 664 | ||
636 | spin_lock(&GlobalMid_Lock); | 665 | spin_lock(&GlobalMid_Lock); |
637 | server->tcpStatus = CifsExiting; | 666 | server->tcpStatus = CifsExiting; |
@@ -660,49 +689,31 @@ multi_t2_fnd: | |||
660 | sock_release(csocket); | 689 | sock_release(csocket); |
661 | server->ssocket = NULL; | 690 | server->ssocket = NULL; |
662 | } | 691 | } |
663 | /* buffer usuallly freed in free_mid - need to free it here on exit */ | 692 | /* buffer usually freed in free_mid - need to free it here on exit */ |
664 | cifs_buf_release(bigbuf); | 693 | cifs_buf_release(bigbuf); |
665 | if (smallbuf) /* no sense logging a debug message if NULL */ | 694 | if (smallbuf) /* no sense logging a debug message if NULL */ |
666 | cifs_small_buf_release(smallbuf); | 695 | cifs_small_buf_release(smallbuf); |
667 | 696 | ||
668 | /* | 697 | if (!list_empty(&server->pending_mid_q)) { |
669 | * BB: we shouldn't have to do any of this. It shouldn't be | 698 | struct list_head dispose_list; |
670 | * possible to exit from the thread with active SMB sessions | ||
671 | */ | ||
672 | read_lock(&cifs_tcp_ses_lock); | ||
673 | if (list_empty(&server->pending_mid_q)) { | ||
674 | /* loop through server session structures attached to this and | ||
675 | mark them dead */ | ||
676 | list_for_each(tmp, &server->smb_ses_list) { | ||
677 | ses = list_entry(tmp, struct cifsSesInfo, | ||
678 | smb_ses_list); | ||
679 | ses->status = CifsExiting; | ||
680 | ses->server = NULL; | ||
681 | } | ||
682 | read_unlock(&cifs_tcp_ses_lock); | ||
683 | } else { | ||
684 | /* although we can not zero the server struct pointer yet, | ||
685 | since there are active requests which may depnd on them, | ||
686 | mark the corresponding SMB sessions as exiting too */ | ||
687 | list_for_each(tmp, &server->smb_ses_list) { | ||
688 | ses = list_entry(tmp, struct cifsSesInfo, | ||
689 | smb_ses_list); | ||
690 | ses->status = CifsExiting; | ||
691 | } | ||
692 | 699 | ||
700 | INIT_LIST_HEAD(&dispose_list); | ||
693 | spin_lock(&GlobalMid_Lock); | 701 | spin_lock(&GlobalMid_Lock); |
694 | list_for_each(tmp, &server->pending_mid_q) { | 702 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
695 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 703 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
696 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | 704 | cFYI(1, "Clearing mid 0x%x", mid_entry->mid); |
697 | cFYI(1, "Clearing Mid 0x%x - waking up ", | 705 | mid_entry->midState = MID_SHUTDOWN; |
698 | mid_entry->mid); | 706 | list_move(&mid_entry->qhead, &dispose_list); |
699 | task_to_wake = mid_entry->tsk; | ||
700 | if (task_to_wake) | ||
701 | wake_up_process(task_to_wake); | ||
702 | } | ||
703 | } | 707 | } |
704 | spin_unlock(&GlobalMid_Lock); | 708 | spin_unlock(&GlobalMid_Lock); |
705 | read_unlock(&cifs_tcp_ses_lock); | 709 | |
710 | /* now walk dispose list and issue callbacks */ | ||
711 | list_for_each_safe(tmp, tmp2, &dispose_list) { | ||
712 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
713 | cFYI(1, "Callback mid 0x%x", mid_entry->mid); | ||
714 | list_del_init(&mid_entry->qhead); | ||
715 | mid_entry->callback(mid_entry); | ||
716 | } | ||
706 | /* 1/8th of sec is more than enough time for them to exit */ | 717 | /* 1/8th of sec is more than enough time for them to exit */ |
707 | msleep(125); | 718 | msleep(125); |
708 | } | 719 | } |
@@ -720,18 +731,6 @@ multi_t2_fnd: | |||
720 | coming home not much else we can do but free the memory */ | 731 | coming home not much else we can do but free the memory */ |
721 | } | 732 | } |
722 | 733 | ||
723 | /* last chance to mark ses pointers invalid | ||
724 | if there are any pointing to this (e.g | ||
725 | if a crazy root user tried to kill cifsd | ||
726 | kernel thread explicitly this might happen) */ | ||
727 | /* BB: This shouldn't be necessary, see above */ | ||
728 | read_lock(&cifs_tcp_ses_lock); | ||
729 | list_for_each(tmp, &server->smb_ses_list) { | ||
730 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | ||
731 | ses->server = NULL; | ||
732 | } | ||
733 | read_unlock(&cifs_tcp_ses_lock); | ||
734 | |||
735 | kfree(server->hostname); | 734 | kfree(server->hostname); |
736 | task_to_wake = xchg(&server->tsk, NULL); | 735 | task_to_wake = xchg(&server->tsk, NULL); |
737 | kfree(server); | 736 | kfree(server); |
@@ -783,35 +782,32 @@ extract_hostname(const char *unc) | |||
783 | } | 782 | } |
784 | 783 | ||
785 | static int | 784 | static int |
786 | cifs_parse_mount_options(char *options, const char *devname, | 785 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
787 | struct smb_vol *vol) | 786 | struct smb_vol *vol) |
788 | { | 787 | { |
789 | char *value; | 788 | char *value, *data, *end; |
790 | char *data; | 789 | char *mountdata_copy = NULL, *options; |
791 | unsigned int temp_len, i, j; | 790 | unsigned int temp_len, i, j; |
792 | char separator[2]; | 791 | char separator[2]; |
793 | short int override_uid = -1; | 792 | short int override_uid = -1; |
794 | short int override_gid = -1; | 793 | short int override_gid = -1; |
795 | bool uid_specified = false; | 794 | bool uid_specified = false; |
796 | bool gid_specified = false; | 795 | bool gid_specified = false; |
796 | char *nodename = utsname()->nodename; | ||
797 | 797 | ||
798 | separator[0] = ','; | 798 | separator[0] = ','; |
799 | separator[1] = 0; | 799 | separator[1] = 0; |
800 | 800 | ||
801 | if (Local_System_Name[0] != 0) | 801 | /* |
802 | memcpy(vol->source_rfc1001_name, Local_System_Name, 15); | 802 | * does not have to be perfect mapping since field is |
803 | else { | 803 | * informational, only used for servers that do not support |
804 | char *nodename = utsname()->nodename; | 804 | * port 445 and it can be overridden at mount time |
805 | int n = strnlen(nodename, 15); | 805 | */ |
806 | memset(vol->source_rfc1001_name, 0x20, 15); | 806 | memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); |
807 | for (i = 0; i < n; i++) { | 807 | for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) |
808 | /* does not have to be perfect mapping since field is | 808 | vol->source_rfc1001_name[i] = toupper(nodename[i]); |
809 | informational, only used for servers that do not support | 809 | |
810 | port 445 and it can be overridden at mount time */ | 810 | vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0; |
811 | vol->source_rfc1001_name[i] = toupper(nodename[i]); | ||
812 | } | ||
813 | } | ||
814 | vol->source_rfc1001_name[15] = 0; | ||
815 | /* null target name indicates to use *SMBSERVR default called name | 811 | /* null target name indicates to use *SMBSERVR default called name |
816 | if we end up sending RFC1001 session initialize */ | 812 | if we end up sending RFC1001 session initialize */ |
817 | vol->target_rfc1001_name[0] = 0; | 813 | vol->target_rfc1001_name[0] = 0; |
@@ -828,9 +824,17 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
828 | /* default to using server inode numbers where available */ | 824 | /* default to using server inode numbers where available */ |
829 | vol->server_ino = 1; | 825 | vol->server_ino = 1; |
830 | 826 | ||
831 | if (!options) | 827 | vol->actimeo = CIFS_DEF_ACTIMEO; |
832 | return 1; | 828 | |
829 | if (!mountdata) | ||
830 | goto cifs_parse_mount_err; | ||
833 | 831 | ||
832 | mountdata_copy = kstrndup(mountdata, PAGE_SIZE, GFP_KERNEL); | ||
833 | if (!mountdata_copy) | ||
834 | goto cifs_parse_mount_err; | ||
835 | |||
836 | options = mountdata_copy; | ||
837 | end = options + strlen(options); | ||
834 | if (strncmp(options, "sep=", 4) == 0) { | 838 | if (strncmp(options, "sep=", 4) == 0) { |
835 | if (options[4] != 0) { | 839 | if (options[4] != 0) { |
836 | separator[0] = options[4]; | 840 | separator[0] = options[4]; |
@@ -855,16 +859,22 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
855 | if (!value) { | 859 | if (!value) { |
856 | printk(KERN_WARNING | 860 | printk(KERN_WARNING |
857 | "CIFS: invalid or missing username\n"); | 861 | "CIFS: invalid or missing username\n"); |
858 | return 1; /* needs_arg; */ | 862 | goto cifs_parse_mount_err; |
859 | } else if (!*value) { | 863 | } else if (!*value) { |
860 | /* null user, ie anonymous, authentication */ | 864 | /* null user, ie anonymous, authentication */ |
861 | vol->nullauth = 1; | 865 | vol->nullauth = 1; |
862 | } | 866 | } |
863 | if (strnlen(value, 200) < 200) { | 867 | if (strnlen(value, MAX_USERNAME_SIZE) < |
864 | vol->username = value; | 868 | MAX_USERNAME_SIZE) { |
869 | vol->username = kstrdup(value, GFP_KERNEL); | ||
870 | if (!vol->username) { | ||
871 | printk(KERN_WARNING "CIFS: no memory " | ||
872 | "for username\n"); | ||
873 | goto cifs_parse_mount_err; | ||
874 | } | ||
865 | } else { | 875 | } else { |
866 | printk(KERN_WARNING "CIFS: username too long\n"); | 876 | printk(KERN_WARNING "CIFS: username too long\n"); |
867 | return 1; | 877 | goto cifs_parse_mount_err; |
868 | } | 878 | } |
869 | } else if (strnicmp(data, "pass", 4) == 0) { | 879 | } else if (strnicmp(data, "pass", 4) == 0) { |
870 | if (!value) { | 880 | if (!value) { |
@@ -895,6 +905,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
895 | the only illegal character in a password is null */ | 905 | the only illegal character in a password is null */ |
896 | 906 | ||
897 | if ((value[temp_len] == 0) && | 907 | if ((value[temp_len] == 0) && |
908 | (value + temp_len < end) && | ||
898 | (value[temp_len+1] == separator[0])) { | 909 | (value[temp_len+1] == separator[0])) { |
899 | /* reinsert comma */ | 910 | /* reinsert comma */ |
900 | value[temp_len] = separator[0]; | 911 | value[temp_len] = separator[0]; |
@@ -927,7 +938,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
927 | if (vol->password == NULL) { | 938 | if (vol->password == NULL) { |
928 | printk(KERN_WARNING "CIFS: no memory " | 939 | printk(KERN_WARNING "CIFS: no memory " |
929 | "for password\n"); | 940 | "for password\n"); |
930 | return 1; | 941 | goto cifs_parse_mount_err; |
931 | } | 942 | } |
932 | for (i = 0, j = 0; i < temp_len; i++, j++) { | 943 | for (i = 0, j = 0; i < temp_len; i++, j++) { |
933 | vol->password[j] = value[i]; | 944 | vol->password[j] = value[i]; |
@@ -943,7 +954,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
943 | if (vol->password == NULL) { | 954 | if (vol->password == NULL) { |
944 | printk(KERN_WARNING "CIFS: no memory " | 955 | printk(KERN_WARNING "CIFS: no memory " |
945 | "for password\n"); | 956 | "for password\n"); |
946 | return 1; | 957 | goto cifs_parse_mount_err; |
947 | } | 958 | } |
948 | strcpy(vol->password, value); | 959 | strcpy(vol->password, value); |
949 | } | 960 | } |
@@ -953,11 +964,16 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
953 | vol->UNCip = NULL; | 964 | vol->UNCip = NULL; |
954 | } else if (strnlen(value, INET6_ADDRSTRLEN) < | 965 | } else if (strnlen(value, INET6_ADDRSTRLEN) < |
955 | INET6_ADDRSTRLEN) { | 966 | INET6_ADDRSTRLEN) { |
956 | vol->UNCip = value; | 967 | vol->UNCip = kstrdup(value, GFP_KERNEL); |
968 | if (!vol->UNCip) { | ||
969 | printk(KERN_WARNING "CIFS: no memory " | ||
970 | "for UNC IP\n"); | ||
971 | goto cifs_parse_mount_err; | ||
972 | } | ||
957 | } else { | 973 | } else { |
958 | printk(KERN_WARNING "CIFS: ip address " | 974 | printk(KERN_WARNING "CIFS: ip address " |
959 | "too long\n"); | 975 | "too long\n"); |
960 | return 1; | 976 | goto cifs_parse_mount_err; |
961 | } | 977 | } |
962 | } else if (strnicmp(data, "sec", 3) == 0) { | 978 | } else if (strnicmp(data, "sec", 3) == 0) { |
963 | if (!value || !*value) { | 979 | if (!value || !*value) { |
@@ -970,16 +986,14 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
970 | /* vol->secFlg |= CIFSSEC_MUST_SEAL | | 986 | /* vol->secFlg |= CIFSSEC_MUST_SEAL | |
971 | CIFSSEC_MAY_KRB5; */ | 987 | CIFSSEC_MAY_KRB5; */ |
972 | cERROR(1, "Krb5 cifs privacy not supported"); | 988 | cERROR(1, "Krb5 cifs privacy not supported"); |
973 | return 1; | 989 | goto cifs_parse_mount_err; |
974 | } else if (strnicmp(value, "krb5", 4) == 0) { | 990 | } else if (strnicmp(value, "krb5", 4) == 0) { |
975 | vol->secFlg |= CIFSSEC_MAY_KRB5; | 991 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
976 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
977 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { | 992 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { |
978 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | | 993 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | |
979 | CIFSSEC_MUST_SIGN; | 994 | CIFSSEC_MUST_SIGN; |
980 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { | 995 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { |
981 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; | 996 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; |
982 | #endif | ||
983 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 997 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
984 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | | 998 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
985 | CIFSSEC_MUST_SIGN; | 999 | CIFSSEC_MUST_SIGN; |
@@ -1002,7 +1016,16 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1002 | vol->nullauth = 1; | 1016 | vol->nullauth = 1; |
1003 | } else { | 1017 | } else { |
1004 | cERROR(1, "bad security option: %s", value); | 1018 | cERROR(1, "bad security option: %s", value); |
1005 | return 1; | 1019 | goto cifs_parse_mount_err; |
1020 | } | ||
1021 | } else if (strnicmp(data, "vers", 3) == 0) { | ||
1022 | if (!value || !*value) { | ||
1023 | cERROR(1, "no protocol version specified" | ||
1024 | " after vers= mount option"); | ||
1025 | } else if ((strnicmp(value, "cifs", 4) == 0) || | ||
1026 | (strnicmp(value, "1", 1) == 0)) { | ||
1027 | /* this is the default */ | ||
1028 | continue; | ||
1006 | } | 1029 | } |
1007 | } else if ((strnicmp(data, "unc", 3) == 0) | 1030 | } else if ((strnicmp(data, "unc", 3) == 0) |
1008 | || (strnicmp(data, "target", 6) == 0) | 1031 | || (strnicmp(data, "target", 6) == 0) |
@@ -1010,12 +1033,12 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1010 | if (!value || !*value) { | 1033 | if (!value || !*value) { |
1011 | printk(KERN_WARNING "CIFS: invalid path to " | 1034 | printk(KERN_WARNING "CIFS: invalid path to " |
1012 | "network resource\n"); | 1035 | "network resource\n"); |
1013 | return 1; /* needs_arg; */ | 1036 | goto cifs_parse_mount_err; |
1014 | } | 1037 | } |
1015 | if ((temp_len = strnlen(value, 300)) < 300) { | 1038 | if ((temp_len = strnlen(value, 300)) < 300) { |
1016 | vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); | 1039 | vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); |
1017 | if (vol->UNC == NULL) | 1040 | if (vol->UNC == NULL) |
1018 | return 1; | 1041 | goto cifs_parse_mount_err; |
1019 | strcpy(vol->UNC, value); | 1042 | strcpy(vol->UNC, value); |
1020 | if (strncmp(vol->UNC, "//", 2) == 0) { | 1043 | if (strncmp(vol->UNC, "//", 2) == 0) { |
1021 | vol->UNC[0] = '\\'; | 1044 | vol->UNC[0] = '\\'; |
@@ -1024,40 +1047,61 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1024 | printk(KERN_WARNING | 1047 | printk(KERN_WARNING |
1025 | "CIFS: UNC Path does not begin " | 1048 | "CIFS: UNC Path does not begin " |
1026 | "with // or \\\\ \n"); | 1049 | "with // or \\\\ \n"); |
1027 | return 1; | 1050 | goto cifs_parse_mount_err; |
1028 | } | 1051 | } |
1029 | } else { | 1052 | } else { |
1030 | printk(KERN_WARNING "CIFS: UNC name too long\n"); | 1053 | printk(KERN_WARNING "CIFS: UNC name too long\n"); |
1031 | return 1; | 1054 | goto cifs_parse_mount_err; |
1032 | } | 1055 | } |
1033 | } else if ((strnicmp(data, "domain", 3) == 0) | 1056 | } else if ((strnicmp(data, "domain", 3) == 0) |
1034 | || (strnicmp(data, "workgroup", 5) == 0)) { | 1057 | || (strnicmp(data, "workgroup", 5) == 0)) { |
1035 | if (!value || !*value) { | 1058 | if (!value || !*value) { |
1036 | printk(KERN_WARNING "CIFS: invalid domain name\n"); | 1059 | printk(KERN_WARNING "CIFS: invalid domain name\n"); |
1037 | return 1; /* needs_arg; */ | 1060 | goto cifs_parse_mount_err; |
1038 | } | 1061 | } |
1039 | /* BB are there cases in which a comma can be valid in | 1062 | /* BB are there cases in which a comma can be valid in |
1040 | a domain name and need special handling? */ | 1063 | a domain name and need special handling? */ |
1041 | if (strnlen(value, 256) < 256) { | 1064 | if (strnlen(value, 256) < 256) { |
1042 | vol->domainname = value; | 1065 | vol->domainname = kstrdup(value, GFP_KERNEL); |
1066 | if (!vol->domainname) { | ||
1067 | printk(KERN_WARNING "CIFS: no memory " | ||
1068 | "for domainname\n"); | ||
1069 | goto cifs_parse_mount_err; | ||
1070 | } | ||
1043 | cFYI(1, "Domain name set"); | 1071 | cFYI(1, "Domain name set"); |
1044 | } else { | 1072 | } else { |
1045 | printk(KERN_WARNING "CIFS: domain name too " | 1073 | printk(KERN_WARNING "CIFS: domain name too " |
1046 | "long\n"); | 1074 | "long\n"); |
1047 | return 1; | 1075 | goto cifs_parse_mount_err; |
1076 | } | ||
1077 | } else if (strnicmp(data, "srcaddr", 7) == 0) { | ||
1078 | vol->srcaddr.ss_family = AF_UNSPEC; | ||
1079 | |||
1080 | if (!value || !*value) { | ||
1081 | printk(KERN_WARNING "CIFS: srcaddr value" | ||
1082 | " not specified.\n"); | ||
1083 | goto cifs_parse_mount_err; | ||
1084 | } | ||
1085 | i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, | ||
1086 | value, strlen(value)); | ||
1087 | if (i == 0) { | ||
1088 | printk(KERN_WARNING "CIFS: Could not parse" | ||
1089 | " srcaddr: %s\n", | ||
1090 | value); | ||
1091 | goto cifs_parse_mount_err; | ||
1048 | } | 1092 | } |
1049 | } else if (strnicmp(data, "prefixpath", 10) == 0) { | 1093 | } else if (strnicmp(data, "prefixpath", 10) == 0) { |
1050 | if (!value || !*value) { | 1094 | if (!value || !*value) { |
1051 | printk(KERN_WARNING | 1095 | printk(KERN_WARNING |
1052 | "CIFS: invalid path prefix\n"); | 1096 | "CIFS: invalid path prefix\n"); |
1053 | return 1; /* needs_argument */ | 1097 | goto cifs_parse_mount_err; |
1054 | } | 1098 | } |
1055 | if ((temp_len = strnlen(value, 1024)) < 1024) { | 1099 | if ((temp_len = strnlen(value, 1024)) < 1024) { |
1056 | if (value[0] != '/') | 1100 | if (value[0] != '/') |
1057 | temp_len++; /* missing leading slash */ | 1101 | temp_len++; /* missing leading slash */ |
1058 | vol->prepath = kmalloc(temp_len+1, GFP_KERNEL); | 1102 | vol->prepath = kmalloc(temp_len+1, GFP_KERNEL); |
1059 | if (vol->prepath == NULL) | 1103 | if (vol->prepath == NULL) |
1060 | return 1; | 1104 | goto cifs_parse_mount_err; |
1061 | if (value[0] != '/') { | 1105 | if (value[0] != '/') { |
1062 | vol->prepath[0] = '/'; | 1106 | vol->prepath[0] = '/'; |
1063 | strcpy(vol->prepath+1, value); | 1107 | strcpy(vol->prepath+1, value); |
@@ -1066,28 +1110,39 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1066 | cFYI(1, "prefix path %s", vol->prepath); | 1110 | cFYI(1, "prefix path %s", vol->prepath); |
1067 | } else { | 1111 | } else { |
1068 | printk(KERN_WARNING "CIFS: prefix too long\n"); | 1112 | printk(KERN_WARNING "CIFS: prefix too long\n"); |
1069 | return 1; | 1113 | goto cifs_parse_mount_err; |
1070 | } | 1114 | } |
1071 | } else if (strnicmp(data, "iocharset", 9) == 0) { | 1115 | } else if (strnicmp(data, "iocharset", 9) == 0) { |
1072 | if (!value || !*value) { | 1116 | if (!value || !*value) { |
1073 | printk(KERN_WARNING "CIFS: invalid iocharset " | 1117 | printk(KERN_WARNING "CIFS: invalid iocharset " |
1074 | "specified\n"); | 1118 | "specified\n"); |
1075 | return 1; /* needs_arg; */ | 1119 | goto cifs_parse_mount_err; |
1076 | } | 1120 | } |
1077 | if (strnlen(value, 65) < 65) { | 1121 | if (strnlen(value, 65) < 65) { |
1078 | if (strnicmp(value, "default", 7)) | 1122 | if (strnicmp(value, "default", 7)) { |
1079 | vol->iocharset = value; | 1123 | vol->iocharset = kstrdup(value, |
1124 | GFP_KERNEL); | ||
1125 | |||
1126 | if (!vol->iocharset) { | ||
1127 | printk(KERN_WARNING "CIFS: no " | ||
1128 | "memory for" | ||
1129 | "charset\n"); | ||
1130 | goto cifs_parse_mount_err; | ||
1131 | } | ||
1132 | } | ||
1080 | /* if iocharset not set then load_nls_default | 1133 | /* if iocharset not set then load_nls_default |
1081 | is used by caller */ | 1134 | is used by caller */ |
1082 | cFYI(1, "iocharset set to %s", value); | 1135 | cFYI(1, "iocharset set to %s", value); |
1083 | } else { | 1136 | } else { |
1084 | printk(KERN_WARNING "CIFS: iocharset name " | 1137 | printk(KERN_WARNING "CIFS: iocharset name " |
1085 | "too long.\n"); | 1138 | "too long.\n"); |
1086 | return 1; | 1139 | goto cifs_parse_mount_err; |
1087 | } | 1140 | } |
1088 | } else if (!strnicmp(data, "uid", 3) && value && *value) { | 1141 | } else if (!strnicmp(data, "uid", 3) && value && *value) { |
1089 | vol->linux_uid = simple_strtoul(value, &value, 0); | 1142 | vol->linux_uid = simple_strtoul(value, &value, 0); |
1090 | uid_specified = true; | 1143 | uid_specified = true; |
1144 | } else if (!strnicmp(data, "cruid", 5) && value && *value) { | ||
1145 | vol->cred_uid = simple_strtoul(value, &value, 0); | ||
1091 | } else if (!strnicmp(data, "forceuid", 8)) { | 1146 | } else if (!strnicmp(data, "forceuid", 8)) { |
1092 | override_uid = 1; | 1147 | override_uid = 1; |
1093 | } else if (!strnicmp(data, "noforceuid", 10)) { | 1148 | } else if (!strnicmp(data, "noforceuid", 10)) { |
@@ -1140,22 +1195,22 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1140 | if (!value || !*value || (*value == ' ')) { | 1195 | if (!value || !*value || (*value == ' ')) { |
1141 | cFYI(1, "invalid (empty) netbiosname"); | 1196 | cFYI(1, "invalid (empty) netbiosname"); |
1142 | } else { | 1197 | } else { |
1143 | memset(vol->source_rfc1001_name, 0x20, 15); | 1198 | memset(vol->source_rfc1001_name, 0x20, |
1144 | for (i = 0; i < 15; i++) { | 1199 | RFC1001_NAME_LEN); |
1145 | /* BB are there cases in which a comma can be | 1200 | /* |
1146 | valid in this workstation netbios name (and need | 1201 | * FIXME: are there cases in which a comma can |
1147 | special handling)? */ | 1202 | * be valid in workstation netbios name (and |
1148 | 1203 | * need special handling)? | |
1149 | /* We do not uppercase netbiosname for user */ | 1204 | */ |
1205 | for (i = 0; i < RFC1001_NAME_LEN; i++) { | ||
1206 | /* don't ucase netbiosname for user */ | ||
1150 | if (value[i] == 0) | 1207 | if (value[i] == 0) |
1151 | break; | 1208 | break; |
1152 | else | 1209 | vol->source_rfc1001_name[i] = value[i]; |
1153 | vol->source_rfc1001_name[i] = | ||
1154 | value[i]; | ||
1155 | } | 1210 | } |
1156 | /* The string has 16th byte zero still from | 1211 | /* The string has 16th byte zero still from |
1157 | set at top of the function */ | 1212 | set at top of the function */ |
1158 | if ((i == 15) && (value[i] != 0)) | 1213 | if (i == RFC1001_NAME_LEN && value[i] != 0) |
1159 | printk(KERN_WARNING "CIFS: netbiosname" | 1214 | printk(KERN_WARNING "CIFS: netbiosname" |
1160 | " longer than 15 truncated.\n"); | 1215 | " longer than 15 truncated.\n"); |
1161 | } | 1216 | } |
@@ -1165,7 +1220,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1165 | cFYI(1, "empty server netbiosname specified"); | 1220 | cFYI(1, "empty server netbiosname specified"); |
1166 | } else { | 1221 | } else { |
1167 | /* last byte, type, is 0x20 for servr type */ | 1222 | /* last byte, type, is 0x20 for servr type */ |
1168 | memset(vol->target_rfc1001_name, 0x20, 16); | 1223 | memset(vol->target_rfc1001_name, 0x20, |
1224 | RFC1001_NAME_LEN_WITH_NULL); | ||
1169 | 1225 | ||
1170 | for (i = 0; i < 15; i++) { | 1226 | for (i = 0; i < 15; i++) { |
1171 | /* BB are there cases in which a comma can be | 1227 | /* BB are there cases in which a comma can be |
@@ -1182,10 +1238,20 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1182 | } | 1238 | } |
1183 | /* The string has 16th byte zero still from | 1239 | /* The string has 16th byte zero still from |
1184 | set at top of the function */ | 1240 | set at top of the function */ |
1185 | if ((i == 15) && (value[i] != 0)) | 1241 | if (i == RFC1001_NAME_LEN && value[i] != 0) |
1186 | printk(KERN_WARNING "CIFS: server net" | 1242 | printk(KERN_WARNING "CIFS: server net" |
1187 | "biosname longer than 15 truncated.\n"); | 1243 | "biosname longer than 15 truncated.\n"); |
1188 | } | 1244 | } |
1245 | } else if (strnicmp(data, "actimeo", 7) == 0) { | ||
1246 | if (value && *value) { | ||
1247 | vol->actimeo = HZ * simple_strtoul(value, | ||
1248 | &value, 0); | ||
1249 | if (vol->actimeo > CIFS_MAX_ACTIMEO) { | ||
1250 | cERROR(1, "CIFS: attribute cache" | ||
1251 | "timeout too large"); | ||
1252 | goto cifs_parse_mount_err; | ||
1253 | } | ||
1254 | } | ||
1189 | } else if (strnicmp(data, "credentials", 4) == 0) { | 1255 | } else if (strnicmp(data, "credentials", 4) == 0) { |
1190 | /* ignore */ | 1256 | /* ignore */ |
1191 | } else if (strnicmp(data, "version", 3) == 0) { | 1257 | } else if (strnicmp(data, "version", 3) == 0) { |
@@ -1295,6 +1361,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1295 | vol->server_ino = 1; | 1361 | vol->server_ino = 1; |
1296 | } else if (strnicmp(data, "noserverino", 9) == 0) { | 1362 | } else if (strnicmp(data, "noserverino", 9) == 0) { |
1297 | vol->server_ino = 0; | 1363 | vol->server_ino = 0; |
1364 | } else if (strnicmp(data, "rwpidforward", 4) == 0) { | ||
1365 | vol->rwpidforward = 1; | ||
1298 | } else if (strnicmp(data, "cifsacl", 7) == 0) { | 1366 | } else if (strnicmp(data, "cifsacl", 7) == 0) { |
1299 | vol->cifs_acl = 1; | 1367 | vol->cifs_acl = 1; |
1300 | } else if (strnicmp(data, "nocifsacl", 9) == 0) { | 1368 | } else if (strnicmp(data, "nocifsacl", 9) == 0) { |
@@ -1303,10 +1371,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1303 | vol->no_psx_acl = 0; | 1371 | vol->no_psx_acl = 0; |
1304 | } else if (strnicmp(data, "noacl", 5) == 0) { | 1372 | } else if (strnicmp(data, "noacl", 5) == 0) { |
1305 | vol->no_psx_acl = 1; | 1373 | vol->no_psx_acl = 1; |
1306 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1307 | } else if (strnicmp(data, "locallease", 6) == 0) { | 1374 | } else if (strnicmp(data, "locallease", 6) == 0) { |
1308 | vol->local_lease = 1; | 1375 | vol->local_lease = 1; |
1309 | #endif | ||
1310 | } else if (strnicmp(data, "sign", 4) == 0) { | 1376 | } else if (strnicmp(data, "sign", 4) == 0) { |
1311 | vol->secFlg |= CIFSSEC_MUST_SIGN; | 1377 | vol->secFlg |= CIFSSEC_MUST_SIGN; |
1312 | } else if (strnicmp(data, "seal", 4) == 0) { | 1378 | } else if (strnicmp(data, "seal", 4) == 0) { |
@@ -1319,12 +1385,23 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1319 | vol->direct_io = 1; | 1385 | vol->direct_io = 1; |
1320 | } else if (strnicmp(data, "forcedirectio", 13) == 0) { | 1386 | } else if (strnicmp(data, "forcedirectio", 13) == 0) { |
1321 | vol->direct_io = 1; | 1387 | vol->direct_io = 1; |
1388 | } else if (strnicmp(data, "strictcache", 11) == 0) { | ||
1389 | vol->strict_io = 1; | ||
1322 | } else if (strnicmp(data, "noac", 4) == 0) { | 1390 | } else if (strnicmp(data, "noac", 4) == 0) { |
1323 | printk(KERN_WARNING "CIFS: Mount option noac not " | 1391 | printk(KERN_WARNING "CIFS: Mount option noac not " |
1324 | "supported. Instead set " | 1392 | "supported. Instead set " |
1325 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 1393 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); |
1326 | } else if (strnicmp(data, "fsc", 3) == 0) { | 1394 | } else if (strnicmp(data, "fsc", 3) == 0) { |
1395 | #ifndef CONFIG_CIFS_FSCACHE | ||
1396 | cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE " | ||
1397 | "kernel config option set"); | ||
1398 | goto cifs_parse_mount_err; | ||
1399 | #endif | ||
1327 | vol->fsc = true; | 1400 | vol->fsc = true; |
1401 | } else if (strnicmp(data, "mfsymlinks", 10) == 0) { | ||
1402 | vol->mfsymlinks = true; | ||
1403 | } else if (strnicmp(data, "multiuser", 8) == 0) { | ||
1404 | vol->multiuser = true; | ||
1328 | } else | 1405 | } else |
1329 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1406 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", |
1330 | data); | 1407 | data); |
@@ -1333,12 +1410,12 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1333 | if (devname == NULL) { | 1410 | if (devname == NULL) { |
1334 | printk(KERN_WARNING "CIFS: Missing UNC name for mount " | 1411 | printk(KERN_WARNING "CIFS: Missing UNC name for mount " |
1335 | "target\n"); | 1412 | "target\n"); |
1336 | return 1; | 1413 | goto cifs_parse_mount_err; |
1337 | } | 1414 | } |
1338 | if ((temp_len = strnlen(devname, 300)) < 300) { | 1415 | if ((temp_len = strnlen(devname, 300)) < 300) { |
1339 | vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); | 1416 | vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); |
1340 | if (vol->UNC == NULL) | 1417 | if (vol->UNC == NULL) |
1341 | return 1; | 1418 | goto cifs_parse_mount_err; |
1342 | strcpy(vol->UNC, devname); | 1419 | strcpy(vol->UNC, devname); |
1343 | if (strncmp(vol->UNC, "//", 2) == 0) { | 1420 | if (strncmp(vol->UNC, "//", 2) == 0) { |
1344 | vol->UNC[0] = '\\'; | 1421 | vol->UNC[0] = '\\'; |
@@ -1346,16 +1423,23 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1346 | } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { | 1423 | } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { |
1347 | printk(KERN_WARNING "CIFS: UNC Path does not " | 1424 | printk(KERN_WARNING "CIFS: UNC Path does not " |
1348 | "begin with // or \\\\ \n"); | 1425 | "begin with // or \\\\ \n"); |
1349 | return 1; | 1426 | goto cifs_parse_mount_err; |
1350 | } | 1427 | } |
1351 | value = strpbrk(vol->UNC+2, "/\\"); | 1428 | value = strpbrk(vol->UNC+2, "/\\"); |
1352 | if (value) | 1429 | if (value) |
1353 | *value = '\\'; | 1430 | *value = '\\'; |
1354 | } else { | 1431 | } else { |
1355 | printk(KERN_WARNING "CIFS: UNC name too long\n"); | 1432 | printk(KERN_WARNING "CIFS: UNC name too long\n"); |
1356 | return 1; | 1433 | goto cifs_parse_mount_err; |
1357 | } | 1434 | } |
1358 | } | 1435 | } |
1436 | |||
1437 | if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { | ||
1438 | cERROR(1, "Multiuser mounts currently require krb5 " | ||
1439 | "authentication!"); | ||
1440 | goto cifs_parse_mount_err; | ||
1441 | } | ||
1442 | |||
1359 | if (vol->UNCip == NULL) | 1443 | if (vol->UNCip == NULL) |
1360 | vol->UNCip = &vol->UNC[2]; | 1444 | vol->UNCip = &vol->UNC[2]; |
1361 | 1445 | ||
@@ -1371,36 +1455,108 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1371 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " | 1455 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " |
1372 | "specified with no gid= option.\n"); | 1456 | "specified with no gid= option.\n"); |
1373 | 1457 | ||
1458 | kfree(mountdata_copy); | ||
1374 | return 0; | 1459 | return 0; |
1460 | |||
1461 | cifs_parse_mount_err: | ||
1462 | kfree(mountdata_copy); | ||
1463 | return 1; | ||
1375 | } | 1464 | } |
1376 | 1465 | ||
1466 | /** Returns true if srcaddr isn't specified and rhs isn't | ||
1467 | * specified, or if srcaddr is specified and | ||
1468 | * matches the IP address of the rhs argument. | ||
1469 | */ | ||
1377 | static bool | 1470 | static bool |
1378 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr) | 1471 | srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) |
1379 | { | 1472 | { |
1380 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | 1473 | switch (srcaddr->sa_family) { |
1381 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | 1474 | case AF_UNSPEC: |
1475 | return (rhs->sa_family == AF_UNSPEC); | ||
1476 | case AF_INET: { | ||
1477 | struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; | ||
1478 | struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; | ||
1479 | return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr); | ||
1480 | } | ||
1481 | case AF_INET6: { | ||
1482 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; | ||
1483 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs; | ||
1484 | return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); | ||
1485 | } | ||
1486 | default: | ||
1487 | WARN_ON(1); | ||
1488 | return false; /* don't expect to be here */ | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | /* | ||
1493 | * If no port is specified in addr structure, we try to match with 445 port | ||
1494 | * and if it fails - with 139 ports. It should be called only if address | ||
1495 | * families of server and addr are equal. | ||
1496 | */ | ||
1497 | static bool | ||
1498 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) | ||
1499 | { | ||
1500 | __be16 port, *sport; | ||
1382 | 1501 | ||
1383 | switch (addr->sa_family) { | 1502 | switch (addr->sa_family) { |
1384 | case AF_INET: | 1503 | case AF_INET: |
1385 | if (addr4->sin_addr.s_addr != | 1504 | sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port; |
1386 | server->addr.sockAddr.sin_addr.s_addr) | 1505 | port = ((struct sockaddr_in *) addr)->sin_port; |
1387 | return false; | ||
1388 | if (addr4->sin_port && | ||
1389 | addr4->sin_port != server->addr.sockAddr.sin_port) | ||
1390 | return false; | ||
1391 | break; | 1506 | break; |
1392 | case AF_INET6: | 1507 | case AF_INET6: |
1393 | if (!ipv6_addr_equal(&addr6->sin6_addr, | 1508 | sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port; |
1394 | &server->addr.sockAddr6.sin6_addr)) | 1509 | port = ((struct sockaddr_in6 *) addr)->sin6_port; |
1510 | break; | ||
1511 | default: | ||
1512 | WARN_ON(1); | ||
1513 | return false; | ||
1514 | } | ||
1515 | |||
1516 | if (!port) { | ||
1517 | port = htons(CIFS_PORT); | ||
1518 | if (port == *sport) | ||
1519 | return true; | ||
1520 | |||
1521 | port = htons(RFC1001_PORT); | ||
1522 | } | ||
1523 | |||
1524 | return port == *sport; | ||
1525 | } | ||
1526 | |||
1527 | static bool | ||
1528 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, | ||
1529 | struct sockaddr *srcaddr) | ||
1530 | { | ||
1531 | switch (addr->sa_family) { | ||
1532 | case AF_INET: { | ||
1533 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
1534 | struct sockaddr_in *srv_addr4 = | ||
1535 | (struct sockaddr_in *)&server->dstaddr; | ||
1536 | |||
1537 | if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr) | ||
1395 | return false; | 1538 | return false; |
1396 | if (addr6->sin6_scope_id != | 1539 | break; |
1397 | server->addr.sockAddr6.sin6_scope_id) | 1540 | } |
1541 | case AF_INET6: { | ||
1542 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1543 | struct sockaddr_in6 *srv_addr6 = | ||
1544 | (struct sockaddr_in6 *)&server->dstaddr; | ||
1545 | |||
1546 | if (!ipv6_addr_equal(&addr6->sin6_addr, | ||
1547 | &srv_addr6->sin6_addr)) | ||
1398 | return false; | 1548 | return false; |
1399 | if (addr6->sin6_port && | 1549 | if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id) |
1400 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | ||
1401 | return false; | 1550 | return false; |
1402 | break; | 1551 | break; |
1403 | } | 1552 | } |
1553 | default: | ||
1554 | WARN_ON(1); | ||
1555 | return false; /* don't expect to be here */ | ||
1556 | } | ||
1557 | |||
1558 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) | ||
1559 | return false; | ||
1404 | 1560 | ||
1405 | return true; | 1561 | return true; |
1406 | } | 1562 | } |
@@ -1441,46 +1597,53 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
1441 | return false; | 1597 | return false; |
1442 | } | 1598 | } |
1443 | 1599 | ||
1444 | /* now check if signing mode is acceptible */ | 1600 | /* now check if signing mode is acceptable */ |
1445 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0 && | 1601 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0 && |
1446 | (server->secMode & SECMODE_SIGN_REQUIRED)) | 1602 | (server->sec_mode & SECMODE_SIGN_REQUIRED)) |
1447 | return false; | 1603 | return false; |
1448 | else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) && | 1604 | else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) && |
1449 | (server->secMode & | 1605 | (server->sec_mode & |
1450 | (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0) | 1606 | (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0) |
1451 | return false; | 1607 | return false; |
1452 | 1608 | ||
1453 | return true; | 1609 | return true; |
1454 | } | 1610 | } |
1455 | 1611 | ||
1612 | static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, | ||
1613 | struct smb_vol *vol) | ||
1614 | { | ||
1615 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) | ||
1616 | return 0; | ||
1617 | |||
1618 | if (!match_address(server, addr, | ||
1619 | (struct sockaddr *)&vol->srcaddr)) | ||
1620 | return 0; | ||
1621 | |||
1622 | if (!match_port(server, addr)) | ||
1623 | return 0; | ||
1624 | |||
1625 | if (!match_security(server, vol)) | ||
1626 | return 0; | ||
1627 | |||
1628 | return 1; | ||
1629 | } | ||
1630 | |||
1456 | static struct TCP_Server_Info * | 1631 | static struct TCP_Server_Info * |
1457 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | 1632 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) |
1458 | { | 1633 | { |
1459 | struct TCP_Server_Info *server; | 1634 | struct TCP_Server_Info *server; |
1460 | 1635 | ||
1461 | write_lock(&cifs_tcp_ses_lock); | 1636 | spin_lock(&cifs_tcp_ses_lock); |
1462 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { | 1637 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
1463 | /* | 1638 | if (!match_server(server, addr, vol)) |
1464 | * the demux thread can exit on its own while still in CifsNew | ||
1465 | * so don't accept any sockets in that state. Since the | ||
1466 | * tcpStatus never changes back to CifsNew it's safe to check | ||
1467 | * for this without a lock. | ||
1468 | */ | ||
1469 | if (server->tcpStatus == CifsNew) | ||
1470 | continue; | ||
1471 | |||
1472 | if (!match_address(server, addr)) | ||
1473 | continue; | ||
1474 | |||
1475 | if (!match_security(server, vol)) | ||
1476 | continue; | 1639 | continue; |
1477 | 1640 | ||
1478 | ++server->srv_count; | 1641 | ++server->srv_count; |
1479 | write_unlock(&cifs_tcp_ses_lock); | 1642 | spin_unlock(&cifs_tcp_ses_lock); |
1480 | cFYI(1, "Existing tcp session with server found"); | 1643 | cFYI(1, "Existing tcp session with server found"); |
1481 | return server; | 1644 | return server; |
1482 | } | 1645 | } |
1483 | write_unlock(&cifs_tcp_ses_lock); | 1646 | spin_unlock(&cifs_tcp_ses_lock); |
1484 | return NULL; | 1647 | return NULL; |
1485 | } | 1648 | } |
1486 | 1649 | ||
@@ -1489,21 +1652,30 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
1489 | { | 1652 | { |
1490 | struct task_struct *task; | 1653 | struct task_struct *task; |
1491 | 1654 | ||
1492 | write_lock(&cifs_tcp_ses_lock); | 1655 | spin_lock(&cifs_tcp_ses_lock); |
1493 | if (--server->srv_count > 0) { | 1656 | if (--server->srv_count > 0) { |
1494 | write_unlock(&cifs_tcp_ses_lock); | 1657 | spin_unlock(&cifs_tcp_ses_lock); |
1495 | return; | 1658 | return; |
1496 | } | 1659 | } |
1497 | 1660 | ||
1661 | put_net(cifs_net_ns(server)); | ||
1662 | |||
1498 | list_del_init(&server->tcp_ses_list); | 1663 | list_del_init(&server->tcp_ses_list); |
1499 | write_unlock(&cifs_tcp_ses_lock); | 1664 | spin_unlock(&cifs_tcp_ses_lock); |
1665 | |||
1666 | cancel_delayed_work_sync(&server->echo); | ||
1500 | 1667 | ||
1501 | spin_lock(&GlobalMid_Lock); | 1668 | spin_lock(&GlobalMid_Lock); |
1502 | server->tcpStatus = CifsExiting; | 1669 | server->tcpStatus = CifsExiting; |
1503 | spin_unlock(&GlobalMid_Lock); | 1670 | spin_unlock(&GlobalMid_Lock); |
1504 | 1671 | ||
1672 | cifs_crypto_shash_release(server); | ||
1505 | cifs_fscache_release_client_cookie(server); | 1673 | cifs_fscache_release_client_cookie(server); |
1506 | 1674 | ||
1675 | kfree(server->session_key.response); | ||
1676 | server->session_key.response = NULL; | ||
1677 | server->session_key.len = 0; | ||
1678 | |||
1507 | task = xchg(&server->tsk, NULL); | 1679 | task = xchg(&server->tsk, NULL); |
1508 | if (task) | 1680 | if (task) |
1509 | force_sig(SIGKILL, task); | 1681 | force_sig(SIGKILL, task); |
@@ -1556,10 +1728,17 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1556 | goto out_err; | 1728 | goto out_err; |
1557 | } | 1729 | } |
1558 | 1730 | ||
1731 | rc = cifs_crypto_shash_allocate(tcp_ses); | ||
1732 | if (rc) { | ||
1733 | cERROR(1, "could not setup hash structures rc %d", rc); | ||
1734 | goto out_err; | ||
1735 | } | ||
1736 | |||
1737 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); | ||
1559 | tcp_ses->hostname = extract_hostname(volume_info->UNC); | 1738 | tcp_ses->hostname = extract_hostname(volume_info->UNC); |
1560 | if (IS_ERR(tcp_ses->hostname)) { | 1739 | if (IS_ERR(tcp_ses->hostname)) { |
1561 | rc = PTR_ERR(tcp_ses->hostname); | 1740 | rc = PTR_ERR(tcp_ses->hostname); |
1562 | goto out_err; | 1741 | goto out_err_crypto_release; |
1563 | } | 1742 | } |
1564 | 1743 | ||
1565 | tcp_ses->noblocksnd = volume_info->noblocksnd; | 1744 | tcp_ses->noblocksnd = volume_info->noblocksnd; |
@@ -1574,9 +1753,12 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1574 | volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 1753 | volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
1575 | memcpy(tcp_ses->server_RFC1001_name, | 1754 | memcpy(tcp_ses->server_RFC1001_name, |
1576 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 1755 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
1756 | tcp_ses->session_estab = false; | ||
1577 | tcp_ses->sequence_number = 0; | 1757 | tcp_ses->sequence_number = 0; |
1758 | tcp_ses->lstrp = jiffies; | ||
1578 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 1759 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
1579 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | 1760 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
1761 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); | ||
1580 | 1762 | ||
1581 | /* | 1763 | /* |
1582 | * at this point we are the only ones with the pointer | 1764 | * at this point we are the only ones with the pointer |
@@ -1584,23 +1766,24 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1584 | * no need to spinlock this init of tcpStatus or srv_count | 1766 | * no need to spinlock this init of tcpStatus or srv_count |
1585 | */ | 1767 | */ |
1586 | tcp_ses->tcpStatus = CifsNew; | 1768 | tcp_ses->tcpStatus = CifsNew; |
1769 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, | ||
1770 | sizeof(tcp_ses->srcaddr)); | ||
1587 | ++tcp_ses->srv_count; | 1771 | ++tcp_ses->srv_count; |
1588 | 1772 | ||
1589 | if (addr.ss_family == AF_INET6) { | 1773 | if (addr.ss_family == AF_INET6) { |
1590 | cFYI(1, "attempting ipv6 connect"); | 1774 | cFYI(1, "attempting ipv6 connect"); |
1591 | /* BB should we allow ipv6 on port 139? */ | 1775 | /* BB should we allow ipv6 on port 139? */ |
1592 | /* other OS never observed in Wild doing 139 with v6 */ | 1776 | /* other OS never observed in Wild doing 139 with v6 */ |
1593 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1777 | memcpy(&tcp_ses->dstaddr, sin_server6, |
1594 | sizeof(struct sockaddr_in6)); | 1778 | sizeof(struct sockaddr_in6)); |
1595 | rc = ipv6_connect(tcp_ses); | 1779 | } else |
1596 | } else { | 1780 | memcpy(&tcp_ses->dstaddr, sin_server, |
1597 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1781 | sizeof(struct sockaddr_in)); |
1598 | sizeof(struct sockaddr_in)); | 1782 | |
1599 | rc = ipv4_connect(tcp_ses); | 1783 | rc = ip_connect(tcp_ses); |
1600 | } | ||
1601 | if (rc < 0) { | 1784 | if (rc < 0) { |
1602 | cERROR(1, "Error connecting to socket. Aborting operation"); | 1785 | cERROR(1, "Error connecting to socket. Aborting operation"); |
1603 | goto out_err; | 1786 | goto out_err_crypto_release; |
1604 | } | 1787 | } |
1605 | 1788 | ||
1606 | /* | 1789 | /* |
@@ -1614,18 +1797,27 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1614 | rc = PTR_ERR(tcp_ses->tsk); | 1797 | rc = PTR_ERR(tcp_ses->tsk); |
1615 | cERROR(1, "error %d create cifsd thread", rc); | 1798 | cERROR(1, "error %d create cifsd thread", rc); |
1616 | module_put(THIS_MODULE); | 1799 | module_put(THIS_MODULE); |
1617 | goto out_err; | 1800 | goto out_err_crypto_release; |
1618 | } | 1801 | } |
1802 | tcp_ses->tcpStatus = CifsNeedNegotiate; | ||
1619 | 1803 | ||
1620 | /* thread spawned, put it on the list */ | 1804 | /* thread spawned, put it on the list */ |
1621 | write_lock(&cifs_tcp_ses_lock); | 1805 | spin_lock(&cifs_tcp_ses_lock); |
1622 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 1806 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
1623 | write_unlock(&cifs_tcp_ses_lock); | 1807 | spin_unlock(&cifs_tcp_ses_lock); |
1624 | 1808 | ||
1625 | cifs_fscache_get_client_cookie(tcp_ses); | 1809 | cifs_fscache_get_client_cookie(tcp_ses); |
1626 | 1810 | ||
1811 | /* queue echo request delayed work */ | ||
1812 | queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL); | ||
1813 | |||
1627 | return tcp_ses; | 1814 | return tcp_ses; |
1628 | 1815 | ||
1816 | out_err_crypto_release: | ||
1817 | cifs_crypto_shash_release(tcp_ses); | ||
1818 | |||
1819 | put_net(cifs_net_ns(tcp_ses)); | ||
1820 | |||
1629 | out_err: | 1821 | out_err: |
1630 | if (tcp_ses) { | 1822 | if (tcp_ses) { |
1631 | if (!IS_ERR(tcp_ses->hostname)) | 1823 | if (!IS_ERR(tcp_ses->hostname)) |
@@ -1637,53 +1829,62 @@ out_err: | |||
1637 | return ERR_PTR(rc); | 1829 | return ERR_PTR(rc); |
1638 | } | 1830 | } |
1639 | 1831 | ||
1640 | static struct cifsSesInfo * | 1832 | static int match_session(struct cifs_ses *ses, struct smb_vol *vol) |
1833 | { | ||
1834 | switch (ses->server->secType) { | ||
1835 | case Kerberos: | ||
1836 | if (vol->cred_uid != ses->cred_uid) | ||
1837 | return 0; | ||
1838 | break; | ||
1839 | default: | ||
1840 | /* anything else takes username/password */ | ||
1841 | if (ses->user_name == NULL) | ||
1842 | return 0; | ||
1843 | if (strncmp(ses->user_name, vol->username, | ||
1844 | MAX_USERNAME_SIZE)) | ||
1845 | return 0; | ||
1846 | if (strlen(vol->username) != 0 && | ||
1847 | ses->password != NULL && | ||
1848 | strncmp(ses->password, | ||
1849 | vol->password ? vol->password : "", | ||
1850 | MAX_PASSWORD_SIZE)) | ||
1851 | return 0; | ||
1852 | } | ||
1853 | return 1; | ||
1854 | } | ||
1855 | |||
1856 | static struct cifs_ses * | ||
1641 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) | 1857 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) |
1642 | { | 1858 | { |
1643 | struct cifsSesInfo *ses; | 1859 | struct cifs_ses *ses; |
1644 | 1860 | ||
1645 | write_lock(&cifs_tcp_ses_lock); | 1861 | spin_lock(&cifs_tcp_ses_lock); |
1646 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { | 1862 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
1647 | switch (server->secType) { | 1863 | if (!match_session(ses, vol)) |
1648 | case Kerberos: | 1864 | continue; |
1649 | if (vol->cred_uid != ses->cred_uid) | ||
1650 | continue; | ||
1651 | break; | ||
1652 | default: | ||
1653 | /* anything else takes username/password */ | ||
1654 | if (strncmp(ses->userName, vol->username, | ||
1655 | MAX_USERNAME_SIZE)) | ||
1656 | continue; | ||
1657 | if (strlen(vol->username) != 0 && | ||
1658 | ses->password != NULL && | ||
1659 | strncmp(ses->password, | ||
1660 | vol->password ? vol->password : "", | ||
1661 | MAX_PASSWORD_SIZE)) | ||
1662 | continue; | ||
1663 | } | ||
1664 | ++ses->ses_count; | 1865 | ++ses->ses_count; |
1665 | write_unlock(&cifs_tcp_ses_lock); | 1866 | spin_unlock(&cifs_tcp_ses_lock); |
1666 | return ses; | 1867 | return ses; |
1667 | } | 1868 | } |
1668 | write_unlock(&cifs_tcp_ses_lock); | 1869 | spin_unlock(&cifs_tcp_ses_lock); |
1669 | return NULL; | 1870 | return NULL; |
1670 | } | 1871 | } |
1671 | 1872 | ||
1672 | static void | 1873 | static void |
1673 | cifs_put_smb_ses(struct cifsSesInfo *ses) | 1874 | cifs_put_smb_ses(struct cifs_ses *ses) |
1674 | { | 1875 | { |
1675 | int xid; | 1876 | int xid; |
1676 | struct TCP_Server_Info *server = ses->server; | 1877 | struct TCP_Server_Info *server = ses->server; |
1677 | 1878 | ||
1678 | cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count); | 1879 | cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count); |
1679 | write_lock(&cifs_tcp_ses_lock); | 1880 | spin_lock(&cifs_tcp_ses_lock); |
1680 | if (--ses->ses_count > 0) { | 1881 | if (--ses->ses_count > 0) { |
1681 | write_unlock(&cifs_tcp_ses_lock); | 1882 | spin_unlock(&cifs_tcp_ses_lock); |
1682 | return; | 1883 | return; |
1683 | } | 1884 | } |
1684 | 1885 | ||
1685 | list_del_init(&ses->smb_ses_list); | 1886 | list_del_init(&ses->smb_ses_list); |
1686 | write_unlock(&cifs_tcp_ses_lock); | 1887 | spin_unlock(&cifs_tcp_ses_lock); |
1687 | 1888 | ||
1688 | if (ses->status == CifsGood) { | 1889 | if (ses->status == CifsGood) { |
1689 | xid = GetXid(); | 1890 | xid = GetXid(); |
@@ -1694,11 +1895,15 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) | |||
1694 | cifs_put_tcp_session(server); | 1895 | cifs_put_tcp_session(server); |
1695 | } | 1896 | } |
1696 | 1897 | ||
1697 | static struct cifsSesInfo * | 1898 | static bool warned_on_ntlm; /* globals init to false automatically */ |
1899 | |||
1900 | static struct cifs_ses * | ||
1698 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | 1901 | cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) |
1699 | { | 1902 | { |
1700 | int rc = -ENOMEM, xid; | 1903 | int rc = -ENOMEM, xid; |
1701 | struct cifsSesInfo *ses; | 1904 | struct cifs_ses *ses; |
1905 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | ||
1906 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | ||
1702 | 1907 | ||
1703 | xid = GetXid(); | 1908 | xid = GetXid(); |
1704 | 1909 | ||
@@ -1742,16 +1947,16 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1742 | 1947 | ||
1743 | /* new SMB session uses our server ref */ | 1948 | /* new SMB session uses our server ref */ |
1744 | ses->server = server; | 1949 | ses->server = server; |
1745 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 1950 | if (server->dstaddr.ss_family == AF_INET6) |
1746 | sprintf(ses->serverName, "%pI6", | 1951 | sprintf(ses->serverName, "%pI6", &addr6->sin6_addr); |
1747 | &server->addr.sockAddr6.sin6_addr); | ||
1748 | else | 1952 | else |
1749 | sprintf(ses->serverName, "%pI4", | 1953 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); |
1750 | &server->addr.sockAddr.sin_addr.s_addr); | ||
1751 | 1954 | ||
1752 | if (volume_info->username) | 1955 | if (volume_info->username) { |
1753 | strncpy(ses->userName, volume_info->username, | 1956 | ses->user_name = kstrdup(volume_info->username, GFP_KERNEL); |
1754 | MAX_USERNAME_SIZE); | 1957 | if (!ses->user_name) |
1958 | goto get_ses_fail; | ||
1959 | } | ||
1755 | 1960 | ||
1756 | /* volume_info->password freed at unmount */ | 1961 | /* volume_info->password freed at unmount */ |
1757 | if (volume_info->password) { | 1962 | if (volume_info->password) { |
@@ -1760,13 +1965,21 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1760 | goto get_ses_fail; | 1965 | goto get_ses_fail; |
1761 | } | 1966 | } |
1762 | if (volume_info->domainname) { | 1967 | if (volume_info->domainname) { |
1763 | int len = strlen(volume_info->domainname); | 1968 | ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL); |
1764 | ses->domainName = kmalloc(len + 1, GFP_KERNEL); | 1969 | if (!ses->domainName) |
1765 | if (ses->domainName) | 1970 | goto get_ses_fail; |
1766 | strcpy(ses->domainName, volume_info->domainname); | ||
1767 | } | 1971 | } |
1768 | ses->cred_uid = volume_info->cred_uid; | 1972 | ses->cred_uid = volume_info->cred_uid; |
1769 | ses->linux_uid = volume_info->linux_uid; | 1973 | ses->linux_uid = volume_info->linux_uid; |
1974 | |||
1975 | /* ntlmv2 is much stronger than ntlm security, and has been broadly | ||
1976 | supported for many years, time to update default security mechanism */ | ||
1977 | if ((volume_info->secFlg == 0) && warned_on_ntlm == false) { | ||
1978 | warned_on_ntlm = true; | ||
1979 | cERROR(1, "default security mechanism requested. The default " | ||
1980 | "security mechanism will be upgraded from ntlm to " | ||
1981 | "ntlmv2 in kernel release 3.1"); | ||
1982 | } | ||
1770 | ses->overrideSecFlg = volume_info->secFlg; | 1983 | ses->overrideSecFlg = volume_info->secFlg; |
1771 | 1984 | ||
1772 | mutex_lock(&ses->session_mutex); | 1985 | mutex_lock(&ses->session_mutex); |
@@ -1778,9 +1991,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1778 | goto get_ses_fail; | 1991 | goto get_ses_fail; |
1779 | 1992 | ||
1780 | /* success, put it on the list */ | 1993 | /* success, put it on the list */ |
1781 | write_lock(&cifs_tcp_ses_lock); | 1994 | spin_lock(&cifs_tcp_ses_lock); |
1782 | list_add(&ses->smb_ses_list, &server->smb_ses_list); | 1995 | list_add(&ses->smb_ses_list, &server->smb_ses_list); |
1783 | write_unlock(&cifs_tcp_ses_lock); | 1996 | spin_unlock(&cifs_tcp_ses_lock); |
1784 | 1997 | ||
1785 | FreeXid(xid); | 1998 | FreeXid(xid); |
1786 | return ses; | 1999 | return ses; |
@@ -1791,43 +2004,49 @@ get_ses_fail: | |||
1791 | return ERR_PTR(rc); | 2004 | return ERR_PTR(rc); |
1792 | } | 2005 | } |
1793 | 2006 | ||
1794 | static struct cifsTconInfo * | 2007 | static int match_tcon(struct cifs_tcon *tcon, const char *unc) |
1795 | cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) | 2008 | { |
2009 | if (tcon->tidStatus == CifsExiting) | ||
2010 | return 0; | ||
2011 | if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) | ||
2012 | return 0; | ||
2013 | return 1; | ||
2014 | } | ||
2015 | |||
2016 | static struct cifs_tcon * | ||
2017 | cifs_find_tcon(struct cifs_ses *ses, const char *unc) | ||
1796 | { | 2018 | { |
1797 | struct list_head *tmp; | 2019 | struct list_head *tmp; |
1798 | struct cifsTconInfo *tcon; | 2020 | struct cifs_tcon *tcon; |
1799 | 2021 | ||
1800 | write_lock(&cifs_tcp_ses_lock); | 2022 | spin_lock(&cifs_tcp_ses_lock); |
1801 | list_for_each(tmp, &ses->tcon_list) { | 2023 | list_for_each(tmp, &ses->tcon_list) { |
1802 | tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); | 2024 | tcon = list_entry(tmp, struct cifs_tcon, tcon_list); |
1803 | if (tcon->tidStatus == CifsExiting) | 2025 | if (!match_tcon(tcon, unc)) |
1804 | continue; | ||
1805 | if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) | ||
1806 | continue; | 2026 | continue; |
1807 | |||
1808 | ++tcon->tc_count; | 2027 | ++tcon->tc_count; |
1809 | write_unlock(&cifs_tcp_ses_lock); | 2028 | spin_unlock(&cifs_tcp_ses_lock); |
1810 | return tcon; | 2029 | return tcon; |
1811 | } | 2030 | } |
1812 | write_unlock(&cifs_tcp_ses_lock); | 2031 | spin_unlock(&cifs_tcp_ses_lock); |
1813 | return NULL; | 2032 | return NULL; |
1814 | } | 2033 | } |
1815 | 2034 | ||
1816 | static void | 2035 | static void |
1817 | cifs_put_tcon(struct cifsTconInfo *tcon) | 2036 | cifs_put_tcon(struct cifs_tcon *tcon) |
1818 | { | 2037 | { |
1819 | int xid; | 2038 | int xid; |
1820 | struct cifsSesInfo *ses = tcon->ses; | 2039 | struct cifs_ses *ses = tcon->ses; |
1821 | 2040 | ||
1822 | cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count); | 2041 | cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count); |
1823 | write_lock(&cifs_tcp_ses_lock); | 2042 | spin_lock(&cifs_tcp_ses_lock); |
1824 | if (--tcon->tc_count > 0) { | 2043 | if (--tcon->tc_count > 0) { |
1825 | write_unlock(&cifs_tcp_ses_lock); | 2044 | spin_unlock(&cifs_tcp_ses_lock); |
1826 | return; | 2045 | return; |
1827 | } | 2046 | } |
1828 | 2047 | ||
1829 | list_del_init(&tcon->tcon_list); | 2048 | list_del_init(&tcon->tcon_list); |
1830 | write_unlock(&cifs_tcp_ses_lock); | 2049 | spin_unlock(&cifs_tcp_ses_lock); |
1831 | 2050 | ||
1832 | xid = GetXid(); | 2051 | xid = GetXid(); |
1833 | CIFSSMBTDis(xid, tcon); | 2052 | CIFSSMBTDis(xid, tcon); |
@@ -1838,11 +2057,11 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1838 | cifs_put_smb_ses(ses); | 2057 | cifs_put_smb_ses(ses); |
1839 | } | 2058 | } |
1840 | 2059 | ||
1841 | static struct cifsTconInfo * | 2060 | static struct cifs_tcon * |
1842 | cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | 2061 | cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) |
1843 | { | 2062 | { |
1844 | int rc, xid; | 2063 | int rc, xid; |
1845 | struct cifsTconInfo *tcon; | 2064 | struct cifs_tcon *tcon; |
1846 | 2065 | ||
1847 | tcon = cifs_find_tcon(ses, volume_info->UNC); | 2066 | tcon = cifs_find_tcon(ses, volume_info->UNC); |
1848 | if (tcon) { | 2067 | if (tcon) { |
@@ -1900,9 +2119,9 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | |||
1900 | tcon->nocase = volume_info->nocase; | 2119 | tcon->nocase = volume_info->nocase; |
1901 | tcon->local_lease = volume_info->local_lease; | 2120 | tcon->local_lease = volume_info->local_lease; |
1902 | 2121 | ||
1903 | write_lock(&cifs_tcp_ses_lock); | 2122 | spin_lock(&cifs_tcp_ses_lock); |
1904 | list_add(&tcon->tcon_list, &ses->tcon_list); | 2123 | list_add(&tcon->tcon_list, &ses->tcon_list); |
1905 | write_unlock(&cifs_tcp_ses_lock); | 2124 | spin_unlock(&cifs_tcp_ses_lock); |
1906 | 2125 | ||
1907 | cifs_fscache_get_super_cookie(tcon); | 2126 | cifs_fscache_get_super_cookie(tcon); |
1908 | 2127 | ||
@@ -1913,9 +2132,123 @@ out_fail: | |||
1913 | return ERR_PTR(rc); | 2132 | return ERR_PTR(rc); |
1914 | } | 2133 | } |
1915 | 2134 | ||
2135 | void | ||
2136 | cifs_put_tlink(struct tcon_link *tlink) | ||
2137 | { | ||
2138 | if (!tlink || IS_ERR(tlink)) | ||
2139 | return; | ||
2140 | |||
2141 | if (!atomic_dec_and_test(&tlink->tl_count) || | ||
2142 | test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) { | ||
2143 | tlink->tl_time = jiffies; | ||
2144 | return; | ||
2145 | } | ||
2146 | |||
2147 | if (!IS_ERR(tlink_tcon(tlink))) | ||
2148 | cifs_put_tcon(tlink_tcon(tlink)); | ||
2149 | kfree(tlink); | ||
2150 | return; | ||
2151 | } | ||
2152 | |||
2153 | static inline struct tcon_link * | ||
2154 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) | ||
2155 | { | ||
2156 | return cifs_sb->master_tlink; | ||
2157 | } | ||
2158 | |||
2159 | static int | ||
2160 | compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) | ||
2161 | { | ||
2162 | struct cifs_sb_info *old = CIFS_SB(sb); | ||
2163 | struct cifs_sb_info *new = mnt_data->cifs_sb; | ||
2164 | |||
2165 | if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK)) | ||
2166 | return 0; | ||
2167 | |||
2168 | if ((old->mnt_cifs_flags & CIFS_MOUNT_MASK) != | ||
2169 | (new->mnt_cifs_flags & CIFS_MOUNT_MASK)) | ||
2170 | return 0; | ||
2171 | |||
2172 | if (old->rsize != new->rsize) | ||
2173 | return 0; | ||
2174 | |||
2175 | /* | ||
2176 | * We want to share sb only if we don't specify wsize or specified wsize | ||
2177 | * is greater or equal than existing one. | ||
2178 | */ | ||
2179 | if (new->wsize && new->wsize < old->wsize) | ||
2180 | return 0; | ||
2181 | |||
2182 | if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid) | ||
2183 | return 0; | ||
2184 | |||
2185 | if (old->mnt_file_mode != new->mnt_file_mode || | ||
2186 | old->mnt_dir_mode != new->mnt_dir_mode) | ||
2187 | return 0; | ||
2188 | |||
2189 | if (strcmp(old->local_nls->charset, new->local_nls->charset)) | ||
2190 | return 0; | ||
2191 | |||
2192 | if (old->actimeo != new->actimeo) | ||
2193 | return 0; | ||
2194 | |||
2195 | return 1; | ||
2196 | } | ||
2197 | |||
2198 | int | ||
2199 | cifs_match_super(struct super_block *sb, void *data) | ||
2200 | { | ||
2201 | struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data; | ||
2202 | struct smb_vol *volume_info; | ||
2203 | struct cifs_sb_info *cifs_sb; | ||
2204 | struct TCP_Server_Info *tcp_srv; | ||
2205 | struct cifs_ses *ses; | ||
2206 | struct cifs_tcon *tcon; | ||
2207 | struct tcon_link *tlink; | ||
2208 | struct sockaddr_storage addr; | ||
2209 | int rc = 0; | ||
2210 | |||
2211 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | ||
2212 | |||
2213 | spin_lock(&cifs_tcp_ses_lock); | ||
2214 | cifs_sb = CIFS_SB(sb); | ||
2215 | tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | ||
2216 | if (IS_ERR(tlink)) { | ||
2217 | spin_unlock(&cifs_tcp_ses_lock); | ||
2218 | return rc; | ||
2219 | } | ||
2220 | tcon = tlink_tcon(tlink); | ||
2221 | ses = tcon->ses; | ||
2222 | tcp_srv = ses->server; | ||
2223 | |||
2224 | volume_info = mnt_data->vol; | ||
2225 | |||
2226 | if (!volume_info->UNCip || !volume_info->UNC) | ||
2227 | goto out; | ||
2228 | |||
2229 | rc = cifs_fill_sockaddr((struct sockaddr *)&addr, | ||
2230 | volume_info->UNCip, | ||
2231 | strlen(volume_info->UNCip), | ||
2232 | volume_info->port); | ||
2233 | if (!rc) | ||
2234 | goto out; | ||
2235 | |||
2236 | if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) || | ||
2237 | !match_session(ses, volume_info) || | ||
2238 | !match_tcon(tcon, volume_info->UNC)) { | ||
2239 | rc = 0; | ||
2240 | goto out; | ||
2241 | } | ||
2242 | |||
2243 | rc = compare_mount_options(sb, mnt_data); | ||
2244 | out: | ||
2245 | spin_unlock(&cifs_tcp_ses_lock); | ||
2246 | cifs_put_tlink(tlink); | ||
2247 | return rc; | ||
2248 | } | ||
1916 | 2249 | ||
1917 | int | 2250 | int |
1918 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 2251 | get_dfs_path(int xid, struct cifs_ses *pSesInfo, const char *old_path, |
1919 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, | 2252 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, |
1920 | struct dfs_info3_param **preferrals, int remap) | 2253 | struct dfs_info3_param **preferrals, int remap) |
1921 | { | 2254 | { |
@@ -1997,21 +2330,135 @@ static void rfc1002mangle(char *target, char *source, unsigned int length) | |||
1997 | 2330 | ||
1998 | } | 2331 | } |
1999 | 2332 | ||
2333 | static int | ||
2334 | bind_socket(struct TCP_Server_Info *server) | ||
2335 | { | ||
2336 | int rc = 0; | ||
2337 | if (server->srcaddr.ss_family != AF_UNSPEC) { | ||
2338 | /* Bind to the specified local IP address */ | ||
2339 | struct socket *socket = server->ssocket; | ||
2340 | rc = socket->ops->bind(socket, | ||
2341 | (struct sockaddr *) &server->srcaddr, | ||
2342 | sizeof(server->srcaddr)); | ||
2343 | if (rc < 0) { | ||
2344 | struct sockaddr_in *saddr4; | ||
2345 | struct sockaddr_in6 *saddr6; | ||
2346 | saddr4 = (struct sockaddr_in *)&server->srcaddr; | ||
2347 | saddr6 = (struct sockaddr_in6 *)&server->srcaddr; | ||
2348 | if (saddr6->sin6_family == AF_INET6) | ||
2349 | cERROR(1, "cifs: " | ||
2350 | "Failed to bind to: %pI6c, error: %d\n", | ||
2351 | &saddr6->sin6_addr, rc); | ||
2352 | else | ||
2353 | cERROR(1, "cifs: " | ||
2354 | "Failed to bind to: %pI4, error: %d\n", | ||
2355 | &saddr4->sin_addr.s_addr, rc); | ||
2356 | } | ||
2357 | } | ||
2358 | return rc; | ||
2359 | } | ||
2360 | |||
2361 | static int | ||
2362 | ip_rfc1001_connect(struct TCP_Server_Info *server) | ||
2363 | { | ||
2364 | int rc = 0; | ||
2365 | /* | ||
2366 | * some servers require RFC1001 sessinit before sending | ||
2367 | * negprot - BB check reconnection in case where second | ||
2368 | * sessinit is sent but no second negprot | ||
2369 | */ | ||
2370 | struct rfc1002_session_packet *ses_init_buf; | ||
2371 | struct smb_hdr *smb_buf; | ||
2372 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2373 | GFP_KERNEL); | ||
2374 | if (ses_init_buf) { | ||
2375 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2376 | |||
2377 | if (server->server_RFC1001_name && | ||
2378 | server->server_RFC1001_name[0] != 0) | ||
2379 | rfc1002mangle(ses_init_buf->trailer. | ||
2380 | session_req.called_name, | ||
2381 | server->server_RFC1001_name, | ||
2382 | RFC1001_NAME_LEN_WITH_NULL); | ||
2383 | else | ||
2384 | rfc1002mangle(ses_init_buf->trailer. | ||
2385 | session_req.called_name, | ||
2386 | DEFAULT_CIFS_CALLED_NAME, | ||
2387 | RFC1001_NAME_LEN_WITH_NULL); | ||
2388 | |||
2389 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2390 | |||
2391 | /* | ||
2392 | * calling name ends in null (byte 16) from old smb | ||
2393 | * convention. | ||
2394 | */ | ||
2395 | if (server->workstation_RFC1001_name && | ||
2396 | server->workstation_RFC1001_name[0] != 0) | ||
2397 | rfc1002mangle(ses_init_buf->trailer. | ||
2398 | session_req.calling_name, | ||
2399 | server->workstation_RFC1001_name, | ||
2400 | RFC1001_NAME_LEN_WITH_NULL); | ||
2401 | else | ||
2402 | rfc1002mangle(ses_init_buf->trailer. | ||
2403 | session_req.calling_name, | ||
2404 | "LINUX_CIFS_CLNT", | ||
2405 | RFC1001_NAME_LEN_WITH_NULL); | ||
2406 | |||
2407 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2408 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2409 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2410 | |||
2411 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2412 | smb_buf->smb_buf_length = cpu_to_be32(0x81000044); | ||
2413 | rc = smb_send(server, smb_buf, 0x44); | ||
2414 | kfree(ses_init_buf); | ||
2415 | /* | ||
2416 | * RFC1001 layer in at least one server | ||
2417 | * requires very short break before negprot | ||
2418 | * presumably because not expecting negprot | ||
2419 | * to follow so fast. This is a simple | ||
2420 | * solution that works without | ||
2421 | * complicating the code and causes no | ||
2422 | * significant slowing down on mount | ||
2423 | * for everyone else | ||
2424 | */ | ||
2425 | usleep_range(1000, 2000); | ||
2426 | } | ||
2427 | /* | ||
2428 | * else the negprot may still work without this | ||
2429 | * even though malloc failed | ||
2430 | */ | ||
2431 | |||
2432 | return rc; | ||
2433 | } | ||
2000 | 2434 | ||
2001 | static int | 2435 | static int |
2002 | ipv4_connect(struct TCP_Server_Info *server) | 2436 | generic_ip_connect(struct TCP_Server_Info *server) |
2003 | { | 2437 | { |
2004 | int rc = 0; | 2438 | int rc = 0; |
2005 | int val; | 2439 | __be16 sport; |
2006 | bool connected = false; | 2440 | int slen, sfamily; |
2007 | __be16 orig_port = 0; | ||
2008 | struct socket *socket = server->ssocket; | 2441 | struct socket *socket = server->ssocket; |
2442 | struct sockaddr *saddr; | ||
2443 | |||
2444 | saddr = (struct sockaddr *) &server->dstaddr; | ||
2445 | |||
2446 | if (server->dstaddr.ss_family == AF_INET6) { | ||
2447 | sport = ((struct sockaddr_in6 *) saddr)->sin6_port; | ||
2448 | slen = sizeof(struct sockaddr_in6); | ||
2449 | sfamily = AF_INET6; | ||
2450 | } else { | ||
2451 | sport = ((struct sockaddr_in *) saddr)->sin_port; | ||
2452 | slen = sizeof(struct sockaddr_in); | ||
2453 | sfamily = AF_INET; | ||
2454 | } | ||
2009 | 2455 | ||
2010 | if (socket == NULL) { | 2456 | if (socket == NULL) { |
2011 | rc = sock_create_kern(PF_INET, SOCK_STREAM, | 2457 | rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM, |
2012 | IPPROTO_TCP, &socket); | 2458 | IPPROTO_TCP, &socket, 1); |
2013 | if (rc < 0) { | 2459 | if (rc < 0) { |
2014 | cERROR(1, "Error %d creating socket", rc); | 2460 | cERROR(1, "Error %d creating socket", rc); |
2461 | server->ssocket = NULL; | ||
2015 | return rc; | 2462 | return rc; |
2016 | } | 2463 | } |
2017 | 2464 | ||
@@ -2019,59 +2466,20 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2019 | cFYI(1, "Socket created"); | 2466 | cFYI(1, "Socket created"); |
2020 | server->ssocket = socket; | 2467 | server->ssocket = socket; |
2021 | socket->sk->sk_allocation = GFP_NOFS; | 2468 | socket->sk->sk_allocation = GFP_NOFS; |
2022 | cifs_reclassify_socket4(socket); | 2469 | if (sfamily == AF_INET6) |
2023 | } | 2470 | cifs_reclassify_socket6(socket); |
2024 | 2471 | else | |
2025 | /* user overrode default port */ | 2472 | cifs_reclassify_socket4(socket); |
2026 | if (server->addr.sockAddr.sin_port) { | ||
2027 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2028 | &server->addr.sockAddr, | ||
2029 | sizeof(struct sockaddr_in), 0); | ||
2030 | if (rc >= 0) | ||
2031 | connected = true; | ||
2032 | } | ||
2033 | |||
2034 | if (!connected) { | ||
2035 | /* save original port so we can retry user specified port | ||
2036 | later if fall back ports fail this time */ | ||
2037 | orig_port = server->addr.sockAddr.sin_port; | ||
2038 | |||
2039 | /* do not retry on the same port we just failed on */ | ||
2040 | if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) { | ||
2041 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); | ||
2042 | rc = socket->ops->connect(socket, | ||
2043 | (struct sockaddr *) | ||
2044 | &server->addr.sockAddr, | ||
2045 | sizeof(struct sockaddr_in), 0); | ||
2046 | if (rc >= 0) | ||
2047 | connected = true; | ||
2048 | } | ||
2049 | } | ||
2050 | if (!connected) { | ||
2051 | server->addr.sockAddr.sin_port = htons(RFC1001_PORT); | ||
2052 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2053 | &server->addr.sockAddr, | ||
2054 | sizeof(struct sockaddr_in), 0); | ||
2055 | if (rc >= 0) | ||
2056 | connected = true; | ||
2057 | } | 2473 | } |
2058 | 2474 | ||
2059 | /* give up here - unless we want to retry on different | 2475 | rc = bind_socket(server); |
2060 | protocol families some day */ | 2476 | if (rc < 0) |
2061 | if (!connected) { | ||
2062 | if (orig_port) | ||
2063 | server->addr.sockAddr.sin_port = orig_port; | ||
2064 | cFYI(1, "Error %d connecting to server via ipv4", rc); | ||
2065 | sock_release(socket); | ||
2066 | server->ssocket = NULL; | ||
2067 | return rc; | 2477 | return rc; |
2068 | } | ||
2069 | |||
2070 | 2478 | ||
2071 | /* | 2479 | /* |
2072 | * Eventually check for other socket options to change from | 2480 | * Eventually check for other socket options to change from |
2073 | * the default. sock_setsockopt not used because it expects | 2481 | * the default. sock_setsockopt not used because it expects |
2074 | * user space buffer | 2482 | * user space buffer |
2075 | */ | 2483 | */ |
2076 | socket->sk->sk_rcvtimeo = 7 * HZ; | 2484 | socket->sk->sk_rcvtimeo = 7 * HZ; |
2077 | socket->sk->sk_sndtimeo = 5 * HZ; | 2485 | socket->sk->sk_sndtimeo = 5 * HZ; |
@@ -2085,7 +2493,7 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2085 | } | 2493 | } |
2086 | 2494 | ||
2087 | if (server->tcp_nodelay) { | 2495 | if (server->tcp_nodelay) { |
2088 | val = 1; | 2496 | int val = 1; |
2089 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | 2497 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, |
2090 | (char *)&val, sizeof(val)); | 2498 | (char *)&val, sizeof(val)); |
2091 | if (rc) | 2499 | if (rc) |
@@ -2096,161 +2504,51 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2096 | socket->sk->sk_sndbuf, | 2504 | socket->sk->sk_sndbuf, |
2097 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); | 2505 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
2098 | 2506 | ||
2099 | /* send RFC1001 sessinit */ | 2507 | rc = socket->ops->connect(socket, saddr, slen, 0); |
2100 | if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) { | 2508 | if (rc < 0) { |
2101 | /* some servers require RFC1001 sessinit before sending | 2509 | cFYI(1, "Error %d connecting to server", rc); |
2102 | negprot - BB check reconnection in case where second | 2510 | sock_release(socket); |
2103 | sessinit is sent but no second negprot */ | 2511 | server->ssocket = NULL; |
2104 | struct rfc1002_session_packet *ses_init_buf; | 2512 | return rc; |
2105 | struct smb_hdr *smb_buf; | ||
2106 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2107 | GFP_KERNEL); | ||
2108 | if (ses_init_buf) { | ||
2109 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2110 | if (server->server_RFC1001_name && | ||
2111 | server->server_RFC1001_name[0] != 0) | ||
2112 | rfc1002mangle(ses_init_buf->trailer. | ||
2113 | session_req.called_name, | ||
2114 | server->server_RFC1001_name, | ||
2115 | RFC1001_NAME_LEN_WITH_NULL); | ||
2116 | else | ||
2117 | rfc1002mangle(ses_init_buf->trailer. | ||
2118 | session_req.called_name, | ||
2119 | DEFAULT_CIFS_CALLED_NAME, | ||
2120 | RFC1001_NAME_LEN_WITH_NULL); | ||
2121 | |||
2122 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2123 | |||
2124 | /* calling name ends in null (byte 16) from old smb | ||
2125 | convention. */ | ||
2126 | if (server->workstation_RFC1001_name && | ||
2127 | server->workstation_RFC1001_name[0] != 0) | ||
2128 | rfc1002mangle(ses_init_buf->trailer. | ||
2129 | session_req.calling_name, | ||
2130 | server->workstation_RFC1001_name, | ||
2131 | RFC1001_NAME_LEN_WITH_NULL); | ||
2132 | else | ||
2133 | rfc1002mangle(ses_init_buf->trailer. | ||
2134 | session_req.calling_name, | ||
2135 | "LINUX_CIFS_CLNT", | ||
2136 | RFC1001_NAME_LEN_WITH_NULL); | ||
2137 | |||
2138 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2139 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2140 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2141 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2142 | smb_buf->smb_buf_length = 0x81000044; | ||
2143 | rc = smb_send(server, smb_buf, 0x44); | ||
2144 | kfree(ses_init_buf); | ||
2145 | msleep(1); /* RFC1001 layer in at least one server | ||
2146 | requires very short break before negprot | ||
2147 | presumably because not expecting negprot | ||
2148 | to follow so fast. This is a simple | ||
2149 | solution that works without | ||
2150 | complicating the code and causes no | ||
2151 | significant slowing down on mount | ||
2152 | for everyone else */ | ||
2153 | } | ||
2154 | /* else the negprot may still work without this | ||
2155 | even though malloc failed */ | ||
2156 | |||
2157 | } | 2513 | } |
2158 | 2514 | ||
2515 | if (sport == htons(RFC1001_PORT)) | ||
2516 | rc = ip_rfc1001_connect(server); | ||
2517 | |||
2159 | return rc; | 2518 | return rc; |
2160 | } | 2519 | } |
2161 | 2520 | ||
2162 | static int | 2521 | static int |
2163 | ipv6_connect(struct TCP_Server_Info *server) | 2522 | ip_connect(struct TCP_Server_Info *server) |
2164 | { | 2523 | { |
2165 | int rc = 0; | 2524 | __be16 *sport; |
2166 | int val; | 2525 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
2167 | bool connected = false; | 2526 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
2168 | __be16 orig_port = 0; | ||
2169 | struct socket *socket = server->ssocket; | ||
2170 | 2527 | ||
2171 | if (socket == NULL) { | 2528 | if (server->dstaddr.ss_family == AF_INET6) |
2172 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, | 2529 | sport = &addr6->sin6_port; |
2173 | IPPROTO_TCP, &socket); | 2530 | else |
2174 | if (rc < 0) { | 2531 | sport = &addr->sin_port; |
2175 | cERROR(1, "Error %d creating ipv6 socket", rc); | ||
2176 | socket = NULL; | ||
2177 | return rc; | ||
2178 | } | ||
2179 | 2532 | ||
2180 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | 2533 | if (*sport == 0) { |
2181 | cFYI(1, "ipv6 Socket created"); | 2534 | int rc; |
2182 | server->ssocket = socket; | ||
2183 | socket->sk->sk_allocation = GFP_NOFS; | ||
2184 | cifs_reclassify_socket6(socket); | ||
2185 | } | ||
2186 | 2535 | ||
2187 | /* user overrode default port */ | 2536 | /* try with 445 port at first */ |
2188 | if (server->addr.sockAddr6.sin6_port) { | 2537 | *sport = htons(CIFS_PORT); |
2189 | rc = socket->ops->connect(socket, | ||
2190 | (struct sockaddr *) &server->addr.sockAddr6, | ||
2191 | sizeof(struct sockaddr_in6), 0); | ||
2192 | if (rc >= 0) | ||
2193 | connected = true; | ||
2194 | } | ||
2195 | |||
2196 | if (!connected) { | ||
2197 | /* save original port so we can retry user specified port | ||
2198 | later if fall back ports fail this time */ | ||
2199 | |||
2200 | orig_port = server->addr.sockAddr6.sin6_port; | ||
2201 | /* do not retry on the same port we just failed on */ | ||
2202 | if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) { | ||
2203 | server->addr.sockAddr6.sin6_port = htons(CIFS_PORT); | ||
2204 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2205 | &server->addr.sockAddr6, | ||
2206 | sizeof(struct sockaddr_in6), 0); | ||
2207 | if (rc >= 0) | ||
2208 | connected = true; | ||
2209 | } | ||
2210 | } | ||
2211 | if (!connected) { | ||
2212 | server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT); | ||
2213 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2214 | &server->addr.sockAddr6, | ||
2215 | sizeof(struct sockaddr_in6), 0); | ||
2216 | if (rc >= 0) | ||
2217 | connected = true; | ||
2218 | } | ||
2219 | |||
2220 | /* give up here - unless we want to retry on different | ||
2221 | protocol families some day */ | ||
2222 | if (!connected) { | ||
2223 | if (orig_port) | ||
2224 | server->addr.sockAddr6.sin6_port = orig_port; | ||
2225 | cFYI(1, "Error %d connecting to server via ipv6", rc); | ||
2226 | sock_release(socket); | ||
2227 | server->ssocket = NULL; | ||
2228 | return rc; | ||
2229 | } | ||
2230 | 2538 | ||
2231 | /* | 2539 | rc = generic_ip_connect(server); |
2232 | * Eventually check for other socket options to change from | 2540 | if (rc >= 0) |
2233 | * the default. sock_setsockopt not used because it expects | 2541 | return rc; |
2234 | * user space buffer | ||
2235 | */ | ||
2236 | socket->sk->sk_rcvtimeo = 7 * HZ; | ||
2237 | socket->sk->sk_sndtimeo = 5 * HZ; | ||
2238 | 2542 | ||
2239 | if (server->tcp_nodelay) { | 2543 | /* if it failed, try with 139 port */ |
2240 | val = 1; | 2544 | *sport = htons(RFC1001_PORT); |
2241 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | ||
2242 | (char *)&val, sizeof(val)); | ||
2243 | if (rc) | ||
2244 | cFYI(1, "set TCP_NODELAY socket option error %d", rc); | ||
2245 | } | 2545 | } |
2246 | 2546 | ||
2247 | server->ssocket = socket; | 2547 | return generic_ip_connect(server); |
2248 | |||
2249 | return rc; | ||
2250 | } | 2548 | } |
2251 | 2549 | ||
2252 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | 2550 | void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, |
2253 | struct super_block *sb, struct smb_vol *vol_info) | 2551 | struct cifs_sb_info *cifs_sb, struct smb_vol *vol_info) |
2254 | { | 2552 | { |
2255 | /* if we are reconnecting then should we check to see if | 2553 | /* if we are reconnecting then should we check to see if |
2256 | * any requested capabilities changed locally e.g. via | 2554 | * any requested capabilities changed locally e.g. via |
@@ -2278,7 +2576,7 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | |||
2278 | 2576 | ||
2279 | if (!CIFSSMBQFSUnixInfo(xid, tcon)) { | 2577 | if (!CIFSSMBQFSUnixInfo(xid, tcon)) { |
2280 | __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | 2578 | __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); |
2281 | 2579 | cFYI(1, "unix caps which server supports %lld", cap); | |
2282 | /* check for reconnect case in which we do not | 2580 | /* check for reconnect case in which we do not |
2283 | want to change the mount behavior if we can avoid it */ | 2581 | want to change the mount behavior if we can avoid it */ |
2284 | if (vol_info == NULL) { | 2582 | if (vol_info == NULL) { |
@@ -2296,33 +2594,31 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | |||
2296 | } | 2594 | } |
2297 | } | 2595 | } |
2298 | 2596 | ||
2597 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) | ||
2598 | cERROR(1, "per-share encryption not supported yet"); | ||
2599 | |||
2299 | cap &= CIFS_UNIX_CAP_MASK; | 2600 | cap &= CIFS_UNIX_CAP_MASK; |
2300 | if (vol_info && vol_info->no_psx_acl) | 2601 | if (vol_info && vol_info->no_psx_acl) |
2301 | cap &= ~CIFS_UNIX_POSIX_ACL_CAP; | 2602 | cap &= ~CIFS_UNIX_POSIX_ACL_CAP; |
2302 | else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { | 2603 | else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { |
2303 | cFYI(1, "negotiated posix acl support"); | 2604 | cFYI(1, "negotiated posix acl support"); |
2304 | if (sb) | 2605 | if (cifs_sb) |
2305 | sb->s_flags |= MS_POSIXACL; | 2606 | cifs_sb->mnt_cifs_flags |= |
2607 | CIFS_MOUNT_POSIXACL; | ||
2306 | } | 2608 | } |
2307 | 2609 | ||
2308 | if (vol_info && vol_info->posix_paths == 0) | 2610 | if (vol_info && vol_info->posix_paths == 0) |
2309 | cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; | 2611 | cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; |
2310 | else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { | 2612 | else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { |
2311 | cFYI(1, "negotiate posix pathnames"); | 2613 | cFYI(1, "negotiate posix pathnames"); |
2312 | if (sb) | 2614 | if (cifs_sb) |
2313 | CIFS_SB(sb)->mnt_cifs_flags |= | 2615 | cifs_sb->mnt_cifs_flags |= |
2314 | CIFS_MOUNT_POSIX_PATHS; | 2616 | CIFS_MOUNT_POSIX_PATHS; |
2315 | } | 2617 | } |
2316 | 2618 | ||
2317 | /* We might be setting the path sep back to a different | 2619 | if (cifs_sb && (cifs_sb->rsize > 127 * 1024)) { |
2318 | form if we are reconnecting and the server switched its | ||
2319 | posix path capability for this share */ | ||
2320 | if (sb && (CIFS_SB(sb)->prepathlen > 0)) | ||
2321 | CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb)); | ||
2322 | |||
2323 | if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) { | ||
2324 | if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { | 2620 | if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { |
2325 | CIFS_SB(sb)->rsize = 127 * 1024; | 2621 | cifs_sb->rsize = 127 * 1024; |
2326 | cFYI(DBG2, "larger reads not supported by srv"); | 2622 | cFYI(DBG2, "larger reads not supported by srv"); |
2327 | } | 2623 | } |
2328 | } | 2624 | } |
@@ -2344,6 +2640,10 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | |||
2344 | cFYI(1, "very large read cap"); | 2640 | cFYI(1, "very large read cap"); |
2345 | if (cap & CIFS_UNIX_LARGE_WRITE_CAP) | 2641 | if (cap & CIFS_UNIX_LARGE_WRITE_CAP) |
2346 | cFYI(1, "very large write cap"); | 2642 | cFYI(1, "very large write cap"); |
2643 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) | ||
2644 | cFYI(1, "transport encryption cap"); | ||
2645 | if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) | ||
2646 | cFYI(1, "mandatory transport encryption cap"); | ||
2347 | #endif /* CIFS_DEBUG2 */ | 2647 | #endif /* CIFS_DEBUG2 */ |
2348 | if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { | 2648 | if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { |
2349 | if (vol_info == NULL) { | 2649 | if (vol_info == NULL) { |
@@ -2360,29 +2660,14 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | |||
2360 | } | 2660 | } |
2361 | } | 2661 | } |
2362 | 2662 | ||
2363 | static void | 2663 | void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, |
2364 | convert_delimiter(char *path, char delim) | 2664 | struct cifs_sb_info *cifs_sb) |
2365 | { | 2665 | { |
2366 | int i; | 2666 | INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); |
2367 | char old_delim; | ||
2368 | 2667 | ||
2369 | if (path == NULL) | 2668 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
2370 | return; | 2669 | cifs_sb->tlink_tree = RB_ROOT; |
2371 | 2670 | ||
2372 | if (delim == '/') | ||
2373 | old_delim = '\\'; | ||
2374 | else | ||
2375 | old_delim = '/'; | ||
2376 | |||
2377 | for (i = 0; path[i] != '\0'; i++) { | ||
2378 | if (path[i] == old_delim) | ||
2379 | path[i] = delim; | ||
2380 | } | ||
2381 | } | ||
2382 | |||
2383 | static void setup_cifs_sb(struct smb_vol *pvolume_info, | ||
2384 | struct cifs_sb_info *cifs_sb) | ||
2385 | { | ||
2386 | if (pvolume_info->rsize > CIFSMaxBufSize) { | 2671 | if (pvolume_info->rsize > CIFSMaxBufSize) { |
2387 | cERROR(1, "rsize %d too large, using MaxBufSize", | 2672 | cERROR(1, "rsize %d too large, using MaxBufSize", |
2388 | pvolume_info->rsize); | 2673 | pvolume_info->rsize); |
@@ -2393,40 +2678,19 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2393 | else /* default */ | 2678 | else /* default */ |
2394 | cifs_sb->rsize = CIFSMaxBufSize; | 2679 | cifs_sb->rsize = CIFSMaxBufSize; |
2395 | 2680 | ||
2396 | if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { | ||
2397 | cERROR(1, "wsize %d too large, using 4096 instead", | ||
2398 | pvolume_info->wsize); | ||
2399 | cifs_sb->wsize = 4096; | ||
2400 | } else if (pvolume_info->wsize) | ||
2401 | cifs_sb->wsize = pvolume_info->wsize; | ||
2402 | else | ||
2403 | cifs_sb->wsize = min_t(const int, | ||
2404 | PAGEVEC_SIZE * PAGE_CACHE_SIZE, | ||
2405 | 127*1024); | ||
2406 | /* old default of CIFSMaxBufSize was too small now | ||
2407 | that SMB Write2 can send multiple pages in kvec. | ||
2408 | RFC1001 does not describe what happens when frame | ||
2409 | bigger than 128K is sent so use that as max in | ||
2410 | conjunction with 52K kvec constraint on arch with 4K | ||
2411 | page size */ | ||
2412 | |||
2413 | if (cifs_sb->rsize < 2048) { | 2681 | if (cifs_sb->rsize < 2048) { |
2414 | cifs_sb->rsize = 2048; | 2682 | cifs_sb->rsize = 2048; |
2415 | /* Windows ME may prefer this */ | 2683 | /* Windows ME may prefer this */ |
2416 | cFYI(1, "readsize set to minimum: 2048"); | 2684 | cFYI(1, "readsize set to minimum: 2048"); |
2417 | } | 2685 | } |
2418 | /* calculate prepath */ | 2686 | |
2419 | cifs_sb->prepath = pvolume_info->prepath; | 2687 | /* |
2420 | if (cifs_sb->prepath) { | 2688 | * Temporarily set wsize for matching superblock. If we end up using |
2421 | cifs_sb->prepathlen = strlen(cifs_sb->prepath); | 2689 | * new sb then cifs_negotiate_wsize will later negotiate it downward |
2422 | /* we can not convert the / to \ in the path | 2690 | * if needed. |
2423 | separators in the prefixpath yet because we do not | 2691 | */ |
2424 | know (until reset_cifs_unix_caps is called later) | 2692 | cifs_sb->wsize = pvolume_info->wsize; |
2425 | whether POSIX PATH CAP is available. We normalize | 2693 | |
2426 | the / to \ after reset_cifs_unix_caps is called */ | ||
2427 | pvolume_info->prepath = NULL; | ||
2428 | } else | ||
2429 | cifs_sb->prepathlen = 0; | ||
2430 | cifs_sb->mnt_uid = pvolume_info->linux_uid; | 2694 | cifs_sb->mnt_uid = pvolume_info->linux_uid; |
2431 | cifs_sb->mnt_gid = pvolume_info->linux_gid; | 2695 | cifs_sb->mnt_gid = pvolume_info->linux_gid; |
2432 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; | 2696 | cifs_sb->mnt_file_mode = pvolume_info->file_mode; |
@@ -2434,6 +2698,9 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2434 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", | 2698 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", |
2435 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); | 2699 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); |
2436 | 2700 | ||
2701 | cifs_sb->actimeo = pvolume_info->actimeo; | ||
2702 | cifs_sb->local_nls = pvolume_info->local_nls; | ||
2703 | |||
2437 | if (pvolume_info->noperm) | 2704 | if (pvolume_info->noperm) |
2438 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | 2705 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; |
2439 | if (pvolume_info->setuids) | 2706 | if (pvolume_info->setuids) |
@@ -2452,6 +2719,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2452 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; | 2719 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOSSYNC; |
2453 | if (pvolume_info->mand_lock) | 2720 | if (pvolume_info->mand_lock) |
2454 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; | 2721 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; |
2722 | if (pvolume_info->rwpidforward) | ||
2723 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD; | ||
2455 | if (pvolume_info->cifs_acl) | 2724 | if (pvolume_info->cifs_acl) |
2456 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | 2725 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; |
2457 | if (pvolume_info->override_uid) | 2726 | if (pvolume_info->override_uid) |
@@ -2462,18 +2731,85 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2462 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 2731 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; |
2463 | if (pvolume_info->fsc) | 2732 | if (pvolume_info->fsc) |
2464 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | 2733 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; |
2734 | if (pvolume_info->multiuser) | ||
2735 | cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | | ||
2736 | CIFS_MOUNT_NO_PERM); | ||
2737 | if (pvolume_info->strict_io) | ||
2738 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_STRICT_IO; | ||
2465 | if (pvolume_info->direct_io) { | 2739 | if (pvolume_info->direct_io) { |
2466 | cFYI(1, "mounting share using direct i/o"); | 2740 | cFYI(1, "mounting share using direct i/o"); |
2467 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2741 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
2468 | } | 2742 | } |
2743 | if (pvolume_info->mfsymlinks) { | ||
2744 | if (pvolume_info->sfu_emul) { | ||
2745 | cERROR(1, "mount option mfsymlinks ignored if sfu " | ||
2746 | "mount option is used"); | ||
2747 | } else { | ||
2748 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; | ||
2749 | } | ||
2750 | } | ||
2469 | 2751 | ||
2470 | if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) | 2752 | if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) |
2471 | cERROR(1, "mount option dynperm ignored if cifsacl " | 2753 | cERROR(1, "mount option dynperm ignored if cifsacl " |
2472 | "mount option supported"); | 2754 | "mount option supported"); |
2473 | } | 2755 | } |
2474 | 2756 | ||
2757 | /* | ||
2758 | * When the server supports very large writes via POSIX extensions, we can | ||
2759 | * allow up to 2^24-1, minus the size of a WRITE_AND_X header, not including | ||
2760 | * the RFC1001 length. | ||
2761 | * | ||
2762 | * Note that this might make for "interesting" allocation problems during | ||
2763 | * writeback however as we have to allocate an array of pointers for the | ||
2764 | * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096. | ||
2765 | */ | ||
2766 | #define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4) | ||
2767 | |||
2768 | /* | ||
2769 | * When the server doesn't allow large posix writes, only allow a wsize of | ||
2770 | * 128k minus the size of the WRITE_AND_X header. That allows for a write up | ||
2771 | * to the maximum size described by RFC1002. | ||
2772 | */ | ||
2773 | #define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4) | ||
2774 | |||
2775 | /* | ||
2776 | * The default wsize is 1M. find_get_pages seems to return a maximum of 256 | ||
2777 | * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill | ||
2778 | * a single wsize request with a single call. | ||
2779 | */ | ||
2780 | #define CIFS_DEFAULT_WSIZE (1024 * 1024) | ||
2781 | |||
2782 | static unsigned int | ||
2783 | cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info) | ||
2784 | { | ||
2785 | __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
2786 | struct TCP_Server_Info *server = tcon->ses->server; | ||
2787 | unsigned int wsize = pvolume_info->wsize ? pvolume_info->wsize : | ||
2788 | CIFS_DEFAULT_WSIZE; | ||
2789 | |||
2790 | /* can server support 24-bit write sizes? (via UNIX extensions) */ | ||
2791 | if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP)) | ||
2792 | wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE); | ||
2793 | |||
2794 | /* | ||
2795 | * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set? | ||
2796 | * Limit it to max buffer offered by the server, minus the size of the | ||
2797 | * WRITEX header, not including the 4 byte RFC1001 length. | ||
2798 | */ | ||
2799 | if (!(server->capabilities & CAP_LARGE_WRITE_X) || | ||
2800 | (!(server->capabilities & CAP_UNIX) && | ||
2801 | (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)))) | ||
2802 | wsize = min_t(unsigned int, wsize, | ||
2803 | server->maxBuf - sizeof(WRITE_REQ) + 4); | ||
2804 | |||
2805 | /* hard limit of CIFS_MAX_WSIZE */ | ||
2806 | wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE); | ||
2807 | |||
2808 | return wsize; | ||
2809 | } | ||
2810 | |||
2475 | static int | 2811 | static int |
2476 | is_path_accessible(int xid, struct cifsTconInfo *tcon, | 2812 | is_path_accessible(int xid, struct cifs_tcon *tcon, |
2477 | struct cifs_sb_info *cifs_sb, const char *full_path) | 2813 | struct cifs_sb_info *cifs_sb, const char *full_path) |
2478 | { | 2814 | { |
2479 | int rc; | 2815 | int rc; |
@@ -2487,99 +2823,138 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon, | |||
2487 | 0 /* not legacy */, cifs_sb->local_nls, | 2823 | 0 /* not legacy */, cifs_sb->local_nls, |
2488 | cifs_sb->mnt_cifs_flags & | 2824 | cifs_sb->mnt_cifs_flags & |
2489 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 2825 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
2826 | |||
2827 | if (rc == -EOPNOTSUPP || rc == -EINVAL) | ||
2828 | rc = SMBQueryInformation(xid, tcon, full_path, pfile_info, | ||
2829 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
2830 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
2490 | kfree(pfile_info); | 2831 | kfree(pfile_info); |
2491 | return rc; | 2832 | return rc; |
2492 | } | 2833 | } |
2493 | 2834 | ||
2494 | static void | 2835 | static void |
2495 | cleanup_volume_info(struct smb_vol **pvolume_info) | 2836 | cleanup_volume_info_contents(struct smb_vol *volume_info) |
2496 | { | 2837 | { |
2497 | struct smb_vol *volume_info; | 2838 | kfree(volume_info->username); |
2498 | |||
2499 | if (!pvolume_info || !*pvolume_info) | ||
2500 | return; | ||
2501 | |||
2502 | volume_info = *pvolume_info; | ||
2503 | kzfree(volume_info->password); | 2839 | kzfree(volume_info->password); |
2504 | kfree(volume_info->UNC); | 2840 | kfree(volume_info->UNC); |
2841 | kfree(volume_info->UNCip); | ||
2842 | kfree(volume_info->domainname); | ||
2843 | kfree(volume_info->iocharset); | ||
2505 | kfree(volume_info->prepath); | 2844 | kfree(volume_info->prepath); |
2845 | } | ||
2846 | |||
2847 | void | ||
2848 | cifs_cleanup_volume_info(struct smb_vol *volume_info) | ||
2849 | { | ||
2850 | if (!volume_info) | ||
2851 | return; | ||
2852 | cleanup_volume_info_contents(volume_info); | ||
2506 | kfree(volume_info); | 2853 | kfree(volume_info); |
2507 | *pvolume_info = NULL; | ||
2508 | return; | ||
2509 | } | 2854 | } |
2510 | 2855 | ||
2856 | |||
2511 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2857 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2512 | /* build_path_to_root returns full path to root when | 2858 | /* build_path_to_root returns full path to root when |
2513 | * we do not have an exiting connection (tcon) */ | 2859 | * we do not have an exiting connection (tcon) */ |
2514 | static char * | 2860 | static char * |
2515 | build_unc_path_to_root(const struct smb_vol *volume_info, | 2861 | build_unc_path_to_root(const struct smb_vol *vol, |
2516 | const struct cifs_sb_info *cifs_sb) | 2862 | const struct cifs_sb_info *cifs_sb) |
2517 | { | 2863 | { |
2518 | char *full_path; | 2864 | char *full_path, *pos; |
2865 | unsigned int pplen = vol->prepath ? strlen(vol->prepath) : 0; | ||
2866 | unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); | ||
2519 | 2867 | ||
2520 | int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); | 2868 | full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); |
2521 | full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL); | ||
2522 | if (full_path == NULL) | 2869 | if (full_path == NULL) |
2523 | return ERR_PTR(-ENOMEM); | 2870 | return ERR_PTR(-ENOMEM); |
2524 | 2871 | ||
2525 | strncpy(full_path, volume_info->UNC, unc_len); | 2872 | strncpy(full_path, vol->UNC, unc_len); |
2526 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | 2873 | pos = full_path + unc_len; |
2527 | int i; | ||
2528 | for (i = 0; i < unc_len; i++) { | ||
2529 | if (full_path[i] == '\\') | ||
2530 | full_path[i] = '/'; | ||
2531 | } | ||
2532 | } | ||
2533 | 2874 | ||
2534 | if (cifs_sb->prepathlen) | 2875 | if (pplen) { |
2535 | strncpy(full_path + unc_len, cifs_sb->prepath, | 2876 | strncpy(pos, vol->prepath, pplen); |
2536 | cifs_sb->prepathlen); | 2877 | pos += pplen; |
2878 | } | ||
2537 | 2879 | ||
2538 | full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ | 2880 | *pos = '\0'; /* add trailing null */ |
2881 | convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); | ||
2882 | cFYI(1, "%s: full_path=%s", __func__, full_path); | ||
2539 | return full_path; | 2883 | return full_path; |
2540 | } | 2884 | } |
2541 | #endif | ||
2542 | 2885 | ||
2543 | int | 2886 | /* |
2544 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2887 | * Perform a dfs referral query for a share and (optionally) prefix |
2545 | char *mount_data_global, const char *devname) | 2888 | * |
2889 | * If a referral is found, cifs_sb->mountdata will be (re-)allocated | ||
2890 | * to a string containing updated options for the submount. Otherwise it | ||
2891 | * will be left untouched. | ||
2892 | * | ||
2893 | * Returns the rc from get_dfs_path to the caller, which can be used to | ||
2894 | * determine whether there were referrals. | ||
2895 | */ | ||
2896 | static int | ||
2897 | expand_dfs_referral(int xid, struct cifs_ses *pSesInfo, | ||
2898 | struct smb_vol *volume_info, struct cifs_sb_info *cifs_sb, | ||
2899 | int check_prefix) | ||
2546 | { | 2900 | { |
2547 | int rc; | 2901 | int rc; |
2548 | int xid; | ||
2549 | struct smb_vol *volume_info; | ||
2550 | struct cifsSesInfo *pSesInfo; | ||
2551 | struct cifsTconInfo *tcon; | ||
2552 | struct TCP_Server_Info *srvTcp; | ||
2553 | char *full_path; | ||
2554 | char *mount_data = mount_data_global; | ||
2555 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
2556 | struct dfs_info3_param *referrals = NULL; | ||
2557 | unsigned int num_referrals = 0; | 2902 | unsigned int num_referrals = 0; |
2558 | int referral_walks_count = 0; | 2903 | struct dfs_info3_param *referrals = NULL; |
2559 | try_mount_again: | 2904 | char *full_path = NULL, *ref_path = NULL, *mdata = NULL; |
2560 | #endif | ||
2561 | rc = 0; | ||
2562 | tcon = NULL; | ||
2563 | pSesInfo = NULL; | ||
2564 | srvTcp = NULL; | ||
2565 | full_path = NULL; | ||
2566 | 2905 | ||
2567 | xid = GetXid(); | 2906 | full_path = build_unc_path_to_root(volume_info, cifs_sb); |
2907 | if (IS_ERR(full_path)) | ||
2908 | return PTR_ERR(full_path); | ||
2568 | 2909 | ||
2569 | volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); | 2910 | /* For DFS paths, skip the first '\' of the UNC */ |
2570 | if (!volume_info) { | 2911 | ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; |
2571 | rc = -ENOMEM; | ||
2572 | goto out; | ||
2573 | } | ||
2574 | 2912 | ||
2575 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) { | 2913 | rc = get_dfs_path(xid, pSesInfo , ref_path, cifs_sb->local_nls, |
2576 | rc = -EINVAL; | 2914 | &num_referrals, &referrals, |
2577 | goto out; | 2915 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
2916 | |||
2917 | if (!rc && num_referrals > 0) { | ||
2918 | char *fake_devname = NULL; | ||
2919 | |||
2920 | mdata = cifs_compose_mount_options(cifs_sb->mountdata, | ||
2921 | full_path + 1, referrals, | ||
2922 | &fake_devname); | ||
2923 | |||
2924 | free_dfs_info_array(referrals, num_referrals); | ||
2925 | |||
2926 | if (IS_ERR(mdata)) { | ||
2927 | rc = PTR_ERR(mdata); | ||
2928 | mdata = NULL; | ||
2929 | } else { | ||
2930 | cleanup_volume_info_contents(volume_info); | ||
2931 | memset(volume_info, '\0', sizeof(*volume_info)); | ||
2932 | rc = cifs_setup_volume_info(volume_info, mdata, | ||
2933 | fake_devname); | ||
2934 | } | ||
2935 | kfree(fake_devname); | ||
2936 | kfree(cifs_sb->mountdata); | ||
2937 | cifs_sb->mountdata = mdata; | ||
2578 | } | 2938 | } |
2939 | kfree(full_path); | ||
2940 | return rc; | ||
2941 | } | ||
2942 | #endif | ||
2943 | |||
2944 | static int | ||
2945 | cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | ||
2946 | const char *devname) | ||
2947 | { | ||
2948 | int rc = 0; | ||
2949 | |||
2950 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) | ||
2951 | return -EINVAL; | ||
2579 | 2952 | ||
2580 | if (volume_info->nullauth) { | 2953 | if (volume_info->nullauth) { |
2581 | cFYI(1, "null user"); | 2954 | cFYI(1, "null user"); |
2582 | volume_info->username = ""; | 2955 | volume_info->username = kzalloc(1, GFP_KERNEL); |
2956 | if (volume_info->username == NULL) | ||
2957 | return -ENOMEM; | ||
2583 | } else if (volume_info->username) { | 2958 | } else if (volume_info->username) { |
2584 | /* BB fixme parse for domain name here */ | 2959 | /* BB fixme parse for domain name here */ |
2585 | cFYI(1, "Username: %s", volume_info->username); | 2960 | cFYI(1, "Username: %s", volume_info->username); |
@@ -2587,8 +2962,7 @@ try_mount_again: | |||
2587 | cifserror("No username specified"); | 2962 | cifserror("No username specified"); |
2588 | /* In userspace mount helper we can get user name from alternate | 2963 | /* In userspace mount helper we can get user name from alternate |
2589 | locations such as env variables and files on disk */ | 2964 | locations such as env variables and files on disk */ |
2590 | rc = -EINVAL; | 2965 | return -EINVAL; |
2591 | goto out; | ||
2592 | } | 2966 | } |
2593 | 2967 | ||
2594 | /* this is needed for ASCII cp to Unicode converts */ | 2968 | /* this is needed for ASCII cp to Unicode converts */ |
@@ -2600,16 +2974,77 @@ try_mount_again: | |||
2600 | if (volume_info->local_nls == NULL) { | 2974 | if (volume_info->local_nls == NULL) { |
2601 | cERROR(1, "CIFS mount error: iocharset %s not found", | 2975 | cERROR(1, "CIFS mount error: iocharset %s not found", |
2602 | volume_info->iocharset); | 2976 | volume_info->iocharset); |
2603 | rc = -ELIBACC; | 2977 | return -ELIBACC; |
2604 | goto out; | ||
2605 | } | 2978 | } |
2606 | } | 2979 | } |
2607 | cifs_sb->local_nls = volume_info->local_nls; | 2980 | |
2981 | return rc; | ||
2982 | } | ||
2983 | |||
2984 | struct smb_vol * | ||
2985 | cifs_get_volume_info(char *mount_data, const char *devname) | ||
2986 | { | ||
2987 | int rc; | ||
2988 | struct smb_vol *volume_info; | ||
2989 | |||
2990 | volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); | ||
2991 | if (!volume_info) | ||
2992 | return ERR_PTR(-ENOMEM); | ||
2993 | |||
2994 | rc = cifs_setup_volume_info(volume_info, mount_data, devname); | ||
2995 | if (rc) { | ||
2996 | cifs_cleanup_volume_info(volume_info); | ||
2997 | volume_info = ERR_PTR(rc); | ||
2998 | } | ||
2999 | |||
3000 | return volume_info; | ||
3001 | } | ||
3002 | |||
3003 | int | ||
3004 | cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) | ||
3005 | { | ||
3006 | int rc = 0; | ||
3007 | int xid; | ||
3008 | struct cifs_ses *pSesInfo; | ||
3009 | struct cifs_tcon *tcon; | ||
3010 | struct TCP_Server_Info *srvTcp; | ||
3011 | char *full_path; | ||
3012 | struct tcon_link *tlink; | ||
3013 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
3014 | int referral_walks_count = 0; | ||
3015 | #endif | ||
3016 | |||
3017 | rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY); | ||
3018 | if (rc) | ||
3019 | return rc; | ||
3020 | |||
3021 | cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; | ||
3022 | |||
3023 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
3024 | try_mount_again: | ||
3025 | /* cleanup activities if we're chasing a referral */ | ||
3026 | if (referral_walks_count) { | ||
3027 | if (tcon) | ||
3028 | cifs_put_tcon(tcon); | ||
3029 | else if (pSesInfo) | ||
3030 | cifs_put_smb_ses(pSesInfo); | ||
3031 | |||
3032 | FreeXid(xid); | ||
3033 | } | ||
3034 | #endif | ||
3035 | tcon = NULL; | ||
3036 | pSesInfo = NULL; | ||
3037 | srvTcp = NULL; | ||
3038 | full_path = NULL; | ||
3039 | tlink = NULL; | ||
3040 | |||
3041 | xid = GetXid(); | ||
2608 | 3042 | ||
2609 | /* get a reference to a tcp session */ | 3043 | /* get a reference to a tcp session */ |
2610 | srvTcp = cifs_get_tcp_session(volume_info); | 3044 | srvTcp = cifs_get_tcp_session(volume_info); |
2611 | if (IS_ERR(srvTcp)) { | 3045 | if (IS_ERR(srvTcp)) { |
2612 | rc = PTR_ERR(srvTcp); | 3046 | rc = PTR_ERR(srvTcp); |
3047 | bdi_destroy(&cifs_sb->bdi); | ||
2613 | goto out; | 3048 | goto out; |
2614 | } | 3049 | } |
2615 | 3050 | ||
@@ -2621,15 +3056,6 @@ try_mount_again: | |||
2621 | goto mount_fail_check; | 3056 | goto mount_fail_check; |
2622 | } | 3057 | } |
2623 | 3058 | ||
2624 | setup_cifs_sb(volume_info, cifs_sb); | ||
2625 | if (pSesInfo->capabilities & CAP_LARGE_FILES) | ||
2626 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
2627 | else | ||
2628 | sb->s_maxbytes = MAX_NON_LFS; | ||
2629 | |||
2630 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | ||
2631 | sb->s_time_gran = 100; | ||
2632 | |||
2633 | /* search for existing tcon to this server share */ | 3059 | /* search for existing tcon to this server share */ |
2634 | tcon = cifs_get_tcon(pSesInfo, volume_info); | 3060 | tcon = cifs_get_tcon(pSesInfo, volume_info); |
2635 | if (IS_ERR(tcon)) { | 3061 | if (IS_ERR(tcon)) { |
@@ -2638,7 +3064,19 @@ try_mount_again: | |||
2638 | goto remote_path_check; | 3064 | goto remote_path_check; |
2639 | } | 3065 | } |
2640 | 3066 | ||
2641 | cifs_sb->tcon = tcon; | 3067 | /* tell server which Unix caps we support */ |
3068 | if (tcon->ses->capabilities & CAP_UNIX) { | ||
3069 | /* reset of caps checks mount to see if unix extensions | ||
3070 | disabled for just this mount */ | ||
3071 | reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info); | ||
3072 | if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && | ||
3073 | (le64_to_cpu(tcon->fsUnixInfo.Capability) & | ||
3074 | CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) { | ||
3075 | rc = -EACCES; | ||
3076 | goto mount_fail_check; | ||
3077 | } | ||
3078 | } else | ||
3079 | tcon->unix_ext = 0; /* server does not support them */ | ||
2642 | 3080 | ||
2643 | /* do not care if following two calls succeed - informational */ | 3081 | /* do not care if following two calls succeed - informational */ |
2644 | if (!tcon->ipc) { | 3082 | if (!tcon->ipc) { |
@@ -2646,40 +3084,45 @@ try_mount_again: | |||
2646 | CIFSSMBQFSAttributeInfo(xid, tcon); | 3084 | CIFSSMBQFSAttributeInfo(xid, tcon); |
2647 | } | 3085 | } |
2648 | 3086 | ||
2649 | /* tell server which Unix caps we support */ | ||
2650 | if (tcon->ses->capabilities & CAP_UNIX) | ||
2651 | /* reset of caps checks mount to see if unix extensions | ||
2652 | disabled for just this mount */ | ||
2653 | reset_cifs_unix_caps(xid, tcon, sb, volume_info); | ||
2654 | else | ||
2655 | tcon->unix_ext = 0; /* server does not support them */ | ||
2656 | |||
2657 | /* convert forward to back slashes in prepath here if needed */ | ||
2658 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | ||
2659 | convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); | ||
2660 | |||
2661 | if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { | 3087 | if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { |
2662 | cifs_sb->rsize = 1024 * 127; | 3088 | cifs_sb->rsize = 1024 * 127; |
2663 | cFYI(DBG2, "no very large read support, rsize now 127K"); | 3089 | cFYI(DBG2, "no very large read support, rsize now 127K"); |
2664 | } | 3090 | } |
2665 | if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) | ||
2666 | cifs_sb->wsize = min(cifs_sb->wsize, | ||
2667 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | ||
2668 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) | 3091 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) |
2669 | cifs_sb->rsize = min(cifs_sb->rsize, | 3092 | cifs_sb->rsize = min(cifs_sb->rsize, |
2670 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 3093 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
2671 | 3094 | ||
3095 | cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info); | ||
3096 | |||
2672 | remote_path_check: | 3097 | remote_path_check: |
2673 | /* check if a whole path (including prepath) is not remote */ | 3098 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2674 | if (!rc && cifs_sb->prepathlen && tcon) { | 3099 | /* |
3100 | * Perform an unconditional check for whether there are DFS | ||
3101 | * referrals for this path without prefix, to provide support | ||
3102 | * for DFS referrals from w2k8 servers which don't seem to respond | ||
3103 | * with PATH_NOT_COVERED to requests that include the prefix. | ||
3104 | * Chase the referral if found, otherwise continue normally. | ||
3105 | */ | ||
3106 | if (referral_walks_count == 0) { | ||
3107 | int refrc = expand_dfs_referral(xid, pSesInfo, volume_info, | ||
3108 | cifs_sb, false); | ||
3109 | if (!refrc) { | ||
3110 | referral_walks_count++; | ||
3111 | goto try_mount_again; | ||
3112 | } | ||
3113 | } | ||
3114 | #endif | ||
3115 | |||
3116 | /* check if a whole path is not remote */ | ||
3117 | if (!rc && tcon) { | ||
2675 | /* build_path_to_root works only when we have a valid tcon */ | 3118 | /* build_path_to_root works only when we have a valid tcon */ |
2676 | full_path = cifs_build_path_to_root(cifs_sb); | 3119 | full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); |
2677 | if (full_path == NULL) { | 3120 | if (full_path == NULL) { |
2678 | rc = -ENOMEM; | 3121 | rc = -ENOMEM; |
2679 | goto mount_fail_check; | 3122 | goto mount_fail_check; |
2680 | } | 3123 | } |
2681 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | 3124 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
2682 | if (rc != -EREMOTE) { | 3125 | if (rc != 0 && rc != -EREMOTE) { |
2683 | kfree(full_path); | 3126 | kfree(full_path); |
2684 | goto mount_fail_check; | 3127 | goto mount_fail_check; |
2685 | } | 3128 | } |
@@ -2699,68 +3142,56 @@ remote_path_check: | |||
2699 | rc = -ELOOP; | 3142 | rc = -ELOOP; |
2700 | goto mount_fail_check; | 3143 | goto mount_fail_check; |
2701 | } | 3144 | } |
2702 | /* convert forward to back slashes in prepath here if needed */ | ||
2703 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | ||
2704 | convert_delimiter(cifs_sb->prepath, | ||
2705 | CIFS_DIR_SEP(cifs_sb)); | ||
2706 | full_path = build_unc_path_to_root(volume_info, cifs_sb); | ||
2707 | if (IS_ERR(full_path)) { | ||
2708 | rc = PTR_ERR(full_path); | ||
2709 | goto mount_fail_check; | ||
2710 | } | ||
2711 | |||
2712 | cFYI(1, "Getting referral for: %s", full_path); | ||
2713 | rc = get_dfs_path(xid, pSesInfo , full_path + 1, | ||
2714 | cifs_sb->local_nls, &num_referrals, &referrals, | ||
2715 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
2716 | if (!rc && num_referrals > 0) { | ||
2717 | char *fake_devname = NULL; | ||
2718 | |||
2719 | if (mount_data != mount_data_global) | ||
2720 | kfree(mount_data); | ||
2721 | 3145 | ||
2722 | mount_data = cifs_compose_mount_options( | 3146 | rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb, |
2723 | cifs_sb->mountdata, full_path + 1, | 3147 | true); |
2724 | referrals, &fake_devname); | ||
2725 | |||
2726 | free_dfs_info_array(referrals, num_referrals); | ||
2727 | kfree(fake_devname); | ||
2728 | kfree(full_path); | ||
2729 | 3148 | ||
2730 | if (IS_ERR(mount_data)) { | 3149 | if (!rc) { |
2731 | rc = PTR_ERR(mount_data); | ||
2732 | mount_data = NULL; | ||
2733 | goto mount_fail_check; | ||
2734 | } | ||
2735 | |||
2736 | if (tcon) | ||
2737 | cifs_put_tcon(tcon); | ||
2738 | else if (pSesInfo) | ||
2739 | cifs_put_smb_ses(pSesInfo); | ||
2740 | |||
2741 | cleanup_volume_info(&volume_info); | ||
2742 | referral_walks_count++; | 3150 | referral_walks_count++; |
2743 | FreeXid(xid); | ||
2744 | goto try_mount_again; | 3151 | goto try_mount_again; |
2745 | } | 3152 | } |
3153 | goto mount_fail_check; | ||
2746 | #else /* No DFS support, return error on mount */ | 3154 | #else /* No DFS support, return error on mount */ |
2747 | rc = -EOPNOTSUPP; | 3155 | rc = -EOPNOTSUPP; |
2748 | #endif | 3156 | #endif |
2749 | } | 3157 | } |
2750 | 3158 | ||
3159 | if (rc) | ||
3160 | goto mount_fail_check; | ||
3161 | |||
3162 | /* now, hang the tcon off of the superblock */ | ||
3163 | tlink = kzalloc(sizeof *tlink, GFP_KERNEL); | ||
3164 | if (tlink == NULL) { | ||
3165 | rc = -ENOMEM; | ||
3166 | goto mount_fail_check; | ||
3167 | } | ||
3168 | |||
3169 | tlink->tl_uid = pSesInfo->linux_uid; | ||
3170 | tlink->tl_tcon = tcon; | ||
3171 | tlink->tl_time = jiffies; | ||
3172 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); | ||
3173 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | ||
3174 | |||
3175 | cifs_sb->master_tlink = tlink; | ||
3176 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3177 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | ||
3178 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3179 | |||
3180 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | ||
3181 | TLINK_IDLE_EXPIRE); | ||
3182 | |||
2751 | mount_fail_check: | 3183 | mount_fail_check: |
2752 | /* on error free sesinfo and tcon struct if needed */ | 3184 | /* on error free sesinfo and tcon struct if needed */ |
2753 | if (rc) { | 3185 | if (rc) { |
2754 | if (mount_data != mount_data_global) | ||
2755 | kfree(mount_data); | ||
2756 | /* If find_unc succeeded then rc == 0 so we can not end */ | 3186 | /* If find_unc succeeded then rc == 0 so we can not end */ |
2757 | /* up accidently freeing someone elses tcon struct */ | 3187 | /* up accidentally freeing someone elses tcon struct */ |
2758 | if (tcon) | 3188 | if (tcon) |
2759 | cifs_put_tcon(tcon); | 3189 | cifs_put_tcon(tcon); |
2760 | else if (pSesInfo) | 3190 | else if (pSesInfo) |
2761 | cifs_put_smb_ses(pSesInfo); | 3191 | cifs_put_smb_ses(pSesInfo); |
2762 | else | 3192 | else |
2763 | cifs_put_tcp_session(srvTcp); | 3193 | cifs_put_tcp_session(srvTcp); |
3194 | bdi_destroy(&cifs_sb->bdi); | ||
2764 | goto out; | 3195 | goto out; |
2765 | } | 3196 | } |
2766 | 3197 | ||
@@ -2770,14 +3201,17 @@ mount_fail_check: | |||
2770 | password will be freed at unmount time) */ | 3201 | password will be freed at unmount time) */ |
2771 | out: | 3202 | out: |
2772 | /* zero out password before freeing */ | 3203 | /* zero out password before freeing */ |
2773 | cleanup_volume_info(&volume_info); | ||
2774 | FreeXid(xid); | 3204 | FreeXid(xid); |
2775 | return rc; | 3205 | return rc; |
2776 | } | 3206 | } |
2777 | 3207 | ||
3208 | /* | ||
3209 | * Issue a TREE_CONNECT request. Note that for IPC$ shares, that the tcon | ||
3210 | * pointer may be NULL. | ||
3211 | */ | ||
2778 | int | 3212 | int |
2779 | CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | 3213 | CIFSTCon(unsigned int xid, struct cifs_ses *ses, |
2780 | const char *tree, struct cifsTconInfo *tcon, | 3214 | const char *tree, struct cifs_tcon *tcon, |
2781 | const struct nls_table *nls_codepage) | 3215 | const struct nls_table *nls_codepage) |
2782 | { | 3216 | { |
2783 | struct smb_hdr *smb_buffer; | 3217 | struct smb_hdr *smb_buffer; |
@@ -2786,8 +3220,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2786 | TCONX_RSP *pSMBr; | 3220 | TCONX_RSP *pSMBr; |
2787 | unsigned char *bcc_ptr; | 3221 | unsigned char *bcc_ptr; |
2788 | int rc = 0; | 3222 | int rc = 0; |
2789 | int length, bytes_left; | 3223 | int length; |
2790 | __u16 count; | 3224 | __u16 bytes_left, count; |
2791 | 3225 | ||
2792 | if (ses == NULL) | 3226 | if (ses == NULL) |
2793 | return -EIO; | 3227 | return -EIO; |
@@ -2809,13 +3243,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2809 | pSMB->AndXCommand = 0xFF; | 3243 | pSMB->AndXCommand = 0xFF; |
2810 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); | 3244 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); |
2811 | bcc_ptr = &pSMB->Password[0]; | 3245 | bcc_ptr = &pSMB->Password[0]; |
2812 | if ((ses->server->secMode) & SECMODE_USER) { | 3246 | if (!tcon || (ses->server->sec_mode & SECMODE_USER)) { |
2813 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ | 3247 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ |
2814 | *bcc_ptr = 0; /* password is null byte */ | 3248 | *bcc_ptr = 0; /* password is null byte */ |
2815 | bcc_ptr++; /* skip password */ | 3249 | bcc_ptr++; /* skip password */ |
2816 | /* already aligned so no need to do it below */ | 3250 | /* already aligned so no need to do it below */ |
2817 | } else { | 3251 | } else { |
2818 | pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 3252 | pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
2819 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos | 3253 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos |
2820 | specified as required (when that support is added to | 3254 | specified as required (when that support is added to |
2821 | the vfs in the future) as only NTLM or the much | 3255 | the vfs in the future) as only NTLM or the much |
@@ -2825,16 +3259,16 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2825 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 3259 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
2826 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && | 3260 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && |
2827 | (ses->server->secType == LANMAN)) | 3261 | (ses->server->secType == LANMAN)) |
2828 | calc_lanman_hash(tcon->password, ses->server->cryptKey, | 3262 | calc_lanman_hash(tcon->password, ses->server->cryptkey, |
2829 | ses->server->secMode & | 3263 | ses->server->sec_mode & |
2830 | SECMODE_PW_ENCRYPT ? true : false, | 3264 | SECMODE_PW_ENCRYPT ? true : false, |
2831 | bcc_ptr); | 3265 | bcc_ptr); |
2832 | else | 3266 | else |
2833 | #endif /* CIFS_WEAK_PW_HASH */ | 3267 | #endif /* CIFS_WEAK_PW_HASH */ |
2834 | SMBNTencrypt(tcon->password, ses->server->cryptKey, | 3268 | rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, |
2835 | bcc_ptr); | 3269 | bcc_ptr); |
2836 | 3270 | ||
2837 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 3271 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
2838 | if (ses->capabilities & CAP_UNICODE) { | 3272 | if (ses->capabilities & CAP_UNICODE) { |
2839 | /* must align unicode strings */ | 3273 | /* must align unicode strings */ |
2840 | *bcc_ptr = 0; /* null byte password */ | 3274 | *bcc_ptr = 0; /* null byte password */ |
@@ -2842,7 +3276,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2842 | } | 3276 | } |
2843 | } | 3277 | } |
2844 | 3278 | ||
2845 | if (ses->server->secMode & | 3279 | if (ses->server->sec_mode & |
2846 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 3280 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
2847 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 3281 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
2848 | 3282 | ||
@@ -2868,11 +3302,12 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2868 | bcc_ptr += strlen("?????"); | 3302 | bcc_ptr += strlen("?????"); |
2869 | bcc_ptr += 1; | 3303 | bcc_ptr += 1; |
2870 | count = bcc_ptr - &pSMB->Password[0]; | 3304 | count = bcc_ptr - &pSMB->Password[0]; |
2871 | pSMB->hdr.smb_buf_length += count; | 3305 | pSMB->hdr.smb_buf_length = cpu_to_be32(be32_to_cpu( |
3306 | pSMB->hdr.smb_buf_length) + count); | ||
2872 | pSMB->ByteCount = cpu_to_le16(count); | 3307 | pSMB->ByteCount = cpu_to_le16(count); |
2873 | 3308 | ||
2874 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 3309 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
2875 | CIFS_STD_OP); | 3310 | 0); |
2876 | 3311 | ||
2877 | /* above now done in SendReceive */ | 3312 | /* above now done in SendReceive */ |
2878 | if ((rc == 0) && (tcon != NULL)) { | 3313 | if ((rc == 0) && (tcon != NULL)) { |
@@ -2882,7 +3317,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2882 | tcon->need_reconnect = false; | 3317 | tcon->need_reconnect = false; |
2883 | tcon->tid = smb_buffer_response->Tid; | 3318 | tcon->tid = smb_buffer_response->Tid; |
2884 | bcc_ptr = pByteArea(smb_buffer_response); | 3319 | bcc_ptr = pByteArea(smb_buffer_response); |
2885 | bytes_left = BCC(smb_buffer_response); | 3320 | bytes_left = get_bcc(smb_buffer_response); |
2886 | length = strnlen(bcc_ptr, bytes_left - 2); | 3321 | length = strnlen(bcc_ptr, bytes_left - 2); |
2887 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) | 3322 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) |
2888 | is_unicode = true; | 3323 | is_unicode = true; |
@@ -2931,25 +3366,35 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2931 | return rc; | 3366 | return rc; |
2932 | } | 3367 | } |
2933 | 3368 | ||
2934 | int | 3369 | void |
2935 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3370 | cifs_umount(struct cifs_sb_info *cifs_sb) |
2936 | { | 3371 | { |
2937 | int rc = 0; | 3372 | struct rb_root *root = &cifs_sb->tlink_tree; |
2938 | char *tmp; | 3373 | struct rb_node *node; |
3374 | struct tcon_link *tlink; | ||
2939 | 3375 | ||
2940 | if (cifs_sb->tcon) | 3376 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); |
2941 | cifs_put_tcon(cifs_sb->tcon); | ||
2942 | 3377 | ||
2943 | cifs_sb->tcon = NULL; | 3378 | spin_lock(&cifs_sb->tlink_tree_lock); |
2944 | tmp = cifs_sb->prepath; | 3379 | while ((node = rb_first(root))) { |
2945 | cifs_sb->prepathlen = 0; | 3380 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); |
2946 | cifs_sb->prepath = NULL; | 3381 | cifs_get_tlink(tlink); |
2947 | kfree(tmp); | 3382 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); |
3383 | rb_erase(node, root); | ||
2948 | 3384 | ||
2949 | return rc; | 3385 | spin_unlock(&cifs_sb->tlink_tree_lock); |
3386 | cifs_put_tlink(tlink); | ||
3387 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3388 | } | ||
3389 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3390 | |||
3391 | bdi_destroy(&cifs_sb->bdi); | ||
3392 | kfree(cifs_sb->mountdata); | ||
3393 | unload_nls(cifs_sb->local_nls); | ||
3394 | kfree(cifs_sb); | ||
2950 | } | 3395 | } |
2951 | 3396 | ||
2952 | int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) | 3397 | int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) |
2953 | { | 3398 | { |
2954 | int rc = 0; | 3399 | int rc = 0; |
2955 | struct TCP_Server_Info *server = ses->server; | 3400 | struct TCP_Server_Info *server = ses->server; |
@@ -2967,7 +3412,7 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) | |||
2967 | } | 3412 | } |
2968 | if (rc == 0) { | 3413 | if (rc == 0) { |
2969 | spin_lock(&GlobalMid_Lock); | 3414 | spin_lock(&GlobalMid_Lock); |
2970 | if (server->tcpStatus != CifsExiting) | 3415 | if (server->tcpStatus == CifsNeedNegotiate) |
2971 | server->tcpStatus = CifsGood; | 3416 | server->tcpStatus = CifsGood; |
2972 | else | 3417 | else |
2973 | rc = -EHOSTDOWN; | 3418 | rc = -EHOSTDOWN; |
@@ -2979,7 +3424,7 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) | |||
2979 | } | 3424 | } |
2980 | 3425 | ||
2981 | 3426 | ||
2982 | int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | 3427 | int cifs_setup_session(unsigned int xid, struct cifs_ses *ses, |
2983 | struct nls_table *nls_info) | 3428 | struct nls_table *nls_info) |
2984 | { | 3429 | { |
2985 | int rc = 0; | 3430 | int rc = 0; |
@@ -2991,12 +3436,22 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | |||
2991 | ses->capabilities &= (~CAP_UNIX); | 3436 | ses->capabilities &= (~CAP_UNIX); |
2992 | 3437 | ||
2993 | cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 3438 | cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
2994 | server->secMode, server->capabilities, server->timeAdj); | 3439 | server->sec_mode, server->capabilities, server->timeAdj); |
2995 | 3440 | ||
2996 | rc = CIFS_SessSetup(xid, ses, nls_info); | 3441 | rc = CIFS_SessSetup(xid, ses, nls_info); |
2997 | if (rc) { | 3442 | if (rc) { |
2998 | cERROR(1, "Send error in SessSetup = %d", rc); | 3443 | cERROR(1, "Send error in SessSetup = %d", rc); |
2999 | } else { | 3444 | } else { |
3445 | mutex_lock(&ses->server->srv_mutex); | ||
3446 | if (!server->session_estab) { | ||
3447 | server->session_key.response = ses->auth_key.response; | ||
3448 | server->session_key.len = ses->auth_key.len; | ||
3449 | server->sequence_number = 0x2; | ||
3450 | server->session_estab = true; | ||
3451 | ses->auth_key.response = NULL; | ||
3452 | } | ||
3453 | mutex_unlock(&server->srv_mutex); | ||
3454 | |||
3000 | cFYI(1, "CIFS Session Established successfully"); | 3455 | cFYI(1, "CIFS Session Established successfully"); |
3001 | spin_lock(&GlobalMid_Lock); | 3456 | spin_lock(&GlobalMid_Lock); |
3002 | ses->status = CifsGood; | 3457 | ses->status = CifsGood; |
@@ -3004,6 +3459,259 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | |||
3004 | spin_unlock(&GlobalMid_Lock); | 3459 | spin_unlock(&GlobalMid_Lock); |
3005 | } | 3460 | } |
3006 | 3461 | ||
3462 | kfree(ses->auth_key.response); | ||
3463 | ses->auth_key.response = NULL; | ||
3464 | ses->auth_key.len = 0; | ||
3465 | kfree(ses->ntlmssp); | ||
3466 | ses->ntlmssp = NULL; | ||
3467 | |||
3007 | return rc; | 3468 | return rc; |
3008 | } | 3469 | } |
3009 | 3470 | ||
3471 | static struct cifs_tcon * | ||
3472 | cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) | ||
3473 | { | ||
3474 | struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); | ||
3475 | struct cifs_ses *ses; | ||
3476 | struct cifs_tcon *tcon = NULL; | ||
3477 | struct smb_vol *vol_info; | ||
3478 | char username[28]; /* big enough for "krb50x" + hex of ULONG_MAX 6+16 */ | ||
3479 | /* We used to have this as MAX_USERNAME which is */ | ||
3480 | /* way too big now (256 instead of 32) */ | ||
3481 | |||
3482 | vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); | ||
3483 | if (vol_info == NULL) { | ||
3484 | tcon = ERR_PTR(-ENOMEM); | ||
3485 | goto out; | ||
3486 | } | ||
3487 | |||
3488 | snprintf(username, sizeof(username), "krb50x%x", fsuid); | ||
3489 | vol_info->username = username; | ||
3490 | vol_info->local_nls = cifs_sb->local_nls; | ||
3491 | vol_info->linux_uid = fsuid; | ||
3492 | vol_info->cred_uid = fsuid; | ||
3493 | vol_info->UNC = master_tcon->treeName; | ||
3494 | vol_info->retry = master_tcon->retry; | ||
3495 | vol_info->nocase = master_tcon->nocase; | ||
3496 | vol_info->local_lease = master_tcon->local_lease; | ||
3497 | vol_info->no_linux_ext = !master_tcon->unix_ext; | ||
3498 | |||
3499 | /* FIXME: allow for other secFlg settings */ | ||
3500 | vol_info->secFlg = CIFSSEC_MUST_KRB5; | ||
3501 | |||
3502 | /* get a reference for the same TCP session */ | ||
3503 | spin_lock(&cifs_tcp_ses_lock); | ||
3504 | ++master_tcon->ses->server->srv_count; | ||
3505 | spin_unlock(&cifs_tcp_ses_lock); | ||
3506 | |||
3507 | ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); | ||
3508 | if (IS_ERR(ses)) { | ||
3509 | tcon = (struct cifs_tcon *)ses; | ||
3510 | cifs_put_tcp_session(master_tcon->ses->server); | ||
3511 | goto out; | ||
3512 | } | ||
3513 | |||
3514 | tcon = cifs_get_tcon(ses, vol_info); | ||
3515 | if (IS_ERR(tcon)) { | ||
3516 | cifs_put_smb_ses(ses); | ||
3517 | goto out; | ||
3518 | } | ||
3519 | |||
3520 | if (ses->capabilities & CAP_UNIX) | ||
3521 | reset_cifs_unix_caps(0, tcon, NULL, vol_info); | ||
3522 | out: | ||
3523 | kfree(vol_info); | ||
3524 | |||
3525 | return tcon; | ||
3526 | } | ||
3527 | |||
3528 | struct cifs_tcon * | ||
3529 | cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) | ||
3530 | { | ||
3531 | return tlink_tcon(cifs_sb_master_tlink(cifs_sb)); | ||
3532 | } | ||
3533 | |||
3534 | static int | ||
3535 | cifs_sb_tcon_pending_wait(void *unused) | ||
3536 | { | ||
3537 | schedule(); | ||
3538 | return signal_pending(current) ? -ERESTARTSYS : 0; | ||
3539 | } | ||
3540 | |||
3541 | /* find and return a tlink with given uid */ | ||
3542 | static struct tcon_link * | ||
3543 | tlink_rb_search(struct rb_root *root, uid_t uid) | ||
3544 | { | ||
3545 | struct rb_node *node = root->rb_node; | ||
3546 | struct tcon_link *tlink; | ||
3547 | |||
3548 | while (node) { | ||
3549 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | ||
3550 | |||
3551 | if (tlink->tl_uid > uid) | ||
3552 | node = node->rb_left; | ||
3553 | else if (tlink->tl_uid < uid) | ||
3554 | node = node->rb_right; | ||
3555 | else | ||
3556 | return tlink; | ||
3557 | } | ||
3558 | return NULL; | ||
3559 | } | ||
3560 | |||
3561 | /* insert a tcon_link into the tree */ | ||
3562 | static void | ||
3563 | tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) | ||
3564 | { | ||
3565 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
3566 | struct tcon_link *tlink; | ||
3567 | |||
3568 | while (*new) { | ||
3569 | tlink = rb_entry(*new, struct tcon_link, tl_rbnode); | ||
3570 | parent = *new; | ||
3571 | |||
3572 | if (tlink->tl_uid > new_tlink->tl_uid) | ||
3573 | new = &((*new)->rb_left); | ||
3574 | else | ||
3575 | new = &((*new)->rb_right); | ||
3576 | } | ||
3577 | |||
3578 | rb_link_node(&new_tlink->tl_rbnode, parent, new); | ||
3579 | rb_insert_color(&new_tlink->tl_rbnode, root); | ||
3580 | } | ||
3581 | |||
3582 | /* | ||
3583 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the | ||
3584 | * current task. | ||
3585 | * | ||
3586 | * If the superblock doesn't refer to a multiuser mount, then just return | ||
3587 | * the master tcon for the mount. | ||
3588 | * | ||
3589 | * First, search the rbtree for an existing tcon for this fsuid. If one | ||
3590 | * exists, then check to see if it's pending construction. If it is then wait | ||
3591 | * for construction to complete. Once it's no longer pending, check to see if | ||
3592 | * it failed and either return an error or retry construction, depending on | ||
3593 | * the timeout. | ||
3594 | * | ||
3595 | * If one doesn't exist then insert a new tcon_link struct into the tree and | ||
3596 | * try to construct a new one. | ||
3597 | */ | ||
3598 | struct tcon_link * | ||
3599 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | ||
3600 | { | ||
3601 | int ret; | ||
3602 | uid_t fsuid = current_fsuid(); | ||
3603 | struct tcon_link *tlink, *newtlink; | ||
3604 | |||
3605 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | ||
3606 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | ||
3607 | |||
3608 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3609 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); | ||
3610 | if (tlink) | ||
3611 | cifs_get_tlink(tlink); | ||
3612 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3613 | |||
3614 | if (tlink == NULL) { | ||
3615 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | ||
3616 | if (newtlink == NULL) | ||
3617 | return ERR_PTR(-ENOMEM); | ||
3618 | newtlink->tl_uid = fsuid; | ||
3619 | newtlink->tl_tcon = ERR_PTR(-EACCES); | ||
3620 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); | ||
3621 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); | ||
3622 | cifs_get_tlink(newtlink); | ||
3623 | |||
3624 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3625 | /* was one inserted after previous search? */ | ||
3626 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); | ||
3627 | if (tlink) { | ||
3628 | cifs_get_tlink(tlink); | ||
3629 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3630 | kfree(newtlink); | ||
3631 | goto wait_for_construction; | ||
3632 | } | ||
3633 | tlink = newtlink; | ||
3634 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | ||
3635 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3636 | } else { | ||
3637 | wait_for_construction: | ||
3638 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, | ||
3639 | cifs_sb_tcon_pending_wait, | ||
3640 | TASK_INTERRUPTIBLE); | ||
3641 | if (ret) { | ||
3642 | cifs_put_tlink(tlink); | ||
3643 | return ERR_PTR(ret); | ||
3644 | } | ||
3645 | |||
3646 | /* if it's good, return it */ | ||
3647 | if (!IS_ERR(tlink->tl_tcon)) | ||
3648 | return tlink; | ||
3649 | |||
3650 | /* return error if we tried this already recently */ | ||
3651 | if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) { | ||
3652 | cifs_put_tlink(tlink); | ||
3653 | return ERR_PTR(-EACCES); | ||
3654 | } | ||
3655 | |||
3656 | if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags)) | ||
3657 | goto wait_for_construction; | ||
3658 | } | ||
3659 | |||
3660 | tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid); | ||
3661 | clear_bit(TCON_LINK_PENDING, &tlink->tl_flags); | ||
3662 | wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING); | ||
3663 | |||
3664 | if (IS_ERR(tlink->tl_tcon)) { | ||
3665 | cifs_put_tlink(tlink); | ||
3666 | return ERR_PTR(-EACCES); | ||
3667 | } | ||
3668 | |||
3669 | return tlink; | ||
3670 | } | ||
3671 | |||
3672 | /* | ||
3673 | * periodic workqueue job that scans tcon_tree for a superblock and closes | ||
3674 | * out tcons. | ||
3675 | */ | ||
3676 | static void | ||
3677 | cifs_prune_tlinks(struct work_struct *work) | ||
3678 | { | ||
3679 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, | ||
3680 | prune_tlinks.work); | ||
3681 | struct rb_root *root = &cifs_sb->tlink_tree; | ||
3682 | struct rb_node *node = rb_first(root); | ||
3683 | struct rb_node *tmp; | ||
3684 | struct tcon_link *tlink; | ||
3685 | |||
3686 | /* | ||
3687 | * Because we drop the spinlock in the loop in order to put the tlink | ||
3688 | * it's not guarded against removal of links from the tree. The only | ||
3689 | * places that remove entries from the tree are this function and | ||
3690 | * umounts. Because this function is non-reentrant and is canceled | ||
3691 | * before umount can proceed, this is safe. | ||
3692 | */ | ||
3693 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3694 | node = rb_first(root); | ||
3695 | while (node != NULL) { | ||
3696 | tmp = node; | ||
3697 | node = rb_next(tmp); | ||
3698 | tlink = rb_entry(tmp, struct tcon_link, tl_rbnode); | ||
3699 | |||
3700 | if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) || | ||
3701 | atomic_read(&tlink->tl_count) != 0 || | ||
3702 | time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies)) | ||
3703 | continue; | ||
3704 | |||
3705 | cifs_get_tlink(tlink); | ||
3706 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | ||
3707 | rb_erase(tmp, root); | ||
3708 | |||
3709 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3710 | cifs_put_tlink(tlink); | ||
3711 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3712 | } | ||
3713 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3714 | |||
3715 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | ||
3716 | TLINK_IDLE_EXPIRE); | ||
3717 | } | ||
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f9ed0751cc12..fa8c21d913bc 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -50,42 +50,48 @@ build_path_from_dentry(struct dentry *direntry) | |||
50 | { | 50 | { |
51 | struct dentry *temp; | 51 | struct dentry *temp; |
52 | int namelen; | 52 | int namelen; |
53 | int pplen; | ||
54 | int dfsplen; | 53 | int dfsplen; |
55 | char *full_path; | 54 | char *full_path; |
56 | char dirsep; | 55 | char dirsep; |
57 | struct cifs_sb_info *cifs_sb; | 56 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); |
57 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | ||
58 | unsigned seq; | ||
58 | 59 | ||
59 | if (direntry == NULL) | 60 | if (direntry == NULL) |
60 | return NULL; /* not much we can do if dentry is freed and | 61 | return NULL; /* not much we can do if dentry is freed and |
61 | we need to reopen the file after it was closed implicitly | 62 | we need to reopen the file after it was closed implicitly |
62 | when the server crashed */ | 63 | when the server crashed */ |
63 | 64 | ||
64 | cifs_sb = CIFS_SB(direntry->d_sb); | ||
65 | dirsep = CIFS_DIR_SEP(cifs_sb); | 65 | dirsep = CIFS_DIR_SEP(cifs_sb); |
66 | pplen = cifs_sb->prepathlen; | 66 | if (tcon->Flags & SMB_SHARE_IS_IN_DFS) |
67 | if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) | 67 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); |
68 | dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); | ||
69 | else | 68 | else |
70 | dfsplen = 0; | 69 | dfsplen = 0; |
71 | cifs_bp_rename_retry: | 70 | cifs_bp_rename_retry: |
72 | namelen = pplen + dfsplen; | 71 | namelen = dfsplen; |
72 | seq = read_seqbegin(&rename_lock); | ||
73 | rcu_read_lock(); | ||
73 | for (temp = direntry; !IS_ROOT(temp);) { | 74 | for (temp = direntry; !IS_ROOT(temp);) { |
74 | namelen += (1 + temp->d_name.len); | 75 | namelen += (1 + temp->d_name.len); |
75 | temp = temp->d_parent; | 76 | temp = temp->d_parent; |
76 | if (temp == NULL) { | 77 | if (temp == NULL) { |
77 | cERROR(1, "corrupt dentry"); | 78 | cERROR(1, "corrupt dentry"); |
79 | rcu_read_unlock(); | ||
78 | return NULL; | 80 | return NULL; |
79 | } | 81 | } |
80 | } | 82 | } |
83 | rcu_read_unlock(); | ||
81 | 84 | ||
82 | full_path = kmalloc(namelen+1, GFP_KERNEL); | 85 | full_path = kmalloc(namelen+1, GFP_KERNEL); |
83 | if (full_path == NULL) | 86 | if (full_path == NULL) |
84 | return full_path; | 87 | return full_path; |
85 | full_path[namelen] = 0; /* trailing null */ | 88 | full_path[namelen] = 0; /* trailing null */ |
89 | rcu_read_lock(); | ||
86 | for (temp = direntry; !IS_ROOT(temp);) { | 90 | for (temp = direntry; !IS_ROOT(temp);) { |
91 | spin_lock(&temp->d_lock); | ||
87 | namelen -= 1 + temp->d_name.len; | 92 | namelen -= 1 + temp->d_name.len; |
88 | if (namelen < 0) { | 93 | if (namelen < 0) { |
94 | spin_unlock(&temp->d_lock); | ||
89 | break; | 95 | break; |
90 | } else { | 96 | } else { |
91 | full_path[namelen] = dirsep; | 97 | full_path[namelen] = dirsep; |
@@ -93,14 +99,17 @@ cifs_bp_rename_retry: | |||
93 | temp->d_name.len); | 99 | temp->d_name.len); |
94 | cFYI(0, "name: %s", full_path + namelen); | 100 | cFYI(0, "name: %s", full_path + namelen); |
95 | } | 101 | } |
102 | spin_unlock(&temp->d_lock); | ||
96 | temp = temp->d_parent; | 103 | temp = temp->d_parent; |
97 | if (temp == NULL) { | 104 | if (temp == NULL) { |
98 | cERROR(1, "corrupt dentry"); | 105 | cERROR(1, "corrupt dentry"); |
106 | rcu_read_unlock(); | ||
99 | kfree(full_path); | 107 | kfree(full_path); |
100 | return NULL; | 108 | return NULL; |
101 | } | 109 | } |
102 | } | 110 | } |
103 | if (namelen != pplen + dfsplen) { | 111 | rcu_read_unlock(); |
112 | if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { | ||
104 | cERROR(1, "did not end path lookup where expected namelen is %d", | 113 | cERROR(1, "did not end path lookup where expected namelen is %d", |
105 | namelen); | 114 | namelen); |
106 | /* presumably this is only possible if racing with a rename | 115 | /* presumably this is only possible if racing with a rename |
@@ -117,7 +126,7 @@ cifs_bp_rename_retry: | |||
117 | /* BB test paths to Windows with '/' in the midst of prepath */ | 126 | /* BB test paths to Windows with '/' in the midst of prepath */ |
118 | 127 | ||
119 | if (dfsplen) { | 128 | if (dfsplen) { |
120 | strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); | 129 | strncpy(full_path, tcon->treeName, dfsplen); |
121 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | 130 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { |
122 | int i; | 131 | int i; |
123 | for (i = 0; i < dfsplen; i++) { | 132 | for (i = 0; i < dfsplen; i++) { |
@@ -126,150 +135,9 @@ cifs_bp_rename_retry: | |||
126 | } | 135 | } |
127 | } | 136 | } |
128 | } | 137 | } |
129 | strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen); | ||
130 | return full_path; | 138 | return full_path; |
131 | } | 139 | } |
132 | 140 | ||
133 | struct cifsFileInfo * | ||
134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | ||
135 | struct file *file, struct vfsmount *mnt, unsigned int oflags) | ||
136 | { | ||
137 | int oplock = 0; | ||
138 | struct cifsFileInfo *pCifsFile; | ||
139 | struct cifsInodeInfo *pCifsInode; | ||
140 | struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); | ||
141 | |||
142 | pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
143 | if (pCifsFile == NULL) | ||
144 | return pCifsFile; | ||
145 | |||
146 | if (oplockEnabled) | ||
147 | oplock = REQ_OPLOCK; | ||
148 | |||
149 | pCifsFile->netfid = fileHandle; | ||
150 | pCifsFile->pid = current->tgid; | ||
151 | pCifsFile->pInode = igrab(newinode); | ||
152 | pCifsFile->mnt = mnt; | ||
153 | pCifsFile->pfile = file; | ||
154 | pCifsFile->invalidHandle = false; | ||
155 | pCifsFile->closePend = false; | ||
156 | mutex_init(&pCifsFile->fh_mutex); | ||
157 | mutex_init(&pCifsFile->lock_mutex); | ||
158 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
159 | atomic_set(&pCifsFile->count, 1); | ||
160 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); | ||
161 | |||
162 | write_lock(&GlobalSMBSeslock); | ||
163 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | ||
164 | pCifsInode = CIFS_I(newinode); | ||
165 | if (pCifsInode) { | ||
166 | /* if readable file instance put first in list*/ | ||
167 | if (oflags & FMODE_READ) | ||
168 | list_add(&pCifsFile->flist, &pCifsInode->openFileList); | ||
169 | else | ||
170 | list_add_tail(&pCifsFile->flist, | ||
171 | &pCifsInode->openFileList); | ||
172 | |||
173 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
174 | pCifsInode->clientCanCacheAll = true; | ||
175 | pCifsInode->clientCanCacheRead = true; | ||
176 | cFYI(1, "Exclusive Oplock inode %p", newinode); | ||
177 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
178 | pCifsInode->clientCanCacheRead = true; | ||
179 | } | ||
180 | write_unlock(&GlobalSMBSeslock); | ||
181 | |||
182 | file->private_data = pCifsFile; | ||
183 | |||
184 | return pCifsFile; | ||
185 | } | ||
186 | |||
187 | int cifs_posix_open(char *full_path, struct inode **pinode, | ||
188 | struct super_block *sb, int mode, int oflags, | ||
189 | __u32 *poplock, __u16 *pnetfid, int xid) | ||
190 | { | ||
191 | int rc; | ||
192 | FILE_UNIX_BASIC_INFO *presp_data; | ||
193 | __u32 posix_flags = 0; | ||
194 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
195 | struct cifs_fattr fattr; | ||
196 | |||
197 | cFYI(1, "posix open %s", full_path); | ||
198 | |||
199 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
200 | if (presp_data == NULL) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | /* So far cifs posix extensions can only map the following flags. | ||
204 | There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but | ||
205 | so far we do not seem to need them, and we can treat them as local only */ | ||
206 | if ((oflags & (FMODE_READ | FMODE_WRITE)) == | ||
207 | (FMODE_READ | FMODE_WRITE)) | ||
208 | posix_flags = SMB_O_RDWR; | ||
209 | else if (oflags & FMODE_READ) | ||
210 | posix_flags = SMB_O_RDONLY; | ||
211 | else if (oflags & FMODE_WRITE) | ||
212 | posix_flags = SMB_O_WRONLY; | ||
213 | if (oflags & O_CREAT) | ||
214 | posix_flags |= SMB_O_CREAT; | ||
215 | if (oflags & O_EXCL) | ||
216 | posix_flags |= SMB_O_EXCL; | ||
217 | if (oflags & O_TRUNC) | ||
218 | posix_flags |= SMB_O_TRUNC; | ||
219 | /* be safe and imply O_SYNC for O_DSYNC */ | ||
220 | if (oflags & O_DSYNC) | ||
221 | posix_flags |= SMB_O_SYNC; | ||
222 | if (oflags & O_DIRECTORY) | ||
223 | posix_flags |= SMB_O_DIRECTORY; | ||
224 | if (oflags & O_NOFOLLOW) | ||
225 | posix_flags |= SMB_O_NOFOLLOW; | ||
226 | if (oflags & O_DIRECT) | ||
227 | posix_flags |= SMB_O_DIRECT; | ||
228 | |||
229 | mode &= ~current_umask(); | ||
230 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, | ||
231 | pnetfid, presp_data, poplock, full_path, | ||
232 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
233 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
234 | if (rc) | ||
235 | goto posix_open_ret; | ||
236 | |||
237 | if (presp_data->Type == cpu_to_le32(-1)) | ||
238 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | ||
239 | |||
240 | if (!pinode) | ||
241 | goto posix_open_ret; /* caller does not need info */ | ||
242 | |||
243 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
244 | |||
245 | /* get new inode and set it up */ | ||
246 | if (*pinode == NULL) { | ||
247 | cifs_fill_uniqueid(sb, &fattr); | ||
248 | *pinode = cifs_iget(sb, &fattr); | ||
249 | if (!*pinode) { | ||
250 | rc = -ENOMEM; | ||
251 | goto posix_open_ret; | ||
252 | } | ||
253 | } else { | ||
254 | cifs_fattr_to_inode(*pinode, &fattr); | ||
255 | } | ||
256 | |||
257 | posix_open_ret: | ||
258 | kfree(presp_data); | ||
259 | return rc; | ||
260 | } | ||
261 | |||
262 | static void setup_cifs_dentry(struct cifsTconInfo *tcon, | ||
263 | struct dentry *direntry, | ||
264 | struct inode *newinode) | ||
265 | { | ||
266 | if (tcon->nocase) | ||
267 | direntry->d_op = &cifs_ci_dentry_ops; | ||
268 | else | ||
269 | direntry->d_op = &cifs_dentry_ops; | ||
270 | d_instantiate(direntry, newinode); | ||
271 | } | ||
272 | |||
273 | /* Inode operations in similar order to how they appear in Linux file fs.h */ | 141 | /* Inode operations in similar order to how they appear in Linux file fs.h */ |
274 | 142 | ||
275 | int | 143 | int |
@@ -291,7 +159,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
291 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; | 159 | int desiredAccess = GENERIC_READ | GENERIC_WRITE; |
292 | __u16 fileHandle; | 160 | __u16 fileHandle; |
293 | struct cifs_sb_info *cifs_sb; | 161 | struct cifs_sb_info *cifs_sb; |
294 | struct cifsTconInfo *tcon; | 162 | struct tcon_link *tlink; |
163 | struct cifs_tcon *tcon; | ||
295 | char *full_path = NULL; | 164 | char *full_path = NULL; |
296 | FILE_ALL_INFO *buf = NULL; | 165 | FILE_ALL_INFO *buf = NULL; |
297 | struct inode *newinode = NULL; | 166 | struct inode *newinode = NULL; |
@@ -300,21 +169,26 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
300 | xid = GetXid(); | 169 | xid = GetXid(); |
301 | 170 | ||
302 | cifs_sb = CIFS_SB(inode->i_sb); | 171 | cifs_sb = CIFS_SB(inode->i_sb); |
303 | tcon = cifs_sb->tcon; | 172 | tlink = cifs_sb_tlink(cifs_sb); |
304 | 173 | if (IS_ERR(tlink)) { | |
305 | full_path = build_path_from_dentry(direntry); | 174 | FreeXid(xid); |
306 | if (full_path == NULL) { | 175 | return PTR_ERR(tlink); |
307 | rc = -ENOMEM; | ||
308 | goto cifs_create_out; | ||
309 | } | 176 | } |
177 | tcon = tlink_tcon(tlink); | ||
310 | 178 | ||
311 | if (oplockEnabled) | 179 | if (oplockEnabled) |
312 | oplock = REQ_OPLOCK; | 180 | oplock = REQ_OPLOCK; |
313 | 181 | ||
314 | if (nd && (nd->flags & LOOKUP_OPEN)) | 182 | if (nd && (nd->flags & LOOKUP_OPEN)) |
315 | oflags = nd->intent.open.flags; | 183 | oflags = nd->intent.open.file->f_flags; |
316 | else | 184 | else |
317 | oflags = FMODE_READ | SMB_O_CREAT; | 185 | oflags = O_RDONLY | O_CREAT; |
186 | |||
187 | full_path = build_path_from_dentry(direntry); | ||
188 | if (full_path == NULL) { | ||
189 | rc = -ENOMEM; | ||
190 | goto cifs_create_out; | ||
191 | } | ||
318 | 192 | ||
319 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 193 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
320 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 194 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
@@ -323,7 +197,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
323 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); | 197 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); |
324 | /* EIO could indicate that (posix open) operation is not | 198 | /* EIO could indicate that (posix open) operation is not |
325 | supported, despite what server claimed in capability | 199 | supported, despite what server claimed in capability |
326 | negotation. EREMOTE indicates DFS junction, which is not | 200 | negotiation. EREMOTE indicates DFS junction, which is not |
327 | handled in posix open */ | 201 | handled in posix open */ |
328 | 202 | ||
329 | if (rc == 0) { | 203 | if (rc == 0) { |
@@ -344,9 +218,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
344 | /* if the file is going to stay open, then we | 218 | /* if the file is going to stay open, then we |
345 | need to set the desired access properly */ | 219 | need to set the desired access properly */ |
346 | desiredAccess = 0; | 220 | desiredAccess = 0; |
347 | if (oflags & FMODE_READ) | 221 | if (OPEN_FMODE(oflags) & FMODE_READ) |
348 | desiredAccess |= GENERIC_READ; /* is this too little? */ | 222 | desiredAccess |= GENERIC_READ; /* is this too little? */ |
349 | if (oflags & FMODE_WRITE) | 223 | if (OPEN_FMODE(oflags) & FMODE_WRITE) |
350 | desiredAccess |= GENERIC_WRITE; | 224 | desiredAccess |= GENERIC_WRITE; |
351 | 225 | ||
352 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | 226 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) |
@@ -375,7 +249,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
375 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0) | 249 | if (!tcon->unix_ext && (mode & S_IWUGO) == 0) |
376 | create_options |= CREATE_OPTION_READONLY; | 250 | create_options |= CREATE_OPTION_READONLY; |
377 | 251 | ||
378 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) | 252 | if (tcon->ses->capabilities & CAP_NT_SMBS) |
379 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | 253 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
380 | desiredAccess, create_options, | 254 | desiredAccess, create_options, |
381 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 255 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
@@ -416,10 +290,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
416 | args.uid = NO_CHANGE_64; | 290 | args.uid = NO_CHANGE_64; |
417 | args.gid = NO_CHANGE_64; | 291 | args.gid = NO_CHANGE_64; |
418 | } | 292 | } |
419 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 293 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, |
420 | cifs_sb->local_nls, | 294 | current->tgid); |
421 | cifs_sb->mnt_cifs_flags & | ||
422 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
423 | } else { | 295 | } else { |
424 | /* BB implement mode setting via Windows security | 296 | /* BB implement mode setting via Windows security |
425 | descriptors e.g. */ | 297 | descriptors e.g. */ |
@@ -452,7 +324,7 @@ cifs_create_get_file_info: | |||
452 | 324 | ||
453 | cifs_create_set_dentry: | 325 | cifs_create_set_dentry: |
454 | if (rc == 0) | 326 | if (rc == 0) |
455 | setup_cifs_dentry(tcon, direntry, newinode); | 327 | d_instantiate(direntry, newinode); |
456 | else | 328 | else |
457 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 329 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
458 | 330 | ||
@@ -467,8 +339,7 @@ cifs_create_set_dentry: | |||
467 | goto cifs_create_out; | 339 | goto cifs_create_out; |
468 | } | 340 | } |
469 | 341 | ||
470 | pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, | 342 | pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); |
471 | nd->path.mnt, oflags); | ||
472 | if (pfile_info == NULL) { | 343 | if (pfile_info == NULL) { |
473 | fput(filp); | 344 | fput(filp); |
474 | CIFSSMBClose(xid, tcon, fileHandle); | 345 | CIFSSMBClose(xid, tcon, fileHandle); |
@@ -481,6 +352,7 @@ cifs_create_set_dentry: | |||
481 | cifs_create_out: | 352 | cifs_create_out: |
482 | kfree(buf); | 353 | kfree(buf); |
483 | kfree(full_path); | 354 | kfree(full_path); |
355 | cifs_put_tlink(tlink); | ||
484 | FreeXid(xid); | 356 | FreeXid(xid); |
485 | return rc; | 357 | return rc; |
486 | } | 358 | } |
@@ -491,7 +363,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
491 | int rc = -EPERM; | 363 | int rc = -EPERM; |
492 | int xid; | 364 | int xid; |
493 | struct cifs_sb_info *cifs_sb; | 365 | struct cifs_sb_info *cifs_sb; |
494 | struct cifsTconInfo *pTcon; | 366 | struct tcon_link *tlink; |
367 | struct cifs_tcon *pTcon; | ||
368 | struct cifs_io_parms io_parms; | ||
495 | char *full_path = NULL; | 369 | char *full_path = NULL; |
496 | struct inode *newinode = NULL; | 370 | struct inode *newinode = NULL; |
497 | int oplock = 0; | 371 | int oplock = 0; |
@@ -503,10 +377,14 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
503 | if (!old_valid_dev(device_number)) | 377 | if (!old_valid_dev(device_number)) |
504 | return -EINVAL; | 378 | return -EINVAL; |
505 | 379 | ||
506 | xid = GetXid(); | ||
507 | |||
508 | cifs_sb = CIFS_SB(inode->i_sb); | 380 | cifs_sb = CIFS_SB(inode->i_sb); |
509 | pTcon = cifs_sb->tcon; | 381 | tlink = cifs_sb_tlink(cifs_sb); |
382 | if (IS_ERR(tlink)) | ||
383 | return PTR_ERR(tlink); | ||
384 | |||
385 | pTcon = tlink_tcon(tlink); | ||
386 | |||
387 | xid = GetXid(); | ||
510 | 388 | ||
511 | full_path = build_path_from_dentry(direntry); | 389 | full_path = build_path_from_dentry(direntry); |
512 | if (full_path == NULL) { | 390 | if (full_path == NULL) { |
@@ -538,10 +416,6 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
538 | 416 | ||
539 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 417 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
540 | inode->i_sb, xid); | 418 | inode->i_sb, xid); |
541 | if (pTcon->nocase) | ||
542 | direntry->d_op = &cifs_ci_dentry_ops; | ||
543 | else | ||
544 | direntry->d_op = &cifs_dentry_ops; | ||
545 | 419 | ||
546 | if (rc == 0) | 420 | if (rc == 0) |
547 | d_instantiate(direntry, newinode); | 421 | d_instantiate(direntry, newinode); |
@@ -574,16 +448,19 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
574 | * timestamps in, but we can reuse it safely */ | 448 | * timestamps in, but we can reuse it safely */ |
575 | 449 | ||
576 | pdev = (struct win_dev *)buf; | 450 | pdev = (struct win_dev *)buf; |
451 | io_parms.netfid = fileHandle; | ||
452 | io_parms.pid = current->tgid; | ||
453 | io_parms.tcon = pTcon; | ||
454 | io_parms.offset = 0; | ||
455 | io_parms.length = sizeof(struct win_dev); | ||
577 | if (S_ISCHR(mode)) { | 456 | if (S_ISCHR(mode)) { |
578 | memcpy(pdev->type, "IntxCHR", 8); | 457 | memcpy(pdev->type, "IntxCHR", 8); |
579 | pdev->major = | 458 | pdev->major = |
580 | cpu_to_le64(MAJOR(device_number)); | 459 | cpu_to_le64(MAJOR(device_number)); |
581 | pdev->minor = | 460 | pdev->minor = |
582 | cpu_to_le64(MINOR(device_number)); | 461 | cpu_to_le64(MINOR(device_number)); |
583 | rc = CIFSSMBWrite(xid, pTcon, | 462 | rc = CIFSSMBWrite(xid, &io_parms, |
584 | fileHandle, | 463 | &bytes_written, (char *)pdev, |
585 | sizeof(struct win_dev), | ||
586 | 0, &bytes_written, (char *)pdev, | ||
587 | NULL, 0); | 464 | NULL, 0); |
588 | } else if (S_ISBLK(mode)) { | 465 | } else if (S_ISBLK(mode)) { |
589 | memcpy(pdev->type, "IntxBLK", 8); | 466 | memcpy(pdev->type, "IntxBLK", 8); |
@@ -591,10 +468,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
591 | cpu_to_le64(MAJOR(device_number)); | 468 | cpu_to_le64(MAJOR(device_number)); |
592 | pdev->minor = | 469 | pdev->minor = |
593 | cpu_to_le64(MINOR(device_number)); | 470 | cpu_to_le64(MINOR(device_number)); |
594 | rc = CIFSSMBWrite(xid, pTcon, | 471 | rc = CIFSSMBWrite(xid, &io_parms, |
595 | fileHandle, | 472 | &bytes_written, (char *)pdev, |
596 | sizeof(struct win_dev), | ||
597 | 0, &bytes_written, (char *)pdev, | ||
598 | NULL, 0); | 473 | NULL, 0); |
599 | } /* else if (S_ISFIFO) */ | 474 | } /* else if (S_ISFIFO) */ |
600 | CIFSSMBClose(xid, pTcon, fileHandle); | 475 | CIFSSMBClose(xid, pTcon, fileHandle); |
@@ -606,6 +481,7 @@ mknod_out: | |||
606 | kfree(full_path); | 481 | kfree(full_path); |
607 | kfree(buf); | 482 | kfree(buf); |
608 | FreeXid(xid); | 483 | FreeXid(xid); |
484 | cifs_put_tlink(tlink); | ||
609 | return rc; | 485 | return rc; |
610 | } | 486 | } |
611 | 487 | ||
@@ -619,7 +495,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
619 | __u16 fileHandle = 0; | 495 | __u16 fileHandle = 0; |
620 | bool posix_open = false; | 496 | bool posix_open = false; |
621 | struct cifs_sb_info *cifs_sb; | 497 | struct cifs_sb_info *cifs_sb; |
622 | struct cifsTconInfo *pTcon; | 498 | struct tcon_link *tlink; |
499 | struct cifs_tcon *pTcon; | ||
623 | struct cifsFileInfo *cfile; | 500 | struct cifsFileInfo *cfile; |
624 | struct inode *newInode = NULL; | 501 | struct inode *newInode = NULL; |
625 | char *full_path = NULL; | 502 | char *full_path = NULL; |
@@ -633,7 +510,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
633 | /* check whether path exists */ | 510 | /* check whether path exists */ |
634 | 511 | ||
635 | cifs_sb = CIFS_SB(parent_dir_inode->i_sb); | 512 | cifs_sb = CIFS_SB(parent_dir_inode->i_sb); |
636 | pTcon = cifs_sb->tcon; | 513 | tlink = cifs_sb_tlink(cifs_sb); |
514 | if (IS_ERR(tlink)) { | ||
515 | FreeXid(xid); | ||
516 | return (struct dentry *)tlink; | ||
517 | } | ||
518 | pTcon = tlink_tcon(tlink); | ||
637 | 519 | ||
638 | /* | 520 | /* |
639 | * Don't allow the separator character in a path component. | 521 | * Don't allow the separator character in a path component. |
@@ -644,8 +526,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
644 | for (i = 0; i < direntry->d_name.len; i++) | 526 | for (i = 0; i < direntry->d_name.len; i++) |
645 | if (direntry->d_name.name[i] == '\\') { | 527 | if (direntry->d_name.name[i] == '\\') { |
646 | cFYI(1, "Invalid file name"); | 528 | cFYI(1, "Invalid file name"); |
647 | FreeXid(xid); | 529 | rc = -EINVAL; |
648 | return ERR_PTR(-EINVAL); | 530 | goto lookup_out; |
649 | } | 531 | } |
650 | } | 532 | } |
651 | 533 | ||
@@ -655,7 +537,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
655 | */ | 537 | */ |
656 | if (nd && (nd->flags & LOOKUP_EXCL)) { | 538 | if (nd && (nd->flags & LOOKUP_EXCL)) { |
657 | d_instantiate(direntry, NULL); | 539 | d_instantiate(direntry, NULL); |
658 | return NULL; | 540 | rc = 0; |
541 | goto lookup_out; | ||
659 | } | 542 | } |
660 | 543 | ||
661 | /* can not grab the rename sem here since it would | 544 | /* can not grab the rename sem here since it would |
@@ -663,8 +546,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
663 | in which we already have the sb rename sem */ | 546 | in which we already have the sb rename sem */ |
664 | full_path = build_path_from_dentry(direntry); | 547 | full_path = build_path_from_dentry(direntry); |
665 | if (full_path == NULL) { | 548 | if (full_path == NULL) { |
666 | FreeXid(xid); | 549 | rc = -ENOMEM; |
667 | return ERR_PTR(-ENOMEM); | 550 | goto lookup_out; |
668 | } | 551 | } |
669 | 552 | ||
670 | if (direntry->d_inode != NULL) { | 553 | if (direntry->d_inode != NULL) { |
@@ -687,11 +570,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
687 | if (pTcon->unix_ext) { | 570 | if (pTcon->unix_ext) { |
688 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 571 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
689 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 572 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
690 | (nd->intent.open.flags & O_CREAT)) { | 573 | (nd->intent.open.file->f_flags & O_CREAT)) { |
691 | rc = cifs_posix_open(full_path, &newInode, | 574 | rc = cifs_posix_open(full_path, &newInode, |
692 | parent_dir_inode->i_sb, | 575 | parent_dir_inode->i_sb, |
693 | nd->intent.open.create_mode, | 576 | nd->intent.open.create_mode, |
694 | nd->intent.open.flags, &oplock, | 577 | nd->intent.open.file->f_flags, &oplock, |
695 | &fileHandle, xid); | 578 | &fileHandle, xid); |
696 | /* | 579 | /* |
697 | * The check below works around a bug in POSIX | 580 | * The check below works around a bug in POSIX |
@@ -713,10 +596,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
713 | parent_dir_inode->i_sb, xid, NULL); | 596 | parent_dir_inode->i_sb, xid, NULL); |
714 | 597 | ||
715 | if ((rc == 0) && (newInode != NULL)) { | 598 | if ((rc == 0) && (newInode != NULL)) { |
716 | if (pTcon->nocase) | ||
717 | direntry->d_op = &cifs_ci_dentry_ops; | ||
718 | else | ||
719 | direntry->d_op = &cifs_dentry_ops; | ||
720 | d_add(direntry, newInode); | 599 | d_add(direntry, newInode); |
721 | if (posix_open) { | 600 | if (posix_open) { |
722 | filp = lookup_instantiate_filp(nd, direntry, | 601 | filp = lookup_instantiate_filp(nd, direntry, |
@@ -727,9 +606,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
727 | goto lookup_out; | 606 | goto lookup_out; |
728 | } | 607 | } |
729 | 608 | ||
730 | cfile = cifs_new_fileinfo(newInode, fileHandle, filp, | 609 | cfile = cifs_new_fileinfo(fileHandle, filp, tlink, |
731 | nd->path.mnt, | 610 | oplock); |
732 | nd->intent.open.flags); | ||
733 | if (cfile == NULL) { | 611 | if (cfile == NULL) { |
734 | fput(filp); | 612 | fput(filp); |
735 | CIFSSMBClose(xid, pTcon, fileHandle); | 613 | CIFSSMBClose(xid, pTcon, fileHandle); |
@@ -744,10 +622,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
744 | } else if (rc == -ENOENT) { | 622 | } else if (rc == -ENOENT) { |
745 | rc = 0; | 623 | rc = 0; |
746 | direntry->d_time = jiffies; | 624 | direntry->d_time = jiffies; |
747 | if (pTcon->nocase) | ||
748 | direntry->d_op = &cifs_ci_dentry_ops; | ||
749 | else | ||
750 | direntry->d_op = &cifs_dentry_ops; | ||
751 | d_add(direntry, NULL); | 625 | d_add(direntry, NULL); |
752 | /* if it was once a directory (but how can we tell?) we could do | 626 | /* if it was once a directory (but how can we tell?) we could do |
753 | shrink_dcache_parent(direntry); */ | 627 | shrink_dcache_parent(direntry); */ |
@@ -759,6 +633,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
759 | 633 | ||
760 | lookup_out: | 634 | lookup_out: |
761 | kfree(full_path); | 635 | kfree(full_path); |
636 | cifs_put_tlink(tlink); | ||
762 | FreeXid(xid); | 637 | FreeXid(xid); |
763 | return ERR_PTR(rc); | 638 | return ERR_PTR(rc); |
764 | } | 639 | } |
@@ -766,22 +641,37 @@ lookup_out: | |||
766 | static int | 641 | static int |
767 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | 642 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) |
768 | { | 643 | { |
769 | int isValid = 1; | 644 | if (nd->flags & LOOKUP_RCU) |
645 | return -ECHILD; | ||
770 | 646 | ||
771 | if (direntry->d_inode) { | 647 | if (direntry->d_inode) { |
772 | if (cifs_revalidate_dentry(direntry)) | 648 | if (cifs_revalidate_dentry(direntry)) |
773 | return 0; | 649 | return 0; |
774 | } else { | 650 | else |
775 | cFYI(1, "neg dentry 0x%p name = %s", | 651 | return 1; |
776 | direntry, direntry->d_name.name); | ||
777 | if (time_after(jiffies, direntry->d_time + HZ) || | ||
778 | !lookupCacheEnabled) { | ||
779 | d_drop(direntry); | ||
780 | isValid = 0; | ||
781 | } | ||
782 | } | 652 | } |
783 | 653 | ||
784 | return isValid; | 654 | /* |
655 | * This may be nfsd (or something), anyway, we can't see the | ||
656 | * intent of this. So, since this can be for creation, drop it. | ||
657 | */ | ||
658 | if (!nd) | ||
659 | return 0; | ||
660 | |||
661 | /* | ||
662 | * Drop the negative dentry, in order to make sure to use the | ||
663 | * case sensitive name which is specified by user if this is | ||
664 | * for creation. | ||
665 | */ | ||
666 | if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { | ||
667 | if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) | ||
672 | return 0; | ||
673 | |||
674 | return 1; | ||
785 | } | 675 | } |
786 | 676 | ||
787 | /* static int cifs_d_delete(struct dentry *direntry) | 677 | /* static int cifs_d_delete(struct dentry *direntry) |
@@ -795,12 +685,14 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | |||
795 | 685 | ||
796 | const struct dentry_operations cifs_dentry_ops = { | 686 | const struct dentry_operations cifs_dentry_ops = { |
797 | .d_revalidate = cifs_d_revalidate, | 687 | .d_revalidate = cifs_d_revalidate, |
688 | .d_automount = cifs_dfs_d_automount, | ||
798 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ | 689 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ |
799 | }; | 690 | }; |
800 | 691 | ||
801 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | 692 | static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode, |
693 | struct qstr *q) | ||
802 | { | 694 | { |
803 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | 695 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; |
804 | unsigned long hash; | 696 | unsigned long hash; |
805 | int i; | 697 | int i; |
806 | 698 | ||
@@ -813,21 +705,16 @@ static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | |||
813 | return 0; | 705 | return 0; |
814 | } | 706 | } |
815 | 707 | ||
816 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | 708 | static int cifs_ci_compare(const struct dentry *parent, |
817 | struct qstr *b) | 709 | const struct inode *pinode, |
710 | const struct dentry *dentry, const struct inode *inode, | ||
711 | unsigned int len, const char *str, const struct qstr *name) | ||
818 | { | 712 | { |
819 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | 713 | struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls; |
820 | 714 | ||
821 | if ((a->len == b->len) && | 715 | if ((name->len == len) && |
822 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | 716 | (nls_strnicmp(codepage, name->name, str, len) == 0)) |
823 | /* | ||
824 | * To preserve case, don't let an existing negative dentry's | ||
825 | * case take precedence. If a is not a negative dentry, this | ||
826 | * should have no side effects | ||
827 | */ | ||
828 | memcpy((void *)a->name, b->name, a->len); | ||
829 | return 0; | 717 | return 0; |
830 | } | ||
831 | return 1; | 718 | return 1; |
832 | } | 719 | } |
833 | 720 | ||
@@ -835,4 +722,5 @@ const struct dentry_operations cifs_ci_dentry_ops = { | |||
835 | .d_revalidate = cifs_d_revalidate, | 722 | .d_revalidate = cifs_d_revalidate, |
836 | .d_hash = cifs_ci_hash, | 723 | .d_hash = cifs_ci_hash, |
837 | .d_compare = cifs_ci_compare, | 724 | .d_compare = cifs_ci_compare, |
725 | .d_automount = cifs_dfs_d_automount, | ||
838 | }; | 726 | }; |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 0eb87026cad3..548f06230a6d 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -66,7 +66,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) | |||
66 | /* Search for server name delimiter */ | 66 | /* Search for server name delimiter */ |
67 | sep = memchr(hostname, '\\', len); | 67 | sep = memchr(hostname, '\\', len); |
68 | if (sep) | 68 | if (sep) |
69 | len = sep - unc; | 69 | len = sep - hostname; |
70 | else | 70 | else |
71 | cFYI(1, "%s: probably server name is whole unc: %s", | 71 | cFYI(1, "%s: probably server name is whole unc: %s", |
72 | __func__, unc); | 72 | __func__, unc); |
diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 993f82045bf6..55d87ac52000 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c | |||
@@ -45,7 +45,7 @@ | |||
45 | #include "cifs_debug.h" | 45 | #include "cifs_debug.h" |
46 | #include "cifsfs.h" | 46 | #include "cifsfs.h" |
47 | 47 | ||
48 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 48 | #ifdef CIFS_NFSD_EXPORT |
49 | static struct dentry *cifs_get_parent(struct dentry *dentry) | 49 | static struct dentry *cifs_get_parent(struct dentry *dentry) |
50 | { | 50 | { |
51 | /* BB need to add code here eventually to enable export via NFSD */ | 51 | /* BB need to add code here eventually to enable export via NFSD */ |
@@ -63,5 +63,5 @@ const struct export_operations cifs_export_ops = { | |||
63 | .encode_fs = */ | 63 | .encode_fs = */ |
64 | }; | 64 | }; |
65 | 65 | ||
66 | #endif /* EXPERIMENTAL */ | 66 | #endif /* CIFS_NFSD_EXPORT */ |
67 | 67 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index de748c652d11..a9b4a24f2a16 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -60,34 +60,32 @@ static inline int cifs_convert_flags(unsigned int flags) | |||
60 | FILE_READ_DATA); | 60 | FILE_READ_DATA); |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline fmode_t cifs_posix_convert_flags(unsigned int flags) | 63 | static u32 cifs_posix_convert_flags(unsigned int flags) |
64 | { | 64 | { |
65 | fmode_t posix_flags = 0; | 65 | u32 posix_flags = 0; |
66 | 66 | ||
67 | if ((flags & O_ACCMODE) == O_RDONLY) | 67 | if ((flags & O_ACCMODE) == O_RDONLY) |
68 | posix_flags = FMODE_READ; | 68 | posix_flags = SMB_O_RDONLY; |
69 | else if ((flags & O_ACCMODE) == O_WRONLY) | 69 | else if ((flags & O_ACCMODE) == O_WRONLY) |
70 | posix_flags = FMODE_WRITE; | 70 | posix_flags = SMB_O_WRONLY; |
71 | else if ((flags & O_ACCMODE) == O_RDWR) { | 71 | else if ((flags & O_ACCMODE) == O_RDWR) |
72 | /* GENERIC_ALL is too much permission to request | 72 | posix_flags = SMB_O_RDWR; |
73 | can cause unnecessary access denied on create */ | 73 | |
74 | /* return GENERIC_ALL; */ | 74 | if (flags & O_CREAT) |
75 | posix_flags = FMODE_READ | FMODE_WRITE; | 75 | posix_flags |= SMB_O_CREAT; |
76 | } | 76 | if (flags & O_EXCL) |
77 | /* can not map O_CREAT or O_EXCL or O_TRUNC flags when | 77 | posix_flags |= SMB_O_EXCL; |
78 | reopening a file. They had their effect on the original open */ | 78 | if (flags & O_TRUNC) |
79 | if (flags & O_APPEND) | 79 | posix_flags |= SMB_O_TRUNC; |
80 | posix_flags |= (fmode_t)O_APPEND; | 80 | /* be safe and imply O_SYNC for O_DSYNC */ |
81 | if (flags & O_DSYNC) | 81 | if (flags & O_DSYNC) |
82 | posix_flags |= (fmode_t)O_DSYNC; | 82 | posix_flags |= SMB_O_SYNC; |
83 | if (flags & __O_SYNC) | ||
84 | posix_flags |= (fmode_t)__O_SYNC; | ||
85 | if (flags & O_DIRECTORY) | 83 | if (flags & O_DIRECTORY) |
86 | posix_flags |= (fmode_t)O_DIRECTORY; | 84 | posix_flags |= SMB_O_DIRECTORY; |
87 | if (flags & O_NOFOLLOW) | 85 | if (flags & O_NOFOLLOW) |
88 | posix_flags |= (fmode_t)O_NOFOLLOW; | 86 | posix_flags |= SMB_O_NOFOLLOW; |
89 | if (flags & O_DIRECT) | 87 | if (flags & O_DIRECT) |
90 | posix_flags |= (fmode_t)O_DIRECT; | 88 | posix_flags |= SMB_O_DIRECT; |
91 | 89 | ||
92 | return posix_flags; | 90 | return posix_flags; |
93 | } | 91 | } |
@@ -106,138 +104,261 @@ static inline int cifs_get_disposition(unsigned int flags) | |||
106 | return FILE_OPEN; | 104 | return FILE_OPEN; |
107 | } | 105 | } |
108 | 106 | ||
109 | /* all arguments to this function must be checked for validity in caller */ | 107 | int cifs_posix_open(char *full_path, struct inode **pinode, |
110 | static inline int | 108 | struct super_block *sb, int mode, unsigned int f_flags, |
111 | cifs_posix_open_inode_helper(struct inode *inode, struct file *file, | 109 | __u32 *poplock, __u16 *pnetfid, int xid) |
112 | struct cifsInodeInfo *pCifsInode, __u32 oplock, | ||
113 | u16 netfid) | ||
114 | { | 110 | { |
111 | int rc; | ||
112 | FILE_UNIX_BASIC_INFO *presp_data; | ||
113 | __u32 posix_flags = 0; | ||
114 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
115 | struct cifs_fattr fattr; | ||
116 | struct tcon_link *tlink; | ||
117 | struct cifs_tcon *tcon; | ||
115 | 118 | ||
116 | write_lock(&GlobalSMBSeslock); | 119 | cFYI(1, "posix open %s", full_path); |
117 | 120 | ||
118 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 121 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); |
119 | if (pCifsInode == NULL) { | 122 | if (presp_data == NULL) |
120 | write_unlock(&GlobalSMBSeslock); | 123 | return -ENOMEM; |
121 | return -EINVAL; | ||
122 | } | ||
123 | 124 | ||
124 | if (pCifsInode->clientCanCacheRead) { | 125 | tlink = cifs_sb_tlink(cifs_sb); |
125 | /* we have the inode open somewhere else | 126 | if (IS_ERR(tlink)) { |
126 | no need to discard cache data */ | 127 | rc = PTR_ERR(tlink); |
127 | goto psx_client_can_cache; | 128 | goto posix_open_ret; |
128 | } | 129 | } |
129 | 130 | ||
130 | /* BB FIXME need to fix this check to move it earlier into posix_open | 131 | tcon = tlink_tcon(tlink); |
131 | BB fIX following section BB FIXME */ | 132 | mode &= ~current_umask(); |
132 | 133 | ||
133 | /* if not oplocked, invalidate inode pages if mtime or file | 134 | posix_flags = cifs_posix_convert_flags(f_flags); |
134 | size changed */ | 135 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, |
135 | /* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); | 136 | poplock, full_path, cifs_sb->local_nls, |
136 | if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) && | 137 | cifs_sb->mnt_cifs_flags & |
137 | (file->f_path.dentry->d_inode->i_size == | 138 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
138 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | 139 | cifs_put_tlink(tlink); |
139 | cFYI(1, "inode unchanged on server"); | 140 | |
140 | } else { | 141 | if (rc) |
141 | if (file->f_path.dentry->d_inode->i_mapping) { | 142 | goto posix_open_ret; |
142 | rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); | 143 | |
143 | if (rc != 0) | 144 | if (presp_data->Type == cpu_to_le32(-1)) |
144 | CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; | 145 | goto posix_open_ret; /* open ok, caller does qpathinfo */ |
146 | |||
147 | if (!pinode) | ||
148 | goto posix_open_ret; /* caller does not need info */ | ||
149 | |||
150 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
151 | |||
152 | /* get new inode and set it up */ | ||
153 | if (*pinode == NULL) { | ||
154 | cifs_fill_uniqueid(sb, &fattr); | ||
155 | *pinode = cifs_iget(sb, &fattr); | ||
156 | if (!*pinode) { | ||
157 | rc = -ENOMEM; | ||
158 | goto posix_open_ret; | ||
145 | } | 159 | } |
146 | cFYI(1, "invalidating remote inode since open detected it " | 160 | } else { |
147 | "changed"); | 161 | cifs_fattr_to_inode(*pinode, &fattr); |
148 | invalidate_remote_inode(file->f_path.dentry->d_inode); | 162 | } |
149 | } */ | 163 | |
150 | 164 | posix_open_ret: | |
151 | psx_client_can_cache: | 165 | kfree(presp_data); |
152 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | 166 | return rc; |
153 | pCifsInode->clientCanCacheAll = true; | ||
154 | pCifsInode->clientCanCacheRead = true; | ||
155 | cFYI(1, "Exclusive Oplock granted on inode %p", | ||
156 | file->f_path.dentry->d_inode); | ||
157 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
158 | pCifsInode->clientCanCacheRead = true; | ||
159 | |||
160 | /* will have to change the unlock if we reenable the | ||
161 | filemap_fdatawrite (which does not seem necessary */ | ||
162 | write_unlock(&GlobalSMBSeslock); | ||
163 | return 0; | ||
164 | } | 167 | } |
165 | 168 | ||
166 | /* all arguments to this function must be checked for validity in caller */ | 169 | static int |
167 | static inline int cifs_open_inode_helper(struct inode *inode, | 170 | cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, |
168 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, | 171 | struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock, |
169 | char *full_path, int xid) | 172 | __u16 *pnetfid, int xid) |
170 | { | 173 | { |
171 | struct cifsInodeInfo *pCifsInode = CIFS_I(inode); | ||
172 | struct timespec temp; | ||
173 | int rc; | 174 | int rc; |
175 | int desiredAccess; | ||
176 | int disposition; | ||
177 | FILE_ALL_INFO *buf; | ||
174 | 178 | ||
175 | if (pCifsInode->clientCanCacheRead) { | 179 | desiredAccess = cifs_convert_flags(f_flags); |
176 | /* we have the inode open somewhere else | ||
177 | no need to discard cache data */ | ||
178 | goto client_can_cache; | ||
179 | } | ||
180 | 180 | ||
181 | /* BB need same check in cifs_create too? */ | 181 | /********************************************************************* |
182 | /* if not oplocked, invalidate inode pages if mtime or file | 182 | * open flag mapping table: |
183 | size changed */ | 183 | * |
184 | temp = cifs_NTtimeToUnix(buf->LastWriteTime); | 184 | * POSIX Flag CIFS Disposition |
185 | if (timespec_equal(&inode->i_mtime, &temp) && | 185 | * ---------- ---------------- |
186 | (inode->i_size == | 186 | * O_CREAT FILE_OPEN_IF |
187 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | 187 | * O_CREAT | O_EXCL FILE_CREATE |
188 | cFYI(1, "inode unchanged on server"); | 188 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF |
189 | } else { | 189 | * O_TRUNC FILE_OVERWRITE |
190 | if (inode->i_mapping) { | 190 | * none of the above FILE_OPEN |
191 | /* BB no need to lock inode until after invalidate | 191 | * |
192 | since namei code should already have it locked? */ | 192 | * Note that there is not a direct match between disposition |
193 | rc = filemap_write_and_wait(inode->i_mapping); | 193 | * FILE_SUPERSEDE (ie create whether or not file exists although |
194 | if (rc != 0) | 194 | * O_CREAT | O_TRUNC is similar but truncates the existing |
195 | pCifsInode->write_behind_rc = rc; | 195 | * file rather than creating a new file as FILE_SUPERSEDE does |
196 | } | 196 | * (which uses the attributes / metadata passed in on open call) |
197 | cFYI(1, "invalidating remote inode since open detected it " | 197 | *? |
198 | "changed"); | 198 | *? O_SYNC is a reasonable match to CIFS writethrough flag |
199 | invalidate_remote_inode(inode); | 199 | *? and the read write flags match reasonably. O_LARGEFILE |
200 | } | 200 | *? is irrelevant because largefile support is always used |
201 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
202 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
203 | *********************************************************************/ | ||
204 | |||
205 | disposition = cifs_get_disposition(f_flags); | ||
206 | |||
207 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
208 | |||
209 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
210 | if (!buf) | ||
211 | return -ENOMEM; | ||
212 | |||
213 | if (tcon->ses->capabilities & CAP_NT_SMBS) | ||
214 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | ||
215 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | ||
216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
217 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
218 | else | ||
219 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | ||
220 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | ||
221 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
222 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
201 | 223 | ||
202 | client_can_cache: | 224 | if (rc) |
203 | if (pTcon->unix_ext) | 225 | goto out; |
226 | |||
227 | if (tcon->unix_ext) | ||
204 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | 228 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, |
205 | xid); | 229 | xid); |
206 | else | 230 | else |
207 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | 231 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, |
208 | xid, NULL); | 232 | xid, pnetfid); |
209 | |||
210 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
211 | pCifsInode->clientCanCacheAll = true; | ||
212 | pCifsInode->clientCanCacheRead = true; | ||
213 | cFYI(1, "Exclusive Oplock granted on inode %p", inode); | ||
214 | } else if ((*oplock & 0xF) == OPLOCK_READ) | ||
215 | pCifsInode->clientCanCacheRead = true; | ||
216 | 233 | ||
234 | out: | ||
235 | kfree(buf); | ||
217 | return rc; | 236 | return rc; |
218 | } | 237 | } |
219 | 238 | ||
239 | struct cifsFileInfo * | ||
240 | cifs_new_fileinfo(__u16 fileHandle, struct file *file, | ||
241 | struct tcon_link *tlink, __u32 oplock) | ||
242 | { | ||
243 | struct dentry *dentry = file->f_path.dentry; | ||
244 | struct inode *inode = dentry->d_inode; | ||
245 | struct cifsInodeInfo *pCifsInode = CIFS_I(inode); | ||
246 | struct cifsFileInfo *pCifsFile; | ||
247 | |||
248 | pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
249 | if (pCifsFile == NULL) | ||
250 | return pCifsFile; | ||
251 | |||
252 | pCifsFile->count = 1; | ||
253 | pCifsFile->netfid = fileHandle; | ||
254 | pCifsFile->pid = current->tgid; | ||
255 | pCifsFile->uid = current_fsuid(); | ||
256 | pCifsFile->dentry = dget(dentry); | ||
257 | pCifsFile->f_flags = file->f_flags; | ||
258 | pCifsFile->invalidHandle = false; | ||
259 | pCifsFile->tlink = cifs_get_tlink(tlink); | ||
260 | mutex_init(&pCifsFile->fh_mutex); | ||
261 | mutex_init(&pCifsFile->lock_mutex); | ||
262 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
263 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); | ||
264 | |||
265 | spin_lock(&cifs_file_list_lock); | ||
266 | list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList)); | ||
267 | /* if readable file instance put first in list*/ | ||
268 | if (file->f_mode & FMODE_READ) | ||
269 | list_add(&pCifsFile->flist, &pCifsInode->openFileList); | ||
270 | else | ||
271 | list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); | ||
272 | spin_unlock(&cifs_file_list_lock); | ||
273 | |||
274 | cifs_set_oplock_level(pCifsInode, oplock); | ||
275 | |||
276 | file->private_data = pCifsFile; | ||
277 | return pCifsFile; | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Release a reference on the file private data. This may involve closing | ||
282 | * the filehandle out on the server. Must be called without holding | ||
283 | * cifs_file_list_lock. | ||
284 | */ | ||
285 | void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | ||
286 | { | ||
287 | struct inode *inode = cifs_file->dentry->d_inode; | ||
288 | struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); | ||
289 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
291 | struct cifsLockInfo *li, *tmp; | ||
292 | |||
293 | spin_lock(&cifs_file_list_lock); | ||
294 | if (--cifs_file->count > 0) { | ||
295 | spin_unlock(&cifs_file_list_lock); | ||
296 | return; | ||
297 | } | ||
298 | |||
299 | /* remove it from the lists */ | ||
300 | list_del(&cifs_file->flist); | ||
301 | list_del(&cifs_file->tlist); | ||
302 | |||
303 | if (list_empty(&cifsi->openFileList)) { | ||
304 | cFYI(1, "closing last open instance for inode %p", | ||
305 | cifs_file->dentry->d_inode); | ||
306 | |||
307 | /* in strict cache mode we need invalidate mapping on the last | ||
308 | close because it may cause a error when we open this file | ||
309 | again and get at least level II oplock */ | ||
310 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) | ||
311 | CIFS_I(inode)->invalid_mapping = true; | ||
312 | |||
313 | cifs_set_oplock_level(cifsi, 0); | ||
314 | } | ||
315 | spin_unlock(&cifs_file_list_lock); | ||
316 | |||
317 | if (!tcon->need_reconnect && !cifs_file->invalidHandle) { | ||
318 | int xid, rc; | ||
319 | |||
320 | xid = GetXid(); | ||
321 | rc = CIFSSMBClose(xid, tcon, cifs_file->netfid); | ||
322 | FreeXid(xid); | ||
323 | } | ||
324 | |||
325 | /* Delete any outstanding lock records. We'll lose them when the file | ||
326 | * is closed anyway. | ||
327 | */ | ||
328 | mutex_lock(&cifs_file->lock_mutex); | ||
329 | list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) { | ||
330 | list_del(&li->llist); | ||
331 | kfree(li); | ||
332 | } | ||
333 | mutex_unlock(&cifs_file->lock_mutex); | ||
334 | |||
335 | cifs_put_tlink(cifs_file->tlink); | ||
336 | dput(cifs_file->dentry); | ||
337 | kfree(cifs_file); | ||
338 | } | ||
339 | |||
220 | int cifs_open(struct inode *inode, struct file *file) | 340 | int cifs_open(struct inode *inode, struct file *file) |
221 | { | 341 | { |
222 | int rc = -EACCES; | 342 | int rc = -EACCES; |
223 | int xid; | 343 | int xid; |
224 | __u32 oplock; | 344 | __u32 oplock; |
225 | struct cifs_sb_info *cifs_sb; | 345 | struct cifs_sb_info *cifs_sb; |
226 | struct cifsTconInfo *tcon; | 346 | struct cifs_tcon *tcon; |
347 | struct tcon_link *tlink; | ||
227 | struct cifsFileInfo *pCifsFile = NULL; | 348 | struct cifsFileInfo *pCifsFile = NULL; |
228 | struct cifsInodeInfo *pCifsInode; | ||
229 | char *full_path = NULL; | 349 | char *full_path = NULL; |
230 | int desiredAccess; | 350 | bool posix_open_ok = false; |
231 | int disposition; | ||
232 | __u16 netfid; | 351 | __u16 netfid; |
233 | FILE_ALL_INFO *buf = NULL; | ||
234 | 352 | ||
235 | xid = GetXid(); | 353 | xid = GetXid(); |
236 | 354 | ||
237 | cifs_sb = CIFS_SB(inode->i_sb); | 355 | cifs_sb = CIFS_SB(inode->i_sb); |
238 | tcon = cifs_sb->tcon; | 356 | tlink = cifs_sb_tlink(cifs_sb); |
239 | 357 | if (IS_ERR(tlink)) { | |
240 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 358 | FreeXid(xid); |
359 | return PTR_ERR(tlink); | ||
360 | } | ||
361 | tcon = tlink_tcon(tlink); | ||
241 | 362 | ||
242 | full_path = build_path_from_dentry(file->f_path.dentry); | 363 | full_path = build_path_from_dentry(file->f_path.dentry); |
243 | if (full_path == NULL) { | 364 | if (full_path == NULL) { |
@@ -257,35 +378,13 @@ int cifs_open(struct inode *inode, struct file *file) | |||
257 | (tcon->ses->capabilities & CAP_UNIX) && | 378 | (tcon->ses->capabilities & CAP_UNIX) && |
258 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 379 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
259 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 380 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
260 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | ||
261 | oflags |= SMB_O_CREAT; | ||
262 | /* can not refresh inode info since size could be stale */ | 381 | /* can not refresh inode info since size could be stale */ |
263 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, | 382 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, |
264 | cifs_sb->mnt_file_mode /* ignored */, | 383 | cifs_sb->mnt_file_mode /* ignored */, |
265 | oflags, &oplock, &netfid, xid); | 384 | file->f_flags, &oplock, &netfid, xid); |
266 | if (rc == 0) { | 385 | if (rc == 0) { |
267 | cFYI(1, "posix open succeeded"); | 386 | cFYI(1, "posix open succeeded"); |
268 | /* no need for special case handling of setting mode | 387 | posix_open_ok = true; |
269 | on read only files needed here */ | ||
270 | |||
271 | rc = cifs_posix_open_inode_helper(inode, file, | ||
272 | pCifsInode, oplock, netfid); | ||
273 | if (rc != 0) { | ||
274 | CIFSSMBClose(xid, tcon, netfid); | ||
275 | goto out; | ||
276 | } | ||
277 | |||
278 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, | ||
279 | file->f_path.mnt, | ||
280 | oflags); | ||
281 | if (pCifsFile == NULL) { | ||
282 | CIFSSMBClose(xid, tcon, netfid); | ||
283 | rc = -ENOMEM; | ||
284 | } | ||
285 | |||
286 | cifs_fscache_set_inode_cookie(inode, file); | ||
287 | |||
288 | goto out; | ||
289 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 388 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
290 | if (tcon->ses->serverNOS) | 389 | if (tcon->ses->serverNOS) |
291 | cERROR(1, "server %s of type %s returned" | 390 | cERROR(1, "server %s of type %s returned" |
@@ -302,106 +401,42 @@ int cifs_open(struct inode *inode, struct file *file) | |||
302 | or DFS errors */ | 401 | or DFS errors */ |
303 | } | 402 | } |
304 | 403 | ||
305 | desiredAccess = cifs_convert_flags(file->f_flags); | 404 | if (!posix_open_ok) { |
306 | 405 | rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, | |
307 | /********************************************************************* | 406 | file->f_flags, &oplock, &netfid, xid); |
308 | * open flag mapping table: | 407 | if (rc) |
309 | * | 408 | goto out; |
310 | * POSIX Flag CIFS Disposition | ||
311 | * ---------- ---------------- | ||
312 | * O_CREAT FILE_OPEN_IF | ||
313 | * O_CREAT | O_EXCL FILE_CREATE | ||
314 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
315 | * O_TRUNC FILE_OVERWRITE | ||
316 | * none of the above FILE_OPEN | ||
317 | * | ||
318 | * Note that there is not a direct match between disposition | ||
319 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
320 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
321 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
322 | * (which uses the attributes / metadata passed in on open call) | ||
323 | *? | ||
324 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
325 | *? and the read write flags match reasonably. O_LARGEFILE | ||
326 | *? is irrelevant because largefile support is always used | ||
327 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
328 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
329 | *********************************************************************/ | ||
330 | |||
331 | disposition = cifs_get_disposition(file->f_flags); | ||
332 | |||
333 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
334 | |||
335 | /* Also refresh inode by passing in file_info buf returned by SMBOpen | ||
336 | and calling get_inode_info with returned buf (at least helps | ||
337 | non-Unix server case) */ | ||
338 | |||
339 | /* BB we can not do this if this is the second open of a file | ||
340 | and the first handle has writebehind data, we might be | ||
341 | able to simply do a filemap_fdatawrite/filemap_fdatawait first */ | ||
342 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
343 | if (!buf) { | ||
344 | rc = -ENOMEM; | ||
345 | goto out; | ||
346 | } | ||
347 | |||
348 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) | ||
349 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | ||
350 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
351 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
352 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
353 | else | ||
354 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | ||
355 | |||
356 | if (rc == -EIO) { | ||
357 | /* Old server, try legacy style OpenX */ | ||
358 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | ||
359 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
360 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
361 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
362 | } | ||
363 | if (rc) { | ||
364 | cFYI(1, "cifs_open returned 0x%x", rc); | ||
365 | goto out; | ||
366 | } | 409 | } |
367 | 410 | ||
368 | rc = cifs_open_inode_helper(inode, tcon, &oplock, buf, full_path, xid); | 411 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock); |
369 | if (rc != 0) | ||
370 | goto out; | ||
371 | |||
372 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, | ||
373 | file->f_flags); | ||
374 | if (pCifsFile == NULL) { | 412 | if (pCifsFile == NULL) { |
413 | CIFSSMBClose(xid, tcon, netfid); | ||
375 | rc = -ENOMEM; | 414 | rc = -ENOMEM; |
376 | goto out; | 415 | goto out; |
377 | } | 416 | } |
378 | 417 | ||
379 | cifs_fscache_set_inode_cookie(inode, file); | 418 | cifs_fscache_set_inode_cookie(inode, file); |
380 | 419 | ||
381 | if (oplock & CIFS_CREATE_ACTION) { | 420 | if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { |
382 | /* time to set mode which we can not set earlier due to | 421 | /* time to set mode which we can not set earlier due to |
383 | problems creating new read-only files */ | 422 | problems creating new read-only files */ |
384 | if (tcon->unix_ext) { | 423 | struct cifs_unix_set_info_args args = { |
385 | struct cifs_unix_set_info_args args = { | 424 | .mode = inode->i_mode, |
386 | .mode = inode->i_mode, | 425 | .uid = NO_CHANGE_64, |
387 | .uid = NO_CHANGE_64, | 426 | .gid = NO_CHANGE_64, |
388 | .gid = NO_CHANGE_64, | 427 | .ctime = NO_CHANGE_64, |
389 | .ctime = NO_CHANGE_64, | 428 | .atime = NO_CHANGE_64, |
390 | .atime = NO_CHANGE_64, | 429 | .mtime = NO_CHANGE_64, |
391 | .mtime = NO_CHANGE_64, | 430 | .device = 0, |
392 | .device = 0, | 431 | }; |
393 | }; | 432 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid, |
394 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 433 | pCifsFile->pid); |
395 | cifs_sb->local_nls, | ||
396 | cifs_sb->mnt_cifs_flags & | ||
397 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
398 | } | ||
399 | } | 434 | } |
400 | 435 | ||
401 | out: | 436 | out: |
402 | kfree(buf); | ||
403 | kfree(full_path); | 437 | kfree(full_path); |
404 | FreeXid(xid); | 438 | FreeXid(xid); |
439 | cifs_put_tlink(tlink); | ||
405 | return rc; | 440 | return rc; |
406 | } | 441 | } |
407 | 442 | ||
@@ -416,14 +451,13 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile) | |||
416 | return rc; | 451 | return rc; |
417 | } | 452 | } |
418 | 453 | ||
419 | static int cifs_reopen_file(struct file *file, bool can_flush) | 454 | static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) |
420 | { | 455 | { |
421 | int rc = -EACCES; | 456 | int rc = -EACCES; |
422 | int xid; | 457 | int xid; |
423 | __u32 oplock; | 458 | __u32 oplock; |
424 | struct cifs_sb_info *cifs_sb; | 459 | struct cifs_sb_info *cifs_sb; |
425 | struct cifsTconInfo *tcon; | 460 | struct cifs_tcon *tcon; |
426 | struct cifsFileInfo *pCifsFile; | ||
427 | struct cifsInodeInfo *pCifsInode; | 461 | struct cifsInodeInfo *pCifsInode; |
428 | struct inode *inode; | 462 | struct inode *inode; |
429 | char *full_path = NULL; | 463 | char *full_path = NULL; |
@@ -431,11 +465,6 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
431 | int disposition = FILE_OPEN; | 465 | int disposition = FILE_OPEN; |
432 | __u16 netfid; | 466 | __u16 netfid; |
433 | 467 | ||
434 | if (file->private_data) | ||
435 | pCifsFile = file->private_data; | ||
436 | else | ||
437 | return -EBADF; | ||
438 | |||
439 | xid = GetXid(); | 468 | xid = GetXid(); |
440 | mutex_lock(&pCifsFile->fh_mutex); | 469 | mutex_lock(&pCifsFile->fh_mutex); |
441 | if (!pCifsFile->invalidHandle) { | 470 | if (!pCifsFile->invalidHandle) { |
@@ -445,39 +474,24 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
445 | return rc; | 474 | return rc; |
446 | } | 475 | } |
447 | 476 | ||
448 | if (file->f_path.dentry == NULL) { | 477 | inode = pCifsFile->dentry->d_inode; |
449 | cERROR(1, "no valid name if dentry freed"); | ||
450 | dump_stack(); | ||
451 | rc = -EBADF; | ||
452 | goto reopen_error_exit; | ||
453 | } | ||
454 | |||
455 | inode = file->f_path.dentry->d_inode; | ||
456 | if (inode == NULL) { | ||
457 | cERROR(1, "inode not valid"); | ||
458 | dump_stack(); | ||
459 | rc = -EBADF; | ||
460 | goto reopen_error_exit; | ||
461 | } | ||
462 | |||
463 | cifs_sb = CIFS_SB(inode->i_sb); | 478 | cifs_sb = CIFS_SB(inode->i_sb); |
464 | tcon = cifs_sb->tcon; | 479 | tcon = tlink_tcon(pCifsFile->tlink); |
465 | 480 | ||
466 | /* can not grab rename sem here because various ops, including | 481 | /* can not grab rename sem here because various ops, including |
467 | those that already have the rename sem can end up causing writepage | 482 | those that already have the rename sem can end up causing writepage |
468 | to get called and if the server was down that means we end up here, | 483 | to get called and if the server was down that means we end up here, |
469 | and we can never tell if the caller already has the rename_sem */ | 484 | and we can never tell if the caller already has the rename_sem */ |
470 | full_path = build_path_from_dentry(file->f_path.dentry); | 485 | full_path = build_path_from_dentry(pCifsFile->dentry); |
471 | if (full_path == NULL) { | 486 | if (full_path == NULL) { |
472 | rc = -ENOMEM; | 487 | rc = -ENOMEM; |
473 | reopen_error_exit: | ||
474 | mutex_unlock(&pCifsFile->fh_mutex); | 488 | mutex_unlock(&pCifsFile->fh_mutex); |
475 | FreeXid(xid); | 489 | FreeXid(xid); |
476 | return rc; | 490 | return rc; |
477 | } | 491 | } |
478 | 492 | ||
479 | cFYI(1, "inode = 0x%p file flags 0x%x for %s", | 493 | cFYI(1, "inode = 0x%p file flags 0x%x for %s", |
480 | inode, file->f_flags, full_path); | 494 | inode, pCifsFile->f_flags, full_path); |
481 | 495 | ||
482 | if (oplockEnabled) | 496 | if (oplockEnabled) |
483 | oplock = REQ_OPLOCK; | 497 | oplock = REQ_OPLOCK; |
@@ -487,8 +501,14 @@ reopen_error_exit: | |||
487 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 501 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
488 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 502 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
489 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 503 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
490 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 504 | |
491 | /* can not refresh inode info since size could be stale */ | 505 | /* |
506 | * O_CREAT, O_EXCL and O_TRUNC already had their effect on the | ||
507 | * original open. Must mask them off for a reopen. | ||
508 | */ | ||
509 | unsigned int oflags = pCifsFile->f_flags & | ||
510 | ~(O_CREAT | O_EXCL | O_TRUNC); | ||
511 | |||
492 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, | 512 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, |
493 | cifs_sb->mnt_file_mode /* ignored */, | 513 | cifs_sb->mnt_file_mode /* ignored */, |
494 | oflags, &oplock, &netfid, xid); | 514 | oflags, &oplock, &netfid, xid); |
@@ -500,7 +520,7 @@ reopen_error_exit: | |||
500 | in the reconnect path it is important to retry hard */ | 520 | in the reconnect path it is important to retry hard */ |
501 | } | 521 | } |
502 | 522 | ||
503 | desiredAccess = cifs_convert_flags(file->f_flags); | 523 | desiredAccess = cifs_convert_flags(pCifsFile->f_flags); |
504 | 524 | ||
505 | /* Can not refresh inode by passing in file_info buf to be returned | 525 | /* Can not refresh inode by passing in file_info buf to be returned |
506 | by SMBOpen and then calling get_inode_info with returned buf | 526 | by SMBOpen and then calling get_inode_info with returned buf |
@@ -516,49 +536,38 @@ reopen_error_exit: | |||
516 | mutex_unlock(&pCifsFile->fh_mutex); | 536 | mutex_unlock(&pCifsFile->fh_mutex); |
517 | cFYI(1, "cifs_open returned 0x%x", rc); | 537 | cFYI(1, "cifs_open returned 0x%x", rc); |
518 | cFYI(1, "oplock: %d", oplock); | 538 | cFYI(1, "oplock: %d", oplock); |
519 | } else { | 539 | goto reopen_error_exit; |
520 | reopen_success: | ||
521 | pCifsFile->netfid = netfid; | ||
522 | pCifsFile->invalidHandle = false; | ||
523 | mutex_unlock(&pCifsFile->fh_mutex); | ||
524 | pCifsInode = CIFS_I(inode); | ||
525 | if (pCifsInode) { | ||
526 | if (can_flush) { | ||
527 | rc = filemap_write_and_wait(inode->i_mapping); | ||
528 | if (rc != 0) | ||
529 | CIFS_I(inode)->write_behind_rc = rc; | ||
530 | /* temporarily disable caching while we | ||
531 | go to server to get inode info */ | ||
532 | pCifsInode->clientCanCacheAll = false; | ||
533 | pCifsInode->clientCanCacheRead = false; | ||
534 | if (tcon->unix_ext) | ||
535 | rc = cifs_get_inode_info_unix(&inode, | ||
536 | full_path, inode->i_sb, xid); | ||
537 | else | ||
538 | rc = cifs_get_inode_info(&inode, | ||
539 | full_path, NULL, inode->i_sb, | ||
540 | xid, NULL); | ||
541 | } /* else we are writing out data to server already | ||
542 | and could deadlock if we tried to flush data, and | ||
543 | since we do not know if we have data that would | ||
544 | invalidate the current end of file on the server | ||
545 | we can not go to the server to get the new inod | ||
546 | info */ | ||
547 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
548 | pCifsInode->clientCanCacheAll = true; | ||
549 | pCifsInode->clientCanCacheRead = true; | ||
550 | cFYI(1, "Exclusive Oplock granted on inode %p", | ||
551 | file->f_path.dentry->d_inode); | ||
552 | } else if ((oplock & 0xF) == OPLOCK_READ) { | ||
553 | pCifsInode->clientCanCacheRead = true; | ||
554 | pCifsInode->clientCanCacheAll = false; | ||
555 | } else { | ||
556 | pCifsInode->clientCanCacheRead = false; | ||
557 | pCifsInode->clientCanCacheAll = false; | ||
558 | } | ||
559 | cifs_relock_file(pCifsFile); | ||
560 | } | ||
561 | } | 540 | } |
541 | |||
542 | reopen_success: | ||
543 | pCifsFile->netfid = netfid; | ||
544 | pCifsFile->invalidHandle = false; | ||
545 | mutex_unlock(&pCifsFile->fh_mutex); | ||
546 | pCifsInode = CIFS_I(inode); | ||
547 | |||
548 | if (can_flush) { | ||
549 | rc = filemap_write_and_wait(inode->i_mapping); | ||
550 | mapping_set_error(inode->i_mapping, rc); | ||
551 | |||
552 | if (tcon->unix_ext) | ||
553 | rc = cifs_get_inode_info_unix(&inode, | ||
554 | full_path, inode->i_sb, xid); | ||
555 | else | ||
556 | rc = cifs_get_inode_info(&inode, | ||
557 | full_path, NULL, inode->i_sb, | ||
558 | xid, NULL); | ||
559 | } /* else we are writing out data to server already | ||
560 | and could deadlock if we tried to flush data, and | ||
561 | since we do not know if we have data that would | ||
562 | invalidate the current end of file on the server | ||
563 | we can not go to the server to get the new inod | ||
564 | info */ | ||
565 | |||
566 | cifs_set_oplock_level(pCifsInode, oplock); | ||
567 | |||
568 | cifs_relock_file(pCifsFile); | ||
569 | |||
570 | reopen_error_exit: | ||
562 | kfree(full_path); | 571 | kfree(full_path); |
563 | FreeXid(xid); | 572 | FreeXid(xid); |
564 | return rc; | 573 | return rc; |
@@ -566,79 +575,13 @@ reopen_success: | |||
566 | 575 | ||
567 | int cifs_close(struct inode *inode, struct file *file) | 576 | int cifs_close(struct inode *inode, struct file *file) |
568 | { | 577 | { |
569 | int rc = 0; | 578 | if (file->private_data != NULL) { |
570 | int xid, timeout; | ||
571 | struct cifs_sb_info *cifs_sb; | ||
572 | struct cifsTconInfo *pTcon; | ||
573 | struct cifsFileInfo *pSMBFile = file->private_data; | ||
574 | |||
575 | xid = GetXid(); | ||
576 | |||
577 | cifs_sb = CIFS_SB(inode->i_sb); | ||
578 | pTcon = cifs_sb->tcon; | ||
579 | if (pSMBFile) { | ||
580 | struct cifsLockInfo *li, *tmp; | ||
581 | write_lock(&GlobalSMBSeslock); | ||
582 | pSMBFile->closePend = true; | ||
583 | if (pTcon) { | ||
584 | /* no sense reconnecting to close a file that is | ||
585 | already closed */ | ||
586 | if (!pTcon->need_reconnect) { | ||
587 | write_unlock(&GlobalSMBSeslock); | ||
588 | timeout = 2; | ||
589 | while ((atomic_read(&pSMBFile->count) != 1) | ||
590 | && (timeout <= 2048)) { | ||
591 | /* Give write a better chance to get to | ||
592 | server ahead of the close. We do not | ||
593 | want to add a wait_q here as it would | ||
594 | increase the memory utilization as | ||
595 | the struct would be in each open file, | ||
596 | but this should give enough time to | ||
597 | clear the socket */ | ||
598 | cFYI(DBG2, "close delay, write pending"); | ||
599 | msleep(timeout); | ||
600 | timeout *= 4; | ||
601 | } | ||
602 | if (!pTcon->need_reconnect && | ||
603 | !pSMBFile->invalidHandle) | ||
604 | rc = CIFSSMBClose(xid, pTcon, | ||
605 | pSMBFile->netfid); | ||
606 | } else | ||
607 | write_unlock(&GlobalSMBSeslock); | ||
608 | } else | ||
609 | write_unlock(&GlobalSMBSeslock); | ||
610 | |||
611 | /* Delete any outstanding lock records. | ||
612 | We'll lose them when the file is closed anyway. */ | ||
613 | mutex_lock(&pSMBFile->lock_mutex); | ||
614 | list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) { | ||
615 | list_del(&li->llist); | ||
616 | kfree(li); | ||
617 | } | ||
618 | mutex_unlock(&pSMBFile->lock_mutex); | ||
619 | |||
620 | write_lock(&GlobalSMBSeslock); | ||
621 | list_del(&pSMBFile->flist); | ||
622 | list_del(&pSMBFile->tlist); | ||
623 | write_unlock(&GlobalSMBSeslock); | ||
624 | cifsFileInfo_put(file->private_data); | 579 | cifsFileInfo_put(file->private_data); |
625 | file->private_data = NULL; | 580 | file->private_data = NULL; |
626 | } else | ||
627 | rc = -EBADF; | ||
628 | |||
629 | read_lock(&GlobalSMBSeslock); | ||
630 | if (list_empty(&(CIFS_I(inode)->openFileList))) { | ||
631 | cFYI(1, "closing last open instance for inode %p", inode); | ||
632 | /* if the file is not open we do not know if we can cache info | ||
633 | on this inode, much less write behind and read ahead */ | ||
634 | CIFS_I(inode)->clientCanCacheRead = false; | ||
635 | CIFS_I(inode)->clientCanCacheAll = false; | ||
636 | } | 581 | } |
637 | read_unlock(&GlobalSMBSeslock); | 582 | |
638 | if ((rc == 0) && CIFS_I(inode)->write_behind_rc) | 583 | /* return code from the ->release op is always ignored */ |
639 | rc = CIFS_I(inode)->write_behind_rc; | 584 | return 0; |
640 | FreeXid(xid); | ||
641 | return rc; | ||
642 | } | 585 | } |
643 | 586 | ||
644 | int cifs_closedir(struct inode *inode, struct file *file) | 587 | int cifs_closedir(struct inode *inode, struct file *file) |
@@ -653,25 +596,21 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
653 | xid = GetXid(); | 596 | xid = GetXid(); |
654 | 597 | ||
655 | if (pCFileStruct) { | 598 | if (pCFileStruct) { |
656 | struct cifsTconInfo *pTcon; | 599 | struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink); |
657 | struct cifs_sb_info *cifs_sb = | ||
658 | CIFS_SB(file->f_path.dentry->d_sb); | ||
659 | |||
660 | pTcon = cifs_sb->tcon; | ||
661 | 600 | ||
662 | cFYI(1, "Freeing private data in close dir"); | 601 | cFYI(1, "Freeing private data in close dir"); |
663 | write_lock(&GlobalSMBSeslock); | 602 | spin_lock(&cifs_file_list_lock); |
664 | if (!pCFileStruct->srch_inf.endOfSearch && | 603 | if (!pCFileStruct->srch_inf.endOfSearch && |
665 | !pCFileStruct->invalidHandle) { | 604 | !pCFileStruct->invalidHandle) { |
666 | pCFileStruct->invalidHandle = true; | 605 | pCFileStruct->invalidHandle = true; |
667 | write_unlock(&GlobalSMBSeslock); | 606 | spin_unlock(&cifs_file_list_lock); |
668 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); | 607 | rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid); |
669 | cFYI(1, "Closing uncompleted readdir with rc %d", | 608 | cFYI(1, "Closing uncompleted readdir with rc %d", |
670 | rc); | 609 | rc); |
671 | /* not much we can do if it fails anyway, ignore rc */ | 610 | /* not much we can do if it fails anyway, ignore rc */ |
672 | rc = 0; | 611 | rc = 0; |
673 | } else | 612 | } else |
674 | write_unlock(&GlobalSMBSeslock); | 613 | spin_unlock(&cifs_file_list_lock); |
675 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | 614 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; |
676 | if (ptmp) { | 615 | if (ptmp) { |
677 | cFYI(1, "closedir free smb buf in srch struct"); | 616 | cFYI(1, "closedir free smb buf in srch struct"); |
@@ -681,6 +620,7 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
681 | else | 620 | else |
682 | cifs_buf_release(ptmp); | 621 | cifs_buf_release(ptmp); |
683 | } | 622 | } |
623 | cifs_put_tlink(pCFileStruct->tlink); | ||
684 | kfree(file->private_data); | 624 | kfree(file->private_data); |
685 | file->private_data = NULL; | 625 | file->private_data = NULL; |
686 | } | 626 | } |
@@ -713,7 +653,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
713 | __u64 length; | 653 | __u64 length; |
714 | bool wait_flag = false; | 654 | bool wait_flag = false; |
715 | struct cifs_sb_info *cifs_sb; | 655 | struct cifs_sb_info *cifs_sb; |
716 | struct cifsTconInfo *tcon; | 656 | struct cifs_tcon *tcon; |
717 | __u16 netfid; | 657 | __u16 netfid; |
718 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; | 658 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; |
719 | bool posix_locking = 0; | 659 | bool posix_locking = 0; |
@@ -767,13 +707,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
767 | cFYI(1, "Unknown type of lock"); | 707 | cFYI(1, "Unknown type of lock"); |
768 | 708 | ||
769 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 709 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
770 | tcon = cifs_sb->tcon; | 710 | tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink); |
771 | |||
772 | if (file->private_data == NULL) { | ||
773 | rc = -EBADF; | ||
774 | FreeXid(xid); | ||
775 | return rc; | ||
776 | } | ||
777 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 711 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
778 | 712 | ||
779 | if ((tcon->ses->capabilities & CAP_UNIX) && | 713 | if ((tcon->ses->capabilities & CAP_UNIX) && |
@@ -791,20 +725,20 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
791 | else | 725 | else |
792 | posix_lock_type = CIFS_WRLCK; | 726 | posix_lock_type = CIFS_WRLCK; |
793 | rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */, | 727 | rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */, |
794 | length, pfLock, | 728 | length, pfLock, posix_lock_type, |
795 | posix_lock_type, wait_flag); | 729 | wait_flag); |
796 | FreeXid(xid); | 730 | FreeXid(xid); |
797 | return rc; | 731 | return rc; |
798 | } | 732 | } |
799 | 733 | ||
800 | /* BB we could chain these into one lock request BB */ | 734 | /* BB we could chain these into one lock request BB */ |
801 | rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, | 735 | rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, |
802 | 0, 1, lockType, 0 /* wait flag */ ); | 736 | 0, 1, lockType, 0 /* wait flag */, 0); |
803 | if (rc == 0) { | 737 | if (rc == 0) { |
804 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 738 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
805 | pfLock->fl_start, 1 /* numUnlock */ , | 739 | pfLock->fl_start, 1 /* numUnlock */ , |
806 | 0 /* numLock */ , lockType, | 740 | 0 /* numLock */ , lockType, |
807 | 0 /* wait flag */ ); | 741 | 0 /* wait flag */, 0); |
808 | pfLock->fl_type = F_UNLCK; | 742 | pfLock->fl_type = F_UNLCK; |
809 | if (rc != 0) | 743 | if (rc != 0) |
810 | cERROR(1, "Error unlocking previously locked " | 744 | cERROR(1, "Error unlocking previously locked " |
@@ -821,13 +755,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
821 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 755 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
822 | pfLock->fl_start, 0, 1, | 756 | pfLock->fl_start, 0, 1, |
823 | lockType | LOCKING_ANDX_SHARED_LOCK, | 757 | lockType | LOCKING_ANDX_SHARED_LOCK, |
824 | 0 /* wait flag */); | 758 | 0 /* wait flag */, 0); |
825 | if (rc == 0) { | 759 | if (rc == 0) { |
826 | rc = CIFSSMBLock(xid, tcon, netfid, | 760 | rc = CIFSSMBLock(xid, tcon, netfid, |
827 | length, pfLock->fl_start, 1, 0, | 761 | length, pfLock->fl_start, 1, 0, |
828 | lockType | | 762 | lockType | |
829 | LOCKING_ANDX_SHARED_LOCK, | 763 | LOCKING_ANDX_SHARED_LOCK, |
830 | 0 /* wait flag */); | 764 | 0 /* wait flag */, 0); |
831 | pfLock->fl_type = F_RDLCK; | 765 | pfLock->fl_type = F_RDLCK; |
832 | if (rc != 0) | 766 | if (rc != 0) |
833 | cERROR(1, "Error unlocking " | 767 | cERROR(1, "Error unlocking " |
@@ -863,15 +797,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
863 | posix_lock_type = CIFS_UNLCK; | 797 | posix_lock_type = CIFS_UNLCK; |
864 | 798 | ||
865 | rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, | 799 | rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, |
866 | length, pfLock, | 800 | length, pfLock, posix_lock_type, |
867 | posix_lock_type, wait_flag); | 801 | wait_flag); |
868 | } else { | 802 | } else { |
869 | struct cifsFileInfo *fid = file->private_data; | 803 | struct cifsFileInfo *fid = file->private_data; |
870 | 804 | ||
871 | if (numLock) { | 805 | if (numLock) { |
872 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 806 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
873 | pfLock->fl_start, | 807 | pfLock->fl_start, 0, numLock, lockType, |
874 | 0, numLock, lockType, wait_flag); | 808 | wait_flag, 0); |
875 | 809 | ||
876 | if (rc == 0) { | 810 | if (rc == 0) { |
877 | /* For Windows locks we must store them. */ | 811 | /* For Windows locks we must store them. */ |
@@ -891,9 +825,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
891 | (pfLock->fl_start + length) >= | 825 | (pfLock->fl_start + length) >= |
892 | (li->offset + li->length)) { | 826 | (li->offset + li->length)) { |
893 | stored_rc = CIFSSMBLock(xid, tcon, | 827 | stored_rc = CIFSSMBLock(xid, tcon, |
894 | netfid, | 828 | netfid, li->length, |
895 | li->length, li->offset, | 829 | li->offset, 1, 0, |
896 | 1, 0, li->type, false); | 830 | li->type, false, 0); |
897 | if (stored_rc) | 831 | if (stored_rc) |
898 | rc = stored_rc; | 832 | rc = stored_rc; |
899 | else { | 833 | else { |
@@ -912,31 +846,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
912 | return rc; | 846 | return rc; |
913 | } | 847 | } |
914 | 848 | ||
915 | /* | ||
916 | * Set the timeout on write requests past EOF. For some servers (Windows) | ||
917 | * these calls can be very long. | ||
918 | * | ||
919 | * If we're writing >10M past the EOF we give a 180s timeout. Anything less | ||
920 | * than that gets a 45s timeout. Writes not past EOF get 15s timeouts. | ||
921 | * The 10M cutoff is totally arbitrary. A better scheme for this would be | ||
922 | * welcome if someone wants to suggest one. | ||
923 | * | ||
924 | * We may be able to do a better job with this if there were some way to | ||
925 | * declare that a file should be sparse. | ||
926 | */ | ||
927 | static int | ||
928 | cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset) | ||
929 | { | ||
930 | if (offset <= cifsi->server_eof) | ||
931 | return CIFS_STD_OP; | ||
932 | else if (offset > (cifsi->server_eof + (10 * 1024 * 1024))) | ||
933 | return CIFS_VLONG_OP; | ||
934 | else | ||
935 | return CIFS_LONG_OP; | ||
936 | } | ||
937 | |||
938 | /* update the file size (if needed) after a write */ | 849 | /* update the file size (if needed) after a write */ |
939 | static void | 850 | void |
940 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 851 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
941 | unsigned int bytes_written) | 852 | unsigned int bytes_written) |
942 | { | 853 | { |
@@ -946,188 +857,58 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | |||
946 | cifsi->server_eof = end_of_write; | 857 | cifsi->server_eof = end_of_write; |
947 | } | 858 | } |
948 | 859 | ||
949 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 860 | static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid, |
950 | size_t write_size, loff_t *poffset) | 861 | const char *write_data, size_t write_size, |
862 | loff_t *poffset) | ||
951 | { | 863 | { |
952 | int rc = 0; | 864 | int rc = 0; |
953 | unsigned int bytes_written = 0; | 865 | unsigned int bytes_written = 0; |
954 | unsigned int total_written; | 866 | unsigned int total_written; |
955 | struct cifs_sb_info *cifs_sb; | 867 | struct cifs_sb_info *cifs_sb; |
956 | struct cifsTconInfo *pTcon; | 868 | struct cifs_tcon *pTcon; |
957 | int xid, long_op; | 869 | int xid; |
958 | struct cifsFileInfo *open_file; | 870 | struct dentry *dentry = open_file->dentry; |
959 | struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | 871 | struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); |
960 | 872 | struct cifs_io_parms io_parms; | |
961 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
962 | |||
963 | pTcon = cifs_sb->tcon; | ||
964 | |||
965 | /* cFYI(1, " write %d bytes to offset %lld of %s", write_size, | ||
966 | *poffset, file->f_path.dentry->d_name.name); */ | ||
967 | |||
968 | if (file->private_data == NULL) | ||
969 | return -EBADF; | ||
970 | open_file = file->private_data; | ||
971 | |||
972 | rc = generic_write_checks(file, poffset, &write_size, 0); | ||
973 | if (rc) | ||
974 | return rc; | ||
975 | |||
976 | xid = GetXid(); | ||
977 | |||
978 | long_op = cifs_write_timeout(cifsi, *poffset); | ||
979 | for (total_written = 0; write_size > total_written; | ||
980 | total_written += bytes_written) { | ||
981 | rc = -EAGAIN; | ||
982 | while (rc == -EAGAIN) { | ||
983 | if (file->private_data == NULL) { | ||
984 | /* file has been closed on us */ | ||
985 | FreeXid(xid); | ||
986 | /* if we have gotten here we have written some data | ||
987 | and blocked, and the file has been freed on us while | ||
988 | we blocked so return what we managed to write */ | ||
989 | return total_written; | ||
990 | } | ||
991 | if (open_file->closePend) { | ||
992 | FreeXid(xid); | ||
993 | if (total_written) | ||
994 | return total_written; | ||
995 | else | ||
996 | return -EBADF; | ||
997 | } | ||
998 | if (open_file->invalidHandle) { | ||
999 | /* we could deadlock if we called | ||
1000 | filemap_fdatawait from here so tell | ||
1001 | reopen_file not to flush data to server | ||
1002 | now */ | ||
1003 | rc = cifs_reopen_file(file, false); | ||
1004 | if (rc != 0) | ||
1005 | break; | ||
1006 | } | ||
1007 | |||
1008 | rc = CIFSSMBWrite(xid, pTcon, | ||
1009 | open_file->netfid, | ||
1010 | min_t(const int, cifs_sb->wsize, | ||
1011 | write_size - total_written), | ||
1012 | *poffset, &bytes_written, | ||
1013 | NULL, write_data + total_written, long_op); | ||
1014 | } | ||
1015 | if (rc || (bytes_written == 0)) { | ||
1016 | if (total_written) | ||
1017 | break; | ||
1018 | else { | ||
1019 | FreeXid(xid); | ||
1020 | return rc; | ||
1021 | } | ||
1022 | } else { | ||
1023 | cifs_update_eof(cifsi, *poffset, bytes_written); | ||
1024 | *poffset += bytes_written; | ||
1025 | } | ||
1026 | long_op = CIFS_STD_OP; /* subsequent writes fast - | ||
1027 | 15 seconds is plenty */ | ||
1028 | } | ||
1029 | |||
1030 | cifs_stats_bytes_written(pTcon, total_written); | ||
1031 | |||
1032 | /* since the write may have blocked check these pointers again */ | ||
1033 | if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) { | ||
1034 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1035 | /* Do not update local mtime - server will set its actual value on write | ||
1036 | * inode->i_ctime = inode->i_mtime = | ||
1037 | * current_fs_time(inode->i_sb);*/ | ||
1038 | if (total_written > 0) { | ||
1039 | spin_lock(&inode->i_lock); | ||
1040 | if (*poffset > file->f_path.dentry->d_inode->i_size) | ||
1041 | i_size_write(file->f_path.dentry->d_inode, | ||
1042 | *poffset); | ||
1043 | spin_unlock(&inode->i_lock); | ||
1044 | } | ||
1045 | mark_inode_dirty_sync(file->f_path.dentry->d_inode); | ||
1046 | } | ||
1047 | FreeXid(xid); | ||
1048 | return total_written; | ||
1049 | } | ||
1050 | |||
1051 | static ssize_t cifs_write(struct file *file, const char *write_data, | ||
1052 | size_t write_size, loff_t *poffset) | ||
1053 | { | ||
1054 | int rc = 0; | ||
1055 | unsigned int bytes_written = 0; | ||
1056 | unsigned int total_written; | ||
1057 | struct cifs_sb_info *cifs_sb; | ||
1058 | struct cifsTconInfo *pTcon; | ||
1059 | int xid, long_op; | ||
1060 | struct cifsFileInfo *open_file; | ||
1061 | struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | ||
1062 | |||
1063 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1064 | 873 | ||
1065 | pTcon = cifs_sb->tcon; | 874 | cifs_sb = CIFS_SB(dentry->d_sb); |
1066 | 875 | ||
1067 | cFYI(1, "write %zd bytes to offset %lld of %s", write_size, | 876 | cFYI(1, "write %zd bytes to offset %lld of %s", write_size, |
1068 | *poffset, file->f_path.dentry->d_name.name); | 877 | *poffset, dentry->d_name.name); |
1069 | 878 | ||
1070 | if (file->private_data == NULL) | 879 | pTcon = tlink_tcon(open_file->tlink); |
1071 | return -EBADF; | ||
1072 | open_file = file->private_data; | ||
1073 | 880 | ||
1074 | xid = GetXid(); | 881 | xid = GetXid(); |
1075 | 882 | ||
1076 | long_op = cifs_write_timeout(cifsi, *poffset); | ||
1077 | for (total_written = 0; write_size > total_written; | 883 | for (total_written = 0; write_size > total_written; |
1078 | total_written += bytes_written) { | 884 | total_written += bytes_written) { |
1079 | rc = -EAGAIN; | 885 | rc = -EAGAIN; |
1080 | while (rc == -EAGAIN) { | 886 | while (rc == -EAGAIN) { |
1081 | if (file->private_data == NULL) { | 887 | struct kvec iov[2]; |
1082 | /* file has been closed on us */ | 888 | unsigned int len; |
1083 | FreeXid(xid); | 889 | |
1084 | /* if we have gotten here we have written some data | ||
1085 | and blocked, and the file has been freed on us | ||
1086 | while we blocked so return what we managed to | ||
1087 | write */ | ||
1088 | return total_written; | ||
1089 | } | ||
1090 | if (open_file->closePend) { | ||
1091 | FreeXid(xid); | ||
1092 | if (total_written) | ||
1093 | return total_written; | ||
1094 | else | ||
1095 | return -EBADF; | ||
1096 | } | ||
1097 | if (open_file->invalidHandle) { | 890 | if (open_file->invalidHandle) { |
1098 | /* we could deadlock if we called | 891 | /* we could deadlock if we called |
1099 | filemap_fdatawait from here so tell | 892 | filemap_fdatawait from here so tell |
1100 | reopen_file not to flush data to | 893 | reopen_file not to flush data to |
1101 | server now */ | 894 | server now */ |
1102 | rc = cifs_reopen_file(file, false); | 895 | rc = cifs_reopen_file(open_file, false); |
1103 | if (rc != 0) | 896 | if (rc != 0) |
1104 | break; | 897 | break; |
1105 | } | 898 | } |
1106 | if (experimEnabled || (pTcon->ses->server && | 899 | |
1107 | ((pTcon->ses->server->secMode & | 900 | len = min((size_t)cifs_sb->wsize, |
1108 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 901 | write_size - total_written); |
1109 | == 0))) { | 902 | /* iov[0] is reserved for smb header */ |
1110 | struct kvec iov[2]; | 903 | iov[1].iov_base = (char *)write_data + total_written; |
1111 | unsigned int len; | 904 | iov[1].iov_len = len; |
1112 | 905 | io_parms.netfid = open_file->netfid; | |
1113 | len = min((size_t)cifs_sb->wsize, | 906 | io_parms.pid = pid; |
1114 | write_size - total_written); | 907 | io_parms.tcon = pTcon; |
1115 | /* iov[0] is reserved for smb header */ | 908 | io_parms.offset = *poffset; |
1116 | iov[1].iov_base = (char *)write_data + | 909 | io_parms.length = len; |
1117 | total_written; | 910 | rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov, |
1118 | iov[1].iov_len = len; | 911 | 1, 0); |
1119 | rc = CIFSSMBWrite2(xid, pTcon, | ||
1120 | open_file->netfid, len, | ||
1121 | *poffset, &bytes_written, | ||
1122 | iov, 1, long_op); | ||
1123 | } else | ||
1124 | rc = CIFSSMBWrite(xid, pTcon, | ||
1125 | open_file->netfid, | ||
1126 | min_t(const int, cifs_sb->wsize, | ||
1127 | write_size - total_written), | ||
1128 | *poffset, &bytes_written, | ||
1129 | write_data + total_written, | ||
1130 | NULL, long_op); | ||
1131 | } | 912 | } |
1132 | if (rc || (bytes_written == 0)) { | 913 | if (rc || (bytes_written == 0)) { |
1133 | if (total_written) | 914 | if (total_written) |
@@ -1140,49 +921,44 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
1140 | cifs_update_eof(cifsi, *poffset, bytes_written); | 921 | cifs_update_eof(cifsi, *poffset, bytes_written); |
1141 | *poffset += bytes_written; | 922 | *poffset += bytes_written; |
1142 | } | 923 | } |
1143 | long_op = CIFS_STD_OP; /* subsequent writes fast - | ||
1144 | 15 seconds is plenty */ | ||
1145 | } | 924 | } |
1146 | 925 | ||
1147 | cifs_stats_bytes_written(pTcon, total_written); | 926 | cifs_stats_bytes_written(pTcon, total_written); |
1148 | 927 | ||
1149 | /* since the write may have blocked check these pointers again */ | 928 | if (total_written > 0) { |
1150 | if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) { | 929 | spin_lock(&dentry->d_inode->i_lock); |
1151 | /*BB We could make this contingent on superblock ATIME flag too */ | 930 | if (*poffset > dentry->d_inode->i_size) |
1152 | /* file->f_path.dentry->d_inode->i_ctime = | 931 | i_size_write(dentry->d_inode, *poffset); |
1153 | file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/ | 932 | spin_unlock(&dentry->d_inode->i_lock); |
1154 | if (total_written > 0) { | ||
1155 | spin_lock(&file->f_path.dentry->d_inode->i_lock); | ||
1156 | if (*poffset > file->f_path.dentry->d_inode->i_size) | ||
1157 | i_size_write(file->f_path.dentry->d_inode, | ||
1158 | *poffset); | ||
1159 | spin_unlock(&file->f_path.dentry->d_inode->i_lock); | ||
1160 | } | ||
1161 | mark_inode_dirty_sync(file->f_path.dentry->d_inode); | ||
1162 | } | 933 | } |
934 | mark_inode_dirty_sync(dentry->d_inode); | ||
1163 | FreeXid(xid); | 935 | FreeXid(xid); |
1164 | return total_written; | 936 | return total_written; |
1165 | } | 937 | } |
1166 | 938 | ||
1167 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 939 | struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, |
1168 | struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | 940 | bool fsuid_only) |
1169 | { | 941 | { |
1170 | struct cifsFileInfo *open_file = NULL; | 942 | struct cifsFileInfo *open_file = NULL; |
943 | struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); | ||
1171 | 944 | ||
1172 | read_lock(&GlobalSMBSeslock); | 945 | /* only filter by fsuid on multiuser mounts */ |
946 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | ||
947 | fsuid_only = false; | ||
948 | |||
949 | spin_lock(&cifs_file_list_lock); | ||
1173 | /* we could simply get the first_list_entry since write-only entries | 950 | /* we could simply get the first_list_entry since write-only entries |
1174 | are always at the end of the list but since the first entry might | 951 | are always at the end of the list but since the first entry might |
1175 | have a close pending, we go through the whole list */ | 952 | have a close pending, we go through the whole list */ |
1176 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 953 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1177 | if (open_file->closePend) | 954 | if (fsuid_only && open_file->uid != current_fsuid()) |
1178 | continue; | 955 | continue; |
1179 | if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) || | 956 | if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { |
1180 | (open_file->pfile->f_flags & O_RDONLY))) { | ||
1181 | if (!open_file->invalidHandle) { | 957 | if (!open_file->invalidHandle) { |
1182 | /* found a good file */ | 958 | /* found a good file */ |
1183 | /* lock it so it will not be closed on us */ | 959 | /* lock it so it will not be closed on us */ |
1184 | cifsFileInfo_get(open_file); | 960 | cifsFileInfo_get(open_file); |
1185 | read_unlock(&GlobalSMBSeslock); | 961 | spin_unlock(&cifs_file_list_lock); |
1186 | return open_file; | 962 | return open_file; |
1187 | } /* else might as well continue, and look for | 963 | } /* else might as well continue, and look for |
1188 | another, or simply have the caller reopen it | 964 | another, or simply have the caller reopen it |
@@ -1190,14 +966,15 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode) | |||
1190 | } else /* write only file */ | 966 | } else /* write only file */ |
1191 | break; /* write only files are last so must be done */ | 967 | break; /* write only files are last so must be done */ |
1192 | } | 968 | } |
1193 | read_unlock(&GlobalSMBSeslock); | 969 | spin_unlock(&cifs_file_list_lock); |
1194 | return NULL; | 970 | return NULL; |
1195 | } | 971 | } |
1196 | #endif | ||
1197 | 972 | ||
1198 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | 973 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, |
974 | bool fsuid_only) | ||
1199 | { | 975 | { |
1200 | struct cifsFileInfo *open_file; | 976 | struct cifsFileInfo *open_file; |
977 | struct cifs_sb_info *cifs_sb; | ||
1201 | bool any_available = false; | 978 | bool any_available = false; |
1202 | int rc; | 979 | int rc; |
1203 | 980 | ||
@@ -1211,53 +988,41 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | |||
1211 | return NULL; | 988 | return NULL; |
1212 | } | 989 | } |
1213 | 990 | ||
1214 | read_lock(&GlobalSMBSeslock); | 991 | cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); |
992 | |||
993 | /* only filter by fsuid on multiuser mounts */ | ||
994 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | ||
995 | fsuid_only = false; | ||
996 | |||
997 | spin_lock(&cifs_file_list_lock); | ||
1215 | refind_writable: | 998 | refind_writable: |
1216 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 999 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1217 | if (open_file->closePend || | 1000 | if (!any_available && open_file->pid != current->tgid) |
1218 | (!any_available && open_file->pid != current->tgid)) | ||
1219 | continue; | 1001 | continue; |
1220 | 1002 | if (fsuid_only && open_file->uid != current_fsuid()) | |
1221 | if (open_file->pfile && | 1003 | continue; |
1222 | ((open_file->pfile->f_flags & O_RDWR) || | 1004 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
1223 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1224 | cifsFileInfo_get(open_file); | 1005 | cifsFileInfo_get(open_file); |
1225 | 1006 | ||
1226 | if (!open_file->invalidHandle) { | 1007 | if (!open_file->invalidHandle) { |
1227 | /* found a good writable file */ | 1008 | /* found a good writable file */ |
1228 | read_unlock(&GlobalSMBSeslock); | 1009 | spin_unlock(&cifs_file_list_lock); |
1229 | return open_file; | 1010 | return open_file; |
1230 | } | 1011 | } |
1231 | 1012 | ||
1232 | read_unlock(&GlobalSMBSeslock); | 1013 | spin_unlock(&cifs_file_list_lock); |
1014 | |||
1233 | /* Had to unlock since following call can block */ | 1015 | /* Had to unlock since following call can block */ |
1234 | rc = cifs_reopen_file(open_file->pfile, false); | 1016 | rc = cifs_reopen_file(open_file, false); |
1235 | if (!rc) { | 1017 | if (!rc) |
1236 | if (!open_file->closePend) | 1018 | return open_file; |
1237 | return open_file; | ||
1238 | else { /* start over in case this was deleted */ | ||
1239 | /* since the list could be modified */ | ||
1240 | read_lock(&GlobalSMBSeslock); | ||
1241 | cifsFileInfo_put(open_file); | ||
1242 | goto refind_writable; | ||
1243 | } | ||
1244 | } | ||
1245 | 1019 | ||
1246 | /* if it fails, try another handle if possible - | 1020 | /* if it fails, try another handle if possible */ |
1247 | (we can not do this if closePending since | ||
1248 | loop could be modified - in which case we | ||
1249 | have to start at the beginning of the list | ||
1250 | again. Note that it would be bad | ||
1251 | to hold up writepages here (rather than | ||
1252 | in caller) with continuous retries */ | ||
1253 | cFYI(1, "wp failed on reopen file"); | 1021 | cFYI(1, "wp failed on reopen file"); |
1254 | read_lock(&GlobalSMBSeslock); | ||
1255 | /* can not use this handle, no write | ||
1256 | pending on this one after all */ | ||
1257 | cifsFileInfo_put(open_file); | 1022 | cifsFileInfo_put(open_file); |
1258 | 1023 | ||
1259 | if (open_file->closePend) /* list could have changed */ | 1024 | spin_lock(&cifs_file_list_lock); |
1260 | goto refind_writable; | 1025 | |
1261 | /* else we simply continue to the next entry. Thus | 1026 | /* else we simply continue to the next entry. Thus |
1262 | we do not loop on reopen errors. If we | 1027 | we do not loop on reopen errors. If we |
1263 | can not reopen the file, for example if we | 1028 | can not reopen the file, for example if we |
@@ -1272,7 +1037,7 @@ refind_writable: | |||
1272 | any_available = true; | 1037 | any_available = true; |
1273 | goto refind_writable; | 1038 | goto refind_writable; |
1274 | } | 1039 | } |
1275 | read_unlock(&GlobalSMBSeslock); | 1040 | spin_unlock(&cifs_file_list_lock); |
1276 | return NULL; | 1041 | return NULL; |
1277 | } | 1042 | } |
1278 | 1043 | ||
@@ -1283,8 +1048,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1283 | char *write_data; | 1048 | char *write_data; |
1284 | int rc = -EFAULT; | 1049 | int rc = -EFAULT; |
1285 | int bytes_written = 0; | 1050 | int bytes_written = 0; |
1286 | struct cifs_sb_info *cifs_sb; | ||
1287 | struct cifsTconInfo *pTcon; | ||
1288 | struct inode *inode; | 1051 | struct inode *inode; |
1289 | struct cifsFileInfo *open_file; | 1052 | struct cifsFileInfo *open_file; |
1290 | 1053 | ||
@@ -1292,8 +1055,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1292 | return -EFAULT; | 1055 | return -EFAULT; |
1293 | 1056 | ||
1294 | inode = page->mapping->host; | 1057 | inode = page->mapping->host; |
1295 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1296 | pTcon = cifs_sb->tcon; | ||
1297 | 1058 | ||
1298 | offset += (loff_t)from; | 1059 | offset += (loff_t)from; |
1299 | write_data = kmap(page); | 1060 | write_data = kmap(page); |
@@ -1314,10 +1075,10 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1314 | if (mapping->host->i_size - offset < (loff_t)to) | 1075 | if (mapping->host->i_size - offset < (loff_t)to) |
1315 | to = (unsigned)(mapping->host->i_size - offset); | 1076 | to = (unsigned)(mapping->host->i_size - offset); |
1316 | 1077 | ||
1317 | open_file = find_writable_file(CIFS_I(mapping->host)); | 1078 | open_file = find_writable_file(CIFS_I(mapping->host), false); |
1318 | if (open_file) { | 1079 | if (open_file) { |
1319 | bytes_written = cifs_write(open_file->pfile, write_data, | 1080 | bytes_written = cifs_write(open_file, open_file->pid, |
1320 | to-from, &offset); | 1081 | write_data, to - from, &offset); |
1321 | cifsFileInfo_put(open_file); | 1082 | cifsFileInfo_put(open_file); |
1322 | /* Does mm or vfs already set times? */ | 1083 | /* Does mm or vfs already set times? */ |
1323 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); | 1084 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
@@ -1337,61 +1098,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1337 | static int cifs_writepages(struct address_space *mapping, | 1098 | static int cifs_writepages(struct address_space *mapping, |
1338 | struct writeback_control *wbc) | 1099 | struct writeback_control *wbc) |
1339 | { | 1100 | { |
1340 | struct backing_dev_info *bdi = mapping->backing_dev_info; | 1101 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); |
1341 | unsigned int bytes_to_write; | 1102 | bool done = false, scanned = false, range_whole = false; |
1342 | unsigned int bytes_written; | 1103 | pgoff_t end, index; |
1343 | struct cifs_sb_info *cifs_sb; | 1104 | struct cifs_writedata *wdata; |
1344 | int done = 0; | ||
1345 | pgoff_t end; | ||
1346 | pgoff_t index; | ||
1347 | int range_whole = 0; | ||
1348 | struct kvec *iov; | ||
1349 | int len; | ||
1350 | int n_iov = 0; | ||
1351 | pgoff_t next; | ||
1352 | int nr_pages; | ||
1353 | __u64 offset = 0; | ||
1354 | struct cifsFileInfo *open_file; | ||
1355 | struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); | ||
1356 | struct page *page; | 1105 | struct page *page; |
1357 | struct pagevec pvec; | ||
1358 | int rc = 0; | 1106 | int rc = 0; |
1359 | int scanned = 0; | ||
1360 | int xid, long_op; | ||
1361 | |||
1362 | cifs_sb = CIFS_SB(mapping->host->i_sb); | ||
1363 | 1107 | ||
1364 | /* | 1108 | /* |
1365 | * If wsize is smaller that the page cache size, default to writing | 1109 | * If wsize is smaller than the page cache size, default to writing |
1366 | * one page at a time via cifs_writepage | 1110 | * one page at a time via cifs_writepage |
1367 | */ | 1111 | */ |
1368 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | 1112 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) |
1369 | return generic_writepages(mapping, wbc); | 1113 | return generic_writepages(mapping, wbc); |
1370 | 1114 | ||
1371 | if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) | ||
1372 | if (cifs_sb->tcon->ses->server->secMode & | ||
1373 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1374 | if (!experimEnabled) | ||
1375 | return generic_writepages(mapping, wbc); | ||
1376 | |||
1377 | iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); | ||
1378 | if (iov == NULL) | ||
1379 | return generic_writepages(mapping, wbc); | ||
1380 | |||
1381 | |||
1382 | /* | ||
1383 | * BB: Is this meaningful for a non-block-device file system? | ||
1384 | * If it is, we should test it again after we do I/O | ||
1385 | */ | ||
1386 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
1387 | wbc->encountered_congestion = 1; | ||
1388 | kfree(iov); | ||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | xid = GetXid(); | ||
1393 | |||
1394 | pagevec_init(&pvec, 0); | ||
1395 | if (wbc->range_cyclic) { | 1115 | if (wbc->range_cyclic) { |
1396 | index = mapping->writeback_index; /* Start from prev offset */ | 1116 | index = mapping->writeback_index; /* Start from prev offset */ |
1397 | end = -1; | 1117 | end = -1; |
@@ -1399,24 +1119,49 @@ static int cifs_writepages(struct address_space *mapping, | |||
1399 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | 1119 | index = wbc->range_start >> PAGE_CACHE_SHIFT; |
1400 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | 1120 | end = wbc->range_end >> PAGE_CACHE_SHIFT; |
1401 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | 1121 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) |
1402 | range_whole = 1; | 1122 | range_whole = true; |
1403 | scanned = 1; | 1123 | scanned = true; |
1404 | } | 1124 | } |
1405 | retry: | 1125 | retry: |
1406 | while (!done && (index <= end) && | 1126 | while (!done && index <= end) { |
1407 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | 1127 | unsigned int i, nr_pages, found_pages; |
1408 | PAGECACHE_TAG_DIRTY, | 1128 | pgoff_t next = 0, tofind; |
1409 | min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { | 1129 | struct page **pages; |
1410 | int first; | 1130 | |
1411 | unsigned int i; | 1131 | tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1, |
1412 | 1132 | end - index) + 1; | |
1413 | first = -1; | 1133 | |
1414 | next = 0; | 1134 | wdata = cifs_writedata_alloc((unsigned int)tofind); |
1415 | n_iov = 0; | 1135 | if (!wdata) { |
1416 | bytes_to_write = 0; | 1136 | rc = -ENOMEM; |
1417 | 1137 | break; | |
1418 | for (i = 0; i < nr_pages; i++) { | 1138 | } |
1419 | page = pvec.pages[i]; | 1139 | |
1140 | /* | ||
1141 | * find_get_pages_tag seems to return a max of 256 on each | ||
1142 | * iteration, so we must call it several times in order to | ||
1143 | * fill the array or the wsize is effectively limited to | ||
1144 | * 256 * PAGE_CACHE_SIZE. | ||
1145 | */ | ||
1146 | found_pages = 0; | ||
1147 | pages = wdata->pages; | ||
1148 | do { | ||
1149 | nr_pages = find_get_pages_tag(mapping, &index, | ||
1150 | PAGECACHE_TAG_DIRTY, | ||
1151 | tofind, pages); | ||
1152 | found_pages += nr_pages; | ||
1153 | tofind -= nr_pages; | ||
1154 | pages += nr_pages; | ||
1155 | } while (nr_pages && tofind && index <= end); | ||
1156 | |||
1157 | if (found_pages == 0) { | ||
1158 | kref_put(&wdata->refcount, cifs_writedata_release); | ||
1159 | break; | ||
1160 | } | ||
1161 | |||
1162 | nr_pages = 0; | ||
1163 | for (i = 0; i < found_pages; i++) { | ||
1164 | page = wdata->pages[i]; | ||
1420 | /* | 1165 | /* |
1421 | * At this point we hold neither mapping->tree_lock nor | 1166 | * At this point we hold neither mapping->tree_lock nor |
1422 | * lock on the page itself: the page may be truncated or | 1167 | * lock on the page itself: the page may be truncated or |
@@ -1425,7 +1170,7 @@ retry: | |||
1425 | * mapping | 1170 | * mapping |
1426 | */ | 1171 | */ |
1427 | 1172 | ||
1428 | if (first < 0) | 1173 | if (nr_pages == 0) |
1429 | lock_page(page); | 1174 | lock_page(page); |
1430 | else if (!trylock_page(page)) | 1175 | else if (!trylock_page(page)) |
1431 | break; | 1176 | break; |
@@ -1436,7 +1181,7 @@ retry: | |||
1436 | } | 1181 | } |
1437 | 1182 | ||
1438 | if (!wbc->range_cyclic && page->index > end) { | 1183 | if (!wbc->range_cyclic && page->index > end) { |
1439 | done = 1; | 1184 | done = true; |
1440 | unlock_page(page); | 1185 | unlock_page(page); |
1441 | break; | 1186 | break; |
1442 | } | 1187 | } |
@@ -1463,110 +1208,96 @@ retry: | |||
1463 | set_page_writeback(page); | 1208 | set_page_writeback(page); |
1464 | 1209 | ||
1465 | if (page_offset(page) >= mapping->host->i_size) { | 1210 | if (page_offset(page) >= mapping->host->i_size) { |
1466 | done = 1; | 1211 | done = true; |
1467 | unlock_page(page); | 1212 | unlock_page(page); |
1468 | end_page_writeback(page); | 1213 | end_page_writeback(page); |
1469 | break; | 1214 | break; |
1470 | } | 1215 | } |
1471 | 1216 | ||
1472 | /* | 1217 | wdata->pages[i] = page; |
1473 | * BB can we get rid of this? pages are held by pvec | 1218 | next = page->index + 1; |
1474 | */ | 1219 | ++nr_pages; |
1475 | page_cache_get(page); | 1220 | } |
1476 | 1221 | ||
1477 | len = min(mapping->host->i_size - page_offset(page), | 1222 | /* reset index to refind any pages skipped */ |
1478 | (loff_t)PAGE_CACHE_SIZE); | 1223 | if (nr_pages == 0) |
1224 | index = wdata->pages[0]->index + 1; | ||
1479 | 1225 | ||
1480 | /* reserve iov[0] for the smb header */ | 1226 | /* put any pages we aren't going to use */ |
1481 | n_iov++; | 1227 | for (i = nr_pages; i < found_pages; i++) { |
1482 | iov[n_iov].iov_base = kmap(page); | 1228 | page_cache_release(wdata->pages[i]); |
1483 | iov[n_iov].iov_len = len; | 1229 | wdata->pages[i] = NULL; |
1484 | bytes_to_write += len; | 1230 | } |
1485 | 1231 | ||
1486 | if (first < 0) { | 1232 | /* nothing to write? */ |
1487 | first = i; | 1233 | if (nr_pages == 0) { |
1488 | offset = page_offset(page); | 1234 | kref_put(&wdata->refcount, cifs_writedata_release); |
1489 | } | 1235 | continue; |
1490 | next = page->index + 1; | ||
1491 | if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) | ||
1492 | break; | ||
1493 | } | 1236 | } |
1494 | if (n_iov) { | 1237 | |
1495 | /* Search for a writable handle every time we call | 1238 | wdata->sync_mode = wbc->sync_mode; |
1496 | * CIFSSMBWrite2. We can't rely on the last handle | 1239 | wdata->nr_pages = nr_pages; |
1497 | * we used to still be valid | 1240 | wdata->offset = page_offset(wdata->pages[0]); |
1498 | */ | 1241 | |
1499 | open_file = find_writable_file(CIFS_I(mapping->host)); | 1242 | do { |
1500 | if (!open_file) { | 1243 | if (wdata->cfile != NULL) |
1244 | cifsFileInfo_put(wdata->cfile); | ||
1245 | wdata->cfile = find_writable_file(CIFS_I(mapping->host), | ||
1246 | false); | ||
1247 | if (!wdata->cfile) { | ||
1501 | cERROR(1, "No writable handles for inode"); | 1248 | cERROR(1, "No writable handles for inode"); |
1502 | rc = -EBADF; | 1249 | rc = -EBADF; |
1503 | } else { | 1250 | break; |
1504 | long_op = cifs_write_timeout(cifsi, offset); | ||
1505 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, | ||
1506 | open_file->netfid, | ||
1507 | bytes_to_write, offset, | ||
1508 | &bytes_written, iov, n_iov, | ||
1509 | long_op); | ||
1510 | cifsFileInfo_put(open_file); | ||
1511 | cifs_update_eof(cifsi, offset, bytes_written); | ||
1512 | |||
1513 | if (rc || bytes_written < bytes_to_write) { | ||
1514 | cERROR(1, "Write2 ret %d, wrote %d", | ||
1515 | rc, bytes_written); | ||
1516 | /* BB what if continued retry is | ||
1517 | requested via mount flags? */ | ||
1518 | if (rc == -ENOSPC) | ||
1519 | set_bit(AS_ENOSPC, &mapping->flags); | ||
1520 | else | ||
1521 | set_bit(AS_EIO, &mapping->flags); | ||
1522 | } else { | ||
1523 | cifs_stats_bytes_written(cifs_sb->tcon, | ||
1524 | bytes_written); | ||
1525 | } | ||
1526 | } | 1251 | } |
1527 | for (i = 0; i < n_iov; i++) { | 1252 | rc = cifs_async_writev(wdata); |
1528 | page = pvec.pages[first + i]; | 1253 | } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN); |
1529 | /* Should we also set page error on | 1254 | |
1530 | success rc but too little data written? */ | 1255 | for (i = 0; i < nr_pages; ++i) |
1531 | /* BB investigate retry logic on temporary | 1256 | unlock_page(wdata->pages[i]); |
1532 | server crash cases and how recovery works | 1257 | |
1533 | when page marked as error */ | 1258 | /* send failure -- clean up the mess */ |
1534 | if (rc) | 1259 | if (rc != 0) { |
1535 | SetPageError(page); | 1260 | for (i = 0; i < nr_pages; ++i) { |
1536 | kunmap(page); | 1261 | if (rc == -EAGAIN) |
1537 | unlock_page(page); | 1262 | redirty_page_for_writepage(wbc, |
1538 | end_page_writeback(page); | 1263 | wdata->pages[i]); |
1539 | page_cache_release(page); | 1264 | else |
1265 | SetPageError(wdata->pages[i]); | ||
1266 | end_page_writeback(wdata->pages[i]); | ||
1267 | page_cache_release(wdata->pages[i]); | ||
1540 | } | 1268 | } |
1541 | if ((wbc->nr_to_write -= n_iov) <= 0) | 1269 | if (rc != -EAGAIN) |
1542 | done = 1; | 1270 | mapping_set_error(mapping, rc); |
1543 | index = next; | 1271 | } |
1544 | } else | 1272 | kref_put(&wdata->refcount, cifs_writedata_release); |
1545 | /* Need to re-find the pages we skipped */ | 1273 | |
1546 | index = pvec.pages[0]->index + 1; | 1274 | wbc->nr_to_write -= nr_pages; |
1275 | if (wbc->nr_to_write <= 0) | ||
1276 | done = true; | ||
1547 | 1277 | ||
1548 | pagevec_release(&pvec); | 1278 | index = next; |
1549 | } | 1279 | } |
1280 | |||
1550 | if (!scanned && !done) { | 1281 | if (!scanned && !done) { |
1551 | /* | 1282 | /* |
1552 | * We hit the last page and there is more work to be done: wrap | 1283 | * We hit the last page and there is more work to be done: wrap |
1553 | * back to the start of the file | 1284 | * back to the start of the file |
1554 | */ | 1285 | */ |
1555 | scanned = 1; | 1286 | scanned = true; |
1556 | index = 0; | 1287 | index = 0; |
1557 | goto retry; | 1288 | goto retry; |
1558 | } | 1289 | } |
1290 | |||
1559 | if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) | 1291 | if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) |
1560 | mapping->writeback_index = index; | 1292 | mapping->writeback_index = index; |
1561 | 1293 | ||
1562 | FreeXid(xid); | ||
1563 | kfree(iov); | ||
1564 | return rc; | 1294 | return rc; |
1565 | } | 1295 | } |
1566 | 1296 | ||
1567 | static int cifs_writepage(struct page *page, struct writeback_control *wbc) | 1297 | static int |
1298 | cifs_writepage_locked(struct page *page, struct writeback_control *wbc) | ||
1568 | { | 1299 | { |
1569 | int rc = -EFAULT; | 1300 | int rc; |
1570 | int xid; | 1301 | int xid; |
1571 | 1302 | ||
1572 | xid = GetXid(); | 1303 | xid = GetXid(); |
@@ -1586,21 +1317,43 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc) | |||
1586 | * to fail to update with the state of the page correctly. | 1317 | * to fail to update with the state of the page correctly. |
1587 | */ | 1318 | */ |
1588 | set_page_writeback(page); | 1319 | set_page_writeback(page); |
1320 | retry_write: | ||
1589 | rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); | 1321 | rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE); |
1590 | SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ | 1322 | if (rc == -EAGAIN && wbc->sync_mode == WB_SYNC_ALL) |
1591 | unlock_page(page); | 1323 | goto retry_write; |
1324 | else if (rc == -EAGAIN) | ||
1325 | redirty_page_for_writepage(wbc, page); | ||
1326 | else if (rc != 0) | ||
1327 | SetPageError(page); | ||
1328 | else | ||
1329 | SetPageUptodate(page); | ||
1592 | end_page_writeback(page); | 1330 | end_page_writeback(page); |
1593 | page_cache_release(page); | 1331 | page_cache_release(page); |
1594 | FreeXid(xid); | 1332 | FreeXid(xid); |
1595 | return rc; | 1333 | return rc; |
1596 | } | 1334 | } |
1597 | 1335 | ||
1336 | static int cifs_writepage(struct page *page, struct writeback_control *wbc) | ||
1337 | { | ||
1338 | int rc = cifs_writepage_locked(page, wbc); | ||
1339 | unlock_page(page); | ||
1340 | return rc; | ||
1341 | } | ||
1342 | |||
1598 | static int cifs_write_end(struct file *file, struct address_space *mapping, | 1343 | static int cifs_write_end(struct file *file, struct address_space *mapping, |
1599 | loff_t pos, unsigned len, unsigned copied, | 1344 | loff_t pos, unsigned len, unsigned copied, |
1600 | struct page *page, void *fsdata) | 1345 | struct page *page, void *fsdata) |
1601 | { | 1346 | { |
1602 | int rc; | 1347 | int rc; |
1603 | struct inode *inode = mapping->host; | 1348 | struct inode *inode = mapping->host; |
1349 | struct cifsFileInfo *cfile = file->private_data; | ||
1350 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | ||
1351 | __u32 pid; | ||
1352 | |||
1353 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | ||
1354 | pid = cfile->pid; | ||
1355 | else | ||
1356 | pid = current->tgid; | ||
1604 | 1357 | ||
1605 | cFYI(1, "write_end for page %p from pos %lld with %d bytes", | 1358 | cFYI(1, "write_end for page %p from pos %lld with %d bytes", |
1606 | page, pos, copied); | 1359 | page, pos, copied); |
@@ -1624,7 +1377,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
1624 | /* BB check if anything else missing out of ppw | 1377 | /* BB check if anything else missing out of ppw |
1625 | such as updating last write time */ | 1378 | such as updating last write time */ |
1626 | page_data = kmap(page); | 1379 | page_data = kmap(page); |
1627 | rc = cifs_write(file, page_data + offset, copied, &pos); | 1380 | rc = cifs_write(cfile, pid, page_data + offset, copied, &pos); |
1628 | /* if (rc < 0) should we set writebehind rc? */ | 1381 | /* if (rc < 0) should we set writebehind rc? */ |
1629 | kunmap(page); | 1382 | kunmap(page); |
1630 | 1383 | ||
@@ -1648,60 +1401,56 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
1648 | return rc; | 1401 | return rc; |
1649 | } | 1402 | } |
1650 | 1403 | ||
1651 | int cifs_fsync(struct file *file, int datasync) | 1404 | int cifs_strict_fsync(struct file *file, int datasync) |
1652 | { | 1405 | { |
1653 | int xid; | 1406 | int xid; |
1654 | int rc = 0; | 1407 | int rc = 0; |
1655 | struct cifsTconInfo *tcon; | 1408 | struct cifs_tcon *tcon; |
1656 | struct cifsFileInfo *smbfile = file->private_data; | 1409 | struct cifsFileInfo *smbfile = file->private_data; |
1657 | struct inode *inode = file->f_path.dentry->d_inode; | 1410 | struct inode *inode = file->f_path.dentry->d_inode; |
1411 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1658 | 1412 | ||
1659 | xid = GetXid(); | 1413 | xid = GetXid(); |
1660 | 1414 | ||
1661 | cFYI(1, "Sync file - name: %s datasync: 0x%x", | 1415 | cFYI(1, "Sync file - name: %s datasync: 0x%x", |
1662 | file->f_path.dentry->d_name.name, datasync); | 1416 | file->f_path.dentry->d_name.name, datasync); |
1663 | 1417 | ||
1664 | rc = filemap_write_and_wait(inode->i_mapping); | 1418 | if (!CIFS_I(inode)->clientCanCacheRead) { |
1665 | if (rc == 0) { | 1419 | rc = cifs_invalidate_mapping(inode); |
1666 | rc = CIFS_I(inode)->write_behind_rc; | 1420 | if (rc) { |
1667 | CIFS_I(inode)->write_behind_rc = 0; | 1421 | cFYI(1, "rc: %d during invalidate phase", rc); |
1668 | tcon = CIFS_SB(inode->i_sb)->tcon; | 1422 | rc = 0; /* don't care about it in fsync */ |
1669 | if (!rc && tcon && smbfile && | 1423 | } |
1670 | !(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | ||
1671 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | ||
1672 | } | 1424 | } |
1673 | 1425 | ||
1426 | tcon = tlink_tcon(smbfile->tlink); | ||
1427 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | ||
1428 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | ||
1429 | |||
1674 | FreeXid(xid); | 1430 | FreeXid(xid); |
1675 | return rc; | 1431 | return rc; |
1676 | } | 1432 | } |
1677 | 1433 | ||
1678 | /* static void cifs_sync_page(struct page *page) | 1434 | int cifs_fsync(struct file *file, int datasync) |
1679 | { | 1435 | { |
1680 | struct address_space *mapping; | 1436 | int xid; |
1681 | struct inode *inode; | ||
1682 | unsigned long index = page->index; | ||
1683 | unsigned int rpages = 0; | ||
1684 | int rc = 0; | 1437 | int rc = 0; |
1438 | struct cifs_tcon *tcon; | ||
1439 | struct cifsFileInfo *smbfile = file->private_data; | ||
1440 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1685 | 1441 | ||
1686 | cFYI(1, "sync page %p", page); | 1442 | xid = GetXid(); |
1687 | mapping = page->mapping; | ||
1688 | if (!mapping) | ||
1689 | return 0; | ||
1690 | inode = mapping->host; | ||
1691 | if (!inode) | ||
1692 | return; */ | ||
1693 | 1443 | ||
1694 | /* fill in rpages then | 1444 | cFYI(1, "Sync file - name: %s datasync: 0x%x", |
1695 | result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ | 1445 | file->f_path.dentry->d_name.name, datasync); |
1696 | 1446 | ||
1697 | /* cFYI(1, "rpages is %d for sync page of Index %ld", rpages, index); | 1447 | tcon = tlink_tcon(smbfile->tlink); |
1448 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | ||
1449 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | ||
1698 | 1450 | ||
1699 | #if 0 | 1451 | FreeXid(xid); |
1700 | if (rc < 0) | 1452 | return rc; |
1701 | return rc; | 1453 | } |
1702 | return 0; | ||
1703 | #endif | ||
1704 | } */ | ||
1705 | 1454 | ||
1706 | /* | 1455 | /* |
1707 | * As file closes, flush all cached write data for this inode checking | 1456 | * As file closes, flush all cached write data for this inode checking |
@@ -1712,92 +1461,301 @@ int cifs_flush(struct file *file, fl_owner_t id) | |||
1712 | struct inode *inode = file->f_path.dentry->d_inode; | 1461 | struct inode *inode = file->f_path.dentry->d_inode; |
1713 | int rc = 0; | 1462 | int rc = 0; |
1714 | 1463 | ||
1715 | /* Rather than do the steps manually: | 1464 | if (file->f_mode & FMODE_WRITE) |
1716 | lock the inode for writing | 1465 | rc = filemap_write_and_wait(inode->i_mapping); |
1717 | loop through pages looking for write behind data (dirty pages) | ||
1718 | coalesce into contiguous 16K (or smaller) chunks to write to server | ||
1719 | send to server (prefer in parallel) | ||
1720 | deal with writebehind errors | ||
1721 | unlock inode for writing | ||
1722 | filemapfdatawrite appears easier for the time being */ | ||
1723 | |||
1724 | rc = filemap_fdatawrite(inode->i_mapping); | ||
1725 | /* reset wb rc if we were able to write out dirty pages */ | ||
1726 | if (!rc) { | ||
1727 | rc = CIFS_I(inode)->write_behind_rc; | ||
1728 | CIFS_I(inode)->write_behind_rc = 0; | ||
1729 | } | ||
1730 | 1466 | ||
1731 | cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc); | 1467 | cFYI(1, "Flush inode %p file %p rc %d", inode, file, rc); |
1732 | 1468 | ||
1733 | return rc; | 1469 | return rc; |
1734 | } | 1470 | } |
1735 | 1471 | ||
1736 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | 1472 | static int |
1737 | size_t read_size, loff_t *poffset) | 1473 | cifs_write_allocate_pages(struct page **pages, unsigned long num_pages) |
1738 | { | 1474 | { |
1739 | int rc = -EACCES; | 1475 | int rc = 0; |
1740 | unsigned int bytes_read = 0; | 1476 | unsigned long i; |
1741 | unsigned int total_read = 0; | 1477 | |
1742 | unsigned int current_read_size; | 1478 | for (i = 0; i < num_pages; i++) { |
1479 | pages[i] = alloc_page(__GFP_HIGHMEM); | ||
1480 | if (!pages[i]) { | ||
1481 | /* | ||
1482 | * save number of pages we have already allocated and | ||
1483 | * return with ENOMEM error | ||
1484 | */ | ||
1485 | num_pages = i; | ||
1486 | rc = -ENOMEM; | ||
1487 | goto error; | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1491 | return rc; | ||
1492 | |||
1493 | error: | ||
1494 | for (i = 0; i < num_pages; i++) | ||
1495 | put_page(pages[i]); | ||
1496 | return rc; | ||
1497 | } | ||
1498 | |||
1499 | static inline | ||
1500 | size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len) | ||
1501 | { | ||
1502 | size_t num_pages; | ||
1503 | size_t clen; | ||
1504 | |||
1505 | clen = min_t(const size_t, len, wsize); | ||
1506 | num_pages = clen / PAGE_CACHE_SIZE; | ||
1507 | if (clen % PAGE_CACHE_SIZE) | ||
1508 | num_pages++; | ||
1509 | |||
1510 | if (cur_len) | ||
1511 | *cur_len = clen; | ||
1512 | |||
1513 | return num_pages; | ||
1514 | } | ||
1515 | |||
1516 | static ssize_t | ||
1517 | cifs_iovec_write(struct file *file, const struct iovec *iov, | ||
1518 | unsigned long nr_segs, loff_t *poffset) | ||
1519 | { | ||
1520 | unsigned int written; | ||
1521 | unsigned long num_pages, npages, i; | ||
1522 | size_t copied, len, cur_len; | ||
1523 | ssize_t total_written = 0; | ||
1524 | struct kvec *to_send; | ||
1525 | struct page **pages; | ||
1526 | struct iov_iter it; | ||
1527 | struct inode *inode; | ||
1528 | struct cifsFileInfo *open_file; | ||
1529 | struct cifs_tcon *pTcon; | ||
1743 | struct cifs_sb_info *cifs_sb; | 1530 | struct cifs_sb_info *cifs_sb; |
1744 | struct cifsTconInfo *pTcon; | 1531 | struct cifs_io_parms io_parms; |
1532 | int xid, rc; | ||
1533 | __u32 pid; | ||
1534 | |||
1535 | len = iov_length(iov, nr_segs); | ||
1536 | if (!len) | ||
1537 | return 0; | ||
1538 | |||
1539 | rc = generic_write_checks(file, poffset, &len, 0); | ||
1540 | if (rc) | ||
1541 | return rc; | ||
1542 | |||
1543 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1544 | num_pages = get_numpages(cifs_sb->wsize, len, &cur_len); | ||
1545 | |||
1546 | pages = kmalloc(sizeof(struct pages *)*num_pages, GFP_KERNEL); | ||
1547 | if (!pages) | ||
1548 | return -ENOMEM; | ||
1549 | |||
1550 | to_send = kmalloc(sizeof(struct kvec)*(num_pages + 1), GFP_KERNEL); | ||
1551 | if (!to_send) { | ||
1552 | kfree(pages); | ||
1553 | return -ENOMEM; | ||
1554 | } | ||
1555 | |||
1556 | rc = cifs_write_allocate_pages(pages, num_pages); | ||
1557 | if (rc) { | ||
1558 | kfree(pages); | ||
1559 | kfree(to_send); | ||
1560 | return rc; | ||
1561 | } | ||
1562 | |||
1563 | xid = GetXid(); | ||
1564 | open_file = file->private_data; | ||
1565 | |||
1566 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | ||
1567 | pid = open_file->pid; | ||
1568 | else | ||
1569 | pid = current->tgid; | ||
1570 | |||
1571 | pTcon = tlink_tcon(open_file->tlink); | ||
1572 | inode = file->f_path.dentry->d_inode; | ||
1573 | |||
1574 | iov_iter_init(&it, iov, nr_segs, len, 0); | ||
1575 | npages = num_pages; | ||
1576 | |||
1577 | do { | ||
1578 | size_t save_len = cur_len; | ||
1579 | for (i = 0; i < npages; i++) { | ||
1580 | copied = min_t(const size_t, cur_len, PAGE_CACHE_SIZE); | ||
1581 | copied = iov_iter_copy_from_user(pages[i], &it, 0, | ||
1582 | copied); | ||
1583 | cur_len -= copied; | ||
1584 | iov_iter_advance(&it, copied); | ||
1585 | to_send[i+1].iov_base = kmap(pages[i]); | ||
1586 | to_send[i+1].iov_len = copied; | ||
1587 | } | ||
1588 | |||
1589 | cur_len = save_len - cur_len; | ||
1590 | |||
1591 | do { | ||
1592 | if (open_file->invalidHandle) { | ||
1593 | rc = cifs_reopen_file(open_file, false); | ||
1594 | if (rc != 0) | ||
1595 | break; | ||
1596 | } | ||
1597 | io_parms.netfid = open_file->netfid; | ||
1598 | io_parms.pid = pid; | ||
1599 | io_parms.tcon = pTcon; | ||
1600 | io_parms.offset = *poffset; | ||
1601 | io_parms.length = cur_len; | ||
1602 | rc = CIFSSMBWrite2(xid, &io_parms, &written, to_send, | ||
1603 | npages, 0); | ||
1604 | } while (rc == -EAGAIN); | ||
1605 | |||
1606 | for (i = 0; i < npages; i++) | ||
1607 | kunmap(pages[i]); | ||
1608 | |||
1609 | if (written) { | ||
1610 | len -= written; | ||
1611 | total_written += written; | ||
1612 | cifs_update_eof(CIFS_I(inode), *poffset, written); | ||
1613 | *poffset += written; | ||
1614 | } else if (rc < 0) { | ||
1615 | if (!total_written) | ||
1616 | total_written = rc; | ||
1617 | break; | ||
1618 | } | ||
1619 | |||
1620 | /* get length and number of kvecs of the next write */ | ||
1621 | npages = get_numpages(cifs_sb->wsize, len, &cur_len); | ||
1622 | } while (len > 0); | ||
1623 | |||
1624 | if (total_written > 0) { | ||
1625 | spin_lock(&inode->i_lock); | ||
1626 | if (*poffset > inode->i_size) | ||
1627 | i_size_write(inode, *poffset); | ||
1628 | spin_unlock(&inode->i_lock); | ||
1629 | } | ||
1630 | |||
1631 | cifs_stats_bytes_written(pTcon, total_written); | ||
1632 | mark_inode_dirty_sync(inode); | ||
1633 | |||
1634 | for (i = 0; i < num_pages; i++) | ||
1635 | put_page(pages[i]); | ||
1636 | kfree(to_send); | ||
1637 | kfree(pages); | ||
1638 | FreeXid(xid); | ||
1639 | return total_written; | ||
1640 | } | ||
1641 | |||
1642 | ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, | ||
1643 | unsigned long nr_segs, loff_t pos) | ||
1644 | { | ||
1645 | ssize_t written; | ||
1646 | struct inode *inode; | ||
1647 | |||
1648 | inode = iocb->ki_filp->f_path.dentry->d_inode; | ||
1649 | |||
1650 | /* | ||
1651 | * BB - optimize the way when signing is disabled. We can drop this | ||
1652 | * extra memory-to-memory copying and use iovec buffers for constructing | ||
1653 | * write request. | ||
1654 | */ | ||
1655 | |||
1656 | written = cifs_iovec_write(iocb->ki_filp, iov, nr_segs, &pos); | ||
1657 | if (written > 0) { | ||
1658 | CIFS_I(inode)->invalid_mapping = true; | ||
1659 | iocb->ki_pos = pos; | ||
1660 | } | ||
1661 | |||
1662 | return written; | ||
1663 | } | ||
1664 | |||
1665 | ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | ||
1666 | unsigned long nr_segs, loff_t pos) | ||
1667 | { | ||
1668 | struct inode *inode; | ||
1669 | |||
1670 | inode = iocb->ki_filp->f_path.dentry->d_inode; | ||
1671 | |||
1672 | if (CIFS_I(inode)->clientCanCacheAll) | ||
1673 | return generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
1674 | |||
1675 | /* | ||
1676 | * In strict cache mode we need to write the data to the server exactly | ||
1677 | * from the pos to pos+len-1 rather than flush all affected pages | ||
1678 | * because it may cause a error with mandatory locks on these pages but | ||
1679 | * not on the region from pos to ppos+len-1. | ||
1680 | */ | ||
1681 | |||
1682 | return cifs_user_writev(iocb, iov, nr_segs, pos); | ||
1683 | } | ||
1684 | |||
1685 | static ssize_t | ||
1686 | cifs_iovec_read(struct file *file, const struct iovec *iov, | ||
1687 | unsigned long nr_segs, loff_t *poffset) | ||
1688 | { | ||
1689 | int rc; | ||
1745 | int xid; | 1690 | int xid; |
1691 | ssize_t total_read; | ||
1692 | unsigned int bytes_read = 0; | ||
1693 | size_t len, cur_len; | ||
1694 | int iov_offset = 0; | ||
1695 | struct cifs_sb_info *cifs_sb; | ||
1696 | struct cifs_tcon *pTcon; | ||
1746 | struct cifsFileInfo *open_file; | 1697 | struct cifsFileInfo *open_file; |
1747 | char *smb_read_data; | ||
1748 | char __user *current_offset; | ||
1749 | struct smb_com_read_rsp *pSMBr; | 1698 | struct smb_com_read_rsp *pSMBr; |
1699 | struct cifs_io_parms io_parms; | ||
1700 | char *read_data; | ||
1701 | __u32 pid; | ||
1702 | |||
1703 | if (!nr_segs) | ||
1704 | return 0; | ||
1705 | |||
1706 | len = iov_length(iov, nr_segs); | ||
1707 | if (!len) | ||
1708 | return 0; | ||
1750 | 1709 | ||
1751 | xid = GetXid(); | 1710 | xid = GetXid(); |
1752 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1711 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1753 | pTcon = cifs_sb->tcon; | ||
1754 | 1712 | ||
1755 | if (file->private_data == NULL) { | ||
1756 | rc = -EBADF; | ||
1757 | FreeXid(xid); | ||
1758 | return rc; | ||
1759 | } | ||
1760 | open_file = file->private_data; | 1713 | open_file = file->private_data; |
1714 | pTcon = tlink_tcon(open_file->tlink); | ||
1715 | |||
1716 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | ||
1717 | pid = open_file->pid; | ||
1718 | else | ||
1719 | pid = current->tgid; | ||
1761 | 1720 | ||
1762 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1721 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1763 | cFYI(1, "attempting read on write only file instance"); | 1722 | cFYI(1, "attempting read on write only file instance"); |
1764 | 1723 | ||
1765 | for (total_read = 0, current_offset = read_data; | 1724 | for (total_read = 0; total_read < len; total_read += bytes_read) { |
1766 | read_size > total_read; | 1725 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); |
1767 | total_read += bytes_read, current_offset += bytes_read) { | ||
1768 | current_read_size = min_t(const int, read_size - total_read, | ||
1769 | cifs_sb->rsize); | ||
1770 | rc = -EAGAIN; | 1726 | rc = -EAGAIN; |
1771 | smb_read_data = NULL; | 1727 | read_data = NULL; |
1728 | |||
1772 | while (rc == -EAGAIN) { | 1729 | while (rc == -EAGAIN) { |
1773 | int buf_type = CIFS_NO_BUFFER; | 1730 | int buf_type = CIFS_NO_BUFFER; |
1774 | if ((open_file->invalidHandle) && | 1731 | if (open_file->invalidHandle) { |
1775 | (!open_file->closePend)) { | 1732 | rc = cifs_reopen_file(open_file, true); |
1776 | rc = cifs_reopen_file(file, true); | ||
1777 | if (rc != 0) | 1733 | if (rc != 0) |
1778 | break; | 1734 | break; |
1779 | } | 1735 | } |
1780 | rc = CIFSSMBRead(xid, pTcon, | 1736 | io_parms.netfid = open_file->netfid; |
1781 | open_file->netfid, | 1737 | io_parms.pid = pid; |
1782 | current_read_size, *poffset, | 1738 | io_parms.tcon = pTcon; |
1783 | &bytes_read, &smb_read_data, | 1739 | io_parms.offset = *poffset; |
1784 | &buf_type); | 1740 | io_parms.length = cur_len; |
1785 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1741 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, |
1786 | if (smb_read_data) { | 1742 | &read_data, &buf_type); |
1787 | if (copy_to_user(current_offset, | 1743 | pSMBr = (struct smb_com_read_rsp *)read_data; |
1788 | smb_read_data + | 1744 | if (read_data) { |
1789 | 4 /* RFC1001 length field */ + | 1745 | char *data_offset = read_data + 4 + |
1790 | le16_to_cpu(pSMBr->DataOffset), | 1746 | le16_to_cpu(pSMBr->DataOffset); |
1791 | bytes_read)) | 1747 | if (memcpy_toiovecend(iov, data_offset, |
1748 | iov_offset, bytes_read)) | ||
1792 | rc = -EFAULT; | 1749 | rc = -EFAULT; |
1793 | |||
1794 | if (buf_type == CIFS_SMALL_BUFFER) | 1750 | if (buf_type == CIFS_SMALL_BUFFER) |
1795 | cifs_small_buf_release(smb_read_data); | 1751 | cifs_small_buf_release(read_data); |
1796 | else if (buf_type == CIFS_LARGE_BUFFER) | 1752 | else if (buf_type == CIFS_LARGE_BUFFER) |
1797 | cifs_buf_release(smb_read_data); | 1753 | cifs_buf_release(read_data); |
1798 | smb_read_data = NULL; | 1754 | read_data = NULL; |
1755 | iov_offset += bytes_read; | ||
1799 | } | 1756 | } |
1800 | } | 1757 | } |
1758 | |||
1801 | if (rc || (bytes_read == 0)) { | 1759 | if (rc || (bytes_read == 0)) { |
1802 | if (total_read) { | 1760 | if (total_read) { |
1803 | break; | 1761 | break; |
@@ -1810,28 +1768,63 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1810 | *poffset += bytes_read; | 1768 | *poffset += bytes_read; |
1811 | } | 1769 | } |
1812 | } | 1770 | } |
1771 | |||
1813 | FreeXid(xid); | 1772 | FreeXid(xid); |
1814 | return total_read; | 1773 | return total_read; |
1815 | } | 1774 | } |
1816 | 1775 | ||
1776 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, | ||
1777 | unsigned long nr_segs, loff_t pos) | ||
1778 | { | ||
1779 | ssize_t read; | ||
1780 | |||
1781 | read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos); | ||
1782 | if (read > 0) | ||
1783 | iocb->ki_pos = pos; | ||
1784 | |||
1785 | return read; | ||
1786 | } | ||
1787 | |||
1788 | ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | ||
1789 | unsigned long nr_segs, loff_t pos) | ||
1790 | { | ||
1791 | struct inode *inode; | ||
1792 | |||
1793 | inode = iocb->ki_filp->f_path.dentry->d_inode; | ||
1794 | |||
1795 | if (CIFS_I(inode)->clientCanCacheRead) | ||
1796 | return generic_file_aio_read(iocb, iov, nr_segs, pos); | ||
1797 | |||
1798 | /* | ||
1799 | * In strict cache mode we need to read from the server all the time | ||
1800 | * if we don't have level II oplock because the server can delay mtime | ||
1801 | * change - so we can't make a decision about inode invalidating. | ||
1802 | * And we can also fail with pagereading if there are mandatory locks | ||
1803 | * on pages affected by this read but not on the region from pos to | ||
1804 | * pos+len-1. | ||
1805 | */ | ||
1806 | |||
1807 | return cifs_user_readv(iocb, iov, nr_segs, pos); | ||
1808 | } | ||
1817 | 1809 | ||
1818 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | 1810 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, |
1819 | loff_t *poffset) | 1811 | loff_t *poffset) |
1820 | { | 1812 | { |
1821 | int rc = -EACCES; | 1813 | int rc = -EACCES; |
1822 | unsigned int bytes_read = 0; | 1814 | unsigned int bytes_read = 0; |
1823 | unsigned int total_read; | 1815 | unsigned int total_read; |
1824 | unsigned int current_read_size; | 1816 | unsigned int current_read_size; |
1825 | struct cifs_sb_info *cifs_sb; | 1817 | struct cifs_sb_info *cifs_sb; |
1826 | struct cifsTconInfo *pTcon; | 1818 | struct cifs_tcon *pTcon; |
1827 | int xid; | 1819 | int xid; |
1828 | char *current_offset; | 1820 | char *current_offset; |
1829 | struct cifsFileInfo *open_file; | 1821 | struct cifsFileInfo *open_file; |
1822 | struct cifs_io_parms io_parms; | ||
1830 | int buf_type = CIFS_NO_BUFFER; | 1823 | int buf_type = CIFS_NO_BUFFER; |
1824 | __u32 pid; | ||
1831 | 1825 | ||
1832 | xid = GetXid(); | 1826 | xid = GetXid(); |
1833 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1827 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1834 | pTcon = cifs_sb->tcon; | ||
1835 | 1828 | ||
1836 | if (file->private_data == NULL) { | 1829 | if (file->private_data == NULL) { |
1837 | rc = -EBADF; | 1830 | rc = -EBADF; |
@@ -1839,6 +1832,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1839 | return rc; | 1832 | return rc; |
1840 | } | 1833 | } |
1841 | open_file = file->private_data; | 1834 | open_file = file->private_data; |
1835 | pTcon = tlink_tcon(open_file->tlink); | ||
1836 | |||
1837 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | ||
1838 | pid = open_file->pid; | ||
1839 | else | ||
1840 | pid = current->tgid; | ||
1842 | 1841 | ||
1843 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1842 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1844 | cFYI(1, "attempting read on write only file instance"); | 1843 | cFYI(1, "attempting read on write only file instance"); |
@@ -1857,17 +1856,18 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1857 | } | 1856 | } |
1858 | rc = -EAGAIN; | 1857 | rc = -EAGAIN; |
1859 | while (rc == -EAGAIN) { | 1858 | while (rc == -EAGAIN) { |
1860 | if ((open_file->invalidHandle) && | 1859 | if (open_file->invalidHandle) { |
1861 | (!open_file->closePend)) { | 1860 | rc = cifs_reopen_file(open_file, true); |
1862 | rc = cifs_reopen_file(file, true); | ||
1863 | if (rc != 0) | 1861 | if (rc != 0) |
1864 | break; | 1862 | break; |
1865 | } | 1863 | } |
1866 | rc = CIFSSMBRead(xid, pTcon, | 1864 | io_parms.netfid = open_file->netfid; |
1867 | open_file->netfid, | 1865 | io_parms.pid = pid; |
1868 | current_read_size, *poffset, | 1866 | io_parms.tcon = pTcon; |
1869 | &bytes_read, ¤t_offset, | 1867 | io_parms.offset = *poffset; |
1870 | &buf_type); | 1868 | io_parms.length = current_read_size; |
1869 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, | ||
1870 | ¤t_offset, &buf_type); | ||
1871 | } | 1871 | } |
1872 | if (rc || (bytes_read == 0)) { | 1872 | if (rc || (bytes_read == 0)) { |
1873 | if (total_read) { | 1873 | if (total_read) { |
@@ -1885,6 +1885,44 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1885 | return total_read; | 1885 | return total_read; |
1886 | } | 1886 | } |
1887 | 1887 | ||
1888 | /* | ||
1889 | * If the page is mmap'ed into a process' page tables, then we need to make | ||
1890 | * sure that it doesn't change while being written back. | ||
1891 | */ | ||
1892 | static int | ||
1893 | cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
1894 | { | ||
1895 | struct page *page = vmf->page; | ||
1896 | |||
1897 | lock_page(page); | ||
1898 | return VM_FAULT_LOCKED; | ||
1899 | } | ||
1900 | |||
1901 | static struct vm_operations_struct cifs_file_vm_ops = { | ||
1902 | .fault = filemap_fault, | ||
1903 | .page_mkwrite = cifs_page_mkwrite, | ||
1904 | }; | ||
1905 | |||
1906 | int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) | ||
1907 | { | ||
1908 | int rc, xid; | ||
1909 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1910 | |||
1911 | xid = GetXid(); | ||
1912 | |||
1913 | if (!CIFS_I(inode)->clientCanCacheRead) { | ||
1914 | rc = cifs_invalidate_mapping(inode); | ||
1915 | if (rc) | ||
1916 | return rc; | ||
1917 | } | ||
1918 | |||
1919 | rc = generic_file_mmap(file, vma); | ||
1920 | if (rc == 0) | ||
1921 | vma->vm_ops = &cifs_file_vm_ops; | ||
1922 | FreeXid(xid); | ||
1923 | return rc; | ||
1924 | } | ||
1925 | |||
1888 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | 1926 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) |
1889 | { | 1927 | { |
1890 | int rc, xid; | 1928 | int rc, xid; |
@@ -1897,6 +1935,8 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
1897 | return rc; | 1935 | return rc; |
1898 | } | 1936 | } |
1899 | rc = generic_file_mmap(file, vma); | 1937 | rc = generic_file_mmap(file, vma); |
1938 | if (rc == 0) | ||
1939 | vma->vm_ops = &cifs_file_vm_ops; | ||
1900 | FreeXid(xid); | 1940 | FreeXid(xid); |
1901 | return rc; | 1941 | return rc; |
1902 | } | 1942 | } |
@@ -1958,13 +1998,15 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1958 | loff_t offset; | 1998 | loff_t offset; |
1959 | struct page *page; | 1999 | struct page *page; |
1960 | struct cifs_sb_info *cifs_sb; | 2000 | struct cifs_sb_info *cifs_sb; |
1961 | struct cifsTconInfo *pTcon; | 2001 | struct cifs_tcon *pTcon; |
1962 | unsigned int bytes_read = 0; | 2002 | unsigned int bytes_read = 0; |
1963 | unsigned int read_size, i; | 2003 | unsigned int read_size, i; |
1964 | char *smb_read_data = NULL; | 2004 | char *smb_read_data = NULL; |
1965 | struct smb_com_read_rsp *pSMBr; | 2005 | struct smb_com_read_rsp *pSMBr; |
1966 | struct cifsFileInfo *open_file; | 2006 | struct cifsFileInfo *open_file; |
2007 | struct cifs_io_parms io_parms; | ||
1967 | int buf_type = CIFS_NO_BUFFER; | 2008 | int buf_type = CIFS_NO_BUFFER; |
2009 | __u32 pid; | ||
1968 | 2010 | ||
1969 | xid = GetXid(); | 2011 | xid = GetXid(); |
1970 | if (file->private_data == NULL) { | 2012 | if (file->private_data == NULL) { |
@@ -1974,7 +2016,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1974 | } | 2016 | } |
1975 | open_file = file->private_data; | 2017 | open_file = file->private_data; |
1976 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2018 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1977 | pTcon = cifs_sb->tcon; | 2019 | pTcon = tlink_tcon(open_file->tlink); |
1978 | 2020 | ||
1979 | /* | 2021 | /* |
1980 | * Reads as many pages as possible from fscache. Returns -ENOBUFS | 2022 | * Reads as many pages as possible from fscache. Returns -ENOBUFS |
@@ -1986,6 +2028,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1986 | goto read_complete; | 2028 | goto read_complete; |
1987 | 2029 | ||
1988 | cFYI(DBG2, "rpages: num pages %d", num_pages); | 2030 | cFYI(DBG2, "rpages: num pages %d", num_pages); |
2031 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | ||
2032 | pid = open_file->pid; | ||
2033 | else | ||
2034 | pid = current->tgid; | ||
2035 | |||
1989 | for (i = 0; i < num_pages; ) { | 2036 | for (i = 0; i < num_pages; ) { |
1990 | unsigned contig_pages; | 2037 | unsigned contig_pages; |
1991 | struct page *tmp_page; | 2038 | struct page *tmp_page; |
@@ -2022,18 +2069,18 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2022 | read_size, contig_pages); | 2069 | read_size, contig_pages); |
2023 | rc = -EAGAIN; | 2070 | rc = -EAGAIN; |
2024 | while (rc == -EAGAIN) { | 2071 | while (rc == -EAGAIN) { |
2025 | if ((open_file->invalidHandle) && | 2072 | if (open_file->invalidHandle) { |
2026 | (!open_file->closePend)) { | 2073 | rc = cifs_reopen_file(open_file, true); |
2027 | rc = cifs_reopen_file(file, true); | ||
2028 | if (rc != 0) | 2074 | if (rc != 0) |
2029 | break; | 2075 | break; |
2030 | } | 2076 | } |
2031 | 2077 | io_parms.netfid = open_file->netfid; | |
2032 | rc = CIFSSMBRead(xid, pTcon, | 2078 | io_parms.pid = pid; |
2033 | open_file->netfid, | 2079 | io_parms.tcon = pTcon; |
2034 | read_size, offset, | 2080 | io_parms.offset = offset; |
2035 | &bytes_read, &smb_read_data, | 2081 | io_parms.length = read_size; |
2036 | &buf_type); | 2082 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, |
2083 | &smb_read_data, &buf_type); | ||
2037 | /* BB more RC checks ? */ | 2084 | /* BB more RC checks ? */ |
2038 | if (rc == -EAGAIN) { | 2085 | if (rc == -EAGAIN) { |
2039 | if (smb_read_data) { | 2086 | if (smb_read_data) { |
@@ -2173,18 +2220,14 @@ static int is_inode_writable(struct cifsInodeInfo *cifs_inode) | |||
2173 | { | 2220 | { |
2174 | struct cifsFileInfo *open_file; | 2221 | struct cifsFileInfo *open_file; |
2175 | 2222 | ||
2176 | read_lock(&GlobalSMBSeslock); | 2223 | spin_lock(&cifs_file_list_lock); |
2177 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 2224 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
2178 | if (open_file->closePend) | 2225 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
2179 | continue; | 2226 | spin_unlock(&cifs_file_list_lock); |
2180 | if (open_file->pfile && | ||
2181 | ((open_file->pfile->f_flags & O_RDWR) || | ||
2182 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
2183 | read_unlock(&GlobalSMBSeslock); | ||
2184 | return 1; | 2227 | return 1; |
2185 | } | 2228 | } |
2186 | } | 2229 | } |
2187 | read_unlock(&GlobalSMBSeslock); | 2230 | spin_unlock(&cifs_file_list_lock); |
2188 | return 0; | 2231 | return 0; |
2189 | } | 2232 | } |
2190 | 2233 | ||
@@ -2306,14 +2349,34 @@ static void cifs_invalidate_page(struct page *page, unsigned long offset) | |||
2306 | cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); | 2349 | cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); |
2307 | } | 2350 | } |
2308 | 2351 | ||
2352 | static int cifs_launder_page(struct page *page) | ||
2353 | { | ||
2354 | int rc = 0; | ||
2355 | loff_t range_start = page_offset(page); | ||
2356 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | ||
2357 | struct writeback_control wbc = { | ||
2358 | .sync_mode = WB_SYNC_ALL, | ||
2359 | .nr_to_write = 0, | ||
2360 | .range_start = range_start, | ||
2361 | .range_end = range_end, | ||
2362 | }; | ||
2363 | |||
2364 | cFYI(1, "Launder page: %p", page); | ||
2365 | |||
2366 | if (clear_page_dirty_for_io(page)) | ||
2367 | rc = cifs_writepage_locked(page, &wbc); | ||
2368 | |||
2369 | cifs_fscache_invalidate_page(page, page->mapping->host); | ||
2370 | return rc; | ||
2371 | } | ||
2372 | |||
2309 | void cifs_oplock_break(struct work_struct *work) | 2373 | void cifs_oplock_break(struct work_struct *work) |
2310 | { | 2374 | { |
2311 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | 2375 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
2312 | oplock_break); | 2376 | oplock_break); |
2313 | struct inode *inode = cfile->pInode; | 2377 | struct inode *inode = cfile->dentry->d_inode; |
2314 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 2378 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
2315 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->mnt->mnt_sb); | 2379 | int rc = 0; |
2316 | int rc, waitrc = 0; | ||
2317 | 2380 | ||
2318 | if (inode && S_ISREG(inode->i_mode)) { | 2381 | if (inode && S_ISREG(inode->i_mode)) { |
2319 | if (cinode->clientCanCacheRead) | 2382 | if (cinode->clientCanCacheRead) |
@@ -2322,13 +2385,10 @@ void cifs_oplock_break(struct work_struct *work) | |||
2322 | break_lease(inode, O_WRONLY); | 2385 | break_lease(inode, O_WRONLY); |
2323 | rc = filemap_fdatawrite(inode->i_mapping); | 2386 | rc = filemap_fdatawrite(inode->i_mapping); |
2324 | if (cinode->clientCanCacheRead == 0) { | 2387 | if (cinode->clientCanCacheRead == 0) { |
2325 | waitrc = filemap_fdatawait(inode->i_mapping); | 2388 | rc = filemap_fdatawait(inode->i_mapping); |
2389 | mapping_set_error(inode->i_mapping, rc); | ||
2326 | invalidate_remote_inode(inode); | 2390 | invalidate_remote_inode(inode); |
2327 | } | 2391 | } |
2328 | if (!rc) | ||
2329 | rc = waitrc; | ||
2330 | if (rc) | ||
2331 | cinode->write_behind_rc = rc; | ||
2332 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); | 2392 | cFYI(1, "Oplock flush inode %p rc %d", inode, rc); |
2333 | } | 2393 | } |
2334 | 2394 | ||
@@ -2338,33 +2398,37 @@ void cifs_oplock_break(struct work_struct *work) | |||
2338 | * not bother sending an oplock release if session to server still is | 2398 | * not bother sending an oplock release if session to server still is |
2339 | * disconnected since oplock already released by the server | 2399 | * disconnected since oplock already released by the server |
2340 | */ | 2400 | */ |
2341 | if (!cfile->closePend && !cfile->oplock_break_cancelled) { | 2401 | if (!cfile->oplock_break_cancelled) { |
2342 | rc = CIFSSMBLock(0, cifs_sb->tcon, cfile->netfid, 0, 0, 0, 0, | 2402 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, |
2343 | LOCKING_ANDX_OPLOCK_RELEASE, false); | 2403 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false, |
2404 | cinode->clientCanCacheRead ? 1 : 0); | ||
2344 | cFYI(1, "Oplock release rc = %d", rc); | 2405 | cFYI(1, "Oplock release rc = %d", rc); |
2345 | } | 2406 | } |
2346 | 2407 | ||
2347 | /* | 2408 | /* |
2348 | * We might have kicked in before is_valid_oplock_break() | 2409 | * We might have kicked in before is_valid_oplock_break() |
2349 | * finished grabbing reference for us. Make sure it's done by | 2410 | * finished grabbing reference for us. Make sure it's done by |
2350 | * waiting for GlobalSMSSeslock. | 2411 | * waiting for cifs_file_list_lock. |
2351 | */ | 2412 | */ |
2352 | write_lock(&GlobalSMBSeslock); | 2413 | spin_lock(&cifs_file_list_lock); |
2353 | write_unlock(&GlobalSMBSeslock); | 2414 | spin_unlock(&cifs_file_list_lock); |
2354 | 2415 | ||
2355 | cifs_oplock_break_put(cfile); | 2416 | cifs_oplock_break_put(cfile); |
2356 | } | 2417 | } |
2357 | 2418 | ||
2419 | /* must be called while holding cifs_file_list_lock */ | ||
2358 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) | 2420 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
2359 | { | 2421 | { |
2360 | mntget(cfile->mnt); | 2422 | cifs_sb_active(cfile->dentry->d_sb); |
2361 | cifsFileInfo_get(cfile); | 2423 | cifsFileInfo_get(cfile); |
2362 | } | 2424 | } |
2363 | 2425 | ||
2364 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) | 2426 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) |
2365 | { | 2427 | { |
2366 | mntput(cfile->mnt); | 2428 | struct super_block *sb = cfile->dentry->d_sb; |
2429 | |||
2367 | cifsFileInfo_put(cfile); | 2430 | cifsFileInfo_put(cfile); |
2431 | cifs_sb_deactive(sb); | ||
2368 | } | 2432 | } |
2369 | 2433 | ||
2370 | const struct address_space_operations cifs_addr_ops = { | 2434 | const struct address_space_operations cifs_addr_ops = { |
@@ -2377,8 +2441,7 @@ const struct address_space_operations cifs_addr_ops = { | |||
2377 | .set_page_dirty = __set_page_dirty_nobuffers, | 2441 | .set_page_dirty = __set_page_dirty_nobuffers, |
2378 | .releasepage = cifs_release_page, | 2442 | .releasepage = cifs_release_page, |
2379 | .invalidatepage = cifs_invalidate_page, | 2443 | .invalidatepage = cifs_invalidate_page, |
2380 | /* .sync_page = cifs_sync_page, */ | 2444 | .launder_page = cifs_launder_page, |
2381 | /* .direct_IO = */ | ||
2382 | }; | 2445 | }; |
2383 | 2446 | ||
2384 | /* | 2447 | /* |
@@ -2395,6 +2458,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
2395 | .set_page_dirty = __set_page_dirty_nobuffers, | 2458 | .set_page_dirty = __set_page_dirty_nobuffers, |
2396 | .releasepage = cifs_release_page, | 2459 | .releasepage = cifs_release_page, |
2397 | .invalidatepage = cifs_invalidate_page, | 2460 | .invalidatepage = cifs_invalidate_page, |
2398 | /* .sync_page = cifs_sync_page, */ | 2461 | .launder_page = cifs_launder_page, |
2399 | /* .direct_IO = */ | ||
2400 | }; | 2462 | }; |
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index 9f3f5c4be161..42e5363b4102 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * fs/cifs/fscache.c - CIFS filesystem cache interface | 2 | * fs/cifs/fscache.c - CIFS filesystem cache interface |
3 | * | 3 | * |
4 | * Copyright (c) 2010 Novell, Inc. | 4 | * Copyright (c) 2010 Novell, Inc. |
5 | * Author(s): Suresh Jayaraman (sjayaraman@suse.de> | 5 | * Author(s): Suresh Jayaraman <sjayaraman@suse.de> |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU Lesser General Public License as published | 8 | * it under the terms of the GNU Lesser General Public License as published |
@@ -28,32 +28,32 @@ void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) | |||
28 | server->fscache = | 28 | server->fscache = |
29 | fscache_acquire_cookie(cifs_fscache_netfs.primary_index, | 29 | fscache_acquire_cookie(cifs_fscache_netfs.primary_index, |
30 | &cifs_fscache_server_index_def, server); | 30 | &cifs_fscache_server_index_def, server); |
31 | cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server, | 31 | cFYI(1, "%s: (0x%p/0x%p)", __func__, server, |
32 | server->fscache); | 32 | server->fscache); |
33 | } | 33 | } |
34 | 34 | ||
35 | void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) | 35 | void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) |
36 | { | 36 | { |
37 | cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server, | 37 | cFYI(1, "%s: (0x%p/0x%p)", __func__, server, |
38 | server->fscache); | 38 | server->fscache); |
39 | fscache_relinquish_cookie(server->fscache, 0); | 39 | fscache_relinquish_cookie(server->fscache, 0); |
40 | server->fscache = NULL; | 40 | server->fscache = NULL; |
41 | } | 41 | } |
42 | 42 | ||
43 | void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) | 43 | void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) |
44 | { | 44 | { |
45 | struct TCP_Server_Info *server = tcon->ses->server; | 45 | struct TCP_Server_Info *server = tcon->ses->server; |
46 | 46 | ||
47 | tcon->fscache = | 47 | tcon->fscache = |
48 | fscache_acquire_cookie(server->fscache, | 48 | fscache_acquire_cookie(server->fscache, |
49 | &cifs_fscache_super_index_def, tcon); | 49 | &cifs_fscache_super_index_def, tcon); |
50 | cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)", | 50 | cFYI(1, "%s: (0x%p/0x%p)", __func__, server->fscache, |
51 | server->fscache, tcon->fscache); | 51 | tcon->fscache); |
52 | } | 52 | } |
53 | 53 | ||
54 | void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) | 54 | void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) |
55 | { | 55 | { |
56 | cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache); | 56 | cFYI(1, "%s: (0x%p)", __func__, tcon->fscache); |
57 | fscache_relinquish_cookie(tcon->fscache, 0); | 57 | fscache_relinquish_cookie(tcon->fscache, 0); |
58 | tcon->fscache = NULL; | 58 | tcon->fscache = NULL; |
59 | } | 59 | } |
@@ -62,15 +62,17 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode) | |||
62 | { | 62 | { |
63 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 63 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
64 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 64 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
65 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | ||
65 | 66 | ||
66 | if (cifsi->fscache) | 67 | if (cifsi->fscache) |
67 | return; | 68 | return; |
68 | 69 | ||
69 | cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, | 70 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { |
70 | &cifs_fscache_inode_object_def, | 71 | cifsi->fscache = fscache_acquire_cookie(tcon->fscache, |
71 | cifsi); | 72 | &cifs_fscache_inode_object_def, cifsi); |
72 | cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", | 73 | cFYI(1, "%s: got FH cookie (0x%p/0x%p)", __func__, |
73 | cifs_sb->tcon->fscache, cifsi->fscache); | 74 | tcon->fscache, cifsi->fscache); |
75 | } | ||
74 | } | 76 | } |
75 | 77 | ||
76 | void cifs_fscache_release_inode_cookie(struct inode *inode) | 78 | void cifs_fscache_release_inode_cookie(struct inode *inode) |
@@ -78,8 +80,7 @@ void cifs_fscache_release_inode_cookie(struct inode *inode) | |||
78 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 80 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
79 | 81 | ||
80 | if (cifsi->fscache) { | 82 | if (cifsi->fscache) { |
81 | cFYI(1, "CIFS releasing inode cookie (0x%p)", | 83 | cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache); |
82 | cifsi->fscache); | ||
83 | fscache_relinquish_cookie(cifsi->fscache, 0); | 84 | fscache_relinquish_cookie(cifsi->fscache, 0); |
84 | cifsi->fscache = NULL; | 85 | cifsi->fscache = NULL; |
85 | } | 86 | } |
@@ -90,8 +91,8 @@ static void cifs_fscache_disable_inode_cookie(struct inode *inode) | |||
90 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 91 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
91 | 92 | ||
92 | if (cifsi->fscache) { | 93 | if (cifsi->fscache) { |
93 | cFYI(1, "CIFS disabling inode cookie (0x%p)", | 94 | cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache); |
94 | cifsi->fscache); | 95 | fscache_uncache_all_inode_pages(cifsi->fscache, inode); |
95 | fscache_relinquish_cookie(cifsi->fscache, 1); | 96 | fscache_relinquish_cookie(cifsi->fscache, 1); |
96 | cifsi->fscache = NULL; | 97 | cifsi->fscache = NULL; |
97 | } | 98 | } |
@@ -101,10 +102,8 @@ void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | |||
101 | { | 102 | { |
102 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | 103 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) |
103 | cifs_fscache_disable_inode_cookie(inode); | 104 | cifs_fscache_disable_inode_cookie(inode); |
104 | else { | 105 | else |
105 | cifs_fscache_enable_inode_cookie(inode); | 106 | cifs_fscache_enable_inode_cookie(inode); |
106 | cFYI(1, "CIFS: fscache inode cookie set"); | ||
107 | } | ||
108 | } | 107 | } |
109 | 108 | ||
110 | void cifs_fscache_reset_inode_cookie(struct inode *inode) | 109 | void cifs_fscache_reset_inode_cookie(struct inode *inode) |
@@ -117,11 +116,12 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode) | |||
117 | /* retire the current fscache cache and get a new one */ | 116 | /* retire the current fscache cache and get a new one */ |
118 | fscache_relinquish_cookie(cifsi->fscache, 1); | 117 | fscache_relinquish_cookie(cifsi->fscache, 1); |
119 | 118 | ||
120 | cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, | 119 | cifsi->fscache = fscache_acquire_cookie( |
120 | cifs_sb_master_tcon(cifs_sb)->fscache, | ||
121 | &cifs_fscache_inode_object_def, | 121 | &cifs_fscache_inode_object_def, |
122 | cifsi); | 122 | cifsi); |
123 | cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p", | 123 | cFYI(1, "%s: new cookie 0x%p oldcookie 0x%p", |
124 | cifsi->fscache, old); | 124 | __func__, cifsi->fscache, old); |
125 | } | 125 | } |
126 | } | 126 | } |
127 | 127 | ||
@@ -131,8 +131,8 @@ int cifs_fscache_release_page(struct page *page, gfp_t gfp) | |||
131 | struct inode *inode = page->mapping->host; | 131 | struct inode *inode = page->mapping->host; |
132 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 132 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
133 | 133 | ||
134 | cFYI(1, "CIFS: fscache release page (0x%p/0x%p)", | 134 | cFYI(1, "%s: (0x%p/0x%p)", __func__, page, |
135 | page, cifsi->fscache); | 135 | cifsi->fscache); |
136 | if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) | 136 | if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) |
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
@@ -143,8 +143,7 @@ int cifs_fscache_release_page(struct page *page, gfp_t gfp) | |||
143 | static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx, | 143 | static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx, |
144 | int error) | 144 | int error) |
145 | { | 145 | { |
146 | cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)", | 146 | cFYI(1, "%s: (0x%p/%d)", __func__, page, error); |
147 | page, error); | ||
148 | if (!error) | 147 | if (!error) |
149 | SetPageUptodate(page); | 148 | SetPageUptodate(page); |
150 | unlock_page(page); | 149 | unlock_page(page); |
@@ -157,7 +156,7 @@ int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) | |||
157 | { | 156 | { |
158 | int ret; | 157 | int ret; |
159 | 158 | ||
160 | cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p", | 159 | cFYI(1, "%s: (fsc:%p, p:%p, i:0x%p", __func__, |
161 | CIFS_I(inode)->fscache, page, inode); | 160 | CIFS_I(inode)->fscache, page, inode); |
162 | ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page, | 161 | ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page, |
163 | cifs_readpage_from_fscache_complete, | 162 | cifs_readpage_from_fscache_complete, |
@@ -166,11 +165,11 @@ int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) | |||
166 | switch (ret) { | 165 | switch (ret) { |
167 | 166 | ||
168 | case 0: /* page found in fscache, read submitted */ | 167 | case 0: /* page found in fscache, read submitted */ |
169 | cFYI(1, "CIFS: readpage_from_fscache: submitted"); | 168 | cFYI(1, "%s: submitted", __func__); |
170 | return ret; | 169 | return ret; |
171 | case -ENOBUFS: /* page won't be cached */ | 170 | case -ENOBUFS: /* page won't be cached */ |
172 | case -ENODATA: /* page not in cache */ | 171 | case -ENODATA: /* page not in cache */ |
173 | cFYI(1, "CIFS: readpage_from_fscache %d", ret); | 172 | cFYI(1, "%s: %d", __func__, ret); |
174 | return 1; | 173 | return 1; |
175 | 174 | ||
176 | default: | 175 | default: |
@@ -189,7 +188,7 @@ int __cifs_readpages_from_fscache(struct inode *inode, | |||
189 | { | 188 | { |
190 | int ret; | 189 | int ret; |
191 | 190 | ||
192 | cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)", | 191 | cFYI(1, "%s: (0x%p/%u/0x%p)", __func__, |
193 | CIFS_I(inode)->fscache, *nr_pages, inode); | 192 | CIFS_I(inode)->fscache, *nr_pages, inode); |
194 | ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping, | 193 | ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping, |
195 | pages, nr_pages, | 194 | pages, nr_pages, |
@@ -198,12 +197,12 @@ int __cifs_readpages_from_fscache(struct inode *inode, | |||
198 | mapping_gfp_mask(mapping)); | 197 | mapping_gfp_mask(mapping)); |
199 | switch (ret) { | 198 | switch (ret) { |
200 | case 0: /* read submitted to the cache for all pages */ | 199 | case 0: /* read submitted to the cache for all pages */ |
201 | cFYI(1, "CIFS: readpages_from_fscache: submitted"); | 200 | cFYI(1, "%s: submitted", __func__); |
202 | return ret; | 201 | return ret; |
203 | 202 | ||
204 | case -ENOBUFS: /* some pages are not cached and can't be */ | 203 | case -ENOBUFS: /* some pages are not cached and can't be */ |
205 | case -ENODATA: /* some pages are not cached */ | 204 | case -ENODATA: /* some pages are not cached */ |
206 | cFYI(1, "CIFS: readpages_from_fscache: no page"); | 205 | cFYI(1, "%s: no page", __func__); |
207 | return 1; | 206 | return 1; |
208 | 207 | ||
209 | default: | 208 | default: |
@@ -217,7 +216,7 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) | |||
217 | { | 216 | { |
218 | int ret; | 217 | int ret; |
219 | 218 | ||
220 | cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p", | 219 | cFYI(1, "%s: (fsc: %p, p: %p, i: %p)", __func__, |
221 | CIFS_I(inode)->fscache, page, inode); | 220 | CIFS_I(inode)->fscache, page, inode); |
222 | ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL); | 221 | ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL); |
223 | if (ret != 0) | 222 | if (ret != 0) |
@@ -229,7 +228,7 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) | |||
229 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 228 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
230 | struct fscache_cookie *cookie = cifsi->fscache; | 229 | struct fscache_cookie *cookie = cifsi->fscache; |
231 | 230 | ||
232 | cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie); | 231 | cFYI(1, "%s: (0x%p/0x%p)", __func__, page, cookie); |
233 | fscache_wait_on_page_write(cookie, page); | 232 | fscache_wait_on_page_write(cookie, page); |
234 | fscache_uncache_page(cookie, page); | 233 | fscache_uncache_page(cookie, page); |
235 | } | 234 | } |
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 31b88ec2341e..63539323e0b9 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h | |||
@@ -40,8 +40,8 @@ extern void cifs_fscache_unregister(void); | |||
40 | */ | 40 | */ |
41 | extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); | 41 | extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); |
42 | extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *); | 42 | extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *); |
43 | extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *); | 43 | extern void cifs_fscache_get_super_cookie(struct cifs_tcon *); |
44 | extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *); | 44 | extern void cifs_fscache_release_super_cookie(struct cifs_tcon *); |
45 | 45 | ||
46 | extern void cifs_fscache_release_inode_cookie(struct inode *); | 46 | extern void cifs_fscache_release_inode_cookie(struct inode *); |
47 | extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *); | 47 | extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *); |
@@ -99,9 +99,9 @@ static inline void | |||
99 | cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {} | 99 | cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {} |
100 | static inline void | 100 | static inline void |
101 | cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {} | 101 | cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {} |
102 | static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {} | 102 | static inline void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon) {} |
103 | static inline void | 103 | static inline void |
104 | cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {} | 104 | cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} |
105 | 105 | ||
106 | static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} | 106 | static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} |
107 | static inline void cifs_fscache_set_inode_cookie(struct inode *inode, | 107 | static inline void cifs_fscache_set_inode_cookie(struct inode *inode, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 53cce8cc2224..9b018c8334fa 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include "fscache.h" | 32 | #include "fscache.h" |
33 | 33 | ||
34 | 34 | ||
35 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | 35 | static void cifs_set_ops(struct inode *inode) |
36 | { | 36 | { |
37 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 37 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
38 | 38 | ||
@@ -44,15 +44,19 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | |||
44 | inode->i_fop = &cifs_file_direct_nobrl_ops; | 44 | inode->i_fop = &cifs_file_direct_nobrl_ops; |
45 | else | 45 | else |
46 | inode->i_fop = &cifs_file_direct_ops; | 46 | inode->i_fop = &cifs_file_direct_ops; |
47 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { | ||
48 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
49 | inode->i_fop = &cifs_file_strict_nobrl_ops; | ||
50 | else | ||
51 | inode->i_fop = &cifs_file_strict_ops; | ||
47 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 52 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
48 | inode->i_fop = &cifs_file_nobrl_ops; | 53 | inode->i_fop = &cifs_file_nobrl_ops; |
49 | else { /* not direct, send byte range locks */ | 54 | else { /* not direct, send byte range locks */ |
50 | inode->i_fop = &cifs_file_ops; | 55 | inode->i_fop = &cifs_file_ops; |
51 | } | 56 | } |
52 | 57 | ||
53 | |||
54 | /* check if server can support readpages */ | 58 | /* check if server can support readpages */ |
55 | if (cifs_sb->tcon->ses->server->maxBuf < | 59 | if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < |
56 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) | 60 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) |
57 | inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | 61 | inode->i_data.a_ops = &cifs_addr_ops_smallbuf; |
58 | else | 62 | else |
@@ -60,7 +64,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | |||
60 | break; | 64 | break; |
61 | case S_IFDIR: | 65 | case S_IFDIR: |
62 | #ifdef CONFIG_CIFS_DFS_UPCALL | 66 | #ifdef CONFIG_CIFS_DFS_UPCALL |
63 | if (is_dfs_referral) { | 67 | if (IS_AUTOMOUNT(inode)) { |
64 | inode->i_op = &cifs_dfs_referral_inode_operations; | 68 | inode->i_op = &cifs_dfs_referral_inode_operations; |
65 | } else { | 69 | } else { |
66 | #else /* NO DFS support, treat as a directory */ | 70 | #else /* NO DFS support, treat as a directory */ |
@@ -167,7 +171,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | |||
167 | } | 171 | } |
168 | spin_unlock(&inode->i_lock); | 172 | spin_unlock(&inode->i_lock); |
169 | 173 | ||
170 | cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); | 174 | if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) |
175 | inode->i_flags |= S_AUTOMOUNT; | ||
176 | cifs_set_ops(inode); | ||
171 | } | 177 | } |
172 | 178 | ||
173 | void | 179 | void |
@@ -288,8 +294,8 @@ int cifs_get_file_info_unix(struct file *filp) | |||
288 | struct cifs_fattr fattr; | 294 | struct cifs_fattr fattr; |
289 | struct inode *inode = filp->f_path.dentry->d_inode; | 295 | struct inode *inode = filp->f_path.dentry->d_inode; |
290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 296 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
291 | struct cifsTconInfo *tcon = cifs_sb->tcon; | ||
292 | struct cifsFileInfo *cfile = filp->private_data; | 297 | struct cifsFileInfo *cfile = filp->private_data; |
298 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
293 | 299 | ||
294 | xid = GetXid(); | 300 | xid = GetXid(); |
295 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); | 301 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); |
@@ -312,16 +318,22 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
312 | int rc; | 318 | int rc; |
313 | FILE_UNIX_BASIC_INFO find_data; | 319 | FILE_UNIX_BASIC_INFO find_data; |
314 | struct cifs_fattr fattr; | 320 | struct cifs_fattr fattr; |
315 | struct cifsTconInfo *tcon; | 321 | struct cifs_tcon *tcon; |
322 | struct tcon_link *tlink; | ||
316 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 323 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
317 | 324 | ||
318 | tcon = cifs_sb->tcon; | ||
319 | cFYI(1, "Getting info on %s", full_path); | 325 | cFYI(1, "Getting info on %s", full_path); |
320 | 326 | ||
327 | tlink = cifs_sb_tlink(cifs_sb); | ||
328 | if (IS_ERR(tlink)) | ||
329 | return PTR_ERR(tlink); | ||
330 | tcon = tlink_tcon(tlink); | ||
331 | |||
321 | /* could have done a find first instead but this returns more info */ | 332 | /* could have done a find first instead but this returns more info */ |
322 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, | 333 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, |
323 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 334 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
324 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 335 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
336 | cifs_put_tlink(tlink); | ||
325 | 337 | ||
326 | if (!rc) { | 338 | if (!rc) { |
327 | cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); | 339 | cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); |
@@ -332,6 +344,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
332 | return rc; | 344 | return rc; |
333 | } | 345 | } |
334 | 346 | ||
347 | /* check for Minshall+French symlinks */ | ||
348 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { | ||
349 | int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); | ||
350 | if (tmprc) | ||
351 | cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); | ||
352 | } | ||
353 | |||
335 | if (*pinode == NULL) { | 354 | if (*pinode == NULL) { |
336 | /* get new inode */ | 355 | /* get new inode */ |
337 | cifs_fill_uniqueid(sb, &fattr); | 356 | cifs_fill_uniqueid(sb, &fattr); |
@@ -353,7 +372,9 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, | |||
353 | int rc; | 372 | int rc; |
354 | int oplock = 0; | 373 | int oplock = 0; |
355 | __u16 netfid; | 374 | __u16 netfid; |
356 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 375 | struct tcon_link *tlink; |
376 | struct cifs_tcon *tcon; | ||
377 | struct cifs_io_parms io_parms; | ||
357 | char buf[24]; | 378 | char buf[24]; |
358 | unsigned int bytes_read; | 379 | unsigned int bytes_read; |
359 | char *pbuf; | 380 | char *pbuf; |
@@ -372,7 +393,12 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, | |||
372 | return -EINVAL; /* EOPNOTSUPP? */ | 393 | return -EINVAL; /* EOPNOTSUPP? */ |
373 | } | 394 | } |
374 | 395 | ||
375 | rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, | 396 | tlink = cifs_sb_tlink(cifs_sb); |
397 | if (IS_ERR(tlink)) | ||
398 | return PTR_ERR(tlink); | ||
399 | tcon = tlink_tcon(tlink); | ||
400 | |||
401 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ, | ||
376 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | 402 | CREATE_NOT_DIR, &netfid, &oplock, NULL, |
377 | cifs_sb->local_nls, | 403 | cifs_sb->local_nls, |
378 | cifs_sb->mnt_cifs_flags & | 404 | cifs_sb->mnt_cifs_flags & |
@@ -380,9 +406,13 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, | |||
380 | if (rc == 0) { | 406 | if (rc == 0) { |
381 | int buf_type = CIFS_NO_BUFFER; | 407 | int buf_type = CIFS_NO_BUFFER; |
382 | /* Read header */ | 408 | /* Read header */ |
383 | rc = CIFSSMBRead(xid, pTcon, netfid, | 409 | io_parms.netfid = netfid; |
384 | 24 /* length */, 0 /* offset */, | 410 | io_parms.pid = current->tgid; |
385 | &bytes_read, &pbuf, &buf_type); | 411 | io_parms.tcon = tcon; |
412 | io_parms.offset = 0; | ||
413 | io_parms.length = 24; | ||
414 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, | ||
415 | &buf_type); | ||
386 | if ((rc == 0) && (bytes_read >= 8)) { | 416 | if ((rc == 0) && (bytes_read >= 8)) { |
387 | if (memcmp("IntxBLK", pbuf, 8) == 0) { | 417 | if (memcmp("IntxBLK", pbuf, 8) == 0) { |
388 | cFYI(1, "Block device"); | 418 | cFYI(1, "Block device"); |
@@ -422,8 +452,9 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, | |||
422 | fattr->cf_dtype = DT_REG; | 452 | fattr->cf_dtype = DT_REG; |
423 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ | 453 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ |
424 | } | 454 | } |
425 | CIFSSMBClose(xid, pTcon, netfid); | 455 | CIFSSMBClose(xid, tcon, netfid); |
426 | } | 456 | } |
457 | cifs_put_tlink(tlink); | ||
427 | return rc; | 458 | return rc; |
428 | } | 459 | } |
429 | 460 | ||
@@ -441,11 +472,19 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | |||
441 | ssize_t rc; | 472 | ssize_t rc; |
442 | char ea_value[4]; | 473 | char ea_value[4]; |
443 | __u32 mode; | 474 | __u32 mode; |
475 | struct tcon_link *tlink; | ||
476 | struct cifs_tcon *tcon; | ||
477 | |||
478 | tlink = cifs_sb_tlink(cifs_sb); | ||
479 | if (IS_ERR(tlink)) | ||
480 | return PTR_ERR(tlink); | ||
481 | tcon = tlink_tcon(tlink); | ||
444 | 482 | ||
445 | rc = CIFSSMBQAllEAs(xid, cifs_sb->tcon, path, "SETFILEBITS", | 483 | rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS", |
446 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, | 484 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, |
447 | cifs_sb->mnt_cifs_flags & | 485 | cifs_sb->mnt_cifs_flags & |
448 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 486 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
487 | cifs_put_tlink(tlink); | ||
449 | if (rc < 0) | 488 | if (rc < 0) |
450 | return (int)rc; | 489 | return (int)rc; |
451 | else if (rc > 3) { | 490 | else if (rc > 3) { |
@@ -468,6 +507,8 @@ static void | |||
468 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | 507 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
469 | struct cifs_sb_info *cifs_sb, bool adjust_tz) | 508 | struct cifs_sb_info *cifs_sb, bool adjust_tz) |
470 | { | 509 | { |
510 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | ||
511 | |||
471 | memset(fattr, 0, sizeof(*fattr)); | 512 | memset(fattr, 0, sizeof(*fattr)); |
472 | fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); | 513 | fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); |
473 | if (info->DeletePending) | 514 | if (info->DeletePending) |
@@ -482,12 +523,13 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | |||
482 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | 523 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
483 | 524 | ||
484 | if (adjust_tz) { | 525 | if (adjust_tz) { |
485 | fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; | 526 | fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj; |
486 | fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; | 527 | fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj; |
487 | } | 528 | } |
488 | 529 | ||
489 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 530 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
490 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 531 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
532 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
491 | 533 | ||
492 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | 534 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
493 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | 535 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; |
@@ -515,8 +557,8 @@ int cifs_get_file_info(struct file *filp) | |||
515 | struct cifs_fattr fattr; | 557 | struct cifs_fattr fattr; |
516 | struct inode *inode = filp->f_path.dentry->d_inode; | 558 | struct inode *inode = filp->f_path.dentry->d_inode; |
517 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 559 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
518 | struct cifsTconInfo *tcon = cifs_sb->tcon; | ||
519 | struct cifsFileInfo *cfile = filp->private_data; | 560 | struct cifsFileInfo *cfile = filp->private_data; |
561 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
520 | 562 | ||
521 | xid = GetXid(); | 563 | xid = GetXid(); |
522 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); | 564 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); |
@@ -553,27 +595,34 @@ int cifs_get_inode_info(struct inode **pinode, | |||
553 | struct super_block *sb, int xid, const __u16 *pfid) | 595 | struct super_block *sb, int xid, const __u16 *pfid) |
554 | { | 596 | { |
555 | int rc = 0, tmprc; | 597 | int rc = 0, tmprc; |
556 | struct cifsTconInfo *pTcon; | 598 | struct cifs_tcon *pTcon; |
599 | struct tcon_link *tlink; | ||
557 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 600 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
558 | char *buf = NULL; | 601 | char *buf = NULL; |
559 | bool adjustTZ = false; | 602 | bool adjustTZ = false; |
560 | struct cifs_fattr fattr; | 603 | struct cifs_fattr fattr; |
561 | 604 | ||
562 | pTcon = cifs_sb->tcon; | 605 | tlink = cifs_sb_tlink(cifs_sb); |
606 | if (IS_ERR(tlink)) | ||
607 | return PTR_ERR(tlink); | ||
608 | pTcon = tlink_tcon(tlink); | ||
609 | |||
563 | cFYI(1, "Getting info on %s", full_path); | 610 | cFYI(1, "Getting info on %s", full_path); |
564 | 611 | ||
565 | if ((pfindData == NULL) && (*pinode != NULL)) { | 612 | if ((pfindData == NULL) && (*pinode != NULL)) { |
566 | if (CIFS_I(*pinode)->clientCanCacheRead) { | 613 | if (CIFS_I(*pinode)->clientCanCacheRead) { |
567 | cFYI(1, "No need to revalidate cached inode sizes"); | 614 | cFYI(1, "No need to revalidate cached inode sizes"); |
568 | return rc; | 615 | goto cgii_exit; |
569 | } | 616 | } |
570 | } | 617 | } |
571 | 618 | ||
572 | /* if file info not passed in then get it from server */ | 619 | /* if file info not passed in then get it from server */ |
573 | if (pfindData == NULL) { | 620 | if (pfindData == NULL) { |
574 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 621 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
575 | if (buf == NULL) | 622 | if (buf == NULL) { |
576 | return -ENOMEM; | 623 | rc = -ENOMEM; |
624 | goto cgii_exit; | ||
625 | } | ||
577 | pfindData = (FILE_ALL_INFO *)buf; | 626 | pfindData = (FILE_ALL_INFO *)buf; |
578 | 627 | ||
579 | /* could do find first instead but this returns more info */ | 628 | /* could do find first instead but this returns more info */ |
@@ -649,18 +698,30 @@ int cifs_get_inode_info(struct inode **pinode, | |||
649 | cFYI(1, "cifs_sfu_type failed: %d", tmprc); | 698 | cFYI(1, "cifs_sfu_type failed: %d", tmprc); |
650 | } | 699 | } |
651 | 700 | ||
652 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 701 | #ifdef CONFIG_CIFS_ACL |
653 | /* fill in 0777 bits from ACL */ | 702 | /* fill in 0777 bits from ACL */ |
654 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 703 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
655 | cFYI(1, "Getting mode bits from ACL"); | 704 | rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, |
656 | cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); | 705 | pfid); |
706 | if (rc) { | ||
707 | cFYI(1, "%s: Getting ACL failed with error: %d", | ||
708 | __func__, rc); | ||
709 | goto cgii_exit; | ||
710 | } | ||
657 | } | 711 | } |
658 | #endif | 712 | #endif /* CONFIG_CIFS_ACL */ |
659 | 713 | ||
660 | /* fill in remaining high mode bits e.g. SUID, VTX */ | 714 | /* fill in remaining high mode bits e.g. SUID, VTX */ |
661 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 715 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
662 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); | 716 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); |
663 | 717 | ||
718 | /* check for Minshall+French symlinks */ | ||
719 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { | ||
720 | tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid); | ||
721 | if (tmprc) | ||
722 | cFYI(1, "CIFSCheckMFSymlink: %d", tmprc); | ||
723 | } | ||
724 | |||
664 | if (!*pinode) { | 725 | if (!*pinode) { |
665 | *pinode = cifs_iget(sb, &fattr); | 726 | *pinode = cifs_iget(sb, &fattr); |
666 | if (!*pinode) | 727 | if (!*pinode) |
@@ -671,6 +732,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
671 | 732 | ||
672 | cgii_exit: | 733 | cgii_exit: |
673 | kfree(buf); | 734 | kfree(buf); |
735 | cifs_put_tlink(tlink); | ||
674 | return rc; | 736 | return rc; |
675 | } | 737 | } |
676 | 738 | ||
@@ -678,9 +740,10 @@ static const struct inode_operations cifs_ipc_inode_ops = { | |||
678 | .lookup = cifs_lookup, | 740 | .lookup = cifs_lookup, |
679 | }; | 741 | }; |
680 | 742 | ||
681 | char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | 743 | char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, |
744 | struct cifs_tcon *tcon) | ||
682 | { | 745 | { |
683 | int pplen = cifs_sb->prepathlen; | 746 | int pplen = vol->prepath ? strlen(vol->prepath) : 0; |
684 | int dfsplen; | 747 | int dfsplen; |
685 | char *full_path = NULL; | 748 | char *full_path = NULL; |
686 | 749 | ||
@@ -692,8 +755,8 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | |||
692 | return full_path; | 755 | return full_path; |
693 | } | 756 | } |
694 | 757 | ||
695 | if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) | 758 | if (tcon->Flags & SMB_SHARE_IS_IN_DFS) |
696 | dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); | 759 | dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); |
697 | else | 760 | else |
698 | dfsplen = 0; | 761 | dfsplen = 0; |
699 | 762 | ||
@@ -702,7 +765,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | |||
702 | return full_path; | 765 | return full_path; |
703 | 766 | ||
704 | if (dfsplen) { | 767 | if (dfsplen) { |
705 | strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); | 768 | strncpy(full_path, tcon->treeName, dfsplen); |
706 | /* switch slash direction in prepath depending on whether | 769 | /* switch slash direction in prepath depending on whether |
707 | * windows or posix style path names | 770 | * windows or posix style path names |
708 | */ | 771 | */ |
@@ -714,7 +777,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | |||
714 | } | 777 | } |
715 | } | 778 | } |
716 | } | 779 | } |
717 | strncpy(full_path + dfsplen, cifs_sb->prepath, pplen); | 780 | strncpy(full_path + dfsplen, vol->prepath, pplen); |
718 | full_path[dfsplen + pplen] = 0; /* add trailing null */ | 781 | full_path[dfsplen + pplen] = 0; /* add trailing null */ |
719 | return full_path; | 782 | return full_path; |
720 | } | 783 | } |
@@ -728,6 +791,10 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
728 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 791 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
729 | return 0; | 792 | return 0; |
730 | 793 | ||
794 | /* use createtime like an i_generation field */ | ||
795 | if (CIFS_I(inode)->createtime != fattr->cf_createtime) | ||
796 | return 0; | ||
797 | |||
731 | /* don't match inode of different type */ | 798 | /* don't match inode of different type */ |
732 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) | 799 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) |
733 | return 0; | 800 | return 0; |
@@ -745,6 +812,7 @@ cifs_init_inode(struct inode *inode, void *opaque) | |||
745 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 812 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; |
746 | 813 | ||
747 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; | 814 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; |
815 | CIFS_I(inode)->createtime = fattr->cf_createtime; | ||
748 | return 0; | 816 | return 0; |
749 | } | 817 | } |
750 | 818 | ||
@@ -758,14 +826,14 @@ inode_has_hashed_dentries(struct inode *inode) | |||
758 | { | 826 | { |
759 | struct dentry *dentry; | 827 | struct dentry *dentry; |
760 | 828 | ||
761 | spin_lock(&dcache_lock); | 829 | spin_lock(&inode->i_lock); |
762 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | 830 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
763 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { | 831 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { |
764 | spin_unlock(&dcache_lock); | 832 | spin_unlock(&inode->i_lock); |
765 | return true; | 833 | return true; |
766 | } | 834 | } |
767 | } | 835 | } |
768 | spin_unlock(&dcache_lock); | 836 | spin_unlock(&inode->i_lock); |
769 | return false; | 837 | return false; |
770 | } | 838 | } |
771 | 839 | ||
@@ -815,35 +883,31 @@ retry_iget5_locked: | |||
815 | } | 883 | } |
816 | 884 | ||
817 | /* gets root inode */ | 885 | /* gets root inode */ |
818 | struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | 886 | struct inode *cifs_root_iget(struct super_block *sb) |
819 | { | 887 | { |
820 | int xid; | 888 | int xid; |
821 | struct cifs_sb_info *cifs_sb; | 889 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
822 | struct inode *inode = NULL; | 890 | struct inode *inode = NULL; |
823 | long rc; | 891 | long rc; |
824 | char *full_path; | 892 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
825 | |||
826 | cifs_sb = CIFS_SB(sb); | ||
827 | full_path = cifs_build_path_to_root(cifs_sb); | ||
828 | if (full_path == NULL) | ||
829 | return ERR_PTR(-ENOMEM); | ||
830 | 893 | ||
831 | xid = GetXid(); | 894 | xid = GetXid(); |
832 | if (cifs_sb->tcon->unix_ext) | 895 | if (tcon->unix_ext) |
833 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); | 896 | rc = cifs_get_inode_info_unix(&inode, "", sb, xid); |
834 | else | 897 | else |
835 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, | 898 | rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL); |
836 | xid, NULL); | ||
837 | 899 | ||
838 | if (!inode) | 900 | if (!inode) { |
839 | return ERR_PTR(rc); | 901 | inode = ERR_PTR(rc); |
902 | goto out; | ||
903 | } | ||
840 | 904 | ||
841 | #ifdef CONFIG_CIFS_FSCACHE | 905 | #ifdef CONFIG_CIFS_FSCACHE |
842 | /* populate tcon->resource_id */ | 906 | /* populate tcon->resource_id */ |
843 | cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; | 907 | tcon->resource_id = CIFS_I(inode)->uniqueid; |
844 | #endif | 908 | #endif |
845 | 909 | ||
846 | if (rc && cifs_sb->tcon->ipc) { | 910 | if (rc && tcon->ipc) { |
847 | cFYI(1, "ipc connection - fake read inode"); | 911 | cFYI(1, "ipc connection - fake read inode"); |
848 | inode->i_mode |= S_IFDIR; | 912 | inode->i_mode |= S_IFDIR; |
849 | inode->i_nlink = 2; | 913 | inode->i_nlink = 2; |
@@ -852,14 +916,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
852 | inode->i_uid = cifs_sb->mnt_uid; | 916 | inode->i_uid = cifs_sb->mnt_uid; |
853 | inode->i_gid = cifs_sb->mnt_gid; | 917 | inode->i_gid = cifs_sb->mnt_gid; |
854 | } else if (rc) { | 918 | } else if (rc) { |
855 | kfree(full_path); | ||
856 | _FreeXid(xid); | ||
857 | iget_failed(inode); | 919 | iget_failed(inode); |
858 | return ERR_PTR(rc); | 920 | inode = ERR_PTR(rc); |
859 | } | 921 | } |
860 | 922 | ||
861 | 923 | out: | |
862 | kfree(full_path); | ||
863 | /* can not call macro FreeXid here since in a void func | 924 | /* can not call macro FreeXid here since in a void func |
864 | * TODO: This is no longer true | 925 | * TODO: This is no longer true |
865 | */ | 926 | */ |
@@ -879,7 +940,8 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | |||
879 | struct cifsFileInfo *open_file; | 940 | struct cifsFileInfo *open_file; |
880 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 941 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
881 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 942 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
882 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 943 | struct tcon_link *tlink = NULL; |
944 | struct cifs_tcon *pTcon; | ||
883 | FILE_BASIC_INFO info_buf; | 945 | FILE_BASIC_INFO info_buf; |
884 | 946 | ||
885 | if (attrs == NULL) | 947 | if (attrs == NULL) |
@@ -918,13 +980,22 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | |||
918 | /* | 980 | /* |
919 | * If the file is already open for write, just use that fileid | 981 | * If the file is already open for write, just use that fileid |
920 | */ | 982 | */ |
921 | open_file = find_writable_file(cifsInode); | 983 | open_file = find_writable_file(cifsInode, true); |
922 | if (open_file) { | 984 | if (open_file) { |
923 | netfid = open_file->netfid; | 985 | netfid = open_file->netfid; |
924 | netpid = open_file->pid; | 986 | netpid = open_file->pid; |
987 | pTcon = tlink_tcon(open_file->tlink); | ||
925 | goto set_via_filehandle; | 988 | goto set_via_filehandle; |
926 | } | 989 | } |
927 | 990 | ||
991 | tlink = cifs_sb_tlink(cifs_sb); | ||
992 | if (IS_ERR(tlink)) { | ||
993 | rc = PTR_ERR(tlink); | ||
994 | tlink = NULL; | ||
995 | goto out; | ||
996 | } | ||
997 | pTcon = tlink_tcon(tlink); | ||
998 | |||
928 | /* | 999 | /* |
929 | * NT4 apparently returns success on this call, but it doesn't | 1000 | * NT4 apparently returns success on this call, but it doesn't |
930 | * really work. | 1001 | * really work. |
@@ -968,6 +1039,8 @@ set_via_filehandle: | |||
968 | else | 1039 | else |
969 | cifsFileInfo_put(open_file); | 1040 | cifsFileInfo_put(open_file); |
970 | out: | 1041 | out: |
1042 | if (tlink != NULL) | ||
1043 | cifs_put_tlink(tlink); | ||
971 | return rc; | 1044 | return rc; |
972 | } | 1045 | } |
973 | 1046 | ||
@@ -985,10 +1058,16 @@ cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid) | |||
985 | struct inode *inode = dentry->d_inode; | 1058 | struct inode *inode = dentry->d_inode; |
986 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 1059 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
987 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1060 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
988 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 1061 | struct tcon_link *tlink; |
1062 | struct cifs_tcon *tcon; | ||
989 | __u32 dosattr, origattr; | 1063 | __u32 dosattr, origattr; |
990 | FILE_BASIC_INFO *info_buf = NULL; | 1064 | FILE_BASIC_INFO *info_buf = NULL; |
991 | 1065 | ||
1066 | tlink = cifs_sb_tlink(cifs_sb); | ||
1067 | if (IS_ERR(tlink)) | ||
1068 | return PTR_ERR(tlink); | ||
1069 | tcon = tlink_tcon(tlink); | ||
1070 | |||
992 | rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, | 1071 | rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, |
993 | DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, | 1072 | DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, |
994 | &netfid, &oplock, NULL, cifs_sb->local_nls, | 1073 | &netfid, &oplock, NULL, cifs_sb->local_nls, |
@@ -1057,6 +1136,7 @@ out_close: | |||
1057 | CIFSSMBClose(xid, tcon, netfid); | 1136 | CIFSSMBClose(xid, tcon, netfid); |
1058 | out: | 1137 | out: |
1059 | kfree(info_buf); | 1138 | kfree(info_buf); |
1139 | cifs_put_tlink(tlink); | ||
1060 | return rc; | 1140 | return rc; |
1061 | 1141 | ||
1062 | /* | 1142 | /* |
@@ -1096,12 +1176,18 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) | |||
1096 | struct cifsInodeInfo *cifs_inode; | 1176 | struct cifsInodeInfo *cifs_inode; |
1097 | struct super_block *sb = dir->i_sb; | 1177 | struct super_block *sb = dir->i_sb; |
1098 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 1178 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
1099 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 1179 | struct tcon_link *tlink; |
1180 | struct cifs_tcon *tcon; | ||
1100 | struct iattr *attrs = NULL; | 1181 | struct iattr *attrs = NULL; |
1101 | __u32 dosattr = 0, origattr = 0; | 1182 | __u32 dosattr = 0, origattr = 0; |
1102 | 1183 | ||
1103 | cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry); | 1184 | cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry); |
1104 | 1185 | ||
1186 | tlink = cifs_sb_tlink(cifs_sb); | ||
1187 | if (IS_ERR(tlink)) | ||
1188 | return PTR_ERR(tlink); | ||
1189 | tcon = tlink_tcon(tlink); | ||
1190 | |||
1105 | xid = GetXid(); | 1191 | xid = GetXid(); |
1106 | 1192 | ||
1107 | /* Unlink can be called from rename so we can not take the | 1193 | /* Unlink can be called from rename so we can not take the |
@@ -1109,8 +1195,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) | |||
1109 | full_path = build_path_from_dentry(dentry); | 1195 | full_path = build_path_from_dentry(dentry); |
1110 | if (full_path == NULL) { | 1196 | if (full_path == NULL) { |
1111 | rc = -ENOMEM; | 1197 | rc = -ENOMEM; |
1112 | FreeXid(xid); | 1198 | goto unlink_out; |
1113 | return rc; | ||
1114 | } | 1199 | } |
1115 | 1200 | ||
1116 | if ((tcon->ses->capabilities & CAP_UNIX) && | 1201 | if ((tcon->ses->capabilities & CAP_UNIX) && |
@@ -1176,10 +1261,11 @@ out_reval: | |||
1176 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); | 1261 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
1177 | cifs_inode = CIFS_I(dir); | 1262 | cifs_inode = CIFS_I(dir); |
1178 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ | 1263 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
1179 | 1264 | unlink_out: | |
1180 | kfree(full_path); | 1265 | kfree(full_path); |
1181 | kfree(attrs); | 1266 | kfree(attrs); |
1182 | FreeXid(xid); | 1267 | FreeXid(xid); |
1268 | cifs_put_tlink(tlink); | ||
1183 | return rc; | 1269 | return rc; |
1184 | } | 1270 | } |
1185 | 1271 | ||
@@ -1188,23 +1274,26 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1188 | int rc = 0, tmprc; | 1274 | int rc = 0, tmprc; |
1189 | int xid; | 1275 | int xid; |
1190 | struct cifs_sb_info *cifs_sb; | 1276 | struct cifs_sb_info *cifs_sb; |
1191 | struct cifsTconInfo *pTcon; | 1277 | struct tcon_link *tlink; |
1278 | struct cifs_tcon *pTcon; | ||
1192 | char *full_path = NULL; | 1279 | char *full_path = NULL; |
1193 | struct inode *newinode = NULL; | 1280 | struct inode *newinode = NULL; |
1194 | struct cifs_fattr fattr; | 1281 | struct cifs_fattr fattr; |
1195 | 1282 | ||
1196 | cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode); | 1283 | cFYI(1, "In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode); |
1197 | 1284 | ||
1198 | xid = GetXid(); | ||
1199 | |||
1200 | cifs_sb = CIFS_SB(inode->i_sb); | 1285 | cifs_sb = CIFS_SB(inode->i_sb); |
1201 | pTcon = cifs_sb->tcon; | 1286 | tlink = cifs_sb_tlink(cifs_sb); |
1287 | if (IS_ERR(tlink)) | ||
1288 | return PTR_ERR(tlink); | ||
1289 | pTcon = tlink_tcon(tlink); | ||
1290 | |||
1291 | xid = GetXid(); | ||
1202 | 1292 | ||
1203 | full_path = build_path_from_dentry(direntry); | 1293 | full_path = build_path_from_dentry(direntry); |
1204 | if (full_path == NULL) { | 1294 | if (full_path == NULL) { |
1205 | rc = -ENOMEM; | 1295 | rc = -ENOMEM; |
1206 | FreeXid(xid); | 1296 | goto mkdir_out; |
1207 | return rc; | ||
1208 | } | 1297 | } |
1209 | 1298 | ||
1210 | if ((pTcon->ses->capabilities & CAP_UNIX) && | 1299 | if ((pTcon->ses->capabilities & CAP_UNIX) && |
@@ -1239,10 +1328,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1239 | /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need | 1328 | /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need |
1240 | to set uid/gid */ | 1329 | to set uid/gid */ |
1241 | inc_nlink(inode); | 1330 | inc_nlink(inode); |
1242 | if (pTcon->nocase) | ||
1243 | direntry->d_op = &cifs_ci_dentry_ops; | ||
1244 | else | ||
1245 | direntry->d_op = &cifs_dentry_ops; | ||
1246 | 1331 | ||
1247 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); | 1332 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); |
1248 | cifs_fill_uniqueid(inode->i_sb, &fattr); | 1333 | cifs_fill_uniqueid(inode->i_sb, &fattr); |
@@ -1283,10 +1368,6 @@ mkdir_get_info: | |||
1283 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 1368 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
1284 | inode->i_sb, xid, NULL); | 1369 | inode->i_sb, xid, NULL); |
1285 | 1370 | ||
1286 | if (pTcon->nocase) | ||
1287 | direntry->d_op = &cifs_ci_dentry_ops; | ||
1288 | else | ||
1289 | direntry->d_op = &cifs_dentry_ops; | ||
1290 | d_instantiate(direntry, newinode); | 1371 | d_instantiate(direntry, newinode); |
1291 | /* setting nlink not necessary except in cases where we | 1372 | /* setting nlink not necessary except in cases where we |
1292 | * failed to get it from the server or was set bogus */ | 1373 | * failed to get it from the server or was set bogus */ |
@@ -1362,6 +1443,7 @@ mkdir_get_info: | |||
1362 | mkdir_out: | 1443 | mkdir_out: |
1363 | kfree(full_path); | 1444 | kfree(full_path); |
1364 | FreeXid(xid); | 1445 | FreeXid(xid); |
1446 | cifs_put_tlink(tlink); | ||
1365 | return rc; | 1447 | return rc; |
1366 | } | 1448 | } |
1367 | 1449 | ||
@@ -1370,7 +1452,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
1370 | int rc = 0; | 1452 | int rc = 0; |
1371 | int xid; | 1453 | int xid; |
1372 | struct cifs_sb_info *cifs_sb; | 1454 | struct cifs_sb_info *cifs_sb; |
1373 | struct cifsTconInfo *pTcon; | 1455 | struct tcon_link *tlink; |
1456 | struct cifs_tcon *pTcon; | ||
1374 | char *full_path = NULL; | 1457 | char *full_path = NULL; |
1375 | struct cifsInodeInfo *cifsInode; | 1458 | struct cifsInodeInfo *cifsInode; |
1376 | 1459 | ||
@@ -1378,18 +1461,23 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
1378 | 1461 | ||
1379 | xid = GetXid(); | 1462 | xid = GetXid(); |
1380 | 1463 | ||
1381 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1382 | pTcon = cifs_sb->tcon; | ||
1383 | |||
1384 | full_path = build_path_from_dentry(direntry); | 1464 | full_path = build_path_from_dentry(direntry); |
1385 | if (full_path == NULL) { | 1465 | if (full_path == NULL) { |
1386 | rc = -ENOMEM; | 1466 | rc = -ENOMEM; |
1387 | FreeXid(xid); | 1467 | goto rmdir_exit; |
1388 | return rc; | ||
1389 | } | 1468 | } |
1390 | 1469 | ||
1470 | cifs_sb = CIFS_SB(inode->i_sb); | ||
1471 | tlink = cifs_sb_tlink(cifs_sb); | ||
1472 | if (IS_ERR(tlink)) { | ||
1473 | rc = PTR_ERR(tlink); | ||
1474 | goto rmdir_exit; | ||
1475 | } | ||
1476 | pTcon = tlink_tcon(tlink); | ||
1477 | |||
1391 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, | 1478 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, |
1392 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 1479 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
1480 | cifs_put_tlink(tlink); | ||
1393 | 1481 | ||
1394 | if (!rc) { | 1482 | if (!rc) { |
1395 | drop_nlink(inode); | 1483 | drop_nlink(inode); |
@@ -1410,6 +1498,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
1410 | direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = | 1498 | direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = |
1411 | current_fs_time(inode->i_sb); | 1499 | current_fs_time(inode->i_sb); |
1412 | 1500 | ||
1501 | rmdir_exit: | ||
1413 | kfree(full_path); | 1502 | kfree(full_path); |
1414 | FreeXid(xid); | 1503 | FreeXid(xid); |
1415 | return rc; | 1504 | return rc; |
@@ -1420,10 +1509,16 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, | |||
1420 | struct dentry *to_dentry, const char *toPath) | 1509 | struct dentry *to_dentry, const char *toPath) |
1421 | { | 1510 | { |
1422 | struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); | 1511 | struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb); |
1423 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 1512 | struct tcon_link *tlink; |
1513 | struct cifs_tcon *pTcon; | ||
1424 | __u16 srcfid; | 1514 | __u16 srcfid; |
1425 | int oplock, rc; | 1515 | int oplock, rc; |
1426 | 1516 | ||
1517 | tlink = cifs_sb_tlink(cifs_sb); | ||
1518 | if (IS_ERR(tlink)) | ||
1519 | return PTR_ERR(tlink); | ||
1520 | pTcon = tlink_tcon(tlink); | ||
1521 | |||
1427 | /* try path-based rename first */ | 1522 | /* try path-based rename first */ |
1428 | rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, | 1523 | rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls, |
1429 | cifs_sb->mnt_cifs_flags & | 1524 | cifs_sb->mnt_cifs_flags & |
@@ -1435,11 +1530,11 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, | |||
1435 | * rename by filehandle to various Windows servers. | 1530 | * rename by filehandle to various Windows servers. |
1436 | */ | 1531 | */ |
1437 | if (rc == 0 || rc != -ETXTBSY) | 1532 | if (rc == 0 || rc != -ETXTBSY) |
1438 | return rc; | 1533 | goto do_rename_exit; |
1439 | 1534 | ||
1440 | /* open-file renames don't work across directories */ | 1535 | /* open-file renames don't work across directories */ |
1441 | if (to_dentry->d_parent != from_dentry->d_parent) | 1536 | if (to_dentry->d_parent != from_dentry->d_parent) |
1442 | return rc; | 1537 | goto do_rename_exit; |
1443 | 1538 | ||
1444 | /* open the file to be renamed -- we need DELETE perms */ | 1539 | /* open the file to be renamed -- we need DELETE perms */ |
1445 | rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, | 1540 | rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, |
@@ -1455,7 +1550,8 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, | |||
1455 | 1550 | ||
1456 | CIFSSMBClose(xid, pTcon, srcfid); | 1551 | CIFSSMBClose(xid, pTcon, srcfid); |
1457 | } | 1552 | } |
1458 | 1553 | do_rename_exit: | |
1554 | cifs_put_tlink(tlink); | ||
1459 | return rc; | 1555 | return rc; |
1460 | } | 1556 | } |
1461 | 1557 | ||
@@ -1465,13 +1561,17 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
1465 | char *fromName = NULL; | 1561 | char *fromName = NULL; |
1466 | char *toName = NULL; | 1562 | char *toName = NULL; |
1467 | struct cifs_sb_info *cifs_sb; | 1563 | struct cifs_sb_info *cifs_sb; |
1468 | struct cifsTconInfo *tcon; | 1564 | struct tcon_link *tlink; |
1565 | struct cifs_tcon *tcon; | ||
1469 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; | 1566 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; |
1470 | FILE_UNIX_BASIC_INFO *info_buf_target; | 1567 | FILE_UNIX_BASIC_INFO *info_buf_target; |
1471 | int xid, rc, tmprc; | 1568 | int xid, rc, tmprc; |
1472 | 1569 | ||
1473 | cifs_sb = CIFS_SB(source_dir->i_sb); | 1570 | cifs_sb = CIFS_SB(source_dir->i_sb); |
1474 | tcon = cifs_sb->tcon; | 1571 | tlink = cifs_sb_tlink(cifs_sb); |
1572 | if (IS_ERR(tlink)) | ||
1573 | return PTR_ERR(tlink); | ||
1574 | tcon = tlink_tcon(tlink); | ||
1475 | 1575 | ||
1476 | xid = GetXid(); | 1576 | xid = GetXid(); |
1477 | 1577 | ||
@@ -1547,6 +1647,7 @@ cifs_rename_exit: | |||
1547 | kfree(fromName); | 1647 | kfree(fromName); |
1548 | kfree(toName); | 1648 | kfree(toName); |
1549 | FreeXid(xid); | 1649 | FreeXid(xid); |
1650 | cifs_put_tlink(tlink); | ||
1550 | return rc; | 1651 | return rc; |
1551 | } | 1652 | } |
1552 | 1653 | ||
@@ -1554,6 +1655,7 @@ static bool | |||
1554 | cifs_inode_needs_reval(struct inode *inode) | 1655 | cifs_inode_needs_reval(struct inode *inode) |
1555 | { | 1656 | { |
1556 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | 1657 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
1658 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1557 | 1659 | ||
1558 | if (cifs_i->clientCanCacheRead) | 1660 | if (cifs_i->clientCanCacheRead) |
1559 | return false; | 1661 | return false; |
@@ -1564,111 +1666,170 @@ cifs_inode_needs_reval(struct inode *inode) | |||
1564 | if (cifs_i->time == 0) | 1666 | if (cifs_i->time == 0) |
1565 | return true; | 1667 | return true; |
1566 | 1668 | ||
1567 | /* FIXME: the actimeo should be tunable */ | 1669 | if (!time_in_range(jiffies, cifs_i->time, |
1568 | if (time_after_eq(jiffies, cifs_i->time + HZ)) | 1670 | cifs_i->time + cifs_sb->actimeo)) |
1569 | return true; | 1671 | return true; |
1570 | 1672 | ||
1571 | /* hardlinked files w/ noserverino get "special" treatment */ | 1673 | /* hardlinked files w/ noserverino get "special" treatment */ |
1572 | if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && | 1674 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && |
1573 | S_ISREG(inode->i_mode) && inode->i_nlink != 1) | 1675 | S_ISREG(inode->i_mode) && inode->i_nlink != 1) |
1574 | return true; | 1676 | return true; |
1575 | 1677 | ||
1576 | return false; | 1678 | return false; |
1577 | } | 1679 | } |
1578 | 1680 | ||
1579 | /* check invalid_mapping flag and zap the cache if it's set */ | 1681 | /* |
1580 | static void | 1682 | * Zap the cache. Called when invalid_mapping flag is set. |
1683 | */ | ||
1684 | int | ||
1581 | cifs_invalidate_mapping(struct inode *inode) | 1685 | cifs_invalidate_mapping(struct inode *inode) |
1582 | { | 1686 | { |
1583 | int rc; | 1687 | int rc = 0; |
1584 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | 1688 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
1585 | 1689 | ||
1586 | cifs_i->invalid_mapping = false; | 1690 | cifs_i->invalid_mapping = false; |
1587 | 1691 | ||
1588 | /* write back any cached data */ | ||
1589 | if (inode->i_mapping && inode->i_mapping->nrpages != 0) { | 1692 | if (inode->i_mapping && inode->i_mapping->nrpages != 0) { |
1590 | rc = filemap_write_and_wait(inode->i_mapping); | 1693 | rc = invalidate_inode_pages2(inode->i_mapping); |
1591 | if (rc) | 1694 | if (rc) { |
1592 | cifs_i->write_behind_rc = rc; | 1695 | cERROR(1, "%s: could not invalidate inode %p", __func__, |
1696 | inode); | ||
1697 | cifs_i->invalid_mapping = true; | ||
1698 | } | ||
1593 | } | 1699 | } |
1594 | invalidate_remote_inode(inode); | 1700 | |
1595 | cifs_fscache_reset_inode_cookie(inode); | 1701 | cifs_fscache_reset_inode_cookie(inode); |
1702 | return rc; | ||
1596 | } | 1703 | } |
1597 | 1704 | ||
1598 | int cifs_revalidate_file(struct file *filp) | 1705 | int cifs_revalidate_file_attr(struct file *filp) |
1599 | { | 1706 | { |
1600 | int rc = 0; | 1707 | int rc = 0; |
1601 | struct inode *inode = filp->f_path.dentry->d_inode; | 1708 | struct inode *inode = filp->f_path.dentry->d_inode; |
1709 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | ||
1602 | 1710 | ||
1603 | if (!cifs_inode_needs_reval(inode)) | 1711 | if (!cifs_inode_needs_reval(inode)) |
1604 | goto check_inval; | 1712 | return rc; |
1605 | 1713 | ||
1606 | if (CIFS_SB(inode->i_sb)->tcon->unix_ext) | 1714 | if (tlink_tcon(cfile->tlink)->unix_ext) |
1607 | rc = cifs_get_file_info_unix(filp); | 1715 | rc = cifs_get_file_info_unix(filp); |
1608 | else | 1716 | else |
1609 | rc = cifs_get_file_info(filp); | 1717 | rc = cifs_get_file_info(filp); |
1610 | 1718 | ||
1611 | check_inval: | ||
1612 | if (CIFS_I(inode)->invalid_mapping) | ||
1613 | cifs_invalidate_mapping(inode); | ||
1614 | |||
1615 | return rc; | 1719 | return rc; |
1616 | } | 1720 | } |
1617 | 1721 | ||
1618 | /* revalidate a dentry's inode attributes */ | 1722 | int cifs_revalidate_dentry_attr(struct dentry *dentry) |
1619 | int cifs_revalidate_dentry(struct dentry *dentry) | ||
1620 | { | 1723 | { |
1621 | int xid; | 1724 | int xid; |
1622 | int rc = 0; | 1725 | int rc = 0; |
1623 | char *full_path = NULL; | ||
1624 | struct inode *inode = dentry->d_inode; | 1726 | struct inode *inode = dentry->d_inode; |
1625 | struct super_block *sb = dentry->d_sb; | 1727 | struct super_block *sb = dentry->d_sb; |
1728 | char *full_path = NULL; | ||
1626 | 1729 | ||
1627 | if (inode == NULL) | 1730 | if (inode == NULL) |
1628 | return -ENOENT; | 1731 | return -ENOENT; |
1629 | 1732 | ||
1630 | xid = GetXid(); | ||
1631 | |||
1632 | if (!cifs_inode_needs_reval(inode)) | 1733 | if (!cifs_inode_needs_reval(inode)) |
1633 | goto check_inval; | 1734 | return rc; |
1735 | |||
1736 | xid = GetXid(); | ||
1634 | 1737 | ||
1635 | /* can not safely grab the rename sem here if rename calls revalidate | 1738 | /* can not safely grab the rename sem here if rename calls revalidate |
1636 | since that would deadlock */ | 1739 | since that would deadlock */ |
1637 | full_path = build_path_from_dentry(dentry); | 1740 | full_path = build_path_from_dentry(dentry); |
1638 | if (full_path == NULL) { | 1741 | if (full_path == NULL) { |
1639 | rc = -ENOMEM; | 1742 | rc = -ENOMEM; |
1640 | goto check_inval; | 1743 | goto out; |
1641 | } | 1744 | } |
1642 | 1745 | ||
1643 | cFYI(1, "Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " | 1746 | cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time " |
1644 | "jiffies %ld", full_path, inode, inode->i_count.counter, | 1747 | "%ld jiffies %ld", full_path, inode, inode->i_count.counter, |
1645 | dentry, dentry->d_time, jiffies); | 1748 | dentry, dentry->d_time, jiffies); |
1646 | 1749 | ||
1647 | if (CIFS_SB(sb)->tcon->unix_ext) | 1750 | if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) |
1648 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); | 1751 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
1649 | else | 1752 | else |
1650 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, | 1753 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
1651 | xid, NULL); | 1754 | xid, NULL); |
1652 | 1755 | ||
1653 | check_inval: | 1756 | out: |
1654 | if (CIFS_I(inode)->invalid_mapping) | ||
1655 | cifs_invalidate_mapping(inode); | ||
1656 | |||
1657 | kfree(full_path); | 1757 | kfree(full_path); |
1658 | FreeXid(xid); | 1758 | FreeXid(xid); |
1659 | return rc; | 1759 | return rc; |
1660 | } | 1760 | } |
1661 | 1761 | ||
1762 | int cifs_revalidate_file(struct file *filp) | ||
1763 | { | ||
1764 | int rc; | ||
1765 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
1766 | |||
1767 | rc = cifs_revalidate_file_attr(filp); | ||
1768 | if (rc) | ||
1769 | return rc; | ||
1770 | |||
1771 | if (CIFS_I(inode)->invalid_mapping) | ||
1772 | rc = cifs_invalidate_mapping(inode); | ||
1773 | return rc; | ||
1774 | } | ||
1775 | |||
1776 | /* revalidate a dentry's inode attributes */ | ||
1777 | int cifs_revalidate_dentry(struct dentry *dentry) | ||
1778 | { | ||
1779 | int rc; | ||
1780 | struct inode *inode = dentry->d_inode; | ||
1781 | |||
1782 | rc = cifs_revalidate_dentry_attr(dentry); | ||
1783 | if (rc) | ||
1784 | return rc; | ||
1785 | |||
1786 | if (CIFS_I(inode)->invalid_mapping) | ||
1787 | rc = cifs_invalidate_mapping(inode); | ||
1788 | return rc; | ||
1789 | } | ||
1790 | |||
1662 | int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 1791 | int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
1663 | struct kstat *stat) | 1792 | struct kstat *stat) |
1664 | { | 1793 | { |
1665 | int err = cifs_revalidate_dentry(dentry); | 1794 | struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb); |
1666 | if (!err) { | 1795 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
1667 | generic_fillattr(dentry->d_inode, stat); | 1796 | struct inode *inode = dentry->d_inode; |
1668 | stat->blksize = CIFS_MAX_MSGSIZE; | 1797 | int rc; |
1669 | stat->ino = CIFS_I(dentry->d_inode)->uniqueid; | 1798 | |
1799 | /* | ||
1800 | * We need to be sure that all dirty pages are written and the server | ||
1801 | * has actual ctime, mtime and file length. | ||
1802 | */ | ||
1803 | if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping && | ||
1804 | inode->i_mapping->nrpages != 0) { | ||
1805 | rc = filemap_fdatawait(inode->i_mapping); | ||
1806 | if (rc) { | ||
1807 | mapping_set_error(inode->i_mapping, rc); | ||
1808 | return rc; | ||
1809 | } | ||
1810 | } | ||
1811 | |||
1812 | rc = cifs_revalidate_dentry_attr(dentry); | ||
1813 | if (rc) | ||
1814 | return rc; | ||
1815 | |||
1816 | generic_fillattr(inode, stat); | ||
1817 | stat->blksize = CIFS_MAX_MSGSIZE; | ||
1818 | stat->ino = CIFS_I(inode)->uniqueid; | ||
1819 | |||
1820 | /* | ||
1821 | * If on a multiuser mount without unix extensions, and the admin hasn't | ||
1822 | * overridden them, set the ownership to the fsuid/fsgid of the current | ||
1823 | * process. | ||
1824 | */ | ||
1825 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) && | ||
1826 | !tcon->unix_ext) { | ||
1827 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) | ||
1828 | stat->uid = current_fsuid(); | ||
1829 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) | ||
1830 | stat->gid = current_fsgid(); | ||
1670 | } | 1831 | } |
1671 | return err; | 1832 | return rc; |
1672 | } | 1833 | } |
1673 | 1834 | ||
1674 | static int cifs_truncate_page(struct address_space *mapping, loff_t from) | 1835 | static int cifs_truncate_page(struct address_space *mapping, loff_t from) |
@@ -1708,7 +1869,9 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1708 | struct cifsFileInfo *open_file; | 1869 | struct cifsFileInfo *open_file; |
1709 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 1870 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
1710 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1871 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1711 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 1872 | struct tcon_link *tlink = NULL; |
1873 | struct cifs_tcon *pTcon = NULL; | ||
1874 | struct cifs_io_parms io_parms; | ||
1712 | 1875 | ||
1713 | /* | 1876 | /* |
1714 | * To avoid spurious oplock breaks from server, in the case of | 1877 | * To avoid spurious oplock breaks from server, in the case of |
@@ -1719,24 +1882,38 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1719 | * writebehind data than the SMB timeout for the SetPathInfo | 1882 | * writebehind data than the SMB timeout for the SetPathInfo |
1720 | * request would allow | 1883 | * request would allow |
1721 | */ | 1884 | */ |
1722 | open_file = find_writable_file(cifsInode); | 1885 | open_file = find_writable_file(cifsInode, true); |
1723 | if (open_file) { | 1886 | if (open_file) { |
1724 | __u16 nfid = open_file->netfid; | 1887 | __u16 nfid = open_file->netfid; |
1725 | __u32 npid = open_file->pid; | 1888 | __u32 npid = open_file->pid; |
1889 | pTcon = tlink_tcon(open_file->tlink); | ||
1726 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, | 1890 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, |
1727 | npid, false); | 1891 | npid, false); |
1728 | cifsFileInfo_put(open_file); | 1892 | cifsFileInfo_put(open_file); |
1729 | cFYI(1, "SetFSize for attrs rc = %d", rc); | 1893 | cFYI(1, "SetFSize for attrs rc = %d", rc); |
1730 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 1894 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
1731 | unsigned int bytes_written; | 1895 | unsigned int bytes_written; |
1732 | rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, | 1896 | |
1733 | &bytes_written, NULL, NULL, 1); | 1897 | io_parms.netfid = nfid; |
1898 | io_parms.pid = npid; | ||
1899 | io_parms.tcon = pTcon; | ||
1900 | io_parms.offset = 0; | ||
1901 | io_parms.length = attrs->ia_size; | ||
1902 | rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, | ||
1903 | NULL, NULL, 1); | ||
1734 | cFYI(1, "Wrt seteof rc %d", rc); | 1904 | cFYI(1, "Wrt seteof rc %d", rc); |
1735 | } | 1905 | } |
1736 | } else | 1906 | } else |
1737 | rc = -EINVAL; | 1907 | rc = -EINVAL; |
1738 | 1908 | ||
1739 | if (rc != 0) { | 1909 | if (rc != 0) { |
1910 | if (pTcon == NULL) { | ||
1911 | tlink = cifs_sb_tlink(cifs_sb); | ||
1912 | if (IS_ERR(tlink)) | ||
1913 | return PTR_ERR(tlink); | ||
1914 | pTcon = tlink_tcon(tlink); | ||
1915 | } | ||
1916 | |||
1740 | /* Set file size by pathname rather than by handle | 1917 | /* Set file size by pathname rather than by handle |
1741 | either because no valid, writeable file handle for | 1918 | either because no valid, writeable file handle for |
1742 | it was found or because there was an error setting | 1919 | it was found or because there was an error setting |
@@ -1758,14 +1935,21 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1758 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1935 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1759 | if (rc == 0) { | 1936 | if (rc == 0) { |
1760 | unsigned int bytes_written; | 1937 | unsigned int bytes_written; |
1761 | rc = CIFSSMBWrite(xid, pTcon, netfid, 0, | 1938 | |
1762 | attrs->ia_size, | 1939 | io_parms.netfid = netfid; |
1763 | &bytes_written, NULL, | 1940 | io_parms.pid = current->tgid; |
1764 | NULL, 1); | 1941 | io_parms.tcon = pTcon; |
1942 | io_parms.offset = 0; | ||
1943 | io_parms.length = attrs->ia_size; | ||
1944 | rc = CIFSSMBWrite(xid, &io_parms, | ||
1945 | &bytes_written, | ||
1946 | NULL, NULL, 1); | ||
1765 | cFYI(1, "wrt seteof rc %d", rc); | 1947 | cFYI(1, "wrt seteof rc %d", rc); |
1766 | CIFSSMBClose(xid, pTcon, netfid); | 1948 | CIFSSMBClose(xid, pTcon, netfid); |
1767 | } | 1949 | } |
1768 | } | 1950 | } |
1951 | if (tlink) | ||
1952 | cifs_put_tlink(tlink); | ||
1769 | } | 1953 | } |
1770 | 1954 | ||
1771 | if (rc == 0) { | 1955 | if (rc == 0) { |
@@ -1786,7 +1970,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1786 | struct inode *inode = direntry->d_inode; | 1970 | struct inode *inode = direntry->d_inode; |
1787 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 1971 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
1788 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1972 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1789 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 1973 | struct tcon_link *tlink; |
1974 | struct cifs_tcon *pTcon; | ||
1790 | struct cifs_unix_set_info_args *args = NULL; | 1975 | struct cifs_unix_set_info_args *args = NULL; |
1791 | struct cifsFileInfo *open_file; | 1976 | struct cifsFileInfo *open_file; |
1792 | 1977 | ||
@@ -1820,10 +2005,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1820 | * the flush returns error? | 2005 | * the flush returns error? |
1821 | */ | 2006 | */ |
1822 | rc = filemap_write_and_wait(inode->i_mapping); | 2007 | rc = filemap_write_and_wait(inode->i_mapping); |
1823 | if (rc != 0) { | 2008 | mapping_set_error(inode->i_mapping, rc); |
1824 | cifsInode->write_behind_rc = rc; | 2009 | rc = 0; |
1825 | rc = 0; | ||
1826 | } | ||
1827 | 2010 | ||
1828 | if (attrs->ia_valid & ATTR_SIZE) { | 2011 | if (attrs->ia_valid & ATTR_SIZE) { |
1829 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | 2012 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
@@ -1873,17 +2056,25 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1873 | args->ctime = NO_CHANGE_64; | 2056 | args->ctime = NO_CHANGE_64; |
1874 | 2057 | ||
1875 | args->device = 0; | 2058 | args->device = 0; |
1876 | open_file = find_writable_file(cifsInode); | 2059 | open_file = find_writable_file(cifsInode, true); |
1877 | if (open_file) { | 2060 | if (open_file) { |
1878 | u16 nfid = open_file->netfid; | 2061 | u16 nfid = open_file->netfid; |
1879 | u32 npid = open_file->pid; | 2062 | u32 npid = open_file->pid; |
2063 | pTcon = tlink_tcon(open_file->tlink); | ||
1880 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | 2064 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); |
1881 | cifsFileInfo_put(open_file); | 2065 | cifsFileInfo_put(open_file); |
1882 | } else { | 2066 | } else { |
2067 | tlink = cifs_sb_tlink(cifs_sb); | ||
2068 | if (IS_ERR(tlink)) { | ||
2069 | rc = PTR_ERR(tlink); | ||
2070 | goto out; | ||
2071 | } | ||
2072 | pTcon = tlink_tcon(tlink); | ||
1883 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 2073 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
1884 | cifs_sb->local_nls, | 2074 | cifs_sb->local_nls, |
1885 | cifs_sb->mnt_cifs_flags & | 2075 | cifs_sb->mnt_cifs_flags & |
1886 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 2076 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
2077 | cifs_put_tlink(tlink); | ||
1887 | } | 2078 | } |
1888 | 2079 | ||
1889 | if (rc) | 2080 | if (rc) |
@@ -1956,10 +2147,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1956 | * the flush returns error? | 2147 | * the flush returns error? |
1957 | */ | 2148 | */ |
1958 | rc = filemap_write_and_wait(inode->i_mapping); | 2149 | rc = filemap_write_and_wait(inode->i_mapping); |
1959 | if (rc != 0) { | 2150 | mapping_set_error(inode->i_mapping, rc); |
1960 | cifsInode->write_behind_rc = rc; | 2151 | rc = 0; |
1961 | rc = 0; | ||
1962 | } | ||
1963 | 2152 | ||
1964 | if (attrs->ia_valid & ATTR_SIZE) { | 2153 | if (attrs->ia_valid & ATTR_SIZE) { |
1965 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | 2154 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
@@ -1988,11 +2177,16 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1988 | 2177 | ||
1989 | if (attrs->ia_valid & ATTR_MODE) { | 2178 | if (attrs->ia_valid & ATTR_MODE) { |
1990 | rc = 0; | 2179 | rc = 0; |
1991 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 2180 | #ifdef CONFIG_CIFS_ACL |
1992 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 2181 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
1993 | rc = mode_to_acl(inode, full_path, mode); | 2182 | rc = mode_to_cifs_acl(inode, full_path, mode); |
1994 | else | 2183 | if (rc) { |
1995 | #endif | 2184 | cFYI(1, "%s: Setting ACL failed with error: %d", |
2185 | __func__, rc); | ||
2186 | goto cifs_setattr_exit; | ||
2187 | } | ||
2188 | } else | ||
2189 | #endif /* CONFIG_CIFS_ACL */ | ||
1996 | if (((mode & S_IWUGO) == 0) && | 2190 | if (((mode & S_IWUGO) == 0) && |
1997 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { | 2191 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
1998 | 2192 | ||
@@ -2051,7 +2245,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
2051 | 2245 | ||
2052 | setattr_copy(inode, attrs); | 2246 | setattr_copy(inode, attrs); |
2053 | mark_inode_dirty(inode); | 2247 | mark_inode_dirty(inode); |
2054 | return 0; | ||
2055 | 2248 | ||
2056 | cifs_setattr_exit: | 2249 | cifs_setattr_exit: |
2057 | kfree(full_path); | 2250 | kfree(full_path); |
@@ -2064,7 +2257,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
2064 | { | 2257 | { |
2065 | struct inode *inode = direntry->d_inode; | 2258 | struct inode *inode = direntry->d_inode; |
2066 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 2259 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
2067 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 2260 | struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); |
2068 | 2261 | ||
2069 | if (pTcon->unix_ext) | 2262 | if (pTcon->unix_ext) |
2070 | return cifs_setattr_unix(direntry, attrs); | 2263 | return cifs_setattr_unix(direntry, attrs); |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 9d38a71c8e14..4221b5e48a42 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
@@ -37,11 +37,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
37 | int xid; | 37 | int xid; |
38 | struct cifs_sb_info *cifs_sb; | 38 | struct cifs_sb_info *cifs_sb; |
39 | #ifdef CONFIG_CIFS_POSIX | 39 | #ifdef CONFIG_CIFS_POSIX |
40 | struct cifsFileInfo *pSMBFile = filep->private_data; | ||
41 | struct cifs_tcon *tcon; | ||
40 | __u64 ExtAttrBits = 0; | 42 | __u64 ExtAttrBits = 0; |
41 | __u64 ExtAttrMask = 0; | 43 | __u64 ExtAttrMask = 0; |
42 | __u64 caps; | 44 | __u64 caps; |
43 | struct cifsTconInfo *tcon; | ||
44 | struct cifsFileInfo *pSMBFile = filep->private_data; | ||
45 | #endif /* CONFIG_CIFS_POSIX */ | 45 | #endif /* CONFIG_CIFS_POSIX */ |
46 | 46 | ||
47 | xid = GetXid(); | 47 | xid = GetXid(); |
@@ -50,17 +50,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
50 | 50 | ||
51 | cifs_sb = CIFS_SB(inode->i_sb); | 51 | cifs_sb = CIFS_SB(inode->i_sb); |
52 | 52 | ||
53 | #ifdef CONFIG_CIFS_POSIX | ||
54 | tcon = cifs_sb->tcon; | ||
55 | if (tcon) | ||
56 | caps = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
57 | else { | ||
58 | rc = -EIO; | ||
59 | FreeXid(xid); | ||
60 | return -EIO; | ||
61 | } | ||
62 | #endif /* CONFIG_CIFS_POSIX */ | ||
63 | |||
64 | switch (command) { | 53 | switch (command) { |
65 | case CIFS_IOC_CHECKUMOUNT: | 54 | case CIFS_IOC_CHECKUMOUNT: |
66 | cFYI(1, "User unmount attempted"); | 55 | cFYI(1, "User unmount attempted"); |
@@ -73,9 +62,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
73 | break; | 62 | break; |
74 | #ifdef CONFIG_CIFS_POSIX | 63 | #ifdef CONFIG_CIFS_POSIX |
75 | case FS_IOC_GETFLAGS: | 64 | case FS_IOC_GETFLAGS: |
65 | if (pSMBFile == NULL) | ||
66 | break; | ||
67 | tcon = tlink_tcon(pSMBFile->tlink); | ||
68 | caps = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
76 | if (CIFS_UNIX_EXTATTR_CAP & caps) { | 69 | if (CIFS_UNIX_EXTATTR_CAP & caps) { |
77 | if (pSMBFile == NULL) | ||
78 | break; | ||
79 | rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, | 70 | rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, |
80 | &ExtAttrBits, &ExtAttrMask); | 71 | &ExtAttrBits, &ExtAttrMask); |
81 | if (rc == 0) | 72 | if (rc == 0) |
@@ -86,13 +77,15 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
86 | break; | 77 | break; |
87 | 78 | ||
88 | case FS_IOC_SETFLAGS: | 79 | case FS_IOC_SETFLAGS: |
80 | if (pSMBFile == NULL) | ||
81 | break; | ||
82 | tcon = tlink_tcon(pSMBFile->tlink); | ||
83 | caps = le64_to_cpu(tcon->fsUnixInfo.Capability); | ||
89 | if (CIFS_UNIX_EXTATTR_CAP & caps) { | 84 | if (CIFS_UNIX_EXTATTR_CAP & caps) { |
90 | if (get_user(ExtAttrBits, (int __user *)arg)) { | 85 | if (get_user(ExtAttrBits, (int __user *)arg)) { |
91 | rc = -EFAULT; | 86 | rc = -EFAULT; |
92 | break; | 87 | break; |
93 | } | 88 | } |
94 | if (pSMBFile == NULL) | ||
95 | break; | ||
96 | /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, | 89 | /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, |
97 | extAttrBits, &ExtAttrMask);*/ | 90 | extAttrBits, &ExtAttrMask);*/ |
98 | } | 91 | } |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 473ca8033656..556b1a0b54de 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -29,6 +29,347 @@ | |||
29 | #include "cifs_debug.h" | 29 | #include "cifs_debug.h" |
30 | #include "cifs_fs_sb.h" | 30 | #include "cifs_fs_sb.h" |
31 | 31 | ||
32 | #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) | ||
33 | #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) | ||
34 | #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) | ||
35 | #define CIFS_MF_SYMLINK_LINK_MAXLEN (1024) | ||
36 | #define CIFS_MF_SYMLINK_FILE_SIZE \ | ||
37 | (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) | ||
38 | |||
39 | #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" | ||
40 | #define CIFS_MF_SYMLINK_MD5_FORMAT \ | ||
41 | "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" | ||
42 | #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \ | ||
43 | md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \ | ||
44 | md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \ | ||
45 | md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\ | ||
46 | md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15] | ||
47 | |||
48 | static int | ||
49 | symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) | ||
50 | { | ||
51 | int rc; | ||
52 | unsigned int size; | ||
53 | struct crypto_shash *md5; | ||
54 | struct sdesc *sdescmd5; | ||
55 | |||
56 | md5 = crypto_alloc_shash("md5", 0, 0); | ||
57 | if (IS_ERR(md5)) { | ||
58 | rc = PTR_ERR(md5); | ||
59 | cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc); | ||
60 | return rc; | ||
61 | } | ||
62 | size = sizeof(struct shash_desc) + crypto_shash_descsize(md5); | ||
63 | sdescmd5 = kmalloc(size, GFP_KERNEL); | ||
64 | if (!sdescmd5) { | ||
65 | rc = -ENOMEM; | ||
66 | cERROR(1, "%s: Memory allocation failure\n", __func__); | ||
67 | goto symlink_hash_err; | ||
68 | } | ||
69 | sdescmd5->shash.tfm = md5; | ||
70 | sdescmd5->shash.flags = 0x0; | ||
71 | |||
72 | rc = crypto_shash_init(&sdescmd5->shash); | ||
73 | if (rc) { | ||
74 | cERROR(1, "%s: Could not init md5 shash\n", __func__); | ||
75 | goto symlink_hash_err; | ||
76 | } | ||
77 | crypto_shash_update(&sdescmd5->shash, link_str, link_len); | ||
78 | rc = crypto_shash_final(&sdescmd5->shash, md5_hash); | ||
79 | |||
80 | symlink_hash_err: | ||
81 | crypto_free_shash(md5); | ||
82 | kfree(sdescmd5); | ||
83 | |||
84 | return rc; | ||
85 | } | ||
86 | |||
87 | static int | ||
88 | CIFSParseMFSymlink(const u8 *buf, | ||
89 | unsigned int buf_len, | ||
90 | unsigned int *_link_len, | ||
91 | char **_link_str) | ||
92 | { | ||
93 | int rc; | ||
94 | unsigned int link_len; | ||
95 | const char *md5_str1; | ||
96 | const char *link_str; | ||
97 | u8 md5_hash[16]; | ||
98 | char md5_str2[34]; | ||
99 | |||
100 | if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) | ||
101 | return -EINVAL; | ||
102 | |||
103 | md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET]; | ||
104 | link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET]; | ||
105 | |||
106 | rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len); | ||
107 | if (rc != 1) | ||
108 | return -EINVAL; | ||
109 | |||
110 | rc = symlink_hash(link_len, link_str, md5_hash); | ||
111 | if (rc) { | ||
112 | cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc); | ||
113 | return rc; | ||
114 | } | ||
115 | |||
116 | snprintf(md5_str2, sizeof(md5_str2), | ||
117 | CIFS_MF_SYMLINK_MD5_FORMAT, | ||
118 | CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); | ||
119 | |||
120 | if (strncmp(md5_str1, md5_str2, 17) != 0) | ||
121 | return -EINVAL; | ||
122 | |||
123 | if (_link_str) { | ||
124 | *_link_str = kstrndup(link_str, link_len, GFP_KERNEL); | ||
125 | if (!*_link_str) | ||
126 | return -ENOMEM; | ||
127 | } | ||
128 | |||
129 | *_link_len = link_len; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int | ||
134 | CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str) | ||
135 | { | ||
136 | int rc; | ||
137 | unsigned int link_len; | ||
138 | unsigned int ofs; | ||
139 | u8 md5_hash[16]; | ||
140 | |||
141 | if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE) | ||
142 | return -EINVAL; | ||
143 | |||
144 | link_len = strlen(link_str); | ||
145 | |||
146 | if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN) | ||
147 | return -ENAMETOOLONG; | ||
148 | |||
149 | rc = symlink_hash(link_len, link_str, md5_hash); | ||
150 | if (rc) { | ||
151 | cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc); | ||
152 | return rc; | ||
153 | } | ||
154 | |||
155 | snprintf(buf, buf_len, | ||
156 | CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, | ||
157 | link_len, | ||
158 | CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); | ||
159 | |||
160 | ofs = CIFS_MF_SYMLINK_LINK_OFFSET; | ||
161 | memcpy(buf + ofs, link_str, link_len); | ||
162 | |||
163 | ofs += link_len; | ||
164 | if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { | ||
165 | buf[ofs] = '\n'; | ||
166 | ofs++; | ||
167 | } | ||
168 | |||
169 | while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) { | ||
170 | buf[ofs] = ' '; | ||
171 | ofs++; | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int | ||
178 | CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon, | ||
179 | const char *fromName, const char *toName, | ||
180 | const struct nls_table *nls_codepage, int remap) | ||
181 | { | ||
182 | int rc; | ||
183 | int oplock = 0; | ||
184 | __u16 netfid = 0; | ||
185 | u8 *buf; | ||
186 | unsigned int bytes_written = 0; | ||
187 | struct cifs_io_parms io_parms; | ||
188 | |||
189 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
190 | if (!buf) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName); | ||
194 | if (rc != 0) { | ||
195 | kfree(buf); | ||
196 | return rc; | ||
197 | } | ||
198 | |||
199 | rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE, | ||
200 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
201 | nls_codepage, remap); | ||
202 | if (rc != 0) { | ||
203 | kfree(buf); | ||
204 | return rc; | ||
205 | } | ||
206 | |||
207 | io_parms.netfid = netfid; | ||
208 | io_parms.pid = current->tgid; | ||
209 | io_parms.tcon = tcon; | ||
210 | io_parms.offset = 0; | ||
211 | io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; | ||
212 | |||
213 | rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0); | ||
214 | CIFSSMBClose(xid, tcon, netfid); | ||
215 | kfree(buf); | ||
216 | if (rc != 0) | ||
217 | return rc; | ||
218 | |||
219 | if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE) | ||
220 | return -EIO; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | CIFSQueryMFSymLink(const int xid, struct cifs_tcon *tcon, | ||
227 | const unsigned char *searchName, char **symlinkinfo, | ||
228 | const struct nls_table *nls_codepage, int remap) | ||
229 | { | ||
230 | int rc; | ||
231 | int oplock = 0; | ||
232 | __u16 netfid = 0; | ||
233 | u8 *buf; | ||
234 | char *pbuf; | ||
235 | unsigned int bytes_read = 0; | ||
236 | int buf_type = CIFS_NO_BUFFER; | ||
237 | unsigned int link_len = 0; | ||
238 | struct cifs_io_parms io_parms; | ||
239 | FILE_ALL_INFO file_info; | ||
240 | |||
241 | rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ, | ||
242 | CREATE_NOT_DIR, &netfid, &oplock, &file_info, | ||
243 | nls_codepage, remap); | ||
244 | if (rc != 0) | ||
245 | return rc; | ||
246 | |||
247 | if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { | ||
248 | CIFSSMBClose(xid, tcon, netfid); | ||
249 | /* it's not a symlink */ | ||
250 | return -EINVAL; | ||
251 | } | ||
252 | |||
253 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
254 | if (!buf) | ||
255 | return -ENOMEM; | ||
256 | pbuf = buf; | ||
257 | io_parms.netfid = netfid; | ||
258 | io_parms.pid = current->tgid; | ||
259 | io_parms.tcon = tcon; | ||
260 | io_parms.offset = 0; | ||
261 | io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; | ||
262 | |||
263 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); | ||
264 | CIFSSMBClose(xid, tcon, netfid); | ||
265 | if (rc != 0) { | ||
266 | kfree(buf); | ||
267 | return rc; | ||
268 | } | ||
269 | |||
270 | rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo); | ||
271 | kfree(buf); | ||
272 | if (rc != 0) | ||
273 | return rc; | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | bool | ||
279 | CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) | ||
280 | { | ||
281 | if (!(fattr->cf_mode & S_IFREG)) | ||
282 | /* it's not a symlink */ | ||
283 | return false; | ||
284 | |||
285 | if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) | ||
286 | /* it's not a symlink */ | ||
287 | return false; | ||
288 | |||
289 | return true; | ||
290 | } | ||
291 | |||
292 | int | ||
293 | CIFSCheckMFSymlink(struct cifs_fattr *fattr, | ||
294 | const unsigned char *path, | ||
295 | struct cifs_sb_info *cifs_sb, int xid) | ||
296 | { | ||
297 | int rc; | ||
298 | int oplock = 0; | ||
299 | __u16 netfid = 0; | ||
300 | struct tcon_link *tlink; | ||
301 | struct cifs_tcon *pTcon; | ||
302 | struct cifs_io_parms io_parms; | ||
303 | u8 *buf; | ||
304 | char *pbuf; | ||
305 | unsigned int bytes_read = 0; | ||
306 | int buf_type = CIFS_NO_BUFFER; | ||
307 | unsigned int link_len = 0; | ||
308 | FILE_ALL_INFO file_info; | ||
309 | |||
310 | if (!CIFSCouldBeMFSymlink(fattr)) | ||
311 | /* it's not a symlink */ | ||
312 | return 0; | ||
313 | |||
314 | tlink = cifs_sb_tlink(cifs_sb); | ||
315 | if (IS_ERR(tlink)) | ||
316 | return PTR_ERR(tlink); | ||
317 | pTcon = tlink_tcon(tlink); | ||
318 | |||
319 | rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, | ||
320 | CREATE_NOT_DIR, &netfid, &oplock, &file_info, | ||
321 | cifs_sb->local_nls, | ||
322 | cifs_sb->mnt_cifs_flags & | ||
323 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
324 | if (rc != 0) | ||
325 | goto out; | ||
326 | |||
327 | if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { | ||
328 | CIFSSMBClose(xid, pTcon, netfid); | ||
329 | /* it's not a symlink */ | ||
330 | goto out; | ||
331 | } | ||
332 | |||
333 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
334 | if (!buf) { | ||
335 | rc = -ENOMEM; | ||
336 | goto out; | ||
337 | } | ||
338 | pbuf = buf; | ||
339 | io_parms.netfid = netfid; | ||
340 | io_parms.pid = current->tgid; | ||
341 | io_parms.tcon = pTcon; | ||
342 | io_parms.offset = 0; | ||
343 | io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; | ||
344 | |||
345 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); | ||
346 | CIFSSMBClose(xid, pTcon, netfid); | ||
347 | if (rc != 0) { | ||
348 | kfree(buf); | ||
349 | goto out; | ||
350 | } | ||
351 | |||
352 | rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); | ||
353 | kfree(buf); | ||
354 | if (rc == -EINVAL) { | ||
355 | /* it's not a symlink */ | ||
356 | rc = 0; | ||
357 | goto out; | ||
358 | } | ||
359 | |||
360 | if (rc != 0) | ||
361 | goto out; | ||
362 | |||
363 | /* it is a symlink */ | ||
364 | fattr->cf_eof = link_len; | ||
365 | fattr->cf_mode &= ~S_IFMT; | ||
366 | fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | ||
367 | fattr->cf_dtype = DT_LNK; | ||
368 | out: | ||
369 | cifs_put_tlink(tlink); | ||
370 | return rc; | ||
371 | } | ||
372 | |||
32 | int | 373 | int |
33 | cifs_hardlink(struct dentry *old_file, struct inode *inode, | 374 | cifs_hardlink(struct dentry *old_file, struct inode *inode, |
34 | struct dentry *direntry) | 375 | struct dentry *direntry) |
@@ -37,17 +378,17 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, | |||
37 | int xid; | 378 | int xid; |
38 | char *fromName = NULL; | 379 | char *fromName = NULL; |
39 | char *toName = NULL; | 380 | char *toName = NULL; |
40 | struct cifs_sb_info *cifs_sb_target; | 381 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
41 | struct cifsTconInfo *pTcon; | 382 | struct tcon_link *tlink; |
383 | struct cifs_tcon *pTcon; | ||
42 | struct cifsInodeInfo *cifsInode; | 384 | struct cifsInodeInfo *cifsInode; |
43 | 385 | ||
44 | xid = GetXid(); | 386 | tlink = cifs_sb_tlink(cifs_sb); |
45 | 387 | if (IS_ERR(tlink)) | |
46 | cifs_sb_target = CIFS_SB(inode->i_sb); | 388 | return PTR_ERR(tlink); |
47 | pTcon = cifs_sb_target->tcon; | 389 | pTcon = tlink_tcon(tlink); |
48 | 390 | ||
49 | /* No need to check for cross device links since server will do that | 391 | xid = GetXid(); |
50 | BB note DFS case in future though (when we may have to check) */ | ||
51 | 392 | ||
52 | fromName = build_path_from_dentry(old_file); | 393 | fromName = build_path_from_dentry(old_file); |
53 | toName = build_path_from_dentry(direntry); | 394 | toName = build_path_from_dentry(direntry); |
@@ -56,16 +397,15 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, | |||
56 | goto cifs_hl_exit; | 397 | goto cifs_hl_exit; |
57 | } | 398 | } |
58 | 399 | ||
59 | /* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/ | ||
60 | if (pTcon->unix_ext) | 400 | if (pTcon->unix_ext) |
61 | rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, | 401 | rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, |
62 | cifs_sb_target->local_nls, | 402 | cifs_sb->local_nls, |
63 | cifs_sb_target->mnt_cifs_flags & | 403 | cifs_sb->mnt_cifs_flags & |
64 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 404 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
65 | else { | 405 | else { |
66 | rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, | 406 | rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, |
67 | cifs_sb_target->local_nls, | 407 | cifs_sb->local_nls, |
68 | cifs_sb_target->mnt_cifs_flags & | 408 | cifs_sb->mnt_cifs_flags & |
69 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 409 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
70 | if ((rc == -EIO) || (rc == -EINVAL)) | 410 | if ((rc == -EIO) || (rc == -EINVAL)) |
71 | rc = -EOPNOTSUPP; | 411 | rc = -EOPNOTSUPP; |
@@ -101,6 +441,7 @@ cifs_hl_exit: | |||
101 | kfree(fromName); | 441 | kfree(fromName); |
102 | kfree(toName); | 442 | kfree(toName); |
103 | FreeXid(xid); | 443 | FreeXid(xid); |
444 | cifs_put_tlink(tlink); | ||
104 | return rc; | 445 | return rc; |
105 | } | 446 | } |
106 | 447 | ||
@@ -113,10 +454,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
113 | char *full_path = NULL; | 454 | char *full_path = NULL; |
114 | char *target_path = NULL; | 455 | char *target_path = NULL; |
115 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 456 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
116 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 457 | struct tcon_link *tlink = NULL; |
458 | struct cifs_tcon *tcon; | ||
117 | 459 | ||
118 | xid = GetXid(); | 460 | xid = GetXid(); |
119 | 461 | ||
462 | tlink = cifs_sb_tlink(cifs_sb); | ||
463 | if (IS_ERR(tlink)) { | ||
464 | rc = PTR_ERR(tlink); | ||
465 | tlink = NULL; | ||
466 | goto out; | ||
467 | } | ||
468 | tcon = tlink_tcon(tlink); | ||
469 | |||
120 | /* | 470 | /* |
121 | * For now, we just handle symlinks with unix extensions enabled. | 471 | * For now, we just handle symlinks with unix extensions enabled. |
122 | * Eventually we should handle NTFS reparse points, and MacOS | 472 | * Eventually we should handle NTFS reparse points, and MacOS |
@@ -130,7 +480,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
130 | * but there doesn't seem to be any harm in allowing the client to | 480 | * but there doesn't seem to be any harm in allowing the client to |
131 | * read them. | 481 | * read them. |
132 | */ | 482 | */ |
133 | if (!(tcon->ses->capabilities & CAP_UNIX)) { | 483 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) |
484 | && !(tcon->ses->capabilities & CAP_UNIX)) { | ||
134 | rc = -EACCES; | 485 | rc = -EACCES; |
135 | goto out; | 486 | goto out; |
136 | } | 487 | } |
@@ -141,8 +492,21 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
141 | 492 | ||
142 | cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); | 493 | cFYI(1, "Full path: %s inode = 0x%p", full_path, inode); |
143 | 494 | ||
144 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, | 495 | rc = -EACCES; |
145 | cifs_sb->local_nls); | 496 | /* |
497 | * First try Minshall+French Symlinks, if configured | ||
498 | * and fallback to UNIX Extensions Symlinks. | ||
499 | */ | ||
500 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) | ||
501 | rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path, | ||
502 | cifs_sb->local_nls, | ||
503 | cifs_sb->mnt_cifs_flags & | ||
504 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
505 | |||
506 | if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX)) | ||
507 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path, | ||
508 | cifs_sb->local_nls); | ||
509 | |||
146 | kfree(full_path); | 510 | kfree(full_path); |
147 | out: | 511 | out: |
148 | if (rc != 0) { | 512 | if (rc != 0) { |
@@ -151,6 +515,8 @@ out: | |||
151 | } | 515 | } |
152 | 516 | ||
153 | FreeXid(xid); | 517 | FreeXid(xid); |
518 | if (tlink) | ||
519 | cifs_put_tlink(tlink); | ||
154 | nd_set_link(nd, target_path); | 520 | nd_set_link(nd, target_path); |
155 | return NULL; | 521 | return NULL; |
156 | } | 522 | } |
@@ -160,29 +526,37 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
160 | { | 526 | { |
161 | int rc = -EOPNOTSUPP; | 527 | int rc = -EOPNOTSUPP; |
162 | int xid; | 528 | int xid; |
163 | struct cifs_sb_info *cifs_sb; | 529 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
164 | struct cifsTconInfo *pTcon; | 530 | struct tcon_link *tlink; |
531 | struct cifs_tcon *pTcon; | ||
165 | char *full_path = NULL; | 532 | char *full_path = NULL; |
166 | struct inode *newinode = NULL; | 533 | struct inode *newinode = NULL; |
167 | 534 | ||
168 | xid = GetXid(); | 535 | xid = GetXid(); |
169 | 536 | ||
170 | cifs_sb = CIFS_SB(inode->i_sb); | 537 | tlink = cifs_sb_tlink(cifs_sb); |
171 | pTcon = cifs_sb->tcon; | 538 | if (IS_ERR(tlink)) { |
539 | rc = PTR_ERR(tlink); | ||
540 | goto symlink_exit; | ||
541 | } | ||
542 | pTcon = tlink_tcon(tlink); | ||
172 | 543 | ||
173 | full_path = build_path_from_dentry(direntry); | 544 | full_path = build_path_from_dentry(direntry); |
174 | |||
175 | if (full_path == NULL) { | 545 | if (full_path == NULL) { |
176 | rc = -ENOMEM; | 546 | rc = -ENOMEM; |
177 | FreeXid(xid); | 547 | goto symlink_exit; |
178 | return rc; | ||
179 | } | 548 | } |
180 | 549 | ||
181 | cFYI(1, "Full path: %s", full_path); | 550 | cFYI(1, "Full path: %s", full_path); |
182 | cFYI(1, "symname is %s", symname); | 551 | cFYI(1, "symname is %s", symname); |
183 | 552 | ||
184 | /* BB what if DFS and this volume is on different share? BB */ | 553 | /* BB what if DFS and this volume is on different share? BB */ |
185 | if (pTcon->unix_ext) | 554 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) |
555 | rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname, | ||
556 | cifs_sb->local_nls, | ||
557 | cifs_sb->mnt_cifs_flags & | ||
558 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
559 | else if (pTcon->unix_ext) | ||
186 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, | 560 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, |
187 | cifs_sb->local_nls); | 561 | cifs_sb->local_nls); |
188 | /* else | 562 | /* else |
@@ -201,15 +575,12 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
201 | cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d", | 575 | cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d", |
202 | rc); | 576 | rc); |
203 | } else { | 577 | } else { |
204 | if (pTcon->nocase) | ||
205 | direntry->d_op = &cifs_ci_dentry_ops; | ||
206 | else | ||
207 | direntry->d_op = &cifs_dentry_ops; | ||
208 | d_instantiate(direntry, newinode); | 578 | d_instantiate(direntry, newinode); |
209 | } | 579 | } |
210 | } | 580 | } |
211 | 581 | symlink_exit: | |
212 | kfree(full_path); | 582 | kfree(full_path); |
583 | cifs_put_tlink(tlink); | ||
213 | FreeXid(xid); | 584 | FreeXid(xid); |
214 | return rc; | 585 | return rc; |
215 | } | 586 | } |
diff --git a/fs/cifs/md4.c b/fs/cifs/md4.c deleted file mode 100644 index a725c2609d67..000000000000 --- a/fs/cifs/md4.c +++ /dev/null | |||
@@ -1,205 +0,0 @@ | |||
1 | /* | ||
2 | Unix SMB/Netbios implementation. | ||
3 | Version 1.9. | ||
4 | a implementation of MD4 designed for use in the SMB authentication protocol | ||
5 | Copyright (C) Andrew Tridgell 1997-1998. | ||
6 | Modified by Steve French (sfrench@us.ibm.com) 2002-2003 | ||
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., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include "cifsencrypt.h" | ||
25 | |||
26 | /* NOTE: This code makes no attempt to be fast! */ | ||
27 | |||
28 | static __u32 | ||
29 | F(__u32 X, __u32 Y, __u32 Z) | ||
30 | { | ||
31 | return (X & Y) | ((~X) & Z); | ||
32 | } | ||
33 | |||
34 | static __u32 | ||
35 | G(__u32 X, __u32 Y, __u32 Z) | ||
36 | { | ||
37 | return (X & Y) | (X & Z) | (Y & Z); | ||
38 | } | ||
39 | |||
40 | static __u32 | ||
41 | H(__u32 X, __u32 Y, __u32 Z) | ||
42 | { | ||
43 | return X ^ Y ^ Z; | ||
44 | } | ||
45 | |||
46 | static __u32 | ||
47 | lshift(__u32 x, int s) | ||
48 | { | ||
49 | x &= 0xFFFFFFFF; | ||
50 | return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); | ||
51 | } | ||
52 | |||
53 | #define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) | ||
54 | #define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) | ||
55 | #define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) | ||
56 | |||
57 | /* this applies md4 to 64 byte chunks */ | ||
58 | static void | ||
59 | mdfour64(__u32 *M, __u32 *A, __u32 *B, __u32 *C, __u32 *D) | ||
60 | { | ||
61 | int j; | ||
62 | __u32 AA, BB, CC, DD; | ||
63 | __u32 X[16]; | ||
64 | |||
65 | |||
66 | for (j = 0; j < 16; j++) | ||
67 | X[j] = M[j]; | ||
68 | |||
69 | AA = *A; | ||
70 | BB = *B; | ||
71 | CC = *C; | ||
72 | DD = *D; | ||
73 | |||
74 | ROUND1(A, B, C, D, 0, 3); | ||
75 | ROUND1(D, A, B, C, 1, 7); | ||
76 | ROUND1(C, D, A, B, 2, 11); | ||
77 | ROUND1(B, C, D, A, 3, 19); | ||
78 | ROUND1(A, B, C, D, 4, 3); | ||
79 | ROUND1(D, A, B, C, 5, 7); | ||
80 | ROUND1(C, D, A, B, 6, 11); | ||
81 | ROUND1(B, C, D, A, 7, 19); | ||
82 | ROUND1(A, B, C, D, 8, 3); | ||
83 | ROUND1(D, A, B, C, 9, 7); | ||
84 | ROUND1(C, D, A, B, 10, 11); | ||
85 | ROUND1(B, C, D, A, 11, 19); | ||
86 | ROUND1(A, B, C, D, 12, 3); | ||
87 | ROUND1(D, A, B, C, 13, 7); | ||
88 | ROUND1(C, D, A, B, 14, 11); | ||
89 | ROUND1(B, C, D, A, 15, 19); | ||
90 | |||
91 | ROUND2(A, B, C, D, 0, 3); | ||
92 | ROUND2(D, A, B, C, 4, 5); | ||
93 | ROUND2(C, D, A, B, 8, 9); | ||
94 | ROUND2(B, C, D, A, 12, 13); | ||
95 | ROUND2(A, B, C, D, 1, 3); | ||
96 | ROUND2(D, A, B, C, 5, 5); | ||
97 | ROUND2(C, D, A, B, 9, 9); | ||
98 | ROUND2(B, C, D, A, 13, 13); | ||
99 | ROUND2(A, B, C, D, 2, 3); | ||
100 | ROUND2(D, A, B, C, 6, 5); | ||
101 | ROUND2(C, D, A, B, 10, 9); | ||
102 | ROUND2(B, C, D, A, 14, 13); | ||
103 | ROUND2(A, B, C, D, 3, 3); | ||
104 | ROUND2(D, A, B, C, 7, 5); | ||
105 | ROUND2(C, D, A, B, 11, 9); | ||
106 | ROUND2(B, C, D, A, 15, 13); | ||
107 | |||
108 | ROUND3(A, B, C, D, 0, 3); | ||
109 | ROUND3(D, A, B, C, 8, 9); | ||
110 | ROUND3(C, D, A, B, 4, 11); | ||
111 | ROUND3(B, C, D, A, 12, 15); | ||
112 | ROUND3(A, B, C, D, 2, 3); | ||
113 | ROUND3(D, A, B, C, 10, 9); | ||
114 | ROUND3(C, D, A, B, 6, 11); | ||
115 | ROUND3(B, C, D, A, 14, 15); | ||
116 | ROUND3(A, B, C, D, 1, 3); | ||
117 | ROUND3(D, A, B, C, 9, 9); | ||
118 | ROUND3(C, D, A, B, 5, 11); | ||
119 | ROUND3(B, C, D, A, 13, 15); | ||
120 | ROUND3(A, B, C, D, 3, 3); | ||
121 | ROUND3(D, A, B, C, 11, 9); | ||
122 | ROUND3(C, D, A, B, 7, 11); | ||
123 | ROUND3(B, C, D, A, 15, 15); | ||
124 | |||
125 | *A += AA; | ||
126 | *B += BB; | ||
127 | *C += CC; | ||
128 | *D += DD; | ||
129 | |||
130 | *A &= 0xFFFFFFFF; | ||
131 | *B &= 0xFFFFFFFF; | ||
132 | *C &= 0xFFFFFFFF; | ||
133 | *D &= 0xFFFFFFFF; | ||
134 | |||
135 | for (j = 0; j < 16; j++) | ||
136 | X[j] = 0; | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | copy64(__u32 *M, unsigned char *in) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | for (i = 0; i < 16; i++) | ||
145 | M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) | | ||
146 | (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0); | ||
147 | } | ||
148 | |||
149 | static void | ||
150 | copy4(unsigned char *out, __u32 x) | ||
151 | { | ||
152 | out[0] = x & 0xFF; | ||
153 | out[1] = (x >> 8) & 0xFF; | ||
154 | out[2] = (x >> 16) & 0xFF; | ||
155 | out[3] = (x >> 24) & 0xFF; | ||
156 | } | ||
157 | |||
158 | /* produce a md4 message digest from data of length n bytes */ | ||
159 | void | ||
160 | mdfour(unsigned char *out, unsigned char *in, int n) | ||
161 | { | ||
162 | unsigned char buf[128]; | ||
163 | __u32 M[16]; | ||
164 | __u32 b = n * 8; | ||
165 | int i; | ||
166 | __u32 A = 0x67452301; | ||
167 | __u32 B = 0xefcdab89; | ||
168 | __u32 C = 0x98badcfe; | ||
169 | __u32 D = 0x10325476; | ||
170 | |||
171 | while (n > 64) { | ||
172 | copy64(M, in); | ||
173 | mdfour64(M, &A, &B, &C, &D); | ||
174 | in += 64; | ||
175 | n -= 64; | ||
176 | } | ||
177 | |||
178 | for (i = 0; i < 128; i++) | ||
179 | buf[i] = 0; | ||
180 | memcpy(buf, in, n); | ||
181 | buf[n] = 0x80; | ||
182 | |||
183 | if (n <= 55) { | ||
184 | copy4(buf + 56, b); | ||
185 | copy64(M, buf); | ||
186 | mdfour64(M, &A, &B, &C, &D); | ||
187 | } else { | ||
188 | copy4(buf + 120, b); | ||
189 | copy64(M, buf); | ||
190 | mdfour64(M, &A, &B, &C, &D); | ||
191 | copy64(M, buf + 64); | ||
192 | mdfour64(M, &A, &B, &C, &D); | ||
193 | } | ||
194 | |||
195 | for (i = 0; i < 128; i++) | ||
196 | buf[i] = 0; | ||
197 | copy64(M, buf); | ||
198 | |||
199 | copy4(out, A); | ||
200 | copy4(out + 4, B); | ||
201 | copy4(out + 8, C); | ||
202 | copy4(out + 12, D); | ||
203 | |||
204 | A = B = C = D = 0; | ||
205 | } | ||
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c deleted file mode 100644 index 98b66a54c319..000000000000 --- a/fs/cifs/md5.c +++ /dev/null | |||
@@ -1,366 +0,0 @@ | |||
1 | /* | ||
2 | * This code implements the MD5 message-digest algorithm. | ||
3 | * The algorithm is due to Ron Rivest. This code was | ||
4 | * written by Colin Plumb in 1993, no copyright is claimed. | ||
5 | * This code is in the public domain; do with it what you wish. | ||
6 | * | ||
7 | * Equivalent code is available from RSA Data Security, Inc. | ||
8 | * This code has been tested against that, and is equivalent, | ||
9 | * except that you don't need to include two pages of legalese | ||
10 | * with every copy. | ||
11 | * | ||
12 | * To compute the message digest of a chunk of bytes, declare an | ||
13 | * MD5Context structure, pass it to cifs_MD5_init, call cifs_MD5_update as | ||
14 | * needed on buffers full of bytes, and then call cifs_MD5_final, which | ||
15 | * will fill a supplied 16-byte array with the digest. | ||
16 | */ | ||
17 | |||
18 | /* This code slightly modified to fit into Samba by | ||
19 | abartlet@samba.org Jun 2001 | ||
20 | and to fit the cifs vfs by | ||
21 | Steve French sfrench@us.ibm.com */ | ||
22 | |||
23 | #include <linux/string.h> | ||
24 | #include "md5.h" | ||
25 | |||
26 | static void MD5Transform(__u32 buf[4], __u32 const in[16]); | ||
27 | |||
28 | /* | ||
29 | * Note: this code is harmless on little-endian machines. | ||
30 | */ | ||
31 | static void | ||
32 | byteReverse(unsigned char *buf, unsigned longs) | ||
33 | { | ||
34 | __u32 t; | ||
35 | do { | ||
36 | t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | | ||
37 | ((unsigned) buf[1] << 8 | buf[0]); | ||
38 | *(__u32 *) buf = t; | ||
39 | buf += 4; | ||
40 | } while (--longs); | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious | ||
45 | * initialization constants. | ||
46 | */ | ||
47 | void | ||
48 | cifs_MD5_init(struct MD5Context *ctx) | ||
49 | { | ||
50 | ctx->buf[0] = 0x67452301; | ||
51 | ctx->buf[1] = 0xefcdab89; | ||
52 | ctx->buf[2] = 0x98badcfe; | ||
53 | ctx->buf[3] = 0x10325476; | ||
54 | |||
55 | ctx->bits[0] = 0; | ||
56 | ctx->bits[1] = 0; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Update context to reflect the concatenation of another buffer full | ||
61 | * of bytes. | ||
62 | */ | ||
63 | void | ||
64 | cifs_MD5_update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) | ||
65 | { | ||
66 | register __u32 t; | ||
67 | |||
68 | /* Update bitcount */ | ||
69 | |||
70 | t = ctx->bits[0]; | ||
71 | if ((ctx->bits[0] = t + ((__u32) len << 3)) < t) | ||
72 | ctx->bits[1]++; /* Carry from low to high */ | ||
73 | ctx->bits[1] += len >> 29; | ||
74 | |||
75 | t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ | ||
76 | |||
77 | /* Handle any leading odd-sized chunks */ | ||
78 | |||
79 | if (t) { | ||
80 | unsigned char *p = (unsigned char *) ctx->in + t; | ||
81 | |||
82 | t = 64 - t; | ||
83 | if (len < t) { | ||
84 | memmove(p, buf, len); | ||
85 | return; | ||
86 | } | ||
87 | memmove(p, buf, t); | ||
88 | byteReverse(ctx->in, 16); | ||
89 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
90 | buf += t; | ||
91 | len -= t; | ||
92 | } | ||
93 | /* Process data in 64-byte chunks */ | ||
94 | |||
95 | while (len >= 64) { | ||
96 | memmove(ctx->in, buf, 64); | ||
97 | byteReverse(ctx->in, 16); | ||
98 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
99 | buf += 64; | ||
100 | len -= 64; | ||
101 | } | ||
102 | |||
103 | /* Handle any remaining bytes of data. */ | ||
104 | |||
105 | memmove(ctx->in, buf, len); | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Final wrapup - pad to 64-byte boundary with the bit pattern | ||
110 | * 1 0* (64-bit count of bits processed, MSB-first) | ||
111 | */ | ||
112 | void | ||
113 | cifs_MD5_final(unsigned char digest[16], struct MD5Context *ctx) | ||
114 | { | ||
115 | unsigned int count; | ||
116 | unsigned char *p; | ||
117 | |||
118 | /* Compute number of bytes mod 64 */ | ||
119 | count = (ctx->bits[0] >> 3) & 0x3F; | ||
120 | |||
121 | /* Set the first char of padding to 0x80. This is safe since there is | ||
122 | always at least one byte free */ | ||
123 | p = ctx->in + count; | ||
124 | *p++ = 0x80; | ||
125 | |||
126 | /* Bytes of padding needed to make 64 bytes */ | ||
127 | count = 64 - 1 - count; | ||
128 | |||
129 | /* Pad out to 56 mod 64 */ | ||
130 | if (count < 8) { | ||
131 | /* Two lots of padding: Pad the first block to 64 bytes */ | ||
132 | memset(p, 0, count); | ||
133 | byteReverse(ctx->in, 16); | ||
134 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
135 | |||
136 | /* Now fill the next block with 56 bytes */ | ||
137 | memset(ctx->in, 0, 56); | ||
138 | } else { | ||
139 | /* Pad block to 56 bytes */ | ||
140 | memset(p, 0, count - 8); | ||
141 | } | ||
142 | byteReverse(ctx->in, 14); | ||
143 | |||
144 | /* Append length in bits and transform */ | ||
145 | ((__u32 *) ctx->in)[14] = ctx->bits[0]; | ||
146 | ((__u32 *) ctx->in)[15] = ctx->bits[1]; | ||
147 | |||
148 | MD5Transform(ctx->buf, (__u32 *) ctx->in); | ||
149 | byteReverse((unsigned char *) ctx->buf, 4); | ||
150 | memmove(digest, ctx->buf, 16); | ||
151 | memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ | ||
152 | } | ||
153 | |||
154 | /* The four core functions - F1 is optimized somewhat */ | ||
155 | |||
156 | /* #define F1(x, y, z) (x & y | ~x & z) */ | ||
157 | #define F1(x, y, z) (z ^ (x & (y ^ z))) | ||
158 | #define F2(x, y, z) F1(z, x, y) | ||
159 | #define F3(x, y, z) (x ^ y ^ z) | ||
160 | #define F4(x, y, z) (y ^ (x | ~z)) | ||
161 | |||
162 | /* This is the central step in the MD5 algorithm. */ | ||
163 | #define MD5STEP(f, w, x, y, z, data, s) \ | ||
164 | (w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x) | ||
165 | |||
166 | /* | ||
167 | * The core of the MD5 algorithm, this alters an existing MD5 hash to | ||
168 | * reflect the addition of 16 longwords of new data. cifs_MD5_update blocks | ||
169 | * the data and converts bytes into longwords for this routine. | ||
170 | */ | ||
171 | static void | ||
172 | MD5Transform(__u32 buf[4], __u32 const in[16]) | ||
173 | { | ||
174 | register __u32 a, b, c, d; | ||
175 | |||
176 | a = buf[0]; | ||
177 | b = buf[1]; | ||
178 | c = buf[2]; | ||
179 | d = buf[3]; | ||
180 | |||
181 | MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); | ||
182 | MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); | ||
183 | MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); | ||
184 | MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); | ||
185 | MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); | ||
186 | MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); | ||
187 | MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); | ||
188 | MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); | ||
189 | MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); | ||
190 | MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); | ||
191 | MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); | ||
192 | MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); | ||
193 | MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); | ||
194 | MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); | ||
195 | MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); | ||
196 | MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); | ||
197 | |||
198 | MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); | ||
199 | MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); | ||
200 | MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); | ||
201 | MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); | ||
202 | MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); | ||
203 | MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); | ||
204 | MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); | ||
205 | MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); | ||
206 | MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); | ||
207 | MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); | ||
208 | MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); | ||
209 | MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); | ||
210 | MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); | ||
211 | MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); | ||
212 | MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); | ||
213 | MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); | ||
214 | |||
215 | MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); | ||
216 | MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); | ||
217 | MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); | ||
218 | MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); | ||
219 | MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); | ||
220 | MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); | ||
221 | MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); | ||
222 | MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); | ||
223 | MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); | ||
224 | MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); | ||
225 | MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); | ||
226 | MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); | ||
227 | MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); | ||
228 | MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); | ||
229 | MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); | ||
230 | MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); | ||
231 | |||
232 | MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); | ||
233 | MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); | ||
234 | MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); | ||
235 | MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); | ||
236 | MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); | ||
237 | MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); | ||
238 | MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); | ||
239 | MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); | ||
240 | MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); | ||
241 | MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); | ||
242 | MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); | ||
243 | MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); | ||
244 | MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); | ||
245 | MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); | ||
246 | MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); | ||
247 | MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); | ||
248 | |||
249 | buf[0] += a; | ||
250 | buf[1] += b; | ||
251 | buf[2] += c; | ||
252 | buf[3] += d; | ||
253 | } | ||
254 | |||
255 | #if 0 /* currently unused */ | ||
256 | /*********************************************************************** | ||
257 | the rfc 2104 version of hmac_md5 initialisation. | ||
258 | ***********************************************************************/ | ||
259 | static void | ||
260 | hmac_md5_init_rfc2104(unsigned char *key, int key_len, | ||
261 | struct HMACMD5Context *ctx) | ||
262 | { | ||
263 | int i; | ||
264 | |||
265 | /* if key is longer than 64 bytes reset it to key=MD5(key) */ | ||
266 | if (key_len > 64) { | ||
267 | unsigned char tk[16]; | ||
268 | struct MD5Context tctx; | ||
269 | |||
270 | cifs_MD5_init(&tctx); | ||
271 | cifs_MD5_update(&tctx, key, key_len); | ||
272 | cifs_MD5_final(tk, &tctx); | ||
273 | |||
274 | key = tk; | ||
275 | key_len = 16; | ||
276 | } | ||
277 | |||
278 | /* start out by storing key in pads */ | ||
279 | memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad)); | ||
280 | memset(ctx->k_opad, 0, sizeof(ctx->k_opad)); | ||
281 | memcpy(ctx->k_ipad, key, key_len); | ||
282 | memcpy(ctx->k_opad, key, key_len); | ||
283 | |||
284 | /* XOR key with ipad and opad values */ | ||
285 | for (i = 0; i < 64; i++) { | ||
286 | ctx->k_ipad[i] ^= 0x36; | ||
287 | ctx->k_opad[i] ^= 0x5c; | ||
288 | } | ||
289 | |||
290 | cifs_MD5_init(&ctx->ctx); | ||
291 | cifs_MD5_update(&ctx->ctx, ctx->k_ipad, 64); | ||
292 | } | ||
293 | #endif | ||
294 | |||
295 | /*********************************************************************** | ||
296 | the microsoft version of hmac_md5 initialisation. | ||
297 | ***********************************************************************/ | ||
298 | void | ||
299 | hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, | ||
300 | struct HMACMD5Context *ctx) | ||
301 | { | ||
302 | int i; | ||
303 | |||
304 | /* if key is longer than 64 bytes truncate it */ | ||
305 | if (key_len > 64) | ||
306 | key_len = 64; | ||
307 | |||
308 | /* start out by storing key in pads */ | ||
309 | memset(ctx->k_ipad, 0, sizeof(ctx->k_ipad)); | ||
310 | memset(ctx->k_opad, 0, sizeof(ctx->k_opad)); | ||
311 | memcpy(ctx->k_ipad, key, key_len); | ||
312 | memcpy(ctx->k_opad, key, key_len); | ||
313 | |||
314 | /* XOR key with ipad and opad values */ | ||
315 | for (i = 0; i < 64; i++) { | ||
316 | ctx->k_ipad[i] ^= 0x36; | ||
317 | ctx->k_opad[i] ^= 0x5c; | ||
318 | } | ||
319 | |||
320 | cifs_MD5_init(&ctx->ctx); | ||
321 | cifs_MD5_update(&ctx->ctx, ctx->k_ipad, 64); | ||
322 | } | ||
323 | |||
324 | /*********************************************************************** | ||
325 | update hmac_md5 "inner" buffer | ||
326 | ***********************************************************************/ | ||
327 | void | ||
328 | hmac_md5_update(const unsigned char *text, int text_len, | ||
329 | struct HMACMD5Context *ctx) | ||
330 | { | ||
331 | cifs_MD5_update(&ctx->ctx, text, text_len); /* then text of datagram */ | ||
332 | } | ||
333 | |||
334 | /*********************************************************************** | ||
335 | finish off hmac_md5 "inner" buffer and generate outer one. | ||
336 | ***********************************************************************/ | ||
337 | void | ||
338 | hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) | ||
339 | { | ||
340 | struct MD5Context ctx_o; | ||
341 | |||
342 | cifs_MD5_final(digest, &ctx->ctx); | ||
343 | |||
344 | cifs_MD5_init(&ctx_o); | ||
345 | cifs_MD5_update(&ctx_o, ctx->k_opad, 64); | ||
346 | cifs_MD5_update(&ctx_o, digest, 16); | ||
347 | cifs_MD5_final(digest, &ctx_o); | ||
348 | } | ||
349 | |||
350 | /*********************************************************** | ||
351 | single function to calculate an HMAC MD5 digest from data. | ||
352 | use the microsoft hmacmd5 init method because the key is 16 bytes. | ||
353 | ************************************************************/ | ||
354 | #if 0 /* currently unused */ | ||
355 | static void | ||
356 | hmac_md5(unsigned char key[16], unsigned char *data, int data_len, | ||
357 | unsigned char *digest) | ||
358 | { | ||
359 | struct HMACMD5Context ctx; | ||
360 | hmac_md5_init_limK_to_64(key, 16, &ctx); | ||
361 | if (data_len != 0) | ||
362 | hmac_md5_update(data, data_len, &ctx); | ||
363 | |||
364 | hmac_md5_final(digest, &ctx); | ||
365 | } | ||
366 | #endif | ||
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h deleted file mode 100644 index 6fba8cb402fd..000000000000 --- a/fs/cifs/md5.h +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | #ifndef MD5_H | ||
2 | #define MD5_H | ||
3 | #ifndef HEADER_MD5_H | ||
4 | /* Try to avoid clashes with OpenSSL */ | ||
5 | #define HEADER_MD5_H | ||
6 | #endif | ||
7 | |||
8 | struct MD5Context { | ||
9 | __u32 buf[4]; | ||
10 | __u32 bits[2]; | ||
11 | unsigned char in[64]; | ||
12 | }; | ||
13 | #endif /* !MD5_H */ | ||
14 | |||
15 | #ifndef _HMAC_MD5_H | ||
16 | struct HMACMD5Context { | ||
17 | struct MD5Context ctx; | ||
18 | unsigned char k_ipad[65]; | ||
19 | unsigned char k_opad[65]; | ||
20 | }; | ||
21 | #endif /* _HMAC_MD5_H */ | ||
22 | |||
23 | void cifs_MD5_init(struct MD5Context *context); | ||
24 | void cifs_MD5_update(struct MD5Context *context, unsigned char const *buf, | ||
25 | unsigned len); | ||
26 | void cifs_MD5_final(unsigned char digest[16], struct MD5Context *context); | ||
27 | |||
28 | /* The following definitions come from lib/hmacmd5.c */ | ||
29 | |||
30 | /* void hmac_md5_init_rfc2104(unsigned char *key, int key_len, | ||
31 | struct HMACMD5Context *ctx);*/ | ||
32 | void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, | ||
33 | struct HMACMD5Context *ctx); | ||
34 | void hmac_md5_update(const unsigned char *text, int text_len, | ||
35 | struct HMACMD5Context *ctx); | ||
36 | void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); | ||
37 | /* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, | ||
38 | unsigned char *digest);*/ | ||
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 3ccadc1326d6..03a1f491d39b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -67,12 +67,12 @@ _FreeXid(unsigned int xid) | |||
67 | spin_unlock(&GlobalMid_Lock); | 67 | spin_unlock(&GlobalMid_Lock); |
68 | } | 68 | } |
69 | 69 | ||
70 | struct cifsSesInfo * | 70 | struct cifs_ses * |
71 | sesInfoAlloc(void) | 71 | sesInfoAlloc(void) |
72 | { | 72 | { |
73 | struct cifsSesInfo *ret_buf; | 73 | struct cifs_ses *ret_buf; |
74 | 74 | ||
75 | ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); | 75 | ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL); |
76 | if (ret_buf) { | 76 | if (ret_buf) { |
77 | atomic_inc(&sesInfoAllocCount); | 77 | atomic_inc(&sesInfoAllocCount); |
78 | ret_buf->status = CifsNew; | 78 | ret_buf->status = CifsNew; |
@@ -85,7 +85,7 @@ sesInfoAlloc(void) | |||
85 | } | 85 | } |
86 | 86 | ||
87 | void | 87 | void |
88 | sesInfoFree(struct cifsSesInfo *buf_to_free) | 88 | sesInfoFree(struct cifs_ses *buf_to_free) |
89 | { | 89 | { |
90 | if (buf_to_free == NULL) { | 90 | if (buf_to_free == NULL) { |
91 | cFYI(1, "Null buffer passed to sesInfoFree"); | 91 | cFYI(1, "Null buffer passed to sesInfoFree"); |
@@ -100,15 +100,16 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) | |||
100 | memset(buf_to_free->password, 0, strlen(buf_to_free->password)); | 100 | memset(buf_to_free->password, 0, strlen(buf_to_free->password)); |
101 | kfree(buf_to_free->password); | 101 | kfree(buf_to_free->password); |
102 | } | 102 | } |
103 | kfree(buf_to_free->user_name); | ||
103 | kfree(buf_to_free->domainName); | 104 | kfree(buf_to_free->domainName); |
104 | kfree(buf_to_free); | 105 | kfree(buf_to_free); |
105 | } | 106 | } |
106 | 107 | ||
107 | struct cifsTconInfo * | 108 | struct cifs_tcon * |
108 | tconInfoAlloc(void) | 109 | tconInfoAlloc(void) |
109 | { | 110 | { |
110 | struct cifsTconInfo *ret_buf; | 111 | struct cifs_tcon *ret_buf; |
111 | ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); | 112 | ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL); |
112 | if (ret_buf) { | 113 | if (ret_buf) { |
113 | atomic_inc(&tconInfoAllocCount); | 114 | atomic_inc(&tconInfoAllocCount); |
114 | ret_buf->tidStatus = CifsNew; | 115 | ret_buf->tidStatus = CifsNew; |
@@ -123,7 +124,7 @@ tconInfoAlloc(void) | |||
123 | } | 124 | } |
124 | 125 | ||
125 | void | 126 | void |
126 | tconInfoFree(struct cifsTconInfo *buf_to_free) | 127 | tconInfoFree(struct cifs_tcon *buf_to_free) |
127 | { | 128 | { |
128 | if (buf_to_free == NULL) { | 129 | if (buf_to_free == NULL) { |
129 | cFYI(1, "Null buffer passed to tconInfoFree"); | 130 | cFYI(1, "Null buffer passed to tconInfoFree"); |
@@ -236,10 +237,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
236 | { | 237 | { |
237 | __u16 mid = 0; | 238 | __u16 mid = 0; |
238 | __u16 last_mid; | 239 | __u16 last_mid; |
239 | int collision; | 240 | bool collision; |
240 | |||
241 | if (server == NULL) | ||
242 | return mid; | ||
243 | 241 | ||
244 | spin_lock(&GlobalMid_Lock); | 242 | spin_lock(&GlobalMid_Lock); |
245 | last_mid = server->CurrentMid; /* we do not want to loop forever */ | 243 | last_mid = server->CurrentMid; /* we do not want to loop forever */ |
@@ -252,24 +250,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
252 | (and it would also have to have been a request that | 250 | (and it would also have to have been a request that |
253 | did not time out) */ | 251 | did not time out) */ |
254 | while (server->CurrentMid != last_mid) { | 252 | while (server->CurrentMid != last_mid) { |
255 | struct list_head *tmp; | ||
256 | struct mid_q_entry *mid_entry; | 253 | struct mid_q_entry *mid_entry; |
254 | unsigned int num_mids; | ||
257 | 255 | ||
258 | collision = 0; | 256 | collision = false; |
259 | if (server->CurrentMid == 0) | 257 | if (server->CurrentMid == 0) |
260 | server->CurrentMid++; | 258 | server->CurrentMid++; |
261 | 259 | ||
262 | list_for_each(tmp, &server->pending_mid_q) { | 260 | num_mids = 0; |
263 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 261 | list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { |
264 | 262 | ++num_mids; | |
265 | if ((mid_entry->mid == server->CurrentMid) && | 263 | if (mid_entry->mid == server->CurrentMid && |
266 | (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | 264 | mid_entry->midState == MID_REQUEST_SUBMITTED) { |
267 | /* This mid is in use, try a different one */ | 265 | /* This mid is in use, try a different one */ |
268 | collision = 1; | 266 | collision = true; |
269 | break; | 267 | break; |
270 | } | 268 | } |
271 | } | 269 | } |
272 | if (collision == 0) { | 270 | |
271 | /* | ||
272 | * if we have more than 32k mids in the list, then something | ||
273 | * is very wrong. Possibly a local user is trying to DoS the | ||
274 | * box by issuing long-running calls and SIGKILL'ing them. If | ||
275 | * we get to 2^16 mids then we're in big trouble as this | ||
276 | * function could loop forever. | ||
277 | * | ||
278 | * Go ahead and assign out the mid in this situation, but force | ||
279 | * an eventual reconnect to clean out the pending_mid_q. | ||
280 | */ | ||
281 | if (num_mids > 32768) | ||
282 | server->tcpStatus = CifsNeedReconnect; | ||
283 | |||
284 | if (!collision) { | ||
273 | mid = server->CurrentMid; | 285 | mid = server->CurrentMid; |
274 | break; | 286 | break; |
275 | } | 287 | } |
@@ -283,21 +295,19 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
283 | case it is responsbility of caller to set the mid */ | 295 | case it is responsbility of caller to set the mid */ |
284 | void | 296 | void |
285 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | 297 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , |
286 | const struct cifsTconInfo *treeCon, int word_count | 298 | const struct cifs_tcon *treeCon, int word_count |
287 | /* length of fixed section (word count) in two byte units */) | 299 | /* length of fixed section (word count) in two byte units */) |
288 | { | 300 | { |
289 | struct list_head *temp_item; | 301 | struct list_head *temp_item; |
290 | struct cifsSesInfo *ses; | 302 | struct cifs_ses *ses; |
291 | char *temp = (char *) buffer; | 303 | char *temp = (char *) buffer; |
292 | 304 | ||
293 | memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ | 305 | memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ |
294 | 306 | ||
295 | buffer->smb_buf_length = | 307 | buffer->smb_buf_length = cpu_to_be32( |
296 | (2 * word_count) + sizeof(struct smb_hdr) - | 308 | (2 * word_count) + sizeof(struct smb_hdr) - |
297 | 4 /* RFC 1001 length field does not count */ + | 309 | 4 /* RFC 1001 length field does not count */ + |
298 | 2 /* for bcc field itself */ ; | 310 | 2 /* for bcc field itself */) ; |
299 | /* Note that this is the only network field that has to be converted | ||
300 | to big endian and it is done just before we send it */ | ||
301 | 311 | ||
302 | buffer->Protocol[0] = 0xFF; | 312 | buffer->Protocol[0] = 0xFF; |
303 | buffer->Protocol[1] = 'S'; | 313 | buffer->Protocol[1] = 'S'; |
@@ -347,9 +357,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
347 | if (current_fsuid() != treeCon->ses->linux_uid) { | 357 | if (current_fsuid() != treeCon->ses->linux_uid) { |
348 | cFYI(1, "Multiuser mode and UID " | 358 | cFYI(1, "Multiuser mode and UID " |
349 | "did not match tcon uid"); | 359 | "did not match tcon uid"); |
350 | read_lock(&cifs_tcp_ses_lock); | 360 | spin_lock(&cifs_tcp_ses_lock); |
351 | list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) { | 361 | list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) { |
352 | ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list); | 362 | ses = list_entry(temp_item, struct cifs_ses, smb_ses_list); |
353 | if (ses->linux_uid == current_fsuid()) { | 363 | if (ses->linux_uid == current_fsuid()) { |
354 | if (ses->server == treeCon->ses->server) { | 364 | if (ses->server == treeCon->ses->server) { |
355 | cFYI(1, "found matching uid substitute right smb_uid"); | 365 | cFYI(1, "found matching uid substitute right smb_uid"); |
@@ -361,7 +371,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
361 | } | 371 | } |
362 | } | 372 | } |
363 | } | 373 | } |
364 | read_unlock(&cifs_tcp_ses_lock); | 374 | spin_unlock(&cifs_tcp_ses_lock); |
365 | } | 375 | } |
366 | } | 376 | } |
367 | } | 377 | } |
@@ -370,7 +380,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
370 | if (treeCon->nocase) | 380 | if (treeCon->nocase) |
371 | buffer->Flags |= SMBFLG_CASELESS; | 381 | buffer->Flags |= SMBFLG_CASELESS; |
372 | if ((treeCon->ses) && (treeCon->ses->server)) | 382 | if ((treeCon->ses) && (treeCon->ses->server)) |
373 | if (treeCon->ses->server->secMode & | 383 | if (treeCon->ses->server->sec_mode & |
374 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 384 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
375 | buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 385 | buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
376 | } | 386 | } |
@@ -381,36 +391,38 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
381 | } | 391 | } |
382 | 392 | ||
383 | static int | 393 | static int |
384 | checkSMBhdr(struct smb_hdr *smb, __u16 mid) | 394 | check_smb_hdr(struct smb_hdr *smb, __u16 mid) |
385 | { | 395 | { |
386 | /* Make sure that this really is an SMB, that it is a response, | 396 | /* does it have the right SMB "signature" ? */ |
387 | and that the message ids match */ | 397 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) { |
388 | if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) && | 398 | cERROR(1, "Bad protocol string signature header 0x%x", |
389 | (mid == smb->Mid)) { | 399 | *(unsigned int *)smb->Protocol); |
390 | if (smb->Flags & SMBFLG_RESPONSE) | 400 | return 1; |
391 | return 0; | 401 | } |
392 | else { | 402 | |
393 | /* only one valid case where server sends us request */ | 403 | /* Make sure that message ids match */ |
394 | if (smb->Command == SMB_COM_LOCKING_ANDX) | 404 | if (mid != smb->Mid) { |
395 | return 0; | 405 | cERROR(1, "Mids do not match. received=%u expected=%u", |
396 | else | 406 | smb->Mid, mid); |
397 | cERROR(1, "Received Request not response"); | 407 | return 1; |
398 | } | ||
399 | } else { /* bad signature or mid */ | ||
400 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) | ||
401 | cERROR(1, "Bad protocol string signature header %x", | ||
402 | *(unsigned int *) smb->Protocol); | ||
403 | if (mid != smb->Mid) | ||
404 | cERROR(1, "Mids do not match"); | ||
405 | } | 408 | } |
406 | cERROR(1, "bad smb detected. The Mid=%d", smb->Mid); | 409 | |
410 | /* if it's a response then accept */ | ||
411 | if (smb->Flags & SMBFLG_RESPONSE) | ||
412 | return 0; | ||
413 | |||
414 | /* only one valid case where server sends us request */ | ||
415 | if (smb->Command == SMB_COM_LOCKING_ANDX) | ||
416 | return 0; | ||
417 | |||
418 | cERROR(1, "Server sent request, not response. mid=%u", smb->Mid); | ||
407 | return 1; | 419 | return 1; |
408 | } | 420 | } |
409 | 421 | ||
410 | int | 422 | int |
411 | checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) | 423 | checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) |
412 | { | 424 | { |
413 | __u32 len = smb->smb_buf_length; | 425 | __u32 len = be32_to_cpu(smb->smb_buf_length); |
414 | __u32 clc_len; /* calculated length */ | 426 | __u32 clc_len; /* calculated length */ |
415 | cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len); | 427 | cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len); |
416 | 428 | ||
@@ -448,9 +460,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) | |||
448 | return 1; | 460 | return 1; |
449 | } | 461 | } |
450 | 462 | ||
451 | if (checkSMBhdr(smb, mid)) | 463 | if (check_smb_hdr(smb, mid)) |
452 | return 1; | 464 | return 1; |
453 | clc_len = smbCalcSize_LE(smb); | 465 | clc_len = smbCalcSize(smb); |
454 | 466 | ||
455 | if (4 + len != length) { | 467 | if (4 + len != length) { |
456 | cERROR(1, "Length read does not match RFC1001 length %d", | 468 | cERROR(1, "Length read does not match RFC1001 length %d", |
@@ -465,25 +477,26 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) | |||
465 | if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) | 477 | if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) |
466 | return 0; /* bcc wrapped */ | 478 | return 0; /* bcc wrapped */ |
467 | } | 479 | } |
468 | cFYI(1, "Calculated size %d vs length %d mismatch for mid %d", | 480 | cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u", |
469 | clc_len, 4 + len, smb->Mid); | 481 | clc_len, 4 + len, smb->Mid); |
470 | /* Windows XP can return a few bytes too much, presumably | 482 | |
471 | an illegal pad, at the end of byte range lock responses | 483 | if (4 + len < clc_len) { |
472 | so we allow for that three byte pad, as long as actual | 484 | cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u", |
473 | received length is as long or longer than calculated length */ | ||
474 | /* We have now had to extend this more, since there is a | ||
475 | case in which it needs to be bigger still to handle a | ||
476 | malformed response to transact2 findfirst from WinXP when | ||
477 | access denied is returned and thus bcc and wct are zero | ||
478 | but server says length is 0x21 bytes too long as if the server | ||
479 | forget to reset the smb rfc1001 length when it reset the | ||
480 | wct and bcc to minimum size and drop the t2 parms and data */ | ||
481 | if ((4+len > clc_len) && (len <= clc_len + 512)) | ||
482 | return 0; | ||
483 | else { | ||
484 | cERROR(1, "RFC1001 size %d bigger than SMB for Mid=%d", | ||
485 | len, smb->Mid); | 485 | len, smb->Mid); |
486 | return 1; | 486 | return 1; |
487 | } else if (len > clc_len + 512) { | ||
488 | /* | ||
489 | * Some servers (Windows XP in particular) send more | ||
490 | * data than the lengths in the SMB packet would | ||
491 | * indicate on certain calls (byte range locks and | ||
492 | * trans2 find first calls in particular). While the | ||
493 | * client can handle such a frame by ignoring the | ||
494 | * trailing data, we choose limit the amount of extra | ||
495 | * data to 512 bytes. | ||
496 | */ | ||
497 | cERROR(1, "RFC1001 size %u more than 512 bytes larger " | ||
498 | "than SMB for mid=%u", len, smb->Mid); | ||
499 | return 1; | ||
487 | } | 500 | } |
488 | } | 501 | } |
489 | return 0; | 502 | return 0; |
@@ -494,8 +507,8 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
494 | { | 507 | { |
495 | struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; | 508 | struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; |
496 | struct list_head *tmp, *tmp1, *tmp2; | 509 | struct list_head *tmp, *tmp1, *tmp2; |
497 | struct cifsSesInfo *ses; | 510 | struct cifs_ses *ses; |
498 | struct cifsTconInfo *tcon; | 511 | struct cifs_tcon *tcon; |
499 | struct cifsInodeInfo *pCifsInode; | 512 | struct cifsInodeInfo *pCifsInode; |
500 | struct cifsFileInfo *netfile; | 513 | struct cifsFileInfo *netfile; |
501 | 514 | ||
@@ -506,7 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
506 | (struct smb_com_transaction_change_notify_rsp *)buf; | 519 | (struct smb_com_transaction_change_notify_rsp *)buf; |
507 | struct file_notify_information *pnotify; | 520 | struct file_notify_information *pnotify; |
508 | __u32 data_offset = 0; | 521 | __u32 data_offset = 0; |
509 | if (pSMBr->ByteCount > sizeof(struct file_notify_information)) { | 522 | if (get_bcc(buf) > sizeof(struct file_notify_information)) { |
510 | data_offset = le32_to_cpu(pSMBr->DataOffset); | 523 | data_offset = le32_to_cpu(pSMBr->DataOffset); |
511 | 524 | ||
512 | pnotify = (struct file_notify_information *) | 525 | pnotify = (struct file_notify_information *) |
@@ -551,60 +564,49 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
551 | return false; | 564 | return false; |
552 | 565 | ||
553 | /* look up tcon based on tid & uid */ | 566 | /* look up tcon based on tid & uid */ |
554 | read_lock(&cifs_tcp_ses_lock); | 567 | spin_lock(&cifs_tcp_ses_lock); |
555 | list_for_each(tmp, &srv->smb_ses_list) { | 568 | list_for_each(tmp, &srv->smb_ses_list) { |
556 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 569 | ses = list_entry(tmp, struct cifs_ses, smb_ses_list); |
557 | list_for_each(tmp1, &ses->tcon_list) { | 570 | list_for_each(tmp1, &ses->tcon_list) { |
558 | tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list); | 571 | tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); |
559 | if (tcon->tid != buf->Tid) | 572 | if (tcon->tid != buf->Tid) |
560 | continue; | 573 | continue; |
561 | 574 | ||
562 | cifs_stats_inc(&tcon->num_oplock_brks); | 575 | cifs_stats_inc(&tcon->num_oplock_brks); |
563 | read_lock(&GlobalSMBSeslock); | 576 | spin_lock(&cifs_file_list_lock); |
564 | list_for_each(tmp2, &tcon->openFileList) { | 577 | list_for_each(tmp2, &tcon->openFileList) { |
565 | netfile = list_entry(tmp2, struct cifsFileInfo, | 578 | netfile = list_entry(tmp2, struct cifsFileInfo, |
566 | tlist); | 579 | tlist); |
567 | if (pSMB->Fid != netfile->netfid) | 580 | if (pSMB->Fid != netfile->netfid) |
568 | continue; | 581 | continue; |
569 | 582 | ||
570 | /* | ||
571 | * don't do anything if file is about to be | ||
572 | * closed anyway. | ||
573 | */ | ||
574 | if (netfile->closePend) { | ||
575 | read_unlock(&GlobalSMBSeslock); | ||
576 | read_unlock(&cifs_tcp_ses_lock); | ||
577 | return true; | ||
578 | } | ||
579 | |||
580 | cFYI(1, "file id match, oplock break"); | 583 | cFYI(1, "file id match, oplock break"); |
581 | pCifsInode = CIFS_I(netfile->pInode); | 584 | pCifsInode = CIFS_I(netfile->dentry->d_inode); |
582 | pCifsInode->clientCanCacheAll = false; | ||
583 | if (pSMB->OplockLevel == 0) | ||
584 | pCifsInode->clientCanCacheRead = false; | ||
585 | 585 | ||
586 | cifs_set_oplock_level(pCifsInode, | ||
587 | pSMB->OplockLevel ? OPLOCK_READ : 0); | ||
586 | /* | 588 | /* |
587 | * cifs_oplock_break_put() can't be called | 589 | * cifs_oplock_break_put() can't be called |
588 | * from here. Get reference after queueing | 590 | * from here. Get reference after queueing |
589 | * succeeded. cifs_oplock_break() will | 591 | * succeeded. cifs_oplock_break() will |
590 | * synchronize using GlobalSMSSeslock. | 592 | * synchronize using cifs_file_list_lock. |
591 | */ | 593 | */ |
592 | if (queue_work(system_nrt_wq, | 594 | if (queue_work(system_nrt_wq, |
593 | &netfile->oplock_break)) | 595 | &netfile->oplock_break)) |
594 | cifs_oplock_break_get(netfile); | 596 | cifs_oplock_break_get(netfile); |
595 | netfile->oplock_break_cancelled = false; | 597 | netfile->oplock_break_cancelled = false; |
596 | 598 | ||
597 | read_unlock(&GlobalSMBSeslock); | 599 | spin_unlock(&cifs_file_list_lock); |
598 | read_unlock(&cifs_tcp_ses_lock); | 600 | spin_unlock(&cifs_tcp_ses_lock); |
599 | return true; | 601 | return true; |
600 | } | 602 | } |
601 | read_unlock(&GlobalSMBSeslock); | 603 | spin_unlock(&cifs_file_list_lock); |
602 | read_unlock(&cifs_tcp_ses_lock); | 604 | spin_unlock(&cifs_tcp_ses_lock); |
603 | cFYI(1, "No matching file for oplock break"); | 605 | cFYI(1, "No matching file for oplock break"); |
604 | return true; | 606 | return true; |
605 | } | 607 | } |
606 | } | 608 | } |
607 | read_unlock(&cifs_tcp_ses_lock); | 609 | spin_unlock(&cifs_tcp_ses_lock); |
608 | cFYI(1, "Can not process oplock break for non-existent connection"); | 610 | cFYI(1, "Can not process oplock break for non-existent connection"); |
609 | return true; | 611 | return true; |
610 | } | 612 | } |
@@ -648,77 +650,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) | |||
648 | return; | 650 | return; |
649 | } | 651 | } |
650 | 652 | ||
651 | /* Convert 16 bit Unicode pathname to wire format from string in current code | ||
652 | page. Conversion may involve remapping up the seven characters that are | ||
653 | only legal in POSIX-like OS (if they are present in the string). Path | ||
654 | names are little endian 16 bit Unicode on the wire */ | ||
655 | int | ||
656 | cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
657 | const struct nls_table *cp, int mapChars) | ||
658 | { | ||
659 | int i, j, charlen; | ||
660 | int len_remaining = maxlen; | ||
661 | char src_char; | ||
662 | __u16 temp; | ||
663 | |||
664 | if (!mapChars) | ||
665 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | ||
666 | |||
667 | for (i = 0, j = 0; i < maxlen; j++) { | ||
668 | src_char = source[i]; | ||
669 | switch (src_char) { | ||
670 | case 0: | ||
671 | target[j] = 0; | ||
672 | goto ctoUCS_out; | ||
673 | case ':': | ||
674 | target[j] = cpu_to_le16(UNI_COLON); | ||
675 | break; | ||
676 | case '*': | ||
677 | target[j] = cpu_to_le16(UNI_ASTERIK); | ||
678 | break; | ||
679 | case '?': | ||
680 | target[j] = cpu_to_le16(UNI_QUESTION); | ||
681 | break; | ||
682 | case '<': | ||
683 | target[j] = cpu_to_le16(UNI_LESSTHAN); | ||
684 | break; | ||
685 | case '>': | ||
686 | target[j] = cpu_to_le16(UNI_GRTRTHAN); | ||
687 | break; | ||
688 | case '|': | ||
689 | target[j] = cpu_to_le16(UNI_PIPE); | ||
690 | break; | ||
691 | /* BB We can not handle remapping slash until | ||
692 | all the calls to build_path_from_dentry | ||
693 | are modified, as they use slash as separator BB */ | ||
694 | /* case '\\': | ||
695 | target[j] = cpu_to_le16(UNI_SLASH); | ||
696 | break;*/ | ||
697 | default: | ||
698 | charlen = cp->char2uni(source+i, | ||
699 | len_remaining, &temp); | ||
700 | /* if no match, use question mark, which | ||
701 | at least in some cases servers as wild card */ | ||
702 | if (charlen < 1) { | ||
703 | target[j] = cpu_to_le16(0x003f); | ||
704 | charlen = 1; | ||
705 | } else | ||
706 | target[j] = cpu_to_le16(temp); | ||
707 | len_remaining -= charlen; | ||
708 | /* character may take more than one byte in the | ||
709 | the source string, but will take exactly two | ||
710 | bytes in the target string */ | ||
711 | i += charlen; | ||
712 | continue; | ||
713 | } | ||
714 | i++; /* move to next char in source string */ | ||
715 | len_remaining--; | ||
716 | } | ||
717 | |||
718 | ctoUCS_out: | ||
719 | return i; | ||
720 | } | ||
721 | |||
722 | void | 653 | void |
723 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) | 654 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) |
724 | { | 655 | { |
@@ -729,6 +660,26 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) | |||
729 | "properly. Hardlinks will not be recognized on this " | 660 | "properly. Hardlinks will not be recognized on this " |
730 | "mount. Consider mounting with the \"noserverino\" " | 661 | "mount. Consider mounting with the \"noserverino\" " |
731 | "option to silence this message.", | 662 | "option to silence this message.", |
732 | cifs_sb->tcon->treeName); | 663 | cifs_sb_master_tcon(cifs_sb)->treeName); |
664 | } | ||
665 | } | ||
666 | |||
667 | void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) | ||
668 | { | ||
669 | oplock &= 0xF; | ||
670 | |||
671 | if (oplock == OPLOCK_EXCLUSIVE) { | ||
672 | cinode->clientCanCacheAll = true; | ||
673 | cinode->clientCanCacheRead = true; | ||
674 | cFYI(1, "Exclusive Oplock granted on inode %p", | ||
675 | &cinode->vfs_inode); | ||
676 | } else if (oplock == OPLOCK_READ) { | ||
677 | cinode->clientCanCacheAll = false; | ||
678 | cinode->clientCanCacheRead = true; | ||
679 | cFYI(1, "Level II Oplock granted on inode %p", | ||
680 | &cinode->vfs_inode); | ||
681 | } else { | ||
682 | cinode->clientCanCacheAll = false; | ||
683 | cinode->clientCanCacheRead = false; | ||
733 | } | 684 | } |
734 | } | 685 | } |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 9aad47a2d62f..73e47e84b61a 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -170,7 +170,7 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) | |||
170 | { | 170 | { |
171 | int rc, alen, slen; | 171 | int rc, alen, slen; |
172 | const char *pct; | 172 | const char *pct; |
173 | char *endp, scope_id[13]; | 173 | char scope_id[13]; |
174 | struct sockaddr_in *s4 = (struct sockaddr_in *) dst; | 174 | struct sockaddr_in *s4 = (struct sockaddr_in *) dst; |
175 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; | 175 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; |
176 | 176 | ||
@@ -197,9 +197,9 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) | |||
197 | memcpy(scope_id, pct + 1, slen); | 197 | memcpy(scope_id, pct + 1, slen); |
198 | scope_id[slen] = '\0'; | 198 | scope_id[slen] = '\0'; |
199 | 199 | ||
200 | s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); | 200 | rc = strict_strtoul(scope_id, 0, |
201 | if (endp != scope_id + slen) | 201 | (unsigned long *)&s6->sin6_scope_id); |
202 | return 0; | 202 | rc = (rc == 0) ? 1 : 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | return rc; | 205 | return rc; |
@@ -836,7 +836,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode) | |||
836 | } | 836 | } |
837 | 837 | ||
838 | int | 838 | int |
839 | map_smb_to_linux_error(struct smb_hdr *smb, int logErr) | 839 | map_smb_to_linux_error(struct smb_hdr *smb, bool logErr) |
840 | { | 840 | { |
841 | unsigned int i; | 841 | unsigned int i; |
842 | int rc = -EIO; /* if transport error smb error may not be set */ | 842 | int rc = -EIO; /* if transport error smb error may not be set */ |
@@ -899,8 +899,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr) | |||
899 | } | 899 | } |
900 | /* else ERRHRD class errors or junk - return EIO */ | 900 | /* else ERRHRD class errors or junk - return EIO */ |
901 | 901 | ||
902 | cFYI(1, "Mapping smb error code %d to POSIX err %d", | 902 | cFYI(1, "Mapping smb error code 0x%x to POSIX err %d", |
903 | smberrcode, rc); | 903 | le32_to_cpu(smb->Status.CifsError), rc); |
904 | 904 | ||
905 | /* generic corrective action e.g. reconnect SMB session on | 905 | /* generic corrective action e.g. reconnect SMB session on |
906 | * ERRbaduid could be added */ | 906 | * ERRbaduid could be added */ |
@@ -916,14 +916,7 @@ unsigned int | |||
916 | smbCalcSize(struct smb_hdr *ptr) | 916 | smbCalcSize(struct smb_hdr *ptr) |
917 | { | 917 | { |
918 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + | 918 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + |
919 | 2 /* size of the bcc field */ + BCC(ptr)); | 919 | 2 /* size of the bcc field */ + get_bcc(ptr)); |
920 | } | ||
921 | |||
922 | unsigned int | ||
923 | smbCalcSize_LE(struct smb_hdr *ptr) | ||
924 | { | ||
925 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + | ||
926 | 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); | ||
927 | } | 920 | } |
928 | 921 | ||
929 | /* The following are taken from fs/ntfs/util.c */ | 922 | /* The following are taken from fs/ntfs/util.c */ |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 49c9a4e75319..5d52e4a3b1ed 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
@@ -61,6 +61,21 @@ | |||
61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | 61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 |
62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | 62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 |
63 | 63 | ||
64 | /* Define AV Pair Field IDs */ | ||
65 | enum av_field_type { | ||
66 | NTLMSSP_AV_EOL = 0, | ||
67 | NTLMSSP_AV_NB_COMPUTER_NAME, | ||
68 | NTLMSSP_AV_NB_DOMAIN_NAME, | ||
69 | NTLMSSP_AV_DNS_COMPUTER_NAME, | ||
70 | NTLMSSP_AV_DNS_DOMAIN_NAME, | ||
71 | NTLMSSP_AV_DNS_TREE_NAME, | ||
72 | NTLMSSP_AV_FLAGS, | ||
73 | NTLMSSP_AV_TIMESTAMP, | ||
74 | NTLMSSP_AV_RESTRICTION, | ||
75 | NTLMSSP_AV_TARGET_NAME, | ||
76 | NTLMSSP_AV_CHANNEL_BINDINGS | ||
77 | }; | ||
78 | |||
64 | /* Although typedefs are not commonly used for structure definitions */ | 79 | /* Although typedefs are not commonly used for structure definitions */ |
65 | /* in the Linux kernel, in this particular case they are useful */ | 80 | /* in the Linux kernel, in this particular case they are useful */ |
66 | /* to more closely match the standards document for NTLMSSP from */ | 81 | /* to more closely match the standards document for NTLMSSP from */ |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index d5e591fab475..6751e745bbc6 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -79,7 +79,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
79 | cFYI(1, "For %s", name->name); | 79 | cFYI(1, "For %s", name->name); |
80 | 80 | ||
81 | if (parent->d_op && parent->d_op->d_hash) | 81 | if (parent->d_op && parent->d_op->d_hash) |
82 | parent->d_op->d_hash(parent, name); | 82 | parent->d_op->d_hash(parent, parent->d_inode, name); |
83 | else | 83 | else |
84 | name->hash = full_name_hash(name->name, name->len); | 84 | name->hash = full_name_hash(name->name, name->len); |
85 | 85 | ||
@@ -102,11 +102,6 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
102 | return NULL; | 102 | return NULL; |
103 | } | 103 | } |
104 | 104 | ||
105 | if (CIFS_SB(sb)->tcon->nocase) | ||
106 | dentry->d_op = &cifs_ci_dentry_ops; | ||
107 | else | ||
108 | dentry->d_op = &cifs_dentry_ops; | ||
109 | |||
110 | alias = d_materialise_unique(dentry, inode); | 105 | alias = d_materialise_unique(dentry, inode); |
111 | if (alias != NULL) { | 106 | if (alias != NULL) { |
112 | dput(dentry); | 107 | dput(dentry); |
@@ -160,6 +155,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, | |||
160 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); | 155 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); |
161 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 156 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
162 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 157 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
158 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
163 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 159 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
164 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); | 160 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
165 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | 161 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
@@ -171,7 +167,7 @@ static void | |||
171 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, | 167 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, |
172 | struct cifs_sb_info *cifs_sb) | 168 | struct cifs_sb_info *cifs_sb) |
173 | { | 169 | { |
174 | int offset = cifs_sb->tcon->ses->server->timeAdj; | 170 | int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj; |
175 | 171 | ||
176 | memset(fattr, 0, sizeof(*fattr)); | 172 | memset(fattr, 0, sizeof(*fattr)); |
177 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, | 173 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, |
@@ -199,7 +195,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
199 | int len; | 195 | int len; |
200 | int oplock = 0; | 196 | int oplock = 0; |
201 | int rc; | 197 | int rc; |
202 | struct cifsTconInfo *ptcon = cifs_sb->tcon; | 198 | struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb); |
203 | char *tmpbuffer; | 199 | char *tmpbuffer; |
204 | 200 | ||
205 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, | 201 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, |
@@ -223,34 +219,38 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
223 | static int initiate_cifs_search(const int xid, struct file *file) | 219 | static int initiate_cifs_search(const int xid, struct file *file) |
224 | { | 220 | { |
225 | int rc = 0; | 221 | int rc = 0; |
226 | char *full_path; | 222 | char *full_path = NULL; |
227 | struct cifsFileInfo *cifsFile; | 223 | struct cifsFileInfo *cifsFile; |
228 | struct cifs_sb_info *cifs_sb; | 224 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
229 | struct cifsTconInfo *pTcon; | 225 | struct tcon_link *tlink = NULL; |
226 | struct cifs_tcon *pTcon; | ||
230 | 227 | ||
231 | if (file->private_data == NULL) { | 228 | if (file->private_data == NULL) { |
232 | file->private_data = | 229 | tlink = cifs_sb_tlink(cifs_sb); |
233 | kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 230 | if (IS_ERR(tlink)) |
231 | return PTR_ERR(tlink); | ||
232 | |||
233 | cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
234 | if (cifsFile == NULL) { | ||
235 | rc = -ENOMEM; | ||
236 | goto error_exit; | ||
237 | } | ||
238 | file->private_data = cifsFile; | ||
239 | cifsFile->tlink = cifs_get_tlink(tlink); | ||
240 | pTcon = tlink_tcon(tlink); | ||
241 | } else { | ||
242 | cifsFile = file->private_data; | ||
243 | pTcon = tlink_tcon(cifsFile->tlink); | ||
234 | } | 244 | } |
235 | 245 | ||
236 | if (file->private_data == NULL) | ||
237 | return -ENOMEM; | ||
238 | cifsFile = file->private_data; | ||
239 | cifsFile->invalidHandle = true; | 246 | cifsFile->invalidHandle = true; |
240 | cifsFile->srch_inf.endOfSearch = false; | 247 | cifsFile->srch_inf.endOfSearch = false; |
241 | 248 | ||
242 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
243 | if (cifs_sb == NULL) | ||
244 | return -EINVAL; | ||
245 | |||
246 | pTcon = cifs_sb->tcon; | ||
247 | if (pTcon == NULL) | ||
248 | return -EINVAL; | ||
249 | |||
250 | full_path = build_path_from_dentry(file->f_path.dentry); | 249 | full_path = build_path_from_dentry(file->f_path.dentry); |
251 | 250 | if (full_path == NULL) { | |
252 | if (full_path == NULL) | 251 | rc = -ENOMEM; |
253 | return -ENOMEM; | 252 | goto error_exit; |
253 | } | ||
254 | 254 | ||
255 | cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); | 255 | cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos); |
256 | 256 | ||
@@ -283,7 +283,9 @@ ffirst_retry: | |||
283 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | 283 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
284 | goto ffirst_retry; | 284 | goto ffirst_retry; |
285 | } | 285 | } |
286 | error_exit: | ||
286 | kfree(full_path); | 287 | kfree(full_path); |
288 | cifs_put_tlink(tlink); | ||
287 | return rc; | 289 | return rc; |
288 | } | 290 | } |
289 | 291 | ||
@@ -494,7 +496,7 @@ static int cifs_save_resume_key(const char *current_entry, | |||
494 | assume that they are located in the findfirst return buffer.*/ | 496 | assume that they are located in the findfirst return buffer.*/ |
495 | /* We start counting in the buffer with entry 2 and increment for every | 497 | /* We start counting in the buffer with entry 2 and increment for every |
496 | entry (do not increment for . or .. entry) */ | 498 | entry (do not increment for . or .. entry) */ |
497 | static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | 499 | static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, |
498 | struct file *file, char **ppCurrentEntry, int *num_to_ret) | 500 | struct file *file, char **ppCurrentEntry, int *num_to_ret) |
499 | { | 501 | { |
500 | int rc = 0; | 502 | int rc = 0; |
@@ -525,14 +527,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
525 | (index_to_find < first_entry_in_buffer)) { | 527 | (index_to_find < first_entry_in_buffer)) { |
526 | /* close and restart search */ | 528 | /* close and restart search */ |
527 | cFYI(1, "search backing up - close and restart search"); | 529 | cFYI(1, "search backing up - close and restart search"); |
528 | write_lock(&GlobalSMBSeslock); | 530 | spin_lock(&cifs_file_list_lock); |
529 | if (!cifsFile->srch_inf.endOfSearch && | 531 | if (!cifsFile->srch_inf.endOfSearch && |
530 | !cifsFile->invalidHandle) { | 532 | !cifsFile->invalidHandle) { |
531 | cifsFile->invalidHandle = true; | 533 | cifsFile->invalidHandle = true; |
532 | write_unlock(&GlobalSMBSeslock); | 534 | spin_unlock(&cifs_file_list_lock); |
533 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 535 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
534 | } else | 536 | } else |
535 | write_unlock(&GlobalSMBSeslock); | 537 | spin_unlock(&cifs_file_list_lock); |
536 | if (cifsFile->srch_inf.ntwrk_buf_start) { | 538 | if (cifsFile->srch_inf.ntwrk_buf_start) { |
537 | cFYI(1, "freeing SMB ff cache buf on search rewind"); | 539 | cFYI(1, "freeing SMB ff cache buf on search rewind"); |
538 | if (cifsFile->srch_inf.smallBuf) | 540 | if (cifsFile->srch_inf.smallBuf) |
@@ -738,24 +740,21 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
738 | cifs_autodisable_serverino(cifs_sb); | 740 | cifs_autodisable_serverino(cifs_sb); |
739 | } | 741 | } |
740 | 742 | ||
743 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) && | ||
744 | CIFSCouldBeMFSymlink(&fattr)) | ||
745 | /* | ||
746 | * trying to get the type and mode can be slow, | ||
747 | * so just call those regular files for now, and mark | ||
748 | * for reval | ||
749 | */ | ||
750 | fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; | ||
751 | |||
741 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | 752 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); |
742 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); | 753 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); |
743 | 754 | ||
744 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, | 755 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, |
745 | ino, fattr.cf_dtype); | 756 | ino, fattr.cf_dtype); |
746 | 757 | ||
747 | /* | ||
748 | * we can not return filldir errors to the caller since they are | ||
749 | * "normal" when the stat blocksize is too small - we return remapped | ||
750 | * error instead | ||
751 | * | ||
752 | * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above | ||
753 | * case already. Why should we be clobbering other errors from it? | ||
754 | */ | ||
755 | if (rc) { | ||
756 | cFYI(1, "filldir rc = %d", rc); | ||
757 | rc = -EOVERFLOW; | ||
758 | } | ||
759 | dput(tmp_dentry); | 758 | dput(tmp_dentry); |
760 | return rc; | 759 | return rc; |
761 | } | 760 | } |
@@ -765,8 +764,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
765 | { | 764 | { |
766 | int rc = 0; | 765 | int rc = 0; |
767 | int xid, i; | 766 | int xid, i; |
768 | struct cifs_sb_info *cifs_sb; | 767 | struct cifs_tcon *pTcon; |
769 | struct cifsTconInfo *pTcon; | ||
770 | struct cifsFileInfo *cifsFile = NULL; | 768 | struct cifsFileInfo *cifsFile = NULL; |
771 | char *current_entry; | 769 | char *current_entry; |
772 | int num_to_fill = 0; | 770 | int num_to_fill = 0; |
@@ -776,10 +774,16 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
776 | 774 | ||
777 | xid = GetXid(); | 775 | xid = GetXid(); |
778 | 776 | ||
779 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 777 | /* |
780 | pTcon = cifs_sb->tcon; | 778 | * Ensure FindFirst doesn't fail before doing filldir() for '.' and |
781 | if (pTcon == NULL) | 779 | * '..'. Otherwise we won't be able to notify VFS in case of failure. |
782 | return -EINVAL; | 780 | */ |
781 | if (file->private_data == NULL) { | ||
782 | rc = initiate_cifs_search(xid, file); | ||
783 | cFYI(1, "initiate cifs search rc %d", rc); | ||
784 | if (rc) | ||
785 | goto rddir2_exit; | ||
786 | } | ||
783 | 787 | ||
784 | switch ((int) file->f_pos) { | 788 | switch ((int) file->f_pos) { |
785 | case 0: | 789 | case 0: |
@@ -805,14 +809,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
805 | if after then keep searching till find it */ | 809 | if after then keep searching till find it */ |
806 | 810 | ||
807 | if (file->private_data == NULL) { | 811 | if (file->private_data == NULL) { |
808 | rc = initiate_cifs_search(xid, file); | ||
809 | cFYI(1, "initiate cifs search rc %d", rc); | ||
810 | if (rc) { | ||
811 | FreeXid(xid); | ||
812 | return rc; | ||
813 | } | ||
814 | } | ||
815 | if (file->private_data == NULL) { | ||
816 | rc = -EINVAL; | 812 | rc = -EINVAL; |
817 | FreeXid(xid); | 813 | FreeXid(xid); |
818 | return rc; | 814 | return rc; |
@@ -829,6 +825,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
829 | CIFSFindClose(xid, pTcon, cifsFile->netfid); | 825 | CIFSFindClose(xid, pTcon, cifsFile->netfid); |
830 | } */ | 826 | } */ |
831 | 827 | ||
828 | pTcon = tlink_tcon(cifsFile->tlink); | ||
832 | rc = find_cifs_entry(xid, pTcon, file, | 829 | rc = find_cifs_entry(xid, pTcon, file, |
833 | ¤t_entry, &num_to_fill); | 830 | ¤t_entry, &num_to_fill); |
834 | if (rc) { | 831 | if (rc) { |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 0a57cb7db5dd..d3e619692ee0 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -32,21 +32,18 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include "cifs_spnego.h" | 33 | #include "cifs_spnego.h" |
34 | 34 | ||
35 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | ||
36 | unsigned char *p24); | ||
37 | |||
38 | /* | 35 | /* |
39 | * Checks if this is the first smb session to be reconnected after | 36 | * Checks if this is the first smb session to be reconnected after |
40 | * the socket has been reestablished (so we know whether to use vc 0). | 37 | * the socket has been reestablished (so we know whether to use vc 0). |
41 | * Called while holding the cifs_tcp_ses_lock, so do not block | 38 | * Called while holding the cifs_tcp_ses_lock, so do not block |
42 | */ | 39 | */ |
43 | static bool is_first_ses_reconnect(struct cifsSesInfo *ses) | 40 | static bool is_first_ses_reconnect(struct cifs_ses *ses) |
44 | { | 41 | { |
45 | struct list_head *tmp; | 42 | struct list_head *tmp; |
46 | struct cifsSesInfo *tmp_ses; | 43 | struct cifs_ses *tmp_ses; |
47 | 44 | ||
48 | list_for_each(tmp, &ses->server->smb_ses_list) { | 45 | list_for_each(tmp, &ses->server->smb_ses_list) { |
49 | tmp_ses = list_entry(tmp, struct cifsSesInfo, | 46 | tmp_ses = list_entry(tmp, struct cifs_ses, |
50 | smb_ses_list); | 47 | smb_ses_list); |
51 | if (tmp_ses->need_reconnect == false) | 48 | if (tmp_ses->need_reconnect == false) |
52 | return false; | 49 | return false; |
@@ -64,11 +61,11 @@ static bool is_first_ses_reconnect(struct cifsSesInfo *ses) | |||
64 | * any vc but zero (some servers reset the connection on vcnum zero) | 61 | * any vc but zero (some servers reset the connection on vcnum zero) |
65 | * | 62 | * |
66 | */ | 63 | */ |
67 | static __le16 get_next_vcnum(struct cifsSesInfo *ses) | 64 | static __le16 get_next_vcnum(struct cifs_ses *ses) |
68 | { | 65 | { |
69 | __u16 vcnum = 0; | 66 | __u16 vcnum = 0; |
70 | struct list_head *tmp; | 67 | struct list_head *tmp; |
71 | struct cifsSesInfo *tmp_ses; | 68 | struct cifs_ses *tmp_ses; |
72 | __u16 max_vcs = ses->server->max_vcs; | 69 | __u16 max_vcs = ses->server->max_vcs; |
73 | __u16 i; | 70 | __u16 i; |
74 | int free_vc_found = 0; | 71 | int free_vc_found = 0; |
@@ -80,7 +77,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) | |||
80 | if (max_vcs < 2) | 77 | if (max_vcs < 2) |
81 | max_vcs = 0xFFFF; | 78 | max_vcs = 0xFFFF; |
82 | 79 | ||
83 | write_lock(&cifs_tcp_ses_lock); | 80 | spin_lock(&cifs_tcp_ses_lock); |
84 | if ((ses->need_reconnect) && is_first_ses_reconnect(ses)) | 81 | if ((ses->need_reconnect) && is_first_ses_reconnect(ses)) |
85 | goto get_vc_num_exit; /* vcnum will be zero */ | 82 | goto get_vc_num_exit; /* vcnum will be zero */ |
86 | for (i = ses->server->srv_count - 1; i < max_vcs; i++) { | 83 | for (i = ses->server->srv_count - 1; i < max_vcs; i++) { |
@@ -90,7 +87,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) | |||
90 | free_vc_found = 1; | 87 | free_vc_found = 1; |
91 | 88 | ||
92 | list_for_each(tmp, &ses->server->smb_ses_list) { | 89 | list_for_each(tmp, &ses->server->smb_ses_list) { |
93 | tmp_ses = list_entry(tmp, struct cifsSesInfo, | 90 | tmp_ses = list_entry(tmp, struct cifs_ses, |
94 | smb_ses_list); | 91 | smb_ses_list); |
95 | if (tmp_ses->vcnum == i) { | 92 | if (tmp_ses->vcnum == i) { |
96 | free_vc_found = 0; | 93 | free_vc_found = 0; |
@@ -112,12 +109,12 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) | |||
112 | vcnum = i; | 109 | vcnum = i; |
113 | ses->vcnum = vcnum; | 110 | ses->vcnum = vcnum; |
114 | get_vc_num_exit: | 111 | get_vc_num_exit: |
115 | write_unlock(&cifs_tcp_ses_lock); | 112 | spin_unlock(&cifs_tcp_ses_lock); |
116 | 113 | ||
117 | return cpu_to_le16(vcnum); | 114 | return cpu_to_le16(vcnum); |
118 | } | 115 | } |
119 | 116 | ||
120 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | 117 | static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB) |
121 | { | 118 | { |
122 | __u32 capabilities = 0; | 119 | __u32 capabilities = 0; |
123 | 120 | ||
@@ -139,7 +136,7 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | |||
139 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | 136 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | |
140 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | 137 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; |
141 | 138 | ||
142 | if (ses->server->secMode & | 139 | if (ses->server->sec_mode & |
143 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 140 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
144 | pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 141 | pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
145 | 142 | ||
@@ -184,7 +181,7 @@ unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) | |||
184 | *pbcc_area = bcc_ptr; | 181 | *pbcc_area = bcc_ptr; |
185 | } | 182 | } |
186 | 183 | ||
187 | static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses, | 184 | static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, |
188 | const struct nls_table *nls_cp) | 185 | const struct nls_table *nls_cp) |
189 | { | 186 | { |
190 | char *bcc_ptr = *pbcc_area; | 187 | char *bcc_ptr = *pbcc_area; |
@@ -207,7 +204,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses, | |||
207 | } | 204 | } |
208 | 205 | ||
209 | 206 | ||
210 | static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | 207 | static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, |
211 | const struct nls_table *nls_cp) | 208 | const struct nls_table *nls_cp) |
212 | { | 209 | { |
213 | char *bcc_ptr = *pbcc_area; | 210 | char *bcc_ptr = *pbcc_area; |
@@ -222,12 +219,12 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
222 | bcc_ptr++; | 219 | bcc_ptr++; |
223 | } */ | 220 | } */ |
224 | /* copy user */ | 221 | /* copy user */ |
225 | if (ses->userName == NULL) { | 222 | if (ses->user_name == NULL) { |
226 | /* null user mount */ | 223 | /* null user mount */ |
227 | *bcc_ptr = 0; | 224 | *bcc_ptr = 0; |
228 | *(bcc_ptr+1) = 0; | 225 | *(bcc_ptr+1) = 0; |
229 | } else { | 226 | } else { |
230 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, | 227 | bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->user_name, |
231 | MAX_USERNAME_SIZE, nls_cp); | 228 | MAX_USERNAME_SIZE, nls_cp); |
232 | } | 229 | } |
233 | bcc_ptr += 2 * bytes_ret; | 230 | bcc_ptr += 2 * bytes_ret; |
@@ -239,7 +236,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
239 | *pbcc_area = bcc_ptr; | 236 | *pbcc_area = bcc_ptr; |
240 | } | 237 | } |
241 | 238 | ||
242 | static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | 239 | static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, |
243 | const struct nls_table *nls_cp) | 240 | const struct nls_table *nls_cp) |
244 | { | 241 | { |
245 | char *bcc_ptr = *pbcc_area; | 242 | char *bcc_ptr = *pbcc_area; |
@@ -247,12 +244,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
247 | /* copy user */ | 244 | /* copy user */ |
248 | /* BB what about null user mounts - check that we do this BB */ | 245 | /* BB what about null user mounts - check that we do this BB */ |
249 | /* copy user */ | 246 | /* copy user */ |
250 | if (ses->userName == NULL) { | 247 | if (ses->user_name != NULL) |
251 | /* BB what about null user mounts - check that we do this BB */ | 248 | strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE); |
252 | } else { | 249 | /* else null user mount */ |
253 | strncpy(bcc_ptr, ses->userName, MAX_USERNAME_SIZE); | 250 | |
254 | } | 251 | bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); |
255 | bcc_ptr += strnlen(ses->userName, MAX_USERNAME_SIZE); | ||
256 | *bcc_ptr = 0; | 252 | *bcc_ptr = 0; |
257 | bcc_ptr++; /* account for null termination */ | 253 | bcc_ptr++; /* account for null termination */ |
258 | 254 | ||
@@ -280,7 +276,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
280 | } | 276 | } |
281 | 277 | ||
282 | static void | 278 | static void |
283 | decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, | 279 | decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses, |
284 | const struct nls_table *nls_cp) | 280 | const struct nls_table *nls_cp) |
285 | { | 281 | { |
286 | int len; | 282 | int len; |
@@ -288,19 +284,6 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, | |||
288 | 284 | ||
289 | cFYI(1, "bleft %d", bleft); | 285 | cFYI(1, "bleft %d", bleft); |
290 | 286 | ||
291 | /* | ||
292 | * Windows servers do not always double null terminate their final | ||
293 | * Unicode string. Check to see if there are an uneven number of bytes | ||
294 | * left. If so, then add an extra NULL pad byte to the end of the | ||
295 | * response. | ||
296 | * | ||
297 | * See section 2.7.2 in "Implementing CIFS" for details | ||
298 | */ | ||
299 | if (bleft % 2) { | ||
300 | data[bleft] = 0; | ||
301 | ++bleft; | ||
302 | } | ||
303 | |||
304 | kfree(ses->serverOS); | 287 | kfree(ses->serverOS); |
305 | ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); | 288 | ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
306 | cFYI(1, "serverOS=%s", ses->serverOS); | 289 | cFYI(1, "serverOS=%s", ses->serverOS); |
@@ -326,8 +309,8 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, | |||
326 | return; | 309 | return; |
327 | } | 310 | } |
328 | 311 | ||
329 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, | 312 | static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft, |
330 | struct cifsSesInfo *ses, | 313 | struct cifs_ses *ses, |
331 | const struct nls_table *nls_cp) | 314 | const struct nls_table *nls_cp) |
332 | { | 315 | { |
333 | int rc = 0; | 316 | int rc = 0; |
@@ -381,8 +364,11 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
381 | } | 364 | } |
382 | 365 | ||
383 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | 366 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, |
384 | struct cifsSesInfo *ses) | 367 | struct cifs_ses *ses) |
385 | { | 368 | { |
369 | unsigned int tioffset; /* challenge message target info area */ | ||
370 | unsigned int tilen; /* challenge message target info area length */ | ||
371 | |||
386 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; | 372 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; |
387 | 373 | ||
388 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { | 374 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { |
@@ -399,40 +385,53 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
399 | return -EINVAL; | 385 | return -EINVAL; |
400 | } | 386 | } |
401 | 387 | ||
402 | memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); | 388 | memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); |
403 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ | 389 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ |
404 | /* In particular we can examine sign flags */ | 390 | /* In particular we can examine sign flags */ |
405 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | 391 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then |
406 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | 392 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ |
393 | ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags); | ||
394 | tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset); | ||
395 | tilen = le16_to_cpu(pblob->TargetInfoArray.Length); | ||
396 | if (tilen) { | ||
397 | ses->auth_key.response = kmalloc(tilen, GFP_KERNEL); | ||
398 | if (!ses->auth_key.response) { | ||
399 | cERROR(1, "Challenge target info allocation failure"); | ||
400 | return -ENOMEM; | ||
401 | } | ||
402 | memcpy(ses->auth_key.response, bcc_ptr + tioffset, tilen); | ||
403 | ses->auth_key.len = tilen; | ||
404 | } | ||
407 | 405 | ||
408 | return 0; | 406 | return 0; |
409 | } | 407 | } |
410 | 408 | ||
411 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
412 | /* BB Move to ntlmssp.c eventually */ | 409 | /* BB Move to ntlmssp.c eventually */ |
413 | 410 | ||
414 | /* We do not malloc the blob, it is passed in pbuffer, because | 411 | /* We do not malloc the blob, it is passed in pbuffer, because |
415 | it is fixed size, and small, making this approach cleaner */ | 412 | it is fixed size, and small, making this approach cleaner */ |
416 | static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | 413 | static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, |
417 | struct cifsSesInfo *ses) | 414 | struct cifs_ses *ses) |
418 | { | 415 | { |
419 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | 416 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; |
420 | __u32 flags; | 417 | __u32 flags; |
421 | 418 | ||
419 | memset(pbuffer, 0, sizeof(NEGOTIATE_MESSAGE)); | ||
422 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 420 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
423 | sec_blob->MessageType = NtLmNegotiate; | 421 | sec_blob->MessageType = NtLmNegotiate; |
424 | 422 | ||
425 | /* BB is NTLMV2 session security format easier to use here? */ | 423 | /* BB is NTLMV2 session security format easier to use here? */ |
426 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | 424 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | |
427 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 425 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
428 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | 426 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
429 | if (ses->server->secMode & | 427 | if (ses->server->sec_mode & |
430 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 428 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
431 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 429 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
432 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | 430 | if (!ses->server->session_estab) |
433 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | 431 | flags |= NTLMSSP_NEGOTIATE_KEY_XCH; |
432 | } | ||
434 | 433 | ||
435 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 434 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
436 | 435 | ||
437 | sec_blob->WorkstationName.BufferOffset = 0; | 436 | sec_blob->WorkstationName.BufferOffset = 0; |
438 | sec_blob->WorkstationName.Length = 0; | 437 | sec_blob->WorkstationName.Length = 0; |
@@ -448,13 +447,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
448 | maximum possible size is fixed and small, making this approach cleaner. | 447 | maximum possible size is fixed and small, making this approach cleaner. |
449 | This function returns the length of the data in the blob */ | 448 | This function returns the length of the data in the blob */ |
450 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | 449 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, |
451 | struct cifsSesInfo *ses, | 450 | u16 *buflen, |
452 | const struct nls_table *nls_cp, bool first) | 451 | struct cifs_ses *ses, |
452 | const struct nls_table *nls_cp) | ||
453 | { | 453 | { |
454 | int rc; | ||
454 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | 455 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; |
455 | __u32 flags; | 456 | __u32 flags; |
456 | unsigned char *tmp; | 457 | unsigned char *tmp; |
457 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
458 | 458 | ||
459 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 459 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
460 | sec_blob->MessageType = NtLmAuthenticate; | 460 | sec_blob->MessageType = NtLmAuthenticate; |
@@ -462,34 +462,36 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
462 | flags = NTLMSSP_NEGOTIATE_56 | | 462 | flags = NTLMSSP_NEGOTIATE_56 | |
463 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | 463 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | |
464 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 464 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
465 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | 465 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
466 | if (ses->server->secMode & | 466 | if (ses->server->sec_mode & |
467 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 467 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
468 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 468 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
469 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | 469 | if (!ses->server->session_estab) |
470 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | 470 | flags |= NTLMSSP_NEGOTIATE_KEY_XCH; |
471 | } | ||
471 | 472 | ||
472 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | 473 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); |
473 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 474 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
474 | 475 | ||
475 | sec_blob->LmChallengeResponse.BufferOffset = | 476 | sec_blob->LmChallengeResponse.BufferOffset = |
476 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); | 477 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); |
477 | sec_blob->LmChallengeResponse.Length = 0; | 478 | sec_blob->LmChallengeResponse.Length = 0; |
478 | sec_blob->LmChallengeResponse.MaximumLength = 0; | 479 | sec_blob->LmChallengeResponse.MaximumLength = 0; |
479 | 480 | ||
480 | /* calculate session key, BB what about adding similar ntlmv2 path? */ | ||
481 | SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); | ||
482 | if (first) | ||
483 | cifs_calculate_mac_key(&ses->server->mac_signing_key, | ||
484 | ntlm_session_key, ses->password); | ||
485 | |||
486 | memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
487 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | 481 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); |
488 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 482 | rc = setup_ntlmv2_rsp(ses, nls_cp); |
489 | sec_blob->NtChallengeResponse.MaximumLength = | 483 | if (rc) { |
490 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 484 | cERROR(1, "Error %d during NTLMSSP authentication", rc); |
485 | goto setup_ntlmv2_ret; | ||
486 | } | ||
487 | memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
488 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
489 | tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; | ||
491 | 490 | ||
492 | tmp += CIFS_SESS_KEY_SIZE; | 491 | sec_blob->NtChallengeResponse.Length = |
492 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
493 | sec_blob->NtChallengeResponse.MaximumLength = | ||
494 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
493 | 495 | ||
494 | if (ses->domainName == NULL) { | 496 | if (ses->domainName == NULL) { |
495 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 497 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
@@ -501,24 +503,22 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
501 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | 503 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, |
502 | MAX_USERNAME_SIZE, nls_cp); | 504 | MAX_USERNAME_SIZE, nls_cp); |
503 | len *= 2; /* unicode is 2 bytes each */ | 505 | len *= 2; /* unicode is 2 bytes each */ |
504 | len += 2; /* trailing null */ | ||
505 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 506 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
506 | sec_blob->DomainName.Length = cpu_to_le16(len); | 507 | sec_blob->DomainName.Length = cpu_to_le16(len); |
507 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | 508 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); |
508 | tmp += len; | 509 | tmp += len; |
509 | } | 510 | } |
510 | 511 | ||
511 | if (ses->userName == NULL) { | 512 | if (ses->user_name == NULL) { |
512 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 513 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
513 | sec_blob->UserName.Length = 0; | 514 | sec_blob->UserName.Length = 0; |
514 | sec_blob->UserName.MaximumLength = 0; | 515 | sec_blob->UserName.MaximumLength = 0; |
515 | tmp += 2; | 516 | tmp += 2; |
516 | } else { | 517 | } else { |
517 | int len; | 518 | int len; |
518 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | 519 | len = cifs_strtoUCS((__le16 *)tmp, ses->user_name, |
519 | MAX_USERNAME_SIZE, nls_cp); | 520 | MAX_USERNAME_SIZE, nls_cp); |
520 | len *= 2; /* unicode is 2 bytes each */ | 521 | len *= 2; /* unicode is 2 bytes each */ |
521 | len += 2; /* trailing null */ | ||
522 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | 522 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); |
523 | sec_blob->UserName.Length = cpu_to_le16(len); | 523 | sec_blob->UserName.Length = cpu_to_le16(len); |
524 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | 524 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); |
@@ -530,38 +530,28 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
530 | sec_blob->WorkstationName.MaximumLength = 0; | 530 | sec_blob->WorkstationName.MaximumLength = 0; |
531 | tmp += 2; | 531 | tmp += 2; |
532 | 532 | ||
533 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 533 | if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) || |
534 | sec_blob->SessionKey.Length = 0; | 534 | (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) |
535 | sec_blob->SessionKey.MaximumLength = 0; | 535 | && !calc_seckey(ses)) { |
536 | return tmp - pbuffer; | 536 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
537 | } | 537 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); |
538 | 538 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | |
539 | 539 | sec_blob->SessionKey.MaximumLength = | |
540 | static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | 540 | cpu_to_le16(CIFS_CPHTXT_SIZE); |
541 | struct cifsSesInfo *ses) | 541 | tmp += CIFS_CPHTXT_SIZE; |
542 | { | 542 | } else { |
543 | build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses); | 543 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); |
544 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | 544 | sec_blob->SessionKey.Length = 0; |
545 | 545 | sec_blob->SessionKey.MaximumLength = 0; | |
546 | return; | 546 | } |
547 | } | ||
548 | |||
549 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, | ||
550 | struct cifsSesInfo *ses, | ||
551 | const struct nls_table *nls, bool first_time) | ||
552 | { | ||
553 | int bloblen; | ||
554 | |||
555 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, | ||
556 | first_time); | ||
557 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
558 | 547 | ||
559 | return bloblen; | 548 | setup_ntlmv2_ret: |
549 | *buflen = tmp - pbuffer; | ||
550 | return rc; | ||
560 | } | 551 | } |
561 | #endif | ||
562 | 552 | ||
563 | int | 553 | int |
564 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 554 | CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses, |
565 | const struct nls_table *nls_cp) | 555 | const struct nls_table *nls_cp) |
566 | { | 556 | { |
567 | int rc = 0; | 557 | int rc = 0; |
@@ -571,26 +561,30 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
571 | char *str_area; | 561 | char *str_area; |
572 | SESSION_SETUP_ANDX *pSMB; | 562 | SESSION_SETUP_ANDX *pSMB; |
573 | __u32 capabilities; | 563 | __u32 capabilities; |
574 | int count; | 564 | __u16 count; |
575 | int resp_buf_type; | 565 | int resp_buf_type; |
576 | struct kvec iov[3]; | 566 | struct kvec iov[3]; |
577 | enum securityEnum type; | 567 | enum securityEnum type; |
578 | __u16 action; | 568 | __u16 action, bytes_remaining; |
579 | int bytes_remaining; | ||
580 | struct key *spnego_key = NULL; | 569 | struct key *spnego_key = NULL; |
581 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | 570 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
582 | bool first_time; | 571 | u16 blob_len; |
572 | char *ntlmsspblob = NULL; | ||
583 | 573 | ||
584 | if (ses == NULL) | 574 | if (ses == NULL) |
585 | return -EINVAL; | 575 | return -EINVAL; |
586 | 576 | ||
587 | read_lock(&cifs_tcp_ses_lock); | ||
588 | first_time = is_first_ses_reconnect(ses); | ||
589 | read_unlock(&cifs_tcp_ses_lock); | ||
590 | |||
591 | type = ses->server->secType; | 577 | type = ses->server->secType; |
592 | |||
593 | cFYI(1, "sess setup type %d", type); | 578 | cFYI(1, "sess setup type %d", type); |
579 | if (type == RawNTLMSSP) { | ||
580 | /* if memory allocation is successful, caller of this function | ||
581 | * frees it. | ||
582 | */ | ||
583 | ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL); | ||
584 | if (!ses->ntlmssp) | ||
585 | return -ENOMEM; | ||
586 | } | ||
587 | |||
594 | ssetup_ntlmssp_authenticate: | 588 | ssetup_ntlmssp_authenticate: |
595 | if (phase == NtLmChallenge) | 589 | if (phase == NtLmChallenge) |
596 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | 590 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ |
@@ -627,7 +621,7 @@ ssetup_ntlmssp_authenticate: | |||
627 | and rest of bcc area. This allows us to avoid | 621 | and rest of bcc area. This allows us to avoid |
628 | a large buffer 17K allocation */ | 622 | a large buffer 17K allocation */ |
629 | iov[0].iov_base = (char *)pSMB; | 623 | iov[0].iov_base = (char *)pSMB; |
630 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | 624 | iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4; |
631 | 625 | ||
632 | /* setting this here allows the code at the end of the function | 626 | /* setting this here allows the code at the end of the function |
633 | to free the request buffer if there's an error */ | 627 | to free the request buffer if there's an error */ |
@@ -648,23 +642,27 @@ ssetup_ntlmssp_authenticate: | |||
648 | 642 | ||
649 | if (type == LANMAN) { | 643 | if (type == LANMAN) { |
650 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 644 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
651 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; | 645 | char lnm_session_key[CIFS_AUTH_RESP_SIZE]; |
652 | 646 | ||
653 | pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; | 647 | pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; |
654 | 648 | ||
655 | /* no capabilities flags in old lanman negotiation */ | 649 | /* no capabilities flags in old lanman negotiation */ |
656 | 650 | ||
657 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 651 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
658 | /* BB calculate hash with password */ | 652 | |
659 | /* and copy into bcc */ | 653 | /* Calculate hash with password and copy into bcc_ptr. |
654 | * Encryption Key (stored as in cryptkey) gets used if the | ||
655 | * security mode bit in Negottiate Protocol response states | ||
656 | * to use challenge/response method (i.e. Password bit is 1). | ||
657 | */ | ||
660 | 658 | ||
661 | calc_lanman_hash(ses->password, ses->server->cryptKey, | 659 | rc = calc_lanman_hash(ses->password, ses->server->cryptkey, |
662 | ses->server->secMode & SECMODE_PW_ENCRYPT ? | 660 | ses->server->sec_mode & SECMODE_PW_ENCRYPT ? |
663 | true : false, lnm_session_key); | 661 | true : false, lnm_session_key); |
664 | 662 | ||
665 | ses->flags |= CIFS_SES_LANMAN; | 663 | ses->flags |= CIFS_SES_LANMAN; |
666 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); | 664 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE); |
667 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 665 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
668 | 666 | ||
669 | /* can not sign if LANMAN negotiated so no need | 667 | /* can not sign if LANMAN negotiated so no need |
670 | to calculate signing key? but what if server | 668 | to calculate signing key? but what if server |
@@ -676,28 +674,27 @@ ssetup_ntlmssp_authenticate: | |||
676 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 674 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
677 | #endif | 675 | #endif |
678 | } else if (type == NTLM) { | 676 | } else if (type == NTLM) { |
679 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
680 | |||
681 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 677 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
682 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | 678 | pSMB->req_no_secext.CaseInsensitivePasswordLength = |
683 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 679 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
684 | pSMB->req_no_secext.CaseSensitivePasswordLength = | 680 | pSMB->req_no_secext.CaseSensitivePasswordLength = |
685 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | 681 | cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
686 | 682 | ||
687 | /* calculate session key */ | 683 | /* calculate ntlm response and session key */ |
688 | SMBNTencrypt(ses->password, ses->server->cryptKey, | 684 | rc = setup_ntlm_response(ses); |
689 | ntlm_session_key); | 685 | if (rc) { |
690 | 686 | cERROR(1, "Error %d during NTLM authentication", rc); | |
691 | if (first_time) /* should this be moved into common code | 687 | goto ssetup_exit; |
692 | with similar ntlmv2 path? */ | 688 | } |
693 | cifs_calculate_mac_key(&ses->server->mac_signing_key, | 689 | |
694 | ntlm_session_key, ses->password); | 690 | /* copy ntlm response */ |
695 | /* copy session key */ | 691 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
696 | 692 | CIFS_AUTH_RESP_SIZE); | |
697 | memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); | 693 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
698 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 694 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, |
699 | memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); | 695 | CIFS_AUTH_RESP_SIZE); |
700 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 696 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
697 | |||
701 | if (ses->capabilities & CAP_UNICODE) { | 698 | if (ses->capabilities & CAP_UNICODE) { |
702 | /* unicode strings must be word aligned */ | 699 | /* unicode strings must be word aligned */ |
703 | if (iov[0].iov_len % 2) { | 700 | if (iov[0].iov_len % 2) { |
@@ -708,33 +705,27 @@ ssetup_ntlmssp_authenticate: | |||
708 | } else | 705 | } else |
709 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 706 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
710 | } else if (type == NTLMv2) { | 707 | } else if (type == NTLMv2) { |
711 | char *v2_sess_key = | ||
712 | kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); | ||
713 | |||
714 | /* BB FIXME change all users of v2_sess_key to | ||
715 | struct ntlmv2_resp */ | ||
716 | |||
717 | if (v2_sess_key == NULL) { | ||
718 | rc = -ENOMEM; | ||
719 | goto ssetup_exit; | ||
720 | } | ||
721 | |||
722 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 708 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
723 | 709 | ||
724 | /* LM2 password would be here if we supported it */ | 710 | /* LM2 password would be here if we supported it */ |
725 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; | 711 | pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; |
726 | /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ | ||
727 | 712 | ||
713 | /* calculate nlmv2 response and session key */ | ||
714 | rc = setup_ntlmv2_rsp(ses, nls_cp); | ||
715 | if (rc) { | ||
716 | cERROR(1, "Error %d during NTLMv2 authentication", rc); | ||
717 | goto ssetup_exit; | ||
718 | } | ||
719 | memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, | ||
720 | ses->auth_key.len - CIFS_SESS_KEY_SIZE); | ||
721 | bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE; | ||
722 | |||
723 | /* set case sensitive password length after tilen may get | ||
724 | * assigned, tilen is 0 otherwise. | ||
725 | */ | ||
728 | pSMB->req_no_secext.CaseSensitivePasswordLength = | 726 | pSMB->req_no_secext.CaseSensitivePasswordLength = |
729 | cpu_to_le16(sizeof(struct ntlmv2_resp)); | 727 | cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); |
730 | 728 | ||
731 | /* calculate session key */ | ||
732 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | ||
733 | /* FIXME: calculate MAC key */ | ||
734 | memcpy(bcc_ptr, (char *)v2_sess_key, | ||
735 | sizeof(struct ntlmv2_resp)); | ||
736 | bcc_ptr += sizeof(struct ntlmv2_resp); | ||
737 | kfree(v2_sess_key); | ||
738 | if (ses->capabilities & CAP_UNICODE) { | 729 | if (ses->capabilities & CAP_UNICODE) { |
739 | if (iov[0].iov_len % 2) { | 730 | if (iov[0].iov_len % 2) { |
740 | *bcc_ptr = 0; | 731 | *bcc_ptr = 0; |
@@ -746,6 +737,7 @@ ssetup_ntlmssp_authenticate: | |||
746 | } else if (type == Kerberos) { | 737 | } else if (type == Kerberos) { |
747 | #ifdef CONFIG_CIFS_UPCALL | 738 | #ifdef CONFIG_CIFS_UPCALL |
748 | struct cifs_spnego_msg *msg; | 739 | struct cifs_spnego_msg *msg; |
740 | |||
749 | spnego_key = cifs_get_spnego_key(ses); | 741 | spnego_key = cifs_get_spnego_key(ses); |
750 | if (IS_ERR(spnego_key)) { | 742 | if (IS_ERR(spnego_key)) { |
751 | rc = PTR_ERR(spnego_key); | 743 | rc = PTR_ERR(spnego_key); |
@@ -763,19 +755,17 @@ ssetup_ntlmssp_authenticate: | |||
763 | rc = -EKEYREJECTED; | 755 | rc = -EKEYREJECTED; |
764 | goto ssetup_exit; | 756 | goto ssetup_exit; |
765 | } | 757 | } |
766 | /* bail out if key is too long */ | 758 | |
767 | if (msg->sesskey_len > | 759 | ses->auth_key.response = kmalloc(msg->sesskey_len, GFP_KERNEL); |
768 | sizeof(ses->server->mac_signing_key.data.krb5)) { | 760 | if (!ses->auth_key.response) { |
769 | cERROR(1, "Kerberos signing key too long (%u bytes)", | 761 | cERROR(1, "Kerberos can't allocate (%u bytes) memory", |
770 | msg->sesskey_len); | 762 | msg->sesskey_len); |
771 | rc = -EOVERFLOW; | 763 | rc = -ENOMEM; |
772 | goto ssetup_exit; | 764 | goto ssetup_exit; |
773 | } | 765 | } |
774 | if (first_time) { | 766 | memcpy(ses->auth_key.response, msg->data, msg->sesskey_len); |
775 | ses->server->mac_signing_key.len = msg->sesskey_len; | 767 | ses->auth_key.len = msg->sesskey_len; |
776 | memcpy(ses->server->mac_signing_key.data.krb5, | 768 | |
777 | msg->data, msg->sesskey_len); | ||
778 | } | ||
779 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 769 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
780 | capabilities |= CAP_EXTENDED_SECURITY; | 770 | capabilities |= CAP_EXTENDED_SECURITY; |
781 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | 771 | pSMB->req.Capabilities = cpu_to_le32(capabilities); |
@@ -799,70 +789,85 @@ ssetup_ntlmssp_authenticate: | |||
799 | rc = -ENOSYS; | 789 | rc = -ENOSYS; |
800 | goto ssetup_exit; | 790 | goto ssetup_exit; |
801 | #endif /* CONFIG_CIFS_UPCALL */ | 791 | #endif /* CONFIG_CIFS_UPCALL */ |
802 | } else { | 792 | } else if (type == RawNTLMSSP) { |
803 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 793 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { |
804 | if (type == RawNTLMSSP) { | 794 | cERROR(1, "NTLMSSP requires Unicode support"); |
805 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 795 | rc = -ENOSYS; |
806 | cERROR(1, "NTLMSSP requires Unicode support"); | 796 | goto ssetup_exit; |
807 | rc = -ENOSYS; | 797 | } |
798 | |||
799 | cFYI(1, "ntlmssp session setup phase %d", phase); | ||
800 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
801 | capabilities |= CAP_EXTENDED_SECURITY; | ||
802 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
803 | switch(phase) { | ||
804 | case NtLmNegotiate: | ||
805 | build_ntlmssp_negotiate_blob( | ||
806 | pSMB->req.SecurityBlob, ses); | ||
807 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
808 | iov[1].iov_base = pSMB->req.SecurityBlob; | ||
809 | pSMB->req.SecurityBlobLength = | ||
810 | cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
811 | break; | ||
812 | case NtLmAuthenticate: | ||
813 | /* | ||
814 | * 5 is an empirical value, large enough to hold | ||
815 | * authenticate message plus max 10 of av paris, | ||
816 | * domain, user, workstation names, flags, etc. | ||
817 | */ | ||
818 | ntlmsspblob = kzalloc( | ||
819 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
820 | GFP_KERNEL); | ||
821 | if (!ntlmsspblob) { | ||
822 | cERROR(1, "Can't allocate NTLMSSP blob"); | ||
823 | rc = -ENOMEM; | ||
808 | goto ssetup_exit; | 824 | goto ssetup_exit; |
809 | } | 825 | } |
810 | 826 | ||
811 | cFYI(1, "ntlmssp session setup phase %d", phase); | 827 | rc = build_ntlmssp_auth_blob(ntlmsspblob, |
812 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 828 | &blob_len, ses, nls_cp); |
813 | capabilities |= CAP_EXTENDED_SECURITY; | 829 | if (rc) |
814 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
815 | if (phase == NtLmNegotiate) { | ||
816 | setup_ntlmssp_neg_req(pSMB, ses); | ||
817 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
818 | } else if (phase == NtLmAuthenticate) { | ||
819 | int blob_len; | ||
820 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, | ||
821 | nls_cp, | ||
822 | first_time); | ||
823 | iov[1].iov_len = blob_len; | ||
824 | /* Make sure that we tell the server that we | ||
825 | are using the uid that it just gave us back | ||
826 | on the response (challenge) */ | ||
827 | smb_buf->Uid = ses->Suid; | ||
828 | } else { | ||
829 | cERROR(1, "invalid phase %d", phase); | ||
830 | rc = -ENOSYS; | ||
831 | goto ssetup_exit; | 830 | goto ssetup_exit; |
832 | } | 831 | iov[1].iov_len = blob_len; |
833 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | 832 | iov[1].iov_base = ntlmsspblob; |
834 | /* unicode strings must be word aligned */ | 833 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); |
835 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 834 | /* |
836 | *bcc_ptr = 0; | 835 | * Make sure that we tell the server that we are using |
837 | bcc_ptr++; | 836 | * the uid that it just gave us back on the response |
838 | } | 837 | * (challenge) |
839 | unicode_oslm_strings(&bcc_ptr, nls_cp); | 838 | */ |
840 | } else { | 839 | smb_buf->Uid = ses->Suid; |
841 | cERROR(1, "secType %d not supported!", type); | 840 | break; |
841 | default: | ||
842 | cERROR(1, "invalid phase %d", phase); | ||
842 | rc = -ENOSYS; | 843 | rc = -ENOSYS; |
843 | goto ssetup_exit; | 844 | goto ssetup_exit; |
844 | } | 845 | } |
845 | #else | 846 | /* unicode strings must be word aligned */ |
847 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
848 | *bcc_ptr = 0; | ||
849 | bcc_ptr++; | ||
850 | } | ||
851 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
852 | } else { | ||
846 | cERROR(1, "secType %d not supported!", type); | 853 | cERROR(1, "secType %d not supported!", type); |
847 | rc = -ENOSYS; | 854 | rc = -ENOSYS; |
848 | goto ssetup_exit; | 855 | goto ssetup_exit; |
849 | #endif | ||
850 | } | 856 | } |
851 | 857 | ||
852 | iov[2].iov_base = str_area; | 858 | iov[2].iov_base = str_area; |
853 | iov[2].iov_len = (long) bcc_ptr - (long) str_area; | 859 | iov[2].iov_len = (long) bcc_ptr - (long) str_area; |
854 | 860 | ||
855 | count = iov[1].iov_len + iov[2].iov_len; | 861 | count = iov[1].iov_len + iov[2].iov_len; |
856 | smb_buf->smb_buf_length += count; | 862 | smb_buf->smb_buf_length = |
863 | cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); | ||
857 | 864 | ||
858 | BCC_LE(smb_buf) = cpu_to_le16(count); | 865 | put_bcc(count, smb_buf); |
859 | 866 | ||
860 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, | 867 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, |
861 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); | 868 | CIFS_LOG_ERROR); |
862 | /* SMB request buf freed in SendReceive2 */ | 869 | /* SMB request buf freed in SendReceive2 */ |
863 | 870 | ||
864 | cFYI(1, "ssetup rc from sendrecv2 is %d", rc); | ||
865 | |||
866 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 871 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
867 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 872 | smb_buf = (struct smb_hdr *)iov[0].iov_base; |
868 | 873 | ||
@@ -891,11 +896,10 @@ ssetup_ntlmssp_authenticate: | |||
891 | cFYI(1, "UID = %d ", ses->Suid); | 896 | cFYI(1, "UID = %d ", ses->Suid); |
892 | /* response can have either 3 or 4 word count - Samba sends 3 */ | 897 | /* response can have either 3 or 4 word count - Samba sends 3 */ |
893 | /* and lanman response is 3 */ | 898 | /* and lanman response is 3 */ |
894 | bytes_remaining = BCC(smb_buf); | 899 | bytes_remaining = get_bcc(smb_buf); |
895 | bcc_ptr = pByteArea(smb_buf); | 900 | bcc_ptr = pByteArea(smb_buf); |
896 | 901 | ||
897 | if (smb_buf->WordCount == 4) { | 902 | if (smb_buf->WordCount == 4) { |
898 | __u16 blob_len; | ||
899 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 903 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
900 | if (blob_len > bytes_remaining) { | 904 | if (blob_len > bytes_remaining) { |
901 | cERROR(1, "bad security blob length %d", blob_len); | 905 | cERROR(1, "bad security blob length %d", blob_len); |
@@ -913,7 +917,9 @@ ssetup_ntlmssp_authenticate: | |||
913 | } | 917 | } |
914 | 918 | ||
915 | /* BB check if Unicode and decode strings */ | 919 | /* BB check if Unicode and decode strings */ |
916 | if (smb_buf->Flags2 & SMBFLG2_UNICODE) { | 920 | if (bytes_remaining == 0) { |
921 | /* no string area to decode, do nothing */ | ||
922 | } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { | ||
917 | /* unicode string area must be word-aligned */ | 923 | /* unicode string area must be word-aligned */ |
918 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { | 924 | if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { |
919 | ++bcc_ptr; | 925 | ++bcc_ptr; |
@@ -931,6 +937,8 @@ ssetup_exit: | |||
931 | key_put(spnego_key); | 937 | key_put(spnego_key); |
932 | } | 938 | } |
933 | kfree(str_area); | 939 | kfree(str_area); |
940 | kfree(ntlmsspblob); | ||
941 | ntlmsspblob = NULL; | ||
934 | if (resp_buf_type == CIFS_SMALL_BUFFER) { | 942 | if (resp_buf_type == CIFS_SMALL_BUFFER) { |
935 | cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); | 943 | cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); |
936 | cifs_small_buf_release(iov[0].iov_base); | 944 | cifs_small_buf_release(iov[0].iov_base); |
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c deleted file mode 100644 index b6b6dcb500bf..000000000000 --- a/fs/cifs/smbdes.c +++ /dev/null | |||
@@ -1,419 +0,0 @@ | |||
1 | /* | ||
2 | Unix SMB/Netbios implementation. | ||
3 | Version 1.9. | ||
4 | |||
5 | a partial implementation of DES designed for use in the | ||
6 | SMB authentication protocol | ||
7 | |||
8 | Copyright (C) Andrew Tridgell 1998 | ||
9 | Modified by Steve French (sfrench@us.ibm.com) 2002,2004 | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of the GNU General Public License as published by | ||
13 | the Free Software Foundation; either version 2 of the License, or | ||
14 | (at your option) any later version. | ||
15 | |||
16 | This program is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with this program; if not, write to the Free Software | ||
23 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
24 | */ | ||
25 | |||
26 | /* NOTES: | ||
27 | |||
28 | This code makes no attempt to be fast! In fact, it is a very | ||
29 | slow implementation | ||
30 | |||
31 | This code is NOT a complete DES implementation. It implements only | ||
32 | the minimum necessary for SMB authentication, as used by all SMB | ||
33 | products (including every copy of Microsoft Windows95 ever sold) | ||
34 | |||
35 | In particular, it can only do a unchained forward DES pass. This | ||
36 | means it is not possible to use this code for encryption/decryption | ||
37 | of data, instead it is only useful as a "hash" algorithm. | ||
38 | |||
39 | There is no entry point into this code that allows normal DES operation. | ||
40 | |||
41 | I believe this means that this code does not come under ITAR | ||
42 | regulations but this is NOT a legal opinion. If you are concerned | ||
43 | about the applicability of ITAR regulations to this code then you | ||
44 | should confirm it for yourself (and maybe let me know if you come | ||
45 | up with a different answer to the one above) | ||
46 | */ | ||
47 | #include <linux/slab.h> | ||
48 | #include "cifsencrypt.h" | ||
49 | #define uchar unsigned char | ||
50 | |||
51 | static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, | ||
52 | 1, 58, 50, 42, 34, 26, 18, | ||
53 | 10, 2, 59, 51, 43, 35, 27, | ||
54 | 19, 11, 3, 60, 52, 44, 36, | ||
55 | 63, 55, 47, 39, 31, 23, 15, | ||
56 | 7, 62, 54, 46, 38, 30, 22, | ||
57 | 14, 6, 61, 53, 45, 37, 29, | ||
58 | 21, 13, 5, 28, 20, 12, 4 | ||
59 | }; | ||
60 | |||
61 | static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, | ||
62 | 3, 28, 15, 6, 21, 10, | ||
63 | 23, 19, 12, 4, 26, 8, | ||
64 | 16, 7, 27, 20, 13, 2, | ||
65 | 41, 52, 31, 37, 47, 55, | ||
66 | 30, 40, 51, 45, 33, 48, | ||
67 | 44, 49, 39, 56, 34, 53, | ||
68 | 46, 42, 50, 36, 29, 32 | ||
69 | }; | ||
70 | |||
71 | static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, | ||
72 | 60, 52, 44, 36, 28, 20, 12, 4, | ||
73 | 62, 54, 46, 38, 30, 22, 14, 6, | ||
74 | 64, 56, 48, 40, 32, 24, 16, 8, | ||
75 | 57, 49, 41, 33, 25, 17, 9, 1, | ||
76 | 59, 51, 43, 35, 27, 19, 11, 3, | ||
77 | 61, 53, 45, 37, 29, 21, 13, 5, | ||
78 | 63, 55, 47, 39, 31, 23, 15, 7 | ||
79 | }; | ||
80 | |||
81 | static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, | ||
82 | 4, 5, 6, 7, 8, 9, | ||
83 | 8, 9, 10, 11, 12, 13, | ||
84 | 12, 13, 14, 15, 16, 17, | ||
85 | 16, 17, 18, 19, 20, 21, | ||
86 | 20, 21, 22, 23, 24, 25, | ||
87 | 24, 25, 26, 27, 28, 29, | ||
88 | 28, 29, 30, 31, 32, 1 | ||
89 | }; | ||
90 | |||
91 | static uchar perm5[32] = { 16, 7, 20, 21, | ||
92 | 29, 12, 28, 17, | ||
93 | 1, 15, 23, 26, | ||
94 | 5, 18, 31, 10, | ||
95 | 2, 8, 24, 14, | ||
96 | 32, 27, 3, 9, | ||
97 | 19, 13, 30, 6, | ||
98 | 22, 11, 4, 25 | ||
99 | }; | ||
100 | |||
101 | static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, | ||
102 | 39, 7, 47, 15, 55, 23, 63, 31, | ||
103 | 38, 6, 46, 14, 54, 22, 62, 30, | ||
104 | 37, 5, 45, 13, 53, 21, 61, 29, | ||
105 | 36, 4, 44, 12, 52, 20, 60, 28, | ||
106 | 35, 3, 43, 11, 51, 19, 59, 27, | ||
107 | 34, 2, 42, 10, 50, 18, 58, 26, | ||
108 | 33, 1, 41, 9, 49, 17, 57, 25 | ||
109 | }; | ||
110 | |||
111 | static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; | ||
112 | |||
113 | static uchar sbox[8][4][16] = { | ||
114 | {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, | ||
115 | {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, | ||
116 | {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, | ||
117 | {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13} }, | ||
118 | |||
119 | {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, | ||
120 | {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, | ||
121 | {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, | ||
122 | {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9} }, | ||
123 | |||
124 | {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, | ||
125 | {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, | ||
126 | {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, | ||
127 | {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12} }, | ||
128 | |||
129 | {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, | ||
130 | {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, | ||
131 | {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, | ||
132 | {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14} }, | ||
133 | |||
134 | {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, | ||
135 | {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, | ||
136 | {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, | ||
137 | {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3} }, | ||
138 | |||
139 | {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, | ||
140 | {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, | ||
141 | {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, | ||
142 | {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13} }, | ||
143 | |||
144 | {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, | ||
145 | {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, | ||
146 | {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, | ||
147 | {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12} }, | ||
148 | |||
149 | {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, | ||
150 | {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, | ||
151 | {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, | ||
152 | {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11} } | ||
153 | }; | ||
154 | |||
155 | static void | ||
156 | permute(char *out, char *in, uchar *p, int n) | ||
157 | { | ||
158 | int i; | ||
159 | for (i = 0; i < n; i++) | ||
160 | out[i] = in[p[i] - 1]; | ||
161 | } | ||
162 | |||
163 | static void | ||
164 | lshift(char *d, int count, int n) | ||
165 | { | ||
166 | char out[64]; | ||
167 | int i; | ||
168 | for (i = 0; i < n; i++) | ||
169 | out[i] = d[(i + count) % n]; | ||
170 | for (i = 0; i < n; i++) | ||
171 | d[i] = out[i]; | ||
172 | } | ||
173 | |||
174 | static void | ||
175 | concat(char *out, char *in1, char *in2, int l1, int l2) | ||
176 | { | ||
177 | while (l1--) | ||
178 | *out++ = *in1++; | ||
179 | while (l2--) | ||
180 | *out++ = *in2++; | ||
181 | } | ||
182 | |||
183 | static void | ||
184 | xor(char *out, char *in1, char *in2, int n) | ||
185 | { | ||
186 | int i; | ||
187 | for (i = 0; i < n; i++) | ||
188 | out[i] = in1[i] ^ in2[i]; | ||
189 | } | ||
190 | |||
191 | static void | ||
192 | dohash(char *out, char *in, char *key, int forw) | ||
193 | { | ||
194 | int i, j, k; | ||
195 | char *pk1; | ||
196 | char c[28]; | ||
197 | char d[28]; | ||
198 | char *cd; | ||
199 | char (*ki)[48]; | ||
200 | char *pd1; | ||
201 | char l[32], r[32]; | ||
202 | char *rl; | ||
203 | |||
204 | /* Have to reduce stack usage */ | ||
205 | pk1 = kmalloc(56+56+64+64, GFP_KERNEL); | ||
206 | if (pk1 == NULL) | ||
207 | return; | ||
208 | |||
209 | ki = kmalloc(16*48, GFP_KERNEL); | ||
210 | if (ki == NULL) { | ||
211 | kfree(pk1); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | cd = pk1 + 56; | ||
216 | pd1 = cd + 56; | ||
217 | rl = pd1 + 64; | ||
218 | |||
219 | permute(pk1, key, perm1, 56); | ||
220 | |||
221 | for (i = 0; i < 28; i++) | ||
222 | c[i] = pk1[i]; | ||
223 | for (i = 0; i < 28; i++) | ||
224 | d[i] = pk1[i + 28]; | ||
225 | |||
226 | for (i = 0; i < 16; i++) { | ||
227 | lshift(c, sc[i], 28); | ||
228 | lshift(d, sc[i], 28); | ||
229 | |||
230 | concat(cd, c, d, 28, 28); | ||
231 | permute(ki[i], cd, perm2, 48); | ||
232 | } | ||
233 | |||
234 | permute(pd1, in, perm3, 64); | ||
235 | |||
236 | for (j = 0; j < 32; j++) { | ||
237 | l[j] = pd1[j]; | ||
238 | r[j] = pd1[j + 32]; | ||
239 | } | ||
240 | |||
241 | for (i = 0; i < 16; i++) { | ||
242 | char *er; /* er[48] */ | ||
243 | char *erk; /* erk[48] */ | ||
244 | char b[8][6]; | ||
245 | char *cb; /* cb[32] */ | ||
246 | char *pcb; /* pcb[32] */ | ||
247 | char *r2; /* r2[32] */ | ||
248 | |||
249 | er = kmalloc(48+48+32+32+32, GFP_KERNEL); | ||
250 | if (er == NULL) { | ||
251 | kfree(pk1); | ||
252 | kfree(ki); | ||
253 | return; | ||
254 | } | ||
255 | erk = er+48; | ||
256 | cb = erk+48; | ||
257 | pcb = cb+32; | ||
258 | r2 = pcb+32; | ||
259 | |||
260 | permute(er, r, perm4, 48); | ||
261 | |||
262 | xor(erk, er, ki[forw ? i : 15 - i], 48); | ||
263 | |||
264 | for (j = 0; j < 8; j++) | ||
265 | for (k = 0; k < 6; k++) | ||
266 | b[j][k] = erk[j * 6 + k]; | ||
267 | |||
268 | for (j = 0; j < 8; j++) { | ||
269 | int m, n; | ||
270 | m = (b[j][0] << 1) | b[j][5]; | ||
271 | |||
272 | n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << | ||
273 | 1) | b[j][4]; | ||
274 | |||
275 | for (k = 0; k < 4; k++) | ||
276 | b[j][k] = | ||
277 | (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; | ||
278 | } | ||
279 | |||
280 | for (j = 0; j < 8; j++) | ||
281 | for (k = 0; k < 4; k++) | ||
282 | cb[j * 4 + k] = b[j][k]; | ||
283 | permute(pcb, cb, perm5, 32); | ||
284 | |||
285 | xor(r2, l, pcb, 32); | ||
286 | |||
287 | for (j = 0; j < 32; j++) | ||
288 | l[j] = r[j]; | ||
289 | |||
290 | for (j = 0; j < 32; j++) | ||
291 | r[j] = r2[j]; | ||
292 | |||
293 | kfree(er); | ||
294 | } | ||
295 | |||
296 | concat(rl, r, l, 32, 32); | ||
297 | |||
298 | permute(out, rl, perm6, 64); | ||
299 | kfree(pk1); | ||
300 | kfree(ki); | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | str_to_key(unsigned char *str, unsigned char *key) | ||
305 | { | ||
306 | int i; | ||
307 | |||
308 | key[0] = str[0] >> 1; | ||
309 | key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); | ||
310 | key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); | ||
311 | key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); | ||
312 | key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); | ||
313 | key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); | ||
314 | key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); | ||
315 | key[7] = str[6] & 0x7F; | ||
316 | for (i = 0; i < 8; i++) | ||
317 | key[i] = (key[i] << 1); | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | smbhash(unsigned char *out, const unsigned char *in, unsigned char *key, | ||
322 | int forw) | ||
323 | { | ||
324 | int i; | ||
325 | char *outb; /* outb[64] */ | ||
326 | char *inb; /* inb[64] */ | ||
327 | char *keyb; /* keyb[64] */ | ||
328 | unsigned char key2[8]; | ||
329 | |||
330 | outb = kmalloc(64 * 3, GFP_KERNEL); | ||
331 | if (outb == NULL) | ||
332 | return; | ||
333 | |||
334 | inb = outb + 64; | ||
335 | keyb = inb + 64; | ||
336 | |||
337 | str_to_key(key, key2); | ||
338 | |||
339 | for (i = 0; i < 64; i++) { | ||
340 | inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; | ||
341 | keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; | ||
342 | outb[i] = 0; | ||
343 | } | ||
344 | |||
345 | dohash(outb, inb, keyb, forw); | ||
346 | |||
347 | for (i = 0; i < 8; i++) | ||
348 | out[i] = 0; | ||
349 | |||
350 | for (i = 0; i < 64; i++) { | ||
351 | if (outb[i]) | ||
352 | out[i / 8] |= (1 << (7 - (i % 8))); | ||
353 | } | ||
354 | kfree(outb); | ||
355 | } | ||
356 | |||
357 | void | ||
358 | E_P16(unsigned char *p14, unsigned char *p16) | ||
359 | { | ||
360 | unsigned char sp8[8] = | ||
361 | { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; | ||
362 | smbhash(p16, sp8, p14, 1); | ||
363 | smbhash(p16 + 8, sp8, p14 + 7, 1); | ||
364 | } | ||
365 | |||
366 | void | ||
367 | E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) | ||
368 | { | ||
369 | smbhash(p24, c8, p21, 1); | ||
370 | smbhash(p24 + 8, c8, p21 + 7, 1); | ||
371 | smbhash(p24 + 16, c8, p21 + 14, 1); | ||
372 | } | ||
373 | |||
374 | #if 0 /* currently unused */ | ||
375 | static void | ||
376 | D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) | ||
377 | { | ||
378 | smbhash(out, in, p14, 0); | ||
379 | smbhash(out + 8, in + 8, p14 + 7, 0); | ||
380 | } | ||
381 | |||
382 | static void | ||
383 | E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) | ||
384 | { | ||
385 | smbhash(out, in, p14, 1); | ||
386 | smbhash(out + 8, in + 8, p14 + 7, 1); | ||
387 | } | ||
388 | /* these routines are currently unneeded, but may be | ||
389 | needed later */ | ||
390 | void | ||
391 | cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) | ||
392 | { | ||
393 | unsigned char buf[8]; | ||
394 | |||
395 | smbhash(buf, in, key, 1); | ||
396 | smbhash(out, buf, key + 9, 1); | ||
397 | } | ||
398 | |||
399 | void | ||
400 | cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) | ||
401 | { | ||
402 | unsigned char buf[8]; | ||
403 | static unsigned char key2[8]; | ||
404 | |||
405 | smbhash(buf, in, key, 1); | ||
406 | key2[0] = key[7]; | ||
407 | smbhash(out, buf, key2, 1); | ||
408 | } | ||
409 | |||
410 | void | ||
411 | cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) | ||
412 | { | ||
413 | static unsigned char key2[8]; | ||
414 | |||
415 | smbhash(out, in, key, forw); | ||
416 | key2[0] = key[7]; | ||
417 | smbhash(out + 8, in + 8, key2, forw); | ||
418 | } | ||
419 | #endif /* unneeded routines */ | ||
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 192ea51af20f..1c5b770c3141 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c | |||
@@ -32,9 +32,8 @@ | |||
32 | #include "cifs_unicode.h" | 32 | #include "cifs_unicode.h" |
33 | #include "cifspdu.h" | 33 | #include "cifspdu.h" |
34 | #include "cifsglob.h" | 34 | #include "cifsglob.h" |
35 | #include "md5.h" | ||
36 | #include "cifs_debug.h" | 35 | #include "cifs_debug.h" |
37 | #include "cifsencrypt.h" | 36 | #include "cifsproto.h" |
38 | 37 | ||
39 | #ifndef false | 38 | #ifndef false |
40 | #define false 0 | 39 | #define false 0 |
@@ -48,36 +47,150 @@ | |||
48 | #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) | 47 | #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) |
49 | #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) | 48 | #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) |
50 | 49 | ||
51 | /*The following definitions come from libsmb/smbencrypt.c */ | 50 | static void |
51 | str_to_key(unsigned char *str, unsigned char *key) | ||
52 | { | ||
53 | int i; | ||
54 | |||
55 | key[0] = str[0] >> 1; | ||
56 | key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); | ||
57 | key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); | ||
58 | key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); | ||
59 | key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); | ||
60 | key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); | ||
61 | key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); | ||
62 | key[7] = str[6] & 0x7F; | ||
63 | for (i = 0; i < 8; i++) | ||
64 | key[i] = (key[i] << 1); | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) | ||
69 | { | ||
70 | int rc; | ||
71 | unsigned char key2[8]; | ||
72 | struct crypto_blkcipher *tfm_des; | ||
73 | struct scatterlist sgin, sgout; | ||
74 | struct blkcipher_desc desc; | ||
75 | |||
76 | str_to_key(key, key2); | ||
77 | |||
78 | tfm_des = crypto_alloc_blkcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC); | ||
79 | if (IS_ERR(tfm_des)) { | ||
80 | rc = PTR_ERR(tfm_des); | ||
81 | cERROR(1, "could not allocate des crypto API\n"); | ||
82 | goto smbhash_err; | ||
83 | } | ||
84 | |||
85 | desc.tfm = tfm_des; | ||
86 | |||
87 | crypto_blkcipher_setkey(tfm_des, key2, 8); | ||
88 | |||
89 | sg_init_one(&sgin, in, 8); | ||
90 | sg_init_one(&sgout, out, 8); | ||
52 | 91 | ||
53 | void SMBencrypt(unsigned char *passwd, const unsigned char *c8, | 92 | rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, 8); |
54 | unsigned char *p24); | 93 | if (rc) |
55 | void E_md4hash(const unsigned char *passwd, unsigned char *p16); | 94 | cERROR(1, "could not encrypt crypt key rc: %d\n", rc); |
56 | static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8, | 95 | |
57 | unsigned char p24[24]); | 96 | crypto_free_blkcipher(tfm_des); |
58 | void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); | 97 | smbhash_err: |
98 | return rc; | ||
99 | } | ||
100 | |||
101 | static int | ||
102 | E_P16(unsigned char *p14, unsigned char *p16) | ||
103 | { | ||
104 | int rc; | ||
105 | unsigned char sp8[8] = | ||
106 | { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; | ||
107 | |||
108 | rc = smbhash(p16, sp8, p14); | ||
109 | if (rc) | ||
110 | return rc; | ||
111 | rc = smbhash(p16 + 8, sp8, p14 + 7); | ||
112 | return rc; | ||
113 | } | ||
114 | |||
115 | static int | ||
116 | E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) | ||
117 | { | ||
118 | int rc; | ||
119 | |||
120 | rc = smbhash(p24, c8, p21); | ||
121 | if (rc) | ||
122 | return rc; | ||
123 | rc = smbhash(p24 + 8, c8, p21 + 7); | ||
124 | if (rc) | ||
125 | return rc; | ||
126 | rc = smbhash(p24 + 16, c8, p21 + 14); | ||
127 | return rc; | ||
128 | } | ||
129 | |||
130 | /* produce a md4 message digest from data of length n bytes */ | ||
131 | int | ||
132 | mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) | ||
133 | { | ||
134 | int rc; | ||
135 | unsigned int size; | ||
136 | struct crypto_shash *md4; | ||
137 | struct sdesc *sdescmd4; | ||
138 | |||
139 | md4 = crypto_alloc_shash("md4", 0, 0); | ||
140 | if (IS_ERR(md4)) { | ||
141 | rc = PTR_ERR(md4); | ||
142 | cERROR(1, "%s: Crypto md4 allocation error %d\n", __func__, rc); | ||
143 | return rc; | ||
144 | } | ||
145 | size = sizeof(struct shash_desc) + crypto_shash_descsize(md4); | ||
146 | sdescmd4 = kmalloc(size, GFP_KERNEL); | ||
147 | if (!sdescmd4) { | ||
148 | rc = -ENOMEM; | ||
149 | cERROR(1, "%s: Memory allocation failure\n", __func__); | ||
150 | goto mdfour_err; | ||
151 | } | ||
152 | sdescmd4->shash.tfm = md4; | ||
153 | sdescmd4->shash.flags = 0x0; | ||
154 | |||
155 | rc = crypto_shash_init(&sdescmd4->shash); | ||
156 | if (rc) { | ||
157 | cERROR(1, "%s: Could not init md4 shash\n", __func__); | ||
158 | goto mdfour_err; | ||
159 | } | ||
160 | crypto_shash_update(&sdescmd4->shash, link_str, link_len); | ||
161 | rc = crypto_shash_final(&sdescmd4->shash, md4_hash); | ||
162 | |||
163 | mdfour_err: | ||
164 | crypto_free_shash(md4); | ||
165 | kfree(sdescmd4); | ||
166 | |||
167 | return rc; | ||
168 | } | ||
59 | 169 | ||
60 | /* | 170 | /* |
61 | This implements the X/Open SMB password encryption | 171 | This implements the X/Open SMB password encryption |
62 | It takes a password, a 8 byte "crypt key" and puts 24 bytes of | 172 | It takes a password, a 8 byte "crypt key" and puts 24 bytes of |
63 | encrypted password into p24 */ | 173 | encrypted password into p24 */ |
64 | /* Note that password must be uppercased and null terminated */ | 174 | /* Note that password must be uppercased and null terminated */ |
65 | void | 175 | int |
66 | SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) | 176 | SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) |
67 | { | 177 | { |
68 | unsigned char p14[15], p21[21]; | 178 | int rc; |
179 | unsigned char p14[14], p16[16], p21[21]; | ||
69 | 180 | ||
70 | memset(p21, '\0', 21); | ||
71 | memset(p14, '\0', 14); | 181 | memset(p14, '\0', 14); |
72 | strncpy((char *) p14, (char *) passwd, 14); | 182 | memset(p16, '\0', 16); |
183 | memset(p21, '\0', 21); | ||
73 | 184 | ||
74 | /* strupper((char *)p14); *//* BB at least uppercase the easy range */ | 185 | memcpy(p14, passwd, 14); |
75 | E_P16(p14, p21); | 186 | rc = E_P16(p14, p16); |
187 | if (rc) | ||
188 | return rc; | ||
76 | 189 | ||
77 | SMBOWFencrypt(p21, c8, p24); | 190 | memcpy(p21, p16, 16); |
191 | rc = E_P24(p21, c8, p24); | ||
78 | 192 | ||
79 | memset(p14, 0, 15); | 193 | return rc; |
80 | memset(p21, 0, 21); | ||
81 | } | 194 | } |
82 | 195 | ||
83 | /* Routines for Windows NT MD4 Hash functions. */ | 196 | /* Routines for Windows NT MD4 Hash functions. */ |
@@ -118,9 +231,10 @@ _my_mbstowcs(__u16 *dst, const unsigned char *src, int len) | |||
118 | * Creates the MD4 Hash of the users password in NT UNICODE. | 231 | * Creates the MD4 Hash of the users password in NT UNICODE. |
119 | */ | 232 | */ |
120 | 233 | ||
121 | void | 234 | int |
122 | E_md4hash(const unsigned char *passwd, unsigned char *p16) | 235 | E_md4hash(const unsigned char *passwd, unsigned char *p16) |
123 | { | 236 | { |
237 | int rc; | ||
124 | int len; | 238 | int len; |
125 | __u16 wpwd[129]; | 239 | __u16 wpwd[129]; |
126 | 240 | ||
@@ -139,8 +253,10 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) | |||
139 | /* Calculate length in bytes */ | 253 | /* Calculate length in bytes */ |
140 | len = _my_wcslen(wpwd) * sizeof(__u16); | 254 | len = _my_wcslen(wpwd) * sizeof(__u16); |
141 | 255 | ||
142 | mdfour(p16, (unsigned char *) wpwd, len); | 256 | rc = mdfour(p16, (unsigned char *) wpwd, len); |
143 | memset(wpwd, 0, 129 * 2); | 257 | memset(wpwd, 0, 129 * 2); |
258 | |||
259 | return rc; | ||
144 | } | 260 | } |
145 | 261 | ||
146 | #if 0 /* currently unused */ | 262 | #if 0 /* currently unused */ |
@@ -212,19 +328,6 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n, | |||
212 | } | 328 | } |
213 | #endif | 329 | #endif |
214 | 330 | ||
215 | /* Does the des encryption from the NT or LM MD4 hash. */ | ||
216 | static void | ||
217 | SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8, | ||
218 | unsigned char p24[24]) | ||
219 | { | ||
220 | unsigned char p21[21]; | ||
221 | |||
222 | memset(p21, '\0', 21); | ||
223 | |||
224 | memcpy(p21, passwd, 16); | ||
225 | E_P24(p21, c8, p24); | ||
226 | } | ||
227 | |||
228 | /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ | 331 | /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ |
229 | #if 0 /* currently unused */ | 332 | #if 0 /* currently unused */ |
230 | static void | 333 | static void |
@@ -242,16 +345,23 @@ NTLMSSPOWFencrypt(unsigned char passwd[8], | |||
242 | #endif | 345 | #endif |
243 | 346 | ||
244 | /* Does the NT MD4 hash then des encryption. */ | 347 | /* Does the NT MD4 hash then des encryption. */ |
245 | 348 | int | |
246 | void | ||
247 | SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) | 349 | SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) |
248 | { | 350 | { |
249 | unsigned char p21[21]; | 351 | int rc; |
352 | unsigned char p16[16], p21[21]; | ||
250 | 353 | ||
354 | memset(p16, '\0', 16); | ||
251 | memset(p21, '\0', 21); | 355 | memset(p21, '\0', 21); |
252 | 356 | ||
253 | E_md4hash(passwd, p21); | 357 | rc = E_md4hash(passwd, p16); |
254 | SMBOWFencrypt(p21, c8, p24); | 358 | if (rc) { |
359 | cFYI(1, "%s Can't generate NT hash, error: %d", __func__, rc); | ||
360 | return rc; | ||
361 | } | ||
362 | memcpy(p21, p16, 16); | ||
363 | rc = E_P24(p21, c8, p24); | ||
364 | return rc; | ||
255 | } | 365 | } |
256 | 366 | ||
257 | 367 | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 82f78c4d6978..147aa22c3c3a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -36,7 +36,13 @@ | |||
36 | 36 | ||
37 | extern mempool_t *cifs_mid_poolp; | 37 | extern mempool_t *cifs_mid_poolp; |
38 | 38 | ||
39 | static struct mid_q_entry * | 39 | static void |
40 | wake_up_task(struct mid_q_entry *mid) | ||
41 | { | ||
42 | wake_up_process(mid->callback_data); | ||
43 | } | ||
44 | |||
45 | struct mid_q_entry * | ||
40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | 46 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) |
41 | { | 47 | { |
42 | struct mid_q_entry *temp; | 48 | struct mid_q_entry *temp; |
@@ -58,28 +64,28 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | |||
58 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ | 64 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
59 | /* when mid allocated can be before when sent */ | 65 | /* when mid allocated can be before when sent */ |
60 | temp->when_alloc = jiffies; | 66 | temp->when_alloc = jiffies; |
61 | temp->tsk = current; | 67 | |
68 | /* | ||
69 | * The default is for the mid to be synchronous, so the | ||
70 | * default callback just wakes up the current task. | ||
71 | */ | ||
72 | temp->callback = wake_up_task; | ||
73 | temp->callback_data = current; | ||
62 | } | 74 | } |
63 | 75 | ||
64 | spin_lock(&GlobalMid_Lock); | ||
65 | list_add_tail(&temp->qhead, &server->pending_mid_q); | ||
66 | atomic_inc(&midCount); | 76 | atomic_inc(&midCount); |
67 | temp->midState = MID_REQUEST_ALLOCATED; | 77 | temp->midState = MID_REQUEST_ALLOCATED; |
68 | spin_unlock(&GlobalMid_Lock); | ||
69 | return temp; | 78 | return temp; |
70 | } | 79 | } |
71 | 80 | ||
72 | static void | 81 | void |
73 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 82 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
74 | { | 83 | { |
75 | #ifdef CONFIG_CIFS_STATS2 | 84 | #ifdef CONFIG_CIFS_STATS2 |
76 | unsigned long now; | 85 | unsigned long now; |
77 | #endif | 86 | #endif |
78 | spin_lock(&GlobalMid_Lock); | ||
79 | midEntry->midState = MID_FREE; | 87 | midEntry->midState = MID_FREE; |
80 | list_del(&midEntry->qhead); | ||
81 | atomic_dec(&midCount); | 88 | atomic_dec(&midCount); |
82 | spin_unlock(&GlobalMid_Lock); | ||
83 | if (midEntry->largeBuf) | 89 | if (midEntry->largeBuf) |
84 | cifs_buf_release(midEntry->resp_buf); | 90 | cifs_buf_release(midEntry->resp_buf); |
85 | else | 91 | else |
@@ -103,6 +109,16 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
103 | mempool_free(midEntry, cifs_mid_poolp); | 109 | mempool_free(midEntry, cifs_mid_poolp); |
104 | } | 110 | } |
105 | 111 | ||
112 | static void | ||
113 | delete_mid(struct mid_q_entry *mid) | ||
114 | { | ||
115 | spin_lock(&GlobalMid_Lock); | ||
116 | list_del(&mid->qhead); | ||
117 | spin_unlock(&GlobalMid_Lock); | ||
118 | |||
119 | DeleteMidQEntry(mid); | ||
120 | } | ||
121 | |||
106 | static int | 122 | static int |
107 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | 123 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) |
108 | { | 124 | { |
@@ -113,13 +129,13 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
113 | unsigned int len = iov[0].iov_len; | 129 | unsigned int len = iov[0].iov_len; |
114 | unsigned int total_len; | 130 | unsigned int total_len; |
115 | int first_vec = 0; | 131 | int first_vec = 0; |
116 | unsigned int smb_buf_length = smb_buffer->smb_buf_length; | 132 | unsigned int smb_buf_length = be32_to_cpu(smb_buffer->smb_buf_length); |
117 | struct socket *ssocket = server->ssocket; | 133 | struct socket *ssocket = server->ssocket; |
118 | 134 | ||
119 | if (ssocket == NULL) | 135 | if (ssocket == NULL) |
120 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 136 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
121 | 137 | ||
122 | smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr; | 138 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; |
123 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 139 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
124 | smb_msg.msg_control = NULL; | 140 | smb_msg.msg_control = NULL; |
125 | smb_msg.msg_controllen = 0; | 141 | smb_msg.msg_controllen = 0; |
@@ -128,17 +144,10 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
128 | else | 144 | else |
129 | smb_msg.msg_flags = MSG_NOSIGNAL; | 145 | smb_msg.msg_flags = MSG_NOSIGNAL; |
130 | 146 | ||
131 | /* smb header is converted in header_assemble. bcc and rest of SMB word | ||
132 | area, and byte area if necessary, is converted to littleendian in | ||
133 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | ||
134 | Flags2 is converted in SendReceive */ | ||
135 | |||
136 | |||
137 | total_len = 0; | 147 | total_len = 0; |
138 | for (i = 0; i < n_vec; i++) | 148 | for (i = 0; i < n_vec; i++) |
139 | total_len += iov[i].iov_len; | 149 | total_len += iov[i].iov_len; |
140 | 150 | ||
141 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | ||
142 | cFYI(1, "Sending smb: total_len %d", total_len); | 151 | cFYI(1, "Sending smb: total_len %d", total_len); |
143 | dump_smb(smb_buffer, len); | 152 | dump_smb(smb_buffer, len); |
144 | 153 | ||
@@ -220,14 +229,14 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
220 | server->tcpStatus = CifsNeedReconnect; | 229 | server->tcpStatus = CifsNeedReconnect; |
221 | } | 230 | } |
222 | 231 | ||
223 | if (rc < 0) { | 232 | if (rc < 0 && rc != -EINTR) |
224 | cERROR(1, "Error %d sending data on socket to server", rc); | 233 | cERROR(1, "Error %d sending data on socket to server", rc); |
225 | } else | 234 | else |
226 | rc = 0; | 235 | rc = 0; |
227 | 236 | ||
228 | /* Don't want to modify the buffer as a | 237 | /* Don't want to modify the buffer as a |
229 | side effect of this call. */ | 238 | side effect of this call. */ |
230 | smb_buffer->smb_buf_length = smb_buf_length; | 239 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buf_length); |
231 | 240 | ||
232 | return rc; | 241 | return rc; |
233 | } | 242 | } |
@@ -244,31 +253,31 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, | |||
244 | return smb_sendv(server, &iov, 1); | 253 | return smb_sendv(server, &iov, 1); |
245 | } | 254 | } |
246 | 255 | ||
247 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | 256 | static int wait_for_free_request(struct TCP_Server_Info *server, |
257 | const int long_op) | ||
248 | { | 258 | { |
249 | if (long_op == CIFS_ASYNC_OP) { | 259 | if (long_op == CIFS_ASYNC_OP) { |
250 | /* oplock breaks must not be held up */ | 260 | /* oplock breaks must not be held up */ |
251 | atomic_inc(&ses->server->inFlight); | 261 | atomic_inc(&server->inFlight); |
252 | return 0; | 262 | return 0; |
253 | } | 263 | } |
254 | 264 | ||
255 | spin_lock(&GlobalMid_Lock); | 265 | spin_lock(&GlobalMid_Lock); |
256 | while (1) { | 266 | while (1) { |
257 | if (atomic_read(&ses->server->inFlight) >= | 267 | if (atomic_read(&server->inFlight) >= cifs_max_pending) { |
258 | cifs_max_pending){ | ||
259 | spin_unlock(&GlobalMid_Lock); | 268 | spin_unlock(&GlobalMid_Lock); |
260 | #ifdef CONFIG_CIFS_STATS2 | 269 | #ifdef CONFIG_CIFS_STATS2 |
261 | atomic_inc(&ses->server->num_waiters); | 270 | atomic_inc(&server->num_waiters); |
262 | #endif | 271 | #endif |
263 | wait_event(ses->server->request_q, | 272 | wait_event(server->request_q, |
264 | atomic_read(&ses->server->inFlight) | 273 | atomic_read(&server->inFlight) |
265 | < cifs_max_pending); | 274 | < cifs_max_pending); |
266 | #ifdef CONFIG_CIFS_STATS2 | 275 | #ifdef CONFIG_CIFS_STATS2 |
267 | atomic_dec(&ses->server->num_waiters); | 276 | atomic_dec(&server->num_waiters); |
268 | #endif | 277 | #endif |
269 | spin_lock(&GlobalMid_Lock); | 278 | spin_lock(&GlobalMid_Lock); |
270 | } else { | 279 | } else { |
271 | if (ses->server->tcpStatus == CifsExiting) { | 280 | if (server->tcpStatus == CifsExiting) { |
272 | spin_unlock(&GlobalMid_Lock); | 281 | spin_unlock(&GlobalMid_Lock); |
273 | return -ENOENT; | 282 | return -ENOENT; |
274 | } | 283 | } |
@@ -278,7 +287,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
278 | 287 | ||
279 | /* update # of requests on the wire to server */ | 288 | /* update # of requests on the wire to server */ |
280 | if (long_op != CIFS_BLOCKING_OP) | 289 | if (long_op != CIFS_BLOCKING_OP) |
281 | atomic_inc(&ses->server->inFlight); | 290 | atomic_inc(&server->inFlight); |
282 | spin_unlock(&GlobalMid_Lock); | 291 | spin_unlock(&GlobalMid_Lock); |
283 | break; | 292 | break; |
284 | } | 293 | } |
@@ -286,7 +295,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
286 | return 0; | 295 | return 0; |
287 | } | 296 | } |
288 | 297 | ||
289 | static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | 298 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, |
290 | struct mid_q_entry **ppmidQ) | 299 | struct mid_q_entry **ppmidQ) |
291 | { | 300 | { |
292 | if (ses->server->tcpStatus == CifsExiting) { | 301 | if (ses->server->tcpStatus == CifsExiting) { |
@@ -308,53 +317,87 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | |||
308 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); | 317 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); |
309 | if (*ppmidQ == NULL) | 318 | if (*ppmidQ == NULL) |
310 | return -ENOMEM; | 319 | return -ENOMEM; |
320 | spin_lock(&GlobalMid_Lock); | ||
321 | list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q); | ||
322 | spin_unlock(&GlobalMid_Lock); | ||
311 | return 0; | 323 | return 0; |
312 | } | 324 | } |
313 | 325 | ||
314 | static int wait_for_response(struct cifsSesInfo *ses, | 326 | static int |
315 | struct mid_q_entry *midQ, | 327 | wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) |
316 | unsigned long timeout, | ||
317 | unsigned long time_to_wait) | ||
318 | { | 328 | { |
319 | unsigned long curr_timeout; | 329 | int error; |
320 | 330 | ||
321 | for (;;) { | 331 | error = wait_event_killable(server->response_q, |
322 | curr_timeout = timeout + jiffies; | 332 | midQ->midState != MID_REQUEST_SUBMITTED); |
323 | wait_event_timeout(ses->server->response_q, | 333 | if (error < 0) |
324 | midQ->midState != MID_REQUEST_SUBMITTED, timeout); | 334 | return -ERESTARTSYS; |
325 | 335 | ||
326 | if (time_after(jiffies, curr_timeout) && | 336 | return 0; |
327 | (midQ->midState == MID_REQUEST_SUBMITTED) && | 337 | } |
328 | ((ses->server->tcpStatus == CifsGood) || | ||
329 | (ses->server->tcpStatus == CifsNew))) { | ||
330 | 338 | ||
331 | unsigned long lrt; | ||
332 | 339 | ||
333 | /* We timed out. Is the server still | 340 | /* |
334 | sending replies ? */ | 341 | * Send a SMB request and set the callback function in the mid to handle |
335 | spin_lock(&GlobalMid_Lock); | 342 | * the result. Caller is responsible for dealing with timeouts. |
336 | lrt = ses->server->lstrp; | 343 | */ |
337 | spin_unlock(&GlobalMid_Lock); | 344 | int |
345 | cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | ||
346 | unsigned int nvec, mid_callback_t *callback, void *cbdata, | ||
347 | bool ignore_pend) | ||
348 | { | ||
349 | int rc; | ||
350 | struct mid_q_entry *mid; | ||
351 | struct smb_hdr *hdr = (struct smb_hdr *)iov[0].iov_base; | ||
338 | 352 | ||
339 | /* Calculate time_to_wait past last receive time. | 353 | rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0); |
340 | Although we prefer not to time out if the | 354 | if (rc) |
341 | server is still responding - we will time | 355 | return rc; |
342 | out if the server takes more than 15 (or 45 | 356 | |
343 | or 180) seconds to respond to this request | 357 | /* enable signing if server requires it */ |
344 | and has not responded to any request from | 358 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
345 | other threads on the client within 10 seconds */ | 359 | hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
346 | lrt += time_to_wait; | 360 | |
347 | if (time_after(jiffies, lrt)) { | 361 | mutex_lock(&server->srv_mutex); |
348 | /* No replies for time_to_wait. */ | 362 | mid = AllocMidQEntry(hdr, server); |
349 | cERROR(1, "server not responding"); | 363 | if (mid == NULL) { |
350 | return -1; | 364 | mutex_unlock(&server->srv_mutex); |
351 | } | 365 | return -ENOMEM; |
352 | } else { | ||
353 | return 0; | ||
354 | } | ||
355 | } | 366 | } |
356 | } | ||
357 | 367 | ||
368 | /* put it on the pending_mid_q */ | ||
369 | spin_lock(&GlobalMid_Lock); | ||
370 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
371 | spin_unlock(&GlobalMid_Lock); | ||
372 | |||
373 | rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); | ||
374 | if (rc) { | ||
375 | mutex_unlock(&server->srv_mutex); | ||
376 | goto out_err; | ||
377 | } | ||
378 | |||
379 | mid->callback = callback; | ||
380 | mid->callback_data = cbdata; | ||
381 | mid->midState = MID_REQUEST_SUBMITTED; | ||
382 | #ifdef CONFIG_CIFS_STATS2 | ||
383 | atomic_inc(&server->inSend); | ||
384 | #endif | ||
385 | rc = smb_sendv(server, iov, nvec); | ||
386 | #ifdef CONFIG_CIFS_STATS2 | ||
387 | atomic_dec(&server->inSend); | ||
388 | mid->when_sent = jiffies; | ||
389 | #endif | ||
390 | mutex_unlock(&server->srv_mutex); | ||
391 | if (rc) | ||
392 | goto out_err; | ||
393 | |||
394 | return rc; | ||
395 | out_err: | ||
396 | delete_mid(mid); | ||
397 | atomic_dec(&server->inFlight); | ||
398 | wake_up(&server->request_q); | ||
399 | return rc; | ||
400 | } | ||
358 | 401 | ||
359 | /* | 402 | /* |
360 | * | 403 | * |
@@ -366,7 +409,7 @@ static int wait_for_response(struct cifsSesInfo *ses, | |||
366 | * | 409 | * |
367 | */ | 410 | */ |
368 | int | 411 | int |
369 | SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | 412 | SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, |
370 | struct smb_hdr *in_buf, int flags) | 413 | struct smb_hdr *in_buf, int flags) |
371 | { | 414 | { |
372 | int rc; | 415 | int rc; |
@@ -374,7 +417,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |||
374 | int resp_buf_type; | 417 | int resp_buf_type; |
375 | 418 | ||
376 | iov[0].iov_base = (char *)in_buf; | 419 | iov[0].iov_base = (char *)in_buf; |
377 | iov[0].iov_len = in_buf->smb_buf_length + 4; | 420 | iov[0].iov_len = be32_to_cpu(in_buf->smb_buf_length) + 4; |
378 | flags |= CIFS_NO_RESP; | 421 | flags |= CIFS_NO_RESP; |
379 | rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); | 422 | rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags); |
380 | cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc); | 423 | cFYI(DBG2, "SendRcvNoRsp flags %d rc %d", flags, rc); |
@@ -382,15 +425,103 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |||
382 | return rc; | 425 | return rc; |
383 | } | 426 | } |
384 | 427 | ||
428 | static int | ||
429 | cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) | ||
430 | { | ||
431 | int rc = 0; | ||
432 | |||
433 | cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command, | ||
434 | mid->mid, mid->midState); | ||
435 | |||
436 | spin_lock(&GlobalMid_Lock); | ||
437 | switch (mid->midState) { | ||
438 | case MID_RESPONSE_RECEIVED: | ||
439 | spin_unlock(&GlobalMid_Lock); | ||
440 | return rc; | ||
441 | case MID_RETRY_NEEDED: | ||
442 | rc = -EAGAIN; | ||
443 | break; | ||
444 | case MID_RESPONSE_MALFORMED: | ||
445 | rc = -EIO; | ||
446 | break; | ||
447 | case MID_SHUTDOWN: | ||
448 | rc = -EHOSTDOWN; | ||
449 | break; | ||
450 | default: | ||
451 | list_del_init(&mid->qhead); | ||
452 | cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, | ||
453 | mid->mid, mid->midState); | ||
454 | rc = -EIO; | ||
455 | } | ||
456 | spin_unlock(&GlobalMid_Lock); | ||
457 | |||
458 | DeleteMidQEntry(mid); | ||
459 | return rc; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * An NT cancel request header looks just like the original request except: | ||
464 | * | ||
465 | * The Command is SMB_COM_NT_CANCEL | ||
466 | * The WordCount is zeroed out | ||
467 | * The ByteCount is zeroed out | ||
468 | * | ||
469 | * This function mangles an existing request buffer into a | ||
470 | * SMB_COM_NT_CANCEL request and then sends it. | ||
471 | */ | ||
472 | static int | ||
473 | send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
474 | struct mid_q_entry *mid) | ||
475 | { | ||
476 | int rc = 0; | ||
477 | |||
478 | /* -4 for RFC1001 length and +2 for BCC field */ | ||
479 | in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); | ||
480 | in_buf->Command = SMB_COM_NT_CANCEL; | ||
481 | in_buf->WordCount = 0; | ||
482 | put_bcc(0, in_buf); | ||
483 | |||
484 | mutex_lock(&server->srv_mutex); | ||
485 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
486 | if (rc) { | ||
487 | mutex_unlock(&server->srv_mutex); | ||
488 | return rc; | ||
489 | } | ||
490 | rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); | ||
491 | mutex_unlock(&server->srv_mutex); | ||
492 | |||
493 | cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", | ||
494 | in_buf->Mid, rc); | ||
495 | |||
496 | return rc; | ||
497 | } | ||
498 | |||
385 | int | 499 | int |
386 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 500 | cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, |
501 | bool log_error) | ||
502 | { | ||
503 | dump_smb(mid->resp_buf, | ||
504 | min_t(u32, 92, be32_to_cpu(mid->resp_buf->smb_buf_length))); | ||
505 | |||
506 | /* convert the length into a more usable form */ | ||
507 | if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | ||
508 | /* FIXME: add code to kill session */ | ||
509 | if (cifs_verify_signature(mid->resp_buf, server, | ||
510 | mid->sequence_number + 1) != 0) | ||
511 | cERROR(1, "Unexpected SMB signature"); | ||
512 | } | ||
513 | |||
514 | /* BB special case reconnect tid and uid here? */ | ||
515 | return map_smb_to_linux_error(mid->resp_buf, log_error); | ||
516 | } | ||
517 | |||
518 | int | ||
519 | SendReceive2(const unsigned int xid, struct cifs_ses *ses, | ||
387 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, | 520 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
388 | const int flags) | 521 | const int flags) |
389 | { | 522 | { |
390 | int rc = 0; | 523 | int rc = 0; |
391 | int long_op; | 524 | int long_op; |
392 | unsigned int receive_len; | ||
393 | unsigned long timeout; | ||
394 | struct mid_q_entry *midQ; | 525 | struct mid_q_entry *midQ; |
395 | struct smb_hdr *in_buf = iov[0].iov_base; | 526 | struct smb_hdr *in_buf = iov[0].iov_base; |
396 | 527 | ||
@@ -413,7 +544,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
413 | to the same server. We may make this configurable later or | 544 | to the same server. We may make this configurable later or |
414 | use ses->maxReq */ | 545 | use ses->maxReq */ |
415 | 546 | ||
416 | rc = wait_for_free_request(ses, long_op); | 547 | rc = wait_for_free_request(ses->server, long_op); |
417 | if (rc) { | 548 | if (rc) { |
418 | cifs_small_buf_release(in_buf); | 549 | cifs_small_buf_release(in_buf); |
419 | return rc; | 550 | return rc; |
@@ -452,126 +583,61 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
452 | #endif | 583 | #endif |
453 | 584 | ||
454 | mutex_unlock(&ses->server->srv_mutex); | 585 | mutex_unlock(&ses->server->srv_mutex); |
455 | cifs_small_buf_release(in_buf); | ||
456 | 586 | ||
457 | if (rc < 0) | 587 | if (rc < 0) { |
458 | goto out; | 588 | cifs_small_buf_release(in_buf); |
459 | |||
460 | if (long_op == CIFS_STD_OP) | ||
461 | timeout = 15 * HZ; | ||
462 | else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ | ||
463 | timeout = 180 * HZ; | ||
464 | else if (long_op == CIFS_LONG_OP) | ||
465 | timeout = 45 * HZ; /* should be greater than | ||
466 | servers oplock break timeout (about 43 seconds) */ | ||
467 | else if (long_op == CIFS_ASYNC_OP) | ||
468 | goto out; | ||
469 | else if (long_op == CIFS_BLOCKING_OP) | ||
470 | timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ | ||
471 | else { | ||
472 | cERROR(1, "unknown timeout flag %d", long_op); | ||
473 | rc = -EIO; | ||
474 | goto out; | 589 | goto out; |
475 | } | 590 | } |
476 | 591 | ||
477 | /* wait for 15 seconds or until woken up due to response arriving or | 592 | if (long_op == CIFS_ASYNC_OP) { |
478 | due to last connection to this server being unmounted */ | 593 | cifs_small_buf_release(in_buf); |
479 | if (signal_pending(current)) { | 594 | goto out; |
480 | /* if signal pending do not hold up user for full smb timeout | ||
481 | but we still give response a chance to complete */ | ||
482 | timeout = 2 * HZ; | ||
483 | } | 595 | } |
484 | 596 | ||
485 | /* No user interrupts in wait - wreaks havoc with performance */ | 597 | rc = wait_for_response(ses->server, midQ); |
486 | wait_for_response(ses, midQ, timeout, 10 * HZ); | 598 | if (rc != 0) { |
487 | 599 | send_nt_cancel(ses->server, in_buf, midQ); | |
488 | spin_lock(&GlobalMid_Lock); | 600 | spin_lock(&GlobalMid_Lock); |
489 | |||
490 | if (midQ->resp_buf == NULL) { | ||
491 | cERROR(1, "No response to cmd %d mid %d", | ||
492 | midQ->command, midQ->mid); | ||
493 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | 601 | if (midQ->midState == MID_REQUEST_SUBMITTED) { |
494 | if (ses->server->tcpStatus == CifsExiting) | 602 | midQ->callback = DeleteMidQEntry; |
495 | rc = -EHOSTDOWN; | 603 | spin_unlock(&GlobalMid_Lock); |
496 | else { | 604 | cifs_small_buf_release(in_buf); |
497 | ses->server->tcpStatus = CifsNeedReconnect; | 605 | atomic_dec(&ses->server->inFlight); |
498 | midQ->midState = MID_RETRY_NEEDED; | 606 | wake_up(&ses->server->request_q); |
499 | } | 607 | return rc; |
500 | } | ||
501 | |||
502 | if (rc != -EHOSTDOWN) { | ||
503 | if (midQ->midState == MID_RETRY_NEEDED) { | ||
504 | rc = -EAGAIN; | ||
505 | cFYI(1, "marking request for retry"); | ||
506 | } else { | ||
507 | rc = -EIO; | ||
508 | } | ||
509 | } | 608 | } |
510 | spin_unlock(&GlobalMid_Lock); | 609 | spin_unlock(&GlobalMid_Lock); |
511 | DeleteMidQEntry(midQ); | 610 | } |
512 | /* Update # of requests on wire to server */ | 611 | |
612 | cifs_small_buf_release(in_buf); | ||
613 | |||
614 | rc = cifs_sync_mid_result(midQ, ses->server); | ||
615 | if (rc != 0) { | ||
513 | atomic_dec(&ses->server->inFlight); | 616 | atomic_dec(&ses->server->inFlight); |
514 | wake_up(&ses->server->request_q); | 617 | wake_up(&ses->server->request_q); |
515 | return rc; | 618 | return rc; |
516 | } | 619 | } |
517 | 620 | ||
518 | spin_unlock(&GlobalMid_Lock); | 621 | if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) { |
519 | receive_len = midQ->resp_buf->smb_buf_length; | ||
520 | |||
521 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | ||
522 | cERROR(1, "Frame too large received. Length: %d Xid: %d", | ||
523 | receive_len, xid); | ||
524 | rc = -EIO; | 622 | rc = -EIO; |
623 | cFYI(1, "Bad MID state?"); | ||
525 | goto out; | 624 | goto out; |
526 | } | 625 | } |
527 | 626 | ||
528 | /* rcvd frame is ok */ | 627 | iov[0].iov_base = (char *)midQ->resp_buf; |
628 | iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4; | ||
629 | if (midQ->largeBuf) | ||
630 | *pRespBufType = CIFS_LARGE_BUFFER; | ||
631 | else | ||
632 | *pRespBufType = CIFS_SMALL_BUFFER; | ||
529 | 633 | ||
530 | if (midQ->resp_buf && | 634 | rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR); |
531 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
532 | |||
533 | iov[0].iov_base = (char *)midQ->resp_buf; | ||
534 | if (midQ->largeBuf) | ||
535 | *pRespBufType = CIFS_LARGE_BUFFER; | ||
536 | else | ||
537 | *pRespBufType = CIFS_SMALL_BUFFER; | ||
538 | iov[0].iov_len = receive_len + 4; | ||
539 | |||
540 | dump_smb(midQ->resp_buf, 80); | ||
541 | /* convert the length into a more usable form */ | ||
542 | if ((receive_len > 24) && | ||
543 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
544 | SECMODE_SIGN_ENABLED))) { | ||
545 | rc = cifs_verify_signature(midQ->resp_buf, | ||
546 | &ses->server->mac_signing_key, | ||
547 | midQ->sequence_number+1); | ||
548 | if (rc) { | ||
549 | cERROR(1, "Unexpected SMB signature"); | ||
550 | /* BB FIXME add code to kill session */ | ||
551 | } | ||
552 | } | ||
553 | |||
554 | /* BB special case reconnect tid and uid here? */ | ||
555 | rc = map_smb_to_linux_error(midQ->resp_buf, | ||
556 | flags & CIFS_LOG_ERROR); | ||
557 | |||
558 | /* convert ByteCount if necessary */ | ||
559 | if (receive_len >= sizeof(struct smb_hdr) - 4 | ||
560 | /* do not count RFC1001 header */ + | ||
561 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) | ||
562 | BCC(midQ->resp_buf) = | ||
563 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
564 | if ((flags & CIFS_NO_RESP) == 0) | ||
565 | midQ->resp_buf = NULL; /* mark it so buf will | ||
566 | not be freed by | ||
567 | DeleteMidQEntry */ | ||
568 | } else { | ||
569 | rc = -EIO; | ||
570 | cFYI(1, "Bad MID state?"); | ||
571 | } | ||
572 | 635 | ||
636 | /* mark it so buf will not be freed by delete_mid */ | ||
637 | if ((flags & CIFS_NO_RESP) == 0) | ||
638 | midQ->resp_buf = NULL; | ||
573 | out: | 639 | out: |
574 | DeleteMidQEntry(midQ); | 640 | delete_mid(midQ); |
575 | atomic_dec(&ses->server->inFlight); | 641 | atomic_dec(&ses->server->inFlight); |
576 | wake_up(&ses->server->request_q); | 642 | wake_up(&ses->server->request_q); |
577 | 643 | ||
@@ -579,13 +645,11 @@ out: | |||
579 | } | 645 | } |
580 | 646 | ||
581 | int | 647 | int |
582 | SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | 648 | SendReceive(const unsigned int xid, struct cifs_ses *ses, |
583 | struct smb_hdr *in_buf, struct smb_hdr *out_buf, | 649 | struct smb_hdr *in_buf, struct smb_hdr *out_buf, |
584 | int *pbytes_returned, const int long_op) | 650 | int *pbytes_returned, const int long_op) |
585 | { | 651 | { |
586 | int rc = 0; | 652 | int rc = 0; |
587 | unsigned int receive_len; | ||
588 | unsigned long timeout; | ||
589 | struct mid_q_entry *midQ; | 653 | struct mid_q_entry *midQ; |
590 | 654 | ||
591 | if (ses == NULL) { | 655 | if (ses == NULL) { |
@@ -604,13 +668,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
604 | to the same server. We may make this configurable later or | 668 | to the same server. We may make this configurable later or |
605 | use ses->maxReq */ | 669 | use ses->maxReq */ |
606 | 670 | ||
607 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 671 | if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + |
672 | MAX_CIFS_HDR_SIZE - 4) { | ||
608 | cERROR(1, "Illegal length, greater than maximum frame, %d", | 673 | cERROR(1, "Illegal length, greater than maximum frame, %d", |
609 | in_buf->smb_buf_length); | 674 | be32_to_cpu(in_buf->smb_buf_length)); |
610 | return -EIO; | 675 | return -EIO; |
611 | } | 676 | } |
612 | 677 | ||
613 | rc = wait_for_free_request(ses, long_op); | 678 | rc = wait_for_free_request(ses->server, long_op); |
614 | if (rc) | 679 | if (rc) |
615 | return rc; | 680 | return rc; |
616 | 681 | ||
@@ -639,7 +704,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
639 | #ifdef CONFIG_CIFS_STATS2 | 704 | #ifdef CONFIG_CIFS_STATS2 |
640 | atomic_inc(&ses->server->inSend); | 705 | atomic_inc(&ses->server->inSend); |
641 | #endif | 706 | #endif |
642 | rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); | 707 | rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); |
643 | #ifdef CONFIG_CIFS_STATS2 | 708 | #ifdef CONFIG_CIFS_STATS2 |
644 | atomic_dec(&ses->server->inSend); | 709 | atomic_dec(&ses->server->inSend); |
645 | midQ->when_sent = jiffies; | 710 | midQ->when_sent = jiffies; |
@@ -649,152 +714,59 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
649 | if (rc < 0) | 714 | if (rc < 0) |
650 | goto out; | 715 | goto out; |
651 | 716 | ||
652 | if (long_op == CIFS_STD_OP) | 717 | if (long_op == CIFS_ASYNC_OP) |
653 | timeout = 15 * HZ; | ||
654 | /* wait for 15 seconds or until woken up due to response arriving or | ||
655 | due to last connection to this server being unmounted */ | ||
656 | else if (long_op == CIFS_ASYNC_OP) | ||
657 | goto out; | ||
658 | else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ | ||
659 | timeout = 180 * HZ; | ||
660 | else if (long_op == CIFS_LONG_OP) | ||
661 | timeout = 45 * HZ; /* should be greater than | ||
662 | servers oplock break timeout (about 43 seconds) */ | ||
663 | else if (long_op == CIFS_BLOCKING_OP) | ||
664 | timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ | ||
665 | else { | ||
666 | cERROR(1, "unknown timeout flag %d", long_op); | ||
667 | rc = -EIO; | ||
668 | goto out; | 718 | goto out; |
669 | } | ||
670 | |||
671 | if (signal_pending(current)) { | ||
672 | /* if signal pending do not hold up user for full smb timeout | ||
673 | but we still give response a chance to complete */ | ||
674 | timeout = 2 * HZ; | ||
675 | } | ||
676 | 719 | ||
677 | /* No user interrupts in wait - wreaks havoc with performance */ | 720 | rc = wait_for_response(ses->server, midQ); |
678 | wait_for_response(ses, midQ, timeout, 10 * HZ); | 721 | if (rc != 0) { |
679 | 722 | send_nt_cancel(ses->server, in_buf, midQ); | |
680 | spin_lock(&GlobalMid_Lock); | 723 | spin_lock(&GlobalMid_Lock); |
681 | if (midQ->resp_buf == NULL) { | ||
682 | cERROR(1, "No response for cmd %d mid %d", | ||
683 | midQ->command, midQ->mid); | ||
684 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | 724 | if (midQ->midState == MID_REQUEST_SUBMITTED) { |
685 | if (ses->server->tcpStatus == CifsExiting) | 725 | /* no longer considered to be "in-flight" */ |
686 | rc = -EHOSTDOWN; | 726 | midQ->callback = DeleteMidQEntry; |
687 | else { | 727 | spin_unlock(&GlobalMid_Lock); |
688 | ses->server->tcpStatus = CifsNeedReconnect; | 728 | atomic_dec(&ses->server->inFlight); |
689 | midQ->midState = MID_RETRY_NEEDED; | 729 | wake_up(&ses->server->request_q); |
690 | } | 730 | return rc; |
691 | } | ||
692 | |||
693 | if (rc != -EHOSTDOWN) { | ||
694 | if (midQ->midState == MID_RETRY_NEEDED) { | ||
695 | rc = -EAGAIN; | ||
696 | cFYI(1, "marking request for retry"); | ||
697 | } else { | ||
698 | rc = -EIO; | ||
699 | } | ||
700 | } | 731 | } |
701 | spin_unlock(&GlobalMid_Lock); | 732 | spin_unlock(&GlobalMid_Lock); |
702 | DeleteMidQEntry(midQ); | 733 | } |
703 | /* Update # of requests on wire to server */ | 734 | |
735 | rc = cifs_sync_mid_result(midQ, ses->server); | ||
736 | if (rc != 0) { | ||
704 | atomic_dec(&ses->server->inFlight); | 737 | atomic_dec(&ses->server->inFlight); |
705 | wake_up(&ses->server->request_q); | 738 | wake_up(&ses->server->request_q); |
706 | return rc; | 739 | return rc; |
707 | } | 740 | } |
708 | 741 | ||
709 | spin_unlock(&GlobalMid_Lock); | 742 | if (!midQ->resp_buf || !out_buf || |
710 | receive_len = midQ->resp_buf->smb_buf_length; | 743 | midQ->midState != MID_RESPONSE_RECEIVED) { |
711 | |||
712 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | ||
713 | cERROR(1, "Frame too large received. Length: %d Xid: %d", | ||
714 | receive_len, xid); | ||
715 | rc = -EIO; | ||
716 | goto out; | ||
717 | } | ||
718 | |||
719 | /* rcvd frame is ok */ | ||
720 | |||
721 | if (midQ->resp_buf && out_buf | ||
722 | && (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
723 | out_buf->smb_buf_length = receive_len; | ||
724 | memcpy((char *)out_buf + 4, | ||
725 | (char *)midQ->resp_buf + 4, | ||
726 | receive_len); | ||
727 | |||
728 | dump_smb(out_buf, 92); | ||
729 | /* convert the length into a more usable form */ | ||
730 | if ((receive_len > 24) && | ||
731 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
732 | SECMODE_SIGN_ENABLED))) { | ||
733 | rc = cifs_verify_signature(out_buf, | ||
734 | &ses->server->mac_signing_key, | ||
735 | midQ->sequence_number+1); | ||
736 | if (rc) { | ||
737 | cERROR(1, "Unexpected SMB signature"); | ||
738 | /* BB FIXME add code to kill session */ | ||
739 | } | ||
740 | } | ||
741 | |||
742 | *pbytes_returned = out_buf->smb_buf_length; | ||
743 | |||
744 | /* BB special case reconnect tid and uid here? */ | ||
745 | rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); | ||
746 | |||
747 | /* convert ByteCount if necessary */ | ||
748 | if (receive_len >= sizeof(struct smb_hdr) - 4 | ||
749 | /* do not count RFC1001 header */ + | ||
750 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | ||
751 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | ||
752 | } else { | ||
753 | rc = -EIO; | 744 | rc = -EIO; |
754 | cERROR(1, "Bad MID state?"); | 745 | cERROR(1, "Bad MID state?"); |
746 | goto out; | ||
755 | } | 747 | } |
756 | 748 | ||
749 | *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length); | ||
750 | memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); | ||
751 | rc = cifs_check_receive(midQ, ses->server, 0); | ||
757 | out: | 752 | out: |
758 | DeleteMidQEntry(midQ); | 753 | delete_mid(midQ); |
759 | atomic_dec(&ses->server->inFlight); | 754 | atomic_dec(&ses->server->inFlight); |
760 | wake_up(&ses->server->request_q); | 755 | wake_up(&ses->server->request_q); |
761 | 756 | ||
762 | return rc; | 757 | return rc; |
763 | } | 758 | } |
764 | 759 | ||
765 | /* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */ | ||
766 | |||
767 | static int | ||
768 | send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | ||
769 | struct mid_q_entry *midQ) | ||
770 | { | ||
771 | int rc = 0; | ||
772 | struct cifsSesInfo *ses = tcon->ses; | ||
773 | __u16 mid = in_buf->Mid; | ||
774 | |||
775 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); | ||
776 | in_buf->Mid = mid; | ||
777 | mutex_lock(&ses->server->srv_mutex); | ||
778 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
779 | if (rc) { | ||
780 | mutex_unlock(&ses->server->srv_mutex); | ||
781 | return rc; | ||
782 | } | ||
783 | rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); | ||
784 | mutex_unlock(&ses->server->srv_mutex); | ||
785 | return rc; | ||
786 | } | ||
787 | |||
788 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows | 760 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows |
789 | blocking lock to return. */ | 761 | blocking lock to return. */ |
790 | 762 | ||
791 | static int | 763 | static int |
792 | send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | 764 | send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon, |
793 | struct smb_hdr *in_buf, | 765 | struct smb_hdr *in_buf, |
794 | struct smb_hdr *out_buf) | 766 | struct smb_hdr *out_buf) |
795 | { | 767 | { |
796 | int bytes_returned; | 768 | int bytes_returned; |
797 | struct cifsSesInfo *ses = tcon->ses; | 769 | struct cifs_ses *ses = tcon->ses; |
798 | LOCK_REQ *pSMB = (LOCK_REQ *)in_buf; | 770 | LOCK_REQ *pSMB = (LOCK_REQ *)in_buf; |
799 | 771 | ||
800 | /* We just modify the current in_buf to change | 772 | /* We just modify the current in_buf to change |
@@ -807,19 +779,18 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | |||
807 | pSMB->hdr.Mid = GetNextMid(ses->server); | 779 | pSMB->hdr.Mid = GetNextMid(ses->server); |
808 | 780 | ||
809 | return SendReceive(xid, ses, in_buf, out_buf, | 781 | return SendReceive(xid, ses, in_buf, out_buf, |
810 | &bytes_returned, CIFS_STD_OP); | 782 | &bytes_returned, 0); |
811 | } | 783 | } |
812 | 784 | ||
813 | int | 785 | int |
814 | SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | 786 | SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, |
815 | struct smb_hdr *in_buf, struct smb_hdr *out_buf, | 787 | struct smb_hdr *in_buf, struct smb_hdr *out_buf, |
816 | int *pbytes_returned) | 788 | int *pbytes_returned) |
817 | { | 789 | { |
818 | int rc = 0; | 790 | int rc = 0; |
819 | int rstart = 0; | 791 | int rstart = 0; |
820 | unsigned int receive_len; | ||
821 | struct mid_q_entry *midQ; | 792 | struct mid_q_entry *midQ; |
822 | struct cifsSesInfo *ses; | 793 | struct cifs_ses *ses; |
823 | 794 | ||
824 | if (tcon == NULL || tcon->ses == NULL) { | 795 | if (tcon == NULL || tcon->ses == NULL) { |
825 | cERROR(1, "Null smb session"); | 796 | cERROR(1, "Null smb session"); |
@@ -839,13 +810,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
839 | to the same server. We may make this configurable later or | 810 | to the same server. We may make this configurable later or |
840 | use ses->maxReq */ | 811 | use ses->maxReq */ |
841 | 812 | ||
842 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 813 | if (be32_to_cpu(in_buf->smb_buf_length) > CIFSMaxBufSize + |
814 | MAX_CIFS_HDR_SIZE - 4) { | ||
843 | cERROR(1, "Illegal length, greater than maximum frame, %d", | 815 | cERROR(1, "Illegal length, greater than maximum frame, %d", |
844 | in_buf->smb_buf_length); | 816 | be32_to_cpu(in_buf->smb_buf_length)); |
845 | return -EIO; | 817 | return -EIO; |
846 | } | 818 | } |
847 | 819 | ||
848 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); | 820 | rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP); |
849 | if (rc) | 821 | if (rc) |
850 | return rc; | 822 | return rc; |
851 | 823 | ||
@@ -863,7 +835,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
863 | 835 | ||
864 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 836 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
865 | if (rc) { | 837 | if (rc) { |
866 | DeleteMidQEntry(midQ); | 838 | delete_mid(midQ); |
867 | mutex_unlock(&ses->server->srv_mutex); | 839 | mutex_unlock(&ses->server->srv_mutex); |
868 | return rc; | 840 | return rc; |
869 | } | 841 | } |
@@ -872,7 +844,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
872 | #ifdef CONFIG_CIFS_STATS2 | 844 | #ifdef CONFIG_CIFS_STATS2 |
873 | atomic_inc(&ses->server->inSend); | 845 | atomic_inc(&ses->server->inSend); |
874 | #endif | 846 | #endif |
875 | rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); | 847 | rc = smb_send(ses->server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); |
876 | #ifdef CONFIG_CIFS_STATS2 | 848 | #ifdef CONFIG_CIFS_STATS2 |
877 | atomic_dec(&ses->server->inSend); | 849 | atomic_dec(&ses->server->inSend); |
878 | midQ->when_sent = jiffies; | 850 | midQ->when_sent = jiffies; |
@@ -880,7 +852,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
880 | mutex_unlock(&ses->server->srv_mutex); | 852 | mutex_unlock(&ses->server->srv_mutex); |
881 | 853 | ||
882 | if (rc < 0) { | 854 | if (rc < 0) { |
883 | DeleteMidQEntry(midQ); | 855 | delete_mid(midQ); |
884 | return rc; | 856 | return rc; |
885 | } | 857 | } |
886 | 858 | ||
@@ -899,10 +871,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
899 | if (in_buf->Command == SMB_COM_TRANSACTION2) { | 871 | if (in_buf->Command == SMB_COM_TRANSACTION2) { |
900 | /* POSIX lock. We send a NT_CANCEL SMB to cause the | 872 | /* POSIX lock. We send a NT_CANCEL SMB to cause the |
901 | blocking lock to return. */ | 873 | blocking lock to return. */ |
902 | 874 | rc = send_nt_cancel(ses->server, in_buf, midQ); | |
903 | rc = send_nt_cancel(tcon, in_buf, midQ); | ||
904 | if (rc) { | 875 | if (rc) { |
905 | DeleteMidQEntry(midQ); | 876 | delete_mid(midQ); |
906 | return rc; | 877 | return rc; |
907 | } | 878 | } |
908 | } else { | 879 | } else { |
@@ -914,94 +885,44 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
914 | /* If we get -ENOLCK back the lock may have | 885 | /* If we get -ENOLCK back the lock may have |
915 | already been removed. Don't exit in this case. */ | 886 | already been removed. Don't exit in this case. */ |
916 | if (rc && rc != -ENOLCK) { | 887 | if (rc && rc != -ENOLCK) { |
917 | DeleteMidQEntry(midQ); | 888 | delete_mid(midQ); |
918 | return rc; | 889 | return rc; |
919 | } | 890 | } |
920 | } | 891 | } |
921 | 892 | ||
922 | /* Wait 5 seconds for the response. */ | 893 | rc = wait_for_response(ses->server, midQ); |
923 | if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) { | 894 | if (rc) { |
924 | /* We got the response - restart system call. */ | 895 | send_nt_cancel(ses->server, in_buf, midQ); |
925 | rstart = 1; | 896 | spin_lock(&GlobalMid_Lock); |
926 | } | 897 | if (midQ->midState == MID_REQUEST_SUBMITTED) { |
927 | } | 898 | /* no longer considered to be "in-flight" */ |
928 | 899 | midQ->callback = DeleteMidQEntry; | |
929 | spin_lock(&GlobalMid_Lock); | 900 | spin_unlock(&GlobalMid_Lock); |
930 | if (midQ->resp_buf) { | 901 | return rc; |
931 | spin_unlock(&GlobalMid_Lock); | ||
932 | receive_len = midQ->resp_buf->smb_buf_length; | ||
933 | } else { | ||
934 | cERROR(1, "No response for cmd %d mid %d", | ||
935 | midQ->command, midQ->mid); | ||
936 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
937 | if (ses->server->tcpStatus == CifsExiting) | ||
938 | rc = -EHOSTDOWN; | ||
939 | else { | ||
940 | ses->server->tcpStatus = CifsNeedReconnect; | ||
941 | midQ->midState = MID_RETRY_NEEDED; | ||
942 | } | 902 | } |
903 | spin_unlock(&GlobalMid_Lock); | ||
943 | } | 904 | } |
944 | 905 | ||
945 | if (rc != -EHOSTDOWN) { | 906 | /* We got the response - restart system call. */ |
946 | if (midQ->midState == MID_RETRY_NEEDED) { | 907 | rstart = 1; |
947 | rc = -EAGAIN; | ||
948 | cFYI(1, "marking request for retry"); | ||
949 | } else { | ||
950 | rc = -EIO; | ||
951 | } | ||
952 | } | ||
953 | spin_unlock(&GlobalMid_Lock); | ||
954 | DeleteMidQEntry(midQ); | ||
955 | return rc; | ||
956 | } | 908 | } |
957 | 909 | ||
958 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 910 | rc = cifs_sync_mid_result(midQ, ses->server); |
959 | cERROR(1, "Frame too large received. Length: %d Xid: %d", | 911 | if (rc != 0) |
960 | receive_len, xid); | 912 | return rc; |
961 | rc = -EIO; | ||
962 | goto out; | ||
963 | } | ||
964 | 913 | ||
965 | /* rcvd frame is ok */ | 914 | /* rcvd frame is ok */ |
966 | 915 | if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) { | |
967 | if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) { | ||
968 | rc = -EIO; | 916 | rc = -EIO; |
969 | cERROR(1, "Bad MID state?"); | 917 | cERROR(1, "Bad MID state?"); |
970 | goto out; | 918 | goto out; |
971 | } | 919 | } |
972 | 920 | ||
973 | out_buf->smb_buf_length = receive_len; | 921 | *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length); |
974 | memcpy((char *)out_buf + 4, | 922 | memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); |
975 | (char *)midQ->resp_buf + 4, | 923 | rc = cifs_check_receive(midQ, ses->server, 0); |
976 | receive_len); | ||
977 | |||
978 | dump_smb(out_buf, 92); | ||
979 | /* convert the length into a more usable form */ | ||
980 | if ((receive_len > 24) && | ||
981 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
982 | SECMODE_SIGN_ENABLED))) { | ||
983 | rc = cifs_verify_signature(out_buf, | ||
984 | &ses->server->mac_signing_key, | ||
985 | midQ->sequence_number+1); | ||
986 | if (rc) { | ||
987 | cERROR(1, "Unexpected SMB signature"); | ||
988 | /* BB FIXME add code to kill session */ | ||
989 | } | ||
990 | } | ||
991 | |||
992 | *pbytes_returned = out_buf->smb_buf_length; | ||
993 | |||
994 | /* BB special case reconnect tid and uid here? */ | ||
995 | rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); | ||
996 | |||
997 | /* convert ByteCount if necessary */ | ||
998 | if (receive_len >= sizeof(struct smb_hdr) - 4 | ||
999 | /* do not count RFC1001 header */ + | ||
1000 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | ||
1001 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | ||
1002 | |||
1003 | out: | 924 | out: |
1004 | DeleteMidQEntry(midQ); | 925 | delete_mid(midQ); |
1005 | if (rstart && rc == -EACCES) | 926 | if (rstart && rc == -EACCES) |
1006 | return -ERESTARTSYS; | 927 | return -ERESTARTSYS; |
1007 | return rc; | 928 | return rc; |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index a1509207bfa6..2a22fb2989e4 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -30,10 +30,11 @@ | |||
30 | 30 | ||
31 | #define MAX_EA_VALUE_SIZE 65535 | 31 | #define MAX_EA_VALUE_SIZE 65535 |
32 | #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" | 32 | #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" |
33 | #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" | ||
33 | #define CIFS_XATTR_USER_PREFIX "user." | 34 | #define CIFS_XATTR_USER_PREFIX "user." |
34 | #define CIFS_XATTR_SYSTEM_PREFIX "system." | 35 | #define CIFS_XATTR_SYSTEM_PREFIX "system." |
35 | #define CIFS_XATTR_OS2_PREFIX "os2." | 36 | #define CIFS_XATTR_OS2_PREFIX "os2." |
36 | #define CIFS_XATTR_SECURITY_PREFIX ".security" | 37 | #define CIFS_XATTR_SECURITY_PREFIX "security." |
37 | #define CIFS_XATTR_TRUSTED_PREFIX "trusted." | 38 | #define CIFS_XATTR_TRUSTED_PREFIX "trusted." |
38 | #define XATTR_TRUSTED_PREFIX_LEN 8 | 39 | #define XATTR_TRUSTED_PREFIX_LEN 8 |
39 | #define XATTR_SECURITY_PREFIX_LEN 9 | 40 | #define XATTR_SECURITY_PREFIX_LEN 9 |
@@ -47,9 +48,10 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) | |||
47 | #ifdef CONFIG_CIFS_XATTR | 48 | #ifdef CONFIG_CIFS_XATTR |
48 | int xid; | 49 | int xid; |
49 | struct cifs_sb_info *cifs_sb; | 50 | struct cifs_sb_info *cifs_sb; |
50 | struct cifsTconInfo *pTcon; | 51 | struct tcon_link *tlink; |
52 | struct cifs_tcon *pTcon; | ||
51 | struct super_block *sb; | 53 | struct super_block *sb; |
52 | char *full_path; | 54 | char *full_path = NULL; |
53 | 55 | ||
54 | if (direntry == NULL) | 56 | if (direntry == NULL) |
55 | return -EIO; | 57 | return -EIO; |
@@ -58,16 +60,19 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) | |||
58 | sb = direntry->d_inode->i_sb; | 60 | sb = direntry->d_inode->i_sb; |
59 | if (sb == NULL) | 61 | if (sb == NULL) |
60 | return -EIO; | 62 | return -EIO; |
61 | xid = GetXid(); | ||
62 | 63 | ||
63 | cifs_sb = CIFS_SB(sb); | 64 | cifs_sb = CIFS_SB(sb); |
64 | pTcon = cifs_sb->tcon; | 65 | tlink = cifs_sb_tlink(cifs_sb); |
66 | if (IS_ERR(tlink)) | ||
67 | return PTR_ERR(tlink); | ||
68 | pTcon = tlink_tcon(tlink); | ||
69 | |||
70 | xid = GetXid(); | ||
65 | 71 | ||
66 | full_path = build_path_from_dentry(direntry); | 72 | full_path = build_path_from_dentry(direntry); |
67 | if (full_path == NULL) { | 73 | if (full_path == NULL) { |
68 | rc = -ENOMEM; | 74 | rc = -ENOMEM; |
69 | FreeXid(xid); | 75 | goto remove_ea_exit; |
70 | return rc; | ||
71 | } | 76 | } |
72 | if (ea_name == NULL) { | 77 | if (ea_name == NULL) { |
73 | cFYI(1, "Null xattr names not supported"); | 78 | cFYI(1, "Null xattr names not supported"); |
@@ -91,6 +96,7 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) | |||
91 | remove_ea_exit: | 96 | remove_ea_exit: |
92 | kfree(full_path); | 97 | kfree(full_path); |
93 | FreeXid(xid); | 98 | FreeXid(xid); |
99 | cifs_put_tlink(tlink); | ||
94 | #endif | 100 | #endif |
95 | return rc; | 101 | return rc; |
96 | } | 102 | } |
@@ -102,9 +108,11 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
102 | #ifdef CONFIG_CIFS_XATTR | 108 | #ifdef CONFIG_CIFS_XATTR |
103 | int xid; | 109 | int xid; |
104 | struct cifs_sb_info *cifs_sb; | 110 | struct cifs_sb_info *cifs_sb; |
105 | struct cifsTconInfo *pTcon; | 111 | struct tcon_link *tlink; |
112 | struct cifs_tcon *pTcon; | ||
106 | struct super_block *sb; | 113 | struct super_block *sb; |
107 | char *full_path; | 114 | char *full_path; |
115 | struct cifs_ntsd *pacl; | ||
108 | 116 | ||
109 | if (direntry == NULL) | 117 | if (direntry == NULL) |
110 | return -EIO; | 118 | return -EIO; |
@@ -113,16 +121,19 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
113 | sb = direntry->d_inode->i_sb; | 121 | sb = direntry->d_inode->i_sb; |
114 | if (sb == NULL) | 122 | if (sb == NULL) |
115 | return -EIO; | 123 | return -EIO; |
116 | xid = GetXid(); | ||
117 | 124 | ||
118 | cifs_sb = CIFS_SB(sb); | 125 | cifs_sb = CIFS_SB(sb); |
119 | pTcon = cifs_sb->tcon; | 126 | tlink = cifs_sb_tlink(cifs_sb); |
127 | if (IS_ERR(tlink)) | ||
128 | return PTR_ERR(tlink); | ||
129 | pTcon = tlink_tcon(tlink); | ||
130 | |||
131 | xid = GetXid(); | ||
120 | 132 | ||
121 | full_path = build_path_from_dentry(direntry); | 133 | full_path = build_path_from_dentry(direntry); |
122 | if (full_path == NULL) { | 134 | if (full_path == NULL) { |
123 | rc = -ENOMEM; | 135 | rc = -ENOMEM; |
124 | FreeXid(xid); | 136 | goto set_ea_exit; |
125 | return rc; | ||
126 | } | 137 | } |
127 | /* return dos attributes as pseudo xattr */ | 138 | /* return dos attributes as pseudo xattr */ |
128 | /* return alt name if available as pseudo attr */ | 139 | /* return alt name if available as pseudo attr */ |
@@ -132,9 +143,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
132 | returns as xattrs */ | 143 | returns as xattrs */ |
133 | if (value_size > MAX_EA_VALUE_SIZE) { | 144 | if (value_size > MAX_EA_VALUE_SIZE) { |
134 | cFYI(1, "size of EA value too large"); | 145 | cFYI(1, "size of EA value too large"); |
135 | kfree(full_path); | 146 | rc = -EOPNOTSUPP; |
136 | FreeXid(xid); | 147 | goto set_ea_exit; |
137 | return -EOPNOTSUPP; | ||
138 | } | 148 | } |
139 | 149 | ||
140 | if (ea_name == NULL) { | 150 | if (ea_name == NULL) { |
@@ -157,6 +167,25 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
157 | rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, | 167 | rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, |
158 | (__u16)value_size, cifs_sb->local_nls, | 168 | (__u16)value_size, cifs_sb->local_nls, |
159 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 169 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
170 | } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, | ||
171 | strlen(CIFS_XATTR_CIFS_ACL)) == 0) { | ||
172 | pacl = kmalloc(value_size, GFP_KERNEL); | ||
173 | if (!pacl) { | ||
174 | cFYI(1, "%s: Can't allocate memory for ACL", | ||
175 | __func__); | ||
176 | rc = -ENOMEM; | ||
177 | } else { | ||
178 | #ifdef CONFIG_CIFS_ACL | ||
179 | memcpy(pacl, ea_value, value_size); | ||
180 | rc = set_cifs_acl(pacl, value_size, | ||
181 | direntry->d_inode, full_path); | ||
182 | if (rc == 0) /* force revalidate of the inode */ | ||
183 | CIFS_I(direntry->d_inode)->time = 0; | ||
184 | kfree(pacl); | ||
185 | #else | ||
186 | cFYI(1, "Set CIFS ACL not supported yet"); | ||
187 | #endif /* CONFIG_CIFS_ACL */ | ||
188 | } | ||
160 | } else { | 189 | } else { |
161 | int temp; | 190 | int temp; |
162 | temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, | 191 | temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, |
@@ -198,6 +227,7 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
198 | set_ea_exit: | 227 | set_ea_exit: |
199 | kfree(full_path); | 228 | kfree(full_path); |
200 | FreeXid(xid); | 229 | FreeXid(xid); |
230 | cifs_put_tlink(tlink); | ||
201 | #endif | 231 | #endif |
202 | return rc; | 232 | return rc; |
203 | } | 233 | } |
@@ -209,7 +239,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
209 | #ifdef CONFIG_CIFS_XATTR | 239 | #ifdef CONFIG_CIFS_XATTR |
210 | int xid; | 240 | int xid; |
211 | struct cifs_sb_info *cifs_sb; | 241 | struct cifs_sb_info *cifs_sb; |
212 | struct cifsTconInfo *pTcon; | 242 | struct tcon_link *tlink; |
243 | struct cifs_tcon *pTcon; | ||
213 | struct super_block *sb; | 244 | struct super_block *sb; |
214 | char *full_path; | 245 | char *full_path; |
215 | 246 | ||
@@ -221,16 +252,18 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
221 | if (sb == NULL) | 252 | if (sb == NULL) |
222 | return -EIO; | 253 | return -EIO; |
223 | 254 | ||
224 | xid = GetXid(); | ||
225 | |||
226 | cifs_sb = CIFS_SB(sb); | 255 | cifs_sb = CIFS_SB(sb); |
227 | pTcon = cifs_sb->tcon; | 256 | tlink = cifs_sb_tlink(cifs_sb); |
257 | if (IS_ERR(tlink)) | ||
258 | return PTR_ERR(tlink); | ||
259 | pTcon = tlink_tcon(tlink); | ||
260 | |||
261 | xid = GetXid(); | ||
228 | 262 | ||
229 | full_path = build_path_from_dentry(direntry); | 263 | full_path = build_path_from_dentry(direntry); |
230 | if (full_path == NULL) { | 264 | if (full_path == NULL) { |
231 | rc = -ENOMEM; | 265 | rc = -ENOMEM; |
232 | FreeXid(xid); | 266 | goto get_ea_exit; |
233 | return rc; | ||
234 | } | 267 | } |
235 | /* return dos attributes as pseudo xattr */ | 268 | /* return dos attributes as pseudo xattr */ |
236 | /* return alt name if available as pseudo attr */ | 269 | /* return alt name if available as pseudo attr */ |
@@ -265,29 +298,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
265 | cifs_sb->local_nls, | 298 | cifs_sb->local_nls, |
266 | cifs_sb->mnt_cifs_flags & | 299 | cifs_sb->mnt_cifs_flags & |
267 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 300 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
268 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
269 | else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | ||
270 | __u16 fid; | ||
271 | int oplock = 0; | ||
272 | struct cifs_ntsd *pacl = NULL; | ||
273 | __u32 buflen = 0; | ||
274 | if (experimEnabled) | ||
275 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
276 | FILE_OPEN, GENERIC_READ, 0, &fid, | ||
277 | &oplock, NULL, cifs_sb->local_nls, | ||
278 | cifs_sb->mnt_cifs_flags & | ||
279 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
280 | /* else rc is EOPNOTSUPP from above */ | ||
281 | |||
282 | if (rc == 0) { | ||
283 | rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl, | ||
284 | &buflen); | ||
285 | CIFSSMBClose(xid, pTcon, fid); | ||
286 | } | ||
287 | } | ||
288 | #endif /* EXPERIMENTAL */ | ||
289 | #else | 301 | #else |
290 | cFYI(1, "query POSIX ACL not supported yet"); | 302 | cFYI(1, "Query POSIX ACL not supported yet"); |
291 | #endif /* CONFIG_CIFS_POSIX */ | 303 | #endif /* CONFIG_CIFS_POSIX */ |
292 | } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT, | 304 | } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT, |
293 | strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | 305 | strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { |
@@ -299,8 +311,33 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
299 | cifs_sb->mnt_cifs_flags & | 311 | cifs_sb->mnt_cifs_flags & |
300 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 312 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
301 | #else | 313 | #else |
302 | cFYI(1, "query POSIX default ACL not supported yet"); | 314 | cFYI(1, "Query POSIX default ACL not supported yet"); |
303 | #endif | 315 | #endif /* CONFIG_CIFS_POSIX */ |
316 | } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL, | ||
317 | strlen(CIFS_XATTR_CIFS_ACL)) == 0) { | ||
318 | #ifdef CONFIG_CIFS_ACL | ||
319 | u32 acllen; | ||
320 | struct cifs_ntsd *pacl; | ||
321 | |||
322 | pacl = get_cifs_acl(cifs_sb, direntry->d_inode, | ||
323 | full_path, &acllen); | ||
324 | if (IS_ERR(pacl)) { | ||
325 | rc = PTR_ERR(pacl); | ||
326 | cERROR(1, "%s: error %zd getting sec desc", | ||
327 | __func__, rc); | ||
328 | } else { | ||
329 | if (ea_value) { | ||
330 | if (acllen > buf_size) | ||
331 | acllen = -ERANGE; | ||
332 | else | ||
333 | memcpy(ea_value, pacl, acllen); | ||
334 | } | ||
335 | rc = acllen; | ||
336 | kfree(pacl); | ||
337 | } | ||
338 | #else | ||
339 | cFYI(1, "Query CIFS ACL not supported yet"); | ||
340 | #endif /* CONFIG_CIFS_ACL */ | ||
304 | } else if (strncmp(ea_name, | 341 | } else if (strncmp(ea_name, |
305 | CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { | 342 | CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { |
306 | cFYI(1, "Trusted xattr namespace not supported yet"); | 343 | cFYI(1, "Trusted xattr namespace not supported yet"); |
@@ -323,6 +360,7 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
323 | get_ea_exit: | 360 | get_ea_exit: |
324 | kfree(full_path); | 361 | kfree(full_path); |
325 | FreeXid(xid); | 362 | FreeXid(xid); |
363 | cifs_put_tlink(tlink); | ||
326 | #endif | 364 | #endif |
327 | return rc; | 365 | return rc; |
328 | } | 366 | } |
@@ -333,7 +371,8 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
333 | #ifdef CONFIG_CIFS_XATTR | 371 | #ifdef CONFIG_CIFS_XATTR |
334 | int xid; | 372 | int xid; |
335 | struct cifs_sb_info *cifs_sb; | 373 | struct cifs_sb_info *cifs_sb; |
336 | struct cifsTconInfo *pTcon; | 374 | struct tcon_link *tlink; |
375 | struct cifs_tcon *pTcon; | ||
337 | struct super_block *sb; | 376 | struct super_block *sb; |
338 | char *full_path; | 377 | char *full_path; |
339 | 378 | ||
@@ -346,18 +385,20 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
346 | return -EIO; | 385 | return -EIO; |
347 | 386 | ||
348 | cifs_sb = CIFS_SB(sb); | 387 | cifs_sb = CIFS_SB(sb); |
349 | pTcon = cifs_sb->tcon; | ||
350 | |||
351 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 388 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
352 | return -EOPNOTSUPP; | 389 | return -EOPNOTSUPP; |
353 | 390 | ||
391 | tlink = cifs_sb_tlink(cifs_sb); | ||
392 | if (IS_ERR(tlink)) | ||
393 | return PTR_ERR(tlink); | ||
394 | pTcon = tlink_tcon(tlink); | ||
395 | |||
354 | xid = GetXid(); | 396 | xid = GetXid(); |
355 | 397 | ||
356 | full_path = build_path_from_dentry(direntry); | 398 | full_path = build_path_from_dentry(direntry); |
357 | if (full_path == NULL) { | 399 | if (full_path == NULL) { |
358 | rc = -ENOMEM; | 400 | rc = -ENOMEM; |
359 | FreeXid(xid); | 401 | goto list_ea_exit; |
360 | return rc; | ||
361 | } | 402 | } |
362 | /* return dos attributes as pseudo xattr */ | 403 | /* return dos attributes as pseudo xattr */ |
363 | /* return alt name if available as pseudo attr */ | 404 | /* return alt name if available as pseudo attr */ |
@@ -370,8 +411,10 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
370 | cifs_sb->mnt_cifs_flags & | 411 | cifs_sb->mnt_cifs_flags & |
371 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 412 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
372 | 413 | ||
414 | list_ea_exit: | ||
373 | kfree(full_path); | 415 | kfree(full_path); |
374 | FreeXid(xid); | 416 | FreeXid(xid); |
417 | cifs_put_tlink(tlink); | ||
375 | #endif | 418 | #endif |
376 | return rc; | 419 | return rc; |
377 | } | 420 | } |