diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/Kconfig | 20 | ||||
-rw-r--r-- | fs/cifs/Makefile | 4 | ||||
-rw-r--r-- | fs/cifs/README | 5 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 56 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 25 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 114 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 20 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 189 | ||||
-rw-r--r-- | fs/cifs/connect.c | 182 | ||||
-rw-r--r-- | fs/cifs/file.c | 783 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 8 | ||||
-rw-r--r-- | fs/cifs/misc.c | 155 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 15 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 243 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 27 | ||||
-rw-r--r-- | fs/cifs/transport.c | 78 |
17 files changed, 1202 insertions, 726 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 2b243af70aa3..a08306a8bec9 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -158,3 +158,23 @@ config CIFS_NFSD_EXPORT | |||
158 | depends on CIFS && EXPERIMENTAL && BROKEN | 158 | depends on CIFS && EXPERIMENTAL && BROKEN |
159 | help | 159 | help |
160 | Allows NFS server to export a CIFS mounted share (nfsd over cifs) | 160 | Allows NFS server to export a CIFS mounted share (nfsd over cifs) |
161 | |||
162 | config CIFS_SMB2 | ||
163 | bool "SMB2 network file system support (EXPERIMENTAL)" | ||
164 | depends on EXPERIMENTAL && INET && BROKEN | ||
165 | select NLS | ||
166 | select KEYS | ||
167 | select FSCACHE | ||
168 | select DNS_RESOLVER | ||
169 | |||
170 | help | ||
171 | This enables experimental support for the SMB2 (Server Message Block | ||
172 | version 2) protocol. The SMB2 protocol is the successor to the | ||
173 | popular CIFS and SMB network file sharing protocols. SMB2 is the | ||
174 | native file sharing mechanism for recent versions of Windows | ||
175 | operating systems (since Vista). SMB2 enablement will eventually | ||
176 | allow users better performance, security and features, than would be | ||
177 | possible with cifs. Note that smb2 mount options also are simpler | ||
178 | (compared to cifs) due to protocol improvements. | ||
179 | |||
180 | Unless you are a developer or tester, say N. | ||
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 005d524c3a4a..4b4127544349 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
@@ -6,7 +6,7 @@ obj-$(CONFIG_CIFS) += cifs.o | |||
6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | 6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ |
7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ | 7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ |
8 | cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ | 8 | cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ |
9 | readdir.o ioctl.o sess.o export.o | 9 | readdir.o ioctl.o sess.o export.o smb1ops.o |
10 | 10 | ||
11 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o | 11 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o |
12 | 12 | ||
@@ -15,3 +15,5 @@ cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | |||
15 | cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o | 15 | cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o |
16 | 16 | ||
17 | cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o | 17 | cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o |
18 | |||
19 | cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o | ||
diff --git a/fs/cifs/README b/fs/cifs/README index b7d782bab797..22ab7b5b8da7 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -608,11 +608,6 @@ Stats Lists summary resource usage information as well as per | |||
608 | in the kernel configuration. | 608 | in the kernel configuration. |
609 | 609 | ||
610 | Configuration pseudo-files: | 610 | Configuration pseudo-files: |
611 | MultiuserMount If set to one, more than one CIFS session to | ||
612 | the same server ip address can be established | ||
613 | if more than one uid accesses the same mount | ||
614 | point and if the uids user/password mapping | ||
615 | information is available. (default is 0) | ||
616 | PacketSigningEnabled If set to one, cifs packet signing is enabled | 611 | PacketSigningEnabled If set to one, cifs packet signing is enabled |
617 | and will be used if the server requires | 612 | and will be used if the server requires |
618 | it. If set to two, cifs packet signing is | 613 | it. If set to two, cifs packet signing is |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 270464629416..e8140528ca5c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -57,19 +57,21 @@ cifs_dump_mem(char *label, void *data, int length) | |||
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | #ifdef CONFIG_CIFS_DEBUG2 | ||
61 | void cifs_dump_detail(void *buf) | 60 | void cifs_dump_detail(void *buf) |
62 | { | 61 | { |
62 | #ifdef CONFIG_CIFS_DEBUG2 | ||
63 | struct smb_hdr *smb = (struct smb_hdr *)buf; | 63 | struct smb_hdr *smb = (struct smb_hdr *)buf; |
64 | 64 | ||
65 | cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", | 65 | cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", |
66 | smb->Command, smb->Status.CifsError, | 66 | smb->Command, smb->Status.CifsError, |
67 | smb->Flags, smb->Flags2, smb->Mid, smb->Pid); | 67 | smb->Flags, smb->Flags2, smb->Mid, smb->Pid); |
68 | cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb)); | 68 | cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb)); |
69 | #endif /* CONFIG_CIFS_DEBUG2 */ | ||
69 | } | 70 | } |
70 | 71 | ||
71 | void cifs_dump_mids(struct TCP_Server_Info *server) | 72 | void cifs_dump_mids(struct TCP_Server_Info *server) |
72 | { | 73 | { |
74 | #ifdef CONFIG_CIFS_DEBUG2 | ||
73 | struct list_head *tmp; | 75 | struct list_head *tmp; |
74 | struct mid_q_entry *mid_entry; | 76 | struct mid_q_entry *mid_entry; |
75 | 77 | ||
@@ -102,8 +104,8 @@ void cifs_dump_mids(struct TCP_Server_Info *server) | |||
102 | } | 104 | } |
103 | } | 105 | } |
104 | spin_unlock(&GlobalMid_Lock); | 106 | spin_unlock(&GlobalMid_Lock); |
105 | } | ||
106 | #endif /* CONFIG_CIFS_DEBUG2 */ | 107 | #endif /* CONFIG_CIFS_DEBUG2 */ |
108 | } | ||
107 | 109 | ||
108 | #ifdef CONFIG_PROC_FS | 110 | #ifdef CONFIG_PROC_FS |
109 | static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | 111 | static int cifs_debug_data_proc_show(struct seq_file *m, void *v) |
@@ -420,7 +422,6 @@ static struct proc_dir_entry *proc_fs_cifs; | |||
420 | static const struct file_operations cifsFYI_proc_fops; | 422 | static const struct file_operations cifsFYI_proc_fops; |
421 | static const struct file_operations cifs_lookup_cache_proc_fops; | 423 | static const struct file_operations cifs_lookup_cache_proc_fops; |
422 | static const struct file_operations traceSMB_proc_fops; | 424 | static const struct file_operations traceSMB_proc_fops; |
423 | static const struct file_operations cifs_multiuser_mount_proc_fops; | ||
424 | static const struct file_operations cifs_security_flags_proc_fops; | 425 | static const struct file_operations cifs_security_flags_proc_fops; |
425 | static const struct file_operations cifs_linux_ext_proc_fops; | 426 | static const struct file_operations cifs_linux_ext_proc_fops; |
426 | 427 | ||
@@ -440,8 +441,6 @@ cifs_proc_init(void) | |||
440 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); | 441 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); |
441 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, | 442 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, |
442 | &cifs_linux_ext_proc_fops); | 443 | &cifs_linux_ext_proc_fops); |
443 | proc_create("MultiuserMount", 0, proc_fs_cifs, | ||
444 | &cifs_multiuser_mount_proc_fops); | ||
445 | proc_create("SecurityFlags", 0, proc_fs_cifs, | 444 | proc_create("SecurityFlags", 0, proc_fs_cifs, |
446 | &cifs_security_flags_proc_fops); | 445 | &cifs_security_flags_proc_fops); |
447 | proc_create("LookupCacheEnabled", 0, proc_fs_cifs, | 446 | proc_create("LookupCacheEnabled", 0, proc_fs_cifs, |
@@ -460,7 +459,6 @@ cifs_proc_clean(void) | |||
460 | #ifdef CONFIG_CIFS_STATS | 459 | #ifdef CONFIG_CIFS_STATS |
461 | remove_proc_entry("Stats", proc_fs_cifs); | 460 | remove_proc_entry("Stats", proc_fs_cifs); |
462 | #endif | 461 | #endif |
463 | remove_proc_entry("MultiuserMount", proc_fs_cifs); | ||
464 | remove_proc_entry("SecurityFlags", proc_fs_cifs); | 462 | remove_proc_entry("SecurityFlags", proc_fs_cifs); |
465 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); | 463 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); |
466 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); | 464 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); |
@@ -617,52 +615,6 @@ static const struct file_operations traceSMB_proc_fops = { | |||
617 | .write = traceSMB_proc_write, | 615 | .write = traceSMB_proc_write, |
618 | }; | 616 | }; |
619 | 617 | ||
620 | static int cifs_multiuser_mount_proc_show(struct seq_file *m, void *v) | ||
621 | { | ||
622 | seq_printf(m, "%d\n", multiuser_mount); | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | static int cifs_multiuser_mount_proc_open(struct inode *inode, struct file *fh) | ||
627 | { | ||
628 | return single_open(fh, cifs_multiuser_mount_proc_show, NULL); | ||
629 | } | ||
630 | |||
631 | static ssize_t cifs_multiuser_mount_proc_write(struct file *file, | ||
632 | const char __user *buffer, size_t count, loff_t *ppos) | ||
633 | { | ||
634 | char c; | ||
635 | int rc; | ||
636 | static bool warned; | ||
637 | |||
638 | rc = get_user(c, buffer); | ||
639 | if (rc) | ||
640 | return rc; | ||
641 | if (c == '0' || c == 'n' || c == 'N') | ||
642 | multiuser_mount = 0; | ||
643 | else if (c == '1' || c == 'y' || c == 'Y') { | ||
644 | multiuser_mount = 1; | ||
645 | if (!warned) { | ||
646 | warned = true; | ||
647 | printk(KERN_WARNING "CIFS VFS: The legacy multiuser " | ||
648 | "mount code is scheduled to be deprecated in " | ||
649 | "3.5. Please switch to using the multiuser " | ||
650 | "mount option."); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | return count; | ||
655 | } | ||
656 | |||
657 | static const struct file_operations cifs_multiuser_mount_proc_fops = { | ||
658 | .owner = THIS_MODULE, | ||
659 | .open = cifs_multiuser_mount_proc_open, | ||
660 | .read = seq_read, | ||
661 | .llseek = seq_lseek, | ||
662 | .release = single_release, | ||
663 | .write = cifs_multiuser_mount_proc_write, | ||
664 | }; | ||
665 | |||
666 | static int cifs_security_flags_proc_show(struct seq_file *m, void *v) | 618 | static int cifs_security_flags_proc_show(struct seq_file *m, void *v) |
667 | { | 619 | { |
668 | seq_printf(m, "0x%x\n", global_secflags); | 620 | seq_printf(m, "0x%x\n", global_secflags); |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index 566e0ae8dc2c..c0c68bb492d7 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
@@ -24,10 +24,10 @@ | |||
24 | #define _H_CIFS_DEBUG | 24 | #define _H_CIFS_DEBUG |
25 | 25 | ||
26 | void cifs_dump_mem(char *label, void *data, int length); | 26 | void cifs_dump_mem(char *label, void *data, int length); |
27 | #ifdef CONFIG_CIFS_DEBUG2 | ||
28 | #define DBG2 2 | ||
29 | void cifs_dump_detail(void *); | 27 | void cifs_dump_detail(void *); |
30 | void cifs_dump_mids(struct TCP_Server_Info *); | 28 | void cifs_dump_mids(struct TCP_Server_Info *); |
29 | #ifdef CONFIG_CIFS_DEBUG2 | ||
30 | #define DBG2 2 | ||
31 | #else | 31 | #else |
32 | #define DBG2 0 | 32 | #define DBG2 0 |
33 | #endif | 33 | #endif |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 541ef81f6ae8..8b6e344eb0ba 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -56,7 +56,6 @@ int traceSMB = 0; | |||
56 | bool enable_oplocks = true; | 56 | bool enable_oplocks = true; |
57 | unsigned int linuxExtEnabled = 1; | 57 | unsigned int linuxExtEnabled = 1; |
58 | unsigned int lookupCacheEnabled = 1; | 58 | unsigned int lookupCacheEnabled = 1; |
59 | unsigned int multiuser_mount = 0; | ||
60 | unsigned int global_secflags = CIFSSEC_DEF; | 59 | unsigned int global_secflags = CIFSSEC_DEF; |
61 | /* unsigned int ntlmv2_support = 0; */ | 60 | /* unsigned int ntlmv2_support = 0; */ |
62 | unsigned int sign_CIFS_PDUs = 1; | 61 | unsigned int sign_CIFS_PDUs = 1; |
@@ -125,7 +124,7 @@ cifs_read_super(struct super_block *sb) | |||
125 | goto out_no_root; | 124 | goto out_no_root; |
126 | } | 125 | } |
127 | 126 | ||
128 | /* do that *after* d_alloc_root() - we want NULL ->d_op for root here */ | 127 | /* do that *after* d_make_root() - we want NULL ->d_op for root here */ |
129 | if (cifs_sb_master_tcon(cifs_sb)->nocase) | 128 | if (cifs_sb_master_tcon(cifs_sb)->nocase) |
130 | sb->s_d_op = &cifs_ci_dentry_ops; | 129 | sb->s_d_op = &cifs_ci_dentry_ops; |
131 | else | 130 | else |
@@ -272,7 +271,7 @@ static void | |||
272 | cifs_evict_inode(struct inode *inode) | 271 | cifs_evict_inode(struct inode *inode) |
273 | { | 272 | { |
274 | truncate_inode_pages(&inode->i_data, 0); | 273 | truncate_inode_pages(&inode->i_data, 0); |
275 | end_writeback(inode); | 274 | clear_inode(inode); |
276 | cifs_fscache_release_inode_cookie(inode); | 275 | cifs_fscache_release_inode_cookie(inode); |
277 | } | 276 | } |
278 | 277 | ||
@@ -329,6 +328,19 @@ cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server) | |||
329 | seq_printf(s, "i"); | 328 | seq_printf(s, "i"); |
330 | } | 329 | } |
331 | 330 | ||
331 | static void | ||
332 | cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb) | ||
333 | { | ||
334 | seq_printf(s, ",cache="); | ||
335 | |||
336 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) | ||
337 | seq_printf(s, "strict"); | ||
338 | else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
339 | seq_printf(s, "none"); | ||
340 | else | ||
341 | seq_printf(s, "loose"); | ||
342 | } | ||
343 | |||
332 | /* | 344 | /* |
333 | * cifs_show_options() is for displaying mount options in /proc/mounts. | 345 | * cifs_show_options() is for displaying mount options in /proc/mounts. |
334 | * Not all settable options are displayed but most of the important | 346 | * Not all settable options are displayed but most of the important |
@@ -342,7 +354,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
342 | struct sockaddr *srcaddr; | 354 | struct sockaddr *srcaddr; |
343 | srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; | 355 | srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; |
344 | 356 | ||
357 | seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string); | ||
345 | cifs_show_security(s, tcon->ses->server); | 358 | cifs_show_security(s, tcon->ses->server); |
359 | cifs_show_cache_flavor(s, cifs_sb); | ||
346 | 360 | ||
347 | seq_printf(s, ",unc=%s", tcon->treeName); | 361 | seq_printf(s, ",unc=%s", tcon->treeName); |
348 | 362 | ||
@@ -408,8 +422,6 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
408 | seq_printf(s, ",rwpidforward"); | 422 | seq_printf(s, ",rwpidforward"); |
409 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) | 423 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) |
410 | seq_printf(s, ",forcemand"); | 424 | seq_printf(s, ",forcemand"); |
411 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | ||
412 | seq_printf(s, ",directio"); | ||
413 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 425 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
414 | seq_printf(s, ",nouser_xattr"); | 426 | seq_printf(s, ",nouser_xattr"); |
415 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 427 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
@@ -432,8 +444,6 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
432 | seq_printf(s, ",nostrictsync"); | 444 | seq_printf(s, ",nostrictsync"); |
433 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) | 445 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
434 | seq_printf(s, ",noperm"); | 446 | seq_printf(s, ",noperm"); |
435 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) | ||
436 | seq_printf(s, ",strictcache"); | ||
437 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) | 447 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) |
438 | seq_printf(s, ",backupuid=%u", cifs_sb->mnt_backupuid); | 448 | seq_printf(s, ",backupuid=%u", cifs_sb->mnt_backupuid); |
439 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) | 449 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) |
@@ -945,7 +955,6 @@ cifs_init_once(void *inode) | |||
945 | struct cifsInodeInfo *cifsi = inode; | 955 | struct cifsInodeInfo *cifsi = inode; |
946 | 956 | ||
947 | inode_init_once(&cifsi->vfs_inode); | 957 | inode_init_once(&cifsi->vfs_inode); |
948 | INIT_LIST_HEAD(&cifsi->llist); | ||
949 | mutex_init(&cifsi->lock_mutex); | 958 | mutex_init(&cifsi->lock_mutex); |
950 | } | 959 | } |
951 | 960 | ||
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 4ff6313f0a91..6df0cbe1cbc9 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -43,6 +43,7 @@ | |||
43 | 43 | ||
44 | #define CIFS_MIN_RCV_POOL 4 | 44 | #define CIFS_MIN_RCV_POOL 4 |
45 | 45 | ||
46 | #define MAX_REOPEN_ATT 5 /* these many maximum attempts to reopen a file */ | ||
46 | /* | 47 | /* |
47 | * default attribute cache timeout (jiffies) | 48 | * default attribute cache timeout (jiffies) |
48 | */ | 49 | */ |
@@ -150,6 +151,58 @@ struct cifs_cred { | |||
150 | ***************************************************************** | 151 | ***************************************************************** |
151 | */ | 152 | */ |
152 | 153 | ||
154 | enum smb_version { | ||
155 | Smb_1 = 1, | ||
156 | Smb_21, | ||
157 | }; | ||
158 | |||
159 | struct mid_q_entry; | ||
160 | struct TCP_Server_Info; | ||
161 | struct cifsFileInfo; | ||
162 | struct cifs_ses; | ||
163 | |||
164 | struct smb_version_operations { | ||
165 | int (*send_cancel)(struct TCP_Server_Info *, void *, | ||
166 | struct mid_q_entry *); | ||
167 | bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *); | ||
168 | /* setup request: allocate mid, sign message */ | ||
169 | int (*setup_request)(struct cifs_ses *, struct kvec *, unsigned int, | ||
170 | struct mid_q_entry **); | ||
171 | /* check response: verify signature, map error */ | ||
172 | int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *, | ||
173 | bool); | ||
174 | void (*add_credits)(struct TCP_Server_Info *, const unsigned int); | ||
175 | void (*set_credits)(struct TCP_Server_Info *, const int); | ||
176 | int * (*get_credits_field)(struct TCP_Server_Info *); | ||
177 | __u64 (*get_next_mid)(struct TCP_Server_Info *); | ||
178 | /* data offset from read response message */ | ||
179 | unsigned int (*read_data_offset)(char *); | ||
180 | /* data length from read response message */ | ||
181 | unsigned int (*read_data_length)(char *); | ||
182 | /* map smb to linux error */ | ||
183 | int (*map_error)(char *, bool); | ||
184 | /* find mid corresponding to the response message */ | ||
185 | struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *); | ||
186 | void (*dump_detail)(void *); | ||
187 | /* verify the message */ | ||
188 | int (*check_message)(char *, unsigned int); | ||
189 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); | ||
190 | }; | ||
191 | |||
192 | struct smb_version_values { | ||
193 | char *version_string; | ||
194 | __u32 large_lock_type; | ||
195 | __u32 exclusive_lock_type; | ||
196 | __u32 shared_lock_type; | ||
197 | __u32 unlock_lock_type; | ||
198 | size_t header_size; | ||
199 | size_t max_header_size; | ||
200 | size_t read_rsp_size; | ||
201 | }; | ||
202 | |||
203 | #define HEADER_SIZE(server) (server->vals->header_size) | ||
204 | #define MAX_HEADER_SIZE(server) (server->vals->max_header_size) | ||
205 | |||
153 | struct smb_vol { | 206 | struct smb_vol { |
154 | char *username; | 207 | char *username; |
155 | char *password; | 208 | char *password; |
@@ -205,6 +258,8 @@ struct smb_vol { | |||
205 | bool sockopt_tcp_nodelay:1; | 258 | bool sockopt_tcp_nodelay:1; |
206 | unsigned short int port; | 259 | unsigned short int port; |
207 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | 260 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ |
261 | struct smb_version_operations *ops; | ||
262 | struct smb_version_values *vals; | ||
208 | char *prepath; | 263 | char *prepath; |
209 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | 264 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ |
210 | struct nls_table *local_nls; | 265 | struct nls_table *local_nls; |
@@ -242,6 +297,8 @@ struct TCP_Server_Info { | |||
242 | int srv_count; /* reference counter */ | 297 | int srv_count; /* reference counter */ |
243 | /* 15 character server name + 0x20 16th byte indicating type = srv */ | 298 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
244 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 299 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
300 | struct smb_version_operations *ops; | ||
301 | struct smb_version_values *vals; | ||
245 | enum statusEnum tcpStatus; /* what we think the status is */ | 302 | enum statusEnum tcpStatus; /* what we think the status is */ |
246 | char *hostname; /* hostname portion of UNC string */ | 303 | char *hostname; /* hostname portion of UNC string */ |
247 | struct socket *ssocket; | 304 | struct socket *ssocket; |
@@ -321,16 +378,6 @@ in_flight(struct TCP_Server_Info *server) | |||
321 | return num; | 378 | return num; |
322 | } | 379 | } |
323 | 380 | ||
324 | static inline int* | ||
325 | get_credits_field(struct TCP_Server_Info *server) | ||
326 | { | ||
327 | /* | ||
328 | * This will change to switch statement when we reserve slots for echos | ||
329 | * and oplock breaks. | ||
330 | */ | ||
331 | return &server->credits; | ||
332 | } | ||
333 | |||
334 | static inline bool | 381 | static inline bool |
335 | has_credits(struct TCP_Server_Info *server, int *credits) | 382 | has_credits(struct TCP_Server_Info *server, int *credits) |
336 | { | 383 | { |
@@ -341,16 +388,22 @@ has_credits(struct TCP_Server_Info *server, int *credits) | |||
341 | return num > 0; | 388 | return num > 0; |
342 | } | 389 | } |
343 | 390 | ||
344 | static inline size_t | 391 | static inline void |
345 | header_size(void) | 392 | add_credits(struct TCP_Server_Info *server, const unsigned int add) |
346 | { | 393 | { |
347 | return sizeof(struct smb_hdr); | 394 | server->ops->add_credits(server, add); |
348 | } | 395 | } |
349 | 396 | ||
350 | static inline size_t | 397 | static inline void |
351 | max_header_size(void) | 398 | set_credits(struct TCP_Server_Info *server, const int val) |
352 | { | 399 | { |
353 | return MAX_CIFS_HDR_SIZE; | 400 | server->ops->set_credits(server, val); |
401 | } | ||
402 | |||
403 | static inline __u64 | ||
404 | get_next_mid(struct TCP_Server_Info *server) | ||
405 | { | ||
406 | return server->ops->get_next_mid(server); | ||
354 | } | 407 | } |
355 | 408 | ||
356 | /* | 409 | /* |
@@ -547,8 +600,7 @@ struct cifsLockInfo { | |||
547 | __u64 offset; | 600 | __u64 offset; |
548 | __u64 length; | 601 | __u64 length; |
549 | __u32 pid; | 602 | __u32 pid; |
550 | __u8 type; | 603 | __u32 type; |
551 | __u16 netfid; | ||
552 | }; | 604 | }; |
553 | 605 | ||
554 | /* | 606 | /* |
@@ -573,6 +625,10 @@ struct cifs_search_info { | |||
573 | struct cifsFileInfo { | 625 | struct cifsFileInfo { |
574 | struct list_head tlist; /* pointer to next fid owned by tcon */ | 626 | struct list_head tlist; /* pointer to next fid owned by tcon */ |
575 | struct list_head flist; /* next fid (file instance) for this inode */ | 627 | struct list_head flist; /* next fid (file instance) for this inode */ |
628 | struct list_head llist; /* | ||
629 | * brlocks held by this fid, protected by | ||
630 | * lock_mutex from cifsInodeInfo structure | ||
631 | */ | ||
576 | unsigned int uid; /* allows finding which FileInfo structure */ | 632 | unsigned int uid; /* allows finding which FileInfo structure */ |
577 | __u32 pid; /* process id who opened file */ | 633 | __u32 pid; /* process id who opened file */ |
578 | __u16 netfid; /* file id from remote */ | 634 | __u16 netfid; /* file id from remote */ |
@@ -615,9 +671,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); | |||
615 | */ | 671 | */ |
616 | 672 | ||
617 | struct cifsInodeInfo { | 673 | struct cifsInodeInfo { |
618 | struct list_head llist; /* brlocks for this inode */ | ||
619 | bool can_cache_brlcks; | 674 | bool can_cache_brlcks; |
620 | struct mutex lock_mutex; /* protect two fields above */ | 675 | struct mutex lock_mutex; /* |
676 | * protect the field above and llist | ||
677 | * from every cifsFileInfo structure | ||
678 | * from openFileList | ||
679 | */ | ||
621 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ | 680 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ |
622 | struct list_head openFileList; | 681 | struct list_head openFileList; |
623 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 682 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
@@ -703,7 +762,6 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon, | |||
703 | 762 | ||
704 | #endif | 763 | #endif |
705 | 764 | ||
706 | struct mid_q_entry; | ||
707 | 765 | ||
708 | /* | 766 | /* |
709 | * This is the prototype for the mid receive function. This function is for | 767 | * This is the prototype for the mid receive function. This function is for |
@@ -1042,12 +1100,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount; | |||
1042 | GLOBAL_EXTERN atomic_t midCount; | 1100 | GLOBAL_EXTERN atomic_t midCount; |
1043 | 1101 | ||
1044 | /* Misc globals */ | 1102 | /* Misc globals */ |
1045 | GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions | 1103 | GLOBAL_EXTERN bool enable_oplocks; /* enable or disable oplocks */ |
1046 | to be established on existing mount if we | ||
1047 | have the uid/password or Kerberos credential | ||
1048 | or equivalent for current user */ | ||
1049 | /* enable or disable oplocks */ | ||
1050 | GLOBAL_EXTERN bool enable_oplocks; | ||
1051 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; | 1104 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; |
1052 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent | 1105 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent |
1053 | with more secure ntlmssp2 challenge/resp */ | 1106 | with more secure ntlmssp2 challenge/resp */ |
@@ -1074,4 +1127,11 @@ void cifs_oplock_break(struct work_struct *work); | |||
1074 | extern const struct slow_work_ops cifs_oplock_break_ops; | 1127 | extern const struct slow_work_ops cifs_oplock_break_ops; |
1075 | extern struct workqueue_struct *cifsiod_wq; | 1128 | extern struct workqueue_struct *cifsiod_wq; |
1076 | 1129 | ||
1130 | /* Operations for different SMB versions */ | ||
1131 | #define SMB1_VERSION_STRING "1.0" | ||
1132 | extern struct smb_version_operations smb1_operations; | ||
1133 | extern struct smb_version_values smb1_values; | ||
1134 | #define SMB21_VERSION_STRING "2.1" | ||
1135 | extern struct smb_version_operations smb21_operations; | ||
1136 | extern struct smb_version_values smb21_values; | ||
1077 | #endif /* _CIFS_GLOB_H */ | 1137 | #endif /* _CIFS_GLOB_H */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 96192c1e380a..0a6cbfe2761e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -78,6 +78,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, | |||
78 | int * /* bytes returned */ , const int long_op); | 78 | int * /* bytes returned */ , const int long_op); |
79 | extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, | 79 | extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, |
80 | char *in_buf, int flags); | 80 | char *in_buf, int flags); |
81 | extern int cifs_setup_request(struct cifs_ses *, struct kvec *, unsigned int, | ||
82 | struct mid_q_entry **); | ||
81 | extern int cifs_check_receive(struct mid_q_entry *mid, | 83 | extern int cifs_check_receive(struct mid_q_entry *mid, |
82 | struct TCP_Server_Info *server, bool log_error); | 84 | struct TCP_Server_Info *server, bool log_error); |
83 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, | 85 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, |
@@ -88,9 +90,6 @@ extern int SendReceiveBlockingLock(const unsigned int xid, | |||
88 | struct smb_hdr *in_buf , | 90 | struct smb_hdr *in_buf , |
89 | struct smb_hdr *out_buf, | 91 | struct smb_hdr *out_buf, |
90 | int *bytes_returned); | 92 | int *bytes_returned); |
91 | extern void cifs_add_credits(struct TCP_Server_Info *server, | ||
92 | const unsigned int add); | ||
93 | extern void cifs_set_credits(struct TCP_Server_Info *server, const int val); | ||
94 | extern int checkSMB(char *buf, unsigned int length); | 93 | extern int checkSMB(char *buf, unsigned int length); |
95 | extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); | 94 | extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *); |
96 | extern bool backup_cred(struct cifs_sb_info *); | 95 | extern bool backup_cred(struct cifs_sb_info *); |
@@ -115,7 +114,6 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, | |||
115 | void **request_buf); | 114 | void **request_buf); |
116 | extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses, | 115 | extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses, |
117 | const struct nls_table *nls_cp); | 116 | const struct nls_table *nls_cp); |
118 | extern __u64 GetNextMid(struct TCP_Server_Info *server); | ||
119 | extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); | 117 | extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); |
120 | extern u64 cifs_UnixTimeToNT(struct timespec); | 118 | extern u64 cifs_UnixTimeToNT(struct timespec); |
121 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | 119 | extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, |
@@ -192,11 +190,13 @@ extern int CIFSTCon(unsigned int xid, struct cifs_ses *ses, | |||
192 | 190 | ||
193 | extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, | 191 | extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, |
194 | const char *searchName, const struct nls_table *nls_codepage, | 192 | const char *searchName, const struct nls_table *nls_codepage, |
195 | __u16 *searchHandle, struct cifs_search_info *psrch_inf, | 193 | __u16 *searchHandle, __u16 search_flags, |
194 | struct cifs_search_info *psrch_inf, | ||
196 | int map, const char dirsep); | 195 | int map, const char dirsep); |
197 | 196 | ||
198 | extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon, | 197 | extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon, |
199 | __u16 searchHandle, struct cifs_search_info *psrch_inf); | 198 | __u16 searchHandle, __u16 search_flags, |
199 | struct cifs_search_info *psrch_inf); | ||
200 | 200 | ||
201 | extern int CIFSFindClose(const int, struct cifs_tcon *tcon, | 201 | extern int CIFSFindClose(const int, struct cifs_tcon *tcon, |
202 | const __u16 search_handle); | 202 | const __u16 search_handle); |
@@ -464,6 +464,9 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, | |||
464 | 464 | ||
465 | /* asynchronous read support */ | 465 | /* asynchronous read support */ |
466 | struct cifs_readdata { | 466 | struct cifs_readdata { |
467 | struct kref refcount; | ||
468 | struct list_head list; | ||
469 | struct completion done; | ||
467 | struct cifsFileInfo *cfile; | 470 | struct cifsFileInfo *cfile; |
468 | struct address_space *mapping; | 471 | struct address_space *mapping; |
469 | __u64 offset; | 472 | __u64 offset; |
@@ -472,12 +475,13 @@ struct cifs_readdata { | |||
472 | int result; | 475 | int result; |
473 | struct list_head pages; | 476 | struct list_head pages; |
474 | struct work_struct work; | 477 | struct work_struct work; |
478 | int (*marshal_iov) (struct cifs_readdata *rdata, | ||
479 | unsigned int remaining); | ||
475 | unsigned int nr_iov; | 480 | unsigned int nr_iov; |
476 | struct kvec iov[1]; | 481 | struct kvec iov[1]; |
477 | }; | 482 | }; |
478 | 483 | ||
479 | struct cifs_readdata *cifs_readdata_alloc(unsigned int nr_pages); | 484 | void cifs_readdata_release(struct kref *refcount); |
480 | void cifs_readdata_free(struct cifs_readdata *rdata); | ||
481 | int cifs_async_readv(struct cifs_readdata *rdata); | 485 | int cifs_async_readv(struct cifs_readdata *rdata); |
482 | 486 | ||
483 | /* asynchronous write support */ | 487 | /* asynchronous write support */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index da2f5446fa7a..5b400730c213 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -87,7 +87,6 @@ static struct { | |||
87 | #endif /* CIFS_POSIX */ | 87 | #endif /* CIFS_POSIX */ |
88 | 88 | ||
89 | /* Forward declarations */ | 89 | /* Forward declarations */ |
90 | static void cifs_readv_complete(struct work_struct *work); | ||
91 | 90 | ||
92 | /* Mark as invalid, all open files on tree connections since they | 91 | /* Mark as invalid, all open files on tree connections since they |
93 | were closed when session to server was lost */ | 92 | were closed when session to server was lost */ |
@@ -269,7 +268,7 @@ small_smb_init_no_tc(const int smb_command, const int wct, | |||
269 | return rc; | 268 | return rc; |
270 | 269 | ||
271 | buffer = (struct smb_hdr *)*request_buf; | 270 | buffer = (struct smb_hdr *)*request_buf; |
272 | buffer->Mid = GetNextMid(ses->server); | 271 | buffer->Mid = get_next_mid(ses->server); |
273 | if (ses->capabilities & CAP_UNICODE) | 272 | if (ses->capabilities & CAP_UNICODE) |
274 | buffer->Flags2 |= SMBFLG2_UNICODE; | 273 | buffer->Flags2 |= SMBFLG2_UNICODE; |
275 | if (ses->capabilities & CAP_STATUS32) | 274 | if (ses->capabilities & CAP_STATUS32) |
@@ -403,7 +402,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) | |||
403 | 402 | ||
404 | cFYI(1, "secFlags 0x%x", secFlags); | 403 | cFYI(1, "secFlags 0x%x", secFlags); |
405 | 404 | ||
406 | pSMB->hdr.Mid = GetNextMid(server); | 405 | pSMB->hdr.Mid = get_next_mid(server); |
407 | pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); | 406 | pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); |
408 | 407 | ||
409 | if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) | 408 | if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) |
@@ -461,7 +460,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) | |||
461 | server->maxReq = min_t(unsigned int, | 460 | server->maxReq = min_t(unsigned int, |
462 | le16_to_cpu(rsp->MaxMpxCount), | 461 | le16_to_cpu(rsp->MaxMpxCount), |
463 | cifs_max_pending); | 462 | cifs_max_pending); |
464 | cifs_set_credits(server, server->maxReq); | 463 | set_credits(server, server->maxReq); |
465 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | 464 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); |
466 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | 465 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); |
467 | /* even though we do not use raw we might as well set this | 466 | /* even though we do not use raw we might as well set this |
@@ -569,7 +568,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) | |||
569 | little endian */ | 568 | little endian */ |
570 | server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), | 569 | server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), |
571 | cifs_max_pending); | 570 | cifs_max_pending); |
572 | cifs_set_credits(server, server->maxReq); | 571 | set_credits(server, server->maxReq); |
573 | /* probably no need to store and check maxvcs */ | 572 | /* probably no need to store and check maxvcs */ |
574 | server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); | 573 | server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); |
575 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 574 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
@@ -721,7 +720,7 @@ cifs_echo_callback(struct mid_q_entry *mid) | |||
721 | struct TCP_Server_Info *server = mid->callback_data; | 720 | struct TCP_Server_Info *server = mid->callback_data; |
722 | 721 | ||
723 | DeleteMidQEntry(mid); | 722 | DeleteMidQEntry(mid); |
724 | cifs_add_credits(server, 1); | 723 | add_credits(server, 1); |
725 | } | 724 | } |
726 | 725 | ||
727 | int | 726 | int |
@@ -783,7 +782,7 @@ CIFSSMBLogoff(const int xid, struct cifs_ses *ses) | |||
783 | return rc; | 782 | return rc; |
784 | } | 783 | } |
785 | 784 | ||
786 | pSMB->hdr.Mid = GetNextMid(ses->server); | 785 | pSMB->hdr.Mid = get_next_mid(ses->server); |
787 | 786 | ||
788 | if (ses->server->sec_mode & | 787 | if (ses->server->sec_mode & |
789 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 788 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
@@ -1385,28 +1384,6 @@ openRetry: | |||
1385 | return rc; | 1384 | return rc; |
1386 | } | 1385 | } |
1387 | 1386 | ||
1388 | struct cifs_readdata * | ||
1389 | cifs_readdata_alloc(unsigned int nr_pages) | ||
1390 | { | ||
1391 | struct cifs_readdata *rdata; | ||
1392 | |||
1393 | /* readdata + 1 kvec for each page */ | ||
1394 | rdata = kzalloc(sizeof(*rdata) + | ||
1395 | sizeof(struct kvec) * nr_pages, GFP_KERNEL); | ||
1396 | if (rdata != NULL) { | ||
1397 | INIT_WORK(&rdata->work, cifs_readv_complete); | ||
1398 | INIT_LIST_HEAD(&rdata->pages); | ||
1399 | } | ||
1400 | return rdata; | ||
1401 | } | ||
1402 | |||
1403 | void | ||
1404 | cifs_readdata_free(struct cifs_readdata *rdata) | ||
1405 | { | ||
1406 | cifsFileInfo_put(rdata->cfile); | ||
1407 | kfree(rdata); | ||
1408 | } | ||
1409 | |||
1410 | /* | 1387 | /* |
1411 | * Discard any remaining data in the current SMB. To do this, we borrow the | 1388 | * Discard any remaining data in the current SMB. To do this, we borrow the |
1412 | * current bigbuf. | 1389 | * current bigbuf. |
@@ -1423,7 +1400,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1423 | 1400 | ||
1424 | length = cifs_read_from_socket(server, server->bigbuf, | 1401 | length = cifs_read_from_socket(server, server->bigbuf, |
1425 | min_t(unsigned int, remaining, | 1402 | min_t(unsigned int, remaining, |
1426 | CIFSMaxBufSize + max_header_size())); | 1403 | CIFSMaxBufSize + MAX_HEADER_SIZE(server))); |
1427 | if (length < 0) | 1404 | if (length < 0) |
1428 | return length; | 1405 | return length; |
1429 | server->total_read += length; | 1406 | server->total_read += length; |
@@ -1434,38 +1411,14 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1434 | return 0; | 1411 | return 0; |
1435 | } | 1412 | } |
1436 | 1413 | ||
1437 | static inline size_t | ||
1438 | read_rsp_size(void) | ||
1439 | { | ||
1440 | return sizeof(READ_RSP); | ||
1441 | } | ||
1442 | |||
1443 | static inline unsigned int | ||
1444 | read_data_offset(char *buf) | ||
1445 | { | ||
1446 | READ_RSP *rsp = (READ_RSP *)buf; | ||
1447 | return le16_to_cpu(rsp->DataOffset); | ||
1448 | } | ||
1449 | |||
1450 | static inline unsigned int | ||
1451 | read_data_length(char *buf) | ||
1452 | { | ||
1453 | READ_RSP *rsp = (READ_RSP *)buf; | ||
1454 | return (le16_to_cpu(rsp->DataLengthHigh) << 16) + | ||
1455 | le16_to_cpu(rsp->DataLength); | ||
1456 | } | ||
1457 | |||
1458 | static int | 1414 | static int |
1459 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | 1415 | cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) |
1460 | { | 1416 | { |
1461 | int length, len; | 1417 | int length, len; |
1462 | unsigned int data_offset, remaining, data_len; | 1418 | unsigned int data_offset, data_len; |
1463 | struct cifs_readdata *rdata = mid->callback_data; | 1419 | struct cifs_readdata *rdata = mid->callback_data; |
1464 | char *buf = server->smallbuf; | 1420 | char *buf = server->smallbuf; |
1465 | unsigned int buflen = get_rfc1002_length(buf) + 4; | 1421 | unsigned int buflen = get_rfc1002_length(buf) + 4; |
1466 | u64 eof; | ||
1467 | pgoff_t eof_index; | ||
1468 | struct page *page, *tpage; | ||
1469 | 1422 | ||
1470 | cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__, | 1423 | cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__, |
1471 | mid->mid, rdata->offset, rdata->bytes); | 1424 | mid->mid, rdata->offset, rdata->bytes); |
@@ -1475,9 +1428,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1475 | * can if there's not enough data. At this point, we've read down to | 1428 | * can if there's not enough data. At this point, we've read down to |
1476 | * the Mid. | 1429 | * the Mid. |
1477 | */ | 1430 | */ |
1478 | len = min_t(unsigned int, buflen, read_rsp_size()) - header_size() + 1; | 1431 | len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - |
1432 | HEADER_SIZE(server) + 1; | ||
1479 | 1433 | ||
1480 | rdata->iov[0].iov_base = buf + header_size() - 1; | 1434 | rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1; |
1481 | rdata->iov[0].iov_len = len; | 1435 | rdata->iov[0].iov_len = len; |
1482 | 1436 | ||
1483 | length = cifs_readv_from_socket(server, rdata->iov, 1, len); | 1437 | length = cifs_readv_from_socket(server, rdata->iov, 1, len); |
@@ -1486,7 +1440,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1486 | server->total_read += length; | 1440 | server->total_read += length; |
1487 | 1441 | ||
1488 | /* Was the SMB read successful? */ | 1442 | /* Was the SMB read successful? */ |
1489 | rdata->result = map_smb_to_linux_error(buf, false); | 1443 | rdata->result = server->ops->map_error(buf, false); |
1490 | if (rdata->result != 0) { | 1444 | if (rdata->result != 0) { |
1491 | cFYI(1, "%s: server returned error %d", __func__, | 1445 | cFYI(1, "%s: server returned error %d", __func__, |
1492 | rdata->result); | 1446 | rdata->result); |
@@ -1494,14 +1448,15 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1494 | } | 1448 | } |
1495 | 1449 | ||
1496 | /* Is there enough to get to the rest of the READ_RSP header? */ | 1450 | /* Is there enough to get to the rest of the READ_RSP header? */ |
1497 | if (server->total_read < read_rsp_size()) { | 1451 | if (server->total_read < server->vals->read_rsp_size) { |
1498 | cFYI(1, "%s: server returned short header. got=%u expected=%zu", | 1452 | cFYI(1, "%s: server returned short header. got=%u expected=%zu", |
1499 | __func__, server->total_read, read_rsp_size()); | 1453 | __func__, server->total_read, |
1454 | server->vals->read_rsp_size); | ||
1500 | rdata->result = -EIO; | 1455 | rdata->result = -EIO; |
1501 | return cifs_readv_discard(server, mid); | 1456 | return cifs_readv_discard(server, mid); |
1502 | } | 1457 | } |
1503 | 1458 | ||
1504 | data_offset = read_data_offset(buf) + 4; | 1459 | data_offset = server->ops->read_data_offset(buf) + 4; |
1505 | if (data_offset < server->total_read) { | 1460 | if (data_offset < server->total_read) { |
1506 | /* | 1461 | /* |
1507 | * win2k8 sometimes sends an offset of 0 when the read | 1462 | * win2k8 sometimes sends an offset of 0 when the read |
@@ -1540,7 +1495,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1540 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); | 1495 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); |
1541 | 1496 | ||
1542 | /* how much data is in the response? */ | 1497 | /* how much data is in the response? */ |
1543 | data_len = read_data_length(buf); | 1498 | data_len = server->ops->read_data_length(buf); |
1544 | if (data_offset + data_len > buflen) { | 1499 | if (data_offset + data_len > buflen) { |
1545 | /* data_len is corrupt -- discard frame */ | 1500 | /* data_len is corrupt -- discard frame */ |
1546 | rdata->result = -EIO; | 1501 | rdata->result = -EIO; |
@@ -1548,64 +1503,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1548 | } | 1503 | } |
1549 | 1504 | ||
1550 | /* marshal up the page array */ | 1505 | /* marshal up the page array */ |
1551 | len = 0; | 1506 | len = rdata->marshal_iov(rdata, data_len); |
1552 | remaining = data_len; | 1507 | data_len -= len; |
1553 | rdata->nr_iov = 1; | ||
1554 | |||
1555 | /* determine the eof that the server (probably) has */ | ||
1556 | eof = CIFS_I(rdata->mapping->host)->server_eof; | ||
1557 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; | ||
1558 | cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index); | ||
1559 | |||
1560 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
1561 | if (remaining >= PAGE_CACHE_SIZE) { | ||
1562 | /* enough data to fill the page */ | ||
1563 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
1564 | rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE; | ||
1565 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
1566 | rdata->nr_iov, page->index, | ||
1567 | rdata->iov[rdata->nr_iov].iov_base, | ||
1568 | rdata->iov[rdata->nr_iov].iov_len); | ||
1569 | ++rdata->nr_iov; | ||
1570 | len += PAGE_CACHE_SIZE; | ||
1571 | remaining -= PAGE_CACHE_SIZE; | ||
1572 | } else if (remaining > 0) { | ||
1573 | /* enough for partial page, fill and zero the rest */ | ||
1574 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
1575 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
1576 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
1577 | rdata->nr_iov, page->index, | ||
1578 | rdata->iov[rdata->nr_iov].iov_base, | ||
1579 | rdata->iov[rdata->nr_iov].iov_len); | ||
1580 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
1581 | '\0', PAGE_CACHE_SIZE - remaining); | ||
1582 | ++rdata->nr_iov; | ||
1583 | len += remaining; | ||
1584 | remaining = 0; | ||
1585 | } else if (page->index > eof_index) { | ||
1586 | /* | ||
1587 | * The VFS will not try to do readahead past the | ||
1588 | * i_size, but it's possible that we have outstanding | ||
1589 | * writes with gaps in the middle and the i_size hasn't | ||
1590 | * caught up yet. Populate those with zeroed out pages | ||
1591 | * to prevent the VFS from repeatedly attempting to | ||
1592 | * fill them until the writes are flushed. | ||
1593 | */ | ||
1594 | zero_user(page, 0, PAGE_CACHE_SIZE); | ||
1595 | list_del(&page->lru); | ||
1596 | lru_cache_add_file(page); | ||
1597 | flush_dcache_page(page); | ||
1598 | SetPageUptodate(page); | ||
1599 | unlock_page(page); | ||
1600 | page_cache_release(page); | ||
1601 | } else { | ||
1602 | /* no need to hold page hostage */ | ||
1603 | list_del(&page->lru); | ||
1604 | lru_cache_add_file(page); | ||
1605 | unlock_page(page); | ||
1606 | page_cache_release(page); | ||
1607 | } | ||
1608 | } | ||
1609 | 1508 | ||
1610 | /* issue the read if we have any iovecs left to fill */ | 1509 | /* issue the read if we have any iovecs left to fill */ |
1611 | if (rdata->nr_iov > 1) { | 1510 | if (rdata->nr_iov > 1) { |
@@ -1621,7 +1520,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1621 | rdata->bytes = length; | 1520 | rdata->bytes = length; |
1622 | 1521 | ||
1623 | cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read, | 1522 | cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read, |
1624 | buflen, remaining); | 1523 | buflen, data_len); |
1625 | 1524 | ||
1626 | /* discard anything left over */ | 1525 | /* discard anything left over */ |
1627 | if (server->total_read < buflen) | 1526 | if (server->total_read < buflen) |
@@ -1632,33 +1531,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1632 | } | 1531 | } |
1633 | 1532 | ||
1634 | static void | 1533 | static void |
1635 | cifs_readv_complete(struct work_struct *work) | ||
1636 | { | ||
1637 | struct cifs_readdata *rdata = container_of(work, | ||
1638 | struct cifs_readdata, work); | ||
1639 | struct page *page, *tpage; | ||
1640 | |||
1641 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
1642 | list_del(&page->lru); | ||
1643 | lru_cache_add_file(page); | ||
1644 | |||
1645 | if (rdata->result == 0) { | ||
1646 | kunmap(page); | ||
1647 | flush_dcache_page(page); | ||
1648 | SetPageUptodate(page); | ||
1649 | } | ||
1650 | |||
1651 | unlock_page(page); | ||
1652 | |||
1653 | if (rdata->result == 0) | ||
1654 | cifs_readpage_to_fscache(rdata->mapping->host, page); | ||
1655 | |||
1656 | page_cache_release(page); | ||
1657 | } | ||
1658 | cifs_readdata_free(rdata); | ||
1659 | } | ||
1660 | |||
1661 | static void | ||
1662 | cifs_readv_callback(struct mid_q_entry *mid) | 1534 | cifs_readv_callback(struct mid_q_entry *mid) |
1663 | { | 1535 | { |
1664 | struct cifs_readdata *rdata = mid->callback_data; | 1536 | struct cifs_readdata *rdata = mid->callback_data; |
@@ -1691,7 +1563,7 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
1691 | 1563 | ||
1692 | queue_work(cifsiod_wq, &rdata->work); | 1564 | queue_work(cifsiod_wq, &rdata->work); |
1693 | DeleteMidQEntry(mid); | 1565 | DeleteMidQEntry(mid); |
1694 | cifs_add_credits(server, 1); | 1566 | add_credits(server, 1); |
1695 | } | 1567 | } |
1696 | 1568 | ||
1697 | /* cifs_async_readv - send an async write, and set up mid to handle result */ | 1569 | /* cifs_async_readv - send an async write, and set up mid to handle result */ |
@@ -1744,12 +1616,15 @@ cifs_async_readv(struct cifs_readdata *rdata) | |||
1744 | rdata->iov[0].iov_base = smb; | 1616 | rdata->iov[0].iov_base = smb; |
1745 | rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; | 1617 | rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; |
1746 | 1618 | ||
1619 | kref_get(&rdata->refcount); | ||
1747 | rc = cifs_call_async(tcon->ses->server, rdata->iov, 1, | 1620 | rc = cifs_call_async(tcon->ses->server, rdata->iov, 1, |
1748 | cifs_readv_receive, cifs_readv_callback, | 1621 | cifs_readv_receive, cifs_readv_callback, |
1749 | rdata, false); | 1622 | rdata, false); |
1750 | 1623 | ||
1751 | if (rc == 0) | 1624 | if (rc == 0) |
1752 | cifs_stats_inc(&tcon->num_reads); | 1625 | cifs_stats_inc(&tcon->num_reads); |
1626 | else | ||
1627 | kref_put(&rdata->refcount, cifs_readdata_release); | ||
1753 | 1628 | ||
1754 | cifs_small_buf_release(smb); | 1629 | cifs_small_buf_release(smb); |
1755 | return rc; | 1630 | return rc; |
@@ -2135,7 +2010,7 @@ cifs_writev_callback(struct mid_q_entry *mid) | |||
2135 | 2010 | ||
2136 | queue_work(cifsiod_wq, &wdata->work); | 2011 | queue_work(cifsiod_wq, &wdata->work); |
2137 | DeleteMidQEntry(mid); | 2012 | DeleteMidQEntry(mid); |
2138 | cifs_add_credits(tcon->ses->server, 1); | 2013 | add_credits(tcon->ses->server, 1); |
2139 | } | 2014 | } |
2140 | 2015 | ||
2141 | /* cifs_async_writev - send an async write, and set up mid to handle result */ | 2016 | /* cifs_async_writev - send an async write, and set up mid to handle result */ |
@@ -4344,7 +4219,7 @@ int | |||
4344 | CIFSFindFirst(const int xid, struct cifs_tcon *tcon, | 4219 | CIFSFindFirst(const int xid, struct cifs_tcon *tcon, |
4345 | const char *searchName, | 4220 | const char *searchName, |
4346 | const struct nls_table *nls_codepage, | 4221 | const struct nls_table *nls_codepage, |
4347 | __u16 *pnetfid, | 4222 | __u16 *pnetfid, __u16 search_flags, |
4348 | struct cifs_search_info *psrch_inf, int remap, const char dirsep) | 4223 | struct cifs_search_info *psrch_inf, int remap, const char dirsep) |
4349 | { | 4224 | { |
4350 | /* level 257 SMB_ */ | 4225 | /* level 257 SMB_ */ |
@@ -4416,8 +4291,7 @@ findFirstRetry: | |||
4416 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | | 4291 | cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | |
4417 | ATTR_DIRECTORY); | 4292 | ATTR_DIRECTORY); |
4418 | pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); | 4293 | pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); |
4419 | pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | | 4294 | pSMB->SearchFlags = cpu_to_le16(search_flags); |
4420 | CIFS_SEARCH_RETURN_RESUME); | ||
4421 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); | 4295 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); |
4422 | 4296 | ||
4423 | /* BB what should we set StorageType to? Does it matter? BB */ | 4297 | /* BB what should we set StorageType to? Does it matter? BB */ |
@@ -4487,8 +4361,8 @@ findFirstRetry: | |||
4487 | return rc; | 4361 | return rc; |
4488 | } | 4362 | } |
4489 | 4363 | ||
4490 | int CIFSFindNext(const int xid, struct cifs_tcon *tcon, | 4364 | int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle, |
4491 | __u16 searchHandle, struct cifs_search_info *psrch_inf) | 4365 | __u16 search_flags, struct cifs_search_info *psrch_inf) |
4492 | { | 4366 | { |
4493 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; | 4367 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; |
4494 | TRANSACTION2_FNEXT_RSP *pSMBr = NULL; | 4368 | TRANSACTION2_FNEXT_RSP *pSMBr = NULL; |
@@ -4531,8 +4405,7 @@ int CIFSFindNext(const int xid, struct cifs_tcon *tcon, | |||
4531 | cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO)); | 4405 | cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO)); |
4532 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); | 4406 | pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); |
4533 | pSMB->ResumeKey = psrch_inf->resume_key; | 4407 | pSMB->ResumeKey = psrch_inf->resume_key; |
4534 | pSMB->SearchFlags = | 4408 | pSMB->SearchFlags = cpu_to_le16(search_flags); |
4535 | cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); | ||
4536 | 4409 | ||
4537 | name_len = psrch_inf->resume_name_len; | 4410 | name_len = psrch_inf->resume_name_len; |
4538 | params += name_len; | 4411 | params += name_len; |
@@ -4889,7 +4762,7 @@ getDFSRetry: | |||
4889 | 4762 | ||
4890 | /* server pointer checked in called function, | 4763 | /* server pointer checked in called function, |
4891 | but should never be null here anyway */ | 4764 | but should never be null here anyway */ |
4892 | pSMB->hdr.Mid = GetNextMid(ses->server); | 4765 | pSMB->hdr.Mid = get_next_mid(ses->server); |
4893 | pSMB->hdr.Tid = ses->ipc_tid; | 4766 | pSMB->hdr.Tid = ses->ipc_tid; |
4894 | pSMB->hdr.Uid = ses->Suid; | 4767 | pSMB->hdr.Uid = ses->Suid; |
4895 | if (ses->capabilities & CAP_STATUS32) | 4768 | if (ses->capabilities & CAP_STATUS32) |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e0b56d7a19c5..78db68a5cf44 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/connect.c | 2 | * fs/cifs/connect.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2009 | 4 | * Copyright (C) International Business Machines Corp., 2002,2011 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -102,7 +102,7 @@ enum { | |||
102 | Opt_srcaddr, Opt_prefixpath, | 102 | Opt_srcaddr, Opt_prefixpath, |
103 | Opt_iocharset, Opt_sockopt, | 103 | Opt_iocharset, Opt_sockopt, |
104 | Opt_netbiosname, Opt_servern, | 104 | Opt_netbiosname, Opt_servern, |
105 | Opt_ver, Opt_sec, | 105 | Opt_ver, Opt_vers, Opt_sec, Opt_cache, |
106 | 106 | ||
107 | /* Mount options to be ignored */ | 107 | /* Mount options to be ignored */ |
108 | Opt_ignore, | 108 | Opt_ignore, |
@@ -210,9 +210,9 @@ static const match_table_t cifs_mount_option_tokens = { | |||
210 | { Opt_netbiosname, "netbiosname=%s" }, | 210 | { Opt_netbiosname, "netbiosname=%s" }, |
211 | { Opt_servern, "servern=%s" }, | 211 | { Opt_servern, "servern=%s" }, |
212 | { Opt_ver, "ver=%s" }, | 212 | { Opt_ver, "ver=%s" }, |
213 | { Opt_ver, "vers=%s" }, | 213 | { Opt_vers, "vers=%s" }, |
214 | { Opt_ver, "version=%s" }, | ||
215 | { Opt_sec, "sec=%s" }, | 214 | { Opt_sec, "sec=%s" }, |
215 | { Opt_cache, "cache=%s" }, | ||
216 | 216 | ||
217 | { Opt_ignore, "cred" }, | 217 | { Opt_ignore, "cred" }, |
218 | { Opt_ignore, "credentials" }, | 218 | { Opt_ignore, "credentials" }, |
@@ -261,6 +261,26 @@ static const match_table_t cifs_secflavor_tokens = { | |||
261 | { Opt_sec_err, NULL } | 261 | { Opt_sec_err, NULL } |
262 | }; | 262 | }; |
263 | 263 | ||
264 | /* cache flavors */ | ||
265 | enum { | ||
266 | Opt_cache_loose, | ||
267 | Opt_cache_strict, | ||
268 | Opt_cache_none, | ||
269 | Opt_cache_err | ||
270 | }; | ||
271 | |||
272 | static const match_table_t cifs_cacheflavor_tokens = { | ||
273 | { Opt_cache_loose, "loose" }, | ||
274 | { Opt_cache_strict, "strict" }, | ||
275 | { Opt_cache_none, "none" }, | ||
276 | { Opt_cache_err, NULL } | ||
277 | }; | ||
278 | |||
279 | static const match_table_t cifs_smb_version_tokens = { | ||
280 | { Smb_1, SMB1_VERSION_STRING }, | ||
281 | { Smb_21, SMB21_VERSION_STRING }, | ||
282 | }; | ||
283 | |||
264 | static int ip_connect(struct TCP_Server_Info *server); | 284 | static int ip_connect(struct TCP_Server_Info *server); |
265 | static int generic_ip_connect(struct TCP_Server_Info *server); | 285 | static int generic_ip_connect(struct TCP_Server_Info *server); |
266 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | 286 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
@@ -549,7 +569,7 @@ allocate_buffers(struct TCP_Server_Info *server) | |||
549 | } | 569 | } |
550 | } else if (server->large_buf) { | 570 | } else if (server->large_buf) { |
551 | /* we are reusing a dirty large buf, clear its start */ | 571 | /* we are reusing a dirty large buf, clear its start */ |
552 | memset(server->bigbuf, 0, header_size()); | 572 | memset(server->bigbuf, 0, HEADER_SIZE(server)); |
553 | } | 573 | } |
554 | 574 | ||
555 | if (!server->smallbuf) { | 575 | if (!server->smallbuf) { |
@@ -563,7 +583,7 @@ allocate_buffers(struct TCP_Server_Info *server) | |||
563 | /* beginning of smb buffer is cleared in our buf_get */ | 583 | /* beginning of smb buffer is cleared in our buf_get */ |
564 | } else { | 584 | } else { |
565 | /* if existing small buf clear beginning */ | 585 | /* if existing small buf clear beginning */ |
566 | memset(server->smallbuf, 0, header_size()); | 586 | memset(server->smallbuf, 0, HEADER_SIZE(server)); |
567 | } | 587 | } |
568 | 588 | ||
569 | return true; | 589 | return true; |
@@ -764,25 +784,6 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type) | |||
764 | return false; | 784 | return false; |
765 | } | 785 | } |
766 | 786 | ||
767 | static struct mid_q_entry * | ||
768 | find_mid(struct TCP_Server_Info *server, char *buffer) | ||
769 | { | ||
770 | struct smb_hdr *buf = (struct smb_hdr *)buffer; | ||
771 | struct mid_q_entry *mid; | ||
772 | |||
773 | spin_lock(&GlobalMid_Lock); | ||
774 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { | ||
775 | if (mid->mid == buf->Mid && | ||
776 | mid->mid_state == MID_REQUEST_SUBMITTED && | ||
777 | le16_to_cpu(mid->command) == buf->Command) { | ||
778 | spin_unlock(&GlobalMid_Lock); | ||
779 | return mid; | ||
780 | } | ||
781 | } | ||
782 | spin_unlock(&GlobalMid_Lock); | ||
783 | return NULL; | ||
784 | } | ||
785 | |||
786 | void | 787 | void |
787 | dequeue_mid(struct mid_q_entry *mid, bool malformed) | 788 | dequeue_mid(struct mid_q_entry *mid, bool malformed) |
788 | { | 789 | { |
@@ -934,7 +935,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
934 | unsigned int pdu_length = get_rfc1002_length(buf); | 935 | unsigned int pdu_length = get_rfc1002_length(buf); |
935 | 936 | ||
936 | /* make sure this will fit in a large buffer */ | 937 | /* make sure this will fit in a large buffer */ |
937 | if (pdu_length > CIFSMaxBufSize + max_header_size() - 4) { | 938 | if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) - 4) { |
938 | cERROR(1, "SMB response too long (%u bytes)", | 939 | cERROR(1, "SMB response too long (%u bytes)", |
939 | pdu_length); | 940 | pdu_length); |
940 | cifs_reconnect(server); | 941 | cifs_reconnect(server); |
@@ -950,8 +951,8 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
950 | } | 951 | } |
951 | 952 | ||
952 | /* now read the rest */ | 953 | /* now read the rest */ |
953 | length = cifs_read_from_socket(server, buf + header_size() - 1, | 954 | length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, |
954 | pdu_length - header_size() + 1 + 4); | 955 | pdu_length - HEADER_SIZE(server) + 1 + 4); |
955 | if (length < 0) | 956 | if (length < 0) |
956 | return length; | 957 | return length; |
957 | server->total_read += length; | 958 | server->total_read += length; |
@@ -967,7 +968,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
967 | * 48 bytes is enough to display the header and a little bit | 968 | * 48 bytes is enough to display the header and a little bit |
968 | * into the payload for debugging purposes. | 969 | * into the payload for debugging purposes. |
969 | */ | 970 | */ |
970 | length = checkSMB(buf, server->total_read); | 971 | length = server->ops->check_message(buf, server->total_read); |
971 | if (length != 0) | 972 | if (length != 0) |
972 | cifs_dump_mem("Bad SMB: ", buf, | 973 | cifs_dump_mem("Bad SMB: ", buf, |
973 | min_t(unsigned int, server->total_read, 48)); | 974 | min_t(unsigned int, server->total_read, 48)); |
@@ -1025,7 +1026,7 @@ cifs_demultiplex_thread(void *p) | |||
1025 | continue; | 1026 | continue; |
1026 | 1027 | ||
1027 | /* make sure we have enough to get to the MID */ | 1028 | /* make sure we have enough to get to the MID */ |
1028 | if (pdu_length < header_size() - 1 - 4) { | 1029 | if (pdu_length < HEADER_SIZE(server) - 1 - 4) { |
1029 | cERROR(1, "SMB response too short (%u bytes)", | 1030 | cERROR(1, "SMB response too short (%u bytes)", |
1030 | pdu_length); | 1031 | pdu_length); |
1031 | cifs_reconnect(server); | 1032 | cifs_reconnect(server); |
@@ -1035,12 +1036,12 @@ cifs_demultiplex_thread(void *p) | |||
1035 | 1036 | ||
1036 | /* read down to the MID */ | 1037 | /* read down to the MID */ |
1037 | length = cifs_read_from_socket(server, buf + 4, | 1038 | length = cifs_read_from_socket(server, buf + 4, |
1038 | header_size() - 1 - 4); | 1039 | HEADER_SIZE(server) - 1 - 4); |
1039 | if (length < 0) | 1040 | if (length < 0) |
1040 | continue; | 1041 | continue; |
1041 | server->total_read += length; | 1042 | server->total_read += length; |
1042 | 1043 | ||
1043 | mid_entry = find_mid(server, buf); | 1044 | mid_entry = server->ops->find_mid(server, buf); |
1044 | 1045 | ||
1045 | if (!mid_entry || !mid_entry->receive) | 1046 | if (!mid_entry || !mid_entry->receive) |
1046 | length = standard_receive3(server, mid_entry); | 1047 | length = standard_receive3(server, mid_entry); |
@@ -1057,12 +1058,15 @@ cifs_demultiplex_thread(void *p) | |||
1057 | if (mid_entry != NULL) { | 1058 | if (mid_entry != NULL) { |
1058 | if (!mid_entry->multiRsp || mid_entry->multiEnd) | 1059 | if (!mid_entry->multiRsp || mid_entry->multiEnd) |
1059 | mid_entry->callback(mid_entry); | 1060 | mid_entry->callback(mid_entry); |
1060 | } else if (!is_valid_oplock_break(buf, server)) { | 1061 | } else if (!server->ops->is_oplock_break || |
1062 | !server->ops->is_oplock_break(buf, server)) { | ||
1061 | cERROR(1, "No task to wake, unknown frame received! " | 1063 | cERROR(1, "No task to wake, unknown frame received! " |
1062 | "NumMids %d", atomic_read(&midCount)); | 1064 | "NumMids %d", atomic_read(&midCount)); |
1063 | cifs_dump_mem("Received Data is: ", buf, header_size()); | 1065 | cifs_dump_mem("Received Data is: ", buf, |
1066 | HEADER_SIZE(server)); | ||
1064 | #ifdef CONFIG_CIFS_DEBUG2 | 1067 | #ifdef CONFIG_CIFS_DEBUG2 |
1065 | cifs_dump_detail(buf); | 1068 | if (server->ops->dump_detail) |
1069 | server->ops->dump_detail(buf); | ||
1066 | cifs_dump_mids(server); | 1070 | cifs_dump_mids(server); |
1067 | #endif /* CIFS_DEBUG2 */ | 1071 | #endif /* CIFS_DEBUG2 */ |
1068 | 1072 | ||
@@ -1186,6 +1190,54 @@ static int cifs_parse_security_flavors(char *value, | |||
1186 | } | 1190 | } |
1187 | 1191 | ||
1188 | static int | 1192 | static int |
1193 | cifs_parse_cache_flavor(char *value, struct smb_vol *vol) | ||
1194 | { | ||
1195 | substring_t args[MAX_OPT_ARGS]; | ||
1196 | |||
1197 | switch (match_token(value, cifs_cacheflavor_tokens, args)) { | ||
1198 | case Opt_cache_loose: | ||
1199 | vol->direct_io = false; | ||
1200 | vol->strict_io = false; | ||
1201 | break; | ||
1202 | case Opt_cache_strict: | ||
1203 | vol->direct_io = false; | ||
1204 | vol->strict_io = true; | ||
1205 | break; | ||
1206 | case Opt_cache_none: | ||
1207 | vol->direct_io = true; | ||
1208 | vol->strict_io = false; | ||
1209 | break; | ||
1210 | default: | ||
1211 | cERROR(1, "bad cache= option: %s", value); | ||
1212 | return 1; | ||
1213 | } | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static int | ||
1218 | cifs_parse_smb_version(char *value, struct smb_vol *vol) | ||
1219 | { | ||
1220 | substring_t args[MAX_OPT_ARGS]; | ||
1221 | |||
1222 | switch (match_token(value, cifs_smb_version_tokens, args)) { | ||
1223 | case Smb_1: | ||
1224 | vol->ops = &smb1_operations; | ||
1225 | vol->vals = &smb1_values; | ||
1226 | break; | ||
1227 | #ifdef CONFIG_CIFS_SMB2 | ||
1228 | case Smb_21: | ||
1229 | vol->ops = &smb21_operations; | ||
1230 | vol->vals = &smb21_values; | ||
1231 | break; | ||
1232 | #endif | ||
1233 | default: | ||
1234 | cERROR(1, "Unknown vers= option specified: %s", value); | ||
1235 | return 1; | ||
1236 | } | ||
1237 | return 0; | ||
1238 | } | ||
1239 | |||
1240 | static int | ||
1189 | cifs_parse_mount_options(const char *mountdata, const char *devname, | 1241 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
1190 | struct smb_vol *vol) | 1242 | struct smb_vol *vol) |
1191 | { | 1243 | { |
@@ -1203,6 +1255,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1203 | char *string = NULL; | 1255 | char *string = NULL; |
1204 | char *tmp_end, *value; | 1256 | char *tmp_end, *value; |
1205 | char delim; | 1257 | char delim; |
1258 | bool cache_specified = false; | ||
1259 | static bool cache_warned = false; | ||
1206 | 1260 | ||
1207 | separator[0] = ','; | 1261 | separator[0] = ','; |
1208 | separator[1] = 0; | 1262 | separator[1] = 0; |
@@ -1236,6 +1290,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1236 | 1290 | ||
1237 | vol->actimeo = CIFS_DEF_ACTIMEO; | 1291 | vol->actimeo = CIFS_DEF_ACTIMEO; |
1238 | 1292 | ||
1293 | /* FIXME: add autonegotiation -- for now, SMB1 is default */ | ||
1294 | vol->ops = &smb1_operations; | ||
1295 | vol->vals = &smb1_values; | ||
1296 | |||
1239 | if (!mountdata) | 1297 | if (!mountdata) |
1240 | goto cifs_parse_mount_err; | 1298 | goto cifs_parse_mount_err; |
1241 | 1299 | ||
@@ -1414,10 +1472,20 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1414 | vol->seal = 1; | 1472 | vol->seal = 1; |
1415 | break; | 1473 | break; |
1416 | case Opt_direct: | 1474 | case Opt_direct: |
1417 | vol->direct_io = 1; | 1475 | cache_specified = true; |
1476 | vol->direct_io = true; | ||
1477 | vol->strict_io = false; | ||
1478 | cERROR(1, "The \"directio\" option will be removed in " | ||
1479 | "3.7. Please switch to the \"cache=none\" " | ||
1480 | "option."); | ||
1418 | break; | 1481 | break; |
1419 | case Opt_strictcache: | 1482 | case Opt_strictcache: |
1420 | vol->strict_io = 1; | 1483 | cache_specified = true; |
1484 | vol->direct_io = false; | ||
1485 | vol->strict_io = true; | ||
1486 | cERROR(1, "The \"strictcache\" option will be removed " | ||
1487 | "in 3.7. Please switch to the \"cache=strict\" " | ||
1488 | "option."); | ||
1421 | break; | 1489 | break; |
1422 | case Opt_noac: | 1490 | case Opt_noac: |
1423 | printk(KERN_WARNING "CIFS: Mount option noac not " | 1491 | printk(KERN_WARNING "CIFS: Mount option noac not " |
@@ -1821,8 +1889,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1821 | if (string == NULL) | 1889 | if (string == NULL) |
1822 | goto out_nomem; | 1890 | goto out_nomem; |
1823 | 1891 | ||
1824 | if (strnicmp(string, "cifs", 4) == 0 || | 1892 | if (strnicmp(string, "1", 1) == 0) { |
1825 | strnicmp(string, "1", 1) == 0) { | ||
1826 | /* This is the default */ | 1893 | /* This is the default */ |
1827 | break; | 1894 | break; |
1828 | } | 1895 | } |
@@ -1830,6 +1897,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1830 | printk(KERN_WARNING "CIFS: Invalid version" | 1897 | printk(KERN_WARNING "CIFS: Invalid version" |
1831 | " specified\n"); | 1898 | " specified\n"); |
1832 | goto cifs_parse_mount_err; | 1899 | goto cifs_parse_mount_err; |
1900 | case Opt_vers: | ||
1901 | string = match_strdup(args); | ||
1902 | if (string == NULL) | ||
1903 | goto out_nomem; | ||
1904 | |||
1905 | if (cifs_parse_smb_version(string, vol) != 0) | ||
1906 | goto cifs_parse_mount_err; | ||
1907 | break; | ||
1833 | case Opt_sec: | 1908 | case Opt_sec: |
1834 | string = match_strdup(args); | 1909 | string = match_strdup(args); |
1835 | if (string == NULL) | 1910 | if (string == NULL) |
@@ -1838,6 +1913,15 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1838 | if (cifs_parse_security_flavors(string, vol) != 0) | 1913 | if (cifs_parse_security_flavors(string, vol) != 0) |
1839 | goto cifs_parse_mount_err; | 1914 | goto cifs_parse_mount_err; |
1840 | break; | 1915 | break; |
1916 | case Opt_cache: | ||
1917 | cache_specified = true; | ||
1918 | string = match_strdup(args); | ||
1919 | if (string == NULL) | ||
1920 | goto out_nomem; | ||
1921 | |||
1922 | if (cifs_parse_cache_flavor(string, vol) != 0) | ||
1923 | goto cifs_parse_mount_err; | ||
1924 | break; | ||
1841 | default: | 1925 | default: |
1842 | /* | 1926 | /* |
1843 | * An option we don't recognize. Save it off for later | 1927 | * An option we don't recognize. Save it off for later |
@@ -1881,6 +1965,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1881 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " | 1965 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " |
1882 | "specified with no gid= option.\n"); | 1966 | "specified with no gid= option.\n"); |
1883 | 1967 | ||
1968 | /* FIXME: remove this block in 3.7 */ | ||
1969 | if (!cache_specified && !cache_warned) { | ||
1970 | cache_warned = true; | ||
1971 | printk(KERN_NOTICE "CIFS: no cache= option specified, using " | ||
1972 | "\"cache=loose\". This default will change " | ||
1973 | "to \"cache=strict\" in 3.7.\n"); | ||
1974 | } | ||
1975 | |||
1884 | kfree(mountdata_copy); | 1976 | kfree(mountdata_copy); |
1885 | return 0; | 1977 | return 0; |
1886 | 1978 | ||
@@ -2041,6 +2133,9 @@ match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
2041 | static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, | 2133 | static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, |
2042 | struct smb_vol *vol) | 2134 | struct smb_vol *vol) |
2043 | { | 2135 | { |
2136 | if ((server->vals != vol->vals) || (server->ops != vol->ops)) | ||
2137 | return 0; | ||
2138 | |||
2044 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) | 2139 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) |
2045 | return 0; | 2140 | return 0; |
2046 | 2141 | ||
@@ -2163,6 +2258,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
2163 | goto out_err; | 2258 | goto out_err; |
2164 | } | 2259 | } |
2165 | 2260 | ||
2261 | tcp_ses->ops = volume_info->ops; | ||
2262 | tcp_ses->vals = volume_info->vals; | ||
2166 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); | 2263 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); |
2167 | tcp_ses->hostname = extract_hostname(volume_info->UNC); | 2264 | tcp_ses->hostname = extract_hostname(volume_info->UNC); |
2168 | if (IS_ERR(tcp_ses->hostname)) { | 2265 | if (IS_ERR(tcp_ses->hostname)) { |
@@ -3569,6 +3666,7 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | |||
3569 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) | 3666 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) |
3570 | return -EINVAL; | 3667 | return -EINVAL; |
3571 | 3668 | ||
3669 | |||
3572 | if (volume_info->nullauth) { | 3670 | if (volume_info->nullauth) { |
3573 | cFYI(1, "Anonymous login"); | 3671 | cFYI(1, "Anonymous login"); |
3574 | kfree(volume_info->username); | 3672 | kfree(volume_info->username); |
@@ -3842,7 +3940,7 @@ CIFSTCon(unsigned int xid, struct cifs_ses *ses, | |||
3842 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | 3940 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, |
3843 | NULL /*no tid */ , 4 /*wct */ ); | 3941 | NULL /*no tid */ , 4 /*wct */ ); |
3844 | 3942 | ||
3845 | smb_buffer->Mid = GetNextMid(ses->server); | 3943 | smb_buffer->Mid = get_next_mid(ses->server); |
3846 | smb_buffer->Uid = ses->Suid; | 3944 | smb_buffer->Uid = ses->Suid; |
3847 | pSMB = (TCONX_REQ *) smb_buffer; | 3945 | pSMB = (TCONX_REQ *) smb_buffer; |
3848 | pSMBr = (TCONX_RSP *) smb_buffer_response; | 3946 | pSMBr = (TCONX_RSP *) smb_buffer_response; |
@@ -4010,11 +4108,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) | |||
4010 | if (server->maxBuf != 0) | 4108 | if (server->maxBuf != 0) |
4011 | return 0; | 4109 | return 0; |
4012 | 4110 | ||
4013 | cifs_set_credits(server, 1); | 4111 | set_credits(server, 1); |
4014 | rc = CIFSSMBNegotiate(xid, ses); | 4112 | rc = CIFSSMBNegotiate(xid, ses); |
4015 | if (rc == -EAGAIN) { | 4113 | if (rc == -EAGAIN) { |
4016 | /* retry only once on 1st time connection */ | 4114 | /* retry only once on 1st time connection */ |
4017 | cifs_set_credits(server, 1); | 4115 | set_credits(server, 1); |
4018 | rc = CIFSSMBNegotiate(xid, ses); | 4116 | rc = CIFSSMBNegotiate(xid, ses); |
4019 | if (rc == -EAGAIN) | 4117 | if (rc == -EAGAIN) |
4020 | rc = -EHOSTDOWN; | 4118 | rc = -EHOSTDOWN; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 81725e9286e9..513adbc211d7 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -264,6 +264,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file, | |||
264 | pCifsFile->tlink = cifs_get_tlink(tlink); | 264 | pCifsFile->tlink = cifs_get_tlink(tlink); |
265 | mutex_init(&pCifsFile->fh_mutex); | 265 | mutex_init(&pCifsFile->fh_mutex); |
266 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); | 266 | INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break); |
267 | INIT_LIST_HEAD(&pCifsFile->llist); | ||
267 | 268 | ||
268 | spin_lock(&cifs_file_list_lock); | 269 | spin_lock(&cifs_file_list_lock); |
269 | list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList)); | 270 | list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList)); |
@@ -334,9 +335,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
334 | * is closed anyway. | 335 | * is closed anyway. |
335 | */ | 336 | */ |
336 | mutex_lock(&cifsi->lock_mutex); | 337 | mutex_lock(&cifsi->lock_mutex); |
337 | list_for_each_entry_safe(li, tmp, &cifsi->llist, llist) { | 338 | list_for_each_entry_safe(li, tmp, &cifs_file->llist, llist) { |
338 | if (li->netfid != cifs_file->netfid) | ||
339 | continue; | ||
340 | list_del(&li->llist); | 339 | list_del(&li->llist); |
341 | cifs_del_lock_waiters(li); | 340 | cifs_del_lock_waiters(li); |
342 | kfree(li); | 341 | kfree(li); |
@@ -645,7 +644,7 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
645 | } | 644 | } |
646 | 645 | ||
647 | static struct cifsLockInfo * | 646 | static struct cifsLockInfo * |
648 | cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 netfid) | 647 | cifs_lock_init(__u64 offset, __u64 length, __u8 type) |
649 | { | 648 | { |
650 | struct cifsLockInfo *lock = | 649 | struct cifsLockInfo *lock = |
651 | kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); | 650 | kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); |
@@ -654,7 +653,6 @@ cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 netfid) | |||
654 | lock->offset = offset; | 653 | lock->offset = offset; |
655 | lock->length = length; | 654 | lock->length = length; |
656 | lock->type = type; | 655 | lock->type = type; |
657 | lock->netfid = netfid; | ||
658 | lock->pid = current->tgid; | 656 | lock->pid = current->tgid; |
659 | INIT_LIST_HEAD(&lock->blist); | 657 | INIT_LIST_HEAD(&lock->blist); |
660 | init_waitqueue_head(&lock->block_q); | 658 | init_waitqueue_head(&lock->block_q); |
@@ -672,19 +670,20 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) | |||
672 | } | 670 | } |
673 | 671 | ||
674 | static bool | 672 | static bool |
675 | __cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, | 673 | cifs_find_fid_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, |
676 | __u64 length, __u8 type, __u16 netfid, | 674 | __u64 length, __u8 type, struct cifsFileInfo *cur, |
677 | struct cifsLockInfo **conf_lock) | 675 | struct cifsLockInfo **conf_lock) |
678 | { | 676 | { |
679 | struct cifsLockInfo *li, *tmp; | 677 | struct cifsLockInfo *li; |
678 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | ||
680 | 679 | ||
681 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | 680 | list_for_each_entry(li, &cfile->llist, llist) { |
682 | if (offset + length <= li->offset || | 681 | if (offset + length <= li->offset || |
683 | offset >= li->offset + li->length) | 682 | offset >= li->offset + li->length) |
684 | continue; | 683 | continue; |
685 | else if ((type & LOCKING_ANDX_SHARED_LOCK) && | 684 | else if ((type & server->vals->shared_lock_type) && |
686 | ((netfid == li->netfid && current->tgid == li->pid) || | 685 | ((server->ops->compare_fids(cur, cfile) && |
687 | type == li->type)) | 686 | current->tgid == li->pid) || type == li->type)) |
688 | continue; | 687 | continue; |
689 | else { | 688 | else { |
690 | *conf_lock = li; | 689 | *conf_lock = li; |
@@ -695,11 +694,23 @@ __cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, | |||
695 | } | 694 | } |
696 | 695 | ||
697 | static bool | 696 | static bool |
698 | cifs_find_lock_conflict(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, | 697 | cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
699 | struct cifsLockInfo **conf_lock) | 698 | __u8 type, struct cifsLockInfo **conf_lock) |
700 | { | 699 | { |
701 | return __cifs_find_lock_conflict(cinode, lock->offset, lock->length, | 700 | bool rc = false; |
702 | lock->type, lock->netfid, conf_lock); | 701 | struct cifsFileInfo *fid, *tmp; |
702 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
703 | |||
704 | spin_lock(&cifs_file_list_lock); | ||
705 | list_for_each_entry_safe(fid, tmp, &cinode->openFileList, flist) { | ||
706 | rc = cifs_find_fid_lock_conflict(fid, offset, length, type, | ||
707 | cfile, conf_lock); | ||
708 | if (rc) | ||
709 | break; | ||
710 | } | ||
711 | spin_unlock(&cifs_file_list_lock); | ||
712 | |||
713 | return rc; | ||
703 | } | 714 | } |
704 | 715 | ||
705 | /* | 716 | /* |
@@ -710,22 +721,24 @@ cifs_find_lock_conflict(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, | |||
710 | * the server or 1 otherwise. | 721 | * the server or 1 otherwise. |
711 | */ | 722 | */ |
712 | static int | 723 | static int |
713 | cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, | 724 | cifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, |
714 | __u8 type, __u16 netfid, struct file_lock *flock) | 725 | __u8 type, struct file_lock *flock) |
715 | { | 726 | { |
716 | int rc = 0; | 727 | int rc = 0; |
717 | struct cifsLockInfo *conf_lock; | 728 | struct cifsLockInfo *conf_lock; |
729 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
730 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | ||
718 | bool exist; | 731 | bool exist; |
719 | 732 | ||
720 | mutex_lock(&cinode->lock_mutex); | 733 | mutex_lock(&cinode->lock_mutex); |
721 | 734 | ||
722 | exist = __cifs_find_lock_conflict(cinode, offset, length, type, netfid, | 735 | exist = cifs_find_lock_conflict(cfile, offset, length, type, |
723 | &conf_lock); | 736 | &conf_lock); |
724 | if (exist) { | 737 | if (exist) { |
725 | flock->fl_start = conf_lock->offset; | 738 | flock->fl_start = conf_lock->offset; |
726 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; | 739 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; |
727 | flock->fl_pid = conf_lock->pid; | 740 | flock->fl_pid = conf_lock->pid; |
728 | if (conf_lock->type & LOCKING_ANDX_SHARED_LOCK) | 741 | if (conf_lock->type & server->vals->shared_lock_type) |
729 | flock->fl_type = F_RDLCK; | 742 | flock->fl_type = F_RDLCK; |
730 | else | 743 | else |
731 | flock->fl_type = F_WRLCK; | 744 | flock->fl_type = F_WRLCK; |
@@ -739,10 +752,11 @@ cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, | |||
739 | } | 752 | } |
740 | 753 | ||
741 | static void | 754 | static void |
742 | cifs_lock_add(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock) | 755 | cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock) |
743 | { | 756 | { |
757 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
744 | mutex_lock(&cinode->lock_mutex); | 758 | mutex_lock(&cinode->lock_mutex); |
745 | list_add_tail(&lock->llist, &cinode->llist); | 759 | list_add_tail(&lock->llist, &cfile->llist); |
746 | mutex_unlock(&cinode->lock_mutex); | 760 | mutex_unlock(&cinode->lock_mutex); |
747 | } | 761 | } |
748 | 762 | ||
@@ -753,10 +767,11 @@ cifs_lock_add(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock) | |||
753 | * 3) -EACCESS, if there is a lock that prevents us and wait is false. | 767 | * 3) -EACCESS, if there is a lock that prevents us and wait is false. |
754 | */ | 768 | */ |
755 | static int | 769 | static int |
756 | cifs_lock_add_if(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, | 770 | cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock, |
757 | bool wait) | 771 | bool wait) |
758 | { | 772 | { |
759 | struct cifsLockInfo *conf_lock; | 773 | struct cifsLockInfo *conf_lock; |
774 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
760 | bool exist; | 775 | bool exist; |
761 | int rc = 0; | 776 | int rc = 0; |
762 | 777 | ||
@@ -764,9 +779,10 @@ try_again: | |||
764 | exist = false; | 779 | exist = false; |
765 | mutex_lock(&cinode->lock_mutex); | 780 | mutex_lock(&cinode->lock_mutex); |
766 | 781 | ||
767 | exist = cifs_find_lock_conflict(cinode, lock, &conf_lock); | 782 | exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, |
783 | lock->type, &conf_lock); | ||
768 | if (!exist && cinode->can_cache_brlcks) { | 784 | if (!exist && cinode->can_cache_brlcks) { |
769 | list_add_tail(&lock->llist, &cinode->llist); | 785 | list_add_tail(&lock->llist, &cfile->llist); |
770 | mutex_unlock(&cinode->lock_mutex); | 786 | mutex_unlock(&cinode->lock_mutex); |
771 | return rc; | 787 | return rc; |
772 | } | 788 | } |
@@ -860,7 +876,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
860 | struct cifsLockInfo *li, *tmp; | 876 | struct cifsLockInfo *li, *tmp; |
861 | struct cifs_tcon *tcon; | 877 | struct cifs_tcon *tcon; |
862 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 878 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); |
863 | unsigned int num, max_num; | 879 | unsigned int num, max_num, max_buf; |
864 | LOCKING_ANDX_RANGE *buf, *cur; | 880 | LOCKING_ANDX_RANGE *buf, *cur; |
865 | int types[] = {LOCKING_ANDX_LARGE_FILES, | 881 | int types[] = {LOCKING_ANDX_LARGE_FILES, |
866 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; | 882 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; |
@@ -876,8 +892,19 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
876 | return rc; | 892 | return rc; |
877 | } | 893 | } |
878 | 894 | ||
879 | max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) / | 895 | /* |
880 | sizeof(LOCKING_ANDX_RANGE); | 896 | * Accessing maxBuf is racy with cifs_reconnect - need to store value |
897 | * and check it for zero before using. | ||
898 | */ | ||
899 | max_buf = tcon->ses->server->maxBuf; | ||
900 | if (!max_buf) { | ||
901 | mutex_unlock(&cinode->lock_mutex); | ||
902 | FreeXid(xid); | ||
903 | return -EINVAL; | ||
904 | } | ||
905 | |||
906 | max_num = (max_buf - sizeof(struct smb_hdr)) / | ||
907 | sizeof(LOCKING_ANDX_RANGE); | ||
881 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); | 908 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); |
882 | if (!buf) { | 909 | if (!buf) { |
883 | mutex_unlock(&cinode->lock_mutex); | 910 | mutex_unlock(&cinode->lock_mutex); |
@@ -888,7 +915,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
888 | for (i = 0; i < 2; i++) { | 915 | for (i = 0; i < 2; i++) { |
889 | cur = buf; | 916 | cur = buf; |
890 | num = 0; | 917 | num = 0; |
891 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | 918 | list_for_each_entry_safe(li, tmp, &cfile->llist, llist) { |
892 | if (li->type != types[i]) | 919 | if (li->type != types[i]) |
893 | continue; | 920 | continue; |
894 | cur->Pid = cpu_to_le16(li->pid); | 921 | cur->Pid = cpu_to_le16(li->pid); |
@@ -898,7 +925,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
898 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); | 925 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); |
899 | if (++num == max_num) { | 926 | if (++num == max_num) { |
900 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | 927 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, |
901 | li->type, 0, num, buf); | 928 | (__u8)li->type, 0, num, |
929 | buf); | ||
902 | if (stored_rc) | 930 | if (stored_rc) |
903 | rc = stored_rc; | 931 | rc = stored_rc; |
904 | cur = buf; | 932 | cur = buf; |
@@ -909,7 +937,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
909 | 937 | ||
910 | if (num) { | 938 | if (num) { |
911 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | 939 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, |
912 | types[i], 0, num, buf); | 940 | (__u8)types[i], 0, num, buf); |
913 | if (stored_rc) | 941 | if (stored_rc) |
914 | rc = stored_rc; | 942 | rc = stored_rc; |
915 | } | 943 | } |
@@ -1053,8 +1081,8 @@ cifs_push_locks(struct cifsFileInfo *cfile) | |||
1053 | } | 1081 | } |
1054 | 1082 | ||
1055 | static void | 1083 | static void |
1056 | cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, | 1084 | cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock, |
1057 | bool *wait_flag) | 1085 | bool *wait_flag, struct TCP_Server_Info *server) |
1058 | { | 1086 | { |
1059 | if (flock->fl_flags & FL_POSIX) | 1087 | if (flock->fl_flags & FL_POSIX) |
1060 | cFYI(1, "Posix"); | 1088 | cFYI(1, "Posix"); |
@@ -1073,38 +1101,50 @@ cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, | |||
1073 | (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) | 1101 | (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) |
1074 | cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags); | 1102 | cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags); |
1075 | 1103 | ||
1076 | *type = LOCKING_ANDX_LARGE_FILES; | 1104 | *type = server->vals->large_lock_type; |
1077 | if (flock->fl_type == F_WRLCK) { | 1105 | if (flock->fl_type == F_WRLCK) { |
1078 | cFYI(1, "F_WRLCK "); | 1106 | cFYI(1, "F_WRLCK "); |
1107 | *type |= server->vals->exclusive_lock_type; | ||
1079 | *lock = 1; | 1108 | *lock = 1; |
1080 | } else if (flock->fl_type == F_UNLCK) { | 1109 | } else if (flock->fl_type == F_UNLCK) { |
1081 | cFYI(1, "F_UNLCK"); | 1110 | cFYI(1, "F_UNLCK"); |
1111 | *type |= server->vals->unlock_lock_type; | ||
1082 | *unlock = 1; | 1112 | *unlock = 1; |
1083 | /* Check if unlock includes more than one lock range */ | 1113 | /* Check if unlock includes more than one lock range */ |
1084 | } else if (flock->fl_type == F_RDLCK) { | 1114 | } else if (flock->fl_type == F_RDLCK) { |
1085 | cFYI(1, "F_RDLCK"); | 1115 | cFYI(1, "F_RDLCK"); |
1086 | *type |= LOCKING_ANDX_SHARED_LOCK; | 1116 | *type |= server->vals->shared_lock_type; |
1087 | *lock = 1; | 1117 | *lock = 1; |
1088 | } else if (flock->fl_type == F_EXLCK) { | 1118 | } else if (flock->fl_type == F_EXLCK) { |
1089 | cFYI(1, "F_EXLCK"); | 1119 | cFYI(1, "F_EXLCK"); |
1120 | *type |= server->vals->exclusive_lock_type; | ||
1090 | *lock = 1; | 1121 | *lock = 1; |
1091 | } else if (flock->fl_type == F_SHLCK) { | 1122 | } else if (flock->fl_type == F_SHLCK) { |
1092 | cFYI(1, "F_SHLCK"); | 1123 | cFYI(1, "F_SHLCK"); |
1093 | *type |= LOCKING_ANDX_SHARED_LOCK; | 1124 | *type |= server->vals->shared_lock_type; |
1094 | *lock = 1; | 1125 | *lock = 1; |
1095 | } else | 1126 | } else |
1096 | cFYI(1, "Unknown type of lock"); | 1127 | cFYI(1, "Unknown type of lock"); |
1097 | } | 1128 | } |
1098 | 1129 | ||
1099 | static int | 1130 | static int |
1100 | cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | 1131 | cifs_mandatory_lock(int xid, struct cifsFileInfo *cfile, __u64 offset, |
1132 | __u64 length, __u32 type, int lock, int unlock, bool wait) | ||
1133 | { | ||
1134 | return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid, | ||
1135 | current->tgid, length, offset, unlock, lock, | ||
1136 | (__u8)type, wait, 0); | ||
1137 | } | ||
1138 | |||
1139 | static int | ||
1140 | cifs_getlk(struct file *file, struct file_lock *flock, __u32 type, | ||
1101 | bool wait_flag, bool posix_lck, int xid) | 1141 | bool wait_flag, bool posix_lck, int xid) |
1102 | { | 1142 | { |
1103 | int rc = 0; | 1143 | int rc = 0; |
1104 | __u64 length = 1 + flock->fl_end - flock->fl_start; | 1144 | __u64 length = 1 + flock->fl_end - flock->fl_start; |
1105 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 1145 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
1106 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1146 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1107 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 1147 | struct TCP_Server_Info *server = tcon->ses->server; |
1108 | __u16 netfid = cfile->netfid; | 1148 | __u16 netfid = cfile->netfid; |
1109 | 1149 | ||
1110 | if (posix_lck) { | 1150 | if (posix_lck) { |
@@ -1114,7 +1154,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1114 | if (!rc) | 1154 | if (!rc) |
1115 | return rc; | 1155 | return rc; |
1116 | 1156 | ||
1117 | if (type & LOCKING_ANDX_SHARED_LOCK) | 1157 | if (type & server->vals->shared_lock_type) |
1118 | posix_lock_type = CIFS_RDLCK; | 1158 | posix_lock_type = CIFS_RDLCK; |
1119 | else | 1159 | else |
1120 | posix_lock_type = CIFS_WRLCK; | 1160 | posix_lock_type = CIFS_WRLCK; |
@@ -1124,38 +1164,35 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1124 | return rc; | 1164 | return rc; |
1125 | } | 1165 | } |
1126 | 1166 | ||
1127 | rc = cifs_lock_test(cinode, flock->fl_start, length, type, netfid, | 1167 | rc = cifs_lock_test(cfile, flock->fl_start, length, type, flock); |
1128 | flock); | ||
1129 | if (!rc) | 1168 | if (!rc) |
1130 | return rc; | 1169 | return rc; |
1131 | 1170 | ||
1132 | /* BB we could chain these into one lock request BB */ | 1171 | /* BB we could chain these into one lock request BB */ |
1133 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1172 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, type, |
1134 | flock->fl_start, 0, 1, type, 0, 0); | 1173 | 1, 0, false); |
1135 | if (rc == 0) { | 1174 | if (rc == 0) { |
1136 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, | 1175 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1137 | length, flock->fl_start, 1, 0, | 1176 | type, 0, 1, false); |
1138 | type, 0, 0); | ||
1139 | flock->fl_type = F_UNLCK; | 1177 | flock->fl_type = F_UNLCK; |
1140 | if (rc != 0) | 1178 | if (rc != 0) |
1141 | cERROR(1, "Error unlocking previously locked " | 1179 | cERROR(1, "Error unlocking previously locked " |
1142 | "range %d during test of lock", rc); | 1180 | "range %d during test of lock", rc); |
1143 | return 0; | 1181 | return 0; |
1144 | } | 1182 | } |
1145 | 1183 | ||
1146 | if (type & LOCKING_ANDX_SHARED_LOCK) { | 1184 | if (type & server->vals->shared_lock_type) { |
1147 | flock->fl_type = F_WRLCK; | 1185 | flock->fl_type = F_WRLCK; |
1148 | return 0; | 1186 | return 0; |
1149 | } | 1187 | } |
1150 | 1188 | ||
1151 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1189 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1152 | flock->fl_start, 0, 1, | 1190 | type | server->vals->shared_lock_type, 1, 0, |
1153 | type | LOCKING_ANDX_SHARED_LOCK, 0, 0); | 1191 | false); |
1154 | if (rc == 0) { | 1192 | if (rc == 0) { |
1155 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, | 1193 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1156 | length, flock->fl_start, 1, 0, | 1194 | type | server->vals->shared_lock_type, |
1157 | type | LOCKING_ANDX_SHARED_LOCK, | 1195 | 0, 1, false); |
1158 | 0, 0); | ||
1159 | flock->fl_type = F_RDLCK; | 1196 | flock->fl_type = F_RDLCK; |
1160 | if (rc != 0) | 1197 | if (rc != 0) |
1161 | cERROR(1, "Error unlocking previously locked " | 1198 | cERROR(1, "Error unlocking previously locked " |
@@ -1192,7 +1229,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1192 | int types[] = {LOCKING_ANDX_LARGE_FILES, | 1229 | int types[] = {LOCKING_ANDX_LARGE_FILES, |
1193 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; | 1230 | LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES}; |
1194 | unsigned int i; | 1231 | unsigned int i; |
1195 | unsigned int max_num, num; | 1232 | unsigned int max_num, num, max_buf; |
1196 | LOCKING_ANDX_RANGE *buf, *cur; | 1233 | LOCKING_ANDX_RANGE *buf, *cur; |
1197 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1234 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1198 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 1235 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); |
@@ -1202,8 +1239,16 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1202 | 1239 | ||
1203 | INIT_LIST_HEAD(&tmp_llist); | 1240 | INIT_LIST_HEAD(&tmp_llist); |
1204 | 1241 | ||
1205 | max_num = (tcon->ses->server->maxBuf - sizeof(struct smb_hdr)) / | 1242 | /* |
1206 | sizeof(LOCKING_ANDX_RANGE); | 1243 | * Accessing maxBuf is racy with cifs_reconnect - need to store value |
1244 | * and check it for zero before using. | ||
1245 | */ | ||
1246 | max_buf = tcon->ses->server->maxBuf; | ||
1247 | if (!max_buf) | ||
1248 | return -EINVAL; | ||
1249 | |||
1250 | max_num = (max_buf - sizeof(struct smb_hdr)) / | ||
1251 | sizeof(LOCKING_ANDX_RANGE); | ||
1207 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); | 1252 | buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); |
1208 | if (!buf) | 1253 | if (!buf) |
1209 | return -ENOMEM; | 1254 | return -ENOMEM; |
@@ -1212,71 +1257,64 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1212 | for (i = 0; i < 2; i++) { | 1257 | for (i = 0; i < 2; i++) { |
1213 | cur = buf; | 1258 | cur = buf; |
1214 | num = 0; | 1259 | num = 0; |
1215 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | 1260 | list_for_each_entry_safe(li, tmp, &cfile->llist, llist) { |
1216 | if (flock->fl_start > li->offset || | 1261 | if (flock->fl_start > li->offset || |
1217 | (flock->fl_start + length) < | 1262 | (flock->fl_start + length) < |
1218 | (li->offset + li->length)) | 1263 | (li->offset + li->length)) |
1219 | continue; | 1264 | continue; |
1220 | if (current->tgid != li->pid) | 1265 | if (current->tgid != li->pid) |
1221 | continue; | 1266 | continue; |
1222 | if (cfile->netfid != li->netfid) | ||
1223 | continue; | ||
1224 | if (types[i] != li->type) | 1267 | if (types[i] != li->type) |
1225 | continue; | 1268 | continue; |
1226 | if (!cinode->can_cache_brlcks) { | 1269 | if (cinode->can_cache_brlcks) { |
1227 | cur->Pid = cpu_to_le16(li->pid); | ||
1228 | cur->LengthLow = cpu_to_le32((u32)li->length); | ||
1229 | cur->LengthHigh = | ||
1230 | cpu_to_le32((u32)(li->length>>32)); | ||
1231 | cur->OffsetLow = cpu_to_le32((u32)li->offset); | ||
1232 | cur->OffsetHigh = | ||
1233 | cpu_to_le32((u32)(li->offset>>32)); | ||
1234 | /* | ||
1235 | * We need to save a lock here to let us add | ||
1236 | * it again to the inode list if the unlock | ||
1237 | * range request fails on the server. | ||
1238 | */ | ||
1239 | list_move(&li->llist, &tmp_llist); | ||
1240 | if (++num == max_num) { | ||
1241 | stored_rc = cifs_lockv(xid, tcon, | ||
1242 | cfile->netfid, | ||
1243 | li->type, num, | ||
1244 | 0, buf); | ||
1245 | if (stored_rc) { | ||
1246 | /* | ||
1247 | * We failed on the unlock range | ||
1248 | * request - add all locks from | ||
1249 | * the tmp list to the head of | ||
1250 | * the inode list. | ||
1251 | */ | ||
1252 | cifs_move_llist(&tmp_llist, | ||
1253 | &cinode->llist); | ||
1254 | rc = stored_rc; | ||
1255 | } else | ||
1256 | /* | ||
1257 | * The unlock range request | ||
1258 | * succeed - free the tmp list. | ||
1259 | */ | ||
1260 | cifs_free_llist(&tmp_llist); | ||
1261 | cur = buf; | ||
1262 | num = 0; | ||
1263 | } else | ||
1264 | cur++; | ||
1265 | } else { | ||
1266 | /* | 1270 | /* |
1267 | * We can cache brlock requests - simply remove | 1271 | * We can cache brlock requests - simply remove |
1268 | * a lock from the inode list. | 1272 | * a lock from the file's list. |
1269 | */ | 1273 | */ |
1270 | list_del(&li->llist); | 1274 | list_del(&li->llist); |
1271 | cifs_del_lock_waiters(li); | 1275 | cifs_del_lock_waiters(li); |
1272 | kfree(li); | 1276 | kfree(li); |
1277 | continue; | ||
1273 | } | 1278 | } |
1279 | cur->Pid = cpu_to_le16(li->pid); | ||
1280 | cur->LengthLow = cpu_to_le32((u32)li->length); | ||
1281 | cur->LengthHigh = cpu_to_le32((u32)(li->length>>32)); | ||
1282 | cur->OffsetLow = cpu_to_le32((u32)li->offset); | ||
1283 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); | ||
1284 | /* | ||
1285 | * We need to save a lock here to let us add it again to | ||
1286 | * the file's list if the unlock range request fails on | ||
1287 | * the server. | ||
1288 | */ | ||
1289 | list_move(&li->llist, &tmp_llist); | ||
1290 | if (++num == max_num) { | ||
1291 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | ||
1292 | li->type, num, 0, buf); | ||
1293 | if (stored_rc) { | ||
1294 | /* | ||
1295 | * We failed on the unlock range | ||
1296 | * request - add all locks from the tmp | ||
1297 | * list to the head of the file's list. | ||
1298 | */ | ||
1299 | cifs_move_llist(&tmp_llist, | ||
1300 | &cfile->llist); | ||
1301 | rc = stored_rc; | ||
1302 | } else | ||
1303 | /* | ||
1304 | * The unlock range request succeed - | ||
1305 | * free the tmp list. | ||
1306 | */ | ||
1307 | cifs_free_llist(&tmp_llist); | ||
1308 | cur = buf; | ||
1309 | num = 0; | ||
1310 | } else | ||
1311 | cur++; | ||
1274 | } | 1312 | } |
1275 | if (num) { | 1313 | if (num) { |
1276 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | 1314 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, |
1277 | types[i], num, 0, buf); | 1315 | types[i], num, 0, buf); |
1278 | if (stored_rc) { | 1316 | if (stored_rc) { |
1279 | cifs_move_llist(&tmp_llist, &cinode->llist); | 1317 | cifs_move_llist(&tmp_llist, &cfile->llist); |
1280 | rc = stored_rc; | 1318 | rc = stored_rc; |
1281 | } else | 1319 | } else |
1282 | cifs_free_llist(&tmp_llist); | 1320 | cifs_free_llist(&tmp_llist); |
@@ -1289,14 +1327,14 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1289 | } | 1327 | } |
1290 | 1328 | ||
1291 | static int | 1329 | static int |
1292 | cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | 1330 | cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, |
1293 | bool wait_flag, bool posix_lck, int lock, int unlock, int xid) | 1331 | bool wait_flag, bool posix_lck, int lock, int unlock, int xid) |
1294 | { | 1332 | { |
1295 | int rc = 0; | 1333 | int rc = 0; |
1296 | __u64 length = 1 + flock->fl_end - flock->fl_start; | 1334 | __u64 length = 1 + flock->fl_end - flock->fl_start; |
1297 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 1335 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
1298 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1336 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1299 | struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode); | 1337 | struct TCP_Server_Info *server = tcon->ses->server; |
1300 | __u16 netfid = cfile->netfid; | 1338 | __u16 netfid = cfile->netfid; |
1301 | 1339 | ||
1302 | if (posix_lck) { | 1340 | if (posix_lck) { |
@@ -1306,7 +1344,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1306 | if (!rc || rc < 0) | 1344 | if (!rc || rc < 0) |
1307 | return rc; | 1345 | return rc; |
1308 | 1346 | ||
1309 | if (type & LOCKING_ANDX_SHARED_LOCK) | 1347 | if (type & server->vals->shared_lock_type) |
1310 | posix_lock_type = CIFS_RDLCK; | 1348 | posix_lock_type = CIFS_RDLCK; |
1311 | else | 1349 | else |
1312 | posix_lock_type = CIFS_WRLCK; | 1350 | posix_lock_type = CIFS_WRLCK; |
@@ -1323,24 +1361,24 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1323 | if (lock) { | 1361 | if (lock) { |
1324 | struct cifsLockInfo *lock; | 1362 | struct cifsLockInfo *lock; |
1325 | 1363 | ||
1326 | lock = cifs_lock_init(flock->fl_start, length, type, netfid); | 1364 | lock = cifs_lock_init(flock->fl_start, length, type); |
1327 | if (!lock) | 1365 | if (!lock) |
1328 | return -ENOMEM; | 1366 | return -ENOMEM; |
1329 | 1367 | ||
1330 | rc = cifs_lock_add_if(cinode, lock, wait_flag); | 1368 | rc = cifs_lock_add_if(cfile, lock, wait_flag); |
1331 | if (rc < 0) | 1369 | if (rc < 0) |
1332 | kfree(lock); | 1370 | kfree(lock); |
1333 | if (rc <= 0) | 1371 | if (rc <= 0) |
1334 | goto out; | 1372 | goto out; |
1335 | 1373 | ||
1336 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1374 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1337 | flock->fl_start, 0, 1, type, wait_flag, 0); | 1375 | type, 1, 0, wait_flag); |
1338 | if (rc) { | 1376 | if (rc) { |
1339 | kfree(lock); | 1377 | kfree(lock); |
1340 | goto out; | 1378 | goto out; |
1341 | } | 1379 | } |
1342 | 1380 | ||
1343 | cifs_lock_add(cinode, lock); | 1381 | cifs_lock_add(cfile, lock); |
1344 | } else if (unlock) | 1382 | } else if (unlock) |
1345 | rc = cifs_unlock_range(cfile, flock, xid); | 1383 | rc = cifs_unlock_range(cfile, flock, xid); |
1346 | 1384 | ||
@@ -1361,7 +1399,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
1361 | struct cifsInodeInfo *cinode; | 1399 | struct cifsInodeInfo *cinode; |
1362 | struct cifsFileInfo *cfile; | 1400 | struct cifsFileInfo *cfile; |
1363 | __u16 netfid; | 1401 | __u16 netfid; |
1364 | __u8 type; | 1402 | __u32 type; |
1365 | 1403 | ||
1366 | rc = -EACCES; | 1404 | rc = -EACCES; |
1367 | xid = GetXid(); | 1405 | xid = GetXid(); |
@@ -1370,11 +1408,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
1370 | "end: %lld", cmd, flock->fl_flags, flock->fl_type, | 1408 | "end: %lld", cmd, flock->fl_flags, flock->fl_type, |
1371 | flock->fl_start, flock->fl_end); | 1409 | flock->fl_start, flock->fl_end); |
1372 | 1410 | ||
1373 | cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag); | ||
1374 | |||
1375 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1376 | cfile = (struct cifsFileInfo *)file->private_data; | 1411 | cfile = (struct cifsFileInfo *)file->private_data; |
1377 | tcon = tlink_tcon(cfile->tlink); | 1412 | tcon = tlink_tcon(cfile->tlink); |
1413 | |||
1414 | cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag, | ||
1415 | tcon->ses->server); | ||
1416 | |||
1417 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1378 | netfid = cfile->netfid; | 1418 | netfid = cfile->netfid; |
1379 | cinode = CIFS_I(file->f_path.dentry->d_inode); | 1419 | cinode = CIFS_I(file->f_path.dentry->d_inode); |
1380 | 1420 | ||
@@ -1539,10 +1579,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
1539 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | 1579 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, |
1540 | bool fsuid_only) | 1580 | bool fsuid_only) |
1541 | { | 1581 | { |
1542 | struct cifsFileInfo *open_file; | 1582 | struct cifsFileInfo *open_file, *inv_file = NULL; |
1543 | struct cifs_sb_info *cifs_sb; | 1583 | struct cifs_sb_info *cifs_sb; |
1544 | bool any_available = false; | 1584 | bool any_available = false; |
1545 | int rc; | 1585 | int rc; |
1586 | unsigned int refind = 0; | ||
1546 | 1587 | ||
1547 | /* Having a null inode here (because mapping->host was set to zero by | 1588 | /* Having a null inode here (because mapping->host was set to zero by |
1548 | the VFS or MM) should not happen but we had reports of on oops (due to | 1589 | the VFS or MM) should not happen but we had reports of on oops (due to |
@@ -1562,40 +1603,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1562 | 1603 | ||
1563 | spin_lock(&cifs_file_list_lock); | 1604 | spin_lock(&cifs_file_list_lock); |
1564 | refind_writable: | 1605 | refind_writable: |
1606 | if (refind > MAX_REOPEN_ATT) { | ||
1607 | spin_unlock(&cifs_file_list_lock); | ||
1608 | return NULL; | ||
1609 | } | ||
1565 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1610 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1566 | if (!any_available && open_file->pid != current->tgid) | 1611 | if (!any_available && open_file->pid != current->tgid) |
1567 | continue; | 1612 | continue; |
1568 | if (fsuid_only && open_file->uid != current_fsuid()) | 1613 | if (fsuid_only && open_file->uid != current_fsuid()) |
1569 | continue; | 1614 | continue; |
1570 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { | 1615 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
1571 | cifsFileInfo_get(open_file); | ||
1572 | |||
1573 | if (!open_file->invalidHandle) { | 1616 | if (!open_file->invalidHandle) { |
1574 | /* found a good writable file */ | 1617 | /* found a good writable file */ |
1618 | cifsFileInfo_get(open_file); | ||
1575 | spin_unlock(&cifs_file_list_lock); | 1619 | spin_unlock(&cifs_file_list_lock); |
1576 | return open_file; | 1620 | return open_file; |
1621 | } else { | ||
1622 | if (!inv_file) | ||
1623 | inv_file = open_file; | ||
1577 | } | 1624 | } |
1578 | |||
1579 | spin_unlock(&cifs_file_list_lock); | ||
1580 | |||
1581 | /* Had to unlock since following call can block */ | ||
1582 | rc = cifs_reopen_file(open_file, false); | ||
1583 | if (!rc) | ||
1584 | return open_file; | ||
1585 | |||
1586 | /* if it fails, try another handle if possible */ | ||
1587 | cFYI(1, "wp failed on reopen file"); | ||
1588 | cifsFileInfo_put(open_file); | ||
1589 | |||
1590 | spin_lock(&cifs_file_list_lock); | ||
1591 | |||
1592 | /* else we simply continue to the next entry. Thus | ||
1593 | we do not loop on reopen errors. If we | ||
1594 | can not reopen the file, for example if we | ||
1595 | reconnected to a server with another client | ||
1596 | racing to delete or lock the file we would not | ||
1597 | make progress if we restarted before the beginning | ||
1598 | of the loop here. */ | ||
1599 | } | 1625 | } |
1600 | } | 1626 | } |
1601 | /* couldn't find useable FH with same pid, try any available */ | 1627 | /* couldn't find useable FH with same pid, try any available */ |
@@ -1603,7 +1629,30 @@ refind_writable: | |||
1603 | any_available = true; | 1629 | any_available = true; |
1604 | goto refind_writable; | 1630 | goto refind_writable; |
1605 | } | 1631 | } |
1632 | |||
1633 | if (inv_file) { | ||
1634 | any_available = false; | ||
1635 | cifsFileInfo_get(inv_file); | ||
1636 | } | ||
1637 | |||
1606 | spin_unlock(&cifs_file_list_lock); | 1638 | spin_unlock(&cifs_file_list_lock); |
1639 | |||
1640 | if (inv_file) { | ||
1641 | rc = cifs_reopen_file(inv_file, false); | ||
1642 | if (!rc) | ||
1643 | return inv_file; | ||
1644 | else { | ||
1645 | spin_lock(&cifs_file_list_lock); | ||
1646 | list_move_tail(&inv_file->flist, | ||
1647 | &cifs_inode->openFileList); | ||
1648 | spin_unlock(&cifs_file_list_lock); | ||
1649 | cifsFileInfo_put(inv_file); | ||
1650 | spin_lock(&cifs_file_list_lock); | ||
1651 | ++refind; | ||
1652 | goto refind_writable; | ||
1653 | } | ||
1654 | } | ||
1655 | |||
1607 | return NULL; | 1656 | return NULL; |
1608 | } | 1657 | } |
1609 | 1658 | ||
@@ -2339,24 +2388,224 @@ ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2339 | return cifs_user_writev(iocb, iov, nr_segs, pos); | 2388 | return cifs_user_writev(iocb, iov, nr_segs, pos); |
2340 | } | 2389 | } |
2341 | 2390 | ||
2391 | static struct cifs_readdata * | ||
2392 | cifs_readdata_alloc(unsigned int nr_vecs, work_func_t complete) | ||
2393 | { | ||
2394 | struct cifs_readdata *rdata; | ||
2395 | |||
2396 | rdata = kzalloc(sizeof(*rdata) + | ||
2397 | sizeof(struct kvec) * nr_vecs, GFP_KERNEL); | ||
2398 | if (rdata != NULL) { | ||
2399 | kref_init(&rdata->refcount); | ||
2400 | INIT_LIST_HEAD(&rdata->list); | ||
2401 | init_completion(&rdata->done); | ||
2402 | INIT_WORK(&rdata->work, complete); | ||
2403 | INIT_LIST_HEAD(&rdata->pages); | ||
2404 | } | ||
2405 | return rdata; | ||
2406 | } | ||
2407 | |||
2408 | void | ||
2409 | cifs_readdata_release(struct kref *refcount) | ||
2410 | { | ||
2411 | struct cifs_readdata *rdata = container_of(refcount, | ||
2412 | struct cifs_readdata, refcount); | ||
2413 | |||
2414 | if (rdata->cfile) | ||
2415 | cifsFileInfo_put(rdata->cfile); | ||
2416 | |||
2417 | kfree(rdata); | ||
2418 | } | ||
2419 | |||
2420 | static int | ||
2421 | cifs_read_allocate_pages(struct list_head *list, unsigned int npages) | ||
2422 | { | ||
2423 | int rc = 0; | ||
2424 | struct page *page, *tpage; | ||
2425 | unsigned int i; | ||
2426 | |||
2427 | for (i = 0; i < npages; i++) { | ||
2428 | page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); | ||
2429 | if (!page) { | ||
2430 | rc = -ENOMEM; | ||
2431 | break; | ||
2432 | } | ||
2433 | list_add(&page->lru, list); | ||
2434 | } | ||
2435 | |||
2436 | if (rc) { | ||
2437 | list_for_each_entry_safe(page, tpage, list, lru) { | ||
2438 | list_del(&page->lru); | ||
2439 | put_page(page); | ||
2440 | } | ||
2441 | } | ||
2442 | return rc; | ||
2443 | } | ||
2444 | |||
2445 | static void | ||
2446 | cifs_uncached_readdata_release(struct kref *refcount) | ||
2447 | { | ||
2448 | struct page *page, *tpage; | ||
2449 | struct cifs_readdata *rdata = container_of(refcount, | ||
2450 | struct cifs_readdata, refcount); | ||
2451 | |||
2452 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2453 | list_del(&page->lru); | ||
2454 | put_page(page); | ||
2455 | } | ||
2456 | cifs_readdata_release(refcount); | ||
2457 | } | ||
2458 | |||
2459 | static int | ||
2460 | cifs_retry_async_readv(struct cifs_readdata *rdata) | ||
2461 | { | ||
2462 | int rc; | ||
2463 | |||
2464 | do { | ||
2465 | if (rdata->cfile->invalidHandle) { | ||
2466 | rc = cifs_reopen_file(rdata->cfile, true); | ||
2467 | if (rc != 0) | ||
2468 | continue; | ||
2469 | } | ||
2470 | rc = cifs_async_readv(rdata); | ||
2471 | } while (rc == -EAGAIN); | ||
2472 | |||
2473 | return rc; | ||
2474 | } | ||
2475 | |||
2476 | /** | ||
2477 | * cifs_readdata_to_iov - copy data from pages in response to an iovec | ||
2478 | * @rdata: the readdata response with list of pages holding data | ||
2479 | * @iov: vector in which we should copy the data | ||
2480 | * @nr_segs: number of segments in vector | ||
2481 | * @offset: offset into file of the first iovec | ||
2482 | * @copied: used to return the amount of data copied to the iov | ||
2483 | * | ||
2484 | * This function copies data from a list of pages in a readdata response into | ||
2485 | * an array of iovecs. It will first calculate where the data should go | ||
2486 | * based on the info in the readdata and then copy the data into that spot. | ||
2487 | */ | ||
2488 | static ssize_t | ||
2489 | cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov, | ||
2490 | unsigned long nr_segs, loff_t offset, ssize_t *copied) | ||
2491 | { | ||
2492 | int rc = 0; | ||
2493 | struct iov_iter ii; | ||
2494 | size_t pos = rdata->offset - offset; | ||
2495 | struct page *page, *tpage; | ||
2496 | ssize_t remaining = rdata->bytes; | ||
2497 | unsigned char *pdata; | ||
2498 | |||
2499 | /* set up iov_iter and advance to the correct offset */ | ||
2500 | iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0); | ||
2501 | iov_iter_advance(&ii, pos); | ||
2502 | |||
2503 | *copied = 0; | ||
2504 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2505 | ssize_t copy; | ||
2506 | |||
2507 | /* copy a whole page or whatever's left */ | ||
2508 | copy = min_t(ssize_t, remaining, PAGE_SIZE); | ||
2509 | |||
2510 | /* ...but limit it to whatever space is left in the iov */ | ||
2511 | copy = min_t(ssize_t, copy, iov_iter_count(&ii)); | ||
2512 | |||
2513 | /* go while there's data to be copied and no errors */ | ||
2514 | if (copy && !rc) { | ||
2515 | pdata = kmap(page); | ||
2516 | rc = memcpy_toiovecend(ii.iov, pdata, ii.iov_offset, | ||
2517 | (int)copy); | ||
2518 | kunmap(page); | ||
2519 | if (!rc) { | ||
2520 | *copied += copy; | ||
2521 | remaining -= copy; | ||
2522 | iov_iter_advance(&ii, copy); | ||
2523 | } | ||
2524 | } | ||
2525 | |||
2526 | list_del(&page->lru); | ||
2527 | put_page(page); | ||
2528 | } | ||
2529 | |||
2530 | return rc; | ||
2531 | } | ||
2532 | |||
2533 | static void | ||
2534 | cifs_uncached_readv_complete(struct work_struct *work) | ||
2535 | { | ||
2536 | struct cifs_readdata *rdata = container_of(work, | ||
2537 | struct cifs_readdata, work); | ||
2538 | |||
2539 | /* if the result is non-zero then the pages weren't kmapped */ | ||
2540 | if (rdata->result == 0) { | ||
2541 | struct page *page; | ||
2542 | |||
2543 | list_for_each_entry(page, &rdata->pages, lru) | ||
2544 | kunmap(page); | ||
2545 | } | ||
2546 | |||
2547 | complete(&rdata->done); | ||
2548 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | ||
2549 | } | ||
2550 | |||
2551 | static int | ||
2552 | cifs_uncached_read_marshal_iov(struct cifs_readdata *rdata, | ||
2553 | unsigned int remaining) | ||
2554 | { | ||
2555 | int len = 0; | ||
2556 | struct page *page, *tpage; | ||
2557 | |||
2558 | rdata->nr_iov = 1; | ||
2559 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2560 | if (remaining >= PAGE_SIZE) { | ||
2561 | /* enough data to fill the page */ | ||
2562 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2563 | rdata->iov[rdata->nr_iov].iov_len = PAGE_SIZE; | ||
2564 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2565 | rdata->nr_iov, page->index, | ||
2566 | rdata->iov[rdata->nr_iov].iov_base, | ||
2567 | rdata->iov[rdata->nr_iov].iov_len); | ||
2568 | ++rdata->nr_iov; | ||
2569 | len += PAGE_SIZE; | ||
2570 | remaining -= PAGE_SIZE; | ||
2571 | } else if (remaining > 0) { | ||
2572 | /* enough for partial page, fill and zero the rest */ | ||
2573 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2574 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
2575 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2576 | rdata->nr_iov, page->index, | ||
2577 | rdata->iov[rdata->nr_iov].iov_base, | ||
2578 | rdata->iov[rdata->nr_iov].iov_len); | ||
2579 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
2580 | '\0', PAGE_SIZE - remaining); | ||
2581 | ++rdata->nr_iov; | ||
2582 | len += remaining; | ||
2583 | remaining = 0; | ||
2584 | } else { | ||
2585 | /* no need to hold page hostage */ | ||
2586 | list_del(&page->lru); | ||
2587 | put_page(page); | ||
2588 | } | ||
2589 | } | ||
2590 | |||
2591 | return len; | ||
2592 | } | ||
2593 | |||
2342 | static ssize_t | 2594 | static ssize_t |
2343 | cifs_iovec_read(struct file *file, const struct iovec *iov, | 2595 | cifs_iovec_read(struct file *file, const struct iovec *iov, |
2344 | unsigned long nr_segs, loff_t *poffset) | 2596 | unsigned long nr_segs, loff_t *poffset) |
2345 | { | 2597 | { |
2346 | int rc; | 2598 | ssize_t rc; |
2347 | int xid; | ||
2348 | ssize_t total_read; | ||
2349 | unsigned int bytes_read = 0; | ||
2350 | size_t len, cur_len; | 2599 | size_t len, cur_len; |
2351 | int iov_offset = 0; | 2600 | ssize_t total_read = 0; |
2601 | loff_t offset = *poffset; | ||
2602 | unsigned int npages; | ||
2352 | struct cifs_sb_info *cifs_sb; | 2603 | struct cifs_sb_info *cifs_sb; |
2353 | struct cifs_tcon *pTcon; | 2604 | struct cifs_tcon *tcon; |
2354 | struct cifsFileInfo *open_file; | 2605 | struct cifsFileInfo *open_file; |
2355 | struct smb_com_read_rsp *pSMBr; | 2606 | struct cifs_readdata *rdata, *tmp; |
2356 | struct cifs_io_parms io_parms; | 2607 | struct list_head rdata_list; |
2357 | char *read_data; | 2608 | pid_t pid; |
2358 | unsigned int rsize; | ||
2359 | __u32 pid; | ||
2360 | 2609 | ||
2361 | if (!nr_segs) | 2610 | if (!nr_segs) |
2362 | return 0; | 2611 | return 0; |
@@ -2365,14 +2614,10 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, | |||
2365 | if (!len) | 2614 | if (!len) |
2366 | return 0; | 2615 | return 0; |
2367 | 2616 | ||
2368 | xid = GetXid(); | 2617 | INIT_LIST_HEAD(&rdata_list); |
2369 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2618 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
2370 | |||
2371 | /* FIXME: set up handlers for larger reads and/or convert to async */ | ||
2372 | rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize); | ||
2373 | |||
2374 | open_file = file->private_data; | 2619 | open_file = file->private_data; |
2375 | pTcon = tlink_tcon(open_file->tlink); | 2620 | tcon = tlink_tcon(open_file->tlink); |
2376 | 2621 | ||
2377 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | 2622 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
2378 | pid = open_file->pid; | 2623 | pid = open_file->pid; |
@@ -2382,56 +2627,78 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, | |||
2382 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 2627 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
2383 | cFYI(1, "attempting read on write only file instance"); | 2628 | cFYI(1, "attempting read on write only file instance"); |
2384 | 2629 | ||
2385 | for (total_read = 0; total_read < len; total_read += bytes_read) { | 2630 | do { |
2386 | cur_len = min_t(const size_t, len - total_read, rsize); | 2631 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); |
2387 | rc = -EAGAIN; | 2632 | npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); |
2388 | read_data = NULL; | ||
2389 | 2633 | ||
2390 | while (rc == -EAGAIN) { | 2634 | /* allocate a readdata struct */ |
2391 | int buf_type = CIFS_NO_BUFFER; | 2635 | rdata = cifs_readdata_alloc(npages, |
2392 | if (open_file->invalidHandle) { | 2636 | cifs_uncached_readv_complete); |
2393 | rc = cifs_reopen_file(open_file, true); | 2637 | if (!rdata) { |
2394 | if (rc != 0) | 2638 | rc = -ENOMEM; |
2395 | break; | 2639 | goto error; |
2396 | } | ||
2397 | io_parms.netfid = open_file->netfid; | ||
2398 | io_parms.pid = pid; | ||
2399 | io_parms.tcon = pTcon; | ||
2400 | io_parms.offset = *poffset; | ||
2401 | io_parms.length = cur_len; | ||
2402 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, | ||
2403 | &read_data, &buf_type); | ||
2404 | pSMBr = (struct smb_com_read_rsp *)read_data; | ||
2405 | if (read_data) { | ||
2406 | char *data_offset = read_data + 4 + | ||
2407 | le16_to_cpu(pSMBr->DataOffset); | ||
2408 | if (memcpy_toiovecend(iov, data_offset, | ||
2409 | iov_offset, bytes_read)) | ||
2410 | rc = -EFAULT; | ||
2411 | if (buf_type == CIFS_SMALL_BUFFER) | ||
2412 | cifs_small_buf_release(read_data); | ||
2413 | else if (buf_type == CIFS_LARGE_BUFFER) | ||
2414 | cifs_buf_release(read_data); | ||
2415 | read_data = NULL; | ||
2416 | iov_offset += bytes_read; | ||
2417 | } | ||
2418 | } | 2640 | } |
2419 | 2641 | ||
2420 | if (rc || (bytes_read == 0)) { | 2642 | rc = cifs_read_allocate_pages(&rdata->pages, npages); |
2421 | if (total_read) { | 2643 | if (rc) |
2422 | break; | 2644 | goto error; |
2423 | } else { | 2645 | |
2424 | FreeXid(xid); | 2646 | rdata->cfile = cifsFileInfo_get(open_file); |
2425 | return rc; | 2647 | rdata->offset = offset; |
2648 | rdata->bytes = cur_len; | ||
2649 | rdata->pid = pid; | ||
2650 | rdata->marshal_iov = cifs_uncached_read_marshal_iov; | ||
2651 | |||
2652 | rc = cifs_retry_async_readv(rdata); | ||
2653 | error: | ||
2654 | if (rc) { | ||
2655 | kref_put(&rdata->refcount, | ||
2656 | cifs_uncached_readdata_release); | ||
2657 | break; | ||
2658 | } | ||
2659 | |||
2660 | list_add_tail(&rdata->list, &rdata_list); | ||
2661 | offset += cur_len; | ||
2662 | len -= cur_len; | ||
2663 | } while (len > 0); | ||
2664 | |||
2665 | /* if at least one read request send succeeded, then reset rc */ | ||
2666 | if (!list_empty(&rdata_list)) | ||
2667 | rc = 0; | ||
2668 | |||
2669 | /* the loop below should proceed in the order of increasing offsets */ | ||
2670 | restart_loop: | ||
2671 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { | ||
2672 | if (!rc) { | ||
2673 | ssize_t copied; | ||
2674 | |||
2675 | /* FIXME: freezable sleep too? */ | ||
2676 | rc = wait_for_completion_killable(&rdata->done); | ||
2677 | if (rc) | ||
2678 | rc = -EINTR; | ||
2679 | else if (rdata->result) | ||
2680 | rc = rdata->result; | ||
2681 | else { | ||
2682 | rc = cifs_readdata_to_iov(rdata, iov, | ||
2683 | nr_segs, *poffset, | ||
2684 | &copied); | ||
2685 | total_read += copied; | ||
2686 | } | ||
2687 | |||
2688 | /* resend call if it's a retryable error */ | ||
2689 | if (rc == -EAGAIN) { | ||
2690 | rc = cifs_retry_async_readv(rdata); | ||
2691 | goto restart_loop; | ||
2426 | } | 2692 | } |
2427 | } else { | ||
2428 | cifs_stats_bytes_read(pTcon, bytes_read); | ||
2429 | *poffset += bytes_read; | ||
2430 | } | 2693 | } |
2694 | list_del_init(&rdata->list); | ||
2695 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | ||
2431 | } | 2696 | } |
2432 | 2697 | ||
2433 | FreeXid(xid); | 2698 | cifs_stats_bytes_read(tcon, total_read); |
2434 | return total_read; | 2699 | *poffset += total_read; |
2700 | |||
2701 | return total_read ? total_read : rc; | ||
2435 | } | 2702 | } |
2436 | 2703 | ||
2437 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, | 2704 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, |
@@ -2606,6 +2873,100 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
2606 | return rc; | 2873 | return rc; |
2607 | } | 2874 | } |
2608 | 2875 | ||
2876 | static void | ||
2877 | cifs_readv_complete(struct work_struct *work) | ||
2878 | { | ||
2879 | struct cifs_readdata *rdata = container_of(work, | ||
2880 | struct cifs_readdata, work); | ||
2881 | struct page *page, *tpage; | ||
2882 | |||
2883 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2884 | list_del(&page->lru); | ||
2885 | lru_cache_add_file(page); | ||
2886 | |||
2887 | if (rdata->result == 0) { | ||
2888 | kunmap(page); | ||
2889 | flush_dcache_page(page); | ||
2890 | SetPageUptodate(page); | ||
2891 | } | ||
2892 | |||
2893 | unlock_page(page); | ||
2894 | |||
2895 | if (rdata->result == 0) | ||
2896 | cifs_readpage_to_fscache(rdata->mapping->host, page); | ||
2897 | |||
2898 | page_cache_release(page); | ||
2899 | } | ||
2900 | kref_put(&rdata->refcount, cifs_readdata_release); | ||
2901 | } | ||
2902 | |||
2903 | static int | ||
2904 | cifs_readpages_marshal_iov(struct cifs_readdata *rdata, unsigned int remaining) | ||
2905 | { | ||
2906 | int len = 0; | ||
2907 | struct page *page, *tpage; | ||
2908 | u64 eof; | ||
2909 | pgoff_t eof_index; | ||
2910 | |||
2911 | /* determine the eof that the server (probably) has */ | ||
2912 | eof = CIFS_I(rdata->mapping->host)->server_eof; | ||
2913 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; | ||
2914 | cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index); | ||
2915 | |||
2916 | rdata->nr_iov = 1; | ||
2917 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2918 | if (remaining >= PAGE_CACHE_SIZE) { | ||
2919 | /* enough data to fill the page */ | ||
2920 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2921 | rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE; | ||
2922 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2923 | rdata->nr_iov, page->index, | ||
2924 | rdata->iov[rdata->nr_iov].iov_base, | ||
2925 | rdata->iov[rdata->nr_iov].iov_len); | ||
2926 | ++rdata->nr_iov; | ||
2927 | len += PAGE_CACHE_SIZE; | ||
2928 | remaining -= PAGE_CACHE_SIZE; | ||
2929 | } else if (remaining > 0) { | ||
2930 | /* enough for partial page, fill and zero the rest */ | ||
2931 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2932 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
2933 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2934 | rdata->nr_iov, page->index, | ||
2935 | rdata->iov[rdata->nr_iov].iov_base, | ||
2936 | rdata->iov[rdata->nr_iov].iov_len); | ||
2937 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
2938 | '\0', PAGE_CACHE_SIZE - remaining); | ||
2939 | ++rdata->nr_iov; | ||
2940 | len += remaining; | ||
2941 | remaining = 0; | ||
2942 | } else if (page->index > eof_index) { | ||
2943 | /* | ||
2944 | * The VFS will not try to do readahead past the | ||
2945 | * i_size, but it's possible that we have outstanding | ||
2946 | * writes with gaps in the middle and the i_size hasn't | ||
2947 | * caught up yet. Populate those with zeroed out pages | ||
2948 | * to prevent the VFS from repeatedly attempting to | ||
2949 | * fill them until the writes are flushed. | ||
2950 | */ | ||
2951 | zero_user(page, 0, PAGE_CACHE_SIZE); | ||
2952 | list_del(&page->lru); | ||
2953 | lru_cache_add_file(page); | ||
2954 | flush_dcache_page(page); | ||
2955 | SetPageUptodate(page); | ||
2956 | unlock_page(page); | ||
2957 | page_cache_release(page); | ||
2958 | } else { | ||
2959 | /* no need to hold page hostage */ | ||
2960 | list_del(&page->lru); | ||
2961 | lru_cache_add_file(page); | ||
2962 | unlock_page(page); | ||
2963 | page_cache_release(page); | ||
2964 | } | ||
2965 | } | ||
2966 | |||
2967 | return len; | ||
2968 | } | ||
2969 | |||
2609 | static int cifs_readpages(struct file *file, struct address_space *mapping, | 2970 | static int cifs_readpages(struct file *file, struct address_space *mapping, |
2610 | struct list_head *page_list, unsigned num_pages) | 2971 | struct list_head *page_list, unsigned num_pages) |
2611 | { | 2972 | { |
@@ -2708,7 +3069,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2708 | nr_pages++; | 3069 | nr_pages++; |
2709 | } | 3070 | } |
2710 | 3071 | ||
2711 | rdata = cifs_readdata_alloc(nr_pages); | 3072 | rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); |
2712 | if (!rdata) { | 3073 | if (!rdata) { |
2713 | /* best to give up if we're out of mem */ | 3074 | /* best to give up if we're out of mem */ |
2714 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { | 3075 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { |
@@ -2722,24 +3083,16 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2722 | } | 3083 | } |
2723 | 3084 | ||
2724 | spin_lock(&cifs_file_list_lock); | 3085 | spin_lock(&cifs_file_list_lock); |
2725 | cifsFileInfo_get(open_file); | ||
2726 | spin_unlock(&cifs_file_list_lock); | 3086 | spin_unlock(&cifs_file_list_lock); |
2727 | rdata->cfile = open_file; | 3087 | rdata->cfile = cifsFileInfo_get(open_file); |
2728 | rdata->mapping = mapping; | 3088 | rdata->mapping = mapping; |
2729 | rdata->offset = offset; | 3089 | rdata->offset = offset; |
2730 | rdata->bytes = bytes; | 3090 | rdata->bytes = bytes; |
2731 | rdata->pid = pid; | 3091 | rdata->pid = pid; |
3092 | rdata->marshal_iov = cifs_readpages_marshal_iov; | ||
2732 | list_splice_init(&tmplist, &rdata->pages); | 3093 | list_splice_init(&tmplist, &rdata->pages); |
2733 | 3094 | ||
2734 | do { | 3095 | rc = cifs_retry_async_readv(rdata); |
2735 | if (open_file->invalidHandle) { | ||
2736 | rc = cifs_reopen_file(open_file, true); | ||
2737 | if (rc != 0) | ||
2738 | continue; | ||
2739 | } | ||
2740 | rc = cifs_async_readv(rdata); | ||
2741 | } while (rc == -EAGAIN); | ||
2742 | |||
2743 | if (rc != 0) { | 3096 | if (rc != 0) { |
2744 | list_for_each_entry_safe(page, tpage, &rdata->pages, | 3097 | list_for_each_entry_safe(page, tpage, &rdata->pages, |
2745 | lru) { | 3098 | lru) { |
@@ -2748,9 +3101,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2748 | unlock_page(page); | 3101 | unlock_page(page); |
2749 | page_cache_release(page); | 3102 | page_cache_release(page); |
2750 | } | 3103 | } |
2751 | cifs_readdata_free(rdata); | 3104 | kref_put(&rdata->refcount, cifs_readdata_release); |
2752 | break; | 3105 | break; |
2753 | } | 3106 | } |
3107 | |||
3108 | kref_put(&rdata->refcount, cifs_readdata_release); | ||
2754 | } | 3109 | } |
2755 | 3110 | ||
2756 | return rc; | 3111 | return rc; |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 4221b5e48a42..6d2667f0c98c 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
@@ -51,7 +51,15 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
51 | cifs_sb = CIFS_SB(inode->i_sb); | 51 | cifs_sb = CIFS_SB(inode->i_sb); |
52 | 52 | ||
53 | switch (command) { | 53 | switch (command) { |
54 | static bool warned = false; | ||
54 | case CIFS_IOC_CHECKUMOUNT: | 55 | case CIFS_IOC_CHECKUMOUNT: |
56 | if (!warned) { | ||
57 | warned = true; | ||
58 | cERROR(1, "the CIFS_IOC_CHECKMOUNT ioctl will " | ||
59 | "be deprecated in 3.7. Please " | ||
60 | "migrate away from the use of " | ||
61 | "umount.cifs"); | ||
62 | } | ||
55 | cFYI(1, "User unmount attempted"); | 63 | cFYI(1, "User unmount attempted"); |
56 | if (cifs_sb->mnt_uid == current_uid()) | 64 | if (cifs_sb->mnt_uid == current_uid()) |
57 | rc = 0; | 65 | rc = 0; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index c29d1aa2c54f..557506ae1e2a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -212,93 +212,6 @@ cifs_small_buf_release(void *buf_to_free) | |||
212 | return; | 212 | return; |
213 | } | 213 | } |
214 | 214 | ||
215 | /* | ||
216 | * Find a free multiplex id (SMB mid). Otherwise there could be | ||
217 | * mid collisions which might cause problems, demultiplexing the | ||
218 | * wrong response to this request. Multiplex ids could collide if | ||
219 | * one of a series requests takes much longer than the others, or | ||
220 | * if a very large number of long lived requests (byte range | ||
221 | * locks or FindNotify requests) are pending. No more than | ||
222 | * 64K-1 requests can be outstanding at one time. If no | ||
223 | * mids are available, return zero. A future optimization | ||
224 | * could make the combination of mids and uid the key we use | ||
225 | * to demultiplex on (rather than mid alone). | ||
226 | * In addition to the above check, the cifs demultiplex | ||
227 | * code already used the command code as a secondary | ||
228 | * check of the frame and if signing is negotiated the | ||
229 | * response would be discarded if the mid were the same | ||
230 | * but the signature was wrong. Since the mid is not put in the | ||
231 | * pending queue until later (when it is about to be dispatched) | ||
232 | * we do have to limit the number of outstanding requests | ||
233 | * to somewhat less than 64K-1 although it is hard to imagine | ||
234 | * so many threads being in the vfs at one time. | ||
235 | */ | ||
236 | __u64 GetNextMid(struct TCP_Server_Info *server) | ||
237 | { | ||
238 | __u64 mid = 0; | ||
239 | __u16 last_mid, cur_mid; | ||
240 | bool collision; | ||
241 | |||
242 | spin_lock(&GlobalMid_Lock); | ||
243 | |||
244 | /* mid is 16 bit only for CIFS/SMB */ | ||
245 | cur_mid = (__u16)((server->CurrentMid) & 0xffff); | ||
246 | /* we do not want to loop forever */ | ||
247 | last_mid = cur_mid; | ||
248 | cur_mid++; | ||
249 | |||
250 | /* | ||
251 | * This nested loop looks more expensive than it is. | ||
252 | * In practice the list of pending requests is short, | ||
253 | * fewer than 50, and the mids are likely to be unique | ||
254 | * on the first pass through the loop unless some request | ||
255 | * takes longer than the 64 thousand requests before it | ||
256 | * (and it would also have to have been a request that | ||
257 | * did not time out). | ||
258 | */ | ||
259 | while (cur_mid != last_mid) { | ||
260 | struct mid_q_entry *mid_entry; | ||
261 | unsigned int num_mids; | ||
262 | |||
263 | collision = false; | ||
264 | if (cur_mid == 0) | ||
265 | cur_mid++; | ||
266 | |||
267 | num_mids = 0; | ||
268 | list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { | ||
269 | ++num_mids; | ||
270 | if (mid_entry->mid == cur_mid && | ||
271 | mid_entry->mid_state == MID_REQUEST_SUBMITTED) { | ||
272 | /* This mid is in use, try a different one */ | ||
273 | collision = true; | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * if we have more than 32k mids in the list, then something | ||
280 | * is very wrong. Possibly a local user is trying to DoS the | ||
281 | * box by issuing long-running calls and SIGKILL'ing them. If | ||
282 | * we get to 2^16 mids then we're in big trouble as this | ||
283 | * function could loop forever. | ||
284 | * | ||
285 | * Go ahead and assign out the mid in this situation, but force | ||
286 | * an eventual reconnect to clean out the pending_mid_q. | ||
287 | */ | ||
288 | if (num_mids > 32768) | ||
289 | server->tcpStatus = CifsNeedReconnect; | ||
290 | |||
291 | if (!collision) { | ||
292 | mid = (__u64)cur_mid; | ||
293 | server->CurrentMid = mid; | ||
294 | break; | ||
295 | } | ||
296 | cur_mid++; | ||
297 | } | ||
298 | spin_unlock(&GlobalMid_Lock); | ||
299 | return mid; | ||
300 | } | ||
301 | |||
302 | /* NB: MID can not be set if treeCon not passed in, in that | 215 | /* NB: MID can not be set if treeCon not passed in, in that |
303 | case it is responsbility of caller to set the mid */ | 216 | case it is responsbility of caller to set the mid */ |
304 | void | 217 | void |
@@ -306,8 +219,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
306 | const struct cifs_tcon *treeCon, int word_count | 219 | const struct cifs_tcon *treeCon, int word_count |
307 | /* length of fixed section (word count) in two byte units */) | 220 | /* length of fixed section (word count) in two byte units */) |
308 | { | 221 | { |
309 | struct list_head *temp_item; | ||
310 | struct cifs_ses *ses; | ||
311 | char *temp = (char *) buffer; | 222 | char *temp = (char *) buffer; |
312 | 223 | ||
313 | memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ | 224 | memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ |
@@ -336,52 +247,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
336 | 247 | ||
337 | /* Uid is not converted */ | 248 | /* Uid is not converted */ |
338 | buffer->Uid = treeCon->ses->Suid; | 249 | buffer->Uid = treeCon->ses->Suid; |
339 | buffer->Mid = GetNextMid(treeCon->ses->server); | 250 | buffer->Mid = get_next_mid(treeCon->ses->server); |
340 | if (multiuser_mount != 0) { | ||
341 | /* For the multiuser case, there are few obvious technically */ | ||
342 | /* possible mechanisms to match the local linux user (uid) */ | ||
343 | /* to a valid remote smb user (smb_uid): */ | ||
344 | /* 1) Query Winbind (or other local pam/nss daemon */ | ||
345 | /* for userid/password/logon_domain or credential */ | ||
346 | /* 2) Query Winbind for uid to sid to username mapping */ | ||
347 | /* and see if we have a matching password for existing*/ | ||
348 | /* session for that user perhas getting password by */ | ||
349 | /* adding a new pam_cifs module that stores passwords */ | ||
350 | /* so that the cifs vfs can get at that for all logged*/ | ||
351 | /* on users */ | ||
352 | /* 3) (Which is the mechanism we have chosen) */ | ||
353 | /* Search through sessions to the same server for a */ | ||
354 | /* a match on the uid that was passed in on mount */ | ||
355 | /* with the current processes uid (or euid?) and use */ | ||
356 | /* that smb uid. If no existing smb session for */ | ||
357 | /* that uid found, use the default smb session ie */ | ||
358 | /* the smb session for the volume mounted which is */ | ||
359 | /* the same as would be used if the multiuser mount */ | ||
360 | /* flag were disabled. */ | ||
361 | |||
362 | /* BB Add support for establishing new tCon and SMB Session */ | ||
363 | /* with userid/password pairs found on the smb session */ | ||
364 | /* for other target tcp/ip addresses BB */ | ||
365 | if (current_fsuid() != treeCon->ses->linux_uid) { | ||
366 | cFYI(1, "Multiuser mode and UID " | ||
367 | "did not match tcon uid"); | ||
368 | spin_lock(&cifs_tcp_ses_lock); | ||
369 | list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) { | ||
370 | ses = list_entry(temp_item, struct cifs_ses, smb_ses_list); | ||
371 | if (ses->linux_uid == current_fsuid()) { | ||
372 | if (ses->server == treeCon->ses->server) { | ||
373 | cFYI(1, "found matching uid substitute right smb_uid"); | ||
374 | buffer->Uid = ses->Suid; | ||
375 | break; | ||
376 | } else { | ||
377 | /* BB eventually call cifs_setup_session here */ | ||
378 | cFYI(1, "local UID found but no smb sess with this server exists"); | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | spin_unlock(&cifs_tcp_ses_lock); | ||
383 | } | ||
384 | } | ||
385 | } | 251 | } |
386 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) | 252 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) |
387 | buffer->Flags2 |= SMBFLG2_DFS; | 253 | buffer->Flags2 |= SMBFLG2_DFS; |
@@ -700,22 +566,3 @@ backup_cred(struct cifs_sb_info *cifs_sb) | |||
700 | 566 | ||
701 | return false; | 567 | return false; |
702 | } | 568 | } |
703 | |||
704 | void | ||
705 | cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add) | ||
706 | { | ||
707 | spin_lock(&server->req_lock); | ||
708 | server->credits += add; | ||
709 | server->in_flight--; | ||
710 | spin_unlock(&server->req_lock); | ||
711 | wake_up(&server->request_q); | ||
712 | } | ||
713 | |||
714 | void | ||
715 | cifs_set_credits(struct TCP_Server_Info *server, const int val) | ||
716 | { | ||
717 | spin_lock(&server->req_lock); | ||
718 | server->credits = val; | ||
719 | server->oplocks = val > 1 ? enable_oplocks : false; | ||
720 | spin_unlock(&server->req_lock); | ||
721 | } | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index e2bbc683e018..0a8224d1c4c5 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -219,6 +219,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | |||
219 | 219 | ||
220 | static int initiate_cifs_search(const int xid, struct file *file) | 220 | static int initiate_cifs_search(const int xid, struct file *file) |
221 | { | 221 | { |
222 | __u16 search_flags; | ||
222 | int rc = 0; | 223 | int rc = 0; |
223 | char *full_path = NULL; | 224 | char *full_path = NULL; |
224 | struct cifsFileInfo *cifsFile; | 225 | struct cifsFileInfo *cifsFile; |
@@ -270,8 +271,12 @@ ffirst_retry: | |||
270 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; | 271 | cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; |
271 | } | 272 | } |
272 | 273 | ||
274 | search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; | ||
275 | if (backup_cred(cifs_sb)) | ||
276 | search_flags |= CIFS_SEARCH_BACKUP_SEARCH; | ||
277 | |||
273 | rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls, | 278 | rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls, |
274 | &cifsFile->netfid, &cifsFile->srch_inf, | 279 | &cifsFile->netfid, search_flags, &cifsFile->srch_inf, |
275 | cifs_sb->mnt_cifs_flags & | 280 | cifs_sb->mnt_cifs_flags & |
276 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | 281 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); |
277 | if (rc == 0) | 282 | if (rc == 0) |
@@ -502,11 +507,13 @@ static int cifs_save_resume_key(const char *current_entry, | |||
502 | static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, | 507 | static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, |
503 | struct file *file, char **ppCurrentEntry, int *num_to_ret) | 508 | struct file *file, char **ppCurrentEntry, int *num_to_ret) |
504 | { | 509 | { |
510 | __u16 search_flags; | ||
505 | int rc = 0; | 511 | int rc = 0; |
506 | int pos_in_buf = 0; | 512 | int pos_in_buf = 0; |
507 | loff_t first_entry_in_buffer; | 513 | loff_t first_entry_in_buffer; |
508 | loff_t index_to_find = file->f_pos; | 514 | loff_t index_to_find = file->f_pos; |
509 | struct cifsFileInfo *cifsFile = file->private_data; | 515 | struct cifsFileInfo *cifsFile = file->private_data; |
516 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
510 | /* check if index in the buffer */ | 517 | /* check if index in the buffer */ |
511 | 518 | ||
512 | if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || | 519 | if ((cifsFile == NULL) || (ppCurrentEntry == NULL) || |
@@ -560,10 +567,14 @@ static int find_cifs_entry(const int xid, struct cifs_tcon *pTcon, | |||
560 | cifsFile); | 567 | cifsFile); |
561 | } | 568 | } |
562 | 569 | ||
570 | search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME; | ||
571 | if (backup_cred(cifs_sb)) | ||
572 | search_flags |= CIFS_SEARCH_BACKUP_SEARCH; | ||
573 | |||
563 | while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 574 | while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && |
564 | (rc == 0) && !cifsFile->srch_inf.endOfSearch) { | 575 | (rc == 0) && !cifsFile->srch_inf.endOfSearch) { |
565 | cFYI(1, "calling findnext2"); | 576 | cFYI(1, "calling findnext2"); |
566 | rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, | 577 | rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags, |
567 | &cifsFile->srch_inf); | 578 | &cifsFile->srch_inf); |
568 | /* FindFirst/Next set last_entry to NULL on malformed reply */ | 579 | /* FindFirst/Next set last_entry to NULL on malformed reply */ |
569 | if (cifsFile->srch_inf.last_entry) | 580 | if (cifsFile->srch_inf.last_entry) |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c new file mode 100644 index 000000000000..6dec38f5522d --- /dev/null +++ b/fs/cifs/smb1ops.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * SMB1 (CIFS) version specific operations | ||
3 | * | ||
4 | * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License v2 as published | ||
8 | * by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
13 | * the GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public License | ||
16 | * along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include "cifsglob.h" | ||
21 | #include "cifsproto.h" | ||
22 | #include "cifs_debug.h" | ||
23 | #include "cifspdu.h" | ||
24 | |||
25 | /* | ||
26 | * An NT cancel request header looks just like the original request except: | ||
27 | * | ||
28 | * The Command is SMB_COM_NT_CANCEL | ||
29 | * The WordCount is zeroed out | ||
30 | * The ByteCount is zeroed out | ||
31 | * | ||
32 | * This function mangles an existing request buffer into a | ||
33 | * SMB_COM_NT_CANCEL request and then sends it. | ||
34 | */ | ||
35 | static int | ||
36 | send_nt_cancel(struct TCP_Server_Info *server, void *buf, | ||
37 | struct mid_q_entry *mid) | ||
38 | { | ||
39 | int rc = 0; | ||
40 | struct smb_hdr *in_buf = (struct smb_hdr *)buf; | ||
41 | |||
42 | /* -4 for RFC1001 length and +2 for BCC field */ | ||
43 | in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); | ||
44 | in_buf->Command = SMB_COM_NT_CANCEL; | ||
45 | in_buf->WordCount = 0; | ||
46 | put_bcc(0, in_buf); | ||
47 | |||
48 | mutex_lock(&server->srv_mutex); | ||
49 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
50 | if (rc) { | ||
51 | mutex_unlock(&server->srv_mutex); | ||
52 | return rc; | ||
53 | } | ||
54 | rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); | ||
55 | mutex_unlock(&server->srv_mutex); | ||
56 | |||
57 | cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", | ||
58 | in_buf->Mid, rc); | ||
59 | |||
60 | return rc; | ||
61 | } | ||
62 | |||
63 | static bool | ||
64 | cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2) | ||
65 | { | ||
66 | return ob1->netfid == ob2->netfid; | ||
67 | } | ||
68 | |||
69 | static unsigned int | ||
70 | cifs_read_data_offset(char *buf) | ||
71 | { | ||
72 | READ_RSP *rsp = (READ_RSP *)buf; | ||
73 | return le16_to_cpu(rsp->DataOffset); | ||
74 | } | ||
75 | |||
76 | static unsigned int | ||
77 | cifs_read_data_length(char *buf) | ||
78 | { | ||
79 | READ_RSP *rsp = (READ_RSP *)buf; | ||
80 | return (le16_to_cpu(rsp->DataLengthHigh) << 16) + | ||
81 | le16_to_cpu(rsp->DataLength); | ||
82 | } | ||
83 | |||
84 | static struct mid_q_entry * | ||
85 | cifs_find_mid(struct TCP_Server_Info *server, char *buffer) | ||
86 | { | ||
87 | struct smb_hdr *buf = (struct smb_hdr *)buffer; | ||
88 | struct mid_q_entry *mid; | ||
89 | |||
90 | spin_lock(&GlobalMid_Lock); | ||
91 | list_for_each_entry(mid, &server->pending_mid_q, qhead) { | ||
92 | if (mid->mid == buf->Mid && | ||
93 | mid->mid_state == MID_REQUEST_SUBMITTED && | ||
94 | le16_to_cpu(mid->command) == buf->Command) { | ||
95 | spin_unlock(&GlobalMid_Lock); | ||
96 | return mid; | ||
97 | } | ||
98 | } | ||
99 | spin_unlock(&GlobalMid_Lock); | ||
100 | return NULL; | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add) | ||
105 | { | ||
106 | spin_lock(&server->req_lock); | ||
107 | server->credits += add; | ||
108 | server->in_flight--; | ||
109 | spin_unlock(&server->req_lock); | ||
110 | wake_up(&server->request_q); | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | cifs_set_credits(struct TCP_Server_Info *server, const int val) | ||
115 | { | ||
116 | spin_lock(&server->req_lock); | ||
117 | server->credits = val; | ||
118 | server->oplocks = val > 1 ? enable_oplocks : false; | ||
119 | spin_unlock(&server->req_lock); | ||
120 | } | ||
121 | |||
122 | static int * | ||
123 | cifs_get_credits_field(struct TCP_Server_Info *server) | ||
124 | { | ||
125 | return &server->credits; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Find a free multiplex id (SMB mid). Otherwise there could be | ||
130 | * mid collisions which might cause problems, demultiplexing the | ||
131 | * wrong response to this request. Multiplex ids could collide if | ||
132 | * one of a series requests takes much longer than the others, or | ||
133 | * if a very large number of long lived requests (byte range | ||
134 | * locks or FindNotify requests) are pending. No more than | ||
135 | * 64K-1 requests can be outstanding at one time. If no | ||
136 | * mids are available, return zero. A future optimization | ||
137 | * could make the combination of mids and uid the key we use | ||
138 | * to demultiplex on (rather than mid alone). | ||
139 | * In addition to the above check, the cifs demultiplex | ||
140 | * code already used the command code as a secondary | ||
141 | * check of the frame and if signing is negotiated the | ||
142 | * response would be discarded if the mid were the same | ||
143 | * but the signature was wrong. Since the mid is not put in the | ||
144 | * pending queue until later (when it is about to be dispatched) | ||
145 | * we do have to limit the number of outstanding requests | ||
146 | * to somewhat less than 64K-1 although it is hard to imagine | ||
147 | * so many threads being in the vfs at one time. | ||
148 | */ | ||
149 | static __u64 | ||
150 | cifs_get_next_mid(struct TCP_Server_Info *server) | ||
151 | { | ||
152 | __u64 mid = 0; | ||
153 | __u16 last_mid, cur_mid; | ||
154 | bool collision; | ||
155 | |||
156 | spin_lock(&GlobalMid_Lock); | ||
157 | |||
158 | /* mid is 16 bit only for CIFS/SMB */ | ||
159 | cur_mid = (__u16)((server->CurrentMid) & 0xffff); | ||
160 | /* we do not want to loop forever */ | ||
161 | last_mid = cur_mid; | ||
162 | cur_mid++; | ||
163 | |||
164 | /* | ||
165 | * This nested loop looks more expensive than it is. | ||
166 | * In practice the list of pending requests is short, | ||
167 | * fewer than 50, and the mids are likely to be unique | ||
168 | * on the first pass through the loop unless some request | ||
169 | * takes longer than the 64 thousand requests before it | ||
170 | * (and it would also have to have been a request that | ||
171 | * did not time out). | ||
172 | */ | ||
173 | while (cur_mid != last_mid) { | ||
174 | struct mid_q_entry *mid_entry; | ||
175 | unsigned int num_mids; | ||
176 | |||
177 | collision = false; | ||
178 | if (cur_mid == 0) | ||
179 | cur_mid++; | ||
180 | |||
181 | num_mids = 0; | ||
182 | list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { | ||
183 | ++num_mids; | ||
184 | if (mid_entry->mid == cur_mid && | ||
185 | mid_entry->mid_state == MID_REQUEST_SUBMITTED) { | ||
186 | /* This mid is in use, try a different one */ | ||
187 | collision = true; | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * if we have more than 32k mids in the list, then something | ||
194 | * is very wrong. Possibly a local user is trying to DoS the | ||
195 | * box by issuing long-running calls and SIGKILL'ing them. If | ||
196 | * we get to 2^16 mids then we're in big trouble as this | ||
197 | * function could loop forever. | ||
198 | * | ||
199 | * Go ahead and assign out the mid in this situation, but force | ||
200 | * an eventual reconnect to clean out the pending_mid_q. | ||
201 | */ | ||
202 | if (num_mids > 32768) | ||
203 | server->tcpStatus = CifsNeedReconnect; | ||
204 | |||
205 | if (!collision) { | ||
206 | mid = (__u64)cur_mid; | ||
207 | server->CurrentMid = mid; | ||
208 | break; | ||
209 | } | ||
210 | cur_mid++; | ||
211 | } | ||
212 | spin_unlock(&GlobalMid_Lock); | ||
213 | return mid; | ||
214 | } | ||
215 | |||
216 | struct smb_version_operations smb1_operations = { | ||
217 | .send_cancel = send_nt_cancel, | ||
218 | .compare_fids = cifs_compare_fids, | ||
219 | .setup_request = cifs_setup_request, | ||
220 | .check_receive = cifs_check_receive, | ||
221 | .add_credits = cifs_add_credits, | ||
222 | .set_credits = cifs_set_credits, | ||
223 | .get_credits_field = cifs_get_credits_field, | ||
224 | .get_next_mid = cifs_get_next_mid, | ||
225 | .read_data_offset = cifs_read_data_offset, | ||
226 | .read_data_length = cifs_read_data_length, | ||
227 | .map_error = map_smb_to_linux_error, | ||
228 | .find_mid = cifs_find_mid, | ||
229 | .check_message = checkSMB, | ||
230 | .dump_detail = cifs_dump_detail, | ||
231 | .is_oplock_break = is_valid_oplock_break, | ||
232 | }; | ||
233 | |||
234 | struct smb_version_values smb1_values = { | ||
235 | .version_string = SMB1_VERSION_STRING, | ||
236 | .large_lock_type = LOCKING_ANDX_LARGE_FILES, | ||
237 | .exclusive_lock_type = 0, | ||
238 | .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, | ||
239 | .unlock_lock_type = 0, | ||
240 | .header_size = sizeof(struct smb_hdr), | ||
241 | .max_header_size = MAX_CIFS_HDR_SIZE, | ||
242 | .read_rsp_size = sizeof(READ_RSP), | ||
243 | }; | ||
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c new file mode 100644 index 000000000000..f065e89756a1 --- /dev/null +++ b/fs/cifs/smb2ops.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * SMB2 version specific operations | ||
3 | * | ||
4 | * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com> | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License v2 as published | ||
8 | * by the Free Software Foundation. | ||
9 | * | ||
10 | * This library is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
13 | * the GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public License | ||
16 | * along with this library; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include "cifsglob.h" | ||
21 | |||
22 | struct smb_version_operations smb21_operations = { | ||
23 | }; | ||
24 | |||
25 | struct smb_version_values smb21_values = { | ||
26 | .version_string = SMB21_VERSION_STRING, | ||
27 | }; | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0961336513d5..3097ee58fd7d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -304,7 +304,8 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int optype, | |||
304 | static int | 304 | static int |
305 | wait_for_free_request(struct TCP_Server_Info *server, const int optype) | 305 | wait_for_free_request(struct TCP_Server_Info *server, const int optype) |
306 | { | 306 | { |
307 | return wait_for_free_credits(server, optype, get_credits_field(server)); | 307 | return wait_for_free_credits(server, optype, |
308 | server->ops->get_credits_field(server)); | ||
308 | } | 309 | } |
309 | 310 | ||
310 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, | 311 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, |
@@ -396,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
396 | rc = cifs_setup_async_request(server, iov, nvec, &mid); | 397 | rc = cifs_setup_async_request(server, iov, nvec, &mid); |
397 | if (rc) { | 398 | if (rc) { |
398 | mutex_unlock(&server->srv_mutex); | 399 | mutex_unlock(&server->srv_mutex); |
399 | cifs_add_credits(server, 1); | 400 | add_credits(server, 1); |
400 | wake_up(&server->request_q); | 401 | wake_up(&server->request_q); |
401 | return rc; | 402 | return rc; |
402 | } | 403 | } |
@@ -418,7 +419,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
418 | return rc; | 419 | return rc; |
419 | out_err: | 420 | out_err: |
420 | delete_mid(mid); | 421 | delete_mid(mid); |
421 | cifs_add_credits(server, 1); | 422 | add_credits(server, 1); |
422 | wake_up(&server->request_q); | 423 | wake_up(&server->request_q); |
423 | return rc; | 424 | return rc; |
424 | } | 425 | } |
@@ -483,41 +484,11 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) | |||
483 | return rc; | 484 | return rc; |
484 | } | 485 | } |
485 | 486 | ||
486 | /* | 487 | static inline int |
487 | * An NT cancel request header looks just like the original request except: | 488 | send_cancel(struct TCP_Server_Info *server, void *buf, struct mid_q_entry *mid) |
488 | * | ||
489 | * The Command is SMB_COM_NT_CANCEL | ||
490 | * The WordCount is zeroed out | ||
491 | * The ByteCount is zeroed out | ||
492 | * | ||
493 | * This function mangles an existing request buffer into a | ||
494 | * SMB_COM_NT_CANCEL request and then sends it. | ||
495 | */ | ||
496 | static int | ||
497 | send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
498 | struct mid_q_entry *mid) | ||
499 | { | 489 | { |
500 | int rc = 0; | 490 | return server->ops->send_cancel ? |
501 | 491 | server->ops->send_cancel(server, buf, mid) : 0; | |
502 | /* -4 for RFC1001 length and +2 for BCC field */ | ||
503 | in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); | ||
504 | in_buf->Command = SMB_COM_NT_CANCEL; | ||
505 | in_buf->WordCount = 0; | ||
506 | put_bcc(0, in_buf); | ||
507 | |||
508 | mutex_lock(&server->srv_mutex); | ||
509 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
510 | if (rc) { | ||
511 | mutex_unlock(&server->srv_mutex); | ||
512 | return rc; | ||
513 | } | ||
514 | rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); | ||
515 | mutex_unlock(&server->srv_mutex); | ||
516 | |||
517 | cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", | ||
518 | in_buf->Mid, rc); | ||
519 | |||
520 | return rc; | ||
521 | } | 492 | } |
522 | 493 | ||
523 | int | 494 | int |
@@ -544,7 +515,7 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, | |||
544 | return map_smb_to_linux_error(mid->resp_buf, log_error); | 515 | return map_smb_to_linux_error(mid->resp_buf, log_error); |
545 | } | 516 | } |
546 | 517 | ||
547 | static int | 518 | int |
548 | cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, | 519 | cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, |
549 | unsigned int nvec, struct mid_q_entry **ret_mid) | 520 | unsigned int nvec, struct mid_q_entry **ret_mid) |
550 | { | 521 | { |
@@ -607,12 +578,12 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
607 | 578 | ||
608 | mutex_lock(&ses->server->srv_mutex); | 579 | mutex_lock(&ses->server->srv_mutex); |
609 | 580 | ||
610 | rc = cifs_setup_request(ses, iov, n_vec, &midQ); | 581 | rc = ses->server->ops->setup_request(ses, iov, n_vec, &midQ); |
611 | if (rc) { | 582 | if (rc) { |
612 | mutex_unlock(&ses->server->srv_mutex); | 583 | mutex_unlock(&ses->server->srv_mutex); |
613 | cifs_small_buf_release(buf); | 584 | cifs_small_buf_release(buf); |
614 | /* Update # of requests on wire to server */ | 585 | /* Update # of requests on wire to server */ |
615 | cifs_add_credits(ses->server, 1); | 586 | add_credits(ses->server, 1); |
616 | return rc; | 587 | return rc; |
617 | } | 588 | } |
618 | 589 | ||
@@ -636,13 +607,13 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
636 | 607 | ||
637 | rc = wait_for_response(ses->server, midQ); | 608 | rc = wait_for_response(ses->server, midQ); |
638 | if (rc != 0) { | 609 | if (rc != 0) { |
639 | send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ); | 610 | send_cancel(ses->server, buf, midQ); |
640 | spin_lock(&GlobalMid_Lock); | 611 | spin_lock(&GlobalMid_Lock); |
641 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { | 612 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { |
642 | midQ->callback = DeleteMidQEntry; | 613 | midQ->callback = DeleteMidQEntry; |
643 | spin_unlock(&GlobalMid_Lock); | 614 | spin_unlock(&GlobalMid_Lock); |
644 | cifs_small_buf_release(buf); | 615 | cifs_small_buf_release(buf); |
645 | cifs_add_credits(ses->server, 1); | 616 | add_credits(ses->server, 1); |
646 | return rc; | 617 | return rc; |
647 | } | 618 | } |
648 | spin_unlock(&GlobalMid_Lock); | 619 | spin_unlock(&GlobalMid_Lock); |
@@ -652,7 +623,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
652 | 623 | ||
653 | rc = cifs_sync_mid_result(midQ, ses->server); | 624 | rc = cifs_sync_mid_result(midQ, ses->server); |
654 | if (rc != 0) { | 625 | if (rc != 0) { |
655 | cifs_add_credits(ses->server, 1); | 626 | add_credits(ses->server, 1); |
656 | return rc; | 627 | return rc; |
657 | } | 628 | } |
658 | 629 | ||
@@ -670,14 +641,15 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
670 | else | 641 | else |
671 | *pRespBufType = CIFS_SMALL_BUFFER; | 642 | *pRespBufType = CIFS_SMALL_BUFFER; |
672 | 643 | ||
673 | rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR); | 644 | rc = ses->server->ops->check_receive(midQ, ses->server, |
645 | flags & CIFS_LOG_ERROR); | ||
674 | 646 | ||
675 | /* mark it so buf will not be freed by delete_mid */ | 647 | /* mark it so buf will not be freed by delete_mid */ |
676 | if ((flags & CIFS_NO_RESP) == 0) | 648 | if ((flags & CIFS_NO_RESP) == 0) |
677 | midQ->resp_buf = NULL; | 649 | midQ->resp_buf = NULL; |
678 | out: | 650 | out: |
679 | delete_mid(midQ); | 651 | delete_mid(midQ); |
680 | cifs_add_credits(ses->server, 1); | 652 | add_credits(ses->server, 1); |
681 | 653 | ||
682 | return rc; | 654 | return rc; |
683 | } | 655 | } |
@@ -727,7 +699,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
727 | if (rc) { | 699 | if (rc) { |
728 | mutex_unlock(&ses->server->srv_mutex); | 700 | mutex_unlock(&ses->server->srv_mutex); |
729 | /* Update # of requests on wire to server */ | 701 | /* Update # of requests on wire to server */ |
730 | cifs_add_credits(ses->server, 1); | 702 | add_credits(ses->server, 1); |
731 | return rc; | 703 | return rc; |
732 | } | 704 | } |
733 | 705 | ||
@@ -753,13 +725,13 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
753 | 725 | ||
754 | rc = wait_for_response(ses->server, midQ); | 726 | rc = wait_for_response(ses->server, midQ); |
755 | if (rc != 0) { | 727 | if (rc != 0) { |
756 | send_nt_cancel(ses->server, in_buf, midQ); | 728 | send_cancel(ses->server, in_buf, midQ); |
757 | spin_lock(&GlobalMid_Lock); | 729 | spin_lock(&GlobalMid_Lock); |
758 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { | 730 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { |
759 | /* no longer considered to be "in-flight" */ | 731 | /* no longer considered to be "in-flight" */ |
760 | midQ->callback = DeleteMidQEntry; | 732 | midQ->callback = DeleteMidQEntry; |
761 | spin_unlock(&GlobalMid_Lock); | 733 | spin_unlock(&GlobalMid_Lock); |
762 | cifs_add_credits(ses->server, 1); | 734 | add_credits(ses->server, 1); |
763 | return rc; | 735 | return rc; |
764 | } | 736 | } |
765 | spin_unlock(&GlobalMid_Lock); | 737 | spin_unlock(&GlobalMid_Lock); |
@@ -767,7 +739,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
767 | 739 | ||
768 | rc = cifs_sync_mid_result(midQ, ses->server); | 740 | rc = cifs_sync_mid_result(midQ, ses->server); |
769 | if (rc != 0) { | 741 | if (rc != 0) { |
770 | cifs_add_credits(ses->server, 1); | 742 | add_credits(ses->server, 1); |
771 | return rc; | 743 | return rc; |
772 | } | 744 | } |
773 | 745 | ||
@@ -783,7 +755,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
783 | rc = cifs_check_receive(midQ, ses->server, 0); | 755 | rc = cifs_check_receive(midQ, ses->server, 0); |
784 | out: | 756 | out: |
785 | delete_mid(midQ); | 757 | delete_mid(midQ); |
786 | cifs_add_credits(ses->server, 1); | 758 | add_credits(ses->server, 1); |
787 | 759 | ||
788 | return rc; | 760 | return rc; |
789 | } | 761 | } |
@@ -807,7 +779,7 @@ send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon, | |||
807 | 779 | ||
808 | pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; | 780 | pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; |
809 | pSMB->Timeout = 0; | 781 | pSMB->Timeout = 0; |
810 | pSMB->hdr.Mid = GetNextMid(ses->server); | 782 | pSMB->hdr.Mid = get_next_mid(ses->server); |
811 | 783 | ||
812 | return SendReceive(xid, ses, in_buf, out_buf, | 784 | return SendReceive(xid, ses, in_buf, out_buf, |
813 | &bytes_returned, 0); | 785 | &bytes_returned, 0); |
@@ -898,7 +870,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
898 | if (in_buf->Command == SMB_COM_TRANSACTION2) { | 870 | if (in_buf->Command == SMB_COM_TRANSACTION2) { |
899 | /* POSIX lock. We send a NT_CANCEL SMB to cause the | 871 | /* POSIX lock. We send a NT_CANCEL SMB to cause the |
900 | blocking lock to return. */ | 872 | blocking lock to return. */ |
901 | rc = send_nt_cancel(ses->server, in_buf, midQ); | 873 | rc = send_cancel(ses->server, in_buf, midQ); |
902 | if (rc) { | 874 | if (rc) { |
903 | delete_mid(midQ); | 875 | delete_mid(midQ); |
904 | return rc; | 876 | return rc; |
@@ -919,7 +891,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
919 | 891 | ||
920 | rc = wait_for_response(ses->server, midQ); | 892 | rc = wait_for_response(ses->server, midQ); |
921 | if (rc) { | 893 | if (rc) { |
922 | send_nt_cancel(ses->server, in_buf, midQ); | 894 | send_cancel(ses->server, in_buf, midQ); |
923 | spin_lock(&GlobalMid_Lock); | 895 | spin_lock(&GlobalMid_Lock); |
924 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { | 896 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { |
925 | /* no longer considered to be "in-flight" */ | 897 | /* no longer considered to be "in-flight" */ |