diff options
author | Steve French <sfrench@us.ibm.com> | 2005-10-21 11:39:12 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2005-10-21 11:39:12 -0400 |
commit | d6d3f5bc68be3c4ab84e6f1f9db92291da671504 (patch) | |
tree | 76946c62cc7d1a18203fba50ea87fd567387f637 | |
parent | ac9b9c667c2e1194e22ebe0a441ae1c37aaa9b90 (diff) | |
parent | 23e7dd7d95f6fdc167a6d6ddea79ced0af33bbff (diff) |
Merge with /pub/scm/linux/kernel/git/sfrench/cifs-2.6.git/
-rw-r--r-- | fs/cifs/AUTHORS | 4 | ||||
-rw-r--r-- | fs/cifs/CHANGES | 60 | ||||
-rw-r--r-- | fs/cifs/README | 24 | ||||
-rw-r--r-- | fs/cifs/TODO | 50 | ||||
-rw-r--r-- | fs/cifs/asn1.c | 3 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 103 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 80 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 98 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 174 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 32 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 659 | ||||
-rw-r--r-- | fs/cifs/connect.c | 219 | ||||
-rw-r--r-- | fs/cifs/dir.c | 108 | ||||
-rw-r--r-- | fs/cifs/fcntl.c | 12 | ||||
-rw-r--r-- | fs/cifs/file.c | 466 | ||||
-rw-r--r-- | fs/cifs/inode.c | 150 | ||||
-rw-r--r-- | fs/cifs/link.c | 5 | ||||
-rw-r--r-- | fs/cifs/misc.c | 123 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 15 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 84 | ||||
-rw-r--r-- | fs/cifs/transport.c | 331 |
24 files changed, 2266 insertions, 545 deletions
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index 72fdc10dfdd7..8848e4dfa026 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS | |||
@@ -32,6 +32,10 @@ Domen Puncer | |||
32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) | 32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) |
33 | Vince Negri and Dave Stahl (for finding an important caching bug) | 33 | Vince Negri and Dave Stahl (for finding an important caching bug) |
34 | Adrian Bunk (kcalloc cleanups) | 34 | Adrian Bunk (kcalloc cleanups) |
35 | Miklos Szeredi | ||
36 | Kazeon team for various fixes especially for 2.4 version. | ||
37 | Asser Ferno (Change Notify support) | ||
38 | Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup | ||
35 | 39 | ||
36 | Test case and Bug Report contributors | 40 | Test case and Bug Report contributors |
37 | ------------------------------------- | 41 | ------------------------------------- |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3196d4c4eed3..5bab24f59053 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,8 +1,52 @@ | |||
1 | Version 1.39 | ||
2 | ------------ | ||
3 | Defer close of a file handle slightly if pending writes depend on that file handle | ||
4 | (this reduces the EBADF bad file handle errors that can be logged under heavy | ||
5 | stress on writes). | ||
6 | |||
7 | Version 1.38 | ||
8 | ------------ | ||
9 | Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket) | ||
10 | to be smaller at first (but increasing) so large write performance performance | ||
11 | over GigE is better. Do not hang thread on illegal byte range lock response | ||
12 | from Windows (Windows can send an RFC1001 size which does not match smb size) by | ||
13 | allowing an SMBs TCP length to be up to a few bytes longer than it should be. | ||
14 | wsize and rsize can now be larger than negotiated buffer size if server | ||
15 | supports large readx/writex, even when directio mount flag not specified. | ||
16 | Write size will in many cases now be 16K instead of 4K which greatly helps | ||
17 | file copy performance on lightly loaded networks. Fix oops in dnotify | ||
18 | when experimental config flag enabled. Make cifsFYI more granular. | ||
19 | |||
20 | Version 1.37 | ||
21 | ------------ | ||
22 | Fix readdir caching when unlink removes file in current search buffer, | ||
23 | and this is followed by a rewind search to just before the deleted entry. | ||
24 | Do not attempt to set ctime unless atime and/or mtime change requested | ||
25 | (most servers throw it away anyway). Fix length check of received smbs | ||
26 | to be more accurate. Fix big endian problem with mapchars mount option, | ||
27 | and with a field returned by statfs. | ||
28 | |||
29 | Version 1.36 | ||
30 | ------------ | ||
31 | Add support for mounting to older pre-CIFS servers such as Windows9x and ME. | ||
32 | For these older servers, add option for passing netbios name of server in | ||
33 | on mount (servernetbiosname). Add suspend support for power management, to | ||
34 | avoid cifsd thread preventing software suspend from working. | ||
35 | Add mount option for disabling the default behavior of sending byte range lock | ||
36 | requests to the server (necessary for certain applications which break with | ||
37 | mandatory lock behavior such as Evolution), and also mount option for | ||
38 | requesting case insensitive matching for path based requests (requesting | ||
39 | case sensitive is the default). | ||
40 | |||
1 | Version 1.35 | 41 | Version 1.35 |
2 | ------------ | 42 | ------------ |
3 | Add writepage performance improvements. Fix path name conversions | 43 | Add writepage performance improvements. Fix path name conversions |
4 | for long filenames on mounts which were done with "mapchars" mount option | 44 | for long filenames on mounts which were done with "mapchars" mount option |
5 | specified. | 45 | specified. Ensure multiplex ids do not collide. Fix case in which |
46 | rmmod can oops if done soon after last unmount. Fix truncated | ||
47 | search (readdir) output when resume filename was a long filename. | ||
48 | Fix filename conversion when mapchars mount option was specified and | ||
49 | filename was a long filename. | ||
6 | 50 | ||
7 | Version 1.34 | 51 | Version 1.34 |
8 | ------------ | 52 | ------------ |
@@ -11,7 +55,7 @@ Do not oops if root user kills cifs oplock kernel thread or | |||
11 | kills the cifsd thread (NB: killing the cifs kernel threads is not | 55 | kills the cifsd thread (NB: killing the cifs kernel threads is not |
12 | recommended, unmount and rmmod cifs will kill them when they are | 56 | recommended, unmount and rmmod cifs will kill them when they are |
13 | no longer needed). Fix readdir to ASCII servers (ie older servers | 57 | no longer needed). Fix readdir to ASCII servers (ie older servers |
14 | which do not support Unicode) and also require asterik. | 58 | which do not support Unicode) and also require asterisk. |
15 | Fix out of memory case in which data could be written one page | 59 | Fix out of memory case in which data could be written one page |
16 | off in the page cache. | 60 | off in the page cache. |
17 | 61 | ||
@@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call. | |||
101 | 145 | ||
102 | Version 1.25 | 146 | Version 1.25 |
103 | ------------ | 147 | ------------ |
104 | Fix internationlization problem in cifs readdir with filenames that map to | 148 | Fix internationalization problem in cifs readdir with filenames that map to |
105 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround | 149 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround |
106 | for readdir to netapp servers. Fix search rewind (seek into readdir to return | 150 | for readdir to netapp servers. Fix search rewind (seek into readdir to return |
107 | non-consecutive entries). Do not do readdir when server negotiates | 151 | non-consecutive entries). Do not do readdir when server negotiates |
@@ -276,7 +320,7 @@ Fix caching problem when files opened by multiple clients in which | |||
276 | page cache could contain stale data, and write through did | 320 | page cache could contain stale data, and write through did |
277 | not occur often enough while file was still open when read ahead | 321 | not occur often enough while file was still open when read ahead |
278 | (read oplock) not allowed. Treat "sep=" when first mount option | 322 | (read oplock) not allowed. Treat "sep=" when first mount option |
279 | as an overrride of comma as the default separator between mount | 323 | as an override of comma as the default separator between mount |
280 | options. | 324 | options. |
281 | 325 | ||
282 | Version 1.01 | 326 | Version 1.01 |
@@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string. | |||
286 | Version 1.00 | 330 | Version 1.00 |
287 | ------------ | 331 | ------------ |
288 | Gracefully clean up failed mounts when attempting to mount to servers such as | 332 | Gracefully clean up failed mounts when attempting to mount to servers such as |
289 | Windows 98 that terminate tcp sessions during prototocol negotiation. Handle | 333 | Windows 98 that terminate tcp sessions during protocol negotiation. Handle |
290 | embedded commas in mount parsing of passwords. | 334 | embedded commas in mount parsing of passwords. |
291 | 335 | ||
292 | Version 0.99 | 336 | Version 0.99 |
@@ -295,7 +339,7 @@ Invalidate local inode cached pages on oplock break and when last file | |||
295 | instance is closed so that the client does not continue using stale local | 339 | instance is closed so that the client does not continue using stale local |
296 | copy rather than later modified server copy of file. Do not reconnect | 340 | copy rather than later modified server copy of file. Do not reconnect |
297 | when server drops the tcp session prematurely before negotiate | 341 | when server drops the tcp session prematurely before negotiate |
298 | protocol response. Fix oops in roepen_file when dentry freed. Allow | 342 | protocol response. Fix oops in reopen_file when dentry freed. Allow |
299 | the support for CIFS Unix Extensions to be disabled via proc interface. | 343 | the support for CIFS Unix Extensions to be disabled via proc interface. |
300 | 344 | ||
301 | Version 0.98 | 345 | Version 0.98 |
@@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early | |||
637 | Version 0.41 | 681 | Version 0.41 |
638 | ------------ | 682 | ------------ |
639 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked | 683 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked |
640 | files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. | 684 | files now return the correct number of links on fstat as they are repeatedly linked and unlinked. |
641 | 685 | ||
642 | Version 0.40 | 686 | Version 0.40 |
643 | ------------ | 687 | ------------ |
@@ -704,7 +748,7 @@ session) | |||
704 | and cleaned them up and made them more consistent with other cifs functions. | 748 | and cleaned them up and made them more consistent with other cifs functions. |
705 | 749 | ||
706 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways | 750 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways |
707 | (with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, | 751 | (with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed, |
708 | nor is the symlink support using the Unix extensions | 752 | nor is the symlink support using the Unix extensions |
709 | 753 | ||
710 | 8) Started adding the readlink and follow_link code | 754 | 8) Started adding the readlink and follow_link code |
diff --git a/fs/cifs/README b/fs/cifs/README index 34b0cf7111f3..bb90941826ad 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -294,8 +294,10 @@ A partial list of the supported mount options follows: | |||
294 | during the local client kernel build will be used. | 294 | during the local client kernel build will be used. |
295 | If server does not support Unicode, this parameter is | 295 | If server does not support Unicode, this parameter is |
296 | unused. | 296 | unused. |
297 | rsize default read size | 297 | rsize default read size (usually 16K) |
298 | wsize default write size | 298 | wsize default write size (usually 16K, 32K is often better over GigE) |
299 | maximum wsize currently allowed by CIFS is 57344 (14 4096 byte | ||
300 | pages) | ||
299 | rw mount the network share read-write (note that the | 301 | rw mount the network share read-write (note that the |
300 | server may still consider the share read-only) | 302 | server may still consider the share read-only) |
301 | ro mount network share read-only | 303 | ro mount network share read-only |
@@ -407,6 +409,13 @@ A partial list of the supported mount options follows: | |||
407 | This has no effect if the server does not support | 409 | This has no effect if the server does not support |
408 | Unicode on the wire. | 410 | Unicode on the wire. |
409 | nomapchars Do not translate any of these seven characters (default). | 411 | nomapchars Do not translate any of these seven characters (default). |
412 | nocase Request case insensitive path name matching (case | ||
413 | sensitive is the default if the server suports it). | ||
414 | nobrl Do not send byte range lock requests to the server. | ||
415 | This is necessary for certain applications that break | ||
416 | with cifs style mandatory byte range locks (and most | ||
417 | cifs servers do not yet support requesting advisory | ||
418 | byte range locks). | ||
410 | remount remount the share (often used to change from ro to rw mounts | 419 | remount remount the share (often used to change from ro to rw mounts |
411 | or vice versa) | 420 | or vice versa) |
412 | 421 | ||
@@ -473,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in | |||
473 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable | 482 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable |
474 | tracing to the kernel message log type: | 483 | tracing to the kernel message log type: |
475 | 484 | ||
476 | echo 1 > /proc/fs/cifs/cifsFYI | 485 | echo 7 > /proc/fs/cifs/cifsFYI |
477 | 486 | ||
478 | and for more extensive tracing including the start of smb requests and responses | 487 | cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel |
488 | logging of various informational messages. 2 enables logging of non-zero | ||
489 | SMB return codes while 4 enables logging of requests that take longer | ||
490 | than one second to complete (except for byte range lock requests). | ||
491 | Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the | ||
492 | source code (typically by setting it in the beginning of cifsglob.h), | ||
493 | and setting it to seven enables all three. Finally, tracing | ||
494 | the start of smb requests and responses can be enabled via: | ||
479 | 495 | ||
480 | echo 1 > /proc/fs/cifs/traceSMB | 496 | echo 1 > /proc/fs/cifs/traceSMB |
481 | 497 | ||
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 8cc881694e29..c909298d11ed 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
@@ -1,4 +1,4 @@ | |||
1 | version 1.34 April 29, 2005 | 1 | version 1.37 October 9, 2005 |
2 | 2 | ||
3 | A Partial List of Missing Features | 3 | A Partial List of Missing Features |
4 | ================================== | 4 | ================================== |
@@ -7,14 +7,14 @@ Contributions are welcome. There are plenty of opportunities | |||
7 | for visible, important contributions to this module. Here | 7 | for visible, important contributions to this module. Here |
8 | is a partial list of the known problems and missing features: | 8 | is a partial list of the known problems and missing features: |
9 | 9 | ||
10 | a) Support for SecurityDescriptors for chmod/chgrp/chown so | 10 | a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown |
11 | these can be supported for Windows servers | 11 | so that these operations can be supported to Windows servers |
12 | 12 | ||
13 | b) Better pam/winbind integration (e.g. to handle uid mapping | 13 | b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS |
14 | better) | 14 | SecurityDescriptors |
15 | 15 | ||
16 | c) multi-user mounts - multiplexed sessionsetups over single vc | 16 | c) Better pam/winbind integration (e.g. to handle uid mapping |
17 | (ie tcp session) - more testing needed | 17 | better) |
18 | 18 | ||
19 | d) Kerberos/SPNEGO session setup support - (started) | 19 | d) Kerberos/SPNEGO session setup support - (started) |
20 | 20 | ||
@@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than | |||
29 | using FindNotify or equivalent. - (started) | 29 | using FindNotify or equivalent. - (started) |
30 | 30 | ||
31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS | 31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS |
32 | style byte range lock differences | 32 | style byte range lock differences. Save byte range locks so |
33 | reconnect can replay them. | ||
33 | 34 | ||
34 | h) quota support | 35 | h) Support unlock all (unlock 0,MAX_OFFSET) |
36 | by unlocking all known byte range locks that we locked on the file. | ||
35 | 37 | ||
36 | j) finish writepages support (multi-page write behind for improved | 38 | i) quota support (needs minor kernel change since quota calls |
37 | performance) and syncpage | 39 | to make it to network filesystems or deviceless filesystems) |
40 | |||
41 | j) investigate sync behavior (including syncpage) and check | ||
42 | for proper behavior of intr/nointr | ||
38 | 43 | ||
39 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the | 44 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the |
40 | extra copy in/out of the socket buffers in some cases. | 45 | extra copy in/out of the socket buffers in some cases. |
@@ -57,20 +62,18 @@ p) Add support for storing symlink and fifo info to Windows servers | |||
57 | in the Extended Attribute format their SFU clients would recognize. | 62 | in the Extended Attribute format their SFU clients would recognize. |
58 | 63 | ||
59 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows | 64 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows |
60 | will autorefresh (started) | 65 | will autorefresh (partially complete by Asser). Needs minor kernel |
66 | vfs change to support removing D_NOTIFY on a file. | ||
61 | 67 | ||
62 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of | 68 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of |
63 | the CIFS statistics (started) | 69 | the CIFS statistics (started) |
64 | 70 | ||
65 | q) implement support for security and trusted categories of xattrs | 71 | s) implement support for security and trusted categories of xattrs |
66 | (requires minor protocol extension) to enable better support for SELINUX | 72 | (requires minor protocol extension) to enable better support for SELINUX |
67 | 73 | ||
68 | r) Implement O_DIRECT flag on open (already supported on mount) | 74 | t) Implement O_DIRECT flag on open (already supported on mount) |
69 | |||
70 | s) Allow remapping of last remaining character (\) to +0xF000 which | ||
71 | (this character is valid for POSIX but not for Windows) | ||
72 | 75 | ||
73 | t) Create UID mapping facility so server UIDs can be mapped on a per | 76 | u) Create UID mapping facility so server UIDs can be mapped on a per |
74 | mount or a per server basis to client UIDs or nobody if no mapping | 77 | mount or a per server basis to client UIDs or nobody if no mapping |
75 | exists. This is helpful when Unix extensions are negotiated to | 78 | exists. This is helpful when Unix extensions are negotiated to |
76 | allow better permission checking when UIDs differ on the server | 79 | allow better permission checking when UIDs differ on the server |
@@ -78,6 +81,17 @@ and client. Add new protocol request to the CIFS protocol | |||
78 | standard for asking the server for the corresponding name of a | 81 | standard for asking the server for the corresponding name of a |
79 | particular uid. | 82 | particular uid. |
80 | 83 | ||
84 | v) Add support for CIFS Unix and also the newer POSIX extensions to the | ||
85 | server side for Samba 4. | ||
86 | |||
87 | w) Finish up the dos time conversion routines needed to return old server | ||
88 | time to the client (default time, of now or time 0 is used now for these | ||
89 | very old servers) | ||
90 | |||
91 | x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) | ||
92 | |||
93 | y) Finish testing of Windows 9x/Windows ME server support (started). | ||
94 | |||
81 | KNOWN BUGS (updated April 29, 2005) | 95 | KNOWN BUGS (updated April 29, 2005) |
82 | ==================================== | 96 | ==================================== |
83 | See http://bugzilla.samba.org - search on product "CifsVFS" for | 97 | See http://bugzilla.samba.org - search on product "CifsVFS" for |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index e02010dd73ec..98539e2afe81 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
@@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx, | |||
191 | unsigned char **eoc, | 191 | unsigned char **eoc, |
192 | unsigned int *cls, unsigned int *con, unsigned int *tag) | 192 | unsigned int *cls, unsigned int *con, unsigned int *tag) |
193 | { | 193 | { |
194 | unsigned int def, len; | 194 | unsigned int def = 0; |
195 | unsigned int len = 0; | ||
195 | 196 | ||
196 | if (!asn1_id_decode(ctx, cls, con, tag)) | 197 | if (!asn1_id_decode(ctx, cls, con, tag)) |
197 | return 0; | 198 | return 0; |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4061e43471c1..22a444a3fe4c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
81 | buf += length; | 81 | buf += length; |
82 | length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); | 82 | length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); |
83 | buf += length; | 83 | buf += length; |
84 | length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid); | ||
85 | buf += length; | ||
84 | length = sprintf(buf, "Servers:"); | 86 | length = sprintf(buf, "Servers:"); |
85 | buf += length; | 87 | buf += length; |
86 | 88 | ||
@@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
97 | } else { | 99 | } else { |
98 | length = | 100 | length = |
99 | sprintf(buf, | 101 | sprintf(buf, |
100 | "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", | 102 | "\n%d) Name: %s Domain: %s Mounts: %d OS: %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t", |
101 | i, ses->serverName, ses->serverDomain, | 103 | i, ses->serverName, ses->serverDomain, |
102 | atomic_read(&ses->inUse), | 104 | atomic_read(&ses->inUse), |
103 | ses->serverOS, ses->serverNOS, | 105 | ses->serverOS, ses->serverNOS, |
@@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
105 | buf += length; | 107 | buf += length; |
106 | } | 108 | } |
107 | if(ses->server) { | 109 | if(ses->server) { |
108 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", | 110 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d", |
109 | ses->server->tcpStatus, | 111 | ses->server->tcpStatus, |
110 | atomic_read(&ses->server->socketUseCount), | 112 | atomic_read(&ses->server->socketUseCount), |
111 | ses->server->secMode, | 113 | ses->server->secMode, |
112 | atomic_read(&ses->server->inFlight)); | 114 | atomic_read(&ses->server->inFlight)); |
113 | 115 | ||
116 | #ifdef CONFIG_CIFS_STATS2 | ||
117 | buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d", | ||
118 | atomic_read(&ses->server->inSend), | ||
119 | atomic_read(&ses->server->num_waiters)); | ||
120 | #endif | ||
121 | |||
114 | length = sprintf(buf, "\nMIDs:\n"); | 122 | length = sprintf(buf, "\nMIDs:\n"); |
115 | buf += length; | 123 | buf += length; |
116 | 124 | ||
@@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
149 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | 157 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); |
150 | length = | 158 | length = |
151 | sprintf(buf, | 159 | sprintf(buf, |
152 | "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", | 160 | "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", |
153 | i, tcon->treeName, | 161 | i, tcon->treeName, |
154 | atomic_read(&tcon->useCount), | 162 | atomic_read(&tcon->useCount), |
155 | tcon->nativeFileSystem, | 163 | tcon->nativeFileSystem, |
@@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
195 | } | 203 | } |
196 | 204 | ||
197 | #ifdef CONFIG_CIFS_STATS | 205 | #ifdef CONFIG_CIFS_STATS |
206 | |||
207 | static int | ||
208 | cifs_stats_write(struct file *file, const char __user *buffer, | ||
209 | unsigned long count, void *data) | ||
210 | { | ||
211 | char c; | ||
212 | int rc; | ||
213 | struct list_head *tmp; | ||
214 | struct cifsTconInfo *tcon; | ||
215 | |||
216 | rc = get_user(c, buffer); | ||
217 | if (rc) | ||
218 | return rc; | ||
219 | |||
220 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { | ||
221 | read_lock(&GlobalSMBSeslock); | ||
222 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
223 | tcon = list_entry(tmp, struct cifsTconInfo, | ||
224 | cifsConnectionList); | ||
225 | atomic_set(&tcon->num_smbs_sent, 0); | ||
226 | atomic_set(&tcon->num_writes, 0); | ||
227 | atomic_set(&tcon->num_reads, 0); | ||
228 | atomic_set(&tcon->num_oplock_brks, 0); | ||
229 | atomic_set(&tcon->num_opens, 0); | ||
230 | atomic_set(&tcon->num_closes, 0); | ||
231 | atomic_set(&tcon->num_deletes, 0); | ||
232 | atomic_set(&tcon->num_mkdirs, 0); | ||
233 | atomic_set(&tcon->num_rmdirs, 0); | ||
234 | atomic_set(&tcon->num_renames, 0); | ||
235 | atomic_set(&tcon->num_t2renames, 0); | ||
236 | atomic_set(&tcon->num_ffirst, 0); | ||
237 | atomic_set(&tcon->num_fnext, 0); | ||
238 | atomic_set(&tcon->num_fclose, 0); | ||
239 | atomic_set(&tcon->num_hardlinks, 0); | ||
240 | atomic_set(&tcon->num_symlinks, 0); | ||
241 | atomic_set(&tcon->num_locks, 0); | ||
242 | } | ||
243 | read_unlock(&GlobalSMBSeslock); | ||
244 | } | ||
245 | |||
246 | return count; | ||
247 | } | ||
248 | |||
198 | static int | 249 | static int |
199 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | 250 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, |
200 | int count, int *eof, void *data) | 251 | int count, int *eof, void *data) |
@@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | |||
254 | buf += sprintf(buf, "\tDISCONNECTED "); | 305 | buf += sprintf(buf, "\tDISCONNECTED "); |
255 | length += 14; | 306 | length += 14; |
256 | } | 307 | } |
257 | item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", | 308 | item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d", |
258 | atomic_read(&tcon->num_smbs_sent), | 309 | atomic_read(&tcon->num_smbs_sent), |
259 | atomic_read(&tcon->num_oplock_brks)); | 310 | atomic_read(&tcon->num_oplock_brks)); |
260 | buf += item_length; | 311 | buf += item_length; |
261 | length += item_length; | 312 | length += item_length; |
262 | item_length = sprintf(buf,"\nReads: %d Bytes %lld", | 313 | item_length = sprintf(buf, "\nReads: %d Bytes: %lld", |
263 | atomic_read(&tcon->num_reads), | 314 | atomic_read(&tcon->num_reads), |
264 | (long long)(tcon->bytes_read)); | 315 | (long long)(tcon->bytes_read)); |
265 | buf += item_length; | 316 | buf += item_length; |
266 | length += item_length; | 317 | length += item_length; |
267 | item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", | 318 | item_length = sprintf(buf, "\nWrites: %d Bytes: %lld", |
268 | atomic_read(&tcon->num_writes), | 319 | atomic_read(&tcon->num_writes), |
269 | (long long)(tcon->bytes_written)); | 320 | (long long)(tcon->bytes_written)); |
321 | buf += item_length; | ||
322 | length += item_length; | ||
323 | item_length = sprintf(buf, | ||
324 | "\nLocks: %d HardLinks: %d Symlinks: %d", | ||
325 | atomic_read(&tcon->num_locks), | ||
326 | atomic_read(&tcon->num_hardlinks), | ||
327 | atomic_read(&tcon->num_symlinks)); | ||
328 | buf += item_length; | ||
329 | length += item_length; | ||
330 | |||
331 | item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d", | ||
332 | atomic_read(&tcon->num_opens), | ||
333 | atomic_read(&tcon->num_closes), | ||
334 | atomic_read(&tcon->num_deletes)); | ||
270 | buf += item_length; | 335 | buf += item_length; |
271 | length += item_length; | 336 | length += item_length; |
272 | item_length = sprintf(buf, | 337 | item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d", |
273 | "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", | ||
274 | atomic_read(&tcon->num_opens), | ||
275 | atomic_read(&tcon->num_deletes), | ||
276 | atomic_read(&tcon->num_mkdirs), | 338 | atomic_read(&tcon->num_mkdirs), |
277 | atomic_read(&tcon->num_rmdirs)); | 339 | atomic_read(&tcon->num_rmdirs)); |
278 | buf += item_length; | 340 | buf += item_length; |
279 | length += item_length; | 341 | length += item_length; |
280 | item_length = sprintf(buf, | 342 | item_length = sprintf(buf, "\nRenames: %d T2 Renames %d", |
281 | "\nRenames: %d T2 Renames %d", | ||
282 | atomic_read(&tcon->num_renames), | 343 | atomic_read(&tcon->num_renames), |
283 | atomic_read(&tcon->num_t2renames)); | 344 | atomic_read(&tcon->num_t2renames)); |
284 | buf += item_length; | 345 | buf += item_length; |
285 | length += item_length; | 346 | length += item_length; |
347 | item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d", | ||
348 | atomic_read(&tcon->num_ffirst), | ||
349 | atomic_read(&tcon->num_fnext), | ||
350 | atomic_read(&tcon->num_fclose)); | ||
351 | buf += item_length; | ||
352 | length += item_length; | ||
286 | } | 353 | } |
287 | read_unlock(&GlobalSMBSeslock); | 354 | read_unlock(&GlobalSMBSeslock); |
288 | 355 | ||
@@ -341,8 +408,10 @@ cifs_proc_init(void) | |||
341 | cifs_debug_data_read, NULL); | 408 | cifs_debug_data_read, NULL); |
342 | 409 | ||
343 | #ifdef CONFIG_CIFS_STATS | 410 | #ifdef CONFIG_CIFS_STATS |
344 | create_proc_read_entry("Stats", 0, proc_fs_cifs, | 411 | pde = create_proc_read_entry("Stats", 0, proc_fs_cifs, |
345 | cifs_stats_read, NULL); | 412 | cifs_stats_read, NULL); |
413 | if (pde) | ||
414 | pde->write_proc = cifs_stats_write; | ||
346 | #endif | 415 | #endif |
347 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, | 416 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, |
348 | cifsFYI_read, NULL); | 417 | cifsFYI_read, NULL); |
@@ -360,7 +429,7 @@ cifs_proc_init(void) | |||
360 | if (pde) | 429 | if (pde) |
361 | pde->write_proc = oplockEnabled_write; | 430 | pde->write_proc = oplockEnabled_write; |
362 | 431 | ||
363 | pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs, | 432 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, |
364 | quotaEnabled_read, NULL); | 433 | quotaEnabled_read, NULL); |
365 | if (pde) | 434 | if (pde) |
366 | pde->write_proc = quotaEnabled_write; | 435 | pde->write_proc = quotaEnabled_write; |
@@ -419,7 +488,7 @@ cifs_proc_clean(void) | |||
419 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); | 488 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); |
420 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); | 489 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); |
421 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); | 490 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); |
422 | remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs); | 491 | remove_proc_entry("Experimental",proc_fs_cifs); |
423 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); | 492 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); |
424 | remove_proc_entry("cifs", proc_root_fs); | 493 | remove_proc_entry("cifs", proc_root_fs); |
425 | } | 494 | } |
@@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer, | |||
459 | cifsFYI = 0; | 528 | cifsFYI = 0; |
460 | else if (c == '1' || c == 'y' || c == 'Y') | 529 | else if (c == '1' || c == 'y' || c == 'Y') |
461 | cifsFYI = 1; | 530 | cifsFYI = 1; |
531 | else if((c > '1') && (c <= '9')) | ||
532 | cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */ | ||
462 | 533 | ||
463 | return count; | 534 | return count; |
464 | } | 535 | } |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index bf24d2828f68..4304d9dcfb6c 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
@@ -26,6 +26,9 @@ | |||
26 | void cifs_dump_mem(char *label, void *data, int length); | 26 | void cifs_dump_mem(char *label, void *data, int length); |
27 | extern int traceSMB; /* flag which enables the function below */ | 27 | extern int traceSMB; /* flag which enables the function below */ |
28 | void dump_smb(struct smb_hdr *, int); | 28 | void dump_smb(struct smb_hdr *, int); |
29 | #define CIFS_INFO 0x01 | ||
30 | #define CIFS_RC 0x02 | ||
31 | #define CIFS_TIMER 0x04 | ||
29 | 32 | ||
30 | /* | 33 | /* |
31 | * debug ON | 34 | * debug ON |
@@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int); | |||
36 | 39 | ||
37 | /* information message: e.g., configuration, major event */ | 40 | /* information message: e.g., configuration, major event */ |
38 | extern int cifsFYI; | 41 | extern int cifsFYI; |
39 | #define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) | 42 | #define cifsfyi(format,arg...) if (cifsFYI & CIFS_INFO) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) |
40 | 43 | ||
41 | #define cFYI(button,prspec) if (button) cifsfyi prspec | 44 | #define cFYI(button,prspec) if (button) cifsfyi prspec |
42 | 45 | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ec00d61d5308..f799f6f0e729 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -24,6 +24,9 @@ | |||
24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ | 24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ |
25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ | 25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ |
26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ | 26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ |
27 | #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ | ||
28 | #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ | ||
29 | #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ | ||
27 | 30 | ||
28 | struct cifs_sb_info { | 31 | struct cifs_sb_info { |
29 | struct cifsTconInfo *tcon; /* primary mount */ | 32 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1ebf7dafc1d7..877095a1192a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0; | |||
59 | unsigned int sign_CIFS_PDUs = 1; | 59 | unsigned int sign_CIFS_PDUs = 1; |
60 | extern struct task_struct * oplockThread; /* remove sparse warning */ | 60 | extern struct task_struct * oplockThread; /* remove sparse warning */ |
61 | struct task_struct * oplockThread = NULL; | 61 | struct task_struct * oplockThread = NULL; |
62 | extern struct task_struct * dnotifyThread; /* remove sparse warning */ | ||
63 | struct task_struct * dnotifyThread = NULL; | ||
62 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | 64 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
63 | module_param(CIFSMaxBufSize, int, 0); | 65 | module_param(CIFSMaxBufSize, int, 0); |
64 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); | 66 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); |
@@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0); | |||
73 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); | 75 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); |
74 | 76 | ||
75 | static DECLARE_COMPLETION(cifs_oplock_exited); | 77 | static DECLARE_COMPLETION(cifs_oplock_exited); |
78 | static DECLARE_COMPLETION(cifs_dnotify_exited); | ||
76 | 79 | ||
77 | extern mempool_t *cifs_sm_req_poolp; | 80 | extern mempool_t *cifs_sm_req_poolp; |
78 | extern mempool_t *cifs_req_poolp; | 81 | extern mempool_t *cifs_req_poolp; |
@@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) | |||
202 | #endif /* CIFS_EXPERIMENTAL */ | 205 | #endif /* CIFS_EXPERIMENTAL */ |
203 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); | 206 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); |
204 | 207 | ||
208 | /* Old Windows servers do not support level 103, retry with level | ||
209 | one if old server failed the previous call */ | ||
210 | if(rc) | ||
211 | rc = SMBOldQFSInfo(xid, pTcon, buf); | ||
205 | /* | 212 | /* |
206 | int f_type; | 213 | int f_type; |
207 | __fsid_t f_fsid; | 214 | __fsid_t f_fsid; |
@@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
253 | cifs_inode->clientCanCacheAll = FALSE; | 260 | cifs_inode->clientCanCacheAll = FALSE; |
254 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; | 261 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; |
255 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 262 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
256 | 263 | cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; | |
257 | INIT_LIST_HEAD(&cifs_inode->openFileList); | 264 | INIT_LIST_HEAD(&cifs_inode->openFileList); |
258 | return &cifs_inode->vfs_inode; | 265 | return &cifs_inode->vfs_inode; |
259 | } | 266 | } |
@@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = { | |||
398 | }; | 405 | }; |
399 | #endif | 406 | #endif |
400 | 407 | ||
408 | static void cifs_umount_begin(struct super_block * sblock) | ||
409 | { | ||
410 | struct cifs_sb_info *cifs_sb; | ||
411 | struct cifsTconInfo * tcon; | ||
412 | |||
413 | cifs_sb = CIFS_SB(sblock); | ||
414 | if(cifs_sb == NULL) | ||
415 | return; | ||
416 | |||
417 | tcon = cifs_sb->tcon; | ||
418 | if(tcon == NULL) | ||
419 | return; | ||
420 | down(&tcon->tconSem); | ||
421 | if (atomic_read(&tcon->useCount) == 1) | ||
422 | tcon->tidStatus = CifsExiting; | ||
423 | up(&tcon->tconSem); | ||
424 | |||
425 | if(tcon->ses && tcon->ses->server) | ||
426 | { | ||
427 | cERROR(1,("wake up tasks now - umount begin not complete")); | ||
428 | wake_up_all(&tcon->ses->server->request_q); | ||
429 | } | ||
430 | /* BB FIXME - finish add checks for tidStatus BB */ | ||
431 | |||
432 | return; | ||
433 | } | ||
434 | |||
435 | |||
401 | static int cifs_remount(struct super_block *sb, int *flags, char *data) | 436 | static int cifs_remount(struct super_block *sb, int *flags, char *data) |
402 | { | 437 | { |
403 | *flags |= MS_NODIRATIME; | 438 | *flags |= MS_NODIRATIME; |
@@ -415,7 +450,7 @@ struct super_operations cifs_super_ops = { | |||
415 | unless later we add lazy close of inodes or unless the kernel forgets to call | 450 | unless later we add lazy close of inodes or unless the kernel forgets to call |
416 | us with the same number of releases (closes) as opens */ | 451 | us with the same number of releases (closes) as opens */ |
417 | .show_options = cifs_show_options, | 452 | .show_options = cifs_show_options, |
418 | /* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ | 453 | /* .umount_begin = cifs_umount_begin, */ /* BB finish in the future */ |
419 | .remount_fs = cifs_remount, | 454 | .remount_fs = cifs_remount, |
420 | }; | 455 | }; |
421 | 456 | ||
@@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg) | |||
783 | do { | 818 | do { |
784 | if (try_to_freeze()) | 819 | if (try_to_freeze()) |
785 | continue; | 820 | continue; |
786 | set_current_state(TASK_INTERRUPTIBLE); | ||
787 | 821 | ||
788 | schedule_timeout(1*HZ); | ||
789 | spin_lock(&GlobalMid_Lock); | 822 | spin_lock(&GlobalMid_Lock); |
790 | if(list_empty(&GlobalOplock_Q)) { | 823 | if(list_empty(&GlobalOplock_Q)) { |
791 | spin_unlock(&GlobalMid_Lock); | 824 | spin_unlock(&GlobalMid_Lock); |
@@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg) | |||
834 | } | 867 | } |
835 | } else | 868 | } else |
836 | spin_unlock(&GlobalMid_Lock); | 869 | spin_unlock(&GlobalMid_Lock); |
870 | set_current_state(TASK_INTERRUPTIBLE); | ||
871 | schedule_timeout(1); /* yield in case q were corrupt */ | ||
837 | } | 872 | } |
838 | } while(!signal_pending(current)); | 873 | } while(!signal_pending(current)); |
839 | complete_and_exit (&cifs_oplock_exited, 0); | ||
840 | oplockThread = NULL; | 874 | oplockThread = NULL; |
875 | complete_and_exit (&cifs_oplock_exited, 0); | ||
876 | } | ||
877 | |||
878 | static int cifs_dnotify_thread(void * dummyarg) | ||
879 | { | ||
880 | daemonize("cifsdnotifyd"); | ||
881 | allow_signal(SIGTERM); | ||
882 | |||
883 | dnotifyThread = current; | ||
884 | do { | ||
885 | if(try_to_freeze()) | ||
886 | continue; | ||
887 | set_current_state(TASK_INTERRUPTIBLE); | ||
888 | schedule_timeout(39*HZ); | ||
889 | } while(!signal_pending(current)); | ||
890 | complete_and_exit (&cifs_dnotify_exited, 0); | ||
841 | } | 891 | } |
842 | 892 | ||
843 | static int __init | 893 | static int __init |
@@ -851,6 +901,10 @@ init_cifs(void) | |||
851 | INIT_LIST_HEAD(&GlobalSMBSessionList); | 901 | INIT_LIST_HEAD(&GlobalSMBSessionList); |
852 | INIT_LIST_HEAD(&GlobalTreeConnectionList); | 902 | INIT_LIST_HEAD(&GlobalTreeConnectionList); |
853 | INIT_LIST_HEAD(&GlobalOplock_Q); | 903 | INIT_LIST_HEAD(&GlobalOplock_Q); |
904 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
905 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | ||
906 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); | ||
907 | #endif | ||
854 | /* | 908 | /* |
855 | * Initialize Global counters | 909 | * Initialize Global counters |
856 | */ | 910 | */ |
@@ -886,10 +940,16 @@ init_cifs(void) | |||
886 | if (!rc) { | 940 | if (!rc) { |
887 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, | 941 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, |
888 | CLONE_FS | CLONE_FILES | CLONE_VM); | 942 | CLONE_FS | CLONE_FILES | CLONE_VM); |
889 | if(rc > 0) | 943 | if(rc > 0) { |
890 | return 0; | 944 | rc = (int)kernel_thread(cifs_dnotify_thread, NULL, |
891 | else | 945 | CLONE_FS | CLONE_FILES | CLONE_VM); |
946 | if(rc > 0) | ||
947 | return 0; | ||
948 | else | ||
949 | cERROR(1,("error %d create dnotify thread", rc)); | ||
950 | } else { | ||
892 | cERROR(1,("error %d create oplock thread",rc)); | 951 | cERROR(1,("error %d create oplock thread",rc)); |
952 | } | ||
893 | } | 953 | } |
894 | cifs_destroy_request_bufs(); | 954 | cifs_destroy_request_bufs(); |
895 | } | 955 | } |
@@ -918,6 +978,10 @@ exit_cifs(void) | |||
918 | send_sig(SIGTERM, oplockThread, 1); | 978 | send_sig(SIGTERM, oplockThread, 1); |
919 | wait_for_completion(&cifs_oplock_exited); | 979 | wait_for_completion(&cifs_oplock_exited); |
920 | } | 980 | } |
981 | if(dnotifyThread) { | ||
982 | send_sig(SIGTERM, dnotifyThread, 1); | ||
983 | wait_for_completion(&cifs_dnotify_exited); | ||
984 | } | ||
921 | } | 985 | } |
922 | 986 | ||
923 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); | 987 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 1fd21f66f243..1223fa81dbd2 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); | |||
81 | 81 | ||
82 | /* Functions related to dir entries */ | 82 | /* Functions related to dir entries */ |
83 | extern struct dentry_operations cifs_dentry_ops; | 83 | extern struct dentry_operations cifs_dentry_ops; |
84 | extern struct dentry_operations cifs_ci_dentry_ops; | ||
84 | 85 | ||
85 | /* Functions related to symlinks */ | 86 | /* Functions related to symlinks */ |
86 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); | 87 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); |
@@ -96,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 97 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
97 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 98 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
98 | unsigned int command, unsigned long arg); | 99 | unsigned int command, unsigned long arg); |
99 | #define CIFS_VERSION "1.35" | 100 | #define CIFS_VERSION "1.39" |
100 | #endif /* _CIFSFS_H */ | 101 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 81babab265e1..1ba08f8c5bc4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -110,8 +110,9 @@ enum protocolEnum { | |||
110 | */ | 110 | */ |
111 | 111 | ||
112 | struct TCP_Server_Info { | 112 | struct TCP_Server_Info { |
113 | char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ | 113 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
114 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ | 114 | char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; |
115 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; | ||
115 | struct socket *ssocket; | 116 | struct socket *ssocket; |
116 | union { | 117 | union { |
117 | struct sockaddr_in sockAddr; | 118 | struct sockaddr_in sockAddr; |
@@ -122,13 +123,17 @@ struct TCP_Server_Info { | |||
122 | struct list_head pending_mid_q; | 123 | struct list_head pending_mid_q; |
123 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | 124 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ |
124 | unsigned short server_codepage; /* codepage for the server */ | 125 | unsigned short server_codepage; /* codepage for the server */ |
125 | unsigned long ip_address; /* IP addr for the server if known */ | 126 | unsigned long ip_address; /* IP addr for the server if known */ |
126 | enum protocolEnum protocolType; | 127 | enum protocolEnum protocolType; |
127 | char versionMajor; | 128 | char versionMajor; |
128 | char versionMinor; | 129 | char versionMinor; |
129 | unsigned svlocal:1; /* local server or remote */ | 130 | unsigned svlocal:1; /* local server or remote */ |
130 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ | 131 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ |
131 | atomic_t inFlight; /* number of requests on the wire to server */ | 132 | atomic_t inFlight; /* number of requests on the wire to server */ |
133 | #ifdef CONFIG_CIFS_STATS2 | ||
134 | atomic_t inSend; /* requests trying to send */ | ||
135 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
136 | #endif | ||
132 | enum statusEnum tcpStatus; /* what we think the status is */ | 137 | enum statusEnum tcpStatus; /* what we think the status is */ |
133 | struct semaphore tcpSem; | 138 | struct semaphore tcpSem; |
134 | struct task_struct *tsk; | 139 | struct task_struct *tsk; |
@@ -147,8 +152,10 @@ struct TCP_Server_Info { | |||
147 | /* (returned on Negotiate */ | 152 | /* (returned on Negotiate */ |
148 | int capabilities; /* allow selective disabling of caps by smb sess */ | 153 | int capabilities; /* allow selective disabling of caps by smb sess */ |
149 | __u16 timeZone; | 154 | __u16 timeZone; |
155 | __u16 CurrentMid; /* multiplex id - rotating counter */ | ||
150 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | 156 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; |
151 | char workstation_RFC1001_name[16]; /* 16th byte is always zero */ | 157 | /* 16th byte of RFC1001 workstation name is always null */ |
158 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; | ||
152 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 159 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
153 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | 160 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; |
154 | }; | 161 | }; |
@@ -214,19 +221,41 @@ struct cifsTconInfo { | |||
214 | atomic_t num_reads; | 221 | atomic_t num_reads; |
215 | atomic_t num_oplock_brks; | 222 | atomic_t num_oplock_brks; |
216 | atomic_t num_opens; | 223 | atomic_t num_opens; |
224 | atomic_t num_closes; | ||
217 | atomic_t num_deletes; | 225 | atomic_t num_deletes; |
218 | atomic_t num_mkdirs; | 226 | atomic_t num_mkdirs; |
219 | atomic_t num_rmdirs; | 227 | atomic_t num_rmdirs; |
220 | atomic_t num_renames; | 228 | atomic_t num_renames; |
221 | atomic_t num_t2renames; | 229 | atomic_t num_t2renames; |
230 | atomic_t num_ffirst; | ||
231 | atomic_t num_fnext; | ||
232 | atomic_t num_fclose; | ||
233 | atomic_t num_hardlinks; | ||
234 | atomic_t num_symlinks; | ||
235 | atomic_t num_locks; | ||
236 | #ifdef CONFIG_CIFS_STATS2 | ||
237 | unsigned long long time_writes; | ||
238 | unsigned long long time_reads; | ||
239 | unsigned long long time_opens; | ||
240 | unsigned long long time_deletes; | ||
241 | unsigned long long time_closes; | ||
242 | unsigned long long time_mkdirs; | ||
243 | unsigned long long time_rmdirs; | ||
244 | unsigned long long time_renames; | ||
245 | unsigned long long time_t2renames; | ||
246 | unsigned long long time_ffirst; | ||
247 | unsigned long long time_fnext; | ||
248 | unsigned long long time_fclose; | ||
249 | #endif /* CONFIG_CIFS_STATS2 */ | ||
222 | __u64 bytes_read; | 250 | __u64 bytes_read; |
223 | __u64 bytes_written; | 251 | __u64 bytes_written; |
224 | spinlock_t stat_lock; | 252 | spinlock_t stat_lock; |
225 | #endif | 253 | #endif /* CONFIG_CIFS_STATS */ |
226 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; | 254 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; |
227 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ | 255 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ |
228 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; | 256 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; |
229 | unsigned retry:1; | 257 | unsigned retry:1; |
258 | unsigned nocase:1; | ||
230 | /* BB add field for back pointer to sb struct? */ | 259 | /* BB add field for back pointer to sb struct? */ |
231 | }; | 260 | }; |
232 | 261 | ||
@@ -270,6 +299,7 @@ struct cifsFileInfo { | |||
270 | struct inode * pInode; /* needed for oplock break */ | 299 | struct inode * pInode; /* needed for oplock break */ |
271 | unsigned closePend:1; /* file is marked to close */ | 300 | unsigned closePend:1; /* file is marked to close */ |
272 | unsigned invalidHandle:1; /* file closed via session abend */ | 301 | unsigned invalidHandle:1; /* file closed via session abend */ |
302 | atomic_t wrtPending; /* handle in use - defer close */ | ||
273 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | 303 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ |
274 | char * search_resume_name; /* BB removeme BB */ | 304 | char * search_resume_name; /* BB removeme BB */ |
275 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ | 305 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ |
@@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb) | |||
306 | return sb->s_fs_info; | 336 | return sb->s_fs_info; |
307 | } | 337 | } |
308 | 338 | ||
339 | static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) | ||
340 | { | ||
341 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | ||
342 | return '/'; | ||
343 | else | ||
344 | return '\\'; | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_CIFS_STATS | ||
348 | #define cifs_stats_inc atomic_inc | ||
349 | |||
350 | static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon, | ||
351 | unsigned int bytes) | ||
352 | { | ||
353 | if (bytes) { | ||
354 | spin_lock(&tcon->stat_lock); | ||
355 | tcon->bytes_written += bytes; | ||
356 | spin_unlock(&tcon->stat_lock); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | ||
361 | unsigned int bytes) | ||
362 | { | ||
363 | spin_lock(&tcon->stat_lock); | ||
364 | tcon->bytes_read += bytes; | ||
365 | spin_unlock(&tcon->stat_lock); | ||
366 | } | ||
367 | #else | ||
368 | |||
369 | #define cifs_stats_inc(field) do {} while(0) | ||
370 | #define cifs_stats_bytes_written(tcon, bytes) do {} while(0) | ||
371 | #define cifs_stats_bytes_read(tcon, bytes) do {} while(0) | ||
372 | |||
373 | #endif | ||
309 | 374 | ||
310 | /* one of these for every pending CIFS request to the server */ | 375 | /* one of these for every pending CIFS request to the server */ |
311 | struct mid_q_entry { | 376 | struct mid_q_entry { |
@@ -313,7 +378,11 @@ struct mid_q_entry { | |||
313 | __u16 mid; /* multiplex id */ | 378 | __u16 mid; /* multiplex id */ |
314 | __u16 pid; /* process id */ | 379 | __u16 pid; /* process id */ |
315 | __u32 sequence_number; /* for CIFS signing */ | 380 | __u32 sequence_number; /* for CIFS signing */ |
316 | struct timeval when_sent; /* time when smb sent */ | 381 | unsigned long when_alloc; /* when mid was created */ |
382 | #ifdef CONFIG_CIFS_STATS2 | ||
383 | unsigned long when_sent; /* time when smb send finished */ | ||
384 | unsigned long when_received; /* when demux complete (taken off wire) */ | ||
385 | #endif | ||
317 | struct cifsSesInfo *ses; /* smb was sent to this server */ | 386 | struct cifsSesInfo *ses; /* smb was sent to this server */ |
318 | struct task_struct *tsk; /* task waiting for response */ | 387 | struct task_struct *tsk; /* task waiting for response */ |
319 | struct smb_hdr *resp_buf; /* response buffer */ | 388 | struct smb_hdr *resp_buf; /* response buffer */ |
@@ -331,6 +400,20 @@ struct oplock_q_entry { | |||
331 | __u16 netfid; | 400 | __u16 netfid; |
332 | }; | 401 | }; |
333 | 402 | ||
403 | /* for pending dnotify requests */ | ||
404 | struct dir_notify_req { | ||
405 | struct list_head lhead; | ||
406 | __le16 Pid; | ||
407 | __le16 PidHigh; | ||
408 | __u16 Mid; | ||
409 | __u16 Tid; | ||
410 | __u16 Uid; | ||
411 | __u16 netfid; | ||
412 | __u32 filter; /* CompletionFilter (for multishot) */ | ||
413 | int multishot; | ||
414 | struct file * pfile; | ||
415 | }; | ||
416 | |||
334 | #define MID_FREE 0 | 417 | #define MID_FREE 0 |
335 | #define MID_REQUEST_ALLOCATED 1 | 418 | #define MID_REQUEST_ALLOCATED 1 |
336 | #define MID_REQUEST_SUBMITTED 2 | 419 | #define MID_REQUEST_SUBMITTED 2 |
@@ -399,6 +482,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ | |||
399 | 482 | ||
400 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 483 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; |
401 | 484 | ||
485 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ | ||
486 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */ | ||
487 | |||
402 | /* | 488 | /* |
403 | * Global transaction id (XID) information | 489 | * Global transaction id (XID) information |
404 | */ | 490 | */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index aede6a813167..193f06eb43f9 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -36,9 +36,11 @@ | |||
36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ | 36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ |
37 | #define SMB_COM_DELETE 0x06 /* trivial response */ | 37 | #define SMB_COM_DELETE 0x06 /* trivial response */ |
38 | #define SMB_COM_RENAME 0x07 /* trivial response */ | 38 | #define SMB_COM_RENAME 0x07 /* trivial response */ |
39 | #define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */ | ||
39 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | 40 | #define SMB_COM_SETATTR 0x09 /* trivial response */ |
40 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | 41 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ |
41 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | 42 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ |
43 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ | ||
42 | #define SMB_COM_READ_ANDX 0x2E | 44 | #define SMB_COM_READ_ANDX 0x2E |
43 | #define SMB_COM_WRITE_ANDX 0x2F | 45 | #define SMB_COM_WRITE_ANDX 0x2F |
44 | #define SMB_COM_TRANSACTION2 0x32 | 46 | #define SMB_COM_TRANSACTION2 0x32 |
@@ -52,6 +54,7 @@ | |||
52 | #define SMB_COM_NT_TRANSACT 0xA0 | 54 | #define SMB_COM_NT_TRANSACT 0xA0 |
53 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 | 55 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 |
54 | #define SMB_COM_NT_CREATE_ANDX 0xA2 | 56 | #define SMB_COM_NT_CREATE_ANDX 0xA2 |
57 | #define SMB_COM_NT_CANCEL 0xA4 /* no response */ | ||
55 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ | 58 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ |
56 | 59 | ||
57 | /* Transact2 subcommand codes */ | 60 | /* Transact2 subcommand codes */ |
@@ -59,6 +62,7 @@ | |||
59 | #define TRANS2_FIND_FIRST 0x01 | 62 | #define TRANS2_FIND_FIRST 0x01 |
60 | #define TRANS2_FIND_NEXT 0x02 | 63 | #define TRANS2_FIND_NEXT 0x02 |
61 | #define TRANS2_QUERY_FS_INFORMATION 0x03 | 64 | #define TRANS2_QUERY_FS_INFORMATION 0x03 |
65 | #define TRANS2_SET_FS_INFORMATION 0x04 | ||
62 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 | 66 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 |
63 | #define TRANS2_SET_PATH_INFORMATION 0x06 | 67 | #define TRANS2_SET_PATH_INFORMATION 0x06 |
64 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 | 68 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 |
@@ -267,10 +271,18 @@ | |||
267 | /* CreateOptions */ | 271 | /* CreateOptions */ |
268 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ | 272 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ |
269 | #define CREATE_WRITE_THROUGH 0x00000002 | 273 | #define CREATE_WRITE_THROUGH 0x00000002 |
270 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | 274 | #define CREATE_SEQUENTIAL 0x00000004 |
275 | #define CREATE_SYNC_ALERT 0x00000010 | ||
276 | #define CREATE_ASYNC_ALERT 0x00000020 | ||
277 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | ||
278 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 | ||
279 | #define CREATE_EIGHT_DOT_THREE 0x00000400 | ||
271 | #define CREATE_RANDOM_ACCESS 0x00000800 | 280 | #define CREATE_RANDOM_ACCESS 0x00000800 |
272 | #define CREATE_DELETE_ON_CLOSE 0x00001000 | 281 | #define CREATE_DELETE_ON_CLOSE 0x00001000 |
282 | #define CREATE_OPEN_BY_ID 0x00002000 | ||
273 | #define OPEN_REPARSE_POINT 0x00200000 | 283 | #define OPEN_REPARSE_POINT 0x00200000 |
284 | #define CREATE_OPTIONS_MASK 0x007FFFFF | ||
285 | #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ | ||
274 | 286 | ||
275 | /* ImpersonationLevel flags */ | 287 | /* ImpersonationLevel flags */ |
276 | #define SECURITY_ANONYMOUS 0 | 288 | #define SECURITY_ANONYMOUS 0 |
@@ -614,6 +626,7 @@ typedef struct smb_com_findclose_req { | |||
614 | } FINDCLOSE_REQ; | 626 | } FINDCLOSE_REQ; |
615 | 627 | ||
616 | /* OpenFlags */ | 628 | /* OpenFlags */ |
629 | #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ | ||
617 | #define REQ_OPLOCK 0x00000002 | 630 | #define REQ_OPLOCK 0x00000002 |
618 | #define REQ_BATCHOPLOCK 0x00000004 | 631 | #define REQ_BATCHOPLOCK 0x00000004 |
619 | #define REQ_OPENDIRONLY 0x00000008 | 632 | #define REQ_OPENDIRONLY 0x00000008 |
@@ -669,6 +682,62 @@ typedef struct smb_com_open_rsp { | |||
669 | __u16 ByteCount; /* bct = 0 */ | 682 | __u16 ByteCount; /* bct = 0 */ |
670 | } OPEN_RSP; | 683 | } OPEN_RSP; |
671 | 684 | ||
685 | /* format of legacy open request */ | ||
686 | typedef struct smb_com_openx_req { | ||
687 | struct smb_hdr hdr; /* wct = 15 */ | ||
688 | __u8 AndXCommand; | ||
689 | __u8 AndXReserved; | ||
690 | __le16 AndXOffset; | ||
691 | __le16 OpenFlags; | ||
692 | __le16 Mode; | ||
693 | __le16 Sattr; /* search attributes */ | ||
694 | __le16 FileAttributes; /* dos attrs */ | ||
695 | __le32 CreateTime; /* os2 format */ | ||
696 | __le16 OpenFunction; | ||
697 | __le32 EndOfFile; | ||
698 | __le32 Timeout; | ||
699 | __le32 Reserved; | ||
700 | __le16 ByteCount; /* file name follows */ | ||
701 | char fileName[1]; | ||
702 | } OPENX_REQ; | ||
703 | |||
704 | typedef struct smb_com_openx_rsp { | ||
705 | struct smb_hdr hdr; /* wct = 15 */ | ||
706 | __u8 AndXCommand; | ||
707 | __u8 AndXReserved; | ||
708 | __le16 AndXOffset; | ||
709 | __u16 Fid; | ||
710 | __le16 FileAttributes; | ||
711 | __le32 LastWriteTime; /* os2 format */ | ||
712 | __le32 EndOfFile; | ||
713 | __le16 Access; | ||
714 | __le16 FileType; | ||
715 | __le16 IPCState; | ||
716 | __le16 Action; | ||
717 | __u32 FileId; | ||
718 | __u16 Reserved; | ||
719 | __u16 ByteCount; | ||
720 | } OPENX_RSP; | ||
721 | |||
722 | /* Legacy write request for older servers */ | ||
723 | typedef struct smb_com_writex_req { | ||
724 | struct smb_hdr hdr; /* wct = 12 */ | ||
725 | __u8 AndXCommand; | ||
726 | __u8 AndXReserved; | ||
727 | __le16 AndXOffset; | ||
728 | __u16 Fid; | ||
729 | __le32 OffsetLow; | ||
730 | __u32 Reserved; /* Timeout */ | ||
731 | __le16 WriteMode; /* 1 = write through */ | ||
732 | __le16 Remaining; | ||
733 | __le16 Reserved2; | ||
734 | __le16 DataLengthLow; | ||
735 | __le16 DataOffset; | ||
736 | __le16 ByteCount; | ||
737 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | ||
738 | char Data[0]; | ||
739 | } WRITEX_REQ; | ||
740 | |||
672 | typedef struct smb_com_write_req { | 741 | typedef struct smb_com_write_req { |
673 | struct smb_hdr hdr; /* wct = 14 */ | 742 | struct smb_hdr hdr; /* wct = 14 */ |
674 | __u8 AndXCommand; | 743 | __u8 AndXCommand; |
@@ -700,6 +769,21 @@ typedef struct smb_com_write_rsp { | |||
700 | __u16 ByteCount; | 769 | __u16 ByteCount; |
701 | } WRITE_RSP; | 770 | } WRITE_RSP; |
702 | 771 | ||
772 | /* legacy read request for older servers */ | ||
773 | typedef struct smb_com_readx_req { | ||
774 | struct smb_hdr hdr; /* wct = 10 */ | ||
775 | __u8 AndXCommand; | ||
776 | __u8 AndXReserved; | ||
777 | __le16 AndXOffset; | ||
778 | __u16 Fid; | ||
779 | __le32 OffsetLow; | ||
780 | __le16 MaxCount; | ||
781 | __le16 MinCount; /* obsolete */ | ||
782 | __le32 Reserved; | ||
783 | __le16 Remaining; | ||
784 | __le16 ByteCount; | ||
785 | } READX_REQ; | ||
786 | |||
703 | typedef struct smb_com_read_req { | 787 | typedef struct smb_com_read_req { |
704 | struct smb_hdr hdr; /* wct = 12 */ | 788 | struct smb_hdr hdr; /* wct = 12 */ |
705 | __u8 AndXCommand; | 789 | __u8 AndXCommand; |
@@ -876,6 +960,22 @@ typedef struct smb_com_create_directory_rsp { | |||
876 | __u16 ByteCount; /* bct = 0 */ | 960 | __u16 ByteCount; /* bct = 0 */ |
877 | } CREATE_DIRECTORY_RSP; | 961 | } CREATE_DIRECTORY_RSP; |
878 | 962 | ||
963 | typedef struct smb_com_query_information_req { | ||
964 | struct smb_hdr hdr; /* wct = 0 */ | ||
965 | __le16 ByteCount; /* 1 + namelen + 1 */ | ||
966 | __u8 BufferFormat; /* 4 = ASCII */ | ||
967 | unsigned char FileName[1]; | ||
968 | } QUERY_INFORMATION_REQ; | ||
969 | |||
970 | typedef struct smb_com_query_information_rsp { | ||
971 | struct smb_hdr hdr; /* wct = 10 */ | ||
972 | __le16 attr; | ||
973 | __le32 last_write_time; | ||
974 | __le32 size; | ||
975 | __u16 reserved[5]; | ||
976 | __le16 ByteCount; /* bcc = 0 */ | ||
977 | } QUERY_INFORMATION_RSP; | ||
978 | |||
879 | typedef struct smb_com_setattr_req { | 979 | typedef struct smb_com_setattr_req { |
880 | struct smb_hdr hdr; /* wct = 8 */ | 980 | struct smb_hdr hdr; /* wct = 8 */ |
881 | __le16 attr; | 981 | __le16 attr; |
@@ -1411,6 +1511,43 @@ typedef struct smb_com_transaction_qfsi_rsp { | |||
1411 | __u8 Pad; /* may be three bytes *//* followed by data area */ | 1511 | __u8 Pad; /* may be three bytes *//* followed by data area */ |
1412 | } TRANSACTION2_QFSI_RSP; | 1512 | } TRANSACTION2_QFSI_RSP; |
1413 | 1513 | ||
1514 | |||
1515 | /* SETFSInfo Levels */ | ||
1516 | #define SMB_SET_CIFS_UNIX_INFO 0x200 | ||
1517 | typedef struct smb_com_transaction2_setfsi_req { | ||
1518 | struct smb_hdr hdr; /* wct = 15 */ | ||
1519 | __le16 TotalParameterCount; | ||
1520 | __le16 TotalDataCount; | ||
1521 | __le16 MaxParameterCount; | ||
1522 | __le16 MaxDataCount; | ||
1523 | __u8 MaxSetupCount; | ||
1524 | __u8 Reserved; | ||
1525 | __le16 Flags; | ||
1526 | __le32 Timeout; | ||
1527 | __u16 Reserved2; | ||
1528 | __le16 ParameterCount; /* 4 */ | ||
1529 | __le16 ParameterOffset; | ||
1530 | __le16 DataCount; /* 12 */ | ||
1531 | __le16 DataOffset; | ||
1532 | __u8 SetupCount; /* one */ | ||
1533 | __u8 Reserved3; | ||
1534 | __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */ | ||
1535 | __le16 ByteCount; | ||
1536 | __u8 Pad; | ||
1537 | __u16 FileNum; /* Parameters start. */ | ||
1538 | __le16 InformationLevel;/* Parameters end. */ | ||
1539 | __le16 ClientUnixMajor; /* Data start. */ | ||
1540 | __le16 ClientUnixMinor; | ||
1541 | __le64 ClientUnixCap; /* Data end */ | ||
1542 | } TRANSACTION2_SETFSI_REQ; | ||
1543 | |||
1544 | typedef struct smb_com_transaction2_setfsi_rsp { | ||
1545 | struct smb_hdr hdr; /* wct = 10 */ | ||
1546 | struct trans2_resp t2; | ||
1547 | __u16 ByteCount; | ||
1548 | } TRANSACTION2_SETFSI_RSP; | ||
1549 | |||
1550 | |||
1414 | typedef struct smb_com_transaction2_get_dfs_refer_req { | 1551 | typedef struct smb_com_transaction2_get_dfs_refer_req { |
1415 | struct smb_hdr hdr; /* wct = 15 */ | 1552 | struct smb_hdr hdr; /* wct = 15 */ |
1416 | __le16 TotalParameterCount; | 1553 | __le16 TotalParameterCount; |
@@ -1547,16 +1684,32 @@ typedef struct { | |||
1547 | } FILE_SYSTEM_INFO; /* size info, level 0x103 */ | 1684 | } FILE_SYSTEM_INFO; /* size info, level 0x103 */ |
1548 | 1685 | ||
1549 | typedef struct { | 1686 | typedef struct { |
1687 | __le32 fsid; | ||
1688 | __le32 SectorsPerAllocationUnit; | ||
1689 | __le32 TotalAllocationUnits; | ||
1690 | __le32 FreeAllocationUnits; | ||
1691 | __le16 BytesPerSector; | ||
1692 | } FILE_SYSTEM_ALLOC_INFO; | ||
1693 | |||
1694 | typedef struct { | ||
1550 | __le16 MajorVersionNumber; | 1695 | __le16 MajorVersionNumber; |
1551 | __le16 MinorVersionNumber; | 1696 | __le16 MinorVersionNumber; |
1552 | __le64 Capability; | 1697 | __le64 Capability; |
1553 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ | 1698 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ |
1699 | |||
1700 | /* Version numbers for CIFS UNIX major and minor. */ | ||
1701 | #define CIFS_UNIX_MAJOR_VERSION 1 | ||
1702 | #define CIFS_UNIX_MINOR_VERSION 0 | ||
1703 | |||
1554 | /* Linux/Unix extensions capability flags */ | 1704 | /* Linux/Unix extensions capability flags */ |
1555 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ | 1705 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ |
1556 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ | 1706 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ |
1557 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ | 1707 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ |
1558 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ | 1708 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ |
1709 | #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Use POSIX pathnames on the wire. */ | ||
1710 | |||
1559 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ | 1711 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ |
1712 | |||
1560 | typedef struct { | 1713 | typedef struct { |
1561 | /* For undefined recommended transfer size return -1 in that field */ | 1714 | /* For undefined recommended transfer size return -1 in that field */ |
1562 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ | 1715 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ |
@@ -1907,18 +2060,17 @@ struct data_blob { | |||
1907 | perhaps add a CreateDevice - to create Pipes and other special .inodes | 2060 | perhaps add a CreateDevice - to create Pipes and other special .inodes |
1908 | Also note POSIX open flags | 2061 | Also note POSIX open flags |
1909 | 2) Close - to return the last write time to do cache across close more safely | 2062 | 2) Close - to return the last write time to do cache across close more safely |
1910 | 3) PosixQFSInfo - to return statfs info | 2063 | 3) FindFirst return unique inode number - what about resume key, two |
1911 | 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) | 2064 | forms short (matches readdir) and full (enough info to cache inodes) |
1912 | 5) Mkdir - set mode | 2065 | 4) Mkdir - set mode |
1913 | 2066 | ||
1914 | And under consideration: | 2067 | And under consideration: |
1915 | 6) FindClose2 (return nanosecond timestamp ??) | 2068 | 5) FindClose2 (return nanosecond timestamp ??) |
1916 | 7) Use nanosecond timestamps throughout all time fields if | 2069 | 6) Use nanosecond timestamps throughout all time fields if |
1917 | corresponding attribute flag is set | 2070 | corresponding attribute flag is set |
1918 | 8) sendfile - handle based copy | 2071 | 7) sendfile - handle based copy |
1919 | 9) Direct i/o | 2072 | 8) Direct i/o |
1920 | 10) "POSIX ACL" support | 2073 | 9) Misc fcntls? |
1921 | 11) Misc fcntls? | ||
1922 | 2074 | ||
1923 | what about fixing 64 bit alignment | 2075 | what about fixing 64 bit alignment |
1924 | 2076 | ||
@@ -1974,7 +2126,7 @@ struct data_blob { | |||
1974 | 2126 | ||
1975 | */ | 2127 | */ |
1976 | 2128 | ||
1977 | /* xsymlink is a symlink format that can be used | 2129 | /* xsymlink is a symlink format (used by MacOS) that can be used |
1978 | to save symlink info in a regular file when | 2130 | to save symlink info in a regular file when |
1979 | mounted to operating systems that do not | 2131 | mounted to operating systems that do not |
1980 | support the cifs Unix extensions or EAs (for xattr | 2132 | support the cifs Unix extensions or EAs (for xattr |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ea239dea571e..d301149b1bb0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
47 | struct smb_hdr * /* input */ , | 47 | struct smb_hdr * /* input */ , |
48 | struct smb_hdr * /* out */ , | 48 | struct smb_hdr * /* out */ , |
49 | int * /* bytes returned */ , const int long_op); | 49 | int * /* bytes returned */ , const int long_op); |
50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | ||
51 | struct kvec *, int /* nvec */, | ||
52 | int * /* bytes returned */ , const int long_op); | ||
50 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
51 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
52 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 55 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
53 | extern int is_size_safe_to_change(struct cifsInodeInfo *); | 56 | extern int is_size_safe_to_change(struct cifsInodeInfo *); |
57 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); | ||
54 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 58 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
59 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | ||
55 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 60 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
56 | enum securityEnum *secType); | 61 | enum securityEnum *secType); |
57 | extern int cifs_inet_pton(int, char * source, void *dst); | 62 | extern int cifs_inet_pton(int, char * source, void *dst); |
58 | extern int map_smb_to_linux_error(struct smb_hdr *smb); | 63 | extern int map_smb_to_linux_error(struct smb_hdr *smb); |
59 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 64 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
60 | const struct cifsTconInfo *, int /* specifies length | 65 | const struct cifsTconInfo *, int /* length of |
61 | of fixed section (word count) in two byte units */ | 66 | fixed section (word count) in two byte units */); |
62 | ); | 67 | extern __u16 GetNextMid(struct TCP_Server_Info *server); |
63 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, | 68 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, |
64 | struct cifsTconInfo *); | 69 | struct cifsTconInfo *); |
65 | extern void DeleteOplockQEntry(struct oplock_q_entry *); | 70 | extern void DeleteOplockQEntry(struct oplock_q_entry *); |
@@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
89 | 94 | ||
90 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, |
91 | const char *searchName, const struct nls_table *nls_codepage, | 96 | const char *searchName, const struct nls_table *nls_codepage, |
92 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); | 97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); |
93 | 98 | ||
94 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 99 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, |
95 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | 100 | __u16 searchHandle, struct cifs_search_info * psrch_inf); |
@@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | |||
101 | const unsigned char *searchName, | 106 | const unsigned char *searchName, |
102 | FILE_ALL_INFO * findData, | 107 | FILE_ALL_INFO * findData, |
103 | const struct nls_table *nls_codepage, int remap); | 108 | const struct nls_table *nls_codepage, int remap); |
109 | extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
110 | const unsigned char *searchName, | ||
111 | FILE_ALL_INFO * findData, | ||
112 | const struct nls_table *nls_codepage, int remap); | ||
104 | 113 | ||
105 | extern int CIFSSMBUnixQPathInfo(const int xid, | 114 | extern int CIFSSMBUnixQPathInfo(const int xid, |
106 | struct cifsTconInfo *tcon, | 115 | struct cifsTconInfo *tcon, |
@@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | |||
125 | int remap); | 134 | int remap); |
126 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | 135 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, |
127 | struct kstatfs *FSData); | 136 | struct kstatfs *FSData); |
137 | extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, | ||
138 | struct kstatfs *FSData); | ||
139 | extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | ||
140 | __u64 cap); | ||
141 | |||
128 | extern int CIFSSMBQFSAttributeInfo(const int xid, | 142 | extern int CIFSSMBQFSAttributeInfo(const int xid, |
129 | struct cifsTconInfo *tcon); | 143 | struct cifsTconInfo *tcon); |
130 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); | 144 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); |
@@ -207,6 +221,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | |||
207 | const int access_flags, const int omode, | 221 | const int access_flags, const int omode, |
208 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | 222 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, |
209 | const struct nls_table *nls_codepage, int remap); | 223 | const struct nls_table *nls_codepage, int remap); |
224 | extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
225 | const char *fileName, const int disposition, | ||
226 | const int access_flags, const int omode, | ||
227 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | ||
228 | const struct nls_table *nls_codepage, int remap); | ||
210 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | 229 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, |
211 | const int smb_file_id); | 230 | const int smb_file_id); |
212 | 231 | ||
@@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
222 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 241 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
223 | const int netfid, const unsigned int count, | 242 | const int netfid, const unsigned int count, |
224 | const __u64 offset, unsigned int *nbytes, | 243 | const __u64 offset, unsigned int *nbytes, |
225 | const char __user *buf,const int long_op); | 244 | struct kvec *iov, const int nvec, const int long_op); |
226 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 245 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
227 | const unsigned char *searchName, __u64 * inode_number, | 246 | const unsigned char *searchName, __u64 * inode_number, |
228 | const struct nls_table *nls_codepage, | 247 | const struct nls_table *nls_codepage, |
@@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid, | |||
264 | int remap_special_chars); | 283 | int remap_special_chars); |
265 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 284 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
266 | const int notify_subdirs,const __u16 netfid, | 285 | const int notify_subdirs,const __u16 netfid, |
267 | __u32 filter, const struct nls_table *nls_codepage); | 286 | __u32 filter, struct file * file, int multishot, |
287 | const struct nls_table *nls_codepage); | ||
268 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 288 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
269 | const unsigned char *searchName, char * EAData, | 289 | const unsigned char *searchName, char * EAData, |
270 | size_t bufsize, const struct nls_table *nls_codepage, | 290 | size_t bufsize, const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0db0b313d715..9312bfc56682 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon | 125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon |
126 | , nls_codepage); | 126 | , nls_codepage); |
127 | up(&tcon->ses->sesSem); | 127 | up(&tcon->ses->sesSem); |
128 | /* BB FIXME add code to check if wsize needs | ||
129 | update due to negotiated smb buffer size | ||
130 | shrinking */ | ||
128 | if(rc == 0) | 131 | if(rc == 0) |
129 | atomic_inc(&tconInfoReconnectCount); | 132 | atomic_inc(&tconInfoReconnectCount); |
130 | 133 | ||
@@ -166,11 +169,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
166 | 169 | ||
167 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); | 170 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); |
168 | 171 | ||
169 | #ifdef CONFIG_CIFS_STATS | 172 | if(tcon != NULL) |
170 | if(tcon != NULL) { | 173 | cifs_stats_inc(&tcon->num_smbs_sent); |
171 | atomic_inc(&tcon->num_smbs_sent); | 174 | |
172 | } | ||
173 | #endif /* CONFIG_CIFS_STATS */ | ||
174 | return rc; | 175 | return rc; |
175 | } | 176 | } |
176 | 177 | ||
@@ -222,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
222 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 223 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
223 | tcon, nls_codepage); | 224 | tcon, nls_codepage); |
224 | up(&tcon->ses->sesSem); | 225 | up(&tcon->ses->sesSem); |
226 | /* BB FIXME add code to check if wsize needs | ||
227 | update due to negotiated smb buffer size | ||
228 | shrinking */ | ||
225 | if(rc == 0) | 229 | if(rc == 0) |
226 | atomic_inc(&tconInfoReconnectCount); | 230 | atomic_inc(&tconInfoReconnectCount); |
227 | 231 | ||
@@ -269,11 +273,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
269 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 273 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
270 | wct /*wct */ ); | 274 | wct /*wct */ ); |
271 | 275 | ||
272 | #ifdef CONFIG_CIFS_STATS | 276 | if(tcon != NULL) |
273 | if(tcon != NULL) { | 277 | cifs_stats_inc(&tcon->num_smbs_sent); |
274 | atomic_inc(&tcon->num_smbs_sent); | 278 | |
275 | } | ||
276 | #endif /* CONFIG_CIFS_STATS */ | ||
277 | return rc; | 279 | return rc; |
278 | } | 280 | } |
279 | 281 | ||
@@ -330,7 +332,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
330 | (void **) &pSMB, (void **) &pSMBr); | 332 | (void **) &pSMB, (void **) &pSMBr); |
331 | if (rc) | 333 | if (rc) |
332 | return rc; | 334 | return rc; |
333 | 335 | pSMB->hdr.Mid = GetNextMid(server); | |
334 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 336 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
335 | if (extended_security) | 337 | if (extended_security) |
336 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 338 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
@@ -422,8 +424,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
422 | } | 424 | } |
423 | 425 | ||
424 | } | 426 | } |
425 | if (pSMB) | 427 | |
426 | cifs_buf_release(pSMB); | 428 | cifs_buf_release(pSMB); |
427 | return rc; | 429 | return rc; |
428 | } | 430 | } |
429 | 431 | ||
@@ -518,6 +520,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
518 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | 520 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ |
519 | 521 | ||
520 | if(ses->server) { | 522 | if(ses->server) { |
523 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
524 | |||
521 | if(ses->server->secMode & | 525 | if(ses->server->secMode & |
522 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 526 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
523 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 527 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
@@ -537,9 +541,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
537 | rc = -ESHUTDOWN; | 541 | rc = -ESHUTDOWN; |
538 | } | 542 | } |
539 | } | 543 | } |
540 | if (pSMB) | ||
541 | cifs_small_buf_release(pSMB); | ||
542 | up(&ses->sesSem); | 544 | up(&ses->sesSem); |
545 | cifs_small_buf_release(pSMB); | ||
543 | 546 | ||
544 | /* if session dead then we do not need to do ulogoff, | 547 | /* if session dead then we do not need to do ulogoff, |
545 | since server closed smb session, no sense reporting | 548 | since server closed smb session, no sense reporting |
@@ -583,14 +586,10 @@ DelFileRetry: | |||
583 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 586 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
584 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 587 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
585 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 588 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
589 | cifs_stats_inc(&tcon->num_deletes); | ||
586 | if (rc) { | 590 | if (rc) { |
587 | cFYI(1, ("Error in RMFile = %d", rc)); | 591 | cFYI(1, ("Error in RMFile = %d", rc)); |
588 | } | 592 | } |
589 | #ifdef CONFIG_CIFS_STATS | ||
590 | else { | ||
591 | atomic_inc(&tcon->num_deletes); | ||
592 | } | ||
593 | #endif | ||
594 | 593 | ||
595 | cifs_buf_release(pSMB); | 594 | cifs_buf_release(pSMB); |
596 | if (rc == -EAGAIN) | 595 | if (rc == -EAGAIN) |
@@ -632,14 +631,10 @@ RmDirRetry: | |||
632 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 631 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
633 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 632 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
634 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 633 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
634 | cifs_stats_inc(&tcon->num_rmdirs); | ||
635 | if (rc) { | 635 | if (rc) { |
636 | cFYI(1, ("Error in RMDir = %d", rc)); | 636 | cFYI(1, ("Error in RMDir = %d", rc)); |
637 | } | 637 | } |
638 | #ifdef CONFIG_CIFS_STATS | ||
639 | else { | ||
640 | atomic_inc(&tcon->num_rmdirs); | ||
641 | } | ||
642 | #endif | ||
643 | 638 | ||
644 | cifs_buf_release(pSMB); | 639 | cifs_buf_release(pSMB); |
645 | if (rc == -EAGAIN) | 640 | if (rc == -EAGAIN) |
@@ -680,20 +675,161 @@ MkDirRetry: | |||
680 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 675 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
681 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 676 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
682 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 677 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
678 | cifs_stats_inc(&tcon->num_mkdirs); | ||
683 | if (rc) { | 679 | if (rc) { |
684 | cFYI(1, ("Error in Mkdir = %d", rc)); | 680 | cFYI(1, ("Error in Mkdir = %d", rc)); |
685 | } | 681 | } |
686 | #ifdef CONFIG_CIFS_STATS | 682 | |
687 | else { | ||
688 | atomic_inc(&tcon->num_mkdirs); | ||
689 | } | ||
690 | #endif | ||
691 | cifs_buf_release(pSMB); | 683 | cifs_buf_release(pSMB); |
692 | if (rc == -EAGAIN) | 684 | if (rc == -EAGAIN) |
693 | goto MkDirRetry; | 685 | goto MkDirRetry; |
694 | return rc; | 686 | return rc; |
695 | } | 687 | } |
696 | 688 | ||
689 | static __u16 convert_disposition(int disposition) | ||
690 | { | ||
691 | __u16 ofun = 0; | ||
692 | |||
693 | switch (disposition) { | ||
694 | case FILE_SUPERSEDE: | ||
695 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
696 | break; | ||
697 | case FILE_OPEN: | ||
698 | ofun = SMBOPEN_OAPPEND; | ||
699 | break; | ||
700 | case FILE_CREATE: | ||
701 | ofun = SMBOPEN_OCREATE; | ||
702 | break; | ||
703 | case FILE_OPEN_IF: | ||
704 | ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND; | ||
705 | break; | ||
706 | case FILE_OVERWRITE: | ||
707 | ofun = SMBOPEN_OTRUNC; | ||
708 | break; | ||
709 | case FILE_OVERWRITE_IF: | ||
710 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
711 | break; | ||
712 | default: | ||
713 | cFYI(1,("unknown disposition %d",disposition)); | ||
714 | ofun = SMBOPEN_OAPPEND; /* regular open */ | ||
715 | } | ||
716 | return ofun; | ||
717 | } | ||
718 | |||
719 | int | ||
720 | SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
721 | const char *fileName, const int openDisposition, | ||
722 | const int access_flags, const int create_options, __u16 * netfid, | ||
723 | int *pOplock, FILE_ALL_INFO * pfile_info, | ||
724 | const struct nls_table *nls_codepage, int remap) | ||
725 | { | ||
726 | int rc = -EACCES; | ||
727 | OPENX_REQ *pSMB = NULL; | ||
728 | OPENX_RSP *pSMBr = NULL; | ||
729 | int bytes_returned; | ||
730 | int name_len; | ||
731 | __u16 count; | ||
732 | |||
733 | OldOpenRetry: | ||
734 | rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, | ||
735 | (void **) &pSMBr); | ||
736 | if (rc) | ||
737 | return rc; | ||
738 | |||
739 | pSMB->AndXCommand = 0xFF; /* none */ | ||
740 | |||
741 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
742 | count = 1; /* account for one byte pad to word boundary */ | ||
743 | name_len = | ||
744 | cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), | ||
745 | fileName, PATH_MAX, nls_codepage, remap); | ||
746 | name_len++; /* trailing null */ | ||
747 | name_len *= 2; | ||
748 | } else { /* BB improve check for buffer overruns BB */ | ||
749 | count = 0; /* no pad */ | ||
750 | name_len = strnlen(fileName, PATH_MAX); | ||
751 | name_len++; /* trailing null */ | ||
752 | strncpy(pSMB->fileName, fileName, name_len); | ||
753 | } | ||
754 | if (*pOplock & REQ_OPLOCK) | ||
755 | pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); | ||
756 | else if (*pOplock & REQ_BATCHOPLOCK) { | ||
757 | pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); | ||
758 | } | ||
759 | pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); | ||
760 | /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ | ||
761 | /* 0 = read | ||
762 | 1 = write | ||
763 | 2 = rw | ||
764 | 3 = execute | ||
765 | */ | ||
766 | pSMB->Mode = cpu_to_le16(2); | ||
767 | pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ | ||
768 | /* set file as system file if special file such | ||
769 | as fifo and server expecting SFU style and | ||
770 | no Unix extensions */ | ||
771 | |||
772 | if(create_options & CREATE_OPTION_SPECIAL) | ||
773 | pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM); | ||
774 | else | ||
775 | pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */ | ||
776 | |||
777 | /* if ((omode & S_IWUGO) == 0) | ||
778 | pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ | ||
779 | /* Above line causes problems due to vfs splitting create into two | ||
780 | pieces - need to set mode after file created not while it is | ||
781 | being created */ | ||
782 | |||
783 | /* BB FIXME BB */ | ||
784 | /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */ | ||
785 | /* BB FIXME END BB */ | ||
786 | |||
787 | pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); | ||
788 | pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); | ||
789 | count += name_len; | ||
790 | pSMB->hdr.smb_buf_length += count; | ||
791 | |||
792 | pSMB->ByteCount = cpu_to_le16(count); | ||
793 | /* long_op set to 1 to allow for oplock break timeouts */ | ||
794 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
795 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | ||
796 | cifs_stats_inc(&tcon->num_opens); | ||
797 | if (rc) { | ||
798 | cFYI(1, ("Error in Open = %d", rc)); | ||
799 | } else { | ||
800 | /* BB verify if wct == 15 */ | ||
801 | |||
802 | /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ | ||
803 | |||
804 | *netfid = pSMBr->Fid; /* cifs fid stays in le */ | ||
805 | /* Let caller know file was created so we can set the mode. */ | ||
806 | /* Do we care about the CreateAction in any other cases? */ | ||
807 | /* BB FIXME BB */ | ||
808 | /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) | ||
809 | *pOplock |= CIFS_CREATE_ACTION; */ | ||
810 | /* BB FIXME END */ | ||
811 | |||
812 | if(pfile_info) { | ||
813 | pfile_info->CreationTime = 0; /* BB convert CreateTime*/ | ||
814 | pfile_info->LastAccessTime = 0; /* BB fixme */ | ||
815 | pfile_info->LastWriteTime = 0; /* BB fixme */ | ||
816 | pfile_info->ChangeTime = 0; /* BB fixme */ | ||
817 | pfile_info->Attributes = | ||
818 | cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); | ||
819 | /* the file_info buf is endian converted by caller */ | ||
820 | pfile_info->AllocationSize = | ||
821 | cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); | ||
822 | pfile_info->EndOfFile = pfile_info->AllocationSize; | ||
823 | pfile_info->NumberOfLinks = cpu_to_le32(1); | ||
824 | } | ||
825 | } | ||
826 | |||
827 | cifs_buf_release(pSMB); | ||
828 | if (rc == -EAGAIN) | ||
829 | goto OldOpenRetry; | ||
830 | return rc; | ||
831 | } | ||
832 | |||
697 | int | 833 | int |
698 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 834 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, |
699 | const char *fileName, const int openDisposition, | 835 | const char *fileName, const int openDisposition, |
@@ -738,7 +874,13 @@ openRetry: | |||
738 | } | 874 | } |
739 | pSMB->DesiredAccess = cpu_to_le32(access_flags); | 875 | pSMB->DesiredAccess = cpu_to_le32(access_flags); |
740 | pSMB->AllocationSize = 0; | 876 | pSMB->AllocationSize = 0; |
741 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | 877 | /* set file as system file if special file such |
878 | as fifo and server expecting SFU style and | ||
879 | no Unix extensions */ | ||
880 | if(create_options & CREATE_OPTION_SPECIAL) | ||
881 | pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); | ||
882 | else | ||
883 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | ||
742 | /* XP does not handle ATTR_POSIX_SEMANTICS */ | 884 | /* XP does not handle ATTR_POSIX_SEMANTICS */ |
743 | /* but it helps speed up case sensitive checks for other | 885 | /* but it helps speed up case sensitive checks for other |
744 | servers such as Samba */ | 886 | servers such as Samba */ |
@@ -752,7 +894,7 @@ openRetry: | |||
752 | being created */ | 894 | being created */ |
753 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); | 895 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); |
754 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); | 896 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); |
755 | pSMB->CreateOptions = cpu_to_le32(create_options); | 897 | pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); |
756 | /* BB Expirement with various impersonation levels and verify */ | 898 | /* BB Expirement with various impersonation levels and verify */ |
757 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); | 899 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); |
758 | pSMB->SecurityFlags = | 900 | pSMB->SecurityFlags = |
@@ -765,6 +907,7 @@ openRetry: | |||
765 | /* long_op set to 1 to allow for oplock break timeouts */ | 907 | /* long_op set to 1 to allow for oplock break timeouts */ |
766 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 908 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
767 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | 909 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); |
910 | cifs_stats_inc(&tcon->num_opens); | ||
768 | if (rc) { | 911 | if (rc) { |
769 | cFYI(1, ("Error in Open = %d", rc)); | 912 | cFYI(1, ("Error in Open = %d", rc)); |
770 | } else { | 913 | } else { |
@@ -782,11 +925,8 @@ openRetry: | |||
782 | pfile_info->EndOfFile = pSMBr->EndOfFile; | 925 | pfile_info->EndOfFile = pSMBr->EndOfFile; |
783 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 926 | pfile_info->NumberOfLinks = cpu_to_le32(1); |
784 | } | 927 | } |
785 | |||
786 | #ifdef CONFIG_CIFS_STATS | ||
787 | atomic_inc(&tcon->num_opens); | ||
788 | #endif | ||
789 | } | 928 | } |
929 | |||
790 | cifs_buf_release(pSMB); | 930 | cifs_buf_release(pSMB); |
791 | if (rc == -EAGAIN) | 931 | if (rc == -EAGAIN) |
792 | goto openRetry; | 932 | goto openRetry; |
@@ -807,11 +947,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
807 | READ_RSP *pSMBr = NULL; | 947 | READ_RSP *pSMBr = NULL; |
808 | char *pReadData = NULL; | 948 | char *pReadData = NULL; |
809 | int bytes_returned; | 949 | int bytes_returned; |
950 | int wct; | ||
810 | 951 | ||
811 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | 952 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); |
953 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
954 | wct = 12; | ||
955 | else | ||
956 | wct = 10; /* old style read */ | ||
812 | 957 | ||
813 | *nbytes = 0; | 958 | *nbytes = 0; |
814 | rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, | 959 | rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, |
815 | (void **) &pSMBr); | 960 | (void **) &pSMBr); |
816 | if (rc) | 961 | if (rc) |
817 | return rc; | 962 | return rc; |
@@ -823,14 +968,26 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
823 | pSMB->AndXCommand = 0xFF; /* none */ | 968 | pSMB->AndXCommand = 0xFF; /* none */ |
824 | pSMB->Fid = netfid; | 969 | pSMB->Fid = netfid; |
825 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 970 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); |
826 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 971 | if(wct == 12) |
972 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | ||
973 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ | ||
974 | return -EIO; | ||
975 | |||
827 | pSMB->Remaining = 0; | 976 | pSMB->Remaining = 0; |
828 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 977 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
829 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); | 978 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); |
830 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | 979 | if(wct == 12) |
831 | 980 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ | |
981 | else { | ||
982 | /* old style read */ | ||
983 | struct smb_com_readx_req * pSMBW = | ||
984 | (struct smb_com_readx_req *)pSMB; | ||
985 | pSMBW->ByteCount = 0; | ||
986 | } | ||
987 | |||
832 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 988 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
833 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 989 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
990 | cifs_stats_inc(&tcon->num_reads); | ||
834 | if (rc) { | 991 | if (rc) { |
835 | cERROR(1, ("Send error in read = %d", rc)); | 992 | cERROR(1, ("Send error in read = %d", rc)); |
836 | } else { | 993 | } else { |
@@ -876,12 +1033,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
876 | int rc = -EACCES; | 1033 | int rc = -EACCES; |
877 | WRITE_REQ *pSMB = NULL; | 1034 | WRITE_REQ *pSMB = NULL; |
878 | WRITE_RSP *pSMBr = NULL; | 1035 | WRITE_RSP *pSMBr = NULL; |
879 | int bytes_returned; | 1036 | int bytes_returned, wct; |
880 | __u32 bytes_sent; | 1037 | __u32 bytes_sent; |
881 | __u16 byte_count; | 1038 | __u16 byte_count; |
882 | 1039 | ||
883 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ | 1040 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ |
884 | rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, | 1041 | if(tcon->ses == NULL) |
1042 | return -ECONNABORTED; | ||
1043 | |||
1044 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
1045 | wct = 14; | ||
1046 | else | ||
1047 | wct = 12; | ||
1048 | |||
1049 | rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, | ||
885 | (void **) &pSMBr); | 1050 | (void **) &pSMBr); |
886 | if (rc) | 1051 | if (rc) |
887 | return rc; | 1052 | return rc; |
@@ -892,7 +1057,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
892 | pSMB->AndXCommand = 0xFF; /* none */ | 1057 | pSMB->AndXCommand = 0xFF; /* none */ |
893 | pSMB->Fid = netfid; | 1058 | pSMB->Fid = netfid; |
894 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1059 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
895 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1060 | if(wct == 14) |
1061 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
1062 | else if((offset >> 32) > 0) /* can not handle this big offset for old */ | ||
1063 | return -EIO; | ||
1064 | |||
896 | pSMB->Reserved = 0xFFFFFFFF; | 1065 | pSMB->Reserved = 0xFFFFFFFF; |
897 | pSMB->WriteMode = 0; | 1066 | pSMB->WriteMode = 0; |
898 | pSMB->Remaining = 0; | 1067 | pSMB->Remaining = 0; |
@@ -911,7 +1080,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
911 | if (bytes_sent > count) | 1080 | if (bytes_sent > count) |
912 | bytes_sent = count; | 1081 | bytes_sent = count; |
913 | pSMB->DataOffset = | 1082 | pSMB->DataOffset = |
914 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1083 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
915 | if(buf) | 1084 | if(buf) |
916 | memcpy(pSMB->Data,buf,bytes_sent); | 1085 | memcpy(pSMB->Data,buf,bytes_sent); |
917 | else if(ubuf) { | 1086 | else if(ubuf) { |
@@ -919,20 +1088,31 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
919 | cifs_buf_release(pSMB); | 1088 | cifs_buf_release(pSMB); |
920 | return -EFAULT; | 1089 | return -EFAULT; |
921 | } | 1090 | } |
922 | } else { | 1091 | } else if (count != 0) { |
923 | /* No buffer */ | 1092 | /* No buffer */ |
924 | cifs_buf_release(pSMB); | 1093 | cifs_buf_release(pSMB); |
925 | return -EINVAL; | 1094 | return -EINVAL; |
1095 | } /* else setting file size with write of zero bytes */ | ||
1096 | if(wct == 14) | ||
1097 | byte_count = bytes_sent + 1; /* pad */ | ||
1098 | else /* wct == 12 */ { | ||
1099 | byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ | ||
926 | } | 1100 | } |
927 | |||
928 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | ||
929 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1101 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
930 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | 1102 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
931 | pSMB->hdr.smb_buf_length += bytes_sent+1; | 1103 | pSMB->hdr.smb_buf_length += byte_count; |
932 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1104 | |
1105 | if(wct == 14) | ||
1106 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
1107 | else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */ | ||
1108 | struct smb_com_writex_req * pSMBW = | ||
1109 | (struct smb_com_writex_req *)pSMB; | ||
1110 | pSMBW->ByteCount = cpu_to_le16(byte_count); | ||
1111 | } | ||
933 | 1112 | ||
934 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1113 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
935 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); | 1114 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); |
1115 | cifs_stats_inc(&tcon->num_writes); | ||
936 | if (rc) { | 1116 | if (rc) { |
937 | cFYI(1, ("Send error in write = %d", rc)); | 1117 | cFYI(1, ("Send error in write = %d", rc)); |
938 | *nbytes = 0; | 1118 | *nbytes = 0; |
@@ -951,56 +1131,72 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
951 | } | 1131 | } |
952 | 1132 | ||
953 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1133 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
954 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1134 | int |
1135 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
955 | const int netfid, const unsigned int count, | 1136 | const int netfid, const unsigned int count, |
956 | const __u64 offset, unsigned int *nbytes, const char __user *buf, | 1137 | const __u64 offset, unsigned int *nbytes, struct kvec *iov, |
957 | const int long_op) | 1138 | int n_vec, const int long_op) |
958 | { | 1139 | { |
959 | int rc = -EACCES; | 1140 | int rc = -EACCES; |
960 | WRITE_REQ *pSMB = NULL; | 1141 | WRITE_REQ *pSMB = NULL; |
961 | WRITE_RSP *pSMBr = NULL; | 1142 | int bytes_returned, wct; |
962 | /*int bytes_returned;*/ | 1143 | int smb_hdr_len; |
963 | unsigned bytes_sent; | ||
964 | __u16 byte_count; | ||
965 | 1144 | ||
966 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 1145 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ |
967 | 1146 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | |
1147 | wct = 14; | ||
1148 | else | ||
1149 | wct = 12; | ||
1150 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); | ||
968 | if (rc) | 1151 | if (rc) |
969 | return rc; | 1152 | return rc; |
970 | |||
971 | pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ | ||
972 | |||
973 | /* tcon and ses pointer are checked in smb_init */ | 1153 | /* tcon and ses pointer are checked in smb_init */ |
974 | if (tcon->ses->server == NULL) | 1154 | if (tcon->ses->server == NULL) |
975 | return -ECONNABORTED; | 1155 | return -ECONNABORTED; |
976 | 1156 | ||
977 | pSMB->AndXCommand = 0xFF; /* none */ | 1157 | pSMB->AndXCommand = 0xFF; /* none */ |
978 | pSMB->Fid = netfid; | 1158 | pSMB->Fid = netfid; |
979 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1159 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
980 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1160 | if(wct == 14) |
1161 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
1162 | else if((offset >> 32) > 0) /* can not handle this big offset for old */ | ||
1163 | return -EIO; | ||
981 | pSMB->Reserved = 0xFFFFFFFF; | 1164 | pSMB->Reserved = 0xFFFFFFFF; |
982 | pSMB->WriteMode = 0; | 1165 | pSMB->WriteMode = 0; |
983 | pSMB->Remaining = 0; | 1166 | pSMB->Remaining = 0; |
984 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; | 1167 | |
985 | if (bytes_sent > count) | ||
986 | bytes_sent = count; | ||
987 | pSMB->DataLengthHigh = 0; | ||
988 | pSMB->DataOffset = | 1168 | pSMB->DataOffset = |
989 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1169 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
990 | 1170 | ||
991 | byte_count = bytes_sent + 1 /* pad */ ; | 1171 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); |
992 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent); | 1172 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); |
993 | pSMB->DataLengthHigh = 0; | 1173 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
994 | pSMB->hdr.smb_buf_length += byte_count; | 1174 | if(wct == 14) |
995 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1175 | pSMB->hdr.smb_buf_length += count+1; |
1176 | else /* wct == 12 */ | ||
1177 | pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ | ||
1178 | if(wct == 14) | ||
1179 | pSMB->ByteCount = cpu_to_le16(count + 1); | ||
1180 | else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { | ||
1181 | struct smb_com_writex_req * pSMBW = | ||
1182 | (struct smb_com_writex_req *)pSMB; | ||
1183 | pSMBW->ByteCount = cpu_to_le16(count + 5); | ||
1184 | } | ||
1185 | iov[0].iov_base = pSMB; | ||
1186 | iov[0].iov_len = smb_hdr_len + 4; | ||
996 | 1187 | ||
997 | /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1188 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, |
998 | (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ | 1189 | long_op); |
1190 | cifs_stats_inc(&tcon->num_writes); | ||
999 | if (rc) { | 1191 | if (rc) { |
1000 | cFYI(1, ("Send error in write2 (large write) = %d", rc)); | 1192 | cFYI(1, ("Send error Write2 = %d", rc)); |
1001 | *nbytes = 0; | 1193 | *nbytes = 0; |
1002 | } else | 1194 | } else { |
1003 | *nbytes = le16_to_cpu(pSMBr->Count); | 1195 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; |
1196 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | ||
1197 | *nbytes = (*nbytes) << 16; | ||
1198 | *nbytes += le16_to_cpu(pSMBr->Count); | ||
1199 | } | ||
1004 | 1200 | ||
1005 | cifs_small_buf_release(pSMB); | 1201 | cifs_small_buf_release(pSMB); |
1006 | 1202 | ||
@@ -1009,6 +1205,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1009 | 1205 | ||
1010 | return rc; | 1206 | return rc; |
1011 | } | 1207 | } |
1208 | |||
1209 | |||
1012 | #endif /* CIFS_EXPERIMENTAL */ | 1210 | #endif /* CIFS_EXPERIMENTAL */ |
1013 | 1211 | ||
1014 | int | 1212 | int |
@@ -1065,7 +1263,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
1065 | 1263 | ||
1066 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1264 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1067 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1265 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); |
1068 | 1266 | cifs_stats_inc(&tcon->num_locks); | |
1069 | if (rc) { | 1267 | if (rc) { |
1070 | cFYI(1, ("Send error in Lock = %d", rc)); | 1268 | cFYI(1, ("Send error in Lock = %d", rc)); |
1071 | } | 1269 | } |
@@ -1099,6 +1297,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
1099 | pSMB->ByteCount = 0; | 1297 | pSMB->ByteCount = 0; |
1100 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1298 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1101 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1299 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1300 | cifs_stats_inc(&tcon->num_closes); | ||
1102 | if (rc) { | 1301 | if (rc) { |
1103 | if(rc!=-EINTR) { | 1302 | if(rc!=-EINTR) { |
1104 | /* EINTR is expected when user ctl-c to kill app */ | 1303 | /* EINTR is expected when user ctl-c to kill app */ |
@@ -1171,16 +1370,11 @@ renameRetry: | |||
1171 | 1370 | ||
1172 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1371 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1173 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1372 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1373 | cifs_stats_inc(&tcon->num_renames); | ||
1174 | if (rc) { | 1374 | if (rc) { |
1175 | cFYI(1, ("Send error in rename = %d", rc)); | 1375 | cFYI(1, ("Send error in rename = %d", rc)); |
1176 | } | 1376 | } |
1177 | 1377 | ||
1178 | #ifdef CONFIG_CIFS_STATS | ||
1179 | else { | ||
1180 | atomic_inc(&tcon->num_renames); | ||
1181 | } | ||
1182 | #endif | ||
1183 | |||
1184 | cifs_buf_release(pSMB); | 1378 | cifs_buf_release(pSMB); |
1185 | 1379 | ||
1186 | if (rc == -EAGAIN) | 1380 | if (rc == -EAGAIN) |
@@ -1255,14 +1449,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | |||
1255 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1449 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1256 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | 1450 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, |
1257 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1451 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1452 | cifs_stats_inc(&pTcon->num_t2renames); | ||
1258 | if (rc) { | 1453 | if (rc) { |
1259 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); | 1454 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); |
1260 | } | 1455 | } |
1261 | #ifdef CONFIG_CIFS_STATS | 1456 | |
1262 | else { | ||
1263 | atomic_inc(&pTcon->num_t2renames); | ||
1264 | } | ||
1265 | #endif | ||
1266 | cifs_buf_release(pSMB); | 1457 | cifs_buf_release(pSMB); |
1267 | 1458 | ||
1268 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1459 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
@@ -1416,6 +1607,7 @@ createSymLinkRetry: | |||
1416 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1607 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1417 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1608 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1418 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1609 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1610 | cifs_stats_inc(&tcon->num_symlinks); | ||
1419 | if (rc) { | 1611 | if (rc) { |
1420 | cFYI(1, | 1612 | cFYI(1, |
1421 | ("Send error in SetPathInfo (create symlink) = %d", | 1613 | ("Send error in SetPathInfo (create symlink) = %d", |
@@ -1505,6 +1697,7 @@ createHardLinkRetry: | |||
1505 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1697 | pSMB->ByteCount = cpu_to_le16(byte_count); |
1506 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1698 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1507 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1699 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1700 | cifs_stats_inc(&tcon->num_hardlinks); | ||
1508 | if (rc) { | 1701 | if (rc) { |
1509 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); | 1702 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); |
1510 | } | 1703 | } |
@@ -1575,6 +1768,7 @@ winCreateHardLinkRetry: | |||
1575 | 1768 | ||
1576 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1769 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
1577 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1770 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
1771 | cifs_stats_inc(&tcon->num_hardlinks); | ||
1578 | if (rc) { | 1772 | if (rc) { |
1579 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); | 1773 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); |
1580 | } | 1774 | } |
@@ -1775,8 +1969,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
1775 | } | 1969 | } |
1776 | } | 1970 | } |
1777 | qreparse_out: | 1971 | qreparse_out: |
1778 | if (pSMB) | 1972 | cifs_buf_release(pSMB); |
1779 | cifs_buf_release(pSMB); | ||
1780 | 1973 | ||
1781 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1974 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1782 | since file handle passed in no longer valid */ | 1975 | since file handle passed in no longer valid */ |
@@ -2165,6 +2358,67 @@ GetExtAttrOut: | |||
2165 | 2358 | ||
2166 | #endif /* CONFIG_POSIX */ | 2359 | #endif /* CONFIG_POSIX */ |
2167 | 2360 | ||
2361 | /* Legacy Query Path Information call for lookup to old servers such | ||
2362 | as Win9x/WinME */ | ||
2363 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
2364 | const unsigned char *searchName, | ||
2365 | FILE_ALL_INFO * pFinfo, | ||
2366 | const struct nls_table *nls_codepage, int remap) | ||
2367 | { | ||
2368 | QUERY_INFORMATION_REQ * pSMB; | ||
2369 | QUERY_INFORMATION_RSP * pSMBr; | ||
2370 | int rc = 0; | ||
2371 | int bytes_returned; | ||
2372 | int name_len; | ||
2373 | |||
2374 | cFYI(1, ("In SMBQPath path %s", searchName)); | ||
2375 | QInfRetry: | ||
2376 | rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, | ||
2377 | (void **) &pSMBr); | ||
2378 | if (rc) | ||
2379 | return rc; | ||
2380 | |||
2381 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
2382 | name_len = | ||
2383 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | ||
2384 | PATH_MAX, nls_codepage, remap); | ||
2385 | name_len++; /* trailing null */ | ||
2386 | name_len *= 2; | ||
2387 | } else { | ||
2388 | name_len = strnlen(searchName, PATH_MAX); | ||
2389 | name_len++; /* trailing null */ | ||
2390 | strncpy(pSMB->FileName, searchName, name_len); | ||
2391 | } | ||
2392 | pSMB->BufferFormat = 0x04; | ||
2393 | name_len++; /* account for buffer type byte */ | ||
2394 | pSMB->hdr.smb_buf_length += (__u16) name_len; | ||
2395 | pSMB->ByteCount = cpu_to_le16(name_len); | ||
2396 | |||
2397 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
2398 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
2399 | if (rc) { | ||
2400 | cFYI(1, ("Send error in QueryInfo = %d", rc)); | ||
2401 | } else if (pFinfo) { /* decode response */ | ||
2402 | memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); | ||
2403 | pFinfo->AllocationSize = | ||
2404 | cpu_to_le64(le32_to_cpu(pSMBr->size)); | ||
2405 | pFinfo->EndOfFile = pFinfo->AllocationSize; | ||
2406 | pFinfo->Attributes = | ||
2407 | cpu_to_le32(le16_to_cpu(pSMBr->attr)); | ||
2408 | } else | ||
2409 | rc = -EIO; /* bad buffer passed in */ | ||
2410 | |||
2411 | cifs_buf_release(pSMB); | ||
2412 | |||
2413 | if (rc == -EAGAIN) | ||
2414 | goto QInfRetry; | ||
2415 | |||
2416 | return rc; | ||
2417 | } | ||
2418 | |||
2419 | |||
2420 | |||
2421 | |||
2168 | int | 2422 | int |
2169 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 2423 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, |
2170 | const unsigned char *searchName, | 2424 | const unsigned char *searchName, |
@@ -2396,7 +2650,7 @@ findUniqueRetry: | |||
2396 | if (rc) { | 2650 | if (rc) { |
2397 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); | 2651 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); |
2398 | } else { /* decode response */ | 2652 | } else { /* decode response */ |
2399 | 2653 | cifs_stats_inc(&tcon->num_ffirst); | |
2400 | /* BB fill in */ | 2654 | /* BB fill in */ |
2401 | } | 2655 | } |
2402 | 2656 | ||
@@ -2414,7 +2668,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | |||
2414 | const char *searchName, | 2668 | const char *searchName, |
2415 | const struct nls_table *nls_codepage, | 2669 | const struct nls_table *nls_codepage, |
2416 | __u16 * pnetfid, | 2670 | __u16 * pnetfid, |
2417 | struct cifs_search_info * psrch_inf, int remap) | 2671 | struct cifs_search_info * psrch_inf, int remap, const char dirsep) |
2418 | { | 2672 | { |
2419 | /* level 257 SMB_ */ | 2673 | /* level 257 SMB_ */ |
2420 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | 2674 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; |
@@ -2441,7 +2695,7 @@ findFirstRetry: | |||
2441 | it got remapped to 0xF03A as if it were part of the | 2695 | it got remapped to 0xF03A as if it were part of the |
2442 | directory name instead of a wildcard */ | 2696 | directory name instead of a wildcard */ |
2443 | name_len *= 2; | 2697 | name_len *= 2; |
2444 | pSMB->FileName[name_len] = '\\'; | 2698 | pSMB->FileName[name_len] = dirsep; |
2445 | pSMB->FileName[name_len+1] = 0; | 2699 | pSMB->FileName[name_len+1] = 0; |
2446 | pSMB->FileName[name_len+2] = '*'; | 2700 | pSMB->FileName[name_len+2] = '*'; |
2447 | pSMB->FileName[name_len+3] = 0; | 2701 | pSMB->FileName[name_len+3] = 0; |
@@ -2455,7 +2709,7 @@ findFirstRetry: | |||
2455 | if(name_len > buffersize-header) | 2709 | if(name_len > buffersize-header) |
2456 | free buffer exit; BB */ | 2710 | free buffer exit; BB */ |
2457 | strncpy(pSMB->FileName, searchName, name_len); | 2711 | strncpy(pSMB->FileName, searchName, name_len); |
2458 | pSMB->FileName[name_len] = '\\'; | 2712 | pSMB->FileName[name_len] = dirsep; |
2459 | pSMB->FileName[name_len+1] = '*'; | 2713 | pSMB->FileName[name_len+1] = '*'; |
2460 | pSMB->FileName[name_len+2] = 0; | 2714 | pSMB->FileName[name_len+2] = 0; |
2461 | name_len += 3; | 2715 | name_len += 3; |
@@ -2496,6 +2750,7 @@ findFirstRetry: | |||
2496 | 2750 | ||
2497 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2751 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2498 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2752 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2753 | cifs_stats_inc(&tcon->num_ffirst); | ||
2499 | 2754 | ||
2500 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ | 2755 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ |
2501 | /* BB Add code to handle unsupported level rc */ | 2756 | /* BB Add code to handle unsupported level rc */ |
@@ -2617,7 +2872,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
2617 | 2872 | ||
2618 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2873 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2619 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2874 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2620 | 2875 | cifs_stats_inc(&tcon->num_fnext); | |
2621 | if (rc) { | 2876 | if (rc) { |
2622 | if (rc == -EBADF) { | 2877 | if (rc == -EBADF) { |
2623 | psrch_inf->endOfSearch = TRUE; | 2878 | psrch_inf->endOfSearch = TRUE; |
@@ -2694,6 +2949,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle | |||
2694 | if (rc) { | 2949 | if (rc) { |
2695 | cERROR(1, ("Send error in FindClose = %d", rc)); | 2950 | cERROR(1, ("Send error in FindClose = %d", rc)); |
2696 | } | 2951 | } |
2952 | cifs_stats_inc(&tcon->num_fclose); | ||
2697 | cifs_small_buf_release(pSMB); | 2953 | cifs_small_buf_release(pSMB); |
2698 | 2954 | ||
2699 | /* Since session is dead, search handle closed on server already */ | 2955 | /* Since session is dead, search handle closed on server already */ |
@@ -2827,7 +3083,10 @@ getDFSRetry: | |||
2827 | (void **) &pSMBr); | 3083 | (void **) &pSMBr); |
2828 | if (rc) | 3084 | if (rc) |
2829 | return rc; | 3085 | return rc; |
2830 | 3086 | ||
3087 | /* server pointer checked in called function, | ||
3088 | but should never be null here anyway */ | ||
3089 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
2831 | pSMB->hdr.Tid = ses->ipc_tid; | 3090 | pSMB->hdr.Tid = ses->ipc_tid; |
2832 | pSMB->hdr.Uid = ses->Suid; | 3091 | pSMB->hdr.Uid = ses->Suid; |
2833 | if (ses->capabilities & CAP_STATUS32) { | 3092 | if (ses->capabilities & CAP_STATUS32) { |
@@ -2968,6 +3227,92 @@ GetDFSRefExit: | |||
2968 | return rc; | 3227 | return rc; |
2969 | } | 3228 | } |
2970 | 3229 | ||
3230 | /* Query File System Info such as free space to old servers such as Win 9x */ | ||
3231 | int | ||
3232 | SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | ||
3233 | { | ||
3234 | /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ | ||
3235 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
3236 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
3237 | FILE_SYSTEM_ALLOC_INFO *response_data; | ||
3238 | int rc = 0; | ||
3239 | int bytes_returned = 0; | ||
3240 | __u16 params, byte_count; | ||
3241 | |||
3242 | cFYI(1, ("OldQFSInfo")); | ||
3243 | oldQFSInfoRetry: | ||
3244 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3245 | (void **) &pSMBr); | ||
3246 | if (rc) | ||
3247 | return rc; | ||
3248 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3249 | (void **) &pSMBr); | ||
3250 | if (rc) | ||
3251 | return rc; | ||
3252 | |||
3253 | params = 2; /* level */ | ||
3254 | pSMB->TotalDataCount = 0; | ||
3255 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
3256 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
3257 | pSMB->MaxSetupCount = 0; | ||
3258 | pSMB->Reserved = 0; | ||
3259 | pSMB->Flags = 0; | ||
3260 | pSMB->Timeout = 0; | ||
3261 | pSMB->Reserved2 = 0; | ||
3262 | byte_count = params + 1 /* pad */ ; | ||
3263 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
3264 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
3265 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
3266 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
3267 | pSMB->DataCount = 0; | ||
3268 | pSMB->DataOffset = 0; | ||
3269 | pSMB->SetupCount = 1; | ||
3270 | pSMB->Reserved3 = 0; | ||
3271 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
3272 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); | ||
3273 | pSMB->hdr.smb_buf_length += byte_count; | ||
3274 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3275 | |||
3276 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3277 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3278 | if (rc) { | ||
3279 | cFYI(1, ("Send error in QFSInfo = %d", rc)); | ||
3280 | } else { /* decode response */ | ||
3281 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3282 | |||
3283 | if (rc || (pSMBr->ByteCount < 18)) | ||
3284 | rc = -EIO; /* bad smb */ | ||
3285 | else { | ||
3286 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
3287 | cFYI(1,("qfsinf resp BCC: %d Offset %d", | ||
3288 | pSMBr->ByteCount, data_offset)); | ||
3289 | |||
3290 | response_data = | ||
3291 | (FILE_SYSTEM_ALLOC_INFO *) | ||
3292 | (((char *) &pSMBr->hdr.Protocol) + data_offset); | ||
3293 | FSData->f_bsize = | ||
3294 | le16_to_cpu(response_data->BytesPerSector) * | ||
3295 | le32_to_cpu(response_data-> | ||
3296 | SectorsPerAllocationUnit); | ||
3297 | FSData->f_blocks = | ||
3298 | le32_to_cpu(response_data->TotalAllocationUnits); | ||
3299 | FSData->f_bfree = FSData->f_bavail = | ||
3300 | le32_to_cpu(response_data->FreeAllocationUnits); | ||
3301 | cFYI(1, | ||
3302 | ("Blocks: %lld Free: %lld Block size %ld", | ||
3303 | (unsigned long long)FSData->f_blocks, | ||
3304 | (unsigned long long)FSData->f_bfree, | ||
3305 | FSData->f_bsize)); | ||
3306 | } | ||
3307 | } | ||
3308 | cifs_buf_release(pSMB); | ||
3309 | |||
3310 | if (rc == -EAGAIN) | ||
3311 | goto oldQFSInfoRetry; | ||
3312 | |||
3313 | return rc; | ||
3314 | } | ||
3315 | |||
2971 | int | 3316 | int |
2972 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | 3317 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) |
2973 | { | 3318 | { |
@@ -2989,7 +3334,7 @@ QFSInfoRetry: | |||
2989 | params = 2; /* level */ | 3334 | params = 2; /* level */ |
2990 | pSMB->TotalDataCount = 0; | 3335 | pSMB->TotalDataCount = 0; |
2991 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3336 | pSMB->MaxParameterCount = cpu_to_le16(2); |
2992 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 3337 | pSMB->MaxDataCount = cpu_to_le16(1000); |
2993 | pSMB->MaxSetupCount = 0; | 3338 | pSMB->MaxSetupCount = 0; |
2994 | pSMB->Reserved = 0; | 3339 | pSMB->Reserved = 0; |
2995 | pSMB->Flags = 0; | 3340 | pSMB->Flags = 0; |
@@ -3012,17 +3357,14 @@ QFSInfoRetry: | |||
3012 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3357 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
3013 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3358 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
3014 | if (rc) { | 3359 | if (rc) { |
3015 | cERROR(1, ("Send error in QFSInfo = %d", rc)); | 3360 | cFYI(1, ("Send error in QFSInfo = %d", rc)); |
3016 | } else { /* decode response */ | 3361 | } else { /* decode response */ |
3017 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3362 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
3018 | 3363 | ||
3019 | if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ | 3364 | if (rc || (pSMBr->ByteCount < 24)) |
3020 | rc = -EIO; /* bad smb */ | 3365 | rc = -EIO; /* bad smb */ |
3021 | else { | 3366 | else { |
3022 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 3367 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
3023 | cFYI(1, | ||
3024 | ("Decoding qfsinfo response. BCC: %d Offset %d", | ||
3025 | pSMBr->ByteCount, data_offset)); | ||
3026 | 3368 | ||
3027 | response_data = | 3369 | response_data = |
3028 | (FILE_SYSTEM_INFO | 3370 | (FILE_SYSTEM_INFO |
@@ -3257,6 +3599,77 @@ QFSUnixRetry: | |||
3257 | return rc; | 3599 | return rc; |
3258 | } | 3600 | } |
3259 | 3601 | ||
3602 | int | ||
3603 | CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) | ||
3604 | { | ||
3605 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ | ||
3606 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | ||
3607 | TRANSACTION2_SETFSI_RSP *pSMBr = NULL; | ||
3608 | int rc = 0; | ||
3609 | int bytes_returned = 0; | ||
3610 | __u16 params, param_offset, offset, byte_count; | ||
3611 | |||
3612 | cFYI(1, ("In SETFSUnixInfo")); | ||
3613 | SETFSUnixRetry: | ||
3614 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
3615 | (void **) &pSMBr); | ||
3616 | if (rc) | ||
3617 | return rc; | ||
3618 | |||
3619 | params = 4; /* 2 bytes zero followed by info level. */ | ||
3620 | pSMB->MaxSetupCount = 0; | ||
3621 | pSMB->Reserved = 0; | ||
3622 | pSMB->Flags = 0; | ||
3623 | pSMB->Timeout = 0; | ||
3624 | pSMB->Reserved2 = 0; | ||
3625 | param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4; | ||
3626 | offset = param_offset + params; | ||
3627 | |||
3628 | pSMB->MaxParameterCount = cpu_to_le16(4); | ||
3629 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
3630 | pSMB->SetupCount = 1; | ||
3631 | pSMB->Reserved3 = 0; | ||
3632 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | ||
3633 | byte_count = 1 /* pad */ + params + 12; | ||
3634 | |||
3635 | pSMB->DataCount = cpu_to_le16(12); | ||
3636 | pSMB->ParameterCount = cpu_to_le16(params); | ||
3637 | pSMB->TotalDataCount = pSMB->DataCount; | ||
3638 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
3639 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
3640 | pSMB->DataOffset = cpu_to_le16(offset); | ||
3641 | |||
3642 | /* Params. */ | ||
3643 | pSMB->FileNum = 0; | ||
3644 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); | ||
3645 | |||
3646 | /* Data. */ | ||
3647 | pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); | ||
3648 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | ||
3649 | pSMB->ClientUnixCap = cpu_to_le64(cap); | ||
3650 | |||
3651 | pSMB->hdr.smb_buf_length += byte_count; | ||
3652 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
3653 | |||
3654 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
3655 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
3656 | if (rc) { | ||
3657 | cERROR(1, ("Send error in SETFSUnixInfo = %d", rc)); | ||
3658 | } else { /* decode response */ | ||
3659 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
3660 | if (rc) { | ||
3661 | rc = -EIO; /* bad smb */ | ||
3662 | } | ||
3663 | } | ||
3664 | cifs_buf_release(pSMB); | ||
3665 | |||
3666 | if (rc == -EAGAIN) | ||
3667 | goto SETFSUnixRetry; | ||
3668 | |||
3669 | return rc; | ||
3670 | } | ||
3671 | |||
3672 | |||
3260 | 3673 | ||
3261 | int | 3674 | int |
3262 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 3675 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |
@@ -3321,16 +3734,16 @@ QFSPosixRetry: | |||
3321 | le64_to_cpu(response_data->TotalBlocks); | 3734 | le64_to_cpu(response_data->TotalBlocks); |
3322 | FSData->f_bfree = | 3735 | FSData->f_bfree = |
3323 | le64_to_cpu(response_data->BlocksAvail); | 3736 | le64_to_cpu(response_data->BlocksAvail); |
3324 | if(response_data->UserBlocksAvail == -1) { | 3737 | if(response_data->UserBlocksAvail == cpu_to_le64(-1)) { |
3325 | FSData->f_bavail = FSData->f_bfree; | 3738 | FSData->f_bavail = FSData->f_bfree; |
3326 | } else { | 3739 | } else { |
3327 | FSData->f_bavail = | 3740 | FSData->f_bavail = |
3328 | le64_to_cpu(response_data->UserBlocksAvail); | 3741 | le64_to_cpu(response_data->UserBlocksAvail); |
3329 | } | 3742 | } |
3330 | if(response_data->TotalFileNodes != -1) | 3743 | if(response_data->TotalFileNodes != cpu_to_le64(-1)) |
3331 | FSData->f_files = | 3744 | FSData->f_files = |
3332 | le64_to_cpu(response_data->TotalFileNodes); | 3745 | le64_to_cpu(response_data->TotalFileNodes); |
3333 | if(response_data->FreeFileNodes != -1) | 3746 | if(response_data->FreeFileNodes != cpu_to_le64(-1)) |
3334 | FSData->f_ffree = | 3747 | FSData->f_ffree = |
3335 | le64_to_cpu(response_data->FreeFileNodes); | 3748 | le64_to_cpu(response_data->FreeFileNodes); |
3336 | } | 3749 | } |
@@ -3376,7 +3789,7 @@ SetEOFRetry: | |||
3376 | PATH_MAX, nls_codepage, remap); | 3789 | PATH_MAX, nls_codepage, remap); |
3377 | name_len++; /* trailing null */ | 3790 | name_len++; /* trailing null */ |
3378 | name_len *= 2; | 3791 | name_len *= 2; |
3379 | } else { /* BB improve the check for buffer overruns BB */ | 3792 | } else { /* BB improve the check for buffer overruns BB */ |
3380 | name_len = strnlen(fileName, PATH_MAX); | 3793 | name_len = strnlen(fileName, PATH_MAX); |
3381 | name_len++; /* trailing null */ | 3794 | name_len++; /* trailing null */ |
3382 | strncpy(pSMB->FileName, fileName, name_len); | 3795 | strncpy(pSMB->FileName, fileName, name_len); |
@@ -3384,7 +3797,7 @@ SetEOFRetry: | |||
3384 | params = 6 + name_len; | 3797 | params = 6 + name_len; |
3385 | data_count = sizeof (struct file_end_of_file_info); | 3798 | data_count = sizeof (struct file_end_of_file_info); |
3386 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3799 | pSMB->MaxParameterCount = cpu_to_le16(2); |
3387 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | 3800 | pSMB->MaxDataCount = cpu_to_le16(4100); |
3388 | pSMB->MaxSetupCount = 0; | 3801 | pSMB->MaxSetupCount = 0; |
3389 | pSMB->Reserved = 0; | 3802 | pSMB->Reserved = 0; |
3390 | pSMB->Flags = 0; | 3803 | pSMB->Flags = 0; |
@@ -3766,7 +4179,7 @@ setPermsRetry: | |||
3766 | PATH_MAX, nls_codepage, remap); | 4179 | PATH_MAX, nls_codepage, remap); |
3767 | name_len++; /* trailing null */ | 4180 | name_len++; /* trailing null */ |
3768 | name_len *= 2; | 4181 | name_len *= 2; |
3769 | } else { /* BB improve the check for buffer overruns BB */ | 4182 | } else { /* BB improve the check for buffer overruns BB */ |
3770 | name_len = strnlen(fileName, PATH_MAX); | 4183 | name_len = strnlen(fileName, PATH_MAX); |
3771 | name_len++; /* trailing null */ | 4184 | name_len++; /* trailing null */ |
3772 | strncpy(pSMB->FileName, fileName, name_len); | 4185 | strncpy(pSMB->FileName, fileName, name_len); |
@@ -3839,12 +4252,14 @@ setPermsRetry: | |||
3839 | } | 4252 | } |
3840 | 4253 | ||
3841 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 4254 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
3842 | const int notify_subdirs, const __u16 netfid, | 4255 | const int notify_subdirs, const __u16 netfid, |
3843 | __u32 filter, const struct nls_table *nls_codepage) | 4256 | __u32 filter, struct file * pfile, int multishot, |
4257 | const struct nls_table *nls_codepage) | ||
3844 | { | 4258 | { |
3845 | int rc = 0; | 4259 | int rc = 0; |
3846 | struct smb_com_transaction_change_notify_req * pSMB = NULL; | 4260 | struct smb_com_transaction_change_notify_req * pSMB = NULL; |
3847 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; | 4261 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; |
4262 | struct dir_notify_req *dnotify_req; | ||
3848 | int bytes_returned; | 4263 | int bytes_returned; |
3849 | 4264 | ||
3850 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); | 4265 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); |
@@ -3877,6 +4292,28 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
3877 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); | 4292 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); |
3878 | if (rc) { | 4293 | if (rc) { |
3879 | cFYI(1, ("Error in Notify = %d", rc)); | 4294 | cFYI(1, ("Error in Notify = %d", rc)); |
4295 | } else { | ||
4296 | /* Add file to outstanding requests */ | ||
4297 | /* BB change to kmem cache alloc */ | ||
4298 | dnotify_req = (struct dir_notify_req *) kmalloc( | ||
4299 | sizeof(struct dir_notify_req), | ||
4300 | GFP_KERNEL); | ||
4301 | if(dnotify_req) { | ||
4302 | dnotify_req->Pid = pSMB->hdr.Pid; | ||
4303 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | ||
4304 | dnotify_req->Mid = pSMB->hdr.Mid; | ||
4305 | dnotify_req->Tid = pSMB->hdr.Tid; | ||
4306 | dnotify_req->Uid = pSMB->hdr.Uid; | ||
4307 | dnotify_req->netfid = netfid; | ||
4308 | dnotify_req->pfile = pfile; | ||
4309 | dnotify_req->filter = filter; | ||
4310 | dnotify_req->multishot = multishot; | ||
4311 | spin_lock(&GlobalMid_Lock); | ||
4312 | list_add_tail(&dnotify_req->lhead, | ||
4313 | &GlobalDnotifyReqList); | ||
4314 | spin_unlock(&GlobalMid_Lock); | ||
4315 | } else | ||
4316 | rc = -ENOMEM; | ||
3880 | } | 4317 | } |
3881 | cifs_buf_release(pSMB); | 4318 | cifs_buf_release(pSMB); |
3882 | return rc; | 4319 | return rc; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 47360156cc54..d74367a08d51 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
30 | #include <linux/mempool.h> | 30 | #include <linux/mempool.h> |
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/completion.h> | ||
33 | #include <linux/pagevec.h> | ||
32 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
33 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
34 | #include "cifspdu.h" | 36 | #include "cifspdu.h" |
@@ -44,6 +46,8 @@ | |||
44 | #define CIFS_PORT 445 | 46 | #define CIFS_PORT 445 |
45 | #define RFC1001_PORT 139 | 47 | #define RFC1001_PORT 139 |
46 | 48 | ||
49 | static DECLARE_COMPLETION(cifsd_complete); | ||
50 | |||
47 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | 51 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, |
48 | unsigned char *p24); | 52 | unsigned char *p24); |
49 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 53 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
@@ -60,6 +64,7 @@ struct smb_vol { | |||
60 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ | 64 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ |
61 | char *iocharset; /* local code page for mapping to and from Unicode */ | 65 | char *iocharset; /* local code page for mapping to and from Unicode */ |
62 | char source_rfc1001_name[16]; /* netbios name of client */ | 66 | char source_rfc1001_name[16]; /* netbios name of client */ |
67 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | ||
63 | uid_t linux_uid; | 68 | uid_t linux_uid; |
64 | gid_t linux_gid; | 69 | gid_t linux_gid; |
65 | mode_t file_mode; | 70 | mode_t file_mode; |
@@ -74,6 +79,10 @@ struct smb_vol { | |||
74 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | 79 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ |
75 | unsigned direct_io:1; | 80 | unsigned direct_io:1; |
76 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | 81 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ |
82 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | ||
83 | unsigned sfu_emul:1; | ||
84 | unsigned nocase; /* request case insensitive filenames */ | ||
85 | unsigned nobrl; /* disable sending byte range locks to srv */ | ||
77 | unsigned int rsize; | 86 | unsigned int rsize; |
78 | unsigned int wsize; | 87 | unsigned int wsize; |
79 | unsigned int sockopt; | 88 | unsigned int sockopt; |
@@ -82,7 +91,8 @@ struct smb_vol { | |||
82 | 91 | ||
83 | static int ipv4_connect(struct sockaddr_in *psin_server, | 92 | static int ipv4_connect(struct sockaddr_in *psin_server, |
84 | struct socket **csocket, | 93 | struct socket **csocket, |
85 | char * netb_name); | 94 | char * netb_name, |
95 | char * server_netb_name); | ||
86 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | 96 | static int ipv6_connect(struct sockaddr_in6 *psin_server, |
87 | struct socket **csocket); | 97 | struct socket **csocket); |
88 | 98 | ||
@@ -175,9 +185,11 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
175 | } else { | 185 | } else { |
176 | rc = ipv4_connect(&server->addr.sockAddr, | 186 | rc = ipv4_connect(&server->addr.sockAddr, |
177 | &server->ssocket, | 187 | &server->ssocket, |
178 | server->workstation_RFC1001_name); | 188 | server->workstation_RFC1001_name, |
189 | server->server_RFC1001_name); | ||
179 | } | 190 | } |
180 | if(rc) { | 191 | if(rc) { |
192 | cFYI(1,("reconnect error %d",rc)); | ||
181 | msleep(3000); | 193 | msleep(3000); |
182 | } else { | 194 | } else { |
183 | atomic_inc(&tcpSesReconnectCount); | 195 | atomic_inc(&tcpSesReconnectCount); |
@@ -293,12 +305,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) | |||
293 | byte_count += total_in_buf2; | 305 | byte_count += total_in_buf2; |
294 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | 306 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); |
295 | 307 | ||
296 | byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); | 308 | byte_count = pTargetSMB->smb_buf_length; |
297 | byte_count += total_in_buf2; | 309 | byte_count += total_in_buf2; |
298 | 310 | ||
299 | /* BB also add check that we are not beyond maximum buffer size */ | 311 | /* BB also add check that we are not beyond maximum buffer size */ |
300 | 312 | ||
301 | pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); | 313 | pTargetSMB->smb_buf_length = byte_count; |
302 | 314 | ||
303 | if(remaining == total_in_buf2) { | 315 | if(remaining == total_in_buf2) { |
304 | cFYI(1,("found the last secondary response")); | 316 | cFYI(1,("found the last secondary response")); |
@@ -323,7 +335,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
323 | struct cifsSesInfo *ses; | 335 | struct cifsSesInfo *ses; |
324 | struct task_struct *task_to_wake = NULL; | 336 | struct task_struct *task_to_wake = NULL; |
325 | struct mid_q_entry *mid_entry; | 337 | struct mid_q_entry *mid_entry; |
326 | char *temp; | 338 | char temp; |
327 | int isLargeBuf = FALSE; | 339 | int isLargeBuf = FALSE; |
328 | int isMultiRsp; | 340 | int isMultiRsp; |
329 | int reconnect; | 341 | int reconnect; |
@@ -337,6 +349,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
337 | atomic_inc(&tcpSesAllocCount); | 349 | atomic_inc(&tcpSesAllocCount); |
338 | length = tcpSesAllocCount.counter; | 350 | length = tcpSesAllocCount.counter; |
339 | write_unlock(&GlobalSMBSeslock); | 351 | write_unlock(&GlobalSMBSeslock); |
352 | complete(&cifsd_complete); | ||
340 | if(length > 1) { | 353 | if(length > 1) { |
341 | mempool_resize(cifs_req_poolp, | 354 | mempool_resize(cifs_req_poolp, |
342 | length + cifs_min_rcv, | 355 | length + cifs_min_rcv, |
@@ -424,22 +437,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
424 | continue; | 437 | continue; |
425 | } | 438 | } |
426 | 439 | ||
427 | /* the right amount was read from socket - 4 bytes */ | 440 | /* The right amount was read from socket - 4 bytes */ |
441 | /* so we can now interpret the length field */ | ||
442 | |||
443 | /* the first byte big endian of the length field, | ||
444 | is actually not part of the length but the type | ||
445 | with the most common, zero, as regular data */ | ||
446 | temp = *((char *) smb_buffer); | ||
428 | 447 | ||
448 | /* Note that FC 1001 length is big endian on the wire, | ||
449 | but we convert it here so it is always manipulated | ||
450 | as host byte order */ | ||
429 | pdu_length = ntohl(smb_buffer->smb_buf_length); | 451 | pdu_length = ntohl(smb_buffer->smb_buf_length); |
430 | cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); | 452 | smb_buffer->smb_buf_length = pdu_length; |
453 | |||
454 | cFYI(1,("rfc1002 length 0x%x)", pdu_length+4)); | ||
431 | 455 | ||
432 | temp = (char *) smb_buffer; | 456 | if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { |
433 | if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { | ||
434 | continue; | 457 | continue; |
435 | } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { | 458 | } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { |
436 | cFYI(1,("Good RFC 1002 session rsp")); | 459 | cFYI(1,("Good RFC 1002 session rsp")); |
437 | continue; | 460 | continue; |
438 | } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { | 461 | } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { |
439 | /* we get this from Windows 98 instead of | 462 | /* we get this from Windows 98 instead of |
440 | an error on SMB negprot response */ | 463 | an error on SMB negprot response */ |
441 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", | 464 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", |
442 | temp[4])); | 465 | pdu_length)); |
443 | if(server->tcpStatus == CifsNew) { | 466 | if(server->tcpStatus == CifsNew) { |
444 | /* if nack on negprot (rather than | 467 | /* if nack on negprot (rather than |
445 | ret of smb negprot error) reconnecting | 468 | ret of smb negprot error) reconnecting |
@@ -461,9 +484,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
461 | wake_up(&server->response_q); | 484 | wake_up(&server->response_q); |
462 | continue; | 485 | continue; |
463 | } | 486 | } |
464 | } else if (temp[0] != (char) 0) { | 487 | } else if (temp != (char) 0) { |
465 | cERROR(1,("Unknown RFC 1002 frame")); | 488 | cERROR(1,("Unknown RFC 1002 frame")); |
466 | cifs_dump_mem(" Received Data: ", temp, length); | 489 | cifs_dump_mem(" Received Data: ", (char *)smb_buffer, |
490 | length); | ||
467 | cifs_reconnect(server); | 491 | cifs_reconnect(server); |
468 | csocket = server->ssocket; | 492 | csocket = server->ssocket; |
469 | continue; | 493 | continue; |
@@ -533,7 +557,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
533 | 557 | ||
534 | dump_smb(smb_buffer, length); | 558 | dump_smb(smb_buffer, length); |
535 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { | 559 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { |
536 | cERROR(1, ("Bad SMB Received ")); | 560 | cifs_dump_mem("Bad SMB: ", smb_buffer, 48); |
537 | continue; | 561 | continue; |
538 | } | 562 | } |
539 | 563 | ||
@@ -581,6 +605,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
581 | multi_t2_fnd: | 605 | multi_t2_fnd: |
582 | task_to_wake = mid_entry->tsk; | 606 | task_to_wake = mid_entry->tsk; |
583 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 607 | mid_entry->midState = MID_RESPONSE_RECEIVED; |
608 | #ifdef CONFIG_CIFS_STATS2 | ||
609 | mid_entry->when_received = jiffies; | ||
610 | #endif | ||
584 | break; | 611 | break; |
585 | } | 612 | } |
586 | } | 613 | } |
@@ -598,7 +625,8 @@ multi_t2_fnd: | |||
598 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) | 625 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) |
599 | && (isMultiRsp == FALSE)) { | 626 | && (isMultiRsp == FALSE)) { |
600 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | 627 | cERROR(1, ("No task to wake, unknown frame rcvd!")); |
601 | cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); | 628 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, |
629 | sizeof(struct smb_hdr)); | ||
602 | } | 630 | } |
603 | } /* end while !EXITING */ | 631 | } /* end while !EXITING */ |
604 | 632 | ||
@@ -676,7 +704,7 @@ multi_t2_fnd: | |||
676 | msleep(125); | 704 | msleep(125); |
677 | } | 705 | } |
678 | 706 | ||
679 | if (list_empty(&server->pending_mid_q)) { | 707 | if (!list_empty(&server->pending_mid_q)) { |
680 | /* mpx threads have not exited yet give them | 708 | /* mpx threads have not exited yet give them |
681 | at least the smb send timeout time for long ops */ | 709 | at least the smb send timeout time for long ops */ |
682 | /* due to delays on oplock break requests, we need | 710 | /* due to delays on oplock break requests, we need |
@@ -713,7 +741,7 @@ multi_t2_fnd: | |||
713 | GFP_KERNEL); | 741 | GFP_KERNEL); |
714 | } | 742 | } |
715 | 743 | ||
716 | msleep(250); | 744 | complete_and_exit(&cifsd_complete, 0); |
717 | return 0; | 745 | return 0; |
718 | } | 746 | } |
719 | 747 | ||
@@ -737,7 +765,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
737 | toupper(system_utsname.nodename[i]); | 765 | toupper(system_utsname.nodename[i]); |
738 | } | 766 | } |
739 | vol->source_rfc1001_name[15] = 0; | 767 | vol->source_rfc1001_name[15] = 0; |
740 | 768 | /* null target name indicates to use *SMBSERVR default called name | |
769 | if we end up sending RFC1001 session initialize */ | ||
770 | vol->target_rfc1001_name[0] = 0; | ||
741 | vol->linux_uid = current->uid; /* current->euid instead? */ | 771 | vol->linux_uid = current->uid; /* current->euid instead? */ |
742 | vol->linux_gid = current->gid; | 772 | vol->linux_gid = current->gid; |
743 | vol->dir_mode = S_IRWXUGO; | 773 | vol->dir_mode = S_IRWXUGO; |
@@ -747,6 +777,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
747 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 777 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
748 | vol->rw = TRUE; | 778 | vol->rw = TRUE; |
749 | 779 | ||
780 | /* default is always to request posix paths. */ | ||
781 | vol->posix_paths = 1; | ||
782 | |||
750 | if (!options) | 783 | if (!options) |
751 | return 1; | 784 | return 1; |
752 | 785 | ||
@@ -987,7 +1020,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
987 | /* The string has 16th byte zero still from | 1020 | /* The string has 16th byte zero still from |
988 | set at top of the function */ | 1021 | set at top of the function */ |
989 | if((i==15) && (value[i] != 0)) | 1022 | if((i==15) && (value[i] != 0)) |
990 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); | 1023 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n"); |
1024 | } | ||
1025 | } else if (strnicmp(data, "servern", 7) == 0) { | ||
1026 | /* servernetbiosname specified override *SMBSERVER */ | ||
1027 | if (!value || !*value || (*value == ' ')) { | ||
1028 | cFYI(1,("empty server netbiosname specified")); | ||
1029 | } else { | ||
1030 | /* last byte, type, is 0x20 for servr type */ | ||
1031 | memset(vol->target_rfc1001_name,0x20,16); | ||
1032 | |||
1033 | for(i=0;i<15;i++) { | ||
1034 | /* BB are there cases in which a comma can be | ||
1035 | valid in this workstation netbios name (and need | ||
1036 | special handling)? */ | ||
1037 | |||
1038 | /* user or mount helper must uppercase netbiosname */ | ||
1039 | if (value[i]==0) | ||
1040 | break; | ||
1041 | else | ||
1042 | vol->target_rfc1001_name[i] = value[i]; | ||
1043 | } | ||
1044 | /* The string has 16th byte zero still from | ||
1045 | set at top of the function */ | ||
1046 | if((i==15) && (value[i] != 0)) | ||
1047 | printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n"); | ||
991 | } | 1048 | } |
992 | } else if (strnicmp(data, "credentials", 4) == 0) { | 1049 | } else if (strnicmp(data, "credentials", 4) == 0) { |
993 | /* ignore */ | 1050 | /* ignore */ |
@@ -1025,6 +1082,27 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
1025 | vol->remap = 1; | 1082 | vol->remap = 1; |
1026 | } else if (strnicmp(data, "nomapchars", 10) == 0) { | 1083 | } else if (strnicmp(data, "nomapchars", 10) == 0) { |
1027 | vol->remap = 0; | 1084 | vol->remap = 0; |
1085 | } else if (strnicmp(data, "sfu", 3) == 0) { | ||
1086 | vol->sfu_emul = 1; | ||
1087 | } else if (strnicmp(data, "nosfu", 5) == 0) { | ||
1088 | vol->sfu_emul = 0; | ||
1089 | } else if (strnicmp(data, "posixpaths", 10) == 0) { | ||
1090 | vol->posix_paths = 1; | ||
1091 | } else if (strnicmp(data, "noposixpaths", 12) == 0) { | ||
1092 | vol->posix_paths = 0; | ||
1093 | } else if ((strnicmp(data, "nocase", 6) == 0) || | ||
1094 | (strnicmp(data, "ignorecase", 10) == 0)) { | ||
1095 | vol->nocase = 1; | ||
1096 | } else if (strnicmp(data, "brl", 3) == 0) { | ||
1097 | vol->nobrl = 0; | ||
1098 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | ||
1099 | (strnicmp(data, "nolock", 6) == 0)) { | ||
1100 | vol->nobrl = 1; | ||
1101 | /* turn off mandatory locking in mode | ||
1102 | if remote locking is turned off since the | ||
1103 | local vfs will do advisory */ | ||
1104 | if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) | ||
1105 | vol->file_mode = S_IALLUGO; | ||
1028 | } else if (strnicmp(data, "setuids", 7) == 0) { | 1106 | } else if (strnicmp(data, "setuids", 7) == 0) { |
1029 | vol->setuids = 1; | 1107 | vol->setuids = 1; |
1030 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1108 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
@@ -1244,7 +1322,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length) | |||
1244 | 1322 | ||
1245 | static int | 1323 | static int |
1246 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | 1324 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, |
1247 | char * netbios_name) | 1325 | char * netbios_name, char * target_name) |
1248 | { | 1326 | { |
1249 | int rc = 0; | 1327 | int rc = 0; |
1250 | int connected = 0; | 1328 | int connected = 0; |
@@ -1309,10 +1387,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1309 | /* Eventually check for other socket options to change from | 1387 | /* Eventually check for other socket options to change from |
1310 | the default. sock_setsockopt not used because it expects | 1388 | the default. sock_setsockopt not used because it expects |
1311 | user space buffer */ | 1389 | user space buffer */ |
1390 | cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf, | ||
1391 | (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); | ||
1312 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | 1392 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; |
1393 | /* make the bufsizes depend on wsize/rsize and max requests */ | ||
1394 | if((*csocket)->sk->sk_sndbuf < (200 * 1024)) | ||
1395 | (*csocket)->sk->sk_sndbuf = 200 * 1024; | ||
1396 | if((*csocket)->sk->sk_rcvbuf < (140 * 1024)) | ||
1397 | (*csocket)->sk->sk_rcvbuf = 140 * 1024; | ||
1313 | 1398 | ||
1314 | /* send RFC1001 sessinit */ | 1399 | /* send RFC1001 sessinit */ |
1315 | |||
1316 | if(psin_server->sin_port == htons(RFC1001_PORT)) { | 1400 | if(psin_server->sin_port == htons(RFC1001_PORT)) { |
1317 | /* some servers require RFC1001 sessinit before sending | 1401 | /* some servers require RFC1001 sessinit before sending |
1318 | negprot - BB check reconnection in case where second | 1402 | negprot - BB check reconnection in case where second |
@@ -1322,8 +1406,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1322 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); | 1406 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); |
1323 | if(ses_init_buf) { | 1407 | if(ses_init_buf) { |
1324 | ses_init_buf->trailer.session_req.called_len = 32; | 1408 | ses_init_buf->trailer.session_req.called_len = 32; |
1325 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | 1409 | if(target_name && (target_name[0] != 0)) { |
1326 | DEFAULT_CIFS_CALLED_NAME,16); | 1410 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, |
1411 | target_name, 16); | ||
1412 | } else { | ||
1413 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | ||
1414 | DEFAULT_CIFS_CALLED_NAME,16); | ||
1415 | } | ||
1416 | |||
1327 | ses_init_buf->trailer.session_req.calling_len = 32; | 1417 | ses_init_buf->trailer.session_req.calling_len = 32; |
1328 | /* calling name ends in null (byte 16) from old smb | 1418 | /* calling name ends in null (byte 16) from old smb |
1329 | convention. */ | 1419 | convention. */ |
@@ -1556,7 +1646,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1556 | sin_server.sin_port = htons(volume_info.port); | 1646 | sin_server.sin_port = htons(volume_info.port); |
1557 | else | 1647 | else |
1558 | sin_server.sin_port = 0; | 1648 | sin_server.sin_port = 0; |
1559 | rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); | 1649 | rc = ipv4_connect(&sin_server,&csocket, |
1650 | volume_info.source_rfc1001_name, | ||
1651 | volume_info.target_rfc1001_name); | ||
1560 | if (rc < 0) { | 1652 | if (rc < 0) { |
1561 | cERROR(1, | 1653 | cERROR(1, |
1562 | ("Error connecting to IPv4 socket. Aborting operation")); | 1654 | ("Error connecting to IPv4 socket. Aborting operation")); |
@@ -1606,9 +1698,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1606 | kfree(volume_info.password); | 1698 | kfree(volume_info.password); |
1607 | FreeXid(xid); | 1699 | FreeXid(xid); |
1608 | return rc; | 1700 | return rc; |
1609 | } else | 1701 | } |
1610 | rc = 0; | 1702 | wait_for_completion(&cifsd_complete); |
1703 | rc = 0; | ||
1611 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); | 1704 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); |
1705 | memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16); | ||
1612 | srvTcp->sequence_number = 0; | 1706 | srvTcp->sequence_number = 0; |
1613 | } | 1707 | } |
1614 | } | 1708 | } |
@@ -1653,17 +1747,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1653 | 1747 | ||
1654 | /* search for existing tcon to this server share */ | 1748 | /* search for existing tcon to this server share */ |
1655 | if (!rc) { | 1749 | if (!rc) { |
1656 | if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | 1750 | if(volume_info.rsize > CIFSMaxBufSize) { |
1751 | cERROR(1,("rsize %d too large, using MaxBufSize", | ||
1752 | volume_info.rsize)); | ||
1753 | cifs_sb->rsize = CIFSMaxBufSize; | ||
1754 | } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | ||
1657 | cifs_sb->rsize = volume_info.rsize; | 1755 | cifs_sb->rsize = volume_info.rsize; |
1658 | else | 1756 | else /* default */ |
1659 | cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ | 1757 | cifs_sb->rsize = CIFSMaxBufSize; |
1660 | if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize)) | 1758 | |
1759 | if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { | ||
1760 | cERROR(1,("wsize %d too large using 4096 instead", | ||
1761 | volume_info.wsize)); | ||
1762 | cifs_sb->wsize = 4096; | ||
1763 | } else if(volume_info.wsize) | ||
1661 | cifs_sb->wsize = volume_info.wsize; | 1764 | cifs_sb->wsize = volume_info.wsize; |
1662 | else | 1765 | else |
1663 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ | 1766 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ |
1664 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { | 1767 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { |
1665 | cifs_sb->rsize = PAGE_CACHE_SIZE; | 1768 | cifs_sb->rsize = PAGE_CACHE_SIZE; |
1666 | cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); | 1769 | /* Windows ME does this */ |
1770 | cFYI(1,("Attempt to set readsize for mount to less than one page (4096)")); | ||
1667 | } | 1771 | } |
1668 | cifs_sb->mnt_uid = volume_info.linux_uid; | 1772 | cifs_sb->mnt_uid = volume_info.linux_uid; |
1669 | cifs_sb->mnt_gid = volume_info.linux_gid; | 1773 | cifs_sb->mnt_gid = volume_info.linux_gid; |
@@ -1681,8 +1785,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1681 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; | 1785 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; |
1682 | if(volume_info.no_xattr) | 1786 | if(volume_info.no_xattr) |
1683 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | 1787 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; |
1788 | if(volume_info.sfu_emul) | ||
1789 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | ||
1790 | if(volume_info.nobrl) | ||
1791 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | ||
1792 | |||
1684 | if(volume_info.direct_io) { | 1793 | if(volume_info.direct_io) { |
1685 | cERROR(1,("mounting share using direct i/o")); | 1794 | cFYI(1,("mounting share using direct i/o")); |
1686 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 1795 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
1687 | } | 1796 | } |
1688 | 1797 | ||
@@ -1696,6 +1805,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1696 | to the same server share the last value passed in | 1805 | to the same server share the last value passed in |
1697 | for the retry flag is used */ | 1806 | for the retry flag is used */ |
1698 | tcon->retry = volume_info.retry; | 1807 | tcon->retry = volume_info.retry; |
1808 | tcon->nocase = volume_info.nocase; | ||
1699 | } else { | 1809 | } else { |
1700 | tcon = tconInfoAlloc(); | 1810 | tcon = tconInfoAlloc(); |
1701 | if (tcon == NULL) | 1811 | if (tcon == NULL) |
@@ -1724,6 +1834,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1724 | if (!rc) { | 1834 | if (!rc) { |
1725 | atomic_inc(&pSesInfo->inUse); | 1835 | atomic_inc(&pSesInfo->inUse); |
1726 | tcon->retry = volume_info.retry; | 1836 | tcon->retry = volume_info.retry; |
1837 | tcon->nocase = volume_info.nocase; | ||
1727 | } | 1838 | } |
1728 | } | 1839 | } |
1729 | } | 1840 | } |
@@ -1745,8 +1856,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1745 | spin_lock(&GlobalMid_Lock); | 1856 | spin_lock(&GlobalMid_Lock); |
1746 | srvTcp->tcpStatus = CifsExiting; | 1857 | srvTcp->tcpStatus = CifsExiting; |
1747 | spin_unlock(&GlobalMid_Lock); | 1858 | spin_unlock(&GlobalMid_Lock); |
1748 | if(srvTcp->tsk) | 1859 | if(srvTcp->tsk) { |
1749 | send_sig(SIGKILL,srvTcp->tsk,1); | 1860 | send_sig(SIGKILL,srvTcp->tsk,1); |
1861 | wait_for_completion(&cifsd_complete); | ||
1862 | } | ||
1750 | } | 1863 | } |
1751 | /* If find_unc succeeded then rc == 0 so we can not end */ | 1864 | /* If find_unc succeeded then rc == 0 so we can not end */ |
1752 | if (tcon) /* up accidently freeing someone elses tcon struct */ | 1865 | if (tcon) /* up accidently freeing someone elses tcon struct */ |
@@ -1759,8 +1872,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1759 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); | 1872 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); |
1760 | /* if the socketUseCount is now zero */ | 1873 | /* if the socketUseCount is now zero */ |
1761 | if((temp_rc == -ESHUTDOWN) && | 1874 | if((temp_rc == -ESHUTDOWN) && |
1762 | (pSesInfo->server->tsk)) | 1875 | (pSesInfo->server->tsk)) { |
1763 | send_sig(SIGKILL,pSesInfo->server->tsk,1); | 1876 | send_sig(SIGKILL,pSesInfo->server->tsk,1); |
1877 | wait_for_completion(&cifsd_complete); | ||
1878 | } | ||
1764 | } else | 1879 | } else |
1765 | cFYI(1, ("No session or bad tcon")); | 1880 | cFYI(1, ("No session or bad tcon")); |
1766 | sesInfoFree(pSesInfo); | 1881 | sesInfoFree(pSesInfo); |
@@ -1783,8 +1898,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1783 | cFYI(1,("server negotiated posix acl support")); | 1898 | cFYI(1,("server negotiated posix acl support")); |
1784 | sb->s_flags |= MS_POSIXACL; | 1899 | sb->s_flags |= MS_POSIXACL; |
1785 | } | 1900 | } |
1901 | |||
1902 | /* Try and negotiate POSIX pathnames if we can. */ | ||
1903 | if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP & | ||
1904 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | ||
1905 | if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) { | ||
1906 | cFYI(1,("negotiated posix pathnames support")); | ||
1907 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; | ||
1908 | } else { | ||
1909 | cFYI(1,("posix pathnames support requested but not supported")); | ||
1910 | } | ||
1911 | } | ||
1786 | } | 1912 | } |
1787 | } | 1913 | } |
1914 | if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) | ||
1915 | cifs_sb->wsize = min(cifs_sb->wsize, | ||
1916 | (tcon->ses->server->maxBuf - | ||
1917 | MAX_CIFS_HDR_SIZE)); | ||
1918 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) | ||
1919 | cifs_sb->rsize = min(cifs_sb->rsize, | ||
1920 | (tcon->ses->server->maxBuf - | ||
1921 | MAX_CIFS_HDR_SIZE)); | ||
1788 | } | 1922 | } |
1789 | 1923 | ||
1790 | /* volume_info.password is freed above when existing session found | 1924 | /* volume_info.password is freed above when existing session found |
@@ -1832,6 +1966,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
1832 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 1966 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
1833 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | 1967 | NULL /* no tCon exists yet */ , 13 /* wct */ ); |
1834 | 1968 | ||
1969 | smb_buffer->Mid = GetNextMid(ses->server); | ||
1835 | pSMB->req_no_secext.AndXCommand = 0xFF; | 1970 | pSMB->req_no_secext.AndXCommand = 0xFF; |
1836 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 1971 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
1837 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | 1972 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); |
@@ -2107,6 +2242,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2107 | /* send SMBsessionSetup here */ | 2242 | /* send SMBsessionSetup here */ |
2108 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2243 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
2109 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2244 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
2245 | |||
2246 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2110 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2247 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
2111 | pSMB->req.AndXCommand = 0xFF; | 2248 | pSMB->req.AndXCommand = 0xFF; |
2112 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 2249 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
@@ -2373,6 +2510,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
2373 | /* send SMBsessionSetup here */ | 2510 | /* send SMBsessionSetup here */ |
2374 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2511 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
2375 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2512 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
2513 | |||
2514 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2376 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2515 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
2377 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | 2516 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); |
2378 | 2517 | ||
@@ -2715,6 +2854,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2715 | /* send SMBsessionSetup here */ | 2854 | /* send SMBsessionSetup here */ |
2716 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2855 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
2717 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2856 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
2857 | |||
2858 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2718 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | 2859 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); |
2719 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2860 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
2720 | pSMB->req.AndXCommand = 0xFF; | 2861 | pSMB->req.AndXCommand = 0xFF; |
@@ -3086,6 +3227,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3086 | 3227 | ||
3087 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | 3228 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, |
3088 | NULL /*no tid */ , 4 /*wct */ ); | 3229 | NULL /*no tid */ , 4 /*wct */ ); |
3230 | |||
3231 | smb_buffer->Mid = GetNextMid(ses->server); | ||
3089 | smb_buffer->Uid = ses->Suid; | 3232 | smb_buffer->Uid = ses->Suid; |
3090 | pSMB = (TCONX_REQ *) smb_buffer; | 3233 | pSMB = (TCONX_REQ *) smb_buffer; |
3091 | pSMBr = (TCONX_RSP *) smb_buffer_response; | 3234 | pSMBr = (TCONX_RSP *) smb_buffer_response; |
@@ -3207,8 +3350,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3207 | return 0; | 3350 | return 0; |
3208 | } else if (rc == -ESHUTDOWN) { | 3351 | } else if (rc == -ESHUTDOWN) { |
3209 | cFYI(1,("Waking up socket by sending it signal")); | 3352 | cFYI(1,("Waking up socket by sending it signal")); |
3210 | if(cifsd_task) | 3353 | if(cifsd_task) { |
3211 | send_sig(SIGKILL,cifsd_task,1); | 3354 | send_sig(SIGKILL,cifsd_task,1); |
3355 | wait_for_completion(&cifsd_complete); | ||
3356 | } | ||
3212 | rc = 0; | 3357 | rc = 0; |
3213 | } /* else - we have an smb session | 3358 | } /* else - we have an smb session |
3214 | left on this socket do not kill cifsd */ | 3359 | left on this socket do not kill cifsd */ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d335269bd91c..8dfe717a332a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry) | |||
48 | struct dentry *temp; | 48 | struct dentry *temp; |
49 | int namelen = 0; | 49 | int namelen = 0; |
50 | char *full_path; | 50 | char *full_path; |
51 | char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); | ||
51 | 52 | ||
52 | if(direntry == NULL) | 53 | if(direntry == NULL) |
53 | return NULL; /* not much we can do if dentry is freed and | 54 | return NULL; /* not much we can do if dentry is freed and |
@@ -74,7 +75,7 @@ cifs_bp_rename_retry: | |||
74 | if (namelen < 0) { | 75 | if (namelen < 0) { |
75 | break; | 76 | break; |
76 | } else { | 77 | } else { |
77 | full_path[namelen] = '\\'; | 78 | full_path[namelen] = dirsep; |
78 | strncpy(full_path + namelen + 1, temp->d_name.name, | 79 | strncpy(full_path + namelen + 1, temp->d_name.name, |
79 | temp->d_name.len); | 80 | temp->d_name.len); |
80 | cFYI(0, (" name: %s ", full_path + namelen)); | 81 | cFYI(0, (" name: %s ", full_path + namelen)); |
@@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
183 | desiredAccess, CREATE_NOT_DIR, | 184 | desiredAccess, CREATE_NOT_DIR, |
184 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 185 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
185 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 186 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
187 | if(rc == -EIO) { | ||
188 | /* old server, retry the open legacy style */ | ||
189 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
190 | desiredAccess, CREATE_NOT_DIR, | ||
191 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | ||
192 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
193 | } | ||
186 | if (rc) { | 194 | if (rc) { |
187 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | 195 | cFYI(1, ("cifs_create returned 0x%x ", rc)); |
188 | } else { | 196 | } else { |
@@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
208 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 216 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
209 | } | 217 | } |
210 | else { | 218 | else { |
211 | /* BB implement via Windows security descriptors */ | 219 | /* BB implement mode setting via Windows security descriptors */ |
212 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ | 220 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ |
213 | /* could set r/o dos attribute if mode & 0222 == 0 */ | 221 | /* could set r/o dos attribute if mode & 0222 == 0 */ |
214 | } | 222 | } |
@@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
225 | } | 233 | } |
226 | 234 | ||
227 | if (rc != 0) { | 235 | if (rc != 0) { |
228 | cFYI(1,("Create worked but get_inode_info failed with rc = %d", | 236 | cFYI(1, |
237 | ("Create worked but get_inode_info failed rc = %d", | ||
229 | rc)); | 238 | rc)); |
230 | } else { | 239 | } else { |
231 | direntry->d_op = &cifs_dentry_ops; | 240 | if (pTcon->nocase) |
241 | direntry->d_op = &cifs_ci_dentry_ops; | ||
242 | else | ||
243 | direntry->d_op = &cifs_dentry_ops; | ||
232 | d_instantiate(direntry, newinode); | 244 | d_instantiate(direntry, newinode); |
233 | } | 245 | } |
234 | if((nd->flags & LOOKUP_OPEN) == FALSE) { | 246 | if((nd->flags & LOOKUP_OPEN) == FALSE) { |
@@ -302,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
302 | up(&direntry->d_sb->s_vfs_rename_sem); | 314 | up(&direntry->d_sb->s_vfs_rename_sem); |
303 | if(full_path == NULL) | 315 | if(full_path == NULL) |
304 | rc = -ENOMEM; | 316 | rc = -ENOMEM; |
305 | 317 | else if (pTcon->ses->capabilities & CAP_UNIX) { | |
306 | if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { | ||
307 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 318 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
308 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 319 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
309 | mode,(__u64)current->euid,(__u64)current->egid, | 320 | mode,(__u64)current->euid,(__u64)current->egid, |
@@ -321,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
321 | if(!rc) { | 332 | if(!rc) { |
322 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 333 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
323 | inode->i_sb,xid); | 334 | inode->i_sb,xid); |
324 | direntry->d_op = &cifs_dentry_ops; | 335 | if (pTcon->nocase) |
336 | direntry->d_op = &cifs_ci_dentry_ops; | ||
337 | else | ||
338 | direntry->d_op = &cifs_dentry_ops; | ||
325 | if(rc == 0) | 339 | if(rc == 0) |
326 | d_instantiate(direntry, newinode); | 340 | d_instantiate(direntry, newinode); |
327 | } | 341 | } |
342 | } else { | ||
343 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
344 | int oplock = 0; | ||
345 | u16 fileHandle; | ||
346 | FILE_ALL_INFO * buf; | ||
347 | |||
348 | cFYI(1,("sfu compat create special file")); | ||
349 | |||
350 | buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); | ||
351 | if(buf == NULL) { | ||
352 | kfree(full_path); | ||
353 | FreeXid(xid); | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
358 | FILE_CREATE, /* fail if exists */ | ||
359 | GENERIC_WRITE /* BB would | ||
360 | WRITE_OWNER | WRITE_DAC be better? */, | ||
361 | /* Create a file and set the | ||
362 | file attribute to SYSTEM */ | ||
363 | CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, | ||
364 | &fileHandle, &oplock, buf, | ||
365 | cifs_sb->local_nls, | ||
366 | cifs_sb->mnt_cifs_flags & | ||
367 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
368 | |||
369 | if(!rc) { | ||
370 | /* BB Do not bother to decode buf since no | ||
371 | local inode yet to put timestamps in */ | ||
372 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
373 | d_drop(direntry); | ||
374 | } | ||
375 | kfree(buf); | ||
376 | /* add code here to set EAs */ | ||
377 | } | ||
328 | } | 378 | } |
329 | 379 | ||
330 | kfree(full_path); | 380 | kfree(full_path); |
@@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
381 | parent_dir_inode->i_sb,xid); | 431 | parent_dir_inode->i_sb,xid); |
382 | 432 | ||
383 | if ((rc == 0) && (newInode != NULL)) { | 433 | if ((rc == 0) && (newInode != NULL)) { |
384 | direntry->d_op = &cifs_dentry_ops; | 434 | if (pTcon->nocase) |
435 | direntry->d_op = &cifs_ci_dentry_ops; | ||
436 | else | ||
437 | direntry->d_op = &cifs_dentry_ops; | ||
385 | d_add(direntry, newInode); | 438 | d_add(direntry, newInode); |
386 | 439 | ||
387 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ | 440 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ |
@@ -440,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = { | |||
440 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ | 493 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ |
441 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ | 494 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ |
442 | }; | 495 | }; |
496 | |||
497 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | ||
498 | { | ||
499 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
500 | unsigned long hash; | ||
501 | int i; | ||
502 | |||
503 | hash = init_name_hash(); | ||
504 | for (i = 0; i < q->len; i++) | ||
505 | hash = partial_name_hash(nls_tolower(codepage, q->name[i]), | ||
506 | hash); | ||
507 | q->hash = end_name_hash(hash); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | ||
513 | struct qstr *b) | ||
514 | { | ||
515 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
516 | |||
517 | if ((a->len == b->len) && | ||
518 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | ||
519 | /* | ||
520 | * To preserve case, don't let an existing negative dentry's | ||
521 | * case take precedence. If a is not a negative dentry, this | ||
522 | * should have no side effects | ||
523 | */ | ||
524 | memcpy((unsigned char *)a->name, b->name, a->len); | ||
525 | return 0; | ||
526 | } | ||
527 | return 1; | ||
528 | } | ||
529 | |||
530 | struct dentry_operations cifs_ci_dentry_ops = { | ||
531 | .d_revalidate = cifs_d_revalidate, | ||
532 | .d_hash = cifs_ci_hash, | ||
533 | .d_compare = cifs_ci_compare, | ||
534 | }; | ||
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 7d2a9202c39a..a7a47bb36bf3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c | |||
@@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; | 78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; |
79 | __u16 netfid; | 79 | __u16 netfid; |
80 | 80 | ||
81 | |||
82 | if(experimEnabled == 0) | ||
83 | return 0; | ||
84 | |||
81 | xid = GetXid(); | 85 | xid = GetXid(); |
82 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 86 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
83 | pTcon = cifs_sb->tcon; | 87 | pTcon = cifs_sb->tcon; |
@@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
100 | } else { | 104 | } else { |
101 | filter = convert_to_cifs_notify_flags(arg); | 105 | filter = convert_to_cifs_notify_flags(arg); |
102 | if(filter != 0) { | 106 | if(filter != 0) { |
103 | rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, | 107 | rc = CIFSSMBNotify(xid, pTcon, |
104 | filter, cifs_sb->local_nls); | 108 | 0 /* no subdirs */, netfid, |
109 | filter, file, arg & DN_MULTISHOT, | ||
110 | cifs_sb->local_nls); | ||
105 | } else { | 111 | } else { |
106 | rc = -EINVAL; | 112 | rc = -EINVAL; |
107 | } | 113 | } |
@@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
109 | it would close automatically but may be a way | 115 | it would close automatically but may be a way |
110 | to do it easily when inode freed or when | 116 | to do it easily when inode freed or when |
111 | notify info is cleared/changed */ | 117 | notify info is cleared/changed */ |
112 | cERROR(1,("notify rc %d",rc)); | 118 | cFYI(1,("notify rc %d",rc)); |
113 | } | 119 | } |
114 | } | 120 | } |
115 | 121 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3497125189df..da4f5e10b3cc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -21,11 +21,15 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/backing-dev.h> | ||
24 | #include <linux/stat.h> | 25 | #include <linux/stat.h> |
25 | #include <linux/fcntl.h> | 26 | #include <linux/fcntl.h> |
27 | #include <linux/mpage.h> | ||
26 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
27 | #include <linux/pagevec.h> | 29 | #include <linux/pagevec.h> |
28 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/writeback.h> | ||
32 | #include <linux/delay.h> | ||
29 | #include <asm/div64.h> | 33 | #include <asm/div64.h> |
30 | #include "cifsfs.h" | 34 | #include "cifsfs.h" |
31 | #include "cifspdu.h" | 35 | #include "cifspdu.h" |
@@ -47,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
47 | private_data->pInode = inode; | 51 | private_data->pInode = inode; |
48 | private_data->invalidHandle = FALSE; | 52 | private_data->invalidHandle = FALSE; |
49 | private_data->closePend = FALSE; | 53 | private_data->closePend = FALSE; |
54 | /* we have to track num writers to the inode, since writepages | ||
55 | does not tell us which handle the write is for so there can | ||
56 | be a close (overlapping with write) of the filehandle that | ||
57 | cifs_writepages chose to use */ | ||
58 | atomic_set(&private_data->wrtPending,0); | ||
50 | 59 | ||
51 | return private_data; | 60 | return private_data; |
52 | } | 61 | } |
@@ -256,6 +265,13 @@ int cifs_open(struct inode *inode, struct file *file) | |||
256 | CREATE_NOT_DIR, &netfid, &oplock, buf, | 265 | CREATE_NOT_DIR, &netfid, &oplock, buf, |
257 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 266 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
258 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 267 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
268 | if (rc == -EIO) { | ||
269 | /* Old server, try legacy style OpenX */ | ||
270 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
271 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
272 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
273 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
274 | } | ||
259 | if (rc) { | 275 | if (rc) { |
260 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | 276 | cFYI(1, ("cifs_open returned 0x%x ", rc)); |
261 | goto out; | 277 | goto out; |
@@ -463,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file) | |||
463 | /* no sense reconnecting to close a file that is | 479 | /* no sense reconnecting to close a file that is |
464 | already closed */ | 480 | already closed */ |
465 | if (pTcon->tidStatus != CifsNeedReconnect) { | 481 | if (pTcon->tidStatus != CifsNeedReconnect) { |
482 | int timeout = 2; | ||
483 | while((atomic_read(&pSMBFile->wrtPending) != 0) | ||
484 | && (timeout < 1000) ) { | ||
485 | /* Give write a better chance to get to | ||
486 | server ahead of the close. We do not | ||
487 | want to add a wait_q here as it would | ||
488 | increase the memory utilization as | ||
489 | the struct would be in each open file, | ||
490 | but this should give enough time to | ||
491 | clear the socket */ | ||
492 | cERROR(1,("close with pending writes")); | ||
493 | msleep(timeout); | ||
494 | timeout *= 4; | ||
495 | } | ||
466 | write_unlock(&file->f_owner.lock); | 496 | write_unlock(&file->f_owner.lock); |
467 | rc = CIFSSMBClose(xid, pTcon, | 497 | rc = CIFSSMBClose(xid, pTcon, |
468 | pSMBFile->netfid); | 498 | pSMBFile->netfid); |
@@ -744,14 +774,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
744 | 15 seconds is plenty */ | 774 | 15 seconds is plenty */ |
745 | } | 775 | } |
746 | 776 | ||
747 | #ifdef CONFIG_CIFS_STATS | 777 | cifs_stats_bytes_written(pTcon, total_written); |
748 | if (total_written > 0) { | ||
749 | atomic_inc(&pTcon->num_writes); | ||
750 | spin_lock(&pTcon->stat_lock); | ||
751 | pTcon->bytes_written += total_written; | ||
752 | spin_unlock(&pTcon->stat_lock); | ||
753 | } | ||
754 | #endif | ||
755 | 778 | ||
756 | /* since the write may have blocked check these pointers again */ | 779 | /* since the write may have blocked check these pointers again */ |
757 | if (file->f_dentry) { | 780 | if (file->f_dentry) { |
@@ -791,9 +814,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
791 | 814 | ||
792 | pTcon = cifs_sb->tcon; | 815 | pTcon = cifs_sb->tcon; |
793 | 816 | ||
794 | /* cFYI(1, | 817 | cFYI(1,("write %zd bytes to offset %lld of %s", write_size, |
795 | (" write %d bytes to offset %lld of %s", write_size, | 818 | *poffset, file->f_dentry->d_name.name)); |
796 | *poffset, file->f_dentry->d_name.name)); */ | ||
797 | 819 | ||
798 | if (file->private_data == NULL) | 820 | if (file->private_data == NULL) |
799 | return -EBADF; | 821 | return -EBADF; |
@@ -846,7 +868,26 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
846 | if (rc != 0) | 868 | if (rc != 0) |
847 | break; | 869 | break; |
848 | } | 870 | } |
849 | 871 | #ifdef CONFIG_CIFS_EXPERIMENTAL | |
872 | /* BB FIXME We can not sign across two buffers yet */ | ||
873 | if((experimEnabled) && ((pTcon->ses->server->secMode & | ||
874 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | ||
875 | struct kvec iov[2]; | ||
876 | unsigned int len; | ||
877 | |||
878 | len = min((size_t)cifs_sb->wsize, | ||
879 | write_size - total_written); | ||
880 | /* iov[0] is reserved for smb header */ | ||
881 | iov[1].iov_base = (char *)write_data + | ||
882 | total_written; | ||
883 | iov[1].iov_len = len; | ||
884 | rc = CIFSSMBWrite2(xid, pTcon, | ||
885 | open_file->netfid, len, | ||
886 | *poffset, &bytes_written, | ||
887 | iov, 1, long_op); | ||
888 | } else | ||
889 | /* BB FIXME fixup indentation of line below */ | ||
890 | #endif | ||
850 | rc = CIFSSMBWrite(xid, pTcon, | 891 | rc = CIFSSMBWrite(xid, pTcon, |
851 | open_file->netfid, | 892 | open_file->netfid, |
852 | min_t(const int, cifs_sb->wsize, | 893 | min_t(const int, cifs_sb->wsize, |
@@ -867,14 +908,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
867 | 15 seconds is plenty */ | 908 | 15 seconds is plenty */ |
868 | } | 909 | } |
869 | 910 | ||
870 | #ifdef CONFIG_CIFS_STATS | 911 | cifs_stats_bytes_written(pTcon, total_written); |
871 | if (total_written > 0) { | ||
872 | atomic_inc(&pTcon->num_writes); | ||
873 | spin_lock(&pTcon->stat_lock); | ||
874 | pTcon->bytes_written += total_written; | ||
875 | spin_unlock(&pTcon->stat_lock); | ||
876 | } | ||
877 | #endif | ||
878 | 912 | ||
879 | /* since the write may have blocked check these pointers again */ | 913 | /* since the write may have blocked check these pointers again */ |
880 | if (file->f_dentry) { | 914 | if (file->f_dentry) { |
@@ -893,6 +927,43 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
893 | return total_written; | 927 | return total_written; |
894 | } | 928 | } |
895 | 929 | ||
930 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | ||
931 | { | ||
932 | struct cifsFileInfo *open_file; | ||
933 | int rc; | ||
934 | |||
935 | read_lock(&GlobalSMBSeslock); | ||
936 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | ||
937 | if (open_file->closePend) | ||
938 | continue; | ||
939 | if (open_file->pfile && | ||
940 | ((open_file->pfile->f_flags & O_RDWR) || | ||
941 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
942 | atomic_inc(&open_file->wrtPending); | ||
943 | read_unlock(&GlobalSMBSeslock); | ||
944 | if((open_file->invalidHandle) && | ||
945 | (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { | ||
946 | rc = cifs_reopen_file(&cifs_inode->vfs_inode, | ||
947 | open_file->pfile, FALSE); | ||
948 | /* if it fails, try another handle - might be */ | ||
949 | /* dangerous to hold up writepages with retry */ | ||
950 | if(rc) { | ||
951 | cFYI(1,("failed on reopen file in wp")); | ||
952 | read_lock(&GlobalSMBSeslock); | ||
953 | /* can not use this handle, no write | ||
954 | pending on this one after all */ | ||
955 | atomic_dec | ||
956 | (&open_file->wrtPending); | ||
957 | continue; | ||
958 | } | ||
959 | } | ||
960 | return open_file; | ||
961 | } | ||
962 | } | ||
963 | read_unlock(&GlobalSMBSeslock); | ||
964 | return NULL; | ||
965 | } | ||
966 | |||
896 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | 967 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) |
897 | { | 968 | { |
898 | struct address_space *mapping = page->mapping; | 969 | struct address_space *mapping = page->mapping; |
@@ -903,10 +974,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
903 | struct cifs_sb_info *cifs_sb; | 974 | struct cifs_sb_info *cifs_sb; |
904 | struct cifsTconInfo *pTcon; | 975 | struct cifsTconInfo *pTcon; |
905 | struct inode *inode; | 976 | struct inode *inode; |
906 | struct cifsInodeInfo *cifsInode; | 977 | struct cifsFileInfo *open_file; |
907 | struct cifsFileInfo *open_file = NULL; | ||
908 | struct list_head *tmp; | ||
909 | struct list_head *tmp1; | ||
910 | 978 | ||
911 | if (!mapping || !mapping->host) | 979 | if (!mapping || !mapping->host) |
912 | return -EFAULT; | 980 | return -EFAULT; |
@@ -934,49 +1002,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
934 | if (mapping->host->i_size - offset < (loff_t)to) | 1002 | if (mapping->host->i_size - offset < (loff_t)to) |
935 | to = (unsigned)(mapping->host->i_size - offset); | 1003 | to = (unsigned)(mapping->host->i_size - offset); |
936 | 1004 | ||
937 | cifsInode = CIFS_I(mapping->host); | 1005 | open_file = find_writable_file(CIFS_I(mapping->host)); |
938 | read_lock(&GlobalSMBSeslock); | 1006 | if (open_file) { |
939 | /* BB we should start at the end */ | 1007 | bytes_written = cifs_write(open_file->pfile, write_data, |
940 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1008 | to-from, &offset); |
941 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1009 | atomic_dec(&open_file->wrtPending); |
942 | if (open_file->closePend) | ||
943 | continue; | ||
944 | /* We check if file is open for writing first */ | ||
945 | if ((open_file->pfile) && | ||
946 | ((open_file->pfile->f_flags & O_RDWR) || | ||
947 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
948 | read_unlock(&GlobalSMBSeslock); | ||
949 | bytes_written = cifs_write(open_file->pfile, | ||
950 | write_data, to-from, | ||
951 | &offset); | ||
952 | read_lock(&GlobalSMBSeslock); | ||
953 | /* Does mm or vfs already set times? */ | 1010 | /* Does mm or vfs already set times? */ |
954 | inode->i_atime = | 1011 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
955 | inode->i_mtime = current_fs_time(inode->i_sb); | 1012 | if ((bytes_written > 0) && (offset)) { |
956 | if ((bytes_written > 0) && (offset)) { | 1013 | rc = 0; |
957 | rc = 0; | 1014 | } else if (bytes_written < 0) { |
958 | } else if (bytes_written < 0) { | 1015 | if (rc != -EBADF) |
959 | if (rc == -EBADF) { | 1016 | rc = bytes_written; |
960 | /* have seen a case in which kernel seemed to | ||
961 | have closed/freed a file even with writes | ||
962 | active so we might as well see if there are | ||
963 | other file structs to try for the same | ||
964 | inode before giving up */ | ||
965 | continue; | ||
966 | } else | ||
967 | rc = bytes_written; | ||
968 | } | ||
969 | break; /* now that we found a valid file handle and | ||
970 | tried to write to it we are done, no sense | ||
971 | continuing to loop looking for another */ | ||
972 | } | ||
973 | if (tmp->next == NULL) { | ||
974 | cFYI(1, ("File instance %p removed", tmp)); | ||
975 | break; | ||
976 | } | 1017 | } |
977 | } | 1018 | } else { |
978 | read_unlock(&GlobalSMBSeslock); | ||
979 | if (open_file == NULL) { | ||
980 | cFYI(1, ("No writeable filehandles for inode")); | 1019 | cFYI(1, ("No writeable filehandles for inode")); |
981 | rc = -EIO; | 1020 | rc = -EIO; |
982 | } | 1021 | } |
@@ -985,20 +1024,207 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
985 | return rc; | 1024 | return rc; |
986 | } | 1025 | } |
987 | 1026 | ||
988 | #if 0 | 1027 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
989 | static int cifs_writepages(struct address_space *mapping, | 1028 | static int cifs_writepages(struct address_space *mapping, |
990 | struct writeback_control *wbc) | 1029 | struct writeback_control *wbc) |
991 | { | 1030 | { |
992 | int rc = -EFAULT; | 1031 | struct backing_dev_info *bdi = mapping->backing_dev_info; |
1032 | unsigned int bytes_to_write; | ||
1033 | unsigned int bytes_written; | ||
1034 | struct cifs_sb_info *cifs_sb; | ||
1035 | int done = 0; | ||
1036 | pgoff_t end = -1; | ||
1037 | pgoff_t index; | ||
1038 | int is_range = 0; | ||
1039 | struct kvec iov[32]; | ||
1040 | int len; | ||
1041 | int n_iov = 0; | ||
1042 | pgoff_t next; | ||
1043 | int nr_pages; | ||
1044 | __u64 offset = 0; | ||
1045 | struct cifsFileInfo *open_file; | ||
1046 | struct page *page; | ||
1047 | struct pagevec pvec; | ||
1048 | int rc = 0; | ||
1049 | int scanned = 0; | ||
993 | int xid; | 1050 | int xid; |
994 | 1051 | ||
1052 | cifs_sb = CIFS_SB(mapping->host->i_sb); | ||
1053 | |||
1054 | /* | ||
1055 | * If wsize is smaller that the page cache size, default to writing | ||
1056 | * one page at a time via cifs_writepage | ||
1057 | */ | ||
1058 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | ||
1059 | return generic_writepages(mapping, wbc); | ||
1060 | |||
1061 | /* BB FIXME we do not have code to sign across multiple buffers yet, | ||
1062 | so go to older writepage style write which we can sign if needed */ | ||
1063 | if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) | ||
1064 | if(cifs_sb->tcon->ses->server->secMode & | ||
1065 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
1066 | return generic_writepages(mapping, wbc); | ||
1067 | |||
1068 | /* | ||
1069 | * BB: Is this meaningful for a non-block-device file system? | ||
1070 | * If it is, we should test it again after we do I/O | ||
1071 | */ | ||
1072 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
1073 | wbc->encountered_congestion = 1; | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
995 | xid = GetXid(); | 1077 | xid = GetXid(); |
996 | 1078 | ||
997 | /* Find contiguous pages then iterate through repeating | 1079 | pagevec_init(&pvec, 0); |
998 | call 16K write then Setpageuptodate or if LARGE_WRITE_X | 1080 | if (wbc->sync_mode == WB_SYNC_NONE) |
999 | support then send larger writes via kevec so as to eliminate | 1081 | index = mapping->writeback_index; /* Start from prev offset */ |
1000 | a memcpy */ | 1082 | else { |
1083 | index = 0; | ||
1084 | scanned = 1; | ||
1085 | } | ||
1086 | if (wbc->start || wbc->end) { | ||
1087 | index = wbc->start >> PAGE_CACHE_SHIFT; | ||
1088 | end = wbc->end >> PAGE_CACHE_SHIFT; | ||
1089 | is_range = 1; | ||
1090 | scanned = 1; | ||
1091 | } | ||
1092 | retry: | ||
1093 | while (!done && (index <= end) && | ||
1094 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | ||
1095 | PAGECACHE_TAG_DIRTY, | ||
1096 | min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { | ||
1097 | int first; | ||
1098 | unsigned int i; | ||
1099 | |||
1100 | first = -1; | ||
1101 | next = 0; | ||
1102 | n_iov = 0; | ||
1103 | bytes_to_write = 0; | ||
1104 | |||
1105 | for (i = 0; i < nr_pages; i++) { | ||
1106 | page = pvec.pages[i]; | ||
1107 | /* | ||
1108 | * At this point we hold neither mapping->tree_lock nor | ||
1109 | * lock on the page itself: the page may be truncated or | ||
1110 | * invalidated (changing page->mapping to NULL), or even | ||
1111 | * swizzled back from swapper_space to tmpfs file | ||
1112 | * mapping | ||
1113 | */ | ||
1114 | |||
1115 | if (first < 0) | ||
1116 | lock_page(page); | ||
1117 | else if (TestSetPageLocked(page)) | ||
1118 | break; | ||
1119 | |||
1120 | if (unlikely(page->mapping != mapping)) { | ||
1121 | unlock_page(page); | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | if (unlikely(is_range) && (page->index > end)) { | ||
1126 | done = 1; | ||
1127 | unlock_page(page); | ||
1128 | break; | ||
1129 | } | ||
1130 | |||
1131 | if (next && (page->index != next)) { | ||
1132 | /* Not next consecutive page */ | ||
1133 | unlock_page(page); | ||
1134 | break; | ||
1135 | } | ||
1136 | |||
1137 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
1138 | wait_on_page_writeback(page); | ||
1139 | |||
1140 | if (PageWriteback(page) || | ||
1141 | !test_clear_page_dirty(page)) { | ||
1142 | unlock_page(page); | ||
1143 | break; | ||
1144 | } | ||
1145 | |||
1146 | if (page_offset(page) >= mapping->host->i_size) { | ||
1147 | done = 1; | ||
1148 | unlock_page(page); | ||
1149 | break; | ||
1150 | } | ||
1151 | |||
1152 | /* | ||
1153 | * BB can we get rid of this? pages are held by pvec | ||
1154 | */ | ||
1155 | page_cache_get(page); | ||
1156 | |||
1157 | len = min(mapping->host->i_size - page_offset(page), | ||
1158 | (loff_t)PAGE_CACHE_SIZE); | ||
1159 | |||
1160 | /* reserve iov[0] for the smb header */ | ||
1161 | n_iov++; | ||
1162 | iov[n_iov].iov_base = kmap(page); | ||
1163 | iov[n_iov].iov_len = len; | ||
1164 | bytes_to_write += len; | ||
1165 | |||
1166 | if (first < 0) { | ||
1167 | first = i; | ||
1168 | offset = page_offset(page); | ||
1169 | } | ||
1170 | next = page->index + 1; | ||
1171 | if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) | ||
1172 | break; | ||
1173 | } | ||
1174 | if (n_iov) { | ||
1175 | /* Search for a writable handle every time we call | ||
1176 | * CIFSSMBWrite2. We can't rely on the last handle | ||
1177 | * we used to still be valid | ||
1178 | */ | ||
1179 | open_file = find_writable_file(CIFS_I(mapping->host)); | ||
1180 | if (!open_file) { | ||
1181 | cERROR(1, ("No writable handles for inode")); | ||
1182 | rc = -EBADF; | ||
1183 | } else { | ||
1184 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, | ||
1185 | open_file->netfid, | ||
1186 | bytes_to_write, offset, | ||
1187 | &bytes_written, iov, n_iov, | ||
1188 | 1); | ||
1189 | atomic_dec(&open_file->wrtPending); | ||
1190 | if (rc || bytes_written < bytes_to_write) { | ||
1191 | cERROR(1,("Write2 ret %d, written = %d", | ||
1192 | rc, bytes_written)); | ||
1193 | /* BB what if continued retry is | ||
1194 | requested via mount flags? */ | ||
1195 | set_bit(AS_EIO, &mapping->flags); | ||
1196 | SetPageError(page); | ||
1197 | } else { | ||
1198 | cifs_stats_bytes_written(cifs_sb->tcon, | ||
1199 | bytes_written); | ||
1200 | } | ||
1201 | } | ||
1202 | for (i = 0; i < n_iov; i++) { | ||
1203 | page = pvec.pages[first + i]; | ||
1204 | kunmap(page); | ||
1205 | unlock_page(page); | ||
1206 | page_cache_release(page); | ||
1207 | } | ||
1208 | if ((wbc->nr_to_write -= n_iov) <= 0) | ||
1209 | done = 1; | ||
1210 | index = next; | ||
1211 | } | ||
1212 | pagevec_release(&pvec); | ||
1213 | } | ||
1214 | if (!scanned && !done) { | ||
1215 | /* | ||
1216 | * We hit the last page and there is more work to be done: wrap | ||
1217 | * back to the start of the file | ||
1218 | */ | ||
1219 | scanned = 1; | ||
1220 | index = 0; | ||
1221 | goto retry; | ||
1222 | } | ||
1223 | if (!is_range) | ||
1224 | mapping->writeback_index = index; | ||
1225 | |||
1001 | FreeXid(xid); | 1226 | FreeXid(xid); |
1227 | |||
1002 | return rc; | 1228 | return rc; |
1003 | } | 1229 | } |
1004 | #endif | 1230 | #endif |
@@ -1207,12 +1433,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1207 | if (rc != 0) | 1433 | if (rc != 0) |
1208 | break; | 1434 | break; |
1209 | } | 1435 | } |
1210 | |||
1211 | rc = CIFSSMBRead(xid, pTcon, | 1436 | rc = CIFSSMBRead(xid, pTcon, |
1212 | open_file->netfid, | 1437 | open_file->netfid, |
1213 | current_read_size, *poffset, | 1438 | current_read_size, *poffset, |
1214 | &bytes_read, &smb_read_data); | 1439 | &bytes_read, &smb_read_data); |
1215 | |||
1216 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1440 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
1217 | if (copy_to_user(current_offset, | 1441 | if (copy_to_user(current_offset, |
1218 | smb_read_data + 4 /* RFC1001 hdr */ | 1442 | smb_read_data + 4 /* RFC1001 hdr */ |
@@ -1235,12 +1459,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1235 | return rc; | 1459 | return rc; |
1236 | } | 1460 | } |
1237 | } else { | 1461 | } else { |
1238 | #ifdef CONFIG_CIFS_STATS | 1462 | cifs_stats_bytes_read(pTcon, bytes_read); |
1239 | atomic_inc(&pTcon->num_reads); | ||
1240 | spin_lock(&pTcon->stat_lock); | ||
1241 | pTcon->bytes_read += total_read; | ||
1242 | spin_unlock(&pTcon->stat_lock); | ||
1243 | #endif | ||
1244 | *poffset += bytes_read; | 1463 | *poffset += bytes_read; |
1245 | } | 1464 | } |
1246 | } | 1465 | } |
@@ -1280,6 +1499,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1280 | total_read += bytes_read, current_offset += bytes_read) { | 1499 | total_read += bytes_read, current_offset += bytes_read) { |
1281 | current_read_size = min_t(const int, read_size - total_read, | 1500 | current_read_size = min_t(const int, read_size - total_read, |
1282 | cifs_sb->rsize); | 1501 | cifs_sb->rsize); |
1502 | /* For windows me and 9x we do not want to request more | ||
1503 | than it negotiated since it will refuse the read then */ | ||
1504 | if((pTcon->ses) && | ||
1505 | !(pTcon->ses->capabilities & CAP_LARGE_FILES)) { | ||
1506 | current_read_size = min_t(const int, current_read_size, | ||
1507 | pTcon->ses->server->maxBuf - 128); | ||
1508 | } | ||
1283 | rc = -EAGAIN; | 1509 | rc = -EAGAIN; |
1284 | while (rc == -EAGAIN) { | 1510 | while (rc == -EAGAIN) { |
1285 | if ((open_file->invalidHandle) && | 1511 | if ((open_file->invalidHandle) && |
@@ -1289,11 +1515,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1289 | if (rc != 0) | 1515 | if (rc != 0) |
1290 | break; | 1516 | break; |
1291 | } | 1517 | } |
1292 | |||
1293 | rc = CIFSSMBRead(xid, pTcon, | 1518 | rc = CIFSSMBRead(xid, pTcon, |
1294 | open_file->netfid, | 1519 | open_file->netfid, |
1295 | current_read_size, *poffset, | 1520 | current_read_size, *poffset, |
1296 | &bytes_read, ¤t_offset); | 1521 | &bytes_read, ¤t_offset); |
1297 | } | 1522 | } |
1298 | if (rc || (bytes_read == 0)) { | 1523 | if (rc || (bytes_read == 0)) { |
1299 | if (total_read) { | 1524 | if (total_read) { |
@@ -1303,12 +1528,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1303 | return rc; | 1528 | return rc; |
1304 | } | 1529 | } |
1305 | } else { | 1530 | } else { |
1306 | #ifdef CONFIG_CIFS_STATS | 1531 | cifs_stats_bytes_read(pTcon, total_read); |
1307 | atomic_inc(&pTcon->num_reads); | ||
1308 | spin_lock(&pTcon->stat_lock); | ||
1309 | pTcon->bytes_read += total_read; | ||
1310 | spin_unlock(&pTcon->stat_lock); | ||
1311 | #endif | ||
1312 | *poffset += bytes_read; | 1532 | *poffset += bytes_read; |
1313 | } | 1533 | } |
1314 | } | 1534 | } |
@@ -1452,10 +1672,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1452 | } | 1672 | } |
1453 | 1673 | ||
1454 | rc = CIFSSMBRead(xid, pTcon, | 1674 | rc = CIFSSMBRead(xid, pTcon, |
1455 | open_file->netfid, | 1675 | open_file->netfid, |
1456 | read_size, offset, | 1676 | read_size, offset, |
1457 | &bytes_read, &smb_read_data); | 1677 | &bytes_read, &smb_read_data); |
1458 | /* BB need to check return code here */ | 1678 | |
1679 | /* BB more RC checks ? */ | ||
1459 | if (rc== -EAGAIN) { | 1680 | if (rc== -EAGAIN) { |
1460 | if (smb_read_data) { | 1681 | if (smb_read_data) { |
1461 | cifs_buf_release(smb_read_data); | 1682 | cifs_buf_release(smb_read_data); |
@@ -1480,12 +1701,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1480 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); | 1701 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); |
1481 | 1702 | ||
1482 | i += bytes_read >> PAGE_CACHE_SHIFT; | 1703 | i += bytes_read >> PAGE_CACHE_SHIFT; |
1483 | #ifdef CONFIG_CIFS_STATS | 1704 | cifs_stats_bytes_read(pTcon, bytes_read); |
1484 | atomic_inc(&pTcon->num_reads); | ||
1485 | spin_lock(&pTcon->stat_lock); | ||
1486 | pTcon->bytes_read += bytes_read; | ||
1487 | spin_unlock(&pTcon->stat_lock); | ||
1488 | #endif | ||
1489 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | 1705 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { |
1490 | i++; /* account for partial page */ | 1706 | i++; /* account for partial page */ |
1491 | 1707 | ||
@@ -1603,40 +1819,21 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
1603 | page caching in the current Linux kernel design */ | 1819 | page caching in the current Linux kernel design */ |
1604 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | 1820 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) |
1605 | { | 1821 | { |
1606 | struct list_head *tmp; | ||
1607 | struct list_head *tmp1; | ||
1608 | struct cifsFileInfo *open_file = NULL; | 1822 | struct cifsFileInfo *open_file = NULL; |
1609 | int rc = TRUE; | ||
1610 | 1823 | ||
1611 | if (cifsInode == NULL) | 1824 | if (cifsInode) |
1612 | return rc; | 1825 | open_file = find_writable_file(cifsInode); |
1613 | 1826 | ||
1614 | read_lock(&GlobalSMBSeslock); | 1827 | if(open_file) { |
1615 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1828 | /* there is not actually a write pending so let |
1616 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1829 | this handle go free and allow it to |
1617 | if (open_file == NULL) | 1830 | be closable if needed */ |
1618 | break; | 1831 | atomic_dec(&open_file->wrtPending); |
1619 | if (open_file->closePend) | 1832 | return 0; |
1620 | continue; | 1833 | } else |
1621 | /* We check if file is open for writing, | 1834 | return 1; |
1622 | BB we could supplement this with a check to see if file size | ||
1623 | changes have been flushed to server - ie inode metadata dirty */ | ||
1624 | if ((open_file->pfile) && | ||
1625 | ((open_file->pfile->f_flags & O_RDWR) || | ||
1626 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
1627 | rc = FALSE; | ||
1628 | break; | ||
1629 | } | ||
1630 | if (tmp->next == NULL) { | ||
1631 | cFYI(1, ("File instance %p removed", tmp)); | ||
1632 | break; | ||
1633 | } | ||
1634 | } | ||
1635 | read_unlock(&GlobalSMBSeslock); | ||
1636 | return rc; | ||
1637 | } | 1835 | } |
1638 | 1836 | ||
1639 | |||
1640 | static int cifs_prepare_write(struct file *file, struct page *page, | 1837 | static int cifs_prepare_write(struct file *file, struct page *page, |
1641 | unsigned from, unsigned to) | 1838 | unsigned from, unsigned to) |
1642 | { | 1839 | { |
@@ -1676,6 +1873,9 @@ struct address_space_operations cifs_addr_ops = { | |||
1676 | .readpage = cifs_readpage, | 1873 | .readpage = cifs_readpage, |
1677 | .readpages = cifs_readpages, | 1874 | .readpages = cifs_readpages, |
1678 | .writepage = cifs_writepage, | 1875 | .writepage = cifs_writepage, |
1876 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1877 | .writepages = cifs_writepages, | ||
1878 | #endif | ||
1679 | .prepare_write = cifs_prepare_write, | 1879 | .prepare_write = cifs_prepare_write, |
1680 | .commit_write = cifs_commit_write, | 1880 | .commit_write = cifs_commit_write, |
1681 | .set_page_dirty = __set_page_dirty_nobuffers, | 1881 | .set_page_dirty = __set_page_dirty_nobuffers, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8d336a900255..912d401600f6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
166 | inode->i_fop = &cifs_file_direct_ops; | 166 | inode->i_fop = &cifs_file_direct_ops; |
167 | else | 167 | else |
168 | inode->i_fop = &cifs_file_ops; | 168 | inode->i_fop = &cifs_file_ops; |
169 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
170 | inode->i_fop->lock = NULL; | ||
169 | inode->i_data.a_ops = &cifs_addr_ops; | 171 | inode->i_data.a_ops = &cifs_addr_ops; |
172 | /* check if server can support readpages */ | ||
173 | if(pTcon->ses->server->maxBuf < | ||
174 | 4096 + MAX_CIFS_HDR_SIZE) | ||
175 | inode->i_data.a_ops->readpages = NULL; | ||
170 | } else if (S_ISDIR(inode->i_mode)) { | 176 | } else if (S_ISDIR(inode->i_mode)) { |
171 | cFYI(1, (" Directory inode")); | 177 | cFYI(1, (" Directory inode")); |
172 | inode->i_op = &cifs_dir_inode_ops; | 178 | inode->i_op = &cifs_dir_inode_ops; |
@@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode, | |||
213 | pfindData = (FILE_ALL_INFO *)buf; | 219 | pfindData = (FILE_ALL_INFO *)buf; |
214 | /* could do find first instead but this returns more info */ | 220 | /* could do find first instead but this returns more info */ |
215 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, | 221 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, |
216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 222 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
217 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 223 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
224 | /* BB optimize code so we do not make the above call | ||
225 | when server claims no NT SMB support and the above call | ||
226 | failed at least once - set flag in tcon or mount */ | ||
227 | if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { | ||
228 | rc = SMBQueryInformation(xid, pTcon, search_path, | ||
229 | pfindData, cifs_sb->local_nls, | ||
230 | cifs_sb->mnt_cifs_flags & | ||
231 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
232 | } | ||
233 | |||
218 | } | 234 | } |
219 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 235 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ |
220 | if (rc) { | 236 | if (rc) { |
@@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode, | |||
320 | on dirs */ | 336 | on dirs */ |
321 | inode->i_mode = cifs_sb->mnt_dir_mode; | 337 | inode->i_mode = cifs_sb->mnt_dir_mode; |
322 | inode->i_mode |= S_IFDIR; | 338 | inode->i_mode |= S_IFDIR; |
339 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
340 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && | ||
341 | /* No need to le64 convert size of zero */ | ||
342 | (pfindData->EndOfFile == 0)) { | ||
343 | inode->i_mode = cifs_sb->mnt_file_mode; | ||
344 | inode->i_mode |= S_IFIFO; | ||
345 | /* BB Finish for SFU style symlinks and devies */ | ||
346 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
347 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ | ||
348 | |||
323 | } else { | 349 | } else { |
324 | inode->i_mode |= S_IFREG; | 350 | inode->i_mode |= S_IFREG; |
325 | /* treat the dos attribute of read-only as read-only | 351 | /* treat the dos attribute of read-only as read-only |
@@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
359 | inode->i_fop = &cifs_file_direct_ops; | 385 | inode->i_fop = &cifs_file_direct_ops; |
360 | else | 386 | else |
361 | inode->i_fop = &cifs_file_ops; | 387 | inode->i_fop = &cifs_file_ops; |
388 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
389 | inode->i_fop->lock = NULL; | ||
362 | inode->i_data.a_ops = &cifs_addr_ops; | 390 | inode->i_data.a_ops = &cifs_addr_ops; |
391 | if(pTcon->ses->server->maxBuf < | ||
392 | 4096 + MAX_CIFS_HDR_SIZE) | ||
393 | inode->i_data.a_ops->readpages = NULL; | ||
363 | } else if (S_ISDIR(inode->i_mode)) { | 394 | } else if (S_ISDIR(inode->i_mode)) { |
364 | cFYI(1, (" Directory inode ")); | 395 | cFYI(1, (" Directory inode ")); |
365 | inode->i_op = &cifs_dir_inode_ops; | 396 | inode->i_op = &cifs_dir_inode_ops; |
@@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
577 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 608 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
578 | inode->i_sb,xid); | 609 | inode->i_sb,xid); |
579 | 610 | ||
580 | direntry->d_op = &cifs_dentry_ops; | 611 | if (pTcon->nocase) |
612 | direntry->d_op = &cifs_ci_dentry_ops; | ||
613 | else | ||
614 | direntry->d_op = &cifs_dentry_ops; | ||
581 | d_instantiate(direntry, newinode); | 615 | d_instantiate(direntry, newinode); |
582 | if (direntry->d_inode) | 616 | if (direntry->d_inode) |
583 | direntry->d_inode->i_nlink = 2; | 617 | direntry->d_inode->i_nlink = 2; |
@@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
928 | struct cifsTconInfo *pTcon; | 962 | struct cifsTconInfo *pTcon; |
929 | char *full_path = NULL; | 963 | char *full_path = NULL; |
930 | int rc = -EACCES; | 964 | int rc = -EACCES; |
931 | int found = FALSE; | ||
932 | struct cifsFileInfo *open_file = NULL; | 965 | struct cifsFileInfo *open_file = NULL; |
933 | FILE_BASIC_INFO time_buf; | 966 | FILE_BASIC_INFO time_buf; |
934 | int set_time = FALSE; | 967 | int set_time = FALSE; |
@@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
936 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | 969 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; |
937 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | 970 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; |
938 | struct cifsInodeInfo *cifsInode; | 971 | struct cifsInodeInfo *cifsInode; |
939 | struct list_head *tmp; | ||
940 | 972 | ||
941 | xid = GetXid(); | 973 | xid = GetXid(); |
942 | 974 | ||
@@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
961 | filemap_fdatawait(direntry->d_inode->i_mapping); | 993 | filemap_fdatawait(direntry->d_inode->i_mapping); |
962 | 994 | ||
963 | if (attrs->ia_valid & ATTR_SIZE) { | 995 | if (attrs->ia_valid & ATTR_SIZE) { |
964 | read_lock(&GlobalSMBSeslock); | ||
965 | /* To avoid spurious oplock breaks from server, in the case of | 996 | /* To avoid spurious oplock breaks from server, in the case of |
966 | inodes that we already have open, avoid doing path based | 997 | inodes that we already have open, avoid doing path based |
967 | setting of file size if we can do it by handle. | 998 | setting of file size if we can do it by handle. |
@@ -969,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
969 | when the local oplock break takes longer to flush | 1000 | when the local oplock break takes longer to flush |
970 | writebehind data than the SMB timeout for the SetPathInfo | 1001 | writebehind data than the SMB timeout for the SetPathInfo |
971 | request would allow */ | 1002 | request would allow */ |
972 | list_for_each(tmp, &cifsInode->openFileList) { | 1003 | open_file = find_writable_file(cifsInode); |
973 | open_file = list_entry(tmp, struct cifsFileInfo, | 1004 | if (open_file) { |
974 | flist); | 1005 | __u16 nfid = open_file->netfid; |
975 | /* We check if file is open for writing first */ | 1006 | __u32 npid = open_file->pid; |
976 | if ((open_file->pfile) && | 1007 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, |
977 | ((open_file->pfile->f_flags & O_RDWR) || | 1008 | nfid, npid, FALSE); |
978 | (open_file->pfile->f_flags & O_WRONLY))) { | 1009 | atomic_dec(&open_file->wrtPending); |
979 | if (open_file->invalidHandle == FALSE) { | 1010 | cFYI(1,("SetFSize for attrs rc = %d", rc)); |
980 | /* we found a valid, writeable network | 1011 | if(rc == -EINVAL) { |
981 | file handle to use to try to set the | 1012 | int bytes_written; |
982 | file size */ | 1013 | rc = CIFSSMBWrite(xid, pTcon, |
983 | __u16 nfid = open_file->netfid; | 1014 | nfid, 0, attrs->ia_size, |
984 | __u32 npid = open_file->pid; | 1015 | &bytes_written, NULL, NULL, |
985 | read_unlock(&GlobalSMBSeslock); | 1016 | 1 /* 45 seconds */); |
986 | found = TRUE; | 1017 | cFYI(1,("Wrt seteof rc %d", rc)); |
987 | rc = CIFSSMBSetFileSize(xid, pTcon, | ||
988 | attrs->ia_size, nfid, npid, | ||
989 | FALSE); | ||
990 | cFYI(1, ("SetFileSize by handle " | ||
991 | "(setattrs) rc = %d", rc)); | ||
992 | /* Do not need reopen and retry on | ||
993 | EAGAIN since we will retry by | ||
994 | pathname below */ | ||
995 | |||
996 | /* now that we found one valid file | ||
997 | handle no sense continuing to loop | ||
998 | trying others, so break here */ | ||
999 | break; | ||
1000 | } | ||
1001 | } | 1018 | } |
1002 | } | 1019 | } |
1003 | if (found == FALSE) | ||
1004 | read_unlock(&GlobalSMBSeslock); | ||
1005 | |||
1006 | if (rc != 0) { | 1020 | if (rc != 0) { |
1007 | /* Set file size by pathname rather than by handle | 1021 | /* Set file size by pathname rather than by handle |
1008 | either because no valid, writeable file handle for | 1022 | either because no valid, writeable file handle for |
@@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1013 | cifs_sb->local_nls, | 1027 | cifs_sb->local_nls, |
1014 | cifs_sb->mnt_cifs_flags & | 1028 | cifs_sb->mnt_cifs_flags & |
1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1029 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1016 | cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | 1030 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); |
1031 | if(rc == -EINVAL) { | ||
1032 | __u16 netfid; | ||
1033 | int oplock = FALSE; | ||
1034 | |||
1035 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
1036 | FILE_OPEN, | ||
1037 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
1038 | CREATE_NOT_DIR, &netfid, &oplock, | ||
1039 | NULL, cifs_sb->local_nls, | ||
1040 | cifs_sb->mnt_cifs_flags & | ||
1041 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1042 | if (rc==0) { | ||
1043 | int bytes_written; | ||
1044 | rc = CIFSSMBWrite(xid, pTcon, | ||
1045 | netfid, 0, | ||
1046 | attrs->ia_size, | ||
1047 | &bytes_written, NULL, | ||
1048 | NULL, 1 /* 45 sec */); | ||
1049 | cFYI(1,("wrt seteof rc %d",rc)); | ||
1050 | CIFSSMBClose(xid, pTcon, netfid); | ||
1051 | } | ||
1052 | |||
1053 | } | ||
1017 | } | 1054 | } |
1018 | 1055 | ||
1019 | /* Server is ok setting allocation size implicitly - no need | 1056 | /* Server is ok setting allocation size implicitly - no need |
@@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1026 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); | 1063 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); |
1027 | cifs_truncate_page(direntry->d_inode->i_mapping, | 1064 | cifs_truncate_page(direntry->d_inode->i_mapping, |
1028 | direntry->d_inode->i_size); | 1065 | direntry->d_inode->i_size); |
1029 | } | 1066 | } else |
1067 | goto cifs_setattr_exit; | ||
1030 | } | 1068 | } |
1031 | if (attrs->ia_valid & ATTR_UID) { | 1069 | if (attrs->ia_valid & ATTR_UID) { |
1032 | cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | 1070 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); |
1033 | uid = attrs->ia_uid; | 1071 | uid = attrs->ia_uid; |
1034 | /* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||
1035 | } | 1072 | } |
1036 | if (attrs->ia_valid & ATTR_GID) { | 1073 | if (attrs->ia_valid & ATTR_GID) { |
1037 | cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | 1074 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); |
1038 | gid = attrs->ia_gid; | 1075 | gid = attrs->ia_gid; |
1039 | /* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||
1040 | } | 1076 | } |
1041 | 1077 | ||
1042 | time_buf.Attributes = 0; | 1078 | time_buf.Attributes = 0; |
1043 | if (attrs->ia_valid & ATTR_MODE) { | 1079 | if (attrs->ia_valid & ATTR_MODE) { |
1044 | cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | 1080 | cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); |
1045 | mode = attrs->ia_mode; | 1081 | mode = attrs->ia_mode; |
1046 | /* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||
1047 | } | 1082 | } |
1048 | 1083 | ||
1049 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 1084 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
@@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1083 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | 1118 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); |
1084 | } else | 1119 | } else |
1085 | time_buf.LastWriteTime = 0; | 1120 | time_buf.LastWriteTime = 0; |
1086 | 1121 | /* Do not set ctime explicitly unless other time | |
1087 | if (attrs->ia_valid & ATTR_CTIME) { | 1122 | stamps are changed explicitly (i.e. by utime() |
1123 | since we would then have a mix of client and | ||
1124 | server times */ | ||
1125 | |||
1126 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
1088 | set_time = TRUE; | 1127 | set_time = TRUE; |
1089 | cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | 1128 | /* Although Samba throws this field away |
1129 | it may be useful to Windows - but we do | ||
1130 | not want to set ctime unless some other | ||
1131 | timestamp is changing */ | ||
1132 | cFYI(1, ("CIFS - CTIME changed ")); | ||
1090 | time_buf.ChangeTime = | 1133 | time_buf.ChangeTime = |
1091 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | 1134 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); |
1092 | } else | 1135 | } else |
1093 | time_buf.ChangeTime = 0; | 1136 | time_buf.ChangeTime = 0; |
1094 | 1137 | ||
1095 | if (set_time || time_buf.Attributes) { | 1138 | if (set_time || time_buf.Attributes) { |
1096 | /* BB what if setting one attribute fails (such as size) but | ||
1097 | time setting works? */ | ||
1098 | time_buf.CreationTime = 0; /* do not change */ | 1139 | time_buf.CreationTime = 0; /* do not change */ |
1099 | /* In the future we should experiment - try setting timestamps | 1140 | /* In the future we should experiment - try setting timestamps |
1100 | via Handle (SetFileInfo) instead of by path */ | 1141 | via Handle (SetFileInfo) instead of by path */ |
@@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
1133 | &time_buf, cifs_sb->local_nls); */ | 1174 | &time_buf, cifs_sb->local_nls); */ |
1134 | } | 1175 | } |
1135 | } | 1176 | } |
1177 | /* Even if error on time set, no sense failing the call if | ||
1178 | the server would set the time to a reasonable value anyway, | ||
1179 | and this check ensures that we are not being called from | ||
1180 | sys_utimes in which case we ought to fail the call back to | ||
1181 | the user when the server rejects the call */ | ||
1182 | if((rc) && (attrs->ia_valid && | ||
1183 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | ||
1184 | rc = 0; | ||
1136 | } | 1185 | } |
1137 | 1186 | ||
1138 | /* do not need local check to inode_check_ok since the server does | 1187 | /* do not need local check to inode_check_ok since the server does |
1139 | that */ | 1188 | that */ |
1140 | if (!rc) | 1189 | if (!rc) |
1141 | rc = inode_setattr(direntry->d_inode, attrs); | 1190 | rc = inode_setattr(direntry->d_inode, attrs); |
1191 | cifs_setattr_exit: | ||
1142 | kfree(full_path); | 1192 | kfree(full_path); |
1143 | FreeXid(xid); | 1193 | FreeXid(xid); |
1144 | return rc; | 1194 | return rc; |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index ab925ef4f863..b43e071fe110 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
198 | ("Create symlink worked but get_inode_info failed with rc = %d ", | 198 | ("Create symlink worked but get_inode_info failed with rc = %d ", |
199 | rc)); | 199 | rc)); |
200 | } else { | 200 | } else { |
201 | direntry->d_op = &cifs_dentry_ops; | 201 | if (pTcon->nocase) |
202 | direntry->d_op = &cifs_ci_dentry_ops; | ||
203 | else | ||
204 | direntry->d_op = &cifs_dentry_ops; | ||
202 | d_instantiate(direntry, newinode); | 205 | d_instantiate(direntry, newinode); |
203 | } | 206 | } |
204 | } | 207 | } |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 20ae4153f791..eba1de917f2a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp; | |||
34 | extern mempool_t *cifs_req_poolp; | 34 | extern mempool_t *cifs_req_poolp; |
35 | extern struct task_struct * oplockThread; | 35 | extern struct task_struct * oplockThread; |
36 | 36 | ||
37 | static __u16 GlobalMid; /* multiplex id - rotating counter */ | ||
38 | |||
39 | /* The xid serves as a useful identifier for each incoming vfs request, | 37 | /* The xid serves as a useful identifier for each incoming vfs request, |
40 | in a similar way to the mid which is useful to track each sent smb, | 38 | in a similar way to the mid which is useful to track each sent smb, |
41 | and CurrentXid can also provide a running counter (although it | 39 | and CurrentXid can also provide a running counter (although it |
@@ -51,6 +49,8 @@ _GetXid(void) | |||
51 | GlobalTotalActiveXid++; | 49 | GlobalTotalActiveXid++; |
52 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) | 50 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) |
53 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ | 51 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ |
52 | if(GlobalTotalActiveXid > 65000) | ||
53 | cFYI(1,("warning: more than 65000 requests active")); | ||
54 | xid = GlobalCurrentXid++; | 54 | xid = GlobalCurrentXid++; |
55 | spin_unlock(&GlobalMid_Lock); | 55 | spin_unlock(&GlobalMid_Lock); |
56 | return xid; | 56 | return xid; |
@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free) | |||
218 | return; | 218 | return; |
219 | } | 219 | } |
220 | 220 | ||
221 | /* | ||
222 | Find a free multiplex id (SMB mid). Otherwise there could be | ||
223 | mid collisions which might cause problems, demultiplexing the | ||
224 | wrong response to this request. Multiplex ids could collide if | ||
225 | one of a series requests takes much longer than the others, or | ||
226 | if a very large number of long lived requests (byte range | ||
227 | locks or FindNotify requests) are pending. No more than | ||
228 | 64K-1 requests can be outstanding at one time. If no | ||
229 | mids are available, return zero. A future optimization | ||
230 | could make the combination of mids and uid the key we use | ||
231 | to demultiplex on (rather than mid alone). | ||
232 | In addition to the above check, the cifs demultiplex | ||
233 | code already used the command code as a secondary | ||
234 | check of the frame and if signing is negotiated the | ||
235 | response would be discarded if the mid were the same | ||
236 | but the signature was wrong. Since the mid is not put in the | ||
237 | pending queue until later (when it is about to be dispatched) | ||
238 | we do have to limit the number of outstanding requests | ||
239 | to somewhat less than 64K-1 although it is hard to imagine | ||
240 | so many threads being in the vfs at one time. | ||
241 | */ | ||
242 | __u16 GetNextMid(struct TCP_Server_Info *server) | ||
243 | { | ||
244 | __u16 mid = 0; | ||
245 | __u16 last_mid; | ||
246 | int collision; | ||
247 | |||
248 | if(server == NULL) | ||
249 | return mid; | ||
250 | |||
251 | spin_lock(&GlobalMid_Lock); | ||
252 | last_mid = server->CurrentMid; /* we do not want to loop forever */ | ||
253 | server->CurrentMid++; | ||
254 | /* This nested loop looks more expensive than it is. | ||
255 | In practice the list of pending requests is short, | ||
256 | fewer than 50, and the mids are likely to be unique | ||
257 | on the first pass through the loop unless some request | ||
258 | takes longer than the 64 thousand requests before it | ||
259 | (and it would also have to have been a request that | ||
260 | did not time out) */ | ||
261 | while(server->CurrentMid != last_mid) { | ||
262 | struct list_head *tmp; | ||
263 | struct mid_q_entry *mid_entry; | ||
264 | |||
265 | collision = 0; | ||
266 | if(server->CurrentMid == 0) | ||
267 | server->CurrentMid++; | ||
268 | |||
269 | list_for_each(tmp, &server->pending_mid_q) { | ||
270 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
271 | |||
272 | if ((mid_entry->mid == server->CurrentMid) && | ||
273 | (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | ||
274 | /* This mid is in use, try a different one */ | ||
275 | collision = 1; | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | if(collision == 0) { | ||
280 | mid = server->CurrentMid; | ||
281 | break; | ||
282 | } | ||
283 | server->CurrentMid++; | ||
284 | } | ||
285 | spin_unlock(&GlobalMid_Lock); | ||
286 | return mid; | ||
287 | } | ||
288 | |||
289 | /* NB: MID can not be set if treeCon not passed in, in that | ||
290 | case it is responsbility of caller to set the mid */ | ||
221 | void | 291 | void |
222 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | 292 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , |
223 | const struct cifsTconInfo *treeCon, int word_count | 293 | const struct cifsTconInfo *treeCon, int word_count |
@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
233 | (2 * word_count) + sizeof (struct smb_hdr) - | 303 | (2 * word_count) + sizeof (struct smb_hdr) - |
234 | 4 /* RFC 1001 length field does not count */ + | 304 | 4 /* RFC 1001 length field does not count */ + |
235 | 2 /* for bcc field itself */ ; | 305 | 2 /* for bcc field itself */ ; |
236 | /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */ | 306 | /* Note that this is the only network field that has to be converted |
307 | to big endian and it is done just before we send it */ | ||
237 | 308 | ||
238 | buffer->Protocol[0] = 0xFF; | 309 | buffer->Protocol[0] = 0xFF; |
239 | buffer->Protocol[1] = 'S'; | 310 | buffer->Protocol[1] = 'S'; |
@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
245 | buffer->Pid = cpu_to_le16((__u16)current->tgid); | 316 | buffer->Pid = cpu_to_le16((__u16)current->tgid); |
246 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); | 317 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); |
247 | spin_lock(&GlobalMid_Lock); | 318 | spin_lock(&GlobalMid_Lock); |
248 | GlobalMid++; | ||
249 | buffer->Mid = GlobalMid; | ||
250 | spin_unlock(&GlobalMid_Lock); | 319 | spin_unlock(&GlobalMid_Lock); |
251 | if (treeCon) { | 320 | if (treeCon) { |
252 | buffer->Tid = treeCon->tid; | 321 | buffer->Tid = treeCon->tid; |
@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
256 | if (treeCon->ses->capabilities & CAP_STATUS32) { | 325 | if (treeCon->ses->capabilities & CAP_STATUS32) { |
257 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; | 326 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; |
258 | } | 327 | } |
259 | 328 | /* Uid is not converted */ | |
260 | buffer->Uid = treeCon->ses->Suid; /* always in LE format */ | 329 | buffer->Uid = treeCon->ses->Suid; |
330 | buffer->Mid = GetNextMid(treeCon->ses->server); | ||
261 | if(multiuser_mount != 0) { | 331 | if(multiuser_mount != 0) { |
262 | /* For the multiuser case, there are few obvious technically */ | 332 | /* For the multiuser case, there are few obvious technically */ |
263 | /* possible mechanisms to match the local linux user (uid) */ | 333 | /* possible mechanisms to match the local linux user (uid) */ |
@@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
305 | } | 375 | } |
306 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) | 376 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) |
307 | buffer->Flags2 |= SMBFLG2_DFS; | 377 | buffer->Flags2 |= SMBFLG2_DFS; |
378 | if (treeCon->nocase) | ||
379 | buffer->Flags |= SMBFLG_CASELESS; | ||
308 | if((treeCon->ses) && (treeCon->ses->server)) | 380 | if((treeCon->ses) && (treeCon->ses->server)) |
309 | if(treeCon->ses->server->secMode & | 381 | if(treeCon->ses->server->secMode & |
310 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 382 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
@@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) | |||
347 | int | 419 | int |
348 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) | 420 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) |
349 | { | 421 | { |
350 | __u32 len = be32_to_cpu(smb->smb_buf_length); | 422 | __u32 len = smb->smb_buf_length; |
423 | __u32 clc_len; /* calculated length */ | ||
351 | cFYI(0, | 424 | cFYI(0, |
352 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", | 425 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", |
353 | length, len)); | 426 | length, len)); |
@@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
368 | cERROR(1, | 441 | cERROR(1, |
369 | ("smb_buf_length greater than MaxBufSize")); | 442 | ("smb_buf_length greater than MaxBufSize")); |
370 | cERROR(1, | 443 | cERROR(1, |
371 | ("bad smb detected. Illegal length. The mid=%d", | 444 | ("bad smb detected. Illegal length. mid=%d", |
372 | smb->Mid)); | 445 | smb->Mid)); |
373 | return 1; | 446 | return 1; |
374 | } | 447 | } |
375 | 448 | ||
376 | if (checkSMBhdr(smb, mid)) | 449 | if (checkSMBhdr(smb, mid)) |
377 | return 1; | 450 | return 1; |
378 | 451 | clc_len = smbCalcSize_LE(smb); | |
379 | if ((4 + len != smbCalcSize(smb)) | 452 | if ((4 + len != clc_len) |
380 | || (4 + len != (unsigned int)length)) { | 453 | || (4 + len != (unsigned int)length)) { |
381 | return 0; | 454 | cERROR(1, ("Calculated size 0x%x vs actual length 0x%x", |
382 | } else { | 455 | clc_len, 4 + len)); |
383 | cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); | 456 | cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); |
384 | cERROR(1, | 457 | /* Windows XP can return a few bytes too much, presumably |
385 | ("bad smb size detected. The Mid=%d", smb->Mid)); | 458 | an illegal pad, at the end of byte range lock responses |
386 | return 1; | 459 | so we allow for up to eight byte pad, as long as actual |
460 | received length is as long or longer than calculated length */ | ||
461 | if((4+len > clc_len) && (len <= clc_len + 3)) | ||
462 | return 0; | ||
463 | else | ||
464 | return 1; | ||
387 | } | 465 | } |
466 | return 0; | ||
388 | } | 467 | } |
389 | int | 468 | int |
390 | is_valid_oplock_break(struct smb_hdr *buf) | 469 | is_valid_oplock_break(struct smb_hdr *buf) |
@@ -448,9 +527,7 @@ is_valid_oplock_break(struct smb_hdr *buf) | |||
448 | list_for_each(tmp, &GlobalTreeConnectionList) { | 527 | list_for_each(tmp, &GlobalTreeConnectionList) { |
449 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 528 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
450 | if (tcon->tid == buf->Tid) { | 529 | if (tcon->tid == buf->Tid) { |
451 | #ifdef CONFIG_CIFS_STATS | 530 | cifs_stats_inc(&tcon->num_oplock_brks); |
452 | atomic_inc(&tcon->num_oplock_brks); | ||
453 | #endif | ||
454 | list_for_each(tmp1,&tcon->openFileList){ | 531 | list_for_each(tmp1,&tcon->openFileList){ |
455 | netfile = list_entry(tmp1,struct cifsFileInfo, | 532 | netfile = list_entry(tmp1,struct cifsFileInfo, |
456 | tlist); | 533 | tlist); |
@@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | |||
603 | int i,j,charlen; | 680 | int i,j,charlen; |
604 | int len_remaining = maxlen; | 681 | int len_remaining = maxlen; |
605 | char src_char; | 682 | char src_char; |
683 | __u16 temp; | ||
606 | 684 | ||
607 | if(!mapChars) | 685 | if(!mapChars) |
608 | return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); | 686 | return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); |
@@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | |||
639 | break;*/ | 717 | break;*/ |
640 | default: | 718 | default: |
641 | charlen = cp->char2uni(source+i, | 719 | charlen = cp->char2uni(source+i, |
642 | len_remaining, target+j); | 720 | len_remaining, &temp); |
643 | /* if no match, use question mark, which | 721 | /* if no match, use question mark, which |
644 | at least in some cases servers as wild card */ | 722 | at least in some cases servers as wild card */ |
645 | if(charlen < 1) { | 723 | if(charlen < 1) { |
646 | target[j] = cpu_to_le16(0x003f); | 724 | target[j] = cpu_to_le16(0x003f); |
647 | charlen = 1; | 725 | charlen = 1; |
648 | } | 726 | } else |
727 | target[j] = cpu_to_le16(temp); | ||
649 | len_remaining -= charlen; | 728 | len_remaining -= charlen; |
650 | /* character may take more than one byte in the | 729 | /* character may take more than one byte in the |
651 | the source string, but will take exactly two | 730 | the source string, but will take exactly two |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index a92af41d4411..f7814689844b 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | |||
133 | int | 133 | int |
134 | cifs_inet_pton(int address_family, char *cp,void *dst) | 134 | cifs_inet_pton(int address_family, char *cp,void *dst) |
135 | { | 135 | { |
136 | struct in_addr address; | ||
137 | int value; | 136 | int value; |
138 | int digit; | 137 | int digit; |
139 | int i; | 138 | int i; |
@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst) | |||
190 | if (value > addr_class_max[end - bytes]) | 189 | if (value > addr_class_max[end - bytes]) |
191 | return 0; | 190 | return 0; |
192 | 191 | ||
193 | address.s_addr = *((__be32 *) bytes) | htonl(value); | 192 | *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value); |
194 | *((__be32 *)dst) = address.s_addr; | ||
195 | return 1; /* success */ | 193 | return 1; /* success */ |
196 | } | 194 | } |
197 | 195 | ||
@@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) | |||
815 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { | 813 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { |
816 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ | 814 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ |
817 | __u32 err = le32_to_cpu(smb->Status.CifsError); | 815 | __u32 err = le32_to_cpu(smb->Status.CifsError); |
818 | if(cifsFYI) | 816 | if(cifsFYI & CIFS_RC) |
819 | cifs_print_status(err); | 817 | cifs_print_status(err); |
820 | ntstatus_to_dos(err, &smberrclass, &smberrcode); | 818 | ntstatus_to_dos(err, &smberrclass, &smberrcode); |
821 | } else { | 819 | } else { |
@@ -870,7 +868,14 @@ unsigned int | |||
870 | smbCalcSize(struct smb_hdr *ptr) | 868 | smbCalcSize(struct smb_hdr *ptr) |
871 | { | 869 | { |
872 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | 870 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + |
873 | BCC(ptr)); | 871 | 2 /* size of the bcc field */ + BCC(ptr)); |
872 | } | ||
873 | |||
874 | unsigned int | ||
875 | smbCalcSize_LE(struct smb_hdr *ptr) | ||
876 | { | ||
877 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | ||
878 | 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); | ||
874 | } | 879 | } |
875 | 880 | ||
876 | /* The following are taken from fs/ntfs/util.c */ | 881 | /* The following are taken from fs/ntfs/util.c */ |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 22557716f9af..a86bd1c07602 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
91 | } | 91 | } |
92 | 92 | ||
93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); | 93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); |
94 | tmp_dentry->d_op = &cifs_dentry_ops; | 94 | if (pTcon->nocase) |
95 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | ||
96 | else | ||
97 | tmp_dentry->d_op = &cifs_dentry_ops; | ||
95 | if(*ptmp_inode == NULL) | 98 | if(*ptmp_inode == NULL) |
96 | return rc; | 99 | return rc; |
97 | rc = 1; | 100 | rc = 1; |
@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
148 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; | 151 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; |
149 | } | 152 | } |
150 | tmp_inode->i_mode |= S_IFDIR; | 153 | tmp_inode->i_mode |= S_IFDIR; |
154 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
155 | (attr & ATTR_SYSTEM) && (end_of_file == 0)) { | ||
156 | *pobject_type = DT_FIFO; | ||
157 | tmp_inode->i_mode |= S_IFIFO; | ||
158 | /* BB Finish for SFU style symlinks and devies */ | ||
159 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
160 | (attr & ATTR_SYSTEM) && ) { */ | ||
151 | /* we no longer mark these because we could not follow them */ | 161 | /* we no longer mark these because we could not follow them */ |
152 | /* } else if (attr & ATTR_REPARSE) { | 162 | /* } else if (attr & ATTR_REPARSE) { |
153 | *pobject_type = DT_LNK; | 163 | *pobject_type = DT_LNK; |
@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
187 | tmp_inode->i_fop = &cifs_file_direct_ops; | 197 | tmp_inode->i_fop = &cifs_file_direct_ops; |
188 | else | 198 | else |
189 | tmp_inode->i_fop = &cifs_file_ops; | 199 | tmp_inode->i_fop = &cifs_file_ops; |
200 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
201 | tmp_inode->i_fop->lock = NULL; | ||
190 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 202 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
191 | 203 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | |
204 | (cifs_sb->tcon->ses->server->maxBuf < | ||
205 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
206 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
192 | if(isNewInode) | 207 | if(isNewInode) |
193 | return; /* No sense invalidating pages for new inode since we | 208 | return; /* No sense invalidating pages for new inode |
194 | have not started caching readahead file data yet */ | 209 | since have not started caching readahead file |
210 | data yet */ | ||
195 | 211 | ||
196 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | 212 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && |
197 | (local_size == tmp_inode->i_size)) { | 213 | (local_size == tmp_inode->i_size)) { |
@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
290 | tmp_inode->i_fop = &cifs_file_direct_ops; | 306 | tmp_inode->i_fop = &cifs_file_direct_ops; |
291 | else | 307 | else |
292 | tmp_inode->i_fop = &cifs_file_ops; | 308 | tmp_inode->i_fop = &cifs_file_ops; |
309 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
310 | tmp_inode->i_fop->lock = NULL; | ||
293 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 311 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
312 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
313 | (cifs_sb->tcon->ses->server->maxBuf < | ||
314 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
315 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
294 | 316 | ||
295 | if(isNewInode) | 317 | if(isNewInode) |
296 | return; /* No sense invalidating pages for new inode since we | 318 | return; /* No sense invalidating pages for new inode since we |
@@ -374,7 +396,8 @@ ffirst_retry: | |||
374 | 396 | ||
375 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | 397 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, |
376 | &cifsFile->netfid, &cifsFile->srch_inf, | 398 | &cifsFile->netfid, &cifsFile->srch_inf, |
377 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 399 | cifs_sb->mnt_cifs_flags & |
400 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | ||
378 | if(rc == 0) | 401 | if(rc == 0) |
379 | cifsFile->invalidHandle = FALSE; | 402 | cifsFile->invalidHandle = FALSE; |
380 | if((rc == -EOPNOTSUPP) && | 403 | if((rc == -EOPNOTSUPP) && |
@@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
491 | return rc; | 514 | return rc; |
492 | } | 515 | } |
493 | 516 | ||
517 | /* Check if directory that we are searching has changed so we can decide | ||
518 | whether we can use the cached search results from the previous search */ | ||
519 | static int is_dir_changed(struct file * file) | ||
520 | { | ||
521 | struct inode * inode; | ||
522 | struct cifsInodeInfo *cifsInfo; | ||
523 | |||
524 | if(file->f_dentry == NULL) | ||
525 | return 0; | ||
526 | |||
527 | inode = file->f_dentry->d_inode; | ||
528 | |||
529 | if(inode == NULL) | ||
530 | return 0; | ||
531 | |||
532 | cifsInfo = CIFS_I(inode); | ||
533 | |||
534 | if(cifsInfo->time == 0) | ||
535 | return 1; /* directory was changed, perhaps due to unlink */ | ||
536 | else | ||
537 | return 0; | ||
538 | |||
539 | } | ||
540 | |||
494 | /* find the corresponding entry in the search */ | 541 | /* find the corresponding entry in the search */ |
495 | /* Note that the SMB server returns search entries for . and .. which | 542 | /* Note that the SMB server returns search entries for . and .. which |
496 | complicates logic here if we choose to parse for them and we do not | 543 | complicates logic here if we choose to parse for them and we do not |
@@ -507,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
507 | struct cifsFileInfo * cifsFile = file->private_data; | 554 | struct cifsFileInfo * cifsFile = file->private_data; |
508 | /* check if index in the buffer */ | 555 | /* check if index in the buffer */ |
509 | 556 | ||
510 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) | 557 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || |
558 | (num_to_ret == NULL)) | ||
511 | return -ENOENT; | 559 | return -ENOENT; |
512 | 560 | ||
513 | *ppCurrentEntry = NULL; | 561 | *ppCurrentEntry = NULL; |
@@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
515 | cifsFile->srch_inf.index_of_last_entry - | 563 | cifsFile->srch_inf.index_of_last_entry - |
516 | cifsFile->srch_inf.entries_in_buffer; | 564 | cifsFile->srch_inf.entries_in_buffer; |
517 | /* dump_cifs_file_struct(file, "In fce ");*/ | 565 | /* dump_cifs_file_struct(file, "In fce ");*/ |
518 | if(index_to_find < first_entry_in_buffer) { | 566 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
567 | is_dir_changed(file)) || | ||
568 | (index_to_find < first_entry_in_buffer)) { | ||
519 | /* close and restart search */ | 569 | /* close and restart search */ |
520 | cFYI(1,("search backing up - close and restart search")); | 570 | cFYI(1,("search backing up - close and restart search")); |
521 | cifsFile->invalidHandle = TRUE; | 571 | cifsFile->invalidHandle = TRUE; |
@@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
536 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 586 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && |
537 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ | 587 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ |
538 | cFYI(1,("calling findnext2")); | 588 | cFYI(1,("calling findnext2")); |
539 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); | 589 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, |
590 | &cifsFile->srch_inf); | ||
540 | if(rc) | 591 | if(rc) |
541 | return -ENOENT; | 592 | return -ENOENT; |
542 | } | 593 | } |
@@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
548 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 599 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + |
549 | smbCalcSize((struct smb_hdr *) | 600 | smbCalcSize((struct smb_hdr *) |
550 | cifsFile->srch_inf.ntwrk_buf_start); | 601 | cifsFile->srch_inf.ntwrk_buf_start); |
551 | /* dump_cifs_file_struct(file,"found entry in fce "); */ | ||
552 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 602 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry |
553 | - cifsFile->srch_inf.entries_in_buffer; | 603 | - cifsFile->srch_inf.entries_in_buffer; |
554 | pos_in_buf = index_to_find - first_entry_in_buffer; | 604 | pos_in_buf = index_to_find - first_entry_in_buffer; |
555 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | 605 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); |
556 | current_entry = cifsFile->srch_inf.srch_entries_start; | 606 | current_entry = cifsFile->srch_inf.srch_entries_start; |
557 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | 607 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { |
558 | /* go entry to next entry figuring out which we need to start with */ | 608 | /* go entry by entry figuring out which is first */ |
559 | /* if( . or ..) | 609 | /* if( . or ..) |
560 | skip */ | 610 | skip */ |
561 | rc = cifs_entry_is_dot(current_entry,cifsFile); | 611 | rc = cifs_entry_is_dot(current_entry,cifsFile); |
@@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
582 | } | 632 | } |
583 | 633 | ||
584 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { | 634 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { |
585 | cFYI(1,("can not return entries when pos_in_buf beyond last entry")); | 635 | cFYI(1,("can not return entries pos_in_buf beyond last entry")); |
586 | *num_to_ret = 0; | 636 | *num_to_ret = 0; |
587 | } else | 637 | } else |
588 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; | 638 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; |
589 | /* dump_cifs_file_struct(file, "end fce ");*/ | ||
590 | 639 | ||
591 | return rc; | 640 | return rc; |
592 | } | 641 | } |
@@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
721 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); | 770 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); |
722 | } | 771 | } |
723 | 772 | ||
724 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); | 773 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, |
774 | tmp_inode->i_ino,obj_type); | ||
725 | if(rc) { | 775 | if(rc) { |
726 | cFYI(1,("filldir rc = %d",rc)); | 776 | cFYI(1,("filldir rc = %d",rc)); |
727 | } | 777 | } |
@@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
805 | FreeXid(xid); | 855 | FreeXid(xid); |
806 | return -EIO; | 856 | return -EIO; |
807 | } | 857 | } |
808 | /* dump_cifs_file_struct(file, "Begin rdir "); */ | ||
809 | 858 | ||
810 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 859 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
811 | pTcon = cifs_sb->tcon; | 860 | pTcon = cifs_sb->tcon; |
812 | if(pTcon == NULL) | 861 | if(pTcon == NULL) |
813 | return -EINVAL; | 862 | return -EINVAL; |
814 | 863 | ||
815 | /* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ | ||
816 | |||
817 | switch ((int) file->f_pos) { | 864 | switch ((int) file->f_pos) { |
818 | case 0: | 865 | case 0: |
819 | /*if (filldir(direntry, ".", 1, file->f_pos, | 866 | /*if (filldir(direntry, ".", 1, file->f_pos, |
@@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
866 | cifsFile->search_resume_name = NULL; */ | 913 | cifsFile->search_resume_name = NULL; */ |
867 | 914 | ||
868 | /* BB account for . and .. in f_pos as special case */ | 915 | /* BB account for . and .. in f_pos as special case */ |
869 | /* dump_cifs_file_struct(file, "rdir after default ");*/ | ||
870 | 916 | ||
871 | rc = find_cifs_entry(xid,pTcon, file, | 917 | rc = find_cifs_entry(xid,pTcon, file, |
872 | ¤t_entry,&num_to_fill); | 918 | ¤t_entry,&num_to_fill); |
@@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
906 | cifs_save_resume_key(current_entry,cifsFile); | 952 | cifs_save_resume_key(current_entry,cifsFile); |
907 | break; | 953 | break; |
908 | } else | 954 | } else |
909 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | 955 | current_entry = nxt_dir_entry(current_entry, |
956 | end_of_smb); | ||
910 | } | 957 | } |
911 | kfree(tmp_buf); | 958 | kfree(tmp_buf); |
912 | break; | 959 | break; |
913 | } /* end switch */ | 960 | } /* end switch */ |
914 | 961 | ||
915 | rddir2_exit: | 962 | rddir2_exit: |
916 | /* dump_cifs_file_struct(file, "end rdir "); */ | ||
917 | FreeXid(xid); | 963 | FreeXid(xid); |
918 | return rc; | 964 | return rc; |
919 | } | 965 | } |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0046c219833d..981ea0d8b9cd 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
49 | return NULL; | 49 | return NULL; |
50 | } | 50 | } |
51 | 51 | ||
52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); | 52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, |
53 | SLAB_KERNEL | SLAB_NOFS); | ||
53 | if (temp == NULL) | 54 | if (temp == NULL) |
54 | return temp; | 55 | return temp; |
55 | else { | 56 | else { |
@@ -58,7 +59,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
58 | temp->pid = current->pid; | 59 | temp->pid = current->pid; |
59 | temp->command = smb_buffer->Command; | 60 | temp->command = smb_buffer->Command; |
60 | cFYI(1, ("For smb_command %d", temp->command)); | 61 | cFYI(1, ("For smb_command %d", temp->command)); |
61 | do_gettimeofday(&temp->when_sent); | 62 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
63 | /* when mid allocated can be before when sent */ | ||
64 | temp->when_alloc = jiffies; | ||
62 | temp->ses = ses; | 65 | temp->ses = ses; |
63 | temp->tsk = current; | 66 | temp->tsk = current; |
64 | } | 67 | } |
@@ -74,6 +77,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
74 | static void | 77 | static void |
75 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 78 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
76 | { | 79 | { |
80 | #ifdef CONFIG_CIFS_STATS2 | ||
81 | unsigned long now; | ||
82 | #endif | ||
77 | spin_lock(&GlobalMid_Lock); | 83 | spin_lock(&GlobalMid_Lock); |
78 | midEntry->midState = MID_FREE; | 84 | midEntry->midState = MID_FREE; |
79 | list_del(&midEntry->qhead); | 85 | list_del(&midEntry->qhead); |
@@ -83,6 +89,22 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
83 | cifs_buf_release(midEntry->resp_buf); | 89 | cifs_buf_release(midEntry->resp_buf); |
84 | else | 90 | else |
85 | cifs_small_buf_release(midEntry->resp_buf); | 91 | cifs_small_buf_release(midEntry->resp_buf); |
92 | #ifdef CONFIG_CIFS_STATS2 | ||
93 | now = jiffies; | ||
94 | /* commands taking longer than one second are indications that | ||
95 | something is wrong, unless it is quite a slow link or server */ | ||
96 | if((now - midEntry->when_alloc) > HZ) { | ||
97 | if((cifsFYI & CIFS_TIMER) && | ||
98 | (midEntry->command != SMB_COM_LOCKING_ANDX)) { | ||
99 | printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d", | ||
100 | midEntry->command, midEntry->mid); | ||
101 | printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n", | ||
102 | now - midEntry->when_alloc, | ||
103 | now - midEntry->when_sent, | ||
104 | now - midEntry->when_received); | ||
105 | } | ||
106 | } | ||
107 | #endif | ||
86 | mempool_free(midEntry, cifs_mid_poolp); | 108 | mempool_free(midEntry, cifs_mid_poolp); |
87 | } | 109 | } |
88 | 110 | ||
@@ -146,32 +168,37 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
146 | Flags2 is converted in SendReceive */ | 168 | Flags2 is converted in SendReceive */ |
147 | 169 | ||
148 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 170 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
149 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 171 | cFYI(1, ("Sending smb of length %d", smb_buf_length)); |
150 | dump_smb(smb_buffer, len); | 172 | dump_smb(smb_buffer, len); |
151 | 173 | ||
152 | while (len > 0) { | 174 | while (len > 0) { |
153 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); | 175 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); |
154 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 176 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
155 | i++; | 177 | i++; |
156 | if(i > 60) { | 178 | /* smaller timeout here than send2 since smaller size */ |
179 | /* Although it may not be required, this also is smaller | ||
180 | oplock break time */ | ||
181 | if(i > 12) { | ||
157 | cERROR(1, | 182 | cERROR(1, |
158 | ("sends on sock %p stuck for 30 seconds", | 183 | ("sends on sock %p stuck for 7 seconds", |
159 | ssocket)); | 184 | ssocket)); |
160 | rc = -EAGAIN; | 185 | rc = -EAGAIN; |
161 | break; | 186 | break; |
162 | } | 187 | } |
163 | msleep(500); | 188 | msleep(1 << i); |
164 | continue; | 189 | continue; |
165 | } | 190 | } |
166 | if (rc < 0) | 191 | if (rc < 0) |
167 | break; | 192 | break; |
193 | else | ||
194 | i = 0; /* reset i after each successful send */ | ||
168 | iov.iov_base += rc; | 195 | iov.iov_base += rc; |
169 | iov.iov_len -= rc; | 196 | iov.iov_len -= rc; |
170 | len -= rc; | 197 | len -= rc; |
171 | } | 198 | } |
172 | 199 | ||
173 | if (rc < 0) { | 200 | if (rc < 0) { |
174 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 201 | cERROR(1,("Error %d sending data on socket to server", rc)); |
175 | } else { | 202 | } else { |
176 | rc = 0; | 203 | rc = 0; |
177 | } | 204 | } |
@@ -179,26 +206,21 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
179 | return rc; | 206 | return rc; |
180 | } | 207 | } |
181 | 208 | ||
182 | #ifdef CIFS_EXPERIMENTAL | 209 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
183 | /* BB finish off this function, adding support for writing set of pages as iovec */ | 210 | static int |
184 | /* and also adding support for operations that need to parse the response smb */ | 211 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, |
185 | 212 | struct sockaddr *sin) | |
186 | int | ||
187 | smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | ||
188 | unsigned int smb_buf_length, struct kvec * write_vector | ||
189 | /* page list */, struct sockaddr *sin) | ||
190 | { | 213 | { |
191 | int rc = 0; | 214 | int rc = 0; |
192 | int i = 0; | 215 | int i = 0; |
193 | struct msghdr smb_msg; | 216 | struct msghdr smb_msg; |
194 | number_of_pages += 1; /* account for SMB header */ | 217 | struct smb_hdr *smb_buffer = iov[0].iov_base; |
195 | struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); | 218 | unsigned int len = iov[0].iov_len; |
196 | unsigned len = smb_buf_length + 4; | 219 | unsigned int total_len; |
197 | 220 | int first_vec = 0; | |
221 | |||
198 | if(ssocket == NULL) | 222 | if(ssocket == NULL) |
199 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 223 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
200 | iov.iov_base = smb_buffer; | ||
201 | iov.iov_len = len; | ||
202 | 224 | ||
203 | smb_msg.msg_name = sin; | 225 | smb_msg.msg_name = sin; |
204 | smb_msg.msg_namelen = sizeof (struct sockaddr); | 226 | smb_msg.msg_namelen = sizeof (struct sockaddr); |
@@ -211,49 +233,80 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
211 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | 233 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send |
212 | Flags2 is converted in SendReceive */ | 234 | Flags2 is converted in SendReceive */ |
213 | 235 | ||
236 | |||
237 | total_len = 0; | ||
238 | for (i = 0; i < n_vec; i++) | ||
239 | total_len += iov[i].iov_len; | ||
240 | |||
214 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 241 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
215 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 242 | cFYI(1, ("Sending smb: total_len %d", total_len)); |
216 | dump_smb(smb_buffer, len); | 243 | dump_smb(smb_buffer, len); |
217 | 244 | ||
218 | while (len > 0) { | 245 | while (total_len) { |
219 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, | 246 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], |
220 | len); | 247 | n_vec - first_vec, total_len); |
221 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 248 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
222 | i++; | 249 | i++; |
223 | if(i > 60) { | 250 | if(i >= 14) { |
224 | cERROR(1, | 251 | cERROR(1, |
225 | ("sends on sock %p stuck for 30 seconds", | 252 | ("sends on sock %p stuck for 15 seconds", |
226 | ssocket)); | 253 | ssocket)); |
227 | rc = -EAGAIN; | 254 | rc = -EAGAIN; |
228 | break; | 255 | break; |
229 | } | 256 | } |
230 | msleep(500); | 257 | msleep(1 << i); |
231 | continue; | 258 | continue; |
232 | } | 259 | } |
233 | if (rc < 0) | 260 | if (rc < 0) |
234 | break; | 261 | break; |
235 | iov.iov_base += rc; | 262 | |
236 | iov.iov_len -= rc; | 263 | if (rc >= total_len) { |
237 | len -= rc; | 264 | WARN_ON(rc > total_len); |
265 | break; | ||
266 | } | ||
267 | if(rc == 0) { | ||
268 | /* should never happen, letting socket clear before | ||
269 | retrying is our only obvious option here */ | ||
270 | cERROR(1,("tcp sent no data")); | ||
271 | msleep(500); | ||
272 | continue; | ||
273 | } | ||
274 | total_len -= rc; | ||
275 | /* the line below resets i */ | ||
276 | for (i = first_vec; i < n_vec; i++) { | ||
277 | if (iov[i].iov_len) { | ||
278 | if (rc > iov[i].iov_len) { | ||
279 | rc -= iov[i].iov_len; | ||
280 | iov[i].iov_len = 0; | ||
281 | } else { | ||
282 | iov[i].iov_base += rc; | ||
283 | iov[i].iov_len -= rc; | ||
284 | first_vec = i; | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | i = 0; /* in case we get ENOSPC on the next send */ | ||
238 | } | 290 | } |
239 | 291 | ||
240 | if (rc < 0) { | 292 | if (rc < 0) { |
241 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 293 | cERROR(1,("Error %d sending data on socket to server", rc)); |
242 | } else { | 294 | } else |
243 | rc = 0; | 295 | rc = 0; |
244 | } | ||
245 | 296 | ||
246 | return rc; | 297 | return rc; |
247 | } | 298 | } |
248 | 299 | ||
249 | |||
250 | int | 300 | int |
251 | CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | 301 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
252 | struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) | 302 | struct kvec *iov, int n_vec, int *pbytes_returned, |
303 | const int long_op) | ||
253 | { | 304 | { |
254 | int rc = 0; | 305 | int rc = 0; |
255 | unsigned long timeout = 15 * HZ; | 306 | unsigned int receive_len; |
256 | struct mid_q_entry *midQ = NULL; | 307 | unsigned long timeout; |
308 | struct mid_q_entry *midQ; | ||
309 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
257 | 310 | ||
258 | if (ses == NULL) { | 311 | if (ses == NULL) { |
259 | cERROR(1,("Null smb session")); | 312 | cERROR(1,("Null smb session")); |
@@ -263,14 +316,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
263 | cERROR(1,("Null tcp session")); | 316 | cERROR(1,("Null tcp session")); |
264 | return -EIO; | 317 | return -EIO; |
265 | } | 318 | } |
266 | if(pbytes_returned == NULL) | ||
267 | return -EIO; | ||
268 | else | ||
269 | *pbytes_returned = 0; | ||
270 | 319 | ||
271 | 320 | if(ses->server->tcpStatus == CifsExiting) | |
272 | |||
273 | if(ses->server->tcpStatus == CIFS_EXITING) | ||
274 | return -ENOENT; | 321 | return -ENOENT; |
275 | 322 | ||
276 | /* Ensure that we do not send more than 50 overlapping requests | 323 | /* Ensure that we do not send more than 50 overlapping requests |
@@ -282,11 +329,18 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
282 | } else { | 329 | } else { |
283 | spin_lock(&GlobalMid_Lock); | 330 | spin_lock(&GlobalMid_Lock); |
284 | while(1) { | 331 | while(1) { |
285 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | 332 | if(atomic_read(&ses->server->inFlight) >= |
333 | cifs_max_pending){ | ||
286 | spin_unlock(&GlobalMid_Lock); | 334 | spin_unlock(&GlobalMid_Lock); |
335 | #ifdef CONFIG_CIFS_STATS2 | ||
336 | atomic_inc(&ses->server->num_waiters); | ||
337 | #endif | ||
287 | wait_event(ses->server->request_q, | 338 | wait_event(ses->server->request_q, |
288 | atomic_read(&ses->server->inFlight) | 339 | atomic_read(&ses->server->inFlight) |
289 | < cifs_max_pending); | 340 | < cifs_max_pending); |
341 | #ifdef CONFIG_CIFS_STATS2 | ||
342 | atomic_dec(&ses->server->num_waiters); | ||
343 | #endif | ||
290 | spin_lock(&GlobalMid_Lock); | 344 | spin_lock(&GlobalMid_Lock); |
291 | } else { | 345 | } else { |
292 | if(ses->server->tcpStatus == CifsExiting) { | 346 | if(ses->server->tcpStatus == CifsExiting) { |
@@ -314,17 +368,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
314 | 368 | ||
315 | if (ses->server->tcpStatus == CifsExiting) { | 369 | if (ses->server->tcpStatus == CifsExiting) { |
316 | rc = -ENOENT; | 370 | rc = -ENOENT; |
317 | goto cifs_out_label; | 371 | goto out_unlock2; |
318 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 372 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { |
319 | cFYI(1,("tcp session dead - return to caller to retry")); | 373 | cFYI(1,("tcp session dead - return to caller to retry")); |
320 | rc = -EAGAIN; | 374 | rc = -EAGAIN; |
321 | goto cifs_out_label; | 375 | goto out_unlock2; |
322 | } else if (ses->status != CifsGood) { | 376 | } else if (ses->status != CifsGood) { |
323 | /* check if SMB session is bad because we are setting it up */ | 377 | /* check if SMB session is bad because we are setting it up */ |
324 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 378 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
325 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | 379 | (in_buf->Command != SMB_COM_NEGOTIATE)) { |
326 | rc = -EAGAIN; | 380 | rc = -EAGAIN; |
327 | goto cifs_out_label; | 381 | goto out_unlock2; |
328 | } /* else ok - we are setting up session */ | 382 | } /* else ok - we are setting up session */ |
329 | } | 383 | } |
330 | midQ = AllocMidQEntry(in_buf, ses); | 384 | midQ = AllocMidQEntry(in_buf, ses); |
@@ -338,51 +392,162 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
338 | return -ENOMEM; | 392 | return -ENOMEM; |
339 | } | 393 | } |
340 | 394 | ||
341 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 395 | /* BB FIXME */ |
342 | up(&ses->server->tcpSem); | 396 | /* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ |
343 | cERROR(1, | 397 | |
344 | ("Illegal length, greater than maximum frame, %d ", | 398 | midQ->midState = MID_REQUEST_SUBMITTED; |
345 | in_buf->smb_buf_length)); | 399 | #ifdef CONFIG_CIFS_STATS2 |
400 | atomic_inc(&ses->server->inSend); | ||
401 | #endif | ||
402 | rc = smb_send2(ses->server->ssocket, iov, n_vec, | ||
403 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
404 | #ifdef CONFIG_CIFS_STATS2 | ||
405 | atomic_dec(&ses->server->inSend); | ||
406 | midQ->when_sent = jiffies; | ||
407 | #endif | ||
408 | if(rc < 0) { | ||
346 | DeleteMidQEntry(midQ); | 409 | DeleteMidQEntry(midQ); |
410 | up(&ses->server->tcpSem); | ||
347 | /* If not lock req, update # of requests on wire to server */ | 411 | /* If not lock req, update # of requests on wire to server */ |
348 | if(long_op < 3) { | 412 | if(long_op < 3) { |
349 | atomic_dec(&ses->server->inFlight); | 413 | atomic_dec(&ses->server->inFlight); |
350 | wake_up(&ses->server->request_q); | 414 | wake_up(&ses->server->request_q); |
351 | } | 415 | } |
352 | return -EIO; | 416 | return rc; |
417 | } else | ||
418 | up(&ses->server->tcpSem); | ||
419 | if (long_op == -1) | ||
420 | goto cifs_no_response_exit2; | ||
421 | else if (long_op == 2) /* writes past end of file can take loong time */ | ||
422 | timeout = 180 * HZ; | ||
423 | else if (long_op == 1) | ||
424 | timeout = 45 * HZ; /* should be greater than | ||
425 | servers oplock break timeout (about 43 seconds) */ | ||
426 | else if (long_op > 2) { | ||
427 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
428 | } else | ||
429 | timeout = 15 * HZ; | ||
430 | /* wait for 15 seconds or until woken up due to response arriving or | ||
431 | due to last connection to this server being unmounted */ | ||
432 | if (signal_pending(current)) { | ||
433 | /* if signal pending do not hold up user for full smb timeout | ||
434 | but we still give response a change to complete */ | ||
435 | timeout = 2 * HZ; | ||
436 | } | ||
437 | |||
438 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
439 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | ||
440 | timeout += jiffies; | ||
441 | wait_event(ses->server->response_q, | ||
442 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
443 | time_after(jiffies, timeout) || | ||
444 | ((ses->server->tcpStatus != CifsGood) && | ||
445 | (ses->server->tcpStatus != CifsNew))); | ||
446 | } else { | ||
447 | wait_event(ses->server->response_q, | ||
448 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
449 | ((ses->server->tcpStatus != CifsGood) && | ||
450 | (ses->server->tcpStatus != CifsNew))); | ||
353 | } | 451 | } |
354 | 452 | ||
355 | /* BB can we sign efficiently in this path? */ | 453 | spin_lock(&GlobalMid_Lock); |
356 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 454 | if (midQ->resp_buf) { |
455 | spin_unlock(&GlobalMid_Lock); | ||
456 | receive_len = midQ->resp_buf->smb_buf_length; | ||
457 | } else { | ||
458 | cERROR(1,("No response to cmd %d mid %d", | ||
459 | midQ->command, midQ->mid)); | ||
460 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
461 | if(ses->server->tcpStatus == CifsExiting) | ||
462 | rc = -EHOSTDOWN; | ||
463 | else { | ||
464 | ses->server->tcpStatus = CifsNeedReconnect; | ||
465 | midQ->midState = MID_RETRY_NEEDED; | ||
466 | } | ||
467 | } | ||
357 | 468 | ||
358 | midQ->midState = MID_REQUEST_SUBMITTED; | 469 | if (rc != -EHOSTDOWN) { |
359 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 470 | if(midQ->midState == MID_RETRY_NEEDED) { |
360 | piovec, | 471 | rc = -EAGAIN; |
361 | (struct sockaddr *) &(ses->server->addr.sockAddr));*/ | 472 | cFYI(1,("marking request for retry")); |
362 | if(rc < 0) { | 473 | } else { |
474 | rc = -EIO; | ||
475 | } | ||
476 | } | ||
477 | spin_unlock(&GlobalMid_Lock); | ||
363 | DeleteMidQEntry(midQ); | 478 | DeleteMidQEntry(midQ); |
364 | up(&ses->server->tcpSem); | ||
365 | /* If not lock req, update # of requests on wire to server */ | 479 | /* If not lock req, update # of requests on wire to server */ |
366 | if(long_op < 3) { | 480 | if(long_op < 3) { |
367 | atomic_dec(&ses->server->inFlight); | 481 | atomic_dec(&ses->server->inFlight); |
368 | wake_up(&ses->server->request_q); | 482 | wake_up(&ses->server->request_q); |
369 | } | 483 | } |
370 | return rc; | 484 | return rc; |
371 | } else | 485 | } |
372 | up(&ses->server->tcpSem); | 486 | |
373 | cifs_out_label: | 487 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
374 | if(midQ) | 488 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
375 | DeleteMidQEntry(midQ); | 489 | receive_len, xid)); |
376 | 490 | rc = -EIO; | |
491 | } else { /* rcvd frame is ok */ | ||
492 | |||
493 | if (midQ->resp_buf && | ||
494 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
495 | in_buf->smb_buf_length = receive_len; | ||
496 | /* BB verify that length would not overrun small buf */ | ||
497 | memcpy((char *)in_buf + 4, | ||
498 | (char *)midQ->resp_buf + 4, | ||
499 | receive_len); | ||
500 | |||
501 | dump_smb(in_buf, 80); | ||
502 | /* convert the length into a more usable form */ | ||
503 | if((receive_len > 24) && | ||
504 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
505 | SECMODE_SIGN_ENABLED))) { | ||
506 | rc = cifs_verify_signature(in_buf, | ||
507 | ses->server->mac_signing_key, | ||
508 | midQ->sequence_number+1); | ||
509 | if(rc) { | ||
510 | cERROR(1,("Unexpected SMB signature")); | ||
511 | /* BB FIXME add code to kill session */ | ||
512 | } | ||
513 | } | ||
514 | |||
515 | *pbytes_returned = in_buf->smb_buf_length; | ||
516 | |||
517 | /* BB special case reconnect tid and uid here? */ | ||
518 | rc = map_smb_to_linux_error(in_buf); | ||
519 | |||
520 | /* convert ByteCount if necessary */ | ||
521 | if (receive_len >= | ||
522 | sizeof (struct smb_hdr) - | ||
523 | 4 /* do not count RFC1001 header */ + | ||
524 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | ||
525 | BCC(in_buf) = le16_to_cpu(BCC(in_buf)); | ||
526 | } else { | ||
527 | rc = -EIO; | ||
528 | cFYI(1,("Bad MID state?")); | ||
529 | } | ||
530 | } | ||
531 | cifs_no_response_exit2: | ||
532 | DeleteMidQEntry(midQ); | ||
533 | |||
377 | if(long_op < 3) { | 534 | if(long_op < 3) { |
378 | atomic_dec(&ses->server->inFlight); | 535 | atomic_dec(&ses->server->inFlight); |
379 | wake_up(&ses->server->request_q); | 536 | wake_up(&ses->server->request_q); |
380 | } | 537 | } |
381 | 538 | ||
382 | return rc; | 539 | return rc; |
383 | } | ||
384 | 540 | ||
541 | out_unlock2: | ||
542 | up(&ses->server->tcpSem); | ||
543 | /* If not lock req, update # of requests on wire to server */ | ||
544 | if(long_op < 3) { | ||
545 | atomic_dec(&ses->server->inFlight); | ||
546 | wake_up(&ses->server->request_q); | ||
547 | } | ||
385 | 548 | ||
549 | return rc; | ||
550 | } | ||
386 | #endif /* CIFS_EXPERIMENTAL */ | 551 | #endif /* CIFS_EXPERIMENTAL */ |
387 | 552 | ||
388 | int | 553 | int |
@@ -419,9 +584,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
419 | if(atomic_read(&ses->server->inFlight) >= | 584 | if(atomic_read(&ses->server->inFlight) >= |
420 | cifs_max_pending){ | 585 | cifs_max_pending){ |
421 | spin_unlock(&GlobalMid_Lock); | 586 | spin_unlock(&GlobalMid_Lock); |
587 | #ifdef CONFIG_CIFS_STATS2 | ||
588 | atomic_inc(&ses->server->num_waiters); | ||
589 | #endif | ||
422 | wait_event(ses->server->request_q, | 590 | wait_event(ses->server->request_q, |
423 | atomic_read(&ses->server->inFlight) | 591 | atomic_read(&ses->server->inFlight) |
424 | < cifs_max_pending); | 592 | < cifs_max_pending); |
593 | #ifdef CONFIG_CIFS_STATS2 | ||
594 | atomic_dec(&ses->server->num_waiters); | ||
595 | #endif | ||
425 | spin_lock(&GlobalMid_Lock); | 596 | spin_lock(&GlobalMid_Lock); |
426 | } else { | 597 | } else { |
427 | if(ses->server->tcpStatus == CifsExiting) { | 598 | if(ses->server->tcpStatus == CifsExiting) { |
@@ -490,8 +661,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
490 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 661 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
491 | 662 | ||
492 | midQ->midState = MID_REQUEST_SUBMITTED; | 663 | midQ->midState = MID_REQUEST_SUBMITTED; |
664 | #ifdef CONFIG_CIFS_STATS2 | ||
665 | atomic_inc(&ses->server->inSend); | ||
666 | #endif | ||
493 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 667 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
494 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 668 | (struct sockaddr *) &(ses->server->addr.sockAddr)); |
669 | #ifdef CONFIG_CIFS_STATS2 | ||
670 | atomic_dec(&ses->server->inSend); | ||
671 | midQ->when_sent = jiffies; | ||
672 | #endif | ||
495 | if(rc < 0) { | 673 | if(rc < 0) { |
496 | DeleteMidQEntry(midQ); | 674 | DeleteMidQEntry(midQ); |
497 | up(&ses->server->tcpSem); | 675 | up(&ses->server->tcpSem); |
@@ -506,7 +684,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
506 | if (long_op == -1) | 684 | if (long_op == -1) |
507 | goto cifs_no_response_exit; | 685 | goto cifs_no_response_exit; |
508 | else if (long_op == 2) /* writes past end of file can take loong time */ | 686 | else if (long_op == 2) /* writes past end of file can take loong time */ |
509 | timeout = 300 * HZ; | 687 | timeout = 180 * HZ; |
510 | else if (long_op == 1) | 688 | else if (long_op == 1) |
511 | timeout = 45 * HZ; /* should be greater than | 689 | timeout = 45 * HZ; /* should be greater than |
512 | servers oplock break timeout (about 43 seconds) */ | 690 | servers oplock break timeout (about 43 seconds) */ |
@@ -540,9 +718,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
540 | spin_lock(&GlobalMid_Lock); | 718 | spin_lock(&GlobalMid_Lock); |
541 | if (midQ->resp_buf) { | 719 | if (midQ->resp_buf) { |
542 | spin_unlock(&GlobalMid_Lock); | 720 | spin_unlock(&GlobalMid_Lock); |
543 | receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); | 721 | receive_len = midQ->resp_buf->smb_buf_length; |
544 | } else { | 722 | } else { |
545 | cERROR(1,("No response buffer")); | 723 | cERROR(1,("No response for cmd %d mid %d", |
724 | midQ->command, midQ->mid)); | ||
546 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | 725 | if(midQ->midState == MID_REQUEST_SUBMITTED) { |
547 | if(ses->server->tcpStatus == CifsExiting) | 726 | if(ses->server->tcpStatus == CifsExiting) |
548 | rc = -EHOSTDOWN; | 727 | rc = -EHOSTDOWN; |
@@ -610,7 +789,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
610 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); | 789 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); |
611 | } else { | 790 | } else { |
612 | rc = -EIO; | 791 | rc = -EIO; |
613 | cFYI(1,("Bad MID state? ")); | 792 | cERROR(1,("Bad MID state? ")); |
614 | } | 793 | } |
615 | } | 794 | } |
616 | cifs_no_response_exit: | 795 | cifs_no_response_exit: |