diff options
author | J. Bruce Fields <bfields@redhat.com> | 2010-08-26 13:22:27 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-08-26 13:22:27 -0400 |
commit | f632265d0ffb5acf331252d98c64939849d96bb2 (patch) | |
tree | 31187d9a726bf1ca6ca12e26ad8e7c609eaf4d8b /fs/cifs | |
parent | 7d94784293096c0a46897acdb83be5abd9278ece (diff) | |
parent | da5cabf80e2433131bf0ed8993abc0f7ea618c73 (diff) |
Merge commit 'v2.6.36-rc1' into HEAD
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/Kconfig | 27 | ||||
-rw-r--r-- | fs/cifs/Makefile | 2 | ||||
-rw-r--r-- | fs/cifs/README | 15 | ||||
-rw-r--r-- | fs/cifs/cache.c | 331 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 25 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 33 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 7 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 50 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 48 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/connect.c | 181 | ||||
-rw-r--r-- | fs/cifs/dir.c | 84 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 166 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.h | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 203 | ||||
-rw-r--r-- | fs/cifs/fscache.c | 236 | ||||
-rw-r--r-- | fs/cifs/fscache.h | 136 | ||||
-rw-r--r-- | fs/cifs/inode.c | 153 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 3 | ||||
-rw-r--r-- | fs/cifs/misc.c | 20 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 63 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 5 | ||||
-rw-r--r-- | fs/cifs/sess.c | 10 | ||||
-rw-r--r-- | fs/cifs/smberr.h | 1 |
26 files changed, 1334 insertions, 475 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 80f352596807..917b7d449bb2 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -2,7 +2,6 @@ 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 SLOW_WORK | ||
6 | help | 5 | help |
7 | This is the client VFS module for the Common Internet File System | 6 | This is the client VFS module for the Common Internet File System |
8 | (CIFS) protocol which is the successor to the Server Message Block | 7 | (CIFS) protocol which is the successor to the Server Message Block |
@@ -71,14 +70,14 @@ config CIFS_WEAK_PW_HASH | |||
71 | If unsure, say N. | 70 | If unsure, say N. |
72 | 71 | ||
73 | config CIFS_UPCALL | 72 | config CIFS_UPCALL |
74 | bool "Kerberos/SPNEGO advanced session setup" | 73 | bool "Kerberos/SPNEGO advanced session setup" |
75 | depends on CIFS && KEYS | 74 | depends on CIFS && KEYS |
76 | help | 75 | select DNS_RESOLVER |
77 | Enables an upcall mechanism for CIFS which accesses | 76 | help |
78 | userspace helper utilities to provide SPNEGO packaged (RFC 4178) | 77 | Enables an upcall mechanism for CIFS which accesses userspace helper |
79 | Kerberos tickets which are needed to mount to certain secure servers | 78 | utilities to provide SPNEGO packaged (RFC 4178) Kerberos tickets |
80 | (for which more secure Kerberos authentication is required). If | 79 | which are needed to mount to certain secure servers (for which more |
81 | unsure, say N. | 80 | secure Kerberos authentication is required). If unsure, say N. |
82 | 81 | ||
83 | config CIFS_XATTR | 82 | config CIFS_XATTR |
84 | bool "CIFS extended attributes" | 83 | bool "CIFS extended attributes" |
@@ -122,6 +121,7 @@ config CIFS_DEBUG2 | |||
122 | config CIFS_DFS_UPCALL | 121 | config CIFS_DFS_UPCALL |
123 | bool "DFS feature support" | 122 | bool "DFS feature support" |
124 | depends on CIFS && KEYS | 123 | depends on CIFS && KEYS |
124 | select DNS_RESOLVER | ||
125 | help | 125 | help |
126 | Distributed File System (DFS) support is used to access shares | 126 | Distributed File System (DFS) support is used to access shares |
127 | transparently in an enterprise name space, even if the share | 127 | transparently in an enterprise name space, even if the share |
@@ -131,6 +131,15 @@ config CIFS_DFS_UPCALL | |||
131 | IP addresses) which is needed for implicit mounts of DFS junction | 131 | IP addresses) which is needed for implicit mounts of DFS junction |
132 | points. If unsure, say N. | 132 | points. If unsure, say N. |
133 | 133 | ||
134 | config CIFS_FSCACHE | ||
135 | bool "Provide CIFS client caching support (EXPERIMENTAL)" | ||
136 | depends on EXPERIMENTAL | ||
137 | depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y | ||
138 | help | ||
139 | Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data | ||
140 | to be cached locally on disk through the general filesystem cache | ||
141 | manager. If unsure, say N. | ||
142 | |||
134 | config CIFS_EXPERIMENTAL | 143 | config CIFS_EXPERIMENTAL |
135 | bool "CIFS Experimental Features (EXPERIMENTAL)" | 144 | bool "CIFS Experimental Features (EXPERIMENTAL)" |
136 | depends on CIFS && EXPERIMENTAL | 145 | depends on CIFS && EXPERIMENTAL |
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 9948c0030e86..adefa60a9bdc 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
@@ -11,3 +11,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | |||
11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o |
12 | 12 | ||
13 | cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o | 13 | cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o |
14 | |||
15 | cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o | ||
diff --git a/fs/cifs/README b/fs/cifs/README index a727b7cb075f..7099a526f775 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -301,6 +301,16 @@ A partial list of the supported mount options follows: | |||
301 | gid Set the default gid for inodes (similar to above). | 301 | gid Set the default gid for inodes (similar to above). |
302 | file_mode If CIFS Unix extensions are not supported by the server | 302 | file_mode If CIFS Unix extensions are not supported by the server |
303 | this overrides the default mode for file inodes. | 303 | this overrides the default mode for file inodes. |
304 | fsc Enable local disk caching using FS-Cache (off by default). This | ||
305 | option could be useful to improve performance on a slow link, | ||
306 | heavily loaded server and/or network where reading from the | ||
307 | disk is faster than reading from the server (over the network). | ||
308 | This could also impact scalability positively as the | ||
309 | number of calls to the server are reduced. However, local | ||
310 | caching is not suitable for all workloads for e.g. read-once | ||
311 | type workloads. So, you need to consider carefully your | ||
312 | workload/scenario before using this option. Currently, local | ||
313 | disk caching is functional for CIFS files opened as read-only. | ||
304 | dir_mode If CIFS Unix extensions are not supported by the server | 314 | dir_mode If CIFS Unix extensions are not supported by the server |
305 | this overrides the default mode for directory inodes. | 315 | this overrides the default mode for directory inodes. |
306 | port attempt to contact the server on this tcp port, before | 316 | port attempt to contact the server on this tcp port, before |
@@ -568,8 +578,9 @@ module can be displayed via modinfo. | |||
568 | Misc /proc/fs/cifs Flags and Debug Info | 578 | Misc /proc/fs/cifs Flags and Debug Info |
569 | ======================================= | 579 | ======================================= |
570 | Informational pseudo-files: | 580 | Informational pseudo-files: |
571 | DebugData Displays information about active CIFS sessions | 581 | DebugData Displays information about active CIFS sessions and |
572 | and shares, as well as the cifs.ko version. | 582 | shares, features enabled as well as the cifs.ko |
583 | version. | ||
573 | Stats Lists summary resource usage information as well as per | 584 | Stats Lists summary resource usage information as well as per |
574 | share statistics, if CONFIG_CIFS_STATS in enabled | 585 | share statistics, if CONFIG_CIFS_STATS in enabled |
575 | in the kernel configuration. | 586 | in the kernel configuration. |
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c new file mode 100644 index 000000000000..224d7bbd1fcc --- /dev/null +++ b/fs/cifs/cache.c | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * fs/cifs/cache.c - CIFS filesystem cache index structure definitions | ||
3 | * | ||
4 | * Copyright (c) 2010 Novell, Inc. | ||
5 | * Authors(s): Suresh Jayaraman (sjayaraman@suse.de> | ||
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 | #include "fscache.h" | ||
22 | #include "cifs_debug.h" | ||
23 | |||
24 | /* | ||
25 | * CIFS filesystem definition for FS-Cache | ||
26 | */ | ||
27 | struct fscache_netfs cifs_fscache_netfs = { | ||
28 | .name = "cifs", | ||
29 | .version = 0, | ||
30 | }; | ||
31 | |||
32 | /* | ||
33 | * Register CIFS for caching with FS-Cache | ||
34 | */ | ||
35 | int cifs_fscache_register(void) | ||
36 | { | ||
37 | return fscache_register_netfs(&cifs_fscache_netfs); | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * Unregister CIFS for caching | ||
42 | */ | ||
43 | void cifs_fscache_unregister(void) | ||
44 | { | ||
45 | fscache_unregister_netfs(&cifs_fscache_netfs); | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Key layout of CIFS server cache index object | ||
50 | */ | ||
51 | struct cifs_server_key { | ||
52 | uint16_t family; /* address family */ | ||
53 | uint16_t port; /* IP port */ | ||
54 | union { | ||
55 | struct in_addr ipv4_addr; | ||
56 | struct in6_addr ipv6_addr; | ||
57 | } addr[0]; | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * Server object keyed by {IPaddress,port,family} tuple | ||
62 | */ | ||
63 | static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | ||
64 | void *buffer, uint16_t maxbuf) | ||
65 | { | ||
66 | const struct TCP_Server_Info *server = cookie_netfs_data; | ||
67 | const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr; | ||
68 | struct cifs_server_key *key = buffer; | ||
69 | uint16_t key_len = sizeof(struct cifs_server_key); | ||
70 | |||
71 | memset(key, 0, key_len); | ||
72 | |||
73 | /* | ||
74 | * Should not be a problem as sin_family/sin6_family overlays | ||
75 | * sa_family field | ||
76 | */ | ||
77 | switch (sa->sa_family) { | ||
78 | case AF_INET: | ||
79 | key->family = server->addr.sockAddr.sin_family; | ||
80 | key->port = server->addr.sockAddr.sin_port; | ||
81 | key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr; | ||
82 | key_len += sizeof(key->addr[0].ipv4_addr); | ||
83 | break; | ||
84 | |||
85 | case AF_INET6: | ||
86 | key->family = server->addr.sockAddr6.sin6_family; | ||
87 | key->port = server->addr.sockAddr6.sin6_port; | ||
88 | key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr; | ||
89 | key_len += sizeof(key->addr[0].ipv6_addr); | ||
90 | break; | ||
91 | |||
92 | default: | ||
93 | cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family); | ||
94 | key_len = 0; | ||
95 | break; | ||
96 | } | ||
97 | |||
98 | return key_len; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Server object for FS-Cache | ||
103 | */ | ||
104 | const struct fscache_cookie_def cifs_fscache_server_index_def = { | ||
105 | .name = "CIFS.server", | ||
106 | .type = FSCACHE_COOKIE_TYPE_INDEX, | ||
107 | .get_key = cifs_server_get_key, | ||
108 | }; | ||
109 | |||
110 | /* | ||
111 | * Auxiliary data attached to CIFS superblock within the cache | ||
112 | */ | ||
113 | struct cifs_fscache_super_auxdata { | ||
114 | u64 resource_id; /* unique server resource id */ | ||
115 | }; | ||
116 | |||
117 | static char *extract_sharename(const char *treename) | ||
118 | { | ||
119 | const char *src; | ||
120 | char *delim, *dst; | ||
121 | int len; | ||
122 | |||
123 | /* skip double chars at the beginning */ | ||
124 | src = treename + 2; | ||
125 | |||
126 | /* share name is always preceded by '\\' now */ | ||
127 | delim = strchr(src, '\\'); | ||
128 | if (!delim) | ||
129 | return ERR_PTR(-EINVAL); | ||
130 | delim++; | ||
131 | len = strlen(delim); | ||
132 | |||
133 | /* caller has to free the memory */ | ||
134 | dst = kstrndup(delim, len, GFP_KERNEL); | ||
135 | if (!dst) | ||
136 | return ERR_PTR(-ENOMEM); | ||
137 | |||
138 | return dst; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * Superblock object currently keyed by share name | ||
143 | */ | ||
144 | static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer, | ||
145 | uint16_t maxbuf) | ||
146 | { | ||
147 | const struct cifsTconInfo *tcon = cookie_netfs_data; | ||
148 | char *sharename; | ||
149 | uint16_t len; | ||
150 | |||
151 | sharename = extract_sharename(tcon->treeName); | ||
152 | if (IS_ERR(sharename)) { | ||
153 | cFYI(1, "CIFS: couldn't extract sharename\n"); | ||
154 | sharename = NULL; | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | len = strlen(sharename); | ||
159 | if (len > maxbuf) | ||
160 | return 0; | ||
161 | |||
162 | memcpy(buffer, sharename, len); | ||
163 | |||
164 | kfree(sharename); | ||
165 | |||
166 | return len; | ||
167 | } | ||
168 | |||
169 | static uint16_t | ||
170 | cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer, | ||
171 | uint16_t maxbuf) | ||
172 | { | ||
173 | struct cifs_fscache_super_auxdata auxdata; | ||
174 | const struct cifsTconInfo *tcon = cookie_netfs_data; | ||
175 | |||
176 | memset(&auxdata, 0, sizeof(auxdata)); | ||
177 | auxdata.resource_id = tcon->resource_id; | ||
178 | |||
179 | if (maxbuf > sizeof(auxdata)) | ||
180 | maxbuf = sizeof(auxdata); | ||
181 | |||
182 | memcpy(buffer, &auxdata, maxbuf); | ||
183 | |||
184 | return maxbuf; | ||
185 | } | ||
186 | |||
187 | static enum | ||
188 | fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, | ||
189 | const void *data, | ||
190 | uint16_t datalen) | ||
191 | { | ||
192 | struct cifs_fscache_super_auxdata auxdata; | ||
193 | const struct cifsTconInfo *tcon = cookie_netfs_data; | ||
194 | |||
195 | if (datalen != sizeof(auxdata)) | ||
196 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
197 | |||
198 | memset(&auxdata, 0, sizeof(auxdata)); | ||
199 | auxdata.resource_id = tcon->resource_id; | ||
200 | |||
201 | if (memcmp(data, &auxdata, datalen) != 0) | ||
202 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
203 | |||
204 | return FSCACHE_CHECKAUX_OKAY; | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * Superblock object for FS-Cache | ||
209 | */ | ||
210 | const struct fscache_cookie_def cifs_fscache_super_index_def = { | ||
211 | .name = "CIFS.super", | ||
212 | .type = FSCACHE_COOKIE_TYPE_INDEX, | ||
213 | .get_key = cifs_super_get_key, | ||
214 | .get_aux = cifs_fscache_super_get_aux, | ||
215 | .check_aux = cifs_fscache_super_check_aux, | ||
216 | }; | ||
217 | |||
218 | /* | ||
219 | * Auxiliary data attached to CIFS inode within the cache | ||
220 | */ | ||
221 | struct cifs_fscache_inode_auxdata { | ||
222 | struct timespec last_write_time; | ||
223 | struct timespec last_change_time; | ||
224 | u64 eof; | ||
225 | }; | ||
226 | |||
227 | static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data, | ||
228 | void *buffer, uint16_t maxbuf) | ||
229 | { | ||
230 | const struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
231 | uint16_t keylen; | ||
232 | |||
233 | /* use the UniqueId as the key */ | ||
234 | keylen = sizeof(cifsi->uniqueid); | ||
235 | if (keylen > maxbuf) | ||
236 | keylen = 0; | ||
237 | else | ||
238 | memcpy(buffer, &cifsi->uniqueid, keylen); | ||
239 | |||
240 | return keylen; | ||
241 | } | ||
242 | |||
243 | static void | ||
244 | cifs_fscache_inode_get_attr(const void *cookie_netfs_data, uint64_t *size) | ||
245 | { | ||
246 | const struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
247 | |||
248 | *size = cifsi->vfs_inode.i_size; | ||
249 | } | ||
250 | |||
251 | static uint16_t | ||
252 | cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer, | ||
253 | uint16_t maxbuf) | ||
254 | { | ||
255 | struct cifs_fscache_inode_auxdata auxdata; | ||
256 | const struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
257 | |||
258 | memset(&auxdata, 0, sizeof(auxdata)); | ||
259 | auxdata.eof = cifsi->server_eof; | ||
260 | auxdata.last_write_time = cifsi->vfs_inode.i_mtime; | ||
261 | auxdata.last_change_time = cifsi->vfs_inode.i_ctime; | ||
262 | |||
263 | if (maxbuf > sizeof(auxdata)) | ||
264 | maxbuf = sizeof(auxdata); | ||
265 | |||
266 | memcpy(buffer, &auxdata, maxbuf); | ||
267 | |||
268 | return maxbuf; | ||
269 | } | ||
270 | |||
271 | static enum | ||
272 | fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, | ||
273 | const void *data, | ||
274 | uint16_t datalen) | ||
275 | { | ||
276 | struct cifs_fscache_inode_auxdata auxdata; | ||
277 | struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
278 | |||
279 | if (datalen != sizeof(auxdata)) | ||
280 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
281 | |||
282 | memset(&auxdata, 0, sizeof(auxdata)); | ||
283 | auxdata.eof = cifsi->server_eof; | ||
284 | auxdata.last_write_time = cifsi->vfs_inode.i_mtime; | ||
285 | auxdata.last_change_time = cifsi->vfs_inode.i_ctime; | ||
286 | |||
287 | if (memcmp(data, &auxdata, datalen) != 0) | ||
288 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
289 | |||
290 | return FSCACHE_CHECKAUX_OKAY; | ||
291 | } | ||
292 | |||
293 | static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data) | ||
294 | { | ||
295 | struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
296 | struct pagevec pvec; | ||
297 | pgoff_t first; | ||
298 | int loop, nr_pages; | ||
299 | |||
300 | pagevec_init(&pvec, 0); | ||
301 | first = 0; | ||
302 | |||
303 | cFYI(1, "cifs inode 0x%p now uncached", cifsi); | ||
304 | |||
305 | for (;;) { | ||
306 | nr_pages = pagevec_lookup(&pvec, | ||
307 | cifsi->vfs_inode.i_mapping, first, | ||
308 | PAGEVEC_SIZE - pagevec_count(&pvec)); | ||
309 | if (!nr_pages) | ||
310 | break; | ||
311 | |||
312 | for (loop = 0; loop < nr_pages; loop++) | ||
313 | ClearPageFsCache(pvec.pages[loop]); | ||
314 | |||
315 | first = pvec.pages[nr_pages - 1]->index + 1; | ||
316 | |||
317 | pvec.nr = nr_pages; | ||
318 | pagevec_release(&pvec); | ||
319 | cond_resched(); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | const struct fscache_cookie_def cifs_fscache_inode_object_def = { | ||
324 | .name = "CIFS.uniqueid", | ||
325 | .type = FSCACHE_COOKIE_TYPE_DATAFILE, | ||
326 | .get_key = cifs_fscache_inode_get_key, | ||
327 | .get_attr = cifs_fscache_inode_get_attr, | ||
328 | .get_aux = cifs_fscache_inode_get_aux, | ||
329 | .check_aux = cifs_fscache_inode_check_aux, | ||
330 | .now_uncached = cifs_fscache_inode_now_uncached, | ||
331 | }; | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4fce6e61b34e..eb1ba493489f 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -119,6 +119,31 @@ 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: "); | ||
123 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
124 | seq_printf(m, "dfs"); | ||
125 | seq_putc(m, ' '); | ||
126 | #endif | ||
127 | #ifdef CONFIG_CIFS_FSCACHE | ||
128 | seq_printf(m, "fscache"); | ||
129 | seq_putc(m, ' '); | ||
130 | #endif | ||
131 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
132 | seq_printf(m, "lanman"); | ||
133 | seq_putc(m, ' '); | ||
134 | #endif | ||
135 | #ifdef CONFIG_CIFS_POSIX | ||
136 | seq_printf(m, "posix"); | ||
137 | seq_putc(m, ' '); | ||
138 | #endif | ||
139 | #ifdef CONFIG_CIFS_UPCALL | ||
140 | seq_printf(m, "spnego"); | ||
141 | seq_putc(m, ' '); | ||
142 | #endif | ||
143 | #ifdef CONFIG_CIFS_XATTR | ||
144 | seq_printf(m, "xattr"); | ||
145 | #endif | ||
146 | seq_putc(m, '\n'); | ||
122 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); | 147 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); |
123 | seq_printf(m, "Servers:"); | 148 | seq_printf(m, "Servers:"); |
124 | 149 | ||
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ac19a6f3dae0..d6ced7aa23cf 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -141,7 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, | |||
141 | } | 141 | } |
142 | 142 | ||
143 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); | 143 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); |
144 | if (rc != 0) { | 144 | if (rc < 0) { |
145 | cERROR(1, "%s: Failed to resolve server part of %s to IP: %d", | 145 | cERROR(1, "%s: Failed to resolve server part of %s to IP: %d", |
146 | __func__, *devname, rc); | 146 | __func__, *devname, rc); |
147 | goto compose_mount_options_err; | 147 | goto compose_mount_options_err; |
@@ -150,8 +150,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, | |||
150 | * assuming that we have 'unc=' and 'ip=' in | 150 | * assuming that we have 'unc=' and 'ip=' in |
151 | * the original sb_mountdata | 151 | * the original sb_mountdata |
152 | */ | 152 | */ |
153 | md_len = strlen(sb_mountdata) + strlen(srvIP) + | 153 | md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12; |
154 | strlen(ref->node_name) + 12; | ||
155 | mountdata = kzalloc(md_len+1, GFP_KERNEL); | 154 | mountdata = kzalloc(md_len+1, GFP_KERNEL); |
156 | if (mountdata == NULL) { | 155 | if (mountdata == NULL) { |
157 | rc = -ENOMEM; | 156 | rc = -ENOMEM; |
@@ -230,28 +229,22 @@ compose_mount_options_err: | |||
230 | goto compose_mount_options_out; | 229 | goto compose_mount_options_out; |
231 | } | 230 | } |
232 | 231 | ||
233 | 232 | /** | |
234 | static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, | 233 | * cifs_dfs_do_refmount - mounts specified path using provided refferal |
235 | struct dentry *dentry, const struct dfs_info3_param *ref) | 234 | * @cifs_sb: parent/root superblock |
235 | * @fullpath: full path in UNC format | ||
236 | * @ref: server's referral | ||
237 | */ | ||
238 | static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, | ||
239 | const char *fullpath, const struct dfs_info3_param *ref) | ||
236 | { | 240 | { |
237 | struct cifs_sb_info *cifs_sb; | ||
238 | struct vfsmount *mnt; | 241 | struct vfsmount *mnt; |
239 | char *mountdata; | 242 | char *mountdata; |
240 | char *devname = NULL; | 243 | char *devname = NULL; |
241 | char *fullpath; | ||
242 | |||
243 | cifs_sb = CIFS_SB(dentry->d_inode->i_sb); | ||
244 | /* | ||
245 | * this function gives us a path with a double backslash prefix. We | ||
246 | * require a single backslash for DFS. | ||
247 | */ | ||
248 | fullpath = build_path_from_dentry(dentry); | ||
249 | if (!fullpath) | ||
250 | return ERR_PTR(-ENOMEM); | ||
251 | 244 | ||
245 | /* strip first '\' from fullpath */ | ||
252 | mountdata = cifs_compose_mount_options(cifs_sb->mountdata, | 246 | mountdata = cifs_compose_mount_options(cifs_sb->mountdata, |
253 | fullpath + 1, ref, &devname); | 247 | fullpath + 1, ref, &devname); |
254 | kfree(fullpath); | ||
255 | 248 | ||
256 | if (IS_ERR(mountdata)) | 249 | if (IS_ERR(mountdata)) |
257 | return (struct vfsmount *)mountdata; | 250 | return (struct vfsmount *)mountdata; |
@@ -357,8 +350,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
357 | rc = -EINVAL; | 350 | rc = -EINVAL; |
358 | goto out_err; | 351 | goto out_err; |
359 | } | 352 | } |
360 | mnt = cifs_dfs_do_refmount(nd->path.mnt, | 353 | mnt = cifs_dfs_do_refmount(cifs_sb, |
361 | nd->path.dentry, referrals + i); | 354 | full_path, referrals + i); |
362 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, | 355 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, |
363 | referrals[i].node_name, mnt); | 356 | referrals[i].node_name, mnt); |
364 | 357 | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 246a167cb913..9e771450c3b8 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ | 35 | #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ |
36 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ | 36 | #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*/ | 37 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ |
38 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ | ||
38 | 39 | ||
39 | struct cifs_sb_info { | 40 | struct cifs_sb_info { |
40 | struct cifsTconInfo *tcon; /* primary mount */ | 41 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 379bd7d9c05f..87044906cd1f 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -84,6 +84,9 @@ struct key_type cifs_spnego_key_type = { | |||
84 | /* strlen of ";uid=0x" */ | 84 | /* strlen of ";uid=0x" */ |
85 | #define UID_KEY_LEN 7 | 85 | #define UID_KEY_LEN 7 |
86 | 86 | ||
87 | /* strlen of ";creduid=0x" */ | ||
88 | #define CREDUID_KEY_LEN 11 | ||
89 | |||
87 | /* strlen of ";user=" */ | 90 | /* strlen of ";user=" */ |
88 | #define USER_KEY_LEN 6 | 91 | #define USER_KEY_LEN 6 |
89 | 92 | ||
@@ -107,6 +110,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
107 | IP_KEY_LEN + INET6_ADDRSTRLEN + | 110 | IP_KEY_LEN + INET6_ADDRSTRLEN + |
108 | MAX_MECH_STR_LEN + | 111 | MAX_MECH_STR_LEN + |
109 | UID_KEY_LEN + (sizeof(uid_t) * 2) + | 112 | UID_KEY_LEN + (sizeof(uid_t) * 2) + |
113 | CREDUID_KEY_LEN + (sizeof(uid_t) * 2) + | ||
110 | USER_KEY_LEN + strlen(sesInfo->userName) + | 114 | USER_KEY_LEN + strlen(sesInfo->userName) + |
111 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; | 115 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; |
112 | 116 | ||
@@ -144,6 +148,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
144 | sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); | 148 | sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); |
145 | 149 | ||
146 | dp = description + strlen(description); | 150 | dp = description + strlen(description); |
151 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); | ||
152 | |||
153 | dp = description + strlen(description); | ||
147 | sprintf(dp, ";user=%s", sesInfo->userName); | 154 | sprintf(dp, ";user=%s", sesInfo->userName); |
148 | 155 | ||
149 | dp = description + strlen(description); | 156 | dp = description + strlen(description); |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 78c02eb4cb1f..b7431afdd76d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -45,8 +45,8 @@ | |||
45 | #include "cifs_fs_sb.h" | 45 | #include "cifs_fs_sb.h" |
46 | #include <linux/mm.h> | 46 | #include <linux/mm.h> |
47 | #include <linux/key-type.h> | 47 | #include <linux/key-type.h> |
48 | #include "dns_resolve.h" | ||
49 | #include "cifs_spnego.h" | 48 | #include "cifs_spnego.h" |
49 | #include "fscache.h" | ||
50 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ | 50 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ |
51 | 51 | ||
52 | int cifsFYI = 0; | 52 | int cifsFYI = 0; |
@@ -329,6 +329,14 @@ cifs_destroy_inode(struct inode *inode) | |||
329 | } | 329 | } |
330 | 330 | ||
331 | static void | 331 | static void |
332 | cifs_evict_inode(struct inode *inode) | ||
333 | { | ||
334 | truncate_inode_pages(&inode->i_data, 0); | ||
335 | end_writeback(inode); | ||
336 | cifs_fscache_release_inode_cookie(inode); | ||
337 | } | ||
338 | |||
339 | static void | ||
332 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 340 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) |
333 | { | 341 | { |
334 | seq_printf(s, ",addr="); | 342 | seq_printf(s, ",addr="); |
@@ -473,14 +481,24 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data) | |||
473 | return 0; | 481 | return 0; |
474 | } | 482 | } |
475 | 483 | ||
484 | static int cifs_drop_inode(struct inode *inode) | ||
485 | { | ||
486 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
487 | |||
488 | /* no serverino => unconditional eviction */ | ||
489 | return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) || | ||
490 | generic_drop_inode(inode); | ||
491 | } | ||
492 | |||
476 | static const struct super_operations cifs_super_ops = { | 493 | static const struct super_operations cifs_super_ops = { |
477 | .put_super = cifs_put_super, | 494 | .put_super = cifs_put_super, |
478 | .statfs = cifs_statfs, | 495 | .statfs = cifs_statfs, |
479 | .alloc_inode = cifs_alloc_inode, | 496 | .alloc_inode = cifs_alloc_inode, |
480 | .destroy_inode = cifs_destroy_inode, | 497 | .destroy_inode = cifs_destroy_inode, |
481 | /* .drop_inode = generic_delete_inode, | 498 | .drop_inode = cifs_drop_inode, |
482 | .delete_inode = cifs_delete_inode, */ /* Do not need above two | 499 | .evict_inode = cifs_evict_inode, |
483 | functions unless later we add lazy close of inodes or unless the | 500 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above |
501 | function unless later we add lazy close of inodes or unless the | ||
484 | kernel forgets to call us with the same number of releases (closes) | 502 | kernel forgets to call us with the same number of releases (closes) |
485 | as opens */ | 503 | as opens */ |
486 | .show_options = cifs_show_options, | 504 | .show_options = cifs_show_options, |
@@ -892,6 +910,10 @@ init_cifs(void) | |||
892 | cFYI(1, "cifs_max_pending set to max of 256"); | 910 | cFYI(1, "cifs_max_pending set to max of 256"); |
893 | } | 911 | } |
894 | 912 | ||
913 | rc = cifs_fscache_register(); | ||
914 | if (rc) | ||
915 | goto out; | ||
916 | |||
895 | rc = cifs_init_inodecache(); | 917 | rc = cifs_init_inodecache(); |
896 | if (rc) | 918 | if (rc) |
897 | goto out_clean_proc; | 919 | goto out_clean_proc; |
@@ -912,27 +934,13 @@ init_cifs(void) | |||
912 | if (rc) | 934 | if (rc) |
913 | goto out_unregister_filesystem; | 935 | goto out_unregister_filesystem; |
914 | #endif | 936 | #endif |
915 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
916 | rc = register_key_type(&key_type_dns_resolver); | ||
917 | if (rc) | ||
918 | goto out_unregister_key_type; | ||
919 | #endif | ||
920 | rc = slow_work_register_user(THIS_MODULE); | ||
921 | if (rc) | ||
922 | goto out_unregister_resolver_key; | ||
923 | 937 | ||
924 | return 0; | 938 | return 0; |
925 | 939 | ||
926 | out_unregister_resolver_key: | ||
927 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
928 | unregister_key_type(&key_type_dns_resolver); | ||
929 | out_unregister_key_type: | ||
930 | #endif | ||
931 | #ifdef CONFIG_CIFS_UPCALL | 940 | #ifdef CONFIG_CIFS_UPCALL |
932 | unregister_key_type(&cifs_spnego_key_type); | ||
933 | out_unregister_filesystem: | 941 | out_unregister_filesystem: |
934 | #endif | ||
935 | unregister_filesystem(&cifs_fs_type); | 942 | unregister_filesystem(&cifs_fs_type); |
943 | #endif | ||
936 | out_destroy_request_bufs: | 944 | out_destroy_request_bufs: |
937 | cifs_destroy_request_bufs(); | 945 | cifs_destroy_request_bufs(); |
938 | out_destroy_mids: | 946 | out_destroy_mids: |
@@ -941,6 +949,8 @@ init_cifs(void) | |||
941 | cifs_destroy_inodecache(); | 949 | cifs_destroy_inodecache(); |
942 | out_clean_proc: | 950 | out_clean_proc: |
943 | cifs_proc_clean(); | 951 | cifs_proc_clean(); |
952 | cifs_fscache_unregister(); | ||
953 | out: | ||
944 | return rc; | 954 | return rc; |
945 | } | 955 | } |
946 | 956 | ||
@@ -949,9 +959,9 @@ exit_cifs(void) | |||
949 | { | 959 | { |
950 | cFYI(DBG2, "exit_cifs"); | 960 | cFYI(DBG2, "exit_cifs"); |
951 | cifs_proc_clean(); | 961 | cifs_proc_clean(); |
962 | cifs_fscache_unregister(); | ||
952 | #ifdef CONFIG_CIFS_DFS_UPCALL | 963 | #ifdef CONFIG_CIFS_DFS_UPCALL |
953 | cifs_dfs_release_automount_timer(); | 964 | cifs_dfs_release_automount_timer(); |
954 | unregister_key_type(&key_type_dns_resolver); | ||
955 | #endif | 965 | #endif |
956 | #ifdef CONFIG_CIFS_UPCALL | 966 | #ifdef CONFIG_CIFS_UPCALL |
957 | unregister_key_type(&cifs_spnego_key_type); | 967 | unregister_key_type(&cifs_spnego_key_type); |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a7eb65c84b1c..d82f5fb4761e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -114,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
114 | extern const struct export_operations cifs_export_ops; | 114 | extern const struct export_operations cifs_export_ops; |
115 | #endif /* EXPERIMENTAL */ | 115 | #endif /* EXPERIMENTAL */ |
116 | 116 | ||
117 | #define CIFS_VERSION "1.64" | 117 | #define CIFS_VERSION "1.65" |
118 | #endif /* _CIFSFS_H */ | 118 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a88479ceaad5..0cdfb8c32ac6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -16,10 +16,13 @@ | |||
16 | * the GNU Lesser General Public License for more details. | 16 | * the GNU Lesser General Public License for more details. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | #ifndef _CIFS_GLOB_H | ||
20 | #define _CIFS_GLOB_H | ||
21 | |||
19 | #include <linux/in.h> | 22 | #include <linux/in.h> |
20 | #include <linux/in6.h> | 23 | #include <linux/in6.h> |
21 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
22 | #include <linux/slow-work.h> | 25 | #include <linux/workqueue.h> |
23 | #include "cifs_fs_sb.h" | 26 | #include "cifs_fs_sb.h" |
24 | #include "cifsacl.h" | 27 | #include "cifsacl.h" |
25 | /* | 28 | /* |
@@ -34,7 +37,7 @@ | |||
34 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ | 37 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ |
35 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | 38 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null |
36 | termination then *2 for unicode versions */ | 39 | termination then *2 for unicode versions */ |
37 | #define MAX_PASSWORD_SIZE 16 | 40 | #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ |
38 | 41 | ||
39 | #define CIFS_MIN_RCV_POOL 4 | 42 | #define CIFS_MIN_RCV_POOL 4 |
40 | 43 | ||
@@ -80,8 +83,7 @@ enum statusEnum { | |||
80 | }; | 83 | }; |
81 | 84 | ||
82 | enum securityEnum { | 85 | enum securityEnum { |
83 | PLAINTXT = 0, /* Legacy with Plaintext passwords */ | 86 | LANMAN = 0, /* Legacy LANMAN auth */ |
84 | LANMAN, /* Legacy LANMAN auth */ | ||
85 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 87 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ |
86 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 88 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
87 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ | 89 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ |
@@ -142,7 +144,6 @@ struct TCP_Server_Info { | |||
142 | struct list_head pending_mid_q; | 144 | struct list_head pending_mid_q; |
143 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | 145 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ |
144 | unsigned short server_codepage; /* codepage for the server */ | 146 | unsigned short server_codepage; /* codepage for the server */ |
145 | unsigned long ip_address; /* IP addr for the server if known */ | ||
146 | enum protocolEnum protocolType; | 147 | enum protocolEnum protocolType; |
147 | char versionMajor; | 148 | char versionMajor; |
148 | char versionMinor; | 149 | char versionMinor; |
@@ -190,19 +191,9 @@ struct TCP_Server_Info { | |||
190 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 191 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
191 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 192 | bool sec_kerberosu2u; /* supports U2U Kerberos */ |
192 | bool sec_ntlmssp; /* supports NTLMSSP */ | 193 | bool sec_ntlmssp; /* supports NTLMSSP */ |
193 | }; | 194 | #ifdef CONFIG_CIFS_FSCACHE |
194 | 195 | struct fscache_cookie *fscache; /* client index cache cookie */ | |
195 | /* | 196 | #endif |
196 | * The following is our shortcut to user information. We surface the uid, | ||
197 | * and name. We always get the password on the fly in case it | ||
198 | * has changed. We also hang a list of sessions owned by this user off here. | ||
199 | */ | ||
200 | struct cifsUidInfo { | ||
201 | struct list_head userList; | ||
202 | struct list_head sessionList; /* SMB sessions for this user */ | ||
203 | uid_t linux_uid; | ||
204 | char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */ | ||
205 | /* BB may need ptr or callback for PAM or WinBind info */ | ||
206 | }; | 197 | }; |
207 | 198 | ||
208 | /* | 199 | /* |
@@ -212,9 +203,6 @@ struct cifsSesInfo { | |||
212 | struct list_head smb_ses_list; | 203 | struct list_head smb_ses_list; |
213 | struct list_head tcon_list; | 204 | struct list_head tcon_list; |
214 | struct mutex session_mutex; | 205 | struct mutex session_mutex; |
215 | #if 0 | ||
216 | struct cifsUidInfo *uidInfo; /* pointer to user info */ | ||
217 | #endif | ||
218 | struct TCP_Server_Info *server; /* pointer to server info */ | 206 | struct TCP_Server_Info *server; /* pointer to server info */ |
219 | int ses_count; /* reference counter */ | 207 | int ses_count; /* reference counter */ |
220 | enum statusEnum status; | 208 | enum statusEnum status; |
@@ -226,7 +214,8 @@ struct cifsSesInfo { | |||
226 | char *serverNOS; /* name of network operating system of server */ | 214 | char *serverNOS; /* name of network operating system of server */ |
227 | char *serverDomain; /* security realm of server */ | 215 | char *serverDomain; /* security realm of server */ |
228 | int Suid; /* remote smb uid */ | 216 | int Suid; /* remote smb uid */ |
229 | uid_t linux_uid; /* local Linux uid */ | 217 | uid_t linux_uid; /* overriding owner of files on the mount */ |
218 | uid_t cred_uid; /* owner of credentials */ | ||
230 | int capabilities; | 219 | int capabilities; |
231 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 220 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for |
232 | TCP names - will ipv6 and sctp addresses fit? */ | 221 | TCP names - will ipv6 and sctp addresses fit? */ |
@@ -311,6 +300,10 @@ struct cifsTconInfo { | |||
311 | bool local_lease:1; /* check leases (only) on local system not remote */ | 300 | bool local_lease:1; /* check leases (only) on local system not remote */ |
312 | bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ | 301 | bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ |
313 | bool need_reconnect:1; /* connection reset, tid now invalid */ | 302 | bool need_reconnect:1; /* connection reset, tid now invalid */ |
303 | #ifdef CONFIG_CIFS_FSCACHE | ||
304 | u64 resource_id; /* server resource id */ | ||
305 | struct fscache_cookie *fscache; /* cookie for share */ | ||
306 | #endif | ||
314 | /* BB add field for back pointer to sb struct(s)? */ | 307 | /* BB add field for back pointer to sb struct(s)? */ |
315 | }; | 308 | }; |
316 | 309 | ||
@@ -363,7 +356,7 @@ struct cifsFileInfo { | |||
363 | atomic_t count; /* reference count */ | 356 | atomic_t count; /* reference count */ |
364 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | 357 | struct mutex fh_mutex; /* prevents reopen race after dead ses*/ |
365 | struct cifs_search_info srch_inf; | 358 | struct cifs_search_info srch_inf; |
366 | struct slow_work oplock_break; /* slow_work job for oplock breaks */ | 359 | struct work_struct oplock_break; /* work for oplock breaks */ |
367 | }; | 360 | }; |
368 | 361 | ||
369 | /* Take a reference on the file private data */ | 362 | /* Take a reference on the file private data */ |
@@ -398,6 +391,9 @@ struct cifsInodeInfo { | |||
398 | bool invalid_mapping:1; /* pagecache is invalid */ | 391 | bool invalid_mapping:1; /* pagecache is invalid */ |
399 | u64 server_eof; /* current file size on server */ | 392 | u64 server_eof; /* current file size on server */ |
400 | u64 uniqueid; /* server inode number */ | 393 | u64 uniqueid; /* server inode number */ |
394 | #ifdef CONFIG_CIFS_FSCACHE | ||
395 | struct fscache_cookie *fscache; | ||
396 | #endif | ||
401 | struct inode vfs_inode; | 397 | struct inode vfs_inode; |
402 | }; | 398 | }; |
403 | 399 | ||
@@ -732,4 +728,10 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
732 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 728 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
733 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 729 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
734 | 730 | ||
731 | void cifs_oplock_break(struct work_struct *work); | ||
732 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); | ||
733 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); | ||
734 | |||
735 | extern const struct slow_work_ops cifs_oplock_break_ops; | 735 | extern const struct slow_work_ops cifs_oplock_break_ops; |
736 | |||
737 | #endif /* _CIFS_GLOB_H */ | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index fb1657e0fdb8..1f5450814087 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -86,7 +86,9 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); | |||
86 | extern unsigned int smbCalcSize_LE(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, | 87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
88 | struct TCP_Server_Info *server); | 88 | struct TCP_Server_Info *server); |
89 | extern int cifs_convert_address(char *src, void *dst); | 89 | extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); |
90 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | ||
91 | unsigned short int port); | ||
90 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 92 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); |
91 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 93 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
92 | const struct cifsTconInfo *, int /* length of | 94 | const struct cifsTconInfo *, int /* length of |
@@ -106,7 +108,6 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, | |||
106 | __u16 fileHandle, struct file *file, | 108 | __u16 fileHandle, struct file *file, |
107 | struct vfsmount *mnt, unsigned int oflags); | 109 | struct vfsmount *mnt, unsigned int oflags); |
108 | extern int cifs_posix_open(char *full_path, struct inode **pinode, | 110 | extern int cifs_posix_open(char *full_path, struct inode **pinode, |
109 | struct vfsmount *mnt, | ||
110 | struct super_block *sb, | 111 | struct super_block *sb, |
111 | int mode, int oflags, | 112 | int mode, int oflags, |
112 | __u32 *poplock, __u16 *pnetfid, int xid); | 113 | __u32 *poplock, __u16 *pnetfid, int xid); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2208f06e4c45..95c2ea67edfb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "nterr.h" | 48 | #include "nterr.h" |
49 | #include "rfc1002pdu.h" | 49 | #include "rfc1002pdu.h" |
50 | #include "cn_cifs.h" | 50 | #include "cn_cifs.h" |
51 | #include "fscache.h" | ||
51 | 52 | ||
52 | #define CIFS_PORT 445 | 53 | #define CIFS_PORT 445 |
53 | #define RFC1001_PORT 139 | 54 | #define RFC1001_PORT 139 |
@@ -66,6 +67,7 @@ struct smb_vol { | |||
66 | char *iocharset; /* local code page for mapping to and from Unicode */ | 67 | char *iocharset; /* local code page for mapping to and from Unicode */ |
67 | char source_rfc1001_name[16]; /* netbios name of client */ | 68 | char source_rfc1001_name[16]; /* netbios name of client */ |
68 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 69 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ |
70 | uid_t cred_uid; | ||
69 | uid_t linux_uid; | 71 | uid_t linux_uid; |
70 | gid_t linux_gid; | 72 | gid_t linux_gid; |
71 | mode_t file_mode; | 73 | mode_t file_mode; |
@@ -97,6 +99,7 @@ struct smb_vol { | |||
97 | bool noblocksnd:1; | 99 | bool noblocksnd:1; |
98 | bool noautotune:1; | 100 | bool noautotune:1; |
99 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | 101 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ |
102 | bool fsc:1; /* enable fscache */ | ||
100 | unsigned int rsize; | 103 | unsigned int rsize; |
101 | unsigned int wsize; | 104 | unsigned int wsize; |
102 | bool sockopt_tcp_nodelay:1; | 105 | bool sockopt_tcp_nodelay:1; |
@@ -830,7 +833,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
830 | /* null target name indicates to use *SMBSERVR default called name | 833 | /* null target name indicates to use *SMBSERVR default called name |
831 | if we end up sending RFC1001 session initialize */ | 834 | if we end up sending RFC1001 session initialize */ |
832 | vol->target_rfc1001_name[0] = 0; | 835 | vol->target_rfc1001_name[0] = 0; |
833 | vol->linux_uid = current_uid(); /* use current_euid() instead? */ | 836 | vol->cred_uid = current_uid(); |
837 | vol->linux_uid = current_uid(); | ||
834 | vol->linux_gid = current_gid(); | 838 | vol->linux_gid = current_gid(); |
835 | 839 | ||
836 | /* default to only allowing write access to owner of the mount */ | 840 | /* default to only allowing write access to owner of the mount */ |
@@ -1257,6 +1261,12 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1257 | } else if ((strnicmp(data, "nocase", 6) == 0) || | 1261 | } else if ((strnicmp(data, "nocase", 6) == 0) || |
1258 | (strnicmp(data, "ignorecase", 10) == 0)) { | 1262 | (strnicmp(data, "ignorecase", 10) == 0)) { |
1259 | vol->nocase = 1; | 1263 | vol->nocase = 1; |
1264 | } else if (strnicmp(data, "mand", 4) == 0) { | ||
1265 | /* ignore */ | ||
1266 | } else if (strnicmp(data, "nomand", 6) == 0) { | ||
1267 | /* ignore */ | ||
1268 | } else if (strnicmp(data, "_netdev", 7) == 0) { | ||
1269 | /* ignore */ | ||
1260 | } else if (strnicmp(data, "brl", 3) == 0) { | 1270 | } else if (strnicmp(data, "brl", 3) == 0) { |
1261 | vol->nobrl = 0; | 1271 | vol->nobrl = 0; |
1262 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | 1272 | } else if ((strnicmp(data, "nobrl", 5) == 0) || |
@@ -1331,6 +1341,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1331 | printk(KERN_WARNING "CIFS: Mount option noac not " | 1341 | printk(KERN_WARNING "CIFS: Mount option noac not " |
1332 | "supported. Instead set " | 1342 | "supported. Instead set " |
1333 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 1343 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); |
1344 | } else if (strnicmp(data, "fsc", 3) == 0) { | ||
1345 | vol->fsc = true; | ||
1334 | } else | 1346 | } else |
1335 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1347 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", |
1336 | data); | 1348 | data); |
@@ -1380,18 +1392,92 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1380 | return 0; | 1392 | return 0; |
1381 | } | 1393 | } |
1382 | 1394 | ||
1395 | static bool | ||
1396 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr) | ||
1397 | { | ||
1398 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
1399 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1400 | |||
1401 | switch (addr->sa_family) { | ||
1402 | case AF_INET: | ||
1403 | if (addr4->sin_addr.s_addr != | ||
1404 | server->addr.sockAddr.sin_addr.s_addr) | ||
1405 | return false; | ||
1406 | if (addr4->sin_port && | ||
1407 | addr4->sin_port != server->addr.sockAddr.sin_port) | ||
1408 | return false; | ||
1409 | break; | ||
1410 | case AF_INET6: | ||
1411 | if (!ipv6_addr_equal(&addr6->sin6_addr, | ||
1412 | &server->addr.sockAddr6.sin6_addr)) | ||
1413 | return false; | ||
1414 | if (addr6->sin6_scope_id != | ||
1415 | server->addr.sockAddr6.sin6_scope_id) | ||
1416 | return false; | ||
1417 | if (addr6->sin6_port && | ||
1418 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | ||
1419 | return false; | ||
1420 | break; | ||
1421 | } | ||
1422 | |||
1423 | return true; | ||
1424 | } | ||
1425 | |||
1426 | static bool | ||
1427 | match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | ||
1428 | { | ||
1429 | unsigned int secFlags; | ||
1430 | |||
1431 | if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
1432 | secFlags = vol->secFlg; | ||
1433 | else | ||
1434 | secFlags = global_secflags | vol->secFlg; | ||
1435 | |||
1436 | switch (server->secType) { | ||
1437 | case LANMAN: | ||
1438 | if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT))) | ||
1439 | return false; | ||
1440 | break; | ||
1441 | case NTLMv2: | ||
1442 | if (!(secFlags & CIFSSEC_MAY_NTLMV2)) | ||
1443 | return false; | ||
1444 | break; | ||
1445 | case NTLM: | ||
1446 | if (!(secFlags & CIFSSEC_MAY_NTLM)) | ||
1447 | return false; | ||
1448 | break; | ||
1449 | case Kerberos: | ||
1450 | if (!(secFlags & CIFSSEC_MAY_KRB5)) | ||
1451 | return false; | ||
1452 | break; | ||
1453 | case RawNTLMSSP: | ||
1454 | if (!(secFlags & CIFSSEC_MAY_NTLMSSP)) | ||
1455 | return false; | ||
1456 | break; | ||
1457 | default: | ||
1458 | /* shouldn't happen */ | ||
1459 | return false; | ||
1460 | } | ||
1461 | |||
1462 | /* now check if signing mode is acceptible */ | ||
1463 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0 && | ||
1464 | (server->secMode & SECMODE_SIGN_REQUIRED)) | ||
1465 | return false; | ||
1466 | else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) && | ||
1467 | (server->secMode & | ||
1468 | (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0) | ||
1469 | return false; | ||
1470 | |||
1471 | return true; | ||
1472 | } | ||
1473 | |||
1383 | static struct TCP_Server_Info * | 1474 | static struct TCP_Server_Info * |
1384 | cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) | 1475 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) |
1385 | { | 1476 | { |
1386 | struct list_head *tmp; | ||
1387 | struct TCP_Server_Info *server; | 1477 | struct TCP_Server_Info *server; |
1388 | struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; | ||
1389 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; | ||
1390 | 1478 | ||
1391 | write_lock(&cifs_tcp_ses_lock); | 1479 | write_lock(&cifs_tcp_ses_lock); |
1392 | list_for_each(tmp, &cifs_tcp_ses_list) { | 1480 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
1393 | server = list_entry(tmp, struct TCP_Server_Info, | ||
1394 | tcp_ses_list); | ||
1395 | /* | 1481 | /* |
1396 | * the demux thread can exit on its own while still in CifsNew | 1482 | * the demux thread can exit on its own while still in CifsNew |
1397 | * so don't accept any sockets in that state. Since the | 1483 | * so don't accept any sockets in that state. Since the |
@@ -1401,37 +1487,11 @@ cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) | |||
1401 | if (server->tcpStatus == CifsNew) | 1487 | if (server->tcpStatus == CifsNew) |
1402 | continue; | 1488 | continue; |
1403 | 1489 | ||
1404 | switch (addr->ss_family) { | 1490 | if (!match_address(server, addr)) |
1405 | case AF_INET: | 1491 | continue; |
1406 | if (addr4->sin_addr.s_addr == | ||
1407 | server->addr.sockAddr.sin_addr.s_addr) { | ||
1408 | addr4->sin_port = htons(port); | ||
1409 | /* user overrode default port? */ | ||
1410 | if (addr4->sin_port) { | ||
1411 | if (addr4->sin_port != | ||
1412 | server->addr.sockAddr.sin_port) | ||
1413 | continue; | ||
1414 | } | ||
1415 | break; | ||
1416 | } else | ||
1417 | continue; | ||
1418 | 1492 | ||
1419 | case AF_INET6: | 1493 | if (!match_security(server, vol)) |
1420 | if (ipv6_addr_equal(&addr6->sin6_addr, | 1494 | continue; |
1421 | &server->addr.sockAddr6.sin6_addr) && | ||
1422 | (addr6->sin6_scope_id == | ||
1423 | server->addr.sockAddr6.sin6_scope_id)) { | ||
1424 | addr6->sin6_port = htons(port); | ||
1425 | /* user overrode default port? */ | ||
1426 | if (addr6->sin6_port) { | ||
1427 | if (addr6->sin6_port != | ||
1428 | server->addr.sockAddr6.sin6_port) | ||
1429 | continue; | ||
1430 | } | ||
1431 | break; | ||
1432 | } else | ||
1433 | continue; | ||
1434 | } | ||
1435 | 1495 | ||
1436 | ++server->srv_count; | 1496 | ++server->srv_count; |
1437 | write_unlock(&cifs_tcp_ses_lock); | 1497 | write_unlock(&cifs_tcp_ses_lock); |
@@ -1460,6 +1520,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
1460 | server->tcpStatus = CifsExiting; | 1520 | server->tcpStatus = CifsExiting; |
1461 | spin_unlock(&GlobalMid_Lock); | 1521 | spin_unlock(&GlobalMid_Lock); |
1462 | 1522 | ||
1523 | cifs_fscache_release_client_cookie(server); | ||
1524 | |||
1463 | task = xchg(&server->tsk, NULL); | 1525 | task = xchg(&server->tsk, NULL); |
1464 | if (task) | 1526 | if (task) |
1465 | force_sig(SIGKILL, task); | 1527 | force_sig(SIGKILL, task); |
@@ -1479,7 +1541,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1479 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); | 1541 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); |
1480 | 1542 | ||
1481 | if (volume_info->UNCip && volume_info->UNC) { | 1543 | if (volume_info->UNCip && volume_info->UNC) { |
1482 | rc = cifs_convert_address(volume_info->UNCip, &addr); | 1544 | rc = cifs_fill_sockaddr((struct sockaddr *)&addr, |
1545 | volume_info->UNCip, | ||
1546 | strlen(volume_info->UNCip), | ||
1547 | volume_info->port); | ||
1483 | if (!rc) { | 1548 | if (!rc) { |
1484 | /* we failed translating address */ | 1549 | /* we failed translating address */ |
1485 | rc = -EINVAL; | 1550 | rc = -EINVAL; |
@@ -1499,7 +1564,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1499 | } | 1564 | } |
1500 | 1565 | ||
1501 | /* see if we already have a matching tcp_ses */ | 1566 | /* see if we already have a matching tcp_ses */ |
1502 | tcp_ses = cifs_find_tcp_session(&addr, volume_info->port); | 1567 | tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info); |
1503 | if (tcp_ses) | 1568 | if (tcp_ses) |
1504 | return tcp_ses; | 1569 | return tcp_ses; |
1505 | 1570 | ||
@@ -1543,12 +1608,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1543 | cFYI(1, "attempting ipv6 connect"); | 1608 | cFYI(1, "attempting ipv6 connect"); |
1544 | /* BB should we allow ipv6 on port 139? */ | 1609 | /* BB should we allow ipv6 on port 139? */ |
1545 | /* other OS never observed in Wild doing 139 with v6 */ | 1610 | /* other OS never observed in Wild doing 139 with v6 */ |
1546 | sin_server6->sin6_port = htons(volume_info->port); | ||
1547 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1611 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, |
1548 | sizeof(struct sockaddr_in6)); | 1612 | sizeof(struct sockaddr_in6)); |
1549 | rc = ipv6_connect(tcp_ses); | 1613 | rc = ipv6_connect(tcp_ses); |
1550 | } else { | 1614 | } else { |
1551 | sin_server->sin_port = htons(volume_info->port); | ||
1552 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1615 | memcpy(&tcp_ses->addr.sockAddr, sin_server, |
1553 | sizeof(struct sockaddr_in)); | 1616 | sizeof(struct sockaddr_in)); |
1554 | rc = ipv4_connect(tcp_ses); | 1617 | rc = ipv4_connect(tcp_ses); |
@@ -1577,6 +1640,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1577 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 1640 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
1578 | write_unlock(&cifs_tcp_ses_lock); | 1641 | write_unlock(&cifs_tcp_ses_lock); |
1579 | 1642 | ||
1643 | cifs_fscache_get_client_cookie(tcp_ses); | ||
1644 | |||
1580 | return tcp_ses; | 1645 | return tcp_ses; |
1581 | 1646 | ||
1582 | out_err: | 1647 | out_err: |
@@ -1591,17 +1656,27 @@ out_err: | |||
1591 | } | 1656 | } |
1592 | 1657 | ||
1593 | static struct cifsSesInfo * | 1658 | static struct cifsSesInfo * |
1594 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) | 1659 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) |
1595 | { | 1660 | { |
1596 | struct list_head *tmp; | ||
1597 | struct cifsSesInfo *ses; | 1661 | struct cifsSesInfo *ses; |
1598 | 1662 | ||
1599 | write_lock(&cifs_tcp_ses_lock); | 1663 | write_lock(&cifs_tcp_ses_lock); |
1600 | list_for_each(tmp, &server->smb_ses_list) { | 1664 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
1601 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 1665 | switch (server->secType) { |
1602 | if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) | 1666 | case Kerberos: |
1603 | continue; | 1667 | if (vol->cred_uid != ses->cred_uid) |
1604 | 1668 | continue; | |
1669 | break; | ||
1670 | default: | ||
1671 | /* anything else takes username/password */ | ||
1672 | if (strncmp(ses->userName, vol->username, | ||
1673 | MAX_USERNAME_SIZE)) | ||
1674 | continue; | ||
1675 | if (strlen(vol->username) != 0 && | ||
1676 | strncmp(ses->password, vol->password, | ||
1677 | MAX_PASSWORD_SIZE)) | ||
1678 | continue; | ||
1679 | } | ||
1605 | ++ses->ses_count; | 1680 | ++ses->ses_count; |
1606 | write_unlock(&cifs_tcp_ses_lock); | 1681 | write_unlock(&cifs_tcp_ses_lock); |
1607 | return ses; | 1682 | return ses; |
@@ -1643,7 +1718,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1643 | 1718 | ||
1644 | xid = GetXid(); | 1719 | xid = GetXid(); |
1645 | 1720 | ||
1646 | ses = cifs_find_smb_ses(server, volume_info->username); | 1721 | ses = cifs_find_smb_ses(server, volume_info); |
1647 | if (ses) { | 1722 | if (ses) { |
1648 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); | 1723 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); |
1649 | 1724 | ||
@@ -1706,6 +1781,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1706 | if (ses->domainName) | 1781 | if (ses->domainName) |
1707 | strcpy(ses->domainName, volume_info->domainname); | 1782 | strcpy(ses->domainName, volume_info->domainname); |
1708 | } | 1783 | } |
1784 | ses->cred_uid = volume_info->cred_uid; | ||
1709 | ses->linux_uid = volume_info->linux_uid; | 1785 | ses->linux_uid = volume_info->linux_uid; |
1710 | ses->overrideSecFlg = volume_info->secFlg; | 1786 | ses->overrideSecFlg = volume_info->secFlg; |
1711 | 1787 | ||
@@ -1773,6 +1849,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1773 | CIFSSMBTDis(xid, tcon); | 1849 | CIFSSMBTDis(xid, tcon); |
1774 | _FreeXid(xid); | 1850 | _FreeXid(xid); |
1775 | 1851 | ||
1852 | cifs_fscache_release_super_cookie(tcon); | ||
1776 | tconInfoFree(tcon); | 1853 | tconInfoFree(tcon); |
1777 | cifs_put_smb_ses(ses); | 1854 | cifs_put_smb_ses(ses); |
1778 | } | 1855 | } |
@@ -1843,6 +1920,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | |||
1843 | list_add(&tcon->tcon_list, &ses->tcon_list); | 1920 | list_add(&tcon->tcon_list, &ses->tcon_list); |
1844 | write_unlock(&cifs_tcp_ses_lock); | 1921 | write_unlock(&cifs_tcp_ses_lock); |
1845 | 1922 | ||
1923 | cifs_fscache_get_super_cookie(tcon); | ||
1924 | |||
1846 | return tcon; | 1925 | return tcon; |
1847 | 1926 | ||
1848 | out_fail: | 1927 | out_fail: |
@@ -2397,6 +2476,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2397 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | 2476 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; |
2398 | if (pvolume_info->dynperm) | 2477 | if (pvolume_info->dynperm) |
2399 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 2478 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; |
2479 | if (pvolume_info->fsc) | ||
2480 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | ||
2400 | if (pvolume_info->direct_io) { | 2481 | if (pvolume_info->direct_io) { |
2401 | cFYI(1, "mounting share using direct i/o"); | 2482 | cFYI(1, "mounting share using direct i/o"); |
2402 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2483 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 391816b461ca..578d88c5b46e 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/namei.h> | 26 | #include <linux/namei.h> |
27 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
28 | #include <linux/file.h> | ||
28 | #include "cifsfs.h" | 29 | #include "cifsfs.h" |
29 | #include "cifspdu.h" | 30 | #include "cifspdu.h" |
30 | #include "cifsglob.h" | 31 | #include "cifsglob.h" |
@@ -129,12 +130,6 @@ cifs_bp_rename_retry: | |||
129 | return full_path; | 130 | return full_path; |
130 | } | 131 | } |
131 | 132 | ||
132 | /* | ||
133 | * When called with struct file pointer set to NULL, there is no way we could | ||
134 | * update file->private_data, but getting it stuck on openFileList provides a | ||
135 | * way to access it from cifs_fill_filedata and thereby set file->private_data | ||
136 | * from cifs_open. | ||
137 | */ | ||
138 | struct cifsFileInfo * | 133 | struct cifsFileInfo * |
139 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | 134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, |
140 | struct file *file, struct vfsmount *mnt, unsigned int oflags) | 135 | struct file *file, struct vfsmount *mnt, unsigned int oflags) |
@@ -162,7 +157,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
162 | mutex_init(&pCifsFile->lock_mutex); | 157 | mutex_init(&pCifsFile->lock_mutex); |
163 | INIT_LIST_HEAD(&pCifsFile->llist); | 158 | INIT_LIST_HEAD(&pCifsFile->llist); |
164 | atomic_set(&pCifsFile->count, 1); | 159 | atomic_set(&pCifsFile->count, 1); |
165 | slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); | 160 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); |
166 | 161 | ||
167 | write_lock(&GlobalSMBSeslock); | 162 | write_lock(&GlobalSMBSeslock); |
168 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | 163 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); |
@@ -184,12 +179,13 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
184 | } | 179 | } |
185 | write_unlock(&GlobalSMBSeslock); | 180 | write_unlock(&GlobalSMBSeslock); |
186 | 181 | ||
182 | file->private_data = pCifsFile; | ||
183 | |||
187 | return pCifsFile; | 184 | return pCifsFile; |
188 | } | 185 | } |
189 | 186 | ||
190 | int cifs_posix_open(char *full_path, struct inode **pinode, | 187 | int cifs_posix_open(char *full_path, struct inode **pinode, |
191 | struct vfsmount *mnt, struct super_block *sb, | 188 | struct super_block *sb, int mode, int oflags, |
192 | int mode, int oflags, | ||
193 | __u32 *poplock, __u16 *pnetfid, int xid) | 189 | __u32 *poplock, __u16 *pnetfid, int xid) |
194 | { | 190 | { |
195 | int rc; | 191 | int rc; |
@@ -258,19 +254,6 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
258 | cifs_fattr_to_inode(*pinode, &fattr); | 254 | cifs_fattr_to_inode(*pinode, &fattr); |
259 | } | 255 | } |
260 | 256 | ||
261 | /* | ||
262 | * cifs_fill_filedata() takes care of setting cifsFileInfo pointer to | ||
263 | * file->private_data. | ||
264 | */ | ||
265 | if (mnt) { | ||
266 | struct cifsFileInfo *pfile_info; | ||
267 | |||
268 | pfile_info = cifs_new_fileinfo(*pinode, *pnetfid, NULL, mnt, | ||
269 | oflags); | ||
270 | if (pfile_info == NULL) | ||
271 | rc = -ENOMEM; | ||
272 | } | ||
273 | |||
274 | posix_open_ret: | 257 | posix_open_ret: |
275 | kfree(presp_data); | 258 | kfree(presp_data); |
276 | return rc; | 259 | return rc; |
@@ -298,7 +281,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
298 | int create_options = CREATE_NOT_DIR; | 281 | int create_options = CREATE_NOT_DIR; |
299 | __u32 oplock = 0; | 282 | __u32 oplock = 0; |
300 | int oflags; | 283 | int oflags; |
301 | bool posix_create = false; | ||
302 | /* | 284 | /* |
303 | * BB below access is probably too much for mknod to request | 285 | * BB below access is probably too much for mknod to request |
304 | * but we have to do query and setpathinfo so requesting | 286 | * but we have to do query and setpathinfo so requesting |
@@ -339,7 +321,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
339 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 321 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
340 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 322 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
341 | rc = cifs_posix_open(full_path, &newinode, | 323 | rc = cifs_posix_open(full_path, &newinode, |
342 | nd ? nd->path.mnt : NULL, | ||
343 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); | 324 | inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); |
344 | /* EIO could indicate that (posix open) operation is not | 325 | /* EIO could indicate that (posix open) operation is not |
345 | supported, despite what server claimed in capability | 326 | supported, despite what server claimed in capability |
@@ -347,7 +328,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
347 | handled in posix open */ | 328 | handled in posix open */ |
348 | 329 | ||
349 | if (rc == 0) { | 330 | if (rc == 0) { |
350 | posix_create = true; | ||
351 | if (newinode == NULL) /* query inode info */ | 331 | if (newinode == NULL) /* query inode info */ |
352 | goto cifs_create_get_file_info; | 332 | goto cifs_create_get_file_info; |
353 | else /* success, no need to query */ | 333 | else /* success, no need to query */ |
@@ -478,21 +458,28 @@ cifs_create_set_dentry: | |||
478 | else | 458 | else |
479 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); | 459 | cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); |
480 | 460 | ||
481 | /* nfsd case - nfs srv does not set nd */ | 461 | if (newinode && nd && (nd->flags & LOOKUP_OPEN)) { |
482 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { | ||
483 | /* mknod case - do not leave file open */ | ||
484 | CIFSSMBClose(xid, tcon, fileHandle); | ||
485 | } else if (!(posix_create) && (newinode)) { | ||
486 | struct cifsFileInfo *pfile_info; | 462 | struct cifsFileInfo *pfile_info; |
487 | /* | 463 | struct file *filp; |
488 | * cifs_fill_filedata() takes care of setting cifsFileInfo | 464 | |
489 | * pointer to file->private_data. | 465 | filp = lookup_instantiate_filp(nd, direntry, generic_file_open); |
490 | */ | 466 | if (IS_ERR(filp)) { |
491 | pfile_info = cifs_new_fileinfo(newinode, fileHandle, NULL, | 467 | rc = PTR_ERR(filp); |
468 | CIFSSMBClose(xid, tcon, fileHandle); | ||
469 | goto cifs_create_out; | ||
470 | } | ||
471 | |||
472 | pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, | ||
492 | nd->path.mnt, oflags); | 473 | nd->path.mnt, oflags); |
493 | if (pfile_info == NULL) | 474 | if (pfile_info == NULL) { |
475 | fput(filp); | ||
476 | CIFSSMBClose(xid, tcon, fileHandle); | ||
494 | rc = -ENOMEM; | 477 | rc = -ENOMEM; |
478 | } | ||
479 | } else { | ||
480 | CIFSSMBClose(xid, tcon, fileHandle); | ||
495 | } | 481 | } |
482 | |||
496 | cifs_create_out: | 483 | cifs_create_out: |
497 | kfree(buf); | 484 | kfree(buf); |
498 | kfree(full_path); | 485 | kfree(full_path); |
@@ -636,6 +623,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
636 | bool posix_open = false; | 623 | bool posix_open = false; |
637 | struct cifs_sb_info *cifs_sb; | 624 | struct cifs_sb_info *cifs_sb; |
638 | struct cifsTconInfo *pTcon; | 625 | struct cifsTconInfo *pTcon; |
626 | struct cifsFileInfo *cfile; | ||
639 | struct inode *newInode = NULL; | 627 | struct inode *newInode = NULL; |
640 | char *full_path = NULL; | 628 | char *full_path = NULL; |
641 | struct file *filp; | 629 | struct file *filp; |
@@ -703,7 +691,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
703 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 691 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
704 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 692 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
705 | (nd->intent.open.flags & O_CREAT)) { | 693 | (nd->intent.open.flags & O_CREAT)) { |
706 | rc = cifs_posix_open(full_path, &newInode, nd->path.mnt, | 694 | rc = cifs_posix_open(full_path, &newInode, |
707 | parent_dir_inode->i_sb, | 695 | parent_dir_inode->i_sb, |
708 | nd->intent.open.create_mode, | 696 | nd->intent.open.create_mode, |
709 | nd->intent.open.flags, &oplock, | 697 | nd->intent.open.flags, &oplock, |
@@ -733,8 +721,25 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
733 | else | 721 | else |
734 | direntry->d_op = &cifs_dentry_ops; | 722 | direntry->d_op = &cifs_dentry_ops; |
735 | d_add(direntry, newInode); | 723 | d_add(direntry, newInode); |
736 | if (posix_open) | 724 | if (posix_open) { |
737 | filp = lookup_instantiate_filp(nd, direntry, NULL); | 725 | filp = lookup_instantiate_filp(nd, direntry, |
726 | generic_file_open); | ||
727 | if (IS_ERR(filp)) { | ||
728 | rc = PTR_ERR(filp); | ||
729 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
730 | goto lookup_out; | ||
731 | } | ||
732 | |||
733 | cfile = cifs_new_fileinfo(newInode, fileHandle, filp, | ||
734 | nd->path.mnt, | ||
735 | nd->intent.open.flags); | ||
736 | if (cfile == NULL) { | ||
737 | fput(filp); | ||
738 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
739 | rc = -ENOMEM; | ||
740 | goto lookup_out; | ||
741 | } | ||
742 | } | ||
738 | /* since paths are not looked up by component - the parent | 743 | /* since paths are not looked up by component - the parent |
739 | directories are presumed to be good here */ | 744 | directories are presumed to be good here */ |
740 | renew_parental_timestamps(direntry); | 745 | renew_parental_timestamps(direntry); |
@@ -755,6 +760,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
755 | is a common return code */ | 760 | is a common return code */ |
756 | } | 761 | } |
757 | 762 | ||
763 | lookup_out: | ||
758 | kfree(full_path); | 764 | kfree(full_path); |
759 | FreeXid(xid); | 765 | FreeXid(xid); |
760 | return ERR_PTR(rc); | 766 | return ERR_PTR(rc); |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 4db2c5e7283f..0eb87026cad3 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (c) 2007 Igor Mammedov | 4 | * Copyright (c) 2007 Igor Mammedov |
5 | * Author(s): Igor Mammedov (niallain@gmail.com) | 5 | * Author(s): Igor Mammedov (niallain@gmail.com) |
6 | * Steve French (sfrench@us.ibm.com) | 6 | * Steve French (sfrench@us.ibm.com) |
7 | * Wang Lei (wang840925@gmail.com) | ||
8 | * David Howells (dhowells@redhat.com) | ||
7 | * | 9 | * |
8 | * Contains the CIFS DFS upcall routines used for hostname to | 10 | * Contains the CIFS DFS upcall routines used for hostname to |
9 | * IP address translation. | 11 | * IP address translation. |
@@ -24,145 +26,73 @@ | |||
24 | */ | 26 | */ |
25 | 27 | ||
26 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
27 | #include <keys/user-type.h> | 29 | #include <linux/dns_resolver.h> |
28 | #include "dns_resolve.h" | 30 | #include "dns_resolve.h" |
29 | #include "cifsglob.h" | 31 | #include "cifsglob.h" |
30 | #include "cifsproto.h" | 32 | #include "cifsproto.h" |
31 | #include "cifs_debug.h" | 33 | #include "cifs_debug.h" |
32 | 34 | ||
33 | /* Checks if supplied name is IP address | 35 | /** |
34 | * returns: | 36 | * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. |
35 | * 1 - name is IP | 37 | * @unc: UNC path specifying the server |
36 | * 0 - name is not IP | 38 | * @ip_addr: Where to return the IP address. |
37 | */ | 39 | * |
38 | static int | 40 | * The IP address will be returned in string form, and the caller is |
39 | is_ip(char *name) | 41 | * responsible for freeing it. |
40 | { | 42 | * |
41 | struct sockaddr_storage ss; | 43 | * Returns length of result on success, -ve on error. |
42 | |||
43 | return cifs_convert_address(name, &ss); | ||
44 | } | ||
45 | |||
46 | static int | ||
47 | dns_resolver_instantiate(struct key *key, const void *data, | ||
48 | size_t datalen) | ||
49 | { | ||
50 | int rc = 0; | ||
51 | char *ip; | ||
52 | |||
53 | ip = kmalloc(datalen + 1, GFP_KERNEL); | ||
54 | if (!ip) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | memcpy(ip, data, datalen); | ||
58 | ip[datalen] = '\0'; | ||
59 | |||
60 | /* make sure this looks like an address */ | ||
61 | if (!is_ip(ip)) { | ||
62 | kfree(ip); | ||
63 | return -EINVAL; | ||
64 | } | ||
65 | |||
66 | key->type_data.x[0] = datalen; | ||
67 | key->payload.data = ip; | ||
68 | |||
69 | return rc; | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | dns_resolver_destroy(struct key *key) | ||
74 | { | ||
75 | kfree(key->payload.data); | ||
76 | } | ||
77 | |||
78 | struct key_type key_type_dns_resolver = { | ||
79 | .name = "dns_resolver", | ||
80 | .def_datalen = sizeof(struct in_addr), | ||
81 | .describe = user_describe, | ||
82 | .instantiate = dns_resolver_instantiate, | ||
83 | .destroy = dns_resolver_destroy, | ||
84 | .match = user_match, | ||
85 | }; | ||
86 | |||
87 | /* Resolves server name to ip address. | ||
88 | * input: | ||
89 | * unc - server UNC | ||
90 | * output: | ||
91 | * *ip_addr - pointer to server ip, caller responcible for freeing it. | ||
92 | * return 0 on success | ||
93 | */ | 44 | */ |
94 | int | 45 | int |
95 | dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) | 46 | dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) |
96 | { | 47 | { |
97 | int rc = -EAGAIN; | 48 | struct sockaddr_storage ss; |
98 | struct key *rkey = ERR_PTR(-EAGAIN); | 49 | const char *hostname, *sep; |
99 | char *name; | 50 | char *name; |
100 | char *data = NULL; | 51 | int len, rc; |
101 | int len; | ||
102 | 52 | ||
103 | if (!ip_addr || !unc) | 53 | if (!ip_addr || !unc) |
104 | return -EINVAL; | 54 | return -EINVAL; |
105 | 55 | ||
106 | /* search for server name delimiter */ | ||
107 | len = strlen(unc); | 56 | len = strlen(unc); |
108 | if (len < 3) { | 57 | if (len < 3) { |
109 | cFYI(1, "%s: unc is too short: %s", __func__, unc); | 58 | cFYI(1, "%s: unc is too short: %s", __func__, unc); |
110 | return -EINVAL; | 59 | return -EINVAL; |
111 | } | 60 | } |
61 | |||
62 | /* Discount leading slashes for cifs */ | ||
112 | len -= 2; | 63 | len -= 2; |
113 | name = memchr(unc+2, '\\', len); | 64 | hostname = unc + 2; |
114 | if (!name) { | 65 | |
66 | /* Search for server name delimiter */ | ||
67 | sep = memchr(hostname, '\\', len); | ||
68 | if (sep) | ||
69 | len = sep - unc; | ||
70 | else | ||
115 | cFYI(1, "%s: probably server name is whole unc: %s", | 71 | cFYI(1, "%s: probably server name is whole unc: %s", |
116 | __func__, unc); | 72 | __func__, unc); |
117 | } else { | 73 | |
118 | len = (name - unc) - 2/* leading // */; | 74 | /* Try to interpret hostname as an IPv4 or IPv6 address */ |
119 | } | 75 | rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len); |
76 | if (rc > 0) | ||
77 | goto name_is_IP_address; | ||
78 | |||
79 | /* Perform the upcall */ | ||
80 | rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL); | ||
81 | if (rc < 0) | ||
82 | cERROR(1, "%s: unable to resolve: %*.*s", | ||
83 | __func__, len, len, hostname); | ||
84 | else | ||
85 | cFYI(1, "%s: resolved: %*.*s to %s", | ||
86 | __func__, len, len, hostname, *ip_addr); | ||
87 | return rc; | ||
120 | 88 | ||
121 | name = kmalloc(len+1, GFP_KERNEL); | 89 | name_is_IP_address: |
122 | if (!name) { | 90 | name = kmalloc(len + 1, GFP_KERNEL); |
123 | rc = -ENOMEM; | 91 | if (!name) |
124 | return rc; | 92 | return -ENOMEM; |
125 | } | 93 | memcpy(name, hostname, len); |
126 | memcpy(name, unc+2, len); | ||
127 | name[len] = 0; | 94 | name[len] = 0; |
128 | 95 | cFYI(1, "%s: unc is IP, skipping dns upcall: %s", __func__, name); | |
129 | if (is_ip(name)) { | 96 | *ip_addr = name; |
130 | cFYI(1, "%s: it is IP, skipping dns upcall: %s", | 97 | return 0; |
131 | __func__, name); | ||
132 | data = name; | ||
133 | goto skip_upcall; | ||
134 | } | ||
135 | |||
136 | rkey = request_key(&key_type_dns_resolver, name, ""); | ||
137 | if (!IS_ERR(rkey)) { | ||
138 | len = rkey->type_data.x[0]; | ||
139 | data = rkey->payload.data; | ||
140 | } else { | ||
141 | cERROR(1, "%s: unable to resolve: %s", __func__, name); | ||
142 | goto out; | ||
143 | } | ||
144 | |||
145 | skip_upcall: | ||
146 | if (data) { | ||
147 | *ip_addr = kmalloc(len + 1, GFP_KERNEL); | ||
148 | if (*ip_addr) { | ||
149 | memcpy(*ip_addr, data, len + 1); | ||
150 | if (!IS_ERR(rkey)) | ||
151 | cFYI(1, "%s: resolved: %s to %s", __func__, | ||
152 | name, | ||
153 | *ip_addr | ||
154 | ); | ||
155 | rc = 0; | ||
156 | } else { | ||
157 | rc = -ENOMEM; | ||
158 | } | ||
159 | if (!IS_ERR(rkey)) | ||
160 | key_put(rkey); | ||
161 | } | ||
162 | |||
163 | out: | ||
164 | kfree(name); | ||
165 | return rc; | ||
166 | } | 98 | } |
167 | |||
168 | |||
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h index 966e9288930b..d3f5d27f4d06 100644 --- a/fs/cifs/dns_resolve.h +++ b/fs/cifs/dns_resolve.h | |||
@@ -24,8 +24,6 @@ | |||
24 | #define _DNS_RESOLVE_H | 24 | #define _DNS_RESOLVE_H |
25 | 25 | ||
26 | #ifdef __KERNEL__ | 26 | #ifdef __KERNEL__ |
27 | #include <linux/key-type.h> | ||
28 | extern struct key_type key_type_dns_resolver; | ||
29 | extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); | 27 | extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); |
30 | #endif /* KERNEL */ | 28 | #endif /* KERNEL */ |
31 | 29 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f1ff785b2292..db11fdef0e92 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "cifs_unicode.h" | 40 | #include "cifs_unicode.h" |
41 | #include "cifs_debug.h" | 41 | #include "cifs_debug.h" |
42 | #include "cifs_fs_sb.h" | 42 | #include "cifs_fs_sb.h" |
43 | #include "fscache.h" | ||
43 | 44 | ||
44 | static inline int cifs_convert_flags(unsigned int flags) | 45 | static inline int cifs_convert_flags(unsigned int flags) |
45 | { | 46 | { |
@@ -162,44 +163,12 @@ psx_client_can_cache: | |||
162 | return 0; | 163 | return 0; |
163 | } | 164 | } |
164 | 165 | ||
165 | static struct cifsFileInfo * | ||
166 | cifs_fill_filedata(struct file *file) | ||
167 | { | ||
168 | struct list_head *tmp; | ||
169 | struct cifsFileInfo *pCifsFile = NULL; | ||
170 | struct cifsInodeInfo *pCifsInode = NULL; | ||
171 | |||
172 | /* search inode for this file and fill in file->private_data */ | ||
173 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | ||
174 | read_lock(&GlobalSMBSeslock); | ||
175 | list_for_each(tmp, &pCifsInode->openFileList) { | ||
176 | pCifsFile = list_entry(tmp, struct cifsFileInfo, flist); | ||
177 | if ((pCifsFile->pfile == NULL) && | ||
178 | (pCifsFile->pid == current->tgid)) { | ||
179 | /* mode set in cifs_create */ | ||
180 | |||
181 | /* needed for writepage */ | ||
182 | pCifsFile->pfile = file; | ||
183 | file->private_data = pCifsFile; | ||
184 | break; | ||
185 | } | ||
186 | } | ||
187 | read_unlock(&GlobalSMBSeslock); | ||
188 | |||
189 | if (file->private_data != NULL) { | ||
190 | return pCifsFile; | ||
191 | } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL)) | ||
192 | cERROR(1, "could not find file instance for " | ||
193 | "new file %p", file); | ||
194 | return NULL; | ||
195 | } | ||
196 | |||
197 | /* all arguments to this function must be checked for validity in caller */ | 166 | /* all arguments to this function must be checked for validity in caller */ |
198 | static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | 167 | static inline int cifs_open_inode_helper(struct inode *inode, |
199 | struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, | ||
200 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, | 168 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, |
201 | char *full_path, int xid) | 169 | char *full_path, int xid) |
202 | { | 170 | { |
171 | struct cifsInodeInfo *pCifsInode = CIFS_I(inode); | ||
203 | struct timespec temp; | 172 | struct timespec temp; |
204 | int rc; | 173 | int rc; |
205 | 174 | ||
@@ -213,36 +182,35 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | |||
213 | /* if not oplocked, invalidate inode pages if mtime or file | 182 | /* if not oplocked, invalidate inode pages if mtime or file |
214 | size changed */ | 183 | size changed */ |
215 | temp = cifs_NTtimeToUnix(buf->LastWriteTime); | 184 | temp = cifs_NTtimeToUnix(buf->LastWriteTime); |
216 | if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) && | 185 | if (timespec_equal(&inode->i_mtime, &temp) && |
217 | (file->f_path.dentry->d_inode->i_size == | 186 | (inode->i_size == |
218 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | 187 | (loff_t)le64_to_cpu(buf->EndOfFile))) { |
219 | cFYI(1, "inode unchanged on server"); | 188 | cFYI(1, "inode unchanged on server"); |
220 | } else { | 189 | } else { |
221 | if (file->f_path.dentry->d_inode->i_mapping) { | 190 | if (inode->i_mapping) { |
222 | /* BB no need to lock inode until after invalidate | 191 | /* BB no need to lock inode until after invalidate |
223 | since namei code should already have it locked? */ | 192 | since namei code should already have it locked? */ |
224 | rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); | 193 | rc = filemap_write_and_wait(inode->i_mapping); |
225 | if (rc != 0) | 194 | if (rc != 0) |
226 | CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; | 195 | pCifsInode->write_behind_rc = rc; |
227 | } | 196 | } |
228 | cFYI(1, "invalidating remote inode since open detected it " | 197 | cFYI(1, "invalidating remote inode since open detected it " |
229 | "changed"); | 198 | "changed"); |
230 | invalidate_remote_inode(file->f_path.dentry->d_inode); | 199 | invalidate_remote_inode(inode); |
231 | } | 200 | } |
232 | 201 | ||
233 | client_can_cache: | 202 | client_can_cache: |
234 | if (pTcon->unix_ext) | 203 | if (pTcon->unix_ext) |
235 | rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode, | 204 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, |
236 | full_path, inode->i_sb, xid); | 205 | xid); |
237 | else | 206 | else |
238 | rc = cifs_get_inode_info(&file->f_path.dentry->d_inode, | 207 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, |
239 | full_path, buf, inode->i_sb, xid, NULL); | 208 | xid, NULL); |
240 | 209 | ||
241 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { | 210 | if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { |
242 | pCifsInode->clientCanCacheAll = true; | 211 | pCifsInode->clientCanCacheAll = true; |
243 | pCifsInode->clientCanCacheRead = true; | 212 | pCifsInode->clientCanCacheRead = true; |
244 | cFYI(1, "Exclusive Oplock granted on inode %p", | 213 | cFYI(1, "Exclusive Oplock granted on inode %p", inode); |
245 | file->f_path.dentry->d_inode); | ||
246 | } else if ((*oplock & 0xF) == OPLOCK_READ) | 214 | } else if ((*oplock & 0xF) == OPLOCK_READ) |
247 | pCifsInode->clientCanCacheRead = true; | 215 | pCifsInode->clientCanCacheRead = true; |
248 | 216 | ||
@@ -256,7 +224,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
256 | __u32 oplock; | 224 | __u32 oplock; |
257 | struct cifs_sb_info *cifs_sb; | 225 | struct cifs_sb_info *cifs_sb; |
258 | struct cifsTconInfo *tcon; | 226 | struct cifsTconInfo *tcon; |
259 | struct cifsFileInfo *pCifsFile; | 227 | struct cifsFileInfo *pCifsFile = NULL; |
260 | struct cifsInodeInfo *pCifsInode; | 228 | struct cifsInodeInfo *pCifsInode; |
261 | char *full_path = NULL; | 229 | char *full_path = NULL; |
262 | int desiredAccess; | 230 | int desiredAccess; |
@@ -270,12 +238,6 @@ int cifs_open(struct inode *inode, struct file *file) | |||
270 | tcon = cifs_sb->tcon; | 238 | tcon = cifs_sb->tcon; |
271 | 239 | ||
272 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 240 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
273 | pCifsFile = cifs_fill_filedata(file); | ||
274 | if (pCifsFile) { | ||
275 | rc = 0; | ||
276 | FreeXid(xid); | ||
277 | return rc; | ||
278 | } | ||
279 | 241 | ||
280 | full_path = build_path_from_dentry(file->f_path.dentry); | 242 | full_path = build_path_from_dentry(file->f_path.dentry); |
281 | if (full_path == NULL) { | 243 | if (full_path == NULL) { |
@@ -299,8 +261,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
299 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 261 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); |
300 | oflags |= SMB_O_CREAT; | 262 | oflags |= SMB_O_CREAT; |
301 | /* can not refresh inode info since size could be stale */ | 263 | /* can not refresh inode info since size could be stale */ |
302 | rc = cifs_posix_open(full_path, &inode, file->f_path.mnt, | 264 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, |
303 | inode->i_sb, | ||
304 | cifs_sb->mnt_file_mode /* ignored */, | 265 | cifs_sb->mnt_file_mode /* ignored */, |
305 | oflags, &oplock, &netfid, xid); | 266 | oflags, &oplock, &netfid, xid); |
306 | if (rc == 0) { | 267 | if (rc == 0) { |
@@ -308,9 +269,23 @@ int cifs_open(struct inode *inode, struct file *file) | |||
308 | /* no need for special case handling of setting mode | 269 | /* no need for special case handling of setting mode |
309 | on read only files needed here */ | 270 | on read only files needed here */ |
310 | 271 | ||
311 | pCifsFile = cifs_fill_filedata(file); | 272 | rc = cifs_posix_open_inode_helper(inode, file, |
312 | cifs_posix_open_inode_helper(inode, file, pCifsInode, | 273 | pCifsInode, oplock, netfid); |
313 | oplock, netfid); | 274 | if (rc != 0) { |
275 | CIFSSMBClose(xid, tcon, netfid); | ||
276 | goto out; | ||
277 | } | ||
278 | |||
279 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, | ||
280 | file->f_path.mnt, | ||
281 | oflags); | ||
282 | if (pCifsFile == NULL) { | ||
283 | CIFSSMBClose(xid, tcon, netfid); | ||
284 | rc = -ENOMEM; | ||
285 | } | ||
286 | |||
287 | cifs_fscache_set_inode_cookie(inode, file); | ||
288 | |||
314 | goto out; | 289 | goto out; |
315 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 290 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
316 | if (tcon->ses->serverNOS) | 291 | if (tcon->ses->serverNOS) |
@@ -391,16 +366,18 @@ int cifs_open(struct inode *inode, struct file *file) | |||
391 | goto out; | 366 | goto out; |
392 | } | 367 | } |
393 | 368 | ||
369 | rc = cifs_open_inode_helper(inode, tcon, &oplock, buf, full_path, xid); | ||
370 | if (rc != 0) | ||
371 | goto out; | ||
372 | |||
394 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, | 373 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, |
395 | file->f_flags); | 374 | file->f_flags); |
396 | file->private_data = pCifsFile; | 375 | if (pCifsFile == NULL) { |
397 | if (file->private_data == NULL) { | ||
398 | rc = -ENOMEM; | 376 | rc = -ENOMEM; |
399 | goto out; | 377 | goto out; |
400 | } | 378 | } |
401 | 379 | ||
402 | rc = cifs_open_inode_helper(inode, file, pCifsInode, pCifsFile, tcon, | 380 | cifs_fscache_set_inode_cookie(inode, file); |
403 | &oplock, buf, full_path, xid); | ||
404 | 381 | ||
405 | if (oplock & CIFS_CREATE_ACTION) { | 382 | if (oplock & CIFS_CREATE_ACTION) { |
406 | /* time to set mode which we can not set earlier due to | 383 | /* time to set mode which we can not set earlier due to |
@@ -456,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
456 | __u16 netfid; | 433 | __u16 netfid; |
457 | 434 | ||
458 | if (file->private_data) | 435 | if (file->private_data) |
459 | pCifsFile = (struct cifsFileInfo *)file->private_data; | 436 | pCifsFile = file->private_data; |
460 | else | 437 | else |
461 | return -EBADF; | 438 | return -EBADF; |
462 | 439 | ||
@@ -513,8 +490,7 @@ reopen_error_exit: | |||
513 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 490 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
514 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 491 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); |
515 | /* can not refresh inode info since size could be stale */ | 492 | /* can not refresh inode info since size could be stale */ |
516 | rc = cifs_posix_open(full_path, NULL, file->f_path.mnt, | 493 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, |
517 | inode->i_sb, | ||
518 | cifs_sb->mnt_file_mode /* ignored */, | 494 | cifs_sb->mnt_file_mode /* ignored */, |
519 | oflags, &oplock, &netfid, xid); | 495 | oflags, &oplock, &netfid, xid); |
520 | if (rc == 0) { | 496 | if (rc == 0) { |
@@ -595,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
595 | int xid, timeout; | 571 | int xid, timeout; |
596 | struct cifs_sb_info *cifs_sb; | 572 | struct cifs_sb_info *cifs_sb; |
597 | struct cifsTconInfo *pTcon; | 573 | struct cifsTconInfo *pTcon; |
598 | struct cifsFileInfo *pSMBFile = | 574 | struct cifsFileInfo *pSMBFile = file->private_data; |
599 | (struct cifsFileInfo *)file->private_data; | ||
600 | 575 | ||
601 | xid = GetXid(); | 576 | xid = GetXid(); |
602 | 577 | ||
@@ -671,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
671 | { | 646 | { |
672 | int rc = 0; | 647 | int rc = 0; |
673 | int xid; | 648 | int xid; |
674 | struct cifsFileInfo *pCFileStruct = | 649 | struct cifsFileInfo *pCFileStruct = file->private_data; |
675 | (struct cifsFileInfo *)file->private_data; | ||
676 | char *ptmp; | 650 | char *ptmp; |
677 | 651 | ||
678 | cFYI(1, "Closedir inode = 0x%p", inode); | 652 | cFYI(1, "Closedir inode = 0x%p", inode); |
@@ -893,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
893 | length, pfLock, | 867 | length, pfLock, |
894 | posix_lock_type, wait_flag); | 868 | posix_lock_type, wait_flag); |
895 | } else { | 869 | } else { |
896 | struct cifsFileInfo *fid = | 870 | struct cifsFileInfo *fid = file->private_data; |
897 | (struct cifsFileInfo *)file->private_data; | ||
898 | 871 | ||
899 | if (numLock) { | 872 | if (numLock) { |
900 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 873 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
@@ -995,7 +968,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
995 | 968 | ||
996 | if (file->private_data == NULL) | 969 | if (file->private_data == NULL) |
997 | return -EBADF; | 970 | return -EBADF; |
998 | open_file = (struct cifsFileInfo *) file->private_data; | 971 | open_file = file->private_data; |
999 | 972 | ||
1000 | rc = generic_write_checks(file, poffset, &write_size, 0); | 973 | rc = generic_write_checks(file, poffset, &write_size, 0); |
1001 | if (rc) | 974 | if (rc) |
@@ -1097,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
1097 | 1070 | ||
1098 | if (file->private_data == NULL) | 1071 | if (file->private_data == NULL) |
1099 | return -EBADF; | 1072 | return -EBADF; |
1100 | open_file = (struct cifsFileInfo *)file->private_data; | 1073 | open_file = file->private_data; |
1101 | 1074 | ||
1102 | xid = GetXid(); | 1075 | xid = GetXid(); |
1103 | 1076 | ||
@@ -1681,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync) | |||
1681 | int xid; | 1654 | int xid; |
1682 | int rc = 0; | 1655 | int rc = 0; |
1683 | struct cifsTconInfo *tcon; | 1656 | struct cifsTconInfo *tcon; |
1684 | struct cifsFileInfo *smbfile = | 1657 | struct cifsFileInfo *smbfile = file->private_data; |
1685 | (struct cifsFileInfo *)file->private_data; | ||
1686 | struct inode *inode = file->f_path.dentry->d_inode; | 1658 | struct inode *inode = file->f_path.dentry->d_inode; |
1687 | 1659 | ||
1688 | xid = GetXid(); | 1660 | xid = GetXid(); |
@@ -1786,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1786 | FreeXid(xid); | 1758 | FreeXid(xid); |
1787 | return rc; | 1759 | return rc; |
1788 | } | 1760 | } |
1789 | open_file = (struct cifsFileInfo *)file->private_data; | 1761 | open_file = file->private_data; |
1790 | 1762 | ||
1791 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1763 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1792 | cFYI(1, "attempting read on write only file instance"); | 1764 | cFYI(1, "attempting read on write only file instance"); |
@@ -1867,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1867 | FreeXid(xid); | 1839 | FreeXid(xid); |
1868 | return rc; | 1840 | return rc; |
1869 | } | 1841 | } |
1870 | open_file = (struct cifsFileInfo *)file->private_data; | 1842 | open_file = file->private_data; |
1871 | 1843 | ||
1872 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1844 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1873 | cFYI(1, "attempting read on write only file instance"); | 1845 | cFYI(1, "attempting read on write only file instance"); |
@@ -1952,6 +1924,7 @@ static void cifs_copy_cache_pages(struct address_space *mapping, | |||
1952 | bytes_read -= PAGE_CACHE_SIZE; | 1924 | bytes_read -= PAGE_CACHE_SIZE; |
1953 | continue; | 1925 | continue; |
1954 | } | 1926 | } |
1927 | page_cache_release(page); | ||
1955 | 1928 | ||
1956 | target = kmap_atomic(page, KM_USER0); | 1929 | target = kmap_atomic(page, KM_USER0); |
1957 | 1930 | ||
@@ -1971,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping, | |||
1971 | SetPageUptodate(page); | 1944 | SetPageUptodate(page); |
1972 | unlock_page(page); | 1945 | unlock_page(page); |
1973 | data += PAGE_CACHE_SIZE; | 1946 | data += PAGE_CACHE_SIZE; |
1947 | |||
1948 | /* add page to FS-Cache */ | ||
1949 | cifs_readpage_to_fscache(mapping->host, page); | ||
1974 | } | 1950 | } |
1975 | return; | 1951 | return; |
1976 | } | 1952 | } |
@@ -1997,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1997 | FreeXid(xid); | 1973 | FreeXid(xid); |
1998 | return rc; | 1974 | return rc; |
1999 | } | 1975 | } |
2000 | open_file = (struct cifsFileInfo *)file->private_data; | 1976 | open_file = file->private_data; |
2001 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1977 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
2002 | pTcon = cifs_sb->tcon; | 1978 | pTcon = cifs_sb->tcon; |
2003 | 1979 | ||
1980 | /* | ||
1981 | * Reads as many pages as possible from fscache. Returns -ENOBUFS | ||
1982 | * immediately if the cookie is negative | ||
1983 | */ | ||
1984 | rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, | ||
1985 | &num_pages); | ||
1986 | if (rc == 0) | ||
1987 | goto read_complete; | ||
1988 | |||
2004 | cFYI(DBG2, "rpages: num pages %d", num_pages); | 1989 | cFYI(DBG2, "rpages: num pages %d", num_pages); |
2005 | for (i = 0; i < num_pages; ) { | 1990 | for (i = 0; i < num_pages; ) { |
2006 | unsigned contig_pages; | 1991 | unsigned contig_pages; |
@@ -2111,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2111 | smb_read_data = NULL; | 2096 | smb_read_data = NULL; |
2112 | } | 2097 | } |
2113 | 2098 | ||
2099 | read_complete: | ||
2114 | FreeXid(xid); | 2100 | FreeXid(xid); |
2115 | return rc; | 2101 | return rc; |
2116 | } | 2102 | } |
@@ -2121,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
2121 | char *read_data; | 2107 | char *read_data; |
2122 | int rc; | 2108 | int rc; |
2123 | 2109 | ||
2110 | /* Is the page cached? */ | ||
2111 | rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page); | ||
2112 | if (rc == 0) | ||
2113 | goto read_complete; | ||
2114 | |||
2124 | page_cache_get(page); | 2115 | page_cache_get(page); |
2125 | read_data = kmap(page); | 2116 | read_data = kmap(page); |
2126 | /* for reads over a certain size could initiate async read ahead */ | 2117 | /* for reads over a certain size could initiate async read ahead */ |
@@ -2140,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
2140 | 2131 | ||
2141 | flush_dcache_page(page); | 2132 | flush_dcache_page(page); |
2142 | SetPageUptodate(page); | 2133 | SetPageUptodate(page); |
2134 | |||
2135 | /* send this page to the cache */ | ||
2136 | cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page); | ||
2137 | |||
2143 | rc = 0; | 2138 | rc = 0; |
2144 | 2139 | ||
2145 | io_error: | 2140 | io_error: |
2146 | kunmap(page); | 2141 | kunmap(page); |
2147 | page_cache_release(page); | 2142 | page_cache_release(page); |
2143 | |||
2144 | read_complete: | ||
2148 | return rc; | 2145 | return rc; |
2149 | } | 2146 | } |
2150 | 2147 | ||
@@ -2294,8 +2291,23 @@ out: | |||
2294 | return rc; | 2291 | return rc; |
2295 | } | 2292 | } |
2296 | 2293 | ||
2297 | static void | 2294 | static int cifs_release_page(struct page *page, gfp_t gfp) |
2298 | cifs_oplock_break(struct slow_work *work) | 2295 | { |
2296 | if (PagePrivate(page)) | ||
2297 | return 0; | ||
2298 | |||
2299 | return cifs_fscache_release_page(page, gfp); | ||
2300 | } | ||
2301 | |||
2302 | static void cifs_invalidate_page(struct page *page, unsigned long offset) | ||
2303 | { | ||
2304 | struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); | ||
2305 | |||
2306 | if (offset == 0) | ||
2307 | cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); | ||
2308 | } | ||
2309 | |||
2310 | void cifs_oplock_break(struct work_struct *work) | ||
2299 | { | 2311 | { |
2300 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | 2312 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
2301 | oplock_break); | 2313 | oplock_break); |
@@ -2332,33 +2344,30 @@ cifs_oplock_break(struct slow_work *work) | |||
2332 | LOCKING_ANDX_OPLOCK_RELEASE, false); | 2344 | LOCKING_ANDX_OPLOCK_RELEASE, false); |
2333 | cFYI(1, "Oplock release rc = %d", rc); | 2345 | cFYI(1, "Oplock release rc = %d", rc); |
2334 | } | 2346 | } |
2347 | |||
2348 | /* | ||
2349 | * We might have kicked in before is_valid_oplock_break() | ||
2350 | * finished grabbing reference for us. Make sure it's done by | ||
2351 | * waiting for GlobalSMSSeslock. | ||
2352 | */ | ||
2353 | write_lock(&GlobalSMBSeslock); | ||
2354 | write_unlock(&GlobalSMBSeslock); | ||
2355 | |||
2356 | cifs_oplock_break_put(cfile); | ||
2335 | } | 2357 | } |
2336 | 2358 | ||
2337 | static int | 2359 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
2338 | cifs_oplock_break_get(struct slow_work *work) | ||
2339 | { | 2360 | { |
2340 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2341 | oplock_break); | ||
2342 | mntget(cfile->mnt); | 2361 | mntget(cfile->mnt); |
2343 | cifsFileInfo_get(cfile); | 2362 | cifsFileInfo_get(cfile); |
2344 | return 0; | ||
2345 | } | 2363 | } |
2346 | 2364 | ||
2347 | static void | 2365 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) |
2348 | cifs_oplock_break_put(struct slow_work *work) | ||
2349 | { | 2366 | { |
2350 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
2351 | oplock_break); | ||
2352 | mntput(cfile->mnt); | 2367 | mntput(cfile->mnt); |
2353 | cifsFileInfo_put(cfile); | 2368 | cifsFileInfo_put(cfile); |
2354 | } | 2369 | } |
2355 | 2370 | ||
2356 | const struct slow_work_ops cifs_oplock_break_ops = { | ||
2357 | .get_ref = cifs_oplock_break_get, | ||
2358 | .put_ref = cifs_oplock_break_put, | ||
2359 | .execute = cifs_oplock_break, | ||
2360 | }; | ||
2361 | |||
2362 | const struct address_space_operations cifs_addr_ops = { | 2371 | const struct address_space_operations cifs_addr_ops = { |
2363 | .readpage = cifs_readpage, | 2372 | .readpage = cifs_readpage, |
2364 | .readpages = cifs_readpages, | 2373 | .readpages = cifs_readpages, |
@@ -2367,6 +2376,8 @@ const struct address_space_operations cifs_addr_ops = { | |||
2367 | .write_begin = cifs_write_begin, | 2376 | .write_begin = cifs_write_begin, |
2368 | .write_end = cifs_write_end, | 2377 | .write_end = cifs_write_end, |
2369 | .set_page_dirty = __set_page_dirty_nobuffers, | 2378 | .set_page_dirty = __set_page_dirty_nobuffers, |
2379 | .releasepage = cifs_release_page, | ||
2380 | .invalidatepage = cifs_invalidate_page, | ||
2370 | /* .sync_page = cifs_sync_page, */ | 2381 | /* .sync_page = cifs_sync_page, */ |
2371 | /* .direct_IO = */ | 2382 | /* .direct_IO = */ |
2372 | }; | 2383 | }; |
@@ -2383,6 +2394,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
2383 | .write_begin = cifs_write_begin, | 2394 | .write_begin = cifs_write_begin, |
2384 | .write_end = cifs_write_end, | 2395 | .write_end = cifs_write_end, |
2385 | .set_page_dirty = __set_page_dirty_nobuffers, | 2396 | .set_page_dirty = __set_page_dirty_nobuffers, |
2397 | .releasepage = cifs_release_page, | ||
2398 | .invalidatepage = cifs_invalidate_page, | ||
2386 | /* .sync_page = cifs_sync_page, */ | 2399 | /* .sync_page = cifs_sync_page, */ |
2387 | /* .direct_IO = */ | 2400 | /* .direct_IO = */ |
2388 | }; | 2401 | }; |
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c new file mode 100644 index 000000000000..9f3f5c4be161 --- /dev/null +++ b/fs/cifs/fscache.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * fs/cifs/fscache.c - CIFS filesystem cache interface | ||
3 | * | ||
4 | * Copyright (c) 2010 Novell, Inc. | ||
5 | * Author(s): Suresh Jayaraman (sjayaraman@suse.de> | ||
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 | #include "fscache.h" | ||
22 | #include "cifsglob.h" | ||
23 | #include "cifs_debug.h" | ||
24 | #include "cifs_fs_sb.h" | ||
25 | |||
26 | void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) | ||
27 | { | ||
28 | server->fscache = | ||
29 | fscache_acquire_cookie(cifs_fscache_netfs.primary_index, | ||
30 | &cifs_fscache_server_index_def, server); | ||
31 | cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server, | ||
32 | server->fscache); | ||
33 | } | ||
34 | |||
35 | void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) | ||
36 | { | ||
37 | cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server, | ||
38 | server->fscache); | ||
39 | fscache_relinquish_cookie(server->fscache, 0); | ||
40 | server->fscache = NULL; | ||
41 | } | ||
42 | |||
43 | void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) | ||
44 | { | ||
45 | struct TCP_Server_Info *server = tcon->ses->server; | ||
46 | |||
47 | tcon->fscache = | ||
48 | fscache_acquire_cookie(server->fscache, | ||
49 | &cifs_fscache_super_index_def, tcon); | ||
50 | cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)", | ||
51 | server->fscache, tcon->fscache); | ||
52 | } | ||
53 | |||
54 | void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) | ||
55 | { | ||
56 | cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache); | ||
57 | fscache_relinquish_cookie(tcon->fscache, 0); | ||
58 | tcon->fscache = NULL; | ||
59 | } | ||
60 | |||
61 | static void cifs_fscache_enable_inode_cookie(struct inode *inode) | ||
62 | { | ||
63 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
64 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
65 | |||
66 | if (cifsi->fscache) | ||
67 | return; | ||
68 | |||
69 | cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, | ||
70 | &cifs_fscache_inode_object_def, | ||
71 | cifsi); | ||
72 | cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", | ||
73 | cifs_sb->tcon->fscache, cifsi->fscache); | ||
74 | } | ||
75 | |||
76 | void cifs_fscache_release_inode_cookie(struct inode *inode) | ||
77 | { | ||
78 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
79 | |||
80 | if (cifsi->fscache) { | ||
81 | cFYI(1, "CIFS releasing inode cookie (0x%p)", | ||
82 | cifsi->fscache); | ||
83 | fscache_relinquish_cookie(cifsi->fscache, 0); | ||
84 | cifsi->fscache = NULL; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void cifs_fscache_disable_inode_cookie(struct inode *inode) | ||
89 | { | ||
90 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
91 | |||
92 | if (cifsi->fscache) { | ||
93 | cFYI(1, "CIFS disabling inode cookie (0x%p)", | ||
94 | cifsi->fscache); | ||
95 | fscache_relinquish_cookie(cifsi->fscache, 1); | ||
96 | cifsi->fscache = NULL; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | ||
101 | { | ||
102 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | ||
103 | cifs_fscache_disable_inode_cookie(inode); | ||
104 | else { | ||
105 | cifs_fscache_enable_inode_cookie(inode); | ||
106 | cFYI(1, "CIFS: fscache inode cookie set"); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | void cifs_fscache_reset_inode_cookie(struct inode *inode) | ||
111 | { | ||
112 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
113 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
114 | struct fscache_cookie *old = cifsi->fscache; | ||
115 | |||
116 | if (cifsi->fscache) { | ||
117 | /* retire the current fscache cache and get a new one */ | ||
118 | fscache_relinquish_cookie(cifsi->fscache, 1); | ||
119 | |||
120 | cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, | ||
121 | &cifs_fscache_inode_object_def, | ||
122 | cifsi); | ||
123 | cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p", | ||
124 | cifsi->fscache, old); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | int cifs_fscache_release_page(struct page *page, gfp_t gfp) | ||
129 | { | ||
130 | if (PageFsCache(page)) { | ||
131 | struct inode *inode = page->mapping->host; | ||
132 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
133 | |||
134 | cFYI(1, "CIFS: fscache release page (0x%p/0x%p)", | ||
135 | page, cifsi->fscache); | ||
136 | if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx, | ||
144 | int error) | ||
145 | { | ||
146 | cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)", | ||
147 | page, error); | ||
148 | if (!error) | ||
149 | SetPageUptodate(page); | ||
150 | unlock_page(page); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Retrieve a page from FS-Cache | ||
155 | */ | ||
156 | int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) | ||
157 | { | ||
158 | int ret; | ||
159 | |||
160 | cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p", | ||
161 | CIFS_I(inode)->fscache, page, inode); | ||
162 | ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page, | ||
163 | cifs_readpage_from_fscache_complete, | ||
164 | NULL, | ||
165 | GFP_KERNEL); | ||
166 | switch (ret) { | ||
167 | |||
168 | case 0: /* page found in fscache, read submitted */ | ||
169 | cFYI(1, "CIFS: readpage_from_fscache: submitted"); | ||
170 | return ret; | ||
171 | case -ENOBUFS: /* page won't be cached */ | ||
172 | case -ENODATA: /* page not in cache */ | ||
173 | cFYI(1, "CIFS: readpage_from_fscache %d", ret); | ||
174 | return 1; | ||
175 | |||
176 | default: | ||
177 | cERROR(1, "unknown error ret = %d", ret); | ||
178 | } | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Retrieve a set of pages from FS-Cache | ||
184 | */ | ||
185 | int __cifs_readpages_from_fscache(struct inode *inode, | ||
186 | struct address_space *mapping, | ||
187 | struct list_head *pages, | ||
188 | unsigned *nr_pages) | ||
189 | { | ||
190 | int ret; | ||
191 | |||
192 | cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)", | ||
193 | CIFS_I(inode)->fscache, *nr_pages, inode); | ||
194 | ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping, | ||
195 | pages, nr_pages, | ||
196 | cifs_readpage_from_fscache_complete, | ||
197 | NULL, | ||
198 | mapping_gfp_mask(mapping)); | ||
199 | switch (ret) { | ||
200 | case 0: /* read submitted to the cache for all pages */ | ||
201 | cFYI(1, "CIFS: readpages_from_fscache: submitted"); | ||
202 | return ret; | ||
203 | |||
204 | case -ENOBUFS: /* some pages are not cached and can't be */ | ||
205 | case -ENODATA: /* some pages are not cached */ | ||
206 | cFYI(1, "CIFS: readpages_from_fscache: no page"); | ||
207 | return 1; | ||
208 | |||
209 | default: | ||
210 | cFYI(1, "unknown error ret = %d", ret); | ||
211 | } | ||
212 | |||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) | ||
217 | { | ||
218 | int ret; | ||
219 | |||
220 | cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p", | ||
221 | CIFS_I(inode)->fscache, page, inode); | ||
222 | ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL); | ||
223 | if (ret != 0) | ||
224 | fscache_uncache_page(CIFS_I(inode)->fscache, page); | ||
225 | } | ||
226 | |||
227 | void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) | ||
228 | { | ||
229 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
230 | struct fscache_cookie *cookie = cifsi->fscache; | ||
231 | |||
232 | cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie); | ||
233 | fscache_wait_on_page_write(cookie, page); | ||
234 | fscache_uncache_page(cookie, page); | ||
235 | } | ||
236 | |||
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h new file mode 100644 index 000000000000..31b88ec2341e --- /dev/null +++ b/fs/cifs/fscache.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * fs/cifs/fscache.h - CIFS filesystem cache interface definitions | ||
3 | * | ||
4 | * Copyright (c) 2010 Novell, Inc. | ||
5 | * Authors(s): Suresh Jayaraman (sjayaraman@suse.de> | ||
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 | #ifndef _CIFS_FSCACHE_H | ||
22 | #define _CIFS_FSCACHE_H | ||
23 | |||
24 | #include <linux/fscache.h> | ||
25 | |||
26 | #include "cifsglob.h" | ||
27 | |||
28 | #ifdef CONFIG_CIFS_FSCACHE | ||
29 | |||
30 | extern struct fscache_netfs cifs_fscache_netfs; | ||
31 | extern const struct fscache_cookie_def cifs_fscache_server_index_def; | ||
32 | extern const struct fscache_cookie_def cifs_fscache_super_index_def; | ||
33 | extern const struct fscache_cookie_def cifs_fscache_inode_object_def; | ||
34 | |||
35 | extern int cifs_fscache_register(void); | ||
36 | extern void cifs_fscache_unregister(void); | ||
37 | |||
38 | /* | ||
39 | * fscache.c | ||
40 | */ | ||
41 | extern void cifs_fscache_get_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 *); | ||
44 | extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *); | ||
45 | |||
46 | extern void cifs_fscache_release_inode_cookie(struct inode *); | ||
47 | extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *); | ||
48 | extern void cifs_fscache_reset_inode_cookie(struct inode *); | ||
49 | |||
50 | extern void __cifs_fscache_invalidate_page(struct page *, struct inode *); | ||
51 | extern int cifs_fscache_release_page(struct page *page, gfp_t gfp); | ||
52 | extern int __cifs_readpage_from_fscache(struct inode *, struct page *); | ||
53 | extern int __cifs_readpages_from_fscache(struct inode *, | ||
54 | struct address_space *, | ||
55 | struct list_head *, | ||
56 | unsigned *); | ||
57 | |||
58 | extern void __cifs_readpage_to_fscache(struct inode *, struct page *); | ||
59 | |||
60 | static inline void cifs_fscache_invalidate_page(struct page *page, | ||
61 | struct inode *inode) | ||
62 | { | ||
63 | if (PageFsCache(page)) | ||
64 | __cifs_fscache_invalidate_page(page, inode); | ||
65 | } | ||
66 | |||
67 | static inline int cifs_readpage_from_fscache(struct inode *inode, | ||
68 | struct page *page) | ||
69 | { | ||
70 | if (CIFS_I(inode)->fscache) | ||
71 | return __cifs_readpage_from_fscache(inode, page); | ||
72 | |||
73 | return -ENOBUFS; | ||
74 | } | ||
75 | |||
76 | static inline int cifs_readpages_from_fscache(struct inode *inode, | ||
77 | struct address_space *mapping, | ||
78 | struct list_head *pages, | ||
79 | unsigned *nr_pages) | ||
80 | { | ||
81 | if (CIFS_I(inode)->fscache) | ||
82 | return __cifs_readpages_from_fscache(inode, mapping, pages, | ||
83 | nr_pages); | ||
84 | return -ENOBUFS; | ||
85 | } | ||
86 | |||
87 | static inline void cifs_readpage_to_fscache(struct inode *inode, | ||
88 | struct page *page) | ||
89 | { | ||
90 | if (PageFsCache(page)) | ||
91 | __cifs_readpage_to_fscache(inode, page); | ||
92 | } | ||
93 | |||
94 | #else /* CONFIG_CIFS_FSCACHE */ | ||
95 | static inline int cifs_fscache_register(void) { return 0; } | ||
96 | static inline void cifs_fscache_unregister(void) {} | ||
97 | |||
98 | static inline void | ||
99 | cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {} | ||
100 | static inline void | ||
101 | cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {} | ||
102 | static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {} | ||
103 | static inline void | ||
104 | cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {} | ||
105 | |||
106 | static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} | ||
107 | static inline void cifs_fscache_set_inode_cookie(struct inode *inode, | ||
108 | struct file *filp) {} | ||
109 | static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {} | ||
110 | static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp) | ||
111 | { | ||
112 | return 1; /* May release page */ | ||
113 | } | ||
114 | |||
115 | static inline void cifs_fscache_invalidate_page(struct page *page, | ||
116 | struct inode *inode) {} | ||
117 | static inline int | ||
118 | cifs_readpage_from_fscache(struct inode *inode, struct page *page) | ||
119 | { | ||
120 | return -ENOBUFS; | ||
121 | } | ||
122 | |||
123 | static inline int cifs_readpages_from_fscache(struct inode *inode, | ||
124 | struct address_space *mapping, | ||
125 | struct list_head *pages, | ||
126 | unsigned *nr_pages) | ||
127 | { | ||
128 | return -ENOBUFS; | ||
129 | } | ||
130 | |||
131 | static inline void cifs_readpage_to_fscache(struct inode *inode, | ||
132 | struct page *page) {} | ||
133 | |||
134 | #endif /* CONFIG_CIFS_FSCACHE */ | ||
135 | |||
136 | #endif /* _CIFS_FSCACHE_H */ | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 62b324f26a56..4bc47e5b5f29 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "cifsproto.h" | 29 | #include "cifsproto.h" |
30 | #include "cifs_debug.h" | 30 | #include "cifs_debug.h" |
31 | #include "cifs_fs_sb.h" | 31 | #include "cifs_fs_sb.h" |
32 | #include "fscache.h" | ||
32 | 33 | ||
33 | 34 | ||
34 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | 35 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) |
@@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp) | |||
288 | struct inode *inode = filp->f_path.dentry->d_inode; | 289 | struct inode *inode = filp->f_path.dentry->d_inode; |
289 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
290 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 291 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
291 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | 292 | struct cifsFileInfo *cfile = filp->private_data; |
292 | 293 | ||
293 | xid = GetXid(); | 294 | xid = GetXid(); |
294 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); | 295 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); |
@@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp) | |||
515 | struct inode *inode = filp->f_path.dentry->d_inode; | 516 | struct inode *inode = filp->f_path.dentry->d_inode; |
516 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 517 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
517 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 518 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
518 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | 519 | struct cifsFileInfo *cfile = filp->private_data; |
519 | 520 | ||
520 | xid = GetXid(); | 521 | xid = GetXid(); |
521 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); | 522 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); |
@@ -723,18 +724,17 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
723 | { | 724 | { |
724 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 725 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; |
725 | 726 | ||
727 | /* don't match inode with different uniqueid */ | ||
726 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 728 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
727 | return 0; | 729 | return 0; |
728 | 730 | ||
729 | /* | 731 | /* don't match inode of different type */ |
730 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | 732 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) |
731 | * verboten. Disable serverino and return it as if it were found, the | 733 | return 0; |
732 | * caller can discard it, generate a uniqueid and retry the find | 734 | |
733 | */ | 735 | /* if it's not a directory or has no dentries, then flag it */ |
734 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) { | 736 | if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) |
735 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; | 737 | fattr->cf_flags |= CIFS_FATTR_INO_COLLISION; |
736 | cifs_autodisable_serverino(CIFS_SB(inode->i_sb)); | ||
737 | } | ||
738 | 738 | ||
739 | return 1; | 739 | return 1; |
740 | } | 740 | } |
@@ -748,6 +748,27 @@ cifs_init_inode(struct inode *inode, void *opaque) | |||
748 | return 0; | 748 | return 0; |
749 | } | 749 | } |
750 | 750 | ||
751 | /* | ||
752 | * walk dentry list for an inode and report whether it has aliases that | ||
753 | * are hashed. We use this to determine if a directory inode can actually | ||
754 | * be used. | ||
755 | */ | ||
756 | static bool | ||
757 | inode_has_hashed_dentries(struct inode *inode) | ||
758 | { | ||
759 | struct dentry *dentry; | ||
760 | |||
761 | spin_lock(&dcache_lock); | ||
762 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | ||
763 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { | ||
764 | spin_unlock(&dcache_lock); | ||
765 | return true; | ||
766 | } | ||
767 | } | ||
768 | spin_unlock(&dcache_lock); | ||
769 | return false; | ||
770 | } | ||
771 | |||
751 | /* Given fattrs, get a corresponding inode */ | 772 | /* Given fattrs, get a corresponding inode */ |
752 | struct inode * | 773 | struct inode * |
753 | cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) | 774 | cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) |
@@ -763,12 +784,16 @@ retry_iget5_locked: | |||
763 | 784 | ||
764 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); | 785 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); |
765 | if (inode) { | 786 | if (inode) { |
766 | /* was there a problematic inode number collision? */ | 787 | /* was there a potentially problematic inode collision? */ |
767 | if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { | 788 | if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) { |
768 | iput(inode); | ||
769 | fattr->cf_uniqueid = iunique(sb, ROOT_I); | ||
770 | fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; | 789 | fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION; |
771 | goto retry_iget5_locked; | 790 | |
791 | if (inode_has_hashed_dentries(inode)) { | ||
792 | cifs_autodisable_serverino(CIFS_SB(sb)); | ||
793 | iput(inode); | ||
794 | fattr->cf_uniqueid = iunique(sb, ROOT_I); | ||
795 | goto retry_iget5_locked; | ||
796 | } | ||
772 | } | 797 | } |
773 | 798 | ||
774 | cifs_fattr_to_inode(inode, fattr); | 799 | cifs_fattr_to_inode(inode, fattr); |
@@ -776,6 +801,10 @@ retry_iget5_locked: | |||
776 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 801 | inode->i_flags |= S_NOATIME | S_NOCMTIME; |
777 | if (inode->i_state & I_NEW) { | 802 | if (inode->i_state & I_NEW) { |
778 | inode->i_ino = hash; | 803 | inode->i_ino = hash; |
804 | #ifdef CONFIG_CIFS_FSCACHE | ||
805 | /* initialize per-inode cache cookie pointer */ | ||
806 | CIFS_I(inode)->fscache = NULL; | ||
807 | #endif | ||
779 | unlock_new_inode(inode); | 808 | unlock_new_inode(inode); |
780 | } | 809 | } |
781 | } | 810 | } |
@@ -807,6 +836,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
807 | if (!inode) | 836 | if (!inode) |
808 | return ERR_PTR(-ENOMEM); | 837 | return ERR_PTR(-ENOMEM); |
809 | 838 | ||
839 | #ifdef CONFIG_CIFS_FSCACHE | ||
840 | /* populate tcon->resource_id */ | ||
841 | cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; | ||
842 | #endif | ||
843 | |||
810 | if (rc && cifs_sb->tcon->ipc) { | 844 | if (rc && cifs_sb->tcon->ipc) { |
811 | cFYI(1, "ipc connection - fake read inode"); | 845 | cFYI(1, "ipc connection - fake read inode"); |
812 | inode->i_mode |= S_IFDIR; | 846 | inode->i_mode |= S_IFDIR; |
@@ -1401,6 +1435,10 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, | |||
1401 | if (rc == 0 || rc != -ETXTBSY) | 1435 | if (rc == 0 || rc != -ETXTBSY) |
1402 | return rc; | 1436 | return rc; |
1403 | 1437 | ||
1438 | /* open-file renames don't work across directories */ | ||
1439 | if (to_dentry->d_parent != from_dentry->d_parent) | ||
1440 | return rc; | ||
1441 | |||
1404 | /* open the file to be renamed -- we need DELETE perms */ | 1442 | /* open the file to be renamed -- we need DELETE perms */ |
1405 | rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, | 1443 | rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE, |
1406 | CREATE_NOT_DIR, &srcfid, &oplock, NULL, | 1444 | CREATE_NOT_DIR, &srcfid, &oplock, NULL, |
@@ -1564,6 +1602,7 @@ cifs_invalidate_mapping(struct inode *inode) | |||
1564 | cifs_i->write_behind_rc = rc; | 1602 | cifs_i->write_behind_rc = rc; |
1565 | } | 1603 | } |
1566 | invalidate_remote_inode(inode); | 1604 | invalidate_remote_inode(inode); |
1605 | cifs_fscache_reset_inode_cookie(inode); | ||
1567 | } | 1606 | } |
1568 | 1607 | ||
1569 | int cifs_revalidate_file(struct file *filp) | 1608 | int cifs_revalidate_file(struct file *filp) |
@@ -1659,26 +1698,16 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) | |||
1659 | return rc; | 1698 | return rc; |
1660 | } | 1699 | } |
1661 | 1700 | ||
1662 | static int cifs_vmtruncate(struct inode *inode, loff_t offset) | 1701 | static void cifs_setsize(struct inode *inode, loff_t offset) |
1663 | { | 1702 | { |
1664 | loff_t oldsize; | 1703 | loff_t oldsize; |
1665 | int err; | ||
1666 | 1704 | ||
1667 | spin_lock(&inode->i_lock); | 1705 | spin_lock(&inode->i_lock); |
1668 | err = inode_newsize_ok(inode, offset); | ||
1669 | if (err) { | ||
1670 | spin_unlock(&inode->i_lock); | ||
1671 | goto out; | ||
1672 | } | ||
1673 | |||
1674 | oldsize = inode->i_size; | 1706 | oldsize = inode->i_size; |
1675 | i_size_write(inode, offset); | 1707 | i_size_write(inode, offset); |
1676 | spin_unlock(&inode->i_lock); | 1708 | spin_unlock(&inode->i_lock); |
1709 | |||
1677 | truncate_pagecache(inode, oldsize, offset); | 1710 | truncate_pagecache(inode, oldsize, offset); |
1678 | if (inode->i_op->truncate) | ||
1679 | inode->i_op->truncate(inode); | ||
1680 | out: | ||
1681 | return err; | ||
1682 | } | 1711 | } |
1683 | 1712 | ||
1684 | static int | 1713 | static int |
@@ -1751,7 +1780,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
1751 | 1780 | ||
1752 | if (rc == 0) { | 1781 | if (rc == 0) { |
1753 | cifsInode->server_eof = attrs->ia_size; | 1782 | cifsInode->server_eof = attrs->ia_size; |
1754 | rc = cifs_vmtruncate(inode, attrs->ia_size); | 1783 | cifs_setsize(inode, attrs->ia_size); |
1755 | cifs_truncate_page(inode->i_mapping, inode->i_size); | 1784 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
1756 | } | 1785 | } |
1757 | 1786 | ||
@@ -1776,14 +1805,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1776 | 1805 | ||
1777 | xid = GetXid(); | 1806 | xid = GetXid(); |
1778 | 1807 | ||
1779 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1808 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
1780 | /* check if we have permission to change attrs */ | 1809 | attrs->ia_valid |= ATTR_FORCE; |
1781 | rc = inode_change_ok(inode, attrs); | 1810 | |
1782 | if (rc < 0) | 1811 | rc = inode_change_ok(inode, attrs); |
1783 | goto out; | 1812 | if (rc < 0) |
1784 | else | 1813 | goto out; |
1785 | rc = 0; | ||
1786 | } | ||
1787 | 1814 | ||
1788 | full_path = build_path_from_dentry(direntry); | 1815 | full_path = build_path_from_dentry(direntry); |
1789 | if (full_path == NULL) { | 1816 | if (full_path == NULL) { |
@@ -1869,18 +1896,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1869 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1896 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1870 | } | 1897 | } |
1871 | 1898 | ||
1872 | if (!rc) { | 1899 | if (rc) |
1873 | rc = inode_setattr(inode, attrs); | 1900 | goto out; |
1874 | 1901 | ||
1875 | /* force revalidate when any of these times are set since some | 1902 | if ((attrs->ia_valid & ATTR_SIZE) && |
1876 | of the fs types (eg ext3, fat) do not have fine enough | 1903 | attrs->ia_size != i_size_read(inode)) |
1877 | time granularity to match protocol, and we do not have a | 1904 | truncate_setsize(inode, attrs->ia_size); |
1878 | a way (yet) to query the server fs's time granularity (and | 1905 | |
1879 | whether it rounds times down). | 1906 | setattr_copy(inode, attrs); |
1880 | */ | 1907 | mark_inode_dirty(inode); |
1881 | if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) | 1908 | |
1882 | cifsInode->time = 0; | 1909 | /* force revalidate when any of these times are set since some |
1883 | } | 1910 | of the fs types (eg ext3, fat) do not have fine enough |
1911 | time granularity to match protocol, and we do not have a | ||
1912 | a way (yet) to query the server fs's time granularity (and | ||
1913 | whether it rounds times down). | ||
1914 | */ | ||
1915 | if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) | ||
1916 | cifsInode->time = 0; | ||
1884 | out: | 1917 | out: |
1885 | kfree(args); | 1918 | kfree(args); |
1886 | kfree(full_path); | 1919 | kfree(full_path); |
@@ -1905,14 +1938,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1905 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", | 1938 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", |
1906 | direntry->d_name.name, attrs->ia_valid); | 1939 | direntry->d_name.name, attrs->ia_valid); |
1907 | 1940 | ||
1908 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1941 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
1909 | /* check if we have permission to change attrs */ | 1942 | attrs->ia_valid |= ATTR_FORCE; |
1910 | rc = inode_change_ok(inode, attrs); | 1943 | |
1911 | if (rc < 0) { | 1944 | rc = inode_change_ok(inode, attrs); |
1912 | FreeXid(xid); | 1945 | if (rc < 0) { |
1913 | return rc; | 1946 | FreeXid(xid); |
1914 | } else | 1947 | return rc; |
1915 | rc = 0; | ||
1916 | } | 1948 | } |
1917 | 1949 | ||
1918 | full_path = build_path_from_dentry(direntry); | 1950 | full_path = build_path_from_dentry(direntry); |
@@ -2020,8 +2052,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
2020 | 2052 | ||
2021 | /* do not need local check to inode_check_ok since the server does | 2053 | /* do not need local check to inode_check_ok since the server does |
2022 | that */ | 2054 | that */ |
2023 | if (!rc) | 2055 | if (rc) |
2024 | rc = inode_setattr(inode, attrs); | 2056 | goto cifs_setattr_exit; |
2057 | |||
2058 | if ((attrs->ia_valid & ATTR_SIZE) && | ||
2059 | attrs->ia_size != i_size_read(inode)) | ||
2060 | truncate_setsize(inode, attrs->ia_size); | ||
2061 | |||
2062 | setattr_copy(inode, attrs); | ||
2063 | mark_inode_dirty(inode); | ||
2064 | return 0; | ||
2065 | |||
2025 | cifs_setattr_exit: | 2066 | cifs_setattr_exit: |
2026 | kfree(full_path); | 2067 | kfree(full_path); |
2027 | FreeXid(xid); | 2068 | FreeXid(xid); |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 505926f1ee6b..9d38a71c8e14 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
@@ -41,8 +41,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
41 | __u64 ExtAttrMask = 0; | 41 | __u64 ExtAttrMask = 0; |
42 | __u64 caps; | 42 | __u64 caps; |
43 | struct cifsTconInfo *tcon; | 43 | struct cifsTconInfo *tcon; |
44 | struct cifsFileInfo *pSMBFile = | 44 | struct cifsFileInfo *pSMBFile = filep->private_data; |
45 | (struct cifsFileInfo *)filep->private_data; | ||
46 | #endif /* CONFIG_CIFS_POSIX */ | 45 | #endif /* CONFIG_CIFS_POSIX */ |
47 | 46 | ||
48 | xid = GetXid(); | 47 | xid = GetXid(); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1394aa37f26c..3ccadc1326d6 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -498,7 +498,6 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
498 | struct cifsTconInfo *tcon; | 498 | struct cifsTconInfo *tcon; |
499 | struct cifsInodeInfo *pCifsInode; | 499 | struct cifsInodeInfo *pCifsInode; |
500 | struct cifsFileInfo *netfile; | 500 | struct cifsFileInfo *netfile; |
501 | int rc; | ||
502 | 501 | ||
503 | cFYI(1, "Checking for oplock break or dnotify response"); | 502 | cFYI(1, "Checking for oplock break or dnotify response"); |
504 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && | 503 | if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && |
@@ -583,13 +582,18 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
583 | pCifsInode->clientCanCacheAll = false; | 582 | pCifsInode->clientCanCacheAll = false; |
584 | if (pSMB->OplockLevel == 0) | 583 | if (pSMB->OplockLevel == 0) |
585 | pCifsInode->clientCanCacheRead = false; | 584 | pCifsInode->clientCanCacheRead = false; |
586 | rc = slow_work_enqueue(&netfile->oplock_break); | 585 | |
587 | if (rc) { | 586 | /* |
588 | cERROR(1, "failed to enqueue oplock " | 587 | * cifs_oplock_break_put() can't be called |
589 | "break: %d\n", rc); | 588 | * from here. Get reference after queueing |
590 | } else { | 589 | * succeeded. cifs_oplock_break() will |
591 | netfile->oplock_break_cancelled = false; | 590 | * synchronize using GlobalSMSSeslock. |
592 | } | 591 | */ |
592 | if (queue_work(system_nrt_wq, | ||
593 | &netfile->oplock_break)) | ||
594 | cifs_oplock_break_get(netfile); | ||
595 | netfile->oplock_break_cancelled = false; | ||
596 | |||
593 | read_unlock(&GlobalSMBSeslock); | 597 | read_unlock(&GlobalSMBSeslock); |
594 | read_unlock(&cifs_tcp_ses_lock); | 598 | read_unlock(&cifs_tcp_ses_lock); |
595 | return true; | 599 | return true; |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index d35d52889cb5..f97851119e6c 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | |||
61 | {ERRremcd, -EACCES}, | 61 | {ERRremcd, -EACCES}, |
62 | {ERRdiffdevice, -EXDEV}, | 62 | {ERRdiffdevice, -EXDEV}, |
63 | {ERRnofiles, -ENOENT}, | 63 | {ERRnofiles, -ENOENT}, |
64 | {ERRwriteprot, -EROFS}, | ||
64 | {ERRbadshare, -ETXTBSY}, | 65 | {ERRbadshare, -ETXTBSY}, |
65 | {ERRlock, -EACCES}, | 66 | {ERRlock, -EACCES}, |
66 | {ERRunsup, -EINVAL}, | 67 | {ERRunsup, -EINVAL}, |
@@ -139,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | |||
139 | * Returns 0 on failure. | 140 | * Returns 0 on failure. |
140 | */ | 141 | */ |
141 | static int | 142 | static int |
142 | cifs_inet_pton(const int address_family, const char *cp, void *dst) | 143 | cifs_inet_pton(const int address_family, const char *cp, int len, void *dst) |
143 | { | 144 | { |
144 | int ret = 0; | 145 | int ret = 0; |
145 | 146 | ||
146 | /* calculate length by finding first slash or NULL */ | 147 | /* calculate length by finding first slash or NULL */ |
147 | if (address_family == AF_INET) | 148 | if (address_family == AF_INET) |
148 | ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); | 149 | ret = in4_pton(cp, len, dst, '\\', NULL); |
149 | else if (address_family == AF_INET6) | 150 | else if (address_family == AF_INET6) |
150 | ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); | 151 | ret = in6_pton(cp, len, dst , '\\', NULL); |
151 | 152 | ||
152 | cFYI(DBG2, "address conversion returned %d for %s", ret, cp); | 153 | cFYI(DBG2, "address conversion returned %d for %*.*s", |
154 | ret, len, len, cp); | ||
153 | if (ret > 0) | 155 | if (ret > 0) |
154 | ret = 1; | 156 | ret = 1; |
155 | return ret; | 157 | return ret; |
@@ -164,43 +166,66 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) | |||
164 | * Returns 0 on failure. | 166 | * Returns 0 on failure. |
165 | */ | 167 | */ |
166 | int | 168 | int |
167 | cifs_convert_address(char *src, void *dst) | 169 | cifs_convert_address(struct sockaddr *dst, const char *src, int len) |
168 | { | 170 | { |
169 | int rc; | 171 | int rc, alen, slen; |
170 | char *pct, *endp; | 172 | const char *pct; |
173 | char *endp, scope_id[13]; | ||
171 | struct sockaddr_in *s4 = (struct sockaddr_in *) dst; | 174 | struct sockaddr_in *s4 = (struct sockaddr_in *) dst; |
172 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; | 175 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; |
173 | 176 | ||
174 | /* IPv4 address */ | 177 | /* IPv4 address */ |
175 | if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) { | 178 | if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) { |
176 | s4->sin_family = AF_INET; | 179 | s4->sin_family = AF_INET; |
177 | return 1; | 180 | return 1; |
178 | } | 181 | } |
179 | 182 | ||
180 | /* temporarily terminate string */ | 183 | /* attempt to exclude the scope ID from the address part */ |
181 | pct = strchr(src, '%'); | 184 | pct = memchr(src, '%', len); |
182 | if (pct) | 185 | alen = pct ? pct - src : len; |
183 | *pct = '\0'; | ||
184 | |||
185 | rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr); | ||
186 | |||
187 | /* repair temp termination (if any) and make pct point to scopeid */ | ||
188 | if (pct) | ||
189 | *pct++ = '%'; | ||
190 | 186 | ||
187 | rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr); | ||
191 | if (!rc) | 188 | if (!rc) |
192 | return rc; | 189 | return rc; |
193 | 190 | ||
194 | s6->sin6_family = AF_INET6; | 191 | s6->sin6_family = AF_INET6; |
195 | if (pct) { | 192 | if (pct) { |
193 | /* grab the scope ID */ | ||
194 | slen = len - (alen + 1); | ||
195 | if (slen <= 0 || slen > 12) | ||
196 | return 0; | ||
197 | memcpy(scope_id, pct + 1, slen); | ||
198 | scope_id[slen] = '\0'; | ||
199 | |||
196 | s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); | 200 | s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); |
197 | if (!*pct || *endp) | 201 | if (endp != scope_id + slen) |
198 | return 0; | 202 | return 0; |
199 | } | 203 | } |
200 | 204 | ||
201 | return rc; | 205 | return rc; |
202 | } | 206 | } |
203 | 207 | ||
208 | int | ||
209 | cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | ||
210 | const unsigned short int port) | ||
211 | { | ||
212 | if (!cifs_convert_address(dst, src, len)) | ||
213 | return 0; | ||
214 | |||
215 | switch (dst->sa_family) { | ||
216 | case AF_INET: | ||
217 | ((struct sockaddr_in *)dst)->sin_port = htons(port); | ||
218 | break; | ||
219 | case AF_INET6: | ||
220 | ((struct sockaddr_in6 *)dst)->sin6_port = htons(port); | ||
221 | break; | ||
222 | default: | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | return 1; | ||
227 | } | ||
228 | |||
204 | /***************************************************************************** | 229 | /***************************************************************************** |
205 | convert a NT status code to a dos class/code | 230 | convert a NT status code to a dos class/code |
206 | *****************************************************************************/ | 231 | *****************************************************************************/ |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index daf1753af674..d5e591fab475 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -847,6 +847,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
847 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 847 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; |
848 | 848 | ||
849 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); | 849 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); |
850 | if (tmp_buf == NULL) { | ||
851 | rc = -ENOMEM; | ||
852 | break; | ||
853 | } | ||
854 | |||
850 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 855 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { |
851 | if (current_entry == NULL) { | 856 | if (current_entry == NULL) { |
852 | /* evaluate whether this case is an error */ | 857 | /* evaluate whether this case is an error */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7707389bdf2c..0a57cb7db5dd 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -730,15 +730,7 @@ ssetup_ntlmssp_authenticate: | |||
730 | 730 | ||
731 | /* calculate session key */ | 731 | /* calculate session key */ |
732 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); | 732 | setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); |
733 | if (first_time) /* should this be moved into common code | 733 | /* FIXME: calculate MAC key */ |
734 | with similar ntlmv2 path? */ | ||
735 | /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, | ||
736 | response BB FIXME, v2_sess_key); */ | ||
737 | |||
738 | /* copy session key */ | ||
739 | |||
740 | /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); | ||
741 | bcc_ptr += LM2_SESS_KEY_SIZE; */ | ||
742 | memcpy(bcc_ptr, (char *)v2_sess_key, | 734 | memcpy(bcc_ptr, (char *)v2_sess_key, |
743 | sizeof(struct ntlmv2_resp)); | 735 | sizeof(struct ntlmv2_resp)); |
744 | bcc_ptr += sizeof(struct ntlmv2_resp); | 736 | bcc_ptr += sizeof(struct ntlmv2_resp); |
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index c5084d27db7c..7f16cb825fe5 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h | |||
@@ -76,6 +76,7 @@ | |||
76 | #define ERRnofiles 18 /* A File Search command can find no | 76 | #define ERRnofiles 18 /* A File Search command can find no |
77 | more files matching the specified | 77 | more files matching the specified |
78 | criteria. */ | 78 | criteria. */ |
79 | #define ERRwriteprot 19 /* media is write protected */ | ||
79 | #define ERRgeneral 31 | 80 | #define ERRgeneral 31 |
80 | #define ERRbadshare 32 /* The sharing mode specified for an | 81 | #define ERRbadshare 32 /* The sharing mode specified for an |
81 | Open conflicts with existing FIDs on | 82 | Open conflicts with existing FIDs on |