diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-29 15:42:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-29 15:42:10 -0400 |
commit | 442a9ffabb21f175027e93e72ea05159818271a6 (patch) | |
tree | c9c708a36c8af91389527dbf310ef8ee2c4e3409 /fs/cifs | |
parent | 4b781474682434e7881f20e9dfbe6687ea619795 (diff) | |
parent | 2c0c2a08bed7a3b791f88d09d16ace56acb3dd98 (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS updates from Steve French.
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6: (29 commits)
cifs: fix oops while traversing open file list (try #4)
cifs: Fix comment as d_alloc_root() is replaced by d_make_root()
CIFS: Introduce SMB2 mounts as vers=2.1
CIFS: Introduce SMB2 Kconfig option
CIFS: Move add/set_credits and get_credits_field to ops structure
CIFS: Move protocol specific demultiplex thread calls to ops struct
CIFS: Move protocol specific part from cifs_readv_receive to ops struct
CIFS: Move header_size/max_header_size to ops structure
CIFS: Move protocol specific part from SendReceive2 to ops struct
cifs: Include backup intent search flags during searches {try #2)
CIFS: Separate protocol specific part from setlk
CIFS: Separate protocol specific part from getlk
CIFS: Separate protocol specific lock type handling
CIFS: Convert lock type to 32 bit variable
CIFS: Move locks to cifsFileInfo structure
cifs: convert send_nt_cancel into a version specific op
cifs: add a smb_version_operations/values structures and a smb_version enum
cifs: remove the vers= and version= synonyms for ver=
cifs: add warning about change in default cache semantics in 3.7
cifs: display cache= option in /proc/mounts
...
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 | 23 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 107 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 19 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 181 | ||||
-rw-r--r-- | fs/cifs/connect.c | 178 | ||||
-rw-r--r-- | fs/cifs/file.c | 683 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 8 | ||||
-rw-r--r-- | fs/cifs/misc.c | 66 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 15 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 154 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 27 | ||||
-rw-r--r-- | fs/cifs/transport.c | 76 |
17 files changed, 1039 insertions, 587 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 0a0fa0250e99..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 |
@@ -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..20350a93ed99 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,57 @@ 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 | /* data offset from read response message */ | ||
178 | unsigned int (*read_data_offset)(char *); | ||
179 | /* data length from read response message */ | ||
180 | unsigned int (*read_data_length)(char *); | ||
181 | /* map smb to linux error */ | ||
182 | int (*map_error)(char *, bool); | ||
183 | /* find mid corresponding to the response message */ | ||
184 | struct mid_q_entry * (*find_mid)(struct TCP_Server_Info *, char *); | ||
185 | void (*dump_detail)(void *); | ||
186 | /* verify the message */ | ||
187 | int (*check_message)(char *, unsigned int); | ||
188 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); | ||
189 | }; | ||
190 | |||
191 | struct smb_version_values { | ||
192 | char *version_string; | ||
193 | __u32 large_lock_type; | ||
194 | __u32 exclusive_lock_type; | ||
195 | __u32 shared_lock_type; | ||
196 | __u32 unlock_lock_type; | ||
197 | size_t header_size; | ||
198 | size_t max_header_size; | ||
199 | size_t read_rsp_size; | ||
200 | }; | ||
201 | |||
202 | #define HEADER_SIZE(server) (server->vals->header_size) | ||
203 | #define MAX_HEADER_SIZE(server) (server->vals->max_header_size) | ||
204 | |||
153 | struct smb_vol { | 205 | struct smb_vol { |
154 | char *username; | 206 | char *username; |
155 | char *password; | 207 | char *password; |
@@ -205,6 +257,8 @@ struct smb_vol { | |||
205 | bool sockopt_tcp_nodelay:1; | 257 | bool sockopt_tcp_nodelay:1; |
206 | unsigned short int port; | 258 | unsigned short int port; |
207 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | 259 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ |
260 | struct smb_version_operations *ops; | ||
261 | struct smb_version_values *vals; | ||
208 | char *prepath; | 262 | char *prepath; |
209 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | 263 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ |
210 | struct nls_table *local_nls; | 264 | struct nls_table *local_nls; |
@@ -242,6 +296,8 @@ struct TCP_Server_Info { | |||
242 | int srv_count; /* reference counter */ | 296 | int srv_count; /* reference counter */ |
243 | /* 15 character server name + 0x20 16th byte indicating type = srv */ | 297 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
244 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 298 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
299 | struct smb_version_operations *ops; | ||
300 | struct smb_version_values *vals; | ||
245 | enum statusEnum tcpStatus; /* what we think the status is */ | 301 | enum statusEnum tcpStatus; /* what we think the status is */ |
246 | char *hostname; /* hostname portion of UNC string */ | 302 | char *hostname; /* hostname portion of UNC string */ |
247 | struct socket *ssocket; | 303 | struct socket *ssocket; |
@@ -321,16 +377,6 @@ in_flight(struct TCP_Server_Info *server) | |||
321 | return num; | 377 | return num; |
322 | } | 378 | } |
323 | 379 | ||
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 | 380 | static inline bool |
335 | has_credits(struct TCP_Server_Info *server, int *credits) | 381 | has_credits(struct TCP_Server_Info *server, int *credits) |
336 | { | 382 | { |
@@ -341,16 +387,16 @@ has_credits(struct TCP_Server_Info *server, int *credits) | |||
341 | return num > 0; | 387 | return num > 0; |
342 | } | 388 | } |
343 | 389 | ||
344 | static inline size_t | 390 | static inline void |
345 | header_size(void) | 391 | add_credits(struct TCP_Server_Info *server, const unsigned int add) |
346 | { | 392 | { |
347 | return sizeof(struct smb_hdr); | 393 | server->ops->add_credits(server, add); |
348 | } | 394 | } |
349 | 395 | ||
350 | static inline size_t | 396 | static inline void |
351 | max_header_size(void) | 397 | set_credits(struct TCP_Server_Info *server, const int val) |
352 | { | 398 | { |
353 | return MAX_CIFS_HDR_SIZE; | 399 | server->ops->set_credits(server, val); |
354 | } | 400 | } |
355 | 401 | ||
356 | /* | 402 | /* |
@@ -547,8 +593,7 @@ struct cifsLockInfo { | |||
547 | __u64 offset; | 593 | __u64 offset; |
548 | __u64 length; | 594 | __u64 length; |
549 | __u32 pid; | 595 | __u32 pid; |
550 | __u8 type; | 596 | __u32 type; |
551 | __u16 netfid; | ||
552 | }; | 597 | }; |
553 | 598 | ||
554 | /* | 599 | /* |
@@ -573,6 +618,10 @@ struct cifs_search_info { | |||
573 | struct cifsFileInfo { | 618 | struct cifsFileInfo { |
574 | struct list_head tlist; /* pointer to next fid owned by tcon */ | 619 | struct list_head tlist; /* pointer to next fid owned by tcon */ |
575 | struct list_head flist; /* next fid (file instance) for this inode */ | 620 | struct list_head flist; /* next fid (file instance) for this inode */ |
621 | struct list_head llist; /* | ||
622 | * brlocks held by this fid, protected by | ||
623 | * lock_mutex from cifsInodeInfo structure | ||
624 | */ | ||
576 | unsigned int uid; /* allows finding which FileInfo structure */ | 625 | unsigned int uid; /* allows finding which FileInfo structure */ |
577 | __u32 pid; /* process id who opened file */ | 626 | __u32 pid; /* process id who opened file */ |
578 | __u16 netfid; /* file id from remote */ | 627 | __u16 netfid; /* file id from remote */ |
@@ -615,9 +664,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); | |||
615 | */ | 664 | */ |
616 | 665 | ||
617 | struct cifsInodeInfo { | 666 | struct cifsInodeInfo { |
618 | struct list_head llist; /* brlocks for this inode */ | ||
619 | bool can_cache_brlcks; | 667 | bool can_cache_brlcks; |
620 | struct mutex lock_mutex; /* protect two fields above */ | 668 | struct mutex lock_mutex; /* |
669 | * protect the field above and llist | ||
670 | * from every cifsFileInfo structure | ||
671 | * from openFileList | ||
672 | */ | ||
621 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ | 673 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ |
622 | struct list_head openFileList; | 674 | struct list_head openFileList; |
623 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 675 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
@@ -703,7 +755,6 @@ static inline void cifs_stats_bytes_read(struct cifs_tcon *tcon, | |||
703 | 755 | ||
704 | #endif | 756 | #endif |
705 | 757 | ||
706 | struct mid_q_entry; | ||
707 | 758 | ||
708 | /* | 759 | /* |
709 | * This is the prototype for the mid receive function. This function is for | 760 | * This is the prototype for the mid receive function. This function is for |
@@ -1042,12 +1093,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount; | |||
1042 | GLOBAL_EXTERN atomic_t midCount; | 1093 | GLOBAL_EXTERN atomic_t midCount; |
1043 | 1094 | ||
1044 | /* Misc globals */ | 1095 | /* Misc globals */ |
1045 | GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions | 1096 | 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; | 1097 | GLOBAL_EXTERN unsigned int lookupCacheEnabled; |
1052 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent | 1098 | GLOBAL_EXTERN unsigned int global_secflags; /* if on, session setup sent |
1053 | with more secure ntlmssp2 challenge/resp */ | 1099 | with more secure ntlmssp2 challenge/resp */ |
@@ -1074,4 +1120,11 @@ void cifs_oplock_break(struct work_struct *work); | |||
1074 | extern const struct slow_work_ops cifs_oplock_break_ops; | 1120 | extern const struct slow_work_ops cifs_oplock_break_ops; |
1075 | extern struct workqueue_struct *cifsiod_wq; | 1121 | extern struct workqueue_struct *cifsiod_wq; |
1076 | 1122 | ||
1123 | /* Operations for different SMB versions */ | ||
1124 | #define SMB1_VERSION_STRING "1.0" | ||
1125 | extern struct smb_version_operations smb1_operations; | ||
1126 | extern struct smb_version_values smb1_values; | ||
1127 | #define SMB21_VERSION_STRING "2.1" | ||
1128 | extern struct smb_version_operations smb21_operations; | ||
1129 | extern struct smb_version_values smb21_values; | ||
1077 | #endif /* _CIFS_GLOB_H */ | 1130 | #endif /* _CIFS_GLOB_H */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 96192c1e380a..5ec21ecf7980 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 *); |
@@ -192,11 +191,13 @@ extern int CIFSTCon(unsigned int xid, struct cifs_ses *ses, | |||
192 | 191 | ||
193 | extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, | 192 | extern int CIFSFindFirst(const int xid, struct cifs_tcon *tcon, |
194 | const char *searchName, const struct nls_table *nls_codepage, | 193 | const char *searchName, const struct nls_table *nls_codepage, |
195 | __u16 *searchHandle, struct cifs_search_info *psrch_inf, | 194 | __u16 *searchHandle, __u16 search_flags, |
195 | struct cifs_search_info *psrch_inf, | ||
196 | int map, const char dirsep); | 196 | int map, const char dirsep); |
197 | 197 | ||
198 | extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon, | 198 | extern int CIFSFindNext(const int xid, struct cifs_tcon *tcon, |
199 | __u16 searchHandle, struct cifs_search_info *psrch_inf); | 199 | __u16 searchHandle, __u16 search_flags, |
200 | struct cifs_search_info *psrch_inf); | ||
200 | 201 | ||
201 | extern int CIFSFindClose(const int, struct cifs_tcon *tcon, | 202 | extern int CIFSFindClose(const int, struct cifs_tcon *tcon, |
202 | const __u16 search_handle); | 203 | const __u16 search_handle); |
@@ -464,6 +465,9 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, | |||
464 | 465 | ||
465 | /* asynchronous read support */ | 466 | /* asynchronous read support */ |
466 | struct cifs_readdata { | 467 | struct cifs_readdata { |
468 | struct kref refcount; | ||
469 | struct list_head list; | ||
470 | struct completion done; | ||
467 | struct cifsFileInfo *cfile; | 471 | struct cifsFileInfo *cfile; |
468 | struct address_space *mapping; | 472 | struct address_space *mapping; |
469 | __u64 offset; | 473 | __u64 offset; |
@@ -472,12 +476,13 @@ struct cifs_readdata { | |||
472 | int result; | 476 | int result; |
473 | struct list_head pages; | 477 | struct list_head pages; |
474 | struct work_struct work; | 478 | struct work_struct work; |
479 | int (*marshal_iov) (struct cifs_readdata *rdata, | ||
480 | unsigned int remaining); | ||
475 | unsigned int nr_iov; | 481 | unsigned int nr_iov; |
476 | struct kvec iov[1]; | 482 | struct kvec iov[1]; |
477 | }; | 483 | }; |
478 | 484 | ||
479 | struct cifs_readdata *cifs_readdata_alloc(unsigned int nr_pages); | 485 | 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); | 486 | int cifs_async_readv(struct cifs_readdata *rdata); |
482 | 487 | ||
483 | /* asynchronous write support */ | 488 | /* asynchronous write support */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index da2f5446fa7a..b5ad716b2642 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 */ |
@@ -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 |
@@ -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; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e0b56d7a19c5..ccafdedd0dbc 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,13 @@ 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(buf, server)) { |
1061 | cERROR(1, "No task to wake, unknown frame received! " | 1062 | cERROR(1, "No task to wake, unknown frame received! " |
1062 | "NumMids %d", atomic_read(&midCount)); | 1063 | "NumMids %d", atomic_read(&midCount)); |
1063 | cifs_dump_mem("Received Data is: ", buf, header_size()); | 1064 | cifs_dump_mem("Received Data is: ", buf, |
1065 | HEADER_SIZE(server)); | ||
1064 | #ifdef CONFIG_CIFS_DEBUG2 | 1066 | #ifdef CONFIG_CIFS_DEBUG2 |
1065 | cifs_dump_detail(buf); | 1067 | server->ops->dump_detail(buf); |
1066 | cifs_dump_mids(server); | 1068 | cifs_dump_mids(server); |
1067 | #endif /* CIFS_DEBUG2 */ | 1069 | #endif /* CIFS_DEBUG2 */ |
1068 | 1070 | ||
@@ -1186,6 +1188,54 @@ static int cifs_parse_security_flavors(char *value, | |||
1186 | } | 1188 | } |
1187 | 1189 | ||
1188 | static int | 1190 | static int |
1191 | cifs_parse_cache_flavor(char *value, struct smb_vol *vol) | ||
1192 | { | ||
1193 | substring_t args[MAX_OPT_ARGS]; | ||
1194 | |||
1195 | switch (match_token(value, cifs_cacheflavor_tokens, args)) { | ||
1196 | case Opt_cache_loose: | ||
1197 | vol->direct_io = false; | ||
1198 | vol->strict_io = false; | ||
1199 | break; | ||
1200 | case Opt_cache_strict: | ||
1201 | vol->direct_io = false; | ||
1202 | vol->strict_io = true; | ||
1203 | break; | ||
1204 | case Opt_cache_none: | ||
1205 | vol->direct_io = true; | ||
1206 | vol->strict_io = false; | ||
1207 | break; | ||
1208 | default: | ||
1209 | cERROR(1, "bad cache= option: %s", value); | ||
1210 | return 1; | ||
1211 | } | ||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static int | ||
1216 | cifs_parse_smb_version(char *value, struct smb_vol *vol) | ||
1217 | { | ||
1218 | substring_t args[MAX_OPT_ARGS]; | ||
1219 | |||
1220 | switch (match_token(value, cifs_smb_version_tokens, args)) { | ||
1221 | case Smb_1: | ||
1222 | vol->ops = &smb1_operations; | ||
1223 | vol->vals = &smb1_values; | ||
1224 | break; | ||
1225 | #ifdef CONFIG_CIFS_SMB2 | ||
1226 | case Smb_21: | ||
1227 | vol->ops = &smb21_operations; | ||
1228 | vol->vals = &smb21_values; | ||
1229 | break; | ||
1230 | #endif | ||
1231 | default: | ||
1232 | cERROR(1, "Unknown vers= option specified: %s", value); | ||
1233 | return 1; | ||
1234 | } | ||
1235 | return 0; | ||
1236 | } | ||
1237 | |||
1238 | static int | ||
1189 | cifs_parse_mount_options(const char *mountdata, const char *devname, | 1239 | cifs_parse_mount_options(const char *mountdata, const char *devname, |
1190 | struct smb_vol *vol) | 1240 | struct smb_vol *vol) |
1191 | { | 1241 | { |
@@ -1203,6 +1253,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1203 | char *string = NULL; | 1253 | char *string = NULL; |
1204 | char *tmp_end, *value; | 1254 | char *tmp_end, *value; |
1205 | char delim; | 1255 | char delim; |
1256 | bool cache_specified = false; | ||
1257 | static bool cache_warned = false; | ||
1206 | 1258 | ||
1207 | separator[0] = ','; | 1259 | separator[0] = ','; |
1208 | separator[1] = 0; | 1260 | separator[1] = 0; |
@@ -1236,6 +1288,10 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1236 | 1288 | ||
1237 | vol->actimeo = CIFS_DEF_ACTIMEO; | 1289 | vol->actimeo = CIFS_DEF_ACTIMEO; |
1238 | 1290 | ||
1291 | /* FIXME: add autonegotiation -- for now, SMB1 is default */ | ||
1292 | vol->ops = &smb1_operations; | ||
1293 | vol->vals = &smb1_values; | ||
1294 | |||
1239 | if (!mountdata) | 1295 | if (!mountdata) |
1240 | goto cifs_parse_mount_err; | 1296 | goto cifs_parse_mount_err; |
1241 | 1297 | ||
@@ -1414,10 +1470,20 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1414 | vol->seal = 1; | 1470 | vol->seal = 1; |
1415 | break; | 1471 | break; |
1416 | case Opt_direct: | 1472 | case Opt_direct: |
1417 | vol->direct_io = 1; | 1473 | cache_specified = true; |
1474 | vol->direct_io = true; | ||
1475 | vol->strict_io = false; | ||
1476 | cERROR(1, "The \"directio\" option will be removed in " | ||
1477 | "3.7. Please switch to the \"cache=none\" " | ||
1478 | "option."); | ||
1418 | break; | 1479 | break; |
1419 | case Opt_strictcache: | 1480 | case Opt_strictcache: |
1420 | vol->strict_io = 1; | 1481 | cache_specified = true; |
1482 | vol->direct_io = false; | ||
1483 | vol->strict_io = true; | ||
1484 | cERROR(1, "The \"strictcache\" option will be removed " | ||
1485 | "in 3.7. Please switch to the \"cache=strict\" " | ||
1486 | "option."); | ||
1421 | break; | 1487 | break; |
1422 | case Opt_noac: | 1488 | case Opt_noac: |
1423 | printk(KERN_WARNING "CIFS: Mount option noac not " | 1489 | printk(KERN_WARNING "CIFS: Mount option noac not " |
@@ -1821,8 +1887,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1821 | if (string == NULL) | 1887 | if (string == NULL) |
1822 | goto out_nomem; | 1888 | goto out_nomem; |
1823 | 1889 | ||
1824 | if (strnicmp(string, "cifs", 4) == 0 || | 1890 | if (strnicmp(string, "1", 1) == 0) { |
1825 | strnicmp(string, "1", 1) == 0) { | ||
1826 | /* This is the default */ | 1891 | /* This is the default */ |
1827 | break; | 1892 | break; |
1828 | } | 1893 | } |
@@ -1830,6 +1895,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1830 | printk(KERN_WARNING "CIFS: Invalid version" | 1895 | printk(KERN_WARNING "CIFS: Invalid version" |
1831 | " specified\n"); | 1896 | " specified\n"); |
1832 | goto cifs_parse_mount_err; | 1897 | goto cifs_parse_mount_err; |
1898 | case Opt_vers: | ||
1899 | string = match_strdup(args); | ||
1900 | if (string == NULL) | ||
1901 | goto out_nomem; | ||
1902 | |||
1903 | if (cifs_parse_smb_version(string, vol) != 0) | ||
1904 | goto cifs_parse_mount_err; | ||
1905 | break; | ||
1833 | case Opt_sec: | 1906 | case Opt_sec: |
1834 | string = match_strdup(args); | 1907 | string = match_strdup(args); |
1835 | if (string == NULL) | 1908 | if (string == NULL) |
@@ -1838,6 +1911,15 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1838 | if (cifs_parse_security_flavors(string, vol) != 0) | 1911 | if (cifs_parse_security_flavors(string, vol) != 0) |
1839 | goto cifs_parse_mount_err; | 1912 | goto cifs_parse_mount_err; |
1840 | break; | 1913 | break; |
1914 | case Opt_cache: | ||
1915 | cache_specified = true; | ||
1916 | string = match_strdup(args); | ||
1917 | if (string == NULL) | ||
1918 | goto out_nomem; | ||
1919 | |||
1920 | if (cifs_parse_cache_flavor(string, vol) != 0) | ||
1921 | goto cifs_parse_mount_err; | ||
1922 | break; | ||
1841 | default: | 1923 | default: |
1842 | /* | 1924 | /* |
1843 | * An option we don't recognize. Save it off for later | 1925 | * An option we don't recognize. Save it off for later |
@@ -1881,6 +1963,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1881 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " | 1963 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " |
1882 | "specified with no gid= option.\n"); | 1964 | "specified with no gid= option.\n"); |
1883 | 1965 | ||
1966 | /* FIXME: remove this block in 3.7 */ | ||
1967 | if (!cache_specified && !cache_warned) { | ||
1968 | cache_warned = true; | ||
1969 | printk(KERN_NOTICE "CIFS: no cache= option specified, using " | ||
1970 | "\"cache=loose\". This default will change " | ||
1971 | "to \"cache=strict\" in 3.7.\n"); | ||
1972 | } | ||
1973 | |||
1884 | kfree(mountdata_copy); | 1974 | kfree(mountdata_copy); |
1885 | return 0; | 1975 | return 0; |
1886 | 1976 | ||
@@ -2041,6 +2131,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, | 2131 | static int match_server(struct TCP_Server_Info *server, struct sockaddr *addr, |
2042 | struct smb_vol *vol) | 2132 | struct smb_vol *vol) |
2043 | { | 2133 | { |
2134 | if ((server->vals != vol->vals) || (server->ops != vol->ops)) | ||
2135 | return 0; | ||
2136 | |||
2044 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) | 2137 | if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns)) |
2045 | return 0; | 2138 | return 0; |
2046 | 2139 | ||
@@ -2163,6 +2256,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
2163 | goto out_err; | 2256 | goto out_err; |
2164 | } | 2257 | } |
2165 | 2258 | ||
2259 | tcp_ses->ops = volume_info->ops; | ||
2260 | tcp_ses->vals = volume_info->vals; | ||
2166 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); | 2261 | cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns)); |
2167 | tcp_ses->hostname = extract_hostname(volume_info->UNC); | 2262 | tcp_ses->hostname = extract_hostname(volume_info->UNC); |
2168 | if (IS_ERR(tcp_ses->hostname)) { | 2263 | if (IS_ERR(tcp_ses->hostname)) { |
@@ -3569,6 +3664,7 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, | |||
3569 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) | 3664 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) |
3570 | return -EINVAL; | 3665 | return -EINVAL; |
3571 | 3666 | ||
3667 | |||
3572 | if (volume_info->nullauth) { | 3668 | if (volume_info->nullauth) { |
3573 | cFYI(1, "Anonymous login"); | 3669 | cFYI(1, "Anonymous login"); |
3574 | kfree(volume_info->username); | 3670 | kfree(volume_info->username); |
@@ -4010,11 +4106,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) | |||
4010 | if (server->maxBuf != 0) | 4106 | if (server->maxBuf != 0) |
4011 | return 0; | 4107 | return 0; |
4012 | 4108 | ||
4013 | cifs_set_credits(server, 1); | 4109 | set_credits(server, 1); |
4014 | rc = CIFSSMBNegotiate(xid, ses); | 4110 | rc = CIFSSMBNegotiate(xid, ses); |
4015 | if (rc == -EAGAIN) { | 4111 | if (rc == -EAGAIN) { |
4016 | /* retry only once on 1st time connection */ | 4112 | /* retry only once on 1st time connection */ |
4017 | cifs_set_credits(server, 1); | 4113 | set_credits(server, 1); |
4018 | rc = CIFSSMBNegotiate(xid, ses); | 4114 | rc = CIFSSMBNegotiate(xid, ses); |
4019 | if (rc == -EAGAIN) | 4115 | if (rc == -EAGAIN) |
4020 | rc = -EHOSTDOWN; | 4116 | rc = -EHOSTDOWN; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 81725e9286e9..253170dfa716 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 | } |
@@ -888,7 +904,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
888 | for (i = 0; i < 2; i++) { | 904 | for (i = 0; i < 2; i++) { |
889 | cur = buf; | 905 | cur = buf; |
890 | num = 0; | 906 | num = 0; |
891 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | 907 | list_for_each_entry_safe(li, tmp, &cfile->llist, llist) { |
892 | if (li->type != types[i]) | 908 | if (li->type != types[i]) |
893 | continue; | 909 | continue; |
894 | cur->Pid = cpu_to_le16(li->pid); | 910 | cur->Pid = cpu_to_le16(li->pid); |
@@ -898,7 +914,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
898 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); | 914 | cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); |
899 | if (++num == max_num) { | 915 | if (++num == max_num) { |
900 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | 916 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, |
901 | li->type, 0, num, buf); | 917 | (__u8)li->type, 0, num, |
918 | buf); | ||
902 | if (stored_rc) | 919 | if (stored_rc) |
903 | rc = stored_rc; | 920 | rc = stored_rc; |
904 | cur = buf; | 921 | cur = buf; |
@@ -909,7 +926,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | |||
909 | 926 | ||
910 | if (num) { | 927 | if (num) { |
911 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | 928 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, |
912 | types[i], 0, num, buf); | 929 | (__u8)types[i], 0, num, buf); |
913 | if (stored_rc) | 930 | if (stored_rc) |
914 | rc = stored_rc; | 931 | rc = stored_rc; |
915 | } | 932 | } |
@@ -1053,8 +1070,8 @@ cifs_push_locks(struct cifsFileInfo *cfile) | |||
1053 | } | 1070 | } |
1054 | 1071 | ||
1055 | static void | 1072 | static void |
1056 | cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, | 1073 | cifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock, |
1057 | bool *wait_flag) | 1074 | bool *wait_flag, struct TCP_Server_Info *server) |
1058 | { | 1075 | { |
1059 | if (flock->fl_flags & FL_POSIX) | 1076 | if (flock->fl_flags & FL_POSIX) |
1060 | cFYI(1, "Posix"); | 1077 | cFYI(1, "Posix"); |
@@ -1073,38 +1090,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))) | 1090 | (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) |
1074 | cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags); | 1091 | cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags); |
1075 | 1092 | ||
1076 | *type = LOCKING_ANDX_LARGE_FILES; | 1093 | *type = server->vals->large_lock_type; |
1077 | if (flock->fl_type == F_WRLCK) { | 1094 | if (flock->fl_type == F_WRLCK) { |
1078 | cFYI(1, "F_WRLCK "); | 1095 | cFYI(1, "F_WRLCK "); |
1096 | *type |= server->vals->exclusive_lock_type; | ||
1079 | *lock = 1; | 1097 | *lock = 1; |
1080 | } else if (flock->fl_type == F_UNLCK) { | 1098 | } else if (flock->fl_type == F_UNLCK) { |
1081 | cFYI(1, "F_UNLCK"); | 1099 | cFYI(1, "F_UNLCK"); |
1100 | *type |= server->vals->unlock_lock_type; | ||
1082 | *unlock = 1; | 1101 | *unlock = 1; |
1083 | /* Check if unlock includes more than one lock range */ | 1102 | /* Check if unlock includes more than one lock range */ |
1084 | } else if (flock->fl_type == F_RDLCK) { | 1103 | } else if (flock->fl_type == F_RDLCK) { |
1085 | cFYI(1, "F_RDLCK"); | 1104 | cFYI(1, "F_RDLCK"); |
1086 | *type |= LOCKING_ANDX_SHARED_LOCK; | 1105 | *type |= server->vals->shared_lock_type; |
1087 | *lock = 1; | 1106 | *lock = 1; |
1088 | } else if (flock->fl_type == F_EXLCK) { | 1107 | } else if (flock->fl_type == F_EXLCK) { |
1089 | cFYI(1, "F_EXLCK"); | 1108 | cFYI(1, "F_EXLCK"); |
1109 | *type |= server->vals->exclusive_lock_type; | ||
1090 | *lock = 1; | 1110 | *lock = 1; |
1091 | } else if (flock->fl_type == F_SHLCK) { | 1111 | } else if (flock->fl_type == F_SHLCK) { |
1092 | cFYI(1, "F_SHLCK"); | 1112 | cFYI(1, "F_SHLCK"); |
1093 | *type |= LOCKING_ANDX_SHARED_LOCK; | 1113 | *type |= server->vals->shared_lock_type; |
1094 | *lock = 1; | 1114 | *lock = 1; |
1095 | } else | 1115 | } else |
1096 | cFYI(1, "Unknown type of lock"); | 1116 | cFYI(1, "Unknown type of lock"); |
1097 | } | 1117 | } |
1098 | 1118 | ||
1099 | static int | 1119 | static int |
1100 | cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | 1120 | cifs_mandatory_lock(int xid, struct cifsFileInfo *cfile, __u64 offset, |
1121 | __u64 length, __u32 type, int lock, int unlock, bool wait) | ||
1122 | { | ||
1123 | return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid, | ||
1124 | current->tgid, length, offset, unlock, lock, | ||
1125 | (__u8)type, wait, 0); | ||
1126 | } | ||
1127 | |||
1128 | static int | ||
1129 | cifs_getlk(struct file *file, struct file_lock *flock, __u32 type, | ||
1101 | bool wait_flag, bool posix_lck, int xid) | 1130 | bool wait_flag, bool posix_lck, int xid) |
1102 | { | 1131 | { |
1103 | int rc = 0; | 1132 | int rc = 0; |
1104 | __u64 length = 1 + flock->fl_end - flock->fl_start; | 1133 | __u64 length = 1 + flock->fl_end - flock->fl_start; |
1105 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 1134 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
1106 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1135 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1107 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 1136 | struct TCP_Server_Info *server = tcon->ses->server; |
1108 | __u16 netfid = cfile->netfid; | 1137 | __u16 netfid = cfile->netfid; |
1109 | 1138 | ||
1110 | if (posix_lck) { | 1139 | if (posix_lck) { |
@@ -1114,7 +1143,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1114 | if (!rc) | 1143 | if (!rc) |
1115 | return rc; | 1144 | return rc; |
1116 | 1145 | ||
1117 | if (type & LOCKING_ANDX_SHARED_LOCK) | 1146 | if (type & server->vals->shared_lock_type) |
1118 | posix_lock_type = CIFS_RDLCK; | 1147 | posix_lock_type = CIFS_RDLCK; |
1119 | else | 1148 | else |
1120 | posix_lock_type = CIFS_WRLCK; | 1149 | posix_lock_type = CIFS_WRLCK; |
@@ -1124,38 +1153,35 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1124 | return rc; | 1153 | return rc; |
1125 | } | 1154 | } |
1126 | 1155 | ||
1127 | rc = cifs_lock_test(cinode, flock->fl_start, length, type, netfid, | 1156 | rc = cifs_lock_test(cfile, flock->fl_start, length, type, flock); |
1128 | flock); | ||
1129 | if (!rc) | 1157 | if (!rc) |
1130 | return rc; | 1158 | return rc; |
1131 | 1159 | ||
1132 | /* BB we could chain these into one lock request BB */ | 1160 | /* BB we could chain these into one lock request BB */ |
1133 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1161 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, type, |
1134 | flock->fl_start, 0, 1, type, 0, 0); | 1162 | 1, 0, false); |
1135 | if (rc == 0) { | 1163 | if (rc == 0) { |
1136 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, | 1164 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1137 | length, flock->fl_start, 1, 0, | 1165 | type, 0, 1, false); |
1138 | type, 0, 0); | ||
1139 | flock->fl_type = F_UNLCK; | 1166 | flock->fl_type = F_UNLCK; |
1140 | if (rc != 0) | 1167 | if (rc != 0) |
1141 | cERROR(1, "Error unlocking previously locked " | 1168 | cERROR(1, "Error unlocking previously locked " |
1142 | "range %d during test of lock", rc); | 1169 | "range %d during test of lock", rc); |
1143 | return 0; | 1170 | return 0; |
1144 | } | 1171 | } |
1145 | 1172 | ||
1146 | if (type & LOCKING_ANDX_SHARED_LOCK) { | 1173 | if (type & server->vals->shared_lock_type) { |
1147 | flock->fl_type = F_WRLCK; | 1174 | flock->fl_type = F_WRLCK; |
1148 | return 0; | 1175 | return 0; |
1149 | } | 1176 | } |
1150 | 1177 | ||
1151 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1178 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1152 | flock->fl_start, 0, 1, | 1179 | type | server->vals->shared_lock_type, 1, 0, |
1153 | type | LOCKING_ANDX_SHARED_LOCK, 0, 0); | 1180 | false); |
1154 | if (rc == 0) { | 1181 | if (rc == 0) { |
1155 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, | 1182 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1156 | length, flock->fl_start, 1, 0, | 1183 | type | server->vals->shared_lock_type, |
1157 | type | LOCKING_ANDX_SHARED_LOCK, | 1184 | 0, 1, false); |
1158 | 0, 0); | ||
1159 | flock->fl_type = F_RDLCK; | 1185 | flock->fl_type = F_RDLCK; |
1160 | if (rc != 0) | 1186 | if (rc != 0) |
1161 | cERROR(1, "Error unlocking previously locked " | 1187 | cERROR(1, "Error unlocking previously locked " |
@@ -1212,15 +1238,13 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1212 | for (i = 0; i < 2; i++) { | 1238 | for (i = 0; i < 2; i++) { |
1213 | cur = buf; | 1239 | cur = buf; |
1214 | num = 0; | 1240 | num = 0; |
1215 | list_for_each_entry_safe(li, tmp, &cinode->llist, llist) { | 1241 | list_for_each_entry_safe(li, tmp, &cfile->llist, llist) { |
1216 | if (flock->fl_start > li->offset || | 1242 | if (flock->fl_start > li->offset || |
1217 | (flock->fl_start + length) < | 1243 | (flock->fl_start + length) < |
1218 | (li->offset + li->length)) | 1244 | (li->offset + li->length)) |
1219 | continue; | 1245 | continue; |
1220 | if (current->tgid != li->pid) | 1246 | if (current->tgid != li->pid) |
1221 | continue; | 1247 | continue; |
1222 | if (cfile->netfid != li->netfid) | ||
1223 | continue; | ||
1224 | if (types[i] != li->type) | 1248 | if (types[i] != li->type) |
1225 | continue; | 1249 | continue; |
1226 | if (!cinode->can_cache_brlcks) { | 1250 | if (!cinode->can_cache_brlcks) { |
@@ -1233,7 +1257,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1233 | cpu_to_le32((u32)(li->offset>>32)); | 1257 | cpu_to_le32((u32)(li->offset>>32)); |
1234 | /* | 1258 | /* |
1235 | * We need to save a lock here to let us add | 1259 | * We need to save a lock here to let us add |
1236 | * it again to the inode list if the unlock | 1260 | * it again to the file's list if the unlock |
1237 | * range request fails on the server. | 1261 | * range request fails on the server. |
1238 | */ | 1262 | */ |
1239 | list_move(&li->llist, &tmp_llist); | 1263 | list_move(&li->llist, &tmp_llist); |
@@ -1247,10 +1271,10 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1247 | * We failed on the unlock range | 1271 | * We failed on the unlock range |
1248 | * request - add all locks from | 1272 | * request - add all locks from |
1249 | * the tmp list to the head of | 1273 | * the tmp list to the head of |
1250 | * the inode list. | 1274 | * the file's list. |
1251 | */ | 1275 | */ |
1252 | cifs_move_llist(&tmp_llist, | 1276 | cifs_move_llist(&tmp_llist, |
1253 | &cinode->llist); | 1277 | &cfile->llist); |
1254 | rc = stored_rc; | 1278 | rc = stored_rc; |
1255 | } else | 1279 | } else |
1256 | /* | 1280 | /* |
@@ -1265,7 +1289,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1265 | } else { | 1289 | } else { |
1266 | /* | 1290 | /* |
1267 | * We can cache brlock requests - simply remove | 1291 | * We can cache brlock requests - simply remove |
1268 | * a lock from the inode list. | 1292 | * a lock from the file's list. |
1269 | */ | 1293 | */ |
1270 | list_del(&li->llist); | 1294 | list_del(&li->llist); |
1271 | cifs_del_lock_waiters(li); | 1295 | cifs_del_lock_waiters(li); |
@@ -1276,7 +1300,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1276 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, | 1300 | stored_rc = cifs_lockv(xid, tcon, cfile->netfid, |
1277 | types[i], num, 0, buf); | 1301 | types[i], num, 0, buf); |
1278 | if (stored_rc) { | 1302 | if (stored_rc) { |
1279 | cifs_move_llist(&tmp_llist, &cinode->llist); | 1303 | cifs_move_llist(&tmp_llist, &cfile->llist); |
1280 | rc = stored_rc; | 1304 | rc = stored_rc; |
1281 | } else | 1305 | } else |
1282 | cifs_free_llist(&tmp_llist); | 1306 | cifs_free_llist(&tmp_llist); |
@@ -1289,14 +1313,14 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, int xid) | |||
1289 | } | 1313 | } |
1290 | 1314 | ||
1291 | static int | 1315 | static int |
1292 | cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | 1316 | cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, |
1293 | bool wait_flag, bool posix_lck, int lock, int unlock, int xid) | 1317 | bool wait_flag, bool posix_lck, int lock, int unlock, int xid) |
1294 | { | 1318 | { |
1295 | int rc = 0; | 1319 | int rc = 0; |
1296 | __u64 length = 1 + flock->fl_end - flock->fl_start; | 1320 | __u64 length = 1 + flock->fl_end - flock->fl_start; |
1297 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | 1321 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; |
1298 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | 1322 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); |
1299 | struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode); | 1323 | struct TCP_Server_Info *server = tcon->ses->server; |
1300 | __u16 netfid = cfile->netfid; | 1324 | __u16 netfid = cfile->netfid; |
1301 | 1325 | ||
1302 | if (posix_lck) { | 1326 | if (posix_lck) { |
@@ -1306,7 +1330,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1306 | if (!rc || rc < 0) | 1330 | if (!rc || rc < 0) |
1307 | return rc; | 1331 | return rc; |
1308 | 1332 | ||
1309 | if (type & LOCKING_ANDX_SHARED_LOCK) | 1333 | if (type & server->vals->shared_lock_type) |
1310 | posix_lock_type = CIFS_RDLCK; | 1334 | posix_lock_type = CIFS_RDLCK; |
1311 | else | 1335 | else |
1312 | posix_lock_type = CIFS_WRLCK; | 1336 | posix_lock_type = CIFS_WRLCK; |
@@ -1323,24 +1347,24 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1323 | if (lock) { | 1347 | if (lock) { |
1324 | struct cifsLockInfo *lock; | 1348 | struct cifsLockInfo *lock; |
1325 | 1349 | ||
1326 | lock = cifs_lock_init(flock->fl_start, length, type, netfid); | 1350 | lock = cifs_lock_init(flock->fl_start, length, type); |
1327 | if (!lock) | 1351 | if (!lock) |
1328 | return -ENOMEM; | 1352 | return -ENOMEM; |
1329 | 1353 | ||
1330 | rc = cifs_lock_add_if(cinode, lock, wait_flag); | 1354 | rc = cifs_lock_add_if(cfile, lock, wait_flag); |
1331 | if (rc < 0) | 1355 | if (rc < 0) |
1332 | kfree(lock); | 1356 | kfree(lock); |
1333 | if (rc <= 0) | 1357 | if (rc <= 0) |
1334 | goto out; | 1358 | goto out; |
1335 | 1359 | ||
1336 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1360 | rc = cifs_mandatory_lock(xid, cfile, flock->fl_start, length, |
1337 | flock->fl_start, 0, 1, type, wait_flag, 0); | 1361 | type, 1, 0, wait_flag); |
1338 | if (rc) { | 1362 | if (rc) { |
1339 | kfree(lock); | 1363 | kfree(lock); |
1340 | goto out; | 1364 | goto out; |
1341 | } | 1365 | } |
1342 | 1366 | ||
1343 | cifs_lock_add(cinode, lock); | 1367 | cifs_lock_add(cfile, lock); |
1344 | } else if (unlock) | 1368 | } else if (unlock) |
1345 | rc = cifs_unlock_range(cfile, flock, xid); | 1369 | rc = cifs_unlock_range(cfile, flock, xid); |
1346 | 1370 | ||
@@ -1361,7 +1385,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
1361 | struct cifsInodeInfo *cinode; | 1385 | struct cifsInodeInfo *cinode; |
1362 | struct cifsFileInfo *cfile; | 1386 | struct cifsFileInfo *cfile; |
1363 | __u16 netfid; | 1387 | __u16 netfid; |
1364 | __u8 type; | 1388 | __u32 type; |
1365 | 1389 | ||
1366 | rc = -EACCES; | 1390 | rc = -EACCES; |
1367 | xid = GetXid(); | 1391 | xid = GetXid(); |
@@ -1370,11 +1394,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
1370 | "end: %lld", cmd, flock->fl_flags, flock->fl_type, | 1394 | "end: %lld", cmd, flock->fl_flags, flock->fl_type, |
1371 | flock->fl_start, flock->fl_end); | 1395 | flock->fl_start, flock->fl_end); |
1372 | 1396 | ||
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; | 1397 | cfile = (struct cifsFileInfo *)file->private_data; |
1377 | tcon = tlink_tcon(cfile->tlink); | 1398 | tcon = tlink_tcon(cfile->tlink); |
1399 | |||
1400 | cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag, | ||
1401 | tcon->ses->server); | ||
1402 | |||
1403 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
1378 | netfid = cfile->netfid; | 1404 | netfid = cfile->netfid; |
1379 | cinode = CIFS_I(file->f_path.dentry->d_inode); | 1405 | cinode = CIFS_I(file->f_path.dentry->d_inode); |
1380 | 1406 | ||
@@ -1539,10 +1565,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
1539 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | 1565 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, |
1540 | bool fsuid_only) | 1566 | bool fsuid_only) |
1541 | { | 1567 | { |
1542 | struct cifsFileInfo *open_file; | 1568 | struct cifsFileInfo *open_file, *inv_file = NULL; |
1543 | struct cifs_sb_info *cifs_sb; | 1569 | struct cifs_sb_info *cifs_sb; |
1544 | bool any_available = false; | 1570 | bool any_available = false; |
1545 | int rc; | 1571 | int rc; |
1572 | unsigned int refind = 0; | ||
1546 | 1573 | ||
1547 | /* Having a null inode here (because mapping->host was set to zero by | 1574 | /* 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 | 1575 | the VFS or MM) should not happen but we had reports of on oops (due to |
@@ -1562,40 +1589,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1562 | 1589 | ||
1563 | spin_lock(&cifs_file_list_lock); | 1590 | spin_lock(&cifs_file_list_lock); |
1564 | refind_writable: | 1591 | refind_writable: |
1592 | if (refind > MAX_REOPEN_ATT) { | ||
1593 | spin_unlock(&cifs_file_list_lock); | ||
1594 | return NULL; | ||
1595 | } | ||
1565 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1596 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1566 | if (!any_available && open_file->pid != current->tgid) | 1597 | if (!any_available && open_file->pid != current->tgid) |
1567 | continue; | 1598 | continue; |
1568 | if (fsuid_only && open_file->uid != current_fsuid()) | 1599 | if (fsuid_only && open_file->uid != current_fsuid()) |
1569 | continue; | 1600 | continue; |
1570 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { | 1601 | if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { |
1571 | cifsFileInfo_get(open_file); | ||
1572 | |||
1573 | if (!open_file->invalidHandle) { | 1602 | if (!open_file->invalidHandle) { |
1574 | /* found a good writable file */ | 1603 | /* found a good writable file */ |
1604 | cifsFileInfo_get(open_file); | ||
1575 | spin_unlock(&cifs_file_list_lock); | 1605 | spin_unlock(&cifs_file_list_lock); |
1576 | return open_file; | 1606 | return open_file; |
1607 | } else { | ||
1608 | if (!inv_file) | ||
1609 | inv_file = open_file; | ||
1577 | } | 1610 | } |
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 | } | 1611 | } |
1600 | } | 1612 | } |
1601 | /* couldn't find useable FH with same pid, try any available */ | 1613 | /* couldn't find useable FH with same pid, try any available */ |
@@ -1603,7 +1615,30 @@ refind_writable: | |||
1603 | any_available = true; | 1615 | any_available = true; |
1604 | goto refind_writable; | 1616 | goto refind_writable; |
1605 | } | 1617 | } |
1618 | |||
1619 | if (inv_file) { | ||
1620 | any_available = false; | ||
1621 | cifsFileInfo_get(inv_file); | ||
1622 | } | ||
1623 | |||
1606 | spin_unlock(&cifs_file_list_lock); | 1624 | spin_unlock(&cifs_file_list_lock); |
1625 | |||
1626 | if (inv_file) { | ||
1627 | rc = cifs_reopen_file(inv_file, false); | ||
1628 | if (!rc) | ||
1629 | return inv_file; | ||
1630 | else { | ||
1631 | spin_lock(&cifs_file_list_lock); | ||
1632 | list_move_tail(&inv_file->flist, | ||
1633 | &cifs_inode->openFileList); | ||
1634 | spin_unlock(&cifs_file_list_lock); | ||
1635 | cifsFileInfo_put(inv_file); | ||
1636 | spin_lock(&cifs_file_list_lock); | ||
1637 | ++refind; | ||
1638 | goto refind_writable; | ||
1639 | } | ||
1640 | } | ||
1641 | |||
1607 | return NULL; | 1642 | return NULL; |
1608 | } | 1643 | } |
1609 | 1644 | ||
@@ -2339,24 +2374,224 @@ ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2339 | return cifs_user_writev(iocb, iov, nr_segs, pos); | 2374 | return cifs_user_writev(iocb, iov, nr_segs, pos); |
2340 | } | 2375 | } |
2341 | 2376 | ||
2377 | static struct cifs_readdata * | ||
2378 | cifs_readdata_alloc(unsigned int nr_vecs, work_func_t complete) | ||
2379 | { | ||
2380 | struct cifs_readdata *rdata; | ||
2381 | |||
2382 | rdata = kzalloc(sizeof(*rdata) + | ||
2383 | sizeof(struct kvec) * nr_vecs, GFP_KERNEL); | ||
2384 | if (rdata != NULL) { | ||
2385 | kref_init(&rdata->refcount); | ||
2386 | INIT_LIST_HEAD(&rdata->list); | ||
2387 | init_completion(&rdata->done); | ||
2388 | INIT_WORK(&rdata->work, complete); | ||
2389 | INIT_LIST_HEAD(&rdata->pages); | ||
2390 | } | ||
2391 | return rdata; | ||
2392 | } | ||
2393 | |||
2394 | void | ||
2395 | cifs_readdata_release(struct kref *refcount) | ||
2396 | { | ||
2397 | struct cifs_readdata *rdata = container_of(refcount, | ||
2398 | struct cifs_readdata, refcount); | ||
2399 | |||
2400 | if (rdata->cfile) | ||
2401 | cifsFileInfo_put(rdata->cfile); | ||
2402 | |||
2403 | kfree(rdata); | ||
2404 | } | ||
2405 | |||
2406 | static int | ||
2407 | cifs_read_allocate_pages(struct list_head *list, unsigned int npages) | ||
2408 | { | ||
2409 | int rc = 0; | ||
2410 | struct page *page, *tpage; | ||
2411 | unsigned int i; | ||
2412 | |||
2413 | for (i = 0; i < npages; i++) { | ||
2414 | page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); | ||
2415 | if (!page) { | ||
2416 | rc = -ENOMEM; | ||
2417 | break; | ||
2418 | } | ||
2419 | list_add(&page->lru, list); | ||
2420 | } | ||
2421 | |||
2422 | if (rc) { | ||
2423 | list_for_each_entry_safe(page, tpage, list, lru) { | ||
2424 | list_del(&page->lru); | ||
2425 | put_page(page); | ||
2426 | } | ||
2427 | } | ||
2428 | return rc; | ||
2429 | } | ||
2430 | |||
2431 | static void | ||
2432 | cifs_uncached_readdata_release(struct kref *refcount) | ||
2433 | { | ||
2434 | struct page *page, *tpage; | ||
2435 | struct cifs_readdata *rdata = container_of(refcount, | ||
2436 | struct cifs_readdata, refcount); | ||
2437 | |||
2438 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2439 | list_del(&page->lru); | ||
2440 | put_page(page); | ||
2441 | } | ||
2442 | cifs_readdata_release(refcount); | ||
2443 | } | ||
2444 | |||
2445 | static int | ||
2446 | cifs_retry_async_readv(struct cifs_readdata *rdata) | ||
2447 | { | ||
2448 | int rc; | ||
2449 | |||
2450 | do { | ||
2451 | if (rdata->cfile->invalidHandle) { | ||
2452 | rc = cifs_reopen_file(rdata->cfile, true); | ||
2453 | if (rc != 0) | ||
2454 | continue; | ||
2455 | } | ||
2456 | rc = cifs_async_readv(rdata); | ||
2457 | } while (rc == -EAGAIN); | ||
2458 | |||
2459 | return rc; | ||
2460 | } | ||
2461 | |||
2462 | /** | ||
2463 | * cifs_readdata_to_iov - copy data from pages in response to an iovec | ||
2464 | * @rdata: the readdata response with list of pages holding data | ||
2465 | * @iov: vector in which we should copy the data | ||
2466 | * @nr_segs: number of segments in vector | ||
2467 | * @offset: offset into file of the first iovec | ||
2468 | * @copied: used to return the amount of data copied to the iov | ||
2469 | * | ||
2470 | * This function copies data from a list of pages in a readdata response into | ||
2471 | * an array of iovecs. It will first calculate where the data should go | ||
2472 | * based on the info in the readdata and then copy the data into that spot. | ||
2473 | */ | ||
2474 | static ssize_t | ||
2475 | cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov, | ||
2476 | unsigned long nr_segs, loff_t offset, ssize_t *copied) | ||
2477 | { | ||
2478 | int rc = 0; | ||
2479 | struct iov_iter ii; | ||
2480 | size_t pos = rdata->offset - offset; | ||
2481 | struct page *page, *tpage; | ||
2482 | ssize_t remaining = rdata->bytes; | ||
2483 | unsigned char *pdata; | ||
2484 | |||
2485 | /* set up iov_iter and advance to the correct offset */ | ||
2486 | iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0); | ||
2487 | iov_iter_advance(&ii, pos); | ||
2488 | |||
2489 | *copied = 0; | ||
2490 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2491 | ssize_t copy; | ||
2492 | |||
2493 | /* copy a whole page or whatever's left */ | ||
2494 | copy = min_t(ssize_t, remaining, PAGE_SIZE); | ||
2495 | |||
2496 | /* ...but limit it to whatever space is left in the iov */ | ||
2497 | copy = min_t(ssize_t, copy, iov_iter_count(&ii)); | ||
2498 | |||
2499 | /* go while there's data to be copied and no errors */ | ||
2500 | if (copy && !rc) { | ||
2501 | pdata = kmap(page); | ||
2502 | rc = memcpy_toiovecend(ii.iov, pdata, ii.iov_offset, | ||
2503 | (int)copy); | ||
2504 | kunmap(page); | ||
2505 | if (!rc) { | ||
2506 | *copied += copy; | ||
2507 | remaining -= copy; | ||
2508 | iov_iter_advance(&ii, copy); | ||
2509 | } | ||
2510 | } | ||
2511 | |||
2512 | list_del(&page->lru); | ||
2513 | put_page(page); | ||
2514 | } | ||
2515 | |||
2516 | return rc; | ||
2517 | } | ||
2518 | |||
2519 | static void | ||
2520 | cifs_uncached_readv_complete(struct work_struct *work) | ||
2521 | { | ||
2522 | struct cifs_readdata *rdata = container_of(work, | ||
2523 | struct cifs_readdata, work); | ||
2524 | |||
2525 | /* if the result is non-zero then the pages weren't kmapped */ | ||
2526 | if (rdata->result == 0) { | ||
2527 | struct page *page; | ||
2528 | |||
2529 | list_for_each_entry(page, &rdata->pages, lru) | ||
2530 | kunmap(page); | ||
2531 | } | ||
2532 | |||
2533 | complete(&rdata->done); | ||
2534 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | ||
2535 | } | ||
2536 | |||
2537 | static int | ||
2538 | cifs_uncached_read_marshal_iov(struct cifs_readdata *rdata, | ||
2539 | unsigned int remaining) | ||
2540 | { | ||
2541 | int len = 0; | ||
2542 | struct page *page, *tpage; | ||
2543 | |||
2544 | rdata->nr_iov = 1; | ||
2545 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2546 | if (remaining >= PAGE_SIZE) { | ||
2547 | /* enough data to fill the page */ | ||
2548 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2549 | rdata->iov[rdata->nr_iov].iov_len = PAGE_SIZE; | ||
2550 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2551 | rdata->nr_iov, page->index, | ||
2552 | rdata->iov[rdata->nr_iov].iov_base, | ||
2553 | rdata->iov[rdata->nr_iov].iov_len); | ||
2554 | ++rdata->nr_iov; | ||
2555 | len += PAGE_SIZE; | ||
2556 | remaining -= PAGE_SIZE; | ||
2557 | } else if (remaining > 0) { | ||
2558 | /* enough for partial page, fill and zero the rest */ | ||
2559 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2560 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
2561 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2562 | rdata->nr_iov, page->index, | ||
2563 | rdata->iov[rdata->nr_iov].iov_base, | ||
2564 | rdata->iov[rdata->nr_iov].iov_len); | ||
2565 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
2566 | '\0', PAGE_SIZE - remaining); | ||
2567 | ++rdata->nr_iov; | ||
2568 | len += remaining; | ||
2569 | remaining = 0; | ||
2570 | } else { | ||
2571 | /* no need to hold page hostage */ | ||
2572 | list_del(&page->lru); | ||
2573 | put_page(page); | ||
2574 | } | ||
2575 | } | ||
2576 | |||
2577 | return len; | ||
2578 | } | ||
2579 | |||
2342 | static ssize_t | 2580 | static ssize_t |
2343 | cifs_iovec_read(struct file *file, const struct iovec *iov, | 2581 | cifs_iovec_read(struct file *file, const struct iovec *iov, |
2344 | unsigned long nr_segs, loff_t *poffset) | 2582 | unsigned long nr_segs, loff_t *poffset) |
2345 | { | 2583 | { |
2346 | int rc; | 2584 | ssize_t rc; |
2347 | int xid; | ||
2348 | ssize_t total_read; | ||
2349 | unsigned int bytes_read = 0; | ||
2350 | size_t len, cur_len; | 2585 | size_t len, cur_len; |
2351 | int iov_offset = 0; | 2586 | ssize_t total_read = 0; |
2587 | loff_t offset = *poffset; | ||
2588 | unsigned int npages; | ||
2352 | struct cifs_sb_info *cifs_sb; | 2589 | struct cifs_sb_info *cifs_sb; |
2353 | struct cifs_tcon *pTcon; | 2590 | struct cifs_tcon *tcon; |
2354 | struct cifsFileInfo *open_file; | 2591 | struct cifsFileInfo *open_file; |
2355 | struct smb_com_read_rsp *pSMBr; | 2592 | struct cifs_readdata *rdata, *tmp; |
2356 | struct cifs_io_parms io_parms; | 2593 | struct list_head rdata_list; |
2357 | char *read_data; | 2594 | pid_t pid; |
2358 | unsigned int rsize; | ||
2359 | __u32 pid; | ||
2360 | 2595 | ||
2361 | if (!nr_segs) | 2596 | if (!nr_segs) |
2362 | return 0; | 2597 | return 0; |
@@ -2365,14 +2600,10 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, | |||
2365 | if (!len) | 2600 | if (!len) |
2366 | return 0; | 2601 | return 0; |
2367 | 2602 | ||
2368 | xid = GetXid(); | 2603 | INIT_LIST_HEAD(&rdata_list); |
2369 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2604 | 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; | 2605 | open_file = file->private_data; |
2375 | pTcon = tlink_tcon(open_file->tlink); | 2606 | tcon = tlink_tcon(open_file->tlink); |
2376 | 2607 | ||
2377 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | 2608 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
2378 | pid = open_file->pid; | 2609 | pid = open_file->pid; |
@@ -2382,56 +2613,78 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, | |||
2382 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 2613 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
2383 | cFYI(1, "attempting read on write only file instance"); | 2614 | cFYI(1, "attempting read on write only file instance"); |
2384 | 2615 | ||
2385 | for (total_read = 0; total_read < len; total_read += bytes_read) { | 2616 | do { |
2386 | cur_len = min_t(const size_t, len - total_read, rsize); | 2617 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); |
2387 | rc = -EAGAIN; | 2618 | npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); |
2388 | read_data = NULL; | ||
2389 | 2619 | ||
2390 | while (rc == -EAGAIN) { | 2620 | /* allocate a readdata struct */ |
2391 | int buf_type = CIFS_NO_BUFFER; | 2621 | rdata = cifs_readdata_alloc(npages, |
2392 | if (open_file->invalidHandle) { | 2622 | cifs_uncached_readv_complete); |
2393 | rc = cifs_reopen_file(open_file, true); | 2623 | if (!rdata) { |
2394 | if (rc != 0) | 2624 | rc = -ENOMEM; |
2395 | break; | 2625 | 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 | } | 2626 | } |
2419 | 2627 | ||
2420 | if (rc || (bytes_read == 0)) { | 2628 | rc = cifs_read_allocate_pages(&rdata->pages, npages); |
2421 | if (total_read) { | 2629 | if (rc) |
2422 | break; | 2630 | goto error; |
2423 | } else { | 2631 | |
2424 | FreeXid(xid); | 2632 | rdata->cfile = cifsFileInfo_get(open_file); |
2425 | return rc; | 2633 | rdata->offset = offset; |
2634 | rdata->bytes = cur_len; | ||
2635 | rdata->pid = pid; | ||
2636 | rdata->marshal_iov = cifs_uncached_read_marshal_iov; | ||
2637 | |||
2638 | rc = cifs_retry_async_readv(rdata); | ||
2639 | error: | ||
2640 | if (rc) { | ||
2641 | kref_put(&rdata->refcount, | ||
2642 | cifs_uncached_readdata_release); | ||
2643 | break; | ||
2644 | } | ||
2645 | |||
2646 | list_add_tail(&rdata->list, &rdata_list); | ||
2647 | offset += cur_len; | ||
2648 | len -= cur_len; | ||
2649 | } while (len > 0); | ||
2650 | |||
2651 | /* if at least one read request send succeeded, then reset rc */ | ||
2652 | if (!list_empty(&rdata_list)) | ||
2653 | rc = 0; | ||
2654 | |||
2655 | /* the loop below should proceed in the order of increasing offsets */ | ||
2656 | restart_loop: | ||
2657 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { | ||
2658 | if (!rc) { | ||
2659 | ssize_t copied; | ||
2660 | |||
2661 | /* FIXME: freezable sleep too? */ | ||
2662 | rc = wait_for_completion_killable(&rdata->done); | ||
2663 | if (rc) | ||
2664 | rc = -EINTR; | ||
2665 | else if (rdata->result) | ||
2666 | rc = rdata->result; | ||
2667 | else { | ||
2668 | rc = cifs_readdata_to_iov(rdata, iov, | ||
2669 | nr_segs, *poffset, | ||
2670 | &copied); | ||
2671 | total_read += copied; | ||
2672 | } | ||
2673 | |||
2674 | /* resend call if it's a retryable error */ | ||
2675 | if (rc == -EAGAIN) { | ||
2676 | rc = cifs_retry_async_readv(rdata); | ||
2677 | goto restart_loop; | ||
2426 | } | 2678 | } |
2427 | } else { | ||
2428 | cifs_stats_bytes_read(pTcon, bytes_read); | ||
2429 | *poffset += bytes_read; | ||
2430 | } | 2679 | } |
2680 | list_del_init(&rdata->list); | ||
2681 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | ||
2431 | } | 2682 | } |
2432 | 2683 | ||
2433 | FreeXid(xid); | 2684 | cifs_stats_bytes_read(tcon, total_read); |
2434 | return total_read; | 2685 | *poffset += total_read; |
2686 | |||
2687 | return total_read ? total_read : rc; | ||
2435 | } | 2688 | } |
2436 | 2689 | ||
2437 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, | 2690 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, |
@@ -2606,6 +2859,100 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
2606 | return rc; | 2859 | return rc; |
2607 | } | 2860 | } |
2608 | 2861 | ||
2862 | static void | ||
2863 | cifs_readv_complete(struct work_struct *work) | ||
2864 | { | ||
2865 | struct cifs_readdata *rdata = container_of(work, | ||
2866 | struct cifs_readdata, work); | ||
2867 | struct page *page, *tpage; | ||
2868 | |||
2869 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2870 | list_del(&page->lru); | ||
2871 | lru_cache_add_file(page); | ||
2872 | |||
2873 | if (rdata->result == 0) { | ||
2874 | kunmap(page); | ||
2875 | flush_dcache_page(page); | ||
2876 | SetPageUptodate(page); | ||
2877 | } | ||
2878 | |||
2879 | unlock_page(page); | ||
2880 | |||
2881 | if (rdata->result == 0) | ||
2882 | cifs_readpage_to_fscache(rdata->mapping->host, page); | ||
2883 | |||
2884 | page_cache_release(page); | ||
2885 | } | ||
2886 | kref_put(&rdata->refcount, cifs_readdata_release); | ||
2887 | } | ||
2888 | |||
2889 | static int | ||
2890 | cifs_readpages_marshal_iov(struct cifs_readdata *rdata, unsigned int remaining) | ||
2891 | { | ||
2892 | int len = 0; | ||
2893 | struct page *page, *tpage; | ||
2894 | u64 eof; | ||
2895 | pgoff_t eof_index; | ||
2896 | |||
2897 | /* determine the eof that the server (probably) has */ | ||
2898 | eof = CIFS_I(rdata->mapping->host)->server_eof; | ||
2899 | eof_index = eof ? (eof - 1) >> PAGE_CACHE_SHIFT : 0; | ||
2900 | cFYI(1, "eof=%llu eof_index=%lu", eof, eof_index); | ||
2901 | |||
2902 | rdata->nr_iov = 1; | ||
2903 | list_for_each_entry_safe(page, tpage, &rdata->pages, lru) { | ||
2904 | if (remaining >= PAGE_CACHE_SIZE) { | ||
2905 | /* enough data to fill the page */ | ||
2906 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2907 | rdata->iov[rdata->nr_iov].iov_len = PAGE_CACHE_SIZE; | ||
2908 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2909 | rdata->nr_iov, page->index, | ||
2910 | rdata->iov[rdata->nr_iov].iov_base, | ||
2911 | rdata->iov[rdata->nr_iov].iov_len); | ||
2912 | ++rdata->nr_iov; | ||
2913 | len += PAGE_CACHE_SIZE; | ||
2914 | remaining -= PAGE_CACHE_SIZE; | ||
2915 | } else if (remaining > 0) { | ||
2916 | /* enough for partial page, fill and zero the rest */ | ||
2917 | rdata->iov[rdata->nr_iov].iov_base = kmap(page); | ||
2918 | rdata->iov[rdata->nr_iov].iov_len = remaining; | ||
2919 | cFYI(1, "%u: idx=%lu iov_base=%p iov_len=%zu", | ||
2920 | rdata->nr_iov, page->index, | ||
2921 | rdata->iov[rdata->nr_iov].iov_base, | ||
2922 | rdata->iov[rdata->nr_iov].iov_len); | ||
2923 | memset(rdata->iov[rdata->nr_iov].iov_base + remaining, | ||
2924 | '\0', PAGE_CACHE_SIZE - remaining); | ||
2925 | ++rdata->nr_iov; | ||
2926 | len += remaining; | ||
2927 | remaining = 0; | ||
2928 | } else if (page->index > eof_index) { | ||
2929 | /* | ||
2930 | * The VFS will not try to do readahead past the | ||
2931 | * i_size, but it's possible that we have outstanding | ||
2932 | * writes with gaps in the middle and the i_size hasn't | ||
2933 | * caught up yet. Populate those with zeroed out pages | ||
2934 | * to prevent the VFS from repeatedly attempting to | ||
2935 | * fill them until the writes are flushed. | ||
2936 | */ | ||
2937 | zero_user(page, 0, PAGE_CACHE_SIZE); | ||
2938 | list_del(&page->lru); | ||
2939 | lru_cache_add_file(page); | ||
2940 | flush_dcache_page(page); | ||
2941 | SetPageUptodate(page); | ||
2942 | unlock_page(page); | ||
2943 | page_cache_release(page); | ||
2944 | } else { | ||
2945 | /* no need to hold page hostage */ | ||
2946 | list_del(&page->lru); | ||
2947 | lru_cache_add_file(page); | ||
2948 | unlock_page(page); | ||
2949 | page_cache_release(page); | ||
2950 | } | ||
2951 | } | ||
2952 | |||
2953 | return len; | ||
2954 | } | ||
2955 | |||
2609 | static int cifs_readpages(struct file *file, struct address_space *mapping, | 2956 | static int cifs_readpages(struct file *file, struct address_space *mapping, |
2610 | struct list_head *page_list, unsigned num_pages) | 2957 | struct list_head *page_list, unsigned num_pages) |
2611 | { | 2958 | { |
@@ -2708,7 +3055,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2708 | nr_pages++; | 3055 | nr_pages++; |
2709 | } | 3056 | } |
2710 | 3057 | ||
2711 | rdata = cifs_readdata_alloc(nr_pages); | 3058 | rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); |
2712 | if (!rdata) { | 3059 | if (!rdata) { |
2713 | /* best to give up if we're out of mem */ | 3060 | /* best to give up if we're out of mem */ |
2714 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { | 3061 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { |
@@ -2722,24 +3069,16 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2722 | } | 3069 | } |
2723 | 3070 | ||
2724 | spin_lock(&cifs_file_list_lock); | 3071 | spin_lock(&cifs_file_list_lock); |
2725 | cifsFileInfo_get(open_file); | ||
2726 | spin_unlock(&cifs_file_list_lock); | 3072 | spin_unlock(&cifs_file_list_lock); |
2727 | rdata->cfile = open_file; | 3073 | rdata->cfile = cifsFileInfo_get(open_file); |
2728 | rdata->mapping = mapping; | 3074 | rdata->mapping = mapping; |
2729 | rdata->offset = offset; | 3075 | rdata->offset = offset; |
2730 | rdata->bytes = bytes; | 3076 | rdata->bytes = bytes; |
2731 | rdata->pid = pid; | 3077 | rdata->pid = pid; |
3078 | rdata->marshal_iov = cifs_readpages_marshal_iov; | ||
2732 | list_splice_init(&tmplist, &rdata->pages); | 3079 | list_splice_init(&tmplist, &rdata->pages); |
2733 | 3080 | ||
2734 | do { | 3081 | 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) { | 3082 | if (rc != 0) { |
2744 | list_for_each_entry_safe(page, tpage, &rdata->pages, | 3083 | list_for_each_entry_safe(page, tpage, &rdata->pages, |
2745 | lru) { | 3084 | lru) { |
@@ -2748,9 +3087,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2748 | unlock_page(page); | 3087 | unlock_page(page); |
2749 | page_cache_release(page); | 3088 | page_cache_release(page); |
2750 | } | 3089 | } |
2751 | cifs_readdata_free(rdata); | 3090 | kref_put(&rdata->refcount, cifs_readdata_release); |
2752 | break; | 3091 | break; |
2753 | } | 3092 | } |
3093 | |||
3094 | kref_put(&rdata->refcount, cifs_readdata_release); | ||
2754 | } | 3095 | } |
2755 | 3096 | ||
2756 | return rc; | 3097 | 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..e2552d2b2e42 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -306,8 +306,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
306 | const struct cifs_tcon *treeCon, int word_count | 306 | const struct cifs_tcon *treeCon, int word_count |
307 | /* length of fixed section (word count) in two byte units */) | 307 | /* length of fixed section (word count) in two byte units */) |
308 | { | 308 | { |
309 | struct list_head *temp_item; | ||
310 | struct cifs_ses *ses; | ||
311 | char *temp = (char *) buffer; | 309 | char *temp = (char *) buffer; |
312 | 310 | ||
313 | memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ | 311 | memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ |
@@ -337,51 +335,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
337 | /* Uid is not converted */ | 335 | /* Uid is not converted */ |
338 | buffer->Uid = treeCon->ses->Suid; | 336 | buffer->Uid = treeCon->ses->Suid; |
339 | buffer->Mid = GetNextMid(treeCon->ses->server); | 337 | buffer->Mid = GetNextMid(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 | } | 338 | } |
386 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) | 339 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) |
387 | buffer->Flags2 |= SMBFLG2_DFS; | 340 | buffer->Flags2 |= SMBFLG2_DFS; |
@@ -700,22 +653,3 @@ backup_cred(struct cifs_sb_info *cifs_sb) | |||
700 | 653 | ||
701 | return false; | 654 | return false; |
702 | } | 655 | } |
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..d9d615fbed3f --- /dev/null +++ b/fs/cifs/smb1ops.c | |||
@@ -0,0 +1,154 @@ | |||
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 | struct smb_version_operations smb1_operations = { | ||
129 | .send_cancel = send_nt_cancel, | ||
130 | .compare_fids = cifs_compare_fids, | ||
131 | .setup_request = cifs_setup_request, | ||
132 | .check_receive = cifs_check_receive, | ||
133 | .add_credits = cifs_add_credits, | ||
134 | .set_credits = cifs_set_credits, | ||
135 | .get_credits_field = cifs_get_credits_field, | ||
136 | .read_data_offset = cifs_read_data_offset, | ||
137 | .read_data_length = cifs_read_data_length, | ||
138 | .map_error = map_smb_to_linux_error, | ||
139 | .find_mid = cifs_find_mid, | ||
140 | .check_message = checkSMB, | ||
141 | .dump_detail = cifs_dump_detail, | ||
142 | .is_oplock_break = is_valid_oplock_break, | ||
143 | }; | ||
144 | |||
145 | struct smb_version_values smb1_values = { | ||
146 | .version_string = SMB1_VERSION_STRING, | ||
147 | .large_lock_type = LOCKING_ANDX_LARGE_FILES, | ||
148 | .exclusive_lock_type = 0, | ||
149 | .shared_lock_type = LOCKING_ANDX_SHARED_LOCK, | ||
150 | .unlock_lock_type = 0, | ||
151 | .header_size = sizeof(struct smb_hdr), | ||
152 | .max_header_size = MAX_CIFS_HDR_SIZE, | ||
153 | .read_rsp_size = sizeof(READ_RSP), | ||
154 | }; | ||
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..1b36ffe6a47b 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 | } |
@@ -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" */ |