diff options
| author | Ingo Molnar <mingo@elte.hu> | 2010-08-12 15:38:56 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-08-12 15:39:04 -0400 |
| commit | f46a6804135795f77d096ab0128f27531c7d051c (patch) | |
| tree | 7cd33f69e3661327739ae4c96e5a8389e7fc912e /fs/cifs | |
| parent | b3e84ffa21f916e3354a12a7f19169c9febe96d0 (diff) | |
| parent | ad41a1e0cab07c5125456e8d38e5b1ab148d04aa (diff) | |
Merge branch 'linus' into perf/urgent
Merge reason: Fix upstream breakage introduced by:
de5d9bf: Move list types from <linux/list.h> to <linux/types.h>.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
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 | 5 | ||||
| -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 | 44 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 48 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 181 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 8 | ||||
| -rw-r--r-- | fs/cifs/dns_resolve.c | 231 | ||||
| -rw-r--r-- | fs/cifs/dns_resolve.h | 2 | ||||
| -rw-r--r-- | fs/cifs/file.c | 104 | ||||
| -rw-r--r-- | fs/cifs/fscache.c | 236 | ||||
| -rw-r--r-- | fs/cifs/fscache.h | 136 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 149 | ||||
| -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/smberr.h | 1 |
25 files changed, 1230 insertions, 438 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..a7081eeeb85d 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -568,8 +568,9 @@ module can be displayed via modinfo. | |||
| 568 | Misc /proc/fs/cifs Flags and Debug Info | 568 | Misc /proc/fs/cifs Flags and Debug Info |
| 569 | ======================================= | 569 | ======================================= |
| 570 | Informational pseudo-files: | 570 | Informational pseudo-files: |
| 571 | DebugData Displays information about active CIFS sessions | 571 | DebugData Displays information about active CIFS sessions and |
| 572 | and shares, as well as the cifs.ko version. | 572 | shares, features enabled as well as the cifs.ko |
| 573 | version. | ||
| 573 | Stats Lists summary resource usage information as well as per | 574 | Stats Lists summary resource usage information as well as per |
| 574 | share statistics, if CONFIG_CIFS_STATS in enabled | 575 | share statistics, if CONFIG_CIFS_STATS in enabled |
| 575 | in the kernel configuration. | 576 | 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 2cb1a70214d7..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,13 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data) | |||
| 473 | return 0; | 481 | return 0; |
| 474 | } | 482 | } |
| 475 | 483 | ||
| 476 | void cifs_drop_inode(struct inode *inode) | 484 | static int cifs_drop_inode(struct inode *inode) |
| 477 | { | 485 | { |
| 478 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 486 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 479 | 487 | ||
| 480 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | 488 | /* no serverino => unconditional eviction */ |
| 481 | return generic_drop_inode(inode); | 489 | return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) || |
| 482 | 490 | generic_drop_inode(inode); | |
| 483 | return generic_delete_inode(inode); | ||
| 484 | } | 491 | } |
| 485 | 492 | ||
| 486 | static const struct super_operations cifs_super_ops = { | 493 | static const struct super_operations cifs_super_ops = { |
| @@ -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 | .evict_inode = cifs_evict_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; |
| @@ -922,27 +934,13 @@ init_cifs(void) | |||
| 922 | if (rc) | 934 | if (rc) |
| 923 | goto out_unregister_filesystem; | 935 | goto out_unregister_filesystem; |
| 924 | #endif | 936 | #endif |
| 925 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
| 926 | rc = cifs_init_dns_resolver(); | ||
| 927 | if (rc) | ||
| 928 | goto out_unregister_key_type; | ||
| 929 | #endif | ||
| 930 | rc = slow_work_register_user(THIS_MODULE); | ||
| 931 | if (rc) | ||
| 932 | goto out_unregister_resolver_key; | ||
| 933 | 937 | ||
| 934 | return 0; | 938 | return 0; |
| 935 | 939 | ||
| 936 | out_unregister_resolver_key: | ||
| 937 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
| 938 | cifs_exit_dns_resolver(); | ||
| 939 | out_unregister_key_type: | ||
| 940 | #endif | ||
| 941 | #ifdef CONFIG_CIFS_UPCALL | 940 | #ifdef CONFIG_CIFS_UPCALL |
| 942 | unregister_key_type(&cifs_spnego_key_type); | ||
| 943 | out_unregister_filesystem: | 941 | out_unregister_filesystem: |
| 944 | #endif | ||
| 945 | unregister_filesystem(&cifs_fs_type); | 942 | unregister_filesystem(&cifs_fs_type); |
| 943 | #endif | ||
| 946 | out_destroy_request_bufs: | 944 | out_destroy_request_bufs: |
| 947 | cifs_destroy_request_bufs(); | 945 | cifs_destroy_request_bufs(); |
| 948 | out_destroy_mids: | 946 | out_destroy_mids: |
| @@ -951,6 +949,8 @@ init_cifs(void) | |||
| 951 | cifs_destroy_inodecache(); | 949 | cifs_destroy_inodecache(); |
| 952 | out_clean_proc: | 950 | out_clean_proc: |
| 953 | cifs_proc_clean(); | 951 | cifs_proc_clean(); |
| 952 | cifs_fscache_unregister(); | ||
| 953 | out: | ||
| 954 | return rc; | 954 | return rc; |
| 955 | } | 955 | } |
| 956 | 956 | ||
| @@ -959,9 +959,9 @@ exit_cifs(void) | |||
| 959 | { | 959 | { |
| 960 | cFYI(DBG2, "exit_cifs"); | 960 | cFYI(DBG2, "exit_cifs"); |
| 961 | cifs_proc_clean(); | 961 | cifs_proc_clean(); |
| 962 | cifs_fscache_unregister(); | ||
| 962 | #ifdef CONFIG_CIFS_DFS_UPCALL | 963 | #ifdef CONFIG_CIFS_DFS_UPCALL |
| 963 | cifs_dfs_release_automount_timer(); | 964 | cifs_dfs_release_automount_timer(); |
| 964 | cifs_exit_dns_resolver(); | ||
| 965 | #endif | 965 | #endif |
| 966 | #ifdef CONFIG_CIFS_UPCALL | 966 | #ifdef CONFIG_CIFS_UPCALL |
| 967 | 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 fb6318b81509..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 |
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 e7ae78b66fa1..578d88c5b46e 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) |
| @@ -163,7 +157,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
| 163 | mutex_init(&pCifsFile->lock_mutex); | 157 | mutex_init(&pCifsFile->lock_mutex); |
| 164 | INIT_LIST_HEAD(&pCifsFile->llist); | 158 | INIT_LIST_HEAD(&pCifsFile->llist); |
| 165 | atomic_set(&pCifsFile->count, 1); | 159 | atomic_set(&pCifsFile->count, 1); |
| 166 | slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); | 160 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); |
| 167 | 161 | ||
| 168 | write_lock(&GlobalSMBSeslock); | 162 | write_lock(&GlobalSMBSeslock); |
| 169 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | 163 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 853a968e82d7..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,214 +26,73 @@ | |||
| 24 | */ | 26 | */ |
| 25 | 27 | ||
| 26 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 27 | #include <linux/keyctl.h> | 29 | #include <linux/dns_resolver.h> |
| 28 | #include <linux/key-type.h> | ||
| 29 | #include <keys/user-type.h> | ||
| 30 | #include "dns_resolve.h" | 30 | #include "dns_resolve.h" |
| 31 | #include "cifsglob.h" | 31 | #include "cifsglob.h" |
| 32 | #include "cifsproto.h" | 32 | #include "cifsproto.h" |
| 33 | #include "cifs_debug.h" | 33 | #include "cifs_debug.h" |
| 34 | 34 | ||
| 35 | static const struct cred *dns_resolver_cache; | 35 | /** |
| 36 | 36 | * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. | |
| 37 | /* Checks if supplied name is IP address | 37 | * @unc: UNC path specifying the server |
| 38 | * returns: | 38 | * @ip_addr: Where to return the IP address. |
| 39 | * 1 - name is IP | 39 | * |
| 40 | * 0 - name is not IP | 40 | * The IP address will be returned in string form, and the caller is |
| 41 | */ | 41 | * responsible for freeing it. |
| 42 | static int | 42 | * |
| 43 | is_ip(char *name) | 43 | * Returns length of result on success, -ve on error. |
| 44 | { | ||
| 45 | struct sockaddr_storage ss; | ||
| 46 | |||
| 47 | return cifs_convert_address(name, &ss); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int | ||
| 51 | dns_resolver_instantiate(struct key *key, const void *data, | ||
| 52 | size_t datalen) | ||
| 53 | { | ||
| 54 | int rc = 0; | ||
| 55 | char *ip; | ||
| 56 | |||
| 57 | ip = kmalloc(datalen + 1, GFP_KERNEL); | ||
| 58 | if (!ip) | ||
| 59 | return -ENOMEM; | ||
| 60 | |||
| 61 | memcpy(ip, data, datalen); | ||
| 62 | ip[datalen] = '\0'; | ||
| 63 | |||
| 64 | /* make sure this looks like an address */ | ||
| 65 | if (!is_ip(ip)) { | ||
| 66 | kfree(ip); | ||
| 67 | return -EINVAL; | ||
| 68 | } | ||
| 69 | |||
| 70 | key->type_data.x[0] = datalen; | ||
| 71 | key->payload.data = ip; | ||
| 72 | |||
| 73 | return rc; | ||
| 74 | } | ||
| 75 | |||
| 76 | static void | ||
| 77 | dns_resolver_destroy(struct key *key) | ||
| 78 | { | ||
| 79 | kfree(key->payload.data); | ||
| 80 | } | ||
| 81 | |||
| 82 | struct key_type key_type_dns_resolver = { | ||
| 83 | .name = "dns_resolver", | ||
| 84 | .def_datalen = sizeof(struct in_addr), | ||
| 85 | .describe = user_describe, | ||
| 86 | .instantiate = dns_resolver_instantiate, | ||
| 87 | .destroy = dns_resolver_destroy, | ||
| 88 | .match = user_match, | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* Resolves server name to ip address. | ||
| 92 | * input: | ||
| 93 | * unc - server UNC | ||
| 94 | * output: | ||
| 95 | * *ip_addr - pointer to server ip, caller responcible for freeing it. | ||
| 96 | * return 0 on success | ||
| 97 | */ | 44 | */ |
| 98 | int | 45 | int |
| 99 | 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) |
| 100 | { | 47 | { |
| 101 | const struct cred *saved_cred; | 48 | struct sockaddr_storage ss; |
| 102 | int rc = -EAGAIN; | 49 | const char *hostname, *sep; |
| 103 | struct key *rkey = ERR_PTR(-EAGAIN); | ||
| 104 | char *name; | 50 | char *name; |
| 105 | char *data = NULL; | 51 | int len, rc; |
| 106 | int len; | ||
| 107 | 52 | ||
| 108 | if (!ip_addr || !unc) | 53 | if (!ip_addr || !unc) |
| 109 | return -EINVAL; | 54 | return -EINVAL; |
| 110 | 55 | ||
| 111 | /* search for server name delimiter */ | ||
| 112 | len = strlen(unc); | 56 | len = strlen(unc); |
| 113 | if (len < 3) { | 57 | if (len < 3) { |
| 114 | cFYI(1, "%s: unc is too short: %s", __func__, unc); | 58 | cFYI(1, "%s: unc is too short: %s", __func__, unc); |
| 115 | return -EINVAL; | 59 | return -EINVAL; |
| 116 | } | 60 | } |
| 117 | len -= 2; | ||
| 118 | name = memchr(unc+2, '\\', len); | ||
| 119 | if (!name) { | ||
| 120 | cFYI(1, "%s: probably server name is whole unc: %s", | ||
| 121 | __func__, unc); | ||
| 122 | } else { | ||
| 123 | len = (name - unc) - 2/* leading // */; | ||
| 124 | } | ||
| 125 | |||
| 126 | name = kmalloc(len+1, GFP_KERNEL); | ||
| 127 | if (!name) { | ||
| 128 | rc = -ENOMEM; | ||
| 129 | return rc; | ||
| 130 | } | ||
| 131 | memcpy(name, unc+2, len); | ||
| 132 | name[len] = 0; | ||
| 133 | |||
| 134 | if (is_ip(name)) { | ||
| 135 | cFYI(1, "%s: it is IP, skipping dns upcall: %s", | ||
| 136 | __func__, name); | ||
| 137 | data = name; | ||
| 138 | goto skip_upcall; | ||
| 139 | } | ||
| 140 | 61 | ||
| 141 | saved_cred = override_creds(dns_resolver_cache); | 62 | /* Discount leading slashes for cifs */ |
| 142 | rkey = request_key(&key_type_dns_resolver, name, ""); | 63 | len -= 2; |
| 143 | revert_creds(saved_cred); | 64 | hostname = unc + 2; |
| 144 | if (!IS_ERR(rkey)) { | ||
| 145 | if (!(rkey->perm & KEY_USR_VIEW)) { | ||
| 146 | down_read(&rkey->sem); | ||
| 147 | rkey->perm |= KEY_USR_VIEW; | ||
| 148 | up_read(&rkey->sem); | ||
| 149 | } | ||
| 150 | len = rkey->type_data.x[0]; | ||
| 151 | data = rkey->payload.data; | ||
| 152 | } else { | ||
| 153 | cERROR(1, "%s: unable to resolve: %s", __func__, name); | ||
| 154 | goto out; | ||
| 155 | } | ||
| 156 | |||
| 157 | skip_upcall: | ||
| 158 | if (data) { | ||
| 159 | *ip_addr = kmalloc(len + 1, GFP_KERNEL); | ||
| 160 | if (*ip_addr) { | ||
| 161 | memcpy(*ip_addr, data, len + 1); | ||
| 162 | if (!IS_ERR(rkey)) | ||
| 163 | cFYI(1, "%s: resolved: %s to %s", __func__, | ||
| 164 | name, | ||
| 165 | *ip_addr | ||
| 166 | ); | ||
| 167 | rc = 0; | ||
| 168 | } else { | ||
| 169 | rc = -ENOMEM; | ||
| 170 | } | ||
| 171 | if (!IS_ERR(rkey)) | ||
| 172 | key_put(rkey); | ||
| 173 | } | ||
| 174 | 65 | ||
| 175 | out: | 66 | /* Search for server name delimiter */ |
| 176 | kfree(name); | 67 | sep = memchr(hostname, '\\', len); |
| 68 | if (sep) | ||
| 69 | len = sep - unc; | ||
| 70 | else | ||
| 71 | cFYI(1, "%s: probably server name is whole unc: %s", | ||
| 72 | __func__, unc); | ||
| 73 | |||
| 74 | /* Try to interpret hostname as an IPv4 or IPv6 address */ | ||
| 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); | ||
| 177 | return rc; | 87 | return rc; |
| 178 | } | ||
| 179 | 88 | ||
| 180 | int __init cifs_init_dns_resolver(void) | 89 | name_is_IP_address: |
| 181 | { | 90 | name = kmalloc(len + 1, GFP_KERNEL); |
| 182 | struct cred *cred; | 91 | if (!name) |
| 183 | struct key *keyring; | ||
| 184 | int ret; | ||
| 185 | |||
| 186 | printk(KERN_NOTICE "Registering the %s key type\n", | ||
| 187 | key_type_dns_resolver.name); | ||
| 188 | |||
| 189 | /* create an override credential set with a special thread keyring in | ||
| 190 | * which DNS requests are cached | ||
| 191 | * | ||
| 192 | * this is used to prevent malicious redirections from being installed | ||
| 193 | * with add_key(). | ||
| 194 | */ | ||
| 195 | cred = prepare_kernel_cred(NULL); | ||
| 196 | if (!cred) | ||
| 197 | return -ENOMEM; | 92 | return -ENOMEM; |
| 198 | 93 | memcpy(name, hostname, len); | |
| 199 | keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred, | 94 | name[len] = 0; |
| 200 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | 95 | cFYI(1, "%s: unc is IP, skipping dns upcall: %s", __func__, name); |
| 201 | KEY_USR_VIEW | KEY_USR_READ, | 96 | *ip_addr = name; |
| 202 | KEY_ALLOC_NOT_IN_QUOTA); | ||
| 203 | if (IS_ERR(keyring)) { | ||
| 204 | ret = PTR_ERR(keyring); | ||
| 205 | goto failed_put_cred; | ||
| 206 | } | ||
| 207 | |||
| 208 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
| 209 | if (ret < 0) | ||
| 210 | goto failed_put_key; | ||
| 211 | |||
| 212 | ret = register_key_type(&key_type_dns_resolver); | ||
| 213 | if (ret < 0) | ||
| 214 | goto failed_put_key; | ||
| 215 | |||
| 216 | /* instruct request_key() to use this special keyring as a cache for | ||
| 217 | * the results it looks up */ | ||
| 218 | cred->thread_keyring = keyring; | ||
| 219 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | ||
| 220 | dns_resolver_cache = cred; | ||
| 221 | return 0; | 97 | return 0; |
| 222 | |||
| 223 | failed_put_key: | ||
| 224 | key_put(keyring); | ||
| 225 | failed_put_cred: | ||
| 226 | put_cred(cred); | ||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | |||
| 230 | void cifs_exit_dns_resolver(void) | ||
| 231 | { | ||
| 232 | key_revoke(dns_resolver_cache->thread_keyring); | ||
| 233 | unregister_key_type(&key_type_dns_resolver); | ||
| 234 | put_cred(dns_resolver_cache); | ||
| 235 | printk(KERN_NOTICE "Unregistered %s key type\n", | ||
| 236 | key_type_dns_resolver.name); | ||
| 237 | } | 98 | } |
diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h index 5d7f291df162..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 | extern int __init cifs_init_dns_resolver(void); | ||
| 28 | extern void cifs_exit_dns_resolver(void); | ||
| 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 409e4f523e61..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 | { |
| @@ -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,8 +2291,23 @@ out: | |||
| 2265 | return rc; | 2291 | return rc; |
| 2266 | } | 2292 | } |
| 2267 | 2293 | ||
| 2268 | static void | 2294 | static int cifs_release_page(struct page *page, gfp_t gfp) |
| 2269 | 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) | ||
| 2270 | { | 2311 | { |
| 2271 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | 2312 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, |
| 2272 | oplock_break); | 2313 | oplock_break); |
| @@ -2303,33 +2344,30 @@ cifs_oplock_break(struct slow_work *work) | |||
| 2303 | LOCKING_ANDX_OPLOCK_RELEASE, false); | 2344 | LOCKING_ANDX_OPLOCK_RELEASE, false); |
| 2304 | cFYI(1, "Oplock release rc = %d", rc); | 2345 | cFYI(1, "Oplock release rc = %d", rc); |
| 2305 | } | 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); | ||
| 2306 | } | 2357 | } |
| 2307 | 2358 | ||
| 2308 | static int | 2359 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
| 2309 | cifs_oplock_break_get(struct slow_work *work) | ||
| 2310 | { | 2360 | { |
| 2311 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
| 2312 | oplock_break); | ||
| 2313 | mntget(cfile->mnt); | 2361 | mntget(cfile->mnt); |
| 2314 | cifsFileInfo_get(cfile); | 2362 | cifsFileInfo_get(cfile); |
| 2315 | return 0; | ||
| 2316 | } | 2363 | } |
| 2317 | 2364 | ||
| 2318 | static void | 2365 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) |
| 2319 | cifs_oplock_break_put(struct slow_work *work) | ||
| 2320 | { | 2366 | { |
| 2321 | struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, | ||
| 2322 | oplock_break); | ||
| 2323 | mntput(cfile->mnt); | 2367 | mntput(cfile->mnt); |
| 2324 | cifsFileInfo_put(cfile); | 2368 | cifsFileInfo_put(cfile); |
| 2325 | } | 2369 | } |
| 2326 | 2370 | ||
| 2327 | const struct slow_work_ops cifs_oplock_break_ops = { | ||
| 2328 | .get_ref = cifs_oplock_break_get, | ||
| 2329 | .put_ref = cifs_oplock_break_put, | ||
| 2330 | .execute = cifs_oplock_break, | ||
| 2331 | }; | ||
| 2332 | |||
| 2333 | const struct address_space_operations cifs_addr_ops = { | 2371 | const struct address_space_operations cifs_addr_ops = { |
| 2334 | .readpage = cifs_readpage, | 2372 | .readpage = cifs_readpage, |
| 2335 | .readpages = cifs_readpages, | 2373 | .readpages = cifs_readpages, |
| @@ -2338,6 +2376,8 @@ const struct address_space_operations cifs_addr_ops = { | |||
| 2338 | .write_begin = cifs_write_begin, | 2376 | .write_begin = cifs_write_begin, |
| 2339 | .write_end = cifs_write_end, | 2377 | .write_end = cifs_write_end, |
| 2340 | .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, | ||
| 2341 | /* .sync_page = cifs_sync_page, */ | 2381 | /* .sync_page = cifs_sync_page, */ |
| 2342 | /* .direct_IO = */ | 2382 | /* .direct_IO = */ |
| 2343 | }; | 2383 | }; |
| @@ -2354,6 +2394,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
| 2354 | .write_begin = cifs_write_begin, | 2394 | .write_begin = cifs_write_begin, |
| 2355 | .write_end = cifs_write_end, | 2395 | .write_end = cifs_write_end, |
| 2356 | .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, | ||
| 2357 | /* .sync_page = cifs_sync_page, */ | 2399 | /* .sync_page = cifs_sync_page, */ |
| 2358 | /* .direct_IO = */ | 2400 | /* .direct_IO = */ |
| 2359 | }; | 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 6f0683c68952..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; |
| @@ -1568,6 +1602,7 @@ cifs_invalidate_mapping(struct inode *inode) | |||
| 1568 | cifs_i->write_behind_rc = rc; | 1602 | cifs_i->write_behind_rc = rc; |
| 1569 | } | 1603 | } |
| 1570 | invalidate_remote_inode(inode); | 1604 | invalidate_remote_inode(inode); |
| 1605 | cifs_fscache_reset_inode_cookie(inode); | ||
| 1571 | } | 1606 | } |
| 1572 | 1607 | ||
| 1573 | int cifs_revalidate_file(struct file *filp) | 1608 | int cifs_revalidate_file(struct file *filp) |
| @@ -1663,26 +1698,16 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) | |||
| 1663 | return rc; | 1698 | return rc; |
| 1664 | } | 1699 | } |
| 1665 | 1700 | ||
| 1666 | static int cifs_vmtruncate(struct inode *inode, loff_t offset) | 1701 | static void cifs_setsize(struct inode *inode, loff_t offset) |
| 1667 | { | 1702 | { |
| 1668 | loff_t oldsize; | 1703 | loff_t oldsize; |
| 1669 | int err; | ||
| 1670 | 1704 | ||
| 1671 | spin_lock(&inode->i_lock); | 1705 | spin_lock(&inode->i_lock); |
| 1672 | err = inode_newsize_ok(inode, offset); | ||
| 1673 | if (err) { | ||
| 1674 | spin_unlock(&inode->i_lock); | ||
| 1675 | goto out; | ||
| 1676 | } | ||
| 1677 | |||
| 1678 | oldsize = inode->i_size; | 1706 | oldsize = inode->i_size; |
| 1679 | i_size_write(inode, offset); | 1707 | i_size_write(inode, offset); |
| 1680 | spin_unlock(&inode->i_lock); | 1708 | spin_unlock(&inode->i_lock); |
| 1709 | |||
| 1681 | truncate_pagecache(inode, oldsize, offset); | 1710 | truncate_pagecache(inode, oldsize, offset); |
| 1682 | if (inode->i_op->truncate) | ||
| 1683 | inode->i_op->truncate(inode); | ||
| 1684 | out: | ||
| 1685 | return err; | ||
| 1686 | } | 1711 | } |
| 1687 | 1712 | ||
| 1688 | static int | 1713 | static int |
| @@ -1755,7 +1780,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
| 1755 | 1780 | ||
| 1756 | if (rc == 0) { | 1781 | if (rc == 0) { |
| 1757 | cifsInode->server_eof = attrs->ia_size; | 1782 | cifsInode->server_eof = attrs->ia_size; |
| 1758 | rc = cifs_vmtruncate(inode, attrs->ia_size); | 1783 | cifs_setsize(inode, attrs->ia_size); |
| 1759 | cifs_truncate_page(inode->i_mapping, inode->i_size); | 1784 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
| 1760 | } | 1785 | } |
| 1761 | 1786 | ||
| @@ -1780,14 +1805,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1780 | 1805 | ||
| 1781 | xid = GetXid(); | 1806 | xid = GetXid(); |
| 1782 | 1807 | ||
| 1783 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1808 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
| 1784 | /* check if we have permission to change attrs */ | 1809 | attrs->ia_valid |= ATTR_FORCE; |
| 1785 | rc = inode_change_ok(inode, attrs); | 1810 | |
| 1786 | if (rc < 0) | 1811 | rc = inode_change_ok(inode, attrs); |
| 1787 | goto out; | 1812 | if (rc < 0) |
| 1788 | else | 1813 | goto out; |
| 1789 | rc = 0; | ||
| 1790 | } | ||
| 1791 | 1814 | ||
| 1792 | full_path = build_path_from_dentry(direntry); | 1815 | full_path = build_path_from_dentry(direntry); |
| 1793 | if (full_path == NULL) { | 1816 | if (full_path == NULL) { |
| @@ -1873,18 +1896,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1873 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1896 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1874 | } | 1897 | } |
| 1875 | 1898 | ||
| 1876 | if (!rc) { | 1899 | if (rc) |
| 1877 | rc = inode_setattr(inode, attrs); | 1900 | goto out; |
| 1878 | 1901 | ||
| 1879 | /* force revalidate when any of these times are set since some | 1902 | if ((attrs->ia_valid & ATTR_SIZE) && |
| 1880 | of the fs types (eg ext3, fat) do not have fine enough | 1903 | attrs->ia_size != i_size_read(inode)) |
| 1881 | time granularity to match protocol, and we do not have a | 1904 | truncate_setsize(inode, attrs->ia_size); |
| 1882 | a way (yet) to query the server fs's time granularity (and | 1905 | |
| 1883 | whether it rounds times down). | 1906 | setattr_copy(inode, attrs); |
| 1884 | */ | 1907 | mark_inode_dirty(inode); |
| 1885 | if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) | 1908 | |
| 1886 | cifsInode->time = 0; | 1909 | /* force revalidate when any of these times are set since some |
| 1887 | } | 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; | ||
| 1888 | out: | 1917 | out: |
| 1889 | kfree(args); | 1918 | kfree(args); |
| 1890 | kfree(full_path); | 1919 | kfree(full_path); |
| @@ -1909,14 +1938,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
| 1909 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", | 1938 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", |
| 1910 | direntry->d_name.name, attrs->ia_valid); | 1939 | direntry->d_name.name, attrs->ia_valid); |
| 1911 | 1940 | ||
| 1912 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1941 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
| 1913 | /* check if we have permission to change attrs */ | 1942 | attrs->ia_valid |= ATTR_FORCE; |
| 1914 | rc = inode_change_ok(inode, attrs); | 1943 | |
| 1915 | if (rc < 0) { | 1944 | rc = inode_change_ok(inode, attrs); |
| 1916 | FreeXid(xid); | 1945 | if (rc < 0) { |
| 1917 | return rc; | 1946 | FreeXid(xid); |
| 1918 | } else | 1947 | return rc; |
| 1919 | rc = 0; | ||
| 1920 | } | 1948 | } |
| 1921 | 1949 | ||
| 1922 | full_path = build_path_from_dentry(direntry); | 1950 | full_path = build_path_from_dentry(direntry); |
| @@ -2024,8 +2052,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
| 2024 | 2052 | ||
| 2025 | /* 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 |
| 2026 | that */ | 2054 | that */ |
| 2027 | if (!rc) | 2055 | if (rc) |
| 2028 | 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 | |||
| 2029 | cifs_setattr_exit: | 2066 | cifs_setattr_exit: |
| 2030 | kfree(full_path); | 2067 | kfree(full_path); |
| 2031 | 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/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 |
