diff options
| -rw-r--r-- | fs/cifs/Kconfig | 9 | ||||
| -rw-r--r-- | fs/cifs/Makefile | 2 | ||||
| -rw-r--r-- | fs/cifs/cache.c | 331 | ||||
| -rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 28 | ||||
| -rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
| -rw-r--r-- | fs/cifs/cifs_spnego.c | 3 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 15 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 40 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 180 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 6 | ||||
| -rw-r--r-- | fs/cifs/dns_resolve.c | 2 | ||||
| -rw-r--r-- | fs/cifs/file.c | 74 | ||||
| -rw-r--r-- | fs/cifs/fscache.c | 236 | ||||
| -rw-r--r-- | fs/cifs/fscache.h | 136 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 20 | ||||
| -rw-r--r-- | fs/cifs/ioctl.c | 3 | ||||
| -rw-r--r-- | fs/cifs/netmisc.c | 24 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 5 | ||||
| -rw-r--r-- | fs/cifs/smberr.h | 1 | 
21 files changed, 1006 insertions, 116 deletions
| diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 80f352596807..5739fd7f88b4 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
| @@ -131,6 +131,15 @@ config CIFS_DFS_UPCALL | |||
| 131 | IP addresses) which is needed for implicit mounts of DFS junction | 131 | IP addresses) which is needed for implicit mounts of DFS junction | 
| 132 | points. If unsure, say N. | 132 | points. If unsure, say N. | 
| 133 | 133 | ||
| 134 | config CIFS_FSCACHE | ||
| 135 | bool "Provide CIFS client caching support (EXPERIMENTAL)" | ||
| 136 | depends on EXPERIMENTAL | ||
| 137 | depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y | ||
| 138 | help | ||
| 139 | Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data | ||
| 140 | to be cached locally on disk through the general filesystem cache | ||
| 141 | manager. If unsure, say N. | ||
| 142 | |||
| 134 | config CIFS_EXPERIMENTAL | 143 | config CIFS_EXPERIMENTAL | 
| 135 | bool "CIFS Experimental Features (EXPERIMENTAL)" | 144 | bool "CIFS Experimental Features (EXPERIMENTAL)" | 
| 136 | depends on CIFS && EXPERIMENTAL | 145 | depends on CIFS && EXPERIMENTAL | 
| diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 9948c0030e86..adefa60a9bdc 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
| @@ -11,3 +11,5 @@ cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | |||
| 11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 
| 12 | 12 | ||
| 13 | cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o | 13 | cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o | 
| 14 | |||
| 15 | cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o | ||
| diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c new file mode 100644 index 000000000000..224d7bbd1fcc --- /dev/null +++ b/fs/cifs/cache.c | |||
| @@ -0,0 +1,331 @@ | |||
| 1 | /* | ||
| 2 | * fs/cifs/cache.c - CIFS filesystem cache index structure definitions | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Novell, Inc. | ||
| 5 | * Authors(s): Suresh Jayaraman (sjayaraman@suse.de> | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as published | ||
| 9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This library is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 15 | * the GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #include "fscache.h" | ||
| 22 | #include "cifs_debug.h" | ||
| 23 | |||
| 24 | /* | ||
| 25 | * CIFS filesystem definition for FS-Cache | ||
| 26 | */ | ||
| 27 | struct fscache_netfs cifs_fscache_netfs = { | ||
| 28 | .name = "cifs", | ||
| 29 | .version = 0, | ||
| 30 | }; | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Register CIFS for caching with FS-Cache | ||
| 34 | */ | ||
| 35 | int cifs_fscache_register(void) | ||
| 36 | { | ||
| 37 | return fscache_register_netfs(&cifs_fscache_netfs); | ||
| 38 | } | ||
| 39 | |||
| 40 | /* | ||
| 41 | * Unregister CIFS for caching | ||
| 42 | */ | ||
| 43 | void cifs_fscache_unregister(void) | ||
| 44 | { | ||
| 45 | fscache_unregister_netfs(&cifs_fscache_netfs); | ||
| 46 | } | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Key layout of CIFS server cache index object | ||
| 50 | */ | ||
| 51 | struct cifs_server_key { | ||
| 52 | uint16_t family; /* address family */ | ||
| 53 | uint16_t port; /* IP port */ | ||
| 54 | union { | ||
| 55 | struct in_addr ipv4_addr; | ||
| 56 | struct in6_addr ipv6_addr; | ||
| 57 | } addr[0]; | ||
| 58 | }; | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Server object keyed by {IPaddress,port,family} tuple | ||
| 62 | */ | ||
| 63 | static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | ||
| 64 | void *buffer, uint16_t maxbuf) | ||
| 65 | { | ||
| 66 | const struct TCP_Server_Info *server = cookie_netfs_data; | ||
| 67 | const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr; | ||
| 68 | struct cifs_server_key *key = buffer; | ||
| 69 | uint16_t key_len = sizeof(struct cifs_server_key); | ||
| 70 | |||
| 71 | memset(key, 0, key_len); | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Should not be a problem as sin_family/sin6_family overlays | ||
| 75 | * sa_family field | ||
| 76 | */ | ||
| 77 | switch (sa->sa_family) { | ||
| 78 | case AF_INET: | ||
| 79 | key->family = server->addr.sockAddr.sin_family; | ||
| 80 | key->port = server->addr.sockAddr.sin_port; | ||
| 81 | key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr; | ||
| 82 | key_len += sizeof(key->addr[0].ipv4_addr); | ||
| 83 | break; | ||
| 84 | |||
| 85 | case AF_INET6: | ||
| 86 | key->family = server->addr.sockAddr6.sin6_family; | ||
| 87 | key->port = server->addr.sockAddr6.sin6_port; | ||
| 88 | key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr; | ||
| 89 | key_len += sizeof(key->addr[0].ipv6_addr); | ||
| 90 | break; | ||
| 91 | |||
| 92 | default: | ||
| 93 | cERROR(1, "CIFS: Unknown network family '%d'", sa->sa_family); | ||
| 94 | key_len = 0; | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | |||
| 98 | return key_len; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Server object for FS-Cache | ||
| 103 | */ | ||
| 104 | const struct fscache_cookie_def cifs_fscache_server_index_def = { | ||
| 105 | .name = "CIFS.server", | ||
| 106 | .type = FSCACHE_COOKIE_TYPE_INDEX, | ||
| 107 | .get_key = cifs_server_get_key, | ||
| 108 | }; | ||
| 109 | |||
| 110 | /* | ||
| 111 | * Auxiliary data attached to CIFS superblock within the cache | ||
| 112 | */ | ||
| 113 | struct cifs_fscache_super_auxdata { | ||
| 114 | u64 resource_id; /* unique server resource id */ | ||
| 115 | }; | ||
| 116 | |||
| 117 | static char *extract_sharename(const char *treename) | ||
| 118 | { | ||
| 119 | const char *src; | ||
| 120 | char *delim, *dst; | ||
| 121 | int len; | ||
| 122 | |||
| 123 | /* skip double chars at the beginning */ | ||
| 124 | src = treename + 2; | ||
| 125 | |||
| 126 | /* share name is always preceded by '\\' now */ | ||
| 127 | delim = strchr(src, '\\'); | ||
| 128 | if (!delim) | ||
| 129 | return ERR_PTR(-EINVAL); | ||
| 130 | delim++; | ||
| 131 | len = strlen(delim); | ||
| 132 | |||
| 133 | /* caller has to free the memory */ | ||
| 134 | dst = kstrndup(delim, len, GFP_KERNEL); | ||
| 135 | if (!dst) | ||
| 136 | return ERR_PTR(-ENOMEM); | ||
| 137 | |||
| 138 | return dst; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Superblock object currently keyed by share name | ||
| 143 | */ | ||
| 144 | static uint16_t cifs_super_get_key(const void *cookie_netfs_data, void *buffer, | ||
| 145 | uint16_t maxbuf) | ||
| 146 | { | ||
| 147 | const struct cifsTconInfo *tcon = cookie_netfs_data; | ||
| 148 | char *sharename; | ||
| 149 | uint16_t len; | ||
| 150 | |||
| 151 | sharename = extract_sharename(tcon->treeName); | ||
| 152 | if (IS_ERR(sharename)) { | ||
| 153 | cFYI(1, "CIFS: couldn't extract sharename\n"); | ||
| 154 | sharename = NULL; | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | len = strlen(sharename); | ||
| 159 | if (len > maxbuf) | ||
| 160 | return 0; | ||
| 161 | |||
| 162 | memcpy(buffer, sharename, len); | ||
| 163 | |||
| 164 | kfree(sharename); | ||
| 165 | |||
| 166 | return len; | ||
| 167 | } | ||
| 168 | |||
| 169 | static uint16_t | ||
| 170 | cifs_fscache_super_get_aux(const void *cookie_netfs_data, void *buffer, | ||
| 171 | uint16_t maxbuf) | ||
| 172 | { | ||
| 173 | struct cifs_fscache_super_auxdata auxdata; | ||
| 174 | const struct cifsTconInfo *tcon = cookie_netfs_data; | ||
| 175 | |||
| 176 | memset(&auxdata, 0, sizeof(auxdata)); | ||
| 177 | auxdata.resource_id = tcon->resource_id; | ||
| 178 | |||
| 179 | if (maxbuf > sizeof(auxdata)) | ||
| 180 | maxbuf = sizeof(auxdata); | ||
| 181 | |||
| 182 | memcpy(buffer, &auxdata, maxbuf); | ||
| 183 | |||
| 184 | return maxbuf; | ||
| 185 | } | ||
| 186 | |||
| 187 | static enum | ||
| 188 | fscache_checkaux cifs_fscache_super_check_aux(void *cookie_netfs_data, | ||
| 189 | const void *data, | ||
| 190 | uint16_t datalen) | ||
| 191 | { | ||
| 192 | struct cifs_fscache_super_auxdata auxdata; | ||
| 193 | const struct cifsTconInfo *tcon = cookie_netfs_data; | ||
| 194 | |||
| 195 | if (datalen != sizeof(auxdata)) | ||
| 196 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
| 197 | |||
| 198 | memset(&auxdata, 0, sizeof(auxdata)); | ||
| 199 | auxdata.resource_id = tcon->resource_id; | ||
| 200 | |||
| 201 | if (memcmp(data, &auxdata, datalen) != 0) | ||
| 202 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
| 203 | |||
| 204 | return FSCACHE_CHECKAUX_OKAY; | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Superblock object for FS-Cache | ||
| 209 | */ | ||
| 210 | const struct fscache_cookie_def cifs_fscache_super_index_def = { | ||
| 211 | .name = "CIFS.super", | ||
| 212 | .type = FSCACHE_COOKIE_TYPE_INDEX, | ||
| 213 | .get_key = cifs_super_get_key, | ||
| 214 | .get_aux = cifs_fscache_super_get_aux, | ||
| 215 | .check_aux = cifs_fscache_super_check_aux, | ||
| 216 | }; | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Auxiliary data attached to CIFS inode within the cache | ||
| 220 | */ | ||
| 221 | struct cifs_fscache_inode_auxdata { | ||
| 222 | struct timespec last_write_time; | ||
| 223 | struct timespec last_change_time; | ||
| 224 | u64 eof; | ||
| 225 | }; | ||
| 226 | |||
| 227 | static uint16_t cifs_fscache_inode_get_key(const void *cookie_netfs_data, | ||
| 228 | void *buffer, uint16_t maxbuf) | ||
| 229 | { | ||
| 230 | const struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
| 231 | uint16_t keylen; | ||
| 232 | |||
| 233 | /* use the UniqueId as the key */ | ||
| 234 | keylen = sizeof(cifsi->uniqueid); | ||
| 235 | if (keylen > maxbuf) | ||
| 236 | keylen = 0; | ||
| 237 | else | ||
| 238 | memcpy(buffer, &cifsi->uniqueid, keylen); | ||
| 239 | |||
| 240 | return keylen; | ||
| 241 | } | ||
| 242 | |||
| 243 | static void | ||
| 244 | cifs_fscache_inode_get_attr(const void *cookie_netfs_data, uint64_t *size) | ||
| 245 | { | ||
| 246 | const struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
| 247 | |||
| 248 | *size = cifsi->vfs_inode.i_size; | ||
| 249 | } | ||
| 250 | |||
| 251 | static uint16_t | ||
| 252 | cifs_fscache_inode_get_aux(const void *cookie_netfs_data, void *buffer, | ||
| 253 | uint16_t maxbuf) | ||
| 254 | { | ||
| 255 | struct cifs_fscache_inode_auxdata auxdata; | ||
| 256 | const struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
| 257 | |||
| 258 | memset(&auxdata, 0, sizeof(auxdata)); | ||
| 259 | auxdata.eof = cifsi->server_eof; | ||
| 260 | auxdata.last_write_time = cifsi->vfs_inode.i_mtime; | ||
| 261 | auxdata.last_change_time = cifsi->vfs_inode.i_ctime; | ||
| 262 | |||
| 263 | if (maxbuf > sizeof(auxdata)) | ||
| 264 | maxbuf = sizeof(auxdata); | ||
| 265 | |||
| 266 | memcpy(buffer, &auxdata, maxbuf); | ||
| 267 | |||
| 268 | return maxbuf; | ||
| 269 | } | ||
| 270 | |||
| 271 | static enum | ||
| 272 | fscache_checkaux cifs_fscache_inode_check_aux(void *cookie_netfs_data, | ||
| 273 | const void *data, | ||
| 274 | uint16_t datalen) | ||
| 275 | { | ||
| 276 | struct cifs_fscache_inode_auxdata auxdata; | ||
| 277 | struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
| 278 | |||
| 279 | if (datalen != sizeof(auxdata)) | ||
| 280 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
| 281 | |||
| 282 | memset(&auxdata, 0, sizeof(auxdata)); | ||
| 283 | auxdata.eof = cifsi->server_eof; | ||
| 284 | auxdata.last_write_time = cifsi->vfs_inode.i_mtime; | ||
| 285 | auxdata.last_change_time = cifsi->vfs_inode.i_ctime; | ||
| 286 | |||
| 287 | if (memcmp(data, &auxdata, datalen) != 0) | ||
| 288 | return FSCACHE_CHECKAUX_OBSOLETE; | ||
| 289 | |||
| 290 | return FSCACHE_CHECKAUX_OKAY; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void cifs_fscache_inode_now_uncached(void *cookie_netfs_data) | ||
| 294 | { | ||
| 295 | struct cifsInodeInfo *cifsi = cookie_netfs_data; | ||
| 296 | struct pagevec pvec; | ||
| 297 | pgoff_t first; | ||
| 298 | int loop, nr_pages; | ||
| 299 | |||
| 300 | pagevec_init(&pvec, 0); | ||
| 301 | first = 0; | ||
| 302 | |||
| 303 | cFYI(1, "cifs inode 0x%p now uncached", cifsi); | ||
| 304 | |||
| 305 | for (;;) { | ||
| 306 | nr_pages = pagevec_lookup(&pvec, | ||
| 307 | cifsi->vfs_inode.i_mapping, first, | ||
| 308 | PAGEVEC_SIZE - pagevec_count(&pvec)); | ||
| 309 | if (!nr_pages) | ||
| 310 | break; | ||
| 311 | |||
| 312 | for (loop = 0; loop < nr_pages; loop++) | ||
| 313 | ClearPageFsCache(pvec.pages[loop]); | ||
| 314 | |||
| 315 | first = pvec.pages[nr_pages - 1]->index + 1; | ||
| 316 | |||
| 317 | pvec.nr = nr_pages; | ||
| 318 | pagevec_release(&pvec); | ||
| 319 | cond_resched(); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | const struct fscache_cookie_def cifs_fscache_inode_object_def = { | ||
| 324 | .name = "CIFS.uniqueid", | ||
| 325 | .type = FSCACHE_COOKIE_TYPE_DATAFILE, | ||
| 326 | .get_key = cifs_fscache_inode_get_key, | ||
| 327 | .get_attr = cifs_fscache_inode_get_attr, | ||
| 328 | .get_aux = cifs_fscache_inode_get_aux, | ||
| 329 | .check_aux = cifs_fscache_inode_check_aux, | ||
| 330 | .now_uncached = cifs_fscache_inode_now_uncached, | ||
| 331 | }; | ||
| diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ac19a6f3dae0..dc1ed50ea06e 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -230,28 +230,22 @@ compose_mount_options_err: | |||
| 230 | goto compose_mount_options_out; | 230 | goto compose_mount_options_out; | 
| 231 | } | 231 | } | 
| 232 | 232 | ||
| 233 | 233 | /** | |
| 234 | static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, | 234 | * cifs_dfs_do_refmount - mounts specified path using provided refferal | 
| 235 | struct dentry *dentry, const struct dfs_info3_param *ref) | 235 | * @cifs_sb: parent/root superblock | 
| 236 | * @fullpath: full path in UNC format | ||
| 237 | * @ref: server's referral | ||
| 238 | */ | ||
| 239 | static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, | ||
| 240 | const char *fullpath, const struct dfs_info3_param *ref) | ||
| 236 | { | 241 | { | 
| 237 | struct cifs_sb_info *cifs_sb; | ||
| 238 | struct vfsmount *mnt; | 242 | struct vfsmount *mnt; | 
| 239 | char *mountdata; | 243 | char *mountdata; | 
| 240 | char *devname = NULL; | 244 | char *devname = NULL; | 
| 241 | char *fullpath; | ||
| 242 | |||
| 243 | cifs_sb = CIFS_SB(dentry->d_inode->i_sb); | ||
| 244 | /* | ||
| 245 | * this function gives us a path with a double backslash prefix. We | ||
| 246 | * require a single backslash for DFS. | ||
| 247 | */ | ||
| 248 | fullpath = build_path_from_dentry(dentry); | ||
| 249 | if (!fullpath) | ||
| 250 | return ERR_PTR(-ENOMEM); | ||
| 251 | 245 | ||
| 246 | /* strip first '\' from fullpath */ | ||
| 252 | mountdata = cifs_compose_mount_options(cifs_sb->mountdata, | 247 | mountdata = cifs_compose_mount_options(cifs_sb->mountdata, | 
| 253 | fullpath + 1, ref, &devname); | 248 | fullpath + 1, ref, &devname); | 
| 254 | kfree(fullpath); | ||
| 255 | 249 | ||
| 256 | if (IS_ERR(mountdata)) | 250 | if (IS_ERR(mountdata)) | 
| 257 | return (struct vfsmount *)mountdata; | 251 | return (struct vfsmount *)mountdata; | 
| @@ -357,8 +351,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 357 | rc = -EINVAL; | 351 | rc = -EINVAL; | 
| 358 | goto out_err; | 352 | goto out_err; | 
| 359 | } | 353 | } | 
| 360 | mnt = cifs_dfs_do_refmount(nd->path.mnt, | 354 | mnt = cifs_dfs_do_refmount(cifs_sb, | 
| 361 | nd->path.dentry, referrals + i); | 355 | full_path, referrals + i); | 
| 362 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, | 356 | cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, | 
| 363 | referrals[i].node_name, mnt); | 357 | referrals[i].node_name, mnt); | 
| 364 | 358 | ||
| diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 246a167cb913..9e771450c3b8 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ | 35 | #define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */ | 
| 36 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ | 36 | #define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */ | 
| 37 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ | 37 | #define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/ | 
| 38 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ | ||
| 38 | 39 | ||
| 39 | struct cifs_sb_info { | 40 | struct cifs_sb_info { | 
| 40 | struct cifsTconInfo *tcon; /* primary mount */ | 41 | struct cifsTconInfo *tcon; /* primary mount */ | 
| diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 379bd7d9c05f..6effccff85a5 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
| @@ -144,6 +144,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
| 144 | sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); | 144 | sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); | 
| 145 | 145 | ||
| 146 | dp = description + strlen(description); | 146 | dp = description + strlen(description); | 
| 147 | sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); | ||
| 148 | |||
| 149 | dp = description + strlen(description); | ||
| 147 | sprintf(dp, ";user=%s", sesInfo->userName); | 150 | sprintf(dp, ";user=%s", sesInfo->userName); | 
| 148 | 151 | ||
| 149 | dp = description + strlen(description); | 152 | dp = description + strlen(description); | 
| diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2cb1a70214d7..8a2cf129e535 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include <linux/key-type.h> | 47 | #include <linux/key-type.h> | 
| 48 | #include "dns_resolve.h" | 48 | #include "dns_resolve.h" | 
| 49 | #include "cifs_spnego.h" | 49 | #include "cifs_spnego.h" | 
| 50 | #include "fscache.h" | ||
| 50 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ | 51 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ | 
| 51 | 52 | ||
| 52 | int cifsFYI = 0; | 53 | int cifsFYI = 0; | 
| @@ -329,6 +330,12 @@ cifs_destroy_inode(struct inode *inode) | |||
| 329 | } | 330 | } | 
| 330 | 331 | ||
| 331 | static void | 332 | static void | 
| 333 | cifs_clear_inode(struct inode *inode) | ||
| 334 | { | ||
| 335 | cifs_fscache_release_inode_cookie(inode); | ||
| 336 | } | ||
| 337 | |||
| 338 | static void | ||
| 332 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 339 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 
| 333 | { | 340 | { | 
| 334 | seq_printf(s, ",addr="); | 341 | seq_printf(s, ",addr="); | 
| @@ -489,6 +496,7 @@ static const struct super_operations cifs_super_ops = { | |||
| 489 | .alloc_inode = cifs_alloc_inode, | 496 | .alloc_inode = cifs_alloc_inode, | 
| 490 | .destroy_inode = cifs_destroy_inode, | 497 | .destroy_inode = cifs_destroy_inode, | 
| 491 | .drop_inode = cifs_drop_inode, | 498 | .drop_inode = cifs_drop_inode, | 
| 499 | .clear_inode = cifs_clear_inode, | ||
| 492 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above | 500 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above | 
| 493 | function unless later we add lazy close of inodes or unless the | 501 | function unless later we add lazy close of inodes or unless the | 
| 494 | kernel forgets to call us with the same number of releases (closes) | 502 | kernel forgets to call us with the same number of releases (closes) | 
| @@ -902,6 +910,10 @@ init_cifs(void) | |||
| 902 | cFYI(1, "cifs_max_pending set to max of 256"); | 910 | cFYI(1, "cifs_max_pending set to max of 256"); | 
| 903 | } | 911 | } | 
| 904 | 912 | ||
| 913 | rc = cifs_fscache_register(); | ||
| 914 | if (rc) | ||
| 915 | goto out; | ||
| 916 | |||
| 905 | rc = cifs_init_inodecache(); | 917 | rc = cifs_init_inodecache(); | 
| 906 | if (rc) | 918 | if (rc) | 
| 907 | goto out_clean_proc; | 919 | goto out_clean_proc; | 
| @@ -951,6 +963,8 @@ init_cifs(void) | |||
| 951 | cifs_destroy_inodecache(); | 963 | cifs_destroy_inodecache(); | 
| 952 | out_clean_proc: | 964 | out_clean_proc: | 
| 953 | cifs_proc_clean(); | 965 | cifs_proc_clean(); | 
| 966 | cifs_fscache_unregister(); | ||
| 967 | out: | ||
| 954 | return rc; | 968 | return rc; | 
| 955 | } | 969 | } | 
| 956 | 970 | ||
| @@ -959,6 +973,7 @@ exit_cifs(void) | |||
| 959 | { | 973 | { | 
| 960 | cFYI(DBG2, "exit_cifs"); | 974 | cFYI(DBG2, "exit_cifs"); | 
| 961 | cifs_proc_clean(); | 975 | cifs_proc_clean(); | 
| 976 | cifs_fscache_unregister(); | ||
| 962 | #ifdef CONFIG_CIFS_DFS_UPCALL | 977 | #ifdef CONFIG_CIFS_DFS_UPCALL | 
| 963 | cifs_dfs_release_automount_timer(); | 978 | cifs_dfs_release_automount_timer(); | 
| 964 | cifs_exit_dns_resolver(); | 979 | cifs_exit_dns_resolver(); | 
| diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a7eb65c84b1c..d82f5fb4761e 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -114,5 +114,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 114 | extern const struct export_operations cifs_export_ops; | 114 | extern const struct export_operations cifs_export_ops; | 
| 115 | #endif /* EXPERIMENTAL */ | 115 | #endif /* EXPERIMENTAL */ | 
| 116 | 116 | ||
| 117 | #define CIFS_VERSION "1.64" | 117 | #define CIFS_VERSION "1.65" | 
| 118 | #endif /* _CIFSFS_H */ | 118 | #endif /* _CIFSFS_H */ | 
| diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a88479ceaad5..59906146ad36 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -16,6 +16,9 @@ | |||
| 16 | * the GNU Lesser General Public License for more details. | 16 | * the GNU Lesser General Public License for more details. | 
| 17 | * | 17 | * | 
| 18 | */ | 18 | */ | 
| 19 | #ifndef _CIFS_GLOB_H | ||
| 20 | #define _CIFS_GLOB_H | ||
| 21 | |||
| 19 | #include <linux/in.h> | 22 | #include <linux/in.h> | 
| 20 | #include <linux/in6.h> | 23 | #include <linux/in6.h> | 
| 21 | #include <linux/slab.h> | 24 | #include <linux/slab.h> | 
| @@ -34,7 +37,7 @@ | |||
| 34 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ | 37 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ | 
| 35 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | 38 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | 
| 36 | termination then *2 for unicode versions */ | 39 | termination then *2 for unicode versions */ | 
| 37 | #define MAX_PASSWORD_SIZE 16 | 40 | #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ | 
| 38 | 41 | ||
| 39 | #define CIFS_MIN_RCV_POOL 4 | 42 | #define CIFS_MIN_RCV_POOL 4 | 
| 40 | 43 | ||
| @@ -80,8 +83,7 @@ enum statusEnum { | |||
| 80 | }; | 83 | }; | 
| 81 | 84 | ||
| 82 | enum securityEnum { | 85 | enum securityEnum { | 
| 83 | PLAINTXT = 0, /* Legacy with Plaintext passwords */ | 86 | LANMAN = 0, /* Legacy LANMAN auth */ | 
| 84 | LANMAN, /* Legacy LANMAN auth */ | ||
| 85 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 87 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 
| 86 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 88 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 
| 87 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ | 89 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ | 
| @@ -142,7 +144,6 @@ struct TCP_Server_Info { | |||
| 142 | struct list_head pending_mid_q; | 144 | struct list_head pending_mid_q; | 
| 143 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | 145 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | 
| 144 | unsigned short server_codepage; /* codepage for the server */ | 146 | unsigned short server_codepage; /* codepage for the server */ | 
| 145 | unsigned long ip_address; /* IP addr for the server if known */ | ||
| 146 | enum protocolEnum protocolType; | 147 | enum protocolEnum protocolType; | 
| 147 | char versionMajor; | 148 | char versionMajor; | 
| 148 | char versionMinor; | 149 | char versionMinor; | 
| @@ -190,19 +191,9 @@ struct TCP_Server_Info { | |||
| 190 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 191 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 
| 191 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 192 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 
| 192 | bool sec_ntlmssp; /* supports NTLMSSP */ | 193 | bool sec_ntlmssp; /* supports NTLMSSP */ | 
| 193 | }; | 194 | #ifdef CONFIG_CIFS_FSCACHE | 
| 194 | 195 | struct fscache_cookie *fscache; /* client index cache cookie */ | |
| 195 | /* | 196 | #endif | 
| 196 | * The following is our shortcut to user information. We surface the uid, | ||
| 197 | * and name. We always get the password on the fly in case it | ||
| 198 | * has changed. We also hang a list of sessions owned by this user off here. | ||
| 199 | */ | ||
| 200 | struct cifsUidInfo { | ||
| 201 | struct list_head userList; | ||
| 202 | struct list_head sessionList; /* SMB sessions for this user */ | ||
| 203 | uid_t linux_uid; | ||
| 204 | char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */ | ||
| 205 | /* BB may need ptr or callback for PAM or WinBind info */ | ||
| 206 | }; | 197 | }; | 
| 207 | 198 | ||
| 208 | /* | 199 | /* | 
| @@ -212,9 +203,6 @@ struct cifsSesInfo { | |||
| 212 | struct list_head smb_ses_list; | 203 | struct list_head smb_ses_list; | 
| 213 | struct list_head tcon_list; | 204 | struct list_head tcon_list; | 
| 214 | struct mutex session_mutex; | 205 | struct mutex session_mutex; | 
| 215 | #if 0 | ||
| 216 | struct cifsUidInfo *uidInfo; /* pointer to user info */ | ||
| 217 | #endif | ||
| 218 | struct TCP_Server_Info *server; /* pointer to server info */ | 206 | struct TCP_Server_Info *server; /* pointer to server info */ | 
| 219 | int ses_count; /* reference counter */ | 207 | int ses_count; /* reference counter */ | 
| 220 | enum statusEnum status; | 208 | enum statusEnum status; | 
| @@ -226,7 +214,8 @@ struct cifsSesInfo { | |||
| 226 | char *serverNOS; /* name of network operating system of server */ | 214 | char *serverNOS; /* name of network operating system of server */ | 
| 227 | char *serverDomain; /* security realm of server */ | 215 | char *serverDomain; /* security realm of server */ | 
| 228 | int Suid; /* remote smb uid */ | 216 | int Suid; /* remote smb uid */ | 
| 229 | uid_t linux_uid; /* local Linux uid */ | 217 | uid_t linux_uid; /* overriding owner of files on the mount */ | 
| 218 | uid_t cred_uid; /* owner of credentials */ | ||
| 230 | int capabilities; | 219 | int capabilities; | 
| 231 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 220 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for | 
| 232 | TCP names - will ipv6 and sctp addresses fit? */ | 221 | TCP names - will ipv6 and sctp addresses fit? */ | 
| @@ -311,6 +300,10 @@ struct cifsTconInfo { | |||
| 311 | bool local_lease:1; /* check leases (only) on local system not remote */ | 300 | bool local_lease:1; /* check leases (only) on local system not remote */ | 
| 312 | bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ | 301 | bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ | 
| 313 | bool need_reconnect:1; /* connection reset, tid now invalid */ | 302 | bool need_reconnect:1; /* connection reset, tid now invalid */ | 
| 303 | #ifdef CONFIG_CIFS_FSCACHE | ||
| 304 | u64 resource_id; /* server resource id */ | ||
| 305 | struct fscache_cookie *fscache; /* cookie for share */ | ||
| 306 | #endif | ||
| 314 | /* BB add field for back pointer to sb struct(s)? */ | 307 | /* BB add field for back pointer to sb struct(s)? */ | 
| 315 | }; | 308 | }; | 
| 316 | 309 | ||
| @@ -398,6 +391,9 @@ struct cifsInodeInfo { | |||
| 398 | bool invalid_mapping:1; /* pagecache is invalid */ | 391 | bool invalid_mapping:1; /* pagecache is invalid */ | 
| 399 | u64 server_eof; /* current file size on server */ | 392 | u64 server_eof; /* current file size on server */ | 
| 400 | u64 uniqueid; /* server inode number */ | 393 | u64 uniqueid; /* server inode number */ | 
| 394 | #ifdef CONFIG_CIFS_FSCACHE | ||
| 395 | struct fscache_cookie *fscache; | ||
| 396 | #endif | ||
| 401 | struct inode vfs_inode; | 397 | struct inode vfs_inode; | 
| 402 | }; | 398 | }; | 
| 403 | 399 | ||
| @@ -733,3 +729,5 @@ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | |||
| 733 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 729 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 
| 734 | 730 | ||
| 735 | extern const struct slow_work_ops cifs_oplock_break_ops; | 731 | extern const struct slow_work_ops cifs_oplock_break_ops; | 
| 732 | |||
| 733 | #endif /* _CIFS_GLOB_H */ | ||
| diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index fb6318b81509..2eaebbd31132 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -86,7 +86,9 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); | |||
| 86 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 86 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 
| 87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 
| 88 | struct TCP_Server_Info *server); | 88 | struct TCP_Server_Info *server); | 
| 89 | extern int cifs_convert_address(char *src, void *dst); | 89 | extern int cifs_convert_address(struct sockaddr *dst, char *src); | 
| 90 | extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src, | ||
| 91 | unsigned short int port); | ||
| 90 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 92 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 
| 91 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 93 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 
| 92 | const struct cifsTconInfo *, int /* length of | 94 | const struct cifsTconInfo *, int /* length of | 
| diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2208f06e4c45..2a43a0aca965 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include "nterr.h" | 48 | #include "nterr.h" | 
| 49 | #include "rfc1002pdu.h" | 49 | #include "rfc1002pdu.h" | 
| 50 | #include "cn_cifs.h" | 50 | #include "cn_cifs.h" | 
| 51 | #include "fscache.h" | ||
| 51 | 52 | ||
| 52 | #define CIFS_PORT 445 | 53 | #define CIFS_PORT 445 | 
| 53 | #define RFC1001_PORT 139 | 54 | #define RFC1001_PORT 139 | 
| @@ -66,6 +67,7 @@ struct smb_vol { | |||
| 66 | char *iocharset; /* local code page for mapping to and from Unicode */ | 67 | char *iocharset; /* local code page for mapping to and from Unicode */ | 
| 67 | char source_rfc1001_name[16]; /* netbios name of client */ | 68 | char source_rfc1001_name[16]; /* netbios name of client */ | 
| 68 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 69 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 
| 70 | uid_t cred_uid; | ||
| 69 | uid_t linux_uid; | 71 | uid_t linux_uid; | 
| 70 | gid_t linux_gid; | 72 | gid_t linux_gid; | 
| 71 | mode_t file_mode; | 73 | mode_t file_mode; | 
| @@ -97,6 +99,7 @@ struct smb_vol { | |||
| 97 | bool noblocksnd:1; | 99 | bool noblocksnd:1; | 
| 98 | bool noautotune:1; | 100 | bool noautotune:1; | 
| 99 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | 101 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | 
| 102 | bool fsc:1; /* enable fscache */ | ||
| 100 | unsigned int rsize; | 103 | unsigned int rsize; | 
| 101 | unsigned int wsize; | 104 | unsigned int wsize; | 
| 102 | bool sockopt_tcp_nodelay:1; | 105 | bool sockopt_tcp_nodelay:1; | 
| @@ -830,7 +833,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 830 | /* null target name indicates to use *SMBSERVR default called name | 833 | /* null target name indicates to use *SMBSERVR default called name | 
| 831 | if we end up sending RFC1001 session initialize */ | 834 | if we end up sending RFC1001 session initialize */ | 
| 832 | vol->target_rfc1001_name[0] = 0; | 835 | vol->target_rfc1001_name[0] = 0; | 
| 833 | vol->linux_uid = current_uid(); /* use current_euid() instead? */ | 836 | vol->cred_uid = current_uid(); | 
| 837 | vol->linux_uid = current_uid(); | ||
| 834 | vol->linux_gid = current_gid(); | 838 | vol->linux_gid = current_gid(); | 
| 835 | 839 | ||
| 836 | /* default to only allowing write access to owner of the mount */ | 840 | /* default to only allowing write access to owner of the mount */ | 
| @@ -1257,6 +1261,12 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1257 | } else if ((strnicmp(data, "nocase", 6) == 0) || | 1261 | } else if ((strnicmp(data, "nocase", 6) == 0) || | 
| 1258 | (strnicmp(data, "ignorecase", 10) == 0)) { | 1262 | (strnicmp(data, "ignorecase", 10) == 0)) { | 
| 1259 | vol->nocase = 1; | 1263 | vol->nocase = 1; | 
| 1264 | } else if (strnicmp(data, "mand", 4) == 0) { | ||
| 1265 | /* ignore */ | ||
| 1266 | } else if (strnicmp(data, "nomand", 6) == 0) { | ||
| 1267 | /* ignore */ | ||
| 1268 | } else if (strnicmp(data, "_netdev", 7) == 0) { | ||
| 1269 | /* ignore */ | ||
| 1260 | } else if (strnicmp(data, "brl", 3) == 0) { | 1270 | } else if (strnicmp(data, "brl", 3) == 0) { | 
| 1261 | vol->nobrl = 0; | 1271 | vol->nobrl = 0; | 
| 1262 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | 1272 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | 
| @@ -1331,6 +1341,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1331 | printk(KERN_WARNING "CIFS: Mount option noac not " | 1341 | printk(KERN_WARNING "CIFS: Mount option noac not " | 
| 1332 | "supported. Instead set " | 1342 | "supported. Instead set " | 
| 1333 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 1343 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 
| 1344 | } else if (strnicmp(data, "fsc", 3) == 0) { | ||
| 1345 | vol->fsc = true; | ||
| 1334 | } else | 1346 | } else | 
| 1335 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1347 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 
| 1336 | data); | 1348 | data); | 
| @@ -1380,18 +1392,92 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1380 | return 0; | 1392 | return 0; | 
| 1381 | } | 1393 | } | 
| 1382 | 1394 | ||
| 1395 | static bool | ||
| 1396 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr) | ||
| 1397 | { | ||
| 1398 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
| 1399 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
| 1400 | |||
| 1401 | switch (addr->sa_family) { | ||
| 1402 | case AF_INET: | ||
| 1403 | if (addr4->sin_addr.s_addr != | ||
| 1404 | server->addr.sockAddr.sin_addr.s_addr) | ||
| 1405 | return false; | ||
| 1406 | if (addr4->sin_port && | ||
| 1407 | addr4->sin_port != server->addr.sockAddr.sin_port) | ||
| 1408 | return false; | ||
| 1409 | break; | ||
| 1410 | case AF_INET6: | ||
| 1411 | if (!ipv6_addr_equal(&addr6->sin6_addr, | ||
| 1412 | &server->addr.sockAddr6.sin6_addr)) | ||
| 1413 | return false; | ||
| 1414 | if (addr6->sin6_scope_id != | ||
| 1415 | server->addr.sockAddr6.sin6_scope_id) | ||
| 1416 | return false; | ||
| 1417 | if (addr6->sin6_port && | ||
| 1418 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | ||
| 1419 | return false; | ||
| 1420 | break; | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | return true; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | static bool | ||
| 1427 | match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | ||
| 1428 | { | ||
| 1429 | unsigned int secFlags; | ||
| 1430 | |||
| 1431 | if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
| 1432 | secFlags = vol->secFlg; | ||
| 1433 | else | ||
| 1434 | secFlags = global_secflags | vol->secFlg; | ||
| 1435 | |||
| 1436 | switch (server->secType) { | ||
| 1437 | case LANMAN: | ||
| 1438 | if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT))) | ||
| 1439 | return false; | ||
| 1440 | break; | ||
| 1441 | case NTLMv2: | ||
| 1442 | if (!(secFlags & CIFSSEC_MAY_NTLMV2)) | ||
| 1443 | return false; | ||
| 1444 | break; | ||
| 1445 | case NTLM: | ||
| 1446 | if (!(secFlags & CIFSSEC_MAY_NTLM)) | ||
| 1447 | return false; | ||
| 1448 | break; | ||
| 1449 | case Kerberos: | ||
| 1450 | if (!(secFlags & CIFSSEC_MAY_KRB5)) | ||
| 1451 | return false; | ||
| 1452 | break; | ||
| 1453 | case RawNTLMSSP: | ||
| 1454 | if (!(secFlags & CIFSSEC_MAY_NTLMSSP)) | ||
| 1455 | return false; | ||
| 1456 | break; | ||
| 1457 | default: | ||
| 1458 | /* shouldn't happen */ | ||
| 1459 | return false; | ||
| 1460 | } | ||
| 1461 | |||
| 1462 | /* now check if signing mode is acceptible */ | ||
| 1463 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0 && | ||
| 1464 | (server->secMode & SECMODE_SIGN_REQUIRED)) | ||
| 1465 | return false; | ||
| 1466 | else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) && | ||
| 1467 | (server->secMode & | ||
| 1468 | (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0) | ||
| 1469 | return false; | ||
| 1470 | |||
| 1471 | return true; | ||
| 1472 | } | ||
| 1473 | |||
| 1383 | static struct TCP_Server_Info * | 1474 | static struct TCP_Server_Info * | 
| 1384 | cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) | 1475 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | 
| 1385 | { | 1476 | { | 
| 1386 | struct list_head *tmp; | ||
| 1387 | struct TCP_Server_Info *server; | 1477 | struct TCP_Server_Info *server; | 
| 1388 | struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; | ||
| 1389 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; | ||
| 1390 | 1478 | ||
| 1391 | write_lock(&cifs_tcp_ses_lock); | 1479 | write_lock(&cifs_tcp_ses_lock); | 
| 1392 | list_for_each(tmp, &cifs_tcp_ses_list) { | 1480 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { | 
| 1393 | server = list_entry(tmp, struct TCP_Server_Info, | ||
| 1394 | tcp_ses_list); | ||
| 1395 | /* | 1481 | /* | 
| 1396 | * the demux thread can exit on its own while still in CifsNew | 1482 | * the demux thread can exit on its own while still in CifsNew | 
| 1397 | * so don't accept any sockets in that state. Since the | 1483 | * so don't accept any sockets in that state. Since the | 
| @@ -1401,37 +1487,11 @@ cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) | |||
| 1401 | if (server->tcpStatus == CifsNew) | 1487 | if (server->tcpStatus == CifsNew) | 
| 1402 | continue; | 1488 | continue; | 
| 1403 | 1489 | ||
| 1404 | switch (addr->ss_family) { | 1490 | if (!match_address(server, addr)) | 
| 1405 | case AF_INET: | 1491 | continue; | 
| 1406 | if (addr4->sin_addr.s_addr == | ||
| 1407 | server->addr.sockAddr.sin_addr.s_addr) { | ||
| 1408 | addr4->sin_port = htons(port); | ||
| 1409 | /* user overrode default port? */ | ||
| 1410 | if (addr4->sin_port) { | ||
| 1411 | if (addr4->sin_port != | ||
| 1412 | server->addr.sockAddr.sin_port) | ||
| 1413 | continue; | ||
| 1414 | } | ||
| 1415 | break; | ||
| 1416 | } else | ||
| 1417 | continue; | ||
| 1418 | 1492 | ||
| 1419 | case AF_INET6: | 1493 | if (!match_security(server, vol)) | 
| 1420 | if (ipv6_addr_equal(&addr6->sin6_addr, | 1494 | continue; | 
| 1421 | &server->addr.sockAddr6.sin6_addr) && | ||
| 1422 | (addr6->sin6_scope_id == | ||
| 1423 | server->addr.sockAddr6.sin6_scope_id)) { | ||
| 1424 | addr6->sin6_port = htons(port); | ||
| 1425 | /* user overrode default port? */ | ||
| 1426 | if (addr6->sin6_port) { | ||
| 1427 | if (addr6->sin6_port != | ||
| 1428 | server->addr.sockAddr6.sin6_port) | ||
| 1429 | continue; | ||
| 1430 | } | ||
| 1431 | break; | ||
| 1432 | } else | ||
| 1433 | continue; | ||
| 1434 | } | ||
| 1435 | 1495 | ||
| 1436 | ++server->srv_count; | 1496 | ++server->srv_count; | 
| 1437 | write_unlock(&cifs_tcp_ses_lock); | 1497 | write_unlock(&cifs_tcp_ses_lock); | 
| @@ -1460,6 +1520,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
| 1460 | server->tcpStatus = CifsExiting; | 1520 | server->tcpStatus = CifsExiting; | 
| 1461 | spin_unlock(&GlobalMid_Lock); | 1521 | spin_unlock(&GlobalMid_Lock); | 
| 1462 | 1522 | ||
| 1523 | cifs_fscache_release_client_cookie(server); | ||
| 1524 | |||
| 1463 | task = xchg(&server->tsk, NULL); | 1525 | task = xchg(&server->tsk, NULL); | 
| 1464 | if (task) | 1526 | if (task) | 
| 1465 | force_sig(SIGKILL, task); | 1527 | force_sig(SIGKILL, task); | 
| @@ -1479,7 +1541,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1479 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); | 1541 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); | 
| 1480 | 1542 | ||
| 1481 | if (volume_info->UNCip && volume_info->UNC) { | 1543 | if (volume_info->UNCip && volume_info->UNC) { | 
| 1482 | rc = cifs_convert_address(volume_info->UNCip, &addr); | 1544 | rc = cifs_fill_sockaddr((struct sockaddr *)&addr, | 
| 1545 | volume_info->UNCip, | ||
| 1546 | volume_info->port); | ||
| 1483 | if (!rc) { | 1547 | if (!rc) { | 
| 1484 | /* we failed translating address */ | 1548 | /* we failed translating address */ | 
| 1485 | rc = -EINVAL; | 1549 | rc = -EINVAL; | 
| @@ -1499,7 +1563,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1499 | } | 1563 | } | 
| 1500 | 1564 | ||
| 1501 | /* see if we already have a matching tcp_ses */ | 1565 | /* see if we already have a matching tcp_ses */ | 
| 1502 | tcp_ses = cifs_find_tcp_session(&addr, volume_info->port); | 1566 | tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info); | 
| 1503 | if (tcp_ses) | 1567 | if (tcp_ses) | 
| 1504 | return tcp_ses; | 1568 | return tcp_ses; | 
| 1505 | 1569 | ||
| @@ -1543,12 +1607,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1543 | cFYI(1, "attempting ipv6 connect"); | 1607 | cFYI(1, "attempting ipv6 connect"); | 
| 1544 | /* BB should we allow ipv6 on port 139? */ | 1608 | /* BB should we allow ipv6 on port 139? */ | 
| 1545 | /* other OS never observed in Wild doing 139 with v6 */ | 1609 | /* other OS never observed in Wild doing 139 with v6 */ | 
| 1546 | sin_server6->sin6_port = htons(volume_info->port); | ||
| 1547 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1610 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 
| 1548 | sizeof(struct sockaddr_in6)); | 1611 | sizeof(struct sockaddr_in6)); | 
| 1549 | rc = ipv6_connect(tcp_ses); | 1612 | rc = ipv6_connect(tcp_ses); | 
| 1550 | } else { | 1613 | } else { | 
| 1551 | sin_server->sin_port = htons(volume_info->port); | ||
| 1552 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1614 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 
| 1553 | sizeof(struct sockaddr_in)); | 1615 | sizeof(struct sockaddr_in)); | 
| 1554 | rc = ipv4_connect(tcp_ses); | 1616 | rc = ipv4_connect(tcp_ses); | 
| @@ -1577,6 +1639,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1577 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 1639 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 
| 1578 | write_unlock(&cifs_tcp_ses_lock); | 1640 | write_unlock(&cifs_tcp_ses_lock); | 
| 1579 | 1641 | ||
| 1642 | cifs_fscache_get_client_cookie(tcp_ses); | ||
| 1643 | |||
| 1580 | return tcp_ses; | 1644 | return tcp_ses; | 
| 1581 | 1645 | ||
| 1582 | out_err: | 1646 | out_err: | 
| @@ -1591,17 +1655,27 @@ out_err: | |||
| 1591 | } | 1655 | } | 
| 1592 | 1656 | ||
| 1593 | static struct cifsSesInfo * | 1657 | static struct cifsSesInfo * | 
| 1594 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) | 1658 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) | 
| 1595 | { | 1659 | { | 
| 1596 | struct list_head *tmp; | ||
| 1597 | struct cifsSesInfo *ses; | 1660 | struct cifsSesInfo *ses; | 
| 1598 | 1661 | ||
| 1599 | write_lock(&cifs_tcp_ses_lock); | 1662 | write_lock(&cifs_tcp_ses_lock); | 
| 1600 | list_for_each(tmp, &server->smb_ses_list) { | 1663 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { | 
| 1601 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 1664 | switch (server->secType) { | 
| 1602 | if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) | 1665 | case Kerberos: | 
| 1603 | continue; | 1666 | if (vol->cred_uid != ses->cred_uid) | 
| 1604 | 1667 | continue; | |
| 1668 | break; | ||
| 1669 | default: | ||
| 1670 | /* anything else takes username/password */ | ||
| 1671 | if (strncmp(ses->userName, vol->username, | ||
| 1672 | MAX_USERNAME_SIZE)) | ||
| 1673 | continue; | ||
| 1674 | if (strlen(vol->username) != 0 && | ||
| 1675 | strncmp(ses->password, vol->password, | ||
| 1676 | MAX_PASSWORD_SIZE)) | ||
| 1677 | continue; | ||
| 1678 | } | ||
| 1605 | ++ses->ses_count; | 1679 | ++ses->ses_count; | 
| 1606 | write_unlock(&cifs_tcp_ses_lock); | 1680 | write_unlock(&cifs_tcp_ses_lock); | 
| 1607 | return ses; | 1681 | return ses; | 
| @@ -1643,7 +1717,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
| 1643 | 1717 | ||
| 1644 | xid = GetXid(); | 1718 | xid = GetXid(); | 
| 1645 | 1719 | ||
| 1646 | ses = cifs_find_smb_ses(server, volume_info->username); | 1720 | ses = cifs_find_smb_ses(server, volume_info); | 
| 1647 | if (ses) { | 1721 | if (ses) { | 
| 1648 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); | 1722 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); | 
| 1649 | 1723 | ||
| @@ -1706,6 +1780,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
| 1706 | if (ses->domainName) | 1780 | if (ses->domainName) | 
| 1707 | strcpy(ses->domainName, volume_info->domainname); | 1781 | strcpy(ses->domainName, volume_info->domainname); | 
| 1708 | } | 1782 | } | 
| 1783 | ses->cred_uid = volume_info->cred_uid; | ||
| 1709 | ses->linux_uid = volume_info->linux_uid; | 1784 | ses->linux_uid = volume_info->linux_uid; | 
| 1710 | ses->overrideSecFlg = volume_info->secFlg; | 1785 | ses->overrideSecFlg = volume_info->secFlg; | 
| 1711 | 1786 | ||
| @@ -1773,6 +1848,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
| 1773 | CIFSSMBTDis(xid, tcon); | 1848 | CIFSSMBTDis(xid, tcon); | 
| 1774 | _FreeXid(xid); | 1849 | _FreeXid(xid); | 
| 1775 | 1850 | ||
| 1851 | cifs_fscache_release_super_cookie(tcon); | ||
| 1776 | tconInfoFree(tcon); | 1852 | tconInfoFree(tcon); | 
| 1777 | cifs_put_smb_ses(ses); | 1853 | cifs_put_smb_ses(ses); | 
| 1778 | } | 1854 | } | 
| @@ -1843,6 +1919,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | |||
| 1843 | list_add(&tcon->tcon_list, &ses->tcon_list); | 1919 | list_add(&tcon->tcon_list, &ses->tcon_list); | 
| 1844 | write_unlock(&cifs_tcp_ses_lock); | 1920 | write_unlock(&cifs_tcp_ses_lock); | 
| 1845 | 1921 | ||
| 1922 | cifs_fscache_get_super_cookie(tcon); | ||
| 1923 | |||
| 1846 | return tcon; | 1924 | return tcon; | 
| 1847 | 1925 | ||
| 1848 | out_fail: | 1926 | out_fail: | 
| @@ -2397,6 +2475,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
| 2397 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | 2475 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | 
| 2398 | if (pvolume_info->dynperm) | 2476 | if (pvolume_info->dynperm) | 
| 2399 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 2477 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 
| 2478 | if (pvolume_info->fsc) | ||
| 2479 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | ||
| 2400 | if (pvolume_info->direct_io) { | 2480 | if (pvolume_info->direct_io) { | 
| 2401 | cFYI(1, "mounting share using direct i/o"); | 2481 | cFYI(1, "mounting share using direct i/o"); | 
| 2402 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2482 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 
| diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e7ae78b66fa1..a7de5e9fff11 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -130,12 +130,6 @@ cifs_bp_rename_retry: | |||
| 130 | return full_path; | 130 | return full_path; | 
| 131 | } | 131 | } | 
| 132 | 132 | ||
| 133 | /* | ||
| 134 | * When called with struct file pointer set to NULL, there is no way we could | ||
| 135 | * update file->private_data, but getting it stuck on openFileList provides a | ||
| 136 | * way to access it from cifs_fill_filedata and thereby set file->private_data | ||
| 137 | * from cifs_open. | ||
| 138 | */ | ||
| 139 | struct cifsFileInfo * | 133 | struct cifsFileInfo * | 
| 140 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | 134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, | 
| 141 | struct file *file, struct vfsmount *mnt, unsigned int oflags) | 135 | struct file *file, struct vfsmount *mnt, unsigned int oflags) | 
| diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 853a968e82d7..3ad7f4300c45 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
| @@ -44,7 +44,7 @@ is_ip(char *name) | |||
| 44 | { | 44 | { | 
| 45 | struct sockaddr_storage ss; | 45 | struct sockaddr_storage ss; | 
| 46 | 46 | ||
| 47 | return cifs_convert_address(name, &ss); | 47 | return cifs_convert_address((struct sockaddr *)&ss, name); | 
| 48 | } | 48 | } | 
| 49 | 49 | ||
| 50 | static int | 50 | static int | 
| diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 409e4f523e61..fa04a00d126d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #include "cifs_unicode.h" | 40 | #include "cifs_unicode.h" | 
| 41 | #include "cifs_debug.h" | 41 | #include "cifs_debug.h" | 
| 42 | #include "cifs_fs_sb.h" | 42 | #include "cifs_fs_sb.h" | 
| 43 | #include "fscache.h" | ||
| 43 | 44 | ||
| 44 | static inline int cifs_convert_flags(unsigned int flags) | 45 | static inline int cifs_convert_flags(unsigned int flags) | 
| 45 | { | 46 | { | 
| @@ -282,6 +283,9 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 282 | CIFSSMBClose(xid, tcon, netfid); | 283 | CIFSSMBClose(xid, tcon, netfid); | 
| 283 | rc = -ENOMEM; | 284 | rc = -ENOMEM; | 
| 284 | } | 285 | } | 
| 286 | |||
| 287 | cifs_fscache_set_inode_cookie(inode, file); | ||
| 288 | |||
| 285 | goto out; | 289 | goto out; | 
| 286 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 290 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 
| 287 | if (tcon->ses->serverNOS) | 291 | if (tcon->ses->serverNOS) | 
| @@ -373,6 +377,8 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 373 | goto out; | 377 | goto out; | 
| 374 | } | 378 | } | 
| 375 | 379 | ||
| 380 | cifs_fscache_set_inode_cookie(inode, file); | ||
| 381 | |||
| 376 | if (oplock & CIFS_CREATE_ACTION) { | 382 | if (oplock & CIFS_CREATE_ACTION) { | 
| 377 | /* time to set mode which we can not set earlier due to | 383 | /* time to set mode which we can not set earlier due to | 
| 378 | problems creating new read-only files */ | 384 | problems creating new read-only files */ | 
| @@ -427,7 +433,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
| 427 | __u16 netfid; | 433 | __u16 netfid; | 
| 428 | 434 | ||
| 429 | if (file->private_data) | 435 | if (file->private_data) | 
| 430 | pCifsFile = (struct cifsFileInfo *)file->private_data; | 436 | pCifsFile = file->private_data; | 
| 431 | else | 437 | else | 
| 432 | return -EBADF; | 438 | return -EBADF; | 
| 433 | 439 | ||
| @@ -565,8 +571,7 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 565 | int xid, timeout; | 571 | int xid, timeout; | 
| 566 | struct cifs_sb_info *cifs_sb; | 572 | struct cifs_sb_info *cifs_sb; | 
| 567 | struct cifsTconInfo *pTcon; | 573 | struct cifsTconInfo *pTcon; | 
| 568 | struct cifsFileInfo *pSMBFile = | 574 | struct cifsFileInfo *pSMBFile = file->private_data; | 
| 569 | (struct cifsFileInfo *)file->private_data; | ||
| 570 | 575 | ||
| 571 | xid = GetXid(); | 576 | xid = GetXid(); | 
| 572 | 577 | ||
| @@ -641,8 +646,7 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
| 641 | { | 646 | { | 
| 642 | int rc = 0; | 647 | int rc = 0; | 
| 643 | int xid; | 648 | int xid; | 
| 644 | struct cifsFileInfo *pCFileStruct = | 649 | struct cifsFileInfo *pCFileStruct = file->private_data; | 
| 645 | (struct cifsFileInfo *)file->private_data; | ||
| 646 | char *ptmp; | 650 | char *ptmp; | 
| 647 | 651 | ||
| 648 | cFYI(1, "Closedir inode = 0x%p", inode); | 652 | cFYI(1, "Closedir inode = 0x%p", inode); | 
| @@ -863,8 +867,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 863 | length, pfLock, | 867 | length, pfLock, | 
| 864 | posix_lock_type, wait_flag); | 868 | posix_lock_type, wait_flag); | 
| 865 | } else { | 869 | } else { | 
| 866 | struct cifsFileInfo *fid = | 870 | struct cifsFileInfo *fid = file->private_data; | 
| 867 | (struct cifsFileInfo *)file->private_data; | ||
| 868 | 871 | ||
| 869 | if (numLock) { | 872 | if (numLock) { | 
| 870 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 873 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 
| @@ -965,7 +968,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 965 | 968 | ||
| 966 | if (file->private_data == NULL) | 969 | if (file->private_data == NULL) | 
| 967 | return -EBADF; | 970 | return -EBADF; | 
| 968 | open_file = (struct cifsFileInfo *) file->private_data; | 971 | open_file = file->private_data; | 
| 969 | 972 | ||
| 970 | rc = generic_write_checks(file, poffset, &write_size, 0); | 973 | rc = generic_write_checks(file, poffset, &write_size, 0); | 
| 971 | if (rc) | 974 | if (rc) | 
| @@ -1067,7 +1070,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 1067 | 1070 | ||
| 1068 | if (file->private_data == NULL) | 1071 | if (file->private_data == NULL) | 
| 1069 | return -EBADF; | 1072 | return -EBADF; | 
| 1070 | open_file = (struct cifsFileInfo *)file->private_data; | 1073 | open_file = file->private_data; | 
| 1071 | 1074 | ||
| 1072 | xid = GetXid(); | 1075 | xid = GetXid(); | 
| 1073 | 1076 | ||
| @@ -1651,8 +1654,7 @@ int cifs_fsync(struct file *file, int datasync) | |||
| 1651 | int xid; | 1654 | int xid; | 
| 1652 | int rc = 0; | 1655 | int rc = 0; | 
| 1653 | struct cifsTconInfo *tcon; | 1656 | struct cifsTconInfo *tcon; | 
| 1654 | struct cifsFileInfo *smbfile = | 1657 | struct cifsFileInfo *smbfile = file->private_data; | 
| 1655 | (struct cifsFileInfo *)file->private_data; | ||
| 1656 | struct inode *inode = file->f_path.dentry->d_inode; | 1658 | struct inode *inode = file->f_path.dentry->d_inode; | 
| 1657 | 1659 | ||
| 1658 | xid = GetXid(); | 1660 | xid = GetXid(); | 
| @@ -1756,7 +1758,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
| 1756 | FreeXid(xid); | 1758 | FreeXid(xid); | 
| 1757 | return rc; | 1759 | return rc; | 
| 1758 | } | 1760 | } | 
| 1759 | open_file = (struct cifsFileInfo *)file->private_data; | 1761 | open_file = file->private_data; | 
| 1760 | 1762 | ||
| 1761 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1763 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 
| 1762 | cFYI(1, "attempting read on write only file instance"); | 1764 | cFYI(1, "attempting read on write only file instance"); | 
| @@ -1837,7 +1839,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
| 1837 | FreeXid(xid); | 1839 | FreeXid(xid); | 
| 1838 | return rc; | 1840 | return rc; | 
| 1839 | } | 1841 | } | 
| 1840 | open_file = (struct cifsFileInfo *)file->private_data; | 1842 | open_file = file->private_data; | 
| 1841 | 1843 | ||
| 1842 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1844 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 
| 1843 | cFYI(1, "attempting read on write only file instance"); | 1845 | cFYI(1, "attempting read on write only file instance"); | 
| @@ -1942,6 +1944,9 @@ static void cifs_copy_cache_pages(struct address_space *mapping, | |||
| 1942 | SetPageUptodate(page); | 1944 | SetPageUptodate(page); | 
| 1943 | unlock_page(page); | 1945 | unlock_page(page); | 
| 1944 | data += PAGE_CACHE_SIZE; | 1946 | data += PAGE_CACHE_SIZE; | 
| 1947 | |||
| 1948 | /* add page to FS-Cache */ | ||
| 1949 | cifs_readpage_to_fscache(mapping->host, page); | ||
| 1945 | } | 1950 | } | 
| 1946 | return; | 1951 | return; | 
| 1947 | } | 1952 | } | 
| @@ -1968,10 +1973,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
| 1968 | FreeXid(xid); | 1973 | FreeXid(xid); | 
| 1969 | return rc; | 1974 | return rc; | 
| 1970 | } | 1975 | } | 
| 1971 | open_file = (struct cifsFileInfo *)file->private_data; | 1976 | open_file = file->private_data; | 
| 1972 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1977 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 
| 1973 | pTcon = cifs_sb->tcon; | 1978 | pTcon = cifs_sb->tcon; | 
| 1974 | 1979 | ||
| 1980 | /* | ||
| 1981 | * Reads as many pages as possible from fscache. Returns -ENOBUFS | ||
| 1982 | * immediately if the cookie is negative | ||
| 1983 | */ | ||
| 1984 | rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, | ||
| 1985 | &num_pages); | ||
| 1986 | if (rc == 0) | ||
| 1987 | goto read_complete; | ||
| 1988 | |||
| 1975 | cFYI(DBG2, "rpages: num pages %d", num_pages); | 1989 | cFYI(DBG2, "rpages: num pages %d", num_pages); | 
| 1976 | for (i = 0; i < num_pages; ) { | 1990 | for (i = 0; i < num_pages; ) { | 
| 1977 | unsigned contig_pages; | 1991 | unsigned contig_pages; | 
| @@ -2082,6 +2096,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
| 2082 | smb_read_data = NULL; | 2096 | smb_read_data = NULL; | 
| 2083 | } | 2097 | } | 
| 2084 | 2098 | ||
| 2099 | read_complete: | ||
| 2085 | FreeXid(xid); | 2100 | FreeXid(xid); | 
| 2086 | return rc; | 2101 | return rc; | 
| 2087 | } | 2102 | } | 
| @@ -2092,6 +2107,11 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
| 2092 | char *read_data; | 2107 | char *read_data; | 
| 2093 | int rc; | 2108 | int rc; | 
| 2094 | 2109 | ||
| 2110 | /* Is the page cached? */ | ||
| 2111 | rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page); | ||
| 2112 | if (rc == 0) | ||
| 2113 | goto read_complete; | ||
| 2114 | |||
| 2095 | page_cache_get(page); | 2115 | page_cache_get(page); | 
| 2096 | read_data = kmap(page); | 2116 | read_data = kmap(page); | 
| 2097 | /* for reads over a certain size could initiate async read ahead */ | 2117 | /* for reads over a certain size could initiate async read ahead */ | 
| @@ -2111,11 +2131,17 @@ static int cifs_readpage_worker(struct file *file, struct page *page, | |||
| 2111 | 2131 | ||
| 2112 | flush_dcache_page(page); | 2132 | flush_dcache_page(page); | 
| 2113 | SetPageUptodate(page); | 2133 | SetPageUptodate(page); | 
| 2134 | |||
| 2135 | /* send this page to the cache */ | ||
| 2136 | cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page); | ||
| 2137 | |||
| 2114 | rc = 0; | 2138 | rc = 0; | 
| 2115 | 2139 | ||
| 2116 | io_error: | 2140 | io_error: | 
| 2117 | kunmap(page); | 2141 | kunmap(page); | 
| 2118 | page_cache_release(page); | 2142 | page_cache_release(page); | 
| 2143 | |||
| 2144 | read_complete: | ||
| 2119 | return rc; | 2145 | return rc; | 
| 2120 | } | 2146 | } | 
| 2121 | 2147 | ||
| @@ -2265,6 +2291,22 @@ out: | |||
| 2265 | return rc; | 2291 | return rc; | 
| 2266 | } | 2292 | } | 
| 2267 | 2293 | ||
| 2294 | static int cifs_release_page(struct page *page, gfp_t gfp) | ||
| 2295 | { | ||
| 2296 | if (PagePrivate(page)) | ||
| 2297 | return 0; | ||
| 2298 | |||
| 2299 | return cifs_fscache_release_page(page, gfp); | ||
| 2300 | } | ||
| 2301 | |||
| 2302 | static void cifs_invalidate_page(struct page *page, unsigned long offset) | ||
| 2303 | { | ||
| 2304 | struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); | ||
| 2305 | |||
| 2306 | if (offset == 0) | ||
| 2307 | cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); | ||
| 2308 | } | ||
| 2309 | |||
| 2268 | static void | 2310 | static void | 
| 2269 | cifs_oplock_break(struct slow_work *work) | 2311 | cifs_oplock_break(struct slow_work *work) | 
| 2270 | { | 2312 | { | 
| @@ -2338,6 +2380,8 @@ const struct address_space_operations cifs_addr_ops = { | |||
| 2338 | .write_begin = cifs_write_begin, | 2380 | .write_begin = cifs_write_begin, | 
| 2339 | .write_end = cifs_write_end, | 2381 | .write_end = cifs_write_end, | 
| 2340 | .set_page_dirty = __set_page_dirty_nobuffers, | 2382 | .set_page_dirty = __set_page_dirty_nobuffers, | 
| 2383 | .releasepage = cifs_release_page, | ||
| 2384 | .invalidatepage = cifs_invalidate_page, | ||
| 2341 | /* .sync_page = cifs_sync_page, */ | 2385 | /* .sync_page = cifs_sync_page, */ | 
| 2342 | /* .direct_IO = */ | 2386 | /* .direct_IO = */ | 
| 2343 | }; | 2387 | }; | 
| @@ -2354,6 +2398,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = { | |||
| 2354 | .write_begin = cifs_write_begin, | 2398 | .write_begin = cifs_write_begin, | 
| 2355 | .write_end = cifs_write_end, | 2399 | .write_end = cifs_write_end, | 
| 2356 | .set_page_dirty = __set_page_dirty_nobuffers, | 2400 | .set_page_dirty = __set_page_dirty_nobuffers, | 
| 2401 | .releasepage = cifs_release_page, | ||
| 2402 | .invalidatepage = cifs_invalidate_page, | ||
| 2357 | /* .sync_page = cifs_sync_page, */ | 2403 | /* .sync_page = cifs_sync_page, */ | 
| 2358 | /* .direct_IO = */ | 2404 | /* .direct_IO = */ | 
| 2359 | }; | 2405 | }; | 
| diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c new file mode 100644 index 000000000000..9f3f5c4be161 --- /dev/null +++ b/fs/cifs/fscache.c | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | /* | ||
| 2 | * fs/cifs/fscache.c - CIFS filesystem cache interface | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Novell, Inc. | ||
| 5 | * Author(s): Suresh Jayaraman (sjayaraman@suse.de> | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as published | ||
| 9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This library is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 15 | * the GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #include "fscache.h" | ||
| 22 | #include "cifsglob.h" | ||
| 23 | #include "cifs_debug.h" | ||
| 24 | #include "cifs_fs_sb.h" | ||
| 25 | |||
| 26 | void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) | ||
| 27 | { | ||
| 28 | server->fscache = | ||
| 29 | fscache_acquire_cookie(cifs_fscache_netfs.primary_index, | ||
| 30 | &cifs_fscache_server_index_def, server); | ||
| 31 | cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server, | ||
| 32 | server->fscache); | ||
| 33 | } | ||
| 34 | |||
| 35 | void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) | ||
| 36 | { | ||
| 37 | cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server, | ||
| 38 | server->fscache); | ||
| 39 | fscache_relinquish_cookie(server->fscache, 0); | ||
| 40 | server->fscache = NULL; | ||
| 41 | } | ||
| 42 | |||
| 43 | void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) | ||
| 44 | { | ||
| 45 | struct TCP_Server_Info *server = tcon->ses->server; | ||
| 46 | |||
| 47 | tcon->fscache = | ||
| 48 | fscache_acquire_cookie(server->fscache, | ||
| 49 | &cifs_fscache_super_index_def, tcon); | ||
| 50 | cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)", | ||
| 51 | server->fscache, tcon->fscache); | ||
| 52 | } | ||
| 53 | |||
| 54 | void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) | ||
| 55 | { | ||
| 56 | cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache); | ||
| 57 | fscache_relinquish_cookie(tcon->fscache, 0); | ||
| 58 | tcon->fscache = NULL; | ||
| 59 | } | ||
| 60 | |||
| 61 | static void cifs_fscache_enable_inode_cookie(struct inode *inode) | ||
| 62 | { | ||
| 63 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
| 64 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 65 | |||
| 66 | if (cifsi->fscache) | ||
| 67 | return; | ||
| 68 | |||
| 69 | cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, | ||
| 70 | &cifs_fscache_inode_object_def, | ||
| 71 | cifsi); | ||
| 72 | cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", | ||
| 73 | cifs_sb->tcon->fscache, cifsi->fscache); | ||
| 74 | } | ||
| 75 | |||
| 76 | void cifs_fscache_release_inode_cookie(struct inode *inode) | ||
| 77 | { | ||
| 78 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
| 79 | |||
| 80 | if (cifsi->fscache) { | ||
| 81 | cFYI(1, "CIFS releasing inode cookie (0x%p)", | ||
| 82 | cifsi->fscache); | ||
| 83 | fscache_relinquish_cookie(cifsi->fscache, 0); | ||
| 84 | cifsi->fscache = NULL; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | static void cifs_fscache_disable_inode_cookie(struct inode *inode) | ||
| 89 | { | ||
| 90 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
| 91 | |||
| 92 | if (cifsi->fscache) { | ||
| 93 | cFYI(1, "CIFS disabling inode cookie (0x%p)", | ||
| 94 | cifsi->fscache); | ||
| 95 | fscache_relinquish_cookie(cifsi->fscache, 1); | ||
| 96 | cifsi->fscache = NULL; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | ||
| 101 | { | ||
| 102 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | ||
| 103 | cifs_fscache_disable_inode_cookie(inode); | ||
| 104 | else { | ||
| 105 | cifs_fscache_enable_inode_cookie(inode); | ||
| 106 | cFYI(1, "CIFS: fscache inode cookie set"); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | void cifs_fscache_reset_inode_cookie(struct inode *inode) | ||
| 111 | { | ||
| 112 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
| 113 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 114 | struct fscache_cookie *old = cifsi->fscache; | ||
| 115 | |||
| 116 | if (cifsi->fscache) { | ||
| 117 | /* retire the current fscache cache and get a new one */ | ||
| 118 | fscache_relinquish_cookie(cifsi->fscache, 1); | ||
| 119 | |||
| 120 | cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache, | ||
| 121 | &cifs_fscache_inode_object_def, | ||
| 122 | cifsi); | ||
| 123 | cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p", | ||
| 124 | cifsi->fscache, old); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | int cifs_fscache_release_page(struct page *page, gfp_t gfp) | ||
| 129 | { | ||
| 130 | if (PageFsCache(page)) { | ||
| 131 | struct inode *inode = page->mapping->host; | ||
| 132 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
| 133 | |||
| 134 | cFYI(1, "CIFS: fscache release page (0x%p/0x%p)", | ||
| 135 | page, cifsi->fscache); | ||
| 136 | if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | |||
| 143 | static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx, | ||
| 144 | int error) | ||
| 145 | { | ||
| 146 | cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)", | ||
| 147 | page, error); | ||
| 148 | if (!error) | ||
| 149 | SetPageUptodate(page); | ||
| 150 | unlock_page(page); | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Retrieve a page from FS-Cache | ||
| 155 | */ | ||
| 156 | int __cifs_readpage_from_fscache(struct inode *inode, struct page *page) | ||
| 157 | { | ||
| 158 | int ret; | ||
| 159 | |||
| 160 | cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p", | ||
| 161 | CIFS_I(inode)->fscache, page, inode); | ||
| 162 | ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page, | ||
| 163 | cifs_readpage_from_fscache_complete, | ||
| 164 | NULL, | ||
| 165 | GFP_KERNEL); | ||
| 166 | switch (ret) { | ||
| 167 | |||
| 168 | case 0: /* page found in fscache, read submitted */ | ||
| 169 | cFYI(1, "CIFS: readpage_from_fscache: submitted"); | ||
| 170 | return ret; | ||
| 171 | case -ENOBUFS: /* page won't be cached */ | ||
| 172 | case -ENODATA: /* page not in cache */ | ||
| 173 | cFYI(1, "CIFS: readpage_from_fscache %d", ret); | ||
| 174 | return 1; | ||
| 175 | |||
| 176 | default: | ||
| 177 | cERROR(1, "unknown error ret = %d", ret); | ||
| 178 | } | ||
| 179 | return ret; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Retrieve a set of pages from FS-Cache | ||
| 184 | */ | ||
| 185 | int __cifs_readpages_from_fscache(struct inode *inode, | ||
| 186 | struct address_space *mapping, | ||
| 187 | struct list_head *pages, | ||
| 188 | unsigned *nr_pages) | ||
| 189 | { | ||
| 190 | int ret; | ||
| 191 | |||
| 192 | cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)", | ||
| 193 | CIFS_I(inode)->fscache, *nr_pages, inode); | ||
| 194 | ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping, | ||
| 195 | pages, nr_pages, | ||
| 196 | cifs_readpage_from_fscache_complete, | ||
| 197 | NULL, | ||
| 198 | mapping_gfp_mask(mapping)); | ||
| 199 | switch (ret) { | ||
| 200 | case 0: /* read submitted to the cache for all pages */ | ||
| 201 | cFYI(1, "CIFS: readpages_from_fscache: submitted"); | ||
| 202 | return ret; | ||
| 203 | |||
| 204 | case -ENOBUFS: /* some pages are not cached and can't be */ | ||
| 205 | case -ENODATA: /* some pages are not cached */ | ||
| 206 | cFYI(1, "CIFS: readpages_from_fscache: no page"); | ||
| 207 | return 1; | ||
| 208 | |||
| 209 | default: | ||
| 210 | cFYI(1, "unknown error ret = %d", ret); | ||
| 211 | } | ||
| 212 | |||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) | ||
| 217 | { | ||
| 218 | int ret; | ||
| 219 | |||
| 220 | cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p", | ||
| 221 | CIFS_I(inode)->fscache, page, inode); | ||
| 222 | ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL); | ||
| 223 | if (ret != 0) | ||
| 224 | fscache_uncache_page(CIFS_I(inode)->fscache, page); | ||
| 225 | } | ||
| 226 | |||
| 227 | void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) | ||
| 228 | { | ||
| 229 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | ||
| 230 | struct fscache_cookie *cookie = cifsi->fscache; | ||
| 231 | |||
| 232 | cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie); | ||
| 233 | fscache_wait_on_page_write(cookie, page); | ||
| 234 | fscache_uncache_page(cookie, page); | ||
| 235 | } | ||
| 236 | |||
| diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h new file mode 100644 index 000000000000..31b88ec2341e --- /dev/null +++ b/fs/cifs/fscache.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * fs/cifs/fscache.h - CIFS filesystem cache interface definitions | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Novell, Inc. | ||
| 5 | * Authors(s): Suresh Jayaraman (sjayaraman@suse.de> | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as published | ||
| 9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This library is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
| 15 | * the GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #ifndef _CIFS_FSCACHE_H | ||
| 22 | #define _CIFS_FSCACHE_H | ||
| 23 | |||
| 24 | #include <linux/fscache.h> | ||
| 25 | |||
| 26 | #include "cifsglob.h" | ||
| 27 | |||
| 28 | #ifdef CONFIG_CIFS_FSCACHE | ||
| 29 | |||
| 30 | extern struct fscache_netfs cifs_fscache_netfs; | ||
| 31 | extern const struct fscache_cookie_def cifs_fscache_server_index_def; | ||
| 32 | extern const struct fscache_cookie_def cifs_fscache_super_index_def; | ||
| 33 | extern const struct fscache_cookie_def cifs_fscache_inode_object_def; | ||
| 34 | |||
| 35 | extern int cifs_fscache_register(void); | ||
| 36 | extern void cifs_fscache_unregister(void); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * fscache.c | ||
| 40 | */ | ||
| 41 | extern void cifs_fscache_get_client_cookie(struct TCP_Server_Info *); | ||
| 42 | extern void cifs_fscache_release_client_cookie(struct TCP_Server_Info *); | ||
| 43 | extern void cifs_fscache_get_super_cookie(struct cifsTconInfo *); | ||
| 44 | extern void cifs_fscache_release_super_cookie(struct cifsTconInfo *); | ||
| 45 | |||
| 46 | extern void cifs_fscache_release_inode_cookie(struct inode *); | ||
| 47 | extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *); | ||
| 48 | extern void cifs_fscache_reset_inode_cookie(struct inode *); | ||
| 49 | |||
| 50 | extern void __cifs_fscache_invalidate_page(struct page *, struct inode *); | ||
| 51 | extern int cifs_fscache_release_page(struct page *page, gfp_t gfp); | ||
| 52 | extern int __cifs_readpage_from_fscache(struct inode *, struct page *); | ||
| 53 | extern int __cifs_readpages_from_fscache(struct inode *, | ||
| 54 | struct address_space *, | ||
| 55 | struct list_head *, | ||
| 56 | unsigned *); | ||
| 57 | |||
| 58 | extern void __cifs_readpage_to_fscache(struct inode *, struct page *); | ||
| 59 | |||
| 60 | static inline void cifs_fscache_invalidate_page(struct page *page, | ||
| 61 | struct inode *inode) | ||
| 62 | { | ||
| 63 | if (PageFsCache(page)) | ||
| 64 | __cifs_fscache_invalidate_page(page, inode); | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline int cifs_readpage_from_fscache(struct inode *inode, | ||
| 68 | struct page *page) | ||
| 69 | { | ||
| 70 | if (CIFS_I(inode)->fscache) | ||
| 71 | return __cifs_readpage_from_fscache(inode, page); | ||
| 72 | |||
| 73 | return -ENOBUFS; | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline int cifs_readpages_from_fscache(struct inode *inode, | ||
| 77 | struct address_space *mapping, | ||
| 78 | struct list_head *pages, | ||
| 79 | unsigned *nr_pages) | ||
| 80 | { | ||
| 81 | if (CIFS_I(inode)->fscache) | ||
| 82 | return __cifs_readpages_from_fscache(inode, mapping, pages, | ||
| 83 | nr_pages); | ||
| 84 | return -ENOBUFS; | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline void cifs_readpage_to_fscache(struct inode *inode, | ||
| 88 | struct page *page) | ||
| 89 | { | ||
| 90 | if (PageFsCache(page)) | ||
| 91 | __cifs_readpage_to_fscache(inode, page); | ||
| 92 | } | ||
| 93 | |||
| 94 | #else /* CONFIG_CIFS_FSCACHE */ | ||
| 95 | static inline int cifs_fscache_register(void) { return 0; } | ||
| 96 | static inline void cifs_fscache_unregister(void) {} | ||
| 97 | |||
| 98 | static inline void | ||
| 99 | cifs_fscache_get_client_cookie(struct TCP_Server_Info *server) {} | ||
| 100 | static inline void | ||
| 101 | cifs_fscache_release_client_cookie(struct TCP_Server_Info *server) {} | ||
| 102 | static inline void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon) {} | ||
| 103 | static inline void | ||
| 104 | cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon) {} | ||
| 105 | |||
| 106 | static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} | ||
| 107 | static inline void cifs_fscache_set_inode_cookie(struct inode *inode, | ||
| 108 | struct file *filp) {} | ||
| 109 | static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {} | ||
| 110 | static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp) | ||
| 111 | { | ||
| 112 | return 1; /* May release page */ | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline void cifs_fscache_invalidate_page(struct page *page, | ||
| 116 | struct inode *inode) {} | ||
| 117 | static inline int | ||
| 118 | cifs_readpage_from_fscache(struct inode *inode, struct page *page) | ||
| 119 | { | ||
| 120 | return -ENOBUFS; | ||
| 121 | } | ||
| 122 | |||
| 123 | static inline int cifs_readpages_from_fscache(struct inode *inode, | ||
| 124 | struct address_space *mapping, | ||
| 125 | struct list_head *pages, | ||
| 126 | unsigned *nr_pages) | ||
| 127 | { | ||
| 128 | return -ENOBUFS; | ||
| 129 | } | ||
| 130 | |||
| 131 | static inline void cifs_readpage_to_fscache(struct inode *inode, | ||
| 132 | struct page *page) {} | ||
| 133 | |||
| 134 | #endif /* CONFIG_CIFS_FSCACHE */ | ||
| 135 | |||
| 136 | #endif /* _CIFS_FSCACHE_H */ | ||
| diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6f0683c68952..a15b3a9bbff4 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "cifsproto.h" | 29 | #include "cifsproto.h" | 
| 30 | #include "cifs_debug.h" | 30 | #include "cifs_debug.h" | 
| 31 | #include "cifs_fs_sb.h" | 31 | #include "cifs_fs_sb.h" | 
| 32 | #include "fscache.h" | ||
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | 35 | static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | 
| @@ -288,7 +289,7 @@ int cifs_get_file_info_unix(struct file *filp) | |||
| 288 | struct inode *inode = filp->f_path.dentry->d_inode; | 289 | struct inode *inode = filp->f_path.dentry->d_inode; | 
| 289 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 
| 290 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 291 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 
| 291 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | 292 | struct cifsFileInfo *cfile = filp->private_data; | 
| 292 | 293 | ||
| 293 | xid = GetXid(); | 294 | xid = GetXid(); | 
| 294 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); | 295 | rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data); | 
| @@ -515,7 +516,7 @@ int cifs_get_file_info(struct file *filp) | |||
| 515 | struct inode *inode = filp->f_path.dentry->d_inode; | 516 | struct inode *inode = filp->f_path.dentry->d_inode; | 
| 516 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 517 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 
| 517 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 518 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 
| 518 | struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; | 519 | struct cifsFileInfo *cfile = filp->private_data; | 
| 519 | 520 | ||
| 520 | xid = GetXid(); | 521 | xid = GetXid(); | 
| 521 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); | 522 | rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); | 
| @@ -723,9 +724,14 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
| 723 | { | 724 | { | 
| 724 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 725 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 
| 725 | 726 | ||
| 727 | /* don't match inode with different uniqueid */ | ||
| 726 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 728 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 
| 727 | return 0; | 729 | return 0; | 
| 728 | 730 | ||
| 731 | /* don't match inode of different type */ | ||
| 732 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) | ||
| 733 | return 0; | ||
| 734 | |||
| 729 | /* | 735 | /* | 
| 730 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | 736 | * uh oh -- it's a directory. We can't use it since hardlinked dirs are | 
| 731 | * verboten. Disable serverino and return it as if it were found, the | 737 | * verboten. Disable serverino and return it as if it were found, the | 
| @@ -776,6 +782,10 @@ retry_iget5_locked: | |||
| 776 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 782 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | 
| 777 | if (inode->i_state & I_NEW) { | 783 | if (inode->i_state & I_NEW) { | 
| 778 | inode->i_ino = hash; | 784 | inode->i_ino = hash; | 
| 785 | #ifdef CONFIG_CIFS_FSCACHE | ||
| 786 | /* initialize per-inode cache cookie pointer */ | ||
| 787 | CIFS_I(inode)->fscache = NULL; | ||
| 788 | #endif | ||
| 779 | unlock_new_inode(inode); | 789 | unlock_new_inode(inode); | 
| 780 | } | 790 | } | 
| 781 | } | 791 | } | 
| @@ -807,6 +817,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
| 807 | if (!inode) | 817 | if (!inode) | 
| 808 | return ERR_PTR(-ENOMEM); | 818 | return ERR_PTR(-ENOMEM); | 
| 809 | 819 | ||
| 820 | #ifdef CONFIG_CIFS_FSCACHE | ||
| 821 | /* populate tcon->resource_id */ | ||
| 822 | cifs_sb->tcon->resource_id = CIFS_I(inode)->uniqueid; | ||
| 823 | #endif | ||
| 824 | |||
| 810 | if (rc && cifs_sb->tcon->ipc) { | 825 | if (rc && cifs_sb->tcon->ipc) { | 
| 811 | cFYI(1, "ipc connection - fake read inode"); | 826 | cFYI(1, "ipc connection - fake read inode"); | 
| 812 | inode->i_mode |= S_IFDIR; | 827 | inode->i_mode |= S_IFDIR; | 
| @@ -1568,6 +1583,7 @@ cifs_invalidate_mapping(struct inode *inode) | |||
| 1568 | cifs_i->write_behind_rc = rc; | 1583 | cifs_i->write_behind_rc = rc; | 
| 1569 | } | 1584 | } | 
| 1570 | invalidate_remote_inode(inode); | 1585 | invalidate_remote_inode(inode); | 
| 1586 | cifs_fscache_reset_inode_cookie(inode); | ||
| 1571 | } | 1587 | } | 
| 1572 | 1588 | ||
| 1573 | int cifs_revalidate_file(struct file *filp) | 1589 | int cifs_revalidate_file(struct file *filp) | 
| diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 505926f1ee6b..9d38a71c8e14 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
| @@ -41,8 +41,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
| 41 | __u64 ExtAttrMask = 0; | 41 | __u64 ExtAttrMask = 0; | 
| 42 | __u64 caps; | 42 | __u64 caps; | 
| 43 | struct cifsTconInfo *tcon; | 43 | struct cifsTconInfo *tcon; | 
| 44 | struct cifsFileInfo *pSMBFile = | 44 | struct cifsFileInfo *pSMBFile = filep->private_data; | 
| 45 | (struct cifsFileInfo *)filep->private_data; | ||
| 46 | #endif /* CONFIG_CIFS_POSIX */ | 45 | #endif /* CONFIG_CIFS_POSIX */ | 
| 47 | 46 | ||
| 48 | xid = GetXid(); | 47 | xid = GetXid(); | 
| diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index d35d52889cb5..c6721ee26dbc 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
| @@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | |||
| 61 | {ERRremcd, -EACCES}, | 61 | {ERRremcd, -EACCES}, | 
| 62 | {ERRdiffdevice, -EXDEV}, | 62 | {ERRdiffdevice, -EXDEV}, | 
| 63 | {ERRnofiles, -ENOENT}, | 63 | {ERRnofiles, -ENOENT}, | 
| 64 | {ERRwriteprot, -EROFS}, | ||
| 64 | {ERRbadshare, -ETXTBSY}, | 65 | {ERRbadshare, -ETXTBSY}, | 
| 65 | {ERRlock, -EACCES}, | 66 | {ERRlock, -EACCES}, | 
| 66 | {ERRunsup, -EINVAL}, | 67 | {ERRunsup, -EINVAL}, | 
| @@ -164,7 +165,7 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) | |||
| 164 | * Returns 0 on failure. | 165 | * Returns 0 on failure. | 
| 165 | */ | 166 | */ | 
| 166 | int | 167 | int | 
| 167 | cifs_convert_address(char *src, void *dst) | 168 | cifs_convert_address(struct sockaddr *dst, char *src) | 
| 168 | { | 169 | { | 
| 169 | int rc; | 170 | int rc; | 
| 170 | char *pct, *endp; | 171 | char *pct, *endp; | 
| @@ -201,6 +202,27 @@ cifs_convert_address(char *src, void *dst) | |||
| 201 | return rc; | 202 | return rc; | 
| 202 | } | 203 | } | 
| 203 | 204 | ||
| 205 | int | ||
| 206 | cifs_fill_sockaddr(struct sockaddr *dst, char *src, | ||
| 207 | const unsigned short int port) | ||
| 208 | { | ||
| 209 | if (!cifs_convert_address(dst, src)) | ||
| 210 | return 0; | ||
| 211 | |||
| 212 | switch (dst->sa_family) { | ||
| 213 | case AF_INET: | ||
| 214 | ((struct sockaddr_in *)dst)->sin_port = htons(port); | ||
| 215 | break; | ||
| 216 | case AF_INET6: | ||
| 217 | ((struct sockaddr_in6 *)dst)->sin6_port = htons(port); | ||
| 218 | break; | ||
| 219 | default: | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | return 1; | ||
| 224 | } | ||
| 225 | |||
| 204 | /***************************************************************************** | 226 | /***************************************************************************** | 
| 205 | convert a NT status code to a dos class/code | 227 | convert a NT status code to a dos class/code | 
| 206 | *****************************************************************************/ | 228 | *****************************************************************************/ | 
| diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index daf1753af674..d5e591fab475 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -847,6 +847,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 847 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 847 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 
| 848 | 848 | ||
| 849 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); | 849 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); | 
| 850 | if (tmp_buf == NULL) { | ||
| 851 | rc = -ENOMEM; | ||
| 852 | break; | ||
| 853 | } | ||
| 854 | |||
| 850 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 855 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 
| 851 | if (current_entry == NULL) { | 856 | if (current_entry == NULL) { | 
| 852 | /* evaluate whether this case is an error */ | 857 | /* evaluate whether this case is an error */ | 
| diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index c5084d27db7c..7f16cb825fe5 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h | |||
| @@ -76,6 +76,7 @@ | |||
| 76 | #define ERRnofiles 18 /* A File Search command can find no | 76 | #define ERRnofiles 18 /* A File Search command can find no | 
| 77 | more files matching the specified | 77 | more files matching the specified | 
| 78 | criteria. */ | 78 | criteria. */ | 
| 79 | #define ERRwriteprot 19 /* media is write protected */ | ||
| 79 | #define ERRgeneral 31 | 80 | #define ERRgeneral 31 | 
| 80 | #define ERRbadshare 32 /* The sharing mode specified for an | 81 | #define ERRbadshare 32 /* The sharing mode specified for an | 
| 81 | Open conflicts with existing FIDs on | 82 | Open conflicts with existing FIDs on | 
