diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-03 17:33:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-03 17:33:09 -0400 |
commit | 54161df1fb1469d66bce3a3b14d8281adbb69263 (patch) | |
tree | b5f0f8741db382daf09dd236e9e678d60422dc48 | |
parent | be82ae0238b0453afcf4a76f0512b7dde34ba500 (diff) | |
parent | cb76d5e25008b76fb8e348c861d32659430ac3fa (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (29 commits)
cifs: fsc should not default to "on"
[CIFS] remove redundant path walking in dfs_do_refmount
cifs: ignore the "mand", "nomand" and "_netdev" mount options
cifs: map NT_STATUS_ERROR_WRITE_PROTECTED to -EROFS
cifs: don't allow cifs_iget to match inodes of the wrong type
[CIFS] relinquish fscache cookie before freeing CIFSTconInfo
cifs: add separate cred_uid field to sesInfo
fs: cifs: check kmalloc() result
[CIFS] Missing ifdef
[CIFS] Missing line from previous commit
[CIFS] Fix build break when CONFIG_CIFS_FSCACHE disabled
cifs: add mount option to enable local caching
cifs: read pages from FS-Cache
cifs: store pages into local cache
cifs: FS-Cache page management
cifs: define inode-level cache object and register them
cifs: define superblock-level cache index objects and register them
cifs: remove unused cifsUidInfo struct
cifs: clean up cifs_find_smb_ses (try #2)
cifs: match secType when searching for existing tcp session
...
-rw-r--r-- | fs/cifs/Kconfig | 9 | ||||
-rw-r--r-- | fs/cifs/Makefile | 2 | ||||
-rw-r--r-- | fs/cifs/cache.c | 331 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 28 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 15 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 40 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/connect.c | 180 | ||||
-rw-r--r-- | fs/cifs/dir.c | 6 | ||||
-rw-r--r-- | fs/cifs/dns_resolve.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 74 | ||||
-rw-r--r-- | fs/cifs/fscache.c | 236 | ||||
-rw-r--r-- | fs/cifs/fscache.h | 136 | ||||
-rw-r--r-- | fs/cifs/inode.c | 20 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 3 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 24 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 5 | ||||
-rw-r--r-- | fs/cifs/smberr.h | 1 |
21 files changed, 1006 insertions, 116 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 80f352596807..5739fd7f88b4 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -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/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_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ac19a6f3dae0..dc1ed50ea06e 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -230,28 +230,22 @@ compose_mount_options_err: | |||
230 | goto compose_mount_options_out; | 230 | goto compose_mount_options_out; |
231 | } | 231 | } |
232 | 232 | ||
233 | 233 | /** | |
234 | static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, | 234 | * cifs_dfs_do_refmount - mounts specified path using provided refferal |
235 | struct dentry *dentry, const struct dfs_info3_param *ref) | 235 | * @cifs_sb: parent/root superblock |
236 | * @fullpath: full path in UNC format | ||
237 | * @ref: server's referral | ||
238 | */ | ||
239 | static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, | ||
240 | const char *fullpath, const struct dfs_info3_param *ref) | ||
236 | { | 241 | { |
237 | struct cifs_sb_info *cifs_sb; | ||
238 | struct vfsmount *mnt; | 242 | struct vfsmount *mnt; |
239 | char *mountdata; | 243 | char *mountdata; |
240 | char *devname = NULL; | 244 | 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 | 245 | ||
246 | /* strip first '\' from fullpath */ | ||
252 | mountdata = cifs_compose_mount_options(cifs_sb->mountdata, | 247 | mountdata = cifs_compose_mount_options(cifs_sb->mountdata, |
253 | fullpath + 1, ref, &devname); | 248 | fullpath + 1, ref, &devname); |
254 | kfree(fullpath); | ||
255 | 249 | ||
256 | if (IS_ERR(mountdata)) | 250 | if (IS_ERR(mountdata)) |
257 | return (struct vfsmount *)mountdata; | 251 | return (struct vfsmount *)mountdata; |
@@ -357,8 +351,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
357 | rc = -EINVAL; | 351 | rc = -EINVAL; |
358 | goto out_err; | 352 | goto out_err; |
359 | } | 353 | } |
360 | mnt = cifs_dfs_do_refmount(nd->path.mnt, | 354 | mnt = cifs_dfs_do_refmount(cifs_sb, |
361 | nd->path.dentry, referrals + i); | 355 | full_path, referrals + i); |
362 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, | 356 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, |
363 | referrals[i].node_name, mnt); | 357 | referrals[i].node_name, mnt); |
364 | 358 | ||
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..6effccff85a5 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -144,6 +144,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
144 | sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); | 144 | sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); |
145 | 145 | ||
146 | dp = description + strlen(description); | 146 | dp = description + strlen(description); |
147 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); | ||
148 | |||
149 | dp = description + strlen(description); | ||
147 | sprintf(dp, ";user=%s", sesInfo->userName); | 150 | sprintf(dp, ";user=%s", sesInfo->userName); |
148 | 151 | ||
149 | dp = description + strlen(description); | 152 | dp = description + strlen(description); |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2cb1a70214d7..8a2cf129e535 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/key-type.h> | 47 | #include <linux/key-type.h> |
48 | #include "dns_resolve.h" | 48 | #include "dns_resolve.h" |
49 | #include "cifs_spnego.h" | 49 | #include "cifs_spnego.h" |
50 | #include "fscache.h" | ||
50 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ | 51 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ |
51 | 52 | ||
52 | int cifsFYI = 0; | 53 | int cifsFYI = 0; |
@@ -329,6 +330,12 @@ cifs_destroy_inode(struct inode *inode) | |||
329 | } | 330 | } |
330 | 331 | ||
331 | static void | 332 | static void |
333 | cifs_clear_inode(struct inode *inode) | ||
334 | { | ||
335 | cifs_fscache_release_inode_cookie(inode); | ||
336 | } | ||
337 | |||
338 | static void | ||
332 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 339 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) |
333 | { | 340 | { |
334 | seq_printf(s, ",addr="); | 341 | seq_printf(s, ",addr="); |
@@ -489,6 +496,7 @@ static const struct super_operations cifs_super_ops = { | |||
489 | .alloc_inode = cifs_alloc_inode, | 496 | .alloc_inode = cifs_alloc_inode, |
490 | .destroy_inode = cifs_destroy_inode, | 497 | .destroy_inode = cifs_destroy_inode, |
491 | .drop_inode = cifs_drop_inode, | 498 | .drop_inode = cifs_drop_inode, |
499 | .clear_inode = cifs_clear_inode, | ||
492 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above | 500 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above |
493 | function unless later we add lazy close of inodes or unless the | 501 | function unless later we add lazy close of inodes or unless the |
494 | 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) |
@@ -902,6 +910,10 @@ init_cifs(void) | |||
902 | cFYI(1, "cifs_max_pending set to max of 256"); | 910 | cFYI(1, "cifs_max_pending set to max of 256"); |
903 | } | 911 | } |
904 | 912 | ||
913 | rc = cifs_fscache_register(); | ||
914 | if (rc) | ||
915 | goto out; | ||
916 | |||
905 | rc = cifs_init_inodecache(); | 917 | rc = cifs_init_inodecache(); |
906 | if (rc) | 918 | if (rc) |
907 | goto out_clean_proc; | 919 | goto out_clean_proc; |
@@ -951,6 +963,8 @@ init_cifs(void) | |||
951 | cifs_destroy_inodecache(); | 963 | cifs_destroy_inodecache(); |
952 | out_clean_proc: | 964 | out_clean_proc: |
953 | cifs_proc_clean(); | 965 | cifs_proc_clean(); |
966 | cifs_fscache_unregister(); | ||
967 | out: | ||
954 | return rc; | 968 | return rc; |
955 | } | 969 | } |
956 | 970 | ||
@@ -959,6 +973,7 @@ exit_cifs(void) | |||
959 | { | 973 | { |
960 | cFYI(DBG2, "exit_cifs"); | 974 | cFYI(DBG2, "exit_cifs"); |
961 | cifs_proc_clean(); | 975 | cifs_proc_clean(); |
976 | cifs_fscache_unregister(); | ||
962 | #ifdef CONFIG_CIFS_DFS_UPCALL | 977 | #ifdef CONFIG_CIFS_DFS_UPCALL |
963 | cifs_dfs_release_automount_timer(); | 978 | cifs_dfs_release_automount_timer(); |
964 | cifs_exit_dns_resolver(); | 979 | cifs_exit_dns_resolver(); |
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..59906146ad36 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -16,6 +16,9 @@ | |||
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> |
@@ -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 | ||
@@ -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 | ||
@@ -733,3 +729,5 @@ 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 | ||
735 | extern const struct slow_work_ops cifs_oplock_break_ops; | 731 | extern const struct slow_work_ops cifs_oplock_break_ops; |
732 | |||
733 | #endif /* _CIFS_GLOB_H */ | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index fb6318b81509..2eaebbd31132 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, char *src); |
90 | extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src, | ||
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 |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2208f06e4c45..2a43a0aca965 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,9 @@ 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 | volume_info->port); | ||
1483 | if (!rc) { | 1547 | if (!rc) { |
1484 | /* we failed translating address */ | 1548 | /* we failed translating address */ |
1485 | rc = -EINVAL; | 1549 | rc = -EINVAL; |
@@ -1499,7 +1563,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1499 | } | 1563 | } |
1500 | 1564 | ||
1501 | /* see if we already have a matching tcp_ses */ | 1565 | /* see if we already have a matching tcp_ses */ |
1502 | tcp_ses = cifs_find_tcp_session(&addr, volume_info->port); | 1566 | tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info); |
1503 | if (tcp_ses) | 1567 | if (tcp_ses) |
1504 | return tcp_ses; | 1568 | return tcp_ses; |
1505 | 1569 | ||
@@ -1543,12 +1607,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1543 | cFYI(1, "attempting ipv6 connect"); | 1607 | cFYI(1, "attempting ipv6 connect"); |
1544 | /* BB should we allow ipv6 on port 139? */ | 1608 | /* BB should we allow ipv6 on port 139? */ |
1545 | /* other OS never observed in Wild doing 139 with v6 */ | 1609 | /* 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, | 1610 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, |
1548 | sizeof(struct sockaddr_in6)); | 1611 | sizeof(struct sockaddr_in6)); |
1549 | rc = ipv6_connect(tcp_ses); | 1612 | rc = ipv6_connect(tcp_ses); |
1550 | } else { | 1613 | } else { |
1551 | sin_server->sin_port = htons(volume_info->port); | ||
1552 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1614 | memcpy(&tcp_ses->addr.sockAddr, sin_server, |
1553 | sizeof(struct sockaddr_in)); | 1615 | sizeof(struct sockaddr_in)); |
1554 | rc = ipv4_connect(tcp_ses); | 1616 | rc = ipv4_connect(tcp_ses); |
@@ -1577,6 +1639,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1577 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 1639 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
1578 | write_unlock(&cifs_tcp_ses_lock); | 1640 | write_unlock(&cifs_tcp_ses_lock); |
1579 | 1641 | ||
1642 | cifs_fscache_get_client_cookie(tcp_ses); | ||
1643 | |||
1580 | return tcp_ses; | 1644 | return tcp_ses; |
1581 | 1645 | ||
1582 | out_err: | 1646 | out_err: |
@@ -1591,17 +1655,27 @@ out_err: | |||
1591 | } | 1655 | } |
1592 | 1656 | ||
1593 | static struct cifsSesInfo * | 1657 | static struct cifsSesInfo * |
1594 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) | 1658 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) |
1595 | { | 1659 | { |
1596 | struct list_head *tmp; | ||
1597 | struct cifsSesInfo *ses; | 1660 | struct cifsSesInfo *ses; |
1598 | 1661 | ||
1599 | write_lock(&cifs_tcp_ses_lock); | 1662 | write_lock(&cifs_tcp_ses_lock); |
1600 | list_for_each(tmp, &server->smb_ses_list) { | 1663 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
1601 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 1664 | switch (server->secType) { |
1602 | if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) | 1665 | case Kerberos: |
1603 | continue; | 1666 | if (vol->cred_uid != ses->cred_uid) |
1604 | 1667 | continue; | |
1668 | break; | ||
1669 | default: | ||
1670 | /* anything else takes username/password */ | ||
1671 | if (strncmp(ses->userName, vol->username, | ||
1672 | MAX_USERNAME_SIZE)) | ||
1673 | continue; | ||
1674 | if (strlen(vol->username) != 0 && | ||
1675 | strncmp(ses->password, vol->password, | ||
1676 | MAX_PASSWORD_SIZE)) | ||
1677 | continue; | ||
1678 | } | ||
1605 | ++ses->ses_count; | 1679 | ++ses->ses_count; |
1606 | write_unlock(&cifs_tcp_ses_lock); | 1680 | write_unlock(&cifs_tcp_ses_lock); |
1607 | return ses; | 1681 | return ses; |
@@ -1643,7 +1717,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1643 | 1717 | ||
1644 | xid = GetXid(); | 1718 | xid = GetXid(); |
1645 | 1719 | ||
1646 | ses = cifs_find_smb_ses(server, volume_info->username); | 1720 | ses = cifs_find_smb_ses(server, volume_info); |
1647 | if (ses) { | 1721 | if (ses) { |
1648 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); | 1722 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); |
1649 | 1723 | ||
@@ -1706,6 +1780,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1706 | if (ses->domainName) | 1780 | if (ses->domainName) |
1707 | strcpy(ses->domainName, volume_info->domainname); | 1781 | strcpy(ses->domainName, volume_info->domainname); |
1708 | } | 1782 | } |
1783 | ses->cred_uid = volume_info->cred_uid; | ||
1709 | ses->linux_uid = volume_info->linux_uid; | 1784 | ses->linux_uid = volume_info->linux_uid; |
1710 | ses->overrideSecFlg = volume_info->secFlg; | 1785 | ses->overrideSecFlg = volume_info->secFlg; |
1711 | 1786 | ||
@@ -1773,6 +1848,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1773 | CIFSSMBTDis(xid, tcon); | 1848 | CIFSSMBTDis(xid, tcon); |
1774 | _FreeXid(xid); | 1849 | _FreeXid(xid); |
1775 | 1850 | ||
1851 | cifs_fscache_release_super_cookie(tcon); | ||
1776 | tconInfoFree(tcon); | 1852 | tconInfoFree(tcon); |
1777 | cifs_put_smb_ses(ses); | 1853 | cifs_put_smb_ses(ses); |
1778 | } | 1854 | } |
@@ -1843,6 +1919,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | |||
1843 | list_add(&tcon->tcon_list, &ses->tcon_list); | 1919 | list_add(&tcon->tcon_list, &ses->tcon_list); |
1844 | write_unlock(&cifs_tcp_ses_lock); | 1920 | write_unlock(&cifs_tcp_ses_lock); |
1845 | 1921 | ||
1922 | cifs_fscache_get_super_cookie(tcon); | ||
1923 | |||
1846 | return tcon; | 1924 | return tcon; |
1847 | 1925 | ||
1848 | out_fail: | 1926 | out_fail: |
@@ -2397,6 +2475,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2397 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | 2475 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; |
2398 | if (pvolume_info->dynperm) | 2476 | if (pvolume_info->dynperm) |
2399 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 2477 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; |
2478 | if (pvolume_info->fsc) | ||
2479 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | ||
2400 | if (pvolume_info->direct_io) { | 2480 | if (pvolume_info->direct_io) { |
2401 | cFYI(1, "mounting share using direct i/o"); | 2481 | cFYI(1, "mounting share using direct i/o"); |
2402 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2482 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e7ae78b66fa1..a7de5e9fff11 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -130,12 +130,6 @@ cifs_bp_rename_retry: | |||
130 | return full_path; | 130 | return full_path; |
131 | } | 131 | } |
132 | 132 | ||
133 | /* | ||
134 | * When called with struct file pointer set to NULL, there is no way we could | ||
135 | * update file->private_data, but getting it stuck on openFileList provides a | ||
136 | * way to access it from cifs_fill_filedata and thereby set file->private_data | ||
137 | * from cifs_open. | ||
138 | */ | ||
139 | struct cifsFileInfo * | 133 | struct cifsFileInfo * |
140 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | 134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, |
141 | struct file *file, struct vfsmount *mnt, unsigned int oflags) | 135 | struct file *file, struct vfsmount *mnt, unsigned int oflags) |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 853a968e82d7..3ad7f4300c45 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -44,7 +44,7 @@ is_ip(char *name) | |||
44 | { | 44 | { |
45 | struct sockaddr_storage ss; | 45 | struct sockaddr_storage ss; |
46 | 46 | ||
47 | return cifs_convert_address(name, &ss); | 47 | return cifs_convert_address((struct sockaddr *)&ss, name); |
48 | } | 48 | } |
49 | 49 | ||
50 | static int | 50 | static int |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 409e4f523e61..fa04a00d126d 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 | { |
@@ -282,6 +283,9 @@ int cifs_open(struct inode *inode, struct file *file) | |||
282 | CIFSSMBClose(xid, tcon, netfid); | 283 | CIFSSMBClose(xid, tcon, netfid); |
283 | rc = -ENOMEM; | 284 | rc = -ENOMEM; |
284 | } | 285 | } |
286 | |||
287 | cifs_fscache_set_inode_cookie(inode, file); | ||
288 | |||
285 | goto out; | 289 | goto out; |
286 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 290 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
287 | if (tcon->ses->serverNOS) | 291 | if (tcon->ses->serverNOS) |
@@ -373,6 +377,8 @@ int cifs_open(struct inode *inode, struct file *file) | |||
373 | goto out; | 377 | goto out; |
374 | } | 378 | } |
375 | 379 | ||
380 | cifs_fscache_set_inode_cookie(inode, file); | ||
381 | |||
376 | if (oplock & CIFS_CREATE_ACTION) { | 382 | if (oplock & CIFS_CREATE_ACTION) { |
377 | /* 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 |
378 | problems creating new read-only files */ | 384 | problems creating new read-only files */ |
@@ -427,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
427 | __u16 netfid; | 433 | __u16 netfid; |
428 | 434 | ||
429 | if (file->private_data) | 435 | if (file->private_data) |
430 | pCifsFile = (struct cifsFileInfo *)file->private_data; | 436 | pCifsFile = file->private_data; |
431 | else | 437 | else |
432 | return -EBADF; | 438 | return -EBADF; |
433 | 439 | ||
@@ -565,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
565 | int xid, timeout; | 571 | int xid, timeout; |
566 | struct cifs_sb_info *cifs_sb; | 572 | struct cifs_sb_info *cifs_sb; |
567 | struct cifsTconInfo *pTcon; | 573 | struct cifsTconInfo *pTcon; |
568 | struct cifsFileInfo *pSMBFile = | 574 | struct cifsFileInfo *pSMBFile = file->private_data; |
569 | (struct cifsFileInfo *)file->private_data; | ||
570 | 575 | ||
571 | xid = GetXid(); | 576 | xid = GetXid(); |
572 | 577 | ||
@@ -641,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
641 | { | 646 | { |
642 | int rc = 0; | 647 | int rc = 0; |
643 | int xid; | 648 | int xid; |
644 | struct cifsFileInfo *pCFileStruct = | 649 | struct cifsFileInfo *pCFileStruct = file->private_data; |
645 | (struct cifsFileInfo *)file->private_data; | ||
646 | char *ptmp; | 650 | char *ptmp; |
647 | 651 | ||
648 | cFYI(1, "Closedir inode = 0x%p", inode); | 652 | cFYI(1, "Closedir inode = 0x%p", inode); |
@@ -863,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
863 | length, pfLock, | 867 | length, pfLock, |
864 | posix_lock_type, wait_flag); | 868 | posix_lock_type, wait_flag); |
865 | } else { | 869 | } else { |
866 | struct cifsFileInfo *fid = | 870 | struct cifsFileInfo *fid = file->private_data; |
867 | (struct cifsFileInfo *)file->private_data; | ||
868 | 871 | ||
869 | if (numLock) { | 872 | if (numLock) { |
870 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 873 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
@@ -965,7 +968,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
965 | 968 | ||
966 | if (file->private_data == NULL) | 969 | if (file->private_data == NULL) |
967 | return -EBADF; | 970 | return -EBADF; |
968 | open_file = (struct cifsFileInfo *) file->private_data; | 971 | open_file = file->private_data; |
969 | 972 | ||
970 | rc = generic_write_checks(file, poffset, &write_size, 0); | 973 | rc = generic_write_checks(file, poffset, &write_size, 0); |
971 | if (rc) | 974 | if (rc) |
@@ -1067,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
1067 | 1070 | ||
1068 | if (file->private_data == NULL) | 1071 | if (file->private_data == NULL) |
1069 | return -EBADF; | 1072 | return -EBADF; |
1070 | open_file = (struct cifsFileInfo *)file->private_data; | 1073 | open_file = file->private_data; |
1071 | 1074 | ||
1072 | xid = GetXid(); | 1075 | xid = GetXid(); |
1073 | 1076 | ||
@@ -1651,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync) | |||
1651 | int xid; | 1654 | int xid; |
1652 | int rc = 0; | 1655 | int rc = 0; |
1653 | struct cifsTconInfo *tcon; | 1656 | struct cifsTconInfo *tcon; |
1654 | struct cifsFileInfo *smbfile = | 1657 | struct cifsFileInfo *smbfile = file->private_data; |
1655 | (struct cifsFileInfo *)file->private_data; | ||
1656 | struct inode *inode = file->f_path.dentry->d_inode; | 1658 | struct inode *inode = file->f_path.dentry->d_inode; |
1657 | 1659 | ||
1658 | xid = GetXid(); | 1660 | xid = GetXid(); |
@@ -1756,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1756 | FreeXid(xid); | 1758 | FreeXid(xid); |
1757 | return rc; | 1759 | return rc; |
1758 | } | 1760 | } |
1759 | open_file = (struct cifsFileInfo *)file->private_data; | 1761 | open_file = file->private_data; |
1760 | 1762 | ||
1761 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1763 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1762 | cFYI(1, "attempting read on write only file instance"); | 1764 | cFYI(1, "attempting read on write only file instance"); |
@@ -1837,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1837 | FreeXid(xid); | 1839 | FreeXid(xid); |
1838 | return rc; | 1840 | return rc; |
1839 | } | 1841 | } |
1840 | open_file = (struct cifsFileInfo *)file->private_data; | 1842 | open_file = file->private_data; |
1841 | 1843 | ||
1842 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1844 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
1843 | cFYI(1, "attempting read on write only file instance"); | 1845 | cFYI(1, "attempting read on write only file instance"); |
@@ -1942,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping, | |||
1942 | SetPageUptodate(page); | 1944 | SetPageUptodate(page); |
1943 | unlock_page(page); | 1945 | unlock_page(page); |
1944 | data += PAGE_CACHE_SIZE; | 1946 | data += PAGE_CACHE_SIZE; |
1947 | |||
1948 | /* add page to FS-Cache */ | ||
1949 | cifs_readpage_to_fscache(mapping->host, page); | ||
1945 | } | 1950 | } |
1946 | return; | 1951 | return; |
1947 | } | 1952 | } |
@@ -1968,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1968 | FreeXid(xid); | 1973 | FreeXid(xid); |
1969 | return rc; | 1974 | return rc; |
1970 | } | 1975 | } |
1971 | open_file = (struct cifsFileInfo *)file->private_data; | 1976 | open_file = file->private_data; |
1972 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1977 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1973 | pTcon = cifs_sb->tcon; | 1978 | pTcon = cifs_sb->tcon; |
1974 | 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 | |||
1975 | cFYI(DBG2, "rpages: num pages %d", num_pages); | 1989 | cFYI(DBG2, "rpages: num pages %d", num_pages); |
1976 | for (i = 0; i < num_pages; ) { | 1990 | for (i = 0; i < num_pages; ) { |
1977 | unsigned contig_pages; | 1991 | unsigned contig_pages; |
@@ -2082,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2082 | smb_read_data = NULL; | 2096 | smb_read_data = NULL; |
2083 | } | 2097 | } |
2084 | 2098 | ||
2099 | read_complete: | ||
2085 | FreeXid(xid); | 2100 | FreeXid(xid); |
2086 | return rc; | 2101 | return rc; |
2087 | } | 2102 | } |
@@ -2092,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
2092 | char *read_data; | 2107 | char *read_data; |
2093 | int rc; | 2108 | int rc; |
2094 | 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 | |||
2095 | page_cache_get(page); | 2115 | page_cache_get(page); |
2096 | read_data = kmap(page); | 2116 | read_data = kmap(page); |
2097 | /* for reads over a certain size could initiate async read ahead */ | 2117 | /* for reads over a certain size could initiate async read ahead */ |
@@ -2111,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
2111 | 2131 | ||
2112 | flush_dcache_page(page); | 2132 | flush_dcache_page(page); |
2113 | 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 | |||
2114 | rc = 0; | 2138 | rc = 0; |
2115 | 2139 | ||
2116 | io_error: | 2140 | io_error: |
2117 | kunmap(page); | 2141 | kunmap(page); |
2118 | page_cache_release(page); | 2142 | page_cache_release(page); |
2143 | |||
2144 | read_complete: | ||
2119 | return rc; | 2145 | return rc; |
2120 | } | 2146 | } |
2121 | 2147 | ||
@@ -2265,6 +2291,22 @@ out: | |||
2265 | return rc; | 2291 | return rc; |
2266 | } | 2292 | } |
2267 | 2293 | ||
2294 | static int cifs_release_page(struct page *page, gfp_t gfp) | ||
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 | |||
2268 | static void | 2310 | static void |
2269 | cifs_oplock_break(struct slow_work *work) | 2311 | cifs_oplock_break(struct slow_work *work) |
2270 | { | 2312 | { |
@@ -2338,6 +2380,8 @@ const struct address_space_operations cifs_addr_ops = { | |||
2338 | .write_begin = cifs_write_begin, | 2380 | .write_begin = cifs_write_begin, |
2339 | .write_end = cifs_write_end, | 2381 | .write_end = cifs_write_end, |
2340 | .set_page_dirty = __set_page_dirty_nobuffers, | 2382 | .set_page_dirty = __set_page_dirty_nobuffers, |
2383 | .releasepage = cifs_release_page, | ||
2384 | .invalidatepage = cifs_invalidate_page, | ||
2341 | /* .sync_page = cifs_sync_page, */ | 2385 | /* .sync_page = cifs_sync_page, */ |
2342 | /* .direct_IO = */ | 2386 | /* .direct_IO = */ |
2343 | }; | 2387 | }; |
@@ -2354,6 +2398,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
2354 | .write_begin = cifs_write_begin, | 2398 | .write_begin = cifs_write_begin, |
2355 | .write_end = cifs_write_end, | 2399 | .write_end = cifs_write_end, |
2356 | .set_page_dirty = __set_page_dirty_nobuffers, | 2400 | .set_page_dirty = __set_page_dirty_nobuffers, |
2401 | .releasepage = cifs_release_page, | ||
2402 | .invalidatepage = cifs_invalidate_page, | ||
2357 | /* .sync_page = cifs_sync_page, */ | 2403 | /* .sync_page = cifs_sync_page, */ |
2358 | /* .direct_IO = */ | 2404 | /* .direct_IO = */ |
2359 | }; | 2405 | }; |
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 6f0683c68952..a15b3a9bbff4 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,9 +724,14 @@ 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 | ||
731 | /* don't match inode of different type */ | ||
732 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) | ||
733 | return 0; | ||
734 | |||
729 | /* | 735 | /* |
730 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | 736 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are |
731 | * verboten. Disable serverino and return it as if it were found, the | 737 | * verboten. Disable serverino and return it as if it were found, the |
@@ -776,6 +782,10 @@ retry_iget5_locked: | |||
776 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 782 | inode->i_flags |= S_NOATIME | S_NOCMTIME; |
777 | if (inode->i_state & I_NEW) { | 783 | if (inode->i_state & I_NEW) { |
778 | inode->i_ino = hash; | 784 | inode->i_ino = hash; |
785 | #ifdef CONFIG_CIFS_FSCACHE | ||
786 | /* initialize per-inode cache cookie pointer */ | ||
787 | CIFS_I(inode)->fscache = NULL; | ||
788 | #endif | ||
779 | unlock_new_inode(inode); | 789 | unlock_new_inode(inode); |
780 | } | 790 | } |
781 | } | 791 | } |
@@ -807,6 +817,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
807 | if (!inode) | 817 | if (!inode) |
808 | return ERR_PTR(-ENOMEM); | 818 | return ERR_PTR(-ENOMEM); |
809 | 819 | ||
820 | #ifdef CONFIG_CIFS_FSCACHE | ||
821 | /* populate tcon->resource_id */ | ||
822 | cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; | ||
823 | #endif | ||
824 | |||
810 | if (rc && cifs_sb->tcon->ipc) { | 825 | if (rc && cifs_sb->tcon->ipc) { |
811 | cFYI(1, "ipc connection - fake read inode"); | 826 | cFYI(1, "ipc connection - fake read inode"); |
812 | inode->i_mode |= S_IFDIR; | 827 | inode->i_mode |= S_IFDIR; |
@@ -1568,6 +1583,7 @@ cifs_invalidate_mapping(struct inode *inode) | |||
1568 | cifs_i->write_behind_rc = rc; | 1583 | cifs_i->write_behind_rc = rc; |
1569 | } | 1584 | } |
1570 | invalidate_remote_inode(inode); | 1585 | invalidate_remote_inode(inode); |
1586 | cifs_fscache_reset_inode_cookie(inode); | ||
1571 | } | 1587 | } |
1572 | 1588 | ||
1573 | int cifs_revalidate_file(struct file *filp) | 1589 | int cifs_revalidate_file(struct file *filp) |
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/netmisc.c b/fs/cifs/netmisc.c index d35d52889cb5..c6721ee26dbc 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}, |
@@ -164,7 +165,7 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) | |||
164 | * Returns 0 on failure. | 165 | * Returns 0 on failure. |
165 | */ | 166 | */ |
166 | int | 167 | int |
167 | cifs_convert_address(char *src, void *dst) | 168 | cifs_convert_address(struct sockaddr *dst, char *src) |
168 | { | 169 | { |
169 | int rc; | 170 | int rc; |
170 | char *pct, *endp; | 171 | char *pct, *endp; |
@@ -201,6 +202,27 @@ cifs_convert_address(char *src, void *dst) | |||
201 | return rc; | 202 | return rc; |
202 | } | 203 | } |
203 | 204 | ||
205 | int | ||
206 | cifs_fill_sockaddr(struct sockaddr *dst, char *src, | ||
207 | const unsigned short int port) | ||
208 | { | ||
209 | if (!cifs_convert_address(dst, src)) | ||
210 | return 0; | ||
211 | |||
212 | switch (dst->sa_family) { | ||
213 | case AF_INET: | ||
214 | ((struct sockaddr_in *)dst)->sin_port = htons(port); | ||
215 | break; | ||
216 | case AF_INET6: | ||
217 | ((struct sockaddr_in6 *)dst)->sin6_port = htons(port); | ||
218 | break; | ||
219 | default: | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | return 1; | ||
224 | } | ||
225 | |||
204 | /***************************************************************************** | 226 | /***************************************************************************** |
205 | convert a NT status code to a dos class/code | 227 | convert a NT status code to a dos class/code |
206 | *****************************************************************************/ | 228 | *****************************************************************************/ |
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/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 |