Commit fca324e7 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6

parents 1d373741 7f285701
...@@ -32,6 +32,10 @@ Domen Puncer ...@@ -32,6 +32,10 @@ Domen Puncer
Jesper Juhl (in particular for lots of whitespace/formatting cleanup) Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
Vince Negri and Dave Stahl (for finding an important caching bug) Vince Negri and Dave Stahl (for finding an important caching bug)
Adrian Bunk (kcalloc cleanups) Adrian Bunk (kcalloc cleanups)
Miklos Szeredi
Kazeon team for various fixes especially for 2.4 version.
Asser Ferno (Change Notify support)
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
Test case and Bug Report contributors Test case and Bug Report contributors
------------------------------------- -------------------------------------
......
Version 1.39
------------
Defer close of a file handle slightly if pending writes depend on that file handle
(this reduces the EBADF bad file handle errors that can be logged under heavy
stress on writes).
Version 1.38
------------
Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
to be smaller at first (but increasing) so large write performance performance
over GigE is better. Do not hang thread on illegal byte range lock response
from Windows (Windows can send an RFC1001 size which does not match smb size) by
allowing an SMBs TCP length to be up to a few bytes longer than it should be.
wsize and rsize can now be larger than negotiated buffer size if server
supports large readx/writex, even when directio mount flag not specified.
Write size will in many cases now be 16K instead of 4K which greatly helps
file copy performance on lightly loaded networks. Fix oops in dnotify
when experimental config flag enabled. Make cifsFYI more granular.
Version 1.37
------------
Fix readdir caching when unlink removes file in current search buffer,
and this is followed by a rewind search to just before the deleted entry.
Do not attempt to set ctime unless atime and/or mtime change requested
(most servers throw it away anyway). Fix length check of received smbs
to be more accurate. Fix big endian problem with mapchars mount option,
and with a field returned by statfs.
Version 1.36
------------
Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
For these older servers, add option for passing netbios name of server in
on mount (servernetbiosname). Add suspend support for power management, to
avoid cifsd thread preventing software suspend from working.
Add mount option for disabling the default behavior of sending byte range lock
requests to the server (necessary for certain applications which break with
mandatory lock behavior such as Evolution), and also mount option for
requesting case insensitive matching for path based requests (requesting
case sensitive is the default).
Version 1.35 Version 1.35
------------ ------------
Add writepage performance improvements. Fix path name conversions Add writepage performance improvements. Fix path name conversions
for long filenames on mounts which were done with "mapchars" mount option for long filenames on mounts which were done with "mapchars" mount option
specified. specified. Ensure multiplex ids do not collide. Fix case in which
rmmod can oops if done soon after last unmount. Fix truncated
search (readdir) output when resume filename was a long filename.
Fix filename conversion when mapchars mount option was specified and
filename was a long filename.
Version 1.34 Version 1.34
------------ ------------
...@@ -11,7 +55,7 @@ Do not oops if root user kills cifs oplock kernel thread or ...@@ -11,7 +55,7 @@ Do not oops if root user kills cifs oplock kernel thread or
kills the cifsd thread (NB: killing the cifs kernel threads is not kills the cifsd thread (NB: killing the cifs kernel threads is not
recommended, unmount and rmmod cifs will kill them when they are recommended, unmount and rmmod cifs will kill them when they are
no longer needed). Fix readdir to ASCII servers (ie older servers no longer needed). Fix readdir to ASCII servers (ie older servers
which do not support Unicode) and also require asterik. which do not support Unicode) and also require asterisk.
Fix out of memory case in which data could be written one page Fix out of memory case in which data could be written one page
off in the page cache. off in the page cache.
...@@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call. ...@@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
Version 1.25 Version 1.25
------------ ------------
Fix internationlization problem in cifs readdir with filenames that map to Fix internationalization problem in cifs readdir with filenames that map to
longer UTF8 strings than the string on the wire was in Unicode. Add workaround longer UTF8 strings than the string on the wire was in Unicode. Add workaround
for readdir to netapp servers. Fix search rewind (seek into readdir to return for readdir to netapp servers. Fix search rewind (seek into readdir to return
non-consecutive entries). Do not do readdir when server negotiates 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,7 +320,7 @@ Fix caching problem when files opened by multiple clients in which
page cache could contain stale data, and write through did page cache could contain stale data, and write through did
not occur often enough while file was still open when read ahead not occur often enough while file was still open when read ahead
(read oplock) not allowed. Treat "sep=" when first mount option (read oplock) not allowed. Treat "sep=" when first mount option
as an overrride of comma as the default separator between mount as an override of comma as the default separator between mount
options. options.
Version 1.01 Version 1.01
...@@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string. ...@@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string.
Version 1.00 Version 1.00
------------ ------------
Gracefully clean up failed mounts when attempting to mount to servers such as Gracefully clean up failed mounts when attempting to mount to servers such as
Windows 98 that terminate tcp sessions during prototocol negotiation. Handle Windows 98 that terminate tcp sessions during protocol negotiation. Handle
embedded commas in mount parsing of passwords. embedded commas in mount parsing of passwords.
Version 0.99 Version 0.99
...@@ -295,7 +339,7 @@ Invalidate local inode cached pages on oplock break and when last file ...@@ -295,7 +339,7 @@ Invalidate local inode cached pages on oplock break and when last file
instance is closed so that the client does not continue using stale local instance is closed so that the client does not continue using stale local
copy rather than later modified server copy of file. Do not reconnect copy rather than later modified server copy of file. Do not reconnect
when server drops the tcp session prematurely before negotiate when server drops the tcp session prematurely before negotiate
protocol response. Fix oops in roepen_file when dentry freed. Allow protocol response. Fix oops in reopen_file when dentry freed. Allow
the support for CIFS Unix Extensions to be disabled via proc interface. the support for CIFS Unix Extensions to be disabled via proc interface.
Version 0.98 Version 0.98
...@@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early ...@@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early
Version 0.41 Version 0.41
------------ ------------
Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked
files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. files now return the correct number of links on fstat as they are repeatedly linked and unlinked.
Version 0.40 Version 0.40
------------ ------------
...@@ -704,7 +748,7 @@ session) ...@@ -704,7 +748,7 @@ session)
and cleaned them up and made them more consistent with other cifs functions. and cleaned them up and made them more consistent with other cifs functions.
7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways
(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, (with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
nor is the symlink support using the Unix extensions nor is the symlink support using the Unix extensions
8) Started adding the readlink and follow_link code 8) Started adding the readlink and follow_link code
......
...@@ -294,8 +294,10 @@ A partial list of the supported mount options follows: ...@@ -294,8 +294,10 @@ A partial list of the supported mount options follows:
during the local client kernel build will be used. during the local client kernel build will be used.
If server does not support Unicode, this parameter is If server does not support Unicode, this parameter is
unused. unused.
rsize default read size rsize default read size (usually 16K)
wsize default write size wsize default write size (usually 16K, 32K is often better over GigE)
maximum wsize currently allowed by CIFS is 57344 (14 4096 byte
pages)
rw mount the network share read-write (note that the rw mount the network share read-write (note that the
server may still consider the share read-only) server may still consider the share read-only)
ro mount network share read-only ro mount network share read-only
...@@ -407,6 +409,13 @@ A partial list of the supported mount options follows: ...@@ -407,6 +409,13 @@ A partial list of the supported mount options follows:
This has no effect if the server does not support This has no effect if the server does not support
Unicode on the wire. Unicode on the wire.
nomapchars Do not translate any of these seven characters (default). nomapchars Do not translate any of these seven characters (default).
nocase Request case insensitive path name matching (case
sensitive is the default if the server suports it).
nobrl Do not send byte range lock requests to the server.
This is necessary for certain applications that break
with cifs style mandatory byte range locks (and most
cifs servers do not yet support requesting advisory
byte range locks).
remount remount the share (often used to change from ro to rw mounts remount remount the share (often used to change from ro to rw mounts
or vice versa) or vice versa)
...@@ -473,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in ...@@ -473,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in
kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable
tracing to the kernel message log type: tracing to the kernel message log type:
echo 1 > /proc/fs/cifs/cifsFYI echo 7 > /proc/fs/cifs/cifsFYI
and for more extensive tracing including the start of smb requests and responses cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
logging of various informational messages. 2 enables logging of non-zero
SMB return codes while 4 enables logging of requests that take longer
than one second to complete (except for byte range lock requests).
Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
source code (typically by setting it in the beginning of cifsglob.h),
and setting it to seven enables all three. Finally, tracing
the start of smb requests and responses can be enabled via:
echo 1 > /proc/fs/cifs/traceSMB echo 1 > /proc/fs/cifs/traceSMB
......
version 1.34 April 29, 2005 version 1.37 October 9, 2005
A Partial List of Missing Features A Partial List of Missing Features
================================== ==================================
...@@ -7,14 +7,14 @@ Contributions are welcome. There are plenty of opportunities ...@@ -7,14 +7,14 @@ Contributions are welcome. There are plenty of opportunities
for visible, important contributions to this module. Here for visible, important contributions to this module. Here
is a partial list of the known problems and missing features: is a partial list of the known problems and missing features:
a) Support for SecurityDescriptors for chmod/chgrp/chown so a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
these can be supported for Windows servers so that these operations can be supported to Windows servers
b) Better pam/winbind integration (e.g. to handle uid mapping b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
better) SecurityDescriptors
c) multi-user mounts - multiplexed sessionsetups over single vc c) Better pam/winbind integration (e.g. to handle uid mapping
(ie tcp session) - more testing needed better)
d) Kerberos/SPNEGO session setup support - (started) d) Kerberos/SPNEGO session setup support - (started)
...@@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than ...@@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than
using FindNotify or equivalent. - (started) using FindNotify or equivalent. - (started)
g) A few byte range testcases fail due to POSIX vs. Windows/CIFS g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
style byte range lock differences style byte range lock differences. Save byte range locks so
reconnect can replay them.
h) quota support h) Support unlock all (unlock 0,MAX_OFFSET)
by unlocking all known byte range locks that we locked on the file.
j) finish writepages support (multi-page write behind for improved i) quota support (needs minor kernel change since quota calls
performance) and syncpage to make it to network filesystems or deviceless filesystems)
j) investigate sync behavior (including syncpage) and check
for proper behavior of intr/nointr
k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases. 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,20 +62,18 @@ p) Add support for storing symlink and fifo info to Windows servers
in the Extended Attribute format their SFU clients would recognize. in the Extended Attribute format their SFU clients would recognize.
q) Finish fcntl D_NOTIFY support so kde and gnome file list windows q) Finish fcntl D_NOTIFY support so kde and gnome file list windows
will autorefresh (started) will autorefresh (partially complete by Asser). Needs minor kernel
vfs change to support removing D_NOTIFY on a file.
r) Add GUI tool to configure /proc/fs/cifs settings and for display of r) Add GUI tool to configure /proc/fs/cifs settings and for display of
the CIFS statistics (started) the CIFS statistics (started)
q) implement support for security and trusted categories of xattrs s) implement support for security and trusted categories of xattrs
(requires minor protocol extension) to enable better support for SELINUX (requires minor protocol extension) to enable better support for SELINUX
r) Implement O_DIRECT flag on open (already supported on mount) t) Implement O_DIRECT flag on open (already supported on mount)
s) Allow remapping of last remaining character (\) to +0xF000 which
(this character is valid for POSIX but not for Windows)
t) Create UID mapping facility so server UIDs can be mapped on a per u) Create UID mapping facility so server UIDs can be mapped on a per
mount or a per server basis to client UIDs or nobody if no mapping mount or a per server basis to client UIDs or nobody if no mapping
exists. This is helpful when Unix extensions are negotiated to exists. This is helpful when Unix extensions are negotiated to
allow better permission checking when UIDs differ on the server 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,6 +81,17 @@ and client. Add new protocol request to the CIFS protocol
standard for asking the server for the corresponding name of a standard for asking the server for the corresponding name of a
particular uid. particular uid.
v) Add support for CIFS Unix and also the newer POSIX extensions to the
server side for Samba 4.
w) Finish up the dos time conversion routines needed to return old server
time to the client (default time, of now or time 0 is used now for these
very old servers)
x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
y) Finish testing of Windows 9x/Windows ME server support (started).
KNOWN BUGS (updated April 29, 2005) KNOWN BUGS (updated April 29, 2005)
==================================== ====================================
See http://bugzilla.samba.org - search on product "CifsVFS" for See http://bugzilla.samba.org - search on product "CifsVFS" for
......
...@@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx, ...@@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx,
unsigned char **eoc, unsigned char **eoc,
unsigned int *cls, unsigned int *con, unsigned int *tag) unsigned int *cls, unsigned int *con, unsigned int *tag)
{ {
unsigned int def, len; unsigned int def = 0;
unsigned int len = 0;
if (!asn1_id_decode(ctx, cls, con, tag)) if (!asn1_id_decode(ctx, cls, con, tag))
return 0; return 0;
......
...@@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length; buf += length;
length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
buf += length; buf += length;
length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid);
buf += length;
length = sprintf(buf, "Servers:"); length = sprintf(buf, "Servers:");
buf += length; buf += length;
...@@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
} else { } else {
length = length =
sprintf(buf, sprintf(buf,
"\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", "\n%d) Name: %s Domain: %s Mounts: %d OS: %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t",
i, ses->serverName, ses->serverDomain, i, ses->serverName, ses->serverDomain,
atomic_read(&ses->inUse), atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->serverOS, ses->serverNOS,
...@@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length; buf += length;
} }
if(ses->server) { if(ses->server) {
buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d",
ses->server->tcpStatus, ses->server->tcpStatus,
atomic_read(&ses->server->socketUseCount), atomic_read(&ses->server->socketUseCount),
ses->server->secMode, ses->server->secMode,
atomic_read(&ses->server->inFlight)); atomic_read(&ses->server->inFlight));
#ifdef CONFIG_CIFS_STATS2
buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d",
atomic_read(&ses->server->inSend),
atomic_read(&ses->server->num_waiters));
#endif
length = sprintf(buf, "\nMIDs:\n"); length = sprintf(buf, "\nMIDs:\n");
buf += length; buf += length;
...@@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
length = length =
sprintf(buf, sprintf(buf,
"\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
i, tcon->treeName, i, tcon->treeName,
atomic_read(&tcon->useCount), atomic_read(&tcon->useCount),
tcon->nativeFileSystem, tcon->nativeFileSystem,
...@@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
} }
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
static int
cifs_stats_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
int rc;
struct list_head *tmp;
struct cifsTconInfo *tcon;
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo,
cifsConnectionList);
atomic_set(&tcon->num_smbs_sent, 0);
atomic_set(&tcon->num_writes, 0);
atomic_set(&tcon->num_reads, 0);
atomic_set(&tcon->num_oplock_brks, 0);
atomic_set(&tcon->num_opens, 0);
atomic_set(&tcon->num_closes, 0);
atomic_set(&tcon->num_deletes, 0);
atomic_set(&tcon->num_mkdirs, 0);
atomic_set(&tcon->num_rmdirs, 0);
atomic_set(&tcon->num_renames, 0);
atomic_set(&tcon->num_t2renames, 0);
atomic_set(&tcon->num_ffirst, 0);
atomic_set(&tcon->num_fnext, 0);
atomic_set(&tcon->num_fclose, 0);
atomic_set(&tcon->num_hardlinks, 0);
atomic_set(&tcon->num_symlinks, 0);
atomic_set(&tcon->num_locks, 0);
}
read_unlock(&GlobalSMBSeslock);
}
return count;
}
static int static int
cifs_stats_read(char *buf, char **beginBuffer, off_t offset, cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
int count, int *eof, void *data) int count, int *eof, void *data)
...@@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
buf += sprintf(buf, "\tDISCONNECTED "); buf += sprintf(buf, "\tDISCONNECTED ");
length += 14; length += 14;
} }
item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d",
atomic_read(&tcon->num_smbs_sent), atomic_read(&tcon->num_smbs_sent),
atomic_read(&tcon->num_oplock_brks)); atomic_read(&tcon->num_oplock_brks));
buf += item_length; buf += item_length;
length += item_length; length += item_length;
item_length = sprintf(buf,"\nReads: %d Bytes %lld", item_length = sprintf(buf, "\nReads: %d Bytes: %lld",
atomic_read(&tcon->num_reads), atomic_read(&tcon->num_reads),
(long long)(tcon->bytes_read)); (long long)(tcon->bytes_read));
buf += item_length; buf += item_length;
length += item_length; length += item_length;
item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", item_length = sprintf(buf, "\nWrites: %d Bytes: %lld",
atomic_read(&tcon->num_writes), atomic_read(&tcon->num_writes),
(long long)(tcon->bytes_written)); (long long)(tcon->bytes_written));
buf += item_length;
length += item_length;
item_length = sprintf(buf,
"\nLocks: %d HardLinks: %d Symlinks: %d",
atomic_read(&tcon->num_locks),
atomic_read(&tcon->num_hardlinks),
atomic_read(&tcon->num_symlinks));
buf += item_length;
length += item_length;
item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d",
atomic_read(&tcon->num_opens),
atomic_read(&tcon->num_closes),
atomic_read(&tcon->num_deletes));
buf += item_length; buf += item_length;
length += item_length; length += item_length;
item_length = sprintf(buf, item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
atomic_read(&tcon->num_opens),
atomic_read(&tcon->num_deletes),
atomic_read(&tcon->num_mkdirs), atomic_read(&tcon->num_mkdirs),
atomic_read(&tcon->num_rmdirs)); atomic_read(&tcon->num_rmdirs));
buf += item_length; buf += item_length;
length += item_length; length += item_length;
item_length = sprintf(buf, item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
"\nRenames: %d T2 Renames %d",
atomic_read(&tcon->num_renames), atomic_read(&tcon->num_renames),
atomic_read(&tcon->num_t2renames)); atomic_read(&tcon->num_t2renames));
buf += item_length; buf += item_length;
length += item_length; length += item_length;
item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d",
atomic_read(&tcon->num_ffirst),
atomic_read(&tcon->num_fnext),
atomic_read(&tcon->num_fclose));
buf += item_length;
length += item_length;
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
...@@ -341,8 +408,10 @@ cifs_proc_init(void) ...@@ -341,8 +408,10 @@ cifs_proc_init(void)
cifs_debug_data_read, NULL); cifs_debug_data_read, NULL);
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
create_proc_read_entry("Stats", 0, proc_fs_cifs, pde = create_proc_read_entry("Stats", 0, proc_fs_cifs,
cifs_stats_read, NULL); cifs_stats_read, NULL);
if (pde)
pde->write_proc = cifs_stats_write;
#endif #endif
pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
cifsFYI_read, NULL); cifsFYI_read, NULL);
...@@ -360,7 +429,7 @@ cifs_proc_init(void) ...@@ -360,7 +429,7 @@ cifs_proc_init(void)
if (pde) if (pde)
pde->write_proc = oplockEnabled_write; pde->write_proc = oplockEnabled_write;
pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs, pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
quotaEnabled_read, NULL); quotaEnabled_read, NULL);
if (pde) if (pde)
pde->write_proc = quotaEnabled_write; pde->write_proc = quotaEnabled_write;
...@@ -419,7 +488,7 @@ cifs_proc_clean(void) ...@@ -419,7 +488,7 @@ cifs_proc_clean(void)
remove_proc_entry("ExtendedSecurity",proc_fs_cifs); remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
remove_proc_entry("cifs", proc_root_fs); remove_proc_entry("cifs", proc_root_fs);
} }
...@@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer, ...@@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer,
cifsFYI = 0; cifsFYI = 0;
else if (c == '1' || c == 'y' || c == 'Y') else if (c == '1' || c == 'y' || c == 'Y')
cifsFYI = 1; cifsFYI = 1;
else if((c > '1') && (c <= '9'))
cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
return count; return count;
} }
......
...@@ -26,6 +26,9 @@ ...@@ -26,6 +26,9 @@
void cifs_dump_mem(char *label, void *data, int length); void cifs_dump_mem(char *label, void *data, int length);
extern int traceSMB; /* flag which enables the function below */ extern int traceSMB; /* flag which enables the function below */
void dump_smb(struct smb_hdr *, int); void dump_smb(struct smb_hdr *, int);
#define CIFS_INFO 0x01
#define CIFS_RC 0x02
#define CIFS_TIMER 0x04
/* /*
* debug ON * debug ON
...@@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int); ...@@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int);
/* information message: e.g., configuration, major event */ /* information message: e.g., configuration, major event */
extern int cifsFYI; extern int cifsFYI;
#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) #define cifsfyi(format,arg...) if (cifsFYI & CIFS_INFO) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
#define cFYI(button,prspec) if (button) cifsfyi prspec #define cFYI(button,prspec) if (button) cifsfyi prspec
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
......
...@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0; ...@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0;
unsigned int sign_CIFS_PDUs = 1; unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */ extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL; struct task_struct * oplockThread = NULL;
extern struct task_struct * dnotifyThread; /* remove sparse warning */
struct task_struct * dnotifyThread = NULL;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0); module_param(CIFSMaxBufSize, int, 0);
MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); 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,6 +75,7 @@ module_param(cifs_max_pending, int, 0);
MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
static DECLARE_COMPLETION(cifs_oplock_exited); static DECLARE_COMPLETION(cifs_oplock_exited);
static DECLARE_COMPLETION(cifs_dnotify_exited);
extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
...@@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
#endif /* CIFS_EXPERIMENTAL */ #endif /* CIFS_EXPERIMENTAL */
rc = CIFSSMBQFSInfo(xid, pTcon, buf); rc = CIFSSMBQFSInfo(xid, pTcon, buf);
/* Old Windows servers do not support level 103, retry with level
one if old server failed the previous call */
if(rc)
rc = SMBOldQFSInfo(xid, pTcon, buf);
/* /*
int f_type; int f_type;
__fsid_t f_fsid; __fsid_t f_fsid;
...@@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->clientCanCacheAll = FALSE; cifs_inode->clientCanCacheAll = FALSE;
cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
INIT_LIST_HEAD(&cifs_inode->openFileList); INIT_LIST_HEAD(&cifs_inode->openFileList);
return &cifs_inode->vfs_inode; return &cifs_inode->vfs_inode;
} }
...@@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = { ...@@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = {
}; };
#endif #endif
static void cifs_umount_begin(struct super_block * sblock)
{
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo * tcon;
cifs_sb = CIFS_SB(sblock);
if(cifs_sb == NULL)
return;
tcon = cifs_sb->tcon;
if(tcon == NULL)
return;
down(&tcon->tconSem);
if (atomic_read(&tcon->useCount) == 1)
tcon->tidStatus = CifsExiting;
up(&tcon->tconSem);
if(tcon->ses && tcon->ses->server)
{
cERROR(1,("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q);
}
/* BB FIXME - finish add checks for tidStatus BB */
return;
}
static int cifs_remount(struct super_block *sb, int *flags, char *data) static int cifs_remount(struct super_block *sb, int *flags, char *data)
{ {
*flags |= MS_NODIRATIME; *flags |= MS_NODIRATIME;
...@@ -415,7 +450,7 @@ struct super_operations cifs_super_ops = { ...@@ -415,7 +450,7 @@ struct super_operations cifs_super_ops = {
unless later we add lazy close of inodes or unless the kernel forgets to call unless later we add lazy close of inodes or unless the kernel forgets to call
us with the same number of releases (closes) as opens */ us with the same number of releases (closes) as opens */
.show_options = cifs_show_options, .show_options = cifs_show_options,
/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ /* .umount_begin = cifs_umount_begin, */ /* BB finish in the future */
.remount_fs = cifs_remount, .remount_fs = cifs_remount,
}; };
...@@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg)
do { do {
if (try_to_freeze()) if (try_to_freeze())
continue; continue;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1*HZ);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if(list_empty(&GlobalOplock_Q)) { if(list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg)
} }
} else } else
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1); /* yield in case q were corrupt */
} }
} while(!signal_pending(current)); } while(!signal_pending(current));
complete_and_exit (&cifs_oplock_exited, 0);
oplockThread = NULL; oplockThread = NULL;
complete_and_exit (&cifs_oplock_exited, 0);
}
static int cifs_dnotify_thread(void * dummyarg)
{
daemonize("cifsdnotifyd");
allow_signal(SIGTERM);
dnotifyThread = current;
do {
if(try_to_freeze())
continue;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(39*HZ);
} while(!signal_pending(current));
complete_and_exit (&cifs_dnotify_exited, 0);
} }
static int __init static int __init
...@@ -851,6 +901,10 @@ init_cifs(void) ...@@ -851,6 +901,10 @@ init_cifs(void)
INIT_LIST_HEAD(&GlobalSMBSessionList); INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList); INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q); INIT_LIST_HEAD(&GlobalOplock_Q);
#ifdef CONFIG_CIFS_EXPERIMENTAL
INIT_LIST_HEAD(&GlobalDnotifyReqList);
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
#endif
/* /*
* Initialize Global counters * Initialize Global counters
*/ */
...@@ -886,10 +940,16 @@ init_cifs(void) ...@@ -886,10 +940,16 @@ init_cifs(void)
if (!rc) { if (!rc) {
rc = (int)kernel_thread(cifs_oplock_thread, NULL, rc = (int)kernel_thread(cifs_oplock_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_VM); CLONE_FS | CLONE_FILES | CLONE_VM);
if(rc > 0) if(rc > 0) {
return 0; rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
else CLONE_FS | CLONE_FILES | CLONE_VM);
if(rc > 0)
return 0;
else
cERROR(1,("error %d create dnotify thread", rc));
} else {
cERROR(1,("error %d create oplock thread",rc)); cERROR(1,("error %d create oplock thread",rc));
}
} }
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
} }
...@@ -918,6 +978,10 @@ exit_cifs(void) ...@@ -918,6 +978,10 @@ exit_cifs(void)
send_sig(SIGTERM, oplockThread, 1); send_sig(SIGTERM, oplockThread, 1);
wait_for_completion(&cifs_oplock_exited); wait_for_completion(&cifs_oplock_exited);
} }
if(dnotifyThread) {
send_sig(SIGTERM, dnotifyThread, 1);
wait_for_completion(&cifs_dnotify_exited);
}
} }
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
......
...@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); ...@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg);
/* Functions related to dir entries */ /* Functions related to dir entries */
extern struct dentry_operations cifs_dentry_ops; extern struct dentry_operations cifs_dentry_ops;
extern struct dentry_operations cifs_ci_dentry_ops;
/* Functions related to symlinks */ /* Functions related to symlinks */
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); 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,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep, extern int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg); unsigned int command, unsigned long arg);
#define CIFS_VERSION "1.35" #define CIFS_VERSION "1.39"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -110,8 +110,9 @@ enum protocolEnum { ...@@ -110,8 +110,9 @@ enum protocolEnum {
*/ */
struct TCP_Server_Info { struct TCP_Server_Info {
char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ /* 15 character server name + 0x20 16th byte indicating type = srv */
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
struct socket *ssocket; struct socket *ssocket;
union { union {
struct sockaddr_in sockAddr; struct sockaddr_in sockAddr;
...@@ -122,13 +123,17 @@ struct TCP_Server_Info { ...@@ -122,13 +123,17 @@ struct TCP_Server_Info {
struct list_head pending_mid_q; struct list_head pending_mid_q;
void *Server_NlsInfo; /* BB - placeholder for future NLS info */ void *Server_NlsInfo; /* BB - placeholder for future NLS info */
unsigned short server_codepage; /* codepage for the server */ unsigned short server_codepage; /* codepage for the server */
unsigned long ip_address; /* IP addr for the server if known */ unsigned long ip_address; /* IP addr for the server if known */
enum protocolEnum protocolType; enum protocolEnum protocolType;
char versionMajor; char versionMajor;
char versionMinor; char versionMinor;
unsigned svlocal:1; /* local server or remote */ unsigned svlocal:1; /* local server or remote */
atomic_t socketUseCount; /* number of open cifs sessions on socket */ atomic_t socketUseCount; /* number of open cifs sessions on socket */
atomic_t inFlight; /* number of requests on the wire to server */ atomic_t inFlight; /* number of requests on the wire to server */
#ifdef CONFIG_CIFS_STATS2
atomic_t inSend; /* requests trying to send */
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
#endif
enum statusEnum tcpStatus; /* what we think the status is */ enum statusEnum tcpStatus; /* what we think the status is */
struct semaphore tcpSem; struct semaphore tcpSem;
struct task_struct *tsk; struct task_struct *tsk;
...@@ -147,8 +152,10 @@ struct TCP_Server_Info { ...@@ -147,8 +152,10 @@ struct TCP_Server_Info {
/* (returned on Negotiate */ /* (returned on Negotiate */
int capabilities; /* allow selective disabling of caps by smb sess */ int capabilities; /* allow selective disabling of caps by smb sess */
__u16 timeZone; __u16 timeZone;
__u16 CurrentMid; /* multiplex id - rotating counter */
char cryptKey[CIFS_CRYPTO_KEY_SIZE]; char cryptKey[CIFS_CRYPTO_KEY_SIZE];
char workstation_RFC1001_name[16]; /* 16th byte is always zero */ /* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */ __u32 sequence_number; /* needed for CIFS PDU signature */
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
}; };
...@@ -214,19 +221,41 @@ struct cifsTconInfo { ...@@ -214,19 +221,41 @@ struct cifsTconInfo {
atomic_t num_reads; atomic_t num_reads;
atomic_t num_oplock_brks; atomic_t num_oplock_brks;
atomic_t num_opens; atomic_t num_opens;
atomic_t num_closes;
atomic_t num_deletes; atomic_t num_deletes;
atomic_t num_mkdirs; atomic_t num_mkdirs;
atomic_t num_rmdirs; atomic_t num_rmdirs;
atomic_t num_renames; atomic_t num_renames;
atomic_t num_t2renames; atomic_t num_t2renames;
atomic_t num_ffirst;
atomic_t num_fnext;
atomic_t num_fclose;
atomic_t num_hardlinks;
atomic_t num_symlinks;
atomic_t num_locks;
#ifdef CONFIG_CIFS_STATS2
unsigned long long time_writes;
unsigned long long time_reads;
unsigned long long time_opens;
unsigned long long time_deletes;
unsigned long long time_closes;
unsigned long long time_mkdirs;
unsigned long long time_rmdirs;
unsigned long long time_renames;
unsigned long long time_t2renames;
unsigned long long time_ffirst;
unsigned long long time_fnext;
unsigned long long time_fclose;
#endif /* CONFIG_CIFS_STATS2 */
__u64 bytes_read; __u64 bytes_read;
__u64 bytes_written; __u64 bytes_written;
spinlock_t stat_lock; spinlock_t stat_lock;
#endif #endif /* CONFIG_CIFS_STATS */
FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_DEVICE_INFO fsDevInfo;
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */
FILE_SYSTEM_UNIX_INFO fsUnixInfo; FILE_SYSTEM_UNIX_INFO fsUnixInfo;
unsigned retry:1; unsigned retry:1;
unsigned nocase:1;
/* BB add field for back pointer to sb struct? */ /* BB add field for back pointer to sb struct? */
}; };
...@@ -270,6 +299,7 @@ struct cifsFileInfo { ...@@ -270,6 +299,7 @@ struct cifsFileInfo {
struct inode * pInode; /* needed for oplock break */ struct inode * pInode; /* needed for oplock break */
unsigned closePend:1; /* file is marked to close */ unsigned closePend:1; /* file is marked to close */
unsigned invalidHandle:1; /* file closed via session abend */ unsigned invalidHandle:1; /* file closed via session abend */
atomic_t wrtPending; /* handle in use - defer close */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/ struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name; /* BB removeme BB */ char * search_resume_name; /* BB removeme BB */
unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
...@@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb) ...@@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb)
return sb->s_fs_info; return sb->s_fs_info;
} }
static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
{
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
return '/';
else
return '\\';
}
#ifdef CONFIG_CIFS_STATS
#define cifs_stats_inc atomic_inc
static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon,
unsigned int bytes)
{
if (bytes) {
spin_lock(&tcon->stat_lock);
tcon->bytes_written += bytes;
spin_unlock(&tcon->stat_lock);
}
}
static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
unsigned int bytes)
{
spin_lock(&tcon->stat_lock);
tcon->bytes_read += bytes;
spin_unlock(&tcon->stat_lock);
}
#else
#define cifs_stats_inc(field) do {} while(0)
#define cifs_stats_bytes_written(tcon, bytes) do {} while(0)
#define cifs_stats_bytes_read(tcon, bytes) do {} while(0)
#endif
/* one of these for every pending CIFS request to the server */ /* one of these for every pending CIFS request to the server */
struct mid_q_entry { struct mid_q_entry {
...@@ -313,7 +378,11 @@ struct mid_q_entry { ...@@ -313,7 +378,11 @@ struct mid_q_entry {
__u16 mid; /* multiplex id */ __u16 mid; /* multiplex id */
__u16 pid; /* process id */ __u16 pid; /* process id */
__u32 sequence_number; /* for CIFS signing */ __u32 sequence_number; /* for CIFS signing */
struct timeval when_sent; /* time when smb sent */ unsigned long when_alloc; /* when mid was created */
#ifdef CONFIG_CIFS_STATS2
unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */
#endif
struct cifsSesInfo *ses; /* smb was sent to this server */ struct cifsSesInfo *ses; /* smb was sent to this server */
struct task_struct *tsk; /* task waiting for response */ struct task_struct *tsk; /* task waiting for response */
struct smb_hdr *resp_buf; /* response buffer */ struct smb_hdr *resp_buf; /* response buffer */
...@@ -331,6 +400,20 @@ struct oplock_q_entry { ...@@ -331,6 +400,20 @@ struct oplock_q_entry {
__u16 netfid; __u16 netfid;
}; };
/* for pending dnotify requests */
struct dir_notify_req {
struct list_head lhead;
__le16 Pid;
__le16 PidHigh;
__u16 Mid;
__u16 Tid;
__u16 Uid;
__u16 netfid;
__u32 filter; /* CompletionFilter (for multishot) */
int multishot;
struct file * pfile;
};
#define MID_FREE 0 #define MID_FREE 0
#define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_ALLOCATED 1
#define MID_REQUEST_SUBMITTED 2 #define MID_REQUEST_SUBMITTED 2
...@@ -399,6 +482,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ ...@@ -399,6 +482,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
GLOBAL_EXTERN struct list_head GlobalOplock_Q; GLOBAL_EXTERN struct list_head GlobalOplock_Q;
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
/* /*
* Global transaction id (XID) information * Global transaction id (XID) information
*/ */
......
This diff is collapsed.
...@@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, ...@@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
int * /* bytes returned */ , const int long_op); int * /* bytes returned */ , const int long_op);
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
struct kvec *, int /* nvec */,
int * /* bytes returned */ , const int long_op);
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
extern int is_valid_oplock_break(struct smb_hdr *smb); extern int is_valid_oplock_break(struct smb_hdr *smb);
extern int is_size_safe_to_change(struct cifsInodeInfo *); extern int is_size_safe_to_change(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int decode_negTokenInit(unsigned char *security_blob, int length,
enum securityEnum *secType); enum securityEnum *secType);
extern int cifs_inet_pton(int, char * source, void *dst); extern int cifs_inet_pton(int, char * source, void *dst);
extern int map_smb_to_linux_error(struct smb_hdr *smb); extern int map_smb_to_linux_error(struct smb_hdr *smb);
extern void header_assemble(struct smb_hdr *, char /* command */ , extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* specifies length const struct cifsTconInfo *, int /* length of
of fixed section (word count) in two byte units */ fixed section (word count) in two byte units */);
); extern __u16 GetNextMid(struct TCP_Server_Info *server);
extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
struct cifsTconInfo *); struct cifsTconInfo *);
extern void DeleteOplockQEntry(struct oplock_q_entry *); extern void DeleteOplockQEntry(struct oplock_q_entry *);
...@@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
const char *searchName, const struct nls_table *nls_codepage, const char *searchName, const struct nls_table *nls_codepage,
__u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep);
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
__u16 searchHandle, struct cifs_search_info * psrch_inf); __u16 searchHandle, struct cifs_search_info * psrch_inf);
...@@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
FILE_ALL_INFO * findData, FILE_ALL_INFO * findData,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * findData,
const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBUnixQPathInfo(const int xid, extern int CIFSSMBUnixQPathInfo(const int xid,
struct cifsTconInfo *tcon, struct cifsTconInfo *tcon,
...@@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
int remap); int remap);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData); struct kstatfs *FSData);
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData);
extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
__u64 cap);
extern int CIFSSMBQFSAttributeInfo(const int xid, extern int CIFSSMBQFSAttributeInfo(const int xid,
struct cifsTconInfo *tcon); struct cifsTconInfo *tcon);
extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
...@@ -207,6 +221,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -207,6 +221,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const int access_flags, const int omode, const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *, __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id); const int smb_file_id);
...@@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, ...@@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
const int netfid, const unsigned int count, const int netfid, const unsigned int count,
const __u64 offset, unsigned int *nbytes, const __u64 offset, unsigned int *nbytes,
const char __user *buf,const int long_op); struct kvec *iov, const int nvec, const int long_op);
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, __u64 * inode_number, const unsigned char *searchName, __u64 * inode_number,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
...@@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid, ...@@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
const int notify_subdirs,const __u16 netfid, const int notify_subdirs,const __u16 netfid,
__u32 filter, const struct nls_table *nls_codepage); __u32 filter, struct file * file, int multishot,
const struct nls_table *nls_codepage);
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, char * EAData, const unsigned char *searchName, char * EAData,
size_t bufsize, const struct nls_table *nls_codepage, size_t bufsize, const struct nls_table *nls_codepage,
......
This diff is collapsed.
This diff is collapsed.
...@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry)
struct dentry *temp; struct dentry *temp;
int namelen = 0; int namelen = 0;
char *full_path; char *full_path;
char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
if(direntry == NULL) if(direntry == NULL)
return NULL; /* not much we can do if dentry is freed and return NULL; /* not much we can do if dentry is freed and
...@@ -74,7 +75,7 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -74,7 +75,7 @@ build_path_from_dentry(struct dentry *direntry)
if (namelen < 0) { if (namelen < 0) {
break; break;
} else { } else {
full_path[namelen] = '\\'; full_path[namelen] = dirsep;
strncpy(full_path + namelen + 1, temp->d_name.name, strncpy(full_path + namelen + 1, temp->d_name.name,
temp->d_name.len); temp->d_name.len);
cFYI(0, (" name: %s ", full_path + namelen)); cFYI(0, (" name: %s ", full_path + namelen));
...@@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
desiredAccess, CREATE_NOT_DIR, desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if(rc == -EIO) {
/* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (rc) { if (rc) {
cFYI(1, ("cifs_create returned 0x%x ", rc)); cFYI(1, ("cifs_create returned 0x%x ", rc));
} else { } else {
...@@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
else { else {
/* BB implement via Windows security descriptors */ /* BB implement mode setting via Windows security descriptors */
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
/* could set r/o dos attribute if mode & 0222 == 0 */ /* could set r/o dos attribute if mode & 0222 == 0 */
} }
...@@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
} }
if (rc != 0) { if (rc != 0) {
cFYI(1,("Create worked but get_inode_info failed with rc = %d", cFYI(1,
("Create worked but get_inode_info failed rc = %d",
rc)); rc));
} else { } else {
direntry->d_op = &cifs_dentry_ops; if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
} }
if((nd->flags & LOOKUP_OPEN) == FALSE) { 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,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
up(&direntry->d_sb->s_vfs_rename_sem); up(&direntry->d_sb->s_vfs_rename_sem);
if(full_path == NULL) if(full_path == NULL)
rc = -ENOMEM; rc = -ENOMEM;
else if (pTcon->ses->capabilities & CAP_UNIX) {
if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode,(__u64)current->euid,(__u64)current->egid, 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,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
if(!rc) { if(!rc) {
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb,xid); inode->i_sb,xid);
direntry->d_op = &cifs_dentry_ops; if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
direntry->d_op = &cifs_dentry_ops;
if(rc == 0) if(rc == 0)
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
} }
} else {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
int oplock = 0;
u16 fileHandle;
FILE_ALL_INFO * buf;
cFYI(1,("sfu compat create special file"));
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf == NULL) {
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBOpen(xid, pTcon, full_path,
FILE_CREATE, /* fail if exists */
GENERIC_WRITE /* BB would
WRITE_OWNER | WRITE_DAC be better? */,
/* Create a file and set the
file attribute to SYSTEM */
CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
&fileHandle, &oplock, buf,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if(!rc) {
/* BB Do not bother to decode buf since no
local inode yet to put timestamps in */
CIFSSMBClose(xid, pTcon, fileHandle);
d_drop(direntry);
}
kfree(buf);
/* add code here to set EAs */
}
} }
kfree(full_path); kfree(full_path);
...@@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name ...@@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
parent_dir_inode->i_sb,xid); parent_dir_inode->i_sb,xid);
if ((rc == 0) && (newInode != NULL)) { if ((rc == 0) && (newInode != NULL)) {
direntry->d_op = &cifs_dentry_ops; if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
direntry->d_op = &cifs_dentry_ops;
d_add(direntry, newInode); d_add(direntry, newInode);
/* since paths are not looked up by component - the parent directories are presumed to be good here */ /* 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,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = {
/* d_delete: cifs_d_delete, *//* not needed except for debugging */ /* d_delete: cifs_d_delete, *//* not needed except for debugging */
/* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
}; };
static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
{
struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
unsigned long hash;
int i;
hash = init_name_hash();
for (i = 0; i < q->len; i++)
hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
hash);
q->hash = end_name_hash(hash);
return 0;
}
static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
struct qstr *b)
{
struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
if ((a->len == b->len) &&
(nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
/*
* To preserve case, don't let an existing negative dentry's
* case take precedence. If a is not a negative dentry, this
* should have no side effects
*/
memcpy((unsigned char *)a->name, b->name, a->len);
return 0;
}
return 1;
}
struct dentry_operations cifs_ci_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
.d_hash = cifs_ci_hash,
.d_compare = cifs_ci_compare,
};
...@@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) ...@@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
__u16 netfid; __u16 netfid;
if(experimEnabled == 0)
return 0;
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
...@@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) ...@@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
} else { } else {
filter = convert_to_cifs_notify_flags(arg); filter = convert_to_cifs_notify_flags(arg);
if(filter != 0) { if(filter != 0) {
rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, rc = CIFSSMBNotify(xid, pTcon,
filter, cifs_sb->local_nls); 0 /* no subdirs */, netfid,
filter, file, arg & DN_MULTISHOT,
cifs_sb->local_nls);
} else { } else {
rc = -EINVAL; rc = -EINVAL;
} }
...@@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg) ...@@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
it would close automatically but may be a way it would close automatically but may be a way
to do it easily when inode freed or when to do it easily when inode freed or when
notify info is cleared/changed */ notify info is cleared/changed */
cERROR(1,("notify rc %d",rc)); cFYI(1,("notify rc %d",rc));
} }
} }
......
This diff is collapsed.
...@@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode->i_fop = &cifs_file_direct_ops; inode->i_fop = &cifs_file_direct_ops;
else else
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop->lock = NULL;
inode->i_data.a_ops = &cifs_addr_ops; inode->i_data.a_ops = &cifs_addr_ops;
/* check if server can support readpages */
if(pTcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops->readpages = NULL;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, (" Directory inode")); cFYI(1, (" Directory inode"));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
...@@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode,
pfindData = (FILE_ALL_INFO *)buf; pfindData = (FILE_ALL_INFO *)buf;
/* could do find first instead but this returns more info */ /* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB optimize code so we do not make the above call
when server claims no NT SMB support and the above call
failed at least once - set flag in tcon or mount */
if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, pTcon, search_path,
pfindData, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
} }
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc) {
...@@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode,
on dirs */ on dirs */
inode->i_mode = cifs_sb->mnt_dir_mode; inode->i_mode = cifs_sb->mnt_dir_mode;
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
/* No need to le64 convert size of zero */
(pfindData->EndOfFile == 0)) {
inode->i_mode = cifs_sb->mnt_file_mode;
inode->i_mode |= S_IFIFO;
/* BB Finish for SFU style symlinks and devies */
/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
} else { } else {
inode->i_mode |= S_IFREG; inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only /* treat the dos attribute of read-only as read-only
...@@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode,
inode->i_fop = &cifs_file_direct_ops; inode->i_fop = &cifs_file_direct_ops;
else else
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop->lock = NULL;
inode->i_data.a_ops = &cifs_addr_ops; inode->i_data.a_ops = &cifs_addr_ops;
if(pTcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops->readpages = NULL;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, (" Directory inode ")); cFYI(1, (" Directory inode "));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
...@@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
rc = cifs_get_inode_info(&newinode, full_path, NULL, rc = cifs_get_inode_info(&newinode, full_path, NULL,
inode->i_sb,xid); inode->i_sb,xid);
direntry->d_op = &cifs_dentry_ops; if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
if (direntry->d_inode) if (direntry->d_inode)
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
...@@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
int rc = -EACCES; int rc = -EACCES;
int found = FALSE;
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
FILE_BASIC_INFO time_buf; FILE_BASIC_INFO time_buf;
int set_time = FALSE; int set_time = FALSE;
...@@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
__u64 uid = 0xFFFFFFFFFFFFFFFFULL; __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
__u64 gid = 0xFFFFFFFFFFFFFFFFULL; __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
struct list_head *tmp;
xid = GetXid(); xid = GetXid();
...@@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
filemap_fdatawait(direntry->d_inode->i_mapping); filemap_fdatawait(direntry->d_inode->i_mapping);
if (attrs->ia_valid & ATTR_SIZE) { if (attrs->ia_valid & ATTR_SIZE) {
read_lock(&GlobalSMBSeslock);
/* To avoid spurious oplock breaks from server, in the case of /* To avoid spurious oplock breaks from server, in the case of
inodes that we already have open, avoid doing path based inodes that we already have open, avoid doing path based
setting of file size if we can do it by handle. 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,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
when the local oplock break takes longer to flush when the local oplock break takes longer to flush
writebehind data than the SMB timeout for the SetPathInfo writebehind data than the SMB timeout for the SetPathInfo
request would allow */ request would allow */
list_for_each(tmp, &cifsInode->openFileList) { open_file = find_writable_file(cifsInode);
open_file = list_entry(tmp, struct cifsFileInfo, if (open_file) {
flist); __u16 nfid = open_file->netfid;
/* We check if file is open for writing first */ __u32 npid = open_file->pid;
if ((open_file->pfile) && rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
((open_file->pfile->f_flags & O_RDWR) || nfid, npid, FALSE);
(open_file->pfile->f_flags & O_WRONLY))) { atomic_dec(&open_file->wrtPending);
if (open_file->invalidHandle == FALSE) { cFYI(1,("SetFSize for attrs rc = %d", rc));
/* we found a valid, writeable network if(rc == -EINVAL) {
file handle to use to try to set the int bytes_written;
file size */ rc = CIFSSMBWrite(xid, pTcon,
__u16 nfid = open_file->netfid; nfid, 0, attrs->ia_size,
__u32 npid = open_file->pid; &bytes_written, NULL, NULL,
read_unlock(&GlobalSMBSeslock); 1 /* 45 seconds */);
found = TRUE; cFYI(1,("Wrt seteof rc %d", rc));
rc = CIFSSMBSetFileSize(xid, pTcon,
attrs->ia_size, nfid, npid,
FALSE);
cFYI(1, ("SetFileSize by handle "
"(setattrs) rc = %d", rc));
/* Do not need reopen and retry on
EAGAIN since we will retry by
pathname below */
/* now that we found one valid file
handle no sense continuing to loop
trying others, so break here */
break;
}
} }
} }
if (found == FALSE)
read_unlock(&GlobalSMBSeslock);
if (rc != 0) { if (rc != 0) {
/* Set file size by pathname rather than by handle /* Set file size by pathname rather than by handle
either because no valid, writeable file handle for either because no valid, writeable file handle for
...@@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
if(rc == -EINVAL) {
__u16 netfid;
int oplock = FALSE;
rc = SMBLegacyOpen(xid, pTcon, full_path,
FILE_OPEN,
SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) {
int bytes_written;
rc = CIFSSMBWrite(xid, pTcon,
netfid, 0,
attrs->ia_size,
&bytes_written, NULL,
NULL, 1 /* 45 sec */);
cFYI(1,("wrt seteof rc %d",rc));
CIFSSMBClose(xid, pTcon, netfid);
}
}
} }
/* Server is ok setting allocation size implicitly - no need /* Server is ok setting allocation size implicitly - no need
...@@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = vmtruncate(direntry->d_inode, attrs->ia_size); rc = vmtruncate(direntry->d_inode, attrs->ia_size);
cifs_truncate_page(direntry->d_inode->i_mapping, cifs_truncate_page(direntry->d_inode->i_mapping,
direntry->d_inode->i_size); direntry->d_inode->i_size);
} } else
goto cifs_setattr_exit;
} }
if (attrs->ia_valid & ATTR_UID) { if (attrs->ia_valid & ATTR_UID) {
cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); cFYI(1, ("UID changed to %d", attrs->ia_uid));
uid = attrs->ia_uid; uid = attrs->ia_uid;
/* entry->uid = cpu_to_le16(attr->ia_uid); */
} }
if (attrs->ia_valid & ATTR_GID) { if (attrs->ia_valid & ATTR_GID) {
cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); cFYI(1, ("GID changed to %d", attrs->ia_gid));
gid = attrs->ia_gid; gid = attrs->ia_gid;
/* entry->gid = cpu_to_le16(attr->ia_gid); */
} }
time_buf.Attributes = 0; time_buf.Attributes = 0;
if (attrs->ia_valid & ATTR_MODE) { if (attrs->ia_valid & ATTR_MODE) {
cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
mode = attrs->ia_mode; mode = attrs->ia_mode;
/* entry->mode = cpu_to_le16(attr->ia_mode); */
} }
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
...@@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
} else } else
time_buf.LastWriteTime = 0; time_buf.LastWriteTime = 0;
/* Do not set ctime explicitly unless other time
if (attrs->ia_valid & ATTR_CTIME) { stamps are changed explicitly (i.e. by utime()
since we would then have a mix of client and
server times */
if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
set_time = TRUE; set_time = TRUE;
cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ /* Although Samba throws this field away
it may be useful to Windows - but we do
not want to set ctime unless some other
timestamp is changing */
cFYI(1, ("CIFS - CTIME changed "));
time_buf.ChangeTime = time_buf.ChangeTime =
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
} else } else
time_buf.ChangeTime = 0; time_buf.ChangeTime = 0;
if (set_time || time_buf.Attributes) { if (set_time || time_buf.Attributes) {
/* BB what if setting one attribute fails (such as size) but
time setting works? */
time_buf.CreationTime = 0; /* do not change */ time_buf.CreationTime = 0; /* do not change */
/* In the future we should experiment - try setting timestamps /* In the future we should experiment - try setting timestamps
via Handle (SetFileInfo) instead of by path */ via Handle (SetFileInfo) instead of by path */
...@@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
&time_buf, cifs_sb->local_nls); */ &time_buf, cifs_sb->local_nls); */
} }
} }
/* Even if error on time set, no sense failing the call if
the server would set the time to a reasonable value anyway,
and this check ensures that we are not being called from
sys_utimes in which case we ought to fail the call back to
the user when the server rejects the call */
if((rc) && (attrs->ia_valid &&
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
rc = 0;
} }
/* do not need local check to inode_check_ok since the server does /* do not need local check to inode_check_ok since the server does
that */ that */
if (!rc) if (!rc)
rc = inode_setattr(direntry->d_inode, attrs); rc = inode_setattr(direntry->d_inode, attrs);
cifs_setattr_exit:
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return rc; return rc;
......
...@@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
("Create symlink worked but get_inode_info failed with rc = %d ", ("Create symlink worked but get_inode_info failed with rc = %d ",
rc)); rc));
} else { } else {
direntry->d_op = &cifs_dentry_ops; if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
} }
} }
......
...@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp; ...@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
extern struct task_struct * oplockThread; extern struct task_struct * oplockThread;
static __u16 GlobalMid; /* multiplex id - rotating counter */
/* The xid serves as a useful identifier for each incoming vfs request, /* The xid serves as a useful identifier for each incoming vfs request,
in a similar way to the mid which is useful to track each sent smb, in a similar way to the mid which is useful to track each sent smb,
and CurrentXid can also provide a running counter (although it and CurrentXid can also provide a running counter (although it
...@@ -51,6 +49,8 @@ _GetXid(void) ...@@ -51,6 +49,8 @@ _GetXid(void)
GlobalTotalActiveXid++; GlobalTotalActiveXid++;
if (GlobalTotalActiveXid > GlobalMaxActiveXid) if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
if(GlobalTotalActiveXid > 65000)
cFYI(1,("warning: more than 65000 requests active"));
xid = GlobalCurrentXid++; xid = GlobalCurrentXid++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return xid; return xid;
...@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free) ...@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free)
return; return;
} }
/*
Find a free multiplex id (SMB mid). Otherwise there could be
mid collisions which might cause problems, demultiplexing the
wrong response to this request. Multiplex ids could collide if
one of a series requests takes much longer than the others, or
if a very large number of long lived requests (byte range
locks or FindNotify requests) are pending. No more than
64K-1 requests can be outstanding at one time. If no
mids are available, return zero. A future optimization
could make the combination of mids and uid the key we use
to demultiplex on (rather than mid alone).
In addition to the above check, the cifs demultiplex
code already used the command code as a secondary
check of the frame and if signing is negotiated the
response would be discarded if the mid were the same
but the signature was wrong. Since the mid is not put in the
pending queue until later (when it is about to be dispatched)
we do have to limit the number of outstanding requests
to somewhat less than 64K-1 although it is hard to imagine
so many threads being in the vfs at one time.
*/
__u16 GetNextMid(struct TCP_Server_Info *server)
{
__u16 mid = 0;
__u16 last_mid;
int collision;
if(server == NULL)
return mid;
spin_lock(&GlobalMid_Lock);
last_mid = server->CurrentMid; /* we do not want to loop forever */
server->CurrentMid++;
/* This nested loop looks more expensive than it is.
In practice the list of pending requests is short,
fewer than 50, and the mids are likely to be unique
on the first pass through the loop unless some request
takes longer than the 64 thousand requests before it
(and it would also have to have been a request that
did not time out) */
while(server->CurrentMid != last_mid) {
struct list_head *tmp;
struct mid_q_entry *mid_entry;
collision = 0;
if(server->CurrentMid == 0)
server->CurrentMid++;
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if ((mid_entry->mid == server->CurrentMid) &&
(mid_entry->midState == MID_REQUEST_SUBMITTED)) {
/* This mid is in use, try a different one */
collision = 1;
break;
}
}
if(collision == 0) {
mid = server->CurrentMid;
break;
}
server->CurrentMid++;
}
spin_unlock(&GlobalMid_Lock);
return mid;
}
/* NB: MID can not be set if treeCon not passed in, in that
case it is responsbility of caller to set the mid */
void void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
const struct cifsTconInfo *treeCon, int word_count const struct cifsTconInfo *treeCon, int word_count
...@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
(2 * word_count) + sizeof (struct smb_hdr) - (2 * word_count) + sizeof (struct smb_hdr) -
4 /* RFC 1001 length field does not count */ + 4 /* RFC 1001 length field does not count */ +
2 /* for bcc field itself */ ; 2 /* for bcc field itself */ ;
/* 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 */ /* 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 */
buffer->Protocol[0] = 0xFF; buffer->Protocol[0] = 0xFF;
buffer->Protocol[1] = 'S'; buffer->Protocol[1] = 'S';
...@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Pid = cpu_to_le16((__u16)current->tgid); buffer->Pid = cpu_to_le16((__u16)current->tgid);
buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
GlobalMid++;
buffer->Mid = GlobalMid;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if (treeCon) { if (treeCon) {
buffer->Tid = treeCon->tid; buffer->Tid = treeCon->tid;
...@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
if (treeCon->ses->capabilities & CAP_STATUS32) { if (treeCon->ses->capabilities & CAP_STATUS32) {
buffer->Flags2 |= SMBFLG2_ERR_STATUS; buffer->Flags2 |= SMBFLG2_ERR_STATUS;
} }
/* Uid is not converted */
buffer->Uid = treeCon->ses->Suid; /* always in LE format */ buffer->Uid = treeCon->ses->Suid;
buffer->Mid = GetNextMid(treeCon->ses->server);
if(multiuser_mount != 0) { if(multiuser_mount != 0) {
/* For the multiuser case, there are few obvious technically */ /* For the multiuser case, there are few obvious technically */
/* possible mechanisms to match the local linux user (uid) */ /* possible mechanisms to match the local linux user (uid) */
...@@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
} }
if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
buffer->Flags2 |= SMBFLG2_DFS; buffer->Flags2 |= SMBFLG2_DFS;
if (treeCon->nocase)
buffer->Flags |= SMBFLG_CASELESS;
if((treeCon->ses) && (treeCon->ses->server)) if((treeCon->ses) && (treeCon->ses->server))
if(treeCon->ses->server->secMode & if(treeCon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
...@@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) ...@@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
int int
checkSMB(struct smb_hdr *smb, __u16 mid, int length) checkSMB(struct smb_hdr *smb, __u16 mid, int length)
{ {
__u32 len = be32_to_cpu(smb->smb_buf_length); __u32 len = smb->smb_buf_length;
__u32 clc_len; /* calculated length */
cFYI(0, cFYI(0,
("Entering checkSMB with Length: %x, smb_buf_length: %x ", ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
length, len)); length, len));
...@@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) ...@@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
cERROR(1, cERROR(1,
("smb_buf_length greater than MaxBufSize")); ("smb_buf_length greater than MaxBufSize"));
cERROR(1, cERROR(1,
("bad smb detected. Illegal length. The mid=%d", ("bad smb detected. Illegal length. mid=%d",
smb->Mid)); smb->Mid));
return 1; return 1;
} }
if (checkSMBhdr(smb, mid)) if (checkSMBhdr(smb, mid))
return 1; return 1;
clc_len = smbCalcSize_LE(smb);
if ((4 + len != smbCalcSize(smb)) if ((4 + len != clc_len)
|| (4 + len != (unsigned int)length)) { || (4 + len != (unsigned int)length)) {
return 0; cERROR(1, ("Calculated size 0x%x vs actual length 0x%x",
} else { clc_len, 4 + len));
cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
cERROR(1, /* Windows XP can return a few bytes too much, presumably
("bad smb size detected. The Mid=%d", smb->Mid)); an illegal pad, at the end of byte range lock responses
return 1; so we allow for up to eight byte pad, as long as actual
received length is as long or longer than calculated length */
if((4+len > clc_len) && (len <= clc_len + 3))
return 0;
else
return 1;
} }
return 0;
} }
int int
is_valid_oplock_break(struct smb_hdr *buf) is_valid_oplock_break(struct smb_hdr *buf)
...@@ -448,9 +527,7 @@ is_valid_oplock_break(struct smb_hdr *buf) ...@@ -448,9 +527,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if (tcon->tid == buf->Tid) { if (tcon->tid == buf->Tid) {
#ifdef CONFIG_CIFS_STATS cifs_stats_inc(&tcon->num_oplock_brks);
atomic_inc(&tcon->num_oplock_brks);
#endif
list_for_each(tmp1,&tcon->openFileList){ list_for_each(tmp1,&tcon->openFileList){
netfile = list_entry(tmp1,struct cifsFileInfo, netfile = list_entry(tmp1,struct cifsFileInfo,
tlist); tlist);
...@@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, ...@@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
int i,j,charlen; int i,j,charlen;
int len_remaining = maxlen; int len_remaining = maxlen;
char src_char; char src_char;
__u16 temp;
if(!mapChars) if(!mapChars)
return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);
...@@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, ...@@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
break;*/ break;*/
default: default:
charlen = cp->char2uni(source+i, charlen = cp->char2uni(source+i,
len_remaining, target+j); len_remaining, &temp);
/* if no match, use question mark, which /* if no match, use question mark, which
at least in some cases servers as wild card */ at least in some cases servers as wild card */
if(charlen < 1) { if(charlen < 1) {
target[j] = cpu_to_le16(0x003f); target[j] = cpu_to_le16(0x003f);
charlen = 1; charlen = 1;
} } else
target[j] = cpu_to_le16(temp);
len_remaining -= charlen; len_remaining -= charlen;
/* character may take more than one byte in the /* character may take more than one byte in the
the source string, but will take exactly two the source string, but will take exactly two
......
...@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { ...@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
int int
cifs_inet_pton(int address_family, char *cp,void *dst) cifs_inet_pton(int address_family, char *cp,void *dst)
{ {
struct in_addr address;
int value; int value;
int digit; int digit;
int i; int i;
...@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst) ...@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
if (value > addr_class_max[end - bytes]) if (value > addr_class_max[end - bytes])
return 0; return 0;
address.s_addr = *((__be32 *) bytes) | htonl(value); *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
*((__be32 *)dst) = address.s_addr;
return 1; /* success */ return 1; /* success */
} }
...@@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) ...@@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb)
if (smb->Flags2 & SMBFLG2_ERR_STATUS) { if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
/* translate the newer STATUS codes to old style errors and then to POSIX errors */ /* translate the newer STATUS codes to old style errors and then to POSIX errors */
__u32 err = le32_to_cpu(smb->Status.CifsError); __u32 err = le32_to_cpu(smb->Status.CifsError);
if(cifsFYI) if(cifsFYI & CIFS_RC)
cifs_print_status(err); cifs_print_status(err);
ntstatus_to_dos(err, &smberrclass, &smberrcode); ntstatus_to_dos(err, &smberrclass, &smberrcode);
} else { } else {
...@@ -870,7 +868,14 @@ unsigned int ...@@ -870,7 +868,14 @@ unsigned int
smbCalcSize(struct smb_hdr *ptr) smbCalcSize(struct smb_hdr *ptr)
{ {
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
BCC(ptr)); 2 /* size of the bcc field */ + BCC(ptr));
}
unsigned int
smbCalcSize_LE(struct smb_hdr *ptr)
{
return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
} }
/* The following are taken from fs/ntfs/util.c */ /* The following are taken from fs/ntfs/util.c */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec) ...@@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec)
pagevec_reinit(pvec); pagevec_reinit(pvec);
} }
EXPORT_SYMBOL(__pagevec_release);
/* /*
* pagevec_release() for pages which are known to not be on the LRU * pagevec_release() for pages which are known to not be on the LRU
* *
...@@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping, ...@@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
return pagevec_count(pvec); return pagevec_count(pvec);
} }
EXPORT_SYMBOL(pagevec_lookup_tag);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment