Commit d6d3f5bc authored by Steve French's avatar Steve French

Merge with /pub/scm/linux/kernel/git/sfrench/cifs-2.6.git/

parents ac9b9c66 23e7dd7d
...@@ -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
*/ */
......
...@@ -36,9 +36,11 @@ ...@@ -36,9 +36,11 @@
#define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */
#define SMB_COM_DELETE 0x06 /* trivial response */ #define SMB_COM_DELETE 0x06 /* trivial response */
#define SMB_COM_RENAME 0x07 /* trivial response */ #define SMB_COM_RENAME 0x07 /* trivial response */
#define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */
#define SMB_COM_SETATTR 0x09 /* trivial response */ #define SMB_COM_SETATTR 0x09 /* trivial response */
#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
#define SMB_COM_READ_ANDX 0x2E #define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_WRITE_ANDX 0x2F
#define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2 0x32
...@@ -52,6 +54,7 @@ ...@@ -52,6 +54,7 @@
#define SMB_COM_NT_TRANSACT 0xA0 #define SMB_COM_NT_TRANSACT 0xA0
#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
#define SMB_COM_NT_CREATE_ANDX 0xA2 #define SMB_COM_NT_CREATE_ANDX 0xA2
#define SMB_COM_NT_CANCEL 0xA4 /* no response */
#define SMB_COM_NT_RENAME 0xA5 /* trivial response */ #define SMB_COM_NT_RENAME 0xA5 /* trivial response */
/* Transact2 subcommand codes */ /* Transact2 subcommand codes */
...@@ -59,6 +62,7 @@ ...@@ -59,6 +62,7 @@
#define TRANS2_FIND_FIRST 0x01 #define TRANS2_FIND_FIRST 0x01
#define TRANS2_FIND_NEXT 0x02 #define TRANS2_FIND_NEXT 0x02
#define TRANS2_QUERY_FS_INFORMATION 0x03 #define TRANS2_QUERY_FS_INFORMATION 0x03
#define TRANS2_SET_FS_INFORMATION 0x04
#define TRANS2_QUERY_PATH_INFORMATION 0x05 #define TRANS2_QUERY_PATH_INFORMATION 0x05
#define TRANS2_SET_PATH_INFORMATION 0x06 #define TRANS2_SET_PATH_INFORMATION 0x06
#define TRANS2_QUERY_FILE_INFORMATION 0x07 #define TRANS2_QUERY_FILE_INFORMATION 0x07
...@@ -267,10 +271,18 @@ ...@@ -267,10 +271,18 @@
/* CreateOptions */ /* CreateOptions */
#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
#define CREATE_WRITE_THROUGH 0x00000002 #define CREATE_WRITE_THROUGH 0x00000002
#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ #define CREATE_SEQUENTIAL 0x00000004
#define CREATE_SYNC_ALERT 0x00000010
#define CREATE_ASYNC_ALERT 0x00000020
#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
#define CREATE_NO_EA_KNOWLEDGE 0x00000200
#define CREATE_EIGHT_DOT_THREE 0x00000400
#define CREATE_RANDOM_ACCESS 0x00000800 #define CREATE_RANDOM_ACCESS 0x00000800
#define CREATE_DELETE_ON_CLOSE 0x00001000 #define CREATE_DELETE_ON_CLOSE 0x00001000
#define CREATE_OPEN_BY_ID 0x00002000
#define OPEN_REPARSE_POINT 0x00200000 #define OPEN_REPARSE_POINT 0x00200000
#define CREATE_OPTIONS_MASK 0x007FFFFF
#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
/* ImpersonationLevel flags */ /* ImpersonationLevel flags */
#define SECURITY_ANONYMOUS 0 #define SECURITY_ANONYMOUS 0
...@@ -614,6 +626,7 @@ typedef struct smb_com_findclose_req { ...@@ -614,6 +626,7 @@ typedef struct smb_com_findclose_req {
} FINDCLOSE_REQ; } FINDCLOSE_REQ;
/* OpenFlags */ /* OpenFlags */
#define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */
#define REQ_OPLOCK 0x00000002 #define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004 #define REQ_BATCHOPLOCK 0x00000004
#define REQ_OPENDIRONLY 0x00000008 #define REQ_OPENDIRONLY 0x00000008
...@@ -669,6 +682,62 @@ typedef struct smb_com_open_rsp { ...@@ -669,6 +682,62 @@ typedef struct smb_com_open_rsp {
__u16 ByteCount; /* bct = 0 */ __u16 ByteCount; /* bct = 0 */
} OPEN_RSP; } OPEN_RSP;
/* format of legacy open request */
typedef struct smb_com_openx_req {
struct smb_hdr hdr; /* wct = 15 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__le16 OpenFlags;
__le16 Mode;
__le16 Sattr; /* search attributes */
__le16 FileAttributes; /* dos attrs */
__le32 CreateTime; /* os2 format */
__le16 OpenFunction;
__le32 EndOfFile;
__le32 Timeout;
__le32 Reserved;
__le16 ByteCount; /* file name follows */
char fileName[1];
} OPENX_REQ;
typedef struct smb_com_openx_rsp {
struct smb_hdr hdr; /* wct = 15 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__u16 Fid;
__le16 FileAttributes;
__le32 LastWriteTime; /* os2 format */
__le32 EndOfFile;
__le16 Access;
__le16 FileType;
__le16 IPCState;
__le16 Action;
__u32 FileId;
__u16 Reserved;
__u16 ByteCount;
} OPENX_RSP;
/* Legacy write request for older servers */
typedef struct smb_com_writex_req {
struct smb_hdr hdr; /* wct = 12 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__u16 Fid;
__le32 OffsetLow;
__u32 Reserved; /* Timeout */
__le16 WriteMode; /* 1 = write through */
__le16 Remaining;
__le16 Reserved2;
__le16 DataLengthLow;
__le16 DataOffset;
__le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
char Data[0];
} WRITEX_REQ;
typedef struct smb_com_write_req { typedef struct smb_com_write_req {
struct smb_hdr hdr; /* wct = 14 */ struct smb_hdr hdr; /* wct = 14 */
__u8 AndXCommand; __u8 AndXCommand;
...@@ -700,6 +769,21 @@ typedef struct smb_com_write_rsp { ...@@ -700,6 +769,21 @@ typedef struct smb_com_write_rsp {
__u16 ByteCount; __u16 ByteCount;
} WRITE_RSP; } WRITE_RSP;
/* legacy read request for older servers */
typedef struct smb_com_readx_req {
struct smb_hdr hdr; /* wct = 10 */
__u8 AndXCommand;
__u8 AndXReserved;
__le16 AndXOffset;
__u16 Fid;
__le32 OffsetLow;
__le16 MaxCount;
__le16 MinCount; /* obsolete */
__le32 Reserved;
__le16 Remaining;
__le16 ByteCount;
} READX_REQ;
typedef struct smb_com_read_req { typedef struct smb_com_read_req {
struct smb_hdr hdr; /* wct = 12 */ struct smb_hdr hdr; /* wct = 12 */
__u8 AndXCommand; __u8 AndXCommand;
...@@ -876,6 +960,22 @@ typedef struct smb_com_create_directory_rsp { ...@@ -876,6 +960,22 @@ typedef struct smb_com_create_directory_rsp {
__u16 ByteCount; /* bct = 0 */ __u16 ByteCount; /* bct = 0 */
} CREATE_DIRECTORY_RSP; } CREATE_DIRECTORY_RSP;
typedef struct smb_com_query_information_req {
struct smb_hdr hdr; /* wct = 0 */
__le16 ByteCount; /* 1 + namelen + 1 */
__u8 BufferFormat; /* 4 = ASCII */
unsigned char FileName[1];
} QUERY_INFORMATION_REQ;
typedef struct smb_com_query_information_rsp {
struct smb_hdr hdr; /* wct = 10 */
__le16 attr;
__le32 last_write_time;
__le32 size;
__u16 reserved[5];
__le16 ByteCount; /* bcc = 0 */
} QUERY_INFORMATION_RSP;
typedef struct smb_com_setattr_req { typedef struct smb_com_setattr_req {
struct smb_hdr hdr; /* wct = 8 */ struct smb_hdr hdr; /* wct = 8 */
__le16 attr; __le16 attr;
...@@ -1411,6 +1511,43 @@ typedef struct smb_com_transaction_qfsi_rsp { ...@@ -1411,6 +1511,43 @@ typedef struct smb_com_transaction_qfsi_rsp {
__u8 Pad; /* may be three bytes *//* followed by data area */ __u8 Pad; /* may be three bytes *//* followed by data area */
} TRANSACTION2_QFSI_RSP; } TRANSACTION2_QFSI_RSP;
/* SETFSInfo Levels */
#define SMB_SET_CIFS_UNIX_INFO 0x200
typedef struct smb_com_transaction2_setfsi_req {
struct smb_hdr hdr; /* wct = 15 */
__le16 TotalParameterCount;
__le16 TotalDataCount;
__le16 MaxParameterCount;
__le16 MaxDataCount;
__u8 MaxSetupCount;
__u8 Reserved;
__le16 Flags;
__le32 Timeout;
__u16 Reserved2;
__le16 ParameterCount; /* 4 */
__le16 ParameterOffset;
__le16 DataCount; /* 12 */
__le16 DataOffset;
__u8 SetupCount; /* one */
__u8 Reserved3;
__le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */
__le16 ByteCount;
__u8 Pad;
__u16 FileNum; /* Parameters start. */
__le16 InformationLevel;/* Parameters end. */
__le16 ClientUnixMajor; /* Data start. */
__le16 ClientUnixMinor;
__le64 ClientUnixCap; /* Data end */
} TRANSACTION2_SETFSI_REQ;
typedef struct smb_com_transaction2_setfsi_rsp {
struct smb_hdr hdr; /* wct = 10 */
struct trans2_resp t2;
__u16 ByteCount;
} TRANSACTION2_SETFSI_RSP;
typedef struct smb_com_transaction2_get_dfs_refer_req { typedef struct smb_com_transaction2_get_dfs_refer_req {
struct smb_hdr hdr; /* wct = 15 */ struct smb_hdr hdr; /* wct = 15 */
__le16 TotalParameterCount; __le16 TotalParameterCount;
...@@ -1546,17 +1683,33 @@ typedef struct { ...@@ -1546,17 +1683,33 @@ typedef struct {
__le32 BytesPerSector; __le32 BytesPerSector;
} FILE_SYSTEM_INFO; /* size info, level 0x103 */ } FILE_SYSTEM_INFO; /* size info, level 0x103 */
typedef struct {
__le32 fsid;
__le32 SectorsPerAllocationUnit;
__le32 TotalAllocationUnits;
__le32 FreeAllocationUnits;
__le16 BytesPerSector;
} FILE_SYSTEM_ALLOC_INFO;
typedef struct { typedef struct {
__le16 MajorVersionNumber; __le16 MajorVersionNumber;
__le16 MinorVersionNumber; __le16 MinorVersionNumber;
__le64 Capability; __le64 Capability;
} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */
/* Version numbers for CIFS UNIX major and minor. */
#define CIFS_UNIX_MAJOR_VERSION 1
#define CIFS_UNIX_MINOR_VERSION 0
/* Linux/Unix extensions capability flags */ /* Linux/Unix extensions capability flags */
#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */
#define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */
#define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Use POSIX pathnames on the wire. */
#define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */
typedef struct { typedef struct {
/* For undefined recommended transfer size return -1 in that field */ /* For undefined recommended transfer size return -1 in that field */
__le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */
...@@ -1907,18 +2060,17 @@ struct data_blob { ...@@ -1907,18 +2060,17 @@ struct data_blob {
perhaps add a CreateDevice - to create Pipes and other special .inodes perhaps add a CreateDevice - to create Pipes and other special .inodes
Also note POSIX open flags Also note POSIX open flags
2) Close - to return the last write time to do cache across close more safely 2) Close - to return the last write time to do cache across close more safely
3) PosixQFSInfo - to return statfs info 3) FindFirst return unique inode number - what about resume key, two
4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) forms short (matches readdir) and full (enough info to cache inodes)
5) Mkdir - set mode 4) Mkdir - set mode
And under consideration: And under consideration:
6) FindClose2 (return nanosecond timestamp ??) 5) FindClose2 (return nanosecond timestamp ??)
7) Use nanosecond timestamps throughout all time fields if 6) Use nanosecond timestamps throughout all time fields if
corresponding attribute flag is set corresponding attribute flag is set
8) sendfile - handle based copy 7) sendfile - handle based copy
9) Direct i/o 8) Direct i/o
10) "POSIX ACL" support 9) Misc fcntls?
11) Misc fcntls?
what about fixing 64 bit alignment what about fixing 64 bit alignment
...@@ -1974,7 +2126,7 @@ struct data_blob { ...@@ -1974,7 +2126,7 @@ struct data_blob {
*/ */
/* xsymlink is a symlink format that can be used /* xsymlink is a symlink format (used by MacOS) that can be used
to save symlink info in a regular file when to save symlink info in a regular file when
mounted to operating systems that do not mounted to operating systems that do not
support the cifs Unix extensions or EAs (for xattr support the cifs Unix extensions or EAs (for xattr
......
...@@ -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 */
......
...@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file, ...@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
} }
*ptmp_inode = new_inode(file->f_dentry->d_sb); *ptmp_inode = new_inode(file->f_dentry->d_sb);
tmp_dentry->d_op = &cifs_dentry_ops; if (pTcon->nocase)
tmp_dentry->d_op = &cifs_ci_dentry_ops;
else
tmp_dentry->d_op = &cifs_dentry_ops;
if(*ptmp_inode == NULL) if(*ptmp_inode == NULL)
return rc; return rc;
rc = 1; rc = 1;
...@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode, ...@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_mode = cifs_sb->mnt_dir_mode; tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
} }
tmp_inode->i_mode |= S_IFDIR; tmp_inode->i_mode |= S_IFDIR;
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(attr & ATTR_SYSTEM) && (end_of_file == 0)) {
*pobject_type = DT_FIFO;
tmp_inode->i_mode |= S_IFIFO;
/* BB Finish for SFU style symlinks and devies */
/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(attr & ATTR_SYSTEM) && ) { */
/* we no longer mark these because we could not follow them */ /* we no longer mark these because we could not follow them */
/* } else if (attr & ATTR_REPARSE) { /* } else if (attr & ATTR_REPARSE) {
*pobject_type = DT_LNK; *pobject_type = DT_LNK;
...@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode, ...@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_fop = &cifs_file_direct_ops; tmp_inode->i_fop = &cifs_file_direct_ops;
else else
tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_fop = &cifs_file_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop->lock = NULL;
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops->readpages = NULL;
if(isNewInode) if(isNewInode)
return; /* No sense invalidating pages for new inode since we return; /* No sense invalidating pages for new inode
have not started caching readahead file data yet */ since have not started caching readahead file
data yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) { (local_size == tmp_inode->i_size)) {
...@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_fop = &cifs_file_direct_ops; tmp_inode->i_fop = &cifs_file_direct_ops;
else else
tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_fop = &cifs_file_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop->lock = NULL;
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
4096 + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops->readpages = NULL;
if(isNewInode) if(isNewInode)
return; /* No sense invalidating pages for new inode since we return; /* No sense invalidating pages for new inode since we
...@@ -374,7 +396,8 @@ static int initiate_cifs_search(const int xid, struct file *file) ...@@ -374,7 +396,8 @@ static int initiate_cifs_search(const int xid, struct file *file)
rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
&cifsFile->netfid, &cifsFile->srch_inf, &cifsFile->netfid, &cifsFile->srch_inf,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
if(rc == 0) if(rc == 0)
cifsFile->invalidHandle = FALSE; cifsFile->invalidHandle = FALSE;
if((rc == -EOPNOTSUPP) && if((rc == -EOPNOTSUPP) &&
...@@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) ...@@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
return rc; return rc;
} }
/* Check if directory that we are searching has changed so we can decide
whether we can use the cached search results from the previous search */
static int is_dir_changed(struct file * file)
{
struct inode * inode;
struct cifsInodeInfo *cifsInfo;
if(file->f_dentry == NULL)
return 0;
inode = file->f_dentry->d_inode;
if(inode == NULL)
return 0;
cifsInfo = CIFS_I(inode);
if(cifsInfo->time == 0)
return 1; /* directory was changed, perhaps due to unlink */
else
return 0;
}
/* find the corresponding entry in the search */ /* find the corresponding entry in the search */
/* Note that the SMB server returns search entries for . and .. which /* Note that the SMB server returns search entries for . and .. which
complicates logic here if we choose to parse for them and we do not 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,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
struct cifsFileInfo * cifsFile = file->private_data; struct cifsFileInfo * cifsFile = file->private_data;
/* check if index in the buffer */ /* check if index in the buffer */
if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) if((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
(num_to_ret == NULL))
return -ENOENT; return -ENOENT;
*ppCurrentEntry = NULL; *ppCurrentEntry = NULL;
...@@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.index_of_last_entry -
cifsFile->srch_inf.entries_in_buffer; cifsFile->srch_inf.entries_in_buffer;
/* dump_cifs_file_struct(file, "In fce ");*/ /* dump_cifs_file_struct(file, "In fce ");*/
if(index_to_find < first_entry_in_buffer) { if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) {
/* close and restart search */ /* close and restart search */
cFYI(1,("search backing up - close and restart search")); cFYI(1,("search backing up - close and restart search"));
cifsFile->invalidHandle = TRUE; cifsFile->invalidHandle = TRUE;
...@@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
(rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
cFYI(1,("calling findnext2")); cFYI(1,("calling findnext2"));
rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); rc = CIFSFindNext(xid,pTcon,cifsFile->netfid,
&cifsFile->srch_inf);
if(rc) if(rc)
return -ENOENT; return -ENOENT;
} }
...@@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
smbCalcSize((struct smb_hdr *) smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start); cifsFile->srch_inf.ntwrk_buf_start);
/* dump_cifs_file_struct(file,"found entry in fce "); */
first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- cifsFile->srch_inf.entries_in_buffer; - cifsFile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_in_buffer; pos_in_buf = index_to_find - first_entry_in_buffer;
cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
current_entry = cifsFile->srch_inf.srch_entries_start; current_entry = cifsFile->srch_inf.srch_entries_start;
for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
/* go entry to next entry figuring out which we need to start with */ /* go entry by entry figuring out which is first */
/* if( . or ..) /* if( . or ..)
skip */ skip */
rc = cifs_entry_is_dot(current_entry,cifsFile); rc = cifs_entry_is_dot(current_entry,cifsFile);
...@@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
} }
if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
cFYI(1,("can not return entries when pos_in_buf beyond last entry")); cFYI(1,("can not return entries pos_in_buf beyond last entry"));
*num_to_ret = 0; *num_to_ret = 0;
} else } else
*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
/* dump_cifs_file_struct(file, "end fce ");*/
return rc; return rc;
} }
...@@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file, ...@@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
(FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
} }
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
tmp_inode->i_ino,obj_type);
if(rc) { if(rc) {
cFYI(1,("filldir rc = %d",rc)); cFYI(1,("filldir rc = %d",rc));
} }
...@@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
FreeXid(xid); FreeXid(xid);
return -EIO; return -EIO;
} }
/* dump_cifs_file_struct(file, "Begin rdir "); */
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;
if(pTcon == NULL) if(pTcon == NULL)
return -EINVAL; return -EINVAL;
/* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
switch ((int) file->f_pos) { switch ((int) file->f_pos) {
case 0: case 0:
/*if (filldir(direntry, ".", 1, file->f_pos, /*if (filldir(direntry, ".", 1, file->f_pos,
...@@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifsFile->search_resume_name = NULL; */ cifsFile->search_resume_name = NULL; */
/* BB account for . and .. in f_pos as special case */ /* BB account for . and .. in f_pos as special case */
/* dump_cifs_file_struct(file, "rdir after default ");*/
rc = find_cifs_entry(xid,pTcon, file, rc = find_cifs_entry(xid,pTcon, file,
&current_entry,&num_to_fill); &current_entry,&num_to_fill);
...@@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
cifs_save_resume_key(current_entry,cifsFile); cifs_save_resume_key(current_entry,cifsFile);
break; break;
} else } else
current_entry = nxt_dir_entry(current_entry,end_of_smb); current_entry = nxt_dir_entry(current_entry,
end_of_smb);
} }
kfree(tmp_buf); kfree(tmp_buf);
break; break;
} /* end switch */ } /* end switch */
rddir2_exit: rddir2_exit:
/* dump_cifs_file_struct(file, "end rdir "); */
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
This diff is collapsed.
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